diff options
92 files changed, 1654 insertions, 665 deletions
diff --git a/COMMUNITY.md b/COMMUNITY.md deleted file mode 100644 index fa00310851..0000000000 --- a/COMMUNITY.md +++ /dev/null @@ -1 +0,0 @@ -Moved to doc/developer/workflow.rst diff --git a/Makefile.am b/Makefile.am index 6cac1a7ba3..3b8deb5884 100644 --- a/Makefile.am +++ b/Makefile.am @@ -83,7 +83,6 @@ rc_SCRIPTS = \ endif EXTRA_DIST += \ - REPORTING-BUGS \ SERVICES \ aclocal.m4 \ update-autotools \ @@ -5,9 +5,9 @@ Currently FRRouting supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, RIPv2, RIPng, IS-IS, PIM-SM/MSDP, LDP and Babel as well as very early support for EIGRP and NHRP. -See the file REPORTING-BUGS to report bugs. +See doc/user/bugs.rst for information on how to report bugs. -See COMMUNITY.md for information on contributing. +See doc/developer/workflow.rst for information on contributing. Free RRRouting is free software. See the file COPYING for copying conditions. diff --git a/README.NetBSD b/README.NetBSD deleted file mode 100755 index c97e3bcb38..0000000000 --- a/README.NetBSD +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/sh - -# This file is helpful for building FRR from cvs on NetBSD, and -# probably on any system using pkgsrc. -# One should have readline installed already (pkgsrc/devel/readline). - -MAKE=make -# FRR is currently documented not to require GNU make, but sometimes -# BSD make fails. Enable this if statement as a workaround. -if false; then - MAKE=gmake - echo "WARNING: using gmake to work around nonportable makefiles" -fi - -# Use /usr/frr to be independent, and /usr/pkg to overwrite pkgsrc. -PREFIX=/usr/pkg - -case $1 in - - build) - # Omitted because it is now default: - # --enable-opaque-lsa - ./bootstrap.sh - LDFLAGS="-L/usr/pkg/lib -R/usr/pkg/lib" CPPFLAGS="-I/usr/pkg/include" \ - ./configure --prefix=${PREFIX} \ - --sysconfdir=/etc/zebra --localstatedir=/var/run/zebra \ - --enable-exampledir=${PREFIX}/share/examples/zebra \ - --enable-pkgsrcrcdir=${PREFIX}/etc/rc.d \ - --enable-vtysh - ${MAKE} - ;; - - install) - ${MAKE} install - ;; - - clean) - ${MAKE} clean - ;; - - *) - echo "Usage: README.NetBSD (build|install|clean)" - exit 1 - ;; - -esac diff --git a/REPORTING-BUGS b/REPORTING-BUGS deleted file mode 100644 index 339ebc24d5..0000000000 --- a/REPORTING-BUGS +++ /dev/null @@ -1,35 +0,0 @@ -This file describes the procedure for reporting FRRouting bugs. You are not -obliged to follow this format, but it would be great help for FRRouting developers -if you report a bug as described below. - -Bugs submitted with woefully incomplete information may be summarily -closed. Submitters of bugs against old versions may be asked to -retest against the latest release. Submitters may be asked for -additional information. Bugs may be closed after 30 days of -non-response to requests to reconfirm or supply additional -information. - -Report bugs on Github Issue Tracker at - https://github.com/frrouting/frr/issues - -Please supply the following information: -1. Your FRRouting version or if it is from git then the commit reference. - Please try to report bugs against git master or the latest release. -2. FRR daemons you run e.g. bgpd or ripd and full name of your OS. Any - specific options you compiled FRR with. -3. Problem description. Copy and paste relative commands and their output to - describe your network setup e.g. "zebra>show ip route". - Please, also give your simple network layout and output of relative OS - commands (e.g., ifconfig (BSD) or ip (Linux)). -4. All FRR configuration files you use. If you don't want to publish your - network numbers change 2 middle bytes in IPv4 address to be XXX (e.g. - 192.XXX.XXX.32/24). Similar could be done with IPv6. -5. If any FRR daemon core dumped, please, supply stack trace using the - following commands: host> gdb exec_file core_file , (gdb) bt . -6. Run all FRR daemons with full debugging on (see documentation on - debugging) and send _only_ part of logs which are relative to your problem. -7. If the problem is difficult to reproduce please send a shell script to - reproduce it. -8. Patches, workarounds, fixes are always welcome. - -Thank You. diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index b6e9ee3cb2..276a7054e3 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2021,36 +2021,32 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */ return 0; } -/* Prefix SID attribute - * draft-ietf-idr-bgp-prefix-sid-05 +/* + * Read an individual SID value returning how much data we have read + * Returns 0 if there was an error that needs to be passed up the stack */ -static bgp_attr_parse_ret_t -bgp_attr_prefix_sid(struct bgp_attr_parser_args *args, - struct bgp_nlri *mp_update) +static bgp_attr_parse_ret_t bgp_attr_psid_sub(int32_t type, + int32_t length, + struct bgp_attr_parser_args *args, + struct bgp_nlri *mp_update) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; - int type; - int length; uint32_t label_index; struct in6_addr ipv6_sid; uint32_t srgb_base; uint32_t srgb_range; int srgb_count; - attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID); - - type = stream_getc(peer->curr); - length = stream_getw(peer->curr); - if (type == BGP_PREFIX_SID_LABEL_INDEX) { if (length != BGP_PREFIX_SID_LABEL_INDEX_LENGTH) { zlog_err( - "Prefix SID label index length is %d instead of %d", - length, BGP_PREFIX_SID_LABEL_INDEX_LENGTH); - return bgp_attr_malformed( - args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - args->total); + "Prefix SID label index length is %d instead of %d", + length, + BGP_PREFIX_SID_LABEL_INDEX_LENGTH); + return bgp_attr_malformed(args, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + args->total); } /* Ignore flags and reserved */ @@ -2060,9 +2056,8 @@ bgp_attr_prefix_sid(struct bgp_attr_parser_args *args, /* Fetch the label index and see if it is valid. */ label_index = stream_getl(peer->curr); if (label_index == BGP_INVALID_LABEL_INDEX) - return bgp_attr_malformed( - args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, - args->total); + return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + args->total); /* Store label index; subsequently, we'll check on * address-family */ @@ -2083,9 +2078,9 @@ bgp_attr_prefix_sid(struct bgp_attr_parser_args *args, if (length != BGP_PREFIX_SID_IPV6_LENGTH) { zlog_err("Prefix SID IPv6 length is %d instead of %d", length, BGP_PREFIX_SID_IPV6_LENGTH); - return bgp_attr_malformed( - args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - args->total); + return bgp_attr_malformed(args, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + args->total); } /* Ignore reserved */ @@ -2122,6 +2117,47 @@ bgp_attr_prefix_sid(struct bgp_attr_parser_args *args, return BGP_ATTR_PARSE_PROCEED; } +/* Prefix SID attribute + * draft-ietf-idr-bgp-prefix-sid-05 + */ +bgp_attr_parse_ret_t +bgp_attr_prefix_sid(int32_t tlength, struct bgp_attr_parser_args *args, + struct bgp_nlri *mp_update) +{ + struct peer *const peer = args->peer; + struct attr *const attr = args->attr; + bgp_attr_parse_ret_t ret; + + attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID); + + while (tlength) { + int32_t type, length; + + type = stream_getc(peer->curr); + length = stream_getw(peer->curr); + + ret = bgp_attr_psid_sub(type, length, args, mp_update); + + if (ret != BGP_ATTR_PARSE_PROCEED) + return ret; + /* + * Subtract length + the T and the L + * since length is the Vector portion + */ + tlength -= length + 3; + + if (tlength < 0) { + zlog_err("Prefix SID internal length %d causes us to read beyond the total Prefix SID length", + length); + return bgp_attr_malformed(args, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + args->total); + } + } + + return BGP_ATTR_PARSE_PROCEED; +} + /* PMSI tunnel attribute (RFC 6514) * Basic validation checks done here. */ @@ -2498,7 +2534,8 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr, startp); break; case BGP_ATTR_PREFIX_SID: - ret = bgp_attr_prefix_sid(&attr_args, mp_update); + ret = bgp_attr_prefix_sid(length, + &attr_args, mp_update); break; case BGP_ATTR_PMSI_TUNNEL: ret = bgp_attr_pmsi_tunnel(&attr_args); diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index d59eae5f14..f17c2a68e4 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -308,6 +308,9 @@ extern int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, struct bgp_nlri *); extern int bgp_mp_unreach_parse(struct bgp_attr_parser_args *args, struct bgp_nlri *); +extern bgp_attr_parse_ret_t +bgp_attr_prefix_sid(int32_t tlength, struct bgp_attr_parser_args *args, + struct bgp_nlri *mp_update); extern struct bgp_attr_encap_subtlv * encap_tlv_dup(struct bgp_attr_encap_subtlv *orig); diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index d2a61b93fe..14ff01ada5 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -227,16 +227,18 @@ extern int bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag, dst->family = AF_EVPN; p_evpn_p->route_type = evpn_type; if (evpn_type == BGP_EVPN_IP_PREFIX_ROUTE) { - p_evpn_p->eth_tag = eth_tag; - p_evpn_p->ip_prefix_length = p2.prefixlen; + p_evpn_p->prefix_addr.eth_tag = eth_tag; + p_evpn_p->prefix_addr.ip_prefix_length = p2.prefixlen; if (src->family == AF_INET) { - SET_IPADDR_V4(&p_evpn_p->ip); - memcpy(&p_evpn_p->ip.ipaddr_v4, &src->u.prefix4, + SET_IPADDR_V4(&p_evpn_p->prefix_addr.ip); + memcpy(&p_evpn_p->prefix_addr.ip.ipaddr_v4, + &src->u.prefix4, sizeof(struct in_addr)); dst->prefixlen = (uint8_t)PREFIX_LEN_ROUTE_TYPE_5_IPV4; } else { - SET_IPADDR_V6(&p_evpn_p->ip); - memcpy(&p_evpn_p->ip.ipaddr_v6, &src->u.prefix6, + SET_IPADDR_V6(&p_evpn_p->prefix_addr.ip); + memcpy(&p_evpn_p->prefix_addr.ip.ipaddr_v6, + &src->u.prefix6, sizeof(struct in6_addr)); dst->prefixlen = (uint8_t)PREFIX_LEN_ROUTE_TYPE_5_IPV6; } diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 49808e7cdd..a8676ab37c 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -510,15 +510,15 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, s, add ? ZEBRA_REMOTE_MACIP_ADD : ZEBRA_REMOTE_MACIP_DEL, bgp->vrf_id); stream_putl(s, vpn->vni); - stream_put(s, &p->prefix.mac.octet, ETH_ALEN); /* Mac Addr */ + stream_put(s, &p->prefix.macip_addr.mac.octet, ETH_ALEN); /* Mac Addr */ /* IP address length and IP address, if any. */ - if (IS_EVPN_PREFIX_IPADDR_NONE(p)) + if (is_evpn_prefix_ipaddr_none(p)) stream_putl(s, 0); else { - ipa_len = IS_EVPN_PREFIX_IPADDR_V4(p) ? IPV4_MAX_BYTELEN + ipa_len = is_evpn_prefix_ipaddr_v4(p) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN; stream_putl(s, ipa_len); - stream_put(s, &p->prefix.ip.ip.addr, ipa_len); + stream_put(s, &p->prefix.macip_addr.ip.ip.addr, ipa_len); } stream_put_in_addr(s, &remote_vtep_ip); @@ -532,8 +532,10 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, zlog_debug( "Tx %s MACIP, VNI %u MAC %s IP %s (flags: 0x%x) remote VTEP %s", add ? "ADD" : "DEL", vpn->vni, - prefix_mac2str(&p->prefix.mac, buf1, sizeof(buf1)), - ipaddr2str(&p->prefix.ip, buf3, sizeof(buf3)), flags, + prefix_mac2str(&p->prefix.macip_addr.mac, + buf1, sizeof(buf1)), + ipaddr2str(&p->prefix.macip_addr.ip, + buf3, sizeof(buf3)), flags, inet_ntop(AF_INET, &remote_vtep_ip, buf2, sizeof(buf2))); @@ -563,9 +565,9 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, s, add ? ZEBRA_REMOTE_VTEP_ADD : ZEBRA_REMOTE_VTEP_DEL, bgp->vrf_id); stream_putl(s, vpn->vni); - if (IS_EVPN_PREFIX_IPADDR_V4(p)) - stream_put_in_addr(s, &p->prefix.ip.ipaddr_v4); - else if (IS_EVPN_PREFIX_IPADDR_V6(p)) { + if (is_evpn_prefix_ipaddr_v4(p)) + stream_put_in_addr(s, &p->prefix.imet_addr.ip.ipaddr_v4); + else if (is_evpn_prefix_ipaddr_v6(p)) { zlog_err( "Bad remote IP when trying to %s remote VTEP for VNI %u", add ? "ADD" : "DEL", vpn->vni); @@ -577,7 +579,7 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, if (bgp_debug_zebra(NULL)) zlog_debug("Tx %s Remote VTEP, VNI %u remote VTEP %s", add ? "ADD" : "DEL", vpn->vni, - inet_ntoa(p->prefix.ip.ipaddr_v4)); + inet_ntoa(p->prefix.imet_addr.ip.ipaddr_v4)); return zclient_send_message(zclient); } @@ -1293,8 +1295,8 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, * these routes. */ if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && - (IS_EVPN_PREFIX_IPADDR_V4(p) || - !IN6_IS_ADDR_LINKLOCAL(&p->prefix.ip.ipaddr_v6)) && + (is_evpn_prefix_ipaddr_v4(p) || + !IN6_IS_ADDR_LINKLOCAL(&p->prefix.macip_addr.ip.ipaddr_v6)) && CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) add_l3_ecomm = 1; @@ -1539,8 +1541,8 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) continue; - if (IS_EVPN_PREFIX_IPADDR_V6(evp) && - IN6_IS_ADDR_LINKLOCAL(&evp->prefix.ip.ipaddr_v6)) + if (is_evpn_prefix_ipaddr_v6(evp) && + IN6_IS_ADDR_LINKLOCAL(&evp->prefix.macip_addr.ip.ipaddr_v6)) update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr_ip6_ll, 0, 1, &ri, 0); else { @@ -1792,10 +1794,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, char buf1[PREFIX_STRLEN]; memset(pp, 0, sizeof(struct prefix)); - if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) - ip_prefix_from_type2_prefix(evp, pp); - else if (evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) - ip_prefix_from_type5_prefix(evp, pp); + ip_prefix_from_evpn_prefix(evp, pp); if (bgp_debug_zebra(NULL)) { zlog_debug( @@ -1807,11 +1806,11 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, /* Create (or fetch) route within the VRF. */ /* NOTE: There is no RD here. */ - if (IS_EVPN_PREFIX_IPADDR_V4(evp)) { + if (is_evpn_prefix_ipaddr_v4(evp)) { afi = AFI_IP; safi = SAFI_UNICAST; rn = bgp_node_get(bgp_vrf->rib[afi][safi], pp); - } else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) { + } else if (is_evpn_prefix_ipaddr_v6(evp)) { afi = AFI_IP6; safi = SAFI_UNICAST; rn = bgp_node_get(bgp_vrf->rib[afi][safi], pp); @@ -1970,10 +1969,7 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, char buf1[PREFIX_STRLEN]; memset(pp, 0, sizeof(struct prefix)); - if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) - ip_prefix_from_type2_prefix(evp, pp); - else if (evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) - ip_prefix_from_type5_prefix(evp, pp); + ip_prefix_from_evpn_prefix(evp, pp); if (bgp_debug_zebra(NULL)) { zlog_debug( @@ -1985,7 +1981,7 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, /* Locate route within the VRF. */ /* NOTE: There is no RD here. */ - if (IS_EVPN_PREFIX_IPADDR_V4(evp)) { + if (is_evpn_prefix_ipaddr_v4(evp)) { afi = AFI_IP; safi = SAFI_UNICAST; rn = bgp_node_lookup(bgp_vrf->rib[afi][safi], pp); @@ -2232,8 +2228,8 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install) continue; /* if not a mac+ip route skip this route */ - if (!(IS_EVPN_PREFIX_IPADDR_V4(evp) - || IS_EVPN_PREFIX_IPADDR_V6(evp))) + if (!(is_evpn_prefix_ipaddr_v4(evp) + || is_evpn_prefix_ipaddr_v6(evp))) continue; for (ri = rn->info; ri; ri = ri->next) { @@ -2423,8 +2419,8 @@ static int install_uninstall_route_in_vrfs(struct bgp *bgp_def, afi_t afi, /* if it is type-2 route and not a mac+ip route skip this route */ if ((evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) - && !(IS_EVPN_PREFIX_IPADDR_V4(evp) - || IS_EVPN_PREFIX_IPADDR_V6(evp))) + && !(is_evpn_prefix_ipaddr_v4(evp) + || is_evpn_prefix_ipaddr_v6(evp))) return 0; for (ALL_LIST_ELEMENTS(vrfs, node, nnode, bgp_vrf)) { @@ -2850,7 +2846,7 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, /* Copy Ethernet Tag */ memcpy(ð_tag, pfx, 4); - p.prefix.eth_tag = ntohl(eth_tag); + p.prefix.macip_addr.eth_tag = ntohl(eth_tag); pfx += 4; /* Get the MAC Addr len */ @@ -2858,7 +2854,7 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, /* Get the MAC Addr */ if (macaddr_len == (ETH_ALEN * 8)) { - memcpy(&p.prefix.mac.octet, pfx, ETH_ALEN); + memcpy(&p.prefix.macip_addr.mac.octet, pfx, ETH_ALEN); pfx += ETH_ALEN; } else { zlog_err( @@ -2880,10 +2876,10 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, if (ipaddr_len) { ipaddr_len /= 8; /* Convert to bytes. */ - p.prefix.ip.ipa_type = (ipaddr_len == IPV4_MAX_BYTELEN) + p.prefix.macip_addr.ip.ipa_type = (ipaddr_len == IPV4_MAX_BYTELEN) ? IPADDR_V4 : IPADDR_V6; - memcpy(&p.prefix.ip.ip.addr, pfx, ipaddr_len); + memcpy(&p.prefix.macip_addr.ip.ip.addr, pfx, ipaddr_len); } pfx += ipaddr_len; @@ -2965,14 +2961,14 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi, /* Copy Ethernet Tag */ memcpy(ð_tag, pfx, 4); - p.prefix.eth_tag = ntohl(eth_tag); + p.prefix.imet_addr.eth_tag = ntohl(eth_tag); pfx += 4; /* Get the IP. */ ipaddr_len = *pfx++; if (ipaddr_len == IPV4_MAX_BITLEN) { - p.prefix.ip.ipa_type = IPADDR_V4; - memcpy(&p.prefix.ip.ip.addr, pfx, IPV4_MAX_BYTELEN); + p.prefix.imet_addr.ip.ipa_type = IPADDR_V4; + memcpy(&p.prefix.imet_addr.ip.ip.addr, pfx, IPV4_MAX_BYTELEN); } else { zlog_err( "%u:%s - Rx EVPN Type-3 NLRI with unsupported IP address length %d", @@ -3039,7 +3035,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, /* Fetch Ethernet Tag. */ memcpy(ð_tag, pfx, 4); - p.prefix.eth_tag = ntohl(eth_tag); + p.prefix.prefix_addr.eth_tag = ntohl(eth_tag); pfx += 4; /* Fetch IP prefix length. */ @@ -3050,21 +3046,21 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, peer->bgp->vrf_id, peer->host, ippfx_len); return -1; } - p.prefix.ip_prefix_length = ippfx_len; + p.prefix.prefix_addr.ip_prefix_length = ippfx_len; /* Determine IPv4 or IPv6 prefix */ /* Since the address and GW are from the same family, this just becomes * a simple check on the total size. */ if (psize == 34) { - SET_IPADDR_V4(&p.prefix.ip); - memcpy(&p.prefix.ip.ipaddr_v4, pfx, 4); + SET_IPADDR_V4(&p.prefix.prefix_addr.ip); + memcpy(&p.prefix.prefix_addr.ip.ipaddr_v4, pfx, 4); pfx += 4; memcpy(&evpn.gw_ip.ipv4, pfx, 4); pfx += 4; } else { - SET_IPADDR_V6(&p.prefix.ip); - memcpy(&p.prefix.ip.ipaddr_v6, pfx, 16); + SET_IPADDR_V6(&p.prefix.prefix_addr.ip); + memcpy(&p.prefix.prefix_addr.ip.ipaddr_v6, pfx, 16); pfx += 16; memcpy(&evpn.gw_ip.ipv6, pfx, 16); pfx += 16; @@ -3109,7 +3105,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p, /* len denites the total len of IP and GW-IP in the route IP and GW-IP have to be both ipv4 or ipv6 */ - if (IS_IPADDR_V4(&p_evpn_p->ip)) + if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip)) len = 8; /* IP and GWIP are both ipv4 */ else len = 32; /* IP and GWIP are both ipv6 */ @@ -3120,20 +3116,20 @@ static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p, stream_put(s, &(attr->evpn_overlay.eth_s_id), 10); else stream_put(s, &temp, 10); - stream_putl(s, p_evpn_p->eth_tag); - stream_putc(s, p_evpn_p->ip_prefix_length); - if (IS_IPADDR_V4(&p_evpn_p->ip)) - stream_put_ipv4(s, p_evpn_p->ip.ipaddr_v4.s_addr); + stream_putl(s, p_evpn_p->prefix_addr.eth_tag); + stream_putc(s, p_evpn_p->prefix_addr.ip_prefix_length); + if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip)) + stream_put_ipv4(s, p_evpn_p->prefix_addr.ip.ipaddr_v4.s_addr); else - stream_put(s, &p_evpn_p->ip.ipaddr_v6, 16); + stream_put(s, &p_evpn_p->prefix_addr.ip.ipaddr_v6, 16); if (attr) { - if (IS_IPADDR_V4(&p_evpn_p->ip)) + if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip)) stream_put_ipv4(s, attr->evpn_overlay.gw_ip.ipv4.s_addr); else stream_put(s, &(attr->evpn_overlay.gw_ip.ipv6), 16); } else { - if (IS_IPADDR_V4(&p_evpn_p->ip)) + if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip)) stream_put_ipv4(s, 0); else stream_put(s, &temp, 16); @@ -3583,44 +3579,49 @@ 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", p->prefix.eth_tag); + json_object_int_add(json, "ethTag", + p->prefix.imet_addr.eth_tag); json_object_int_add(json, "ipLen", - IS_EVPN_PREFIX_IPADDR_V4(p) + is_evpn_prefix_ipaddr_v4(p) ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN); json_object_string_add(json, "ip", - inet_ntoa(p->prefix.ip.ipaddr_v4)); + inet_ntoa(p->prefix.imet_addr.ip.ipaddr_v4)); } else if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { - if (IS_EVPN_PREFIX_IPADDR_NONE(p)) { + if (is_evpn_prefix_ipaddr_none(p)) { json_object_int_add(json, "routeType", p->prefix.route_type); - json_object_int_add(json, "ethTag", p->prefix.eth_tag); + json_object_int_add(json, "ethTag", + p->prefix.macip_addr.eth_tag); json_object_int_add(json, "macLen", 8 * ETH_ALEN); json_object_string_add(json, "mac", - prefix_mac2str(&p->prefix.mac, + prefix_mac2str(&p->prefix.macip_addr.mac, buf1, sizeof(buf1))); } else { uint8_t family; - family = IS_EVPN_PREFIX_IPADDR_V4(p) ? AF_INET + family = is_evpn_prefix_ipaddr_v4(p) ? AF_INET : AF_INET6; json_object_int_add(json, "routeType", p->prefix.route_type); - json_object_int_add(json, "ethTag", p->prefix.eth_tag); + json_object_int_add(json, "ethTag", + p->prefix.macip_addr.eth_tag); json_object_int_add(json, "macLen", 8 * ETH_ALEN); json_object_string_add(json, "mac", - prefix_mac2str(&p->prefix.mac, + prefix_mac2str(&p->prefix.macip_addr.mac, buf1, sizeof(buf1))); json_object_int_add(json, "ipLen", - IS_EVPN_PREFIX_IPADDR_V4(p) + is_evpn_prefix_ipaddr_v4(p) ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN); json_object_string_add( json, "ip", - inet_ntop(family, &p->prefix.ip.ip.addr, buf2, + inet_ntop(family, + &p->prefix.macip_addr.ip.ip.addr, + buf2, PREFIX2STR_BUFFER)); } } else { @@ -3639,42 +3640,44 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len) if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) { snprintf(buf, len, "[%d]:[%d]:[%d]:[%s]", p->prefix.route_type, - p->prefix.eth_tag, - IS_EVPN_PREFIX_IPADDR_V4(p) ? IPV4_MAX_BITLEN + p->prefix.imet_addr.eth_tag, + is_evpn_prefix_ipaddr_v4(p) ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN, - inet_ntoa(p->prefix.ip.ipaddr_v4)); + inet_ntoa(p->prefix.imet_addr.ip.ipaddr_v4)); } else if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { - if (IS_EVPN_PREFIX_IPADDR_NONE(p)) + if (is_evpn_prefix_ipaddr_none(p)) snprintf(buf, len, "[%d]:[%d]:[%d]:[%s]", p->prefix.route_type, - p->prefix.eth_tag, + p->prefix.macip_addr.eth_tag, 8 * ETH_ALEN, - prefix_mac2str(&p->prefix.mac, buf1, + prefix_mac2str(&p->prefix.macip_addr.mac, buf1, sizeof(buf1))); else { uint8_t family; - family = IS_EVPN_PREFIX_IPADDR_V4(p) ? AF_INET + family = is_evpn_prefix_ipaddr_v4(p) ? AF_INET : AF_INET6; snprintf(buf, len, "[%d]:[%d]:[%d]:[%s]:[%d]:[%s]", p->prefix.route_type, - p->prefix.eth_tag, + p->prefix.macip_addr.eth_tag, 8 * ETH_ALEN, - prefix_mac2str(&p->prefix.mac, buf1, + prefix_mac2str(&p->prefix.macip_addr.mac, buf1, sizeof(buf1)), family == AF_INET ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN, - inet_ntop(family, &p->prefix.ip.ip.addr, buf2, + inet_ntop(family, + &p->prefix.macip_addr.ip.ip.addr, + buf2, PREFIX2STR_BUFFER)); } } else if (p->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) { 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)); + p->prefix.prefix_addr.eth_tag, + p->prefix.prefix_addr.ip_prefix_length, + is_evpn_prefix_ipaddr_v4(p) + ? inet_ntoa(p->prefix.prefix_addr.ip.ipaddr_v4) + : inet6_ntoa(p->prefix.prefix_addr.ip.ipaddr_v6)); } else { /* For EVPN route types not supported yet. */ snprintf(buf, len, "(unsupported route type %d)", @@ -3703,9 +3706,9 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p, switch (evp->prefix.route_type) { case BGP_EVPN_MAC_IP_ROUTE: - if (IS_EVPN_PREFIX_IPADDR_V4(evp)) + if (is_evpn_prefix_ipaddr_v4(evp)) ipa_len = IPV4_MAX_BYTELEN; - else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) + else if (is_evpn_prefix_ipaddr_v6(evp)) ipa_len = IPV6_MAX_BYTELEN; /* RD, ESI, EthTag, MAC+len, IP len, [IP], 1 VNI */ len = 8 + 10 + 4 + 1 + 6 + 1 + ipa_len + 3; @@ -3717,12 +3720,13 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p, 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_putl(s, evp->prefix.macip_addr.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 */ - if (ipa_len) /* IP */ - stream_put(s, &evp->prefix.ip.ip.addr, ipa_len); + stream_put(s, evp->prefix.macip_addr.mac.octet, 6); /* Mac Addr */ + stream_putc(s, 8 * ipa_len); /* IP address Length */ + if (ipa_len) /* IP */ + stream_put(s, &evp->prefix.macip_addr.ip.ip.addr, + ipa_len); /* 1st label is the L2 VNI */ stream_put(s, label, BGP_LABEL_BYTES); /* Include 2nd label (L3 VNI) if advertising MAC+IP */ @@ -3733,10 +3737,10 @@ 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, evp->prefix.eth_tag); /* Ethernet Tag ID */ + stream_putl(s, evp->prefix.imet_addr.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); + stream_put_in_addr(s, &evp->prefix.imet_addr.ip.ipaddr_v4); break; case BGP_EVPN_IP_PREFIX_ROUTE: @@ -4421,8 +4425,10 @@ int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni) /* Locate VNI hash */ vpn = bgp_evpn_lookup_vni(bgp, vni); if (!vpn) { - zlog_warn("%u: VNI hash entry for VNI %u not found at DEL", - bgp->vrf_id, vni); + if (bgp_debug_zebra(NULL)) + zlog_warn( + "%u: VNI hash entry for VNI %u not found at DEL", + bgp->vrf_id, vni); return 0; } diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 1eecb9ecf7..1efde3a719 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -272,15 +272,15 @@ static inline void ip_prefix_from_type5_prefix(struct prefix_evpn *evp, struct prefix *ip) { memset(ip, 0, sizeof(struct prefix)); - if (IS_EVPN_PREFIX_IPADDR_V4(evp)) { + if (is_evpn_prefix_ipaddr_v4(evp)) { ip->family = AF_INET; - ip->prefixlen = evp->prefix.ip_prefix_length; - memcpy(&(ip->u.prefix4), &(evp->prefix.ip.ip), + ip->prefixlen = evp->prefix.prefix_addr.ip_prefix_length; + memcpy(&(ip->u.prefix4), &(evp->prefix.prefix_addr.ip.ip), IPV4_MAX_BYTELEN); - } else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) { + } else if (is_evpn_prefix_ipaddr_v6(evp)) { ip->family = AF_INET6; - ip->prefixlen = evp->prefix.ip_prefix_length; - memcpy(&(ip->u.prefix6), &(evp->prefix.ip.ip), + ip->prefixlen = evp->prefix.prefix_addr.ip_prefix_length; + memcpy(&(ip->u.prefix6), &(evp->prefix.prefix_addr.ip.ip), IPV6_MAX_BYTELEN); } } @@ -290,26 +290,36 @@ static inline int is_evpn_prefix_default(struct prefix *evp) if (evp->family != AF_EVPN) return 0; - return ((evp->u.prefix_evpn.ip_prefix_length == 0) ? 1 : 0); + return ((evp->u.prefix_evpn.prefix_addr.ip_prefix_length == 0) ? + 1 : 0); } static inline void ip_prefix_from_type2_prefix(struct prefix_evpn *evp, struct prefix *ip) { memset(ip, 0, sizeof(struct prefix)); - if (IS_EVPN_PREFIX_IPADDR_V4(evp)) { + if (is_evpn_prefix_ipaddr_v4(evp)) { ip->family = AF_INET; ip->prefixlen = IPV4_MAX_BITLEN; - memcpy(&(ip->u.prefix4), &(evp->prefix.ip.ip), + memcpy(&(ip->u.prefix4), &(evp->prefix.macip_addr.ip.ip), IPV4_MAX_BYTELEN); - } else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) { + } else if (is_evpn_prefix_ipaddr_v6(evp)) { ip->family = AF_INET6; ip->prefixlen = IPV6_MAX_BITLEN; - memcpy(&(ip->u.prefix6), &(evp->prefix.ip.ip), + memcpy(&(ip->u.prefix6), &(evp->prefix.macip_addr.ip.ip), IPV6_MAX_BYTELEN); } } +static inline void ip_prefix_from_evpn_prefix(struct prefix_evpn *evp, + struct prefix *ip) +{ + if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) + ip_prefix_from_type2_prefix(evp, ip); + else if (evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) + ip_prefix_from_type5_prefix(evp, ip); +} + static inline void build_evpn_type2_prefix(struct prefix_evpn *p, struct ethaddr *mac, struct ipaddr *ip) @@ -318,10 +328,10 @@ static inline void build_evpn_type2_prefix(struct prefix_evpn *p, p->family = AF_EVPN; p->prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN; p->prefix.route_type = BGP_EVPN_MAC_IP_ROUTE; - memcpy(&p->prefix.mac.octet, mac->octet, ETH_ALEN); - p->prefix.ip.ipa_type = IPADDR_NONE; + memcpy(&p->prefix.macip_addr.mac.octet, mac->octet, ETH_ALEN); + p->prefix.macip_addr.ip.ipa_type = IPADDR_NONE; if (ip) - memcpy(&p->prefix.ip, ip, sizeof(*ip)); + memcpy(&p->prefix.macip_addr.ip, ip, sizeof(*ip)); } static inline void build_type5_prefix_from_ip_prefix(struct prefix_evpn *evp, @@ -343,10 +353,10 @@ static inline void build_type5_prefix_from_ip_prefix(struct prefix_evpn *evp, memset(evp, 0, sizeof(struct prefix_evpn)); evp->family = AF_EVPN; evp->prefixlen = EVPN_TYPE_5_ROUTE_PREFIXLEN; - evp->prefix.ip_prefix_length = ip_prefix->prefixlen; evp->prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE; - evp->prefix.ip.ipa_type = ip.ipa_type; - memcpy(&evp->prefix.ip, &ip, sizeof(struct ipaddr)); + evp->prefix.prefix_addr.ip_prefix_length = ip_prefix->prefixlen; + evp->prefix.prefix_addr.ip.ipa_type = ip.ipa_type; + memcpy(&evp->prefix.prefix_addr.ip, &ip, sizeof(struct ipaddr)); } static inline void build_evpn_type3_prefix(struct prefix_evpn *p, @@ -356,8 +366,8 @@ static inline void build_evpn_type3_prefix(struct prefix_evpn *p, p->family = AF_EVPN; p->prefixlen = EVPN_TYPE_3_ROUTE_PREFIXLEN; p->prefix.route_type = BGP_EVPN_IMET_ROUTE; - p->prefix.ip.ipa_type = IPADDR_V4; - p->prefix.ip.ipaddr_v4 = originator_ip; + p->prefix.imet_addr.ip.ipa_type = IPADDR_V4; + p->prefix.imet_addr.ip.ipaddr_v4 = originator_ip; } static inline int evpn_default_originate_set(struct bgp *bgp, afi_t afi, diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index c74a1bfb7c..fd3c229472 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -311,7 +311,7 @@ static void bgp_evpn_show_route_rd_header(struct vty *vty, } static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp, - json_object *json) + uint64_t tbl_ver, json_object *json) { char ri_header[] = " Network Next Hop Metric LocPrf Weight Path\n"; @@ -319,9 +319,8 @@ static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp, if (json) return; - - vty_out(vty, "BGP table version is 0, local router ID is %s\n", - inet_ntoa(bgp->router_id)); + vty_out(vty, "BGP table version is %" PRIu64 ", local router ID is %s\n", + tbl_ver, inet_ntoa(bgp->router_id)); vty_out(vty, "Status codes: s suppressed, d damped, h history, " "* valid, > best, i - internal\n"); @@ -494,12 +493,16 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, { struct bgp_node *rn; struct bgp_info *ri; + struct bgp_table *table; int header = 1; + uint64_t tbl_ver; uint32_t prefix_cnt, path_cnt; prefix_cnt = path_cnt = 0; - for (rn = bgp_table_top(vpn->route_table); rn; + table = vpn->route_table; + tbl_ver = table->version; + for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; int add_prefix_to_json = 0; @@ -519,7 +522,8 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, if (rn->info) { /* Overall header/legend displayed once. */ if (header) { - bgp_evpn_show_route_header(vty, bgp, json); + bgp_evpn_show_route_header(vty, bgp, + tbl_ver, json); header = 0; } @@ -603,9 +607,9 @@ static void show_vni_routes_hash(struct hash_backet *backet, void *arg) static void show_l3vni_entry(struct vty *vty, struct bgp *bgp, json_object *json) { - json_object *json_vni; - json_object *json_import_rtl; - json_object *json_export_rtl; + json_object *json_vni = NULL; + json_object *json_import_rtl = NULL; + json_object *json_export_rtl = NULL; char buf1[10]; char buf2[INET6_ADDRSTRLEN]; char rt_buf[25]; @@ -862,6 +866,8 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, for (rn = bgp_table_top(bgp->rib[afi][SAFI_EVPN]); rn; rn = bgp_route_next(rn)) { + uint64_t tbl_ver; + if (use_json) continue; /* XXX json TODO */ @@ -872,6 +878,7 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, continue; rd_header = 1; + tbl_ver = table->version; for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) for (ri = rm->info; ri; ri = ri->next) { @@ -891,7 +898,7 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, json_object_int_add( json, "bgpTableVersion", - 0); + tbl_ver); json_object_string_add( json, "bgpLocalRouterId", @@ -917,7 +924,8 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, V4_HEADER_OVERLAY); else { vty_out(vty, - "BGP table version is 0, local router ID is %s\n", + "BGP table version is %" PRIu64 ", local router ID is %s\n", + tbl_ver, inet_ntoa( bgp->router_id)); vty_out(vty, @@ -2201,11 +2209,13 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, char rd_str[RD_ADDRSTRLEN]; json_object *json_rd = NULL; /* contains routes for an RD */ int add_rd_to_json = 0; + uint64_t tbl_ver; table = (struct bgp_table *)rd_rn->info; if (table == NULL) continue; + tbl_ver = table->version; prefix_rd2str((struct prefix_rd *)&rd_rn->p, rd_str, sizeof(rd_str)); @@ -2236,6 +2246,7 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, /* Overall header/legend displayed once. */ if (header) { bgp_evpn_show_route_header(vty, bgp, + tbl_ver, json); header = 0; } @@ -2873,7 +2884,7 @@ DEFUN (no_bgp_evpn_advertise_type5, if (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST)) { bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi); - UNSET_FLAG(bgp_vrf->vrf_flags, + UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST); } } @@ -4382,12 +4393,22 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi, vty_out(vty, " advertise-default-gw\n"); if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN], - BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST)) - vty_out(vty, " advertise ipv4 unicast\n"); + BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST)) { + if (bgp->adv_cmd_rmap[AFI_IP][SAFI_UNICAST].name) + vty_out(vty, " advertise ipv4 unicast route-map %s\n", + bgp->adv_cmd_rmap[AFI_IP][SAFI_UNICAST].name); + else + vty_out(vty, " advertise ipv4 unicast\n"); + } if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN], - BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST)) - vty_out(vty, " advertise ipv6 unicast\n"); + BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST)) { + if (bgp->adv_cmd_rmap[AFI_IP6][SAFI_UNICAST].name) + vty_out(vty, " advertise ipv6 unicast route-map %s\n", + bgp->adv_cmd_rmap[AFI_IP6][SAFI_UNICAST].name); + else + vty_out(vty, " advertise ipv6 unicast\n"); + } if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN], BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4)) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 4802a4caa5..fd5648ac39 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1336,6 +1336,8 @@ static void subgroup_announce_reset_nhop(uint8_t family, struct attr *attr) } if (family == AF_INET6) memset(&attr->mp_nexthop_global, 0, IPV6_MAX_BYTELEN); + if (family == AF_EVPN) + memset(&attr->mp_nexthop_global_in, 0, BGP_ATTR_NHLEN_IPV4); } int subgroup_announce_check(struct bgp_node *rn, struct bgp_info *ri, @@ -2336,10 +2338,18 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, if (new_select && new_select->type == ZEBRA_ROUTE_BGP && (new_select->sub_type == BGP_ROUTE_NORMAL || new_select->sub_type == BGP_ROUTE_AGGREGATE - || new_select->sub_type == BGP_ROUTE_IMPORTED)) + || new_select->sub_type == BGP_ROUTE_IMPORTED)) { + + /* if this is an evpn imported type-5 prefix, + * we need to withdraw the route first to clear + * the nh neigh and the RMAC entry. + */ + if (old_select && + is_route_parent_evpn(old_select)) + bgp_zebra_withdraw(p, old_select, bgp, safi); bgp_zebra_announce(rn, p, new_select, bgp, afi, safi); - else { + } else { /* Withdraw the route from the kernel. */ if (old_select && old_select->type == ZEBRA_ROUTE_BGP && (old_select->sub_type == BGP_ROUTE_NORMAL @@ -2353,12 +2363,28 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, /* advertise/withdraw type-5 routes */ if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { if (advertise_type5_routes(bgp, afi) && new_select && - (!new_select->extra || !new_select->extra->parent)) - bgp_evpn_advertise_type5_route(bgp, &rn->p, - new_select->attr, - afi, safi); - else if (advertise_type5_routes(bgp, afi) && old_select && - (!old_select->extra || !old_select->extra->parent)) + (!new_select->extra || !new_select->extra->parent)) { + + /* apply the route-map */ + if (bgp->adv_cmd_rmap[afi][safi].map) { + int ret = 0; + + ret = route_map_apply( + bgp->adv_cmd_rmap[afi][safi].map, + &rn->p, RMAP_BGP, new_select); + if (ret == RMAP_MATCH) + bgp_evpn_advertise_type5_route( + bgp, &rn->p, new_select->attr, + afi, safi); + } else { + bgp_evpn_advertise_type5_route(bgp, + &rn->p, + new_select->attr, + afi, safi); + + } + } else if (advertise_type5_routes(bgp, afi) && old_select && + (!old_select->extra || !old_select->extra->parent)) bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi); } @@ -4626,7 +4652,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p, if (bgp_static->encap_tunneltype == BGP_ENCAP_TYPE_VXLAN) { struct bgp_encap_type_vxlan bet; memset(&bet, 0, sizeof(struct bgp_encap_type_vxlan)); - bet.vnid = p->u.prefix_evpn.eth_tag; + bet.vnid = p->u.prefix_evpn.prefix_addr.eth_tag; bgp_encap_type_vxlan_to_tlv(&bet, &attr); } if (bgp_static->router_mac) { @@ -5101,10 +5127,10 @@ int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty, return CMD_WARNING_CONFIG_FAILED; } if ((gw_ip.family == AF_INET - && IS_EVPN_PREFIX_IPADDR_V6( + && is_evpn_prefix_ipaddr_v6( (struct prefix_evpn *)&p)) || (gw_ip.family == AF_INET6 - && IS_EVPN_PREFIX_IPADDR_V4( + && is_evpn_prefix_ipaddr_v4( (struct prefix_evpn *)&p))) { vty_out(vty, "%% GatewayIp family differs with IP prefix\n"); @@ -7129,10 +7155,10 @@ void route_vty_out_overlay(struct vty *vty, struct prefix *p, vty_out(vty, "%s", str); XFREE(MTYPE_TMP, str); - if (IS_EVPN_PREFIX_IPADDR_V4((struct prefix_evpn *)p)) { + if (is_evpn_prefix_ipaddr_v4((struct prefix_evpn *)p)) { vty_out(vty, "/%s", inet_ntoa(attr->evpn_overlay.gw_ip.ipv4)); - } else if (IS_EVPN_PREFIX_IPADDR_V6((struct prefix_evpn *)p)) { + } else if (is_evpn_prefix_ipaddr_v6((struct prefix_evpn *)p)) { vty_out(vty, "/%s", inet_ntop(AF_INET6, &(attr->evpn_overlay.gw_ip.ipv6), buf, @@ -11398,14 +11424,15 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp, prefix_rd2str(prd, rdbuf, sizeof(rdbuf)); if (p->u.prefix_evpn.route_type == 5) { char local_buf[PREFIX_STRLEN]; - uint8_t family = IS_EVPN_PREFIX_IPADDR_V4(( + uint8_t family = is_evpn_prefix_ipaddr_v4(( struct prefix_evpn *)p) ? AF_INET : AF_INET6; - inet_ntop(family, &p->u.prefix_evpn.ip.ip.addr, + inet_ntop(family, + &p->u.prefix_evpn.prefix_addr.ip.ip.addr, local_buf, PREFIX_STRLEN); sprintf(buf, "%s/%u", local_buf, - p->u.prefix_evpn.ip_prefix_length); + p->u.prefix_evpn.prefix_addr.ip_prefix_length); } else { prefix2str(p, buf, sizeof(buf)); } @@ -11417,7 +11444,8 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp, sizeof(buf2)); vty_out(vty, " network %s rd %s ethtag %u label %u esi %s gwip %s routermac %s\n", - buf, rdbuf, p->u.prefix_evpn.eth_tag, + buf, rdbuf, + p->u.prefix_evpn.prefix_addr.eth_tag, decode_label(&bgp_static->label), esi, buf2, macrouter); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 4cc889286e..63400f7d31 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -635,7 +635,7 @@ static route_map_result_t route_match_mac_address(void *rule, p.family = AF_ETHERNET; p.prefixlen = ETH_ALEN * 8; - p.u.prefix_eth = prefix->u.prefix_evpn.mac; + p.u.prefix_eth = prefix->u.prefix_evpn.macip_addr.mac; return (access_list_apply(alist, &p) == FILTER_DENY ? RMAP_NOMATCH diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 2c7e4e0435..241b23a62d 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -356,20 +356,19 @@ static struct peer *peer_lookup_addr_ipv4(struct in_addr *src) struct bgp *bgp; struct peer *peer; struct listnode *node; - struct in_addr addr; - int ret; bgp = bgp_get_default(); if (!bgp) return NULL; for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { - ret = inet_pton(AF_INET, peer->host, &addr); - if (ret > 0) { - if (IPV4_ADDR_SAME(&addr, src)) - return peer; - } + if (sockunion_family(&peer->su) != AF_INET) + continue; + + if (sockunion2ip(&peer->su) == src->s_addr) + return peer; } + return NULL; } @@ -377,28 +376,31 @@ static struct peer *bgp_peer_lookup_next(struct in_addr *src) { struct bgp *bgp; struct peer *peer; + struct peer *next_peer = NULL; struct listnode *node; - struct in_addr *p; - union sockunion su; - int ret; - - sockunion_init(&su); bgp = bgp_get_default(); if (!bgp) return NULL; for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { - ret = inet_pton(AF_INET, peer->host, &su.sin.sin_addr); - if (ret > 0) { - p = &su.sin.sin_addr; - - if (ntohl(p->s_addr) > ntohl(src->s_addr)) { - src->s_addr = p->s_addr; - return peer; - } + if (sockunion_family(&peer->su) != AF_INET) + continue; + if (ntohl(sockunion2ip(&peer->su)) <= ntohl(src->s_addr)) + continue; + + if (!next_peer + || ntohl(sockunion2ip(&next_peer->su)) + > ntohl(sockunion2ip(&peer->su))) { + next_peer = peer; } } + + if (next_peer) { + src->s_addr = sockunion2ip(&next_peer->su); + return next_peer; + } + return NULL; } diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 8ba7902a5f..cabd5b5cbd 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -467,13 +467,12 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, nh_modified = 1; } else if ( peer->sort == BGP_PEER_EBGP - && paf->safi != SAFI_EVPN && (bgp_multiaccess_check_v4(v4nh, peer) == 0) && !CHECK_FLAG( vec->flags, BPKT_ATTRVEC_FLAGS_RMAP_NH_UNCHANGED) && !peer_af_flag_check( - peer, nhafi, paf->safi, + peer, paf->afi, paf->safi, PEER_FLAG_NEXTHOP_UNCHANGED)) { /* NOTE: not handling case where NH has new AFI */ diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index e1b050bf59..b8c81232bb 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -12153,7 +12153,6 @@ static void bgp_ac_neighbor(vector comps, struct cmd_token *token) { struct bgp *bgp; struct peer *peer; - struct peer_group *group; struct listnode *lnbgp, *lnpeer; for (ALL_LIST_ELEMENTS_RO(bm->bgp, lnbgp, bgp)) { @@ -12177,11 +12176,6 @@ static void bgp_ac_neighbor(vector comps, struct cmd_token *token) vector_set(comps, XSTRDUP(MTYPE_COMPLETION, name)); } - - if (token->type == VARIABLE_TKN) - for (ALL_LIST_ELEMENTS_RO(bgp->group, lnpeer, group)) - vector_set(comps, XSTRDUP(MTYPE_COMPLETION, - group->name)); } } @@ -12191,9 +12185,27 @@ static const struct cmd_variable_handler bgp_var_neighbor[] = { {.varname = "peer", .completions = bgp_ac_neighbor}, {.completions = NULL}}; +static void bgp_ac_peergroup(vector comps, struct cmd_token *token) +{ + struct bgp *bgp; + struct peer_group *group; + struct listnode *lnbgp, *lnpeer; + + for (ALL_LIST_ELEMENTS_RO(bm->bgp, lnbgp, bgp)) { + for (ALL_LIST_ELEMENTS_RO(bgp->group, lnpeer, group)) + vector_set(comps, XSTRDUP(MTYPE_COMPLETION, + group->name)); + } +} + +static const struct cmd_variable_handler bgp_var_peergroup[] = { + {.tokenname = "PGNAME", .completions = bgp_ac_peergroup}, + {.completions = NULL} }; + void bgp_vty_init(void) { cmd_variable_handler_register(bgp_var_neighbor); + cmd_variable_handler_register(bgp_var_peergroup); /* Install bgp top node. */ install_node(&bgp_node, bgp_config_write); @@ -12575,6 +12587,8 @@ void bgp_vty_init(void) install_element(BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd); install_element(BGP_VPNV6_NODE, &neighbor_nexthop_self_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_nexthop_self_cmd); + install_element(BGP_EVPN_NODE, &neighbor_nexthop_self_cmd); + install_element(BGP_EVPN_NODE, &no_neighbor_nexthop_self_cmd); /* "neighbor next-hop-self force" commands. */ install_element(BGP_NODE, &neighbor_nexthop_self_force_hidden_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 93a509c219..52a246387e 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1207,7 +1207,6 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, /* Make Zebra API structure. */ memset(&api, 0, sizeof(api)); - memcpy(&api.rmac, &(info->attr->rmac), sizeof(struct ethaddr)); api.vrf_id = bgp->vrf_id; api.type = ZEBRA_ROUTE_BGP; api.safi = safi; @@ -1288,17 +1287,11 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, } } - if (bgp->table_map[afi][safi].name || nh_othervrf) { + if (bgp->table_map[afi][safi].name) { /* Copy info and attributes, so the route-map apply doesn't modify the BGP route info. */ local_attr = *mpinfo->attr; mpinfo_cp->attr = &local_attr; - if (nh_othervrf) { - /* allow route-map to modify */ - local_attr.nexthop = - info->extra->nexthop_orig.u - .prefix4; - } } if (bgp->table_map[afi][safi].name) { @@ -1323,19 +1316,11 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, ifindex_t ifindex; struct in6_addr *nexthop; - if (bgp->table_map[afi][safi].name || nh_othervrf) { + if (bgp->table_map[afi][safi].name) { /* Copy info and attributes, so the route-map apply doesn't modify the BGP route info. */ local_attr = *mpinfo->attr; mpinfo_cp->attr = &local_attr; - if (nh_othervrf) { - /* allow route-map to modify */ - local_attr.mp_nexthop_global = - info->extra->nexthop_orig.u - .prefix6; - local_attr.mp_nexthop_len = - BGP_ATTR_NHLEN_IPV6_GLOBAL; - } } if (bgp->table_map[afi][safi].name) { @@ -1376,6 +1361,8 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, api_nh->label_num = 1; api_nh->labels[0] = label; } + memcpy(&api_nh->rmac, &(mpinfo->attr->rmac), + sizeof(struct ethaddr)); valid_nh_count++; } @@ -1500,7 +1487,6 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, } memset(&api, 0, sizeof(api)); - memcpy(&api.rmac, &(info->attr->rmac), sizeof(struct ethaddr)); api.vrf_id = bgp->vrf_id; api.type = ZEBRA_ROUTE_BGP; api.safi = safi; @@ -1913,7 +1899,7 @@ int bgp_zebra_advertise_gw_macip(struct bgp *bgp, int advertise, vni_t vni) zclient_create_header(s, ZEBRA_ADVERTISE_DEFAULT_GW, bgp->vrf_id); stream_putc(s, advertise); - stream_put3(s, vni); + stream_putl(s, vni); stream_putw_at(s, 0, stream_get_endp(s)); return zclient_send_message(zclient); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 58d9fb24e0..71707b6afa 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1174,6 +1174,11 @@ struct peer *peer_new(struct bgp *bgp) } peer->orf_plist[afi][safi] = NULL; } + + /* set nexthop-unchanged for l2vpn evpn by default */ + SET_FLAG(peer->af_flags[AFI_L2VPN][SAFI_EVPN], + PEER_FLAG_NEXTHOP_UNCHANGED); + SET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN); /* Create buffers. */ @@ -4072,6 +4077,35 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, return 0; } + /* + * For EVPN we implicitly set the NEXTHOP_UNCHANGED flag, + * if we are setting/unsetting flags which conflict with this flag + * handle accordingly + */ + if (afi == AFI_L2VPN && safi == SAFI_EVPN) { + if (set) { + + /* + * if we are setting NEXTHOP_SELF, we need to unset the + * NEXTHOP_UNCHANGED flag + */ + if (CHECK_FLAG(flag, PEER_FLAG_NEXTHOP_SELF) || + CHECK_FLAG(flag, PEER_FLAG_FORCE_NEXTHOP_SELF)) + UNSET_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_NEXTHOP_UNCHANGED); + } else { + + /* + * if we are unsetting NEXTHOP_SELF, we need to set the + * NEXTHOP_UNCHANGED flag to reset the defaults for EVPN + */ + if (CHECK_FLAG(flag, PEER_FLAG_NEXTHOP_SELF) || + CHECK_FLAG(flag, PEER_FLAG_FORCE_NEXTHOP_SELF)) + SET_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_NEXTHOP_UNCHANGED); + } + } + if (set) SET_FLAG(peer->af_flags[afi][safi], flag); else @@ -5947,39 +5981,63 @@ int peer_maximum_prefix_set(struct peer *peer, afi_t afi, safi_t safi, struct peer_group *group; struct listnode *node, *nnode; + /* apply configuration and set flags */ SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); - peer->pmax[afi][safi] = max; - peer->pmax_threshold[afi][safi] = threshold; - peer->pmax_restart[afi][safi] = restart; if (warning) SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); else UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); + peer->pmax[afi][safi] = max; + peer->pmax_threshold[afi][safi] = threshold; + peer->pmax_restart[afi][safi] = restart; + /* if handling a peer-group, apply to all children */ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { group = peer->group; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { - SET_FLAG(peer->af_flags[afi][safi], - PEER_FLAG_MAX_PREFIX); - peer->pmax[afi][safi] = max; - peer->pmax_threshold[afi][safi] = threshold; - peer->pmax_restart[afi][safi] = restart; - if (warning) + /* + * If peer configuration is user-set, it overrides + * peer-group config. + */ + if (!CHECK_FLAG(peer->af_flags_override[afi][safi], + PEER_FLAG_MAX_PREFIX)) { SET_FLAG(peer->af_flags[afi][safi], - PEER_FLAG_MAX_PREFIX_WARNING); - else - UNSET_FLAG(peer->af_flags[afi][safi], - PEER_FLAG_MAX_PREFIX_WARNING); + PEER_FLAG_MAX_PREFIX); + peer->pmax[afi][safi] = max; + peer->pmax_threshold[afi][safi] = threshold; + peer->pmax_restart[afi][safi] = restart; + } + if (!CHECK_FLAG(peer->af_flags_override[afi][safi], + PEER_FLAG_MAX_PREFIX_WARNING)) { + if (warning) + SET_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_MAX_PREFIX_WARNING); + else + UNSET_FLAG( + peer->af_flags[afi][safi], + PEER_FLAG_MAX_PREFIX_WARNING); + } if ((peer->status == Established) && (peer->afc[afi][safi])) bgp_maximum_prefix_overflow(peer, afi, safi, 1); } } else { + /* if not handling a peer-group, set the override flags */ if ((peer->status == Established) && (peer->afc[afi][safi])) bgp_maximum_prefix_overflow(peer, afi, safi, 1); + + SET_FLAG(peer->af_flags_override[afi][safi], + PEER_FLAG_MAX_PREFIX); + + if (warning) + SET_FLAG(peer->af_flags_override[afi][safi], + PEER_FLAG_MAX_PREFIX_WARNING); + else + UNSET_FLAG(peer->af_flags_override[afi][safi], + PEER_FLAG_MAX_PREFIX_WARNING); } return 0; @@ -5990,49 +6048,49 @@ int peer_maximum_prefix_unset(struct peer *peer, afi_t afi, safi_t safi) struct peer_group *group; struct listnode *node, *nnode; - /* apply peer-group config */ - if (peer_group_active(peer)) { - if (CHECK_FLAG(peer->group->conf->af_flags[afi][safi], - PEER_FLAG_MAX_PREFIX)) - SET_FLAG(peer->af_flags[afi][safi], - PEER_FLAG_MAX_PREFIX); - else - UNSET_FLAG(peer->af_flags[afi][safi], - PEER_FLAG_MAX_PREFIX); - - if (CHECK_FLAG(peer->group->conf->af_flags[afi][safi], - PEER_FLAG_MAX_PREFIX_WARNING)) - SET_FLAG(peer->af_flags[afi][safi], - PEER_FLAG_MAX_PREFIX_WARNING); - else - UNSET_FLAG(peer->af_flags[afi][safi], - PEER_FLAG_MAX_PREFIX_WARNING); - - peer->pmax[afi][safi] = peer->group->conf->pmax[afi][safi]; - peer->pmax_threshold[afi][safi] = - peer->group->conf->pmax_threshold[afi][safi]; - peer->pmax_restart[afi][safi] = - peer->group->conf->pmax_restart[afi][safi]; - return 0; - } - UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); peer->pmax[afi][safi] = 0; peer->pmax_threshold[afi][safi] = 0; peer->pmax_restart[afi][safi] = 0; - if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) + /* if not handling a peer-group, unset override flags */ + if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + UNSET_FLAG(peer->af_flags_override[afi][safi], + PEER_FLAG_MAX_PREFIX); + UNSET_FLAG(peer->af_flags_override[afi][safi], + PEER_FLAG_MAX_PREFIX_WARNING); + /* if peer is part of a peer-group, apply peer-group config */ + if (peer_group_active(peer)) { + peer->pmax[afi][safi] = + peer->group->conf->pmax[afi][safi]; + peer->pmax_threshold[afi][safi] = + peer->group->conf->pmax_threshold[afi][safi]; + peer->pmax_restart[afi][safi] = + peer->group->conf->pmax_restart[afi][safi]; + } + return 0; + } + /* + * If this peer is a peer-group, set all peers in the group unless they + * have overrides for our config. + */ group = peer->group; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { - UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); - UNSET_FLAG(peer->af_flags[afi][safi], - PEER_FLAG_MAX_PREFIX_WARNING); - peer->pmax[afi][safi] = 0; - peer->pmax_threshold[afi][safi] = 0; - peer->pmax_restart[afi][safi] = 0; + if (!CHECK_FLAG(peer->af_flags_override[afi][safi], + PEER_FLAG_MAX_PREFIX_WARNING)) + UNSET_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_MAX_PREFIX_WARNING); + if (!CHECK_FLAG(peer->af_flags_override[afi][safi], + PEER_FLAG_MAX_PREFIX)) { + UNSET_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_MAX_PREFIX); + peer->pmax[afi][safi] = 0; + peer->pmax_threshold[afi][safi] = 0; + peer->pmax_restart[afi][safi] = 0; + } } return 0; } @@ -7109,7 +7167,9 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, /* atribute-unchanged. */ if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_AS_PATH_UNCHANGED) - || peer_af_flag_check(peer, afi, safi, PEER_FLAG_NEXTHOP_UNCHANGED) + || (safi != SAFI_EVPN + && peer_af_flag_check(peer, afi, safi, + PEER_FLAG_NEXTHOP_UNCHANGED)) || peer_af_flag_check(peer, afi, safi, PEER_FLAG_MED_UNCHANGED)) { if (!peer_group_active(peer) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index f460b0fa98..1ad6a5c9c8 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -837,7 +837,28 @@ struct peer { /* NSF mode (graceful restart) */ uint8_t nsf[AFI_MAX][SAFI_MAX]; - /* Per AF configuration flags. */ + /* Peer Per AF flags */ + /* + * Parallel array to af_flags that indicates whether each flag + * originates from a peer-group or if it is config that is specific to + * this individual peer. If a flag is set independent of the + * peer-group the same bit should be set here. If this peer is a + * peer-group, this memory region should be all zeros. The assumption + * is that the default state for all flags is unset. + * + * Notes: + * - if a flag for an individual peer is unset, the corresponding + * override flag is unset and the peer is considered to be back in + * sync with the peer-group. + * - This does *not* contain the flag values, rather it contains + * whether the flag at the same position in af_flags is + * *peer-specific*. + */ + uint32_t af_flags_override[AFI_MAX][SAFI_MAX]; + /* + * Effective flags, computed by applying peer-group flags and then + * overriding with individual flags + */ uint32_t af_flags[AFI_MAX][SAFI_MAX]; #define PEER_FLAG_SEND_COMMUNITY (1 << 0) /* send-community */ #define PEER_FLAG_SEND_EXT_COMMUNITY (1 << 1) /* send-community ext. */ diff --git a/configure.ac b/configure.ac index 7662f2a4e5..8b49295444 100755 --- a/configure.ac +++ b/configure.ac @@ -1913,8 +1913,13 @@ AC_MSG_RESULT($ac_cv_htonl_works) AC_CONFIG_FILES([Makefile bgpd/Makefile vtysh/Makefile - doc/Makefile tests/Makefile - bgpd/rfp-example/rfptest/Makefile bgpd/rfp-example/librfp/Makefile + doc/Makefile + doc/user/Makefile + doc/manpages/Makefile + doc/developer/Makefile + tests/Makefile + bgpd/rfp-example/rfptest/Makefile + bgpd/rfp-example/librfp/Makefile redhat/frr.spec debianpkg/Makefile debianpkg/changelog diff --git a/debianpkg/backports/ubuntu14.04/debian/frr.postinst b/debianpkg/backports/ubuntu14.04/debian/frr.postinst index b1d463a33d..5a14e510cd 100644 --- a/debianpkg/backports/ubuntu14.04/debian/frr.postinst +++ b/debianpkg/backports/ubuntu14.04/debian/frr.postinst @@ -18,7 +18,7 @@ chgrp ${frrvtygid} /etc/frr/vtysh* chmod 644 /etc/frr/* ENVIRONMENTFILE=/etc/environment -if ! grep --quiet VTYSH_PAGER=/bin/cat ${ENVIRONMENTFILE}; then +if ! egrep --quiet '^VTYSH_PAGER=' ${ENVIRONMENTFILE}; then echo "VTYSH_PAGER=/bin/cat" >> ${ENVIRONMENTFILE} fi ################################################## diff --git a/debianpkg/frr-doc.docs b/debianpkg/frr-doc.docs index 4720a3b920..d2218d00f9 100644 --- a/debianpkg/frr-doc.docs +++ b/debianpkg/frr-doc.docs @@ -1,6 +1,5 @@ AUTHORS NEWS README -REPORTING-BUGS doc/user/*.rst doc/figures/*.png diff --git a/debianpkg/frr.postinst b/debianpkg/frr.postinst index 972f8c0500..32af741c98 100644 --- a/debianpkg/frr.postinst +++ b/debianpkg/frr.postinst @@ -19,7 +19,7 @@ chgrp ${frrvtygid} /etc/frr/vtysh* chmod 644 /etc/frr/* ENVIRONMENTFILE=/etc/environment -if ! grep --quiet VTYSH_PAGER=/bin/cat ${ENVIRONMENTFILE}; then +if ! egrep --quiet '^VTYSH_PAGER=' ${ENVIRONMENTFILE}; then echo "VTYSH_PAGER=/bin/cat" >> ${ENVIRONMENTFILE} fi ################################################## diff --git a/doc/Makefile.am b/doc/Makefile.am index 053842283e..8fa057424a 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -14,7 +14,7 @@ .NOTPARALLEL: SUBDIRS = manpages user -AM_MAKEFLAGS = DESTDIR=${DESTDIR} infodir=${infodir} doczdir=${abs_srcdir} +AM_MAKEFLAGS = DESTDIR=${DESTDIR} infodir=${infodir} MANPAGE_BUILDDIR = manpages/_build/man diff --git a/doc/developer/.gitignore b/doc/developer/.gitignore index 0505537159..2e7d8573f1 100644 --- a/doc/developer/.gitignore +++ b/doc/developer/.gitignore @@ -1,3 +1,3 @@ /_templates /_build -!/Makefile +!/Makefile.in diff --git a/doc/developer/Makefile b/doc/developer/Makefile deleted file mode 100644 index 9807a750bf..0000000000 --- a/doc/developer/Makefile +++ /dev/null @@ -1 +0,0 @@ -include ../frr-sphinx.mk diff --git a/doc/developer/Makefile.in b/doc/developer/Makefile.in new file mode 100644 index 0000000000..76758f9242 --- /dev/null +++ b/doc/developer/Makefile.in @@ -0,0 +1,8 @@ +# This is necessary to support VPATH builds. +srcdir = @srcdir@ +VPATH = @srcdir@ + +# This variable is used as the documentation source location in frr-sphinx.mk +SOURCESDIR = @srcdir@ + +include @srcdir@/../frr-sphinx.mk diff --git a/doc/developer/conf.py b/doc/developer/conf.py index a3968b60ff..61253c4b2f 100644 --- a/doc/developer/conf.py +++ b/doc/developer/conf.py @@ -342,6 +342,14 @@ texinfo_documents = [ # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False +# contents of ../extra/frrlexer.py. +# This is read here to support VPATH build. Since this section is execfile()'d +# with the file location, we can safely use a relative path here to save the +# contents of the lexer file for later use even if our relative path changes +# due to VPATH. +with open('../extra/frrlexer.py', 'rb') as lex: + frrlexerpy = lex.read() + # custom extensions here def setup(app): # object type for FRR CLI commands, can be extended to document parent CLI @@ -357,5 +365,5 @@ def setup(app): # # frrlexer = pygments.lexers.load_lexer_from_file('../extra/frrlexer.py', lexername="FRRLexer") custom_namespace = {} - exec(open('../extra/frrlexer.py', 'rb').read(), custom_namespace) + exec(frrlexerpy, custom_namespace) lexers['frr'] = custom_namespace['FRRLexer']() diff --git a/doc/developer/index.rst b/doc/developer/index.rst index 2f4b96bc1f..2c855ee880 100644 --- a/doc/developer/index.rst +++ b/doc/developer/index.rst @@ -1,5 +1,5 @@ -Welcome to FRR's documentation! -=============================== +FRRouting Developer's Guide +=========================== .. toctree:: :maxdepth: 2 diff --git a/doc/developer/library.rst b/doc/developer/library.rst index c5ce1f5982..f6efa33051 100644 --- a/doc/developer/library.rst +++ b/doc/developer/library.rst @@ -1,3 +1,5 @@ +.. _libfrr: + *************************** Library Facilities (libfrr) *************************** diff --git a/doc/developer/process-architecture.rst b/doc/developer/process-architecture.rst index 514b5becdd..806afa644c 100644 --- a/doc/developer/process-architecture.rst +++ b/doc/developer/process-architecture.rst @@ -32,6 +32,8 @@ explicitly named, they will be formatted ``like this`` to differentiate from the conceptual names. When speaking of kernel threads, the term used will be "pthread" since FRR's kernel threading implementation is POSIX threads. +.. This should be broken into its document under :ref:`libfrr` +.. _event-architecture: Event Architecture ------------------ @@ -67,7 +69,8 @@ are given by integer macros in :file:`thread.h` and are: ``THREAD_EVENT`` Generic task that executes with high priority and carries an arbitrary - integer indicating the event type to its handler. + integer indicating the event type to its handler. These are commonly used to + implement the finite state machines typically found in routing protocols. ``THREAD_READY`` Type used internally for tasks on the ready queue. @@ -110,6 +113,26 @@ highest priority, followed by expired timers and finally I/O tasks (type arbitrary argument are provided. The task returned from ``thread_fetch()`` is then executed with ``thread_call()``. +The following diagram illustrates a simplified version of this infrastructure. + +.. todo: replace these with SVG +.. figure:: ../figures/threadmaster-single.png + :align: center + + Lifecycle of a program using a single threadmaster. + +The series of "task" boxes represents the current ready task queue. The various +other queues for other types are not shown. The fetch-execute loop is +illustrated at the bottom. + +Mapping the general names used in the figure to specific FRR functions: + +- ``task`` is ``struct thread *`` +- ``fetch`` is ``thread_fetch()`` +- ``exec()`` is ``thread_call`` +- ``cancel()`` is ``thread_cancel()`` +- ``schedule()`` is any of the various task-specific ``thread_add_*`` functions + Adding tasks is done with various task-specific function-like macros. These macros wrap underlying functions in :file:`thread.c` to provide additional information added at compile time, such as the line number the task was @@ -134,10 +157,6 @@ There are some gotchas to keep in mind: call is the responsibility of the caller. -.. todo: include this when its more complete -.. .. figure:: ../figures/threadmaster.svg - - Kernel Thread Architecture -------------------------- Efforts have begun to introduce kernel threads into FRR to improve performance @@ -158,6 +177,27 @@ the currently existing task and context primitives. In this way the familiar execution model of FRR gains the ability to execute tasks simultaneously while preserving the existing model for concurrency. +The following figure illustrates the architecture with multiple pthreads, each +running their own ``threadmaster``-based event loop. + +.. todo: replace these with SVG +.. figure:: ../figures/threadmaster-multiple.png + :align: center + + Lifecycle of a program using multiple pthreads, each running their own + ``threadmaster`` + +Each roundrect represents a single pthread running the same event loop +described under :ref:`event-architecture`. Note the arrow from the ``exec()`` +box on the right to the ``schedule()`` box in the middle pthread. This +illustrates code running in one pthread scheduling a task onto another +pthread's threadmaster. A global lock for each ``threadmaster`` is used to +synchronize these operations. The pthread names are examples. + + +.. This should be broken into its document under :ref:`libfrr` +.. _kernel-thread-wrapper: + Kernel Thread Wrapper ^^^^^^^^^^^^^^^^^^^^^ The basis for the integration of pthreads and the event system is a lightweight @@ -184,7 +224,9 @@ passing, where the messages are the regular task events as used in the event-driven model. The only difference is thread cancellation, which requires calling ``thread_cancel_async()`` instead of ``thread_cancel`` to cancel a task currently scheduled on a ``threadmaster`` belonging to a different pthread. -This is necessary +This is necessary to avoid race conditions in the specific case where one +pthread wants to guarantee that a task on another pthread is cancelled before +proceeding. In addition, the existing commands to show statistics and other information for tasks within the event driven model have been expanded to handle multiple diff --git a/doc/figures/threadmaster-multiple.png b/doc/figures/threadmaster-multiple.png Binary files differnew file mode 100644 index 0000000000..2ded50c4cb --- /dev/null +++ b/doc/figures/threadmaster-multiple.png diff --git a/doc/figures/threadmaster-single.png b/doc/figures/threadmaster-single.png Binary files differnew file mode 100644 index 0000000000..a068389b2a --- /dev/null +++ b/doc/figures/threadmaster-single.png diff --git a/doc/frr-sphinx.mk b/doc/frr-sphinx.mk index df4056760d..3e4c67d374 100644 --- a/doc/frr-sphinx.mk +++ b/doc/frr-sphinx.mk @@ -10,6 +10,11 @@ SPHINXBUILD ?= sphinx-build PAPER ?= BUILDDIR = _build +# This is a custom FRR variable just for this docs subdirectory used to support +# VPATH builds. Makefiles which include this file should override it to point +# to the correct sources path. +SOURCESDIR ?= . + # User-friendly check for sphinx-build ifneq ($(MAKECMDGOALS), clean) ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) @@ -23,9 +28,9 @@ endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(SOURCESDIR) # the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(SOURCESDIR) .PHONY: help help: diff --git a/doc/manpages/.gitignore b/doc/manpages/.gitignore index 0505537159..2e7d8573f1 100644 --- a/doc/manpages/.gitignore +++ b/doc/manpages/.gitignore @@ -1,3 +1,3 @@ /_templates /_build -!/Makefile +!/Makefile.in diff --git a/doc/manpages/Makefile b/doc/manpages/Makefile.in index ebbbc31009..f28746cee6 100644 --- a/doc/manpages/Makefile +++ b/doc/manpages/Makefile.in @@ -1,4 +1,11 @@ -include ../frr-sphinx.mk +# This is necessary to support VPATH builds. +srcdir = @srcdir@ +VPATH = @srcdir@ + +# This variable is used as the documentation source location in frr-sphinx.mk +SOURCESDIR = @srcdir@ + +include @srcdir@/../frr-sphinx.mk # ----------------------------------------------------------------------------- # Automake requires that 3rd-party Makefiles recognize these targets. diff --git a/doc/manpages/index.rst b/doc/manpages/index.rst index ae622bb699..6d3f3aae55 100644 --- a/doc/manpages/index.rst +++ b/doc/manpages/index.rst @@ -3,9 +3,6 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to FRR's documentation! -=============================== - .. toctree:: :maxdepth: 2 diff --git a/doc/user/.gitignore b/doc/user/.gitignore index 0505537159..2e7d8573f1 100644 --- a/doc/user/.gitignore +++ b/doc/user/.gitignore @@ -1,3 +1,3 @@ /_templates /_build -!/Makefile +!/Makefile.in diff --git a/doc/user/Makefile b/doc/user/Makefile.in index 223f8a64a3..77c6abf917 100644 --- a/doc/user/Makefile +++ b/doc/user/Makefile.in @@ -1,4 +1,11 @@ -include ../frr-sphinx.mk +# This is necessary to support VPATH builds. +srcdir = @srcdir@ +VPATH = @srcdir@ + +# This variable is used as the documentation source location in frr-sphinx.mk +SOURCESDIR = @srcdir@ + +include @srcdir@/../frr-sphinx.mk # ----------------------------------------------------------------------------- # Automake requires that 3rd-party Makefiles recognize these targets. diff --git a/doc/user/basic.rst b/doc/user/basic.rst index f134133da4..b861444e88 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -55,18 +55,23 @@ Basic Config Commands Set hostname of the router. -.. index:: password PASSWORD +.. index:: + single: no password PASSWORD + single: password PASSWORD -.. clicmd:: password PASSWORD +.. clicmd:: [no] password PASSWORD - Set password for vty interface. If there is no password, a vty won't - accept connections. + Set password for vty interface. The ``no`` form of the command deletes the + password. If there is no password, a vty won't accept connections. -.. index:: enable password PASSWORD +.. index:: + single: no enable password PASSWORD + single: enable password PASSWORD -.. clicmd:: enable password PASSWORD +.. clicmd:: [no] enable password PASSWORD - Set enable password. + Set enable password. The ``no`` form of the command deletes the enable + password. .. index:: single: no log trap [LEVEL] diff --git a/doc/user/bugs.rst b/doc/user/bugs.rst new file mode 100644 index 0000000000..60ddf612db --- /dev/null +++ b/doc/user/bugs.rst @@ -0,0 +1,67 @@ +.. _bugs: + +************** +Reporting Bugs +************** + +This file describes the procedure for reporting FRRouting bugs. You are asked +to follow this format when submitting bug reports. + +Bugs submitted with woefully incomplete information will receive little +attention and are likely to be closed. If you hit a suspected bug in an older +version, you may be asked to test with a later version in your environment. + +Often you may be asked for additional information to help solve the bug. Bugs +may be closed after 30 days of non-response to requests to reconfirm or supply +additional information. + +Please report bugs on the project GitHub issue tracker at +https://github.com/frrouting/frr/issues + +Report Format & Requested Information +===================================== + +When reporting a bug, please provide the following information. + +#. Your FRR version if it is a release build, or the commit hash if you built + from source. + +#. If you compiled from source, please provide your ``./configure`` line, + including all option flags. + +#. A full list of the FRR daemons you run. + +#. Your platform name and version, e.g. ``Ubuntu 18.04``. + +#. Problem description. + + - Provide as much information as possible. + - Copy and paste relevant commands and their output to describe your network + setup. + - Topology diagrams are helpful when reporting bugs involving more than one + box. + - Platform routing tables and interface configurations are useful if you are + reporting a routing issue. + + *Please be sure to review the provided information and censor any sensitive + material.* + +#. All FRR configuration files you use. Again, please be sure to censor any + sensitive information. For sensitive v4 / v6 addresses, we ask that you + censor the inner octets; e.g., ``192.XXX.XXX.32/24``. + +#. If you are reporting a crash and have a core file, please supply a stack + trace using GDB: + + :: + + $ gdb exec_file core_file + (gdb) bt . + +#. Run all FRR daemons with full debugging on and send *only* the portion of + logs which are relevant to your problem. + +#. Patches, workarounds, and fixes are always welcome. + +.. seealso:: :ref:`basic-config-commands` + diff --git a/doc/user/conf.py b/doc/user/conf.py index 886403b69d..3fced11024 100644 --- a/doc/user/conf.py +++ b/doc/user/conf.py @@ -342,6 +342,14 @@ texinfo_documents = [ # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False +# contents of ../extra/frrlexer.py. +# This is read here to support VPATH build. Since this section is execfile()'d +# with the file location, we can safely use a relative path here to save the +# contents of the lexer file for later use even if our relative path changes +# due to VPATH. +with open('../extra/frrlexer.py', 'rb') as lex: + frrlexerpy = lex.read() + # custom extensions here def setup(app): # object type for FRR CLI commands, can be extended to document parent CLI @@ -357,5 +365,5 @@ def setup(app): # # frrlexer = pygments.lexers.load_lexer_from_file('../extra/frrlexer.py', lexername="FRRLexer") custom_namespace = {} - exec(open('../extra/frrlexer.py', 'rb').read(), custom_namespace) + exec(frrlexerpy, custom_namespace) lexers['frr'] = custom_namespace['FRRLexer']() diff --git a/doc/user/index.rst b/doc/user/index.rst index 28a85da8aa..f20ff8ec2b 100644 --- a/doc/user/index.rst +++ b/doc/user/index.rst @@ -1,5 +1,5 @@ -Welcome to FRR's documentation! -=============================== +FRRouting User Guide +==================== .. toctree:: :maxdepth: 2 @@ -27,6 +27,7 @@ Welcome to FRR's documentation! ripngd sharp vnc + bugs glossary appendix diff --git a/doc/user/installation.rst b/doc/user/installation.rst index 8501054fdb..700a727d8f 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -117,11 +117,6 @@ customize the build to include or exclude specific features and dependencies. Enable Traffic Engineering Extension for ISIS (RFC5305) -.. option:: --enable-multipath <ARG> - - Enable support for Equal Cost Multipath. `ARG` is the maximum number - of ECMP paths to allow, set to 0 to allow unlimited number of paths. - .. option:: --enable-realms Enable the support of Linux Realms. Convert tag values from 1-255 into a @@ -176,6 +171,14 @@ customize the build to include or exclude specific features and dependencies. With this option, we provide a way to strip out these characters for APK dev package builds. +.. option:: --enable-multipath=X + + Compile FRR with up to X way ECMP supported. This number can be from 0-999. + For backwards compatability with older configure options when setting X = 0, + we will build FRR with 64 way ECMP. This is needed because there are + hardcoded arrays that FRR builds towards, so we need to know how big to + make these arrays at build time. + You may specify any combination of the above options to the configure script. By default, the executables are placed in :file:`/usr/local/sbin` and the configuration files in :file:`/usr/local/etc`. The :file:`/usr/local/` diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 56f95e64b0..71bc047720 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -101,7 +101,7 @@ OSPF6 interface .. index:: ipv6 ospf6 hello-interval HELLOINTERVAL .. clicmd:: ipv6 ospf6 hello-interval HELLOINTERVAL - Sets interface's Hello Interval. Default 40 + Sets interface's Hello Interval. Default 10 .. index:: ipv6 ospf6 dead-interval DEADINTERVAL .. clicmd:: ipv6 ospf6 dead-interval DEADINTERVAL diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst index eec575cf3f..aa48a3cd4f 100644 --- a/doc/user/pbr.rst +++ b/doc/user/pbr.rst @@ -57,7 +57,7 @@ against incoming packets. If matched the nexthop-group or nexthop is used to forward the packets to the end destination .. index:: pbr-map -.. clicmd:: pbr-map NAME seq (1-1000) +.. clicmd:: pbr-map NAME seq (1-700) Create a pbr-map with NAME and sequence number specified. This command puts you into a new submode for pbr-map specification. To exit this mode type diff --git a/doc/user/snmp.rst b/doc/user/snmp.rst index 1a24d56cb7..38918ff250 100644 --- a/doc/user/snmp.rst +++ b/doc/user/snmp.rst @@ -43,6 +43,9 @@ master SNMP agent (snmpd) and each of the FRR daemons must be configured. In In each of the FRR daemons, ``agentx`` command will enable AgentX support. :file:`/etc/snmp/snmpd.conf`: + +:: + # # example access restrictions setup # @@ -113,6 +116,9 @@ using the password "frr_ospfd". For testing it is recommending to take exactly the below snmpd.conf as wrong access restrictions can be hard to debug. :file:`/etc/snmp/snmpd.conf`: + +:: + # # example access restrictions setup # @@ -126,6 +132,9 @@ the below snmpd.conf as wrong access restrictions can be hard to debug. smuxpeer .1.3.6.1.4.1.3317.1.2.5 frr_ospfd :file:`/etc/frr/ospf`: + +:: + ! ... the rest of ospfd.conf has been omitted for clarity ... ! smux peer .1.3.6.1.4.1.3317.1.2.5 frr_ospfd diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 0927a4dbe9..78e1959d36 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -31,6 +31,21 @@ Besides the common invocation options (:ref:`common-invocation-options`), the When program terminates, retain routes added by zebra. +.. option:: -e X, --ecmp X + + Run zebra with a limited ecmp ability compared to what it is compiled to. + If you are running zebra on hardware limited functionality you can + force zebra to limit the maximum ecmp allowed to X. This number + is bounded by what you compiled FRR with as the maximum number. + +.. option:: -n, --vrfwnetns + + When *Zebra* starts with this option, the VRF backend is based on Linux + network namespaces. That implies that all network namespaces discovered by + ZEBRA will create an associated VRF. The other daemons will operate on the VRF + VRF defined by *Zebra*, as usual. More information in the :ref:`VRF Commands` + chapter. + .. program:: configure .. _interface-commands: @@ -47,6 +62,10 @@ Standard Commands .. clicmd:: interface IFNAME +.. index:: interface IFNAME vrf VRF + +.. clicmd:: interface IFNAME vrf VRF + .. index:: shutdown .. clicmd:: shutdown @@ -351,6 +370,139 @@ default) should the specified gateways not be reachable. E.g.: .. _multicast-rib-commands: +VRF (Virtual Routing and Forwarding) +==================================== + +Currently, the user has the possibility to configure VRFs. VRF is a way to +separate networking contexts on the same machine. Those networking contexts +are associated with separate interfaces, thus making it possible to associate +one interface with a specific VRF. +VRF can be used, for example, when instantiating per enterprise networking +services, without having to instantiate the physical host machine or the routing +management daemons for each enterprise. As a result, interfaces are separate for +each set of VRF, and routing daemons can have their own context for each VRF. + +This conceptual view introduces the *Default VRF* case. If the user does not +configure any specific VRF, then by default, the user will however configure the +*Default VRF*. +On the *Zebra* context, this can be done when being in configuration mode, when +configuring a static route clicmd:`ip route NETWORK GATEWAY`. + +.. code-block:: frr + + # case without VRF + configure terminal + ip route 10.0.0.0 255.255.255.0 10.0.0.2 + exit + +Configuring VRF networking contexts can be done in various ways on FRR. The VRF +interfaces can be configured by entering in interface configuration mode : +:clicmd:`interface IFNAME vrf VRF`. Also, if the user wants to configure a static +route for a specific VRF, then a specific VRF configuration mode is available. After +entering into that mode by following command: :clicmd:`vrf VRF`. the user can enter +the same route command as before, but this time, the route command will apply to vrf +VRF. + +.. code-block:: frr + + # case with VRF + configure terminal + vrf r1-cust1 + ip route 10.0.0.0 255.255.255.0 10.0.0.2 + exit-vrf + +A VRF backend mode is chosen when running *Zebra*. + +If no option is chosen, then the *Linux VRF* implementation as references in +`https://www.kernel.org/doc/Documentation/networking/vrf.txt` will be mapped over +the *Zebra* VRF. The routing table associated to that VRF is a Linux table +identifier located in the same *Linux network namespace* where *Zebra* started. + +If the :option:`-n` option is chosen, then the *Linux network namespace* will be +mapped over the *Zebra* VRF. That implies that *Zebra* is able to configure several +*Linux network namespaces*. The routing table associated to that VRF is the whole +routing tables located in that namespace. For instance, this mode matches OpenStack +Network Namespaces. It matches also OpenFastPath. The default behavior remains Linux +VRF which is supported by the Linux kernel community, see +`https://www.kernel.org/doc/Documentation/networking/vrf.txt`. + +Because of that difference, there are some subtle differences when running some +commands in relationship to VRF. Here is an extract of some of those commands: + +.. index:: vrf VRF +.. clicmd:: vrf VRF + + This command is available on configuration mode. By default, above command + permits accessing the vrf configuration mode. This mode is available for both + VRFs. It is to be noted that *Zebra* does not create *Linux VRF*. Provisioning + this command is used to keep the configuration intact. + +.. index:: netns NAMESPACE +.. clicmd:: netns NAMESPACE + + This command is based on VRF configuration mode. This command is available when + *Zebra* is run in :option:`-n` mode. This command reflects which *Linux network + namespace* is to be mapped with *Zebra* VRF. It is to be noted that *Zebra* + creates and detects added/suppressed VRFs from the Linux environment (in fact, + those managed with iproute2). Provisioning this command is used to keep the + configuration intact. + +.. index:: ip route NETWORK NETMASK GATEWAY +.. clicmd:: ip route NETWORK NETMASK GATEWAY + + This command is based on VRF configuration mode or in configuration mode. If + applied on configuration mode, this applies to default VRF. Otherwise, this + command applies to the VRF of the vrf configuration mode. By default, above + command permits configuring a network in the table identifier of the mentioned + VRF. If :option:`-n` option is given, the network will be configured in the + default routing table of the *Linux network namespace*. + +.. index:: ip route NETWORK NETMASK GATEWAY NEXTHOPVRF +.. clicmd:: ip route NETWORK NETMASK GATEWAY NEXTHOPVRF + + This command is based on VRF configuration mode or in configuration mode. If + on configuration mode, this applies to default VRF. Otherwise, this command + applies to the VRF of the vrf configuration mode. This command is used to + configure a vrf route leak across 2 VRFs. This command is only available when + *Zebra* is launched without :option:`-n` option. + +.. index:: ip route NETWORK NETMASK GATEWAY table TABLENO +.. clicmd:: ip route NETWORK NETMASK GATEWAY table TABLENO + + This command is based on VRF configuration mode. There, this command is only + available with :option:`-n` command. This commands permits configuring a network + route in the given ``TABLENO`` of the *Linux network namespace*. + +.. index:: ip route NETWORK NETMASK GATEWAY table TABLENO +.. clicmd:: ip route NETWORK NETMASK GATEWAY table TABLENO + + This command is based on configuration mode. There, for default VRF, this command + is available for all modes. The ``TABLENO`` configured is one of the tables from + Default *Linux network namespace*. + +.. index:: show ip route vrf VRF +.. clicmd:: show ip route vrf VRF + + The show command permits dumping the routing table associated to the VRF. If + *Zebra* is launched with default settings, this will be the ``TABLENO`` of the + VRF configured on the kernel, thanks to information provided in + `https://www.kernel.org/doc/Documentation/networking/vrf.txt`. + If *Zebra* is launched with :option:`-n` option, this will be the default routing + table of the *Linux network namespace* ``VRF``. + +.. index:: show ip route vrf VRF table TABLENO +.. clicmd:: show ip route vrf VRF table TABLENO + + The show command is only available with :option:`-n` option. + This command will dump the routing table ``TABLENO`` of the *Linux network + namespace* ``VRF``. + +.. code-block:: frr + + ip route 10.0.0.0 255.255.255.0 10.0.0.2 vrf r1-cust1 table 43 + show ip table vrf r1-cust1 table 43 + + Multicast RIB Commands ====================== diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c index 9c61512df4..e903dc8c7f 100644 --- a/isisd/isis_redist.c +++ b/isisd/isis_redist.c @@ -184,8 +184,7 @@ static void isis_redist_update_ext_reach(struct isis_area *area, int level, route_map_result_t map_ret; memcpy(&area_info, info, sizeof(area_info)); - if (redist->metric != 0xffffffff) - area_info.metric = redist->metric; + area_info.metric = redist->metric; if (redist->map_name) { map_ret = @@ -540,7 +539,7 @@ DEFUN (isis_redistribute, int afi; int type; int level; - unsigned long metric; + unsigned long metric = 0; const char *routemap = NULL; family = str2family(argv[idx_afi]->text); @@ -567,9 +566,6 @@ DEFUN (isis_redistribute, return CMD_WARNING_CONFIG_FAILED; } - metric = 0xffffffff; - routemap = NULL; - if (argc > idx_metric_rmap + 1) { if (argv[idx_metric_rmap + 1]->arg[0] == '\0') return CMD_WARNING_CONFIG_FAILED; @@ -651,7 +647,7 @@ DEFUN (isis_default_originate, int family; int originate_type = DEFAULT_ORIGINATE; int level; - unsigned long metric = 0xffffffff; + unsigned long metric = 0; const char *routemap = NULL; family = str2family(argv[idx_afi]->text); @@ -748,7 +744,7 @@ int isis_redist_config_write(struct vty *vty, struct isis_area *area, continue; vty_out(vty, " redistribute %s %s level-%d", family_str, zebra_route_string(type), level); - if (redist->metric != 0xffffffff) + if (redist->metric) vty_out(vty, " metric %u", redist->metric); if (redist->map_name) vty_out(vty, " route-map %s", redist->map_name); @@ -766,7 +762,7 @@ int isis_redist_config_write(struct vty *vty, struct isis_area *area, family_str, level); if (redist->redist == DEFAULT_ORIGINATE_ALWAYS) vty_out(vty, " always"); - if (redist->metric != 0xffffffff) + if (redist->metric) vty_out(vty, " metric %u", redist->metric); if (redist->map_name) vty_out(vty, " route-map %s", redist->map_name); diff --git a/lib/command.c b/lib/command.c index 2744061b5a..69e301fcfa 100644 --- a/lib/command.c +++ b/lib/command.c @@ -85,6 +85,7 @@ const char *node_names[] = { "keychain", // KEYCHAIN_NODE, "keychain key", // KEYCHAIN_KEY_NODE, "logical-router", // LOGICALROUTER_NODE, + "static ip", // IP_NODE, "vrf", // VRF_NODE, "interface", // INTERFACE_NODE, "nexthop-group", // NH_GROUP_NODE, @@ -119,7 +120,6 @@ const char *node_names[] = { "ldp l2vpn", // LDP_L2VPN_NODE, "ldp", // LDP_PSEUDOWIRE_NODE, "isis", // ISIS_NODE, - "static ip", // IP_NODE, "ipv4 access list", // ACCESS_NODE, "ipv4 prefix list", // PREFIX_NODE, "ipv6 access list", // ACCESS_IPV6_NODE, @@ -529,87 +529,103 @@ static int config_write_host(struct vty *vty) if (cmd_domainname_get()) vty_out(vty, "domainname %s\n", cmd_domainname_get()); - if (host.encrypt) { - if (host.password_encrypt) - vty_out(vty, "password 8 %s\n", host.password_encrypt); - if (host.enable_encrypt) - vty_out(vty, "enable password 8 %s\n", - host.enable_encrypt); - } else { - if (host.password) - vty_out(vty, "password %s\n", host.password); - if (host.enable) - vty_out(vty, "enable password %s\n", host.enable); - } + /* The following are all configuration commands that are not sent to + * watchfrr. For instance watchfrr is hardcoded to log to syslog so + * we would always display 'log syslog informational' in the config + * which would cause other daemons to then switch to syslog when they + * parse frr.conf. + */ + if (strcmp(zlog_default->protoname, "WATCHFRR")) { + if (host.encrypt) { + if (host.password_encrypt) + vty_out(vty, "password 8 %s\n", + host.password_encrypt); + if (host.enable_encrypt) + vty_out(vty, "enable password 8 %s\n", + host.enable_encrypt); + } else { + if (host.password) + vty_out(vty, "password %s\n", host.password); + if (host.enable) + vty_out(vty, "enable password %s\n", + host.enable); + } - if (zlog_default->default_lvl != LOG_DEBUG) { - vty_out(vty, "! N.B. The 'log trap' command is deprecated.\n"); - vty_out(vty, "log trap %s\n", - zlog_priority[zlog_default->default_lvl]); - } + if (zlog_default->default_lvl != LOG_DEBUG) { + vty_out(vty, + "! N.B. The 'log trap' command is deprecated.\n"); + vty_out(vty, "log trap %s\n", + zlog_priority[zlog_default->default_lvl]); + } - if (host.logfile - && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED)) { - vty_out(vty, "log file %s", host.logfile); - if (zlog_default->maxlvl[ZLOG_DEST_FILE] - != zlog_default->default_lvl) - vty_out(vty, " %s", - zlog_priority - [zlog_default->maxlvl[ZLOG_DEST_FILE]]); - vty_out(vty, "\n"); - } + if (host.logfile + && (zlog_default->maxlvl[ZLOG_DEST_FILE] + != ZLOG_DISABLED)) { + vty_out(vty, "log file %s", host.logfile); + if (zlog_default->maxlvl[ZLOG_DEST_FILE] + != zlog_default->default_lvl) + vty_out(vty, " %s", + zlog_priority + [zlog_default->maxlvl + [ZLOG_DEST_FILE]]); + vty_out(vty, "\n"); + } - if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED) { - vty_out(vty, "log stdout"); - if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] - != zlog_default->default_lvl) - vty_out(vty, " %s", - zlog_priority[zlog_default->maxlvl - [ZLOG_DEST_STDOUT]]); - vty_out(vty, "\n"); - } + if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED) { + vty_out(vty, "log stdout"); + if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] + != zlog_default->default_lvl) + vty_out(vty, " %s", + zlog_priority + [zlog_default->maxlvl + [ZLOG_DEST_STDOUT]]); + vty_out(vty, "\n"); + } - if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED) - vty_out(vty, "no log monitor\n"); - else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] - != zlog_default->default_lvl) - vty_out(vty, "log monitor %s\n", - zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]]); - - if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED) { - vty_out(vty, "log syslog"); - if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] - != zlog_default->default_lvl) - vty_out(vty, " %s", + if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED) + vty_out(vty, "no log monitor\n"); + else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] + != zlog_default->default_lvl) + vty_out(vty, "log monitor %s\n", zlog_priority[zlog_default->maxlvl - [ZLOG_DEST_SYSLOG]]); - vty_out(vty, "\n"); - } + [ZLOG_DEST_MONITOR]]); + + if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED) { + vty_out(vty, "log syslog"); + if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] + != zlog_default->default_lvl) + vty_out(vty, " %s", + zlog_priority[zlog_default->maxlvl + [ZLOG_DEST_SYSLOG]]); + vty_out(vty, "\n"); + } - if (zlog_default->facility != LOG_DAEMON) - vty_out(vty, "log facility %s\n", - facility_name(zlog_default->facility)); + if (zlog_default->facility != LOG_DAEMON) + vty_out(vty, "log facility %s\n", + facility_name(zlog_default->facility)); - if (zlog_default->record_priority == 1) - vty_out(vty, "log record-priority\n"); + if (zlog_default->record_priority == 1) + vty_out(vty, "log record-priority\n"); - if (zlog_default->timestamp_precision > 0) - vty_out(vty, "log timestamp precision %d\n", - zlog_default->timestamp_precision); + if (zlog_default->timestamp_precision > 0) + vty_out(vty, "log timestamp precision %d\n", + zlog_default->timestamp_precision); - if (host.advanced) - vty_out(vty, "service advanced-vty\n"); + if (host.advanced) + vty_out(vty, "service advanced-vty\n"); - if (host.encrypt) - vty_out(vty, "service password-encryption\n"); + if (host.encrypt) + vty_out(vty, "service password-encryption\n"); - if (host.lines >= 0) - vty_out(vty, "service terminal-length %d\n", host.lines); + if (host.lines >= 0) + vty_out(vty, "service terminal-length %d\n", + host.lines); - if (host.motdfile) - vty_out(vty, "banner motd file %s\n", host.motdfile); - else if (!host.motd) - vty_out(vty, "no banner motd\n"); + if (host.motdfile) + vty_out(vty, "banner motd file %s\n", host.motdfile); + else if (!host.motd) + vty_out(vty, "no banner motd\n"); + } if (debug_memstats_at_exit) vty_out(vty, "!\ndebug memstats-at-exit\n"); @@ -1895,7 +1911,7 @@ DEFUN (config_no_hostname, DEFUN (config_password, password_cmd, "password [(8-8)] WORD", - "Assign the terminal connection password\n" + "Modify the terminal connection password\n" "Specifies a HIDDEN password will follow\n" "The password string\n") { @@ -1934,6 +1950,36 @@ DEFUN (config_password, return CMD_SUCCESS; } +/* VTY interface password delete. */ +DEFUN (no_config_password, + no_password_cmd, + "no password", + NO_STR + "Modify the terminal connection password\n") +{ + bool warned = false; + + if (host.password) { + vty_out(vty, + "Please be aware that removing the password is a security risk and " + "you should think twice about this command\n"); + warned = true; + XFREE(MTYPE_HOST, host.password); + } + host.password = NULL; + + if (host.password_encrypt) { + if (!warned) + vty_out(vty, + "Please be aware that removing the password is a security risk " + "and you should think twice about this command\n"); + XFREE(MTYPE_HOST, host.password_encrypt); + } + host.password_encrypt = NULL; + + return CMD_SUCCESS; +} + /* VTY enable password set. */ DEFUN (config_enable_password, enable_password_cmd, @@ -1995,12 +2041,24 @@ DEFUN (no_config_enable_password, "Modify enable password parameters\n" "Assign the privileged level password\n") { - if (host.enable) + bool warned = false; + + if (host.enable) { + vty_out(vty, + "Please be aware that removing the password is a security risk and " + "you should think twice about this command\n"); + warned = true; XFREE(MTYPE_HOST, host.enable); + } host.enable = NULL; - if (host.enable_encrypt) + if (host.enable_encrypt) { + if (!warned) + vty_out(vty, + "Please be aware that removing the password is a security risk " + "and you should think twice about this command\n"); XFREE(MTYPE_HOST, host.enable_encrypt); + } host.enable_encrypt = NULL; return CMD_SUCCESS; @@ -2304,7 +2362,7 @@ static int set_log_file(struct vty *vty, const char *fname, int loglevel) #if defined(HAVE_CUMULUS) if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED) - zlog_default->maxlvl[ZLOG_DEST_SYSLOG] = ZLOG_DISABLED; + zlog_set_level(ZLOG_DEST_SYSLOG, ZLOG_DISABLED); #endif return CMD_SUCCESS; } @@ -2330,6 +2388,16 @@ DEFUN (config_log_file, zlog_default->default_lvl); } +static void disable_log_file(void) +{ + zlog_reset_file(); + + if (host.logfile) + XFREE(MTYPE_HOST, host.logfile); + + host.logfile = NULL; +} + DEFUN (no_config_log_file, no_config_log_file_cmd, "no log file [FILENAME [LEVEL]]", @@ -2339,13 +2407,7 @@ DEFUN (no_config_log_file, "Logging file name\n" "Logging level\n") { - zlog_reset_file(); - - if (host.logfile) - XFREE(MTYPE_HOST, host.logfile); - - host.logfile = NULL; - + disable_log_file(); return CMD_SUCCESS; } @@ -2357,6 +2419,9 @@ DEFUN (config_log_syslog, LOG_LEVEL_DESC) { int idx_log_levels = 2; + + disable_log_file(); + if (argc == 3) { int level; if ((level = level_match(argv[idx_log_levels]->arg)) @@ -2710,6 +2775,7 @@ void cmd_init(int terminal) if (terminal > 0) { install_element(CONFIG_NODE, &password_cmd); + install_element(CONFIG_NODE, &no_password_cmd); install_element(CONFIG_NODE, &enable_password_cmd); install_element(CONFIG_NODE, &no_enable_password_cmd); diff --git a/lib/command.h b/lib/command.h index f18de3417c..9ba53e0907 100644 --- a/lib/command.h +++ b/lib/command.h @@ -85,6 +85,7 @@ enum node_type { KEYCHAIN_NODE, /* Key-chain node. */ KEYCHAIN_KEY_NODE, /* Key-chain key node. */ LOGICALROUTER_NODE, /* Logical-Router node. */ + IP_NODE, /* Static ip route node. */ VRF_NODE, /* VRF mode node. */ INTERFACE_NODE, /* Interface mode node. */ NH_GROUP_NODE, /* Nexthop-Group mode node. */ @@ -119,7 +120,6 @@ enum node_type { LDP_L2VPN_NODE, /* LDP L2VPN node */ LDP_PSEUDOWIRE_NODE, /* LDP Pseudowire node */ ISIS_NODE, /* ISIS protocol mode */ - IP_NODE, /* Static ip route node. */ ACCESS_NODE, /* Access list node. */ PREFIX_NODE, /* Prefix list node. */ ACCESS_IPV6_NODE, /* Access list node. */ diff --git a/lib/ipaddr.h b/lib/ipaddr.h index 33591cb4e7..7f2d06548b 100644 --- a/lib/ipaddr.h +++ b/lib/ipaddr.h @@ -102,4 +102,14 @@ static inline void ipv4_to_ipv4_mapped_ipv6(struct in6_addr *in6, memcpy((char *)in6 + 12, &in, sizeof(struct in_addr)); } +/* + * convert an ipv4 mapped ipv6 address back to ipv4 address + */ +static inline void ipv4_mapped_ipv6_to_ipv4(struct in6_addr *in6, + struct in_addr *in) +{ + memset(in, 0, sizeof(struct in_addr)); + memcpy(in, (char *)in6 + 12, sizeof(struct in_addr)); +} + #endif /* __IPADDR_H__ */ diff --git a/lib/prefix.c b/lib/prefix.c index b38dd94589..05af190e9d 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -1206,54 +1206,104 @@ int str2prefix(const char *str, struct prefix *p) return 0; } -static const char *prefixevpn2str(const struct prefix *p, char *str, int size) +static const char *prefixevpn_ead2str(const struct prefix_evpn *p, char *str, + int size) +{ + snprintf(str, size, "Unsupported EVPN prefix"); + return str; +} + +static const char *prefixevpn_macip2str(const struct prefix_evpn *p, char *str, + int size) { uint8_t family; char buf[PREFIX2STR_BUFFER]; char buf2[ETHER_ADDR_STRLEN]; - if (p->u.prefix_evpn.route_type == 2) { - if (IS_EVPN_PREFIX_IPADDR_NONE((struct prefix_evpn *)p)) - snprintf(str, size, "[%d]:[%s]/%d", - p->u.prefix_evpn.route_type, - prefix_mac2str(&p->u.prefix_evpn.mac, buf2, - sizeof(buf2)), - p->prefixlen); - else { - family = IS_EVPN_PREFIX_IPADDR_V4( - (struct prefix_evpn *)p) - ? AF_INET - : AF_INET6; - snprintf(str, size, "[%d]:[%s]:[%s]/%d", - p->u.prefix_evpn.route_type, - prefix_mac2str(&p->u.prefix_evpn.mac, buf2, - sizeof(buf2)), - inet_ntop(family, &p->u.prefix_evpn.ip.ip.addr, - buf, PREFIX2STR_BUFFER), - p->prefixlen); - } - } else if (p->u.prefix_evpn.route_type == 3) { - family = IS_EVPN_PREFIX_IPADDR_V4((struct prefix_evpn *)p) - ? AF_INET - : AF_INET6; - snprintf(str, size, "[%d]:[%s]/%d", p->u.prefix_evpn.route_type, - inet_ntop(family, &p->u.prefix_evpn.ip.ip.addr, buf, - PREFIX2STR_BUFFER), + if (is_evpn_prefix_ipaddr_none(p)) + snprintf(str, size, "[%d]:[%s]/%d", + p->prefix.route_type, + prefix_mac2str(&p->prefix.macip_addr.mac, + buf2, sizeof(buf2)), p->prefixlen); - } else if (p->u.prefix_evpn.route_type == 5) { - family = IS_EVPN_PREFIX_IPADDR_V4((struct prefix_evpn *)p) + else { + family = is_evpn_prefix_ipaddr_v4(p) ? AF_INET : AF_INET6; - snprintf(str, size, "[%d]:[%u][%s/%d]/%d", - p->u.prefix_evpn.route_type, p->u.prefix_evpn.eth_tag, - inet_ntop(family, &p->u.prefix_evpn.ip.ip.addr, buf, - PREFIX2STR_BUFFER), - p->u.prefix_evpn.ip_prefix_length, p->prefixlen); - } else { - sprintf(str, "Unsupported EVPN route type %d", - p->u.prefix_evpn.route_type); + snprintf(str, size, "[%d]:[%s]:[%s]/%d", + p->prefix.route_type, + prefix_mac2str(&p->prefix.macip_addr.mac, + buf2, sizeof(buf2)), + inet_ntop(family, + &p->prefix.macip_addr.ip.ip.addr, + buf, PREFIX2STR_BUFFER), + p->prefixlen); } + return str; +} + +static const char *prefixevpn_imet2str(const struct prefix_evpn *p, char *str, + int size) +{ + uint8_t family; + char buf[PREFIX2STR_BUFFER]; + + family = is_evpn_prefix_ipaddr_v4(p) + ? AF_INET + : AF_INET6; + snprintf(str, size, "[%d]:[%s]/%d", p->prefix.route_type, + inet_ntop(family, + &p->prefix.imet_addr.ip.ip.addr, buf, + PREFIX2STR_BUFFER), + p->prefixlen); + return str; +} +static const char *prefixevpn_es2str(const struct prefix_evpn *p, char *str, + int size) +{ + snprintf(str, size, "Unsupported EVPN prefix"); + return str; +} + +static const char *prefixevpn_prefix2str(const struct prefix_evpn *p, char *str, + int size) +{ + uint8_t family; + char buf[PREFIX2STR_BUFFER]; + + family = is_evpn_prefix_ipaddr_v4(p) + ? AF_INET + : AF_INET6; + snprintf(str, size, "[%d]:[%u][%s/%d]/%d", + p->prefix.route_type, + p->prefix.prefix_addr.eth_tag, + inet_ntop(family, + &p->prefix.prefix_addr.ip.ip.addr, buf, + PREFIX2STR_BUFFER), + p->prefix.prefix_addr.ip_prefix_length, + p->prefixlen); + return str; +} + +static const char *prefixevpn2str(const struct prefix_evpn *p, char *str, + int size) +{ + switch (p->prefix.route_type) { + case 1: + return prefixevpn_ead2str(p, str, size); + case 2: + return prefixevpn_macip2str(p, str, size); + case 3: + return prefixevpn_imet2str(p, str, size); + case 4: + return prefixevpn_es2str(p, str, size); + case 5: + return prefixevpn_prefix2str(p, str, size); + default: + snprintf(str, size, "Unsupported EVPN prefix"); + break; + } return str; } @@ -1277,7 +1327,7 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) break; case AF_EVPN: - prefixevpn2str(p, str, size); + prefixevpn2str((const struct prefix_evpn *)p, str, size); break; case AF_FLOWSPEC: diff --git a/lib/prefix.h b/lib/prefix.h index f01c85b811..ab3c05ae74 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -56,26 +56,56 @@ struct ethaddr { #define PREFIX_LEN_ROUTE_TYPE_5_IPV4 (18*8) #define PREFIX_LEN_ROUTE_TYPE_5_IPV6 (30*8) -/* EVPN address (RFC 7432) */ -struct evpn_addr { - uint8_t route_type; +typedef struct esi_t_ { + uint8_t val[10]; +} esi_t; + +struct evpn_ead_addr { + esi_t esi; + uint32_t eth_tag; +}; + +struct evpn_macip_addr { + uint32_t eth_tag; uint8_t ip_prefix_length; struct ethaddr mac; + struct ipaddr ip; +}; + +struct evpn_imet_addr { uint32_t eth_tag; + uint8_t ip_prefix_length; struct ipaddr ip; -#if 0 - union - { - uint8_t addr; - struct in_addr v4_addr; - struct in6_addr v6_addr; - } ip; -#endif }; -#define IS_EVPN_PREFIX_IPADDR_NONE(evp) IS_IPADDR_NONE(&(evp)->prefix.ip) -#define IS_EVPN_PREFIX_IPADDR_V4(evp) IS_IPADDR_V4(&(evp)->prefix.ip) -#define IS_EVPN_PREFIX_IPADDR_V6(evp) IS_IPADDR_V6(&(evp)->prefix.ip) +struct evpn_es_addr { + esi_t esi; + uint8_t ip_prefix_length; + struct ipaddr ip; +}; + +struct evpn_prefix_addr { + uint32_t eth_tag; + uint8_t ip_prefix_length; + struct ipaddr ip; +}; + +/* EVPN address (RFC 7432) */ +struct evpn_addr { + uint8_t route_type; + union { + struct evpn_ead_addr _ead_addr; + struct evpn_macip_addr _macip_addr; + struct evpn_imet_addr _imet_addr; + struct evpn_es_addr _es_addr; + struct evpn_prefix_addr _prefix_addr; + } u; +#define ead_addr u._ead_addr +#define macip_addr u._macip_addr +#define imet_addr u._imet_addr +#define es_addr u._es_addr +#define prefix_addr u._prefix_addr +}; /* * A struct prefix contains an address family, a prefix length, and an @@ -177,6 +207,39 @@ struct prefix_evpn { struct evpn_addr prefix __attribute__((aligned(8))); }; +static inline int is_evpn_prefix_ipaddr_none(const struct prefix_evpn *evp) +{ + if (evp->prefix.route_type == 2) + return IS_IPADDR_NONE(&(evp)->prefix.macip_addr.ip); + if (evp->prefix.route_type == 3) + return IS_IPADDR_NONE(&(evp)->prefix.imet_addr.ip); + if (evp->prefix.route_type == 5) + return IS_IPADDR_NONE(&(evp)->prefix.prefix_addr.ip); + return 0; +} + +static inline int is_evpn_prefix_ipaddr_v4(const struct prefix_evpn *evp) +{ + if (evp->prefix.route_type == 2) + return IS_IPADDR_V4(&(evp)->prefix.macip_addr.ip); + if (evp->prefix.route_type == 3) + return IS_IPADDR_V4(&(evp)->prefix.imet_addr.ip); + if (evp->prefix.route_type == 5) + return IS_IPADDR_V4(&(evp)->prefix.prefix_addr.ip); + return 0; +} + +static inline int is_evpn_prefix_ipaddr_v6(const struct prefix_evpn *evp) +{ + if (evp->prefix.route_type == 2) + return IS_IPADDR_V6(&(evp)->prefix.macip_addr.ip); + if (evp->prefix.route_type == 3) + return IS_IPADDR_V6(&(evp)->prefix.imet_addr.ip); + if (evp->prefix.route_type == 5) + return IS_IPADDR_V6(&(evp)->prefix.prefix_addr.ip); + return 0; +} + /* Prefix for a generic pointer */ struct prefix_ptr { uint8_t family; diff --git a/lib/zclient.c b/lib/zclient.c index cb39099fc2..05bd907589 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -975,8 +975,6 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) stream_putl(s, api->flags); stream_putc(s, api->message); stream_putc(s, api->safi); - if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) - stream_put(s, &(api->rmac), sizeof(struct ethaddr)); /* Put prefix information. */ stream_putc(s, api->prefix.family); @@ -1061,6 +1059,11 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) api_nh->label_num * sizeof(mpls_label_t)); } + + /* Router MAC for EVPN routes. */ + if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) + stream_put(s, &(api_nh->rmac), + sizeof(struct ethaddr)); } } @@ -1101,8 +1104,6 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) STREAM_GETL(s, api->flags); STREAM_GETC(s, api->message); STREAM_GETC(s, api->safi); - if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) - STREAM_GET(&(api->rmac), s, sizeof(struct ethaddr)); /* Prefix. */ STREAM_GETC(s, api->prefix.family); @@ -1212,6 +1213,11 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) api_nh->label_num * sizeof(mpls_label_t)); } + + /* Router MAC for EVPN routes. */ + if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) + stream_get(&(api_nh->rmac), s, + sizeof(struct ethaddr)); } } diff --git a/lib/zclient.h b/lib/zclient.h index 8d26b7fe59..c5eaf9c0fd 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -302,6 +302,8 @@ struct zapi_nexthop { /* MPLS labels for BGP-LU or Segment Routing */ uint8_t label_num; mpls_label_t labels[MPLS_MAX_LABELS]; + + struct ethaddr rmac; }; /* @@ -342,8 +344,6 @@ struct zapi_route { vrf_id_t vrf_id; uint32_t tableid; - - struct ethaddr rmac; }; /* Zebra IPv4 route message API. */ diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index b895b5ad8b..bc1ce621ae 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -684,7 +684,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) { struct prefix prefix, abr_prefix; struct ospf6_route_table *table = NULL; - struct ospf6_route *range, *route, *old = NULL; + struct ospf6_route *range, *route, *old = NULL, *old_route; struct ospf6_route *abr_entry; uint8_t type = 0; char options[3] = {0, 0, 0}; @@ -695,14 +695,15 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) int is_debug = 0; struct ospf6_inter_prefix_lsa *prefix_lsa = NULL; struct ospf6_inter_router_lsa *router_lsa = NULL; - struct ospf6_path *path; + bool old_entry_updated = false; memset(&prefix, 0, sizeof(prefix)); if (lsa->header->type == htons(OSPF6_LSTYPE_INTER_PREFIX)) { if (IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX)) { is_debug++; - zlog_debug("Examin %s in area %s", lsa->name, oa->name); + zlog_debug("%s: Examin %s in area %s", + __PRETTY_FUNCTION__, lsa->name, oa->name); } prefix_lsa = @@ -720,7 +721,8 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) } else if (lsa->header->type == htons(OSPF6_LSTYPE_INTER_ROUTER)) { if (IS_OSPF6_DEBUG_EXAMIN(INTER_ROUTER)) { is_debug++; - zlog_debug("Examin %s in area %s", lsa->name, oa->name); + zlog_debug("%s: Examin %s in area %s", + __PRETTY_FUNCTION__, lsa->name, oa->name); } router_lsa = @@ -768,7 +770,8 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) } if (OSPF6_LSA_IS_MAXAGE(lsa)) { if (is_debug) - zlog_debug("LSA is MaxAge, ignore"); + zlog_debug("%s: LSA %s is MaxAge, ignore", + __PRETTY_FUNCTION__, lsa->name); if (old) ospf6_route_remove(old, table); return; @@ -845,9 +848,24 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) || CHECK_FLAG(abr_entry->flag, OSPF6_ROUTE_REMOVE) || !CHECK_FLAG(abr_entry->path.router_bits, OSPF6_ROUTER_BIT_B)) { if (is_debug) - zlog_debug("ABR router entry does not exist, ignore"); - if (old) - ospf6_route_remove(old, table); + zlog_debug("%s: ABR router entry does not exist, ignore", + __PRETTY_FUNCTION__); + if (old) { + if (old->type == OSPF6_DEST_TYPE_ROUTER && + oa->intra_brouter_calc) { + if (is_debug) + zlog_debug( + "%s: intra_brouter_calc is on, skip brouter remove: %s (%p)", + __PRETTY_FUNCTION__, buf, + (void *)old); + } else { + if (is_debug) + zlog_debug("%s: remove old entry: %s %p ", + __PRETTY_FUNCTION__, buf, + (void *)old); + ospf6_route_remove(old, table); + } + } return; } @@ -902,11 +920,11 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) route->path.type = OSPF6_PATH_TYPE_INTER; route->path.cost = abr_entry->path.cost + cost; - ospf6_route_copy_nexthops(route, abr_entry); - - path = ospf6_path_dup(&route->path); - ospf6_copy_nexthops(path->nh_list, abr_entry->nh_list); - listnode_add_sort(route->paths, path); + /* Inter abr_entry is same as brouter. + * Avoid duplicate nexthops to brouter and its + * learnt route. i.e. use merge nexthops. + */ + ospf6_route_merge_nexthops(route, abr_entry); /* (7) If the routes are identical, copy the next hops over to existing route. ospf6's route table implementation will otherwise string both @@ -915,11 +933,28 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) */ old = ospf6_route_lookup(&prefix, table); - if (old && (ospf6_route_cmp(route, old) == 0)) { - ospf6_route_merge_nexthops(old, route); + for (old_route = old; old_route; old_route = old_route->next) { + if (!ospf6_route_is_same(old_route, route) || + (old_route->type != route->type) || + (old_route->path.type != route->path.type)) + continue; + + if ((ospf6_route_cmp(route, old_route) != 0)) { + if (is_debug) { + prefix2str(&prefix, buf, sizeof(buf)); + zlog_debug("%s: old %p %s cost %u new route cost %u are not same", + __PRETTY_FUNCTION__, + (void *)old_route, buf, + old_route->path.cost, + route->path.cost); + } + continue; + } + old_entry_updated = true; + ospf6_route_merge_nexthops(old, route); if (is_debug) - zlog_debug("%s: Update route: %s old cost %u new cost %u nh count %u", + zlog_debug("%s: Update route: %s old cost %u new cost %u nh %u", __PRETTY_FUNCTION__, buf, old->path.cost, route->path.cost, listcount(route->nh_list)); @@ -930,9 +965,12 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) /* Delete new route */ ospf6_route_delete(route); - } else { + break; + } + + if (old_entry_updated == false) { if (is_debug) - zlog_debug("%s: Install route: %s cost %u nh count %u", + zlog_debug("%s: Install route: %s cost %u nh %u", __PRETTY_FUNCTION__, buf, route->path.cost, listcount(route->nh_list)); /* ospf6_ia_add_nw_route (table, &prefix, route); */ diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h index eaf3e5c6de..ba497a168e 100644 --- a/ospf6d/ospf6_area.h +++ b/ospf6d/ospf6_area.h @@ -50,6 +50,9 @@ struct ospf6_area { /* Area type */ int no_summary; + /* Brouter traversal protection */ + int intra_brouter_calc; + /* OSPF interface list */ struct list *if_list; diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index b234b10d51..26e6deadae 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -2047,8 +2047,10 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa) uint32_t brouter_id; char brouter_name[16]; - if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(oa->area_id)) - zlog_info("border-router calculation for area %s", oa->name); + if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(oa->area_id) || + IS_OSPF6_DEBUG_ROUTE(MEMORY)) + zlog_info("%s: border-router calculation for area %s", + __PRETTY_FUNCTION__, oa->name); hook_add = oa->ospf6->brouter_table->hook_add; hook_remove = oa->ospf6->brouter_table->hook_remove; @@ -2114,6 +2116,7 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa) for (brouter = ospf6_route_head(oa->ospf6->brouter_table); brouter; brouter = nbrouter) { + /* * brouter may have been "deleted" in the last loop iteration. * If this is the case there is still 1 final refcount lock @@ -2122,6 +2125,8 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa) * skip processing the deleted route. */ if (brouter->lock == 1) { + if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) + ospf6_brouter_debug_print(brouter); nbrouter = ospf6_route_next(brouter); continue; } else { @@ -2173,8 +2178,14 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa) brouter_id) || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID( oa->area_id)) - zlog_info("brouter %s disappears via area %s", - brouter_name, oa->name); + zlog_info("%s: brouter %s disappears via area %s", + __PRETTY_FUNCTION__, brouter_name, + oa->name); + /* This is used to protect nbrouter from removed from + * the table. For an example, ospf6_abr_examin_summary, + * removes brouters which are marked for remove. + */ + oa->intra_brouter_calc = 1; ospf6_route_remove(brouter, oa->ospf6->brouter_table); brouter = NULL; } else if (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_ADD) @@ -2184,8 +2195,9 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa) brouter_id) || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID( oa->area_id)) - zlog_info("brouter %s appears via area %s", - brouter_name, oa->name); + zlog_info("%s: brouter %s appears via area %s", + __PRETTY_FUNCTION__, brouter_name, + oa->name); /* newly added */ if (hook_add) @@ -2205,11 +2217,14 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa) UNSET_FLAG(brouter->flag, OSPF6_ROUTE_ADD); UNSET_FLAG(brouter->flag, OSPF6_ROUTE_CHANGE); } + /* Reset for nbrouter */ + oa->intra_brouter_calc = 0; } - if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(oa->area_id)) - zlog_info("border-router calculation for area %s: done", - oa->name); + if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(oa->area_id) || + IS_OSPF6_DEBUG_ROUTE(MEMORY)) + zlog_info("%s: border-router calculation for area %s: done", + __PRETTY_FUNCTION__, oa->name); } struct ospf6_lsa_handler router_handler = {.lh_type = OSPF6_LSTYPE_ROUTER, diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 39272b3701..15d8eb6cf2 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -925,10 +925,11 @@ struct ospf6_route *ospf6_route_next(struct ospf6_route *route) struct ospf6_route *next = route->next; if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) - zlog_info("%s %p: route next: %p<-[%p]->%p", + zlog_info("%s %p: route next: %p<-[%p]->%p , route ref count %u", ospf6_route_table_name(route->table), (void *)route->table, (void *)route->prev, - (void *)route, (void *)route->next); + (void *)route, (void *)route->next, + route->lock); ospf6_route_unlock(route); if (next) diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index e4a4891526..7bf099fbbf 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -97,7 +97,8 @@ static void ospf6_top_route_hook_remove(struct ospf6_route *route) static void ospf6_top_brouter_hook_add(struct ospf6_route *route) { - if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL) || + IS_OSPF6_DEBUG_BROUTER) { uint32_t brouter_id; char brouter_name[16]; @@ -116,15 +117,17 @@ static void ospf6_top_brouter_hook_add(struct ospf6_route *route) static void ospf6_top_brouter_hook_remove(struct ospf6_route *route) { - if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL) || + IS_OSPF6_DEBUG_BROUTER) { uint32_t brouter_id; char brouter_name[16]; brouter_id = ADV_ROUTER_IN_PREFIX(&route->prefix); inet_ntop(AF_INET, &brouter_id, brouter_name, sizeof(brouter_name)); - zlog_debug("%s: brouter %s del with nh count %u", - __PRETTY_FUNCTION__, brouter_name, + zlog_debug("%s: brouter %p %s del with adv router %x nh %u", + __PRETTY_FUNCTION__, (void *)route, brouter_name, + route->path.origin.adv_router, listcount(route->nh_list)); } route->flag |= OSPF6_ROUTE_REMOVE; diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index 8d6d5b4a26..db61fe087b 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -97,7 +97,7 @@ DEFUN_NOSH (show_debugging_ospf6, DEBUG_STR OSPF6_STR) { - vty_out(vty, "OSPF6 debugging status:"); + vty_out(vty, "OSPF6 debugging status:\n"); config_write_ospf6_debug(vty); diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index ba5c49ad5c..b7d2b1a928 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -38,7 +38,7 @@ #include "pbrd/pbr_vty_clippy.c" #endif -DEFUN_NOSH(pbr_map, pbr_map_cmd, "pbr-map WORD seq (1-1000)", +DEFUN_NOSH(pbr_map, pbr_map_cmd, "pbr-map WORD seq (1-700)", "Create pbr-map or enter pbr-map command mode\n" "The name of the PBR MAP\n" "Sequence to insert in existing pbr-map entry\n" @@ -54,7 +54,7 @@ DEFUN_NOSH(pbr_map, pbr_map_cmd, "pbr-map WORD seq (1-1000)", return CMD_SUCCESS; } -DEFUN_NOSH(no_pbr_map, no_pbr_map_cmd, "no pbr-map WORD [seq (1-65535)]", +DEFUN_NOSH(no_pbr_map, no_pbr_map_cmd, "no pbr-map WORD [seq (1-700)]", NO_STR "Delete pbr-map\n" "The name of the PBR MAP\n" diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index bc7dd20832..cdacfad4b4 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -479,6 +479,7 @@ static void pbr_encode_pbr_map_sequence(struct stream *s, stream_putw(s, 0); /* src port */ pbr_encode_pbr_map_sequence_prefix(s, pbrms->dst, family); stream_putw(s, 0); /* dst port */ + stream_putl(s, 0); /* fwmark */ if (pbrms->nhgrp_name) stream_putl(s, pbr_nht_get_table(pbrms->nhgrp_name)); else if (pbrms->nhg) diff --git a/pimd/COMMANDS b/pimd/COMMANDS index 6f2e020bd8..141ec62aeb 100644 --- a/pimd/COMMANDS +++ b/pimd/COMMANDS @@ -24,6 +24,7 @@ verification commands: show ip igmp groups retransmissions IGMP group retransmission show ip igmp sources IGMP sources information show ip igmp sources retransmissions IGMP source retransmission + show ip igmp statistics IGMP statistics information show ip pim address PIM interface address show ip pim assert PIM interface assert show ip pim assert-internal PIM interface internal assert state diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 35514a85da..81191eb96c 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1294,6 +1294,76 @@ static void pim_show_interfaces_single(struct pim_instance *pim, } } +static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty, + const char *ifname, uint8_t uj) +{ + struct interface *ifp; + struct igmp_stats rx_stats; + + igmp_stats_init(&rx_stats); + + FOR_ALL_INTERFACES (pim->vrf, ifp) { + struct pim_interface *pim_ifp; + struct listnode *sock_node; + struct igmp_sock *igmp; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + if (ifname && strcmp(ifname, ifp->name)) + continue; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, + igmp)) { + igmp_stats_add(&rx_stats, &igmp->rx_stats); + } + } + if (uj) { + json_object *json = NULL; + json_object *json_row = NULL; + + json = json_object_new_object(); + json_row = json_object_new_object(); + + json_object_string_add(json_row, "name", ifname ? ifname : + "global"); + json_object_int_add(json_row, "queryV1", rx_stats.query_v1); + json_object_int_add(json_row, "queryV2", rx_stats.query_v2); + json_object_int_add(json_row, "queryV3", rx_stats.query_v3); + json_object_int_add(json_row, "leaveV3", rx_stats.leave_v2); + json_object_int_add(json_row, "reportV1", rx_stats.report_v1); + json_object_int_add(json_row, "reportV2", rx_stats.report_v2); + json_object_int_add(json_row, "reportV3", rx_stats.report_v3); + json_object_int_add(json_row, "mtraceResponse", + rx_stats.mtrace_rsp); + json_object_int_add(json_row, "mtraceRequest", + rx_stats.mtrace_req); + json_object_int_add(json_row, "unsupported", + rx_stats.unsupported); + json_object_object_add(json, ifname ? ifname : "global", + json_row); + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } else { + vty_out(vty, "IGMP RX statistics\n"); + vty_out(vty, "Interface : %s\n", + ifname ? ifname : "global"); + vty_out(vty, "V1 query : %u\n", rx_stats.query_v1); + vty_out(vty, "V2 query : %u\n", rx_stats.query_v2); + vty_out(vty, "V3 query : %u\n", rx_stats.query_v3); + vty_out(vty, "V2 leave : %u\n", rx_stats.leave_v2); + vty_out(vty, "V1 report : %u\n", rx_stats.report_v1); + vty_out(vty, "V2 report : %u\n", rx_stats.report_v2); + vty_out(vty, "V3 report : %u\n", rx_stats.report_v3); + vty_out(vty, "mtrace response : %u\n", rx_stats.mtrace_rsp); + vty_out(vty, "mtrace request : %u\n", rx_stats.mtrace_req); + vty_out(vty, "unsupported : %u\n", rx_stats.unsupported); + } +} + static void pim_show_interfaces(struct pim_instance *pim, struct vty *vty, uint8_t uj) { @@ -3527,6 +3597,33 @@ DEFUN (show_ip_igmp_sources_retransmissions, return CMD_SUCCESS; } +DEFUN (show_ip_igmp_statistics, + show_ip_igmp_statistics_cmd, + "show ip igmp [vrf NAME] statistics [interface WORD] [json]", + SHOW_STR + IP_STR + IGMP_STR + VRF_CMD_HELP_STR + "IGMP statistics\n" + "interface\n" + "IGMP interface\n" + JSON_STR) +{ + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + uint8_t uj = use_json(argc, argv); + + if (!vrf) + return CMD_WARNING; + + if (argv_find(argv, argc, "WORD", &idx)) + igmp_show_statistics(vrf->info, vty, argv[idx]->arg, uj); + else + igmp_show_statistics(vrf->info, vty, NULL, uj); + + return CMD_SUCCESS; +} + DEFUN (show_ip_pim_assert, show_ip_pim_assert_cmd, "show ip pim [vrf NAME] assert", @@ -8644,6 +8741,7 @@ void pim_cmd_init(void) install_element(VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd); install_element(VIEW_NODE, &show_ip_igmp_sources_cmd); install_element(VIEW_NODE, &show_ip_igmp_sources_retransmissions_cmd); + install_element(VIEW_NODE, &show_ip_igmp_statistics_cmd); install_element(VIEW_NODE, &show_ip_pim_assert_cmd); install_element(VIEW_NODE, &show_ip_pim_assert_internal_cmd); install_element(VIEW_NODE, &show_ip_pim_assert_metric_cmd); diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 5e1aecc3a3..c980f5fcba 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -303,6 +303,21 @@ static int igmp_recv_query(struct igmp_sock *igmp, int query_version, return -1; } + /* Collecting IGMP Rx stats */ + switch (query_version) { + case 1: + igmp->rx_stats.query_v1++; + break; + case 2: + igmp->rx_stats.query_v2++; + break; + case 3: + igmp->rx_stats.query_v3++; + break; + default: + igmp->rx_stats.unsupported++; + } + /* * RFC 3376 defines some guidelines on operating in backwards * compatibility with older versions of IGMP but there are some gaps in @@ -400,6 +415,9 @@ static int igmp_v1_recv_report(struct igmp_sock *igmp, struct in_addr from, return -1; } + /* Collecting IGMP Rx stats */ + igmp->rx_stats.report_v1++; + if (PIM_DEBUG_IGMP_TRACE) { zlog_warn("%s %s: FIXME WRITEME", __FILE__, __PRETTY_FUNCTION__); @@ -524,6 +542,9 @@ int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len) zlog_warn("Ignoring unsupported IGMP message type: %d", msg_type); + /* Collecting IGMP Rx stats */ + igmp->rx_stats.unsupported++; + return -1; } @@ -867,6 +888,8 @@ static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr, pim_ifp->igmp_default_robustness_variable; igmp->sock_creation = pim_time_monotonic_sec(); + igmp_stats_init(&igmp->rx_stats); + if (mtrace_only) { igmp->mtrace_only = mtrace_only; return igmp; diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h index 561a127d0f..c8b880ddd7 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -25,6 +25,7 @@ #include <zebra.h> #include "vty.h" #include "linklist.h" +#include "pim_igmp_stats.h" /* The following sizes are likely to support @@ -94,6 +95,8 @@ struct igmp_sock { struct list *igmp_group_list; /* list of struct igmp_group */ struct hash *igmp_group_hash; + + struct igmp_stats rx_stats; }; struct igmp_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list, diff --git a/pimd/pim_igmp_mtrace.c b/pimd/pim_igmp_mtrace.c index d3ae185709..673e2ca5b8 100644 --- a/pimd/pim_igmp_mtrace.c +++ b/pimd/pim_igmp_mtrace.c @@ -671,6 +671,9 @@ int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr, return -1; } + /* Collecting IGMP Rx stats */ + igmp->rx_stats.mtrace_req++; + if (PIM_DEBUG_MTRACE) mtrace_debug(pim_ifp, mtracep, igmp_msg_len); @@ -881,6 +884,9 @@ int igmp_mtrace_recv_response(struct igmp_sock *igmp, struct ip *ip_hdr, mtracep->checksum = checksum; + /* Collecting IGMP Rx stats */ + igmp->rx_stats.mtrace_rsp++; + if (PIM_DEBUG_MTRACE) mtrace_debug(pim_ifp, mtracep, igmp_msg_len); diff --git a/pimd/pim_igmp_stats.c b/pimd/pim_igmp_stats.c new file mode 100644 index 0000000000..428816e1f0 --- /dev/null +++ b/pimd/pim_igmp_stats.c @@ -0,0 +1,42 @@ +/* + * PIM for FRRouting + * Copyright (C) 2018 Mladen Sablic + * + * 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 "pim_igmp_stats.h" + +void igmp_stats_init(struct igmp_stats *stats) +{ + memset(stats, 0, sizeof(struct igmp_stats)); +} + +void igmp_stats_add(struct igmp_stats *a, struct igmp_stats *b) +{ + if (!a || !b) + return; + + a->query_v1 += b->query_v1; + a->query_v2 += b->query_v2; + a->query_v3 += b->query_v3; + a->report_v1 += b->report_v1; + a->report_v2 += b->report_v2; + a->report_v3 += b->report_v3; + a->leave_v2 += b->leave_v2; + a->mtrace_rsp += b->mtrace_rsp; + a->mtrace_req += b->mtrace_req; + a->unsupported += b->unsupported; +} diff --git a/pimd/pim_igmp_stats.h b/pimd/pim_igmp_stats.h new file mode 100644 index 0000000000..57b5cc62f4 --- /dev/null +++ b/pimd/pim_igmp_stats.h @@ -0,0 +1,41 @@ +/* + * PIM for FRRouting + * Copyright (C) 2018 Mladen Sablic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PIM_IGMP_STATS_H +#define PIM_IGMP_STATS_H + +#include <zebra.h> + +struct igmp_stats { + uint32_t query_v1; + uint32_t query_v2; + uint32_t query_v3; + uint32_t report_v1; + uint32_t report_v2; + uint32_t report_v3; + uint32_t leave_v2; + uint32_t mtrace_rsp; + uint32_t mtrace_req; + uint32_t unsupported; +}; + +void igmp_stats_init(struct igmp_stats *stats); +void igmp_stats_add(struct igmp_stats *a, struct igmp_stats *b); + +#endif /* PIM_IGMP_STATS_H */ diff --git a/pimd/pim_igmpv2.c b/pimd/pim_igmpv2.c index dbbe83a965..19c3768813 100644 --- a/pimd/pim_igmpv2.c +++ b/pimd/pim_igmpv2.c @@ -121,6 +121,9 @@ int igmp_v2_recv_report(struct igmp_sock *igmp, struct in_addr from, return -1; } + /* Collecting IGMP Rx stats */ + igmp->rx_stats.report_v2++; + memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); if (PIM_DEBUG_IGMP_PACKETS) { @@ -167,6 +170,9 @@ int igmp_v2_recv_leave(struct igmp_sock *igmp, struct in_addr from, return -1; } + /* Collecting IGMP Rx stats */ + igmp->rx_stats.leave_v2++; + memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); if (PIM_DEBUG_IGMP_PACKETS) { diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 3360e36b4a..5ccad39b33 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -1900,6 +1900,9 @@ int igmp_v3_recv_report(struct igmp_sock *igmp, struct in_addr from, return -1; } + /* Collecting IGMP Rx stats */ + igmp->rx_stats.report_v3++; + num_groups = ntohs( *(uint16_t *)(igmp_msg + IGMP_V3_REPORT_NUMGROUPS_OFFSET)); if (num_groups < 1) { diff --git a/pimd/subdir.am b/pimd/subdir.am index 2254362221..0696d9b1e8 100644 --- a/pimd/subdir.am +++ b/pimd/subdir.am @@ -20,6 +20,7 @@ pimd_libpim_a_SOURCES = \ pimd/pim_ifchannel.c \ pimd/pim_igmp.c \ pimd/pim_igmp_mtrace.c \ + pimd/pim_igmp_stats.c \ pimd/pim_igmpv2.c \ pimd/pim_igmpv3.c \ pimd/pim_instance.c \ @@ -69,6 +70,7 @@ noinst_HEADERS += \ pimd/pim_igmp.h \ pimd/pim_igmp_join.h \ pimd/pim_igmp_mtrace.h \ + pimd/pim_igmp_stats.h \ pimd/pim_igmpv2.h \ pimd/pim_igmpv3.h \ pimd/pim_instance.h \ diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index f83c08e611..8632a4fb2f 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -534,7 +534,7 @@ rm -rf %{buildroot} %defattr(-,root,root) %doc */*.sample* AUTHORS COPYING %doc doc/mpls -%doc ChangeLog INSTALL NEWS README REPORTING-BUGS SERVICES +%doc ChangeLog NEWS README SERVICES %if 0%{?frr_user:1} %dir %attr(751,%frr_user,%frr_user) %{_sysconfdir} %dir %attr(750,%frr_user,%frr_user) /var/log/frr diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c index 9e0cb1f5ca..8db1cb2ca1 100644 --- a/tests/bgpd/test_mp_attr.c +++ b/tests/bgpd/test_mp_attr.c @@ -945,6 +945,24 @@ static struct test_segment mp_unreach_segments[] = { }, {NULL, NULL, {0}, 0, 0}}; +static struct test_segment mp_prefix_sid[] = { + { + "PREFIX-SID", + "PREFIX-SID Test 1", + { + 0x01, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, + 0x03, 0x00, 0x08, 0x00, + 0x00, 0x0a, 0x1b, 0xfe, + 0x00, 0x00, 0x0a + }, + .len = 21, + .parses = SHOULD_PARSE, + }, + {NULL, NULL, { 0 }, 0, 0}, +}; + /* nlri_parse indicates 0 on successful parse, and -1 otherwise. * attr_parse indicates BGP_ATTR_PARSE_PROCEED/0 on success, * and BGP_ATTR_PARSE_ERROR/-1 or lower negative ret on err. @@ -1000,10 +1018,20 @@ static void parse_test(struct peer *peer, struct test_segment *t, int type) printf("%s: %s\n", t->name, t->desc); - if (type == BGP_ATTR_MP_REACH_NLRI) + switch (type) { + case BGP_ATTR_MP_REACH_NLRI: parse_ret = bgp_mp_reach_parse(&attr_args, &nlri); - else + break; + case BGP_ATTR_MP_UNREACH_NLRI: parse_ret = bgp_mp_unreach_parse(&attr_args, &nlri); + break; + case BGP_ATTR_PREFIX_SID: + parse_ret = bgp_attr_prefix_sid(t->len, &attr_args, &nlri); + break; + default: + printf("unknown type"); + return; + } if (!parse_ret) { iana_afi_t pkt_afi; iana_safi_t pkt_safi; @@ -1022,7 +1050,7 @@ static void parse_test(struct peer *peer, struct test_segment *t, int type) if (!parse_ret) { if (type == BGP_ATTR_MP_REACH_NLRI) nlri_ret = bgp_nlri_parse(peer, &attr, &nlri, 0); - else + else if (type == BGP_ATTR_MP_UNREACH_NLRI) nlri_ret = bgp_nlri_parse(peer, &attr, &nlri, 1); } handle_result(peer, t, parse_ret, nlri_ret); @@ -1085,6 +1113,10 @@ int main(void) parse_test(peer, &mp_unreach_segments[i++], BGP_ATTR_MP_UNREACH_NLRI); + i = 0; + while (mp_prefix_sid[i].name) + parse_test(peer, &mp_prefix_sid[i++], + BGP_ATTR_PREFIX_SID); printf("failures: %d\n", failed); return failed; } diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 867dc9cd15..01ba007767 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1537,7 +1537,7 @@ DEFUNSH(VTYSH_RMAP, vtysh_route_map, vtysh_route_map_cmd, } DEFUNSH(VTYSH_PBRD, vtysh_pbr_map, vtysh_pbr_map_cmd, - "pbr-map NAME seq (1-1000)", + "pbr-map NAME seq (1-700)", "Create pbr-map or enter pbr-map command mode\n" "The name of the PBR MAP\n" "Sequence to insert to/delete from existing pbr-map entry\n" @@ -1547,7 +1547,7 @@ DEFUNSH(VTYSH_PBRD, vtysh_pbr_map, vtysh_pbr_map_cmd, return CMD_SUCCESS; } -DEFSH(VTYSH_PBRD, vtysh_no_pbr_map_cmd, "no pbr-map WORD [seq (1-65535)]", +DEFSH(VTYSH_PBRD, vtysh_no_pbr_map_cmd, "no pbr-map WORD [seq (1-700)]", NO_STR "Delete pbr-map\n" "The name of the PBR MAP\n" @@ -2361,13 +2361,20 @@ DEFUNSH(VTYSH_ALL, no_vtysh_service_password_encrypt, DEFUNSH(VTYSH_ALL, vtysh_config_password, vtysh_password_cmd, "password [(8-8)] LINE", - "Assign the terminal connection password\n" + "Modify the terminal connection password\n" "Specifies a HIDDEN password will follow\n" "The password string\n") { return CMD_SUCCESS; } +DEFUNSH(VTYSH_ALL, no_vtysh_config_password, no_vtysh_password_cmd, + "no password", NO_STR + "Modify the terminal connection password\n") +{ + return CMD_SUCCESS; +} + DEFUNSH(VTYSH_ALL, vtysh_config_enable_password, vtysh_enable_password_cmd, "enable password [(8-8)] LINE", "Modify enable password parameters\n" @@ -3605,6 +3612,7 @@ void vtysh_init_vty(void) install_element(CONFIG_NODE, &no_vtysh_service_password_encrypt_cmd); install_element(CONFIG_NODE, &vtysh_password_cmd); + install_element(CONFIG_NODE, &no_vtysh_password_cmd); install_element(CONFIG_NODE, &vtysh_enable_password_cmd); install_element(CONFIG_NODE, &no_vtysh_enable_password_cmd); } diff --git a/zebra/connected.c b/zebra/connected.c index 23f2f666a0..a9a4dfe08f 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -403,10 +403,10 @@ void connected_down(struct interface *ifp, struct connected *ifc) * head. */ rib_delete(afi, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, - &p, NULL, &nh, 0, 0, false, NULL); + &p, NULL, &nh, 0, 0, false); rib_delete(afi, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, - &p, NULL, &nh, 0, 0, false, NULL); + &p, NULL, &nh, 0, 0, false); if (IS_ZEBRA_DEBUG_RIB_DETAILED) { char buf[PREFIX_STRLEN]; diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index e28c189f86..7423e9237f 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1025,7 +1025,7 @@ static void if_netlink_check_ifp_instance_consistency(uint16_t cmd, struct interface *ifp, ns_id_t ns_id) { - struct interface *old_ifp; + struct interface *other_ifp; /* * look if interface name is also found on other netns @@ -1037,29 +1037,42 @@ static void if_netlink_check_ifp_instance_consistency(uint16_t cmd, if (!vrf_is_backend_netns() || !strcmp(ifp->name, "lo")) return; - old_ifp = if_lookup_by_name_not_ns(ns_id, ifp->name); - if (!old_ifp) + other_ifp = if_lookup_by_name_not_ns(ns_id, ifp->name); + if (!other_ifp) + return; + /* because previous interface may be inactive, + * interface is moved back to default vrf + * then one may find the same pointer; ignore + */ + if (other_ifp == ifp) return; if ((cmd == RTM_NEWLINK) - && (CHECK_FLAG(old_ifp->status, ZEBRA_INTERFACE_ACTIVE))) + && (CHECK_FLAG(other_ifp->status, ZEBRA_INTERFACE_ACTIVE))) return; - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("%s %s(%u) %s VRF %u", - cmd == RTM_DELLINK ? - "RTM_DELLINK replaced by" : - "RTM_NEWLINK replaces", + if (IS_ZEBRA_DEBUG_KERNEL && cmd == RTM_NEWLINK) { + zlog_debug("RTM_NEWLINK %s(%u, VRF %u) replaces %s(%u, VRF %u)\n", ifp->name, - old_ifp->ifindex, - cmd == RTM_DELLINK ? - "in" : "from", - old_ifp->vrf_id); + ifp->ifindex, + ifp->vrf_id, + other_ifp->name, + other_ifp->ifindex, + other_ifp->vrf_id); + } else if (IS_ZEBRA_DEBUG_KERNEL && cmd == RTM_DELLINK) { + zlog_debug("RTM_DELLINK %s(%u, VRF %u) is replaced by %s(%u, VRF %u)\n", + ifp->name, + ifp->ifindex, + ifp->vrf_id, + other_ifp->name, + other_ifp->ifindex, + other_ifp->vrf_id); + } /* the found interface replaces the current one * remove it */ if (cmd == RTM_DELLINK) if_delete(ifp); else - if_delete(old_ifp); + if_delete(other_ifp); /* the found interface is replaced by the current one * suppress it */ diff --git a/zebra/interface.c b/zebra/interface.c index 6f59a2d399..7de18d683c 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -202,6 +202,7 @@ struct interface *if_link_per_ns(struct zebra_ns *ns, struct interface *ifp) if (rn->info) { ifp = (struct interface *)rn->info; route_unlock_node(rn); /* get */ + ifp->node = rn; return ifp; } @@ -725,6 +726,9 @@ void if_delete_update(struct interface *ifp) return; } + if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) + return; + /* Mark interface as inactive */ UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE); @@ -1224,8 +1228,13 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) br_slave->bridge_ifindex); } - if (zebra_if->link_ifindex != IFINDEX_INTERNAL) - vty_out(vty, " Link ifindex %u\n", zebra_if->link_ifindex); + if (zebra_if->link_ifindex != IFINDEX_INTERNAL) { + vty_out(vty, " Link ifindex %u", zebra_if->link_ifindex); + if (zebra_if->link) + vty_out(vty, "(%s)\n", zebra_if->link->name); + else + vty_out(vty, "(Unknown)\n"); + } if (HAS_LINK_PARAMS(ifp)) { int i; diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index db4f19460a..6b587dab38 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -463,7 +463,7 @@ int netlink_parse_info(int (*filter)(struct sockaddr_nl *, struct nlmsghdr *, int read_in = 0; while (1) { - char buf[NL_PKT_BUF_SIZE]; + char buf[NL_RCV_PKT_BUF_SIZE]; struct iovec iov = {.iov_base = buf, .iov_len = sizeof buf}; struct sockaddr_nl snl; struct msghdr msg = {.msg_name = (void *)&snl, diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index 8441eeac76..dc075b9aff 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -23,6 +23,7 @@ #ifdef HAVE_NETLINK +#define NL_RCV_PKT_BUF_SIZE 32768 #define NL_PKT_BUF_SIZE 8192 extern void netlink_parse_rtattr(struct rtattr **tb, int max, diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index e60e05bcdf..b85c4748c4 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1043,7 +1043,7 @@ void rtm_read(struct rt_msghdr *rtm) if (rtm->rtm_type == RTM_CHANGE) rib_delete(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - NULL, 0, 0, true, NULL); + NULL, 0, 0, true); if (!nh.type) { nh.type = NEXTHOP_TYPE_IPV4; @@ -1058,7 +1058,7 @@ void rtm_read(struct rt_msghdr *rtm) else rib_delete(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - &nh, 0, 0, true, NULL); + &nh, 0, 0, true); } if (dest.sa.sa_family == AF_INET6) { /* One day we might have a debug section here like one in the @@ -1089,7 +1089,7 @@ void rtm_read(struct rt_msghdr *rtm) if (rtm->rtm_type == RTM_CHANGE) rib_delete(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - NULL, 0, 0, true, NULL); + NULL, 0, 0, true); if (!nh.type) { nh.type = ifindex ? NEXTHOP_TYPE_IPV6_IFINDEX @@ -1106,7 +1106,7 @@ void rtm_read(struct rt_msghdr *rtm) else rib_delete(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - &nh, 0, 0, true, NULL); + &nh, 0, 0, true); } } diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 810ee33839..5a6565aec9 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -592,7 +592,7 @@ int zebra_del_import_table_entry(struct route_node *rn, struct route_entry *re) rib_delete(afi, SAFI_UNICAST, re->vrf_id, ZEBRA_ROUTE_TABLE, re->table, re->flags, &p, NULL, re->ng.nexthop, - zebrad.rtm_table_default, re->metric, false, NULL); + zebrad.rtm_table_default, re->metric, false); return 0; } diff --git a/zebra/rib.h b/zebra/rib.h index d68bf787c0..7b9e6d56a7 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -313,8 +313,7 @@ extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, unsigned short instance, int flags, struct prefix *p, struct prefix_ipv6 *src_p, const struct nexthop *nh, - uint32_t table_id, uint32_t metric, bool fromkernel, - struct ethaddr *rmac); + uint32_t table_id, uint32_t metric, bool fromkernel); extern struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id, union g_addr *addr, diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index a35dc9a177..9510a0e12c 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -613,12 +613,12 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl, if (gate) memcpy(&nh.gate, gate, sz); rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, - &p, NULL, &nh, table, metric, true, NULL); + &p, NULL, &nh, table, metric, true); } else { /* XXX: need to compare the entire list of nexthops * here for NLM_F_APPEND stupidity */ rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, - &p, NULL, NULL, table, metric, true, NULL); + &p, NULL, NULL, table, metric, true); } } @@ -1233,14 +1233,6 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, "netlink_route_multipath() (%s): " "nexthop via if %u", routedesc, nexthop->ifindex); - } else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "netlink_route_multipath() (%s): " - "nexthop via if %u", - routedesc, nexthop->ifindex); - } else { - rtnh->rtnh_ifindex = 0; } } diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 2ff660b3f9..6bd12391db 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1382,7 +1382,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) &(api_nh->gate.ipv4), sizeof(struct in_addr)); zebra_vxlan_evpn_vrf_route_add( - vrf_id, &api.rmac, &vtep_ip, + vrf_id, &api_nh->rmac, &vtep_ip, &api.prefix); } break; @@ -1415,7 +1415,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) &(api_nh->gate.ipv6), sizeof(struct in6_addr)); zebra_vxlan_evpn_vrf_route_add( - vrf_id, &api.rmac, &vtep_ip, + vrf_id, &api_nh->rmac, &vtep_ip, &api.prefix); } break; @@ -1522,7 +1522,7 @@ static void zread_route_del(ZAPI_HANDLER_ARGS) rib_delete(afi, api.safi, zvrf_id(zvrf), api.type, api.instance, api.flags, &api.prefix, src_p, NULL, table_id, api.metric, - false, &api.rmac); + false); /* Stats */ switch (api.prefix.family) { @@ -1724,7 +1724,7 @@ static void zread_ipv4_delete(ZAPI_HANDLER_ARGS) table_id = zvrf->table_id; rib_delete(AFI_IP, api.safi, zvrf_id(zvrf), api.type, api.instance, - api.flags, &p, NULL, NULL, table_id, 0, false, NULL); + api.flags, &p, NULL, NULL, table_id, 0, false); client->v4_route_del_cnt++; stream_failure: @@ -2148,8 +2148,7 @@ static void zread_ipv6_delete(ZAPI_HANDLER_ARGS) src_pp = NULL; rib_delete(AFI_IP6, api.safi, zvrf_id(zvrf), api.type, api.instance, - api.flags, &p, src_pp, NULL, client->rtm_table, 0, false, - NULL); + api.flags, &p, src_pp, NULL, client->rtm_table, 0, false); client->v6_route_del_cnt++; diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index 07e81aa020..d20f93f521 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -298,6 +298,9 @@ DEFUN (zebra_ptm_enable_if, int old_ptm_enable; int send_linkdown = 0; + if_data = ifp->info; + if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC; + if (ifp->ifindex == IFINDEX_INTERNAL) { return CMD_SUCCESS; } @@ -317,9 +320,6 @@ DEFUN (zebra_ptm_enable_if, } } - if_data = ifp->info; - if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC; - return CMD_SUCCESS; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 67832f2d3f..7ec640164a 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2394,8 +2394,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, unsigned short instance, int flags, struct prefix *p, struct prefix_ipv6 *src_p, const struct nexthop *nh, - uint32_t table_id, uint32_t metric, bool fromkernel, - struct ethaddr *rmac) + uint32_t table_id, uint32_t metric, bool fromkernel) { struct route_table *table; struct route_node *rn; @@ -2569,7 +2568,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, &(tmp_nh->gate.ipv6), sizeof(struct in6_addr)); } - zebra_vxlan_evpn_vrf_route_del(re->vrf_id, rmac, + zebra_vxlan_evpn_vrf_route_del(re->vrf_id, &vtep_ip, p); } } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 2ae9ac5082..e6f80f92a7 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -2798,12 +2798,14 @@ DEFUN (vrf_vni_mapping, DEFUN (no_vrf_vni_mapping, no_vrf_vni_mapping_cmd, - "no vni " CMD_VNI_RANGE, + "no vni " CMD_VNI_RANGE "[prefix-routes-only]", NO_STR "VNI corresponding to tenant VRF\n" - "VNI-ID") + "VNI-ID\n" + "prefix-routes-only\n") { int ret = 0; + int filter = 0; char err[ERR_STR_SZ]; vni_t vni = strtoul(argv[2]->arg, NULL, 10); @@ -2812,7 +2814,11 @@ DEFUN (no_vrf_vni_mapping, assert(vrf); assert(zvrf); - ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0, 0); + if (argc == 4) + filter = 1; + + ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, + ERR_STR_SZ, filter, 0); if (ret != 0) { vty_out(vty, "%s\n", err); return CMD_WARNING; diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 6e901a0457..3278c86b99 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3238,15 +3238,9 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac, /* handle rmac delete */ -static int zl3vni_remote_rmac_del(zebra_l3vni_t *zl3vni, struct ethaddr *rmac, +static void zl3vni_remote_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac, struct prefix *host_prefix) { - zebra_mac_t *zrmac = NULL; - - zrmac = zl3vni_rmac_lookup(zl3vni, rmac); - if (!zrmac) - return -1; - host_list_delete_host(zrmac->host_list, host_prefix); if (list_isempty(zrmac->host_list)) { @@ -3256,7 +3250,6 @@ static int zl3vni_remote_rmac_del(zebra_l3vni_t *zl3vni, struct ethaddr *rmac, /* del the rmac entry */ zl3vni_rmac_del(zl3vni, zrmac); } - return 0; } /* @@ -3394,15 +3387,9 @@ static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *vtep_ip, } /* handle nh neigh delete */ -static int zl3vni_remote_nh_del(zebra_l3vni_t *zl3vni, struct ipaddr *vtep_ip, - struct prefix *host_prefix) +static void zl3vni_remote_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *nh, + struct prefix *host_prefix) { - zebra_neigh_t *nh = NULL; - - nh = zl3vni_nh_lookup(zl3vni, vtep_ip); - if (!nh) - return -1; - host_list_delete_host(nh->host_list, host_prefix); if (list_isempty(nh->host_list)) { @@ -3412,8 +3399,6 @@ static int zl3vni_remote_nh_del(zebra_l3vni_t *zl3vni, struct ipaddr *vtep_ip, /* delete the nh entry */ zl3vni_nh_del(zl3vni, nh); } - - return 0; } /* handle neigh update from kernel - the only thing of interest is to @@ -3958,34 +3943,65 @@ void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, struct ethaddr *rmac, struct prefix *host_prefix) { zebra_l3vni_t *zl3vni = NULL; + struct ipaddr ipv4_vtep; zl3vni = zl3vni_from_vrf(vrf_id); if (!zl3vni || !is_l3vni_oper_up(zl3vni)) return; - /* add the next hop neighbor */ + /* + * add the next hop neighbor - + * neigh to be installed is the ipv6 nexthop neigh + */ zl3vni_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix); - /* add the rmac */ - zl3vni_remote_rmac_add(zl3vni, rmac, vtep_ip, host_prefix); + /* + * if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4 + * address. Rmac is programmed against the ipv4 vtep because we only + * support ipv4 tunnels in the h/w right now + */ + memset(&ipv4_vtep, 0, sizeof(struct ipaddr)); + ipv4_vtep.ipa_type = IPADDR_V4; + if (vtep_ip->ipa_type == IPADDR_V6) + ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, + &(ipv4_vtep.ipaddr_v4)); + else + memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4, + sizeof(struct in_addr)); + + /* + * add the rmac - remote rmac to be installed is against the ipv4 + * nexthop address + */ + zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep, host_prefix); } /* handle evpn vrf route delete */ -void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id, struct ethaddr *rmac, +void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id, struct ipaddr *vtep_ip, struct prefix *host_prefix) { zebra_l3vni_t *zl3vni = NULL; + zebra_neigh_t *nh = NULL; + zebra_mac_t *zrmac = NULL; zl3vni = zl3vni_from_vrf(vrf_id); if (!zl3vni) return; + /* find the next hop entry and rmac entry */ + nh = zl3vni_nh_lookup(zl3vni, vtep_ip); + if (!nh) + return; + zrmac = zl3vni_rmac_lookup(zl3vni, &nh->emac); + /* delete the next hop entry */ - zl3vni_remote_nh_del(zl3vni, vtep_ip, host_prefix); + zl3vni_remote_nh_del(zl3vni, nh, host_prefix); /* delete the rmac entry */ - zl3vni_remote_rmac_del(zl3vni, rmac, host_prefix); + if (zrmac) + zl3vni_remote_rmac_del(zl3vni, zrmac, host_prefix); + } void zebra_vxlan_print_specific_rmac_l3vni(struct vty *vty, vni_t l3vni, @@ -5143,7 +5159,7 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS) l += IPV4_MAX_BYTELEN; /* Get flags - sticky mac and/or gateway mac */ - flags = stream_getc(s); + STREAM_GETC(s, flags); sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); l++; @@ -6516,6 +6532,12 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, return -1; } + if (filter && !CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY)) { + snprintf(err, ERR_STR_SZ, + "prefix-routes-only is not set for the vni"); + return -1; + } + zebra_vxlan_process_l3vni_oper_down(zl3vni); /* delete and uninstall all rmacs */ @@ -6602,7 +6624,7 @@ void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS) } s = msg; - advertise = stream_getc(s); + STREAM_GETC(s, advertise); vni = stream_get3(s); zvni = zvni_lookup(vni); @@ -6641,6 +6663,9 @@ void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS) zvni_advertise_subnet(zvni, vlan_if, 1); else zvni_advertise_subnet(zvni, vlan_if, 0); + +stream_failure: + return; } /* @@ -6663,7 +6688,7 @@ void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS) s = msg; STREAM_GETC(s, advertise); - STREAM_GET(&vni, s, 3); + STREAM_GETL(s, vni); if (!vni) { if (IS_ZEBRA_DEBUG_VXLAN) diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index 6153c7d7e3..34d1152751 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -160,7 +160,6 @@ extern void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, struct ipaddr *ip, struct prefix *host_prefix); extern void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id, - struct ethaddr *rmac, struct ipaddr *vtep_ip, struct prefix *host_prefix); |
