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 <dslice@cumulusnetworks.com>
This commit is contained in:
Don Slice 2016-12-27 07:09:28 -08:00 committed by Donald Sharp
parent bc7268d524
commit f31e084c7c
4 changed files with 506 additions and 0 deletions

View File

@ -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;
}

View File

@ -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.
*/

View File

@ -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 <A.B.C.D/M|X:X::X:X/M> <(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 <A.B.C.D/M|X:X::X:X/M> [<(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 [<A.B.C.D/M|X:X::X:X/M>]",
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);
}

View File

@ -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)