diff options
Diffstat (limited to '')
-rw-r--r-- | zebra/zebra_mpls.h | 599 |
1 files changed, 599 insertions, 0 deletions
diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h new file mode 100644 index 0000000..cf24786 --- /dev/null +++ b/zebra/zebra_mpls.h @@ -0,0 +1,599 @@ +/* + * Zebra MPLS Data structures and definitions + * Copyright (C) 2015 Cumulus Networks, Inc. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _ZEBRA_MPLS_H +#define _ZEBRA_MPLS_H + +#include "prefix.h" +#include "table.h" +#include "queue.h" +#include "hash.h" +#include "jhash.h" +#include "nexthop.h" +#include "vty.h" +#include "memory.h" +#include "mpls.h" +#include "zebra/zserv.h" +#include "zebra/zebra_vrf.h" +#include "hook.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Definitions and macros. */ + +#define NHLFE_FAMILY(nhlfe) \ + (((nhlfe)->nexthop->type == NEXTHOP_TYPE_IPV6 \ + || (nhlfe)->nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) \ + ? AF_INET6 \ + : AF_INET) + +/* Declare LSP nexthop list types */ +PREDECL_DLIST(nhlfe_list); + +/* + * (Outgoing) nexthop label forwarding entry + */ +struct zebra_nhlfe { + /* Type of entry - static etc. */ + enum lsp_types_t type; + + /* Nexthop information (with outgoing label) */ + struct nexthop *nexthop; + + /* Backpointer to base entry. */ + struct zebra_lsp *lsp; + + /* Runtime info - flags, pointers etc. */ + uint32_t flags; +#define NHLFE_FLAG_CHANGED (1 << 0) +#define NHLFE_FLAG_SELECTED (1 << 1) +#define NHLFE_FLAG_MULTIPATH (1 << 2) +#define NHLFE_FLAG_DELETED (1 << 3) +#define NHLFE_FLAG_INSTALLED (1 << 4) +#define NHLFE_FLAG_IS_BACKUP (1 << 5) + + uint8_t distance; + + /* Linkage for LSPs' lists */ + struct nhlfe_list_item list; +}; + +/* + * Incoming label entry + */ +struct zebra_ile { + mpls_label_t in_label; +}; + +/* + * Label swap entry (ile -> list of nhlfes) + */ +struct zebra_lsp { + /* Incoming label */ + struct zebra_ile ile; + + /* List of NHLFEs, pointer to best, and num equal-cost. */ + struct nhlfe_list_head nhlfe_list; + + struct zebra_nhlfe *best_nhlfe; + uint32_t num_ecmp; + + /* Backup nhlfes, if present. The nexthop in a primary/active nhlfe + * refers to its backup (if any) by index, so the order of this list + * is significant. + */ + struct nhlfe_list_head backup_nhlfe_list; + + /* Flags */ + uint32_t flags; +#define LSP_FLAG_SCHEDULED (1 << 0) +#define LSP_FLAG_INSTALLED (1 << 1) +#define LSP_FLAG_CHANGED (1 << 2) +#define LSP_FLAG_FPM (1 << 3) + + /* Address-family of NHLFE - saved here for delete. All NHLFEs */ + /* have to be of the same AF */ + uint8_t addr_family; +}; + +/* + * FEC to label binding. + */ +struct zebra_fec { + /* FEC (prefix) */ + struct route_node *rn; + + /* In-label - either statically bound or derived from label block. */ + mpls_label_t label; + + /* Label index (into global label block), if valid */ + uint32_t label_index; + + /* Flags. */ + uint32_t flags; +#define FEC_FLAG_CONFIGURED (1 << 0) + + /* Clients interested in this FEC. */ + struct list *client_list; +}; + +/* Declare typesafe list apis/macros */ +DECLARE_DLIST(nhlfe_list, struct zebra_nhlfe, list); + +/* Function declarations. */ + +/* + * Add/update global label block. + */ +int zebra_mpls_label_block_add(struct zebra_vrf *zvrf, uint32_t start_label, + uint32_t end_label); + +/* + * Delete global label block. + */ +int zebra_mpls_label_block_del(struct zebra_vrf *vrf); + +/* + * Display MPLS global label block configuration (VTY command handler). + */ +int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *vrf); + +/* + * Install dynamic LSP entry. + */ +int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn, + struct route_entry *re); + +/* + * Uninstall dynamic LSP entry, if any. + */ +int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn, + struct route_entry *re); + +/* Add an NHLFE to an LSP, return the newly-added object */ +struct zebra_nhlfe * +zebra_mpls_lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t lsp_type, + enum nexthop_types_t gtype, const union g_addr *gate, + ifindex_t ifindex, uint8_t num_labels, + const mpls_label_t *out_labels); + +/* Add or update a backup NHLFE for an LSP; return the object */ +struct zebra_nhlfe *zebra_mpls_lsp_add_backup_nhlfe( + struct zebra_lsp *lsp, enum lsp_types_t lsp_type, + enum nexthop_types_t gtype, const union g_addr *gate, ifindex_t ifindex, + uint8_t num_labels, const mpls_label_t *out_labels); + +/* + * Add NHLFE or backup NHLFE to an LSP based on a nexthop. These just maintain + * the LSP and NHLFE objects; nothing is scheduled for processing. + * Return: the newly-added object + */ +struct zebra_nhlfe *zebra_mpls_lsp_add_nh(struct zebra_lsp *lsp, + enum lsp_types_t lsp_type, + const struct nexthop *nh); +struct zebra_nhlfe *zebra_mpls_lsp_add_backup_nh(struct zebra_lsp *lsp, + enum lsp_types_t lsp_type, + const struct nexthop *nh); + +/* Free an allocated NHLFE */ +void zebra_mpls_nhlfe_free(struct zebra_nhlfe *nhlfe); + +int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p, + uint32_t label, uint32_t label_index, + struct zserv *client); + +/* + * Deregistration from a client for the label binding for a FEC. The FEC + * itself is deleted if no other registered clients exist and there is no + * label bound to the FEC. + */ +int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p, + struct zserv *client); + +/* + * Return FEC (if any) to which this label is bound. + * Note: Only works for per-prefix binding and when the label is not + * implicit-null. + * TODO: Currently walks entire table, can optimize later with another + * hash.. + */ +struct zebra_fec *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf, + mpls_label_t label); + +/* + * Inform if specified label is currently bound to a FEC or not. + */ +int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, mpls_label_t label); + +/* + * Add static FEC to label binding. If there are clients registered for this + * FEC, notify them. If there are labeled routes for this FEC, install the + * label forwarding entry. + */ +int zebra_mpls_static_fec_add(struct zebra_vrf *zvrf, struct prefix *p, + mpls_label_t in_label); + +/* + * Remove static FEC to label binding. If there are no clients registered + * for this FEC, delete the FEC; else notify clients. + * Note: Upon delete of static binding, if label index exists for this FEC, + * client may need to be updated with derived label. + */ +int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p); + +/* + * Display MPLS FEC to label binding configuration (VTY command handler). + */ +int zebra_mpls_write_fec_config(struct vty *vty, struct zebra_vrf *zvrf); + +/* + * Display MPLS FEC to label binding (VTY command handler). + */ +void zebra_mpls_print_fec_table(struct vty *vty, struct zebra_vrf *zvrf); + +/* + * Display MPLS FEC to label binding for a specific FEC (VTY command handler). + */ +void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf, + struct prefix *p); + +/* + * Handle zapi request to install/uninstall LSP and + * (optionally) FEC-To-NHLFE (FTN) bindings. + * + * mpls_zapi_labels_process -> Installs for future processing + * in the meta-q + * zebra_mpls_labels_process -> called by the meta-q + */ +void mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf, + const struct zapi_labels *zl); +void zebra_mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf, + const struct zapi_labels *zl); + +/* + * Uninstall all NHLFEs bound to a single FEC. + * + * mpls_ftn_uninstall -> Called to enqueue into early label processing + * via the metaq + * zebra_mpls_ftn_uninstall -> Called when we process the meta q + * for this item + */ +void mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, + struct prefix *prefix, uint8_t route_type, + uint8_t route_instance); +void zebra_mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, + struct prefix *prefix, uint8_t route_type, + uint8_t route_instance); +/* + * Install/update a NHLFE for an LSP in the forwarding table. This may be + * a new LSP entry or a new NHLFE for an existing in-label or an update of + * the out-label(s) for an existing NHLFE (update case). + */ +int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, + mpls_label_t in_label, uint8_t num_out_labels, + const mpls_label_t *out_labels, enum nexthop_types_t gtype, + const union g_addr *gate, ifindex_t ifindex); + +/* + * Lookup LSP by its input label. + */ +struct zebra_lsp *mpls_lsp_find(struct zebra_vrf *zvrf, mpls_label_t in_label); + +/* + * Uninstall a particular NHLFE in the forwarding table. If this is + * the only NHLFE, the entire LSP forwarding entry has to be deleted. + */ +int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, + mpls_label_t in_label, enum nexthop_types_t gtype, + const union g_addr *gate, ifindex_t ifindex, + bool backup_p); + +/* + * Uninstall all NHLFEs for a particular LSP forwarding entry. + */ +int mpls_lsp_uninstall_all_vrf(struct zebra_vrf *zvrf, enum lsp_types_t type, + mpls_label_t in_label); + +#if defined(HAVE_CUMULUS) +/* + * Check that the label values used in LSP creation are consistent. The + * main criteria is that if there is ECMP, the label operation must still + * be consistent - i.e., all paths either do a swap or do PHP. This is due + * to current HW restrictions. + */ +int zebra_mpls_lsp_label_consistent(struct zebra_vrf *zvrf, + mpls_label_t in_label, + mpls_label_t out_label, + enum nexthop_types_t gtype, + union g_addr *gate, ifindex_t ifindex); +#endif /* HAVE_CUMULUS */ + +/* + * Add static LSP entry. This may be the first entry for this incoming label + * or an additional nexthop; an existing entry may also have outgoing label + * changed. + * Note: The label operation (swap or PHP) is common for the LSP entry (all + * NHLFEs). + */ +int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label, + mpls_label_t out_label, + enum nexthop_types_t gtype, union g_addr *gate, + ifindex_t ifindex); + +/* + * Delete static LSP entry. This may be the delete of one particular + * NHLFE for this incoming label or the delete of the entire entry (i.e., + * all NHLFEs). + * NOTE: Delete of the only NHLFE will also end up deleting the entire + * LSP configuration. + */ +int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label, + enum nexthop_types_t gtype, union g_addr *gate, + ifindex_t ifindex); + +/* + * Process LSP update results from zebra dataplane. + */ +/* Forward ref of dplane update context type */ +struct zebra_dplane_ctx; + +void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx); + +/* Process async dplane notifications. */ +void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx); + +/* + * Schedule all MPLS label forwarding entries for processing. + * Called upon changes that may affect one or more of them such as + * interface or nexthop state changes. + */ +void zebra_mpls_lsp_schedule(struct zebra_vrf *zvrf); + +/* + * Display MPLS label forwarding table for a specific LSP + * (VTY command handler). + */ +void zebra_mpls_print_lsp(struct vty *vty, struct zebra_vrf *zvrf, + mpls_label_t label, bool use_json); + +/* + * Display MPLS label forwarding table (VTY command handler). + */ +void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf, + bool use_json); + +/* + * Display MPLS LSP configuration of all static LSPs (VTY command handler). + */ +int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf); + +/* + * Called when VRF becomes inactive, cleans up information but keeps + * the table itself. + * NOTE: Currently supported only for default VRF. + */ +void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf); + +/* + * Called upon process exiting, need to delete LSP forwarding + * entries from the kernel. + * NOTE: Currently supported only for default VRF. + */ +void zebra_mpls_close_tables(struct zebra_vrf *zvrf); + +/* + * Allocate MPLS tables for this VRF. + * NOTE: Currently supported only for default VRF. + */ +void zebra_mpls_init_tables(struct zebra_vrf *zvrf); + +/* + * If mpls is turned on *after* FRR is brought + * up let's actually notice this and turn on + * the relevant bits to make it work. + */ +void zebra_mpls_turned_on(void); + +/* + * Global MPLS initialization. + */ +void zebra_mpls_init(void); + +/* + * MPLS VTY. + */ +void zebra_mpls_vty_init(void); + +/* + * When cleaning up a client connection ensure that there are no + * vrf labels that need cleaning up too + */ +void zebra_mpls_client_cleanup_vrf_label(uint8_t proto); + +/* Inline functions. */ + +/* + * Distance (priority) definition for LSP NHLFE. + */ +static inline uint8_t lsp_distance(enum lsp_types_t type) +{ + switch (type) { + case ZEBRA_LSP_STATIC: + return (route_distance(ZEBRA_ROUTE_STATIC)); + case ZEBRA_LSP_LDP: + return (route_distance(ZEBRA_ROUTE_LDP)); + case ZEBRA_LSP_BGP: + return (route_distance(ZEBRA_ROUTE_BGP)); + case ZEBRA_LSP_NONE: + case ZEBRA_LSP_SHARP: + case ZEBRA_LSP_OSPF_SR: + case ZEBRA_LSP_ISIS_SR: + case ZEBRA_LSP_SRTE: + return 150; + } + + /* + * For some reason certain compilers do not believe + * that all the cases have been handled. And + * WTF does this work differently than when I removed + * the default case???? + */ + return 150; +} + +/* + * Map RIB type to LSP type. Used when labeled-routes from BGP + * are converted into LSPs. + */ +static inline enum lsp_types_t lsp_type_from_re_type(int re_type) +{ + switch (re_type) { + case ZEBRA_ROUTE_STATIC: + return ZEBRA_LSP_STATIC; + case ZEBRA_ROUTE_LDP: + return ZEBRA_LSP_LDP; + case ZEBRA_ROUTE_BGP: + return ZEBRA_LSP_BGP; + case ZEBRA_ROUTE_OSPF: + return ZEBRA_LSP_OSPF_SR; + case ZEBRA_ROUTE_ISIS: + return ZEBRA_LSP_ISIS_SR; + case ZEBRA_ROUTE_SHARP: + return ZEBRA_LSP_SHARP; + case ZEBRA_ROUTE_SRTE: + return ZEBRA_LSP_SRTE; + default: + return ZEBRA_LSP_NONE; + } +} + +/* + * Map LSP type to RIB type. + */ +static inline int re_type_from_lsp_type(enum lsp_types_t lsp_type) +{ + switch (lsp_type) { + case ZEBRA_LSP_STATIC: + return ZEBRA_ROUTE_STATIC; + case ZEBRA_LSP_LDP: + return ZEBRA_ROUTE_LDP; + case ZEBRA_LSP_BGP: + return ZEBRA_ROUTE_BGP; + case ZEBRA_LSP_OSPF_SR: + return ZEBRA_ROUTE_OSPF; + case ZEBRA_LSP_ISIS_SR: + return ZEBRA_ROUTE_ISIS; + case ZEBRA_LSP_NONE: + return ZEBRA_ROUTE_KERNEL; + case ZEBRA_LSP_SHARP: + return ZEBRA_ROUTE_SHARP; + case ZEBRA_LSP_SRTE: + return ZEBRA_ROUTE_SRTE; + } + + /* + * For some reason certain compilers do not believe + * that all the cases have been handled. And + * WTF does this work differently than when I removed + * the default case???? + */ + return ZEBRA_ROUTE_KERNEL; +} + +/* NHLFE type as printable string. */ +static inline const char *nhlfe_type2str(enum lsp_types_t lsp_type) +{ + switch (lsp_type) { + case ZEBRA_LSP_STATIC: + return "Static"; + case ZEBRA_LSP_LDP: + return "LDP"; + case ZEBRA_LSP_BGP: + return "BGP"; + case ZEBRA_LSP_OSPF_SR: + return "SR (OSPF)"; + case ZEBRA_LSP_ISIS_SR: + return "SR (IS-IS)"; + case ZEBRA_LSP_SHARP: + return "SHARP"; + case ZEBRA_LSP_SRTE: + return "SR-TE"; + case ZEBRA_LSP_NONE: + return "Unknown"; + } + + /* + * For some reason certain compilers do not believe + * that all the cases have been handled. And + * WTF does this work differently than when I removed + * the default case???? + */ + return "Unknown"; +} + +static inline void mpls_mark_lsps_for_processing(struct zebra_vrf *zvrf, + struct prefix *p) +{ + struct route_table *table; + struct route_node *rn; + rib_dest_t *dest; + + if (!zvrf) + return; + + table = zvrf->table[family2afi(p->family)][SAFI_UNICAST]; + if (!table) + return; + + rn = route_node_match(table, p); + if (!rn) + return; + + + dest = rib_dest_from_rnode(rn); + SET_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS); +} + +static inline void mpls_unmark_lsps_for_processing(struct route_node *rn) +{ + rib_dest_t *dest = rib_dest_from_rnode(rn); + + UNSET_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS); +} + +static inline int mpls_should_lsps_be_processed(struct route_node *rn) +{ + rib_dest_t *dest = rib_dest_from_rnode(rn); + + return !!CHECK_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS); +} + +/* Global variables. */ +extern bool mpls_enabled; +extern bool mpls_pw_reach_strict; /* Strict pseudowire reachability checking */ + +#ifdef __cplusplus +} +#endif + +#endif /*_ZEBRA_MPLS_H */ |