diff options
226 files changed, 8592 insertions, 3817 deletions
diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in index 0f56a427dd..e0b00f9782 100644 --- a/alpine/APKBUILD.in +++ b/alpine/APKBUILD.in @@ -19,7 +19,7 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre perl pkgconf python2 python2-dev readline readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs - py-sphinx" + py-sphinx rtrlib rtrlib-dev" checkdepends="pytest py-setuptools" install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall" subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg" @@ -42,6 +42,7 @@ build() { --libdir=$_libdir \ --localstatedir=$_localstatedir \ --enable-systemd=no \ + --enable-rpki \ --enable-vtysh \ --enable-multipath=64 \ --enable-vty-group=frrvty \ diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 05577cb8bd..f5652b07c5 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1232,7 +1232,8 @@ struct aspath *aspath_replace_specific_asn(struct aspath *aspath, } /* Replace all private ASNs with our own ASN */ -struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t asn) +struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t asn, + as_t peer_asn) { struct aspath *new; struct assegment *seg; @@ -1244,7 +1245,9 @@ struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t asn) int i; for (i = 0; i < seg->length; i++) { - if (BGP_AS_IS_PRIVATE(seg->as[i])) + /* Don't replace if public ASN or peer's ASN */ + if (BGP_AS_IS_PRIVATE(seg->as[i]) + && (seg->as[i] != peer_asn)) seg->as[i] = asn; } seg = seg->next; @@ -1255,7 +1258,7 @@ struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t asn) } /* Remove all private ASNs */ -struct aspath *aspath_remove_private_asns(struct aspath *aspath) +struct aspath *aspath_remove_private_asns(struct aspath *aspath, as_t peer_asn) { struct aspath *new; struct assegment *seg; @@ -1282,16 +1285,9 @@ struct aspath *aspath_remove_private_asns(struct aspath *aspath) } } - // The entire segment is private so skip it - if (!public) { - seg = seg->next; - continue; - } - // The entire segment is public so copy it - else if (public == seg->length) { + if (public == seg->length) new_seg = assegment_dup(seg); - } // The segment is a mix of public and private ASNs. Copy as many // spots as @@ -1301,8 +1297,9 @@ struct aspath *aspath_remove_private_asns(struct aspath *aspath) new_seg = assegment_new(seg->type, public); j = 0; for (i = 0; i < seg->length; i++) { - // ASN is public - if (!BGP_AS_IS_PRIVATE(seg->as[i])) { + // keep ASN if public or matches peer's ASN + if (!BGP_AS_IS_PRIVATE(seg->as[i]) + || (seg->as[i] == peer_asn)) { new_seg->as[j] = seg->as[i]; j++; } @@ -1469,7 +1466,7 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2) /* Not reached */ } -/* Iterate over AS_PATH segments and wipe all occurences of the +/* Iterate over AS_PATH segments and wipe all occurrences of the * listed AS numbers. Hence some segments may lose some or even * all data on the way, the operation is implemented as a smarter * version of aspath_dup(), which allocates memory to hold the new @@ -1888,7 +1885,7 @@ static const char *aspath_gettoken(const char *buf, enum as_token *token, const char *p = buf; /* Skip seperators (space for sequences, ',' for sets). */ - while (isspace((int)*p) || *p == ',') + while (isspace((unsigned char)*p) || *p == ',') p++; /* Check the end of the string and type specify characters @@ -1923,14 +1920,14 @@ static const char *aspath_gettoken(const char *buf, enum as_token *token, } /* Check actual AS value. */ - if (isdigit((int)*p)) { + if (isdigit((unsigned char)*p)) { as_t asval; *token = as_token_asval; asval = (*p - '0'); p++; - while (isdigit((int)*p)) { + while (isdigit((unsigned char)*p)) { asval *= 10; asval += (*p - '0'); p++; diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index 6f3d94cdb3..f84b3740c9 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -112,8 +112,9 @@ extern struct aspath *aspath_replace_specific_asn(struct aspath *aspath, as_t target_asn, as_t our_asn); extern struct aspath *aspath_replace_private_asns(struct aspath *aspath, - as_t asn); -extern struct aspath *aspath_remove_private_asns(struct aspath *aspath); + as_t asn, as_t peer_asn); +extern struct aspath *aspath_remove_private_asns(struct aspath *aspath, + as_t peer_asn); extern int aspath_firstas_check(struct aspath *, as_t); extern int aspath_confed_check(struct aspath *); extern int aspath_left_confed_check(struct aspath *); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 35946444dd..e21c84355e 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2956,7 +2956,8 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, addpath_encode, addpath_tx_id); } else if (safi == SAFI_LABELED_UNICAST) { /* Prefix write with label. */ - stream_put_labeled_prefix(s, p, label); + stream_put_labeled_prefix(s, p, label, addpath_encode, + addpath_tx_id); } else if (safi == SAFI_FLOWSPEC) { if (PSIZE (p->prefixlen)+2 < FLOWSPEC_NLRI_SIZELIMIT) stream_putc(s, PSIZE (p->prefixlen)+2); @@ -3215,6 +3216,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, /* Nexthop attribute. */ if (afi == AFI_IP && safi == SAFI_UNICAST && !peer_cap_enhe(peer, afi, safi)) { + afi_t nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len); + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) { stream_putc(s, BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_NEXT_HOP); @@ -3222,17 +3225,18 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, attr); stream_putc(s, 4); stream_put_ipv4(s, attr->nexthop.s_addr); - } else if (peer_cap_enhe(from, afi, safi)) { + } else if (peer_cap_enhe(from, afi, safi) + || (nh_afi == AFI_IP6)) { /* * Likely this is the case when an IPv4 prefix was - * received with - * Extended Next-hop capability and now being advertised - * to - * non-ENHE peers. + * received with Extended Next-hop capability in this + * or another vrf and is now being advertised to + * non-ENHE peers. Since peer_cap_enhe only checks + * peers in this vrf, also check the nh_afi to catch + * the case where the originator was in another vrf. * Setting the mandatory (ipv4) next-hop attribute here - * to enable - * implicit next-hop self with correct (ipv4 address - * family). + * to enable implicit next-hop self with correct A-F + * (ipv4 address family). */ stream_putc(s, BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_NEXT_HOP); diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index ff2ea6f7cd..29e668d179 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -157,7 +157,7 @@ community_list_insert(struct community_list_handler *ch, const char *name, /* If name is made by all digit character. We treat it as number. */ for (number = 0, i = 0; i < strlen(name); i++) { - if (isdigit((int)name[i])) + if (isdigit((unsigned char)name[i])) number = (number * 10) + (name[i] - '0'); else break; @@ -823,6 +823,7 @@ struct community *community_list_match_delete(struct community *com, /* Delete all of the communities we flagged for deletion */ for (i = delete_index - 1; i >= 0; i--) { val = community_val_get(com, com_index_to_delete[i]); + val = htonl(val); community_del_val(com, &val); } diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index 6fc52ff9e0..22d61f702d 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -651,7 +651,7 @@ community_gettoken(const char *buf, enum community_token *token, uint32_t *val) const char *p = buf; /* Skip white space. */ - while (isspace((int)*p)) + while (isspace((unsigned char)*p)) p++; /* Check the end of the line. */ @@ -659,7 +659,7 @@ community_gettoken(const char *buf, enum community_token *token, uint32_t *val) return NULL; /* Well known community string check. */ - if (isalpha((int)*p)) { + if (isalpha((unsigned char)*p)) { if (strncmp(p, "internet", strlen("internet")) == 0) { *val = COMMUNITY_INTERNET; *token = community_token_no_export; @@ -770,13 +770,13 @@ community_gettoken(const char *buf, enum community_token *token, uint32_t *val) } /* Community value. */ - if (isdigit((int)*p)) { + if (isdigit((unsigned char)*p)) { int separator = 0; int digit = 0; uint32_t community_low = 0; uint32_t community_high = 0; - while (isdigit((int)*p) || *p == ':') { + while (isdigit((unsigned char)*p) || *p == ':') { if (*p == ':') { if (separator) { *token = community_token_unknown; diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index 7ea6ae586b..535f36ab5e 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -584,7 +584,7 @@ static unsigned int bgp_dump_parse_time(const char *str) len = strlen(str); for (i = 0; i < len; i++) { - if (isdigit((int)str[i])) { + if (isdigit((unsigned char)str[i])) { time *= 10; time += str[i] - '0'; } else if (str[i] == 'H' || str[i] == 'h') { diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 76bd0e815e..850b85aa6a 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -352,7 +352,7 @@ static const char *ecommunity_gettoken(const char *str, char buf[INET_ADDRSTRLEN + 1]; /* Skip white space. */ - while (isspace((int)*p)) { + while (isspace((unsigned char)*p)) { p++; str++; } @@ -362,38 +362,38 @@ static const char *ecommunity_gettoken(const char *str, return NULL; /* "rt" and "soo" keyword parse. */ - if (!isdigit((int)*p)) { + if (!isdigit((unsigned char)*p)) { /* "rt" match check. */ - if (tolower((int)*p) == 'r') { + if (tolower((unsigned char)*p) == 'r') { p++; - if (tolower((int)*p) == 't') { + if (tolower((unsigned char)*p) == 't') { p++; *token = ecommunity_token_rt; return p; } - if (isspace((int)*p) || *p == '\0') { + if (isspace((unsigned char)*p) || *p == '\0') { *token = ecommunity_token_rt; return p; } goto error; } /* "soo" match check. */ - else if (tolower((int)*p) == 's') { + else if (tolower((unsigned char)*p) == 's') { p++; - if (tolower((int)*p) == 'o') { + if (tolower((unsigned char)*p) == 'o') { p++; - if (tolower((int)*p) == 'o') { + if (tolower((unsigned char)*p) == 'o') { p++; *token = ecommunity_token_soo; return p; } - if (isspace((int)*p) || *p == '\0') { + if (isspace((unsigned char)*p) || *p == '\0') { *token = ecommunity_token_soo; return p; } goto error; } - if (isspace((int)*p) || *p == '\0') { + if (isspace((unsigned char)*p) || *p == '\0') { *token = ecommunity_token_soo; return p; } @@ -415,7 +415,7 @@ static const char *ecommunity_gettoken(const char *str, * OPQR: Four byte value * */ - while (isdigit((int)*p) || *p == ':' || *p == '.') { + while (isdigit((unsigned char)*p) || *p == ':' || *p == '.') { if (*p == ':') { if (separator) goto error; diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 94022ec1be..3bc3d74de6 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -4411,7 +4411,7 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi, /* apply the route-map */ if (bgp_vrf->adv_cmd_rmap[afi][safi].map) { - int ret = 0; + route_map_result_t ret; ret = route_map_apply( bgp_vrf->adv_cmd_rmap[afi][safi] diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index a22082c072..d031d34f1f 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -1069,11 +1069,9 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, pi = pi->next) { total_count++; if (type == bgp_show_type_neighbor) { - union sockunion *su = output_arg; + struct peer *peer = output_arg; - if (pi->peer->su_remote == NULL - || !sockunion_same( - pi->peer->su_remote, su)) + if (peer_cmp(peer, pi->peer) != 0) continue; } if (header) { @@ -1292,29 +1290,41 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_tags, 0); } -DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_routes, - show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd, - "show [ip] bgp l2vpn evpn all neighbors A.B.C.D routes [json]", +DEFUN(show_ip_bgp_l2vpn_evpn_neighbor_routes, + show_ip_bgp_l2vpn_evpn_neighbor_routes_cmd, + "show [ip] bgp l2vpn evpn neighbors <A.B.C.D|X:X::X:X|WORD> routes [json]", SHOW_STR IP_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR - "Display information about all EVPN NLRIs\n" "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" + "IPv4 Neighbor to display information about\n" + "IPv6 Neighbor to display information about\n" + "Neighbor on BGP configured interface\n" "Display routes learned from neighbor\n" JSON_STR) { - int idx_ipv4 = 0; - union sockunion su; + int idx = 0; struct peer *peer; - int ret; + char *peerstr = NULL; bool uj = use_json(argc, argv); + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + struct bgp *bgp = NULL; - argv_find(argv, argc, "A.B.C.D", &idx_ipv4); + bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi, + &bgp, uj); + if (!idx) { + vty_out(vty, "No index\n"); + return CMD_WARNING; + } + + /* neighbors <A.B.C.D|X:X::X:X|WORD> */ + argv_find(argv, argc, "neighbors", &idx); + peerstr = argv[++idx]->arg; - ret = str2sockunion(argv[idx_ipv4]->arg, &su); - if (ret < 0) { + peer = peer_lookup_in_view(vty, bgp, peerstr, uj); + if (!peer) { if (uj) { json_object *json_no = NULL; json_no = json_object_new_object(); @@ -1325,11 +1335,9 @@ DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_routes, json_object_free(json_no); } else vty_out(vty, "Malformed address: %s\n", - argv[idx_ipv4]->arg); + argv[idx]->arg); return CMD_WARNING; } - - peer = peer_lookup(NULL, &su); if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) { if (uj) { json_object *json_no = NULL; @@ -1345,13 +1353,13 @@ DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_routes, return CMD_WARNING; } - return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_neighbor, &su, 0, + return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_neighbor, peer, 0, uj); } DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes, show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd, - "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN neighbors A.B.C.D routes [json]", + "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN neighbors <A.B.C.D|X:X::X:X|WORD> routes [json]", SHOW_STR IP_STR BGP_STR @@ -1360,20 +1368,30 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes, "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" + "IPv4 Neighbor to display information about\n" + "IPv6 Neighbor to display information about\n" + "Neighbor on BGP configured interface\n" "Display routes learned from neighbor\n" JSON_STR) { int idx_ext_community = 0; - int idx_ipv4 = 0; + int idx = 0; int ret; - union sockunion su; struct peer *peer; + char *peerstr = NULL; struct prefix_rd prd; bool uj = use_json(argc, argv); + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + struct bgp *bgp = NULL; - argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community); - argv_find(argv, argc, "A.B.C.D", &idx_ipv4); + bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi, + &bgp, uj); + if (!idx) { + vty_out(vty, "No index\n"); + return CMD_WARNING; + } + argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community); ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); if (!ret) { if (uj) { @@ -1389,8 +1407,12 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes, return CMD_WARNING; } - ret = str2sockunion(argv[idx_ipv4]->arg, &su); - if (ret < 0) { + /* neighbors <A.B.C.D|X:X::X:X|WORD> */ + argv_find(argv, argc, "neighbors", &idx); + peerstr = argv[++idx]->arg; + + peer = peer_lookup_in_view(vty, bgp, peerstr, uj); + if (!peer) { if (uj) { json_object *json_no = NULL; json_no = json_object_new_object(); @@ -1401,11 +1423,9 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes, json_object_free(json_no); } else vty_out(vty, "Malformed address: %s\n", - argv[idx_ext_community]->arg); + argv[idx]->arg); return CMD_WARNING; } - - peer = peer_lookup(NULL, &su); if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) { if (uj) { json_object *json_no = NULL; @@ -1421,33 +1441,48 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes, return CMD_WARNING; } - return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_neighbor, &su, 0, + return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_neighbor, peer, 0, uj); } -DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes, - show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd, - "show [ip] bgp l2vpn evpn all neighbors A.B.C.D advertised-routes [json]", +DEFUN(show_ip_bgp_l2vpn_evpn_neighbor_advertised_routes, + show_ip_bgp_l2vpn_evpn_neighbor_advertised_routes_cmd, + "show [ip] bgp l2vpn evpn neighbors <A.B.C.D|X:X::X:X|WORD> advertised-routes [json]", SHOW_STR IP_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR - "Display information about all EVPN NLRIs\n" "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" + "IPv4 Neighbor to display information about\n" + "IPv6 Neighbor to display information about\n" + "Neighbor on BGP configured interface\n" "Display the routes advertised to a BGP neighbor\n" JSON_STR) { - int idx_ipv4 = 0; - int ret; + int idx = 0; struct peer *peer; - union sockunion su; bool uj = use_json(argc, argv); + struct bgp *bgp = NULL; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + char *peerstr = NULL; + + if (uj) + argc--; - argv_find(argv, argc, "A.B.C.D", &idx_ipv4); + bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi, + &bgp, uj); + if (!idx) { + vty_out(vty, "No index\n"); + return CMD_WARNING; + } + + /* neighbors <A.B.C.D|X:X::X:X|WORD> */ + argv_find(argv, argc, "neighbors", &idx); + peerstr = argv[++idx]->arg; - ret = str2sockunion(argv[idx_ipv4]->arg, &su); - if (ret < 0) { + peer = peer_lookup_in_view(vty, bgp, peerstr, uj); + if (!peer) { if (uj) { json_object *json_no = NULL; json_no = json_object_new_object(); @@ -1458,10 +1493,9 @@ DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes, json_object_free(json_no); } else vty_out(vty, "Malformed address: %s\n", - argv[idx_ipv4]->arg); + argv[idx]->arg); return CMD_WARNING; } - peer = peer_lookup(NULL, &su); if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) { if (uj) { json_object *json_no = NULL; @@ -1482,7 +1516,7 @@ DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes, DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes, show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd, - "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN neighbors A.B.C.D advertised-routes [json]", + "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN neighbors <A.B.C.D|X:X::X:X|WORD> advertised-routes [json]", SHOW_STR IP_STR BGP_STR @@ -1491,22 +1525,43 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes, "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" + "IPv4 Neighbor to display information about\n" + "IPv6 Neighbor to display information about\n" + "Neighbor on BGP configured interface\n" "Display the routes advertised to a BGP neighbor\n" JSON_STR) { int idx_ext_community = 0; - int idx_ipv4 = 0; + int idx = 0; int ret; struct peer *peer; struct prefix_rd prd; - union sockunion su; + struct bgp *bgp = NULL; bool uj = use_json(argc, argv); + char *peerstr = NULL; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + + if (uj) + argc--; + + if (uj) + argc--; + + bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi, + &bgp, uj); + if (!idx) { + vty_out(vty, "No index\n"); + return CMD_WARNING; + } argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community); - argv_find(argv, argc, "A.B.C.D", &idx_ipv4); - ret = str2sockunion(argv[idx_ipv4]->arg, &su); - if (ret < 0) { + /* neighbors <A.B.C.D|X:X::X:X|WORD> */ + argv_find(argv, argc, "neighbors", &idx); + peerstr = argv[++idx]->arg; + + peer = peer_lookup_in_view(vty, bgp, peerstr, uj); + if (!peer) { if (uj) { json_object *json_no = NULL; json_no = json_object_new_object(); @@ -1517,10 +1572,9 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes, json_object_free(json_no); } else vty_out(vty, "Malformed address: %s\n", - argv[idx_ext_community]->arg); + argv[idx]->arg); return CMD_WARNING; } - peer = peer_lookup(NULL, &su); if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) { if (uj) { json_object *json_no = NULL; @@ -1599,7 +1653,7 @@ DEFUN(show_ip_bgp_evpn_rd_overlay, use_json(argc, argv)); } -/* For testing purpose, static route of MPLS-VPN. */ +/* For testing purpose, static route of EVPN RT-5. */ DEFUN(evpnrt5_network, evpnrt5_network_cmd, "network <A.B.C.D/M|X:X::X:X/M> rd ASN:NN_OR_IP-ADDRESS:NN ethtag WORD label WORD esi WORD gwip <A.B.C.D|X:X::X:X> routermac WORD [route-map WORD]", @@ -1638,7 +1692,7 @@ DEFUN(evpnrt5_network, argv[idx_routermac]->arg); } -/* For testing purpose, static route of MPLS-VPN. */ +/* For testing purpose, static route of EVPN RT-5. */ DEFUN(no_evpnrt5_network, no_evpnrt5_network_cmd, "no network <A.B.C.D/M|X:X::X:X/M> rd ASN:NN_OR_IP-ADDRESS:NN ethtag WORD label WORD esi WORD gwip <A.B.C.D|X:X::X:X>", @@ -5323,12 +5377,12 @@ void bgp_ethernetvpn_init(void) install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_tags_cmd); install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_tags_cmd); install_element(VIEW_NODE, - &show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd); + &show_ip_bgp_l2vpn_evpn_neighbor_routes_cmd); install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd); install_element( VIEW_NODE, - &show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd); + &show_ip_bgp_l2vpn_evpn_neighbor_advertised_routes_cmd); install_element( VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd); diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index d4f608d40f..30a964a22c 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -193,7 +193,7 @@ static struct as_list *as_list_insert(const char *name) /* If name is made by all digit character. We treat it as number. */ for (number = 0, i = 0; i < strlen(name); i++) { - if (isdigit((int)name[i])) + if (isdigit((unsigned char)name[i])) number = (number * 10) + (name[i] - '0'); else break; diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 4348e6b240..c9c6fc157e 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -96,6 +96,21 @@ static int bgp_holdtime_timer(struct thread *); /* BGP FSM functions. */ static int bgp_start(struct peer *); +/* Register peer with NHT */ +static int bgp_peer_reg_with_nht(struct peer *peer) +{ + int connected = 0; + + if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 + && !CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) + && !bgp_flag_check(peer->bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) + connected = 1; + + return bgp_find_or_add_nexthop( + peer->bgp, peer->bgp, family2afi(peer->su.sa.sa_family), + NULL, peer, connected); +} + static void peer_xfer_stats(struct peer *peer_dst, struct peer *peer_src) { /* Copy stats over. These are only the pre-established state stats */ @@ -293,6 +308,11 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) if (from_peer) peer_xfer_stats(peer, from_peer); + /* Register peer for NHT. This is to allow RAs to be enabled when + * needed, even on a passive connection. + */ + bgp_peer_reg_with_nht(peer); + bgp_reads_on(peer); bgp_writes_on(peer); thread_add_timer_msec(bm->master, bgp_process_packet, peer, 0, @@ -1382,7 +1402,6 @@ static int bgp_connect_fail(struct peer *peer) int bgp_start(struct peer *peer) { int status; - int connected = 0; bgp_peer_conf_if_to_su_update(peer); @@ -1439,17 +1458,10 @@ int bgp_start(struct peer *peer) return -1; } - /* Register to be notified on peer up */ - if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 - && !CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) - && !bgp_flag_check(peer->bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) - connected = 1; - else - connected = 0; - - if (!bgp_find_or_add_nexthop(peer->bgp, peer->bgp, - family2afi(peer->su.sa.sa_family), NULL, - peer, connected)) { + /* Register peer for NHT. If next hop is already resolved, proceed + * with connection setup, else wait. + */ + if (!bgp_peer_reg_with_nht(peer)) { if (bgp_zebra_num_connects()) { if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [FSM] Waiting for NHT", diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c index 098374fa9f..aeb290719a 100644 --- a/bgpd/bgp_lcommunity.c +++ b/bgpd/bgp_lcommunity.c @@ -359,7 +359,7 @@ static const char *lcommunity_gettoken(const char *str, const char *p = str; /* Skip white space. */ - while (isspace((int)*p)) { + while (isspace((unsigned char)*p)) { p++; str++; } @@ -369,14 +369,14 @@ static const char *lcommunity_gettoken(const char *str, return NULL; /* Community value. */ - if (isdigit((int)*p)) { + if (isdigit((unsigned char)*p)) { int separator = 0; int digit = 0; uint32_t globaladmin = 0; uint32_t localdata1 = 0; uint32_t localdata2 = 0; - while (isdigit((int)*p) || *p == ':') { + while (isdigit((unsigned char)*p) || *p == ':') { if (*p == ':') { if (separator == 2) { *token = lcommunity_token_unknown; @@ -439,7 +439,8 @@ struct lcommunity *lcommunity_str2com(const char *str) enum lcommunity_token token = lcommunity_token_unknown; struct lcommunity_val lval; - while ((str = lcommunity_gettoken(str, &lval, &token))) { + do { + str = lcommunity_gettoken(str, &lval, &token); switch (token) { case lcommunity_token_val: if (lcom == NULL) @@ -452,7 +453,8 @@ struct lcommunity *lcommunity_str2com(const char *str) lcommunity_free(&lcom); return NULL; } - } + } while (str); + return lcom; } diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index a8c507832c..812f0ce16e 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -680,17 +680,23 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, int detail, continue; for (rn = bgp_table_top(table[afi]); rn; rn = bgp_route_next(rn)) { + struct peer *peer; + bnc = bgp_node_get_bgp_nexthop_info(rn); if (!bnc) continue; + peer = (struct peer *)bnc->nht_info; if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) { vty_out(vty, - " %s valid [IGP metric %d], #paths %d\n", + " %s valid [IGP metric %d], #paths %d", inet_ntop(rn->p.family, &rn->p.u.prefix, buf, sizeof(buf)), bnc->metric, bnc->path_count); + if (peer) + vty_out(vty, ", peer %s", peer->host); + vty_out(vty, "\n"); if (!detail) continue; @@ -698,10 +704,13 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, int detail, bgp_show_nexthops_detail(vty, bgp, bnc); } else { - vty_out(vty, " %s invalid\n", + vty_out(vty, " %s invalid", inet_ntop(rn->p.family, &rn->p.u.prefix, buf, sizeof(buf))); + if (peer) + vty_out(vty, ", peer %s", peer->host); + vty_out(vty, "\n"); if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) vty_out(vty, " Must be Connected\n"); diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index e8eacee589..fc6fc66a4c 100644 --- a/bgpd/bgp_packet.h +++ b/bgpd/bgp_packet.h @@ -57,9 +57,6 @@ extern void bgp_notify_send_with_data(struct peer *, uint8_t, uint8_t, extern void bgp_route_refresh_send(struct peer *, afi_t, safi_t, uint8_t, uint8_t, int); extern void bgp_capability_send(struct peer *, afi_t, safi_t, int, int); -extern void bgp_default_update_send(struct peer *, struct attr *, afi_t, safi_t, - struct peer *); -extern void bgp_default_withdraw_send(struct peer *, afi_t, safi_t); extern int bgp_capability_receive(struct peer *, bgp_size_t); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index aa02cc3c63..183debddba 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1243,10 +1243,12 @@ static int bgp_cluster_filter(struct peer *peer, struct attr *attr) static int bgp_input_modifier(struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, - const char *rmap_name) + const char *rmap_name, mpls_label_t *label, + uint32_t num_labels) { struct bgp_filter *filter; - struct bgp_path_info rmap_path; + struct bgp_path_info rmap_path = { 0 }; + struct bgp_path_info_extra extra = { 0 }; route_map_result_t ret; struct route_map *rmap = NULL; @@ -1276,6 +1278,11 @@ static int bgp_input_modifier(struct peer *peer, struct prefix *p, /* Duplicate current value to new strucutre for modification. */ rmap_path.peer = peer; rmap_path.attr = attr; + rmap_path.extra = &extra; + extra.num_labels = num_labels; + if (label && num_labels && num_labels <= BGP_MAX_LABELS) + memcpy(extra.label, label, + num_labels * sizeof(mpls_label_t)); SET_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN); @@ -1366,7 +1373,7 @@ static void bgp_peer_remove_private_as(struct bgp *bgp, afi_t afi, safi_t safi, peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE)) attr->aspath = aspath_replace_private_asns( - attr->aspath, bgp->as); + attr->aspath, bgp->as, peer->as); // The entire aspath consists of private ASNs so create // an empty aspath @@ -1377,7 +1384,7 @@ static void bgp_peer_remove_private_as(struct bgp *bgp, afi_t afi, safi_t safi, // the private ASNs else attr->aspath = aspath_remove_private_asns( - attr->aspath); + attr->aspath, peer->as); } // 'all' was not specified so the entire aspath must be private @@ -1388,7 +1395,7 @@ static void bgp_peer_remove_private_as(struct bgp *bgp, afi_t afi, safi_t safi, peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE)) attr->aspath = aspath_replace_private_asns( - attr->aspath, bgp->as); + attr->aspath, bgp->as, peer->as); else attr->aspath = aspath_empty_get(); } @@ -1465,7 +1472,7 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, struct bgp *bgp; struct attr *piattr; char buf[PREFIX_STRLEN]; - int ret; + route_map_result_t ret; int transparent; int reflect; afi_t afi; @@ -2544,12 +2551,12 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, /* apply the route-map */ if (bgp->adv_cmd_rmap[afi][safi].map) { - int ret = 0; + route_map_result_t ret; ret = route_map_apply( bgp->adv_cmd_rmap[afi][safi].map, &rn->p, RMAP_BGP, new_select); - if (ret == RMAP_MATCH) + if (ret == RMAP_PERMITMATCH) bgp_evpn_advertise_type5_route( bgp, &rn->p, new_select->attr, afi, safi); @@ -3149,8 +3156,8 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, * commands, so we need bgp_attr_flush in the error paths, until we * intern * the attr (which takes over the memory references) */ - if (bgp_input_modifier(peer, p, &new_attr, afi, safi, NULL) - == RMAP_DENY) { + if (bgp_input_modifier(peer, p, &new_attr, afi, safi, NULL, + label, num_labels) == RMAP_DENY) { peer->stat_pfx_filter++; reason = "route-map;"; bgp_attr_flush(&new_attr); @@ -4593,7 +4600,7 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p, struct bgp_path_info rmap_path; struct attr attr; struct attr *attr_new; - int ret; + route_map_result_t ret; #if ENABLE_BGP_VNC int vnc_implicit_withdraw = 0; #endif @@ -4941,7 +4948,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p, if (bgp_static->rmap.name) { struct attr attr_tmp = attr; struct bgp_path_info rmap_path; - int ret; + route_map_result_t ret; rmap_path.peer = bgp->peer_self; rmap_path.attr = &attr_tmp; @@ -5325,6 +5332,13 @@ static void bgp_purge_af_static_redist_routes(struct bgp *bgp, afi_t afi, struct bgp_node *rn; struct bgp_path_info *pi; + /* Do not install the aggregate route if BGP is in the + * process of termination. + */ + if (bgp_flag_check(bgp, BGP_FLAG_DELETE_IN_PROGRESS) || + (bgp->peer_self == NULL)) + return; + table = bgp->rib[afi][safi]; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) { @@ -6620,7 +6634,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, struct attr attr; struct attr *new_attr; afi_t afi; - int ret; + route_map_result_t ret; struct bgp_redist *red; /* Make default attribute. */ @@ -8151,20 +8165,25 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, json_nexthop_global = json_object_new_object(); } - if (!json_paths && safi == SAFI_EVPN) { + if (!json_paths && path->extra) { char tag_buf[30]; - bgp_evpn_route2str((struct prefix_evpn *)&bn->p, - buf2, sizeof(buf2)); - vty_out(vty, " Route %s", buf2); + buf2[0] = '\0'; tag_buf[0] = '\0'; if (path->extra && path->extra->num_labels) { bgp_evpn_label2str(path->extra->label, path->extra->num_labels, tag_buf, sizeof(tag_buf)); - vty_out(vty, " VNI %s", tag_buf); } - vty_out(vty, "\n"); + if (safi == SAFI_EVPN) { + bgp_evpn_route2str((struct prefix_evpn *)&bn->p, + buf2, sizeof(buf2)); + vty_out(vty, " Route %s", buf2); + if (tag_buf[0] != '\0') + vty_out(vty, " VNI %s", tag_buf); + vty_out(vty, "\n"); + } + if (path->extra && path->extra->parent) { struct bgp_path_info *parent_ri; struct bgp_node *rn, *prn; @@ -8173,11 +8192,14 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, rn = parent_ri->net; if (rn && rn->prn) { prn = rn->prn; - vty_out(vty, " Imported from %s:%s\n", - prefix_rd2str( - (struct prefix_rd *)&prn->p, - buf1, sizeof(buf1)), - buf2); + prefix_rd2str((struct prefix_rd *)&prn->p, + buf1, sizeof(buf1)); + if (is_pi_family_evpn(parent_ri)) { + bgp_evpn_route2str((struct prefix_evpn *)&rn->p, + buf2, sizeof(buf2)); + vty_out(vty, " Imported from %s:%s, VNI %s\n", buf1, buf2, tag_buf); + } else + vty_out(vty, " Imported from %s:%s\n", buf1, buf2); } } } @@ -9139,7 +9161,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, struct route_map *rmap = output_arg; struct bgp_path_info path; struct attr dummy_attr; - int ret; + route_map_result_t ret; bgp_attr_dup(&dummy_attr, pi->attr); @@ -10486,63 +10508,6 @@ static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp, return ret; } -static struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp, - const char *ip_str, bool use_json) -{ - int ret; - struct peer *peer; - union sockunion su; - - /* Get peer sockunion. */ - ret = str2sockunion(ip_str, &su); - if (ret < 0) { - peer = peer_lookup_by_conf_if(bgp, ip_str); - if (!peer) { - peer = peer_lookup_by_hostname(bgp, ip_str); - - if (!peer) { - if (use_json) { - json_object *json_no = NULL; - json_no = json_object_new_object(); - json_object_string_add( - json_no, - "malformedAddressOrName", - ip_str); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json_no, - JSON_C_TO_STRING_PRETTY)); - json_object_free(json_no); - } else - vty_out(vty, - "%% Malformed address or name: %s\n", - ip_str); - return NULL; - } - } - return peer; - } - - /* Peer structure lookup. */ - peer = peer_lookup(bgp, &su); - if (!peer) { - if (use_json) { - json_object *json_no = NULL; - json_no = json_object_new_object(); - json_object_string_add(json_no, "warning", - "No such neighbor in this view/vrf"); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json_no, JSON_C_TO_STRING_PRETTY)); - json_object_free(json_no); - } else - vty_out(vty, "No such neighbor in this view/vrf\n"); - return NULL; - } - - return peer; -} - enum bgp_stats { BGP_STATS_MAXBITLEN = 0, BGP_STATS_RIB, @@ -11284,7 +11249,7 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, /* Filter prefix using route-map */ ret = bgp_input_modifier(peer, &rn->p, &attr, - afi, safi, rmap_name); + afi, safi, rmap_name, NULL, 0); if (type == bgp_show_adj_route_filtered && !route_filtered && ret != RMAP_DENY) { diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 1f90fa742a..7f1a9b71c1 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -62,6 +62,7 @@ #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_pbr.h" #include "bgpd/bgp_flowspec_util.h" +#include "bgpd/bgp_encap_types.h" #if ENABLE_BGP_VNC #include "bgpd/rfapi/bgp_rfapi_cfg.h" @@ -239,10 +240,9 @@ struct bgp_match_peer_compiled { /* Compares the peer specified in the 'match peer' clause with the peer received in bgp_path_info->peer. If it is the same, or if the peer structure received is a peer_group containing it, returns RMAP_MATCH. */ -static route_map_result_t route_match_peer(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_peer(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct bgp_match_peer_compiled *pc; union sockunion *su; @@ -335,10 +335,9 @@ struct route_map_rule_cmd route_match_peer_cmd = {"peer", route_match_peer, route_match_peer_free}; #if defined(HAVE_LUA) -static route_map_result_t route_match_command(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_command(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { int status = RMAP_NOMATCH; u_int32_t locpref = 0; @@ -434,10 +433,9 @@ struct route_map_rule_cmd route_match_command_cmd = { /* Match function should return 1 if match is success else return zero. */ -static route_map_result_t route_match_ip_address(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_ip_address(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct access_list *alist; @@ -474,10 +472,9 @@ struct route_map_rule_cmd route_match_ip_address_cmd = { /* `match ip next-hop IP_ADDRESS' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_ip_next_hop(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_ip_next_hop(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct access_list *alist; struct bgp_path_info *path; @@ -521,10 +518,9 @@ struct route_map_rule_cmd route_match_ip_next_hop_cmd = { /* `match ip route-source ACCESS-LIST' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_ip_route_source(void *rule, - const struct prefix *pfx, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_ip_route_source(void *rule, const struct prefix *pfx, + route_map_object_t type, void *object) { struct access_list *alist; struct bgp_path_info *path; @@ -571,9 +567,9 @@ struct route_map_rule_cmd route_match_ip_route_source_cmd = { "ip route-source", route_match_ip_route_source, route_match_ip_route_source_compile, route_match_ip_route_source_free}; -static route_map_result_t route_match_prefix_list_flowspec(afi_t afi, - struct prefix_list *plist, - const struct prefix *p) +static enum route_map_cmd_result_t +route_match_prefix_list_flowspec(afi_t afi, struct prefix_list *plist, + const struct prefix *p) { int ret; struct bgp_pbr_entry_main api; @@ -604,8 +600,7 @@ static route_map_result_t route_match_prefix_list_flowspec(afi_t afi, return RMAP_NOMATCH; } -/* `match ip address prefix-list PREFIX_LIST' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_address_prefix_list(void *rule, afi_t afi, const struct prefix *prefix, route_map_object_t type, void *object) @@ -626,7 +621,7 @@ route_match_address_prefix_list(void *rule, afi_t afi, : RMAP_MATCH); } -static route_map_result_t +static enum route_map_cmd_result_t route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -651,7 +646,7 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { /* `match ip next-hop prefix-list PREFIX_LIST' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -693,7 +688,7 @@ struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = { /* `match ip next-hop type <blackhole>' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ip_next_hop_type(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -702,7 +697,7 @@ route_match_ip_next_hop_type(void *rule, const struct prefix *prefix, if (type == RMAP_BGP && prefix->family == AF_INET) { path = (struct bgp_path_info *)object; if (!path || !path->attr) - return RMAP_DENYMATCH; + return RMAP_NOMATCH; /* If nexthop interface's index can't be resolved and nexthop is set to any address then mark it as type `blackhole`. @@ -732,7 +727,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = { /* `match ip route-source prefix-list PREFIX_LIST' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ip_route_source_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) @@ -782,10 +777,9 @@ struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd = { /* `match evpn default-route' */ /* Match function should return 1 if match is success else 0 */ -static route_map_result_t route_match_evpn_default_route(void *rule, - const struct prefix *p, - route_map_object_t - type, void *object) +static enum route_map_cmd_result_t +route_match_evpn_default_route(void *rule, const struct prefix *p, + route_map_object_t type, void *object) { if (type == RMAP_BGP && is_evpn_prefix_default(p)) return RMAP_MATCH; @@ -801,10 +795,9 @@ struct route_map_rule_cmd route_match_evpn_default_route_cmd = { /* Match function should return 1 if match is success else return zero. */ -static route_map_result_t route_match_mac_address(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_mac_address(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct access_list *alist; struct prefix p; @@ -847,26 +840,51 @@ struct route_map_rule_cmd route_match_mac_address_cmd = { "mac address", route_match_mac_address, route_match_mac_address_compile, route_match_mac_address_free}; -/* `match vni' */ - -/* Match function should return 1 if match is success else return - zero. */ -static route_map_result_t route_match_vni(void *rule, - const struct prefix *prefix, - route_map_object_t type, void *object) +/* + * Match function returns: + * ...RMAP_MATCH if match is found. + * ...RMAP_NOMATCH if match is not found. + * ...RMAP_NOOP to ignore this match check. + */ +static enum route_map_cmd_result_t +route_match_vni(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { vni_t vni = 0; + unsigned int label_cnt = 0; struct bgp_path_info *path = NULL; + struct prefix_evpn *evp = (struct prefix_evpn *) prefix; if (type == RMAP_BGP) { vni = *((vni_t *)rule); path = (struct bgp_path_info *)object; + /* + * This rmap filter is valid for vxlan tunnel type only. + * For any other tunnel type, return noop to ignore + * this check. + */ + if (path->attr && path->attr->encap_tunneltype != + BGP_ENCAP_TYPE_VXLAN) + return RMAP_NOOP; + + /* + * Apply filter to type 1, 2, 5 routes only. + * Other route types do not have vni label. + */ + if (evp && (evp->prefix.route_type != BGP_EVPN_AD_ROUTE && + evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE && + evp->prefix.route_type != BGP_EVPN_IP_PREFIX_ROUTE)) + return RMAP_NOOP; + if (path->extra == NULL) return RMAP_NOMATCH; - if (vni == label2vni(&path->extra->label[0])) - return RMAP_MATCH; + for ( ; label_cnt < BGP_MAX_LABELS && + label_cnt < path->extra->num_labels; label_cnt++) { + if (vni == label2vni(&path->extra->label[label_cnt])) + return RMAP_MATCH; + } } return RMAP_NOMATCH; @@ -904,10 +922,9 @@ struct route_map_rule_cmd route_match_evpn_vni_cmd = { /* Match function should return 1 if match is success else return zero. */ -static route_map_result_t route_match_evpn_route_type(void *rule, - const struct prefix *pfx, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_evpn_route_type(void *rule, const struct prefix *pfx, + route_map_object_t type, void *object) { uint8_t route_type = 0; @@ -950,7 +967,7 @@ struct route_map_rule_cmd route_match_evpn_route_type_cmd = { route_match_evpn_route_type_compile, route_match_evpn_route_type_free}; /* Route map commands for VRF route leak with source vrf matching */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_vrl_source_vrf(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -999,10 +1016,9 @@ struct route_map_rule_cmd route_match_vrl_source_vrf_cmd = { /* `match local-preference LOCAL-PREF' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_local_pref(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_local_pref(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { uint32_t *local_pref; struct bgp_path_info *path; @@ -1056,10 +1072,9 @@ struct route_map_rule_cmd route_match_local_pref_cmd = { /* `match metric METRIC' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_metric(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_metric(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct rmap_value *rv; struct bgp_path_info *path; @@ -1080,10 +1095,9 @@ struct route_map_rule_cmd route_match_metric_cmd = { /* `match as-path ASPATH' */ /* Match function for as-path match. I assume given object is */ -static route_map_result_t route_match_aspath(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_aspath(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct as_list *as_list; @@ -1130,10 +1144,9 @@ struct rmap_community { }; /* Match function for community match. */ -static route_map_result_t route_match_community(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_community(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct community_list *list; struct bgp_path_info *path; @@ -1200,10 +1213,9 @@ struct route_map_rule_cmd route_match_community_cmd = { route_match_community_free}; /* Match function for lcommunity match. */ -static route_map_result_t route_match_lcommunity(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_lcommunity(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct community_list *list; struct bgp_path_info *path; @@ -1273,10 +1285,9 @@ struct route_map_rule_cmd route_match_lcommunity_cmd = { /* Match function for extcommunity match. */ -static route_map_result_t route_match_ecommunity(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_ecommunity(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct community_list *list; struct bgp_path_info *path; @@ -1327,10 +1338,9 @@ struct route_map_rule_cmd route_match_ecommunity_cmd = { and `address-family vpnv4'. */ /* `match origin' */ -static route_map_result_t route_match_origin(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_origin(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { uint8_t *origin; struct bgp_path_info *path; @@ -1375,10 +1385,9 @@ struct route_map_rule_cmd route_match_origin_cmd = { /* match probability { */ -static route_map_result_t route_match_probability(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_probability(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { long r = random(); @@ -1430,10 +1439,9 @@ struct route_map_rule_cmd route_match_probability_cmd = { /* `match interface IFNAME' */ /* Match function should return 1 if match is success else return zero. */ -static route_map_result_t route_match_interface(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_interface(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct interface *ifp; struct bgp_path_info *path; @@ -1477,9 +1485,9 @@ struct route_map_rule_cmd route_match_interface_cmd = { /* `set ip next-hop IP_ADDRESS' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_tag(void *rule, - const struct prefix *prefix, - route_map_object_t type, void *object) +static enum route_map_cmd_result_t +route_match_tag(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { route_tag_t *tag; struct bgp_path_info *path; @@ -1509,10 +1517,9 @@ struct rmap_ip_nexthop_set { int unchanged; }; -static route_map_result_t route_set_ip_nexthop(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_ip_nexthop(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct rmap_ip_nexthop_set *rins = rule; struct bgp_path_info *path; @@ -1615,10 +1622,9 @@ struct route_map_rule_cmd route_set_ip_nexthop_cmd = { /* `set local-preference LOCAL_PREF' */ /* Set local preference. */ -static route_map_result_t route_set_local_pref(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_local_pref(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct rmap_value *rv; struct bgp_path_info *path; @@ -1650,10 +1656,9 @@ struct route_map_rule_cmd route_set_local_pref_cmd = { /* `set weight WEIGHT' */ /* Set weight. */ -static route_map_result_t route_set_weight(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_weight(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct rmap_value *rv; struct bgp_path_info *path; @@ -1678,10 +1683,9 @@ struct route_map_rule_cmd route_set_weight_cmd = { /* `set metric METRIC' */ /* Set metric to attribute. */ -static route_map_result_t route_set_metric(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_metric(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct rmap_value *rv; struct bgp_path_info *path; @@ -1709,10 +1713,9 @@ struct route_map_rule_cmd route_set_metric_cmd = { /* `set as-path prepend ASPATH' */ /* For AS path prepend mechanism. */ -static route_map_result_t route_set_aspath_prepend(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_aspath_prepend(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct aspath *aspath; struct aspath *new; @@ -1772,10 +1775,9 @@ struct route_map_rule_cmd route_set_aspath_prepend_cmd = { * one. * Make a deep copy of existing AS_PATH, but for the first ASn only. */ -static route_map_result_t route_set_aspath_exclude(void *rule, - const struct prefix *dummy, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_aspath_exclude(void *rule, const struct prefix *dummy, + route_map_object_t type, void *object) { struct aspath *new_path, *exclude_path; struct bgp_path_info *path; @@ -1807,10 +1809,9 @@ struct rmap_com_set { }; /* For community set mechanism. */ -static route_map_result_t route_set_community(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_community(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct rmap_com_set *rcs; struct bgp_path_info *path; @@ -1923,10 +1924,9 @@ struct rmap_lcom_set { /* For lcommunity set mechanism. */ -static route_map_result_t route_set_lcommunity(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_lcommunity(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct rmap_lcom_set *rcs; struct bgp_path_info *path; @@ -2036,10 +2036,9 @@ struct route_map_rule_cmd route_set_lcommunity_cmd = { /* `set large-comm-list (<1-99>|<100-500>|WORD) delete' */ /* For large community set mechanism. */ -static route_map_result_t route_set_lcommunity_delete(void *rule, - const struct prefix *pfx, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_lcommunity_delete(void *rule, const struct prefix *pfx, + route_map_object_t type, void *object) { struct community_list *list; struct lcommunity *merge; @@ -2092,12 +2091,19 @@ static route_map_result_t route_set_lcommunity_delete(void *rule, static void *route_set_lcommunity_delete_compile(const char *arg) { struct rmap_community *rcom; + char **splits; + int num; - rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community)); + frrstr_split(arg, " ", &splits, &num); - rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); + rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community)); + rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, splits[0]); rcom->name_hash = bgp_clist_hash_key(rcom->name); + for (int i = 0; i < num; i++) + XFREE(MTYPE_TMP, splits[i]); + XFREE(MTYPE_TMP, splits); + return rcom; } @@ -2120,11 +2126,9 @@ struct route_map_rule_cmd route_set_lcommunity_delete_cmd = { /* `set comm-list (<1-99>|<100-500>|WORD) delete' */ /* For community set mechanism. */ -static route_map_result_t route_set_community_delete( - void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_community_delete(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct community_list *list; struct community *merge; @@ -2177,12 +2181,19 @@ static route_map_result_t route_set_community_delete( static void *route_set_community_delete_compile(const char *arg) { struct rmap_community *rcom; + char **splits; + int num; - rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community)); + frrstr_split(arg, " ", &splits, &num); - rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); + rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community)); + rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, splits[0]); rcom->name_hash = bgp_clist_hash_key(rcom->name); + for (int i = 0; i < num; i++) + XFREE(MTYPE_TMP, splits[i]); + XFREE(MTYPE_TMP, splits); + return rcom; } @@ -2204,10 +2215,9 @@ struct route_map_rule_cmd route_set_community_delete_cmd = { /* `set extcommunity rt COMMUNITY' */ /* For community set mechanism. Used by _rt and _soo. */ -static route_map_result_t route_set_ecommunity(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_ecommunity(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct ecommunity *ecom; struct ecommunity *new_ecom; @@ -2292,10 +2302,9 @@ struct route_map_rule_cmd route_set_ecommunity_soo_cmd = { /* `set origin ORIGIN' */ /* For origin set. */ -static route_map_result_t route_set_origin(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_origin(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { uint8_t *origin; struct bgp_path_info *path; @@ -2342,10 +2351,9 @@ struct route_map_rule_cmd route_set_origin_cmd = { /* `set atomic-aggregate' */ /* For atomic aggregate set. */ -static route_map_result_t route_set_atomic_aggregate(void *rule, - const struct prefix *pfx, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_atomic_aggregate(void *rule, const struct prefix *pfx, + route_map_object_t type, void *object) { struct bgp_path_info *path; @@ -2381,10 +2389,9 @@ struct aggregator { struct in_addr address; }; -static route_map_result_t route_set_aggregator_as(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_aggregator_as(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct bgp_path_info *path; struct aggregator *aggregator; @@ -2435,9 +2442,9 @@ struct route_map_rule_cmd route_set_aggregator_as_cmd = { }; /* Set tag to object. object must be pointer to struct bgp_path_info */ -static route_map_result_t route_set_tag(void *rule, - const struct prefix *prefix, - route_map_object_t type, void *object) +static enum route_map_cmd_result_t +route_set_tag(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { route_tag_t *tag; struct bgp_path_info *path; @@ -2460,10 +2467,9 @@ static struct route_map_rule_cmd route_set_tag_cmd = { }; /* Set label-index to object. object must be pointer to struct bgp_path_info */ -static route_map_result_t route_set_label_index(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_label_index(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct rmap_value *rv; struct bgp_path_info *path; @@ -2493,10 +2499,9 @@ static struct route_map_rule_cmd route_set_label_index_cmd = { /* `match ipv6 address IP_ACCESS_LIST' */ -static route_map_result_t route_match_ipv6_address(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_ipv6_address(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct access_list *alist; @@ -2529,10 +2534,9 @@ struct route_map_rule_cmd route_match_ipv6_address_cmd = { /* `match ipv6 next-hop IP_ADDRESS' */ -static route_map_result_t route_match_ipv6_next_hop(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_ipv6_next_hop(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct in6_addr *addr = rule; struct bgp_path_info *path; @@ -2581,7 +2585,7 @@ struct route_map_rule_cmd route_match_ipv6_next_hop_cmd = { /* `match ipv6 address prefix-list PREFIX_LIST' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -2606,9 +2610,9 @@ struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = { /* `match ipv6 next-hop type <TYPE>' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix, - route_map_object_t type, void *object) + route_map_object_t type, void *object) { struct bgp_path_info *path; struct in6_addr *addr = rule; @@ -2616,7 +2620,7 @@ route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix, if (type == RMAP_BGP && prefix->family == AF_INET6) { path = (struct bgp_path_info *)object; if (!path || !path->attr) - return RMAP_DENYMATCH; + return RMAP_NOMATCH; if (IPV6_ADDR_SAME(&path->attr->mp_nexthop_global, addr) && !path->attr->nh_ifindex) @@ -2654,10 +2658,9 @@ struct route_map_rule_cmd route_match_ipv6_next_hop_type_cmd = { /* `set ipv6 nexthop global IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ -static route_map_result_t route_set_ipv6_nexthop_global(void *rule, - const struct prefix *p, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_ipv6_nexthop_global(void *rule, const struct prefix *p, + route_map_object_t type, void *object) { struct in6_addr *address; struct bgp_path_info *path; @@ -2713,7 +2716,7 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_global_cmd = { route_set_ipv6_nexthop_global_free}; /* Set next-hop preference value. */ -static route_map_result_t +static enum route_map_cmd_result_t route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -2767,10 +2770,9 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_prefer_global_cmd = { /* `set ipv6 nexthop local IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ -static route_map_result_t route_set_ipv6_nexthop_local(void *rule, - const struct prefix *p, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_ipv6_nexthop_local(void *rule, const struct prefix *p, + route_map_object_t type, void *object) { struct in6_addr *address; struct bgp_path_info *path; @@ -2830,10 +2832,9 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = { /* `set ipv6 nexthop peer-address' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ -static route_map_result_t route_set_ipv6_nexthop_peer(void *rule, - const struct prefix *pfx, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_ipv6_nexthop_peer(void *rule, const struct prefix *pfx, + route_map_object_t type, void *object) { struct in6_addr peer_address; struct bgp_path_info *path; @@ -2908,10 +2909,9 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_peer_cmd = { /* `set ipv4 vpn next-hop A.B.C.D' */ -static route_map_result_t route_set_vpnv4_nexthop(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_vpnv4_nexthop(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct in_addr *address; struct bgp_path_info *path; @@ -2948,10 +2948,9 @@ static void *route_set_vpnv4_nexthop_compile(const char *arg) /* `set ipv6 vpn next-hop A.B.C.D' */ -static route_map_result_t route_set_vpnv6_nexthop(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_vpnv6_nexthop(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct in6_addr *address; struct bgp_path_info *path; @@ -3004,10 +3003,9 @@ struct route_map_rule_cmd route_set_vpnv6_nexthop_cmd = { /* `set originator-id' */ /* For origin set. */ -static route_map_result_t route_set_originator_id(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_originator_id(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct in_addr *address; struct bgp_path_info *path; @@ -3408,31 +3406,34 @@ int bgp_route_map_update_timer(struct thread *thread) static void bgp_route_map_mark_update(const char *rmap_name) { - if (bm->t_rmap_update == NULL) { - struct listnode *node, *nnode; - struct bgp *bgp; - - /* rmap_update_timer of 0 means don't do route updates */ - if (bm->rmap_update_timer) { - bm->t_rmap_update = NULL; - thread_add_timer(bm->master, bgp_route_map_update_timer, - NULL, bm->rmap_update_timer, - &bm->t_rmap_update); - - /* Signal the groups that a route-map update event has - * started */ - for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) - update_group_policy_update(bgp, - BGP_POLICY_ROUTE_MAP, - rmap_name, 1, 1); - } else { - for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) - bgp_route_map_process_update(bgp, rmap_name, 0); + struct listnode *node, *nnode; + struct bgp *bgp; + + /* If new update is received before the current timer timed out, + * turn it off and start a new timer. + */ + if (bm->t_rmap_update != NULL) + THREAD_OFF(bm->t_rmap_update); + + /* rmap_update_timer of 0 means don't do route updates */ + if (bm->rmap_update_timer) { + thread_add_timer(bm->master, bgp_route_map_update_timer, + NULL, bm->rmap_update_timer, + &bm->t_rmap_update); + + /* Signal the groups that a route-map update event has + * started */ + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + update_group_policy_update(bgp, + BGP_POLICY_ROUTE_MAP, + rmap_name, 1, 1); + } else { + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + bgp_route_map_process_update(bgp, rmap_name, 0); #if ENABLE_BGP_VNC - zlog_debug("%s: calling vnc_routemap_update", __func__); - vnc_routemap_update(bgp, __func__); + zlog_debug("%s: calling vnc_routemap_update", __func__); + vnc_routemap_update(bgp, __func__); #endif - } } } diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 0637723990..22840d54c6 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -129,8 +129,10 @@ static void print_record(const struct pfx_record *record, struct vty *vty); static int is_synchronized(void); static int is_running(void); static void route_match_free(void *rule); -static route_map_result_t route_match(void *rule, const struct prefix *prefix, - route_map_object_t type, void *object); +static enum route_map_cmd_result_t route_match(void *rule, + const struct prefix *prefix, + route_map_object_t type, + void *object); static void *route_match_compile(const char *arg); static void revalidate_bgp_node(struct bgp_node *bgp_node, afi_t afi, safi_t safi); @@ -140,7 +142,6 @@ static struct rtr_mgr_config *rtr_config; static struct list *cache_list; static int rtr_is_running; static int rtr_is_stopping; -static int rtr_is_starting; static _Atomic int rtr_update_overflow; static int rpki_debug; static unsigned int polling_period; @@ -213,8 +214,10 @@ static void ipv6_addr_to_host_byte_order(const uint32_t *src, uint32_t *dest) dest[i] = ntohl(src[i]); } -static route_map_result_t route_match(void *rule, const struct prefix *prefix, - route_map_object_t type, void *object) +static enum route_map_cmd_result_t route_match(void *rule, + const struct prefix *prefix, + route_map_object_t type, + void *object) { int *rpki_status = rule; struct bgp_path_info *path; @@ -474,7 +477,7 @@ static void rpki_update_cb_sync_rtr(struct pfx_table *p __attribute__((unused)), const struct pfx_record rec, const bool added __attribute__((unused))) { - if (rtr_is_stopping || rtr_is_starting + if (rtr_is_stopping || atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst)) return; @@ -566,11 +569,9 @@ static int bgp_rpki_module_init(void) static int start(void) { - unsigned int waiting_time = 0; int ret; rtr_is_stopping = 0; - rtr_is_starting = 1; rtr_update_overflow = 0; if (list_isempty(cache_list)) { @@ -599,23 +600,6 @@ static int start(void) return ERROR; } rtr_is_running = 1; - RPKI_DEBUG("Waiting for rtr connection to synchronize."); - while (waiting_time++ <= initial_synchronisation_timeout) { - if (rtr_mgr_conf_in_sync(rtr_config)) - break; - - sleep(1); - } - if (rtr_mgr_conf_in_sync(rtr_config)) { - RPKI_DEBUG("Got synchronisation with at least one RPKI cache!"); - RPKI_DEBUG("Forcing revalidation."); - rtr_is_starting = 0; - revalidate_all_routes(); - } else { - RPKI_DEBUG( - "Timeout expired! Proceeding without RPKI validation data."); - rtr_is_starting = 0; - } XFREE(MTYPE_BGP_RPKI_CACHE_GROUP, groups); @@ -1196,7 +1180,7 @@ DEFPY (show_rpki_prefix, { if (!is_synchronized()) { - vty_out(vty, "No Conection to RPKI cache server.\n"); + vty_out(vty, "No Connection to RPKI cache server.\n"); return CMD_WARNING; } diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index ecde71279d..53175bfccf 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -156,8 +156,10 @@ void bgp_table_range_lookup(const struct bgp_table *table, struct prefix *p, struct bgp_node *node = bgp_node_from_rnode(table->route_table->top); struct bgp_node *matched = NULL; - while (node && node->p.prefixlen <= p->prefixlen - && prefix_match(&node->p, p)) { + if (node == NULL) + return; + + while (node->p.prefixlen <= p->prefixlen && prefix_match(&node->p, p)) { if (bgp_node_has_bgp_path_info_data(node) && node->p.prefixlen == p->prefixlen) { matched = node; @@ -167,10 +169,10 @@ void bgp_table_range_lookup(const struct bgp_table *table, struct prefix *p, &p->u.prefix, node->p.prefixlen)]); } - if (node == NULL) - return; - - if ((matched == NULL && node->p.prefixlen > maxlen) || !node->parent) + if (matched == NULL && node->p.prefixlen <= maxlen + && prefix_match(p, &node->p) && node->parent == NULL) + matched = node; + else if ((matched == NULL && node->p.prefixlen > maxlen) || !node->parent) return; else if (matched == NULL) matched = node = bgp_node_from_rnode(node->parent); diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index b64c51f341..21f1dff60d 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -716,7 +716,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) struct bgp_node *rn; struct bgp_path_info *ri; struct peer *peer; - int ret = RMAP_DENYMATCH; + route_map_result_t ret = RMAP_DENYMATCH; afi_t afi; safi_t safi; diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c index 54ca980cad..09b1cb429b 100644 --- a/bgpd/bgp_vpn.c +++ b/bgpd/bgp_vpn.c @@ -74,7 +74,7 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, json_object_string_add(json_ocode, "incomplete", "?"); } - for (rn = bgp_table_top(bgp->rib[afi][SAFI_MPLS_VPN]); rn; + for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; rn = bgp_route_next(rn)) { if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0) continue; @@ -200,7 +200,7 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, json_array); } else { route_vty_out_tmp(vty, &rm->p, path->attr, - SAFI_MPLS_VPN, use_json, + safi, use_json, json_array); } } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index d7f6b65384..4447c2ccf8 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -596,12 +596,61 @@ static void bgp_clear_vty_error(struct vty *vty, struct peer *peer, afi_t afi, } } +static int bgp_peer_clear(struct peer *peer, afi_t afi, safi_t safi, + struct listnode *nnode, enum bgp_clear_type stype) +{ + int ret = 0; + + /* if afi/.safi not specified, spin thru all of them */ + if ((afi == AFI_UNSPEC) && (safi == SAFI_UNSPEC)) { + afi_t tmp_afi; + safi_t tmp_safi; + + FOREACH_AFI_SAFI (tmp_afi, tmp_safi) { + if (!peer->afc[tmp_afi][tmp_safi]) + continue; + + if (stype == BGP_CLEAR_SOFT_NONE) + ret = peer_clear(peer, &nnode); + else + ret = peer_clear_soft(peer, tmp_afi, tmp_safi, + stype); + } + /* if afi specified and safi not, spin thru safis on this afi */ + } else if (safi == SAFI_UNSPEC) { + safi_t tmp_safi; + + for (tmp_safi = SAFI_UNICAST; + tmp_safi < SAFI_MAX; tmp_safi++) { + if (!peer->afc[afi][tmp_safi]) + continue; + + if (stype == BGP_CLEAR_SOFT_NONE) + ret = peer_clear(peer, &nnode); + else + ret = peer_clear_soft(peer, afi, + tmp_safi, stype); + } + /* both afi/safi specified, let the caller know if not defined */ + } else { + if (!peer->afc[afi][safi]) + return 1; + + if (stype == BGP_CLEAR_SOFT_NONE) + ret = peer_clear(peer, &nnode); + else + ret = peer_clear_soft(peer, afi, safi, stype); + } + + return ret; +} + /* `clear ip bgp' functions. */ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, enum clear_sort sort, enum bgp_clear_type stype, const char *arg) { - int ret; + int ret = 0; bool found = false; struct peer *peer; struct listnode *node, *nnode; @@ -614,28 +663,17 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, */ if (sort == clear_all) { for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (!peer->afc[afi][safi]) - continue; - - if (stype == BGP_CLEAR_SOFT_NONE) - ret = peer_clear(peer, &nnode); - else - ret = peer_clear_soft(peer, afi, safi, stype); + ret = bgp_peer_clear(peer, afi, safi, nnode, + stype); if (ret < 0) bgp_clear_vty_error(vty, peer, afi, safi, ret); - else - found = true; } /* This is to apply read-only mode on this clear. */ if (stype == BGP_CLEAR_SOFT_NONE) bgp->update_delay_over = 0; - if (!found) - vty_out(vty, "%%BGP: No %s peer configured\n", - afi_safi_print(afi, safi)); - return CMD_SUCCESS; } @@ -666,12 +704,11 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, } } - if (!peer->afc[afi][safi]) + ret = bgp_peer_clear(peer, afi, safi, NULL, stype); + + /* if afi/safi not defined for this peer, let caller know */ + if (ret == 1) ret = BGP_ERR_AF_UNCONFIGURED; - else if (stype == BGP_CLEAR_SOFT_NONE) - ret = peer_clear(peer, NULL); - else - ret = peer_clear_soft(peer, afi, safi, stype); if (ret < 0) bgp_clear_vty_error(vty, peer, afi, safi, ret); @@ -690,13 +727,7 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, } for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { - if (!peer->afc[afi][safi]) - continue; - - if (stype == BGP_CLEAR_SOFT_NONE) - ret = peer_clear(peer, NULL); - else - ret = peer_clear_soft(peer, afi, safi, stype); + ret = bgp_peer_clear(peer, afi, safi, nnode, stype); if (ret < 0) bgp_clear_vty_error(vty, peer, afi, safi, ret); @@ -718,13 +749,7 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, if (peer->sort == BGP_PEER_IBGP) continue; - if (!peer->afc[afi][safi]) - continue; - - if (stype == BGP_CLEAR_SOFT_NONE) - ret = peer_clear(peer, &nnode); - else - ret = peer_clear_soft(peer, afi, safi, stype); + ret = bgp_peer_clear(peer, afi, safi, nnode, stype); if (ret < 0) bgp_clear_vty_error(vty, peer, afi, safi, ret); @@ -748,12 +773,7 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, if (peer->as != as) continue; - if (!peer->afc[afi][safi]) - ret = BGP_ERR_AF_UNCONFIGURED; - else if (stype == BGP_CLEAR_SOFT_NONE) - ret = peer_clear(peer, &nnode); - else - ret = peer_clear_soft(peer, afi, safi, stype); + ret = bgp_peer_clear(peer, afi, safi, nnode, stype); if (ret < 0) bgp_clear_vty_error(vty, peer, afi, safi, ret); @@ -6075,7 +6095,7 @@ DEFUN (neighbor_allowas_in, NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Accept as-path with my AS present in it\n" - "Number of occurences of AS number\n" + "Number of occurrences of AS number\n" "Only accept my AS in the as-path if the route was originated in my AS\n") { int idx_peer = 1; @@ -6109,7 +6129,7 @@ ALIAS_HIDDEN( "neighbor <A.B.C.D|X:X::X:X|WORD> allowas-in [<(1-10)|origin>]", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Accept as-path with my AS present in it\n" - "Number of occurences of AS number\n" + "Number of occurrences of AS number\n" "Only accept my AS in the as-path if the route was originated in my AS\n") DEFUN (no_neighbor_allowas_in, @@ -6119,7 +6139,7 @@ DEFUN (no_neighbor_allowas_in, NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "allow local ASN appears in aspath attribute\n" - "Number of occurences of AS number\n" + "Number of occurrences of AS number\n" "Only accept my AS in the as-path if the route was originated in my AS\n") { int idx_peer = 2; @@ -6141,7 +6161,7 @@ ALIAS_HIDDEN( "no neighbor <A.B.C.D|X:X::X:X|WORD> allowas-in [<(1-10)|origin>]", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "allow local ASN appears in aspath attribute\n" - "Number of occurences of AS number\n" + "Number of occurrences of AS number\n" "Only accept my AS in the as-path if the route was originated in my AS\n") DEFUN (neighbor_ttl_security, @@ -7244,8 +7264,8 @@ DEFUN (clear_ip_bgp_all, { char *vrf = NULL; - afi_t afi = AFI_IP6; - safi_t safi = SAFI_UNICAST; + afi_t afi = AFI_UNSPEC; + safi_t safi = SAFI_UNSPEC; enum clear_sort clr_sort = clear_peer; enum bgp_clear_type clr_type; char *clr_arg = NULL; @@ -7287,6 +7307,9 @@ DEFUN (clear_ip_bgp_all, } else if (argv_find(argv, argc, "PGNAME", &idx)) { clr_sort = clear_peer; clr_arg = argv[idx]->arg; + } else if (argv_find(argv, argc, "WORD", &idx)) { + clr_sort = clear_peer; + clr_arg = argv[idx]->arg; } else if (argv_find(argv, argc, "(1-4294967295)", &idx)) { clr_sort = clear_as; clr_arg = argv[idx]->arg; @@ -7773,7 +7796,7 @@ static void bgp_show_bestpath_json(struct bgp *bgp, json_object *json) /* Show BGP peer's summary information. */ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, - bool use_json, json_object *json) + bool use_json) { struct peer *peer; struct listnode *node, *nnode; @@ -7784,6 +7807,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, int len; int max_neighbor_width = 0; int pfx_rcd_safi; + json_object *json = NULL; json_object *json_peer = NULL; json_object *json_peers = NULL; struct peer_af *paf; @@ -7798,9 +7822,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, pfx_rcd_safi = safi; if (use_json) { - if (json == NULL) - json = json_object_new_object(); - + json = json_object_new_object(); json_peers = json_object_new_object(); } else { /* Loop over all neighbors that will be displayed to determine @@ -8205,8 +8227,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, } static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, - int safi, bool use_json, - json_object *json) + int safi, bool use_json) { int is_first = 1; int afi_wildcard = (afi == AFI_MAX); @@ -8224,6 +8245,7 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, while (safi < SAFI_MAX) { if (bgp_afi_safi_peer_exists(bgp, afi, safi)) { nbr_output = true; + if (is_wildcard) { /* * So limit output to those afi/safi @@ -8232,8 +8254,6 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, * them */ if (use_json) { - json = json_object_new_object(); - if (!is_first) vty_out(vty, ",\n"); else @@ -8248,8 +8268,7 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, safi)); } } - bgp_show_summary(vty, bgp, afi, safi, use_json, - json); + bgp_show_summary(vty, bgp, afi, safi, use_json); } safi++; if (!safi_wildcard) @@ -8275,7 +8294,6 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, { struct listnode *node, *nnode; struct bgp *bgp; - json_object *json = NULL; int is_first = 1; bool nbr_output = false; @@ -8285,8 +8303,6 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { nbr_output = true; if (use_json) { - json = json_object_new_object(); - if (!is_first) vty_out(vty, ",\n"); else @@ -8302,7 +8318,7 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, ? VRF_DEFAULT_NAME : bgp->name); } - bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json, json); + bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json); } if (use_json) @@ -8333,8 +8349,8 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, return CMD_WARNING; } - bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json, - NULL); + bgp_show_summary_afi_safi(vty, bgp, afi, safi, + use_json); return CMD_SUCCESS; } } @@ -8342,7 +8358,7 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, bgp = bgp_get_default(); if (bgp) - bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json, NULL); + bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json); else { if (use_json) vty_out(vty, "{}\n"); @@ -13199,20 +13215,44 @@ void bgp_vty_init(void) install_element(BGP_NODE, &no_neighbor_nexthop_self_all_hidden_cmd); install_element(BGP_IPV4_NODE, &neighbor_nexthop_self_force_cmd); install_element(BGP_IPV4_NODE, &no_neighbor_nexthop_self_force_cmd); + install_element(BGP_IPV4_NODE, &neighbor_nexthop_self_all_hidden_cmd); + install_element(BGP_IPV4_NODE, + &no_neighbor_nexthop_self_all_hidden_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_IPV4M_NODE, &neighbor_nexthop_self_all_hidden_cmd); + install_element(BGP_IPV4M_NODE, + &no_neighbor_nexthop_self_all_hidden_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_IPV4L_NODE, &neighbor_nexthop_self_all_hidden_cmd); + install_element(BGP_IPV4L_NODE, + &no_neighbor_nexthop_self_all_hidden_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_IPV6_NODE, &neighbor_nexthop_self_all_hidden_cmd); + install_element(BGP_IPV6_NODE, + &no_neighbor_nexthop_self_all_hidden_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_IPV6M_NODE, &neighbor_nexthop_self_all_hidden_cmd); + install_element(BGP_IPV6M_NODE, + &no_neighbor_nexthop_self_all_hidden_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_IPV6L_NODE, &neighbor_nexthop_self_all_hidden_cmd); + install_element(BGP_IPV6L_NODE, + &no_neighbor_nexthop_self_all_hidden_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_VPNV4_NODE, &neighbor_nexthop_self_all_hidden_cmd); + install_element(BGP_VPNV4_NODE, + &no_neighbor_nexthop_self_all_hidden_cmd); install_element(BGP_VPNV6_NODE, &neighbor_nexthop_self_force_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_nexthop_self_force_cmd); + install_element(BGP_VPNV6_NODE, &neighbor_nexthop_self_all_hidden_cmd); + install_element(BGP_VPNV6_NODE, + &no_neighbor_nexthop_self_all_hidden_cmd); /* "neighbor as-override" commands. */ install_element(BGP_NODE, &neighbor_as_override_hidden_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index d79a68dcab..b5f267cc38 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -8047,3 +8047,61 @@ void bgp_terminate(void) bgp_mac_finish(); } + +struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp, + const char *ip_str, bool use_json) +{ + int ret; + struct peer *peer; + union sockunion su; + + /* Get peer sockunion. */ + ret = str2sockunion(ip_str, &su); + if (ret < 0) { + peer = peer_lookup_by_conf_if(bgp, ip_str); + if (!peer) { + peer = peer_lookup_by_hostname(bgp, ip_str); + + if (!peer) { + if (use_json) { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add( + json_no, + "malformedAddressOrName", + ip_str); + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json_no, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json_no); + } else + vty_out(vty, + "%% Malformed address or name: %s\n", + ip_str); + return NULL; + } + } + return peer; + } + + /* Peer structure lookup. */ + peer = peer_lookup(bgp, &su); + if (!peer) { + if (use_json) { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", + "No such neighbor in this view/vrf"); + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json_no, JSON_C_TO_STRING_PRETTY)); + json_object_free(json_no); + } else + vty_out(vty, "No such neighbor in this view/vrf\n"); + return NULL; + } + + return peer; +} + diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 777db0ce22..9e05fd5629 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1927,4 +1927,8 @@ extern void bgp_unset_redist_vrf_bitmaps(struct bgp *, vrf_id_t); /* For benefit of rfapi */ extern struct peer *peer_new(struct bgp *bgp); + +extern struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp, + const char *ip_str, bool use_json); + #endif /* _QUAGGA_BGPD_H */ diff --git a/configure.ac b/configure.ac index 961336fbd0..134c8692d4 100755 --- a/configure.ac +++ b/configure.ac @@ -572,6 +572,20 @@ AC_ARG_ENABLE([thread-sanitizer], AS_HELP_STRING([--enable-thread-sanitizer], [enable ThreadSanitizer support for detecting data races])) AC_ARG_ENABLE([memory-sanitizer], AS_HELP_STRING([--enable-memory-sanitizer], [enable MemorySanitizer support for detecting uninitialized memory reads])) +AC_ARG_WITH([crypto], + AS_HELP_STRING([--with-crypto=<internal|openssl>], [choose between different implementations of cryptographic functions(default value is --with-crypto=internal)])) + +#if openssl, else use the internal +AS_IF([test x"${with_crypto}" = x"openssl"], [ +AC_CHECK_LIB([crypto], [EVP_DigestInit], [LIBS="$LIBS -lcrypto"], [], []) +if test $ac_cv_lib_crypto_EVP_DigestInit = no; then + AC_MSG_ERROR([build with openssl has been specified but openssl library was not found on your system]) +else + AC_DEFINE([CRYPTO_OPENSSL], [1], [Compile with openssl support]) +fi +], [test x"${with_crypto}" = x"internal" || test x"${with_crypto}" = x"" ], [AC_DEFINE([CRYPTO_INTERNAL], [1], [Compile with internal cryptographic implementation]) +], [AC_MSG_ERROR([Unknown value for --with-crypto])] +) AS_IF([test "${enable_clippy_only}" != "yes"], [ AC_CHECK_HEADERS([json-c/json.h]) diff --git a/debian/.gitignore b/debian/.gitignore new file mode 100644 index 0000000000..0b267c6f5c --- /dev/null +++ b/debian/.gitignore @@ -0,0 +1,13 @@ + +/.debhelper/ +/*/ +!/tests/ +!/source + +/*.log +/*.substvars +/*.debhelper +/autoreconf.* +/files +/frr.init +/frr.service diff --git a/doc/developer/building-frr-for-centos6.rst b/doc/developer/building-frr-for-centos6.rst index ee0ffc2bf7..3d9edbe3a1 100644 --- a/doc/developer/building-frr-for-centos6.rst +++ b/doc/developer/building-frr-for-centos6.rst @@ -45,7 +45,7 @@ Add packages: sudo yum install git autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig \ - json-c-devel pam-devel flex epel-release c-ares-devel + json-c-devel pam-devel flex epel-release c-ares-devel libcap-devel Install newer version of bison (CentOS 6 package source is too old) from CentOS 7: diff --git a/doc/developer/building-frr-for-centos7.rst b/doc/developer/building-frr-for-centos7.rst index 67f71bc3a5..cd90d41ffb 100644 --- a/doc/developer/building-frr-for-centos7.rst +++ b/doc/developer/building-frr-for-centos7.rst @@ -21,7 +21,7 @@ Add packages: sudo yum install git autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig \ json-c-devel pam-devel bison flex pytest c-ares-devel \ - python-devel systemd-devel python-sphinx + python-devel systemd-devel python-sphinx libcap-devel .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-debian8.rst b/doc/developer/building-frr-for-debian8.rst index 76f927853d..c12bf46f8d 100644 --- a/doc/developer/building-frr-for-debian8.rst +++ b/doc/developer/building-frr-for-debian8.rst @@ -18,7 +18,7 @@ Add packages: sudo apt-get install git autoconf automake libtool make \ libreadline-dev texinfo libjson-c-dev pkg-config bison flex python3-pip \ libc-ares-dev python3-dev python3-sphinx build-essential libsystemd-dev \ - libsnmp-dev + libsnmp-dev libcap-dev Install newer pytest (>3.0) from pip diff --git a/doc/developer/building-frr-for-debian9.rst b/doc/developer/building-frr-for-debian9.rst index e58c59f451..f976b9f49a 100644 --- a/doc/developer/building-frr-for-debian9.rst +++ b/doc/developer/building-frr-for-debian9.rst @@ -11,7 +11,7 @@ Add packages: sudo apt-get install git autoconf automake libtool make \ libreadline-dev texinfo libjson-c-dev pkg-config bison flex \ libc-ares-dev python3-dev python3-pytest python3-sphinx build-essential \ - libsnmp-dev libsystemd-dev + libsnmp-dev libsystemd-dev libcap-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-fedora.rst b/doc/developer/building-frr-for-fedora.rst index 0bfd43e93c..d8405eb351 100644 --- a/doc/developer/building-frr-for-fedora.rst +++ b/doc/developer/building-frr-for-fedora.rst @@ -14,7 +14,7 @@ Installing Dependencies sudo dnf install git autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig json-c-devel \ pam-devel python3-pytest bison flex c-ares-devel python3-devel \ - python3-sphinx perl-core patch systemd-devel + python3-sphinx perl-core patch systemd-devel libcap-devel .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu1404.rst b/doc/developer/building-frr-for-ubuntu1404.rst index 569b3bded1..cc54415266 100644 --- a/doc/developer/building-frr-for-ubuntu1404.rst +++ b/doc/developer/building-frr-for-ubuntu1404.rst @@ -14,7 +14,7 @@ Installing Dependencies git autoconf automake libtool make libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ libc-ares-dev python3-dev python3-sphinx install-info build-essential \ - libsnmp-dev perl + libsnmp-dev perl libcap-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu1604.rst b/doc/developer/building-frr-for-ubuntu1604.rst index 03852a62aa..63c6f8648c 100644 --- a/doc/developer/building-frr-for-ubuntu1604.rst +++ b/doc/developer/building-frr-for-ubuntu1604.rst @@ -14,7 +14,7 @@ Installing Dependencies git autoconf automake libtool make libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ - install-info build-essential libsystemd-dev libsnmp-dev perl + install-info build-essential libsystemd-dev libsnmp-dev perl libcap-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu1804.rst b/doc/developer/building-frr-for-ubuntu1804.rst index 96c0efe02a..9d85957d88 100644 --- a/doc/developer/building-frr-for-ubuntu1804.rst +++ b/doc/developer/building-frr-for-ubuntu1804.rst @@ -14,7 +14,7 @@ Installing Dependencies git autoconf automake libtool make libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ - install-info build-essential libsystemd-dev libsnmp-dev perl + install-info build-essential libsystemd-dev libsnmp-dev perl libcap-dev .. include:: building-libyang.rst diff --git a/doc/developer/cli.rst b/doc/developer/cli.rst index c0716a5c93..cf35b03f0c 100644 --- a/doc/developer/cli.rst +++ b/doc/developer/cli.rst @@ -160,27 +160,27 @@ parser, but this is merely a dumb copy job. Here is a brief summary of the various token types along with examples. -+-----------------+-----------------+-------------------------------------------------------------+ -| Token type | Syntax | Description | -+=================+=================+=============================================================+ -| ``WORD`` | ``show ip bgp`` | Matches itself. In the given example every token is a WORD. | -+-----------------+-----------------+-------------------------------------------------------------+ -| ``IPV4`` | ``A.B.C.D`` | Matches an IPv4 address. | -+-----------------+-----------------+-------------------------------------------------------------+ -| ``IPV6`` | ``X:X::X:X`` | Matches an IPv6 address. | -+-----------------+-----------------+-------------------------------------------------------------+ -| ``IPV4_PREFIX`` | ``A.B.C.D/M`` | Matches an IPv4 prefix in CIDR notation. | -+-----------------+-----------------+-------------------------------------------------------------+ -| ``IPV6_PREFIX`` | ``X:X::X:X/M`` | Matches an IPv6 prefix in CIDR notation. | -+-----------------+-----------------+-------------------------------------------------------------+ -| ``MAC`` | ``M:A:C`` | Matches a 48-bit mac address. | -+-----------------+-----------------+-------------------------------------------------------------+ -| ``MAC_PREFIX`` | ``M:A:C/M`` | Matches a 48-bit mac address with a mask. | -+-----------------+-----------------+-------------------------------------------------------------+ -| ``VARIABLE`` | ``FOOBAR`` | Matches anything. | -+-----------------+-----------------+-------------------------------------------------------------+ -| ``RANGE`` | ``(X-Y)`` | Matches numbers in the range X..Y inclusive. | -+-----------------+-----------------+-------------------------------------------------------------+ ++-----------------+-------------------+-------------------------------------------------------------+ +| Token type | Syntax | Description | ++=================+===================+=============================================================+ +| ``WORD`` | ``show ip bgp`` | Matches itself. In the given example every token is a WORD. | ++-----------------+-------------------+-------------------------------------------------------------+ +| ``IPV4`` | ``A.B.C.D`` | Matches an IPv4 address. | ++-----------------+-------------------+-------------------------------------------------------------+ +| ``IPV6`` | ``X:X::X:X`` | Matches an IPv6 address. | ++-----------------+-------------------+-------------------------------------------------------------+ +| ``IPV4_PREFIX`` | ``A.B.C.D/M`` | Matches an IPv4 prefix in CIDR notation. | ++-----------------+-------------------+-------------------------------------------------------------+ +| ``IPV6_PREFIX`` | ``X:X::X:X/M`` | Matches an IPv6 prefix in CIDR notation. | ++-----------------+-------------------+-------------------------------------------------------------+ +| ``MAC`` | ``X:X:X:X:X:X`` | Matches a 48-bit mac address. | ++-----------------+-------------------+-------------------------------------------------------------+ +| ``MAC_PREFIX`` | ``X:X:X:X:X:X/M`` | Matches a 48-bit mac address with a mask. | ++-----------------+-------------------+-------------------------------------------------------------+ +| ``VARIABLE`` | ``FOOBAR`` | Matches anything. | ++-----------------+-------------------+-------------------------------------------------------------+ +| ``RANGE`` | ``(X-Y)`` | Matches numbers in the range X..Y inclusive. | ++-----------------+-------------------+-------------------------------------------------------------+ When presented with user input, the parser will search over all defined commands in the current context to find a match. It is aware of the various diff --git a/doc/developer/library.rst b/doc/developer/library.rst index 4ba0c0ebc6..7cd493ccc4 100644 --- a/doc/developer/library.rst +++ b/doc/developer/library.rst @@ -8,6 +8,7 @@ Library Facilities (libfrr) :maxdepth: 2 memtypes + rcu lists logging hooks diff --git a/doc/developer/lists.rst b/doc/developer/lists.rst index fc47a67e42..5f020060ce 100644 --- a/doc/developer/lists.rst +++ b/doc/developer/lists.rst @@ -611,6 +611,38 @@ Head removal (pop) and deallocation: * note nothing between wrlock() and unlock() */ XFREE(MTYPE_ITEM, i); +FAQ +--- + +Why is the list head not ``const`` in the list APIs? + The semantics that a ``const`` list head would imply are not obvious. It + could mean any of the following: + + * the list just shouldn't be allocated/deallocated, but may be modified. + This doesn't actually work since the list head needs to be modified for + inserting or deleting items. + + * the list shouldn't be modified, but items can. This may make sense for + iterating, but it's not exactly consistent - an item might be on more + than one list, does it apply to all of them? If not, which one? + + * neither the list nor the items should be modified. This is consistent, + but hard to do without creating a ``const`` copy of every single list + function. Ease of use trumps this. + +Why is there no "is this item on a/the list" test? + It's slow for several of the data structures, and the work of adding it + just hasn't been done. It can certainly be added if it's needed. + +Why is it ``PREDECL`` + ``DECLARE`` instead of ``DECLARE`` + ``DEFINE``? + The rule is that a ``DEFINE`` must be in a ``.c`` file, and linked exactly + once because it defines some kind of global symbol. This is not the case + for the data structure macros; they only define ``static`` symbols and it + is perfectly fine to include both ``PREDECL`` and ``DECLARE`` in a header + file. It is also perfectly fine to have the same ``DECLARE`` statement in + 2 ``.c`` files, but only **if the macro arguments are identical.** Maybe + don't do that unless you really need it. + FRR lists --------- diff --git a/doc/developer/rcu.rst b/doc/developer/rcu.rst new file mode 100644 index 0000000000..c2ddf93f53 --- /dev/null +++ b/doc/developer/rcu.rst @@ -0,0 +1,269 @@ +.. highlight:: c + +RCU +=== + +Introduction +------------ + +RCU (Read-Copy-Update) is, fundamentally, a paradigm of multithreaded +operation (and not a set of APIs.) The core ideas are: + +* longer, complicated updates to structures are made only on private, + "invisible" copies. Other threads, when they access the structure, see an + older (but consistent) copy. + +* once done, the updated copy is swapped in in a single operation so that + other threads see either the old or the new data but no inconsistent state + between. + +* the old instance is only released after making sure that it is impossible + any other thread might still be reading it. + +For more information, please search for general or Linux kernel RCU +documentation; there is no way this doc can be comprehensive in explaining the +interactions: + +* https://en.wikipedia.org/wiki/Read-copy-update +* https://www.kernel.org/doc/html/latest/kernel-hacking/locking.html#avoiding-locks-read-copy-update +* https://lwn.net/Articles/262464/ +* http://www.rdrop.com/users/paulmck/RCU/rclock_OLS.2001.05.01c.pdf +* http://lse.sourceforge.net/locking/rcupdate.html + +RCU, the TL;DR +^^^^^^^^^^^^^^ + +#. data structures are always consistent for reading. That's the "R" part. +#. reading never blocks / takes a lock. +#. rcu_read_lock is not a lock in the traditional sense. Think of it as a + "reservation"; it notes what the *oldest* possible thing the thread might + be seeing is, and which thus can't be deleted yet. +#. you create some object, finish it up, and then publish it. +#. publishing is an ``atomic_*`` call with ``memory_order_release``, which + tells the compiler to make sure prior memory writes have completed before + doing the atomic op. +#. ``ATOMLIST_*`` ``add`` operations do the ``memory_order_release`` for you. +#. you can't touch the object after it is published, except with atomic ops. +#. because you can't touch it, if you want to change it you make a new copy, + work on that, and then publish the new copy. That's the "CU" part. +#. deleting the object is also an atomic op. +#. other threads that started working before you published / deleted an object + might not see the new object / still see the deleted object. +#. because other threads may still see deleted objects, the ``free()`` needs + to be delayed. That's what :c:func:`rcu_free()` is for. + + +When (not) to use RCU +^^^^^^^^^^^^^^^^^^^^^ + +RCU is designed for read-heavy workloads where objects are updated relatively +rarely, but frequently accessed. Do *not* indiscriminately replace locking by +RCU patterns. + +The "copy" part of RCU implies that, while updating, several copies of a given +object exist in parallel. Even after the updated copy is swapped in, the old +object remains queued for freeing until all other threads are guaranteed to +not be accessing it anymore, due to passing a sequence point. In addition to +the increased memory usage, there may be some bursted (due to batching) malloc +contention when the RCU cleanup thread does its thing and frees memory. + +Other useful patterns +^^^^^^^^^^^^^^^^^^^^^ + +In addition to the full "copy object, apply changes, atomically update" +approach, there are 2 "reduced" usage cases that can be done: + +* atomically updating single pieces of a particular object, e.g. some flags + or configuration piece + +* straight up read-only / immutable objects + +Both of these cases can be considered RCU "subsets". For example, when +maintaining an atomic list of items, but these items only have a single +integer value that needs to be updated, that value can be atomically updated +without copying the entire object. However, the object still needs to be +free'd through :c:func:`rcu_free()` since reading/updating and deleting might +be happening concurrently. The same applies for immutable objects; deletion +might still race with reading so they need to be free'd through RCU. + +FRR API +------- + +Before diving into detail on the provided functions, it is important to note +that the FRR RCU API covers the **cleanup part of RCU, not the read-copy-update +paradigm itself**. These parts are handled by standard C11 atomic operations, +and by extension through the atomic data structures (ATOMLIST, ATOMSORT & co.) + +The ``rcu_*`` functions only make sense in conjunction with these RCU access +patterns. If you're calling the RCU API but not using these, something is +wrong. The other way around is not necessarily true; it is possible to use +atomic ops & datastructures with other types of locking, e.g. rwlocks. + +.. c:function:: void rcu_read_lock() +.. c:function:: void rcu_read_unlock() + + These functions acquire / release the RCU read-side lock. All access to + RCU-guarded data must be inside a block guarded by these. Any number of + threads may hold the RCU read-side lock at a given point in time, including + both no threads at all and all threads. + + The functions implement a depth counter, i.e. can be nested. The nested + calls are cheap, since they only increment/decrement the counter. + Therefore, any place that uses RCU data and doesn't have a guarantee that + the caller holds RCU (e.g. ``lib/`` code) should just have its own + rcu_read_lock/rcu_read_unlock pair. + + At the "root" level (e.g. un-nested), these calls can incur the cost of one + syscall (to ``futex()``). That puts them on about the same cost as a + mutex lock/unlock. + + The ``thread_master`` code currently always holds RCU everywhere, except + while doing the actual ``poll()`` syscall. This is both an optimization as + well as an "easement" into getting RCU going. The current implementation + contract is that any ``struct thread *`` callback is called with a RCU + holding depth of 1, and that this is owned by the thread so it may (should) + drop and reacquire it when doing some longer-running work. + + .. warning:: + + The RCU read-side lock must be held **continuously** for the entire time + any piece of RCU data is used. This includes any access to RCU data + after the initial ``atomic_load``. If the RCU read-side lock is + released, any RCU-protected pointers as well as the data they refer to + become invalid, as another thread may have called :c:func:`rcu_free` on + them. + +.. c:type:: struct rcu_head +.. c:type:: struct rcu_head_close +.. c:type:: struct rcu_action + + The ``rcu_head`` structures are small (16-byte) bits that contain the + queueing machinery for the RCU sweeper/cleanup mechanisms. + + Any piece of data that is cleaned up by RCU needs to have a matching + ``rcu_head`` embedded in it. If there is more than one cleanup operation + to be done (e.g. closing a file descriptor), more than one ``rcu_head`` may + be embedded. + + .. warning:: + + It is not possible to reuse a ``rcu_head``. It is owned by the RCU code + as soon as ``rcu_*`` is called on it. + + The ``_close`` variant carries an extra ``int fd`` field to store the fd to + be closed. + + To minimize the amount of memory used for ``rcu_head``, details about the + RCU operation to be performed are moved into the ``rcu_action`` structure. + It contains e.g. the MTYPE for :c:func:`rcu_free` calls. The pointer to be + freed is stored as an offset relative to the ``rcu_head``, which means it + must be embedded as a struct field so the offset is constant. + + The ``rcu_action`` structure is an implementation detail. Using + ``rcu_free`` or ``rcu_close`` will set it up correctly without further + code needed. + + The ``rcu_head`` may be put in an union with other data if the other data + is only used during "life" of the data, since the ``rcu_head`` is used only + for the "death" of data. But note that other threads may still be reading + a piece of data while a thread is working to free it. + +.. c:function:: void rcu_free(struct memtype *mtype, struct X *ptr, field) + + Free a block of memory after RCU has ensured no other thread can be + accessing it anymore. The pointer remains valid for any other thread that + has called :c:func:`rcu_read_lock` before the ``rcu_free`` call. + + .. warning:: + + In some other RCU implementations, the pointer remains valid to the + *calling* thread if it is holding the RCU read-side lock. This is not + the case in FRR, particularly when running single-threaded. Enforcing + this rule also allows static analysis to find use-after-free issues. + + ``mtype`` is the libfrr ``MTYPE_FOO`` allocation type to pass to + :c:func:`XFREE`. + + ``field`` must be the name of a ``struct rcu_head`` member field in ``ptr``. + The offset of this field (which must be constant) is used to reduce the + memory size of ``struct rcu_head``. + + .. note:: + + ``rcu_free`` (and ``rcu_close``) calls are more efficient if they are + put close to each other. When freeing several RCU'd resources, try to + move the calls next to each other (even if the data structures do not + directly point to each other.) + + Having the calls bundled reduces the cost of adding the ``rcu_head`` to + the RCU queue; the RCU queue is an atomic data structure whose usage + will require the CPU to acquire an exclusive hold on relevant cache + lines. + +.. c:function:: void rcu_close(struct rcu_head_close *head, int fd) + + Close a file descriptor after ensuring no other thread might be using it + anymore. Same as :c:func:`rcu_free`, except it calls ``close`` instead of + ``free``. + +Internals +^^^^^^^^^ + +.. c:type:: struct rcu_thread + + Per-thread state maintained by the RCU code, set up by the following + functions. A pointer to a thread's own ``rcu_thread`` is saved in + thread-local storage. + +.. c:function:: struct rcu_thread *rcu_thread_prepare(void) +.. c:function:: void rcu_thread_unprepare(struct rcu_thread *rcu_thread) +.. c:function:: void rcu_thread_start(struct rcu_thread *rcu_thread) + + Since the RCU code needs to have a list of all active threads, these + functions are used by the ``frr_pthread`` code to set up threads. Teardown + is automatic. It should not be necessary to call these functions. + + Any thread that accesses RCU-protected data needs to be registered with + these functions. Threads that do not access RCU-protected data may call + these functions but do not need to. + + Note that passing a pointer to RCU-protected data to some library which + accesses that pointer makes the library "access RCU-protected data". In + that case, either all of the library's threads must be registered for RCU, + or the code must instead pass a (non-RCU) copy of the data to the library. + +.. c:function:: void rcu_shutdown(void) + + Stop the RCU sweeper thread and make sure all cleanup has finished. + + This function is called on daemon exit by the libfrr code to ensure pending + RCU operations are completed. This is mostly to get a clean exit without + memory leaks from queued RCU operations. It should not be necessary to + call this function as libfrr handles this. + +FRR specifics and implementation details +---------------------------------------- + +The FRR RCU infrastructure has the following characteristics: + +* it is Epoch-based with a 32-bit wrapping counter. (This is somewhat + different from other Epoch-based approaches which may be designed to only + use 3 counter values, but works out to a simple implementation.) + +* instead of tracking CPUs as the Linux kernel does, threads are tracked. This + has exactly zero semantic impact, RCU just cares about "threads of + execution", which the kernel can optimize to CPUs but we can't. But it + really boils down to the same thing. + +* there are no ``rcu_dereference`` and ``rcu_assign_pointer`` - use + ``atomic_load`` and ``atomic_store`` instead. (These didn't exist when the + Linux RCU code was created.) + +* there is no ``synchronize_rcu``; this is a design choice but may be revisited + at a later point. ``synchronize_rcu`` blocks a thread until it is guaranteed + that no other threads might still be accessing data structures that they may + have access to at the beginning of the function call. This is a blocking + design and probably not appropriate for FRR. Instead, ``rcu_call`` can be + used to have the RCU sweeper thread make a callback after the same constraint + is fulfilled in an asynchronous way. Most needs should be covered by + ``rcu_free`` and ``rcu_close``. diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am index 996f12d47f..1fc593e566 100644 --- a/doc/developer/subdir.am +++ b/doc/developer/subdir.am @@ -42,6 +42,7 @@ dev_RSTFILES = \ doc/developer/packaging-debian.rst \ doc/developer/packaging-redhat.rst \ doc/developer/packaging.rst \ + doc/developer/rcu.rst \ doc/developer/testing.rst \ doc/developer/topotests-snippets.rst \ doc/developer/topotests.rst \ diff --git a/doc/figures/nodes.dot b/doc/figures/nodes.dot index d0e234958f..b548b5529a 100644 --- a/doc/figures/nodes.dot +++ b/doc/figures/nodes.dot @@ -55,7 +55,6 @@ digraph climodes { CONFIG_NODE -> KEYCHAIN_KEY_NODE [ label="key (0-2147483647)" ]; KEYCHAIN_NODE -> KEYCHAIN_KEY_NODE [ label="key (0-2147483647)" ]; KEYCHAIN_KEY_NODE -> KEYCHAIN_NODE [ label="no key (0-2147483647)" ]; - CONFIG_NODE -> LOGICALROUTER_NODE [ label="logical-router (1-65535) ns NAME" ]; CONFIG_NODE -> VRF_NODE [ label="vrf NAME" ]; CONFIG_NODE -> INTERFACE_NODE [ label="interface IFNAME vrf NAME" ]; INTERFACE_NODE -> LINK_PARAMS_NODE [ label="link-params" ]; diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index f2b1328075..c329ab6d9f 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -2138,20 +2138,40 @@ Dumping Messages and Routing Tables Other BGP Commands ------------------ +.. index:: clear bgp \* +.. clicmd:: clear bgp \* + + Clear all peers. + .. index:: clear bgp ipv4|ipv6 \* .. clicmd:: clear bgp ipv4|ipv6 \* - Clear all address family peers. + Clear all peers with this address-family activated. + +.. index:: clear bgp ipv4|ipv6 unicast \* +.. clicmd:: clear bgp ipv4|ipv6 unicast \* + + Clear all peers with this address-family and sub-address-family activated. .. index:: clear bgp ipv4|ipv6 PEER .. clicmd:: clear bgp ipv4|ipv6 PEER - Clear peers which have addresses of X.X.X.X + Clear peers with address of X.X.X.X and this address-family activated. + +.. index:: clear bgp ipv4|ipv6 unicast PEER +.. clicmd:: clear bgp ipv4|ipv6 unicast PEER + + Clear peer with address of X.X.X.X and this address-family and sub-address-family activated. + +.. index:: clear bgp ipv4|ipv6 PEER soft|in|out +.. clicmd:: clear bgp ipv4|ipv6 PEER soft|in|out + + Clear peer using soft reconfiguration in this address-family. -.. index:: clear bgp ipv4|ipv6 PEER soft in -.. clicmd:: clear bgp ipv4|ipv6 PEER soft in +.. index:: clear bgp ipv4|ipv6 unicast PEER soft|in|out +.. clicmd:: clear bgp ipv4|ipv6 unicast PEER soft|in|out - Clear peer using soft reconfiguration. + Clear peer using soft reconfiguration in this address-family and sub-address-family. .. _bgp-displaying-bgp-information: diff --git a/doc/user/installation.rst b/doc/user/installation.rst index b45c83ca1c..45549dccad 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -149,6 +149,11 @@ options from the list below. Turn off building of pimd. On some BSD platforms pimd will not build properly due to lack of kernel support. +.. option:: --disable-vrrpd + + Turn off building of vrrpd. Linux is required for vrrpd support; + other platforms are not supported. + .. option:: --disable-pbrd Turn off building of pbrd. This daemon currently requires linux in order to function @@ -194,11 +199,6 @@ options from the list below. Disable building of the example OSPF-API client. -.. option:: --disable-ospf-ri - - Disable support for OSPF Router Information (RFC4970 & RFC5088) this - requires support for Opaque LSAs and Traffic Engineering. - .. option:: --disable-isisd Do not build isisd. @@ -211,10 +211,6 @@ options from the list below. Enable IS-IS topology generator. -.. option:: --enable-isis-te - - Enable Traffic Engineering Extension for ISIS (RFC5305) - .. option:: --enable-realms Enable the support of Linux Realms. Convert tag values from 1-255 into a diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index f7607a54f7..6684a83e1f 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -423,6 +423,12 @@ Showing ISIS information Traffic Engineering =================== +.. note:: + + At this time, FRR offers partial support for some of the routing + protocol extensions that can be used with MPLS-TE. FRR does not + support a complete RSVP-TE solution currently. + .. index:: mpls-te on .. clicmd:: mpls-te on diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 6413c62995..2300cb0e19 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -195,7 +195,7 @@ Example of ospf6d configured on one interface and area: ipv6 ospf6 instance-id 0 ! router ospf6 - router-id 212.17.55.53 + ospf6 router-id 212.17.55.53 area 0.0.0.0 range 2001:770:105:2::/64 interface eth0 area 0.0.0.0 ! diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index 83e14d474f..3772cf9556 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -69,7 +69,7 @@ The instance number should be specified in the config when addressing a particul .. code-block:: frr router ospf 5 - router-id 1.2.3.4 + ospf router-id 1.2.3.4 area 0.0.0.0 authentication message-digest ... @@ -906,10 +906,13 @@ Opaque LSA .. index:: no capability opaque .. clicmd:: no capability opaque - *ospfd* supports Opaque LSA (:rfc:`2370`) as fundamental for MPLS Traffic - Engineering LSA. Prior to used MPLS TE, opaque-lsa must be enable in the - configuration file. Alternate command could be "mpls-te on" - (:ref:`ospf-traffic-engineering`). + *ospfd* supports Opaque LSA (:rfc:`2370`) as partial support for + MPLS Traffic Engineering LSAs. The opaque-lsa capability must be + enabled in the configuration. An alternate command could be + "mpls-te on" (:ref:`ospf-traffic-engineering`). Note that FRR + offers only partial support for some of the routing protocol + extensions that are used with MPLS-TE; it does not support a + complete RSVP-TE solution. .. index:: show ip ospf database (opaque-link|opaque-area|opaque-external) .. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) @@ -936,6 +939,12 @@ Opaque LSA Traffic Engineering =================== +.. note:: + + At this time, FRR offers partial support for some of the routing + protocol extensions that can be used with MPLS-TE. FRR does not + support a complete RSVP-TE solution currently. + .. index:: mpls-te on .. clicmd:: mpls-te on diff --git a/doc/user/overview.rst b/doc/user/overview.rst index 7f8ea392dc..5f9a7b937e 100644 --- a/doc/user/overview.rst +++ b/doc/user/overview.rst @@ -239,6 +239,15 @@ The indicators have the following semantics: * :mark:`CP` - control plane only (i.e. BGP route server / route reflector) * :mark:`N` - daemon/feature not supported by operating system + +Known Kernel Issues: +==================== + +- Linux + v6 Route Replacement - Linux kernels before 4.11 can cause issues with v6 route deletion when you + have ecmp routes installed into the kernel. This especially becomes apparent if the route is being + transformed from one ecmp path to another. + .. _supported-rfcs: Supported RFCs diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index bac61cbc58..09cbd7c7b0 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -153,8 +153,8 @@ Route Map Match Command Matches the specified `ipv4_addr`. -.. index:: match aspath AS_PATH -.. clicmd:: match aspath AS_PATH +.. index:: match as-path AS_PATH +.. clicmd:: match as-path AS_PATH Matches the specified `as_path`. diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst index 4568c2a901..111e9dc9e8 100644 --- a/doc/user/sharp.rst +++ b/doc/user/sharp.rst @@ -71,7 +71,7 @@ keyword. At present, no sharp commands will be preserved in the config. be used for pop and forward operations when the specified label is seen. .. index:: sharp watch -.. clicmd:: [no] sharp watch <nexthop|import> <A.B.C.D|X:X::X:X> [connected] +.. clicmd:: [no] sharp watch <nexthop <A.B.C.D|X:X::X:X>|import <A.B.C.D/M:X:X::X:X/M> [connected] Instruct zebra to monitor and notify sharp when the specified nexthop is changed. The notification from zebra is written into the debug log. diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index eefc5802a2..50c518d456 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -193,18 +193,25 @@ Standard Commands Link Parameters Commands ------------------------ +.. note:: + + At this time, FRR offers partial support for some of the routing + protocol extensions that can be used with MPLS-TE. FRR does not + support a complete RSVP-TE solution currently. + .. index:: link-params .. clicmd:: link-params .. index:: no link-param .. clicmd:: no link-param - Enter into the link parameters sub node. At least 'enable' must be set to - activate the link parameters, and consequently Traffic Engineering on this - interface. MPLS-TE must be enable at the OSPF - (:ref:`ospf-traffic-engineering`) or ISIS (:ref:`isis-traffic-engineering`) - router level in complement to this. Disable link parameters for this - interface. + Enter into the link parameters sub node. At least 'enable' must be + set to activate the link parameters, and consequently routing + information that could be used as part of Traffic Engineering on + this interface. MPLS-TE must be enable at the OSPF + (:ref:`ospf-traffic-engineering`) or ISIS + (:ref:`isis-traffic-engineering`) router level in complement to + this. Disable link parameters for this interface. Under link parameter statement, the following commands set the different TE values: @@ -361,6 +368,12 @@ commands in relationship to VRF. Here is an extract of some of those commands: will dump the routing table ``TABLENO`` of the *Linux network namespace* ``VRF``. +.. index:: show ip route vrf VRF tables +.. clicmd:: show ip route vrf VRF tables + + This command will dump the routing tables within the vrf scope. If `vrf all` + is executed, all routing tables will be dumped. + By using the :option:`-n` option, the *Linux network namespace* will be mapped over the *Zebra* VRF. One nice feature that is possible by handling *Linux network namespace* is the ability to name default VRF. At startup, *Zebra* diff --git a/eigrpd/eigrp_cli.c b/eigrpd/eigrp_cli.c new file mode 100644 index 0000000000..ba657a7d5d --- /dev/null +++ b/eigrpd/eigrp_cli.c @@ -0,0 +1,920 @@ +/* + * EIGRP daemon CLI implementation. + * + * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF") + * Rafael Zalamena + * + * 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; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + */ + +#include <zebra.h> + +#include "lib/command.h" +#include "lib/log.h" +#include "lib/northbound_cli.h" + +#include "eigrp_structs.h" +#include "eigrpd.h" +#include "eigrp_zebra.h" + +#ifndef VTYSH_EXTRACT_PL +#include "eigrpd/eigrp_cli_clippy.c" +#endif /* VTYSH_EXTRACT_PL */ + +/* + * XPath: /frr-eigrpd:eigrpd/instance + */ +DEFPY_NOSH( + router_eigrp, + router_eigrp_cmd, + "router eigrp (1-65535)$as", + ROUTER_STR + EIGRP_STR + AS_STR) +{ + char xpath[XPATH_MAXLEN]; + int rv; + + snprintf(xpath, sizeof(xpath), + "/frr-eigrpd:eigrpd/instance[asn='%s'][vrf='']", + as_str); + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + rv = nb_cli_apply_changes(vty, NULL); + if (rv == CMD_SUCCESS) + VTY_PUSH_XPATH(EIGRP_NODE, xpath); + + return rv; +} + +DEFPY_NOSH( + no_router_eigrp, + no_router_eigrp_cmd, + "no router eigrp (1-65535)$as", + NO_STR + ROUTER_STR + EIGRP_STR + AS_STR) +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), + "/frr-eigrpd:eigrpd/instance[asn='%s'][vrf='']", + as_str); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *asn = yang_dnode_get_string(dnode, "./asn"); + + vty_out(vty, "router eigrp %s\n", asn); +} + +void eigrp_cli_show_end_header(struct vty *vty, struct lyd_node *dnode) +{ + vty_out(vty, "!\n"); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/router-id + */ +DEFPY( + eigrp_router_id, + eigrp_router_id_cmd, + "eigrp router-id A.B.C.D$addr", + EIGRP_STR + "Router ID for this EIGRP process\n" + "EIGRP Router-ID in IP address format\n") +{ + nb_cli_enqueue_change(vty, "./router-id", NB_OP_MODIFY, addr_str); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_router_id, + no_eigrp_router_id_cmd, + "no eigrp router-id [A.B.C.D]", + NO_STR + EIGRP_STR + "Router ID for this EIGRP process\n" + "EIGRP Router-ID in IP address format\n") +{ + nb_cli_enqueue_change(vty, "./router-id", NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_router_id(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *router_id = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " eigrp router-id %s\n", router_id); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/passive-interface + */ +DEFPY( + eigrp_passive_interface, + eigrp_passive_interface_cmd, + "[no] passive-interface IFNAME", + NO_STR + "Suppress routing updates on an interface\n" + "Interface to suppress on\n") +{ + if (no) + nb_cli_enqueue_change(vty, "./passive-interface", + NB_OP_DESTROY, ifname); + else + nb_cli_enqueue_change(vty, "./passive-interface", + NB_OP_CREATE, ifname); + + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_passive_interface(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *ifname = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " passive-interface %s\n", ifname); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/active-time + */ +DEFPY( + eigrp_timers_active, + eigrp_timers_active_cmd, + "timers active-time <(1-65535)$timer|disabled$disabled>", + "Adjust routing timers\n" + "Time limit for active state\n" + "Active state time limit in seconds\n" + "Disable time limit for active state\n") +{ + if (disabled) + nb_cli_enqueue_change(vty, "./active-time", NB_OP_MODIFY, "0"); + else + nb_cli_enqueue_change(vty, "./active-time", + NB_OP_MODIFY, timer_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_timers_active, + no_eigrp_timers_active_cmd, + "no timers active-time [<(1-65535)|disabled>]", + NO_STR + "Adjust routing timers\n" + "Time limit for active state\n" + "Active state time limit in seconds\n" + "Disable time limit for active state\n") +{ + nb_cli_enqueue_change(vty, "./active-time", NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_active_time(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *timer = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " timers active-time %s\n", timer); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/variance + */ +DEFPY( + eigrp_variance, + eigrp_variance_cmd, + "variance (1-128)$variance", + "Control load balancing variance\n" + "Metric variance multiplier\n") +{ + nb_cli_enqueue_change(vty, "./variance", NB_OP_MODIFY, variance_str); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_variance, + no_eigrp_variance_cmd, + "no variance [(1-128)]", + NO_STR + "Control load balancing variance\n" + "Metric variance multiplier\n") +{ + nb_cli_enqueue_change(vty, "./variance", NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_variance(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *variance = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " variance %s\n", variance); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/maximum-paths + */ +DEFPY( + eigrp_maximum_paths, + eigrp_maximum_paths_cmd, + "maximum-paths (1-32)$maximum_paths", + "Forward packets over multiple paths\n" + "Number of paths\n") +{ + nb_cli_enqueue_change(vty, "./maximum-paths", NB_OP_MODIFY, + maximum_paths_str); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_maximum_paths, + no_eigrp_maximum_paths_cmd, + "no maximum-paths [(1-32)]", + NO_STR + "Forward packets over multiple paths\n" + "Number of paths\n") +{ + nb_cli_enqueue_change(vty, "./maximum-paths", NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_maximum_paths(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *maximum_paths = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " maximum-paths %s\n", maximum_paths); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K1 + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K2 + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K3 + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K4 + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K5 + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K6 + */ +DEFPY( + eigrp_metric_weights, + eigrp_metric_weights_cmd, + "metric weights (0-255)$k1 (0-255)$k2 (0-255)$k3 (0-255)$k4 (0-255)$k5 [(0-255)$k6]", + "Modify metrics and parameters for advertisement\n" + "Modify metric coefficients\n" + "K1\n" + "K2\n" + "K3\n" + "K4\n" + "K5\n" + "K6\n") +{ + nb_cli_enqueue_change(vty, "./metric-weights/K1", NB_OP_MODIFY, k1_str); + nb_cli_enqueue_change(vty, "./metric-weights/K2", NB_OP_MODIFY, k2_str); + nb_cli_enqueue_change(vty, "./metric-weights/K3", NB_OP_MODIFY, k3_str); + nb_cli_enqueue_change(vty, "./metric-weights/K4", NB_OP_MODIFY, k4_str); + nb_cli_enqueue_change(vty, "./metric-weights/K5", NB_OP_MODIFY, k5_str); + if (k6) + nb_cli_enqueue_change(vty, "./metric-weights/K6", + NB_OP_MODIFY, k6_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_metric_weights, + no_eigrp_metric_weights_cmd, + "no metric weights [(0-255) (0-255) (0-255) (0-255) (0-255) (0-255)]", + NO_STR + "Modify metrics and parameters for advertisement\n" + "Modify metric coefficients\n" + "K1\n" + "K2\n" + "K3\n" + "K4\n" + "K5\n" + "K6\n") +{ + nb_cli_enqueue_change(vty, "./metric-weights/K1", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./metric-weights/K2", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./metric-weights/K3", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./metric-weights/K4", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./metric-weights/K5", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./metric-weights/K6", NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_metrics(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *k1, *k2, *k3, *k4, *k5, *k6; + + k1 = yang_dnode_exists(dnode, "./K1") ? + yang_dnode_get_string(dnode, "./K1") : "0"; + k2 = yang_dnode_exists(dnode, "./K2") ? + yang_dnode_get_string(dnode, "./K2") : "0"; + k3 = yang_dnode_exists(dnode, "./K3") ? + yang_dnode_get_string(dnode, "./K3") : "0"; + k4 = yang_dnode_exists(dnode, "./K4") ? + yang_dnode_get_string(dnode, "./K4") : "0"; + k5 = yang_dnode_exists(dnode, "./K5") ? + yang_dnode_get_string(dnode, "./K5") : "0"; + k6 = yang_dnode_exists(dnode, "./K6") ? + yang_dnode_get_string(dnode, "./K6") : "0"; + + vty_out(vty, " metric weights %s %s %s %s %s", + k1, k2, k3, k4, k5); + if (k6) + vty_out(vty, " %s", k6); + vty_out(vty, "\n"); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/network + */ +DEFPY( + eigrp_network, + eigrp_network_cmd, + "[no] network A.B.C.D/M$prefix", + NO_STR + "Enable routing on an IP network\n" + "EIGRP network prefix\n") +{ + if (no) + nb_cli_enqueue_change(vty, "./network", NB_OP_DESTROY, + prefix_str); + else + nb_cli_enqueue_change(vty, "./network", NB_OP_CREATE, + prefix_str); + + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_network(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *prefix = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " network %s\n", prefix); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/neighbor + */ +DEFPY( + eigrp_neighbor, + eigrp_neighbor_cmd, + "[no] neighbor A.B.C.D$addr", + NO_STR + "Specify a neighbor router\n" + "Neighbor address\n") +{ + if (no) + nb_cli_enqueue_change(vty, "./neighbor", NB_OP_DESTROY, + addr_str); + else + nb_cli_enqueue_change(vty, "./neighbor", NB_OP_CREATE, + addr_str); + + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_neighbor(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *prefix = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " neighbor %s\n", prefix); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/redistribute + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/route-map + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/bandwidth + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/delay + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/reliability + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/load + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/mtu + */ +DEFPY( + eigrp_redistribute_source_metric, + eigrp_redistribute_source_metric_cmd, + "[no] redistribute " FRR_REDIST_STR_EIGRPD + "$proto [metric (1-4294967295)$bw (0-4294967295)$delay (0-255)$rlbt (1-255)$load (1-65535)$mtu]", + NO_STR + REDIST_STR + FRR_REDIST_HELP_STR_EIGRPD + "Metric for redistributed routes\n" + "Bandwidth metric in Kbits per second\n" + "EIGRP delay metric, in 10 microsecond units\n" + "EIGRP reliability metric where 255 is 100% reliable2 ?\n" + "EIGRP Effective bandwidth metric (Loading) where 255 is 100% loaded\n" + "EIGRP MTU of the path\n") +{ + char xpath[XPATH_MAXLEN], xpath_metric[XPATH_MAXLEN + 64]; + + snprintf(xpath, sizeof(xpath), "./redistribute[protocol='%s']", proto); + + if (no) { + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); + } + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (bw == 0 || delay == 0 || rlbt == 0 || load == 0 || mtu == 0) + return nb_cli_apply_changes(vty, NULL); + + snprintf(xpath_metric, sizeof(xpath_metric), "%s/metrics/bandwidth", + xpath); + nb_cli_enqueue_change(vty, xpath_metric, NB_OP_MODIFY, bw_str); + snprintf(xpath_metric, sizeof(xpath_metric), "%s/metrics/delay", xpath); + nb_cli_enqueue_change(vty, xpath_metric, NB_OP_MODIFY, delay_str); + snprintf(xpath_metric, sizeof(xpath_metric), "%s/metrics/reliability", + xpath); + nb_cli_enqueue_change(vty, xpath_metric, NB_OP_MODIFY, rlbt_str); + snprintf(xpath_metric, sizeof(xpath_metric), "%s/metrics/load", xpath); + nb_cli_enqueue_change(vty, xpath_metric, NB_OP_MODIFY, load_str); + snprintf(xpath_metric, sizeof(xpath_metric), "%s/metrics/mtu", xpath); + nb_cli_enqueue_change(vty, xpath_metric, NB_OP_MODIFY, mtu_str); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_redistribute(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *proto = yang_dnode_get_string(dnode, "./protocol"); + const char *bw, *delay, *load, *mtu, *rlbt; + + bw = yang_dnode_exists(dnode, "./metrics/bandwidth") ? + yang_dnode_get_string(dnode, "./metrics/bandwidth") : NULL; + delay = yang_dnode_exists(dnode, "./metrics/delay") ? + yang_dnode_get_string(dnode, "./metrics/delay") : NULL; + rlbt = yang_dnode_exists(dnode, "./metrics/reliability") ? + yang_dnode_get_string(dnode, "./metrics/reliability") : NULL; + load = yang_dnode_exists(dnode, "./metrics/load") ? + yang_dnode_get_string(dnode, "./metrics/load") : NULL; + mtu = yang_dnode_exists(dnode, "./metrics/mtu") ? + yang_dnode_get_string(dnode, "./metrics/mtu") : NULL; + + vty_out(vty, " redistribute %s", proto); + if (bw || rlbt || delay || load || mtu) + vty_out(vty, " metric %s %s %s %s %s", bw, delay, rlbt, load, + mtu); + vty_out(vty, "\n"); +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/delay + */ +DEFPY( + eigrp_if_delay, + eigrp_if_delay_cmd, + "delay (1-16777215)$delay", + "Specify interface throughput delay\n" + "Throughput delay (tens of microseconds)\n") +{ + nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/delay", + NB_OP_MODIFY, delay_str); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_if_delay, + no_eigrp_if_delay_cmd, + "no delay [(1-16777215)]", + NO_STR + "Specify interface throughput delay\n" + "Throughput delay (tens of microseconds)\n") +{ + nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/delay", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_delay(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *delay = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " delay %s\n", delay); +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/bandwidth + */ +DEFPY( + eigrp_if_bandwidth, + eigrp_if_bandwidth_cmd, + "eigrp bandwidth (1-10000000)$bw", + EIGRP_STR + "Set bandwidth informational parameter\n" + "Bandwidth in kilobits\n") +{ + nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/bandwidth", + NB_OP_MODIFY, bw_str); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_if_bandwidth, + no_eigrp_if_bandwidth_cmd, + "no eigrp bandwidth [(1-10000000)]", + NO_STR + EIGRP_STR + "Set bandwidth informational parameter\n" + "Bandwidth in kilobits\n") +{ + nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/bandwidth", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_bandwidth(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *bandwidth = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " eigrp bandwidth %s\n", bandwidth); +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/hello-interval + */ +DEFPY( + eigrp_if_ip_hellointerval, + eigrp_if_ip_hellointerval_cmd, + "ip hello-interval eigrp (1-65535)$hello", + "Interface Internet Protocol config commands\n" + "Configures EIGRP hello interval\n" + EIGRP_STR + "Seconds between hello transmissions\n") +{ + nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/hello-interval", + NB_OP_MODIFY, hello_str); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_if_ip_hellointerval, + no_eigrp_if_ip_hellointerval_cmd, + "no ip hello-interval eigrp [(1-65535)]", + NO_STR + "Interface Internet Protocol config commands\n" + "Configures EIGRP hello interval\n" + EIGRP_STR + "Seconds between hello transmissions\n") +{ + nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/hello-interval", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + + +void eigrp_cli_show_hello_interval(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *hello = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " ip hello-interval eigrp %s\n", hello); +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/hold-time + */ +DEFPY( + eigrp_if_ip_holdinterval, + eigrp_if_ip_holdinterval_cmd, + "ip hold-time eigrp (1-65535)$hold", + "Interface Internet Protocol config commands\n" + "Configures EIGRP IPv4 hold time\n" + EIGRP_STR + "Seconds before neighbor is considered down\n") +{ + nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/hold-time", + NB_OP_MODIFY, hold_str); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_if_ip_holdinterval, + no_eigrp_if_ip_holdinterval_cmd, + "no ip hold-time eigrp [(1-65535)]", + NO_STR + "Interface Internet Protocol config commands\n" + "Configures EIGRP IPv4 hold time\n" + EIGRP_STR + "Seconds before neighbor is considered down\n") +{ + nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/hold-time", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_hold_time(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *holdtime = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " ip hold-time eigrp %s\n", holdtime); +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/split-horizon + */ +/* NOT implemented. */ + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/summarize-addresses + */ +DEFPY( + eigrp_ip_summary_address, + eigrp_ip_summary_address_cmd, + "ip summary-address eigrp (1-65535)$as A.B.C.D/M$prefix", + "Interface Internet Protocol config commands\n" + "Perform address summarization\n" + EIGRP_STR + AS_STR + "Summary <network>/<length>, e.g. 192.168.0.0/16\n") +{ + char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64]; + + snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']", + as_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-address", xpath); + nb_cli_enqueue_change(vty, xpath_auth, NB_OP_CREATE, prefix_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_ip_summary_address, + no_eigrp_ip_summary_address_cmd, + "no ip summary-address eigrp (1-65535)$as A.B.C.D/M$prefix", + NO_STR + "Interface Internet Protocol config commands\n" + "Perform address summarization\n" + EIGRP_STR + AS_STR + "Summary <network>/<length>, e.g. 192.168.0.0/16\n") +{ + char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64]; + + snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']", + as_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-address", xpath); + nb_cli_enqueue_change(vty, xpath_auth, NB_OP_DESTROY, prefix_str); + + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_summarize_address(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL, + true); + const char *summarize_address = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " ip summary-address eigrp %d %s\n", + eif->eigrp->AS, summarize_address); +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/authentication + */ +DEFPY( + eigrp_authentication_mode, + eigrp_authentication_mode_cmd, + "ip authentication mode eigrp (1-65535)$as <md5|hmac-sha-256>$crypt", + "Interface Internet Protocol config commands\n" + "Authentication subcommands\n" + "Mode\n" + EIGRP_STR + AS_STR + "Keyed message digest\n" + "HMAC SHA256 algorithm \n") +{ + char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64]; + + snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']", + as_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_auth, sizeof(xpath_auth), "%s/authentication", xpath); + nb_cli_enqueue_change(vty, xpath_auth, NB_OP_MODIFY, crypt); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_authentication_mode, + no_eigrp_authentication_mode_cmd, + "no ip authentication mode eigrp (1-65535)$as [<md5|hmac-sha-256>]", + NO_STR + "Interface Internet Protocol config commands\n" + "Authentication subcommands\n" + "Mode\n" + EIGRP_STR + AS_STR + "Keyed message digest\n" + "HMAC SHA256 algorithm \n") +{ + char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64]; + + snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']", + as_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_auth, sizeof(xpath_auth), "%s/authentication", xpath); + nb_cli_enqueue_change(vty, xpath_auth, NB_OP_MODIFY, "none"); + + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_authentication(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL, + true); + const char *crypt = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " ip authentication mode eigrp %d %s\n", + eif->eigrp->AS, crypt); +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/keychain + */ +DEFPY( + eigrp_authentication_keychain, + eigrp_authentication_keychain_cmd, + "ip authentication key-chain eigrp (1-65535)$as WORD$name", + "Interface Internet Protocol config commands\n" + "Authentication subcommands\n" + "Key-chain\n" + EIGRP_STR + AS_STR + "Name of key-chain\n") +{ + char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64]; + + snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']", + as_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_auth, sizeof(xpath_auth), "%s/keychain", xpath); + nb_cli_enqueue_change(vty, xpath_auth, NB_OP_MODIFY, name); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_authentication_keychain, + no_eigrp_authentication_keychain_cmd, + "no ip authentication key-chain eigrp (1-65535)$as [WORD]", + NO_STR + "Interface Internet Protocol config commands\n" + "Authentication subcommands\n" + "Key-chain\n" + EIGRP_STR + AS_STR + "Name of key-chain\n") +{ + char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64]; + + snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']", + as_str); + snprintf(xpath_auth, sizeof(xpath_auth), "%s/keychain", xpath); + nb_cli_enqueue_change(vty, xpath_auth, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL, + true); + const char *keychain = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " ip authentication key-chain eigrp %d %s\n", + eif->eigrp->AS, keychain); +} + + +/* + * CLI installation procedures. + */ +static struct cmd_node eigrp_node = {EIGRP_NODE, "%s(config-router)# ", 1}; + +static int eigrp_config_write(struct vty *vty) +{ + struct lyd_node *dnode; + int written = 0; + + dnode = yang_dnode_get(running_config->dnode, "/frr-eigrpd:eigrpd"); + if (dnode) { + nb_cli_show_dnode_cmds(vty, dnode, false); + written = 1; + } + + return written; +} + +static struct cmd_node eigrp_interface_node = {INTERFACE_NODE, + "%s(config-if)# ", 1}; + + +static int eigrp_write_interface(struct vty *vty) +{ + struct lyd_node *dnode; + struct interface *ifp; + struct vrf *vrf; + int written = 0; + + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) { + FOR_ALL_INTERFACES(vrf, ifp) { + dnode = yang_dnode_get( + running_config->dnode, + "/frr-interface:lib/interface[name='%s'][vrf='%s']", + ifp->name, vrf->name); + if (dnode == NULL) + continue; + + written = 1; + nb_cli_show_dnode_cmds(vty, dnode, false); + } + } + + return written; +} + +void +eigrp_cli_init(void) +{ + install_element(CONFIG_NODE, &router_eigrp_cmd); + install_element(CONFIG_NODE, &no_router_eigrp_cmd); + + install_node(&eigrp_node, eigrp_config_write); + install_default(EIGRP_NODE); + + install_element(EIGRP_NODE, &eigrp_router_id_cmd); + install_element(EIGRP_NODE, &no_eigrp_router_id_cmd); + install_element(EIGRP_NODE, &eigrp_passive_interface_cmd); + install_element(EIGRP_NODE, &eigrp_timers_active_cmd); + install_element(EIGRP_NODE, &no_eigrp_timers_active_cmd); + install_element(EIGRP_NODE, &eigrp_variance_cmd); + install_element(EIGRP_NODE, &no_eigrp_variance_cmd); + install_element(EIGRP_NODE, &eigrp_maximum_paths_cmd); + install_element(EIGRP_NODE, &no_eigrp_maximum_paths_cmd); + install_element(EIGRP_NODE, &eigrp_metric_weights_cmd); + install_element(EIGRP_NODE, &no_eigrp_metric_weights_cmd); + install_element(EIGRP_NODE, &eigrp_network_cmd); + install_element(EIGRP_NODE, &eigrp_neighbor_cmd); + install_element(EIGRP_NODE, &eigrp_redistribute_source_metric_cmd); + + install_node(&eigrp_interface_node, eigrp_write_interface); + if_cmd_init(); + + install_element(INTERFACE_NODE, &eigrp_if_delay_cmd); + install_element(INTERFACE_NODE, &no_eigrp_if_delay_cmd); + install_element(INTERFACE_NODE, &eigrp_if_bandwidth_cmd); + install_element(INTERFACE_NODE, &no_eigrp_if_bandwidth_cmd); + install_element(INTERFACE_NODE, &eigrp_if_ip_hellointerval_cmd); + install_element(INTERFACE_NODE, &no_eigrp_if_ip_hellointerval_cmd); + install_element(INTERFACE_NODE, &eigrp_if_ip_holdinterval_cmd); + install_element(INTERFACE_NODE, &no_eigrp_if_ip_holdinterval_cmd); + install_element(INTERFACE_NODE, &eigrp_ip_summary_address_cmd); + install_element(INTERFACE_NODE, &no_eigrp_ip_summary_address_cmd); + install_element(INTERFACE_NODE, &eigrp_authentication_mode_cmd); + install_element(INTERFACE_NODE, &no_eigrp_authentication_mode_cmd); + install_element(INTERFACE_NODE, &eigrp_authentication_keychain_cmd); + install_element(INTERFACE_NODE, &no_eigrp_authentication_keychain_cmd); +} diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c index 3db59a838b..1781a88173 100644 --- a/eigrpd/eigrp_main.c +++ b/eigrpd/eigrp_main.c @@ -90,10 +90,16 @@ struct option longopts[] = {{0}}; /* Master of threads. */ struct thread_master *master; +/* Forward declaration of daemon info structure. */ +static struct frr_daemon_info eigrpd_di; + /* SIGHUP handler. */ static void sighup(void) { zlog_info("SIGHUP received"); + + /* Reload config file. */ + vty_read_config(NULL, eigrpd_di.config_file, config_default); } /* SIGINT / SIGTERM handler. */ @@ -131,6 +137,7 @@ struct quagga_signal_t eigrp_signals[] = { }; static const struct frr_yang_module_info *eigrpd_yang_modules[] = { + &frr_eigrpd_info, &frr_interface_info, }; @@ -187,7 +194,7 @@ int main(int argc, char **argv, char **envp) eigrp_vty_init(); keychain_init(); eigrp_vty_show_init(); - eigrp_vty_if_init(); + eigrp_cli_init(); #ifdef HAVE_SNMP eigrp_snmp_init(); diff --git a/eigrpd/eigrp_northbound.c b/eigrpd/eigrp_northbound.c new file mode 100644 index 0000000000..5f0c91809e --- /dev/null +++ b/eigrpd/eigrp_northbound.c @@ -0,0 +1,1584 @@ +/* + * EIGRP daemon northbound implementation. + * + * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF") + * Rafael Zalamena + * + * 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; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + */ + +#include <zebra.h> + +#include "lib/keychain.h" +#include "lib/log.h" +#include "lib/northbound.h" +#include "lib/table.h" +#include "lib/vrf.h" +#include "lib/zclient.h" + +#include "eigrp_structs.h" +#include "eigrpd.h" +#include "eigrp_interface.h" +#include "eigrp_network.h" +#include "eigrp_zebra.h" + +/* Helper functions. */ +static void redistribute_get_metrics(const struct lyd_node *dnode, + struct eigrp_metrics *em) +{ + memset(em, 0, sizeof(*em)); + + if (yang_dnode_exists(dnode, "./bandwidth")) + em->bandwidth = yang_dnode_get_uint32(dnode, "./bandwidth"); + if (yang_dnode_exists(dnode, "./delay")) + em->delay = yang_dnode_get_uint32(dnode, "./delay"); +#if 0 /* TODO: How does MTU work? */ + if (yang_dnode_exists(dnode, "./mtu")) + em->mtu[0] = yang_dnode_get_uint32(dnode, "./mtu"); +#endif + if (yang_dnode_exists(dnode, "./load")) + em->load = yang_dnode_get_uint32(dnode, "./load"); + if (yang_dnode_exists(dnode, "./reliability")) + em->reliability = yang_dnode_get_uint32(dnode, "./reliability"); +} + +static struct eigrp_interface *eigrp_interface_lookup(const struct eigrp *eigrp, + const char *ifname) +{ + struct eigrp_interface *eif; + struct listnode *ln; + + for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, ln, eif)) { + if (strcmp(ifname, eif->ifp->name)) + continue; + + return eif; + } + + return NULL; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance + */ +static int eigrpd_instance_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + /* NOTHING */ + break; + case NB_EV_PREPARE: + eigrp = eigrp_get(yang_dnode_get_string(dnode, "./asn")); + resource->ptr = eigrp; + break; + case NB_EV_ABORT: + eigrp_finish_final(resource->ptr); + break; + case NB_EV_APPLY: + nb_running_set_entry(dnode, resource->ptr); + break; + } + + return NB_OK; +} + +static int eigrpd_instance_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_unset_entry(dnode); + eigrp_finish_final(eigrp); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/router-id + */ +static int eigrpd_instance_router_id_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + yang_dnode_get_ipv4(&eigrp->router_id_static, dnode, NULL); + break; + } + + return NB_OK; +} + +static int eigrpd_instance_router_id_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->router_id_static.s_addr = 0; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/passive-interface + */ +static int +eigrpd_instance_passive_interface_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp_interface *eif; + struct eigrp *eigrp; + const char *ifname; + + switch (event) { + case NB_EV_VALIDATE: + eigrp = nb_running_get_entry(dnode, NULL, false); + if (eigrp == NULL) { + /* + * XXX: we can't verify if the interface exists + * and is active until EIGRP is up. + */ + break; + } + + ifname = yang_dnode_get_string(dnode, NULL); + eif = eigrp_interface_lookup(eigrp, ifname); + if (eif == NULL) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + ifname = yang_dnode_get_string(dnode, NULL); + eif = eigrp_interface_lookup(eigrp, ifname); + if (eif == NULL) + return NB_ERR_INCONSISTENCY; + + eif->params.passive_interface = EIGRP_IF_PASSIVE; + break; + } + + return NB_OK; +} + +static int +eigrpd_instance_passive_interface_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp_interface *eif; + struct eigrp *eigrp; + const char *ifname; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + ifname = yang_dnode_get_string(dnode, NULL); + eif = eigrp_interface_lookup(eigrp, ifname); + if (eif == NULL) + break; + + eif->params.passive_interface = EIGRP_IF_ACTIVE; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/active-time + */ +static int eigrpd_instance_active_time_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + /* TODO: Not implemented. */ + return NB_ERR_INCONSISTENCY; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/variance + */ +static int eigrpd_instance_variance_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->variance = yang_dnode_get_uint8(dnode, NULL); + break; + } + + return NB_OK; +} + +static int eigrpd_instance_variance_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->variance = EIGRP_VARIANCE_DEFAULT; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/maximum-paths + */ +static int eigrpd_instance_maximum_paths_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->max_paths = yang_dnode_get_uint8(dnode, NULL); + break; + } + + return NB_OK; +} + +static int eigrpd_instance_maximum_paths_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->max_paths = EIGRP_MAX_PATHS_DEFAULT; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K1 + */ +static int +eigrpd_instance_metric_weights_K1_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[0] = yang_dnode_get_uint8(dnode, NULL); + break; + } + + return NB_OK; +} + +static int +eigrpd_instance_metric_weights_K1_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[0] = EIGRP_K1_DEFAULT; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K2 + */ +static int +eigrpd_instance_metric_weights_K2_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[1] = yang_dnode_get_uint8(dnode, NULL); + break; + } + + return NB_OK; +} + +static int +eigrpd_instance_metric_weights_K2_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[1] = EIGRP_K2_DEFAULT; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K3 + */ +static int +eigrpd_instance_metric_weights_K3_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[2] = yang_dnode_get_uint8(dnode, NULL); + break; + } + + return NB_OK; +} + +static int +eigrpd_instance_metric_weights_K3_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[2] = EIGRP_K3_DEFAULT; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K4 + */ +static int +eigrpd_instance_metric_weights_K4_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[3] = yang_dnode_get_uint8(dnode, NULL); + break; + } + + return NB_OK; +} + +static int +eigrpd_instance_metric_weights_K4_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[3] = EIGRP_K4_DEFAULT; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K5 + */ +static int +eigrpd_instance_metric_weights_K5_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[4] = yang_dnode_get_uint8(dnode, NULL); + break; + } + + return NB_OK; +} + +static int +eigrpd_instance_metric_weights_K5_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[4] = EIGRP_K5_DEFAULT; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K6 + */ +static int +eigrpd_instance_metric_weights_K6_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[5] = yang_dnode_get_uint8(dnode, NULL); + break; + } + + return NB_OK; +} + +static int +eigrpd_instance_metric_weights_K6_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[5] = EIGRP_K6_DEFAULT; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/network + */ +static int eigrpd_instance_network_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct route_node *rnode; + struct prefix prefix; + struct eigrp *eigrp; + int exists; + + yang_dnode_get_ipv4p(&prefix, dnode, NULL); + + switch (event) { + case NB_EV_VALIDATE: + eigrp = nb_running_get_entry(dnode, NULL, false); + /* If entry doesn't exist it means the list is empty. */ + if (eigrp == NULL) + break; + + rnode = route_node_get(eigrp->networks, &prefix); + exists = (rnode->info != NULL); + route_unlock_node(rnode); + if (exists) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + if (eigrp_network_set(eigrp, &prefix) == 0) + return NB_ERR_INCONSISTENCY; + break; + } + + return NB_OK; +} + +static int eigrpd_instance_network_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct route_node *rnode; + struct prefix prefix; + struct eigrp *eigrp; + int exists = 0; + + yang_dnode_get_ipv4p(&prefix, dnode, NULL); + + switch (event) { + case NB_EV_VALIDATE: + eigrp = nb_running_get_entry(dnode, NULL, false); + /* If entry doesn't exist it means the list is empty. */ + if (eigrp == NULL) + break; + + rnode = route_node_get(eigrp->networks, &prefix); + exists = (rnode->info != NULL); + route_unlock_node(rnode); + if (exists == 0) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp_network_unset(eigrp, &prefix); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/neighbor + */ +static int eigrpd_instance_neighbor_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + /* TODO: Not implemented. */ + return NB_ERR_INCONSISTENCY; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + return NB_OK; +} + +static int eigrpd_instance_neighbor_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + /* TODO: Not implemented. */ + return NB_ERR_INCONSISTENCY; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/redistribute + */ +static int eigrpd_instance_redistribute_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp_metrics metrics; + struct eigrp *eigrp; + uint32_t proto; + + switch (event) { + case NB_EV_VALIDATE: + proto = yang_dnode_get_enum(dnode, "./protocol"); + if (vrf_bitmap_check(zclient->redist[AFI_IP][proto], + VRF_DEFAULT)) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + proto = yang_dnode_get_enum(dnode, "./protocol"); + redistribute_get_metrics(dnode, &metrics); + eigrp_redistribute_set(eigrp, proto, metrics); + break; + } + + return NB_OK; +} + +static int eigrpd_instance_redistribute_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + uint32_t proto; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + proto = yang_dnode_get_enum(dnode, "./protocol"); + eigrp_redistribute_unset(eigrp, proto); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/route-map + */ +static int +eigrpd_instance_redistribute_route_map_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + /* TODO: Not implemented. */ + return NB_ERR_INCONSISTENCY; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + return NB_OK; +} + +static int +eigrpd_instance_redistribute_route_map_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + /* TODO: Not implemented. */ + return NB_ERR_INCONSISTENCY; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/bandwidth + */ +static int eigrpd_instance_redistribute_metrics_bandwidth_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp_metrics metrics; + struct eigrp *eigrp; + uint32_t proto; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + proto = yang_dnode_get_enum(dnode, "../../protocol"); + redistribute_get_metrics(dnode, &metrics); + eigrp_redistribute_set(eigrp, proto, metrics); + break; + } + + return NB_OK; +} + +static int eigrpd_instance_redistribute_metrics_bandwidth_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + struct eigrp_metrics metrics; + struct eigrp *eigrp; + uint32_t proto; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + proto = yang_dnode_get_enum(dnode, "../../protocol"); + redistribute_get_metrics(dnode, &metrics); + eigrp_redistribute_set(eigrp, proto, metrics); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/delay + */ +static int +eigrpd_instance_redistribute_metrics_delay_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + return eigrpd_instance_redistribute_metrics_bandwidth_modify(event, + dnode, + resource); +} + +static int +eigrpd_instance_redistribute_metrics_delay_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + return eigrpd_instance_redistribute_metrics_bandwidth_destroy(event, + dnode); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/reliability + */ +static int eigrpd_instance_redistribute_metrics_reliability_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + return eigrpd_instance_redistribute_metrics_bandwidth_modify(event, + dnode, + resource); +} + +static int eigrpd_instance_redistribute_metrics_reliability_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return eigrpd_instance_redistribute_metrics_bandwidth_destroy(event, + dnode); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/load + */ +static int +eigrpd_instance_redistribute_metrics_load_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + return eigrpd_instance_redistribute_metrics_bandwidth_modify(event, + dnode, + resource); +} + +static int +eigrpd_instance_redistribute_metrics_load_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + return eigrpd_instance_redistribute_metrics_bandwidth_destroy(event, + dnode); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/mtu + */ +static int +eigrpd_instance_redistribute_metrics_mtu_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + return eigrpd_instance_redistribute_metrics_bandwidth_modify(event, + dnode, + resource); +} + +static int +eigrpd_instance_redistribute_metrics_mtu_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + return eigrpd_instance_redistribute_metrics_bandwidth_destroy(event, + dnode); +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/delay + */ +static int lib_interface_eigrp_delay_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp_interface *ei; + struct interface *ifp; + + switch (event) { + case NB_EV_VALIDATE: + ifp = nb_running_get_entry(dnode, NULL, false); + if (ifp == NULL) { + /* + * XXX: we can't verify if the interface exists + * and is active until EIGRP is up. + */ + break; + } + + ei = ifp->info; + if (ei == NULL) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(dnode, NULL, true); + ei = ifp->info; + if (ei == NULL) + return NB_ERR_INCONSISTENCY; + + ei->params.delay = yang_dnode_get_uint32(dnode, NULL); + eigrp_if_reset(ifp); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/bandwidth + */ +static int lib_interface_eigrp_bandwidth_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct interface *ifp; + struct eigrp_interface *ei; + + switch (event) { + case NB_EV_VALIDATE: + ifp = nb_running_get_entry(dnode, NULL, false); + if (ifp == NULL) { + /* + * XXX: we can't verify if the interface exists + * and is active until EIGRP is up. + */ + break; + } + + ei = ifp->info; + if (ei == NULL) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(dnode, NULL, true); + ei = ifp->info; + if (ei == NULL) + return NB_ERR_INCONSISTENCY; + + ei->params.bandwidth = yang_dnode_get_uint32(dnode, NULL); + eigrp_if_reset(ifp); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/hello-interval + */ +static int +lib_interface_eigrp_hello_interval_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct interface *ifp; + struct eigrp_interface *ei; + + switch (event) { + case NB_EV_VALIDATE: + ifp = nb_running_get_entry(dnode, NULL, false); + if (ifp == NULL) { + /* + * XXX: we can't verify if the interface exists + * and is active until EIGRP is up. + */ + break; + } + + ei = ifp->info; + if (ei == NULL) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(dnode, NULL, true); + ei = ifp->info; + if (ei == NULL) + return NB_ERR_INCONSISTENCY; + + ei->params.v_hello = yang_dnode_get_uint16(dnode, NULL); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/hold-time + */ +static int lib_interface_eigrp_hold_time_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct interface *ifp; + struct eigrp_interface *ei; + + switch (event) { + case NB_EV_VALIDATE: + ifp = nb_running_get_entry(dnode, NULL, false); + if (ifp == NULL) { + /* + * XXX: we can't verify if the interface exists + * and is active until EIGRP is up. + */ + break; + } + + ei = ifp->info; + if (ei == NULL) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(dnode, NULL, true); + ei = ifp->info; + if (ei == NULL) + return NB_ERR_INCONSISTENCY; + + ei->params.v_wait = yang_dnode_get_uint16(dnode, NULL); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/split-horizon + */ +static int +lib_interface_eigrp_split_horizon_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + /* TODO: Not implemented. */ + return NB_ERR_INCONSISTENCY; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance + */ +static int lib_interface_eigrp_instance_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp_interface *eif; + struct interface *ifp; + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + ifp = nb_running_get_entry(dnode, NULL, false); + if (ifp == NULL) { + /* + * XXX: we can't verify if the interface exists + * and is active until EIGRP is up. + */ + break; + } + + eigrp = eigrp_get(yang_dnode_get_string(dnode, "./asn")); + eif = eigrp_interface_lookup(eigrp, ifp->name); + if (eif == NULL) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(dnode, NULL, true); + eigrp = eigrp_get(yang_dnode_get_string(dnode, "./asn")); + eif = eigrp_interface_lookup(eigrp, ifp->name); + if (eif == NULL) + return NB_ERR_INCONSISTENCY; + + nb_running_set_entry(dnode, eif); + break; + } + + return NB_OK; +} + +static int lib_interface_eigrp_instance_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + nb_running_unset_entry(dnode); + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/summarize-addresses + */ +static int lib_interface_eigrp_instance_summarize_addresses_create( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + /* TODO: Not implemented. */ + return NB_ERR_INCONSISTENCY; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + return NB_OK; +} + +static int lib_interface_eigrp_instance_summarize_addresses_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + /* TODO: Not implemented. */ + return NB_ERR_INCONSISTENCY; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/authentication + */ +static int +lib_interface_eigrp_instance_authentication_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp_interface *eif; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eif = nb_running_get_entry(dnode, NULL, true); + eif->params.auth_type = yang_dnode_get_enum(dnode, NULL); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/keychain + */ +static int +lib_interface_eigrp_instance_keychain_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp_interface *eif; + struct keychain *keychain; + + switch (event) { + case NB_EV_VALIDATE: + keychain = keychain_lookup(yang_dnode_get_string(dnode, NULL)); + if (keychain == NULL) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + resource->ptr = strdup(yang_dnode_get_string(dnode, NULL)); + if (resource->ptr == NULL) + return NB_ERR_RESOURCE; + break; + case NB_EV_ABORT: + free(resource->ptr); + resource->ptr = NULL; + break; + case NB_EV_APPLY: + eif = nb_running_get_entry(dnode, NULL, true); + if (eif->params.auth_keychain) + free(eif->params.auth_keychain); + + eif->params.auth_keychain = resource->ptr; + break; + } + + return NB_OK; +} + +static int +lib_interface_eigrp_instance_keychain_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp_interface *eif; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eif = nb_running_get_entry(dnode, NULL, true); + if (eif->params.auth_keychain) + free(eif->params.auth_keychain); + + eif->params.auth_keychain = NULL; + break; + } + + return NB_OK; +} + +/* clang-format off */ +const struct frr_yang_module_info frr_eigrpd_info = { + .name = "frr-eigrpd", + .nodes = { + { + .xpath = "/frr-eigrpd:eigrpd/instance", + .cbs = { + .create = eigrpd_instance_create, + .destroy = eigrpd_instance_destroy, + .cli_show = eigrp_cli_show_header, + .cli_show_end = eigrp_cli_show_end_header, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/router-id", + .cbs = { + .modify = eigrpd_instance_router_id_modify, + .destroy = eigrpd_instance_router_id_destroy, + .cli_show = eigrp_cli_show_router_id, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/passive-interface", + .cbs = { + .create = eigrpd_instance_passive_interface_create, + .destroy = eigrpd_instance_passive_interface_destroy, + .cli_show = eigrp_cli_show_passive_interface, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/active-time", + .cbs = { + .modify = eigrpd_instance_active_time_modify, + .cli_show = eigrp_cli_show_active_time, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/variance", + .cbs = { + .modify = eigrpd_instance_variance_modify, + .destroy = eigrpd_instance_variance_destroy, + .cli_show = eigrp_cli_show_variance, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/maximum-paths", + .cbs = { + .modify = eigrpd_instance_maximum_paths_modify, + .destroy = eigrpd_instance_maximum_paths_destroy, + .cli_show = eigrp_cli_show_maximum_paths, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights", + .cbs = { + .cli_show = eigrp_cli_show_metrics, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K1", + .cbs = { + .modify = eigrpd_instance_metric_weights_K1_modify, + .destroy = eigrpd_instance_metric_weights_K1_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K2", + .cbs = { + .modify = eigrpd_instance_metric_weights_K2_modify, + .destroy = eigrpd_instance_metric_weights_K2_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K3", + .cbs = { + .modify = eigrpd_instance_metric_weights_K3_modify, + .destroy = eigrpd_instance_metric_weights_K3_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K4", + .cbs = { + .modify = eigrpd_instance_metric_weights_K4_modify, + .destroy = eigrpd_instance_metric_weights_K4_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K5", + .cbs = { + .modify = eigrpd_instance_metric_weights_K5_modify, + .destroy = eigrpd_instance_metric_weights_K5_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K6", + .cbs = { + .modify = eigrpd_instance_metric_weights_K6_modify, + .destroy = eigrpd_instance_metric_weights_K6_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/network", + .cbs = { + .create = eigrpd_instance_network_create, + .destroy = eigrpd_instance_network_destroy, + .cli_show = eigrp_cli_show_network, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/neighbor", + .cbs = { + .create = eigrpd_instance_neighbor_create, + .destroy = eigrpd_instance_neighbor_destroy, + .cli_show = eigrp_cli_show_neighbor, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/redistribute", + .cbs = { + .create = eigrpd_instance_redistribute_create, + .destroy = eigrpd_instance_redistribute_destroy, + .cli_show = eigrp_cli_show_redistribute, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/route-map", + .cbs = { + .modify = eigrpd_instance_redistribute_route_map_modify, + .destroy = eigrpd_instance_redistribute_route_map_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/metrics/bandwidth", + .cbs = { + .modify = eigrpd_instance_redistribute_metrics_bandwidth_modify, + .destroy = eigrpd_instance_redistribute_metrics_bandwidth_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/metrics/delay", + .cbs = { + .modify = eigrpd_instance_redistribute_metrics_delay_modify, + .destroy = eigrpd_instance_redistribute_metrics_delay_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/metrics/reliability", + .cbs = { + .modify = eigrpd_instance_redistribute_metrics_reliability_modify, + .destroy = eigrpd_instance_redistribute_metrics_reliability_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/metrics/load", + .cbs = { + .modify = eigrpd_instance_redistribute_metrics_load_modify, + .destroy = eigrpd_instance_redistribute_metrics_load_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/metrics/mtu", + .cbs = { + .modify = eigrpd_instance_redistribute_metrics_mtu_modify, + .destroy = eigrpd_instance_redistribute_metrics_mtu_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/delay", + .cbs = { + .modify = lib_interface_eigrp_delay_modify, + .cli_show = eigrp_cli_show_delay, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/bandwidth", + .cbs = { + .modify = lib_interface_eigrp_bandwidth_modify, + .cli_show = eigrp_cli_show_bandwidth, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/hello-interval", + .cbs = { + .modify = lib_interface_eigrp_hello_interval_modify, + .cli_show = eigrp_cli_show_hello_interval, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/hold-time", + .cbs = { + .modify = lib_interface_eigrp_hold_time_modify, + .cli_show = eigrp_cli_show_hold_time, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/split-horizon", + .cbs = { + .modify = lib_interface_eigrp_split_horizon_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/instance", + .cbs = { + .create = lib_interface_eigrp_instance_create, + .destroy = lib_interface_eigrp_instance_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/instance/summarize-addresses", + .cbs = { + .create = lib_interface_eigrp_instance_summarize_addresses_create, + .destroy = lib_interface_eigrp_instance_summarize_addresses_destroy, + .cli_show = eigrp_cli_show_summarize_address, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/instance/authentication", + .cbs = { + .modify = lib_interface_eigrp_instance_authentication_modify, + .cli_show = eigrp_cli_show_authentication, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/instance/keychain", + .cbs = { + .modify = lib_interface_eigrp_instance_keychain_modify, + .destroy = lib_interface_eigrp_instance_keychain_destroy, + .cli_show = eigrp_cli_show_keychain, + } + }, + { + .xpath = NULL, + }, + } +}; diff --git a/eigrpd/eigrp_routemap.c b/eigrpd/eigrp_routemap.c index f080ba4876..bac7494774 100644 --- a/eigrpd/eigrp_routemap.c +++ b/eigrpd/eigrp_routemap.c @@ -251,9 +251,9 @@ void eigrp_route_map_update(const char *notused) /* `match metric METRIC' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_metric(void *rule, struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_metric(void *rule, struct prefix *prefix, route_map_object_t type, + void *object) { // uint32_t *metric; // uint32_t check; @@ -311,10 +311,9 @@ struct route_map_rule_cmd route_match_metric_cmd = { /* `match interface IFNAME' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_interface(void *rule, - struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_interface(void *rule, struct prefix *prefix, + route_map_object_t type, void *object) { // struct rip_info *rinfo; // struct interface *ifp; @@ -360,10 +359,9 @@ struct route_map_rule_cmd route_match_interface_cmd = { /* `match ip next-hop IP_ACCESS_LIST' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_ip_next_hop(void *rule, - struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_ip_next_hop(void *rule, struct prefix *prefix, + route_map_object_t type, void *object) { // struct access_list *alist; // struct rip_info *rinfo; @@ -407,7 +405,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_cmd = { /* `match ip next-hop prefix-list PREFIX_LIST' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ip_next_hop_prefix_list(void *rule, struct prefix *prefix, route_map_object_t type, void *object) { @@ -452,10 +450,9 @@ static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = { /* Match function should return 1 if match is success else return zero. */ -static route_map_result_t route_match_ip_address(void *rule, - struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_ip_address(void *rule, struct prefix *prefix, + route_map_object_t type, void *object) { struct access_list *alist; @@ -491,7 +488,7 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = { /* `match ip address prefix-list PREFIX_LIST' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ip_address_prefix_list(void *rule, struct prefix *prefix, route_map_object_t type, void *object) { @@ -526,8 +523,9 @@ static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { /* `match tag TAG' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_tag(void *rule, struct prefix *prefix, - route_map_object_t type, void *object) +static enum route_map_cmd_result_t +route_match_tag(void *rule, struct prefix *prefix, route_map_object_t type, + void *object) { // unsigned short *tag; // struct rip_info *rinfo; @@ -568,9 +566,9 @@ struct route_map_rule_cmd route_match_tag_cmd = { "tag", route_match_tag, route_match_tag_compile, route_match_tag_free}; /* Set metric to attribute. */ -static route_map_result_t route_set_metric(void *rule, struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_metric(void *rule, struct prefix *prefix, + route_map_object_t type, void *object) { // if (type == RMAP_RIP) // { @@ -662,10 +660,9 @@ static struct route_map_rule_cmd route_set_metric_cmd = { /* `set ip next-hop IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ -static route_map_result_t route_set_ip_nexthop(void *rule, - struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_ip_nexthop(void *rule, struct prefix *prefix, + route_map_object_t type, void *object) { // struct in_addr *address; // struct rip_info *rinfo; @@ -718,8 +715,9 @@ static struct route_map_rule_cmd route_set_ip_nexthop_cmd = { /* `set tag TAG' */ /* Set tag to object. ojbect must be pointer to struct attr. */ -static route_map_result_t route_set_tag(void *rule, struct prefix *prefix, - route_map_object_t type, void *object) +static enum route_map_cmd_result_t +route_set_tag(void *rule, struct prefix *prefix, + route_map_object_t type, void *object) { // unsigned short *tag; // struct rip_info *rinfo; diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c index d51faaac59..207622e659 100644 --- a/eigrpd/eigrp_vty.c +++ b/eigrpd/eigrp_vty.c @@ -59,402 +59,6 @@ #include "eigrpd/eigrp_vty_clippy.c" #endif -static int config_write_network(struct vty *vty, struct eigrp *eigrp) -{ - struct route_node *rn; - int i; - - /* `network area' print. */ - for (rn = route_top(eigrp->networks); rn; rn = route_next(rn)) - if (rn->info) { - /* Network print. */ - vty_out(vty, " network %s/%d \n", - inet_ntoa(rn->p.u.prefix4), rn->p.prefixlen); - } - - if (eigrp->max_paths != EIGRP_MAX_PATHS_DEFAULT) - vty_out(vty, " maximum-paths %d\n", eigrp->max_paths); - - if (eigrp->variance != EIGRP_VARIANCE_DEFAULT) - vty_out(vty, " variance %d\n", eigrp->variance); - - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - if (i != zclient->redist_default - && vrf_bitmap_check(zclient->redist[AFI_IP][i], - VRF_DEFAULT)) - vty_out(vty, " redistribute %s\n", - zebra_route_string(i)); - - /*Separate EIGRP configuration from the rest of the config*/ - vty_out(vty, "!\n"); - - return 0; -} - -static int config_write_interfaces(struct vty *vty, struct eigrp *eigrp) -{ - struct eigrp_interface *ei; - struct listnode *node; - - for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) { - vty_frame(vty, "interface %s\n", ei->ifp->name); - - if (ei->params.auth_type == EIGRP_AUTH_TYPE_MD5) { - vty_out(vty, " ip authentication mode eigrp %d md5\n", - eigrp->AS); - } - - if (ei->params.auth_type == EIGRP_AUTH_TYPE_SHA256) { - vty_out(vty, - " ip authentication mode eigrp %d hmac-sha-256\n", - eigrp->AS); - } - - if (ei->params.auth_keychain) { - vty_out(vty, - " ip authentication key-chain eigrp %d %s\n", - eigrp->AS, ei->params.auth_keychain); - } - - if (ei->params.v_hello != EIGRP_HELLO_INTERVAL_DEFAULT) { - vty_out(vty, " ip hello-interval eigrp %d\n", - ei->params.v_hello); - } - - if (ei->params.v_wait != EIGRP_HOLD_INTERVAL_DEFAULT) { - vty_out(vty, " ip hold-time eigrp %d\n", - ei->params.v_wait); - } - - /*Separate this EIGRP interface configuration from the others*/ - vty_endframe(vty, "!\n"); - } - - return 0; -} - -static int eigrp_write_interface(struct vty *vty) -{ - struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); - struct interface *ifp; - struct eigrp_interface *ei; - - FOR_ALL_INTERFACES (vrf, ifp) { - ei = ifp->info; - if (!ei) - continue; - - vty_frame(vty, "interface %s\n", ifp->name); - - if (ifp->desc) - vty_out(vty, " description %s\n", ifp->desc); - - if (ei->params.bandwidth != EIGRP_BANDWIDTH_DEFAULT) - vty_out(vty, " bandwidth %u\n", ei->params.bandwidth); - if (ei->params.delay != EIGRP_DELAY_DEFAULT) - vty_out(vty, " delay %u\n", ei->params.delay); - if (ei->params.v_hello != EIGRP_HELLO_INTERVAL_DEFAULT) - vty_out(vty, " ip hello-interval eigrp %u\n", - ei->params.v_hello); - if (ei->params.v_wait != EIGRP_HOLD_INTERVAL_DEFAULT) - vty_out(vty, " ip hold-time eigrp %u\n", - ei->params.v_wait); - - vty_endframe(vty, "!\n"); - } - - return 0; -} - -/** - * Writes distribute lists to config - */ -static int config_write_eigrp_distribute(struct vty *vty, struct eigrp *eigrp) -{ - int write = 0; - - /* Distribute configuration. */ - write += config_write_distribute(vty, eigrp->distribute_ctx); - - return write; -} - -/** - * Writes 'router eigrp' section to config - */ -static int config_write_eigrp_router(struct vty *vty, struct eigrp *eigrp) -{ - int write = 0; - - /* `router eigrp' print. */ - vty_out(vty, "router eigrp %d\n", eigrp->AS); - - write++; - - /* Router ID print. */ - if (eigrp->router_id_static.s_addr != 0) { - vty_out(vty, " eigrp router-id %s\n", - inet_ntoa(eigrp->router_id_static)); - } - - /* Network area print. */ - config_write_network(vty, eigrp); - - /* Distribute-list and default-information print. */ - config_write_eigrp_distribute(vty, eigrp); - - /*Separate EIGRP configuration from the rest of the config*/ - vty_out(vty, "!\n"); - - return write; -} - -DEFUN_NOSH (router_eigrp, - router_eigrp_cmd, - "router eigrp (1-65535)", - "Enable a routing process\n" - "Start EIGRP configuration\n" - "AS Number to use\n") -{ - struct eigrp *eigrp = eigrp_get(argv[2]->arg); - VTY_PUSH_CONTEXT(EIGRP_NODE, eigrp); - - return CMD_SUCCESS; -} - -DEFUN (no_router_eigrp, - no_router_eigrp_cmd, - "no router eigrp (1-65535)", - NO_STR - "Routing process\n" - "EIGRP configuration\n" - "AS number to use\n") -{ - vty->node = CONFIG_NODE; - - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (eigrp->AS != atoi(argv[3]->arg)) { - vty_out(vty, "%% Attempting to deconfigure non-existent AS\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - eigrp_finish_final(eigrp); - - return CMD_SUCCESS; -} - -DEFPY (eigrp_router_id, - eigrp_router_id_cmd, - "eigrp router-id A.B.C.D$addr", - "EIGRP specific commands\n" - "Router ID for this EIGRP process\n" - "EIGRP Router-ID in IP address format\n") -{ - VTY_DECLVAR_CONTEXT(eigrp, eigrp); - - eigrp->router_id_static = addr; - - return CMD_SUCCESS; -} - -DEFPY (no_eigrp_router_id, - no_eigrp_router_id_cmd, - "no eigrp router-id [A.B.C.D$addr]", - NO_STR - "EIGRP specific commands\n" - "Router ID for this EIGRP process\n" - "EIGRP Router-ID in IP address format\n") -{ - VTY_DECLVAR_CONTEXT(eigrp, eigrp); - - eigrp->router_id_static.s_addr = 0; - - return CMD_SUCCESS; -} - -DEFUN (eigrp_passive_interface, - eigrp_passive_interface_cmd, - "passive-interface IFNAME", - "Suppress routing updates on an interface\n" - "Interface to suppress on\n") -{ - VTY_DECLVAR_CONTEXT(eigrp, eigrp); - struct eigrp_interface *ei; - struct listnode *node; - char *ifname = argv[1]->arg; - - for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) { - if (strcmp(ifname, ei->ifp->name) == 0) { - ei->params.passive_interface = EIGRP_IF_PASSIVE; - return CMD_SUCCESS; - } - } - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_passive_interface, - no_eigrp_passive_interface_cmd, - "no passive-interface IFNAME", - NO_STR - "Suppress routing updates on an interface\n" - "Interface to suppress on\n") -{ - VTY_DECLVAR_CONTEXT(eigrp, eigrp); - struct eigrp_interface *ei; - struct listnode *node; - char *ifname = argv[2]->arg; - - for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) { - if (strcmp(ifname, ei->ifp->name) == 0) { - ei->params.passive_interface = EIGRP_IF_ACTIVE; - return CMD_SUCCESS; - } - } - - return CMD_SUCCESS; -} - -DEFUN (eigrp_timers_active, - eigrp_timers_active_cmd, - "timers active-time <(1-65535)|disabled>", - "Adjust routing timers\n" - "Time limit for active state\n" - "Active state time limit in seconds\n" - "Disable time limit for active state\n") -{ - // struct eigrp *eigrp = vty->index; - /*TODO: */ - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_timers_active, - no_eigrp_timers_active_cmd, - "no timers active-time <(1-65535)|disabled>", - NO_STR - "Adjust routing timers\n" - "Time limit for active state\n" - "Active state time limit in seconds\n" - "Disable time limit for active state\n") -{ - // struct eigrp *eigrp = vty->index; - /*TODO: */ - - return CMD_SUCCESS; -} - - -DEFUN (eigrp_metric_weights, - eigrp_metric_weights_cmd, - "metric weights (0-255) (0-255) (0-255) (0-255) (0-255) ", - "Modify metrics and parameters for advertisement\n" - "Modify metric coefficients\n" - "K1\n" - "K2\n" - "K3\n" - "K4\n" - "K5\n") -{ - // struct eigrp *eigrp = vty->index; - /*TODO: */ - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_metric_weights, - no_eigrp_metric_weights_cmd, - "no metric weights (0-255) (0-255) (0-255) (0-255) (0-255)", - NO_STR - "Modify metrics and parameters for advertisement\n" - "Modify metric coefficients\n" - "K1\n" - "K2\n" - "K3\n" - "K4\n" - "K5\n") -{ - // struct eigrp *eigrp = vty->index; - /*TODO: */ - - return CMD_SUCCESS; -} - - -DEFUN (eigrp_network, - eigrp_network_cmd, - "network A.B.C.D/M", - "Enable routing on an IP network\n" - "EIGRP network prefix\n") -{ - VTY_DECLVAR_CONTEXT(eigrp, eigrp); - struct prefix p; - int ret; - - (void)str2prefix(argv[1]->arg, &p); - - ret = eigrp_network_set(eigrp, &p); - - if (ret == 0) { - vty_out(vty, "There is already same network statement.\n"); - return CMD_WARNING; - } - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_network, - no_eigrp_network_cmd, - "no network A.B.C.D/M", - NO_STR - "Disable routing on an IP network\n" - "EIGRP network prefix\n") -{ - VTY_DECLVAR_CONTEXT(eigrp, eigrp); - struct prefix p; - int ret; - - (void)str2prefix(argv[2]->arg, &p); - - ret = eigrp_network_unset(eigrp, &p); - - if (ret == 0) { - vty_out(vty, "Can't find specified network configuration.\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; -} - -DEFUN (eigrp_neighbor, - eigrp_neighbor_cmd, - "neighbor A.B.C.D", - "Specify a neighbor router\n" - "Neighbor address\n") -{ - // struct eigrp *eigrp = vty->index; - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_neighbor, - no_eigrp_neighbor_cmd, - "no neighbor A.B.C.D", - NO_STR - "Specify a neighbor router\n" - "Neighbor address\n") -{ - // struct eigrp *eigrp = vty->index; - - return CMD_SUCCESS; -} - static void eigrp_vty_display_prefix_entry(struct vty *vty, struct eigrp *eigrp, struct eigrp_prefix_entry *pe, @@ -650,585 +254,6 @@ DEFUN (show_ip_eigrp_neighbors, return CMD_SUCCESS; } -DEFUN (eigrp_if_delay, - eigrp_if_delay_cmd, - "delay (1-16777215)", - "Specify interface throughput delay\n" - "Throughput delay (tens of microseconds)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - uint32_t delay; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - delay = atoi(argv[1]->arg); - - ei->params.delay = delay; - eigrp_if_reset(ifp); - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_if_delay, - no_eigrp_if_delay_cmd, - "no delay (1-16777215)", - NO_STR - "Specify interface throughput delay\n" - "Throughput delay (tens of microseconds)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - - return CMD_SUCCESS; - } - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - ei->params.delay = EIGRP_DELAY_DEFAULT; - eigrp_if_reset(ifp); - - return CMD_SUCCESS; -} - -DEFPY (eigrp_if_bandwidth, - eigrp_if_bandwidth_cmd, - "eigrp bandwidth (1-10000000)$bw", - "EIGRP specific commands\n" - "Set bandwidth informational parameter\n" - "Bandwidth in kilobits\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - ei->params.bandwidth = bw; - eigrp_if_reset(ifp); - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_if_bandwidth, - no_eigrp_if_bandwidth_cmd, - "no eigrp bandwidth [(1-10000000)]", - NO_STR - "EIGRP specific commands\n" - "Set bandwidth informational parameter\n" - "Bandwidth in kilobits\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - ei->params.bandwidth = EIGRP_BANDWIDTH_DEFAULT; - eigrp_if_reset(ifp); - - return CMD_SUCCESS; -} - -DEFUN (eigrp_if_ip_hellointerval, - eigrp_if_ip_hellointerval_cmd, - "ip hello-interval eigrp (1-65535)", - "Interface Internet Protocol config commands\n" - "Configures EIGRP hello interval\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" - "Seconds between hello transmissions\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - uint32_t hello; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - hello = atoi(argv[3]->arg); - - ei->params.v_hello = hello; - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_if_ip_hellointerval, - no_eigrp_if_ip_hellointerval_cmd, - "no ip hello-interval eigrp [(1-65535)]", - NO_STR - "Interface Internet Protocol config commands\n" - "Configures EIGRP hello interval\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" - "Seconds between hello transmissions\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - ei->params.v_hello = EIGRP_HELLO_INTERVAL_DEFAULT; - - THREAD_TIMER_OFF(ei->t_hello); - thread_add_timer(master, eigrp_hello_timer, ei, 1, &ei->t_hello); - - return CMD_SUCCESS; -} - -DEFUN (eigrp_if_ip_holdinterval, - eigrp_if_ip_holdinterval_cmd, - "ip hold-time eigrp (1-65535)", - "Interface Internet Protocol config commands\n" - "Configures EIGRP IPv4 hold time\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" - "Seconds before neighbor is considered down\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - uint32_t hold; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - hold = atoi(argv[3]->arg); - - ei->params.v_wait = hold; - - return CMD_SUCCESS; -} - -DEFUN (eigrp_ip_summary_address, - eigrp_ip_summary_address_cmd, - "ip summary-address eigrp (1-65535) A.B.C.D/M", - "Interface Internet Protocol config commands\n" - "Perform address summarization\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" - "AS number\n" - "Summary <network>/<length>, e.g. 192.168.0.0/16\n") -{ - // VTY_DECLVAR_CONTEXT(interface, ifp); - // uint32_t AS; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - // AS = atoi (argv[3]->arg); - - /*TODO: */ - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_ip_summary_address, - no_eigrp_ip_summary_address_cmd, - "no ip summary-address eigrp (1-65535) A.B.C.D/M", - NO_STR - "Interface Internet Protocol config commands\n" - "Perform address summarization\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" - "AS number\n" - "Summary <network>/<length>, e.g. 192.168.0.0/16\n") -{ - // VTY_DECLVAR_CONTEXT(interface, ifp); - // uint32_t AS; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - // AS = atoi (argv[4]->arg); - - /*TODO: */ - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_if_ip_holdinterval, - no_eigrp_if_ip_holdinterval_cmd, - "no ip hold-time eigrp", - NO_STR - "Interface Internet Protocol config commands\n" - "Configures EIGRP hello interval\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - ei->params.v_wait = EIGRP_HOLD_INTERVAL_DEFAULT; - - return CMD_SUCCESS; -} - -static int str2auth_type(const char *str, struct eigrp_interface *ei) -{ - /* Sanity check. */ - if (str == NULL) - return CMD_WARNING_CONFIG_FAILED; - - if (strncmp(str, "md5", 3) == 0) { - ei->params.auth_type = EIGRP_AUTH_TYPE_MD5; - return CMD_SUCCESS; - } else if (strncmp(str, "hmac-sha-256", 12) == 0) { - ei->params.auth_type = EIGRP_AUTH_TYPE_SHA256; - return CMD_SUCCESS; - } - - return CMD_WARNING_CONFIG_FAILED; -} - -DEFUN (eigrp_authentication_mode, - eigrp_authentication_mode_cmd, - "ip authentication mode eigrp (1-65535) <md5|hmac-sha-256>", - "Interface Internet Protocol config commands\n" - "Authentication subcommands\n" - "Mode\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" - "Autonomous system number\n" - "Keyed message digest\n" - "HMAC SHA256 algorithm \n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - // if(strncmp(argv[2], "md5",3)) - // IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_MD5; - // else if(strncmp(argv[2], "hmac-sha-256",12)) - // IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_SHA256; - - return str2auth_type(argv[5]->arg, ei); -} - -DEFUN (no_eigrp_authentication_mode, - no_eigrp_authentication_mode_cmd, - "no ip authentication mode eigrp (1-65535) <md5|hmac-sha-256>", - "Disable\n" - "Interface Internet Protocol config commands\n" - "Authentication subcommands\n" - "Mode\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" - "Autonomous system number\n" - "Keyed message digest\n" - "HMAC SHA256 algorithm \n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - ei->params.auth_type = EIGRP_AUTH_TYPE_NONE; - - return CMD_SUCCESS; -} - -DEFPY (eigrp_authentication_keychain, - eigrp_authentication_keychain_cmd, - "[no] ip authentication key-chain eigrp (1-65535)$as WORD$name", - NO_STR - "Interface Internet Protocol config commands\n" - "Authentication subcommands\n" - "Key-chain\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" - "Autonomous system number\n" - "Name of key-chain\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - struct keychain *keychain; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, "EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - if (no) { - if ((ei->params.auth_keychain != NULL) - && (strcmp(ei->params.auth_keychain, name) == 0)) { - free(ei->params.auth_keychain); - ei->params.auth_keychain = NULL; - } else - vty_out(vty, - "Key chain with specified name not configured on interface\n"); - return CMD_SUCCESS; - } - - keychain = keychain_lookup(name); - if (keychain != NULL) { - if (ei->params.auth_keychain) { - free(ei->params.auth_keychain); - ei->params.auth_keychain = strdup(keychain->name); - } else - ei->params.auth_keychain = strdup(keychain->name); - } else { - vty_out(vty, - "Key chain with specified name not found\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; -} - -DEFUN (eigrp_redistribute_source_metric, - eigrp_redistribute_source_metric_cmd, - "redistribute " FRR_REDIST_STR_EIGRPD - " [metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)]", - REDIST_STR - FRR_REDIST_HELP_STR_EIGRPD - "Metric for redistributed routes\n" - "Bandwidth metric in Kbits per second\n" - "EIGRP delay metric, in 10 microsecond units\n" - "EIGRP reliability metric where 255 is 100% reliable2 ?\n" - "EIGRP Effective bandwidth metric (Loading) where 255 is 100% loaded\n" - "EIGRP MTU of the path\n") -{ - VTY_DECLVAR_CONTEXT(eigrp, eigrp); - struct eigrp_metrics metrics_from_command = {0}; - int source; - int idx = 0; - - /* Get distribute source. */ - argv_find(argv, argc, "redistribute", &idx); - source = proto_redistnum(AFI_IP, argv[idx + 1]->text); - if (source < 0) { - vty_out(vty, "%% Invalid route type\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Get metrics values */ - - return eigrp_redistribute_set(eigrp, source, metrics_from_command); -} - -DEFUN (no_eigrp_redistribute_source_metric, - no_eigrp_redistribute_source_metric_cmd, - "no redistribute " FRR_REDIST_STR_EIGRPD - " [metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)]", - "Disable\n" - REDIST_STR - FRR_REDIST_HELP_STR_EIGRPD - "Metric for redistributed routes\n" - "Bandwidth metric in Kbits per second\n" - "EIGRP delay metric, in 10 microsecond units\n" - "EIGRP reliability metric where 255 is 100% reliable2 ?\n" - "EIGRP Effective bandwidth metric (Loading) where 255 is 100% loaded\n" - "EIGRP MTU of the path\n") -{ - VTY_DECLVAR_CONTEXT(eigrp, eigrp); - int source; - int idx = 0; - - /* Get distribute source. */ - argv_find(argv, argc, "redistribute", &idx); - source = proto_redistnum(AFI_IP, argv[idx + 1]->text); - if (source < 0) { - vty_out(vty, "%% Invalid route type\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Get metrics values */ - - return eigrp_redistribute_unset(eigrp, source); -} - -DEFUN (eigrp_variance, - eigrp_variance_cmd, - "variance (1-128)", - "Control load balancing variance\n" - "Metric variance multiplier\n") -{ - struct eigrp *eigrp; - uint8_t variance; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, "EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - variance = atoi(argv[1]->arg); - - eigrp->variance = variance; - - /*TODO: */ - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_variance, - no_eigrp_variance_cmd, - "no variance (1-128)", - "Disable\n" - "Control load balancing variance\n" - "Metric variance multiplier\n") -{ - struct eigrp *eigrp; - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, "EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - eigrp->variance = EIGRP_VARIANCE_DEFAULT; - - /*TODO: */ - - return CMD_SUCCESS; -} - -DEFUN (eigrp_maximum_paths, - eigrp_maximum_paths_cmd, - "maximum-paths (1-32)", - "Forward packets over multiple paths\n" - "Number of paths\n") -{ - struct eigrp *eigrp; - uint8_t max; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, "EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - max = atoi(argv[1]->arg); - - eigrp->max_paths = max; - - /*TODO: */ - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_maximum_paths, - no_eigrp_maximum_paths_cmd, - "no maximum-paths (1-32)", - NO_STR - "Forward packets over multiple paths\n" - "Number of paths\n") -{ - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, "EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - eigrp->max_paths = EIGRP_MAX_PATHS_DEFAULT; - - /*TODO: */ - - return CMD_SUCCESS; -} - /* * Execute hard restart for all neighbors */ @@ -1492,40 +517,6 @@ DEFUN (clear_ip_eigrp_neighbors_IP_soft, return CMD_SUCCESS; } -static struct cmd_node eigrp_node = {EIGRP_NODE, "%s(config-router)# ", 1}; - -/* Save EIGRP configuration */ -static int eigrp_config_write(struct vty *vty) -{ - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp != NULL) { - /* Writes 'router eigrp' section to config */ - config_write_eigrp_router(vty, eigrp); - - /* Interface config print */ - config_write_interfaces(vty, eigrp); - // - // /* static neighbor print. */ - // config_write_eigrp_nbr_nbma (vty, eigrp); - // - // /* Virtual-Link print. */ - // config_write_virtual_link (vty, eigrp); - // - // /* Default metric configuration. */ - // config_write_eigrp_default_metric (vty, eigrp); - // - // /* Distribute-list and default-information print. */ - // config_write_eigrp_distribute (vty, eigrp); - // - // /* Distance configuration. */ - // config_write_eigrp_distance (vty, eigrp) - } - - return 0; -} - void eigrp_vty_show_init(void) { install_element(VIEW_NODE, &show_ip_eigrp_interfaces_cmd); @@ -1536,69 +527,9 @@ void eigrp_vty_show_init(void) install_element(VIEW_NODE, &show_ip_eigrp_topology_all_cmd); } -/* eigrpd's interface node. */ -static struct cmd_node eigrp_interface_node = {INTERFACE_NODE, - "%s(config-if)# ", 1}; - -void eigrp_vty_if_init(void) -{ - install_node(&eigrp_interface_node, eigrp_write_interface); - if_cmd_init(); - - /* Delay and bandwidth configuration commands*/ - install_element(INTERFACE_NODE, &eigrp_if_delay_cmd); - install_element(INTERFACE_NODE, &no_eigrp_if_delay_cmd); - install_element(INTERFACE_NODE, &eigrp_if_bandwidth_cmd); - install_element(INTERFACE_NODE, &no_eigrp_if_bandwidth_cmd); - - /*Hello-interval and hold-time interval configuration commands*/ - install_element(INTERFACE_NODE, &eigrp_if_ip_holdinterval_cmd); - install_element(INTERFACE_NODE, &no_eigrp_if_ip_holdinterval_cmd); - install_element(INTERFACE_NODE, &eigrp_if_ip_hellointerval_cmd); - install_element(INTERFACE_NODE, &no_eigrp_if_ip_hellointerval_cmd); - - /* "Authentication configuration commands */ - install_element(INTERFACE_NODE, &eigrp_authentication_mode_cmd); - install_element(INTERFACE_NODE, &no_eigrp_authentication_mode_cmd); - install_element(INTERFACE_NODE, &eigrp_authentication_keychain_cmd); - - /*EIGRP Summarization commands*/ - install_element(INTERFACE_NODE, &eigrp_ip_summary_address_cmd); - install_element(INTERFACE_NODE, &no_eigrp_ip_summary_address_cmd); -} - -static void eigrp_vty_zebra_init(void) -{ - install_element(EIGRP_NODE, &eigrp_redistribute_source_metric_cmd); - install_element(EIGRP_NODE, &no_eigrp_redistribute_source_metric_cmd); -} - /* Install EIGRP related vty commands. */ void eigrp_vty_init(void) { - install_node(&eigrp_node, eigrp_config_write); - - install_default(EIGRP_NODE); - - install_element(CONFIG_NODE, &router_eigrp_cmd); - install_element(CONFIG_NODE, &no_router_eigrp_cmd); - install_element(EIGRP_NODE, &eigrp_network_cmd); - install_element(EIGRP_NODE, &no_eigrp_network_cmd); - install_element(EIGRP_NODE, &eigrp_variance_cmd); - install_element(EIGRP_NODE, &no_eigrp_variance_cmd); - install_element(EIGRP_NODE, &eigrp_router_id_cmd); - install_element(EIGRP_NODE, &no_eigrp_router_id_cmd); - install_element(EIGRP_NODE, &eigrp_passive_interface_cmd); - install_element(EIGRP_NODE, &no_eigrp_passive_interface_cmd); - install_element(EIGRP_NODE, &eigrp_timers_active_cmd); - install_element(EIGRP_NODE, &no_eigrp_timers_active_cmd); - install_element(EIGRP_NODE, &eigrp_metric_weights_cmd); - install_element(EIGRP_NODE, &no_eigrp_metric_weights_cmd); - install_element(EIGRP_NODE, &eigrp_maximum_paths_cmd); - install_element(EIGRP_NODE, &no_eigrp_maximum_paths_cmd); - install_element(EIGRP_NODE, &eigrp_neighbor_cmd); - install_element(EIGRP_NODE, &no_eigrp_neighbor_cmd); - /* commands for manual hard restart */ install_element(ENABLE_NODE, &clear_ip_eigrp_neighbors_cmd); install_element(ENABLE_NODE, &clear_ip_eigrp_neighbors_int_cmd); @@ -1607,6 +538,4 @@ void eigrp_vty_init(void) install_element(ENABLE_NODE, &clear_ip_eigrp_neighbors_soft_cmd); install_element(ENABLE_NODE, &clear_ip_eigrp_neighbors_int_soft_cmd); install_element(ENABLE_NODE, &clear_ip_eigrp_neighbors_IP_soft_cmd); - - eigrp_vty_zebra_init(); } diff --git a/eigrpd/eigrp_vty.h b/eigrpd/eigrp_vty.h index 3fbadf6dfb..ebbf503857 100644 --- a/eigrpd/eigrp_vty.h +++ b/eigrpd/eigrp_vty.h @@ -35,6 +35,5 @@ /* Prototypes. */ extern void eigrp_vty_init(void); extern void eigrp_vty_show_init(void); -extern void eigrp_vty_if_init(void); #endif /* _Quagga_EIGRP_VTY_H_ */ diff --git a/eigrpd/eigrpd.h b/eigrpd/eigrpd.h index de7c881ac0..3ef3a9c0cc 100644 --- a/eigrpd/eigrpd.h +++ b/eigrpd/eigrpd.h @@ -52,4 +52,51 @@ extern struct eigrp *eigrp_get(const char *); extern struct eigrp *eigrp_lookup(void); extern void eigrp_router_id_update(struct eigrp *); +/* eigrp_cli.c */ +extern void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_end_header(struct vty *vty, struct lyd_node *dnode); +extern void eigrp_cli_show_router_id(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_passive_interface(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_active_time(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_variance(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_maximum_paths(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_metrics(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_network(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_neighbor(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_redistribute(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_delay(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_bandwidth(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_hello_interval(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_hold_time(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_summarize_address(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_authentication(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_init(void); + +/* eigrp_northbound.c */ +extern const struct frr_yang_module_info frr_eigrpd_info; + #endif /* _ZEBRA_EIGRPD_H */ diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am index 4503030fdf..cc46766586 100644 --- a/eigrpd/subdir.am +++ b/eigrpd/subdir.am @@ -7,6 +7,7 @@ noinst_LIBRARIES += eigrpd/libeigrp.a sbin_PROGRAMS += eigrpd/eigrpd dist_examples_DATA += eigrpd/eigrpd.conf.sample vtysh_scan += \ + $(top_srcdir)/eigrpd/eigrp_cli.c \ $(top_srcdir)/eigrpd/eigrp_dump.c \ $(top_srcdir)/eigrpd/eigrp_vty.c \ # end @@ -15,6 +16,7 @@ man8 += $(MANBUILD)/eigrpd.8 endif eigrpd_libeigrp_a_SOURCES = \ + eigrpd/eigrp_cli.c \ eigrpd/eigrp_dump.c \ eigrpd/eigrp_errors.c \ eigrpd/eigrp_filter.c \ @@ -24,6 +26,7 @@ eigrpd_libeigrp_a_SOURCES = \ eigrpd/eigrp_memory.c \ eigrpd/eigrp_neighbor.c \ eigrpd/eigrp_network.c \ + eigrpd/eigrp_northbound.c \ eigrpd/eigrp_packet.c \ eigrpd/eigrp_query.c \ eigrpd/eigrp_reply.c \ @@ -47,6 +50,9 @@ eigrpdheader_HEADERS = \ eigrpd/eigrp_vty_clippy.c: $(CLIPPY_DEPS) eigrpd/eigrp_vty.$(OBJEXT): eigrpd/eigrp_vty_clippy.c +eigrpd/eigrp_cli_clippy.c: $(CLIPPY_DEPS) +eigrpd/eigrp_cli.$(OBJEXT): eigrpd/eigrp_cli_clippy.c + noinst_HEADERS += \ eigrpd/eigrp_const.h \ eigrpd/eigrp_errors.h \ @@ -64,5 +70,9 @@ noinst_HEADERS += \ eigrpd/eigrp_zebra.h \ # end +nodist_eigrpd_eigrpd_SOURCES = \ + yang/frr-eigrpd.yang.c \ + # end + eigrpd_eigrpd_SOURCES = eigrpd/eigrp_main.c eigrpd_eigrpd_LDADD = eigrpd/libeigrp.a lib/libfrr.la $(LIBCAP) diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index 4b43260773..bd06286755 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -363,7 +363,7 @@ void cli_show_ip_isis_bfd_monitoring(struct vty *vty, struct lyd_node *dnode, if (!yang_dnode_get_bool(dnode, NULL)) vty_out(vty, " no"); - vty_out(vty, "isis bfd\n"); + vty_out(vty, " isis bfd\n"); } /* diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c index 3ad8278e10..a7f491e87d 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -117,7 +117,8 @@ int dotformat2buff(uint8_t *buff, const char *dotted) break; } - if ((isxdigit((int)*pos)) && (isxdigit((int)*(pos + 1)))) { + if ((isxdigit((unsigned char)*pos)) && + (isxdigit((unsigned char)*(pos + 1)))) { memcpy(number, pos, 2); pos += 2; } else { @@ -157,7 +158,8 @@ int sysid2buff(uint8_t *buff, const char *dotted) pos++; continue; } - if ((isxdigit((int)*pos)) && (isxdigit((int)*(pos + 1)))) { + if ((isxdigit((unsigned char)*pos)) && + (isxdigit((unsigned char)*(pos + 1)))) { memcpy(number, pos, 2); pos += 2; } else { diff --git a/isisd/isis_routemap.c b/isisd/isis_routemap.c index d63676256b..eb9b661d37 100644 --- a/isisd/isis_routemap.c +++ b/isisd/isis_routemap.c @@ -48,10 +48,9 @@ #include "isis_zebra.h" #include "isis_routemap.h" -static route_map_result_t route_match_ip_address(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_ip_address(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct access_list *alist; @@ -81,7 +80,7 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = { /* ------------------------------------------------------------*/ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -114,10 +113,9 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { /* ------------------------------------------------------------*/ -static route_map_result_t route_match_ipv6_address(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_ipv6_address(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct access_list *alist; @@ -147,7 +145,7 @@ static struct route_map_rule_cmd route_match_ipv6_address_cmd = { /* ------------------------------------------------------------*/ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -180,10 +178,9 @@ struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = { /* ------------------------------------------------------------*/ -static route_map_result_t route_set_metric(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_metric(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { uint32_t *metric; struct isis_ext_info *info; diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 6edfeb4c97..488dfedae4 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -1478,7 +1478,7 @@ static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context, bool sane = true; for (uint8_t i = 0; i < tlv_len; i++) { if ((unsigned char)tlvs->hostname[i] > 127 - || !isprint((int)tlvs->hostname[i])) { + || !isprint((unsigned char)tlvs->hostname[i])) { sane = false; tlvs->hostname[i] = '?'; } diff --git a/ldpd/lde.c b/ldpd/lde.c index 0ddf4f07d9..ac680b47a9 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -1654,6 +1654,19 @@ lde_del_label_chunk(void *val) } static int +lde_release_label_chunk(uint32_t start, uint32_t end) +{ + int ret; + + ret = lm_release_label_chunk(zclient_sync, start, end); + if (ret < 0) { + log_warnx("Error releasing label chunk!"); + return (-1); + } + return (0); +} + +static int lde_get_label_chunk(void) { int ret; @@ -1709,6 +1722,32 @@ on_get_label_chunk_response(uint32_t start, uint32_t end) current_label_chunk = listtail(label_chunk_list); } +void +lde_free_label(uint32_t label) +{ + struct listnode *node; + struct label_chunk *label_chunk; + uint64_t pos; + + for (ALL_LIST_ELEMENTS_RO(label_chunk_list, node, label_chunk)) { + if (label <= label_chunk->end && label >= label_chunk->start) { + pos = 1ULL << (label - label_chunk->start); + label_chunk->used_mask &= ~pos; + /* if nobody is using this chunk and it's not current_label_chunk, then free it */ + if (!label_chunk->used_mask && (current_label_chunk != node)) { + if (lde_release_label_chunk(label_chunk->start, label_chunk->end) != 0) + log_warnx("%s: Error releasing label chunk!", __func__); + else { + listnode_delete(label_chunk_list, label_chunk); + lde_del_label_chunk(label_chunk); + } + } + break; + } + } + return; +} + static uint32_t lde_get_next_label(void) { diff --git a/ldpd/lde.h b/ldpd/lde.h index 94077d1631..0a7d0a58fe 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -147,6 +147,7 @@ void lde_imsg_compose_parent_sync(int, pid_t, void *, uint16_t); int lde_imsg_compose_ldpe(int, uint32_t, pid_t, void *, uint16_t); int lde_acl_check(char *, int, union ldpd_addr *, uint8_t); uint32_t lde_update_label(struct fec_node *); +void lde_free_label(uint32_t label); void lde_send_change_klabel(struct fec_node *, struct fec_nh *); void lde_send_delete_klabel(struct fec_node *, struct fec_nh *); void lde_fec2map(struct fec *, struct map *); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index 28e455c7a5..0957a5455e 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -919,6 +919,9 @@ lde_gc_timer(struct thread *thread) !RB_EMPTY(lde_map_head, &fn->upstream)) continue; + if (fn->local_label != NO_LABEL) + lde_free_label(fn->local_label); + fec_remove(&ft, &fn->fec); free(fn); count++; diff --git a/lib/atomlist.h b/lib/atomlist.h index e4098ccb54..621db6824f 100644 --- a/lib/atomlist.h +++ b/lib/atomlist.h @@ -135,8 +135,10 @@ macro_inline void prefix ## _add_tail(struct prefix##_head *h, type *item) \ macro_inline void prefix ## _del_hint(struct prefix##_head *h, type *item, \ _Atomic atomptr_t *hint) \ { atomlist_del_hint(&h->ah, &item->field.ai, hint); } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ -{ atomlist_del_hint(&h->ah, &item->field.ai, NULL); } \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ +{ atomlist_del_hint(&h->ah, &item->field.ai, NULL); \ + /* TODO: Return NULL if not found */ \ + return item; } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { char *p = (char *)atomlist_pop(&h->ah); \ return p ? (type *)(p - offsetof(type, field)) : NULL; } \ @@ -273,9 +275,11 @@ macro_inline void prefix ## _del_hint(struct prefix##_head *h, type *item, \ { \ atomsort_del_hint(&h->ah, &item->field.ai, hint); \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ atomsort_del_hint(&h->ah, &item->field.ai, NULL); \ + /* TODO: Return NULL if not found */ \ + return item; \ } \ macro_inline size_t prefix ## _count(struct prefix##_head *h) \ { \ diff --git a/lib/command.c b/lib/command.c index c8fbf22721..9dabc2af7e 100644 --- a/lib/command.c +++ b/lib/command.c @@ -89,7 +89,6 @@ const char *node_names[] = { "aaa", // AAA_NODE, "keychain", // KEYCHAIN_NODE, "keychain key", // KEYCHAIN_KEY_NODE, - "logical-router", // LOGICALROUTER_NODE, "static ip", // IP_NODE, "vrf", // VRF_NODE, "interface", // INTERFACE_NODE, @@ -290,7 +289,7 @@ vector cmd_make_strvec(const char *string) const char *copy = string; /* skip leading whitespace */ - while (isspace((int)*copy) && *copy != '\0') + while (isspace((unsigned char)*copy) && *copy != '\0') copy++; /* if the entire string was whitespace or a comment, return */ @@ -1456,7 +1455,6 @@ void cmd_exit(struct vty *vty) break; case INTERFACE_NODE: case PW_NODE: - case LOGICALROUTER_NODE: case VRF_NODE: case NH_GROUP_NODE: case ZEBRA_NODE: @@ -1936,7 +1934,7 @@ DEFUN(config_domainname, { struct cmd_token *word = argv[1]; - if (!isalpha((int)word->arg[0])) { + if (!isalpha((unsigned char)word->arg[0])) { vty_out(vty, "Please specify string starting with alphabet\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -1970,7 +1968,7 @@ DEFUN (config_hostname, { struct cmd_token *word = argv[1]; - if (!isalnum((int)word->arg[0])) { + if (!isalnum((unsigned char)word->arg[0])) { vty_out(vty, "Please specify string starting with alphabet or number\n"); return CMD_WARNING_CONFIG_FAILED; @@ -2018,7 +2016,7 @@ DEFUN (config_password, return CMD_SUCCESS; } - if (!isalnum((int)argv[idx_8]->arg[0])) { + if (!isalnum((unsigned char)argv[idx_8]->arg[0])) { vty_out(vty, "Please specify string starting with alphanumeric\n"); return CMD_WARNING_CONFIG_FAILED; @@ -2098,7 +2096,7 @@ DEFUN (config_enable_password, } } - if (!isalnum((int)argv[idx_8]->arg[0])) { + if (!isalnum((unsigned char)argv[idx_8]->arg[0])) { vty_out(vty, "Please specify string starting with alphanumeric\n"); return CMD_WARNING_CONFIG_FAILED; diff --git a/lib/command.h b/lib/command.h index 08d6128af4..8dc35a0fdc 100644 --- a/lib/command.h +++ b/lib/command.h @@ -98,7 +98,6 @@ enum node_type { AAA_NODE, /* AAA node. */ KEYCHAIN_NODE, /* Key-chain node. */ KEYCHAIN_KEY_NODE, /* Key-chain key node. */ - LOGICALROUTER_NODE, /* Logical-Router node. */ IP_NODE, /* Static ip route node. */ VRF_NODE, /* VRF mode node. */ INTERFACE_NODE, /* Interface mode node. */ diff --git a/lib/command_graph.c b/lib/command_graph.c index 4757fd951f..d30d9ab702 100644 --- a/lib/command_graph.c +++ b/lib/command_graph.c @@ -97,7 +97,7 @@ void cmd_token_varname_set(struct cmd_token *token, const char *varname) token->varname[i] = '_'; break; default: - token->varname[i] = tolower((int)varname[i]); + token->varname[i] = tolower((unsigned char)varname[i]); } token->varname[len] = '\0'; } diff --git a/lib/command_match.c b/lib/command_match.c index 9456e1585a..26d763849d 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -714,7 +714,7 @@ static enum match_type match_ipv4(const char *str) dots++; break; } - if (!isdigit((int)*str)) + if (!isdigit((unsigned char)*str)) return no_match; str++; @@ -765,7 +765,7 @@ static enum match_type match_ipv4_prefix(const char *str) break; } - if (!isdigit((int)*str)) + if (!isdigit((unsigned char)*str)) return no_match; str++; @@ -797,7 +797,7 @@ static enum match_type match_ipv4_prefix(const char *str) sp = str; while (*str != '\0') { - if (!isdigit((int)*str)) + if (!isdigit((unsigned char)*str)) return no_match; str++; diff --git a/lib/compiler.h b/lib/compiler.h index 7c7f4ce294..6700ca9e8b 100644 --- a/lib/compiler.h +++ b/lib/compiler.h @@ -165,6 +165,13 @@ extern "C" { _min_a < _min_b ? _min_a : _min_b; \ }) +#define numcmp(a, b) \ + ({ \ + typeof(a) _cmp_a = (a); \ + typeof(b) _cmp_b = (b); \ + (_cmp_a < _cmp_b) ? -1 : ((_cmp_a > _cmp_b) ? 1 : 0); \ + }) + #ifndef offsetof #ifdef __compiler_offsetof #define offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE,MEMBER) diff --git a/lib/ferr.c b/lib/ferr.c index 65c0cf886d..8afc926c41 100644 --- a/lib/ferr.c +++ b/lib/ferr.c @@ -126,10 +126,8 @@ void log_ref_display(struct vty *vty, uint32_t code, bool json) if (code) { ref = log_ref_get(code); - if (!ref) { - vty_out(vty, "Code %"PRIu32" - Unknown\n", code); + if (!ref) return; - } listnode_add(errlist, ref); } @@ -197,8 +195,6 @@ void log_ref_init(void) "Error Reference Texts"); } pthread_mutex_unlock(&refs_mtx); - - install_element(VIEW_NODE, &show_error_code_cmd); } void log_ref_fini(void) @@ -212,6 +208,12 @@ void log_ref_fini(void) pthread_mutex_unlock(&refs_mtx); } +void log_ref_vty_init(void) +{ + install_element(VIEW_NODE, &show_error_code_cmd); +} + + const struct ferr *ferr_get_last(ferr_r errval) { struct ferr *last_error = pthread_getspecific(errkey); diff --git a/lib/ferr.h b/lib/ferr.h index 93d0ced538..a89b595e87 100644 --- a/lib/ferr.h +++ b/lib/ferr.h @@ -158,6 +158,7 @@ void log_ref_display(struct vty *vty, uint32_t code, bool json); */ void log_ref_init(void); void log_ref_fini(void); +void log_ref_vty_init(void); /* get error details. * diff --git a/lib/filter.c b/lib/filter.c index 276df4b4d7..fe62ca1c13 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -60,6 +60,9 @@ struct filter { /* Filter type information. */ enum filter_type type; + /* Sequence number */ + int64_t seq; + /* Cisco access-list */ int cisco; @@ -270,7 +273,7 @@ static struct access_list *access_list_insert(afi_t afi, const char *name) /* If name is made by all digit character. We treat it as number. */ for (number = 0, i = 0; i < strlen(name); i++) { - if (isdigit((int)name[i])) + if (isdigit((unsigned char)name[i])) number = (number * 10) + (name[i] - '0'); else break; @@ -406,23 +409,35 @@ void access_list_delete_hook(void (*func)(struct access_list *access)) access_master_mac.delete_hook = func; } -/* Add new filter to the end of specified access_list. */ -static void access_list_filter_add(struct access_list *access, - struct filter *filter) +/* Calculate new sequential number. */ +static int64_t filter_new_seq_get(struct access_list *access) { - filter->next = NULL; - filter->prev = access->tail; + int64_t maxseq; + int64_t newseq; + struct filter *filter; - if (access->tail) - access->tail->next = filter; - else - access->head = filter; - access->tail = filter; + maxseq = newseq = 0; - /* Run hook function. */ - if (access->master->add_hook) - (*access->master->add_hook)(access); - route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_ADDED); + for (filter = access->head; filter; filter = filter->next) { + if (maxseq < filter->seq) + maxseq = filter->seq; + } + + newseq = ((maxseq / 5) * 5) + 5; + + return (newseq > UINT_MAX) ? UINT_MAX : newseq; +} + +/* Return access list entry which has same seq number. */ +static struct filter *filter_seq_check(struct access_list *access, + int64_t seq) +{ + struct filter *filter; + + for (filter = access->head; filter; filter = filter->next) + if (filter->seq == seq) + return filter; + return NULL; } /* If access_list has no filter then return 1. */ @@ -465,6 +480,58 @@ static void access_list_filter_delete(struct access_list *access, access_list_delete(access); } +/* Add new filter to the end of specified access_list. */ +static void access_list_filter_add(struct access_list *access, + struct filter *filter) +{ + struct filter *replace; + struct filter *point; + + /* Automatic asignment of seq no. */ + if (filter->seq == -1) + filter->seq = filter_new_seq_get(access); + + if (access->tail && filter->seq > access->tail->seq) + point = NULL; + else { + /* Is there any same seq access list filter? */ + replace = filter_seq_check(access, filter->seq); + if (replace) + access_list_filter_delete(access, replace); + + /* Check insert point. */ + for (point = access->head; point; point = point->next) + if (point->seq >= filter->seq) + break; + } + + /* In case of this is the first element of the list. */ + filter->next = point; + + if (point) { + if (point->prev) + point->prev->next = filter; + else + access->head = filter; + + filter->prev = point->prev; + point->prev = filter; + } else { + if (access->tail) + access->tail->next = filter; + else + access->head = filter; + + filter->prev = access->tail; + access->tail = filter; + } + + /* Run hook function. */ + if (access->master->add_hook) + (*access->master->add_hook)(access); + route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_ADDED); +} + /* deny Specify packets to reject permit Specify packets to forward @@ -553,12 +620,13 @@ static int vty_access_list_remark_unset(struct vty *vty, afi_t afi, } static int filter_set_cisco(struct vty *vty, const char *name_str, - const char *type_str, const char *addr_str, - const char *addr_mask_str, const char *mask_str, - const char *mask_mask_str, int extended, int set) + const char *seq, const char *type_str, + const char *addr_str, const char *addr_mask_str, + const char *mask_str, const char *mask_mask_str, + int extended, int set) { int ret; - enum filter_type type; + enum filter_type type = FILTER_DENY; struct filter *mfilter; struct filter_cisco *filter; struct access_list *access; @@ -566,15 +634,21 @@ static int filter_set_cisco(struct vty *vty, const char *name_str, struct in_addr addr_mask; struct in_addr mask; struct in_addr mask_mask; + int64_t seqnum = -1; + + if (seq) + seqnum = (int64_t)atol(seq); /* Check of filter type. */ - if (strncmp(type_str, "p", 1) == 0) - type = FILTER_PERMIT; - else if (strncmp(type_str, "d", 1) == 0) - type = FILTER_DENY; - else { - vty_out(vty, "%% filter type must be permit or deny\n"); - return CMD_WARNING_CONFIG_FAILED; + if (type_str) { + if (strncmp(type_str, "p", 1) == 0) + type = FILTER_PERMIT; + else if (strncmp(type_str, "d", 1) == 0) + type = FILTER_DENY; + else { + vty_out(vty, "%% filter type must be permit or deny\n"); + return CMD_WARNING_CONFIG_FAILED; + } } ret = inet_aton(addr_str, &addr); @@ -606,6 +680,7 @@ static int filter_set_cisco(struct vty *vty, const char *name_str, mfilter = filter_new(); mfilter->type = type; mfilter->cisco = 1; + mfilter->seq = seqnum; filter = &mfilter->u.cfilter; filter->extended = extended; filter->addr.s_addr = addr.s_addr & ~addr_mask.s_addr; @@ -640,163 +715,311 @@ static int filter_set_cisco(struct vty *vty, const char *name_str, /* Standard access-list */ DEFUN (access_list_standard, access_list_standard_cmd, - "access-list <(1-99)|(1300-1999)> <deny|permit> A.B.C.D A.B.C.D", + "access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> A.B.C.D A.B.C.D", "Add an access list entry\n" "IP standard access list\n" "IP standard access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Address to match\n" "Wildcard bits\n") { int idx_acl = 1; - int idx_permit_deny = 2; - int idx_ipv4 = 3; - int idx_ipv4_2 = 4; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, - argv[idx_ipv4_2]->arg, NULL, NULL, 0, 1); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *address = NULL; + char *wildcard = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) { + address = argv[idx]->arg; + wildcard = argv[idx + 1]->arg; + } + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, + address, wildcard, NULL, NULL, 0, 1); } DEFUN (access_list_standard_nomask, access_list_standard_nomask_cmd, - "access-list <(1-99)|(1300-1999)> <deny|permit> A.B.C.D", + "access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> A.B.C.D", "Add an access list entry\n" "IP standard access list\n" "IP standard access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Address to match\n") { int idx_acl = 1; - int idx_permit_deny = 2; - int idx_ipv4 = 3; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, - "0.0.0.0", NULL, NULL, 0, 1); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *address = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) + address = argv[idx]->arg; + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, + address, "0.0.0.0", NULL, NULL, 0, 1); } DEFUN (access_list_standard_host, access_list_standard_host_cmd, - "access-list <(1-99)|(1300-1999)> <deny|permit> host A.B.C.D", + "access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> host A.B.C.D", "Add an access list entry\n" "IP standard access list\n" "IP standard access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "A single host address\n" "Address to match\n") { int idx_acl = 1; - int idx_permit_deny = 2; - int idx_ipv4 = 4; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, - "0.0.0.0", NULL, NULL, 0, 1); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *address = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) + address = argv[idx]->arg; + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, + address, "0.0.0.0", NULL, NULL, 0, 1); } DEFUN (access_list_standard_any, access_list_standard_any_cmd, - "access-list <(1-99)|(1300-1999)> <deny|permit> any", + "access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> any", "Add an access list entry\n" "IP standard access list\n" "IP standard access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any source host\n") { int idx_acl = 1; - int idx_permit_deny = 2; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, "0.0.0.0", - "255.255.255.255", NULL, NULL, 0, 1); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, + "0.0.0.0", "255.255.255.255", NULL, NULL, 0, 1); } DEFUN (no_access_list_standard, no_access_list_standard_cmd, - "no access-list <(1-99)|(1300-1999)> <deny|permit> A.B.C.D A.B.C.D", + "no access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> A.B.C.D A.B.C.D", NO_STR "Add an access list entry\n" "IP standard access list\n" "IP standard access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Address to match\n" "Wildcard bits\n") { - int idx_acl = 2; - int idx_permit_deny = 3; - int idx_ipv4 = 4; - int idx_ipv4_2 = 5; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, - argv[idx_ipv4_2]->arg, NULL, NULL, 0, 0); + int idx_acl = 1; + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *address = NULL; + char *wildcard = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) { + address = argv[idx]->arg; + wildcard = argv[idx + 1]->arg; + } + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, + address, wildcard, NULL, NULL, 0, 0); } DEFUN (no_access_list_standard_nomask, no_access_list_standard_nomask_cmd, - "no access-list <(1-99)|(1300-1999)> <deny|permit> A.B.C.D", + "no access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> A.B.C.D", NO_STR "Add an access list entry\n" "IP standard access list\n" "IP standard access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Address to match\n") { int idx_acl = 2; - int idx_permit_deny = 3; - int idx_ipv4 = 4; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, - "0.0.0.0", NULL, NULL, 0, 0); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *address = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) + address = argv[idx]->arg; + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, + address, "0.0.0.0", NULL, NULL, 0, 0); } DEFUN (no_access_list_standard_host, no_access_list_standard_host_cmd, - "no access-list <(1-99)|(1300-1999)> <deny|permit> host A.B.C.D", + "no access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> host A.B.C.D", NO_STR "Add an access list entry\n" "IP standard access list\n" "IP standard access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "A single host address\n" "Address to match\n") { int idx_acl = 2; - int idx_permit_deny = 3; - int idx_ipv4 = 5; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, - "0.0.0.0", NULL, NULL, 0, 0); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *address = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) + address = argv[idx]->arg; + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, + address, "0.0.0.0", NULL, NULL, 0, 0); } DEFUN (no_access_list_standard_any, no_access_list_standard_any_cmd, - "no access-list <(1-99)|(1300-1999)> <deny|permit> any", + "no access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> any", NO_STR "Add an access list entry\n" "IP standard access list\n" "IP standard access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any source host\n") { int idx_acl = 2; - int idx_permit_deny = 3; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, "0.0.0.0", - "255.255.255.255", NULL, NULL, 0, 0); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, + "0.0.0.0", "255.255.255.255", NULL, NULL, 0, 0); } /* Extended access-list */ DEFUN (access_list_extended, access_list_extended_cmd, - "access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D", + "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -806,23 +1029,45 @@ DEFUN (access_list_extended, "Destination Wildcard bits\n") { int idx_acl = 1; - int idx_permit_deny = 2; - int idx_ipv4 = 4; - int idx_ipv4_2 = 5; - int idx_ipv4_3 = 6; - int idx_ipv4_4 = 7; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, - argv[idx_ipv4_2]->arg, argv[idx_ipv4_3]->arg, - argv[idx_ipv4_4]->arg, 1, 1); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *src = NULL; + char *dst = NULL; + char *src_wildcard = NULL; + char *dst_wildcard = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) { + src = argv[idx]->arg; + src_wildcard = argv[idx + 1]->arg; + dst = argv[idx + 2]->arg; + dst_wildcard = argv[idx + 3]->arg; + } + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src, + src_wildcard, dst, dst_wildcard, 1, 1); } DEFUN (access_list_extended_mask_any, access_list_extended_mask_any_cmd, - "access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D any", + "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D any", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -831,21 +1076,42 @@ DEFUN (access_list_extended_mask_any, "Any destination host\n") { int idx_acl = 1; - int idx_permit_deny = 2; - int idx_ipv4 = 4; - int idx_ipv4_2 = 5; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, - argv[idx_ipv4_2]->arg, "0.0.0.0", - "255.255.255.255", 1, 1); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *src = NULL; + char *src_wildcard = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) { + src = argv[idx]->arg; + src_wildcard = argv[idx + 1]->arg; + } + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src, + src_wildcard, "0.0.0.0", "255.255.255.255", 1, + 1); } DEFUN (access_list_extended_any_mask, access_list_extended_any_mask_cmd, - "access-list <(100-199)|(2000-2699)> <deny|permit> ip any A.B.C.D A.B.C.D", + "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any A.B.C.D A.B.C.D", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -854,21 +1120,42 @@ DEFUN (access_list_extended_any_mask, "Destination Wildcard bits\n") { int idx_acl = 1; - int idx_permit_deny = 2; - int idx_ipv4 = 5; - int idx_ipv4_2 = 6; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, "0.0.0.0", - "255.255.255.255", argv[idx_ipv4]->arg, - argv[idx_ipv4_2]->arg, 1, 1); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *dst = NULL; + char *dst_wildcard = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) { + dst = argv[idx]->arg; + dst_wildcard = argv[idx + 1]->arg; + } + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, + "0.0.0.0", "255.255.255.255", dst, dst_wildcard, + 1, 1); } DEFUN (access_list_extended_any_any, access_list_extended_any_any_cmd, - "access-list <(100-199)|(2000-2699)> <deny|permit> ip any any", + "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any any", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -876,18 +1163,33 @@ DEFUN (access_list_extended_any_any, "Any destination host\n") { int idx_acl = 1; - int idx_permit_deny = 2; - return filter_set_cisco( - vty, argv[idx_acl]->arg, argv[idx_permit_deny]->arg, "0.0.0.0", - "255.255.255.255", "0.0.0.0", "255.255.255.255", 1, 1); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, + "0.0.0.0", "255.255.255.255", "0.0.0.0", + "255.255.255.255", 1, 1); } DEFUN (access_list_extended_mask_host, access_list_extended_mask_host_cmd, - "access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D host A.B.C.D", + "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D host A.B.C.D", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -897,22 +1199,43 @@ DEFUN (access_list_extended_mask_host, "Destination address\n") { int idx_acl = 1; - int idx_permit_deny = 2; - int idx_ipv4 = 4; - int idx_ipv4_2 = 5; - int idx_ipv4_3 = 7; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, - argv[idx_ipv4_2]->arg, argv[idx_ipv4_3]->arg, - "0.0.0.0", 1, 1); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *src = NULL; + char *dst = NULL; + char *src_wildcard = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) { + src = argv[idx]->arg; + src_wildcard = argv[idx + 1]->arg; + dst = argv[idx + 3]->arg; + } + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src, + src_wildcard, dst, "0.0.0.0", 1, 1); } DEFUN (access_list_extended_host_mask, access_list_extended_host_mask_cmd, - "access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D A.B.C.D A.B.C.D", + "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D A.B.C.D A.B.C.D", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -922,22 +1245,43 @@ DEFUN (access_list_extended_host_mask, "Destination Wildcard bits\n") { int idx_acl = 1; - int idx_permit_deny = 2; - int idx_ipv4 = 5; - int idx_ipv4_2 = 6; - int idx_ipv4_3 = 7; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, - "0.0.0.0", argv[idx_ipv4_2]->arg, - argv[idx_ipv4_3]->arg, 1, 1); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *src = NULL; + char *dst = NULL; + char *dst_wildcard = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) { + src = argv[idx]->arg; + dst = argv[idx + 1]->arg; + dst_wildcard = argv[idx + 2]->arg; + } + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src, + "0.0.0.0", dst, dst_wildcard, 1, 1); } DEFUN (access_list_extended_host_host, access_list_extended_host_host_cmd, - "access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D host A.B.C.D", + "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D host A.B.C.D", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -947,21 +1291,41 @@ DEFUN (access_list_extended_host_host, "Destination address\n") { int idx_acl = 1; - int idx_permit_deny = 2; - int idx_ipv4 = 5; - int idx_ipv4_2 = 7; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, - "0.0.0.0", argv[idx_ipv4_2]->arg, "0.0.0.0", 1, - 1); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *src = NULL; + char *dst = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) { + src = argv[idx]->arg; + dst = argv[idx + 2]->arg; + } + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src, + "0.0.0.0", dst, "0.0.0.0", 1, 1); } DEFUN (access_list_extended_any_host, access_list_extended_any_host_cmd, - "access-list <(100-199)|(2000-2699)> <deny|permit> ip any host A.B.C.D", + "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any host A.B.C.D", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -970,19 +1334,39 @@ DEFUN (access_list_extended_any_host, "Destination address\n") { int idx_acl = 1; - int idx_permit_deny = 2; - int idx_ipv4 = 6; - return filter_set_cisco( - vty, argv[idx_acl]->arg, argv[idx_permit_deny]->arg, "0.0.0.0", - "255.255.255.255", argv[idx_ipv4]->arg, "0.0.0.0", 1, 1); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *dst = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) + dst = argv[idx]->arg; + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, + "0.0.0.0", "255.255.255.255", dst, "0.0.0.0", 1, + 1); } DEFUN (access_list_extended_host_any, access_list_extended_host_any_cmd, - "access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D any", + "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D any", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -991,20 +1375,39 @@ DEFUN (access_list_extended_host_any, "Any destination host\n") { int idx_acl = 1; - int idx_permit_deny = 2; - int idx_ipv4 = 5; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *src = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) + src = argv[idx]->arg; + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src, "0.0.0.0", "0.0.0.0", "255.255.255.255", 1, 1); } DEFUN (no_access_list_extended, no_access_list_extended_cmd, - "no access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D", + "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D", NO_STR "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -1014,24 +1417,46 @@ DEFUN (no_access_list_extended, "Destination Wildcard bits\n") { int idx_acl = 2; - int idx_permit_deny = 3; - int idx_ipv4 = 5; - int idx_ipv4_2 = 6; - int idx_ipv4_3 = 7; - int idx_ipv4_4 = 8; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, - argv[idx_ipv4_2]->arg, argv[idx_ipv4_3]->arg, - argv[idx_ipv4_4]->arg, 1, 0); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *src = NULL; + char *dst = NULL; + char *src_wildcard = NULL; + char *dst_wildcard = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) { + src = argv[idx]->arg; + src_wildcard = argv[idx + 1]->arg; + dst = argv[idx + 2]->arg; + dst_wildcard = argv[idx + 3]->arg; + } + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src, + src_wildcard, dst, dst_wildcard, 1, 0); } DEFUN (no_access_list_extended_mask_any, no_access_list_extended_mask_any_cmd, - "no access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D any", + "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D any", NO_STR "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -1040,22 +1465,43 @@ DEFUN (no_access_list_extended_mask_any, "Any destination host\n") { int idx_acl = 2; - int idx_permit_deny = 3; - int idx_ipv4 = 5; - int idx_ipv4_2 = 6; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, - argv[idx_ipv4_2]->arg, "0.0.0.0", - "255.255.255.255", 1, 0); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *src = NULL; + char *src_wildcard = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) { + src = argv[idx]->arg; + src_wildcard = argv[idx + 1]->arg; + } + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src, + src_wildcard, "0.0.0.0", "255.255.255.255", 1, + 0); } DEFUN (no_access_list_extended_any_mask, no_access_list_extended_any_mask_cmd, - "no access-list <(100-199)|(2000-2699)> <deny|permit> ip any A.B.C.D A.B.C.D", + "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any A.B.C.D A.B.C.D", NO_STR "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -1064,22 +1510,43 @@ DEFUN (no_access_list_extended_any_mask, "Destination Wildcard bits\n") { int idx_acl = 2; - int idx_permit_deny = 3; - int idx_ipv4 = 6; - int idx_ipv4_2 = 7; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, "0.0.0.0", - "255.255.255.255", argv[idx_ipv4]->arg, - argv[idx_ipv4_2]->arg, 1, 0); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *dst = NULL; + char *dst_wildcard = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) { + dst = argv[idx]->arg; + dst_wildcard = argv[idx + 1]->arg; + } + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, + "0.0.0.0", "255.255.255.255", dst, dst_wildcard, + 1, 0); } DEFUN (no_access_list_extended_any_any, no_access_list_extended_any_any_cmd, - "no access-list <(100-199)|(2000-2699)> <deny|permit> ip any any", + "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any any", NO_STR "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -1087,19 +1554,34 @@ DEFUN (no_access_list_extended_any_any, "Any destination host\n") { int idx_acl = 2; - int idx_permit_deny = 3; - return filter_set_cisco( - vty, argv[idx_acl]->arg, argv[idx_permit_deny]->arg, "0.0.0.0", - "255.255.255.255", "0.0.0.0", "255.255.255.255", 1, 0); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, + "0.0.0.0", "255.255.255.255", "0.0.0.0", + "255.255.255.255", 1, 0); } DEFUN (no_access_list_extended_mask_host, no_access_list_extended_mask_host_cmd, - "no access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D host A.B.C.D", + "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D host A.B.C.D", NO_STR "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -1109,23 +1591,44 @@ DEFUN (no_access_list_extended_mask_host, "Destination address\n") { int idx_acl = 2; - int idx_permit_deny = 3; - int idx_ipv4 = 5; - int idx_ipv4_2 = 6; - int idx_ipv4_3 = 8; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, - argv[idx_ipv4_2]->arg, argv[idx_ipv4_3]->arg, - "0.0.0.0", 1, 0); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *src = NULL; + char *dst = NULL; + char *src_wildcard = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) { + src = argv[idx]->arg; + src_wildcard = argv[idx + 1]->arg; + dst = argv[idx + 3]->arg; + } + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src, + src_wildcard, dst, "0.0.0.0", 1, 0); } DEFUN (no_access_list_extended_host_mask, no_access_list_extended_host_mask_cmd, - "no access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D A.B.C.D A.B.C.D", + "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D A.B.C.D A.B.C.D", NO_STR "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -1135,23 +1638,44 @@ DEFUN (no_access_list_extended_host_mask, "Destination Wildcard bits\n") { int idx_acl = 2; - int idx_permit_deny = 3; - int idx_ipv4 = 6; - int idx_ipv4_2 = 7; - int idx_ipv4_3 = 8; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, - "0.0.0.0", argv[idx_ipv4_2]->arg, - argv[idx_ipv4_3]->arg, 1, 0); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *src = NULL; + char *dst = NULL; + char *dst_wildcard = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) { + src = argv[idx]->arg; + dst = argv[idx + 1]->arg; + dst_wildcard = argv[idx + 2]->arg; + } + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src, + "0.0.0.0", dst, dst_wildcard, 1, 0); } DEFUN (no_access_list_extended_host_host, no_access_list_extended_host_host_cmd, - "no access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D host A.B.C.D", + "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D host A.B.C.D", NO_STR "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -1161,22 +1685,42 @@ DEFUN (no_access_list_extended_host_host, "Destination address\n") { int idx_acl = 2; - int idx_permit_deny = 3; - int idx_ipv4 = 6; - int idx_ipv4_2 = 8; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, - "0.0.0.0", argv[idx_ipv4_2]->arg, "0.0.0.0", 1, - 0); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *src = NULL; + char *dst = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) { + src = argv[idx]->arg; + dst = argv[idx + 2]->arg; + } + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src, + "0.0.0.0", dst, "0.0.0.0", 1, 0); } DEFUN (no_access_list_extended_any_host, no_access_list_extended_any_host_cmd, - "no access-list <(100-199)|(2000-2699)> <deny|permit> ip any host A.B.C.D", + "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any host A.B.C.D", NO_STR "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -1185,20 +1729,40 @@ DEFUN (no_access_list_extended_any_host, "Destination address\n") { int idx_acl = 2; - int idx_permit_deny = 3; - int idx_ipv4 = 7; - return filter_set_cisco( - vty, argv[idx_acl]->arg, argv[idx_permit_deny]->arg, "0.0.0.0", - "255.255.255.255", argv[idx_ipv4]->arg, "0.0.0.0", 1, 0); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *dst = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) + dst = argv[idx]->arg; + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, + "0.0.0.0", "255.255.255.255", dst, "0.0.0.0", 1, + 0); } DEFUN (no_access_list_extended_host_any, no_access_list_extended_host_any_cmd, - "no access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D any", + "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D any", NO_STR "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" @@ -1207,23 +1771,41 @@ DEFUN (no_access_list_extended_host_any, "Any destination host\n") { int idx_acl = 2; - int idx_permit_deny = 3; - int idx_ipv4 = 6; - return filter_set_cisco(vty, argv[idx_acl]->arg, - argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg, + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *src = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D", &idx); + if (idx) + src = argv[idx]->arg; + + return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src, "0.0.0.0", "0.0.0.0", "255.255.255.255", 1, 0); } static int filter_set_zebra(struct vty *vty, const char *name_str, - const char *type_str, afi_t afi, + const char *seq, const char *type_str, afi_t afi, const char *prefix_str, int exact, int set) { int ret; - enum filter_type type; + enum filter_type type = FILTER_DENY; struct filter *mfilter; struct filter_zebra *filter; struct access_list *access; struct prefix p; + int64_t seqnum = -1; if (strlen(name_str) > ACL_NAMSIZ) { vty_out(vty, @@ -1233,14 +1815,19 @@ static int filter_set_zebra(struct vty *vty, const char *name_str, return CMD_WARNING_CONFIG_FAILED; } + if (seq) + seqnum = (int64_t)atol(seq); + /* Check of filter type. */ - if (strncmp(type_str, "p", 1) == 0) - type = FILTER_PERMIT; - else if (strncmp(type_str, "d", 1) == 0) - type = FILTER_DENY; - else { - vty_out(vty, "filter type must be [permit|deny]\n"); - return CMD_WARNING_CONFIG_FAILED; + if (type_str) { + if (strncmp(type_str, "p", 1) == 0) + type = FILTER_PERMIT; + else if (strncmp(type_str, "d", 1) == 0) + type = FILTER_DENY; + else { + vty_out(vty, "filter type must be [permit|deny]\n"); + return CMD_WARNING_CONFIG_FAILED; + } } /* Check string format of prefix and prefixlen. */ @@ -1269,6 +1856,7 @@ static int filter_set_zebra(struct vty *vty, const char *name_str, mfilter = filter_new(); mfilter->type = type; + mfilter->seq = seqnum; filter = &mfilter->u.zfilter; prefix_copy(&filter->prefix, &p); @@ -1298,67 +1886,145 @@ static int filter_set_zebra(struct vty *vty, const char *name_str, DEFUN (mac_access_list, mac_access_list_cmd, - "mac access-list WORD <deny|permit> X:X:X:X:X:X", + "mac access-list WORD [seq (1-4294967295)] <deny|permit> X:X:X:X:X:X", "Add a mac access-list\n" "Add an access list entry\n" "MAC zebra access-list name\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "MAC address to match. e.g. 00:01:00:01:00:01\n") { - return filter_set_zebra(vty, argv[2]->arg, argv[3]->arg, AFI_L2VPN, - argv[4]->arg, 0, 1); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *mac = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "X:X:X:X:X:X", &idx); + if (idx) + mac = argv[idx]->arg; + + return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN, + mac, 0, 1); } DEFUN (no_mac_access_list, no_mac_access_list_cmd, - "no mac access-list WORD <deny|permit> X:X:X:X:X:X", + "no mac access-list WORD [seq (1-4294967295)] <deny|permit> X:X:X:X:X:X", NO_STR "Remove a mac access-list\n" "Remove an access list entry\n" "MAC zebra access-list name\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "MAC address to match. e.g. 00:01:00:01:00:01\n") { - return filter_set_zebra(vty, argv[3]->arg, argv[4]->arg, AFI_L2VPN, - argv[5]->arg, 0, 0); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + char *mac = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "X:X:X:X:X:X", &idx); + if (idx) + mac = argv[idx]->arg; + + return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN, + mac, 0, 0); } DEFUN (mac_access_list_any, mac_access_list_any_cmd, - "mac access-list WORD <deny|permit> any", + "mac access-list WORD [seq (1-4294967295)] <deny|permit> any", "Add a mac access-list\n" "Add an access list entry\n" "MAC zebra access-list name\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "MAC address to match. e.g. 00:01:00:01:00:01\n") { - return filter_set_zebra(vty, argv[2]->arg, argv[3]->arg, AFI_L2VPN, + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN, "00:00:00:00:00:00", 0, 1); } DEFUN (no_mac_access_list_any, no_mac_access_list_any_cmd, - "no mac access-list WORD <deny|permit> any", + "no mac access-list WORD [seq (1-4294967295)] <deny|permit> any", NO_STR "Remove a mac access-list\n" "Remove an access list entry\n" "MAC zebra access-list name\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "MAC address to match. e.g. 00:01:00:01:00:01\n") { - return filter_set_zebra(vty, argv[3]->arg, argv[4]->arg, AFI_L2VPN, + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN, "00:00:00:00:00:00", 0, 0); } DEFUN (access_list_exact, access_list_exact_cmd, - "access-list WORD <deny|permit> A.B.C.D/M [exact-match]", + "access-list WORD [seq (1-4294967295)] <deny|permit> A.B.C.D/M [exact-match]", "Add an access list entry\n" "IP zebra access-list name\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Prefix to match. e.g. 10.0.0.0/8\n" @@ -1366,41 +2032,71 @@ DEFUN (access_list_exact, { int idx = 0; int exact = 0; - int idx_word = 1; - int idx_permit_deny = 2; - int idx_ipv4_prefixlen = 3; - idx = idx_ipv4_prefixlen; - + char *seq = NULL; + char *permit_deny = NULL; + char *prefix = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D/M", &idx); + if (idx) + prefix = argv[idx]->arg; + + idx = 0; if (argv_find(argv, argc, "exact-match", &idx)) exact = 1; - return filter_set_zebra(vty, argv[idx_word]->arg, - argv[idx_permit_deny]->arg, AFI_IP, - argv[idx_ipv4_prefixlen]->arg, exact, 1); + return filter_set_zebra(vty, argv[1]->arg, seq, permit_deny, + AFI_IP, prefix, exact, 1); } DEFUN (access_list_any, access_list_any_cmd, - "access-list WORD <deny|permit> any", + "access-list WORD [seq (1-4294967295)] <deny|permit> any", "Add an access list entry\n" "IP zebra access-list name\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Prefix to match. e.g. 10.0.0.0/8\n") { int idx_word = 1; - int idx_permit_deny = 2; - return filter_set_zebra(vty, argv[idx_word]->arg, - argv[idx_permit_deny]->arg, AFI_IP, "0.0.0.0/0", - 0, 1); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny, + AFI_IP, "0.0.0.0/0", 0, 1); } DEFUN (no_access_list_exact, no_access_list_exact_cmd, - "no access-list WORD <deny|permit> A.B.C.D/M [exact-match]", + "no access-list WORD [seq (1-4294967295)] <deny|permit> A.B.C.D/M [exact-match]", NO_STR "Add an access list entry\n" "IP zebra access-list name\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Prefix to match. e.g. 10.0.0.0/8\n" @@ -1408,34 +2104,62 @@ DEFUN (no_access_list_exact, { int idx = 0; int exact = 0; - int idx_word = 2; - int idx_permit_deny = 3; - int idx_ipv4_prefixlen = 4; - idx = idx_ipv4_prefixlen; - + char *seq = NULL; + char *permit_deny = NULL; + char *prefix = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "A.B.C.D/M", &idx); + if (idx) + prefix = argv[idx]->arg; + + idx = 0; if (argv_find(argv, argc, "exact-match", &idx)) exact = 1; - return filter_set_zebra(vty, argv[idx_word]->arg, - argv[idx_permit_deny]->arg, AFI_IP, - argv[idx_ipv4_prefixlen]->arg, exact, 0); + return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, + AFI_IP, prefix, exact, 0); } DEFUN (no_access_list_any, no_access_list_any_cmd, - "no access-list WORD <deny|permit> any", + "no access-list WORD [seq (1-4294967295)] <deny|permit> any", NO_STR "Add an access list entry\n" "IP zebra access-list name\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Prefix to match. e.g. 10.0.0.0/8\n") { - int idx_word = 2; - int idx_permit_deny = 3; - return filter_set_zebra(vty, argv[idx_word]->arg, - argv[idx_permit_deny]->arg, AFI_IP, "0.0.0.0/0", - 0, 0); + int idx_word = 1; + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny, + AFI_IP, "0.0.0.0/0", 0, 0); } DEFUN (no_access_list_all, @@ -1536,10 +2260,12 @@ DEFUN (no_access_list_remark_comment, DEFUN (ipv6_access_list_exact, ipv6_access_list_exact_cmd, - "ipv6 access-list WORD <deny|permit> X:X::X:X/M [exact-match]", + "ipv6 access-list WORD [seq (1-4294967295)] <deny|permit> X:X::X:X/M [exact-match]", IPV6_STR "Add an access list entry\n" "IPv6 zebra access-list\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix\n" @@ -1548,41 +2274,73 @@ DEFUN (ipv6_access_list_exact, int idx = 0; int exact = 0; int idx_word = 2; - int idx_allow = 3; - int idx_addr = 4; - idx = idx_addr; - + char *seq = NULL; + char *permit_deny = NULL; + char *prefix = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "X:X::X:X/M", &idx); + if (idx) + prefix = argv[idx]->arg; + + idx = 0; if (argv_find(argv, argc, "exact-match", &idx)) exact = 1; - return filter_set_zebra(vty, argv[idx_word]->arg, argv[idx_allow]->text, - AFI_IP6, argv[idx_addr]->arg, exact, 1); + return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny, + AFI_IP6, prefix, exact, 1); } DEFUN (ipv6_access_list_any, ipv6_access_list_any_cmd, - "ipv6 access-list WORD <deny|permit> any", + "ipv6 access-list WORD [seq (1-4294967295)] <deny|permit> any", IPV6_STR "Add an access list entry\n" "IPv6 zebra access-list\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any prefixi to match\n") { int idx_word = 2; - int idx_permit_deny = 3; - return filter_set_zebra(vty, argv[idx_word]->arg, - argv[idx_permit_deny]->arg, AFI_IP6, "::/0", 0, - 1); + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny, + AFI_IP6, "::/0", 0, 1); } DEFUN (no_ipv6_access_list_exact, no_ipv6_access_list_exact_cmd, - "no ipv6 access-list WORD <deny|permit> X:X::X:X/M [exact-match]", + "no ipv6 access-list WORD [seq (1-4294967295)] <deny|permit> X:X::X:X/M [exact-match]", NO_STR IPV6_STR "Add an access list entry\n" "IPv6 zebra access-list\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Prefix to match. e.g. 3ffe:506::/32\n" @@ -1590,35 +2348,64 @@ DEFUN (no_ipv6_access_list_exact, { int idx = 0; int exact = 0; - int idx_word = 3; - int idx_permit_deny = 4; - int idx_ipv6_prefixlen = 5; - idx = idx_ipv6_prefixlen; - + int idx_word = 2; + char *seq = NULL; + char *permit_deny = NULL; + char *prefix = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "X:X::X:X/M", &idx); + if (idx) + prefix = argv[idx]->arg; + + idx = 0; if (argv_find(argv, argc, "exact-match", &idx)) exact = 1; - return filter_set_zebra(vty, argv[idx_word]->arg, - argv[idx_permit_deny]->arg, AFI_IP6, - argv[idx_ipv6_prefixlen]->arg, exact, 0); + return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny, + AFI_IP6, prefix, exact, 0); } DEFUN (no_ipv6_access_list_any, no_ipv6_access_list_any_cmd, - "no ipv6 access-list WORD <deny|permit> any", + "no ipv6 access-list WORD [seq (1-4294967295)] <deny|permit> any", NO_STR IPV6_STR "Add an access list entry\n" "IPv6 zebra access-list\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any prefixi to match\n") { - int idx_word = 3; - int idx_permit_deny = 4; - return filter_set_zebra(vty, argv[idx_word]->arg, - argv[idx_permit_deny]->arg, AFI_IP6, "::/0", 0, - 0); + int idx_word = 2; + int idx = 0; + char *seq = NULL; + char *permit_deny = NULL; + + argv_find(argv, argc, "(1-4294967295)", &idx); + if (idx) + seq = argv[idx]->arg; + + idx = 0; + argv_find(argv, argc, "permit", &idx); + argv_find(argv, argc, "deny", &idx); + if (idx) + permit_deny = argv[idx]->arg; + + return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny, + AFI_IP6, "::/0", 0, 0); } @@ -1748,7 +2535,8 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi) write = 0; } - vty_out(vty, " %s%s", filter_type_str(mfilter), + vty_out(vty, " seq %" PRId64, mfilter->seq); + vty_out(vty, " %s%s", filter_type_str(mfilter), mfilter->type == FILTER_DENY ? " " : ""); if (!mfilter->cisco) @@ -1795,7 +2583,8 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi) write = 0; } - vty_out(vty, " %s%s", filter_type_str(mfilter), + vty_out(vty, " seq %" PRId64, mfilter->seq); + vty_out(vty, " %s%s", filter_type_str(mfilter), mfilter->type == FILTER_DENY ? " " : ""); if (!mfilter->cisco) @@ -1978,11 +2767,12 @@ static int config_write_access(struct vty *vty, afi_t afi) } for (mfilter = access->head; mfilter; mfilter = mfilter->next) { - vty_out(vty, "%saccess-list %s %s", + vty_out(vty, "%saccess-list %s seq %" PRId64 " %s", (afi == AFI_IP) ? ("") : ((afi == AFI_IP6) ? ("ipv6 ") : ("mac ")), - access->name, filter_type_str(mfilter)); + access->name, mfilter->seq, + filter_type_str(mfilter)); if (mfilter->cisco) config_write_access_cisco(vty, mfilter); @@ -2004,11 +2794,12 @@ static int config_write_access(struct vty *vty, afi_t afi) } for (mfilter = access->head; mfilter; mfilter = mfilter->next) { - vty_out(vty, "%saccess-list %s %s", + vty_out(vty, "%saccess-list %s seq %" PRId64 " %s", (afi == AFI_IP) ? ("") : ((afi == AFI_IP6) ? ("ipv6 ") : ("mac ")), - access->name, filter_type_str(mfilter)); + access->name, mfilter->seq, + filter_type_str(mfilter)); if (mfilter->cisco) config_write_access_cisco(vty, mfilter); diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c index e588571c01..bdb6c2a397 100644 --- a/lib/frr_pthread.c +++ b/lib/frr_pthread.c @@ -133,18 +133,29 @@ int frr_pthread_set_name(struct frr_pthread *fpt) return ret; } +static void *frr_pthread_inner(void *arg) +{ + struct frr_pthread *fpt = arg; + + rcu_thread_start(fpt->rcu_thread); + return fpt->attr.start(fpt); +} + int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr) { int ret; - ret = pthread_create(&fpt->thread, attr, fpt->attr.start, fpt); + fpt->rcu_thread = rcu_thread_prepare(); + ret = pthread_create(&fpt->thread, attr, frr_pthread_inner, fpt); /* * 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) + if (ret < 0) { + rcu_thread_unprepare(fpt->rcu_thread); memset(&fpt->thread, 0x00, sizeof(fpt->thread)); + } return ret; } diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h index 3afe7ba966..6096a50370 100644 --- a/lib/frr_pthread.h +++ b/lib/frr_pthread.h @@ -23,6 +23,7 @@ #include <pthread.h> #include "frratomic.h" #include "memory.h" +#include "frrcu.h" #include "thread.h" #ifdef __cplusplus @@ -50,6 +51,8 @@ struct frr_pthread { /* pthread id */ pthread_t thread; + struct rcu_thread *rcu_thread; + /* thread master for this pthread's thread.c event loop */ struct thread_master *master; diff --git a/lib/frrcu.c b/lib/frrcu.c new file mode 100644 index 0000000000..7e6475b648 --- /dev/null +++ b/lib/frrcu.c @@ -0,0 +1,527 @@ +/* + * Copyright (c) 2017-19 David Lamparter, for NetDEF, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* implementation notes: this is an epoch-based RCU implementation. rcu_seq + * (global variable) counts the current epoch. Threads hold a specific epoch + * in rcu_read_lock(). This is the oldest epoch a thread might be accessing + * data from. + * + * The rcu_seq global is only pushed forward on rcu_read_lock() and + * rcu_read_unlock() calls. This makes things a tad more efficient since + * those are the only places it matters: + * - on rcu_read_lock, we don't want to hold an old epoch pointlessly + * - on rcu_read_unlock, we want to make sure we're not stuck on an old epoch + * when heading into a long idle period where no thread holds RCU + * + * rcu_thread structures themselves are RCU-free'd. + * + * rcu_head structures are the most iffy; normally for an ATOMLIST we would + * need to make sure we use rcu_free or pthread_rwlock to deallocate old items + * to prevent ABA or use-after-free problems. However, our ATOMLIST code + * guarantees that if the list remains non-empty in all cases, we only need + * the "last" pointer to do an "add_tail()", i.e. we can't run into ABA/UAF + * issues - but we do need to keep at least 1 item on the list. + * + * (Search the atomlist code for all uses of "last") + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#ifdef HAVE_PTHREAD_NP_H +#include <pthread_np.h> +#endif +#include <string.h> +#include <unistd.h> +#include <signal.h> + +#include "frrcu.h" +#include "seqlock.h" +#include "atomlist.h" + +DEFINE_MTYPE_STATIC(LIB, RCU_THREAD, "RCU thread") +DEFINE_MTYPE_STATIC(LIB, RCU_NEXT, "RCU sequence barrier") + +DECLARE_ATOMLIST(rcu_heads, struct rcu_head, head) + +PREDECL_ATOMLIST(rcu_threads) +struct rcu_thread { + struct rcu_threads_item head; + + struct rcu_head rcu_head; + + struct seqlock rcu; + + /* only accessed by thread itself, not atomic */ + unsigned depth; +}; +DECLARE_ATOMLIST(rcu_threads, struct rcu_thread, head) + +static const struct rcu_action rcua_next = { .type = RCUA_NEXT }; +static const struct rcu_action rcua_end = { .type = RCUA_END }; +static const struct rcu_action rcua_close = { .type = RCUA_CLOSE }; + +struct rcu_next { + struct rcu_head head_free; + struct rcu_head head_next; +}; + +#define rcu_free_internal(mtype, ptr, field) \ + do { \ + typeof(ptr) _ptr = (ptr); \ + struct rcu_head *_rcu_head = &_ptr->field; \ + static const struct rcu_action _rcu_action = { \ + .type = RCUA_FREE, \ + .u.free = { \ + .mt = mtype, \ + .offset = offsetof(typeof(*_ptr), field), \ + }, \ + }; \ + _rcu_head->action = &_rcu_action; \ + rcu_heads_add_tail(&rcu_heads, _rcu_head); \ + } while (0) + +/* primary global RCU position */ +static struct seqlock rcu_seq; +/* this is set to rcu_seq whenever something is added on the RCU queue. + * rcu_read_lock() and rcu_read_unlock() will then bump rcu_seq up one step. + */ +static _Atomic seqlock_val_t rcu_dirty; + +static struct rcu_threads_head rcu_threads; +static struct rcu_heads_head rcu_heads; + +/* main thread & RCU sweeper have pre-setup rcu_thread structures. The + * reasons are different: + * + * - rcu_thread_main is there because the main thread isn't started like + * other threads, it's implicitly created when the program is started. So + * rcu_thread_main matches up implicitly. + * + * - rcu_thread_rcu isn't actually put on the rcu_threads list (makes no + * sense really), it only exists so we can call RCU-using functions from + * the RCU thread without special handling in rcu_read_lock/unlock. + */ +static struct rcu_thread rcu_thread_main; +static struct rcu_thread rcu_thread_rcu; + +static pthread_t rcu_pthread; +static pthread_key_t rcu_thread_key; +static bool rcu_active; + +static void rcu_start(void); +static void rcu_bump(void); + +/* + * preinitialization for main thread + */ +static void rcu_thread_end(void *rcu_thread); + +static void rcu_preinit(void) __attribute__((constructor)); +static void rcu_preinit(void) +{ + struct rcu_thread *rt; + + rt = &rcu_thread_main; + rt->depth = 1; + seqlock_init(&rt->rcu); + seqlock_acquire_val(&rt->rcu, SEQLOCK_STARTVAL); + + pthread_key_create(&rcu_thread_key, rcu_thread_end); + pthread_setspecific(rcu_thread_key, rt); + + rcu_threads_add_tail(&rcu_threads, rt); + + /* RCU sweeper's rcu_thread is a dummy, NOT added to rcu_threads */ + rt = &rcu_thread_rcu; + rt->depth = 1; + + seqlock_init(&rcu_seq); + seqlock_acquire_val(&rcu_seq, SEQLOCK_STARTVAL); +} + +static struct rcu_thread *rcu_self(void) +{ + return (struct rcu_thread *)pthread_getspecific(rcu_thread_key); +} + +/* + * thread management (for the non-main thread) + */ +struct rcu_thread *rcu_thread_prepare(void) +{ + struct rcu_thread *rt, *cur; + + rcu_assert_read_locked(); + + if (!rcu_active) + rcu_start(); + + cur = rcu_self(); + assert(cur->depth); + + /* new thread always starts with rcu_read_lock held at depth 1, and + * holding the same epoch as the parent (this makes it possible to + * use RCU for things passed into the thread through its arg) + */ + rt = XCALLOC(MTYPE_RCU_THREAD, sizeof(*rt)); + rt->depth = 1; + + seqlock_init(&rt->rcu); + seqlock_acquire(&rt->rcu, &cur->rcu); + + rcu_threads_add_tail(&rcu_threads, rt); + + return rt; +} + +void rcu_thread_start(struct rcu_thread *rt) +{ + pthread_setspecific(rcu_thread_key, rt); +} + +void rcu_thread_unprepare(struct rcu_thread *rt) +{ + if (rt == &rcu_thread_rcu) + return; + + rt->depth = 1; + seqlock_acquire(&rt->rcu, &rcu_seq); + + rcu_bump(); + if (rt != &rcu_thread_main) + /* this free() happens after seqlock_release() below */ + rcu_free_internal(MTYPE_RCU_THREAD, rt, rcu_head); + + rcu_threads_del(&rcu_threads, rt); + seqlock_release(&rt->rcu); +} + +static void rcu_thread_end(void *rtvoid) +{ + struct rcu_thread *rt = rtvoid; + rcu_thread_unprepare(rt); +} + +/* + * main RCU control aspects + */ + +static void rcu_bump(void) +{ + struct rcu_next *rn; + + rn = XMALLOC(MTYPE_RCU_NEXT, sizeof(*rn)); + + /* note: each RCUA_NEXT item corresponds to exactly one seqno bump. + * This means we don't need to communicate which seqno is which + * RCUA_NEXT, since we really don't care. + */ + + /* + * Important race condition: while rcu_heads_add_tail is executing, + * there is an intermediate point where the rcu_heads "last" pointer + * already points to rn->head_next, but rn->head_next isn't added to + * the list yet. That means any other "add_tail" calls append to this + * item, which isn't fully on the list yet. Freeze this thread at + * that point and look at another thread doing a rcu_bump. It adds + * these two items and then does a seqlock_bump. But the rcu_heads + * list is still "interrupted" and there's no RCUA_NEXT on the list + * yet (from either the frozen thread or the second thread). So + * rcu_main() might actually hit the end of the list at the + * "interrupt". + * + * This situation is prevented by requiring that rcu_read_lock is held + * for any calls to rcu_bump, since if we're holding the current RCU + * epoch, that means rcu_main can't be chewing on rcu_heads and hit + * that interruption point. Only by the time the thread has continued + * to rcu_read_unlock() - and therefore completed the add_tail - the + * RCU sweeper gobbles up the epoch and can be sure to find at least + * the RCUA_NEXT and RCUA_FREE items on rcu_heads. + */ + rn->head_next.action = &rcua_next; + rcu_heads_add_tail(&rcu_heads, &rn->head_next); + + /* free rn that we allocated above. + * + * This is INTENTIONALLY not built into the RCUA_NEXT action. This + * ensures that after the action above is popped off the queue, there + * is still at least 1 item on the RCU queue. This means we never + * delete the last item, which is extremely important since it keeps + * the atomlist ->last pointer alive and well. + * + * If we were to "run dry" on the RCU queue, add_tail may run into the + * "last item is being deleted - start over" case, and then we may end + * up accessing old RCU queue items that are already free'd. + */ + rcu_free_internal(MTYPE_RCU_NEXT, rn, head_free); + + /* Only allow the RCU sweeper to run after these 2 items are queued. + * + * If another thread enqueues some RCU action in the intermediate + * window here, nothing bad happens - the queued action is associated + * with a larger seq# than strictly necessary. Thus, it might get + * executed a bit later, but that's not a problem. + * + * If another thread acquires the read lock in this window, it holds + * the previous epoch, but its RCU queue actions will be in the next + * epoch. This isn't a problem either, just a tad inefficient. + */ + seqlock_bump(&rcu_seq); +} + +static void rcu_bump_maybe(void) +{ + seqlock_val_t dirty; + + dirty = atomic_load_explicit(&rcu_dirty, memory_order_relaxed); + /* no problem if we race here and multiple threads bump rcu_seq; + * bumping too much causes no issues while not bumping enough will + * result in delayed cleanup + */ + if (dirty == seqlock_cur(&rcu_seq)) + rcu_bump(); +} + +void rcu_read_lock(void) +{ + struct rcu_thread *rt = rcu_self(); + + assert(rt); + if (rt->depth++ > 0) + return; + + seqlock_acquire(&rt->rcu, &rcu_seq); + /* need to hold RCU for bump ... */ + rcu_bump_maybe(); + /* ... but no point in holding the old epoch if we just bumped */ + seqlock_acquire(&rt->rcu, &rcu_seq); +} + +void rcu_read_unlock(void) +{ + struct rcu_thread *rt = rcu_self(); + + assert(rt && rt->depth); + if (--rt->depth > 0) + return; + rcu_bump_maybe(); + seqlock_release(&rt->rcu); +} + +void rcu_assert_read_locked(void) +{ + struct rcu_thread *rt = rcu_self(); + assert(rt && rt->depth && seqlock_held(&rt->rcu)); +} + +void rcu_assert_read_unlocked(void) +{ + struct rcu_thread *rt = rcu_self(); + assert(rt && !rt->depth && !seqlock_held(&rt->rcu)); +} + +/* + * RCU resource-release thread + */ + +static void *rcu_main(void *arg); + +static void rcu_start(void) +{ + /* ensure we never handle signals on the RCU thread by blocking + * everything here (new thread inherits signal mask) + */ + sigset_t oldsigs, blocksigs; + + sigfillset(&blocksigs); + pthread_sigmask(SIG_BLOCK, &blocksigs, &oldsigs); + + rcu_active = true; + + assert(!pthread_create(&rcu_pthread, NULL, rcu_main, NULL)); + + pthread_sigmask(SIG_SETMASK, &oldsigs, NULL); + +#ifdef HAVE_PTHREAD_SETNAME_NP +# ifdef GNU_LINUX + pthread_setname_np(rcu_pthread, "RCU sweeper"); +# elif defined(__NetBSD__) + pthread_setname_np(rcu_pthread, "RCU sweeper", NULL); +# endif +#elif defined(HAVE_PTHREAD_SET_NAME_NP) + pthread_set_name_np(rcu_pthread, "RCU sweeper"); +#endif +} + +static void rcu_do(struct rcu_head *rh) +{ + struct rcu_head_close *rhc; + void *p; + + switch (rh->action->type) { + case RCUA_FREE: + p = (char *)rh - rh->action->u.free.offset; + if (rh->action->u.free.mt) + qfree(rh->action->u.free.mt, p); + else + free(p); + break; + case RCUA_CLOSE: + rhc = container_of(rh, struct rcu_head_close, + rcu_head); + close(rhc->fd); + break; + case RCUA_CALL: + p = (char *)rh - rh->action->u.call.offset; + rh->action->u.call.fptr(p); + break; + + case RCUA_INVALID: + case RCUA_NEXT: + case RCUA_END: + default: + assert(0); + } +} + +static void rcu_watchdog(struct rcu_thread *rt) +{ +#if 0 + /* future work: print a backtrace for the thread that's holding up + * RCU. The only (good) way of doing that is to send a signal to the + * other thread, save away the backtrace in the signal handler, and + * block here until the signal is done processing. + * + * Just haven't implemented that yet. + */ + fprintf(stderr, "RCU watchdog %p\n", rt); +#endif +} + +static void *rcu_main(void *arg) +{ + struct rcu_thread *rt; + struct rcu_head *rh = NULL; + bool end = false; + struct timespec maxwait; + + seqlock_val_t rcuval = SEQLOCK_STARTVAL; + + pthread_setspecific(rcu_thread_key, &rcu_thread_rcu); + + while (!end) { + seqlock_wait(&rcu_seq, rcuval); + + /* RCU watchdog timeout, TODO: configurable value */ + clock_gettime(CLOCK_MONOTONIC, &maxwait); + maxwait.tv_nsec += 100 * 1000 * 1000; + if (maxwait.tv_nsec >= 1000000000) { + maxwait.tv_sec++; + maxwait.tv_nsec -= 1000000000; + } + + frr_each (rcu_threads, &rcu_threads, rt) + if (!seqlock_timedwait(&rt->rcu, rcuval, &maxwait)) { + rcu_watchdog(rt); + seqlock_wait(&rt->rcu, rcuval); + } + + while ((rh = rcu_heads_pop(&rcu_heads))) { + if (rh->action->type == RCUA_NEXT) + break; + else if (rh->action->type == RCUA_END) + end = true; + else + rcu_do(rh); + } + + rcuval += SEQLOCK_INCR; + } + + /* rcu_shutdown can only be called singlethreaded, and it does a + * pthread_join, so it should be impossible that anything ended up + * on the queue after RCUA_END + */ +#if 1 + assert(!rcu_heads_first(&rcu_heads)); +#else + while ((rh = rcu_heads_pop(&rcu_heads))) + if (rh->action->type >= RCUA_FREE) + rcu_do(rh); +#endif + return NULL; +} + +void rcu_shutdown(void) +{ + static struct rcu_head rcu_head_end; + struct rcu_thread *rt = rcu_self(); + void *retval; + + if (!rcu_active) + return; + + rcu_assert_read_locked(); + assert(rcu_threads_count(&rcu_threads) == 1); + + rcu_enqueue(&rcu_head_end, &rcua_end); + + rt->depth = 0; + seqlock_release(&rt->rcu); + seqlock_release(&rcu_seq); + rcu_active = false; + + /* clearing rcu_active is before pthread_join in case we hang in + * pthread_join & get a SIGTERM or something - in that case, just + * ignore the maybe-still-running RCU thread + */ + if (pthread_join(rcu_pthread, &retval) == 0) { + seqlock_acquire_val(&rcu_seq, SEQLOCK_STARTVAL); + seqlock_acquire_val(&rt->rcu, SEQLOCK_STARTVAL); + rt->depth = 1; + } +} + +/* + * RCU'd free functions + */ + +void rcu_enqueue(struct rcu_head *rh, const struct rcu_action *action) +{ + /* refer to rcu_bump() for why we need to hold RCU when adding items + * to rcu_heads + */ + rcu_assert_read_locked(); + + rh->action = action; + + if (!rcu_active) { + rcu_do(rh); + return; + } + rcu_heads_add_tail(&rcu_heads, rh); + atomic_store_explicit(&rcu_dirty, seqlock_cur(&rcu_seq), + memory_order_relaxed); +} + +void rcu_close(struct rcu_head_close *rhc, int fd) +{ + rhc->fd = fd; + rcu_enqueue(&rhc->rcu_head, &rcua_close); +} diff --git a/lib/frrcu.h b/lib/frrcu.h new file mode 100644 index 0000000000..8f789303cc --- /dev/null +++ b/lib/frrcu.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2017-19 David Lamparter, for NetDEF, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _FRRCU_H +#define _FRRCU_H + +#include "memory.h" +#include "atomlist.h" +#include "seqlock.h" + +/* quick RCU primer: + * There's a global sequence counter. Whenever a thread does a + * rcu_read_lock(), it is marked as holding the current sequence counter. + * When something is cleaned with RCU, the global sequence counter is + * increased and the item is queued for cleanup - *after* all threads are + * at a more recent sequence counter (or no sequence counter / unheld). + * + * So, by delaying resource cleanup, RCU ensures that things don't go away + * while another thread may hold a (stale) reference. + * + * Note that even if a thread is in rcu_read_lock(), it is invalid for that + * thread to access bits after rcu_free() & co on them. This is a design + * choice to allow no-op'ing out the entire RCU mechanism if we're running + * singlethreaded. (Also allows some optimization on the counter bumping.) + * + * differences from Linux Kernel RCU: + * - there's no rcu_synchronize(), if you really need to defer something + * use rcu_call() (and double check it's really necessary) + * - rcu_dereference() and rcu_assign_pointer() don't exist, use atomic_* + * instead (ATOM* list structures do the right thing) + */ + +/* opaque */ +struct rcu_thread; + +/* called before new thread creation, sets up rcu thread info for new thread + * before it actually exits. This ensures possible RCU references are held + * for thread startup. + * + * return value must be passed into the new thread's call to rcu_thread_start() + */ +extern struct rcu_thread *rcu_thread_prepare(void); + +/* cleanup in case pthread_create() fails */ +extern void rcu_thread_unprepare(struct rcu_thread *rcu_thread); + +/* called early in the new thread, with the return value from the above. + * NB: new thread is initially in RCU-held state! (at depth 1) + * + * TBD: maybe inherit RCU state from rcu_thread_prepare()? + */ +extern void rcu_thread_start(struct rcu_thread *rcu_thread); + +/* thread exit is handled through pthread_key_create's destructor function */ + +/* global RCU shutdown - must be called with only 1 active thread left. waits + * until remaining RCU actions are done & RCU thread has exited. + * + * This is mostly here to get a clean exit without memleaks. + */ +extern void rcu_shutdown(void); + +/* enter / exit RCU-held state. counter-based, so can be called nested. */ +extern void rcu_read_lock(void); +extern void rcu_read_unlock(void); + +/* for debugging / safety checks */ +extern void rcu_assert_read_locked(void); +extern void rcu_assert_read_unlocked(void); + +enum rcu_action_type { + RCUA_INVALID = 0, + /* used internally by the RCU code, shouldn't ever show up outside */ + RCUA_NEXT, + RCUA_END, + /* normal RCU actions, for outside use */ + RCUA_FREE, + RCUA_CLOSE, + RCUA_CALL, +}; + +/* since rcu_head is intended to be embedded into structs which may exist + * with lots of copies, rcu_head is shrunk down to its absolute minimum - + * the atomlist pointer + a pointer to this action struct. + */ +struct rcu_action { + enum rcu_action_type type; + + union { + struct { + struct memtype *mt; + ptrdiff_t offset; + } free; + + struct { + void (*fptr)(void *arg); + ptrdiff_t offset; + } call; + } u; +}; + +/* RCU cleanup function queue item */ +PREDECL_ATOMLIST(rcu_heads) +struct rcu_head { + struct rcu_heads_item head; + const struct rcu_action *action; +}; + +/* special RCU head for delayed fd-close */ +struct rcu_head_close { + struct rcu_head rcu_head; + int fd; +}; + +/* enqueue RCU action - use the macros below to get the rcu_action set up */ +extern void rcu_enqueue(struct rcu_head *head, const struct rcu_action *action); + +/* RCU free() and file close() operations. + * + * freed memory / closed fds become _immediately_ unavailable to the calling + * thread, but will remain available for other threads until they have passed + * into RCU-released state. + */ + +/* may be called with NULL mt to do non-MTYPE free() */ +#define rcu_free(mtype, ptr, field) \ + do { \ + typeof(ptr) _ptr = (ptr); \ + struct rcu_head *_rcu_head = &_ptr->field; \ + static const struct rcu_action _rcu_action = { \ + .type = RCUA_FREE, \ + .u.free = { \ + .mt = mtype, \ + .offset = offsetof(typeof(*_ptr), field), \ + }, \ + }; \ + rcu_enqueue(_rcu_head, &_rcu_action); \ + } while (0) + +/* use this sparingly, it runs on (and blocks) the RCU thread */ +#define rcu_call(func, ptr, field) \ + do { \ + typeof(ptr) _ptr = (ptr); \ + void (*fptype)(typeof(ptr)); \ + struct rcu_head *_rcu_head = &_ptr->field; \ + static const struct rcu_action _rcu_action = { \ + .type = RCUA_CALL, \ + .u.call = { \ + .fptr = (void *)func, \ + .offset = offsetof(typeof(*_ptr), field), \ + }, \ + }; \ + (void)(_fptype = func); \ + rcu_enqueue(_rcu_head, &_rcu_action); \ + } while (0) + +extern void rcu_close(struct rcu_head_close *head, int fd); + +#endif /* _FRRCU_H */ diff --git a/lib/frrstr.c b/lib/frrstr.c index c575c0b568..8a72a35af0 100644 --- a/lib/frrstr.c +++ b/lib/frrstr.c @@ -209,7 +209,7 @@ bool frrstr_endswith(const char *str, const char *suffix) int all_digit(const char *str) { for (; *str != '\0'; str++) - if (!isdigit((int)*str)) + if (!isdigit((unsigned char)*str)) return 0; return 1; } @@ -132,18 +132,26 @@ static int if_cmp_index_func(const struct interface *ifp1, } /* Create new interface structure. */ -struct interface *if_create(const char *name, vrf_id_t vrf_id) +static struct interface *if_create_backend(const char *name, ifindex_t ifindex, + vrf_id_t vrf_id) { struct vrf *vrf = vrf_get(vrf_id, NULL); struct interface *ifp; ifp = XCALLOC(MTYPE_IF, sizeof(struct interface)); - ifp->ifindex = IFINDEX_INTERNAL; - - assert(name); - strlcpy(ifp->name, name, sizeof(ifp->name)); ifp->vrf_id = vrf_id; - IFNAME_RB_INSERT(vrf, ifp); + + if (name) { + strlcpy(ifp->name, name, sizeof(ifp->name)); + IFNAME_RB_INSERT(vrf, ifp); + } else + ifp->name[0] = '\0'; + + if (ifindex != IFINDEX_INTERNAL) + if_set_index(ifp, ifindex); + else + ifp->ifindex = ifindex; /* doesn't add it to the list */ + ifp->connected = list_new(); ifp->connected->del = (void (*)(void *))connected_free; @@ -158,6 +166,16 @@ struct interface *if_create(const char *name, vrf_id_t vrf_id) return ifp; } +struct interface *if_create(const char *name, vrf_id_t vrf_id) +{ + return if_create_backend(name, IFINDEX_INTERNAL, vrf_id); +} + +struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id) +{ + return if_create_backend(NULL, ifindex, vrf_id); +} + /* Create new interface structure. */ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id) { @@ -302,6 +320,23 @@ struct interface *if_lookup_by_name_all_vrf(const char *name) return NULL; } +struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex) +{ + struct vrf *vrf; + struct interface *ifp; + + if (ifindex == IFINDEX_INTERNAL) + return NULL; + + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { + ifp = if_lookup_by_index(ifindex, vrf->vrf_id); + if (ifp) + return ifp; + } + + return NULL; +} + /* Lookup interface by IPv4 address. */ struct interface *if_lookup_exact_address(void *src, int family, vrf_id_t vrf_id) @@ -447,6 +482,34 @@ struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id) return NULL; } +struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id) +{ + struct interface *ifp; + + switch (vrf_get_backend()) { + case VRF_BACKEND_UNKNOWN: + case VRF_BACKEND_NETNS: + ifp = if_lookup_by_index(ifindex, vrf_id); + if (ifp) + return ifp; + return if_create_ifindex(ifindex, vrf_id); + case VRF_BACKEND_VRF_LITE: + ifp = if_lookup_by_index_all_vrf(ifindex); + if (ifp) { + if (ifp->vrf_id == vrf_id) + return ifp; + /* If it came from the kernel or by way of zclient, + * believe it and update the ifp accordingly. + */ + if_update_to_new_vrf(ifp, vrf_id); + return ifp; + } + return if_create_ifindex(ifindex, vrf_id); + } + + return NULL; +} + void if_set_index(struct interface *ifp, ifindex_t ifindex) { struct vrf *vrf; @@ -478,7 +478,9 @@ extern int if_cmp_name_func(const char *p1, const char *p2); */ extern void if_update_to_new_vrf(struct interface *, vrf_id_t vrf_id); extern struct interface *if_create(const char *name, vrf_id_t vrf_id); +extern struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id); extern struct interface *if_lookup_by_index(ifindex_t, vrf_id_t vrf_id); +extern struct interface *if_lookup_by_index_all_vrf(ifindex_t); extern struct interface *if_lookup_exact_address(void *matchaddr, int family, vrf_id_t vrf_id); extern struct connected *if_lookup_address(void *matchaddr, int family, @@ -493,6 +495,7 @@ size_t if_lookup_by_hwaddr(const uint8_t *hw_addr, size_t addrsz, extern struct interface *if_lookup_by_name_all_vrf(const char *ifname); extern struct interface *if_lookup_by_name(const char *ifname, vrf_id_t vrf_id); extern struct interface *if_get_by_name(const char *ifname, vrf_id_t vrf_id); +extern struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id); extern void if_set_index(struct interface *ifp, ifindex_t ifindex); /* Delete the interface, but do not free the structure, and leave it in the diff --git a/lib/libfrr.c b/lib/libfrr.c index 3294a61295..4301dc20ad 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -41,6 +41,7 @@ #include "northbound_cli.h" #include "northbound_db.h" #include "debug.h" +#include "frrcu.h" DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm)) DEFINE_KOOH(frr_early_fini, (), ()) @@ -409,7 +410,7 @@ static int frr_opt(int opt) } if (di->zpathspace) fprintf(stderr, - "-N option overriden by -z for zebra named socket path\n"); + "-N option overridden by -z for zebra named socket path\n"); if (strchr(optarg, '/') || strchr(optarg, '.')) { fprintf(stderr, @@ -681,6 +682,7 @@ struct thread_master *frr_init(void) log_filter_cmd_init(); log_ref_init(); + log_ref_vty_init(); lib_error_init(); yang_init(); @@ -1080,6 +1082,7 @@ void frr_fini(void) master = NULL; closezlog(); /* frrmod_init -> nothing needed / hooks */ + rcu_shutdown(); if (!debug_memstats_at_exit) return; @@ -387,10 +387,8 @@ void vzlog(int priority, const char *format, va_list args) /* If it doesn't match on a filter, do nothing with the debug log */ if ((priority == LOG_DEBUG) && zlog_filter_count - && vzlog_filter(zl, &tsctl, proto_str, priority, msg)) { - pthread_mutex_unlock(&loglock); + && vzlog_filter(zl, &tsctl, proto_str, priority, msg)) goto out; - } /* call external hook */ hook_call(zebra_ext_log, priority, format, args); @@ -561,9 +559,7 @@ static void crash_write(struct fbuf *fb, char *msgstart) void zlog_signal(int signo, const char *action, void *siginfo_v, void *program_counter) { -#ifdef SA_SIGINFO siginfo_t *siginfo = siginfo_v; -#endif time_t now; char buf[sizeof("DEFAULT: Received signal S at T (si_addr 0xP, PC 0xP); aborting...") + 100]; @@ -577,7 +573,6 @@ void zlog_signal(int signo, const char *action, void *siginfo_v, msgstart = fb.pos; bprintfrr(&fb, "Received signal %d at %lld", signo, (long long)now); -#ifdef SA_SIGINFO if (program_counter) bprintfrr(&fb, " (si_addr 0x%tx, PC 0x%tx)", (ptrdiff_t)siginfo->si_addr, @@ -585,7 +580,6 @@ void zlog_signal(int signo, const char *action, void *siginfo_v, else bprintfrr(&fb, " (si_addr 0x%tx)", (ptrdiff_t)siginfo->si_addr); -#endif /* SA_SIGINFO */ bprintfrr(&fb, "; %s\n", action); crash_write(&fb, msgstart); @@ -1271,6 +1265,7 @@ void zlog_hexdump(const void *mem, unsigned int len) size_t bs = ((len / 8) + 1) * 53 + 1; char buf[bs]; char *s = buf; + const unsigned char *memch = mem; memset(buf, 0, sizeof(buf)); @@ -1279,12 +1274,11 @@ void zlog_hexdump(const void *mem, unsigned int len) /* print offset */ if (i % columns == 0) s += snprintf(s, bs - (s - buf), - "0x%016lx: ", (unsigned long)mem + i); + "0x%016lx: ", (unsigned long)memch + i); /* print hex data */ if (i < len) - s += snprintf(s, bs - (s - buf), "%02x ", - 0xFF & ((const char *)mem)[i]); + s += snprintf(s, bs - (s - buf), "%02x ", memch[i]); /* end of block, just aligning for ASCII dump */ else @@ -1296,10 +1290,9 @@ void zlog_hexdump(const void *mem, unsigned int len) /* end of block not really printing */ if (j >= len) s += snprintf(s, bs - (s - buf), " "); - else if (isprint((int)((const char *)mem)[j])) - s += snprintf( - s, bs - (s - buf), "%c", - 0xFF & ((const char *)mem)[j]); + else if (isprint(memch[j])) + s += snprintf(s, bs - (s - buf), "%c", + memch[j]); else /* other char */ s += snprintf(s, bs - (s - buf), "."); } diff --git a/lib/logicalrouter.c b/lib/logicalrouter.c deleted file mode 100644 index da69ae5312..0000000000 --- a/lib/logicalrouter.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Logical Router functions. - * Copyright (C) 2018 6WIND S.A. - * - * 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 <zebra.h> - -#include "ns.h" -#include "log.h" -#include "memory.h" - -#include "command.h" -#include "vty.h" -#include "logicalrouter.h" - -/* Comment that useless define to avoid compilation error - * in order to use it, one could provide the kind of NETNS to NS backend - * so that the allocation will match the logical router - * DEFINE_MTYPE_STATIC(LIB, LOGICALROUTER, "LogicalRouter Context") - */ -DEFINE_MTYPE_STATIC(LIB, LOGICALROUTER_NAME, "Logical Router Name") - -/* Logical Router node has no interface. */ -static struct cmd_node logicalrouter_node = {LOGICALROUTER_NODE, "", 1}; - -static int logicalrouter_backend; - -/* Get a NS. If not found, create one. */ -static struct ns *logicalrouter_get(ns_id_t ns_id) -{ - struct ns *ns; - - ns = ns_lookup(ns_id); - if (ns) - return (ns); - ns = ns_get_created(ns, NULL, ns_id); - return ns; -} - -static int logicalrouter_is_backend_netns(void) -{ - return (logicalrouter_backend == LOGICALROUTER_BACKEND_NETNS); -} - - -DEFUN_NOSH (logicalrouter, - logicalrouter_cmd, - "logical-router (1-65535) ns NAME", - "Enable a logical-router\n" - "Specify the logical-router indentifier\n" - "The Name Space\n" - "The file name in " NS_RUN_DIR ", or a full pathname\n") -{ - int idx_number = 1; - int idx_name = 3; - ns_id_t ns_id; - struct ns *ns = NULL; - char *pathname = ns_netns_pathname(vty, argv[idx_name]->arg); - - if (!pathname) - return CMD_WARNING_CONFIG_FAILED; - - ns_id = strtoul(argv[idx_number]->arg, NULL, 10); - ns = logicalrouter_get(ns_id); - - if (ns->name && strcmp(ns->name, pathname) != 0) { - vty_out(vty, "NS %u is already configured with NETNS %s\n", - ns->ns_id, ns->name); - return CMD_WARNING; - } - - if (!ns->name) - ns->name = XSTRDUP(MTYPE_LOGICALROUTER_NAME, pathname); - - if (!ns_enable(ns, NULL)) { - vty_out(vty, "Can not associate NS %u with NETNS %s\n", - ns->ns_id, ns->name); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; -} - -DEFUN (no_logicalrouter, - no_logicalrouter_cmd, - "no logical-router (1-65535) ns NAME", - NO_STR - "Enable a Logical-Router\n" - "Specify the Logical-Router identifier\n" - "The Name Space\n" - "The file name in " NS_RUN_DIR ", or a full pathname\n") -{ - int idx_number = 2; - int idx_name = 4; - ns_id_t ns_id; - struct ns *ns = NULL; - char *pathname = ns_netns_pathname(vty, argv[idx_name]->arg); - - if (!pathname) - return CMD_WARNING_CONFIG_FAILED; - - ns_id = strtoul(argv[idx_number]->arg, NULL, 10); - ns = ns_lookup(ns_id); - - if (!ns) { - vty_out(vty, "NS %u is not found\n", ns_id); - return CMD_SUCCESS; - } - - if (ns->name && strcmp(ns->name, pathname) != 0) { - vty_out(vty, "Incorrect NETNS file name\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - ns_disable(ns); - - if (ns->name) { - XFREE(MTYPE_LOGICALROUTER_NAME, ns->name); - ns->name = NULL; - } - - return CMD_SUCCESS; -} - -/* Initialize NS module. */ -void logicalrouter_init(int (*writefunc)(struct vty *vty)) -{ - if (ns_have_netns() && logicalrouter_is_backend_netns()) { - /* Install LogicalRouter commands. */ - install_node(&logicalrouter_node, writefunc); - install_element(CONFIG_NODE, &logicalrouter_cmd); - install_element(CONFIG_NODE, &no_logicalrouter_cmd); - } -} - -void logicalrouter_terminate(void) -{ - ns_terminate(); -} - -void logicalrouter_configure_backend(int backend_netns) -{ - logicalrouter_backend = backend_netns; -} diff --git a/lib/logicalrouter.h b/lib/logicalrouter.h deleted file mode 100644 index d18832ef70..0000000000 --- a/lib/logicalrouter.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Logical Router related header. - * Copyright (C) 2018 6WIND S.A. - * - * 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 _ZEBRA_LOGICAL_ROUTER_H -#define _ZEBRA_LOGICAL_ROUTER_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Logical Router Backend defines */ -#define LOGICALROUTER_BACKEND_OFF 0 -#define LOGICALROUTER_BACKEND_NETNS 1 - -/* - * Logical Router initializer/destructor - */ -extern void logicalrouter_init(int (*writefunc)(struct vty *vty)); -extern void logicalrouter_terminate(void); - -/* used to configure backend for logical router - * Currently, the whole NETNS feature is exclusively shared - * between logical router and VRF backend NETNS - * However, when logical router feature will be available, - * one can think of having exclusivity only per NETNS - */ -extern void logicalrouter_configure_backend(int backend_netns); - -#ifdef __cplusplus -} -#endif - -#endif /*_ZEBRA_LOGICAL_ROUTER_H*/ diff --git a/lib/netns_other.c b/lib/netns_other.c index 4c7be05fab..b0aae4f8df 100644 --- a/lib/netns_other.c +++ b/lib/netns_other.c @@ -82,7 +82,7 @@ const char *ns_get_name(struct ns *ns) } /* only called from vrf ( when removing netns from vrf) - * or at VRF or logical router termination + * or at VRF termination */ void ns_delete(struct ns *ns) { @@ -41,7 +41,7 @@ typedef uint32_t ns_id_t; #ifdef HAVE_NETNS #define NS_DEFAULT_NAME "/proc/self/ns/net" #else /* !HAVE_NETNS */ -#define NS_DEFAULT_NAME "Default-logical-router" +#define NS_DEFAULT_NAME "default-netns" #endif /* HAVE_NETNS */ struct ns { @@ -82,10 +82,10 @@ extern struct ns_head ns_tree; * NS hooks */ -#define NS_NEW_HOOK 0 /* a new logical-router is just created */ -#define NS_DELETE_HOOK 1 /* a logical-router is to be deleted */ -#define NS_ENABLE_HOOK 2 /* a logical-router is ready to use */ -#define NS_DISABLE_HOOK 3 /* a logical-router is to be unusable */ +#define NS_NEW_HOOK 0 /* a new netns is just created */ +#define NS_DELETE_HOOK 1 /* a netns is to be deleted */ +#define NS_ENABLE_HOOK 2 /* a netns is ready to use */ +#define NS_DISABLE_HOOK 3 /* a netns is to be unusable */ /* * Add a specific hook ns module. @@ -128,7 +128,7 @@ extern void ns_walk_func(int (*func)(struct ns *)); extern const char *ns_get_name(struct ns *ns); /* only called from vrf ( when removing netns from vrf) - * or at VRF or logical router termination + * or at VRF termination */ extern void ns_delete(struct ns *ns); diff --git a/lib/plist.c b/lib/plist.c index 1ba8982499..64571a05b7 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -218,7 +218,7 @@ static struct prefix_list *prefix_list_insert(afi_t afi, int orf, /* If name is made by all digit character. We treat it as number. */ for (number = 0, i = 0; i < strlen(name); i++) { - if (isdigit((int)name[i])) + if (isdigit((unsigned char)name[i])) number = (number * 10) + (name[i] - '0'); else break; diff --git a/lib/pqueue.c b/lib/pqueue.c deleted file mode 100644 index 87b54a681a..0000000000 --- a/lib/pqueue.c +++ /dev/null @@ -1,185 +0,0 @@ -/* Priority queue functions. - * Copyright (C) 2003 Yasuhiro Ohara - * - * 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 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 <zebra.h> - -#include "memory.h" -#include "pqueue.h" - -DEFINE_MTYPE_STATIC(LIB, PQUEUE, "Priority queue") -DEFINE_MTYPE_STATIC(LIB, PQUEUE_DATA, "Priority queue data") - -/* priority queue using heap sort */ - -/* pqueue->cmp() controls the order of sorting (i.e, ascending or - descending). If you want the left node to move upper of the heap - binary tree, make cmp() to return less than 0. for example, if cmp - (10, 20) returns -1, the sorting is ascending order. if cmp (10, - 20) returns 1, the sorting is descending order. if cmp (10, 20) - returns 0, this library does not do sorting (which will not be what - you want). To be brief, if the contents of cmp_func (left, right) - is left - right, dequeue () returns the smallest node. Otherwise - (if the contents is right - left), dequeue () returns the largest - node. */ - -#define DATA_SIZE (sizeof (void *)) -#define PARENT_OF(x) ((x - 1) / 2) -#define LEFT_OF(x) (2 * x + 1) -#define RIGHT_OF(x) (2 * x + 2) -#define HAVE_CHILD(x,q) (x < (q)->size / 2) - -void trickle_up(int index, struct pqueue *queue) -{ - void *tmp; - - /* Save current node as tmp node. */ - tmp = queue->array[index]; - - /* Continue until the node reaches top or the place where the parent - node should be upper than the tmp node. */ - while (index > 0 - && (*queue->cmp)(tmp, queue->array[PARENT_OF(index)]) < 0) { - /* actually trickle up */ - queue->array[index] = queue->array[PARENT_OF(index)]; - if (queue->update != NULL) - (*queue->update)(queue->array[index], index); - index = PARENT_OF(index); - } - - /* Restore the tmp node to appropriate place. */ - queue->array[index] = tmp; - if (queue->update != NULL) - (*queue->update)(tmp, index); -} - -void trickle_down(int index, struct pqueue *queue) -{ - void *tmp; - int which; - - /* Save current node as tmp node. */ - tmp = queue->array[index]; - - /* Continue until the node have at least one (left) child. */ - while (HAVE_CHILD(index, queue)) { - /* If right child exists, and if the right child is more proper - to be moved upper. */ - if (RIGHT_OF(index) < queue->size - && (*queue->cmp)(queue->array[LEFT_OF(index)], - queue->array[RIGHT_OF(index)]) - > 0) - which = RIGHT_OF(index); - else - which = LEFT_OF(index); - - /* If the tmp node should be upper than the child, break. */ - if ((*queue->cmp)(queue->array[which], tmp) > 0) - break; - - /* Actually trickle down the tmp node. */ - queue->array[index] = queue->array[which]; - if (queue->update != NULL) - (*queue->update)(queue->array[index], index); - index = which; - } - - /* Restore the tmp node to appropriate place. */ - queue->array[index] = tmp; - if (queue->update != NULL) - (*queue->update)(tmp, index); -} - -struct pqueue *pqueue_create(void) -{ - struct pqueue *queue; - - queue = XCALLOC(MTYPE_PQUEUE, sizeof(struct pqueue)); - - queue->array = - XCALLOC(MTYPE_PQUEUE_DATA, DATA_SIZE * PQUEUE_INIT_ARRAYSIZE); - queue->array_size = PQUEUE_INIT_ARRAYSIZE; - - /* By default we want nothing to happen when a node changes. */ - queue->update = NULL; - return queue; -} - -void pqueue_delete(struct pqueue *queue) -{ - XFREE(MTYPE_PQUEUE_DATA, queue->array); - XFREE(MTYPE_PQUEUE, queue); -} - -static int pqueue_expand(struct pqueue *queue) -{ - void **newarray; - - newarray = - XCALLOC(MTYPE_PQUEUE_DATA, queue->array_size * DATA_SIZE * 2); - - memcpy(newarray, queue->array, queue->array_size * DATA_SIZE); - - XFREE(MTYPE_PQUEUE_DATA, queue->array); - queue->array = newarray; - queue->array_size *= 2; - - return 1; -} - -void pqueue_enqueue(void *data, struct pqueue *queue) -{ - if (queue->size + 2 >= queue->array_size && !pqueue_expand(queue)) - return; - - queue->array[queue->size] = data; - if (queue->update != NULL) - (*queue->update)(data, queue->size); - trickle_up(queue->size, queue); - queue->size++; -} - -void *pqueue_dequeue(struct pqueue *queue) -{ - void *data = queue->array[0]; - queue->array[0] = queue->array[--queue->size]; - trickle_down(0, queue); - return data; -} - -void pqueue_remove_at(int index, struct pqueue *queue) -{ - queue->array[index] = queue->array[--queue->size]; - - if (index > 0 - && (*queue->cmp)(queue->array[index], - queue->array[PARENT_OF(index)]) - < 0) { - trickle_up(index, queue); - } else { - trickle_down(index, queue); - } -} - -void pqueue_remove(void *data, struct pqueue *queue) -{ - for (int i = 0; i < queue->size; i++) - if (queue->array[i] == data) - pqueue_remove_at(i, queue); -} diff --git a/lib/pqueue.h b/lib/pqueue.h deleted file mode 100644 index 032ee9db4c..0000000000 --- a/lib/pqueue.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Priority queue functions. - * Copyright (C) 2003 Yasuhiro Ohara - * - * 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 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 _ZEBRA_PQUEUE_H -#define _ZEBRA_PQUEUE_H - -#ifdef __cplusplus -extern "C" { -#endif - -struct pqueue { - void **array; - int array_size; - int size; - - int (*cmp)(void *, void *); - void (*update)(void *node, int actual_position); -}; - -#define PQUEUE_INIT_ARRAYSIZE 32 - -extern struct pqueue *pqueue_create(void); -extern void pqueue_delete(struct pqueue *queue); - -extern void pqueue_enqueue(void *data, struct pqueue *queue); -extern void *pqueue_dequeue(struct pqueue *queue); -extern void pqueue_remove_at(int index, struct pqueue *queue); -extern void pqueue_remove(void *data, struct pqueue *queue); - -extern void trickle_down(int index, struct pqueue *queue); -extern void trickle_up(int index, struct pqueue *queue); - -#ifdef __cplusplus -} -#endif - -#endif /* _ZEBRA_PQUEUE_H */ diff --git a/lib/prefix.c b/lib/prefix.c index 7abeebcd09..1a4a914e05 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -628,8 +628,15 @@ int prefix_match_network_statement(const struct prefix *n, return 1; } -void prefix_copy(struct prefix *dest, const struct prefix *src) +#ifdef __clang_analyzer__ +#undef prefix_copy /* cf. prefix.h */ +#endif + +void prefix_copy(union prefixptr udest, union prefixconstptr usrc) { + struct prefix *dest = udest.p; + const struct prefix *src = usrc.p; + dest->family = src->family; dest->prefixlen = src->prefixlen; @@ -674,8 +681,11 @@ void prefix_copy(struct prefix *dest, const struct prefix *src) * the same. Note that this routine has the same return value sense * as '==' (which is different from prefix_cmp). */ -int prefix_same(const struct prefix *p1, const struct prefix *p2) +int prefix_same(union prefixconstptr up1, union prefixconstptr up2) { + const struct prefix *p1 = up1.p; + const struct prefix *p2 = up2.p; + if ((p1 && !p2) || (!p1 && p2)) return 0; @@ -712,57 +722,59 @@ int prefix_same(const struct prefix *p1, const struct prefix *p2) } /* - * Return 0 if the network prefixes represented by the struct prefix - * arguments are the same prefix, and 1 otherwise. Network prefixes - * are considered the same if the prefix lengths are equal and the - * network parts are the same. Host bits (which are considered masked + * Return -1/0/1 comparing the prefixes in a way that gives a full/linear + * order. + * + * Network prefixes are considered the same if the prefix lengths are equal + * and the network parts are the same. Host bits (which are considered masked * by the prefix length) are not significant. Thus, 10.0.0.1/8 and * 10.0.0.2/8 are considered equivalent by this routine. Note that * this routine has the same return sense as strcmp (which is different * from prefix_same). */ -int prefix_cmp(const struct prefix *p1, const struct prefix *p2) +int prefix_cmp(union prefixconstptr up1, union prefixconstptr up2) { + const struct prefix *p1 = up1.p; + const struct prefix *p2 = up2.p; int offset; int shift; + int i; /* Set both prefix's head pointer. */ const uint8_t *pp1; const uint8_t *pp2; if (p1->family != p2->family) - return 1; + return numcmp(p1->family, p2->family); if (p1->family == AF_FLOWSPEC) { pp1 = (const uint8_t *)p1->u.prefix_flowspec.ptr; pp2 = (const uint8_t *)p2->u.prefix_flowspec.ptr; if (p1->u.prefix_flowspec.prefixlen != p2->u.prefix_flowspec.prefixlen) - return 1; + return numcmp(p1->u.prefix_flowspec.prefixlen, + p2->u.prefix_flowspec.prefixlen); offset = p1->u.prefix_flowspec.prefixlen; while (offset--) if (pp1[offset] != pp2[offset]) - return 1; + return numcmp(pp1[offset], pp2[offset]); return 0; } pp1 = p1->u.val; pp2 = p2->u.val; if (p1->prefixlen != p2->prefixlen) - return 1; + return numcmp(p1->prefixlen, p2->prefixlen); offset = p1->prefixlen / PNBBY; shift = p1->prefixlen % PNBBY; - if (shift) - if (maskbit[shift] & (pp1[offset] ^ pp2[offset])) - return 1; - - while (offset--) - if (pp1[offset] != pp2[offset]) - return 1; + i = memcmp(pp1, pp2, offset); + if (i) + return i; - return 0; + return numcmp(pp1[offset] & maskbit[shift], + pp2[offset] & maskbit[shift]); } /* diff --git a/lib/prefix.h b/lib/prefix.h index d57b43dac6..e338140f1a 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -410,12 +410,20 @@ extern const char *prefix2str(union prefixconstptr, char *, int); extern int prefix_match(const struct prefix *, const struct prefix *); extern int prefix_match_network_statement(const struct prefix *, const struct prefix *); -extern int prefix_same(const struct prefix *, const struct prefix *); -extern int prefix_cmp(const struct prefix *, const struct prefix *); +extern int prefix_same(union prefixconstptr, union prefixconstptr); +extern int prefix_cmp(union prefixconstptr, union prefixconstptr); extern int prefix_common_bits(const struct prefix *, const struct prefix *); -extern void prefix_copy(struct prefix *dest, const struct prefix *src); +extern void prefix_copy(union prefixptr, union prefixconstptr); extern void apply_mask(struct prefix *); +#ifdef __clang_analyzer__ +/* clang-SA doesn't understand transparent unions, making it think that the + * target of prefix_copy is uninitialized. So just memset the target. + * cf. https://bugs.llvm.org/show_bug.cgi?id=42811 + */ +#define prefix_copy(a, b) ({ memset(a, 0, sizeof(*a)); prefix_copy(a, b); }) +#endif + extern struct prefix *sockunion2prefix(const union sockunion *dest, const union sockunion *mask); extern struct prefix *sockunion2hostprefix(const union sockunion *, diff --git a/lib/ptm_lib.c b/lib/ptm_lib.c index 7f868beda4..a2ce9a0e2f 100644 --- a/lib/ptm_lib.c +++ b/lib/ptm_lib.c @@ -125,7 +125,7 @@ static int _ptm_lib_decode_header(csv_t *csv, int *msglen, int *version, } /* remove leading spaces */ for (i = j = 0; i < csv_field_len(fld); i++) { - if (!isspace((int)hdr[i])) { + if (!isspace((unsigned char)hdr[i])) { client_name[j] = hdr[i]; j++; } diff --git a/lib/routemap.c b/lib/routemap.c index 2fee3a479e..eca02e8366 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -927,15 +927,15 @@ static const char *route_map_type_str(enum route_map_type type) return ""; } -static const char *route_map_result_str(route_map_result_t res) +static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res) { switch (res) { case RMAP_MATCH: return "match"; - case RMAP_DENYMATCH: - return "deny"; case RMAP_NOMATCH: return "no match"; + case RMAP_NOOP: + return "noop"; case RMAP_ERROR: return "error"; case RMAP_OKAY: @@ -945,6 +945,18 @@ static const char *route_map_result_str(route_map_result_t res) return "invalid"; } +static const char *route_map_result_str(route_map_result_t res) +{ + switch (res) { + case RMAP_DENYMATCH: + return "deny"; + case RMAP_PERMITMATCH: + return "permit"; + } + + return "invalid"; +} + static int route_map_empty(struct route_map *map) { if (map->head == NULL && map->tail == NULL) @@ -1558,20 +1570,98 @@ int route_map_delete_set(struct route_map_index *index, const char *set_name, return 1; } +static enum route_map_cmd_result_t +route_map_apply_match(struct route_map_rule_list *match_list, + const struct prefix *prefix, route_map_object_t type, + void *object) +{ + enum route_map_cmd_result_t ret = RMAP_NOMATCH; + struct route_map_rule *match; + bool is_matched = false; + + + /* Check all match rule and if there is no match rule, go to the + set statement. */ + if (!match_list->head) + ret = RMAP_MATCH; + else { + for (match = match_list->head; match; match = match->next) { + /* + * Try each match statement. If any match does not + * return RMAP_MATCH or RMAP_NOOP, return. + * Otherwise continue on to next match statement. + * All match statements must MATCH for + * end-result to be a match. + * (Exception:If match stmts result in a mix of + * MATCH/NOOP, then also end-result is a match) + * If all result in NOOP, end-result is NOOP. + */ + ret = (*match->cmd->func_apply)(match->value, prefix, + type, object); + + /* + * If the consolidated result of func_apply is: + * ----------------------------------------------- + * | MATCH | NOMATCH | NOOP | Final Result | + * ------------------------------------------------ + * | yes | yes | yes | NOMATCH | + * | no | no | yes | NOOP | + * | yes | no | yes | MATCH | + * | no | yes | yes | NOMATCH | + * |----------------------------------------------- + * + * Traditionally, all rules within route-map + * should match for it to MATCH. + * If there are noops within the route-map rules, + * it follows the above matrix. + * + * Eg: route-map rm1 permit 10 + * match rule1 + * match rule2 + * match rule3 + * .... + * route-map rm1 permit 20 + * match ruleX + * match ruleY + * ... + */ + + switch (ret) { + case RMAP_MATCH: + is_matched = true; + break; + + case RMAP_NOMATCH: + return ret; + + case RMAP_NOOP: + if (is_matched) + ret = RMAP_MATCH; + break; + + default: + break; + } + + } + } + return ret; +} + /* Apply route map's each index to the object. The matrix for a route-map looks like this: (note, this includes the description for the "NEXT" and "GOTO" frobs now - Match | No Match - | - permit action | cont - | - ------------------+--------------- - | - deny deny | cont - | + | Match | No Match | No op + |-----------|--------------|------- + permit | action | cont | cont. + | | default:deny | default:permit + -------------------+----------------------- + | deny | cont | cont. + deny | | default:deny | default:permit + |-----------|--------------|-------- action) -Apply Set statements, accept route @@ -1604,45 +1694,13 @@ int route_map_delete_set(struct route_map_index *index, const char *set_name, We need to make sure our route-map processing matches the above */ - -static route_map_result_t -route_map_apply_match(struct route_map_rule_list *match_list, - const struct prefix *prefix, route_map_object_t type, - void *object) -{ - route_map_result_t ret = RMAP_NOMATCH; - struct route_map_rule *match; - - - /* Check all match rule and if there is no match rule, go to the - set statement. */ - if (!match_list->head) - ret = RMAP_MATCH; - else { - for (match = match_list->head; match; match = match->next) { - /* Try each match statement in turn, If any do not - return - RMAP_MATCH, return, otherwise continue on to next - match - statement. All match statements must match for - end-result - to be a match. */ - ret = (*match->cmd->func_apply)(match->value, prefix, - type, object); - if (ret != RMAP_MATCH) - return ret; - } - } - return ret; -} - -/* Apply route map to the object. */ route_map_result_t route_map_apply(struct route_map *map, const struct prefix *prefix, route_map_object_t type, void *object) { static int recursion = 0; - int ret = 0; + enum route_map_cmd_result_t match_ret = RMAP_NOMATCH; + route_map_result_t ret = RMAP_PERMITMATCH; struct route_map_index *index; struct route_map_rule *set; char buf[PREFIX_STRLEN]; @@ -1656,7 +1714,7 @@ route_map_result_t route_map_apply(struct route_map *map, return RMAP_DENYMATCH; } - if (map == NULL) { + if (map == NULL || map->head == NULL) { ret = RMAP_DENYMATCH; goto route_map_apply_end; } @@ -1665,29 +1723,64 @@ route_map_result_t route_map_apply(struct route_map *map, for (index = map->head; index; index = index->next) { /* Apply this index. */ index->applied++; - ret = route_map_apply_match(&index->match_list, prefix, type, - object); + match_ret = route_map_apply_match(&index->match_list, prefix, + type, object); if (rmap_debug) { zlog_debug("Route-map: %s, sequence: %d, prefix: %s, result: %s", map->name, index->pref, prefix2str(prefix, buf, sizeof(buf)), - route_map_result_str(ret)); + route_map_cmd_result_str(match_ret)); } /* Now we apply the matrix from above */ - if (ret == RMAP_NOMATCH) - /* 'cont' from matrix - continue to next route-map - * sequence */ + if (match_ret == RMAP_NOOP) + /* + * Do not change the return value. Retain the previous + * return value. Previous values can be: + * 1)permitmatch (if a nomatch was never + * seen before in this route-map.) + * 2)denymatch (if a nomatch was seen earlier in one + * of the previous sequences) + */ + + /* + * 'cont' from matrix - continue to next route-map + * sequence + */ continue; - else if (ret == RMAP_MATCH) { + else if (match_ret == RMAP_NOMATCH) { + + /* + * The return value is now changed to denymatch. + * So from here on out, even if we see more noops, + * we retain this return value and return this + * eventually if there are no matches. + */ + ret = RMAP_DENYMATCH; + + /* + * 'cont' from matrix - continue to next route-map + * sequence + */ + continue; + } else if (match_ret == RMAP_MATCH) { if (index->type == RMAP_PERMIT) /* 'action' */ { + /* Match succeeded, rmap is of type permit */ + ret = RMAP_PERMITMATCH; + /* permit+match must execute sets */ for (set = index->set_list.head; set; set = set->next) - ret = (*set->cmd->func_apply)( + /* + * set cmds return RMAP_OKAY or + * RMAP_ERROR. We do not care if + * set succeeded or not. So, ignore + * return code. + */ + (void) (*set->cmd->func_apply)( set->value, prefix, type, object); @@ -1741,8 +1834,6 @@ route_map_result_t route_map_apply(struct route_map *map, } } } - /* Finally route-map does not match at all. */ - ret = RMAP_DENYMATCH; route_map_apply_end: if (rmap_debug) { diff --git a/lib/routemap.h b/lib/routemap.h index 90df1048ed..f9ad0f64a9 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -38,13 +38,35 @@ DECLARE_MTYPE(ROUTE_MAP_COMPILED) enum route_map_type { RMAP_PERMIT, RMAP_DENY, RMAP_ANY }; typedef enum { - RMAP_MATCH, RMAP_DENYMATCH, - RMAP_NOMATCH, - RMAP_ERROR, - RMAP_OKAY + RMAP_PERMITMATCH } route_map_result_t; +/* + * Route-map match or set result "Eg: match evpn vni xx" + * route-map match cmd always returns match/nomatch/noop + * match--> found a match + * nomatch--> didnt find a match + * noop--> not applicable + * route-map set retuns okay/error + * okay --> set was successful + * error --> set was not successful + */ +enum route_map_cmd_result_t { + /* + * route-map match cmd results + */ + RMAP_MATCH, + RMAP_NOMATCH, + RMAP_NOOP, + /* + * route-map set cmd results + */ + RMAP_OKAY, + RMAP_ERROR +}; + + typedef enum { RMAP_RIP, RMAP_RIPNG, @@ -91,10 +113,10 @@ struct route_map_rule_cmd { const char *str; /* Function for value set or match. */ - route_map_result_t (*func_apply)(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object); + enum route_map_cmd_result_t (*func_apply)(void *rule, + const struct prefix *prefix, + route_map_object_t type, + void *object); /* Compile argument and return result as void *. */ void *(*func_compile)(const char *); diff --git a/lib/seqlock.c b/lib/seqlock.c index 223d14952c..c05ec19db4 100644 --- a/lib/seqlock.c +++ b/lib/seqlock.c @@ -25,6 +25,7 @@ #include "config.h" #endif +#include <string.h> #include <unistd.h> #include <limits.h> #include <errno.h> @@ -35,44 +36,75 @@ #include "seqlock.h" +/**************************************** + * OS specific synchronization wrappers * + ****************************************/ + +/* + * Linux: sys_futex() + */ #ifdef HAVE_SYNC_LINUX_FUTEX -/* Linux-specific - sys_futex() */ #include <sys/syscall.h> #include <linux/futex.h> -static long sys_futex(void *addr1, int op, int val1, struct timespec *timeout, - void *addr2, int val3) +static long sys_futex(void *addr1, int op, int val1, + const struct timespec *timeout, void *addr2, int val3) { return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3); } #define wait_once(sqlo, val) \ sys_futex((int *)&sqlo->pos, FUTEX_WAIT, (int)val, NULL, NULL, 0) +#define wait_time(sqlo, val, time, reltime) \ + sys_futex((int *)&sqlo->pos, FUTEX_WAIT_BITSET, (int)val, time, \ + NULL, ~0U) #define wait_poke(sqlo) \ sys_futex((int *)&sqlo->pos, FUTEX_WAKE, INT_MAX, NULL, NULL, 0) +/* + * OpenBSD: sys_futex(), almost the same as on Linux + */ #elif defined(HAVE_SYNC_OPENBSD_FUTEX) -/* OpenBSD variant of the above. untested, not upstream in OpenBSD. */ #include <sys/syscall.h> #include <sys/futex.h> +#define TIME_RELATIVE 1 + #define wait_once(sqlo, val) \ futex((int *)&sqlo->pos, FUTEX_WAIT, (int)val, NULL, NULL, 0) +#define wait_time(sqlo, val, time, reltime) \ + futex((int *)&sqlo->pos, FUTEX_WAIT, (int)val, reltime, NULL, 0) #define wait_poke(sqlo) \ futex((int *)&sqlo->pos, FUTEX_WAKE, INT_MAX, NULL, NULL, 0) +/* + * FreeBSD: _umtx_op() + */ #elif defined(HAVE_SYNC_UMTX_OP) -/* FreeBSD-specific: umtx_op() */ #include <sys/umtx.h> #define wait_once(sqlo, val) \ _umtx_op((void *)&sqlo->pos, UMTX_OP_WAIT_UINT, val, NULL, NULL) +static int wait_time(struct seqlock *sqlo, uint32_t val, + const struct timespec *abstime, + const struct timespec *reltime) +{ + struct _umtx_time t; + t._flags = UMTX_ABSTIME; + t._clockid = CLOCK_MONOTONIC; + memcpy(&t._timeout, abstime, sizeof(t._timeout)); + return _umtx_op((void *)&sqlo->pos, UMTX_OP_WAIT_UINT, val, + (void *)(uintptr_t) sizeof(t), &t); +} #define wait_poke(sqlo) \ _umtx_op((void *)&sqlo->pos, UMTX_OP_WAKE, INT_MAX, NULL, NULL) -#else -/* generic version. used on *BSD, Solaris and OSX. +/* + * generic version. used on NetBSD, Solaris and OSX. really shitty. */ +#else + +#define TIME_ABS_REALTIME 1 #define wait_init(sqlo) do { \ pthread_mutex_init(&sqlo->lock, NULL); \ @@ -80,6 +112,9 @@ static long sys_futex(void *addr1, int op, int val1, struct timespec *timeout, } while (0) #define wait_prep(sqlo) pthread_mutex_lock(&sqlo->lock) #define wait_once(sqlo, val) pthread_cond_wait(&sqlo->wake, &sqlo->lock) +#define wait_time(sqlo, val, time, reltime) \ + pthread_cond_timedwait(&sqlo->wake, \ + &sqlo->lock, time); #define wait_done(sqlo) pthread_mutex_unlock(&sqlo->lock) #define wait_poke(sqlo) do { \ pthread_mutex_lock(&sqlo->lock); \ @@ -103,18 +138,112 @@ void seqlock_wait(struct seqlock *sqlo, seqlock_val_t val) seqlock_assert_valid(val); wait_prep(sqlo); - while (1) { - cur = atomic_load_explicit(&sqlo->pos, memory_order_acquire); - if (!(cur & 1)) + cur = atomic_load_explicit(&sqlo->pos, memory_order_relaxed); + + while (cur & SEQLOCK_HELD) { + cal = SEQLOCK_VAL(cur) - val - 1; + assert(cal < 0x40000000 || cal > 0xc0000000); + if (cal < 0x80000000) break; - cal = cur - val - 1; + + if ((cur & SEQLOCK_WAITERS) + || atomic_compare_exchange_weak_explicit( + &sqlo->pos, &cur, cur | SEQLOCK_WAITERS, + memory_order_relaxed, memory_order_relaxed)) { + wait_once(sqlo, cur | SEQLOCK_WAITERS); + cur = atomic_load_explicit(&sqlo->pos, + memory_order_relaxed); + } + /* else: we failed to swap in cur because it just changed */ + } + wait_done(sqlo); +} + +bool seqlock_timedwait(struct seqlock *sqlo, seqlock_val_t val, + const struct timespec *abs_monotime_limit) +{ +/* + * ABS_REALTIME - used on NetBSD, Solaris and OSX + */ +#if TIME_ABS_REALTIME +#define time_arg1 &abs_rt +#define time_arg2 NULL +#define time_prep + struct timespec curmono, abs_rt; + + clock_gettime(CLOCK_MONOTONIC, &curmono); + clock_gettime(CLOCK_REALTIME, &abs_rt); + + abs_rt.tv_nsec += abs_monotime_limit->tv_nsec - curmono.tv_nsec; + if (abs_rt.tv_nsec < 0) { + abs_rt.tv_sec--; + abs_rt.tv_nsec += 1000000000; + } else if (abs_rt.tv_nsec >= 1000000000) { + abs_rt.tv_sec++; + abs_rt.tv_nsec -= 1000000000; + } + abs_rt.tv_sec += abs_monotime_limit->tv_sec - curmono.tv_sec; + +/* + * RELATIVE - used on OpenBSD (might get a patch to get absolute monotime) + */ +#elif TIME_RELATIVE + struct timespec reltime; + +#define time_arg1 abs_monotime_limit +#define time_arg2 &reltime +#define time_prep \ + clock_gettime(CLOCK_MONOTONIC, &reltime); \ + reltime.tv_sec = abs_monotime_limit.tv_sec - reltime.tv_sec; \ + reltime.tv_nsec = abs_monotime_limit.tv_nsec - reltime.tv_nsec; \ + if (reltime.tv_nsec < 0) { \ + reltime.tv_sec--; \ + reltime.tv_nsec += 1000000000; \ + } +/* + * FreeBSD & Linux: absolute time re. CLOCK_MONOTONIC + */ +#else +#define time_arg1 abs_monotime_limit +#define time_arg2 NULL +#define time_prep +#endif + + bool ret = true; + seqlock_val_t cur, cal; + + seqlock_assert_valid(val); + + wait_prep(sqlo); + cur = atomic_load_explicit(&sqlo->pos, memory_order_relaxed); + + while (cur & SEQLOCK_HELD) { + cal = SEQLOCK_VAL(cur) - val - 1; assert(cal < 0x40000000 || cal > 0xc0000000); if (cal < 0x80000000) break; - wait_once(sqlo, cur); + if ((cur & SEQLOCK_WAITERS) + || atomic_compare_exchange_weak_explicit( + &sqlo->pos, &cur, cur | SEQLOCK_WAITERS, + memory_order_relaxed, memory_order_relaxed)) { + int rv; + + time_prep + + rv = wait_time(sqlo, cur | SEQLOCK_WAITERS, time_arg1, + time_arg2); + if (rv) { + ret = false; + break; + } + cur = atomic_load_explicit(&sqlo->pos, + memory_order_relaxed); + } } wait_done(sqlo); + + return ret; } bool seqlock_check(struct seqlock *sqlo, seqlock_val_t val) @@ -123,26 +252,32 @@ bool seqlock_check(struct seqlock *sqlo, seqlock_val_t val) seqlock_assert_valid(val); - cur = atomic_load_explicit(&sqlo->pos, memory_order_acquire); - if (!(cur & 1)) + cur = atomic_load_explicit(&sqlo->pos, memory_order_relaxed); + if (!(cur & SEQLOCK_HELD)) return 1; - cur -= val; + cur = SEQLOCK_VAL(cur) - val - 1; assert(cur < 0x40000000 || cur > 0xc0000000); return cur < 0x80000000; } void seqlock_acquire_val(struct seqlock *sqlo, seqlock_val_t val) { + seqlock_val_t prev; + seqlock_assert_valid(val); - atomic_store_explicit(&sqlo->pos, val, memory_order_release); - wait_poke(sqlo); + prev = atomic_exchange_explicit(&sqlo->pos, val, memory_order_relaxed); + if (prev & SEQLOCK_WAITERS) + wait_poke(sqlo); } void seqlock_release(struct seqlock *sqlo) { - atomic_store_explicit(&sqlo->pos, 0, memory_order_release); - wait_poke(sqlo); + seqlock_val_t prev; + + prev = atomic_exchange_explicit(&sqlo->pos, 0, memory_order_relaxed); + if (prev & SEQLOCK_WAITERS) + wait_poke(sqlo); } void seqlock_init(struct seqlock *sqlo) @@ -154,14 +289,23 @@ void seqlock_init(struct seqlock *sqlo) seqlock_val_t seqlock_cur(struct seqlock *sqlo) { - return atomic_load_explicit(&sqlo->pos, memory_order_acquire); + return SEQLOCK_VAL(atomic_load_explicit(&sqlo->pos, + memory_order_relaxed)); } seqlock_val_t seqlock_bump(struct seqlock *sqlo) { - seqlock_val_t val; + seqlock_val_t val, cur; + + cur = atomic_load_explicit(&sqlo->pos, memory_order_relaxed); + seqlock_assert_valid(cur); + + do { + val = SEQLOCK_VAL(cur) + SEQLOCK_INCR; + } while (!atomic_compare_exchange_weak_explicit(&sqlo->pos, &cur, val, + memory_order_relaxed, memory_order_relaxed)); - val = atomic_fetch_add_explicit(&sqlo->pos, 2, memory_order_release); - wait_poke(sqlo); + if (cur & SEQLOCK_WAITERS) + wait_poke(sqlo); return val; } diff --git a/lib/seqlock.h b/lib/seqlock.h index eef05a4307..b551e3ffc4 100644 --- a/lib/seqlock.h +++ b/lib/seqlock.h @@ -54,12 +54,28 @@ */ /* use sequentially increasing "ticket numbers". lowest bit will always - * be 1 to have a 'cleared' indication (i.e., counts 1,3,5,7,etc. ) + * be 1 to have a 'cleared' indication (i.e., counts 1,5,9,13,etc. ) + * 2nd lowest bit is used to indicate we have waiters. */ typedef _Atomic uint32_t seqlock_ctr_t; typedef uint32_t seqlock_val_t; -#define seqlock_assert_valid(val) assert(val & 1) +#define seqlock_assert_valid(val) assert((val) & SEQLOCK_HELD) +/* NB: SEQLOCK_WAITERS is only allowed if SEQLOCK_HELD is also set; can't + * have waiters on an unheld seqlock + */ +#define SEQLOCK_HELD (1U << 0) +#define SEQLOCK_WAITERS (1U << 1) +#define SEQLOCK_VAL(n) ((n) & ~SEQLOCK_WAITERS) +#define SEQLOCK_STARTVAL 1U +#define SEQLOCK_INCR 4U + +/* TODO: originally, this was using "atomic_fetch_add", which is the reason + * bit 0 is used to indicate held state. With SEQLOCK_WAITERS added, there's + * no fetch_add anymore (cmpxchg loop instead), so we don't need to use bit 0 + * for this anymore & can just special-case the value 0 for it and skip it in + * counting. + */ struct seqlock { /* always used */ @@ -74,8 +90,16 @@ struct seqlock { extern void seqlock_init(struct seqlock *sqlo); -/* while (sqlo <= val) - wait until seqlock->pos > val, or seqlock unheld */ +/* basically: "while (sqlo <= val) wait();" + * returns when sqlo > val || !seqlock_held(sqlo) + */ extern void seqlock_wait(struct seqlock *sqlo, seqlock_val_t val); + +/* same, but time-limited (limit is an absolute CLOCK_MONOTONIC value) */ +extern bool seqlock_timedwait(struct seqlock *sqlo, seqlock_val_t val, + const struct timespec *abs_monotime_limit); + +/* one-shot test, returns true if seqlock_wait would return immediately */ extern bool seqlock_check(struct seqlock *sqlo, seqlock_val_t val); static inline bool seqlock_held(struct seqlock *sqlo) @@ -85,12 +109,20 @@ static inline bool seqlock_held(struct seqlock *sqlo) /* sqlo - get seqlock position -- for the "counter" seqlock */ extern seqlock_val_t seqlock_cur(struct seqlock *sqlo); -/* sqlo++ - note: like x++, returns previous value, before bumping */ + +/* ++sqlo (but atomic & wakes waiters) - returns value that we bumped to. + * + * guarantees: + * - each seqlock_bump call bumps the position by exactly one SEQLOCK_INCR. + * There are no skipped/missed or multiple increments. + * - each return value is only returned from one seqlock_bump() call + */ extern seqlock_val_t seqlock_bump(struct seqlock *sqlo); /* sqlo = val - can be used on held seqlock. */ extern void seqlock_acquire_val(struct seqlock *sqlo, seqlock_val_t val); + /* sqlo = ref - standard pattern: acquire relative to other seqlock */ static inline void seqlock_acquire(struct seqlock *sqlo, struct seqlock *ref) { diff --git a/lib/sigevent.c b/lib/sigevent.c index d02b074223..fcd85d0d43 100644 --- a/lib/sigevent.c +++ b/lib/sigevent.c @@ -24,7 +24,6 @@ #include <memory.h> #include <lib_errors.h> -#ifdef SA_SIGINFO #ifdef HAVE_UCONTEXT_H #ifdef GNU_LINUX /* get REG_EIP from ucontext.h */ @@ -34,7 +33,6 @@ #endif /* GNU_LINUX */ #include <ucontext.h> #endif /* HAVE_UCONTEXT_H */ -#endif /* SA_SIGINFO */ /* master signals descriptor struct */ @@ -158,8 +156,6 @@ static int signal_set(int signo) return 0; } -#ifdef SA_SIGINFO - /* XXX This function should be enhanced to support more platforms (it currently works only on Linux/x86). */ static void *program_counter(void *context) @@ -199,41 +195,19 @@ static void *program_counter(void *context) return NULL; } -#endif /* SA_SIGINFO */ - static void __attribute__((noreturn)) -exit_handler(int signo -#ifdef SA_SIGINFO - , - siginfo_t *siginfo, void *context -#endif - ) +exit_handler(int signo, siginfo_t *siginfo, void *context) { -#ifndef SA_SIGINFO - void *siginfo = NULL; - void *pc = NULL; -#else void *pc = program_counter(context); -#endif zlog_signal(signo, "exiting...", siginfo, pc); _exit(128 + signo); } static void __attribute__((noreturn)) -core_handler(int signo -#ifdef SA_SIGINFO - , - siginfo_t *siginfo, void *context -#endif - ) +core_handler(int signo, siginfo_t *siginfo, void *context) { -#ifndef SA_SIGINFO - void *siginfo = NULL; - void *pc = NULL; -#else void *pc = program_counter(context); -#endif /* make sure we don't hang in here. default for SIGALRM is terminate. * - if we're in backtrace for more than a second, abort. */ @@ -290,12 +264,7 @@ static void trap_default_signals(void) static const struct { const int *sigs; unsigned int nsigs; - void (*handler)(int signo -#ifdef SA_SIGINFO - , - siginfo_t *info, void *context -#endif - ); + void (*handler)(int signo, siginfo_t *info, void *context); } sigmap[] = { {core_signals, array_size(core_signals), core_handler}, {exit_signals, array_size(exit_signals), exit_handler}, @@ -316,15 +285,10 @@ static void trap_default_signals(void) act.sa_handler = SIG_IGN; act.sa_flags = 0; } else { -#ifdef SA_SIGINFO /* Request extra arguments to signal * handler. */ act.sa_sigaction = sigmap[i].handler; act.sa_flags = SA_SIGINFO; -#else - act.sa_handler = sigmap[i].handler; - act.sa_flags = 0; -#endif #ifdef SA_RESETHAND /* don't try to print backtraces * recursively */ diff --git a/lib/stream.c b/lib/stream.c index 6c187bd359..c67bc3c993 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -904,20 +904,30 @@ int stream_put_prefix(struct stream *s, struct prefix *p) /* Put NLRI with label */ int stream_put_labeled_prefix(struct stream *s, struct prefix *p, - mpls_label_t *label) + mpls_label_t *label, int addpath_encode, + uint32_t addpath_tx_id) { size_t psize; + size_t psize_with_addpath; uint8_t *label_pnt = (uint8_t *)label; STREAM_VERIFY_SANE(s); psize = PSIZE(p->prefixlen); + psize_with_addpath = psize + (addpath_encode ? 4 : 0); - if (STREAM_WRITEABLE(s) < (psize + 3)) { + if (STREAM_WRITEABLE(s) < (psize_with_addpath + 3)) { STREAM_BOUND_WARN(s, "put"); return 0; } + if (addpath_encode) { + s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 24); + s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 16); + s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 8); + s->data[s->endp++] = (uint8_t)addpath_tx_id; + } + stream_putc(s, (p->prefixlen + 24)); stream_putc(s, label_pnt[0]); stream_putc(s, label_pnt[1]); diff --git a/lib/stream.h b/lib/stream.h index 5341bfa40b..a903ec0ea5 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -199,7 +199,8 @@ extern int stream_put_prefix_addpath(struct stream *, struct prefix *, uint32_t addpath_tx_id); extern int stream_put_prefix(struct stream *, struct prefix *); extern int stream_put_labeled_prefix(struct stream *, struct prefix *, - mpls_label_t *); + mpls_label_t *, int addpath_encode, + uint32_t addpath_tx_id); extern void stream_get(void *, struct stream *, size_t); extern bool stream_get2(void *data, struct stream *s, size_t size); extern void stream_get_from(void *, struct stream *, size_t, size_t); diff --git a/lib/subdir.am b/lib/subdir.am index aa89622028..2be7537bcc 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -21,6 +21,7 @@ lib_libfrr_la_SOURCES = \ lib/distribute.c \ lib/ferr.c \ lib/filter.c \ + lib/frrcu.c \ lib/frrlua.c \ lib/frr_pthread.c \ lib/frrstr.c \ @@ -61,7 +62,6 @@ lib_libfrr_la_SOURCES = \ lib/openbsd-tree.c \ lib/pid_output.c \ lib/plist.c \ - lib/pqueue.c \ lib/prefix.c \ lib/privs.c \ lib/ptm_lib.c \ @@ -95,7 +95,6 @@ lib_libfrr_la_SOURCES = \ lib/yang_translator.c \ lib/yang_wrappers.c \ lib/zclient.c \ - lib/logicalrouter.c \ lib/printf/printf-pos.c \ lib/printf/vfprintf.c \ lib/printf/glue.c \ @@ -113,7 +112,6 @@ vtysh_scan += \ $(top_srcdir)/lib/if.c \ $(top_srcdir)/lib/if_rmap.c \ $(top_srcdir)/lib/keychain.c \ - $(top_srcdir)/lib/logicalrouter.c \ $(top_srcdir)/lib/nexthop_group.c \ $(top_srcdir)/lib/plist.c \ $(top_srcdir)/lib/routemap.c \ @@ -163,6 +161,7 @@ pkginclude_HEADERS += \ lib/frrlua.h \ lib/frr_pthread.h \ lib/frratomic.h \ + lib/frrcu.h \ lib/frrstr.h \ lib/getopt.h \ lib/graph.h \ @@ -200,7 +199,6 @@ pkginclude_HEADERS += \ lib/openbsd-queue.h \ lib/openbsd-tree.h \ lib/plist.h \ - lib/pqueue.h \ lib/prefix.h \ lib/printfrr.h \ lib/privs.h \ @@ -241,7 +239,6 @@ pkginclude_HEADERS += \ lib/zassert.h \ lib/zclient.h \ lib/zebra.h \ - lib/logicalrouter.h \ lib/pbr.h \ # end diff --git a/lib/thread.c b/lib/thread.c index fc2de09df0..943b849ebf 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -25,9 +25,9 @@ #include "thread.h" #include "memory.h" +#include "frrcu.h" #include "log.h" #include "hash.h" -#include "pqueue.h" #include "command.h" #include "sigevent.h" #include "network.h" @@ -42,6 +42,22 @@ DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats") DECLARE_LIST(thread_list, struct thread, threaditem) +static int thread_timer_cmp(const struct thread *a, const struct thread *b) +{ + if (a->u.sands.tv_sec < b->u.sands.tv_sec) + return -1; + if (a->u.sands.tv_sec > b->u.sands.tv_sec) + return 1; + if (a->u.sands.tv_usec < b->u.sands.tv_usec) + return -1; + if (a->u.sands.tv_usec > b->u.sands.tv_usec) + return 1; + return 0; +} + +DECLARE_HEAP(thread_timer_list, struct thread, timeritem, + thread_timer_cmp) + #if defined(__APPLE__) #include <mach/mach.h> #include <mach/mach_time.h> @@ -401,25 +417,6 @@ void thread_cmd_init(void) /* CLI end ------------------------------------------------------------------ */ -static int thread_timer_cmp(void *a, void *b) -{ - struct thread *thread_a = a; - struct thread *thread_b = b; - - if (timercmp(&thread_a->u.sands, &thread_b->u.sands, <)) - return -1; - if (timercmp(&thread_a->u.sands, &thread_b->u.sands, >)) - return 1; - return 0; -} - -static void thread_timer_update(void *node, int actual_position) -{ - struct thread *thread = node; - - thread->index = actual_position; -} - static void cancelreq_del(void *cr) { XFREE(MTYPE_TMP, cr); @@ -464,11 +461,7 @@ struct thread_master *thread_master_create(const char *name) thread_list_init(&rv->event); thread_list_init(&rv->ready); thread_list_init(&rv->unuse); - - /* Initialize the timer queues */ - rv->timer = pqueue_create(); - rv->timer->cmp = thread_timer_cmp; - rv->timer->update = thread_timer_update; + thread_timer_list_init(&rv->timer); /* Initialize thread_fetch() settings */ rv->spin = true; @@ -566,16 +559,6 @@ static void thread_array_free(struct thread_master *m, XFREE(MTYPE_THREAD_POLL, thread_array); } -static void thread_queue_free(struct thread_master *m, struct pqueue *queue) -{ - int i; - - for (i = 0; i < queue->size; i++) - thread_free(m, queue->array[i]); - - pqueue_delete(queue); -} - /* * thread_master_free_unused * @@ -598,6 +581,8 @@ void thread_master_free_unused(struct thread_master *m) /* Stop thread scheduler. */ void thread_master_free(struct thread_master *m) { + struct thread *t; + pthread_mutex_lock(&masters_mtx); { listnode_delete(masters, m); @@ -609,7 +594,8 @@ void thread_master_free(struct thread_master *m) thread_array_free(m, m->read); thread_array_free(m, m->write); - thread_queue_free(m, m->timer); + while ((t = thread_timer_list_pop(&m->timer))) + thread_free(m, t); thread_list_free(m, &m->event); thread_list_free(m, &m->ready); thread_list_free(m, &m->unuse); @@ -683,7 +669,6 @@ static struct thread *thread_get(struct thread_master *m, uint8_t type, thread->add_type = type; thread->master = m; thread->arg = arg; - thread->index = -1; thread->yield = THREAD_YIELD_TIME_SLOT; /* default */ thread->ref = NULL; @@ -729,7 +714,7 @@ static int fd_poll(struct thread_master *m, struct pollfd *pfds, nfds_t pfdsize, { /* If timer_wait is null here, that means poll() should block * indefinitely, - * unless the thread_master has overriden it by setting + * unless the thread_master has overridden it by setting * ->selectpoll_timeout. * If the value is positive, it specifies the maximum number of * milliseconds @@ -753,6 +738,9 @@ static int fd_poll(struct thread_master *m, struct pollfd *pfds, nfds_t pfdsize, < 0) // effect a poll (return immediately) timeout = 0; + rcu_read_unlock(); + rcu_assert_read_unlocked(); + /* add poll pipe poker */ assert(count + 1 < pfdsize); pfds[count].fd = m->io_pipe[0]; @@ -766,6 +754,8 @@ static int fd_poll(struct thread_master *m, struct pollfd *pfds, nfds_t pfdsize, while (read(m->io_pipe[0], &trash, sizeof(trash)) > 0) ; + rcu_read_lock(); + return num; } @@ -854,7 +844,6 @@ funcname_thread_add_timer_timeval(struct thread_master *m, struct thread **t_ptr, debugargdef) { struct thread *thread; - struct pqueue *queue; assert(m != NULL); @@ -870,7 +859,6 @@ funcname_thread_add_timer_timeval(struct thread_master *m, return NULL; } - queue = m->timer; thread = thread_get(m, type, func, arg, debugargpass); pthread_mutex_lock(&thread->mtx); @@ -878,7 +866,7 @@ funcname_thread_add_timer_timeval(struct thread_master *m, monotime(&thread->u.sands); timeradd(&thread->u.sands, time_relative, &thread->u.sands); - pqueue_enqueue(thread, queue); + thread_timer_list_add(&m->timer, thread); if (t_ptr) { *t_ptr = thread; thread->ref = t_ptr; @@ -1055,7 +1043,6 @@ static void thread_cancel_rw(struct thread_master *master, int fd, short state) static void do_thread_cancel(struct thread_master *master) { struct thread_list_head *list = NULL; - struct pqueue *queue = NULL; struct thread **thread_array = NULL; struct thread *thread; @@ -1111,7 +1098,7 @@ static void do_thread_cancel(struct thread_master *master) thread_array = master->write; break; case THREAD_TIMER: - queue = master->timer; + thread_timer_list_del(&master->timer, thread); break; case THREAD_EVENT: list = &master->event; @@ -1124,16 +1111,10 @@ static void do_thread_cancel(struct thread_master *master) break; } - if (queue) { - assert(thread->index >= 0); - assert(thread == queue->array[thread->index]); - pqueue_remove_at(thread->index, queue); - } else if (list) { + if (list) { thread_list_del(list, thread); } else if (thread_array) { thread_array[thread->u.fd] = NULL; - } else { - assert(!"Thread should be either in queue or list or array!"); } if (thread->ref) @@ -1251,15 +1232,15 @@ void thread_cancel_async(struct thread_master *master, struct thread **thread, } /* ------------------------------------------------------------------------- */ -static struct timeval *thread_timer_wait(struct pqueue *queue, +static struct timeval *thread_timer_wait(struct thread_timer_list_head *timers, struct timeval *timer_val) { - if (queue->size) { - struct thread *next_timer = queue->array[0]; - monotime_until(&next_timer->u.sands, timer_val); - return timer_val; - } - return NULL; + if (!thread_timer_list_count(timers)) + return NULL; + + struct thread *next_timer = thread_timer_list_first(timers); + monotime_until(&next_timer->u.sands, timer_val); + return timer_val; } static struct thread *thread_run(struct thread_master *m, struct thread *thread, @@ -1369,17 +1350,16 @@ static void thread_process_io(struct thread_master *m, unsigned int num) } /* Add all timers that have popped to the ready list. */ -static unsigned int thread_process_timers(struct pqueue *queue, +static unsigned int thread_process_timers(struct thread_timer_list_head *timers, struct timeval *timenow) { struct thread *thread; unsigned int ready = 0; - while (queue->size) { - thread = queue->array[0]; + while ((thread = thread_timer_list_first(timers))) { if (timercmp(timenow, &thread->u.sands, <)) return ready; - pqueue_dequeue(queue); + thread_timer_list_pop(timers); thread->type = THREAD_READY; thread_list_add_tail(&thread->master->ready, thread); ready++; @@ -1461,7 +1441,7 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch) * once per loop to avoid starvation by events */ if (!thread_list_count(&m->ready)) - tw = thread_timer_wait(m->timer, &tv); + tw = thread_timer_wait(&m->timer, &tv); if (thread_list_count(&m->ready) || (tw && !timercmp(tw, &zerotime, >))) @@ -1506,7 +1486,7 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch) /* Post timers to ready queue. */ monotime(&now); - thread_process_timers(m->timer, &now); + thread_process_timers(&m->timer, &now); /* Post I/O to ready queue. */ if (num > 0) diff --git a/lib/thread.h b/lib/thread.h index 7897265120..412a4d93bf 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -41,8 +41,7 @@ struct rusage_t { #define GETRUSAGE(X) thread_getrusage(X) PREDECL_LIST(thread_list) - -struct pqueue; +PREDECL_HEAP(thread_timer_list) struct fd_handler { /* number of pfd that fit in the allocated space of pfds. This is a @@ -73,7 +72,7 @@ struct thread_master { struct thread **read; struct thread **write; - struct pqueue *timer; + struct thread_timer_list_head timer; struct thread_list_head event, ready, unuse; struct list *cancel_req; bool canceled; @@ -95,6 +94,7 @@ struct thread { uint8_t type; /* thread type */ uint8_t add_type; /* thread type */ struct thread_list_item threaditem; + struct thread_timer_list_item timeritem; struct thread **ref; /* external reference (if given) */ struct thread_master *master; /* pointer to the struct thread_master */ int (*func)(struct thread *); /* event function */ @@ -104,7 +104,6 @@ struct thread { int fd; /* file descriptor in case of r/w */ struct timeval sands; /* rest of time sands value. */ } u; - int index; /* queue position for timers */ struct timeval real; struct cpu_thread_history *hist; /* cache pointer to cpu_history */ unsigned long yield; /* yield time in microseconds */ diff --git a/lib/typerb.c b/lib/typerb.c index 4c48d6434f..3886fc678e 100644 --- a/lib/typerb.c +++ b/lib/typerb.c @@ -333,9 +333,10 @@ color: return (old); } -void typed_rb_remove(struct rbt_tree *rbt, struct rb_entry *rbe) +struct typed_rb_entry *typed_rb_remove(struct rbt_tree *rbt, + struct rb_entry *rbe) { - rbe_remove(rbt, rbe); + return rbe_remove(rbt, rbe); } struct typed_rb_entry *typed_rb_insert(struct rbt_tree *rbt, diff --git a/lib/typerb.h b/lib/typerb.h index ce8446f853..2d7b0ba637 100644 --- a/lib/typerb.h +++ b/lib/typerb.h @@ -38,29 +38,30 @@ struct typed_rb_root { size_t count; }; -struct typed_rb_entry *typed_rb_insert(struct typed_rb_root *, +struct typed_rb_entry *typed_rb_insert(struct typed_rb_root *rbt, struct typed_rb_entry *rbe, int (*cmpfn)( const struct typed_rb_entry *a, const struct typed_rb_entry *b)); -void typed_rb_remove(struct typed_rb_root *, struct typed_rb_entry *rbe); -struct typed_rb_entry *typed_rb_find(struct typed_rb_root *, +struct typed_rb_entry *typed_rb_remove(struct typed_rb_root *rbt, + struct typed_rb_entry *rbe); +struct typed_rb_entry *typed_rb_find(struct typed_rb_root *rbt, const struct typed_rb_entry *rbe, int (*cmpfn)( const struct typed_rb_entry *a, const struct typed_rb_entry *b)); -struct typed_rb_entry *typed_rb_find_gteq(struct typed_rb_root *, +struct typed_rb_entry *typed_rb_find_gteq(struct typed_rb_root *rbt, const struct typed_rb_entry *rbe, int (*cmpfn)( const struct typed_rb_entry *a, const struct typed_rb_entry *b)); -struct typed_rb_entry *typed_rb_find_lt(struct typed_rb_root *, +struct typed_rb_entry *typed_rb_find_lt(struct typed_rb_root *rbt, const struct typed_rb_entry *rbe, int (*cmpfn)( const struct typed_rb_entry *a, const struct typed_rb_entry *b)); -struct typed_rb_entry *typed_rb_min(struct typed_rb_root *); -struct typed_rb_entry *typed_rb_next(struct typed_rb_entry *); +struct typed_rb_entry *typed_rb_min(struct typed_rb_root *rbt); +struct typed_rb_entry *typed_rb_next(struct typed_rb_entry *rbe); #define _PREDECL_RBTREE(prefix) \ struct prefix ## _head { struct typed_rb_root rr; }; \ @@ -99,9 +100,11 @@ macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \ re = typed_rb_find_lt(&h->rr, &item->field.re, cmpfn_nuq); \ return container_of_null(re, type, field.re); \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ - typed_rb_remove(&h->rr, &item->field.re); \ + struct typed_rb_entry *re; \ + re = typed_rb_remove(&h->rr, &item->field.re); \ + return container_of_null(re, type, field.re); \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -130,7 +133,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ re = item ? typed_rb_next(&item->field.re) : NULL; \ return container_of_null(re, type, field.re); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->rr.count; \ } \ diff --git a/lib/typesafe.c b/lib/typesafe.c index f2ca67b7c6..7e5939d5b3 100644 --- a/lib/typesafe.c +++ b/lib/typesafe.c @@ -341,13 +341,14 @@ struct sskip_item *typesafe_skiplist_find_lt(struct sskip_head *head, return best; } -void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item, - int (*cmpfn)(const struct sskip_item *a, - const struct sskip_item *b)) +struct sskip_item *typesafe_skiplist_del( + struct sskip_head *head, struct sskip_item *item, + int (*cmpfn)(const struct sskip_item *a, const struct sskip_item *b)) { size_t level = SKIPLIST_MAXDEPTH; struct sskip_item *prev = &head->hitem, *next; int cmpval; + bool found = false; while (level) { next = sl_level_get(prev, level - 1); @@ -359,6 +360,7 @@ void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item, sl_level_set(prev, level - 1, sl_level_get(item, level - 1)); level--; + found = true; continue; } cmpval = cmpfn(next, item); @@ -369,6 +371,9 @@ void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item, level--; } + if (!found) + return NULL; + /* TBD: assert when trying to remove non-existing item? */ head->count--; @@ -379,6 +384,8 @@ void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item, XFREE(MTYPE_SKIPLIST_OFLOW, oflow); } memset(item, 0, sizeof(*item)); + + return item; } struct sskip_item *typesafe_skiplist_pop(struct sskip_head *head) diff --git a/lib/typesafe.h b/lib/typesafe.h index 0a4ed69e4e..c30d73d1b3 100644 --- a/lib/typesafe.h +++ b/lib/typesafe.h @@ -109,17 +109,18 @@ macro_inline void prefix ## _add_after(struct prefix##_head *h, \ typesafe_list_add(&h->sh, nextp, &item->field.si); \ } \ /* TODO: del_hint */ \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ struct slist_item **iter = &h->sh.first; \ while (*iter && *iter != &item->field.si) \ iter = &(*iter)->next; \ if (!*iter) \ - return; \ + return NULL; \ h->sh.count--; \ *iter = item->field.si.next; \ if (!item->field.si.next) \ h->sh.last_next = iter; \ + return item; \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -149,7 +150,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ sitem = &item->field.si; \ return container_of_null(sitem->next, type, field.si); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->sh.count; \ } \ @@ -212,13 +213,14 @@ macro_inline void prefix ## _add_after(struct prefix##_head *h, \ prev = after ? &after->field.di : &h->dh.hitem; \ typesafe_dlist_add(&h->dh, prev, &item->field.di); \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ struct dlist_item *ditem = &item->field.di; \ ditem->prev->next = ditem->next; \ ditem->next->prev = ditem->prev; \ h->dh.count--; \ ditem->prev = ditem->next = NULL; \ + return item; \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -250,7 +252,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ return NULL; \ return prefix ## _next(h, item); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->dh.count; \ } \ @@ -308,7 +310,7 @@ macro_inline type *prefix ## _add(struct prefix##_head *h, type *item) \ h->hh.count++; \ return NULL; \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ struct heap_item *other; \ uint32_t index = item->field.hi.index; \ @@ -321,6 +323,7 @@ macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ typesafe_heap_pushdown(&h->hh, index, other, prefix ## __cmp); \ if (HEAP_RESIZE_TRESH_DN(h)) \ typesafe_heap_resize(&h->hh, false); \ + return item; \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -354,7 +357,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ return NULL; \ return prefix ## _next(h, item); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->hh.count; \ } \ @@ -434,7 +437,7 @@ macro_inline type *prefix ## _find_gteq(struct prefix##_head *h, \ struct ssort_item *sitem = h->sh.first; \ int cmpval = 0; \ while (sitem && (cmpval = cmpfn_nuq( \ - container_of(sitem, type, field.si), item) < 0)) \ + container_of(sitem, type, field.si), item)) < 0) \ sitem = sitem->next; \ return container_of_null(sitem, type, field.si); \ } \ @@ -444,20 +447,21 @@ macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \ struct ssort_item *prev = NULL, *sitem = h->sh.first; \ int cmpval = 0; \ while (sitem && (cmpval = cmpfn_nuq( \ - container_of(sitem, type, field.si), item) < 0)) \ + container_of(sitem, type, field.si), item)) < 0) \ sitem = (prev = sitem)->next; \ return container_of_null(prev, type, field.si); \ } \ /* TODO: del_hint */ \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ struct ssort_item **iter = &h->sh.first; \ while (*iter && *iter != &item->field.si) \ iter = &(*iter)->next; \ if (!*iter) \ - return; \ + return NULL; \ h->sh.count--; \ *iter = item->field.si.next; \ + return item; \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -485,7 +489,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ sitem = &item->field.si; \ return container_of_null(sitem->next, type, field.si); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->sh.count; \ } \ @@ -499,7 +503,7 @@ macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \ struct ssort_item *sitem = h->sh.first; \ int cmpval = 0; \ while (sitem && (cmpval = cmpfn( \ - container_of(sitem, type, field.si), item) < 0)) \ + container_of(sitem, type, field.si), item)) < 0) \ sitem = sitem->next; \ if (!sitem || cmpval > 0) \ return NULL; \ @@ -617,10 +621,10 @@ macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \ } \ return NULL; \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ if (!h->hh.tabshift) \ - return; \ + return NULL; \ uint32_t hval = item->field.hi.hashval, hbits = HASH_KEY(h->hh, hval); \ struct thash_item **np = &h->hh.entries[hbits]; \ while (*np && (*np)->hashval < hval) \ @@ -628,12 +632,13 @@ macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ while (*np && *np != &item->field.hi && (*np)->hashval == hval) \ np = &(*np)->next; \ if (*np != &item->field.hi) \ - return; \ + return NULL; \ *np = item->field.hi.next; \ item->field.hi.next = NULL; \ h->hh.count--; \ if (HASH_SHRINK_THRESHOLD(h->hh)) \ typesafe_hash_shrink(&h->hh); \ + return item; \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -675,7 +680,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ return NULL; \ return prefix ## _next(h, item); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->hh.count; \ } \ @@ -751,9 +756,11 @@ macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \ &item->field.si, cmpfn_nuq); \ return container_of_null(sitem, type, field.si); \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ - typesafe_skiplist_del(&h->sh, &item->field.si, cmpfn_uq); \ + struct sskip_item *sitem = typesafe_skiplist_del(&h->sh, \ + &item->field.si, cmpfn_uq); \ + return container_of_null(sitem, type, field.si); \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -776,7 +783,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ next = item ? item->field.si.next[0] : NULL; \ return container_of_null(next, type, field.si); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->sh.count; \ } \ @@ -848,8 +855,8 @@ extern struct sskip_item *typesafe_skiplist_find_lt(struct sskip_head *head, const struct sskip_item *item, int (*cmpfn)( const struct sskip_item *a, const struct sskip_item *b)); -extern void typesafe_skiplist_del(struct sskip_head *head, - struct sskip_item *item, int (*cmpfn)( +extern struct sskip_item *typesafe_skiplist_del( + struct sskip_head *head, struct sskip_item *item, int (*cmpfn)( const struct sskip_item *a, const struct sskip_item *b)); extern struct sskip_item *typesafe_skiplist_pop(struct sskip_head *head); @@ -337,7 +337,8 @@ void vty_hello(struct vty *vty) /* work backwards to ignore trailling isspace() */ for (s = buf + strlen(buf); - (s > buf) && isspace((int)*(s - 1)); s--) + (s > buf) && isspace((unsigned char)s[-1]); + s--) ; *s = '\0'; vty_out(vty, "%s\n", buf); @@ -468,7 +469,7 @@ static int vty_command(struct vty *vty, char *buf) cp = buf; if (cp != NULL) { /* Skip white spaces. */ - while (isspace((int)*cp) && *cp != '\0') + while (isspace((unsigned char)*cp) && *cp != '\0') cp++; } if (cp != NULL && *cp != '\0') { @@ -892,7 +893,7 @@ static void vty_complete_command(struct vty *vty) return; /* In case of 'help \t'. */ - if (isspace((int)vty->buf[vty->length - 1])) + if (isspace((unsigned char)vty->buf[vty->length - 1])) vector_set(vline, NULL); matched = cmd_complete_command(vline, vty, &ret); @@ -1006,7 +1007,7 @@ static void vty_describe_command(struct vty *vty) if (vline == NULL) { vline = vector_init(1); vector_set(vline, NULL); - } else if (isspace((int)vty->buf[vty->length - 1])) + } else if (isspace((unsigned char)vty->buf[vty->length - 1])) vector_set(vline, NULL); describe = cmd_describe_command(vline, vty, &ret); diff --git a/lib/zebra.h b/lib/zebra.h index 22239f8e60..789a93a3c4 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -134,6 +134,10 @@ typedef unsigned char uint8_t; #endif #endif +#ifdef CRYPTO_OPENSSL +#include <openssl/evp.h> +#endif + #include "openbsd-tree.h" #include <netinet/in.h> @@ -356,6 +360,7 @@ typedef enum { /* Subsequent Address Family Identifier. */ typedef enum { + SAFI_UNSPEC = 0, SAFI_UNICAST = 1, SAFI_MULTICAST = 2, SAFI_MPLS_VPN = 3, diff --git a/m4/ax_python.m4 b/m4/ax_python.m4 index 32043c81ae..66338511a3 100644 --- a/m4/ax_python.m4 +++ b/m4/ax_python.m4 @@ -186,7 +186,11 @@ AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_MSG_RESULT([yes]) PYTHON_CFLAGS="`\"$pycfg\" --includes`" - PYTHON_LIBS="`\"$pycfg\" --ldflags`" + if test x"${py_ver}" == x"3.8" || test x"{py_ver}" == x"3.9"; then + PYTHON_LIBS="`\"$pycfg\" --ldflags --embed`" + else + PYTHON_LIBS="`\"$pycfg\" --ldflags`" + fi AC_MSG_CHECKING([whether ${pycfg} provides a working build environment]) _FRR_PYTHON_DEVENV([$py_hex], [ diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 946bbf8cc9..33b9f71b5f 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1018,7 +1018,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, unsigned int nexthop_num, struct in6_addr *nexthop, route_tag_t tag) { - int ret; + route_map_result_t ret; struct ospf6_route troute; struct ospf6_external_info tinfo; struct ospf6_route *route, *match; @@ -1355,7 +1355,7 @@ static void ospf6_redistribute_show_config(struct vty *vty) /* Routemap Functions */ -static route_map_result_t +static enum route_map_cmd_result_t ospf6_routemap_rule_match_address_prefixlist(void *rule, const struct prefix *prefix, route_map_object_t type, @@ -1395,7 +1395,7 @@ struct route_map_rule_cmd ospf6_routemap_rule_match_address_prefixlist_cmd = { /* `match interface IFNAME' */ /* Match function should return 1 if match is success else return zero. */ -static route_map_result_t +static enum route_map_cmd_result_t ospf6_routemap_rule_match_interface(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1433,10 +1433,9 @@ struct route_map_rule_cmd ospf6_routemap_rule_match_interface_cmd = { ospf6_routemap_rule_match_interface_free}; /* Match function for matching route tags */ -static route_map_result_t ospf6_routemap_rule_match_tag(void *rule, - const struct prefix *p, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +ospf6_routemap_rule_match_tag(void *rule, const struct prefix *p, + route_map_object_t type, void *object) { route_tag_t *tag = rule; struct ospf6_route *route = object; @@ -1453,7 +1452,7 @@ static struct route_map_rule_cmd ospf6_routemap_rule_match_tag_cmd = { route_map_rule_tag_free, }; -static route_map_result_t +static enum route_map_cmd_result_t ospf6_routemap_rule_set_metric_type(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1489,7 +1488,7 @@ struct route_map_rule_cmd ospf6_routemap_rule_set_metric_type_cmd = { ospf6_routemap_rule_set_metric_type_free, }; -static route_map_result_t +static enum route_map_cmd_result_t ospf6_routemap_rule_set_metric(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1524,7 +1523,7 @@ struct route_map_rule_cmd ospf6_routemap_rule_set_metric_cmd = { ospf6_routemap_rule_set_metric_free, }; -static route_map_result_t +static enum route_map_cmd_result_t ospf6_routemap_rule_set_forwarding(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1562,10 +1561,9 @@ struct route_map_rule_cmd ospf6_routemap_rule_set_forwarding_cmd = { ospf6_routemap_rule_set_forwarding_free, }; -static route_map_result_t ospf6_routemap_rule_set_tag(void *rule, - const struct prefix *p, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +ospf6_routemap_rule_set_tag(void *rule, const struct prefix *p, + route_map_object_t type, void *object) { route_tag_t *tag = rule; struct ospf6_route *route = object; diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index af16c5aa7c..8454016b2e 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -258,7 +258,7 @@ DEFUN (show_zebra, return CMD_SUCCESS; } - vty_out(vty, "Zebra Infomation\n"); + vty_out(vty, "Zebra Information\n"); vty_out(vty, " fail: %d\n", zclient->fail); vty_out(vty, " redistribute default: %d\n", vrf_bitmap_check(zclient->default_information[AFI_IP6], diff --git a/ospfd/ospf_errors.c b/ospfd/ospf_errors.c index dd02160195..a985efc668 100644 --- a/ospfd/ospf_errors.c +++ b/ospfd/ospf_errors.c @@ -39,7 +39,7 @@ static struct log_ref ferr_ospf_warn[] = { }, { .code = EC_OSPF_PACKET, - .title = "OSPF has detected packet information missmatch", + .title = "OSPF has detected packet information mismatch", .description = "OSPF has detected that packet information received is incorrect", .suggestion = "Ensure interface configuration is correct, gather log files from here and the peer and open an Issue", }, diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 6d1e44996e..1d85a04984 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -83,6 +83,9 @@ struct external_info *ospf_external_info_check(struct ospf *ospf, struct as_external_lsa *al; struct prefix_ipv4 p; struct route_node *rn; + struct list *ext_list; + struct listnode *node; + struct ospf_external *ext; int type; al = (struct as_external_lsa *)lsa->data; @@ -91,7 +94,7 @@ struct external_info *ospf_external_info_check(struct ospf *ospf, p.prefix = lsa->data->id; p.prefixlen = ip_masklen(al->mask); - for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { int redist_on = 0; redist_on = @@ -105,10 +108,6 @@ struct external_info *ospf_external_info_check(struct ospf *ospf, ospf->vrf_id)); // Pending: check for MI above. if (redist_on) { - struct list *ext_list; - struct listnode *node; - struct ospf_external *ext; - ext_list = ospf->external[type]; if (!ext_list) continue; @@ -129,6 +128,22 @@ struct external_info *ospf_external_info_check(struct ospf *ospf, } } + if (is_prefix_default(&p) && ospf->external[DEFAULT_ROUTE]) { + ext_list = ospf->external[DEFAULT_ROUTE]; + + for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) { + if (!ext->external_info) + continue; + + rn = route_node_lookup(ext->external_info, + (struct prefix *)&p); + if (!rn) + continue; + route_unlock_node(rn); + if (rn->info != NULL) + return (struct external_info *)rn->info; + } + } return NULL; } diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index bf46d22031..db41df7c47 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -1979,6 +1979,13 @@ struct ospf_lsa *ospf_external_lsa_originate(struct ospf *ospf, */ + if (ospf->router_id.s_addr == 0) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("LSA[Type5:%pI4]: deferring AS-external-LSA origination, router ID is zero", + &ei->p.prefix); + return NULL; + } + /* Check the AS-external-LSA should be originated. */ if (!ospf_redistribute_check(ospf, ei, NULL)) return NULL; @@ -2019,50 +2026,6 @@ struct ospf_lsa *ospf_external_lsa_originate(struct ospf *ospf, return new; } -/* Originate AS-external-LSA from external info with initial flag. */ -int ospf_external_lsa_originate_timer(struct thread *thread) -{ - struct ospf *ospf = THREAD_ARG(thread); - struct route_node *rn; - struct external_info *ei; - struct route_table *rt; - int type = THREAD_VAL(thread); - struct list *ext_list; - struct listnode *node; - struct ospf_external *ext; - - ospf->t_external_lsa = NULL; - - ext_list = ospf->external[type]; - if (!ext_list) - return 0; - - for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) { - /* Originate As-external-LSA from all type of distribute source. - */ - rt = ext->external_info; - if (!rt) - continue; - - for (rn = route_top(rt); rn; rn = route_next(rn)) { - ei = rn->info; - - if (!ei) - continue; - - if (is_prefix_default((struct prefix_ipv4 *)&ei->p)) - continue; - - if (!ospf_external_lsa_originate(ospf, ei)) - flog_warn( - EC_OSPF_LSA_INSTALL_FAILURE, - "LSA: AS-external-LSA was not originated."); - } - } - - return 0; -} - static struct external_info *ospf_default_external_info(struct ospf *ospf) { int type; @@ -2102,31 +2065,52 @@ static struct external_info *ospf_default_external_info(struct ospf *ospf) return NULL; } -int ospf_default_originate_timer(struct thread *thread) +void ospf_external_lsa_rid_change(struct ospf *ospf) { - struct prefix_ipv4 p; - struct in_addr nexthop; struct external_info *ei; - struct ospf *ospf; + int type; - ospf = THREAD_ARG(thread); + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { + struct route_node *rn; + struct route_table *rt; + struct list *ext_list; + struct listnode *node; + struct ospf_external *ext; - p.family = AF_INET; - p.prefix.s_addr = 0; - p.prefixlen = 0; + ext_list = ospf->external[type]; + if (!ext_list) + continue; - if (ospf->default_originate == DEFAULT_ORIGINATE_ALWAYS) { - /* If there is no default route via redistribute, - then originate AS-external-LSA with nexthop 0 (self). */ - nexthop.s_addr = 0; - ospf_external_info_add(ospf, DEFAULT_ROUTE, 0, p, 0, nexthop, - 0); - } + for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) { + /* Originate As-external-LSA from all type of + * distribute source. + */ + rt = ext->external_info; + if (!rt) + continue; - if ((ei = ospf_default_external_info(ospf))) - ospf_external_lsa_originate(ospf, ei); + for (rn = route_top(rt); rn; rn = route_next(rn)) { + ei = rn->info; - return 0; + if (!ei) + continue; + + if (is_prefix_default( + (struct prefix_ipv4 *)&ei->p)) + continue; + + if (!ospf_external_lsa_originate(ospf, ei)) + flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, + "LSA: AS-external-LSA was not originated."); + } + } + } + + ei = ospf_default_external_info(ospf); + if (ei && !ospf_external_lsa_originate(ospf, ei)) { + flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, + "LSA: AS-external-LSA for default route was not originated."); + } } /* Flush any NSSA LSAs for given prefix */ @@ -2218,44 +2202,20 @@ void ospf_external_lsa_refresh_default(struct ospf *ospf) ei = ospf_default_external_info(ospf); lsa = ospf_external_info_find_lsa(ospf, &p); - if (ei) { - if (lsa) { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p", - (void *)lsa); - ospf_external_lsa_refresh(ospf, lsa, ei, - LSA_REFRESH_FORCE); - } else { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "LSA[Type5:0.0.0.0]: Originate AS-external-LSA"); - ospf_external_lsa_originate(ospf, ei); - } - } else { - if (lsa) { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "LSA[Type5:0.0.0.0]: Flush AS-external-LSA"); - ospf_refresher_unregister_lsa(ospf, lsa); - ospf_lsa_flush_as(ospf, lsa); - } - } -} - -void ospf_default_originate_lsa_update(struct ospf *ospf) -{ - struct prefix_ipv4 p; - struct ospf_lsa *lsa; - - p.family = AF_INET; - p.prefixlen = 0; - p.prefix.s_addr = 0; - - lsa = ospf_external_info_find_lsa(ospf, &p); - if (lsa && IS_LSA_MAXAGE(lsa)) { - ospf_discard_from_db(ospf, lsa->lsdb, lsa); - ospf_lsdb_delete(lsa->lsdb, lsa); + if (ei && lsa) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p", + (void *)lsa); + ospf_external_lsa_refresh(ospf, lsa, ei, LSA_REFRESH_FORCE); + } else if (ei && !lsa) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "LSA[Type5:0.0.0.0]: Originate AS-external-LSA"); + ospf_external_lsa_originate(ospf, ei); + } else if (lsa) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("LSA[Type5:0.0.0.0]: Flush AS-external-LSA"); + ospf_external_lsa_flush(ospf, DEFAULT_ROUTE, &p, 0); } } diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index 5e3dabc27a..4033659bff 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -275,8 +275,7 @@ extern struct in_addr ospf_get_ip_from_ifp(struct ospf_interface *); extern struct ospf_lsa *ospf_external_lsa_originate(struct ospf *, struct external_info *); -extern int ospf_external_lsa_originate_timer(struct thread *); -extern int ospf_default_originate_timer(struct thread *); +extern void ospf_external_lsa_rid_change(struct ospf *ospf); extern struct ospf_lsa *ospf_lsa_lookup(struct ospf *ospf, struct ospf_area *, uint32_t, struct in_addr, struct in_addr); @@ -301,7 +300,6 @@ extern int ospf_lsa_maxage_walker(struct thread *); extern struct ospf_lsa *ospf_lsa_refresh(struct ospf *, struct ospf_lsa *); extern void ospf_external_lsa_refresh_default(struct ospf *); -extern void ospf_default_originate_lsa_update(struct ospf *ospf); extern void ospf_external_lsa_refresh_type(struct ospf *, uint8_t, unsigned short, int); diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index f7c73fee33..ee27ec0942 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -616,8 +616,6 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state) struct ospf_interface *oi = nbr->oi; struct ospf_area *vl_area = NULL; uint8_t old_state; - int x; - int force = 1; /* Preserve old status. */ old_state = nbr->state; @@ -664,32 +662,6 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state) if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area) if (++vl_area->full_vls == 1) ospf_schedule_abr_task(oi->ospf); - - /* kevinm: refresh any redistributions */ - for (x = ZEBRA_ROUTE_SYSTEM; x < ZEBRA_ROUTE_MAX; x++) { - struct list *red_list; - struct listnode *node; - struct ospf_redist *red; - - if (x == ZEBRA_ROUTE_OSPF6) - continue; - - red_list = oi->ospf->redist[x]; - if (!red_list) - continue; - - for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) - ospf_external_lsa_refresh_type( - oi->ospf, x, red->instance, - force); - } - /* XXX: Clearly some thing is wrong with refresh of - * external LSAs - * this added to hack around defaults not refreshing - * after a timer - * jump. - */ - ospf_external_lsa_refresh_default(oi->ospf); } else { oi->full_nbrs--; oi->area->full_nbrs--; diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 50c30a6fa0..62b0444796 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -33,7 +33,9 @@ #include "log.h" #include "sockopt.h" #include "checksum.h" +#ifdef CRYPTO_INTERNAL #include "md5.h" +#endif #include "vrf.h" #include "lib_errors.h" @@ -332,7 +334,11 @@ static unsigned int ospf_packet_max(struct ospf_interface *oi) static int ospf_check_md5_digest(struct ospf_interface *oi, struct ospf_header *ospfh) { +#ifdef CRYPTO_OPENSSL + EVP_MD_CTX *ctx; +#elif CRYPTO_INTERNAL MD5_CTX ctx; +#endif unsigned char digest[OSPF_AUTH_MD5_SIZE]; struct crypt_key *ck; struct ospf_neighbor *nbr; @@ -361,11 +367,21 @@ static int ospf_check_md5_digest(struct ospf_interface *oi, } /* Generate a digest for the ospf packet - their digest + our digest. */ +#ifdef CRYPTO_OPENSSL + unsigned int md5_size = OSPF_AUTH_MD5_SIZE; + ctx = EVP_MD_CTX_new(); + EVP_DigestInit(ctx, EVP_md5()); + EVP_DigestUpdate(ctx, ospfh, length); + EVP_DigestUpdate(ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE); + EVP_DigestFinal(ctx, digest, &md5_size); + EVP_MD_CTX_free(ctx); +#elif CRYPTO_INTERNAL memset(&ctx, 0, sizeof(ctx)); MD5Init(&ctx); MD5Update(&ctx, ospfh, length); MD5Update(&ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE); MD5Final(digest, &ctx); +#endif /* compare the two */ if (memcmp((caddr_t)ospfh + length, digest, OSPF_AUTH_MD5_SIZE)) { @@ -389,7 +405,11 @@ static int ospf_make_md5_digest(struct ospf_interface *oi, { struct ospf_header *ospfh; unsigned char digest[OSPF_AUTH_MD5_SIZE] = {0}; +#ifdef CRYPTO_OPENSSL + EVP_MD_CTX *ctx; +#elif CRYPTO_INTERNAL MD5_CTX ctx; +#endif void *ibuf; uint32_t t; struct crypt_key *ck; @@ -422,11 +442,21 @@ static int ospf_make_md5_digest(struct ospf_interface *oi, } /* Generate a digest for the entire packet + our secret key. */ +#ifdef CRYPTO_OPENSSL + unsigned int md5_size = OSPF_AUTH_MD5_SIZE; + ctx = EVP_MD_CTX_new(); + EVP_DigestInit(ctx, EVP_md5()); + EVP_DigestUpdate(ctx, ibuf, ntohs(ospfh->length)); + EVP_DigestUpdate(ctx, auth_key, OSPF_AUTH_MD5_SIZE); + EVP_DigestFinal(ctx, digest, &md5_size); + EVP_MD_CTX_free(ctx); +#elif CRYPTO_INTERNAL memset(&ctx, 0, sizeof(ctx)); MD5Init(&ctx); MD5Update(&ctx, ibuf, ntohs(ospfh->length)); MD5Update(&ctx, auth_key, OSPF_AUTH_MD5_SIZE); MD5Final(digest, &ctx); +#endif /* Append md5 digest to the end of the stream. */ stream_put(op->s, digest, OSPF_AUTH_MD5_SIZE); diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c index bb7e97bf7b..1669c817e6 100644 --- a/ospfd/ospf_routemap.c +++ b/ospfd/ospf_routemap.c @@ -126,10 +126,9 @@ static void ospf_route_map_event(const char *name) /* `match ip netxthop ' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_ip_nexthop(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_ip_nexthop(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct access_list *alist; struct external_info *ei = object; @@ -171,7 +170,7 @@ struct route_map_rule_cmd route_match_ip_nexthop_cmd = { /* `match ip next-hop prefix-list PREFIX_LIST' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -212,7 +211,7 @@ struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = { /* `match ip next-hop type <blackhole>' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ip_next_hop_type(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -221,7 +220,7 @@ route_match_ip_next_hop_type(void *rule, const struct prefix *prefix, if (type == RMAP_OSPF && prefix->family == AF_INET) { ei = (struct external_info *)object; if (!ei) - return RMAP_DENYMATCH; + return RMAP_NOMATCH; if (ei->nexthop.s_addr == INADDR_ANY && !ei->ifindex) return RMAP_MATCH; @@ -247,10 +246,9 @@ static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = { /* `match ip address IP_ACCESS_LIST' */ /* Match function should return 1 if match is success else return zero. */ -static route_map_result_t route_match_ip_address(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_ip_address(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct access_list *alist; /* struct prefix_ipv4 match; */ @@ -286,7 +284,7 @@ struct route_map_rule_cmd route_match_ip_address_cmd = { route_match_ip_address_free}; /* `match ip address prefix-list PREFIX_LIST' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -322,10 +320,9 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { /* `match interface IFNAME' */ /* Match function should return 1 if match is success else return zero. */ -static route_map_result_t route_match_interface(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_interface(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct interface *ifp; struct external_info *ei; @@ -361,9 +358,9 @@ struct route_map_rule_cmd route_match_interface_cmd = { route_match_interface_free}; /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_tag(void *rule, - const struct prefix *prefix, - route_map_object_t type, void *object) +static enum route_map_cmd_result_t +route_match_tag(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { route_tag_t *tag; struct external_info *ei; @@ -392,10 +389,9 @@ struct ospf_metric { /* `set metric METRIC' */ /* Set metric to attribute. */ -static route_map_result_t route_set_metric(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_metric(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct ospf_metric *metric; struct external_info *ei; @@ -473,10 +469,9 @@ struct route_map_rule_cmd route_set_metric_cmd = { /* `set metric-type TYPE' */ /* Set metric-type to attribute. */ -static route_map_result_t route_set_metric_type(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_metric_type(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { uint32_t *metric_type; struct external_info *ei; @@ -523,8 +518,9 @@ struct route_map_rule_cmd route_set_metric_type_cmd = { route_set_metric_type_free, }; -static route_map_result_t route_set_tag(void *rule, const struct prefix *prefix, - route_map_object_t type, void *object) +static enum route_map_cmd_result_t +route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type, + void *object) { route_tag_t *tag; struct external_info *ei; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 98ddd6a79e..2564c6f330 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -8487,22 +8487,8 @@ DEFUN (no_ospf_default_information_originate, "Pointer to route-map entries\n") { VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - struct prefix_ipv4 p; - struct ospf_external *ext; struct ospf_redist *red; - p.family = AF_INET; - p.prefix.s_addr = 0; - p.prefixlen = 0; - - ospf_external_lsa_flush(ospf, DEFAULT_ROUTE, &p, 0); - - ext = ospf_external_lookup(ospf, DEFAULT_ROUTE, 0); - if (ext && EXTERNAL_INFO(ext)) { - ospf_external_info_delete(ospf, DEFAULT_ROUTE, 0, p); - ospf_external_del(ospf, DEFAULT_ROUTE, 0); - } - red = ospf_redist_lookup(ospf, DEFAULT_ROUTE, 0); if (!red) return CMD_SUCCESS; @@ -8510,7 +8496,8 @@ DEFUN (no_ospf_default_information_originate, ospf_routemap_unset(red); ospf_redist_del(ospf, DEFAULT_ROUTE, 0); - return ospf_redistribute_default_unset(ospf); + return ospf_redistribute_default_set(ospf, DEFAULT_ORIGINATE_NONE, + 0, 0); } DEFUN (ospf_default_metric, diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index c178e367d3..b478832d84 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -744,10 +744,10 @@ int ospf_redistribute_unset(struct ospf *ospf, int type, int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype, int mvalue) { - struct ospf_external *ext; struct prefix_ipv4 p; struct in_addr nexthop; int cur_originate = ospf->default_originate; + const char *type_str = NULL; nexthop.s_addr = 0; p.family = AF_INET; @@ -756,41 +756,7 @@ int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype, ospf->default_originate = originate; - ospf_external_add(ospf, DEFAULT_ROUTE, 0); - - if (cur_originate == DEFAULT_ORIGINATE_NONE) { - /* First time configuration */ - if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug("Redistribute[DEFAULT]: Start Type[%d], Metric[%d]", - metric_type(ospf, DEFAULT_ROUTE, 0), - metric_value(ospf, DEFAULT_ROUTE, 0)); - - if (ospf->router_id.s_addr == 0) - ospf->external_origin |= (1 << DEFAULT_ROUTE); - if ((originate == DEFAULT_ORIGINATE_ALWAYS) - && (ospf->router_id.s_addr)) { - - /* always , so originate lsa even it doesn't - * exist in RIB. - */ - ospf_external_info_add(ospf, DEFAULT_ROUTE, 0, - p, 0, nexthop, 0); - ospf_external_lsa_refresh_default(ospf); - - } else if (originate == DEFAULT_ORIGINATE_ZEBRA) { - /* Send msg to Zebra to validate default route - * existance. - */ - zclient_redistribute_default( - ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient, AFI_IP, - ospf->vrf_id); - } - - ospf_asbr_status_update(ospf, ++ospf->redistribute); - return CMD_SUCCESS; - - - } else if (originate == cur_originate) { + if (cur_originate == originate) { /* Refresh the lsa since metric might different */ if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) zlog_debug( @@ -800,67 +766,51 @@ int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype, metric_value(ospf, DEFAULT_ROUTE, 0)); ospf_external_lsa_refresh_default(ospf); - - } else { - /* "default-info originate always" configured now, - * where "default-info originate" configured previoulsly. - */ - if (originate == DEFAULT_ORIGINATE_ALWAYS) { - - zclient_redistribute_default( - ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, - zclient, AFI_IP, ospf->vrf_id); - /* here , ex-info should be added since ex-info might - * have not updated earlier if def route is not exist. - * If ex-iinfo ex-info already exist , it will return - * smoothly. - */ - ospf_external_info_add(ospf, DEFAULT_ROUTE, 0, - p, 0, nexthop, 0); - ospf_external_lsa_refresh_default(ospf); - - } else { - /* "default-info originate" configured now,where - * "default-info originate always" configured - * previoulsy. - */ - - ospf_external_lsa_flush(ospf, DEFAULT_ROUTE, &p, 0); - - ext = ospf_external_lookup(ospf, DEFAULT_ROUTE, 0); - if (ext && EXTERNAL_INFO(ext)) - ospf_external_info_delete(ospf, - DEFAULT_ROUTE, 0, p); - - zclient_redistribute_default( - ZEBRA_REDISTRIBUTE_DEFAULT_ADD, - zclient, AFI_IP, ospf->vrf_id); - } + return CMD_SUCCESS; } - return CMD_SUCCESS; -} -int ospf_redistribute_default_unset(struct ospf *ospf) -{ - if (ospf->default_originate == DEFAULT_ORIGINATE_ZEBRA) { - if (!ospf_is_type_redistributed(ospf, DEFAULT_ROUTE, 0)) - return CMD_SUCCESS; + switch (cur_originate) { + case DEFAULT_ORIGINATE_NONE: + break; + case DEFAULT_ORIGINATE_ZEBRA: zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, zclient, AFI_IP, ospf->vrf_id); + ospf->redistribute--; + break; + case DEFAULT_ORIGINATE_ALWAYS: + ospf_external_info_delete(ospf, DEFAULT_ROUTE, 0, p); + ospf_external_del(ospf, DEFAULT_ROUTE, 0); + ospf->redistribute--; + break; } - ospf->default_originate = DEFAULT_ORIGINATE_NONE; + switch (originate) { + case DEFAULT_ORIGINATE_NONE: + type_str = "none"; + break; + case DEFAULT_ORIGINATE_ZEBRA: + type_str = "normal"; + ospf->redistribute++; + zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD, + zclient, AFI_IP, ospf->vrf_id); + break; + case DEFAULT_ORIGINATE_ALWAYS: + type_str = "always"; + ospf->redistribute++; + ospf_external_add(ospf, DEFAULT_ROUTE, 0); + ospf_external_info_add(ospf, DEFAULT_ROUTE, 0, p, 0, nexthop, + 0); + break; + } if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug("Redistribute[DEFAULT]: Stop"); - - // Pending: how does the external_info cleanup work in this case? - - ospf_asbr_status_update(ospf, --ospf->redistribute); - - /* clean up maxage default originate external lsa */ - ospf_default_originate_lsa_update(ospf); + zlog_debug("Redistribute[DEFAULT]: %s Type[%d], Metric[%d]", + type_str, + metric_type(ospf, DEFAULT_ROUTE, 0), + metric_value(ospf, DEFAULT_ROUTE, 0)); + ospf_external_lsa_refresh_default(ospf); + ospf_asbr_status_update(ospf, ospf->redistribute); return CMD_SUCCESS; } @@ -943,7 +893,7 @@ int ospf_redistribute_check(struct ospf *ospf, struct external_info *ei, /* apply route-map if needed */ red = ospf_redist_lookup(ospf, type, instance); if (red && ROUTEMAP_NAME(red)) { - int ret; + route_map_result_t ret; ret = route_map_apply(ROUTEMAP(red), (struct prefix *)p, RMAP_OSPF, ei); @@ -1033,7 +983,8 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS) char buf_prefix[PREFIX_STRLEN]; prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix)); - zlog_debug("%s: from client %s: vrf_id %d, p %s", __func__, + zlog_debug("%s: cmd %s from client %s: vrf_id %d, p %s", + __func__, zserv_command_string(cmd), zebra_route_string(api.type), vrf_id, buf_prefix); } @@ -1067,11 +1018,7 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS) /* Nothing has changed, so nothing to do; return */ return 0; } - if (ospf->router_id.s_addr == 0) - /* Set flags to generate AS-external-LSA originate event - for each redistributed protocols later. */ - ospf->external_origin |= (1 << rt_type); - else { + if (ospf->router_id.s_addr != 0) { if (ei) { if (is_prefix_default(&p)) ospf_external_lsa_refresh_default(ospf); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index a64ddbc3b7..b91a55f635 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -91,7 +91,6 @@ void ospf_router_id_update(struct ospf *ospf) struct ospf_interface *oi; struct interface *ifp; struct listnode *node; - int type; if (!ospf->oi_running) { if (IS_DEBUG_OSPF_EVENT) @@ -135,24 +134,6 @@ void ospf_router_id_update(struct ospf *ospf) ospf_nbr_self_reset(oi, router_id); } - /* If AS-external-LSA is queued, then flush those LSAs. */ - if (router_id_old.s_addr == 0 && ospf->external_origin) { - /* Originate each redistributed external route. */ - for (type = 0; type < ZEBRA_ROUTE_MAX; type++) - if (ospf->external_origin & (1 << type)) - thread_add_event( - master, - ospf_external_lsa_originate_timer, - ospf, type, NULL); - /* Originate Deafult. */ - if (ospf->external_origin & (1 << ZEBRA_ROUTE_MAX)) - thread_add_event(master, - ospf_default_originate_timer, - ospf, 0, NULL); - - ospf->external_origin = 0; - } - /* Flush (inline) all external LSAs based on the OSPF_LSA_SELF * flag */ if (ospf->lsdb) { @@ -196,20 +177,14 @@ void ospf_router_id_update(struct ospf *ospf) } } - /* Originate each redistributed external route. */ - for (type = 0; type < ZEBRA_ROUTE_MAX; type++) - thread_add_event(master, - ospf_external_lsa_originate_timer, - ospf, type, NULL); - thread_add_event(master, ospf_default_originate_timer, ospf, 0, - NULL); - /* update router-lsa's for each area */ ospf_router_lsa_update(ospf); /* update ospf_interface's */ FOR_ALL_INTERFACES (vrf, ifp) ospf_if_update(ospf, ifp); + + ospf_external_lsa_rid_change(ospf); } } @@ -633,7 +608,7 @@ static void ospf_finish_final(struct ospf *ospf) ospf_redist_del(ospf, i, red->instance); } } - ospf_redistribute_default_unset(ospf); + ospf_redistribute_default_set(ospf, DEFAULT_ORIGINATE_NONE, 0, 0); for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) ospf_remove_vls_through_area(ospf, area); @@ -702,7 +677,6 @@ static void ospf_finish_final(struct ospf *ospf) /* Cancel all timers. */ OSPF_TIMER_OFF(ospf->t_read); OSPF_TIMER_OFF(ospf->t_write); - OSPF_TIMER_OFF(ospf->t_external_lsa); OSPF_TIMER_OFF(ospf->t_spf_calc); OSPF_TIMER_OFF(ospf->t_ase_calc); OSPF_TIMER_OFF(ospf->t_maxage); diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index cbea033b73..b31ad30375 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -202,7 +202,6 @@ struct ospf { struct ospf_lsdb *lsdb; /* Flags. */ - int external_origin; /* AS-external-LSA origin flag. */ int ase_calc; /* ASE calculation flag. */ struct list *opaque_lsa_self; /* Type-11 Opaque-LSAs */ @@ -233,7 +232,6 @@ struct ospf { struct thread *t_distribute_update; /* Distirbute list update timer. */ struct thread *t_spf_calc; /* SPF calculation timer. */ struct thread *t_ase_calc; /* ASE calculation timer. */ - struct thread *t_external_lsa; /* AS-external-LSA origin timer. */ struct thread *t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */ struct thread *t_sr_update; /* Segment Routing update timer */ diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index a69bb00848..57e8cf5742 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -227,7 +227,6 @@ void pbr_nhgroup_add_cb(const char *name) DEBUGD(&pbr_dbg_nht, "%s: Added nexthop-group %s", __PRETTY_FUNCTION__, name); - pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg); pbr_map_check_nh_group_change(name); } diff --git a/pbrd/pbrd.conf.sample b/pbrd/pbrd.conf.sample index bb1c2edca8..c9e7dce01f 100644 --- a/pbrd/pbrd.conf.sample +++ b/pbrd/pbrd.conf.sample @@ -1,3 +1,19 @@ +! Sample pbrd configuration file +! +! A quick example of what a pbr configuration might look like ! ! log stdout +! +! nexthop-group TEST +! nexthop 4.5.6.7 +! nexthop 5.6.7.8 +! ! +! pbr-map BLUE seq 100 +! match dst-ip 9.9.9.0/24 +! match src-ip 10.10.10.0/24 +! set nexthop-group TEST +! ! +! int swp1 +! pbr-policy BLUE +! diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c index 62f13b5b53..675092dbec 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -711,11 +711,11 @@ static bool pim_bsm_frag_send(uint8_t *buf, uint32_t len, struct interface *ifp, /* MTU passed here is PIM MTU (IP MTU less IP Hdr) */ if (pim_mtu < (PIM_MIN_BSM_LEN)) { zlog_warn( - "%s: mtu(pim mtu: %d) size less than minimum bootsrap len", + "%s: mtu(pim mtu: %d) size less than minimum bootstrap len", __PRETTY_FUNCTION__, pim_mtu); if (PIM_DEBUG_BSM) zlog_debug( - "%s: mtu (pim mtu:%d) less than minimum bootsrap len", + "%s: mtu (pim mtu:%d) less than minimum bootstrap len", __PRETTY_FUNCTION__, pim_mtu); return false; } diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index b1c55c1f43..1c66007fbb 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -190,8 +190,6 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, sg.grp = msg->im_dst; if (!(PIM_I_am_DR(pim_ifp))) { - struct channel_oil *c_oil; - if (PIM_DEBUG_MROUTE_DETAIL) zlog_debug("%s: Interface is not the DR blackholing incoming traffic for %s", __PRETTY_FUNCTION__, pim_str_sg_dump(&sg)); @@ -206,10 +204,10 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, * that I see no way to get rid of. Just noting * this for future reference. */ - c_oil = pim_channel_oil_add(pim_ifp->pim, &sg, - pim_ifp->mroute_vif_index, - __PRETTY_FUNCTION__); - pim_mroute_add(c_oil, __PRETTY_FUNCTION__); + up = pim_upstream_find_or_add( + &sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE, + __PRETTY_FUNCTION__); + pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); return 0; } @@ -238,7 +236,8 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, vif_index = pim_if_find_vifindex_by_ifindex( pim_ifp->pim, up->rpf.source_nexthop.interface->ifindex); - up->channel_oil->oil.mfcc_parent = vif_index; + pim_channel_oil_change_iif(pim_ifp->pim, up->channel_oil, + vif_index, __PRETTY_FUNCTION__); } pim_register_join(up); @@ -453,7 +452,6 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, struct pim_upstream *up; struct prefix_sg star_g; struct prefix_sg sg; - struct channel_oil *oil; pim_ifp = ifp->info; @@ -517,11 +515,7 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, up->upstream_register); up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE; } - if (!up->channel_oil) - up->channel_oil = pim_channel_oil_add( - pim_ifp->pim, &sg, - pim_ifp->mroute_vif_index, - __PRETTY_FUNCTION__); + pim_upstream_inherited_olist(pim_ifp->pim, up); if (!up->channel_oil->installed) pim_mroute_add(up->channel_oil, @@ -546,10 +540,6 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, } pim_ifp = ifp->info; - oil = pim_channel_oil_add(pim_ifp->pim, &sg, pim_ifp->mroute_vif_index, - __PRETTY_FUNCTION__); - if (!oil->installed) - pim_mroute_add(oil, __PRETTY_FUNCTION__); if (pim_if_connected_to_source(ifp, sg.src)) { up = pim_upstream_add(pim_ifp->pim, &sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR, @@ -564,13 +554,18 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags); pim_upstream_keep_alive_timer_start( up, pim_ifp->pim->keep_alive_time); - up->channel_oil = oil; up->channel_oil->cc.pktcnt++; pim_register_join(up); pim_upstream_inherited_olist(pim_ifp->pim, up); // Send the packet to the RP pim_mroute_msg_wholepkt(fd, ifp, buf); + } else { + up = pim_upstream_add(pim_ifp->pim, &sg, ifp, + PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE, + __PRETTY_FUNCTION__, NULL); + if (!up->channel_oil->installed) + pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); } return 0; diff --git a/pimd/pim_msg.h b/pimd/pim_msg.h index b6e2cada1f..2d69a4b03a 100644 --- a/pimd/pim_msg.h +++ b/pimd/pim_msg.h @@ -42,7 +42,7 @@ enum pim_msg_address_family { }; /* - * Network Order pim_msg_hdr + * pim_msg_hdr * ========================= * PIM Header definition as per RFC 5059. N bit introduced to indicate * do-not-forward option in PIM Boot strap Message. @@ -53,10 +53,19 @@ enum pim_msg_address_family { * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ struct pim_msg_header { +#if (BYTE_ORDER == LITTLE_ENDIAN) uint8_t type : 4; uint8_t ver : 4; + uint8_t reserved : 7; + uint8_t Nbit : 1; /* No Fwd Bit */ +#elif (BYTE_ORDER == BIG_ENDIAN) + uint8_t ver : 4; + uint8_t type : 4; uint8_t Nbit : 1; /* No Fwd Bit */ uint8_t reserved : 7; +#else +#error"Please set byte order" +#endif uint16_t checksum; } __attribute__((packed)); @@ -79,9 +88,17 @@ struct pim_encoded_ipv4_unicast { struct pim_encoded_group_ipv4 { uint8_t family; uint8_t ne; +#if (BYTE_ORDER == LITTLE_ENDIAN) + uint8_t sz : 1; /* scope zone bit */ + uint8_t reserved : 6; /* Reserved */ + uint8_t bidir : 1; /* Bidir bit */ +#elif (BYTE_ORDER == BIG_ENDIAN) uint8_t bidir : 1; /* Bidir bit */ uint8_t reserved : 6; /* Reserved */ uint8_t sz : 1; /* scope zone bit */ +#else +#error"Please set byte order" +#endif uint8_t mask; struct in_addr addr; } __attribute__((packed)); diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index a63b09fc1f..722ecb2a72 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -424,10 +424,11 @@ struct pim_neighbor *pim_neighbor_find_by_secondary(struct interface *ifp, struct pim_neighbor *neigh; struct prefix *p; - pim_ifp = ifp->info; - if (!pim_ifp) + if (!ifp || !ifp->info) return NULL; + pim_ifp = ifp->info; + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, pnode, p)) { if (prefix_same(p, src)) diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 65ea858cb6..7900e39231 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -479,7 +479,7 @@ static int pim_update_upstream_nh_helper(struct hash_bucket *bucket, void *arg) zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s", __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name, old.source_nexthop.interface - ? old.source_nexthop.interface->name : "Unknwon", + ? old.source_nexthop.interface->name : "Unknown", up->rpf.source_nexthop.interface->name); } @@ -842,6 +842,14 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS) } if (!ifp->info) { + /* + * Though Multicast is not enabled on this + * Interface store it in database otheriwse we + * may miss this update and this will not cause + * any issue, because while choosing the path we + * are ommitting the Interfaces which are not + * multicast enabled + */ if (PIM_DEBUG_PIM_NHT) { char buf[NEXTHOP_STRLEN]; @@ -853,8 +861,6 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS) nexthop2str(nexthop, buf, sizeof(buf))); } - nexthop_free(nexthop); - continue; } if (nhlist_tail) { diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index d4fc03e20c..d142934916 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -146,6 +146,43 @@ struct channel_oil *pim_find_channel_oil(struct pim_instance *pim, return c_oil; } +void pim_channel_oil_change_iif(struct pim_instance *pim, + struct channel_oil *c_oil, + int input_vif_index, + const char *name) +{ + int old_vif_index = c_oil->oil.mfcc_parent; + struct prefix_sg sg = {.src = c_oil->oil.mfcc_mcastgrp, + .grp = c_oil->oil.mfcc_origin}; + + if (c_oil->oil.mfcc_parent == input_vif_index) { + if (PIM_DEBUG_MROUTE_DETAIL) + zlog_debug("%s(%s): Existing channel oil %pSG4 already using %d as IIF", + __PRETTY_FUNCTION__, name, &sg, + input_vif_index); + + return; + } + + if (PIM_DEBUG_MROUTE_DETAIL) + zlog_debug("%s(%s): Changing channel oil %pSG4 IIF from %d to %d installed: %d", + __PRETTY_FUNCTION__, name, &sg, + c_oil->oil.mfcc_parent, input_vif_index, + c_oil->installed); + + c_oil->oil.mfcc_parent = input_vif_index; + if (c_oil->installed) { + if (input_vif_index == MAXVIFS) + pim_mroute_del(c_oil, name); + else + pim_mroute_add(c_oil, name); + } else + if (old_vif_index == MAXVIFS) + pim_mroute_add(c_oil, name); + + return; +} + struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, struct prefix_sg *sg, int input_vif_index, const char *name) @@ -164,7 +201,8 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, c_oil->oil.mfcc_parent, input_vif_index); } - c_oil->oil.mfcc_parent = input_vif_index; + pim_channel_oil_change_iif(pim, c_oil, input_vif_index, + name); ++c_oil->oil_ref_count; /* channel might be present prior to upstream */ c_oil->up = pim_upstream_find(pim, sg); diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h index 485299196d..319a1c91a3 100644 --- a/pimd/pim_oil.h +++ b/pimd/pim_oil.h @@ -114,6 +114,9 @@ struct channel_oil *pim_find_channel_oil(struct pim_instance *pim, struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, struct prefix_sg *sg, int input_vif_index, const char *name); +void pim_channel_oil_change_iif(struct pim_instance *pim, + struct channel_oil *c_oil, int input_vif_index, + const char *name); void pim_channel_oil_del(struct channel_oil *c_oil, const char *name); int pim_channel_add_oif(struct channel_oil *c_oil, struct interface *oif, diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index 7d263e99e3..357ad6ba46 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -307,11 +307,11 @@ void pim_upstream_rpf_clear(struct pim_instance *pim, struct pim_upstream *up) { if (up->rpf.source_nexthop.interface) { - if (up->channel_oil) { - up->channel_oil->oil.mfcc_parent = MAXVIFS; - pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__); + if (up->channel_oil) + pim_channel_oil_change_iif(pim, up->channel_oil, + MAXVIFS, + __PRETTY_FUNCTION__); - } pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED); up->rpf.source_nexthop.interface = NULL; up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = diff --git a/pimd/pim_static.c b/pimd/pim_static.c index 62c3216e86..e3138360c8 100644 --- a/pimd/pim_static.c +++ b/pimd/pim_static.c @@ -138,7 +138,9 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif, } else { /* input interface changed */ s_route->iif = iif_index; - s_route->c_oil.oil.mfcc_parent = iif_index; + pim_channel_oil_change_iif(pim, &s_route->c_oil, + iif_index, + __PRETTY_FUNCTION__); #ifdef PIM_ENFORCE_LOOPFREE_MFC /* check to make sure the new input was not an diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 50df2fdbf9..c0651561ac 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -716,7 +716,8 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, up->join_state = PIM_UPSTREAM_NOTJOINED; up->reg_state = PIM_REG_NOINFO; up->state_transition = pim_time_monotonic_sec(); - up->channel_oil = NULL; + up->channel_oil = + pim_channel_oil_add(pim, &up->sg, MAXVIFS, __PRETTY_FUNCTION__); up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE; up->rpf.source_nexthop.interface = NULL; @@ -736,52 +737,34 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, if (up->sg.src.s_addr != INADDR_ANY) wheel_add_item(pim->upstream_sg_wheel, up); - if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)) { + if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags) + || PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) { pim_upstream_fill_static_iif(up, incoming); pim_ifp = up->rpf.source_nexthop.interface->info; assert(pim_ifp); - up->channel_oil = pim_channel_oil_add(pim, &up->sg, - pim_ifp->mroute_vif_index, - __PRETTY_FUNCTION__); - } else if (up->upstream_addr.s_addr == INADDR_ANY) { - /* Create a dummmy channel oil with incoming ineterface MAXVIFS, - * since RP is not configured - */ - up->channel_oil = pim_channel_oil_add(pim, &up->sg, MAXVIFS, - __PRETTY_FUNCTION__); - - } else { + pim_channel_oil_change_iif(pim, up->channel_oil, + pim_ifp->mroute_vif_index, + __PRETTY_FUNCTION__); + + if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) + pim_upstream_keep_alive_timer_start( + up, pim->keep_alive_time); + } else if (up->upstream_addr.s_addr != INADDR_ANY) { rpf_result = pim_rpf_update(pim, up, NULL); if (rpf_result == PIM_RPF_FAILURE) { if (PIM_DEBUG_TRACE) zlog_debug( "%s: Attempting to create upstream(%s), Unable to RPF for source", __PRETTY_FUNCTION__, up->sg_str); - /* Create a dummmy channel oil with incoming ineterface - * MAXVIFS, since RP is not reachable - */ - up->channel_oil = pim_channel_oil_add( - pim, &up->sg, MAXVIFS, __PRETTY_FUNCTION__); } if (up->rpf.source_nexthop.interface) { pim_ifp = up->rpf.source_nexthop.interface->info; if (pim_ifp) - up->channel_oil = pim_channel_oil_add( - pim, &up->sg, pim_ifp->mroute_vif_index, - __PRETTY_FUNCTION__); - else { - /* - * Yeah this should not happen - * but let's be sure that we are not - * doing something stupid, all paths - * through upstream creation will - * create a channel oil - */ - up->channel_oil = pim_channel_oil_add( - pim, &up->sg, MAXVIFS, + pim_channel_oil_change_iif( + pim, up->channel_oil, + pim_ifp->mroute_vif_index, __PRETTY_FUNCTION__); - } } } @@ -1201,6 +1184,13 @@ struct pim_upstream *pim_upstream_keep_alive_timer_proc( if (!pim_upstream_del(pim, up, __PRETTY_FUNCTION__)) return NULL; } + if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) { + PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(up->flags); + + if (!pim_upstream_del(pim, up, __PRETTY_FUNCTION__)) + return NULL; + } + /* upstream reference would have been added to track the local * membership if it is LHR. We have to clear it when KAT expires. * Otherwise would result in stale entry with uncleared ref count. @@ -1526,22 +1516,14 @@ int pim_upstream_inherited_olist_decide(struct pim_instance *pim, struct pim_upstream *up) { struct interface *ifp; - struct pim_interface *pim_ifp = NULL; struct pim_ifchannel *ch, *starch; struct pim_upstream *starup = up->parent; int output_intf = 0; - if (up->rpf.source_nexthop.interface) - pim_ifp = up->rpf.source_nexthop.interface->info; - else { + if (!up->rpf.source_nexthop.interface) if (PIM_DEBUG_TRACE) zlog_debug("%s: up %s RPF is not present", __PRETTY_FUNCTION__, up->sg_str); - } - if (pim_ifp && !up->channel_oil) - up->channel_oil = pim_channel_oil_add(pim, &up->sg, - pim_ifp->mroute_vif_index, - __PRETTY_FUNCTION__); FOR_ALL_INTERFACES (pim->vrf, ifp) { if (!ifp->info) diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index 02ae998290..c6c9291eed 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -74,6 +74,13 @@ * blackholing the traffic pulled down to the LHR. */ #define PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF (1 << 17) +/* + * We are creating a non-joined upstream data structure + * for this S,G as that we want to have a channel oil + * associated with an upstream + */ +#define PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE (1 << 19) + #define PIM_UPSTREAM_FLAG_ALL 0xFFFFFFFF #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) @@ -95,6 +102,7 @@ #define PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN(flags) ((flags) & (PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG | PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM)) #define PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN) #define PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF) +#define PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(flags) ((flags) &PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE) #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) @@ -133,6 +141,7 @@ #define PIM_UPSTREAM_FLAG_UNSET_SRC_VXLAN_TERM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM) #define PIM_UPSTREAM_FLAG_UNSET_MLAG_VXLAN(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN) #define PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF) +#define PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE) enum pim_upstream_state { PIM_UPSTREAM_NOTJOINED, diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 675e81f5a1..b0db23f54a 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -601,7 +601,6 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) { struct in_addr vif_source; int input_iface_vif_index; - int old_vif_index; pim_rp_set_upstream_addr(c_oil->pim, &vif_source, c_oil->oil.mfcc_origin, @@ -701,33 +700,9 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) } /* update iif vif_index */ - old_vif_index = c_oil->oil.mfcc_parent; - c_oil->oil.mfcc_parent = input_iface_vif_index; - - /* update kernel multicast forwarding cache (MFC) */ - if (pim_mroute_add(c_oil, __PRETTY_FUNCTION__)) { - if (PIM_DEBUG_MROUTE) { - /* just log warning */ - struct interface *old_iif = pim_if_find_by_vif_index( - c_oil->pim, old_vif_index); - struct interface *new_iif = pim_if_find_by_vif_index( - c_oil->pim, input_iface_vif_index); - char source_str[INET_ADDRSTRLEN]; - char group_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, - source_str, sizeof(source_str)); - pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, - group_str, sizeof(group_str)); - zlog_debug( - "%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d", - __FILE__, __PRETTY_FUNCTION__, source_str, - group_str, - old_iif ? old_iif->name : "<old_iif?>", - c_oil->oil.mfcc_parent, - new_iif ? new_iif->name : "<new_iif?>", - input_iface_vif_index); - } - } + pim_channel_oil_change_iif(c_oil->pim, c_oil, input_iface_vif_index, + __PRETTY_FUNCTION__); + pim_mroute_add(c_oil, __PRETTY_FUNCTION__); } void pim_scan_oil(struct pim_instance *pim) @@ -1256,14 +1231,15 @@ void pim_forward_start(struct pim_ifchannel *ch) __FILE__, __PRETTY_FUNCTION__, source_str); } - up->channel_oil = pim_channel_oil_add( - pim, &up->sg, MAXVIFS, __PRETTY_FUNCTION__); + pim_channel_oil_change_iif(pim, up->channel_oil, + MAXVIFS, + __PRETTY_FUNCTION__); } else - up->channel_oil = pim_channel_oil_add( - pim, &up->sg, input_iface_vif_index, - __PRETTY_FUNCTION__); + pim_channel_oil_change_iif(pim, up->channel_oil, + input_iface_vif_index, + __PRETTY_FUNCTION__); if (PIM_DEBUG_TRACE) { struct interface *in_intf = pim_if_find_by_vif_index( @@ -1274,10 +1250,6 @@ void pim_forward_start(struct pim_ifchannel *ch) in_intf ? in_intf->name : "Unknown", input_iface_vif_index, up->sg_str); } - - up->channel_oil = - pim_channel_oil_add(pim, &up->sg, input_iface_vif_index, - __PRETTY_FUNCTION__); } if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP) diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 27042e197c..014cae02ee 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -1,6 +1,6 @@ # configure options # -# Some can be overriden on rpmbuild commandline with: +# Some can be overridden on rpmbuild commandline with: # rpmbuild --define 'variable value' # (use any value, ie 1 for flag "with_XXXX" definitions) # diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c index 85d83c61dc..459188fefd 100644 --- a/ripd/rip_routemap.c +++ b/ripd/rip_routemap.c @@ -42,10 +42,9 @@ struct rip_metric_modifier { /* `match metric METRIC' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_metric(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_metric(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { uint32_t *metric; uint32_t check; @@ -95,10 +94,9 @@ struct route_map_rule_cmd route_match_metric_cmd = { /* `match interface IFNAME' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_interface(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_interface(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct rip_info *rinfo; struct interface *ifp; @@ -143,10 +141,9 @@ struct route_map_rule_cmd route_match_interface_cmd = { /* `match ip next-hop IP_ACCESS_LIST' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_ip_next_hop(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_ip_next_hop(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct access_list *alist; struct rip_info *rinfo; @@ -190,7 +187,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_cmd = { /* `match ip next-hop prefix-list PREFIX_LIST' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -233,7 +230,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = { /* `match ip next-hop type <blackhole>' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ip_next_hop_type(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -242,7 +239,7 @@ route_match_ip_next_hop_type(void *rule, const struct prefix *prefix, if (type == RMAP_RIP && prefix->family == AF_INET) { rinfo = (struct rip_info *)object; if (!rinfo) - return RMAP_DENYMATCH; + return RMAP_NOMATCH; if (rinfo->nh.type == NEXTHOP_TYPE_BLACKHOLE) return RMAP_MATCH; @@ -269,10 +266,9 @@ static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = { /* Match function should return 1 if match is success else return zero. */ -static route_map_result_t route_match_ip_address(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_ip_address(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct access_list *alist; @@ -308,7 +304,7 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = { /* `match ip address prefix-list PREFIX_LIST' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -343,8 +339,9 @@ static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { /* `match tag TAG' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_tag(void *rule, const struct prefix *p, - route_map_object_t type, void *object) +static enum route_map_cmd_result_t +route_match_tag(void *rule, const struct prefix *p, route_map_object_t type, + void *object) { route_tag_t *tag; struct rip_info *rinfo; @@ -373,10 +370,9 @@ static struct route_map_rule_cmd route_match_tag_cmd = { /* `set metric METRIC' */ /* Set metric to attribute. */ -static route_map_result_t route_set_metric(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_metric(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { if (type == RMAP_RIP) { struct rip_metric_modifier *mod; @@ -472,10 +468,10 @@ static struct route_map_rule_cmd route_set_metric_cmd = { /* `set ip next-hop IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ -static route_map_result_t route_set_ip_nexthop(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t route_set_ip_nexthop(void *rule, + const struct prefix *prefix, + route_map_object_t type, + void *object) { struct in_addr *address; struct rip_info *rinfo; @@ -525,8 +521,9 @@ static struct route_map_rule_cmd route_set_ip_nexthop_cmd = { /* `set tag TAG' */ /* Set tag to object. ojbect must be pointer to struct attr. */ -static route_map_result_t route_set_tag(void *rule, const struct prefix *prefix, - route_map_object_t type, void *object) +static enum route_map_cmd_result_t +route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type, + void *object) { route_tag_t *tag; struct rip_info *rinfo; diff --git a/ripd/ripd.c b/ripd/ripd.c index e0ff0430f8..561fbcb52d 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -37,7 +37,9 @@ #include "if_rmap.h" #include "plist.h" #include "distribute.h" +#ifdef CRYPTO_INTERNAL #include "md5.h" +#endif #include "keychain.h" #include "privs.h" #include "lib_errors.h" @@ -870,7 +872,11 @@ static int rip_auth_md5(struct rip_packet *packet, struct sockaddr_in *from, struct rip_md5_data *md5data; struct keychain *keychain; struct key *key; +#ifdef CRYPTO_OPENSSL + EVP_MD_CTX *ctx; +#elif CRYPTO_INTERNAL MD5_CTX ctx; +#endif uint8_t digest[RIP_AUTH_MD5_SIZE]; uint16_t packet_len; char auth_str[RIP_AUTH_MD5_SIZE] = {}; @@ -934,11 +940,21 @@ static int rip_auth_md5(struct rip_packet *packet, struct sockaddr_in *from, return 0; /* MD5 digest authentication. */ +#ifdef CRYPTO_OPENSSL + unsigned int md5_size = RIP_AUTH_MD5_SIZE; + ctx = EVP_MD_CTX_new(); + EVP_DigestInit(ctx, EVP_md5()); + EVP_DigestUpdate(ctx, packet, packet_len + RIP_HEADER_SIZE); + EVP_DigestUpdate(ctx, auth_str, RIP_AUTH_MD5_SIZE); + EVP_DigestFinal(ctx, digest, &md5_size); + EVP_MD_CTX_free(ctx); +#elif CRYPTO_INTERNAL memset(&ctx, 0, sizeof(ctx)); MD5Init(&ctx); MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE); MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE); MD5Final(digest, &ctx); +#endif if (memcmp(md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0) return packet_len; @@ -1063,7 +1079,11 @@ static void rip_auth_md5_set(struct stream *s, struct rip_interface *ri, size_t doff, char *auth_str, int authlen) { unsigned long len; +#ifdef CRYPTO_OPENSSL + EVP_MD_CTX *ctx; +#elif CRYPTO_INTERNAL MD5_CTX ctx; +#endif unsigned char digest[RIP_AUTH_MD5_SIZE]; /* Make it sure this interface is configured as MD5 @@ -1092,11 +1112,21 @@ static void rip_auth_md5_set(struct stream *s, struct rip_interface *ri, stream_putw(s, RIP_AUTH_DATA); /* Generate a digest for the RIP packet. */ +#ifdef CRYPTO_OPENSSL + unsigned int md5_size = RIP_AUTH_MD5_SIZE; + ctx = EVP_MD_CTX_new(); + EVP_DigestInit(ctx, EVP_md5()); + EVP_DigestUpdate(ctx, STREAM_DATA(s), stream_get_endp(s)); + EVP_DigestUpdate(ctx, auth_str, RIP_AUTH_MD5_SIZE); + EVP_DigestFinal(ctx, digest, &md5_size); + EVP_MD_CTX_free(ctx); +#elif CRYPTO_INTERNAL memset(&ctx, 0, sizeof(ctx)); MD5Init(&ctx); MD5Update(&ctx, STREAM_DATA(s), stream_get_endp(s)); MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE); MD5Final(digest, &ctx); +#endif /* Copy the digest to the packet. */ stream_write(s, digest, RIP_AUTH_MD5_SIZE); diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c index 0604e272cd..d27ec76a56 100644 --- a/ripngd/ripng_routemap.c +++ b/ripngd/ripng_routemap.c @@ -38,10 +38,9 @@ struct rip_metric_modifier { /* `match metric METRIC' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_metric(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_metric(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { uint32_t *metric; struct ripng_info *rinfo; @@ -86,10 +85,9 @@ static struct route_map_rule_cmd route_match_metric_cmd = { /* `match interface IFNAME' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_interface(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_interface(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct ripng_info *rinfo; struct interface *ifp; @@ -129,9 +127,10 @@ static struct route_map_rule_cmd route_match_interface_cmd = { /* `match tag TAG' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_tag(void *rule, - const struct prefix *prefix, - route_map_object_t type, void *object) +static enum route_map_cmd_result_t route_match_tag(void *rule, + const struct prefix *prefix, + route_map_object_t type, + void *object) { route_tag_t *tag; struct ripng_info *rinfo; @@ -159,10 +158,9 @@ static struct route_map_rule_cmd route_match_tag_cmd = { /* `set metric METRIC' */ /* Set metric to attribute. */ -static route_map_result_t route_set_metric(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_metric(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { if (type == RMAP_RIPNG) { struct rip_metric_modifier *mod; @@ -256,10 +254,9 @@ static struct route_map_rule_cmd route_set_metric_cmd = { /* `set ipv6 next-hop local IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ -static route_map_result_t route_set_ipv6_nexthop_local(void *rule, - const struct prefix *p, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_set_ipv6_nexthop_local(void *rule, const struct prefix *p, + route_map_object_t type, void *object) { struct in6_addr *address; struct ripng_info *rinfo; @@ -310,9 +307,9 @@ static struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = { /* `set tag TAG' */ /* Set tag to object. ojbect must be pointer to struct attr. */ -static route_map_result_t route_set_tag(void *rule, - const struct prefix *prefix, - route_map_object_t type, void *object) +static enum route_map_cmd_result_t +route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type, + void *object) { route_tag_t *tag; struct ripng_info *rinfo; diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index a7552547e9..60cfb2e486 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -39,14 +39,15 @@ #endif DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, - "sharp watch [vrf NAME$name] <nexthop$n|import$import> X:X::X:X$nhop [connected$connected]", + "sharp watch [vrf NAME$name] <nexthop$n X:X::X:X$nhop|import$import X:X::X:X/M$inhop> [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" "The vrf we would like to watch if non-default\n" "The NAME of the vrf\n" "Watch for nexthop changes\n" - "Watch for import check changes\n" "The v6 nexthop to signal for watching\n" + "Watch for import check changes\n" + "The v6 prefix to signal for watching\n" "Should the route be connected\n") { struct vrf *vrf; @@ -62,16 +63,17 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, return CMD_WARNING; } - if (n) - type_import = false; - else - type_import = true; - memset(&p, 0, sizeof(p)); - p.prefixlen = 128; - memcpy(&p.u.prefix6, &nhop, 16); - p.family = AF_INET6; + if (n) { + type_import = false; + p.prefixlen = 128; + memcpy(&p.u.prefix6, &nhop, 16); + p.family = AF_INET6; + } else { + type_import = true; + p = *(const struct prefix *)inhop; + } sharp_nh_tracker_get(&p); sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import, @@ -81,14 +83,15 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, } DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, - "sharp watch [vrf NAME$name] <nexthop$n|import$import> A.B.C.D$nhop [connected$connected]", + "sharp watch [vrf NAME$name] <nexthop$n A.B.C.D$nhop|import$import A.B.C.D/M$inhop> [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" "The vrf we would like to watch if non-default\n" "The NAME of the vrf\n" "Watch for nexthop changes\n" + "The v4 address to signal for watching\n" "Watch for import check changes\n" - "The v4 nexthop to signal for watching\n" + "The v4 prefix for import check to watch\n" "Should the route be connected\n") { struct vrf *vrf; @@ -106,14 +109,16 @@ DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, memset(&p, 0, sizeof(p)); - if (n) + if (n) { type_import = false; - else + p.prefixlen = 32; + p.u.prefix4 = nhop; + p.family = AF_INET; + } + else { type_import = true; - - p.prefixlen = 32; - p.u.prefix4 = nhop; - p.family = AF_INET; + p = *(const struct prefix *)inhop; + } sharp_nh_tracker_get(&p); sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import, diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index cd6f956580..6263f429ea 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -188,7 +188,7 @@ static void handle_repeated(bool installed) sg.r.inst, sg.r.total_routes); } - if (installed) { + if (!installed) { sg.r.installed_routes = 0; sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst, &sg.r.nhop_group, diff --git a/sharpd/sharpd.conf.sample b/sharpd/sharpd.conf.sample index bb1c2edca8..d1cc19a51f 100644 --- a/sharpd/sharpd.conf.sample +++ b/sharpd/sharpd.conf.sample @@ -1,3 +1,6 @@ +! Default sharpd configuration sample ! +! There are no `default` configuration commands for sharpd +! all commands are at the view or enable level. ! log stdout diff --git a/staticd/static_nht.c b/staticd/static_nht.c index 2aa0db59f1..1a2ddd7f05 100644 --- a/staticd/static_nht.c +++ b/staticd/static_nht.c @@ -23,18 +23,48 @@ #include "table.h" #include "vrf.h" #include "nexthop.h" +#include "srcdest_table.h" #include "static_vrf.h" #include "static_routes.h" #include "static_zebra.h" #include "static_nht.h" -static void static_nht_update_safi(struct prefix *p, uint32_t nh_num, - afi_t afi, safi_t safi, struct vrf *vrf, - vrf_id_t nh_vrf_id) +static void static_nht_update_rn(struct route_node *rn, + struct prefix *nhp, uint32_t nh_num, + vrf_id_t nh_vrf_id, struct vrf *vrf, + safi_t safi) { - struct route_table *stable; struct static_route *si; + + for (si = rn->info; si; si = si->next) { + if (si->nh_vrf_id != nh_vrf_id) + continue; + + if (si->type != STATIC_IPV4_GATEWAY + && si->type != STATIC_IPV4_GATEWAY_IFNAME + && si->type != STATIC_IPV6_GATEWAY + && si->type != STATIC_IPV6_GATEWAY_IFNAME) + continue; + + if (nhp->family == AF_INET + && nhp->u.prefix4.s_addr == si->addr.ipv4.s_addr) + si->nh_valid = !!nh_num; + + if (nhp->family == AF_INET6 + && memcmp(&nhp->u.prefix6, &si->addr.ipv6, 16) == 0) + si->nh_valid = !!nh_num; + + if (si->state == STATIC_START) + static_zebra_route_add(rn, si, vrf->vrf_id, safi, true); + } +} + +static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp, + uint32_t nh_num, afi_t afi, safi_t safi, + struct vrf *vrf, vrf_id_t nh_vrf_id) +{ + struct route_table *stable; struct static_vrf *svrf; struct route_node *rn; @@ -46,40 +76,129 @@ static void static_nht_update_safi(struct prefix *p, uint32_t nh_num, if (!stable) return; + if (sp) { + rn = srcdest_rnode_lookup(stable, sp, NULL); + if (rn) { + static_nht_update_rn(rn, nhp, nh_num, nh_vrf_id, + vrf, safi); + route_unlock_node(rn); + } + return; + } + + for (rn = route_top(stable); rn; rn = route_next(rn)) + static_nht_update_rn(rn, nhp, nh_num, nh_vrf_id, vrf, safi); + +} + +void static_nht_update(struct prefix *sp, struct prefix *nhp, + uint32_t nh_num, afi_t afi, vrf_id_t nh_vrf_id) +{ + + struct vrf *vrf; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + static_nht_update_safi(sp, nhp, nh_num, afi, SAFI_UNICAST, + vrf, nh_vrf_id); + static_nht_update_safi(sp, nhp, nh_num, afi, SAFI_MULTICAST, + vrf, nh_vrf_id); + } +} + +static void static_nht_reset_start_safi(struct prefix *nhp, afi_t afi, + safi_t safi, struct vrf *vrf, + vrf_id_t nh_vrf_id) +{ + struct static_vrf *svrf; + struct route_table *stable; + struct static_route *si; + struct route_node *rn; + + svrf = vrf->info; + if (!svrf) + return; + + stable = static_vrf_static_table(afi, safi, svrf); + if (!stable) + return; + for (rn = route_top(stable); rn; rn = route_next(rn)) { for (si = rn->info; si; si = si->next) { if (si->nh_vrf_id != nh_vrf_id) continue; - if (si->type != STATIC_IPV4_GATEWAY - && si->type != STATIC_IPV4_GATEWAY_IFNAME - && si->type != STATIC_IPV6_GATEWAY - && si->type != STATIC_IPV6_GATEWAY_IFNAME) + if (nhp->family == AF_INET + && nhp->u.prefix4.s_addr != si->addr.ipv4.s_addr) continue; - if (p->family == AF_INET - && p->u.prefix4.s_addr == si->addr.ipv4.s_addr) - si->nh_valid = !!nh_num; - - if (p->family == AF_INET6 - && memcmp(&p->u.prefix6, &si->addr.ipv6, 16) == 0) - si->nh_valid = !!nh_num; + if (nhp->family == AF_INET6 + && memcmp(&nhp->u.prefix6, &si->addr.ipv6, 16) != 0) + continue; - static_zebra_route_add(rn, si, vrf->vrf_id, safi, true); + /* + * We've been told that a nexthop we depend + * on has changed in some manner, so reset + * the state machine to allow us to start + * over. + */ + si->state = STATIC_START; } } } -void static_nht_update(struct prefix *p, uint32_t nh_num, afi_t afi, - vrf_id_t nh_vrf_id) +void static_nht_reset_start(struct prefix *nhp, afi_t afi, vrf_id_t nh_vrf_id) { - struct vrf *vrf; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - static_nht_update_safi(p, nh_num, afi, SAFI_UNICAST, - vrf, nh_vrf_id); - static_nht_update_safi(p, nh_num, afi, SAFI_MULTICAST, - vrf, nh_vrf_id); + static_nht_reset_start_safi(nhp, afi, SAFI_UNICAST, + vrf, nh_vrf_id); + static_nht_reset_start_safi(nhp, afi, SAFI_MULTICAST, + vrf, nh_vrf_id); } } + +static void static_nht_mark_state_safi(struct prefix *sp, afi_t afi, + safi_t safi, struct vrf *vrf, + enum static_install_states state) +{ + struct static_vrf *svrf; + struct route_table *stable; + struct static_route *si; + struct route_node *rn; + + svrf = vrf->info; + if (!svrf) + return; + + stable = static_vrf_static_table(afi, safi, svrf); + if (!stable) + return; + + rn = srcdest_rnode_lookup(stable, sp, NULL); + if (!rn) + return; + + for (si = rn->info; si; si = si->next) + si->state = state; + + route_unlock_node(rn); +} + +void static_nht_mark_state(struct prefix *sp, vrf_id_t vrf_id, + enum static_install_states state) +{ + struct vrf *vrf; + + afi_t afi = AFI_IP; + + if (sp->family == AF_INET6) + afi = AFI_IP6; + + vrf = vrf_lookup_by_id(vrf_id); + if (!vrf || !vrf->info) + return; + + static_nht_mark_state_safi(sp, afi, SAFI_UNICAST, vrf, state); + static_nht_mark_state_safi(sp, afi, SAFI_MULTICAST, vrf, state); +} diff --git a/staticd/static_nht.h b/staticd/static_nht.h index f273c71bba..18bb9e39ca 100644 --- a/staticd/static_nht.h +++ b/staticd/static_nht.h @@ -20,6 +20,31 @@ #ifndef __STATIC_NHT_H__ #define __STATIC_NHT_H__ -extern void static_nht_update(struct prefix *p, uint32_t nh_num, - afi_t afi, vrf_id_t vrf_id); +/* + * When we get notification that nexthop tracking has an answer for + * us call this function to find the nexthop we are tracking so it + * can be installed or removed. + * + * sp -> The route we are looking at. If NULL then look at all + * routes. + * nhp -> The nexthop that is being tracked. + * nh_num -> number of valid nexthops. + * afi -> The afi we are working in. + * vrf_id -> The vrf the nexthop is in. + */ +extern void static_nht_update(struct prefix *sp, struct prefix *nhp, + uint32_t nh_num, afi_t afi, vrf_id_t vrf_id); + +/* + * For the given tracked nexthop, nhp, mark all routes that use + * this route as in starting state again. + */ +extern void static_nht_reset_start(struct prefix *nhp, afi_t afi, + vrf_id_t nh_vrf_id); + +/* + * For the given prefix, sp, mark it as in a particular state + */ +extern void static_nht_mark_state(struct prefix *sp, vrf_id_t vrf_id, + enum static_install_states state); #endif diff --git a/staticd/static_routes.c b/staticd/static_routes.c index 5f9ecad694..34f58a98e2 100644 --- a/staticd/static_routes.c +++ b/staticd/static_routes.c @@ -39,7 +39,7 @@ static void static_install_route(struct route_node *rn, struct static_route *si; for (si = rn->info; si; si = si->next) - static_zebra_nht_register(si, true); + static_zebra_nht_register(rn, si, true); si = rn->info; if (si) @@ -73,6 +73,7 @@ int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p, struct static_route *cp; struct static_route *update = NULL; struct route_table *stable = svrf->stable[afi][safi]; + struct interface *ifp; if (!stable) return -1; @@ -182,11 +183,26 @@ int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p, si->next = cp; /* check whether interface exists in system & install if it does */ - if (!ifname) - static_install_route(rn, si, safi); - else { - struct interface *ifp; + switch (si->type) { + case STATIC_IPV4_GATEWAY: + case STATIC_IPV6_GATEWAY: + static_zebra_nht_register(rn, si, true); + break; + case STATIC_IPV4_GATEWAY_IFNAME: + case STATIC_IPV6_GATEWAY_IFNAME: + ifp = if_lookup_by_name(ifname, nh_svrf->vrf->vrf_id); + if (ifp && ifp->ifindex != IFINDEX_INTERNAL) + si->ifindex = ifp->ifindex; + else + zlog_warn("Static Route using %s interface not installed because the interface does not exist in specified vrf", + ifname); + static_zebra_nht_register(rn, si, true); + break; + case STATIC_BLACKHOLE: + static_install_route(rn, si, safi); + break; + case STATIC_IFNAME: ifp = if_lookup_by_name(ifname, nh_svrf->vrf->vrf_id); if (ifp && ifp->ifindex != IFINDEX_INTERNAL) { si->ifindex = ifp->ifindex; @@ -194,6 +210,8 @@ int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p, } else zlog_warn("Static Route using %s interface not installed because the interface does not exist in specified vrf", ifname); + + break; } return 1; @@ -242,7 +260,7 @@ int static_delete_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p, return 0; } - static_zebra_nht_register(si, false); + static_zebra_nht_register(rn, si, false); /* Unlink static route from linked list. */ if (si->prev) diff --git a/staticd/static_routes.h b/staticd/static_routes.h index 6036bfe396..6414947b16 100644 --- a/staticd/static_routes.h +++ b/staticd/static_routes.h @@ -44,6 +44,26 @@ typedef enum { STATIC_IPV6_GATEWAY_IFNAME, } static_types; +/* + * Route Creation gives us: + * START -> Initial State, only exit is when we send the route to + * zebra for installation + * When we send the route to Zebra move to SENT_TO_ZEBRA + * SENT_TO_ZEBRA -> A way to notice that we've sent the route to zebra + * But have not received a response on it's status yet + * After The response from zebra we move to INSTALLED or FAILED + * INSTALLED -> Route was accepted + * FAILED -> Route was rejected + * When we receive notification about a nexthop that a route uses + * We move the route back to START and initiate the process again. + */ +enum static_install_states { + STATIC_START, + STATIC_SENT_TO_ZEBRA, + STATIC_INSTALLED, + STATIC_NOT_INSTALLED, +}; + /* Static route information. */ struct static_route { /* For linked list. */ @@ -55,6 +75,12 @@ struct static_route { vrf_id_t nh_vrf_id; char nh_vrfname[VRF_NAMSIZ + 1]; + /* + * States that we walk the route through + * To know where we are. + */ + enum static_install_states state; + /* Administrative distance. */ uint8_t distance; diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index c6da00418b..13c04259d7 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -43,6 +43,8 @@ #include "static_nht.h" #include "static_vty.h" +bool debug; + /* Zebra structure to hold current status. */ struct zclient *zclient; static struct hash *static_nht_hash; @@ -154,18 +156,23 @@ static int route_notify_owner(ZAPI_CALLBACK_ARGS) switch (note) { case ZAPI_ROUTE_FAIL_INSTALL: + static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED); zlog_warn("%s: Route %s failed to install for table: %u", __PRETTY_FUNCTION__, buf, table_id); break; case ZAPI_ROUTE_BETTER_ADMIN_WON: + static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED); zlog_warn("%s: Route %s over-ridden by better route for table: %u", __PRETTY_FUNCTION__, buf, table_id); break; case ZAPI_ROUTE_INSTALLED: + static_nht_mark_state(&p, vrf_id, STATIC_INSTALLED); break; case ZAPI_ROUTE_REMOVED: + static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED); break; case ZAPI_ROUTE_REMOVE_FAIL: + static_nht_mark_state(&p, vrf_id, STATIC_INSTALLED); zlog_warn("%s: Route %s failure to remove for table: %u", __PRETTY_FUNCTION__, buf, table_id); break; @@ -210,7 +217,8 @@ static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS) if (nhtd) { nhtd->nh_num = nhr.nexthop_num; - static_nht_update(&nhr.prefix, nhr.nexthop_num, afi, + static_nht_reset_start(&nhr.prefix, afi, nhtd->nh_vrf_id); + static_nht_update(NULL, &nhr.prefix, nhr.nexthop_num, afi, nhtd->nh_vrf_id); } else zlog_err("No nhtd?"); @@ -267,7 +275,8 @@ static void static_nht_hash_free(void *data) XFREE(MTYPE_TMP, nhtd); } -void static_zebra_nht_register(struct static_route *si, bool reg) +void static_zebra_nht_register(struct route_node *rn, + struct static_route *si, bool reg) { struct static_nht_data *nhtd, lookup; uint32_t cmd; @@ -315,8 +324,11 @@ void static_zebra_nht_register(struct static_route *si, bool reg) static_nht_hash_alloc); nhtd->refcount++; - if (nhtd->refcount > 1) { - static_nht_update(nhtd->nh, nhtd->nh_num, + if (debug) + zlog_debug("Registered nexthop(%pFX) for %pRN %d", &p, + rn, nhtd->nh_num); + if (nhtd->refcount > 1 && nhtd->nh_num) { + static_nht_update(&rn->p, nhtd->nh, nhtd->nh_num, afi, si->nh_vrf_id); return; } @@ -389,6 +401,8 @@ extern void static_zebra_route_add(struct route_node *rn, api_nh->vrf_id = si->nh_vrf_id; api_nh->onlink = si->onlink; + si->state = STATIC_SENT_TO_ZEBRA; + switch (si->type) { case STATIC_IFNAME: if (si->ifindex == IFINDEX_INTERNAL) diff --git a/staticd/static_zebra.h b/staticd/static_zebra.h index a82eb162e1..15f5410b81 100644 --- a/staticd/static_zebra.h +++ b/staticd/static_zebra.h @@ -21,7 +21,8 @@ extern struct thread_master *master; -extern void static_zebra_nht_register(struct static_route *si, bool reg); +extern void static_zebra_nht_register(struct route_node *rn, + struct static_route *si, bool reg); extern void static_zebra_route_add(struct route_node *rn, struct static_route *si_changed, diff --git a/staticd/staticd.conf.sample b/staticd/staticd.conf.sample index bb1c2edca8..3b64eb9c90 100644 --- a/staticd/staticd.conf.sample +++ b/staticd/staticd.conf.sample @@ -1,3 +1,5 @@ -! +! Default staticd configuration sample ! log stdout +! +! ip route 4.5.6.7/32 10.10.10.10 diff --git a/tests/bgpd/test_bgp_table.c b/tests/bgpd/test_bgp_table.c index 7b38df5f66..819c2d7282 100644 --- a/tests/bgpd/test_bgp_table.c +++ b/tests/bgpd/test_bgp_table.c @@ -183,7 +183,7 @@ static void test_range_lookup(void) do_test(table, "16.0.0.0/8", 16, "16.0.0.0/16", NULL); - do_test(table, "0.0.0.0/3", 21, "1.16.0.0/16", "1.16.128.0/18", + do_test(table, "0.0.0.0/2", 21, "1.16.0.0/16", "1.16.128.0/18", "1.16.192.0/18", "1.16.64.0/19", "1.16.160.0/19", "1.16.32.0/20", "1.16.32.0/21", "16.0.0.0/16", NULL); } diff --git a/tests/bgpd/test_bgp_table.py b/tests/bgpd/test_bgp_table.py index 4423530fe0..4deaf08c22 100644 --- a/tests/bgpd/test_bgp_table.py +++ b/tests/bgpd/test_bgp_table.py @@ -3,5 +3,5 @@ import frrtest class TestTable(frrtest.TestMultiOut): program = './test_bgp_table' -for i in range(6): +for i in range(9): TestTable.onesimple('Checks successfull') diff --git a/tests/lib/cli/test_commands.c b/tests/lib/cli/test_commands.c index ba46bdcea9..bbdc8b238d 100644 --- a/tests/lib/cli/test_commands.c +++ b/tests/lib/cli/test_commands.c @@ -243,7 +243,8 @@ static void test_run(struct prng *prng, struct vty *vty, const char *cmd, (test_buf[0] != '\0') ? ", " : "", test_buf); - if (isspace((int)test_str[strlen(test_str) - 1])) { + if (isspace((unsigned char)test_str[ + strlen(test_str) - 1])) { vector_set(vline, NULL); appended_null = 1; } diff --git a/tests/lib/cxxcompat.c b/tests/lib/cxxcompat.c index 6624de7386..88126e84bc 100644 --- a/tests/lib/cxxcompat.c +++ b/tests/lib/cxxcompat.c @@ -55,7 +55,6 @@ #include "lib/libospf.h" #include "lib/linklist.h" #include "lib/log.h" -#include "lib/logicalrouter.h" #include "lib/md5.h" #include "lib/memory.h" #include "lib/memory_vty.h" @@ -73,7 +72,6 @@ #include "lib/openbsd-tree.h" #include "lib/pbr.h" #include "lib/plist.h" -#include "lib/pqueue.h" #include "lib/prefix.h" #include "lib/privs.h" #include "lib/ptm_lib.h" diff --git a/tests/lib/test_atomlist.c b/tests/lib/test_atomlist.c index 249fff8edb..238ee9539e 100644 --- a/tests/lib/test_atomlist.c +++ b/tests/lib/test_atomlist.c @@ -253,7 +253,7 @@ static void *thr1func(void *arg) struct testrun *tr; for (tr = runs; tr; tr = tr->next) { - sv = seqlock_bump(&p->sqlo); + sv = seqlock_bump(&p->sqlo) - SEQLOCK_INCR; seqlock_wait(&sqlo, sv); tr->func(offset); @@ -288,14 +288,14 @@ static void run_tr(struct testrun *tr) size_t c = 0, s = 0, n = 0; struct item *item, *prev, dummy; - printf("[%02u] %35s %s\n", seqlock_cur(&sqlo) >> 1, "", desc); + printf("[%02u] %35s %s\n", seqlock_cur(&sqlo) >> 2, "", desc); fflush(stdout); if (tr->prefill != NOCLEAR) clear_list(tr->prefill); monotime(&tv); - sv = seqlock_bump(&sqlo); + sv = seqlock_bump(&sqlo) - SEQLOCK_INCR; for (size_t i = 0; i < NTHREADS; i++) { seqlock_wait(&thr[i].sqlo, seqlock_cur(&sqlo)); s += thr[i].counter; @@ -325,7 +325,7 @@ static void run_tr(struct testrun *tr) assert(c == alist_count(&ahead)); } printf("\033[1A[%02u] %9"PRId64"us c=%5zu s=%5zu n=%5zu %s\n", - sv >> 1, delta, c, s, n, desc); + sv >> 2, delta, c, s, n, desc); } #ifdef BASIC_TESTS @@ -381,7 +381,7 @@ int main(int argc, char **argv) basic_tests(); seqlock_init(&sqlo); - seqlock_acquire_val(&sqlo, 1); + seqlock_acquire_val(&sqlo, SEQLOCK_STARTVAL); for (i = 0; i < NTHREADS; i++) { seqlock_init(&thr[i].sqlo); diff --git a/tests/lib/test_seqlock.c b/tests/lib/test_seqlock.c index 9cc6f80702..639c2bdc2b 100644 --- a/tests/lib/test_seqlock.c +++ b/tests/lib/test_seqlock.c @@ -66,20 +66,20 @@ static void *thr1func(void *arg) seqlock_wait(&sqlo, 1); writestr("thr1 @1\n"); - seqlock_wait(&sqlo, 3); - writestr("thr1 @3\n"); - seqlock_wait(&sqlo, 5); writestr("thr1 @5\n"); - seqlock_wait(&sqlo, 7); - writestr("thr1 @7\n"); - seqlock_wait(&sqlo, 9); writestr("thr1 @9\n"); - seqlock_wait(&sqlo, 11); - writestr("thr1 @11\n"); + seqlock_wait(&sqlo, 13); + writestr("thr1 @13\n"); + + seqlock_wait(&sqlo, 17); + writestr("thr1 @17\n"); + + seqlock_wait(&sqlo, 21); + writestr("thr1 @21\n"); return NULL; } @@ -95,11 +95,11 @@ int main(int argc, char **argv) assert(seqlock_cur(&sqlo) == 1); assert(seqlock_bump(&sqlo) == 1); - assert(seqlock_cur(&sqlo) == 3); - assert(seqlock_bump(&sqlo) == 3); + assert(seqlock_cur(&sqlo) == 5); assert(seqlock_bump(&sqlo) == 5); - assert(seqlock_bump(&sqlo) == 7); - assert(seqlock_cur(&sqlo) == 9); + assert(seqlock_bump(&sqlo) == 9); + assert(seqlock_bump(&sqlo) == 13); + assert(seqlock_cur(&sqlo) == 17); assert(seqlock_held(&sqlo)); seqlock_release(&sqlo); @@ -108,16 +108,16 @@ int main(int argc, char **argv) pthread_create(&thr1, NULL, thr1func, NULL); sleep(1); - writestr("main @3\n"); - seqlock_acquire_val(&sqlo, 3); + writestr("main @5\n"); + seqlock_acquire_val(&sqlo, 5); sleep(2); - writestr("main @5\n"); + writestr("main @9\n"); seqlock_bump(&sqlo); sleep(1); - writestr("main @9\n"); - seqlock_acquire_val(&sqlo, 9); + writestr("main @17\n"); + seqlock_acquire_val(&sqlo, 17); sleep(1); writestr("main @release\n"); diff --git a/tests/lib/test_timer_correctness.c b/tests/lib/test_timer_correctness.c index 43e79ba9d0..cbf9b05546 100644 --- a/tests/lib/test_timer_correctness.c +++ b/tests/lib/test_timer_correctness.c @@ -28,7 +28,6 @@ #include <unistd.h> #include "memory.h" -#include "pqueue.h" #include "prng.h" #include "thread.h" diff --git a/tests/lib/test_timer_performance.c b/tests/lib/test_timer_performance.c index d5f4badc85..2960e0d81e 100644 --- a/tests/lib/test_timer_performance.c +++ b/tests/lib/test_timer_performance.c @@ -28,7 +28,6 @@ #include <unistd.h> #include "thread.h" -#include "pqueue.h" #include "prng.h" #define SCHEDULE_TIMERS 1000000 diff --git a/tests/lib/test_typelist.h b/tests/lib/test_typelist.h index b288f0bd8e..7ff210cae3 100644 --- a/tests/lib/test_typelist.h +++ b/tests/lib/test_typelist.h @@ -209,7 +209,7 @@ static void concat(test_, TYPE)(void) assert(list_add(&head, &dummy) == &itm[j]); else { assert(list_add(&head, &dummy) == NULL); - list_del(&head, &dummy); + assert(list_del(&head, &dummy) != NULL); } } ts_hashx("add-dup", "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838"); @@ -255,7 +255,7 @@ static void concat(test_, TYPE)(void) list_first(&head) == &dummy); } else if (list_next(&head, &dummy)) assert(list_next(&head, &dummy)->val > j); - list_del(&head, &dummy); + assert(list_del(&head, &dummy) != NULL); } ts_hash("add-dup+find_{lt,gteq}", "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838"); #endif @@ -295,7 +295,7 @@ static void concat(test_, TYPE)(void) (void)prng_rand(prng); j = prng_rand(prng) % NITEM; if (itm[j].scratchpad == 1) { - list_del(&head, &itm[j]); + assert(list_del(&head, &itm[j]) != NULL); itm[j].scratchpad = 0; l++; } @@ -307,7 +307,7 @@ static void concat(test_, TYPE)(void) assert(item->scratchpad != 0); if (item->val & 1) { - list_del(&head, item); + assert(list_del(&head, item) != NULL); item->scratchpad = 0; l++; } @@ -333,7 +333,7 @@ static void concat(test_, TYPE)(void) for (i = 0; i < NITEM / 2; i++) { j = prng_rand(prng) % NITEM; if (itm[j].scratchpad == 1) { - list_del(&head, &itm[j]); + assert(list_del(&head, &itm[j]) != NULL); itm[j].scratchpad = 0; k--; } @@ -371,7 +371,7 @@ static void concat(test_, TYPE)(void) for (i = 0; i < NITEM / 2; i++) { j = prng_rand(prng) % NITEM; if (itm[j].scratchpad == 1) { - list_del(&head, &itm[j]); + assert(list_del(&head, &itm[j]) != NULL); itm[j].scratchpad = 0; k--; } @@ -424,7 +424,7 @@ static void concat(test_, TYPE)(void) item = &itm[j]; if (item->scratchpad == 0) continue; - list_del(&head, item); + assert(list_del(&head, item) != NULL); } item->scratchpad = 0; k--; @@ -469,7 +469,7 @@ static void concat(test_, TYPE)(void) item = &itm[j]; if (item->scratchpad == 0) continue; - list_del(&head, item); + assert(list_del(&head, item) != NULL); } item->scratchpad = 0; k--; diff --git a/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref index e75d896721..1fb70a0e2f 100644 --- a/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref +++ b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref @@ -10,3 +10,9 @@ C>* 192.168.8.0/26 is directly connected, r1-eth8, XX:XX:XX C>* 192.168.9.0/26 is directly connected, r1-eth9, XX:XX:XX O 192.168.0.0/24 [110/10] is directly connected, r1-eth0, XX:XX:XX O 192.168.3.0/26 [110/10] is directly connected, r1-eth3, XX:XX:XX +S>* 4.5.6.10/32 [1/0] via 192.168.0.2, r1-eth0, XX:XX:XX +S>* 4.5.6.11/32 [1/0] via 192.168.0.2, r1-eth0, XX:XX:XX +S>* 4.5.6.12/32 [1/0] is directly connected, r1-eth0, XX:XX:XX +S>* 4.5.6.7/32 [1/0] unreachable (blackhole), XX:XX:XX +S>* 4.5.6.8/32 [1/0] unreachable (blackhole), XX:XX:XX +S>* 4.5.6.9/32 [1/0] unreachable (ICMP unreachable), XX:XX:XX diff --git a/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref b/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref index 88cee964d6..6e3e9c87c1 100644 --- a/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref +++ b/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref @@ -20,3 +20,9 @@ C * fe80::/64 is directly connected, r1-eth7, XX:XX:XX C * fe80::/64 is directly connected, r1-eth8, XX:XX:XX C * fe80::/64 is directly connected, r1-eth9, XX:XX:XX O fc00:0:0:4::/64 [110/10] is directly connected, r1-eth4, XX:XX:XX +S>* 4:5::/32 [1/0] is directly connected, r1-eth0, XX:XX:XX +S>* 4:5::6:10/128 [1/0] via fc00::2, r1-eth0, XX:XX:XX +S>* 4:5::6:11/128 [1/0] via fc00::2, r1-eth0, XX:XX:XX +S>* 4:5::6:7/128 [1/0] unreachable (blackhole), XX:XX:XX +S>* 4:5::6:8/128 [1/0] unreachable (blackhole), XX:XX:XX +S>* 4:5::6:9/128 [1/0] unreachable (ICMP unreachable), XX:XX:XX diff --git a/tests/topotests/all-protocol-startup/r1/zebra.conf b/tests/topotests/all-protocol-startup/r1/zebra.conf index 164104da7e..30e05f01e3 100644 --- a/tests/topotests/all-protocol-startup/r1/zebra.conf +++ b/tests/topotests/all-protocol-startup/r1/zebra.conf @@ -2,6 +2,23 @@ log file zebra.log ! hostname r1 ! +# Create the various blackhole route types +ip route 4.5.6.7/32 blackhole +ipv6 route 4:5::6:7/128 blackhole +ip route 4.5.6.8/32 Null0 +ipv6 route 4:5::6:8/128 Null0 +ip route 4.5.6.9/32 reject +ipv6 route 4:5::6:9/128 reject +# Create normal gateway routes +ip route 4.5.6.10/32 192.168.0.2 +ipv6 route 4:5::6:10/128 fc00:0:0:0::2 +# Create normal gateway + interface routes +ip route 4.5.6.11/32 192.168.0.2 r1-eth0 +ipv6 route 4:5::6:11/128 fc00:0:0:0::2 r1-eth0 +# Create ifname routes +ip route 4.5.6.12/32 r1-eth0 +ipv6 route 4:5::6:12/32 r1-eth0 +! interface r1-eth0 description to sw0 - no routing protocol ip address 192.168.0.1/24 diff --git a/tests/topotests/bfd-topo2/r1/ipv4_routes.json b/tests/topotests/bfd-topo2/r1/ipv4_routes.json index 8a2ec25baa..b0333de410 100644 --- a/tests/topotests/bfd-topo2/r1/ipv4_routes.json +++ b/tests/topotests/bfd-topo2/r1/ipv4_routes.json @@ -8,7 +8,7 @@ "selected": true, "installed": true, "prefix": "10.0.3.0/24", - "internalStatus": 34, + "internalStatus": 16, "nexthops": [ { "interfaceName": "r1-eth0", @@ -30,7 +30,7 @@ "selected": true, "installed": true, "prefix": "10.254.254.2/32", - "internalStatus": 34, + "internalStatus": 16, "nexthops": [ { "interfaceName": "r1-eth0", @@ -52,7 +52,7 @@ "selected": true, "installed": true, "prefix": "10.254.254.1/32", - "internalStatus": 32, + "internalStatus": 16, "nexthops": [ { "directlyConnected": true, diff --git a/tests/topotests/bfd-topo2/r1/ipv6_routes.json b/tests/topotests/bfd-topo2/r1/ipv6_routes.json index 618853bd42..d09439a8a6 100644 --- a/tests/topotests/bfd-topo2/r1/ipv6_routes.json +++ b/tests/topotests/bfd-topo2/r1/ipv6_routes.json @@ -8,7 +8,7 @@ "selected": true, "installed": true, "prefix": "2001:db8:4::/64", - "internalStatus": 34, + "internalStatus": 16, "nexthops": [ { "interfaceName": "r1-eth0", @@ -27,7 +27,7 @@ "protocol": "bgp", "internalFlags": 0, "metric": 0, - "internalStatus": 2, + "internalStatus": 0, "prefix": "2001:db8:1::/64", "nexthops": [ { @@ -47,7 +47,7 @@ "selected": true, "installed": true, "prefix": "2001:db8:1::/64", - "internalStatus": 32, + "internalStatus": 16, "nexthops": [ { "directlyConnected": true, diff --git a/tests/topotests/bfd-topo2/r2/ipv4_routes.json b/tests/topotests/bfd-topo2/r2/ipv4_routes.json index b9d8afb430..3c41e13434 100644 --- a/tests/topotests/bfd-topo2/r2/ipv4_routes.json +++ b/tests/topotests/bfd-topo2/r2/ipv4_routes.json @@ -5,7 +5,7 @@ "protocol": "ospf", "internalFlags": 0, "metric": 10, - "internalStatus": 2, + "internalStatus": 0, "prefix": "10.0.3.0/24", "nexthops": [ { @@ -25,7 +25,7 @@ "selected": true, "installed": true, "prefix": "10.0.3.0/24", - "internalStatus": 32, + "internalStatus": 16, "nexthops": [ { "directlyConnected": true, @@ -47,7 +47,7 @@ "selected": true, "installed": true, "prefix": "10.254.254.3/32", - "internalStatus": 34, + "internalStatus": 16, "nexthops": [ { "interfaceName": "r2-eth1", @@ -70,7 +70,7 @@ "selected": true, "installed": true, "prefix": "10.254.254.2/32", - "internalStatus": 32, + "internalStatus": 16, "nexthops": [ { "directlyConnected": true, @@ -92,7 +92,7 @@ "selected": true, "installed": true, "prefix": "10.254.254.1/32", - "internalStatus": 34, + "internalStatus": 16, "nexthops": [ { "interfaceName": "r2-eth0", diff --git a/tests/topotests/bfd-topo2/r2/ipv6_routes.json b/tests/topotests/bfd-topo2/r2/ipv6_routes.json index 004e7588aa..bb45bbae52 100644 --- a/tests/topotests/bfd-topo2/r2/ipv6_routes.json +++ b/tests/topotests/bfd-topo2/r2/ipv6_routes.json @@ -5,7 +5,7 @@ "protocol": "ospf6", "internalFlags": 0, "metric": 10, - "internalStatus": 2, + "internalStatus": 0, "prefix": "2001:db8:4::/64", "nexthops": [ { @@ -25,7 +25,7 @@ "selected": true, "installed": true, "prefix": "2001:db8:4::/64", - "internalStatus": 32, + "internalStatus": 16, "nexthops": [ { "directlyConnected": true, @@ -47,7 +47,7 @@ "selected": true, "installed": true, "prefix": "2001:db8:1::/64", - "internalStatus": 32, + "internalStatus": 16, "nexthops": [ { "directlyConnected": true, diff --git a/tests/topotests/bfd-topo2/r3/ipv4_routes.json b/tests/topotests/bfd-topo2/r3/ipv4_routes.json index 14dfc692fe..cbf116e687 100644 --- a/tests/topotests/bfd-topo2/r3/ipv4_routes.json +++ b/tests/topotests/bfd-topo2/r3/ipv4_routes.json @@ -25,7 +25,7 @@ "selected": true, "installed": true, "prefix": "10.0.3.0/24", - "internalStatus": 32, + "internalStatus": 16, "nexthops": [ { "directlyConnected": true, @@ -47,7 +47,7 @@ "selected": true, "installed": true, "prefix": "10.254.254.3/32", - "internalStatus": 32, + "internalStatus": 16, "nexthops": [ { "directlyConnected": true, @@ -69,7 +69,7 @@ "selected": true, "installed": true, "prefix": "10.254.254.2/32", - "internalStatus": 34, + "internalStatus": 16, "nexthops": [ { "interfaceName": "r3-eth0", @@ -92,7 +92,7 @@ "selected": true, "installed": true, "prefix": "10.254.254.1/32", - "internalStatus": 34, + "internalStatus": 16, "nexthops": [ { "interfaceName": "r3-eth0", diff --git a/tests/topotests/bfd-topo2/r4/ipv4_routes.json b/tests/topotests/bfd-topo2/r4/ipv4_routes.json index ae1e97b017..b06184a44d 100644 --- a/tests/topotests/bfd-topo2/r4/ipv4_routes.json +++ b/tests/topotests/bfd-topo2/r4/ipv4_routes.json @@ -8,7 +8,7 @@ "selected": true, "installed": true, "prefix": "10.254.254.4/32", - "internalStatus": 32, + "internalStatus": 16, "nexthops": [ { "directlyConnected": true, diff --git a/tests/topotests/bfd-topo2/r4/ipv6_routes.json b/tests/topotests/bfd-topo2/r4/ipv6_routes.json index 33608b45aa..a22c90cbba 100644 --- a/tests/topotests/bfd-topo2/r4/ipv6_routes.json +++ b/tests/topotests/bfd-topo2/r4/ipv6_routes.json @@ -5,7 +5,7 @@ "protocol": "ospf6", "internalFlags": 0, "metric": 10, - "internalStatus": 2, + "internalStatus": 0, "prefix": "2001:db8:4::/64", "nexthops": [ { @@ -25,7 +25,7 @@ "selected": true, "installed": true, "prefix": "2001:db8:4::/64", - "internalStatus": 32, + "internalStatus": 16, "nexthops": [ { "directlyConnected": true, @@ -47,7 +47,7 @@ "selected": true, "installed": true, "prefix": "2001:db8:1::/64", - "internalStatus": 34, + "internalStatus": 16, "nexthops": [ { "interfaceName": "r4-eth0", diff --git a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py index abd6b396d1..2b9c411ff2 100755 --- a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py +++ b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py @@ -218,11 +218,8 @@ def test_next_hop_attribute(request): # Verifying RIB routes dut = "r1" protocol = "bgp" - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) - try: - assert result is True - except AssertionError: - logger.info("Expected behaviour: %s", result) + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) + assert result is not True # Configure next-hop-self to bgp neighbor input_dict_1 = { diff --git a/tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py b/tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py index 25a346f20d..d3892e9d07 100755 --- a/tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py +++ b/tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py @@ -385,7 +385,7 @@ def test_ip_prefix_lists_out_permit(request): assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) assert result is not True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) write_test_footer(tc_name) @@ -496,7 +496,7 @@ def test_ip_prefix_lists_in_deny_and_permit_any(request): # Verifying RIB routes dut = "r3" protocol = "bgp" - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) assert result is not True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) @@ -713,7 +713,7 @@ def test_ip_prefix_lists_out_deny_and_permit_any(request): # Verifying RIB routes dut = "r4" protocol = "bgp" - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) assert result is not True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) @@ -858,7 +858,7 @@ def test_modify_prefix_lists_in_permit_to_deny(request): # Verifying RIB routes dut = "r3" protocol = "bgp" - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) assert result is not True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) @@ -971,7 +971,7 @@ def test_modify_prefix_lists_in_deny_to_permit(request): # Verifying RIB routes dut = "r3" protocol = "bgp" - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) assert result is not True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) @@ -1151,7 +1151,7 @@ def test_modify_prefix_lists_out_permit_to_deny(request): # Verifying RIB routes dut = "r4" protocol = "bgp" - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) assert result is not True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) @@ -1264,7 +1264,7 @@ def test_modify_prefix_lists_out_deny_to_permit(request): # Verifying RIB routes dut = "r4" protocol = "bgp" - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) assert result is not True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) @@ -1438,7 +1438,7 @@ def test_ip_prefix_lists_implicit_deny(request): # Verifying RIB routes dut = "r4" protocol = "bgp" - result = verify_rib(tgen, "ipv4", dut, input_dict_1, protocol=protocol) + result = verify_rib(tgen, "ipv4", dut, input_dict_1, protocol=protocol, expected=False) assert result is not True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) diff --git a/tests/topotests/bgp_comm-list_delete/__init__.py b/tests/topotests/bgp_comm-list_delete/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_comm-list_delete/__init__.py diff --git a/tests/topotests/bgp_comm-list_delete/r1/bgpd.conf b/tests/topotests/bgp_comm-list_delete/r1/bgpd.conf new file mode 100644 index 0000000000..6e1273f464 --- /dev/null +++ b/tests/topotests/bgp_comm-list_delete/r1/bgpd.conf @@ -0,0 +1,9 @@ +router bgp 65000 + neighbor 192.168.255.2 remote-as 65001 + address-family ipv4 unicast + redistribute connected route-map r2-out + exit-address-family +! +route-map r2-out permit 10 + set community 111:111 222:222 333:333 444:444 +! diff --git a/tests/topotests/bgp_comm-list_delete/r1/zebra.conf b/tests/topotests/bgp_comm-list_delete/r1/zebra.conf new file mode 100644 index 0000000000..0a283c06d5 --- /dev/null +++ b/tests/topotests/bgp_comm-list_delete/r1/zebra.conf @@ -0,0 +1,9 @@ +! +interface lo + ip address 172.16.255.254/32 +! +interface r1-eth0 + ip address 192.168.255.1/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_comm-list_delete/r2/bgpd.conf b/tests/topotests/bgp_comm-list_delete/r2/bgpd.conf new file mode 100644 index 0000000000..3d354d56b1 --- /dev/null +++ b/tests/topotests/bgp_comm-list_delete/r2/bgpd.conf @@ -0,0 +1,11 @@ +router bgp 65001 + neighbor 192.168.255.1 remote-as 65000 + address-family ipv4 + neighbor 192.168.255.1 route-map r1-in in + exit-address-family +! +bgp community-list standard r1 permit 333:333 +! +route-map r1-in permit 10 + set comm-list r1 delete +! diff --git a/tests/topotests/bgp_comm-list_delete/r2/zebra.conf b/tests/topotests/bgp_comm-list_delete/r2/zebra.conf new file mode 100644 index 0000000000..606c17bec9 --- /dev/null +++ b/tests/topotests/bgp_comm-list_delete/r2/zebra.conf @@ -0,0 +1,6 @@ +! +interface r2-eth0 + ip address 192.168.255.2/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py b/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py new file mode 100644 index 0000000000..de6c35ba8f --- /dev/null +++ b/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python + +# +# bgp_comm-list_delete.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2019 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +bgp_comm-list_delete.py: + +Test if works the following commands: +route-map test permit 10 + set comm-list <arg> delete +""" + +import os +import sys +import json +import time +import pytest + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from mininet.topo import Topo + +class TemplateTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + + for routern in range(1, 3): + tgen.add_router('r{}'.format(routern)) + + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + +def setup_module(mod): + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.iteritems(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname)) + ) + + tgen.start_router() + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + +def test_bgp_maximum_prefix_invalid(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def _bgp_converge(router): + while True: + output = json.loads(tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) + if output['192.168.255.1']['bgpState'] == 'Established': + if output['192.168.255.1']['addressFamilyInfo']['IPv4 Unicast']['acceptedPrefixCounter'] == 2: + return True + + def _bgp_comm_list_delete(router): + output = json.loads(tgen.gears[router].vtysh_cmd("show ip bgp 172.16.255.254/32 json")) + if '333:333' in output['paths'][0]['community']['list']: + return False + return True + + if _bgp_converge('r2'): + assert _bgp_comm_list_delete('r2') == True + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py index db53c1aacd..0279e482ff 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py @@ -14,12 +14,12 @@ if ret != False and found != None: luCommand('ce1', 'vtysh -c "sharp remove routes 10.0.0.0 {}"'.format(num),'.','none','Removing {} routes'.format(num)) luCommand('ce2', 'vtysh -c "sharp remove routes 10.0.0.0 {}"'.format(num),'.','none','Removing {} routes'.format(num)) for rtr in rtrs: - luCommand(rtr, 'vtysh -c "show bgp ipv4 uni" | grep Display',' 10 route', 'wait', 'BGP routes removed', wait) + luCommand(rtr, 'vtysh -c "show bgp ipv4 uni" | grep Display',' 10 route', 'wait', 'BGP routes removed', wait, wait_time=10) luCommand(rtr, 'vtysh -c "show bgp ipv4 uni"','.', 'none', 'BGP routes post remove') for rtr in rtrs: - luCommand(rtr, 'ip route show | grep -c \\^10\\.','^0$', 'wait', 'Linux routes removed', wait) + luCommand(rtr, 'ip route show | grep -c \\^10\\.','^0$', 'wait', 'Linux routes removed', wait, wait_time=10) luCommand(rtr, 'ip route show','.', 'none', 'Linux routes post remove') rtrs = ['r1', 'r3', 'r4'] for rtr in rtrs: - luCommand(rtr, 'ip route show vrf {}-cust1 | grep -c \\^10\\.'.format(rtr),'^0$','wait','VRF route removed',wait) + luCommand(rtr, 'ip route show vrf {}-cust1 | grep -c \\^10\\.'.format(rtr),'^0$','wait','VRF route removed',wait, wait_time=10) #done diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py index 3619cdf84f..21543ab78e 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py @@ -36,10 +36,10 @@ if doSharp == True: luCommand('ce2', 'vtysh -c "sharp install routes 10.0.0.0 nexthop 99.0.0.2 {}"'.format(num),'','pass','Adding {} routes'.format(num)) rtrs = ['ce1', 'ce2', 'ce3'] for rtr in rtrs: - luCommand(rtr, 'vtysh -c "show bgp ipv4 uni 10.{}.{}.{}"'.format(b,c,d), 'Last update:', 'wait', 'RXed last route, 10.{}.{}.{}'.format(b,c,d), wait) - luCommand(rtr, 'vtysh -c "show bgp ipv4 uni" | grep -c 10\\.\\*/32', str(num), 'wait', 'See all sharp routes in BGP', wait) - luCommand('r1', 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 10.{}.{}.{}"'.format(b,c,d),'99.0.0.1','wait','RXed -> 10.{}.{}.{} from CE1'.format(b,c,d), wait) - luCommand('r3', 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 10.{}.{}.{}"'.format(b,c,d),'99.0.0.2','wait','RXed -> 10.{}.{}.{} from CE2'.format(b,c,d), wait) + luCommand(rtr, 'vtysh -c "show bgp ipv4 uni 10.{}.{}.{}"'.format(b,c,d), 'Last update:', 'wait', 'RXed last route, 10.{}.{}.{}'.format(b,c,d), wait, wait_time=10) + luCommand(rtr, 'vtysh -c "show bgp ipv4 uni" | grep -c 10\\.\\*/32', str(num), 'wait', 'See all sharp routes in BGP', wait, wait_time=10) + luCommand('r1', 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 10.{}.{}.{}"'.format(b,c,d),'99.0.0.1','wait','RXed -> 10.{}.{}.{} from CE1'.format(b,c,d), wait, wait_time=10) + luCommand('r3', 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 10.{}.{}.{}"'.format(b,c,d),'99.0.0.2','wait','RXed -> 10.{}.{}.{} from CE2'.format(b,c,d), wait, wait_time=10) luCommand('r1', 'vtysh -c "show bgp ipv4 vpn 10.{}.{}.{}"'.format(b,c,d),'99.0.0.1','wait','see VPN safi -> 10.{}.{}.{} from CE1'.format(b,c,d)) luCommand('r3', 'vtysh -c "show bgp ipv4 vpn 10.{}.{}.{}"'.format(b,c,d),'99.0.0.2','wait','see VPN safi -> 10.{}.{}.{} from CE2'.format(b,c,d)) luCommand('r3', 'vtysh -c "show bgp ipv4 vpn 10.{}.{}.{}"'.format(b,c,d),'1.1.1.1','wait','see VPN safi -> 10.{}.{}.{} from CE1'.format(b,c,d)) @@ -48,13 +48,13 @@ if doSharp == True: luCommand('r4', 'vtysh -c "show bgp ipv4 vpn 10.{}.{}.{}"'.format(b,c,d),'3.3.3.3','wait','see VPN safi -> 10.{}.{}.{} from CE2'.format(b,c,d)) rtrs = ['ce1', 'ce2', 'ce3'] for rtr in rtrs: - luCommand(rtr, 'ip route get 10.{}.{}.{}'.format(b,c,d),'dev','wait','Route to 10.{}.{}.{} available'.format(b,c,d), wait) - luCommand(rtr, 'ip route show | grep -c \\^10\\.', str(num), 'wait', 'See {} linux routes'.format(num), wait) + luCommand(rtr, 'ip route get 10.{}.{}.{}'.format(b,c,d),'dev','wait','Route to 10.{}.{}.{} available'.format(b,c,d), wait, wait_time=10) + luCommand(rtr, 'ip route show | grep -c \\^10\\.', str(num), 'wait', 'See {} linux routes'.format(num), wait, wait_time=10) rtrs = ['r1', 'r3', 'r4'] for rtr in rtrs: - luCommand(rtr, 'ip route get vrf {}-cust1 10.{}.{}.{}'.format(rtr,b,c,d),'dev','wait','VRF route available',wait) - luCommand(rtr, 'ip route show vrf {}-cust1 | grep -c \\^10\\.'.format(rtr), str(num), 'wait','See {} linux routes'.format(num), wait) + luCommand(rtr, 'ip route get vrf {}-cust1 10.{}.{}.{}'.format(rtr,b,c,d),'dev','wait','VRF route available',wait, wait_time=10) + luCommand(rtr, 'ip route show vrf {}-cust1 | grep -c \\^10\\.'.format(rtr), str(num), 'wait','See {} linux routes'.format(num), wait, wait_time=10) rtrs = ['ce1', 'ce2', 'ce3', 'r1', 'r2', 'r3', 'r4'] for rtr in rtrs: ret = luCommand(rtr, 'vtysh -c "show memory"', 'zebra: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*) .*bgpd: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*)', 'none', 'collect bgpd memory stats') diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv4_routes.json b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv4_routes.json index e32c84b7d5..1649ade96d 100644 --- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv4_routes.json +++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv4_routes.json @@ -9,7 +9,7 @@ "distance": 20, "metric": 0, "installed": true, - "internalStatus": 34, + "internalStatus": 16, "internalFlags": 8, "nexthops": [ { @@ -33,7 +33,7 @@ "distance": 0, "metric": 0, "installed": true, - "internalStatus": 32, + "internalStatus": 16, "internalFlags": 8, "nexthops": [ { diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json index 88e8c5cd83..1ca62094bd 100644 --- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json +++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json @@ -6,7 +6,7 @@ "vrfId":3, "distance": 20, "metric": 0, - "internalStatus": 2, + "internalStatus": 0, "internalFlags": 0, "nexthops": [ { @@ -27,7 +27,7 @@ "distance": 0, "metric": 0, "installed": true, - "internalStatus": 32, + "internalStatus": 16, "internalFlags": 8, "nexthops": [ { diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv4_routes.json b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv4_routes.json index 9d7c0e6e4f..eda4bed035 100644 --- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv4_routes.json +++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv4_routes.json @@ -9,7 +9,7 @@ "distance": 0, "metric": 0, "installed": true, - "internalStatus": 32, + "internalStatus": 16, "internalFlags": 8, "nexthops": [ { @@ -33,7 +33,7 @@ "distance": 20, "metric": 0, "installed": true, - "internalStatus": 34, + "internalStatus": 16, "internalFlags": 8, "nexthops": [ { diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv6_routes.json b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv6_routes.json index 230fe38748..45c1b76017 100644 --- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv6_routes.json +++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv6_routes.json @@ -9,7 +9,7 @@ "distance": 0, "metric": 0, "installed": true, - "internalStatus": 32, + "internalStatus": 16, "internalFlags": 8, "nexthops": [ { diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 13f8824976..2613f45f1c 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -932,7 +932,7 @@ def clear_bgp_and_verify(tgen, topo, router): # Peer up time dictionary peer_uptime_before_clear_bgp[bgp_neighbor] = \ - ipv4_data[neighbor_ip]["peerUptime"] + ipv4_data[neighbor_ip]["peerUptimeEstablishedEpoch"] else: ipv6_data = show_bgp_json["ipv6Unicast"][ "peers"] @@ -940,7 +940,7 @@ def clear_bgp_and_verify(tgen, topo, router): # Peer up time dictionary peer_uptime_before_clear_bgp[bgp_neighbor] = \ - ipv6_data[neighbor_ip]["peerUptime"] + ipv6_data[neighbor_ip]["peerUptimeEstablishedEpoch"] if nh_state == "Established": no_of_peer += 1 @@ -953,6 +953,7 @@ def clear_bgp_and_verify(tgen, topo, router): logger.warning("BGP is not yet Converged for router %s " "before bgp clear", router) + logger.info(peer_uptime_before_clear_bgp) # Clearing BGP logger.info("Clearing BGP neighborship for router %s..", router) for addr_type in bgp_addr_type.keys(): @@ -1010,14 +1011,14 @@ def clear_bgp_and_verify(tgen, topo, router): "peers"] nh_state = ipv4_data[neighbor_ip]["state"] peer_uptime_after_clear_bgp[bgp_neighbor] = \ - ipv4_data[neighbor_ip]["peerUptime"] + ipv4_data[neighbor_ip]["peerUptimeEstablishedEpoch"] else: ipv6_data = show_bgp_json["ipv6Unicast"][ "peers"] nh_state = ipv6_data[neighbor_ip]["state"] # Peer up time dictionary peer_uptime_after_clear_bgp[bgp_neighbor] = \ - ipv6_data[neighbor_ip]["peerUptime"] + ipv6_data[neighbor_ip]["peerUptimeEstablishedEpoch"] if nh_state == "Established": no_of_peer += 1 @@ -1030,7 +1031,8 @@ def clear_bgp_and_verify(tgen, topo, router): logger.warning("BGP is not yet Converged for router %s after" " bgp clear", router) - # Compariung peerUptime dictionaries + logger.info(peer_uptime_after_clear_bgp) + # Comparing peerUptimeEstablishedEpoch dictionaries if peer_uptime_before_clear_bgp != peer_uptime_after_clear_bgp: logger.info("BGP neighborship is reset after clear BGP on router %s", router) diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 628c198e1a..75880cfd28 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -30,6 +30,9 @@ import traceback import socket import ipaddr +from lib import topotest + +from functools import partial from lib.topolog import logger, logger_config from lib.topogen import TopoRouter @@ -1089,7 +1092,7 @@ def create_route_maps(tgen, input_dict, build=False): ############################################# # Verification APIs ############################################# -def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None): +def _verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None): """ Data will be read from input_dict or input JSON file, API will generate same prefixes, which were redistributed by either create_static_routes() or @@ -1258,6 +1261,26 @@ def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None): return True +def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None, expected=True): + """ + Wrapper function for `_verify_rib` that tries multiple time to get results. + + When the expected result is `False` we actually should expect for an string instead. + """ + + # Use currying to hide the parameters and create a test function. + test_func = partial(_verify_rib, tgen, addr_type, dut, input_dict, next_hop, protocol) + + # Call the test function and expect it to return True, otherwise try it again. + if expected is True: + _, result = topotest.run_and_expect(test_func, True, count=20, wait=6) + else: + _, result = topotest.run_and_expect_type(test_func, str, count=20, wait=6) + + # Return as normal. + return result + + def verify_admin_distance_for_static_routes(tgen, input_dict): """ API to verify admin distance for static routes as defined in input_dict/ diff --git a/tests/topotests/lib/lutil.py b/tests/topotests/lib/lutil.py index e58b4725eb..7c89ada013 100755 --- a/tests/topotests/lib/lutil.py +++ b/tests/topotests/lib/lutil.py @@ -22,6 +22,7 @@ import sys import time import datetime import json +import math from topolog import logger from mininet.net import Mininet @@ -242,22 +243,27 @@ Total %-4d %-4d %d\n\ return js return ret - def wait(self, target, command, regexp, op, result, wait, returnJson): - self.log('%s:%s WAIT:%s:%s:%s:%s:%s:%s:' % \ - (self.l_filename, self.l_line, target, command, regexp, op, result,wait)) - llevel = LUtil.l_level + def wait(self, target, command, regexp, op, result, wait, returnJson, wait_time=0.5): + self.log('%s:%s WAIT:%s:%s:%s:%s:%s:%s:%s:' % \ + (self.l_filename, self.l_line, target, command, regexp, op, result,wait,wait_time)) found = False n = 0 startt = time.time() - delta = time.time() - startt - while delta < wait and found is False: + + # Calculate the amount of `sleep`s we are going to peform. + wait_count = int(math.ceil(wait / wait_time)) + 1 + + while wait_count > 0: + n += 1 found = self.command(target, command, regexp, op, result, returnJson) - n+=1 - LUtil.l_level = 0 - delta = time.time() - startt - if delta < wait and found is False: - time.sleep (0.5) - LUtil.l_level = llevel + if found is not False: + break + + wait_count -= 1 + if wait_count > 0: + time.sleep(wait_time) + + delta = time.time() - startt self.log('Done after %d loops, time=%s, Found=%s' % (n, delta, found)) found = self.command(target, command, regexp, 'pass', '%s +%4.2f secs' % (result, delta), returnJson) return found @@ -283,11 +289,11 @@ def luStart(baseScriptDir='.', baseLogDir='.', net='', LUtil.l_dotall_experiment = False LUtil.l_dotall_experiment = True -def luCommand(target, command, regexp='.', op='none', result='', time=10, returnJson=False): +def luCommand(target, command, regexp='.', op='none', result='', time=10, returnJson=False, wait_time=0.5): if op != 'wait': return LUtil.command(target, command, regexp, op, result, returnJson) else: - return LUtil.wait(target, command, regexp, op, result, time, returnJson) + return LUtil.wait(target, command, regexp, op, result, time, returnJson, wait_time) def luLast(usenl=False): if usenl: diff --git a/tests/topotests/lib/test/test_run_and_expect.py b/tests/topotests/lib/test/test_run_and_expect.py new file mode 100755 index 0000000000..3c22c20e7b --- /dev/null +++ b/tests/topotests/lib/test/test_run_and_expect.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python + +# +# test_run_and_expect.py +# Tests for library function: run_and_expect(_type)(). +# +# Copyright (c) 2019 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Tests for the `run_and_expect(_type)()` functions. +""" + +import os +import sys +import pytest + +# Save the Current Working Directory to find lib files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../../')) + +# pylint: disable=C0413 +from lib.topotest import run_and_expect_type + +def test_run_and_expect_type(): + "Test basic `run_and_expect_type` functionality." + + def return_true(): + "Test function that returns `True`." + return True + + # Test value success. + success, value = run_and_expect_type(return_true, bool, count=1, wait=0, avalue=True) + assert success is True + assert value is True + + # Test value failure. + success, value = run_and_expect_type(return_true, bool, count=1, wait=0, avalue=False) + assert success is False + assert value is True + + # Test type success. + success, value = run_and_expect_type(return_true, bool, count=1, wait=0) + assert success is True + assert value is True + + # Test type failure. + success, value = run_and_expect_type(return_true, str, count=1, wait=0) + assert success is False + assert value is True + + # Test type failure, return correct type. + success, value = run_and_expect_type(return_true, str, count=1, wait=0, avalue=True) + assert success is False + assert value is True + + +if __name__ == '__main__': + sys.exit(pytest.main()) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 867f9f2f03..9e1d344687 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -252,6 +252,54 @@ def run_and_expect(func, what, count=20, wait=3): return (False, result) +def run_and_expect_type(func, etype, count=20, wait=3, avalue=None): + """ + Run `func` and compare the result with `etype`. Do it for `count` times + waiting `wait` seconds between tries. By default it tries 20 times with + 3 seconds delay between tries. + + This function is used when you want to test the return type and, + optionally, the return value. + + Returns (True, func-return) on success or + (False, func-return) on failure. + """ + start_time = time.time() + func_name = "<unknown>" + if func.__class__ == functools.partial: + func_name = func.func.__name__ + else: + func_name = func.__name__ + + logger.info( + "'{}' polling started (interval {} secs, maximum wait {} secs)".format( + func_name, wait, int(wait * count))) + + while count > 0: + result = func() + if not isinstance(result, etype): + logger.debug("Expected result type '{}' got '{}' instead".format(etype, type(result))) + time.sleep(wait) + count -= 1 + continue + + if etype != type(None) and avalue != None and result != avalue: + logger.debug("Expected value '{}' got '{}' instead".format(avalue, result)) + time.sleep(wait) + count -= 1 + continue + + end_time = time.time() + logger.info("'{}' succeeded after {:.2f} seconds".format( + func_name, end_time - start_time)) + return (True, result) + + end_time = time.time() + logger.error("'{}' failed after {:.2f} seconds".format( + func_name, end_time - start_time)) + return (False, result) + + def int2dpid(dpid): "Converting Integer to DPID" diff --git a/tools/coccinelle/ctype_cast.cocci b/tools/coccinelle/ctype_cast.cocci new file mode 100644 index 0000000000..b0b00959da --- /dev/null +++ b/tools/coccinelle/ctype_cast.cocci @@ -0,0 +1,11 @@ + +@@ +identifier func =~ "^(to|is)(alnum|cntrl|print|xdigit|alpha|digit|punct|ascii|graph|space|blank|lower|upper)$"; +expression e; +@@ + + func( +- (int) ++ (unsigned char) + e) + diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 23e8f3000d..e182c77c78 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -393,8 +393,10 @@ end # is not the main router bgp block, but enabling multi-instance oneline_ctx_keywords = ("access-list ", "agentx", + "allow-external-route-update", "bgp ", "debug ", + "domainname ", "dump ", "enable ", "frr ", diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c index f6c757f5d7..14f648e8da 100644 --- a/tools/gen_northbound_callbacks.c +++ b/tools/gen_northbound_callbacks.c @@ -28,7 +28,8 @@ static void __attribute__((noreturn)) usage(int status) { - fprintf(stderr, "usage: gen_northbound_callbacks [-h] MODULE\n"); + extern const char *__progname; + fprintf(stderr, "usage: %s [-h] [-p path] MODULE\n", __progname); exit(status); } @@ -152,6 +153,36 @@ static void generate_callback_name(struct lys_node *snode, replace_hyphens_by_underscores(buffer); } +static void generate_callback(const struct nb_callback_info *ncinfo, + const char *cb_name) +{ + printf("static %s%s(%s)\n{\n", + ncinfo->return_type, cb_name, ncinfo->arguments); + + switch (ncinfo->operation) { + case NB_OP_CREATE: + case NB_OP_MODIFY: + case NB_OP_DESTROY: + case NB_OP_MOVE: + printf("\tswitch (event) {\n" + "\tcase NB_EV_VALIDATE:\n" + "\tcase NB_EV_PREPARE:\n" + "\tcase NB_EV_ABORT:\n" + "\tcase NB_EV_APPLY:\n" + "\t\t/* TODO: implement me. */\n" + "\t\tbreak;\n" + "\t}\n\n" + ); + break; + + default: + printf("\t/* TODO: implement me. */\n"); + break; + } + + printf("\treturn %s;\n}\n\n", ncinfo->return_value); +} + static int generate_callbacks(const struct lys_node *snode, void *arg) { bool first = true; @@ -191,14 +222,7 @@ static int generate_callbacks(const struct lys_node *snode, void *arg) generate_callback_name((struct lys_node *)snode, cb->operation, cb_name, sizeof(cb_name)); - printf("static %s%s(%s)\n" - "{\n" - "\t/* TODO: implement me. */\n" - "\treturn %s;\n" - "}\n\n", - nb_callbacks[cb->operation].return_type, cb_name, - nb_callbacks[cb->operation].arguments, - nb_callbacks[cb->operation].return_value); + generate_callback(cb, cb_name); } return YANG_ITER_CONTINUE; @@ -237,32 +261,52 @@ static int generate_nb_nodes(const struct lys_node *snode, void *arg) printf("\t\t{\n" "\t\t\t.xpath = \"%s\",\n", xpath); + printf("\t\t\t.cbs = {\n"); first = false; } generate_callback_name((struct lys_node *)snode, cb->operation, cb_name, sizeof(cb_name)); - printf("\t\t\t.cbs.%s = %s,\n", - nb_operation_name(cb->operation), cb_name); + printf("\t\t\t\t.%s = %s,\n", nb_operation_name(cb->operation), + cb_name); } - if (!first) + if (!first) { + printf("\t\t\t}\n"); printf("\t\t},\n"); + } return YANG_ITER_CONTINUE; } int main(int argc, char *argv[]) { + const char *search_path = NULL; struct yang_module *module; char module_name_underscores[64]; + struct stat st; int opt; - while ((opt = getopt(argc, argv, "h")) != -1) { + while ((opt = getopt(argc, argv, "hp:")) != -1) { switch (opt) { case 'h': usage(EXIT_SUCCESS); /* NOTREACHED */ + case 'p': + if (stat(optarg, &st) == -1) { + fprintf(stderr, + "error: invalid search path '%s': %s\n", + optarg, strerror(errno)); + exit(EXIT_FAILURE); + } + if (S_ISDIR(st.st_mode) == 0) { + fprintf(stderr, + "error: search path is not directory"); + exit(EXIT_FAILURE); + } + + search_path = optarg; + break; default: usage(EXIT_FAILURE); /* NOTREACHED */ @@ -275,6 +319,9 @@ int main(int argc, char *argv[]) yang_init(); + if (search_path) + ly_ctx_set_searchdir(ly_native_ctx, search_path); + /* Load all FRR native models to ensure all augmentations are loaded. */ yang_module_load_all(); module = yang_module_find(argv[0]); diff --git a/tools/start-stop-daemon.c b/tools/start-stop-daemon.c index 5903f8732f..c75306a959 100644 --- a/tools/start-stop-daemon.c +++ b/tools/start-stop-daemon.c @@ -401,7 +401,7 @@ static void parse_schedule_item(const char *string, struct schedule_item *item) if (!strcmp(string, "forever")) { item->type = sched_forever; - } else if (isdigit((int)string[0])) { + } else if (isdigit((unsigned char)string[0])) { item->type = sched_timeout; if (parse_integer(string, &item->value) != 0) badusage("invalid timeout value in schedule"); diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c index 5213b27d32..951ad3f58f 100644 --- a/vrrpd/vrrp.c +++ b/vrrpd/vrrp.c @@ -196,9 +196,20 @@ static struct vrrp_vrouter *vrrp_lookup_by_if_mvl(struct interface *mvl_ifp) { struct interface *p; - if (!mvl_ifp || !mvl_ifp->link_ifindex - || !vrrp_ifp_has_vrrp_mac(mvl_ifp)) + if (!mvl_ifp || mvl_ifp->link_ifindex == 0 + || !vrrp_ifp_has_vrrp_mac(mvl_ifp)) { + if (mvl_ifp && mvl_ifp->link_ifindex == 0) + DEBUGD(&vrrp_dbg_zebra, + VRRP_LOGPFX + "Interface %s has no parent ifindex; disregarding", + mvl_ifp->name); + if (mvl_ifp && !vrrp_ifp_has_vrrp_mac(mvl_ifp)) + DEBUGD(&vrrp_dbg_zebra, + VRRP_LOGPFX + "Interface %s has a non-VRRP MAC; disregarding", + mvl_ifp->name); return NULL; + } p = if_lookup_by_index(mvl_ifp->link_ifindex, VRF_DEFAULT); uint8_t vrid = mvl_ifp->hw_addr[5]; @@ -2028,9 +2039,19 @@ static void vrrp_bind_pending(struct interface *mvl_ifp) { struct vrrp_vrouter *vr; + DEBUGD(&vrrp_dbg_zebra, + VRRP_LOGPFX + "Searching for instances that could use interface %s", + mvl_ifp->name); + vr = vrrp_lookup_by_if_mvl(mvl_ifp); if (vr) { + DEBUGD(&vrrp_dbg_zebra, + VRRP_LOGPFX VRRP_LOGPFX_VRID + "<-- This instance can probably use interface %s", + vr->vrid, mvl_ifp->name); + if (mvl_ifp->hw_addr[4] == 0x01 && !vr->v4->mvl_ifp) vrrp_attach_interface(vr->v4); else if (mvl_ifp->hw_addr[4] == 0x02 && !vr->v6->mvl_ifp) @@ -2112,9 +2133,13 @@ void vrrp_if_down(struct interface *ifp) struct listnode *ln; struct list *vrs; + vrrp_bind_pending(ifp); + vrs = vrrp_lookup_by_if_any(ifp); for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr)) { + vrrp_check_start(vr); + if (vr->ifp == ifp || vr->v4->mvl_ifp == ifp || vr->v6->mvl_ifp == ifp) { DEBUGD(&vrrp_dbg_auto, diff --git a/vrrpd/vrrp_zebra.c b/vrrpd/vrrp_zebra.c index c15c250bdf..72b77c1313 100644 --- a/vrrpd/vrrp_zebra.c +++ b/vrrpd/vrrp_zebra.c @@ -38,9 +38,11 @@ static void vrrp_zebra_debug_if_state(struct interface *ifp, vrf_id_t vrf_id, const char *func) { DEBUGD(&vrrp_dbg_zebra, - "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", - func, ifp->name, ifp->ifindex, vrf_id, (long)ifp->flags, - ifp->metric, ifp->mtu, if_is_operative(ifp)); + "%s: %s index %d(%u) parent %d mac %02x:%02x:%02x:%02x:%02x:%02x flags %ld metric %d mtu %d operative %d", + func, ifp->name, vrf_id, ifp->link_ifindex, ifp->ifindex, + ifp->hw_addr[0], ifp->hw_addr[1], ifp->hw_addr[2], + ifp->hw_addr[3], ifp->hw_addr[4], ifp->hw_addr[5], + (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); } static void vrrp_zebra_debug_if_dump_address(struct interface *ifp, @@ -113,6 +115,8 @@ static int vrrp_zebra_if_del(int command, struct zclient *zclient, vrrp_if_del(ifp); + if_set_index(ifp, IFINDEX_INTERNAL); + return 0; } @@ -208,8 +212,6 @@ static int vrrp_zebra_if_address_del(int command, struct zclient *client, vrrp_if_address_del(c->ifp); - if_set_index(c->ifp, IFINDEX_INTERNAL); - return 0; } diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 4dc34d10ef..d0b0c701a7 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -96,18 +96,12 @@ sub scan_file { elsif ($file =~ /lib\/if\.c$/) { $protocol = "VTYSH_INTERFACE"; } - elsif ($file =~ /lib\/logicalrouter\.c$/) { - $protocol = "VTYSH_ALL"; - } elsif ($file =~ /lib\/filter\.c$/) { $protocol = "VTYSH_ALL"; } elsif ($file =~ /lib\/agentx\.c$/) { $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA"; } - elsif ($file =~ /lib\/ns\.c$/) { - $protocol = "VTYSH_ZEBRA"; - } elsif ($file =~ /lib\/nexthop_group\.c$/) { $protocol = "VTYSH_PBRD | VTYSH_SHARPD"; } diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 053848bfc3..fba754f626 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -46,6 +46,7 @@ #include "command_graph.h" #include "frrstr.h" #include "json.h" +#include "ferr.h" DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy") @@ -667,11 +668,11 @@ static char *trim(char *s) return s; end = s + size - 1; - while (end >= s && isspace((int)*end)) + while (end >= s && isspace((unsigned char)*end)) end--; *(end + 1) = '\0'; - while (*s && isspace((int)*s)) + while (*s && isspace((unsigned char)*s)) s++; return s; @@ -851,11 +852,15 @@ int vtysh_mark_file(const char *filename) return CMD_ERR_INCOMPLETE; case CMD_SUCCESS: vty_out(vty, "%s", vty->buf); + if (strmatch(vty_buf_trimmed, "exit-vrf")) + vty_out(vty, "end\n"); break; case CMD_SUCCESS_DAEMON: { int cmd_stat; vty_out(vty, "%s", vty->buf); + if (strmatch(vty_buf_trimmed, "exit-vrf")) + vty_out(vty, "end\n"); cmd_stat = vtysh_client_execute(&vtysh_client[0], vty->buf); if (cmd_stat != CMD_SUCCESS) @@ -978,7 +983,7 @@ static int vtysh_process_questionmark(const char *input, int input_len) if (vline == NULL) { vline = vector_init(1); vector_set(vline, NULL); - } else if (input_len && isspace((int)input[input_len - 1])) + } else if (input_len && isspace((unsigned char)input[input_len - 1])) vector_set(vline, NULL); describe = cmd_describe_command(vline, vty, &ret); @@ -1126,7 +1131,8 @@ static char *command_generator(const char *text, int state) if (vline == NULL) return NULL; - if (rl_end && isspace((int)rl_line_buffer[rl_end - 1])) + if (rl_end && + isspace((unsigned char)rl_line_buffer[rl_end - 1])) vector_set(vline, NULL); matched = cmd_complete_command(vline, vty, &complete_status); @@ -1187,10 +1193,6 @@ static struct cmd_node pw_node = { PW_NODE, "%s(config-pw)# ", }; -static struct cmd_node logicalrouter_node = { - LOGICALROUTER_NODE, "%s(config-logical-router)# ", -}; - static struct cmd_node vrf_node = { VRF_NODE, "%s(config-vrf)# ", }; @@ -1797,7 +1799,6 @@ static int vtysh_exit(struct vty *vty) break; case INTERFACE_NODE: case PW_NODE: - case LOGICALROUTER_NODE: case VRF_NODE: case NH_GROUP_NODE: case ZEBRA_NODE: @@ -1927,7 +1928,7 @@ DEFUNSH(VTYSH_BGPD, rpki_quit, rpki_quit_cmd, "quit", return rpki_exit(self, vty, argc, argv); } -DEFUNSH(VTYSH_PIMD|VTYSH_ZEBRA, exit_vrf_config, exit_vrf_config_cmd, "exit-vrf", +DEFUNSH(VTYSH_VRF, exit_vrf_config, exit_vrf_config_cmd, "exit-vrf", "Exit from VRF configuration mode\n") { if (vty->node == VRF_NODE) @@ -2127,24 +2128,6 @@ DEFUNSH(VTYSH_ZEBRA, vtysh_pseudowire, vtysh_pseudowire_cmd, return CMD_SUCCESS; } -DEFUNSH(VTYSH_ZEBRA, vtysh_logicalrouter, vtysh_logicalrouter_cmd, - "logical-router (1-65535) ns NAME", - "Enable a logical-router\n" - "Specify the logical-router indentifier\n" - "The Name Space\n" - "The file name in " NS_RUN_DIR ", or a full pathname\n") -{ - vty->node = LOGICALROUTER_NODE; - return CMD_SUCCESS; -} - -DEFSH(VTYSH_ZEBRA, vtysh_no_logicalrouter_cmd, - "no logical-router (1-65535) ns NAME", NO_STR - "Enable a Logical-Router\n" - "Specify the Logical-Router identifier\n" - "The Name Space\n" - "The file name in " NS_RUN_DIR ", or a full pathname\n") - DEFUNSH(VTYSH_PBRD | VTYSH_SHARPD, vtysh_nexthop_group, vtysh_nexthop_group_cmd, "nexthop-group NHGNAME", "Nexthop Group configuration\n" @@ -2179,20 +2162,6 @@ DEFSH(VTYSH_ZEBRA, vtysh_no_vrf_netns_cmd, "Detach VRF from a Namespace\n" "The file name in " NS_RUN_DIR ", or a full pathname\n") -DEFUNSH(VTYSH_NS, vtysh_exit_logicalrouter, - vtysh_exit_logicalrouter_cmd, "exit", - "Exit current mode and down to previous mode\n") -{ - return vtysh_exit(vty); -} - -DEFUNSH(VTYSH_NS, vtysh_quit_logicalrouter, - vtysh_quit_logicalrouter_cmd, "quit", - "Exit current mode and down to previous mode\n") -{ - return vtysh_exit_logicalrouter(self, vty, argc, argv); -} - DEFUNSH(VTYSH_VRF, vtysh_exit_vrf, vtysh_exit_vrf_cmd, "exit", "Exit current mode and down to previous mode\n") { @@ -2211,7 +2180,7 @@ DEFUNSH(VTYSH_PBRD | VTYSH_SHARPD, vtysh_exit_nexthop_group, vtysh_exit_nexthop_ return vtysh_exit(vty); } -DEFUNSH(VTYSH_VRF, vtysh_quit_nexthop_group, vtysh_quit_nexthop_group_cmd, +DEFUNSH(VTYSH_PBRD | VTYSH_SHARPD, vtysh_quit_nexthop_group, vtysh_quit_nexthop_group_cmd, "quit", "Exit current mode and down to previous mode\n") { return vtysh_exit_nexthop_group(self, vty, argc, argv); @@ -2394,17 +2363,30 @@ DEFUN (vtysh_show_error_code, "Information on all errors\n" JSON_STR) { - char *fcmd = argv_concat(argv, argc, 0); - char cmd[256]; - int rv; + uint32_t arg = 0; + + if (!strmatch(argv[2]->text, "all")) + arg = strtoul(argv[2]->arg, NULL, 10); - snprintf(cmd, sizeof(cmd), "do %s", fcmd); + /* If it's not a shared code, send it to all the daemons */ + if (arg < LIB_FERR_START || arg > LIB_FERR_END) { + char *fcmd = argv_concat(argv, argc, 0); + char cmd[256]; - /* FIXME: Needs to determine which daemon to send to via code ranges */ - rv = show_per_daemon(cmd, ""); + snprintf(cmd, sizeof(cmd), "do %s", fcmd); + show_per_daemon(cmd, ""); + XFREE(MTYPE_TMP, fcmd); + /* Otherwise, print it ourselves to avoid duplication */ + } else { + bool json = strmatch(argv[argc - 1]->text, "json"); - XFREE(MTYPE_TMP, fcmd); - return rv; + if (!strmatch(argv[2]->text, "all")) + arg = strtoul(argv[2]->arg, NULL, 10); + + log_ref_display(vty, arg, json); + } + + return CMD_SUCCESS; } /* Memory */ @@ -3595,7 +3577,6 @@ void vtysh_init_vty(void) install_node(&interface_node, NULL); install_node(&pw_node, NULL); install_node(&link_params_node, NULL); - install_node(&logicalrouter_node, NULL); install_node(&vrf_node, NULL); install_node(&nh_group_node, NULL); install_node(&rmap_node, NULL); @@ -3805,13 +3786,6 @@ void vtysh_init_vty(void) install_element(PW_NODE, &vtysh_exit_interface_cmd); install_element(PW_NODE, &vtysh_quit_interface_cmd); - install_element(LOGICALROUTER_NODE, &vtysh_end_all_cmd); - - install_element(CONFIG_NODE, &vtysh_logicalrouter_cmd); - install_element(CONFIG_NODE, &vtysh_no_logicalrouter_cmd); - install_element(LOGICALROUTER_NODE, &vtysh_exit_logicalrouter_cmd); - install_element(LOGICALROUTER_NODE, &vtysh_quit_logicalrouter_cmd); - install_element(CONFIG_NODE, &vtysh_nexthop_group_cmd); install_element(NH_GROUP_NODE, &vtysh_end_all_cmd); install_element(NH_GROUP_NODE, &vtysh_exit_nexthop_group_cmd); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index 3b0b570a56..b16761b41a 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -54,7 +54,6 @@ DECLARE_MGROUP(MVTYSH) #define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD #define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_SHARPD|VTYSH_FABRICD #define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD|VTYSH_FABRICD|VTYSH_VRRPD -#define VTYSH_NS VTYSH_ZEBRA #define VTYSH_VRF VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_STATICD #define VTYSH_KEYS VTYSH_RIPD|VTYSH_EIGRPD diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 1e45e6f972..3ec2eb239d 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -23,6 +23,7 @@ #include "command.h" #include "linklist.h" #include "memory.h" +#include "typesafe.h" #include "vtysh/vtysh.h" #include "vtysh/vtysh_user.h" @@ -33,6 +34,8 @@ DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line") vector configvec; +PREDECL_RBTREE_UNIQ(config_master); + struct config { /* Configuration node name. */ char *name; @@ -45,6 +48,9 @@ struct config { /* Index of this config. */ uint32_t index; + + /* Node entry for the typed Red-black tree */ + struct config_master_item rbt_item; }; struct list *config_top; @@ -66,7 +72,7 @@ static struct config *config_new(void) return config; } -static int config_cmp(struct config *c1, struct config *c2) +static int config_cmp(const struct config *c1, const struct config *c2) { return strcmp(c1->name, c2->name); } @@ -78,28 +84,23 @@ static void config_del(struct config *config) XFREE(MTYPE_VTYSH_CONFIG, config); } +DECLARE_RBTREE_UNIQ(config_master, struct config, rbt_item, config_cmp) + static struct config *config_get(int index, const char *line) { struct config *config; - struct config *config_loop; - struct list *master; - struct listnode *node, *nnode; - - config = config_loop = NULL; + struct config_master_head *master; master = vector_lookup_ensure(configvec, index); if (!master) { - master = list_new(); - master->del = (void (*)(void *))config_del; - master->cmp = (int (*)(void *, void *))config_cmp; + master = XMALLOC(MTYPE_VTYSH_CONFIG, sizeof(struct config_master_head)); + config_master_init(master); vector_set_index(configvec, index, master); } - for (ALL_LIST_ELEMENTS(master, node, nnode, config_loop)) { - if (strcmp(config_loop->name, line) == 0) - config = config_loop; - } + const struct config config_ref = { .name = (char *)line }; + config = config_master_find(master, &config_ref); if (!config) { config = config_new(); @@ -108,7 +109,7 @@ static struct config *config_get(int index, const char *line) config->line->cmp = (int (*)(void *, void *))line_cmp; config->name = XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line); config->index = index; - listnode_add(master, config); + config_master_add(master, config); } return config; } @@ -263,7 +264,6 @@ void vtysh_config_parse_line(void *arg, const char *line) config_add_line(config->line, line); } else if (config->index == RMAP_NODE || config->index == INTERFACE_NODE - || config->index == LOGICALROUTER_NODE || config->index == VTY_NODE || config->index == VRF_NODE || config->index == NH_GROUP_NODE) @@ -278,8 +278,6 @@ void vtysh_config_parse_line(void *arg, const char *line) config = config_get(INTERFACE_NODE, line); else if (strncmp(line, "pseudowire", strlen("pseudowire")) == 0) config = config_get(PW_NODE, line); - else if (strncmp(line, "logical-router", strlen("logical-router")) == 0) - config = config_get(LOGICALROUTER_NODE, line); else if (strncmp(line, "vrf", strlen("vrf")) == 0) config = config_get(VRF_NODE, line); else if (strncmp(line, "nexthop-group", strlen("nexthop-group")) @@ -435,7 +433,7 @@ void vtysh_config_dump(void) struct listnode *node, *nnode; struct listnode *mnode, *mnnode; struct config *config; - struct list *master; + struct config_master_head *master; char *line; unsigned int i; @@ -446,7 +444,7 @@ void vtysh_config_dump(void) for (i = 0; i < vector_active(configvec); i++) if ((master = vector_slot(configvec, i)) != NULL) { - for (ALL_LIST_ELEMENTS(master, node, nnode, config)) { + while ((config = config_master_pop(master))) { /* Don't print empty sections for interface. * Route maps on the * other hand could have a legitimate empty @@ -466,6 +464,8 @@ void vtysh_config_dump(void) vty_out(vty, "%s\n", line); if (!NO_DELIMITER(i)) vty_out(vty, "!\n"); + + config_del(config); } if (NO_DELIMITER(i)) vty_out(vty, "!\n"); @@ -473,7 +473,8 @@ void vtysh_config_dump(void) for (i = 0; i < vector_active(configvec); i++) if ((master = vector_slot(configvec, i)) != NULL) { - list_delete(&master); + config_master_fini(master); + XFREE(MTYPE_VTYSH_CONFIG, master); vector_slot(configvec, i) = NULL; } list_delete_all_node(config_top); diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 9667460189..d536263db0 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -47,6 +47,8 @@ #include "linklist.h" #include "memory_vty.h" #include "libfrr.h" +#include "ferr.h" +#include "lib_errors.h" #include "vtysh/vtysh.h" #include "vtysh/vtysh_user.h" @@ -461,6 +463,9 @@ int main(int argc, char **argv, char **env) vtysh_read_config(vtysh_config); suid_off(); } + /* Error code library system */ + log_ref_init(); + lib_error_init(); if (markfile) { if (!inputfile) { diff --git a/yang/frr-bfdd.yang b/yang/frr-bfdd.yang index 24ca8f68a8..f9ac2e43b0 100644 --- a/yang/frr-bfdd.yang +++ b/yang/frr-bfdd.yang @@ -264,22 +264,22 @@ module frr-bfdd { leaf session-down-count { type uint32; - description "Amount of times the session went down"; + description "Number of times the session went down"; } leaf session-up-count { type uint32; - description "Amount of times the session went up"; + description "Number of times the session went up"; } leaf control-packet-input-count { type uint64; - description "Amount of control packets received"; + description "Number of control packets received"; } leaf control-packet-output-count { type uint64; - description "Amount of control packets sent"; + description "Number of control packets sent"; } /* @@ -296,12 +296,12 @@ module frr-bfdd { */ leaf echo-packet-input-count { type uint64; - description "Amount of echo packets received"; + description "Number of echo packets received"; } leaf echo-packet-output-count { type uint64; - description "Amount of echo packets sent"; + description "Number of echo packets sent"; } } diff --git a/yang/frr-eigrpd.yang b/yang/frr-eigrpd.yang index 26de7a71ae..853d823880 100644 --- a/yang/frr-eigrpd.yang +++ b/yang/frr-eigrpd.yang @@ -57,7 +57,7 @@ module frr-eigrpd { value 2; } - enum hmac-sha2 { + enum hmac-sha-256 { description "HMAC SHA256 algorithm"; value 3; } diff --git a/yang/frr-filter.yang b/yang/frr-filter.yang new file mode 100644 index 0000000000..e79ede87b7 --- /dev/null +++ b/yang/frr-filter.yang @@ -0,0 +1,353 @@ +module frr-filter { + yang-version 1.1; + namespace "http://frrouting.org/yang/filter"; + prefix frr-filter; + + import ietf-inet-types { + prefix inet; + } + import ietf-yang-types { + prefix yang; + } + + organization "Free Range Routing"; + contact + "FRR Users List: <mailto:frog@lists.frrouting.org> + FRR Development List: <mailto:dev@lists.frrouting.org>"; + description "This module defines filter settings"; + + revision 2019-07-04 { + description "Initial revision"; + } + + /* + * Types. + */ + typedef access-list-standard { + description "Standard IPv4 access list (any, host or a prefix)"; + type uint16 { + range "1..99 | 1300..1999"; + } + } + + typedef access-list-extended { + description + "Extended IPv4 access list (source / destination any, hosts or prefixes)"; + type uint16 { + range "100..199 | 2000..2699"; + } + } + + typedef access-list-legacy { + description "Standard/Extended IPv4 access list"; + type uint16 { + range "1..199 | 1300..2699"; + } + } + + typedef access-list-name { + description "Access list name formatting"; + type string; + } + + typedef access-list-sequence { + description "Access list sequence number"; + type uint32 { + range "1..4294967295"; + } + } + + typedef access-list-action { + description "Access list return action on match"; + type enumeration { + enum deny { + description "Deny an entry"; + value 0; + } + enum permit { + description "Accept an entry"; + value 1; + } + } + } + + /* + * Configuration data. + */ + container filter-list { + list access-list-legacy { + description "Access list legacy instance"; + + key "number sequence"; + + leaf number { + description "Access list sequence value"; + type access-list-legacy; + } + + leaf sequence { + description "Access list sequence value"; + type access-list-sequence; + } + + leaf action { + description "Access list action on match"; + type access-list-action; + mandatory true; + } + + leaf remark { + description "Access list remark"; + type string; + } + + choice value { + description + "Standard access list: value to match. + Extended access list: source value to match."; + mandatory true; + + leaf host { + description "Host to match"; + type inet:ipv4-address; + } + leaf network { + description "Network to match"; + type inet:ipv4-prefix; + } + leaf any { + description "Match any"; + type empty; + } + } + + choice extended-value { + when "./sequence >= 100 and ./sequence <= 199 or + ./sequence >= 2000 and ./sequence <= 2699"; + description "Destination value to match"; + + leaf destination-host { + description "Host to match"; + type inet:ipv4-address; + } + leaf destination-network { + description "Network to match"; + type inet:ipv4-prefix; + } + leaf destination-any { + description "Match any"; + type empty; + } + } + } + + list access-list { + description "Access list instance"; + + key "type identifier sequence"; + + leaf type { + description "Access list content type"; + type enumeration { + enum ipv4 { + description "Internet Protocol address version 4"; + value 0; + } + enum ipv6 { + description "Internet Protocol address version 6"; + value 1; + } + enum mac { + description "Media Access Control address"; + value 2; + } + + /* + * Protocol YANG models should augment the parent node to + * contain the routing protocol specific value. The protocol + * must also augment `value` leaf to include its specific + * values or expand the `when` statement on the existing cases. + */ + enum custom { + description "Custom data type"; + value 100; + } + } + } + + leaf identifier { + description "Access list identifier"; + type access-list-name; + } + + leaf sequence { + description "Access list sequence value"; + type access-list-sequence; + } + + leaf action { + description "Access list action on match"; + type access-list-action; + mandatory true; + } + + leaf remark { + description "Access list remark"; + type string; + } + + choice value { + description "Access list value to match"; + mandatory true; + + case ipv4-prefix { + when "./type = 'ipv4'"; + + leaf ipv4-prefix { + description "Configure IPv4 prefix to match"; + type inet:ipv4-prefix; + } + + leaf ipv4-exact-match { + description "Exact match of prefix"; + type boolean; + default false; + } + } + case ipv6-prefix { + when "./type = 'ipv6'"; + + leaf ipv6-prefix { + description "Configure IPv6 prefix to match"; + type inet:ipv6-prefix; + } + + leaf ipv6-exact-match { + description "Exact match of prefix"; + type boolean; + default false; + } + } + case mac { + when "./type = 'mac'"; + + leaf mac { + description "Configure MAC address to match"; + type yang:mac-address; + } + } + case any { + leaf any { + description "Match anything"; + type empty; + } + } + } + } + + list prefix-list { + description "Prefix list instance"; + + key "type name sequence"; + + leaf type { + description "Prefix list type"; + type enumeration { + enum ipv4 { + description "Internet Protocol address version 4"; + value 0; + } + enum ipv6 { + description "Internet Protocol address version 6"; + value 1; + } + } + } + + leaf name { + description "Prefix list name"; + type access-list-name; + } + + leaf sequence { + description "Access list sequence value"; + type access-list-sequence; + } + + leaf action { + description "Prefix list action on match"; + type access-list-action; + mandatory true; + } + + leaf description { + description "Prefix list user description"; + type string; + } + + choice value { + description "Prefix list value to match"; + mandatory true; + + case ipv4-prefix { + when "./type = 'ipv4'"; + + leaf ipv4-prefix { + description "Configure IPv4 prefix to match"; + type inet:ipv4-prefix; + } + + leaf ipv4-prefix-length-greater-or-equal { + description + "Specifies if matching prefixes with length greater than + or equal to value"; + type uint8 { + range "0..32"; + } + } + + leaf ipv4-prefix-length-lesser-or-equal { + description + "Specifies if matching prefixes with length lesser than + or equal to value"; + type uint8 { + range "0..32"; + } + } + } + case ipv6-prefix { + when "./type = 'ipv6'"; + + leaf ipv6-prefix { + description "Configure IPv6 prefix to match"; + type inet:ipv6-prefix; + } + + leaf ipv6-prefix-length-greater-or-equal { + description + "Specifies if matching prefixes with length greater than + or equal to value"; + type uint8 { + range "0..128"; + } + } + + leaf ipv6-prefix-length-lesser-or-equal { + description + "Specifies if matching prefixes with length lesser than + or equal to value"; + type uint8 { + range "0..128"; + } + } + } + case any { + leaf any { + description "Match anything"; + type empty; + } + } + } + } + } +} diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index 05a896a1db..9180b0c5f3 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -1024,7 +1024,7 @@ module frr-isisd { "This notification is sent when we attempt to propagate an LSP that is larger than the dataLinkBlockSize for the circuit. The notification generation must be throttled - with at least 5 seconds betweeen successive + with at least 5 seconds between successive notifications."; uses notification-instance-hdr; @@ -1090,7 +1090,7 @@ module frr-isisd { "This notification is sent when we receive a PDU with a different value for the System ID length. The notification generation must be throttled - with at least 5 seconds betweeen successive + with at least 5 seconds between successive notifications."; uses notification-instance-hdr; @@ -1114,7 +1114,7 @@ module frr-isisd { "This notification is sent when we receive a PDU with a different value for the Maximum Area Addresses. The notification generation must be throttled - with at least 5 seconds betweeen successive + with at least 5 seconds between successive notifications."; uses notification-instance-hdr; @@ -1170,7 +1170,7 @@ module frr-isisd { "This notification is sent when the system receives a PDU with the wrong authentication type field. The notification generation must be throttled - with at least 5 seconds betweeen successive + with at least 5 seconds between successive notifications."; uses notification-instance-hdr; @@ -1188,7 +1188,7 @@ module frr-isisd { "This notification is sent when the system receives a PDU with the wrong authentication information. The notification generation must be throttled with - with at least 5 seconds betweeen successive + with at least 5 seconds between successive notifications."; uses notification-instance-hdr; @@ -1206,7 +1206,7 @@ module frr-isisd { "This notification is sent when the system receives a PDU with a different protocol version number. The notification generation must be throttled - with at least 5 seconds betweeen successive + with at least 5 seconds between successive notifications."; uses notification-instance-hdr; @@ -1230,7 +1230,7 @@ module frr-isisd { "This notification is sent when the system receives a Hello PDU from an IS that does not share any area address. The notification generation must be throttled - with at least 5 seconds betweeen successive + with at least 5 seconds between successive notifications."; uses notification-instance-hdr; @@ -1248,7 +1248,7 @@ module frr-isisd { "This notification is sent when the system receives a Hello PDU from an IS but does not establish an adjacency for some reason. The notification generation must be - throttled with at least 5 seconds betweeen successive + throttled with at least 5 seconds between successive notifications."; uses notification-instance-hdr; @@ -1273,7 +1273,7 @@ module frr-isisd { description "This notification is sent when the system receives an LSP with a parse error. The notification generation must - be throttled with at least 5 seconds betweeen successive + be throttled with at least 5 seconds between successive notifications."; uses notification-instance-hdr; @@ -1350,7 +1350,7 @@ module frr-isisd { description "This notification is sent when an LSP is received. The notification generation must be throttled with at - least 5 seconds betweeen successive notifications."; + least 5 seconds between successive notifications."; uses notification-instance-hdr; uses notification-interface-hdr; @@ -1384,7 +1384,7 @@ module frr-isisd { description "This notification is sent when an LSP is regenerated. The notification generation must be throttled with at - least 5 seconds betweeen successive notifications."; + least 5 seconds between successive notifications."; uses notification-instance-hdr; leaf lsp-id { diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang new file mode 100644 index 0000000000..0ce40b474b --- /dev/null +++ b/yang/frr-route-map.yang @@ -0,0 +1,404 @@ +module frr-route-map { + yang-version 1.1; + namespace "http://frrouting.org/yang/route-map"; + prefix frr-route-map; + + import ietf-inet-types { + prefix inet; + } + import frr-filter { + prefix filter; + } + + organization "Free Range Routing"; + contact + "FRR Users List: <mailto:frog@lists.frrouting.org> + FRR Development List: <mailto:dev@lists.frrouting.org>"; + description "This module defines route map settings"; + + revision 2019-07-01 { + description "Initial revision"; + } + + /* + * Types. + */ + typedef route-map-sequence { + description "Route map valid sequence numbers"; + type uint16 { + range "1..65535"; + } + } + + typedef route-map-name { + description "Route map name format"; + type string; + } + + /* + * Operational data. + */ + container route-map { + list instance { + description "Route map instance"; + + key "name sequence"; + + leaf name { + description "Route map instance name"; + type route-map-name; + } + + leaf sequence { + description + "Route map instance priority (low number means higher priority)"; + type route-map-sequence; + } + + leaf description { + description "Route map description"; + type string; + } + + leaf action { + description + "Route map actions: permit (executes action), deny (quits evaluation)"; + mandatory true; + type enumeration { + enum permit { + description + "Executes configured action and permits the prefix/route + if the conditions matched. An alternative exit action can + be configured to continue processing the route map list + or jump to process another route map."; + value 0; + } + enum deny { + description + "If all conditions are met the prefix/route is denied and + route map processing stops."; + value 1; + } + } + } + + list match-condition { + description "Route map match conditions"; + + key "condition"; + + leaf condition { + description "Match condition"; + type enumeration { + enum interface { + description "Match interface"; + value 0; + } + enum ipv4-address-list { + description "Match an IPv4 access-list"; + value 1; + } + enum ipv4-prefix-list { + description "Match an IPv4 prefix-list"; + value 2; + } + enum ipv4-prefix-length { + description "Match an IPv4 prefix length"; + value 3; + } + enum ipv4-next-hop-list { + description "Match an IPv4 next-hop"; + value 4; + } + enum ipv4-next-hop-prefix-list { + description "Match an IPv4 next-hop prefix list"; + value 5; + } + enum ipv4-next-hop-prefix-length { + description "Match an IPv4 next-hop prefix length"; + value 6; + } + enum ipv4-next-hop-type { + description "Match an IPv4 next-hop type"; + value 7; + } + enum ipv6-address-list { + description "Match an IPv6 access-list"; + value 8; + } + enum ipv6-prefix-list { + description "Match an IPv6 prefix-list"; + value 9; + } + enum ipv6-prefix-length { + description "Match an IPv6 prefix length"; + value 10; + } + enum ipv6-next-hop { + description "Match an IPv6 next-hop"; + value 11; + } + enum ipv6-next-hop-type { + description "Match an IPv6 next-hop type"; + value 12; + } + enum metric { + description "Match a route metric"; + value 13; + } + enum tag { + description "Match a route tag"; + value 14; + } + + /* + * Protocol YANG models should augment the parent node to + * contain the routing protocol specific value. The protocol + * must also augment `condition-value` to include its specific + * values or expand the `when` statement on the existing cases. + */ + enum routing-protocol-specific { + description "Match a routing protocol specific type"; + value 100; + } + } + } + + choice condition-value { + description + "Value to match (interpretation depends on condition type)"; + case access-list-num { + when "./condition = 'ipv4-address-list' or + ./condition = 'ipv4-next-hop-list'"; + leaf access-list-num { + type filter:access-list-standard; + } + } + case access-list-num-extended { + when "./condition = 'ipv4-address-list' or + ./condition = 'ipv4-next-hop-list'"; + leaf access-list-num-extended { + type filter:access-list-extended; + } + } + case list-name { + when "./condition = 'ipv4-address-list' or + ./condition = 'ipv4-prefix-list' or + ./condition = 'ipv4-next-hop-list' or + ./condition = 'ipv4-next-hop-prefix-list' or + ./condition = 'ipv6-address-list' or + ./condition = 'ipv6-prefix-list'"; + leaf list-name { + type filter:access-list-name; + } + } + case ipv6-address { + when "./condition = 'ipv6-next-hop'"; + leaf ipv6-address { + type inet:ipv6-address; + } + } + case ipv4-prefix-length { + when "./condition = 'ipv4-prefix-length' or + ./condition = 'ipv4-next-hop-prefix-length'"; + leaf ipv4-prefix-length { + type uint8 { + range "0..32"; + } + } + } + case ipv6-prefix-length { + when "./condition = 'ipv6-prefix-length'"; + leaf ipv6-prefix-length { + type uint8 { + range "0..128"; + } + } + } + case ipv4-next-hop-type { + when "./condition = 'ipv4-next-hop-type'"; + leaf ipv4-next-hop-type { + type enumeration { + enum blackhole { + value 0; + } + } + } + } + case ipv6-next-hop-type { + when "./condition = 'ipv6-next-hop-type'"; + leaf ipv6-next-hop-type { + type enumeration { + enum blackhole { + value 0; + } + } + } + } + case metric { + when "./condition = 'metric'"; + leaf metric { + type uint32 { + range "1..4294967295"; + } + } + } + case tag { + when "./condition = 'tag'"; + leaf tag { + type uint32 { + range "1..4294967295"; + } + } + } + } + } + + list set-action { + description "Route map set actions"; + + key "action"; + + leaf action { + description "Action to do when the route map matches"; + type enumeration { + enum ipv4-next-hop { + description "Set IPv4 address of the next hop"; + value 0; + } + enum ipv6-next-hop { + description "Set IPv6 address of the next hop"; + value 1; + } + enum metric { + description "Set prefix/route metric"; + value 2; + } + enum tag { + description "Set tag"; + value 3; + } + + /* + * Protocol YANG models should augment the parent node to + * contain the routing protocol specific value. The protocol + * must also augment `action-value` to include its specific + * values or expand the `when` statement on the existing cases. + */ + enum routing-protocol-specific { + description "Set a routing protocol specific action"; + value 100; + } + } + } + + choice action-value { + description + "Value to set (interpretation depends on action-type)"; + case ipv4-address { + when "./action = 'ipv4-next-hop'"; + leaf ipv4-address { + description "IPv4 address"; + type inet:ipv4-address; + } + } + case ipv6-address { + when "./action = 'ipv6-next-hop'"; + leaf ipv6-address { + description "IPv6 address"; + type inet:ipv6-address; + } + } + case metric { + when "./action = 'metric'"; + choice metric-value { + description "Metric to set or use"; + case value { + leaf value { + description "Use the following metric value"; + type uint32 { + range "0..4294967295"; + } + } + } + case add-metric { + leaf add-metric { + description "Add unit to metric"; + type boolean; + } + } + case subtract-metric { + leaf subtract-metric { + description "Subtract unit from metric"; + type boolean; + } + } + case use-round-trip-time { + leaf use-round-trip-time { + description "Use the round trip time as metric"; + type boolean; + } + } + case add-round-trip-time { + leaf add-round-trip-time { + description "Add round trip time to metric"; + type boolean; + } + } + case subtract-round-trip-time { + leaf subtract-round-trip-time { + description "Subtract round trip time to metric"; + type boolean; + } + } + } + } + case tag { + leaf tag { + description "Tag value"; + type uint32 { + range "0..4294967295"; + } + } + } + } + } + + leaf call { + description + "Call another route map before calling `exit-policy`. If the + called route map returns deny then this route map will also + return deny"; + type string; + } + + leaf exit-policy { + description "What do to after route map successful match, set and call"; + type enumeration { + enum permit-or-deny { + description "End route map evaluation and return"; + value 0; + } + enum next { + description + "Proceed evaluating next route map entry per sequence"; + value 1; + } + enum goto { + description + "Go to route map entry with the provided sequence number"; + value 2; + } + } + default "permit-or-deny"; + } + + leaf goto-value { + when "../exit-policy = 'goto'"; + description + "Sequence number to jump (when using `goto` exit policy)"; + type route-map-sequence; + } + } + } +} diff --git a/yang/subdir.am b/yang/subdir.am index 4b3baeea9d..18d2bf160c 100644 --- a/yang/subdir.am +++ b/yang/subdir.am @@ -28,6 +28,10 @@ if BFDD dist_yangmodels_DATA += yang/frr-bfdd.yang endif +if EIGRPD +dist_yangmodels_DATA += yang/frr-eigrpd.yang +endif + if RIPD dist_yangmodels_DATA += yang/frr-ripd.yang endif diff --git a/zebra/connected.c b/zebra/connected.c index bba221c2cf..4101a4bf24 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -260,16 +260,6 @@ void connected_up(struct interface *ifp, struct connected *ifc) rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, &p, NULL, &nh, zvrf->table_id, metric, 0, 0, 0); - if (IS_ZEBRA_DEBUG_RIB_DETAILED) { - char buf[PREFIX_STRLEN]; - - zlog_debug( - "%u: IF %s address %s add/up, scheduling RIB processing", - ifp->vrf_id, ifp->name, - prefix2str(&p, buf, sizeof(buf))); - } - rib_update(zvrf->vrf->vrf_id, RIB_UPDATE_IF_CHANGE); - /* Schedule LSP forwarding entries for processing, if appropriate. */ if (zvrf->vrf->vrf_id == VRF_DEFAULT) { if (IS_ZEBRA_DEBUG_MPLS) { @@ -433,17 +423,6 @@ void connected_down(struct interface *ifp, struct connected *ifc) rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, &p, NULL, &nh, zvrf->table_id, 0, 0, false); - if (IS_ZEBRA_DEBUG_RIB_DETAILED) { - char buf[PREFIX_STRLEN]; - - zlog_debug( - "%u: IF %s IP %s address down, scheduling RIB processing", - zvrf->vrf->vrf_id, ifp->name, - prefix2str(&p, buf, sizeof(buf))); - } - - rib_update(zvrf->vrf->vrf_id, RIB_UPDATE_IF_CHANGE); - /* Schedule LSP forwarding entries for processing, if appropriate. */ if (zvrf->vrf->vrf_id == VRF_DEFAULT) { if (IS_ZEBRA_DEBUG_MPLS) { @@ -468,16 +447,6 @@ static void connected_delete_helper(struct connected *ifc, struct prefix *p) connected_withdraw(ifc); - if (IS_ZEBRA_DEBUG_RIB_DETAILED) { - char buf[PREFIX_STRLEN]; - - zlog_debug( - "%u: IF %s IP %s address del, scheduling RIB processing", - ifp->vrf_id, ifp->name, - prefix2str(p, buf, sizeof(buf))); - } - rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE); - /* Schedule LSP forwarding entries for processing, if appropriate. */ if (ifp->vrf_id == VRF_DEFAULT) { if (IS_ZEBRA_DEBUG_MPLS) { diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index df8d4bfe15..2c536c5d1f 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -590,7 +590,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) char *kind = NULL; char *desc = NULL; char *slave_kind = NULL; - struct zebra_ns *zns; + struct zebra_ns *zns = NULL; vrf_id_t vrf_id = VRF_DEFAULT; zebra_iftype_t zif_type = ZEBRA_IF_OTHER; zebra_slave_iftype_t zif_slave_type = ZEBRA_IF_SLAVE_NONE; @@ -598,6 +598,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) ifindex_t link_ifindex = IFINDEX_INTERNAL; ifindex_t bond_ifindex = IFINDEX_INTERNAL; struct zebra_if *zif; + struct vrf *vrf = NULL; zns = zebra_ns_lookup(ns_id); ifi = NLMSG_DATA(h); @@ -681,9 +682,17 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (tb[IFLA_LINK]) link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]); - /* Add interface. */ - ifp = if_get_by_name(name, vrf_id); - set_ifindex(ifp, ifi->ifi_index, zns); + vrf = vrf_get(vrf_id, NULL); + /* Add interface. + * We add by index first because in some cases such as the master + * interface, we have the index before we have the name. Fixing + * back references on the slave interfaces is painful if not done + * this way, i.e. by creating by ifindex. + */ + ifp = if_get_by_ifindex(ifi->ifi_index, vrf_id); + set_ifindex(ifp, ifi->ifi_index, zns); /* add it to ns struct */ + strlcpy(ifp->name, name, sizeof(ifp->name)); + IFNAME_RB_INSERT(vrf, ifp); ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu6 = ifp->mtu = *(uint32_t *)RTA_DATA(tb[IFLA_MTU]); ifp->metric = 0; @@ -1347,6 +1356,12 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) "Intf %s(%u) has come UP", name, ifp->ifindex); if_up(ifp); + } else { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "Intf %s(%u) has gone DOWN", + name, ifp->ifindex); + if_down(ifp); } } diff --git a/zebra/interface.c b/zebra/interface.c index 4eec435f1c..a2f80aff4e 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -799,15 +799,6 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id) /* Install connected routes (in new VRF). */ if (if_is_operative(ifp)) if_install_connected(ifp); - - /* Due to connected route change, schedule RIB processing for both old - * and new VRF. - */ - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug("%u: IF %s VRF change, scheduling RIB processing", - ifp->vrf_id, ifp->name); - rib_update(old_vrf_id, RIB_UPDATE_IF_CHANGE); - rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE); } static void ipv6_ll_address_to_mac(struct in6_addr *address, uint8_t *mac) @@ -950,11 +941,6 @@ void if_up(struct interface *ifp) /* Install connected routes to the kernel. */ if_install_connected(ifp); - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug("%u: IF %s up, scheduling RIB processing", - ifp->vrf_id, ifp->name); - rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE); - /* Handle interface up for specific types for EVPN. Non-VxLAN interfaces * are checked to see if (remote) neighbor entries need to be installed * on them for ARP suppression. @@ -1008,11 +994,6 @@ void if_down(struct interface *ifp) /* Uninstall connected routes from the kernel. */ if_uninstall_connected(ifp); - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug("%u: IF %s down, scheduling RIB processing", - ifp->vrf_id, ifp->name); - rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE); - if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp); /* Delete all neighbor addresses learnt through IPv6 RA */ @@ -1401,26 +1382,35 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) struct zebra_l2info_brslave *br_slave; br_slave = &zebra_if->brslave_info; - if (br_slave->bridge_ifindex != IFINDEX_INTERNAL) - vty_out(vty, " Master (bridge) ifindex %u\n", - br_slave->bridge_ifindex); + if (br_slave->bridge_ifindex != IFINDEX_INTERNAL) { + if (br_slave->br_if) + vty_out(vty, " Master interface: %s\n", + br_slave->br_if->name); + else + vty_out(vty, " Master ifindex: %u\n", + br_slave->bridge_ifindex); + } } if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) { struct zebra_l2info_bondslave *bond_slave; bond_slave = &zebra_if->bondslave_info; - if (bond_slave->bond_ifindex != IFINDEX_INTERNAL) - vty_out(vty, " Master (bond) ifindex %u\n", - bond_slave->bond_ifindex); + if (bond_slave->bond_ifindex != IFINDEX_INTERNAL) { + if (bond_slave->bond_if) + vty_out(vty, " Master interface: %s\n", + bond_slave->bond_if->name); + else + vty_out(vty, " Master ifindex: %u\n", + bond_slave->bond_ifindex); + } } if (zebra_if->link_ifindex != IFINDEX_INTERNAL) { - vty_out(vty, " Link ifindex %u", zebra_if->link_ifindex); if (zebra_if->link) - vty_out(vty, "(%s)\n", zebra_if->link->name); + vty_out(vty, " Parent interface: %s\n", zebra_if->link->name); else - vty_out(vty, "(Unknown)\n"); + vty_out(vty, " Parent ifindex: %d\n", zebra_if->link_ifindex); } if (HAS_LINK_PARAMS(ifp)) { diff --git a/zebra/label_manager.c b/zebra/label_manager.c index 03cfa572db..6e58f4b925 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -39,6 +39,7 @@ #include "zebra/label_manager.h" #include "zebra/zebra_errors.h" #include "zebra/zapi_msg.h" +#include "zebra/debug.h" #define CONNECTION_DELAY 5 @@ -116,8 +117,9 @@ int release_daemon_label_chunks(uint8_t proto, unsigned short instance) int count = 0; int ret; - zlog_debug("%s: Releasing chunks for client proto %s, instance %d", - __func__, zebra_route_string(proto), instance); + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Releasing chunks for client proto %s, instance %d", + __func__, zebra_route_string(proto), instance); for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) { if (lmc->proto == proto && lmc->instance == instance @@ -129,7 +131,8 @@ int release_daemon_label_chunks(uint8_t proto, unsigned short instance) } } - zlog_debug("%s: Released %d label chunks", __func__, count); + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Released %d label chunks", __func__, count); return count; } @@ -371,7 +374,8 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start, int ret = -1; /* check that size matches */ - zlog_debug("Releasing label chunk: %u - %u", start, end); + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("Releasing label chunk: %u - %u", start, end); /* find chunk and disown */ for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) { if (lmc->start != start) diff --git a/zebra/main.c b/zebra/main.c index 84e83bc37e..657d1247e9 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -34,7 +34,6 @@ #include "privs.h" #include "sigevent.h" #include "vrf.h" -#include "logicalrouter.h" #include "libfrr.h" #include "routemap.h" #include "frr_pthread.h" @@ -262,7 +261,6 @@ int main(int argc, char **argv) graceful_restart = 0; vrf_configure_backend(VRF_BACKEND_VRF_LITE); - logicalrouter_configure_backend(LOGICALROUTER_BACKEND_NETNS); frr_preinit(&zebra_di, argc, argv); @@ -349,8 +347,6 @@ int main(int argc, char **argv) break; case 'n': vrf_configure_backend(VRF_BACKEND_NETNS); - logicalrouter_configure_backend( - LOGICALROUTER_BACKEND_OFF); break; case OPTION_V6_RR_SEMANTICS: v6_rr_semantics = true; diff --git a/zebra/redistribute.c b/zebra/redistribute.c index d56579ff4f..1ae2ba92b0 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -172,6 +172,13 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p, __FUNCTION__); return; } + if (!zebra_check_addr(p)) { + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug("Redist update filter prefix %s", + prefix2str(p, buf, sizeof(buf))); + return; + } + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { send_redistribute = 0; @@ -246,6 +253,13 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p, return; } + if (!zebra_check_addr(p)) { + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug("Redist delete filter prefix %s", + prefix2str(p, buf, sizeof(buf))); + return; + } + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { if ((is_default_prefix(p) && vrf_bitmap_check(client->redist_default[afi], @@ -574,7 +588,7 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, struct route_entry *newre; struct route_entry *same; struct prefix p; - route_map_result_t ret = RMAP_MATCH; + route_map_result_t ret = RMAP_PERMITMATCH; afi_t afi; afi = family2afi(rn->p.family); @@ -583,7 +597,7 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, afi, re->type, re->instance, &rn->p, re->ng.nexthop, zvrf->vrf->vrf_id, re->tag, rmap_name); - if (ret != RMAP_MATCH) { + if (ret != RMAP_PERMITMATCH) { UNSET_FLAG(re->flags, ZEBRA_FLAG_SELECTED); zebra_del_import_table_entry(zvrf, rn, re); return 0; diff --git a/zebra/rib.h b/zebra/rib.h index 9d8cee8bf7..b82428e54c 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -124,18 +124,16 @@ struct route_entry { /* RIB internal status */ uint32_t status; #define ROUTE_ENTRY_REMOVED 0x1 -/* to simplify NHT logic when NHs change, instead of doing a NH by NH cmp */ -#define ROUTE_ENTRY_NEXTHOPS_CHANGED 0x2 /* The Route Entry has changed */ -#define ROUTE_ENTRY_CHANGED 0x4 +#define ROUTE_ENTRY_CHANGED 0x2 /* The Label has changed on the Route entry */ -#define ROUTE_ENTRY_LABELS_CHANGED 0x8 +#define ROUTE_ENTRY_LABELS_CHANGED 0x4 /* Route is queued for Installation into the Data Plane */ -#define ROUTE_ENTRY_QUEUED 0x10 +#define ROUTE_ENTRY_QUEUED 0x8 /* Route is installed into the Data Plane */ -#define ROUTE_ENTRY_INSTALLED 0x20 +#define ROUTE_ENTRY_INSTALLED 0x10 /* Route has Failed installation into the Data Plane in some manner */ -#define ROUTE_ENTRY_FAILED 0x40 +#define ROUTE_ENTRY_FAILED 0x20 /* Nexthop information. */ uint8_t nexthop_num; @@ -303,7 +301,6 @@ typedef struct rib_tables_iter_t_ { /* Events/reasons triggering a RIB update. */ typedef enum { - RIB_UPDATE_IF_CHANGE, RIB_UPDATE_RMAP_CHANGE, RIB_UPDATE_OTHER } rib_update_event_t; diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index e48ed9ef8b..3655763164 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1833,6 +1833,19 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) if (p->family == AF_INET || v6_rr_semantics) { /* Single 'replace' operation */ cmd = RTM_NEWROUTE; + + /* + * With route replace semantics in place + * for v4 routes and the new route is a system + * route we do not install anything. + * The problem here is that the new system + * route should cause us to withdraw from + * the kernel the old non-system route + */ + if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)) && + !RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) + (void)netlink_route_multipath(RTM_DELROUTE, + ctx); } else { /* * So v6 route replace semantics are not in diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 98bb2eda60..b6a8ee950c 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1431,12 +1431,10 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) if (!CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) || api.nexthop_num == 0) { - char buf_prefix[PREFIX_STRLEN]; - - prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix)); flog_warn(EC_ZEBRA_RX_ROUTE_NO_NEXTHOPS, - "%s: received a route without nexthops for prefix %s", - __func__, buf_prefix); + "%s: received a route without nexthops for prefix %pFX from client %s", + __func__, &api.prefix, + zebra_route_string(client->proto)); XFREE(MTYPE_RE, re); return; } @@ -1938,9 +1936,10 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg, "Unable to assign Label Chunk of size %u to %s instance %u", size, zebra_route_string(proto), instance); else - zlog_debug("Assigned Label Chunk %u - %u to %s instance %u", - lmc->start, lmc->end, - zebra_route_string(proto), instance); + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("Assigned Label Chunk %u - %u to %s instance %u", + lmc->start, lmc->end, + zebra_route_string(proto), instance); stream_failure: return; diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 78127f8ce8..5414502fa3 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -3225,7 +3225,7 @@ void zebra_dplane_start(void) /* Start dataplane pthread */ zdplane_info.dg_pthread = frr_pthread_new(&pattr, "Zebra dplane thread", - "Zebra dplane"); + "zebra_dplane"); zdplane_info.dg_master = zdplane_info.dg_pthread->master; diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c index 5f0a9ec011..a7e5147af3 100644 --- a/zebra/zebra_errors.c +++ b/zebra/zebra_errors.c @@ -659,7 +659,7 @@ static struct log_ref ferr_zebra_err[] = { { .code = EC_ZEBRA_RTM_VERSION_MISMATCH, .title = - "Zebra received kernel message with uknown version", + "Zebra received kernel message with unknown version", .description = "Zebra received a message from the kernel with a message version that does not match Zebra's internal version. Depending on version compatibility, this may cause issues sending and receiving messages to the kernel.", .suggestion = diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 822def318a..f347d3955c 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -238,7 +238,7 @@ static int netlink_route_info_add_nh(netlink_route_info_t *ri, if (re && CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)) { nhi.encap_info.encap_type = FPM_NH_ENCAP_VXLAN; - zl3vni = zl3vni_from_vrf(ri->rtm_table); + zl3vni = zl3vni_from_vrf(nexthop->vrf_id); if (zl3vni && is_l3vni_oper_up(zl3vni)) { /* Add VNI to VxLAN encap info */ diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index ca37dd748e..e549d80a5c 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -99,15 +99,18 @@ void zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave) br_slave->br_if = NULL; } -void zebra_l2_map_slave_to_bond(struct zebra_l2info_bondslave *bond_slave) +void zebra_l2_map_slave_to_bond(struct zebra_l2info_bondslave *bond_slave, + vrf_id_t vrf_id) { struct interface *bond_if; /* TODO: Handle change of master */ - bond_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), - bond_slave->bond_ifindex); + bond_if = if_lookup_by_index_all_vrf(bond_slave->bond_ifindex); if (bond_if) bond_slave->bond_if = bond_if; + else + bond_slave->bond_if = if_create_ifindex(bond_slave->bond_ifindex, + vrf_id); } void zebra_l2_unmap_slave_from_bond(struct zebra_l2info_bondslave *bond_slave) @@ -282,7 +285,7 @@ void zebra_l2if_update_bond_slave(struct interface *ifp, ifindex_t bond_ifindex) /* Set up or remove link with master */ if (bond_ifindex != IFINDEX_INTERNAL) - zebra_l2_map_slave_to_bond(&zif->bondslave_info); + zebra_l2_map_slave_to_bond(&zif->bondslave_info, ifp->vrf_id); else if (old_bond_ifindex != IFINDEX_INTERNAL) zebra_l2_unmap_slave_from_bond(&zif->bondslave_info); } diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h index 33aa2e3746..d9f0eec3f8 100644 --- a/zebra/zebra_l2.h +++ b/zebra/zebra_l2.h @@ -81,7 +81,7 @@ extern void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave); extern void zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave); extern void -zebra_l2_map_slave_to_bond(struct zebra_l2info_bondslave *bond_slave); +zebra_l2_map_slave_to_bond(struct zebra_l2info_bondslave *bond_slave, vrf_id_t); extern void zebra_l2_unmap_slave_from_bond(struct zebra_l2info_bondslave *bond_slave); extern void zebra_l2_bridge_add_update(struct interface *ifp, diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 4a88296051..f4b86f3cfe 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -87,7 +87,7 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop, break; case NEXTHOP_TYPE_BLACKHOLE: resolved_hop->type = NEXTHOP_TYPE_BLACKHOLE; - resolved_hop->bh_type = nexthop->bh_type; + resolved_hop->bh_type = newhop->bh_type; break; } @@ -272,8 +272,6 @@ static int nexthop_active(afi_t afi, struct route_entry *re, SET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE); - SET_FLAG(re->status, - ROUTE_ENTRY_NEXTHOPS_CHANGED); nexthop_set_resolved(afi, newhop, nexthop); resolved = 1; } @@ -339,7 +337,7 @@ static unsigned nexthop_active_check(struct route_node *rn, struct nexthop *nexthop) { struct interface *ifp; - route_map_result_t ret = RMAP_MATCH; + route_map_result_t ret = RMAP_PERMITMATCH; int family; char buf[SRCDEST2STR_BUFFER]; const struct prefix *p, *src_p; @@ -501,10 +499,8 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) && nexthop->type < NEXTHOP_TYPE_BLACKHOLE) && !(IPV6_ADDR_SAME(&prev_src.ipv6, &nexthop->rmap_src.ipv6))) - || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)) { + || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)) SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); - SET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED); - } } return re->nexthop_active_num; diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index db4f9d0015..94918365a3 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -23,7 +23,6 @@ #include "lib/ns.h" #include "lib/vrf.h" -#include "lib/logicalrouter.h" #include "lib/prefix.h" #include "lib/memory.h" @@ -45,7 +44,6 @@ DEFINE_MTYPE(ZEBRA, ZEBRA_NS, "Zebra Name Space") static struct zebra_ns *dzns; -static int logicalrouter_config_write(struct vty *vty); static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete); struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id) @@ -188,8 +186,6 @@ int zebra_ns_init(const char *optional_default_name) ns_id_external = ns_map_nsid_with_external(ns_id, true); ns_init_management(ns_id_external, ns_id); - logicalrouter_init(logicalrouter_config_write); - /* Do any needed per-NS data structure allocation. */ dzns->if_table = route_table_init(); @@ -215,21 +211,6 @@ int zebra_ns_init(const char *optional_default_name) return 0; } -static int logicalrouter_config_write(struct vty *vty) -{ - struct ns *ns; - int write = 0; - - RB_FOREACH (ns, ns_head, &ns_tree) { - if (ns->ns_id == NS_DEFAULT || ns->name == NULL) - continue; - vty_out(vty, "logical-router %u netns %s\n", ns->ns_id, - ns->name); - write = 1; - } - return write; -} - int zebra_ns_config_write(struct vty *vty, struct ns *ns) { if (ns && ns->name != NULL) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index fa8b5d400a..335cc8294c 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1128,8 +1128,6 @@ static void rib_process(struct route_node *rn) re->status, re->flags, re->distance, re->metric); - UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED); - /* Currently selected re. */ if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) { assert(old_selected == NULL); @@ -1364,6 +1362,7 @@ static void zebra_rib_fixup_system(struct route_node *rn) continue; SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED); for (ALL_NEXTHOPS(re->ng, nhop)) { if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE)) @@ -1775,7 +1774,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) /* Redistribute */ redistribute_update(dest_pfx, src_pfx, - re, NULL); + re, old_re); } /* @@ -1927,6 +1926,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) goto done; } + /* Ensure we clear the QUEUED flag */ + UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED); + /* Is this a notification that ... matters? We only really care about * the route that is currently selected for installation. */ @@ -1991,7 +1993,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) dplane_ctx_get_vrf(ctx), dest_str); /* We expect this to be the selected route, so we want - * to tell others about this transistion. + * to tell others about this transition. */ SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); @@ -2967,50 +2969,6 @@ void rib_update_table(struct route_table *table, rib_update_event_t event) RIB_ROUTE_ANY_QUEUED)) continue; switch (event) { - case RIB_UPDATE_IF_CHANGE: - /* Examine all routes that won't get processed by the - * protocol or - * triggered by nexthop evaluation (NHT). This would be - * system, - * kernel and certain static routes. Note that NHT will - * get - * triggered upon an interface event as connected routes - * always - * get queued for processing. - */ - RNODE_FOREACH_RE_SAFE (rn, re, next) { - struct nexthop *nh; - - if (re->type != ZEBRA_ROUTE_SYSTEM - && re->type != ZEBRA_ROUTE_KERNEL - && re->type != ZEBRA_ROUTE_CONNECT - && re->type != ZEBRA_ROUTE_STATIC) - continue; - - if (re->type != ZEBRA_ROUTE_STATIC) { - SET_FLAG(re->status, - ROUTE_ENTRY_CHANGED); - rib_queue_add(rn); - continue; - } - - for (nh = re->ng.nexthop; nh; nh = nh->next) - if (!(nh->type == NEXTHOP_TYPE_IPV4 - || nh->type == NEXTHOP_TYPE_IPV6)) - break; - - /* If we only have nexthops to a - * gateway, NHT will - * take care. - */ - if (nh) { - SET_FLAG(re->status, - ROUTE_ENTRY_CHANGED); - rib_queue_add(rn); - } - } - break; - case RIB_UPDATE_RMAP_CHANGE: case RIB_UPDATE_OTHER: /* Right now, examine all routes. Can restrict to a diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 6f65f8ab7a..da2fe4a30c 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -403,7 +403,7 @@ static int zebra_rnh_apply_nht_rmap(afi_t afi, struct zebra_vrf *zvrf, { int at_least_one = 0; struct nexthop *nexthop; - int ret; + route_map_result_t ret; if (prn && re) { for (nexthop = re->ng.nexthop; nexthop; @@ -465,6 +465,7 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi, RNODE_FOREACH_RE (rn, re) { if (!CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED) && CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED) + && !CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED) && (re->type != ZEBRA_ROUTE_BGP)) break; } @@ -679,6 +680,14 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, continue; } + if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED)) { + if (IS_ZEBRA_DEBUG_NHT_DETAILED) + zlog_debug( + "\tRoute Entry %s queued", + zebra_route_string(re->type)); + continue; + } + /* Just being SELECTED isn't quite enough - must * have an installed nexthop to be useful. */ @@ -859,10 +868,8 @@ static void zebra_rnh_clear_nhc_flag(struct zebra_vrf *zvrf, afi_t afi, re = zebra_rnh_resolve_nexthop_entry(zvrf, afi, nrn, rnh, &prn); - if (re) { - UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED); + if (re) UNSET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); - } } /* Evaluate all tracked entries (nexthops or routes for import into BGP) @@ -917,7 +924,7 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty, } for (rn = route_top(table); rn; rn = route_next(rn)) { - if (p && prefix_cmp(&rn->p, p) != 0) + if (p && !prefix_match(&rn->p, p)) continue; if (rn->info) diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 2f7d50541e..cee2c8980f 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -136,9 +136,9 @@ static int zebra_route_match_delete(struct vty *vty, const char *command, /* 'match tag TAG' * Match function return 1 if match is success else return 0 */ -static route_map_result_t route_match_tag(void *rule, - const struct prefix *prefix, - route_map_object_t type, void *object) +static enum route_map_cmd_result_t +route_match_tag(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { route_tag_t *tag; struct nh_rmap_obj *nh_data; @@ -162,10 +162,9 @@ static struct route_map_rule_cmd route_match_tag_cmd = { /* `match interface IFNAME' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_interface(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_interface(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct nh_rmap_obj *nh_data; char *ifname = rule; @@ -1025,10 +1024,9 @@ DEFPY (show_ipv6_protocol_nht, /* `match ip next-hop IP_ACCESS_LIST' */ /* Match function return 1 if match is success else return zero. */ -static route_map_result_t route_match_ip_next_hop(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_ip_next_hop(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct access_list *alist; struct nh_rmap_obj *nh_data; @@ -1037,7 +1035,7 @@ static route_map_result_t route_match_ip_next_hop(void *rule, if (type == RMAP_ZEBRA) { nh_data = object; if (!nh_data) - return RMAP_DENYMATCH; + return RMAP_NOMATCH; switch (nh_data->nexthop->type) { case NEXTHOP_TYPE_IFINDEX: @@ -1083,7 +1081,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_cmd = { /* `match ip next-hop prefix-list PREFIX_LIST' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1094,7 +1092,7 @@ route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix, if (type == RMAP_ZEBRA) { nh_data = (struct nh_rmap_obj *)object; if (!nh_data) - return RMAP_DENYMATCH; + return RMAP_NOMATCH; switch (nh_data->nexthop->type) { case NEXTHOP_TYPE_IFINDEX: @@ -1139,10 +1137,9 @@ static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = { /* Match function should return 1 if match is success else return zero. */ -static route_map_result_t route_match_address(afi_t afi, void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_address(afi_t afi, void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { struct access_list *alist; @@ -1158,19 +1155,16 @@ static route_map_result_t route_match_address(afi_t afi, void *rule, return RMAP_NOMATCH; } -static route_map_result_t route_match_ip_address(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_ip_address(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { return route_match_address(AFI_IP, rule, prefix, type, object); } -static route_map_result_t route_match_ipv6_address(void *rule, - const struct prefix *prefix, - route_map_object_t type, - void *object) - +static enum route_map_cmd_result_t +route_match_ipv6_address(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) { return route_match_address(AFI_IP6, rule, prefix, type, object); } @@ -1200,7 +1194,7 @@ static struct route_map_rule_cmd route_match_ipv6_address_cmd = { /* `match ip address prefix-list PREFIX_LIST' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_address_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object, afi_t afi) { @@ -1218,7 +1212,7 @@ route_match_address_prefix_list(void *rule, const struct prefix *prefix, return RMAP_NOMATCH; } -static route_map_result_t +static enum route_map_cmd_result_t route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1241,7 +1235,7 @@ static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { route_match_address_prefix_list_compile, route_match_address_prefix_list_free}; -static route_map_result_t +static enum route_map_cmd_result_t route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1256,7 +1250,7 @@ static struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = { /* `match ipv6 next-hop type <TYPE>' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1265,7 +1259,7 @@ route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix, if (type == RMAP_ZEBRA && prefix->family == AF_INET6) { nh_data = (struct nh_rmap_obj *)object; if (!nh_data) - return RMAP_DENYMATCH; + return RMAP_NOMATCH; if (nh_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) return RMAP_MATCH; @@ -1290,7 +1284,7 @@ struct route_map_rule_cmd route_match_ipv6_next_hop_type_cmd = { /* `match ip address prefix-len PREFIXLEN' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_address_prefix_len(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1341,7 +1335,7 @@ static struct route_map_rule_cmd route_match_ipv6_address_prefix_len_cmd = { /* `match ip nexthop prefix-len PREFIXLEN' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ip_nexthop_prefix_len(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1352,7 +1346,7 @@ route_match_ip_nexthop_prefix_len(void *rule, const struct prefix *prefix, if (type == RMAP_ZEBRA) { nh_data = (struct nh_rmap_obj *)object; if (!nh_data || !nh_data->nexthop) - return RMAP_DENYMATCH; + return RMAP_NOMATCH; switch (nh_data->nexthop->type) { case NEXTHOP_TYPE_IFINDEX: @@ -1381,7 +1375,7 @@ static struct route_map_rule_cmd route_match_ip_nexthop_prefix_len_cmd = { /* `match ip next-hop type <blackhole>' */ -static route_map_result_t +static enum route_map_cmd_result_t route_match_ip_next_hop_type(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1390,7 +1384,7 @@ route_match_ip_next_hop_type(void *rule, const struct prefix *prefix, if (type == RMAP_ZEBRA && prefix->family == AF_INET) { nh_data = (struct nh_rmap_obj *)object; if (!nh_data) - return RMAP_DENYMATCH; + return RMAP_NOMATCH; if (nh_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) return RMAP_MATCH; @@ -1415,10 +1409,9 @@ static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = { /* `match source-protocol PROTOCOL' */ -static route_map_result_t route_match_source_protocol(void *rule, - const struct prefix *p, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_source_protocol(void *rule, const struct prefix *p, + route_map_object_t type, void *object) { uint32_t *rib_type = (uint32_t *)rule; struct nh_rmap_obj *nh_data; @@ -1426,7 +1419,7 @@ static route_map_result_t route_match_source_protocol(void *rule, if (type == RMAP_ZEBRA) { nh_data = (struct nh_rmap_obj *)object; if (!nh_data) - return RMAP_DENYMATCH; + return RMAP_NOMATCH; return ((nh_data->source_protocol == *rib_type) ? RMAP_MATCH : RMAP_NOMATCH); @@ -1457,10 +1450,9 @@ static struct route_map_rule_cmd route_match_source_protocol_cmd = { route_match_source_protocol_compile, route_match_source_protocol_free}; /* `source-instance` */ -static route_map_result_t route_match_source_instance(void *rule, - const struct prefix *p, - route_map_object_t type, - void *object) +static enum route_map_cmd_result_t +route_match_source_instance(void *rule, const struct prefix *p, + route_map_object_t type, void *object) { uint8_t *instance = (uint8_t *)rule; struct nh_rmap_obj *nh_data; @@ -1470,7 +1462,7 @@ static route_map_result_t route_match_source_instance(void *rule, nh_data = (struct nh_rmap_obj *)object; if (!nh_data) - return RMAP_DENYMATCH; + return RMAP_NOMATCH; return (nh_data->instance == *instance) ? RMAP_MATCH : RMAP_NOMATCH; } @@ -1500,8 +1492,9 @@ static struct route_map_rule_cmd route_match_source_instance_cmd = { /* `set src A.B.C.D' */ /* Set src. */ -static route_map_result_t route_set_src(void *rule, const struct prefix *prefix, - route_map_object_t type, void *object) +static enum route_map_cmd_result_t +route_set_src(void *rule, const struct prefix *prefix, route_map_object_t type, + void *object) { struct nh_rmap_obj *nh_data; @@ -1767,7 +1760,7 @@ zebra_route_map_check(int family, int rib_type, uint8_t instance, struct zebra_vrf *zvrf, route_tag_t tag) { struct route_map *rmap = NULL; - route_map_result_t ret = RMAP_MATCH; + route_map_result_t ret = RMAP_PERMITMATCH; struct nh_rmap_obj nh_obj; nh_obj.nexthop = nexthop; @@ -1839,7 +1832,7 @@ route_map_result_t zebra_nht_route_map_check(afi_t afi, int client_proto, struct nexthop *nexthop) { struct route_map *rmap = NULL; - route_map_result_t ret = RMAP_MATCH; + route_map_result_t ret = RMAP_PERMITMATCH; struct nh_rmap_obj nh_obj; nh_obj.nexthop = nexthop; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 74baabbf24..5c0dc27380 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -448,6 +448,9 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if (re->tag) json_object_int_add(json_route, "tag", re->tag); + if (re->table) + json_object_int_add(json_route, "table", re->table); + json_object_int_add(json_route, "internalStatus", re->status); json_object_int_add(json_route, "internalFlags", @@ -804,7 +807,8 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, bool use_fib, route_tag_t tag, const struct prefix *longer_prefix_p, bool supernets_only, int type, - unsigned short ospf_instance_id, bool use_json) + unsigned short ospf_instance_id, bool use_json, + uint32_t tableid) { struct route_node *rn; struct route_entry *re; @@ -867,10 +871,12 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, vty_out(vty, SHOW_ROUTE_V6_HEADER); - if (zvrf_id(zvrf) != VRF_DEFAULT) + if (tableid && tableid != RT_TABLE_MAIN) + vty_out(vty, "\nVRF %s table %u:\n", + zvrf_name(zvrf), tableid); + else if (zvrf_id(zvrf) != VRF_DEFAULT) vty_out(vty, "\nVRF %s:\n", zvrf_name(zvrf)); - first = 0; } } @@ -927,7 +933,7 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, do_show_route_helper(vty, zvrf, table, afi, use_fib, tag, longer_prefix_p, supernets_only, type, - ospf_instance_id, use_json); + ospf_instance_id, use_json, 0); return CMD_SUCCESS; } @@ -950,7 +956,7 @@ DEFPY (show_route_table, t = zebra_router_find_table(zvrf, table, afi, SAFI_UNICAST); if (t) do_show_route_helper(vty, zvrf, t, afi, false, 0, false, false, - 0, 0, !!json); + 0, 0, !!json, table); return CMD_SUCCESS; } @@ -979,14 +985,50 @@ DEFPY (show_route_table_vrf, t = zebra_router_find_table(zvrf, table, afi, SAFI_UNICAST); if (t) do_show_route_helper(vty, zvrf, t, afi, false, 0, false, false, - 0, 0, !!json); + 0, 0, !!json, table); + + return CMD_SUCCESS; +} + +DEFPY (show_route_all_table_vrf, + show_route_all_table_vrf_cmd, + "show <ip$ipv4|ipv6$ipv6> route [vrf <NAME$vrf_name|all$vrf_all>] tables [json$json]", + SHOW_STR + IP_STR + IP6_STR + "IP routing table\n" + "Display all tables\n" + VRF_FULL_CMD_HELP_STR + JSON_STR) +{ + afi_t afi = ipv4 ? AFI_IP : AFI_IP6; + struct zebra_vrf *zvrf = NULL; + vrf_id_t vrf_id = VRF_UNKNOWN; + struct zebra_router_table *zrt; + if (vrf_name) { + VRF_GET_ID(vrf_id, vrf_name, !!json); + zvrf = zebra_vrf_lookup_by_id(vrf_id); + } + + RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) { + rib_table_info_t *info = route_table_get_info(zrt->table); + + if (zvrf && zvrf != info->zvrf) + continue; + if (zrt->afi != afi || zrt->safi != SAFI_UNICAST) + continue; + if (zrt->table) + do_show_route_helper(vty, info->zvrf, zrt->table, afi, + false, 0, false, false, + 0, 0, !!json, zrt->tableid); + } return CMD_SUCCESS; } DEFPY (show_ip_nht, show_ip_nht_cmd, - "show <ip$ipv4|ipv6$ipv6> <nht|import-check>$type [<A.B.C.D|X:X::X:X>$addr|vrf NAME$vrf_name <A.B.C.D|X:X::X:X>$addr|vrf all$vrf_all]", + "show <ip$ipv4|ipv6$ipv6> <nht|import-check>$type [<A.B.C.D|X:X::X:X>$addr|vrf NAME$vrf_name [<A.B.C.D|X:X::X:X>$addr]|vrf all$vrf_all]", SHOW_STR IP_STR IP6_STR @@ -2383,7 +2425,7 @@ DEFUN (show_pbr_iptable, DEFPY (clear_evpn_dup_addr, clear_evpn_dup_addr_cmd, - "clear evpn dup-addr vni <all$vni_all |" CMD_VNI_RANGE"$vni [mac M:A:C$mac_val | ip <A.B.C.D|X:X::X:X>]>", + "clear evpn dup-addr vni <all$vni_all |" CMD_VNI_RANGE"$vni [mac X:X:X:X:X:X | ip <A.B.C.D|X:X::X:X>]>", CLEAR_STR "EVPN\n" "Duplicate address \n" @@ -2398,16 +2440,14 @@ DEFPY (clear_evpn_dup_addr, { struct zebra_vrf *zvrf; struct ipaddr host_ip = {.ipa_type = IPADDR_NONE }; - struct ethaddr mac_addr; int ret = CMD_SUCCESS; zvrf = zebra_vrf_get_evpn(); if (vni_str) { - if (mac_val) { - prefix_str2mac(mac_val, &mac_addr); + if (!is_zero_mac(&mac->eth_addr)) { ret = zebra_vxlan_clear_dup_detect_vni_mac(vty, zvrf, vni, - &mac_addr); + &mac->eth_addr); } else if (ip) { if (sockunion_family(ip) == AF_INET) { host_ip.ipa_type = IPADDR_V4; @@ -2991,6 +3031,7 @@ void zebra_vty_init(void) install_element(VIEW_NODE, &show_route_table_cmd); if (vrf_is_backend_netns()) install_element(VIEW_NODE, &show_route_table_vrf_cmd); + install_element(VIEW_NODE, &show_route_all_table_vrf_cmd); install_element(VIEW_NODE, &show_route_detail_cmd); install_element(VIEW_NODE, &show_route_summary_cmd); install_element(VIEW_NODE, &show_ip_nht_cmd); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 24cd88b91f..bb31247b6a 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2787,27 +2787,40 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, /* Set "local" forwarding info. */ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); - SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW); ZEBRA_NEIGH_SET_ACTIVE(n); - /* Set Router flag (R-bit) */ - if (ip->ipa_type == IPADDR_V6) - SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); memcpy(&n->emac, macaddr, ETH_ALEN); n->ifindex = ifp->ifindex; /* Only advertise in BGP if the knob is enabled */ - if (!advertise_gw_macip_enabled(zvni)) - return 0; + if (advertise_gw_macip_enabled(zvni)) { - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( + SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW); + SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW); + /* Set Router flag (R-bit) */ + if (ip->ipa_type == IPADDR_V6) + SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s add to BGP with flags 0x%x", ifp->name, ifp->ifindex, zvni->vni, prefix_mac2str(macaddr, buf, sizeof(buf)), ipaddr2str(ip, buf2, sizeof(buf2)), n->flags); - zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, - n->flags, n->loc_seq); + zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, + n->flags, n->loc_seq); + } else if (advertise_svi_macip_enabled(zvni)) { + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "SVI %s(%u) L2-VNI %u, sending SVI MAC %s IP %s add to BGP with flags 0x%x", + ifp->name, ifp->ifindex, zvni->vni, + prefix_mac2str(macaddr, buf, sizeof(buf)), + ipaddr2str(ip, buf2, sizeof(buf2)), n->flags); + + zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, + n->flags, n->loc_seq); + } return 0; } @@ -3403,6 +3416,39 @@ static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac) return 0; } +static bool zvni_check_mac_del_from_db(struct mac_walk_ctx *wctx, + zebra_mac_t *mac) +{ + if ((wctx->flags & DEL_LOCAL_MAC) && + (mac->flags & ZEBRA_MAC_LOCAL)) + return true; + else if ((wctx->flags & DEL_REMOTE_MAC) && + (mac->flags & ZEBRA_MAC_REMOTE)) + return true; + else if ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP) && + (mac->flags & ZEBRA_MAC_REMOTE) && + IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip)) + return true; + else if ((wctx->flags & DEL_LOCAL_MAC) && + (mac->flags & ZEBRA_MAC_AUTO) && + !listcount(mac->neigh_list)) { + if (IS_ZEBRA_DEBUG_VXLAN) { + char buf[ETHER_ADDR_STRLEN]; + + zlog_debug("%s: Del MAC %s flags 0x%x", + __PRETTY_FUNCTION__, + prefix_mac2str(&mac->macaddr, + buf, sizeof(buf)), + mac->flags); + } + wctx->uninstall = 0; + + return true; + } + + return false; +} + /* * Free MAC hash entry (callback) */ @@ -3411,18 +3457,11 @@ static void zvni_mac_del_hash_entry(struct hash_bucket *bucket, void *arg) struct mac_walk_ctx *wctx = arg; zebra_mac_t *mac = bucket->data; - if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL)) - || ((wctx->flags & DEL_REMOTE_MAC) - && (mac->flags & ZEBRA_MAC_REMOTE)) - || ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP) - && (mac->flags & ZEBRA_MAC_REMOTE) - && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, - &wctx->r_vtep_ip))) { + if (zvni_check_mac_del_from_db(wctx, mac)) { if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) { zvni_mac_send_del_to_client(wctx->zvni->vni, &mac->macaddr); } - if (wctx->uninstall) zvni_mac_uninstall(wctx->zvni, mac); @@ -5352,8 +5391,6 @@ static void process_remote_macip_add(vni_t vni, if (ipa_len) SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); } else { - const char *mac_type; - /* When host moves but changes its (MAC,IP) * binding, BGP may install a MACIP entry that * corresponds to "older" location of the host @@ -5362,16 +5399,14 @@ static void process_remote_macip_add(vni_t vni, * the sequence number and ignore this update * if appropriate. */ - if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) tmp_seq = mac->loc_seq; - mac_type = "local"; - } else { + else tmp_seq = mac->rem_seq; - mac_type = "remote"; - } + if (seq < tmp_seq) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing %s MAC has higher seq %u", + zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing MAC has higher seq %u flags 0x%x", vni, prefix_mac2str(macaddr, buf, sizeof(buf)), @@ -5379,8 +5414,7 @@ static void process_remote_macip_add(vni_t vni, ipa_len ? ipaddr2str(ipaddr, buf1, sizeof(buf1)) : "", - mac_type, - tmp_seq); + tmp_seq, mac->flags); return; } } @@ -6758,7 +6792,7 @@ int zebra_vxlan_clear_dup_detect_vni_ip(struct vty *vty, if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) { vty_out(vty, - "%% Requsted host IP %s is not duplicate detected\n", + "%% Requested host IP %s is not duplicate detected\n", buf); return CMD_WARNING; } @@ -7294,8 +7328,13 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp, * of a VxLAN bridge. */ zvni = zvni_from_svi(ifp, link_if); - if (!zvni) + if (!zvni) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%s: Del neighbor %s VNI is not present for interface %s", + __PRETTY_FUNCTION__, + ipaddr2str(ip, buf, sizeof(buf)), ifp->name); return 0; + } if (!zvni->vxlan_if) { zlog_debug( @@ -7692,9 +7731,10 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, return 0; if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("DEL MAC %s intf %s(%u) VID %u -> VNI %u flags 0x%x", + zlog_debug("DEL MAC %s intf %s(%u) VID %u -> VNI %u seq %u flags 0x%x nbr count %u", prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, - ifp->ifindex, vid, zvni->vni, mac->flags); + ifp->ifindex, vid, zvni->vni, mac->loc_seq, + mac->flags, listcount(mac->neigh_list)); /* Update all the neigh entries associated with this mac */ zvni_process_neigh_on_local_mac_del(zvni, mac); @@ -9008,7 +9048,7 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS) if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug("EVPN SVI-MACIP Adv %s, currently %s", advertise ? "enabled" : "disabled", - advertise_gw_macip_enabled(NULL) + advertise_svi_macip_enabled(NULL) ? "enabled" : "disabled"); @@ -9739,8 +9779,9 @@ void zebra_vxlan_sg_replay(ZAPI_HANDLER_ARGS) SET_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG); if (!EVPN_ENABLED(zvrf)) { - zlog_debug("VxLAN SG replay request on unexpected vrf %d", - zvrf->vrf->vrf_id); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("VxLAN SG replay request on unexpected vrf %d", + zvrf->vrf->vrf_id); return; } |
