From: Don Slice Date: Tue, 27 Dec 2016 15:09:28 +0000 (-0800) Subject: zebra: static label binding X-Git-Tag: reindent-master-before~213^2~32 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=f31e084c7c0e6699926ad72bc4f9a8ca2663f50b;p=mirror%2Ffrr.git zebra: static label binding Implement static label binding of a label to a prefix (FEC). Note: Currently, only binding to a prefix is supported, the nexthop and/or other parameters are not considered. This was cherry-picked by hand from an earlier mpls branch. Signed-off-by: Don Slice --- diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 5a3ed7545d..814d171d9f 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -47,6 +47,7 @@ #include "zebra/zebra_mpls.h" DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object") +DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object") DEFINE_MTYPE_STATIC(ZEBRA, SLSP, "MPLS static LSP config") DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object") DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE, "MPLS static nexthop object") @@ -58,6 +59,17 @@ int mpls_enabled; extern struct zebra_t zebrad; /* static function declarations */ + +static void +fec_print (zebra_fec_t *fec, struct vty *vty); +static zebra_fec_t * +fec_find (struct route_table *table, struct prefix *p); +static zebra_fec_t * +fec_add (struct route_table *table, struct prefix *p, u_int32_t label, + u_int32_t flags); +static int +fec_del (zebra_fec_t *fec); + static unsigned int label_hash (void *p); static int @@ -68,6 +80,7 @@ static int nhlfe_nexthop_active_ipv6 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop); static int nhlfe_nexthop_active (zebra_nhlfe_t *nhlfe); + static void lsp_select_best_nhlfe (zebra_lsp_t *lsp); static void @@ -84,6 +97,7 @@ static int lsp_processq_add (zebra_lsp_t *lsp); static void * lsp_alloc (void *p); + static char * nhlfe2str (zebra_nhlfe_t *nhlfe, char *buf, int size); static int @@ -134,6 +148,88 @@ mpls_processq_init (struct zebra_t *zebra); /* Static functions */ +/* + * Print a FEC-label binding entry. + */ +static void +fec_print (zebra_fec_t *fec, struct vty *vty) +{ + struct route_node *rn; + char buf[BUFSIZ]; + + rn = fec->rn; + prefix2str(&rn->p, buf, BUFSIZ); + vty_out(vty, "%s%s", buf, VTY_NEWLINE); + vty_out(vty, " Label: %s", label2str(fec->label, buf, BUFSIZ)); + vty_out(vty, "%s", VTY_NEWLINE); +} + +/* + * Locate FEC-label binding that matches with passed info. + */ +static zebra_fec_t * +fec_find (struct route_table *table, struct prefix *p) +{ + struct route_node *rn; + + apply_mask (p); + rn = route_node_lookup(table, p); + if (!rn) + return NULL; + + route_unlock_node(rn); + return (rn->info); +} + +/* + * Add a FEC. + */ +static zebra_fec_t * +fec_add (struct route_table *table, struct prefix *p, + mpls_label_t label, u_int32_t flags) +{ + struct route_node *rn; + zebra_fec_t *fec; + + apply_mask (p); + + /* Lookup (or add) route node.*/ + rn = route_node_get (table, p); + if (!rn) + return NULL; + + fec = rn->info; + + if (!fec) + { + fec = XCALLOC (MTYPE_FEC, sizeof(zebra_fec_t)); + if (!fec) + return NULL; + + rn->info = fec; + fec->rn = rn; + fec->label = label; + } + else + route_unlock_node (rn); /* for the route_node_get */ + + fec->flags = flags; + + return fec; +} + +/* + * Delete a FEC. + */ +static int +fec_del (zebra_fec_t *fec) +{ + fec->rn->info = NULL; + route_unlock_node (fec->rn); + XFREE (MTYPE_FEC, fec); + return 0; +} + /* * Hash function for label. */ @@ -1274,6 +1370,215 @@ mpls_label2str (u_int8_t num_labels, mpls_label_t *labels, return buf; } +/* + * 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.. + */ +zebra_fec_t * +zebra_mpls_fec_for_label (struct zebra_vrf *zvrf, mpls_label_t label) +{ + struct route_node *rn; + zebra_fec_t *fec; + int af; + + for (af = AFI_IP; af < AFI_MAX; af++) + { + if (zvrf->fec_table[af] == NULL) + continue; + + for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn)) + { + if (!rn->info) + continue; + fec = rn->info; + if (fec->label == label) + return fec; + } + } + + return NULL; +} + +/* + * 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) +{ + return (zebra_mpls_fec_for_label (zvrf, label) ? 1 : 0); +} + +/* + * Add static FEC to label binding. + */ +int +zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p, + mpls_label_t in_label) +{ + struct route_table *table; + zebra_fec_t *fec; + char buf[BUFSIZ]; + int ret = 0; + + table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))]; + if (!table) + return -1; + + if (IS_ZEBRA_DEBUG_MPLS) + prefix2str(p, buf, BUFSIZ); + + /* Update existing FEC or create a new one. */ + fec = fec_find (table, p); + if (!fec) + { + fec = fec_add (table, p, in_label, FEC_FLAG_CONFIGURED); + if (!fec) + { + prefix2str(p, buf, BUFSIZ); + zlog_err ("Failed to add FEC %s upon config", buf); + return -1; + } + + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug ("Add fec %s label %u", buf, in_label); + } + else + { + fec->flags |= FEC_FLAG_CONFIGURED; + if (fec->label == in_label) + /* Duplicate config */ + return 0; + + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug ("Update fec %s new label %u", buf, in_label); + + fec->label = in_label; + } + + return ret; +} + +/* + * Remove static FEC to label binding. + */ +int +zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p) +{ + struct route_table *table; + zebra_fec_t *fec; + char buf[BUFSIZ]; + + table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))]; + if (!table) + return -1; + + fec = fec_find (table, p); + if (!fec) + { + prefix2str(p, buf, BUFSIZ); + zlog_err("Failed to find FEC %s upon delete", buf); + return -1; + } + + if (IS_ZEBRA_DEBUG_MPLS) + { + prefix2str(p, buf, BUFSIZ); + zlog_debug ("Delete fec %s", buf); + } + + fec_del (fec); + return 0; +} + +/* + * Display MPLS FEC to label binding configuration (VTY command handler). + */ +int +zebra_mpls_write_fec_config (struct vty *vty, struct zebra_vrf *zvrf) +{ + struct route_node *rn; + int af; + zebra_fec_t *fec; + char buf[BUFSIZ]; + int write = 0; + + for (af = AFI_IP; af < AFI_MAX; af++) + { + if (zvrf->fec_table[af] == NULL) + continue; + + for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn)) + { + if (!rn->info) + continue; + + char lstr[BUFSIZ]; + fec = rn->info; + + if (!(fec->flags & FEC_FLAG_CONFIGURED)) + continue; + + write = 1; + prefix2str(&rn->p, buf, BUFSIZ); + vty_out(vty, "mpls label bind %s %s%s", buf, + label2str(fec->label, lstr, BUFSIZ), VTY_NEWLINE); + } + } + + return write; +} + +/* + * Display MPLS FEC to label binding (VTY command handler). + */ +void +zebra_mpls_print_fec_table (struct vty *vty, struct zebra_vrf *zvrf) +{ + struct route_node *rn; + int af; + + for (af = AFI_IP; af < AFI_MAX; af++) + { + if (zvrf->fec_table[af] == NULL) + continue; + + for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn)) + { + if (!rn->info) + continue; + fec_print (rn->info, vty); + } + } +} + +/* + * 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) +{ + struct route_table *table; + struct route_node *rn; + + table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))]; + if (!table) + return; + + apply_mask (p); + rn = route_node_lookup(table, p); + if (!rn) + return; + + route_unlock_node(rn); + if (!rn->info) + return; + + fec_print (rn->info, vty); +} + /* * Install/uninstall a FEC-To-NHLFE (FTN) binding. */ @@ -1927,6 +2232,8 @@ zebra_mpls_init_tables (struct zebra_vrf *zvrf) return; zvrf->slsp_table = hash_create(label_hash, label_cmp); zvrf->lsp_table = hash_create(label_hash, label_cmp); + zvrf->fec_table[AFI_IP] = route_table_init(); + zvrf->fec_table[AFI_IP6] = route_table_init(); zvrf->mpls_flags = 0; } diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index a871fac651..9ff230e5ee 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -52,6 +52,7 @@ typedef struct zebra_snhlfe_t_ zebra_snhlfe_t; typedef struct zebra_slsp_t_ zebra_slsp_t; typedef struct zebra_nhlfe_t_ zebra_nhlfe_t; typedef struct zebra_lsp_t_ zebra_lsp_t; +typedef struct zebra_fec_t_ zebra_fec_t; /* * (Outgoing) nexthop label forwarding entry configuration @@ -147,6 +148,21 @@ struct zebra_lsp_t_ u_char addr_family; }; +/* + * FEC to label binding. + */ +struct zebra_fec_t_ +{ + /* FEC (prefix) */ + struct route_node *rn; + + /* In-label - either statically bound or derived from label block. */ + mpls_label_t label; + + /* Flags. */ + u_int32_t flags; +#define FEC_FLAG_CONFIGURED (1 << 0) +}; /* Function declarations. */ @@ -164,6 +180,53 @@ char * mpls_label2str (u_int8_t num_labels, mpls_label_t *labels, char *buf, int len); +/* + * 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.. + */ +zebra_fec_t * +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. + */ +int +zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p, + mpls_label_t in_label); + +/* + * Remove static FEC to label binding. + */ +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); + /* * Install/uninstall a FEC-To-NHLFE (FTN) binding. */ diff --git a/zebra/zebra_mpls_vty.c b/zebra/zebra_mpls_vty.c index dd381723c5..90624c12a4 100644 --- a/zebra/zebra_mpls_vty.c +++ b/zebra/zebra_mpls_vty.c @@ -209,6 +209,101 @@ DEFUN (no_mpls_transit_lsp_all, return zebra_mpls_transit_lsp (vty, 0, argv[3]->arg, NULL, NULL, NULL); } +static int +zebra_mpls_bind (struct vty *vty, int add_cmd, const char *prefix, + const char *label_str) +{ + struct zebra_vrf *zvrf; + struct prefix p; + u_int32_t label; + int ret; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (!zvrf) + { + vty_out (vty, "%% Default VRF does not exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + + memset(&p, 0, sizeof(struct prefix)); + ret = str2prefix(prefix, &p); + if (ret <= 0) + { + vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (add_cmd) + { + if (!label_str) + { + vty_out (vty, "%% No label binding specified%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (!strcmp(label_str, "implicit-null")) + label = MPLS_IMP_NULL_LABEL; + else + { + label = atoi(label_str); + if (!IS_MPLS_UNRESERVED_LABEL(label)) + { + vty_out (vty, "%% Invalid label%s", VTY_NEWLINE); + return CMD_WARNING; + } + if (zebra_mpls_label_already_bound (zvrf, label)) + { + vty_out (vty, "%% Label already bound to a FEC%s", + VTY_NEWLINE); + return CMD_WARNING; + } + } + + ret = zebra_mpls_static_fec_add (zvrf, &p, label); + } + else + ret = zebra_mpls_static_fec_del (zvrf, &p); + + if (ret) + { + vty_out (vty, "%% FEC to label binding cannot be %s%s", + add_cmd ? "added" : "deleted", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (mpls_label_bind, + mpls_label_bind_cmd, + "mpls label bind <(16-1048575)|implicit-null>", + MPLS_STR + "Label configuration\n" + "Establish FEC to label binding\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "MPLS Label to bind\n" + "Use Implicit-Null Label\n") +{ + return zebra_mpls_bind (vty, 1, argv[3]->arg, argv[4]->arg); +} + +DEFUN (no_mpls_label_bind, + no_mpls_label_bind_cmd, + "no mpls label bind [<(16-1048575)|implicit-null>]", + NO_STR + MPLS_STR + "Label configuration\n" + "Establish FEC to label binding\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "MPLS Label to bind\n" + "Use Implicit-Null Label\n") + +{ + return zebra_mpls_bind (vty, 0, argv[4]->arg, NULL); +} + /* Static route configuration. */ DEFUN (ip_route_label, ip_route_label_cmd, @@ -777,9 +872,44 @@ zebra_mpls_config (struct vty *vty) return 0; write += zebra_mpls_write_lsp_config(vty, zvrf); + write += zebra_mpls_write_fec_config(vty, zvrf); return write; } +DEFUN (show_mpls_fec, + show_mpls_fec_cmd, + "show mpls fec []", + SHOW_STR + MPLS_STR + "MPLS FEC table\n" + "FEC to display information about\n" + "FEC to display information about\n") +{ + struct zebra_vrf *zvrf; + struct prefix p; + int ret; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (!zvrf) + return 0; + + if (argc == 3) + zebra_mpls_print_fec_table(vty, zvrf); + else + { + memset(&p, 0, sizeof(struct prefix)); + ret = str2prefix(argv[3]->arg, &p); + if (ret <= 0) + { + vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + zebra_mpls_print_fec (vty, zvrf, &p); + } + + return CMD_SUCCESS; +} + DEFUN (show_mpls_table, show_mpls_table_cmd, "show mpls table [json]", @@ -876,7 +1006,10 @@ zebra_mpls_vty_init (void) install_element (CONFIG_NODE, &no_mpls_transit_lsp_cmd); install_element (CONFIG_NODE, &no_mpls_transit_lsp_out_label_cmd); install_element (CONFIG_NODE, &no_mpls_transit_lsp_all_cmd); + install_element (CONFIG_NODE, &mpls_label_bind_cmd); + install_element (CONFIG_NODE, &no_mpls_label_bind_cmd); install_element (VIEW_NODE, &show_mpls_table_cmd); install_element (VIEW_NODE, &show_mpls_table_lsp_cmd); + install_element (VIEW_NODE, &show_mpls_fec_cmd); } diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index 96d631d646..8333ca27d7 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -79,6 +79,9 @@ struct zebra_vrf /* MPLS label forwarding table */ struct hash *lsp_table; + /* MPLS FEC binding table */ + struct route_table *fec_table[AFI_MAX]; + /* MPLS processing flags */ u_int16_t mpls_flags; #define MPLS_FLAG_SCHEDULE_LSPS (1 << 0)