diff options
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(ð_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(ð_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 \ @@ -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, ¬e)) 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, |
