From: Don Slice Date: Wed, 1 Feb 2017 18:10:56 +0000 (-0500) Subject: zebra: fec register X-Git-Tag: reindent-master-before~213^2~31 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=5aba114af433e92403859beaa48e133baf93ffc2;p=mirror%2Ffrr.git 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 --- diff --git a/lib/zclient.c b/lib/zclient.c index 71b95ae7db..9e53b66c77 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1867,6 +1867,12 @@ zclient_read (struct thread *thread) if (zclient->interface_link_params) (*zclient->interface_link_params) (command, zclient, length); 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: break; } diff --git a/lib/zclient.h b/lib/zclient.h index d3d0a202c5..a5a1b530c5 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -94,6 +94,9 @@ typedef enum { ZEBRA_LABEL_MANAGER_CONNECT, ZEBRA_GET_LABEL_CHUNK, ZEBRA_RELEASE_LABEL_CHUNK, + ZEBRA_FEC_REGISTER, + ZEBRA_FEC_UNREGISTER, + ZEBRA_FEC_UPDATE, } zebra_message_types_t; 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_ipv6_add) (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. */ diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 3e0de3b463..821264a15e 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -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 \ 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_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 = \ zebra_memory.h \ diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 814d171d9f..366853cc00 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -60,6 +60,10 @@ extern struct zebra_t zebrad; /* 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 fec_print (zebra_fec_t *fec, struct vty *vty); static zebra_fec_t * @@ -148,6 +152,49 @@ mpls_processq_init (struct zebra_t *zebra); /* 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. */ @@ -155,6 +202,8 @@ static void fec_print (zebra_fec_t *fec, struct vty *vty) { struct route_node *rn; + struct listnode *node; + struct zserv *client; char buf[BUFSIZ]; 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, " Label: %s", label2str(fec->label, buf, BUFSIZ)); 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 * 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; fec->rn = rn; fec->label = label; + fec->client_list = list_new(); } else 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 fec_del (zebra_fec_t *fec) { + list_free (fec->client_list); fec->rn->info = NULL; route_unlock_node (fec->rn); XFREE (MTYPE_FEC, fec); @@ -1370,6 +1432,142 @@ mpls_label2str (u_int8_t num_labels, mpls_label_t *labels, 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. * Note: Only works for per-prefix binding and when the label is not @@ -1412,8 +1610,9 @@ 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 zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p, mpls_label_t in_label) @@ -1452,17 +1651,20 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p, /* Duplicate config */ return 0; + /* Label change, update clients. */ if (IS_ZEBRA_DEBUG_MPLS) zlog_debug ("Update fec %s new label %u", buf, in_label); fec->label = in_label; + fec_update_clients (fec); } 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 zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p) @@ -1489,7 +1691,18 @@ zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p) zlog_debug ("Delete fec %s", buf); } - fec_del (fec); + 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); + return 0; + } + + fec_update_clients (fec); + return 0; } diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index 9ff230e5ee..4636a28c10 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -162,6 +162,9 @@ struct zebra_fec_t_ /* Flags. */ u_int32_t flags; #define FEC_FLAG_CONFIGURED (1 << 0) + + /* Clients interested in this FEC. */ + struct list *client_list; }; /* Function declarations. */ @@ -180,6 +183,29 @@ char * mpls_label2str (u_int8_t num_labels, mpls_label_t *labels, 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. * 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); /* - * Add static FEC to label binding. + * Add static FEC to label binding. If there are clients registered for this + * FEC, notify them. */ int zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p, 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 zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p); diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c index 23f5e72956..29990928d3 100644 --- a/zebra/zebra_mpls_null.c +++ b/zebra/zebra_mpls_null.c @@ -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_del_lsp (zebra_lsp_t *lsp) { return 0; } 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; +} + diff --git a/zebra/zserv.c b/zebra/zserv.c index 3477dc36d2..73ea589805 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -934,6 +934,60 @@ zserv_rnh_unregister (struct zserv *client, int sock, u_short length, 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(): 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_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. */ if (client->sock) { @@ -2263,6 +2320,12 @@ zebra_client_read (struct thread *thread) case ZEBRA_RELEASE_LABEL_CHUNK: zread_label_manager_request (command, client, vrf_id); break; + case ZEBRA_FEC_REGISTER: + zserv_fec_register (client, sock, length); + break; + case ZEBRA_FEC_UNREGISTER: + zserv_fec_unregister (client, sock, length); + break; default: zlog_info ("Zebra received unknown command %d", command); break;