diff options
143 files changed, 3037 insertions, 1470 deletions
diff --git a/Makefile.am b/Makefile.am index ed22c60e7c..f9fb231962 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,8 +5,7 @@ include common.am AM_CPPFLAGS += -I$(top_srcdir) -I$(top_srcdir)/include -I$(top_srcdir)/lib \ -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/lib -VERSION_TYPE := $(shell if echo $(VERSION) | grep -q '^[0-9\.]*$$'; then echo RELEASE ; else echo DEV ; fi) -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DCONFDATE=$(CONFDATE) -DVERSION_TYPE_$(VERSION_TYPE) +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DCONFDATE=$(CONFDATE) LIBCAP = @LIBCAP@ EXTRA_DIST = diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 3880d2020d..2f19bbbd73 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -134,6 +134,7 @@ dist_examples_DATA = bgpd.conf.sample bgpd.conf.sample2 \ bgp_vty.o: bgp_vty_clippy.c bgp_route.o: bgp_route_clippy.c +bgp_debug.o: bgp_debug_clippy.c EXTRA_DIST = BGP4-MIB.txt diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 6596e7cfa2..e5ad5e2338 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1890,6 +1890,16 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) /* Check if this is a Gateway MAC-IP advertisement */ attr->default_gw = bgp_attr_default_gw(attr); + /* Handle scenario where router flag ecommunity is not + * set but default gw ext community is present. + * Use default gateway, set and propogate R-bit. + */ + if (attr->default_gw) + attr->router_flag = 1; + + /* Check EVPN Neighbor advertisement flags, R-bit */ + bgp_attr_evpn_na_flag(attr, &attr->router_flag); + /* Extract the Rmac, if any */ bgp_attr_rmac(attr, &attr->rmac); diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index f17c2a68e4..883b129136 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -185,6 +185,9 @@ struct attr { /* Flag for default gateway extended community in EVPN */ uint8_t default_gw; + /* NA router flag (R-bit) support in EVPN */ + uint8_t router_flag; + /* route tag */ route_tag_t tag; diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 14ff01ada5..88e520fdc5 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -210,6 +210,39 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) return 0; } +/* + * return true if attr contains router flag extended community + */ +void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag) +{ + struct ecommunity *ecom; + int i; + uint8_t val; + + ecom = attr->ecommunity; + if (!ecom || !ecom->size) + return; + + /* If there is a evpn na extendd community set router_flag */ + for (i = 0; i < ecom->size; i++) { + uint8_t *pnt; + uint8_t type, sub_type; + + pnt = (ecom->val + (i * ECOMMUNITY_SIZE)); + type = *pnt++; + sub_type = *pnt++; + + if (type == ECOMMUNITY_ENCODE_EVPN && + sub_type == ECOMMUNITY_EVPN_SUBTYPE_ND) { + val = *pnt++; + if (val & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG) { + *router_flag = 1; + break; + } + } + } +} + /* dst prefix must be AF_INET or AF_INET6 prefix, to forge EVPN prefix */ extern int bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag, struct prefix *dst) diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index 7454b81b96..b036702151 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -65,4 +65,6 @@ extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky); extern uint8_t bgp_attr_default_gw(struct attr *attr); +extern void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag); + #endif /* _QUAGGA_BGP_ATTR_EVPN_H */ diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index b2f34dd968..3a93db1ac6 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -332,71 +332,70 @@ community_list_entry_lookup(struct community_list *list, const void *arg, static char *community_str_get(struct community *com, int i) { - int len; uint32_t comval; uint16_t as; uint16_t val; char *str; - char *pnt; memcpy(&comval, com_nthval(com, i), sizeof(uint32_t)); comval = ntohl(comval); switch (comval) { case COMMUNITY_INTERNET: - len = strlen(" internet"); + str = XSTRDUP(MTYPE_COMMUNITY_STR, "internet"); break; - case COMMUNITY_NO_EXPORT: - len = strlen(" no-export"); + case COMMUNITY_GSHUT: + str = XSTRDUP(MTYPE_COMMUNITY_STR, "graceful-shutdown"); break; - case COMMUNITY_NO_ADVERTISE: - len = strlen(" no-advertise"); + case COMMUNITY_ACCEPT_OWN: + str = XSTRDUP(MTYPE_COMMUNITY_STR, "accept-own"); break; - case COMMUNITY_LOCAL_AS: - len = strlen(" local-AS"); + case COMMUNITY_ROUTE_FILTER_TRANSLATED_v4: + str = XSTRDUP(MTYPE_COMMUNITY_STR, + "route-filter-translated-v4"); break; - case COMMUNITY_GSHUT: - len = strlen(" graceful-shutdown"); + case COMMUNITY_ROUTE_FILTER_v4: + str = XSTRDUP(MTYPE_COMMUNITY_STR, "route-filter-v4"); break; - default: - len = strlen(" 65536:65535"); + case COMMUNITY_ROUTE_FILTER_TRANSLATED_v6: + str = XSTRDUP(MTYPE_COMMUNITY_STR, + "route-filter-translated-v6"); break; - } - - /* Allocate memory. */ - str = pnt = XMALLOC(MTYPE_COMMUNITY_STR, len); - - switch (comval) { - case COMMUNITY_INTERNET: - strcpy(pnt, "internet"); - pnt += strlen("internet"); + case COMMUNITY_ROUTE_FILTER_v6: + str = XSTRDUP(MTYPE_COMMUNITY_STR, "route-filter-v6"); + break; + case COMMUNITY_LLGR_STALE: + str = XSTRDUP(MTYPE_COMMUNITY_STR, "llgr-stale"); + break; + case COMMUNITY_NO_LLGR: + str = XSTRDUP(MTYPE_COMMUNITY_STR, "no-llgr"); + break; + case COMMUNITY_ACCEPT_OWN_NEXTHOP: + str = XSTRDUP(MTYPE_COMMUNITY_STR, "accept-own-nexthop"); + break; + case COMMUNITY_BLACKHOLE: + str = XSTRDUP(MTYPE_COMMUNITY_STR, "blackhole"); break; case COMMUNITY_NO_EXPORT: - strcpy(pnt, "no-export"); - pnt += strlen("no-export"); + str = XSTRDUP(MTYPE_COMMUNITY_STR, "no-export"); break; case COMMUNITY_NO_ADVERTISE: - strcpy(pnt, "no-advertise"); - pnt += strlen("no-advertise"); + str = XSTRDUP(MTYPE_COMMUNITY_STR, "no-advertise"); break; case COMMUNITY_LOCAL_AS: - strcpy(pnt, "local-AS"); - pnt += strlen("local-AS"); + str = XSTRDUP(MTYPE_COMMUNITY_STR, "local-AS"); break; - case COMMUNITY_GSHUT: - strcpy(pnt, "graceful-shutdown"); - pnt += strlen("graceful-shutdown"); + case COMMUNITY_NO_PEER: + str = XSTRDUP(MTYPE_COMMUNITY_STR, "no-peer"); break; default: + str = XSTRDUP(MTYPE_COMMUNITY_STR, "65536:65535"); as = (comval >> 16) & 0xFFFF; val = comval & 0xFFFF; - sprintf(pnt, "%u:%d", as, val); - pnt += strlen(pnt); + snprintf(str, strlen(str), "%u:%d", as, val); break; } - *pnt = '\0'; - return str; } @@ -547,47 +546,77 @@ static int ecommunity_regexp_match(struct ecommunity *ecom, regex_t *reg) static struct community * community_regexp_delete (struct community *com, regex_t * reg) { - int i; - uint32_t comval; - /* Maximum is "65535:65535" + '\0'. */ - char c[12]; - const char *str; - - if (!com) - return NULL; - - i = 0; - while (i < com->size) - { - memcpy (&comval, com_nthval (com, i), sizeof (uint32_t)); - comval = ntohl (comval); - - switch (comval) - { - case COMMUNITY_INTERNET: - str = "internet"; - break; - case COMMUNITY_NO_EXPORT: - str = "no-export"; - break; - case COMMUNITY_NO_ADVERTISE: - str = "no-advertise"; - break; - case COMMUNITY_LOCAL_AS: - str = "local-AS"; - break; - default: - sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF, comval & 0xFFFF); - str = c; - break; - } - - if (regexec (reg, str, 0, NULL, 0) == 0) - community_del_val (com, com_nthval (com, i)); - else - i++; - } - return com; + int i; + uint32_t comval; + /* Maximum is "65535:65535" + '\0'. */ + char c[12]; + const char *str; + + if (!com) + return NULL; + + i = 0; + while (i < com->size) + { + memcpy (&comval, com_nthval (com, i), sizeof (uint32_t)); + comval = ntohl (comval); + + switch (comval) { + case COMMUNITY_INTERNET: + str = "internet"; + break; + case COMMUNITY_ACCEPT_OWN: + str = "accept-own"; + break; + case COMMUNITY_ROUTE_FILTER_TRANSLATED_v4: + str = "route-filter-translated-v4"; + break; + case COMMUNITY_ROUTE_FILTER_v4: + str = "route-filter-v4"; + break; + case COMMUNITY_ROUTE_FILTER_TRANSLATED_v6: + str = "route-filter-translated-v6"; + break; + case COMMUNITY_ROUTE_FILTER_v6: + str = "route-filter-v6"; + break; + case COMMUNITY_LLGR_STALE: + str = "llgr-stale"; + break; + case COMMUNITY_NO_LLGR: + str = "no-llgr"; + break; + case COMMUNITY_ACCEPT_OWN_NEXTHOP: + str = "accept-own-nexthop"; + break; + case COMMUNITY_BLACKHOLE: + str = "blackhole"; + break; + case COMMUNITY_NO_EXPORT: + str = "no-export"; + break; + case COMMUNITY_NO_ADVERTISE: + str = "no-advertise"; + break; + case COMMUNITY_LOCAL_AS: + str = "local-AS"; + break; + case COMMUNITY_NO_PEER: + str = "no-peer"; + break; + default: + sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF, + comval & 0xFFFF); + str = c; + break; + } + + if (regexec (reg, str, 0, NULL, 0) == 0) + community_del_val (com, com_nthval (com, i)); + else + i++; + } + return com; } #endif diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index 9170481769..e40674d635 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -188,10 +188,20 @@ struct community *community_uniq_sort(struct community *com) For Well-known communities value, below keyword is used. 0x0 "internet" + 0xFFFF0000 "graceful-shutdown" + 0xFFFF0001 "accept-own" + 0xFFFF0002 "route-filter-translated-v4" + 0xFFFF0003 "route-filter-v4" + 0xFFFF0004 "route-filter-translated-v6" + 0xFFFF0005 "route-filter-v6" + 0xFFFF0006 "llgr-stale" + 0xFFFF0007 "no-llgr" + 0xFFFF0008 "accept-own-nexthop" + 0xFFFF029A "blackhole" 0xFFFFFF01 "no-export" 0xFFFFFF02 "no-advertise" 0xFFFFFF03 "local-AS" - 0xFFFF0000 "graceful-shutdown" + 0xFFFFFF04 "no-peer" For other values, "AS:VAL" format is used. */ static void set_community_string(struct community *com, bool make_json) @@ -241,6 +251,36 @@ static void set_community_string(struct community *com, bool make_json) case COMMUNITY_INTERNET: len += strlen(" internet"); break; + case COMMUNITY_GSHUT: + len += strlen(" graceful-shutdown"); + break; + case COMMUNITY_ACCEPT_OWN: + len += strlen(" accept-own"); + break; + case COMMUNITY_ROUTE_FILTER_TRANSLATED_v4: + len += strlen(" route-filter-translated-v4"); + break; + case COMMUNITY_ROUTE_FILTER_v4: + len += strlen(" route-filter-v4"); + break; + case COMMUNITY_ROUTE_FILTER_TRANSLATED_v6: + len += strlen(" route-filter-translated-v6"); + break; + case COMMUNITY_ROUTE_FILTER_v6: + len += strlen(" route-filter-v6"); + break; + case COMMUNITY_LLGR_STALE: + len += strlen(" llgr-stale"); + break; + case COMMUNITY_NO_LLGR: + len += strlen(" no-llgr"); + break; + case COMMUNITY_ACCEPT_OWN_NEXTHOP: + len += strlen(" accept-own-nexthop"); + break; + case COMMUNITY_BLACKHOLE: + len += strlen(" blackhole"); + break; case COMMUNITY_NO_EXPORT: len += strlen(" no-export"); break; @@ -250,8 +290,8 @@ static void set_community_string(struct community *com, bool make_json) case COMMUNITY_LOCAL_AS: len += strlen(" local-AS"); break; - case COMMUNITY_GSHUT: - len += strlen(" graceful-shutdown"); + case COMMUNITY_NO_PEER: + len += strlen(" no-peer"); break; default: len += strlen(" 65536:65535"); @@ -284,6 +324,106 @@ static void set_community_string(struct community *com, bool make_json) json_string); } break; + case COMMUNITY_GSHUT: + strcpy(pnt, "graceful-shutdown"); + pnt += strlen("graceful-shutdown"); + if (make_json) { + json_string = json_object_new_string( + "gracefulShutdown"); + json_object_array_add(json_community_list, + json_string); + } + break; + case COMMUNITY_ACCEPT_OWN: + strcpy(pnt, "accept-own"); + pnt += strlen("accept-own"); + if (make_json) { + json_string = json_object_new_string( + "acceptown"); + json_object_array_add(json_community_list, + json_string); + } + break; + case COMMUNITY_ROUTE_FILTER_TRANSLATED_v4: + strcpy(pnt, "route-filter-translated-v4"); + pnt += strlen("route-filter-translated-v4"); + if (make_json) { + json_string = json_object_new_string( + "routeFilterTranslatedV4"); + json_object_array_add(json_community_list, + json_string); + } + break; + case COMMUNITY_ROUTE_FILTER_v4: + strcpy(pnt, "route-filter-v4"); + pnt += strlen("route-filter-v4"); + if (make_json) { + json_string = json_object_new_string( + "routeFilterV4"); + json_object_array_add(json_community_list, + json_string); + } + break; + case COMMUNITY_ROUTE_FILTER_TRANSLATED_v6: + strcpy(pnt, "route-filter-translated-v6"); + pnt += strlen("route-filter-translated-v6"); + if (make_json) { + json_string = json_object_new_string( + "routeFilterTranslatedV6"); + json_object_array_add(json_community_list, + json_string); + } + break; + case COMMUNITY_ROUTE_FILTER_v6: + strcpy(pnt, "route-filter-v6"); + pnt += strlen("route-filter-v6"); + if (make_json) { + json_string = json_object_new_string( + "routeFilterV6"); + json_object_array_add(json_community_list, + json_string); + } + break; + case COMMUNITY_LLGR_STALE: + strcpy(pnt, "llgr-stale"); + pnt += strlen("llgr-stale"); + if (make_json) { + json_string = json_object_new_string( + "llgrStale"); + json_object_array_add(json_community_list, + json_string); + } + break; + case COMMUNITY_NO_LLGR: + strcpy(pnt, "no-llgr"); + pnt += strlen("no-llgr"); + if (make_json) { + json_string = json_object_new_string( + "noLlgr"); + json_object_array_add(json_community_list, + json_string); + } + break; + case COMMUNITY_ACCEPT_OWN_NEXTHOP: + strcpy(pnt, "accept-own-nexthop"); + pnt += strlen("accept-own-nexthop"); + if (make_json) { + json_string = json_object_new_string( + "acceptownnexthop"); + json_object_array_add(json_community_list, + json_string); + } + break; + case COMMUNITY_BLACKHOLE: + strcpy(pnt, "blackhole"); + pnt += strlen("blackhole"); + if (make_json) { + json_string = json_object_new_string( + "blackhole"); + json_object_array_add(json_community_list, + json_string); + } + break; case COMMUNITY_NO_EXPORT: strcpy(pnt, "no-export"); pnt += strlen("no-export"); @@ -313,12 +453,11 @@ static void set_community_string(struct community *com, bool make_json) json_string); } break; - case COMMUNITY_GSHUT: - strcpy(pnt, "graceful-shutdown"); - pnt += strlen("graceful-shutdown"); + case COMMUNITY_NO_PEER: + strcpy(pnt, "no-peer"); + pnt += strlen("no-peer"); if (make_json) { - json_string = json_object_new_string( - "gracefulShutdown"); + json_string = json_object_new_string("noPeer"); json_object_array_add(json_community_list, json_string); } @@ -508,10 +647,20 @@ struct community *community_merge(struct community *com1, /* Community token enum. */ enum community_token { community_token_val, + community_token_gshut, + community_token_accept_own, + community_token_route_filter_translated_v4, + community_token_route_filter_v4, + community_token_route_filter_translated_v6, + community_token_route_filter_v6, + community_token_llgr_stale, + community_token_no_llgr, + community_token_accept_own_nexthop, + community_token_blackhole, community_token_no_export, community_token_no_advertise, community_token_local_as, - community_token_gshut, + community_token_no_peer, community_token_unknown }; @@ -537,6 +686,79 @@ community_gettoken(const char *buf, enum community_token *token, uint32_t *val) p += strlen("internet"); return p; } + if (strncmp(p, "graceful-shutdown", strlen("graceful-shutdown")) + == 0) { + *val = COMMUNITY_GSHUT; + *token = community_token_gshut; + p += strlen("graceful-shutdown"); + return p; + } + if (strncmp(p, "accept-own", strlen("accept-own")) + == 0) { + *val = COMMUNITY_ACCEPT_OWN; + *token = community_token_accept_own; + p += strlen("accept-own"); + return p; + } + if (strncmp(p, "route-filter-translated-v4", + strlen("route-filter-translated-v4")) + == 0) { + *val = COMMUNITY_ROUTE_FILTER_TRANSLATED_v4; + *token = community_token_route_filter_translated_v4; + p += strlen("route-filter-translated-v4"); + return p; + } + if (strncmp(p, "route-filter-v4", strlen("route-filter-v4")) + == 0) { + *val = COMMUNITY_ROUTE_FILTER_v4; + *token = community_token_route_filter_v4; + p += strlen("route-filter-v4"); + return p; + } + if (strncmp(p, "route-filter-translated-v6", + strlen("route-filter-translated-v6")) + == 0) { + *val = COMMUNITY_ROUTE_FILTER_TRANSLATED_v6; + *token = community_token_route_filter_translated_v6; + p += strlen("route-filter-translated-v6"); + return p; + } + if (strncmp(p, "route-filter-v6", strlen("route-filter-v6")) + == 0) { + *val = COMMUNITY_ROUTE_FILTER_v6; + *token = community_token_route_filter_v6; + p += strlen("route-filter-v6"); + return p; + } + if (strncmp(p, "llgr-stale", strlen("llgr-stale")) + == 0) { + *val = COMMUNITY_LLGR_STALE; + *token = community_token_llgr_stale; + p += strlen("llgr-stale"); + return p; + } + if (strncmp(p, "no-llgr", strlen("no-llgr")) + == 0) { + *val = COMMUNITY_NO_LLGR; + *token = community_token_no_llgr; + p += strlen("no-llgr"); + return p; + } + if (strncmp(p, "accept-own-nexthop", + strlen("accept-own-nexthop")) + == 0) { + *val = COMMUNITY_ACCEPT_OWN_NEXTHOP; + *token = community_token_accept_own_nexthop; + p += strlen("accept-own-nexthop"); + return p; + } + if (strncmp(p, "blackhole", strlen("blackhole")) + == 0) { + *val = COMMUNITY_BLACKHOLE; + *token = community_token_blackhole; + p += strlen("blackhole"); + return p; + } if (strncmp(p, "no-export", strlen("no-export")) == 0) { *val = COMMUNITY_NO_EXPORT; *token = community_token_no_export; @@ -555,11 +777,10 @@ community_gettoken(const char *buf, enum community_token *token, uint32_t *val) p += strlen("local-AS"); return p; } - if (strncmp(p, "graceful-shutdown", strlen("graceful-shutdown")) - == 0) { - *val = COMMUNITY_GSHUT; - *token = community_token_gshut; - p += strlen("graceful-shutdown"); + if (strncmp(p, "no-peer", strlen("no-peer")) == 0) { + *val = COMMUNITY_NO_PEER; + *token = community_token_no_peer; + p += strlen("no-peer"); return p; } @@ -631,10 +852,20 @@ struct community *community_str2com(const char *str) switch (token) { case community_token_val: + case community_token_gshut: + case community_token_accept_own: + case community_token_route_filter_translated_v4: + case community_token_route_filter_v4: + case community_token_route_filter_translated_v6: + case community_token_route_filter_v6: + case community_token_llgr_stale: + case community_token_no_llgr: + case community_token_accept_own_nexthop: + case community_token_blackhole: case community_token_no_export: case community_token_no_advertise: case community_token_local_as: - case community_token_gshut: + case community_token_no_peer: if (com == NULL) { com = community_new(); com->json = NULL; diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h index c180bea465..61af9f038c 100644 --- a/bgpd/bgp_community.h +++ b/bgpd/bgp_community.h @@ -43,12 +43,22 @@ struct community { }; /* Well-known communities value. */ -#define COMMUNITY_INTERNET 0x0 -#define COMMUNITY_NO_EXPORT 0xFFFFFF01 -#define COMMUNITY_NO_ADVERTISE 0xFFFFFF02 -#define COMMUNITY_NO_EXPORT_SUBCONFED 0xFFFFFF03 -#define COMMUNITY_LOCAL_AS 0xFFFFFF03 -#define COMMUNITY_GSHUT 0xFFFF0000 +#define COMMUNITY_INTERNET 0x0 +#define COMMUNITY_GSHUT 0xFFFF0000 +#define COMMUNITY_ACCEPT_OWN 0xFFFF0001 +#define COMMUNITY_ROUTE_FILTER_TRANSLATED_v4 0xFFFF0002 +#define COMMUNITY_ROUTE_FILTER_v4 0xFFFF0003 +#define COMMUNITY_ROUTE_FILTER_TRANSLATED_v6 0xFFFF0004 +#define COMMUNITY_ROUTE_FILTER_v6 0xFFFF0005 +#define COMMUNITY_LLGR_STALE 0xFFFF0006 +#define COMMUNITY_NO_LLGR 0xFFFF0007 +#define COMMUNITY_ACCEPT_OWN_NEXTHOP 0xFFFF0008 +#define COMMUNITY_BLACKHOLE 0xFFFF029A +#define COMMUNITY_NO_EXPORT 0xFFFFFF01 +#define COMMUNITY_NO_ADVERTISE 0xFFFFFF02 +#define COMMUNITY_NO_EXPORT_SUBCONFED 0xFFFFFF03 +#define COMMUNITY_LOCAL_AS 0xFFFFFF03 +#define COMMUNITY_NO_PEER 0xFFFFFF04 /* Macros of community attribute. */ #define com_length(X) ((X)->size * 4) diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index a4ded57c25..c7c36882af 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -42,6 +42,9 @@ #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_label.h" #include "bgpd/bgp_evpn.h" +#include "bgpd/bgp_evpn_private.h" +#include "bgpd/bgp_evpn_vty.h" +#include "bgpd/bgp_vty.h" #include "bgpd/bgp_flowspec.h" unsigned long conf_bgp_debug_as4; @@ -169,6 +172,8 @@ static const struct message bgp_notify_capability_msg[] = { const char *bgp_origin_str[] = {"i", "e", "?"}; const char *bgp_origin_long_str[] = {"IGP", "EGP", "incomplete"}; +static int bgp_debug_print_evpn_prefix(struct vty *vty, const char *desc, + struct prefix *p); /* Given a string return a pointer the corresponding peer structure */ static struct peer *bgp_find_peer(struct vty *vty, const char *peer_str) { @@ -213,14 +218,16 @@ static void bgp_debug_list_free(struct list *list) } } -/* Print the desc along with a list of peers/prefixes this debug is - * enabled for */ +/* + * Print the desc along with a list of peers/prefixes this debug is + * enabled for + */ static void bgp_debug_list_print(struct vty *vty, const char *desc, struct list *list) { struct bgp_debug_filter *filter; struct listnode *node, *nnode; - char buf[INET6_ADDRSTRLEN]; + char buf[PREFIX2STR_BUFFER]; vty_out(vty, "%s", desc); @@ -230,19 +237,20 @@ static void bgp_debug_list_print(struct vty *vty, const char *desc, if (filter->host) vty_out(vty, " %s", filter->host); - if (filter->p) - vty_out(vty, " %s/%d", - inet_ntop(filter->p->family, - &filter->p->u.prefix, buf, - INET6_ADDRSTRLEN), - filter->p->prefixlen); + if (filter->p && filter->p->family == AF_EVPN) + bgp_debug_print_evpn_prefix(vty, "", filter->p); + else if (filter->p) { + prefix2str(filter->p, buf, sizeof(buf)); + vty_out(vty, " %s", buf); + } } } vty_out(vty, "\n"); } -/* Print the command to enable the debug for each peer/prefix this debug is +/* + * Print the command to enable the debug for each peer/prefix this debug is * enabled for */ static int bgp_debug_list_conf_print(struct vty *vty, const char *desc, @@ -250,7 +258,7 @@ static int bgp_debug_list_conf_print(struct vty *vty, const char *desc, { struct bgp_debug_filter *filter; struct listnode *node, *nnode; - char buf[INET6_ADDRSTRLEN]; + char buf[PREFIX2STR_BUFFER]; int write = 0; if (list && !list_isempty(list)) { @@ -260,13 +268,13 @@ static int bgp_debug_list_conf_print(struct vty *vty, const char *desc, write++; } - - if (filter->p) { - vty_out(vty, "%s %s/%d\n", desc, - inet_ntop(filter->p->family, - &filter->p->u.prefix, buf, - INET6_ADDRSTRLEN), - filter->p->prefixlen); + if (filter->p && filter->p->family == AF_EVPN) { + bgp_debug_print_evpn_prefix(vty, desc, + filter->p); + write++; + } else if (filter->p) { + prefix2str(filter->p, buf, sizeof(buf)); + vty_out(vty, "%s %s\n", desc, buf); write++; } } @@ -543,6 +551,106 @@ static void bgp_debug_clear_updgrp_update_dbg(struct bgp *bgp) update_group_walk(bgp, update_group_clear_update_dbg, NULL); } +static int bgp_debug_print_evpn_prefix(struct vty *vty, const char *desc, + struct prefix *p) +{ + char evpn_desc[PREFIX2STR_BUFFER + INET_ADDRSTRLEN]; + char buf[PREFIX2STR_BUFFER]; + char buf2[ETHER_ADDR_STRLEN]; + + if (p->u.prefix_evpn.route_type == BGP_EVPN_MAC_IP_ROUTE) { + if (is_evpn_prefix_ipaddr_none((struct prefix_evpn *)p)) { + sprintf(evpn_desc, "l2vpn evpn type macip mac %s", + prefix_mac2str( + &p->u.prefix_evpn.macip_addr.mac, + buf2, sizeof(buf2))); + } else { + uint8_t family = is_evpn_prefix_ipaddr_v4( + (struct prefix_evpn *)p) ? + AF_INET : AF_INET6; + sprintf(evpn_desc, "l2vpn evpn type macip mac %s ip %s", + prefix_mac2str( + &p->u.prefix_evpn.macip_addr.mac, + buf2, sizeof(buf2)), + inet_ntop(family, + &p->u.prefix_evpn.macip_addr.ip.ip.addr, + buf, PREFIX2STR_BUFFER)); + } + } else if (p->u.prefix_evpn.route_type == BGP_EVPN_IMET_ROUTE) { + sprintf(evpn_desc, "l2vpn evpn type multicast ip %s", + inet_ntoa(p->u.prefix_evpn.imet_addr.ip.ipaddr_v4)); + } else if (p->u.prefix_evpn.route_type == BGP_EVPN_IP_PREFIX_ROUTE) { + uint8_t family = is_evpn_prefix_ipaddr_v4( + (struct prefix_evpn *)p) ? AF_INET + : AF_INET6; + sprintf(evpn_desc, "l2vpn evpn type prefix ip %s/%d", + inet_ntop(family, + &p->u.prefix_evpn.prefix_addr.ip.ip.addr, buf, + PREFIX2STR_BUFFER), + p->u.prefix_evpn.prefix_addr.ip_prefix_length); + } + + vty_out(vty, "%s %s\n", desc, evpn_desc); + + return 0; +} + +static int bgp_debug_parse_evpn_prefix(struct vty *vty, struct cmd_token **argv, + int argc, struct prefix **argv_pp) +{ + struct prefix *argv_p; + struct ethaddr mac; + struct ipaddr ip; + int evpn_type; + int type_idx = 0; + int mac_idx = 0; + int ip_idx = 0; + + argv_p = *argv_pp; + + if (argv_find(argv, argc, "macip", &type_idx)) + evpn_type = BGP_EVPN_MAC_IP_ROUTE; + else if (argv_find(argv, argc, "multicast", &type_idx)) + evpn_type = BGP_EVPN_IMET_ROUTE; + else if (argv_find(argv, argc, "prefix", &type_idx)) + evpn_type = BGP_EVPN_IP_PREFIX_ROUTE; + else + evpn_type = 0; + + if (evpn_type == BGP_EVPN_MAC_IP_ROUTE) { + memset(&ip, 0, sizeof(struct ipaddr)); + + argv_find(argv, argc, "mac", &mac_idx); + prefix_str2mac(argv[mac_idx + 1]->arg, &mac); + + argv_find(argv, argc, "ip", &ip_idx); + str2ipaddr(argv[ip_idx + 1]->arg, &ip); + + build_evpn_type2_prefix((struct prefix_evpn *)argv_p, + &mac, &ip); + } else if (evpn_type == BGP_EVPN_IMET_ROUTE) { + memset(&ip, 0, sizeof(struct ipaddr)); + + argv_find(argv, argc, "ip", &ip_idx); + str2ipaddr(argv[ip_idx + 1]->arg, &ip); + + build_evpn_type3_prefix((struct prefix_evpn *)argv_p, + ip.ipaddr_v4); + } else if (evpn_type == BGP_EVPN_IP_PREFIX_ROUTE) { + struct prefix ip_prefix; + + memset(&ip_prefix, 0, sizeof(struct prefix)); + if (argv_find(argv, argc, "ip", &ip_idx)) { + (void)str2prefix(argv[ip_idx + 1]->arg, &ip_prefix); + apply_mask(&ip_prefix); + } + build_type5_prefix_from_ip_prefix( + (struct prefix_evpn *)argv_p, + &ip_prefix); + } + + return CMD_SUCCESS; +} /* Debug option setting interface. */ unsigned long bgp_debug_option = 0; @@ -1266,6 +1374,141 @@ DEFUN (no_debug_bgp_update_direct_peer, return CMD_SUCCESS; } +#ifndef VTYSH_EXTRACT_PL +#include "bgpd/bgp_debug_clippy.c" +#endif + +DEFPY (debug_bgp_update_prefix_afi_safi, + debug_bgp_update_prefix_afi_safi_cmd, + "debug bgp updates prefix l2vpn$afi evpn$safi type <macip mac <M:A:C|M:A:C/M> [ip <A.B.C.D|X:X::X:X>]|multicast ip <A.B.C.D|X:X::X:X>|prefix ip <A.B.C.D/M|X:X::X:X/M>>", + DEBUG_STR + BGP_STR + "BGP updates\n" + "Specify a prefix to debug\n" + L2VPN_HELP_STR + EVPN_HELP_STR + "Specify EVPN Route type\n" + "MAC-IP (Type-2) route\n" + MAC_STR MAC_STR MAC_STR + IP_STR + "IPv4 address\n" + "IPv6 address\n" + "Multicast (Type-3) route\n" + IP_STR + "IPv4 address\n" + "IPv6 address\n" + "Prefix (Type-5) route\n" + IP_STR + "IPv4 prefix\n" + "IPv6 prefix\n") +{ + struct prefix *argv_p; + int ret = CMD_SUCCESS; + char buf[PREFIX2STR_BUFFER]; + + argv_p = prefix_new(); + + ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p); + if (ret != CMD_SUCCESS) { + prefix_free(argv_p); + return ret; + } + + if (!bgp_debug_update_prefixes) + bgp_debug_update_prefixes = list_new(); + + prefix2str(argv_p, buf, sizeof(buf)); + + if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, argv_p)) { + vty_out(vty, + "BGP updates debugging is already enabled for %s\n", + buf); + prefix_free(argv_p); + return CMD_SUCCESS; + } + + bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, argv_p); + + if (vty->node == CONFIG_NODE) { + DEBUG_ON(update, UPDATE_PREFIX); + } else { + TERM_DEBUG_ON(update, UPDATE_PREFIX); + vty_out(vty, "BGP updates debugging is on for %s\n", buf); + } + + prefix_free(argv_p); + + return CMD_SUCCESS; +} + +DEFPY (no_debug_bgp_update_prefix_afi_safi, + no_debug_bgp_update_prefix_afi_safi_cmd, + "no debug bgp updates prefix l2vpn$afi evpn$safi type <macip mac <M:A:C|M:A:C/M> [ip <A.B.C.D|X:X::X:X>]|multicast ip <A.B.C.D|X:X::X:X>|prefix ip <A.B.C.D/M|X:X::X:X/M>>", + NO_STR + DEBUG_STR + BGP_STR + "BGP updates\n" + "Specify a prefix to debug\n" + L2VPN_HELP_STR + EVPN_HELP_STR + "Specify EVPN Route type\n" + "MAC-IP (Type-2) route\n" + MAC_STR MAC_STR MAC_STR + IP_STR + "IPv4 address\n" + "IPv6 address\n" + "Multicast (Type-3) route\n" + IP_STR + "IPv4 address\n" + "IPv6 address\n" + "Prefix (Type-5) route\n" + IP_STR + "IPv4 prefix\n" + "IPv6 prefix\n") +{ + struct prefix *argv_p; + bool found_prefix = false; + int ret = CMD_SUCCESS; + char buf[PREFIX2STR_BUFFER]; + + argv_p = prefix_new(); + + ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p); + if (ret != CMD_SUCCESS) { + prefix_free(argv_p); + return ret; + } + + if (bgp_debug_update_prefixes + && !list_isempty(bgp_debug_update_prefixes)) { + found_prefix = bgp_debug_list_remove_entry( + bgp_debug_update_prefixes, NULL, argv_p); + + if (list_isempty(bgp_debug_update_prefixes)) { + if (vty->node == CONFIG_NODE) { + DEBUG_OFF(update, UPDATE_PREFIX); + } else { + TERM_DEBUG_OFF(update, UPDATE_PREFIX); + vty_out(vty, + "BGP updates debugging (per prefix) is off\n"); + } + } + } + + prefix2str(argv_p, buf, sizeof(buf)); + + if (found_prefix) + vty_out(vty, "BGP updates debugging is off for %s\n", buf); + else + vty_out(vty, "BGP updates debugging was not enabled for %s\n", + buf); + + prefix_free(argv_p); + + return ret; +} + + DEFUN (debug_bgp_update_prefix, debug_bgp_update_prefix_cmd, "debug bgp updates prefix <A.B.C.D/M|X:X::X:X/M>", @@ -2095,6 +2338,10 @@ void bgp_debug_init(void) install_element(CONFIG_NODE, &debug_bgp_update_prefix_cmd); install_element(ENABLE_NODE, &no_debug_bgp_update_prefix_cmd); install_element(CONFIG_NODE, &no_debug_bgp_update_prefix_cmd); + install_element(ENABLE_NODE, &debug_bgp_update_prefix_afi_safi_cmd); + install_element(CONFIG_NODE, &debug_bgp_update_prefix_afi_safi_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_update_prefix_afi_safi_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_update_prefix_afi_safi_cmd); /* debug bgp zebra prefix A.B.C.D/M */ install_element(ENABLE_NODE, &debug_bgp_zebra_prefix_cmd); diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 2f59308d65..c71f371a97 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -48,8 +48,11 @@ #define ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT 0x02 #define ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC 0x03 #define ECOMMUNITY_EVPN_SUBTYPE_DEF_GW 0x0d +#define ECOMMUNITY_EVPN_SUBTYPE_ND 0x08 #define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY 0x01 +#define ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG 0x01 +#define ECOMMUNITY_EVPN_SUBTYPE_ND_OVERRIDE_FLAG 0x02 /* Low-order octet of the Extended Communities type field for OPAQUE types */ #define ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP 0x0c diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index a026df59a0..73f225784c 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -730,10 +730,13 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, struct ecommunity ecom_sticky; struct ecommunity ecom_default_gw; struct ecommunity ecom_rmac; + struct ecommunity ecom_na; struct ecommunity_val eval; struct ecommunity_val eval_sticky; struct ecommunity_val eval_default_gw; struct ecommunity_val eval_rmac; + struct ecommunity_val eval_na; + bgp_encap_types tnl_type; struct listnode *node, *nnode; struct ecommunity *ecom; @@ -798,6 +801,15 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, ecommunity_merge(attr->ecommunity, &ecom_default_gw); } + if (attr->router_flag) { + memset(&ecom_na, 0, sizeof(ecom_na)); + encode_na_flag_extcomm(&eval_na, attr->router_flag); + ecom_na.size = 1; + ecom_na.val = (uint8_t *)eval_na.val; + attr->ecommunity = ecommunity_merge(attr->ecommunity, + &ecom_na); + } + attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); } @@ -1089,6 +1101,7 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, { struct bgp_info *old_select, *new_select; struct bgp_info_pair old_and_new; + struct prefix_evpn *evp; afi_t afi = AFI_L2VPN; safi_t safi = SAFI_EVPN; int ret = 0; @@ -1100,6 +1113,7 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, old_select = old_and_new.old; new_select = old_and_new.new; + evp = (struct prefix_evpn *)&rn->p; /* If the best path hasn't changed - see if there is still something to * update * to zebra RIB. @@ -1115,6 +1129,10 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); if (old_select->attr->default_gw) SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); + if (is_evpn_prefix_ipaddr_v6(evp) && + old_select->attr->router_flag) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); + ret = evpn_zebra_install( bgp, vpn, (struct prefix_evpn *)&rn->p, old_select->attr->nexthop, flags); @@ -1148,6 +1166,10 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); if (new_select->attr->default_gw) SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); + if (is_evpn_prefix_ipaddr_v6(evp) && + new_select->attr->router_flag) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); + ret = evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p, new_select->attr->nexthop, flags); /* If an old best existed and it was a "local" route, the only @@ -1695,6 +1717,8 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; attr.sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? 1 : 0; attr.default_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? 1 : 0; + attr.router_flag = CHECK_FLAG(flags, + ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? 1 : 0; /* PMSI is only needed for type-3 routes */ if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) @@ -1993,11 +2017,13 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr_sticky, 0, 1, &ri, 0); - else if (evpn_route_is_def_gw(bgp, rn)) + else if (evpn_route_is_def_gw(bgp, rn)) { + if (is_evpn_prefix_ipaddr_v6(evp)) + attr_def_gw.router_flag = 1; update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr_def_gw, 0, 1, &ri, 0); - else + } else update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr, 0, 1, &ri, 0); } diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index bf6a24dea6..8d71c3123e 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -311,6 +311,16 @@ static inline void encode_mac_mobility_extcomm(int static_mac, uint32_t seq, eval->val[7] = seq & 0xff; } +static inline void encode_na_flag_extcomm(struct ecommunity_val *eval, + uint8_t na_flag) +{ + memset(eval, 0, sizeof(*eval)); + eval->val[0] = ECOMMUNITY_ENCODE_EVPN; + eval->val[1] = ECOMMUNITY_EVPN_SUBTYPE_ND; + if (na_flag) + eval->val[2] |= ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG; +} + static inline void ip_prefix_from_type5_prefix(struct prefix_evpn *evp, struct prefix *ip) { @@ -328,7 +338,7 @@ static inline void ip_prefix_from_type5_prefix(struct prefix_evpn *evp, } } -static inline int is_evpn_prefix_default(struct prefix *evp) +static inline int is_evpn_prefix_default(const struct prefix *evp) { if (evp->family != AF_EVPN) return 0; diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 5a4ebc9b17..b45c1a99db 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -2807,9 +2807,6 @@ DEFUN (bgp_evpn_advertise_default_gw_vni, if (!bgp) return CMD_WARNING; - if (!vpn) - return CMD_WARNING; - evpn_set_advertise_default_gw(bgp, vpn); return CMD_SUCCESS; @@ -2827,9 +2824,6 @@ DEFUN (no_bgp_evpn_advertise_default_vni_gw, if (!bgp) return CMD_WARNING; - if (!vpn) - return CMD_WARNING; - evpn_unset_advertise_default_gw(bgp, vpn); return CMD_SUCCESS; @@ -2972,9 +2966,6 @@ DEFUN_HIDDEN (bgp_evpn_advertise_vni_subnet, if (!bgp) return CMD_WARNING; - if (!vpn) - return CMD_WARNING; - bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id); if (!bgp_vrf) return CMD_WARNING; @@ -2995,9 +2986,6 @@ DEFUN_HIDDEN (no_bgp_evpn_advertise_vni_subnet, if (!bgp) return CMD_WARNING; - if (!vpn) - return CMD_WARNING; - evpn_unset_advertise_subnet(bgp, vpn); return CMD_SUCCESS; } @@ -4225,7 +4213,7 @@ DEFUN (bgp_evpn_vni_rd, VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); int ret; - if (!bgp || !vpn) + if (!bgp) return CMD_WARNING; if (bgp->vrf_id != VRF_DEFAULT) { @@ -4261,7 +4249,7 @@ DEFUN (no_bgp_evpn_vni_rd, VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); int ret; - if (!bgp || !vpn) + if (!bgp) return CMD_WARNING; if (bgp->vrf_id != VRF_DEFAULT) { @@ -4301,7 +4289,7 @@ DEFUN (no_bgp_evpn_vni_rd_without_val, struct bgp *bgp = VTY_GET_CONTEXT(bgp); VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); - if (!bgp || !vpn) + if (!bgp) return CMD_WARNING; if (bgp->vrf_id != VRF_DEFAULT) { @@ -4630,7 +4618,7 @@ DEFUN (bgp_evpn_vni_rt, int rt_type; struct ecommunity *ecomadd = NULL; - if (!bgp || !vpn) + if (!bgp) return CMD_WARNING; if (bgp->vrf_id != VRF_DEFAULT) { @@ -4698,7 +4686,7 @@ DEFUN (no_bgp_evpn_vni_rt, int rt_type, found_ecomdel; struct ecommunity *ecomdel = NULL; - if (!bgp || !vpn) + if (!bgp) return CMD_WARNING; if (bgp->vrf_id != VRF_DEFAULT) { @@ -4797,7 +4785,7 @@ DEFUN (no_bgp_evpn_vni_rt_without_val, VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); int rt_type; - if (!bgp || !vpn) + if (!bgp) return CMD_WARNING; if (bgp->vrf_id != VRF_DEFAULT) { diff --git a/bgpd/bgp_flowspec.h b/bgpd/bgp_flowspec.h index 5dd2c3931a..9f69dbedda 100644 --- a/bgpd/bgp_flowspec.h +++ b/bgpd/bgp_flowspec.h @@ -50,4 +50,12 @@ extern void route_vty_out_flowspec(struct vty *vty, struct prefix *p, extern int bgp_fs_config_write_pbr(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi); +extern int bgp_flowspec_display_match_per_ip(afi_t afi, + struct bgp_table *rib, + struct prefix *match, + int prefix_check, + struct vty *vty, + uint8_t use_json, + json_object *json_paths); + #endif /* _FRR_BGP_FLOWSPEC_H */ diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c index 1b87427661..6408337a5f 100644 --- a/bgpd/bgp_flowspec_util.c +++ b/bgpd/bgp_flowspec_util.c @@ -73,9 +73,9 @@ static int bgp_flowspec_call_non_opaque_decode(uint8_t *nlri_content, int len, return ret; } -static bool bgp_flowspec_contains_prefix(struct prefix *pfs, - struct prefix *input, - int prefix_check) +bool bgp_flowspec_contains_prefix(struct prefix *pfs, + struct prefix *input, + int prefix_check) { uint32_t offset = 0; int type; @@ -564,24 +564,3 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len, } return error; } - - -struct bgp_node *bgp_flowspec_get_match_per_ip(afi_t afi, - struct bgp_table *rib, - struct prefix *match, - int prefix_check) -{ - struct bgp_node *rn; - struct prefix *prefix; - - for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) { - prefix = &rn->p; - - if (prefix->family != AF_FLOWSPEC) - continue; - - if (bgp_flowspec_contains_prefix(prefix, match, prefix_check)) - return rn; - } - return NULL; -} diff --git a/bgpd/bgp_flowspec_util.h b/bgpd/bgp_flowspec_util.h index 2d16e57a36..9bf05847d3 100644 --- a/bgpd/bgp_flowspec_util.h +++ b/bgpd/bgp_flowspec_util.h @@ -50,8 +50,8 @@ struct bgp_pbr_entry_main; extern int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len, struct bgp_pbr_entry_main *bpem); -extern struct bgp_node *bgp_flowspec_get_match_per_ip(afi_t afi, - struct bgp_table *rib, - struct prefix *match, - int prefix_check); +extern bool bgp_flowspec_contains_prefix(struct prefix *pfs, + struct prefix *input, + int prefix_check); + #endif /* _FRR_BGP_FLOWSPEC_UTIL_H */ diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index c695e7f125..f8c0613208 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -332,16 +332,32 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p, struct bgp_info_extra *extra = bgp_info_extra_get(binfo); if (extra->bgp_fs_pbr) { + struct listnode *node; struct bgp_pbr_match_entry *bpme; struct bgp_pbr_match *bpm; + int unit = 0; + struct list *list_bpm; - bpme = (struct bgp_pbr_match_entry *)extra->bgp_fs_pbr; - bpm = bpme->backpointer; - vty_out(vty, "\tinstalled in PBR"); - if (bpm) - vty_out(vty, " (%s)\n", bpm->ipset_name); - else - vty_out(vty, "\n"); + list_bpm = list_new(); + if (listcount(extra->bgp_fs_pbr)) + vty_out(vty, "\tinstalled in PBR"); + for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_pbr, + node, bpme)) { + bpm = bpme->backpointer; + if (listnode_lookup(list_bpm, bpm)) + continue; + listnode_add(list_bpm, bpm); + if (unit == 0) + vty_out(vty, " ("); + else + vty_out(vty, ", "); + vty_out(vty, "%s", bpm->ipset_name); + unit++; + } + if (unit) + vty_out(vty, ")"); + vty_out(vty, "\n"); + list_delete_and_null(&list_bpm); } else vty_out(vty, "\tnot installed in PBR\n"); } @@ -444,8 +460,6 @@ int bgp_fs_config_write_pbr(struct vty *vty, struct bgp *bgp, RB_FOREACH (pbr_if, bgp_pbr_interface_head, head) { vty_out(vty, " local-install %s\n", pbr_if->name); } - if (!bgp_pbr_interface_any) - vty_out(vty, " no local-install any\n"); return declare_node ? 1 : 0; } @@ -513,17 +527,34 @@ DEFUN (bgp_fs_local_install_ifname, return bgp_fs_local_install_interface(bgp, no, ifname); } -DEFUN (bgp_fs_local_install_any, - bgp_fs_local_install_any_cmd, - "[no] local-install any", - NO_STR - "Apply local policy routing\n" - "Any Interface\n") +extern int bgp_flowspec_display_match_per_ip(afi_t afi, + struct bgp_table *rib, + struct prefix *match, + int prefix_check, + struct vty *vty, + uint8_t use_json, + json_object *json_paths) { - struct bgp *bgp = VTY_GET_CONTEXT(bgp); - const char *no = strmatch(argv[0]->text, (char *)"no") ? "no" : NULL; + struct bgp_node *rn; + struct prefix *prefix; + int display = 0; - return bgp_fs_local_install_interface(bgp, no, NULL); + for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) { + prefix = &rn->p; + + if (prefix->family != AF_FLOWSPEC) + continue; + + if (bgp_flowspec_contains_prefix(prefix, match, prefix_check)) { + route_vty_out_flowspec(vty, &rn->p, + rn->info, use_json ? + NLRI_STRING_FORMAT_JSON : + NLRI_STRING_FORMAT_LARGE, + json_paths); + display++; + } + } + return display; } void bgp_flowspec_vty_init(void) @@ -532,6 +563,5 @@ void bgp_flowspec_vty_init(void) install_element(CONFIG_NODE, &debug_bgp_flowspec_cmd); install_element(ENABLE_NODE, &no_debug_bgp_flowspec_cmd); install_element(CONFIG_NODE, &no_debug_bgp_flowspec_cmd); - install_element(BGP_FLOWSPECV4_NODE, &bgp_fs_local_install_any_cmd); install_element(BGP_FLOWSPECV4_NODE, &bgp_fs_local_install_ifname_cmd); } diff --git a/bgpd/bgp_keepalives.c b/bgpd/bgp_keepalives.c index 1504893c47..3216683a54 100644 --- a/bgpd/bgp_keepalives.c +++ b/bgpd/bgp_keepalives.c @@ -180,6 +180,12 @@ void *bgp_keepalives_start(void *arg) pthread_cond_init(peerhash_cond, &attrs); pthread_condattr_destroy(&attrs); +#ifdef GNU_LINUX + pthread_setname_np(fpt->thread, "bgpd_ka"); +#elif defined(OPEN_BSD) + pthread_set_name_np(fpt->thread, "bgpd_ka"); +#endif + /* initialize peer hashtable */ peerhash = hash_create_size(2048, peer_hash_key, peer_hash_cmp, NULL); pthread_mutex_lock(peerhash_mtx); diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index b5ddfd4b21..de475d2dcd 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -231,6 +231,8 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, struct nexthop *nh, float *rate); +static void bgp_pbr_dump_entry(struct bgp_pbr_filter *bpf, bool add); + static bool bgp_pbr_extract_enumerate_unary_opposite( uint8_t unary_operator, struct bgp_pbr_val_mask *and_valmask, @@ -833,12 +835,12 @@ uint32_t bgp_pbr_match_hash_key(void *arg) key = jhash_1word(pbm->vrf_id, 0x4312abde); key = jhash_1word(pbm->flags, key); - key = jhash_1word(pbm->pkt_len_min, key); - key = jhash_1word(pbm->pkt_len_max, key); - key = jhash_1word(pbm->tcp_flags, key); - key = jhash_1word(pbm->tcp_mask_flags, key); - key = jhash_1word(pbm->dscp_value, key); - key = jhash_1word(pbm->fragment, key); + key = jhash(&pbm->pkt_len_min, 2, key); + key = jhash(&pbm->pkt_len_max, 2, key); + key = jhash(&pbm->tcp_flags, 2, key); + key = jhash(&pbm->tcp_mask_flags, 2, key); + key = jhash(&pbm->dscp_value, 1, key); + key = jhash(&pbm->fragment, 1, key); return jhash_1word(pbm->type, key); } @@ -1225,7 +1227,8 @@ static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa, /* unlink bgp_info to bpme */ bgp_info = (struct bgp_info *)bpme->bgp_info; extra = bgp_info_extra_get(bgp_info); - extra->bgp_fs_pbr = NULL; + if (extra->bgp_fs_pbr) + listnode_delete(extra->bgp_fs_pbr, bpme); bpme->bgp_info = NULL; } } @@ -1282,7 +1285,13 @@ static int bgp_pbr_get_remaining_entry(struct hash_backet *backet, void *arg) bpm_temp = bpme->backpointer; if (bpm_temp->vrf_id != bpm->vrf_id || bpm_temp->type != bpm->type || - bpm_temp->flags != bpm->flags) + bpm_temp->flags != bpm->flags || + bpm_temp->tcp_flags != bpm->tcp_flags || + bpm_temp->tcp_mask_flags != bpm->tcp_mask_flags || + bpm_temp->pkt_len_min != bpm->pkt_len_min || + bpm_temp->pkt_len_max != bpm->pkt_len_max || + bpm_temp->dscp_value != bpm->dscp_value || + bpm_temp->fragment != bpm->fragment) return HASHWALK_CONTINUE; /* look for remaining bpme */ @@ -1311,6 +1320,9 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(struct bgp *bgp, dst_port = bpf->dst_port; pkt_len = bpf->pkt_len; + if (BGP_DEBUG(zebra, ZEBRA)) + bgp_pbr_dump_entry(bpf, false); + /* as we don't know information from EC * look for bpm that have the bpm * with vrf_id characteristics @@ -1581,6 +1593,101 @@ static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp, list_delete_all_node(bpof->fragment); } +static void bgp_pbr_dump_entry(struct bgp_pbr_filter *bpf, bool add) +{ + struct bgp_pbr_range_port *src_port; + struct bgp_pbr_range_port *dst_port; + struct bgp_pbr_range_port *pkt_len; + char bufsrc[64], bufdst[64]; + char buffer[64]; + int remaining_len = 0; + char protocol_str[16]; + + if (!bpf) + return; + src_port = bpf->src_port; + dst_port = bpf->dst_port; + pkt_len = bpf->pkt_len; + + protocol_str[0] = '\0'; + if (bpf->tcp_flags && bpf->tcp_flags->mask) + bpf->protocol = IPPROTO_TCP; + if (bpf->protocol) + snprintf(protocol_str, sizeof(protocol_str), + "proto %d", bpf->protocol); + buffer[0] = '\0'; + if (bpf->protocol == IPPROTO_ICMP && src_port && dst_port) + remaining_len += snprintf(buffer, sizeof(buffer), + "type %d, code %d", + src_port->min_port, + dst_port->min_port); + else if (bpf->protocol == IPPROTO_UDP || + bpf->protocol == IPPROTO_TCP) { + + if (src_port && src_port->min_port) + remaining_len += snprintf(buffer, + sizeof(buffer), + "from [%u:%u]", + src_port->min_port, + src_port->max_port ? + src_port->max_port : + src_port->min_port); + if (dst_port && dst_port->min_port) + remaining_len += snprintf(buffer + + remaining_len, + sizeof(buffer) + - remaining_len, + "to [%u:%u]", + dst_port->min_port, + dst_port->max_port ? + dst_port->max_port : + dst_port->min_port); + } + if (pkt_len && (pkt_len->min_port || pkt_len->max_port)) { + remaining_len += snprintf(buffer + remaining_len, + sizeof(buffer) + - remaining_len, + " len [%u:%u]", + pkt_len->min_port, + pkt_len->max_port ? + pkt_len->max_port : + pkt_len->min_port); + } else if (bpf->pkt_len_val) { + remaining_len += snprintf(buffer + remaining_len, + sizeof(buffer) + - remaining_len, + " %s len %u", + bpf->pkt_len_val->mask + ? "!" : "", + bpf->pkt_len_val->val); + } + if (bpf->tcp_flags) { + remaining_len += snprintf(buffer + remaining_len, + sizeof(buffer) + - remaining_len, + "tcpflags %x/%x", + bpf->tcp_flags->val, + bpf->tcp_flags->mask); + } + if (bpf->dscp) { + snprintf(buffer + remaining_len, + sizeof(buffer) + - remaining_len, + "%s dscp %d", + bpf->dscp->mask + ? "!" : "", + bpf->dscp->val); + } + zlog_info("BGP: %s FS PBR from %s to %s, %s %s", + add ? "adding" : "removing", + bpf->src == NULL ? "<all>" : + prefix2str(bpf->src, bufsrc, sizeof(bufsrc)), + bpf->dst == NULL ? "<all>" : + prefix2str(bpf->dst, bufdst, sizeof(bufdst)), + protocol_str, buffer); + +} + static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, struct bgp_info *binfo, struct bgp_pbr_filter *bpf, @@ -1597,6 +1704,7 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, struct bgp_pbr_range_port *src_port; struct bgp_pbr_range_port *dst_port; struct bgp_pbr_range_port *pkt_len; + bool bpme_found = false; if (!bpf) return; @@ -1604,87 +1712,9 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, dst_port = bpf->dst_port; pkt_len = bpf->pkt_len; - if (BGP_DEBUG(zebra, ZEBRA)) { - char bufsrc[64], bufdst[64]; - char buffer[64]; - int remaining_len = 0; - char protocol_str[16]; - - protocol_str[0] = '\0'; - if (bpf->tcp_flags && bpf->tcp_flags->mask) - bpf->protocol = IPPROTO_TCP; - if (bpf->protocol) - snprintf(protocol_str, sizeof(protocol_str), - "proto %d", bpf->protocol); - buffer[0] = '\0'; - if (bpf->protocol == IPPROTO_ICMP && src_port && dst_port) - remaining_len += snprintf(buffer, sizeof(buffer), - "type %d, code %d", - src_port->min_port, dst_port->min_port); - else if (bpf->protocol == IPPROTO_UDP || - bpf->protocol == IPPROTO_TCP) { - - if (src_port && src_port->min_port) - remaining_len += snprintf(buffer, - sizeof(buffer), - "from [%u:%u]", - src_port->min_port, - src_port->max_port ? - src_port->max_port : - src_port->min_port); - if (dst_port && dst_port->min_port) - remaining_len += snprintf(buffer + - remaining_len, - sizeof(buffer) - - remaining_len, - "to [%u:%u]", - dst_port->min_port, - dst_port->max_port ? - dst_port->max_port : - dst_port->min_port); - } - if (pkt_len && (pkt_len->min_port || pkt_len->max_port)) { - remaining_len += snprintf(buffer + remaining_len, - sizeof(buffer) - - remaining_len, - " len [%u:%u]", - pkt_len->min_port, - pkt_len->max_port ? - pkt_len->max_port : - pkt_len->min_port); - } else if (bpf->pkt_len_val) { - remaining_len += snprintf(buffer + remaining_len, - sizeof(buffer) - - remaining_len, - " %s len %u", - bpf->pkt_len_val->mask - ? "!" : "", - bpf->pkt_len_val->val); - } - if (bpf->tcp_flags) { - remaining_len += snprintf(buffer + remaining_len, - sizeof(buffer) - - remaining_len, - "tcpflags %x/%x", - bpf->tcp_flags->val, - bpf->tcp_flags->mask); - } - if (bpf->dscp) { - snprintf(buffer + remaining_len, - sizeof(buffer) - - remaining_len, - "%s dscp %d", - bpf->dscp->mask - ? "!" : "", - bpf->dscp->val); - } - zlog_info("BGP: adding FS PBR from %s to %s, %s %s", - bpf->src == NULL ? "<all>" : - prefix2str(bpf->src, bufsrc, sizeof(bufsrc)), - bpf->dst == NULL ? "<all>" : - prefix2str(bpf->dst, bufdst, sizeof(bufdst)), - protocol_str, buffer); - } + if (BGP_DEBUG(zebra, ZEBRA)) + bgp_pbr_dump_entry(bpf, true); + /* look for bpa first */ memset(&temp3, 0, sizeof(temp3)); if (rate) @@ -1817,8 +1847,21 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, bpme->install_in_progress = false; /* link bgp info to bpme */ bpme->bgp_info = (void *)binfo; - } + } else + bpme_found = true; + /* already installed */ + if (bpme_found && bpme) { + struct bgp_info_extra *extra = bgp_info_extra_get(binfo); + + if (extra && extra->bgp_fs_pbr && + listnode_lookup(extra->bgp_fs_pbr, bpme)) { + if (BGP_DEBUG(pbr, PBR_ERROR)) + zlog_err("%s: entry %p/%p already installed in bgp pbr", + __func__, binfo, bpme); + return; + } + } /* BGP FS: append entry to zebra * - policies are not routing entries and as such * route replace semantics don't necessarily follow @@ -2195,7 +2238,6 @@ void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p, bool nlri_update) { struct bgp_pbr_entry_main api; - struct bgp_info_extra *extra = bgp_info_extra_get(info); if (afi == AFI_IP6) return; /* IPv6 not supported */ @@ -2212,13 +2254,6 @@ void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p, __func__); return; } - /* already installed */ - if (nlri_update && extra->bgp_fs_pbr) { - if (BGP_DEBUG(pbr, PBR_ERROR)) - zlog_err("%s: entry %p already installed in bgp pbr", - __func__, info); - return; - } if (bgp_pbr_build_and_validate_entry(p, info, &api) < 0) { if (BGP_DEBUG(pbr, PBR_ERROR)) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index f10f7425c6..b66a913f54 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -188,14 +188,17 @@ static void bgp_info_extra_free(struct bgp_info_extra **extra) struct bgp_info *bi = (struct bgp_info *)e->parent; if (bi->net) - bgp_unlock_node((struct bgp_node *)bi->net); - bi->net = NULL; + bi->net = bgp_unlock_node((struct bgp_node *)bi->net); bgp_info_unlock(e->parent); e->parent = NULL; } if (e->bgp_orig) bgp_unlock(e->bgp_orig); + + if ((*extra)->bgp_fs_pbr) + list_delete_all_node((*extra)->bgp_fs_pbr); + (*extra)->bgp_fs_pbr = NULL; XFREE(MTYPE_BGP_ROUTE_EXTRA, *extra); *extra = NULL; @@ -5198,8 +5201,8 @@ int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty, if (routermac) { bgp_static->router_mac = XCALLOC(MTYPE_ATTR, ETH_ALEN + 1); - prefix_str2mac(routermac, - bgp_static->router_mac); + (void)prefix_str2mac(routermac, + bgp_static->router_mac); } if (gwip) prefix_copy(&bgp_static->gatewayIp, &gw_ip); @@ -7734,13 +7737,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, else vty_out(vty, ", localpref %u", attr->local_pref); - } else { - if (json_paths) - json_object_int_add(json_path, "localpref", - bgp->default_local_pref); - else - vty_out(vty, ", localpref %u", - bgp->default_local_pref); } if (attr->weight != 0) { @@ -8789,17 +8785,11 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, bgp_unlock_node(rm); } } else if (safi == SAFI_FLOWSPEC) { - rn = bgp_flowspec_get_match_per_ip(afi, rib, - &match, prefix_check); - if (rn != NULL) { - route_vty_out_flowspec(vty, &rn->p, - rn->info, use_json ? - NLRI_STRING_FORMAT_JSON : - NLRI_STRING_FORMAT_LARGE, - json_paths); - display++; - bgp_unlock_node(rn); - } + display = bgp_flowspec_display_match_per_ip(afi, rib, + &match, prefix_check, + vty, + use_json, + json_paths); } else { header = 1; @@ -9570,7 +9560,7 @@ ravg_tally (unsigned long count, unsigned long oldavg, unsigned long newval) unsigned long newtot = (count-1) * oldavg + (newval * TALLY_SIGFIG); unsigned long res = (newtot * TALLY_SIGFIG) / count; unsigned long ret = newtot / count; - + if ((res % TALLY_SIGFIG) > (TALLY_SIGFIG/2)) return ret + 1; else @@ -9664,7 +9654,7 @@ static int bgp_table_stats_walker(struct thread *t) ts->counts[BGP_STATS_ASPATH_TOTHOPS] += hops; ts->counts[BGP_STATS_ASPATH_TOTSIZE] += size; #if 0 - ts->counts[BGP_STATS_ASPATH_AVGHOPS] + ts->counts[BGP_STATS_ASPATH_AVGHOPS] = ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT], ts->counts[BGP_STATS_ASPATH_AVGHOPS], hops); @@ -10101,6 +10091,7 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, json_object *json_ocode = NULL; json_object *json_ar = NULL; struct peer_af *paf; + bool route_filtered; if (use_json) { json_scode = json_object_new_object(); @@ -10151,9 +10142,9 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, json_scode); json_object_object_add(json, "bgpOriginCodes", json_ocode); - json_object_string_add(json, - "bgpOriginatingDefaultNetwork", - "0.0.0.0"); + json_object_string_add( + json, "bgpOriginatingDefaultNetwork", + (afi == AFI_IP) ? "0.0.0.0/0" : "::/0"); } else { vty_out(vty, "BGP table version is %" PRIu64 ", local router ID is %s, vrf id ", @@ -10167,7 +10158,8 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, vty_out(vty, BGP_SHOW_NCODE_HEADER); vty_out(vty, BGP_SHOW_OCODE_HEADER); - vty_out(vty, "Originating default network 0.0.0.0\n\n"); + vty_out(vty, "Originating default network %s\n\n", + (afi == AFI_IP) ? "0.0.0.0/0" : "::/0"); } header1 = 0; } @@ -10223,17 +10215,27 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, } bgp_attr_dup(&attr, ain->attr); + route_filtered = false; + + /* Filter prefix using distribute list, + * filter list or prefix list + */ + if ((bgp_input_filter(peer, &rn->p, &attr, afi, + safi)) == FILTER_DENY) + route_filtered = true; + + /* Filter prefix using route-map */ ret = bgp_input_modifier(peer, &rn->p, &attr, - afi, safi, rmap_name); + afi, safi, rmap_name); - if (type == bgp_show_adj_route_filtered - && ret != RMAP_DENY) { + if (type == bgp_show_adj_route_filtered && + !route_filtered && ret != RMAP_DENY) { bgp_attr_undup(&attr, ain->attr); continue; } - if (type == bgp_show_adj_route_received - && ret == RMAP_DENY) + if (type == bgp_show_adj_route_received && + (route_filtered || ret == RMAP_DENY)) filtered_count++; route_vty_out_tmp(vty, &rn->p, &attr, safi, diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 72923901b8..dfef9a8f79 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -147,7 +147,7 @@ struct bgp_info_extra { */ struct prefix nexthop_orig; /* presence of FS pbr entry */ - void *bgp_fs_pbr; + struct list *bgp_fs_pbr; }; struct bgp_info { diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index f9f5142cd0..bee4fca705 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -234,7 +234,8 @@ struct bgp_match_peer_compiled { /* Compares the peer specified in the 'match peer' clause with the peer received in bgp_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, struct prefix *prefix, +static route_map_result_t route_match_peer(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -334,7 +335,7 @@ struct route_map_rule_cmd route_match_peer_cmd = {"peer", route_match_peer, /* 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, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -374,7 +375,7 @@ struct route_map_rule_cmd route_match_ip_address_cmd = { /* 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, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -421,7 +422,7 @@ struct route_map_rule_cmd route_match_ip_next_hop_cmd = { /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_ip_route_source(void *rule, - struct prefix *prefix, + const struct prefix *pfx, route_map_object_t type, void *object) { @@ -430,7 +431,7 @@ static route_map_result_t route_match_ip_route_source(void *rule, struct peer *peer; struct prefix_ipv4 p; - if (type == RMAP_BGP && prefix->family == AF_INET) { + if (type == RMAP_BGP && pfx->family == AF_INET) { bgp_info = object; peer = bgp_info->peer; @@ -473,7 +474,7 @@ struct route_map_rule_cmd route_match_ip_route_source_cmd = { /* `match ip address prefix-list PREFIX_LIST' */ static route_map_result_t -route_match_ip_address_prefix_list(void *rule, struct prefix *prefix, +route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; @@ -508,7 +509,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 -route_match_ip_next_hop_prefix_list(void *rule, struct prefix *prefix, +route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; @@ -550,7 +551,8 @@ struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = { /* `match ip route-source prefix-list PREFIX_LIST' */ static route_map_result_t -route_match_ip_route_source_prefix_list(void *rule, struct prefix *prefix, +route_match_ip_route_source_prefix_list(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; @@ -599,7 +601,7 @@ struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd = { /* Match function should return 1 if match is success else 0 */ static route_map_result_t route_match_evpn_default_route(void *rule, - struct prefix *p, + const struct prefix *p, route_map_object_t type, void *object) { @@ -618,7 +620,7 @@ 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, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -667,7 +669,8 @@ struct route_map_rule_cmd route_match_mac_address_cmd = { /* Match function should return 1 if match is success else return zero. */ -static route_map_result_t route_match_vni(void *rule, struct prefix *prefix, +static route_map_result_t route_match_vni(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { vni_t vni = 0; @@ -722,7 +725,7 @@ 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, - struct prefix *prefix, + const struct prefix *pfx, route_map_object_t type, void *object) { @@ -731,7 +734,7 @@ static route_map_result_t route_match_evpn_route_type(void *rule, if (type == RMAP_BGP) { route_type = *((uint8_t *)rule); - if (route_type == prefix->u.prefix_evpn.route_type) + if (route_type == pfx->u.prefix_evpn.route_type) return RMAP_MATCH; } @@ -770,7 +773,7 @@ struct route_map_rule_cmd route_match_evpn_route_type_cmd = { /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_local_pref(void *rule, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -829,7 +832,8 @@ 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, struct prefix *prefix, +static route_map_result_t route_match_metric(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -852,7 +856,8 @@ 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, struct prefix *prefix, +static route_map_result_t route_match_aspath(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -901,7 +906,7 @@ struct rmap_community { /* Match function for community match. */ static route_map_result_t route_match_community(void *rule, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -969,7 +974,7 @@ struct route_map_rule_cmd route_match_community_cmd = { /* Match function for lcommunity match. */ static route_map_result_t route_match_lcommunity(void *rule, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1030,7 +1035,7 @@ struct route_map_rule_cmd route_match_lcommunity_cmd = { /* Match function for extcommunity match. */ static route_map_result_t route_match_ecommunity(void *rule, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1072,7 +1077,8 @@ 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, struct prefix *prefix, +static route_map_result_t route_match_origin(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1120,7 +1126,7 @@ struct route_map_rule_cmd route_match_origin_cmd = { /* match probability { */ static route_map_result_t route_match_probability(void *rule, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1175,7 +1181,7 @@ struct route_map_rule_cmd route_match_probability_cmd = { /* Match function should return 1 if match is success else return zero. */ static route_map_result_t route_match_interface(void *rule, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1221,7 +1227,8 @@ 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, struct prefix *prefix, +static route_map_result_t route_match_tag(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag; @@ -1254,7 +1261,7 @@ struct rmap_ip_nexthop_set { }; static route_map_result_t route_set_ip_nexthop(void *rule, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1362,7 +1369,7 @@ struct route_map_rule_cmd route_set_ip_nexthop_cmd = { /* Set local preference. */ static route_map_result_t route_set_local_pref(void *rule, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1396,7 +1403,8 @@ 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, struct prefix *prefix, +static route_map_result_t route_set_weight(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1424,7 +1432,8 @@ 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, struct prefix *prefix, +static route_map_result_t route_set_metric(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1457,7 +1466,7 @@ struct route_map_rule_cmd route_set_metric_cmd = { /* For AS path prepend mechanism. */ static route_map_result_t route_set_aspath_prepend(void *rule, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1520,7 +1529,7 @@ struct route_map_rule_cmd route_set_aspath_prepend_cmd = { * 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, - struct prefix *dummy, + const struct prefix *dummy, route_map_object_t type, void *object) { @@ -1554,7 +1563,8 @@ struct rmap_com_set { }; /* For community set mechanism. */ -static route_map_result_t route_set_community(void *rule, struct prefix *prefix, +static route_map_result_t route_set_community(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1670,7 +1680,7 @@ struct rmap_lcom_set { /* For lcommunity set mechanism. */ static route_map_result_t route_set_lcommunity(void *rule, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1783,7 +1793,7 @@ struct route_map_rule_cmd route_set_lcommunity_cmd = { /* For large community set mechanism. */ static route_map_result_t route_set_lcommunity_delete(void *rule, - struct prefix *prefix, + const struct prefix *pfx, route_map_object_t type, void *object) { @@ -1866,10 +1876,11 @@ 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, - struct prefix *prefix, - route_map_object_t type, - void *object) +static route_map_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; @@ -1950,7 +1961,7 @@ struct route_map_rule_cmd route_set_community_delete_cmd = { /* For community set mechanism. Used by _rt and _soo. */ static route_map_result_t route_set_ecommunity(void *rule, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -2037,7 +2048,8 @@ 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, struct prefix *prefix, +static route_map_result_t route_set_origin(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -2087,7 +2099,7 @@ struct route_map_rule_cmd route_set_origin_cmd = { /* For atomic aggregate set. */ static route_map_result_t route_set_atomic_aggregate(void *rule, - struct prefix *prefix, + const struct prefix *pfx, route_map_object_t type, void *object) { @@ -2127,7 +2139,7 @@ struct aggregator { }; static route_map_result_t route_set_aggregator_as(void *rule, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -2180,7 +2192,8 @@ struct route_map_rule_cmd route_set_aggregator_as_cmd = { }; /* Set tag to object. object must be pointer to struct bgp_info */ -static route_map_result_t route_set_tag(void *rule, struct prefix *prefix, +static route_map_result_t route_set_tag(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag; @@ -2205,7 +2218,7 @@ static struct route_map_rule_cmd route_set_tag_cmd = { /* Set label-index to object. object must be pointer to struct bgp_info */ static route_map_result_t route_set_label_index(void *rule, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -2239,7 +2252,7 @@ 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, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -2275,7 +2288,7 @@ 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, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -2327,7 +2340,7 @@ struct route_map_rule_cmd route_match_ipv6_next_hop_cmd = { /* `match ipv6 address prefix-list PREFIX_LIST' */ static route_map_result_t -route_match_ipv6_address_prefix_list(void *rule, struct prefix *prefix, +route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; @@ -2363,7 +2376,7 @@ struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = { /* Set nexthop to object. ojbect must be pointer to struct attr. */ static route_map_result_t route_set_ipv6_nexthop_global(void *rule, - struct prefix *prefix, + const struct prefix *p, route_map_object_t type, void *object) { @@ -2423,7 +2436,7 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_global_cmd = { /* Set next-hop preference value. */ static route_map_result_t -route_set_ipv6_nexthop_prefer_global(void *rule, struct prefix *prefix, +route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { struct bgp_info *bgp_info; @@ -2477,7 +2490,7 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_prefer_global_cmd = { /* Set nexthop to object. ojbect must be pointer to struct attr. */ static route_map_result_t route_set_ipv6_nexthop_local(void *rule, - struct prefix *prefix, + const struct prefix *p, route_map_object_t type, void *object) { @@ -2540,7 +2553,7 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = { /* Set nexthop to object. ojbect must be pointer to struct attr. */ static route_map_result_t route_set_ipv6_nexthop_peer(void *rule, - struct prefix *prefix, + const struct prefix *pfx, route_map_object_t type, void *object) { @@ -2619,7 +2632,7 @@ 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, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -2659,7 +2672,7 @@ 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, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -2715,7 +2728,7 @@ struct route_map_rule_cmd route_set_vpnv6_nexthop_cmd = { /* For origin set. */ static route_map_result_t route_set_originator_id(void *rule, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -4797,9 +4810,5 @@ void bgp_route_map_init(void) void bgp_route_map_terminate(void) { /* ToDo: Cleanup all the used memory */ - - route_map_add_hook(NULL); - route_map_delete_hook(NULL); - route_map_event_hook(NULL); route_map_finish(); } diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index 94e2d83cfe..234553b6ea 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -144,9 +144,6 @@ 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; - if (node == NULL) - return; - while (node && node->p.prefixlen <= p->prefixlen && prefix_match(&node->p, p)) { if (node->info && node->p.prefixlen == p->prefixlen) { @@ -157,6 +154,9 @@ 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) return; else if (matched == NULL) diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 60c2cbd4a4..f7eac09546 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -128,9 +128,9 @@ static inline struct bgp_node *bgp_node_parent_nolock(struct bgp_node *node) /* * bgp_unlock_node */ -static inline void bgp_unlock_node(struct bgp_node *node) +static inline struct bgp_node *bgp_unlock_node(struct bgp_node *node) { - route_unlock_node(bgp_node_to_rnode(node)); + return (struct bgp_node *)route_unlock_node(bgp_node_to_rnode(node)); } /* diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index d555006571..6ffb1d448b 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -663,7 +663,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) { struct bgp *bgp; struct attr attr; - struct aspath *aspath; + struct bgp_info *info, init_info, tmp_info; struct prefix p; struct peer *from; struct bgp_node *rn; @@ -687,47 +687,59 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) from = bgp->peer_self; bgp_attr_default_set(&attr, BGP_ORIGIN_IGP); - aspath = attr.aspath; - attr.local_pref = bgp->default_local_pref; - memset(&p, 0, sizeof(p)); - p.family = afi2family(afi); - p.prefixlen = 0; - if ((afi == AFI_IP6) || peer_cap_enhe(peer, afi, safi)) { - /* IPv6 global nexthop must be included. */ + /* IPv6 global nexthop must be included. + */ attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; - /* If the peer is on shared nextwork and we have link-local - nexthop set it. */ + /* If the peer is on shared nextwork and + * we have link-local nexthop set it. */ if (peer->shared_network && !IN6_IS_ADDR_UNSPECIFIED(&peer->nexthop.v6_local)) attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL; } + init_info.attr = &attr; + info = &init_info; + bgp_attr_intern(info->attr); + + memset(&p, 0, sizeof(p)); + p.family = afi2family(afi); + p.prefixlen = 0; if (peer->default_rmap[afi][safi].name) { SET_FLAG(bgp->peer_self->rmap_type, PEER_RMAP_TYPE_DEFAULT); for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; rn = bgp_route_next(rn)) { for (ri = rn->info; ri; ri = ri->next) { - struct attr dummy_attr; - struct bgp_info info; - - /* Provide dummy so the route-map can't modify - * the attributes */ - bgp_attr_dup(&dummy_attr, ri->attr); - info.peer = ri->peer; - info.attr = &dummy_attr; + tmp_info.peer = ri->peer; + tmp_info.attr = ri->attr; + + /* Reset attributes every time to avoid \ + * unexpected as-path prepends */ + bgp_attr_default_set(tmp_info.attr, + BGP_ORIGIN_IGP); + + if ((afi == AFI_IP6) + || peer_cap_enhe(peer, afi, safi)) { + tmp_info.attr->mp_nexthop_len = + BGP_ATTR_NHLEN_IPV6_GLOBAL; + + if (peer->shared_network + && !IN6_IS_ADDR_UNSPECIFIED( + &peer->nexthop.v6_local)) + tmp_info.attr->mp_nexthop_len = + BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL; + } ret = route_map_apply( peer->default_rmap[afi][safi].map, - &rn->p, RMAP_BGP, &info); + &rn->p, RMAP_BGP, &tmp_info); + + info = &tmp_info; + bgp_attr_intern(info->attr); - /* The route map might have set attributes. If - * we don't flush them - * here, they will be leaked. */ - bgp_attr_flush(&dummy_attr); if (ret != RMAP_DENYMATCH) break; } @@ -749,12 +761,13 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) SUBGRP_STATUS_DEFAULT_ORIGINATE)) { if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) { - bgp_attr_add_gshut_community(&attr); + bgp_attr_add_gshut_community(info->attr); } SET_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE); - subgroup_default_update_packet(subgrp, &attr, from); + subgroup_default_update_packet(subgrp, info->attr, + from); /* The 'neighbor x.x.x.x default-originate' default will * act as an @@ -774,8 +787,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE); } } - - aspath_unintern(&aspath); + aspath_unintern(&info->attr->aspath); } /* diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index ec8595259e..e3efbbf252 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -184,6 +184,7 @@ safi_t bgp_node_safi(struct vty *vty) * @param afi string, one of * - "ipv4" * - "ipv6" + * - "l2vpn" * @return the corresponding afi_t */ afi_t bgp_vty_afi_from_str(const char *afi_str) @@ -193,6 +194,8 @@ afi_t bgp_vty_afi_from_str(const char *afi_str) afi = AFI_IP; else if (strmatch(afi_str, "ipv6")) afi = AFI_IP6; + else if (strmatch(afi_str, "l2vpn")) + afi = AFI_L2VPN; return afi; } @@ -222,6 +225,8 @@ safi_t bgp_vty_safi_from_str(const char *safi_str) safi = SAFI_UNICAST; else if (strmatch(safi_str, "vpn")) safi = SAFI_MPLS_VPN; + else if (strmatch(safi_str, "evpn")) + safi = SAFI_EVPN; else if (strmatch(safi_str, "labeled-unicast")) safi = SAFI_LABELED_UNICAST; else if (strmatch(safi_str, "flowspec")) @@ -772,7 +777,7 @@ static void bgp_clear_star_soft_out(struct vty *vty, const char *name) #endif /* BGP global configuration. */ -#if defined(VERSION_TYPE_DEV) && (CONFDATE > 20190601) +#if (CONFDATE > 20190601) CPP_NOTICE("bgpd: time to remove deprecated bgp multiple-instance") CPP_NOTICE("This includes BGP_OPT_MULTIPLE_INSTANCE") #endif @@ -806,7 +811,7 @@ DEFUN_HIDDEN (no_bgp_multiple_instance, return CMD_SUCCESS; } -#if defined(VERSION_TYPE_DEV) && (CONFDATE > 20190601) +#if (CONFDATE > 20190601) CPP_NOTICE("bgpd: time to remove deprecated cli bgp config-type cisco") CPP_NOTICE("This includes BGP_OPT_CISCO_CONFIG") #endif @@ -2013,7 +2018,7 @@ DEFUN (no_bgp_fast_external_failover, } /* "bgp enforce-first-as" configuration. */ -#if defined(VERSION_TYPE_DEV) && CONFDATE > 20180517 +#if CONFDATE > 20180517 CPP_NOTICE("bgpd: remove deprecated '[no] bgp enforce-first-as' commands") #endif @@ -7909,9 +7914,11 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, if (use_json) { json_peer = json_object_new_object(); - if (peer_dynamic_neighbor(peer)) + if (peer_dynamic_neighbor(peer)) { + dn_count++; json_object_boolean_true_add(json_peer, "dynamicPeer"); + } if (peer->hostname) json_object_string_add(json_peer, "hostname", @@ -9138,7 +9145,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, uint8_t use_json, uptime -= p->uptime; epoch_tbuf = time(NULL) - uptime; -#if defined(VERSION_TYPE_DEV) && CONFDATE > 20200101 +#if CONFDATE > 20200101 CPP_NOTICE( "bgpTimerUp should be deprecated and can be removed now"); #endif diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 714f6791c1..9591fe673f 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1998,7 +1998,7 @@ static int ipset_notify_owner(int command, struct zclient *zclient, bgp_pbim = bgp_pbr_match_ipset_lookup(vrf_id, unique); if (!bgp_pbim) { if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("%s: Fail to look BGP match ( %u %u)", + zlog_debug("%s: Fail to look BGP match ( %u, ID %u)", __PRETTY_FUNCTION__, note, unique); return 0; } @@ -2048,7 +2048,7 @@ static int ipset_entry_notify_owner(int command, struct zclient *zclient, unique); if (!bgp_pbime) { if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("%s: Fail to look BGP match entry (%u %u)", + zlog_debug("%s: Fail to look BGP match entry (%u, ID %u)", __PRETTY_FUNCTION__, note, unique); return 0; } @@ -2074,7 +2074,9 @@ static int ipset_entry_notify_owner(int command, struct zclient *zclient, /* link bgp_info to bpme */ bgp_info = (struct bgp_info *)bgp_pbime->bgp_info; extra = bgp_info_extra_get(bgp_info); - extra->bgp_fs_pbr = (void *)bgp_pbime; + if (extra->bgp_fs_pbr == NULL) + extra->bgp_fs_pbr = list_new(); + listnode_add(extra->bgp_fs_pbr, bgp_pbime); } break; case ZAPI_IPSET_ENTRY_FAIL_REMOVE: @@ -2587,9 +2589,10 @@ void bgp_send_pbr_ipset_match(struct bgp_pbr_match *pbrim, bool install) if (pbrim->install_in_progress) return; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("%s: name %s type %d %d", + zlog_debug("%s: name %s type %d %d, ID %u", __PRETTY_FUNCTION__, - pbrim->ipset_name, pbrim->type, install); + pbrim->ipset_name, pbrim->type, + install, pbrim->unique); s = zclient->obuf; stream_reset(s); @@ -2615,9 +2618,9 @@ void bgp_send_pbr_ipset_entry_match(struct bgp_pbr_match_entry *pbrime, if (pbrime->install_in_progress) return; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("%s: name %s %d %d", __PRETTY_FUNCTION__, + zlog_debug("%s: name %s %d %d, ID %u", __PRETTY_FUNCTION__, pbrime->backpointer->ipset_name, - pbrime->unique, install); + pbrime->unique, install, pbrime->unique); s = zclient->obuf; stream_reset(s); @@ -2682,9 +2685,10 @@ void bgp_send_pbr_iptable(struct bgp_pbr_action *pba, if (pbm->install_iptable_in_progress) return; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("%s: name %s type %d mark %d %d", + zlog_debug("%s: name %s type %d mark %d %d, ID %u", __PRETTY_FUNCTION__, pbm->ipset_name, - pbm->type, pba->fwmark, install); + pbm->type, pba->fwmark, install, + pbm->unique2); s = zclient->obuf; stream_reset(s); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index e5b269eb70..82da0245b5 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3120,6 +3120,9 @@ int bgp_delete(struct bgp *bgp) assert(bgp); THREAD_OFF(bgp->t_startup); + THREAD_OFF(bgp->t_maxmed_onstartup); + THREAD_OFF(bgp->t_update_delay); + THREAD_OFF(bgp->t_establish_wait); if (BGP_DEBUG(zebra, ZEBRA)) { if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) @@ -7356,7 +7359,7 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi, } /* clang-format off */ -#if defined(VERSION_TYPE_DEV) && CONFDATE > 20180517 +#if CONFDATE > 20180517 CPP_NOTICE("bgpd: remove 'bgp enforce-first-as' config migration from bgp_config_write") #endif /* clang-format on */ diff --git a/configure.ac b/configure.ac index 8846fcdf71..a155a12ba7 100755 --- a/configure.ac +++ b/configure.ac @@ -436,6 +436,8 @@ AC_ARG_ENABLE(datacenter, AS_HELP_STRING([--enable-datacenter], [enable Compilation for Data Center Extensions])) AC_ARG_ENABLE(fuzzing, AS_HELP_STRING([--enable-fuzzing], [enable ability to fuzz various parts of FRR])) +AC_ARG_ENABLE(netlink_fuzzing, + AS_HELP_STRING([--enable-netlink-fuzzing], [enable ability to fuzz netlink listening socket in zebra])) AC_ARG_ENABLE(rr-semantics, AS_HELP_STRING([--disable-rr-semantics], [disable the v6 Route Replace semantics])) AC_ARG_ENABLE([protobuf], @@ -501,6 +503,10 @@ if test "${enable_fuzzing}" = "yes" ; then AC_DEFINE(HANDLE_ZAPI_FUZZING,,Compile extensions to use with a fuzzer) fi +if test "${enable_netlink_fuzzing}" = "yes" ; then + AC_DEFINE(HANDLE_NETLINK_FUZZING,,Compile extensions to use with a fuzzer for netlink) +fi + if test "${enable_cumulus}" = "yes" ; then AC_DEFINE(HAVE_CUMULUS,,Compile Special Cumulus Code in) fi @@ -1832,7 +1838,13 @@ AM_CONDITIONAL([ZEROMQ], test "x$ZEROMQ" = "xtrue") dnl ---------- dnl configure date dnl ---------- -CONFDATE=`date '+%Y%m%d'` +dev_version=`echo $VERSION | grep dev` +#don't expire deprecated code in non 'dev' branch +if test "${dev_version}" = ""; then + CONFDATE=0 +else + CONFDATE=`date '+%Y%m%d'` +fi AC_SUBST(CONFDATE) dnl ------------------------------ diff --git a/debianpkg/control b/debianpkg/control index 468581045b..71c412a960 100644 --- a/debianpkg/control +++ b/debianpkg/control @@ -4,7 +4,7 @@ Priority: optional Maintainer: Nobody <nobody@frrouting.org> Uploaders: Nobody <nobody@frrouting.org> XSBC-Original-Maintainer: <maintainers@frrouting.org> -Build-Depends: debhelper (>= 7.0.50~), libncurses5-dev, libreadline-dev, texlive-latex-base, texlive-generic-recommended, libpam0g-dev | libpam-dev, libcap-dev, texinfo (>= 4.7), autotools-dev, libpcre3-dev, gawk, chrpath, libsnmp-dev, git, dh-autoreconf, libjson-c-dev, libjson-c2 | libjson-c3, dh-systemd, libsystemd-dev, bison, flex, libc-ares-dev, pkg-config, python (>= 2.7), python-ipaddr, python-sphinx, libpython-dev +Build-Depends: debhelper (>= 7.0.50~), libncurses5-dev, libreadline-dev, texlive-latex-base, texlive-generic-recommended, libpam0g-dev | libpam-dev, libcap-dev, texinfo (>= 4.7), autotools-dev, libpcre3-dev, gawk, chrpath, libsnmp-dev, git, dh-autoreconf, libjson-c-dev, libjson-c2 | libjson-c3, dh-systemd, libsystemd-dev, bison, flex, libc-ares-dev, pkg-config, python (>= 2.7), python-ipaddr, python-sphinx, libpython-dev, install-info Standards-Version: 3.9.6 Homepage: http://www.frrouting.org/ @@ -29,9 +29,9 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, frr (= ${binary:Version}) Priority: extra Section: debug Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (debug symbols) - This package provides debugging symbols for all binary packages built + This package provides debugging symbols for all binary packages built from frr source package. It's highly recommended to have this package - installed before reporting any FRR crashes to either FRR developers or + installed before reporting any FRR crashes to either FRR developers or Debian package maintainers. Package: frr-doc diff --git a/doc/Makefile.am b/doc/Makefile.am index 62cb3c2edb..19aab63ea3 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -193,6 +193,7 @@ EXTRA_DIST = frr-sphinx.mk \ developer/workflow.rst \ developer/zebra.rst \ user/babeld.rst \ + user/ldpd.rst \ user/basic.rst \ user/bgp.rst \ user/bugs.rst \ diff --git a/doc/developer/modules.rst b/doc/developer/modules.rst index b832413a6c..bde7682e4e 100644 --- a/doc/developer/modules.rst +++ b/doc/developer/modules.rst @@ -100,6 +100,15 @@ a function that removes all of a module's installed hooks. There's also the ``frr_module`` symbol in modules, pretty much a standard entry point for loadable modules. +Command line parameters +----------------------- + +Command line parameters can be passed directly to a module by appending a +colon to the module name when loading it, e.g. ``-M mymodule:myparameter``. +The text after the colon will be accessible in the module's code through +``THIS_MODULE->load_args``. For example, see how the format parameter is +configured in the ``zfpm_init()`` function inside ``zebra_fpm.c``. + Hooks ----- diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index cd03d2733d..358cb9ac7b 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -776,7 +776,7 @@ annotations must be ignored non-development branches. For example: .. code-block:: c - #if defined(VERSION_TYPE_DEV) && CONFDATE > 20180403 + #if CONFDATE > 20180403 CPP_NOTICE("Use of <XYZ> is deprecated, please use <ABC>") #endif diff --git a/doc/extra/spelling_wordlist.txt b/doc/extra/spelling_wordlist.txt index 4c9455e8e9..2944592962 100644 --- a/doc/extra/spelling_wordlist.txt +++ b/doc/extra/spelling_wordlist.txt @@ -83,6 +83,7 @@ IPv isis isisd lan +ldpd le libc libcap diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 579b0b6497..734c9cabd0 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -31,9 +31,9 @@ be specified (:ref:`common-invocation-options`). .. option:: -l, --listenon - Specify a specific IP address for bgpd to listen on, rather than its - default of INADDR_ANY / IN6ADDR_ANY. This can be useful to constrain bgpd - to an internal address, or to run multiple bgpd processes on one host. + Specify a specific IP address for bgpd to listen on, rather than its default + of ``0.0.0.0`` / ``::``. This can be useful to constrain bgpd to an internal + address, or to run multiple bgpd processes on one host. .. _bgp-basic-concepts: @@ -45,26 +45,33 @@ Basic Concepts Autonomous Systems ------------------ -The :abbr:`AS (Autonomous System)` number is one of the essential element of +From :rfc:`1930`: + + An AS is a connected group of one or more IP prefixes run by one or more + network operators which has a SINGLE and CLEARLY DEFINED routing policy. + +Each AS has an identifying number associated with it called an :abbr:`ASN +(Autonomous System Number)`. This is a two octet value ranging in value from 1 +to 65535. The AS numbers 64512 through 65535 are defined as private AS numbers. +Private AS numbers must not be advertised on the global Internet. + +The :abbr:`ASN (Autonomous System Number)` is one of the essential elements of BGP. BGP is a distance vector routing protocol, and the AS-Path framework -provides distance vector metric and loop detection to BGP. :rfc:`1930` provides -some background on the concepts of an AS. +provides distance vector metric and loop detection to BGP. -The AS number is a two octet value, ranging in value from 1 to 65535. The AS -numbers 64512 through 65535 are defined as private AS numbers. Private AS -numbers must not to be advertised in the global Internet. +.. seealso:: :rfc:`1930` .. _bgp-address-families: Address Families ---------------- -Multiprotocol BGP enables BGP to carry routing information for multiple Network -Layer protocols. BGP supports an Address Family Identifier (AFI) for IPv4 and -IPv6. Support is also provided for multiple sets of per-AFI information via the -BGP Subsequent Address Family Identifier (SAFI). FRR supports SAFIs for unicast -information, labeled information :rfc:`3107` and :rfc:`8277`, and Layer 3 VPN -information :rfc:`4364` and :rfc:`4659`. +Multiprotocol extensions enable BGP to carry routing information for multiple +network layer protocols. BGP supports an Address Family Identifier (AFI) for +IPv4 and IPv6. Support is also provided for multiple sets of per-AFI +information via the BGP Subsequent Address Family Identifier (SAFI). FRR +supports SAFIs for unicast information, labeled information (:rfc:`3107` and +:rfc:`8277`), and Layer 3 VPN information (:rfc:`4364` and :rfc:`4659`). .. _bgp-route-selection: @@ -718,35 +725,30 @@ Defining Peers Configuring Peers ^^^^^^^^^^^^^^^^^ -.. index:: neighbor PEER shutdown -.. clicmd:: neighbor PEER shutdown - -.. index:: no neighbor PEER shutdown -.. clicmd:: no neighbor PEER shutdown +.. index:: [no] neighbor PEER shutdown +.. clicmd:: [no] neighbor PEER shutdown Shutdown the peer. We can delete the neighbor's configuration by ``no neighbor PEER remote-as ASN`` but all configuration of the neighbor will be deleted. When you want to preserve the configuration, but want to drop the BGP peer, use this syntax. -.. index:: neighbor PEER ebgp-multihop -.. clicmd:: neighbor PEER ebgp-multihop - -.. index:: no neighbor PEER ebgp-multihop -.. clicmd:: no neighbor PEER ebgp-multihop - +.. index:: [no] neighbor PEER disable-connected-check +.. clicmd:: [no] neighbor PEER disable-connected-check -.. index:: neighbor PEER description ... -.. clicmd:: neighbor PEER description ... + Allow peerings between directly connected eBGP peers using loopback + addresses. +.. index:: [no] neighbor PEER ebgp-multihop +.. clicmd:: [no] neighbor PEER ebgp-multihop -.. index:: no neighbor PEER description ... -.. clicmd:: no neighbor PEER description ... +.. index:: [no] neighbor PEER description ... +.. clicmd:: [no] neighbor PEER description ... Set description of the peer. -.. index:: neighbor PEER version VERSION -.. clicmd:: neighbor PEER version VERSION +.. index:: [no] neighbor PEER version VERSION +.. clicmd:: [no] neighbor PEER version VERSION Set up the neighbor's BGP version. `version` can be `4`, `4+` or `4-`. BGP version `4` is the default value used for BGP peering. BGP version `4+` @@ -755,12 +757,8 @@ Configuring Peers revision 00's Multiprotocol Extensions for BGP-4. Some routing software is still using this version. -.. index:: neighbor PEER interface IFNAME -.. clicmd:: neighbor PEER interface IFNAME - - -.. index:: no neighbor PEER interface IFNAME -.. clicmd:: no neighbor PEER interface IFNAME +.. index:: [no] neighbor PEER interface IFNAME +.. clicmd:: [no] neighbor PEER interface IFNAME When you connect to a BGP peer over an IPv6 link-local address, you have to specify the IFNAME of the interface used for the connection. To specify @@ -770,24 +768,16 @@ Configuring Peers This command is deprecated and may be removed in a future release. Its use should be avoided. -.. index:: neighbor PEER next-hop-self [all] -.. clicmd:: neighbor PEER next-hop-self [all] - - -.. index:: no neighbor PEER next-hop-self [all] -.. clicmd:: no neighbor PEER next-hop-self [all] +.. index:: [no] neighbor PEER next-hop-self [all] +.. clicmd:: [no] neighbor PEER next-hop-self [all] This command specifies an announced route's nexthop as being equivalent to the address of the bgp router if it is learned via eBGP. If the optional keyword `all` is specified the modification is done also for routes learned via iBGP. -.. index:: neighbor PEER update-source <IFNAME|ADDRESS> -.. clicmd:: neighbor PEER update-source <IFNAME|ADDRESS> - - -.. index:: no neighbor PEER update-source -.. clicmd:: no neighbor PEER update-source +.. index:: [no] neighbor PEER update-source <IFNAME|ADDRESS> +.. clicmd:: [no] neighbor PEER update-source <IFNAME|ADDRESS> Specify the IPv4 source address to use for the :abbr:`BGP` session to this neighbour, may be specified as either an IPv4 address directly or as an @@ -801,11 +791,8 @@ Configuring Peers neighbor bar update-source lo0 -.. index:: neighbor PEER default-originate -.. clicmd:: neighbor PEER default-originate - -.. index:: no neighbor PEER default-originate -.. clicmd:: no neighbor PEER default-originate +.. index:: [no] neighbor PEER default-originate +.. clicmd:: [no] neighbor PEER default-originate *bgpd*'s default is to not announce the default route (0.0.0.0/0) even if it is in routing table. When you want to announce default routes to the peer, @@ -817,37 +804,22 @@ Configuring Peers .. index:: neighbor PEER send-community .. clicmd:: neighbor PEER send-community -.. index:: neighbor PEER weight WEIGHT -.. clicmd:: neighbor PEER weight WEIGHT - - -.. index:: no neighbor PEER weight WEIGHT -.. clicmd:: no neighbor PEER weight WEIGHT +.. index:: [no] neighbor PEER weight WEIGHT +.. clicmd:: [no] neighbor PEER weight WEIGHT This command specifies a default `weight` value for the neighbor's routes. -.. index:: neighbor PEER maximum-prefix NUMBER -.. clicmd:: neighbor PEER maximum-prefix NUMBER - - -.. index:: no neighbor PEER maximum-prefix NUMBER -.. clicmd:: no neighbor PEER maximum-prefix NUMBER - +.. index:: [no] neighbor PEER maximum-prefix NUMBER +.. clicmd:: [no] neighbor PEER maximum-prefix NUMBER -.. index:: neighbor PEER local-as AS-NUMBER -.. clicmd:: neighbor PEER local-as AS-NUMBER +.. index:: [no] neighbor PEER local-as AS-NUMBER no-prepend +.. clicmd:: [no] neighbor PEER local-as AS-NUMBER no-prepend +.. index:: [no] neighbor PEER local-as AS-NUMBER no-prepend replace-as +.. clicmd:: [no] neighbor PEER local-as AS-NUMBER no-prepend replace-as -.. index:: neighbor PEER local-as AS-NUMBER no-prepend -.. clicmd:: neighbor PEER local-as AS-NUMBER no-prepend - - -.. index:: neighbor PEER local-as AS-NUMBER no-prepend replace-as -.. clicmd:: neighbor PEER local-as AS-NUMBER no-prepend replace-as - - -.. index:: no neighbor PEER local-as -.. clicmd:: no neighbor PEER local-as +.. index:: [no] neighbor PEER local-as AS-NUMBER +.. clicmd:: [no] neighbor PEER local-as AS-NUMBER Specify an alternate AS for this BGP process when interacting with the specified peer. With no modifiers, the specified local-as is prepended to @@ -865,12 +837,8 @@ Configuring Peers This command is only allowed for eBGP peers. -.. index:: neighbor PEER ttl-security hops NUMBER -.. clicmd:: neighbor PEER ttl-security hops NUMBER - - -.. index:: no neighbor PEER ttl-security hops NUMBER -.. clicmd:: no neighbor PEER ttl-security hops NUMBER +.. index:: [no] neighbor PEER ttl-security hops NUMBER +.. clicmd:: [no] neighbor PEER ttl-security hops NUMBER This command enforces Generalized TTL Security Mechanism (GTSM), as specified in RFC 5082. With this command, only neighbors that are the diff --git a/doc/user/index.rst b/doc/user/index.rst index a8109fe479..746cc1c32d 100644 --- a/doc/user/index.rst +++ b/doc/user/index.rst @@ -41,6 +41,7 @@ Protocols zebra bgp babeld + ldpd eigrpd isisd nhrpd diff --git a/doc/user/ldpd.rst b/doc/user/ldpd.rst new file mode 100644 index 0000000000..8d88ef176b --- /dev/null +++ b/doc/user/ldpd.rst @@ -0,0 +1,309 @@ +.. _ldp: + +*** +LDP +*** + +The *ldpd* daemon is a standardised protocol that permits exchanging MPLS label +information between MPLS devices. The LDP protocol creates peering between +devices, so as to exchange that label information. This information is stored in +MPLS table of *zebra*, and it injects that MPLS information in the underlying +system (Linux kernel or OpenBSD system for instance). +*ldpd* provides necessary options to create a Layer 2 VPN across MPLS network. +For instance, it is possible to interconnect several sites that share the same +broadcast domain. + +FRR implements LDP as described in :rfc:`5036`; other LDP standard are the +following ones: :rfc:`6720`, :rfc:`6667`, :rfc:`5919`, :rfc:`5561`, :rfc:`7552`, +:rfc:`4447`. +Because MPLS is already available, FRR also supports :rfc:`3031`. + +Running Ldpd +============ + +The *ldpd* daemon can be invoked with any of the common +options (:ref:`common-invocation-options`). + +The *zebra* daemon must be running before *ldpd* is invoked. + +Configuration of *ldpd* is done in its configuration file +:file:`ldpd.conf`. + + +.. _understanding-ldp: + +Understanding LDP principles +============================ + +Let's first introduce some definitions that permit understand better the LDP +protocol: + +- `LSR` : Labeled Switch Router. Networking devices handling labels used to + forward traffic between and through them. + +- `LER` : Labeled Edge Router. A Labeled edge router is located at the edge of + an MPLS network, generally between an IP network and an MPLS network. + + +``LDP`` aims at sharing label information across devices. It tries to establish +peering with remote LDP capable devices, first by discovering using UDP port 646 +, then by peering using TCP port 646. Once the TCP session is established, the +label information is shared, through label advertisements. + +There are different methods to send label advertisement modes. The +implementation actually supports the following : Liberal Label Retention + +Downstream Unsolicited + Independent Control. +The other advertising modes are depicted below, and compared with the current +implementation. + +- Liberal label retention versus conservative mode + In liberal mode, every label sent by every LSR is stored in the MPLS table. + In conservative mode, only the label that was sent by the best next hop + (determined by the IGP metric) for that particular FEC is stored in the MPLS + table. + +- Independent LSP Control versus ordered LSP Control + MPLS has two ways of binding labels to FEC’s; either through ordered LSP + control, or independent LSP control. + Ordered LSP control only binds a label to a FEC if it is the egress LSR, or + the router received a label binding for a FEC from the next hop router. In + this mode, an MPLS router will create a label binding for each FEC and + distribute it to its neighbors so long as he has a entry in the RIB for the + destination. + In the other mode, label bindings are made without any dependencies on another + router advertising a label for a particular FEC. Each router makes it own + independent decision to create a label for each FEC. + By default IOS uses Independent LSP Control, while Juniper implements the + Ordered Control. Both modes are interoperable, the difference is that Ordered + Control prevent blackholing during the LDP convergence process, at cost of + slowing down the convergence itself + +- unsolicited downstream versus downstream on demand + Downstream on demand label distribution is where an LSR must explicitly + request that a label be sent from its downstream router for a particular FEC. + Unsolicited label distribution is where a label is sent from the downstream + router without the original router requesting it. + +.. _configuring-ldpd: + +.. _ldp-configuration: + +LDP Configuration +=================== + +.. index:: [no] mpls ldp +.. clicmd:: [no] mpls ldp + + Enable or disable LDP daemon + +.. index:: [no] router-id A.B.C.D +.. clicmd:: [no] router-id A.B.C.D + + The following command located under MPLS router node configures the MPLS + router-id of the local device. + +.. index:: [no] address-family [ipv4 | ipv6] +.. clicmd:: [no] address-family [ipv4 | ipv6] + + Configure LDP for IPv4 or IPv6 address-family. Located under MPLS route node, + this subnode permits configuring the LDP neighbors. + +.. index:: [no] interface IFACE +.. clicmd:: [no] interface IFACE + + Located under MPLS address-family node, use this command to enable or disable + LDP discovery per interface. IFACE stands for the interface name where LDP is + enabled. By default it is disabled. Once this command executed, the + address-family interface node is configured. + +.. index:: [no] discovery transport-address A.B.C.D | A:B::C:D +.. clicmd:: [no] discovery transport-address A.B.C.D | A:B::C:D + + Located under mpls address-family interface node, use this command to set + the IPv4 or IPv6 transport-address used by the LDP protocol to talk on this + interface. + +.. index:: [no] neighbor A.B.C.D password PASSWORD +.. clicmd:: [no] neighbor A.B.C.D password PASSWORD + + The following command located under MPLS router node configures the router + of a LDP device. This device, if found, will have to comply with the + configured password. PASSWORD is a clear text password wit its digest sent + through the network. + +.. index:: [no] neighbor A.B.C.D holdtime HOLDTIME +.. clicmd:: [no] neighbor A.B.C.D holdtime HOLDTIME + + The following command located under MPLS router node configures the holdtime + value in seconds of the LDP neighbor ID. Configuring it triggers a keepalive + mechanism. That value can be configured between 15 and 65535 seconds. After + this time of non response, the LDP established session will be considered as + set to down. By default, no holdtime is configured for the LDP devices. + +.. index:: [no] discovery hello holdtime HOLDTIME +.. clicmd:: [no] discovery hello holdtime HOLDTIME + +.. index:: [no] discovery hello interval INTERVAL +.. clicmd:: [no] discovery hello interval INTERVAL + + INTERVAL value ranges from 1 to 65535 seconds. Default value is 5 seconds. + This is the value between each hello timer message sent. + HOLDTIME value ranges from 1 to 65535 seconds. Default value is 15 seconds. + That value is added as a TLV in the LDP messages. + +.. _show-ldp-information: + +Show LDP Information +==================== + +These commands dump various parts of *ldpd*. + +.. index:: show mpls ldp neighbor [A.B.C.D] +.. clicmd:: show mpls ldp neighbor [A.B.C.D] + + This command dumps the various neighbors discovered. Below example shows that + local machine has an operation neighbor with ID set to 1.1.1.1. + + :: + + west-vm# show mpls ldp neighbor + AF ID State Remote Address Uptime + ipv4 1.1.1.1 OPERATIONAL 1.1.1.1 00:01:37 + west-vm# + +.. index:: show mpls ldp neighbor [A.B.C.D] capabilities +.. clicmd:: show mpls ldp neighbor [A.B.C.D] capabilities + +.. index:: show mpls ldp neighbor [A.B.C.D] detail +.. clicmd:: show mpls ldp neighbor [A.B.C.D] detail + + Above commands dump other neighbor information. + +.. index:: show mpls ldp discovery [detail] +.. clicmd:: show mpls ldp discovery [detail] + +.. index:: show mpls ldp ipv4 discovery [detail] +.. clicmd:: show mpls ldp ipv4 discovery [detail] + +.. index:: show mpls ldp ipv6 discovery [detail] +.. clicmd:: show mpls ldp ipv6 discovery [detail] + + Above commands dump discovery information. + +.. index:: show mpls ldp ipv4 interface +.. clicmd:: show mpls ldp ipv4 interface + +.. index:: show mpls ldp ipv6 interface +.. clicmd:: show mpls ldp ipv6 interface + + Above command dumps the IPv4 or IPv6 interface per where LDP is enabled. + Below output illustrates what is dumped for IPv4. + + :: + + west-vm# show mpls ldp ipv4 interface + AF Interface State Uptime Hello Timers ac + ipv4 eth1 ACTIVE 00:08:35 5/15 0 + ipv4 eth3 ACTIVE 00:08:35 5/15 1 + + +.. index:: show mpls ldp ipv4|ipv6 binding +.. clicmd:: show mpls ldp ipv4|ipv6 binding + + Above command dumps the binding obtained through MPLS exchanges with LDP. + + :: + + west-vm# show mpls ldp ipv4 binding + AF Destination Nexthop Local Label Remote Label In Use + ipv4 1.1.1.1/32 1.1.1.1 16 imp-null yes + ipv4 2.2.2.2/32 1.1.1.1 imp-null 16 no + ipv4 10.0.2.0/24 1.1.1.1 imp-null imp-null no + ipv4 10.115.0.0/24 1.1.1.1 imp-null 17 no + ipv4 10.135.0.0/24 1.1.1.1 imp-null imp-null no + ipv4 10.200.0.0/24 1.1.1.1 17 imp-null yes + west-vm# + +LDP debugging commands +======================== + +.. index:: + simple: debug mpls ldp KIND + simple: no debug mpls ldp KIND + +.. clicmd:: [no] debug mpls ldp KIND + + Enable or disable debugging messages of a given kind. ``KIND`` can + be one of: + + - ``discovery`` + - ``errors`` + - ``event`` + - ``labels`` + - ``messages`` + - ``zebra`` + +LDP Example Configuration +========================= + +Below configuration gives a typical MPLS configuration of a device located in a +MPLS backbone. LDP is enabled on two interfaces and will attempt to peer with +two neighbors with router-id set to either 1.1.1.1 or 3.3.3.3. + +.. code-block:: frr + + mpls ldp + router-id 2.2.2.2 + neighbor 1.1.1.1 password test + neighbor 3.3.3.3 password test + ! + address-family ipv4 + discovery transport-address 2.2.2.2 + ! + interface eth1 + ! + interface eth3 + ! + exit-address-family + ! + + +Deploying LDP across a backbone generally is done in a full mesh configuration +topology. LDP is typically deployed with an IGP like OSPF, that helps discover +the remote IPs. Below example is an OSPF configuration extract that goes with +LDP configuration + +.. code-block:: frr + + router ospf + ospf router-id 2.2.2.2 + network 0.0.0.0/0 area 0 + ! + + +Below output shows the routing entry on the LER side. The OSPF routing entry +(10.200.0.0) is associated with Label entry (17), and shows that MPLS push action +that traffic to that destination will be applied. + +:: + + north-vm# show ip route + Codes: K - kernel route, C - connected, S - static, R - RIP, + O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP, + F - PBR, + > - selected route, * - FIB route + + O>* 1.1.1.1/32 [110/120] via 10.115.0.1, eth2, label 16, 00:00:15 + O>* 2.2.2.2/32 [110/20] via 10.115.0.1, eth2, label implicit-null, 00:00:15 + O 3.3.3.3/32 [110/10] via 0.0.0.0, loopback1 onlink, 00:01:19 + C>* 3.3.3.3/32 is directly connected, loopback1, 00:01:29 + O>* 10.0.2.0/24 [110/11] via 10.115.0.1, eth2, label implicit-null, 00:00:15 + O 10.100.0.0/24 [110/10] is directly connected, eth1, 00:00:32 + C>* 10.100.0.0/24 is directly connected, eth1, 00:00:32 + O 10.115.0.0/24 [110/10] is directly connected, eth2, 00:00:25 + C>* 10.115.0.0/24 is directly connected, eth2, 00:00:32 + O>* 10.135.0.0/24 [110/110] via 10.115.0.1, eth2, label implicit-null, 00:00:15 + O>* 10.200.0.0/24 [110/210] via 10.115.0.1, eth2, label 17, 00:00:15 + north-vm# + diff --git a/doc/user/rpki.rst b/doc/user/rpki.rst index 38b2b68e98..f48ff2e6ba 100644 --- a/doc/user/rpki.rst +++ b/doc/user/rpki.rst @@ -60,39 +60,41 @@ Enabling RPKI This command enables the RPKI configuration mode. Most commands that start with *rpki* can only be used in this mode. - When it is used in a telnet session, leaving of this mode cause rpki to be initialized. + When it is used in a telnet session, leaving of this mode cause rpki to be + initialized. Executing this command alone does not activate prefix validation. You need to configure at least one reachable cache server. See section :ref:`configuring-rpki-rtr-cache-servers` for configuring a cache server. -.. _configuring-rpki-rtr-cache-servers: +.. index:: RPKI and daemons.conf -.. index:: daemons.conf +When first installing FRR with RPKI support from the pre-packaged binaries. +Remember to add ``-M rpki`` to the variable ``bgpd_options`` in +:file:`/etc/frr/daemons.conf` , like so:: - When first installing FRR with RPKI support from the pre-packaged binaries. Remember - to append '-M rpki' in the /etc/frr/daemons.conf file to the bgpd_options. - bgpd_options=" --daemon -A 127.0.0.1 -M rpki" - instead of the default setting + +instead of the default setting:: + bgpd_options=" --daemon -A 127.0.0.1" - - Else you will encounter an error when trying to enter RPKI configuration mode. Because - the rpki module is not loaded when the BGP daemon is initialized. +Otherwise you will encounter an error when trying to enter RPKI +configuration mode due to the ``rpki`` module not being loaded when the BGP +daemon is initialized. - Examples of the error: +Examples of the error:: router(config)# debug rpki % [BGP] Unknown command: debug rpki - + router(config)# rpki % [BGP] Unknown command: rpki - - Note that the rpki commands will be available in vtysh when running 'find rpki'. - Even if the RPKI module is NOT loaded. - The RPKI commands will be unavailable if you try running the same command in the - cli specific to the BGP daemon. + +Note that the RPKI commands will be available in vtysh when running +``find rpki`` regardless of whether the module is loaded. + +.. _configuring-rpki-rtr-cache-servers: Configuring RPKI/RTR Cache Servers ---------------------------------- diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 08606c2128..a9431b16e3 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -463,7 +463,7 @@ commands in relationship to VRF. Here is an extract of some of those commands: .. clicmd:: vrf VRF This command is available on configuration mode. By default, above command - permits accessing the vrf configuration mode. This mode is available for + permits accessing the VRF configuration mode. This mode is available for both VRFs. It is to be noted that *Zebra* does not create Linux VRF. The network administrator can however decide to provision this command in configuration file to provide more clarity about the intended configuration. @@ -493,7 +493,10 @@ commands in relationship to VRF. Here is an extract of some of those commands: This command is based on configuration mode. There, for default VRF, this command is available for all modes. The ``TABLENO`` configured is one of the - tables from Default *Linux network namespace*. + tables from Default *Linux network namespace*. This command is also available + on vrf configuration mode, provided that *Zebra* is run with :option:`-n` + option. In that case, this command configures a network route in the given + ``TABLENO`` of the *Linux network namespace* of the relevant VRF. .. index:: show ip route vrf VRF .. clicmd:: show ip route vrf VRF diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index c8ef829064..37651163f5 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -37,6 +37,7 @@ #include "checksum.h" #include "md5.h" #include "table.h" +#include "srcdest_table.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" @@ -765,18 +766,28 @@ static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, return; for (struct route_node *rn = route_top(er_table); rn; - rn = route_next(rn)) { + rn = srcdest_route_next(rn)) { if (!rn->info) continue; - - struct prefix_ipv6 *ipv6 = (struct prefix_ipv6 *)&rn->p; struct isis_ext_info *info = rn->info; + struct prefix_ipv6 *p, *src_p; + srcdest_rnode_prefixes(rn, (const struct prefix **)&p, + (const struct prefix **)&src_p); + uint32_t metric = info->metric; if (info->metric > MAX_WIDE_PATH_METRIC) metric = MAX_WIDE_PATH_METRIC; - isis_tlvs_add_ipv6_reach( - lsp->tlvs, isis_area_ipv6_topology(area), ipv6, metric); + + if (!src_p || !src_p->prefixlen) { + isis_tlvs_add_ipv6_reach(lsp->tlvs, + isis_area_ipv6_topology(area), + p, metric); + } else if (isis_area_ipv6_dstsrc_enabled(area)) { + isis_tlvs_add_ipv6_dstsrc_reach(lsp->tlvs, + ISIS_MT_IPV6_DSTSRC, + p, src_p, metric); + } } } diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index d13f2a13f3..2155bf584e 100644 --- a/isisd/isis_mt.c +++ b/isisd/isis_mt.c @@ -33,6 +33,14 @@ DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting") DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting") DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info") +bool isis_area_ipv6_dstsrc_enabled(struct isis_area *area) +{ + struct isis_area_mt_setting *area_mt_setting; + area_mt_setting = area_lookup_mt_setting(area, ISIS_MT_IPV6_DSTSRC); + + return (area_mt_setting && area_mt_setting->enabled); +} + uint16_t isis_area_ipv6_topology(struct isis_area *area) { struct isis_area_mt_setting *area_mt_setting; @@ -61,6 +69,8 @@ const char *isis_mtid2str(uint16_t mtid) return "ipv6-multicast"; case ISIS_MT_IPV6_MGMT: return "ipv6-mgmt"; + case ISIS_MT_IPV6_DSTSRC: + return "ipv6-dstsrc"; default: snprintf(buf, sizeof(buf), "%" PRIu16, mtid); return buf; @@ -81,6 +91,8 @@ uint16_t isis_str2mtid(const char *name) return ISIS_MT_IPV6_MULTICAST; if (!strcmp(name, "ipv6-mgmt")) return ISIS_MT_IPV6_MGMT; + if (!strcmp(name, "ipv6-dstsrc")) + return ISIS_MT_IPV6_DSTSRC; return -1; } diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h index 95aa99dba0..8c57d24afa 100644 --- a/isisd/isis_mt.h +++ b/isisd/isis_mt.h @@ -32,6 +32,7 @@ #define ISIS_MT_IPV4_MULTICAST 3 #define ISIS_MT_IPV6_MULTICAST 4 #define ISIS_MT_IPV6_MGMT 5 +#define ISIS_MT_IPV6_DSTSRC 3996 /* FIXME: IANA */ #define ISIS_MT_NAMES \ "<ipv4-unicast" \ @@ -40,6 +41,7 @@ "|ipv4-multicast" \ "|ipv6-multicast" \ "|ipv6-mgmt" \ + "|ipv6-dstsrc" \ ">" #define ISIS_MT_DESCRIPTIONS \ @@ -48,7 +50,9 @@ "IPv6 unicast topology\n" \ "IPv4 multicast topology\n" \ "IPv6 multicast topology\n" \ - "IPv6 management topology\n" + "IPv6 management topology\n" \ + "IPv6 dst-src topology\n" \ + "" #define ISIS_MT_INFO_FIELDS uint16_t mtid; @@ -75,6 +79,8 @@ struct tlvs; struct te_is_neigh; struct isis_tlvs; +bool isis_area_ipv6_dstsrc_enabled(struct isis_area *area); + uint16_t isis_area_ipv6_topology(struct isis_area *area); struct isis_area_mt_setting *area_lookup_mt_setting(struct isis_area *area, diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 7a6c4dd2dc..8e2a7f13a5 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -673,8 +673,15 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, iih.v6_usable = (circuit->ipv6_link && listcount(circuit->ipv6_link) && iih.tlvs->ipv6_address.count); - if (!iih.v4_usable && !iih.v6_usable) + if (!iih.v4_usable && !iih.v6_usable) { + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_warn( + "ISIS-Adj (%s): Neither IPv4 nor IPv6 considered usable. Ignoring IIH", + circuit->area->area_tag); + } + goto out; + } retval = p2p_hello ? process_p2p_hello(&iih) : process_lan_hello(&iih); out: diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c index e903dc8c7f..cd3ca44379 100644 --- a/isisd/isis_redist.c +++ b/isisd/isis_redist.c @@ -30,6 +30,7 @@ #include "stream.h" #include "table.h" #include "vty.h" +#include "srcdest_table.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" @@ -86,33 +87,13 @@ struct route_table *get_ext_reach(struct isis_area *area, int family, int level) return area->ext_reach[protocol][level - 1]; } -static struct route_node * -isis_redist_route_node_create(route_table_delegate_t *delegate, - struct route_table *table) -{ - struct route_node *node; - node = XCALLOC(MTYPE_ISIS_EXT_ROUTE, sizeof(*node)); - return node; -} - -static void isis_redist_route_node_destroy(route_table_delegate_t *delegate, - struct route_table *table, - struct route_node *node) -{ - if (node->info) - XFREE(MTYPE_ISIS_EXT_INFO, node->info); - XFREE(MTYPE_ISIS_EXT_ROUTE, node); -} - -static route_table_delegate_t isis_redist_rt_delegate = { - .create_node = isis_redist_route_node_create, - .destroy_node = isis_redist_route_node_destroy}; - /* Install external reachability information into a * specific area for a specific level. * Schedule an lsp regenerate if necessary */ static void isis_redist_install(struct isis_area *area, int level, - struct prefix *p, struct isis_ext_info *info) + const struct prefix *p, + const struct prefix_ipv6 *src_p, + struct isis_ext_info *info) { int family = p->family; struct route_table *er_table = get_ext_reach(area, family, level); @@ -126,7 +107,7 @@ static void isis_redist_install(struct isis_area *area, int level, return; } - er_node = route_node_get(er_table, p); + er_node = srcdest_rnode_get(er_table, p, src_p); if (er_node->info) { route_unlock_node(er_node); @@ -145,7 +126,8 @@ static void isis_redist_install(struct isis_area *area, int level, * specific area for a specific level. * Schedule an lsp regenerate if necessary. */ static void isis_redist_uninstall(struct isis_area *area, int level, - struct prefix *p) + const struct prefix *p, + const struct prefix_ipv6 *src_p) { int family = p->family; struct route_table *er_table = get_ext_reach(area, family, level); @@ -159,7 +141,7 @@ static void isis_redist_uninstall(struct isis_area *area, int level, return; } - er_node = route_node_lookup(er_table, p); + er_node = srcdest_rnode_lookup(er_table, p, src_p); if (!er_node) return; else @@ -177,7 +159,8 @@ static void isis_redist_uninstall(struct isis_area *area, int level, * and prefix, using the given redistribution settings. */ static void isis_redist_update_ext_reach(struct isis_area *area, int level, struct isis_redist *redist, - struct prefix *p, + const struct prefix *p, + const struct prefix_ipv6 *src_p, struct isis_ext_info *info) { struct isis_ext_info area_info; @@ -188,7 +171,8 @@ static void isis_redist_update_ext_reach(struct isis_area *area, int level, if (redist->map_name) { map_ret = - route_map_apply(redist->map, p, RMAP_ISIS, &area_info); + route_map_apply(redist->map, (struct prefix *)p, + RMAP_ISIS, &area_info); if (map_ret == RMAP_DENYMATCH) area_info.distance = 255; } @@ -199,9 +183,9 @@ static void isis_redist_update_ext_reach(struct isis_area *area, int level, area_info.distance = 255; if (area_info.distance < 255) - isis_redist_install(area, level, p, &area_info); + isis_redist_install(area, level, p, src_p, &area_info); else - isis_redist_uninstall(area, level, p); + isis_redist_uninstall(area, level, p, src_p); } static void isis_redist_ensure_default(struct isis *isis, int family) @@ -222,7 +206,7 @@ static void isis_redist_ensure_default(struct isis *isis, int family) } else assert(!"Unknown family!"); - ei_node = route_node_get(ei_table, &p); + ei_node = srcdest_rnode_get(ei_table, &p, NULL); if (ei_node->info) { route_unlock_node(ei_node); return; @@ -238,8 +222,8 @@ static void isis_redist_ensure_default(struct isis *isis, int family) } /* Handle notification about route being added */ -void isis_redist_add(int type, struct prefix *p, uint8_t distance, - uint32_t metric) +void isis_redist_add(int type, struct prefix *p, struct prefix_ipv6 *src_p, + uint8_t distance, uint32_t metric) { int family = p->family; struct route_table *ei_table = get_ext_info(isis, family); @@ -262,7 +246,7 @@ void isis_redist_add(int type, struct prefix *p, uint8_t distance, return; } - ei_node = route_node_get(ei_table, p); + ei_node = srcdest_rnode_get(ei_table, p, src_p); if (ei_node->info) route_unlock_node(ei_node); else @@ -274,8 +258,10 @@ void isis_redist_add(int type, struct prefix *p, uint8_t distance, info->distance = distance; info->metric = metric; - if (is_default_prefix(p)) + if (is_default_prefix(p) + && (!src_p || !src_p->prefixlen)) { type = DEFAULT_ROUTE; + } for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) for (level = 1; level <= ISIS_LEVELS; level++) { @@ -284,11 +270,11 @@ void isis_redist_add(int type, struct prefix *p, uint8_t distance, continue; isis_redist_update_ext_reach(area, level, redist, p, - info); + src_p, info); } } -void isis_redist_delete(int type, struct prefix *p) +void isis_redist_delete(int type, struct prefix *p, struct prefix_ipv6 *src_p) { int family = p->family; struct route_table *ei_table = get_ext_info(isis, family); @@ -304,12 +290,14 @@ void isis_redist_delete(int type, struct prefix *p) zlog_debug("%s: Removing route %s from %s.", __func__, debug_buf, zebra_route_string(type)); - if (is_default_prefix(p)) { + if (is_default_prefix(p) + && (!src_p || !src_p->prefixlen)) { /* Don't remove default route but add synthetic route for use * by "default-information originate always". Areas without the * "always" setting will ignore routes with origin * DEFAULT_ROUTE. */ - isis_redist_add(DEFAULT_ROUTE, p, 254, MAX_WIDE_PATH_METRIC); + isis_redist_add(DEFAULT_ROUTE, p, NULL, + 254, MAX_WIDE_PATH_METRIC); return; } @@ -319,7 +307,7 @@ void isis_redist_delete(int type, struct prefix *p) return; } - ei_node = route_node_lookup(ei_table, p); + ei_node = srcdest_rnode_lookup(ei_table, p, src_p); if (!ei_node || !ei_node->info) { char buf[BUFSIZ]; prefix2str(p, buf, sizeof(buf)); @@ -334,12 +322,12 @@ void isis_redist_delete(int type, struct prefix *p) route_unlock_node(ei_node); for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) - for (level = 1; level < ISIS_LEVELS; level++) { + for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { redist = get_redist_settings(area, family, type, level); if (!redist->redist) continue; - isis_redist_uninstall(area, level, p); + isis_redist_uninstall(area, level, p, src_p); } XFREE(MTYPE_ISIS_EXT_INFO, ei_node->info); @@ -418,17 +406,14 @@ static void isis_redist_set(struct isis_area *area, int level, int family, isis_redist_routemap_set(redist, routemap); if (!area->ext_reach[protocol][level - 1]) { - area->ext_reach[protocol][level - 1] = - route_table_init_with_delegate( - &isis_redist_rt_delegate); + area->ext_reach[protocol][level - 1] = srcdest_table_init(); } - for (i = 0; i < REDIST_PROTOCOL_COUNT; i++) + for (i = 0; i < REDIST_PROTOCOL_COUNT; i++) { if (!area->isis->ext_info[i]) { - area->isis->ext_info[i] = - route_table_init_with_delegate( - &isis_redist_rt_delegate); + area->isis->ext_info[i] = srcdest_table_init(); } + } isis_redist_update_zebra_subscriptions(area->isis); @@ -436,20 +421,27 @@ static void isis_redist_set(struct isis_area *area, int level, int family, isis_redist_ensure_default(area->isis, family); ei_table = get_ext_info(area->isis, family); - for (rn = route_top(ei_table); rn; rn = route_next(rn)) { + for (rn = route_top(ei_table); rn; rn = srcdest_route_next(rn)) { if (!rn->info) continue; info = rn->info; + const struct prefix *p, *src_p; + + srcdest_rnode_prefixes(rn, &p, &src_p); + if (type == DEFAULT_ROUTE) { - if (!is_default_prefix(&rn->p)) + if (!is_default_prefix(p) + || (src_p && src_p->prefixlen)) { continue; + } } else { if (info->origin != type) continue; } - isis_redist_update_ext_reach(area, level, redist, &rn->p, info); + isis_redist_update_ext_reach(area, level, redist, p, + (struct prefix_ipv6 *)src_p, info); } } @@ -472,14 +464,19 @@ static void isis_redist_unset(struct isis_area *area, int level, int family, return; } - for (rn = route_top(er_table); rn; rn = route_next(rn)) { + for (rn = route_top(er_table); rn; rn = srcdest_route_next(rn)) { if (!rn->info) continue; info = rn->info; + const struct prefix *p, *src_p; + srcdest_rnode_prefixes(rn, &p, &src_p); + if (type == DEFAULT_ROUTE) { - if (!is_default_prefix(&rn->p)) + if (!is_default_prefix(p) + || (src_p && src_p->prefixlen)) { continue; + } } else { if (info->origin != type) continue; diff --git a/isisd/isis_redist.h b/isisd/isis_redist.h index c12363d508..95f06f71ec 100644 --- a/isisd/isis_redist.h +++ b/isisd/isis_redist.h @@ -42,13 +42,14 @@ struct isis_redist { struct isis_area; struct prefix; +struct prefix_ipv6; struct vty; struct route_table *get_ext_reach(struct isis_area *area, int family, int level); -void isis_redist_add(int type, struct prefix *p, uint8_t distance, - uint32_t metric); -void isis_redist_delete(int type, struct prefix *p); +void isis_redist_add(int type, struct prefix *p, struct prefix_ipv6 *src_p, + uint8_t distance, uint32_t metric); +void isis_redist_delete(int type, struct prefix *p, struct prefix_ipv6 *src_p); int isis_redist_config_write(struct vty *vty, struct isis_area *area, int family); void isis_redist_init(void); diff --git a/isisd/isis_route.c b/isisd/isis_route.c index c98e16e2bd..b1225ae547 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -33,6 +33,7 @@ #include "hash.h" #include "if.h" #include "table.h" +#include "srcdest_table.h" #include "isis_constants.h" #include "isis_common.h" @@ -199,6 +200,7 @@ static void adjinfo2nexthop6(struct list *nexthops6, struct isis_adjacency *adj) } static struct isis_route_info *isis_route_info_new(struct prefix *prefix, + struct prefix_ipv6 *src_p, uint32_t cost, uint32_t depth, struct list *adjacencies) @@ -232,8 +234,10 @@ static struct isis_route_info *isis_route_info_new(struct prefix *prefix, SET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); /* update neighbor router address */ - if (depth == 2 && prefix->prefixlen == 128) + if (depth == 2 && prefix->prefixlen == 128 + && (!src_p || !src_p->prefixlen)) { adj->router_address6 = prefix->u.prefix6; + } adjinfo2nexthop6(rinfo->nexthops6, adj); } } @@ -317,10 +321,13 @@ static int isis_route_info_same(struct isis_route_info *new, return 1; } -struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost, +struct isis_route_info *isis_route_create(struct prefix *prefix, + struct prefix_ipv6 *src_p, + uint32_t cost, uint32_t depth, struct list *adjacencies, - struct isis_area *area, int level) + struct isis_area *area, + struct route_table *table) { struct route_node *route_node; struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL; @@ -331,18 +338,12 @@ struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost, /* for debugs */ prefix2str(prefix, buff, sizeof(buff)); - rinfo_new = isis_route_info_new(prefix, cost, depth, adjacencies); - - if (family == AF_INET) - route_node = - route_node_get(area->route_table[level - 1], prefix); - else if (family == AF_INET6) - route_node = - route_node_get(area->route_table6[level - 1], prefix); - else { - isis_route_info_delete(rinfo_new); + if (!table) return NULL; - } + + rinfo_new = isis_route_info_new(prefix, src_p, cost, + depth, adjacencies); + route_node = srcdest_rnode_get(table, prefix, src_p); rinfo_old = route_node->info; if (!rinfo_old) { @@ -352,6 +353,7 @@ struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost, route_info = rinfo_new; UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); } else { + route_unlock_node(route_node); if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug("ISIS-Rte (%s) route already exists: %s", area->area_tag, buff); @@ -378,19 +380,21 @@ struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost, return route_info; } -static void isis_route_delete(struct prefix *prefix, struct route_table *table) +static void isis_route_delete(struct route_node *rode, + struct route_table *table) { - struct route_node *rode; struct isis_route_info *rinfo; - char buff[PREFIX2STR_BUFFER]; + char buff[SRCDEST2STR_BUFFER]; + struct prefix *prefix; + struct prefix_ipv6 *src_p; /* for log */ - prefix2str(prefix, buff, sizeof(buff)); + srcdest_rnode2str(rode, buff, sizeof(buff)); + srcdest_rnode_prefixes(rode, (const struct prefix **)&prefix, + (const struct prefix **)&src_p); - rode = route_node_get(table, prefix); rinfo = rode->info; - if (rinfo == NULL) { if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug( @@ -403,29 +407,36 @@ static void isis_route_delete(struct prefix *prefix, struct route_table *table) UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE); if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug("ISIS-Rte: route delete %s", buff); - isis_zebra_route_update(prefix, rinfo); + isis_zebra_route_update(prefix, src_p, rinfo); } isis_route_info_delete(rinfo); rode->info = NULL; - - return; + route_unlock_node(rode); } -/* Validating routes in particular table. */ -static void isis_route_validate_table(struct isis_area *area, - struct route_table *table) +static void _isis_route_verify_table(struct isis_area *area, + struct route_table *table, + struct route_table **tables) { struct route_node *rnode, *drnode; struct isis_route_info *rinfo; - char buff[PREFIX2STR_BUFFER]; + char buff[SRCDEST2STR_BUFFER]; - for (rnode = route_top(table); rnode; rnode = route_next(rnode)) { + for (rnode = route_top(table); rnode; + rnode = srcdest_route_next(rnode)) { if (rnode->info == NULL) continue; rinfo = rnode->info; + struct prefix *dst_p; + struct prefix_ipv6 *src_p; + + srcdest_rnode_prefixes(rnode, + (const struct prefix **)&dst_p, + (const struct prefix **)&src_p); + if (isis->debugs & DEBUG_RTE_EVENTS) { - prefix2str(&rnode->p, buff, sizeof(buff)); + srcdest2str(dst_p, src_p, buff, sizeof(buff)); zlog_debug( "ISIS-Rte (%s): route validate: %s %s %s %s", area->area_tag, @@ -443,50 +454,47 @@ static void isis_route_validate_table(struct isis_area *area, buff); } - isis_zebra_route_update(&rnode->p, rinfo); - if (!CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)) { - /* Area is either L1 or L2 => we use level route tables - * directly for - * validating => no problems with deleting routes. */ - if (area->is_type != IS_LEVEL_1_AND_2) { - isis_route_delete(&rnode->p, table); + isis_zebra_route_update(dst_p, src_p, rinfo); + + if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)) + continue; + + /* Area is either L1 or L2 => we use level route tables + * directly for + * validating => no problems with deleting routes. */ + if (!tables) { + isis_route_delete(rnode, table); + continue; + } + + /* If area is L1L2, we work with merge table and + * therefore must + * delete node from level tables as well before deleting + * route info. */ + for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { + drnode = srcdest_rnode_lookup(tables[level - 1], + dst_p, src_p); + if (!drnode) continue; - } - /* If area is L1L2, we work with merge table and - * therefore must - * delete node from level tables as well before deleting - * route info. - * FIXME: Is it performance problem? There has to be the - * better way. - * Like not to deal with it here at all (see the next - * comment)? */ - if (rnode->p.family == AF_INET) { - drnode = route_node_get(area->route_table[0], - &rnode->p); - if (drnode->info == rnode->info) - drnode->info = NULL; - drnode = route_node_get(area->route_table[1], - &rnode->p); - if (drnode->info == rnode->info) - drnode->info = NULL; - } - if (rnode->p.family == AF_INET6) { - drnode = route_node_get(area->route_table6[0], - &rnode->p); - if (drnode->info == rnode->info) - drnode->info = NULL; - drnode = route_node_get(area->route_table6[1], - &rnode->p); - if (drnode->info == rnode->info) - drnode->info = NULL; - } + route_unlock_node(drnode); + + if (drnode->info != rnode->info) + continue; - isis_route_delete(&rnode->p, table); + drnode->info = NULL; + route_unlock_node(drnode); } + + isis_route_delete(rnode, table); } } +void isis_route_verify_table(struct isis_area *area, struct route_table *table) +{ + return _isis_route_verify_table(area, table, NULL); +} + /* Function to validate route tables for L1L2 areas. In this case we can't use * level route tables directly, we have to merge them at first. L1 routes are * preferred over the L2 ones. @@ -497,87 +505,71 @@ static void isis_route_validate_table(struct isis_area *area, * * FIXME: Is it right place to do it at all? Maybe we should push both levels * to the RIB with different zebra route types and let RIB handle this? */ -static void isis_route_validate_merge(struct isis_area *area, int family) +void isis_route_verify_merge(struct isis_area *area, + struct route_table *level1_table, + struct route_table *level2_table) { - struct route_table *table = NULL; + struct route_table *tables[] = { level1_table, level2_table }; struct route_table *merge; struct route_node *rnode, *mrnode; - merge = route_table_init(); + merge = srcdest_table_init(); - if (family == AF_INET) - table = area->route_table[0]; - else if (family == AF_INET6) - table = area->route_table6[0]; - else { - zlog_warn("ISIS-Rte (%s) %s called for unknown family %d", - area->area_tag, __func__, family); - route_table_finish(merge); - return; - } - - for (rnode = route_top(table); rnode; rnode = route_next(rnode)) { - if (rnode->info == NULL) - continue; - mrnode = route_node_get(merge, &rnode->p); - mrnode->info = rnode->info; - } - - if (family == AF_INET) - table = area->route_table[1]; - else if (family == AF_INET6) - table = area->route_table6[1]; + for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { + for (rnode = route_top(tables[level - 1]); rnode; + rnode = srcdest_route_next(rnode)) { + struct isis_route_info *rinfo = rnode->info; + if (!rinfo) + continue; - for (rnode = route_top(table); rnode; rnode = route_next(rnode)) { - if (rnode->info == NULL) - continue; - mrnode = route_node_get(merge, &rnode->p); - if (mrnode->info != NULL) - continue; - mrnode->info = rnode->info; + struct prefix *prefix; + struct prefix_ipv6 *src_p; + + srcdest_rnode_prefixes(rnode, + (const struct prefix **)&prefix, + (const struct prefix **)&src_p); + mrnode = srcdest_rnode_get(merge, prefix, src_p); + struct isis_route_info *mrinfo = mrnode->info; + if (mrinfo) { + route_unlock_node(mrnode); + if (CHECK_FLAG(mrinfo->flag, + ISIS_ROUTE_FLAG_ACTIVE)) { + /* Clear the ZEBRA_SYNCED flag on the + * L2 route when L1 wins, otherwise L2 + * won't get reinstalled when L1 + * disappears. + */ + UNSET_FLAG( + rinfo->flag, + ISIS_ROUTE_FLAG_ZEBRA_SYNCED + ); + continue; + } else { + /* Clear the ZEBRA_SYNCED flag on the L1 + * route when L2 wins, otherwise L1 + * won't get reinstalled when it + * reappears. + */ + UNSET_FLAG( + mrinfo->flag, + ISIS_ROUTE_FLAG_ZEBRA_SYNCED + ); + } + } + mrnode->info = rnode->info; + } } - isis_route_validate_table(area, merge); + _isis_route_verify_table(area, merge, tables); route_table_finish(merge); } -/* Walk through route tables and propagate necessary changes into RIB. In case - * of L1L2 area, level tables have to be merged at first. */ -void isis_route_validate(struct isis_area *area) -{ - struct listnode *node; - struct isis_circuit *circuit; - - if (area->is_type == IS_LEVEL_1) - isis_route_validate_table(area, area->route_table[0]); - else if (area->is_type == IS_LEVEL_2) - isis_route_validate_table(area, area->route_table[1]); - else - isis_route_validate_merge(area, AF_INET); - - if (area->is_type == IS_LEVEL_1) - isis_route_validate_table(area, area->route_table6[0]); - else if (area->is_type == IS_LEVEL_2) - isis_route_validate_table(area, area->route_table6[1]); - else - isis_route_validate_merge(area, AF_INET6); - - if (!area->circuit_list) { - return; - } - /* walk all circuits and reset any spf specific flags */ - for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) - UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); - - return; -} - void isis_route_invalidate_table(struct isis_area *area, struct route_table *table) { struct route_node *rode; struct isis_route_info *rinfo; - for (rode = route_top(table); rode; rode = route_next(rode)) { + for (rode = route_top(table); rode; rode = srcdest_route_next(rode)) { if (rode->info == NULL) continue; rinfo = rode->info; @@ -585,11 +577,3 @@ void isis_route_invalidate_table(struct isis_area *area, UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE); } } - -void isis_route_invalidate(struct isis_area *area) -{ - if (area->is_type & IS_LEVEL_1) - isis_route_invalidate_table(area, area->route_table[0]); - if (area->is_type & IS_LEVEL_2) - isis_route_invalidate_table(area, area->route_table[1]); -} diff --git a/isisd/isis_route.h b/isisd/isis_route.h index 82f37c29f2..9d6858586b 100644 --- a/isisd/isis_route.h +++ b/isisd/isis_route.h @@ -50,14 +50,26 @@ struct isis_route_info { struct list *nexthops6; }; -struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost, +struct isis_route_info *isis_route_create(struct prefix *prefix, + struct prefix_ipv6 *src_p, + uint32_t cost, uint32_t depth, struct list *adjacencies, - struct isis_area *area, int level); + struct isis_area *area, + struct route_table *table); -void isis_route_validate(struct isis_area *area); +/* Walk the given table and install new routes to zebra and remove old ones. + * route status is tracked using ISIS_ROUTE_FLAG_ACTIVE */ +void isis_route_verify_table(struct isis_area *area, + struct route_table *table); + +/* Same as isis_route_verify_table, but merge L1 and L2 routes before */ +void isis_route_verify_merge(struct isis_area *area, + struct route_table *level1_table, + struct route_table *level2_table); + +/* Unset ISIS_ROUTE_FLAG_ACTIVE on all routes. Used before running spf. */ void isis_route_invalidate_table(struct isis_area *area, struct route_table *table); -void isis_route_invalidate(struct isis_area *area); #endif /* _ZEBRA_ISIS_ROUTE_H */ diff --git a/isisd/isis_routemap.c b/isisd/isis_routemap.c index d92207d57c..3c2cf7b3fc 100644 --- a/isisd/isis_routemap.c +++ b/isisd/isis_routemap.c @@ -50,7 +50,7 @@ #include "isis_routemap.h" static route_map_result_t route_match_ip_address(void *rule, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -83,7 +83,7 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = { /* ------------------------------------------------------------*/ static route_map_result_t -route_match_ip_address_prefix_list(void *rule, struct prefix *prefix, +route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; @@ -116,7 +116,7 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { /* ------------------------------------------------------------*/ static route_map_result_t route_match_ipv6_address(void *rule, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -149,7 +149,7 @@ static struct route_map_rule_cmd route_match_ipv6_address_cmd = { /* ------------------------------------------------------------*/ static route_map_result_t -route_match_ipv6_address_prefix_list(void *rule, struct prefix *prefix, +route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; @@ -181,7 +181,8 @@ struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = { /* ------------------------------------------------------------*/ -static route_map_result_t route_set_metric(void *rule, struct prefix *prefix, +static route_map_result_t route_set_metric(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 556f2890cf..0a8b0e927e 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -37,6 +37,7 @@ #include "spf_backoff.h" #include "jhash.h" #include "skiplist.h" +#include "srcdest_table.h" #include "isis_constants.h" #include "isis_common.h" @@ -74,12 +75,17 @@ enum vertextype { #define VTYPE_ES(t) ((t) == VTYPE_ES) #define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL) +struct prefix_pair { + struct prefix dest; + struct prefix_ipv6 src; +}; + /* * Triple <N, d(N), {Adj(N)}> */ union isis_N { uint8_t id[ISIS_SYS_ID_LEN + 1]; - struct prefix prefix; + struct prefix_pair ip; }; struct isis_vertex { enum vertextype type; @@ -106,8 +112,13 @@ static unsigned isis_vertex_queue_hash_key(void *vp) { struct isis_vertex *vertex = vp; - if (VTYPE_IP(vertex->type)) - return prefix_hash_key(&vertex->N.prefix); + if (VTYPE_IP(vertex->type)) { + uint32_t key; + + key = prefix_hash_key(&vertex->N.ip.dest); + key = jhash_1word(prefix_hash_key(&vertex->N.ip.src), key); + return key; + } return jhash(vertex->N.id, ISIS_SYS_ID_LEN + 1, 0x55aa5a5a); } @@ -119,8 +130,13 @@ static int isis_vertex_queue_hash_cmp(const void *a, const void *b) if (va->type != vb->type) return 0; - if (VTYPE_IP(va->type)) - return prefix_cmp(&va->N.prefix, &vb->N.prefix) == 0; + if (VTYPE_IP(va->type)) { + if (prefix_cmp(&va->N.ip.dest, &vb->N.ip.dest)) + return 0; + + return prefix_cmp((struct prefix *)&va->N.ip.src, + (struct prefix *)&vb->N.ip.src) == 0; + } return memcmp(va->N.id, vb->N.id, ISIS_SYS_ID_LEN + 1) == 0; } @@ -275,6 +291,7 @@ static void isis_vertex_queue_delete(struct isis_vertex_queue *queue, struct isis_spftree { struct isis_vertex_queue paths; /* the SPT */ struct isis_vertex_queue tents; /* TENT */ + struct route_table *route_table; struct isis_area *area; /* back pointer to area */ unsigned int runcount; /* number of runs since uptime */ time_t last_run_timestamp; /* last run timestamp as wall time for display */ @@ -284,6 +301,7 @@ struct isis_spftree { uint16_t mtid; int family; int level; + enum spf_tree_id tree_id; }; @@ -392,6 +410,7 @@ static const char *vtype2string(enum vertextype vtype) return NULL; /* Not reached */ } +#define VID2STR_BUFFER SRCDEST2STR_BUFFER static const char *vid2string(struct isis_vertex *vertex, char *buff, int size) { if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type)) { @@ -399,7 +418,9 @@ static const char *vid2string(struct isis_vertex *vertex, char *buff, int size) } if (VTYPE_IP(vertex->type)) { - prefix2str((struct prefix *)&vertex->N.prefix, buff, size); + srcdest2str(&vertex->N.ip.dest, + &vertex->N.ip.src, + buff, size); return buff; } @@ -414,7 +435,7 @@ static void isis_vertex_id_init(struct isis_vertex *vertex, union isis_N *n, if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) { memcpy(vertex->N.id, n->id, ISIS_SYS_ID_LEN + 1); } else if (VTYPE_IP(vtype)) { - memcpy(&vertex->N.prefix, &n->prefix, sizeof(struct prefix)); + memcpy(&vertex->N.ip, &n->ip, sizeof(n->ip)); } else { zlog_err("WTF!"); } @@ -472,6 +493,7 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area) isis_vertex_queue_init(&tree->tents, "IS-IS SPF tents", true); isis_vertex_queue_init(&tree->paths, "IS-IS SPF paths", false); + tree->route_table = srcdest_table_init(); tree->area = area; tree->last_run_timestamp = 0; tree->last_run_monotime = 0; @@ -484,8 +506,10 @@ void isis_spftree_del(struct isis_spftree *spftree) { isis_vertex_queue_free(&spftree->tents); isis_vertex_queue_free(&spftree->paths); - XFREE(MTYPE_ISIS_SPFTREE, spftree); + route_table_finish(spftree->route_table); + spftree->route_table = NULL; + XFREE(MTYPE_ISIS_SPFTREE, spftree); return; } @@ -504,67 +528,44 @@ static void isis_spftree_adj_del(struct isis_spftree *spftree, void spftree_area_init(struct isis_area *area) { - if (area->is_type & IS_LEVEL_1) { - if (area->spftree[0] == NULL) - area->spftree[0] = isis_spftree_new(area); - if (area->spftree6[0] == NULL) - area->spftree6[0] = isis_spftree_new(area); - } + for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) { + for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { + if (!(area->is_type & level)) + continue; + if (area->spftree[tree][level - 1]) + continue; - if (area->is_type & IS_LEVEL_2) { - if (area->spftree[1] == NULL) - area->spftree[1] = isis_spftree_new(area); - if (area->spftree6[1] == NULL) - area->spftree6[1] = isis_spftree_new(area); + area->spftree[tree][level - 1] = isis_spftree_new(area); + } } - - return; } void spftree_area_del(struct isis_area *area) { - if (area->is_type & IS_LEVEL_1) { - if (area->spftree[0] != NULL) { - isis_spftree_del(area->spftree[0]); - area->spftree[0] = NULL; - } - if (area->spftree6[0]) { - isis_spftree_del(area->spftree6[0]); - area->spftree6[0] = NULL; - } - } + for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) { + for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { + if (!(area->is_type & level)) + continue; + if (!area->spftree[tree][level - 1]) + continue; - if (area->is_type & IS_LEVEL_2) { - if (area->spftree[1] != NULL) { - isis_spftree_del(area->spftree[1]); - area->spftree[1] = NULL; - } - if (area->spftree6[1] != NULL) { - isis_spftree_del(area->spftree6[1]); - area->spftree6[1] = NULL; + isis_spftree_del(area->spftree[tree][level - 1]); } } - - return; } void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj) { - if (area->is_type & IS_LEVEL_1) { - if (area->spftree[0] != NULL) - isis_spftree_adj_del(area->spftree[0], adj); - if (area->spftree6[0] != NULL) - isis_spftree_adj_del(area->spftree6[0], adj); - } - - if (area->is_type & IS_LEVEL_2) { - if (area->spftree[1] != NULL) - isis_spftree_adj_del(area->spftree[1], adj); - if (area->spftree6[1] != NULL) - isis_spftree_adj_del(area->spftree6[1], adj); + for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) { + for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { + if (!(area->is_type & level)) + continue; + if (!area->spftree[tree][level - 1]) + continue; + isis_spftree_adj_del(area->spftree[tree][level - 1], + adj); + } } - - return; } /* @@ -595,7 +596,7 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree, struct isis_vertex *vertex; struct isis_lsp *lsp; #ifdef EXTREME_DEBUG - char buff[PREFIX2STR_BUFFER]; + char buff[VID2STR_BUFFER]; #endif /* EXTREME_DEBUG */ union isis_N n; @@ -646,7 +647,7 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree, struct listnode *node; struct isis_adjacency *parent_adj; #ifdef EXTREME_DEBUG - char buff[PREFIX2STR_BUFFER]; + char buff[VID2STR_BUFFER]; #endif assert(isis_find_vertex(&spftree->paths, id, vtype) == NULL); @@ -719,15 +720,16 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype, { struct isis_vertex *vertex; #ifdef EXTREME_DEBUG - char buff[PREFIX2STR_BUFFER]; + char buff[VID2STR_BUFFER]; #endif assert(spftree && parent); - struct prefix p; + struct prefix_pair p; if (vtype >= VTYPE_IPREACH_INTERNAL) { - prefix_copy(&p, id); - apply_mask(&p); + memcpy(&p, id, sizeof(p)); + apply_mask(&p.dest); + apply_mask((struct prefix *)&p.src); id = &p; } @@ -814,6 +816,7 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree, enum vertextype vtype; static const uint8_t null_sysid[ISIS_SYS_ID_LEN]; struct isis_mt_router_info *mt_router_info = NULL; + struct prefix_pair ip_info; if (!lsp->tlvs) return ISIS_OK; @@ -907,12 +910,17 @@ lspfragloop: vtype = i ? VTYPE_IPREACH_EXTERNAL : VTYPE_IPREACH_INTERNAL; + memset(&ip_info, 0, sizeof(ip_info)); + ip_info.dest.family = AF_INET; + struct isis_oldstyle_ip_reach *r; for (r = (struct isis_oldstyle_ip_reach *)reachs[i] ->head; r; r = r->next) { dist = cost + r->metric; - process_N(spftree, vtype, (void *)&r->prefix, + ip_info.dest.u.prefix4 = r->prefix.prefix; + ip_info.dest.prefixlen = r->prefix.prefixlen; + process_N(spftree, vtype, &ip_info, dist, depth + 1, parent); } } @@ -926,6 +934,9 @@ lspfragloop: ipv4_reachs = isis_lookup_mt_items( &lsp->tlvs->mt_ip_reach, spftree->mtid); + memset(&ip_info, 0, sizeof(ip_info)); + ip_info.dest.family = AF_INET; + struct isis_extended_ip_reach *r; for (r = ipv4_reachs ? (struct isis_extended_ip_reach *) @@ -933,7 +944,9 @@ lspfragloop: : NULL; r; r = r->next) { dist = cost + r->metric; - process_N(spftree, VTYPE_IPREACH_TE, (void *)&r->prefix, + ip_info.dest.u.prefix4 = r->prefix.prefix; + ip_info.dest.prefixlen = r->prefix.prefixlen; + process_N(spftree, VTYPE_IPREACH_TE, &ip_info, dist, depth + 1, parent); } } @@ -954,7 +967,28 @@ lspfragloop: dist = cost + r->metric; vtype = r->external ? VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL; - process_N(spftree, vtype, (void *)&r->prefix, dist, + memset(&ip_info, 0, sizeof(ip_info)); + ip_info.dest.family = AF_INET6; + ip_info.dest.u.prefix6 = r->prefix.prefix; + ip_info.dest.prefixlen = r->prefix.prefixlen; + + if (r->subtlvs + && r->subtlvs->source_prefix + && r->subtlvs->source_prefix->prefixlen) { + if (spftree->tree_id != SPFTREE_DSTSRC) { + char buff[VID2STR_BUFFER]; + zlog_warn("Ignoring dest-src route %s in non dest-src topology", + srcdest2str( + &ip_info.dest, + r->subtlvs->source_prefix, + buff, sizeof(buff) + ) + ); + continue; + } + ip_info.src = *r->subtlvs->source_prefix; + } + process_N(spftree, vtype, &ip_info, dist, depth + 1, parent); } } @@ -983,7 +1017,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree, struct list *adj_list; struct list *adjdb; struct prefix_ipv4 *ipv4; - struct prefix prefix; + struct prefix_pair ip_info; int retval = ISIS_OK; uint8_t lsp_id[ISIS_SYS_ID_LEN + 2]; static uint8_t null_lsp_id[ISIS_SYS_ID_LEN + 2]; @@ -1007,27 +1041,29 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree, * Add IP(v6) addresses of this circuit */ if (spftree->family == AF_INET) { - prefix.family = AF_INET; + memset(&ip_info, 0, sizeof(ip_info)); + ip_info.dest.family = AF_INET; for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode, ipv4)) { - prefix.u.prefix4 = ipv4->prefix; - prefix.prefixlen = ipv4->prefixlen; - apply_mask(&prefix); + ip_info.dest.u.prefix4 = ipv4->prefix; + ip_info.dest.prefixlen = ipv4->prefixlen; + apply_mask(&ip_info.dest); isis_spf_add_local(spftree, VTYPE_IPREACH_INTERNAL, - &prefix, NULL, 0, parent); + &ip_info, NULL, 0, parent); } } if (spftree->family == AF_INET6) { - prefix.family = AF_INET6; + memset(&ip_info, 0, sizeof(ip_info)); + ip_info.dest.family = AF_INET6; for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, ipnode, ipv6)) { - prefix.prefixlen = ipv6->prefixlen; - prefix.u.prefix6 = ipv6->prefix; - apply_mask(&prefix); + ip_info.dest.u.prefix6 = ipv6->prefix; + ip_info.dest.prefixlen = ipv6->prefixlen; + apply_mask(&ip_info.dest); isis_spf_add_local(spftree, VTYPE_IP6REACH_INTERNAL, - &prefix, NULL, 0, parent); + &ip_info, NULL, 0, parent); } } if (circuit->circ_type == CIRCUIT_T_BROADCAST) { @@ -1210,7 +1246,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree, static void add_to_paths(struct isis_spftree *spftree, struct isis_vertex *vertex) { - char buff[PREFIX2STR_BUFFER]; + char buff[VID2STR_BUFFER]; if (isis_find_vertex(&spftree->paths, &vertex->N, vertex->type)) return; @@ -1225,10 +1261,11 @@ static void add_to_paths(struct isis_spftree *spftree, if (VTYPE_IP(vertex->type)) { if (listcount(vertex->Adj_N) > 0) - isis_route_create((struct prefix *)&vertex->N.prefix, + isis_route_create(&vertex->N.ip.dest, + &vertex->N.ip.src, vertex->d_N, vertex->depth, vertex->Adj_N, spftree->area, - spftree->level); + spftree->route_table); else if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug( "ISIS-Spf: no adjacencies do not install route for " @@ -1241,7 +1278,7 @@ static void add_to_paths(struct isis_spftree *spftree, } static void init_spt(struct isis_spftree *spftree, int mtid, int level, - int family) + int family, enum spf_tree_id tree_id) { isis_vertex_queue_clear(&spftree->tents); isis_vertex_queue_clear(&spftree->paths); @@ -1249,53 +1286,54 @@ static void init_spt(struct isis_spftree *spftree, int mtid, int level, spftree->mtid = mtid; spftree->level = level; spftree->family = family; + spftree->tree_id = tree_id; return; } -static int isis_run_spf(struct isis_area *area, int level, int family, +static int isis_run_spf(struct isis_area *area, int level, + enum spf_tree_id tree_id, uint8_t *sysid, struct timeval *nowtv) { int retval = ISIS_OK; struct isis_vertex *vertex; struct isis_vertex *root_vertex; - struct isis_spftree *spftree = NULL; + struct isis_spftree *spftree = area->spftree[tree_id][level - 1]; uint8_t lsp_id[ISIS_SYS_ID_LEN + 2]; struct isis_lsp *lsp; - struct route_table *table = NULL; struct timeval time_now; unsigned long long start_time, end_time; - uint16_t mtid; + uint16_t mtid = 0; /* Get time that can't roll backwards. */ start_time = nowtv->tv_sec; start_time = (start_time * 1000000) + nowtv->tv_usec; - if (family == AF_INET) - spftree = area->spftree[level - 1]; - else if (family == AF_INET6) - spftree = area->spftree6[level - 1]; + int family = -1; + switch (tree_id) { + case SPFTREE_IPV4: + family = AF_INET; + mtid = ISIS_MT_IPV4_UNICAST; + break; + case SPFTREE_IPV6: + family = AF_INET6; + mtid = isis_area_ipv6_topology(area); + break; + case SPFTREE_DSTSRC: + family = AF_INET6; + mtid = ISIS_MT_IPV6_DSTSRC; + break; + case SPFTREE_COUNT: + assert(!"isis_run_spf should never be called with SPFTREE_COUNT as argument!"); + return ISIS_WARNING; + } + assert(spftree); assert(sysid); - /* Make all routes in current route table inactive. */ - if (family == AF_INET) - table = area->route_table[level - 1]; - else if (family == AF_INET6) - table = area->route_table6[level - 1]; - - isis_route_invalidate_table(area, table); - - /* We only support ipv4-unicast and ipv6-unicast as topologies for now - */ - if (family == AF_INET6) - mtid = isis_area_ipv6_topology(area); - else - mtid = ISIS_MT_IPV4_UNICAST; - /* * C.2.5 Step 0 */ - init_spt(spftree, mtid, level, family); + init_spt(spftree, mtid, level, family, tree_id); /* a) */ root_vertex = isis_spf_add_root(spftree, sysid); /* b) */ @@ -1342,7 +1380,6 @@ static int isis_run_spf(struct isis_area *area, int level, int family, } out: - isis_route_validate(area); spftree->runcount++; spftree->last_run_timestamp = time(NULL); spftree->last_run_monotime = monotime(&time_now); @@ -1353,6 +1390,23 @@ out: return retval; } +void isis_spf_verify_routes(struct isis_area *area, struct isis_spftree **trees) +{ + if (area->is_type == IS_LEVEL_1) { + isis_route_verify_table(area, trees[0]->route_table); + } else if (area->is_type == IS_LEVEL_2) { + isis_route_verify_table(area, trees[1]->route_table); + } else { + isis_route_verify_merge(area, trees[0]->route_table, + trees[1]->route_table); + } +} + +void isis_spf_invalidate_routes(struct isis_spftree *tree) +{ + isis_route_invalidate_table(tree->area, tree->route_table); +} + static int isis_run_spf_cb(struct thread *thread) { struct isis_spf_run *run = THREAD_ARG(thread); @@ -1370,17 +1424,31 @@ static int isis_run_spf_cb(struct thread *thread) return ISIS_WARNING; } + isis_area_invalidate_routes(area, level); + if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug("ISIS-Spf (%s) L%d SPF needed, periodic SPF", area->area_tag, level); if (area->ip_circuits) - retval = isis_run_spf(area, level, AF_INET, isis->sysid, + retval = isis_run_spf(area, level, SPFTREE_IPV4, isis->sysid, &thread->real); if (area->ipv6_circuits) - retval = isis_run_spf(area, level, AF_INET6, isis->sysid, + retval = isis_run_spf(area, level, SPFTREE_IPV6, isis->sysid, + &thread->real); + if (area->ipv6_circuits + && isis_area_ipv6_dstsrc_enabled(area)) + retval = isis_run_spf(area, level, SPFTREE_DSTSRC, isis->sysid, &thread->real); + isis_area_verify_routes(area); + + /* walk all circuits and reset any spf specific flags */ + struct listnode *node; + struct isis_circuit *circuit; + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) + UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); + return retval; } @@ -1396,7 +1464,7 @@ static struct isis_spf_run *isis_run_spf_arg(struct isis_area *area, int level) int isis_spf_schedule(struct isis_area *area, int level) { - struct isis_spftree *spftree = area->spftree[level - 1]; + struct isis_spftree *spftree = area->spftree[SPFTREE_IPV4][level - 1]; time_t now = monotime(NULL); int diff = now - spftree->last_run_monotime; @@ -1451,7 +1519,7 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, { struct listnode *node; struct isis_vertex *vertex; - char buff[PREFIX2STR_BUFFER]; + char buff[VID2STR_BUFFER]; vty_out(vty, "Vertex Type Metric Next-Hop Interface Parent\n"); @@ -1517,6 +1585,39 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, } } +static void isis_print_spftree(struct vty *vty, int level, + struct isis_area *area, + enum spf_tree_id tree_id) +{ + const char *tree_id_text = NULL; + + switch (tree_id) { + case SPFTREE_IPV4: + tree_id_text = "that speak IP"; + break; + case SPFTREE_IPV6: + tree_id_text = "that speak IPv6"; + break; + case SPFTREE_DSTSRC: + tree_id_text = "that support IPv6 dst-src routing"; + break; + case SPFTREE_COUNT: + assert(!"isis_print_spftree shouldn't be called with SPFTREE_COUNT as type"); + return; + } + + if (!area->spftree[tree_id][level - 1] + || !isis_vertex_queue_count( + &area->spftree[tree_id][level - 1]->paths)) + return; + + vty_out(vty, "IS-IS paths to level-%d routers %s\n", + level, tree_id_text); + isis_print_paths(vty, &area->spftree[tree_id][level - 1]->paths, + isis->sysid); + vty_out(vty, "\n"); +} + DEFUN (show_isis_topology, show_isis_topology_cmd, "show isis topology [<level-1|level-2>]", @@ -1548,25 +1649,17 @@ DEFUN (show_isis_topology, if ((level & levels) == 0) continue; - if (area->ip_circuits > 0 && area->spftree[level - 1] - && isis_vertex_queue_count(&area->spftree[level - 1]->paths) > 0) { - vty_out(vty, - "IS-IS paths to level-%d routers that speak IP\n", - level); - isis_print_paths( - vty, &area->spftree[level - 1]->paths, - isis->sysid); - vty_out(vty, "\n"); + if (area->ip_circuits > 0) { + isis_print_spftree(vty, level, area, + SPFTREE_IPV4); } - if (area->ipv6_circuits > 0 && area->spftree6[level - 1] - && isis_vertex_queue_count(&area->spftree6[level - 1]->paths) > 0) { - vty_out(vty, - "IS-IS paths to level-%d routers that speak IPv6\n", - level); - isis_print_paths( - vty, &area->spftree6[level - 1]->paths, - isis->sysid); - vty_out(vty, "\n"); + if (area->ipv6_circuits > 0) { + isis_print_spftree(vty, level, area, + SPFTREE_IPV6); + } + if (isis_area_ipv6_dstsrc_enabled(area)) { + isis_print_spftree(vty, level, area, + SPFTREE_DSTSRC); } } diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index 84e07861d2..9a73ca8783 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -27,6 +27,9 @@ struct isis_spftree; struct isis_spftree *isis_spftree_new(struct isis_area *area); +void isis_spf_invalidate_routes(struct isis_spftree *tree); +void isis_spf_verify_routes(struct isis_area *area, + struct isis_spftree **trees); void isis_spftree_del(struct isis_spftree *spftree); void spftree_area_init(struct isis_area *area); void spftree_area_del(struct isis_area *area); diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 9b2aa7470b..a433fcdb41 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -1912,6 +1912,11 @@ static void append_item(struct isis_item_list *dest, struct isis_item *item) dest->count++; } +static struct isis_item *last_item(struct isis_item_list *list) +{ + return container_of(list->tail, struct isis_item, next); +} + static int unpack_item(uint16_t mtid, enum isis_tlv_context context, uint8_t tlv_type, uint8_t len, struct stream *s, struct sbuf *log, void *dest, int indent) @@ -3168,6 +3173,21 @@ void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid, append_item(l, (struct isis_item *)r); } +void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid, + struct prefix_ipv6 *dest, + struct prefix_ipv6 *src, + uint32_t metric) +{ + isis_tlvs_add_ipv6_reach(tlvs, mtid, dest, metric); + struct isis_item_list *l = isis_get_mt_items(&tlvs->mt_ipv6_reach, + mtid); + + struct isis_ipv6_reach *r = (struct isis_ipv6_reach*)last_item(l); + r->subtlvs = isis_alloc_subtlvs(); + r->subtlvs->source_prefix = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*src)); + memcpy(r->subtlvs->source_prefix, src, sizeof(*src)); +} + void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id, uint8_t metric) { diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h index 98edbf14e7..bd1fa3e676 100644 --- a/isisd/isis_tlvs.h +++ b/isisd/isis_tlvs.h @@ -313,6 +313,10 @@ void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs, struct prefix_ipv4 *dest, uint32_t metric); void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid, struct prefix_ipv6 *dest, uint32_t metric); +void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid, + struct prefix_ipv6 *dest, + struct prefix_ipv6 *src, + uint32_t metric); void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id, uint8_t metric); void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid, diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index ac640c5e49..9bc0f2ef35 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -247,6 +247,7 @@ static int isis_zebra_link_params(int command, struct zclient *zclient, } static void isis_zebra_route_add_route(struct prefix *prefix, + struct prefix_ipv6 *src_p, struct isis_route_info *route_info) { struct zapi_route api; @@ -264,6 +265,10 @@ static void isis_zebra_route_add_route(struct prefix *prefix, api.type = ZEBRA_ROUTE_ISIS; api.safi = SAFI_UNICAST; api.prefix = *prefix; + if (src_p && src_p->prefixlen) { + api.src_prefix = *src_p; + SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX); + } SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); api.metric = route_info->cost; @@ -322,6 +327,7 @@ static void isis_zebra_route_add_route(struct prefix *prefix, } static void isis_zebra_route_del_route(struct prefix *prefix, + struct prefix_ipv6 *src_p, struct isis_route_info *route_info) { struct zapi_route api; @@ -334,21 +340,26 @@ static void isis_zebra_route_del_route(struct prefix *prefix, api.type = ZEBRA_ROUTE_ISIS; api.safi = SAFI_UNICAST; api.prefix = *prefix; + if (src_p && src_p->prefixlen) { + api.src_prefix = *src_p; + SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX); + } zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); } void isis_zebra_route_update(struct prefix *prefix, + struct prefix_ipv6 *src_p, struct isis_route_info *route_info) { if (zclient->sock < 0) return; if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) - isis_zebra_route_add_route(prefix, route_info); + isis_zebra_route_add_route(prefix, src_p, route_info); else - isis_zebra_route_del_route(prefix, route_info); + isis_zebra_route_del_route(prefix, src_p, route_info); } static int isis_zebra_read(int command, struct zclient *zclient, @@ -359,24 +370,23 @@ static int isis_zebra_read(int command, struct zclient *zclient, if (zapi_route_decode(zclient->ibuf, &api) < 0) return -1; - /* we completely ignore srcdest routes for now. */ - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) - return 0; - /* * Avoid advertising a false default reachability. (A default * route installed by IS-IS gets redistributed from zebra back * into IS-IS causing us to start advertising default reachabity * without this check) */ - if (api.prefix.prefixlen == 0 && api.type == ZEBRA_ROUTE_ISIS) + if (api.prefix.prefixlen == 0 + && api.src_prefix.prefixlen == 0 + && api.type == ZEBRA_ROUTE_ISIS) { command = ZEBRA_REDISTRIBUTE_ROUTE_DEL; + } if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD) - isis_redist_add(api.type, &api.prefix, api.distance, - api.metric); + isis_redist_add(api.type, &api.prefix, &api.src_prefix, + api.distance, api.metric); else - isis_redist_delete(api.type, &api.prefix); + isis_redist_delete(api.type, &api.prefix, &api.src_prefix); return 0; } diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index bd7bf2b5c5..4fbcf87217 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -28,6 +28,7 @@ void isis_zebra_init(struct thread_master *); void isis_zebra_stop(void); void isis_zebra_route_update(struct prefix *prefix, + struct prefix_ipv6 *src_p, struct isis_route_info *route_info); int isis_distribute_list_update(int routetype); void isis_zebra_redistribute_set(afi_t afi, int type); diff --git a/isisd/isisd.c b/isisd/isisd.c index cecaa0693d..a19f287453 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -118,13 +118,9 @@ struct isis_area *isis_area_create(const char *area_tag) */ if (area->is_type & IS_LEVEL_1) { area->lspdb[0] = lsp_db_init(); - area->route_table[0] = route_table_init(); - area->route_table6[0] = route_table_init(); } if (area->is_type & IS_LEVEL_2) { area->lspdb[1] = lsp_db_init(); - area->route_table[1] = route_table_init(); - area->route_table6[1] = route_table_init(); } spftree_area_init(area); @@ -232,6 +228,10 @@ int isis_area_destroy(struct vty *vty, const char *area_tag) area->lspdb[1] = NULL; } + /* invalidate and verify to delete all routes from zebra */ + isis_area_invalidate_routes(area, ISIS_LEVEL1 & ISIS_LEVEL2); + isis_area_verify_routes(area); + spftree_area_del(area); THREAD_TIMER_OFF(area->spf_timer[0]); @@ -240,27 +240,6 @@ int isis_area_destroy(struct vty *vty, const char *area_tag) spf_backoff_free(area->spf_delay_ietf[0]); spf_backoff_free(area->spf_delay_ietf[1]); - /* invalidate and validate would delete all routes from zebra */ - isis_route_invalidate(area); - isis_route_validate(area); - - if (area->route_table[0]) { - route_table_finish(area->route_table[0]); - area->route_table[0] = NULL; - } - if (area->route_table[1]) { - route_table_finish(area->route_table[1]); - area->route_table[1] = NULL; - } - if (area->route_table6[0]) { - route_table_finish(area->route_table6[0]); - area->route_table6[0] = NULL; - } - if (area->route_table6[1]) { - route_table_finish(area->route_table6[1]); - area->route_table6[1] = NULL; - } - isis_redist_area_finish(area); for (ALL_LIST_ELEMENTS(area->area_addrs, node, nnode, addr)) { @@ -1340,10 +1319,16 @@ DEFUN (show_isis_summary, vty_out(vty, "\n"); vty_out(vty, " IPv4 route computation:\n"); - isis_spf_print(area->spftree[level - 1], vty); + isis_spf_print(area->spftree[SPFTREE_IPV4][level - 1], + vty); vty_out(vty, " IPv6 route computation:\n"); - isis_spf_print(area->spftree6[level - 1], vty); + isis_spf_print(area->spftree[SPFTREE_IPV6][level - 1], + vty); + + vty_out(vty, " IPv6 dst-src route computation:\n"); + isis_spf_print(area->spftree[SPFTREE_DSTSRC][level-1], + vty); } } vty_out(vty, "\n"); @@ -1680,29 +1665,42 @@ int isis_area_passwd_hmac_md5_set(struct isis_area *area, int level, passwd, snp_auth); } +void isis_area_invalidate_routes(struct isis_area *area, int levels) +{ + for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { + if (!(level & levels)) + continue; + for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) { + isis_spf_invalidate_routes( + area->spftree[tree][level - 1]); + } + } +} + +void isis_area_verify_routes(struct isis_area *area) +{ + for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) + isis_spf_verify_routes(area, area->spftree[tree]); +} + static void area_resign_level(struct isis_area *area, int level) { + isis_area_invalidate_routes(area, level); + isis_area_verify_routes(area); + if (area->lspdb[level - 1]) { lsp_db_destroy(area->lspdb[level - 1]); area->lspdb[level - 1] = NULL; } - if (area->spftree[level - 1]) { - isis_spftree_del(area->spftree[level - 1]); - area->spftree[level - 1] = NULL; - } - if (area->spftree6[level - 1]) { - isis_spftree_del(area->spftree6[level - 1]); - area->spftree6[level - 1] = NULL; + + for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) { + if (area->spftree[tree][level - 1]) { + isis_spftree_del(area->spftree[tree][level - 1]); + area->spftree[tree][level - 1] = NULL; + } } + THREAD_TIMER_OFF(area->spf_timer[level - 1]); - if (area->route_table[level - 1]) { - route_table_finish(area->route_table[level - 1]); - area->route_table[level - 1] = NULL; - } - if (area->route_table6[level - 1]) { - route_table_finish(area->route_table6[level - 1]); - area->route_table6[level - 1] = NULL; - } sched_debug( "ISIS (%s): Resigned from L%d - canceling LSP regeneration timer.", @@ -1731,10 +1729,6 @@ void isis_area_is_type_set(struct isis_area *area, int is_type) if (area->lspdb[1] == NULL) area->lspdb[1] = lsp_db_init(); - if (area->route_table[1] == NULL) - area->route_table[1] = route_table_init(); - if (area->route_table6[1] == NULL) - area->route_table6[1] = route_table_init(); break; case IS_LEVEL_1_AND_2: @@ -1750,10 +1744,6 @@ void isis_area_is_type_set(struct isis_area *area, int is_type) if (area->lspdb[0] == NULL) area->lspdb[0] = lsp_db_init(); - if (area->route_table[0] == NULL) - area->route_table[0] = route_table_init(); - if (area->route_table6[0] == NULL) - area->route_table6[0] = route_table_init(); break; default: diff --git a/isisd/isisd.h b/isisd/isisd.h index d1ad9f3b8e..ce602e4402 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -63,13 +63,17 @@ struct isis { extern struct isis *isis; DECLARE_QOBJ_TYPE(isis_area) +enum spf_tree_id { + SPFTREE_IPV4 = 0, + SPFTREE_IPV6, + SPFTREE_DSTSRC, + SPFTREE_COUNT +}; + struct isis_area { struct isis *isis; /* back pointer */ dict_t *lspdb[ISIS_LEVELS]; /* link-state dbs */ - struct isis_spftree *spftree[ISIS_LEVELS]; /* The v4 SPTs */ - struct route_table *route_table[ISIS_LEVELS]; /* IPv4 routes */ - struct isis_spftree *spftree6[ISIS_LEVELS]; /* The v6 SPTs */ - struct route_table *route_table6[ISIS_LEVELS]; /* IPv6 routes */ + struct isis_spftree *spftree[SPFTREE_COUNT][ISIS_LEVELS]; #define DEFAULT_LSP_MTU 1497 unsigned int lsp_mtu; /* Size of LSPs to generate */ struct list *circuit_list; /* IS-IS circuits */ @@ -144,6 +148,9 @@ struct isis_area *isis_area_lookup(const char *); int isis_area_get(struct vty *vty, const char *area_tag); void print_debug(struct vty *, int, int); +void isis_area_invalidate_routes(struct isis_area *area, int levels); +void isis_area_verify_routes(struct isis_area *area); + void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit); void isis_area_attached_bit_set(struct isis_area *area, bool attached_bit); void isis_area_dynhostname_set(struct isis_area *area, bool dynhostname); diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c index 6c86582960..d77a3e7e93 100644 --- a/ldpd/ldp_vty_cmds.c +++ b/ldpd/ldp_vty_cmds.c @@ -861,6 +861,7 @@ ldp_vty_init (void) install_element(LDP_IPV6_NODE, &ldp_label_remote_accept_cmd); install_element(LDP_IPV6_NODE, &ldp_ttl_security_disable_cmd); install_element(LDP_IPV6_NODE, &ldp_interface_cmd); + install_element(LDP_IPV6_NODE, &no_ldp_interface_cmd); install_element(LDP_IPV6_NODE, &ldp_session_holdtime_cmd); install_element(LDP_IPV6_NODE, &ldp_neighbor_ipv6_targeted_cmd); install_element(LDP_IPV6_NODE, &ldp_exit_address_family_cmd); diff --git a/lib/command.h b/lib/command.h index 2d333b098a..a001a90e2e 100644 --- a/lib/command.h +++ b/lib/command.h @@ -338,6 +338,7 @@ struct cmd_node { #define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n" #define ROUTER_STR "Enable a routing process\n" #define AS_STR "AS number\n" +#define MAC_STR "MAC address\n" #define MBGP_STR "MBGP information\n" #define MATCH_STR "Match values from routing table\n" #define SET_STR "Set values in destination routing protocol\n" diff --git a/lib/compiler.h b/lib/compiler.h index 773a52e742..b19c33f65e 100644 --- a/lib/compiler.h +++ b/lib/compiler.h @@ -76,6 +76,7 @@ #else #define CPP_WARN(text) +#define CPP_NOTICE(text) #endif #endif /* _FRR_COMPILER_H */ diff --git a/lib/filter.c b/lib/filter.c index 670c65374a..0528b0f2ad 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -157,7 +157,7 @@ static const char *filter_type_str(struct filter *filter) } /* If filter match to the prefix then return 1. */ -static int filter_match_cisco(struct filter *mfilter, struct prefix *p) +static int filter_match_cisco(struct filter *mfilter, const struct prefix *p) { struct filter_cisco *filter; struct in_addr mask; @@ -181,7 +181,7 @@ static int filter_match_cisco(struct filter *mfilter, struct prefix *p) } /* If filter match to the prefix then return 1. */ -static int filter_match_zebra(struct filter *mfilter, struct prefix *p) +static int filter_match_zebra(struct filter *mfilter, const struct prefix *p) { struct filter_zebra *filter = NULL; @@ -372,10 +372,11 @@ static struct access_list *access_list_get(afi_t afi, const char *name) } /* Apply access list to object (which should be struct prefix *). */ -enum filter_type access_list_apply(struct access_list *access, void *object) +enum filter_type access_list_apply(struct access_list *access, + const void *object) { struct filter *filter; - struct prefix *p = (struct prefix *)object; + const struct prefix *p = (const struct prefix *)object; if (access == NULL) return FILTER_DENY; diff --git a/lib/filter.h b/lib/filter.h index c02516409b..97854b1e97 100644 --- a/lib/filter.h +++ b/lib/filter.h @@ -59,6 +59,7 @@ extern void access_list_reset(void); extern void access_list_add_hook(void (*func)(struct access_list *)); extern void access_list_delete_hook(void (*func)(struct access_list *)); extern struct access_list *access_list_lookup(afi_t, const char *); -extern enum filter_type access_list_apply(struct access_list *, void *); +extern enum filter_type access_list_apply(struct access_list *access, + const void *object); #endif /* _ZEBRA_FILTER_H */ diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c index 00681b9db8..f5a6383f48 100644 --- a/lib/frr_pthread.c +++ b/lib/frr_pthread.c @@ -273,7 +273,33 @@ static int fpt_halt(struct frr_pthread *fpt, void **res) return 0; } -/* entry pthread function & main event loop */ +/* + * Entry pthread function & main event loop. + * + * Upon thread start the following actions occur: + * + * - frr_pthread's owner field is set to pthread ID. + * - All signals are blocked (except for unblockable signals). + * - Pthread's threadmaster is set to never handle pending signals + * - Poker pipe for poll() is created and queued as I/O source + * - The frr_pthread->running_cond condition variable is signalled to indicate + * that the previous actions have completed. It is not safe to assume any of + * the above have occurred before receiving this signal. + * + * After initialization is completed, the event loop begins running. Each tick, + * the following actions are performed before running the usual event system + * tick function: + * + * - Verify that the running boolean is set + * - Verify that there are no pending cancellation requests + * - Verify that there are tasks scheduled + * + * So long as the conditions are met, the event loop tick is run and the + * returned task is executed. + * + * If any of these conditions are not met, the event loop exits, closes the + * pipes and dies without running any cleanup functions. + */ static void *fpt_run(void *arg) { struct frr_pthread *fpt = arg; @@ -289,6 +315,7 @@ static void *fpt_run(void *arg) struct thread task; while (atomic_load_explicit(&fpt->running, memory_order_relaxed)) { + pthread_testcancel(); if (thread_fetch(fpt->master, &task)) { thread_call(&task); } @@ -652,7 +652,7 @@ DEFUN (interface, /*Pending: need proper vrf name based lookup/(possible creation of VRF) Imagine forward reference of a vrf by name in this interface config */ if (vrfname) - VRF_GET_ID(vrf_id, vrfname); + VRF_GET_ID(vrf_id, vrfname, false); #ifdef SUNOS_5 ifp = if_sunwzebra_get(ifname, vrf_id); @@ -686,7 +686,7 @@ DEFUN_NOSH (no_interface, vrf_id_t vrf_id = VRF_DEFAULT; if (argc > 3) - VRF_GET_ID(vrf_id, vrfname); + VRF_GET_ID(vrf_id, vrfname, false); ifp = if_lookup_by_name(ifname, vrf_id); diff --git a/lib/keychain.c b/lib/keychain.c index c3e1a6d3c4..494f6f6430 100644 --- a/lib/keychain.c +++ b/lib/keychain.c @@ -172,7 +172,7 @@ struct key *key_match_for_accept(const struct keychain *keychain, if (key->accept.start == 0 || (key->accept.start <= now && (key->accept.end >= now || key->accept.end == -1))) - if (strncmp(key->string, auth_str, 16) == 0) + if (key->string && (strncmp(key->string, auth_str, 16) == 0)) return key; } return NULL; diff --git a/lib/linklist.h b/lib/linklist.h index 1e2631ea46..cee6c1e505 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -232,7 +232,7 @@ extern void list_sort(struct list *list, * and remove list_delete_original and the list_delete #define * Additionally remove list_free entirely */ -#if defined(VERSION_TYPE_DEV) && CONFDATE > 20181001 +#if CONFDATE > 20181001 CPP_NOTICE("list_delete without double pointer is deprecated, please fixup") #endif diff --git a/lib/plist.c b/lib/plist.c index 056b737f54..2b666f256f 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -656,7 +656,7 @@ static const char *prefix_list_type_str(struct prefix_list_entry *pentry) } static int prefix_list_entry_match(struct prefix_list_entry *pentry, - struct prefix *p) + const struct prefix *p) { int ret; @@ -683,14 +683,15 @@ static int prefix_list_entry_match(struct prefix_list_entry *pentry, return 1; } -enum prefix_list_type prefix_list_apply_which_prefix(struct prefix_list *plist, - struct prefix **which, - void *object) +enum prefix_list_type prefix_list_apply_which_prefix( + struct prefix_list *plist, + const struct prefix **which, + const void *object) { struct prefix_list_entry *pentry, *pbest = NULL; - struct prefix *p = (struct prefix *)object; - uint8_t *byte = p->u.val; + const struct prefix *p = (const struct prefix *)object; + const uint8_t *byte = p->u.val; size_t depth; size_t validbits = p->prefixlen; struct pltrie_table *table; diff --git a/lib/plist.h b/lib/plist.h index 67e345a485..fecbe0e2ce 100644 --- a/lib/plist.h +++ b/lib/plist.h @@ -61,8 +61,9 @@ extern struct prefix_list *prefix_list_lookup(afi_t, const char *); * If it is a empty plist return a NULL pointer. */ extern enum prefix_list_type -prefix_list_apply_which_prefix(struct prefix_list *plist, struct prefix **which, - void *object); +prefix_list_apply_which_prefix(struct prefix_list *plist, + const struct prefix **which, + const void *object); #define prefix_list_apply(A, B) prefix_list_apply_which_prefix((A), NULL, (B)) extern struct prefix_list *prefix_bgp_orf_lookup(afi_t, const char *); diff --git a/lib/routemap.c b/lib/routemap.c index 056c793454..4e8682f312 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -1387,7 +1387,7 @@ int route_map_delete_set(struct route_map_index *index, const char *set_name, static route_map_result_t route_map_apply_match(struct route_map_rule_list *match_list, - struct prefix *prefix, route_map_object_t type, + const struct prefix *prefix, route_map_object_t type, void *object) { route_map_result_t ret = RMAP_NOMATCH; @@ -1417,7 +1417,8 @@ route_map_apply_match(struct route_map_rule_list *match_list, } /* Apply route map to the object. */ -route_map_result_t route_map_apply(struct route_map *map, struct prefix *prefix, +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; @@ -2740,6 +2741,15 @@ void route_map_finish(void) vector_free(route_set_vec); route_set_vec = NULL; + /* + * All protocols are setting these to NULL + * by default on shutdown( route_map_finish ) + * Why are we making them do this work? + */ + route_map_master.add_hook = NULL; + route_map_master.delete_hook = NULL; + route_map_master.event_hook = NULL; + /* cleanup route_map */ while (route_map_master.head) { struct route_map *map = route_map_master.head; diff --git a/lib/routemap.h b/lib/routemap.h index 0aeba7e1f6..a193e32536 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -87,8 +87,10 @@ struct route_map_rule_cmd { const char *str; /* Function for value set or match. */ - route_map_result_t (*func_apply)(void *, struct prefix *, - route_map_object_t, void *); + route_map_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 *); @@ -167,6 +169,12 @@ DECLARE_QOBJ_TYPE(route_map) /* Prototypes. */ extern void route_map_init(void); + +/* + * This should only be called on shutdown + * Additionally this function sets the hooks to NULL + * before any processing is done. + */ extern void route_map_finish(void); /* Add match statement to route map. */ @@ -208,7 +216,7 @@ extern struct route_map *route_map_lookup_by_name(const char *name); /* Apply route map to the object. */ extern route_map_result_t route_map_apply(struct route_map *map, - struct prefix *, + const struct prefix *prefix, route_map_object_t object_type, void *object); diff --git a/lib/sockopt.c b/lib/sockopt.c index 815be86c2e..e979bef174 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -75,7 +75,7 @@ static void *getsockopt_cmsg_data(struct msghdr *msgh, int level, int type) for (cmsg = ZCMSG_FIRSTHDR(msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(msgh, cmsg)) - if (cmsg->cmsg_level == level && cmsg->cmsg_type) + if (cmsg->cmsg_level == level && cmsg->cmsg_type == type) return (ptr = CMSG_DATA(cmsg)); return NULL; diff --git a/lib/srcdest_table.c b/lib/srcdest_table.c index 32f8e8ca5b..4497faf6fc 100644 --- a/lib/srcdest_table.c +++ b/lib/srcdest_table.c @@ -281,13 +281,12 @@ void srcdest_rnode_prefixes(struct route_node *rn, const struct prefix **p, } } -const char *srcdest_rnode2str(struct route_node *rn, char *str, int size) +const char *srcdest2str(const struct prefix *dst_p, + const struct prefix_ipv6 *src_p, + char *str, int size) { - const struct prefix *dst_p, *src_p; char dst_buf[PREFIX_STRLEN], src_buf[PREFIX_STRLEN]; - srcdest_rnode_prefixes(rn, &dst_p, &src_p); - snprintf(str, size, "%s%s%s", prefix2str(dst_p, dst_buf, sizeof(dst_buf)), (src_p && src_p->prefixlen) ? " from " : "", @@ -296,3 +295,11 @@ const char *srcdest_rnode2str(struct route_node *rn, char *str, int size) : ""); return str; } + +const char *srcdest_rnode2str(struct route_node *rn, char *str, int size) +{ + const struct prefix *dst_p, *src_p; + + srcdest_rnode_prefixes(rn, &dst_p, &src_p); + return srcdest2str(dst_p, (struct prefix_ipv6*)src_p, str, size); +} diff --git a/lib/srcdest_table.h b/lib/srcdest_table.h index 5f97f02bac..9ceb876f81 100644 --- a/lib/srcdest_table.h +++ b/lib/srcdest_table.h @@ -64,6 +64,9 @@ extern struct route_node *srcdest_rnode_lookup(struct route_table *table, extern void srcdest_rnode_prefixes(struct route_node *rn, const struct prefix **p, const struct prefix **src_p); +extern const char *srcdest2str(const struct prefix *dst_p, + const struct prefix_ipv6 *src_p, + char *str, int size); extern const char *srcdest_rnode2str(struct route_node *rn, char *str, int size); extern struct route_node *srcdest_route_next(struct route_node *rn); diff --git a/lib/stream.c b/lib/stream.c index a172eedc99..cf9af4d3bb 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -100,16 +100,12 @@ struct stream *stream_new(size_t size) assert(size > 0); - s = XCALLOC(MTYPE_STREAM, sizeof(struct stream)); + s = XMALLOC(MTYPE_STREAM, sizeof(struct stream)); - if (s == NULL) - return s; - - if ((s->data = XMALLOC(MTYPE_STREAM_DATA, size)) == NULL) { - XFREE(MTYPE_STREAM, s); - return NULL; - } + s->data = XMALLOC(MTYPE_STREAM_DATA, size); + s->getp = s->endp = 0; + s->next = NULL; s->size = size; return s; } diff --git a/lib/stream.h b/lib/stream.h index 11af85c663..e808f039c6 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -133,7 +133,7 @@ struct stream_fifo { #define STREAM_CONCAT_REMAIN(S1, S2, size) ((size) - (S1)->endp - (S2)->endp) /* deprecated macros - do not use in new code */ -#if defined(VERSION_TYPE_DEV) && CONFDATE > 20181128 +#if CONFDATE > 20181128 CPP_NOTICE("lib: time to remove deprecated stream.h macros") #endif #define STREAM_PNT(S) stream_pnt((S)) diff --git a/lib/table.h b/lib/table.h index a9d788b35a..ac7df3e695 100644 --- a/lib/table.h +++ b/lib/table.h @@ -178,35 +178,37 @@ struct route_table_iter_t_ { extern struct route_table *route_table_init(void); extern struct route_table * -route_table_init_with_delegate(route_table_delegate_t *); +route_table_init_with_delegate(route_table_delegate_t *delegate); extern route_table_delegate_t *route_table_get_default_delegate(void); -extern void route_table_finish(struct route_table *); -extern struct route_node *route_top(struct route_table *); -extern struct route_node *route_next(struct route_node *); -extern struct route_node *route_next_until(struct route_node *, - const struct route_node *); -extern struct route_node *route_node_get(struct route_table *const, - union prefixconstptr); -extern struct route_node *route_node_lookup(const struct route_table *, - union prefixconstptr); -extern struct route_node *route_node_lookup_maynull(const struct route_table *, - union prefixconstptr); -extern struct route_node *route_node_match(const struct route_table *, - union prefixconstptr); -extern struct route_node *route_node_match_ipv4(const struct route_table *, - const struct in_addr *); -extern struct route_node *route_node_match_ipv6(const struct route_table *, - const struct in6_addr *); - -extern unsigned long route_table_count(const struct route_table *); - -extern struct route_node *route_node_create(route_table_delegate_t *, - struct route_table *); -extern void route_node_delete(struct route_node *); -extern void route_node_destroy(route_table_delegate_t *, struct route_table *, - struct route_node *); +extern void route_table_finish(struct route_table *table); +extern struct route_node *route_top(struct route_table *table); +extern struct route_node *route_next(struct route_node *node); +extern struct route_node *route_next_until(struct route_node *node, + const struct route_node *limit); +extern struct route_node *route_node_get(struct route_table *const table, + union prefixconstptr pu); +extern struct route_node *route_node_lookup(const struct route_table *table, + union prefixconstptr pu); +extern struct route_node * +route_node_lookup_maynull(const struct route_table *table, + union prefixconstptr pu); +extern struct route_node *route_node_match(const struct route_table *table, + union prefixconstptr pu); +extern struct route_node *route_node_match_ipv4(const struct route_table *table, + const struct in_addr *addr); +extern struct route_node *route_node_match_ipv6(const struct route_table *table, + const struct in6_addr *addr); + +extern unsigned long route_table_count(const struct route_table *table); + +extern struct route_node *route_node_create(route_table_delegate_t *delegate, + struct route_table *table); +extern void route_node_delete(struct route_node *node); +extern void route_node_destroy(route_table_delegate_t *delegate, + struct route_table *table, + struct route_node *node); extern struct route_node *route_table_get_next(const struct route_table *table, union prefixconstptr pu); @@ -233,13 +235,17 @@ static inline struct route_node *route_lock_node(struct route_node *node) } /* Unlock node. */ -static inline void route_unlock_node(struct route_node *node) +static inline struct route_node *route_unlock_node(struct route_node *node) { assert(node->lock > 0); (*(unsigned *)&node->lock)--; - if (node->lock == 0) + if (node->lock == 0) { route_node_delete(node); + return NULL; + } + + return node; } /* diff --git a/lib/thread.c b/lib/thread.c index 1c5e838772..898e9e9fce 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -782,6 +782,7 @@ struct thread *funcname_thread_add_read_write(int dir, struct thread_master *m, { struct thread *thread = NULL; + assert(fd >= 0 && fd < m->fd_limit); pthread_mutex_lock(&m->mtx); { if (t_ptr @@ -111,15 +111,23 @@ extern struct vrf *vrf_get(vrf_id_t, const char *); extern const char *vrf_id_to_name(vrf_id_t vrf_id); extern vrf_id_t vrf_name_to_id(const char *); -#define VRF_GET_ID(V, NAME) \ +#define VRF_GET_ID(V, NAME, USE_JSON) \ do { \ struct vrf *vrf; \ if (!(vrf = vrf_lookup_by_name(NAME))) { \ - vty_out(vty, "%% VRF %s not found\n", NAME); \ + if (USE_JSON) { \ + vty_out(vty, "{}\n"); \ + } else { \ + vty_out(vty, "%% VRF %s not found\n", NAME); \ + } \ return CMD_WARNING; \ } \ if (vrf->vrf_id == VRF_UNKNOWN) { \ - vty_out(vty, "%% VRF %s not active\n", NAME); \ + if (USE_JSON) { \ + vty_out(vty, "{}\n"); \ + } else { \ + vty_out(vty, "%% VRF %s not active\n", NAME); \ + } \ return CMD_WARNING; \ } \ (V) = vrf->vrf_id; \ diff --git a/lib/workqueue.h b/lib/workqueue.h index 6085820393..fe1700f8de 100644 --- a/lib/workqueue.h +++ b/lib/workqueue.h @@ -154,7 +154,7 @@ extern struct work_queue *work_queue_new(struct thread_master *, const char *); * The usage of work_queue_free is being transitioned to pass * in the double pointer to remove use after free's. */ -#if defined(VERSION_TYPE_DEV) && CONFDATE > 20190205 +#if CONFDATE > 20190205 CPP_NOTICE("work_queue_free without double pointer is deprecated, please fixup") #endif extern void work_queue_free_and_null(struct work_queue **); diff --git a/lib/zclient.h b/lib/zclient.h index ad98b8db87..49419b3df3 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -448,6 +448,8 @@ enum zapi_iptable_notify_owner { /* Zebra MAC types */ #define ZEBRA_MACIP_TYPE_STICKY 0x01 /* Sticky MAC*/ #define ZEBRA_MACIP_TYPE_GW 0x02 /* gateway (SVI) mac*/ +#define ZEBRA_MACIP_TYPE_ROUTER_FLAG 0x04 /* Router Flag - proxy NA */ +#define ZEBRA_MACIP_TYPE_OVERRIDE_FLAG 0x08 /* Override Flag */ struct zclient_options { bool receive_notify; @@ -457,7 +459,7 @@ struct zclient_options { extern struct zclient *zclient_new(struct thread_master *); /* clang-format off */ -#if defined(VERSION_TYPE_DEV) && CONFDATE > 20181101 +#if CONFDATE > 20181101 CPP_NOTICE("zclient_new_notify can take over or zclient_new now"); #endif /* clang-format on */ @@ -598,7 +600,7 @@ extern void zebra_interface_if_set_value(struct stream *, struct interface *); extern void zebra_router_id_update_read(struct stream *s, struct prefix *rid); /* clang-format off */ -#if defined(VERSION_TYPE_DEV) && CONFDATE > 20180823 +#if CONFDATE > 20180823 CPP_NOTICE("zapi_ipv4_route, zapi_ipv6_route, zapi_ipv4_route_ipv6_nexthop as well as the zapi_ipv4 and zapi_ipv6 data structures should be removed now"); #endif /* clang-format on */ diff --git a/lib/zebra.h b/lib/zebra.h index 98428eaab2..9ac96372ff 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -365,6 +365,22 @@ struct in_pktinfo { _a < _b ? _a : _b; \ }) +#ifndef offsetof +#ifdef __compiler_offsetof +#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) +#else +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif +#endif + +#ifndef container_of +#define container_of(ptr, type, member) \ + ({ \ + const typeof(((type *)0)->member) *__mptr = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); \ + }) +#endif + #define ZEBRA_NUM_OF(x) (sizeof (x) / sizeof (x[0])) /* For old definition. */ diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index a723396507..5af88defeb 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1345,7 +1345,8 @@ static void ospf6_redistribute_show_config(struct vty *vty) /* Routemap Functions */ static route_map_result_t -ospf6_routemap_rule_match_address_prefixlist(void *rule, struct prefix *prefix, +ospf6_routemap_rule_match_address_prefixlist(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1384,7 +1385,7 @@ struct route_map_rule_cmd ospf6_routemap_rule_match_address_prefixlist_cmd = { /* Match function should return 1 if match is success else return zero. */ static route_map_result_t -ospf6_routemap_rule_match_interface(void *rule, struct prefix *prefix, +ospf6_routemap_rule_match_interface(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { struct interface *ifp; @@ -1422,7 +1423,7 @@ struct route_map_rule_cmd ospf6_routemap_rule_match_interface_cmd = { /* Match function for matching route tags */ static route_map_result_t ospf6_routemap_rule_match_tag(void *rule, - struct prefix *prefix, + const struct prefix *p, route_map_object_t type, void *object) { @@ -1442,7 +1443,7 @@ static struct route_map_rule_cmd ospf6_routemap_rule_match_tag_cmd = { }; static route_map_result_t -ospf6_routemap_rule_set_metric_type(void *rule, struct prefix *prefix, +ospf6_routemap_rule_set_metric_type(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { char *metric_type = rule; @@ -1478,7 +1479,7 @@ struct route_map_rule_cmd ospf6_routemap_rule_set_metric_type_cmd = { }; static route_map_result_t -ospf6_routemap_rule_set_metric(void *rule, struct prefix *prefix, +ospf6_routemap_rule_set_metric(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { char *metric = rule; @@ -1513,7 +1514,7 @@ struct route_map_rule_cmd ospf6_routemap_rule_set_metric_cmd = { }; static route_map_result_t -ospf6_routemap_rule_set_forwarding(void *rule, struct prefix *prefix, +ospf6_routemap_rule_set_forwarding(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { char *forwarding = rule; @@ -1551,7 +1552,7 @@ struct route_map_rule_cmd ospf6_routemap_rule_set_forwarding_cmd = { }; static route_map_result_t ospf6_routemap_rule_set_tag(void *rule, - struct prefix *prefix, + const struct prefix *p, route_map_object_t type, void *object) { @@ -1860,9 +1861,6 @@ void ospf6_asbr_redistribute_reset(void) void ospf6_asbr_terminate(void) { /* Cleanup route maps */ - route_map_add_hook(NULL); - route_map_delete_hook(NULL); - route_map_event_hook(NULL); route_map_finish(); } diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 7bf099fbbf..fde47c74fe 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -425,13 +425,13 @@ DEFUN(no_ospf6_router_id, return CMD_SUCCESS; } -#if defined(VERSION_TYPE_DEV) && CONFDATE > 20180828 +#if CONFDATE > 20180828 CPP_NOTICE("ospf6: `router-id A.B.C.D` deprecated 2017/08/28") #endif ALIAS_HIDDEN(ospf6_router_id, ospf6_router_id_hdn_cmd, "router-id A.B.C.D", "Configure OSPF6 Router-ID\n" V4NOTATION_STR) -#if defined(VERSION_TYPE_DEV) && CONFDATE > 20180828 +#if CONFDATE > 20180828 CPP_NOTICE("ospf6: `no router-id A.B.C.D` deprecated 2017/08/28") #endif ALIAS_HIDDEN(no_ospf6_router_id, no_ospf6_router_id_hdn_cmd, diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 502f233036..4165338834 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -1921,7 +1921,7 @@ struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf, zlog_debug( "ospf_translated_nssa_refresh(): Could not install " "translated LSA, Id %s", - type7 ? inet_ntoa(type7->data->id) : "(null)"); + inet_ntoa(type7->data->id)); return NULL; } diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c index f3271acfa2..c5ec1db336 100644 --- a/ospfd/ospf_routemap.c +++ b/ospfd/ospf_routemap.c @@ -118,7 +118,7 @@ static void ospf_route_map_event(route_map_event_t 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, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -163,7 +163,7 @@ struct route_map_rule_cmd route_match_ip_nexthop_cmd = { /* `match ip next-hop prefix-list PREFIX_LIST' */ static route_map_result_t -route_match_ip_next_hop_prefix_list(void *rule, struct prefix *prefix, +route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; @@ -205,7 +205,7 @@ 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, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -244,7 +244,7 @@ struct route_map_rule_cmd route_match_ip_address_cmd = { /* `match ip address prefix-list PREFIX_LIST' */ static route_map_result_t -route_match_ip_address_prefix_list(void *rule, struct prefix *prefix, +route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; @@ -280,7 +280,7 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { /* Match function should return 1 if match is success else return zero. */ static route_map_result_t route_match_interface(void *rule, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -318,7 +318,8 @@ 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, struct prefix *prefix, +static route_map_result_t route_match_tag(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag; @@ -348,7 +349,8 @@ struct ospf_metric { /* `set metric METRIC' */ /* Set metric to attribute. */ -static route_map_result_t route_set_metric(void *rule, struct prefix *prefix, +static route_map_result_t route_set_metric(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -427,7 +429,7 @@ 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, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -476,7 +478,7 @@ 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, struct prefix *prefix, +static route_map_result_t route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag; diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index f315421843..2298c2261a 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -561,9 +561,6 @@ void ospf_terminate(void) ospf_finish(ospf); /* Cleanup route maps */ - route_map_add_hook(NULL); - route_map_delete_hook(NULL); - route_map_event_hook(NULL); route_map_finish(); /* reverse prefix_list_init */ diff --git a/pimd/pim_bfd.c b/pimd/pim_bfd.c index f5772174ba..4a3cf715da 100644 --- a/pimd/pim_bfd.c +++ b/pimd/pim_bfd.c @@ -99,9 +99,9 @@ void pim_bfd_info_nbr_create(struct pim_interface *pim_ifp, /* * pim_bfd_info_free - Free BFD info structure */ -void pim_bfd_info_free(void **bfd_info) +void pim_bfd_info_free(struct bfd_info **bfd_info) { - bfd_info_free((struct bfd_info **)bfd_info); + bfd_info_free(bfd_info); } static void pim_bfd_reg_dereg_nbr(struct pim_neighbor *nbr, int command) @@ -151,7 +151,7 @@ int pim_bfd_reg_dereg_all_nbr(struct interface *ifp, int command) if (command != ZEBRA_BFD_DEST_DEREGISTER) pim_bfd_info_nbr_create(pim_ifp, neigh); else - bfd_info_free((struct bfd_info **)&neigh->bfd_info); + pim_bfd_info_free((struct bfd_info **)&neigh->bfd_info); pim_bfd_reg_dereg_nbr(neigh, command); } @@ -170,7 +170,7 @@ void pim_bfd_trigger_event(struct pim_interface *pim_ifp, pim_bfd_info_nbr_create(pim_ifp, nbr); pim_bfd_reg_dereg_nbr(nbr, ZEBRA_BFD_DEST_REGISTER); } else { - pim_bfd_info_free((void *)&nbr->bfd_info); + pim_bfd_info_free(&nbr->bfd_info); pim_bfd_reg_dereg_nbr(nbr, ZEBRA_BFD_DEST_DEREGISTER); } } diff --git a/pimd/pim_bfd.h b/pimd/pim_bfd.h index 0dfd80839f..83def93b66 100644 --- a/pimd/pim_bfd.h +++ b/pimd/pim_bfd.h @@ -36,5 +36,5 @@ void pim_bfd_trigger_event(struct pim_interface *pim_ifp, struct pim_neighbor *nbr, uint8_t nbr_up); void pim_bfd_info_nbr_create(struct pim_interface *pim_ifp, struct pim_neighbor *neigh); -void pim_bfd_info_free(void **bfd_info); +void pim_bfd_info_free(struct bfd_info **bfd_info); #endif /* _PIM_BFD_H */ diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index e075ff5ac2..e79e91d7df 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -46,6 +46,7 @@ #include "pim_rp.h" #include "pim_nht.h" #include "pim_jp_agg.h" +#include "pim_igmp_join.h" static void pim_if_igmp_join_del_all(struct interface *ifp); static int igmp_join_sock(const char *ifname, ifindex_t ifindex, @@ -1194,8 +1195,18 @@ static int igmp_join_sock(const char *ifname, ifindex_t ifindex, return -1; } - if (pim_socket_join_source(join_fd, ifindex, group_addr, source_addr, - ifname)) { + if (pim_igmp_join_source(join_fd, ifindex, group_addr, source_addr)) { + char group_str[INET_ADDRSTRLEN]; + char source_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<grp?>", group_addr, group_str, + sizeof(group_str)); + pim_inet4_dump("<src?>", source_addr, source_str, + sizeof(source_str)); + zlog_warn( + "%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s", + __PRETTY_FUNCTION__, join_fd, group_str, source_str, + ifindex, ifname, errno, safe_strerror(errno)); + close(join_fd); return -2; } @@ -1219,6 +1230,7 @@ static struct igmp_join *igmp_join_new(struct interface *ifp, if (join_fd < 0) { char group_str[INET_ADDRSTRLEN]; char source_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<src?>", source_addr, source_str, diff --git a/pimd/pim_igmp_join.h b/pimd/pim_igmp_join.h index abee080064..88385bffba 100644 --- a/pimd/pim_igmp_join.h +++ b/pimd/pim_igmp_join.h @@ -60,8 +60,6 @@ static int pim_igmp_join_source(int fd, ifindex_t ifindex, return setsockopt(fd, SOL_IP, MCAST_JOIN_SOURCE_GROUP, &req, sizeof(req)); - - return 0; } #endif /* PIM_IGMP_JOIN_H */ diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index 5121dc94ca..e664bf3062 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -54,10 +54,10 @@ static void pim_instance_terminate(struct pim_instance *pim) pim->rpf_hash = NULL; } - pim_oil_terminate(pim); - pim_if_terminate(pim); + pim_oil_terminate(pim); + pim_msdp_exit(pim); XFREE(MTYPE_PIM_PIM_INSTANCE, pim); diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index 951e743494..4910cb8b38 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -1242,8 +1242,10 @@ static int pim_msdp_peer_comp(const void *p1, const void *p2) } /************************** Mesh group management **************************/ -static void pim_msdp_mg_free(struct pim_instance *pim, struct pim_msdp_mg *mg) +static void pim_msdp_mg_free(struct pim_instance *pim) { + struct pim_msdp_mg *mg = pim->msdp.mg; + /* If the mesh-group has valid member or src_ip don't delete it */ if (!mg || mg->mbr_cnt || (mg->src_ip.s_addr != INADDR_ANY)) { return; @@ -1258,8 +1260,7 @@ static void pim_msdp_mg_free(struct pim_instance *pim, struct pim_msdp_mg *mg) if (mg->mbr_list) list_delete_and_null(&mg->mbr_list); - XFREE(MTYPE_PIM_MSDP_MG, mg); - pim->msdp.mg = NULL; + XFREE(MTYPE_PIM_MSDP_MG, pim->msdp.mg); } static struct pim_msdp_mg *pim_msdp_mg_new(const char *mesh_group_name) @@ -1299,7 +1300,7 @@ enum pim_msdp_err pim_msdp_mg_del(struct pim_instance *pim, mg->src_ip.s_addr = INADDR_ANY; /* free up the mesh-group */ - pim_msdp_mg_free(pim, mg); + pim_msdp_mg_free(pim); return PIM_MSDP_ERR_NONE; } @@ -1438,7 +1439,7 @@ enum pim_msdp_err pim_msdp_mg_mbr_del(struct pim_instance *pim, pim_msdp_mg_mbr_do_del(mg, mbr); /* if there are no references to the mg free it */ - pim_msdp_mg_free(pim, mg); + pim_msdp_mg_free(pim); return PIM_MSDP_ERR_NONE; } @@ -1475,7 +1476,7 @@ enum pim_msdp_err pim_msdp_mg_src_del(struct pim_instance *pim, mg->src_ip.s_addr = INADDR_ANY; pim_msdp_mg_src_do_del(pim); /* if there are no references to the mg free it */ - pim_msdp_mg_free(pim, mg); + pim_msdp_mg_free(pim); } return PIM_MSDP_ERR_NONE; } @@ -1598,7 +1599,10 @@ void pim_msdp_exit(struct pim_instance *pim) /* XXX: stop listener and delete all peer sessions */ + pim_msdp_mg_free(pim); + if (pim->msdp.peer_hash) { + hash_clean(pim->msdp.peer_hash, NULL); hash_free(pim->msdp.peer_hash); pim->msdp.peer_hash = NULL; } @@ -1608,6 +1612,7 @@ void pim_msdp_exit(struct pim_instance *pim) } if (pim->msdp.sa_hash) { + hash_clean(pim->msdp.sa_hash, NULL); hash_free(pim->msdp.sa_hash); pim->msdp.sa_hash = NULL; } @@ -1615,4 +1620,8 @@ void pim_msdp_exit(struct pim_instance *pim) if (pim->msdp.sa_list) { list_delete_and_null(&pim->msdp.sa_list); } + + if (pim->msdp.work_obuf) + stream_free(pim->msdp.work_obuf); + pim->msdp.work_obuf = NULL; } diff --git a/pimd/pim_msg.c b/pimd/pim_msg.c index 5d4ddf14e8..63688f87e0 100644 --- a/pimd/pim_msg.c +++ b/pimd/pim_msg.c @@ -114,7 +114,7 @@ size_t pim_msg_get_jp_group_size(struct list *sources) size += sizeof(struct pim_encoded_source_ipv4) * sources->count; js = listgetdata(listhead(sources)); - if (js && js->up->sg.src.s_addr == INADDR_ANY) { + if (js && js->up->sg.src.s_addr == INADDR_ANY && js->is_join) { struct pim_upstream *child, *up; struct listnode *up_node; diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 2730f5e7aa..e73422331f 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -409,6 +409,9 @@ void pim_neighbor_free(struct pim_neighbor *neigh) list_delete_and_null(&neigh->upstream_jp_agg); THREAD_OFF(neigh->jp_timer); + if (neigh->bfd_info) + pim_bfd_info_free(&neigh->bfd_info); + XFREE(MTYPE_PIM_NEIGHBOR, neigh); } diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 78152b266f..0a64c8db3d 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -300,59 +300,9 @@ static int pim_update_upstream_nh_helper(struct hash_backet *backet, void *arg) } } - if (rpf_result == PIM_RPF_CHANGED) { - struct pim_neighbor *nbr; + if (rpf_result == PIM_RPF_CHANGED) + pim_zebra_upstream_rpf_changed(pim, up, &old); - nbr = pim_neighbor_find(old.source_nexthop.interface, - old.rpf_addr.u.prefix4); - if (nbr) - pim_jp_agg_remove_group(nbr->upstream_jp_agg, up); - - /* - * We have detected a case where we might need to rescan - * the inherited o_list so do it. - */ - if (up->channel_oil && up->channel_oil->oil_inherited_rescan) { - pim_upstream_inherited_olist_decide(pim, up); - up->channel_oil->oil_inherited_rescan = 0; - } - - if (up->join_state == PIM_UPSTREAM_JOINED) { - /* - * If we come up real fast we can be here - * where the mroute has not been installed - * so install it. - */ - if (up->channel_oil && !up->channel_oil->installed) - pim_mroute_add(up->channel_oil, - __PRETTY_FUNCTION__); - - /* - * RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages - * - * Transitions from Joined State - * - * RPF'(S,G) changes not due to an Assert - * - * The upstream (S,G) state machine remains in Joined - * state. Send Join(S,G) to the new upstream - * neighbor, which is the new value of RPF'(S,G). - * Send Prune(S,G) to the old upstream neighbor, which - * is the old value of RPF'(S,G). Set the Join - * Timer (JT) to expire after t_periodic seconds. - */ - pim_jp_agg_switch_interface(&old, &up->rpf, up); - - pim_upstream_join_timer_restart(up, &old); - } /* up->join_state == PIM_UPSTREAM_JOINED */ - - /* - * FIXME can join_desired actually be changed by - * pim_rpf_update() returning PIM_RPF_CHANGED ? - */ - pim_upstream_update_join_desired(pim, up); - - } /* PIM_RPF_CHANGED */ if (PIM_DEBUG_PIM_NHT) { zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s", @@ -367,25 +317,9 @@ static int pim_update_upstream_nh_helper(struct hash_backet *backet, void *arg) static int pim_update_upstream_nh(struct pim_instance *pim, struct pim_nexthop_cache *pnc) { - struct listnode *node; - struct interface *ifp; - hash_walk(pnc->upstream_hash, pim_update_upstream_nh_helper, pim); - FOR_ALL_INTERFACES (pim->vrf, ifp) - if (ifp->info) { - struct pim_interface *pim_ifp = ifp->info; - struct pim_iface_upstream_switch *us; - - for (ALL_LIST_ELEMENTS_RO(pim_ifp->upstream_switch_list, - node, us)) { - struct pim_rpf rpf; - rpf.source_nexthop.interface = ifp; - rpf.rpf_addr.u.prefix4 = us->address; - pim_joinprune_send(&rpf, us->us); - pim_jp_agg_clear_group(us->us); - } - } + pim_zebra_update_all_interfaces(pim); return 0; } @@ -418,7 +352,7 @@ int pim_ecmp_nexthop_search(struct pim_instance *pim, struct pim_nexthop *nexthop, struct prefix *src, struct prefix *grp, int neighbor_needed) { - struct pim_neighbor *nbrs[MULTIPATH_NUM], *nbr; + struct pim_neighbor *nbrs[MULTIPATH_NUM], *nbr = NULL; struct interface *ifps[MULTIPATH_NUM]; struct nexthop *nh_node = NULL; ifindex_t first_ifindex; @@ -430,6 +364,9 @@ int pim_ecmp_nexthop_search(struct pim_instance *pim, if (!pnc || !pnc->nexthop_num || !nexthop) return 0; + memset(&nbrs, 0, sizeof(nbrs)); + memset(&ifps, 0, sizeof(ifps)); + // Current Nexthop is VALID, check to stay on the current path. if (nexthop->interface && nexthop->interface->info && nexthop->mrib_nexthop_addr.u.prefix4.s_addr @@ -829,6 +766,9 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim, return 0; } + memset(&nbrs, 0, sizeof(nbrs)); + memset(&ifps, 0, sizeof(ifps)); + /* * Look up all interfaces and neighbors, * store for later usage diff --git a/pimd/pim_routemap.c b/pimd/pim_routemap.c index b41124376f..4230c127ad 100644 --- a/pimd/pim_routemap.c +++ b/pimd/pim_routemap.c @@ -52,8 +52,5 @@ void pim_route_map_init(void) void pim_route_map_terminate(void) { - route_map_add_hook(NULL); - route_map_delete_hook(NULL); - route_map_event_hook(NULL); route_map_finish(); } diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index cc39b09043..783f931752 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -62,6 +62,9 @@ void pim_rp_list_hash_clean(void *data) static void pim_rp_info_free(struct rp_info *rp_info) { + if (rp_info->plist) + XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist); + XFREE(MTYPE_PIM_RP, rp_info); } @@ -194,7 +197,7 @@ static int pim_rp_prefix_list_used(struct pim_instance *pim, const char *plist) */ static struct rp_info *pim_rp_find_exact(struct pim_instance *pim, struct in_addr rp, - struct prefix *group) + const struct prefix *group) { struct listnode *node; struct rp_info *rp_info; @@ -212,13 +215,13 @@ static struct rp_info *pim_rp_find_exact(struct pim_instance *pim, * Given a group, return the rp_info for that group */ static struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, - struct prefix *group) + const struct prefix *group) { struct listnode *node; struct rp_info *best = NULL; struct rp_info *rp_info; struct prefix_list *plist; - struct prefix *p, *bp; + const struct prefix *p, *bp; struct route_node *rn; bp = NULL; @@ -600,7 +603,6 @@ int pim_rp_del(struct pim_instance *pim, const char *rp, if (rp_info->plist) { XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist); - rp_info->plist = NULL; was_plist = true; } @@ -852,9 +854,9 @@ struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group) __PRETTY_FUNCTION__, buf, buf1); } pim_rpf_set_refresh_time(pim); - pim_ecmp_nexthop_lookup(pim, - &rp_info->rp.source_nexthop, - &nht_p, &rp_info->group, 1); + (void)pim_ecmp_nexthop_lookup( + pim, &rp_info->rp.source_nexthop, &nht_p, + &rp_info->group, 1); } return (&rp_info->rp); } diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 8f311391e1..fb0d6b5064 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -38,7 +38,6 @@ #include "pim_mroute.h" #include "pim_sock.h" #include "pim_str.h" -#include "pim_igmp_join.h" /* GLOBAL VARS */ @@ -322,26 +321,6 @@ int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr, return ret; } -int pim_socket_join_source(int fd, ifindex_t ifindex, struct in_addr group_addr, - struct in_addr source_addr, const char *ifname) -{ - if (pim_igmp_join_source(fd, ifindex, group_addr, source_addr)) { - char group_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<grp?>", group_addr, group_str, - sizeof(group_str)); - pim_inet4_dump("<src?>", source_addr, source_str, - sizeof(source_str)); - zlog_warn( - "%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s", - __PRETTY_FUNCTION__, fd, group_str, source_str, ifindex, - ifname, errno, safe_strerror(errno)); - return -1; - } - - return 0; -} - int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, struct sockaddr_in *from, socklen_t *fromlen, struct sockaddr_in *to, socklen_t *tolen, diff --git a/pimd/pim_sock.h b/pimd/pim_sock.h index 98db6fecd7..08b0099321 100644 --- a/pimd/pim_sock.h +++ b/pimd/pim_sock.h @@ -42,8 +42,6 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp, uint8_t loop); int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr, ifindex_t ifindex); -int pim_socket_join_source(int fd, ifindex_t ifindex, struct in_addr group_addr, - struct in_addr source_addr, const char *ifname); int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, struct sockaddr_in *from, socklen_t *fromlen, struct sockaddr_in *to, socklen_t *tolen, diff --git a/pimd/pim_ssm.c b/pimd/pim_ssm.c index d35f5cff7e..1f7cfcaa91 100644 --- a/pimd/pim_ssm.c +++ b/pimd/pim_ssm.c @@ -146,6 +146,11 @@ void *pim_ssm_init(void) void pim_ssm_terminate(struct pim_ssm *ssm) { - if (ssm && ssm->plist_name) + if (!ssm) + return; + + if (ssm->plist_name) XFREE(MTYPE_PIM_FILTER_NAME, ssm->plist_name); + + XFREE(MTYPE_PIM_SSM_INFO, ssm); } diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index e3488b6a66..db89125a98 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -192,7 +192,8 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, up->rpf.source_nexthop.interface = NULL; if (up->sg.src.s_addr != INADDR_ANY) { - wheel_remove_item(pim->upstream_sg_wheel, up); + if (pim->upstream_sg_wheel) + wheel_remove_item(pim->upstream_sg_wheel, up); notify_msdp = true; } @@ -1546,6 +1547,10 @@ void pim_upstream_terminate(struct pim_instance *pim) if (pim->upstream_hash) hash_free(pim->upstream_hash); pim->upstream_hash = NULL; + + if (pim->upstream_sg_wheel) + wheel_delete(pim->upstream_sg_wheel); + pim->upstream_sg_wheel = NULL; } int pim_upstream_equal(const void *arg1, const void *arg2) diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 862b2cc148..f4d833c26f 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -313,15 +313,6 @@ int pim_interface_config_write(struct vty *vty) ++writes; } - /* IF ip igmp query-interval */ - if (pim_ifp->igmp_default_query_interval - != IGMP_GENERAL_QUERY_INTERVAL) { - vty_out(vty, - " ip igmp query-interval %d\n", - pim_ifp->igmp_default_query_interval); - ++writes; - } - /* IF ip igmp query-max-response-time */ if (pim_ifp->igmp_query_max_response_time_dsec != IGMP_QUERY_MAX_RESPONSE_TIME_DSEC) { @@ -331,6 +322,15 @@ int pim_interface_config_write(struct vty *vty) ++writes; } + /* IF ip igmp query-interval */ + if (pim_ifp->igmp_default_query_interval + != IGMP_GENERAL_QUERY_INTERVAL) { + vty_out(vty, + " ip igmp query-interval %d\n", + pim_ifp->igmp_default_query_interval); + ++writes; + } + /* IF ip igmp join */ if (pim_ifp->igmp_join_list) { struct listnode *node; diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 38a29b72af..ab6258ad36 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -425,13 +425,91 @@ static int pim_zebra_if_address_del(int command, struct zclient *client, return 0; } +void pim_zebra_update_all_interfaces(struct pim_instance *pim) +{ + struct interface *ifp; + + FOR_ALL_INTERFACES (pim->vrf, ifp) { + struct pim_interface *pim_ifp = ifp->info; + struct pim_iface_upstream_switch *us; + struct listnode *node; + + if (!pim_ifp) + continue; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->upstream_switch_list, node, + us)) { + struct pim_rpf rpf; + + rpf.source_nexthop.interface = ifp; + rpf.rpf_addr.u.prefix4 = us->address; + pim_joinprune_send(&rpf, us->us); + pim_jp_agg_clear_group(us->us); + } + } +} + +void pim_zebra_upstream_rpf_changed(struct pim_instance *pim, + struct pim_upstream *up, + struct pim_rpf *old) +{ + struct pim_neighbor *nbr; + + nbr = pim_neighbor_find(old->source_nexthop.interface, + old->rpf_addr.u.prefix4); + if (nbr) + pim_jp_agg_remove_group(nbr->upstream_jp_agg, up); + + /* + * We have detected a case where we might need + * to rescan the inherited o_list so do it. + */ + if (up->channel_oil->oil_inherited_rescan) { + pim_upstream_inherited_olist_decide(pim, up); + up->channel_oil->oil_inherited_rescan = 0; + } + + if (up->join_state == PIM_UPSTREAM_JOINED) { + /* + * If we come up real fast we can be here + * where the mroute has not been installed + * so install it. + */ + if (!up->channel_oil->installed) + pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); + + /* + * RFC 4601: 4.5.7. Sending (S,G) + * Join/Prune Messages + * + * Transitions from Joined State + * + * RPF'(S,G) changes not due to an Assert + * + * The upstream (S,G) state machine remains + * in Joined state. Send Join(S,G) to the new + * upstream neighbor, which is the new value + * of RPF'(S,G). Send Prune(S,G) to the old + * upstream neighbor, which is the old value + * of RPF'(S,G). Set the Join Timer (JT) to + * expire after t_periodic seconds. + */ + pim_jp_agg_switch_interface(old, &up->rpf, up); + + pim_upstream_join_timer_restart(up, old); + } /* up->join_state == PIM_UPSTREAM_JOINED */ + + /* FIXME can join_desired actually be changed by + pim_rpf_update() + returning PIM_RPF_CHANGED ? */ + pim_upstream_update_join_desired(pim, up); +} + static void scan_upstream_rpf_cache(struct pim_instance *pim) { struct listnode *up_node; struct listnode *up_nextnode; - struct listnode *node; struct pim_upstream *up; - struct interface *ifp; for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) { enum pim_rpf_result rpf_result; @@ -450,80 +528,12 @@ static void scan_upstream_rpf_cache(struct pim_instance *pim) if (rpf_result == PIM_RPF_FAILURE) continue; - if (rpf_result == PIM_RPF_CHANGED) { - struct pim_neighbor *nbr; - - nbr = pim_neighbor_find(old.source_nexthop.interface, - old.rpf_addr.u.prefix4); - if (nbr) - pim_jp_agg_remove_group(nbr->upstream_jp_agg, - up); - - /* - * We have detected a case where we might need - * to rescan - * the inherited o_list so do it. - */ - if (up->channel_oil->oil_inherited_rescan) { - pim_upstream_inherited_olist_decide(pim, up); - up->channel_oil->oil_inherited_rescan = 0; - } - - if (up->join_state == PIM_UPSTREAM_JOINED) { - /* - * If we come up real fast we can be here - * where the mroute has not been installed - * so install it. - */ - if (!up->channel_oil->installed) - pim_mroute_add(up->channel_oil, - __PRETTY_FUNCTION__); - - /* - * RFC 4601: 4.5.7. Sending (S,G) - * Join/Prune Messages - * - * Transitions from Joined State - * - * RPF'(S,G) changes not due to an Assert - * - * The upstream (S,G) state machine remains - * in Joined state. Send Join(S,G) to the new - * upstream neighbor, which is the new value - * of RPF'(S,G). Send Prune(S,G) to the old - * upstream neighbor, which is the old value - * of RPF'(S,G). Set the Join Timer (JT) to - * expire after t_periodic seconds. - */ - pim_jp_agg_switch_interface(&old, &up->rpf, up); - - pim_upstream_join_timer_restart(up, &old); - } /* up->join_state == PIM_UPSTREAM_JOINED */ - - /* FIXME can join_desired actually be changed by - pim_rpf_update() - returning PIM_RPF_CHANGED ? */ - pim_upstream_update_join_desired(pim, up); - - } /* PIM_RPF_CHANGED */ + if (rpf_result == PIM_RPF_CHANGED) + pim_zebra_upstream_rpf_changed(pim, up, &old); } /* for (qpim_upstream_list) */ - FOR_ALL_INTERFACES (pim->vrf, ifp) - if (ifp->info) { - struct pim_interface *pim_ifp = ifp->info; - struct pim_iface_upstream_switch *us; - - for (ALL_LIST_ELEMENTS_RO(pim_ifp->upstream_switch_list, - node, us)) { - struct pim_rpf rpf; - - rpf.source_nexthop.interface = ifp; - rpf.rpf_addr.u.prefix4 = us->address; - pim_joinprune_send(&rpf, us->us); - pim_jp_agg_clear_group(us->us); - } - } + pim_zebra_update_all_interfaces(pim); } void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) @@ -868,6 +878,7 @@ void igmp_source_forward_reevaluate_all(struct pim_instance *pim) void igmp_source_forward_start(struct pim_instance *pim, struct igmp_source *source) { + struct pim_interface *pim_oif; struct igmp_group *group; struct prefix_sg sg; int result; @@ -893,10 +904,20 @@ void igmp_source_forward_start(struct pim_instance *pim, } group = source->source_group; + pim_oif = group->group_igmp_sock->interface->info; + if (!pim_oif) { + if (PIM_DEBUG_IGMP_TRACE) { + zlog_debug( + "%s: multicast not enabled on oif=%s ?", + __PRETTY_FUNCTION__, + source->source_group->group_igmp_sock + ->interface->name); + } + return; + } if (!source->source_channel_oil) { struct in_addr vif_source; - struct pim_interface *pim_oif; struct prefix nht_p, src, grp; struct pim_nexthop_cache out_pnc; struct pim_nexthop nexthop; @@ -983,19 +1004,6 @@ void igmp_source_forward_start(struct pim_instance *pim, source and receiver attached to the same interface. See TODO T22. */ - pim_oif = - source->source_group->group_igmp_sock->interface->info; - if (!pim_oif) { - if (PIM_DEBUG_IGMP_TRACE) { - zlog_debug( - "%s: multicast not enabled on oif=%s ?", - __PRETTY_FUNCTION__, - source->source_group->group_igmp_sock - ->interface->name); - } - return; - } - if (input_iface_vif_index == pim_oif->mroute_vif_index) { /* ignore request for looped MFC entry */ if (PIM_DEBUG_IGMP_TRACE) { @@ -1036,12 +1044,15 @@ void igmp_source_forward_start(struct pim_instance *pim, return; } + if (!(PIM_I_am_DR(pim_oif))) + return; + /* Feed IGMPv3-gathered local membership information into PIM per-interface (S,G) state. */ if (!pim_ifchannel_local_membership_add( - group->group_igmp_sock->interface, &sg)) { + group->group_igmp_sock->interface, &sg)) { if (PIM_DEBUG_MROUTE) zlog_warn("%s: Failure to add local membership for %s", __PRETTY_FUNCTION__, pim_str_sg_dump(&sg)); diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h index dd46fd40f9..c9ed89863c 100644 --- a/pimd/pim_zebra.h +++ b/pimd/pim_zebra.h @@ -46,4 +46,9 @@ void pim_forward_stop(struct pim_ifchannel *ch, bool install_it); void sched_rpf_cache_refresh(struct pim_instance *pim); struct zclient *pim_zebra_zclient_get(void); + +void pim_zebra_update_all_interfaces(struct pim_instance *pim); +void pim_zebra_upstream_rpf_changed(struct pim_instance *pim, + struct pim_upstream *up, + struct pim_rpf *old); #endif /* PIM_ZEBRA_H */ diff --git a/pimd/pimd.c b/pimd/pimd.c index 5f87102626..cb7b8b589a 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -79,8 +79,6 @@ static void pim_free() pim_route_map_terminate(); zclient_lookup_free(); - - zprivs_terminate(&pimd_privs); } void pim_init() diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index e2be7050d7..85fb309048 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -370,6 +370,10 @@ ln -s %{_sbindir}/frr %{buildroot}%{_initddir}/frr %endif install %{zeb_rh_src}/daemons %{buildroot}%{_sysconfdir}/frr +# add rpki module to daemon +%if %{with_rpki} + sed -i -e 's/^\(bgpd_options=\)\(.*\)\(".*\)/\1\2 -M rpki\3/' %{buildroot}%{_sysconfdir}/frr/daemons +%endif install -m644 %{zeb_rh_src}/frr.pam %{buildroot}%{_sysconfdir}/pam.d/frr install -m644 %{zeb_rh_src}/frr.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/frr install -d -m750 %{buildroot}%{rundir} diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 5a3f341205..58247f1622 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -514,14 +514,12 @@ static void rip_interface_reset(struct rip_interface *ri) ri->v2_broadcast = 0; - if (ri->auth_str) { - free(ri->auth_str); - ri->auth_str = NULL; - } - if (ri->key_chain) { - free(ri->key_chain); - ri->key_chain = NULL; - } + if (ri->auth_str) + XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str); + + if (ri->key_chain) + XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain); + ri->list[RIP_FILTER_IN] = NULL; ri->list[RIP_FILTER_OUT] = NULL; @@ -825,7 +823,8 @@ static int rip_enable_if_add(const char *ifname) if (ret >= 0) return -1; - vector_set(rip_enable_interface, strdup(ifname)); + vector_set(rip_enable_interface, + XSTRDUP(MTYPE_RIP_INTERFACE_STRING, ifname)); rip_enable_apply_all(); /* TODOVJ */ @@ -843,7 +842,7 @@ static int rip_enable_if_delete(const char *ifname) return -1; str = vector_slot(rip_enable_interface, index); - free(str); + XFREE(MTYPE_RIP_INTERFACE_STRING, str); vector_unset(rip_enable_interface, index); rip_enable_apply_all(); /* TODOVJ */ @@ -1062,7 +1061,7 @@ void rip_clean_network() /* rip_enable_interface. */ for (i = 0; i < vector_active(rip_enable_interface); i++) if ((str = vector_slot(rip_enable_interface, i)) != NULL) { - free(str); + XFREE(MTYPE_RIP_INTERFACE_STRING, str); vector_slot(rip_enable_interface, i) = NULL; } } @@ -1110,7 +1109,8 @@ static int rip_passive_nondefault_set(struct vty *vty, const char *ifname) if (rip_passive_nondefault_lookup(ifname) >= 0) return CMD_WARNING_CONFIG_FAILED; - vector_set(Vrip_passive_nondefault, strdup(ifname)); + vector_set(Vrip_passive_nondefault, + XSTRDUP(MTYPE_RIP_INTERFACE_STRING, ifname)); rip_passive_interface_apply_all(); @@ -1127,7 +1127,7 @@ static int rip_passive_nondefault_unset(struct vty *vty, const char *ifname) return CMD_WARNING_CONFIG_FAILED; str = vector_slot(Vrip_passive_nondefault, i); - free(str); + XFREE(MTYPE_RIP_INTERFACE_STRING, str); vector_unset(Vrip_passive_nondefault, i); rip_passive_interface_apply_all(); @@ -1143,7 +1143,7 @@ void rip_passive_nondefault_clean(void) for (i = 0; i < vector_active(Vrip_passive_nondefault); i++) if ((str = vector_slot(Vrip_passive_nondefault, i)) != NULL) { - free(str); + XFREE(MTYPE_RIP_INTERFACE_STRING, str); vector_slot(Vrip_passive_nondefault, i) = NULL; } rip_passive_interface_apply_all(); @@ -1529,9 +1529,9 @@ DEFUN (ip_rip_authentication_string, } if (ri->auth_str) - free(ri->auth_str); + XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str); - ri->auth_str = strdup(argv[idx_line]->arg); + ri->auth_str = XSTRDUP(MTYPE_RIP_INTERFACE_STRING, argv[idx_line]->arg); return CMD_SUCCESS; } @@ -1552,9 +1552,7 @@ DEFUN (no_ip_rip_authentication_string, ri = ifp->info; if (ri->auth_str) - free(ri->auth_str); - - ri->auth_str = NULL; + XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str); return CMD_SUCCESS; } @@ -1581,9 +1579,10 @@ DEFUN (ip_rip_authentication_key_chain, } if (ri->key_chain) - free(ri->key_chain); + XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain); - ri->key_chain = strdup(argv[idx_line]->arg); + ri->key_chain = + XSTRDUP(MTYPE_RIP_INTERFACE_STRING, argv[idx_line]->arg); return CMD_SUCCESS; } @@ -1604,9 +1603,7 @@ DEFUN (no_ip_rip_authentication_key_chain, ri = ifp->info; if (ri->key_chain) - free(ri->key_chain); - - ri->key_chain = NULL; + XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain); return CMD_SUCCESS; } diff --git a/ripd/rip_memory.c b/ripd/rip_memory.c index 4cdd3df048..1852410743 100644 --- a/ripd/rip_memory.c +++ b/ripd/rip_memory.c @@ -29,6 +29,7 @@ DEFINE_MGROUP(RIPD, "ripd") DEFINE_MTYPE(RIPD, RIP, "RIP structure") DEFINE_MTYPE(RIPD, RIP_INFO, "RIP route info") DEFINE_MTYPE(RIPD, RIP_INTERFACE, "RIP interface") +DEFINE_MTYPE(RIPD, RIP_INTERFACE_STRING, "RIP Interface String") DEFINE_MTYPE(RIPD, RIP_PEER, "RIP peer") DEFINE_MTYPE(RIPD, RIP_OFFSET_LIST, "RIP offset list") DEFINE_MTYPE(RIPD, RIP_DISTANCE, "RIP distance") diff --git a/ripd/rip_memory.h b/ripd/rip_memory.h index 57abedd3aa..29013ecec3 100644 --- a/ripd/rip_memory.h +++ b/ripd/rip_memory.h @@ -28,6 +28,7 @@ DECLARE_MGROUP(RIPD) DECLARE_MTYPE(RIP) DECLARE_MTYPE(RIP_INFO) DECLARE_MTYPE(RIP_INTERFACE) +DECLARE_MTYPE(RIP_INTERFACE_STRING) DECLARE_MTYPE(RIP_PEER) DECLARE_MTYPE(RIP_OFFSET_LIST) DECLARE_MTYPE(RIP_DISTANCE) diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c index 2c02324876..88473c164e 100644 --- a/ripd/rip_routemap.c +++ b/ripd/rip_routemap.c @@ -58,7 +58,8 @@ static void rip_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, +static route_map_result_t route_match_metric(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -111,7 +112,7 @@ 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, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -159,7 +160,7 @@ struct route_map_rule_cmd route_match_interface_cmd = { /* 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, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -206,7 +207,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 -route_match_ip_next_hop_prefix_list(void *rule, struct prefix *prefix, +route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; @@ -251,7 +252,7 @@ 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, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -290,7 +291,7 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = { /* `match ip address prefix-list PREFIX_LIST' */ static route_map_result_t -route_match_ip_address_prefix_list(void *rule, struct prefix *prefix, +route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; @@ -324,7 +325,7 @@ 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, +static route_map_result_t route_match_tag(void *rule, const struct prefix *p, route_map_object_t type, void *object) { route_tag_t *tag; @@ -354,7 +355,8 @@ 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, struct prefix *prefix, +static route_map_result_t route_set_metric(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -453,7 +455,7 @@ static struct route_map_rule_cmd route_set_metric_cmd = { /* 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, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -505,7 +507,7 @@ 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, +static route_map_result_t route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag; diff --git a/ripd/ripd.c b/ripd/ripd.c index 90dc7808eb..f7d6d3d929 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -828,7 +828,7 @@ static int rip_auth_simple_password(struct rte *rte, struct sockaddr_in *from, struct key *key; keychain = keychain_lookup(ri->key_chain); - if (keychain == NULL) + if (keychain == NULL || keychain->key == NULL) return 0; key = key_match_for_accept(keychain, auth_str); @@ -902,7 +902,7 @@ static int rip_auth_md5(struct rip_packet *packet, struct sockaddr_in *from, return 0; key = key_lookup_for_accept(keychain, md5->keyid); - if (key == NULL) + if (key == NULL || key->string == NULL) return 0; strncpy(auth_str, key->string, RIP_AUTH_MD5_SIZE); diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c index e9a38d137b..a18332516e 100644 --- a/ripngd/ripng_routemap.c +++ b/ripngd/ripng_routemap.c @@ -38,7 +38,8 @@ 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, struct prefix *prefix, +static route_map_result_t route_match_metric(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -86,7 +87,7 @@ 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, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -128,7 +129,8 @@ 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, struct prefix *prefix, +static route_map_result_t route_match_tag(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag; @@ -157,7 +159,8 @@ 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, struct prefix *prefix, +static route_map_result_t route_set_metric(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -254,7 +257,7 @@ static struct route_map_rule_cmd route_set_metric_cmd = { /* Set nexthop to object. ojbect must be pointer to struct attr. */ static route_map_result_t route_set_ipv6_nexthop_local(void *rule, - struct prefix *prefix, + const struct prefix *p, route_map_object_t type, void *object) { @@ -307,7 +310,8 @@ 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, struct prefix *prefix, +static route_map_result_t route_set_tag(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag; diff --git a/tests/bgpd/test_bgp_table.c b/tests/bgpd/test_bgp_table.c index 01ce7480d7..a0382827b9 100644 --- a/tests/bgpd/test_bgp_table.c +++ b/tests/bgpd/test_bgp_table.c @@ -116,8 +116,8 @@ static void check_lookup_result(struct list *list, va_list arglist) assert(prefix_count == listcount(list)); } -static void do_test(struct bgp_table *table, const char *prefix, uint8_t maxlen, - ...) +static void do_test(struct bgp_table *table, const char *prefix, + uint32_t maxlen, ...) { va_list arglist; struct list *list = list_new(); diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c index c75a699a16..4612bdc26b 100644 --- a/tests/bgpd/test_capability.c +++ b/tests/bgpd/test_capability.c @@ -821,6 +821,7 @@ static void parse_test(struct peer *peer, struct test_segment *t, int type) switch (type) { case CAPABILITY: len += 2; /* to cover the OPT-Param header */ + __attribute__ ((fallthrough)); case OPT_PARAM: printf("len: %u\n", len); /* peek_for_as4 wants getp at capibility*/ diff --git a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz Binary files differindex cca702b138..4abbe81499 100644 --- a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz +++ b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz diff --git a/tests/isisd/test_isis_vertex_queue.c b/tests/isisd/test_isis_vertex_queue.c index 0e473d7a6b..3e31b83351 100644 --- a/tests/isisd/test_isis_vertex_queue.c +++ b/tests/isisd/test_isis_vertex_queue.c @@ -16,43 +16,42 @@ static size_t vertex_count; static void setup_test_vertices(void) { - struct prefix p = { - .family = AF_UNSPEC + union isis_N nid, nip = { + .ip.dest.family = AF_UNSPEC }; - uint8_t node_id[7]; vertices = XMALLOC(MTYPE_TMP, sizeof(*vertices) * 16); - p.family = AF_INET; - p.prefixlen = 24; - inet_pton(AF_INET, "192.168.1.0", &p.u.prefix4); - vertices[vertex_count] = isis_vertex_new(&p, VTYPE_IPREACH_TE); + nip.ip.dest.family = AF_INET; + nip.ip.dest.prefixlen = 24; + inet_pton(AF_INET, "192.168.1.0", &nip.ip.dest.u.prefix4); + vertices[vertex_count] = isis_vertex_new(&nip, VTYPE_IPREACH_TE); vertices[vertex_count]->d_N = 20; vertex_count++; - p.family = AF_INET; - p.prefixlen = 24; - inet_pton(AF_INET, "192.168.2.0", &p.u.prefix4); - vertices[vertex_count] = isis_vertex_new(&p, VTYPE_IPREACH_TE); + nip.ip.dest.family = AF_INET; + nip.ip.dest.prefixlen = 24; + inet_pton(AF_INET, "192.168.2.0", &nip.ip.dest.u.prefix4); + vertices[vertex_count] = isis_vertex_new(&nip, VTYPE_IPREACH_TE); vertices[vertex_count]->d_N = 20; vertex_count++; - memset(node_id, 0, sizeof(node_id)); - node_id[6] = 1; - vertices[vertex_count] = isis_vertex_new(node_id, VTYPE_PSEUDO_TE_IS); + memset(nid.id, 0, sizeof(nid.id)); + nid.id[6] = 1; + vertices[vertex_count] = isis_vertex_new(&nid, VTYPE_PSEUDO_TE_IS); vertices[vertex_count]->d_N = 15; vertex_count++; - memset(node_id, 0, sizeof(node_id)); - node_id[5] = 2; - vertices[vertex_count] = isis_vertex_new(node_id, VTYPE_NONPSEUDO_TE_IS); + memset(nid.id, 0, sizeof(nid.id)); + nid.id[5] = 2; + vertices[vertex_count] = isis_vertex_new(&nid, VTYPE_NONPSEUDO_TE_IS); vertices[vertex_count]->d_N = 15; vertex_count++; - p.family = AF_INET; - p.prefixlen = 24; - inet_pton(AF_INET, "192.168.3.0", &p.u.prefix4); - vertices[vertex_count] = isis_vertex_new(&p, VTYPE_IPREACH_TE); + nip.ip.dest.family = AF_INET; + nip.ip.dest.prefixlen = 24; + inet_pton(AF_INET, "192.168.3.0", &nip.ip.dest.u.prefix4); + vertices[vertex_count] = isis_vertex_new(&nip, VTYPE_IPREACH_TE); vertices[vertex_count]->d_N = 20; vertex_count++; }; @@ -76,23 +75,23 @@ static void test_ordered(void) assert(isis_vertex_queue_count(&q) == vertex_count); for (size_t i = 0; i < vertex_count; i++) { - assert(isis_find_vertex(&q, vertices[i]->N.id, vertices[i]->type) == vertices[i]); + assert(isis_find_vertex(&q, &vertices[i]->N, vertices[i]->type) == vertices[i]); } assert(isis_vertex_queue_pop(&q) == vertices[2]); - assert(isis_find_vertex(&q, vertices[2]->N.id, vertices[2]->type) == NULL); + assert(isis_find_vertex(&q, &vertices[2]->N, vertices[2]->type) == NULL); assert(isis_vertex_queue_pop(&q) == vertices[3]); - assert(isis_find_vertex(&q, vertices[3]->N.id, vertices[3]->type) == NULL); + assert(isis_find_vertex(&q, &vertices[3]->N, vertices[3]->type) == NULL); assert(isis_vertex_queue_pop(&q) == vertices[0]); - assert(isis_find_vertex(&q, vertices[0]->N.id, vertices[0]->type) == NULL); + assert(isis_find_vertex(&q, &vertices[0]->N, vertices[0]->type) == NULL); assert(isis_vertex_queue_pop(&q) == vertices[1]); - assert(isis_find_vertex(&q, vertices[1]->N.id, vertices[1]->type) == NULL); + assert(isis_find_vertex(&q, &vertices[1]->N, vertices[1]->type) == NULL); isis_vertex_queue_delete(&q, vertices[4]); - assert(isis_find_vertex(&q, vertices[4]->N.id, vertices[4]->type) == NULL); + assert(isis_find_vertex(&q, &vertices[4]->N, vertices[4]->type) == NULL); assert(isis_vertex_queue_count(&q) == 0); assert(isis_vertex_queue_pop(&q) == NULL); diff --git a/tests/lib/test_srcdest_table.c b/tests/lib/test_srcdest_table.c index 53180564bd..e717da15b3 100644 --- a/tests/lib/test_srcdest_table.c +++ b/tests/lib/test_srcdest_table.c @@ -392,7 +392,8 @@ static void test_state_del_one_route(struct test_state *test, struct prng *prng) } assert(rn); - srcdest_rnode_prefixes(rn, &dst_p, &src_p); + srcdest_rnode_prefixes(rn, (const struct prefix **)&dst_p, + (const struct prefix **)&src_p); memcpy(&dst6_p, dst_p, sizeof(dst6_p)); if (src_p) memcpy(&src6_p, src_p, sizeof(src6_p)); diff --git a/tools/checkpatch.sh b/tools/checkpatch.sh index e1fb529d35..6071f4804d 100755 --- a/tools/checkpatch.sh +++ b/tools/checkpatch.sh @@ -72,12 +72,13 @@ else echo "Done." for file in ${tmp1}/*_cp; do if [ -a ${tmp2}/$(basename $file) ]; then - result=$(diff $file ${tmp2}/$(basename $file) | grep -A3 "ERROR\|WARNING" | grep -A2 -B2 "${tmp1}") + result=$(diff $file ${tmp2}/$(basename $file) | awk '/< ERROR|< WARNING/,/^< $|^< #|^<[^ ]/ { print $0; ++n }; END { exit n }') else - result=$(cat $file | grep -A3 "ERROR\|WARNING" | grep -A2 -B2 "${tmp1}") + result=$(cat $file | awk '/ERROR|WARNING/,/^$/ { print $0; ++n }; END { exit n }') fi - if [ "$?" -eq "0" ]; then - echo "Report for $(basename $file _cp)" 1>&2 + ni="$?" + if [ "$ni" -ne "0" ]; then + echo "Report for $(basename $file _cp) | $ni issues" 1>&2 echo "===============================================" 1>&2 echo "$result" 1>&2 if echo $result | grep -q "ERROR"; then @@ -574,7 +574,11 @@ case "$1" in reload) # Just apply the commands that have changed, no restart necessary - [ ! -x "$RELOAD_SCRIPT" ] && echo "frr-reload script not available" && exit 0 + if [ ! -x "$RELOAD_SCRIPT" ]; then + echo "Please install frr-pythontools package. Required for reload" + exit 0 + fi + NEW_CONFIG_FILE="${2:-$C_PATH/frr.conf}" [ ! -r $NEW_CONFIG_FILE ] && echo "Unable to read new configuration file $NEW_CONFIG_FILE" && exit 1 echo "Applying only incremental changes to running configuration from frr.conf" diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 208fb116e6..a9f183ed7b 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -403,7 +403,7 @@ end self.save_contexts(ctx_keys, current_context_lines) new_ctx = True - elif line == "end": + elif line in ["end", "exit-vrf"]: self.save_contexts(ctx_keys, current_context_lines) log.debug('LINE %-50s: exiting old context, %-50s', line, ctx_keys) diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 5516d73f4e..52ab28dfda 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -179,6 +179,9 @@ void vtysh_config_parse_line(void *arg, const char *line) strlen(" ip multicast boundary")) == 0) { config_add_line_end(config->line, line); + } else if (strncmp(line, " ip igmp query-interval", + strlen(" ip igmp query-interval")) == 0) { + config_add_line_end(config->line, line); } else if (config->index == LINK_PARAMS_NODE && strncmp(line, " exit-link-params", strlen(" exit")) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 8f6e31cfa8..56e27e6dc8 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -891,8 +891,12 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) zns = zebra_ns_lookup(ns_id); ifa = NLMSG_DATA(h); - if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) + if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) { + zlog_warn( + "Invalid address family: %u received from kernel interface addr change: %u", + ifa->ifa_family, h->nlmsg_type); return 0; + } if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR) return 0; @@ -991,6 +995,12 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* Register interface address to the interface. */ if (ifa->ifa_family == AF_INET) { + if (ifa->ifa_prefixlen > IPV4_MAX_BITLEN) { + zlog_err( + "Invalid prefix length: %u received from kernel interface addr change: %u", + ifa->ifa_prefixlen, h->nlmsg_type); + return -1; + } if (h->nlmsg_type == RTM_NEWADDR) connected_add_ipv4(ifp, flags, (struct in_addr *)addr, ifa->ifa_prefixlen, @@ -1001,6 +1011,12 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) ifa->ifa_prefixlen, (struct in_addr *)broad); } if (ifa->ifa_family == AF_INET6) { + if (ifa->ifa_prefixlen > IPV6_MAX_BITLEN) { + zlog_err( + "Invalid prefix length: %u received from kernel interface addr change: %u", + ifa->ifa_prefixlen, h->nlmsg_type); + return -1; + } if (h->nlmsg_type == RTM_NEWADDR) { /* Only consider valid addresses; we'll not get a * notification from @@ -1114,6 +1130,14 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) return 0; } + if (!(ifi->ifi_family == AF_UNSPEC || ifi->ifi_family == AF_BRIDGE + || ifi->ifi_family == AF_INET6)) { + zlog_warn( + "Invalid address family: %u received from kernel link change: %u", + ifi->ifi_family, h->nlmsg_type); + return 0; + } + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg)); if (len < 0) { zlog_err("%s: Message received from netlink is of a broken size %d %zu", @@ -1218,6 +1242,12 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* Update interface information. */ set_ifindex(ifp, ifi->ifi_index, zns); ifp->flags = ifi->ifi_flags & 0x0000fffff; + if (!tb[IFLA_MTU]) { + zlog_warn( + "RTM_NEWLINK for interface %s(%u) without MTU set", + name, ifi->ifi_index); + return 0; + } ifp->mtu6 = ifp->mtu = *(int *)RTA_DATA(tb[IFLA_MTU]); ifp->metric = 0; ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; @@ -1267,6 +1297,12 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) bridge_ifindex, ifi->ifi_flags); set_ifindex(ifp, ifi->ifi_index, zns); + if (!tb[IFLA_MTU]) { + zlog_warn( + "RTM_NEWLINK for interface %s(%u) without MTU set", + name, ifi->ifi_index); + return 0; + } ifp->mtu6 = ifp->mtu = *(int *)RTA_DATA(tb[IFLA_MTU]); ifp->metric = 0; diff --git a/zebra/interface.c b/zebra/interface.c index 6125ff9a16..1067f9bdc1 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1417,7 +1417,7 @@ DEFUN (show_interface, interface_update_stats(); if (argc > 2) - VRF_GET_ID(vrf_id, argv[3]->arg); + VRF_GET_ID(vrf_id, argv[3]->arg, false); /* All interface print. */ vrf = vrf_lookup_by_id(vrf_id); @@ -1466,7 +1466,7 @@ DEFUN (show_interface_name_vrf, interface_update_stats(); - VRF_GET_ID(vrf_id, argv[idx_name]->arg); + VRF_GET_ID(vrf_id, argv[idx_name]->arg, false); /* Specified interface print. */ ifp = if_lookup_by_name(argv[idx_ifname]->arg, vrf_id); @@ -1560,7 +1560,7 @@ DEFUN (show_interface_desc, vrf_id_t vrf_id = VRF_DEFAULT; if (argc > 3) - VRF_GET_ID(vrf_id, argv[4]->arg); + VRF_GET_ID(vrf_id, argv[4]->arg, false); if_show_description(vty, vrf_id); diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 8703b01319..a5c2cd69f3 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -20,6 +20,11 @@ #include <zebra.h> +#if defined(HANDLE_NETLINK_FUZZING) +#include <stdio.h> +#include <string.h> +#endif /* HANDLE_NETLINK_FUZZING */ + #ifdef HAVE_NETLINK #include "linklist.h" @@ -293,6 +298,81 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, return 0; } +#if defined(HANDLE_NETLINK_FUZZING) +/* Using globals here to avoid adding function parameters */ + +/* Keep distinct filenames for netlink fuzzy collection */ +static unsigned int netlink_file_counter = 1; + +/* File name to read fuzzed netlink from */ +static char netlink_fuzz_file[MAXPATHLEN] = ""; + +/* Flag for whether to read from file or not */ +bool netlink_read; + +/** + * netlink_read_init() - Starts the message parser + * @fname: Filename to read. + */ +void netlink_read_init(const char *fname) +{ + snprintf(netlink_fuzz_file, MAXPATHLEN, "%s", fname); + /* Creating this fake socket for testing purposes */ + struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); + + netlink_parse_info(netlink_information_fetch, &zns->netlink, zns, 1, 0); +} + +/** + * netlink_write_incoming() - Writes all data received from netlink to a file + * @buf: Data from netlink. + * @size: Size of data. + * @counter: Counter for keeping filenames distinct. + */ +static void netlink_write_incoming(const char *buf, const unsigned int size, + unsigned int counter) +{ + char fname[MAXPATHLEN]; + FILE *f; + + zserv_privs.change(ZPRIVS_RAISE); + snprintf(fname, MAXPATHLEN, "%s/%s_%u", DAEMON_VTY_DIR, "netlink", + counter); + f = fopen(fname, "w"); + if (f) { + fwrite(buf, 1, size, f); + fclose(f); + } + zserv_privs.change(ZPRIVS_LOWER); +} + +/** + * netlink_read_file() - Reads netlink data from file + * @buf: Netlink buffer being overwritten. + * @fname: File name to read from. + * + * Return: Size of file. + */ +static long netlink_read_file(char *buf, const char *fname) +{ + FILE *f; + long file_bytes = -1; + + zserv_privs.change(ZPRIVS_RAISE); + f = fopen(fname, "r"); + if (f) { + fseek(f, 0, SEEK_END); + file_bytes = ftell(f); + rewind(f); + fread(buf, NL_RCV_PKT_BUF_SIZE, 1, f); + fclose(f); + } + zserv_privs.change(ZPRIVS_LOWER); + return file_bytes; +} + +#endif /* HANDLE_NETLINK_FUZZING */ + static int kernel_read(struct thread *thread) { struct zebra_ns *zns = (struct zebra_ns *)THREAD_ARG(thread); @@ -602,7 +682,18 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), if (count && read_in >= count) return 0; +#if defined(HANDLE_NETLINK_FUZZING) + /* Check if reading and filename is set */ + if (netlink_read && '\0' != netlink_fuzz_file[0]) { + zlog_debug("Reading netlink fuzz file"); + status = netlink_read_file(buf, netlink_fuzz_file); + snl.nl_pid = 0; + } else { + status = recvmsg(nl->sock, &msg, 0); + } +#else status = recvmsg(nl->sock, &msg, 0); +#endif /* HANDLE_NETLINK_FUZZING */ if (status < 0) { if (errno == EINTR) continue; @@ -636,9 +727,17 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), zlog_hexdump(buf, status); } +#if defined(HANDLE_NETLINK_FUZZING) + if (!netlink_read) { + zlog_debug("Writing incoming netlink message"); + netlink_write_incoming(buf, status, + netlink_file_counter++); + } +#endif /* HANDLE_NETLINK_FUZZING */ + read_in++; for (h = (struct nlmsghdr *)buf; - NLMSG_OK(h, (unsigned int)status); + (status >= 0 && NLMSG_OK(h, (unsigned int)status)); h = NLMSG_NEXT(h, status)) { /* Finish of reading. */ if (h->nlmsg_type == NLMSG_DONE) @@ -986,6 +1085,7 @@ void kernel_init(struct zebra_ns *zns) if (nl_rcvbufsize) netlink_recvbuf(&zns->netlink, nl_rcvbufsize); + assert(zns->netlink.sock >= 0); netlink_install_filter(zns->netlink.sock, zns->netlink_cmd.snl.nl_pid); zns->t_netlink = NULL; diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index 80bb876e0b..65df15599d 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -45,6 +45,10 @@ extern const char *nl_rtproto_to_str(uint8_t rtproto); extern const char *nl_family_to_str(uint8_t family); extern const char *nl_rttype_to_str(uint8_t rttype); +#if defined(HANDLE_NETLINK_FUZZING) +extern bool netlink_read; +extern void netlink_read_init(const char *fname); +#endif /* HANDLE_NETLINK_FUZZING */ extern int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), struct nlsock *nl, struct zebra_ns *zns, int count, int startup); diff --git a/zebra/main.c b/zebra/main.c index 3e44a41707..4eeba8549a 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -54,6 +54,10 @@ #include "zebra/zebra_rnh.h" #include "zebra/zebra_pbr.h" +#if defined(HANDLE_NETLINK_FUZZING) +#include "zebra/kernel_netlink.h" +#endif /* HANDLE_NETLINK_FUZZING */ + #define ZEBRA_PTM_SUPPORT /* Zebra instance */ @@ -134,11 +138,16 @@ static void sigint(void) { struct vrf *vrf; struct zebra_vrf *zvrf; + struct listnode *ln, *nn; + struct zserv *client; zlog_notice("Terminating on signal"); frr_early_fini(); + for (ALL_LIST_ELEMENTS(zebrad.client_list, ln, nn, client)) + zserv_close_client(client); + list_delete_all_node(zebrad.client_list); zebra_ptm_finish(); @@ -213,8 +222,11 @@ int main(int argc, char **argv) struct sockaddr_storage dummy; socklen_t dummylen; #if defined(HANDLE_ZAPI_FUZZING) - char *fuzzing = NULL; -#endif + char *zapi_fuzzing = NULL; +#endif /* HANDLE_ZAPI_FUZZING */ +#if defined(HANDLE_NETLINK_FUZZING) + char *netlink_fuzzing = NULL; +#endif /* HANDLE_NETLINK_FUZZING */ vrf_configure_backend(VRF_BACKEND_VRF_LITE); logicalrouter_configure_backend(LOGICALROUTER_BACKEND_NETNS); @@ -228,7 +240,10 @@ int main(int argc, char **argv) #endif #if defined(HANDLE_ZAPI_FUZZING) "c:" -#endif +#endif /* HANDLE_ZAPI_FUZZING */ +#if defined(HANDLE_NETLINK_FUZZING) + "w:" +#endif /* HANDLE_NETLINK_FUZZING */ , longopts, " -b, --batch Runs in batch mode\n" @@ -244,8 +259,11 @@ int main(int argc, char **argv) " --v6-rr-semantics Use v6 RR semantics\n" #endif /* HAVE_NETLINK */ #if defined(HANDLE_ZAPI_FUZZING) - " -c <file> Bypass normal startup and use this file for testing of zapi" -#endif + " -c <file> Bypass normal startup and use this file for testing of zapi\n" +#endif /* HANDLE_ZAPI_FUZZING */ +#if defined(HANDLE_NETLINK_FUZZING) + " -w <file> Bypass normal startup and use this file for testing of netlink input\n" +#endif /* HANDLE_NETLINK_FUZZING */ ); while (1) { @@ -306,9 +324,19 @@ int main(int argc, char **argv) #endif /* HAVE_NETLINK */ #if defined(HANDLE_ZAPI_FUZZING) case 'c': - fuzzing = optarg; + zapi_fuzzing = optarg; break; -#endif +#endif /* HANDLE_ZAPI_FUZZING */ +#if defined(HANDLE_NETLINK_FUZZING) + case 'w': + netlink_fuzzing = optarg; + /* This ensures we are aren't writing any of the + * startup netlink messages that happen when we + * just want to read. + */ + netlink_read = true; + break; +#endif /* HANDLE_NETLINK_FUZZING */ default: frr_help_exit(1); break; @@ -385,11 +413,17 @@ int main(int argc, char **argv) zebra_rnh_init(); #if defined(HANDLE_ZAPI_FUZZING) - if (fuzzing) { - zserv_read_file(fuzzing); + if (zapi_fuzzing) { + zserv_read_file(zapi_fuzzing); exit(0); } -#endif +#endif /* HANDLE_ZAPI_FUZZING */ +#if defined(HANDLE_NETLINK_FUZZING) + if (netlink_fuzzing) { + netlink_read_init(netlink_fuzzing); + exit(0); + } +#endif /* HANDLE_NETLINK_FUZZING */ frr_run(zebrad.master); diff --git a/zebra/router-id.c b/zebra/router-id.c index 252b558a8b..3b96b3371d 100644 --- a/zebra/router-id.c +++ b/zebra/router-id.c @@ -226,7 +226,7 @@ DEFUN (router_id, rid.family = AF_INET; if (argc > 2) - VRF_GET_ID(vrf_id, argv[idx_name]->arg); + VRF_GET_ID(vrf_id, argv[idx_name]->arg, false); router_id_set(&rid, vrf_id); @@ -251,7 +251,7 @@ DEFUN (no_router_id, rid.family = AF_INET; if (argc > 3) - VRF_GET_ID(vrf_id, argv[idx_name]->arg); + VRF_GET_ID(vrf_id, argv[idx_name]->arg, false); router_id_set(&rid, vrf_id); diff --git a/zebra/rt.h b/zebra/rt.h index 57e62e4f6e..e40bae3a3e 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -122,7 +122,7 @@ extern int kernel_del_mac(struct interface *ifp, vlanid_t vid, int local); extern int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip, - struct ethaddr *mac); + struct ethaddr *mac, uint8_t flags); extern int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip); /* diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 485abc3f12..4a13fbc8e1 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -384,29 +384,46 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, if (rtm->rtm_family == AF_INET) { p.family = AF_INET; + if (rtm->rtm_dst_len > IPV4_MAX_BITLEN) { + zlog_err( + "Invalid destination prefix length: %u received from kernel route change", + rtm->rtm_dst_len); + return -1; + } memcpy(&p.u.prefix4, dest, 4); p.prefixlen = rtm->rtm_dst_len; - src_p.prefixlen = - 0; // Forces debug below to not display anything + if (rtm->rtm_src_len != 0) { + char buf[PREFIX_STRLEN]; + zlog_warn("unsupported IPv4 sourcedest route (dest %s vrf %u)", + prefix2str(&p, buf, sizeof(buf)), vrf_id); + return 0; + } + + /* Force debug below to not display anything for source */ + src_p.prefixlen = 0; } else if (rtm->rtm_family == AF_INET6) { p.family = AF_INET6; + if (rtm->rtm_dst_len > IPV6_MAX_BITLEN) { + zlog_err( + "Invalid destination prefix length: %u received from kernel route change", + rtm->rtm_dst_len); + return -1; + } memcpy(&p.u.prefix6, dest, 16); p.prefixlen = rtm->rtm_dst_len; src_p.family = AF_INET6; + if (rtm->rtm_src_len > IPV6_MAX_BITLEN) { + zlog_err( + "Invalid source prefix length: %u received from kernel route change", + rtm->rtm_src_len); + return -1; + } memcpy(&src_p.prefix, src, 16); src_p.prefixlen = rtm->rtm_src_len; } - if (rtm->rtm_src_len != 0) { - char buf[PREFIX_STRLEN]; - zlog_warn( - "unsupported IPv[4|6] sourcedest route (dest %s vrf %u)", - prefix2str(&p, buf, sizeof(buf)), vrf_id); - return 0; - } - /* * For ZEBRA_ROUTE_KERNEL types: * @@ -492,7 +509,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, nh.vrf_id = nh_vrf_id; rib_add(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p, - NULL, &nh, table, metric, mtu, distance, tag); + &src_p, &nh, table, metric, mtu, distance, tag); } else { /* This is a multipath route */ @@ -581,6 +598,9 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, route_entry_nexthop_ifindex_add( re, index, nh_vrf_id); + if (rtnh->rtnh_len == 0) + break; + len -= NLMSG_ALIGN(rtnh->rtnh_len); rtnh = RTNH_NEXT(rtnh); } @@ -591,8 +611,8 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, if (re->nexthop_num == 0) XFREE(MTYPE_RE, re); else - rib_add_multipath(afi, SAFI_UNICAST, &p, NULL, - re); + rib_add_multipath(afi, SAFI_UNICAST, &p, + &src_p, re); } } else { if (!tb[RTA_MULTIPATH]) { @@ -624,12 +644,12 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, if (gate) memcpy(&nh.gate, gate, sz); rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, - &p, NULL, &nh, table, metric, true); + &p, &src_p, &nh, table, metric, true); } else { /* XXX: need to compare the entire list of nexthops * here for NLM_F_APPEND stupidity */ rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, - &p, NULL, NULL, table, metric, true); + &p, &src_p, NULL, table, metric, true); } } @@ -701,6 +721,9 @@ static int netlink_route_change_read_multicast(struct nlmsghdr *h, oif[oif_count] = rtnh->rtnh_ifindex; oif_count++; + if (rtnh->rtnh_len == 0) + break; + len -= NLMSG_ALIGN(rtnh->rtnh_len); rtnh = RTNH_NEXT(rtnh); } @@ -740,6 +763,13 @@ int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) return 0; } + if (!(rtm->rtm_family == AF_INET || rtm->rtm_family == AF_INET6)) { + zlog_warn( + "Invalid address family: %u received from kernel route change: %u", + rtm->rtm_family, h->nlmsg_type); + return 0; + } + /* Connected route. */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("%s %s %s proto %s NS %u", @@ -748,10 +778,6 @@ int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) nl_rttype_to_str(rtm->rtm_type), nl_rtproto_to_str(rtm->rtm_protocol), ns_id); - /* We don't care about change notifications for the MPLS table. */ - /* TODO: Revisit this. */ - if (rtm->rtm_family == AF_MPLS) - return 0; len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); if (len < 0) { @@ -2151,6 +2177,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) char buf2[INET6_ADDRSTRLEN]; int mac_present = 0; uint8_t ext_learned; + uint8_t router_flag; ndm = NLMSG_DATA(h); @@ -2241,6 +2268,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) } ext_learned = (ndm->ndm_flags & NTF_EXT_LEARNED) ? 1 : 0; + router_flag = (ndm->ndm_flags & NTF_ROUTER) ? 1 : 0; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( @@ -2263,7 +2291,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) if (ndm->ndm_state & NUD_VALID) return zebra_vxlan_handle_kernel_neigh_update( ifp, link_if, &ip, &mac, ndm->ndm_state, - ext_learned); + ext_learned, router_flag); return zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip); } @@ -2386,12 +2414,19 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id) if (ndm->ndm_family == AF_INET || ndm->ndm_family == AF_INET6) return netlink_ipneigh_change(h, len, ns_id); + else { + zlog_warn( + "Invalid address family: %u received from kernel neighbor change: %u", + ndm->ndm_family, h->nlmsg_type); + return 0; + } return 0; } static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip, - struct ethaddr *mac, uint32_t flags, int cmd) + struct ethaddr *mac, uint8_t flags, + uint16_t state, int cmd) { struct { struct nlmsghdr n; @@ -2414,11 +2449,10 @@ static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip, req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE); req.n.nlmsg_type = cmd; // RTM_NEWNEIGH or RTM_DELNEIGH req.ndm.ndm_family = IS_IPADDR_V4(ip) ? AF_INET : AF_INET6; - req.ndm.ndm_state = flags; + req.ndm.ndm_state = state; req.ndm.ndm_ifindex = ifp->ifindex; req.ndm.ndm_type = RTN_UNICAST; - req.ndm.ndm_flags = NTF_EXT_LEARNED; - + req.ndm.ndm_flags = flags; ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN; addattr_l(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len); @@ -2426,12 +2460,12 @@ static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip, addattr_l(&req.n, sizeof(req), NDA_LLADDR, mac, 6); if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Tx %s family %s IF %s(%u) Neigh %s MAC %s", + zlog_debug("Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x", nl_msg_type_to_str(cmd), nl_family_to_str(req.ndm.ndm_family), ifp->name, ifp->ifindex, ipaddr2str(ip, buf, sizeof(buf)), mac ? prefix_mac2str(mac, buf2, sizeof(buf2)) - : "null"); + : "null", flags); return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); @@ -2452,14 +2486,15 @@ int kernel_del_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac, } int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip, - struct ethaddr *mac) + struct ethaddr *mac, uint8_t flags) { - return netlink_neigh_update2(ifp, ip, mac, NUD_NOARP, RTM_NEWNEIGH); + return netlink_neigh_update2(ifp, ip, mac, flags, + NUD_NOARP, RTM_NEWNEIGH); } int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip) { - return netlink_neigh_update2(ifp, ip, NULL, 0, RTM_DELNEIGH); + return netlink_neigh_update2(ifp, ip, NULL, 0, 0, RTM_DELNEIGH); } /* diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index cba0376300..346699198f 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -88,7 +88,8 @@ static int kernel_rtm_add_labels(struct mpls_label_stack *nh_label, #endif /* Interface between zebra message and rtm message. */ -static int kernel_rtm_ipv4(int cmd, struct prefix *p, struct route_entry *re) +static int kernel_rtm_ipv4(int cmd, const struct prefix *p, + struct route_entry *re) { struct sockaddr_in *mask = NULL; @@ -272,7 +273,8 @@ static int sin6_masklen(struct in6_addr mask) #endif /* SIN6_LEN */ /* Interface between zebra message and rtm message. */ -static int kernel_rtm_ipv6(int cmd, struct prefix *p, struct route_entry *re) +static int kernel_rtm_ipv6(int cmd, const struct prefix *p, + struct route_entry *re) { struct sockaddr_in6 *mask; struct sockaddr_in6 sin_dest, sin_mask, sin_gate; @@ -374,7 +376,7 @@ static int kernel_rtm_ipv6(int cmd, struct prefix *p, struct route_entry *re) return 0; /*XXX*/ } -static int kernel_rtm(int cmd, struct prefix *p, struct route_entry *re) +static int kernel_rtm(int cmd, const struct prefix *p, struct route_entry *re) { switch (PREFIX_FAMILY(p)) { case AF_INET: @@ -460,7 +462,7 @@ int kernel_del_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac, } int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip, - struct ethaddr *mac) + struct ethaddr *mac, uint8_t flags) { return 0; } diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index c7a8517e17..87d3769a5a 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -204,8 +204,12 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) } frh = NLMSG_DATA(h); - if (frh->family != AF_INET && frh->family != AF_INET6) + if (frh->family != AF_INET && frh->family != AF_INET6) { + zlog_warn( + "Invalid address family: %u received from kernel rule change: %u", + frh->family, h->nlmsg_type); return 0; + } if (frh->action != FR_ACT_TO_TBL) return 0; diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c index 60b72298a1..2dd686fd0d 100644 --- a/zebra/zebra_netns_notify.c +++ b/zebra/zebra_netns_notify.c @@ -105,6 +105,7 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name) if (ret != CMD_SUCCESS) { zlog_warn("NS notify : failed to create NS %s", netnspath); ns_map_nsid_with_external(ns_id, false); + vrf_delete(vrf); return; } zlog_info("NS notify : created VRF %s NS %s", name, netnspath); diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 74ef25b031..e2217a5d2b 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -832,6 +832,7 @@ struct zebra_pbr_ipset_entry_unique_display { struct zebra_pbr_env_display { struct zebra_ns *zns; struct vty *vty; + char *name; }; static const char *zebra_pbr_prefix2str(union prefixconstptr pu, @@ -1037,6 +1038,7 @@ void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname) } uniqueipset.zns = zns; uniqueipset.vty = vty; + uniqueipset.name = NULL; hash_walk(zns->ipset_hash, zebra_pbr_show_ipset_walkcb, &uniqueipset); } @@ -1060,19 +1062,25 @@ static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_backet *backet, return HASHWALK_CONTINUE; } -static int zebra_pbr_show_iptable_walkcb(struct hash_backet *backet, void *arg) +static void zebra_pbr_show_iptable_unit(struct zebra_pbr_iptable *iptable, + struct vty *vty, + struct zebra_ns *zns) { - struct zebra_pbr_iptable *iptable = - (struct zebra_pbr_iptable *)backet->data; - struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg; - struct vty *vty = env->vty; - struct zebra_ns *zns = env->zns; int ret; uint64_t pkts = 0, bytes = 0; vty_out(vty, "IPtable %s action %s (%u)\n", iptable->ipset_name, iptable->action == ZEBRA_IPTABLES_DROP ? "drop" : "redirect", iptable->unique); + if (iptable->type == IPSET_NET_PORT || + iptable->type == IPSET_NET_PORT_NET) { + if (!(iptable->filter_bm & MATCH_ICMP_SET)) { + if (iptable->filter_bm & PBR_FILTER_DST_PORT) + vty_out(vty, "\t lookup dst port\n"); + else if (iptable->filter_bm & PBR_FILTER_SRC_PORT) + vty_out(vty, "\t lookup src port\n"); + } + } if (iptable->pkt_len_min || iptable->pkt_len_max) { if (!iptable->pkt_len_max) vty_out(vty, "\t pkt len %u\n", @@ -1129,17 +1137,34 @@ static int zebra_pbr_show_iptable_walkcb(struct hash_backet *backet, void *arg) prfl.fwmark); } } +} + +static int zebra_pbr_show_iptable_walkcb(struct hash_backet *backet, void *arg) +{ + struct zebra_pbr_iptable *iptable = + (struct zebra_pbr_iptable *)backet->data; + struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg; + struct vty *vty = env->vty; + struct zebra_ns *zns = env->zns; + char *iptable_name = env->name; + + if (!iptable_name) + zebra_pbr_show_iptable_unit(iptable, vty, zns); + else if (!strncmp(iptable_name, + iptable->ipset_name, + ZEBRA_IPSET_NAME_SIZE)) + zebra_pbr_show_iptable_unit(iptable, vty, zns); return HASHWALK_CONTINUE; } -void zebra_pbr_show_iptable(struct vty *vty) +void zebra_pbr_show_iptable(struct vty *vty, char *iptable_name) { struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); struct zebra_pbr_env_display env; env.vty = vty; env.zns = zns; - + env.name = iptable_name; hash_walk(zns->iptable_hash, zebra_pbr_show_iptable_walkcb, &env); } diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index fd83502ae1..0db33d1f8c 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -235,7 +235,7 @@ extern int zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2); extern void zebra_pbr_init(void); extern void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname); -extern void zebra_pbr_show_iptable(struct vty *vty); +extern void zebra_pbr_show_iptable(struct vty *vty, char *iptable); extern void zebra_pbr_iptable_update_interfacelist(struct stream *s, struct zebra_pbr_iptable *zpi); size_t zebra_pbr_tcpflags_snprintf(char *buffer, size_t len, diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 9bf6bfa22f..71d48632c1 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2331,7 +2331,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, if (!re) return 0; - assert(!src_p || afi == AFI_IP6); + assert(!src_p || !src_p->prefixlen || afi == AFI_IP6); /* Lookup table. */ table = zebra_vrf_table_with_table_id(afi, safi, re->vrf_id, re->table); @@ -2421,7 +2421,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, char buf2[INET6_ADDRSTRLEN]; rib_dest_t *dest; - assert(!src_p || afi == AFI_IP6); + assert(!src_p || !src_p->prefixlen || afi == AFI_IP6); /* Lookup table. */ table = zebra_vrf_table_with_table_id(afi, safi, vrf_id, table_id); diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index bf6718164f..0b48e87b1b 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -137,7 +137,8 @@ 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, struct prefix *prefix, +static route_map_result_t route_match_tag(void *rule, + const struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag; @@ -163,7 +164,7 @@ 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, - struct prefix *prefix, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -879,7 +880,7 @@ DEFUN (show_ipv6_protocol_nht, /* 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, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -937,7 +938,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 -route_match_ip_next_hop_prefix_list(void *rule, struct prefix *prefix, +route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; @@ -993,7 +994,7 @@ 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, + const struct prefix *prefix, route_map_object_t type, void *object) { @@ -1032,7 +1033,7 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = { /* `match ip address prefix-list PREFIX_LIST' */ static route_map_result_t -route_match_ip_address_prefix_list(void *rule, struct prefix *prefix, +route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; @@ -1068,7 +1069,7 @@ static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { /* `match ip address prefix-len PREFIXLEN' */ static route_map_result_t -route_match_address_prefix_len(void *rule, struct prefix *prefix, +route_match_address_prefix_len(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { uint32_t *prefixlen = (uint32_t *)rule; @@ -1122,7 +1123,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 -route_match_ip_nexthop_prefix_len(void *rule, struct prefix *prefix, +route_match_ip_nexthop_prefix_len(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { uint32_t *prefixlen = (uint32_t *)rule; @@ -1162,7 +1163,7 @@ static struct route_map_rule_cmd route_match_ip_nexthop_prefix_len_cmd = { /* `match source-protocol PROTOCOL' */ static route_map_result_t route_match_source_protocol(void *rule, - struct prefix *prefix, + const struct prefix *p, route_map_object_t type, void *object) { @@ -1204,7 +1205,7 @@ static struct route_map_rule_cmd route_match_source_protocol_cmd = { /* `source-instance` */ static route_map_result_t route_match_source_instance(void *rule, - struct prefix *prefix, + const struct prefix *p, route_map_object_t type, void *object) { @@ -1246,7 +1247,7 @@ 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, struct prefix *prefix, +static route_map_result_t route_set_src(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { struct nh_rmap_obj *nh_data; @@ -1359,8 +1360,7 @@ route_map_result_t zebra_route_map_check(int family, int rib_type, rmap = route_map_lookup_by_name( proto_rm[family][ZEBRA_ROUTE_MAX]); if (rmap) { - ret = route_map_apply(rmap, (struct prefix *)p, - RMAP_ZEBRA, &nh_obj); + ret = route_map_apply(rmap, p, RMAP_ZEBRA, &nh_obj); } return (ret); @@ -1385,7 +1385,8 @@ void zebra_del_import_table_route_map(afi_t afi, uint32_t table) route_map_result_t zebra_import_table_route_map_check(int family, int re_type, uint8_t instance, - struct prefix *p, struct nexthop *nexthop, + const struct prefix *p, + struct nexthop *nexthop, vrf_id_t vrf_id, route_tag_t tag, const char *rmap_name) { @@ -1410,7 +1411,7 @@ zebra_import_table_route_map_check(int family, int re_type, uint8_t instance, } route_map_result_t zebra_nht_route_map_check(int family, int client_proto, - struct prefix *p, + const struct prefix *p, struct route_entry *re, struct nexthop *nexthop) { @@ -1430,11 +1431,10 @@ route_map_result_t zebra_nht_route_map_check(int family, int client_proto, if (!rmap && nht_rm[family][ZEBRA_ROUTE_MAX]) rmap = route_map_lookup_by_name( nht_rm[family][ZEBRA_ROUTE_MAX]); - if (rmap) { + if (rmap) ret = route_map_apply(rmap, p, RMAP_ZEBRA, &nh_obj); - } - return (ret); + return ret; } static void zebra_route_map_mark_update(const char *rmap_name) diff --git a/zebra/zebra_routemap.h b/zebra/zebra_routemap.h index 688c8b7203..d33487d7af 100644 --- a/zebra/zebra_routemap.h +++ b/zebra/zebra_routemap.h @@ -35,7 +35,8 @@ extern void zebra_route_map_write_delay_timer(struct vty *); extern route_map_result_t zebra_import_table_route_map_check(int family, int rib_type, uint8_t instance, - struct prefix *p, struct nexthop *nexthop, + const struct prefix *p, + struct nexthop *nexthop, vrf_id_t vrf_id, route_tag_t tag, const char *rmap_name); extern route_map_result_t @@ -43,7 +44,7 @@ zebra_route_map_check(int family, int rib_type, uint8_t instance, const struct prefix *p, struct nexthop *nexthop, vrf_id_t vrf_id, route_tag_t tag); extern route_map_result_t -zebra_nht_route_map_check(int family, int client_proto, struct prefix *p, +zebra_nht_route_map_check(int family, int client_proto, const struct prefix *p, struct route_entry *, struct nexthop *nexthop); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 55c4f6e916..4d71682f64 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1071,7 +1071,7 @@ DEFPY(ip_route_vrf, return zebra_static_route_leak( vty, zvrf, nh_zvrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str, NULL, gate_str, ifname, flag, tag_str, distance_str, label, - NULL); + table_str); } /* New RIB. Detailed information for IPv4 route. */ @@ -1198,7 +1198,8 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, break; } - if (re->vrf_id != nexthop->vrf_id) { + if ((re->vrf_id != nexthop->vrf_id) + && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) { struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id); @@ -1415,7 +1416,8 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, break; } - if (nexthop->vrf_id != re->vrf_id) { + if ((nexthop->vrf_id != re->vrf_id) + && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) { struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id); @@ -1569,7 +1571,8 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, break; } - if (nexthop->vrf_id != re->vrf_id) { + if ((nexthop->vrf_id != re->vrf_id) + && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) { struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id); if (vrf) @@ -1651,7 +1654,7 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, json = json_object_new_object(); /* Show all routes. */ - for (rn = route_top(table); rn; rn = route_next(rn)) { + for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) { dest = rib_dest_from_rnode(rn); RNODE_FOREACH_RE (rn, re) { @@ -1805,7 +1808,7 @@ DEFPY (show_route_table_vrf, vrf_id_t vrf_id = VRF_DEFAULT; if (vrf_name) - VRF_GET_ID(vrf_id, vrf_name); + VRF_GET_ID(vrf_id, vrf_name, !!json); zvrf = zebra_vrf_lookup_by_id(vrf_id); t = zebra_ns_find_table(zvrf->zns, table, afi); @@ -1828,7 +1831,7 @@ DEFUN (show_ip_nht, vrf_id_t vrf_id = VRF_DEFAULT; if (argc == 5) - VRF_GET_ID(vrf_id, argv[idx_vrf]->arg); + VRF_GET_ID(vrf_id, argv[idx_vrf]->arg, false); zebra_print_rnh_table(vrf_id, AF_INET, vty, RNH_NEXTHOP_TYPE); return CMD_SUCCESS; @@ -1868,7 +1871,7 @@ DEFUN (show_ipv6_nht, vrf_id_t vrf_id = VRF_DEFAULT; if (argc == 5) - VRF_GET_ID(vrf_id, argv[idx_vrf]->arg); + VRF_GET_ID(vrf_id, argv[idx_vrf]->arg, false); zebra_print_rnh_table(vrf_id, AF_INET6, vty, RNH_NEXTHOP_TYPE); return CMD_SUCCESS; @@ -2034,7 +2037,7 @@ DEFPY (show_route, vrf_id_t vrf_id = VRF_DEFAULT; if (vrf_name) - VRF_GET_ID(vrf_id, vrf_name); + VRF_GET_ID(vrf_id, vrf_name, !!json); vrf = vrf_lookup_by_id(vrf_id); do_show_ip_route(vty, vrf->name, afi, SAFI_UNICAST, !!fib, !!json, tag, prefix_str ? prefix : NULL, @@ -2108,7 +2111,7 @@ DEFPY (show_route_detail, vrf_id_t vrf_id = VRF_DEFAULT; if (vrf_name) - VRF_GET_ID(vrf_id, vrf_name); + VRF_GET_ID(vrf_id, vrf_name, false); table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id); if (!table) @@ -2175,7 +2178,7 @@ DEFPY (show_route_summary, vrf_id_t vrf_id = VRF_DEFAULT; if (vrf_name) - VRF_GET_ID(vrf_id, vrf_name); + VRF_GET_ID(vrf_id, vrf_name, false); table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id); if (!table) @@ -2790,7 +2793,7 @@ DEFUN (show_ipv6_mroute, vrf_id_t vrf_id = VRF_DEFAULT; if (argc == 5) - VRF_GET_ID(vrf_id, argv[4]->arg); + VRF_GET_ID(vrf_id, argv[4]->arg, false); table = zebra_vrf_table(AFI_IP6, SAFI_MULTICAST, vrf_id); if (!table) @@ -3471,12 +3474,20 @@ DEFUN (show_pbr_ipset, /* policy routing contexts */ DEFUN (show_pbr_iptable, show_pbr_iptable_cmd, - "show pbr iptable", + "show pbr iptable [WORD]", SHOW_STR "Policy-Based Routing\n" - "IPtable Context information\n") + "IPtable Context information\n" + "IPtable Name information\n") { - zebra_pbr_show_iptable(vty); + int idx = 0; + int found = 0; + + found = argv_find(argv, argc, "WORD", &idx); + if (!found) + zebra_pbr_show_iptable(vty, NULL); + else + zebra_pbr_show_iptable(vty, argv[idx]->arg); return CMD_SUCCESS; } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 59f0cf52f0..4955f3f77c 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -33,6 +33,9 @@ #include "jhash.h" #include "vlan.h" #include "vxlan.h" +#ifdef GNU_LINUX +#include <linux/neighbour.h> +#endif #include "zebra/rib.h" #include "zebra/rt.h" @@ -241,6 +244,7 @@ static uint32_t num_valid_macs(zebra_vni_t *zvni) for (hb = hash->index[i]; hb; hb = hb->next) { mac = (zebra_mac_t *)hb->data; if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) + || CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) || !CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) num_macs++; } @@ -282,6 +286,7 @@ static void zvni_find_neigh_addr_width(struct hash_backet *backet, void *ctxt) ipaddr2str(&n->ip, buf, sizeof(buf)), width = strlen(buf); if (width > wctx->addr_width) wctx->addr_width = width; + } /* @@ -327,6 +332,10 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json) else json_object_boolean_true_add(json, "defaultGateway"); } + if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG)) { + if (!json) + vty_out(vty, " Router"); + } if (json == NULL) vty_out(vty, "\n"); } @@ -432,11 +441,11 @@ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, return; } num_neigh = hashcount(zvni->neigh_table); - if (json == NULL) + if (json == NULL) { vty_out(vty, "\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n", zvni->vni, num_neigh); - else { + } else { json_vni = json_object_new_object(); json_object_int_add(json_vni, "numArpNd", num_neigh); snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni); @@ -458,9 +467,10 @@ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, wctx.json = json_vni; hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); - if (json == NULL) + if (json == NULL) { vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP", "Type", "MAC", "Remote VTEP"); + } hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); if (json) @@ -581,6 +591,9 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt) if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) vty_out(vty, " Default-gateway Mac "); + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW)) + vty_out(vty, " Remote-gateway Mac "); + vty_out(vty, "\n"); /* print all the associated neigh */ vty_out(vty, " Neighbors:\n"); @@ -1553,6 +1566,9 @@ static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip, if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_DEF_GW)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); + /* Set router flag (R-bit) based on local neigh entry add */ + if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_ROUTER_FLAG)) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags, ZEBRA_MACIP_ADD); @@ -1576,6 +1592,8 @@ static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n) struct zebra_if *zif; struct zebra_l2info_vxlan *vxl; struct interface *vlan_if; + uint8_t flags; + int ret = 0; if (!(n->flags & ZEBRA_NEIGH_REMOTE)) return 0; @@ -1588,8 +1606,13 @@ static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n) vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if); if (!vlan_if) return -1; - - return kernel_add_neigh(vlan_if, &n->ip, &n->emac); +#ifdef GNU_LINUX + flags = NTF_EXT_LEARNED; + if (n->flags & ZEBRA_NEIGH_ROUTER_FLAG) + flags |= NTF_ROUTER; + ret = kernel_add_neigh(vlan_if, &n->ip, &n->emac, flags); +#endif + return ret; } /* @@ -1811,6 +1834,9 @@ 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); + /* 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; @@ -1820,10 +1846,10 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s add to BGP", + "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))); + ipaddr2str(ip, buf2, sizeof(buf2)), n->flags); zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, n->flags); @@ -1966,7 +1992,8 @@ static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet, static int zvni_local_neigh_update(zebra_vni_t *zvni, struct interface *ifp, struct ipaddr *ip, - struct ethaddr *macaddr) + struct ethaddr *macaddr, + uint8_t router_flag) { char buf[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; @@ -2084,15 +2111,19 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, return 0; } + /*Set router flag (R-bit) */ + if (router_flag) + SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); + /* Inform BGP. */ if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Neigh %s (MAC %s) is now ACTIVE on L2-VNI %u", + zlog_debug("Neigh %s (MAC %s) is now ACTIVE on L2-VNI %u with flags 0x%x", ipaddr2str(ip, buf2, sizeof(buf2)), prefix_mac2str(macaddr, buf, sizeof(buf)), - zvni->vni); + zvni->vni, n->flags); ZEBRA_NEIGH_SET_ACTIVE(n); - return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, 0); + return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, n->flags); } static int zvni_remote_neigh_update(zebra_vni_t *zvni, @@ -2534,7 +2565,8 @@ static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac) return -1; vxl = &zif->l2info.vxl; - sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0; + sticky = CHECK_FLAG(mac->flags, + (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW)) ? 1 : 0; return kernel_add_mac(zvni->vxlan_if, vxl->access_vlan, &mac->macaddr, mac->fwd_info.r_vtep_ip, sticky); @@ -3362,14 +3394,22 @@ static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n) */ static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n) { + uint8_t flags; + int ret = 0; + if (!is_l3vni_oper_up(zl3vni)) return -1; if (!(n->flags & ZEBRA_NEIGH_REMOTE) || !(n->flags & ZEBRA_NEIGH_REMOTE_NH)) return 0; - - return kernel_add_neigh(zl3vni->svi_if, &n->ip, &n->emac); +#ifdef GNU_LINUX + flags = NTF_EXT_LEARNED; + if (n->flags & ZEBRA_NEIGH_ROUTER_FLAG) + flags |= NTF_ROUTER; + ret = kernel_add_neigh(zl3vni->svi_if, &n->ip, &n->emac, flags); +#endif + return ret; } /* @@ -4513,9 +4553,11 @@ void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); wctx.zvni = zvni; wctx.vty = vty; + wctx.addr_width = 15; wctx.flags = SHOW_REMOTE_NEIGH_FROM_VTEP; wctx.r_vtep_ip = vtep_ip; wctx.json = json; + hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); if (use_json) { @@ -4944,7 +4986,8 @@ int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp, struct ipaddr *ip, struct ethaddr *macaddr, uint16_t state, - uint8_t ext_learned) + uint8_t ext_learned, + uint8_t router_flag) { char buf[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; @@ -4975,7 +5018,8 @@ int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp, /* Is this about a local neighbor or a remote one? */ if (!ext_learned) - return zvni_local_neigh_update(zvni, ifp, ip, macaddr); + return zvni_local_neigh_update(zvni, ifp, ip, macaddr, + router_flag); return zvni_remote_neigh_update(zvni, ifp, ip, macaddr, state); } @@ -5152,6 +5196,7 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS) char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; uint8_t sticky = 0; + u_char remote_gw = 0; uint8_t flags = 0; struct interface *ifp = NULL; struct zebra_if *zif = NULL; @@ -5193,6 +5238,7 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS) /* Get flags - sticky mac and/or gateway mac */ STREAM_GETC(s, flags); sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); + remote_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW); l++; if (IS_ZEBRA_DEBUG_VXLAN) @@ -5266,6 +5312,8 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS) if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) || (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0) != sticky + || (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? 1 : 0) + != remote_gw || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)) update_mac = 1; @@ -5297,6 +5345,11 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS) else UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); + if (remote_gw) + SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW); + else + UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW); + zvni_process_neigh_on_remote_mac_add(zvni, mac); /* Install the entry. */ @@ -5353,6 +5406,10 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS) n->r_vtep_ip = vtep_ip; SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); + /* Set router flag (R-bit) to this Neighbor entry */ + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG)) + SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); + /* Install the entry. */ zvni_neigh_install(zvni, n); } diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index 34d1152751..2732ef72ed 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -124,7 +124,8 @@ extern int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if); extern int zebra_vxlan_handle_kernel_neigh_update( struct interface *ifp, struct interface *link_if, struct ipaddr *ip, - struct ethaddr *macaddr, uint16_t state, uint8_t ext_learned); + struct ethaddr *macaddr, uint16_t state, uint8_t ext_learned, + uint8_t router_flag); extern int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp, struct interface *link_if, struct ipaddr *ip); diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index fa7075f2de..e86967041b 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -247,6 +247,8 @@ struct zebra_mac_t_ { #define ZEBRA_MAC_STICKY 0x08 /* Static MAC */ #define ZEBRA_MAC_REMOTE_RMAC 0x10 /* remote router mac */ #define ZEBRA_MAC_DEF_GW 0x20 +/* remote VTEP advertised MAC as default GW */ +#define ZEBRA_MAC_REMOTE_DEF_GW 0x40 /* Local or remote info. */ union { @@ -329,6 +331,7 @@ struct zebra_neigh_t_ { #define ZEBRA_NEIGH_REMOTE 0x02 #define ZEBRA_NEIGH_REMOTE_NH 0x04 /* neigh entry for remote vtep */ #define ZEBRA_NEIGH_DEF_GW 0x08 +#define ZEBRA_NEIGH_ROUTER_FLAG 0x10 enum zebra_neigh_state state; diff --git a/zebra/zserv.c b/zebra/zserv.c index 4c90757d70..f76c2fabd6 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -91,7 +91,7 @@ enum zserv_event { /* The calling client has packets on its input buffer */ ZSERV_PROCESS_MESSAGES, /* The calling client wishes to be killed */ - ZSERV_HANDLE_CLOSE, + ZSERV_HANDLE_CLIENT_FAIL, }; /* @@ -160,18 +160,25 @@ static void zserv_log_message(const char *errmsg, struct stream *msg, /* * Gracefully shut down a client connection. * - * Cancel any pending tasks for the client's thread. Then schedule a task on the - * main thread to shut down the calling thread. + * Cancel any pending tasks for the client's thread. Then schedule a task on + * the main thread to shut down the calling thread. + * + * It is not safe to close the client socket in this function. The socket is + * owned by the main thread. * * Must be called from the client pthread, never the main thread. */ -static void zserv_client_close(struct zserv *client) +static void zserv_client_fail(struct zserv *client) { + zlog_warn("Client '%s' encountered an error and is shutting down.", + zebra_route_string(client->proto)); + atomic_store_explicit(&client->pthread->running, false, - memory_order_seq_cst); + memory_order_relaxed); + THREAD_OFF(client->t_read); THREAD_OFF(client->t_write); - zserv_event(client, ZSERV_HANDLE_CLOSE); + zserv_event(client, ZSERV_HANDLE_CLIENT_FAIL); } /* @@ -264,7 +271,7 @@ static int zserv_write(struct thread *thread) zwrite_fail: zlog_warn("%s: could not write to %s [fd = %d], closing.", __func__, zebra_route_string(client->proto), client->sock); - zserv_client_close(client); + zserv_client_fail(client); return 0; } @@ -438,7 +445,7 @@ static int zserv_read(struct thread *thread) zread_fail: stream_fifo_free(cache); - zserv_client_close(client); + zserv_client_fail(client); return -1; } @@ -569,6 +576,7 @@ static void zserv_client_free(struct zserv *client) unsigned long nroutes; close(client->sock); + nroutes = rib_score_proto(client->proto, client->instance); zlog_notice( "client %d disconnected. %lu %s routes removed from the rib", @@ -605,28 +613,40 @@ static void zserv_client_free(struct zserv *client) XFREE(MTYPE_TMP, client); } -/* - * Finish closing a client. - * - * This task is scheduled by a ZAPI client pthread on the main pthread when it - * wants to stop itself. When this executes, the client connection should - * already have been closed. This task's responsibility is to gracefully - * terminate the client thread, update relevant internal datastructures and - * free any resources allocated by the main thread. - */ -static int zserv_handle_client_close(struct thread *thread) +void zserv_close_client(struct zserv *client) { - struct zserv *client = THREAD_ARG(thread); - - /* synchronously stop thread */ + /* synchronously stop and join pthread */ frr_pthread_stop(client->pthread, NULL); - /* destroy frr_pthread */ + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug("Closing client '%s'", + zebra_route_string(client->proto)); + + thread_cancel_event(zebrad.master, client); + THREAD_OFF(client->t_cleanup); + + /* destroy pthread */ frr_pthread_destroy(client->pthread); client->pthread = NULL; + /* remove from client list */ listnode_delete(zebrad.client_list, client); + + /* delete client */ zserv_client_free(client); +} + +/* + * This task is scheduled by a ZAPI client pthread on the main pthread when it + * wants to stop itself. When this executes, the client connection should + * already have been closed and the thread will most likely have died, but its + * resources still need to be cleaned up. + */ +static int zserv_handle_client_fail(struct thread *thread) +{ + struct zserv *client = THREAD_ARG(thread); + + zserv_close_client(client); return 0; } @@ -814,9 +834,9 @@ void zserv_event(struct zserv *client, enum zserv_event event) thread_add_event(zebrad.master, zserv_process_messages, client, 0, NULL); break; - case ZSERV_HANDLE_CLOSE: - thread_add_event(zebrad.master, zserv_handle_client_close, - client, 0, NULL); + case ZSERV_HANDLE_CLIENT_FAIL: + thread_add_event(zebrad.master, zserv_handle_client_fail, + client, 0, &client->t_cleanup); } } @@ -1024,7 +1044,6 @@ DEFUN (show_zebra_client_summary, void zserv_read_file(char *input) { int fd; - struct zserv *client = NULL; struct thread t; fd = open(input, O_RDONLY | O_NONBLOCK); @@ -1038,7 +1057,6 @@ void zserv_init(void) { /* Client list init. */ zebrad.client_list = list_new(); - zebrad.client_list->del = (void (*)(void *)) zserv_client_free; /* Misc init. */ zebrad.sock = -1; diff --git a/zebra/zserv.h b/zebra/zserv.h index 78cc200fa8..aaefd78eea 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -73,6 +73,9 @@ struct zserv { struct thread *t_read; struct thread *t_write; + /* Threads for the main pthread */ + struct thread *t_cleanup; + /* default routing table this client munges */ int rtm_table; @@ -232,6 +235,18 @@ extern int zserv_send_message(struct zserv *client, struct stream *msg); */ extern struct zserv *zserv_find_client(uint8_t proto, unsigned short instance); + +/* + * Close a client. + * + * Kills a client's thread, removes the client from the client list and cleans + * up its resources. + * + * client + * the client to close + */ +extern void zserv_close_client(struct zserv *client); + #if defined(HANDLE_ZAPI_FUZZING) extern void zserv_read_file(char *input); #endif |
