summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfdd/bfd.c18
-rw-r--r--bfdd/bfd.h8
-rw-r--r--bfdd/bfd_packet.c415
-rw-r--r--bfdd/bfdd_cli.c11
-rw-r--r--bgpd/bgp_attr.c6
-rw-r--r--bgpd/bgp_conditional_adv.c20
-rw-r--r--bgpd/bgp_vty.c14
-rw-r--r--bgpd/bgpd.c16
-rw-r--r--bgpd/bgpd.h2
-rw-r--r--doc/user/basic.rst6
-rw-r--r--isisd/isis_spf.c31
-rw-r--r--lib/command.c26
-rw-r--r--lib/command.h4
-rw-r--r--lib/prefix.c18
-rw-r--r--lib/prefix.h20
-rw-r--r--lib/privs.c15
-rw-r--r--lib/typesafe.h3
-rw-r--r--ospfd/ospf_bfd.c10
-rw-r--r--pimd/pim6_cmd.c8
-rw-r--r--pimd/pim_cmd.c10
-rw-r--r--pimd/pim_igmp.c4
-rw-r--r--pimd/pim_instance.h2
-rw-r--r--pimd/pim_oil.h3
-rw-r--r--pimd/pim_vty.c11
-rw-r--r--tests/topotests/bfd_profiles_topo1/r1/ospfd.conf1
-rw-r--r--tests/topotests/bfd_vrf_topo1/r1/bfdd.conf4
-rw-r--r--tests/topotests/bfd_vrf_topo1/r1/peers.json2
-rw-r--r--tests/topotests/bfd_vrf_topo1/r2/bfdd.conf8
-rw-r--r--tests/topotests/bfd_vrf_topo1/r2/peers.json2
-rw-r--r--tests/topotests/bfd_vrf_topo1/r3/bfdd.conf4
-rw-r--r--tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py679
-rw-r--r--tests/topotests/bgp_ipv4_class_e_peer/__init__.py0
-rw-r--r--tests/topotests/bgp_ipv4_class_e_peer/r1/bgpd.conf12
-rw-r--r--tests/topotests/bgp_ipv4_class_e_peer/r1/zebra.conf11
-rw-r--r--tests/topotests/bgp_ipv4_class_e_peer/r2/bgpd.conf9
-rw-r--r--tests/topotests/bgp_ipv4_class_e_peer/r2/zebra.conf8
-rw-r--r--tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py127
-rw-r--r--tests/topotests/lib/common_config.py15
-rw-r--r--vtysh/vtysh.c17
-rw-r--r--vtysh/vtysh_config.c20
-rw-r--r--zebra/interface.c6
-rw-r--r--zebra/kernel_netlink.c50
-rw-r--r--zebra/kernel_socket.c11
-rw-r--r--zebra/main.c5
-rw-r--r--zebra/rt_netlink.c29
-rw-r--r--zebra/zebra_mpls.c9
-rw-r--r--zebra/zebra_nhg.c2
-rw-r--r--zebra/zebra_pbr.c3
-rw-r--r--zebra/zebra_rib.c96
-rw-r--r--zebra/zebra_router.c2
-rw-r--r--zebra/zebra_router.h3
-rw-r--r--zebra/zebra_vty.c10
-rw-r--r--zebra/zebra_vxlan.c3
53 files changed, 1421 insertions, 408 deletions
diff --git a/bfdd/bfd.c b/bfdd/bfd.c
index d52eeeddba..483beb1b17 100644
--- a/bfdd/bfd.c
+++ b/bfdd/bfd.c
@@ -454,7 +454,17 @@ void ptm_bfd_start_xmt_timer(struct bfd_session *bfd, bool is_echo)
static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd)
{
/* Send the scheduled echo packet */
- ptm_bfd_echo_snd(bfd);
+ /* if ipv4 use the new echo implementation that causes
+ * the packet to be looped in forwarding plane of peer
+ */
+ if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6) == 0)
+#ifdef BFD_LINUX
+ ptm_bfd_echo_fp_snd(bfd);
+#else
+ ptm_bfd_echo_snd(bfd);
+#endif
+ else
+ ptm_bfd_echo_snd(bfd);
/* Restart the timer for next time */
ptm_bfd_start_xmt_timer(bfd, true);
@@ -558,6 +568,12 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag)
state_list[bfd->ses_state].str,
get_diag_str(bfd->local_diag));
}
+
+ /* clear peer's mac address */
+ UNSET_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET);
+ memset(bfd->peer_hw_addr, 0, sizeof(bfd->peer_hw_addr));
+ /* reset local address ,it might has been be changed after bfd is up*/
+ memset(&bfd->local_address, 0, sizeof(bfd->local_address));
}
static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa,
diff --git a/bfdd/bfd.h b/bfdd/bfd.h
index 6aa9e00586..48a1e0bc31 100644
--- a/bfdd/bfd.h
+++ b/bfdd/bfd.h
@@ -168,9 +168,10 @@ enum bfd_session_flags {
* expires
*/
BFD_SESS_FLAG_SHUTDOWN = 1 << 7, /* disable BGP peer function */
- BFD_SESS_FLAG_CONFIG = 1 << 8, /* Session configured with bfd NB API */
- BFD_SESS_FLAG_CBIT = 1 << 9, /* CBIT is set */
+ BFD_SESS_FLAG_CONFIG = 1 << 8, /* Session configured with bfd NB API */
+ BFD_SESS_FLAG_CBIT = 1 << 9, /* CBIT is set */
BFD_SESS_FLAG_PASSIVE = 1 << 10, /* Passive mode */
+ BFD_SESS_FLAG_MAC_SET = 1 << 11, /* MAC of peer known */
};
/*
@@ -290,6 +291,8 @@ struct bfd_session {
struct peer_label *pl;
struct bfd_dplane_ctx *bdc;
+ struct sockaddr_any local_address;
+ uint8_t peer_hw_addr[ETH_ALEN];
struct interface *ifp;
struct vrf *vrf;
@@ -554,6 +557,7 @@ int bp_echov6_socket(const struct vrf *vrf);
void ptm_bfd_snd(struct bfd_session *bfd, int fbit);
void ptm_bfd_echo_snd(struct bfd_session *bfd);
+void ptm_bfd_echo_fp_snd(struct bfd_session *bfd);
void bfd_recv_cb(struct thread *t);
diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c
index c717a333a6..6b0afef65f 100644
--- a/bfdd/bfd_packet.c
+++ b/bfdd/bfd_packet.c
@@ -34,6 +34,8 @@
#include <netinet/udp.h>
#include "lib/sockopt.h"
+#include "lib/checksum.h"
+#include "lib/network.h"
#include "bfd.h"
@@ -55,6 +57,18 @@ int bp_udp_send(int sd, uint8_t ttl, uint8_t *data, size_t datalen,
struct sockaddr *to, socklen_t tolen);
int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd,
uint8_t *ttl, uint32_t *my_discr);
+#ifdef BFD_LINUX
+ssize_t bfd_recv_ipv4_fp(int sd, uint8_t *msgbuf, size_t msgbuflen,
+ uint8_t *ttl, ifindex_t *ifindex,
+ struct sockaddr_any *local, struct sockaddr_any *peer);
+void bfd_peer_mac_set(int sd, struct bfd_session *bfd,
+ struct sockaddr_any *peer, struct interface *ifp);
+int bp_udp_send_fp(int sd, uint8_t *data, size_t datalen,
+ struct bfd_session *bfd);
+ssize_t bfd_recv_fp_echo(int sd, uint8_t *msgbuf, size_t msgbuflen,
+ uint8_t *ttl, ifindex_t *ifindex,
+ struct sockaddr_any *local, struct sockaddr_any *peer);
+#endif
/* socket related prototypes */
static void bp_set_ipopts(int sd);
@@ -126,6 +140,142 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
return 0;
}
+#ifdef BFD_LINUX
+/*
+ * Compute the UDP checksum.
+ *
+ * Checksum is not set in the packet, just computed.
+ *
+ * pkt
+ * Packet, fully filled out except for checksum field.
+ *
+ * pktsize
+ * sizeof(*pkt)
+ *
+ * ip
+ * IP address that pkt will be transmitted from and too.
+ *
+ * Returns:
+ * Checksum in network byte order.
+ */
+static uint16_t bfd_pkt_checksum(struct udphdr *pkt, size_t pktsize,
+ struct in6_addr *ip, sa_family_t family)
+{
+ uint16_t chksum;
+
+ pkt->check = 0;
+
+ if (family == AF_INET6) {
+ struct ipv6_ph ph = {};
+
+ memcpy(&ph.src, ip, sizeof(ph.src));
+ memcpy(&ph.dst, ip, sizeof(ph.dst));
+ ph.ulpl = htons(pktsize);
+ ph.next_hdr = IPPROTO_UDP;
+ chksum = in_cksum_with_ph6(&ph, pkt, pktsize);
+ } else {
+ struct ipv4_ph ph = {};
+
+ memcpy(&ph.src, ip, sizeof(ph.src));
+ memcpy(&ph.dst, ip, sizeof(ph.dst));
+ ph.proto = IPPROTO_UDP;
+ ph.len = htons(pktsize);
+ chksum = in_cksum_with_ph4(&ph, pkt, pktsize);
+ }
+
+ return chksum;
+}
+
+/*
+ * This routine creates the entire ECHO packet so that it will be looped
+ * in the forwarding plane of the peer router instead of going up the
+ * stack in BFD to be looped. If we haven't learned the peers MAC yet
+ * no echo is sent.
+ *
+ * echo packet with src/dst IP equal to local IP
+ * dest MAC as peer's MAC
+ *
+ * currently support ipv4
+ */
+void ptm_bfd_echo_fp_snd(struct bfd_session *bfd)
+{
+ int sd;
+ struct bfd_vrf_global *bvrf = bfd_vrf_look_by_session(bfd);
+ int total_len = 0;
+ struct ethhdr *eth;
+ struct udphdr *uh;
+ struct iphdr *iph;
+ struct bfd_echo_pkt *beph;
+ static char sendbuff[100];
+
+ if (!bvrf)
+ return;
+ if (!CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET))
+ return;
+ if (!CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE))
+ SET_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE);
+
+ memset(sendbuff, 0, sizeof(sendbuff));
+
+ /* add eth hdr */
+ eth = (struct ethhdr *)(sendbuff);
+ memcpy(eth->h_source, bfd->ifp->hw_addr, sizeof(bfd->ifp->hw_addr));
+ memcpy(eth->h_dest, bfd->peer_hw_addr, sizeof(bfd->peer_hw_addr));
+
+ total_len += sizeof(struct ethhdr);
+
+ sd = bvrf->bg_echo;
+ eth->h_proto = htons(ETH_P_IP);
+
+ /* add ip hdr */
+ iph = (struct iphdr *)(sendbuff + sizeof(struct ethhdr));
+
+ iph->ihl = sizeof(struct ip) >> 2;
+ iph->version = IPVERSION;
+ iph->tos = IPTOS_PREC_INTERNETCONTROL;
+ iph->id = (uint16_t)frr_weak_random();
+ iph->ttl = BFD_TTL_VAL;
+ iph->protocol = IPPROTO_UDP;
+ memcpy(&iph->saddr, &bfd->local_address.sa_sin.sin_addr,
+ sizeof(bfd->local_address.sa_sin.sin_addr));
+ memcpy(&iph->daddr, &bfd->local_address.sa_sin.sin_addr,
+ sizeof(bfd->local_address.sa_sin.sin_addr));
+ total_len += sizeof(struct iphdr);
+
+ /* add udp hdr */
+ uh = (struct udphdr *)(sendbuff + sizeof(struct iphdr) +
+ sizeof(struct ethhdr));
+ uh->source = htons(BFD_DEF_ECHO_PORT);
+ uh->dest = htons(BFD_DEF_ECHO_PORT);
+
+ total_len += sizeof(struct udphdr);
+
+ /* add bfd echo */
+ beph = (struct bfd_echo_pkt *)(sendbuff + sizeof(struct udphdr) +
+ sizeof(struct iphdr) +
+ sizeof(struct ethhdr));
+
+ beph->ver = BFD_ECHO_VERSION;
+ beph->len = BFD_ECHO_PKT_LEN;
+ beph->my_discr = htonl(bfd->discrs.my_discr);
+
+ total_len += sizeof(struct bfd_echo_pkt);
+ uh->len =
+ htons(total_len - sizeof(struct iphdr) - sizeof(struct ethhdr));
+ uh->check = bfd_pkt_checksum(
+ uh, (total_len - sizeof(struct iphdr) - sizeof(struct ethhdr)),
+ (struct in6_addr *)&iph->saddr, AF_INET);
+
+ iph->tot_len = htons(total_len - sizeof(struct ethhdr));
+ iph->check = in_cksum((const void *)iph, sizeof(struct iphdr));
+
+ if (bp_udp_send_fp(sd, (uint8_t *)&sendbuff, total_len, bfd) == -1)
+ return;
+
+ bfd->stats.tx_echo_pkt++;
+}
+#endif
+
void ptm_bfd_echo_snd(struct bfd_session *bfd)
{
struct sockaddr *sa;
@@ -275,6 +425,94 @@ void ptm_bfd_snd(struct bfd_session *bfd, int fbit)
bfd->stats.tx_ctrl_pkt++;
}
+#ifdef BFD_LINUX
+/*
+ * receive the ipv4 echo packet that was loopback in the peers forwarding plane
+ */
+ssize_t bfd_recv_ipv4_fp(int sd, uint8_t *msgbuf, size_t msgbuflen,
+ uint8_t *ttl, ifindex_t *ifindex,
+ struct sockaddr_any *local, struct sockaddr_any *peer)
+{
+ ssize_t mlen;
+ struct sockaddr_ll msgaddr;
+ struct msghdr msghdr;
+ struct iovec iov[1];
+ uint16_t recv_checksum;
+ uint16_t checksum;
+ struct iphdr *ip;
+ struct udphdr *uh;
+
+ /* Prepare the recvmsg params. */
+ iov[0].iov_base = msgbuf;
+ iov[0].iov_len = msgbuflen;
+
+ memset(&msghdr, 0, sizeof(msghdr));
+ msghdr.msg_name = &msgaddr;
+ msghdr.msg_namelen = sizeof(msgaddr);
+ msghdr.msg_iov = iov;
+ msghdr.msg_iovlen = 1;
+
+ mlen = recvmsg(sd, &msghdr, MSG_DONTWAIT);
+ if (mlen == -1) {
+ if (errno != EAGAIN || errno != EWOULDBLOCK || errno != EINTR)
+ zlog_err("%s: recv failed: %s", __func__,
+ strerror(errno));
+
+ return -1;
+ }
+
+ ip = (struct iphdr *)(msgbuf + sizeof(struct ethhdr));
+
+ /* verify ip checksum */
+ recv_checksum = ip->check;
+ ip->check = 0;
+ checksum = in_cksum((const void *)ip, sizeof(struct iphdr));
+ if (recv_checksum != checksum) {
+ if (bglobal.debug_network)
+ zlog_debug(
+ "%s: invalid iphdr checksum expected 0x%x rcvd 0x%x",
+ __func__, checksum, recv_checksum);
+ return -1;
+ }
+
+ *ttl = ip->ttl;
+ if (*ttl != 254) {
+ /* Echo should be looped in peer's forwarding plane, but it also
+ * comes up to BFD so silently drop it
+ */
+ if (ip->daddr == ip->saddr)
+ return -1;
+
+ if (bglobal.debug_network)
+ zlog_debug("%s: invalid TTL: %u", __func__, *ttl);
+ return -1;
+ }
+
+ local->sa_sin.sin_family = AF_INET;
+ memcpy(&local->sa_sin.sin_addr, &ip->saddr, sizeof(ip->saddr));
+ peer->sa_sin.sin_family = AF_INET;
+ memcpy(&peer->sa_sin.sin_addr, &ip->daddr, sizeof(ip->daddr));
+
+ *ifindex = msgaddr.sll_ifindex;
+
+ /* verify udp checksum */
+ uh = (struct udphdr *)(msgbuf + sizeof(struct iphdr) +
+ sizeof(struct ethhdr));
+ recv_checksum = uh->check;
+ uh->check = 0;
+ checksum = bfd_pkt_checksum(uh, ntohs(uh->len),
+ (struct in6_addr *)&ip->saddr, AF_INET);
+ if (recv_checksum != checksum) {
+ if (bglobal.debug_network)
+ zlog_debug(
+ "%s: invalid udphdr checksum expected 0x%x rcvd 0x%x",
+ __func__, checksum, recv_checksum);
+ return -1;
+ }
+ return mlen;
+}
+#endif
+
ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
ifindex_t *ifindex, struct sockaddr_any *local,
struct sockaddr_any *peer)
@@ -649,6 +887,8 @@ void bfd_recv_cb(struct thread *t)
/*
* Multi hop: validate packet TTL.
+ * Single hop: set local address that received the packet.
+ * set peers mac address for echo packets
*/
if (is_mhop) {
if (ttl < bfd->mh_ttl) {
@@ -657,6 +897,14 @@ void bfd_recv_cb(struct thread *t)
bfd->mh_ttl, ttl);
return;
}
+ } else {
+
+ if (bfd->local_address.sa_sin.sin_family == AF_UNSPEC)
+ bfd->local_address = local;
+#ifdef BFD_LINUX
+ if (ifp)
+ bfd_peer_mac_set(sd, bfd, &peer, ifp);
+#endif
}
bfd->stats.rx_ctrl_pkt++;
@@ -756,13 +1004,30 @@ int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd,
ifindex_t ifindex = IFINDEX_INTERNAL;
vrf_id_t vrfid = VRF_DEFAULT;
uint8_t msgbuf[1516];
+ size_t bfd_offset = 0;
+
+ if (sd == bvrf->bg_echo) {
+#ifdef BFD_LINUX
+ rlen = bfd_recv_ipv4_fp(sd, msgbuf, sizeof(msgbuf), ttl,
+ &ifindex, &local, &peer);
- if (sd == bvrf->bg_echo)
+ /* silently drop echo packet that is looped in fastpath but
+ * still comes up to BFD
+ */
+ if (rlen == -1)
+ return -1;
+ bfd_offset = sizeof(struct udphdr) + sizeof(struct iphdr) +
+ sizeof(struct ethhdr);
+#else
rlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), ttl, &ifindex,
&local, &peer);
- else
+ bfd_offset = 0;
+#endif
+ } else {
rlen = bfd_recv_ipv6(sd, msgbuf, sizeof(msgbuf), ttl, &ifindex,
&local, &peer);
+ bfd_offset = 0;
+ }
/* Short packet, better not risk reading it. */
if (rlen < (ssize_t)sizeof(*bep)) {
@@ -771,8 +1036,8 @@ int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd,
return -1;
}
- /* Test for loopback. */
- if (*ttl == BFD_TTL_VAL) {
+ /* Test for loopback for ipv6, ipv4 is looped in forwarding plane */
+ if ((*ttl == BFD_TTL_VAL) && (sd == bvrf->bg_echov6)) {
bp_udp_send(sd, *ttl - 1, msgbuf, rlen,
(struct sockaddr *)&peer,
(sd == bvrf->bg_echo) ? sizeof(peer.sa_sin)
@@ -781,7 +1046,7 @@ int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd,
}
/* Read my discriminator from BFD Echo packet. */
- bep = (struct bfd_echo_pkt *)msgbuf;
+ bep = (struct bfd_echo_pkt *)(msgbuf + bfd_offset);
*my_discr = ntohl(bep->my_discr);
if (*my_discr == 0) {
cp_debug(false, &peer, &local, ifindex, vrfid,
@@ -792,6 +1057,56 @@ int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd,
return 0;
}
+#ifdef BFD_LINUX
+/*
+ * send a bfd packet with src/dst same IP so that the peer will receive
+ * the packet and forward it back to sender in the forwarding plane
+ */
+int bp_udp_send_fp(int sd, uint8_t *data, size_t datalen,
+ struct bfd_session *bfd)
+{
+ ssize_t wlen;
+ struct msghdr msg;
+ struct iovec iov[1];
+ uint8_t msgctl[255];
+ struct sockaddr_ll sadr_ll;
+
+
+ sadr_ll.sll_ifindex = bfd->ifp->ifindex;
+ sadr_ll.sll_halen = ETH_ALEN;
+ memcpy(sadr_ll.sll_addr, bfd->peer_hw_addr, sizeof(bfd->peer_hw_addr));
+ sadr_ll.sll_protocol = htons(ETH_P_IP);
+
+ /* Prepare message data. */
+ iov[0].iov_base = data;
+ iov[0].iov_len = datalen;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(msgctl, 0, sizeof(msgctl));
+ msg.msg_name = &sadr_ll;
+ msg.msg_namelen = sizeof(sadr_ll);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+
+ /* Send echo to peer */
+ wlen = sendmsg(sd, &msg, 0);
+
+ if (wlen <= 0) {
+ if (bglobal.debug_network)
+ zlog_debug("udp-send: loopback failure: (%d) %s", errno,
+ strerror(errno));
+ return -1;
+ } else if (wlen < (ssize_t)datalen) {
+ if (bglobal.debug_network)
+ zlog_debug("udp-send: partial send: %zd expected %zu",
+ wlen, datalen);
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
int bp_udp_send(int sd, uint8_t ttl, uint8_t *data, size_t datalen,
struct sockaddr *to, socklen_t tolen)
{
@@ -1219,6 +1534,57 @@ int bp_udp6_mhop(const struct vrf *vrf)
return sd;
}
+#ifdef BFD_LINUX
+/* tcpdump -dd udp dst port 3785 */
+struct sock_filter my_filterudp[] = {
+ {0x28, 0, 0, 0x0000000c}, {0x15, 0, 8, 0x00000800},
+ {0x30, 0, 0, 0x00000017}, {0x15, 0, 6, 0x00000011},
+ {0x28, 0, 0, 0x00000014}, {0x45, 4, 0, 0x00001fff},
+ {0xb1, 0, 0, 0x0000000e}, {0x48, 0, 0, 0x00000010},
+ {0x15, 0, 1, 0x00000ec9}, {0x6, 0, 0, 0x00040000},
+ {0x6, 0, 0, 0x00000000},
+};
+
+#define MY_FILTER_LENGTH 11
+
+int bp_echo_socket(const struct vrf *vrf)
+{
+ int s;
+
+ frr_with_privs (&bglobal.bfdd_privs) {
+ s = vrf_socket(AF_PACKET, SOCK_RAW, ETH_P_IP, vrf->vrf_id,
+ vrf->name);
+ }
+
+ if (s == -1)
+ zlog_fatal("echo-socket: socket: %s", strerror(errno));
+
+ struct sock_fprog pf;
+ struct sockaddr_ll sll;
+
+ /* adjust filter for socket to only receive ECHO packets */
+ pf.filter = my_filterudp;
+ pf.len = MY_FILTER_LENGTH;
+ if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &pf, sizeof(pf)) ==
+ -1) {
+ zlog_warn("%s: setsockopt(SO_ATTACH_FILTER): %s", __func__,
+ strerror(errno));
+ return -1;
+ }
+
+
+ sll.sll_family = AF_PACKET;
+ sll.sll_protocol = htons(ETH_P_IP);
+ sll.sll_ifindex = 0;
+ if (bind(s, (struct sockaddr *)&sll, sizeof(sll)) < 0) {
+ zlog_warn("Failed to bind echo socket: %s",
+ safe_strerror(errno));
+ return -1;
+ }
+
+ return s;
+}
+#else
int bp_echo_socket(const struct vrf *vrf)
{
int s;
@@ -1234,6 +1600,7 @@ int bp_echo_socket(const struct vrf *vrf)
return s;
}
+#endif
int bp_echov6_socket(const struct vrf *vrf)
{
@@ -1257,3 +1624,41 @@ int bp_echov6_socket(const struct vrf *vrf)
return s;
}
+
+#ifdef BFD_LINUX
+/* get peer's mac address to be used with Echo packets when they are looped in
+ * peers forwarding plane
+ */
+void bfd_peer_mac_set(int sd, struct bfd_session *bfd,
+ struct sockaddr_any *peer, struct interface *ifp)
+{
+ struct arpreq arpreq_;
+
+ if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET))
+ return;
+
+ if (peer->sa_sin.sin_family == AF_INET) {
+ /* IPV4 */
+ struct sockaddr_in *addr =
+ (struct sockaddr_in *)&arpreq_.arp_pa;
+
+ memset(&arpreq_, 0, sizeof(struct arpreq));
+ addr->sin_family = AF_INET;
+ memcpy(&addr->sin_addr.s_addr, &peer->sa_sin.sin_addr,
+ sizeof(addr->sin_addr));
+ strlcpy(arpreq_.arp_dev, ifp->name, sizeof(arpreq_.arp_dev));
+
+ if (ioctl(sd, SIOCGARP, &arpreq_) < 0) {
+ zlog_warn("BFD: getting peer's mac failed error %s",
+ strerror(errno));
+ UNSET_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET);
+ memset(bfd->peer_hw_addr, 0, sizeof(bfd->peer_hw_addr));
+
+ } else {
+ memcpy(bfd->peer_hw_addr, arpreq_.arp_ha.sa_data,
+ sizeof(bfd->peer_hw_addr));
+ SET_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET);
+ }
+ }
+}
+#endif
diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c
index d4e12e4f1a..69424c45d9 100644
--- a/bfdd/bfdd_cli.c
+++ b/bfdd/bfdd_cli.c
@@ -423,12 +423,19 @@ DEFPY_YANG(
"Configure echo mode\n")
{
if (!bfd_cli_is_profile(vty) && !bfd_cli_is_single_hop(vty)) {
- vty_out(vty, "%% Echo mode is only available for single hop sessions.\n");
+ vty_out(vty,
+ "%% Echo mode is only available for single hop sessions.\n");
return CMD_WARNING_CONFIG_FAILED;
}
if (!no && !bglobal.bg_use_dplane) {
- vty_out(vty, "%% Current implementation of echo mode works only when the peer is also FRR.\n");
+#ifdef BFD_LINUX
+ vty_out(vty,
+ "%% Echo mode works correctly for IPv4, but only works when the peer is also FRR for IPv6.\n");
+#else
+ vty_out(vty,
+ "%% Current implementation of echo mode works only when the peer is also FRR.\n");
+#endif /* BFD_LINUX */
}
nb_cli_enqueue_change(vty, "./echo-mode", NB_OP_MODIFY,
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index e7690ed8df..1a253b122a 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -1606,13 +1606,9 @@ static int bgp_attr_as4_path(struct bgp_attr_parser_args *args,
enum bgp_attr_parse_ret bgp_attr_nexthop_valid(struct peer *peer,
struct attr *attr)
{
- in_addr_t nexthop_h;
struct bgp *bgp = peer->bgp;
- nexthop_h = ntohl(attr->nexthop.s_addr);
- if ((IPV4_NET0(nexthop_h) || IPV4_NET127(nexthop_h) ||
- !ipv4_unicast_valid(&attr->nexthop)) &&
- !bgp->allow_martian) {
+ if (ipv4_martian(&attr->nexthop) && !bgp->allow_martian) {
uint8_t data[7]; /* type(2) + length(1) + nhop(4) */
char buf[INET_ADDRSTRLEN];
diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c
index dd1510a678..9c2826fa13 100644
--- a/bgpd/bgp_conditional_adv.c
+++ b/bgpd/bgp_conditional_adv.c
@@ -100,7 +100,8 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi,
if (BGP_DEBUG(update, UPDATE_OUT))
zlog_debug("%s: %s routes to/from %s for %s", __func__,
- update_type == ADVERTISE ? "Advertise" : "Withdraw",
+ update_type == UPDATE_TYPE_ADVERTISE ? "Advertise"
+ : "Withdraw",
peer->host, get_afi_safi_str(afi, safi, false));
addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
@@ -133,7 +134,7 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi,
* on same peer, routes in advertise-map may not
* be advertised as expected.
*/
- if (update_type == ADVERTISE &&
+ if (update_type == UPDATE_TYPE_ADVERTISE &&
subgroup_announce_check(dest, pi, subgrp, dest_p,
&attr, &advmap_attr)) {
bgp_adj_out_set_subgroup(dest, subgrp, &attr,
@@ -248,12 +249,14 @@ static void bgp_conditional_adv_timer(struct thread *t)
*/
if (filter->advmap.condition == CONDITION_EXIST)
filter->advmap.update_type =
- (ret == RMAP_PERMITMATCH) ? ADVERTISE
- : WITHDRAW;
+ (ret == RMAP_PERMITMATCH)
+ ? UPDATE_TYPE_ADVERTISE
+ : UPDATE_TYPE_WITHDRAW;
else
filter->advmap.update_type =
- (ret == RMAP_PERMITMATCH) ? WITHDRAW
- : ADVERTISE;
+ (ret == RMAP_PERMITMATCH)
+ ? UPDATE_TYPE_WITHDRAW
+ : UPDATE_TYPE_ADVERTISE;
/* Send regular update as per the existing policy.
* There is a change in route-map, match-rule, ACLs,
@@ -312,8 +315,9 @@ void bgp_conditional_adv_enable(struct peer *peer, afi_t afi, safi_t safi)
}
/* Register for conditional routes polling timer */
- thread_add_timer(bm->master, bgp_conditional_adv_timer, bgp,
- bgp->condition_check_period, &bgp->t_condition_check);
+ if (!thread_is_scheduled(bgp->t_condition_check))
+ thread_add_timer(bm->master, bgp_conditional_adv_timer, bgp, 0,
+ &bgp->t_condition_check);
}
void bgp_conditional_adv_disable(struct peer *peer, afi_t afi, safi_t safi)
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 63b73bc583..19901792ea 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -12115,11 +12115,12 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
filter->advmap.cname);
json_object_string_add(json_advmap, "advertiseMap",
filter->advmap.aname);
- json_object_string_add(json_advmap, "advertiseStatus",
- filter->advmap.update_type
- == ADVERTISE
- ? "Advertise"
- : "Withdraw");
+ json_object_string_add(
+ json_advmap, "advertiseStatus",
+ filter->advmap.update_type ==
+ UPDATE_TYPE_ADVERTISE
+ ? "Advertise"
+ : "Withdraw");
json_object_object_add(json_addr, "advertiseMap",
json_advmap);
}
@@ -12429,7 +12430,8 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
filter->advmap.cname,
filter->advmap.amap ? "*" : "",
filter->advmap.aname,
- filter->advmap.update_type == ADVERTISE
+ filter->advmap.update_type ==
+ UPDATE_TYPE_ADVERTISE
? "Advertise"
: "Withdraw");
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index b6f2a294a6..0bfcf5163f 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -7225,18 +7225,15 @@ static void peer_advertise_map_filter_update(struct peer *peer, afi_t afi,
/* Increment condition_filter_count and/or create timer. */
if (!filter_exists) {
- filter->advmap.update_type = ADVERTISE;
+ filter->advmap.update_type = UPDATE_TYPE_ADVERTISE;
bgp_conditional_adv_enable(peer, afi, safi);
}
+
+ /* Process peer route updates. */
+ peer_on_policy_change(peer, afi, safi, 1);
}
-/* Set advertise-map to the peer but do not process peer route updates here. *
- * Hold filter changes until the conditional routes polling thread is called *
- * AS we need to advertise/withdraw prefixes (in advertise-map) based on the *
- * condition (exist-map/non-exist-map) and routes(specified in condition-map) *
- * in BGP table. So do not call peer_on_policy_change() here, only create *
- * polling timer thread, update filters and increment condition_filter_count.
- */
+/* Set advertise-map to the peer. */
int peer_advertise_map_set(struct peer *peer, afi_t afi, safi_t safi,
const char *advertise_name,
struct route_map *advertise_map,
@@ -7316,7 +7313,6 @@ int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi,
__func__, peer->host,
get_afi_safi_str(afi, safi, false));
- peer_on_policy_change(peer, afi, safi, 1);
return 0;
}
@@ -7339,8 +7335,6 @@ int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi,
zlog_debug("%s: Send normal update to %s for %s ",
__func__, member->host,
get_afi_safi_str(afi, safi, false));
-
- peer_on_policy_change(member, afi, safi, 1);
}
return 0;
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index bc5f6cf6fd..7f3d240b8e 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -859,7 +859,7 @@ struct bgp_nexthop {
#define CONDITION_NON_EXIST false
#define CONDITION_EXIST true
-enum update_type { WITHDRAW, ADVERTISE };
+enum update_type { UPDATE_TYPE_WITHDRAW, UPDATE_TYPE_ADVERTISE };
#include "filter.h"
diff --git a/doc/user/basic.rst b/doc/user/basic.rst
index 42faefd10b..7679a377eb 100644
--- a/doc/user/basic.rst
+++ b/doc/user/basic.rst
@@ -338,6 +338,12 @@ Basic Config Commands
Restrict vty connections with an access list.
+.. clicmd:: allow-reserved-ranges
+
+ Allow using IPv4 reserved (Class E) IP ranges for daemons. E.g.: setting
+ IPv4 addresses for interfaces or allowing reserved ranges in BGP next-hops.
+
+ Default: off.
.. _sample-config-file:
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index 09f92554c0..3aef8ada24 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -1400,20 +1400,21 @@ static void spf_adj_list_parse_tlv(struct isis_spftree *spftree,
spf_adj_list_parse_lsp(spftree, adj_list, lsp, id, metric);
}
-static void spf_adj_list_parse_lsp_frag(struct isis_spftree *spftree,
- struct list *adj_list,
- struct isis_lsp *lsp,
- const uint8_t *pseudo_nodeid,
- uint32_t pseudo_metric)
+static void spf_adj_list_parse_lsp(struct isis_spftree *spftree,
+ struct list *adj_list, struct isis_lsp *lsp,
+ const uint8_t *pseudo_nodeid,
+ uint32_t pseudo_metric)
{
bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id);
+ struct isis_lsp *frag;
+ struct listnode *node;
struct isis_item *head;
struct isis_item_list *te_neighs;
if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0)
return;
- /* Parse main LSP. */
+ /* Parse LSP. */
if (lsp->tlvs) {
if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) {
head = lsp->tlvs->oldstyle_reach.head;
@@ -1444,27 +1445,17 @@ static void spf_adj_list_parse_lsp_frag(struct isis_spftree *spftree,
}
}
}
-}
-
-static void spf_adj_list_parse_lsp(struct isis_spftree *spftree,
- struct list *adj_list, struct isis_lsp *lsp,
- const uint8_t *pseudo_nodeid,
- uint32_t pseudo_metric)
-{
- struct isis_lsp *frag;
- struct listnode *node;
-
- spf_adj_list_parse_lsp_frag(spftree, adj_list, lsp, pseudo_nodeid,
- pseudo_metric);
+ if (LSP_FRAGMENT(lsp->hdr.lsp_id))
+ return;
/* Parse LSP fragments. */
for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
if (!frag->tlvs)
continue;
- spf_adj_list_parse_lsp_frag(spftree, adj_list, frag,
- pseudo_nodeid, pseudo_metric);
+ spf_adj_list_parse_lsp(spftree, adj_list, frag, pseudo_nodeid,
+ pseudo_metric);
}
}
diff --git a/lib/command.c b/lib/command.c
index cbecc81574..a23afb1e43 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -121,6 +121,11 @@ const char *cmd_version_get(void)
return host.version;
}
+bool cmd_allow_reserved_ranges_get(void)
+{
+ return host.allow_reserved_ranges;
+}
+
static int root_on_exit(struct vty *vty);
/* Standard command node structures. */
@@ -454,6 +459,9 @@ static int config_write_host(struct vty *vty)
if (name && name[0] != '\0')
vty_out(vty, "domainname %s\n", name);
+ if (cmd_allow_reserved_ranges_get())
+ vty_out(vty, "allow-reserved-ranges\n");
+
/* 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
@@ -2294,6 +2302,21 @@ DEFUN (no_banner_motd,
return CMD_SUCCESS;
}
+DEFUN(allow_reserved_ranges, allow_reserved_ranges_cmd, "allow-reserved-ranges",
+ "Allow using IPv4 (Class E) reserved IP space\n")
+{
+ host.allow_reserved_ranges = true;
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_allow_reserved_ranges, no_allow_reserved_ranges_cmd,
+ "no allow-reserved-ranges",
+ NO_STR "Allow using IPv4 (Class E) reserved IP space\n")
+{
+ host.allow_reserved_ranges = false;
+ return CMD_SUCCESS;
+}
+
int cmd_find_cmds(struct vty *vty, struct cmd_token **argv, int argc)
{
const struct cmd_node *node;
@@ -2483,6 +2506,7 @@ void cmd_init(int terminal)
host.lines = -1;
cmd_banner_motd_line(FRR_DEFAULT_MOTD);
host.motdfile = NULL;
+ host.allow_reserved_ranges = false;
/* Install top nodes. */
install_node(&view_node);
@@ -2552,6 +2576,8 @@ void cmd_init(int terminal)
install_element(CONFIG_NODE, &no_banner_motd_cmd);
install_element(CONFIG_NODE, &service_terminal_length_cmd);
install_element(CONFIG_NODE, &no_service_terminal_length_cmd);
+ install_element(CONFIG_NODE, &allow_reserved_ranges_cmd);
+ install_element(CONFIG_NODE, &no_allow_reserved_ranges_cmd);
log_cmd_init();
vrf_install_commands();
diff --git a/lib/command.h b/lib/command.h
index 7363ed84c8..70e52708a7 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -84,6 +84,9 @@ struct host {
/* Banner configuration. */
char *motd;
char *motdfile;
+
+ /* Allow using IPv4 (Class E) reserved IP space */
+ bool allow_reserved_ranges;
};
/* List of CLI nodes. Please remember to update the name array in command.c. */
@@ -614,6 +617,7 @@ extern const char *cmd_domainname_get(void);
extern const char *cmd_system_get(void);
extern const char *cmd_release_get(void);
extern const char *cmd_version_get(void);
+extern bool cmd_allow_reserved_ranges_get(void);
/* NOT safe for general use; call this only if DEV_BUILD! */
extern void grammar_sandbox_init(void);
diff --git a/lib/prefix.c b/lib/prefix.c
index 1a3efd32b1..e64b10bf24 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -21,6 +21,7 @@
#include <zebra.h>
+#include "command.h"
#include "prefix.h"
#include "ipaddr.h"
#include "vty.h"
@@ -1386,6 +1387,23 @@ char *evpn_es_df_alg2str(uint8_t df_alg, char *buf, int buf_len)
return buf;
}
+bool ipv4_unicast_valid(const struct in_addr *addr)
+{
+ in_addr_t ip = ntohl(addr->s_addr);
+
+ if (IPV4_CLASS_D(ip))
+ return false;
+
+ if (IPV4_CLASS_E(ip)) {
+ if (cmd_allow_reserved_ranges_get())
+ return true;
+ else
+ return false;
+ }
+
+ return true;
+}
+
printfrr_ext_autoreg_p("EA", printfrr_ea);
static ssize_t printfrr_ea(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
diff --git a/lib/prefix.h b/lib/prefix.h
index f9eef28a0b..3a768572c4 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -382,6 +382,8 @@ static inline void ipv4_addr_copy(struct in_addr *dst,
#define IPV4_NET0(a) ((((uint32_t)(a)) & 0xff000000) == 0x00000000)
#define IPV4_NET127(a) ((((uint32_t)(a)) & 0xff000000) == 0x7f000000)
#define IPV4_LINKLOCAL(a) ((((uint32_t)(a)) & 0xffff0000) == 0xa9fe0000)
+#define IPV4_CLASS_D(a) ((((uint32_t)(a)) & 0xf0000000) == 0xe0000000)
+#define IPV4_CLASS_E(a) ((((uint32_t)(a)) & 0xf0000000) == 0xf0000000)
#define IPV4_CLASS_DE(a) ((((uint32_t)(a)) & 0xe0000000) == 0xe0000000)
#define IPV4_MC_LINKLOCAL(a) ((((uint32_t)(a)) & 0xffffff00) == 0xe0000000)
@@ -507,17 +509,7 @@ extern int str_to_esi(const char *str, esi_t *esi);
extern char *esi_to_str(const esi_t *esi, char *buf, int size);
extern char *evpn_es_df_alg2str(uint8_t df_alg, char *buf, int buf_len);
extern void prefix_evpn_hexdump(const struct prefix_evpn *p);
-
-static inline bool ipv4_unicast_valid(const struct in_addr *addr)
-{
-
- in_addr_t ip = ntohl(addr->s_addr);
-
- if (IPV4_CLASS_DE(ip))
- return false;
-
- return true;
-}
+extern bool ipv4_unicast_valid(const struct in_addr *addr);
static inline int ipv6_martian(const struct in6_addr *addr)
{
@@ -534,14 +526,14 @@ static inline int ipv6_martian(const struct in6_addr *addr)
extern int macstr2prefix_evpn(const char *str, struct prefix_evpn *p);
/* NOTE: This routine expects the address argument in network byte order. */
-static inline int ipv4_martian(const struct in_addr *addr)
+static inline bool ipv4_martian(const struct in_addr *addr)
{
in_addr_t ip = ntohl(addr->s_addr);
if (IPV4_NET0(ip) || IPV4_NET127(ip) || !ipv4_unicast_valid(addr)) {
- return 1;
+ return true;
}
- return 0;
+ return false;
}
static inline bool is_default_prefix4(const struct prefix_ipv4 *p)
diff --git a/lib/privs.c b/lib/privs.c
index c012178e71..5cba90839f 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -286,9 +286,6 @@ static void zprivs_caps_init(struct zebra_privs_t *zprivs)
}
}
- if (!zprivs_state.syscaps_p)
- return;
-
if (!(zprivs_state.caps = cap_init())) {
fprintf(stderr, "privs_init: failed to cap_init, %s\n",
safe_strerror(errno));
@@ -301,10 +298,12 @@ static void zprivs_caps_init(struct zebra_privs_t *zprivs)
exit(1);
}
- /* set permitted caps */
- cap_set_flag(zprivs_state.caps, CAP_PERMITTED,
- zprivs_state.syscaps_p->num, zprivs_state.syscaps_p->caps,
- CAP_SET);
+ /* set permitted caps, if any */
+ if (zprivs_state.syscaps_p && zprivs_state.syscaps_p->num) {
+ cap_set_flag(zprivs_state.caps, CAP_PERMITTED,
+ zprivs_state.syscaps_p->num,
+ zprivs_state.syscaps_p->caps, CAP_SET);
+ }
/* set inheritable caps, if any */
if (zprivs_state.syscaps_i && zprivs_state.syscaps_i->num) {
@@ -364,7 +363,7 @@ static void zprivs_caps_terminate(void)
}
/* free up private state */
- if (zprivs_state.syscaps_p->num) {
+ if (zprivs_state.syscaps_p && zprivs_state.syscaps_p->num) {
XFREE(MTYPE_PRIVS, zprivs_state.syscaps_p->caps);
XFREE(MTYPE_PRIVS, zprivs_state.syscaps_p);
}
diff --git a/lib/typesafe.h b/lib/typesafe.h
index 06fdc52e78..df963f530d 100644
--- a/lib/typesafe.h
+++ b/lib/typesafe.h
@@ -309,7 +309,8 @@ static inline void typesafe_dlist_add(struct dlist_head *head,
struct dlist_item *prev, struct dlist_item *item)
{
item->next = prev->next;
- item->next->prev = item;
+ if (item->next)
+ item->next->prev = item;
item->prev = prev;
prev->next = item;
head->count++;
diff --git a/ospfd/ospf_bfd.c b/ospfd/ospf_bfd.c
index 56116cd28d..fb117ecfc2 100644
--- a/ospfd/ospf_bfd.c
+++ b/ospfd/ospf_bfd.c
@@ -266,8 +266,12 @@ DEFUN (ip_ospf_bfd_prof,
struct ospf_if_params *params;
int idx_prof = 4;
- ospf_interface_enable_bfd(ifp);
params = IF_DEF_PARAMS(ifp);
+ if (!params->bfd_config) {
+ vty_out(vty, "ip ospf bfd has not been set\n");
+ return CMD_WARNING;
+ }
+
strlcpy(params->bfd_config->profile, argv[idx_prof]->arg,
sizeof(params->bfd_config->profile));
ospf_interface_bfd_apply(ifp);
@@ -288,8 +292,10 @@ DEFUN (no_ip_ospf_bfd_prof,
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf_if_params *params;
- ospf_interface_enable_bfd(ifp);
params = IF_DEF_PARAMS(ifp);
+ if (!params->bfd_config)
+ return CMD_SUCCESS;
+
params->bfd_config->profile[0] = 0;
ospf_interface_bfd_apply(ifp);
diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c
index 9ff2224992..e46b4d6a10 100644
--- a/pimd/pim6_cmd.c
+++ b/pimd/pim6_cmd.c
@@ -686,9 +686,7 @@ DEFPY (ipv6_mld_group_watermark,
"Group count to generate watermark warning\n")
{
PIM_DECLVAR_CONTEXT_VRF(vrf, pim);
-
- /* TBD Depends on MLD data structure changes */
- (void)pim;
+ pim->gm_watermark_limit = limit;
return CMD_SUCCESS;
}
@@ -703,9 +701,7 @@ DEFPY (no_ipv6_mld_group_watermark,
IGNORED_IN_NO_STR)
{
PIM_DECLVAR_CONTEXT_VRF(vrf, pim);
-
- /* TBD Depends on MLD data structure changes */
- (void)pim;
+ pim->gm_watermark_limit = 0;
return CMD_SUCCESS;
}
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 8f3777e03e..10ea472fb5 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -1135,12 +1135,12 @@ static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj)
json = json_object_new_object();
json_object_int_add(json, "totalGroups", pim->igmp_group_count);
json_object_int_add(json, "watermarkLimit",
- pim->igmp_watermark_limit);
+ pim->gm_watermark_limit);
} else {
vty_out(vty, "Total IGMP groups: %u\n", pim->igmp_group_count);
vty_out(vty, "Watermark warn limit(%s): %u\n",
- pim->igmp_watermark_limit ? "Set" : "Not Set",
- pim->igmp_watermark_limit);
+ pim->gm_watermark_limit ? "Set" : "Not Set",
+ pim->gm_watermark_limit);
vty_out(vty,
"Interface Group Mode Timer Srcs V Uptime \n");
}
@@ -3335,7 +3335,7 @@ DEFPY (ip_igmp_group_watermark,
"Group count to generate watermark warning\n")
{
PIM_DECLVAR_CONTEXT_VRF(vrf, pim);
- pim->igmp_watermark_limit = limit;
+ pim->gm_watermark_limit = limit;
return CMD_SUCCESS;
}
@@ -3350,7 +3350,7 @@ DEFPY (no_ip_igmp_group_watermark,
IGNORED_IN_NO_STR)
{
PIM_DECLVAR_CONTEXT_VRF(vrf, pim);
- pim->igmp_watermark_limit = 0;
+ pim->gm_watermark_limit = 0;
return CMD_SUCCESS;
}
diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c
index 849216af62..6ffeeb9657 100644
--- a/pimd/pim_igmp.c
+++ b/pimd/pim_igmp.c
@@ -1009,8 +1009,8 @@ static void igmp_group_count_incr(struct pim_interface *pim_ifp)
uint32_t group_count = listcount(pim_ifp->gm_group_list);
++pim_ifp->pim->igmp_group_count;
- if (pim_ifp->pim->igmp_group_count
- == pim_ifp->pim->igmp_watermark_limit) {
+ if (pim_ifp->pim->igmp_group_count ==
+ pim_ifp->pim->gm_watermark_limit) {
zlog_warn(
"IGMP group count reached watermark limit: %u(vrf: %s)",
pim_ifp->pim->igmp_group_count,
diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h
index 23b9df4aff..684785dd13 100644
--- a/pimd/pim_instance.h
+++ b/pimd/pim_instance.h
@@ -173,7 +173,7 @@ struct pim_instance {
struct thread *t_gm_recv;
unsigned int igmp_group_count;
- unsigned int igmp_watermark_limit;
+ unsigned int gm_watermark_limit;
unsigned int keep_alive_time;
unsigned int rp_keep_alive_time;
diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h
index d0c4921d07..5a2647b93f 100644
--- a/pimd/pim_oil.h
+++ b/pimd/pim_oil.h
@@ -187,9 +187,6 @@ extern int pim_channel_oil_compare(const struct channel_oil *c1,
DECLARE_RBTREE_UNIQ(rb_pim_oil, struct channel_oil, oil_rb,
pim_channel_oil_compare);
-
-extern struct list *pim_channel_oil_list;
-
void pim_oil_init(struct pim_instance *pim);
void pim_oil_terminate(struct pim_instance *pim);
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index 4dd1398733..43d9c29278 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -260,9 +260,14 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty)
++writes;
}
- if (pim->igmp_watermark_limit != 0) {
- vty_out(vty, "%sip igmp watermark-warn %u\n", spaces,
- pim->igmp_watermark_limit);
+ if (pim->gm_watermark_limit != 0) {
+#if PIM_IPV == 4
+ vty_out(vty, "%s" PIM_AF_NAME " igmp watermark-warn %u\n",
+ spaces, pim->gm_watermark_limit);
+#else
+ vty_out(vty, "%s" PIM_AF_NAME " mld watermark-warn %u\n",
+ spaces, pim->gm_watermark_limit);
+#endif
++writes;
}
diff --git a/tests/topotests/bfd_profiles_topo1/r1/ospfd.conf b/tests/topotests/bfd_profiles_topo1/r1/ospfd.conf
index fcea5d48fc..373a0c5b94 100644
--- a/tests/topotests/bfd_profiles_topo1/r1/ospfd.conf
+++ b/tests/topotests/bfd_profiles_topo1/r1/ospfd.conf
@@ -2,6 +2,7 @@ interface r1-eth1
ip ospf area 0
ip ospf hello-interval 2
ip ospf dead-interval 10
+ ip ospf bfd
ip ospf bfd profile slowtx
!
router ospf
diff --git a/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf
index 8fca099686..0476df740a 100644
--- a/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf
+++ b/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf
@@ -5,7 +5,11 @@
!
bfd
peer 192.168.0.2 vrf r1-bfd-cust1
+ receive-interval 1000
+ transmit-interval 1000
echo-mode
+ echo transmit-interval 1000
+ echo receive-interval 1000
no shutdown
!
!
diff --git a/tests/topotests/bfd_vrf_topo1/r1/peers.json b/tests/topotests/bfd_vrf_topo1/r1/peers.json
index f49768ff75..57cea71e53 100644
--- a/tests/topotests/bfd_vrf_topo1/r1/peers.json
+++ b/tests/topotests/bfd_vrf_topo1/r1/peers.json
@@ -1,7 +1,7 @@
[
{
"remote-receive-interval": 1000,
- "remote-transmit-interval": 500,
+ "remote-transmit-interval": 1000,
"peer": "192.168.0.2",
"status": "up"
}
diff --git a/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf
index 4490090ec6..69edd1536b 100644
--- a/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf
+++ b/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf
@@ -6,12 +6,18 @@
bfd
peer 192.168.0.1 vrf r2-bfd-cust1
receive-interval 1000
- transmit-interval 500
+ transmit-interval 1000
echo-mode
+ echo transmit-interval 1000
+ echo receive-interval 1000
no shutdown
!
peer 192.168.1.1 vrf r2-bfd-cust1
+ receive-interval 1000
+ transmit-interval 1000
echo-mode
+ echo transmit-interval 1000
+ echo receive-interval 1000
no shutdown
!
!
diff --git a/tests/topotests/bfd_vrf_topo1/r2/peers.json b/tests/topotests/bfd_vrf_topo1/r2/peers.json
index 267459c7a8..0a1c34224b 100644
--- a/tests/topotests/bfd_vrf_topo1/r2/peers.json
+++ b/tests/topotests/bfd_vrf_topo1/r2/peers.json
@@ -4,7 +4,7 @@
"status": "up"
},
{
- "remote-echo-receive-interval": 100,
+ "remote-echo-receive-interval": 1000,
"peer": "192.168.1.1",
"status": "up"
},
diff --git a/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf
index 0333320898..00162b5247 100644
--- a/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf
+++ b/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf
@@ -5,7 +5,9 @@
!
bfd
peer 192.168.1.2 vrf r3-bfd-cust1
- echo-interval 100
+ receive-interval 1000
+ transmit-interval 1000
+ echo-interval 1000
echo-mode
no shutdown
!
diff --git a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py
index 6153aee418..1097be3d70 100644
--- a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py
+++ b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py
@@ -197,11 +197,199 @@ def teardown_module(mod):
logger.info("=" * 40)
-def test_bgp_conditional_advertisement():
- """
- Test BGP conditional advertisement functionality.
- """
+def all_routes_advertised(router):
+ output = json.loads(router.vtysh_cmd("show ip route json"))
+ expected = {
+ "0.0.0.0/0": [{"protocol": "bgp"}],
+ "192.0.2.1/32": [{"protocol": "bgp"}],
+ "192.0.2.5/32": [{"protocol": "bgp"}],
+ "10.139.224.0/20": [{"protocol": "bgp"}],
+ "203.0.113.1/32": [{"protocol": "bgp"}],
+ }
+ return topotest.json_cmp(output, expected)
+
+
+def all_routes_withdrawn(router):
+ output = json.loads(router.vtysh_cmd("show ip route json"))
+ expected = {
+ "0.0.0.0/0": None,
+ "192.0.2.1/32": None,
+ "192.0.2.5/32": None,
+ "10.139.224.0/20": None,
+ "203.0.113.1/32": None,
+ }
+ return topotest.json_cmp(output, expected)
+
+
+# BGP conditional advertisement with route-maps
+# EXIST-MAP, ADV-MAP-1 and RMAP-1
+def exist_map_routes_present(router):
+ return all_routes_advertised(router)
+
+
+def exist_map_routes_not_present(router):
+ output = json.loads(router.vtysh_cmd("show ip route json"))
+ expected = {
+ "0.0.0.0/0": None,
+ "192.0.2.1/32": None,
+ "192.0.2.5/32": [{"protocol": "bgp"}],
+ "10.139.224.0/20": None,
+ "203.0.113.1/32": [{"protocol": "bgp"}],
+ }
+ return topotest.json_cmp(output, expected)
+
+
+def non_exist_map_routes_present(router):
+ output = json.loads(router.vtysh_cmd("show ip route json"))
+ expected = {
+ "0.0.0.0/0": [{"protocol": "bgp"}],
+ "192.0.2.1/32": None,
+ "192.0.2.5/32": [{"protocol": "bgp"}],
+ "10.139.224.0/20": None,
+ "203.0.113.1/32": [{"protocol": "bgp"}],
+ }
+ return topotest.json_cmp(output, expected)
+
+
+def non_exist_map_routes_not_present(router):
+ output = json.loads(router.vtysh_cmd("show ip route json"))
+ expected = {
+ "0.0.0.0/0": None,
+ "192.0.2.1/32": [{"protocol": "bgp"}],
+ "192.0.2.5/32": [{"protocol": "bgp"}],
+ "10.139.224.0/20": [{"protocol": "bgp"}],
+ "203.0.113.1/32": [{"protocol": "bgp"}],
+ }
+ return topotest.json_cmp(output, expected)
+
+
+def exist_map_no_condition_route_map(router):
+ return non_exist_map_routes_present(router)
+
+
+def non_exist_map_no_condition_route_map(router):
+ return all_routes_advertised(router)
+
+
+def exist_map_routes_present_rmap_filter(router):
+ output = json.loads(router.vtysh_cmd("show ip route json"))
+ expected = {
+ "0.0.0.0/0": None,
+ "192.0.2.1/32": [{"protocol": "bgp"}],
+ "192.0.2.5/32": None,
+ "10.139.224.0/20": [{"protocol": "bgp"}],
+ "203.0.113.1/32": None,
+ }
+ return topotest.json_cmp(output, expected)
+
+
+def exist_map_routes_present_no_rmap_filter(router):
+ return all_routes_advertised(router)
+
+
+def non_exist_map_routes_present_rmap_filter(router):
+ return all_routes_withdrawn(router)
+
+
+def non_exist_map_routes_present_no_rmap_filter(router):
+ return non_exist_map_routes_present(router)
+
+
+def exist_map_routes_not_present_rmap_filter(router):
+ return all_routes_withdrawn(router)
+
+
+def exist_map_routes_not_present_no_rmap_filter(router):
+ return exist_map_routes_not_present(router)
+
+
+def non_exist_map_routes_not_present_rmap_filter(router):
+ return exist_map_routes_present_rmap_filter(router)
+
+
+def non_exist_map_routes_not_present_no_rmap_filter(router):
+ return non_exist_map_routes_not_present(router)
+
+
+# BGP conditional advertisement with route-maps
+# EXIST-MAP, ADV-MAP-2 and RMAP-2
+def exist_map_routes_not_present_rmap2_filter(router):
+ return all_routes_withdrawn(router)
+
+
+def exist_map_routes_not_present_no_rmap2_filter(router):
+ output = json.loads(router.vtysh_cmd("show ip route json"))
+ expected = {
+ "0.0.0.0/0": None,
+ "192.0.2.1/32": [{"protocol": "bgp"}],
+ "192.0.2.5/32": [{"protocol": "bgp"}],
+ "10.139.224.0/20": [{"protocol": "bgp"}],
+ "203.0.113.1/32": None,
+ }
+ return topotest.json_cmp(output, expected)
+
+
+def non_exist_map_routes_not_present_rmap2_filter(router):
+ output = json.loads(router.vtysh_cmd("show ip route json"))
+ expected = {
+ "0.0.0.0/0": None,
+ "192.0.2.1/32": None,
+ "192.0.2.5/32": None,
+ "10.139.224.0/20": None,
+ "203.0.113.1/32": [{"protocol": "bgp", "metric": 911}],
+ }
+ return topotest.json_cmp(output, expected)
+
+def non_exist_map_routes_not_present_no_rmap2_filter(router):
+ return non_exist_map_routes_not_present(router)
+
+
+def exist_map_routes_present_rmap2_filter(router):
+ return non_exist_map_routes_not_present_rmap2_filter(router)
+
+
+def exist_map_routes_present_no_rmap2_filter(router):
+ return all_routes_advertised(router)
+
+
+def non_exist_map_routes_present_rmap2_filter(router):
+ return all_routes_withdrawn(router)
+
+
+def non_exist_map_routes_present_no_rmap2_filter(router):
+ output = json.loads(router.vtysh_cmd("show ip route json"))
+ expected = {
+ "0.0.0.0/0": [{"protocol": "bgp"}],
+ "192.0.2.1/32": [{"protocol": "bgp"}],
+ "192.0.2.5/32": [{"protocol": "bgp"}],
+ "10.139.224.0/20": [{"protocol": "bgp"}],
+ "203.0.113.1/32": None,
+ }
+ return topotest.json_cmp(output, expected)
+
+
+def exist_map_routes_present_rmap2_network(router):
+ return non_exist_map_routes_not_present_rmap2_filter(router)
+
+
+def exist_map_routes_present_rmap2_no_network(router):
+ return all_routes_withdrawn(router)
+
+
+def non_exist_map_routes_not_present_rmap2_network(router):
+ return non_exist_map_routes_not_present_rmap2_filter(router)
+
+
+def non_exist_map_routes_not_present_rmap2_no_network(router):
+ return all_routes_withdrawn(router)
+
+
+passed = "PASSED!!!"
+failed = "FAILED!!!"
+
+
+def test_bgp_conditional_advertisement_step1():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -210,172 +398,9 @@ def test_bgp_conditional_advertisement():
router2 = tgen.gears["r2"]
router3 = tgen.gears["r3"]
- passed = "PASSED!!!"
- failed = "FAILED!!!"
-
- def _all_routes_advertised(router):
- output = json.loads(router.vtysh_cmd("show ip route json"))
- expected = {
- "0.0.0.0/0": [{"protocol": "bgp"}],
- "192.0.2.1/32": [{"protocol": "bgp"}],
- "192.0.2.5/32": [{"protocol": "bgp"}],
- "10.139.224.0/20": [{"protocol": "bgp"}],
- "203.0.113.1/32": [{"protocol": "bgp"}],
- }
- return topotest.json_cmp(output, expected)
-
- def _all_routes_withdrawn(router):
- output = json.loads(router.vtysh_cmd("show ip route json"))
- expected = {
- "0.0.0.0/0": None,
- "192.0.2.1/32": None,
- "192.0.2.5/32": None,
- "10.139.224.0/20": None,
- "203.0.113.1/32": None,
- }
- return topotest.json_cmp(output, expected)
-
- # BGP conditional advertisement with route-maps
- # EXIST-MAP, ADV-MAP-1 and RMAP-1
- def _exist_map_routes_present(router):
- return _all_routes_advertised(router)
-
- def _exist_map_routes_not_present(router):
- output = json.loads(router.vtysh_cmd("show ip route json"))
- expected = {
- "0.0.0.0/0": None,
- "192.0.2.1/32": None,
- "192.0.2.5/32": [{"protocol": "bgp"}],
- "10.139.224.0/20": None,
- "203.0.113.1/32": [{"protocol": "bgp"}],
- }
- return topotest.json_cmp(output, expected)
-
- def _non_exist_map_routes_present(router):
- output = json.loads(router.vtysh_cmd("show ip route json"))
- expected = {
- "0.0.0.0/0": [{"protocol": "bgp"}],
- "192.0.2.1/32": None,
- "192.0.2.5/32": [{"protocol": "bgp"}],
- "10.139.224.0/20": None,
- "203.0.113.1/32": [{"protocol": "bgp"}],
- }
- return topotest.json_cmp(output, expected)
-
- def _non_exist_map_routes_not_present(router):
- output = json.loads(router.vtysh_cmd("show ip route json"))
- expected = {
- "0.0.0.0/0": None,
- "192.0.2.1/32": [{"protocol": "bgp"}],
- "192.0.2.5/32": [{"protocol": "bgp"}],
- "10.139.224.0/20": [{"protocol": "bgp"}],
- "203.0.113.1/32": [{"protocol": "bgp"}],
- }
- return topotest.json_cmp(output, expected)
-
- def _exist_map_no_condition_route_map(router):
- return _non_exist_map_routes_present(router)
-
- def _non_exist_map_no_condition_route_map(router):
- return _all_routes_advertised(router)
-
- def _exist_map_routes_present_rmap_filter(router):
- output = json.loads(router.vtysh_cmd("show ip route json"))
- expected = {
- "0.0.0.0/0": None,
- "192.0.2.1/32": [{"protocol": "bgp"}],
- "192.0.2.5/32": None,
- "10.139.224.0/20": [{"protocol": "bgp"}],
- "203.0.113.1/32": None,
- }
- return topotest.json_cmp(output, expected)
-
- def _exist_map_routes_present_no_rmap_filter(router):
- return _all_routes_advertised(router)
-
- def _non_exist_map_routes_present_rmap_filter(router):
- return _all_routes_withdrawn(router)
-
- def _non_exist_map_routes_present_no_rmap_filter(router):
- return _non_exist_map_routes_present(router)
-
- def _exist_map_routes_not_present_rmap_filter(router):
- return _all_routes_withdrawn(router)
-
- def _exist_map_routes_not_present_no_rmap_filter(router):
- return _exist_map_routes_not_present(router)
-
- def _non_exist_map_routes_not_present_rmap_filter(router):
- return _exist_map_routes_present_rmap_filter(router)
-
- def _non_exist_map_routes_not_present_no_rmap_filter(router):
- return _non_exist_map_routes_not_present(router)
-
- # BGP conditional advertisement with route-maps
- # EXIST-MAP, ADV-MAP-2 and RMAP-2
- def _exist_map_routes_not_present_rmap2_filter(router):
- return _all_routes_withdrawn(router)
-
- def _exist_map_routes_not_present_no_rmap2_filter(router):
- output = json.loads(router.vtysh_cmd("show ip route json"))
- expected = {
- "0.0.0.0/0": None,
- "192.0.2.1/32": [{"protocol": "bgp"}],
- "192.0.2.5/32": [{"protocol": "bgp"}],
- "10.139.224.0/20": [{"protocol": "bgp"}],
- "203.0.113.1/32": None,
- }
- return topotest.json_cmp(output, expected)
-
- def _non_exist_map_routes_not_present_rmap2_filter(router):
- output = json.loads(router.vtysh_cmd("show ip route json"))
- expected = {
- "0.0.0.0/0": None,
- "192.0.2.1/32": None,
- "192.0.2.5/32": None,
- "10.139.224.0/20": None,
- "203.0.113.1/32": [{"protocol": "bgp", "metric": 911}],
- }
- return topotest.json_cmp(output, expected)
-
- def _non_exist_map_routes_not_present_no_rmap2_filter(router):
- return _non_exist_map_routes_not_present(router)
-
- def _exist_map_routes_present_rmap2_filter(router):
- return _non_exist_map_routes_not_present_rmap2_filter(router)
-
- def _exist_map_routes_present_no_rmap2_filter(router):
- return _all_routes_advertised(router)
-
- def _non_exist_map_routes_present_rmap2_filter(router):
- return _all_routes_withdrawn(router)
-
- def _non_exist_map_routes_present_no_rmap2_filter(router):
- output = json.loads(router.vtysh_cmd("show ip route json"))
- expected = {
- "0.0.0.0/0": [{"protocol": "bgp"}],
- "192.0.2.1/32": [{"protocol": "bgp"}],
- "192.0.2.5/32": [{"protocol": "bgp"}],
- "10.139.224.0/20": [{"protocol": "bgp"}],
- "203.0.113.1/32": None,
- }
- return topotest.json_cmp(output, expected)
-
- def _exist_map_routes_present_rmap2_network(router):
- return _non_exist_map_routes_not_present_rmap2_filter(router)
-
- def _exist_map_routes_present_rmap2_no_network(router):
- return _all_routes_withdrawn(router)
-
- def _non_exist_map_routes_not_present_rmap2_network(router):
- return _non_exist_map_routes_not_present_rmap2_filter(router)
-
- def _non_exist_map_routes_not_present_rmap2_no_network(router):
- return _all_routes_withdrawn(router)
-
# TC11: R3 BGP convergence, without advertise-map configuration.
# All routes are advertised to R3.
- test_func = functools.partial(_all_routes_advertised, router3)
+ test_func = functools.partial(all_routes_advertised, router3)
success, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
msg = 'TC11: "router3" BGP convergence - '
@@ -383,6 +408,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step2():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC21: exist-map routes present in R2's BGP table.
# advertise-map routes present in R2's BGP table are advertised to R3.
router2.vtysh_cmd(
@@ -394,7 +429,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_exist_map_routes_present, router3)
+ test_func = functools.partial(exist_map_routes_present, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = 'TC21: exist-map routes present in "router2" BGP table - '
@@ -402,6 +437,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step3():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC22: exist-map routes not present in R2's BGP table
# advertise-map routes present in R2's BGP table are withdrawn from R3.
router1.vtysh_cmd(
@@ -413,7 +458,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_exist_map_routes_not_present, router3)
+ test_func = functools.partial(exist_map_routes_not_present, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = 'TC22: exist-map routes not present in "router2" BGP table - '
@@ -421,6 +466,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step4():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC31: non-exist-map routes not present in R2's BGP table
# advertise-map routes present in R2's BGP table are advertised to R3.
router2.vtysh_cmd(
@@ -432,7 +487,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_non_exist_map_routes_not_present, router3)
+ test_func = functools.partial(non_exist_map_routes_not_present, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = 'TC31: non-exist-map routes not present in "router2" BGP table - '
@@ -440,6 +495,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step5():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC32: non-exist-map routes present in R2's BGP table
# advertise-map routes present in R2's BGP table are withdrawn from R3.
router1.vtysh_cmd(
@@ -451,7 +516,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_non_exist_map_routes_present, router3)
+ test_func = functools.partial(non_exist_map_routes_present, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = 'TC32: non-exist-map routes present in "router2" BGP table - '
@@ -459,6 +524,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step6():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC41: non-exist-map route-map configuration removed in R2.
# advertise-map routes present in R2's BGP table are advertised to R3.
router2.vtysh_cmd(
@@ -468,7 +543,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_non_exist_map_no_condition_route_map, router3)
+ test_func = functools.partial(non_exist_map_no_condition_route_map, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = 'TC41: non-exist-map route-map removed in "router2" - '
@@ -476,6 +551,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step7():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC42: exist-map route-map configuration removed in R2
# advertise-map routes present in R2's BGP table are withdrawn from R3.
router2.vtysh_cmd(
@@ -487,7 +572,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_exist_map_no_condition_route_map, router3)
+ test_func = functools.partial(exist_map_no_condition_route_map, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = 'TC42: exist-map route-map removed in "router2" - '
@@ -495,6 +580,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step8():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC51: exist-map routes present in R2's BGP table, with route-map filter.
# All routes are withdrawn from R3 except advertise-map routes.
router2.vtysh_cmd(
@@ -510,7 +605,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_exist_map_routes_present_rmap_filter, router3)
+ test_func = functools.partial(exist_map_routes_present_rmap_filter, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = "TC51: exist-map routes present with route-map filter - "
@@ -518,6 +613,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step9():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC52: exist-map routes present in R2's BGP table, no route-map filter.
# All routes are advertised to R3 including advertise-map routes.
router2.vtysh_cmd(
@@ -529,7 +634,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_exist_map_routes_present_no_rmap_filter, router3)
+ test_func = functools.partial(exist_map_routes_present_no_rmap_filter, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = "TC52: exist-map routes present, no route-map filter - "
@@ -537,6 +642,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step10():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC53: non-exist-map routes present in R2's BGP table, with route-map filter.
# All routes are withdrawn from R3 including advertise-map routes.
router2.vtysh_cmd(
@@ -549,7 +664,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_non_exist_map_routes_present_rmap_filter, router3)
+ test_func = functools.partial(non_exist_map_routes_present_rmap_filter, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = "TC53: non-exist-map routes present, with route-map filter - "
@@ -557,6 +672,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step11():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC54: non-exist-map routes present in R2's BGP table, no route-map filter.
# All routes are advertised to R3 except advertise-map routes.
router2.vtysh_cmd(
@@ -568,7 +693,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_non_exist_map_routes_present_no_rmap_filter, router3)
+ test_func = functools.partial(non_exist_map_routes_present_no_rmap_filter, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = "TC54: non-exist-map routes present, no route-map filter - "
@@ -576,6 +701,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step12():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC61: exist-map routes not present in R2's BGP table, with route-map filter.
# All routes are withdrawn from R3 including advertise-map routes.
router1.vtysh_cmd(
@@ -596,7 +731,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_exist_map_routes_not_present_rmap_filter, router3)
+ test_func = functools.partial(exist_map_routes_not_present_rmap_filter, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = "TC61: exist-map routes not present, route-map filter - "
@@ -604,6 +739,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step13():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC62: exist-map routes not present in R2's BGP table, without route-map filter.
# All routes are advertised to R3 except advertise-map routes.
router2.vtysh_cmd(
@@ -615,7 +760,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_exist_map_routes_not_present_no_rmap_filter, router3)
+ test_func = functools.partial(exist_map_routes_not_present_no_rmap_filter, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = "TC62: exist-map routes not present, no route-map filter - "
@@ -623,6 +768,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step14():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC63: non-exist-map routes not present in R2's BGP table, with route-map filter.
# All routes are withdrawn from R3 except advertise-map routes.
router2.vtysh_cmd(
@@ -635,9 +790,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(
- _non_exist_map_routes_not_present_rmap_filter, router3
- )
+ test_func = functools.partial(non_exist_map_routes_not_present_rmap_filter, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = "TC63: non-exist-map routes not present, route-map filter - "
@@ -645,6 +798,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step15():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC64: non-exist-map routes not present in R2's BGP table, without route-map filter.
# All routes are advertised to R3 including advertise-map routes.
router2.vtysh_cmd(
@@ -657,7 +820,7 @@ def test_bgp_conditional_advertisement():
)
test_func = functools.partial(
- _non_exist_map_routes_not_present_no_rmap_filter, router3
+ non_exist_map_routes_not_present_no_rmap_filter, router3
)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
@@ -666,6 +829,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step16():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC71: exist-map routes present in R2's BGP table, with route-map filter.
# All routes are withdrawn from R3 except advertise-map routes.
router1.vtysh_cmd(
@@ -686,7 +859,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_exist_map_routes_present_rmap2_filter, router3)
+ test_func = functools.partial(exist_map_routes_present_rmap2_filter, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = "TC71: exist-map routes present, route-map filter - "
@@ -694,6 +867,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step17():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC72: exist-map routes present in R2's BGP table, without route-map filter.
# All routes are advertised to R3 including advertise-map routes.
router2.vtysh_cmd(
@@ -705,7 +888,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_exist_map_routes_present_no_rmap2_filter, router3)
+ test_func = functools.partial(exist_map_routes_present_no_rmap2_filter, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = "TC72: exist-map routes present, no route-map filter - "
@@ -713,6 +896,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step18():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC73: non-exist-map routes present in R2's BGP table, with route-map filter.
# All routes are advertised to R3 including advertise-map routes.
router2.vtysh_cmd(
@@ -725,7 +918,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_non_exist_map_routes_present_rmap2_filter, router3)
+ test_func = functools.partial(non_exist_map_routes_present_rmap2_filter, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = "TC73: non-exist-map routes present, route-map filter - "
@@ -733,6 +926,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step19():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC74: non-exist-map routes present in R2's BGP table, without route-map filter.
# All routes are advertised to R3 including advertise-map routes.
router2.vtysh_cmd(
@@ -744,9 +947,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(
- _non_exist_map_routes_present_no_rmap2_filter, router3
- )
+ test_func = functools.partial(non_exist_map_routes_present_no_rmap2_filter, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = "TC74: non-exist-map routes present, no route-map filter - "
@@ -754,6 +955,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step20():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC81: exist-map routes not present in R2's BGP table, with route-map filter.
# All routes are withdrawn from R3 including advertise-map routes.
router1.vtysh_cmd(
@@ -774,7 +985,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_exist_map_routes_not_present_rmap2_filter, router3)
+ test_func = functools.partial(exist_map_routes_not_present_rmap2_filter, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = "TC81: exist-map routes not present, route-map filter - "
@@ -782,6 +993,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step21():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC82: exist-map routes not present in R2's BGP table, without route-map filter.
# All routes are advertised to R3 except advertise-map routes.
router2.vtysh_cmd(
@@ -793,9 +1014,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(
- _exist_map_routes_not_present_no_rmap2_filter, router3
- )
+ test_func = functools.partial(exist_map_routes_not_present_no_rmap2_filter, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = "TC82: exist-map routes not present, no route-map filter - "
@@ -803,6 +1022,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step22():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC83: non-exist-map routes not present in R2's BGP table, with route-map filter.
# All routes are advertised to R3 including advertise-map routes.
router2.vtysh_cmd(
@@ -816,7 +1045,7 @@ def test_bgp_conditional_advertisement():
)
test_func = functools.partial(
- _non_exist_map_routes_not_present_rmap2_filter, router3
+ non_exist_map_routes_not_present_rmap2_filter, router3
)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
@@ -825,6 +1054,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step23():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC84: non-exist-map routes not present in R2's BGP table, without route-map filter.
# All routes are advertised to R3 including advertise-map routes.
router2.vtysh_cmd(
@@ -837,7 +1076,7 @@ def test_bgp_conditional_advertisement():
)
test_func = functools.partial(
- _non_exist_map_routes_not_present_no_rmap2_filter, router3
+ non_exist_map_routes_not_present_no_rmap2_filter, router3
)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
@@ -846,6 +1085,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step24():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC91: exist-map routes present in R2's BGP table, with route-map filter and network.
# All routes are advertised to R3 including advertise-map routes.
router1.vtysh_cmd(
@@ -866,7 +1115,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_exist_map_routes_present_rmap2_network, router3)
+ test_func = functools.partial(exist_map_routes_present_rmap2_network, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = "TC91: exist-map routes present, route-map filter and network - "
@@ -874,6 +1123,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step25():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC92: exist-map routes present in R2's BGP table, with route-map filter and no network.
# All routes are advertised to R3 except advertise-map routes.
router2.vtysh_cmd(
@@ -885,7 +1144,7 @@ def test_bgp_conditional_advertisement():
"""
)
- test_func = functools.partial(_exist_map_routes_present_rmap2_no_network, router3)
+ test_func = functools.partial(exist_map_routes_present_rmap2_no_network, router3)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
msg = "TC92: exist-map routes present, route-map filter and no network - "
@@ -893,6 +1152,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step26():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC93: non-exist-map routes not present in R2's BGP table, with route-map filter and network.
# All routes are advertised to R3 including advertise-map routes.
router1.vtysh_cmd(
@@ -914,7 +1183,7 @@ def test_bgp_conditional_advertisement():
)
test_func = functools.partial(
- _non_exist_map_routes_not_present_rmap2_network, router3
+ non_exist_map_routes_not_present_rmap2_network, router3
)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
@@ -923,6 +1192,16 @@ def test_bgp_conditional_advertisement():
logger.info(msg + passed)
+
+def test_bgp_conditional_advertisement_step27():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
# TC94: non-exist-map routes not present in R2's BGP table, with route-map filter and no network.
# All routes are advertised to R3 except advertise-map routes.
router2.vtysh_cmd(
@@ -935,7 +1214,7 @@ def test_bgp_conditional_advertisement():
)
test_func = functools.partial(
- _non_exist_map_routes_not_present_rmap2_no_network, router3
+ non_exist_map_routes_not_present_rmap2_no_network, router3
)
success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
diff --git a/tests/topotests/bgp_ipv4_class_e_peer/__init__.py b/tests/topotests/bgp_ipv4_class_e_peer/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_ipv4_class_e_peer/__init__.py
diff --git a/tests/topotests/bgp_ipv4_class_e_peer/r1/bgpd.conf b/tests/topotests/bgp_ipv4_class_e_peer/r1/bgpd.conf
new file mode 100644
index 0000000000..bf0a68eea2
--- /dev/null
+++ b/tests/topotests/bgp_ipv4_class_e_peer/r1/bgpd.conf
@@ -0,0 +1,12 @@
+!
+allow-reserved-ranges
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 240.0.0.2 remote-as external
+ neighbor 240.0.0.2 timers 1 3
+ neighbor 240.0.0.2 timers connect 1
+ address-family ipv4
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_ipv4_class_e_peer/r1/zebra.conf b/tests/topotests/bgp_ipv4_class_e_peer/r1/zebra.conf
new file mode 100644
index 0000000000..d4ac46f248
--- /dev/null
+++ b/tests/topotests/bgp_ipv4_class_e_peer/r1/zebra.conf
@@ -0,0 +1,11 @@
+!
+allow-reserved-ranges
+!
+interface lo
+ ip address 172.16.255.1/32
+!
+interface r1-eth0
+ ip address 240.0.0.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_ipv4_class_e_peer/r2/bgpd.conf b/tests/topotests/bgp_ipv4_class_e_peer/r2/bgpd.conf
new file mode 100644
index 0000000000..7d08963633
--- /dev/null
+++ b/tests/topotests/bgp_ipv4_class_e_peer/r2/bgpd.conf
@@ -0,0 +1,9 @@
+!
+allow-reserved-ranges
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 240.0.0.1 remote-as external
+ neighbor 240.0.0.1 timers 1 3
+ neighbor 240.0.0.1 timers connect 1
+!
diff --git a/tests/topotests/bgp_ipv4_class_e_peer/r2/zebra.conf b/tests/topotests/bgp_ipv4_class_e_peer/r2/zebra.conf
new file mode 100644
index 0000000000..f0a350fcea
--- /dev/null
+++ b/tests/topotests/bgp_ipv4_class_e_peer/r2/zebra.conf
@@ -0,0 +1,8 @@
+!
+allow-reserved-ranges
+!
+interface r2-eth0
+ ip address 240.0.0.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py b/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py
new file mode 100644
index 0000000000..c2f0d2e0dc
--- /dev/null
+++ b/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py
@@ -0,0 +1,127 @@
+#!/usr/bin/env python
+
+#
+# bgp_ipv4_class_e_peer.py
+#
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Check if the peering works by using IPv4 Class E IP ranges, and if
+we don't treat next-hop as martian in such a case.
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ for routern in range(1, 3):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_ipv4_class_e_peer():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router = tgen.gears["r2"]
+
+ def _bgp_converge():
+ output = json.loads(router.vtysh_cmd("show ip bgp neighbor 240.0.0.1 json"))
+ expected = {
+ "240.0.0.1": {
+ "bgpState": "Established",
+ "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 2}},
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_next_hop_ipv4_class_e():
+ output = json.loads(
+ router.vtysh_cmd("show bgp ipv4 unicast 172.16.255.1/32 json")
+ )
+ expected = {
+ "paths": [
+ {
+ "valid": True,
+ "nexthops": [
+ {
+ "ip": "240.0.0.1",
+ "accessible": True,
+ }
+ ],
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ step("Initial BGP converge")
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to see BGP convergence on R2"
+
+ step("Check if IPv4 BGP peering works with Class E IP ranges")
+ test_func = functools.partial(_bgp_next_hop_ipv4_class_e)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to see 172.16.255.1/32 via 240.0.0.1 on R2"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index 0e9e0ba403..4afa86f740 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -3437,8 +3437,23 @@ def verify_rib(
found_hops = [
rib_r["ip"]
for rib_r in rib_routes_json[st_rt][0]["nexthops"]
+ if "ip" in rib_r
]
+ # If somehow key "ip" is not found in nexthops JSON
+ # then found_hops would be 0, this particular
+ # situation will be handled here
+ if not len(found_hops):
+ errormsg = (
+ "Nexthop {} is Missing for "
+ "route {} in RIB of router {}\n".format(
+ next_hop,
+ st_rt,
+ dut,
+ )
+ )
+ return errormsg
+
# Check only the count of nexthops
if count_only:
if len(next_hop) == len(found_hops):
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index a52bd7b116..21bd2f4883 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -3140,6 +3140,20 @@ DEFUN(vtysh_debug_uid_backtrace,
return err;
}
+DEFUNSH(VTYSH_ALL, vtysh_allow_reserved_ranges, vtysh_allow_reserved_ranges_cmd,
+ "allow-reserved-ranges",
+ "Allow using IPv4 (Class E) reserved IP space\n")
+{
+ return CMD_SUCCESS;
+}
+
+DEFUNSH(VTYSH_ALL, no_vtysh_allow_reserved_ranges,
+ no_vtysh_allow_reserved_ranges_cmd, "no allow-reserved-ranges",
+ NO_STR "Allow using IPv4 (Class E) reserved IP space\n")
+{
+ return CMD_SUCCESS;
+}
+
DEFUNSH(VTYSH_ALL, vtysh_service_password_encrypt,
vtysh_service_password_encrypt_cmd, "service password-encryption",
"Set up miscellaneous service\n"
@@ -4902,6 +4916,9 @@ void vtysh_init_vty(void)
install_element(CONFIG_NODE, &vtysh_service_password_encrypt_cmd);
install_element(CONFIG_NODE, &no_vtysh_service_password_encrypt_cmd);
+ install_element(CONFIG_NODE, &vtysh_allow_reserved_ranges_cmd);
+ install_element(CONFIG_NODE, &no_vtysh_allow_reserved_ranges_cmd);
+
install_element(CONFIG_NODE, &vtysh_password_cmd);
install_element(CONFIG_NODE, &no_vtysh_password_cmd);
install_element(CONFIG_NODE, &vtysh_enable_password_cmd);
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index 3bd5489eef..a7ec2a93c2 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -478,14 +478,18 @@ void vtysh_config_parse_line(void *arg, const char *line)
else if (strncmp(line, "rpki", strlen("rpki")) == 0)
config = config_get(RPKI_NODE, line);
else {
- if (strncmp(line, "log", strlen("log")) == 0
- || strncmp(line, "hostname", strlen("hostname")) == 0
- || strncmp(line, "domainname", strlen("domainname")) == 0
- || strncmp(line, "frr", strlen("frr")) == 0
- || strncmp(line, "agentx", strlen("agentx")) == 0
- || strncmp(line, "no log", strlen("no log")) == 0
- || strncmp(line, "no ip prefix-list", strlen("no ip prefix-list")) == 0
- || strncmp(line, "no ipv6 prefix-list", strlen("no ipv6 prefix-list")) == 0)
+ if (strncmp(line, "log", strlen("log")) == 0 ||
+ strncmp(line, "hostname", strlen("hostname")) ==
+ 0 ||
+ strncmp(line, "domainname", strlen("domainname")) ==
+ 0 ||
+ strncmp(line, "frr", strlen("frr")) == 0 ||
+ strncmp(line, "agentx", strlen("agentx")) == 0 ||
+ strncmp(line, "no log", strlen("no log")) == 0 ||
+ strncmp(line, "no ip prefix-list",
+ strlen("no ip prefix-list")) == 0 ||
+ strncmp(line, "no ipv6 prefix-list",
+ strlen("no ipv6 prefix-list")) == 0)
config_add_line_uniq(config_top, line);
else
config_add_line(config_top, line);
diff --git a/zebra/interface.c b/zebra/interface.c
index 9800e64503..de7db2d48f 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -1504,7 +1504,7 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx)
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: can't find zns id %u", __func__, ns_id);
- goto done;
+ return;
}
ifp = if_lookup_by_index_per_ns(zns, ifindex);
@@ -1516,7 +1516,7 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx)
"%s: can't find ifp at nsid %u index %d",
__func__, ns_id, ifindex);
- goto done;
+ return;
}
}
@@ -1578,8 +1578,6 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_GRE_SET:
break; /* should never hit here */
}
-done:
- dplane_ctx_fini(&ctx);
}
/* Dump if address information to vty. */
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index 4bd0ac27f6..31d8294a0f 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -290,9 +290,20 @@ static int netlink_recvbuf(struct nlsock *nl, uint32_t newsize)
return 0;
}
+static const char *group2str(uint32_t group)
+{
+ switch (group) {
+ case RTNLGRP_TUNNEL:
+ return "RTNLGRP_TUNNEL";
+ default:
+ return "UNKNOWN";
+ }
+}
+
/* Make socket for Linux netlink interface. */
static int netlink_socket(struct nlsock *nl, unsigned long groups,
- unsigned long ext_groups, ns_id_t ns_id)
+ uint32_t ext_groups[], uint8_t ext_group_size,
+ ns_id_t ns_id)
{
int ret;
struct sockaddr_nl snl;
@@ -311,18 +322,30 @@ static int netlink_socket(struct nlsock *nl, unsigned long groups,
snl.nl_family = AF_NETLINK;
snl.nl_groups = groups;
+ if (ext_group_size) {
+ uint8_t i;
+
+ for (i = 0; i < ext_group_size; i++) {
#if defined SOL_NETLINK
- if (ext_groups) {
- ret = setsockopt(sock, SOL_NETLINK,
- NETLINK_ADD_MEMBERSHIP, &ext_groups,
- sizeof(ext_groups));
- if (ret < 0) {
+ ret = setsockopt(sock, SOL_NETLINK,
+ NETLINK_ADD_MEMBERSHIP,
+ &ext_groups[i],
+ sizeof(ext_groups[i]));
+ if (ret < 0) {
+ zlog_notice(
+ "can't setsockopt NETLINK_ADD_MEMBERSHIP for group %s(%u), this linux kernel does not support it: %s(%d)",
+ group2str(ext_groups[i]),
+ ext_groups[i],
+ safe_strerror(errno), errno);
+ }
+#else
zlog_notice(
- "can't setsockopt NETLINK_ADD_MEMBERSHIP: %s(%d)",
- safe_strerror(errno), errno);
+ "Unable to use NETLINK_ADD_MEMBERSHIP via SOL_NETLINK for %s(%u) since the linux kernel does not support the socket option",
+ group2str(ext_groups[i]),
+ ext_groups[i]);
+#endif
}
}
-#endif
/* Bind the socket to the netlink structure for anything. */
ret = bind(sock, (struct sockaddr *)&snl, sizeof(snl));
@@ -1734,7 +1757,8 @@ void kernel_init(struct zebra_ns *zns)
snprintf(zns->netlink.name, sizeof(zns->netlink.name),
"netlink-listen (NS %u)", zns->ns_id);
zns->netlink.sock = -1;
- if (netlink_socket(&zns->netlink, groups, ext_groups, zns->ns_id) < 0) {
+ if (netlink_socket(&zns->netlink, groups, &ext_groups, 1, zns->ns_id) <
+ 0) {
zlog_err("Failure to create %s socket",
zns->netlink.name);
exit(-1);
@@ -1745,7 +1769,7 @@ void kernel_init(struct zebra_ns *zns)
snprintf(zns->netlink_cmd.name, sizeof(zns->netlink_cmd.name),
"netlink-cmd (NS %u)", zns->ns_id);
zns->netlink_cmd.sock = -1;
- if (netlink_socket(&zns->netlink_cmd, 0, 0, zns->ns_id) < 0) {
+ if (netlink_socket(&zns->netlink_cmd, 0, 0, 0, zns->ns_id) < 0) {
zlog_err("Failure to create %s socket",
zns->netlink_cmd.name);
exit(-1);
@@ -1758,7 +1782,7 @@ void kernel_init(struct zebra_ns *zns)
sizeof(zns->netlink_dplane_out.name), "netlink-dp (NS %u)",
zns->ns_id);
zns->netlink_dplane_out.sock = -1;
- if (netlink_socket(&zns->netlink_dplane_out, 0, 0, zns->ns_id) < 0) {
+ if (netlink_socket(&zns->netlink_dplane_out, 0, 0, 0, zns->ns_id) < 0) {
zlog_err("Failure to create %s socket",
zns->netlink_dplane_out.name);
exit(-1);
@@ -1771,7 +1795,7 @@ void kernel_init(struct zebra_ns *zns)
sizeof(zns->netlink_dplane_in.name), "netlink-dp-in (NS %u)",
zns->ns_id);
zns->netlink_dplane_in.sock = -1;
- if (netlink_socket(&zns->netlink_dplane_in, dplane_groups, 0,
+ if (netlink_socket(&zns->netlink_dplane_in, dplane_groups, 0, 0,
zns->ns_id) < 0) {
zlog_err("Failure to create %s socket",
zns->netlink_dplane_in.name);
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index 57fd304ae8..2741a23242 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -1354,6 +1354,16 @@ static void kernel_read(struct thread *thread)
if (nbytes < 0) {
if (errno == ENOBUFS) {
+#ifdef __FreeBSD__
+ /*
+ * ENOBUFS indicates a temporary resource
+ * shortage and is not harmful for consistency of
+ * reading the routing socket. Ignore it.
+ */
+ thread_add_read(zrouter.master, kernel_read, NULL, sock,
+ NULL);
+ return;
+#else
flog_err(EC_ZEBRA_RECVMSG_OVERRUN,
"routing socket overrun: %s",
safe_strerror(errno));
@@ -1363,6 +1373,7 @@ static void kernel_read(struct thread *thread)
* recover zebra at this point.
*/
exit(-1);
+#endif
}
if (errno != EAGAIN && errno != EWOULDBLOCK)
flog_err_sys(EC_LIB_SOCKET, "routing socket error: %s",
diff --git a/zebra/main.c b/zebra/main.c
index e516688a19..46cf2eea7d 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -71,9 +71,6 @@ struct thread_master *master;
/* Route retain mode flag. */
int retain_mode = 0;
-/* Allow non-frr entities to delete frr routes */
-int allow_delete = 0;
-
int graceful_restart;
bool v6_rr_semantics = false;
@@ -336,7 +333,7 @@ int main(int argc, char **argv)
// batch_mode = 1;
break;
case 'a':
- allow_delete = 1;
+ zrouter.allow_delete = true;
break;
case 'e': {
unsigned long int parsed_multipath =
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 21c991c7db..ce06f1683d 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -341,6 +341,22 @@ static inline int proto2zebra(int proto, int family, bool is_nexthop)
case RTPROT_SRTE:
proto = ZEBRA_ROUTE_SRTE;
break;
+ case RTPROT_UNSPEC:
+ case RTPROT_REDIRECT:
+ case RTPROT_KERNEL:
+ case RTPROT_BOOT:
+ case RTPROT_GATED:
+ case RTPROT_RA:
+ case RTPROT_MRT:
+ case RTPROT_BIRD:
+ case RTPROT_DNROUTED:
+ case RTPROT_XORP:
+ case RTPROT_NTK:
+ case RTPROT_MROUTED:
+ case RTPROT_KEEPALIVED:
+ case RTPROT_OPENR:
+ proto = ZEBRA_ROUTE_KERNEL;
+ break;
case RTPROT_ZEBRA:
if (is_nexthop) {
proto = ZEBRA_ROUTE_NHG;
@@ -977,8 +993,19 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
if (nhe_id || ng)
rib_add_multipath(afi, SAFI_UNICAST, &p,
&src_p, re, ng, startup);
- else
+ else {
+ /*
+ * I really don't see how this is possible
+ * but since we are testing for it let's
+ * let the end user know why the route
+ * that was just received was swallowed
+ * up and forgotten
+ */
+ zlog_err(
+ "%s: %pFX multipath RTM_NEWROUTE has a invalid nexthop group from the kernel",
+ __func__, &p);
XFREE(MTYPE_RE, re);
+ }
}
} else {
if (nhe_id) {
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index 8237bebf3b..772e30833c 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -1855,8 +1855,6 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
break;
} /* Switch */
-
- dplane_ctx_fini(&ctx);
}
/*
@@ -2064,7 +2062,7 @@ void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
/* Look for zebra LSP object */
zvrf = vrf_info_lookup(VRF_DEFAULT);
if (zvrf == NULL)
- goto done;
+ return;
lsp_table = zvrf->lsp_table;
@@ -2074,7 +2072,7 @@ void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
if (is_debug)
zlog_debug("dplane LSP notif: in-label %u not found",
dplane_ctx_get_in_label(ctx));
- goto done;
+ return;
}
/*
@@ -2147,9 +2145,6 @@ void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
clear_nhlfe_installed(lsp);
}
-
-done:
- dplane_ctx_fini(&ctx);
}
/*
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 9a0f48158f..8a255981b7 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -3076,8 +3076,6 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_INTF_DELETE:
break;
}
-
- dplane_ctx_fini(&ctx);
}
static int zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg)
diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c
index e6424fea4f..43e21a6d34 100644
--- a/zebra/zebra_pbr.c
+++ b/zebra/zebra_pbr.c
@@ -1068,9 +1068,6 @@ void zebra_pbr_dplane_result(struct zebra_dplane_ctx *ctx)
EC_ZEBRA_PBR_RULE_UPDATE,
"Context received in pbr rule dplane result handler with incorrect OP code (%u)",
op);
-
-
- dplane_ctx_fini(&ctx);
}
/*
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 63f15b0f20..d92a4c2365 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -77,9 +77,6 @@ static struct dplane_ctx_q rib_dplane_q;
DEFINE_HOOK(rib_update, (struct route_node * rn, const char *reason),
(rn, reason));
-/* Should we allow non FRR processes to delete our routes */
-extern int allow_delete;
-
/* Each route type's string and default distance value. */
static const struct {
int key;
@@ -167,6 +164,30 @@ struct wq_evpn_wrapper {
#pragma FRR printfrr_ext "%pZN" (struct route_node *)
#endif
+static const char *subqueue2str(uint8_t index)
+{
+ switch (index) {
+ case 0:
+ return "NHG Objects";
+ case 1:
+ return "EVPN/VxLan Objects";
+ case 2:
+ return "Connected Routes";
+ case 3:
+ return "Kernel Routes";
+ case 4:
+ return "Static Routes";
+ case 5:
+ return "RIP/OSPF/ISIS/EIGRP/NHRP Routes";
+ case 6:
+ return "BGP Routes";
+ case 7:
+ return "Other Routes";
+ }
+
+ return "Unknown";
+}
+
printfrr_ext_autoreg_p("ZN", printfrr_zebra_node);
static ssize_t printfrr_zebra_node(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
@@ -2087,9 +2108,6 @@ done:
if (rn)
route_unlock_node(rn);
-
- /* Return context to dataplane module */
- dplane_ctx_fini(&ctx);
}
/*
@@ -2323,9 +2341,6 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
done:
if (rn)
route_unlock_node(rn);
-
- /* Return context to dataplane module */
- dplane_ctx_fini(&ctx);
}
/*
@@ -2407,8 +2422,8 @@ static void process_subq_nhg(struct listnode *lnode)
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
- "NHG Context id=%u dequeued from sub-queue %u",
- ctx->id, qindex);
+ "NHG Context id=%u dequeued from sub-queue %s",
+ ctx->id, subqueue2str(qindex));
/* Process nexthop group updates coming 'up' from the OS */
@@ -2418,8 +2433,8 @@ static void process_subq_nhg(struct listnode *lnode)
nhe = w->u.nhe;
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("NHG %u dequeued from sub-queue %u",
- nhe->id, qindex);
+ zlog_debug("NHG %u dequeued from sub-queue %s", nhe->id,
+ subqueue2str(qindex));
/* Process incoming nhg update, probably from a proto daemon */
newnhe = zebra_nhg_proto_add(nhe->id, nhe->type,
@@ -2465,9 +2480,9 @@ static void process_subq_route(struct listnode *lnode, uint8_t qindex)
if (dest)
re = re_list_first(&dest->routes);
- zlog_debug("%s(%u:%u):%pRN rn %p dequeued from sub-queue %u",
+ zlog_debug("%s(%u:%u):%pRN rn %p dequeued from sub-queue %s",
zvrf_name(zvrf), zvrf_id(zvrf), re ? re->table : 0,
- rnode, rnode, qindex);
+ rnode, rnode, subqueue2str(qindex));
}
if (rnode->info)
@@ -2578,8 +2593,8 @@ static int rib_meta_queue_add(struct meta_queue *mq, void *data)
RIB_ROUTE_QUEUED(qindex))) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
rnode_debug(rn, re->vrf_id,
- "rn %p is already queued in sub-queue %u",
- (void *)rn, qindex);
+ "rn %p is already queued in sub-queue %s",
+ (void *)rn, subqueue2str(qindex));
return -1;
}
@@ -2589,8 +2604,8 @@ static int rib_meta_queue_add(struct meta_queue *mq, void *data)
mq->size++;
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- rnode_debug(rn, re->vrf_id, "queued rn %p into sub-queue %u",
- (void *)rn, qindex);
+ rnode_debug(rn, re->vrf_id, "queued rn %p into sub-queue %s",
+ (void *)rn, subqueue2str(qindex));
return 0;
}
@@ -2615,8 +2630,8 @@ static int rib_meta_queue_nhg_ctx_add(struct meta_queue *mq, void *data)
mq->size++;
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("NHG Context id=%u queued into sub-queue %u",
- ctx->id, qindex);
+ zlog_debug("NHG Context id=%u queued into sub-queue %s",
+ ctx->id, subqueue2str(qindex));
return 0;
}
@@ -2641,8 +2656,8 @@ static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data)
mq->size++;
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("NHG id=%u queued into sub-queue %u",
- nhe->id, qindex);
+ zlog_debug("NHG id=%u queued into sub-queue %s", nhe->id,
+ subqueue2str(qindex));
return 0;
}
@@ -3722,8 +3737,8 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
rn, fib,
zebra_route_string(fib->type));
}
- if (allow_delete
- || CHECK_FLAG(dest->flags, RIB_ROUTE_ANY_QUEUED)) {
+ if (zrouter.allow_delete ||
+ CHECK_FLAG(dest->flags, RIB_ROUTE_ANY_QUEUED)) {
UNSET_FLAG(fib->status, ROUTE_ENTRY_INSTALLED);
/* Unset flags. */
for (rtnh = fib->nhe->nhg.nexthop; rtnh;
@@ -3768,8 +3783,8 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
if (same) {
struct nexthop *tmp_nh;
- if (fromkernel && CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE)
- && !allow_delete) {
+ if (fromkernel && CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE) &&
+ !zrouter.allow_delete) {
rib_install_kernel(rn, same, NULL);
route_unlock_node(rn);
@@ -4191,7 +4206,7 @@ void rib_close_table(struct route_table *table)
/*
* Handler for async dataplane results after a pseudowire installation
*/
-static int handle_pw_result(struct zebra_dplane_ctx *ctx)
+static void handle_pw_result(struct zebra_dplane_ctx *ctx)
{
struct zebra_pw *pw;
struct zebra_vrf *vrf;
@@ -4200,7 +4215,7 @@ static int handle_pw_result(struct zebra_dplane_ctx *ctx)
* result for installation attempts here.
*/
if (dplane_ctx_get_op(ctx) != DPLANE_OP_PW_INSTALL)
- goto done;
+ return;
if (dplane_ctx_get_status(ctx) != ZEBRA_DPLANE_REQUEST_SUCCESS) {
vrf = zebra_vrf_lookup_by_id(dplane_ctx_get_vrf(ctx));
@@ -4209,14 +4224,8 @@ static int handle_pw_result(struct zebra_dplane_ctx *ctx)
zebra_pw_install_failure(pw,
dplane_ctx_get_pw_status(ctx));
}
-
-done:
- dplane_ctx_fini(&ctx);
-
- return 0;
}
-
/*
* Handle results from the dataplane system. Dequeue update context
* structs, dispatch to appropriate internal handlers.
@@ -4289,7 +4298,6 @@ static void rib_process_dplane_results(struct thread *thread)
case DPLANE_OP_ROUTE_INSTALL:
case DPLANE_OP_ROUTE_UPDATE:
case DPLANE_OP_ROUTE_DELETE:
- {
/* Bit of special case for route updates
* that were generated by async notifications:
* we don't want to continue processing these
@@ -4297,10 +4305,7 @@ static void rib_process_dplane_results(struct thread *thread)
*/
if (dplane_ctx_get_notif_provider(ctx) == 0)
rib_process_result(ctx);
- else
- dplane_ctx_fini(&ctx);
- }
- break;
+ break;
case DPLANE_OP_ROUTE_NOTIFY:
rib_process_dplane_notify(ctx);
@@ -4315,17 +4320,13 @@ static void rib_process_dplane_results(struct thread *thread)
case DPLANE_OP_LSP_INSTALL:
case DPLANE_OP_LSP_UPDATE:
case DPLANE_OP_LSP_DELETE:
- {
/* Bit of special case for LSP updates
* that were generated by async notifications:
* we don't want to continue processing these.
*/
if (dplane_ctx_get_notif_provider(ctx) == 0)
zebra_mpls_lsp_dplane_result(ctx);
- else
- dplane_ctx_fini(&ctx);
- }
- break;
+ break;
case DPLANE_OP_LSP_NOTIFY:
zebra_mpls_process_dplane_notify(ctx);
@@ -4338,8 +4339,6 @@ static void rib_process_dplane_results(struct thread *thread)
case DPLANE_OP_SYS_ROUTE_ADD:
case DPLANE_OP_SYS_ROUTE_DELETE:
- /* No further processing in zebra for these. */
- dplane_ctx_fini(&ctx);
break;
case DPLANE_OP_MAC_INSTALL:
@@ -4383,12 +4382,11 @@ static void rib_process_dplane_results(struct thread *thread)
case DPLANE_OP_NEIGH_TABLE_UPDATE:
case DPLANE_OP_GRE_SET:
case DPLANE_OP_NONE:
- /* Don't expect this: just return the struct? */
- dplane_ctx_fini(&ctx);
break;
} /* Dispatch by op code */
+ dplane_ctx_fini(&ctx);
ctx = dplane_ctx_dequeue(&ctxlist);
}
diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c
index 9fccda9e08..f7ad30b41f 100644
--- a/zebra/zebra_router.c
+++ b/zebra/zebra_router.c
@@ -278,6 +278,8 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack)
{
zrouter.sequence_num = 0;
+ zrouter.allow_delete = false;
+
zrouter.packets_to_process = ZEBRA_ZAPI_PACKETS_TO_PROCESS;
zrouter.nhg_keep = ZEBRA_DEFAULT_NHG_KEEP_TIMER;
diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h
index d51e7a2b7d..0e2725c977 100644
--- a/zebra/zebra_router.h
+++ b/zebra/zebra_router.h
@@ -229,6 +229,9 @@ struct zebra_router {
#define ZEBRA_DEFAULT_NHG_KEEP_TIMER 180
uint32_t nhg_keep;
+
+ /* Should we allow non FRR processes to delete our routes */
+ bool allow_delete;
};
#define GRACEFUL_RESTART_TIME 60
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 6ae55cdba4..e6038d0bc2 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -66,8 +66,6 @@
#include "zebra/rtadv.h"
#include "zebra/zebra_neigh.h"
-extern int allow_delete;
-
/* context to manage dumps in multiple tables or vrfs */
struct route_show_ctx {
bool multi; /* dump multiple tables or vrf */
@@ -2699,7 +2697,7 @@ DEFUN (allow_external_route_update,
"allow-external-route-update",
"Allow FRR routes to be overwritten by external processes\n")
{
- allow_delete = 1;
+ zrouter.allow_delete = true;
return CMD_SUCCESS;
}
@@ -2710,7 +2708,7 @@ DEFUN (no_allow_external_route_update,
NO_STR
"Allow FRR routes to be overwritten by external processes\n")
{
- allow_delete = 0;
+ zrouter.allow_delete = false;
return CMD_SUCCESS;
}
@@ -3911,7 +3909,7 @@ DEFPY (zebra_nexthop_group_keep,
static int config_write_protocol(struct vty *vty)
{
- if (allow_delete)
+ if (zrouter.allow_delete)
vty_out(vty, "allow-external-route-update\n");
if (zrouter.nhg_keep != ZEBRA_DEFAULT_NHG_KEEP_TIMER)
@@ -4011,6 +4009,8 @@ DEFUN (show_zebra,
ttable_add_row(table, "Kernel NHG|%s",
zrouter.supports_nhgs ? "Available" : "Unavailable");
+ ttable_add_row(table, "Allow Non FRR route deletion|%s",
+ zrouter.allow_delete ? "Yes" : "No");
ttable_add_row(table, "v4 All LinkDown Routes|%s",
zrouter.all_linkdownv4 ? "On" : "Off");
ttable_add_row(table, "v4 Default LinkDown Routes|%s",
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 4cf309f7fc..dbe1ce3e46 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -6260,8 +6260,7 @@ static int zebra_evpn_cfg_clean_up(struct zserv *client)
*/
extern void zebra_vxlan_handle_result(struct zebra_dplane_ctx *ctx)
{
- /* TODO -- anything other than freeing the context? */
- dplane_ctx_fini(&ctx);
+ return;
}
/* Cleanup BGP EVPN configuration upon client disconnect */