summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-rw-r--r--bgpd/Makefile.am1
-rw-r--r--bgpd/bgp_attr.c10
-rw-r--r--bgpd/bgp_attr.h3
-rw-r--r--bgpd/bgp_attr_evpn.c33
-rw-r--r--bgpd/bgp_attr_evpn.h2
-rw-r--r--bgpd/bgp_clist.c181
-rw-r--r--bgpd/bgp_community.c261
-rw-r--r--bgpd/bgp_community.h22
-rw-r--r--bgpd/bgp_debug.c283
-rw-r--r--bgpd/bgp_ecommunity.h3
-rw-r--r--bgpd/bgp_evpn.c30
-rw-r--r--bgpd/bgp_evpn_private.h12
-rw-r--r--bgpd/bgp_evpn_vty.c24
-rw-r--r--bgpd/bgp_flowspec.h8
-rw-r--r--bgpd/bgp_flowspec_util.c27
-rw-r--r--bgpd/bgp_flowspec_util.h8
-rw-r--r--bgpd/bgp_flowspec_vty.c68
-rw-r--r--bgpd/bgp_keepalives.c6
-rw-r--r--bgpd/bgp_pbr.c231
-rw-r--r--bgpd/bgp_route.c68
-rw-r--r--bgpd/bgp_route.h2
-rw-r--r--bgpd/bgp_routemap.c121
-rw-r--r--bgpd/bgp_table.c6
-rw-r--r--bgpd/bgp_table.h4
-rw-r--r--bgpd/bgp_updgrp_adv.c66
-rw-r--r--bgpd/bgp_vty.c17
-rw-r--r--bgpd/bgp_zebra.c22
-rw-r--r--bgpd/bgpd.c5
-rwxr-xr-xconfigure.ac14
-rw-r--r--debianpkg/control6
-rw-r--r--doc/Makefile.am1
-rw-r--r--doc/developer/modules.rst9
-rw-r--r--doc/developer/workflow.rst2
-rw-r--r--doc/extra/spelling_wordlist.txt1
-rw-r--r--doc/user/bgp.rst140
-rw-r--r--doc/user/index.rst1
-rw-r--r--doc/user/ldpd.rst309
-rw-r--r--doc/user/rpki.rst36
-rw-r--r--doc/user/zebra.rst7
-rw-r--r--isisd/isis_lsp.c21
-rw-r--r--isisd/isis_mt.c12
-rw-r--r--isisd/isis_mt.h8
-rw-r--r--isisd/isis_pdu.c9
-rw-r--r--isisd/isis_redist.c105
-rw-r--r--isisd/isis_redist.h7
-rw-r--r--isisd/isis_route.c262
-rw-r--r--isisd/isis_route.h20
-rw-r--r--isisd/isis_routemap.c11
-rw-r--r--isisd/isis_spf.c345
-rw-r--r--isisd/isis_spf.h3
-rw-r--r--isisd/isis_tlvs.c20
-rw-r--r--isisd/isis_tlvs.h4
-rw-r--r--isisd/isis_zebra.c30
-rw-r--r--isisd/isis_zebra.h1
-rw-r--r--isisd/isisd.c90
-rw-r--r--isisd/isisd.h15
-rw-r--r--ldpd/ldp_vty_cmds.c1
-rw-r--r--lib/command.h1
-rw-r--r--lib/compiler.h1
-rw-r--r--lib/filter.c9
-rw-r--r--lib/filter.h3
-rw-r--r--lib/frr_pthread.c29
-rw-r--r--lib/if.c4
-rw-r--r--lib/keychain.c2
-rw-r--r--lib/linklist.h2
-rw-r--r--lib/plist.c13
-rw-r--r--lib/plist.h5
-rw-r--r--lib/routemap.c14
-rw-r--r--lib/routemap.h14
-rw-r--r--lib/sockopt.c2
-rw-r--r--lib/srcdest_table.c15
-rw-r--r--lib/srcdest_table.h3
-rw-r--r--lib/stream.c12
-rw-r--r--lib/stream.h2
-rw-r--r--lib/table.h62
-rw-r--r--lib/thread.c1
-rw-r--r--lib/vrf.h14
-rw-r--r--lib/workqueue.h2
-rw-r--r--lib/zclient.h6
-rw-r--r--lib/zebra.h16
-rw-r--r--ospf6d/ospf6_asbr.c18
-rw-r--r--ospf6d/ospf6_top.c4
-rw-r--r--ospfd/ospf_lsa.c2
-rw-r--r--ospfd/ospf_routemap.c20
-rw-r--r--ospfd/ospfd.c3
-rw-r--r--pimd/pim_bfd.c8
-rw-r--r--pimd/pim_bfd.h2
-rw-r--r--pimd/pim_iface.c16
-rw-r--r--pimd/pim_igmp_join.h2
-rw-r--r--pimd/pim_instance.c4
-rw-r--r--pimd/pim_msdp.c21
-rw-r--r--pimd/pim_msg.c2
-rw-r--r--pimd/pim_neighbor.c3
-rw-r--r--pimd/pim_nht.c80
-rw-r--r--pimd/pim_routemap.c3
-rw-r--r--pimd/pim_rp.c16
-rw-r--r--pimd/pim_sock.c21
-rw-r--r--pimd/pim_sock.h2
-rw-r--r--pimd/pim_ssm.c7
-rw-r--r--pimd/pim_upstream.c7
-rw-r--r--pimd/pim_vty.c18
-rw-r--r--pimd/pim_zebra.c187
-rw-r--r--pimd/pim_zebra.h5
-rw-r--r--pimd/pimd.c2
-rw-r--r--redhat/frr.spec.in4
-rw-r--r--ripd/rip_interface.c45
-rw-r--r--ripd/rip_memory.c1
-rw-r--r--ripd/rip_memory.h1
-rw-r--r--ripd/rip_routemap.c22
-rw-r--r--ripd/ripd.c4
-rw-r--r--ripngd/ripng_routemap.c16
-rw-r--r--tests/bgpd/test_bgp_table.c4
-rw-r--r--tests/bgpd/test_capability.c1
-rw-r--r--tests/isisd/test_fuzz_isis_tlv_tests.h.gzbin262877 -> 233035 bytes
-rw-r--r--tests/isisd/test_isis_vertex_queue.c53
-rw-r--r--tests/lib/test_srcdest_table.c3
-rwxr-xr-xtools/checkpatch.sh9
-rwxr-xr-xtools/frr6
-rwxr-xr-xtools/frr-reload.py2
-rw-r--r--vtysh/vtysh_config.c3
-rw-r--r--zebra/if_netlink.c38
-rw-r--r--zebra/interface.c6
-rw-r--r--zebra/kernel_netlink.c102
-rw-r--r--zebra/kernel_netlink.h4
-rw-r--r--zebra/main.c54
-rw-r--r--zebra/router-id.c4
-rw-r--r--zebra/rt.h2
-rw-r--r--zebra/rt_netlink.c93
-rw-r--r--zebra/rt_socket.c10
-rw-r--r--zebra/rule_netlink.c6
-rw-r--r--zebra/zebra_netns_notify.c1
-rw-r--r--zebra/zebra_pbr.c41
-rw-r--r--zebra/zebra_pbr.h2
-rw-r--r--zebra/zebra_rib.c4
-rw-r--r--zebra/zebra_routemap.c36
-rw-r--r--zebra/zebra_routemap.h5
-rw-r--r--zebra/zebra_vty.c41
-rw-r--r--zebra/zebra_vxlan.c89
-rw-r--r--zebra/zebra_vxlan.h3
-rw-r--r--zebra/zebra_vxlan_private.h3
-rw-r--r--zebra/zserv.c72
-rw-r--r--zebra/zserv.h15
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);
}
diff --git a/lib/if.c b/lib/if.c
index 2320093a15..e31ccd8563 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -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
diff --git a/lib/vrf.h b/lib/vrf.h
index 8aa0fc2215..0f4f36be50 100644
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -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
index cca702b138..4abbe81499 100644
--- a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
+++ b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
Binary files differ
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
diff --git a/tools/frr b/tools/frr
index 7d7b97433a..43aa2954ac 100755
--- a/tools/frr
+++ b/tools/frr
@@ -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