zebra: fec register

Implement interface that allows a client to register a FEC for obtaining
a label binding (in-label). Update client whenever the label binding is
updated and cleanup when client goes away.

Signed-off-by: Don Slice <dslice@cumulusnetworks.com>
This commit is contained in:
Don Slice 2017-02-01 13:10:56 -05:00 committed by Donald Sharp
parent f31e084c7c
commit 5aba114af4
7 changed files with 458 additions and 9 deletions

View File

@ -1867,6 +1867,12 @@ zclient_read (struct thread *thread)
if (zclient->interface_link_params) if (zclient->interface_link_params)
(*zclient->interface_link_params) (command, zclient, length); (*zclient->interface_link_params) (command, zclient, length);
break; break;
case ZEBRA_FEC_UPDATE:
if (zclient_debug)
zlog_debug("zclient rcvd fec update\n");
if (zclient->fec_update)
(*zclient->fec_update) (command, zclient, length);
break;
default: default:
break; break;
} }

View File

@ -94,6 +94,9 @@ typedef enum {
ZEBRA_LABEL_MANAGER_CONNECT, ZEBRA_LABEL_MANAGER_CONNECT,
ZEBRA_GET_LABEL_CHUNK, ZEBRA_GET_LABEL_CHUNK,
ZEBRA_RELEASE_LABEL_CHUNK, ZEBRA_RELEASE_LABEL_CHUNK,
ZEBRA_FEC_REGISTER,
ZEBRA_FEC_UNREGISTER,
ZEBRA_FEC_UPDATE,
} zebra_message_types_t; } zebra_message_types_t;
struct redist_proto struct redist_proto
@ -164,6 +167,7 @@ struct zclient
int (*redistribute_route_ipv4_del) (int, struct zclient *, uint16_t, vrf_id_t); int (*redistribute_route_ipv4_del) (int, struct zclient *, uint16_t, vrf_id_t);
int (*redistribute_route_ipv6_add) (int, struct zclient *, uint16_t, vrf_id_t); int (*redistribute_route_ipv6_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*redistribute_route_ipv6_del) (int, struct zclient *, uint16_t, vrf_id_t); int (*redistribute_route_ipv6_del) (int, struct zclient *, uint16_t, vrf_id_t);
int (*fec_update) (int, struct zclient *, uint16_t);
}; };
/* Zebra API message flag. */ /* Zebra API message flag. */

View File

@ -40,7 +40,7 @@ testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \
zebra_vty.c zebra_ptm.c zebra_routemap.c zebra_ns.c zebra_vrf.c \ zebra_vty.c zebra_ptm.c zebra_routemap.c zebra_ns.c zebra_vrf.c \
kernel_null.c redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.c \ kernel_null.c redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.c \
zebra_ptm_null.c rtadv_null.c if_null.c zserv_null.c zebra_static.c \ zebra_ptm_null.c rtadv_null.c if_null.c zserv_null.c zebra_static.c \
zebra_memory.c zebra_mpls.c zebra_mpls_vty.c zebra_mpls_null.c zebra_memory.c zebra_mpls_vty.c zebra_mpls_null.c
noinst_HEADERS = \ noinst_HEADERS = \
zebra_memory.h \ zebra_memory.h \

View File

@ -60,6 +60,10 @@ extern struct zebra_t zebrad;
/* static function declarations */ /* static function declarations */
static int
fec_send (zebra_fec_t *fec, struct zserv *client);
static void
fec_update_clients (zebra_fec_t *fec);
static void static void
fec_print (zebra_fec_t *fec, struct vty *vty); fec_print (zebra_fec_t *fec, struct vty *vty);
static zebra_fec_t * static zebra_fec_t *
@ -148,6 +152,49 @@ mpls_processq_init (struct zebra_t *zebra);
/* Static functions */ /* Static functions */
/*
* Inform about FEC to a registered client.
*/
static int
fec_send (zebra_fec_t *fec, struct zserv *client)
{
struct stream *s;
struct route_node *rn;
rn = fec->rn;
/* Get output stream. */
s = client->obuf;
stream_reset (s);
zserv_create_header (s, ZEBRA_FEC_UPDATE, VRF_DEFAULT);
stream_putw(s, rn->p.family);
stream_put_prefix (s, &rn->p);
stream_putl(s, fec->label);
stream_putw_at(s, 0, stream_get_endp(s));
return zebra_server_send_message(client);
}
/*
* Update all registered clients about this FEC. Caller should've updated
* FEC and ensure no duplicate updates.
*/
static void
fec_update_clients (zebra_fec_t *fec)
{
struct listnode *node;
struct zserv *client;
for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client))
{
if (IS_ZEBRA_DEBUG_MPLS)
zlog_debug ("Update client %s", zebra_route_string(client->proto));
fec_send(fec, client);
}
}
/* /*
* Print a FEC-label binding entry. * Print a FEC-label binding entry.
*/ */
@ -155,6 +202,8 @@ static void
fec_print (zebra_fec_t *fec, struct vty *vty) fec_print (zebra_fec_t *fec, struct vty *vty)
{ {
struct route_node *rn; struct route_node *rn;
struct listnode *node;
struct zserv *client;
char buf[BUFSIZ]; char buf[BUFSIZ];
rn = fec->rn; rn = fec->rn;
@ -162,6 +211,14 @@ fec_print (zebra_fec_t *fec, struct vty *vty)
vty_out(vty, "%s%s", buf, VTY_NEWLINE); vty_out(vty, "%s%s", buf, VTY_NEWLINE);
vty_out(vty, " Label: %s", label2str(fec->label, buf, BUFSIZ)); vty_out(vty, " Label: %s", label2str(fec->label, buf, BUFSIZ));
vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "%s", VTY_NEWLINE);
if (!list_isempty(fec->client_list))
{
vty_out(vty, " Client list:");
for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client))
vty_out(vty, " %s(fd %d)",
zebra_route_string(client->proto), client->sock);
vty_out(vty, "%s", VTY_NEWLINE);
}
} }
/* /*
@ -182,7 +239,8 @@ fec_find (struct route_table *table, struct prefix *p)
} }
/* /*
* Add a FEC. * Add a FEC. This may be upon a client registering for a binding
* or when a binding is configured.
*/ */
static zebra_fec_t * static zebra_fec_t *
fec_add (struct route_table *table, struct prefix *p, fec_add (struct route_table *table, struct prefix *p,
@ -209,6 +267,7 @@ fec_add (struct route_table *table, struct prefix *p,
rn->info = fec; rn->info = fec;
fec->rn = rn; fec->rn = rn;
fec->label = label; fec->label = label;
fec->client_list = list_new();
} }
else else
route_unlock_node (rn); /* for the route_node_get */ route_unlock_node (rn); /* for the route_node_get */
@ -219,11 +278,14 @@ fec_add (struct route_table *table, struct prefix *p,
} }
/* /*
* Delete a FEC. * Delete a FEC. This may be upon the last client deregistering for
* a FEC and no binding exists or when the binding is deleted and there
* are no registered clients.
*/ */
static int static int
fec_del (zebra_fec_t *fec) fec_del (zebra_fec_t *fec)
{ {
list_free (fec->client_list);
fec->rn->info = NULL; fec->rn->info = NULL;
route_unlock_node (fec->rn); route_unlock_node (fec->rn);
XFREE (MTYPE_FEC, fec); XFREE (MTYPE_FEC, fec);
@ -1370,6 +1432,142 @@ mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
return buf; return buf;
} }
/*
* Registration from a client for the label binding for a FEC. If a binding
* already exists, it is informed to the client.
*/
int
zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
struct zserv *client)
{
struct route_table *table;
zebra_fec_t *fec;
char buf[BUFSIZ];
table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
if (!table)
return -1;
if (IS_ZEBRA_DEBUG_MPLS)
prefix2str(p, buf, BUFSIZ);
/* Locate FEC */
fec = fec_find (table, p);
if (!fec)
{
fec = fec_add (table, p, MPLS_INVALID_LABEL, 0);
if (!fec)
{
prefix2str(p, buf, BUFSIZ);
zlog_err("Failed to add FEC %s upon register, client %s",
buf, zebra_route_string(client->proto));
return -1;
}
}
else
{
if (listnode_lookup(fec->client_list, client))
/* Duplicate register */
return 0;
}
listnode_add (fec->client_list, client);
if (IS_ZEBRA_DEBUG_MPLS)
zlog_debug("FEC %s registered by client %s",
buf, zebra_route_string(client->proto));
if (fec->label != MPLS_INVALID_LABEL)
{
if (IS_ZEBRA_DEBUG_MPLS)
zlog_debug ("Update client label %u", fec->label);
fec_send (fec, client);
}
return 0;
}
/*
* 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)
{
struct route_table *table;
zebra_fec_t *fec;
char buf[BUFSIZ];
table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
if (!table)
return -1;
if (IS_ZEBRA_DEBUG_MPLS)
prefix2str(p, buf, BUFSIZ);
fec = fec_find (table, p);
if (!fec)
{
prefix2str(p, buf, BUFSIZ);
zlog_err("Failed to find FEC %s upon unregister, client %s",
buf, zebra_route_string(client->proto));
return -1;
}
listnode_delete(fec->client_list, client);
if (IS_ZEBRA_DEBUG_MPLS)
zlog_debug("FEC %s unregistered by client %s",
buf, zebra_route_string(client->proto));
if (list_isempty(fec->client_list) && (fec->label == MPLS_INVALID_LABEL))
fec_del (fec);
return 0;
}
/*
* Cleanup any FECs registered by this client.
*/
int
zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client)
{
struct route_node *rn;
zebra_fec_t *fec;
struct listnode *node;
struct zserv *fec_client;
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))
{
fec = rn->info;
if (!fec || list_isempty(fec->client_list))
continue;
for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, fec_client))
{
if (fec_client == client)
{
listnode_delete(fec->client_list, fec_client);
if (!(fec->flags & FEC_FLAG_CONFIGURED) &&
list_isempty(fec->client_list))
fec_del (fec);
break;
}
}
}
}
return 0;
}
/* /*
* Return FEC (if any) to which this label is bound. * Return FEC (if any) to which this label is bound.
* Note: Only works for per-prefix binding and when the label is not * Note: Only works for per-prefix binding and when the label is not
@ -1412,7 +1610,8 @@ zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label)
} }
/* /*
* Add static FEC to label binding. * Add static FEC to label binding. If there are clients registered for this
* FEC, notify them.
*/ */
int int
zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p, zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
@ -1452,17 +1651,20 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
/* Duplicate config */ /* Duplicate config */
return 0; return 0;
/* Label change, update clients. */
if (IS_ZEBRA_DEBUG_MPLS) if (IS_ZEBRA_DEBUG_MPLS)
zlog_debug ("Update fec %s new label %u", buf, in_label); zlog_debug ("Update fec %s new label %u", buf, in_label);
fec->label = in_label; fec->label = in_label;
fec_update_clients (fec);
} }
return ret; return ret;
} }
/* /*
* Remove static FEC to label binding. * Remove static FEC to label binding. If there are no clients registered
* for this FEC, delete the FEC; else notify clients
*/ */
int int
zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p) zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
@ -1489,10 +1691,21 @@ zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
zlog_debug ("Delete fec %s", buf); zlog_debug ("Delete fec %s", buf);
} }
fec->flags &= ~FEC_FLAG_CONFIGURED;
fec->label = MPLS_INVALID_LABEL;
/* If no client exists, just delete the FEC. */
if (list_isempty(fec->client_list))
{
fec_del (fec); fec_del (fec);
return 0; return 0;
} }
fec_update_clients (fec);
return 0;
}
/* /*
* Display MPLS FEC to label binding configuration (VTY command handler). * Display MPLS FEC to label binding configuration (VTY command handler).
*/ */

View File

@ -162,6 +162,9 @@ struct zebra_fec_t_
/* Flags. */ /* Flags. */
u_int32_t flags; u_int32_t flags;
#define FEC_FLAG_CONFIGURED (1 << 0) #define FEC_FLAG_CONFIGURED (1 << 0)
/* Clients interested in this FEC. */
struct list *client_list;
}; };
/* Function declarations. */ /* Function declarations. */
@ -180,6 +183,29 @@ char *
mpls_label2str (u_int8_t num_labels, mpls_label_t *labels, mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
char *buf, int len); char *buf, int len);
/*
* Registration from a client for the label binding for a FEC. If a binding
* already exists, it is informed to the client.
*/
int
zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
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);
/*
* Cleanup any FECs registered by this client.
*/
int
zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client);
/* /*
* Return FEC (if any) to which this label is bound. * Return FEC (if any) to which this label is bound.
* Note: Only works for per-prefix binding and when the label is not * Note: Only works for per-prefix binding and when the label is not
@ -197,14 +223,16 @@ int
zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label); zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label);
/* /*
* Add static FEC to label binding. * Add static FEC to label binding. If there are clients registered for this
* FEC, notify them.
*/ */
int int
zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p, zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
mpls_label_t in_label); mpls_label_t in_label);
/* /*
* Remove static FEC to label binding. * Remove static FEC to label binding. If there are no clients registered
* for this FEC, delete the FEC; else notify clients.
*/ */
int int
zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p); zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p);

View File

@ -27,3 +27,138 @@ int kernel_add_lsp (zebra_lsp_t *lsp) { return 0; }
int kernel_upd_lsp (zebra_lsp_t *lsp) { return 0; } int kernel_upd_lsp (zebra_lsp_t *lsp) { return 0; }
int kernel_del_lsp (zebra_lsp_t *lsp) { return 0; } int kernel_del_lsp (zebra_lsp_t *lsp) { return 0; }
int mpls_kernel_init (void) { return -1; }; int mpls_kernel_init (void) { return -1; };
int mpls_enabled;
char *
mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
char *buf, int len)
{
return NULL;
}
int
mpls_str2label (const char *label_str, u_int8_t *num_labels,
mpls_label_t *labels)
{
return 0;
}
void
zebra_mpls_init_tables (struct zebra_vrf *zvrf)
{
}
void
zebra_mpls_print_lsp (struct vty *vty, struct zebra_vrf *zvrf, mpls_label_t label,
u_char use_json)
{
}
void
zebra_mpls_print_lsp_table (struct vty *vty, struct zebra_vrf *zvrf,
u_char use_json)
{
}
int
zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf)
{
return 0;
}
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, char *ifname, ifindex_t ifindex)
{
return 0;
}
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, char *ifname, ifindex_t ifindex)
{
return 0;
}
int
zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
enum nexthop_types_t gtype, union g_addr *gate,
char *ifname, ifindex_t ifindex)
{
return 0;
}
void
zebra_mpls_lsp_schedule (struct zebra_vrf *zvrf)
{
}
void
zebra_mpls_close_tables (struct zebra_vrf *zvrf)
{
}
zebra_fec_t *
zebra_mpls_fec_for_label (struct zebra_vrf *zvrf, mpls_label_t label)
{
return NULL;
}
int
zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label)
{
return 0;
}
int
zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
mpls_label_t in_label)
{
return 0;
}
int
zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
{
return 0;
}
int
zebra_mpls_write_fec_config (struct vty *vty, struct zebra_vrf *zvrf)
{
return 0;
}
void
zebra_mpls_print_fec_table (struct vty *vty, struct zebra_vrf *zvrf)
{
}
void
zebra_mpls_print_fec (struct vty *vty, struct zebra_vrf *zvrf, struct prefix *p)
{
}
int
zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
struct zserv *client)
{
return 0;
}
int
zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p,
struct zserv *client)
{
return 0;
}
int
zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client)
{
return 0;
}

View File

@ -934,6 +934,60 @@ zserv_rnh_unregister (struct zserv *client, int sock, u_short length,
return 0; return 0;
} }
/* FEC register */
static int
zserv_fec_register (struct zserv *client, int sock, u_short length)
{
struct stream *s;
struct zebra_vrf *zvrf;
u_short l = 0;
struct prefix p;
s = client->ibuf;
zvrf = vrf_info_lookup(VRF_DEFAULT);
if (!zvrf)
return 0; // unexpected
while (l < length)
{
p.family = stream_getw(s);
p.prefixlen = stream_getc(s);
l += 5;
stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
l += PSIZE(p.prefixlen);
zebra_mpls_fec_register (zvrf, &p, client);
}
return 0;
}
/* FEC unregister */
static int
zserv_fec_unregister (struct zserv *client, int sock, u_short length)
{
struct stream *s;
struct zebra_vrf *zvrf;
u_short l = 0;
struct prefix p;
s = client->ibuf;
zvrf = vrf_info_lookup(VRF_DEFAULT);
if (!zvrf)
return 0; // unexpected
while (l < length)
{
p.family = stream_getw(s);
p.prefixlen = stream_getc(s);
l += 5;
stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
l += PSIZE(p.prefixlen);
zebra_mpls_fec_unregister (zvrf, &p, client);
}
return 0;
}
/* /*
Modified version of zsend_ipv4_nexthop_lookup(): Modified version of zsend_ipv4_nexthop_lookup():
Query unicast rib if nexthop is not found on mrib. Query unicast rib if nexthop is not found on mrib.
@ -1975,6 +2029,9 @@ zebra_client_close (struct zserv *client)
/* Release Label Manager chunks */ /* Release Label Manager chunks */
release_daemon_chunks (client->proto, client->instance); release_daemon_chunks (client->proto, client->instance);
/* Cleanup any FECs registered by this client. */
zebra_mpls_cleanup_fecs_for_client (vrf_info_lookup(VRF_DEFAULT), client);
/* Close file descriptor. */ /* Close file descriptor. */
if (client->sock) if (client->sock)
{ {
@ -2263,6 +2320,12 @@ zebra_client_read (struct thread *thread)
case ZEBRA_RELEASE_LABEL_CHUNK: case ZEBRA_RELEASE_LABEL_CHUNK:
zread_label_manager_request (command, client, vrf_id); zread_label_manager_request (command, client, vrf_id);
break; break;
case ZEBRA_FEC_REGISTER:
zserv_fec_register (client, sock, length);
break;
case ZEBRA_FEC_UNREGISTER:
zserv_fec_unregister (client, sock, length);
break;
default: default:
zlog_info ("Zebra received unknown command %d", command); zlog_info ("Zebra received unknown command %d", command);
break; break;