From f31e084c7c0e6699926ad72bc4f9a8ca2663f50b Mon Sep 17 00:00:00 2001 From: Don Slice Date: Tue, 27 Dec 2016 07:09:28 -0800 Subject: [PATCH 01/55] 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 --- zebra/zebra_mpls.c | 307 +++++++++++++++++++++++++++++++++++++++++ zebra/zebra_mpls.h | 63 +++++++++ zebra/zebra_mpls_vty.c | 133 ++++++++++++++++++ zebra/zebra_vrf.h | 3 + 4 files changed, 506 insertions(+) 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) From 5aba114af433e92403859beaa48e133baf93ffc2 Mon Sep 17 00:00:00 2001 From: Don Slice Date: Wed, 1 Feb 2017 13:10:56 -0500 Subject: [PATCH 02/55] 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 --- lib/zclient.c | 6 ++ lib/zclient.h | 4 + zebra/Makefile.am | 2 +- zebra/zebra_mpls.c | 225 ++++++++++++++++++++++++++++++++++++++-- zebra/zebra_mpls.h | 32 +++++- zebra/zebra_mpls_null.c | 135 ++++++++++++++++++++++++ zebra/zserv.c | 63 +++++++++++ 7 files changed, 458 insertions(+), 9 deletions(-) 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; From cceb79ac9b05c2f5d3e4a74b9cd11e908ea634ec Mon Sep 17 00:00:00 2001 From: Don Slice Date: Wed, 1 Feb 2017 13:19:37 -0500 Subject: [PATCH 03/55] bgpd: update debugs enance Add information about AFI/SAFI to updates - received and sent. Signed-off-by: Don Slice --- bgpd/bgp_updgrp_packet.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 8839de391e..57e5c07029 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -783,6 +783,17 @@ subgroup_update_packet (struct update_subgroup *subgrp) { zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE w/ attr: %s", subgrp->update_group->id, subgrp->id, send_attr_str); + if (!stream_empty (snlri)) + { + afi_t pkt_afi; + safi_t pkt_safi; + + pkt_afi = afi_int2iana (afi); + pkt_safi = safi_int2iana (safi); + zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send MP_REACH for afi/safi %d/%d", + subgrp->update_group->id, subgrp->id, pkt_afi, pkt_safi); + } + send_attr_printed = 1; } @@ -824,7 +835,7 @@ subgroup_update_packet (struct update_subgroup *subgrp) packet = stream_dup (s); bgp_packet_set_size (packet); if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0)) - zlog_debug ("u%" PRIu64 ":s%" PRIu64 " UPDATE len %zd numpfx %d", + zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE len %zd numpfx %d", subgrp->update_group->id, subgrp->id, (stream_get_endp(packet) - stream_get_getp(packet)), num_pfx); pkt = bpacket_queue_add (SUBGRP_PKTQ (subgrp), packet, &vecarr); @@ -917,11 +928,20 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp) /* If first time, format the MP_UNREACH header */ if (first_time) { + afi_t pkt_afi; + safi_t pkt_safi; + + pkt_afi = afi_int2iana (afi); + pkt_safi = safi_int2iana (safi); + attrlen_pos = stream_get_endp (s); /* total attr length = 0 for now. reevaluate later */ stream_putw (s, 0); mp_start = stream_get_endp (s); mplen_pos = bgp_packet_mpunreach_start (s, afi, safi); + if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0)) + zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send MP_UNREACH for afi/safi %d/%d", + subgrp->update_group->id, subgrp->id, pkt_afi, pkt_safi); } bgp_packet_mpunreach_prefix (s, &rn->p, afi, safi, prd, NULL, @@ -968,7 +988,7 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp) } bgp_packet_set_size (s); if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0)) - zlog_debug ("u%" PRIu64 ":s%" PRIu64 " UPDATE (withdraw) len %zd numpfx %d", + zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE (withdraw) len %zd numpfx %d", subgrp->update_group->id, subgrp->id, (stream_get_endp(s) - stream_get_getp(s)), num_pfx); pkt = bpacket_queue_add (SUBGRP_PKTQ (subgrp), stream_dup (s), NULL); From a64448baa6150a7431d55e0e65d0b51d62c4b5be Mon Sep 17 00:00:00 2001 From: Don Slice Date: Thu, 2 Feb 2017 12:58:33 -0500 Subject: [PATCH 04/55] zebra: labeled unicast handling Support install of labeled-unicast routes by a client. This would be BGP, in order to install routes corresponding to AFI/SAFI 1/4 (IPv4) or 2/4 (IPv6). Convert labeled-unicast routes into label forwarding entries (i.e., transit LSPs) when there is a static label binding. Signed-off-by: Don Slice --- lib/mpls.h | 3 +- lib/nexthop.c | 22 +++ lib/nexthop.h | 1 + lib/zclient.c | 47 ++++- lib/zclient.h | 7 + lib/zebra.h | 4 +- zebra/rib.h | 2 +- zebra/zebra_mpls.c | 384 ++++++++++++++++++++++++++++++++++++---- zebra/zebra_mpls.h | 29 ++- zebra/zebra_mpls_null.c | 18 +- zebra/zebra_mpls_vty.c | 6 +- zebra/zebra_rib.c | 47 ++++- zebra/zserv.c | 60 +++++-- 13 files changed, 564 insertions(+), 66 deletions(-) diff --git a/lib/mpls.h b/lib/mpls.h index 13a46e1012..5a91883753 100644 --- a/lib/mpls.h +++ b/lib/mpls.h @@ -85,7 +85,8 @@ enum lsp_types_t { ZEBRA_LSP_NONE = 0, /* No LSP. */ ZEBRA_LSP_STATIC = 1, /* Static LSP. */ - ZEBRA_LSP_LDP = 2 /* LDP LSP. */ + ZEBRA_LSP_LDP = 2, /* LDP LSP. */ + ZEBRA_LSP_BGP = 3 /* BGP LSP. */ }; /* Functions for basic label operations. */ diff --git a/lib/nexthop.c b/lib/nexthop.c index 7b8ac95e83..a6420fea33 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -92,6 +92,28 @@ nexthop_type_to_str (enum nexthop_types_t nh_type) return desc[nh_type]; } +/* + * Check if the labels match for the 2 nexthops specified. + */ +int +nexthop_labels_match (struct nexthop *nh1, struct nexthop *nh2) +{ + struct nexthop_label *nhl1, *nhl2; + + nhl1 = nh1->nh_label; + nhl2 = nh2->nh_label; + if ((nhl1 && !nhl2) || (!nhl1 && nhl2)) + return 0; + + if (nhl1->num_labels != nhl2->num_labels) + return 0; + + if (memcmp (nhl1->label, nhl2->label, nhl1->num_labels)) + return 0; + + return 1; +} + struct nexthop * nexthop_new (void) { diff --git a/lib/nexthop.h b/lib/nexthop.h index e66e0eee20..83c5b850b8 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -117,6 +117,7 @@ void nexthop_del_labels (struct nexthop *); extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type); extern int nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2); +extern int nexthop_labels_match (struct nexthop *nh1, struct nexthop *nh2); extern const char * nexthop2str (struct nexthop *nexthop, char *str, int size); #endif /*_LIB_NEXTHOP_H */ diff --git a/lib/zclient.c b/lib/zclient.c index 9e53b66c77..541a5444cf 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -733,6 +733,18 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, s = zclient->obuf; stream_reset (s); + /* Some checks for labeled-unicast. The current expectation is that each + * nexthop is accompanied by a label in the case of labeled-unicast. + */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) && + CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) + { + /* We expect prefixes installed with labels and the number to match + * the number of nexthops. + */ + assert (api->label_num == api->nexthop_num); + } + zclient_create_header (s, cmd, api->vrf_id); /* Put type and nexthop. */ @@ -749,7 +761,7 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, /* Nexthop, ifindex, distance and metric information. */ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) - { + { /* traditional 32-bit data units */ if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE)) { @@ -765,6 +777,9 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, { stream_putc (s, NEXTHOP_TYPE_IPV4); stream_put_in_addr (s, api->nexthop[i]); + /* For labeled-unicast, each nexthop is followed by label. */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL)) + stream_putl (s, api->label[i]); } for (i = 0; i < api->ifindex_num; i++) { @@ -800,6 +815,18 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient, s = zclient->obuf; stream_reset (s); + /* Some checks for labeled-unicast. The current expectation is that each + * nexthop is accompanied by a label in the case of labeled-unicast. + */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) && + CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) + { + /* We expect prefixes installed with labels and the number to match + * the number of nexthops. + */ + assert (api->label_num == api->nexthop_num); + } + zclient_create_header (s, cmd, api->vrf_id); /* Put type and nexthop. */ @@ -831,6 +858,9 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient, { stream_putc (s, NEXTHOP_TYPE_IPV6); stream_write (s, (u_char *)api->nexthop[i], 16); + /* For labeled-unicast, each nexthop is followed by label. */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL)) + stream_putl (s, api->label[i]); } for (i = 0; i < api->ifindex_num; i++) { @@ -869,6 +899,18 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, s = zclient->obuf; stream_reset (s); + /* Some checks for labeled-unicast. The current expectation is that each + * nexthop is accompanied by a label in the case of labeled-unicast. + */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) && + CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) + { + /* We expect prefixes installed with labels and the number to match + * the number of nexthops. + */ + assert (api->label_num == api->nexthop_num); + } + zclient_create_header (s, cmd, api->vrf_id); /* Put type and nexthop. */ @@ -907,6 +949,9 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, { stream_putc (s, NEXTHOP_TYPE_IPV6); stream_write (s, (u_char *)api->nexthop[i], 16); + /* For labeled-unicast, each nexthop is followed by label. */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL)) + stream_putl (s, api->label[i]); } for (i = 0; i < api->ifindex_num; i++) { diff --git a/lib/zclient.h b/lib/zclient.h index a5a1b530c5..a54bf420d3 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -178,6 +178,7 @@ struct zclient #define ZAPI_MESSAGE_TAG 0x10 #define ZAPI_MESSAGE_MTU 0x20 #define ZAPI_MESSAGE_SRCPFX 0x40 +#define ZAPI_MESSAGE_LABEL 0x80 /* Zserv protocol message header */ struct zserv_header @@ -210,6 +211,9 @@ struct zapi_ipv4 u_char ifindex_num; ifindex_t *ifindex; + u_char label_num; + unsigned int *label; + u_char distance; u_int32_t metric; @@ -301,6 +305,9 @@ struct zapi_ipv6 u_char ifindex_num; ifindex_t *ifindex; + u_char label_num; + unsigned int *label; + u_char distance; u_int32_t metric; diff --git a/lib/zebra.h b/lib/zebra.h index 760264d752..985382bff5 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -413,11 +413,13 @@ typedef enum { #define SAFI_ENCAP 5 #define SAFI_RESERVED_5 5 #define SAFI_EVPN 6 -#define SAFI_MAX 7 +#define SAFI_LABELED_UNICAST 7 +#define SAFI_MAX 8 #define IANA_SAFI_RESERVED 0 #define IANA_SAFI_UNICAST 1 #define IANA_SAFI_MULTICAST 2 +#define IANA_SAFI_LABELED_UNICAST 4 #define IANA_SAFI_ENCAP 7 #define IANA_SAFI_MPLS_VPN 128 diff --git a/zebra/rib.h b/zebra/rib.h index 5381d76b98..8f6cff0d8a 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -372,7 +372,7 @@ extern void rib_init (void); extern unsigned long rib_score_proto (u_char proto, u_short instance); extern void rib_queue_add (struct route_node *rn); extern void meta_queue_free (struct meta_queue *mq); - +extern int zebra_rib_labeled_unicast (struct rib *rib); extern struct route_table *rib_table_ipv6; extern void rib_unlink (struct route_node *, struct rib *); diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 366853cc00..f13a3f4f0a 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -60,6 +60,13 @@ extern struct zebra_t zebrad; /* static function declarations */ +static int +lsp_install (struct zebra_vrf *zvrf, mpls_label_t label, + struct route_node *rn, struct rib *rib); +static int +lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t label); +static int +fec_change_update_lsp (struct zebra_vrf *zvrf, zebra_fec_t *fec, mpls_label_t old_label); static int fec_send (zebra_fec_t *fec, struct zserv *client); static void @@ -69,7 +76,7 @@ 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, +fec_add (struct route_table *table, struct prefix *p, mpls_label_t label, u_int32_t flags); static int fec_del (zebra_fec_t *fec); @@ -106,17 +113,19 @@ static char * nhlfe2str (zebra_nhlfe_t *nhlfe, char *buf, int size); static int nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype, - union g_addr *gate, char *ifname, ifindex_t ifindex); + union g_addr *gate, ifindex_t ifindex); static zebra_nhlfe_t * nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type, enum nexthop_types_t gtype, union g_addr *gate, - char *ifname, ifindex_t ifindex); + ifindex_t ifindex); static zebra_nhlfe_t * nhlfe_add (zebra_lsp_t *lsp, enum lsp_types_t lsp_type, enum nexthop_types_t gtype, union g_addr *gate, - char *ifname, ifindex_t ifindex, mpls_label_t out_label); + ifindex_t ifindex, mpls_label_t out_label); static int nhlfe_del (zebra_nhlfe_t *snhlfe); +static void +nhlfe_out_label_update (zebra_nhlfe_t *nhlfe, struct nexthop_label *nh_label); static int mpls_lsp_uninstall_all (struct hash *lsp_table, zebra_lsp_t *lsp, enum lsp_types_t type); @@ -130,14 +139,13 @@ static void * slsp_alloc (void *p); static int snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype, - union g_addr *gate, char *ifname, ifindex_t ifindex); + union g_addr *gate, ifindex_t ifindex); static zebra_snhlfe_t * snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype, - union g_addr *gate, char *ifname, ifindex_t ifindex); + union g_addr *gate, ifindex_t ifindex); static zebra_snhlfe_t * snhlfe_add (zebra_slsp_t *slsp, enum nexthop_types_t gtype, - union g_addr *gate, char *ifname, ifindex_t ifindex, - mpls_label_t out_label); + union g_addr *gate, ifindex_t ifindex, mpls_label_t out_label); static int snhlfe_del (zebra_snhlfe_t *snhlfe); static int @@ -152,6 +160,245 @@ mpls_processq_init (struct zebra_t *zebra); /* Static functions */ +/* + * Install label forwarding entry based on labeled-route entry. + */ +static int +lsp_install (struct zebra_vrf *zvrf, mpls_label_t label, + struct route_node *rn, struct rib *rib) +{ + struct hash *lsp_table; + zebra_ile_t tmp_ile; + zebra_lsp_t *lsp; + zebra_nhlfe_t *nhlfe; + struct nexthop *nexthop; + enum lsp_types_t lsp_type; + char buf[BUFSIZ]; + int added, changed; + + /* Lookup table. */ + lsp_table = zvrf->lsp_table; + if (!lsp_table) + return -1; + + /* See if route entry is selected; we really expect only 1 entry here. */ + if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + return 0; + + lsp_type = lsp_type_from_rib_type (rib->type); + added = changed = 0; + + /* Locate or allocate LSP entry. */ + tmp_ile.in_label = label; + lsp = hash_get (lsp_table, &tmp_ile, lsp_alloc); + if (!lsp) + return -1; + + /* For each active nexthop, create NHLFE. Note that we deliberately skip + * recursive nexthops right now, because intermediate hops won't understand + * the label advertised by the recursive nexthop (plus we don't have the + * logic yet to push multiple labels). + */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + /* Skip inactive and recursive entries. */ + if (!CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + continue; + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + continue; + + nhlfe = nhlfe_find (lsp, lsp_type, nexthop->type, &nexthop->gate, + nexthop->ifindex); + if (nhlfe) + { + /* Clear deleted flag (in case it was set) */ + UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED); + if (nexthop_labels_match (nhlfe->nexthop, nexthop)) + /* No change */ + continue; + + + if (IS_ZEBRA_DEBUG_MPLS) + { + nhlfe2str (nhlfe, buf, BUFSIZ); + zlog_debug ("LSP in-label %u type %d nexthop %s " + "out-label changed", + lsp->ile.in_label, lsp_type, buf); + } + + /* Update out label, trigger processing. */ + nhlfe_out_label_update (nhlfe, nexthop->nh_label); + SET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED); + changed++; + } + else + { + /* Add LSP entry to this nexthop */ + nhlfe = nhlfe_add (lsp, lsp_type, nexthop->type, + &nexthop->gate, nexthop->ifindex, + nexthop->nh_label->label[0]); + if (!nhlfe) + return -1; + + if (IS_ZEBRA_DEBUG_MPLS) + { + nhlfe2str (nhlfe, buf, BUFSIZ); + zlog_debug ("Add LSP in-label %u type %d nexthop %s " + "out-label %u", + lsp->ile.in_label, lsp_type, buf, + nexthop->nh_label->label[0]); + } + + lsp->addr_family = NHLFE_FAMILY (nhlfe); + + /* Mark NHLFE as changed. */ + SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED); + added++; + } + } + + /* Queue LSP for processing if necessary. If no NHLFE got added (special + * case), delete the LSP entry; this case results in somewhat ugly logging. + */ + if (added || changed) + { + if (lsp_processq_add (lsp)) + return -1; + } + else if (!lsp->nhlfe_list && + !CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED)) + { + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug ("Free LSP in-label %u flags 0x%x", + lsp->ile.in_label, lsp->flags); + + lsp = hash_release(lsp_table, &lsp->ile); + if (lsp) + XFREE(MTYPE_LSP, lsp); + } + + return 0; +} + +/* + * Uninstall all non-static NHLFEs of a label forwarding entry. If all + * NHLFEs are removed, the entire entry is deleted. + */ +static int +lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t label) +{ + struct hash *lsp_table; + zebra_ile_t tmp_ile; + zebra_lsp_t *lsp; + zebra_nhlfe_t *nhlfe, *nhlfe_next; + char buf[BUFSIZ]; + + /* Lookup table. */ + lsp_table = zvrf->lsp_table; + if (!lsp_table) + return -1; + + /* If entry is not present, exit. */ + tmp_ile.in_label = label; + lsp = hash_lookup (lsp_table, &tmp_ile); + if (!lsp || !lsp->nhlfe_list) + return 0; + + /* Mark NHLFEs for delete or directly delete, as appropriate. */ + for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next) + { + nhlfe_next = nhlfe->next; + + /* Skip static NHLFEs */ + if (nhlfe->type == ZEBRA_LSP_STATIC) + continue; + + if (IS_ZEBRA_DEBUG_MPLS) + { + nhlfe2str (nhlfe, buf, BUFSIZ); + zlog_debug ("Del LSP in-label %u type %d nexthop %s flags 0x%x", + label, nhlfe->type, buf, nhlfe->flags); + } + + if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)) + { + UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED); + SET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED); + } + else + { + nhlfe_del (nhlfe); + } + } + + /* Queue LSP for processing, if needed, else delete. */ + if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) + { + if (lsp_processq_add (lsp)) + return -1; + } + else if (!lsp->nhlfe_list && + !CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED)) + { + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug ("Del LSP in-label %u flags 0x%x", + lsp->ile.in_label, lsp->flags); + + lsp = hash_release(lsp_table, &lsp->ile); + if (lsp) + XFREE(MTYPE_LSP, lsp); + } + + return 0; +} + +/* + * There is a change for this FEC. Install or uninstall label forwarding + * entries, as appropriate. + */ +static int +fec_change_update_lsp (struct zebra_vrf *zvrf, zebra_fec_t *fec, mpls_label_t old_label) +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + afi_t afi; + + /* Uninstall label forwarding entry, if previously installed. */ + if (old_label != MPLS_INVALID_LABEL && + old_label != MPLS_IMP_NULL_LABEL) + lsp_uninstall (zvrf, old_label); + + /* Install label forwarding entry corr. to new label, if needed. */ + if (fec->label == MPLS_INVALID_LABEL || + fec->label == MPLS_IMP_NULL_LABEL) + return 0; + + afi = family2afi(PREFIX_FAMILY(&fec->rn->p)); + table = zebra_vrf_table (afi, SAFI_UNICAST, zvrf_id (zvrf)); + if (!table) + return 0; + + /* See if labeled route exists. */ + rn = route_node_lookup (table, &fec->rn->p); + if (!rn) + return 0; + + RNODE_FOREACH_RIB (rn, rib) + { + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + break; + } + + if (!rib || !zebra_rib_labeled_unicast (rib)) + return 0; + + if (lsp_install (zvrf, fec->label, rn, rib)) + return -1; + + return 0; +} + /* * Inform about FEC to a registered client. */ @@ -760,7 +1007,7 @@ nhlfe2str (zebra_nhlfe_t *nhlfe, char *buf, int size) */ static int nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype, - union g_addr *gate, char *ifname, ifindex_t ifindex) + union g_addr *gate, ifindex_t ifindex) { struct nexthop *nhop; int cmp = 1; @@ -802,7 +1049,7 @@ nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype, static zebra_nhlfe_t * nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type, enum nexthop_types_t gtype, union g_addr *gate, - char *ifname, ifindex_t ifindex) + ifindex_t ifindex) { zebra_nhlfe_t *nhlfe; @@ -813,7 +1060,7 @@ nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type, { if (nhlfe->type != lsp_type) continue; - if (!nhlfe_nhop_match (nhlfe, gtype, gate, ifname, ifindex)) + if (!nhlfe_nhop_match (nhlfe, gtype, gate, ifindex)) break; } @@ -827,7 +1074,7 @@ nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type, static zebra_nhlfe_t * nhlfe_add (zebra_lsp_t *lsp, enum lsp_types_t lsp_type, enum nexthop_types_t gtype, union g_addr *gate, - char *ifname, ifindex_t ifindex, mpls_label_t out_label) + ifindex_t ifindex, mpls_label_t out_label) { zebra_nhlfe_t *nhlfe; struct nexthop *nexthop; @@ -917,6 +1164,15 @@ nhlfe_del (zebra_nhlfe_t *nhlfe) return 0; } +/* + * Update label for NHLFE entry. + */ +static void +nhlfe_out_label_update (zebra_nhlfe_t *nhlfe, struct nexthop_label *nh_label) +{ + nhlfe->nexthop->nh_label->label[0] = nh_label->label[0]; +} + static int mpls_lsp_uninstall_all (struct hash *lsp_table, zebra_lsp_t *lsp, enum lsp_types_t type) @@ -1184,7 +1440,7 @@ slsp_cmp (zebra_slsp_t *slsp1, zebra_slsp_t *slsp2) */ static int snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype, - union g_addr *gate, char *ifname, ifindex_t ifindex) + union g_addr *gate, ifindex_t ifindex) { int cmp = 1; @@ -1216,7 +1472,7 @@ snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype, */ static zebra_snhlfe_t * snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype, - union g_addr *gate, char *ifname, ifindex_t ifindex) + union g_addr *gate, ifindex_t ifindex) { zebra_snhlfe_t *snhlfe; @@ -1225,7 +1481,7 @@ snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype, for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next) { - if (!snhlfe_match (snhlfe, gtype, gate, ifname, ifindex)) + if (!snhlfe_match (snhlfe, gtype, gate, ifindex)) break; } @@ -1239,7 +1495,7 @@ snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype, */ static zebra_snhlfe_t * snhlfe_add (zebra_slsp_t *slsp, enum nexthop_types_t gtype, - union g_addr *gate, char *ifname, ifindex_t ifindex, + union g_addr *gate, ifindex_t ifindex, mpls_label_t out_label) { zebra_snhlfe_t *snhlfe; @@ -1388,7 +1644,7 @@ mpls_str2label (const char *label_str, u_int8_t *num_labels, *num_labels = 0; for (i = 0; i < MPLS_MAX_LABELS; i++) { - u_int32_t label; + mpls_label_t label; label = strtoul(label_str, &endp, 0); @@ -1432,6 +1688,58 @@ mpls_label2str (u_int8_t num_labels, mpls_label_t *labels, return buf; } +/* + * Install dynamic LSP entry. + */ +int +zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib) +{ + struct route_table *table; + zebra_fec_t *fec; + + table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))]; + if (!table) + return -1; + + /* See if there is a configured label binding for this FEC. */ + fec = fec_find (table, &rn->p); + if (!fec || fec->label == MPLS_INVALID_LABEL) + return 0; + + /* We cannot install a label forwarding entry if local label is the + * implicit-null label. + */ + if (fec->label == MPLS_IMP_NULL_LABEL) + return 0; + + if (lsp_install (zvrf, fec->label, rn, rib)) + return -1; + + return 0; +} + +/* + * Uninstall dynamic LSP entry, if any. + */ +int +zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib) +{ + struct route_table *table; + zebra_fec_t *fec; + + table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))]; + if (!table) + return -1; + + /* See if there is a configured label binding for this FEC. */ + fec = fec_find (table, &rn->p); + if (!fec || fec->label == MPLS_INVALID_LABEL) + return 0; + + /* Uninstall always removes all dynamic NHLFEs. */ + return lsp_uninstall (zvrf, fec->label); +} + /* * Registration from a client for the label binding for a FEC. If a binding * already exists, it is informed to the client. @@ -1611,7 +1919,8 @@ 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. + * 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, @@ -1620,6 +1929,7 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p, struct route_table *table; zebra_fec_t *fec; char buf[BUFSIZ]; + mpls_label_t old_label; int ret = 0; table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))]; @@ -1652,11 +1962,15 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p, return 0; /* Label change, update clients. */ + old_label = fec->label; if (IS_ZEBRA_DEBUG_MPLS) zlog_debug ("Update fec %s new label %u", buf, in_label); fec->label = in_label; fec_update_clients (fec); + + /* Update label forwarding entries appropriately */ + ret = fec_change_update_lsp (zvrf, fec, old_label); } return ret; @@ -1671,6 +1985,7 @@ zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p) { struct route_table *table; zebra_fec_t *fec; + mpls_label_t old_label; char buf[BUFSIZ]; table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))]; @@ -1691,6 +2006,7 @@ zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p) zlog_debug ("Delete fec %s", buf); } + old_label = fec->label; fec->flags &= ~FEC_FLAG_CONFIGURED; fec->label = MPLS_INVALID_LABEL; @@ -1703,7 +2019,8 @@ zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p) fec_update_clients (fec); - return 0; + /* Update label forwarding entries appropriately */ + return fec_change_update_lsp (zvrf, fec, old_label); } /* @@ -1879,7 +2196,7 @@ int mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type, mpls_label_t in_label, mpls_label_t out_label, enum nexthop_types_t gtype, union g_addr *gate, - char *ifname, ifindex_t ifindex) + ifindex_t ifindex) { struct hash *lsp_table; zebra_ile_t tmp_ile; @@ -1897,7 +2214,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type, lsp = hash_get (lsp_table, &tmp_ile, lsp_alloc); if (!lsp) return -1; - nhlfe = nhlfe_find (lsp, type, gtype, gate, ifname, ifindex); + nhlfe = nhlfe_find (lsp, type, gtype, gate, ifindex); if (nhlfe) { struct nexthop *nh = nhlfe->nexthop; @@ -1926,8 +2243,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type, else { /* Add LSP entry to this nexthop */ - nhlfe = nhlfe_add (lsp, type, gtype, gate, - ifname, ifindex, out_label); + nhlfe = nhlfe_add (lsp, type, gtype, gate, ifindex, out_label); if (!nhlfe) return -1; @@ -1956,7 +2272,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type, int mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type, mpls_label_t in_label, enum nexthop_types_t gtype, - union g_addr *gate, char *ifname, ifindex_t ifindex) + union g_addr *gate, ifindex_t ifindex) { struct hash *lsp_table; zebra_ile_t tmp_ile; @@ -1974,7 +2290,7 @@ mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type, lsp = hash_lookup (lsp_table, &tmp_ile); if (!lsp) return 0; - nhlfe = nhlfe_find (lsp, type, gtype, gate, ifname, ifindex); + nhlfe = nhlfe_find (lsp, type, gtype, gate, ifindex); if (!nhlfe) return 0; @@ -2079,7 +2395,7 @@ mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi) 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) + union g_addr *gate, ifindex_t ifindex) { struct hash *slsp_table; zebra_ile_t tmp_ile; @@ -2097,7 +2413,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label, if (!slsp) return 1; - snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex); + snhlfe = snhlfe_find (slsp, gtype, gate, ifindex); if (snhlfe) { if (snhlfe->out_label == out_label) @@ -2137,7 +2453,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label, 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) + union g_addr *gate, ifindex_t ifindex) { struct hash *slsp_table; zebra_ile_t tmp_ile; @@ -2155,7 +2471,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label, slsp = hash_get (slsp_table, &tmp_ile, slsp_alloc); if (!slsp) return -1; - snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex); + snhlfe = snhlfe_find (slsp, gtype, gate, ifindex); if (snhlfe) { if (snhlfe->out_label == out_label) @@ -2174,7 +2490,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label, else { /* Add static LSP entry to this nexthop */ - snhlfe = snhlfe_add (slsp, gtype, gate, ifname, ifindex, out_label); + snhlfe = snhlfe_add (slsp, gtype, gate, ifindex, out_label); if (!snhlfe) return -1; @@ -2188,7 +2504,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label, /* (Re)Install LSP in the main table. */ if (mpls_lsp_install (zvrf, ZEBRA_LSP_STATIC, in_label, out_label, gtype, - gate, ifname, ifindex)) + gate, ifindex)) return -1; return 0; @@ -2204,7 +2520,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label, 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) + ifindex_t ifindex) { struct hash *slsp_table; zebra_ile_t tmp_ile; @@ -2237,7 +2553,7 @@ zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label, else { /* Find specific NHLFE, exit if not found. */ - snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex); + snhlfe = snhlfe_find (slsp, gtype, gate, ifindex); if (!snhlfe) return 0; @@ -2251,7 +2567,7 @@ zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label, /* Uninstall LSP from the main table. */ mpls_lsp_uninstall (zvrf, ZEBRA_LSP_STATIC, in_label, gtype, gate, - ifname, ifindex); + ifindex); /* Delete static LSP NHLFE */ snhlfe_del (snhlfe); diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index 4636a28c10..f9d58a46e8 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -183,6 +183,18 @@ char * mpls_label2str (u_int8_t num_labels, mpls_label_t *labels, char *buf, int len); +/* + * Install dynamic LSP entry. + */ +int +zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib); + +/* + * Uninstall dynamic LSP entry, if any. + */ +int +zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib); + /* * Registration from a client for the label binding for a FEC. If a binding * already exists, it is informed to the client. @@ -224,7 +236,8 @@ 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. + * 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, @@ -273,7 +286,7 @@ int mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type, mpls_label_t in_label, mpls_label_t out_label, enum nexthop_types_t gtype, union g_addr *gate, - char *ifname, ifindex_t ifindex); + ifindex_t ifindex); /* * Uninstall a particular NHLFE in the forwarding table. If this is @@ -282,7 +295,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type, int mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type, mpls_label_t in_label, enum nexthop_types_t gtype, - union g_addr *gate, char *ifname, ifindex_t ifindex); + union g_addr *gate, ifindex_t ifindex); /* * Uninstall all LDP NHLFEs for a particular LSP forwarding entry. @@ -307,7 +320,7 @@ mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi); 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); + union g_addr *gate, ifindex_t ifindex); #endif /* HAVE_CUMULUS */ /* @@ -320,7 +333,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label, 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); + union g_addr *gate, ifindex_t ifindex); /* * Delete static LSP entry. This may be the delete of one particular @@ -332,7 +345,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label, 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); + ifindex_t ifindex); /* * Schedule all MPLS label forwarding entries for processing. @@ -415,6 +428,8 @@ lsp_type_from_rib_type (int rib_type) { case ZEBRA_ROUTE_STATIC: return ZEBRA_LSP_STATIC; + case ZEBRA_ROUTE_BGP: + return ZEBRA_LSP_BGP; default: return ZEBRA_LSP_NONE; } @@ -430,6 +445,8 @@ nhlfe_type2str(enum lsp_types_t lsp_type) return "Static"; case ZEBRA_LSP_LDP: return "LDP"; + case ZEBRA_LSP_BGP: + return "BGP"; default: return "Unknown"; } diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c index 29990928d3..d6f99b5178 100644 --- a/zebra/zebra_mpls_null.c +++ b/zebra/zebra_mpls_null.c @@ -44,6 +44,18 @@ mpls_str2label (const char *label_str, u_int8_t *num_labels, return 0; } +int +zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib) +{ + return 0; +} + +int +zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib) +{ + return 0; +} + void zebra_mpls_init_tables (struct zebra_vrf *zvrf) { @@ -70,7 +82,7 @@ zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf) 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) + union g_addr *gate, ifindex_t ifindex) { return 0; } @@ -78,7 +90,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label, 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) + union g_addr *gate, ifindex_t ifindex) { return 0; } @@ -86,7 +98,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label, 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) + ifindex_t ifindex) { return 0; } diff --git a/zebra/zebra_mpls_vty.c b/zebra/zebra_mpls_vty.c index 90624c12a4..8d8025682a 100644 --- a/zebra/zebra_mpls_vty.c +++ b/zebra/zebra_mpls_vty.c @@ -133,7 +133,7 @@ zebra_mpls_transit_lsp (struct vty *vty, int add_cmd, const char *inlabel_str, #if defined(HAVE_CUMULUS) /* Check that label value is consistent. */ if (!zebra_mpls_lsp_label_consistent (zvrf, in_label, out_label, gtype, - &gate, NULL, 0)) + &gate, 0)) { vty_out (vty, "%% Label value not consistent%s", VTY_NEWLINE); @@ -142,10 +142,10 @@ zebra_mpls_transit_lsp (struct vty *vty, int add_cmd, const char *inlabel_str, #endif /* HAVE_CUMULUS */ ret = zebra_mpls_static_lsp_add (zvrf, in_label, out_label, gtype, - &gate, NULL, 0); + &gate, 0); } else - ret = zebra_mpls_static_lsp_del (zvrf, in_label, gtype, &gate, NULL, 0); + ret = zebra_mpls_static_lsp_del (zvrf, in_label, gtype, &gate, 0); if (ret) { diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index b3e70e46fa..e4d583d5f2 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1084,7 +1084,25 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) return rib->nexthop_active_num; } +/* + * Is this RIB labeled-unicast? It must be of type BGP and all paths + * (nexthops) must have a label. + */ +int +zebra_rib_labeled_unicast (struct rib *rib) +{ + struct nexthop *nexthop = NULL, *tnexthop; + int recursing; + if (rib->type != ZEBRA_ROUTE_BGP) + return 0; + + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) + if (!nexthop->nh_label || !nexthop->nh_label->num_labels) + return 0; + + return 1; +} /* Update flag indicates whether this is a "replace" or not. Currently, this * is only used for IPv4. @@ -1177,7 +1195,12 @@ rib_uninstall (struct route_node *rn, struct rib *rib) if (! RIB_SYSTEM_ROUTE (rib)) rib_uninstall_kernel (rn, rib); - UNSET_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB); + + /* If labeled-unicast route, uninstall transit LSP. */ + if (zebra_rib_labeled_unicast (rib)) + zebra_mpls_lsp_uninstall (info->zvrf, rn, rib); + + UNSET_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB); } if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) @@ -1272,6 +1295,10 @@ rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, zvrf_id (zvrf), buf, rn, new, new->type); } + /* If labeled-unicast route, install transit LSP. */ + if (zebra_rib_labeled_unicast (new)) + zebra_mpls_lsp_install (zvrf, rn, new); + if (!RIB_SYSTEM_ROUTE (new)) { if (rib_install_kernel (rn, new, NULL)) @@ -1301,6 +1328,10 @@ rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn, zvrf_id (zvrf), buf, rn, old, old->type); } + /* If labeled-unicast route, uninstall transit LSP. */ + if (zebra_rib_labeled_unicast (old)) + zebra_mpls_lsp_uninstall (zvrf, rn, old); + if (!RIB_SYSTEM_ROUTE (old)) rib_uninstall_kernel (rn, old); @@ -1354,6 +1385,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn, /* Non-system route should be installed. */ if (!RIB_SYSTEM_ROUTE (new)) { + /* If labeled-unicast route, install transit LSP. */ + if (zebra_rib_labeled_unicast (new)) + zebra_mpls_lsp_install (zvrf, rn, new); + if (rib_install_kernel (rn, new, old)) { char buf[SRCDEST2STR_BUFFER]; @@ -1368,6 +1403,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn, { if (RIB_SYSTEM_ROUTE(new)) { + /* If labeled-unicast route, uninstall transit LSP. */ + if (zebra_rib_labeled_unicast (old)) + zebra_mpls_lsp_uninstall (zvrf, rn, old); + if (!RIB_SYSTEM_ROUTE (old)) rib_uninstall_kernel (rn, old); } @@ -1404,6 +1443,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn, nh_active ? "install failed" : "nexthop inactive"); } + /* If labeled-unicast route, uninstall transit LSP. */ + if (zebra_rib_labeled_unicast (old)) + zebra_mpls_lsp_uninstall (zvrf, rn, old); + if (!RIB_SYSTEM_ROUTE (old)) rib_uninstall_kernel (rn, old); UNSET_FLAG (new->status, RIB_ENTRY_SELECTED_FIB); @@ -2934,8 +2977,10 @@ rib_tables_iter_next (rib_tables_iter_t *iter) } afi_safis[] = { { AFI_IP, SAFI_UNICAST }, { AFI_IP, SAFI_MULTICAST }, + { AFI_IP, SAFI_LABELED_UNICAST }, { AFI_IP6, SAFI_UNICAST }, { AFI_IP6, SAFI_MULTICAST }, + { AFI_IP6, SAFI_LABELED_UNICAST }, }; table = NULL; diff --git a/zebra/zserv.c b/zebra/zserv.c index 73ea589805..c11f1bf3fd 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1129,13 +1129,15 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) struct rib *rib; struct prefix p; u_char message; - struct in_addr nexthop; + struct in_addr nhop_addr; u_char nexthop_num; u_char nexthop_type; struct stream *s; ifindex_t ifindex; safi_t safi; int ret; + mpls_label_t label; + struct nexthop *nexthop; /* Get input stream. */ s = client->ibuf; @@ -1177,13 +1179,19 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) rib_nexthop_ifindex_add (rib, ifindex); break; case NEXTHOP_TYPE_IPV4: - nexthop.s_addr = stream_get_ipv4 (s); - rib_nexthop_ipv4_add (rib, &nexthop, NULL); + nhop_addr.s_addr = stream_get_ipv4 (s); + nexthop = rib_nexthop_ipv4_add (rib, &nhop_addr, NULL); + /* For labeled-unicast, each nexthop is followed by label. */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL)) + { + label = (mpls_label_t)stream_getl (s); + nexthop_add_labels (nexthop, nexthop->nh_label_type, 1, &label); + } break; case NEXTHOP_TYPE_IPV4_IFINDEX: - nexthop.s_addr = stream_get_ipv4 (s); + nhop_addr.s_addr = stream_get_ipv4 (s); ifindex = stream_getl (s); - rib_nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex); + rib_nexthop_ipv4_ifindex_add (rib, &nhop_addr, NULL, ifindex); break; case NEXTHOP_TYPE_IPV6: stream_forward_getp (s, IPV6_MAX_BYTELEN); @@ -1276,6 +1284,11 @@ zread_ipv4_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf) break; case NEXTHOP_TYPE_IPV4: nexthop.s_addr = stream_get_ipv4 (s); + /* For labeled-unicast, each nexthop is followed by label, but + * we don't care for delete. + */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_LABEL)) + stream_forward_getp (s, sizeof(u_int32_t)); nexthop_p = (union g_addr *)&nexthop; break; case NEXTHOP_TYPE_IPV4_IFINDEX: @@ -1461,7 +1474,7 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) { unsigned int i; struct stream *s; - struct in6_addr nexthop; + struct in6_addr nhop_addr; struct rib *rib; u_char message; u_char nexthop_num; @@ -1472,11 +1485,14 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) static struct in6_addr nexthops[MULTIPATH_NUM]; static unsigned int ifindices[MULTIPATH_NUM]; int ret; + static mpls_label_t labels[MULTIPATH_NUM]; + mpls_label_t label; + struct nexthop *nexthop; /* Get input stream. */ s = client->ibuf; - memset (&nexthop, 0, sizeof (struct in6_addr)); + memset (&nhop_addr, 0, sizeof (struct in6_addr)); /* Allocate new rib. */ rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); @@ -1525,10 +1541,17 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) switch (nexthop_type) { case NEXTHOP_TYPE_IPV6: - stream_get (&nexthop, s, 16); - if (nh_count < multipath_num) { - nexthops[nh_count++] = nexthop; - } + stream_get (&nhop_addr, s, 16); + if (nh_count < MULTIPATH_NUM) + { + /* For labeled-unicast, each nexthop is followed by label. */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL)) + { + label = (mpls_label_t)stream_getl (s); + labels[nh_count++] = label; + } + nexthops[nh_count++] = nhop_addr; + } break; case NEXTHOP_TYPE_IFINDEX: if (if_count < multipath_num) { @@ -1546,9 +1569,11 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) { if ((i < nh_count) && !IN6_IS_ADDR_UNSPECIFIED (&nexthops[i])) { if ((i < if_count) && ifindices[i]) - rib_nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]); + nexthop = rib_nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]); else - rib_nexthop_ipv6_add (rib, &nexthops[i]); + nexthop = rib_nexthop_ipv6_add (rib, &nexthops[i]); + if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL)) + nexthop_add_labels (nexthop, nexthop->nh_label_type, 1, &labels[i]); } else { if ((i < if_count) && ifindices[i]) @@ -1645,6 +1670,11 @@ zread_ipv6_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf) { case NEXTHOP_TYPE_IPV6: stream_get (&nexthop, s, 16); + /* For labeled-unicast, each nexthop is followed by label, but + * we don't care for delete. + */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_LABEL)) + stream_forward_getp (s, sizeof(u_int32_t)); pnexthop = (union g_addr *)&nexthop; break; case NEXTHOP_TYPE_IFINDEX: @@ -1815,14 +1845,14 @@ zread_mpls_labels (int command, struct zserv *client, u_short length, if (command == ZEBRA_MPLS_LABELS_ADD) { mpls_lsp_install (zvrf, type, in_label, out_label, gtype, &gate, - NULL, ifindex); + ifindex); if (out_label != MPLS_IMP_NULL_LABEL) mpls_ftn_update (1, zvrf, type, &prefix, gtype, &gate, ifindex, distance, out_label); } else if (command == ZEBRA_MPLS_LABELS_DELETE) { - mpls_lsp_uninstall (zvrf, type, in_label, gtype, &gate, NULL, ifindex); + mpls_lsp_uninstall (zvrf, type, in_label, gtype, &gate, ifindex); if (out_label != MPLS_IMP_NULL_LABEL) mpls_ftn_update (0, zvrf, type, &prefix, gtype, &gate, ifindex, distance, out_label); From e05fd627fb9886cecdff07413eabb51f958811f1 Mon Sep 17 00:00:00 2001 From: Don Slice Date: Thu, 2 Feb 2017 13:34:00 -0500 Subject: [PATCH 05/55] quagga: labeled unicast definitions Internal and IANA definitions for labeled-unicast SAFI. Note that this SAFI is specific to BGP and maps to the corresponding unicast SAFI in Zebra. Signed-off-by: Don Slice --- lib/zebra.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/zebra.h b/lib/zebra.h index 985382bff5..ef261eedc1 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -514,6 +514,8 @@ static inline safi_t safi_iana2int (safi_t safi) return SAFI_ENCAP; if (safi == IANA_SAFI_EVPN) return SAFI_EVPN; + if (safi == IANA_SAFI_LABELED_UNICAST) + return SAFI_LABELED_UNICAST; return SAFI_MAX; } @@ -529,6 +531,8 @@ static inline safi_t safi_int2iana (safi_t safi) return IANA_SAFI_ENCAP; if (safi == SAFI_EVPN) return IANA_SAFI_EVPN; + if (safi == SAFI_LABELED_UNICAST) + return IANA_SAFI_LABELED_UNICAST; return IANA_SAFI_RESERVED; } From f51bae9cf9c9bdfbf1d53a2cc4e01e0fdd0af119 Mon Sep 17 00:00:00 2001 From: Don Slice Date: Wed, 8 Feb 2017 14:19:54 -0500 Subject: [PATCH 06/55] bgpd: labeled unicast config Implement support for activating the labeled-unicast address family in BGP and relevant configuration for this address family. Signed-off-by: Don Slice --- bgpd/bgp_route.c | 19 ++++ bgpd/bgp_vty.c | 282 ++++++++++++++++++++++++++++++++++++++++------- bgpd/bgp_vty.h | 1 + bgpd/bgpd.c | 10 ++ lib/command.c | 6 + lib/command.h | 3 + lib/vty.c | 2 + vtysh/vtysh.c | 81 ++++++++++---- 8 files changed, 340 insertions(+), 64 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 1fa3e8bc44..432a566c15 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -10684,6 +10684,19 @@ bgp_route_init (void) install_element (BGP_IPV4M_NODE, &no_aggregate_address_cmd); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd); + /* IPv4 labeled-unicast configuration. */ + install_element (BGP_IPV4L_NODE, &bgp_table_map_cmd); + install_element (BGP_IPV4L_NODE, &bgp_network_cmd); + install_element (BGP_IPV4L_NODE, &bgp_network_mask_cmd); + install_element (BGP_IPV4L_NODE, &bgp_network_mask_natural_cmd); + install_element (BGP_IPV4L_NODE, &bgp_network_route_map_cmd); + install_element (BGP_IPV4L_NODE, &bgp_network_mask_route_map_cmd); + install_element (BGP_IPV4L_NODE, &bgp_network_mask_natural_route_map_cmd); + install_element (BGP_IPV4L_NODE, &no_bgp_table_map_cmd); + install_element (BGP_IPV4L_NODE, &no_bgp_network_cmd); + install_element (BGP_IPV4L_NODE, &no_bgp_network_mask_cmd); + install_element (BGP_IPV4L_NODE, &no_bgp_network_mask_natural_cmd); + install_element (VIEW_NODE, &show_ip_bgp_instance_all_cmd); install_element (VIEW_NODE, &show_ip_bgp_cmd); install_element (VIEW_NODE, &show_ip_bgp_route_cmd); @@ -10724,6 +10737,12 @@ bgp_route_init (void) install_element (BGP_IPV6M_NODE, &ipv6_bgp_network_cmd); install_element (BGP_IPV6M_NODE, &no_ipv6_bgp_network_cmd); + install_element (BGP_IPV6L_NODE, &bgp_table_map_cmd); + install_element (BGP_IPV6L_NODE, &ipv6_bgp_network_cmd); + install_element (BGP_IPV6L_NODE, &ipv6_bgp_network_route_map_cmd); + install_element (BGP_IPV6L_NODE, &no_bgp_table_map_cmd); + install_element (BGP_IPV6L_NODE, &no_ipv6_bgp_network_cmd); + install_element (BGP_NODE, &bgp_distance_cmd); install_element (BGP_NODE, &no_bgp_distance_cmd); install_element (BGP_NODE, &bgp_distance_source_cmd); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index e94de682d5..b1819e2f03 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -60,6 +60,72 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA static struct peer_group * listen_range_exists (struct bgp *bgp, struct prefix *range, int exact); +#if 0 +#define INSTALL_CMD_ON_AF_NODES(cmd) \ + install_element(BGP_IPV4_NODE, cmd); \ + install_element(BGP_IPV4M_NODE, cmd); \ + install_element(BGP_IPV4L_NODE, cmd); \ + install_element(BGP_IPV6_NODE, cmd); \ + install_element(BGP_IPV6M_NODE, cmd); \ + install_element(BGP_IPV6L_NODE, cmd); \ + install_element(BGP_VPNV4_NODE, cmd); +#endif +static enum node_type +bgp_node_type (afi_t afi, safi_t safi) +{ + switch (afi) + { + case AFI_IP: + switch (safi) + { + case SAFI_UNICAST: + return BGP_IPV4_NODE; + break; + case SAFI_MULTICAST: + return BGP_IPV4M_NODE; + break; + case SAFI_LABELED_UNICAST: + return BGP_IPV4L_NODE; + break; + case SAFI_MPLS_VPN: + return BGP_VPNV4_NODE; + break; + case SAFI_ENCAP: + return BGP_ENCAP_NODE; + break; + default: + return UNDEFINED_NODE; + break; + } + break; + case AFI_IP6: + switch (safi) + { + case SAFI_UNICAST: + return BGP_IPV6_NODE; + break; + case SAFI_MULTICAST: + return BGP_IPV6M_NODE; + break; + case SAFI_LABELED_UNICAST: + return BGP_IPV6L_NODE; + break; + case SAFI_MPLS_VPN: + return BGP_VPNV6_NODE; + break; + case SAFI_ENCAP: + return BGP_ENCAP_NODE; + break; + default: + return UNDEFINED_NODE; + break; + } + break; + default: + return UNDEFINED_NODE; + break; + } +} /* Utility function to get address family from current node. */ afi_t @@ -70,6 +136,7 @@ bgp_node_afi (struct vty *vty) { case BGP_IPV6_NODE: case BGP_IPV6M_NODE: + case BGP_IPV6L_NODE: case BGP_VPNV6_NODE: case BGP_ENCAPV6_NODE: afi = AFI_IP6; @@ -107,6 +174,10 @@ bgp_node_safi (struct vty *vty) case BGP_EVPN_NODE: safi = SAFI_EVPN; break; + case BGP_IPV4L_NODE: + case BGP_IPV6L_NODE: + safi = SAFI_LABELED_UNICAST; + break; default: safi = SAFI_UNICAST; break; @@ -160,7 +231,7 @@ argv_find_and_parse_afi(struct cmd_token **argv, int argc, int *index, afi_t *af return ret; } -/* supports */ +/* supports */ safi_t bgp_vty_safi_from_arg(const char *safi_str) { @@ -173,6 +244,8 @@ bgp_vty_safi_from_arg(const char *safi_str) safi = SAFI_ENCAP; else if (strncmp (safi_str, "v", 1) == 0) safi = SAFI_MPLS_VPN; + else if (strncmp (safi_str, "l", 1) == 0) + safi = SAFI_LABELED_UNICAST; return safi; } @@ -5649,30 +5722,16 @@ DEFUN (no_neighbor_addpath_tx_bestpath_per_as, DEFUN_NOSH (address_family_ipv4_safi, address_family_ipv4_safi_cmd, - "address-family ipv4 []", + "address-family ipv4 []", "Enter Address Family command mode\n" "Address Family\n" BGP_SAFI_HELP_STR) { - int idx_safi = 2; - if (argc == (idx_safi + 1)) + + if (argc == 3) { - switch (bgp_vty_safi_from_arg(argv[idx_safi]->arg)) - { - case SAFI_MULTICAST: - vty->node = BGP_IPV4M_NODE; - break; - case SAFI_ENCAP: - vty->node = BGP_ENCAP_NODE; - break; - case SAFI_MPLS_VPN: - vty->node = BGP_VPNV4_NODE; - break; - case SAFI_UNICAST: - default: - vty->node = BGP_IPV4_NODE; - break; - } + safi_t safi = bgp_vty_safi_from_arg(argv[2]->arg); + vty->node = bgp_node_type(AFI_IP, safi); } else vty->node = BGP_IPV4_NODE; @@ -5682,30 +5741,15 @@ DEFUN_NOSH (address_family_ipv4_safi, DEFUN_NOSH (address_family_ipv6_safi, address_family_ipv6_safi_cmd, - "address-family ipv6 []", + "address-family ipv6 []", "Enter Address Family command mode\n" "Address Family\n" BGP_SAFI_HELP_STR) { - int idx_safi = 2; - if (argc == (idx_safi + 1)) + if (argc == 3) { - switch (bgp_vty_safi_from_arg(argv[idx_safi]->arg)) - { - case SAFI_MULTICAST: - vty->node = BGP_IPV6M_NODE; - break; - case SAFI_ENCAP: - vty->node = BGP_ENCAPV6_NODE; - break; - case SAFI_MPLS_VPN: - vty->node = BGP_VPNV6_NODE; - break; - case SAFI_UNICAST: - default: - vty->node = BGP_IPV6_NODE; - break; - } + safi_t safi = bgp_vty_safi_from_arg(argv[2]->arg); + vty->node = bgp_node_type(AFI_IP6, safi); } else vty->node = BGP_IPV6_NODE; @@ -5778,9 +5822,11 @@ DEFUN_NOSH (exit_address_family, { if (vty->node == BGP_IPV4_NODE || vty->node == BGP_IPV4M_NODE + || vty->node == BGP_IPV4L_NODE || vty->node == BGP_VPNV4_NODE || vty->node == BGP_IPV6_NODE || vty->node == BGP_IPV6M_NODE + || vty->node == BGP_IPV6L_NODE || vty->node == BGP_VPNV6_NODE || vty->node == BGP_ENCAP_NODE || vty->node == BGP_ENCAPV6_NODE @@ -10033,6 +10079,13 @@ static struct cmd_node bgp_ipv4_multicast_node = 1, }; +static struct cmd_node bgp_ipv4_labeled_unicast_node = +{ + BGP_IPV4L_NODE, + "%s(config-router-af)# ", + 1, +}; + static struct cmd_node bgp_ipv6_unicast_node = { BGP_IPV6_NODE, @@ -10047,6 +10100,13 @@ static struct cmd_node bgp_ipv6_multicast_node = 1, }; +static struct cmd_node bgp_ipv6_labeled_unicast_node = +{ + BGP_IPV6L_NODE, + "%s(config-router-af)# ", + 1, +}; + static struct cmd_node bgp_vpnv4_node = { BGP_VPNV4_NODE, @@ -10091,8 +10151,10 @@ bgp_vty_init (void) install_node (&bgp_node, bgp_config_write); install_node (&bgp_ipv4_unicast_node, NULL); install_node (&bgp_ipv4_multicast_node, NULL); + install_node (&bgp_ipv4_labeled_unicast_node, NULL); install_node (&bgp_ipv6_unicast_node, NULL); install_node (&bgp_ipv6_multicast_node, NULL); + install_node (&bgp_ipv6_labeled_unicast_node, NULL); install_node (&bgp_vpnv4_node, NULL); install_node (&bgp_vpnv6_node, NULL); install_node (&bgp_encap_node, NULL); @@ -10103,8 +10165,10 @@ bgp_vty_init (void) install_default (BGP_NODE); install_default (BGP_IPV4_NODE); install_default (BGP_IPV4M_NODE); + install_default (BGP_IPV4L_NODE); install_default (BGP_IPV6_NODE); install_default (BGP_IPV6M_NODE); + install_default (BGP_IPV6L_NODE); install_default (BGP_VPNV4_NODE); install_default (BGP_VPNV6_NODE); install_default (BGP_ENCAP_NODE); @@ -10180,15 +10244,27 @@ bgp_vty_init (void) install_element (BGP_IPV6_NODE, &bgp_maxpaths_cmd); install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_cmd); install_element (BGP_NODE, &bgp_maxpaths_ibgp_cmd); - install_element(BGP_NODE, &bgp_maxpaths_ibgp_cluster_cmd); + install_element (BGP_NODE, &bgp_maxpaths_ibgp_cluster_cmd); install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_cmd); install_element (BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cmd); - install_element(BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cluster_cmd); + install_element (BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cluster_cmd); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_cmd); install_element (BGP_IPV6_NODE, &bgp_maxpaths_ibgp_cmd); - install_element(BGP_IPV6_NODE, &bgp_maxpaths_ibgp_cluster_cmd); + install_element (BGP_IPV6_NODE, &bgp_maxpaths_ibgp_cluster_cmd); install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_ibgp_cmd); + install_element (BGP_IPV4L_NODE, &bgp_maxpaths_cmd); + install_element (BGP_IPV4L_NODE, &no_bgp_maxpaths_cmd); + install_element (BGP_IPV6L_NODE, &bgp_maxpaths_cmd); + install_element (BGP_IPV6L_NODE, &no_bgp_maxpaths_cmd); + + install_element (BGP_IPV4L_NODE, &bgp_maxpaths_ibgp_cmd); + install_element (BGP_IPV4L_NODE, &bgp_maxpaths_ibgp_cluster_cmd); + install_element (BGP_IPV4L_NODE, &no_bgp_maxpaths_ibgp_cmd); + install_element (BGP_IPV6L_NODE, &bgp_maxpaths_ibgp_cmd); + install_element (BGP_IPV6L_NODE, &bgp_maxpaths_ibgp_cluster_cmd); + install_element (BGP_IPV6L_NODE, &no_bgp_maxpaths_ibgp_cmd); + /* "timers bgp" commands. */ install_element (BGP_NODE, &bgp_timers_cmd); install_element (BGP_NODE, &no_bgp_timers_cmd); @@ -10317,8 +10393,10 @@ bgp_vty_init (void) install_element (BGP_NODE, &neighbor_activate_cmd); install_element (BGP_IPV4_NODE, &neighbor_activate_cmd); install_element (BGP_IPV4M_NODE, &neighbor_activate_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_activate_cmd); install_element (BGP_IPV6_NODE, &neighbor_activate_cmd); install_element (BGP_IPV6M_NODE, &neighbor_activate_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_activate_cmd); install_element (BGP_VPNV4_NODE, &neighbor_activate_cmd); install_element (BGP_VPNV6_NODE, &neighbor_activate_cmd); install_element (BGP_ENCAP_NODE, &neighbor_activate_cmd); @@ -10329,8 +10407,10 @@ bgp_vty_init (void) install_element (BGP_NODE, &no_neighbor_activate_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_activate_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_activate_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_activate_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_activate_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_activate_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_activate_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_activate_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_activate_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_activate_cmd); @@ -10346,8 +10426,10 @@ bgp_vty_init (void) install_element (BGP_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_IPV4_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_IPV4M_NODE, &neighbor_set_peer_group_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_IPV6_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_IPV6M_NODE, &neighbor_set_peer_group_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_VPNV4_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_VPNV6_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_ENCAP_NODE, &neighbor_set_peer_group_cmd); @@ -10357,8 +10439,10 @@ bgp_vty_init (void) install_element (BGP_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_set_peer_group_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_set_peer_group_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_set_peer_group_cmd); @@ -10369,12 +10453,16 @@ bgp_vty_init (void) install_element (BGP_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element (BGP_IPV4_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_soft_reconfiguration_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_soft_reconfiguration_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element (BGP_IPV4M_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element (BGP_IPV6_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element (BGP_IPV6M_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_soft_reconfiguration_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_soft_reconfiguration_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element (BGP_VPNV4_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element (BGP_VPNV6_NODE, &neighbor_soft_reconfiguration_cmd); @@ -10391,10 +10479,14 @@ bgp_vty_init (void) install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged_cmd); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_attr_unchanged_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_attr_unchanged_cmd); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_attr_unchanged_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_attr_unchanged_cmd); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged_cmd); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged_cmd); @@ -10420,10 +10512,14 @@ bgp_vty_init (void) install_element (BGP_IPV4_NODE, &no_neighbor_nexthop_self_cmd); install_element (BGP_IPV4M_NODE, &neighbor_nexthop_self_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_nexthop_self_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_nexthop_self_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_nexthop_self_cmd); install_element (BGP_IPV6_NODE, &neighbor_nexthop_self_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_self_cmd); install_element (BGP_IPV6M_NODE, &neighbor_nexthop_self_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_nexthop_self_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_nexthop_self_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_nexthop_self_cmd); install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd); install_element (BGP_VPNV6_NODE, &neighbor_nexthop_self_cmd); @@ -10440,10 +10536,14 @@ bgp_vty_init (void) install_element (BGP_IPV4_NODE, &no_neighbor_nexthop_self_force_cmd); install_element (BGP_IPV4M_NODE, &neighbor_nexthop_self_force_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_nexthop_self_force_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_nexthop_self_force_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_nexthop_self_force_cmd); install_element (BGP_IPV6_NODE, &neighbor_nexthop_self_force_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_self_force_cmd); install_element (BGP_IPV6M_NODE, &neighbor_nexthop_self_force_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_nexthop_self_force_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_nexthop_self_force_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_nexthop_self_force_cmd); install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_force_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_force_cmd); install_element (BGP_VPNV6_NODE, &neighbor_nexthop_self_force_cmd); @@ -10456,10 +10556,14 @@ bgp_vty_init (void) install_element (BGP_IPV4_NODE, &no_neighbor_as_override_cmd); install_element (BGP_IPV4M_NODE, &neighbor_as_override_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_as_override_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_as_override_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_as_override_cmd); install_element (BGP_IPV6_NODE, &neighbor_as_override_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_as_override_cmd); install_element (BGP_IPV6M_NODE, &neighbor_as_override_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_as_override_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_as_override_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_as_override_cmd); install_element (BGP_VPNV4_NODE, &neighbor_as_override_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_as_override_cmd); install_element (BGP_VPNV6_NODE, &neighbor_as_override_cmd); @@ -10490,6 +10594,14 @@ bgp_vty_init (void) install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_replace_as_cmd); install_element (BGP_IPV4M_NODE, &neighbor_remove_private_as_all_replace_as_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_remove_private_as_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_remove_private_as_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_remove_private_as_all_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_remove_private_as_all_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_remove_private_as_replace_as_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_remove_private_as_replace_as_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_remove_private_as_all_replace_as_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd); install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_remove_private_as_cmd); install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_all_cmd); @@ -10506,6 +10618,14 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &no_neighbor_remove_private_as_replace_as_cmd); install_element (BGP_IPV6M_NODE, &neighbor_remove_private_as_all_replace_as_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_remove_private_as_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_remove_private_as_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_remove_private_as_all_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_remove_private_as_all_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_remove_private_as_replace_as_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_remove_private_as_replace_as_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_remove_private_as_all_replace_as_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd); install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_cmd); install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_all_cmd); @@ -10540,6 +10660,10 @@ bgp_vty_init (void) install_element (BGP_IPV4M_NODE, &neighbor_send_community_type_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_type_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_send_community_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_send_community_type_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_send_community_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_send_community_type_cmd); install_element (BGP_IPV6_NODE, &neighbor_send_community_cmd); install_element (BGP_IPV6_NODE, &neighbor_send_community_type_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_send_community_cmd); @@ -10548,6 +10672,10 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &neighbor_send_community_type_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_send_community_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_send_community_type_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_send_community_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_send_community_type_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_send_community_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_send_community_type_cmd); install_element (BGP_VPNV4_NODE, &neighbor_send_community_cmd); install_element (BGP_VPNV4_NODE, &neighbor_send_community_type_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_cmd); @@ -10572,10 +10700,14 @@ bgp_vty_init (void) install_element (BGP_IPV4_NODE, &no_neighbor_route_reflector_client_cmd); install_element (BGP_IPV4M_NODE, &neighbor_route_reflector_client_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_route_reflector_client_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_route_reflector_client_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_route_reflector_client_cmd); install_element (BGP_IPV6_NODE, &neighbor_route_reflector_client_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_route_reflector_client_cmd); install_element (BGP_IPV6M_NODE, &neighbor_route_reflector_client_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_route_reflector_client_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_route_reflector_client_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_route_reflector_client_cmd); install_element (BGP_VPNV4_NODE, &neighbor_route_reflector_client_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_route_reflector_client_cmd); install_element (BGP_VPNV6_NODE, &neighbor_route_reflector_client_cmd); @@ -10592,10 +10724,14 @@ bgp_vty_init (void) install_element (BGP_IPV4_NODE, &no_neighbor_route_server_client_cmd); install_element (BGP_IPV4M_NODE, &neighbor_route_server_client_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_route_server_client_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_route_server_client_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_route_server_client_cmd); install_element (BGP_IPV6_NODE, &neighbor_route_server_client_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_route_server_client_cmd); install_element (BGP_IPV6M_NODE, &neighbor_route_server_client_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_route_server_client_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_route_server_client_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_route_server_client_cmd); install_element (BGP_VPNV4_NODE, &neighbor_route_server_client_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd); install_element (BGP_VPNV6_NODE, &neighbor_route_server_client_cmd); @@ -10612,10 +10748,14 @@ bgp_vty_init (void) install_element (BGP_IPV4_NODE, &no_neighbor_addpath_tx_all_paths_cmd); install_element (BGP_IPV4M_NODE, &neighbor_addpath_tx_all_paths_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_addpath_tx_all_paths_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_addpath_tx_all_paths_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_addpath_tx_all_paths_cmd); install_element (BGP_IPV6_NODE, &neighbor_addpath_tx_all_paths_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_addpath_tx_all_paths_cmd); install_element (BGP_IPV6M_NODE, &neighbor_addpath_tx_all_paths_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_addpath_tx_all_paths_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_addpath_tx_all_paths_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_addpath_tx_all_paths_cmd); install_element (BGP_VPNV4_NODE, &neighbor_addpath_tx_all_paths_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_addpath_tx_all_paths_cmd); install_element (BGP_VPNV6_NODE, &neighbor_addpath_tx_all_paths_cmd); @@ -10628,10 +10768,14 @@ bgp_vty_init (void) install_element (BGP_IPV4_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd); install_element (BGP_IPV4M_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd); install_element (BGP_IPV6_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd); install_element (BGP_IPV6M_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd); install_element (BGP_VPNV4_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd); install_element (BGP_VPNV6_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd); @@ -10659,10 +10803,14 @@ bgp_vty_init (void) install_element (BGP_IPV4_NODE, &no_neighbor_capability_orf_prefix_cmd); install_element (BGP_IPV4M_NODE, &neighbor_capability_orf_prefix_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_capability_orf_prefix_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_capability_orf_prefix_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_capability_orf_prefix_cmd); install_element (BGP_IPV6_NODE, &neighbor_capability_orf_prefix_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_capability_orf_prefix_cmd); install_element (BGP_IPV6M_NODE, &neighbor_capability_orf_prefix_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_capability_orf_prefix_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_capability_orf_prefix_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_capability_orf_prefix_cmd); /* "neighbor capability dynamic" commands.*/ install_element (BGP_NODE, &neighbor_capability_dynamic_cmd); @@ -10699,12 +10847,18 @@ bgp_vty_init (void) install_element (BGP_IPV4M_NODE, &neighbor_default_originate_cmd); install_element (BGP_IPV4M_NODE, &neighbor_default_originate_rmap_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_default_originate_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_default_originate_rmap_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_default_originate_cmd); install_element (BGP_IPV6_NODE, &neighbor_default_originate_cmd); install_element (BGP_IPV6_NODE, &neighbor_default_originate_rmap_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_cmd); install_element (BGP_IPV6M_NODE, &neighbor_default_originate_cmd); install_element (BGP_IPV6M_NODE, &neighbor_default_originate_rmap_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_default_originate_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_default_originate_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_default_originate_rmap_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_default_originate_cmd); /* "neighbor port" commands. */ install_element (BGP_NODE, &neighbor_port_cmd); @@ -10718,10 +10872,14 @@ bgp_vty_init (void) install_element (BGP_IPV4_NODE, &no_neighbor_weight_cmd); install_element (BGP_IPV4M_NODE, &neighbor_weight_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_weight_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_weight_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_weight_cmd); install_element (BGP_IPV6_NODE, &neighbor_weight_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_weight_cmd); install_element (BGP_IPV6M_NODE, &neighbor_weight_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_weight_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_weight_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_weight_cmd); install_element (BGP_VPNV4_NODE, &neighbor_weight_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_weight_cmd); install_element (BGP_VPNV6_NODE, &neighbor_weight_cmd); @@ -10762,10 +10920,14 @@ bgp_vty_init (void) install_element (BGP_IPV4_NODE, &no_neighbor_distribute_list_cmd); install_element (BGP_IPV4M_NODE, &neighbor_distribute_list_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_distribute_list_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_distribute_list_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_distribute_list_cmd); install_element (BGP_IPV6_NODE, &neighbor_distribute_list_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_distribute_list_cmd); install_element (BGP_IPV6M_NODE, &neighbor_distribute_list_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_distribute_list_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_distribute_list_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_distribute_list_cmd); install_element (BGP_VPNV4_NODE, &neighbor_distribute_list_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd); install_element (BGP_VPNV6_NODE, &neighbor_distribute_list_cmd); @@ -10782,10 +10944,14 @@ bgp_vty_init (void) install_element (BGP_IPV4_NODE, &no_neighbor_prefix_list_cmd); install_element (BGP_IPV4M_NODE, &neighbor_prefix_list_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_prefix_list_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_prefix_list_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_prefix_list_cmd); install_element (BGP_IPV6_NODE, &neighbor_prefix_list_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_prefix_list_cmd); install_element (BGP_IPV6M_NODE, &neighbor_prefix_list_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_prefix_list_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_prefix_list_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_prefix_list_cmd); install_element (BGP_VPNV4_NODE, &neighbor_prefix_list_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd); install_element (BGP_VPNV6_NODE, &neighbor_prefix_list_cmd); @@ -10802,10 +10968,14 @@ bgp_vty_init (void) install_element (BGP_IPV4_NODE, &no_neighbor_filter_list_cmd); install_element (BGP_IPV4M_NODE, &neighbor_filter_list_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_filter_list_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_filter_list_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_filter_list_cmd); install_element (BGP_IPV6_NODE, &neighbor_filter_list_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_filter_list_cmd); install_element (BGP_IPV6M_NODE, &neighbor_filter_list_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_filter_list_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_filter_list_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_filter_list_cmd); install_element (BGP_VPNV4_NODE, &neighbor_filter_list_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_filter_list_cmd); install_element (BGP_VPNV6_NODE, &neighbor_filter_list_cmd); @@ -10822,10 +10992,14 @@ bgp_vty_init (void) install_element (BGP_IPV4_NODE, &no_neighbor_route_map_cmd); install_element (BGP_IPV4M_NODE, &neighbor_route_map_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_route_map_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_route_map_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_route_map_cmd); install_element (BGP_IPV6_NODE, &neighbor_route_map_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_route_map_cmd); install_element (BGP_IPV6M_NODE, &neighbor_route_map_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_route_map_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_route_map_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_route_map_cmd); install_element (BGP_VPNV4_NODE, &neighbor_route_map_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_route_map_cmd); install_element (BGP_VPNV6_NODE, &neighbor_route_map_cmd); @@ -10842,10 +11016,14 @@ bgp_vty_init (void) install_element (BGP_IPV4_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_IPV4M_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_unsuppress_map_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_unsuppress_map_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_IPV6_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_IPV6M_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_unsuppress_map_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_unsuppress_map_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_VPNV4_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd); @@ -10877,6 +11055,13 @@ bgp_vty_init (void) install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_restart_cmd); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_warning_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_restart_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_maximum_prefix_cmd); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_cmd); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_cmd); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_warning_cmd); @@ -10891,6 +11076,13 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_restart_cmd); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_warning_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_restart_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_maximum_prefix_cmd); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_cmd); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_cmd); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_warning_cmd); @@ -10929,10 +11121,14 @@ bgp_vty_init (void) install_element (BGP_IPV4_NODE, &no_neighbor_allowas_in_cmd); install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_allowas_in_cmd); + install_element (BGP_IPV4L_NODE, &neighbor_allowas_in_cmd); + install_element (BGP_IPV4L_NODE, &no_neighbor_allowas_in_cmd); install_element (BGP_IPV6_NODE, &neighbor_allowas_in_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_allowas_in_cmd); install_element (BGP_IPV6M_NODE, &neighbor_allowas_in_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_allowas_in_cmd); + install_element (BGP_IPV6L_NODE, &neighbor_allowas_in_cmd); + install_element (BGP_IPV6L_NODE, &no_neighbor_allowas_in_cmd); install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_allowas_in_cmd); install_element (BGP_VPNV6_NODE, &neighbor_allowas_in_cmd); @@ -10958,8 +11154,10 @@ bgp_vty_init (void) /* "exit-address-family" command. */ install_element (BGP_IPV4_NODE, &exit_address_family_cmd); install_element (BGP_IPV4M_NODE, &exit_address_family_cmd); + install_element (BGP_IPV4L_NODE, &exit_address_family_cmd); install_element (BGP_IPV6_NODE, &exit_address_family_cmd); install_element (BGP_IPV6M_NODE, &exit_address_family_cmd); + install_element (BGP_IPV6L_NODE, &exit_address_family_cmd); install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); install_element (BGP_VPNV6_NODE, &exit_address_family_cmd); install_element (BGP_ENCAP_NODE, &exit_address_family_cmd); diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index 33d24d530e..f0342c2c35 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -33,6 +33,7 @@ struct bgp; "Address Family modifier\n" \ "Address Family modifier\n" \ "Address Family modifier\n" \ + "Address Family modifier\n" \ "Address Family modifier\n" #define BGP_AFI_SAFI_CMD_STR BGP_AFI_CMD_STR" "BGP_SAFI_CMD_STR #define BGP_AFI_SAFI_HELP_STR BGP_AFI_HELP_STR BGP_SAFI_HELP_STR diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 3f81c1c50c..0ed277b164 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -7262,6 +7262,8 @@ bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi, { if (safi == SAFI_UNICAST) vty_out (vty, "ipv4 unicast"); + else if (safi == SAFI_LABELED_UNICAST) + vty_out (vty, "ipv4 labeled-unicast"); else if (safi == SAFI_MULTICAST) vty_out (vty, "ipv4 multicast"); else if (safi == SAFI_MPLS_VPN) @@ -7273,6 +7275,8 @@ bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi, { if (safi == SAFI_UNICAST) vty_out (vty, "ipv6 unicast"); + else if (safi == SAFI_LABELED_UNICAST) + vty_out (vty, "ipv6 labeled-unicast"); else if (safi == SAFI_MULTICAST) vty_out (vty, "ipv6 multicast"); else if (safi == SAFI_MPLS_VPN) @@ -7579,6 +7583,9 @@ bgp_config_write (struct vty *vty) /* IPv4 multicast configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MULTICAST); + /* IPv4 labeled-unicast configuration. */ + write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_LABELED_UNICAST); + /* IPv4 VPN configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MPLS_VPN); @@ -7591,6 +7598,9 @@ bgp_config_write (struct vty *vty) /* IPv6 multicast configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MULTICAST); + /* IPv6 labeled-unicast configuration. */ + write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_LABELED_UNICAST); + /* IPv6 VPN configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MPLS_VPN); diff --git a/lib/command.c b/lib/command.c index 993d6f9055..af13542bc3 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1055,9 +1055,11 @@ node_parent ( enum node_type node ) case BGP_VNC_L2_GROUP_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: + case BGP_IPV4L_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: case BGP_EVPN_NODE: + case BGP_IPV6L_NODE: ret = BGP_NODE; break; case KEYCHAIN_KEY_NODE: @@ -1414,6 +1416,7 @@ cmd_exit (struct vty *vty) break; case BGP_IPV4_NODE: case BGP_IPV4M_NODE: + case BGP_IPV4L_NODE: case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: case BGP_ENCAP_NODE: @@ -1425,6 +1428,7 @@ cmd_exit (struct vty *vty) case BGP_IPV6_NODE: case BGP_IPV6M_NODE: case BGP_EVPN_NODE: + case BGP_IPV6L_NODE: vty->node = BGP_NODE; break; case LDP_IPV4_NODE: @@ -1491,9 +1495,11 @@ DEFUN (config_end, case BGP_VPNV6_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: + case BGP_IPV4L_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: case BGP_EVPN_NODE: + case BGP_IPV6L_NODE: case RMAP_NODE: case OSPF_NODE: case OSPF6_NODE: diff --git a/lib/command.h b/lib/command.h index d62f7655ee..1a5e069ce3 100644 --- a/lib/command.h +++ b/lib/command.h @@ -96,8 +96,10 @@ enum node_type BGP_VPNV6_NODE, /* BGP MPLS-VPN PE exchange. */ BGP_IPV4_NODE, /* BGP IPv4 unicast address family. */ BGP_IPV4M_NODE, /* BGP IPv4 multicast address family. */ + BGP_IPV4L_NODE, /* BGP IPv4 labeled unicast address family. */ BGP_IPV6_NODE, /* BGP IPv6 address family */ BGP_IPV6M_NODE, /* BGP IPv6 multicast address family. */ + BGP_IPV6L_NODE, /* BGP IPv6 labeled unicast address family. */ BGP_ENCAP_NODE, /* BGP ENCAP SAFI */ BGP_ENCAPV6_NODE, /* BGP ENCAP SAFI */ BGP_VRF_POLICY_NODE, /* BGP VRF policy */ @@ -134,6 +136,7 @@ enum node_type MPLS_NODE, /* MPLS config node */ VTY_NODE, /* Vty node. */ LINK_PARAMS_NODE, /* Link-parameters node */ + UNDEFINED_NODE }; /* Node which has some commands and prompt string and configuration diff --git a/lib/vty.c b/lib/vty.c index 36755b1d95..3c5b28a5df 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -745,9 +745,11 @@ vty_end_config (struct vty *vty) case BGP_VNC_L2_GROUP_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: + case BGP_IPV4L_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: case BGP_EVPN_NODE: + case BGP_IPV6L_NODE: case RMAP_NODE: case OSPF_NODE: case OSPF6_NODE: diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index d0038ea3cf..10b98ac4c6 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -309,7 +309,8 @@ vtysh_execute_func (const char *line, int pager) || saved_node == BGP_ENCAP_NODE || saved_node == BGP_ENCAPV6_NODE || saved_node == BGP_IPV4_NODE || saved_node == BGP_IPV6_NODE || saved_node == BGP_IPV4M_NODE - || saved_node == BGP_IPV6M_NODE || saved_node == BGP_EVPN_NODE) + || saved_node == BGP_IPV4L_NODE || saved_node == BGP_IPV6L_NODE + || saved_node == BGP_IPV6M_NODE || saved_node == BGP_EVPN_NODE) && (tried == 1)) { vtysh_execute("exit-address-family"); @@ -947,6 +948,12 @@ static struct cmd_node bgp_ipv4m_node = "%s(config-router-af)# " }; +static struct cmd_node bgp_ipv4l_node = +{ + BGP_IPV4L_NODE, + "%s(config-router-af)# " +}; + static struct cmd_node bgp_ipv6_node = { BGP_IPV6_NODE, @@ -965,6 +972,12 @@ static struct cmd_node bgp_evpn_node = "%s(config-router-af)# " }; +static struct cmd_node bgp_ipv6l_node = +{ + BGP_IPV6L_NODE, + "%s(config-router-af)# " +}; + static struct cmd_node bgp_vnc_defaults_node = { BGP_VNC_DEFAULTS_NODE, @@ -1115,7 +1128,7 @@ DEFUNSH (VTYSH_BGPD, "address-family vpnv4 [unicast]", "Enter Address Family command mode\n" "Address Family\n" - "Address Family Modifier\n") + "Address Family modifier\n") { vty->node = BGP_VPNV4_NODE; return CMD_SUCCESS; @@ -1127,7 +1140,7 @@ DEFUNSH (VTYSH_BGPD, "address-family vpnv6 [unicast]", "Enter Address Family command mode\n" "Address Family\n" - "Address Family Modifier\n") + "Address Family modifier\n") { vty->node = BGP_VPNV6_NODE; return CMD_SUCCESS; @@ -1157,15 +1170,16 @@ DEFUNSH (VTYSH_BGPD, } DEFUNSH (VTYSH_BGPD, - address_family_ipv4_unicast, - address_family_ipv4_unicast_cmd, - "address-family ipv4 []", - "Enter Address Family command mode\n" - "Address Family\n" - "Address Family Modifier\n" - "Address Family Modifier\n" - "Address Family Modifier\n" - "Address Family Modifier\n") + address_family_ipv4, + address_family_ipv4_cmd, + "address-family ipv4 []", + "Enter Address Family command mode\n" + "Address Family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n") { int idx = 0; @@ -1178,6 +1192,9 @@ DEFUNSH (VTYSH_BGPD, else if (argv_find (argv, argc, "vpn", &idx)) vty->node = BGP_VPNV4_NODE; + else if (argv_find (argv, argc, "labeled-unicast", &idx)) + vty->node = BGP_IPV4L_NODE; + else vty->node = BGP_IPV4_NODE; @@ -1185,15 +1202,16 @@ DEFUNSH (VTYSH_BGPD, } DEFUNSH (VTYSH_BGPD, - address_family_ipv6, - address_family_ipv6_cmd, - "address-family ipv6 []", - "Enter Address Family command mode\n" - "Address Family\n" - "Address Family Modifier\n" - "Address Family Modifier\n" - "Address Family Modifier\n" - "Address Family Modifier\n") + address_family_ipv6, + address_family_ipv6_cmd, + "address-family ipv6 []", + "Enter Address Family command mode\n" + "Address Family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n") { int idx = 0; @@ -1206,6 +1224,9 @@ DEFUNSH (VTYSH_BGPD, else if (argv_find (argv, argc, "vpn", &idx)) vty->node = BGP_VPNV6_NODE; + else if (argv_find (argv, argc, "labeled-unicast", &idx)) + vty->node = BGP_IPV6L_NODE; + else vty->node = BGP_IPV6_NODE; @@ -1532,8 +1553,10 @@ vtysh_exit (struct vty *vty) case BGP_ENCAPV6_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: + case BGP_IPV4L_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: + case BGP_IPV6L_NODE: case BGP_VRF_POLICY_NODE: case BGP_EVPN_NODE: case BGP_VNC_DEFAULTS_NODE: @@ -1592,11 +1615,13 @@ DEFUNSH (VTYSH_BGPD, { if (vty->node == BGP_IPV4_NODE || vty->node == BGP_IPV4M_NODE + || vty->node == BGP_IPV4L_NODE || vty->node == BGP_VPNV4_NODE || vty->node == BGP_VPNV6_NODE || vty->node == BGP_ENCAP_NODE || vty->node == BGP_ENCAPV6_NODE || vty->node == BGP_IPV6_NODE + || vty->node == BGP_IPV6L_NODE || vty->node == BGP_IPV6M_NODE) vty->node = BGP_NODE; return CMD_SUCCESS; @@ -3124,8 +3149,10 @@ vtysh_init_vty (void) install_node (&bgp_encapv6_node, NULL); install_node (&bgp_ipv4_node, NULL); install_node (&bgp_ipv4m_node, NULL); + install_node (&bgp_ipv4l_node, NULL); install_node (&bgp_ipv6_node, NULL); install_node (&bgp_ipv6m_node, NULL); + install_node (&bgp_ipv6l_node, NULL); install_node (&bgp_vrf_policy_node, NULL); install_node (&bgp_evpn_node, NULL); install_node (&bgp_vnc_defaults_node, NULL); @@ -3162,9 +3189,11 @@ vtysh_init_vty (void) vtysh_install_default (BGP_ENCAPV6_NODE); vtysh_install_default (BGP_IPV4_NODE); vtysh_install_default (BGP_IPV4M_NODE); + vtysh_install_default (BGP_IPV4L_NODE); vtysh_install_default (BGP_IPV6_NODE); vtysh_install_default (BGP_IPV6M_NODE); vtysh_install_default (BGP_EVPN_NODE); + vtysh_install_default (BGP_IPV6L_NODE); #if ENABLE_BGP_VNC vtysh_install_default (BGP_VRF_POLICY_NODE); vtysh_install_default (BGP_VNC_DEFAULTS_NODE); @@ -3233,11 +3262,15 @@ vtysh_init_vty (void) install_element (BGP_IPV4_NODE, &vtysh_quit_bgpd_cmd); install_element (BGP_IPV4M_NODE, &vtysh_exit_bgpd_cmd); install_element (BGP_IPV4M_NODE, &vtysh_quit_bgpd_cmd); + install_element (BGP_IPV4L_NODE, &vtysh_exit_bgpd_cmd); + install_element (BGP_IPV4L_NODE, &vtysh_quit_bgpd_cmd); install_element (BGP_IPV6_NODE, &vtysh_exit_bgpd_cmd); install_element (BGP_IPV6_NODE, &vtysh_quit_bgpd_cmd); install_element (BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd); install_element (BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd); install_element (BGP_EVPN_NODE, &vtysh_quit_bgpd_cmd); + install_element (BGP_IPV6L_NODE, &vtysh_exit_bgpd_cmd); + install_element (BGP_IPV6L_NODE, &vtysh_quit_bgpd_cmd); #if defined (ENABLE_BGP_VNC) install_element (BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd); install_element (BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd); @@ -3276,12 +3309,14 @@ vtysh_init_vty (void) install_element (BGP_NODE, &vtysh_end_all_cmd); install_element (BGP_IPV4_NODE, &vtysh_end_all_cmd); install_element (BGP_IPV4M_NODE, &vtysh_end_all_cmd); + install_element (BGP_IPV4L_NODE, &vtysh_end_all_cmd); install_element (BGP_VPNV4_NODE, &vtysh_end_all_cmd); install_element (BGP_VPNV6_NODE, &vtysh_end_all_cmd); install_element (BGP_ENCAP_NODE, &vtysh_end_all_cmd); install_element (BGP_ENCAPV6_NODE, &vtysh_end_all_cmd); install_element (BGP_IPV6_NODE, &vtysh_end_all_cmd); install_element (BGP_IPV6M_NODE, &vtysh_end_all_cmd); + install_element (BGP_IPV6L_NODE, &vtysh_end_all_cmd); install_element (BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd); install_element (BGP_EVPN_NODE, &vtysh_end_all_cmd); install_element (BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd); @@ -3337,7 +3372,7 @@ vtysh_init_vty (void) install_element (BGP_NODE, &vnc_nve_group_cmd); install_element (BGP_NODE, &vnc_l2_group_cmd); #endif - install_element (BGP_NODE, &address_family_ipv4_unicast_cmd); + install_element (BGP_NODE, &address_family_ipv4_cmd); install_element (BGP_NODE, &address_family_ipv6_cmd); install_element (BGP_NODE, &address_family_evpn_cmd); install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); @@ -3346,9 +3381,11 @@ vtysh_init_vty (void) install_element (BGP_ENCAPV6_NODE, &exit_address_family_cmd); install_element (BGP_IPV4_NODE, &exit_address_family_cmd); install_element (BGP_IPV4M_NODE, &exit_address_family_cmd); + install_element (BGP_IPV4L_NODE, &exit_address_family_cmd); install_element (BGP_IPV6_NODE, &exit_address_family_cmd); install_element (BGP_IPV6M_NODE, &exit_address_family_cmd); install_element (BGP_EVPN_NODE, &exit_address_family_cmd); + install_element (BGP_IPV6L_NODE, &exit_address_family_cmd); install_element (BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd); install_element (BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd); From cd1964ff38bdbd2b5d36d0a0d89890e9d1bb2a50 Mon Sep 17 00:00:00 2001 From: Don Slice Date: Thu, 9 Mar 2017 09:54:20 -0500 Subject: [PATCH 07/55] bgpd: labeled unicast processing Implement support for negotiating IPv4 or IPv6 labeled-unicast address family, exchanging prefixes and installing them in the routing table, as well as interactions with Zebra for FEC registration. This is the implementation of RFC 3107. Signed-off-by: Don Slice --- bgpd/Makefile.am | 5 +- bgpd/bgp_attr.c | 14 +- bgpd/bgp_fsm.c | 2 + bgpd/bgp_label.c | 318 +++++++++++++++++++++++++++++++++++++++ bgpd/bgp_label.h | 124 +++++++++++++++ bgpd/bgp_main.c | 2 + bgpd/bgp_nht.c | 18 ++- bgpd/bgp_open.c | 8 + bgpd/bgp_packet.c | 5 + bgpd/bgp_route.c | 137 ++++++++++++++--- bgpd/bgp_route.h | 13 +- bgpd/bgp_table.h | 3 + bgpd/bgp_updgrp_adv.c | 2 +- bgpd/bgp_updgrp_packet.c | 15 +- bgpd/bgp_zebra.c | 156 +++++++++++++++++-- bgpd/bgp_zebra.h | 6 +- bgpd/bgpd.c | 8 + bgpd/bgpd.h | 13 +- lib/prefix.h | 2 + lib/stream.c | 25 +++ lib/stream.h | 3 +- 21 files changed, 819 insertions(+), 60 deletions(-) create mode 100644 bgpd/bgp_label.c create mode 100644 bgpd/bgp_label.h diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index b6ed9a4d6d..4ea0455525 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -81,7 +81,7 @@ libbgp_a_SOURCES = \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \ bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \ bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \ - bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c + bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c bgp_label.c noinst_HEADERS = \ bgp_memory.h \ @@ -92,7 +92,8 @@ noinst_HEADERS = \ bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ bgp_advertise.h bgp_vty.h bgp_mpath.h bgp_nht.h \ bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \ - $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h bgp_vpn.h + $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h \ + bgp_vpn.h bgp_label.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@ diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 1fccd25c8a..2c6bb5de0e 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2748,6 +2748,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi, { case SAFI_UNICAST: case SAFI_MULTICAST: + case SAFI_LABELED_UNICAST: bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr); stream_putc (s, 4); stream_put_ipv4 (s, attr->nexthop.s_addr); @@ -2772,6 +2773,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi, { case SAFI_UNICAST: case SAFI_MULTICAST: + case SAFI_LABELED_UNICAST: { struct attr_extra *attre = attr->extra; @@ -2875,6 +2877,11 @@ bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi, { bgp_packet_mpattr_route_type_5(s, p, prd, tag, attr); } + else if (safi == SAFI_LABELED_UNICAST) + { + /* Prefix write with label. */ + stream_put_labeled_prefix(s, p, tag); + } else stream_put_prefix_addpath (s, p, addpath_encode, addpath_tx_id); } @@ -3112,7 +3119,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, stream_putc (s, 4); stream_put_ipv4 (s, attr->nexthop.s_addr); } - else if (safi == SAFI_UNICAST && peer_cap_enhe(from)) + else if (peer_cap_enhe(from)) { /* * Likely this is the case when an IPv4 prefix was received with @@ -3439,6 +3446,11 @@ bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p, u_char *tag, int addpath_encode, u_int32_t addpath_tx_id, struct attr *attr) { + u_char wlabel[3] = {0x80, 0x00, 0x00}; + + if (safi == SAFI_LABELED_UNICAST) + tag = wlabel; + return bgp_packet_mpattr_prefix (s, afi, safi, p, prd, tag, addpath_encode, addpath_tx_id, attr); } diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 2bbdca595c..b178884824 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1142,9 +1142,11 @@ bgp_stop (struct peer *peer) /* Reset prefix count */ peer->pcount[AFI_IP][SAFI_UNICAST] = 0; peer->pcount[AFI_IP][SAFI_MULTICAST] = 0; + peer->pcount[AFI_IP][SAFI_LABELED_UNICAST] = 0; peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0; peer->pcount[AFI_IP6][SAFI_UNICAST] = 0; peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0; + peer->pcount[AFI_IP6][SAFI_LABELED_UNICAST] = 0; #endif /* 0 */ if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) && diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c new file mode 100644 index 0000000000..283afbc922 --- /dev/null +++ b/bgpd/bgp_label.c @@ -0,0 +1,318 @@ +/* BGP carrying label information + * Copyright (C) 2013 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "command.h" +#include "thread.h" +#include "prefix.h" +#include "zclient.h" +#include "stream.h" +#include "network.h" +#include "log.h" +#include "memory.h" +#include "nexthop.h" +#include "mpls.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_label.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_debug.h" + +extern struct zclient *zclient; + +int +bgp_parse_fec_update (void) +{ + struct stream *s; + struct bgp_node *rn; + struct bgp *bgp; + struct bgp_table *table; + struct prefix p; + u_int32_t label; + afi_t afi; + safi_t safi; + + s = zclient->ibuf; + + memset(&p, 0, sizeof(struct prefix)); + p.family = stream_getw(s); + p.prefixlen = stream_getc(s); + stream_get(&p.u.prefix, s, PSIZE(p.prefixlen)); + label = stream_getl(s); + + /* hack for the bgp instance & SAFI = have to send/receive it */ + afi = family2afi(p.family); + safi = SAFI_LABELED_UNICAST; + bgp = bgp_get_default(); + if (!bgp) + { + zlog_debug("no default bgp instance"); + return -1; + } + + table = bgp->rib[afi][safi]; + if (!table) + { + zlog_debug("no %u labeled-unicast table", p.family); + return -1; + } + rn = bgp_node_lookup(table, &p); + if (!rn) + { + zlog_debug("no node for the prefix"); + return -1; + } + + /* treat it as implicit withdraw - the label is invalid */ + if (label == MPLS_INVALID_LABEL) + bgp_unset_valid_label(rn->local_label); + else + { + label_ntop(label, 1, rn->local_label); + bgp_set_valid_label(rn->local_label); + } + SET_FLAG(rn->flags, BGP_NODE_LABEL_CHANGED); + bgp_unlock_node (rn); + bgp_process (bgp, rn, afi, safi); + return 1; +} + +u_char * +bgp_adv_label (struct bgp_node *rn, struct bgp_info *ri, struct peer *to, + afi_t afi, safi_t safi) +{ + struct peer *from; + u_char *remote_label; + int reflect; + + if (!rn || !ri || !to) + return NULL; + + remote_label = ri->extra ? ri->extra->tag : NULL; + from = ri->peer; + reflect = ((from->sort == BGP_PEER_IBGP) && (to->sort == BGP_PEER_IBGP)); + + if (reflect && !CHECK_FLAG(to->af_flags[afi][safi], + PEER_FLAG_FORCE_NEXTHOP_SELF)) + return remote_label; + + if (CHECK_FLAG(to->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)) + return remote_label; + + return rn->local_label; +} + +void +bgp_reg_dereg_for_label (struct bgp_node *rn, int reg) +{ + struct stream *s; + struct prefix *p; + int command; + + /* Check socket. */ + if (!zclient || zclient->sock < 0) + return; + + p = &(rn->p); + s = zclient->obuf; + stream_reset (s); + command = (reg) ? ZEBRA_FEC_REGISTER : ZEBRA_FEC_UNREGISTER; + zclient_create_header (s, command, VRF_DEFAULT); + stream_putw(s, PREFIX_FAMILY(p)); + stream_put_prefix(s, p); + stream_putw_at (s, 0, stream_get_endp (s)); + zclient_send_message(zclient); + + return; +} + +static int +bgp_nlri_get_labels (struct peer *peer, u_char *pnt, u_char plen, + u_char label[]) +{ + u_char *data = pnt; + u_char *lim = pnt + plen; + u_char llen = 0; + + for (; data < lim; data += BGP_LABEL_BYTES) + { + memcpy(label, data, BGP_LABEL_BYTES); + llen += 3; + if (bgp_is_withdraw_label(label) || label_bos(label)) + break; + } + if (!(bgp_is_withdraw_label(label) || label_bos(label))) + zlog_warn("%s: [Update:RCVD] invalid label - no bottom of stack", + peer->host); + + return llen; +} + +int +bgp_nlri_parse_label (struct peer *peer, struct attr *attr, + struct bgp_nlri *packet) +{ + u_char *pnt; + u_char *lim; + struct prefix p; + int psize = 0; + int prefixlen; + afi_t afi; + safi_t safi; + int addpath_encoded; + u_int32_t addpath_id; + u_char label[3]; + u_char llen; + + /* Check peer status. */ + if (peer->status != Established) + return 0; + + pnt = packet->nlri; + lim = pnt + packet->length; + afi = packet->afi; + safi = packet->safi; + addpath_id = 0; + + addpath_encoded = (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV) && + CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_RCV)); + + for (; pnt < lim; pnt += psize) + { + /* Clear prefix structure. */ + memset (&p, 0, sizeof (struct prefix)); + llen = 0; + + if (addpath_encoded) + { + + /* When packet overflow occurs return immediately. */ + if (pnt + BGP_ADDPATH_ID_LEN > lim) + return -1; + + addpath_id = ntohl(*((uint32_t*) pnt)); + pnt += BGP_ADDPATH_ID_LEN; + } + + /* Fetch prefix length. */ + prefixlen = *pnt++; + p.family = afi2family (packet->afi); + psize = PSIZE (prefixlen); + + /* sanity check against packet data */ + if ((pnt + psize) > lim) + { + zlog_err ("%s [Error] Update packet error / L-U (prefix length %d exceeds packet size %u)", + peer->host, + prefixlen, (uint)(lim-pnt)); + return -1; + } + + /* Fill in the labels */ + llen = bgp_nlri_get_labels(peer, pnt, psize, label); + // zlog_debug("rcvd label [%x/%x/%x], llen=%d\n", label[0], label[1], label[2], llen); + p.prefixlen -= BSIZE(llen); + + /* There needs to be at least one label */ + if (prefixlen < 24) + { + zlog_err ("%s [Error] Update packet error" + " (wrong label length %d)", + peer->host, prefixlen); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NETWORK); + return -1; + } + + if ((afi == AFI_IP && p.prefixlen > 32) + || (afi == AFI_IP6 && p.prefixlen > 128)) + return -1; + + /* Fetch prefix from NLRI packet */ + memcpy (&p.u.prefix, pnt + llen, psize - llen); + + /* Check address. */ + if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST) + { + if (IN_CLASSD (ntohl (p.u.prefix4.s_addr))) + { + /* From RFC4271 Section 6.3: + * + * If a prefix in the NLRI field is semantically incorrect + * (e.g., an unexpected multicast IP address), an error SHOULD + * be logged locally, and the prefix SHOULD be ignored. + */ + zlog_err ("%s: IPv4 labeled-unicast NLRI is multicast address %s, ignoring", + peer->host, inet_ntoa (p.u.prefix4)); + continue; + } + } + + /* Check address. */ + if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST) + { + if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) + { + char buf[BUFSIZ]; + + zlog_err ("%s: IPv6 labeled-unicast NLRI is link-local address %s, ignoring", + peer->host, inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ)); + + continue; + } + + if (IN6_IS_ADDR_MULTICAST (&p.u.prefix6)) + { + char buf[BUFSIZ]; + + zlog_err ("%s: IPv6 unicast NLRI is multicast address %s, ignoring", + peer->host, inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ)); + + continue; + } + } + + if (attr) + { + bgp_update (peer, &p, addpath_id, attr, packet->afi, SAFI_LABELED_UNICAST, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label, 0, NULL); + } + else + { + bgp_withdraw (peer, &p, addpath_id, attr, packet->afi, SAFI_LABELED_UNICAST, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label, NULL); + } + } + + /* Packet length consistency check. */ + if (pnt != lim) + { + zlog_err ("%s [Error] Update packet error / L-U (%zu data remaining after parsing)", + peer->host, lim - pnt); + return -1; + } + + return 0; +} diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h new file mode 100644 index 0000000000..a7e7d5c47b --- /dev/null +++ b/bgpd/bgp_label.h @@ -0,0 +1,124 @@ +/* BGP carrying Label information + * Copyright (C) 2013 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _BGP_LABEL_H +#define _BGP_LABEL_H + +#define BGP_LABEL_BYTES 3 +#define BGP_LABEL_BITS 24 +#define BGP_WITHDRAW_LABEL 0x800000 + +struct bgp_node; +struct bgp_info; +struct peer; + +extern void bgp_reg_dereg_for_label (struct bgp_node *rn, int reg); +extern int bgp_parse_fec_update(void); +extern u_char * bgp_adv_label(struct bgp_node *rn, struct bgp_info *ri, + struct peer *to, afi_t afi, safi_t safi); + +extern int bgp_nlri_parse_label (struct peer *peer, struct attr *attr, + struct bgp_nlri *packet); + +static inline int +bgp_labeled_safi (safi_t safi) +{ + if ((safi == SAFI_LABELED_UNICAST) || (safi == SAFI_MPLS_VPN)) + return 1; + return 0; +} + +static inline int +bgp_is_withdraw_label (u_char *pkt) +{ + if ((pkt[0] == 0x80) && (pkt[1] == 0x00) && (pkt[2] == 0x00)) + return 1; + return 0; +} + +static inline u_char * +bgp_encode_withdraw_label (u_char *pkt) +{ + *pkt++ = 0x80; *pkt++ = 0x00; *pkt++ = 0x00; + return pkt; +} + +static inline int +bgp_is_valid_label (u_char *t) +{ + if (!t) + return 0; + return (t[2] & 0x02); +} + +static inline void +bgp_set_valid_label (u_char *t) +{ + if (t) + t[2] |= 0x02; +} + +static inline void +bgp_unset_valid_label (u_char *t) +{ + if (t) + t[2] &= ~0x02; +} + +static inline void +bgp_register_for_label (struct bgp_node *rn) +{ + bgp_reg_dereg_for_label (rn, 1); +} + +static inline void +bgp_unregister_for_label (struct bgp_node *rn) +{ + bgp_reg_dereg_for_label (rn, 0); +} + +/* Label stream to value */ +static inline u_int32_t +label_pton (u_char t[]) +{ + return ((((unsigned int) t[0]) << 12) | (((unsigned int) t[1]) << 4) | + ((unsigned int) ((t[2] & 0xF0) >> 4))); +} + +/* Encode label values */ +static inline void +label_ntop (u_int32_t l, int bos, u_char t[]) +{ + t[0] = ((l & 0x000FF000) >> 12); + t[1] = ((l & 0x00000FF0) >> 4); + t[2] = ((l & 0x0000000F) << 4); + if (bos) + t[2] |= 0x01; +} + +/* Return BOS value of label stream */ +static inline u_char +label_bos (u_char t[]) +{ + return (t[2] & 0x01); +}; + +#endif /* _BGP_LABEL_H */ diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 423c9453eb..152d4a7acd 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -235,6 +235,8 @@ bgp_exit (int status) stream_free (bgp_nexthop_buf); if (bgp_ifindices_buf) stream_free (bgp_ifindices_buf); + if (bgp_label_buf) + stream_free (bgp_label_buf); /* reverse bgp_master_init */ if (bm->master) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index b0362b5537..1e8dc5d974 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -404,8 +404,9 @@ bgp_parse_nexthop_update (int command, vrf_id_t vrf_id) { char buf[PREFIX2STR_BUFFER]; prefix2str(&p, buf, sizeof (buf)); - zlog_debug("%d: NH update for %s - metric %d (cur %d) #nhops %d (cur %d)", - vrf_id, buf, metric, bnc->metric, nexthop_num, bnc->nexthop_num); + zlog_debug("%d: Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x", + vrf_id, buf, metric, bnc->metric, nexthop_num, bnc->nexthop_num, + bnc->flags); } if (metric != bnc->metric) @@ -678,6 +679,8 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) struct bgp *bgp = bnc->bgp; int afi; struct peer *peer = (struct peer *)bnc->nht_info; + struct bgp_table *table; + safi_t safi; if (BGP_DEBUG(nht, NHT)) { @@ -695,7 +698,10 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) continue; rn = path->net; + assert (rn && bgp_node_table (rn)); afi = family2afi(rn->p.family); + table = bgp_node_table (rn); + safi = table->safi; /* Path becomes valid/invalid depending on whether the nexthop * reachable/unreachable. @@ -705,15 +711,13 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) { if (CHECK_FLAG (path->flags, BGP_INFO_VALID)) { - bgp_aggregate_decrement (bgp, &rn->p, path, - afi, SAFI_UNICAST); + bgp_aggregate_decrement (bgp, &rn->p, path, afi, safi); bgp_info_unset_flag (rn, path, BGP_INFO_VALID); } else { bgp_info_set_flag (rn, path, BGP_INFO_VALID); - bgp_aggregate_increment (bgp, &rn->p, path, - afi, SAFI_UNICAST); + bgp_aggregate_increment (bgp, &rn->p, path, afi, safi); } } @@ -727,7 +731,7 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED)) SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED); - bgp_process(bgp, rn, afi, SAFI_UNICAST); + bgp_process(bgp, rn, afi, safi); } if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED)) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 51079f31e0..83fc3fe977 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -108,6 +108,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso case SAFI_MULTICAST: json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "multicast"); break; + case SAFI_LABELED_UNICAST: + json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "labeled-unicast"); + break; case SAFI_MPLS_VPN: json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "MPLS-labeled VPN"); break; @@ -148,6 +151,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso case SAFI_MULTICAST: vty_out (vty, "SAFI Multicast"); break; + case SAFI_LABELED_UNICAST: + vty_out (vty, "SAFI Labeled-unicast"); + break; case SAFI_MPLS_VPN: vty_out (vty, "SAFI MPLS-labeled VPN"); break; @@ -1143,10 +1149,12 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability) { if (! peer->afc_nego[AFI_IP][SAFI_UNICAST] && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST] + && ! peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] && ! peer->afc_nego[AFI_IP][SAFI_ENCAP] && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST] && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST] + && ! peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] && ! peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] && ! peer->afc_nego[AFI_IP6][SAFI_ENCAP] && ! peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 853fcc8697..f7a78caf91 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -55,6 +55,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_updgrp.h" +#include "bgpd/bgp_label.h" /* Set up BGP packet marker and packet type. */ int @@ -1153,8 +1154,10 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) { peer->afc_nego[AFI_IP][SAFI_UNICAST] = peer->afc[AFI_IP][SAFI_UNICAST]; peer->afc_nego[AFI_IP][SAFI_MULTICAST] = peer->afc[AFI_IP][SAFI_MULTICAST]; + peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] = peer->afc[AFI_IP][SAFI_LABELED_UNICAST]; peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST]; peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST]; + peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] = peer->afc[AFI_IP6][SAFI_LABELED_UNICAST]; } /* When collision is detected and this peer is closed. Retrun @@ -1342,6 +1345,8 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet, i case SAFI_UNICAST: case SAFI_MULTICAST: return bgp_nlri_parse_ip (peer, mp_withdraw?NULL:attr, packet); + case SAFI_LABELED_UNICAST: + return bgp_nlri_parse_label (peer, attr, packet); case SAFI_MPLS_VPN: return bgp_nlri_parse_vpn (peer, mp_withdraw?NULL:attr, packet); case SAFI_ENCAP: diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 432a566c15..77154b0f33 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -35,6 +35,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "thread.h" #include "workqueue.h" #include "queue.h" +#include "mpls.h" #include "memory.h" #include "lib/json.h" @@ -62,6 +63,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_mpath.h" #include "bgpd/bgp_nht.h" #include "bgpd/bgp_updgrp.h" +#include "bgpd/bgp_label.h" #if ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" @@ -1187,7 +1189,8 @@ subgroup_announce_reset_nhop (u_char family, struct attr *attr) } int -subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp, +subgroup_announce_check (struct bgp_node *rn, struct bgp_info *ri, + struct update_subgroup *subgrp, struct prefix *p, struct attr *attr) { struct bgp_filter *filter; @@ -1261,6 +1264,21 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp, return 0; } + /* If it's labeled safi, make sure the route has a valid label. */ + if (bgp_labeled_safi(safi)) + { + u_char *tag = bgp_adv_label(rn, ri, peer, afi, safi); + if (!bgp_is_valid_label(tag)) + { + if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) + zlog_debug ("u%" PRIu64 ":s%" PRIu64 " %s/%d is filtered - no label (%p)", + subgrp->update_group->id, subgrp->id, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen, tag); + return 0; + } + } + /* Do not send back route to sender. */ if (onlypeer && from == onlypeer) { @@ -1804,7 +1822,7 @@ subgroup_process_announce_selected (struct update_subgroup *subgrp, /* Announcement to the subgroup. If the route is filtered withdraw it. */ if (selected) { - if (subgroup_announce_check(selected, subgrp, p, &attr)) + if (subgroup_announce_check(rn, selected, subgrp, p, &attr)) bgp_adj_out_set_subgroup(rn, subgrp, &attr, selected); else bgp_adj_out_unset_subgroup(rn, subgrp, 1, selected->addpath_tx_id); @@ -1890,6 +1908,7 @@ bgp_process_main (struct work_queue *wq, void *data) struct bgp_info *new_select; struct bgp_info *old_select; struct bgp_info_pair old_and_new; + int label_valid; /* Is it end of initial update? (after startup) */ if (!rn) @@ -1914,7 +1933,24 @@ bgp_process_main (struct work_queue *wq, void *data) old_select = old_and_new.old; new_select = old_and_new.new; - /* Nothing to do. */ + /* Do we need to allocate or free labels? + * Right now, since we only deal with per-prefix labels, it is not necessary + * to do this upon changes to best path. + */ + bgp_table_lock (bgp_node_table (rn)); + if (bgp_labeled_safi (safi)) + { + label_valid = bgp_is_valid_label (rn->local_label); + if (!old_select && new_select && !label_valid) + bgp_register_for_label (rn); + else if (old_select && !new_select) + bgp_unregister_for_label (rn); + } + + /* If best route remains the same and this is not due to user-initiated + * clear, see exactly what needs to be done. + */ + if (old_select && old_select == new_select && !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR) && !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED) && @@ -1926,10 +1962,26 @@ bgp_process_main (struct work_queue *wq, void *data) vnc_import_bgp_add_route(bgp, p, old_select); vnc_import_bgp_exterior_add_route(bgp, p, old_select); #endif - bgp_zebra_announce (p, old_select, bgp, afi, safi); + if (bgp_fibupd_safi(safi) && + !bgp->name && + !bgp_option_check (BGP_OPT_NO_FIB) && + new_select->type == ZEBRA_ROUTE_BGP && + new_select->sub_type == BGP_ROUTE_NORMAL) + bgp_zebra_announce (rn, p, old_select, bgp, afi, safi); } UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG); bgp_zebra_clear_route_change_flags (rn); + + /* If there is a change of interest to peers, reannounce the route. */ + if (CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED) || + CHECK_FLAG (rn->flags, BGP_NODE_LABEL_CHANGED)) + { + group_announce_route(bgp, afi, safi, rn, new_select); + + UNSET_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED); + UNSET_FLAG (rn->flags, BGP_NODE_LABEL_CHANGED); + } + UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return WQ_SUCCESS; } @@ -1978,7 +2030,7 @@ bgp_process_main (struct work_queue *wq, void *data) group_announce_route(bgp, afi, safi, rn, new_select); /* FIB update. */ - if ((safi == SAFI_UNICAST || safi == SAFI_MULTICAST) && + if (bgp_fibupd_safi(safi) && (bgp->inst_type != BGP_INSTANCE_TYPE_VIEW) && !bgp_option_check (BGP_OPT_NO_FIB)) { @@ -1986,7 +2038,7 @@ bgp_process_main (struct work_queue *wq, void *data) && new_select->type == ZEBRA_ROUTE_BGP && (new_select->sub_type == BGP_ROUTE_NORMAL || new_select->sub_type == BGP_ROUTE_AGGREGATE)) - bgp_zebra_announce (p, new_select, bgp, afi, safi); + bgp_zebra_announce (rn, p, new_select, bgp, afi, safi); else { /* Withdraw the route from the kernel. */ @@ -2406,6 +2458,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, struct bgp_info *new; const char *reason; char pfx_buf[BGP_PRD_PATH_STRLEN]; + char label_buf[20]; int connected = 0; int do_loop_check = 1; #if ENABLE_BGP_VNC @@ -2417,6 +2470,9 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, bgp = peer->bgp; rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); + label_buf[0] = '\0'; + if (bgp_labeled_safi(safi)) + sprintf (label_buf, "label %u", label_pton(tag)); /* When peer's soft reconfiguration enabled. Record input packet in Adj-RIBs-In. */ @@ -2516,6 +2572,8 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* Same attribute comes in. */ if (!CHECK_FLAG (ri->flags, BGP_INFO_REMOVED) && attrhash_cmp (ri->attr, attr_new) + && (!bgp_labeled_safi(safi) || + memcmp ((bgp_info_extra_get (ri))->tag, tag, 3) == 0) && (overlay_index_equal(afi, ri, evpn==NULL?NULL:&evpn->eth_s_id, evpn==NULL?NULL:&evpn->gw_ip))) { @@ -2524,9 +2582,9 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, && CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) { if (bgp_debug_update(peer, p, NULL, 1)) - zlog_debug ("%s rcvd %s", peer->host, + zlog_debug ("%s rcvd %s %s", peer->host, bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf))); + addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf); if (bgp_damp_update (ri, rn, afi, safi) != BGP_DAMP_SUPPRESSED) { @@ -2544,10 +2602,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, peer->rcvd_attr_printed = 1; } - zlog_debug ("%s rcvd %s...duplicate ignored", + zlog_debug ("%s rcvd %s %s...duplicate ignored", peer->host, bgp_debug_rdpfxpath2str (prd, p, addpath_id ? - 1 : 0, addpath_id, pfx_buf, sizeof (pfx_buf))); + 1 : 0, addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf); } /* graceful restart STALE flag unset. */ @@ -2568,18 +2626,18 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { if (bgp_debug_update(peer, p, NULL, 1)) - zlog_debug ("%s rcvd %s, flapped quicker than processing", + zlog_debug ("%s rcvd %s %s, flapped quicker than processing", peer->host, bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf))); + addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf); bgp_info_restore (rn, ri); } /* Received Logging. */ if (bgp_debug_update(peer, p, NULL, 1)) - zlog_debug ("%s rcvd %s", peer->host, + zlog_debug ("%s rcvd %s %s", peer->host, bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf))); + addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf); /* graceful restart STALE flag unset. */ if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) @@ -2637,7 +2695,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, ri->attr = attr_new; /* Update MPLS tag. */ - if (safi == SAFI_MPLS_VPN || safi == SAFI_EVPN) + if (bgp_labeled_safi(safi)) memcpy ((bgp_info_extra_get (ri))->tag, tag, 3); #if ENABLE_BGP_VNC @@ -2678,8 +2736,9 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, } } - /* Nexthop reachability check. */ - if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST) + /* Nexthop reachability check - for unicast and labeled-unicast.. */ + if ((afi == AFI_IP || afi == AFI_IP6) && + (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) { if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) @@ -2759,16 +2818,16 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, peer->rcvd_attr_printed = 1; } - zlog_debug ("%s rcvd %s", peer->host, + zlog_debug ("%s rcvd %s%s ", peer->host, bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf))); + addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf); } /* Make new BGP info. */ new = info_make(type, sub_type, 0, peer, attr_new, rn); /* Update MPLS tag. */ - if (safi == SAFI_MPLS_VPN || safi == SAFI_EVPN) + if (bgp_labeled_safi(safi) || safi == SAFI_EVPN) memcpy ((bgp_info_extra_get (new))->tag, tag, 3); /* Update Overlay Index */ @@ -2778,7 +2837,8 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, evpn==NULL?NULL:&evpn->gw_ip); } /* Nexthop reachability check. */ - if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST) + if ((afi == AFI_IP || afi == AFI_IP6) && + (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) { if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) @@ -2873,10 +2933,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, peer->rcvd_attr_printed = 1; } - zlog_debug ("%s rcvd UPDATE about %s -- DENIED due to: %s", + zlog_debug ("%s rcvd UPDATE about %s %s -- DENIED due to: %s", peer->host, bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf)), reason); + addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf, reason); } if (ri) @@ -3818,9 +3878,11 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, #endif /* Nexthop reachability check. */ - if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) + if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK) && + safi == SAFI_UNICAST) { - if (bgp_find_or_add_nexthop (bgp, afi, ri, NULL, 0)) + if (bgp_find_or_add_nexthop (bgp, afi, ri, NULL, 0) && + safi == SAFI_UNICAST) bgp_info_set_flag (rn, ri, BGP_INFO_VALID); else { @@ -5557,6 +5619,8 @@ bgp_aggregate_unset (struct vty *vty, const char *prefix_str, aggregate = rn->info; if (aggregate->safi & SAFI_UNICAST) bgp_aggregate_delete (bgp, &p, afi, SAFI_UNICAST, aggregate); + if (aggregate->safi & SAFI_LABELED_UNICAST) + bgp_aggregate_delete (bgp, &p, afi, SAFI_LABELED_UNICAST, aggregate); if (aggregate->safi & SAFI_MULTICAST) bgp_aggregate_delete (bgp, &p, afi, SAFI_MULTICAST, aggregate); @@ -5615,6 +5679,8 @@ bgp_aggregate_set (struct vty *vty, const char *prefix_str, /* Aggregate address insert into BGP routing table. */ if (safi & SAFI_UNICAST) bgp_aggregate_add (bgp, &p, afi, SAFI_UNICAST, aggregate); + if (safi & SAFI_LABELED_UNICAST) + bgp_aggregate_add (bgp, &p, afi, SAFI_LABELED_UNICAST, aggregate); if (safi & SAFI_MULTICAST) bgp_aggregate_add (bgp, &p, afi, SAFI_MULTICAST, aggregate); @@ -7439,6 +7505,15 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (binfo->extra && binfo->extra->damp_info) bgp_damp_info_vty (vty, binfo, json_path); + if (bgp_labeled_safi(safi) && binfo->extra) + { + uint32_t label = label_pton(binfo->extra->tag); + if (json_paths) + json_object_int_add(json_path, "remote-label", label); + else + vty_out(vty, " Remote label: %d%s", label, VTY_NEWLINE); + } + /* Line 8 display Addpath IDs */ if (binfo->addpath_rx_id || binfo->addpath_tx_id) { @@ -7932,6 +8007,18 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) ? ":" : "", buf2, p->prefixlen, VTY_NEWLINE); + + if (bgp_labeled_safi(safi)) + { + vty_out(vty, "Local label: "); + if (!bgp_is_valid_label(rn->local_label)) + vty_out(vty, "not allocated%s", VTY_NEWLINE); + else + { + uint32_t label = label_pton(rn->local_label); + vty_out(vty, "%d%s", label, VTY_NEWLINE); + } + } } for (ri = rn->info; ri; ri = ri->next) diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index e75978d003..69b8ea8a55 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -150,6 +150,7 @@ struct bgp_info #define BGP_INFO_COUNTED (1 << 10) #define BGP_INFO_MULTIPATH (1 << 11) #define BGP_INFO_MULTIPATH_CHG (1 << 12) +#define BGP_INFO_RIB_ATTR_CHG (1 << 13) /* BGP route type. This can be static, RIP, OSPF, BGP etc. */ u_char type; @@ -273,6 +274,16 @@ bgp_bump_version (struct bgp_node *node) node->version = bgp_table_next_version(bgp_node_table(node)); } +static inline int +bgp_fibupd_safi (safi_t safi) +{ + if (safi == SAFI_UNICAST || + safi == SAFI_MULTICAST || + safi == SAFI_LABELED_UNICAST) + return 1; + return 0; +} + /* Prototypes. */ extern void bgp_process_queue_init (void); extern void bgp_route_init (void); @@ -370,7 +381,7 @@ subgroup_process_announce_selected (struct update_subgroup *subgrp, struct bgp_node *rn, u_int32_t addpath_tx_id); -extern int subgroup_announce_check(struct bgp_info *ri, +extern int subgroup_announce_check(struct bgp_node *rn, struct bgp_info *ri, struct update_subgroup *subgrp, struct prefix *p, struct attr *attr); diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 3c96dac617..2b874f66a6 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -56,10 +56,13 @@ struct bgp_node struct bgp_node *prn; + u_char local_label[3]; + uint64_t version; u_char flags; #define BGP_NODE_PROCESS_SCHEDULED (1 << 0) #define BGP_NODE_USER_CLEAR (1 << 1) +#define BGP_NODE_LABEL_CHANGED (1 << 2) }; /* diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index efb2046e12..ac5f77474c 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -618,7 +618,7 @@ subgroup_announce_table (struct update_subgroup *subgrp, if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) || (addpath_capable && bgp_addpath_tx_path(peer, afi, safi, ri))) { - if (subgroup_announce_check (ri, subgrp, &rn->p, &attr)) + if (subgroup_announce_check (rn, ri, subgrp, &rn->p, &attr)) bgp_adj_out_set_subgroup (rn, subgrp, &attr, ri); else bgp_adj_out_unset_subgroup (rn, subgrp, 1, ri->addpath_tx_id); diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 57e5c07029..135cdadb24 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -43,6 +43,7 @@ #include "workqueue.h" #include "hash.h" #include "queue.h" +#include "mpls.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_debug.h" @@ -54,6 +55,7 @@ #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_nht.h" #include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_label.h" /******************** * PRIVATE FUNCTIONS @@ -653,6 +655,7 @@ subgroup_update_packet (struct update_subgroup *subgrp) int addpath_encode = 0; u_int32_t addpath_tx_id = 0; struct prefix_rd *prd = NULL; + char label_buf[20]; if (!subgrp) return NULL; @@ -660,7 +663,6 @@ subgroup_update_packet (struct update_subgroup *subgrp) if (bpacket_queue_is_full (SUBGRP_INST (subgrp), SUBGRP_PKTQ (subgrp))) return NULL; - peer = SUBGRP_PEER (subgrp); afi = SUBGRP_AFI (subgrp); safi = SUBGRP_SAFI (subgrp); @@ -668,6 +670,7 @@ subgroup_update_packet (struct update_subgroup *subgrp) stream_reset (s); snlri = subgrp->scratch; stream_reset (snlri); + label_buf[0] = '\0'; bpacket_attr_vec_arr_reset (&vecarr); @@ -760,8 +763,9 @@ subgroup_update_packet (struct update_subgroup *subgrp) if (rn->prn) prd = (struct prefix_rd *) &rn->prn->p; - if (binfo && binfo->extra) - tag = binfo->extra->tag; + tag = bgp_adv_label(rn, binfo, peer, afi, safi); + if (bgp_labeled_safi(safi)) + sprintf (label_buf, "label %u", label_pton(tag)); if (stream_empty (snlri)) mpattrlen_pos = bgp_packet_mpattr_start (snlri, afi, safi, @@ -797,11 +801,12 @@ subgroup_update_packet (struct update_subgroup *subgrp) send_attr_printed = 1; } - zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s", + zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s %s", subgrp->update_group->id, subgrp->id, bgp_debug_rdpfxpath2str (prd, &rn->p, addpath_encode, addpath_tx_id, - pfx_buf, sizeof (pfx_buf))); + pfx_buf, sizeof (pfx_buf)), + label_buf); } /* Synchnorize attribute. */ diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 72bd081a7e..1ded613f65 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -34,6 +34,7 @@ Boston, MA 02111-1307, USA. */ #include "lib/json.h" #include "lib/bfd.h" #include "filter.h" +#include "mpls.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" @@ -46,6 +47,7 @@ Boston, MA 02111-1307, USA. */ #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_nht.h" #include "bgpd/bgp_bfd.h" +#include "bgpd/bgp_label.h" #if ENABLE_BGP_VNC # include "bgpd/rfapi/rfapi_backend.h" # include "bgpd/rfapi/vnc_export_bgp.h" @@ -57,6 +59,7 @@ struct zclient *zclient = NULL; /* Growable buffer for nexthops sent to zebra */ struct stream *bgp_nexthop_buf = NULL; struct stream *bgp_ifindices_buf = NULL; +struct stream *bgp_label_buf = NULL; /* These array buffers are used in making a copy of the attributes for route-map apply. Arrays are being used here to minimize mallocs and @@ -178,6 +181,14 @@ bgp_update_interface_nbrs (struct bgp *bgp, struct interface *ifp, } } +static int +bgp_read_fec_update (int command, struct zclient *zclient, + zebra_size_t length) +{ + bgp_parse_fec_update(); + return 0; +} + static void bgp_start_interface_nbrs (struct bgp *bgp, struct interface *ifp) { @@ -1204,8 +1215,8 @@ bgp_table_map_apply (struct route_map *map, struct prefix *p, } void -bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, - afi_t afi, safi_t safi) +bgp_zebra_announce (struct bgp_node *rn, struct prefix *p, struct bgp_info *info, + struct bgp *bgp, afi_t afi, safi_t safi) { u_int32_t flags; u_char distance; @@ -1216,6 +1227,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, struct bgp_info local_info; struct bgp_info *info_cp = &local_info; route_tag_t tag; + u_int32_t label; /* Don't try to install if we're not connected to Zebra or Zebra doesn't * know of this instance. @@ -1271,7 +1283,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, if ((oldsize = stream_get_size (bgp_nexthop_buf)) < (sizeof (struct in_addr *) * nhcount)) { - newsize = (sizeof (struct in_addr *) * nhcount); + newsize = sizeof (struct in_addr *) * nhcount; newsize = stream_resize (bgp_nexthop_buf, newsize); if (newsize == oldsize) { @@ -1282,6 +1294,25 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, stream_reset (bgp_nexthop_buf); nexthop = NULL; + /* For labeled unicast, each nexthop has a label too. Resize label + * buffer, if required. + */ + if (safi == SAFI_LABELED_UNICAST) + { + if ((oldsize = stream_get_size (bgp_label_buf)) < + (sizeof (unsigned int) * nhcount)) + { + newsize = (sizeof (unsigned int) * nhcount); + newsize = stream_resize (bgp_label_buf, newsize); + if (newsize == oldsize) + { + zlog_err ("can't resize label buffer"); + return; + } + } + stream_reset (bgp_label_buf); + } + /* Metric is currently based on the best-path only. */ metric = info->attr->med; @@ -1311,6 +1342,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, { stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *)); valid_nh_count++; + if (safi == SAFI_LABELED_UNICAST) + { + label = label_pton(info->extra->tag); + stream_put (bgp_label_buf, &label, sizeof (u_int32_t)); + } } for (mpinfo = bgp_info_mpath_first (info); mpinfo; @@ -1336,6 +1372,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, continue; stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *)); + if (safi == SAFI_LABELED_UNICAST) + { + label = label_pton(mpinfo->extra->tag); + stream_put (bgp_label_buf, &label, sizeof (u_int32_t)); + } valid_nh_count++; } @@ -1344,8 +1385,10 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, api.type = ZEBRA_ROUTE_BGP; api.instance = 0; api.message = 0; - api.safi = safi; + api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + if (safi == SAFI_LABELED_UNICAST) + SET_FLAG (api.message, ZAPI_MESSAGE_LABEL); /* Note that this currently only applies to Null0 routes for aggregates. * ZEBRA_FLAG_BLACKHOLE signals zapi_ipv4_route to encode a special @@ -1358,6 +1401,16 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, api.nexthop_num = valid_nh_count; api.nexthop = (struct in_addr **)STREAM_DATA (bgp_nexthop_buf); + if (safi == SAFI_LABELED_UNICAST) + { + api.label_num = valid_nh_count; + api.label = (unsigned int *)STREAM_DATA (bgp_label_buf); + } + else + { + api.label_num = 0; + api.label = NULL; + } api.ifindex_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = metric; @@ -1379,14 +1432,22 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, if (bgp_debug_zebra(p)) { int i; + char label_buf[20]; zlog_debug("Tx IPv4 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI " count %d", (valid_nh_count ? "add":"delete"), bgp->vrf_id, inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])), p->prefixlen, api.metric, api.tag, api.nexthop_num); for (i = 0; i < api.nexthop_num; i++) - zlog_debug(" IPv4 [nexthop %d] %s", i+1, - inet_ntop(AF_INET, api.nexthop[i], buf[1], sizeof(buf[1]))); + { + label_buf[0] = '\0'; + if (safi == SAFI_LABELED_UNICAST) + sprintf(label_buf, "label %u", api.label[i]); + zlog_debug(" nhop [%d]: %s %s", + i+1, + inet_ntop(AF_INET, api.nexthop[i], buf[1], sizeof(buf[1])), + label_buf); + } } zapi_ipv4_route (valid_nh_count ? ZEBRA_IPV4_ROUTE_ADD: ZEBRA_IPV4_ROUTE_DELETE, @@ -1431,6 +1492,25 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, } stream_reset (bgp_ifindices_buf); + /* For labeled unicast, each nexthop has a label too. Resize label + * buffer, if required. + */ + if (safi == SAFI_LABELED_UNICAST) + { + if ((oldsize = stream_get_size (bgp_label_buf)) < + (sizeof (unsigned int) * nhcount)) + { + newsize = (sizeof (unsigned int) * nhcount); + newsize = stream_resize (bgp_label_buf, newsize); + if (newsize == oldsize) + { + zlog_err ("can't resize label buffer"); + return; + } + } + stream_reset (bgp_label_buf); + } + ifindex = 0; nexthop = NULL; @@ -1476,6 +1556,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, } stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *)); stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int)); + if (safi == SAFI_LABELED_UNICAST) + { + label = label_pton(info->extra->tag); + stream_put (bgp_label_buf, &label, sizeof (u_int32_t)); + } valid_nh_count++; } @@ -1518,6 +1603,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *)); stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int)); + if (safi == SAFI_LABELED_UNICAST) + { + label = label_pton(mpinfo->extra->tag); + stream_put (bgp_label_buf, &label, sizeof (u_int32_t)); + } valid_nh_count++; } @@ -1527,8 +1617,10 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, api.type = ZEBRA_ROUTE_BGP; api.instance = 0; api.message = 0; - api.safi = safi; + api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + if (safi == SAFI_LABELED_UNICAST) + SET_FLAG (api.message, ZAPI_MESSAGE_LABEL); /* Note that this currently only applies to Null0 routes for aggregates. * ZEBRA_FLAG_BLACKHOLE signals zapi_ipv6_route to encode a special @@ -1544,6 +1636,16 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.ifindex_num = valid_nh_count; api.ifindex = (ifindex_t *)STREAM_DATA (bgp_ifindices_buf); + if (safi == SAFI_LABELED_UNICAST) + { + api.label_num = valid_nh_count; + api.label = (unsigned int *)STREAM_DATA (bgp_label_buf); + } + else + { + api.label_num = 0; + api.label = NULL; + } SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = metric; api.tag = 0; @@ -1566,13 +1668,22 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, if (bgp_debug_zebra(p)) { int i; + char label_buf[20]; zlog_debug("Tx IPv4 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI, valid_nh_count ? "add" : "delete", bgp->vrf_id, inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])), p->prefixlen, api.metric, api.tag); for (i = 0; i < api.nexthop_num; i++) - zlog_debug(" IPv6 [nexthop %d] %s", i+1, - inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1]))); + { + label_buf[0] = '\0'; + if (safi == SAFI_LABELED_UNICAST) + sprintf(label_buf, "label %u", api.label[i]); + zlog_debug(" nhop [%d]: %s if %s %s", + i+1, + inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])), + ifindex2ifname (api.ifindex[i], bgp->vrf_id), + label_buf); + } } if (valid_nh_count) @@ -1588,13 +1699,22 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, if (bgp_debug_zebra(p)) { int i; + char label_buf[20]; zlog_debug("Tx IPv6 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI, valid_nh_count ? "add" : "delete", bgp->vrf_id, inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])), p->prefixlen, api.metric, api.tag); for (i = 0; i < api.nexthop_num; i++) - zlog_debug(" IPv6 [nexthop %d] %s", i+1, - inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1]))); + { + label_buf[0] = '\0'; + if (safi == SAFI_LABELED_UNICAST) + sprintf(label_buf, "label %u", api.label[i]); + zlog_debug(" nhop [%d]: %s if %s %s", + i+1, + inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])), + ifindex2ifname (api.ifindex[i], bgp->vrf_id), + label_buf); + } } zapi_ipv6_route (valid_nh_count ? @@ -1626,7 +1746,7 @@ bgp_zebra_announce_table (struct bgp *bgp, afi_t afi, safi_t safi) if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_NORMAL) - bgp_zebra_announce (&rn->p, ri, bgp, afi, safi); + bgp_zebra_announce (rn, &rn->p, ri, bgp, afi, safi); } void @@ -1673,10 +1793,14 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) api.type = ZEBRA_ROUTE_BGP; api.instance = 0; api.message = 0; - api.safi = safi; + api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + if (safi == SAFI_LABELED_UNICAST) + SET_FLAG (api.message, ZAPI_MESSAGE_LABEL); api.nexthop_num = 0; api.nexthop = NULL; + api.label_num = 0; + api.label = NULL; api.ifindex_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; @@ -1712,11 +1836,14 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) api.type = ZEBRA_ROUTE_BGP; api.instance = 0; api.message = 0; - api.safi = safi; + api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + if (safi == SAFI_LABELED_UNICAST) + SET_FLAG (api.message, ZAPI_MESSAGE_LABEL); api.nexthop_num = 0; api.nexthop = NULL; api.ifindex_num = 0; + api.label_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; api.tag = 0; @@ -2141,6 +2268,7 @@ bgp_zebra_init (struct thread_master *master) zclient->redistribute_route_ipv6_del = zebra_read_ipv6; zclient->nexthop_update = bgp_read_nexthop_update; zclient->import_check_update = bgp_read_import_check_update; + zclient->fec_update = bgp_read_fec_update; bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE); bgp_ifindices_buf = stream_new(BGP_IFINDICES_BUF_SIZE); diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index d22a00e8fb..bc4e36352d 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -23,9 +23,11 @@ Boston, MA 02111-1307, USA. */ #define BGP_NEXTHOP_BUF_SIZE (8 * sizeof (struct in_addr *)) #define BGP_IFINDICES_BUF_SIZE (8 * sizeof (unsigned int)) +#define BGP_LABEL_BUF_SIZE (8 * sizeof (unsigned int)) extern struct stream *bgp_nexthop_buf; extern struct stream *bgp_ifindices_buf; +extern struct stream *bgp_label_buf; extern void bgp_zebra_init (struct thread_master *master); extern void bgp_zebra_destroy (void); @@ -34,8 +36,8 @@ extern int bgp_config_write_maxpaths (struct vty *, struct bgp *, afi_t, safi_t, int *); extern int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t, int *); -extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *, - afi_t, safi_t); +extern void bgp_zebra_announce (struct bgp_node *, struct prefix *, + struct bgp_info *, struct bgp *, afi_t, safi_t); extern void bgp_zebra_announce_table (struct bgp *, afi_t, safi_t); extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *, safi_t); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 0ed277b164..1c73fb9407 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1636,6 +1636,8 @@ peer_as_change (struct peer *peer, as_t as, int as_specified) PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MULTICAST], PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_LABELED_UNICAST], + PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MPLS_VPN], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_ENCAP], @@ -1644,6 +1646,8 @@ peer_as_change (struct peer *peer, as_t as, int as_specified) PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MULTICAST], PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_LABELED_UNICAST], + PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MPLS_VPN], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_ENCAP], @@ -3608,10 +3612,12 @@ peer_active (struct peer *peer) return 0; if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST] + || peer->afc[AFI_IP][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP][SAFI_ENCAP] || peer->afc[AFI_IP6][SAFI_UNICAST] || peer->afc[AFI_IP6][SAFI_MULTICAST] + || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP6][SAFI_MPLS_VPN] || peer->afc[AFI_IP6][SAFI_ENCAP]) return 1; @@ -3624,10 +3630,12 @@ peer_active_nego (struct peer *peer) { if (peer->afc_nego[AFI_IP][SAFI_UNICAST] || peer->afc_nego[AFI_IP][SAFI_MULTICAST] + || peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] || peer->afc_nego[AFI_IP][SAFI_ENCAP] || peer->afc_nego[AFI_IP6][SAFI_UNICAST] || peer->afc_nego[AFI_IP6][SAFI_MULTICAST] + || peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] || peer->afc_nego[AFI_IP6][SAFI_ENCAP]) return 1; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index a72974bc1d..e95d059227 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -76,6 +76,8 @@ enum bgp_af_index BGP_AF_IPV4_ENCAP, BGP_AF_IPV6_ENCAP, BGP_AF_L2VPN_EVPN, + BGP_AF_IPV4_LBL_UNICAST, + BGP_AF_IPV6_LBL_UNICAST, BGP_AF_MAX }; @@ -1394,6 +1396,9 @@ afindex (afi_t afi, safi_t safi) case SAFI_MULTICAST: return BGP_AF_IPV4_MULTICAST; break; + case SAFI_LABELED_UNICAST: + return BGP_AF_IPV4_LBL_UNICAST; + break; case SAFI_MPLS_VPN: return BGP_AF_IPV4_VPN; break; @@ -1414,7 +1419,10 @@ afindex (afi_t afi, safi_t safi) case SAFI_MULTICAST: return BGP_AF_IPV6_MULTICAST; break; - case SAFI_MPLS_VPN: + case SAFI_LABELED_UNICAST: + return BGP_AF_IPV6_LBL_UNICAST; + break; + case SAFI_MPLS_VPN: return BGP_AF_IPV6_VPN; break; case SAFI_ENCAP: @@ -1456,6 +1464,7 @@ peer_afi_active_nego (const struct peer *peer, afi_t afi) { if (peer->afc_nego[afi][SAFI_UNICAST] || peer->afc_nego[afi][SAFI_MULTICAST] + || peer->afc_nego[afi][SAFI_LABELED_UNICAST] || peer->afc_nego[afi][SAFI_MPLS_VPN] || peer->afc_nego[afi][SAFI_ENCAP]) return 1; @@ -1470,10 +1479,12 @@ peer_group_af_configured (struct peer_group *group) if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST] + || peer->afc[AFI_IP][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP][SAFI_ENCAP] || peer->afc[AFI_IP6][SAFI_UNICAST] || peer->afc[AFI_IP6][SAFI_MULTICAST] + || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP6][SAFI_MPLS_VPN] || peer->afc[AFI_IP6][SAFI_ENCAP]) return 1; diff --git a/lib/prefix.h b/lib/prefix.h index eb3ae3dafb..786c2bf7ea 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -244,6 +244,8 @@ union prefixconstptr /* Count prefix size from mask length */ #define PSIZE(a) (((a) + 7) / (8)) +#define BSIZE(a) ((a) * (8)) + /* Prefix's family member. */ #define PREFIX_FAMILY(p) ((p)->family) diff --git a/lib/stream.c b/lib/stream.c index 301ebc6275..32dde1ca0c 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -919,6 +919,31 @@ stream_put_prefix (struct stream *s, struct prefix *p) return stream_put_prefix_addpath (s, p, 0, 0); } +/* Put NLRI with label */ +int +stream_put_labeled_prefix (struct stream *s, struct prefix *p, u_char *label) +{ + size_t psize; + + STREAM_VERIFY_SANE(s); + + psize = PSIZE (p->prefixlen); + + if (STREAM_WRITEABLE (s) < (psize + 3)) + { + STREAM_BOUND_WARN (s, "put"); + return 0; + } + + stream_putc (s, (p->prefixlen + 24)); + stream_putc(s, label[0]); + stream_putc(s, label[1]); + stream_putc(s, label[2]); + memcpy (s->data + s->endp, &p->u.prefix, psize); + s->endp += psize; + + return (psize + 3); +} /* Read size from fd. */ int diff --git a/lib/stream.h b/lib/stream.h index 1e2bc89b32..b7bf31bf7f 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -181,7 +181,8 @@ extern int stream_put_prefix_addpath (struct stream *, struct prefix *, int addpath_encode, u_int32_t addpath_tx_id); extern int stream_put_prefix (struct stream *, struct prefix *); - +extern int stream_put_labeled_prefix (struct stream *, struct prefix *, + u_char *); extern void stream_get (void *, struct stream *, size_t); extern void stream_get_from (void *, struct stream *, size_t, size_t); extern u_char stream_getc (struct stream *); From b60f5275565c66b35ca8e630e9ffb12cc244e419 Mon Sep 17 00:00:00 2001 From: Don Slice Date: Thu, 9 Mar 2017 16:12:44 -0500 Subject: [PATCH 08/55] bgpd: labeled unicast display Implement 'show' and 'clear' commands for the labeled-unicast address-family. Signed-off-by: Don Slice --- bgpd/bgp_route.c | 9 ++++++--- bgpd/bgp_vty.c | 18 ++++++++++++++++-- bgpd/bgp_vty.h | 3 ++- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 77154b0f33..3114893c9d 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -8300,7 +8300,7 @@ bgp_show_lcommunity_list (struct vty *vty, struct bgp *bgp, const char *lcom, DEFUN (show_ip_bgp_large_community_list, show_ip_bgp_large_community_list_cmd, - "show [ip] bgp [ WORD] [ []] large-community-list <(1-500)|WORD> [json]", + "show [ip] bgp [ WORD] [ []] large-community-list <(1-500)|WORD> [json]", SHOW_STR IP_STR BGP_STR @@ -8311,6 +8311,7 @@ DEFUN (show_ip_bgp_large_community_list, "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" + "Address Family modifier\n" "Display routes matching the large-community-list\n" "large-community-list number\n" "large-community-list name\n" @@ -8346,7 +8347,7 @@ DEFUN (show_ip_bgp_large_community_list, } DEFUN (show_ip_bgp_large_community, show_ip_bgp_large_community_cmd, - "show [ip] bgp [ WORD] [ []] large-community [AA:BB:CC] [json]", + "show [ip] bgp [ WORD] [ []] large-community [AA:BB:CC] [json]", SHOW_STR IP_STR BGP_STR @@ -8357,6 +8358,7 @@ DEFUN (show_ip_bgp_large_community, "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" + "Address Family modifier\n" "Display routes matching the large-communities\n" "List of large-community numbers\n" JSON_STR) @@ -9300,7 +9302,7 @@ bgp_peer_counts (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, u_c DEFUN (show_ip_bgp_instance_neighbor_prefix_counts, show_ip_bgp_instance_neighbor_prefix_counts_cmd, - "show [ip] bgp [ WORD] [ []] " + "show [ip] bgp [ WORD] [ []] " "neighbors prefix-counts [json]", SHOW_STR IP_STR @@ -9312,6 +9314,7 @@ DEFUN (show_ip_bgp_instance_neighbor_prefix_counts, "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" + "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index b1819e2f03..ef5571c9ae 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -265,6 +265,12 @@ argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t if (safi) *safi = SAFI_MULTICAST; } + else if (argv_find (argv, argc, "labeled-unicast", index)) + { + ret = 1; + if (safi) + *safi = SAFI_LABELED_UNICAST; + } else if (argv_find (argv, argc, "vpn", index)) { ret = 1; @@ -296,12 +302,12 @@ argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t * that is being parsed. * * The show commands are generally of the form: - * "show [ip] bgp [ WORD] [ []] ..." + * "show [ip] bgp [ WORD] [ []] ..." * * Since we use argv_find if the show command in particular doesn't have: * [ip] * [ WORD] - * [ []] + * [ []] * The command parsing should still be ok. * * vty -> The vty for the command so we can output some useful data in @@ -6917,6 +6923,8 @@ afi_safi_print (afi_t afi, safi_t safi) return "IPv4 Unicast"; else if (afi == AFI_IP && safi == SAFI_MULTICAST) return "IPv4 Multicast"; + else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST) + return "IPv4 labeled-unicast"; else if (afi == AFI_IP && safi == SAFI_MPLS_VPN) return "IPv4 VPN"; else if (afi == AFI_IP && safi == SAFI_ENCAP) @@ -6925,6 +6933,8 @@ afi_safi_print (afi_t afi, safi_t safi) return "IPv6 Unicast"; else if (afi == AFI_IP6 && safi == SAFI_MULTICAST) return "IPv6 Multicast"; + else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST) + return "IPv6 labeled-unicast"; else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN) return "IPv6 VPN"; else if (afi == AFI_IP6 && safi == SAFI_ENCAP) @@ -6942,6 +6952,8 @@ afi_safi_json (afi_t afi, safi_t safi) return "IPv4Unicast"; else if (afi == AFI_IP && safi == SAFI_MULTICAST) return "IPv4Multicast"; + else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST) + return "IPv4LabeledUnicast"; else if (afi == AFI_IP && safi == SAFI_MPLS_VPN) return "IPv4VPN"; else if (afi == AFI_IP && safi == SAFI_ENCAP) @@ -6950,6 +6962,8 @@ afi_safi_json (afi_t afi, safi_t safi) return "IPv6Unicast"; else if (afi == AFI_IP6 && safi == SAFI_MULTICAST) return "IPv6Multicast"; + else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST) + return "IPv6LabeledUnicast"; else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN) return "IPv6VPN"; else if (afi == AFI_IP6 && safi == SAFI_ENCAP) diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index f0342c2c35..a0aabcbd2c 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -28,12 +28,13 @@ struct bgp; #define BGP_AFI_CMD_STR "" #define BGP_AFI_HELP_STR "Address Family\nAddress Family\n" -#define BGP_SAFI_CMD_STR "" +#define BGP_SAFI_CMD_STR "" #define BGP_SAFI_HELP_STR \ "Address Family modifier\n" \ "Address Family modifier\n" \ "Address Family modifier\n" \ "Address Family modifier\n" \ + "Address Family modifier\n" \ "Address Family modifier\n" #define BGP_AFI_SAFI_CMD_STR BGP_AFI_CMD_STR" "BGP_SAFI_CMD_STR #define BGP_AFI_SAFI_HELP_STR BGP_AFI_HELP_STR BGP_SAFI_HELP_STR From 1b6d5c7e0873e34bb8674ed0d41795eac7a79960 Mon Sep 17 00:00:00 2001 From: Vivek Venkatraman Date: Thu, 9 Mar 2017 11:43:59 -0500 Subject: [PATCH 09/55] bgpd, zebra: Implement BGP Prefix-SID IETF draft Implement BGP Prefix-SID IETF draft to be able to signal a labeled-unicast prefix with a label index (segment ID). This makes it easier to deploy global MPLS labels with BGP, even without other aspects of Segment Routing implemented. This patch implements configuration of the global label block (SRGB) and configuration of a label-index for a network in BGP. Signed-off-by: Vivek Venkatraman --- bgpd/bgp_route.c | 155 ++++++++++++++++++++++++++++++++++++---- bgpd/bgp_route.h | 4 ++ zebra/zebra_mpls.c | 41 +++++++++++ zebra/zebra_mpls.h | 19 +++++ zebra/zebra_mpls_null.c | 19 +++++ zebra/zebra_mpls_vty.c | 83 +++++++++++++++++++++ zebra/zebra_vrf.h | 10 +++ 7 files changed, 319 insertions(+), 12 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 3114893c9d..0c29254f3f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4220,7 +4220,8 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, route should be installed as valid. */ static int bgp_static_set (struct vty *vty, const char *ip_str, - afi_t afi, safi_t safi, const char *rmap, int backdoor) + afi_t afi, safi_t safi, const char *rmap, int backdoor, + u_int32_t label_index) { VTY_DECLVAR_CONTEXT(bgp, bgp); int ret; @@ -4253,6 +4254,13 @@ bgp_static_set (struct vty *vty, const char *ip_str, /* Configuration change. */ bgp_static = rn->info; + /* Label index cannot be changed. */ + if (bgp_static->label_index != label_index) + { + vty_out (vty, "%% Label index cannot be changed%s", VTY_NEWLINE); + return CMD_WARNING; + } + /* Check previous routes are installed into BGP. */ if (bgp_static->valid && bgp_static->backdoor != backdoor) need_update = 1; @@ -4284,6 +4292,7 @@ bgp_static_set (struct vty *vty, const char *ip_str, bgp_static->valid = 0; bgp_static->igpmetric = 0; bgp_static->igpnexthop.s_addr = 0; + bgp_static->label_index = label_index; if (rmap) { @@ -4810,7 +4819,8 @@ DEFUN (bgp_network, { int idx_ipv4_prefixlen = 1; return bgp_static_set (vty, argv[idx_ipv4_prefixlen]->arg, - AFI_IP, bgp_node_safi (vty), NULL, 0); + AFI_IP, bgp_node_safi (vty), NULL, 0, + BGP_INVALID_LABEL_INDEX); } DEFUN (bgp_network_route_map, @@ -4824,7 +4834,8 @@ DEFUN (bgp_network_route_map, int idx_ipv4_prefixlen = 1; int idx_word = 3; return bgp_static_set (vty, argv[idx_ipv4_prefixlen]->arg, - AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0); + AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0, + BGP_INVALID_LABEL_INDEX); } DEFUN (bgp_network_backdoor, @@ -4836,7 +4847,7 @@ DEFUN (bgp_network_backdoor, { int idx_ipv4_prefixlen = 1; return bgp_static_set (vty, argv[idx_ipv4_prefixlen]->arg, AFI_IP, SAFI_UNICAST, - NULL, 1); + NULL, 1, BGP_INVALID_LABEL_INDEX); } DEFUN (bgp_network_mask, @@ -4860,7 +4871,7 @@ DEFUN (bgp_network_mask, } return bgp_static_set (vty, prefix_str, - AFI_IP, bgp_node_safi (vty), NULL, 0); + AFI_IP, bgp_node_safi (vty), NULL, 0, BGP_INVALID_LABEL_INDEX); } DEFUN (bgp_network_mask_route_map, @@ -4887,7 +4898,7 @@ DEFUN (bgp_network_mask_route_map, } return bgp_static_set (vty, prefix_str, - AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0); + AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0, BGP_INVALID_LABEL_INDEX); } DEFUN (bgp_network_mask_backdoor, @@ -4912,7 +4923,8 @@ DEFUN (bgp_network_mask_backdoor, } return bgp_static_set (vty, prefix_str, AFI_IP, SAFI_UNICAST, - NULL, 1); + NULL, 1, + BGP_INVALID_LABEL_INDEX); } DEFUN (bgp_network_mask_natural, @@ -4933,7 +4945,8 @@ DEFUN (bgp_network_mask_natural, } return bgp_static_set (vty, prefix_str, - AFI_IP, bgp_node_safi (vty), NULL, 0); + AFI_IP, bgp_node_safi (vty), NULL, 0, + BGP_INVALID_LABEL_INDEX); } DEFUN (bgp_network_mask_natural_route_map, @@ -4957,7 +4970,8 @@ DEFUN (bgp_network_mask_natural_route_map, } return bgp_static_set (vty, prefix_str, - AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0); + AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0, + BGP_INVALID_LABEL_INDEX); } DEFUN (bgp_network_mask_natural_backdoor, @@ -4979,7 +4993,39 @@ DEFUN (bgp_network_mask_natural_backdoor, } return bgp_static_set (vty, prefix_str, AFI_IP, SAFI_UNICAST, - NULL, 1); + NULL, 1, BGP_INVALID_LABEL_INDEX); +} + +DEFUN (bgp_network_label_index, + bgp_network_label_index_cmd, + "network A.B.C.D/M label-index (0-4294967294)", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Label index to associate with the prefix\n" + "Label index value\n") +{ + u_int32_t label_index; + + VTY_GET_INTEGER ("label-index", label_index, argv[3]->arg); + return bgp_static_set (vty, argv[1]->arg, + AFI_IP, bgp_node_safi (vty), NULL, 0, label_index); +} + +DEFUN (bgp_network_label_index_route_map, + bgp_network_label_index_route_map_cmd, + "network A.B.C.D/M label-index (0-4294967294) route-map WORD", + "Specify a network to announce via BGP\n" + "IP prefix\n" + "Label index to associate with the prefix\n" + "Label index value\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") +{ + u_int32_t label_index; + + VTY_GET_INTEGER ("label-index", label_index, argv[3]->arg); + return bgp_static_set (vty, argv[1]->arg, + AFI_IP, bgp_node_safi (vty), argv[5]->arg, 0, label_index); } DEFUN (no_bgp_network, @@ -5050,6 +5096,26 @@ DEFUN (no_bgp_network_mask_natural, bgp_node_safi (vty)); } +ALIAS (no_bgp_network, + no_bgp_network_label_index_cmd, + "no network A.B.C.D/M label-index (0-4294967294)", + NO_STR + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Label index to associate with the prefix\n" + "Label index value\n") + +ALIAS (no_bgp_network, + no_bgp_network_label_index_route_map_cmd, + "no network A.B.C.D/M label-index (0-4294967294)route-map WORD", + NO_STR + "Specify a network to announce via BGP\n" + "IP prefix\n" + "Label index to associate with the prefix\n" + "Label index value\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") + DEFUN (ipv6_bgp_network, ipv6_bgp_network_cmd, "network X:X::X:X/M", @@ -5058,7 +5124,8 @@ DEFUN (ipv6_bgp_network, { int idx_ipv6_prefixlen = 1; return bgp_static_set (vty, argv[idx_ipv6_prefixlen]->arg, AFI_IP6, bgp_node_safi(vty), - NULL, 0); + NULL, 0, + BGP_INVALID_LABEL_INDEX); } DEFUN (ipv6_bgp_network_route_map, @@ -5072,7 +5139,40 @@ DEFUN (ipv6_bgp_network_route_map, int idx_ipv6_prefixlen = 1; int idx_word = 3; return bgp_static_set (vty, argv[idx_ipv6_prefixlen]->arg, AFI_IP6, - bgp_node_safi (vty), argv[idx_word]->arg, 0); + bgp_node_safi (vty), argv[idx_word]->arg, 0, + BGP_INVALID_LABEL_INDEX); +} + +DEFUN (ipv6_bgp_network_label_index, + ipv6_bgp_network_label_index_cmd, + "network X:X::X:X/M label-index (0-4294967294)", + "Specify a network to announce via BGP\n" + "IPv6 prefix /\n" + "Label index to associate with the prefix\n" + "Label index value\n") +{ + u_int32_t label_index; + + VTY_GET_INTEGER ("label-index", label_index, argv[3]->arg); + return bgp_static_set (vty, argv[1]->arg, + AFI_IP6, bgp_node_safi (vty), NULL, 0, label_index); +} + +DEFUN (ipv6_bgp_network_label_index_route_map, + ipv6_bgp_network_label_index_route_map_cmd, + "network X:X::X:X/M label-index (0-4294967294) route-map WORD", + "Specify a network to announce via BGP\n" + "IPv6 prefix\n" + "Label index to associate with the prefix\n" + "Label index value\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") +{ + u_int32_t label_index; + + VTY_GET_INTEGER ("label-index", label_index, argv[3]->arg); + return bgp_static_set (vty, argv[1]->arg, + AFI_IP6, bgp_node_safi (vty), argv[5]->arg, 0, label_index); } DEFUN (no_ipv6_bgp_network, @@ -5088,6 +5188,26 @@ DEFUN (no_ipv6_bgp_network, return bgp_static_unset (vty, argv[idx_ipv6_prefixlen]->arg, AFI_IP6, bgp_node_safi(vty)); } +ALIAS (no_ipv6_bgp_network, + no_ipv6_bgp_network_label_index_cmd, + "no network X:X::X:X/M label-index (0-4294967294)", + NO_STR + "Specify a network to announce via BGP\n" + "IPv6 prefix /\n" + "Label index to associate with the prefix\n" + "Label index value\n") + +ALIAS (no_ipv6_bgp_network, + no_ipv6_bgp_network_label_index_route_map_cmd, + "no network X:X::X:X/M label-index (0-4294967294) route-map WORD", + NO_STR + "Specify a network to announce via BGP\n" + "IPv6 prefix\n" + "Label index to associate with the prefix\n" + "Label index value\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") + /* Aggreagete address: advertise-map Set condition to advertise attribute @@ -10621,6 +10741,9 @@ bgp_config_write_network (struct vty *vty, struct bgp *bgp, p->prefixlen); } + if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX) + vty_out (vty, " label-index %u", bgp_static->label_index); + if (bgp_static->rmap.name) vty_out (vty, " route-map %s", bgp_static->rmap.name); else @@ -10747,6 +10870,8 @@ bgp_route_init (void) install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_label_index_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_label_index_route_map_cmd); install_element (BGP_IPV4_NODE, &no_bgp_table_map_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd); @@ -10782,6 +10907,8 @@ bgp_route_init (void) install_element (BGP_IPV4L_NODE, &bgp_network_route_map_cmd); install_element (BGP_IPV4L_NODE, &bgp_network_mask_route_map_cmd); install_element (BGP_IPV4L_NODE, &bgp_network_mask_natural_route_map_cmd); + install_element (BGP_IPV4L_NODE, &bgp_network_label_index_cmd); + install_element (BGP_IPV4L_NODE, &bgp_network_label_index_route_map_cmd); install_element (BGP_IPV4L_NODE, &no_bgp_table_map_cmd); install_element (BGP_IPV4L_NODE, &no_bgp_network_cmd); install_element (BGP_IPV4L_NODE, &no_bgp_network_mask_cmd); @@ -10820,6 +10947,10 @@ bgp_route_init (void) install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd); install_element (BGP_IPV6_NODE, &no_bgp_table_map_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd); + install_element (BGP_IPV6_NODE, &ipv6_bgp_network_label_index_cmd); + install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_label_index_cmd); + install_element (BGP_IPV6_NODE, &ipv6_bgp_network_label_index_route_map_cmd); + install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_label_index_route_map_cmd); install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 69b8ea8a55..35994d4f76 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -180,6 +180,10 @@ struct bgp_static /* Backdoor configuration. */ int backdoor; + /* Label index configuration; applies to LU prefixes. */ + u_int32_t label_index; +#define BGP_INVALID_LABEL_INDEX 0xFFFFFFFF + /* Import check status. */ u_char valid; diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index f13a3f4f0a..85ce147d25 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -2735,6 +2735,45 @@ zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf) return (zvrf->slsp_table->count ? 1 : 0); } +/* + * Add/update global label block. + */ +int +zebra_mpls_label_block_add (struct zebra_vrf *zvrf, u_int32_t start_label, + u_int32_t end_label) +{ + zvrf->mpls_srgb.start_label = start_label; + zvrf->mpls_srgb.end_label = end_label; + return 0; +} + +/* + * Delete global label block. + */ +int +zebra_mpls_label_block_del (struct zebra_vrf *zvrf) +{ + zvrf->mpls_srgb.start_label = 0; + zvrf->mpls_srgb.end_label = 0; + return 0; +} + +/* + * Display MPLS global label block configuration (VTY command handler). + */ +int +zebra_mpls_write_label_block_config (struct vty *vty, struct zebra_vrf *zvrf) +{ + if (zvrf->mpls_srgb.start_label == 0) + return 0; + + vty_out(vty, "mpls label global-block %u %u%s", + zvrf->mpls_srgb.start_label, zvrf->mpls_srgb.end_label, + VTY_NEWLINE); + + return 1; +} + /* * Called upon process exiting, need to delete LSP forwarding * entries from the kernel. @@ -2764,6 +2803,8 @@ zebra_mpls_init_tables (struct zebra_vrf *zvrf) zvrf->fec_table[AFI_IP] = route_table_init(); zvrf->fec_table[AFI_IP6] = route_table_init(); zvrf->mpls_flags = 0; + zvrf->mpls_srgb.start_label = 0; + zvrf->mpls_srgb.end_label = 0; } /* diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index f9d58a46e8..f8e95fa100 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -183,6 +183,25 @@ char * mpls_label2str (u_int8_t num_labels, mpls_label_t *labels, char *buf, int len); +/* + * Add/update global label block. + */ +int +zebra_mpls_label_block_add (struct zebra_vrf *zvrf, u_int32_t start_label, + u_int32_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. */ diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c index d6f99b5178..12176c024e 100644 --- a/zebra/zebra_mpls_null.c +++ b/zebra/zebra_mpls_null.c @@ -44,6 +44,25 @@ mpls_str2label (const char *label_str, u_int8_t *num_labels, return 0; } +int +zebra_mpls_label_block_add (struct zebra_vrf *vrf, u_int32_t start_label, + u_int32_t end_label) +{ + return 0; +} + +int +zebra_mpls_label_block_del (struct zebra_vrf *zvrf) +{ + return 0; +} + +int +zebra_mpls_write_label_block_config (struct vty *vty, struct zebra_vrf *zvrf) +{ + return 0; +} + int zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib) { diff --git a/zebra/zebra_mpls_vty.c b/zebra/zebra_mpls_vty.c index 8d8025682a..f46037487e 100644 --- a/zebra/zebra_mpls_vty.c +++ b/zebra/zebra_mpls_vty.c @@ -873,6 +873,7 @@ zebra_mpls_config (struct vty *vty) write += zebra_mpls_write_lsp_config(vty, zvrf); write += zebra_mpls_write_fec_config(vty, zvrf); + write += zebra_mpls_write_label_block_config (vty, zvrf); return write; } @@ -957,6 +958,85 @@ DEFUN (show_mpls_status, return CMD_SUCCESS; } +static int +zebra_mpls_global_block (struct vty *vty, int add_cmd, + const char *start_label_str, const char *end_label_str) +{ + int ret; + u_int32_t start_label; + u_int32_t end_label; + struct zebra_vrf *zvrf; + + zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); + if (!zvrf) + { + vty_out (vty, "%% Default VRF does not exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (add_cmd) + { + if (!start_label_str || !end_label_str) + { + vty_out (vty, "%% Labels not specified%s", VTY_NEWLINE); + return CMD_WARNING; + } + + start_label = atoi(start_label_str); + end_label = atoi(end_label_str); + if (!IS_MPLS_UNRESERVED_LABEL(start_label) || + !IS_MPLS_UNRESERVED_LABEL(end_label)) + { + vty_out (vty, "%% Invalid label%s", VTY_NEWLINE); + return CMD_WARNING; + } + if (end_label < start_label) + { + vty_out (vty, "%% End label is less than Start label%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ret = zebra_mpls_label_block_add (zvrf, start_label, end_label); + } + else + ret = zebra_mpls_label_block_del (zvrf); + + if (ret) + { + vty_out (vty, "%% Global label block could not be %s%s", + add_cmd ? "added" : "deleted", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (mpls_label_global_block, + mpls_label_global_block_cmd, + "mpls label global-block (16-1048575) (16-1048575)", + MPLS_STR + "Label configuration\n" + "Configure global label block\n" + "Start label\n" + "End label\n") +{ + return zebra_mpls_global_block (vty, 1, argv[3]->arg, argv[4]->arg); +} + +DEFUN (no_mpls_label_global_block, + no_mpls_label_global_block_cmd, + "no mpls label global-block [(16-1048575) (16-1048575)]", + NO_STR + MPLS_STR + "Label configuration\n" + "Configure global label block\n" + "Start label\n" + "End label\n") +{ + return zebra_mpls_global_block (vty, 0, NULL, NULL); +} + /* MPLS node for MPLS LSP. */ static struct cmd_node mpls_node = { MPLS_NODE, "", 1 }; @@ -1009,6 +1089,9 @@ zebra_mpls_vty_init (void) install_element (CONFIG_NODE, &mpls_label_bind_cmd); install_element (CONFIG_NODE, &no_mpls_label_bind_cmd); + install_element (CONFIG_NODE, &mpls_label_global_block_cmd); + install_element (CONFIG_NODE, &no_mpls_label_global_block_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 8333ca27d7..74c2a52171 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -25,6 +25,13 @@ #include +/* MPLS (Segment Routing) global block */ +typedef struct mpls_srgb_t_ +{ + u_int32_t start_label; + u_int32_t end_label; +} mpls_srgb_t; + /* Routing table instance. */ struct zebra_vrf { @@ -82,6 +89,9 @@ struct zebra_vrf /* MPLS FEC binding table */ struct route_table *fec_table[AFI_MAX]; + /* MPLS Segment Routing Global block */ + mpls_srgb_t mpls_srgb; + /* MPLS processing flags */ u_int16_t mpls_flags; #define MPLS_FLAG_SCHEDULE_LSPS (1 << 0) From 6cf48acc1c17d590da4101fa5e0a2764cb931a9c Mon Sep 17 00:00:00 2001 From: Vivek Venkatraman Date: Thu, 9 Mar 2017 12:22:04 -0500 Subject: [PATCH 10/55] bgpd: This patch implements the exchange of the BGP-Prefix-SID label index attr Implement BGP Prefix-SID IETF draft to be able to signal a labeled-unicast prefix with a label index (segment ID). This makes it easier to deploy global MPLS labels with BGP, even without other aspects of Segment Routing implemented. Signed-off-by: Vivek Venkatraman --- bgpd/bgp_attr.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_attr.h | 3 ++ bgpd/bgp_debug.c | 4 +++ bgpd/bgp_label.c | 5 +++ bgpd/bgp_route.c | 36 ++++++++++++++++++++-- bgpd/bgp_table.h | 1 + bgpd/bgpd.h | 1 + 7 files changed, 127 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 2c6bb5de0e..acc08184b9 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -676,6 +676,7 @@ attrhash_key_make (void *p) MIX(extra->mp_nexthop_global_in.s_addr); MIX(extra->originator_id.s_addr); MIX(extra->tag); + MIX(extra->label_index); } if (attr->aspath) @@ -730,6 +731,7 @@ attrhash_cmp (const void *p1, const void *p2) && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr && ae1->weight == ae2->weight && ae1->tag == ae2->tag + && ae1->label_index == ae2->label_index && ae1->mp_nexthop_len == ae2->mp_nexthop_len && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global) && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local) @@ -1287,6 +1289,7 @@ const u_int8_t attr_flags_values [] = { [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, [BGP_ATTR_LARGE_COMMUNITIES]= BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, + [BGP_ATTR_LABEL_INDEX] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, }; static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1; @@ -2274,6 +2277,52 @@ bgp_attr_encap( return 0; } +/* Label index attribute */ +static bgp_attr_parse_ret_t +bgp_attr_label_index (struct bgp_attr_parser_args *args, struct bgp_nlri *mp_update) +{ + struct peer *const peer = args->peer; + struct attr *const attr = args->attr; + const bgp_size_t length = args->length; + u_int32_t label_index; + + /* Length check. */ + if (length != 8) + { + zlog_err ("Bad label index length %d", length); + + return bgp_attr_malformed (args, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + args->total); + } + + /* First u32 is currently unused - reserved and flags (undefined) */ + stream_getl (peer->ibuf); + + /* Fetch the label index and see if it is valid. */ + label_index = stream_getl (peer->ibuf); + if (label_index == BGP_INVALID_LABEL_INDEX) + return bgp_attr_malformed (args, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + args->total); + + /* Store label index; subsequently, we'll check on address-family */ + (bgp_attr_extra_get (attr))->label_index = label_index; + + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX); + + /* + * Ignore the Label index attribute unless received for labeled-unicast + * SAFI. We reset the flag, though it is probably unnecesary. + */ + if (!mp_update->length || mp_update->afi != SAFI_LABELED_UNICAST) + { + attr->extra->label_index = BGP_INVALID_LABEL_INDEX; + attr->flag &= ~ATTR_FLAG_BIT(BGP_ATTR_LABEL_INDEX); + } + return BGP_ATTR_PARSE_PROCEED; +} + /* BGP unknown attribute treatment. */ static bgp_attr_parse_ret_t bgp_attr_unknown (struct bgp_attr_parser_args *args) @@ -2572,6 +2621,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, case BGP_ATTR_ENCAP: ret = bgp_attr_encap (type, peer, length, attr, flag, startp); break; + case BGP_ATTR_LABEL_INDEX: + ret = bgp_attr_label_index (&attr_args, mp_update); + break; default: ret = bgp_attr_unknown (&attr_args); break; @@ -3355,6 +3407,23 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, } } + /* Label index attribute. */ + if (safi == SAFI_LABELED_UNICAST) + { + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)) + { + u_int32_t label_index; + + assert (attr->extra); + label_index = attr->extra->label_index; + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_LABEL_INDEX); + stream_putc (s, 8); + stream_putl (s, 0); + stream_putl (s, label_index); + } + } + if ( send_as4_path ) { /* If the peer is NOT As4 capable, AND */ @@ -3638,6 +3707,17 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1); } + /* Label index */ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)) + { + assert (attr->extra); + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_LABEL_INDEX); + stream_putc (s, 8); + stream_putl (s, 0); + stream_putl (s, attr->extra->label_index); + } + /* Return total size of attribute. */ len = stream_get_endp (s) - cp - 2; stream_putw_at (s, cp, len); diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 015039c6cd..310fc0215d 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -134,6 +134,9 @@ struct attr_extra /* route tag */ route_tag_t tag; + /* Label index */ + u_int32_t label_index; + uint16_t encap_tunneltype; /* grr */ struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */ diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 232f53c778..8e4d8bf4f2 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -450,6 +450,10 @@ bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size) snprintf (buf + strlen (buf), size - strlen (buf), ", path %s", aspath_print (attr->aspath)); + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))) + snprintf (buf + strlen (buf), size - strlen (buf), ", label-index %u", + attr->extra->label_index); + if (strlen (buf) > 1) return 1; else diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index 283afbc922..e2c4a54044 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -143,6 +143,11 @@ bgp_reg_dereg_for_label (struct bgp_node *rn, int reg) stream_putw(s, PREFIX_FAMILY(p)); stream_put_prefix(s, p); stream_putw_at (s, 0, stream_get_endp (s)); + + if (reg) + SET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL); + else + UNSET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL); zclient_send_message(zclient); return; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 0c29254f3f..451b54edab 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1942,9 +1942,21 @@ bgp_process_main (struct work_queue *wq, void *data) { label_valid = bgp_is_valid_label (rn->local_label); if (!old_select && new_select && !label_valid) - bgp_register_for_label (rn); + { + if (new_select->sub_type == BGP_ROUTE_STATIC && + new_select->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)) + { + label_ntop (MPLS_IMP_NULL_LABEL, 1, rn->local_label); + bgp_set_valid_label(rn->local_label); + } + else + bgp_register_for_label (rn); + } else if (old_select && !new_select) - bgp_unregister_for_label (rn); + { + if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) + bgp_unregister_for_label (rn); + } } /* If best route remains the same and this is not due to user-initiated @@ -3792,6 +3804,13 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, if (bgp_static->atomic) attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); + /* Store label index, if required. */ + if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX) + { + (bgp_attr_extra_get (&attr))->label_index = bgp_static->label_index; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX); + } + /* Apply route-map. */ if (bgp_static->rmap.name) { @@ -7631,9 +7650,20 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (json_paths) json_object_int_add(json_path, "remote-label", label); else - vty_out(vty, " Remote label: %d%s", label, VTY_NEWLINE); + vty_out(vty, " Remote label: %d", label); } + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))) + { + if (json_paths) + json_object_int_add(json_path, "label-index", attr->extra->label_index); + else + vty_out(vty, ", Label Index: %d", attr->extra->label_index); + } + + if (!json_paths) + vty_out (vty, "%s", VTY_NEWLINE); + /* Line 8 display Addpath IDs */ if (binfo->addpath_rx_id || binfo->addpath_tx_id) { diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 2b874f66a6..a6b99a53d6 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -63,6 +63,7 @@ struct bgp_node #define BGP_NODE_PROCESS_SCHEDULED (1 << 0) #define BGP_NODE_USER_CLEAR (1 << 1) #define BGP_NODE_LABEL_CHANGED (1 << 2) +#define BGP_NODE_REGISTERED_FOR_LABEL (1 << 3) }; /* diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index e95d059227..83c5d90ddf 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -972,6 +972,7 @@ struct bgp_nlri #define BGP_ATTR_AS4_AGGREGATOR 18 #define BGP_ATTR_AS_PATHLIMIT 21 #define BGP_ATTR_ENCAP 23 +#define BGP_ATTR_LABEL_INDEX 30 #define BGP_ATTR_LARGE_COMMUNITIES 32 #if ENABLE_BGP_VNC #define BGP_ATTR_VNC 255 From 28d58fd7b166836029656c29ad8ed9a9e8a744ac Mon Sep 17 00:00:00 2001 From: Vivek Venkatraman Date: Thu, 9 Mar 2017 12:55:54 -0500 Subject: [PATCH 11/55] bgpd, lib, zebra: Implement handling of BGP-Prefix-SID label Index Implement BGP Prefix-SID IETF draft to be able to signal a labeled-unicast prefix with a label index (segment ID). This makes it easier to deploy global MPLS labels with BGP, even without other aspects of Segment Routing implemented. This patch implements the handling of the BGP-Prefix-SID Label Index attribute. When received from a peer and the index is acceptable, the local label is picked up from the SRGB and is programmed as the incoming label as well as advertised to peers. If the index is not acceptable, no local label is assigned. The outgoing label will always be the one advertised by the downstream neighbor. Signed-off-by: Vivek Venkatraman --- bgpd/bgp_label.c | 27 ++++-- bgpd/bgp_label.h | 9 +- bgpd/bgp_route.c | 46 +++++++---- lib/mpls.h | 5 ++ lib/zebra.h | 3 + zebra/zebra_mpls.c | 176 +++++++++++++++++++++++++++++++++++++--- zebra/zebra_mpls.h | 11 ++- zebra/zebra_mpls_null.c | 2 +- zebra/zserv.c | 12 ++- 9 files changed, 250 insertions(+), 41 deletions(-) diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index e2c4a54044..0c331c5d59 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -125,11 +125,14 @@ bgp_adv_label (struct bgp_node *rn, struct bgp_info *ri, struct peer *to, } void -bgp_reg_dereg_for_label (struct bgp_node *rn, int reg) +bgp_reg_dereg_for_label (struct bgp_node *rn, struct bgp_info *ri, + int reg) { struct stream *s; struct prefix *p; int command; + u_int16_t flags = 0; + size_t flags_pos = 0; /* Check socket. */ if (!zclient || zclient->sock < 0) @@ -140,17 +143,29 @@ bgp_reg_dereg_for_label (struct bgp_node *rn, int reg) stream_reset (s); command = (reg) ? ZEBRA_FEC_REGISTER : ZEBRA_FEC_UNREGISTER; zclient_create_header (s, command, VRF_DEFAULT); + flags_pos = stream_get_endp (s); /* save position of 'flags' */ + stream_putw(s, flags); /* initial flags */ stream_putw(s, PREFIX_FAMILY(p)); stream_put_prefix(s, p); - stream_putw_at (s, 0, stream_get_endp (s)); - if (reg) - SET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL); + { + assert (ri); + if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)) + { + assert (ri->attr->extra); + flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX; + stream_putl (s, ri->attr->extra->label_index); + } + SET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL); + } else UNSET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL); - zclient_send_message(zclient); - return; + /* Set length and flags */ + stream_putw_at (s, 0, stream_get_endp (s)); + stream_putw_at (s, flags_pos, flags); + + zclient_send_message(zclient); } static int diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h index a7e7d5c47b..49a7b945ab 100644 --- a/bgpd/bgp_label.h +++ b/bgpd/bgp_label.h @@ -30,7 +30,8 @@ struct bgp_node; struct bgp_info; struct peer; -extern void bgp_reg_dereg_for_label (struct bgp_node *rn, int reg); +extern void bgp_reg_dereg_for_label (struct bgp_node *rn, struct bgp_info *ri, + int reg); extern int bgp_parse_fec_update(void); extern u_char * bgp_adv_label(struct bgp_node *rn, struct bgp_info *ri, struct peer *to, afi_t afi, safi_t safi); @@ -84,15 +85,15 @@ bgp_unset_valid_label (u_char *t) } static inline void -bgp_register_for_label (struct bgp_node *rn) +bgp_register_for_label (struct bgp_node *rn, struct bgp_info *ri) { - bgp_reg_dereg_for_label (rn, 1); + bgp_reg_dereg_for_label (rn, ri, 1); } static inline void bgp_unregister_for_label (struct bgp_node *rn) { - bgp_reg_dereg_for_label (rn, 0); + bgp_reg_dereg_for_label (rn, NULL, 0); } /* Label stream to value */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 451b54edab..b016122a7f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -298,6 +298,20 @@ bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri) } } +static int +bgp_label_index_differs (struct bgp_info *ri1, struct bgp_info *ri2) +{ + u_int32_t ri1_label_index = BGP_INVALID_LABEL_INDEX; + u_int32_t ri2_label_index = BGP_INVALID_LABEL_INDEX; + + if (ri1->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)) + ri1_label_index = ri1->attr->extra->label_index; + + if (ri2->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)) + ri2_label_index = ri2->attr->extra->label_index; + + return (!(ri1_label_index == ri2_label_index)); +} /* Set/unset bgp_info flags, adjusting any other state as needed. * This is here primarily to keep prefix-count in check. @@ -1908,7 +1922,6 @@ bgp_process_main (struct work_queue *wq, void *data) struct bgp_info *new_select; struct bgp_info *old_select; struct bgp_info_pair old_and_new; - int label_valid; /* Is it end of initial update? (after startup) */ if (!rn) @@ -1935,28 +1948,31 @@ bgp_process_main (struct work_queue *wq, void *data) /* Do we need to allocate or free labels? * Right now, since we only deal with per-prefix labels, it is not necessary - * to do this upon changes to best path. + * to do this upon changes to best path except of the label index changes. */ bgp_table_lock (bgp_node_table (rn)); if (bgp_labeled_safi (safi)) { - label_valid = bgp_is_valid_label (rn->local_label); - if (!old_select && new_select && !label_valid) + if (new_select) { - if (new_select->sub_type == BGP_ROUTE_STATIC && - new_select->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)) + if (!old_select || + bgp_label_index_differs (new_select, old_select) || + new_select->sub_type != old_select->sub_type) { - label_ntop (MPLS_IMP_NULL_LABEL, 1, rn->local_label); - bgp_set_valid_label(rn->local_label); + if (new_select->sub_type == BGP_ROUTE_STATIC && + new_select->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)) + { + if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) + bgp_unregister_for_label (rn); + label_ntop (MPLS_IMP_NULL_LABEL, 1, rn->local_label); + bgp_set_valid_label(rn->local_label); + } + else + bgp_register_for_label (rn, new_select); } - else - bgp_register_for_label (rn); - } - else if (old_select && !new_select) - { - if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) - bgp_unregister_for_label (rn); } + else if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) + bgp_unregister_for_label (rn); } /* If best route remains the same and this is not due to user-initiated diff --git a/lib/mpls.h b/lib/mpls.h index 5a91883753..f4f360c957 100644 --- a/lib/mpls.h +++ b/lib/mpls.h @@ -123,6 +123,11 @@ mpls_lse_decode (mpls_lse_t lse, mpls_label_t *label, *ttl = MPLS_LABEL_TTL(local_lse); } +/* Invalid label index value (when used with BGP Prefix-SID). Should + * match the BGP definition. + */ +#define MPLS_INVALID_LABEL_INDEX 0xFFFFFFFF + /* Printable string for labels (with consideration for reserved values). */ static inline char * diff --git a/lib/zebra.h b/lib/zebra.h index ef261eedc1..cd72dc67f8 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -393,6 +393,9 @@ extern const char *zserv_command_string (unsigned int command); #define ZEBRA_FLAG_SCOPE_LINK 0x100 #define ZEBRA_FLAG_FIB_OVERRIDE 0x200 +/* Zebra FEC flags. */ +#define ZEBRA_FEC_REGISTER_LABEL_INDEX 0x1 + #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */ #endif diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 85ce147d25..42738f8fb9 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -60,6 +60,10 @@ extern struct zebra_t zebrad; /* static function declarations */ +static void +fec_evaluate (struct zebra_vrf *zvrf, int add); +static u_int32_t +fec_derive_label_from_index (struct zebra_vrf *vrf, zebra_fec_t *fec); static int lsp_install (struct zebra_vrf *zvrf, mpls_label_t label, struct route_node *rn, struct rib *rib); @@ -77,7 +81,7 @@ 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, mpls_label_t label, - u_int32_t flags); + u_int32_t flags, u_int32_t label_index); static int fec_del (zebra_fec_t *fec); @@ -352,6 +356,84 @@ lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t label) return 0; } +/* + * This function is invoked upon change to label block configuration; it + * will walk all registered FECs with label-index and appropriately update + * their local labels and trigger client updates. + */ +static void +fec_evaluate (struct zebra_vrf *zvrf, int add) +{ + struct route_node *rn; + zebra_fec_t *fec; + u_int32_t old_label, new_label; + int af; + char buf[BUFSIZ]; + + for (af = AFI_IP; af < AFI_MAX; af++) + { + for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn)) + { + if ((fec = rn->info) == NULL) + continue; + + /* Skip configured FECs and those without a label index. */ + if (fec->flags & FEC_FLAG_CONFIGURED || + fec->label_index == MPLS_INVALID_LABEL_INDEX) + continue; + + if (IS_ZEBRA_DEBUG_MPLS) + prefix2str(&rn->p, buf, BUFSIZ); + + /* Save old label, determine new label. */ + old_label = fec->label; + if (add) + { + new_label = zvrf->mpls_srgb.start_label + fec->label_index; + if (new_label >= zvrf->mpls_srgb.end_label) + new_label = MPLS_INVALID_LABEL; + } + else + new_label = MPLS_INVALID_LABEL; + + /* If label has changed, update FEC and clients. */ + if (new_label == old_label) + continue; + + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug ("Update fec %s new label %u upon label block %s", + buf, new_label, add ? "ADD" : "DEL"); + + fec->label = new_label; + fec_update_clients (fec); + + /* Update label forwarding entries appropriately */ + fec_change_update_lsp (zvrf, fec, old_label); + } + } +} + +/* + * Derive (if possible) and update the local label for the FEC based on + * its label index. The index is "acceptable" if it falls within the + * globally configured label block (SRGB). + */ +static u_int32_t +fec_derive_label_from_index (struct zebra_vrf *zvrf, zebra_fec_t *fec) +{ + u_int32_t label; + + if (fec->label_index != MPLS_INVALID_LABEL_INDEX && + zvrf->mpls_srgb.start_label && + ((label = zvrf->mpls_srgb.start_label + fec->label_index) < + zvrf->mpls_srgb.end_label)) + fec->label = label; + else + fec->label = MPLS_INVALID_LABEL; + + return fec->label; +} + /* * There is a change for this FEC. Install or uninstall label forwarding * entries, as appropriate. @@ -457,6 +539,8 @@ fec_print (zebra_fec_t *fec, struct vty *vty) prefix2str(&rn->p, buf, BUFSIZ); vty_out(vty, "%s%s", buf, VTY_NEWLINE); vty_out(vty, " Label: %s", label2str(fec->label, buf, BUFSIZ)); + if (fec->label_index != MPLS_INVALID_LABEL_INDEX) + vty_out(vty, ", Label Index: %u", fec->label_index); vty_out(vty, "%s", VTY_NEWLINE); if (!list_isempty(fec->client_list)) { @@ -491,7 +575,7 @@ fec_find (struct route_table *table, struct prefix *p) */ static zebra_fec_t * fec_add (struct route_table *table, struct prefix *p, - mpls_label_t label, u_int32_t flags) + mpls_label_t label, u_int32_t flags, u_int32_t label_index) { struct route_node *rn; zebra_fec_t *fec; @@ -519,6 +603,7 @@ fec_add (struct route_table *table, struct prefix *p, else route_unlock_node (rn); /* for the route_node_get */ + fec->label_index = label_index; fec->flags = flags; return fec; @@ -1743,14 +1828,21 @@ zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct /* * Registration from a client for the label binding for a FEC. If a binding * already exists, it is informed to the client. + * NOTE: If there is a manually configured label binding, that is used. + * Otherwise, if aa label index is specified, it means we have to allocate the + * label from a locally configured label block (SRGB), if one exists and index + * is acceptable. */ int zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p, - struct zserv *client) + u_int32_t label_index, struct zserv *client) { struct route_table *table; zebra_fec_t *fec; char buf[BUFSIZ]; + int new_client; + int label_change = 0; + u_int32_t old_label; table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))]; if (!table) @@ -1763,7 +1855,7 @@ zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p, fec = fec_find (table, p); if (!fec) { - fec = fec_add (table, p, MPLS_INVALID_LABEL, 0); + fec = fec_add (table, p, MPLS_INVALID_LABEL, 0, label_index); if (!fec) { prefix2str(p, buf, BUFSIZ); @@ -1771,27 +1863,60 @@ zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p, buf, zebra_route_string(client->proto)); return -1; } + + old_label = MPLS_INVALID_LABEL; + new_client = 1; } else { - if (listnode_lookup(fec->client_list, client)) + /* Client may register same FEC with different label index. */ + new_client = (listnode_lookup(fec->client_list, client) == NULL); + if (!new_client && fec->label_index == label_index) /* Duplicate register */ return 0; + + /* Save current label, update label index */ + old_label = fec->label; + fec->label_index = label_index; } - listnode_add (fec->client_list, client); + if (new_client) + 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)); + zlog_debug("FEC %s Label Index %u %s by client %s", + buf, label_index, new_client ? "registered" : "updated", + zebra_route_string(client->proto)); - if (fec->label != MPLS_INVALID_LABEL) + /* If not a configured FEC, derive the local label (from label index) + * or reset it. + */ + if (!(fec->flags & FEC_FLAG_CONFIGURED)) + { + fec_derive_label_from_index (zvrf, fec); + + /* If no label change, exit. */ + if (fec->label == old_label) + return 0; + + label_change = 1; + } + + /* If new client or label change, update client and install or uninstall + * label forwarding entry as needed. + */ + /* Inform client of label, if needed. */ + if ((new_client && fec->label != MPLS_INVALID_LABEL) || + label_change) { if (IS_ZEBRA_DEBUG_MPLS) zlog_debug ("Update client label %u", fec->label); fec_send (fec, client); } + if (new_client || label_change) + return fec_change_update_lsp (zvrf, fec, old_label); + return 0; } @@ -1830,8 +1955,17 @@ zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p, 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); + /* If not a configured entry, delete the FEC if no other clients. Before + * deleting, see if any LSP needs to be uninstalled. + */ + if (!(fec->flags & FEC_FLAG_CONFIGURED) && + list_isempty(fec->client_list)) + { + mpls_label_t old_label = fec->label; + fec->label = MPLS_INVALID_LABEL; /* reset */ + fec_change_update_lsp (zvrf, fec, old_label); + fec_del (fec); + } return 0; } @@ -1943,7 +2077,8 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p, fec = fec_find (table, p); if (!fec) { - fec = fec_add (table, p, in_label, FEC_FLAG_CONFIGURED); + fec = fec_add (table, p, in_label, FEC_FLAG_CONFIGURED, + MPLS_INVALID_LABEL_INDEX); if (!fec) { prefix2str(p, buf, BUFSIZ); @@ -1979,6 +2114,8 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p, /* * 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) @@ -2003,7 +2140,8 @@ zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p) if (IS_ZEBRA_DEBUG_MPLS) { prefix2str(p, buf, BUFSIZ); - zlog_debug ("Delete fec %s", buf); + zlog_debug ("Delete fec %s label index %u", + buf, fec->label_index); } old_label = fec->label; @@ -2017,6 +2155,12 @@ zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p) return 0; } + /* Derive the local label (from label index) or reset it. */ + fec_derive_label_from_index (zvrf, fec); + + /* If there is a label change, update clients. */ + if (fec->label == old_label) + return 0; fec_update_clients (fec); /* Update label forwarding entries appropriately */ @@ -2744,6 +2888,9 @@ zebra_mpls_label_block_add (struct zebra_vrf *zvrf, u_int32_t start_label, { zvrf->mpls_srgb.start_label = start_label; zvrf->mpls_srgb.end_label = end_label; + + /* Evaluate registered FECs to see if any get a label or not. */ + fec_evaluate (zvrf, 1); return 0; } @@ -2755,6 +2902,9 @@ zebra_mpls_label_block_del (struct zebra_vrf *zvrf) { zvrf->mpls_srgb.start_label = 0; zvrf->mpls_srgb.end_label = 0; + + /* Process registered FECs to clear their local label, if needed. */ + fec_evaluate (zvrf, 0); return 0; } diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index f8e95fa100..e271edd2eb 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -159,6 +159,9 @@ struct zebra_fec_t_ /* In-label - either statically bound or derived from label block. */ mpls_label_t label; + /* Label index (into global label block), if valid */ + u_int32_t label_index; + /* Flags. */ u_int32_t flags; #define FEC_FLAG_CONFIGURED (1 << 0) @@ -217,10 +220,14 @@ zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct /* * Registration from a client for the label binding for a FEC. If a binding * already exists, it is informed to the client. + * NOTE: If there is a manually configured label binding, that is used. + * Otherwise, if aa label index is specified, it means we have to allocate the + * label from a locally configured label block (SRGB), if one exists and index + * is acceptable. */ int zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p, - struct zserv *client); + u_int32_t label_index, struct zserv *client); /* * Deregistration from a client for the label binding for a FEC. The FEC @@ -265,6 +272,8 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p, /* * 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); diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c index 12176c024e..6b0a91de02 100644 --- a/zebra/zebra_mpls_null.c +++ b/zebra/zebra_mpls_null.c @@ -175,7 +175,7 @@ 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) + u_int32_t label_index, struct zserv *client) { return 0; } diff --git a/zebra/zserv.c b/zebra/zserv.c index c11f1bf3fd..7c8e6de765 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -942,6 +942,8 @@ zserv_fec_register (struct zserv *client, int sock, u_short length) struct zebra_vrf *zvrf; u_short l = 0; struct prefix p; + u_int16_t flags; + u_int32_t label_index = MPLS_INVALID_LABEL_INDEX; s = client->ibuf; zvrf = vrf_info_lookup(VRF_DEFAULT); @@ -950,12 +952,18 @@ zserv_fec_register (struct zserv *client, int sock, u_short length) while (l < length) { + flags = stream_getw(s); 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); + if (flags & ZEBRA_FEC_REGISTER_LABEL_INDEX) + { + label_index = stream_getl(s); + l += 4; + } + zebra_mpls_fec_register (zvrf, &p, label_index, client); } return 0; @@ -969,6 +977,7 @@ zserv_fec_unregister (struct zserv *client, int sock, u_short length) struct zebra_vrf *zvrf; u_short l = 0; struct prefix p; + u_int16_t flags; s = client->ibuf; zvrf = vrf_info_lookup(VRF_DEFAULT); @@ -977,6 +986,7 @@ zserv_fec_unregister (struct zserv *client, int sock, u_short length) while (l < length) { + flags = stream_getw(s); p.family = stream_getw(s); p.prefixlen = stream_getc(s); l += 5; From 02cd9458d6de1c86f8cd1f6f08406348d2994486 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 10 Mar 2017 07:59:52 -0500 Subject: [PATCH 12/55] bgpd: Modify attr->flag to be 64 bit With the some current bgp drafts the Attribute number has surpassed 32. Which is a bit unfortunate in that we keep track of the attributes via a bitfield based on the attribute #. For the moment since I am not aware of Attribute #'s being greater than 64, convert the flag to 64 bit and allow the bit shifting to know about it. Signed-off-by: Donald Sharp --- bgpd/bgp_attr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 310fc0215d..e0dac354fb 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -163,7 +163,7 @@ struct attr unsigned long refcnt; /* Flag of attribute is set or not. */ - u_int32_t flag; + u_int64_t flag; /* Apart from in6_addr, the remaining static attributes */ struct in_addr nexthop; @@ -204,7 +204,7 @@ struct transit u_char *val; }; -#define ATTR_FLAG_BIT(X) (1 << ((X) - 1)) +#define ATTR_FLAG_BIT(X) (1ULL << ((X) - 1)) #define BGP_CLUSTER_LIST_LENGTH(attr) \ (((attr)->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) ? \ From 64d222e2c3d628c76817d402c85e84dfa528f13f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 10 Mar 2017 08:04:39 -0500 Subject: [PATCH 13/55] bgpd: Use appropriate Attribute number for labels The draft-ietf-idr-bgp-prefix-sid-04 specifies the label attribute should be 40 not 30. Signed-off-by: Donald Sharp --- bgpd/bgpd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 83c5d90ddf..1b97a25039 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -972,8 +972,8 @@ struct bgp_nlri #define BGP_ATTR_AS4_AGGREGATOR 18 #define BGP_ATTR_AS_PATHLIMIT 21 #define BGP_ATTR_ENCAP 23 -#define BGP_ATTR_LABEL_INDEX 30 #define BGP_ATTR_LARGE_COMMUNITIES 32 +#define BGP_ATTR_LABEL_INDEX 40 #if ENABLE_BGP_VNC #define BGP_ATTR_VNC 255 #endif From 85154a40cd9c22e67564c2606962ce549f489778 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 10 Mar 2017 13:34:02 -0500 Subject: [PATCH 14/55] zebra: Fix gcc compile warn->error issue flags is set but never used. Since we plan to use it in the future, make it evident what is going on here. Signed-off-by: Donald Sharp --- zebra/zserv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/zebra/zserv.c b/zebra/zserv.c index 7c8e6de765..afbaf7eefa 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -977,7 +977,7 @@ zserv_fec_unregister (struct zserv *client, int sock, u_short length) struct zebra_vrf *zvrf; u_short l = 0; struct prefix p; - u_int16_t flags; + //u_int16_t flags; s = client->ibuf; zvrf = vrf_info_lookup(VRF_DEFAULT); @@ -986,7 +986,8 @@ zserv_fec_unregister (struct zserv *client, int sock, u_short length) while (l < length) { - flags = stream_getw(s); + //flags = stream_getw(s); + (void)stream_getw(s); p.family = stream_getw(s); p.prefixlen = stream_getc(s); l += 5; From 42313c3f4426716bd4b5e797285cdaf9d64f335c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 14 Mar 2017 10:02:16 -0400 Subject: [PATCH 15/55] bgpd: bgp_static_update just called bgp_static_update_main Just make it one function call Signed-off-by: Donald Sharp Date: Wed, 15 Mar 2017 08:43:01 -0400 Subject: [PATCH 16/55] bgpd: Fix labeled-unicast generation and parsing issues Labeled-unicast updates were being sent with an ipv6 nexthop due to not setting the mp_nexthop_len or nh_afi. On the receive side, the prefix length was being incorrectly determined and has been fixed. Also the stream for bgp_label_buf was not created. All resolved. Ticket: CM-15260 Signed-off-by: Don Slice Reviewed-by: --- bgpd/bgp_attr.c | 4 ++++ bgpd/bgp_label.c | 2 +- bgpd/bgp_zebra.c | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index acc08184b9..7a28da5780 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2792,6 +2792,10 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi, if (nh_afi == AFI_MAX) nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->extra->mp_nexthop_len); + + if (safi == SAFI_LABELED_UNICAST) + nh_afi = AFI_IP; + /* Nexthop */ switch (nh_afi) { diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index 0c331c5d59..615eca5884 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -253,7 +253,7 @@ bgp_nlri_parse_label (struct peer *peer, struct attr *attr, /* Fill in the labels */ llen = bgp_nlri_get_labels(peer, pnt, psize, label); // zlog_debug("rcvd label [%x/%x/%x], llen=%d\n", label[0], label[1], label[2], llen); - p.prefixlen -= BSIZE(llen); + p.prefixlen = prefixlen - BSIZE(llen); /* There needs to be at least one label */ if (prefixlen < 24) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 1ded613f65..d76eb951db 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -2272,6 +2272,7 @@ bgp_zebra_init (struct thread_master *master) bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE); bgp_ifindices_buf = stream_new(BGP_IFINDICES_BUF_SIZE); + bgp_label_buf = stream_new(BGP_LABEL_BUF_SIZE); } void From ea47f948b9c80795ff8609ba17b3e255143bb090 Mon Sep 17 00:00:00 2001 From: Don Slice Date: Wed, 15 Mar 2017 14:06:54 -0400 Subject: [PATCH 17/55] bgpd: correct labeled-unicast withdraw update Signed-off-by: Don Slice Reviewed-by: Donald Sharp --- bgpd/bgp_packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index f7a78caf91..3b13055604 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1346,7 +1346,7 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet, i case SAFI_MULTICAST: return bgp_nlri_parse_ip (peer, mp_withdraw?NULL:attr, packet); case SAFI_LABELED_UNICAST: - return bgp_nlri_parse_label (peer, attr, packet); + return bgp_nlri_parse_label (peer, mp_withdraw?NULL:attr, packet); case SAFI_MPLS_VPN: return bgp_nlri_parse_vpn (peer, mp_withdraw?NULL:attr, packet); case SAFI_ENCAP: From fe460659b954a04d1a9a6cf6401422728627fdbb Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 15 Mar 2017 15:12:47 -0400 Subject: [PATCH 18/55] bgpd: Fix iana_afi_t afi_t confusion Signed-off-by: Donald Sharp --- bgpd/bgp_updgrp_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 135cdadb24..9be1a50db7 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -789,7 +789,7 @@ subgroup_update_packet (struct update_subgroup *subgrp) subgrp->update_group->id, subgrp->id, send_attr_str); if (!stream_empty (snlri)) { - afi_t pkt_afi; + iana_afi_t pkt_afi; safi_t pkt_safi; pkt_afi = afi_int2iana (afi); @@ -933,7 +933,7 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp) /* If first time, format the MP_UNREACH header */ if (first_time) { - afi_t pkt_afi; + iana_afi_t pkt_afi; safi_t pkt_safi; pkt_afi = afi_int2iana (afi); From aa1ce2dc70dee20345fb0e0b7f7618b56a738d3c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 15 Mar 2017 15:15:40 -0400 Subject: [PATCH 19/55] zebra: Fix usage of HAVE_CUMULUS The function zebra_mpls_lsp_label_consistent needs to be wrappered by HAVE_CUMULUS Signed-off-by: Donald Sharp --- zebra/zebra_mpls_null.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c index 6b0a91de02..0b4d670fda 100644 --- a/zebra/zebra_mpls_null.c +++ b/zebra/zebra_mpls_null.c @@ -98,6 +98,7 @@ zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf) return 0; } +#ifdef HAVE_CUMULUS 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, @@ -105,6 +106,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label, { return 0; } +#endif int zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label, From 95f40dbe21f163d6a906bb4ac027ef44936ba89f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 6 Apr 2017 10:25:43 -0400 Subject: [PATCH 20/55] zebra: Get mpls building across multiple platforms. The build system for mpls is a bit convoluted. We need a way to handle builds across multiple platforms. This, I believe addresses this issue. Signed-off-by: Donald Sharp --- configure.ac | 4 ++-- zebra/Makefile.am | 2 +- zebra/zebra_mpls_null.c | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index b4a3e37fd2..2c9f64a4fe 100755 --- a/configure.ac +++ b/configure.ac @@ -367,11 +367,11 @@ dnl ---------- AC_MSG_CHECKING(whether this OS has MPLS stack) case "$host" in *-linux*) - MPLS_METHOD="zebra_mpls_netlink.o" + MPLS_METHOD="zebra_mpls_netlink.o zebra_mpls.o" AC_MSG_RESULT(Linux MPLS) ;; *-openbsd*) - MPLS_METHOD="zebra_mpls_openbsd.o" + MPLS_METHOD="zebra_mpls_openbsd.o zebra_mpls.o" AC_MSG_RESULT(OpenBSD MPLS) ;; *) diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 821264a15e..c86f81ca7e 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -31,7 +31,7 @@ zebra_SOURCES = \ redistribute.c debug.c rtadv.c zebra_vty.c \ irdp_main.c irdp_interface.c irdp_packet.c router-id.c \ zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c \ - zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls.c zebra_mpls_vty.c \ + zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls_vty.c \ zebra_mroute.c \ label_manager.c \ # end diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c index 0b4d670fda..168c8d003c 100644 --- a/zebra/zebra_mpls_null.c +++ b/zebra/zebra_mpls_null.c @@ -195,3 +195,41 @@ zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client return 0; } +void mpls_ldp_lsp_uninstall_all (struct hash_backet *backet, void *ctxt) +{ + return; +} + +void mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi) +{ + return; +} + +void zebra_mpls_init (void) +{ + return; +} + +int mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type, + mpls_label_t in_label, mpls_label_t out_label, + enum nexthop_types_t gtype, union g_addr *gate, + ifindex_t ifindex) +{ + return 0; +} + +int mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type, + mpls_label_t in_label, enum nexthop_types_t gtype, + union g_addr *gate, ifindex_t ifindex) +{ + return 0; +} + +int mpls_ftn_update (int add, struct zebra_vrf *zvrf, enum lsp_types_t type, + struct prefix *prefix, enum nexthop_types_t gtype, + union g_addr *gate, ifindex_t ifindex, u_int8_t distance, + mpls_label_t out_label) +{ + return 0; +} + From ccddeb994bbae82d55c3734b613368125d843e9f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 7 Apr 2017 13:34:01 -0400 Subject: [PATCH 21/55] bgpd: Switch u_int64_t -> uint64_t Apparently u_int64_t is not available( or we don't pull the right headers in for solaris based systems). Signed-off-by: Donald Sharp --- bgpd/bgp_attr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index e0dac354fb..d57e944aa0 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -163,7 +163,7 @@ struct attr unsigned long refcnt; /* Flag of attribute is set or not. */ - u_int64_t flag; + uint64_t flag; /* Apart from in6_addr, the remaining static attributes */ struct in_addr nexthop; From 5326da0c5c0e3f719848c7def98e8ece539bd916 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 7 Apr 2017 13:56:41 -0400 Subject: [PATCH 22/55] zebra: Experimental commit to see if this fixes snap builds Signed-off-by: Donald Sharp --- zebra/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/Makefile.am b/zebra/Makefile.am index c86f81ca7e..6c5e069064 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -88,7 +88,7 @@ EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_netlink.c \ rt_socket.c rtread_netlink.c rtread_sysctl.c \ rtread_getmsg.c kernel_socket.c kernel_netlink.c \ ioctl.c ioctl_solaris.c \ - zebra_mpls_netlink.c zebra_mpls_openbsd.c \ + zebra_mpls_netlink.c zebra_mpls_openbsd.c zebra_mpls.c \ GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB client : client_main.o ../lib/libfrr.la From 902726b81f80f0e471f886757e95a51e34f4dc78 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 4 Apr 2017 20:36:16 -0400 Subject: [PATCH 23/55] doc: Cleanup 'Build the Software' The frrouting.org web page: https://frrouting.org/manual/Build-the-Software.html#Build-the-Software is built from doc/install.texi. The output on this page is a bit missleading, let's clean it up some. Signed-off-by: Donald Sharp --- doc/install.texi | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/doc/install.texi b/doc/install.texi index 8c501ed45d..595898277a 100644 --- a/doc/install.texi +++ b/doc/install.texi @@ -218,18 +218,14 @@ routing utility. It contains @command{ifconfig}, @command{route}, After configuring the software, you will need to compile it for your system. Simply issue the command @command{make} in the root of the source -directory and the software will be compiled. If you have *any* problems -at this stage, be certain to send a bug report @xref{Bug Reports}. +directory and the software will be compiled. Cliff Note versions of +different compilation examples can be found in the doc/Building_FRR_on_XXX.md +files. If you have *any* problems at this stage, be certain to send a +bug report @xref{Bug Reports}. @example -% ./configure -. -. -. -./configure output -. -. -. +% ./bootstrap.sh +% ./configure % make @end example @c A - End of node, Building the Software From 2a3a819a9c2b2c9700e6228e7352e53b3562776c Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Wed, 12 Apr 2017 16:00:43 -0700 Subject: [PATCH 24/55] snapcraft: Improve README.usage.md based on feedback received - Fix snap connect (it's now called core, not ubuntu-core) - Add section on MPLS configuration - Add FAQ topic on ospfd/ospf6d crashing before privs are assigned to snap - Add pointer to official webpage Signed-off-by: Martin Winter --- snapcraft/README.usage.md | 59 +++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/snapcraft/README.usage.md b/snapcraft/README.usage.md index aaff59438a..c678c8805c 100644 --- a/snapcraft/README.usage.md +++ b/snapcraft/README.usage.md @@ -3,7 +3,7 @@ Using the FRRouting Snap After installing the Snap, the priviledged plug need to be connected: - snap connect frr:network-control ubuntu-core:network-control + snap connect frr:network-control core:network-control Enabling/Disabling FRRouting Daemons ------------------------------------------- @@ -53,25 +53,74 @@ depend on them). These are mainly intended to debug the Snap - `frr.ldpd-debug`: Starts ldpd daemon in foreground +MPLS (LDP) +---------- +The MPLS forwarding requires a Linux Kernel version 4.5 or newer and +specific MPLS kernel modules loaded. It will be auto-detected by +FRR. You can check the detected setup with the `show mpls status` +command from within `frr.vtysh` + +The following kernel modules `mpls-router` and `mpls-iptunnel` +need to be loaded. On Ubuntu 16.04, this can be done by editing +'/etc/modules-load.d/modules.conf' and add the following lines: + + # Load MPLS Kernel Modules + mpls-router + mpls-iptunnel + +For other distributions, please check the documentation on loading +modules. You need to either reboot or use `modprobe` to manually load +the modules as well before MPLS will be available. + +In addition to this, the MPLS Label-Processing needs to be enabled +with `sysctl` on the required interfaces. Assuming the interfaces +are named `eth0`, `eth1` and `eth2`, then the additional lines in +`/etc/sysctl.conf` will enable it on a Ubuntu 16.04 system: + + # Enable MPLS Label processing on all interfaces + net.mpls.conf.eth0.input=1 + net.mpls.conf.eth1.input=1 + net.mpls.conf.eth2.input=1 + net.mpls.platform_labels=100000 + +These settings require either a reboot or a manual configuration with +`sysctl` as well. + FAQ --- - frr.vtysh displays `--MORE--` on long output. How to suppress this? - Define `VTYSH_PAGER` to `cat` (default is `more`). (Ie add `export VTYSH_PAGER=cat` to the end of your `.profile`) +- ospfd / ospf6d are not running after installation + - Installing a new snap starts the daemons, but at this time they + may not have the required priviledged access. Make sure you + issue the `snap connect` command as given above (can be verified + with `snap interfaces`) and **THEN** restart the daemons (or + reboot the system). + This is a limitation of any snap package at this time which + requires priviledged interfaces (ie to manipulate routing tables) + Sourcecode available ==================== The source for this SNAP is available as part of the FRRouting -Source Code Distribution. +Source Code Distribution under `GPLv2 or later` - https://github.com/frrouting/frr.git + -Instructions for rebuilding the snap are in `README.snap_build.md` +Instructions for rebuilding the snap are in `snapcraft/README.snap_build.md` + +*Please checkout the desired branch before following the instructions +as they may have changed between versions of FRR* + +Official Webpage for FRR +======================== + +Official webpage for FRR is at Feedback welcome ================ Please send Feedback about this snap to Martin Winter at `mwinter@opensourcerouting.org` - From 7caef08c842f616c65bf2d30b622828507fb2db1 Mon Sep 17 00:00:00 2001 From: Phil Huang Date: Thu, 13 Apr 2017 18:11:28 +0800 Subject: [PATCH 25/55] Add user `frr` into group `frrvty` Signed-off-by: Phil Huang --- doc/Building_FRR_on_Debian8.md | 8 ++++---- doc/Building_FRR_on_Ubuntu1204.md | 5 +++-- doc/Building_FRR_on_Ubuntu1404.md | 5 +++-- doc/Building_FRR_on_Ubuntu1604.md | 5 +++-- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/doc/Building_FRR_on_Debian8.md b/doc/Building_FRR_on_Debian8.md index 81d58827d3..f14930334e 100644 --- a/doc/Building_FRR_on_Debian8.md +++ b/doc/Building_FRR_on_Debian8.md @@ -31,9 +31,9 @@ any packages** sudo addgroup --system --gid 92 frr sudo addgroup --system --gid 85 frrvty - sudo adduser --system --ingroup frr --groups frrvty --home /var/run/frr/ \ - --gecos "FRR FRRouting suite" --shell /bin/false frr - sudo usermode + sudo adduser --system --ingroup frr --home /var/run/frr/ \ + --gecos "FRR suite" --shell /bin/false frr + sudo usermod -a -G frrvty frr ### Download Source, configure and compile it (You may prefer different options on configure statement. These are just @@ -95,4 +95,4 @@ other settings) # based on Router Advertisements for this host net.ipv6.conf.all.forwarding=1 -**Reboot** or use `sysctl` to apply the same config to the running system +**Reboot** or use `sysctl -p` to apply the same config to the running system diff --git a/doc/Building_FRR_on_Ubuntu1204.md b/doc/Building_FRR_on_Ubuntu1204.md index 6e6374c2f8..d39c34f525 100644 --- a/doc/Building_FRR_on_Ubuntu1204.md +++ b/doc/Building_FRR_on_Ubuntu1204.md @@ -65,8 +65,9 @@ any packages** sudo groupadd -g 92 frr sudo groupadd -r -g 85 frrvty - sudo adduser --system --ingroup frr --groups frrvty --home /var/run/frr/ \ + sudo adduser --system --ingroup frr --home /var/run/frr/ \ --gecos "FRR suite" --shell /sbin/nologin frr + sudo usermod -a -G frrvty frr ### Download Source, configure and compile it (You may prefer different options on configure statement. These are just @@ -133,4 +134,4 @@ other settings) # based on Router Advertisements for this host net.ipv6.conf.all.forwarding=1 -**Reboot** or use `sysctl` to apply the same config to the running system +**Reboot** or use `sysctl -p` to apply the same config to the running system diff --git a/doc/Building_FRR_on_Ubuntu1404.md b/doc/Building_FRR_on_Ubuntu1404.md index 6db3f426b4..3c4e518fba 100644 --- a/doc/Building_FRR_on_Ubuntu1404.md +++ b/doc/Building_FRR_on_Ubuntu1404.md @@ -25,8 +25,9 @@ any packages** sudo groupadd -g 92 frr sudo groupadd -r -g 85 frrvty - sudo adduser --system --ingroup frr --groups frrvty --home /var/run/frr/ \ + sudo adduser --system --ingroup frr --home /var/run/frr/ \ --gecos "FRR suite" --shell /sbin/nologin frr + sudo usermod -a -G frrvty frr ### Download Source, configure and compile it (You may prefer different options on configure statement. These are just @@ -91,4 +92,4 @@ other settings) # based on Router Advertisements for this host net.ipv6.conf.all.forwarding=1 -**Reboot** or use `sysctl` to apply the same config to the running system +**Reboot** or use `sysctl -p` to apply the same config to the running system diff --git a/doc/Building_FRR_on_Ubuntu1604.md b/doc/Building_FRR_on_Ubuntu1604.md index 8e71cc1eee..2a6a30f961 100644 --- a/doc/Building_FRR_on_Ubuntu1604.md +++ b/doc/Building_FRR_on_Ubuntu1604.md @@ -26,8 +26,9 @@ any packages** sudo groupadd -g 92 frr sudo groupadd -r -g 85 frrvty - sudo adduser --system --ingroup frr --groups frrvty --home /var/run/frr/ \ + sudo adduser --system --ingroup frr --home /var/run/frr/ \ --gecos "FRR suite" --shell /sbin/nologin frr + sudo usermod -a -G frrvty frr ### Download Source, configure and compile it (You may prefer different options on configure statement. These are just @@ -113,4 +114,4 @@ Add the following lines to `/etc/modules-load.d/modules.conf`: mpls-router mpls-iptunnel -**Reboot** or use `sysctl` to apply the same config to the running system +**Reboot** or use `sysctl -p` to apply the same config to the running system From be9665641df19efdfe08b941fef4507956fff97c Mon Sep 17 00:00:00 2001 From: Phil Huang Date: Thu, 13 Apr 2017 21:20:53 +0800 Subject: [PATCH 26/55] Clean installation guide with Debian/Ubuntu Signed-off-by: Phil Huang --- doc/Building_FRR_on_Debian8.md | 3 +++ doc/Building_FRR_on_Ubuntu1204.md | 28 ++++++++++++---------------- doc/Building_FRR_on_Ubuntu1404.md | 28 +++++++++++++--------------- doc/Building_FRR_on_Ubuntu1604.md | 28 ++++++++++++---------------- 4 files changed, 40 insertions(+), 47 deletions(-) diff --git a/doc/Building_FRR_on_Debian8.md b/doc/Building_FRR_on_Debian8.md index f14930334e..0084433721 100644 --- a/doc/Building_FRR_on_Debian8.md +++ b/doc/Building_FRR_on_Debian8.md @@ -63,6 +63,7 @@ an example.) --enable-rtadv \ --enable-tcp-zebra \ --enable-fpm \ + --enable-ldpd \ --with-pkg-git-version \ --with-pkg-extra-version=-MyOwnFRRVersion make @@ -70,6 +71,7 @@ an example.) sudo make install ### Create empty FRR configuration files + sudo install -m 755 -o frr -g frr -d /var/log/frr sudo install -m 775 -o frr -g frrvty -d /etc/frr sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf @@ -80,6 +82,7 @@ an example.) sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf ### Enable IP & IPv6 forwarding diff --git a/doc/Building_FRR_on_Ubuntu1204.md b/doc/Building_FRR_on_Ubuntu1204.md index d39c34f525..7766ff548b 100644 --- a/doc/Building_FRR_on_Ubuntu1204.md +++ b/doc/Building_FRR_on_Ubuntu1204.md @@ -104,22 +104,18 @@ an example.) ### Create empty FRR configuration files - sudo mkdir /var/log/frr - sudo chown frr:fee /var/log/frr - sudo mkdir /etc/frr - sudo touch /etc/frr/etc/zebra.conf - sudo touch /etc/frr/etc/bgpd.conf - sudo touch /etc/frr/etc/ospfd.conf - sudo touch /etc/frr/etc/ospf6d.conf - sudo touch /etc/frr/etc/isisd.conf - sudo touch /etc/frr/etc/ripd.conf - sudo touch /etc/frr/etc/ripngd.conf - sudo touch /etc/frr/etc/pimd.conf - sudo touch /etc/frr/etc/ldpd.conf - sudo chown frr:frr /etc/frr/ - sudo touch /etc/frr/etc/vtysh.conf - sudo chown frr:frrvty /etc/frr/etc/vtysh.conf - sudo chmod 640 /etc/frr/*.conf + sudo install -m 755 -o frr -g frr -d /var/log/frr + sudo install -m 775 -o frr -g frrvty -d /etc/frr + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf + sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf ### Enable IP & IPv6 forwarding diff --git a/doc/Building_FRR_on_Ubuntu1404.md b/doc/Building_FRR_on_Ubuntu1404.md index 3c4e518fba..43b20e7143 100644 --- a/doc/Building_FRR_on_Ubuntu1404.md +++ b/doc/Building_FRR_on_Ubuntu1404.md @@ -55,6 +55,7 @@ an example.) --enable-rtadv \ --enable-tcp-zebra \ --enable-fpm \ + --enable-ldpd \ --with-pkg-git-version \ --with-pkg-extra-version=-MyOwnFRRVersion make @@ -63,21 +64,18 @@ an example.) ### Create empty FRR configuration files - sudo mkdir /var/log/frr - sudo chown frr:fee /var/log/frr - sudo mkdir /etc/frr - sudo touch /etc/frr/etc/zebra.conf - sudo touch /etc/frr/etc/bgpd.conf - sudo touch /etc/frr/etc/ospfd.conf - sudo touch /etc/frr/etc/ospf6d.conf - sudo touch /etc/frr/etc/isisd.conf - sudo touch /etc/frr/etc/ripd.conf - sudo touch /etc/frr/etc/ripngd.conf - sudo touch /etc/frr/etc/pimd.conf - sudo chown frr:frr /etc/frr/ - sudo touch /etc/frr/etc/vtysh.conf - sudo chown frr:frrvty /etc/frr/etc/vtysh.conf - sudo chmod 640 /etc/frr/*.conf + sudo install -m 755 -o frr -g frr -d /var/log/frr + sudo install -m 775 -o frr -g frrvty -d /etc/frr + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf + sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf ### Enable IP & IPv6 forwarding diff --git a/doc/Building_FRR_on_Ubuntu1604.md b/doc/Building_FRR_on_Ubuntu1604.md index 2a6a30f961..b213a90858 100644 --- a/doc/Building_FRR_on_Ubuntu1604.md +++ b/doc/Building_FRR_on_Ubuntu1604.md @@ -65,22 +65,18 @@ an example.) ### Create empty FRR configuration files - sudo mkdir /var/log/frr - sudo chown frr:fee /var/log/frr - sudo mkdir /etc/frr - sudo touch /etc/frr/etc/zebra.conf - sudo touch /etc/frr/etc/bgpd.conf - sudo touch /etc/frr/etc/ospfd.conf - sudo touch /etc/frr/etc/ospf6d.conf - sudo touch /etc/frr/etc/isisd.conf - sudo touch /etc/frr/etc/ripd.conf - sudo touch /etc/frr/etc/ripngd.conf - sudo touch /etc/frr/etc/pimd.conf - sudo touch /etc/frr/etc/ldpd.conf - sudo chown frr:frr /etc/frr/ - sudo touch /etc/frr/etc/vtysh.conf - sudo chown frr:frrvty /etc/frr/etc/vtysh.conf - sudo chmod 640 /etc/frr/*.conf + sudo install -m 755 -o frr -g frr -d /var/log/frr + sudo install -m 775 -o frr -g frrvty -d /etc/frr + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf + sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf ### Enable IP & IPv6 forwarding From 5cf5f2033b3fbbf6ab84dd6095c26f461e4e75b7 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 14 Apr 2017 20:05:48 -0400 Subject: [PATCH 27/55] bgpd: Fix 'set as-path prepend last-as 10' The route-map compilation function was comparing < 10 instead of <= 10. While the cli was accepting 1-10. Fix: ! route-map FOO permit 44 set as-path prepend last-as 10 ! Signed-off-by: Donald Sharp --- bgpd/bgp_routemap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index d0cce4a955..78ecb91abf 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1362,7 +1362,7 @@ route_set_aspath_prepend_compile (const char *arg) { unsigned int num; - if (sscanf(arg, "last-as %u", &num) == 1 && num > 0 && num < 10) + if (sscanf(arg, "last-as %u", &num) == 1 && num > 0 && num <= 10) return (void*)(uintptr_t)num; return route_aspath_compile(arg); From b3b3879c3e65606370bdfaaf5781645a2381d8b9 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 15 Apr 2017 08:33:43 -0400 Subject: [PATCH 28/55] lib, bgpd: Remove UNDEFINED_NODE Remove the UNDEFINED_NODE as that it's implementation breaks our ability in BGP to figure out where we are by allowing default: in the switch statement. Signed-off-by: Donald Sharp --- bgpd/bgp_vty.c | 17 +++++++++-------- lib/command.h | 1 - 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index ef5571c9ae..44389b99c2 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -93,9 +93,6 @@ bgp_node_type (afi_t afi, safi_t safi) case SAFI_ENCAP: return BGP_ENCAP_NODE; break; - default: - return UNDEFINED_NODE; - break; } break; case AFI_IP6: @@ -116,15 +113,19 @@ bgp_node_type (afi_t afi, safi_t safi) case SAFI_ENCAP: return BGP_ENCAP_NODE; break; - default: - return UNDEFINED_NODE; - break; } break; - default: - return UNDEFINED_NODE; + case AFI_L2VPN: + return BGP_EVPN_NODE; + break; + case AFI_MAX: + // We should never be here but to clarify the switch statement.. + return BGP_IPV4_NODE; break; } + + // Impossible to happen + return BGP_IPV4_NODE; } /* Utility function to get address family from current node. */ diff --git a/lib/command.h b/lib/command.h index 1a5e069ce3..a8256c0312 100644 --- a/lib/command.h +++ b/lib/command.h @@ -136,7 +136,6 @@ enum node_type MPLS_NODE, /* MPLS config node */ VTY_NODE, /* Vty node. */ LINK_PARAMS_NODE, /* Link-parameters node */ - UNDEFINED_NODE }; /* Node which has some commands and prompt string and configuration From 95169c2f785d09aebd6c0e25bf311ecc185fb61a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 15 Apr 2017 08:42:18 -0400 Subject: [PATCH 29/55] zebra: Fix crash with dereference of NULL pointer We only create the v4 and v6 mpls fec tables currently. Follow the code pattern for the rest of the code and ensure that the table exists before we attempt to access it. Signed-off-by: Donald Sharp --- zebra/zebra_mpls.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 42738f8fb9..76263024c5 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -372,6 +372,9 @@ fec_evaluate (struct zebra_vrf *zvrf, int add) 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 ((fec = rn->info) == NULL) From bf995813b2176819aa5816d8935cf73aeb2f7d51 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 15 Apr 2017 08:57:03 -0400 Subject: [PATCH 30/55] zebra: Allow explicit-null as a label option When entering 'mpls label bind ...' command allow the explicit-null as an option. Signed-off-by: Donald Sharp --- zebra/zebra_mpls_vty.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_mpls_vty.c b/zebra/zebra_mpls_vty.c index f46037487e..ae1de8be2e 100644 --- a/zebra/zebra_mpls_vty.c +++ b/zebra/zebra_mpls_vty.c @@ -243,6 +243,13 @@ zebra_mpls_bind (struct vty *vty, int add_cmd, const char *prefix, if (!strcmp(label_str, "implicit-null")) label = MPLS_IMP_NULL_LABEL; + else if (!strcmp(label_str, "explicit-null")) + { + if (p.family == AF_INET) + label = MPLS_V4_EXP_NULL_LABEL; + else + label = MPLS_V6_EXP_NULL_LABEL; + } else { label = atoi(label_str); @@ -276,14 +283,15 @@ zebra_mpls_bind (struct vty *vty, int add_cmd, const char *prefix, DEFUN (mpls_label_bind, mpls_label_bind_cmd, - "mpls label bind <(16-1048575)|implicit-null>", + "mpls label bind <(16-1048575)|implicit-null|explicit-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") + "Use Implicit-Null Label\n" + "Use Explicit-Null Label\n") { return zebra_mpls_bind (vty, 1, argv[3]->arg, argv[4]->arg); } From 9db2da6c5953e115824fb39a5ff3b25b313d537a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 15 Apr 2017 08:59:40 -0400 Subject: [PATCH 31/55] zebra: Fix whitespace issue with if statement Signed-off-by: Donald Sharp --- zebra/zebra_mpls_vty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_mpls_vty.c b/zebra/zebra_mpls_vty.c index ae1de8be2e..7662cf4163 100644 --- a/zebra/zebra_mpls_vty.c +++ b/zebra/zebra_mpls_vty.c @@ -899,8 +899,8 @@ DEFUN (show_mpls_fec, int ret; zvrf = vrf_info_lookup(VRF_DEFAULT); - if (!zvrf) - return 0; + if (!zvrf) + return 0; if (argc == 3) zebra_mpls_print_fec_table(vty, zvrf); From 9fbea8d56d4aa5d71ce0ae9204e15fbd06c3c02a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 15 Apr 2017 09:31:59 -0400 Subject: [PATCH 32/55] bgpd: Fix up several issues in bgp_route.c 1) Some commands were installed in the wrong node 2) Fix output to show labeled information to correctly display 3) Whitespace issue in route-map command Signed-off-by: Donald Sharp --- bgpd/bgp_route.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index d1924fe91e..05e34b4375 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5135,7 +5135,7 @@ ALIAS (no_bgp_network, ALIAS (no_bgp_network, no_bgp_network_label_index_route_map_cmd, - "no network A.B.C.D/M label-index (0-4294967294)route-map WORD", + "no network A.B.C.D/M label-index (0-4294967294) route-map WORD", NO_STR "Specify a network to announce via BGP\n" "IP prefix\n" @@ -7653,21 +7653,28 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (binfo->extra && binfo->extra->damp_info) bgp_damp_info_vty (vty, binfo, json_path); - if (bgp_labeled_safi(safi) && binfo->extra) + if ((bgp_labeled_safi(safi) && binfo->extra) || + (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)))) { - uint32_t label = label_pton(binfo->extra->tag); - if (json_paths) - json_object_int_add(json_path, "remote-label", label); - else - vty_out(vty, " Remote label: %d", label); - } + if (!json_paths) + vty_out (vty, "%s ", VTY_NEWLINE); - if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))) - { - if (json_paths) - json_object_int_add(json_path, "label-index", attr->extra->label_index); - else - vty_out(vty, ", Label Index: %d", attr->extra->label_index); + if (bgp_labeled_safi(safi) && binfo->extra) + { + uint32_t label = label_pton(binfo->extra->tag); + if (json_paths) + json_object_int_add(json_path, "remote-label", label); + else + vty_out(vty, "Remote label: %d, ", label); + } + + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))) + { + if (json_paths) + json_object_int_add(json_path, "label-index", attr->extra->label_index); + else + vty_out(vty, "Label Index: %d", attr->extra->label_index); + } } if (!json_paths) @@ -10909,8 +10916,8 @@ bgp_route_init (void) install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd); - install_element (BGP_IPV4_NODE, &no_bgp_network_label_index_cmd); - install_element (BGP_IPV4_NODE, &no_bgp_network_label_index_route_map_cmd); + install_element (BGP_IPV4L_NODE, &no_bgp_network_label_index_cmd); + install_element (BGP_IPV4L_NODE, &no_bgp_network_label_index_route_map_cmd); install_element (BGP_IPV4_NODE, &no_bgp_table_map_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd); From 7abc04e686fefeb76bc825e908837e55bec0efc7 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 15 Apr 2017 13:25:03 -0400 Subject: [PATCH 33/55] zebra: Add some more checks to fec [un]registration Be a bit more rigoruous about what we can receive from another protocol and attempt to make the code less likely to crash and to just safely bail out when an error is received. Signed-off-by: Donald Sharp --- zebra/zserv.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/zebra/zserv.c b/zebra/zserv.c index afbaf7eefa..416e5444ea 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -934,6 +934,8 @@ zserv_rnh_unregister (struct zserv *client, int sock, u_short length, return 0; } +#define ZEBRA_MIN_FEC_LENGTH 9 + /* FEC register */ static int zserv_fec_register (struct zserv *client, int sock, u_short length) @@ -950,10 +952,28 @@ zserv_fec_register (struct zserv *client, int sock, u_short length) if (!zvrf) return 0; // unexpected + /* + * The minimum amount of data that can be sent for one fec + * registration + */ + if (length < ZEBRA_MIN_FEC_LENGTH) + { + zlog_err ("fec_register: Received a fec register of length %d, it is of insufficient size to properly decode", + length); + return -1; + } + while (l < length) { flags = stream_getw(s); p.family = stream_getw(s); + if (p.family != AF_INET && + p.family != AF_INET6) + { + zlog_err ("fec_register: Received unknown family type %d\n", + p.family); + return -1; + } p.prefixlen = stream_getc(s); l += 5; stream_get(&p.u.prefix, s, PSIZE(p.prefixlen)); @@ -984,11 +1004,29 @@ zserv_fec_unregister (struct zserv *client, int sock, u_short length) if (!zvrf) return 0; // unexpected + /* + * The minimum amount of data that can be sent for one + * fec unregistration + */ + if (length < ZEBRA_MIN_FEC_LENGTH) + { + zlog_err ("fec_unregister: Received a fec unregister of length %d, it is of insufficient size to properly decode", + length); + return -1; + } + while (l < length) { //flags = stream_getw(s); (void)stream_getw(s); p.family = stream_getw(s); + if (p.family != AF_INET && + p.family != AF_INET6) + { + zlog_err ("fec_unregister: Received unknown family type %d\n", + p.family); + return -1; + } p.prefixlen = stream_getc(s); l += 5; stream_get(&p.u.prefix, s, PSIZE(p.prefixlen)); From ef01549170d412edb8f22519414108586e5ca219 Mon Sep 17 00:00:00 2001 From: Don Slice Date: Tue, 18 Apr 2017 08:11:32 -0400 Subject: [PATCH 34/55] zebra: stop crash on process termination due to stale ifp->node Problem reported that crash occurred when stopping quagga in certain circumstances. Determined that this was due to a stale pointer on the ifp for a deleted interface. The ifp->node had been freed but the ifp still kept a pointer to it, and when later the process was stopped, it attempted to delete it again. Ticket: CM-15550 Signed-off-by: Don Slice Reviewed-by: Donald Sharp --- zebra/interface.c | 1 + 1 file changed, 1 insertion(+) diff --git a/zebra/interface.c b/zebra/interface.c index 1d015e8588..1eefe1339c 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -691,6 +691,7 @@ if_delete_update (struct interface *ifp) for setting ifindex to IFINDEX_INTERNAL after processing the interface deletion message. */ ifp->ifindex = IFINDEX_INTERNAL; + ifp->node = NULL; } /* VRF change for an interface */ From 23b1f334515a1c9198f436cdf06982818378936c Mon Sep 17 00:00:00 2001 From: Dinesh G Dutt Date: Wed, 11 Jan 2017 14:33:39 -0800 Subject: [PATCH 35/55] Add source of route as protocol string in ip route pushed into kernel Ticket: CM-14313 Reviewed By: Testing Done: bgpmin, ospfmin, bgp_kitchen_sink_test 'ip route show' displays all routes as belonging to protocol zebra. The user has to run an additional command (in vtysh) to get the actual source of a route (bgp/ospf/static etc.). This patch addresses that by pushing the appropriate protocol string into the protocol field of the netlink route update message. Now you can see routes with the correct origin as well as filter on them (ip route show proto ospf). 'ospf' is used for both IPv4 and IPv6 routes, even though the OSPF version is different in both cases. Sample output (old): 9.9.12.13 via 69.254.2.38 dev swp3.2 proto zebra metric 20 9.9.13.3 proto zebra metric 20 nexthop via 69.254.2.30 dev swp1.2 weight 1 nexthop via 69.254.2.34 dev swp2.2 weight 1 nexthop via 69.254.2.38 dev swp3.2 weight 1 Sample output (new): 9.9.12.13 via 69.254.2.38 dev swp3.2 proto bgp metric 20 9.9.13.3 proto bgp metric 20 nexthop via 69.254.2.30 dev swp1.2 weight 1 nexthop via 69.254.2.34 dev swp2.2 weight 1 nexthop via 69.254.2.38 dev swp3.2 weight 1 --- cumulus/etc/iproute2/rt_protos.d/frr.conf | 8 ++++ debian/frr.dirs | 1 + tools/frr | 9 ++++- zebra/kernel_netlink.c | 5 +++ zebra/rt_netlink.c | 47 +++++++++++++++++++++-- zebra/rt_netlink.h | 8 ++++ 6 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 cumulus/etc/iproute2/rt_protos.d/frr.conf diff --git a/cumulus/etc/iproute2/rt_protos.d/frr.conf b/cumulus/etc/iproute2/rt_protos.d/frr.conf new file mode 100644 index 0000000000..3f55b11268 --- /dev/null +++ b/cumulus/etc/iproute2/rt_protos.d/frr.conf @@ -0,0 +1,8 @@ +# Additional protocol strings defined by frr for each of its daemons + +186 bgp +187 isis +188 ospf +189 rip +190 ripng +191 static diff --git a/debian/frr.dirs b/debian/frr.dirs index 58290080d0..56699b2daa 100644 --- a/debian/frr.dirs +++ b/debian/frr.dirs @@ -1,5 +1,6 @@ etc/logrotate.d/ etc/frr/ +etc/iproute2/rt_protos.d/ usr/share/doc/frr/ usr/share/doc/frr/examples/ usr/share/lintian/overrides/ diff --git a/tools/frr b/tools/frr index 80dd9e8747..1906b4ad15 100755 --- a/tools/frr +++ b/tools/frr @@ -532,8 +532,15 @@ case "$1" in fi if [ -z "$dmn" -o "$dmn" = "zebra" ]; then - echo "Removing all routes made by zebra." + echo "Removing all routes made by FRR." + ip route flush proto bgp + ip route flush proto ospf + ip route flush proto static + ip route flush proto rip + ip route flush proto ripng ip route flush proto zebra + ip route flush proto isis + else [ -n "$dmn" ] && eval "${dmn/-/_}=0" start_watchfrr diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 49394bd6f8..e974203219 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -100,6 +100,11 @@ static const struct message rtproto_str[] = { {RTPROT_BIRD, "BIRD"}, #endif /* RTPROT_BIRD */ {RTPROT_MROUTED, "mroute"}, + {RTPROT_BGP, "BGP"}, + {RTPROT_OSPF, "OSPF"}, + {RTPROT_ISIS, "IS-IS"}, + {RTPROT_RIP, "RIP"}, + {RTPROT_RIPNG, "RIPNG"}, {0, NULL} }; diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index a544593dd6..77f03a2c67 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -103,6 +103,47 @@ struct gw_family_t union g_addr gate; }; +static inline int is_selfroute(int proto) +{ + if ((proto == RTPROT_BGP) || (proto == RTPROT_OSPF) || + (proto == RTPROT_STATIC) || (proto == RTPROT_ZEBRA) || + (proto == RTPROT_ISIS) || (proto == RTPROT_RIPNG)) { + return 1; + } + + return 0; +} + +static inline int get_rt_proto(int proto) +{ + switch (proto) { + case ZEBRA_ROUTE_BGP: + proto = RTPROT_BGP; + break; + case ZEBRA_ROUTE_OSPF: + case ZEBRA_ROUTE_OSPF6: + proto = RTPROT_OSPF; + break; + case ZEBRA_ROUTE_STATIC: + proto = RTPROT_STATIC; + break; + case ZEBRA_ROUTE_ISIS: + proto = RTPROT_ISIS; + break; + case ZEBRA_ROUTE_RIP: + proto = RTPROT_RIP; + break; + case ZEBRA_ROUTE_RIPNG: + proto = RTPROT_RIPNG; + break; + default: + proto = RTPROT_ZEBRA; + break; + } + + return proto; +} + /* Pending: create an efficient table_id (in a tree/hash) based lookup) */ @@ -171,7 +212,7 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h, return 0; if (!startup && - rtm->rtm_protocol == RTPROT_ZEBRA && + is_selfroute (rtm->rtm_protocol) && h->nlmsg_type == RTM_NEWROUTE) return 0; @@ -196,7 +237,7 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h, } /* Route which inserted by Zebra. */ - if (rtm->rtm_protocol == RTPROT_ZEBRA) + if (is_selfroute(rtm->rtm_protocol)) flags |= ZEBRA_FLAG_SELFROUTE; if (tb[RTA_OIF]) @@ -1137,7 +1178,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct prefix *src_p, req.r.rtm_family = family; req.r.rtm_dst_len = p->prefixlen; req.r.rtm_src_len = src_p ? src_p->prefixlen : 0; - req.r.rtm_protocol = RTPROT_ZEBRA; + req.r.rtm_protocol = get_rt_proto(rib->type); req.r.rtm_scope = RT_SCOPE_UNIVERSE; if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT)) diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index 93ee622e35..af58a0f0d4 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -28,6 +28,14 @@ #define NL_DEFAULT_ROUTE_METRIC 20 +/* Additional protocol strings to push into routes */ +#define RTPROT_BGP 186 +#define RTPROT_ISIS 187 +#define RTPROT_OSPF 188 +#define RTPROT_RIP 189 +#define RTPROT_RIPNG 190 + + extern void clear_nhlfe_installed (zebra_lsp_t *lsp); extern int From 22d289d393285e696e391d3319ba8c758210c72c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 25 Apr 2017 07:37:00 -0400 Subject: [PATCH 36/55] *: Move the cumulus/etc/rt_protos.d/frr.conf Moving cumulus/etc/rt_protos.d/frr.conf to tools/etc/rt_protos.d/frr.conf Requested in Review. Signed-off-by: Donald Sharp --- debian/frr.install | 1 + {cumulus => tools}/etc/iproute2/rt_protos.d/frr.conf | 0 2 files changed, 1 insertion(+) rename {cumulus => tools}/etc/iproute2/rt_protos.d/frr.conf (100%) diff --git a/debian/frr.install b/debian/frr.install index 45b3b973be..e81ebbc5be 100644 --- a/debian/frr.install +++ b/debian/frr.install @@ -18,5 +18,6 @@ usr/share/man/man8/isisd.8 usr/share/man/man8/watchfrr.8 usr/share/snmp/mibs/ cumulus/etc/* etc/ +tools/etc/* etc/ tools/*.service lib/systemd/system debian/frr.conf usr/lib/tmpfiles.d diff --git a/cumulus/etc/iproute2/rt_protos.d/frr.conf b/tools/etc/iproute2/rt_protos.d/frr.conf similarity index 100% rename from cumulus/etc/iproute2/rt_protos.d/frr.conf rename to tools/etc/iproute2/rt_protos.d/frr.conf From 1d4b7d0e1ad1dfb2028774813b60a62ad18553c3 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 25 Apr 2017 21:53:28 +0000 Subject: [PATCH 37/55] bgpd: Do not force nh_afi to be AFI_IP for 'ipv4 labeled-unicast' Signed-off-by: Daniel Walton --- bgpd/bgp_attr.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 7a28da5780..6f4e797a94 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2793,9 +2793,6 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi, if (nh_afi == AFI_MAX) nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->extra->mp_nexthop_len); - if (safi == SAFI_LABELED_UNICAST) - nh_afi = AFI_IP; - /* Nexthop */ switch (nh_afi) { From d39cdd933f499e94577e1888fd78123a6dfe2d44 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Wed, 26 Apr 2017 15:53:35 +0000 Subject: [PATCH 38/55] BGP_ATTR_LABEL_INDEX fixes Signed-off-by: Daniel Walton - cleaned up the "show bgp ipv4 labeled-unicast x.x.x.x" output - fixed some json keys to use camelCase - bgp_attr_label_index() was clearing BGP_ATTR_LABEL_INDEX because it was comparing mp_update->afi against SAFI_LABELED_UNICAST instead of mp_update->safi - added BGP_ATTR_LABEL_INDEX to attr_str --- bgpd/bgp_attr.c | 5 +++-- bgpd/bgp_route.c | 15 +++++---------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 6f4e797a94..a25ebf4772 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -78,7 +78,8 @@ static const struct message attr_str [] = #if ENABLE_BGP_VNC { BGP_ATTR_VNC, "VNC" }, #endif - { BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" } + { BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" }, + { BGP_ATTR_LABEL_INDEX, "LABEL_INDEX" } }; static const int attr_str_max = array_size(attr_str); @@ -2315,7 +2316,7 @@ bgp_attr_label_index (struct bgp_attr_parser_args *args, struct bgp_nlri *mp_upd * Ignore the Label index attribute unless received for labeled-unicast * SAFI. We reset the flag, though it is probably unnecesary. */ - if (!mp_update->length || mp_update->afi != SAFI_LABELED_UNICAST) + if (!mp_update->length || mp_update->safi != SAFI_LABELED_UNICAST) { attr->extra->label_index = BGP_INVALID_LABEL_INDEX; attr->flag &= ~ATTR_FLAG_BIT(BGP_ATTR_LABEL_INDEX); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 140003cef0..88147e2b68 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -7653,33 +7653,28 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (binfo->extra && binfo->extra->damp_info) bgp_damp_info_vty (vty, binfo, json_path); + /* Label information */ if ((bgp_labeled_safi(safi) && binfo->extra) || (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)))) { - if (!json_paths) - vty_out (vty, "%s ", VTY_NEWLINE); - if (bgp_labeled_safi(safi) && binfo->extra) { uint32_t label = label_pton(binfo->extra->tag); if (json_paths) - json_object_int_add(json_path, "remote-label", label); + json_object_int_add(json_path, "remoteLabel", label); else - vty_out(vty, "Remote label: %d, ", label); + vty_out(vty, " Remote label: %d%s", label, VTY_NEWLINE); } if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))) { if (json_paths) - json_object_int_add(json_path, "label-index", attr->extra->label_index); + json_object_int_add(json_path, "labelIndex", attr->extra->label_index); else - vty_out(vty, "Label Index: %d", attr->extra->label_index); + vty_out(vty, " Label Index: %d%s", attr->extra->label_index, VTY_NEWLINE); } } - if (!json_paths) - vty_out (vty, "%s", VTY_NEWLINE); - /* Line 8 display Addpath IDs */ if (binfo->addpath_rx_id || binfo->addpath_tx_id) { From 8399fd9d36f46ae8f30ea8850b2eb1e50329c2a6 Mon Sep 17 00:00:00 2001 From: Hung-Wei Chiu Date: Thu, 27 Apr 2017 11:10:36 +0800 Subject: [PATCH 39/55] Update Building_FRR_on_Ubuntu1604.md 1. Modify the configure prefix (since there some hard coded path in **/usr/lib/frr/fr** 2. Install the systemd service config --- doc/Building_FRR_on_Ubuntu1604.md | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/doc/Building_FRR_on_Ubuntu1604.md b/doc/Building_FRR_on_Ubuntu1604.md index b213a90858..b3bcdf9f96 100644 --- a/doc/Building_FRR_on_Ubuntu1604.md +++ b/doc/Building_FRR_on_Ubuntu1604.md @@ -39,6 +39,7 @@ an example.) git checkout stable/2.0 ./bootstrap.sh ./configure \ + --prefix=/usr \ --enable-exampledir=/usr/share/doc/frr/examples/ \ --localstatedir=/var/run/frr \ --sbindir=/usr/lib/frr \ @@ -111,3 +112,39 @@ Add the following lines to `/etc/modules-load.d/modules.conf`: mpls-iptunnel **Reboot** or use `sysctl -p` to apply the same config to the running system + + +### Install The Systemd Service + + sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service + sudo install -m 644 cumulus/etc/default/frr /etc/default/frr + sudo install -m 644 cumulus/etc/frr/daemons /etc/frr/daemons + sudo install -m 644 cumulus/etc/frr/debian.conf /etc/frr/debian.conf + sudo install -m 644 cumulus/etc/frr/Frr.conf /etc/frr/Frr.conf + sudo install -m 644 -o frr -g frr cumulus/etc/frr/vtysh.conf /etc/frr/vtysh.conf + + +### Enable Daemons + +Edit `/etc/frr/daemons` and change the value from "no" to "yes" for those daemons you want to start by systemd. +For example. + + zebra=yes + bgpd=yes + ospfd=yes + ospf6d=yes + ripd=yes + ripngd=yes + isisd=yes + +### Enable the Systemd Serivce +Edit `/etc/systemd/system/frr.service` and remove the line **OnFailure=heartbeat-failed@%n.service** +For example. + + [Unit] + Description=Cumulus Linux FRR + After=syslog.target networking.service +     +### Start the Systemd Service +- systemctl start frr +- use `syttemctl status frr` to check its status. From 8a77d75b8ae54d1f52739d0689933e7a0d90fb72 Mon Sep 17 00:00:00 2001 From: Hung-Wei Chiu Date: Thu, 27 Apr 2017 11:22:15 +0800 Subject: [PATCH 40/55] Update Building_FRR_on_Ubuntu1604.md Fix typo --- doc/Building_FRR_on_Ubuntu1604.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/doc/Building_FRR_on_Ubuntu1604.md b/doc/Building_FRR_on_Ubuntu1604.md index b3bcdf9f96..7848ff68ab 100644 --- a/doc/Building_FRR_on_Ubuntu1604.md +++ b/doc/Building_FRR_on_Ubuntu1604.md @@ -114,7 +114,7 @@ Add the following lines to `/etc/modules-load.d/modules.conf`: **Reboot** or use `sysctl -p` to apply the same config to the running system -### Install The Systemd Service +### Install the systemd service sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service sudo install -m 644 cumulus/etc/default/frr /etc/default/frr @@ -123,8 +123,7 @@ Add the following lines to `/etc/modules-load.d/modules.conf`: sudo install -m 644 cumulus/etc/frr/Frr.conf /etc/frr/Frr.conf sudo install -m 644 -o frr -g frr cumulus/etc/frr/vtysh.conf /etc/frr/vtysh.conf - -### Enable Daemons +### Enable daemons Edit `/etc/frr/daemons` and change the value from "no" to "yes" for those daemons you want to start by systemd. For example. @@ -137,7 +136,7 @@ For example. ripngd=yes isisd=yes -### Enable the Systemd Serivce +### Enable the systemd serivce Edit `/etc/systemd/system/frr.service` and remove the line **OnFailure=heartbeat-failed@%n.service** For example. @@ -145,6 +144,6 @@ For example. Description=Cumulus Linux FRR After=syslog.target networking.service     -### Start the Systemd Service +### Start the systemd service - systemctl start frr -- use `syttemctl status frr` to check its status. +- use `systemctl status frr` to check its status. From af7e63a35774771ad87e7a25c2a3a08a3a7128af Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 27 Apr 2017 08:56:15 -0300 Subject: [PATCH 41/55] ldpd: fix issues detected by Coverity Scan Signed-off-by: Renato Westphal --- ldpd/lde.c | 10 ++-------- ldpd/ldpe.c | 10 ++-------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/ldpd/lde.c b/ldpd/lde.c index 25f7178b6b..859d47431b 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -80,10 +80,6 @@ static zebra_capabilities_t _caps_p [] = static struct zebra_privs_t lde_privs = { -#if defined(FRR_USER) && defined(FRR_GROUP) - .user = FRR_USER, - .group = FRR_GROUP, -#endif #if defined(VTY_GROUP) .vty_group = VTY_GROUP, #endif @@ -164,10 +160,8 @@ void lde_init(struct ldpd_init *init) { /* drop privileges */ - if (init->user) - lde_privs.user = init->user; - if (init->group) - lde_privs.group = init->group; + lde_privs.user = init->user; + lde_privs.group = init->group; zprivs_init(&lde_privs); #ifdef HAVE_PLEDGE diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 20cc9f7444..017eec2502 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -66,10 +66,6 @@ static zebra_capabilities_t _caps_p [] = struct zebra_privs_t ldpe_privs = { -#if defined(FRR_USER) && defined(FRR_GROUP) - .user = FRR_USER, - .group = FRR_GROUP, -#endif #if defined(VTY_GROUP) .vty_group = VTY_GROUP, #endif @@ -143,10 +139,8 @@ void ldpe_init(struct ldpd_init *init) { /* drop privileges */ - if (init->user) - ldpe_privs.user = init->user; - if (init->group) - ldpe_privs.group = init->group; + ldpe_privs.user = init->user; + ldpe_privs.group = init->group; zprivs_init(&ldpe_privs); /* listen on ldpd control socket */ From 795c08fc9e07a316731e1a78123c67378458a661 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 27 Apr 2017 12:42:56 +0200 Subject: [PATCH 42/55] isisd: function lsp_te_tlv_fit is never used Signed-off-by: Christian Franke --- isisd/isis_lsp.c | 58 ------------------------------------------------ isisd/isis_lsp.h | 2 -- 2 files changed, 60 deletions(-) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index f633a8fb78..d490bc47cd 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1085,64 +1085,6 @@ lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, return; } -/* Process IS_NEIGHBOURS TLV with TE subTLVs */ -void -lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, int frag_thold) -{ - int count, size = 0; - struct listnode *node, *nextnode; - struct te_is_neigh *elem; - - /* Start computing real size of TLVs */ - for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem)) - size = size + elem->sub_tlvs_length + IS_NEIGHBOURS_LEN; - - /* can we fit all ? */ - if (!FRAG_NEEDED (lsp->pdu, frag_thold, size)) - { - tlv_add_te_is_neighs (*from, lsp->pdu); - if (listcount (*to) != 0) - { - for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem)) - { - listnode_add (*to, elem); - list_delete_node (*from, node); - } - } - else - { - list_free (*to); - *to = *from; - *from = NULL; - } - } - else - { - /* fit all we can */ - /* Compute remaining place in LSP PDU */ - count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 - - (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu)); - /* Determine size of TE SubTLVs */ - elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from)); - count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN; - if (count > 0) - { - while (count > 0) - { - listnode_add (*to, listgetdata ((struct listnode *)listhead (*from))); - listnode_delete (*from, listgetdata ((struct listnode *)listhead (*from))); - - elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from)); - count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN; - } - - tlv_add_te_is_neighs (*to, lsp->pdu); - } - } - lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); - return; -} - static u_int16_t lsp_rem_lifetime (struct isis_area *area, int level) { diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index 24fae57a7b..6f697df62c 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -108,8 +108,6 @@ void lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost); int lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost); const char *lsp_bits2string (u_char *); -void lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from, - struct list **to, int frag_thold); /* sets SRMflags for all active circuits of an lsp */ void lsp_set_all_srmflags (struct isis_lsp *lsp); From 1b49e4f0ba4073821701cb339bde94055d3b5786 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 27 Apr 2017 12:54:21 +0200 Subject: [PATCH 43/55] isisd: do some cleanup on the spf implementation Signed-off-by: Christian Franke --- isisd/isis_spf.c | 637 ++++++++++++++++------------------------------- isisd/isis_spf.h | 9 +- 2 files changed, 226 insertions(+), 420 deletions(-) diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 554fa563ad..8dd1dc981f 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -5,6 +5,7 @@ * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering + * Copyright (C) 2017 Christian Franke * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free @@ -51,6 +52,13 @@ #include "isis_route.h" #include "isis_csm.h" +DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info"); + +struct isis_spf_run { + struct isis_area *area; + int level; +}; + /* 7.2.7 */ static void remove_excess_adjs (struct list *adjs) @@ -142,35 +150,24 @@ vtype2string (enum vertextype vtype) default: return "UNKNOWN"; } - return NULL; /* Not reached */ + return NULL; /* Not reached */ } static const char * vid2string (struct isis_vertex *vertex, char * buff, int size) { - switch (vertex->type) + if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type)) { - case VTYPE_PSEUDO_IS: - case VTYPE_PSEUDO_TE_IS: return print_sys_hostname (vertex->N.id); - break; - case VTYPE_NONPSEUDO_IS: - case VTYPE_NONPSEUDO_TE_IS: - case VTYPE_ES: - return print_sys_hostname (vertex->N.id); - break; - case VTYPE_IPREACH_INTERNAL: - case VTYPE_IPREACH_EXTERNAL: - case VTYPE_IPREACH_TE: - case VTYPE_IP6REACH_INTERNAL: - case VTYPE_IP6REACH_EXTERNAL: - prefix2str ((struct prefix *) &vertex->N.prefix, buff, size); - break; - default: - return "UNKNOWN"; } - return (char *) buff; + if (VTYPE_IP(vertex->type)) + { + prefix2str ((struct prefix *) &vertex->N.prefix, buff, size); + return buff; + } + + return "UNKNOWN"; } static struct isis_vertex * @@ -181,26 +178,17 @@ isis_vertex_new (void *id, enum vertextype vtype) vertex = XCALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex)); vertex->type = vtype; - switch (vtype) + + if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) { - case VTYPE_ES: - case VTYPE_NONPSEUDO_IS: - case VTYPE_NONPSEUDO_TE_IS: - memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN); - break; - case VTYPE_PSEUDO_IS: - case VTYPE_PSEUDO_TE_IS: memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1); - break; - case VTYPE_IPREACH_INTERNAL: - case VTYPE_IPREACH_EXTERNAL: - case VTYPE_IPREACH_TE: - case VTYPE_IP6REACH_INTERNAL: - case VTYPE_IP6REACH_EXTERNAL: - memcpy (&vertex->N.prefix, (struct prefix *) id, - sizeof (struct prefix)); - break; - default: + } + else if (VTYPE_IP(vtype)) + { + memcpy (&vertex->N.prefix, (struct prefix *) id, sizeof (struct prefix)); + } + else + { zlog_err ("WTF!"); } @@ -280,7 +268,7 @@ isis_spftree_del (struct isis_spftree *spftree) return; } -void +static void isis_spftree_adj_del (struct isis_spftree *spftree, struct isis_adjacency *adj) { struct listnode *node; @@ -394,23 +382,24 @@ isis_root_system_lsp (struct isis_area *area, int level, u_char *sysid) * Add this IS to the root of SPT */ static struct isis_vertex * -isis_spf_add_root (struct isis_spftree *spftree, int level, u_char *sysid) +isis_spf_add_root (struct isis_spftree *spftree, u_char *sysid) { struct isis_vertex *vertex; struct isis_lsp *lsp; #ifdef EXTREME_DEBUG char buff[PREFIX2STR_BUFFER]; #endif /* EXTREME_DEBUG */ + u_char id[ISIS_SYS_ID_LEN + 1]; - lsp = isis_root_system_lsp (spftree->area, level, sysid); + memcpy(id, sysid, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID(id) = 0; + + lsp = isis_root_system_lsp (spftree->area, spftree->level, sysid); if (lsp == NULL) - zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level); - - if (!spftree->area->oldmetric) - vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_TE_IS); - else - vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_IS); + zlog_warn ("ISIS-Spf: could not find own l%d LSP!", spftree->level); + vertex = isis_vertex_new (id, spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS + : VTYPE_NONPSEUDO_TE_IS); listnode_add (spftree->paths, vertex); #ifdef EXTREME_DEBUG @@ -432,44 +421,51 @@ isis_find_vertex (struct list *list, void *id, enum vertextype vtype) for (ALL_LIST_ELEMENTS_RO (list, node, vertex)) { if (vertex->type != vtype) - continue; - switch (vtype) - { - case VTYPE_ES: - case VTYPE_NONPSEUDO_IS: - case VTYPE_NONPSEUDO_TE_IS: - if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN) == 0) - return vertex; - break; - case VTYPE_PSEUDO_IS: - case VTYPE_PSEUDO_TE_IS: - if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN + 1) == 0) - return vertex; - break; - case VTYPE_IPREACH_INTERNAL: - case VTYPE_IPREACH_EXTERNAL: - case VTYPE_IPREACH_TE: - case VTYPE_IP6REACH_INTERNAL: - case VTYPE_IP6REACH_EXTERNAL: - p1 = (struct prefix *) id; - p2 = (struct prefix *) &vertex->N.id; - if (p1->family == p2->family && p1->prefixlen == p2->prefixlen && - memcmp (&p1->u.prefix, &p2->u.prefix, - PSIZE (p1->prefixlen)) == 0) - return vertex; - break; - } + continue; + if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type)) + { + if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN + 1) == 0) + return vertex; + } + if (VTYPE_IP(vertex->type)) + { + p1 = (struct prefix *) id; + p2 = (struct prefix *) &vertex->N.id; + if (p1->family == p2->family + && p1->prefixlen == p2->prefixlen + && !memcmp(&p1->u.prefix, &p2->u.prefix, PSIZE (p1->prefixlen))) + { + return vertex; + } + } } return NULL; } +/* + * Compares vertizes for sorting in the TENT list. Returns true + * if candidate should be considered before current, false otherwise. + */ +static bool +tent_cmp (struct isis_vertex *current, struct isis_vertex *candidate) +{ + if (current->d_N > candidate->d_N) + return true; + + if (current->d_N == candidate->d_N + && current->type > candidate->type) + return true; + + return false; +} + /* * Add a vertex to TENT sorted by cost and by vertextype on tie break situation */ static struct isis_vertex * isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype, - void *id, uint32_t cost, int depth, int family, + void *id, uint32_t cost, int depth, struct isis_adjacency *adj, struct isis_vertex *parent) { struct isis_vertex *vertex, *v; @@ -515,17 +511,11 @@ isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype, for (node = listhead (spftree->tents); node; node = listnextnode (node)) { v = listgetdata (node); - if (v->d_N > vertex->d_N) - { - listnode_add_before (spftree->tents, node, vertex); - break; - } - else if (v->d_N == vertex->d_N && v->type > vertex->type) - { - /* Tie break, add according to type */ + if (tent_cmp(v, vertex)) + { listnode_add_before (spftree->tents, node, vertex); - break; - } + break; + } } if (node == NULL) @@ -537,7 +527,7 @@ isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype, static void isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype, void *id, struct isis_adjacency *adj, uint32_t cost, - int family, struct isis_vertex *parent) + struct isis_vertex *parent) { struct isis_vertex *vertex; @@ -576,13 +566,13 @@ isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype, } } - isis_spf_add2tent (spftree, vtype, id, cost, 1, family, adj, parent); + isis_spf_add2tent (spftree, vtype, id, cost, 1, adj, parent); return; } static void process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id, - uint32_t dist, uint16_t depth, int family, + uint32_t dist, uint16_t depth, struct isis_vertex *parent) { struct isis_vertex *vertex; @@ -670,7 +660,7 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id, (parent ? print_sys_hostname (parent->N.id) : "null")); #endif /* EXTREME_DEBUG */ - isis_spf_add2tent (spftree, vtype, id, dist, depth, family, NULL, parent); + isis_spf_add2tent (spftree, vtype, id, dist, depth, NULL, parent); return; } @@ -679,9 +669,10 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id, */ static int isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, - uint32_t cost, uint16_t depth, int family, + uint32_t cost, uint16_t depth, u_char *root_sysid, struct isis_vertex *parent) { + bool pseudo_lsp = LSP_PSEUDO_ID(lsp->lsp_header->lsp_id); struct listnode *node, *fragnode = NULL; uint32_t dist; struct is_neigh *is_neigh; @@ -693,7 +684,7 @@ isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, struct ipv6_reachability *ip6reach; static const u_char null_sysid[ISIS_SYS_ID_LEN]; - if (!speaks (lsp->tlv_data.nlpids, family)) + if (!pseudo_lsp && !speaks (lsp->tlv_data.nlpids, spftree->family)) return ISIS_OK; lspfragloop: @@ -707,7 +698,8 @@ lspfragloop: zlog_debug ("ISIS-Spf: process_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id)); #endif /* EXTREME_DEBUG */ - if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits)) + /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */ + if (pseudo_lsp || !ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits)) { if (lsp->tlv_data.is_neighs) { @@ -717,13 +709,12 @@ lspfragloop: /* Two way connectivity */ if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) continue; - if (!memcmp (is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN)) + if (!pseudo_lsp && !memcmp (is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN)) continue; dist = cost + is_neigh->metrics.metric_default; - vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS - : VTYPE_NONPSEUDO_IS; - process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist, - depth + 1, family, parent); + process_N (spftree, LSP_PSEUDO_ID(is_neigh->neigh_id) ? VTYPE_PSEUDO_IS + : VTYPE_NONPSEUDO_IS, + (void *) is_neigh->neigh_id, dist, depth + 1, parent); } } if (lsp->tlv_data.te_is_neighs) @@ -733,64 +724,53 @@ lspfragloop: { if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) continue; - if (!memcmp (te_is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN)) + if (!pseudo_lsp && !memcmp (te_is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN)) continue; dist = cost + GET_TE_METRIC(te_is_neigh); - vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS - : VTYPE_NONPSEUDO_TE_IS; - process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist, - depth + 1, family, parent); + process_N (spftree, LSP_PSEUDO_ID(te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS + : VTYPE_NONPSEUDO_TE_IS, + (void *) te_is_neigh->neigh_id, dist, depth + 1, parent); } } } - if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs) - { - prefix.family = AF_INET; - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, node, ipreach)) - { - dist = cost + ipreach->metrics.metric_default; - vtype = VTYPE_IPREACH_INTERNAL; - prefix.u.prefix4 = ipreach->prefix; - prefix.prefixlen = ip_masklen (ipreach->mask); - apply_mask (&prefix); - process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, - family, parent); - } - } - if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs) - { - prefix.family = AF_INET; - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, node, ipreach)) - { - dist = cost + ipreach->metrics.metric_default; - vtype = VTYPE_IPREACH_EXTERNAL; - prefix.u.prefix4 = ipreach->prefix; - prefix.prefixlen = ip_masklen (ipreach->mask); - apply_mask (&prefix); - process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, - family, parent); - } - } - if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs) + if (!pseudo_lsp && spftree->family == AF_INET) { + struct list *reachs[] = {lsp->tlv_data.ipv4_int_reachs, + lsp->tlv_data.ipv4_ext_reachs}; + prefix.family = AF_INET; + for (unsigned int i = 0; i < array_size(reachs); i++) + { + vtype = (reachs[i] == lsp->tlv_data.ipv4_int_reachs) ? VTYPE_IPREACH_INTERNAL + : VTYPE_IPREACH_EXTERNAL; + for (ALL_LIST_ELEMENTS_RO (reachs[i], node, ipreach)) + { + dist = cost + ipreach->metrics.metric_default; + prefix.u.prefix4 = ipreach->prefix; + prefix.prefixlen = ip_masklen (ipreach->mask); + apply_mask (&prefix); + process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, + parent); + } + } + for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, node, te_ipv4_reach)) { assert ((te_ipv4_reach->control & 0x3F) <= IPV4_MAX_BITLEN); dist = cost + ntohl (te_ipv4_reach->te_metric); - vtype = VTYPE_IPREACH_TE; prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start, te_ipv4_reach->control); prefix.prefixlen = (te_ipv4_reach->control & 0x3F); apply_mask (&prefix); - process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, - family, parent); + process_N (spftree, VTYPE_IPREACH_TE, (void *) &prefix, dist, depth + 1, + parent); } } - if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs) + + if (!pseudo_lsp && spftree->family == AF_INET6) { prefix.family = AF_INET6; for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, node, ip6reach)) @@ -799,13 +779,13 @@ lspfragloop: dist = cost + ntohl(ip6reach->metric); vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ? - VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL; + VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL; prefix.prefixlen = ip6reach->prefix_len; memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix, PSIZE (ip6reach->prefix_len)); apply_mask (&prefix); process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, - family, parent); + parent); } } @@ -824,76 +804,8 @@ lspfragloop: } static int -isis_spf_process_pseudo_lsp (struct isis_spftree *spftree, - struct isis_lsp *lsp, uint32_t cost, - uint16_t depth, int family, - u_char *root_sysid, - struct isis_vertex *parent) -{ - struct listnode *node, *fragnode = NULL; - struct is_neigh *is_neigh; - struct te_is_neigh *te_is_neigh; - enum vertextype vtype; - uint32_t dist; - -pseudofragloop: - - if (lsp->lsp_header->seq_num == 0) - { - zlog_warn ("isis_spf_process_pseudo_lsp(): lsp with 0 seq_num" - " - do not process"); - return ISIS_WARNING; - } - -#ifdef EXTREME_DEBUG - zlog_debug ("ISIS-Spf: process_pseudo_lsp %s", - print_sys_hostname(lsp->lsp_header->lsp_id)); -#endif /* EXTREME_DEBUG */ - - /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */ - - if (lsp->tlv_data.is_neighs) - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh)) - { - /* Two way connectivity */ - if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) - continue; - dist = cost + is_neigh->metrics.metric_default; - vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS - : VTYPE_NONPSEUDO_IS; - process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist, - depth + 1, family, parent); - } - if (lsp->tlv_data.te_is_neighs) - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, te_is_neigh)) - { - /* Two way connectivity */ - if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) - continue; - dist = cost + GET_TE_METRIC(te_is_neigh); - vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS - : VTYPE_NONPSEUDO_TE_IS; - process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist, - depth + 1, family, parent); - } - - if (fragnode == NULL) - fragnode = listhead (lsp->lspu.frags); - else - fragnode = listnextnode (fragnode); - - if (fragnode) - { - lsp = listgetdata (fragnode); - goto pseudofragloop; - } - - return ISIS_OK; -} - -static int -isis_spf_preload_tent (struct isis_spftree *spftree, int level, - int family, u_char *root_sysid, +isis_spf_preload_tent (struct isis_spftree *spftree, + u_char *root_sysid, struct isis_vertex *parent) { struct isis_circuit *circuit; @@ -913,16 +825,16 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level, { if (circuit->state != C_STATE_UP) continue; - if (!(circuit->is_type & level)) + if (!(circuit->is_type & spftree->level)) continue; - if (family == AF_INET && !circuit->ip_router) + if (spftree->family == AF_INET && !circuit->ip_router) continue; - if (family == AF_INET6 && !circuit->ipv6_router) + if (spftree->family == AF_INET6 && !circuit->ipv6_router) continue; /* * Add IP(v6) addresses of this circuit */ - if (family == AF_INET) + if (spftree->family == AF_INET) { prefix.family = AF_INET; for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4)) @@ -931,10 +843,10 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level, prefix.prefixlen = ipv4->prefixlen; apply_mask (&prefix); isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix, - NULL, 0, family, parent); + NULL, 0, parent); } } - if (family == AF_INET6) + if (spftree->family == AF_INET6) { prefix.family = AF_INET6; for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6)) @@ -943,7 +855,7 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level, prefix.u.prefix6 = ipv6->prefix; apply_mask (&prefix); isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL, - &prefix, NULL, 0, family, parent); + &prefix, NULL, 0, parent); } } if (circuit->circ_type == CIRCUIT_T_BROADCAST) @@ -952,45 +864,44 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level, * Add the adjacencies */ adj_list = list_new (); - adjdb = circuit->u.bc.adjdb[level - 1]; + adjdb = circuit->u.bc.adjdb[spftree->level - 1]; isis_adj_build_up_list (adjdb, adj_list); if (listcount (adj_list) == 0) { list_delete (adj_list); if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf: no L%d adjacencies on circuit %s", - level, circuit->interface->name); + spftree->level, circuit->interface->name); continue; } for (ALL_LIST_ELEMENTS_RO (adj_list, anode, adj)) { - if (!speaks (&adj->nlpids, family)) + if (!speaks (&adj->nlpids, spftree->family)) continue; switch (adj->sys_type) { case ISIS_SYSTYPE_ES: isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj, - circuit->te_metric[level - 1], - family, parent); + circuit->te_metric[spftree->level - 1], + parent); break; case ISIS_SYSTYPE_IS: case ISIS_SYSTYPE_L1_IS: case ISIS_SYSTYPE_L2_IS: - isis_spf_add_local (spftree, - spftree->area->oldmetric ? - VTYPE_NONPSEUDO_IS : - VTYPE_NONPSEUDO_TE_IS, - adj->sysid, adj, - circuit->te_metric[level - 1], - family, parent); memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (lsp_id) = 0; LSP_FRAGMENT (lsp_id) = 0; - lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]); + isis_spf_add_local (spftree, + spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS + : VTYPE_NONPSEUDO_TE_IS, + lsp_id, adj, + circuit->te_metric[spftree->level - 1], + parent); + lsp = lsp_search (lsp_id, spftree->area->lspdb[spftree->level - 1]); if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) zlog_warn ("ISIS-Spf: No LSP %s found for IS adjacency " "L%d on %s (ID %u)", - rawlspid_print (lsp_id), level, + rawlspid_print (lsp_id), spftree->level, circuit->interface->name, circuit->circuit_id); break; case ISIS_SYSTYPE_UNKNOWN: @@ -1002,7 +913,7 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level, /* * Add the pseudonode */ - if (level == 1) + if (spftree->level == 1) memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1); else memcpy (lsp_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); @@ -1011,31 +922,31 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level, { if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf: No L%d DR on %s (ID %d)", - level, circuit->interface->name, circuit->circuit_id); + spftree->level, circuit->interface->name, circuit->circuit_id); continue; } adj = isis_adj_lookup (lsp_id, adjdb); /* if no adj, we are the dis or error */ - if (!adj && !circuit->u.bc.is_dr[level - 1]) + if (!adj && !circuit->u.bc.is_dr[spftree->level - 1]) { zlog_warn ("ISIS-Spf: No adjacency found from root " "to L%d DR %s on %s (ID %d)", - level, rawlspid_print (lsp_id), + spftree->level, rawlspid_print (lsp_id), circuit->interface->name, circuit->circuit_id); continue; } - lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]); + lsp = lsp_search (lsp_id, spftree->area->lspdb[spftree->level - 1]); if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) { zlog_warn ("ISIS-Spf: No lsp (%p) found from root " "to L%d DR %s on %s (ID %d)", - (void *)lsp, level, rawlspid_print (lsp_id), + (void *)lsp, spftree->level, rawlspid_print (lsp_id), circuit->interface->name, circuit->circuit_id); continue; } - isis_spf_process_pseudo_lsp (spftree, lsp, - circuit->te_metric[level - 1], 0, - family, root_sysid, parent); + isis_spf_process_lsp (spftree, lsp, + circuit->te_metric[spftree->level - 1], 0, + root_sysid, parent); } else if (circuit->circ_type == CIRCUIT_T_P2P) { @@ -1046,20 +957,22 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level, { case ISIS_SYSTYPE_ES: isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj, - circuit->te_metric[level - 1], family, + circuit->te_metric[spftree->level - 1], parent); break; case ISIS_SYSTYPE_IS: case ISIS_SYSTYPE_L1_IS: case ISIS_SYSTYPE_L2_IS: - if (speaks (&adj->nlpids, family)) + memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID (lsp_id) = 0; + LSP_FRAGMENT (lsp_id) = 0; + if (speaks (&adj->nlpids, spftree->family)) isis_spf_add_local (spftree, - spftree->area->oldmetric ? - VTYPE_NONPSEUDO_IS : - VTYPE_NONPSEUDO_TE_IS, - adj->sysid, - adj, circuit->te_metric[level - 1], - family, parent); + spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS + : VTYPE_NONPSEUDO_TE_IS, + lsp_id, + adj, circuit->te_metric[spftree->level - 1], + parent); break; case ISIS_SYSTYPE_UNKNOWN: default: @@ -1086,8 +999,7 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level, * now we just put the child pointer(s) in place */ static void -add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex, - int level) +add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex) { char buff[PREFIX2STR_BUFFER]; @@ -1102,11 +1014,11 @@ add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex, vertex->depth, vertex->d_N); #endif /* EXTREME_DEBUG */ - if (vertex->type > VTYPE_ES) + if (VTYPE_IP(vertex->type)) { if (listcount (vertex->Adj_N) > 0) isis_route_create ((struct prefix *) &vertex->N.prefix, vertex->d_N, - vertex->depth, vertex->Adj_N, spftree->area, level); + vertex->depth, vertex->Adj_N, spftree->area, spftree->level); else if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf: no adjacencies do not install route for " "%s depth %d dist %d", vid2string (vertex, buff, sizeof (buff)), @@ -1117,12 +1029,15 @@ add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex, } static void -init_spt (struct isis_spftree *spftree) +init_spt (struct isis_spftree *spftree, int level, int family) { spftree->tents->del = spftree->paths->del = (void (*)(void *)) isis_vertex_del; list_delete_all_node (spftree->tents); list_delete_all_node (spftree->paths); spftree->tents->del = spftree->paths->del = NULL; + + spftree->level = level; + spftree->family = family; return; } @@ -1163,11 +1078,11 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid) /* * C.2.5 Step 0 */ - init_spt (spftree); + init_spt (spftree, level, family); /* a) */ - root_vertex = isis_spf_add_root (spftree, level, sysid); + root_vertex = isis_spf_add_root (spftree, sysid); /* b) */ - retval = isis_spf_preload_tent (spftree, level, family, sysid, root_vertex); + retval = isis_spf_preload_tent (spftree, sysid, root_vertex); if (retval != ISIS_OK) { zlog_warn ("ISIS-Spf: failed to load TENT SPF-root:%s", print_sys_hostname(sysid)); @@ -1196,37 +1111,22 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid) /* Remove from tent list and add to paths list */ list_delete_node (spftree->tents, node); - add_to_paths (spftree, vertex, level); - switch (vertex->type) + add_to_paths (spftree, vertex); + if (VTYPE_IS(vertex->type)) { - case VTYPE_PSEUDO_IS: - case VTYPE_NONPSEUDO_IS: - case VTYPE_PSEUDO_TE_IS: - case VTYPE_NONPSEUDO_TE_IS: memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT (lsp_id) = 0; lsp = lsp_search (lsp_id, area->lspdb[level - 1]); if (lsp && lsp->lsp_header->rem_lifetime != 0) { - if (LSP_PSEUDO_ID (lsp_id)) - { - isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N, - vertex->depth, family, sysid, - vertex); - } - else - { - isis_spf_process_lsp (spftree, lsp, vertex->d_N, - vertex->depth, family, sysid, vertex); - } + isis_spf_process_lsp (spftree, lsp, vertex->d_N, + vertex->depth, sysid, vertex); } else { zlog_warn ("ISIS-Spf: No LSP found for %s", rawlspid_print (lsp_id)); } - break; - default:; } } @@ -1243,17 +1143,17 @@ out: } static int -isis_run_spf_l1 (struct thread *thread) +isis_run_spf_cb (struct thread *thread) { - struct isis_area *area; + struct isis_spf_run *run = THREAD_ARG (thread); + struct isis_area *area = run->area; + int level = run->level; int retval = ISIS_OK; - area = THREAD_ARG (thread); - assert (area); + XFREE(MTYPE_ISIS_SPF_RUN, run); + area->spf_timer[level - 1] = NULL; - area->spf_timer[0] = NULL; - - if (!(area->is_type & IS_LEVEL_1)) + if (!(area->is_type & level)) { if (isis->debugs & DEBUG_SPF_EVENTS) zlog_warn ("ISIS-SPF (%s) area does not share level", @@ -1262,43 +1162,26 @@ isis_run_spf_l1 (struct thread *thread) } if (isis->debugs & DEBUG_SPF_EVENTS) - zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag); + zlog_debug ("ISIS-Spf (%s) L%d SPF needed, periodic SPF", + area->area_tag, level); if (area->ip_circuits) - retval = isis_run_spf (area, 1, AF_INET, isis->sysid); + retval = isis_run_spf (area, level, AF_INET, isis->sysid); if (area->ipv6_circuits) - retval = isis_run_spf (area, 1, AF_INET6, isis->sysid); + retval = isis_run_spf (area, level, AF_INET6, isis->sysid); return retval; } -static int -isis_run_spf_l2 (struct thread *thread) +static struct isis_spf_run* +isis_run_spf_arg(struct isis_area *area, int level) { - struct isis_area *area; - int retval = ISIS_OK; + struct isis_spf_run *run = XMALLOC(MTYPE_ISIS_SPF_RUN, sizeof(*run)); - area = THREAD_ARG (thread); - assert (area); + run->area = area; + run->level = level; - area->spf_timer[1] = NULL; - - if (!(area->is_type & IS_LEVEL_2)) - { - if (isis->debugs & DEBUG_SPF_EVENTS) - zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag); - return ISIS_WARNING; - } - - if (isis->debugs & DEBUG_SPF_EVENTS) - zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag); - - if (area->ip_circuits) - retval = isis_run_spf (area, 2, AF_INET, isis->sysid); - if (area->ipv6_circuits) - retval = isis_run_spf (area, 2, AF_INET6, isis->sysid); - - return retval; + return run; } int @@ -1323,16 +1206,9 @@ isis_spf_schedule (struct isis_area *area, int level) if (area->spf_timer[level - 1]) return ISIS_OK; - if (level == 1) - { - THREAD_TIMER_MSEC_ON(master, area->spf_timer[0], - isis_run_spf_l1, area, delay); - } - else - { - THREAD_TIMER_MSEC_ON(master, area->spf_timer[1], - isis_run_spf_l2, area, delay); - } + THREAD_TIMER_MSEC_ON(master, area->spf_timer[level-1], + isis_run_spf_cb, isis_run_spf_arg(area, level), + delay); return ISIS_OK; } @@ -1352,12 +1228,9 @@ isis_spf_schedule (struct isis_area *area, int level) return retval; } - if (level == 1) - THREAD_TIMER_ON (master, area->spf_timer[0], isis_run_spf_l1, area, - area->min_spf_interval[0] - diff); - else - THREAD_TIMER_ON (master, area->spf_timer[1], isis_run_spf_l2, area, - area->min_spf_interval[1] - diff); + THREAD_TIMER_ON (master, area->spf_timer[level-1], + isis_run_spf_cb, isis_run_spf_arg(area, level), + area->min_spf_interval[level-1] - diff); if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now", @@ -1427,14 +1300,23 @@ isis_print_paths (struct vty *vty, struct list *paths, u_char *root_sysid) DEFUN (show_isis_topology, show_isis_topology_cmd, - "show isis topology", + "show isis topology []", SHOW_STR "IS-IS information\n" - "IS-IS paths to Intermediate Systems\n") + "IS-IS paths to Intermediate Systems\n" + "Paths to all level-1 routers in the area\n" + "Paths to all level-2 routers in the domain\n") { + int levels; struct listnode *node; struct isis_area *area; - int level; + + if (argc < 4) + levels = ISIS_LEVEL1|ISIS_LEVEL2; + else if (!strcmp(argv[3]->arg, "level-1")) + levels = ISIS_LEVEL1; + else + levels = ISIS_LEVEL2; if (!isis->area_list || isis->area_list->count == 0) return CMD_SUCCESS; @@ -1444,23 +1326,26 @@ DEFUN (show_isis_topology, vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null", VTY_NEWLINE); - for (level = 0; level < ISIS_LEVELS; level++) + for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { - if (area->ip_circuits > 0 && area->spftree[level] - && area->spftree[level]->paths->count > 0) + if ((level & levels) == 0) + continue; + + if (area->ip_circuits > 0 && area->spftree[level-1] + && area->spftree[level-1]->paths->count > 0) { vty_out (vty, "IS-IS paths to level-%d routers that speak IP%s", - level + 1, VTY_NEWLINE); - isis_print_paths (vty, area->spftree[level]->paths, isis->sysid); + level, VTY_NEWLINE); + isis_print_paths (vty, area->spftree[level-1]->paths, isis->sysid); vty_out (vty, "%s", VTY_NEWLINE); } - if (area->ipv6_circuits > 0 && area->spftree6[level] - && area->spftree6[level]->paths->count > 0) + if (area->ipv6_circuits > 0 && area->spftree6[level-1] + && area->spftree6[level-1]->paths->count > 0) { vty_out (vty, "IS-IS paths to level-%d routers that speak IPv6%s", - level + 1, VTY_NEWLINE); - isis_print_paths (vty, area->spftree6[level]->paths, isis->sysid); + level, VTY_NEWLINE); + isis_print_paths (vty, area->spftree6[level-1]->paths, isis->sysid); vty_out (vty, "%s", VTY_NEWLINE); } } @@ -1471,92 +1356,8 @@ DEFUN (show_isis_topology, return CMD_SUCCESS; } -DEFUN (show_isis_topology_l1, - show_isis_topology_l1_cmd, - "show isis topology level-1", - SHOW_STR - "IS-IS information\n" - "IS-IS paths to Intermediate Systems\n" - "Paths to all level-1 routers in the area\n") -{ - struct listnode *node; - struct isis_area *area; - - if (!isis->area_list || isis->area_list->count == 0) - return CMD_SUCCESS; - - for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) - { - vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null", - VTY_NEWLINE); - - if (area->ip_circuits > 0 && area->spftree[0] - && area->spftree[0]->paths->count > 0) - { - vty_out (vty, "IS-IS paths to level-1 routers that speak IP%s", - VTY_NEWLINE); - isis_print_paths (vty, area->spftree[0]->paths, isis->sysid); - vty_out (vty, "%s", VTY_NEWLINE); - } - if (area->ipv6_circuits > 0 && area->spftree6[0] - && area->spftree6[0]->paths->count > 0) - { - vty_out (vty, "IS-IS paths to level-1 routers that speak IPv6%s", - VTY_NEWLINE); - isis_print_paths (vty, area->spftree6[0]->paths, isis->sysid); - vty_out (vty, "%s", VTY_NEWLINE); - } - vty_out (vty, "%s", VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - -DEFUN (show_isis_topology_l2, - show_isis_topology_l2_cmd, - "show isis topology level-2", - SHOW_STR - "IS-IS information\n" - "IS-IS paths to Intermediate Systems\n" - "Paths to all level-2 routers in the domain\n") -{ - struct listnode *node; - struct isis_area *area; - - if (!isis->area_list || isis->area_list->count == 0) - return CMD_SUCCESS; - - for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) - { - vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null", - VTY_NEWLINE); - - if (area->ip_circuits > 0 && area->spftree[1] - && area->spftree[1]->paths->count > 0) - { - vty_out (vty, "IS-IS paths to level-2 routers that speak IP%s", - VTY_NEWLINE); - isis_print_paths (vty, area->spftree[1]->paths, isis->sysid); - vty_out (vty, "%s", VTY_NEWLINE); - } - if (area->ipv6_circuits > 0 && area->spftree6[1] - && area->spftree6[1]->paths->count > 0) - { - vty_out (vty, "IS-IS paths to level-2 routers that speak IPv6%s", - VTY_NEWLINE); - isis_print_paths (vty, area->spftree6[1]->paths, isis->sysid); - vty_out (vty, "%s", VTY_NEWLINE); - } - vty_out (vty, "%s", VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - void isis_spf_cmds_init () { install_element (VIEW_NODE, &show_isis_topology_cmd); - install_element (VIEW_NODE, &show_isis_topology_l1_cmd); - install_element (VIEW_NODE, &show_isis_topology_l2_cmd); } diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index fb534542d0..64582c62c9 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -38,6 +38,10 @@ enum vertextype VTYPE_IP6REACH_EXTERNAL }; +#define VTYPE_IS(t) ((t) >= VTYPE_PSEUDO_IS && (t) <= VTYPE_NONPSEUDO_TE_IS) +#define VTYPE_ES(t) ((t) == VTYPE_ES) +#define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL) + /* * Triple */ @@ -66,12 +70,13 @@ struct isis_spftree unsigned int runcount; /* number of runs since uptime */ time_t last_run_timestamp; /* last run timestamp for scheduling */ time_t last_run_duration; /* last run duration in msec */ + + int family; + int level; }; struct isis_spftree * isis_spftree_new (struct isis_area *area); void isis_spftree_del (struct isis_spftree *spftree); -void isis_spftree_adj_del (struct isis_spftree *spftree, - struct isis_adjacency *adj); void spftree_area_init (struct isis_area *area); void spftree_area_del (struct isis_area *area); void spftree_area_adj_del (struct isis_area *area, From 316a98ecd151dfba86a4a87e11c98cb2a0e94518 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 27 Apr 2017 12:56:11 +0200 Subject: [PATCH 44/55] isisd: implement draft-ietf-isis-ext-eth and support p2p over LAN on BSD Signed-off-by: Christian Franke --- isisd/isis_bpf.c | 33 +++------------------------------ isisd/isis_constants.h | 10 ++++++++++ isisd/isis_pfpacket.c | 5 +++-- 3 files changed, 16 insertions(+), 32 deletions(-) diff --git a/isisd/isis_bpf.c b/isisd/isis_bpf.c index 3a5eaf5585..0a1610b6f2 100644 --- a/isisd/isis_bpf.c +++ b/isisd/isis_bpf.c @@ -212,16 +212,11 @@ isis_sock_init (struct isis_circuit *circuit) goto end; } - if (circuit->circ_type == CIRCUIT_T_BROADCAST) + if (if_is_broadcast(circuit->interface)) { circuit->tx = isis_send_pdu_bcast; circuit->rx = isis_recv_pdu_bcast; } - else if (circuit->circ_type == CIRCUIT_T_P2P) - { - circuit->tx = isis_send_pdu_p2p; - circuit->rx = isis_recv_pdu_p2p; - } else { zlog_warn ("isis_sock_init(): unknown circuit type"); @@ -283,23 +278,6 @@ isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa) return ISIS_OK; } -int -isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa) -{ - int bytesread; - - bytesread = stream_read (circuit->rcv_stream, circuit->fd, - circuit->interface->mtu); - - if (bytesread < 0) - { - zlog_warn ("isis_recv_pdu_p2p(): read () failed: %s", safe_strerror (errno)); - return ISIS_WARNING; - } - - return ISIS_OK; -} - int isis_send_pdu_bcast (struct isis_circuit *circuit, int level) { @@ -327,7 +305,8 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) else memcpy (eth->ether_dhost, ALL_L2_ISS, ETHER_ADDR_LEN); memcpy (eth->ether_shost, circuit->u.bc.snpa, ETHER_ADDR_LEN); - eth->ether_type = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN); + size_t frame_size = stream_get_endp(circuit->snd_stream) + LLC_LEN; + eth->ether_type = htons(isis_ethertype(frame_size)); /* * Then the LLC @@ -354,10 +333,4 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) return ISIS_OK; } -int -isis_send_pdu_p2p (struct isis_circuit *circuit, int level) -{ - return ISIS_OK; -} - #endif /* ISIS_METHOD == ISIS_METHOD_BPF */ diff --git a/isisd/isis_constants.h b/isisd/isis_constants.h index 17616d671b..ec0f6fb62c 100644 --- a/isisd/isis_constants.h +++ b/isisd/isis_constants.h @@ -171,4 +171,14 @@ #define ETH_ALEN 6 #endif +#define MAX_LLC_LEN 0x5ff +#define ETHERTYPE_EXT_LLC 0x8870 + +static inline uint16_t isis_ethertype(size_t len) +{ + if (len > MAX_LLC_LEN) + return ETHERTYPE_EXT_LLC; + return len; +} + #endif /* ISIS_CONSTANTS_H */ diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c index dd07a9c6f5..5c434b90d1 100644 --- a/isisd/isis_pfpacket.c +++ b/isisd/isis_pfpacket.c @@ -371,7 +371,9 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) stream_set_getp (circuit->snd_stream, 0); memset (&sa, 0, sizeof (struct sockaddr_ll)); sa.sll_family = AF_PACKET; - sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN); + + size_t frame_size = stream_get_endp(circuit->snd_stream) + LLC_LEN; + sa.sll_protocol = htons(isis_ethertype(frame_size)); sa.sll_ifindex = circuit->interface->ifindex; sa.sll_halen = ETH_ALEN; /* RFC5309 section 4.1 recommends ALL_ISS */ @@ -418,7 +420,6 @@ isis_send_pdu_p2p (struct isis_circuit *circuit, int level) stream_set_getp (circuit->snd_stream, 0); memset (&sa, 0, sizeof (struct sockaddr_ll)); sa.sll_family = AF_PACKET; - sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN); sa.sll_ifindex = circuit->interface->ifindex; sa.sll_halen = ETH_ALEN; if (level == 1) From 064f48967b1d352511702dd4e999a0e790835d2a Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 27 Apr 2017 13:56:35 +0200 Subject: [PATCH 45/55] isisd: add MT configuration Signed-off-by: Christian Franke --- isisd/Makefile.am | 4 +- isisd/isis_circuit.c | 22 ++++ isisd/isis_circuit.h | 3 + isisd/isis_mt.c | 262 +++++++++++++++++++++++++++++++++++++++++++ isisd/isis_mt.h | 97 ++++++++++++++++ isisd/isis_vty.c | 46 ++++++++ isisd/isisd.c | 91 +++++++++++++++ isisd/isisd.h | 2 + 8 files changed, 525 insertions(+), 2 deletions(-) create mode 100644 isisd/isis_mt.c create mode 100644 isisd/isis_mt.h diff --git a/isisd/Makefile.am b/isisd/Makefile.am index c97385f87a..2973820eed 100644 --- a/isisd/Makefile.am +++ b/isisd/Makefile.am @@ -16,7 +16,7 @@ libisis_a_SOURCES = \ isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \ isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \ isis_spf.c isis_redist.c isis_route.c isis_routemap.c isis_te.c \ - isis_vty.c + isis_vty.c isis_mt.c noinst_HEADERS = \ @@ -25,7 +25,7 @@ noinst_HEADERS = \ isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \ isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \ iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_redist.h \ - isis_route.h isis_routemap.h isis_te.h + isis_route.h isis_routemap.h isis_te.h isis_mt.h isisd_SOURCES = \ isis_main.c $(libisis_a_SOURCES) \ diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 6207ae189a..6caf8200ee 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -60,6 +60,7 @@ #include "isisd/isis_csm.h" #include "isisd/isis_events.h" #include "isisd/isis_te.h" +#include "isisd/isis_mt.h" DEFINE_QOBJ_TYPE(isis_circuit) @@ -102,6 +103,8 @@ isis_circuit_new () circuit->mtc = mpls_te_circuit_new(); + circuit_mt_init(circuit); + QOBJ_REG (circuit, isis_circuit); return circuit; @@ -117,6 +120,8 @@ isis_circuit_del (struct isis_circuit *circuit) isis_circuit_if_unbind (circuit, circuit->interface); + circuit_mt_finish(circuit); + /* and lastly the circuit itself */ XFREE (MTYPE_ISIS_CIRCUIT, circuit); @@ -1215,6 +1220,7 @@ isis_interface_config_write (struct vty *vty) VTY_NEWLINE); write++; } + write += circuit_write_mt_settings(circuit, vty); } vty_out (vty, "!%s", VTY_NEWLINE); } @@ -1382,6 +1388,22 @@ isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type) return 0; } +int +isis_circuit_mt_enabled_set (struct isis_circuit *circuit, uint16_t mtid, + bool enabled) +{ + struct isis_circuit_mt_setting *setting; + + setting = circuit_get_mt_setting(circuit, mtid); + if (setting->enabled != enabled) + { + setting->enabled = enabled; + lsp_regenerate_schedule (circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0); + } + + return CMD_SUCCESS; +} + int isis_if_new_hook (struct interface *ifp) { diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index bb0dc0f983..16dfa6304c 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -123,6 +123,7 @@ struct isis_circuit struct mpls_te_circuit *mtc; /* Support for MPLS-TE parameters - see isis_te.[c,h] */ int ip_router; /* Route IP ? */ int is_passive; /* Is Passive ? */ + struct list *mt_settings; /* IS-IS MT Settings */ struct list *ip_addrs; /* our IP addresses */ int ipv6_router; /* Route IPv6 ? */ struct list *ipv6_link; /* our link local IPv6 addresses */ @@ -187,4 +188,6 @@ int isis_circuit_passwd_unset (struct isis_circuit *circuit); int isis_circuit_passwd_cleartext_set (struct isis_circuit *circuit, const char *passwd); int isis_circuit_passwd_hmac_md5_set (struct isis_circuit *circuit, const char *passwd); +int isis_circuit_mt_enabled_set (struct isis_circuit *circuit, uint16_t mtid, bool enabled); + #endif /* _ZEBRA_ISIS_CIRCUIT_H */ diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c new file mode 100644 index 0000000000..7908fd4bb3 --- /dev/null +++ b/isisd/isis_mt.c @@ -0,0 +1,262 @@ +/* + * IS-IS Rout(e)ing protocol - Multi Topology Support + * + * Copyright (C) 2017 Christian Franke + * + * This file is part of FreeRangeRouting (FRR) + * + * FRR 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. + * + * FRR 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 FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#include +#include "isisd/isisd.h" +#include "isisd/isis_memory.h" +#include "isisd/isis_circuit.h" +#include "isisd/isis_mt.h" + +DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting") +DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting") + +/* MT naming api */ +const char *isis_mtid2str(uint16_t mtid) +{ + switch(mtid) + { + case ISIS_MT_IPV4_UNICAST: + return "ipv4-unicast"; + case ISIS_MT_IPV4_MGMT: + return "ipv4-mgmt"; + case ISIS_MT_IPV6_UNICAST: + return "ipv6-unicast"; + case ISIS_MT_IPV4_MULTICAST: + return "ipv4-multicast"; + case ISIS_MT_IPV6_MULTICAST: + return "ipv6-multicast"; + case ISIS_MT_IPV6_MGMT: + return "ipv6-mgmt"; + default: + return NULL; + } +} + +uint16_t isis_str2mtid(const char *name) +{ + if (!strcmp(name,"ipv4-unicast")) + return ISIS_MT_IPV4_UNICAST; + if (!strcmp(name,"ipv4-mgmt")) + return ISIS_MT_IPV4_MGMT; + if (!strcmp(name,"ipv6-unicast")) + return ISIS_MT_IPV6_UNICAST; + if (!strcmp(name,"ipv4-multicast")) + return ISIS_MT_IPV4_MULTICAST; + if (!strcmp(name,"ipv6-multicast")) + return ISIS_MT_IPV6_MULTICAST; + if (!strcmp(name,"ipv6-mgmt")) + return ISIS_MT_IPV6_MGMT; + return -1; +} + +/* General MT settings api */ + +struct mt_setting { + ISIS_MT_INFO_FIELDS; +}; + +static void * +lookup_mt_setting(struct list *mt_list, uint16_t mtid) +{ + struct listnode *node; + struct mt_setting *setting; + + for (ALL_LIST_ELEMENTS_RO(mt_list, node, setting)) + { + if (setting->mtid == mtid) + return setting; + } + return NULL; +} + +static void +add_mt_setting(struct list **mt_list, void *setting) +{ + if (!*mt_list) + *mt_list = list_new(); + listnode_add(*mt_list, setting); +} + +/* Area specific MT settings api */ + +struct isis_area_mt_setting* +area_lookup_mt_setting(struct isis_area *area, uint16_t mtid) +{ + return lookup_mt_setting(area->mt_settings, mtid); +} + +struct isis_area_mt_setting* +area_new_mt_setting(struct isis_area *area, uint16_t mtid) +{ + struct isis_area_mt_setting *setting; + + setting = XCALLOC(MTYPE_MT_AREA_SETTING, sizeof(*setting)); + setting->mtid = mtid; + return setting; +} + +static void +area_free_mt_setting(void *setting) +{ + XFREE(MTYPE_MT_AREA_SETTING, setting); +} + +void +area_add_mt_setting(struct isis_area *area, struct isis_area_mt_setting *setting) +{ + add_mt_setting(&area->mt_settings, setting); +} + +void +area_mt_init(struct isis_area *area) +{ + struct isis_area_mt_setting *v4_unicast_setting; + + /* MTID 0 is always enabled */ + v4_unicast_setting = area_new_mt_setting(area, ISIS_MT_IPV4_UNICAST); + v4_unicast_setting->enabled = true; + add_mt_setting(&area->mt_settings, v4_unicast_setting); + area->mt_settings->del = area_free_mt_setting; +} + +void +area_mt_finish(struct isis_area *area) +{ + list_delete(area->mt_settings); + area->mt_settings = NULL; +} + +struct isis_area_mt_setting * +area_get_mt_setting(struct isis_area *area, uint16_t mtid) +{ + struct isis_area_mt_setting *setting; + + setting = area_lookup_mt_setting(area, mtid); + if (!setting) + { + setting = area_new_mt_setting(area, mtid); + area_add_mt_setting(area, setting); + } + return setting; +} + +int +area_write_mt_settings(struct isis_area *area, struct vty *vty) +{ + int written = 0; + struct listnode *node; + struct isis_area_mt_setting *setting; + + for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting)) + { + const char *name = isis_mtid2str(setting->mtid); + if (name && setting->enabled) + { + if (setting->mtid == ISIS_MT_IPV4_UNICAST) + continue; /* always enabled, no need to write out config */ + vty_out (vty, " topology %s%s%s", name, + setting->overload ? " overload" : "", + VTY_NEWLINE); + written++; + } + } + return written; +} + +/* Circuit specific MT settings api */ + +struct isis_circuit_mt_setting* +circuit_lookup_mt_setting(struct isis_circuit *circuit, uint16_t mtid) +{ + return lookup_mt_setting(circuit->mt_settings, mtid); +} + +struct isis_circuit_mt_setting* +circuit_new_mt_setting(struct isis_circuit *circuit, uint16_t mtid) +{ + struct isis_circuit_mt_setting *setting; + + setting = XCALLOC(MTYPE_MT_CIRCUIT_SETTING, sizeof(*setting)); + setting->mtid = mtid; + setting->enabled = true; /* Enabled is default for circuit */ + return setting; +} + +static void +circuit_free_mt_setting(void *setting) +{ + XFREE(MTYPE_MT_CIRCUIT_SETTING, setting); +} + +void +circuit_add_mt_setting(struct isis_circuit *circuit, + struct isis_circuit_mt_setting *setting) +{ + add_mt_setting(&circuit->mt_settings, setting); +} + +void +circuit_mt_init(struct isis_circuit *circuit) +{ + circuit->mt_settings = list_new(); + circuit->mt_settings->del = circuit_free_mt_setting; +} + +void +circuit_mt_finish(struct isis_circuit *circuit) +{ + list_delete(circuit->mt_settings); + circuit->mt_settings = NULL; +} + +struct isis_circuit_mt_setting* +circuit_get_mt_setting(struct isis_circuit *circuit, uint16_t mtid) +{ + struct isis_circuit_mt_setting *setting; + + setting = circuit_lookup_mt_setting(circuit, mtid); + if (!setting) + { + setting = circuit_new_mt_setting(circuit, mtid); + circuit_add_mt_setting(circuit, setting); + } + return setting; +} + +int +circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty) +{ + int written = 0; + struct listnode *node; + struct isis_circuit_mt_setting *setting; + + for (ALL_LIST_ELEMENTS_RO (circuit->mt_settings, node, setting)) + { + const char *name = isis_mtid2str(setting->mtid); + if (name && !setting->enabled) + { + vty_out (vty, " no isis topology %s%s", name, VTY_NEWLINE); + written++; + } + } + return written; +} diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h new file mode 100644 index 0000000000..a6f4013577 --- /dev/null +++ b/isisd/isis_mt.h @@ -0,0 +1,97 @@ +/* + * IS-IS Rout(e)ing protocol - Multi Topology Support + * + * Copyright (C) 2017 Christian Franke + * + * This file is part of FreeRangeRouting (FRR) + * + * FRR 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. + * + * FRR 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 FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#ifndef ISIS_MT_H +#define ISIS_MT_H + +#define ISIS_MT_IPV4_UNICAST 0 +#define ISIS_MT_IPV4_MGMT 1 +#define ISIS_MT_IPV6_UNICAST 2 +#define ISIS_MT_IPV4_MULTICAST 3 +#define ISIS_MT_IPV6_MULTICAST 4 +#define ISIS_MT_IPV6_MGMT 5 + +#define ISIS_MT_NAMES \ + "" + +#define ISIS_MT_DESCRIPTIONS \ + "IPv4 unicast topology\n" \ + "IPv4 management topology\n" \ + "IPv6 unicast topology\n" \ + "IPv4 multicast topology\n" \ + "IPv6 multicast topology\n" \ + "IPv6 management topology\n" + +#define ISIS_MT_INFO_FIELDS \ + uint16_t mtid; + +struct isis_area_mt_setting { + ISIS_MT_INFO_FIELDS + bool enabled; + bool overload; +}; + +struct isis_circuit_mt_setting { + ISIS_MT_INFO_FIELDS + bool enabled; +}; + +const char *isis_mtid2str(uint16_t mtid); +uint16_t isis_str2mtid(const char *name); + +struct isis_area; +struct isis_circuit; + +struct isis_area_mt_setting* area_lookup_mt_setting(struct isis_area *area, + uint16_t mtid); +struct isis_area_mt_setting* area_new_mt_setting(struct isis_area *area, + uint16_t mtid); +void area_add_mt_setting(struct isis_area *area, + struct isis_area_mt_setting *setting); + +void area_mt_init(struct isis_area *area); +void area_mt_finish(struct isis_area *area); +struct isis_area_mt_setting* area_get_mt_setting(struct isis_area *area, + uint16_t mtid); +int area_write_mt_settings(struct isis_area *area, struct vty *vty); + +struct isis_circuit_mt_setting* circuit_lookup_mt_setting( + struct isis_circuit *circuit, + uint16_t mtid); +struct isis_circuit_mt_setting* circuit_new_mt_setting( + struct isis_circuit *circuit, + uint16_t mtid); +void circuit_add_mt_setting(struct isis_circuit *circuit, + struct isis_circuit_mt_setting *setting); +void circuit_mt_init(struct isis_circuit *circuit); +void circuit_mt_finish(struct isis_circuit *circuit); +struct isis_circuit_mt_setting* circuit_get_mt_setting( + struct isis_circuit *circuit, + uint16_t mtid); +int circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty); +#endif diff --git a/isisd/isis_vty.c b/isisd/isis_vty.c index 721959859a..1658ca3733 100644 --- a/isisd/isis_vty.c +++ b/isisd/isis_vty.c @@ -29,6 +29,7 @@ #include "isis_circuit.h" #include "isis_csm.h" #include "isis_misc.h" +#include "isis_mt.h" #include "isisd.h" static struct isis_circuit * @@ -1271,6 +1272,48 @@ DEFUN (no_psnp_interval_l2, return CMD_SUCCESS; } +DEFUN (circuit_topology, + circuit_topology_cmd, + "isis topology " ISIS_MT_NAMES, + "IS-IS commands\n" + "Configure interface IS-IS topologies\n" + ISIS_MT_DESCRIPTIONS) +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + const char *arg = argv[2]->arg; + uint16_t mtid = isis_str2mtid(arg); + if (mtid == (uint16_t)-1) + { + vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + return isis_circuit_mt_enabled_set(circuit, mtid, true); +} + +DEFUN (no_circuit_topology, + no_circuit_topology_cmd, + "no isis topology " ISIS_MT_NAMES, + NO_STR + "IS-IS commands\n" + "Configure interface IS-IS topologies\n" + ISIS_MT_DESCRIPTIONS) +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + const char *arg = argv[3]->arg; + uint16_t mtid = isis_str2mtid(arg); + if (mtid == (uint16_t)-1) + { + vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + return isis_circuit_mt_enabled_set(circuit, mtid, false); +} static int validate_metric_style_narrow (struct vty *vty, struct isis_area *area) @@ -2116,6 +2159,9 @@ isis_vty_init (void) install_element (INTERFACE_NODE, &psnp_interval_l2_cmd); install_element (INTERFACE_NODE, &no_psnp_interval_l2_cmd); + install_element (INTERFACE_NODE, &circuit_topology_cmd); + install_element (INTERFACE_NODE, &no_circuit_topology_cmd); + install_element (ISIS_NODE, &metric_style_cmd); install_element (ISIS_NODE, &no_metric_style_cmd); diff --git a/isisd/isisd.c b/isisd/isisd.c index f226c4a1f3..179e430986 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -56,6 +56,7 @@ #include "isisd/isis_zebra.h" #include "isisd/isis_events.h" #include "isisd/isis_te.h" +#include "isisd/isis_mt.h" struct isis *isis = NULL; @@ -156,6 +157,8 @@ isis_area_create (const char *area_tag) area->lsp_frag_threshold = 90; area->lsp_mtu = DEFAULT_LSP_MTU; + area_mt_init(area); + area->area_tag = strdup (area_tag); listnode_add (isis->area_list, area); area->isis = isis; @@ -296,6 +299,8 @@ isis_area_destroy (struct vty *vty, const char *area_tag) free (area->area_tag); + area_mt_finish(area); + XFREE (MTYPE_ISIS_AREA, area); if (listcount (isis->area_list) == 0) @@ -307,6 +312,33 @@ isis_area_destroy (struct vty *vty, const char *area_tag) return CMD_SUCCESS; } +static void +area_set_mt_enabled(struct isis_area *area, uint16_t mtid, bool enabled) +{ + struct isis_area_mt_setting *setting; + + setting = area_get_mt_setting(area, mtid); + if (setting->enabled != enabled) + { + setting->enabled = enabled; + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0); + } +} + +static void +area_set_mt_overload(struct isis_area *area, uint16_t mtid, bool overload) +{ + struct isis_area_mt_setting *setting; + + setting = area_get_mt_setting(area, mtid); + if (setting->overload != overload) + { + setting->overload = overload; + if (setting->enabled) + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0); + } +} + int area_net_title (struct vty *vty, const char *net_title) { @@ -1626,6 +1658,61 @@ DEFUN (no_net, return area_clear_net_title (vty, argv[idx_word]->arg); } +DEFUN (isis_topology, + isis_topology_cmd, + "topology " ISIS_MT_NAMES " [overload]", + "Configure IS-IS topologies\n" + ISIS_MT_DESCRIPTIONS + "Set overload bit for topology\n") +{ + VTY_DECLVAR_CONTEXT (isis_area, area); + + const char *arg = argv[1]->arg; + uint16_t mtid = isis_str2mtid(arg); + if (mtid == (uint16_t)-1) + { + vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + if (mtid == ISIS_MT_IPV4_UNICAST) + { + vty_out (vty, "Cannot configure IPv4 unicast topology%s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + area_set_mt_enabled(area, mtid, true); + area_set_mt_overload(area, mtid, (argc == 3)); + return CMD_SUCCESS; +} + +DEFUN (no_isis_topology, + no_isis_topology_cmd, + "no topology " ISIS_MT_NAMES " [overload]", + NO_STR + "Configure IS-IS topologies\n" + ISIS_MT_DESCRIPTIONS + "Set overload bit for topology\n") +{ + VTY_DECLVAR_CONTEXT (isis_area, area); + + const char *arg = argv[2]->arg; + uint16_t mtid = isis_str2mtid(arg); + if (mtid == (uint16_t)-1) + { + vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + if (mtid == ISIS_MT_IPV4_UNICAST) + { + vty_out (vty, "Cannot configure IPv4 unicast topology%s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + area_set_mt_enabled(area, mtid, false); + area_set_mt_overload(area, mtid, false); + return CMD_SUCCESS; +} + void isis_area_lsp_mtu_set(struct isis_area *area, unsigned int lsp_mtu) { area->lsp_mtu = lsp_mtu; @@ -2148,6 +2235,7 @@ isis_config_write (struct vty *vty) write++; } + write += area_write_mt_settings(area, vty); } isis_mpls_te_config_write_router(vty); } @@ -2254,6 +2342,9 @@ isis_init () install_element (ISIS_NODE, &net_cmd); install_element (ISIS_NODE, &no_net_cmd); + install_element (ISIS_NODE, &isis_topology_cmd); + install_element (ISIS_NODE, &no_isis_topology_cmd); + install_element (ISIS_NODE, &log_adj_changes_cmd); install_element (ISIS_NODE, &no_log_adj_changes_cmd); diff --git a/isisd/isisd.h b/isisd/isisd.h index e1d3a69f8d..a8cf3673fc 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -120,6 +120,8 @@ struct isis_area int ip_circuits; /* logging adjacency changes? */ u_char log_adj_changes; + /* multi topology settings */ + struct list *mt_settings; int ipv6_circuits; /* Counters */ u_int32_t circuit_state_changes; From 99894f9a17b319ca80d4a667b13cbc1a87814d2d Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 27 Apr 2017 13:56:38 +0200 Subject: [PATCH 46/55] isisd: announce MT capabilities in IIH and LSP Signed-off-by: Christian Franke --- isisd/isis_lsp.c | 37 +++++++++++++++++++ isisd/isis_mt.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++ isisd/isis_mt.h | 8 ++++ isisd/isis_pdu.c | 34 +++++++++++++++++ isisd/isis_tlv.c | 63 ++++++++++++++++++++++++++++++++ isisd/isis_tlv.h | 12 ++++++ 6 files changed, 249 insertions(+) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index d490bc47cd..d7d76942a6 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -53,6 +53,7 @@ #include "isisd/isis_adjacency.h" #include "isisd/isis_spf.h" #include "isisd/isis_te.h" +#include "isisd/isis_mt.h" /* staticly assigned vars for printing purposes */ char lsp_bits_string[200]; /* FIXME: enough ? */ @@ -501,6 +502,7 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream, expected |= TLVFLAG_TE_IPV4_REACHABILITY; expected |= TLVFLAG_TE_ROUTER_ID; } + expected |= TLVFLAG_MT_ROUTER_INFORMATION; expected |= TLVFLAG_IPV4_ADDR; expected |= TLVFLAG_IPV4_INT_REACHABILITY; expected |= TLVFLAG_IPV4_EXT_REACHABILITY; @@ -838,6 +840,7 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost) struct in_addr *ipv4_addr; struct te_ipv4_reachability *te_ipv4_reach; struct ipv6_reachability *ipv6_reach; + struct mt_router_info *mt_router_info; struct in6_addr in6; u_char buff[BUFSIZ]; u_char LSPid[255]; @@ -877,6 +880,14 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost) } } + for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_router_info, lnode, mt_router_info)) + { + vty_out (vty, " MT : %s%s%s", + isis_mtid2str(mt_router_info->mtid), + mt_router_info->overload ? " (overload)" : "", + VTY_NEWLINE); + } + /* for the hostname tlv */ if (lsp->tlv_data.hostname) { @@ -1344,6 +1355,32 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu); } + if (area_is_mt(area)) + { + lsp_debug("ISIS (%s): Adding MT router tlv...", area->area_tag); + lsp->tlv_data.mt_router_info = list_new(); + lsp->tlv_data.mt_router_info->del = free_tlv; + + struct isis_area_mt_setting **mt_settings; + unsigned int mt_count; + + mt_settings = area_mt_settings(area, &mt_count); + for (unsigned int i = 0; i < mt_count; i++) + { + struct mt_router_info *info; + + info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info)); + info->mtid = mt_settings[i]->mtid; + info->overload = mt_settings[i]->overload; + listnode_add(lsp->tlv_data.mt_router_info, info); + lsp_debug("ISIS (%s): MT %s", area->area_tag, isis_mtid2str(info->mtid)); + } + tlv_add_mt_router_info (lsp->tlv_data.mt_router_info, lsp->pdu); + } + else + { + lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)", area->area_tag); + } /* Dynamic Hostname */ if (area->dynhostname) { diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index 7908fd4bb3..6d43fdf03a 100644 --- a/isisd/isis_mt.c +++ b/isisd/isis_mt.c @@ -182,6 +182,58 @@ area_write_mt_settings(struct isis_area *area, struct vty *vty) return written; } +bool area_is_mt(struct isis_area *area) +{ + struct listnode *node, *node2; + struct isis_area_mt_setting *setting; + struct isis_circuit *circuit; + struct isis_circuit_mt_setting *csetting; + + for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting)) + { + if (setting->enabled && setting->mtid != ISIS_MT_IPV4_UNICAST) + return true; + } + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) + { + for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node2, csetting)) + { + if (!csetting->enabled && csetting->mtid == ISIS_MT_IPV4_UNICAST) + return true; + } + } + + return false; +} + +struct isis_area_mt_setting** +area_mt_settings(struct isis_area *area, unsigned int *mt_count) +{ + static unsigned int size = 0; + static struct isis_area_mt_setting **rv = NULL; + + unsigned int count = 0; + struct listnode *node; + struct isis_area_mt_setting *setting; + + for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting)) + { + if (!setting->enabled) + continue; + + count++; + if (count > size) + { + rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv)); + size = count; + } + rv[count-1] = setting; + } + + *mt_count = count; + return rv; +} + /* Circuit specific MT settings api */ struct isis_circuit_mt_setting* @@ -260,3 +312,46 @@ circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty) } return written; } + +struct isis_circuit_mt_setting** +circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count) +{ + static unsigned int size = 0; + static struct isis_circuit_mt_setting **rv = NULL; + + struct isis_area_mt_setting **area_settings; + unsigned int area_count; + + unsigned int count = 0; + + struct listnode *node; + struct isis_circuit_mt_setting *setting; + + area_settings = area_mt_settings(circuit->area, &area_count); + + for (unsigned int i = 0; i < area_count; i++) + { + for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node, setting)) + { + if (setting->mtid != area_settings[i]->mtid) + continue; + break; + } + if (!setting) + setting = circuit_get_mt_setting(circuit, area_settings[i]->mtid); + + if (!setting->enabled) + continue; + + count++; + if (count > size) + { + rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv)); + size = count; + } + rv[count-1] = setting; + } + + *mt_count = count; + return rv; +} diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h index a6f4013577..6b1711f4c8 100644 --- a/isisd/isis_mt.h +++ b/isisd/isis_mt.h @@ -23,6 +23,9 @@ #ifndef ISIS_MT_H #define ISIS_MT_H +#define ISIS_MT_MASK 0x0fff +#define ISIS_MT_OL_MASK 0x8000 + #define ISIS_MT_IPV4_UNICAST 0 #define ISIS_MT_IPV4_MGMT 1 #define ISIS_MT_IPV6_UNICAST 2 @@ -79,6 +82,9 @@ void area_mt_finish(struct isis_area *area); struct isis_area_mt_setting* area_get_mt_setting(struct isis_area *area, uint16_t mtid); int area_write_mt_settings(struct isis_area *area, struct vty *vty); +bool area_is_mt(struct isis_area *area); +struct isis_area_mt_setting** area_mt_settings(struct isis_area *area, + unsigned int *mt_count); struct isis_circuit_mt_setting* circuit_lookup_mt_setting( struct isis_circuit *circuit, @@ -94,4 +100,6 @@ struct isis_circuit_mt_setting* circuit_get_mt_setting( struct isis_circuit *circuit, uint16_t mtid); int circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty); +struct isis_circuit_mt_setting** circuit_mt_settings(struct isis_circuit *circuit, + unsigned int *mt_count); #endif diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 5fbf6c194e..8909eb31e0 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -53,6 +53,7 @@ #include "isisd/isis_csm.h" #include "isisd/isis_events.h" #include "isisd/isis_te.h" +#include "isisd/isis_mt.h" #define ISIS_MINIMUM_FIXED_HDR_LEN 15 #define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */ @@ -471,6 +472,7 @@ process_p2p_hello (struct isis_circuit *circuit) expected |= TLVFLAG_NLPID; expected |= TLVFLAG_IPV4_ADDR; expected |= TLVFLAG_IPV6_ADDR; + expected |= TLVFLAG_MT_ROUTER_INFORMATION; auth_tlv_offset = stream_get_getp (circuit->rcv_stream); retval = parse_tlvs (circuit->area->area_tag, @@ -1021,6 +1023,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa) expected |= TLVFLAG_NLPID; expected |= TLVFLAG_IPV4_ADDR; expected |= TLVFLAG_IPV6_ADDR; + expected |= TLVFLAG_MT_ROUTER_INFORMATION; auth_tlv_offset = stream_get_getp (circuit->rcv_stream); retval = parse_tlvs (circuit->area->area_tag, @@ -2337,6 +2340,37 @@ send_hello (struct isis_circuit *circuit, int level) if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream)) return ISIS_WARNING; + /* + * MT Supported TLV + * + * TLV gets included if no topology is enabled on the interface, + * if one topology other than #0 is enabled, or if multiple topologies + * are enabled. + */ + struct isis_circuit_mt_setting **mt_settings; + unsigned int mt_count; + + mt_settings = circuit_mt_settings(circuit, &mt_count); + if ((mt_count == 0 && area_is_mt(circuit->area)) + || (mt_count == 1 && mt_settings[0]->mtid != ISIS_MT_IPV4_UNICAST) + || (mt_count > 1)) + { + struct list *mt_info = list_new(); + mt_info->del = free_tlv; + + for (unsigned int i = 0; i < mt_count; i++) + { + struct mt_router_info *info; + + info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info)); + info->mtid = mt_settings[i]->mtid; + /* overload info is not valid in IIH, so it's not included here */ + listnode_add(mt_info, info); + } + tlv_add_mt_router_info (mt_info, circuit->snd_stream); + list_free(mt_info); + } + /* IPv6 Interface Address TLV */ if (circuit->ipv6_router && circuit->ipv6_link && listcount (circuit->ipv6_link) > 0) diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c index 4192fff9a8..14ebed94d3 100644 --- a/isisd/isis_tlv.c +++ b/isisd/isis_tlv.c @@ -61,6 +61,8 @@ free_tlvs (struct tlvs *tlvs) { if (tlvs->area_addrs) list_delete (tlvs->area_addrs); + if (tlvs->mt_router_info) + list_delete (tlvs->mt_router_info); if (tlvs->is_neighs) list_delete (tlvs->is_neighs); if (tlvs->te_is_neighs) @@ -786,6 +788,42 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, pnt += length; break; + case MT_ROUTER_INFORMATION: + *found |= TLVFLAG_MT_ROUTER_INFORMATION; + if (*expected & TLVFLAG_MT_ROUTER_INFORMATION) + { + if (!tlvs->mt_router_info) + { + tlvs->mt_router_info = list_new(); + tlvs->mt_router_info->del = free_tlv; + } + while (length > value_len) + { + uint16_t mt_info; + struct mt_router_info *info; + + if (value_len + sizeof(mt_info) > length) { + zlog_warn("ISIS-TLV (%s): TLV 229 is truncated.", areatag); + pnt += length - value_len; + break; + } + + memcpy(&mt_info, pnt, sizeof(mt_info)); + pnt += sizeof(mt_info); + value_len += sizeof(mt_info); + + mt_info = ntohs(mt_info); + info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info)); + info->mtid = mt_info & ISIS_MT_MASK; + info->overload = mt_info & ISIS_MT_OL_MASK; + listnode_add(tlvs->mt_router_info, info); + } + } + else + { + pnt += length; + } + break; default: zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d", areatag, type, length); @@ -825,6 +863,31 @@ add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream) return ISIS_OK; } +int +tlv_add_mt_router_info (struct list *mt_router_info, struct stream *stream) +{ + struct listnode *node; + struct mt_router_info *info; + + uint16_t value[127]; + uint16_t *pos = value; + + for (ALL_LIST_ELEMENTS_RO(mt_router_info, node, info)) + { + uint16_t mt_info; + + mt_info = info->mtid; + if (info->overload) + mt_info |= ISIS_MT_OL_MASK; + + *pos = htons(mt_info); + pos++; + } + + return add_tlv(MT_ROUTER_INFORMATION, (pos - value) * sizeof(*pos), + (u_char*)value, stream); +} + int tlv_add_area_addrs (struct list *area_addrs, struct stream *stream) { diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h index f899b9e9db..12025ff73a 100644 --- a/isisd/isis_tlv.h +++ b/isisd/isis_tlv.h @@ -24,6 +24,8 @@ #ifndef _ZEBRA_ISIS_TLV_H #define _ZEBRA_ISIS_TLV_H +#include "isisd/isis_mt.h" + /* * The list of TLVs we (should) support. * ____________________________________________________________________________ @@ -109,6 +111,7 @@ #define TE_IPV4_REACHABILITY 135 #define DYNAMIC_HOSTNAME 137 #define GRACEFUL_RESTART 211 +#define MT_ROUTER_INFORMATION 229 #define IPV6_ADDR 232 #define IPV6_REACHABILITY 236 #define WAY3_HELLO 240 @@ -250,6 +253,12 @@ struct ipv6_reachability #define CTRL_INFO_SUBTLVS 0x20 +struct mt_router_info +{ + ISIS_MT_INFO_FIELDS + bool overload; +}; + /* * Pointer to each tlv type, filled by parse_tlvs() */ @@ -260,6 +269,7 @@ struct tlvs struct nlpids *nlpids; struct te_router_id *router_id; struct list *area_addrs; + struct list *mt_router_info; struct list *is_neighs; struct list *te_is_neighs; struct list *es_neighs; @@ -301,6 +311,7 @@ struct tlvs #define TLVFLAG_TE_ROUTER_ID (1<<19) #define TLVFLAG_CHECKSUM (1<<20) #define TLVFLAG_GRACEFUL_RESTART (1<<21) +#define TLVFLAG_MT_ROUTER_INFORMATION (1<<22) void init_tlvs (struct tlvs *tlvs, uint32_t expected); void free_tlvs (struct tlvs *tlvs); @@ -310,6 +321,7 @@ int parse_tlvs (char *areatag, u_char * stream, int size, int add_tlv (u_char, u_char, u_char *, struct stream *); void free_tlv (void *val); +int tlv_add_mt_router_info (struct list *mt_router_info, struct stream *stream); int tlv_add_area_addrs (struct list *area_addrs, struct stream *stream); int tlv_add_is_neighs (struct list *is_neighs, struct stream *stream); int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream); From d8fba7d9742b93545a49b5e280825ecdf083d1a0 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 27 Apr 2017 13:56:41 +0200 Subject: [PATCH 47/55] isisd: track intersecting set of supported MTs for each adj Signed-off-by: Christian Franke --- isisd/isis_adjacency.c | 19 ++++++++++ isisd/isis_adjacency.h | 3 ++ isisd/isis_mt.c | 84 +++++++++++++++++++++++++++++++++++++++++- isisd/isis_mt.h | 5 +++ isisd/isis_pdu.c | 14 +++++++ 5 files changed, 124 insertions(+), 1 deletion(-) diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index f550924874..c6fc6b008d 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -148,6 +148,8 @@ isis_delete_adj (void *arg) if (adj->ipv6_addrs) list_delete (adj->ipv6_addrs); + adj_mt_finish(adj); + XFREE (MTYPE_ISIS_ADJACENCY, adj); return; } @@ -521,3 +523,20 @@ isis_adj_build_up_list (struct list *adjdb, struct list *list) return; } + +int +isis_adj_usage2levels(enum isis_adj_usage usage) +{ + switch (usage) + { + case ISIS_ADJ_LEVEL1: + return IS_LEVEL_1; + case ISIS_ADJ_LEVEL2: + return IS_LEVEL_2; + case ISIS_ADJ_LEVEL1AND2: + return IS_LEVEL_1 | IS_LEVEL_2; + default: + break; + } + return 0; +} diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index 8539b03d6b..4f89e30960 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -97,6 +97,8 @@ struct isis_adjacency int flaps; /* number of adjacency flaps */ struct thread *t_expire; /* expire after hold_time */ struct isis_circuit *circuit; /* back pointer */ + uint16_t *mt_set; /* Topologies this adjacency is valid for */ + unsigned int mt_count; /* Number of entries in mt_set */ }; struct isis_adjacency *isis_adj_lookup (const u_char * sysid, struct list *adjdb); @@ -112,5 +114,6 @@ int isis_adj_expire (struct thread *thread); void isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail); void isis_adj_build_neigh_list (struct list *adjdb, struct list *list); void isis_adj_build_up_list (struct list *adjdb, struct list *list); +int isis_adj_usage2levels(enum isis_adj_usage usage); #endif /* ISIS_ADJACENCY_H */ diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index 6d43fdf03a..4e36b91433 100644 --- a/isisd/isis_mt.c +++ b/isisd/isis_mt.c @@ -24,14 +24,19 @@ #include "isisd/isisd.h" #include "isisd/isis_memory.h" #include "isisd/isis_circuit.h" +#include "isisd/isis_adjacency.h" +#include "isisd/isis_tlv.h" #include "isisd/isis_mt.h" DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting") DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting") +DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info") /* MT naming api */ const char *isis_mtid2str(uint16_t mtid) { + static char buf[sizeof("65535")]; + switch(mtid) { case ISIS_MT_IPV4_UNICAST: @@ -47,7 +52,8 @@ const char *isis_mtid2str(uint16_t mtid) case ISIS_MT_IPV6_MGMT: return "ipv6-mgmt"; default: - return NULL; + snprintf(buf, sizeof(buf), "%" PRIu16, mtid); + return buf; } } @@ -355,3 +361,79 @@ circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count) *mt_count = count; return rv; } + +static void adj_mt_set(struct isis_adjacency *adj, unsigned int index, + uint16_t mtid) +{ + if (adj->mt_count < index + 1) + { + adj->mt_set = XREALLOC(MTYPE_MT_ADJ_INFO, adj->mt_set, + (index + 1) * sizeof(*adj->mt_set)); + adj->mt_count = index + 1; + } + adj->mt_set[index] = mtid; +} + +bool +tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable, + struct isis_adjacency *adj) +{ + struct isis_circuit_mt_setting **mt_settings; + unsigned int circuit_mt_count; + + unsigned int intersect_count = 0; + + uint16_t *old_mt_set; + unsigned int old_mt_count; + + old_mt_count = adj->mt_count; + if (old_mt_count) + { + old_mt_set = XCALLOC(MTYPE_TMP, old_mt_count * sizeof(*old_mt_set)); + memcpy(old_mt_set, adj->mt_set, old_mt_count * sizeof(*old_mt_set)); + } + + mt_settings = circuit_mt_settings(adj->circuit, &circuit_mt_count); + for (unsigned int i = 0; i < circuit_mt_count; i++) + { + if (!tlvs->mt_router_info) + { + /* Other end does not have MT enabled */ + if (mt_settings[i]->mtid == ISIS_MT_IPV4_UNICAST) + adj_mt_set(adj, intersect_count++, ISIS_MT_IPV4_UNICAST); + } + else + { + struct listnode *node; + struct mt_router_info *info; + for (ALL_LIST_ELEMENTS_RO(tlvs->mt_router_info, node, info)) + { + if (mt_settings[i]->mtid == info->mtid) + adj_mt_set(adj, intersect_count++, info->mtid); + } + } + } + adj->mt_count = intersect_count; + + bool changed = false; + + if (adj->mt_count != old_mt_count) + changed = true; + + if (!changed && old_mt_count + && memcmp(adj->mt_set, old_mt_set, + old_mt_count * sizeof(*old_mt_set))) + changed = true; + + if (old_mt_count) + XFREE(MTYPE_TMP, old_mt_set); + + return changed; +} + +void +adj_mt_finish(struct isis_adjacency *adj) +{ + XFREE(MTYPE_MT_ADJ_INFO, adj->mt_set); + adj->mt_count = 0; +} diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h index 6b1711f4c8..3ad8c05e47 100644 --- a/isisd/isis_mt.h +++ b/isisd/isis_mt.h @@ -67,8 +67,10 @@ struct isis_circuit_mt_setting { const char *isis_mtid2str(uint16_t mtid); uint16_t isis_str2mtid(const char *name); +struct isis_adjacency; struct isis_area; struct isis_circuit; +struct tlvs; struct isis_area_mt_setting* area_lookup_mt_setting(struct isis_area *area, uint16_t mtid); @@ -102,4 +104,7 @@ struct isis_circuit_mt_setting* circuit_get_mt_setting( int circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty); struct isis_circuit_mt_setting** circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count); +bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable, + struct isis_adjacency *adj); +void adj_mt_finish(struct isis_adjacency *adj); #endif diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 8909eb31e0..9e90acf2e0 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -635,6 +635,8 @@ process_p2p_hello (struct isis_circuit *circuit) if (found & TLVFLAG_IPV6_ADDR) tlvs_to_adj_ipv6_addrs (&tlvs, adj); + bool mt_set_changed = tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj); + /* lets take care of the expiry */ THREAD_TIMER_OFF (adj->t_expire); THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj, @@ -871,6 +873,13 @@ process_p2p_hello (struct isis_circuit *circuit) /* down - area mismatch */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch"); } + + if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed) + { + lsp_regenerate_schedule(adj->circuit->area, + isis_adj_usage2levels(adj->adj_usage), 0); + } + /* 8.2.5.2 c) if the action was up - comparing circuit IDs */ /* FIXME - Missing parts */ @@ -1226,6 +1235,8 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa) adj->circuit_t = hdr.circuit_t; + bool mt_set_changed = tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj); + /* lets take care of the expiry */ THREAD_TIMER_OFF (adj->t_expire); THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj, @@ -1269,6 +1280,9 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa) "no LAN Neighbours TLV found"); } + if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed) + lsp_regenerate_schedule(adj->circuit->area, level, 0); + out: if (isis->debugs & DEBUG_ADJ_PACKETS) { From 206f4aae58385290ca6d0bb376cf20b6b1e194da Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 27 Apr 2017 13:56:43 +0200 Subject: [PATCH 48/55] isisd: announce and parse MT IS reachabilities Signed-off-by: Christian Franke --- isisd/isis_adjacency.c | 1 + isisd/isis_lsp.c | 119 +++++++++++++++++++++----- isisd/isis_mt.c | 157 +++++++++++++++++++++++++++++++++++ isisd/isis_mt.h | 15 ++++ isisd/isis_tlv.c | 184 +++++++++++++++++++++++++++++------------ isisd/isis_tlv.h | 4 +- 6 files changed, 404 insertions(+), 76 deletions(-) diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index c6fc6b008d..fea99ec907 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -47,6 +47,7 @@ #include "isisd/isis_lsp.h" #include "isisd/isis_spf.h" #include "isisd/isis_events.h" +#include "isisd/isis_mt.h" extern struct isis *isis; diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index d7d76942a6..5009c34b02 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -828,6 +828,34 @@ lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost) lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE); } +static void +lsp_print_mt_reach(struct list *list, struct vty *vty, + char dynhost, uint16_t mtid) +{ + struct listnode *node; + struct te_is_neigh *neigh; + + for (ALL_LIST_ELEMENTS_RO (list, node, neigh)) + { + u_char lspid[255]; + + lspid_print(neigh->neigh_id, lspid, dynhost, 0); + if (mtid == ISIS_MT_IPV4_UNICAST) + { + vty_out(vty, " Metric : %-8d IS-Extended : %s%s", + GET_TE_METRIC(neigh), lspid, VTY_NEWLINE); + } + else + { + vty_out(vty, " Metric : %-8d MT-Reach : %s %s%s", + GET_TE_METRIC(neigh), lspid, + isis_mtid2str(mtid), VTY_NEWLINE); + } + if (IS_MPLS_TE(isisMplsTE)) + mpls_te_print_detail(vty, neigh); + } +} + void lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost) { @@ -835,12 +863,12 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost) int i; struct listnode *lnode; struct is_neigh *is_neigh; - struct te_is_neigh *te_is_neigh; struct ipv4_reachability *ipv4_reach; struct in_addr *ipv4_addr; struct te_ipv4_reachability *te_ipv4_reach; struct ipv6_reachability *ipv6_reach; struct mt_router_info *mt_router_info; + struct tlv_mt_neighbors *mt_is_neigh; struct in6_addr in6; u_char buff[BUFSIZ]; u_char LSPid[255]; @@ -978,15 +1006,12 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost) } /* TE IS neighbor tlv */ - if (lsp->tlv_data.te_is_neighs) - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh)) - { - lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0); - vty_out (vty, " Metric : %-8d IS-Extended : %s%s", - GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE); - if (IS_MPLS_TE(isisMplsTE)) - mpls_te_print_detail(vty, te_is_neigh); - } + lsp_print_mt_reach(lsp->tlv_data.te_is_neighs, vty, + dynhost, ISIS_MT_IPV4_UNICAST); + + /* MT IS neighbor tlv */ + for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.mt_is_neighs, lnode, mt_is_neigh)) + lsp_print_mt_reach(mt_is_neigh->list, vty, dynhost, mt_is_neigh->mtid); /* TE IPv4 tlv */ if (lsp->tlv_data.te_ipv4_reachs) @@ -1039,6 +1064,42 @@ lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost) return lsp_count; } +static void +_lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, + int frag_thold, + unsigned int tlv_build_func (struct list *, struct stream *, + void *arg), + void *arg) +{ + while (*from && listcount(*from)) + { + unsigned int count; + + count = tlv_build_func(*from, lsp->pdu, arg); + + if (listcount(*to) != 0 || count != listcount(*from)) + { + struct listnode *node, *nnode; + void *elem; + + for (ALL_LIST_ELEMENTS(*from, node, nnode, elem)) + { + if (!count) + break; + listnode_add (*to, elem); + list_delete_node (*from, node); + --count; + } + } + else + { + list_free (*to); + *to = *from; + *from = NULL; + } + } +} + #define FRAG_THOLD(S,T) \ ((STREAM_SIZE(S)*T)/100) @@ -1637,10 +1698,8 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */ te_is_neigh->sub_tlvs_length = 0; - listnode_add (tlv_data.te_is_neighs, te_is_neigh); - lsp_debug("ISIS (%s): Adding DIS %s.%02x as te-style neighbor", - area->area_tag, sysid_print(te_is_neigh->neigh_id), - LSP_PSEUDO_ID(te_is_neigh->neigh_id)); + tlvs_add_mt_bcast(&tlv_data, circuit, level, te_is_neigh); + XFREE(MTYPE_ISIS_TLV, te_is_neigh); } } } @@ -1697,9 +1756,9 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) else /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */ te_is_neigh->sub_tlvs_length = 0; - listnode_add (tlv_data.te_is_neighs, te_is_neigh); - lsp_debug("ISIS (%s): Adding te-style is reach for %s", area->area_tag, - sysid_print(te_is_neigh->neigh_id)); + + tlvs_add_mt_p2p(&tlv_data, circuit, te_is_neigh); + XFREE(MTYPE_ISIS_TLV, te_is_neigh); } } else @@ -1791,13 +1850,31 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) { if (lsp->tlv_data.te_is_neighs == NULL) lsp->tlv_data.te_is_neighs = list_new (); - lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs, - IS_NEIGHBOURS_LEN, area->lsp_frag_threshold, - tlv_add_te_is_neighs); + _lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs, + area->lsp_frag_threshold, tlv_add_te_is_neighs, NULL); if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); } + + struct tlv_mt_neighbors *mt_neighs; + for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_is_neighs, node, mt_neighs)) + { + while (mt_neighs->list && listcount(mt_neighs->list)) + { + struct tlv_mt_neighbors *frag_mt_neighs; + + frag_mt_neighs = tlvs_get_mt_neighbors(&lsp->tlv_data, mt_neighs->mtid); + _lsp_tlv_fit (lsp, &mt_neighs->list, &frag_mt_neighs->list, + area->lsp_frag_threshold, tlv_add_te_is_neighs, + &mt_neighs->mtid); + if (mt_neighs->list && listcount(mt_neighs->list)) + lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, + lsp0, area, level); + } + } + + lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); free_tlvs (&tlv_data); @@ -2234,7 +2311,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu); if (lsp->tlv_data.te_is_neighs && listcount (lsp->tlv_data.te_is_neighs) > 0) - tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu); + tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu, NULL); if (lsp->tlv_data.es_neighs && listcount (lsp->tlv_data.es_neighs) > 0) tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu); diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index 4e36b91433..e66c9d7d9c 100644 --- a/isisd/isis_mt.c +++ b/isisd/isis_mt.c @@ -26,11 +26,14 @@ #include "isisd/isis_circuit.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_tlv.h" +#include "isisd/isis_misc.h" +#include "isisd/isis_lsp.h" #include "isisd/isis_mt.h" DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting") DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting") DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info") +DEFINE_MTYPE_STATIC(ISISD, MT_NEIGHBORS, "ISIS MT Neighbors for TLV") /* MT naming api */ const char *isis_mtid2str(uint16_t mtid) @@ -362,6 +365,7 @@ circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count) return rv; } +/* ADJ specific MT API */ static void adj_mt_set(struct isis_adjacency *adj, unsigned int index, uint16_t mtid) { @@ -437,3 +441,156 @@ adj_mt_finish(struct isis_adjacency *adj) XFREE(MTYPE_MT_ADJ_INFO, adj->mt_set); adj->mt_count = 0; } + +/* TLV MT Neighbors api */ +struct tlv_mt_neighbors* +tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid) +{ + return lookup_mt_setting(tlvs->mt_is_neighs, mtid); +} + +static struct tlv_mt_neighbors* +tlvs_new_mt_neighbors(uint16_t mtid) +{ + struct tlv_mt_neighbors *rv; + + rv = XCALLOC(MTYPE_MT_NEIGHBORS, sizeof(*rv)); + rv->mtid = mtid; + rv->list = list_new(); + + return rv; +}; + +static void +tlvs_free_mt_neighbors(void *arg) +{ + struct tlv_mt_neighbors *neighbors = arg; + + if (neighbors && neighbors->list) + list_delete(neighbors->list); + XFREE(MTYPE_MT_NEIGHBORS, neighbors); +} + +static void +tlvs_add_mt_neighbors(struct tlvs *tlvs, struct tlv_mt_neighbors *neighbors) +{ + add_mt_setting(&tlvs->mt_is_neighs, neighbors); + tlvs->mt_is_neighs->del = tlvs_free_mt_neighbors; +} + +struct tlv_mt_neighbors* +tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid) +{ + struct tlv_mt_neighbors *neighbors; + + neighbors = tlvs_lookup_mt_neighbors(tlvs, mtid); + if (!neighbors) + { + neighbors = tlvs_new_mt_neighbors(mtid); + tlvs_add_mt_neighbors(tlvs, neighbors); + } + return neighbors; +} + +static void +mt_set_add(uint16_t **mt_set, unsigned int *size, + unsigned int *index, uint16_t mtid) +{ + for (unsigned int i = 0; i < *index; i++) + { + if ((*mt_set)[i] == mtid) + return; + } + + if (*index >= *size) + { + *mt_set = XREALLOC(MTYPE_TMP, *mt_set, sizeof(**mt_set) * ((*index) + 1)); + *size = (*index) + 1; + } + + (*mt_set)[*index] = mtid; + *index = (*index) + 1; +} + +static uint16_t * +circuit_bcast_mt_set(struct isis_circuit *circuit, int level, + unsigned int *mt_count) +{ + static uint16_t *rv; + static unsigned int size; + struct listnode *node; + struct isis_adjacency *adj; + + unsigned int count = 0; + + if (circuit->circ_type != CIRCUIT_T_BROADCAST) + { + *mt_count = 0; + return NULL; + } + + for (ALL_LIST_ELEMENTS_RO(circuit->u.bc.adjdb[level - 1], node, adj)) + { + if (adj->adj_state != ISIS_ADJ_UP) + continue; + for (unsigned int i = 0; i < adj->mt_count; i++) + mt_set_add(&rv, &size, &count, adj->mt_set[i]); + } + + *mt_count = count; + return rv; +} + +static void +tlvs_add_mt_set(struct isis_area *area, + struct tlvs *tlvs, unsigned int mt_count, + uint16_t *mt_set, struct te_is_neigh *neigh) +{ + for (unsigned int i = 0; i < mt_count; i++) + { + uint16_t mtid = mt_set[i]; + struct te_is_neigh *ne_copy; + + ne_copy = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ne_copy)); + memcpy(ne_copy, neigh, sizeof(*ne_copy)); + + if (mt_set[i] == ISIS_MT_IPV4_UNICAST) + { + listnode_add(tlvs->te_is_neighs, ne_copy); + lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor", + area->area_tag, sysid_print(ne_copy->neigh_id), + LSP_PSEUDO_ID(ne_copy->neigh_id)); + } + else + { + struct tlv_mt_neighbors *neighbors; + + neighbors = tlvs_get_mt_neighbors(tlvs, mtid); + neighbors->list->del = free_tlv; + listnode_add(neighbors->list, ne_copy); + lsp_debug("ISIS (%s): Adding %s.%02x as mt-style neighbor for %s", + area->area_tag, sysid_print(ne_copy->neigh_id), + LSP_PSEUDO_ID(ne_copy->neigh_id), isis_mtid2str(mtid)); + } + } +} + +void +tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit, + int level, struct te_is_neigh *neigh) +{ + unsigned int mt_count; + uint16_t *mt_set = circuit_bcast_mt_set(circuit, level, + &mt_count); + + tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, neigh); +} + +void +tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit, + struct te_is_neigh *neigh) +{ + struct isis_adjacency *adj = circuit->u.p2p.neighbor; + + tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, neigh); +} diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h index 3ad8c05e47..313e992b4a 100644 --- a/isisd/isis_mt.h +++ b/isisd/isis_mt.h @@ -53,6 +53,8 @@ #define ISIS_MT_INFO_FIELDS \ uint16_t mtid; +struct list; + struct isis_area_mt_setting { ISIS_MT_INFO_FIELDS bool enabled; @@ -64,6 +66,11 @@ struct isis_circuit_mt_setting { bool enabled; }; +struct tlv_mt_neighbors { + ISIS_MT_INFO_FIELDS + struct list *list; +}; + const char *isis_mtid2str(uint16_t mtid); uint16_t isis_str2mtid(const char *name); @@ -71,6 +78,10 @@ struct isis_adjacency; struct isis_area; struct isis_circuit; struct tlvs; +struct te_is_neigh; + +struct tlv_mt_neighbors* tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid); +struct tlv_mt_neighbors* tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid); struct isis_area_mt_setting* area_lookup_mt_setting(struct isis_area *area, uint16_t mtid); @@ -107,4 +118,8 @@ struct isis_circuit_mt_setting** circuit_mt_settings(struct isis_circuit *circui bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable, struct isis_adjacency *adj); void adj_mt_finish(struct isis_adjacency *adj); +void tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit, + int level, struct te_is_neigh *neigh); +void tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit, + struct te_is_neigh *neigh); #endif diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c index 14ebed94d3..41c861bf58 100644 --- a/isisd/isis_tlv.c +++ b/isisd/isis_tlv.c @@ -43,6 +43,7 @@ #include "isisd/isis_pdu.h" #include "isisd/isis_lsp.h" #include "isisd/isis_te.h" +#include "isisd/isis_mt.h" void free_tlv (void *val) @@ -67,6 +68,8 @@ free_tlvs (struct tlvs *tlvs) list_delete (tlvs->is_neighs); if (tlvs->te_is_neighs) list_delete (tlvs->te_is_neighs); + if (tlvs->mt_is_neighs) + list_delete (tlvs->mt_is_neighs); if (tlvs->es_neighs) list_delete (tlvs->es_neighs); if (tlvs->lsp_entries) @@ -93,6 +96,83 @@ free_tlvs (struct tlvs *tlvs) return; } +static int +parse_mt_is_neighs(struct tlvs *tlvs, bool read_mtid, + unsigned int length, u_char *pnt) +{ + struct list *neigh_list; + uint16_t mtid; + + if (read_mtid) + { + uint16_t mtid_buf; + + if (length < sizeof(mtid_buf)) + { + zlog_warn("ISIS-TLV: mt tlv too short to contain MT id"); + return ISIS_WARNING; + } + + memcpy(&mtid_buf, pnt, sizeof(mtid_buf)); + pnt += sizeof(mtid_buf); + length -= sizeof(mtid_buf); + + mtid = ntohs(mtid_buf) & ISIS_MT_MASK; + } + else + { + mtid = ISIS_MT_IPV4_UNICAST; + } + + if (mtid == ISIS_MT_IPV4_UNICAST) + { + if (!tlvs->te_is_neighs) + { + tlvs->te_is_neighs = list_new(); + tlvs->te_is_neighs->del = free_tlv; + } + neigh_list = tlvs->te_is_neighs; + } + else + { + struct tlv_mt_neighbors *neighbors; + + neighbors = tlvs_get_mt_neighbors(tlvs, mtid); + neighbors->list->del = free_tlv; + neigh_list = neighbors->list; + } + + while (length >= IS_NEIGHBOURS_LEN) + { + struct te_is_neigh *neigh = XCALLOC(MTYPE_ISIS_TLV, sizeof(*neigh)); + + memcpy(neigh, pnt, IS_NEIGHBOURS_LEN); + pnt += IS_NEIGHBOURS_LEN; + length -= IS_NEIGHBOURS_LEN; + + if (neigh->sub_tlvs_length > length) + { + zlog_warn("ISIS-TLV: neighbor subtlv length exceeds TLV size"); + XFREE(MTYPE_ISIS_TLV, neigh); + return ISIS_WARNING; + } + + memcpy(neigh->sub_tlvs, pnt, neigh->sub_tlvs_length); + pnt += neigh->sub_tlvs_length; + length -= neigh->sub_tlvs_length; + + listnode_add(neigh_list, neigh); + } + + if (length) + { + zlog_warn("ISIS-TLV: TE/MT neighor TLV has trailing data"); + return ISIS_WARNING; + } + + return ISIS_OK; +} + /* * Parses the tlvs found in the variant length part of the PDU. * Caller tells with flags in "expected" which TLV's it is interested in. @@ -105,7 +185,6 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, struct lan_neigh *lan_nei; struct area_addr *area_addr; struct is_neigh *is_nei; - struct te_is_neigh *te_is_nei; struct es_neigh *es_nei; struct lsp_entry *lsp_entry; struct in_addr *ipv4_addr; @@ -209,54 +288,25 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, break; case TE_IS_NEIGHBOURS: - /* +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Neighbour ID | 7 - * +---------------------------------------------------------------+ - * | TE Metric | 3 - * +---------------------------------------------------------------+ - * | SubTLVs Length | 1 - * +---------------------------------------------------------------+ - * : : - */ *found |= TLVFLAG_TE_IS_NEIGHS; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): Extended IS Neighbours length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (TLVFLAG_TE_IS_NEIGHS & *expected) - { - while (length > value_len) - { - te_is_nei = (struct te_is_neigh *) pnt; - value_len += IS_NEIGHBOURS_LEN; - pnt += IS_NEIGHBOURS_LEN; - /* FIXME - subtlvs are handled here, for now we skip */ - /* FIXME: All TE SubTLVs are not necessary present in LSP PDU. */ - /* So, it must be copied in a new te_is_neigh structure */ - /* rather than just initialize pointer to the original LSP PDU */ - /* to avoid consider the rest of lspdu as subTLVs or buffer overflow */ - if (IS_MPLS_TE(isisMplsTE)) - { - struct te_is_neigh *new = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct te_is_neigh)); - memcpy(new->neigh_id, te_is_nei->neigh_id, ISIS_SYS_ID_LEN + 1); - memcpy(new->te_metric, te_is_nei->te_metric, 3); - new->sub_tlvs_length = te_is_nei->sub_tlvs_length; - memcpy(new->sub_tlvs, pnt, te_is_nei->sub_tlvs_length); - te_is_nei = new; - } - /* Skip SUB TLVs payload */ - value_len += te_is_nei->sub_tlvs_length; - pnt += te_is_nei->sub_tlvs_length; + retval = parse_mt_is_neighs(tlvs, false, length, pnt); + pnt += length; + break; - if (!tlvs->te_is_neighs) - tlvs->te_is_neighs = list_new (); - listnode_add (tlvs->te_is_neighs, te_is_nei); - } - } - else - { - pnt += length; - } + case MT_IS_NEIGHBOURS: + *found |= TLVFLAG_TE_IS_NEIGHS; +#ifdef EXTREME_TLV_DEBUG + zlog_debug ("ISIS-TLV (%s): MT IS Neighbours length %d", + areatag, length); +#endif + if (TLVFLAG_TE_IS_NEIGHS & *expected) + retval = parse_mt_is_neighs(tlvs, true, length, pnt); + pnt += length; break; case ES_NEIGHBOURS: @@ -950,26 +1000,44 @@ tlv_add_is_neighs (struct list *is_neighs, struct stream *stream) return add_tlv (IS_NEIGHBOURS, pos - value, value, stream); } -int -tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream) +static size_t +max_tlv_size(struct stream *stream) +{ + size_t avail = stream_get_size (stream) - stream_get_endp(stream); + + if (avail < 2) + return 0; + + if (avail < 257) + return avail - 2; + + return 255; +} + +unsigned int +tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream, void *arg) { struct listnode *node; struct te_is_neigh *te_is_neigh; u_char value[255]; u_char *pos = value; - int retval; + uint16_t mtid = arg ? *(uint16_t*)arg : ISIS_MT_IPV4_UNICAST; + unsigned int consumed = 0; + size_t max_size = max_tlv_size(stream); + + if (mtid != ISIS_MT_IPV4_UNICAST) + { + uint16_t mtid_conversion = ntohs(mtid); + memcpy(pos, &mtid_conversion, sizeof(mtid_conversion)); + pos += sizeof(mtid_conversion); + } for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh)) { /* FIXME: Check if Total SubTLVs size doesn't exceed 255 */ - if (pos - value + IS_NEIGHBOURS_LEN + te_is_neigh->sub_tlvs_length > 255) - { - retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream); - if (retval != ISIS_OK) - return retval; - pos = value; - } - + if ((size_t)(pos - value) + IS_NEIGHBOURS_LEN + te_is_neigh->sub_tlvs_length > max_size) + break; + memcpy (pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1); pos += ISIS_SYS_ID_LEN + 1; memcpy (pos, te_is_neigh->te_metric, 3); @@ -983,9 +1051,17 @@ tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream) memcpy (pos, te_is_neigh->sub_tlvs, te_is_neigh->sub_tlvs_length); pos += te_is_neigh->sub_tlvs_length; } + consumed++; } - return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream); + if (consumed) + { + int rv = add_tlv ((mtid != ISIS_MT_IPV4_UNICAST) ? MT_IS_NEIGHBOURS + : TE_IS_NEIGHBOURS, + pos - value, value, stream); + assert(rv == ISIS_OK); + } + return consumed; } int diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h index 12025ff73a..f3c04baf54 100644 --- a/isisd/isis_tlv.h +++ b/isisd/isis_tlv.h @@ -111,6 +111,7 @@ #define TE_IPV4_REACHABILITY 135 #define DYNAMIC_HOSTNAME 137 #define GRACEFUL_RESTART 211 +#define MT_IS_NEIGHBOURS 222 #define MT_ROUTER_INFORMATION 229 #define IPV6_ADDR 232 #define IPV6_REACHABILITY 236 @@ -272,6 +273,7 @@ struct tlvs struct list *mt_router_info; struct list *is_neighs; struct list *te_is_neighs; + struct list *mt_is_neighs; struct list *es_neighs; struct list *lsp_entries; struct list *prefix_neighs; @@ -324,7 +326,7 @@ void free_tlv (void *val); int tlv_add_mt_router_info (struct list *mt_router_info, struct stream *stream); int tlv_add_area_addrs (struct list *area_addrs, struct stream *stream); int tlv_add_is_neighs (struct list *is_neighs, struct stream *stream); -int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream); +unsigned int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream, void *arg); int tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream); int tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream); int tlv_add_checksum (struct checksum *checksum, struct stream *stream); From c3ae3127028a92c09bcaed2eabfeaf5e11157438 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 27 Apr 2017 13:56:45 +0200 Subject: [PATCH 49/55] isisd: announce and parse MT IP reachabilities Signed-off-by: Christian Franke --- isisd/isis_lsp.c | 210 +++++++++++++++------ isisd/isis_mt.c | 112 +++++++++++ isisd/isis_mt.h | 18 ++ isisd/isis_tlv.c | 478 ++++++++++++++++++++++++++++++----------------- isisd/isis_tlv.h | 8 +- 5 files changed, 596 insertions(+), 230 deletions(-) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 5009c34b02..955a73ef61 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -856,6 +856,79 @@ lsp_print_mt_reach(struct list *list, struct vty *vty, } } +static void +lsp_print_mt_ipv6_reach(struct list *list, struct vty *vty, uint16_t mtid) +{ + struct listnode *node; + struct ipv6_reachability *ipv6_reach; + struct in6_addr in6; + u_char buff[BUFSIZ]; + + for (ALL_LIST_ELEMENTS_RO (list, node, ipv6_reach)) + { + memset (&in6, 0, sizeof (in6)); + memcpy (in6.s6_addr, ipv6_reach->prefix, + PSIZE (ipv6_reach->prefix_len)); + inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ); + if (mtid == ISIS_MT_IPV4_UNICAST) + { + if ((ipv6_reach->control_info & + CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL) + vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s", + ntohl (ipv6_reach->metric), + buff, ipv6_reach->prefix_len, VTY_NEWLINE); + else + vty_out (vty, " Metric : %-8d IPv6-External : %s/%d%s", + ntohl (ipv6_reach->metric), + buff, ipv6_reach->prefix_len, VTY_NEWLINE); + } + else + { + if ((ipv6_reach->control_info & + CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL) + vty_out (vty, " Metric : %-8d IPv6-MT-Int : %s/%d %s%s", + ntohl (ipv6_reach->metric), + buff, ipv6_reach->prefix_len, + isis_mtid2str(mtid), VTY_NEWLINE); + else + vty_out (vty, " Metric : %-8d IPv6-MT-Ext : %s/%d %s%s", + ntohl (ipv6_reach->metric), + buff, ipv6_reach->prefix_len, + isis_mtid2str(mtid), VTY_NEWLINE); + } + } +} + +static void +lsp_print_mt_ipv4_reach(struct list *list, struct vty *vty, uint16_t mtid) +{ + struct listnode *node; + struct te_ipv4_reachability *te_ipv4_reach; + + for (ALL_LIST_ELEMENTS_RO (list, node, te_ipv4_reach)) + { + if (mtid == ISIS_MT_IPV4_UNICAST) + { + /* FIXME: There should be better way to output this stuff. */ + vty_out (vty, " Metric : %-8d IPv4-Extended : %s/%d%s", + ntohl (te_ipv4_reach->te_metric), + inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start, + te_ipv4_reach->control)), + te_ipv4_reach->control & 0x3F, VTY_NEWLINE); + } + else + { + /* FIXME: There should be better way to output this stuff. */ + vty_out (vty, " Metric : %-8d IPv4-MT : %s/%d %s%s", + ntohl (te_ipv4_reach->te_metric), + inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start, + te_ipv4_reach->control)), + te_ipv4_reach->control & 0x3F, + isis_mtid2str(mtid), VTY_NEWLINE); + } + } +} + void lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost) { @@ -865,12 +938,10 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost) struct is_neigh *is_neigh; struct ipv4_reachability *ipv4_reach; struct in_addr *ipv4_addr; - struct te_ipv4_reachability *te_ipv4_reach; - struct ipv6_reachability *ipv6_reach; struct mt_router_info *mt_router_info; + struct tlv_mt_ipv6_reachs *mt_ipv6_reachs; struct tlv_mt_neighbors *mt_is_neigh; - struct in6_addr in6; - u_char buff[BUFSIZ]; + struct tlv_mt_ipv4_reachs *mt_ipv4_reachs; u_char LSPid[255]; u_char hostname[255]; u_char ipv4_reach_prefix[20]; @@ -985,25 +1056,14 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost) ipv4_reach->metrics.metric_default, ipv4_reach_prefix, ipv4_reach_mask, VTY_NEWLINE); } - + /* IPv6 tlv */ - if (lsp->tlv_data.ipv6_reachs) - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, lnode, ipv6_reach)) - { - memset (&in6, 0, sizeof (in6)); - memcpy (in6.s6_addr, ipv6_reach->prefix, - PSIZE (ipv6_reach->prefix_len)); - inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ); - if ((ipv6_reach->control_info & - CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL) - vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s", - ntohl (ipv6_reach->metric), - buff, ipv6_reach->prefix_len, VTY_NEWLINE); - else - vty_out (vty, " Metric : %-8d IPv6-External : %s/%d%s", - ntohl (ipv6_reach->metric), - buff, ipv6_reach->prefix_len, VTY_NEWLINE); - } + lsp_print_mt_ipv6_reach(lsp->tlv_data.ipv6_reachs, vty, + ISIS_MT_IPV4_UNICAST); + + /* MT IPv6 reachability tlv */ + for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.mt_ipv6_reachs, lnode, mt_ipv6_reachs)) + lsp_print_mt_ipv6_reach(mt_ipv6_reachs->list, vty, mt_ipv6_reachs->mtid); /* TE IS neighbor tlv */ lsp_print_mt_reach(lsp->tlv_data.te_is_neighs, vty, @@ -1014,17 +1074,13 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost) lsp_print_mt_reach(mt_is_neigh->list, vty, dynhost, mt_is_neigh->mtid); /* TE IPv4 tlv */ - if (lsp->tlv_data.te_ipv4_reachs) - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, lnode, - te_ipv4_reach)) - { - /* FIXME: There should be better way to output this stuff. */ - vty_out (vty, " Metric : %-8d IPv4-Extended : %s/%d%s", - ntohl (te_ipv4_reach->te_metric), - inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start, - te_ipv4_reach->control)), - te_ipv4_reach->control & 0x3F, VTY_NEWLINE); - } + lsp_print_mt_ipv4_reach(lsp->tlv_data.te_ipv4_reachs, vty, + ISIS_MT_IPV4_UNICAST); + + /* MT IPv4 reachability tlv */ + for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.mt_ipv4_reachs, lnode, mt_ipv4_reachs)) + lsp_print_mt_ipv4_reach(mt_ipv4_reachs->list, vty, mt_ipv4_reachs->mtid); + vty_out (vty, "%s", VTY_NEWLINE); return; @@ -1292,6 +1348,24 @@ lsp_build_ext_reach_ipv4(struct isis_lsp *lsp, struct isis_area *area, } } +static struct list * +tlv_get_ipv6_reach_list(struct isis_area *area, struct tlvs *tlv_data) +{ + uint16_t mtid = isis_area_ipv6_topology(area); + if (mtid == ISIS_MT_IPV4_UNICAST) + { + if (!tlv_data->ipv6_reachs) + { + tlv_data->ipv6_reachs = list_new(); + tlv_data->ipv6_reachs->del = free_tlv; + } + return tlv_data->ipv6_reachs; + } + + struct tlv_mt_ipv6_reachs *reachs = tlvs_get_mt_ipv6_reachs(tlv_data, mtid); + return reachs->list; +} + static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area, struct tlvs *tlv_data) @@ -1301,6 +1375,7 @@ lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area, struct prefix_ipv6 *ipv6; struct isis_ext_info *info; struct ipv6_reachability *ip6reach; + struct list *reach_list = NULL; er_table = get_ext_reach(area, AF_INET6, lsp->level); if (!er_table) @@ -1314,11 +1389,9 @@ lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area, ipv6 = (struct prefix_ipv6*)&rn->p; info = rn->info; - if (tlv_data->ipv6_reachs == NULL) - { - tlv_data->ipv6_reachs = list_new(); - tlv_data->ipv6_reachs->del = free_tlv; - } + if (!reach_list) + reach_list = tlv_get_ipv6_reach_list(area, tlv_data); + ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach)); if (info->metric > MAX_WIDE_PATH_METRIC) ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC); @@ -1327,7 +1400,7 @@ lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area, ip6reach->control_info = DISTRIBUTION_EXTERNAL; ip6reach->prefix_len = ipv6->prefixlen; memcpy(ip6reach->prefix, ipv6->prefix.s6_addr, sizeof(ip6reach->prefix)); - listnode_add(tlv_data->ipv6_reachs, ip6reach); + listnode_add(reach_list, ip6reach); } } @@ -1356,6 +1429,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) struct te_ipv4_reachability *te_ipreach; struct isis_adjacency *nei; struct prefix_ipv6 *ipv6, ip6prefix; + struct list *ipv6_reachs = NULL; struct ipv6_reachability *ip6reach; struct tlvs tlv_data; struct isis_lsp *lsp0 = lsp; @@ -1591,12 +1665,9 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) if (circuit->ipv6_router && circuit->ipv6_non_link && circuit->ipv6_non_link->count > 0) { + if (!ipv6_reachs) + ipv6_reachs = tlv_get_ipv6_reach_list(area, &tlv_data); - if (tlv_data.ipv6_reachs == NULL) - { - tlv_data.ipv6_reachs = list_new (); - tlv_data.ipv6_reachs->del = free_tlv; - } for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6)) { ip6reach = @@ -1619,7 +1690,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) memcpy (ip6reach->prefix, ip6prefix.prefix.s6_addr, sizeof (ip6reach->prefix)); - listnode_add (tlv_data.ipv6_reachs, ip6reach); + listnode_add (ipv6_reachs, ip6reach); } } @@ -1804,35 +1875,62 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) lsp0, area, level); } - /* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit() - * for now. lsp_tlv_fit() needs to be fixed to deal with variable length - * TLVs (sub TLVs!). */ while (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs)) { if (lsp->tlv_data.te_ipv4_reachs == NULL) lsp->tlv_data.te_ipv4_reachs = list_new (); - lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs, - &lsp->tlv_data.te_ipv4_reachs, - TE_IPV4_REACH_LEN, area->lsp_frag_threshold, - tlv_add_te_ipv4_reachs); + _lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs, &lsp->tlv_data.te_ipv4_reachs, + area->lsp_frag_threshold, tlv_add_te_ipv4_reachs, NULL); if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); } + struct tlv_mt_ipv4_reachs *mt_ipv4_reachs; + for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv4_reachs, node, mt_ipv4_reachs)) + { + while (mt_ipv4_reachs->list && listcount(mt_ipv4_reachs->list)) + { + struct tlv_mt_ipv4_reachs *frag_mt_ipv4_reachs; + + frag_mt_ipv4_reachs = tlvs_get_mt_ipv4_reachs(&lsp->tlv_data, mt_ipv4_reachs->mtid); + _lsp_tlv_fit (lsp, &mt_ipv4_reachs->list, &frag_mt_ipv4_reachs->list, + area->lsp_frag_threshold, tlv_add_te_ipv4_reachs, + &mt_ipv4_reachs->mtid); + if (mt_ipv4_reachs->list && listcount(mt_ipv4_reachs->list)) + lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, + lsp0, area, level); + } + } + while (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs)) { if (lsp->tlv_data.ipv6_reachs == NULL) lsp->tlv_data.ipv6_reachs = list_new (); - lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs, - &lsp->tlv_data.ipv6_reachs, - IPV6_REACH_LEN, area->lsp_frag_threshold, - tlv_add_ipv6_reachs); + _lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs, &lsp->tlv_data.ipv6_reachs, + area->lsp_frag_threshold, tlv_add_ipv6_reachs, NULL); if (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); } + struct tlv_mt_ipv6_reachs *mt_ipv6_reachs; + for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv6_reachs, node, mt_ipv6_reachs)) + { + while (mt_ipv6_reachs->list && listcount(mt_ipv6_reachs->list)) + { + struct tlv_mt_ipv6_reachs *frag_mt_ipv6_reachs; + + frag_mt_ipv6_reachs = tlvs_get_mt_ipv6_reachs(&lsp->tlv_data, mt_ipv6_reachs->mtid); + _lsp_tlv_fit (lsp, &mt_ipv6_reachs->list, &frag_mt_ipv6_reachs->list, + area->lsp_frag_threshold, tlv_add_ipv6_reachs, + &mt_ipv6_reachs->mtid); + if (mt_ipv6_reachs->list && listcount(mt_ipv6_reachs->list)) + lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, + lsp0, area, level); + } + } + while (tlv_data.is_neighs && listcount (tlv_data.is_neighs)) { if (lsp->tlv_data.is_neighs == NULL) diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index e66c9d7d9c..baf72ad22c 100644 --- a/isisd/isis_mt.c +++ b/isisd/isis_mt.c @@ -34,6 +34,18 @@ DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting") DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting") DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info") DEFINE_MTYPE_STATIC(ISISD, MT_NEIGHBORS, "ISIS MT Neighbors for TLV") +DEFINE_MTYPE_STATIC(ISISD, MT_IPV4_REACHS, "ISIS MT IPv4 Reachabilities for TLV") +DEFINE_MTYPE_STATIC(ISISD, MT_IPV6_REACHS, "ISIS MT IPv6 Reachabilities for TLV") + +uint16_t isis_area_ipv6_topology(struct isis_area *area) +{ + struct isis_area_mt_setting *area_mt_setting; + area_mt_setting = area_lookup_mt_setting(area, ISIS_MT_IPV6_UNICAST); + + if (area_mt_setting && area_mt_setting->enabled) + return ISIS_MT_IPV6_UNICAST; + return ISIS_MT_IPV4_UNICAST; +} /* MT naming api */ const char *isis_mtid2str(uint16_t mtid) @@ -492,6 +504,106 @@ tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid) return neighbors; } +/* TLV MT IPv4 reach api */ +struct tlv_mt_ipv4_reachs* +tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid) +{ + return lookup_mt_setting(tlvs->mt_ipv4_reachs, mtid); +} + +static struct tlv_mt_ipv4_reachs* +tlvs_new_mt_ipv4_reachs(uint16_t mtid) +{ + struct tlv_mt_ipv4_reachs *rv; + + rv = XCALLOC(MTYPE_MT_IPV4_REACHS, sizeof(*rv)); + rv->mtid = mtid; + rv->list = list_new(); + + return rv; +}; + +static void +tlvs_free_mt_ipv4_reachs(void *arg) +{ + struct tlv_mt_ipv4_reachs *reachs = arg; + + if (reachs && reachs->list) + list_delete(reachs->list); + XFREE(MTYPE_MT_IPV4_REACHS, reachs); +} + +static void +tlvs_add_mt_ipv4_reachs(struct tlvs *tlvs, struct tlv_mt_ipv4_reachs *reachs) +{ + add_mt_setting(&tlvs->mt_ipv4_reachs, reachs); + tlvs->mt_ipv4_reachs->del = tlvs_free_mt_ipv4_reachs; +} + +struct tlv_mt_ipv4_reachs* +tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid) +{ + struct tlv_mt_ipv4_reachs *reachs; + + reachs = tlvs_lookup_mt_ipv4_reachs(tlvs, mtid); + if (!reachs) + { + reachs = tlvs_new_mt_ipv4_reachs(mtid); + tlvs_add_mt_ipv4_reachs(tlvs, reachs); + } + return reachs; +} + +/* TLV MT IPv6 reach api */ +struct tlv_mt_ipv6_reachs* +tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid) +{ + return lookup_mt_setting(tlvs->mt_ipv6_reachs, mtid); +} + +static struct tlv_mt_ipv6_reachs* +tlvs_new_mt_ipv6_reachs(uint16_t mtid) +{ + struct tlv_mt_ipv6_reachs *rv; + + rv = XCALLOC(MTYPE_MT_IPV6_REACHS, sizeof(*rv)); + rv->mtid = mtid; + rv->list = list_new(); + + return rv; +}; + +static void +tlvs_free_mt_ipv6_reachs(void *arg) +{ + struct tlv_mt_ipv6_reachs *reachs = arg; + + if (reachs && reachs->list) + list_delete(reachs->list); + XFREE(MTYPE_MT_IPV6_REACHS, reachs); +} + +static void +tlvs_add_mt_ipv6_reachs(struct tlvs *tlvs, struct tlv_mt_ipv6_reachs *reachs) +{ + add_mt_setting(&tlvs->mt_ipv6_reachs, reachs); + tlvs->mt_ipv6_reachs->del = tlvs_free_mt_ipv6_reachs; +} + +struct tlv_mt_ipv6_reachs* +tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid) +{ + struct tlv_mt_ipv6_reachs *reachs; + + reachs = tlvs_lookup_mt_ipv6_reachs(tlvs, mtid); + if (!reachs) + { + reachs = tlvs_new_mt_ipv6_reachs(mtid); + tlvs_add_mt_ipv6_reachs(tlvs, reachs); + } + return reachs; +} + static void mt_set_add(uint16_t **mt_set, unsigned int *size, unsigned int *index, uint16_t mtid) diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h index 313e992b4a..4c991dc5c9 100644 --- a/isisd/isis_mt.h +++ b/isisd/isis_mt.h @@ -71,6 +71,16 @@ struct tlv_mt_neighbors { struct list *list; }; +struct tlv_mt_ipv4_reachs { + ISIS_MT_INFO_FIELDS + struct list *list; +}; + +struct tlv_mt_ipv6_reachs { + ISIS_MT_INFO_FIELDS + struct list *list; +}; + const char *isis_mtid2str(uint16_t mtid); uint16_t isis_str2mtid(const char *name); @@ -80,9 +90,17 @@ struct isis_circuit; struct tlvs; struct te_is_neigh; +uint16_t isis_area_ipv6_topology(struct isis_area *area); + struct tlv_mt_neighbors* tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid); struct tlv_mt_neighbors* tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid); +struct tlv_mt_ipv4_reachs* tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid); +struct tlv_mt_ipv4_reachs* tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid); + +struct tlv_mt_ipv6_reachs* tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid); +struct tlv_mt_ipv6_reachs* tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid); + struct isis_area_mt_setting* area_lookup_mt_setting(struct isis_area *area, uint16_t mtid); struct isis_area_mt_setting* area_new_mt_setting(struct isis_area *area, diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c index 41c861bf58..b033e35a2e 100644 --- a/isisd/isis_tlv.c +++ b/isisd/isis_tlv.c @@ -86,43 +86,57 @@ free_tlvs (struct tlvs *tlvs) list_delete (tlvs->ipv4_ext_reachs); if (tlvs->te_ipv4_reachs) list_delete (tlvs->te_ipv4_reachs); + if (tlvs->mt_ipv4_reachs) + list_delete (tlvs->mt_ipv4_reachs); if (tlvs->ipv6_addrs) list_delete (tlvs->ipv6_addrs); if (tlvs->ipv6_reachs) list_delete (tlvs->ipv6_reachs); + if (tlvs->mt_ipv6_reachs) + list_delete (tlvs->mt_ipv6_reachs); memset (tlvs, 0, sizeof (struct tlvs)); return; } +static int +parse_mtid(uint16_t *mtid, bool read_mtid, + unsigned int *length, u_char **pnt) +{ + if (!read_mtid) + { + *mtid = ISIS_MT_IPV4_UNICAST; + return ISIS_OK; + } + + uint16_t mtid_buf; + + if (*length < sizeof(mtid_buf)) + { + zlog_warn("ISIS-TLV: mt tlv too short to contain MT id"); + return ISIS_WARNING; + } + + memcpy(&mtid_buf, *pnt, sizeof(mtid_buf)); + *pnt += sizeof(mtid_buf); + *length -= sizeof(mtid_buf); + + *mtid = ntohs(mtid_buf) & ISIS_MT_MASK; + return ISIS_OK; +} + static int parse_mt_is_neighs(struct tlvs *tlvs, bool read_mtid, unsigned int length, u_char *pnt) { struct list *neigh_list; uint16_t mtid; + int rv; - if (read_mtid) - { - uint16_t mtid_buf; - - if (length < sizeof(mtid_buf)) - { - zlog_warn("ISIS-TLV: mt tlv too short to contain MT id"); - return ISIS_WARNING; - } - - memcpy(&mtid_buf, pnt, sizeof(mtid_buf)); - pnt += sizeof(mtid_buf); - length -= sizeof(mtid_buf); - - mtid = ntohs(mtid_buf) & ISIS_MT_MASK; - } - else - { - mtid = ISIS_MT_IPV4_UNICAST; - } + rv = parse_mtid(&mtid, read_mtid, &length, &pnt); + if (rv != ISIS_OK) + return rv; if (mtid == ISIS_MT_IPV4_UNICAST) { @@ -173,6 +187,192 @@ parse_mt_is_neighs(struct tlvs *tlvs, bool read_mtid, return ISIS_OK; } +static int +parse_mt_ipv4_reachs(struct tlvs *tlvs, bool read_mtid, + unsigned int length, u_char *pnt) +{ + struct list *reach_list; + uint16_t mtid; + int rv; + + rv = parse_mtid(&mtid, read_mtid, &length, &pnt); + if (rv != ISIS_OK) + return rv; + + if (mtid == ISIS_MT_IPV4_UNICAST) + { + if (!tlvs->te_ipv4_reachs) + { + tlvs->te_ipv4_reachs = list_new(); + tlvs->te_ipv4_reachs->del = free_tlv; + } + reach_list = tlvs->te_ipv4_reachs; + } + else + { + struct tlv_mt_ipv4_reachs *reachs; + + reachs = tlvs_get_mt_ipv4_reachs(tlvs, mtid); + reachs->list->del = free_tlv; + reach_list = reachs->list; + } + + while (length >= 5) /* Metric + Control */ + { + struct te_ipv4_reachability *reach = XCALLOC(MTYPE_ISIS_TLV, TE_IPV4_REACH_LEN); + + memcpy(reach, pnt, 5); /* Metric + Control */ + pnt += 5; + length -= 5; + + unsigned char prefixlen = reach->control & 0x3F; + + if (prefixlen > IPV4_MAX_BITLEN) + { + zlog_warn("ISIS-TLV: invalid IPv4 extended reachability prefix length %d", prefixlen); + XFREE(MTYPE_ISIS_TLV, reach); + return ISIS_WARNING; + } + + if (length < (unsigned int)PSIZE(prefixlen)) + { + zlog_warn("ISIS-TLV: invalid IPv4 extended reachability prefix too long for tlv"); + XFREE(MTYPE_ISIS_TLV, reach); + return ISIS_WARNING; + } + + memcpy(&reach->prefix_start, pnt, PSIZE(prefixlen)); + pnt += PSIZE(prefixlen); + length -= PSIZE(prefixlen); + + if (reach->control & TE_IPV4_HAS_SUBTLV) + { + if (length < 1) + { + zlog_warn("ISIS-TLV: invalid IPv4 extended reachability SubTLV missing"); + XFREE(MTYPE_ISIS_TLV, reach); + return ISIS_WARNING; + } + + u_char subtlv_len = *pnt; + pnt++; + length--; + + if (length < subtlv_len) + { + zlog_warn("ISIS-TLV: invalid IPv4 extended reachability SubTLVs have oversize"); + XFREE(MTYPE_ISIS_TLV, reach); + return ISIS_WARNING; + } + + /* Skip Sub-TLVs for now */ + pnt += subtlv_len; + length -= subtlv_len; + } + listnode_add(reach_list, reach); + } + + if (length) + { + zlog_warn("ISIS-TLV: TE/MT ipv4 reachability TLV has trailing data"); + return ISIS_WARNING; + } + + return ISIS_OK; +} + +static int +parse_mt_ipv6_reachs(struct tlvs *tlvs, bool read_mtid, + unsigned int length, u_char *pnt) +{ + struct list *reach_list; + uint16_t mtid; + int rv; + + rv = parse_mtid(&mtid, read_mtid, &length, &pnt); + if (rv != ISIS_OK) + return rv; + + if (mtid == ISIS_MT_IPV4_UNICAST) + { + if (!tlvs->ipv6_reachs) + { + tlvs->ipv6_reachs = list_new(); + tlvs->ipv6_reachs->del = free_tlv; + } + reach_list = tlvs->ipv6_reachs; + } + else + { + struct tlv_mt_ipv6_reachs *reachs; + + reachs = tlvs_get_mt_ipv6_reachs(tlvs, mtid); + reachs->list->del = free_tlv; + reach_list = reachs->list; + } + + while (length >= 6) /* Metric + Control + Prefixlen */ + { + struct ipv6_reachability *reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*reach)); + + memcpy(reach, pnt, 6); /* Metric + Control + Prefixlen */ + pnt += 6; + length -= 6; + + if (reach->prefix_len > IPV6_MAX_BITLEN) + { + zlog_warn("ISIS-TLV: invalid IPv6 reachability prefix length %d", reach->prefix_len); + XFREE(MTYPE_ISIS_TLV, reach); + return ISIS_WARNING; + } + + if (length < (unsigned int)PSIZE(reach->prefix_len)) + { + zlog_warn("ISIS-TLV: invalid IPv6 reachability prefix too long for tlv"); + XFREE(MTYPE_ISIS_TLV, reach); + return ISIS_WARNING; + } + + memcpy(&reach->prefix, pnt, PSIZE(reach->prefix_len)); + pnt += PSIZE(reach->prefix_len); + length -= PSIZE(reach->prefix_len); + + if (reach->control_info & CTRL_INFO_SUBTLVS) + { + if (length < 1) + { + zlog_warn("ISIS-TLV: invalid IPv6 reachability SubTLV missing"); + XFREE(MTYPE_ISIS_TLV, reach); + return ISIS_WARNING; + } + + u_char subtlv_len = *pnt; + pnt++; + length--; + + if (length < subtlv_len) + { + zlog_warn("ISIS-TLV: invalid IPv6 reachability SubTLVs have oversize"); + XFREE(MTYPE_ISIS_TLV, reach); + return ISIS_WARNING; + } + + /* Skip Sub-TLVs for now */ + pnt += subtlv_len; + length -= subtlv_len; + } + listnode_add(reach_list, reach); + } + + if (length) + { + zlog_warn("ISIS-TLV: (MT) IPv6 reachability TLV has trailing data"); + return ISIS_WARNING; + } + + return ISIS_OK; +} + /* * Parses the tlvs found in the variant length part of the PDU. * Caller tells with flags in "expected" which TLV's it is interested in. @@ -189,12 +389,9 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, struct lsp_entry *lsp_entry; struct in_addr *ipv4_addr; struct ipv4_reachability *ipv4_reach; - struct te_ipv4_reachability *te_ipv4_reach; struct in6_addr *ipv6_addr; - struct ipv6_reachability *ipv6_reach; - int prefix_octets; int value_len, retval = ISIS_OK; - u_char *start = stream, *pnt = stream, *endpnt; + u_char *start = stream, *pnt = stream; *found = 0; memset (tlvs, 0, sizeof (struct tlvs)); @@ -629,71 +826,25 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, break; case TE_IPV4_REACHABILITY: - /* +-------+-------+-------+-------+-------+-------+-------+-------+ - * | TE Metric | 4 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | U/D | sTLV? | Prefix Mask Len | 1 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Prefix | 0-4 - * +---------------------------------------------------------------+ - * | sub tlvs | - * +---------------------------------------------------------------+ - * : : - */ *found |= TLVFLAG_TE_IPV4_REACHABILITY; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d", - areatag, length); + areatag, length); #endif /* EXTREME_TLV_DEBUG */ - endpnt = pnt + length; if (*expected & TLVFLAG_TE_IPV4_REACHABILITY) - { - while (length > value_len) - { - te_ipv4_reach = (struct te_ipv4_reachability *) pnt; - if ((te_ipv4_reach->control & 0x3F) > IPV4_MAX_BITLEN) - { - zlog_warn ("ISIS-TLV (%s): invalid IPv4 extended reach" - "ability prefix length %d", areatag, - te_ipv4_reach->control & 0x3F); - retval = ISIS_WARNING; - break; - } - if (!tlvs->te_ipv4_reachs) - tlvs->te_ipv4_reachs = list_new (); - listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach); - - /* Metric + Control-Byte + Prefix */ - unsigned int entry_len = 5 + PSIZE(te_ipv4_reach->control & 0x3F); - value_len += entry_len; - pnt += entry_len; - - if (te_ipv4_reach->control & TE_IPV4_HAS_SUBTLV) - { - if (length <= value_len) - { - zlog_warn("ISIS-TLV (%s): invalid IPv4 extended reachability SubTLV missing", - areatag); - retval = ISIS_WARNING; - break; - } - u_char subtlv_len = *pnt; - value_len += subtlv_len + 1; - pnt += subtlv_len + 1; - if (length < value_len) - { - zlog_warn("ISIS-TLV (%s): invalid IPv4 extended reachability SubTLVs have oversize", - areatag); - retval = ISIS_WARNING; - break; - } - } - } - } - - pnt = endpnt; + retval = parse_mt_ipv4_reachs(tlvs, false, length, pnt); + pnt += length; + break; + case MT_IPV4_REACHABILITY: + *found |= TLVFLAG_TE_IPV4_REACHABILITY; +#ifdef EXTREME_TLV_DEBUG + zlog_debug ("ISIS-TLV (%s): IPv4 MT Reachability length %d", + areatag, length); +#endif /* EXTREME_TLV_DEBUG */ + if (*expected & TLVFLAG_TE_IPV4_REACHABILITY) + retval = parse_mt_ipv4_reachs(tlvs, true, length, pnt); + pnt += length; break; - case IPV6_ADDR: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * + IP version 6 address + 16 @@ -724,67 +875,25 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, break; case IPV6_REACHABILITY: - /* +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Default Metric | 4 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Control Informantion | - * +---------------------------------------------------------------+ - * | IPv6 Prefix Length |--+ - * +---------------------------------------------------------------+ | - * | IPv6 Prefix |<-+ - * +---------------------------------------------------------------+ - */ *found |= TLVFLAG_IPV6_REACHABILITY; - endpnt = pnt + length; - +#ifdef EXTREME_TLV_DEBUG + zlog_debug ("ISIS-TLV (%s): IPv6 Reachability length %d", + areatag, length); +#endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_IPV6_REACHABILITY) - { - while (length > value_len) - { - ipv6_reach = (struct ipv6_reachability *) pnt; - if (ipv6_reach->prefix_len > IPV6_MAX_BITLEN) - { - zlog_warn ("ISIS-TLV (%s): invalid IPv6 extended reach" - "ability prefix length %d", areatag, - ipv6_reach->prefix_len); - retval = ISIS_WARNING; - break; - } - - prefix_octets = ((ipv6_reach->prefix_len + 7) / 8); - value_len += prefix_octets + 6; - pnt += prefix_octets + 6; - - if (ipv6_reach->control_info & CTRL_INFO_SUBTLVS) - { - if (length <= value_len) - { - zlog_warn("ISIS-TLV (%s): invalid IPv6 extended reachability SubTLV missing", - areatag); - retval = ISIS_WARNING; - break; - } - u_char subtlv_len = *pnt; - value_len += subtlv_len + 1; - pnt += subtlv_len + 1; - if (length < value_len) - { - zlog_warn("ISIS-TLV (%s): invalid IPv6 extended reachability SubTLVs have oversize", - areatag); - retval = ISIS_WARNING; - break; - } - } - /* FIXME: sub-tlvs */ - if (!tlvs->ipv6_reachs) - tlvs->ipv6_reachs = list_new (); - listnode_add (tlvs->ipv6_reachs, ipv6_reach); - } - } - - pnt = endpnt; + retval = parse_mt_ipv6_reachs(tlvs, false, length, pnt); + pnt += length; + break; + case MT_IPV6_REACHABILITY: + *found |= TLVFLAG_IPV6_REACHABILITY; +#ifdef EXTREME_TLV_DEBUG + zlog_debug ("ISIS-TLV (%s): IPv6 Reachability length %d", + areatag, length); +#endif /* EXTREME_TLV_DEBUG */ + if (*expected & TLVFLAG_IPV6_REACHABILITY) + retval = parse_mt_ipv6_reachs(tlvs, true, length, pnt); + pnt += length; break; - case WAY3_HELLO: /* +---------------------------------------------------------------+ * | Adjacency state | 1 @@ -1239,37 +1348,49 @@ tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream) } -int -tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream) +unsigned int +tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream, void *arg) { struct listnode *node; struct te_ipv4_reachability *te_reach; u_char value[255]; u_char *pos = value; - u_char prefix_size; - int retval; + uint16_t mtid = arg ? *(uint16_t*)arg : ISIS_MT_IPV4_UNICAST; + unsigned int consumed = 0; + size_t max_size = max_tlv_size(stream); + + if (mtid != ISIS_MT_IPV4_UNICAST) + { + uint16_t mtid_conversion = ntohs(mtid); + memcpy(pos, &mtid_conversion, sizeof(mtid_conversion)); + pos += sizeof(mtid_conversion); + } for (ALL_LIST_ELEMENTS_RO (te_ipv4_reachs, node, te_reach)) { - prefix_size = ((((te_reach->control & 0x3F) - 1) >> 3) + 1); + unsigned char prefixlen = te_reach->control & 0x3F; + + if ((size_t)(pos - value) + 5 + PSIZE(prefixlen) > max_size) + break; - if (pos - value + (5 + prefix_size) > 255) - { - retval = - add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream); - if (retval != ISIS_OK) - return retval; - pos = value; - } *(u_int32_t *) pos = te_reach->te_metric; pos += 4; *pos = te_reach->control; pos++; - memcpy (pos, &te_reach->prefix_start, prefix_size); - pos += prefix_size; + memcpy (pos, &te_reach->prefix_start, PSIZE(prefixlen)); + pos += PSIZE(prefixlen); + consumed++; } - return add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream); + if (consumed) + { + int rv = add_tlv ((mtid != ISIS_MT_IPV4_UNICAST) ? MT_IPV4_REACHABILITY + : TE_IPV4_REACHABILITY, + pos - value, value, stream); + assert(rv == ISIS_OK); + } + + return consumed; } int @@ -1297,36 +1418,49 @@ tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream) return add_tlv (IPV6_ADDR, pos - value, value, stream); } -int -tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream) +unsigned int +tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream, void *arg) { struct listnode *node; struct ipv6_reachability *ip6reach; u_char value[255]; u_char *pos = value; - int retval, prefix_octets; + uint16_t mtid = arg ? *(uint16_t*)arg : ISIS_MT_IPV4_UNICAST; + unsigned int consumed = 0; + size_t max_size = max_tlv_size(stream); + + if (mtid != ISIS_MT_IPV4_UNICAST) + { + uint16_t mtid_conversion = ntohs(mtid); + memcpy(pos, &mtid_conversion, sizeof(mtid_conversion)); + pos += sizeof(mtid_conversion); + } for (ALL_LIST_ELEMENTS_RO (ipv6_reachs, node, ip6reach)) { - if (pos - value + IPV6_MAX_BYTELEN + 6 > 255) - { - retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream); - if (retval != ISIS_OK) - return retval; - pos = value; - } - *(uint32_t *) pos = ip6reach->metric; + if ((size_t)(pos - value) + 6 + PSIZE(ip6reach->prefix_len) > max_size) + break; + + *(uint32_t *)pos = ip6reach->metric; pos += 4; *pos = ip6reach->control_info; pos++; - prefix_octets = ((ip6reach->prefix_len + 7) / 8); *pos = ip6reach->prefix_len; pos++; - memcpy (pos, ip6reach->prefix, prefix_octets); - pos += prefix_octets; + memcpy (pos, ip6reach->prefix, PSIZE(ip6reach->prefix_len)); + pos += PSIZE(ip6reach->prefix_len); + consumed++; } - return add_tlv (IPV6_REACHABILITY, pos - value, value, stream); + if (consumed) + { + int rv = add_tlv ((mtid != ISIS_MT_IPV4_UNICAST) ? MT_IPV6_REACHABILITY + : IPV6_REACHABILITY, + pos - value, value, stream); + assert(rv == ISIS_OK); + } + + return consumed; } int diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h index f3c04baf54..2135f5071f 100644 --- a/isisd/isis_tlv.h +++ b/isisd/isis_tlv.h @@ -114,7 +114,9 @@ #define MT_IS_NEIGHBOURS 222 #define MT_ROUTER_INFORMATION 229 #define IPV6_ADDR 232 +#define MT_IPV4_REACHABILITY 235 #define IPV6_REACHABILITY 236 +#define MT_IPV6_REACHABILITY 237 #define WAY3_HELLO 240 #define ROUTER_INFORMATION 242 @@ -282,8 +284,10 @@ struct tlvs struct list *ipv4_int_reachs; struct list *ipv4_ext_reachs; struct list *te_ipv4_reachs; + struct list *mt_ipv4_reachs; struct list *ipv6_addrs; struct list *ipv6_reachs; + struct list *mt_ipv6_reachs; struct isis_passwd auth_info; }; @@ -339,9 +343,9 @@ int tlv_add_dynamic_hostname (struct hostname *hostname, int tlv_add_lsp_entries (struct list *lsps, struct stream *stream); int tlv_add_ipv4_int_reachs (struct list *ipv4_reachs, struct stream *stream); int tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream); -int tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream); +unsigned int tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream, void *arg); int tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream); -int tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream); +unsigned int tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream, void *arg); int tlv_add_padding (struct stream *stream); From 2b67862ccac99737913a674b3e9138a49a44421d Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 27 Apr 2017 13:56:47 +0200 Subject: [PATCH 50/55] isisd: make spf MT aware Signed-off-by: Christian Franke --- isisd/isis_mt.c | 16 ++++++++ isisd/isis_mt.h | 3 ++ isisd/isis_spf.c | 105 +++++++++++++++++++++++++++++++++++++++-------- isisd/isis_spf.h | 1 + 4 files changed, 107 insertions(+), 18 deletions(-) diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index baf72ad22c..42e7b57aa4 100644 --- a/isisd/isis_mt.c +++ b/isisd/isis_mt.c @@ -447,6 +447,15 @@ tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable, return changed; } +bool +adj_has_mt(struct isis_adjacency *adj, uint16_t mtid) +{ + for (unsigned int i = 0; i < adj->mt_count; i++) + if (adj->mt_set[i] == mtid) + return true; + return false; +} + void adj_mt_finish(struct isis_adjacency *adj) { @@ -454,6 +463,13 @@ adj_mt_finish(struct isis_adjacency *adj) adj->mt_count = 0; } +/* TLV Router info api */ +struct mt_router_info* +tlvs_lookup_mt_router_info(struct tlvs *tlvs, uint16_t mtid) +{ + return lookup_mt_setting(tlvs->mt_router_info, mtid); +} + /* TLV MT Neighbors api */ struct tlv_mt_neighbors* tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid) diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h index 4c991dc5c9..d4dc4c6f2a 100644 --- a/isisd/isis_mt.h +++ b/isisd/isis_mt.h @@ -92,6 +92,8 @@ struct te_is_neigh; uint16_t isis_area_ipv6_topology(struct isis_area *area); +struct mt_router_info* tlvs_lookup_mt_router_info(struct tlvs *tlvs, uint16_t mtid); + struct tlv_mt_neighbors* tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid); struct tlv_mt_neighbors* tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid); @@ -135,6 +137,7 @@ struct isis_circuit_mt_setting** circuit_mt_settings(struct isis_circuit *circui unsigned int *mt_count); bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable, struct isis_adjacency *adj); +bool adj_has_mt(struct isis_adjacency *adj, uint16_t mtid); void adj_mt_finish(struct isis_adjacency *adj); void tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit, int level, struct te_is_neigh *neigh); diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 8dd1dc981f..d85f08f50b 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -51,6 +51,7 @@ #include "isis_spf.h" #include "isis_route.h" #include "isis_csm.h" +#include "isis_mt.h" DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info"); @@ -683,8 +684,14 @@ isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, struct prefix prefix; struct ipv6_reachability *ip6reach; static const u_char null_sysid[ISIS_SYS_ID_LEN]; + struct mt_router_info *mt_router_info = NULL; - if (!pseudo_lsp && !speaks (lsp->tlv_data.nlpids, spftree->family)) + if (spftree->mtid != ISIS_MT_IPV4_UNICAST) + mt_router_info = tlvs_lookup_mt_router_info(&lsp->tlv_data, spftree->mtid); + + if (!pseudo_lsp + && (spftree->mtid == ISIS_MT_IPV4_UNICAST && !speaks(lsp->tlv_data.nlpids, spftree->family)) + && !mt_router_info) return ISIS_OK; lspfragloop: @@ -699,9 +706,12 @@ lspfragloop: #endif /* EXTREME_DEBUG */ /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */ - if (pseudo_lsp || !ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits)) + if (pseudo_lsp + || (spftree->mtid == ISIS_MT_IPV4_UNICAST && !ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits)) + || (mt_router_info && !mt_router_info->overload)) + { - if (lsp->tlv_data.is_neighs) + if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) { for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh)) { @@ -717,10 +727,20 @@ lspfragloop: (void *) is_neigh->neigh_id, dist, depth + 1, parent); } } - if (lsp->tlv_data.te_is_neighs) - { - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, - te_is_neigh)) + + struct list *te_is_neighs = NULL; + if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) + { + te_is_neighs = lsp->tlv_data.te_is_neighs; + } + else + { + struct tlv_mt_neighbors *mt_neighbors; + mt_neighbors = tlvs_lookup_mt_neighbors(&lsp->tlv_data, spftree->mtid); + if (mt_neighbors) + te_is_neighs = mt_neighbors->list; + } + for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh)) { if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) continue; @@ -731,10 +751,11 @@ lspfragloop: : VTYPE_NONPSEUDO_TE_IS, (void *) te_is_neigh->neigh_id, dist, depth + 1, parent); } - } } - if (!pseudo_lsp && spftree->family == AF_INET) + if (!pseudo_lsp + && spftree->family == AF_INET + && spftree->mtid == ISIS_MT_IPV4_UNICAST) { struct list *reachs[] = {lsp->tlv_data.ipv4_int_reachs, lsp->tlv_data.ipv4_ext_reachs}; @@ -754,9 +775,26 @@ lspfragloop: parent); } } + } - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, - node, te_ipv4_reach)) + if (!pseudo_lsp && spftree->family == AF_INET) + { + struct list *ipv4reachs = NULL; + + if (spftree->mtid == ISIS_MT_IPV4_UNICAST) + { + ipv4reachs = lsp->tlv_data.te_ipv4_reachs; + } + else + { + struct tlv_mt_ipv4_reachs *mt_reachs; + mt_reachs = tlvs_lookup_mt_ipv4_reachs(&lsp->tlv_data, spftree->mtid); + if (mt_reachs) + ipv4reachs = mt_reachs->list; + } + + prefix.family = AF_INET; + for (ALL_LIST_ELEMENTS_RO (ipv4reachs, node, te_ipv4_reach)) { assert ((te_ipv4_reach->control & 0x3F) <= IPV4_MAX_BITLEN); @@ -770,10 +808,25 @@ lspfragloop: } } - if (!pseudo_lsp && spftree->family == AF_INET6) + if (!pseudo_lsp + && spftree->family == AF_INET6) { + struct list *ipv6reachs = NULL; + + if (spftree->mtid == ISIS_MT_IPV4_UNICAST) + { + ipv6reachs = lsp->tlv_data.ipv6_reachs; + } + else + { + struct tlv_mt_ipv6_reachs *mt_reachs; + mt_reachs = tlvs_lookup_mt_ipv6_reachs(&lsp->tlv_data, spftree->mtid); + if (mt_reachs) + ipv6reachs = mt_reachs->list; + } + prefix.family = AF_INET6; - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, node, ip6reach)) + for (ALL_LIST_ELEMENTS_RO (ipv6reachs, node, ip6reach)) { assert (ip6reach->prefix_len <= IPV6_MAX_BITLEN); @@ -820,9 +873,13 @@ isis_spf_preload_tent (struct isis_spftree *spftree, u_char lsp_id[ISIS_SYS_ID_LEN + 2]; static u_char null_lsp_id[ISIS_SYS_ID_LEN + 2]; struct prefix_ipv6 *ipv6; + struct isis_circuit_mt_setting *circuit_mt; for (ALL_LIST_ELEMENTS_RO (spftree->area->circuit_list, cnode, circuit)) { + circuit_mt = circuit_lookup_mt_setting(circuit, spftree->mtid); + if (circuit_mt && !circuit_mt->enabled) + continue; if (circuit->state != C_STATE_UP) continue; if (!(circuit->is_type & spftree->level)) @@ -876,8 +933,10 @@ isis_spf_preload_tent (struct isis_spftree *spftree, } for (ALL_LIST_ELEMENTS_RO (adj_list, anode, adj)) { - if (!speaks (&adj->nlpids, spftree->family)) - continue; + if (!adj_has_mt(adj, spftree->mtid)) + continue; + if (spftree->mtid == ISIS_MT_IPV4_UNICAST && !speaks (&adj->nlpids, spftree->family)) + continue; switch (adj->sys_type) { case ISIS_SYSTYPE_ES: @@ -953,6 +1012,8 @@ isis_spf_preload_tent (struct isis_spftree *spftree, adj = circuit->u.p2p.neighbor; if (!adj) continue; + if (!adj_has_mt(adj, spftree->mtid)) + continue; switch (adj->sys_type) { case ISIS_SYSTYPE_ES: @@ -966,7 +1027,7 @@ isis_spf_preload_tent (struct isis_spftree *spftree, memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (lsp_id) = 0; LSP_FRAGMENT (lsp_id) = 0; - if (speaks (&adj->nlpids, spftree->family)) + if (spftree->mtid != ISIS_MT_IPV4_UNICAST || speaks (&adj->nlpids, spftree->family)) isis_spf_add_local (spftree, spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS : VTYPE_NONPSEUDO_TE_IS, @@ -1029,13 +1090,14 @@ add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex) } static void -init_spt (struct isis_spftree *spftree, int level, int family) +init_spt (struct isis_spftree *spftree, int mtid, int level, int family) { spftree->tents->del = spftree->paths->del = (void (*)(void *)) isis_vertex_del; list_delete_all_node (spftree->tents); list_delete_all_node (spftree->paths); spftree->tents->del = spftree->paths->del = NULL; + spftree->mtid = mtid; spftree->level = level; spftree->family = family; return; @@ -1054,6 +1116,7 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid) struct route_table *table = NULL; struct timeval time_now; unsigned long long start_time, end_time; + uint16_t mtid; /* Get time that can't roll backwards. */ monotime(&time_now); @@ -1075,10 +1138,16 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid) isis_route_invalidate_table (area, table); + /* We only support ipv4-unicast and ipv6-unicast as topologies for now */ + if (family == AF_INET6) + mtid = isis_area_ipv6_topology(area); + else + mtid = ISIS_MT_IPV4_UNICAST; + /* * C.2.5 Step 0 */ - init_spt (spftree, level, family); + init_spt (spftree, mtid, level, family); /* a) */ root_vertex = isis_spf_add_root (spftree, sysid); /* b) */ diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index 64582c62c9..9f06dbb602 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -71,6 +71,7 @@ struct isis_spftree time_t last_run_timestamp; /* last run timestamp for scheduling */ time_t last_run_duration; /* last run duration in msec */ + uint16_t mtid; int family; int level; }; From 1189d95fcab50132623cb8f8c25f78ed68ec36e2 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 3 Mar 2017 19:01:49 +0000 Subject: [PATCH 51/55] lib: make thread.c pthread-safe This change introduces synchronization mechanisms to thread.c in order to allow safe concurrent use. Thread.c should now be threadstafe with respect to: * struct thread * struct thread_master Calls into thread.c for operations upon data of this type should not require external synchronization. Signed-off-by: Quentin Young --- lib/thread.c | 292 ++++++++++++++++++++++++++++++++++----------------- lib/thread.h | 3 + 2 files changed, 200 insertions(+), 95 deletions(-) diff --git a/lib/thread.c b/lib/thread.c index e707fc584c..3f7ab12b7f 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -41,7 +41,7 @@ DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats") #include #endif -/* Relative time, since startup */ +static pthread_mutex_t cpu_record_mtx = PTHREAD_MUTEX_INITIALIZER; static struct hash *cpu_record = NULL; static unsigned long @@ -137,9 +137,14 @@ cpu_record_print(struct vty *vty, thread_type filter) vty_out(vty, "Active Runtime(ms) Invoked Avg uSec Max uSecs"); vty_out(vty, " Avg uSec Max uSecs"); vty_out(vty, " Type Thread%s", VTY_NEWLINE); - hash_iterate(cpu_record, - (void(*)(struct hash_backet*,void*))cpu_record_hash_print, - args); + + pthread_mutex_lock (&cpu_record_mtx); + { + hash_iterate(cpu_record, + (void(*)(struct hash_backet*,void*))cpu_record_hash_print, + args); + } + pthread_mutex_unlock (&cpu_record_mtx); if (tmp.total_calls > 0) vty_out_cpu_thread_history(vty, &tmp); @@ -216,16 +221,25 @@ cpu_record_hash_clear (struct hash_backet *bucket, if ( !(a->types & *filter) ) return; - hash_release (cpu_record, bucket->data); + pthread_mutex_lock (&cpu_record_mtx); + { + hash_release (cpu_record, bucket->data); + } + pthread_mutex_unlock (&cpu_record_mtx); } static void cpu_record_clear (thread_type filter) { thread_type *tmp = &filter; - hash_iterate (cpu_record, - (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear, - tmp); + + pthread_mutex_lock (&cpu_record_mtx); + { + hash_iterate (cpu_record, + (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear, + tmp); + } + pthread_mutex_unlock (&cpu_record_mtx); } DEFUN (clear_thread_cpu, @@ -326,16 +340,20 @@ thread_master_create (void) getrlimit(RLIMIT_NOFILE, &limit); - if (cpu_record == NULL) - cpu_record - = hash_create ((unsigned int (*) (void *))cpu_record_hash_key, - (int (*) (const void *, const void *))cpu_record_hash_cmp); + pthread_mutex_lock (&cpu_record_mtx); + { + if (cpu_record == NULL) + cpu_record = hash_create ((unsigned int (*) (void *))cpu_record_hash_key, + (int (*) (const void *, const void *)) + cpu_record_hash_cmp); + } + pthread_mutex_unlock (&cpu_record_mtx); rv = XCALLOC (MTYPE_THREAD_MASTER, sizeof (struct thread_master)); if (rv == NULL) - { - return NULL; - } + return NULL; + + pthread_mutex_init (&rv->mtx, NULL); rv->fd_limit = (int)limit.rlim_cur; rv->read = XCALLOC (MTYPE_THREAD, sizeof (struct thread *) * rv->fd_limit); @@ -498,11 +516,16 @@ thread_queue_free (struct thread_master *m, struct pqueue *queue) void thread_master_free_unused (struct thread_master *m) { - struct thread *t; - while ((t = thread_trim_head(&m->unuse)) != NULL) - { - XFREE(MTYPE_THREAD, t); - } + pthread_mutex_lock (&m->mtx); + { + struct thread *t; + while ((t = thread_trim_head(&m->unuse)) != NULL) + { + pthread_mutex_destroy (&t->mtx); + XFREE(MTYPE_THREAD, t); + } + } + pthread_mutex_unlock (&m->mtx); } /* Stop thread scheduler. */ @@ -516,25 +539,37 @@ thread_master_free (struct thread_master *m) thread_list_free (m, &m->ready); thread_list_free (m, &m->unuse); thread_queue_free (m, m->background); + pthread_mutex_destroy (&m->mtx); #if defined(HAVE_POLL) XFREE (MTYPE_THREAD_MASTER, m->handler.pfds); #endif XFREE (MTYPE_THREAD_MASTER, m); - if (cpu_record) - { - hash_clean (cpu_record, cpu_record_hash_free); - hash_free (cpu_record); - cpu_record = NULL; - } + pthread_mutex_lock (&cpu_record_mtx); + { + if (cpu_record) + { + hash_clean (cpu_record, cpu_record_hash_free); + hash_free (cpu_record); + cpu_record = NULL; + } + } + pthread_mutex_unlock (&cpu_record_mtx); } /* Return remain time in second. */ unsigned long thread_timer_remain_second (struct thread *thread) { - int64_t remain = monotime_until(&thread->u.sands, NULL) / 1000000LL; + int64_t remain; + + pthread_mutex_lock (&thread->mtx); + { + remain = monotime_until(&thread->u.sands, NULL) / 1000000LL; + } + pthread_mutex_unlock (&thread->mtx); + return remain < 0 ? 0 : remain; } @@ -545,7 +580,11 @@ struct timeval thread_timer_remain(struct thread *thread) { struct timeval remain; - monotime_until(&thread->u.sands, &remain); + pthread_mutex_lock (&thread->mtx); + { + monotime_until(&thread->u.sands, &remain); + } + pthread_mutex_unlock (&thread->mtx); return remain; } @@ -560,8 +599,11 @@ thread_get (struct thread_master *m, u_char type, if (! thread) { thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread)); + /* mutex only needs to be initialized at struct creation. */ + pthread_mutex_init (&thread->mtx, NULL); m->alloc++; } + thread->type = type; thread->add_type = type; thread->master = m; @@ -584,8 +626,12 @@ thread_get (struct thread_master *m, u_char type, { tmp.func = func; tmp.funcname = funcname; - thread->hist = hash_get (cpu_record, &tmp, - (void * (*) (void *))cpu_record_hash_alloc); + pthread_mutex_lock (&cpu_record_mtx); + { + thread->hist = hash_get (cpu_record, &tmp, + (void * (*) (void *))cpu_record_hash_alloc); + } + pthread_mutex_unlock (&cpu_record_mtx); } thread->hist->total_active++; thread->func = func; @@ -703,36 +749,39 @@ funcname_thread_add_read_write (int dir, struct thread_master *m, { struct thread *thread = NULL; -#if !defined(HAVE_POLL) - thread_fd_set *fdset = NULL; - if (dir == THREAD_READ) - fdset = &m->handler.readfd; - else - fdset = &m->handler.writefd; -#endif - + pthread_mutex_lock (&m->mtx); + { #if defined (HAVE_POLL) - thread = generic_thread_add(m, func, arg, fd, dir, debugargpass); - - if (thread == NULL) - return NULL; + thread = generic_thread_add(m, func, arg, fd, dir, debugargpass); #else - if (FD_ISSET (fd, fdset)) - { - zlog_warn ("There is already %s fd [%d]", - (dir == THREAD_READ) ? "read" : "write", fd); - return NULL; - } + thread_fd_set *fdset = NULL; + if (dir == THREAD_READ) + fdset = &m->handler.readfd; + else + fdset = &m->handler.writefd; - FD_SET (fd, fdset); - thread = thread_get (m, dir, func, arg, debugargpass); + if (FD_ISSET (fd, fdset)) + { + zlog_warn ("There is already %s fd [%d]", + (dir == THREAD_READ) ? "read" : "write", fd); + } + else + { + FD_SET (fd, fdset); + thread = thread_get (m, dir, func, arg, debugargpass); + } #endif - thread->u.fd = fd; - if (dir == THREAD_READ) - thread_add_fd (m->read, thread); - else - thread_add_fd (m->write, thread); + if (thread) + { + thread->u.fd = fd; + if (dir == THREAD_READ) + thread_add_fd (m->read, thread); + else + thread_add_fd (m->write, thread); + } + } + pthread_mutex_unlock (&m->mtx); return thread; } @@ -754,7 +803,11 @@ funcname_thread_add_timer_timeval (struct thread_master *m, assert (time_relative); queue = ((type == THREAD_TIMER) ? m->timer : m->background); - thread = thread_get (m, type, func, arg, debugargpass); + pthread_mutex_lock (&m->mtx); + { + thread = thread_get (m, type, func, arg, debugargpass); + } + pthread_mutex_unlock (&m->mtx); monotime(&thread->u.sands); timeradd(&thread->u.sands, time_relative, &thread->u.sands); @@ -847,9 +900,13 @@ funcname_thread_add_event (struct thread_master *m, assert (m != NULL); - thread = thread_get (m, THREAD_EVENT, func, arg, debugargpass); - thread->u.val = val; - thread_list_add (&m->event, thread); + pthread_mutex_lock (&m->mtx); + { + thread = thread_get (m, THREAD_EVENT, func, arg, debugargpass); + thread->u.val = val; + thread_list_add (&m->event, thread); + } + pthread_mutex_unlock (&m->mtx); return thread; } @@ -880,14 +937,19 @@ thread_cancel_read_or_write (struct thread *thread, short int state) fd_clear_read_write (thread); } -/* Cancel thread from scheduler. */ +/** + * Cancel thread from scheduler. + * + * This function is *NOT* MT-safe. DO NOT call it from any other thread than + * the primary thread. + */ void thread_cancel (struct thread *thread) { struct thread_list *list = NULL; struct pqueue *queue = NULL; struct thread **thread_array = NULL; - + switch (thread->type) { case THREAD_READ: @@ -951,39 +1013,48 @@ thread_cancel_event (struct thread_master *m, void *arg) { unsigned int ret = 0; struct thread *thread; + struct thread *t; - thread = m->event.head; - while (thread) - { - struct thread *t; - - t = thread; - thread = t->next; - - if (t->arg == arg) + pthread_mutex_lock (&m->mtx); + { + thread = m->event.head; + while (thread) + { + t = thread; + pthread_mutex_lock (&t->mtx); { - ret++; - thread_list_delete (&m->event, t); - thread_add_unuse (m, t); + thread = t->next; + + if (t->arg == arg) + { + ret++; + thread_list_delete (&m->event, t); + thread_add_unuse (m, t); + } } - } + pthread_mutex_unlock (&t->mtx); + } - /* thread can be on the ready list too */ - thread = m->ready.head; - while (thread) - { - struct thread *t; - - t = thread; - thread = t->next; - - if (t->arg == arg) + /* thread can be on the ready list too */ + thread = m->ready.head; + while (thread) + { + t = thread; + pthread_mutex_lock (&t->mtx); { - ret++; - thread_list_delete (&m->ready, t); - thread_add_unuse (m, t); + thread = t->next; + + if (t->arg == arg) + { + ret++; + thread_list_delete (&m->ready, t); + thread_add_unuse (m, t); + } } - } + pthread_mutex_unlock (&t->mtx); + } + } + pthread_mutex_unlock (&m->mtx); return ret; } @@ -1143,18 +1214,25 @@ thread_fetch (struct thread_master *m, struct thread *fetch) struct timeval *timer_wait = &timer_val; struct timeval *timer_wait_bg; + pthread_mutex_lock (&m->mtx); while (1) { int num = 0; /* Signals pre-empt everything */ + pthread_mutex_unlock (&m->mtx); quagga_sigevent_process (); + pthread_mutex_lock (&m->mtx); /* Drain the ready queue of already scheduled jobs, before scheduling * more. */ if ((thread = thread_trim_head (&m->ready)) != NULL) - return thread_run (m, thread, fetch); + { + fetch = thread_run (m, thread, fetch); + pthread_mutex_unlock (&m->mtx); + return fetch; + } /* To be fair to all kinds of threads, and avoid starvation, we * need to be careful to consider all thread types for scheduling @@ -1196,6 +1274,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch) if (errno == EINTR) continue; /* signal received - process it */ zlog_warn ("select() error: %s", safe_strerror (errno)); + pthread_mutex_unlock (&m->mtx); return NULL; } @@ -1215,14 +1294,22 @@ thread_fetch (struct thread_master *m, struct thread *fetch) list at this time. If this is code is uncommented, then background timer threads will not run unless there is nothing else to do. */ if ((thread = thread_trim_head (&m->ready)) != NULL) - return thread_run (m, thread, fetch); + { + fetch = thread_run (m, thread, fetch); + pthread_mutex_unlock (&m->mtx); + return fetch; + } #endif /* Background timer/events, lowest priority */ thread_timer_process (m->background, &now); if ((thread = thread_trim_head (&m->ready)) != NULL) - return thread_run (m, thread, fetch); + { + fetch = thread_run (m, thread, fetch); + pthread_mutex_unlock (&m->mtx); + return fetch; + } } } @@ -1248,13 +1335,23 @@ thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime) int thread_should_yield (struct thread *thread) { - return monotime_since(&thread->real, NULL) > (int64_t)thread->yield; + int result; + pthread_mutex_lock (&thread->mtx); + { + result = monotime_since(&thread->real, NULL) > (int64_t)thread->yield; + } + pthread_mutex_unlock (&thread->mtx); + return result; } void thread_set_yield_time (struct thread *thread, unsigned long yield_time) { - thread->yield = yield_time; + pthread_mutex_lock (&thread->mtx); + { + thread->yield = yield_time; + } + pthread_mutex_unlock (&thread->mtx); } void @@ -1324,6 +1421,7 @@ funcname_thread_execute (struct thread_master *m, memset (&dummy, 0, sizeof (struct thread)); + pthread_mutex_init (&dummy.mtx, NULL); dummy.type = THREAD_EVENT; dummy.add_type = THREAD_EXECUTE; dummy.master = NULL; @@ -1332,8 +1430,12 @@ funcname_thread_execute (struct thread_master *m, tmp.func = dummy.func = func; tmp.funcname = dummy.funcname = funcname; - dummy.hist = hash_get (cpu_record, &tmp, - (void * (*) (void *))cpu_record_hash_alloc); + pthread_mutex_lock (&cpu_record_mtx); + { + dummy.hist = hash_get (cpu_record, &tmp, + (void * (*) (void *))cpu_record_hash_alloc); + } + pthread_mutex_unlock (&cpu_record_mtx); dummy.schedfrom = schedfrom; dummy.schedfrom_line = fromln; diff --git a/lib/thread.h b/lib/thread.h index 34adcc4d09..0cc9841272 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -24,6 +24,7 @@ #include #include "monotime.h" +#include struct rusage_t { @@ -84,6 +85,7 @@ struct thread_master int fd_limit; struct fd_handler handler; unsigned long alloc; + pthread_mutex_t mtx; }; typedef unsigned char thread_type; @@ -110,6 +112,7 @@ struct thread const char *funcname; const char *schedfrom; int schedfrom_line; + pthread_mutex_t mtx; }; struct cpu_thread_history From 2c70efaed19379be49457069fc033d322394e29d Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Mon, 17 Apr 2017 18:33:58 +0000 Subject: [PATCH 52/55] lib: additional thread.c MT-safety work Fixes a few insufficient critical sections. Adds back locking for thread_cancel(), since while thread_cancel() is only safe to call from the pthread which owns the thread master due to races involving thread_fetch() modifying thread master's ready queue, we still need mutual exclusion here for all of the other public thread.c functions to maintain their MT-safety. Signed-off-by: Quentin Young --- lib/thread.c | 67 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/lib/thread.c b/lib/thread.c index 3f7ab12b7f..6cd3b9676f 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -773,13 +773,17 @@ funcname_thread_add_read_write (int dir, struct thread_master *m, #endif if (thread) - { - thread->u.fd = fd; - if (dir == THREAD_READ) - thread_add_fd (m->read, thread); - else - thread_add_fd (m->write, thread); - } + { + pthread_mutex_lock (&thread->mtx); + { + thread->u.fd = fd; + if (dir == THREAD_READ) + thread_add_fd (m->read, thread); + else + thread_add_fd (m->write, thread); + } + pthread_mutex_unlock (&thread->mtx); + } } pthread_mutex_unlock (&m->mtx); @@ -802,17 +806,21 @@ funcname_thread_add_timer_timeval (struct thread_master *m, assert (type == THREAD_TIMER || type == THREAD_BACKGROUND); assert (time_relative); - queue = ((type == THREAD_TIMER) ? m->timer : m->background); pthread_mutex_lock (&m->mtx); { + queue = ((type == THREAD_TIMER) ? m->timer : m->background); thread = thread_get (m, type, func, arg, debugargpass); + + pthread_mutex_lock (&thread->mtx); + { + monotime(&thread->u.sands); + timeradd(&thread->u.sands, time_relative, &thread->u.sands); + pqueue_enqueue(thread, queue); + } + pthread_mutex_unlock (&thread->mtx); } pthread_mutex_unlock (&m->mtx); - monotime(&thread->u.sands); - timeradd(&thread->u.sands, time_relative, &thread->u.sands); - - pqueue_enqueue(thread, queue); return thread; } @@ -903,8 +911,12 @@ funcname_thread_add_event (struct thread_master *m, pthread_mutex_lock (&m->mtx); { thread = thread_get (m, THREAD_EVENT, func, arg, debugargpass); - thread->u.val = val; - thread_list_add (&m->event, thread); + pthread_mutex_lock (&thread->mtx); + { + thread->u.val = val; + thread_list_add (&m->event, thread); + } + pthread_mutex_unlock (&thread->mtx); } pthread_mutex_unlock (&m->mtx); @@ -940,8 +952,8 @@ thread_cancel_read_or_write (struct thread *thread, short int state) /** * Cancel thread from scheduler. * - * This function is *NOT* MT-safe. DO NOT call it from any other thread than - * the primary thread. + * This function is *NOT* MT-safe. DO NOT call it from any other pthread except + * the one which owns thread->master. */ void thread_cancel (struct thread *thread) @@ -950,6 +962,9 @@ thread_cancel (struct thread *thread) struct pqueue *queue = NULL; struct thread **thread_array = NULL; + pthread_mutex_lock (&thread->master->mtx); + pthread_mutex_lock (&thread->mtx); + switch (thread->type) { case THREAD_READ: @@ -981,15 +996,14 @@ thread_cancel (struct thread *thread) queue = thread->master->background; break; default: - return; + goto done; break; } if (queue) { assert(thread->index >= 0); - assert(thread == queue->array[thread->index]); - pqueue_remove_at(thread->index, queue); + pqueue_remove (thread, queue); } else if (list) { @@ -1005,6 +1019,10 @@ thread_cancel (struct thread *thread) } thread_add_unuse (thread->master, thread); + +done: + pthread_mutex_unlock (&thread->mtx); + pthread_mutex_unlock (&thread->master->mtx); } /* Delete all events which has argument value arg. */ @@ -1214,16 +1232,14 @@ thread_fetch (struct thread_master *m, struct thread *fetch) struct timeval *timer_wait = &timer_val; struct timeval *timer_wait_bg; - pthread_mutex_lock (&m->mtx); while (1) { int num = 0; /* Signals pre-empt everything */ - pthread_mutex_unlock (&m->mtx); quagga_sigevent_process (); - pthread_mutex_lock (&m->mtx); + pthread_mutex_lock (&m->mtx); /* Drain the ready queue of already scheduled jobs, before scheduling * more. */ @@ -1272,7 +1288,10 @@ thread_fetch (struct thread_master *m, struct thread *fetch) if (num < 0) { if (errno == EINTR) - continue; /* signal received - process it */ + { + pthread_mutex_unlock (&m->mtx); + continue; /* signal received - process it */ + } zlog_warn ("select() error: %s", safe_strerror (errno)); pthread_mutex_unlock (&m->mtx); return NULL; @@ -1310,6 +1329,8 @@ thread_fetch (struct thread_master *m, struct thread *fetch) pthread_mutex_unlock (&m->mtx); return fetch; } + + pthread_mutex_unlock (&m->mtx); } } From 98f14af8bf8340115049e0df4888b6acc8701ea5 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Sun, 16 Apr 2017 03:14:36 +0000 Subject: [PATCH 53/55] lib: add pthread manager Adds infrastructure for keeping track of pthreads. The general idea is to maintain a daemon-wide table of all pthreads, running or not. A pthread is associated with its own thread master that can be used with existing thread.c code, which provides user-space timers, an event loop, non-blocking I/O callbacks and other facilities. Each frr_pthread has a unique identifier that can be used to fetch it from the table. This is to allow naming threads using a macro, for example: #define WRITE_THREAD 0 #define READ_THREAD 1 #define WORK_THREAD 2 The idea here is to be relatively flexible with regard to how daemons manage their collection of pthreads; the implementation could get away with just some #define'd constants, or keep a dynamically allocated data structure that provides organization, searching, prioritizing, etc. Overall this interface should provide a way to maintain the familiar thread.c userspace threading model while progressively introducing pthreads. Signed-off-by: Quentin Young --- lib/Makefile.am | 2 + lib/frr_pthread.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++ lib/frr_pthread.h | 145 ++++++++++++++++++++++++++++++++++++ 3 files changed, 331 insertions(+) create mode 100644 lib/frr_pthread.c create mode 100644 lib/frr_pthread.h diff --git a/lib/Makefile.am b/lib/Makefile.am index 75947e6146..ad8a488689 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -34,6 +34,7 @@ libfrr_la_SOURCES = \ strlcat.c \ module.c \ hook.c \ + frr_pthread.c \ # end BUILT_SOURCES = route_types.h gitversion.h command_parse.h command_lex.h @@ -74,6 +75,7 @@ pkginclude_HEADERS = \ module.h \ hook.h \ libfrr.h \ + frr_pthread.h \ # end noinst_HEADERS = \ diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c new file mode 100644 index 0000000000..0408bca096 --- /dev/null +++ b/lib/frr_pthread.c @@ -0,0 +1,184 @@ +/* + Utilities and interfaces for managing POSIX threads + Copyright (C) 2017 Cumulus Networks + + This program 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 of the License, or + (at your option) any later version. + + This program 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 + */ + +#include +#include + +#include "frr_pthread.h" +#include "memory.h" +#include "hash.h" + +DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread"); + +static unsigned int next_id = 0; + +/* Hash table of all frr_pthreads along with synchronization primitive(s) and + * hash table callbacks. + * ------------------------------------------------------------------------ */ +static struct hash *pthread_table; +static pthread_mutex_t pthread_table_mtx = PTHREAD_MUTEX_INITIALIZER; + +/* pthread_table->hash_cmp */ +static int pthread_table_hash_cmp(const void *value1, const void *value2) +{ + const struct frr_pthread *tq1 = value1; + const struct frr_pthread *tq2 = value2; + + return (tq1->id == tq2->id); +} + +/* pthread_table->hash_key */ +static unsigned int pthread_table_hash_key(void *value) +{ + return ((struct frr_pthread *)value)->id; +} +/* ------------------------------------------------------------------------ */ + +void frr_pthread_init() +{ + pthread_mutex_lock(&pthread_table_mtx); + { + pthread_table = + hash_create(pthread_table_hash_key, pthread_table_hash_cmp); + } + pthread_mutex_unlock(&pthread_table_mtx); +} + +void frr_pthread_finish() +{ + pthread_mutex_lock(&pthread_table_mtx); + { + hash_clean(pthread_table, (void (*)(void *))frr_pthread_destroy); + hash_free(pthread_table); + } + pthread_mutex_unlock(&pthread_table_mtx); +} + +struct frr_pthread *frr_pthread_new(const char *name, unsigned int id, + void *(*start_routine) (void *), + int (*stop_routine) (void **, struct frr_pthread *)) +{ + static struct frr_pthread holder = { 0 }; + struct frr_pthread *fpt = NULL; + + pthread_mutex_lock(&pthread_table_mtx); + { + holder.id = id; + + if (!hash_lookup(pthread_table, &holder)) { + struct frr_pthread *fpt = + XCALLOC(MTYPE_FRR_PTHREAD, + sizeof(struct frr_pthread)); + fpt->id = id; + fpt->master = thread_master_create(); + fpt->start_routine = start_routine; + fpt->stop_routine = stop_routine; + fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name); + + hash_get(pthread_table, fpt, hash_alloc_intern); + } + } + pthread_mutex_unlock(&pthread_table_mtx); + + return fpt; +} + +void frr_pthread_destroy(struct frr_pthread *fpt) +{ + thread_master_free(fpt->master); + XFREE(MTYPE_FRR_PTHREAD, fpt->name); + XFREE(MTYPE_FRR_PTHREAD, fpt); +} + +struct frr_pthread *frr_pthread_get(unsigned int id) +{ + static struct frr_pthread holder = { 0 }; + struct frr_pthread *fpt; + + pthread_mutex_lock(&pthread_table_mtx); + { + holder.id = id; + fpt = hash_lookup(pthread_table, &holder); + } + pthread_mutex_unlock(&pthread_table_mtx); + + return fpt; +} + +int frr_pthread_run(unsigned int id, const pthread_attr_t * attr, void *arg) +{ + struct frr_pthread *fpt = frr_pthread_get(id); + int ret; + + if (!fpt) + return -1; + + ret = pthread_create(&fpt->thread, attr, fpt->start_routine, arg); + + /* Per pthread_create(3), the contents of fpt->thread are undefined if + * pthread_create() did not succeed. Reset this value to zero. */ + if (ret < 0) + memset(&fpt->thread, 0x00, sizeof(fpt->thread)); + + return ret; +} + +/** + * Calls the stop routine for the frr_pthread and resets any relevant fields. + * + * @param fpt - the frr_pthread to stop + * @param result - pointer to result pointer + * @return the return code from the stop routine + */ +static int frr_pthread_stop_actual(struct frr_pthread *fpt, void **result) +{ + int ret = (*fpt->stop_routine) (result, fpt); + memset(&fpt->thread, 0x00, sizeof(fpt->thread)); + return ret; +} + +int frr_pthread_stop(unsigned int id, void **result) +{ + struct frr_pthread *fpt = frr_pthread_get(id); + return frr_pthread_stop_actual(fpt, result); +} + +/** + * Callback for hash_iterate to stop all frr_pthread's. + */ +static void frr_pthread_stop_all_iter(struct hash_backet *hb, void *arg) +{ + struct frr_pthread *fpt = hb->data; + frr_pthread_stop_actual(fpt, NULL); +} + +void frr_pthread_stop_all() +{ + pthread_mutex_lock(&pthread_table_mtx); + { + hash_iterate(pthread_table, frr_pthread_stop_all_iter, NULL); + } + pthread_mutex_unlock(&pthread_table_mtx); +} + +unsigned int frr_pthread_get_id() +{ + return next_id++; +} diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h new file mode 100644 index 0000000000..b4954367f4 --- /dev/null +++ b/lib/frr_pthread.h @@ -0,0 +1,145 @@ +/* + Utilities and interfaces for managing POSIX threads + Copyright (C) 2017 Cumulus Networks + + This program 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 of the License, or + (at your option) any later version. + + This program 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 _FRR_PTHREAD_H +#define _FRR_PTHREAD_H + +#include +#include "thread.h" + +struct frr_pthread { + + /* pthread id */ + pthread_t thread; + + /* frr thread identifier */ + unsigned int id; + + /* thread master for this pthread's thread.c event loop */ + struct thread_master *master; + + /* start routine */ + void *(*start_routine) (void *); + + /* stop routine */ + int (*stop_routine) (void **, struct frr_pthread *); + + /* the (hopefully descriptive) name of this thread */ + char *name; +}; + +/* Initializes this module. + * + * Must be called before using any of the other functions. + */ +void frr_pthread_init(void); + +/* Uninitializes this module. + * + * Destroys all registered frr_pthread's and internal data structures. + * + * It is safe to call frr_pthread_init() after this function to reinitialize + * the module. + */ +void frr_pthread_finish(void); + +/* Creates a new frr_pthread. + * + * If the provided ID is already assigned to an existing frr_pthread, the + * return value will be NULL. + * + * @param name - the name of the thread. Doesn't have to be unique, but it + * probably should be. This value is copied and may be safely free'd upon + * return. + * + * @param id - the integral ID of the thread. MUST be unique. The caller may + * use this id to retrieve the thread. + * + * @param start_routine - start routine for the pthread, will be passed to + * pthread_create (see those docs for details) + * + * @param stop_routine - stop routine for the pthread, called to terminate the + * thread. This function should gracefully stop the pthread and clean up any + * thread-specific resources. The passed pointer is used to return a data + * result. + * + * @return the created frr_pthread upon success, or NULL upon failure + */ +struct frr_pthread *frr_pthread_new(const char *name, unsigned int id, + void *(*start_routine) (void *), + int (*stop_routine) (void **, struct frr_pthread *)); + +/* Destroys an frr_pthread. + * + * Assumes that the associated pthread, if any, has already terminated. + * + * @param fpt - the frr_pthread to destroy + */ +void frr_pthread_destroy(struct frr_pthread *fpt); + +/* Gets an existing frr_pthread by its id. + * + * @return frr_thread associated with the provided id, or NULL on error + */ +struct frr_pthread *frr_pthread_get(unsigned int id); + +/* Creates a new pthread and binds it to a frr_pthread. + * + * This function is a wrapper for pthread_create. The first parameter is the + * frr_pthread to bind the created pthread to. All subsequent arguments are + * passed unmodified to pthread_create(). + * + * This function returns the same code as pthread_create(). If the value is + * zero, the provided frr_pthread is bound to a running POSIX thread. If the + * value is less than zero, the provided frr_pthread is guaranteed to be a + * clean instance that may be susbsequently passed to frr_pthread_run(). + * + * @param id - frr_pthread to bind the created pthread to + * @param attr - see pthread_create(3) + * @param arg - see pthread_create(3) + * + * @return see pthread_create(3) + */ +int frr_pthread_run(unsigned int id, const pthread_attr_t * attr, void *arg); + +/* Stops an frr_pthread with a result. + * + * @param id - frr_pthread to stop + * @param result - where to store the thread's result, if any. May be NULL if a + * result is not needed. + */ +int frr_pthread_stop(unsigned int id, void **result); + +/* Stops all frr_pthread's. */ +void frr_pthread_stop_all(void); + +/* Returns a unique identifier for use with frr_pthread_new(). + * + * Internally, this is an integer that increments after each call to this + * function. Because the number of pthreads created should never exceed INT_MAX + * during the life of the program, there is no overflow protection. If by + * chance this function returns an ID which is already in use, + * frr_pthread_new() will fail when it is provided. + * + * @return unique identifier + */ +unsigned int frr_pthread_get_id(void); + +#endif /* _FRR_PTHREAD_H */ From 11dde3fa02e1b68c1e79d943d59ae94735c93972 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 28 Apr 2017 23:30:59 +0000 Subject: [PATCH 54/55] isisd: fix uninitialized pointer Signed-off-by: Quentin Young --- isisd/isis_mt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index 42e7b57aa4..552365ad10 100644 --- a/isisd/isis_mt.c +++ b/isisd/isis_mt.c @@ -399,7 +399,7 @@ tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable, unsigned int intersect_count = 0; - uint16_t *old_mt_set; + uint16_t *old_mt_set = NULL; unsigned int old_mt_count; old_mt_count = adj->mt_count; From 705f21797e348a02660a638b6d1b2751ef37372e Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 28 Apr 2017 22:45:59 +0000 Subject: [PATCH 55/55] lib: allow nonblocking thread_fetch() This change adds three fields to thread_master and associated code to use them. The fields are: * long selectpoll_timeout This is a millisecond value that, if nonzero, will override the internally calculated timeout for select()/poll(). -1 indicates nonblocking while a positive value indicates the desired timeout in milliseconds. * bool spin This indicates whether a call to thread_fetch() should result in a loop until work is available. By default this is set to true, in order to keep the default behavior. In this case a return value of NULL indicates that a fatal signal was received in select() or poll(). If it is set to false, thread_fetch() will return immediately. NULL is then an acceptable return value if there is no work to be done. * bool handle_signals This indicates whether or not the pthread that owns the thread master is responsible for handling signals (since this is an MT-unsafe operation, it is best to have just the root thread do it). It is set to true by default. Non-root pthreads should set this to false. Signed-off-by: Quentin Young --- lib/thread.c | 48 ++++++++++++++++++++++++++++++++++++++++++------ lib/thread.h | 3 +++ 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/lib/thread.c b/lib/thread.c index 6cd3b9676f..d4ed5d1a08 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -376,6 +376,8 @@ thread_master_create (void) rv->background = pqueue_create(); rv->timer->cmp = rv->background->cmp = thread_timer_cmp; rv->timer->update = rv->background->update = thread_timer_update; + rv->spin = true; + rv->handle_signals = true; #if defined(HAVE_POLL) rv->handler.pfdsize = rv->fd_limit; @@ -696,15 +698,45 @@ static int fd_select (struct thread_master *m, int size, thread_fd_set *read, thread_fd_set *write, thread_fd_set *except, struct timeval *timer_wait) { int num; + + /* If timer_wait is null here, that means either select() or poll() should + * block indefinitely, unless the thread_master has overriden it. select() + * and poll() differ in the timeout values they interpret as an indefinite + * block; select() requires a null pointer, while poll takes a millisecond + * value of -1. + * + * The thread_master owner has the option of overriding the default behavior + * by setting ->selectpoll_timeout. If the value is positive, it specifies + * the maximum number of milliseconds to wait. If the timeout is -1, it + * specifies that we should never wait and always return immediately even if + * no event is detected. If the value is zero, the behavior is default. + */ + #if defined(HAVE_POLL) - /* recalc timeout for poll. Attention NULL pointer is no timeout with - select, where with poll no timeount is -1 */ int timeout = -1; - if (timer_wait != NULL) + + if (timer_wait != NULL && m->selectpoll_timeout == 0) // use the default value timeout = (timer_wait->tv_sec*1000) + (timer_wait->tv_usec/1000); + else if (m->selectpoll_timeout > 0) // use the user's timeout + timeout = m->selectpoll_timeout; + else if (m->selectpoll_timeout < 0) // effect a poll (return immediately) + timeout = 0; num = poll (m->handler.pfds, m->handler.pfdcount + m->handler.pfdcountsnmp, timeout); #else + struct timeval timeout; + if (m->selectpoll_timeout > 0) // use the user's timeout + { + timeout.tv_sec = m->selectpoll_timeout / 1000; + timeout.tv_usec = (m->selectpoll_timeout % 1000) * 1000; + timer_wait = &timeout; + } + else if (m->selectpoll_timeout < 0) // effect a poll (return immediately) + { + timeout.tv_sec = 0; + timeout.tv_usec = 0; + timer_wait = &timeout; + } num = select (size, read, write, except, timer_wait); #endif @@ -1232,12 +1264,13 @@ thread_fetch (struct thread_master *m, struct thread *fetch) struct timeval *timer_wait = &timer_val; struct timeval *timer_wait_bg; - while (1) + do { int num = 0; /* Signals pre-empt everything */ - quagga_sigevent_process (); + if (m->handle_signals) + quagga_sigevent_process (); pthread_mutex_lock (&m->mtx); /* Drain the ready queue of already scheduled jobs, before scheduling @@ -1331,7 +1364,10 @@ thread_fetch (struct thread_master *m, struct thread *fetch) } pthread_mutex_unlock (&m->mtx); - } + + } while (m->spin); + + return NULL; } unsigned long diff --git a/lib/thread.h b/lib/thread.h index 0cc9841272..18fd340ba5 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -85,6 +85,9 @@ struct thread_master int fd_limit; struct fd_handler handler; unsigned long alloc; + long selectpoll_timeout; + bool spin; + bool handle_signals; pthread_mutex_t mtx; };