summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_attr_evpn.h1
-rw-r--r--bgpd/bgp_clist.c28
-rw-r--r--bgpd/bgp_clist.h4
-rw-r--r--bgpd/bgp_damp.c2
-rw-r--r--bgpd/bgp_evpn.c64
-rw-r--r--bgpd/bgp_evpn_vty.c26
-rw-r--r--bgpd/bgp_vty.c16
-rw-r--r--bgpd/rfapi/rfapi_import.c23
-rw-r--r--doc/developer/building-frr-on-alpine.rst22
-rw-r--r--eigrpd/eigrp_snmp.c2
-rw-r--r--lib/buffer.c3
-rw-r--r--lib/imsg.c2
-rw-r--r--lib/mpls.c100
-rw-r--r--lib/mpls.h15
-rw-r--r--lib/nexthop_group.c373
-rw-r--r--lib/nexthop_group.h14
-rwxr-xr-xlib/route_types.pl14
-rw-r--r--lib/route_types.txt60
-rw-r--r--lib/subdir.am1
-rw-r--r--lib/vrf.c8
-rw-r--r--lib/zclient.c5
-rw-r--r--ospfd/ospf_snmp.c2
-rw-r--r--ospfd/ospf_te.c21
-rw-r--r--pbrd/pbr_debug.c97
-rw-r--r--pbrd/pbr_debug.h24
-rw-r--r--pbrd/pbr_main.c5
-rw-r--r--pbrd/pbr_map.c25
-rw-r--r--pbrd/pbr_map.h14
-rw-r--r--pbrd/pbr_nht.c34
-rw-r--r--pbrd/pbr_vty.c104
-rw-r--r--pbrd/pbr_zebra.c43
-rw-r--r--pimd/mtracebis_routeget.c2
-rw-r--r--tests/ospf6d/test_lsdb.c8
-rw-r--r--zebra/client_main.c5
-rw-r--r--zebra/redistribute.c2
-rw-r--r--zebra/rt_netlink.c20
-rw-r--r--zebra/zebra_mpls.c77
-rw-r--r--zebra/zebra_mpls.h16
-rw-r--r--zebra/zebra_pbr.c11
-rw-r--r--zebra/zebra_rnh.c4
-rw-r--r--zebra/zebra_static.c4
-rw-r--r--zebra/zebra_vty.c3
-rw-r--r--zebra/zebra_vxlan.c318
-rw-r--r--zebra/zebra_vxlan.h4
44 files changed, 1055 insertions, 571 deletions
diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h
index cb1c131ef7..7454b81b96 100644
--- a/bgpd/bgp_attr_evpn.h
+++ b/bgpd/bgp_attr_evpn.h
@@ -37,6 +37,7 @@
unsigned long eth_tag_id;
struct attr;
+/* EVPN ESI */
struct eth_segment_id {
uint8_t val[ESI_LEN];
};
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index 8f38f5765f..d1bc7f6e53 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -852,7 +852,7 @@ int community_list_set(struct community_list_handler *ch, const char *name,
/* Unset community-list */
int community_list_unset(struct community_list_handler *ch, const char *name,
- const char *str, int direct, int style, int delete_all)
+ const char *str, int direct, int style)
{
struct community_entry *entry = NULL;
struct community_list *list;
@@ -864,16 +864,14 @@ int community_list_unset(struct community_list_handler *ch, const char *name,
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
/* Delete all of entry belongs to this community-list. */
- if (delete_all) {
+ if (!str) {
community_list_delete(list);
route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
return 0;
}
- if (style == COMMUNITY_LIST_STANDARD) {
- if (str)
- com = community_str2com(str);
- }
+ if (style == COMMUNITY_LIST_STANDARD)
+ com = community_str2com(str);
if (com) {
entry = community_list_entry_lookup(list, com, direct);
@@ -1117,11 +1115,13 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
return 0;
}
-/* Unset extcommunity-list. When str is NULL, delete all of
- extcommunity-list entry belongs to the specified name. */
+/* Unset extcommunity-list.
+ *
+ * When str is NULL, delete all extcommunity-list entries belonging to the
+ * specified name.
+ */
int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
- const char *str, int direct, int style,
- int delete_all)
+ const char *str, int direct, int style)
{
struct community_entry *entry = NULL;
struct community_list *list;
@@ -1133,16 +1133,14 @@ int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
/* Delete all of entry belongs to this extcommunity-list. */
- if (delete_all) {
+ if (!str) {
community_list_delete(list);
route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
return 0;
}
- if (style == EXTCOMMUNITY_LIST_STANDARD) {
- if (str)
- ecom = ecommunity_str2com(str, 0, 1);
- }
+ if (style == EXTCOMMUNITY_LIST_STANDARD)
+ ecom = ecommunity_str2com(str, 0, 1);
if (ecom) {
entry = community_list_entry_lookup(list, ecom, direct);
diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h
index 0dbde2a453..9efb34d7b9 100644
--- a/bgpd/bgp_clist.h
+++ b/bgpd/bgp_clist.h
@@ -133,13 +133,13 @@ extern int community_list_set(struct community_list_handler *ch,
int style);
extern int community_list_unset(struct community_list_handler *ch,
const char *name, const char *str, int direct,
- int style, int delete_all);
+ int style);
extern int extcommunity_list_set(struct community_list_handler *ch,
const char *name, const char *str, int direct,
int style);
extern int extcommunity_list_unset(struct community_list_handler *ch,
const char *name, const char *str,
- int direct, int style, int delete_all);
+ int direct, int style);
extern int lcommunity_list_set(struct community_list_handler *ch,
const char *name, const char *str, int direct,
int style);
diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c
index 1ed557e074..bce6056ded 100644
--- a/bgpd/bgp_damp.c
+++ b/bgpd/bgp_damp.c
@@ -233,7 +233,7 @@ int bgp_damp_withdraw(struct bgp_info *binfo, struct bgp_node *rn, afi_t afi,
/* Remove the route from a reuse list if it is on one. */
if (CHECK_FLAG(bdi->binfo->flags, BGP_INFO_DAMPED)) {
/* If decay rate isn't equal to 0, reinsert brn. */
- if (bdi->penalty != last_penalty) {
+ if (bdi->penalty != last_penalty && bdi->index >= 0) {
bgp_reuse_list_delete(bdi);
bgp_reuse_list_add(bdi);
}
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index e5e5f72699..483d65be71 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -2810,10 +2810,12 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
{
struct prefix_rd prd;
struct prefix_evpn p;
+ struct bgp_route_evpn evpn;
uint8_t ipaddr_len;
uint8_t macaddr_len;
mpls_label_t label[BGP_MAX_LABELS]; /* holds the VNI(s) as in packet */
uint32_t num_labels = 0;
+ uint32_t eth_tag;
int ret;
/* Type-2 route should be either 33, 37 or 49 bytes or an
@@ -2829,6 +2831,8 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
return -1;
}
+ memset(&evpn, 0, sizeof(evpn));
+
/* Make prefix_rd */
prd.family = AF_UNSPEC;
prd.prefixlen = 64;
@@ -2841,10 +2845,13 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
p.prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN;
p.prefix.route_type = BGP_EVPN_MAC_IP_ROUTE;
- /* Skip over Ethernet Seg Identifier for now. */
- pfx += 10;
+ /* Copy Ethernet Seg Identifier */
+ memcpy(&evpn.eth_s_id.val, pfx, ESI_LEN);
+ pfx += ESI_LEN;
- /* Skip over Ethernet Tag for now. */
+ /* Copy Ethernet Tag */
+ memcpy(&eth_tag, pfx, 4);
+ p.prefix.eth_tag = ntohl(eth_tag);
pfx += 4;
/* Get the MAC Addr len */
@@ -2902,11 +2909,11 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
if (attr)
ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
- &prd, &label[0], num_labels, 0, NULL);
+ &prd, &label[0], num_labels, 0, &evpn);
else
ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
- &prd, &label[0], num_labels, NULL);
+ &prd, &label[0], num_labels, &evpn);
return ret;
}
@@ -2920,6 +2927,7 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
struct prefix_rd prd;
struct prefix_evpn p;
uint8_t ipaddr_len;
+ uint32_t eth_tag;
int ret;
/* Type-3 route should be either 17 or 29 bytes: RD (8), Eth Tag (4),
@@ -2956,7 +2964,9 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
p.prefixlen = EVPN_TYPE_3_ROUTE_PREFIXLEN;
p.prefix.route_type = BGP_EVPN_IMET_ROUTE;
- /* Skip over Ethernet Tag for now. */
+ /* Copy Ethernet Tag */
+ memcpy(&eth_tag, pfx, 4);
+ p.prefix.eth_tag = ntohl(eth_tag);
pfx += 4;
/* Get the IP. */
@@ -3574,7 +3584,7 @@ void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json)
if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) {
json_object_int_add(json, "routeType", p->prefix.route_type);
- json_object_int_add(json, "ethTag", 0);
+ json_object_int_add(json, "ethTag", p->prefix.eth_tag);
json_object_int_add(json, "ipLen",
IS_EVPN_PREFIX_IPADDR_V4(p)
? IPV4_MAX_BITLEN
@@ -3585,10 +3595,7 @@ void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json)
if (IS_EVPN_PREFIX_IPADDR_NONE(p)) {
json_object_int_add(json, "routeType",
p->prefix.route_type);
- json_object_int_add(
- json, "esi",
- 0); /* TODO: we don't support esi yet */
- json_object_int_add(json, "ethTag", 0);
+ json_object_int_add(json, "ethTag", p->prefix.eth_tag);
json_object_int_add(json, "macLen", 8 * ETH_ALEN);
json_object_string_add(json, "mac",
prefix_mac2str(&p->prefix.mac,
@@ -3602,10 +3609,7 @@ void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json)
json_object_int_add(json, "routeType",
p->prefix.route_type);
- json_object_int_add(
- json, "esi",
- 0); /* TODO: we don't support esi yet */
- json_object_int_add(json, "ethTag", 0);
+ json_object_int_add(json, "ethTag", p->prefix.eth_tag);
json_object_int_add(json, "macLen", 8 * ETH_ALEN);
json_object_string_add(json, "mac",
prefix_mac2str(&p->prefix.mac,
@@ -3635,14 +3639,17 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
char buf2[PREFIX2STR_BUFFER];
if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) {
- snprintf(buf, len, "[%d]:[0]:[%d]:[%s]", p->prefix.route_type,
+ snprintf(buf, len, "[%d]:[%d]:[%d]:[%s]", p->prefix.route_type,
+ p->prefix.eth_tag,
IS_EVPN_PREFIX_IPADDR_V4(p) ? IPV4_MAX_BITLEN
: IPV6_MAX_BITLEN,
inet_ntoa(p->prefix.ip.ipaddr_v4));
} else if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
if (IS_EVPN_PREFIX_IPADDR_NONE(p))
- snprintf(buf, len, "[%d]:[0]:[0]:[%d]:[%s]",
- p->prefix.route_type, 8 * ETH_ALEN,
+ snprintf(buf, len, "[%d]:[%d]:[%d]:[%s]",
+ p->prefix.route_type,
+ p->prefix.eth_tag,
+ 8 * ETH_ALEN,
prefix_mac2str(&p->prefix.mac, buf1,
sizeof(buf1)));
else {
@@ -3650,8 +3657,10 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
family = IS_EVPN_PREFIX_IPADDR_V4(p) ? AF_INET
: AF_INET6;
- snprintf(buf, len, "[%d]:[0]:[0]:[%d]:[%s]:[%d]:[%s]",
- p->prefix.route_type, 8 * ETH_ALEN,
+ snprintf(buf, len, "[%d]:[%d]:[%d]:[%s]:[%d]:[%s]",
+ p->prefix.route_type,
+ p->prefix.eth_tag,
+ 8 * ETH_ALEN,
prefix_mac2str(&p->prefix.mac, buf1,
sizeof(buf1)),
family == AF_INET ? IPV4_MAX_BITLEN
@@ -3660,8 +3669,10 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
PREFIX2STR_BUFFER));
}
} else if (p->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) {
- snprintf(buf, len, "[%d]:[0]:[0]:[%d]:[%s]",
- p->prefix.route_type, p->prefix.ip_prefix_length,
+ snprintf(buf, len, "[%d]:[%d]:[%d]:[%s]",
+ p->prefix.route_type,
+ p->prefix.eth_tag,
+ p->prefix.ip_prefix_length,
IS_EVPN_PREFIX_IPADDR_V4(p)
? inet_ntoa(p->prefix.ip.ipaddr_v4)
: inet6_ntoa(p->prefix.ip.ipaddr_v6));
@@ -3703,8 +3714,11 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
len += 3;
stream_putc(s, len);
stream_put(s, prd->val, 8); /* RD */
- stream_put(s, 0, 10); /* ESI */
- stream_putl(s, 0); /* Ethernet Tag ID */
+ if (attr)
+ stream_put(s, &attr->evpn_overlay.eth_s_id, ESI_LEN);
+ else
+ stream_put(s, 0, 10);
+ stream_putl(s, evp->prefix.eth_tag); /* Ethernet Tag ID */
stream_putc(s, 8 * ETH_ALEN); /* Mac Addr Len - bits */
stream_put(s, evp->prefix.mac.octet, 6); /* Mac Addr */
stream_putc(s, 8 * ipa_len); /* IP address Length */
@@ -3720,7 +3734,7 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
case BGP_EVPN_IMET_ROUTE:
stream_putc(s, 17); // TODO: length - assumes IPv4 address
stream_put(s, prd->val, 8); /* RD */
- stream_putl(s, 0); /* Ethernet Tag ID */
+ stream_putl(s, evp->prefix.eth_tag); /* Ethernet Tag ID */
stream_putc(s, IPV4_MAX_BITLEN); /* IP address Length - bits */
/* Originating Router's IP Addr */
stream_put_in_addr(s, &evp->prefix.ip.ipaddr_v4);
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 8fd7cb5d14..c74a1bfb7c 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -327,9 +327,9 @@ static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp,
"* valid, > best, i - internal\n");
vty_out(vty, "Origin codes: i - IGP, e - EGP, ? - incomplete\n");
vty_out(vty,
- "EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:[MAC]:[IPlen]:[IP]\n");
+ "EVPN type-2 prefix: [2]:[EthTag]:[MAClen]:[MAC]:[IPlen]:[IP]\n");
vty_out(vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n");
- vty_out(vty, "EVPN type-5 prefix: [5]:[ESI]:[EthTag]:[IPlen]:[IP]\n\n");
+ vty_out(vty, "EVPN type-5 prefix: [5]:[EthTag]:[IPlen]:[IP]\n\n");
vty_out(vty, "%s", ri_header);
}
@@ -2110,11 +2110,11 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
/* RD header and legend - once overall. */
if (rd_header && !json) {
vty_out(vty,
- "EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:[MAC]\n");
+ "EVPN type-2 prefix: [2]:[EthTag]:[MAClen]:[MAC]\n");
vty_out(vty,
"EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n");
vty_out(vty,
- "EVPN type-5 prefix: [5]:[ESI]:[EthTag]:[IPlen]:[IP]\n\n");
+ "EVPN type-5 prefix: [5]:[EthTag]:[IPlen]:[IP]\n\n");
rd_header = 0;
}
@@ -2692,10 +2692,10 @@ DEFUN (no_bgp_evpn_default_originate,
return CMD_SUCCESS;
}
-DEFUN (bgp_evpn_advertise_vni_subnet,
- bgp_evpn_advertise_vni_subnet_cmd,
- "advertise-subnet",
- "Advertise the subnet corresponding to VNI\n")
+DEFUN_HIDDEN (bgp_evpn_advertise_vni_subnet,
+ bgp_evpn_advertise_vni_subnet_cmd,
+ "advertise-subnet",
+ "Advertise the subnet corresponding to VNI\n")
{
struct bgp *bgp_vrf = NULL;
struct bgp *bgp = VTY_GET_CONTEXT(bgp);
@@ -2715,11 +2715,11 @@ DEFUN (bgp_evpn_advertise_vni_subnet,
return CMD_SUCCESS;
}
-DEFUN (no_bgp_evpn_advertise_vni_subnet,
- no_bgp_evpn_advertise_vni_subnet_cmd,
- "no advertise-subnet",
- NO_STR
- "Advertise All local VNIs\n")
+DEFUN_HIDDEN (no_bgp_evpn_advertise_vni_subnet,
+ no_bgp_evpn_advertise_vni_subnet_cmd,
+ "no advertise-subnet",
+ NO_STR
+ "Advertise All local VNIs\n")
{
struct bgp *bgp = VTY_GET_CONTEXT(bgp);
VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 17bb3fed96..6bc50fb77e 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -13206,8 +13206,6 @@ DEFUN (no_ip_community_list_standard_all,
"Specify community to accept\n"
COMMUNITY_VAL_STR)
{
- int delete_all = 0;
-
char *cl_name_or_number = NULL;
int direct = 0;
int style = COMMUNITY_LIST_STANDARD;
@@ -13222,7 +13220,7 @@ DEFUN (no_ip_community_list_standard_all,
char *str = argv_concat(argv, argc, idx);
int ret = community_list_unset(bgp_clist, cl_name_or_number, str,
- direct, style, delete_all);
+ direct, style);
XFREE(MTYPE_TMP, str);
@@ -13287,8 +13285,6 @@ DEFUN (no_ip_community_list_expanded_all,
"Specify community to accept\n"
COMMUNITY_VAL_STR)
{
- int delete_all = 0;
-
char *cl_name_or_number = NULL;
int direct = 0;
int style = COMMUNITY_LIST_EXPANDED;
@@ -13303,7 +13299,7 @@ DEFUN (no_ip_community_list_expanded_all,
char *str = argv_concat(argv, argc, idx);
int ret = community_list_unset(bgp_clist, cl_name_or_number, str,
- direct, style, delete_all);
+ direct, style);
XFREE(MTYPE_TMP, str);
@@ -13840,8 +13836,6 @@ DEFUN (no_ip_extcommunity_list_standard_all,
"Specify community to accept\n"
EXTCOMMUNITY_VAL_STR)
{
- int deleteall = 0;
-
int style = EXTCOMMUNITY_LIST_STANDARD;
int direct = 0;
char *cl_number_or_name = NULL;
@@ -13856,7 +13850,7 @@ DEFUN (no_ip_extcommunity_list_standard_all,
char *str = argv_concat(argv, argc, idx);
int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str,
- direct, style, deleteall);
+ direct, style);
XFREE(MTYPE_TMP, str);
@@ -13881,8 +13875,6 @@ DEFUN (no_ip_extcommunity_list_expanded_all,
"Specify community to accept\n"
"An ordered list as a regular-expression\n")
{
- int deleteall = 0;
-
int style = EXTCOMMUNITY_LIST_EXPANDED;
int direct = 0;
char *cl_number_or_name = NULL;
@@ -13897,7 +13889,7 @@ DEFUN (no_ip_extcommunity_list_expanded_all,
char *str = argv_concat(argv, argc, idx);
int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str,
- direct, style, deleteall);
+ direct, style);
XFREE(MTYPE_TMP, str);
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index 392c878675..c1af269d3f 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -2802,19 +2802,16 @@ rfapiBiStartWithdrawTimer(struct rfapi_import_table *import_table,
uint32_t lifetime;
struct rfapi_withdraw *wcb;
- if
- CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)
- {
- /*
- * Already on the path to being withdrawn,
- * should already have a timer set up to
- * delete it.
- */
- vnc_zlog_debug_verbose(
- "%s: already being withdrawn, do nothing",
- __func__);
- return;
- }
+ if (CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) {
+ /*
+ * Already on the path to being withdrawn,
+ * should already have a timer set up to
+ * delete it.
+ */
+ vnc_zlog_debug_verbose(
+ "%s: already being withdrawn, do nothing", __func__);
+ return;
+ }
rfapiGetVncLifetime(bi->attr, &lifetime);
vnc_zlog_debug_verbose("%s: VNC lifetime is %u", __func__, lifetime);
diff --git a/doc/developer/building-frr-on-alpine.rst b/doc/developer/building-frr-on-alpine.rst
index 089032b03c..d303784d4e 100644
--- a/doc/developer/building-frr-on-alpine.rst
+++ b/doc/developer/building-frr-on-alpine.rst
@@ -10,6 +10,28 @@ Depending on your host, there are different ways of installing docker. Refer
to the documentation here for instructions on how to install a free version of
docker: https://www.docker.com/community-edition
+Pre-built packages and docker images
+------------------------------------
+
+The master branch of https://github.com/frrouting/frr.git has a
+continuous delivery of docker images to docker hub at:
+https://hub.docker.com/r/ajones17/frr/. These images have the frr packages
+in /pkgs/apk and have the frr package pre-installed. To copy Alpine
+packages out of these images:
+
+::
+
+ id=`docker create ajones17/frr:latest`
+ docker cp ${id}:/pkgs _some_directory_
+ docker rm $id
+
+To run the frr daemons (see below for how to configure them):
+
+::
+
+ docker run -it --rm --name frr ajones17/frr:latest
+ docker exec -it frr /bin/sh
+
Work with sources
-----------------
diff --git a/eigrpd/eigrp_snmp.c b/eigrpd/eigrp_snmp.c
index e418b40343..7dd95b7bc6 100644
--- a/eigrpd/eigrp_snmp.c
+++ b/eigrpd/eigrp_snmp.c
@@ -516,7 +516,7 @@ eigrp_snmp_nbr_lookup_next(struct in_addr *nbr_addr, unsigned int *ifindex,
struct eigrp_neighbor *nbr;
struct route_node *rn;
struct eigrp_neighbor *min = NULL;
- struct eigrp *eigrp = eigrp;
+ struct eigrp *eigrp;
eigrp = eigrp_lookup();
diff --git a/lib/buffer.c b/lib/buffer.c
index 03202f1253..b573981c1b 100644
--- a/lib/buffer.c
+++ b/lib/buffer.c
@@ -429,6 +429,9 @@ in one shot. */
size_t iovcnt = 0;
size_t nbyte = 0;
+ if (fd < 0)
+ return BUFFER_ERROR;
+
for (d = b->head; d && (iovcnt < MAX_CHUNKS) && (nbyte < MAX_FLUSH);
d = d->next, iovcnt++) {
iov[iovcnt].iov_base = d->data + d->sp;
diff --git a/lib/imsg.c b/lib/imsg.c
index 0ea1dd6302..6419f805ab 100644
--- a/lib/imsg.c
+++ b/lib/imsg.c
@@ -241,6 +241,8 @@ struct ibuf *imsg_create(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid,
struct ibuf *wbuf;
struct imsg_hdr hdr;
+ memset(&hdr, 0x00, IMSG_HEADER_SIZE);
+
datalen += IMSG_HEADER_SIZE;
if (datalen > MAX_IMSGSIZE) {
errno = ERANGE;
diff --git a/lib/mpls.c b/lib/mpls.c
new file mode 100644
index 0000000000..759fe1206d
--- /dev/null
+++ b/lib/mpls.c
@@ -0,0 +1,100 @@
+/*
+ * mpls functions
+ *
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+#include <mpls.h>
+#include <memory.h>
+
+/*
+ * String to label conversion, labels separated by '/'.
+ *
+ * @param label_str labels separated by /
+ * @param num_labels number of labels; zero if conversion was unsuccessful
+ * @param labels preallocated mpls_label_t array of size MPLS_MAX_LABELS; only
+ * modified if the conversion succeeded
+ * @return 0 on success
+ * -1 if the string could not be parsed as integers
+ * -2 if a label was inside the reserved range (0-15)
+ * -3 if the number of labels given exceeds MPLS_MAX_LABELS
+ */
+int mpls_str2label(const char *label_str, uint8_t *num_labels,
+ mpls_label_t *labels)
+{
+ char *ostr; // copy of label string (start)
+ char *lstr; // copy of label string
+ char *nump; // pointer to next segment
+ char *endp; // end pointer
+ int i; // for iterating label_str
+ int rc; // return code
+ mpls_label_t pl[MPLS_MAX_LABELS]; // parsed labels
+
+ /* labels to zero until we have a successful parse */
+ ostr = lstr = XSTRDUP(MTYPE_TMP, label_str);
+ *num_labels = 0;
+ rc = 0;
+
+ for (i = 0; i < MPLS_MAX_LABELS && lstr && !rc; i++) {
+ nump = strsep(&lstr, "/");
+ pl[i] = strtoul(nump, &endp, 10);
+
+ /* format check */
+ if (*endp != '\0')
+ rc = -1;
+ /* validity check */
+ else if (!IS_MPLS_UNRESERVED_LABEL(pl[i]))
+ rc = -2;
+ }
+
+ /* excess labels */
+ if (!rc && i == MPLS_MAX_LABELS && lstr)
+ rc = -3;
+
+ if (!rc) {
+ *num_labels = i;
+ memcpy(labels, pl, *num_labels * sizeof(mpls_label_t));
+ }
+
+ XFREE(MTYPE_TMP, ostr);
+
+ return rc;
+}
+
+/*
+ * Label to string conversion, labels in string separated by '/'.
+ */
+char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf,
+ int len, int pretty)
+{
+ char label_buf[BUFSIZ];
+ int i;
+
+ buf[0] = '\0';
+ for (i = 0; i < num_labels; i++) {
+ if (i != 0)
+ strlcat(buf, "/", len);
+ if (pretty)
+ label2str(labels[i], label_buf, sizeof(label_buf));
+ else
+ snprintf(label_buf, sizeof(label_buf), "%u", labels[i]);
+ strlcat(buf, label_buf, len);
+ }
+
+ return buf;
+}
diff --git a/lib/mpls.h b/lib/mpls.h
index 4e5c70cf8c..ff6f1d6c98 100644
--- a/lib/mpls.h
+++ b/lib/mpls.h
@@ -28,6 +28,10 @@
#undef MPLS_LABEL_MAX
#endif
+#define MPLS_LABEL_HELPSTR \
+ "Specify label(s) for this route\nOne or more " \
+ "labels in the range (16-1048575) separated by '/'\n"
+
/* Well-known MPLS label values (RFC 3032 etc). */
#define MPLS_LABEL_IPV4_EXPLICIT_NULL 0 /* [RFC3032] */
#define MPLS_LABEL_ROUTER_ALERT 1 /* [RFC3032] */
@@ -192,5 +196,16 @@ static inline char *label2str(mpls_label_t label, char *buf, size_t len)
}
}
+/*
+ * String to label conversion, labels separated by '/'.
+ */
+int mpls_str2label(const char *label_str, uint8_t *num_labels,
+ mpls_label_t *labels);
+
+/*
+ * Label to string conversion, labels in string separated by '/'.
+ */
+char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf,
+ int len, int pretty);
#endif
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index 1ec49c2a02..5ac38d6685 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -20,6 +20,7 @@
#include <zebra.h>
#include <vrf.h>
+#include <sockunion.h>
#include <nexthop.h>
#include <nexthop_group.h>
#include <vty.h>
@@ -112,6 +113,9 @@ void nexthop_del(struct nexthop_group *nhg, struct nexthop *nh)
if (nexthop->next)
nexthop->next->prev = nexthop->prev;
+
+ nh->prev = NULL;
+ nh->next = NULL;
}
void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
@@ -151,6 +155,7 @@ static void nhgc_delete_nexthops(struct nexthop_group_cmd *nhgc)
while (nexthop) {
struct nexthop *next = nexthop_next(nexthop);
+ nexthop_del(&nhgc->nhg, nexthop);
if (nhg_hooks.del_nexthop)
nhg_hooks.del_nexthop(nhgc, nexthop);
@@ -169,6 +174,46 @@ struct nexthop_group_cmd *nhgc_find(const char *name)
return RB_FIND(nhgc_entry_head, &nhgc_entries, &find);
}
+static int nhgc_cmp_helper(const char *a, const char *b)
+{
+ if (!a && !b)
+ return 0;
+
+ if (a && !b)
+ return -1;
+
+ if (!a && b)
+ return 1;
+
+ return strcmp(a, b);
+}
+
+static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2)
+{
+ int ret;
+
+ ret = sockunion_cmp(&nh1->addr, &nh2->addr);
+ if (ret)
+ return ret;
+
+ ret = nhgc_cmp_helper(nh1->intf, nh2->intf);
+ if (ret)
+ return ret;
+
+ return nhgc_cmp_helper(nh1->nhvrf_name, nh2->nhvrf_name);
+}
+
+static void nhgl_delete(struct nexthop_hold *nh)
+{
+ if (nh->intf)
+ XFREE(MTYPE_TMP, nh->intf);
+
+ if (nh->nhvrf_name)
+ XFREE(MTYPE_TMP, nh->nhvrf_name);
+
+ XFREE(MTYPE_TMP, nh);
+}
+
static struct nexthop_group_cmd *nhgc_get(const char *name)
{
struct nexthop_group_cmd *nhgc;
@@ -181,6 +226,10 @@ static struct nexthop_group_cmd *nhgc_get(const char *name)
QOBJ_REG(nhgc, nexthop_group_cmd);
RB_INSERT(nhgc_entry_head, &nhgc_entries, nhgc);
+ nhgc->nhg_list = list_new();
+ nhgc->nhg_list->cmp = (int (*)(void *, void *))nhgl_cmp;
+ nhgc->nhg_list->del = (void (*)(void *))nhgl_delete;
+
if (nhg_hooks.new)
nhg_hooks.new(name);
}
@@ -196,6 +245,10 @@ static void nhgc_delete(struct nexthop_group_cmd *nhgc)
nhg_hooks.delete(nhgc->name);
RB_REMOVE(nhgc_entry_head, &nhgc_entries, nhgc);
+
+ list_delete_and_null(&nhgc->nhg_list);
+
+ XFREE(MTYPE_TMP, nhgc);
}
DEFINE_QOBJ_TYPE(nexthop_group_cmd)
@@ -228,65 +281,125 @@ DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NAME",
return CMD_SUCCESS;
}
-DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
- "[no] nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
- NO_STR
- "Specify one of the nexthops in this ECMP group\n"
- "v4 Address\n"
- "v6 Address\n"
- "Interface to use\n"
- "If the nexthop is in a different vrf tell us\n"
- "The nexthop-vrf Name\n")
+static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
+ const char *nhvrf_name,
+ const union sockunion *addr,
+ const char *intf)
+{
+ struct nexthop_hold *nh;
+
+ nh = XCALLOC(MTYPE_TMP, sizeof(*nh));
+
+ if (nhvrf_name)
+ nh->nhvrf_name = XSTRDUP(MTYPE_TMP, nhvrf_name);
+ if (intf)
+ nh->intf = XSTRDUP(MTYPE_TMP, intf);
+
+ nh->addr = *addr;
+
+ listnode_add_sort(nhgc->nhg_list, nh);
+}
+
+static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
+ const char *nhvrf_name,
+ const union sockunion *addr,
+ const char *intf)
+{
+ struct nexthop_hold *nh;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
+ if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 &&
+ sockunion_cmp(addr, &nh->addr) == 0 &&
+ nhgc_cmp_helper(intf, nh->intf) == 0)
+ break;
+ }
+
+ /*
+ * Something has gone seriously wrong, fail gracefully
+ */
+ if (!nh)
+ return;
+
+ list_delete_node(nhgc->nhg_list, node);
+
+ if (nh->nhvrf_name)
+ XFREE(MTYPE_TMP, nh->nhvrf_name);
+ if (nh->intf)
+ XFREE(MTYPE_TMP, nh->intf);
+
+ XFREE(MTYPE_TMP, nh);
+}
+
+static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
+ const union sockunion *addr,
+ const char *intf, const char *name)
{
- VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
struct vrf *vrf;
- struct nexthop nhop;
- struct nexthop *nh;
+
+ memset(nhop, 0, sizeof(*nhop));
if (name)
vrf = vrf_lookup_by_name(name);
else
vrf = vrf_lookup_by_id(VRF_DEFAULT);
- if (!vrf) {
- vty_out(vty, "Specified: %s is non-existent\n", name);
- return CMD_WARNING;
- }
+ if (!vrf)
+ return false;
- memset(&nhop, 0, sizeof(nhop));
- nhop.vrf_id = vrf->vrf_id;
+ nhop->vrf_id = vrf->vrf_id;
if (addr->sa.sa_family == AF_INET) {
- nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
+ nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
if (intf) {
- nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
- nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
- if (nhop.ifindex == IFINDEX_INTERNAL) {
- vty_out(vty,
- "Specified Intf %s does not exist in vrf: %s\n",
- intf, vrf->name);
- return CMD_WARNING;
- }
+ nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
+ if (nhop->ifindex == IFINDEX_INTERNAL)
+ return false;
} else
- nhop.type = NEXTHOP_TYPE_IPV4;
+ nhop->type = NEXTHOP_TYPE_IPV4;
} else {
- memcpy(&nhop.gate.ipv6, &addr->sin6.sin6_addr, 16);
+ memcpy(&nhop->gate.ipv6, &addr->sin6.sin6_addr, 16);
if (intf) {
- nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
- nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
- if (nhop.ifindex == IFINDEX_INTERNAL) {
- vty_out(vty,
- "Specified Intf %s does not exist in vrf: %s\n",
- intf, vrf->name);
- return CMD_WARNING;
- }
+ nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
+ if (nhop->ifindex == IFINDEX_INTERNAL)
+ return false;
} else
- nhop.type = NEXTHOP_TYPE_IPV6;
+ nhop->type = NEXTHOP_TYPE_IPV6;
+ }
+
+ return true;
+}
+
+DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
+ "[no] nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
+ NO_STR
+ "Specify one of the nexthops in this ECMP group\n"
+ "v4 Address\n"
+ "v6 Address\n"
+ "Interface to use\n"
+ "If the nexthop is in a different vrf tell us\n"
+ "The nexthop-vrf Name\n")
+{
+ VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
+ struct nexthop nhop;
+ struct nexthop *nh;
+ bool legal;
+
+ legal = nexthop_group_parse_nexthop(&nhop, addr, intf, name);
+
+ if (nhop.type == NEXTHOP_TYPE_IPV6
+ && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
+ vty_out(vty,
+ "Specified a v6 LL with no interface, rejecting\n");
+ return CMD_WARNING_CONFIG_FAILED;
}
nh = nexthop_exists(&nhgc->nhg, &nhop);
if (no) {
+ nexthop_group_unsave_nhop(nhgc, name, addr, intf);
if (nh) {
nexthop_del(&nhgc->nhg, nh);
@@ -297,12 +410,16 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
}
} else if (!nh) {
/* must be adding new nexthop since !no and !nexthop_exists */
- nh = nexthop_new();
+ if (legal) {
+ nh = nexthop_new();
+
+ memcpy(nh, &nhop, sizeof(nhop));
+ nexthop_add(&nhgc->nhg.nexthop, nh);
+ }
- memcpy(nh, &nhop, sizeof(nhop));
- nexthop_add(&nhgc->nhg.nexthop, nh);
+ nexthop_group_save_nhop(nhgc, name, addr, intf);
- if (nhg_hooks.add_nexthop)
+ if (legal && nhg_hooks.add_nexthop)
nhg_hooks.add_nexthop(nhgc, nh);
}
@@ -353,17 +470,37 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
vty_out(vty, "\n");
}
+static void nexthop_group_write_nexthop_internal(struct vty *vty,
+ struct nexthop_hold *nh)
+{
+ char buf[100];
+
+ vty_out(vty, "nexthop ");
+
+ vty_out(vty, "%s", sockunion2str(&nh->addr, buf, sizeof(buf)));
+
+ if (nh->intf)
+ vty_out(vty, " %s", nh->intf);
+
+ if (nh->nhvrf_name)
+ vty_out(vty, " nexthop-vrf %s", nh->nhvrf_name);
+
+ vty_out(vty, "\n");
+}
+
static int nexthop_group_write(struct vty *vty)
{
struct nexthop_group_cmd *nhgc;
- struct nexthop *nh;
+ struct nexthop_hold *nh;
RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
+ struct listnode *node;
+
vty_out(vty, "nexthop-group %s\n", nhgc->name);
- for (nh = nhgc->nhg.nexthop; nh; nh = nh->next) {
+ for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
vty_out(vty, " ");
- nexthop_group_write_nexthop(vty, nh);
+ nexthop_group_write_nexthop_internal(vty, nh);
}
vty_out(vty, "!\n");
@@ -372,6 +509,152 @@ static int nexthop_group_write(struct vty *vty)
return 1;
}
+void nexthop_group_enable_vrf(struct vrf *vrf)
+{
+ struct nexthop_group_cmd *nhgc;
+ struct nexthop_hold *nhh;
+
+ RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
+ struct nexthop nhop;
+ struct nexthop *nh;
+
+ if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
+ nhh->intf,
+ nhh->nhvrf_name))
+ continue;
+
+ nh = nexthop_exists(&nhgc->nhg, &nhop);
+
+ if (nh)
+ continue;
+
+ if (nhop.vrf_id != vrf->vrf_id)
+ continue;
+
+ nh = nexthop_new();
+
+ memcpy(nh, &nhop, sizeof(nhop));
+ nexthop_add(&nhgc->nhg.nexthop, nh);
+
+ if (nhg_hooks.add_nexthop)
+ nhg_hooks.add_nexthop(nhgc, nh);
+ }
+ }
+}
+
+void nexthop_group_disable_vrf(struct vrf *vrf)
+{
+ struct nexthop_group_cmd *nhgc;
+ struct nexthop_hold *nhh;
+
+ RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
+ struct nexthop nhop;
+ struct nexthop *nh;
+
+ if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
+ nhh->intf,
+ nhh->nhvrf_name))
+ continue;
+
+ nh = nexthop_exists(&nhgc->nhg, &nhop);
+
+ if (!nh)
+ continue;
+
+ if (nh->vrf_id != vrf->vrf_id)
+ continue;
+
+ nexthop_del(&nhgc->nhg, nh);
+
+ if (nhg_hooks.del_nexthop)
+ nhg_hooks.del_nexthop(nhgc, nh);
+
+ nexthop_free(nh);
+ }
+ }
+}
+
+void nexthop_group_interface_state_change(struct interface *ifp,
+ ifindex_t oldifindex)
+{
+ struct nexthop_group_cmd *nhgc;
+ struct nexthop_hold *nhh;
+
+ RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
+ struct listnode *node;
+ struct nexthop *nh;
+
+ if (if_is_up(ifp)) {
+ for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
+ struct nexthop nhop;
+
+ if (!nexthop_group_parse_nexthop(
+ &nhop, &nhh->addr, nhh->intf,
+ nhh->nhvrf_name))
+ continue;
+
+ switch (nhop.type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_BLACKHOLE:
+ continue;
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ break;
+ }
+ nh = nexthop_exists(&nhgc->nhg, &nhop);
+
+ if (nh)
+ continue;
+
+ if (ifp->ifindex != nhop.ifindex)
+ continue;
+
+ nh = nexthop_new();
+
+ memcpy(nh, &nhop, sizeof(nhop));
+ nexthop_add(&nhgc->nhg.nexthop, nh);
+
+ if (nhg_hooks.add_nexthop)
+ nhg_hooks.add_nexthop(nhgc, nh);
+ }
+ } else {
+ struct nexthop *next_nh;
+
+ for (nh = nhgc->nhg.nexthop; nh; nh = next_nh) {
+ next_nh = nh->next;
+ switch (nh->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_BLACKHOLE:
+ continue;
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ break;
+ }
+
+ if (oldifindex != nh->ifindex)
+ continue;
+
+ nexthop_del(&nhgc->nhg, nh);
+
+ if (nhg_hooks.del_nexthop)
+ nhg_hooks.del_nexthop(nhgc, nh);
+
+ nexthop_free(nh);
+ }
+ }
+ }
+}
+
void nexthop_group_init(void (*new)(const char *name),
void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
const struct nexthop *nhop),
diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h
index c2e4c4d757..a44f4e3542 100644
--- a/lib/nexthop_group.h
+++ b/lib/nexthop_group.h
@@ -56,6 +56,13 @@ void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
(nhop); \
(nhop) = nexthop_next(nhop)
+
+struct nexthop_hold {
+ char *nhvrf_name;
+ union sockunion addr;
+ char *intf;
+};
+
struct nexthop_group_cmd {
RB_ENTRY(nexthop_group_cmd) nhgc_entry;
@@ -64,6 +71,8 @@ struct nexthop_group_cmd {
struct nexthop_group nhg;
+ struct list *nhg_list;
+
QOBJ_FIELDS
};
RB_HEAD(nhgc_entry_head, nexthp_group_cmd);
@@ -85,6 +94,11 @@ void nexthop_group_init(
const struct nexthop *nhop),
void (*delete)(const char *name));
+void nexthop_group_enable_vrf(struct vrf *vrf);
+void nexthop_group_disable_vrf(struct vrf *vrf);
+void nexthop_group_interface_state_change(struct interface *ifp,
+ ifindex_t oldifindex);
+
extern struct nexthop *nexthop_exists(struct nexthop_group *nhg,
struct nexthop *nh);
diff --git a/lib/route_types.pl b/lib/route_types.pl
index 9d50acaaed..66384fe449 100755
--- a/lib/route_types.pl
+++ b/lib/route_types.pl
@@ -54,15 +54,15 @@ while (<STDIN>) {
$_ =~ s/\s*,\s*/,/g;
- # else: 7-field line
+ # else: 8-field line
my @f = split(/,/, $_);
- unless (@f == 7 || @f == 8) {
+ unless (@f == 8 || @f == 9) {
die "invalid input on route_types line $.\n";
}
my $proto = $f[0];
$f[3] = $1 if ($f[3] =~ /^'(.*)'$/);
- $f[6] = $1 if ($f[6] =~ /^"(.*)"$/);
+ $f[7] = $1 if ($f[7] =~ /^"(.*)"$/);
$protodetail{$proto} = {
"number" => scalar @protos,
@@ -72,8 +72,9 @@ while (<STDIN>) {
"char" => $f[3],
"ipv4" => int($f[4]),
"ipv6" => int($f[5]),
- "shorthelp" => $f[6],
- "restrict2" => $f[7],
+ "redist" => int($f[6]),
+ "shorthelp" => $f[7],
+ "restrict2" => $f[8],
};
push @protos, $proto;
$daemons{$f[2]} = {
@@ -136,8 +137,9 @@ sub collect {
next if ($protodetail{$p}->{"daemon"} eq $daemon && $daemon ne "zebra");
next if ($protodetail{$p}->{"restrict2"} ne "" &&
$protodetail{$p}->{"restrict2"} ne $daemon);
+ next if ($protodetail{$p}->{"redist"} eq 0);
next unless (($ipv4 && $protodetail{$p}->{"ipv4"})
- || ($ipv6 && $protodetail{$p}->{"ipv6"}));
+ || ($ipv6 && $protodetail{$p}->{"ipv6"}));
push @names, $protodetail{$p}->{"cname"};
push @help, " \"".$protodetail{$p}->{"longhelp"}."\\n\"";
}
diff --git a/lib/route_types.txt b/lib/route_types.txt
index 91eaf94d95..cfa55e468c 100644
--- a/lib/route_types.txt
+++ b/lib/route_types.txt
@@ -7,8 +7,8 @@
# Lines /beginning/ with # are comments.
#
####
-# 7 field line has format:
-# ZServ route type, canonical name, daemon, route char, ipv4, ipv6, short desc
+# 9 field line has format:
+# ZServ route type, canonical name, daemon, route char, ipv4, ipv6, redist, short desc, Restrictions
#
# Zserv route type: Corresponding with zebra.h. Key field.
# canonical name: Typically derived from the route type definition.
@@ -25,9 +25,11 @@
# 'X' is reserved as the 'not needed' placeholder.
# ipv4: IPv4 capable? yes/no, or 1/0.
# ipv6: IPv6 capable? ditto.
+# redist: Allow this protocol to be used in redistribution statements
# short desc: Very brief description. Used in header of
# 'show ip route'. May be specified as NULL
# if the canonical name suffices.
+# Restriction: If this cannot be used with the listed protocol for redistribution events
#
# Key fields obviously must be a unique ASCII alpha-numeric word.
# Lower-case is required, brevity is optional but highly desirable.
@@ -43,43 +45,43 @@
# If you add a new routing protocol here, make sure you also update
# meta_queue_map in zebra_rib.c
#
-## type cname daemon C 4 6 short help
-ZEBRA_ROUTE_SYSTEM, system, NULL, 'X', 0, 0, "Reserved"
-ZEBRA_ROUTE_KERNEL, kernel, zebra, 'K', 1, 1, "kernel route"
-ZEBRA_ROUTE_CONNECT, connected, zebra, 'C', 1, 1, "connected"
-ZEBRA_ROUTE_STATIC, static, zebra, 'S', 1, 1, "static"
-ZEBRA_ROUTE_RIP, rip, ripd, 'R', 1, 0, "RIP"
-ZEBRA_ROUTE_RIPNG, ripng, ripngd, 'R', 0, 1, "RIPng"
-ZEBRA_ROUTE_OSPF, ospf, ospfd, 'O', 1, 0, "OSPF"
-ZEBRA_ROUTE_OSPF6, ospf6, ospf6d, 'O', 0, 1, "OSPFv3"
-ZEBRA_ROUTE_ISIS, isis, isisd, 'I', 1, 1, "IS-IS"
-ZEBRA_ROUTE_BGP, bgp, bgpd, 'B', 1, 1, "BGP"
-ZEBRA_ROUTE_PIM, pim, pimd, 'P', 1, 0, "PIM"
-ZEBRA_ROUTE_EIGRP, eigrp, eigrpd, 'E', 1, 0, "EIGRP"
-ZEBRA_ROUTE_NHRP, nhrp, nhrpd, 'N', 1, 1, "NHRP"
+## type cname daemon C 4 6 Redist short help Restrictions
+ZEBRA_ROUTE_SYSTEM, system, NULL, 'X', 0, 0, 0, "Reserved"
+ZEBRA_ROUTE_KERNEL, kernel, zebra, 'K', 1, 1, 1, "kernel route"
+ZEBRA_ROUTE_CONNECT, connected, zebra, 'C', 1, 1, 1, "connected"
+ZEBRA_ROUTE_STATIC, static, zebra, 'S', 1, 1, 1, "static"
+ZEBRA_ROUTE_RIP, rip, ripd, 'R', 1, 0, 1, "RIP"
+ZEBRA_ROUTE_RIPNG, ripng, ripngd, 'R', 0, 1, 1, "RIPng"
+ZEBRA_ROUTE_OSPF, ospf, ospfd, 'O', 1, 0, 1, "OSPF"
+ZEBRA_ROUTE_OSPF6, ospf6, ospf6d, 'O', 0, 1, 1, "OSPFv3"
+ZEBRA_ROUTE_ISIS, isis, isisd, 'I', 1, 1, 1, "IS-IS"
+ZEBRA_ROUTE_BGP, bgp, bgpd, 'B', 1, 1, 1, "BGP"
+ZEBRA_ROUTE_PIM, pim, pimd, 'P', 0, 0, 0, "PIM"
+ZEBRA_ROUTE_EIGRP, eigrp, eigrpd, 'E', 1, 0, 1, "EIGRP"
+ZEBRA_ROUTE_NHRP, nhrp, nhrpd, 'N', 1, 1, 1, "NHRP"
# HSLS and OLSR both are AFI independent (so: 1, 1), however
# we want to disable for them for general Quagga distribution.
# This at least makes it trivial for users of these protocols
# to 'switch on' redist support (direct numeric entry remaining
# possible).
-ZEBRA_ROUTE_HSLS, hsls, hslsd, 'H', 0, 0, "HSLS"
-ZEBRA_ROUTE_OLSR, olsr, olsrd, 'o', 0, 0, "OLSR"
-ZEBRA_ROUTE_TABLE, table, zebra, 'T', 1, 1, "Table"
-ZEBRA_ROUTE_LDP, ldp, ldpd, 'L', 0, 0, "LDP"
+ZEBRA_ROUTE_HSLS, hsls, hslsd, 'H', 0, 0, 0, "HSLS"
+ZEBRA_ROUTE_OLSR, olsr, olsrd, 'o', 0, 0, 0, "OLSR"
+ZEBRA_ROUTE_TABLE, table, zebra, 'T', 1, 1, 1, "Table"
+ZEBRA_ROUTE_LDP, ldp, ldpd, 'L', 0, 0, 0, "LDP"
#vnc when sent to zebra
-ZEBRA_ROUTE_VNC, vnc, NULL, 'v', 1, 1, "VNC"
+ZEBRA_ROUTE_VNC, vnc, NULL, 'v', 1, 1, 1, "VNC"
# vnc when sent to bgp
-ZEBRA_ROUTE_VNC_DIRECT, vnc-direct,NULL, 'V', 1, 1, "VNC-Direct", bgpd
+ZEBRA_ROUTE_VNC_DIRECT, vnc-direct,NULL, 'V', 1, 1, 1, "VNC-Direct", bgpd
# vnc when sent to bgp (resolve NVE mode)
-ZEBRA_ROUTE_VNC_DIRECT_RH, vnc-rn, NULL, 'V', 0, 0, "VNC-RN"
+ZEBRA_ROUTE_VNC_DIRECT_RH, vnc-rn, NULL, 'V', 0, 0, 0, "VNC-RN"
# bgp unicast -> vnc
-ZEBRA_ROUTE_BGP_DIRECT, bgp-direct, NULL, 'b', 0, 0, "BGP-Direct"
+ZEBRA_ROUTE_BGP_DIRECT, bgp-direct, NULL, 'b', 0, 0, 0, "BGP-Direct"
# bgp unicast -> vnc
-ZEBRA_ROUTE_BGP_DIRECT_EXT, bgp-direct-to-nve-groups, NULL, 'e', 0, 0, "BGP2VNC"
-ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, "Babel"
-ZEBRA_ROUTE_SHARP, sharp, sharpd, 'D', 1, 1, "SHARP"
-ZEBRA_ROUTE_PBR, pbr, pbrd, 'F', 1, 1, "PBR"
-ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, "-"
+ZEBRA_ROUTE_BGP_DIRECT_EXT, bgp-direct-to-nve-groups, NULL, 'e', 0, 0, 0, "BGP2VNC"
+ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, 1, "Babel"
+ZEBRA_ROUTE_SHARP, sharp, sharpd, 'D', 1, 1, 1, "SHARP"
+ZEBRA_ROUTE_PBR, pbr, pbrd, 'F', 1, 1, 0, "PBR"
+ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-"
## help strings
diff --git a/lib/subdir.am b/lib/subdir.am
index 0319f7764e..3b469d4524 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -41,6 +41,7 @@ lib_libfrr_la_SOURCES = \
lib/memory.c \
lib/memory_vty.c \
lib/module.c \
+ lib/mpls.c \
lib/network.c \
lib/nexthop.c \
lib/netns_linux.c \
diff --git a/lib/vrf.c b/lib/vrf.c
index b493f832f3..db539d375d 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -34,6 +34,7 @@
#include "command.h"
#include "ns.h"
#include "privs.h"
+#include "nexthop_group.h"
/* default VRF ID value used when VRF backend is not NETNS */
#define VRF_DEFAULT_INTERNAL 0
@@ -269,6 +270,13 @@ int vrf_enable(struct vrf *vrf)
if (vrf_master.vrf_enable_hook)
(*vrf_master.vrf_enable_hook)(vrf);
+ /*
+ * If we have any nexthop group entries that
+ * are awaiting vrf initialization then
+ * let's let people know about it
+ */
+ nexthop_group_enable_vrf(vrf);
+
return 1;
}
diff --git a/lib/zclient.c b/lib/zclient.c
index e1ce40ce70..48182d6b2c 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -37,6 +37,7 @@
#include "mpls.h"
#include "sockopt.h"
#include "pbr.h"
+#include "nexthop_group.h"
DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient")
DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs")
@@ -1697,7 +1698,9 @@ struct interface *zebra_interface_link_params_read(struct stream *s)
void zebra_interface_if_set_value(struct stream *s, struct interface *ifp)
{
uint8_t link_params_status = 0;
+ ifindex_t old_ifindex;
+ old_ifindex = ifp->ifindex;
/* Read interface's index. */
if_set_index(ifp, stream_getl(s));
ifp->status = stream_getc(s);
@@ -1724,6 +1727,8 @@ void zebra_interface_if_set_value(struct stream *s, struct interface *ifp)
struct if_link_params *iflp = if_link_params_get(ifp);
link_params_set_value(s, iflp);
}
+
+ nexthop_group_interface_state_change(ifp, old_ifindex);
}
size_t zebra_interface_link_params_write(struct stream *s,
diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c
index 7464b14b1f..6825be83ac 100644
--- a/ospfd/ospf_snmp.c
+++ b/ospfd/ospf_snmp.c
@@ -2117,7 +2117,7 @@ static struct ospf_neighbor *ospf_snmp_nbr_lookup_next(struct in_addr *nbr_addr,
struct ospf_neighbor *nbr;
struct route_node *rn;
struct ospf_neighbor *min = NULL;
- struct ospf *ospf = ospf;
+ struct ospf *ospf;
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c
index 05adc5aa4f..26df7a24cd 100644
--- a/ospfd/ospf_te.c
+++ b/ospfd/ospf_te.c
@@ -1161,16 +1161,13 @@ static struct ospf_lsa *ospf_mpls_te_lsa_new(struct ospf *ospf,
/* Set opaque-LSA header fields depending of the type of RFC */
if (IS_INTER_AS(lp->type)) {
- if
- IS_FLOOD_AS(lp->type)
- {
- options |= OSPF_OPTION_E; /* Enable AS external
- as we flood
- Inter-AS with
- Opaque Type 11 */
- lsa_type = OSPF_OPAQUE_AS_LSA;
- }
- else {
+ if (IS_FLOOD_AS(lp->type)) {
+ /* Enable AS external as we flood Inter-AS with Opaque
+ * Type 11
+ */
+ options |= OSPF_OPTION_E;
+ lsa_type = OSPF_OPAQUE_AS_LSA;
+ } else {
options |= LSA_OPTIONS_GET(
area); /* Get area default option */
options |= LSA_OPTIONS_NSSA_GET(area);
@@ -1210,12 +1207,12 @@ static struct ospf_lsa *ospf_mpls_te_lsa_new(struct ospf *ospf,
/* Now, create an OSPF LSA instance. */
if ((new = ospf_lsa_new()) == NULL) {
- zlog_warn("ospf_mpls_te_lsa_new: ospf_lsa_new() ?");
+ zlog_warn("%s: ospf_lsa_new() ?", __func__);
stream_free(s);
return NULL;
}
if ((new->data = ospf_lsa_data_new(length)) == NULL) {
- zlog_warn("ospf_mpls_te_lsa_new: ospf_lsa_data_new() ?");
+ zlog_warn("%s: ospf_lsa_data_new() ?", __func__);
ospf_lsa_unlock(&new);
new = NULL;
stream_free(s);
diff --git a/pbrd/pbr_debug.c b/pbrd/pbr_debug.c
index e9b4a52955..82f045c462 100644
--- a/pbrd/pbr_debug.c
+++ b/pbrd/pbr_debug.c
@@ -43,16 +43,7 @@ const char *pbr_debugs_conflines[] = {
"debug pbr events",
};
-/*
- * Set or unset flags on all debugs for pbrd.
- *
- * flags
- * The flags to set
- *
- * set
- * Whether to set or unset the specified flags
- */
-static void pbr_debug_set_all(uint32_t flags, bool set)
+void pbr_debug_set_all(uint32_t flags, bool set)
{
for (unsigned int i = 0; i < array_size(pbr_debugs); i++) {
DEBUG_FLAGS_SET(pbr_debugs[i], flags, set);
@@ -63,36 +54,13 @@ static void pbr_debug_set_all(uint32_t flags, bool set)
}
}
-/*
- * Check flags on all debugs for pbrd.
- *
- * flags
- * The flags to set
- *
- * Returns:
- * The subset of the given flags that were set in all pbrd debugs
- */
-static uint32_t pbr_debug_check_all(uint32_t flags)
-{
- uint32_t mode = DEBUG_MODE_ALL;
-
- for (unsigned int i = 0; i < array_size(pbr_debugs); i++)
- mode &= DEBUG_MODE_CHECK(pbr_debugs[i], flags);
- return mode;
-}
-
-static int pbr_debug_config_write_helper(struct vty *vty, bool config)
+int pbr_debug_config_write_helper(struct vty *vty, bool config)
{
uint32_t mode = DEBUG_MODE_ALL;
if (config)
mode = DEBUG_MODE_CONF;
- if (pbr_debug_check_all(DEBUG_MODE_CONF) == mode) {
- vty_out(vty, "debug pbr\n");
- return 0;
- }
-
for (unsigned int i = 0; i < array_size(pbr_debugs); i++)
if (DEBUG_MODE_CHECK(pbr_debugs[i], mode))
vty_out(vty, "%s\n", pbr_debugs_conflines[i]);
@@ -104,70 +72,9 @@ int pbr_debug_config_write(struct vty *vty)
return pbr_debug_config_write_helper(vty, true);
}
-/* PBR debugging CLI ------------------------------------------------------- */
-/* clang-format off */
-
-DEFPY(debug_pbr,
- debug_pbr_cmd,
- "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
- NO_STR
- DEBUG_STR
- "Policy Based Routing\n"
- "Policy maps\n"
- "PBRD <-> Zebra communications\n"
- "Nexthop tracking\n"
- "Events\n")
-{
- uint32_t mode = DEBUG_NODE2MODE(vty->node);
-
- if (map)
- DEBUG_MODE_SET(&pbr_dbg_map, mode, !no);
- if (zebra)
- DEBUG_MODE_SET(&pbr_dbg_zebra, mode, !no);
- if (nht)
- DEBUG_MODE_SET(&pbr_dbg_nht, mode, !no);
- if (events)
- DEBUG_MODE_SET(&pbr_dbg_event, mode, !no);
-
- /* no specific debug --> act on all of them */
- if (strmatch(argv[argc - 1]->text, "pbr"))
- pbr_debug_set_all(mode, !no);
-
- return CMD_SUCCESS;
-}
-
-DEFUN_NOSH(show_debugging_pbr,
- show_debugging_pbr_cmd,
- "show debugging [pbr]",
- SHOW_STR
- DEBUG_STR
- "Policy Based Routing\n")
-{
- vty_out(vty, "PBR debugging status:\n");
-
- pbr_debug_config_write_helper(vty, false);
-
- return CMD_SUCCESS;
-}
-
-/* clang-format on */
-/* ------------------------------------------------------------------------- */
-
-static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
-
struct debug_callbacks pbr_dbg_cbs = {.debug_set_all = pbr_debug_set_all};
void pbr_debug_init(void)
{
debug_init(&pbr_dbg_cbs);
}
-
-void pbr_debug_init_vty(void)
-{
- install_node(&debug_node, pbr_debug_config_write);
-
- install_element(VIEW_NODE, &debug_pbr_cmd);
- install_element(CONFIG_NODE, &debug_pbr_cmd);
-
- install_element(VIEW_NODE, &show_debugging_pbr_cmd);
-}
diff --git a/pbrd/pbr_debug.h b/pbrd/pbr_debug.h
index 2744724629..e72fb88beb 100644
--- a/pbrd/pbr_debug.h
+++ b/pbrd/pbr_debug.h
@@ -38,9 +38,29 @@ extern struct debug pbr_dbg_event;
void pbr_debug_init(void);
/*
- * Install PBR debugging VTY commands.
+ * Set or unset flags on all debugs for pbrd.
+ *
+ * flags
+ * The flags to set
+ *
+ * set
+ * Whether to set or unset the specified flags
+ */
+void pbr_debug_set_all(uint32_t flags, bool set);
+
+/*
+ * Config write helper.
+ *
+ * vty
+ * Vty to write to
+ *
+ * config
+ * Whether we are writing to show run or saving config file
+ *
+ * Returns:
+ * 0 for convenience
*/
-void pbr_debug_init_vty(void);
+int pbr_debug_config_write_helper(struct vty *vty, bool config);
/*
* Print PBR debugging configuration.
diff --git a/pbrd/pbr_main.c b/pbrd/pbr_main.c
index 638e284a1a..ba09621083 100644
--- a/pbrd/pbr_main.c
+++ b/pbrd/pbr_main.c
@@ -152,6 +152,11 @@ int main(int argc, char **argv, char **envp)
pbr_nhgroup_del_nexthop_cb,
pbr_nhgroup_delete_cb);
+ /*
+ * So we safely ignore these commands since
+ * we are getting them at this point in time
+ */
+ access_list_init();
pbr_nht_init();
pbr_map_init();
pbr_zebra_init();
diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c
index ea79320a71..eb2c082fb9 100644
--- a/pbrd/pbr_map.c
+++ b/pbrd/pbr_map.c
@@ -152,8 +152,9 @@ void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp_add)
pmi->pbrm = pbrm;
listnode_add_sort(pbrm->incoming, pmi);
+ bf_assign_index(pbrm->ifi_bitfield, pmi->install_bit);
pbr_map_check_valid(pbrm->name);
- if (pbrm->valid && !pbrm->installed)
+ if (pbrm->valid)
pbr_map_install(pbrm);
}
@@ -193,6 +194,8 @@ extern void pbr_map_delete(struct pbr_map_sequence *pbrms)
if (pbrm->seqnumbers->count == 0) {
RB_REMOVE(pbr_map_entry_head, &pbr_maps, pbrm);
+
+ bf_free(pbrm->ifi_bitfield);
XFREE(MTYPE_PBR_MAP, pbrm);
}
}
@@ -210,13 +213,12 @@ void pbr_map_delete_nexthop_group(struct pbr_map_sequence *pbrms)
pbrm->valid = false;
pbrms->nhs_installed = false;
- pbrms->installed = false;
pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
pbrms->nhgrp_name = NULL;
}
-struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique,
- ifindex_t ifindex)
+struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex,
+ struct pbr_map_interface **ppmi)
{
struct pbr_map_sequence *pbrms;
struct listnode *snode, *inode;
@@ -228,6 +230,9 @@ struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique,
if (pmi->ifp->ifindex != ifindex)
continue;
+ if (ppmi)
+ *ppmi = pmi;
+
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode,
pbrms)) {
DEBUGD(&pbr_dbg_map, "%s: Comparing %u to %u",
@@ -268,7 +273,7 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
pbrm = pbrm_find(name);
if (!pbrm) {
pbrm = XCALLOC(MTYPE_PBR_MAP, sizeof(*pbrm));
- strcpy(pbrm->name, name);
+ snprintf(pbrm->name, sizeof(pbrm->name), "%s", name);
pbrm->seqnumbers = list_new();
pbrm->seqnumbers->cmp =
@@ -284,6 +289,7 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
RB_INSERT(pbr_map_entry_head, &pbr_maps, pbrm);
+ bf_init(pbrm->ifi_bitfield, 64);
pbr_map_add_interfaces(pbrm);
}
@@ -305,8 +311,6 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
QOBJ_REG(pbrms, pbr_map_sequence);
listnode_add_sort(pbrm->seqnumbers, pbrms);
-
- pbrm->installed = false;
}
return pbrms;
@@ -463,6 +467,8 @@ void pbr_map_policy_delete(struct pbr_map *pbrm, struct pbr_map_interface *pmi)
listnode_delete(pbrm->incoming, pmi);
pmi->pbrm = NULL;
+
+ bf_release_index(pbrm->ifi_bitfield, pmi->install_bit);
XFREE(MTYPE_PBR_MAP_INTERFACE, pmi);
}
@@ -541,8 +547,9 @@ void pbr_map_check(struct pbr_map_sequence *pbrms)
pbrms->seqno, pbrms->reason);
}
- for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
+ for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) {
pbr_send_pbr_map(pbrms, pmi, install);
+ }
}
void pbr_map_install(struct pbr_map *pbrm)
@@ -557,8 +564,6 @@ void pbr_map_install(struct pbr_map *pbrm)
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
pbr_send_pbr_map(pbrms, pmi, true);
-
- pbrm->installed = true;
}
void pbr_map_init(void)
diff --git a/pbrd/pbr_map.h b/pbrd/pbr_map.h
index 5cb22d7429..7cd079d169 100644
--- a/pbrd/pbr_map.h
+++ b/pbrd/pbr_map.h
@@ -20,6 +20,8 @@
#ifndef __PBR_MAP_H__
#define __PBR_MAP_H__
+#include <bitfield.h>
+
struct pbr_map {
/*
* RB Tree of the pbr_maps
@@ -40,20 +42,21 @@ struct pbr_map {
*/
struct list *incoming;
+ bitfield_t ifi_bitfield;
/*
* If valid is true we think the pbr_map is valid,
* If false, look in individual pbrms to see
* what we think is the invalid reason
*/
bool valid;
-
- bool installed;
};
RB_HEAD(pbr_map_entry_head, pbr_map);
RB_PROTOTYPE(pbr_map_entry_head, pbr_map, pbr_map_entry, pbr_map_compare)
struct pbr_map_interface {
+ uint32_t install_bit;
+
struct interface *ifp;
struct pbr_map *pbrm;
@@ -112,7 +115,7 @@ struct pbr_map_sequence {
/*
* Are we installed
*/
- bool installed;
+ uint64_t installed;
/*
* A reason of 0 means we think the pbr_map_sequence is good to go
@@ -134,8 +137,9 @@ DECLARE_QOBJ_TYPE(pbr_map_sequence)
extern struct pbr_map_entry_head pbr_maps;
extern struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno);
-extern struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique,
- ifindex_t ifindex);
+extern struct pbr_map_sequence *
+pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex,
+ struct pbr_map_interface **ppmi);
extern struct pbr_map *pbrm_find(const char *name);
extern void pbr_map_delete(struct pbr_map_sequence *pbrms);
diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c
index 1ce8c2104d..1ccf3ebffa 100644
--- a/pbrd/pbr_nht.c
+++ b/pbrd/pbr_nht.c
@@ -209,6 +209,13 @@ void pbr_nhgroup_add_cb(const char *name)
struct nexthop_group_cmd *nhgc;
nhgc = nhgc_find(name);
+
+ if (!nhgc) {
+ DEBUGD(&pbr_dbg_nht, "%s: Could not find nhgc with name: %s\n",
+ __PRETTY_FUNCTION__, name);
+ return;
+ }
+
pnhgc = pbr_nht_add_group(name);
DEBUGD(&pbr_dbg_nht, "%s: Added nexthop-group %s", __PRETTY_FUNCTION__,
@@ -312,8 +319,16 @@ static void pbr_nht_find_nhg_from_table_install(struct hash_backet *b,
if (pnhgc->table_id == *table_id) {
DEBUGD(&pbr_dbg_nht, "%s: Table ID (%u) matches %s",
__PRETTY_FUNCTION__, *table_id, pnhgc->name);
- pnhgc->installed = true;
- pbr_map_schedule_policy_from_nhg(pnhgc->name);
+
+ /*
+ * If the table has been re-handled by zebra
+ * and we are already installed no need to do
+ * anything here.
+ */
+ if (!pnhgc->installed) {
+ pnhgc->installed = true;
+ pbr_map_schedule_policy_from_nhg(pnhgc->name);
+ }
}
}
@@ -402,8 +417,6 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
install_afi = pbr_nht_which_afi(nhg, nh_afi);
- pnhgc->installed = false;
-
route_add(pnhgc, nhg, install_afi);
}
@@ -433,7 +446,7 @@ void pbr_nht_change_group(const char *name)
return;
memset(&find, 0, sizeof(find));
- strcpy(find.name, name);
+ snprintf(find.name, sizeof(find.name), "%s", name);
pnhgc = hash_lookup(pbr_nhg_hash, &find);
if (!pnhgc) {
@@ -504,11 +517,10 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
pbrm->valid = false;
pbrms->nhs_installed = false;
- pbrms->installed = false;
pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
memset(&find, 0, sizeof(find));
- strcpy(&find.name[0], pbrms->internal_nhg_name);
+ snprintf(find.name, sizeof(find.name), "%s", pbrms->internal_nhg_name);
pnhgc = hash_lookup(pbr_nhg_hash, &find);
nh = pbrms->nhg->nexthop;
@@ -543,7 +555,7 @@ struct pbr_nexthop_group_cache *pbr_nht_add_group(const char *name)
return NULL;
}
- strcpy(lookup.name, name);
+ snprintf(lookup.name, sizeof(lookup.name), "%s", name);
pnhgc = hash_get(pbr_nhg_hash, &lookup, pbr_nhgc_alloc);
DEBUGD(&pbr_dbg_nht, "%s: Retrieved NHGC @ %p", __PRETTY_FUNCTION__,
pnhgc);
@@ -602,7 +614,7 @@ bool pbr_nht_nexthop_group_valid(const char *name)
DEBUGD(&pbr_dbg_nht, "%s: %s", __PRETTY_FUNCTION__, name);
- strcpy(lookup.name, name);
+ snprintf(lookup.name, sizeof(lookup.name), "%s", name);
pnhgc = hash_get(pbr_nhg_hash, &lookup, NULL);
if (!pnhgc)
return false;
@@ -757,7 +769,7 @@ uint32_t pbr_nht_get_table(const char *name)
struct pbr_nexthop_group_cache *pnhgc;
memset(&find, 0, sizeof(find));
- strcpy(find.name, name);
+ snprintf(find.name, sizeof(find.name), "%s", name);
pnhgc = hash_lookup(pbr_nhg_hash, &find);
if (!pnhgc) {
@@ -776,7 +788,7 @@ bool pbr_nht_get_installed(const char *name)
struct pbr_nexthop_group_cache *pnhgc;
memset(&find, 0, sizeof(find));
- strcpy(find.name, name);
+ snprintf(find.name, sizeof(find.name), "%s", name);
pnhgc = hash_lookup(pbr_nhg_hash, &find);
diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c
index 87ec3804a5..475ad86b58 100644
--- a/pbrd/pbr_vty.c
+++ b/pbrd/pbr_vty.c
@@ -251,8 +251,14 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
intf, vrf->name);
return CMD_WARNING_CONFIG_FAILED;
}
- } else
+ } else {
+ if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
+ vty_out(vty,
+ "Specified a v6 LL with no interface, rejecting\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
nhop.type = NEXTHOP_TYPE_IPV6;
+ }
}
if (pbrms->nhg)
@@ -313,36 +319,30 @@ DEFPY (pbr_policy,
pbrm = pbrm_find(mapname);
if (!pbr_ifp) {
- /*
- * Some one could have fat fingered the interface
- * name
- */
+ /* we don't want one and we don't have one, so... */
+ if (no)
+ return CMD_SUCCESS;
+
+ /* Some one could have fat fingered the interface name */
pbr_ifp = pbr_if_new(ifp);
}
if (no) {
if (strcmp(pbr_ifp->mapname, mapname) == 0) {
- strcpy(pbr_ifp->mapname, "");
-
+ pbr_ifp->mapname[0] = '\0';
if (pbrm)
pbr_map_interface_delete(pbrm, ifp);
}
} else {
- if (strcmp(pbr_ifp->mapname, "") == 0) {
- strcpy(pbr_ifp->mapname, mapname);
-
- if (pbrm)
- pbr_map_add_interface(pbrm, ifp);
- } else {
- if (!(strcmp(pbr_ifp->mapname, mapname) == 0)) {
- old_pbrm = pbrm_find(pbr_ifp->mapname);
- if (old_pbrm)
- pbr_map_interface_delete(old_pbrm, ifp);
- strcpy(pbr_ifp->mapname, mapname);
- if (pbrm)
- pbr_map_add_interface(pbrm, ifp);
- }
+ if (strcmp(pbr_ifp->mapname, "") != 0) {
+ old_pbrm = pbrm_find(pbr_ifp->mapname);
+ if (old_pbrm)
+ pbr_map_interface_delete(old_pbrm, ifp);
}
+ snprintf(pbr_ifp->mapname, sizeof(pbr_ifp->mapname),
+ "%s", mapname);
+ if (pbrm)
+ pbr_map_add_interface(pbrm, ifp);
}
return CMD_SUCCESS;
@@ -389,7 +389,7 @@ DEFPY (show_pbr_map,
pbr_map_reason_string(pbrms->reason, rbuf,
sizeof(rbuf));
vty_out(vty,
- " Seq: %u rule: %u Installed: %d(%u) Reason: %s\n",
+ " Seq: %u rule: %u Installed: %" PRIu64 "(%u) Reason: %s\n",
pbrms->seqno, pbrms->ruleno, pbrms->installed,
pbrms->unique, pbrms->reason ? rbuf : "Valid");
@@ -483,6 +483,58 @@ DEFPY (show_pbr_interface,
return CMD_SUCCESS;
}
+/* PBR debugging CLI ------------------------------------------------------- */
+/* clang-format off */
+
+static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
+
+DEFPY(debug_pbr,
+ debug_pbr_cmd,
+ "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
+ NO_STR
+ DEBUG_STR
+ "Policy Based Routing\n"
+ "Policy maps\n"
+ "PBRD <-> Zebra communications\n"
+ "Nexthop tracking\n"
+ "Events\n")
+{
+ uint32_t mode = DEBUG_NODE2MODE(vty->node);
+
+ if (map)
+ DEBUG_MODE_SET(&pbr_dbg_map, mode, !no);
+ if (zebra)
+ DEBUG_MODE_SET(&pbr_dbg_zebra, mode, !no);
+ if (nht)
+ DEBUG_MODE_SET(&pbr_dbg_nht, mode, !no);
+ if (events)
+ DEBUG_MODE_SET(&pbr_dbg_event, mode, !no);
+
+ /* no specific debug --> act on all of them */
+ if (strmatch(argv[argc - 1]->text, "pbr"))
+ pbr_debug_set_all(mode, !no);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_NOSH(show_debugging_pbr,
+ show_debugging_pbr_cmd,
+ "show debugging [pbr]",
+ SHOW_STR
+ DEBUG_STR
+ "Policy Based Routing\n")
+{
+ vty_out(vty, "PBR debugging status:\n");
+
+ pbr_debug_config_write_helper(vty, false);
+
+ return CMD_SUCCESS;
+}
+
+/* clang-format on */
+/* ------------------------------------------------------------------------- */
+
+
static struct cmd_node interface_node = {
INTERFACE_NODE, "%s(config-if)# ", 1 /* vtysh ? yes */
};
@@ -567,6 +619,12 @@ void pbr_vty_init(void)
install_node(&pbr_map_node,
pbr_vty_map_config_write);
+ /* debug */
+ install_node(&debug_node, pbr_debug_config_write);
+ install_element(VIEW_NODE, &debug_pbr_cmd);
+ install_element(CONFIG_NODE, &debug_pbr_cmd);
+ install_element(VIEW_NODE, &show_debugging_pbr_cmd);
+
install_default(PBRMAP_NODE);
install_element(CONFIG_NODE, &pbr_map_cmd);
@@ -580,6 +638,4 @@ void pbr_vty_init(void)
install_element(VIEW_NODE, &show_pbr_map_cmd);
install_element(VIEW_NODE, &show_pbr_interface_cmd);
install_element(VIEW_NODE, &show_pbr_nexthop_group_cmd);
-
- pbr_debug_init_vty();
}
diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c
index a1a2d34ac1..4e5b5f3dde 100644
--- a/pbrd/pbr_zebra.c
+++ b/pbrd/pbr_zebra.c
@@ -45,17 +45,6 @@ DEFINE_MTYPE_STATIC(PBRD, PBR_INTERFACE, "PBR Interface")
/* Zebra structure to hold current status. */
struct zclient *zclient;
-static struct interface *zebra_interface_if_lookup(struct stream *s)
-{
- char ifname_tmp[INTERFACE_NAMSIZ];
-
- /* Read interface name. */
- stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
-
- /* And look it up. */
- return if_lookup_by_name(ifname_tmp, VRF_DEFAULT);
-}
-
struct pbr_interface *pbr_if_new(struct interface *ifp)
{
struct pbr_interface *pbr_ifp;
@@ -140,7 +129,7 @@ static int interface_state_up(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
- zebra_interface_if_lookup(zclient->ibuf);
+ zebra_interface_state_read(zclient->ibuf, vrf_id);
return 0;
}
@@ -206,13 +195,16 @@ static int rule_notify_owner(int command, struct zclient *zclient,
uint32_t seqno, priority, unique;
enum zapi_rule_notify_owner note;
struct pbr_map_sequence *pbrms;
+ struct pbr_map_interface *pmi;
ifindex_t ifi;
+ uint64_t installed;
if (!zapi_rule_notify_decode(zclient->ibuf, &seqno, &priority, &unique,
&ifi, &note))
return -1;
- pbrms = pbrms_lookup_unique(unique, ifi);
+ pmi = NULL;
+ pbrms = pbrms_lookup_unique(unique, ifi, &pmi);
if (!pbrms) {
DEBUGD(&pbr_dbg_zebra,
"%s: Failure to lookup pbrms based upon %u",
@@ -220,18 +212,21 @@ static int rule_notify_owner(int command, struct zclient *zclient,
return 0;
}
+ installed = 1 << pmi->install_bit;
+
switch (note) {
case ZAPI_RULE_FAIL_INSTALL:
DEBUGD(&pbr_dbg_zebra, "%s: Recieved RULE_FAIL_INSTALL",
__PRETTY_FUNCTION__);
- pbrms->installed = false;
+ pbrms->installed &= ~installed;
break;
case ZAPI_RULE_INSTALLED:
- pbrms->installed = true;
+ pbrms->installed |= installed;
DEBUGD(&pbr_dbg_zebra, "%s: Recived RULE_INSTALLED",
__PRETTY_FUNCTION__);
break;
case ZAPI_RULE_REMOVED:
+ pbrms->installed &= ~installed;
DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED",
__PRETTY_FUNCTION__);
break;
@@ -499,9 +494,23 @@ void pbr_send_pbr_map(struct pbr_map_sequence *pbrms,
{
struct pbr_map *pbrm = pbrms->parent;
struct stream *s;
+ uint64_t is_installed = 1 << pmi->install_bit;
- DEBUGD(&pbr_dbg_zebra, "%s: for %s %d", __PRETTY_FUNCTION__, pbrm->name,
- install);
+ is_installed &= pbrms->installed;
+
+ DEBUGD(&pbr_dbg_zebra, "%s: for %s %d(%" PRIu64 ")",
+ __PRETTY_FUNCTION__, pbrm->name, install, is_installed);
+
+ /*
+ * If we are installed and asked to do so again
+ * just return. If we are not installed and asked
+ * and asked to delete just return;
+ */
+ if (install && is_installed)
+ return;
+
+ if (!install && !is_installed)
+ return;
s = zclient->obuf;
stream_reset(s);
diff --git a/pimd/mtracebis_routeget.c b/pimd/mtracebis_routeget.c
index d75aaa3708..8c1cd8d963 100644
--- a/pimd/mtracebis_routeget.c
+++ b/pimd/mtracebis_routeget.c
@@ -81,7 +81,7 @@ int routeget(struct in_addr dst, struct in_addr *src, struct in_addr *gw)
ret = rtnl_open(&rth, 0);
- if (ret < 0)
+ if (ret < 0 || rth.fd <= 0)
return ret;
if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
diff --git a/tests/ospf6d/test_lsdb.c b/tests/ospf6d/test_lsdb.c
index 633e88e769..ec0835c719 100644
--- a/tests/ospf6d/test_lsdb.c
+++ b/tests/ospf6d/test_lsdb.c
@@ -38,9 +38,15 @@ static size_t lsa_count = 0;
static void lsa_check_resize(size_t len)
{
+ struct ospf6_lsa **templsas;
+
if (lsa_count >= len)
return;
- lsas = realloc(lsas, len * sizeof(lsas[0]));
+ templsas = realloc(lsas, len * sizeof(lsas[0]));
+ if (templsas)
+ lsas = templsas;
+ else
+ return;
memset(lsas + lsa_count, 0, sizeof(lsas[0]) * (len - lsa_count));
lsa_count = len;
diff --git a/zebra/client_main.c b/zebra/client_main.c
index 4035e53f7c..1ead7ee1fd 100644
--- a/zebra/client_main.c
+++ b/zebra/client_main.c
@@ -148,9 +148,8 @@ void zebra_sim(FILE *fp)
continue;
}
- for (i = 0; i < 10; i++) {
- if (!zebra_type[i].str)
- break;
+ i = 0;
+ while (zebra_type[i++].str) {
if (strcmp(zebra_type[i].str, str) == 0) {
type = zebra_type[i].type;
break;
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 6a7a75f209..2e19d6fb75 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -531,7 +531,7 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re,
re->tag, rmap_name);
if (ret != RMAP_MATCH) {
- UNSET_FLAG(same->flags, ZEBRA_FLAG_SELECTED);
+ UNSET_FLAG(re->flags, ZEBRA_FLAG_SELECTED);
zebra_del_import_table_entry(rn, re);
return 0;
}
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index df53a06bc2..e68e3aaafd 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -1350,7 +1350,17 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
req.r.rtm_src_len = src_p ? src_p->prefixlen : 0;
req.r.rtm_protocol = zebra2proto(re->type);
req.r.rtm_scope = RT_SCOPE_UNIVERSE;
- req.r.rtm_type = RTN_UNICAST;
+
+ /*
+ * blackhole routes are not RTN_UNICAST, they are
+ * RTN_ BLACKHOLE|UNREACHABLE|PROHIBIT
+ * so setting this value as a RTN_UNICAST would
+ * cause the route lookup of just the prefix
+ * to fail. So no need to specify this for
+ * the RTM_DELROUTE case
+ */
+ if (cmd != RTM_DELROUTE)
+ req.r.rtm_type = RTN_UNICAST;
addattr_l(&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
if (src_p)
@@ -2220,11 +2230,11 @@ static int netlink_ipneigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
* in re-adding the neighbor if it is a valid "remote" neighbor.
*/
if (ndm->ndm_state & NUD_VALID)
- return zebra_vxlan_local_neigh_add_update(
+ return zebra_vxlan_handle_kernel_neigh_update(
ifp, link_if, &ip, &mac, ndm->ndm_state,
ext_learned);
- return zebra_vxlan_local_neigh_del(ifp, link_if, &ip);
+ return zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
}
if (IS_ZEBRA_DEBUG_KERNEL)
@@ -2237,7 +2247,7 @@ static int netlink_ipneigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
/* Process the delete - it may result in re-adding the neighbor if it is
* a valid "remote" neighbor.
*/
- return zebra_vxlan_local_neigh_del(ifp, link_if, &ip);
+ return zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
}
static int netlink_neigh_table(struct sockaddr_nl *snl, struct nlmsghdr *h,
@@ -2412,7 +2422,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)
{
- return netlink_neigh_update2(ifp, ip, mac, NUD_REACHABLE, RTM_NEWNEIGH);
+ return netlink_neigh_update2(ifp, ip, mac, NUD_NOARP, RTM_NEWNEIGH);
}
int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip)
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index 3cc1848ee3..7df03efc10 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -1723,83 +1723,6 @@ void kernel_lsp_pass_fail(zebra_lsp_t *lsp, enum southbound_results res)
}
/*
- * String to label conversion, labels separated by '/'.
- *
- * @param label_str labels separated by /
- * @param num_labels number of labels; zero if conversion was unsuccessful
- * @param labels preallocated mpls_label_t array of size MPLS_MAX_LABELS; only
- * modified if the conversion succeeded
- * @return 0 on success
- * -1 if the string could not be parsed as integers
- * -2 if a label was inside the reserved range (0-15)
- * -3 if the number of labels given exceeds MPLS_MAX_LABELS
- */
-int mpls_str2label(const char *label_str, uint8_t *num_labels,
- mpls_label_t *labels)
-{
- char *ostr; // copy of label string (start)
- char *lstr; // copy of label string
- char *nump; // pointer to next segment
- char *endp; // end pointer
- int i; // for iterating label_str
- int rc; // return code
- mpls_label_t pl[MPLS_MAX_LABELS]; // parsed labels
-
- /* labels to zero until we have a successful parse */
- ostr = lstr = XSTRDUP(MTYPE_TMP, label_str);
- *num_labels = 0;
- rc = 0;
-
- for (i = 0; i < MPLS_MAX_LABELS && lstr && !rc; i++) {
- nump = strsep(&lstr, "/");
- pl[i] = strtoul(nump, &endp, 10);
-
- /* format check */
- if (*endp != '\0')
- rc = -1;
- /* validity check */
- else if (!IS_MPLS_UNRESERVED_LABEL(pl[i]))
- rc = -2;
- }
-
- /* excess labels */
- if (!rc && i == MPLS_MAX_LABELS && lstr)
- rc = -3;
-
- if (!rc) {
- *num_labels = i;
- memcpy(labels, pl, *num_labels * sizeof(mpls_label_t));
- }
-
- XFREE(MTYPE_TMP, ostr);
-
- return rc;
-}
-
-/*
- * Label to string conversion, labels in string separated by '/'.
- */
-char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf,
- int len, int pretty)
-{
- char label_buf[BUFSIZ];
- int i;
-
- buf[0] = '\0';
- for (i = 0; i < num_labels; i++) {
- if (i != 0)
- strlcat(buf, "/", len);
- if (pretty)
- label2str(labels[i], label_buf, sizeof(label_buf));
- else
- snprintf(label_buf, sizeof(label_buf), "%u", labels[i]);
- strlcat(buf, label_buf, len);
- }
-
- return buf;
-}
-
-/*
* Install dynamic LSP entry.
*/
int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h
index 2637327a7e..98905a2831 100644
--- a/zebra/zebra_mpls.h
+++ b/zebra/zebra_mpls.h
@@ -43,10 +43,6 @@
? AF_INET6 \
: AF_INET)
-#define MPLS_LABEL_HELPSTR \
- "Specify label(s) for this route\nOne or more " \
- "labels in the range (16-1048575) separated by '/'\n"
-
/* Typedefs */
typedef struct zebra_ile_t_ zebra_ile_t;
@@ -168,18 +164,6 @@ struct zebra_fec_t_ {
/* Function declarations. */
/*
- * String to label conversion, labels separated by '/'.
- */
-int mpls_str2label(const char *label_str, uint8_t *num_labels,
- mpls_label_t *labels);
-
-/*
- * Label to string conversion, labels in string separated by '/'.
- */
-char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf,
- int len, int pretty);
-
-/*
* Add/update global label block.
*/
int zebra_mpls_label_block_add(struct zebra_vrf *zvrf, uint32_t start_label,
diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c
index 27daa2d807..758365d716 100644
--- a/zebra/zebra_pbr.c
+++ b/zebra/zebra_pbr.c
@@ -111,6 +111,7 @@ int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
struct pbr_rule_unique_lookup {
struct zebra_pbr_rule *rule;
uint32_t unique;
+ struct interface *ifp;
};
static int pbr_rule_lookup_unique_walker(struct hash_backet *b, void *data)
@@ -118,7 +119,7 @@ static int pbr_rule_lookup_unique_walker(struct hash_backet *b, void *data)
struct pbr_rule_unique_lookup *pul = data;
struct zebra_pbr_rule *rule = b->data;
- if (pul->unique == rule->rule.unique) {
+ if (pul->unique == rule->rule.unique && pul->ifp == rule->ifp) {
pul->rule = rule;
return HASHWALK_ABORT;
}
@@ -127,11 +128,13 @@ static int pbr_rule_lookup_unique_walker(struct hash_backet *b, void *data)
}
static struct zebra_pbr_rule *pbr_rule_lookup_unique(struct zebra_ns *zns,
- uint32_t unique)
+ uint32_t unique,
+ struct interface *ifp)
{
struct pbr_rule_unique_lookup pul;
pul.unique = unique;
+ pul.ifp = ifp;
pul.rule = NULL;
hash_walk(zns->rules_hash, &pbr_rule_lookup_unique_walker, &pul);
@@ -275,7 +278,7 @@ static void *pbr_rule_alloc_intern(void *arg)
void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule)
{
struct zebra_pbr_rule *unique =
- pbr_rule_lookup_unique(zns, rule->rule.unique);
+ pbr_rule_lookup_unique(zns, rule->rule.unique, rule->ifp);
(void)hash_get(zns->rules_hash, rule, pbr_rule_alloc_intern);
kernel_add_pbr_rule(rule);
@@ -493,8 +496,10 @@ void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule,
zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_INSTALL);
break;
case SOUTHBOUND_DELETE_SUCCESS:
+ zsend_rule_notify_owner(rule, ZAPI_RULE_REMOVED);
break;
case SOUTHBOUND_DELETE_FAILURE:
+ zsend_rule_notify_owner(rule, ZAPI_RULE_REMOVED);
break;
}
}
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index 879da092f0..22a04ee23d 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -561,8 +561,10 @@ static void zebra_rnh_process_pbr_tables(int family,
* just rethink it. Yes this is a hammer, but
* a small one
*/
- if (o_re)
+ if (o_re) {
+ SET_FLAG(o_re->status, ROUTE_ENTRY_CHANGED);
rib_queue_add(o_rn);
+ }
}
}
}
diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c
index 914b049c05..24160655d7 100644
--- a/zebra/zebra_static.c
+++ b/zebra/zebra_static.c
@@ -516,7 +516,9 @@ int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p,
if (ifp && ifp->ifindex != IFINDEX_INTERNAL) {
si->ifindex = ifp->ifindex;
static_install_route(afi, safi, p, src_p, si);
- }
+ } else
+ zlog_warn("Static Route using %s interface not installed because the interface does not exist in specified vrf",
+ ifname);
}
return 1;
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 84fc76d7f6..16aece9747 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -207,6 +207,9 @@ static int zebra_static_route_holdem(
struct static_hold_route *shr, *lookup;
struct listnode *node;
+ zlog_warn("Static Route to %s not installed currently because dependent config not fully available",
+ dest_str);
+
shr = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(*shr));
shr->vrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, zvrf->vrf->name);
shr->nhvrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, nh_zvrf->vrf->name);
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index fa8f837408..6e901a0457 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -1930,6 +1930,183 @@ static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet,
return;
}
+static int zvni_local_neigh_update(zebra_vni_t *zvni,
+ struct interface *ifp,
+ struct ipaddr *ip,
+ struct ethaddr *macaddr)
+{
+ char buf[ETHER_ADDR_STRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+ zebra_neigh_t *n = NULL;
+ zebra_mac_t *zmac = NULL, *old_zmac = NULL;
+
+ /* create a dummy MAC if the MAC is not already present */
+ zmac = zvni_mac_lookup(zvni, macaddr);
+ if (!zmac) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "AUTO MAC %s created for neigh %s on VNI %u",
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni);
+
+ zmac = zvni_mac_add(zvni, macaddr);
+ if (!zmac) {
+ zlog_warn("Failed to add MAC %s VNI %u",
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ zvni->vni);
+ return -1;
+ }
+
+ memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info));
+ memset(&zmac->flags, 0, sizeof(uint32_t));
+ SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO);
+ }
+
+ /* If same entry already exists, it might be a change or it might be a
+ * move from remote to local.
+ */
+ n = zvni_neigh_lookup(zvni, ip);
+ if (n) {
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+ if (memcmp(n->emac.octet, macaddr->octet,
+ ETH_ALEN) == 0) {
+ /* Update any params and return - client doesn't
+ * care about a purely local change.
+ */
+ n->ifindex = ifp->ifindex;
+ return 0;
+ }
+
+ /* If the MAC has changed,
+ * need to issue a delete first
+ * as this means a different MACIP route.
+ * Also, need to do some unlinking/relinking.
+ */
+ zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
+ &n->emac, 0);
+ old_zmac = zvni_mac_lookup(zvni, &n->emac);
+ if (old_zmac) {
+ listnode_delete(old_zmac->neigh_list, n);
+ zvni_deref_ip2mac(zvni, old_zmac, 0);
+ }
+
+ /* Update the forwarding info. */
+ n->ifindex = ifp->ifindex;
+ memcpy(&n->emac, macaddr, ETH_ALEN);
+
+ /* Link to new MAC */
+ listnode_add_sort(zmac->neigh_list, n);
+
+ } else
+ /* Neighbor has moved from remote to local. */
+ {
+ /* If MAC has changed, do the unlink/link */
+ if (memcmp(n->emac.octet, macaddr->octet,
+ ETH_ALEN) != 0) {
+ old_zmac = zvni_mac_lookup(zvni, &n->emac);
+ if (old_zmac) {
+ listnode_delete(old_zmac->neigh_list,
+ n);
+ zvni_deref_ip2mac(zvni, old_zmac, 0);
+ }
+
+ /* Link to new MAC */
+ memcpy(&n->emac, macaddr, ETH_ALEN);
+ listnode_add_sort(zmac->neigh_list, n);
+ }
+
+ /* Mark appropriately */
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
+ n->r_vtep_ip.s_addr = 0;
+ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+ n->ifindex = ifp->ifindex;
+ }
+ } else {
+ /* New neighbor - create */
+ n = zvni_neigh_add(zvni, ip, macaddr);
+ if (!n) {
+ zlog_err(
+ "Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
+ ipaddr2str(ip, buf2, sizeof(buf2)),
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ifp->name, ifp->ifindex, zvni->vni);
+ return -1;
+ }
+ /* Set "local" forwarding info. */
+ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+ n->ifindex = ifp->ifindex;
+ }
+
+ /* Before we program this in BGP, we need to check if MAC is locally
+ * learnt as well
+ */
+ if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Skipping neigh %s add to client as MAC %s is not local on VNI %u",
+ ipaddr2str(ip, buf2, sizeof(buf2)),
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ zvni->vni);
+
+ return 0;
+ }
+
+ /* Inform BGP. */
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Neigh %s (MAC %s) is now ACTIVE on L2-VNI %u",
+ ipaddr2str(ip, buf2, sizeof(buf2)),
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ zvni->vni);
+ ZEBRA_NEIGH_SET_ACTIVE(n);
+
+ return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, 0);
+}
+
+static int zvni_remote_neigh_update(zebra_vni_t *zvni,
+ struct interface *ifp,
+ struct ipaddr *ip,
+ struct ethaddr *macaddr,
+ uint16_t state)
+{
+ char buf[ETHER_ADDR_STRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+ zebra_neigh_t *n = NULL;
+ zebra_mac_t *zmac = NULL;
+
+ /* If the neighbor is unknown, there is no further action. */
+ n = zvni_neigh_lookup(zvni, ip);
+ if (!n)
+ return 0;
+
+ /* If a remote entry, see if it needs to be refreshed */
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
+#ifdef GNU_LINUX
+ if (state & NUD_STALE)
+ zvni_neigh_install(zvni, n);
+#endif
+ } else {
+ /* We got a "remote" neighbor notification for an entry
+ * we think is local. This can happen in a multihoming
+ * scenario - but only if the MAC is already "remote".
+ * Just mark our entry as "remote".
+ */
+ zmac = zvni_mac_lookup(zvni, macaddr);
+ if (!zmac || !CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) {
+ zlog_err("Ignore remote neigh %s (MAC %s) on L2-VNI %u - MAC unknown or local",
+ ipaddr2str(&n->ip, buf2, sizeof(buf2)),
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ zvni->vni);
+ return -1;
+ }
+
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+ SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
+ n->r_vtep_ip = zmac->fwd_info.r_vtep_ip;
+ }
+
+ return 0;
+}
+
/*
* Make hash key for MAC.
*/
@@ -4626,13 +4803,14 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
}
/*
- * Handle neighbor delete (on a VLAN device / L3 interface) from the
- * kernel. This may result in either the neighbor getting deleted from
- * our database or being re-added to the kernel (if it is a valid
+ * Handle neighbor delete notification from the kernel (on a VLAN device
+ * / L3 interface). This may result in either the neighbor getting deleted
+ * from our database or being re-added to the kernel (if it is a valid
* remote neighbor).
*/
-int zebra_vxlan_local_neigh_del(struct interface *ifp,
- struct interface *link_if, struct ipaddr *ip)
+int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp,
+ struct interface *link_if,
+ struct ipaddr *ip)
{
char buf[INET6_ADDRSTRLEN];
char buf2[ETHER_ADDR_STRLEN];
@@ -4708,20 +4886,21 @@ int zebra_vxlan_local_neigh_del(struct interface *ifp,
}
/*
- * Handle neighbor add or update (on a VLAN device / L3 interface)
- * from the kernel.
+ * Handle neighbor add or update notification from the kernel (on a VLAN
+ * device / L3 interface). This is typically for a local neighbor but can
+ * also be for a remote neighbor (e.g., ageout notification). It could
+ * also be a "move" scenario.
*/
-int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
- struct interface *link_if,
- struct ipaddr *ip,
- struct ethaddr *macaddr, uint16_t state,
- uint8_t ext_learned)
+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)
{
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
zebra_vni_t *zvni = NULL;
- zebra_neigh_t *n = NULL;
- zebra_mac_t *zmac = NULL, *old_zmac = NULL;
zebra_l3vni_t *zl3vni = NULL;
/* check if this is a remote neigh entry corresponding to remote
@@ -4746,114 +4925,11 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
ifp->ifindex, state, ext_learned ? "ext-learned " : "",
zvni->vni);
- /* create a dummy MAC if the MAC is not already present */
- zmac = zvni_mac_lookup(zvni, macaddr);
- if (!zmac) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("AUTO MAC %s created for neigh %s on VNI %u",
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ipaddr2str(ip, buf2, sizeof(buf2)),
- zvni->vni);
-
- zmac = zvni_mac_add(zvni, macaddr);
- if (!zmac) {
- zlog_warn("Failed to add MAC %s VNI %u",
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- zvni->vni);
- return -1;
- }
-
- memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info));
- memset(&zmac->flags, 0, sizeof(uint32_t));
- SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO);
- }
-
- /* If same entry already exists, it might be a change or it might be a
- * move from remote to local.
- */
- n = zvni_neigh_lookup(zvni, ip);
- if (n) {
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
- if (memcmp(n->emac.octet, macaddr->octet, ETH_ALEN)
- == 0) {
- /* Update any params and return - client doesn't
- * care about a purely local change.
- */
- n->ifindex = ifp->ifindex;
- return 0;
- }
-
- /* If the MAC has changed,
- * need to issue a delete first
- * as this means a different MACIP route.
- * Also, need to do some unlinking/relinking.
- */
- zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
- &n->emac, 0);
- old_zmac = zvni_mac_lookup(zvni, &n->emac);
- if (old_zmac) {
- listnode_delete(old_zmac->neigh_list, n);
- zvni_deref_ip2mac(zvni, old_zmac, 0);
- }
-
- /* Set "local" forwarding info. */
- SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
- n->ifindex = ifp->ifindex;
- memcpy(&n->emac, macaddr, ETH_ALEN);
-
- /* Link to new MAC */
- listnode_add_sort(zmac->neigh_list, n);
- } else if (ext_learned)
- /* The neighbor is remote and that is the notification we got.
- */
- {
- /* TODO: Evaluate if we need to do anything here. */
- return 0;
- } else
- /* Neighbor has moved from remote to local. */
- {
- UNSET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
- n->r_vtep_ip.s_addr = 0;
- SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
- n->ifindex = ifp->ifindex;
- }
- } else {
- n = zvni_neigh_add(zvni, ip, macaddr);
- if (!n) {
- zlog_err(
- "Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
- ipaddr2str(ip, buf2, sizeof(buf2)),
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ifp->name, ifp->ifindex, zvni->vni);
- return -1;
- }
- /* Set "local" forwarding info. */
- SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
- n->ifindex = ifp->ifindex;
- }
-
- /* Before we program this in BGP, we need to check if MAC is locally
- * learnt as well */
- if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Skipping neigh %s add to client as MAC %s is not local on VNI %u",
- ipaddr2str(ip, buf2, sizeof(buf2)),
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- zvni->vni);
-
- return 0;
- }
-
- /* Inform BGP. */
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("neigh %s (MAC %s) is now ACTIVE on L2-VNI %u",
- ipaddr2str(ip, buf2, sizeof(buf2)),
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- zvni->vni);
- ZEBRA_NEIGH_SET_ACTIVE(n);
+ /* Is this about a local neighbor or a remote one? */
+ if (!ext_learned)
+ return zvni_local_neigh_update(zvni, ifp, ip, macaddr);
- return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, n->flags);
+ return zvni_remote_neigh_update(zvni, ifp, ip, macaddr, state);
}
diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h
index 16b01e6acd..6153c7d7e3 100644
--- a/zebra/zebra_vxlan.h
+++ b/zebra/zebra_vxlan.h
@@ -122,10 +122,10 @@ extern int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
extern int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if);
extern int zebra_vxlan_svi_down(struct interface *ifp,
struct interface *link_if);
-extern int zebra_vxlan_local_neigh_add_update(
+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);
-extern int zebra_vxlan_local_neigh_del(struct interface *ifp,
+extern int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp,
struct interface *link_if,
struct ipaddr *ip);
extern int zebra_vxlan_local_mac_add_update(struct interface *ifp,