+++ /dev/null
-#!/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
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 */
/* 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 */
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 */
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.
*/
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);
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);
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;
}
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);
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)));
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);
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);
}
* 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;
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 {
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(
/* 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);
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(
/* 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);
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) {
/* 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)) {
/* Copy Ethernet Tag */
memcpy(ð_tag, pfx, 4);
- p.prefix.eth_tag = ntohl(eth_tag);
+ p.prefix.macip_addr.eth_tag = ntohl(eth_tag);
pfx += 4;
/* Get the MAC Addr len */
/* 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(
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;
/* Copy Ethernet Tag */
memcpy(ð_tag, pfx, 4);
- p.prefix.eth_tag = ntohl(eth_tag);
+ p.prefix.imet_addr.eth_tag = ntohl(eth_tag);
pfx += 4;
/* Get the IP. */
ipaddr_len = *pfx++;
if (ipaddr_len == IPV4_MAX_BITLEN) {
- p.prefix.ip.ipa_type = IPADDR_V4;
- memcpy(&p.prefix.ip.ip.addr, pfx, IPV4_MAX_BYTELEN);
+ p.prefix.imet_addr.ip.ipa_type = IPADDR_V4;
+ memcpy(&p.prefix.imet_addr.ip.ip.addr, pfx, IPV4_MAX_BYTELEN);
} else {
zlog_err(
"%u:%s - Rx EVPN Type-3 NLRI with unsupported IP address length %d",
/* Fetch Ethernet Tag. */
memcpy(ð_tag, pfx, 4);
- p.prefix.eth_tag = ntohl(eth_tag);
+ p.prefix.prefix_addr.eth_tag = ntohl(eth_tag);
pfx += 4;
/* Fetch IP prefix length. */
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;
/* 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 */
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);
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 {
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)",
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;
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 */
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:
/* 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;
}
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);
}
}
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)
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,
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,
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,
}
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";
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");
{
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;
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;
}
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];
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 */
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) {
json_object_int_add(
json,
"bgpTableVersion",
- 0);
+ tbl_ver);
json_object_string_add(
json,
"bgpLocalRouterId",
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,
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));
/* Overall header/legend displayed once. */
if (header) {
bgp_evpn_show_route_header(vty, bgp,
+ tbl_ver,
json);
header = 0;
}
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);
}
}
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))
}
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,
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
/* 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);
}
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) {
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");
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,
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));
}
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);
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
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;
}
{
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;
}
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
*/
{
struct bgp *bgp;
struct peer *peer;
- struct peer_group *group;
struct listnode *lnbgp, *lnpeer;
for (ALL_LIST_ELEMENTS_RO(bm->bgp, lnbgp, bgp)) {
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));
}
}
{.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);
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);
/* 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;
}
}
- 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) {
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) {
api_nh->label_num = 1;
api_nh->labels[0] = label;
}
+ memcpy(&api_nh->rmac, &(mpinfo->attr->rmac),
+ sizeof(struct ethaddr));
valid_nh_count++;
}
}
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;
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);
}
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. */
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
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;
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;
}
/* 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)
/* 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. */
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
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
##################################################
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
##################################################
.NOTPARALLEL:
SUBDIRS = manpages user
-AM_MAKEFLAGS = DESTDIR=${DESTDIR} infodir=${infodir} doczdir=${abs_srcdir}
+AM_MAKEFLAGS = DESTDIR=${DESTDIR} infodir=${infodir}
MANPAGE_BUILDDIR = manpages/_build/man
/_templates
/_build
-!/Makefile
+!/Makefile.in
+++ /dev/null
-include ../frr-sphinx.mk
--- /dev/null
+# 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
# 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
#
# 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']()
-Welcome to FRR's documentation!
-===============================
+FRRouting Developer's Guide
+===========================
.. toctree::
:maxdepth: 2
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)
# 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:
/_templates
/_build
-!/Makefile
+!/Makefile.in
+++ /dev/null
-include ../frr-sphinx.mk
-
-# -----------------------------------------------------------------------------
-# Automake requires that 3rd-party Makefiles recognize these targets.
-# -----------------------------------------------------------------------------
-# install
-# install-data
-# install-exec
-# uninstall
-# install-dvi
-# install-html
-# install-info
-# install-ps
-# install-pdf
-# installdirs
-# check
-# installcheck
-# mostlyclean
-# clean
-# distclean
-# maintainer-clean
-# dvi
-# pdf
-# ps
-# info
-# html
-# tags
-# ctags
-
-# ignore these targets
-EMPTY_AUTOMAKE_TARGETS = dvi pdf ps tags ctags distdir installdirs check installcheck install-dvi install-ps install-html install-pdf install-info install-exec
-.PHONY: $(EMPTY_AUTOMAKE_TARGETS)
-$(EMPTY_AUTOMAKE_TARGETS):
-
-# These targets are automatically generated by Sphinx but conflict with
-# implicitly defined Automake rules, so we manually override them to nothing.
-# The other option is deleting the Sphinx-generated rules, which suppresses the
-# warning but kinda screws up the symmetry between Makefiles.
-info: ;
-html: ;
-
-all: man
-
-install-data: man
-
-install: install-data
-
-mostlyclean distclean maintainer-clean: clean
--- /dev/null
+# 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.
+# -----------------------------------------------------------------------------
+# install
+# install-data
+# install-exec
+# uninstall
+# install-dvi
+# install-html
+# install-info
+# install-ps
+# install-pdf
+# installdirs
+# check
+# installcheck
+# mostlyclean
+# clean
+# distclean
+# maintainer-clean
+# dvi
+# pdf
+# ps
+# info
+# html
+# tags
+# ctags
+
+# ignore these targets
+EMPTY_AUTOMAKE_TARGETS = dvi pdf ps tags ctags distdir installdirs check installcheck install-dvi install-ps install-html install-pdf install-info install-exec
+.PHONY: $(EMPTY_AUTOMAKE_TARGETS)
+$(EMPTY_AUTOMAKE_TARGETS):
+
+# These targets are automatically generated by Sphinx but conflict with
+# implicitly defined Automake rules, so we manually override them to nothing.
+# The other option is deleting the Sphinx-generated rules, which suppresses the
+# warning but kinda screws up the symmetry between Makefiles.
+info: ;
+html: ;
+
+all: man
+
+install-data: man
+
+install: install-data
+
+mostlyclean distclean maintainer-clean: clean
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
/_templates
/_build
-!/Makefile
+!/Makefile.in
+++ /dev/null
-include ../frr-sphinx.mk
-
-# -----------------------------------------------------------------------------
-# Automake requires that 3rd-party Makefiles recognize these targets.
-# -----------------------------------------------------------------------------
-# install
-# install-data
-# install-exec
-# uninstall
-# install-dvi
-# install-html
-# install-info
-# install-ps
-# install-pdf
-# installdirs
-# check
-# installcheck
-# mostlyclean
-# clean
-# distclean
-# maintainer-clean
-# dvi
-# pdf
-# ps
-# info
-# html
-# tags
-# ctags
-
-# ignore these targets
-EMPTY_AUTOMAKE_TARGETS = dvi ps tags ctags distdir install-exec install-dvi install-ps installdirs check installcheck install-html install-pdf install-data install
-.PHONY: $(EMPTY_AUTOMAKE_TARGETS)
-$(EMPTY_AUTOMAKE_TARGETS):
-
-# When building 'all', the logic is that we want to make docs that are easily
-# readable by the person that just built them. Technically the reST source is
-# readable in its own right, but we'll also build info and html because those
-# offer sequentially better reading experiences. PDF is not built by default
-# because it takes quite a while.
-all: info
-
-# info and html already have built-in sphinx rules; pdf goes to latexpdf
-pdf: latexpdf
-
-# install user manual as info file
-install-info: info
- install -d ${DESTDIR}${infodir}
- gzip < _build/texinfo/frr.info > ${DESTDIR}${infodir}/frr.info.gz
- install-info _build/texinfo/frr.info ${DESTDIR}${infodir}/dir
-
-install-data: install-info
-
-install: install-data
-
-mostlyclean distclean maintainer-clean: clean
--- /dev/null
+# 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.
+# -----------------------------------------------------------------------------
+# install
+# install-data
+# install-exec
+# uninstall
+# install-dvi
+# install-html
+# install-info
+# install-ps
+# install-pdf
+# installdirs
+# check
+# installcheck
+# mostlyclean
+# clean
+# distclean
+# maintainer-clean
+# dvi
+# pdf
+# ps
+# info
+# html
+# tags
+# ctags
+
+# ignore these targets
+EMPTY_AUTOMAKE_TARGETS = dvi ps tags ctags distdir install-exec install-dvi install-ps installdirs check installcheck install-html install-pdf install-data install
+.PHONY: $(EMPTY_AUTOMAKE_TARGETS)
+$(EMPTY_AUTOMAKE_TARGETS):
+
+# When building 'all', the logic is that we want to make docs that are easily
+# readable by the person that just built them. Technically the reST source is
+# readable in its own right, but we'll also build info and html because those
+# offer sequentially better reading experiences. PDF is not built by default
+# because it takes quite a while.
+all: info
+
+# info and html already have built-in sphinx rules; pdf goes to latexpdf
+pdf: latexpdf
+
+# install user manual as info file
+install-info: info
+ install -d ${DESTDIR}${infodir}
+ gzip < _build/texinfo/frr.info > ${DESTDIR}${infodir}/frr.info.gz
+ install-info _build/texinfo/frr.info ${DESTDIR}${infodir}/dir
+
+install-data: install-info
+
+install: install-data
+
+mostlyclean distclean maintainer-clean: clean
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]
# 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
#
# 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']()
-Welcome to FRR's documentation!
-===============================
+FRRouting User Guide
+====================
.. toctree::
:maxdepth: 2
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
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
In each of the FRR daemons, ``agentx`` command will enable AgentX support.
:file:`/etc/snmp/snmpd.conf`:
+
+::
+
#
# example access restrictions setup
#
the below snmpd.conf as wrong access restrictions can be hard to debug.
:file:`/etc/snmp/snmpd.conf`:
+
+::
+
#
# example access restrictions setup
#
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
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:
.. clicmd:: interface IFNAME
+.. index:: interface IFNAME vrf VRF
+
+.. clicmd:: interface IFNAME vrf VRF
+
.. index:: shutdown
.. clicmd:: shutdown
.. _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
======================
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 =
int afi;
int type;
int level;
- unsigned long metric;
+ unsigned long metric = 0;
const char *routemap = NULL;
family = str2family(argv[idx_afi]->text);
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;
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);
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);
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);
"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,
"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,
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");
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")
{
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,
"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;
#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;
}
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]]",
"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;
}
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))
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);
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. */
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. */
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__ */
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;
}
break;
case AF_EVPN:
- prefixevpn2str(p, str, size);
+ prefixevpn2str((const struct prefix_evpn *)p, str, size);
break;
case AF_FLOWSPEC:
#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
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;
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);
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));
}
}
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);
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));
}
}
/* MPLS labels for BGP-LU or Segment Routing */
uint8_t label_num;
mpls_label_t labels[MPLS_MAX_LABELS];
+
+ struct ethaddr rmac;
};
/*
vrf_id_t vrf_id;
uint32_t tableid;
-
- struct ethaddr rmac;
};
/* Zebra IPv4 route message API. */
{
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};
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 =
} 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 =
}
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;
|| 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;
}
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
*/
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));
/* 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); */
/* Area type */
int no_summary;
+ /* Brouter traversal protection */
+ int intra_brouter_calc;
+
/* OSPF interface list */
struct list *if_list;
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;
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
* 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 {
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)
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)
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,
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)
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];
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;
#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"
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"
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)
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
}
}
+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)
{
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",
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);
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
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__);
zlog_warn("Ignoring unsupported IGMP message type: %d", msg_type);
+ /* Collecting IGMP Rx stats */
+ igmp->rx_stats.unsupported++;
+
return -1;
}
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;
#include <zebra.h>
#include "vty.h"
#include "linklist.h"
+#include "pim_igmp_stats.h"
/*
The following sizes are likely to support
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,
return -1;
}
+ /* Collecting IGMP Rx stats */
+ igmp->rx_stats.mtrace_req++;
+
if (PIM_DEBUG_MTRACE)
mtrace_debug(pim_ifp, mtracep, igmp_msg_len);
mtracep->checksum = checksum;
+ /* Collecting IGMP Rx stats */
+ igmp->rx_stats.mtrace_rsp++;
+
if (PIM_DEBUG_MTRACE)
mtrace_debug(pim_ifp, mtracep, igmp_msg_len);
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
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) {
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) {
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) {
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 \
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 \
},
{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.
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;
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);
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;
}
}
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"
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"
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"
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);
}
* 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];
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
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
*/
if (rn->info) {
ifp = (struct interface *)rn->info;
route_unlock_node(rn); /* get */
+ ifp->node = rn;
return ifp;
}
return;
}
+ if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE))
+ return;
+
/* Mark interface as inactive */
UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE);
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;
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,
#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,
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;
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
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
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);
}
}
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;
}
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,
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);
}
}
"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;
}
}
&(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;
&(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;
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) {
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:
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++;
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;
}
}
}
- if_data = ifp->info;
- if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC;
-
return CMD_SUCCESS;
}
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;
&(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);
}
}
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);
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;
/* 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)) {
/* del the rmac entry */
zl3vni_rmac_del(zl3vni, zrmac);
}
- return 0;
}
/*
}
/* 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)) {
/* delete the nh entry */
zl3vni_nh_del(zl3vni, nh);
}
-
- return 0;
}
/* handle neigh update from kernel - the only thing of interest is to
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,
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++;
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 */
}
s = msg;
- advertise = stream_getc(s);
+ STREAM_GETC(s, advertise);
vni = stream_get3(s);
zvni = zvni_lookup(vni);
zvni_advertise_subnet(zvni, vlan_if, 1);
else
zvni_advertise_subnet(zvni, vlan_if, 0);
+
+stream_failure:
+ return;
}
/*
s = msg;
STREAM_GETC(s, advertise);
- STREAM_GET(&vni, s, 3);
+ STREAM_GETL(s, vni);
if (!vni) {
if (IS_ZEBRA_DEBUG_VXLAN)
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);