summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COMMUNITY.md1
-rw-r--r--Makefile.am1
-rw-r--r--README4
-rwxr-xr-xREADME.NetBSD46
-rw-r--r--REPORTING-BUGS35
-rw-r--r--bgpd/bgp_attr.c85
-rw-r--r--bgpd/bgp_attr.h3
-rw-r--r--bgpd/bgp_attr_evpn.c14
-rw-r--r--bgpd/bgp_evpn.c180
-rw-r--r--bgpd/bgp_evpn_private.h48
-rw-r--r--bgpd/bgp_evpn_vty.c53
-rw-r--r--bgpd/bgp_route.c62
-rw-r--r--bgpd/bgp_routemap.c2
-rw-r--r--bgpd/bgp_snmp.c42
-rw-r--r--bgpd/bgp_updgrp_packet.c3
-rw-r--r--bgpd/bgp_vty.c26
-rw-r--r--bgpd/bgp_zebra.c24
-rw-r--r--bgpd/bgpd.c154
-rw-r--r--bgpd/bgpd.h23
-rwxr-xr-xconfigure.ac9
-rw-r--r--debianpkg/backports/ubuntu14.04/debian/frr.postinst2
-rw-r--r--debianpkg/frr-doc.docs1
-rw-r--r--debianpkg/frr.postinst2
-rw-r--r--doc/Makefile.am2
-rw-r--r--doc/developer/.gitignore2
-rw-r--r--doc/developer/Makefile1
-rw-r--r--doc/developer/Makefile.in8
-rw-r--r--doc/developer/conf.py10
-rw-r--r--doc/developer/index.rst4
-rw-r--r--doc/developer/library.rst2
-rw-r--r--doc/developer/process-architecture.rst54
-rw-r--r--doc/figures/threadmaster-multiple.pngbin0 -> 62628 bytes
-rw-r--r--doc/figures/threadmaster-single.pngbin0 -> 26152 bytes
-rw-r--r--doc/frr-sphinx.mk9
-rw-r--r--doc/manpages/.gitignore2
-rw-r--r--doc/manpages/Makefile.in (renamed from doc/manpages/Makefile)9
-rw-r--r--doc/manpages/index.rst3
-rw-r--r--doc/user/.gitignore2
-rw-r--r--doc/user/Makefile.in (renamed from doc/user/Makefile)9
-rw-r--r--doc/user/basic.rst19
-rw-r--r--doc/user/bugs.rst67
-rw-r--r--doc/user/conf.py10
-rw-r--r--doc/user/index.rst5
-rw-r--r--doc/user/installation.rst13
-rw-r--r--doc/user/ospf6d.rst2
-rw-r--r--doc/user/pbr.rst2
-rw-r--r--doc/user/snmp.rst9
-rw-r--r--doc/user/zebra.rst152
-rw-r--r--isisd/isis_redist.c14
-rw-r--r--lib/command.c228
-rw-r--r--lib/command.h2
-rw-r--r--lib/ipaddr.h10
-rw-r--r--lib/prefix.c128
-rw-r--r--lib/prefix.h91
-rw-r--r--lib/zclient.c14
-rw-r--r--lib/zclient.h4
-rw-r--r--ospf6d/ospf6_abr.c74
-rw-r--r--ospf6d/ospf6_area.h3
-rw-r--r--ospf6d/ospf6_intra.c33
-rw-r--r--ospf6d/ospf6_route.c5
-rw-r--r--ospf6d/ospf6_top.c11
-rw-r--r--ospf6d/ospf6d.c2
-rw-r--r--pbrd/pbr_vty.c4
-rw-r--r--pbrd/pbr_zebra.c1
-rw-r--r--pimd/COMMANDS1
-rw-r--r--pimd/pim_cmd.c98
-rw-r--r--pimd/pim_igmp.c23
-rw-r--r--pimd/pim_igmp.h3
-rw-r--r--pimd/pim_igmp_mtrace.c6
-rw-r--r--pimd/pim_igmp_stats.c42
-rw-r--r--pimd/pim_igmp_stats.h41
-rw-r--r--pimd/pim_igmpv2.c6
-rw-r--r--pimd/pim_igmpv3.c3
-rw-r--r--pimd/subdir.am2
-rw-r--r--redhat/frr.spec.in2
-rw-r--r--tests/bgpd/test_mp_attr.c38
-rw-r--r--vtysh/vtysh.c14
-rw-r--r--zebra/connected.c4
-rw-r--r--zebra/if_netlink.c41
-rw-r--r--zebra/interface.c13
-rw-r--r--zebra/kernel_netlink.c2
-rw-r--r--zebra/kernel_netlink.h1
-rw-r--r--zebra/kernel_socket.c8
-rw-r--r--zebra/redistribute.c2
-rw-r--r--zebra/rib.h3
-rw-r--r--zebra/rt_netlink.c12
-rw-r--r--zebra/zapi_msg.c11
-rw-r--r--zebra/zebra_ptm.c6
-rw-r--r--zebra/zebra_rib.c5
-rw-r--r--zebra/zebra_vty.c12
-rw-r--r--zebra/zebra_vxlan.c79
-rw-r--r--zebra/zebra_vxlan.h1
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 \
diff --git a/README b/README
index af14795a6a..95ed0d3fc2 100644
--- a/README
+++ b/README
@@ -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(&eth_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(&eth_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(&eth_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
new file mode 100644
index 0000000000..2ded50c4cb
--- /dev/null
+++ b/doc/figures/threadmaster-multiple.png
Binary files differ
diff --git a/doc/figures/threadmaster-single.png b/doc/figures/threadmaster-single.png
new file mode 100644
index 0000000000..a068389b2a
--- /dev/null
+++ b/doc/figures/threadmaster-single.png
Binary files differ
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);