pim6d: Completing "ipv6 mld" config command.
ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre
perl pkgconf python3 python3-dev readline readline-dev sqlite-libs
squashfs-tools sudo tar texinfo xorriso xz-libs py-pip rtrlib rtrlib-dev
- py3-sphinx elfutils elfutils-dev"
+ py3-sphinx elfutils elfutils-dev libyang-dev"
checkdepends="pytest py-setuptools"
install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall"
subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
len - parsed_len, channels);
}
- if (ignore_update)
+ if (!ignore_update)
update_route(router_id, prefix, plen, seqno, metric,
interval, neigh, nh, channels,
channels_len(channels));
ptm_bfd_start_xmt_timer(bs, false);
}
+ /* initialize RTT */
+ bfd_rtt_init(bs);
+
return 0;
}
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);
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));
+
+ /* reset RTT */
+ bfd_rtt_init(bfd);
}
static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa,
if (bglobal.debug_zebra)
zlog_debug("VRF enable add %s id %u", vrf->name, vrf->vrf_id);
- if (vrf->vrf_id == VRF_DEFAULT ||
- vrf_get_backend() == VRF_BACKEND_NETNS) {
- if (!bvrf->bg_shop)
- bvrf->bg_shop = bp_udp_shop(vrf);
- if (!bvrf->bg_mhop)
- bvrf->bg_mhop = bp_udp_mhop(vrf);
- if (!bvrf->bg_shop6)
- bvrf->bg_shop6 = bp_udp6_shop(vrf);
- if (!bvrf->bg_mhop6)
- bvrf->bg_mhop6 = bp_udp6_mhop(vrf);
- if (!bvrf->bg_echo)
- bvrf->bg_echo = bp_echo_socket(vrf);
- if (!bvrf->bg_echov6)
- bvrf->bg_echov6 = bp_echov6_socket(vrf);
-
- if (!bvrf->bg_ev[0] && bvrf->bg_shop != -1)
- thread_add_read(master, bfd_recv_cb, bvrf,
- bvrf->bg_shop, &bvrf->bg_ev[0]);
- if (!bvrf->bg_ev[1] && bvrf->bg_mhop != -1)
- thread_add_read(master, bfd_recv_cb, bvrf,
- bvrf->bg_mhop, &bvrf->bg_ev[1]);
- if (!bvrf->bg_ev[2] && bvrf->bg_shop6 != -1)
- thread_add_read(master, bfd_recv_cb, bvrf,
- bvrf->bg_shop6, &bvrf->bg_ev[2]);
- if (!bvrf->bg_ev[3] && bvrf->bg_mhop6 != -1)
- thread_add_read(master, bfd_recv_cb, bvrf,
- bvrf->bg_mhop6, &bvrf->bg_ev[3]);
- if (!bvrf->bg_ev[4] && bvrf->bg_echo != -1)
- thread_add_read(master, bfd_recv_cb, bvrf,
- bvrf->bg_echo, &bvrf->bg_ev[4]);
- if (!bvrf->bg_ev[5] && bvrf->bg_echov6 != -1)
- thread_add_read(master, bfd_recv_cb, bvrf,
- bvrf->bg_echov6, &bvrf->bg_ev[5]);
- }
+ if (!bvrf->bg_shop)
+ bvrf->bg_shop = bp_udp_shop(vrf);
+ if (!bvrf->bg_mhop)
+ bvrf->bg_mhop = bp_udp_mhop(vrf);
+ if (!bvrf->bg_shop6)
+ bvrf->bg_shop6 = bp_udp6_shop(vrf);
+ if (!bvrf->bg_mhop6)
+ bvrf->bg_mhop6 = bp_udp6_mhop(vrf);
+ if (!bvrf->bg_echo)
+ bvrf->bg_echo = bp_echo_socket(vrf);
+ if (!bvrf->bg_echov6)
+ bvrf->bg_echov6 = bp_echov6_socket(vrf);
+
+ if (!bvrf->bg_ev[0] && bvrf->bg_shop != -1)
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop,
+ &bvrf->bg_ev[0]);
+ if (!bvrf->bg_ev[1] && bvrf->bg_mhop != -1)
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop,
+ &bvrf->bg_ev[1]);
+ if (!bvrf->bg_ev[2] && bvrf->bg_shop6 != -1)
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop6,
+ &bvrf->bg_ev[2]);
+ if (!bvrf->bg_ev[3] && bvrf->bg_mhop6 != -1)
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop6,
+ &bvrf->bg_ev[3]);
+ if (!bvrf->bg_ev[4] && bvrf->bg_echo != -1)
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echo,
+ &bvrf->bg_ev[4]);
+ if (!bvrf->bg_ev[5] && bvrf->bg_echov6 != -1)
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echov6,
+ &bvrf->bg_ev[5]);
+
if (vrf->vrf_id != VRF_DEFAULT) {
bfdd_zclient_register(vrf->vrf_id);
bfdd_sessions_enable_vrf(vrf);
{
return bfd_key_hash->count;
}
+
+void bfd_rtt_init(struct bfd_session *bfd)
+{
+ uint8_t i;
+
+ /* initialize RTT */
+ bfd->rtt_valid = 0;
+ bfd->rtt_index = 0;
+ for (i = 0; i < BFD_RTT_SAMPLE; i++)
+ bfd->rtt[i] = 0;
+}
};
};
uint32_t my_discr;
- uint8_t pad[16];
+ uint64_t time_sent_sec;
+ uint64_t time_sent_usec;
};
* 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 */
};
/*
uint32_t required_min_echo_rx;
};
+#define BFD_RTT_SAMPLE 8
+
/*
* Session state information
*/
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;
struct bfd_timers remote_timers;
uint64_t refcount; /* number of pointers referencing this. */
+
+ uint8_t rtt_valid; /* number of valid samples */
+ uint8_t rtt_index; /* last index added */
+ uint64_t rtt[BFD_RTT_SAMPLE]; /* RRT in usec for echo to be looped */
};
struct peer_label {
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);
bool mhop);
void bfd_sessions_remove_manual(void);
void bfd_profiles_remove(void);
+void bfd_rtt_init(struct bfd_session *bfd);
/**
* Set the BFD session echo state.
#include <netinet/udp.h>
#include "lib/sockopt.h"
+#include "lib/checksum.h"
+#include "lib/network.h"
#include "bfd.h"
struct sockaddr_any *peer);
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);
+int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd, uint8_t *ttl,
+ uint32_t *my_discr, uint64_t *my_rtt);
+#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);
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];
+ struct timeval time_sent;
+
+ 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(eth->h_source));
+ memcpy(eth->h_dest, bfd->peer_hw_addr, sizeof(eth->h_dest));
+
+ 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);
+
+ /* RTT calculation: add starting time in packet */
+ monotime(&time_sent);
+ beph->time_sent_sec = htobe64(time_sent.tv_sec);
+ beph->time_sent_usec = htobe64(time_sent.tv_usec);
+
+ 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;
{
struct bfd_session *bfd;
uint32_t my_discr = 0;
+ uint64_t my_rtt = 0;
uint8_t ttl = 0;
/* Receive and parse echo packet. */
- if (bp_bfd_echo_in(bvrf, s, &ttl, &my_discr) == -1)
+ if (bp_bfd_echo_in(bvrf, s, &ttl, &my_discr, &my_rtt) == -1)
return 0;
/* Your discriminator not zero - use it to find session */
return -1;
}
+ /* RTT Calculation: add current RTT to samples */
+ if (my_rtt != 0) {
+ bfd->rtt[bfd->rtt_index] = my_rtt;
+ bfd->rtt_index++;
+ if (bfd->rtt_index >= BFD_RTT_SAMPLE)
+ bfd->rtt_index = 0;
+ if (bfd->rtt_valid < BFD_RTT_SAMPLE)
+ bfd->rtt_valid++;
+ }
+
bfd->stats.rx_echo_pkt++;
/* Compute detect time */
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)
"no session found");
return;
}
+ /*
+ * We may have a situation where received packet is on wrong vrf
+ */
+ if (bfd && bfd->vrf && bfd->vrf != bvrf->vrf) {
+ cp_debug(is_mhop, &peer, &local, ifindex, vrfid,
+ "wrong vrfid.");
+ return;
+ }
/* Ensure that existing good sessions are not overridden. */
if (!cp->discrs.remote_discr && bfd->ses_state != PTM_BFD_DOWN &&
/*
* 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) {
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++;
*
* Returns -1 on error or loopback or 0 on success.
*/
-int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd,
- uint8_t *ttl, uint32_t *my_discr)
+int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd, uint8_t *ttl,
+ uint32_t *my_discr, uint64_t *my_rtt)
{
struct bfd_echo_pkt *bep;
ssize_t rlen;
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)
+ if (sd == bvrf->bg_echo) {
+#ifdef BFD_LINUX
+ rlen = bfd_recv_ipv4_fp(sd, msgbuf, sizeof(msgbuf), ttl,
+ &ifindex, &local, &peer);
+
+ /* 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)) {
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)
}
/* 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,
return -1;
}
+#ifdef BFD_LINUX
+ /* RTT Calculation: determine RTT time of IPv4 echo pkt */
+ if (sd == bvrf->bg_echo) {
+ struct timeval time_sent = {0, 0};
+
+ time_sent.tv_sec = be64toh(bep->time_sent_sec);
+ time_sent.tv_usec = be64toh(bep->time_sent_usec);
+ *my_rtt = monotime_since(&time_sent, NULL);
+ }
+#endif
+
+ 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 = {0};
+ struct iovec iov[1];
+ uint8_t msgctl[255];
+ struct sockaddr_ll sadr_ll = {0};
+
+ 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(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)
return 0;
}
+static bool bp_set_reuse_addr(int sd)
+{
+ int one = 1;
+
+ if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
+ zlog_warn("set-reuse-addr: setsockopt(SO_REUSEADDR, %d): %s",
+ one, strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+static bool bp_set_reuse_port(int sd)
+{
+ int one = 1;
+
+ if (setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) == -1) {
+ zlog_warn("set-reuse-port: setsockopt(SO_REUSEPORT, %d): %s",
+ one, strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+
static void bp_set_ipopts(int sd)
{
int rcvttl = BFD_RCV_TTL_VAL;
+ if (!bp_set_reuse_addr(sd))
+ zlog_fatal("set-reuse-addr: failed");
+
+ if (!bp_set_reuse_port(sd))
+ zlog_fatal("set-reuse-port: failed");
+
if (bp_set_ttl(sd, BFD_TTL_VAL) != 0)
zlog_fatal("set-ipopts: TTL configuration failed");
int ipv6_pktinfo = BFD_IPV6_PKT_INFO_VAL;
int ipv6_only = BFD_IPV6_ONLY_VAL;
+ if (!bp_set_reuse_addr(sd))
+ zlog_fatal("set-reuse-addr: failed");
+
+ if (!bp_set_reuse_port(sd))
+ zlog_fatal("set-reuse-port: failed");
+
if (bp_set_ttlv6(sd, BFD_TTL_VAL) == -1)
zlog_fatal(
"set-ipv6opts: setsockopt(IPV6_UNICAST_HOPS, %d): %s",
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 = {0};
+
+ /* 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));
+ close(s);
+ return -1;
+ }
+
+ memset(&sll, 0, sizeof(sll));
+ 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));
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
+#else
int bp_echo_socket(const struct vrf *vrf)
{
int s;
return s;
}
+#endif
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 (ifp->flags & IFF_NOARP)
+ 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 on %s failed error %s",
+ ifp->name, 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
"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,
static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg);
static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg);
static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json);
+static void _display_rtt(uint32_t *min, uint32_t *avg, uint32_t *max,
+ struct bfd_session *bs);
+
static struct bfd_session *
_find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
const char *label, const char *peer_str,
{
char buf[256];
time_t now;
+ uint32_t min = 0;
+ uint32_t avg = 0;
+ uint32_t max = 0;
_display_peer_header(vty, bs);
vty_out(vty, "\t\tRemote diagnostics: %s\n", diag2str(bs->remote_diag));
vty_out(vty, "\t\tPeer Type: %s\n",
CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG) ? "configured" : "dynamic");
+ _display_rtt(&min, &avg, &max, bs);
+ vty_out(vty, "\t\tRTT min/avg/max: %u/%u/%u usec\n", min, avg, max);
vty_out(vty, "\t\tLocal timers:\n");
vty_out(vty, "\t\t\tDetect-multiplier: %u\n",
static struct json_object *__display_peer_json(struct bfd_session *bs)
{
struct json_object *jo = _peer_json_header(bs);
+ uint32_t min = 0;
+ uint32_t avg = 0;
+ uint32_t max = 0;
json_object_int_add(jo, "id", bs->discrs.my_discr);
json_object_int_add(jo, "remote-id", bs->discrs.remote_discr);
json_object_int_add(jo, "remote-detect-multiplier",
bs->remote_detect_mult);
+ _display_rtt(&min, &avg, &max, bs);
+ json_object_int_add(jo, "rtt-min", min);
+ json_object_int_add(jo, "rtt-avg", avg);
+ json_object_int_add(jo, "rtt-max", max);
+
return jo;
}
return bs;
}
+void _display_rtt(uint32_t *min, uint32_t *avg, uint32_t *max,
+ struct bfd_session *bs)
+{
+#ifdef BFD_LINUX
+ uint8_t i;
+ uint32_t average = 0;
+
+ if (bs->rtt_valid == 0)
+ return;
+
+ *max = bs->rtt[0];
+ *min = 1000;
+ *avg = 0;
+
+ for (i = 0; i < bs->rtt_valid; i++) {
+ if (bs->rtt[i] < *min)
+ *min = bs->rtt[i];
+ if (bs->rtt[i] > *max)
+ *max = bs->rtt[i];
+ average += bs->rtt[i];
+ }
+ *avg = average / bs->rtt_valid;
+
+#endif
+}
/*
* Show commands.
/* BGP advertise attribute is used for pack same attribute update into
one packet. To do that we maintain attribute hash in struct
peer. */
-struct bgp_advertise_attr *baa_new(void)
+struct bgp_advertise_attr *bgp_advertise_attr_new(void)
{
return XCALLOC(MTYPE_BGP_ADVERTISE_ATTR,
sizeof(struct bgp_advertise_attr));
}
-static void baa_free(struct bgp_advertise_attr *baa)
+void bgp_advertise_attr_free(struct bgp_advertise_attr *baa)
{
XFREE(MTYPE_BGP_ADVERTISE_ATTR, baa);
}
-static void *baa_hash_alloc(void *p)
+static void *bgp_advertise_attr_hash_alloc(void *p)
{
struct bgp_advertise_attr *ref = (struct bgp_advertise_attr *)p;
struct bgp_advertise_attr *baa;
- baa = baa_new();
+ baa = bgp_advertise_attr_new();
baa->attr = ref->attr;
return baa;
}
-unsigned int baa_hash_key(const void *p)
+unsigned int bgp_advertise_attr_hash_key(const void *p)
{
const struct bgp_advertise_attr *baa = p;
return attrhash_key_make(baa->attr);
}
-bool baa_hash_cmp(const void *p1, const void *p2)
+bool bgp_advertise_attr_hash_cmp(const void *p1, const void *p2)
{
const struct bgp_advertise_attr *baa1 = p1;
const struct bgp_advertise_attr *baa2 = p2;
baa->adv = adv->next;
}
-struct bgp_advertise_attr *bgp_advertise_intern(struct hash *hash,
- struct attr *attr)
+struct bgp_advertise_attr *bgp_advertise_attr_intern(struct hash *hash,
+ struct attr *attr)
{
struct bgp_advertise_attr ref;
struct bgp_advertise_attr *baa;
ref.attr = bgp_attr_intern(attr);
- baa = (struct bgp_advertise_attr *)hash_get(hash, &ref, baa_hash_alloc);
+ baa = (struct bgp_advertise_attr *)hash_get(
+ hash, &ref, bgp_advertise_attr_hash_alloc);
baa->refcnt++;
return baa;
}
-void bgp_advertise_unintern(struct hash *hash, struct bgp_advertise_attr *baa)
+void bgp_advertise_attr_unintern(struct hash *hash,
+ struct bgp_advertise_attr *baa)
{
if (baa->refcnt)
baa->refcnt--;
hash_release(hash, baa);
bgp_attr_unintern(&baa->attr);
}
- baa_free(baa);
+ bgp_advertise_attr_free(baa);
}
}
extern void bgp_sync_init(struct peer *peer);
extern void bgp_sync_delete(struct peer *peer);
-extern unsigned int baa_hash_key(const void *p);
-extern bool baa_hash_cmp(const void *p1, const void *p2);
+extern unsigned int bgp_advertise_attr_hash_key(const void *p);
+extern bool bgp_advertise_attr_hash_cmp(const void *p1, const void *p2);
extern void bgp_advertise_add(struct bgp_advertise_attr *baa,
struct bgp_advertise *adv);
extern struct bgp_advertise *bgp_advertise_new(void);
extern void bgp_advertise_free(struct bgp_advertise *adv);
-extern struct bgp_advertise_attr *bgp_advertise_intern(struct hash *hash,
- struct attr *attr);
-extern struct bgp_advertise_attr *baa_new(void);
+extern struct bgp_advertise_attr *bgp_advertise_attr_intern(struct hash *hash,
+ struct attr *attr);
+extern struct bgp_advertise_attr *bgp_advertise_attr_new(void);
extern void bgp_advertise_delete(struct bgp_advertise_attr *baa,
struct bgp_advertise *adv);
-extern void bgp_advertise_unintern(struct hash *hash,
- struct bgp_advertise_attr *baa);
+extern void bgp_advertise_attr_unintern(struct hash *hash,
+ struct bgp_advertise_attr *baa);
+extern void bgp_advertise_attr_free(struct bgp_advertise_attr *baa);
#endif /* _QUAGGA_BGP_ADVERTISE_H */
return true;
}
-/* Return True if the entire ASPATH consist of the specified ASN */
-bool aspath_single_asn_check(struct aspath *aspath, as_t asn)
-{
- struct assegment *seg;
-
- if (!(aspath && aspath->segments))
- return false;
-
- seg = aspath->segments;
-
- while (seg) {
- int i;
-
- for (i = 0; i < seg->length; i++) {
- if (seg->as[i] != asn)
- return false;
- }
- seg = seg->next;
- }
- return true;
-}
-
/* Replace all instances of the target ASN with our own ASN */
struct aspath *aspath_replace_specific_asn(struct aspath *aspath,
as_t target_asn, as_t our_asn)
extern unsigned int aspath_get_last_as(struct aspath *aspath);
extern int aspath_loop_check(struct aspath *aspath, as_t asno);
extern bool aspath_private_as_check(struct aspath *aspath);
-extern bool aspath_single_asn_check(struct aspath *aspath, as_t asn);
extern struct aspath *aspath_replace_specific_asn(struct aspath *aspath,
as_t target_asn,
as_t our_asn);
case BGP_ATTR_LARGE_COMMUNITIES:
case BGP_ATTR_ORIGINATOR_ID:
case BGP_ATTR_CLUSTER_LIST:
+ case BGP_ATTR_OTC:
return BGP_ATTR_PARSE_WITHDRAW;
case BGP_ATTR_MP_REACH_NLRI:
case BGP_ATTR_MP_UNREACH_NLRI:
0);
}
+ /* Conformant BGP speakers SHOULD NOT send BGP
+ * UPDATE messages containing AS_SET or AS_CONFED_SET. Upon receipt of
+ * such messages, conformant BGP speakers SHOULD use the "Treat-as-
+ * withdraw" error handling behavior as per [RFC7606].
+ */
+ if (peer->bgp->reject_as_sets && aspath_check_as_sets(attr->aspath)) {
+ flog_err(EC_BGP_ATTR_MAL_AS_PATH,
+ "AS_SET and AS_CONFED_SET are deprecated from %pBP",
+ peer);
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
+ 0);
+ }
+
/* Set aspath attribute flag. */
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
0);
}
+ /* Conformant BGP speakers SHOULD NOT send BGP
+ * UPDATE messages containing AS_SET or AS_CONFED_SET. Upon receipt of
+ * such messages, conformant BGP speakers SHOULD use the "Treat-as-
+ * withdraw" error handling behavior as per [RFC7606].
+ */
+ if (peer->bgp->reject_as_sets && aspath_check_as_sets(attr->aspath)) {
+ flog_err(EC_BGP_ATTR_MAL_AS_PATH,
+ "AS_SET and AS_CONFED_SET are deprecated from %pBP",
+ peer);
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
+ 0);
+ }
+
/* Set aspath attribute flag. */
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH);
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_DEBUG(allow_martians, ALLOW_MARTIANS)) {
+ if (ipv4_martian(&attr->nexthop) && !bgp->allow_martian) {
uint8_t data[7]; /* type(2) + length(1) + nhop(4) */
char buf[INET_ADDRSTRLEN];
}
attr->otc = stream_getl(peer->curr);
+ if (!attr->otc) {
+ flog_err(EC_BGP_ATTR_MAL_AS_PATH, "OTC attribute value is 0");
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
+ args->total);
+ }
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_OTC);
DECLARE_SORTLIST_UNIQ(bmp_listeners, struct bmp_listener, bli,
bmp_listener_cmp);
+static void bmp_listener_put(struct bmp_listener *bl)
+{
+ bmp_listeners_del(&bl->targets->listeners, bl);
+ XFREE(MTYPE_BMP_LISTENER, bl);
+}
+
static int bmp_targets_cmp(const struct bmp_targets *a,
const struct bmp_targets *b)
{
else if (b->afi == AFI_L2VPN && b->safi == SAFI_EVPN)
return -1;
+ if (a->afi == b->afi && a->safi == SAFI_MPLS_VPN &&
+ b->safi == SAFI_MPLS_VPN) {
+ ret = prefix_cmp(&a->rd, &b->rd);
+ if (ret)
+ return ret;
+ } else if (a->safi == SAFI_MPLS_VPN)
+ return 1;
+ else if (b->safi == SAFI_MPLS_VPN)
+ return -1;
+
ret = prefix_cmp(&a->p, &b->p);
if (ret)
return ret;
offsetof(struct bmp_queue_entry, refcount)
- offsetof(struct bmp_queue_entry, peerid),
key);
- if (e->afi == AFI_L2VPN && e->safi == SAFI_EVPN)
+ if ((e->afi == AFI_L2VPN && e->safi == SAFI_EVPN) ||
+ (e->safi == SAFI_MPLS_VPN))
key = jhash(&e->rd,
offsetof(struct bmp_queue_entry, rd)
- offsetof(struct bmp_queue_entry, refcount)
}
struct bgp_table *table = bmp->targets->bgp->rib[afi][safi];
- struct bgp_dest *bn;
+ struct bgp_dest *bn = NULL;
struct bgp_path_info *bpi = NULL, *bpiter;
struct bgp_adj_in *adjin = NULL, *adjiter;
- if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
+ if ((afi == AFI_L2VPN && safi == SAFI_EVPN) ||
+ (safi == SAFI_MPLS_VPN)) {
/* initialize syncrdpos to the first
* mid-layer table entry
*/
if (!bn) {
bn = bgp_table_get_next(table, &bmp->syncpos);
if (!bn) {
- if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
+ if ((afi == AFI_L2VPN && safi == SAFI_EVPN) ||
+ (safi == SAFI_MPLS_VPN)) {
/* reset bottom-layer pointer */
memset(&bmp->syncpos, 0,
sizeof(bmp->syncpos));
const struct prefix *bn_p = bgp_dest_get_prefix(bn);
struct prefix_rd *prd = NULL;
- if (afi == AFI_L2VPN && safi == SAFI_EVPN)
+ if (((afi == AFI_L2VPN) && (safi == SAFI_EVPN)) ||
+ (safi == SAFI_MPLS_VPN))
prd = (struct prefix_rd *)bgp_dest_get_prefix(bmp->syncrdpos);
if (bpi)
bmp_monitor(bmp, adjin->peer, 0, bn_p, prd, adjin->attr, afi,
safi, adjin->uptime);
+ if (bn)
+ bgp_dest_unlock_node(bn);
+
return true;
}
{
struct bmp_queue_entry *bqe;
struct peer *peer;
- struct bgp_dest *bn;
+ struct bgp_dest *bn = NULL;
bool written = false;
bqe = bmp_pull(bmp);
if (!peer_established(peer))
goto out;
- bn = bgp_node_lookup(bmp->targets->bgp->rib[afi][safi], &bqe->p);
- struct prefix_rd *prd = NULL;
- if (bqe->afi == AFI_L2VPN && bqe->safi == SAFI_EVPN)
- prd = &bqe->rd;
+ bool is_vpn = (bqe->afi == AFI_L2VPN && bqe->safi == SAFI_EVPN) ||
+ (bqe->safi == SAFI_MPLS_VPN);
+
+ struct prefix_rd *prd = is_vpn ? &bqe->rd : NULL;
+ bn = bgp_afi_node_lookup(bmp->targets->bgp->rib[afi][safi], afi, safi,
+ &bqe->p, prd);
+
if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) {
struct bgp_path_info *bpi;
out:
if (!bqe->refcount)
XFREE(MTYPE_BMP_QUEUE, bqe);
+
+ if (bn)
+ bgp_dest_unlock_node(bn);
+
return written;
}
bqeref.afi = afi;
bqeref.safi = safi;
- if (afi == AFI_L2VPN && safi == SAFI_EVPN && bn->pdest)
+ if ((afi == AFI_L2VPN && safi == SAFI_EVPN && bn->pdest) ||
+ (safi == SAFI_MPLS_VPN))
prefix_copy(&bqeref.rd,
(struct prefix_rd *)bgp_dest_get_prefix(bn->pdest));
static void bmp_bgp_put(struct bmp_bgp *bmpbgp)
{
struct bmp_targets *bt;
+ struct bmp_listener *bl;
bmp_bgph_del(&bmp_bgph, bmpbgp);
- frr_each_safe(bmp_targets, &bmpbgp->targets, bt)
+ frr_each_safe (bmp_targets, &bmpbgp->targets, bt) {
+ frr_each_safe (bmp_listeners, &bt->listeners, bl)
+ bmp_listener_put(bl);
+
bmp_targets_put(bt);
+ }
bmp_mirrorq_fini(&bmpbgp->mirrorq);
XFREE(MTYPE_BMP, bmpbgp);
return bl;
}
-static void bmp_listener_put(struct bmp_listener *bl)
-{
- bmp_listeners_del(&bl->targets->listeners, bl);
- XFREE(MTYPE_BMP_LISTENER, bl);
-}
-
static void bmp_listener_start(struct bmp_listener *bl)
{
int sock, ret;
DEFPY(bmp_monitor_cfg,
bmp_monitor_cmd,
- "[no] bmp monitor <ipv4|ipv6|l2vpn> <unicast|multicast|evpn> <pre-policy|post-policy>$policy",
+ "[no] bmp monitor <ipv4|ipv6|l2vpn> <unicast|multicast|evpn|vpn> <pre-policy|post-policy>$policy",
NO_STR
BMP_STR
"Send BMP route monitoring messages\n"
- "Address Family\nAddress Family\nAddress Family\n"
- "Address Family\nAddress Family\nAddress Family\n"
+ BGP_AF_STR
+ BGP_AF_STR
+ BGP_AF_STR
+ BGP_AF_STR
+ BGP_AF_STR
+ BGP_AF_STR
+ BGP_AF_STR
"Send state before policy and filter processing\n"
"Send state with policy and filters applied\n")
{
"BGP Community Hash");
}
+static void community_hash_free(void *data)
+{
+ struct community *com = data;
+
+ community_free(&com);
+}
+
void community_finish(void)
{
+ hash_clean(comhash, community_hash_free);
hash_free(comhash);
comhash = NULL;
}
"BGP community alias (alias)");
}
+static void bgp_ca_free(void *ca)
+{
+ XFREE(MTYPE_COMMUNITY_ALIAS, ca);
+}
+
void bgp_community_alias_finish(void)
{
+ hash_clean(bgp_ca_community_hash, bgp_ca_free);
hash_free(bgp_ca_community_hash);
+ hash_clean(bgp_ca_alias_hash, bgp_ca_free);
hash_free(bgp_ca_alias_hash);
}
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);
* 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,
*/
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;
+
+ /*
+ * Update condadv update type so
+ * subgroup_announce_check() can properly apply
+ * outbound policy according to advertisement state
+ */
+ paf = peer_af_find(peer, afi, safi);
+ if (paf && (SUBGRP_PEER(PAF_SUBGRP(paf))
+ ->filter[afi][safi]
+ .advmap.update_type !=
+ filter->advmap.update_type)) {
+ /* Handle change to peer advmap */
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug(
+ "%s: advmap.update_type changed for peer %s, adjusting update_group.",
+ __func__, peer->host);
+
+ update_group_adjust_peer(paf);
+ }
/* Send regular update as per the existing policy.
* There is a change in route-map, match-rule, ACLs,
__func__, peer->host,
get_afi_safi_str(afi, safi,
false));
-
- paf = peer_af_find(peer, afi, safi);
if (paf) {
update_subgroup_split_peer(paf, NULL);
subgrp = paf->subgroup;
+
if (subgrp && subgrp->update_group)
subgroup_announce_table(
paf->subgroup, NULL);
}
/* 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)
return 0;
/* Cancel reuse event. */
- thread_cancel(&(bdc->t_reuse));
+ THREAD_OFF(bdc->t_reuse);
/* Clean BGP dampening information. */
bgp_damp_info_clean(afi, safi);
return CMD_SUCCESS;
}
-DEFUN (debug_bgp_allow_martians,
- debug_bgp_allow_martians_cmd,
- "debug bgp allow-martians",
- DEBUG_STR
- BGP_STR
- "BGP allow martian next hops\n")
-{
- if (vty->node == CONFIG_NODE)
- DEBUG_ON(allow_martians, ALLOW_MARTIANS);
- else {
- TERM_DEBUG_ON(allow_martians, ALLOW_MARTIANS);
- vty_out(vty, "BGP allow_martian next hop debugging is on\n");
- }
- return CMD_SUCCESS;
-}
-
-DEFUN (no_debug_bgp_allow_martians,
- no_debug_bgp_allow_martians_cmd,
- "no debug bgp allow-martians",
- NO_STR
- DEBUG_STR
- BGP_STR
- "BGP allow martian next hops\n")
-{
- if (vty->node == CONFIG_NODE)
- DEBUG_OFF(allow_martians, ALLOW_MARTIANS);
- else {
- TERM_DEBUG_OFF(allow_martians, ALLOW_MARTIANS);
- vty_out(vty, "BGP allow martian next hop debugging is off\n");
- }
- return CMD_SUCCESS;
-}
-
-
/* debug bgp update-groups */
DEFUN (debug_bgp_update_groups,
debug_bgp_update_groups_cmd,
install_element(CONFIG_NODE, &debug_bgp_update_cmd);
install_element(ENABLE_NODE, &debug_bgp_zebra_cmd);
install_element(CONFIG_NODE, &debug_bgp_zebra_cmd);
- install_element(ENABLE_NODE, &debug_bgp_allow_martians_cmd);
- install_element(CONFIG_NODE, &debug_bgp_allow_martians_cmd);
install_element(ENABLE_NODE, &debug_bgp_update_groups_cmd);
install_element(CONFIG_NODE, &debug_bgp_update_groups_cmd);
install_element(ENABLE_NODE, &debug_bgp_bestpath_prefix_cmd);
install_element(CONFIG_NODE, &no_debug_bgp_update_cmd);
install_element(ENABLE_NODE, &no_debug_bgp_zebra_cmd);
install_element(CONFIG_NODE, &no_debug_bgp_zebra_cmd);
- install_element(ENABLE_NODE, &no_debug_bgp_allow_martians_cmd);
- install_element(CONFIG_NODE, &no_debug_bgp_allow_martians_cmd);
install_element(ENABLE_NODE, &no_debug_bgp_update_groups_cmd);
install_element(CONFIG_NODE, &no_debug_bgp_update_groups_cmd);
install_element(ENABLE_NODE, &no_debug_bgp_cmd);
}
/* Removing interval event. */
- thread_cancel(&bgp_dump->t_interval);
+ THREAD_OFF(bgp_dump->t_interval);
bgp_dump->interval = 0;
bgp_attr_set_pmsi_tnl_type(&attr, PMSI_TNLTYPE_INGR_REPL);
}
+ /* router mac is only needed for type-2 routes here. */
+ if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ uint8_t af_flags = 0;
+
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP))
+ SET_FLAG(af_flags, BGP_EVPN_MACIP_TYPE_SVI_IP);
+
+ bgp_evpn_get_rmac_nexthop(vpn, p, &attr, af_flags);
+ }
+
if (bgp_debug_zebra(NULL)) {
char buf3[ESI_STR_LEN];
vpn->vni, p, &attr.rmac, &attr.mp_nexthop_global_in,
esi_to_str(esi, buf3, sizeof(buf3)));
}
- /* router mac is only needed for type-2 routes here. */
- if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
- uint8_t af_flags = 0;
-
- if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP))
- SET_FLAG(af_flags, BGP_EVPN_MACIP_TYPE_SVI_IP);
-
- bgp_evpn_get_rmac_nexthop(vpn, p, &attr, af_flags);
- }
vni2label(vpn->vni, &(attr.label));
if (attr.evpn_overlay.type != OVERLAY_INDEX_GATEWAY_IP) {
if (afi == AFI_IP6)
evpn_convert_nexthop_to_ipv6(&attr);
- else
+ else {
+ attr.nexthop = attr.mp_nexthop_global_in;
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+ }
} else {
/*
return;
tree = &vpn->bgp_vrf->nexthop_cache_table[afi];
- bnc = bnc_find(tree, &p, 0);
+ bnc = bnc_find(tree, &p, 0, 0);
if (!bnc || !bnc->is_evpn_gwip_nexthop)
return;
bgp_evpn_es_local_info_clear(es, true);
}
if (bgp_mh_info->t_cons_check)
- thread_cancel(&bgp_mh_info->t_cons_check);
+ THREAD_OFF(bgp_mh_info->t_cons_check);
list_delete(&bgp_mh_info->local_es_list);
list_delete(&bgp_mh_info->pend_es_list);
list_delete(&bgp_mh_info->ead_es_export_rtl);
afi_t afi = 0;
safi_t safi = 0;
+ if (!bgp_vrf)
+ return CMD_WARNING;
+
argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
argv_find_and_parse_safi(argv, argc, &idx_safi, &safi);
: "Disabled");
json_object_string_add(
json, "flooding",
- bgp_evpn->vxlan_flood_ctrl
- == VXLAN_FLOOD_HEAD_END_REPL
+ bgp_evpn->vxlan_flood_ctrl ==
+ VXLAN_FLOOD_HEAD_END_REPL
? "Head-end replication"
: "Disabled");
+ json_object_string_add(
+ json, "vxlanFlooding",
+ bgp_evpn->vxlan_flood_ctrl ==
+ VXLAN_FLOOD_HEAD_END_REPL
+ ? "Enabled"
+ : "Disabled");
json_object_int_add(json, "numVnis", num_vnis);
json_object_int_add(json, "numL2Vnis", num_l2vnis);
json_object_int_add(json, "numL3Vnis", num_l3vnis);
vty_out(vty, "Advertise All VNI flag: %s\n",
is_evpn_enabled() ? "Enabled" : "Disabled");
vty_out(vty, "BUM flooding: %s\n",
- bgp_evpn->vxlan_flood_ctrl
- == VXLAN_FLOOD_HEAD_END_REPL
+ bgp_evpn->vxlan_flood_ctrl ==
+ VXLAN_FLOOD_HEAD_END_REPL
? "Head-end replication"
: "Disabled");
+ vty_out(vty, "VXLAN flooding: %s\n",
+ bgp_evpn->vxlan_flood_ctrl ==
+ VXLAN_FLOOD_HEAD_END_REPL
+ ? "Enabled"
+ : "Disabled");
vty_out(vty, "Number of L2 VNIs: %u\n", num_l2vnis);
vty_out(vty, "Number of L3 VNIs: %u\n", num_l3vnis);
}
if (uj)
json = json_object_new_object();
- if (argv_find(argv, argc, "all", &rd_all)) {
+ if (!argv_find(argv, argc, "all", &rd_all)) {
/* get the RD */
if (argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN",
&idx_ext_community)) {
json = json_object_new_object();
/* get the prd */
- if (argv_find(argv, argc, "all", &rd_all)) {
+ if (!argv_find(argv, argc, "all", &rd_all)) {
if (argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN",
&idx_ext_community)) {
ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
replace = bgp_aslist_seq_check(aslist, asfilter->seq);
if (replace) {
as_filter_entry_replace(aslist, replace, asfilter);
- return;
+ goto hook;
}
/* Check insert point. */
aslist->tail = asfilter;
}
+hook:
/* Run hook function. */
if (as_list_master.add_hook)
(*as_list_master.add_hook)(aslist->name);
if (!config_bgp_aspath_validate(regstr)) {
vty_out(vty, "Invalid character in as-path access-list %s\n",
regstr);
+ XFREE(MTYPE_TMP, regstr);
return CMD_WARNING_CONFIG_FAILED;
}
*/
bgp_keepalives_off(from_peer);
- BGP_TIMER_OFF(peer->t_routeadv);
- BGP_TIMER_OFF(peer->t_connect);
- BGP_TIMER_OFF(peer->t_delayopen);
- BGP_TIMER_OFF(peer->t_connect_check_r);
- BGP_TIMER_OFF(peer->t_connect_check_w);
- BGP_TIMER_OFF(from_peer->t_routeadv);
- BGP_TIMER_OFF(from_peer->t_connect);
- BGP_TIMER_OFF(from_peer->t_delayopen);
- BGP_TIMER_OFF(from_peer->t_connect_check_r);
- BGP_TIMER_OFF(from_peer->t_connect_check_w);
- BGP_TIMER_OFF(from_peer->t_process_packet);
+ THREAD_OFF(peer->t_routeadv);
+ THREAD_OFF(peer->t_connect);
+ THREAD_OFF(peer->t_delayopen);
+ THREAD_OFF(peer->t_connect_check_r);
+ THREAD_OFF(peer->t_connect_check_w);
+ THREAD_OFF(from_peer->t_routeadv);
+ THREAD_OFF(from_peer->t_connect);
+ THREAD_OFF(from_peer->t_delayopen);
+ THREAD_OFF(from_peer->t_connect_check_r);
+ THREAD_OFF(from_peer->t_connect_check_w);
+ THREAD_OFF(from_peer->t_process_packet);
/*
* At this point in time, it is possible that there are packets pending
* on various buffers. Those need to be transferred or dropped,
* otherwise we'll get spurious failures during session establishment.
*/
- frr_with_mutex(&peer->io_mtx, &from_peer->io_mtx) {
+ frr_with_mutex (&peer->io_mtx, &from_peer->io_mtx) {
fd = peer->fd;
peer->fd = from_peer->fd;
from_peer->fd = fd;
inactive. All other timer must be turned off */
if (BGP_PEER_START_SUPPRESSED(peer) || !peer_active(peer)
|| peer->bgp->vrf_id == VRF_UNKNOWN) {
- BGP_TIMER_OFF(peer->t_start);
+ THREAD_OFF(peer->t_start);
} else {
BGP_TIMER_ON(peer->t_start, bgp_start_timer,
peer->v_start);
}
- BGP_TIMER_OFF(peer->t_connect);
- BGP_TIMER_OFF(peer->t_holdtime);
+ THREAD_OFF(peer->t_connect);
+ THREAD_OFF(peer->t_holdtime);
bgp_keepalives_off(peer);
- BGP_TIMER_OFF(peer->t_routeadv);
- BGP_TIMER_OFF(peer->t_delayopen);
+ THREAD_OFF(peer->t_routeadv);
+ THREAD_OFF(peer->t_delayopen);
break;
case Connect:
/* After start timer is expired, the peer moves to Connect
status. Make sure start timer is off and connect timer is
on. */
- BGP_TIMER_OFF(peer->t_start);
+ THREAD_OFF(peer->t_start);
if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN))
BGP_TIMER_ON(peer->t_connect, bgp_connect_timer,
(peer->v_delayopen + peer->v_connect));
BGP_TIMER_ON(peer->t_connect, bgp_connect_timer,
peer->v_connect);
- BGP_TIMER_OFF(peer->t_holdtime);
+ THREAD_OFF(peer->t_holdtime);
bgp_keepalives_off(peer);
- BGP_TIMER_OFF(peer->t_routeadv);
+ THREAD_OFF(peer->t_routeadv);
break;
case Active:
/* Active is waiting connection from remote peer. And if
connect timer is expired, change status to Connect. */
- BGP_TIMER_OFF(peer->t_start);
+ THREAD_OFF(peer->t_start);
/* If peer is passive mode, do not set connect timer. */
if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSIVE)
|| CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) {
- BGP_TIMER_OFF(peer->t_connect);
+ THREAD_OFF(peer->t_connect);
} else {
if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN))
BGP_TIMER_ON(
BGP_TIMER_ON(peer->t_connect, bgp_connect_timer,
peer->v_connect);
}
- BGP_TIMER_OFF(peer->t_holdtime);
+ THREAD_OFF(peer->t_holdtime);
bgp_keepalives_off(peer);
- BGP_TIMER_OFF(peer->t_routeadv);
+ THREAD_OFF(peer->t_routeadv);
break;
case OpenSent:
/* OpenSent status. */
- BGP_TIMER_OFF(peer->t_start);
- BGP_TIMER_OFF(peer->t_connect);
+ THREAD_OFF(peer->t_start);
+ THREAD_OFF(peer->t_connect);
if (peer->v_holdtime != 0) {
BGP_TIMER_ON(peer->t_holdtime, bgp_holdtime_timer,
peer->v_holdtime);
} else {
- BGP_TIMER_OFF(peer->t_holdtime);
+ THREAD_OFF(peer->t_holdtime);
}
bgp_keepalives_off(peer);
- BGP_TIMER_OFF(peer->t_routeadv);
- BGP_TIMER_OFF(peer->t_delayopen);
+ THREAD_OFF(peer->t_routeadv);
+ THREAD_OFF(peer->t_delayopen);
break;
case OpenConfirm:
/* OpenConfirm status. */
- BGP_TIMER_OFF(peer->t_start);
- BGP_TIMER_OFF(peer->t_connect);
+ THREAD_OFF(peer->t_start);
+ THREAD_OFF(peer->t_connect);
/* If the negotiated Hold Time value is zero, then the Hold Time
timer and KeepAlive timers are not started. */
if (peer->v_holdtime == 0) {
- BGP_TIMER_OFF(peer->t_holdtime);
+ THREAD_OFF(peer->t_holdtime);
bgp_keepalives_off(peer);
} else {
BGP_TIMER_ON(peer->t_holdtime, bgp_holdtime_timer,
peer->v_holdtime);
bgp_keepalives_on(peer);
}
- BGP_TIMER_OFF(peer->t_routeadv);
- BGP_TIMER_OFF(peer->t_delayopen);
+ THREAD_OFF(peer->t_routeadv);
+ THREAD_OFF(peer->t_delayopen);
break;
case Established:
/* In Established status start and connect timer is turned
off. */
- BGP_TIMER_OFF(peer->t_start);
- BGP_TIMER_OFF(peer->t_connect);
- BGP_TIMER_OFF(peer->t_delayopen);
+ THREAD_OFF(peer->t_start);
+ THREAD_OFF(peer->t_connect);
+ THREAD_OFF(peer->t_delayopen);
/* Same as OpenConfirm, if holdtime is zero then both holdtime
and keepalive must be turned off. */
if (peer->v_holdtime == 0) {
- BGP_TIMER_OFF(peer->t_holdtime);
+ THREAD_OFF(peer->t_holdtime);
bgp_keepalives_off(peer);
} else {
BGP_TIMER_ON(peer->t_holdtime, bgp_holdtime_timer,
}
break;
case Deleted:
- BGP_TIMER_OFF(peer->t_gr_restart);
- BGP_TIMER_OFF(peer->t_gr_stale);
+ THREAD_OFF(peer->t_gr_restart);
+ THREAD_OFF(peer->t_gr_stale);
FOREACH_AFI_SAFI (afi, safi)
- BGP_TIMER_OFF(peer->t_llgr_stale[afi][safi]);
+ THREAD_OFF(peer->t_llgr_stale[afi][safi]);
- BGP_TIMER_OFF(peer->t_pmax_restart);
- BGP_TIMER_OFF(peer->t_refresh_stalepath);
+ THREAD_OFF(peer->t_pmax_restart);
+ THREAD_OFF(peer->t_refresh_stalepath);
/* fallthru */
case Clearing:
- BGP_TIMER_OFF(peer->t_start);
- BGP_TIMER_OFF(peer->t_connect);
- BGP_TIMER_OFF(peer->t_holdtime);
+ THREAD_OFF(peer->t_start);
+ THREAD_OFF(peer->t_connect);
+ THREAD_OFF(peer->t_holdtime);
bgp_keepalives_off(peer);
- BGP_TIMER_OFF(peer->t_routeadv);
- BGP_TIMER_OFF(peer->t_delayopen);
+ THREAD_OFF(peer->t_routeadv);
+ THREAD_OFF(peer->t_delayopen);
break;
case BGP_STATUS_MAX:
flog_err(EC_LIB_DEVELOPMENT,
peer = THREAD_ARG(thread);
/* stop the DelayOpenTimer if it is running */
- BGP_TIMER_OFF(peer->t_delayopen);
+ THREAD_OFF(peer->t_delayopen);
assert(!peer->t_write);
assert(!peer->t_read);
return;
UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
- BGP_TIMER_OFF(peer->t_gr_stale);
+ THREAD_OFF(peer->t_gr_stale);
if (peer_dynamic_neighbor(peer) &&
!(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) {
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (!peer_established(peer))
continue;
- BGP_TIMER_OFF(peer->t_routeadv);
+ THREAD_OFF(peer->t_routeadv);
BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0);
}
}
* different
* duration and schedule write thread immediately.
*/
- BGP_TIMER_OFF(peer->t_routeadv);
+ THREAD_OFF(peer->t_routeadv);
peer->synctime = bgp_clock();
/* If suppress fib pending is enabled, route is advertised to
*/
diff = difftime(nowtime, peer->last_update);
if (diff > (double)peer->v_routeadv) {
- BGP_TIMER_OFF(peer->t_routeadv);
+ THREAD_OFF(peer->t_routeadv);
BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0);
return;
}
remain = peer->v_routeadv;
diff = peer->v_routeadv - diff;
if (diff <= (double)remain) {
- BGP_TIMER_OFF(peer->t_routeadv);
+ THREAD_OFF(peer->t_routeadv);
BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, diff);
}
}
/* graceful restart */
if (peer->t_gr_stale) {
- BGP_TIMER_OFF(peer->t_gr_stale);
+ THREAD_OFF(peer->t_gr_stale);
if (bgp_debug_neighbor_events(peer))
zlog_debug(
"%pBP graceful restart stalepath timer stopped",
/* Stop route-refresh stalepath timer */
if (peer->t_refresh_stalepath) {
- BGP_TIMER_OFF(peer->t_refresh_stalepath);
+ THREAD_OFF(peer->t_refresh_stalepath);
if (bgp_debug_neighbor_events(peer))
zlog_debug(
/* There is no pending EOR message */
if (gr_info->eor_required == 0) {
- BGP_TIMER_OFF(
- gr_info->t_select_deferral);
+ THREAD_OFF(gr_info->t_select_deferral);
gr_info->eor_received = 0;
}
}
THREAD_OFF(peer->t_connect_check_w);
/* Stop all timers. */
- BGP_TIMER_OFF(peer->t_start);
- BGP_TIMER_OFF(peer->t_connect);
- BGP_TIMER_OFF(peer->t_holdtime);
- BGP_TIMER_OFF(peer->t_routeadv);
- BGP_TIMER_OFF(peer->t_delayopen);
+ THREAD_OFF(peer->t_start);
+ THREAD_OFF(peer->t_connect);
+ THREAD_OFF(peer->t_holdtime);
+ THREAD_OFF(peer->t_routeadv);
+ THREAD_OFF(peer->t_delayopen);
/* Clear input and output buffer. */
- frr_with_mutex(&peer->io_mtx) {
+ frr_with_mutex (&peer->io_mtx) {
if (peer->ibuf)
stream_fifo_clean(peer->ibuf);
if (peer->obuf)
static int bgp_fsm_delayopen_timer_expire(struct peer *peer)
{
/* Stop the DelayOpenTimer */
- BGP_TIMER_OFF(peer->t_delayopen);
+ THREAD_OFF(peer->t_delayopen);
/* Send open message to peer */
bgp_open_send(peer);
else {
UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
if (peer->t_gr_stale) {
- BGP_TIMER_OFF(peer->t_gr_stale);
+ THREAD_OFF(peer->t_gr_stale);
if (bgp_debug_neighbor_events(peer))
zlog_debug(
"%pBP graceful restart stalepath timer stopped",
}
if (peer->t_gr_restart) {
- BGP_TIMER_OFF(peer->t_gr_restart);
+ THREAD_OFF(peer->t_gr_restart);
if (bgp_debug_neighbor_events(peer))
zlog_debug("%pBP graceful restart timer stopped", peer);
}
*/
FOREACH_AFI_SAFI (afi, safi) {
if (peer->t_llgr_stale[afi][safi]) {
- BGP_TIMER_OFF(peer->t_llgr_stale[afi][safi]);
+ THREAD_OFF(peer->t_llgr_stale[afi][safi]);
if (bgp_debug_neighbor_events(peer))
zlog_debug(
"%pBP Long-lived stale timer stopped for afi/safi: %d/%d",
* of read-only mode.
*/
if (!bgp_update_delay_active(peer->bgp)) {
- BGP_TIMER_OFF(peer->t_routeadv);
+ THREAD_OFF(peer->t_routeadv);
BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0);
}
/* Keepalive packet is received. */
static int bgp_fsm_keepalive(struct peer *peer)
{
- BGP_TIMER_OFF(peer->t_holdtime);
+ THREAD_OFF(peer->t_holdtime);
return 0;
}
/* Update packet is received. */
static int bgp_fsm_update(struct peer *peer)
{
- BGP_TIMER_OFF(peer->t_holdtime);
+ THREAD_OFF(peer->t_holdtime);
return 0;
}
break;
case Connect:
if (!has_valid_nexthops) {
- BGP_TIMER_OFF(peer->t_connect);
+ THREAD_OFF(peer->t_connect);
BGP_EVENT_ADD(peer, TCP_fatal_error);
}
break;
case Active:
if (has_valid_nexthops) {
- BGP_TIMER_OFF(peer->t_connect);
+ THREAD_OFF(peer->t_connect);
BGP_EVENT_ADD(peer, ConnectRetry_timer_expired);
}
break;
thread_add_timer(bm->master, (F), peer, (V), &(T)); \
} while (0)
-#define BGP_TIMER_OFF(T) \
- do { \
- THREAD_OFF((T)); \
- } while (0)
-
#define BGP_EVENT_ADD(P, E) \
do { \
if ((P)->status != Deleted) \
struct frr_pthread *fpt = bgp_pth_io;
- frr_with_mutex(&peer->io_mtx) {
+ frr_with_mutex (&peer->io_mtx) {
status = bgp_write(peer);
reschedule = (stream_fifo_head(peer->obuf) != NULL);
}
struct frr_pthread *fpt = bgp_pth_io;
- frr_with_mutex(&peer->io_mtx) {
+ frr_with_mutex (&peer->io_mtx) {
status = bgp_read(peer, &code);
}
stream_set_endp(pkt, pktsize);
frrtrace(2, frr_bgp, packet_read, peer, pkt);
- frr_with_mutex(&peer->io_mtx) {
+ frr_with_mutex (&peer->io_mtx) {
stream_fifo_push(peer->ibuf, pkt);
}
*/
assert(peerhash_mtx);
- frr_with_mutex(peerhash_mtx) {
+ frr_with_mutex (peerhash_mtx) {
holder.peer = peer;
if (!hash_lookup(peerhash, &holder)) {
struct pkat *pkat = pkat_new(peer);
*/
assert(peerhash_mtx);
- frr_with_mutex(peerhash_mtx) {
+ frr_with_mutex (peerhash_mtx) {
holder.peer = peer;
struct pkat *res = hash_release(peerhash, &holder);
if (res) {
void bgp_keepalives_wake(void)
{
- frr_with_mutex(peerhash_mtx) {
+ frr_with_mutex (peerhash_mtx) {
pthread_cond_signal(peerhash_cond);
}
}
}
case 'l':
listnode_add_sort_nodup(addresses, optarg);
- /* listenon implies -n */
- /* fallthru */
+ break;
case 'n':
no_fib_flag = 1;
break;
memset(extra->sid, 0, sizeof(extra->sid));
}
+static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn,
+ struct attr *new_attr, afi_t afi,
+ safi_t safi,
+ struct bgp_path_info *source_bpi,
+ struct bgp_path_info *bpi,
+ struct bgp *bgp_orig,
+ const struct prefix *p, int debug)
+{
+ struct bgp_path_info *bpi_ultimate;
+ struct bgp *bgp_nexthop;
+ bool nh_valid;
+
+ bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi);
+
+ if (bpi->extra && bpi->extra->bgp_orig)
+ bgp_nexthop = bpi->extra->bgp_orig;
+ else
+ bgp_nexthop = bgp_orig;
+
+ /*
+ * No nexthop tracking for redistributed routes or for
+ * EVPN-imported routes that get leaked.
+ */
+ if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
+ is_pi_family_evpn(bpi_ultimate))
+ nh_valid = 1;
+ else
+ /*
+ * TBD do we need to do anything about the
+ * 'connected' parameter?
+ */
+ nh_valid = bgp_find_or_add_nexthop(to_bgp, bgp_nexthop, afi,
+ safi, bpi, NULL, 0, p);
+
+ /*
+ * If you are using SRv6 VPN instead of MPLS, it need to check
+ * the SID allocation. If the sid is not allocated, the rib
+ * will be invalid.
+ */
+ if (to_bgp->srv6_enabled &&
+ (!new_attr->srv6_l3vpn && !new_attr->srv6_vpn)) {
+ nh_valid = false;
+ }
+
+ if (debug)
+ zlog_debug("%s: %pFX nexthop is %svalid (in vrf %s)", __func__,
+ p, (nh_valid ? "" : "not "),
+ bgp_nexthop->name_pretty);
+
+ return nh_valid;
+}
+
/*
* returns pointer to new bgp_path_info upon success
*/
static struct bgp_path_info *
-leak_update(struct bgp *bgp, /* destination bgp instance */
- struct bgp_dest *bn, struct attr *new_attr, /* already interned */
+leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
+ struct attr *new_attr, /* already interned */
afi_t afi, safi_t safi, struct bgp_path_info *source_bpi,
- mpls_label_t *label, uint32_t num_labels, void *parent,
- struct bgp *bgp_orig, struct prefix *nexthop_orig,
- int nexthop_self_flag, int debug)
+ mpls_label_t *label, uint32_t num_labels, struct bgp *bgp_orig,
+ struct prefix *nexthop_orig, int nexthop_self_flag, int debug)
{
const struct prefix *p = bgp_dest_get_prefix(bn);
struct bgp_path_info *bpi;
- struct bgp_path_info *bpi_ultimate;
struct bgp_path_info *new;
struct bgp_path_info_extra *extra;
uint32_t num_sids = 0;
+ void *parent = source_bpi;
if (new_attr->srv6_l3vpn || new_attr->srv6_vpn)
num_sids = 1;
if (debug)
zlog_debug(
"%s: entry: leak-to=%s, p=%pBD, type=%d, sub_type=%d",
- __func__, bgp->name_pretty, bn, source_bpi->type,
+ __func__, to_bgp->name_pretty, bn, source_bpi->type,
source_bpi->sub_type);
/*
* schemes that could be implemented in the future.
*
*/
- bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi);
/*
* match parent
if (debug) {
zlog_debug(
"%s: ->%s(s_flags: 0x%x b_flags: 0x%x): %pFX: Found route, being removed, not leaking",
- __func__, bgp->name_pretty,
+ __func__, to_bgp->name_pretty,
source_bpi->flags, bpi->flags, p);
}
return NULL;
if (debug)
zlog_debug(
"%s: ->%s: %pBD: Found route, no change",
- __func__, bgp->name_pretty, bn);
+ __func__, to_bgp->name_pretty, bn);
return NULL;
}
if (!ecommunity_cmp(
bgp_attr_get_ecommunity(bpi->attr),
bgp_attr_get_ecommunity(new_attr))) {
- vpn_leak_to_vrf_withdraw(bgp, bpi);
- bgp_aggregate_decrement(bgp, p, bpi, afi, safi);
+ vpn_leak_to_vrf_withdraw(to_bgp, bpi);
+ bgp_aggregate_decrement(to_bgp, p, bpi, afi,
+ safi);
bgp_path_info_delete(bn, bpi);
}
}
if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED))
bgp_path_info_restore(bn, bpi);
else
- bgp_aggregate_decrement(bgp, p, bpi, afi, safi);
+ bgp_aggregate_decrement(to_bgp, p, bpi, afi, safi);
bgp_attr_unintern(&bpi->attr);
bpi->attr = new_attr;
bpi->uptime = bgp_clock();
if (nexthop_self_flag)
bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF);
- struct bgp *bgp_nexthop = bgp;
- int nh_valid;
-
- if (bpi->extra && bpi->extra->bgp_orig)
- bgp_nexthop = bpi->extra->bgp_orig;
-
- /*
- * No nexthop tracking for redistributed routes or for
- * EVPN-imported routes that get leaked.
- */
- if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
- is_pi_family_evpn(bpi_ultimate))
- nh_valid = 1;
+ if (leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi,
+ source_bpi, bpi, bgp_orig, p,
+ debug))
+ bgp_path_info_set_flag(bn, bpi, BGP_PATH_VALID);
else
- /*
- * TBD do we need to do anything about the
- * 'connected' parameter?
- */
- nh_valid = bgp_find_or_add_nexthop(
- bgp, bgp_nexthop, afi, safi, bpi, NULL, 0, p);
-
- /*
- * If you are using SRv6 VPN instead of MPLS, it need to check
- * the SID allocation. If the sid is not allocated, the rib
- * will be invalid.
- */
- if (bgp->srv6_enabled
- && (!new_attr->srv6_l3vpn && !new_attr->srv6_vpn)) {
bgp_path_info_unset_flag(bn, bpi, BGP_PATH_VALID);
- nh_valid = false;
- }
-
- if (debug)
- zlog_debug("%s: nexthop is %svalid (in vrf %s)",
- __func__, (nh_valid ? "" : "not "),
- bgp_nexthop->name_pretty);
-
- if (nh_valid)
- bgp_path_info_set_flag(bn, bpi, BGP_PATH_VALID);
/* Process change. */
- bgp_aggregate_increment(bgp, p, bpi, afi, safi);
- bgp_process(bgp, bn, afi, safi);
+ bgp_aggregate_increment(to_bgp, p, bpi, afi, safi);
+ bgp_process(to_bgp, bn, afi, safi);
bgp_dest_unlock_node(bn);
if (debug)
zlog_debug("%s: ->%s: %pBD Found route, changed attr",
- __func__, bgp->name_pretty, bn);
+ __func__, to_bgp->name_pretty, bn);
return bpi;
}
if (debug) {
zlog_debug(
"%s: ->%s(s_flags: 0x%x): %pFX: New route, being removed, not leaking",
- __func__, bgp->name_pretty,
+ __func__, to_bgp->name_pretty,
source_bpi->flags, p);
}
return NULL;
}
new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0,
- bgp->peer_self, new_attr, bn);
+ to_bgp->peer_self, new_attr, bn);
if (nexthop_self_flag)
bgp_path_info_set_flag(bn, new, BGP_PATH_ANNC_NH_SELF);
if (nexthop_orig)
new->extra->nexthop_orig = *nexthop_orig;
- /*
- * nexthop tracking for unicast routes
- */
- struct bgp *bgp_nexthop = bgp;
- int nh_valid;
-
- if (new->extra->bgp_orig)
- bgp_nexthop = new->extra->bgp_orig;
-
- /*
- * No nexthop tracking for redistributed routes because
- * their originating protocols will do the tracking and
- * withdraw those routes if the nexthops become unreachable
- * This also holds good for EVPN-imported routes that get
- * leaked.
- */
- if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
- is_pi_family_evpn(bpi_ultimate))
- nh_valid = 1;
+ if (leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi,
+ source_bpi, new, bgp_orig, p, debug))
+ bgp_path_info_set_flag(bn, new, BGP_PATH_VALID);
else
- /*
- * TBD do we need to do anything about the
- * 'connected' parameter?
- */
- nh_valid = bgp_find_or_add_nexthop(bgp, bgp_nexthop, afi, safi,
- new, NULL, 0, p);
-
- /*
- * If you are using SRv6 VPN instead of MPLS, it need to check
- * the SID allocation. If the sid is not allocated, the rib
- * will be invalid.
- */
- if (bgp->srv6_enabled
- && (!new->attr->srv6_l3vpn && !new->attr->srv6_vpn)) {
bgp_path_info_unset_flag(bn, new, BGP_PATH_VALID);
- nh_valid = false;
- }
- if (debug)
- zlog_debug("%s: nexthop is %svalid (in vrf %s)",
- __func__, (nh_valid ? "" : "not "),
- bgp_nexthop->name_pretty);
- if (nh_valid)
- bgp_path_info_set_flag(bn, new, BGP_PATH_VALID);
-
- bgp_aggregate_increment(bgp, p, new, afi, safi);
+ bgp_aggregate_increment(to_bgp, p, new, afi, safi);
bgp_path_info_add(bn, new);
bgp_dest_unlock_node(bn);
- bgp_process(bgp, bn, afi, safi);
+ bgp_process(to_bgp, bn, afi, safi);
if (debug)
zlog_debug("%s: ->%s: %pBD: Added new route", __func__,
- bgp->name_pretty, bn);
+ to_bgp->name_pretty, bn);
return new;
}
/* cf vnc_import_bgp_add_route_mode_nvegroup() and add_vnc_route() */
-void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
- struct bgp *bgp_vrf, /* from */
+void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
+ struct bgp *from_bgp, /* from */
struct bgp_path_info *path_vrf) /* route */
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
int nexthop_self_flag = 0;
if (debug)
- zlog_debug("%s: from vrf %s", __func__, bgp_vrf->name_pretty);
+ zlog_debug("%s: from vrf %s", __func__, from_bgp->name_pretty);
if (debug && bgp_attr_get_ecommunity(path_vrf->attr)) {
char *s = ecommunity_ecom2str(
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
zlog_debug("%s: %s path_vrf->type=%d, EC{%s}", __func__,
- bgp_vrf->name, path_vrf->type, s);
+ from_bgp->name, path_vrf->type, s);
XFREE(MTYPE_ECOMMUNITY_STR, s);
}
- if (!bgp_vpn)
+ if (!to_bgp)
return;
if (!afi) {
if (!is_route_injectable_into_vpn(path_vrf))
return;
- if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
+ if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: %s skipping: %s", __func__,
- bgp_vrf->name, debugmsg);
+ from_bgp->name, debugmsg);
return;
}
/*
* route map handling
*/
- if (bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN]) {
+ if (from_bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN]) {
struct bgp_path_info info;
route_map_result_t ret;
memset(&info, 0, sizeof(info));
- info.peer = bgp_vpn->peer_self;
+ info.peer = to_bgp->peer_self;
info.attr = &static_attr;
- ret = route_map_apply(
- bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN],
- p, &info);
+ ret = route_map_apply(from_bgp->vpn_policy[afi]
+ .rmap[BGP_VPN_POLICY_DIR_TOVPN],
+ p, &info);
if (RMAP_DENYMATCH == ret) {
bgp_attr_flush(&static_attr); /* free any added parts */
if (debug)
zlog_debug(
"%s: vrf %s route map \"%s\" says DENY, returning",
- __func__, bgp_vrf->name_pretty,
- bgp_vrf->vpn_policy[afi]
+ __func__, from_bgp->name_pretty,
+ from_bgp->vpn_policy[afi]
.rmap[BGP_VPN_POLICY_DIR_TOVPN]
->name);
return;
old_ecom = bgp_attr_get_ecommunity(&static_attr);
if (old_ecom) {
new_ecom = ecommunity_dup(old_ecom);
- if (CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
- BGP_CONFIG_VRF_TO_VRF_EXPORT))
+ if (CHECK_FLAG(from_bgp->af_flags[afi][SAFI_UNICAST],
+ BGP_CONFIG_VRF_TO_VRF_EXPORT))
ecommunity_strip_rts(new_ecom);
- new_ecom = ecommunity_merge(new_ecom,
- bgp_vrf->vpn_policy[afi]
- .rtlist[BGP_VPN_POLICY_DIR_TOVPN]);
+ new_ecom = ecommunity_merge(
+ new_ecom, from_bgp->vpn_policy[afi]
+ .rtlist[BGP_VPN_POLICY_DIR_TOVPN]);
if (!old_ecom->refcnt)
ecommunity_free(&old_ecom);
} else {
new_ecom = ecommunity_dup(
- bgp_vrf->vpn_policy[afi]
+ from_bgp->vpn_policy[afi]
.rtlist[BGP_VPN_POLICY_DIR_TOVPN]);
}
bgp_attr_set_ecommunity(&static_attr, new_ecom);
/* Nexthop */
/* if policy nexthop not set, use 0 */
- if (CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
+ if (CHECK_FLAG(from_bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_NEXTHOP_SET)) {
struct prefix *nexthop =
- &bgp_vrf->vpn_policy[afi].tovpn_nexthop;
+ &from_bgp->vpn_policy[afi].tovpn_nexthop;
switch (nexthop->family) {
case AF_INET:
assert(0);
}
} else {
- if (!CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
+ if (!CHECK_FLAG(from_bgp->af_flags[afi][SAFI_UNICAST],
BGP_CONFIG_VRF_TO_VRF_EXPORT)) {
if (afi == AFI_IP) {
/*
nexthop_self_flag = 1;
}
- label_val = bgp_vrf->vpn_policy[afi].tovpn_label;
+ label_val = from_bgp->vpn_policy[afi].tovpn_label;
if (label_val == MPLS_LABEL_NONE) {
encode_label(MPLS_LABEL_IMPLICIT_NULL, &label);
} else {
/* Set originator ID to "me" */
SET_FLAG(static_attr.flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID));
- static_attr.originator_id = bgp_vpn->router_id;
+ static_attr.originator_id = to_bgp->router_id;
/* Set SID for SRv6 VPN */
- if (bgp_vrf->vpn_policy[afi].tovpn_sid_locator) {
- encode_label(bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label,
- &label);
+ if (from_bgp->vpn_policy[afi].tovpn_sid_locator) {
+ encode_label(
+ from_bgp->vpn_policy[afi].tovpn_sid_transpose_label,
+ &label);
static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,
sizeof(struct bgp_attr_srv6_l3vpn));
static_attr.srv6_l3vpn->sid_flags = 0x00;
static_attr.srv6_l3vpn->transposition_offset =
BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET;
memcpy(&static_attr.srv6_l3vpn->sid,
- bgp_vrf->vpn_policy[afi].tovpn_sid_locator,
+ from_bgp->vpn_policy[afi].tovpn_sid_locator,
sizeof(struct in6_addr));
}
/* Now new_attr is an allocated interned attr */
- bn = bgp_afi_node_get(bgp_vpn->rib[afi][safi], afi, safi, p,
- &(bgp_vrf->vpn_policy[afi].tovpn_rd));
+ bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p,
+ &(from_bgp->vpn_policy[afi].tovpn_rd));
struct bgp_path_info *new_info;
- new_info = leak_update(bgp_vpn, bn, new_attr, afi, safi, path_vrf,
- &label, 1, path_vrf, bgp_vrf, NULL,
- nexthop_self_flag, debug);
+ new_info =
+ leak_update(to_bgp, bn, new_attr, afi, safi, path_vrf, &label,
+ 1, from_bgp, NULL, nexthop_self_flag, debug);
/*
* Routes actually installed in the vpn RIB must also be
* because of loop checking.
*/
if (new_info)
- vpn_leak_to_vrf_update(bgp_vrf, new_info);
+ vpn_leak_to_vrf_update(from_bgp, new_info);
}
-void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
- struct bgp *bgp_vrf, /* from */
+void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp, /* to */
+ struct bgp *from_bgp, /* from */
struct bgp_path_info *path_vrf) /* route */
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
if (debug) {
zlog_debug(
"%s: entry: leak-from=%s, p=%pBD, type=%d, sub_type=%d",
- __func__, bgp_vrf->name_pretty, path_vrf->net,
+ __func__, from_bgp->name_pretty, path_vrf->net,
path_vrf->type, path_vrf->sub_type);
}
- if (!bgp_vpn)
+ if (!to_bgp)
return;
if (!afi) {
if (!is_route_injectable_into_vpn(path_vrf))
return;
- if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
+ if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: skipping: %s", __func__, debugmsg);
return;
if (debug)
zlog_debug("%s: withdrawing (path_vrf=%p)", __func__, path_vrf);
- bn = bgp_afi_node_get(bgp_vpn->rib[afi][safi], afi, safi, p,
- &(bgp_vrf->vpn_policy[afi].tovpn_rd));
+ bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p,
+ &(from_bgp->vpn_policy[afi].tovpn_rd));
if (!bn)
return;
if (bpi) {
/* withdraw from looped vrfs as well */
- vpn_leak_to_vrf_withdraw(bgp_vpn, bpi);
+ vpn_leak_to_vrf_withdraw(to_bgp, bpi);
- bgp_aggregate_decrement(bgp_vpn, p, bpi, afi, safi);
+ bgp_aggregate_decrement(to_bgp, p, bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
- bgp_process(bgp_vpn, bn, afi, safi);
+ bgp_process(to_bgp, bn, afi, safi);
}
bgp_dest_unlock_node(bn);
}
-void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */
- struct bgp *bgp_vrf, /* from */
+void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp, struct bgp *from_bgp,
afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
safi_t safi = SAFI_MPLS_VPN;
/*
- * Walk vpn table, delete bpi with bgp_orig == bgp_vrf
+ * Walk vpn table, delete bpi with bgp_orig == from_bgp
*/
- for (pdest = bgp_table_top(bgp_vpn->rib[afi][safi]); pdest;
+ for (pdest = bgp_table_top(to_bgp->rib[afi][safi]); pdest;
pdest = bgp_route_next(pdest)) {
struct bgp_table *table;
continue;
if (!bpi->extra)
continue;
- if ((struct bgp *)bpi->extra->bgp_orig
- == bgp_vrf) {
+ if ((struct bgp *)bpi->extra->bgp_orig ==
+ from_bgp) {
/* delete route */
if (debug)
zlog_debug("%s: deleting it",
__func__);
/* withdraw from leak-to vrfs as well */
- vpn_leak_to_vrf_withdraw(bgp_vpn, bpi);
+ vpn_leak_to_vrf_withdraw(to_bgp, bpi);
bgp_aggregate_decrement(
- bgp_vpn,
- bgp_dest_get_prefix(bn), bpi,
- afi, safi);
+ to_bgp, bgp_dest_get_prefix(bn),
+ bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
- bgp_process(bgp_vpn, bn, afi, safi);
+ bgp_process(to_bgp, bn, afi, safi);
}
}
}
}
}
-void vpn_leak_from_vrf_update_all(struct bgp *bgp_vpn, /* to */
- struct bgp *bgp_vrf, /* from */
+void vpn_leak_from_vrf_update_all(struct bgp *to_bgp, struct bgp *from_bgp,
afi_t afi)
{
struct bgp_dest *bn;
if (debug)
zlog_debug("%s: entry, afi=%d, vrf=%s", __func__, afi,
- bgp_vrf->name_pretty);
+ from_bgp->name_pretty);
- for (bn = bgp_table_top(bgp_vrf->rib[afi][SAFI_UNICAST]); bn;
+ for (bn = bgp_table_top(from_bgp->rib[afi][SAFI_UNICAST]); bn;
bn = bgp_route_next(bn)) {
if (debug)
zlog_debug(
"%s: calling vpn_leak_from_vrf_update",
__func__);
- vpn_leak_from_vrf_update(bgp_vpn, bgp_vrf, bpi);
+ vpn_leak_from_vrf_update(to_bgp, from_bgp, bpi);
}
}
}
-static void
-vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
- struct bgp *bgp_vpn, /* from */
+static bool
+vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
+ struct bgp *from_bgp, /* from */
struct bgp_path_info *path_vpn) /* route */
{
const struct prefix *p = bgp_dest_get_prefix(path_vpn->net);
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
- if (!vpn_leak_from_vpn_active(bgp_vrf, afi, &debugmsg)) {
+ if (!vpn_leak_from_vpn_active(to_bgp, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: skipping: %s", __func__, debugmsg);
- return;
+ return false;
}
/* Check for intersection of route targets */
if (!ecom_intersect(
- bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
+ to_bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
bgp_attr_get_ecommunity(path_vpn->attr))) {
if (debug)
zlog_debug(
"from vpn (%s) to vrf (%s), skipping after no intersection of route targets",
- bgp_vpn->name_pretty, bgp_vrf->name_pretty);
- return;
+ from_bgp->name_pretty, to_bgp->name_pretty);
+ return false;
}
if (debug)
zlog_debug("%s: updating %pFX to vrf %s", __func__, p,
- bgp_vrf->name_pretty);
+ to_bgp->name_pretty);
/* shallow copy */
static_attr = *path_vpn->attr;
/* If doing VRF-to-VRF leaking, strip RTs. */
old_ecom = bgp_attr_get_ecommunity(&static_attr);
- if (old_ecom && CHECK_FLAG(bgp_vrf->af_flags[afi][safi],
- BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
+ if (old_ecom && CHECK_FLAG(to_bgp->af_flags[afi][safi],
+ BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
new_ecom = ecommunity_dup(old_ecom);
ecommunity_strip_rts(new_ecom);
bgp_attr_set_ecommunity(&static_attr, new_ecom);
nexthop_orig.u.prefix4 = path_vpn->attr->mp_nexthop_global_in;
nexthop_orig.prefixlen = IPV4_MAX_BITLEN;
- if (CHECK_FLAG(bgp_vrf->af_flags[afi][safi],
+ if (CHECK_FLAG(to_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
static_attr.nexthop.s_addr =
nexthop_orig.u.prefix4.s_addr;
nexthop_orig.u.prefix6 = path_vpn->attr->mp_nexthop_global;
nexthop_orig.prefixlen = IPV6_MAX_BITLEN;
- if (CHECK_FLAG(bgp_vrf->af_flags[afi][safi],
+ if (CHECK_FLAG(to_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
static_attr.mp_nexthop_global = nexthop_orig.u.prefix6;
}
/*
* route map handling
*/
- if (bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_FROMVPN]) {
+ if (to_bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_FROMVPN]) {
struct bgp_path_info info;
route_map_result_t ret;
memset(&info, 0, sizeof(info));
- info.peer = bgp_vrf->peer_self;
+ info.peer = to_bgp->peer_self;
info.attr = &static_attr;
info.extra = path_vpn->extra; /* Used for source-vrf filter */
- ret = route_map_apply(bgp_vrf->vpn_policy[afi]
+ ret = route_map_apply(to_bgp->vpn_policy[afi]
.rmap[BGP_VPN_POLICY_DIR_FROMVPN],
p, &info);
if (RMAP_DENYMATCH == ret) {
if (debug)
zlog_debug(
"%s: vrf %s vpn-policy route map \"%s\" says DENY, returning",
- __func__, bgp_vrf->name_pretty,
- bgp_vrf->vpn_policy[afi]
+ __func__, to_bgp->name_pretty,
+ to_bgp->vpn_policy[afi]
.rmap[BGP_VPN_POLICY_DIR_FROMVPN]
->name);
- return;
+ return false;
}
/*
* if route-map changed nexthop, don't nexthop-self on output
new_attr = bgp_attr_intern(&static_attr);
bgp_attr_flush(&static_attr);
- bn = bgp_afi_node_get(bgp_vrf->rib[afi][safi], afi, safi, p, NULL);
+ bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL);
/*
* ensure labels are copied
* labels for these routes enables the non-labeled nexthops
* from the originating VRF to be considered valid for this route.
*/
- if (!CHECK_FLAG(bgp_vrf->af_flags[afi][safi],
+ if (!CHECK_FLAG(to_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
/* work back to original route */
bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn);
if (path_vpn->extra && path_vpn->extra->bgp_orig)
src_vrf = path_vpn->extra->bgp_orig;
else
- src_vrf = bgp_vpn;
+ src_vrf = from_bgp;
- leak_update(bgp_vrf, bn, new_attr, afi, safi, path_vpn, pLabels,
- num_labels, path_vpn, /* parent */
- src_vrf, &nexthop_orig, nexthop_self_flag, debug);
+ leak_update(to_bgp, bn, new_attr, afi, safi, path_vpn, pLabels,
+ num_labels, src_vrf, &nexthop_orig, nexthop_self_flag,
+ debug);
+ return true;
}
-void vpn_leak_to_vrf_update(struct bgp *bgp_vpn, /* from */
+bool vpn_leak_to_vrf_update(struct bgp *from_bgp, /* from */
struct bgp_path_info *path_vpn) /* route */
{
struct listnode *mnode, *mnnode;
struct bgp *bgp;
+ bool leak_success = false;
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
if (!path_vpn->extra
|| path_vpn->extra->bgp_orig != bgp) { /* no loop */
- vpn_leak_to_vrf_update_onevrf(bgp, bgp_vpn, path_vpn);
+ leak_success |= vpn_leak_to_vrf_update_onevrf(
+ bgp, from_bgp, path_vpn);
}
}
+ return leak_success;
}
-void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn, /* from */
+void vpn_leak_to_vrf_withdraw(struct bgp *from_bgp, /* from */
struct bgp_path_info *path_vpn) /* route */
{
const struct prefix *p;
}
}
-void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, /* to */
- afi_t afi)
+void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi)
{
struct bgp_dest *bn;
struct bgp_path_info *bpi;
/*
* Walk vrf table, delete bpi with bgp_orig in a different vrf
*/
- for (bn = bgp_table_top(bgp_vrf->rib[afi][safi]); bn;
+ for (bn = bgp_table_top(to_bgp->rib[afi][safi]); bn;
bn = bgp_route_next(bn)) {
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
bpi = bpi->next) {
- if (bpi->extra
- && bpi->extra->bgp_orig != bgp_vrf
- && bpi->extra->parent
- && is_pi_family_vpn(bpi->extra->parent)) {
+ if (bpi->extra && bpi->extra->bgp_orig != to_bgp &&
+ bpi->extra->parent &&
+ is_pi_family_vpn(bpi->extra->parent)) {
/* delete route */
- bgp_aggregate_decrement(bgp_vrf,
+ bgp_aggregate_decrement(to_bgp,
bgp_dest_get_prefix(bn),
bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
- bgp_process(bgp_vrf, bn, afi, safi);
+ bgp_process(to_bgp, bn, afi, safi);
}
}
}
}
-void vpn_leak_to_vrf_update_all(struct bgp *bgp_vrf, /* to */
- struct bgp *bgp_vpn, /* from */
+void vpn_leak_to_vrf_update_all(struct bgp *to_bgp, struct bgp *vpn_from,
afi_t afi)
{
struct bgp_dest *pdest;
safi_t safi = SAFI_MPLS_VPN;
- assert(bgp_vpn);
+ assert(vpn_from);
/*
* Walk vpn table
*/
- for (pdest = bgp_table_top(bgp_vpn->rib[afi][safi]); pdest;
+ for (pdest = bgp_table_top(vpn_from->rib[afi][safi]); pdest;
pdest = bgp_route_next(pdest)) {
struct bgp_table *table;
struct bgp_dest *bn;
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
bpi = bpi->next) {
- if (bpi->extra
- && bpi->extra->bgp_orig == bgp_vrf)
+ if (bpi->extra &&
+ bpi->extra->bgp_orig == to_bgp)
continue;
- vpn_leak_to_vrf_update_onevrf(bgp_vrf, bgp_vpn,
+ vpn_leak_to_vrf_update_onevrf(to_bgp, vpn_from,
bpi);
}
}
IP_STR
BGP_STR
BGP_AFI_HELP_STR
- "Address Family modifier\n"
+ BGP_AF_MODIFIER_STR
"Display information for a route distinguisher\n"
"VPN Route Distinguisher\n"
"All VPN Route Distinguishers\n")
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_rd.h"
#include "bgpd/bgp_zebra.h"
+#include "bgpd/bgp_vty.h"
#define MPLS_LABEL_IS_SPECIAL(label) ((label) <= MPLS_LABEL_EXTENSION)
#define MPLS_LABEL_IS_NULL(label) \
|| (label) == MPLS_LABEL_IPV6_EXPLICIT_NULL \
|| (label) == MPLS_LABEL_IMPLICIT_NULL)
-#define BGP_VPNVX_HELP_STR \
- "Address Family\n" \
- "Address Family\n"
+#define BGP_VPNVX_HELP_STR BGP_AF_STR BGP_AF_STR
#define V4_HEADER \
" Network Next Hop Metric LocPrf Weight Path\n"
enum bgp_show_type type, void *output_arg,
int tags, bool use_json);
-extern void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
+extern void vpn_leak_from_vrf_update(struct bgp *to_bgp, struct bgp *from_bgp,
struct bgp_path_info *path_vrf);
-extern void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
+extern void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp, struct bgp *from_bgp,
struct bgp_path_info *path_vrf);
-extern void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn,
- struct bgp *bgp_vrf, afi_t afi);
+extern void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp,
+ struct bgp *from_bgp, afi_t afi);
-extern void vpn_leak_from_vrf_update_all(struct bgp *bgp_vpn,
- struct bgp *bgp_vrf, afi_t afi);
+extern void vpn_leak_from_vrf_update_all(struct bgp *to_bgp,
+ struct bgp *from_bgp, afi_t afi);
-extern void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, afi_t afi);
+extern void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi);
-extern void vpn_leak_to_vrf_update_all(struct bgp *bgp_vrf, struct bgp *bgp_vpn,
+extern void vpn_leak_to_vrf_update_all(struct bgp *to_bgp, struct bgp *from_bgp,
afi_t afi);
-extern void vpn_leak_to_vrf_update(struct bgp *bgp_vpn,
+extern bool vpn_leak_to_vrf_update(struct bgp *from_bgp,
struct bgp_path_info *path_vpn);
-extern void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn,
+extern void vpn_leak_to_vrf_withdraw(struct bgp *from_bgp,
struct bgp_path_info *path_vpn);
extern void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi);
if (!bgp_vpn)
return;
- if (direction == BGP_VPN_POLICY_DIR_FROMVPN)
- vpn_leak_to_vrf_update_all(bgp_vrf, bgp_vpn, afi);
+ if (direction == BGP_VPN_POLICY_DIR_FROMVPN) {
+ /* trigger a flush to re-sync with ADJ-RIB-in */
+ if (!CHECK_FLAG(bgp_vpn->af_flags[afi][SAFI_MPLS_VPN],
+ BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL))
+ bgp_clear_soft_in(bgp_vpn, afi, SAFI_MPLS_VPN);
+ else
+ vpn_leak_to_vrf_update_all(bgp_vrf, bgp_vpn, afi);
+ }
if (direction == BGP_VPN_POLICY_DIR_TOVPN) {
if (bgp_vrf->vpn_policy[afi].tovpn_label !=
sockopt_tcp_mss_set(bgp_sock, peer1->tcp_mss);
bgp_fsm_change_status(peer1, Active);
- BGP_TIMER_OFF(
+ THREAD_OFF(
peer1->t_start); /* created in peer_create() */
if (peer_active(peer1)) {
}
bgp_peer_reg_with_nht(peer);
bgp_fsm_change_status(peer, Active);
- BGP_TIMER_OFF(peer->t_start); /* created in peer_create() */
+ THREAD_OFF(peer->t_start); /* created in peer_create() */
SET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER);
/* Make dummy peer until read Open packet. */
if (a->srte_color > b->srte_color)
return 1;
+ if (a->ifindex < b->ifindex)
+ return -1;
+ if (a->ifindex > b->ifindex)
+ return 1;
+
return prefix_cmp(&a->prefix, &b->prefix);
}
}
struct bgp_nexthop_cache *bnc_new(struct bgp_nexthop_cache_head *tree,
- struct prefix *prefix, uint32_t srte_color)
+ struct prefix *prefix, uint32_t srte_color,
+ ifindex_t ifindex)
{
struct bgp_nexthop_cache *bnc;
bnc = XCALLOC(MTYPE_BGP_NEXTHOP_CACHE,
sizeof(struct bgp_nexthop_cache));
bnc->prefix = *prefix;
+ bnc->ifindex = ifindex;
bnc->srte_color = srte_color;
bnc->tree = tree;
LIST_INIT(&(bnc->paths));
}
struct bgp_nexthop_cache *bnc_find(struct bgp_nexthop_cache_head *tree,
- struct prefix *prefix, uint32_t srte_color)
+ struct prefix *prefix, uint32_t srte_color,
+ ifindex_t ifindex)
{
struct bgp_nexthop_cache bnc = {};
bnc.prefix = *prefix;
bnc.srte_color = srte_color;
+ bnc.ifindex = ifindex;
return bgp_nexthop_cache_find(tree, &bnc);
}
}
tree = import_table ? &bgp->import_check_table
: &bgp->nexthop_cache_table;
- bnc = bnc_find(tree[family2afi(nhop.family)], &nhop, 0);
+ bnc = bnc_find(tree[family2afi(nhop.family)], &nhop, 0, 0);
if (!bnc) {
vty_out(vty, "specified nexthop does not have entry\n");
return CMD_SUCCESS;
struct bgp_dest *dest);
extern struct bgp_nexthop_cache *bnc_new(struct bgp_nexthop_cache_head *tree,
struct prefix *prefix,
- uint32_t srte_color);
+ uint32_t srte_color,
+ ifindex_t ifindex);
extern bool bnc_existing_for_prefix(struct bgp_nexthop_cache *bnc);
extern void bnc_free(struct bgp_nexthop_cache *bnc);
extern struct bgp_nexthop_cache *bnc_find(struct bgp_nexthop_cache_head *tree,
struct prefix *prefix,
- uint32_t srte_color);
+ uint32_t srte_color,
+ ifindex_t ifindex);
extern void bnc_nexthop_free(struct bgp_nexthop_cache *bnc);
extern const char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size);
extern void bgp_scan_init(struct bgp *bgp);
if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info) {
if (BGP_DEBUG(nht, NHT)) {
char buf[PREFIX2STR_BUFFER];
- zlog_debug("%s: freeing bnc %s(%u)(%s)", __func__,
+ zlog_debug("%s: freeing bnc %s(%d)(%u)(%s)", __func__,
bnc_str(bnc, buf, PREFIX2STR_BUFFER),
- bnc->srte_color, bnc->bgp->name_pretty);
+ bnc->ifindex, bnc->srte_color,
+ bnc->bgp->name_pretty);
}
/* only unregister if this is the last nh for this prefix*/
if (!bnc_existing_for_prefix(bnc))
struct prefix pt;
struct bgp_nexthop_cache *bncp, *bnct;
afi_t afi;
+ ifindex_t ifindex = 0;
if (!sockunion2hostprefix(&from->su, &pp))
return;
+ /*
+ * Gather the ifindex for if up/down events to be
+ * tagged into this fun
+ */
+ if (from->conf_if && IN6_IS_ADDR_LINKLOCAL(&from->su.sin6.sin6_addr))
+ ifindex = from->su.sin6.sin6_scope_id;
+
afi = family2afi(pp.family);
- bncp = bnc_find(&from->bgp->nexthop_cache_table[afi], &pp, 0);
+ bncp = bnc_find(&from->bgp->nexthop_cache_table[afi], &pp, 0, ifindex);
if (!sockunion2hostprefix(&to->su, &pt))
return;
- bnct = bnc_find(&to->bgp->nexthop_cache_table[afi], &pt, 0);
+ /*
+ * Gather the ifindex for if up/down events to be
+ * tagged into this fun
+ */
+ ifindex = 0;
+ if (to->conf_if && IN6_IS_ADDR_LINKLOCAL(&to->su.sin6.sin6_addr))
+ ifindex = to->su.sin6.sin6_scope_id;
+ bnct = bnc_find(&to->bgp->nexthop_cache_table[afi], &pt, 0, ifindex);
if (bnct != bncp)
return;
struct prefix p;
struct bgp_nexthop_cache *bnc;
afi_t afi = family2afi(peer->su.sa.sa_family);
+ ifindex_t ifindex = 0;
if (!sockunion2hostprefix(&peer->su, &p))
return;
-
- bnc = bnc_find(&peer->bgp->nexthop_cache_table[afi], &p, 0);
+ /*
+ * Gather the ifindex for if up/down events to be
+ * tagged into this fun
+ */
+ if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr))
+ ifindex = peer->su.sin6.sin6_scope_id;
+ bnc = bnc_find(&peer->bgp->nexthop_cache_table[afi], &p, 0, ifindex);
if (!bnc)
return;
to derive
address-family from the next-hop. */
if (!is_bgp_static_route)
- afi = BGP_ATTR_NEXTHOP_AFI_IP6(pi->attr) ? AFI_IP6
- : AFI_IP;
+ afi = BGP_ATTR_MP_NEXTHOP_LEN_IP6(pi->attr) ? AFI_IP6
+ : AFI_IP;
/* Validation for the ipv4 mapped ipv6 nexthop. */
if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) {
* Gather the ifindex for if up/down events to be
* tagged into this fun
*/
- if (afi == AFI_IP6
- && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr))
+ if (afi == AFI_IP6 &&
+ IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)) {
ifindex = peer->su.sin6.sin6_scope_id;
+ if (ifindex == 0) {
+ if (BGP_DEBUG(nht, NHT)) {
+ zlog_debug(
+ "%s: Unable to locate ifindex, waiting till we have one",
+ peer->conf_if);
+ }
+ return 0;
+ }
+ }
if (!sockunion2hostprefix(&peer->su, &p)) {
if (BGP_DEBUG(nht, NHT)) {
else
tree = &bgp_nexthop->nexthop_cache_table[afi];
- bnc = bnc_find(tree, &p, srte_color);
+ bnc = bnc_find(tree, &p, srte_color, ifindex);
if (!bnc) {
- bnc = bnc_new(tree, &p, srte_color);
+ bnc = bnc_new(tree, &p, srte_color, ifindex);
bnc->bgp = bgp_nexthop;
- bnc->ifindex = ifindex;
if (BGP_DEBUG(nht, NHT)) {
char buf[PREFIX2STR_BUFFER];
- zlog_debug("Allocated bnc %s(%u)(%s) peer %p",
+ zlog_debug("Allocated bnc %s(%d)(%u)(%s) peer %p",
bnc_str(bnc, buf, PREFIX2STR_BUFFER),
- bnc->srte_color, bnc->bgp->name_pretty,
- peer);
+ bnc->ifindex, bnc->srte_color,
+ bnc->bgp->name_pretty, peer);
}
} else {
if (BGP_DEBUG(nht, NHT)) {
char buf[PREFIX2STR_BUFFER];
zlog_debug(
- "Found existing bnc %s(%s) flags 0x%x ifindex %d #paths %d peer %p",
+ "Found existing bnc %s(%d)(%s) flags 0x%x ifindex %d #paths %d peer %p",
bnc_str(bnc, buf, PREFIX2STR_BUFFER),
- bnc->bgp->name_pretty, bnc->flags, bnc->ifindex,
- bnc->path_count, bnc->nht_info);
+ bnc->ifindex, bnc->bgp->name_pretty, bnc->flags,
+ bnc->ifindex, bnc->path_count, bnc->nht_info);
}
}
{
struct bgp_nexthop_cache *bnc;
struct prefix p;
+ ifindex_t ifindex = 0;
if (!peer)
return;
if (!sockunion2hostprefix(&peer->su, &p))
return;
-
+ /*
+ * Gather the ifindex for if up/down events to be
+ * tagged into this fun
+ */
+ if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr))
+ ifindex = peer->su.sin6.sin6_scope_id;
bnc = bnc_find(&peer->bgp->nexthop_cache_table[family2afi(p.family)],
- &p, 0);
+ &p, 0, ifindex);
if (!bnc) {
if (BGP_DEBUG(nht, NHT))
zlog_debug(
char bnc_buf[BNC_FLAG_DUMP_SIZE];
zlog_debug(
- "%s(%u): Rcvd NH update %pFX(%u) - metric %d/%d #nhops %d/%d flags %s",
+ "%s(%u): Rcvd NH update %pFX(%u)%u) - metric %d/%d #nhops %d/%d flags %s",
bnc->bgp->name_pretty, bnc->bgp->vrf_id, &nhr->prefix,
- bnc->srte_color, nhr->metric, bnc->metric,
+ bnc->ifindex, bnc->srte_color, nhr->metric, bnc->metric,
nhr->nexthop_num, bnc->nexthop_num,
bgp_nexthop_dump_bnc_flags(bnc, bnc_buf,
sizeof(bnc_buf)));
struct bgp_nexthop_cache_head *table;
struct bgp_nexthop_cache *bnc;
struct prefix p;
+ ifindex_t ifindex = 0;
if (!IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr))
return;
if (!sockunion2hostprefix(&peer->su, &p))
return;
+ /*
+ * Gather the ifindex for if up/down events to be
+ * tagged into this fun
+ */
+ if (peer->conf_if && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr))
+ ifindex = peer->su.sin6.sin6_scope_id;
table = &bgp->nexthop_cache_table[AFI_IP6];
- bnc = bnc_find(table, &p, 0);
+ bnc = bnc_find(table, &p, 0, ifindex);
if (!bnc)
return;
afi = family2afi(match.family);
tree = &bgp->nexthop_cache_table[afi];
- bnc_nhc = bnc_find(tree, &match, nhr.srte_color);
+ bnc_nhc = bnc_find(tree, &match, nhr.srte_color, 0);
if (!bnc_nhc) {
if (BGP_DEBUG(nht, NHT))
zlog_debug(
tree = &bgp->import_check_table[afi];
- bnc_import = bnc_find(tree, &match, nhr.srte_color);
+ bnc_import = bnc_find(tree, &match, nhr.srte_color, 0);
if (!bnc_import) {
if (BGP_DEBUG(nht, NHT))
zlog_debug(
p->u.prefix4 = ipv4;
p->prefixlen = IPV4_MAX_BITLEN;
} else {
- p->u.prefix4 = pi->attr->nexthop;
+ if (p_orig->family == AF_EVPN)
+ p->u.prefix4 =
+ pi->attr->mp_nexthop_global_in;
+ else
+ p->u.prefix4 = pi->attr->nexthop;
p->prefixlen = IPV4_MAX_BITLEN;
}
}
bnc_str(bnc, buf, PREFIX2STR_BUFFER);
zlog_debug(
- "NH update for %s(%u)(%s) - flags %s chgflags %s- evaluate paths",
- buf, bnc->srte_color, bnc->bgp->name_pretty,
+ "NH update for %s(%d)(%u)(%s) - flags %s chgflags %s- evaluate paths",
+ buf, bnc->ifindex, bnc->srte_color,
+ bnc->bgp->name_pretty,
bgp_nexthop_dump_bnc_flags(bnc, bnc_buf,
sizeof(bnc_buf)),
bgp_nexthop_dump_bnc_change_flags(bnc, chg_buf,
struct nexthop *nhop;
struct interface *ifp;
struct prefix p;
+ ifindex_t ifindex = 0;
if (peer->ifp)
return;
if (p.family != AF_INET6)
return;
+ /*
+ * Gather the ifindex for if up/down events to be
+ * tagged into this fun
+ */
+ if (peer->conf_if && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr))
+ ifindex = peer->su.sin6.sin6_scope_id;
- bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p, 0);
+ bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p, 0, ifindex);
if (!bnc)
return;
struct nexthop *nhop;
struct interface *ifp;
struct prefix p;
+ ifindex_t ifindex = 0;
if (peer->ifp)
return;
if (p.family != AF_INET6)
return;
+ /*
+ * Gather the ifindex for if up/down events to be
+ * tagged into this fun
+ */
+ if (peer->conf_if && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr))
+ ifindex = peer->su.sin6.sin6_scope_id;
- bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p, 0);
+ bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p, 0, ifindex);
if (!bnc)
return;
return true;
}
if (remote_role == ROLE_UNDEFINED &&
- CHECK_FLAG(peer->flags, PEER_FLAG_STRICT_MODE)) {
+ CHECK_FLAG(peer->flags, PEER_FLAG_ROLE_STRICT_MODE)) {
const char *err_msg =
"Strict mode. Please set the role on your side.";
bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR,
intmax_t delta;
uint32_t holdtime;
- frr_with_mutex(&peer->io_mtx) {
+ frr_with_mutex (&peer->io_mtx) {
/* if the queue is empty, reset the "last OK" timestamp to
* now, otherwise if we write another packet immediately
* after it'll get confused
bn.subcode = notify->raw_data[1];
bn.length = notify->length - 2;
- bn.raw_data = XCALLOC(MTYPE_BGP_NOTIFICATION, bn.length);
+ bn.raw_data = XMALLOC(MTYPE_BGP_NOTIFICATION, bn.length);
memcpy(bn.raw_data, notify->raw_data + 2, bn.length);
return bn;
gr_info->eor_required,
"EOR RCV",
gr_info->eor_received);
- BGP_TIMER_OFF(
- gr_info->t_select_deferral);
+ THREAD_OFF(gr_info->t_select_deferral);
gr_info->eor_required = 0;
gr_info->eor_received = 0;
/* Best path selection */
- if (bgp_best_path_select_defer(
- peer->bgp, afi, safi)
- < 0)
- return BGP_Stop;
+ bgp_best_path_select_defer(peer->bgp,
+ afi, safi);
}
}
if (outer.length) {
XFREE(MTYPE_BGP_NOTIFICATION, outer.data);
XFREE(MTYPE_BGP_NOTIFICATION, outer.raw_data);
+
+ /* If this is a Hard Reset notification, we MUST free
+ * the inner (encapsulated) notification too.
+ */
+ if (hard_reset)
+ XFREE(MTYPE_BGP_NOTIFICATION, inner.raw_data);
outer.length = 0;
}
}
peer, orf_type, orf_len);
}
+ /* ORF prefix-list name */
+ snprintf(name, sizeof(name), "%s.%d.%d",
+ peer->host, afi, safi);
+
/* we're going to read at least 1 byte of common
* ORF header,
* and 7 bytes of ORF Address-filter entry from
* the stream
*/
- if (orf_len < 7)
+ if (*p_pnt & ORF_COMMON_PART_REMOVE_ALL) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%pBP rcvd Remove-All pfxlist ORF request",
+ peer);
+ prefix_bgp_orf_remove_all(afi, name);
break;
+ }
- /* ORF prefix-list name */
- snprintf(name, sizeof(name), "%s.%d.%d",
- peer->host, afi, safi);
+ if (orf_len < 7)
+ break;
while (p_pnt < p_end) {
/* If the ORF entry is malformed, want
memset(&orfp, 0, sizeof(orfp));
common = *p_pnt++;
/* after ++: p_pnt <= p_end */
- if (common
- & ORF_COMMON_PART_REMOVE_ALL) {
- if (bgp_debug_neighbor_events(
- peer))
- zlog_debug(
- "%pBP rcvd Remove-All pfxlist ORF request",
- peer);
- prefix_bgp_orf_remove_all(afi,
- name);
- break;
- }
ok = ((uint32_t)(p_end - p_pnt)
>= sizeof(uint32_t));
if (ok) {
return BGP_PACKET_NOOP;
}
- BGP_TIMER_OFF(peer->t_refresh_stalepath);
+ THREAD_OFF(peer->t_refresh_stalepath);
SET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_EORR_RECEIVED);
UNSET_FLAG(peer->af_sflags[afi][safi],
"%s CAPABILITY has action: %d, code: %u, length %u",
peer->host, action, hdr->code, hdr->length);
+ if (hdr->length < sizeof(struct capability_mp_data)) {
+ zlog_info(
+ "%pBP Capability structure is not properly filled out, expected at least %zu bytes but header length specified is %d",
+ peer, sizeof(struct capability_mp_data),
+ hdr->length);
+ return BGP_Stop;
+ }
+
/* Capability length check. */
if ((pnt + hdr->length + 3) > end) {
zlog_info("%s Capability length error", peer->host);
bgp_size_t size;
char notify_data_length[2];
- frr_with_mutex(&peer->io_mtx) {
+ frr_with_mutex (&peer->io_mtx) {
peer->curr = stream_fifo_pop(peer->ibuf);
}
if (fsm_update_result != FSM_PEER_TRANSFERRED
&& fsm_update_result != FSM_PEER_STOPPED) {
- frr_with_mutex(&peer->io_mtx) {
+ frr_with_mutex (&peer->io_mtx) {
// more work to do, come back later
if (peer->ibuf->count > 0)
thread_add_event(
static void bgp_peer_as_override(struct bgp *bgp, afi_t afi, safi_t safi,
struct peer *peer, struct attr *attr)
{
- if (peer->sort == BGP_PEER_EBGP
- && peer_af_flag_check(peer, afi, safi, PEER_FLAG_AS_OVERRIDE)) {
- if (aspath_single_asn_check(attr->aspath, peer->as))
- attr->aspath = aspath_replace_specific_asn(
- attr->aspath, peer->as, bgp->as);
- }
+ if (peer->sort == BGP_PEER_EBGP &&
+ peer_af_flag_check(peer, afi, safi, PEER_FLAG_AS_OVERRIDE))
+ attr->aspath = aspath_replace_specific_asn(attr->aspath,
+ peer->as, bgp->as);
}
void bgp_attr_add_llgr_community(struct attr *attr)
bgp_peer_remove_private_as(bgp, afi, safi, peer, attr);
bgp_peer_as_override(bgp, afi, safi, peer, attr);
+ if (filter->advmap.update_type == UPDATE_TYPE_WITHDRAW &&
+ filter->advmap.aname &&
+ route_map_lookup_by_name(filter->advmap.aname)) {
+ struct bgp_path_info rmap_path = {0};
+ struct bgp_path_info_extra dummy_rmap_path_extra = {0};
+ struct attr dummy_attr = *attr;
+
+ /* Fill temp path_info */
+ prep_for_rmap_apply(&rmap_path, &dummy_rmap_path_extra, dest,
+ pi, peer, &dummy_attr);
+
+ struct route_map *amap =
+ route_map_lookup_by_name(filter->advmap.aname);
+
+ ret = route_map_apply(amap, p, &rmap_path);
+
+ bgp_attr_flush(&dummy_attr);
+
+ /*
+ * The conditional advertisement mode is Withdraw and this
+ * prefix is a conditional prefix. Don't advertise it
+ */
+ if (ret == RMAP_PERMITMATCH)
+ return false;
+ }
+
/* Route map & unsuppress-map apply. */
if (!post_attr &&
(ROUTE_MAP_OUT_NAME(filter) || bgp_path_suppressed(pi))) {
}
/* Process the routes with the flag BGP_NODE_SELECT_DEFER set */
-int bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi)
+void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi)
{
struct bgp_dest *dest;
int cnt = 0;
thread_info = THREAD_ARG(t);
XFREE(MTYPE_TMP, thread_info);
- BGP_TIMER_OFF(bgp->gr_info[afi][safi].t_route_select);
+ THREAD_OFF(bgp->gr_info[afi][safi].t_route_select);
}
if (BGP_DEBUG(update, UPDATE_OUT)) {
/* Send route processing complete message to RIB */
bgp_zebra_update(afi, safi, bgp->vrf_id,
ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE);
- return 0;
+ return;
}
thread_info = XMALLOC(MTYPE_TMP, sizeof(struct afi_safi_info));
thread_add_timer(bm->master, bgp_route_select_timer_expire, thread_info,
BGP_ROUTE_SELECT_DELAY,
&bgp->gr_info[afi][safi].t_route_select);
- return 0;
}
static wq_item_status bgp_process_wq(struct work_queue *wq, void *data)
uint8_t pi_sub_type = 0;
bool force_evpn_import = false;
safi_t orig_safi = safi;
+ bool leak_success = true;
if (frrtrace_enabled(frr_bgp, process_update)) {
char pfxprint[PREFIX2STR_BUFFER];
if ((SAFI_MPLS_VPN == safi)
&& (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
- vpn_leak_to_vrf_update(bgp, pi);
+ leak_success = vpn_leak_to_vrf_update(bgp, pi);
}
#ifdef ENABLE_BGP_VNC
type, sub_type, NULL);
}
#endif
-
+ if ((safi == SAFI_MPLS_VPN) &&
+ !CHECK_FLAG(bgp->af_flags[afi][safi],
+ BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL) &&
+ !leak_success) {
+ bgp_unlink_nexthop(pi);
+ bgp_path_info_delete(dest, pi);
+ }
return 0;
} // End of implicit withdraw
}
if ((SAFI_MPLS_VPN == safi)
&& (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
-
- vpn_leak_to_vrf_update(bgp, new);
+ leak_success = vpn_leak_to_vrf_update(bgp, new);
}
#ifdef ENABLE_BGP_VNC
if (SAFI_MPLS_VPN == safi) {
sub_type, NULL);
}
#endif
+ if ((safi == SAFI_MPLS_VPN) &&
+ !CHECK_FLAG(bgp->af_flags[afi][safi],
+ BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL) &&
+ !leak_success) {
+ bgp_unlink_nexthop(new);
+ bgp_path_info_delete(dest, new);
+ }
return 0;
if (!paf->t_announce_route)
return;
- thread_cancel(&paf->t_announce_route);
+ THREAD_OFF(paf->t_announce_route);
}
/*
list_delete(&ntable->soft_reconfig_peers);
bgp_soft_reconfig_table_flag(ntable, false);
- BGP_TIMER_OFF(ntable->soft_reconfig_thread);
+ THREAD_OFF(ntable->soft_reconfig_thread);
}
}
attr.med = bgp_static->igpmetric;
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
+ if (afi == AFI_IP)
+ attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
+
if (bgp_static->atomic)
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
attr.nexthop = nexthop->ipv4;
+ attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
switch (p->family) {
case AF_INET:
attr.nexthop.s_addr = INADDR_ANY;
+ attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
break;
case AF_INET6:
memset(&attr.mp_nexthop_global, 0,
json_nexthop_global = json_object_new_object();
json_object_string_addf(json_nexthop_global, "ip",
- "%pI4", &attr->nexthop);
+ "%pI4",
+ &attr->mp_nexthop_global_in);
if (path->peer->hostname)
json_object_string_add(json_nexthop_global,
"used");
} else {
if (nexthop_hostname)
- len = vty_out(vty, "%pI4(%s)%s", &attr->nexthop,
+ len = vty_out(vty, "%pI4(%s)%s",
+ &attr->mp_nexthop_global_in,
nexthop_hostname, vrf_id_str);
else
- len = vty_out(vty, "%pI4%s", &attr->nexthop,
+ len = vty_out(vty, "%pI4%s",
+ &attr->mp_nexthop_global_in,
vrf_id_str);
len = wide ? (41 - len) : (16 - len);
vty_out(vty, "%*s", len, " ");
}
}
- } else if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) {
+ } else if (p->family == AF_INET && !BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr)) {
if (json_paths) {
json_nexthop_global = json_object_new_object();
}
/* IPv6 Next Hop */
- else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr)) {
+ else if (p->family == AF_INET6 || BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr)) {
if (json_paths) {
json_nexthop_global = json_object_new_object();
json_object_string_addf(json_nexthop_global, "ip",
/* Print attribute */
if (attr) {
if (use_json) {
- if (p->family == AF_INET
- && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
- || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
+ if (p->family == AF_INET &&
+ (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP ||
+ !BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr))) {
if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
json_object_string_addf(
json_net, "nextHop", "%pI4",
json_object_string_addf(
json_net, "nextHop", "%pI4",
&attr->nexthop);
- } else if (p->family == AF_INET6
- || BGP_ATTR_NEXTHOP_AFI_IP6(attr)) {
+ } else if (p->family == AF_INET6 ||
+ BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr)) {
json_object_string_addf(
json_net, "nextHopGlobal", "%pI6",
&attr->mp_nexthop_global);
- } else if (p->family == AF_EVPN
- && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) {
+ } else if (p->family == AF_EVPN &&
+ !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) {
json_object_string_addf(
json_net, "nextHop", "%pI4",
&attr->mp_nexthop_global_in);
json_object_string_add(json_net, "bgpOriginCode",
bgp_origin_str[attr->origin]);
} else {
- if (p->family == AF_INET
- && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
- || safi == SAFI_EVPN
- || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
+ if (p->family == AF_INET &&
+ (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP ||
+ safi == SAFI_EVPN ||
+ !BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr))) {
if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
|| safi == SAFI_EVPN)
vty_out(vty, "%-16pI4",
vty_out(vty, "%-41pI4", &attr->nexthop);
else
vty_out(vty, "%-16pI4", &attr->nexthop);
- } else if (p->family == AF_INET6
- || BGP_ATTR_NEXTHOP_AFI_IP6(attr)) {
+ } else if (p->family == AF_INET6 ||
+ BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr)) {
char buf[BUFSIZ];
len = vty_out(
/* Print attribute */
attr = path->attr;
- if (((p->family == AF_INET)
- && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)))
- || (safi == SAFI_EVPN && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))
- || (!BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
+ if (((p->family == AF_INET) &&
+ ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP))) ||
+ (safi == SAFI_EVPN && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) ||
+ (!BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr))) {
if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
|| safi == SAFI_EVPN) {
if (json)
else
vty_out(vty, "%-16pI4", &attr->nexthop);
}
- } else if (((p->family == AF_INET6)
- && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)))
- || (safi == SAFI_EVPN && BGP_ATTR_NEXTHOP_AFI_IP6(attr))
- || (BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
+ } else if (((p->family == AF_INET6) &&
+ ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP))) ||
+ (safi == SAFI_EVPN && BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr)) ||
+ (BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr))) {
char buf_a[512];
if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) {
/* Display the nexthop */
const struct prefix *bn_p = bgp_dest_get_prefix(bn);
- if ((bn_p->family == AF_INET || bn_p->family == AF_ETHERNET
- || bn_p->family == AF_EVPN)
- && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN
- || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
+ if ((bn_p->family == AF_INET || bn_p->family == AF_ETHERNET ||
+ bn_p->family == AF_EVPN) &&
+ (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN ||
+ !BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr))) {
if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
|| safi == SAFI_EVPN) {
if (json_paths) {
/* This path was originated locally */
if (path->peer == bgp->peer_self) {
- if (safi == SAFI_EVPN
- || (bn_p->family == AF_INET
- && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
+ if (safi == SAFI_EVPN || (bn_p->family == AF_INET &&
+ !BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr))) {
if (json_paths)
json_object_string_add(json_peer, "peerId",
"0.0.0.0");
!= PREFIX_PERMIT)
continue;
}
+ if (type == bgp_show_type_access_list) {
+ struct access_list *alist = output_arg;
+
+ if (access_list_apply(alist, dest_p) !=
+ FILTER_PERMIT)
+ continue;
+ }
if (type == bgp_show_type_filter_list) {
struct as_list *as_list = output_arg;
|community-list <(1-500)|COMMUNITY_LIST_NAME> [exact-match]\
|filter-list AS_PATH_FILTER_NAME\
|prefix-list WORD\
+ |access-list ACCESSLIST_NAME\
|route-map RMAP_NAME\
|rpki <invalid|valid|notfound>\
|version (1-4294967295)\
"Regular expression access list name\n"
"Display routes conforming to the prefix-list\n"
"Prefix-list name\n"
+ "Display routes conforming to the access-list\n"
+ "Access-list name\n"
"Display routes matching the route-map\n"
"A route-map to match on\n"
"RPKI route types\n"
list = community_list_lookup(bgp_clist, clist_number_or_name, 0,
COMMUNITY_LIST_MASTER);
if (list == NULL) {
- vty_out(vty,
- "%% %s is not a valid community-list name\n",
+ vty_out(vty, "%% %s community-list not found\n",
clist_number_or_name);
return CMD_WARNING;
}
as_list = as_list_lookup(filter);
if (as_list == NULL) {
- vty_out(vty,
- "%% %s is not a valid AS-path access-list name\n",
+ vty_out(vty, "%% %s AS-path access-list not found\n",
filter);
return CMD_WARNING;
}
plist = prefix_list_lookup(afi, prefix_list_str);
if (plist == NULL) {
- vty_out(vty, "%% %s is not a valid prefix-list name\n",
+ vty_out(vty, "%% %s prefix-list not found\n",
prefix_list_str);
return CMD_WARNING;
}
output_arg = plist;
}
+ if (argv_find(argv, argc, "access-list", &idx)) {
+ const char *access_list_str = argv[++idx]->arg;
+ struct access_list *alist;
+
+ alist = access_list_lookup(afi, access_list_str);
+ if (!alist) {
+ vty_out(vty, "%% %s access-list not found\n",
+ access_list_str);
+ return CMD_WARNING;
+ }
+
+ sh_type = bgp_show_type_access_list;
+ output_arg = alist;
+ }
+
if (argv_find(argv, argc, "route-map", &idx)) {
const char *rmap_str = argv[++idx]->arg;
struct route_map *rmap;
rmap = route_map_lookup_by_name(rmap_str);
if (!rmap) {
- vty_out(vty, "%% %s is not a valid route-map name\n",
- rmap_str);
+ vty_out(vty, "%% %s route-map not found\n", rmap_str);
return CMD_WARNING;
}
IP_STR
BGP_STR
BGP_INSTANCE_HELP_STR
- "Address Family\n"
- "Address Family\n"
- "Address Family modifier\n"
+ BGP_AF_STR
+ BGP_AF_STR
+ BGP_AF_MODIFIER_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
SHOW_STR
BGP_STR
BGP_AFI_HELP_STR
- "Address Family modifier\n"
+ BGP_AF_MODIFIER_STR
"Display information for a route distinguisher\n"
"Route Distinguisher\n"
"All Route Distinguishers\n"
bgp_show_type_normal,
bgp_show_type_regexp,
bgp_show_type_prefix_list,
+ bgp_show_type_access_list,
bgp_show_type_filter_list,
bgp_show_type_route_map,
bgp_show_type_neighbor,
? 0 \
: ((nhlen) < IPV6_MAX_BYTELEN ? AFI_IP : AFI_IP6))
+#define BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr) \
+ ((attr)->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL || \
+ (attr)->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL || \
+ (attr)->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL || \
+ (attr)->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL)
+
#define BGP_ATTR_NEXTHOP_AFI_IP6(attr) \
- (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) \
- && ((attr)->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL \
- || (attr)->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL \
- || (attr)->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL \
- || (attr)->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL))
+ (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) && \
+ BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr))
+
#define BGP_PATH_COUNTABLE(BI) \
(!CHECK_FLAG((BI)->flags, BGP_PATH_HISTORY) \
&& !CHECK_FLAG((BI)->flags, BGP_PATH_REMOVED))
struct bgp_table *table, struct prefix_rd *prd,
enum bgp_show_type type, void *output_arg,
bool use_json);
-extern int bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi);
+extern void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi);
extern bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
uint8_t type, uint8_t stype,
struct attr *attr, struct bgp_dest *dest);
* network statements, etc looking to see if they use this route-map.
*/
static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
- int route_update)
+ bool route_update)
{
int i;
bool matched;
struct bgp *bgp;
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
- bgp_route_map_process_update(bgp, rmap_name, 1);
+ bgp_route_map_process_update(bgp, rmap_name, true);
#ifdef ENABLE_BGP_VNC
vnc_routemap_update(bgp, __func__);
/* Signal the groups that a route-map update event has
* started */
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
- update_group_policy_update(bgp,
- BGP_POLICY_ROUTE_MAP,
- rmap_name, 1, 1);
+ update_group_policy_update(bgp, BGP_POLICY_ROUTE_MAP,
+ rmap_name, true, 1);
} else {
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
- bgp_route_map_process_update(bgp, rmap_name, 0);
+ bgp_route_map_process_update(bgp, rmap_name, false);
#ifdef ENABLE_BGP_VNC
vnc_routemap_update(bgp, __func__);
#endif
bgp_adv_fifo_init(&subgrp->sync->withdraw);
bgp_adv_fifo_init(&subgrp->sync->withdraw_low);
subgrp->hash =
- hash_create(baa_hash_key, baa_hash_cmp, "BGP SubGroup Hash");
+ hash_create(bgp_advertise_attr_hash_key,
+ bgp_advertise_attr_hash_cmp, "BGP SubGroup Hash");
/* We use a larger buffer for subgrp->work in the event that:
* - We RX a BGP_UPDATE where the attributes alone are just
static void sync_delete(struct update_subgroup *subgrp)
{
XFREE(MTYPE_BGP_SYNCHRONISE, subgrp->sync);
- if (subgrp->hash)
+ if (subgrp->hash) {
+ hash_clean(subgrp->hash,
+ (void (*)(void *))bgp_advertise_attr_free);
hash_free(subgrp->hash);
+ }
subgrp->hash = NULL;
if (subgrp->work)
stream_free(subgrp->work);
MTYPE_BGP_FILTER_NAME, CONDITION_MAP_NAME(srcfilter));
CONDITION_MAP(dstfilter) = CONDITION_MAP(srcfilter);
}
+
+ dstfilter->advmap.update_type = srcfilter->advmap.update_type;
}
/**
strlen(filter->advmap.aname), SEED1),
key);
+ if (filter->advmap.update_type)
+ key = jhash_1word(filter->advmap.update_type, key);
+
if (peer->default_rmap[afi][safi].name)
key = jhash_1word(
jhash(peer->default_rmap[afi][safi].name,
if (bgp_debug_neighbor_events(peer)) {
zlog_debug(
- "%pBP Update Group Hash: sort: %d UpdGrpFlags: %" PRIu64
- " UpdGrpAFFlags: %u",
+ "%pBP Update Group Hash: sort: %d UpdGrpFlags: %ju UpdGrpAFFlags: %u",
peer, peer->sort,
- (uint64_t)(peer->flags & PEER_UPDGRP_FLAGS),
+ (intmax_t)(peer->flags & PEER_UPDGRP_FLAGS),
flags & PEER_UPDGRP_AF_FLAGS);
zlog_debug(
"%pBP Update Group Hash: addpath: %u UpdGrpCapFlag: %u UpdGrpCapAFFlag: %u route_adv: %u change local as: %u",
peer->shared_network &&
peer_afi_active_nego(peer, AFI_IP6));
zlog_debug(
- "%pBP Update Group Hash: Lonesoul: %" PRIu64
- " ORF prefix: %u ORF old: %u max prefix out: %u",
- peer,
- (uint64_t)CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL),
+ "%pBP Update Group Hash: Lonesoul: %d ORF prefix: %u ORF old: %u max prefix out: %u",
+ peer, !!CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL),
CHECK_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ORF_PREFIX_SM_RCV),
CHECK_FLAG(peer->af_cap[afi][safi],
&& strcmp(fl1->advmap.aname, fl2->advmap.aname)))
return false;
+ if (fl1->advmap.update_type != fl2->advmap.update_type)
+ return false;
+
if ((pe1->default_rmap[afi][safi].name
&& !pe2->default_rmap[afi][safi].name)
|| (!pe1->default_rmap[afi][safi].name
"u%" PRIu64 ":s%" PRIu64" announcing default upon default routemap %s change",
updgrp->id, subgrp->id,
ctx->policy_name);
- subgroup_default_originate(subgrp, 0);
+ if (route_map_lookup_by_name(ctx->policy_name)) {
+ /*
+ * When there is change in routemap, this flow
+ * is triggered. the routemap is still present
+ * in lib, hence its a update flow. The flag
+ * needs to be unset.
+ */
+ UNSET_FLAG(subgrp->sflags,
+ SUBGRP_STATUS_DEFAULT_ORIGINATE);
+ subgroup_default_originate(subgrp, 0);
+ } else {
+ /*
+ * This is a explicit withdraw, since the
+ * routemap is not present in routemap lib. need
+ * to pass 1 for withdraw arg.
+ */
+ subgroup_default_originate(subgrp, 1);
+ }
}
update_subgroup_set_needs_refresh(subgrp, 0);
}
* update groups.
*/
void update_group_policy_update(struct bgp *bgp, enum bgp_policy_type ptype,
- const char *pname, int route_update,
+ const char *pname, bool route_update,
int start_event)
{
struct updwalk_context ctx;
safi = SUBGRP_SAFI(subgrp);
if (peer->default_rmap[afi][safi].name) {
+ /*
+ * When there is change in routemap this flow will
+ * be triggered. We need to unset the Flag to ensure
+ * the update flow gets triggered.
+ */
+ UNSET_FLAG(subgrp->sflags,
+ SUBGRP_STATUS_DEFAULT_ORIGINATE);
subgroup_default_originate(subgrp, 0);
}
}
bgp = THREAD_ARG(thread);
update_group_walk(bgp, update_group_default_originate_route_map_walkcb,
reason);
- thread_cancel(&bgp->t_rmap_def_originate_eval);
+ THREAD_OFF(bgp->t_rmap_def_originate_eval);
bgp_unlock(bgp);
}
#define SUBGRP_STATUS_DEFAULT_ORIGINATE (1 << 0)
#define SUBGRP_STATUS_FORCE_UPDATES (1 << 1)
#define SUBGRP_STATUS_TABLE_REPARSING (1 << 2)
+/*
+ * This flag has been added to ensure that the SNT counters
+ * gets incremented and decremented only during the creation
+ * and deletion workflows of default originate,
+ * not during the update workflow.
+ */
+#define SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED (1 << 3)
uint16_t flags;
#define SUBGRP_FLAG_NEEDS_REFRESH (1 << 0)
enum bgp_policy_type policy_type;
const char *policy_name;
int policy_event_start_flag;
- int policy_route_update;
+ bool policy_route_update;
updgrp_walkcb cb;
void *context;
uint8_t flags;
int force);
extern void update_group_policy_update(struct bgp *bgp,
enum bgp_policy_type ptype,
- const char *pname, int route_update,
+ const char *pname, bool route_update,
int start_event);
extern void update_group_af_walk(struct bgp *bgp, afi_t afi, safi_t safi,
updgrp_walkcb cb, void *ctx);
/* Look through all of the paths we have advertised for this rn and send
* a withdraw for the ones that are no longer present */
RB_FOREACH_SAFE (adj, bgp_adj_out_rb, &ctx->dest->adj_out, adj_next) {
+ if (adj->subgroup != subgrp)
+ continue;
- if (adj->subgroup == subgrp) {
- for (pi = bgp_dest_get_bgp_path_info(ctx->dest); pi;
- pi = pi->next) {
- id = bgp_addpath_id_for_peer(peer, afi, safi,
- &pi->tx_addpath);
+ for (pi = bgp_dest_get_bgp_path_info(ctx->dest); pi;
+ pi = pi->next) {
+ id = bgp_addpath_id_for_peer(peer, afi, safi,
+ &pi->tx_addpath);
- if (id == adj->addpath_tx_id) {
- break;
- }
+ if (id == adj->addpath_tx_id) {
+ break;
}
+ }
- if (!pi) {
- subgroup_process_announce_selected(
- subgrp, NULL, ctx->dest,
- adj->addpath_tx_id);
- }
+ if (!pi) {
+ subgroup_process_announce_selected(
+ subgrp, NULL, ctx->dest, adj->addpath_tx_id);
}
}
}
* coalesce timer fires.
*/
if (!subgrp->t_coalesce) {
+
/* An update-group that uses addpath */
if (addpath_capable) {
subgrp_withdraw_stale_addpath(ctx, subgrp);
peer, afi, safi,
&ctx->pi->tx_addpath));
}
-
/* An update-group that does not use addpath */
else {
if (ctx->pi) {
for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
const struct prefix *dest_p = bgp_dest_get_prefix(dest);
- RB_FOREACH (adj, bgp_adj_out_rb, &dest->adj_out)
- if (adj->subgroup == subgrp) {
- if (header1) {
- vty_out(vty,
- "BGP table version is %" PRIu64
- ", local router ID is %pI4\n",
- table->version,
- &bgp->router_id);
- vty_out(vty, BGP_SHOW_SCODE_HEADER);
- vty_out(vty, BGP_SHOW_OCODE_HEADER);
- header1 = 0;
- }
- if (header2) {
- vty_out(vty, BGP_SHOW_HEADER);
- header2 = 0;
- }
- if ((flags & UPDWALK_FLAGS_ADVQUEUE) && adj->adv
- && adj->adv->baa) {
- route_vty_out_tmp(vty, dest, dest_p,
- adj->adv->baa->attr,
- SUBGRP_SAFI(subgrp),
- 0, NULL, false);
- output_count++;
- }
- if ((flags & UPDWALK_FLAGS_ADVERTISED)
- && adj->attr) {
- route_vty_out_tmp(vty, dest, dest_p,
- adj->attr,
- SUBGRP_SAFI(subgrp),
- 0, NULL, false);
- output_count++;
- }
+ RB_FOREACH (adj, bgp_adj_out_rb, &dest->adj_out) {
+ if (adj->subgroup != subgrp)
+ continue;
+
+ if (header1) {
+ vty_out(vty,
+ "BGP table version is %" PRIu64
+ ", local router ID is %pI4\n",
+ table->version, &bgp->router_id);
+ vty_out(vty, BGP_SHOW_SCODE_HEADER);
+ vty_out(vty, BGP_SHOW_OCODE_HEADER);
+ header1 = 0;
+ }
+ if (header2) {
+ vty_out(vty, BGP_SHOW_HEADER);
+ header2 = 0;
+ }
+ if ((flags & UPDWALK_FLAGS_ADVQUEUE) && adj->adv &&
+ adj->adv->baa) {
+ route_vty_out_tmp(
+ vty, dest, dest_p, adj->adv->baa->attr,
+ SUBGRP_SAFI(subgrp), 0, NULL, false);
+ output_count++;
+ }
+ if ((flags & UPDWALK_FLAGS_ADVERTISED) && adj->attr) {
+ route_vty_out_tmp(vty, dest, dest_p, adj->attr,
+ SUBGRP_SAFI(subgrp), 0, NULL,
+ false);
+ output_count++;
}
+ }
}
if (output_count != 0)
vty_out(vty, "\nTotal number of prefixes %ld\n", output_count);
SUBGRP_FOREACH_PEER (subgrp, paf) {
peer = PAF_PEER(paf);
- BGP_TIMER_OFF(peer->t_routeadv);
+ THREAD_OFF(peer->t_routeadv);
BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0);
}
}
next = baa->adv;
/* Unintern BGP advertise attribute. */
- bgp_advertise_unintern(subgrp->hash, baa);
+ bgp_advertise_attr_unintern(subgrp->hash, baa);
} else
fhead = &subgrp->sync->withdraw;
/* bgp_path_info adj_out reference */
adv->pathi = bgp_path_info_lock(path);
- adv->baa = bgp_advertise_intern(subgrp->hash, attr);
+ adv->baa = bgp_advertise_attr_intern(subgrp->hash, attr);
adv->adj = adj;
adj->attr_hash = attr_hash;
/* Check if the route can be advertised */
advertise = bgp_check_advertise(bgp, dest);
- for (ri = bgp_dest_get_bgp_path_info(dest); ri; ri = ri->next)
-
- if (bgp_check_selected(ri, peer, addpath_capable, afi,
- safi)) {
- if (subgroup_announce_check(dest, ri, subgrp,
- dest_p, &attr,
- NULL)) {
- /* Check if route can be advertised */
- if (advertise) {
- if (!bgp_check_withdrawal(bgp,
- dest))
- bgp_adj_out_set_subgroup(
- dest, subgrp,
- &attr, ri);
- else
- bgp_adj_out_unset_subgroup(
- dest, subgrp, 1,
- bgp_addpath_id_for_peer(
- peer,
- afi,
- safi,
- &ri->tx_addpath));
- }
- } else {
- /* If default originate is enabled for
- * the peer, do not send explicit
- * withdraw. This will prevent deletion
- * of default route advertised through
- * default originate
- */
- if (CHECK_FLAG(
- peer->af_flags[afi][safi],
- PEER_FLAG_DEFAULT_ORIGINATE)
- && is_default_prefix(bgp_dest_get_prefix(dest)))
- break;
-
- bgp_adj_out_unset_subgroup(
- dest, subgrp, 1,
- bgp_addpath_id_for_peer(
- peer, afi, safi,
- &ri->tx_addpath));
+ for (ri = bgp_dest_get_bgp_path_info(dest); ri; ri = ri->next) {
+
+ if (!bgp_check_selected(ri, peer, addpath_capable, afi,
+ safi))
+ continue;
+
+ if (subgroup_announce_check(dest, ri, subgrp, dest_p,
+ &attr, NULL)) {
+ /* Check if route can be advertised */
+ if (advertise) {
+ if (!bgp_check_withdrawal(bgp, dest))
+ bgp_adj_out_set_subgroup(
+ dest, subgrp, &attr,
+ ri);
+ else
+ bgp_adj_out_unset_subgroup(
+ dest, subgrp, 1,
+ bgp_addpath_id_for_peer(
+ peer, afi, safi,
+ &ri->tx_addpath));
}
+ } else {
+ /* If default originate is enabled for
+ * the peer, do not send explicit
+ * withdraw. This will prevent deletion
+ * of default route advertised through
+ * default originate
+ */
+ if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_DEFAULT_ORIGINATE) &&
+ is_default_prefix(
+ bgp_dest_get_prefix(dest)))
+ break;
+
+ bgp_adj_out_unset_subgroup(
+ dest, subgrp, 1,
+ bgp_addpath_id_for_peer(
+ peer, afi, safi,
+ &ri->tx_addpath));
}
+ }
}
UNSET_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING);
struct peer *peer;
struct bgp_adj_out *adj;
route_map_result_t ret = RMAP_DENYMATCH;
+ route_map_result_t new_ret = RMAP_DENYMATCH;
afi_t afi;
safi_t safi;
+ int pref = 65536;
+ int new_pref = 0;
if (!subgrp)
return;
tmp_pi.attr = &tmp_attr;
- ret = route_map_apply_ext(
+ new_ret = route_map_apply_ext(
peer->default_rmap[afi][safi].map,
- bgp_dest_get_prefix(dest), pi, &tmp_pi);
-
- if (ret == RMAP_DENYMATCH) {
- bgp_attr_flush(&tmp_attr);
- continue;
- } else {
- new_attr = bgp_attr_intern(&tmp_attr);
-
+ bgp_dest_get_prefix(dest), pi, &tmp_pi,
+ &new_pref);
+
+ if (new_ret == RMAP_PERMITMATCH) {
+ if (new_pref < pref) {
+ pref = new_pref;
+ bgp_attr_flush(new_attr);
+ new_attr = bgp_attr_intern(
+ tmp_pi.attr);
+ bgp_attr_flush(tmp_pi.attr);
+ }
subgroup_announce_reset_nhop(
(peer_cap_enhe(peer, afi, safi)
? AF_INET6
: AF_INET),
new_attr);
-
- break;
- }
- }
- if (ret == RMAP_PERMITMATCH) {
- bgp_dest_unlock_node(dest);
- break;
+ ret = new_ret;
+ } else
+ bgp_attr_flush(&tmp_attr);
}
}
bgp->peer_self->rmap_type = 0;
- if (ret == RMAP_DENYMATCH)
+ if (ret == RMAP_DENYMATCH) {
+ /*
+ * If its a implicit withdraw due to routemap
+ * deny operation need to set the flag back.
+ * This is a convertion of update flow to
+ * withdraw flow.
+ */
+ if (!withdraw &&
+ (!CHECK_FLAG(subgrp->sflags,
+ SUBGRP_STATUS_DEFAULT_ORIGINATE)))
+ SET_FLAG(subgrp->sflags,
+ SUBGRP_STATUS_DEFAULT_ORIGINATE);
withdraw = 1;
+ }
}
/* Check if the default route is in local BGP RIB which is
(void)bpacket_queue_add(SUBGRP_PKTQ(subgrp), s, &vecarr);
subgroup_trigger_write(subgrp);
- subgrp->scount++;
+
+ if (!CHECK_FLAG(subgrp->sflags,
+ SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED)) {
+ subgrp->scount++;
+ SET_FLAG(subgrp->sflags, SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED);
+ }
}
void subgroup_default_withdraw_packet(struct update_subgroup *subgrp)
(void)bpacket_queue_add(SUBGRP_PKTQ(subgrp), s, NULL);
subgroup_trigger_write(subgrp);
- subgrp->scount--;
+
+ if (CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED)) {
+ subgrp->scount--;
+ UNSET_FLAG(subgrp->sflags,
+ SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED);
+ }
}
static void
{
switch (error) {
case BGP_ERR_AF_UNCONFIGURED:
- vty_out(vty,
- "%% BGP: Enable %s address family for the neighbor %s\n",
- get_afi_safi_str(afi, safi, false), peer->host);
+ if (vty)
+ vty_out(vty,
+ "%% BGP: Enable %s address family for the neighbor %s\n",
+ get_afi_safi_str(afi, safi, false), peer->host);
+ else
+ zlog_warn(
+ "%% BGP: Enable %s address family for the neighbor %s",
+ get_afi_safi_str(afi, safi, false), peer->host);
break;
case BGP_ERR_SOFT_RECONFIG_UNCONFIGURED:
- vty_out(vty,
- "%% BGP: Inbound soft reconfig for %s not possible as it\n has neither refresh capability, nor inbound soft reconfig\n",
- peer->host);
+ if (vty)
+ vty_out(vty,
+ "%% BGP: Inbound soft reconfig for %s not possible as it\n has neither refresh capability, nor inbound soft reconfig\n",
+ peer->host);
+ else
+ zlog_warn(
+ "%% BGP: Inbound soft reconfig for %s not possible as it has neither refresh capability, nor inbound soft reconfig",
+ peer->host);
break;
default:
break;
}
+void bgp_clear_soft_in(struct bgp *bgp, afi_t afi, safi_t safi)
+{
+ bgp_clear(NULL, bgp, afi, safi, clear_all, BGP_CLEAR_SOFT_IN, NULL);
+}
+
#ifndef VTYSH_EXTRACT_PL
#include "bgpd/bgp_vty_clippy.c"
#endif
/* Cancel max-med onstartup if its on */
if (bgp->t_maxmed_onstartup) {
- thread_cancel(&bgp->t_maxmed_onstartup);
+ THREAD_OFF(bgp->t_maxmed_onstartup);
bgp->maxmed_onstartup_over = 1;
}
afi_t afi = bgp_vty_afi_from_str(afi_str);
safi_t safi;
+ /*
+ * Impossible situation but making coverity happy
+ */
+ assert(afi != AFI_MAX);
+
if (strmatch(safi_str, "labeled"))
safi = bgp_vty_safi_from_str("labeled-unicast");
else
safi = bgp_vty_safi_from_str(safi_str);
+ assert(safi != SAFI_MAX);
if (no)
bgp->default_af[afi][safi] = false;
else {
return peer_remote_as_vty(vty, argv[idx_peer]->arg,
argv[idx_remote_as]->arg);
}
+
+DEFPY (bgp_allow_martian,
+ bgp_allow_martian_cmd,
+ "[no]$no bgp allow-martian-nexthop",
+ NO_STR
+ BGP_STR
+ "Allow Martian nexthops to be received in the NLRI from a peer\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (no)
+ bgp->allow_martian = false;
+ else
+ bgp->allow_martian = true;
+
+ return CMD_SUCCESS;
+}
+
/* Enable fast convergence of bgp sessions. If this is enabled, bgp
* sessions do not wait for hold timer expiry to bring down the sessions
* when nexthop becomes unreachable
{
struct peer *peer;
- peer = peer_lookup_vty(vty, ip_str);
+ peer = peer_and_group_lookup_vty(vty, ip_str);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
uint8_t role = get_role_by_name(role_str);
{
struct peer *peer;
- peer = peer_lookup_vty(vty, ip_str);
+ peer = peer_and_group_lookup_vty(vty, ip_str);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
return bgp_vty_return(vty, peer_role_unset(peer));
uint16_t port;
struct servent *sp;
- peer = peer_lookup_vty(vty, ip_str);
+ peer = peer_and_group_lookup_vty(vty, ip_str);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
/* Set specified peer's BGP port. */
DEFUN (neighbor_port,
neighbor_port_cmd,
- "neighbor <A.B.C.D|X:X::X:X> port (0-65535)",
+ "neighbor <A.B.C.D|X:X::X:X|WORD> port (0-65535)",
NEIGHBOR_STR
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR2
"Neighbor's BGP port\n"
"TCP port number\n")
{
DEFUN (no_neighbor_port,
no_neighbor_port_cmd,
- "no neighbor <A.B.C.D|X:X::X:X> port [(0-65535)]",
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> port [(0-65535)]",
NO_STR
NEIGHBOR_STR
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR2
"Neighbor's BGP port\n"
"TCP port number\n")
{
* fired.
*/
if (!rmap_delay_timer && bm->t_rmap_update) {
- BGP_TIMER_OFF(bm->t_rmap_update);
+ THREAD_OFF(bm->t_rmap_update);
thread_execute(bm->master, bgp_route_map_update_timer,
NULL, 0);
}
address_family_ipv4_safi_cmd,
"address-family ipv4 [<unicast|multicast|vpn|labeled-unicast|flowspec>]",
"Enter Address Family command mode\n"
- "Address Family\n"
+ BGP_AF_STR
BGP_SAFI_WITH_LABEL_HELP_STR)
{
address_family_ipv6_safi_cmd,
"address-family ipv6 [<unicast|multicast|vpn|labeled-unicast|flowspec>]",
"Enter Address Family command mode\n"
- "Address Family\n"
+ BGP_AF_STR
BGP_SAFI_WITH_LABEL_HELP_STR)
{
if (argc == 3) {
address_family_vpnv4_cmd,
"address-family vpnv4 [unicast]",
"Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family modifier\n")
+ BGP_AF_STR
+ BGP_AF_MODIFIER_STR)
{
vty->node = BGP_VPNV4_NODE;
return CMD_SUCCESS;
address_family_vpnv6_cmd,
"address-family vpnv6 [unicast]",
"Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family modifier\n")
+ BGP_AF_STR
+ BGP_AF_MODIFIER_STR)
{
vty->node = BGP_VPNV6_NODE;
return CMD_SUCCESS;
address_family_evpn_cmd,
"address-family l2vpn evpn",
"Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family modifier\n")
+ BGP_AF_STR
+ BGP_AF_MODIFIER_STR)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
vty->node = BGP_EVPN_NODE;
BGP_STR
BGP_INSTANCE_HELP_STR
BGP_AFI_HELP_STR
- "Address Family\n"
+ BGP_AF_STR
BGP_SAFI_WITH_LABEL_HELP_STR
- "Address Family modifier\n"
+ BGP_AF_MODIFIER_STR
"Clear all peers\n"
"BGP IPv4 neighbor to clear\n"
"BGP IPv6 neighbor to clear\n"
CLEAR_STR
IP_STR
BGP_STR
- "Address Family\n"
+ BGP_AF_STR
BGP_SAFI_HELP_STR
"Clear bestpath and re-advertise\n"
"IPv6 prefix\n")
IP_STR
BGP_STR
BGP_INSTANCE_HELP_STR
- "Address Family\n"
+ BGP_AF_STR
BGP_SAFI_HELP_STR
"Clear bestpath and re-advertise\n"
"IPv6 prefix\n")
count, mtype_memstr(memstrbuf, sizeof(memstrbuf),
count * sizeof(struct community)));
if ((count = mtype_stats_alloc(MTYPE_ECOMMUNITY)))
- vty_out(vty, "%ld BGP community entries, using %s of memory\n",
- count, mtype_memstr(memstrbuf, sizeof(memstrbuf),
- count * sizeof(struct ecommunity)));
+ vty_out(vty,
+ "%ld BGP ext-community entries, using %s of memory\n",
+ count,
+ mtype_memstr(memstrbuf, sizeof(memstrbuf),
+ count * sizeof(struct ecommunity)));
if ((count = mtype_stats_alloc(MTYPE_LCOMMUNITY)))
vty_out(vty,
"%ld BGP large-community entries, using %s of memory\n",
static char *bgp_peer_description_stripped(char *desc, uint32_t size)
{
static char stripped[BUFSIZ];
- uint32_t len = size > strlen(desc) ? strlen(desc) : size;
+ uint32_t i = 0;
+ uint32_t last_space = 0;
- strlcpy(stripped, desc, len + 1);
+ while (i < size) {
+ if (*(desc + i) == 0) {
+ stripped[i] = '\0';
+ return stripped;
+ }
+ if (i != 0 && *(desc + i) == ' ' && last_space != i - 1)
+ last_space = i;
+ stripped[i] = *(desc + i);
+ i++;
+ }
+
+ if (last_space > size)
+ stripped[size + 1] = '\0';
+ else
+ stripped[last_space] = '\0';
return stripped;
}
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);
}
filter->advmap.cname,
filter->advmap.amap ? "*" : "",
filter->advmap.aname,
- filter->advmap.update_type == ADVERTISE
+ filter->advmap.update_type ==
+ UPDATE_TYPE_ADVERTISE
? "Advertise"
: "Withdraw");
/* Configured timer values. */
json_object_int_add(json_neigh,
"bgpTimerConfiguredHoldTimeMsecs",
- p->holdtime ? p->holdtime * 1000
- : bgp->default_holdtime * 1000);
- json_object_int_add(
- json_neigh, "bgpTimerConfiguredKeepAliveIntervalMsecs",
- p->keepalive ? p->keepalive * 1000
- : bgp->default_keepalive * 1000);
+ CHECK_FLAG(p->flags, PEER_FLAG_TIMER)
+ ? p->holdtime * 1000
+ : bgp->default_holdtime * 1000);
+ json_object_int_add(json_neigh,
+ "bgpTimerConfiguredKeepAliveIntervalMsecs",
+ CHECK_FLAG(p->flags, PEER_FLAG_TIMER)
+ ? p->keepalive * 1000
+ : bgp->default_keepalive * 1000);
json_object_int_add(json_neigh, "bgpTimerHoldTimeMsecs",
p->v_holdtime * 1000);
json_object_int_add(json_neigh,
/* Configured timer values. */
vty_out(vty,
- " Hold time is %d, keepalive interval is %d seconds\n",
+ " Hold time is %d seconds, keepalive interval is %d seconds\n",
p->v_holdtime, p->v_keepalive);
- vty_out(vty, " Configured hold time is %d",
- p->holdtime ? p->holdtime : bgp->default_holdtime);
+ vty_out(vty, " Configured hold time is %d seconds",
+ CHECK_FLAG(p->flags, PEER_FLAG_TIMER)
+ ? p->holdtime
+ : bgp->default_holdtime);
vty_out(vty, ", keepalive interval is %d seconds\n",
- p->keepalive ? p->keepalive : bgp->default_keepalive);
+ CHECK_FLAG(p->flags, PEER_FLAG_TIMER)
+ ? p->keepalive
+ : bgp->default_keepalive);
if (CHECK_FLAG(p->flags, PEER_FLAG_TIMER_DELAYOPEN))
vty_out(vty,
" Configured DelayOpenTime is %d seconds\n",
IP_STR
BGP_STR
BGP_INSTANCE_HELP_STR
- "Address Family\n"
- "Address Family\n"
+ BGP_AF_STR
+ BGP_AF_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
return peer_tcp_mss_vty(vty, argv[peer_index]->arg, NULL);
}
+DEFPY(bgp_retain_route_target, bgp_retain_route_target_cmd,
+ "[no$no] bgp retain route-target all",
+ NO_STR BGP_STR
+ "Retain BGP updates\n"
+ "Retain BGP updates based on route-target values\n"
+ "Retain all BGP updates\n")
+{
+ bool check;
+ struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+
+ check = CHECK_FLAG(bgp->af_flags[bgp_node_afi(vty)][bgp_node_safi(vty)],
+ BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL);
+ if (check != !no) {
+ if (!no)
+ SET_FLAG(bgp->af_flags[bgp_node_afi(vty)]
+ [bgp_node_safi(vty)],
+ BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL);
+ else
+ UNSET_FLAG(bgp->af_flags[bgp_node_afi(vty)]
+ [bgp_node_safi(vty)],
+ BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL);
+ /* trigger a flush to re-sync with ADJ-RIB-in */
+ bgp_clear(vty, bgp, bgp_node_afi(vty), bgp_node_safi(vty),
+ clear_all, BGP_CLEAR_SOFT_IN, NULL);
+ }
+ return CMD_SUCCESS;
+}
+
static void bgp_config_write_redistribute(struct vty *vty, struct bgp *bgp,
afi_t afi, safi_t safi)
{
}
/* role */
- if (peer->local_role != ROLE_UNDEFINED) {
+ if (peergroup_flag_check(peer, PEER_FLAG_ROLE) &&
+ peer->local_role != ROLE_UNDEFINED)
vty_out(vty, " neighbor %s local-role %s%s\n", addr,
bgp_get_name_by_role(peer->local_role),
- CHECK_FLAG(peer->flags, PEER_FLAG_STRICT_MODE)
+ CHECK_FLAG(peer->flags, PEER_FLAG_ROLE_STRICT_MODE)
? " strict-mode"
: "");
- }
/* ttl-security hops */
if (peer->gtsm_hops != BGP_GTSM_HOPS_DISABLED) {
}
}
+static void bgp_vpn_config_write(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi)
+{
+ if (!CHECK_FLAG(bgp->af_flags[afi][safi],
+ BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL))
+ vty_out(vty, " no bgp retain route-target all\n");
+}
+
/* Address family based peer configuration display. */
static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
safi_t safi)
if (safi == SAFI_FLOWSPEC)
bgp_fs_config_write_pbr(vty, bgp, afi, safi);
+ if (safi == SAFI_MPLS_VPN)
+ bgp_vpn_config_write(vty, bgp, afi, safi);
+
if (safi == SAFI_UNICAST) {
bgp_vpn_policy_config_write_afi(vty, bgp, afi);
if (CHECK_FLAG(bgp->af_flags[afi][safi],
if (CHECK_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN))
vty_out(vty, " bgp shutdown\n");
+ if (bgp->allow_martian)
+ vty_out(vty, " bgp allow-martian-nexthop\n");
+
if (bgp->fast_convergence)
vty_out(vty, " bgp fast-convergence\n");
install_element(CONFIG_NODE, &bgp_set_route_map_delay_timer_cmd);
install_element(CONFIG_NODE, &no_bgp_set_route_map_delay_timer_cmd);
+ install_element(BGP_NODE, &bgp_allow_martian_cmd);
+
/* bgp fast-convergence command */
install_element(BGP_NODE, &bgp_fast_convergence_cmd);
install_element(BGP_NODE, &no_bgp_fast_convergence_cmd);
install_element(BGP_FLOWSPECV6_NODE, &exit_address_family_cmd);
install_element(BGP_EVPN_NODE, &exit_address_family_cmd);
+ /* BGP retain all route-target */
+ install_element(BGP_VPNV4_NODE, &bgp_retain_route_target_cmd);
+ install_element(BGP_VPNV6_NODE, &bgp_retain_route_target_cmd);
+
/* "clear ip bgp commands" */
install_element(ENABLE_NODE, &clear_ip_bgp_all_cmd);
#define BGP_INSTANCE_HELP_STR "BGP view\nBGP VRF\nView/VRF name\n"
#define BGP_INSTANCE_ALL_HELP_STR "BGP view\nBGP VRF\nAll Views/VRFs\n"
+#define BGP_AF_STR "Address Family\n"
+#define BGP_AF_MODIFIER_STR "Address Family modifier\n"
#define BGP_AFI_CMD_STR "<ipv4|ipv6>"
-#define BGP_AFI_HELP_STR "Address Family\nAddress Family\n"
+#define BGP_AFI_HELP_STR BGP_AF_STR BGP_AF_STR
#define BGP_SAFI_CMD_STR "<unicast|multicast|vpn>"
#define BGP_SAFI_HELP_STR \
- "Address Family modifier\n" \
- "Address Family modifier\n" \
- "Address Family modifier\n"
+ BGP_AF_MODIFIER_STR BGP_AF_MODIFIER_STR BGP_AF_MODIFIER_STR
#define BGP_AFI_SAFI_CMD_STR BGP_AFI_CMD_STR" "BGP_SAFI_CMD_STR
#define BGP_AFI_SAFI_HELP_STR BGP_AFI_HELP_STR BGP_SAFI_HELP_STR
#define BGP_SAFI_WITH_LABEL_CMD_STR "<unicast|multicast|vpn|labeled-unicast|flowspec>"
#define BGP_SAFI_WITH_LABEL_HELP_STR \
- "Address Family modifier\n" \
- "Address Family modifier\n" \
- "Address Family modifier\n" \
- "Address Family modifier\n" \
- "Address Family modifier\n"
+ BGP_AF_MODIFIER_STR BGP_AF_MODIFIER_STR BGP_AF_MODIFIER_STR \
+ BGP_AF_MODIFIER_STR BGP_AF_MODIFIER_STR
#define SHOW_GR_HEADER \
"Codes: GR - Graceful Restart," \
"endOfRibSentAfterUpdate"); \
} while (0)
+extern void bgp_clear_soft_in(struct bgp *bgp, afi_t afi, safi_t safi);
extern void bgp_vty_init(void);
extern void community_alias_vty(void);
extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
p, &path->attr->nexthop);
}
if (p->family == AF_INET6) {
- char buf[2][INET6_ADDRSTRLEN];
ifindex_t ifindex;
struct in6_addr *nexthop;
nexthop = bgp_path_info_to_ipv6_nexthop(path, &ifindex);
zlog_debug(
- "Zebra rmap deny: IPv6 route %pFX nexthop %s",
- p,
- nexthop ? inet_ntop(AF_INET6, nexthop, buf[1],
- sizeof(buf[1]))
- : inet_ntop(AF_INET,
- &path->attr->nexthop,
- buf[1], sizeof(buf[1])));
+ "Zebra rmap deny: IPv6 route %pFX nexthop %pI6",
+ p, nexthop);
}
}
return false;
nh_weight = 0;
/* Get nexthop address-family */
- if (p->family == AF_INET
- && !BGP_ATTR_NEXTHOP_AFI_IP6(mpinfo_cp->attr))
+ if (p->family == AF_INET &&
+ !BGP_ATTR_MP_NEXTHOP_LEN_IP6(mpinfo_cp->attr))
nh_family = AF_INET;
- else if (p->family == AF_INET6
- || (p->family == AF_INET
- && BGP_ATTR_NEXTHOP_AFI_IP6(mpinfo_cp->attr)))
+ else if (p->family == AF_INET6 ||
+ (p->family == AF_INET &&
+ BGP_ATTR_MP_NEXTHOP_LEN_IP6(mpinfo_cp->attr)))
nh_family = AF_INET6;
else
continue;
else
stream_putl(s, pbra->fwmark); /* fwmark */
+ stream_putl(s, 0); /* queue id */
+ stream_putw(s, 0); /* vlan_id */
+ stream_putw(s, 0); /* vlan_flags */
+ stream_putw(s, 0); /* pcp */
+
stream_putl(s, pbra->table_id);
memset(ifname, 0, sizeof(ifname));
}
/* BGP's cluster-id control. */
-int bgp_cluster_id_set(struct bgp *bgp, struct in_addr *cluster_id)
+void bgp_cluster_id_set(struct bgp *bgp, struct in_addr *cluster_id)
{
struct peer *peer;
struct listnode *node, *nnode;
if (bgp_config_check(bgp, BGP_CONFIG_CLUSTER_ID)
&& IPV4_ADDR_SAME(&bgp->cluster_id, cluster_id))
- return 0;
+ return;
IPV4_ADDR_COPY(&bgp->cluster_id, cluster_id);
bgp_config_set(bgp, BGP_CONFIG_CLUSTER_ID);
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
}
- return 0;
}
-int bgp_cluster_id_unset(struct bgp *bgp)
+void bgp_cluster_id_unset(struct bgp *bgp)
{
struct peer *peer;
struct listnode *node, *nnode;
if (!bgp_config_check(bgp, BGP_CONFIG_CLUSTER_ID))
- return 0;
+ return;
bgp->cluster_id.s_addr = 0;
bgp_config_unset(bgp, BGP_CONFIG_CLUSTER_ID);
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
}
- return 0;
}
/* time_t value that is monotonicly increasing
return;
}
-int bgp_confederation_id_unset(struct bgp *bgp)
+void bgp_confederation_id_unset(struct bgp *bgp)
{
struct peer *peer;
struct listnode *node, *nnode;
bgp_session_reset_safe(peer, &nnode);
}
}
- return 0;
}
/* Is an AS part of the confed or not? */
}
/* Add an AS to the confederation set. */
-int bgp_confederation_peers_add(struct bgp *bgp, as_t as)
+void bgp_confederation_peers_add(struct bgp *bgp, as_t as)
{
struct peer *peer;
struct listnode *node, *nnode;
if (bgp->as == as)
- return BGP_ERR_INVALID_AS;
+ return;
if (bgp_confederation_peers_check(bgp, as))
- return -1;
+ return;
bgp->confed_peers =
XREALLOC(MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
}
}
}
- return 0;
}
/* Delete an AS from the confederation set. */
-int bgp_confederation_peers_remove(struct bgp *bgp, as_t as)
+void bgp_confederation_peers_remove(struct bgp *bgp, as_t as)
{
int i;
int j;
struct listnode *node, *nnode;
if (!bgp)
- return -1;
+ return;
if (!bgp_confederation_peers_check(bgp, as))
- return -1;
+ return;
for (i = 0; i < bgp->confed_peers_cnt; i++)
if (bgp->confed_peers[i] == as)
}
}
}
-
- return 0;
}
/* Local preference configuration. */
-int bgp_default_local_preference_set(struct bgp *bgp, uint32_t local_pref)
+void bgp_default_local_preference_set(struct bgp *bgp, uint32_t local_pref)
{
if (!bgp)
- return -1;
+ return;
bgp->default_local_pref = local_pref;
-
- return 0;
}
-int bgp_default_local_preference_unset(struct bgp *bgp)
+void bgp_default_local_preference_unset(struct bgp *bgp)
{
if (!bgp)
- return -1;
+ return;
bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
-
- return 0;
}
/* Local preference configuration. */
-int bgp_default_subgroup_pkt_queue_max_set(struct bgp *bgp, uint32_t queue_size)
+void bgp_default_subgroup_pkt_queue_max_set(struct bgp *bgp,
+ uint32_t queue_size)
{
if (!bgp)
- return -1;
+ return;
bgp->default_subgroup_pkt_queue_max = queue_size;
-
- return 0;
}
-int bgp_default_subgroup_pkt_queue_max_unset(struct bgp *bgp)
+void bgp_default_subgroup_pkt_queue_max_unset(struct bgp *bgp)
{
if (!bgp)
- return -1;
+ return;
bgp->default_subgroup_pkt_queue_max =
BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX;
-
- return 0;
}
/* Listen limit configuration. */
-int bgp_listen_limit_set(struct bgp *bgp, int listen_limit)
+void bgp_listen_limit_set(struct bgp *bgp, int listen_limit)
{
if (!bgp)
- return -1;
+ return;
bgp->dynamic_neighbors_limit = listen_limit;
-
- return 0;
}
-int bgp_listen_limit_unset(struct bgp *bgp)
+void bgp_listen_limit_unset(struct bgp *bgp)
{
if (!bgp)
- return -1;
+ return;
bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT;
-
- return 0;
}
int bgp_map_afi_safi_iana2int(iana_afi_t pkt_afi, iana_safi_t pkt_safi,
/*
* Return true if we have a peer configured to use this afi/safi
*/
-int bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi)
+bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi)
{
struct listnode *node;
struct peer *peer;
continue;
if (peer->afc[afi][safi])
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/* Change peer's AS number. */
peer->nsf[afi][safi] = 0;
if (peer->t_gr_restart) {
- BGP_TIMER_OFF(peer->t_gr_restart);
+ THREAD_OFF(peer->t_gr_restart);
if (bgp_debug_neighbor_events(peer))
zlog_debug("%pBP graceful restart timer stopped", peer);
}
if (peer->t_gr_stale) {
- BGP_TIMER_OFF(peer->t_gr_stale);
+ THREAD_OFF(peer->t_gr_stale);
if (bgp_debug_neighbor_events(peer))
zlog_debug(
"%pBP graceful restart stalepath timer stopped",
}
}
+ /* role */
+ PEER_ATTR_INHERIT(peer, group, local_role);
+
/* Update GR flags for the peer. */
bgp_peer_gr_flags_update(peer);
bgp_lock(bgp);
+ bgp->allow_martian = false;
bgp_process_queue_init(bgp);
bgp->heuristic_coalesce = true;
bgp->inst_type = inst_type;
bgp->vpn_policy[afi].export_vrf = list_new();
bgp->vpn_policy[afi].export_vrf->del =
bgp_vrf_string_name_delete;
+ SET_FLAG(bgp->af_flags[afi][SAFI_MPLS_VPN],
+ BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL);
}
if (name)
bgp->name = XSTRDUP(MTYPE_BGP, name);
/* Stop timers. */
if (bgp->t_rmap_def_originate_eval) {
- BGP_TIMER_OFF(bgp->t_rmap_def_originate_eval);
+ THREAD_OFF(bgp->t_rmap_def_originate_eval);
bgp_unlock(bgp); /* TODO - This timer is started with a lock -
why? */
}
if (!gr_info)
continue;
- BGP_TIMER_OFF(gr_info->t_select_deferral);
+ THREAD_OFF(gr_info->t_select_deferral);
t = gr_info->t_route_select;
if (t) {
XFREE(MTYPE_TMP, info);
}
- BGP_TIMER_OFF(gr_info->t_route_select);
+ THREAD_OFF(gr_info->t_route_select);
}
if (BGP_DEBUG(zebra, ZEBRA)) {
/* Stop timers. */
if (bgp->t_rmap_def_originate_eval) {
- BGP_TIMER_OFF(bgp->t_rmap_def_originate_eval);
+ THREAD_OFF(bgp->t_rmap_def_originate_eval);
bgp_unlock(bgp); /* TODO - This timer is started with a lock -
why? */
}
{PEER_FLAG_UPDATE_SOURCE, 0, peer_change_none},
{PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE, 0, peer_change_none},
{PEER_FLAG_EXTENDED_OPT_PARAMS, 0, peer_change_reset},
- {PEER_FLAG_STRICT_MODE, 0, peer_change_reset},
+ {PEER_FLAG_ROLE_STRICT_MODE, 0, peer_change_reset},
+ {PEER_FLAG_ROLE, 0, peer_change_reset},
+ {PEER_FLAG_PORT, 0, peer_change_reset},
{0, 0, 0}};
static const struct peer_flag_action peer_af_flag_action_list[] = {
UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
if (peer->t_pmax_restart) {
- BGP_TIMER_OFF(peer->t_pmax_restart);
+ THREAD_OFF(peer->t_pmax_restart);
if (bgp_debug_neighbor_events(peer))
zlog_debug(
"%pBP Maximum-prefix restart timer canceled",
/* Set Open Policy Role and check its correctness */
int peer_role_set(struct peer *peer, uint8_t role, bool strict_mode)
{
- if (peer->sort != BGP_PEER_EBGP)
- return BGP_ERR_INVALID_INTERNAL_ROLE;
-
- if (peer->local_role == role) {
- if (CHECK_FLAG(peer->flags, PEER_FLAG_STRICT_MODE) &&
- !strict_mode)
- /* TODO: Is session restart needed if it was down? */
- UNSET_FLAG(peer->flags, PEER_FLAG_STRICT_MODE);
- if (!CHECK_FLAG(peer->flags, PEER_FLAG_STRICT_MODE) &&
- strict_mode) {
- SET_FLAG(peer->flags, PEER_FLAG_STRICT_MODE);
- /* Restart session to throw Role Mismatch Notification
- */
- if (peer->remote_role == ROLE_UNDEFINED)
- bgp_session_reset(peer);
+ struct peer *member;
+ struct listnode *node, *nnode;
+
+ peer_flag_set(peer, PEER_FLAG_ROLE);
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ if (peer->sort != BGP_PEER_EBGP)
+ return BGP_ERR_INVALID_INTERNAL_ROLE;
+
+ if (peer->local_role == role) {
+ if (CHECK_FLAG(peer->flags,
+ PEER_FLAG_ROLE_STRICT_MODE) &&
+ !strict_mode)
+ /* TODO: Is session restart needed if it was
+ * down?
+ */
+ UNSET_FLAG(peer->flags,
+ PEER_FLAG_ROLE_STRICT_MODE);
+ if (!CHECK_FLAG(peer->flags,
+ PEER_FLAG_ROLE_STRICT_MODE) &&
+ strict_mode) {
+ SET_FLAG(peer->flags,
+ PEER_FLAG_ROLE_STRICT_MODE);
+ /* Restart session to throw Role Mismatch
+ * Notification
+ */
+ if (peer->remote_role == ROLE_UNDEFINED)
+ bgp_session_reset(peer);
+ }
+ } else {
+ peer->local_role = role;
+ if (strict_mode)
+ SET_FLAG(peer->flags,
+ PEER_FLAG_ROLE_STRICT_MODE);
+ else
+ UNSET_FLAG(peer->flags,
+ PEER_FLAG_ROLE_STRICT_MODE);
+ bgp_session_reset(peer);
}
- } else {
- peer->local_role = role;
- if (strict_mode)
- SET_FLAG(peer->flags, PEER_FLAG_STRICT_MODE);
- else
- UNSET_FLAG(peer->flags, PEER_FLAG_STRICT_MODE);
- bgp_session_reset(peer);
+
+ return CMD_SUCCESS;
}
- return 0;
+
+ peer->local_role = role;
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ if (member->sort != BGP_PEER_EBGP)
+ return BGP_ERR_INVALID_INTERNAL_ROLE;
+
+ if (member->local_role == role) {
+ if (CHECK_FLAG(member->flags,
+ PEER_FLAG_ROLE_STRICT_MODE) &&
+ !strict_mode)
+ /* TODO: Is session restart needed if it was
+ * down?
+ */
+ UNSET_FLAG(member->flags,
+ PEER_FLAG_ROLE_STRICT_MODE);
+ if (!CHECK_FLAG(member->flags,
+ PEER_FLAG_ROLE_STRICT_MODE) &&
+ strict_mode) {
+ SET_FLAG(peer->flags,
+ PEER_FLAG_ROLE_STRICT_MODE);
+ SET_FLAG(member->flags,
+ PEER_FLAG_ROLE_STRICT_MODE);
+ /* Restart session to throw Role Mismatch
+ * Notification
+ */
+ if (member->remote_role == ROLE_UNDEFINED)
+ bgp_session_reset(member);
+ }
+ } else {
+ member->local_role = role;
+
+ if (strict_mode) {
+ SET_FLAG(peer->flags,
+ PEER_FLAG_ROLE_STRICT_MODE);
+ SET_FLAG(member->flags,
+ PEER_FLAG_ROLE_STRICT_MODE);
+ } else {
+ UNSET_FLAG(member->flags,
+ PEER_FLAG_ROLE_STRICT_MODE);
+ }
+ bgp_session_reset(member);
+ }
+ }
+
+ return CMD_SUCCESS;
}
int peer_role_unset(struct peer *peer)
{
- return peer_role_set(peer, ROLE_UNDEFINED, 0);
+ struct peer *member;
+ struct listnode *node, *nnode;
+
+ peer_flag_unset(peer, PEER_FLAG_ROLE);
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ return peer_role_set(peer, ROLE_UNDEFINED, 0);
+
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member))
+ peer_role_set(member, ROLE_UNDEFINED, 0);
+
+ return CMD_SUCCESS;
}
/* Neighbor description. */
return 0;
}
-int peer_update_source_addr_set(struct peer *peer, const union sockunion *su)
+void peer_update_source_addr_set(struct peer *peer, const union sockunion *su)
{
struct peer *member;
struct listnode *node, *nnode;
peer_flag_set(peer, PEER_FLAG_UPDATE_SOURCE);
if (peer->update_source) {
if (sockunion_cmp(peer->update_source, su) == 0)
- return 0;
+ return;
sockunion_free(peer->update_source);
}
peer->update_source = sockunion_dup(su);
bgp_peer_bfd_update_source(peer);
/* Skip peer-group mechanics for regular peers. */
- return 0;
+ return;
}
/*
if (member->bfd_config)
bgp_peer_bfd_update_source(member);
}
-
- return 0;
}
-int peer_update_source_unset(struct peer *peer)
+void peer_update_source_unset(struct peer *peer)
{
struct peer *member;
struct listnode *node, *nnode;
if (!CHECK_FLAG(peer->flags, PEER_FLAG_UPDATE_SOURCE))
- return 0;
+ return;
/* Inherit configuration from peer-group if peer is member. */
if (peer_group_active(peer)) {
bgp_peer_bfd_update_source(peer);
/* Skip peer-group mechanics for regular peers. */
- return 0;
+ return;
}
/*
if (member->bfd_config)
bgp_peer_bfd_update_source(member);
}
-
- return 0;
}
int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
{
struct peer *member;
struct listnode *node, *nnode;
+ struct update_subgroup *subgrp;
/* Set flag and configuration on peer. */
peer_af_flag_set(peer, afi, safi, PEER_FLAG_DEFAULT_ORIGINATE);
+
+ subgrp = peer_subgroup(peer, afi, safi);
+
if (rmap) {
if (!peer->default_rmap[afi][safi].name
|| strcmp(rmap, peer->default_rmap[afi][safi].name) != 0) {
XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].name);
+ /*
+ * When there is a change in route-map policy,
+ * this flow gets triggered. Since, the default
+ * route is already originated, the flag is set.
+ * The flag should be unset here,
+ * to trigger the flow of sending update message.
+ */
+ if (subgrp)
+ UNSET_FLAG(subgrp->sflags,
+ SUBGRP_STATUS_DEFAULT_ORIGINATE);
+
route_map_counter_decrement(peer->default_rmap[afi][safi].map);
peer->default_rmap[afi][safi].name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].name);
+ /*
+ * This is triggered in case of route-map deletion.
+ * The flag needs to be unset, to trigger the flow
+ * of sending an update message.
+ */
+ if (subgrp)
+ UNSET_FLAG(subgrp->sflags,
+ SUBGRP_STATUS_DEFAULT_ORIGINATE);
+
route_map_counter_decrement(peer->default_rmap[afi][safi].map);
peer->default_rmap[afi][safi].name = NULL;
peer->default_rmap[afi][safi].map = NULL;
void peer_port_set(struct peer *peer, uint16_t port)
{
peer->port = port;
+ peer_flag_set(peer, PEER_FLAG_PORT);
}
void peer_port_unset(struct peer *peer)
{
peer->port = BGP_PORT_DEFAULT;
+ peer_flag_unset(peer, PEER_FLAG_PORT);
}
/* Set the TCP-MSS value in the peer structure,
return;
if (CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_SOFT_RECONFIG))
+ PEER_FLAG_SOFT_RECONFIG)) {
bgp_soft_reconfig_in(peer, afi, safi);
- else if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV)
- || CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV))
- bgp_route_refresh_send(peer, afi, safi, 0, 0, 0,
- BGP_ROUTE_REFRESH_NORMAL);
+ } else if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV) ||
+ CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV)) {
+ if (CHECK_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_ORF_PREFIX_SM_ADV) &&
+ (CHECK_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_ORF_PREFIX_RM_RCV) ||
+ CHECK_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_ORF_PREFIX_RM_OLD_RCV)))
+ peer_clear_soft(peer, afi, safi,
+ BGP_CLEAR_SOFT_IN_ORF_PREFIX);
+ else
+ bgp_route_refresh_send(
+ peer, afi, safi, 0, 0, 0,
+ BGP_ROUTE_REFRESH_NORMAL);
+ }
}
}
if (access->name)
update_group_policy_update(bgp,
BGP_POLICY_DISTRIBUTE_LIST,
- access->name, 0, 0);
+ access->name, true, 0);
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
FOREACH_AFI_SAFI (afi, safi) {
filter = &peer->filter[afi][safi];
*/
update_group_policy_update(
bgp, BGP_POLICY_PREFIX_LIST,
- plist ? prefix_list_name(plist) : NULL, 0, 0);
+ plist ? prefix_list_name(plist) : NULL, true, 0);
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
FOREACH_AFI_SAFI (afi, safi) {
filter->plist[direct].plist =
NULL;
}
+
+ /* If we touch prefix-list, we need to process
+ * new updates. This is important for ORF to
+ * work correctly as well.
+ */
+ if (peer->afc_nego[afi][safi])
+ peer_on_policy_change(peer, afi, safi,
+ 0);
}
}
for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) {
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
update_group_policy_update(bgp, BGP_POLICY_FILTER_LIST,
- aslist_name, 0, 0);
+ aslist_name, true, 0);
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
FOREACH_AFI_SAFI (afi, safi) {
/* 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,
__func__, peer->host,
get_afi_safi_str(afi, safi, false));
- peer_on_policy_change(peer, afi, safi, 1);
return 0;
}
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;
UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
if (peer->t_pmax_restart) {
- BGP_TIMER_OFF(peer->t_pmax_restart);
+ THREAD_OFF(peer->t_pmax_restart);
if (bgp_debug_neighbor_events(peer))
zlog_debug(
"%pBP Maximum-prefix restart timer cancelled",
* of a large number of peers this will ensure that no peer is left with
* a dangling connection
*/
- /* reverse bgp_master_init */
- bgp_close();
-
- if (bm->listen_sockets)
- list_delete(&bm->listen_sockets);
- for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp))
+ bgp_close();
+ /* reverse bgp_master_init */
+ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
+ bgp_close_vrf_socket(bgp);
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer))
if (peer_established(peer) || peer->status == OpenSent
|| peer->status == OpenConfirm)
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_PEER_UNCONFIG);
+ }
+
+ if (bm->listen_sockets)
+ list_delete(&bm->listen_sockets);
- BGP_TIMER_OFF(bm->t_rmap_update);
+ THREAD_OFF(bm->t_rmap_update);
bgp_mac_finish();
}
/* vrf-route leaking flags */
#define BGP_CONFIG_VRF_TO_VRF_IMPORT (1 << 9)
#define BGP_CONFIG_VRF_TO_VRF_EXPORT (1 << 10)
+/* vpnvx retain flag */
+#define BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL (1 << 11)
/* BGP per AF peer count */
uint32_t af_peer_count[AFI_MAX][SAFI_MAX];
struct timeval ebgprequirespolicywarning;
#define FIFTEENMINUTE2USEC (int64_t)15 * 60 * 1000000
+ bool allow_martian;
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(bgp);
#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"
#define PEER_FLAG_EXTENDED_OPT_PARAMS (1ULL << 30)
/* BGP Open Policy flags.
- * Enforce using roles on both sides
+ * Enforce using roles on both sides:
+ * `local-role ROLE strict-mode` configured.
*/
-#define PEER_FLAG_STRICT_MODE (1ULL << 31)
+#define PEER_FLAG_ROLE_STRICT_MODE (1ULL << 31)
+ /* `local-role` configured */
+#define PEER_FLAG_ROLE (1ULL << 32)
+#define PEER_FLAG_PORT (1ULL << 33)
/*
*GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
extern void bm_wait_for_fib_set(bool set);
extern void bgp_suppress_fib_pending_set(struct bgp *bgp, bool set);
-extern int bgp_cluster_id_set(struct bgp *, struct in_addr *);
-extern int bgp_cluster_id_unset(struct bgp *);
+extern void bgp_cluster_id_set(struct bgp *bgp, struct in_addr *cluster_id);
+extern void bgp_cluster_id_unset(struct bgp *bgp);
-extern void bgp_confederation_id_set(struct bgp *, as_t);
-extern int bgp_confederation_id_unset(struct bgp *);
+extern void bgp_confederation_id_set(struct bgp *bgp, as_t as);
+extern void bgp_confederation_id_unset(struct bgp *bgp);
extern bool bgp_confederation_peers_check(struct bgp *, as_t);
-extern int bgp_confederation_peers_add(struct bgp *, as_t);
-extern int bgp_confederation_peers_remove(struct bgp *, as_t);
+extern void bgp_confederation_peers_add(struct bgp *bgp, as_t as);
+extern void bgp_confederation_peers_remove(struct bgp *bgp, as_t as);
extern void bgp_timers_set(struct bgp *, uint32_t keepalive, uint32_t holdtime,
uint32_t connect_retry, uint32_t delayopen);
extern void bgp_timers_unset(struct bgp *);
-extern int bgp_default_local_preference_set(struct bgp *, uint32_t);
-extern int bgp_default_local_preference_unset(struct bgp *);
+extern void bgp_default_local_preference_set(struct bgp *bgp,
+ uint32_t local_pref);
+extern void bgp_default_local_preference_unset(struct bgp *bgp);
-extern int bgp_default_subgroup_pkt_queue_max_set(struct bgp *bgp, uint32_t);
-extern int bgp_default_subgroup_pkt_queue_max_unset(struct bgp *bgp);
+extern void bgp_default_subgroup_pkt_queue_max_set(struct bgp *bgp,
+ uint32_t queue_size);
+extern void bgp_default_subgroup_pkt_queue_max_unset(struct bgp *bgp);
-extern int bgp_listen_limit_set(struct bgp *, int);
-extern int bgp_listen_limit_unset(struct bgp *);
+extern void bgp_listen_limit_set(struct bgp *bgp, int listen_limit);
+extern void bgp_listen_limit_unset(struct bgp *bgp);
extern bool bgp_update_delay_active(struct bgp *);
extern bool bgp_update_delay_configured(struct bgp *);
-extern int bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi);
+extern bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi);
extern void peer_as_change(struct peer *, as_t, int);
extern int peer_remote_as(struct bgp *, union sockunion *, const char *, as_t *,
int);
extern void peer_description_unset(struct peer *);
extern int peer_update_source_if_set(struct peer *, const char *);
-extern int peer_update_source_addr_set(struct peer *, const union sockunion *);
-extern int peer_update_source_unset(struct peer *);
+extern void peer_update_source_addr_set(struct peer *peer,
+ const union sockunion *su);
+extern void peer_update_source_unset(struct peer *peer);
extern int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
const char *rmap,
encaptlv = XCALLOC(MTYPE_ENCAP_TLV,
sizeof(struct bgp_attr_encap_subtlv) + 4);
- assert(encaptlv);
encaptlv->type =
BGP_VNC_SUBTLV_TYPE_LIFETIME; /* prefix lifetime */
encaptlv->length = 4;
MTYPE_ENCAP_TLV,
sizeof(struct bgp_attr_encap_subtlv) + 2
+ hop->length);
- assert(encaptlv);
encaptlv->type =
BGP_VNC_SUBTLV_TYPE_RFPOPTION; /* RFP
option
SET_FLAG(new->flags, BGP_PATH_VALID);
/* save backref to rfapi handle */
- assert(bgp_path_info_extra_get(new));
+ bgp_path_info_extra_get(new);
new->extra->vnc.export.rfapi_handle = (void *)rfd;
encode_label(label_val, &new->extra->label[0]);
* since this peer is not on the I/O thread, this lock is not strictly
* necessary, but serves as a reminder to those who may meddle...
*/
- frr_with_mutex(&rfd->peer->io_mtx) {
+ frr_with_mutex (&rfd->peer->io_mtx) {
// we don't need any I/O related facilities
if (rfd->peer->ibuf)
stream_fifo_free(rfd->peer->ibuf);
rfd = XCALLOC(MTYPE_RFAPI_DESC,
sizeof(struct rfapi_descriptor));
}
- assert(rfd);
rfd->bgp = bgp;
if (default_options) {
DEFUN (debug_rfapi_register_vn_un_l2o,
debug_rfapi_register_vn_un_l2o_cmd,
- "debug rfapi-dev register vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M> lifetime SECONDS macaddr YY:YY:YY:YY:YY:YY lni (0-16777215)",
+ "debug rfapi-dev register vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M> lifetime SECONDS macaddr X:X:X:X:X:X lni (0-16777215)",
DEBUG_STR
DEBUG_RFAPI_STR
"rfapi_register\n"
DEFUN (debug_rfapi_query_vn_un_l2o,
debug_rfapi_query_vn_un_l2o_cmd,
- "debug rfapi-dev query vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> lni LNI target YY:YY:YY:YY:YY:YY",
+ "debug rfapi-dev query vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> lni LNI target X:X:X:X:X:X",
DEBUG_STR
DEBUG_RFAPI_STR
"rfapi_query\n"
if (rc) {
/* Not found */
adb = XCALLOC(MTYPE_RFAPI_ADB, sizeof(struct rfapi_adb));
- assert(adb);
adb->lifetime = lifetime;
adb->u.key = rk;
stlv = attr->encap_subtlvs;
uo = XCALLOC(MTYPE_RFAPI_UN_OPTION, sizeof(struct rfapi_un_option));
- assert(uo);
uo->type = RFAPI_UN_OPTION_TYPE_TUNNELTYPE;
uo->v.tunnel.type = attr->encap_tunneltype;
tto = &uo->v.tunnel;
*/
if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
&& bpi->extra->vnc.import.timer) {
-
- struct thread **t =
- &(bpi->extra->vnc.import.timer);
- struct rfapi_withdraw *wcb = (*t)->arg;
+ struct rfapi_withdraw *wcb =
+ THREAD_ARG(bpi->extra->vnc.import.timer);
XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
- thread_cancel(t);
+ THREAD_OFF(bpi->extra->vnc.import.timer);
}
next = bpi->next;
#endif
new = XCALLOC(MTYPE_RFAPI_NEXTHOP, sizeof(struct rfapi_next_hop_entry));
- assert(new);
new->prefix = *rprefix;
vo = XCALLOC(MTYPE_RFAPI_VN_OPTION,
sizeof(struct rfapi_vn_option));
- assert(vo);
vo->type = RFAPI_VN_OPTION_TYPE_L2ADDR;
m = XCALLOC(MTYPE_RFAPI_MONITOR_ENCAP,
sizeof(struct rfapi_monitor_encap));
- assert(m);
m->node = vpn_rn;
m->bpi = vpn_bpi;
*/
static void rfapiWithdrawTimerVPN(struct thread *t)
{
- struct rfapi_withdraw *wcb = t->arg;
+ struct rfapi_withdraw *wcb = THREAD_ARG(t);
struct bgp_path_info *bpi = wcb->info;
struct bgp *bgp = bgp_get_default();
const struct prefix *p;
static void rfapiWithdrawTimerEncap(struct thread *t)
{
- struct rfapi_withdraw *wcb = t->arg;
+ struct rfapi_withdraw *wcb = THREAD_ARG(t);
struct bgp_path_info *bpi = wcb->info;
int was_first_route = 0;
struct rfapi_monitor_encap *em;
* service routine, which is supposed to free the wcb.
*/
wcb = XCALLOC(MTYPE_RFAPI_WITHDRAW, sizeof(struct rfapi_withdraw));
- assert(wcb);
wcb->node = rn;
wcb->info = bpi;
wcb->import_table = import_table;
*/
if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
&& bpi->extra->vnc.import.timer) {
-
- struct thread **t =
- &(bpi->extra->vnc.import.timer);
- struct rfapi_withdraw *wcb = (*t)->arg;
+ struct rfapi_withdraw *wcb = THREAD_ARG(
+ bpi->extra->vnc.import.timer);
XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
- thread_cancel(t);
+ THREAD_OFF(
+ bpi->extra->vnc.import.timer);
}
if (action == FIF_ACTION_UPDATE) {
"%s: removing holddown bpi matching NVE of new route",
__func__);
if (bpi->extra->vnc.import.timer) {
- struct thread **t =
- &(bpi->extra->vnc.import.timer);
- struct rfapi_withdraw *wcb = (*t)->arg;
+ struct rfapi_withdraw *wcb =
+ THREAD_ARG(bpi->extra->vnc.import.timer);
XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
- thread_cancel(t);
+ THREAD_OFF(bpi->extra->vnc.import.timer);
}
rfapiExpireEncapNow(import_table, rn, bpi);
}
struct agg_table *referenced_vpn_table;
referenced_vpn_table = agg_table_init();
- assert(referenced_vpn_table);
/*
* iterate over the set of monitors at this ENCAP node.
mnext = XCALLOC(
MTYPE_RFAPI_MONITOR_ENCAP,
sizeof(struct rfapi_monitor_encap));
- assert(mnext);
mnext->node = m->node;
mnext->next = referenced_vpn_prefix->info;
referenced_vpn_prefix->info = mnext;
*/
if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
&& bpi->extra->vnc.import.timer) {
-
- struct thread **t =
- &(bpi->extra->vnc.import.timer);
- struct rfapi_withdraw *wcb = (*t)->arg;
+ struct rfapi_withdraw *wcb = THREAD_ARG(
+ bpi->extra->vnc.import.timer);
XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
- thread_cancel(t);
+ THREAD_OFF(
+ bpi->extra->vnc.import.timer);
import_table->holddown_count[afi] -= 1;
RFAPI_UPDATE_ITABLE_COUNT(
"%s: removing holddown bpi matching NVE of new route",
__func__);
if (bpi->extra->vnc.import.timer) {
- struct thread **t =
- &(bpi->extra->vnc.import.timer);
- struct rfapi_withdraw *wcb = (*t)->arg;
+ struct rfapi_withdraw *wcb =
+ THREAD_ARG(bpi->extra->vnc.import.timer);
XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
- thread_cancel(t);
+ THREAD_OFF(bpi->extra->vnc.import.timer);
}
rfapiExpireVpnNow(import_table, rn, bpi, 0);
}
if (!it) {
it = XCALLOC(MTYPE_RFAPI_IMPORTTABLE,
sizeof(struct rfapi_import_table));
- assert(it);
it->next = h->imports;
h->imports = it;
if (!delete_holddown)
continue;
if (bpi->extra->vnc.import.timer) {
-
- struct thread **t =
- &(bpi->extra->vnc
- .import.timer);
struct rfapi_withdraw *wcb =
- (*t)->arg;
+ THREAD_ARG(
+ bpi->extra->vnc
+ .import
+ .timer);
wcb->import_table
->holddown_count[afi] -=
afi, 1);
XFREE(MTYPE_RFAPI_WITHDRAW,
wcb);
- thread_cancel(t);
+ THREAD_OFF(
+ bpi->extra->vnc.import
+ .timer);
}
} else {
if (!delete_active)
MTYPE_RFAPI_NVE_ADDR,
sizeof(struct
rfapi_nve_addr));
- assert(nap);
*nap = na;
nap->info = is_active
? pAHcount
rfapiMonitorDetachImport(m);
}
- thread_cancel(&m->timer);
+ THREAD_OFF(m->timer);
/*
* remove from rfd list
rfapiMonitorDetachImport(m);
}
- thread_cancel(&m->timer);
+ THREAD_OFF(m->timer);
XFREE(MTYPE_RFAPI_MONITOR, m);
rn->info = NULL;
#endif
}
- thread_cancel(&mon_eth->timer);
+ THREAD_OFF(mon_eth->timer);
/*
* remove from rfd list
static void rfapiMonitorTimerExpire(struct thread *t)
{
- struct rfapi_monitor_vpn *m = t->arg;
+ struct rfapi_monitor_vpn *m = THREAD_ARG(t);
/* forget reference to thread, it's gone */
m->timer = NULL;
static void rfapiMonitorTimerRestart(struct rfapi_monitor_vpn *m)
{
- if (m->timer) {
- unsigned long remain = thread_timer_remain_second(m->timer);
+ unsigned long remain = thread_timer_remain_second(m->timer);
- /* unexpected case, but avoid wraparound problems below */
- if (remain > m->rfd->response_lifetime)
- return;
+ /* unexpected case, but avoid wraparound problems below */
+ if (remain > m->rfd->response_lifetime)
+ return;
- /* don't restart if we just restarted recently */
- if (m->rfd->response_lifetime - remain < 2)
- return;
+ /* don't restart if we just restarted recently */
+ if (m->rfd->response_lifetime - remain < 2)
+ return;
- thread_cancel(&m->timer);
- }
+ THREAD_OFF(m->timer);
{
char buf[BUFSIZ];
rfapi_ntop(m->p.family, m->p.u.val, buf, BUFSIZ),
m->rfd->response_lifetime);
}
- m->timer = NULL;
+
thread_add_timer(bm->master, rfapiMonitorTimerExpire, m,
m->rfd->response_lifetime, &m->timer);
}
static void rfapiMonitorEthTimerExpire(struct thread *t)
{
- struct rfapi_monitor_eth *m = t->arg;
+ struct rfapi_monitor_eth *m = THREAD_ARG(t);
/* forget reference to thread, it's gone */
m->timer = NULL;
static void rfapiMonitorEthTimerRestart(struct rfapi_monitor_eth *m)
{
- if (m->timer) {
- unsigned long remain = thread_timer_remain_second(m->timer);
+ unsigned long remain = thread_timer_remain_second(m->timer);
- /* unexpected case, but avoid wraparound problems below */
- if (remain > m->rfd->response_lifetime)
- return;
+ /* unexpected case, but avoid wraparound problems below */
+ if (remain > m->rfd->response_lifetime)
+ return;
- /* don't restart if we just restarted recently */
- if (m->rfd->response_lifetime - remain < 2)
- return;
+ /* don't restart if we just restarted recently */
+ if (m->rfd->response_lifetime - remain < 2)
+ return;
- thread_cancel(&m->timer);
- }
+ THREAD_OFF(m->timer);
{
char buf[BUFSIZ];
rfapiEthAddr2Str(&m->macaddr, buf, BUFSIZ),
m->rfd->response_lifetime);
}
- m->timer = NULL;
+
thread_add_timer(bm->master, rfapiMonitorEthTimerExpire, m,
m->rfd->response_lifetime, &m->timer);
}
rfapiMonitorEthDetachImport(bgp, val);
}
- thread_cancel(&val->timer);
+ THREAD_OFF(val->timer);
/*
* remove from rfd list
if (goner->timer) {
struct rfapi_rib_tcb *tcb;
- tcb = goner->timer->arg;
- thread_cancel(&goner->timer);
+ tcb = THREAD_ARG(goner->timer);
+ THREAD_OFF(goner->timer);
XFREE(MTYPE_RFAPI_RECENT_DELETE, tcb);
}
XFREE(MTYPE_RFAPI_INFO, goner);
*/
static void rfapiRibExpireTimer(struct thread *t)
{
- struct rfapi_rib_tcb *tcb = t->arg;
+ struct rfapi_rib_tcb *tcb = THREAD_ARG(t);
RFAPI_RIB_CHECK_COUNTS(1, 0);
struct rfapi_rib_tcb *tcb = NULL;
if (ri->timer) {
- tcb = ri->timer->arg;
- thread_cancel(&ri->timer);
+ tcb = THREAD_ARG(ri->timer);
+ THREAD_OFF(ri->timer);
} else {
tcb = XCALLOC(MTYPE_RFAPI_RECENT_DELETE,
sizeof(struct rfapi_rib_tcb));
vnc_zlog_debug_verbose("%s: rfd %p pfx %pRN life %u", __func__, rfd, rn,
ri->lifetime);
- ri->timer = NULL;
+
thread_add_timer(bm->master, rfapiRibExpireTimer, tcb, ri->lifetime,
&ri->timer);
- assert(ri->timer);
}
extern void rfapi_rib_key_init(struct prefix *prefix, /* may be NULL */
if (ri->timer) {
struct rfapi_rib_tcb *tcb;
- tcb = ri->timer->arg;
- thread_cancel(&ri->timer);
+ tcb = THREAD_ARG(ri->timer);
+ THREAD_OFF(ri->timer);
XFREE(MTYPE_RFAPI_RECENT_DELETE, tcb);
}
if (ori->timer) {
struct rfapi_rib_tcb *tcb;
- tcb = ori->timer->arg;
- thread_cancel(&ori->timer);
+ tcb = THREAD_ARG(ori->timer);
+ THREAD_OFF(ori->timer);
XFREE(MTYPE_RFAPI_RECENT_DELETE, tcb);
}
new = XCALLOC(MTYPE_RFAPI_NEXTHOP,
sizeof(struct rfapi_next_hop_entry));
- assert(new);
if (ri->rk.aux_prefix.family) {
rfapiQprefix2Rprefix(&ri->rk.aux_prefix,
new = XCALLOC(
MTYPE_RFAPI_NEXTHOP,
sizeof(struct rfapi_next_hop_entry));
- assert(new);
if (ri->rk.aux_prefix.family) {
rfapiQprefix2Rprefix(&ri->rk.aux_prefix,
if (ri->timer) {
struct rfapi_rib_tcb *tcb;
- tcb = ri->timer->arg;
- thread_cancel(&ri->timer);
+ tcb = THREAD_ARG(ri->timer);
+ THREAD_OFF(ri->timer);
XFREE(MTYPE_RFAPI_RECENT_DELETE, tcb);
}
RFAPI_RIB_CHECK_COUNTS(0, delete_list->count);
urq = XCALLOC(MTYPE_RFAPI_UPDATED_RESPONSE_QUEUE,
sizeof(struct rfapi_updated_responses_queue));
- assert(urq);
if (!rfd->updated_responses_queue)
updated_responses_queue_init(rfd);
} else
fp(out, "%-15s %-15s", "", "");
buf_remain[0] = 0;
- if (m->timer) {
- rfapiFormatSeconds(
- thread_timer_remain_second(
- m->timer),
- buf_remain, BUFSIZ);
- }
+ rfapiFormatSeconds(
+ thread_timer_remain_second(m->timer),
+ buf_remain, BUFSIZ);
fp(out, " %-15s %-10s\n",
inet_ntop(m->p.family, &m->p.u.prefix,
buf_pfx, BUFSIZ),
} else
fp(out, "%-15s %-15s", "", "");
buf_remain[0] = 0;
- if (mon_eth->timer) {
- rfapiFormatSeconds(
- thread_timer_remain_second(
- mon_eth->timer),
- buf_remain, BUFSIZ);
- }
+ rfapiFormatSeconds(thread_timer_remain_second(
+ mon_eth->timer),
+ buf_remain, BUFSIZ);
fp(out, " %-17s %10d %-10s\n",
rfapi_ntop(pfx_mac.family, &pfx_mac.u.prefix,
buf_pfx, BUFSIZ),
************************************************************************/
DEFUN (add_vnc_mac_vni_prefix_cost_life,
add_vnc_mac_vni_prefix_cost_life_cmd,
- "add vnc mac YY:YY:YY:YY:YY:YY virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M> cost (0-255) lifetime (1-4294967295)",
+ "add vnc mac X:X:X:X:X:X virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M> cost (0-255) lifetime (1-4294967295)",
"Add registration\n"
"VNC Information\n"
"Add/modify mac address information\n"
DEFUN (add_vnc_mac_vni_prefix_life,
add_vnc_mac_vni_prefix_life_cmd,
- "add vnc mac YY:YY:YY:YY:YY:YY virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M> lifetime (1-4294967295)",
+ "add vnc mac X:X:X:X:X:X virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M> lifetime (1-4294967295)",
"Add registration\n"
"VNC Information\n"
"Add/modify mac address information\n"
DEFUN (add_vnc_mac_vni_prefix_cost,
add_vnc_mac_vni_prefix_cost_cmd,
- "add vnc mac YY:YY:YY:YY:YY:YY virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M> cost (0-255)",
+ "add vnc mac X:X:X:X:X:X virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M> cost (0-255)",
"Add registration\n"
"VNC Information\n"
"Add/modify mac address information\n"
DEFUN (add_vnc_mac_vni_prefix,
add_vnc_mac_vni_prefix_cmd,
- "add vnc mac YY:YY:YY:YY:YY:YY virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M>",
+ "add vnc mac X:X:X:X:X:X virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M>",
"Add registration\n"
"VNC Information\n"
"Add/modify mac address information\n"
DEFUN (add_vnc_mac_vni_cost_life,
add_vnc_mac_vni_cost_life_cmd,
- "add vnc mac YY:YY:YY:YY:YY:YY virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> cost (0-255) lifetime (1-4294967295)",
+ "add vnc mac X:X:X:X:X:X virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> cost (0-255) lifetime (1-4294967295)",
"Add registration\n"
"VNC Information\n"
"Add/modify mac address information\n"
DEFUN (add_vnc_mac_vni_cost,
add_vnc_mac_vni_cost_cmd,
- "add vnc mac YY:YY:YY:YY:YY:YY virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> cost (0-255)",
+ "add vnc mac X:X:X:X:X:X virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> cost (0-255)",
"Add registration\n"
"VNC Information\n"
"Add/modify mac address information\n"
DEFUN (add_vnc_mac_vni_life,
add_vnc_mac_vni_life_cmd,
- "add vnc mac YY:YY:YY:YY:YY:YY virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> lifetime (1-4294967295)",
+ "add vnc mac X:X:X:X:X:X virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> lifetime (1-4294967295)",
"Add registration\n"
"VNC Information\n"
"Add/modify mac address information\n"
DEFUN (add_vnc_mac_vni,
add_vnc_mac_vni_cmd,
- "add vnc mac YY:YY:YY:YY:YY:YY virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
+ "add vnc mac X:X:X:X:X:X virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
"Add registration\n"
"VNC Information\n"
"Add/modify mac address information\n"
*/
DEFUN (clear_vnc_mac_vn_un,
clear_vnc_mac_vn_un_cmd,
- "clear vnc mac <*|YY:YY:YY:YY:YY:YY> virtual-network-identifier <*|(1-4294967295)> vn <*|A.B.C.D|X:X::X:X> un <*|A.B.C.D|X:X::X:X>",
+ "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> vn <*|A.B.C.D|X:X::X:X> un <*|A.B.C.D|X:X::X:X>",
"clear\n"
"VNC Information\n"
"Clear mac registration information\n"
DEFUN (clear_vnc_mac_un_vn,
clear_vnc_mac_un_vn_cmd,
- "clear vnc mac <*|YY:YY:YY:YY:YY:YY> virtual-network-identifier <*|(1-4294967295)> un <*|A.B.C.D|X:X::X:X> vn <*|A.B.C.D|X:X::X:X>",
+ "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> un <*|A.B.C.D|X:X::X:X> vn <*|A.B.C.D|X:X::X:X>",
"clear\n"
"VNC Information\n"
"Clear mac registration information\n"
DEFUN (clear_vnc_mac_un,
clear_vnc_mac_un_cmd,
- "clear vnc mac <*|YY:YY:YY:YY:YY:YY> virtual-network-identifier <*|(1-4294967295)> un <*|A.B.C.D|X:X::X:X>",
+ "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> un <*|A.B.C.D|X:X::X:X>",
"clear\n"
"VNC Information\n"
"Clear mac registration information\n"
DEFUN (clear_vnc_mac_vn,
clear_vnc_mac_vn_cmd,
- "clear vnc mac <*|YY:YY:YY:YY:YY:YY> virtual-network-identifier <*|(1-4294967295)> vn <*|A.B.C.D|X:X::X:X>",
+ "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> vn <*|A.B.C.D|X:X::X:X>",
"clear\n"
"VNC Information\n"
"Clear mac registration information\n"
DEFUN (clear_vnc_mac_all,
clear_vnc_mac_all_cmd,
- "clear vnc mac <*|YY:YY:YY:YY:YY:YY> virtual-network-identifier <*|(1-4294967295)> *",
+ "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> *",
"clear\n"
"VNC Information\n"
"Clear mac registration information\n"
DEFUN (clear_vnc_mac_vn_un_prefix,
clear_vnc_mac_vn_un_prefix_cmd,
- "clear vnc mac <*|YY:YY:YY:YY:YY:YY> virtual-network-identifier <*|(1-4294967295)> vn <*|A.B.C.D|X:X::X:X> un <*|A.B.C.D|X:X::X:X> prefix <*|A.B.C.D/M|X:X::X:X/M>",
+ "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> vn <*|A.B.C.D|X:X::X:X> un <*|A.B.C.D|X:X::X:X> prefix <*|A.B.C.D/M|X:X::X:X/M>",
"clear\n"
"VNC Information\n"
"Clear mac registration information\n"
DEFUN (clear_vnc_mac_un_vn_prefix,
clear_vnc_mac_un_vn_prefix_cmd,
- "clear vnc mac <*|YY:YY:YY:YY:YY:YY> virtual-network-identifier <*|(1-4294967295)> un <*|A.B.C.D|X:X::X:X> vn <*|A.B.C.D|X:X::X:X> prefix <*|A.B.C.D/M|X:X::X:X/M> prefix <*|A.B.C.D/M|X:X::X:X/M>",
+ "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> un <*|A.B.C.D|X:X::X:X> vn <*|A.B.C.D|X:X::X:X> prefix <*|A.B.C.D/M|X:X::X:X/M> prefix <*|A.B.C.D/M|X:X::X:X/M>",
"clear\n"
"VNC Information\n"
"Clear mac registration information\n"
DEFUN (clear_vnc_mac_un_prefix,
clear_vnc_mac_un_prefix_cmd,
- "clear vnc mac <*|YY:YY:YY:YY:YY:YY> virtual-network-identifier <*|(1-4294967295)> un <*|A.B.C.D|X:X::X:X> prefix <*|A.B.C.D/M|X:X::X:X/M>",
+ "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> un <*|A.B.C.D|X:X::X:X> prefix <*|A.B.C.D/M|X:X::X:X/M>",
"clear\n"
"VNC Information\n"
"Clear mac registration information\n"
DEFUN (clear_vnc_mac_vn_prefix,
clear_vnc_mac_vn_prefix_cmd,
- "clear vnc mac <*|YY:YY:YY:YY:YY:YY> virtual-network-identifier <*|(1-4294967295)> vn <*|A.B.C.D|X:X::X:X> prefix <*|A.B.C.D/M|X:X::X:X/M>",
+ "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> vn <*|A.B.C.D|X:X::X:X> prefix <*|A.B.C.D/M|X:X::X:X/M>",
"clear\n"
"VNC Information\n"
"Clear mac registration information\n"
DEFUN (clear_vnc_mac_all_prefix,
clear_vnc_mac_all_prefix_cmd,
- "clear vnc mac <*|YY:YY:YY:YY:YY:YY> virtual-network-identifier <*|(1-4294967295)> prefix <*|A.B.C.D/M|X:X::X:X/M>",
+ "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> prefix <*|A.B.C.D/M|X:X::X:X/M>",
"clear\n"
"VNC Information\n"
"Clear mac registration information\n"
DEFUN (vnc_show_registrations_pfx,
vnc_show_registrations_pfx_cmd,
- "show vnc registrations [<A.B.C.D/M|X:X::X:X/M|YY:YY:YY:YY:YY:YY>]",
+ "show vnc registrations [<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M|X:X:X:X:X:X>]",
SHOW_STR
VNC_SHOW_STR
"List active prefix registrations\n"
+ "Limit output to a particualr IPV4 address\n"
"Limit output to a particular IPv4 prefix\n"
+ "Limit output to a particualr IPV6 address\n"
"Limit output to a particular IPv6 prefix\n"
- "Limit output to a particular IPv6 address\n")
+ "Limit output to a particular MAC address\n")
{
struct prefix p;
struct prefix *p_addr = NULL;
DEFUN (vnc_show_registrations_some_pfx,
vnc_show_registrations_some_pfx_cmd,
- "show vnc registrations <all|holddown|imported|local|remote> [<A.B.C.D/M|X:X::X:X/M|YY:YY:YY:YY:YY:YY>]",
+ "show vnc registrations <all|holddown|imported|local|remote> [<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M|X:X:X:X:X:X>]",
SHOW_STR
VNC_SHOW_STR
"List active prefix registrations\n"
"show only imported prefixes\n"
"show only local registrations\n"
"show only remote registrations\n"
- "Limit output to a particular prefix or address\n"
- "Limit output to a particular prefix or address\n"
- "Limit output to a particular prefix or address\n")
+ "Limit output to a particualr IPV4 address\n"
+ "Limit output to a particular IPv4 prefix\n"
+ "Limit output to a particualr IPV6 address\n"
+ "Limit output to a particular IPv6 prefix\n"
+ "Limit output to a particular MAC address\n")
{
struct prefix p;
struct prefix *p_addr = NULL;
DEFUN (vnc_show_responses_pfx,
vnc_show_responses_pfx_cmd,
- "show vnc responses [<A.B.C.D/M|X:X::X:X/M|YY:YY:YY:YY:YY:YY>]",
+ "show vnc responses [<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M|X:X:X:X:X:X>]",
SHOW_STR
VNC_SHOW_STR
"List recent query responses\n"
+ "Limit output to a particualr IPV4 address\n"
"Limit output to a particular IPv4 prefix\n"
+ "Limit output to a particualr IPV6 address\n"
"Limit output to a particular IPv6 prefix\n"
- "Limit output to a particular IPv6 address\n" )
+ "Limit output to a particular MAC address\n" )
{
struct prefix p;
struct prefix *p_addr = NULL;
DEFUN (vnc_show_responses_some_pfx,
vnc_show_responses_some_pfx_cmd,
- "show vnc responses <active|removed> [<A.B.C.D/M|X:X::X:X/M|YY:YY:YY:YY:YY:YY>]",
+ "show vnc responses <active|removed> [<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M|X:X:X:X:X:X>]",
SHOW_STR
VNC_SHOW_STR
"List recent query responses\n"
"show only active query responses\n"
"show only removed query responses\n"
+ "Limit output to a particualr IPV4 address\n"
"Limit output to a particular IPv4 prefix\n"
+ "Limit output to a particualr IPV6 address\n"
"Limit output to a particular IPv6 prefix\n"
- "Limit output to a particular IPV6 address\n")
+ "Limit output to a particular MAC address\n")
{
struct prefix p;
struct prefix *p_addr = NULL;
DEFUN (show_vnc_queries_pfx,
show_vnc_queries_pfx_cmd,
- "show vnc queries [<A.B.C.D/M|X:X::X:X/M|YY:YY:YY:YY:YY:YY>]",
+ "show vnc queries [<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M|X:X:X:X:X:X>]",
SHOW_STR
VNC_SHOW_STR
"List active queries\n"
- "Limit output to a particular IPv4 prefix or address\n"
+ "Limit output to a particualr IPV4 address\n"
+ "Limit output to a particular IPv4 prefix\n"
+ "Limit output to a particualr IPV6 address\n"
"Limit output to a particular IPv6 prefix\n"
- "Limit output to a particualr IPV6 address\n")
+ "Limit output to a particualr MAC address\n")
{
struct prefix pfx;
struct prefix *p = NULL;
roec.val[7] = 0;
new = ecommunity_new();
- assert(new);
ecommunity_add_val(new, &roec, false, false);
if (!new->size) {
* export expiration timer is already running on
* this route: cancel it
*/
- thread_cancel(&eti->timer);
+ THREAD_OFF(eti->timer);
bgp_update(peer, prefix, /* prefix */
0, /* addpath_id */
static void vncExportWithdrawTimer(struct thread *t)
{
- struct vnc_export_info *eti = t->arg;
+ struct vnc_export_info *eti = THREAD_ARG(t);
const struct prefix *p = agg_node_get_prefix(eti->node);
/*
* already running on
* this route: cancel it
*/
- thread_cancel(&eti->timer);
+ THREAD_OFF(eti->timer);
vnc_zlog_debug_verbose(
"%s: calling bgp_update",
ZEBRA_ROUTE_VNC_DIRECT_RH,
BGP_ROUTE_REDISTRIBUTE);
if (eti) {
- thread_cancel(&eti->timer);
+ THREAD_OFF(eti->timer);
vnc_eti_delete(eti);
}
agg_unlock_node(etn);
} else {
eti = XCALLOC(MTYPE_RFAPI_ETI, sizeof(struct vnc_export_info));
- assert(eti);
eti->node = etn;
eti->peer = peer;
peer_lock(peer);
* is not strictly necessary, but serves as a reminder
* to those who may meddle...
*/
- frr_with_mutex(&vncHD1VR.peer->io_mtx) {
+ frr_with_mutex (&vncHD1VR.peer->io_mtx) {
// we don't need any I/O related facilities
if (vncHD1VR.peer->ibuf)
stream_fifo_free(vncHD1VR.peer->ibuf);
AS_HELP_STRING([--disable-isisd], [do not build isisd]))
AC_ARG_ENABLE([pimd],
AS_HELP_STRING([--disable-pimd], [do not build pimd]))
+AC_ARG_ENABLE([pim6d],
+ AS_HELP_STRING([--enable-pim6d], [build pim6d]))
AC_ARG_ENABLE([pbrd],
AS_HELP_STRING([--disable-pbrd], [do not build pbrd]))
AC_ARG_ENABLE([sharpd],
AC_DEFINE([HAVE_PIMD], [1], [pimd])
])
+AS_IF([test "$enable_pim6d" = "yes"], [
+ AC_DEFINE([HAVE_PIM6D], [1], [pim6d])
+])
+
AS_IF([test "$enable_pbrd" != "no"], [
AC_DEFINE([HAVE_PBRD], [1], [pbrd])
])
AM_CONDITIONAL([OSPF6D], [test "$enable_ospf6d" != "no"])
AM_CONDITIONAL([ISISD], [test "$enable_isisd" != "no"])
AM_CONDITIONAL([PIMD], [test "$enable_pimd" != "no"])
+AM_CONDITIONAL([PIM6D], [test "$enable_pim6d" = "yes"])
AM_CONDITIONAL([PBRD], [test "$enable_pbrd" != "no"])
AM_CONDITIONAL([SHARPD], [test "$enable_sharpd" = "yes"])
AM_CONDITIONAL([STATICD], [test "$enable_staticd" != "no"])
frr (8.4~dev-1) UNRELEASED; urgency=medium
- * New upstream release...
+ * FRR Dev 8.4
- -- Donatas Abraitis <donatas@opensourcerouting.org> Tue, 07 May 2022 23:00:00 +0300
+ -- Jafar Al-Gharaibeh <jafar@atcorp.com> Wed, 20 Jul 2022 10:00:00 +0500
-frr (8.2-0) UNRELEASED; urgency=medium
+frr (8.3-0) unstable; urgency=medium
+
+ * New upstream release FRR 8.3
+
+ -- Jafar Al-Gharaibeh <jafar@atcorp.com> Wed, 13 Jul 2022 10:00:00 +0500
+
+frr (8.2-0) unstable; urgency=medium
* New upstream release FRR 8.2
libpcre2-dev,
libpython3-dev,
libreadline-dev,
- librtr-dev (>= 0.8.0) <!pkg.frr.nortrlib>,
+ librtr-dev (>= 0.8.0~) <!pkg.frr.nortrlib>,
libsnmp-dev,
libssh-dev <!pkg.frr.nortrlib>,
libyang2-dev,
# open, as well as the daemons, so always signal the daemons.
# It's safe, a NOP if (only) syslog is being used.
for i in babeld bgpd eigrpd isisd ldpd nhrpd ospf6d ospfd sharpd \
- pimd ripd ripngd zebra pathd pbrd staticd bfdd fabricd vrrpd; do
+ pimd pim6d ripd ripngd zebra pathd pbrd staticd bfdd fabricd vrrpd; do
if [ -e /var/run/frr/$i.pid ] ; then
pids="$pids $(cat /var/run/frr/$i.pid)"
fi
CONF_LUA=--enable-scripting
endif
+ifeq ($(filter pkg.frr.pim6d,$(DEB_BUILD_PROFILES)),)
+ CONF_PIM6=--disable-pim6d
+else
+ CONF_PIM6=--enable-pim6d
+endif
+
export PYTHON=python3
%:
\
$(CONF_RPKI) \
$(CONF_LUA) \
+ $(CONF_PIM6) \
--with-libpam \
--enable-doc \
--enable-doc-html \
``pthread_mutex_unlock``. Use ``#include "frr_pthread.h"`` to get these
macros.
-.. c:macro:: frr_with_mutex(mutex)
+.. c:macro:: frr_with_mutex (mutex)
(With ``pthread_mutex_t *mutex``.)
int somefunction(int option)
{
- frr_with_mutex(&my_mutex) {
+ frr_with_mutex (&my_mutex) {
/* mutex will be locked */
if (!option)
+================+===================+=========================================+
| pkg.frr.rtrlib | pkg.frr.nortrlib | builds frr-rpki-rtrlib package (or not) |
+----------------+-------------------+-----------------------------------------+
+ | pkg.frr.lua | pkg.frr.nolua | builds lua scripting extension |
+ +----------------+-------------------+-----------------------------------------+
+ | pkg.frr.pim6d | pkg.frr.nopim6d | builds pim6d (work in progress) |
+ +----------------+-------------------+-----------------------------------------+
* the ``-uc -us`` options to disable signing the packages with your GPG key
"invisible" copies. Other threads, when they access the structure, see an
older (but consistent) copy.
-* once done, the updated copy is swapped in in a single operation so that
+* once done, the updated copy is swapped in a single operation so that
other threads see either the old or the new data but no inconsistent state
between.
# To enable the gRPC topotest install:
python3 -m pip install grpcio grpcio-tools
+ # Install Socat tool to run PIMv6 tests,
+ # Socat code can be taken from below url,
+ # which has latest changes done for PIMv6,
+ # join and traffic:
+ https://github.com/opensourcerouting/socat/
+
Enable Coredumps
""""""""""""""""
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:
frr# show bfd peer 192.168.0.1 json
{"multihop":false,"peer":"192.168.0.1","id":1,"remote-id":1,"status":"up","uptime":161,"diagnostic":"ok","remote-diagnostic":"ok","receive-interval":300,"transmit-interval":300,"echo-receive-interval":50,"echo-transmit-interval":0,"detect-multiplier":3,"remote-receive-interval":300,"remote-transmit-interval":300,"remote-echo-receive-interval":50,"remote-detect-multiplier":3,"peer-type":"dynamic"}
+If you are running IPV4 BFD Echo, on a Linux platform, we also
+calculate round trip time for the packets. We display minimum,
+average and maximum time it took to receive the looped Echo packets
+in the RTT fields.
You can inspect the current BFD peer status in brief with the following commands:
.. clicmd:: bgp fast-external-failover
- This command causes bgp to not take down ebgp peers immediately
+ This command causes bgp to take down ebgp peers immediately
when a link flaps. `bgp fast-external-failover` is the default
and will not be displayed as part of a `show run`. The no form
of the command turns off this ability.
exit-address-family
!
bgp community-list 70 permit 7675:70
- bgp community-list 70 deny
bgp community-list 80 permit 7675:80
- bgp community-list 80 deny
bgp community-list 90 permit 7675:90
- bgp community-list 90 deny
!
route-map RMAP permit 10
match community 70
The CLI will disallow attempts to configure incompatible leaking
modes.
+.. clicmd:: bgp retain route-target all
+
+It is possible to retain or not VPN prefixes that are not imported by local
+VRF configuration. This can be done via the following command in the context
+of the global VPNv4/VPNv6 family. This command defaults to on and is not
+displayed.
+The `no bgp retain route-target all` form of the command is displayed.
+
.. _bgp-l3vpn-srv6:
L3VPN SRv6
Display Listen sockets and the vrf that created them. Useful for debugging of when
listen is not working and this is considered a developer debug statement.
+.. clicmd:: debug bgp allow-martian
+
+ Enable or disable BGP accepting martian nexthops from a peer. Please note
+ this is not an actual debug command and this command is also being deprecated
+ and will be removed soon. The new command is :clicmd:`bgp allow-martian-nexthop`
+
.. clicmd:: debug bgp bfd
Enable or disable debugging for BFD events. This will show BFD integration
If the ``json`` option is specified, output is displayed in JSON format.
+.. clicmd:: show [ip] bgp [afi] [safi] [all] access-list WORD [wide|json]
+
+ Display routes that match the specified access-list.
+
.. clicmd:: show [ip] bgp [afi] [safi] [all] filter-list WORD [wide|json]
Display routes that match the specified AS-Path filter-list.
configuration write operation. At this point in time non SAFI_UNICAST BGP
data is not properly withdrawn from zebra when this command is issued.
+.. clicmd:: bgp allow-martian-nexthop
+
+When a peer receives a martian nexthop as part of the NLRI for a route
+permit the nexthop to be used as such, instead of rejecting and resetting
+the connection.
+
.. clicmd:: bgp send-extra-data zebra
This command turns on the ability of BGP to send extra data to zebra. Currently,
.. clicmd:: bmp monitor AFI SAFI <pre-policy|post-policy>
Perform Route Monitoring for the specified AFI and SAFI. Only IPv4 and
- IPv6 are currently valid for AFI, and only unicast and multicast are valid
- for SAFI. Other AFI/SAFI combinations may be added in the future.
+ IPv6 are currently valid for AFI. SAFI valid values are currently
+ unicast, multicast, evpn and vpn.
+ Other AFI/SAFI combinations may be added in the future.
All BGP neighbors are included in Route Monitoring. Options to select
a subset of BGP sessions may be added in the future.
+-----------------------------------+----------------+--------------+------------+------------+
| **Multicast Routing** | | | | |
+-----------------------------------+----------------+--------------+------------+------------+
-| `pimd` (PIM) | :mark:`≥4.18` | :mark:`N` | :mark:`Y` | :mark:`Y` |
+| `pimd` (PIM) | :mark:`≥4.19` | :mark:`N` | :mark:`Y` | :mark:`Y` |
+-----------------------------------+----------------+--------------+------------+------------+
| SSM (Source Specific) | :mark:`Y` | :mark:`N` | :mark:`Y` | :mark:`Y` |
+-----------------------------------+----------------+--------------+------------+------------+
.. note::
- On Linux for PIM-SM operation you *must* have kernel version 4.18 or greater.
+ On Linux for PIM-SM operation you *must* have kernel version 4.19 or greater.
To use PIM for EVPN BUM forwarding, kernels 5.0 or greater are required.
OpenBSD has no multicast support and FreeBSD, and NetBSD only
have support for SSM.
packet count, byte count and wrong interface to 0 and start count
up from this spot.
+.. clicmd:: clear ipv6 pim interfaces
+
+ Reset PIMv6 interfaces.
+
+.. clicmd:: clear ipv6 pim [vrf NAME] interface traffic
+
+ When this command is issued, resets the information about the
+ number of PIM protocol packets sent/received on an interface.
+
.. clicmd:: clear ipv6 pim oil
Rescan PIMv6 OIL (output interface list).
+.. clicmd:: clear ipv6 pim [vrf NAME] bsr-data
+
+ This command will clear the BSM scope data struct. This command also
+ removes the next hop tracking for the bsr and resets the upstreams
+ for the dynamically learnt RPs.
+
PIMv6 Debug Commands
====================
.. clicmd:: debug pimv6 zebra
This gathers data about events from zebra that come up through the ZAPI.
+
+.. clicmd:: debug mroute6
+
+ This turns on debugging for PIMv6 interaction with kernel MFC cache.
+
+.. clicmd:: debug mroute6 detail
+
+ This turns on detailed debugging for PIMv6 interaction with kernel MFC cache.
.. clicmd:: neighbor A.B.C.D
- Specify RIP neighbor. When a neighbor doesn't understand multicast, this
- command is used to specify neighbors. In some cases, not all routers will be
- able to understand multicasting, where packets are sent to a network or a
- group of addresses. In a situation where a neighbor cannot process multicast
- packets, it is necessary to establish a direct link between routers. The
- neighbor command allows the network administrator to specify a router as a
- RIP neighbor. The `no neighbor a.b.c.d` command will disable the RIP
- neighbor.
+ Specify a RIP neighbor to send updates to. This is required when a neighbor
+ is connected via a network that does not support multicast, or when it is
+ desired to statically define a neighbor. RIP updates will be sent via unicast
+ to each neighbour. Neighbour updates are in addition to any multicast updates
+ sent when an interface is not in passive mode (see the `passive-interface`
+ command). RIP will continue to process updates received from both the
+ neighbor and any received via multicast. The `no neighbor a.b.c.d` command
+ will disable the RIP neighbor.
Below is very simple RIP configuration. Interface `eth0` and interface which
address match to `10.0.0.0/8` are RIP enabled.
Set description for the interface.
+.. clicmd:: mpls enable
+
+ Enable or disable mpls kernel processing on the interface, for linux. Interfaces
+ configured with mpls will not automatically turn on if mpls kernel modules do not
+ happen to be loaded. This command will fail on 3.X linux kernels and does not
+ work on non-linux systems at all.
+
.. clicmd:: multicast
# This stage builds a libyang APK from source
FROM alpine-builder as libyang-builder
RUN mkdir -p /libyang && chown -R builder /pkgs /libyang
-COPY docker/alpine/libyang/ /libyang
-USER builder
-RUN cd /libyang \
- && abuild checksum \
- && abuild -r -P /pkgs/apk
+# -- Not currently needed - libyang currently available in Alpine upstream
+# COPY docker/alpine/libyang/ /libyang
+# USER builder
+# RUN cd /libyang \
+# && abuild checksum \
+# && abuild -r -P /pkgs/apk
# This stage builds a dist tarball from the source
FROM alpine:3.15 as source-builder
&& pip install pytest
RUN mkdir -p /pkgs/apk
-COPY --from=libyang-builder /pkgs/apk/ /pkgs/apk/
-RUN apk add \
- --no-cache \
- --allow-untrusted /pkgs/apk/*/*.apk
+# -- Not needed while libyang is not built
+# COPY --from=libyang-builder /pkgs/apk/ /pkgs/apk/
+# RUN apk add \
+# --no-cache \
+# --allow-untrusted /pkgs/apk/*/*.apk \
COPY . /src
ARG PKGVER
# This stage builds an APK from the dist tarball
FROM alpine-builder as frr-apk-builder
-COPY --from=libyang-builder /pkgs/apk/ /pkgs/apk/
+# -- Not needed while libyang is not built
+# COPY --from=libyang-builder /pkgs/apk/ /pkgs/apk/
+# RUN apk add \
+# --no-cache \
+# --allow-untrusted /pkgs/apk/*/*.apk
COPY --from=source-builder /src/frr-*.tar.gz /src/alpine/* /dist/
RUN find /pkgs/apk -type f -name APKINDEX.tar.gz -delete
-RUN apk add \
- --no-cache \
- --allow-untrusted /pkgs/apk/*/*.apk
RUN chown -R builder /dist /pkgs
USER builder
RUN cd /dist \
# Contributor: Sören Tempel <soeren+alpine@soeren-tempel.net>
# Maintainer: Christian Franke <nobody@nowhere.ws>
pkgname=libyang
-pkgver=2.0.7
+pkgver=2.0.194
pkgrel=0
pkgdesc="YANG data modelling language parser and toolkit"
url="https://github.com/CESNET/libyang"
makedepends="bison cmake cmocka-dev flex pcre2-dev"
checkdepends="expect grep shunit2"
subpackages="$pkgname-dev $pkgname-doc"
-source="$pkgname-$pkgver.tar.gz::https://github.com/CESNET/libyang/archive/v$pkgver.tar.gz
- 10-remove-non-standard-headers.patch
- 11-utest-dont-parse-dlerror.patch"
+source="$pkgname-$pkgver.tar.gz::https://github.com/CESNET/libyang/archive/v$pkgver.tar.gz"
# secfixes:
# 1.0.215-r1:
package() {
make -C build DESTDIR="$pkgdir" install
}
-
-sha512sums="edb1d8d372b25ed820fa312e0dc96d4af7c8cd5ddeb785964de73f64774062ea7a5586bb27e2039ad24189d4a2ba04268921ca86e82423fc48647d1d10a2a0a7 libyang-2.0.7.tar.gz
-385008c715e6b0dc9e8f33c9cb550b3af7ee16f056f35d09a4ba01b9e00ddb88940915f93fc608fedd30b4f9a6a1503df414ae0be64b1263681b0ee18e6f4db8 10-remove-non-standard-headers.patch
-b16881d301a6aec68fbe6bfb7ba53a8fcdb4b9eead3b03573e0e2a4a8c3c3d6962db623be14d29c023b5a7ad0f685da1f6033dd9985f7a2914ad2f4da07e60cb 11-utest-dont-parse-dlerror.patch"
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_PKT_CLS_H
+#define __LINUX_PKT_CLS_H
+
+#include <linux/types.h>
+#include <linux/pkt_sched.h>
+
+#define TC_COOKIE_MAX_SIZE 16
+
+/* Action attributes */
+enum {
+ TCA_ACT_UNSPEC,
+ TCA_ACT_KIND,
+ TCA_ACT_OPTIONS,
+ TCA_ACT_INDEX,
+ TCA_ACT_STATS,
+ TCA_ACT_PAD,
+ TCA_ACT_COOKIE,
+ TCA_ACT_FLAGS,
+ TCA_ACT_HW_STATS,
+ TCA_ACT_USED_HW_STATS,
+ __TCA_ACT_MAX
+};
+
+#define TCA_ACT_FLAGS_NO_PERCPU_STATS 1 /* Don't use percpu allocator for
+ * actions stats.
+ */
+
+/* tca HW stats type
+ * When user does not pass the attribute, he does not care.
+ * It is the same as if he would pass the attribute with
+ * all supported bits set.
+ * In case no bits are set, user is not interested in getting any HW statistics.
+ */
+#define TCA_ACT_HW_STATS_IMMEDIATE (1 << 0) /* Means that in dump, user
+ * gets the current HW stats
+ * state from the device
+ * queried at the dump time.
+ */
+#define TCA_ACT_HW_STATS_DELAYED (1 << 1) /* Means that in dump, user gets
+ * HW stats that might be out of date
+ * for some time, maybe couple of
+ * seconds. This is the case when
+ * driver polls stats updates
+ * periodically or when it gets async
+ * stats update from the device.
+ */
+
+#define TCA_ACT_MAX __TCA_ACT_MAX
+#define TCA_OLD_COMPAT (TCA_ACT_MAX+1)
+#define TCA_ACT_MAX_PRIO 32
+#define TCA_ACT_BIND 1
+#define TCA_ACT_NOBIND 0
+#define TCA_ACT_UNBIND 1
+#define TCA_ACT_NOUNBIND 0
+#define TCA_ACT_REPLACE 1
+#define TCA_ACT_NOREPLACE 0
+
+#define TC_ACT_UNSPEC (-1)
+#define TC_ACT_OK 0
+#define TC_ACT_RECLASSIFY 1
+#define TC_ACT_SHOT 2
+#define TC_ACT_PIPE 3
+#define TC_ACT_STOLEN 4
+#define TC_ACT_QUEUED 5
+#define TC_ACT_REPEAT 6
+#define TC_ACT_REDIRECT 7
+#define TC_ACT_TRAP 8 /* For hw path, this means "trap to cpu"
+ * and don't further process the frame
+ * in hardware. For sw path, this is
+ * equivalent of TC_ACT_STOLEN - drop
+ * the skb and act like everything
+ * is alright.
+ */
+#define TC_ACT_VALUE_MAX TC_ACT_TRAP
+
+/* There is a special kind of actions called "extended actions",
+ * which need a value parameter. These have a local opcode located in
+ * the highest nibble, starting from 1. The rest of the bits
+ * are used to carry the value. These two parts together make
+ * a combined opcode.
+ */
+#define __TC_ACT_EXT_SHIFT 28
+#define __TC_ACT_EXT(local) ((local) << __TC_ACT_EXT_SHIFT)
+#define TC_ACT_EXT_VAL_MASK ((1 << __TC_ACT_EXT_SHIFT) - 1)
+#define TC_ACT_EXT_OPCODE(combined) ((combined) & (~TC_ACT_EXT_VAL_MASK))
+#define TC_ACT_EXT_CMP(combined, opcode) (TC_ACT_EXT_OPCODE(combined) == opcode)
+
+#define TC_ACT_JUMP __TC_ACT_EXT(1)
+#define TC_ACT_GOTO_CHAIN __TC_ACT_EXT(2)
+#define TC_ACT_EXT_OPCODE_MAX TC_ACT_GOTO_CHAIN
+
+/* These macros are put here for binary compatibility with userspace apps that
+ * make use of them. For kernel code and new userspace apps, use the TCA_ID_*
+ * versions.
+ */
+#define TCA_ACT_GACT 5
+#define TCA_ACT_IPT 6
+#define TCA_ACT_PEDIT 7
+#define TCA_ACT_MIRRED 8
+#define TCA_ACT_NAT 9
+#define TCA_ACT_XT 10
+#define TCA_ACT_SKBEDIT 11
+#define TCA_ACT_VLAN 12
+#define TCA_ACT_BPF 13
+#define TCA_ACT_CONNMARK 14
+#define TCA_ACT_SKBMOD 15
+#define TCA_ACT_CSUM 16
+#define TCA_ACT_TUNNEL_KEY 17
+#define TCA_ACT_SIMP 22
+#define TCA_ACT_IFE 25
+#define TCA_ACT_SAMPLE 26
+
+/* Action type identifiers*/
+enum tca_id {
+ TCA_ID_UNSPEC = 0,
+ TCA_ID_POLICE = 1,
+ TCA_ID_GACT = TCA_ACT_GACT,
+ TCA_ID_IPT = TCA_ACT_IPT,
+ TCA_ID_PEDIT = TCA_ACT_PEDIT,
+ TCA_ID_MIRRED = TCA_ACT_MIRRED,
+ TCA_ID_NAT = TCA_ACT_NAT,
+ TCA_ID_XT = TCA_ACT_XT,
+ TCA_ID_SKBEDIT = TCA_ACT_SKBEDIT,
+ TCA_ID_VLAN = TCA_ACT_VLAN,
+ TCA_ID_BPF = TCA_ACT_BPF,
+ TCA_ID_CONNMARK = TCA_ACT_CONNMARK,
+ TCA_ID_SKBMOD = TCA_ACT_SKBMOD,
+ TCA_ID_CSUM = TCA_ACT_CSUM,
+ TCA_ID_TUNNEL_KEY = TCA_ACT_TUNNEL_KEY,
+ TCA_ID_SIMP = TCA_ACT_SIMP,
+ TCA_ID_IFE = TCA_ACT_IFE,
+ TCA_ID_SAMPLE = TCA_ACT_SAMPLE,
+ TCA_ID_CTINFO,
+ TCA_ID_MPLS,
+ TCA_ID_CT,
+ TCA_ID_GATE,
+ /* other actions go here */
+ __TCA_ID_MAX = 255
+};
+
+#define TCA_ID_MAX __TCA_ID_MAX
+
+struct tc_police {
+ __u32 index;
+ int action;
+#define TC_POLICE_UNSPEC TC_ACT_UNSPEC
+#define TC_POLICE_OK TC_ACT_OK
+#define TC_POLICE_RECLASSIFY TC_ACT_RECLASSIFY
+#define TC_POLICE_SHOT TC_ACT_SHOT
+#define TC_POLICE_PIPE TC_ACT_PIPE
+
+ __u32 limit;
+ __u32 burst;
+ __u32 mtu;
+ struct tc_ratespec rate;
+ struct tc_ratespec peakrate;
+ int refcnt;
+ int bindcnt;
+ __u32 capab;
+};
+
+struct tcf_t {
+ __u64 install;
+ __u64 lastuse;
+ __u64 expires;
+ __u64 firstuse;
+};
+
+struct tc_cnt {
+ int refcnt;
+ int bindcnt;
+};
+
+#define tc_gen \
+ __u32 index; \
+ __u32 capab; \
+ int action; \
+ int refcnt; \
+ int bindcnt
+
+enum {
+ TCA_POLICE_UNSPEC,
+ TCA_POLICE_TBF,
+ TCA_POLICE_RATE,
+ TCA_POLICE_PEAKRATE,
+ TCA_POLICE_AVRATE,
+ TCA_POLICE_RESULT,
+ TCA_POLICE_TM,
+ TCA_POLICE_PAD,
+ TCA_POLICE_RATE64,
+ TCA_POLICE_PEAKRATE64,
+ __TCA_POLICE_MAX
+#define TCA_POLICE_RESULT TCA_POLICE_RESULT
+};
+
+#define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1)
+
+/* tca flags definitions */
+#define TCA_CLS_FLAGS_SKIP_HW (1 << 0) /* don't offload filter to HW */
+#define TCA_CLS_FLAGS_SKIP_SW (1 << 1) /* don't use filter in SW */
+#define TCA_CLS_FLAGS_IN_HW (1 << 2) /* filter is offloaded to HW */
+#define TCA_CLS_FLAGS_NOT_IN_HW (1 << 3) /* filter isn't offloaded to HW */
+#define TCA_CLS_FLAGS_VERBOSE (1 << 4) /* verbose logging */
+
+/* U32 filters */
+
+#define TC_U32_HTID(h) ((h)&0xFFF00000)
+#define TC_U32_USERHTID(h) (TC_U32_HTID(h)>>20)
+#define TC_U32_HASH(h) (((h)>>12)&0xFF)
+#define TC_U32_NODE(h) ((h)&0xFFF)
+#define TC_U32_KEY(h) ((h)&0xFFFFF)
+#define TC_U32_UNSPEC 0
+#define TC_U32_ROOT (0xFFF00000)
+
+enum {
+ TCA_U32_UNSPEC,
+ TCA_U32_CLASSID,
+ TCA_U32_HASH,
+ TCA_U32_LINK,
+ TCA_U32_DIVISOR,
+ TCA_U32_SEL,
+ TCA_U32_POLICE,
+ TCA_U32_ACT,
+ TCA_U32_INDEV,
+ TCA_U32_PCNT,
+ TCA_U32_MARK,
+ TCA_U32_FLAGS,
+ TCA_U32_PAD,
+ __TCA_U32_MAX
+};
+
+#define TCA_U32_MAX (__TCA_U32_MAX - 1)
+
+struct tc_u32_key {
+ __be32 mask;
+ __be32 val;
+ int off;
+ int offmask;
+};
+
+struct tc_u32_sel {
+ unsigned char flags;
+ unsigned char offshift;
+ unsigned char nkeys;
+
+ __be16 offmask;
+ __u16 off;
+ short offoff;
+
+ short hoff;
+ __be32 hmask;
+ struct tc_u32_key keys[0];
+};
+
+struct tc_u32_mark {
+ __u32 val;
+ __u32 mask;
+ __u32 success;
+};
+
+struct tc_u32_pcnt {
+ __u64 rcnt;
+ __u64 rhit;
+ __u64 kcnts[0];
+};
+
+/* Flags */
+
+#define TC_U32_TERMINAL 1
+#define TC_U32_OFFSET 2
+#define TC_U32_VAROFFSET 4
+#define TC_U32_EAT 8
+
+#define TC_U32_MAXDEPTH 8
+
+
+/* RSVP filter */
+
+enum {
+ TCA_RSVP_UNSPEC,
+ TCA_RSVP_CLASSID,
+ TCA_RSVP_DST,
+ TCA_RSVP_SRC,
+ TCA_RSVP_PINFO,
+ TCA_RSVP_POLICE,
+ TCA_RSVP_ACT,
+ __TCA_RSVP_MAX
+};
+
+#define TCA_RSVP_MAX (__TCA_RSVP_MAX - 1 )
+
+struct tc_rsvp_gpi {
+ __u32 key;
+ __u32 mask;
+ int offset;
+};
+
+struct tc_rsvp_pinfo {
+ struct tc_rsvp_gpi dpi;
+ struct tc_rsvp_gpi spi;
+ __u8 protocol;
+ __u8 tunnelid;
+ __u8 tunnelhdr;
+ __u8 pad;
+};
+
+/* ROUTE filter */
+
+enum {
+ TCA_ROUTE4_UNSPEC,
+ TCA_ROUTE4_CLASSID,
+ TCA_ROUTE4_TO,
+ TCA_ROUTE4_FROM,
+ TCA_ROUTE4_IIF,
+ TCA_ROUTE4_POLICE,
+ TCA_ROUTE4_ACT,
+ __TCA_ROUTE4_MAX
+};
+
+#define TCA_ROUTE4_MAX (__TCA_ROUTE4_MAX - 1)
+
+
+/* FW filter */
+
+enum {
+ TCA_FW_UNSPEC,
+ TCA_FW_CLASSID,
+ TCA_FW_POLICE,
+ TCA_FW_INDEV,
+ TCA_FW_ACT, /* used by CONFIG_NET_CLS_ACT */
+ TCA_FW_MASK,
+ __TCA_FW_MAX
+};
+
+#define TCA_FW_MAX (__TCA_FW_MAX - 1)
+
+/* TC index filter */
+
+enum {
+ TCA_TCINDEX_UNSPEC,
+ TCA_TCINDEX_HASH,
+ TCA_TCINDEX_MASK,
+ TCA_TCINDEX_SHIFT,
+ TCA_TCINDEX_FALL_THROUGH,
+ TCA_TCINDEX_CLASSID,
+ TCA_TCINDEX_POLICE,
+ TCA_TCINDEX_ACT,
+ __TCA_TCINDEX_MAX
+};
+
+#define TCA_TCINDEX_MAX (__TCA_TCINDEX_MAX - 1)
+
+/* Flow filter */
+
+enum {
+ FLOW_KEY_SRC,
+ FLOW_KEY_DST,
+ FLOW_KEY_PROTO,
+ FLOW_KEY_PROTO_SRC,
+ FLOW_KEY_PROTO_DST,
+ FLOW_KEY_IIF,
+ FLOW_KEY_PRIORITY,
+ FLOW_KEY_MARK,
+ FLOW_KEY_NFCT,
+ FLOW_KEY_NFCT_SRC,
+ FLOW_KEY_NFCT_DST,
+ FLOW_KEY_NFCT_PROTO_SRC,
+ FLOW_KEY_NFCT_PROTO_DST,
+ FLOW_KEY_RTCLASSID,
+ FLOW_KEY_SKUID,
+ FLOW_KEY_SKGID,
+ FLOW_KEY_VLAN_TAG,
+ FLOW_KEY_RXHASH,
+ __FLOW_KEY_MAX,
+};
+
+#define FLOW_KEY_MAX (__FLOW_KEY_MAX - 1)
+
+enum {
+ FLOW_MODE_MAP,
+ FLOW_MODE_HASH,
+};
+
+enum {
+ TCA_FLOW_UNSPEC,
+ TCA_FLOW_KEYS,
+ TCA_FLOW_MODE,
+ TCA_FLOW_BASECLASS,
+ TCA_FLOW_RSHIFT,
+ TCA_FLOW_ADDEND,
+ TCA_FLOW_MASK,
+ TCA_FLOW_XOR,
+ TCA_FLOW_DIVISOR,
+ TCA_FLOW_ACT,
+ TCA_FLOW_POLICE,
+ TCA_FLOW_EMATCHES,
+ TCA_FLOW_PERTURB,
+ __TCA_FLOW_MAX
+};
+
+#define TCA_FLOW_MAX (__TCA_FLOW_MAX - 1)
+
+/* Basic filter */
+
+struct tc_basic_pcnt {
+ __u64 rcnt;
+ __u64 rhit;
+};
+
+enum {
+ TCA_BASIC_UNSPEC,
+ TCA_BASIC_CLASSID,
+ TCA_BASIC_EMATCHES,
+ TCA_BASIC_ACT,
+ TCA_BASIC_POLICE,
+ TCA_BASIC_PCNT,
+ TCA_BASIC_PAD,
+ __TCA_BASIC_MAX
+};
+
+#define TCA_BASIC_MAX (__TCA_BASIC_MAX - 1)
+
+
+/* Cgroup classifier */
+
+enum {
+ TCA_CGROUP_UNSPEC,
+ TCA_CGROUP_ACT,
+ TCA_CGROUP_POLICE,
+ TCA_CGROUP_EMATCHES,
+ __TCA_CGROUP_MAX,
+};
+
+#define TCA_CGROUP_MAX (__TCA_CGROUP_MAX - 1)
+
+/* BPF classifier */
+
+#define TCA_BPF_FLAG_ACT_DIRECT (1 << 0)
+
+enum {
+ TCA_BPF_UNSPEC,
+ TCA_BPF_ACT,
+ TCA_BPF_POLICE,
+ TCA_BPF_CLASSID,
+ TCA_BPF_OPS_LEN,
+ TCA_BPF_OPS,
+ TCA_BPF_FD,
+ TCA_BPF_NAME,
+ TCA_BPF_FLAGS,
+ TCA_BPF_FLAGS_GEN,
+ TCA_BPF_TAG,
+ TCA_BPF_ID,
+ __TCA_BPF_MAX,
+};
+
+#define TCA_BPF_MAX (__TCA_BPF_MAX - 1)
+
+/* Flower classifier */
+
+enum {
+ TCA_FLOWER_UNSPEC,
+ TCA_FLOWER_CLASSID,
+ TCA_FLOWER_INDEV,
+ TCA_FLOWER_ACT,
+ TCA_FLOWER_KEY_ETH_DST, /* ETH_ALEN */
+ TCA_FLOWER_KEY_ETH_DST_MASK, /* ETH_ALEN */
+ TCA_FLOWER_KEY_ETH_SRC, /* ETH_ALEN */
+ TCA_FLOWER_KEY_ETH_SRC_MASK, /* ETH_ALEN */
+ TCA_FLOWER_KEY_ETH_TYPE, /* be16 */
+ TCA_FLOWER_KEY_IP_PROTO, /* u8 */
+ TCA_FLOWER_KEY_IPV4_SRC, /* be32 */
+ TCA_FLOWER_KEY_IPV4_SRC_MASK, /* be32 */
+ TCA_FLOWER_KEY_IPV4_DST, /* be32 */
+ TCA_FLOWER_KEY_IPV4_DST_MASK, /* be32 */
+ TCA_FLOWER_KEY_IPV6_SRC, /* struct in6_addr */
+ TCA_FLOWER_KEY_IPV6_SRC_MASK, /* struct in6_addr */
+ TCA_FLOWER_KEY_IPV6_DST, /* struct in6_addr */
+ TCA_FLOWER_KEY_IPV6_DST_MASK, /* struct in6_addr */
+ TCA_FLOWER_KEY_TCP_SRC, /* be16 */
+ TCA_FLOWER_KEY_TCP_DST, /* be16 */
+ TCA_FLOWER_KEY_UDP_SRC, /* be16 */
+ TCA_FLOWER_KEY_UDP_DST, /* be16 */
+
+ TCA_FLOWER_FLAGS,
+ TCA_FLOWER_KEY_VLAN_ID, /* be16 */
+ TCA_FLOWER_KEY_VLAN_PRIO, /* u8 */
+ TCA_FLOWER_KEY_VLAN_ETH_TYPE, /* be16 */
+
+ TCA_FLOWER_KEY_ENC_KEY_ID, /* be32 */
+ TCA_FLOWER_KEY_ENC_IPV4_SRC, /* be32 */
+ TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,/* be32 */
+ TCA_FLOWER_KEY_ENC_IPV4_DST, /* be32 */
+ TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,/* be32 */
+ TCA_FLOWER_KEY_ENC_IPV6_SRC, /* struct in6_addr */
+ TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,/* struct in6_addr */
+ TCA_FLOWER_KEY_ENC_IPV6_DST, /* struct in6_addr */
+ TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,/* struct in6_addr */
+
+ TCA_FLOWER_KEY_TCP_SRC_MASK, /* be16 */
+ TCA_FLOWER_KEY_TCP_DST_MASK, /* be16 */
+ TCA_FLOWER_KEY_UDP_SRC_MASK, /* be16 */
+ TCA_FLOWER_KEY_UDP_DST_MASK, /* be16 */
+ TCA_FLOWER_KEY_SCTP_SRC_MASK, /* be16 */
+ TCA_FLOWER_KEY_SCTP_DST_MASK, /* be16 */
+
+ TCA_FLOWER_KEY_SCTP_SRC, /* be16 */
+ TCA_FLOWER_KEY_SCTP_DST, /* be16 */
+
+ TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, /* be16 */
+ TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, /* be16 */
+ TCA_FLOWER_KEY_ENC_UDP_DST_PORT, /* be16 */
+ TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, /* be16 */
+
+ TCA_FLOWER_KEY_FLAGS, /* be32 */
+ TCA_FLOWER_KEY_FLAGS_MASK, /* be32 */
+
+ TCA_FLOWER_KEY_ICMPV4_CODE, /* u8 */
+ TCA_FLOWER_KEY_ICMPV4_CODE_MASK,/* u8 */
+ TCA_FLOWER_KEY_ICMPV4_TYPE, /* u8 */
+ TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,/* u8 */
+ TCA_FLOWER_KEY_ICMPV6_CODE, /* u8 */
+ TCA_FLOWER_KEY_ICMPV6_CODE_MASK,/* u8 */
+ TCA_FLOWER_KEY_ICMPV6_TYPE, /* u8 */
+ TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,/* u8 */
+
+ TCA_FLOWER_KEY_ARP_SIP, /* be32 */
+ TCA_FLOWER_KEY_ARP_SIP_MASK, /* be32 */
+ TCA_FLOWER_KEY_ARP_TIP, /* be32 */
+ TCA_FLOWER_KEY_ARP_TIP_MASK, /* be32 */
+ TCA_FLOWER_KEY_ARP_OP, /* u8 */
+ TCA_FLOWER_KEY_ARP_OP_MASK, /* u8 */
+ TCA_FLOWER_KEY_ARP_SHA, /* ETH_ALEN */
+ TCA_FLOWER_KEY_ARP_SHA_MASK, /* ETH_ALEN */
+ TCA_FLOWER_KEY_ARP_THA, /* ETH_ALEN */
+ TCA_FLOWER_KEY_ARP_THA_MASK, /* ETH_ALEN */
+
+ TCA_FLOWER_KEY_MPLS_TTL, /* u8 - 8 bits */
+ TCA_FLOWER_KEY_MPLS_BOS, /* u8 - 1 bit */
+ TCA_FLOWER_KEY_MPLS_TC, /* u8 - 3 bits */
+ TCA_FLOWER_KEY_MPLS_LABEL, /* be32 - 20 bits */
+
+ TCA_FLOWER_KEY_TCP_FLAGS, /* be16 */
+ TCA_FLOWER_KEY_TCP_FLAGS_MASK, /* be16 */
+
+ TCA_FLOWER_KEY_IP_TOS, /* u8 */
+ TCA_FLOWER_KEY_IP_TOS_MASK, /* u8 */
+ TCA_FLOWER_KEY_IP_TTL, /* u8 */
+ TCA_FLOWER_KEY_IP_TTL_MASK, /* u8 */
+
+ TCA_FLOWER_KEY_CVLAN_ID, /* be16 */
+ TCA_FLOWER_KEY_CVLAN_PRIO, /* u8 */
+ TCA_FLOWER_KEY_CVLAN_ETH_TYPE, /* be16 */
+
+ TCA_FLOWER_KEY_ENC_IP_TOS, /* u8 */
+ TCA_FLOWER_KEY_ENC_IP_TOS_MASK, /* u8 */
+ TCA_FLOWER_KEY_ENC_IP_TTL, /* u8 */
+ TCA_FLOWER_KEY_ENC_IP_TTL_MASK, /* u8 */
+
+ TCA_FLOWER_KEY_ENC_OPTS,
+ TCA_FLOWER_KEY_ENC_OPTS_MASK,
+
+ TCA_FLOWER_IN_HW_COUNT,
+
+ TCA_FLOWER_KEY_PORT_SRC_MIN, /* be16 */
+ TCA_FLOWER_KEY_PORT_SRC_MAX, /* be16 */
+ TCA_FLOWER_KEY_PORT_DST_MIN, /* be16 */
+ TCA_FLOWER_KEY_PORT_DST_MAX, /* be16 */
+
+ TCA_FLOWER_KEY_CT_STATE, /* u16 */
+ TCA_FLOWER_KEY_CT_STATE_MASK, /* u16 */
+ TCA_FLOWER_KEY_CT_ZONE, /* u16 */
+ TCA_FLOWER_KEY_CT_ZONE_MASK, /* u16 */
+ TCA_FLOWER_KEY_CT_MARK, /* u32 */
+ TCA_FLOWER_KEY_CT_MARK_MASK, /* u32 */
+ TCA_FLOWER_KEY_CT_LABELS, /* u128 */
+ TCA_FLOWER_KEY_CT_LABELS_MASK, /* u128 */
+
+ TCA_FLOWER_KEY_MPLS_OPTS,
+
+ TCA_FLOWER_KEY_HASH, /* u32 */
+ TCA_FLOWER_KEY_HASH_MASK, /* u32 */
+
+ __TCA_FLOWER_MAX,
+};
+
+#define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1)
+
+enum {
+ TCA_FLOWER_KEY_CT_FLAGS_NEW = 1 << 0, /* Beginning of a new connection. */
+ TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED = 1 << 1, /* Part of an existing connection. */
+ TCA_FLOWER_KEY_CT_FLAGS_RELATED = 1 << 2, /* Related to an established connection. */
+ TCA_FLOWER_KEY_CT_FLAGS_TRACKED = 1 << 3, /* Conntrack has occurred. */
+ TCA_FLOWER_KEY_CT_FLAGS_INVALID = 1 << 4, /* Conntrack is invalid. */
+ TCA_FLOWER_KEY_CT_FLAGS_REPLY = 1 << 5, /* Packet is in the reply direction. */
+ __TCA_FLOWER_KEY_CT_FLAGS_MAX,
+};
+
+enum {
+ TCA_FLOWER_KEY_ENC_OPTS_UNSPEC,
+ TCA_FLOWER_KEY_ENC_OPTS_GENEVE, /* Nested
+ * TCA_FLOWER_KEY_ENC_OPT_GENEVE_
+ * attributes
+ */
+ TCA_FLOWER_KEY_ENC_OPTS_VXLAN, /* Nested
+ * TCA_FLOWER_KEY_ENC_OPT_VXLAN_
+ * attributes
+ */
+ TCA_FLOWER_KEY_ENC_OPTS_ERSPAN, /* Nested
+ * TCA_FLOWER_KEY_ENC_OPT_ERSPAN_
+ * attributes
+ */
+ __TCA_FLOWER_KEY_ENC_OPTS_MAX,
+};
+
+#define TCA_FLOWER_KEY_ENC_OPTS_MAX (__TCA_FLOWER_KEY_ENC_OPTS_MAX - 1)
+
+enum {
+ TCA_FLOWER_KEY_ENC_OPT_GENEVE_UNSPEC,
+ TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS, /* u16 */
+ TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE, /* u8 */
+ TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA, /* 4 to 128 bytes */
+
+ __TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX,
+};
+
+#define TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX \
+ (__TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX - 1)
+
+enum {
+ TCA_FLOWER_KEY_ENC_OPT_VXLAN_UNSPEC,
+ TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP, /* u32 */
+ __TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX,
+};
+
+#define TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX \
+ (__TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX - 1)
+
+enum {
+ TCA_FLOWER_KEY_ENC_OPT_ERSPAN_UNSPEC,
+ TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER, /* u8 */
+ TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX, /* be32 */
+ TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR, /* u8 */
+ TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID, /* u8 */
+ __TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX,
+};
+
+#define TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX \
+ (__TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX - 1)
+
+enum {
+ TCA_FLOWER_KEY_MPLS_OPTS_UNSPEC,
+ TCA_FLOWER_KEY_MPLS_OPTS_LSE,
+ __TCA_FLOWER_KEY_MPLS_OPTS_MAX,
+};
+
+#define TCA_FLOWER_KEY_MPLS_OPTS_MAX (__TCA_FLOWER_KEY_MPLS_OPTS_MAX - 1)
+
+enum {
+ TCA_FLOWER_KEY_MPLS_OPT_LSE_UNSPEC,
+ TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH,
+ TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL,
+ TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS,
+ TCA_FLOWER_KEY_MPLS_OPT_LSE_TC,
+ TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL,
+ __TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX,
+};
+
+#define TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX \
+ (__TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX - 1)
+
+enum {
+ TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT = (1 << 0),
+ TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1),
+};
+
+#define TCA_FLOWER_MASK_FLAGS_RANGE (1 << 0) /* Range-based match */
+
+/* Match-all classifier */
+
+struct tc_matchall_pcnt {
+ __u64 rhit;
+};
+
+enum {
+ TCA_MATCHALL_UNSPEC,
+ TCA_MATCHALL_CLASSID,
+ TCA_MATCHALL_ACT,
+ TCA_MATCHALL_FLAGS,
+ TCA_MATCHALL_PCNT,
+ TCA_MATCHALL_PAD,
+ __TCA_MATCHALL_MAX,
+};
+
+#define TCA_MATCHALL_MAX (__TCA_MATCHALL_MAX - 1)
+
+/* Extended Matches */
+
+struct tcf_ematch_tree_hdr {
+ __u16 nmatches;
+ __u16 progid;
+};
+
+enum {
+ TCA_EMATCH_TREE_UNSPEC,
+ TCA_EMATCH_TREE_HDR,
+ TCA_EMATCH_TREE_LIST,
+ __TCA_EMATCH_TREE_MAX
+};
+#define TCA_EMATCH_TREE_MAX (__TCA_EMATCH_TREE_MAX - 1)
+
+struct tcf_ematch_hdr {
+ __u16 matchid;
+ __u16 kind;
+ __u16 flags;
+ __u16 pad; /* currently unused */
+};
+
+/* 0 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +-----------------------+-+-+---+
+ * | Unused |S|I| R |
+ * +-----------------------+-+-+---+
+ *
+ * R(2) ::= relation to next ematch
+ * where: 0 0 END (last ematch)
+ * 0 1 AND
+ * 1 0 OR
+ * 1 1 Unused (invalid)
+ * I(1) ::= invert result
+ * S(1) ::= simple payload
+ */
+#define TCF_EM_REL_END 0
+#define TCF_EM_REL_AND (1<<0)
+#define TCF_EM_REL_OR (1<<1)
+#define TCF_EM_INVERT (1<<2)
+#define TCF_EM_SIMPLE (1<<3)
+
+#define TCF_EM_REL_MASK 3
+#define TCF_EM_REL_VALID(v) (((v) & TCF_EM_REL_MASK) != TCF_EM_REL_MASK)
+
+enum {
+ TCF_LAYER_LINK,
+ TCF_LAYER_NETWORK,
+ TCF_LAYER_TRANSPORT,
+ __TCF_LAYER_MAX
+};
+#define TCF_LAYER_MAX (__TCF_LAYER_MAX - 1)
+
+/* Ematch type assignments
+ * 1..32767 Reserved for ematches inside kernel tree
+ * 32768..65535 Free to use, not reliable
+ */
+#define TCF_EM_CONTAINER 0
+#define TCF_EM_CMP 1
+#define TCF_EM_NBYTE 2
+#define TCF_EM_U32 3
+#define TCF_EM_META 4
+#define TCF_EM_TEXT 5
+#define TCF_EM_VLAN 6
+#define TCF_EM_CANID 7
+#define TCF_EM_IPSET 8
+#define TCF_EM_IPT 9
+#define TCF_EM_MAX 9
+
+enum {
+ TCF_EM_PROG_TC
+};
+
+enum {
+ TCF_EM_OPND_EQ,
+ TCF_EM_OPND_GT,
+ TCF_EM_OPND_LT
+};
+
+#endif
void fabricd_finish(struct fabricd *f)
{
- thread_cancel(&(f->initial_sync_timeout));
+ THREAD_OFF(f->initial_sync_timeout);
- thread_cancel(&(f->tier_calculation_timer));
+ THREAD_OFF(f->tier_calculation_timer);
- thread_cancel(&(f->tier_set_timer));
+ THREAD_OFF(f->tier_set_timer);
isis_spftree_del(f->spftree);
neighbor_lists_clear(f);
f->initial_sync_circuit->interface->name);
f->initial_sync_state = FABRICD_SYNC_COMPLETE;
f->initial_sync_circuit = NULL;
- thread_cancel(&(f->initial_sync_timeout));
+ THREAD_OFF(f->initial_sync_timeout);
}
static void fabricd_bump_tier_calculation_timer(struct fabricd *f);
{
/* Cancel timer if we already know our tier */
if (f->tier != ISIS_TIER_UNDEFINED || f->tier_set_timer) {
- thread_cancel(&(f->tier_calculation_timer));
+ THREAD_OFF(f->tier_calculation_timer);
return;
}
/* If we need to calculate the tier, wait some
* time for the topology to settle before running
* the calculation */
- thread_cancel(&(f->tier_calculation_timer));
+ THREAD_OFF(f->tier_calculation_timer);
thread_add_timer(master, fabricd_tier_calculation_cb, f,
2 * f->area->lsp_gen_interval[ISIS_LEVEL2 - 1],
if (!circuit->t_send_csnp[1])
continue;
- thread_cancel(&(circuit->t_send_csnp[ISIS_LEVEL2 - 1]));
+ THREAD_OFF(circuit->t_send_csnp[ISIS_LEVEL2 - 1]);
thread_add_timer_msec(master, send_l2_csnp, circuit,
isis_jitter(f->csnp_delay, CSNP_JITTER),
&circuit->t_send_csnp[ISIS_LEVEL2 - 1]);
/* Remove self from snmp list without walking the list*/
list_delete_node(adj->circuit->snmp_adj_list, adj->snmp_list_node);
- thread_cancel(&adj->t_expire);
+ THREAD_OFF(adj->t_expire);
if (adj->adj_state != ISIS_ADJ_DOWN)
adj->adj_state = ISIS_ADJ_DOWN;
XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses);
XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses);
XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ll_ipv6_addrs);
-
+ XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->global_ipv6_addrs);
adj_mt_finish(adj);
list_delete(&adj->adj_sids);
memset(circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1);
memset(circuit->u.bc.snpa, 0, ETH_ALEN);
- thread_cancel(&circuit->u.bc.t_send_lan_hello[0]);
- thread_cancel(&circuit->u.bc.t_send_lan_hello[1]);
- thread_cancel(&circuit->u.bc.t_run_dr[0]);
- thread_cancel(&circuit->u.bc.t_run_dr[1]);
- thread_cancel(&circuit->u.bc.t_refresh_pseudo_lsp[0]);
- thread_cancel(&circuit->u.bc.t_refresh_pseudo_lsp[1]);
+ THREAD_OFF(circuit->u.bc.t_send_lan_hello[0]);
+ THREAD_OFF(circuit->u.bc.t_send_lan_hello[1]);
+ THREAD_OFF(circuit->u.bc.t_run_dr[0]);
+ THREAD_OFF(circuit->u.bc.t_run_dr[1]);
+ THREAD_OFF(circuit->u.bc.t_refresh_pseudo_lsp[0]);
+ THREAD_OFF(circuit->u.bc.t_refresh_pseudo_lsp[1]);
circuit->lsp_regenerate_pending[0] = 0;
circuit->lsp_regenerate_pending[1] = 0;
} else if (circuit->circ_type == CIRCUIT_T_P2P) {
isis_delete_adj(circuit->u.p2p.neighbor);
circuit->u.p2p.neighbor = NULL;
- thread_cancel(&circuit->u.p2p.t_send_p2p_hello);
+ THREAD_OFF(circuit->u.p2p.t_send_p2p_hello);
}
/*
circuit->snmp_adj_idx_gen = 0;
/* Cancel all active threads */
- thread_cancel(&circuit->t_send_csnp[0]);
- thread_cancel(&circuit->t_send_csnp[1]);
- thread_cancel(&circuit->t_send_psnp[0]);
- thread_cancel(&circuit->t_send_psnp[1]);
- thread_cancel(&circuit->t_read);
+ THREAD_OFF(circuit->t_send_csnp[0]);
+ THREAD_OFF(circuit->t_send_csnp[1]);
+ THREAD_OFF(circuit->t_send_psnp[0]);
+ THREAD_OFF(circuit->t_send_psnp[1]);
+ THREAD_OFF(circuit->t_read);
if (circuit->tx_queue) {
isis_tx_queue_free(circuit->tx_queue);
if (strmatch(lh_behavior, "no-php-flag"))
value = "no-php";
- else
+ else if (strmatch(lh_behavior, "explicit-null"))
value = "explicit-null";
+ else
+ value = "php";
nb_cli_enqueue_change(vty, "./last-hop-behavior", NB_OP_MODIFY,
value);
circuit->u.bc.is_dr[level - 1] = 0;
circuit->u.bc.run_dr_elect[level - 1] = 0;
- thread_cancel(&circuit->u.bc.t_run_dr[level - 1]);
- thread_cancel(&circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
+ THREAD_OFF(circuit->u.bc.t_run_dr[level - 1]);
+ THREAD_OFF(circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
circuit->lsp_regenerate_pending[level - 1] = 0;
memcpy(id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
&circuit->t_send_psnp[1]);
}
- thread_cancel(&circuit->t_send_csnp[level - 1]);
+ THREAD_OFF(circuit->t_send_csnp[level - 1]);
thread_add_timer(master, isis_run_dr,
&circuit->level_arg[level - 1],
circuit->circuit_id;
assert(circuit->circuit_id); /* must be non-zero */
- /* if (circuit->t_send_l1_psnp)
- thread_cancel (circuit->t_send_l1_psnp); */
lsp_generate_pseudo(circuit, 1);
thread_add_timer(master, send_l1_csnp, circuit,
circuit->circuit_id;
assert(circuit->circuit_id); /* must be non-zero */
- /* if (circuit->t_send_l1_psnp)
- thread_cancel (circuit->t_send_l1_psnp); */
lsp_generate_pseudo(circuit, 2);
thread_add_timer(master, send_l2_csnp, circuit,
struct listnode *node, *nnode;
struct isis_dynhn *dyn;
- thread_cancel(&isis->t_dync_clean);
+ THREAD_OFF(isis->t_dync_clean);
for (ALL_LIST_ELEMENTS(isis->dyn_cache, node, nnode, dyn)) {
list_delete_node(isis->dyn_cache, node);
circuit->area->area_tag, circuit->circuit_id,
circuit->interface->name, level);
- thread_cancel(&circuit->t_send_csnp[idx]);
- thread_cancel(&circuit->t_send_psnp[idx]);
+ THREAD_OFF(circuit->t_send_csnp[idx]);
+ THREAD_OFF(circuit->t_send_psnp[idx]);
if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
- thread_cancel(&circuit->u.bc.t_send_lan_hello[idx]);
- thread_cancel(&circuit->u.bc.t_run_dr[idx]);
- thread_cancel(&circuit->u.bc.t_refresh_pseudo_lsp[idx]);
+ THREAD_OFF(circuit->u.bc.t_send_lan_hello[idx]);
+ THREAD_OFF(circuit->u.bc.t_run_dr[idx]);
+ THREAD_OFF(circuit->u.bc.t_refresh_pseudo_lsp[idx]);
circuit->lsp_regenerate_pending[idx] = 0;
circuit->u.bc.run_dr_elect[idx] = 0;
circuit->u.bc.is_dr[idx] = 0;
spftree->route_table_backup);
spftree->lfa.protection_counters.rlfa[vertex->N.ip.priority] += 1;
- thread_cancel(&area->t_rlfa_rib_update);
+ THREAD_OFF(area->t_rlfa_rib_update);
thread_add_timer(master, isis_area_verify_routes_cb, area, 2,
&area->t_rlfa_rib_update);
isis_route_delete(area, rn, spftree->route_table_backup);
spftree->lfa.protection_counters.rlfa[vertex->N.ip.priority] -= 1;
- thread_cancel(&area->t_rlfa_rib_update);
+ THREAD_OFF(area->t_rlfa_rib_update);
thread_add_timer(master, isis_area_verify_routes_cb, area, 2,
&area->t_rlfa_rib_update);
}
refresh_time = lsp_refresh_time(newlsp, rem_lifetime);
- thread_cancel(&area->t_lsp_refresh[level - 1]);
+ THREAD_OFF(area->t_lsp_refresh[level - 1]);
area->lsp_regenerate_pending[level - 1] = 0;
thread_add_timer(master, lsp_refresh,
&area->lsp_refresh_arg[level - 1], refresh_time,
"ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
area->area_tag, (long long)lsp->last_generated,
(long long)now);
- thread_cancel(&area->t_lsp_refresh[lvl - 1]);
+ THREAD_OFF(area->t_lsp_refresh[lvl - 1]);
diff = now - lsp->last_generated;
if (diff < area->lsp_gen_interval[lvl - 1]
&& !(area->bfd_signalled_down)) {
lsp_flood(lsp, NULL);
refresh_time = lsp_refresh_time(lsp, rem_lifetime);
- thread_cancel(&circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
+ THREAD_OFF(circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
circuit->lsp_regenerate_pending[level - 1] = 0;
if (level == IS_LEVEL_1)
thread_add_timer(
"ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
area->area_tag, (long long)lsp->last_generated,
(long long)now);
- thread_cancel(&circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
+ THREAD_OFF(circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
diff = now - lsp->last_generated;
if (diff < circuit->area->lsp_gen_interval[lvl - 1]) {
timeout =
adj);
/* lets take care of the expiry */
- thread_cancel(&adj->t_expire);
+ THREAD_OFF(adj->t_expire);
thread_add_timer(master, isis_adj_expire, adj, (long)adj->hold_time,
&adj->t_expire);
adj);
/* lets take care of the expiry */
- thread_cancel(&adj->t_expire);
+ THREAD_OFF(adj->t_expire);
thread_add_timer(master, isis_adj_expire, adj, (long)adj->hold_time,
&adj->t_expire);
if (thread_timer_remain_msec(*threadp) < (unsigned long)delay)
return;
- thread_cancel(threadp);
+ THREAD_OFF(*threadp);
}
thread_add_timer_msec(master, send_hello_cb,
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;
}
}
}
-}
-
-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);
}
}
area->area_tag, level, diff, func, file, line);
}
- thread_cancel(&area->t_rlfa_rib_update);
+ THREAD_OFF(area->t_rlfa_rib_update);
if (area->spf_delay_ietf[level - 1]) {
/* Need to call schedule function also if spf delay is running
* to
area->area_tag);
/* Disable any re-attempt to connect to Label Manager */
- thread_cancel(&srdb->t_start_lm);
+ THREAD_OFF(srdb->t_start_lm);
/* Uninstall all local Adjacency-SIDs. */
for (ALL_LIST_ELEMENTS(area->srdb.adj_sids, node, nnode, sra))
}
static int unpack_tlv_router_cap(enum isis_tlv_context context,
- uint8_t tlv_type, uint8_t tlv_len,
- struct stream *s, struct sbuf *log,
- void *dest, int indent)
+ uint8_t tlv_type, uint8_t tlv_len,
+ struct stream *s, struct sbuf *log, void *dest,
+ int indent)
{
struct isis_tlvs *tlvs = dest;
struct isis_router_cap *rcap;
log, indent,
"WARNING: Router Capability subTLV length too large compared to expected size\n");
stream_forward_getp(s, STREAM_READABLE(s));
-
+ XFREE(MTYPE_ISIS_TLV, rcap);
return 0;
}
{
struct isis_tx_queue_entry *e = element;
- thread_cancel(&(e->retry));
+ THREAD_OFF(e->retry);
XFREE(MTYPE_TX_QUEUE_ENTRY, e);
}
e->type = type;
- thread_cancel(&(e->retry));
+ THREAD_OFF(e->retry);
thread_add_event(master, tx_queue_send_event, e, 0, &e->retry);
e->is_retry = false;
func, file, line);
}
- thread_cancel(&(e->retry));
+ THREAD_OFF(e->retry);
hash_release(queue->hash, e);
XFREE(MTYPE_TX_QUEUE_ENTRY, e);
if (area->spf_timer[0])
isis_spf_timer_free(THREAD_ARG(area->spf_timer[0]));
- thread_cancel(&area->spf_timer[0]);
+ THREAD_OFF(area->spf_timer[0]);
if (area->spf_timer[1])
isis_spf_timer_free(THREAD_ARG(area->spf_timer[1]));
- thread_cancel(&area->spf_timer[1]);
+ THREAD_OFF(area->spf_timer[1]);
spf_backoff_free(area->spf_delay_ietf[0]);
spf_backoff_free(area->spf_delay_ietf[1]);
isis_lfa_tiebreakers_clear(area, ISIS_LEVEL1);
isis_lfa_tiebreakers_clear(area, ISIS_LEVEL2);
- thread_cancel(&area->t_tick);
- thread_cancel(&area->t_lsp_refresh[0]);
- thread_cancel(&area->t_lsp_refresh[1]);
- thread_cancel(&area->t_rlfa_rib_update);
+ THREAD_OFF(area->t_tick);
+ THREAD_OFF(area->t_lsp_refresh[0]);
+ THREAD_OFF(area->t_lsp_refresh[1]);
+ THREAD_OFF(area->t_rlfa_rib_update);
thread_cancel_event(master, area);
if (area->spf_timer[level - 1])
isis_spf_timer_free(THREAD_ARG(area->spf_timer[level - 1]));
- thread_cancel(&area->spf_timer[level - 1]);
+ THREAD_OFF(area->spf_timer[level - 1]);
sched_debug(
"ISIS (%s): Resigned from L%d - canceling LSP regeneration timer.",
area->area_tag, level);
- thread_cancel(&area->t_lsp_refresh[level - 1]);
+ THREAD_OFF(area->t_lsp_refresh[level - 1]);
area->lsp_regenerate_pending[level - 1] = 0;
}
LIST_FOREACH(av, &accept_queue.queue, entry)
if (av->fd == fd) {
log_debug("%s: %d removed from queue", __func__, fd);
- thread_cancel(&av->ev);
+ THREAD_OFF(av->ev);
LIST_REMOVE(av, entry);
free(av);
return;
{
if (accept_queue.evt != NULL) {
log_debug(__func__);
- thread_cancel(&accept_queue.evt);
+ THREAD_OFF(accept_queue.evt);
accept_arm();
}
}
{
struct accept_ev *av;
LIST_FOREACH(av, &accept_queue.queue, entry)
- thread_cancel(&av->ev);
+ THREAD_OFF(av->ev);
}
static void accept_cb(struct thread *thread)
void
adj_start_itimer(struct adj *adj)
{
- thread_cancel(&adj->inactivity_timer);
+ THREAD_OFF(adj->inactivity_timer);
adj->inactivity_timer = NULL;
thread_add_timer(master, adj_itimer, adj, adj->holdtime,
&adj->inactivity_timer);
void
adj_stop_itimer(struct adj *adj)
{
- thread_cancel(&adj->inactivity_timer);
+ THREAD_OFF(adj->inactivity_timer);
}
/* targeted neighbors */
static void
tnbr_start_hello_timer(struct tnbr *tnbr)
{
- thread_cancel(&tnbr->hello_timer);
+ THREAD_OFF(tnbr->hello_timer);
tnbr->hello_timer = NULL;
thread_add_timer(master, tnbr_hello_timer, tnbr, tnbr_get_hello_interval(tnbr),
&tnbr->hello_timer);
static void
tnbr_stop_hello_timer(struct tnbr *tnbr)
{
- thread_cancel(&tnbr->hello_timer);
+ THREAD_OFF(tnbr->hello_timer);
}
struct ctl_adj *
}
actl.holdtime = adj->holdtime;
actl.holdtime_remaining =
- thread_timer_remain_second(adj->inactivity_timer);
+ thread_timer_remain_second(adj->inactivity_timer);
actl.trans_addr = adj->trans_addr;
actl.ds_tlv = adj->ds_tlv;
msgbuf_clear(&c->iev.ibuf.w);
TAILQ_REMOVE(&ctl_conns, c, entry);
- thread_cancel(&c->iev.ev_read);
- thread_cancel(&c->iev.ev_write);
+ THREAD_OFF(c->iev.ev_read);
+ THREAD_OFF(c->iev.ev_write);
close(c->iev.ibuf.fd);
accept_unpause();
free(c);
static void
if_start_hello_timer(struct iface_af *ia)
{
- thread_cancel(&ia->hello_timer);
+ THREAD_OFF(ia->hello_timer);
thread_add_timer(master, if_hello_timer, ia, if_get_hello_interval(ia),
&ia->hello_timer);
}
static void
if_stop_hello_timer(struct iface_af *ia)
{
- thread_cancel(&ia->hello_timer);
+ THREAD_OFF(ia->hello_timer);
}
struct ctl_iface *
ictl.wait_time = if_get_wait_for_sync_interval();
ictl.timer_running = iface->ldp_sync.wait_for_sync_timer ? true : false;
- if (iface->ldp_sync.wait_for_sync_timer)
- ictl.wait_time_remaining =
+ ictl.wait_time_remaining =
thread_timer_remain_second(iface->ldp_sync.wait_for_sync_timer);
- else
- ictl.wait_time_remaining = 0;
memset(&ictl.peer_ldp_id, 0, sizeof(ictl.peer_ldp_id));
imsg_event_add(iev);
else {
/* this pipe is dead, so remove the event handlers and exit */
- thread_cancel(&iev->ev_read);
- thread_cancel(&iev->ev_write);
+ THREAD_OFF(iev->ev_read);
+ THREAD_OFF(iev->ev_write);
lde_shutdown();
}
}
imsg_event_add(iev);
else {
/* this pipe is dead, so remove the event handlers and exit */
- thread_cancel(&iev->ev_read);
- thread_cancel(&iev->ev_write);
+ THREAD_OFF(iev->ev_read);
+ THREAD_OFF(iev->ev_write);
lde_shutdown();
}
}
void
lde_gc_start_timer(void)
{
- thread_cancel(&gc_timer);
+ THREAD_OFF(gc_timer);
thread_add_timer(master, lde_gc_timer, NULL, LDE_GC_INTERVAL,
&gc_timer);
}
void
lde_gc_stop_timer(void)
{
- thread_cancel(&gc_timer);
+ THREAD_OFF(gc_timer);
}
imsg_event_add(iev);
else {
/* this pipe is dead, so remove the event handlers and exit */
- thread_cancel(&iev->ev_read);
- thread_cancel(&iev->ev_write);
+ THREAD_OFF(iev->ev_read);
+ THREAD_OFF(iev->ev_write);
ldpe_pid = 0;
if (lde_pid == 0)
ldpd_shutdown();
imsg_event_add(iev);
else {
/* this pipe is dead, so remove the event handlers and exit */
- thread_cancel(&iev->ev_read);
- thread_cancel(&iev->ev_write);
+ THREAD_OFF(iev->ev_read);
+ THREAD_OFF(iev->ev_write);
lde_pid = 0;
if (ldpe_pid == 0)
ldpd_shutdown();
fatal("msgbuf_write");
if (n == 0) {
/* this pipe is dead, so remove the event handlers */
- thread_cancel(&iev->ev_read);
- thread_cancel(&iev->ev_write);
+ THREAD_OFF(iev->ev_read);
+ THREAD_OFF(iev->ev_write);
return;
}
void
evbuf_clear(struct evbuf *eb)
{
- thread_cancel(&eb->ev);
+ THREAD_OFF(eb->ev);
msgbuf_clear(&eb->wbuf);
eb->wbuf.fd = -1;
}
#ifdef __OpenBSD__
if (sysdep.no_pfkey == 0) {
- thread_cancel(&pfkey_ev);
+ THREAD_OFF(pfkey_ev);
close(global.pfkeysock);
}
#endif
imsg_event_add(iev);
else {
/* this pipe is dead, so remove the event handlers and exit */
- thread_cancel(&iev->ev_read);
- thread_cancel(&iev->ev_write);
+ THREAD_OFF(iev->ev_read);
+ THREAD_OFF(iev->ev_write);
ldpe_shutdown();
}
}
imsg_event_add(iev);
else {
/* this pipe is dead, so remove the event handlers and exit */
- thread_cancel(&iev->ev_read);
- thread_cancel(&iev->ev_write);
+ THREAD_OFF(iev->ev_read);
+ THREAD_OFF(iev->ev_write);
ldpe_shutdown();
}
}
af_global = ldp_af_global_get(&global, af);
/* discovery socket */
- thread_cancel(&af_global->disc_ev);
+ THREAD_OFF(af_global->disc_ev);
if (af_global->ldp_disc_socket != -1) {
close(af_global->ldp_disc_socket);
af_global->ldp_disc_socket = -1;
}
/* extended discovery socket */
- thread_cancel(&af_global->edisc_ev);
+ THREAD_OFF(af_global->edisc_ev);
if (af_global->ldp_edisc_socket != -1) {
close(af_global->ldp_edisc_socket);
af_global->ldp_edisc_socket = -1;
nbr->auth.method = AUTH_NONE;
if (nbr_pending_connect(nbr))
- thread_cancel(&nbr->ev_connect);
+ THREAD_OFF(nbr->ev_connect);
nbr_stop_ktimer(nbr);
nbr_stop_ktimeout(nbr);
nbr_stop_itimeout(nbr);
/* send three keepalives per period */
secs = nbr->keepalive / KEEPALIVE_PER_PERIOD;
- thread_cancel(&nbr->keepalive_timer);
+ THREAD_OFF(nbr->keepalive_timer);
nbr->keepalive_timer = NULL;
thread_add_timer(master, nbr_ktimer, nbr, secs, &nbr->keepalive_timer);
}
void
nbr_stop_ktimer(struct nbr *nbr)
{
- thread_cancel(&nbr->keepalive_timer);
+ THREAD_OFF(nbr->keepalive_timer);
}
/* Keepalive timeout: if the nbr hasn't sent keepalive */
static void
nbr_start_ktimeout(struct nbr *nbr)
{
- thread_cancel(&nbr->keepalive_timeout);
+ THREAD_OFF(nbr->keepalive_timeout);
nbr->keepalive_timeout = NULL;
thread_add_timer(master, nbr_ktimeout, nbr, nbr->keepalive,
&nbr->keepalive_timeout);
void
nbr_stop_ktimeout(struct nbr *nbr)
{
- thread_cancel(&nbr->keepalive_timeout);
+ THREAD_OFF(nbr->keepalive_timeout);
}
/* Session initialization timeout: if nbr got stuck in the initialization FSM */
int secs;
secs = INIT_FSM_TIMEOUT;
- thread_cancel(&nbr->init_timeout);
+ THREAD_OFF(nbr->init_timeout);
nbr->init_timeout = NULL;
thread_add_timer(master, nbr_itimeout, nbr, secs, &nbr->init_timeout);
}
void
nbr_stop_itimeout(struct nbr *nbr)
{
- thread_cancel(&nbr->init_timeout);
+ THREAD_OFF(nbr->init_timeout);
}
/* Init delay timer: timer to retry to iniziatize session */
break;
}
- thread_cancel(&nbr->initdelay_timer);
+ THREAD_OFF(nbr->initdelay_timer);
nbr->initdelay_timer = NULL;
thread_add_timer(master, nbr_idtimer, nbr, secs,
&nbr->initdelay_timer);
void
nbr_stop_idtimer(struct nbr *nbr)
{
- thread_cancel(&nbr->initdelay_timer);
+ THREAD_OFF(nbr->initdelay_timer);
}
int
nctl.stats = nbr->stats;
nctl.flags = nbr->flags;
nctl.max_pdu_len = nbr->max_pdu_len;
- if (nbr->keepalive_timer)
- nctl.hold_time_remaining =
- thread_timer_remain_second(nbr->keepalive_timer);
- else
- nctl.hold_time_remaining = 0;
+ nctl.hold_time_remaining =
+ thread_timer_remain_second(nbr->keepalive_timer);
gettimeofday(&now, NULL);
if (nbr->state == NBR_STA_OPER) {
switch (nbr->state) {
case NBR_STA_PRESENT:
if (nbr_pending_connect(nbr))
- thread_cancel(&nbr->ev_connect);
+ THREAD_OFF(nbr->ev_connect);
break;
case NBR_STA_INITIAL:
case NBR_STA_OPENREC:
evbuf_clear(&tcp->wbuf);
if (tcp->nbr) {
- thread_cancel(&tcp->rev);
+ THREAD_OFF(tcp->rev);
free(tcp->rbuf);
tcp->nbr->tcp = NULL;
}
void
pending_conn_del(struct pending_conn *pconn)
{
- thread_cancel(&pconn->ev_timeout);
+ THREAD_OFF(pconn->ev_timeout);
TAILQ_REMOVE(&global.pending_conns, pconn, entry);
free(pconn);
}
snmp_select_info(&maxfd, &fds, &timeout, &block);
if (!block) {
- timeout_thr = NULL;
thread_add_timer_tv(agentx_tm, agentx_timeout, NULL, &timeout,
&timeout_thr);
}
else if (FD_ISSET(fd, &fds)) {
struct listnode *newln;
thr = XCALLOC(MTYPE_TMP, sizeof(struct thread *));
- thread_add_read(agentx_tm, agentx_read, NULL, fd, thr);
+
newln = listnode_add_before(events, ln, thr);
- (*thr)->arg = newln;
+ thread_add_read(agentx_tm, agentx_read, newln, fd, thr);
}
}
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. */
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
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;
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);
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();
/* 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. */
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);
{
uint32_t i = 0;
- frr_with_mutex(&refs_mtx) {
+ frr_with_mutex (&refs_mtx) {
while (ref[i].code != END_FERR) {
(void)hash_get(refs, &ref[i], hash_alloc_intern);
i++;
struct log_ref *ref;
holder.code = code;
- frr_with_mutex(&refs_mtx) {
+ frr_with_mutex (&refs_mtx) {
ref = hash_lookup(refs, &holder);
}
if (json)
top = json_object_new_object();
- frr_with_mutex(&refs_mtx) {
+ frr_with_mutex (&refs_mtx) {
errlist = code ? list_new() : hash_to_list(refs);
}
void log_ref_init(void)
{
- frr_with_mutex(&refs_mtx) {
+ frr_with_mutex (&refs_mtx) {
refs = hash_create(ferr_hash_key, ferr_hash_cmp,
"Error Reference Texts");
}
void log_ref_fini(void)
{
- frr_with_mutex(&refs_mtx) {
+ frr_with_mutex (&refs_mtx) {
hash_clean(refs, NULL);
hash_free(refs);
refs = NULL;
static int _plist_is_dup(const struct lyd_node *dnode, void *arg)
{
struct plist_dup_args *pda = arg;
- struct prefix p;
+ struct prefix p = {};
int ge, le;
bool any;
void frr_pthread_init(void)
{
- frr_with_mutex(&frr_pthread_list_mtx) {
+ frr_with_mutex (&frr_pthread_list_mtx) {
frr_pthread_list = list_new();
}
}
{
frr_pthread_stop_all();
- frr_with_mutex(&frr_pthread_list_mtx) {
+ frr_with_mutex (&frr_pthread_list_mtx) {
struct listnode *n, *nn;
struct frr_pthread *fpt;
pthread_mutex_init(fpt->running_cond_mtx, NULL);
pthread_cond_init(fpt->running_cond, NULL);
- frr_with_mutex(&frr_pthread_list_mtx) {
+ frr_with_mutex (&frr_pthread_list_mtx) {
listnode_add(frr_pthread_list, fpt);
}
void frr_pthread_destroy(struct frr_pthread *fpt)
{
- frr_with_mutex(&frr_pthread_list_mtx) {
+ frr_with_mutex (&frr_pthread_list_mtx) {
listnode_delete(frr_pthread_list, fpt);
}
void frr_pthread_wait_running(struct frr_pthread *fpt)
{
- frr_with_mutex(fpt->running_cond_mtx) {
+ frr_with_mutex (fpt->running_cond_mtx) {
while (!fpt->running)
pthread_cond_wait(fpt->running_cond,
fpt->running_cond_mtx);
void frr_pthread_notify_running(struct frr_pthread *fpt)
{
- frr_with_mutex(fpt->running_cond_mtx) {
+ frr_with_mutex (fpt->running_cond_mtx) {
fpt->running = true;
pthread_cond_signal(fpt->running_cond);
}
void frr_pthread_stop_all(void)
{
- frr_with_mutex(&frr_pthread_list_mtx) {
+ frr_with_mutex (&frr_pthread_list_mtx) {
struct listnode *n;
struct frr_pthread *fpt;
for (ALL_LIST_ELEMENTS_RO(frr_pthread_list, n, fpt)) {
hash->name = name ? XSTRDUP(MTYPE_HASH, name) : NULL;
hash->stats.empty = hash->size;
- frr_with_mutex(&_hashes_mtx) {
+ frr_with_mutex (&_hashes_mtx) {
if (!_hashes)
_hashes = list_new();
void hash_free(struct hash *hash)
{
- frr_with_mutex(&_hashes_mtx) {
+ frr_with_mutex (&_hashes_mtx) {
if (_hashes) {
listnode_delete(_hashes, hash);
if (_hashes->count == 0) {
/* Read LS Message header */
STREAM_GETC(s, msg->event);
STREAM_GETC(s, msg->type);
- STREAM_GET(&msg->remote_id, s, sizeof(struct ls_node_id));
/* Read Message Payload */
switch (msg->type) {
msg->data.node = ls_parse_node(s);
break;
case LS_MSG_TYPE_ATTRIBUTES:
+ STREAM_GET(&msg->remote_id, s, sizeof(struct ls_node_id));
msg->data.attr = ls_parse_attributes(s);
break;
case LS_MSG_TYPE_PREFIX:
/* Prepare Link State header */
stream_putc(s, msg->event);
stream_putc(s, msg->type);
- stream_put(s, &msg->remote_id, sizeof(struct ls_node_id));
/* Add Message Payload */
switch (msg->type) {
case LS_MSG_TYPE_NODE:
return ls_format_node(s, msg->data.node);
case LS_MSG_TYPE_ATTRIBUTES:
+ /* Add remote node first */
+ stream_put(s, &msg->remote_id, sizeof(struct ls_node_id));
return ls_format_attributes(s, msg->data.attr);
case LS_MSG_TYPE_PREFIX:
return ls_format_prefix(s, msg->data.prefix);
return zclient_send_message(zclient);
}
-
struct ls_message *ls_vertex2msg(struct ls_message *msg,
struct ls_vertex *vertex)
{
case LS_MSG_EVENT_DELETE:
edge = ls_find_edge_by_source(ted, attr);
if (edge) {
- if (delete)
+ if (delete) {
ls_edge_del_all(ted, edge);
- else
+ edge = NULL;
+ } else
edge->status = DELETE;
}
break;
uint8_t level; /* ISIS Level */
uint8_t padding;
} iso;
- } id __attribute__((aligned(8)));
+ } id;
};
/**
void zlog_filter_clear(void)
{
- frr_with_mutex(&logfilterlock) {
+ frr_with_mutex (&logfilterlock) {
zlog_filter_count = 0;
}
}
int zlog_filter_add(const char *filter)
{
- frr_with_mutex(&logfilterlock) {
+ frr_with_mutex (&logfilterlock) {
if (zlog_filter_count >= ZLOG_FILTERS_MAX)
return 1;
int zlog_filter_del(const char *filter)
{
- frr_with_mutex(&logfilterlock) {
+ frr_with_mutex (&logfilterlock) {
int found_idx = zlog_filter_lookup(filter);
int last_idx = zlog_filter_count - 1;
{
int len = 0;
- frr_with_mutex(&logfilterlock) {
+ frr_with_mutex (&logfilterlock) {
for (int i = 0; i < zlog_filter_count; i++) {
int ret;
{
char *found = NULL;
- frr_with_mutex(&logfilterlock) {
+ frr_with_mutex (&logfilterlock) {
for (int i = 0; i < zlog_filter_count; i++) {
found = memmem(buf, len, zlog_filters[i],
strlen(zlog_filters[i]));
static void c_callback(struct thread *thread)
{
- auto _tag = static_cast<RpcStateBase *>(thread->arg);
+ auto _tag = static_cast<RpcStateBase *>(THREAD_ARG(thread));
/*
* We hold the lock until the callback finishes and has updated
* _tag->state, then we signal done and release.
#include <zebra.h>
+#include "command.h"
#include "prefix.h"
#include "ipaddr.h"
#include "vty.h"
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)
#define PREFIX_STRLEN 80
/*
- * Longest possible length of a (S,G) string is 36 bytes
+ * Longest possible length of a (S,G) string is 34 bytes
* 123.123.123.123 = 15 * 2
* (,) = 3
* NULL Character at end = 1
#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)
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)
{
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)
}
}
- 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));
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) {
}
/* 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);
}
* Serialize 'raise' operations; particularly important for
* OSes where privs are process-wide.
*/
- frr_with_mutex(&(privs->mutex)) {
+ frr_with_mutex (&(privs->mutex)) {
/* Locate ref-counting object to use */
refs = get_privs_refs(privs);
/* Serialize 'lower privs' operation - particularly important
* when OS privs are process-wide.
*/
- frr_with_mutex(&(*privs)->mutex) {
+ frr_with_mutex (&(*privs)->mutex) {
refs = get_privs_refs(*privs);
if (--(refs->refcount) == 0) {
{
int ret;
+ if (hostname == NULL)
+ return;
+
if (query->callback != NULL) {
flog_err(
EC_LIB_RESOLVER,
*/
route_map_result_t route_map_apply_ext(struct route_map *map,
const struct prefix *prefix,
- void *match_object, void *set_object)
+ void *match_object, void *set_object,
+ int *pref)
{
static int recursion = 0;
enum route_map_cmd_result_t match_ret = RMAP_NOMATCH;
ret = route_map_apply_ext(
nextrm, prefix,
match_object,
- set_object);
+ set_object, NULL);
recursion--;
}
(map ? map->name : "null"), prefix,
route_map_result_str(ret));
+ if (pref) {
+ if (index != NULL && ret == RMAP_PERMITMATCH)
+ *pref = index->pref;
+ else
+ *pref = 65536;
+ }
+
return (ret);
}
extern route_map_result_t route_map_apply_ext(struct route_map *map,
const struct prefix *prefix,
void *match_object,
- void *set_object);
+ void *set_object, int *pref);
#define route_map_apply(map, prefix, object) \
- route_map_apply_ext(map, prefix, object, object)
+ route_map_apply_ext(map, prefix, object, object, NULL)
extern void route_map_add_hook(void (*func)(const char *));
extern void route_map_delete_hook(void (*func)(const char *));
&& (errno == EADDRINUSE)) {
/* see above: handle possible problem when interface comes back
* up */
- char buf[1][INET_ADDRSTRLEN];
zlog_info(
- "setsockopt_ipv4_multicast attempting to drop and re-add (fd %d, mcast %s, ifindex %u)",
- sock, inet_ntop(AF_INET, &mreqn.imr_multiaddr, buf[0],
- sizeof(buf[0])),
- ifindex);
+ "setsockopt_ipv4_multicast attempting to drop and re-add (fd %d, mcast %pI4, ifindex %u)",
+ sock, &mreqn.imr_multiaddr, ifindex);
setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void *)&mreqn,
sizeof(mreqn));
ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&& (errno == EADDRINUSE)) {
/* see above: handle possible problem when interface comes back
* up */
- char buf[1][INET_ADDRSTRLEN];
zlog_info(
- "setsockopt_ipv4_multicast attempting to drop and re-add (fd %d, mcast %s, ifindex %u)",
- sock, inet_ntop(AF_INET, &mreq.imr_multiaddr, buf[0],
- sizeof(buf[0])),
- ifindex);
+ "setsockopt_ipv4_multicast attempting to drop and re-add (fd %d, mcast %pI4, ifindex %u)",
+ sock, &mreq.imr_multiaddr, ifindex);
setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void *)&mreq,
sizeof(mreq));
ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
sizeof(on));
if (ret < 0) {
- flog_err(EC_LIB_SOCKET,
- "can't set sockopt SO_REUSEADDR to socket %d", sock);
+ flog_err(
+ EC_LIB_SOCKET,
+ "can't set sockopt SO_REUSEADDR to socket %d errno=%d: %s",
+ sock, errno, safe_strerror(errno));
return -1;
}
return 0;
void stream_fifo_push_safe(struct stream_fifo *fifo, struct stream *s)
{
- frr_with_mutex(&fifo->mtx) {
+ frr_with_mutex (&fifo->mtx) {
stream_fifo_push(fifo, s);
}
}
{
struct stream *ret;
- frr_with_mutex(&fifo->mtx) {
+ frr_with_mutex (&fifo->mtx) {
ret = stream_fifo_pop(fifo);
}
{
struct stream *ret;
- frr_with_mutex(&fifo->mtx) {
+ frr_with_mutex (&fifo->mtx) {
ret = stream_fifo_head(fifo);
}
void stream_fifo_clean_safe(struct stream_fifo *fifo)
{
- frr_with_mutex(&fifo->mtx) {
+ frr_with_mutex (&fifo->mtx) {
stream_fifo_clean(fifo);
}
}
am__v_XRELFO_0 = @echo " XRELFO " $@;
am__v_XRELFO_1 =
-if DEV_BUILD
XRELFO_FLAGS = -Wlog-format -Wlog-args
-else
-XRELFO_FLAGS =
-endif
SUFFIXES += .xref
%.xref: % $(CLIPPY)
*/
void ttable_del(struct ttable *tt);
-/**
- * Deletes an individual cell.
- *
- * @param cell the cell to destroy
- */
-void ttable_cell_del(struct ttable_cell *cell);
-
/**
* Inserts a new row at the given index.
*
tmp.funcname = "TOTAL";
tmp.types = filter;
- frr_with_mutex(&masters_mtx) {
+ frr_with_mutex (&masters_mtx) {
for (ALL_LIST_ELEMENTS_RO(masters, ln, m)) {
const char *name = m->name ? m->name : "main";
struct thread_master *m;
struct listnode *ln;
- frr_with_mutex(&masters_mtx) {
+ frr_with_mutex (&masters_mtx) {
for (ALL_LIST_ELEMENTS_RO(masters, ln, m)) {
- frr_with_mutex(&m->mtx) {
+ frr_with_mutex (&m->mtx) {
void *args[2] = {tmp, m->cpu_record};
hash_iterate(
m->cpu_record,
struct listnode *node;
struct thread_master *m;
- frr_with_mutex(&masters_mtx) {
+ frr_with_mutex (&masters_mtx) {
for (ALL_LIST_ELEMENTS_RO(masters, node, m)) {
show_thread_poll_helper(vty, m);
}
sizeof(struct pollfd) * rv->handler.pfdsize);
/* add to list of threadmasters */
- frr_with_mutex(&masters_mtx) {
+ frr_with_mutex (&masters_mtx) {
if (!masters)
masters = list_new();
void thread_master_set_name(struct thread_master *master, const char *name)
{
- frr_with_mutex(&master->mtx) {
+ frr_with_mutex (&master->mtx) {
XFREE(MTYPE_THREAD_MASTER, master->name);
master->name = XSTRDUP(MTYPE_THREAD_MASTER, name);
}
*/
void thread_master_free_unused(struct thread_master *m)
{
- frr_with_mutex(&m->mtx) {
+ frr_with_mutex (&m->mtx) {
struct thread *t;
while ((t = thread_list_pop(&m->unuse)))
thread_free(m, t);
{
struct thread *t;
- frr_with_mutex(&masters_mtx) {
+ frr_with_mutex (&masters_mtx) {
listnode_delete(masters, m);
if (masters->count == 0) {
list_delete(&masters);
{
int64_t remain;
- frr_with_mutex(&thread->mtx) {
+ if (!thread_is_scheduled(thread))
+ return 0;
+
+ frr_with_mutex (&thread->mtx) {
remain = monotime_until(&thread->u.sands, NULL) / 1000LL;
}
struct timeval thread_timer_remain(struct thread *thread)
{
struct timeval remain;
- frr_with_mutex(&thread->mtx) {
+ frr_with_mutex (&thread->mtx) {
monotime_until(&thread->u.sands, &remain);
}
return remain;
if (fd >= m->fd_limit)
assert(!"Number of FD's open is greater than FRR currently configured to handle, aborting");
- frr_with_mutex(&m->mtx) {
+ frr_with_mutex (&m->mtx) {
if (t_ptr && *t_ptr)
// thread is already scheduled; don't reschedule
break;
m->handler.pfdcount++;
if (thread) {
- frr_with_mutex(&thread->mtx) {
+ frr_with_mutex (&thread->mtx) {
thread->u.fd = fd;
thread_array[thread->u.fd] = thread;
}
monotime(&t);
timeradd(&t, time_relative, &t);
- frr_with_mutex(&m->mtx) {
+ frr_with_mutex (&m->mtx) {
if (t_ptr && *t_ptr)
/* thread is already scheduled; don't reschedule */
return;
thread = thread_get(m, THREAD_TIMER, func, arg, xref);
- frr_with_mutex(&thread->mtx) {
+ frr_with_mutex (&thread->mtx) {
thread->u.sands = t;
thread_timer_list_add(&m->timer, thread);
if (t_ptr) {
assert(m != NULL);
- frr_with_mutex(&m->mtx) {
+ frr_with_mutex (&m->mtx) {
if (t_ptr && *t_ptr)
/* thread is already scheduled; don't reschedule */
break;
thread = thread_get(m, THREAD_EVENT, func, arg, xref);
- frr_with_mutex(&thread->mtx) {
+ frr_with_mutex (&thread->mtx) {
thread->u.val = val;
thread_list_add_tail(&m->event, thread);
}
cr->flags = flags;
- frr_with_mutex(&m->mtx) {
+ frr_with_mutex (&m->mtx) {
cr->eventobj = arg;
listnode_add(m->cancel_req, cr);
do_thread_cancel(m);
assert(master->owner == pthread_self());
- frr_with_mutex(&master->mtx) {
+ frr_with_mutex (&master->mtx) {
struct cancel_req *cr =
XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
cr->thread = *thread;
assert(master->owner != pthread_self());
- frr_with_mutex(&master->mtx) {
+ frr_with_mutex (&master->mtx) {
master->canceled = false;
if (thread) {
int thread_should_yield(struct thread *thread)
{
int result;
- frr_with_mutex(&thread->mtx) {
+ frr_with_mutex (&thread->mtx) {
result = monotime_since(&thread->real, NULL)
> (int64_t)thread->yield;
}
void thread_set_yield_time(struct thread *thread, unsigned long yield_time)
{
- frr_with_mutex(&thread->mtx) {
+ frr_with_mutex (&thread->mtx) {
thread->yield = yield_time;
}
}
struct thread *thread;
/* Get or allocate new thread to execute. */
- frr_with_mutex(&m->mtx) {
+ frr_with_mutex (&m->mtx) {
thread = thread_get(m, THREAD_EVENT, func, arg, xref);
/* Set its event value. */
- frr_with_mutex(&thread->mtx) {
+ frr_with_mutex (&thread->mtx) {
thread->add_type = THREAD_EXECUTE;
thread->u.val = val;
thread->ref = &thread;
static inline void typesafe_dlist_add(struct dlist_head *head,
struct dlist_item *prev, struct dlist_item *item)
{
+ /* SA on clang-11 thinks this can happen, but in reality -assuming no
+ * memory corruption- it can't. DLIST uses a "closed" ring, i.e. the
+ * termination at the end of the list is not NULL but rather a pointer
+ * back to the head. (This eliminates special-casing the first or last
+ * item.)
+ *
+ * Sadly, can't use assert() here since the libfrr assert / xref code
+ * uses typesafe lists itself... that said, if an assert tripped here
+ * we'd already be way past some memory corruption, so we might as
+ * well just take the SEGV. (In the presence of corruption, we'd see
+ * random SEGVs from places that make no sense at all anyway, an
+ * assert might actually be a red herring.)
+ *
+ * ("assume()" tells the compiler to produce code as if the condition
+ * will always hold; it doesn't have any actual effect here, it'll
+ * just SEGV out on "item->next->prev = item".)
+ */
+ assume(prev->next != NULL);
+
item->next = prev->next;
item->next->prev = item;
item->prev = prev;
canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt);
cannon_len = strlen(canon);
- decode_len = cannon_len;
+ decode_len = cannon_len + 1;
value_str = (char *)malloc(decode_len);
base64_init_decodestate(&s);
cnt = base64_decode_block(canon, cannon_len, value_str, &s);
void zlog_file_set_other(struct zlog_cfg_file *zcf)
{
- frr_with_mutex(&zcf->cfg_mtx) {
+ frr_with_mutex (&zcf->cfg_mtx) {
zlog_file_cycle(zcf);
}
}
bool zlog_file_set_filename(struct zlog_cfg_file *zcf, const char *filename)
{
- frr_with_mutex(&zcf->cfg_mtx) {
+ frr_with_mutex (&zcf->cfg_mtx) {
XFREE(MTYPE_LOG_FD_NAME, zcf->filename);
zcf->filename = XSTRDUP(MTYPE_LOG_FD_NAME, filename);
zcf->fd = -1;
bool zlog_file_set_fd(struct zlog_cfg_file *zcf, int fd)
{
- frr_with_mutex(&zcf->cfg_mtx) {
+ frr_with_mutex (&zcf->cfg_mtx) {
if (zcf->fd == fd)
return true;
struct rcu_close_rotate *rcr;
int fd;
- frr_with_mutex(&zcf->cfg_mtx) {
+ frr_with_mutex (&zcf->cfg_mtx) {
if (!zcf->active || !zcf->filename)
return true;
struct zlog_target *newztc;
struct zlt_syslog *newzt;
- frr_with_mutex(&syslog_cfg_mutex) {
+ frr_with_mutex (&syslog_cfg_mutex) {
if (facility == syslog_facility)
return;
syslog_facility = facility;
int zlog_syslog_get_facility(void)
{
- frr_with_mutex(&syslog_cfg_mutex) {
+ frr_with_mutex (&syslog_cfg_mutex) {
return syslog_facility;
}
assert(0);
struct zlog_target *newztc;
struct zlt_syslog *newzt = NULL;
- frr_with_mutex(&syslog_cfg_mutex) {
+ frr_with_mutex (&syslog_cfg_mutex) {
if (prio_min == syslog_prio_min)
return;
syslog_prio_min = prio_min;
int zlog_syslog_get_prio_min(void)
{
- frr_with_mutex(&syslog_cfg_mutex) {
+ frr_with_mutex (&syslog_cfg_mutex) {
return syslog_prio_min;
}
assert(0);
#include "memory.h"
#include "thread.h"
#include "hash.h"
+#include "network.h"
#include "nhrpd.h"
#include "nhrp_protocol.h"
&p->t_fallback);
} else {
/* Maximum timeout is 1 second */
- int r_time_ms = rand() % 1000;
+ int r_time_ms = frr_weak_random() % 1000;
debugf(NHRP_DEBUG_COMMON,
"Initiating IPsec connection request to %pSU after %d ms:",
&& !OSPF6_GR_IS_PLANNED_RESTART(restart_reason)) {
if (IS_DEBUG_OSPF6_GR)
zlog_debug(
- "%s, Router supports only planned restarts but received the GRACE LSA due a unplanned restart",
+ "%s, Router supports only planned restarts but received the GRACE LSA due to an unplanned restart",
__func__);
restarter->gr_helper_info.rejected_reason =
OSPF6_HELPER_PLANNED_ONLY_RESTART;
return "UNKNOWN";
}
-#if CONFDATE > 20220709
-CPP_NOTICE("Time to remove ospf6Enabled from JSON output")
-#endif
-
/* show specified interface structure */
static int ospf6_interface_show(struct vty *vty, struct interface *ifp,
json_object *json_obj, bool use_json)
ospf6_iftype_str(default_iftype));
json_object_int_add(json_obj, "interfaceId", ifp->ifindex);
- if (ifp->info == NULL) {
- json_object_boolean_false_add(json_obj, "ospf6Enabled");
+ if (ifp->info == NULL)
return 0;
- }
- json_object_boolean_true_add(json_obj, "ospf6Enabled");
oi = (struct ospf6_interface *)ifp->info;
if (oi->area_id_format == OSPF6_AREA_FMT_UNSET)
return;
- if (oi->area)
+ if (oi->area) {
+ /* Recompute cost */
+ ospf6_interface_recalculate_cost(oi);
return;
+ }
ospf6 = oi->interface->vrf->info;
if (!ospf6)
intra_prefix_lsa =
(struct ospf6_intra_prefix_lsa *)OSPF6_LSA_HEADER_END(
lsa->header);
- if (intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_ROUTER))
- ospf6_linkstate_prefix(intra_prefix_lsa->ref_adv_router,
- intra_prefix_lsa->ref_id, &ls_prefix);
- else if (intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_NETWORK))
+ if (intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_ROUTER) ||
+ intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_NETWORK))
ospf6_linkstate_prefix(intra_prefix_lsa->ref_adv_router,
intra_prefix_lsa->ref_id, &ls_prefix);
else {
{
struct ospf6 *ospf6 = THREAD_ARG(thread);
struct ospf6_interface *oi;
- struct ospf6_interface *last_serviced_oi = NULL;
struct ospf6_header *oh;
struct ospf6_packet *op;
struct listnode *node;
assert(node);
oi = listgetdata(node);
- while ((pkt_count < ospf6->write_oi_count) && oi
- && (last_serviced_oi != oi)) {
-
+ while ((pkt_count < ospf6->write_oi_count) && oi) {
op = ospf6_fifo_head(oi->obuf);
assert(op);
assert(op->length >= OSPF6_HEADER_SIZE);
list_delete_node(ospf6->oi_write_q, node);
if (ospf6_fifo_head(oi->obuf) == NULL) {
oi->on_write_q = 0;
- last_serviced_oi = NULL;
oi = NULL;
} else {
listnode_add(ospf6->oi_write_q, oi);
struct lsa_header *lsah;
uint32_t tmp;
+ /* Validate opaque LSA length */
+ if ((size_t)opaquelen > sizeof(buf) - sizeof(struct lsa_header)) {
+ fprintf(stderr, "opaquelen(%d) is larger than buf size %zu\n",
+ opaquelen, sizeof(buf));
+ return OSPF_API_NOMEMORY;
+ }
/* We can only originate opaque LSAs */
if (!IS_OPAQUE_LSA(lsa_type)) {
struct ospf_lsa *lsa;
struct router_lsa *rlsa;
struct in_addr *best = NULL;
- char buf[PREFIX_STRLEN];
LSDB_LOOP (ROUTER_LSDB(area), rn, lsa) {
/* sanity checks */
if (IS_DEBUG_OSPF_NSSA)
zlog_debug(
- "ospf_abr_nssa_am_elected: best electable ABR is: %s",
- (best) ? inet_ntop(AF_INET, best, buf, sizeof(buf)) :
- "<none>");
+ "ospf_abr_nssa_am_elected: best electable ABR is: %pI4",
+ best);
if (best == NULL)
return 1;
&& !OSPF_IS_AREA_ID_BACKBONE(or->u.std.area_id)) {
if (IS_DEBUG_OSPF_EVENT)
zlog_debug(
- "ospf_abr_process_network_rt(): this is route is not backbone one, skipping");
+ "ospf_abr_process_network_rt(): this route is not backbone one, skipping");
continue;
}
struct listnode *node;
/* Cancel read and write threads. */
- thread_cancel(&apiserv->t_sync_read);
+ THREAD_OFF(apiserv->t_sync_read);
#ifdef USE_ASYNC_READ
- thread_cancel(&apiserv->t_async_read);
+ THREAD_OFF(apiserv->t_async_read);
#endif /* USE_ASYNC_READ */
- thread_cancel(&apiserv->t_sync_write);
- thread_cancel(&apiserv->t_async_write);
+ THREAD_OFF(apiserv->t_sync_write);
+ THREAD_OFF(apiserv->t_async_write);
/* Unregister all opaque types that application registered
and flush opaque LSAs if still in LSDB. */
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);
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);
struct ospf_neighbor *onbr;
struct route_node *rn;
int retx_flag;
- char buf[PREFIX_STRLEN];
if (IS_DEBUG_OSPF_EVENT)
zlog_debug(
- "%s: considering int %s (%s), INBR(%s), LSA[%s] AGE %u",
+ "%s: considering int %s (%s), INBR(%pI4), LSA[%s] AGE %u",
__func__, IF_NAME(oi), ospf_get_name(oi->ospf),
- inbr ? inet_ntop(AF_INET, &inbr->router_id, buf,
- sizeof(buf))
- : "NULL",
- dump_lsa_key(lsa), ntohs(lsa->data->ls_age));
+ inbr ? &inbr->router_id : NULL, dump_lsa_key(lsa),
+ ntohs(lsa->data->ls_age));
if (!ospf_if_is_enable(oi))
return 0;
if (oi->type == OSPF_IFTYPE_NBMA) {
struct ospf_neighbor *nbr;
- for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
- if ((nbr = rn->info) != NULL)
- if (nbr != oi->nbr_self
- && nbr->state >= NSM_Exchange)
- ospf_ls_upd_send_lsa(
- nbr, lsa,
- OSPF_SEND_PACKET_DIRECT);
+ for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
+ nbr = rn->info;
+
+ if (!nbr)
+ continue;
+ if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange)
+ ospf_ls_upd_send_lsa(nbr, lsa,
+ OSPF_SEND_PACKET_DIRECT);
+ }
} else
ospf_ls_upd_send_lsa(oi->nbr_self, lsa,
OSPF_SEND_PACKET_INDIRECT);
struct ospf_lsa *lsr;
if (ospf_if_is_enable(oi))
- for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
+ for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
/* If LSA find in LS-retransmit list, then remove it. */
- if ((nbr = rn->info) != NULL) {
- lsr = ospf_ls_retransmit_lookup(nbr, lsa);
+ nbr = rn->info;
- /* If LSA find in ls-retransmit list, remove it.
- */
- if (lsr != NULL
- && lsr->data->ls_seqnum
- == lsa->data->ls_seqnum)
- ospf_ls_retransmit_delete(nbr, lsr);
- }
+ if (!nbr)
+ continue;
+
+ lsr = ospf_ls_retransmit_lookup(nbr, lsa);
+
+ /* If LSA find in ls-retransmit list, remove it. */
+ if (lsr != NULL &&
+ lsr->data->ls_seqnum == lsa->data->ls_seqnum)
+ ospf_ls_retransmit_delete(nbr, lsr);
+ }
}
void ospf_ls_retransmit_delete_nbr_area(struct ospf_area *area,
zlog_debug("GR: exiting graceful restart: %s", reason);
ospf->gr_info.restart_in_progress = false;
- OSPF_TIMER_OFF(ospf->gr_info.t_grace_period);
+ THREAD_OFF(ospf->gr_info.t_grace_period);
/* Record in non-volatile memory that the restart is complete. */
ospf_gr_nvm_delete(ospf);
for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
nbr = rn->info;
- if (nbr) {
- /* Do not show myself. */
- if (nbr == oi->nbr_self)
- continue;
- /* Down state is not shown. */
- if (nbr->state == NSM_Down)
- continue;
- count++;
- }
+ if (!nbr)
+ continue;
+
+ /* Do not show myself. */
+ if (nbr == oi->nbr_self)
+ continue;
+ /* Down state is not shown. */
+ if (nbr->state == NSM_Down)
+ continue;
+ count++;
}
return count;
/* oi->nbrs and oi->nbr_nbma should be deleted on InterfaceDown event */
/* delete all static neighbors attached to this interface */
for (ALL_LIST_ELEMENTS(oi->nbr_nbma, node, nnode, nbr_nbma)) {
- OSPF_POLL_TIMER_OFF(nbr_nbma->t_poll);
+ THREAD_OFF(nbr_nbma->t_poll);
if (nbr_nbma->nbr) {
nbr_nbma->nbr->nbr_nbma = NULL;
}
/* send Neighbor event KillNbr to all associated neighbors. */
- for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
+ for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
if ((nbr = rn->info) != NULL)
if (nbr != oi->nbr_self)
OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr);
+ }
/* Cleanup Link State Acknowlegdment list. */
for (ALL_LIST_ELEMENTS(oi->ls_ack, node, nnode, lsa))
return match;
}
+void ospf_interface_fifo_flush(struct ospf_interface *oi)
+{
+ struct ospf *ospf = oi->ospf;
+
+ ospf_fifo_flush(oi->obuf);
+
+ if (oi->on_write_q) {
+ listnode_delete(ospf->oi_write_q, oi);
+ if (list_isempty(ospf->oi_write_q))
+ THREAD_OFF(ospf->t_write);
+ oi->on_write_q = 0;
+ }
+}
+
static void ospf_if_reset_stats(struct ospf_interface *oi)
{
oi->hello_in = oi->hello_out = 0;
void ospf_if_stream_unset(struct ospf_interface *oi)
{
- struct ospf *ospf = oi->ospf;
-
/* flush the interface packet queue */
- ospf_fifo_flush(oi->obuf);
+ ospf_interface_fifo_flush(oi);
/*reset protocol stats */
ospf_if_reset_stats(oi);
-
- if (oi->on_write_q) {
- listnode_delete(ospf->oi_write_q, oi);
- if (list_isempty(ospf->oi_write_q))
- OSPF_TIMER_OFF(ospf->t_write);
- oi->on_write_q = 0;
- }
}
ospf_hello_send(oi);
/* Restart hello timer for this interface */
- OSPF_ISM_TIMER_OFF(oi->t_hello);
+ THREAD_OFF(oi->t_hello);
OSPF_HELLO_TIMER_ON(oi);
}
ospf_hello_send(oi);
/* Restart the hello timer. */
- OSPF_ISM_TIMER_OFF(oi->t_hello);
+ THREAD_OFF(oi->t_hello);
OSPF_HELLO_TIMER_ON(oi);
}
}
extern uint32_t ospf_if_count_area_params(struct interface *ifp);
extern void ospf_reset_hello_timer(struct interface *ifp, struct in_addr addr,
bool is_addr);
+
+extern void ospf_interface_fifo_flush(struct ospf_interface *oi);
DECLARE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd));
DECLARE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd));
interface parameters must be set to initial values, and
timers are
reset also. */
- OSPF_ISM_TIMER_OFF(oi->t_hello);
- OSPF_ISM_TIMER_OFF(oi->t_wait);
- OSPF_ISM_TIMER_OFF(oi->t_ls_ack);
+ THREAD_OFF(oi->t_hello);
+ THREAD_OFF(oi->t_wait);
+ THREAD_OFF(oi->t_ls_ack);
break;
case ISM_Loopback:
/* In this state, the interface may be looped back and will be
unavailable for regular data traffic. */
- OSPF_ISM_TIMER_OFF(oi->t_hello);
- OSPF_ISM_TIMER_OFF(oi->t_wait);
- OSPF_ISM_TIMER_OFF(oi->t_ls_ack);
+ THREAD_OFF(oi->t_hello);
+ THREAD_OFF(oi->t_wait);
+ THREAD_OFF(oi->t_ls_ack);
break;
case ISM_Waiting:
/* The router is trying to determine the identity of DRouter and
OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1);
OSPF_ISM_TIMER_ON(oi->t_wait, ospf_wait_timer,
OSPF_IF_PARAM(oi, v_wait));
- OSPF_ISM_TIMER_OFF(oi->t_ls_ack);
+ THREAD_OFF(oi->t_ls_ack);
break;
case ISM_PointToPoint:
/* The interface connects to a physical Point-to-point network
neighboring router. Hello packets are also sent. */
/* send first hello immediately */
OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1);
- OSPF_ISM_TIMER_OFF(oi->t_wait);
+ THREAD_OFF(oi->t_wait);
OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer,
oi->v_ls_ack);
break;
and the router itself is neither Designated Router nor
Backup Designated Router. */
OSPF_HELLO_TIMER_ON(oi);
- OSPF_ISM_TIMER_OFF(oi->t_wait);
+ THREAD_OFF(oi->t_wait);
OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer,
oi->v_ls_ack);
break;
network,
and the router is Backup Designated Router. */
OSPF_HELLO_TIMER_ON(oi);
- OSPF_ISM_TIMER_OFF(oi->t_wait);
+ THREAD_OFF(oi->t_wait);
OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer,
oi->v_ls_ack);
break;
network,
and the router is Designated Router. */
OSPF_HELLO_TIMER_ON(oi);
- OSPF_ISM_TIMER_OFF(oi->t_wait);
+ THREAD_OFF(oi->t_wait);
OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer,
oi->v_ls_ack);
break;
OSPF_IF_PARAM((O), v_hello)); \
} while (0)
-/* Macro for OSPF ISM timer turn off. */
-#define OSPF_ISM_TIMER_OFF(X) thread_cancel(&(X))
-
/* Macro for OSPF schedule event. */
#define OSPF_ISM_EVENT_SCHEDULE(I, E) \
thread_add_event(master, ospf_ism_event, (I), (E), NULL)
struct as_external_lsa *al;
struct in_addr mask;
struct ospf_lsa *new;
- struct external_info ei_summary;
+ struct external_info ei_summary = {};
struct external_info *ei_old;
lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, OSPF_AS_EXTERNAL_LSA,
* without conflicting to other threads.
*/
if (ospf->t_maxage != NULL) {
- OSPF_TIMER_OFF(ospf->t_maxage);
+ THREAD_OFF(ospf->t_maxage);
thread_execute(master, ospf_maxage_lsa_remover, ospf, 0);
}
if (IS_DEBUG_OSPF(lsa, LSA_REFRESH))
zlog_debug(
- "LSA[Refresh:Type%d:%pI4]: ospf_refresher_register_lsa(): setting refresh_list on lsa %p (slod %d)",
- lsa->data->type, &lsa->data->id,
- (void *)lsa, index);
+ "LSA[Refresh:Type%d:%pI4]: ospf_refresher_register_lsa(): setting refresh_list on lsa %p (slot %d)",
+ lsa->data->type, &lsa->data->id, (void *)lsa,
+ index);
}
}
}
/* Cancel all timers. */
- OSPF_NSM_TIMER_OFF(nbr->t_inactivity);
- OSPF_NSM_TIMER_OFF(nbr->t_db_desc);
- OSPF_NSM_TIMER_OFF(nbr->t_ls_req);
- OSPF_NSM_TIMER_OFF(nbr->t_ls_upd);
+ THREAD_OFF(nbr->t_inactivity);
+ THREAD_OFF(nbr->t_db_desc);
+ THREAD_OFF(nbr->t_ls_req);
+ THREAD_OFF(nbr->t_ls_upd);
/* Cancel all events. */ /* Thread lookup cost would be negligible. */
thread_cancel_event(master, nbr);
bfd_sess_free(&nbr->bfd_session);
- OSPF_NSM_TIMER_OFF(nbr->gr_helper_info.t_grace_timer);
+ THREAD_OFF(nbr->gr_helper_info.t_grace_timer);
nbr->oi = NULL;
XFREE(MTYPE_OSPF_NEIGHBOR, nbr);
nbr->nbr_nbma = nbr_nbma;
if (nbr_nbma->t_poll)
- OSPF_POLL_TIMER_OFF(nbr_nbma->t_poll);
+ THREAD_OFF(nbr_nbma->t_poll);
nbr->state_change = nbr_nbma->state_change + 1;
}
switch (nbr->state) {
case NSM_Deleted:
case NSM_Down:
- OSPF_NSM_TIMER_OFF(nbr->t_inactivity);
- OSPF_NSM_TIMER_OFF(nbr->t_hello_reply);
+ THREAD_OFF(nbr->t_inactivity);
+ THREAD_OFF(nbr->t_hello_reply);
/* fallthru */
case NSM_Attempt:
case NSM_Init:
case NSM_TwoWay:
- OSPF_NSM_TIMER_OFF(nbr->t_db_desc);
- OSPF_NSM_TIMER_OFF(nbr->t_ls_upd);
- OSPF_NSM_TIMER_OFF(nbr->t_ls_req);
+ THREAD_OFF(nbr->t_db_desc);
+ THREAD_OFF(nbr->t_ls_upd);
+ THREAD_OFF(nbr->t_ls_req);
break;
case NSM_ExStart:
OSPF_NSM_TIMER_ON(nbr->t_db_desc, ospf_db_desc_timer,
nbr->v_db_desc);
- OSPF_NSM_TIMER_OFF(nbr->t_ls_upd);
- OSPF_NSM_TIMER_OFF(nbr->t_ls_req);
+ THREAD_OFF(nbr->t_ls_upd);
+ THREAD_OFF(nbr->t_ls_req);
break;
case NSM_Exchange:
OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer,
nbr->v_ls_upd);
if (!IS_SET_DD_MS(nbr->dd_flags))
- OSPF_NSM_TIMER_OFF(nbr->t_db_desc);
+ THREAD_OFF(nbr->t_db_desc);
break;
case NSM_Loading:
case NSM_Full:
default:
- OSPF_NSM_TIMER_OFF(nbr->t_db_desc);
+ THREAD_OFF(nbr->t_db_desc);
break;
}
}
static int nsm_hello_received(struct ospf_neighbor *nbr)
{
/* Start or Restart Inactivity Timer. */
- OSPF_NSM_TIMER_OFF(nbr->t_inactivity);
+ THREAD_OFF(nbr->t_inactivity);
OSPF_NSM_TIMER_ON(nbr->t_inactivity, ospf_inactivity_timer,
nbr->v_inactivity);
if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma)
- OSPF_POLL_TIMER_OFF(nbr->nbr_nbma->t_poll);
+ THREAD_OFF(nbr->nbr_nbma->t_poll);
/* Send proactive ARP requests */
if (nbr->state < NSM_Exchange)
static int nsm_start(struct ospf_neighbor *nbr)
{
if (nbr->nbr_nbma)
- OSPF_POLL_TIMER_OFF(nbr->nbr_nbma->t_poll);
+ THREAD_OFF(nbr->nbr_nbma->t_poll);
- OSPF_NSM_TIMER_OFF(nbr->t_inactivity);
+ THREAD_OFF(nbr->t_inactivity);
OSPF_NSM_TIMER_ON(nbr->t_inactivity, ospf_inactivity_timer,
nbr->v_inactivity);
static int nsm_kill_nbr(struct ospf_neighbor *nbr)
{
+ struct ospf_interface *oi = nbr->oi;
+ struct ospf_neighbor *on;
+ struct route_node *rn;
+
/* killing nbr_self is invalid */
if (nbr == nbr->oi->nbr_self) {
assert(nbr != nbr->oi->nbr_self);
ospf_get_name(nbr->oi->ospf));
}
+ /*
+ * Do we have any neighbors that are also operating
+ * on this interface?
+ */
+ for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
+ on = rn->info;
+
+ if (!on)
+ continue;
+
+ if (on == nbr || on == oi->nbr_self)
+ continue;
+
+ /*
+ * on is in some state where we might be
+ * sending packets on this interface
+ */
+ if (on->state > NSM_Down) {
+ route_unlock_node(rn);
+ return 0;
+ }
+ }
+ /*
+ * If we get here we know that this interface
+ * has no neighbors in a state where we could
+ * be sending packets. Let's flush anything
+ * we got.
+ */
+ ospf_interface_fifo_flush(oi);
return 0;
}
/* Macro for OSPF NSM timer turn on. */
#define OSPF_NSM_TIMER_ON(T,F,V) thread_add_timer (master, (F), nbr, (V), &(T))
-/* Macro for OSPF NSM timer turn off. */
-#define OSPF_NSM_TIMER_OFF(X) thread_cancel(&(X))
-
/* Macro for OSPF NSM schedule event. */
#define OSPF_NSM_EVENT_SCHEDULE(N, E) \
thread_add_event(master, ospf_nsm_event, (N), (E), NULL)
void ospf_opaque_type9_lsa_term(struct ospf_interface *oi)
{
- OSPF_TIMER_OFF(oi->t_opaque_lsa_self);
+ THREAD_OFF(oi->t_opaque_lsa_self);
if (oi->opaque_lsa_self != NULL)
list_delete(&oi->opaque_lsa_self);
oi->opaque_lsa_self = NULL;
area->lsdb->new_lsa_hook = area->lsdb->del_lsa_hook = NULL;
#endif /* MONITOR_LSDB_CHANGE */
- OSPF_TIMER_OFF(area->t_opaque_lsa_self);
+ THREAD_OFF(area->t_opaque_lsa_self);
if (area->opaque_lsa_self != NULL)
list_delete(&area->opaque_lsa_self);
return;
top->lsdb->new_lsa_hook = top->lsdb->del_lsa_hook = NULL;
#endif /* MONITOR_LSDB_CHANGE */
- OSPF_TIMER_OFF(top->t_opaque_lsa_self);
+ THREAD_OFF(top->t_opaque_lsa_self);
if (top->opaque_lsa_self != NULL)
list_delete(&top->opaque_lsa_self);
return;
ospf_opaque_lsa_flush_schedule(lsa);
}
- OSPF_TIMER_OFF(oipt->t_opaque_lsa_self);
+ THREAD_OFF(oipt->t_opaque_lsa_self);
list_delete(&oipt->id_list);
if (cleanup_owner) {
/* Remove from its owner's self-originated LSA list. */
{
struct opaque_info_per_id *oipi = (struct opaque_info_per_id *)val;
- OSPF_TIMER_OFF(oipi->t_opaque_lsa_self);
+ THREAD_OFF(oipi->t_opaque_lsa_self);
if (oipi->lsa != NULL)
ospf_lsa_unlock(&oipi->lsa);
XFREE(MTYPE_OPAQUE_INFO_PER_ID, oipi);
void ospf_ls_req_event(struct ospf_neighbor *nbr)
{
- thread_cancel(&nbr->t_ls_req);
+ THREAD_OFF(nbr->t_ls_req);
thread_add_event(master, ospf_ls_req_timer, nbr, 0, &nbr->t_ls_req);
}
{
struct ospf *ospf = THREAD_ARG(thread);
struct ospf_interface *oi;
- struct ospf_interface *last_serviced_oi = NULL;
struct ospf_packet *op;
struct sockaddr_in sa_dst;
struct ip iph;
ipid = (time(NULL) & 0xffff);
#endif /* WANT_OSPF_WRITE_FRAGMENT */
- while ((pkt_count < ospf->write_oi_count) && oi
- && (last_serviced_oi != oi)) {
- /* If there is only packet in the queue, the oi is removed from
- write-q, so fix up the last interface that was serviced */
- if (last_serviced_oi == NULL) {
- last_serviced_oi = oi;
- }
+ while ((pkt_count < ospf->write_oi_count) && oi) {
pkt_count++;
#ifdef WANT_OSPF_WRITE_FRAGMENT
/* convenience - max OSPF data per packet */
list_delete_node(ospf->oi_write_q, node);
if (ospf_fifo_head(oi->obuf) == NULL) {
oi->on_write_q = 0;
- last_serviced_oi = NULL;
oi = NULL;
- } else {
+ } else
listnode_add(ospf->oi_write_q, oi);
- }
/* Setup to service from the head of the queue again */
if (!list_isempty(ospf->oi_write_q)) {
stream_put_ipv4(s, BDR(oi).s_addr);
/* Add neighbor seen. */
- for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
- if ((nbr = rn->info))
- if (nbr->router_id.s_addr
- != INADDR_ANY) /* Ignore 0.0.0.0 node. */
- if (nbr->state
- != NSM_Attempt) /* Ignore Down neighbor. */
- if (nbr->state
- != NSM_Down) /* This is myself for
- DR election. */
- if (!IPV4_ADDR_SAME(
- &nbr->router_id,
- &oi->ospf->router_id)) {
- /* Check neighbor is
- * sane? */
- if (nbr->d_router.s_addr
- != INADDR_ANY
- && IPV4_ADDR_SAME(
- &nbr->d_router,
- &oi->address
- ->u
- .prefix4)
- && IPV4_ADDR_SAME(
- &nbr->bd_router,
- &oi->address
- ->u
- .prefix4))
- flag = 1;
-
- /* Hello packet overflows interface MTU. */
- if (length + sizeof(uint32_t)
- > ospf_packet_max(oi)) {
- flog_err(
- EC_OSPF_LARGE_HELLO,
- "Oversized Hello packet! Larger than MTU. Not sending it out");
- return 0;
- }
-
- stream_put_ipv4(
- s,
- nbr->router_id
- .s_addr);
- length += 4;
- }
+ for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
+ nbr = rn->info;
+
+ if (!nbr)
+ continue;
+
+ /* Ignore the 0.0.0.0 node */
+ if (nbr->router_id.s_addr == INADDR_ANY)
+ continue;
+
+ /* Ignore Down neighbor */
+ if (nbr->state == NSM_Attempt)
+ continue;
+
+ /* This is myself for DR election */
+ if (nbr->state == NSM_Down)
+ continue;
+
+ if (IPV4_ADDR_SAME(&nbr->router_id, &oi->ospf->router_id))
+ continue;
+ /* Check neighbor is sane? */
+ if (nbr->d_router.s_addr != INADDR_ANY &&
+ IPV4_ADDR_SAME(&nbr->d_router, &oi->address->u.prefix4) &&
+ IPV4_ADDR_SAME(&nbr->bd_router, &oi->address->u.prefix4))
+ flag = 1;
+
+ /* Hello packet overflows interface MTU.
+ */
+ if (length + sizeof(uint32_t) > ospf_packet_max(oi)) {
+ flog_err(
+ EC_OSPF_LARGE_HELLO,
+ "Oversized Hello packet! Larger than MTU. Not sending it out");
+ return 0;
+ }
+
+ stream_put_ipv4(s, nbr->router_id.s_addr);
+ length += 4;
+ }
/* Let neighbor generate BackupSeen. */
if (flag == 1)
struct ospf_neighbor *nbr;
struct route_node *rn;
- for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
- if ((nbr = rn->info))
- if (nbr != oi->nbr_self)
- if (nbr->state != NSM_Down) {
- /* RFC 2328 Section 9.5.1
- If the router is not
- eligible to become Designated
- Router,
- it must periodically send
- Hello Packets to both the
- Designated Router and the
- Backup Designated Router (if
- they
- exist). */
- if (PRIORITY(oi) == 0
- && IPV4_ADDR_CMP(
- &DR(oi),
- &nbr->address.u
- .prefix4)
- && IPV4_ADDR_CMP(
- &BDR(oi),
- &nbr->address.u
- .prefix4))
- continue;
-
- /* If the router is eligible to
- become Designated Router, it
- must periodically send Hello
- Packets to all neighbors that
- are also eligible. In
- addition, if the router is
- itself the
- Designated Router or Backup
- Designated Router, it must
- also
- send periodic Hello Packets
- to all other neighbors. */
-
- if (nbr->priority == 0
- && oi->state == ISM_DROther)
- continue;
- /* if oi->state == Waiting, send
- * hello to all neighbors */
- ospf_hello_send_sub(
- oi,
- nbr->address.u.prefix4
- .s_addr);
- }
+ for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
+ nbr = rn->info;
+ if (!nbr)
+ continue;
+
+ if (nbr == oi->nbr_self)
+ continue;
+
+ if (nbr->state == NSM_Down)
+ continue;
+
+ /*
+ * RFC 2328 Section 9.5.1
+ * If the router is not eligible to become Designated
+ * Router, it must periodically send Hello Packets to
+ * both the Designated Router and the Backup
+ * Designated Router (if they exist).
+ */
+ if (PRIORITY(oi) == 0 &&
+ IPV4_ADDR_CMP(&DR(oi), &nbr->address.u.prefix4) &&
+ IPV4_ADDR_CMP(&BDR(oi), &nbr->address.u.prefix4))
+ continue;
+
+ /*
+ * If the router is eligible to become Designated
+ * Router, it must periodically send Hello Packets to
+ * all neighbors that are also eligible. In addition,
+ * if the router is itself the Designated Router or
+ * Backup Designated Router, it must also send periodic
+ * Hello Packets to all other neighbors.
+ */
+ if (nbr->priority == 0 && oi->state == ISM_DROther)
+ continue;
+
+ /* if oi->state == Waiting, send
+ * hello to all neighbors */
+ ospf_hello_send_sub(oi, nbr->address.u.prefix4.s_addr);
+ }
} else {
/* Decide destination address. */
if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
* is actually turned off.
*/
if (list_isempty(oi->ospf->oi_write_q))
- OSPF_TIMER_OFF(oi->ospf->t_write);
+ THREAD_OFF(oi->ospf->t_write);
} else {
/* Hook thread to write packet. */
OSPF_ISM_WRITE_ON(oi->ospf);
struct ospf_neighbor *nbr;
struct route_node *rn;
- for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
- if ((nbr = rn->info) != NULL)
- if (nbr != oi->nbr_self
- && nbr->state >= NSM_Exchange)
- while (listcount(oi->ls_ack))
- ospf_ls_ack_send_list(
- oi, oi->ls_ack,
- nbr->address.u.prefix4);
+ for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
+ nbr = rn->info;
+
+ if (!nbr)
+ continue;
+
+ if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange)
+ while (listcount(oi->ls_ack))
+ ospf_ls_ack_send_list(
+ oi, oi->ls_ack,
+ nbr->address.u.prefix4);
+ }
return;
}
if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
if (ospf_nexthop_calculation(area, v, w, l, distance,
lsa_pos))
vertex_pqueue_add(candidate, w);
- else if (IS_DEBUG_OSPF_EVENT)
- zlog_debug("Nexthop Calc failed");
+ else {
+ listnode_delete(area->spf_vertex_list, w);
+ ospf_vertex_free(w);
+ w_lsa->stat = LSA_SPF_NOT_EXPLORED;
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("Nexthop Calc failed");
+ }
} else if (w_lsa->stat != LSA_SPF_IN_SPFTREE) {
w = w_lsa->stat;
if (w->distance < distance) {
for (ALL_LIST_ELEMENTS_RO(top->oiflist, node, oi))
for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
nbr = rn->info;
- if (nbr)
- if (IPV4_ADDR_SAME(&nbr->address.u.prefix4,
- &addr)
- || IPV4_ADDR_SAME(&nbr->router_id, &addr)) {
- route_unlock_node(rn);
- return nbr;
- }
+ if (!nbr)
+ continue;
+
+ if (IPV4_ADDR_SAME(&nbr->address.u.prefix4, &addr) ||
+ IPV4_ADDR_SAME(&nbr->router_id, &addr)) {
+ route_unlock_node(rn);
+ return nbr;
+ }
}
return NULL;
}
oi->ls_ack_in);
json_object_int_add(json_interface_sub, "lsAckOut",
oi->ls_ack_out);
+ json_object_int_add(json_interface_sub, "packetsQueued",
+ listcount(oi->obuf));
} else {
vty_out(vty,
- "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u\n",
+ "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %12lu\n",
oi->ifp->name, oi->hello_in, oi->hello_out,
oi->db_desc_in, oi->db_desc_out, oi->ls_req_in,
oi->ls_req_out, oi->ls_upd_in, oi->ls_upd_out,
- oi->ls_ack_in, oi->ls_ack_out);
+ oi->ls_ack_in, oi->ls_ack_out, listcount(oi->obuf));
}
}
if (!use_json && !display_once) {
vty_out(vty, "\n");
- vty_out(vty, "%-12s%-17s%-17s%-17s%-17s%-17s\n", "Interface",
- " HELLO", " DB-Desc", " LS-Req", " LS-Update",
- " LS-Ack");
- vty_out(vty, "%-10s%-18s%-18s%-17s%-17s%-17s\n", "",
+ vty_out(vty, "%-12s%-17s%-17s%-17s%-17s%-17s%-17s\n",
+ "Interface", " HELLO", " DB-Desc", " LS-Req",
+ " LS-Update", " LS-Ack", " Packets");
+ vty_out(vty, "%-10s%-18s%-18s%-17s%-17s%-17s%-17s\n", "",
" Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx",
- " Rx/Tx");
+ " Rx/Tx", " Queued");
vty_out(vty,
- "--------------------------------------------------------------------------------------------\n");
+ "-------------------------------------------------------------------------------------------------------------\n");
} else if (use_json) {
if (use_vrf)
json_vrf = json_object_new_object();
struct ospf_neighbor *nbr, *prev_nbr = NULL;
for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
- if ((nbr = rn->info)) {
- /* Do not show myself. */
- if (nbr == oi->nbr_self)
- continue;
- /* Down state is not shown. */
- if (nbr->state == NSM_Down)
- continue;
+ nbr = rn->info;
- prev_nbr = nbr;
+ if (!nbr)
+ continue;
- show_ip_ospf_neighbour_brief(vty, nbr, prev_nbr, json,
- use_json);
- }
+ /* Do not show myself. */
+ if (nbr == oi->nbr_self)
+ continue;
+ /* Down state is not shown. */
+ if (nbr->state == NSM_Down)
+ continue;
+
+ prev_nbr = nbr;
+
+ show_ip_ospf_neighbour_brief(vty, nbr, prev_nbr, json,
+ use_json);
}
}
ospf_show_vrf_name(ospf, vty, json, use_vrf);
for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
- if ((nbr = ospf_nbr_lookup_by_routerid(oi->nbrs, router_id))) {
- if (is_detail)
- show_ip_ospf_neighbor_detail_sub(
- vty, oi, nbr, NULL, json, use_json);
- else
- show_ip_ospf_neighbour_brief(vty, nbr, NULL,
- json, use_json);
- }
+ nbr = ospf_nbr_lookup_by_routerid(oi->nbrs, router_id);
+
+ if (!nbr)
+ continue;
+
+ if (is_detail)
+ show_ip_ospf_neighbor_detail_sub(vty, oi, nbr, NULL,
+ json, use_json);
+ else
+ show_ip_ospf_neighbour_brief(vty, nbr, NULL, json,
+ use_json);
}
if (use_json)
struct ospf_neighbor *nbr, *prev_nbr = NULL;
for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
- if ((nbr = rn->info)) {
- if (nbr != oi->nbr_self) {
- if (nbr->state != NSM_Down) {
- show_ip_ospf_neighbor_detail_sub(
- vty, oi, nbr, prev_nbr,
- json_nbr_sub, use_json);
- }
+ nbr = rn->info;
+
+ if (!nbr)
+ continue;
+
+ if (nbr != oi->nbr_self) {
+ if (nbr->state != NSM_Down) {
+ show_ip_ospf_neighbor_detail_sub(
+ vty, oi, nbr, prev_nbr,
+ json_nbr_sub, use_json);
}
- prev_nbr = nbr;
}
+ prev_nbr = nbr;
}
}
struct ospf_nbr_nbma *nbr_nbma;
for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
- if ((nbr = rn->info)) {
- if (nbr != oi->nbr_self)
- if (nbr->state != NSM_Down)
- show_ip_ospf_neighbor_detail_sub(
- vty, oi, rn->info,
- prev_nbr,
- json_vrf, use_json);
- prev_nbr = nbr;
- }
+ nbr = rn->info;
+
+ if (!nbr)
+ continue;
+
+ if (nbr != oi->nbr_self)
+ if (nbr->state != NSM_Down)
+ show_ip_ospf_neighbor_detail_sub(
+ vty, oi, rn->info, prev_nbr,
+ json_vrf, use_json);
+ prev_nbr = nbr;
}
- if (oi->type == OSPF_IFTYPE_NBMA) {
- struct listnode *nd;
+ if (oi->type != OSPF_IFTYPE_NBMA)
+ continue;
- for (ALL_LIST_ELEMENTS_RO(oi->nbr_nbma, nd, nbr_nbma)) {
- if (nbr_nbma->nbr == NULL
- || nbr_nbma->nbr->state == NSM_Down)
- show_ip_ospf_nbr_nbma_detail_sub(
- vty, oi, nbr_nbma, use_json,
- json_vrf);
- }
+ struct listnode *nd;
+
+ for (ALL_LIST_ELEMENTS_RO(oi->nbr_nbma, nd, nbr_nbma)) {
+ if (nbr_nbma->nbr == NULL ||
+ nbr_nbma->nbr->state == NSM_Down)
+ show_ip_ospf_nbr_nbma_detail_sub(
+ vty, oi, nbr_nbma, use_json, json_vrf);
}
}
}
for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) {
- if ((oi = rn->info)) {
- for (nrn = route_top(oi->nbrs); nrn;
- nrn = route_next(nrn)) {
- if ((nbr = nrn->info)) {
- if (nbr != oi->nbr_self) {
- if (nbr->state != NSM_Down)
- show_ip_ospf_neighbor_detail_sub(
- vty, oi, nbr,
- NULL,
- json, use_json);
- }
- }
- }
+ oi = rn->info;
+
+ if (!oi)
+ continue;
+
+ for (nrn = route_top(oi->nbrs); nrn; nrn = route_next(nrn)) {
+ nbr = nrn->info;
+
+ if (!nbr)
+ continue;
+
+ if (nbr == oi->nbr_self)
+ continue;
+
+ if (nbr->state == NSM_Down)
+ continue;
+
+ show_ip_ospf_neighbor_detail_sub(vty, oi, nbr, NULL,
+ json, use_json);
}
}
struct route_node *rn;
struct ospf_neighbor *nbr;
- for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
- if ((nbr = rn->info)) {
- nbr->v_inactivity = OSPF_IF_PARAM(oi, v_wait);
- nbr->v_db_desc = OSPF_IF_PARAM(oi, retransmit_interval);
- nbr->v_ls_req = OSPF_IF_PARAM(oi, retransmit_interval);
- nbr->v_ls_upd = OSPF_IF_PARAM(oi, retransmit_interval);
- }
+ for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
+ nbr = rn->info;
+
+ if (!nbr)
+ continue;
+
+ nbr->v_inactivity = OSPF_IF_PARAM(oi, v_wait);
+ nbr->v_db_desc = OSPF_IF_PARAM(oi, retransmit_interval);
+ nbr->v_ls_req = OSPF_IF_PARAM(oi, retransmit_interval);
+ nbr->v_ls_upd = OSPF_IF_PARAM(oi, retransmit_interval);
+ }
}
static int ospf_vty_dead_interval_set(struct vty *vty, const char *interval_str,
for (ALL_LIST_ELEMENTS_RO(ospf->areas, ln, area)) {
SET_FLAG(area->stub_router_state,
OSPF_AREA_WAS_START_STUB_ROUTED);
- OSPF_TIMER_OFF(area->t_stub_router);
+ THREAD_OFF(area->t_stub_router);
/* Don't trample on admin stub routed */
if (!CHECK_FLAG(area->stub_router_state,
static void ospf_deferred_shutdown_finish(struct ospf *ospf)
{
ospf->stub_router_shutdown_time = OSPF_STUB_ROUTER_UNCONFIGURED;
- OSPF_TIMER_OFF(ospf->t_deferred_shutdown);
+ THREAD_OFF(ospf->t_deferred_shutdown);
ospf_finish_final(ospf);
/* Clear static neighbors */
for (rn = route_top(ospf->nbr_nbma); rn; rn = route_next(rn))
if ((nbr_nbma = rn->info)) {
- OSPF_POLL_TIMER_OFF(nbr_nbma->t_poll);
+ THREAD_OFF(nbr_nbma->t_poll);
if (nbr_nbma->nbr) {
nbr_nbma->nbr->nbr_nbma = NULL;
}
/* Cancel all timers. */
- OSPF_TIMER_OFF(ospf->t_read);
- OSPF_TIMER_OFF(ospf->t_write);
- OSPF_TIMER_OFF(ospf->t_spf_calc);
- OSPF_TIMER_OFF(ospf->t_ase_calc);
- OSPF_TIMER_OFF(ospf->t_maxage);
- OSPF_TIMER_OFF(ospf->t_maxage_walker);
- OSPF_TIMER_OFF(ospf->t_abr_task);
- OSPF_TIMER_OFF(ospf->t_asbr_check);
- OSPF_TIMER_OFF(ospf->t_asbr_nssa_redist_update);
- OSPF_TIMER_OFF(ospf->t_distribute_update);
- OSPF_TIMER_OFF(ospf->t_lsa_refresher);
- OSPF_TIMER_OFF(ospf->t_opaque_lsa_self);
- OSPF_TIMER_OFF(ospf->t_sr_update);
- OSPF_TIMER_OFF(ospf->t_default_routemap_timer);
- OSPF_TIMER_OFF(ospf->t_external_aggr);
- OSPF_TIMER_OFF(ospf->gr_info.t_grace_period);
+ THREAD_OFF(ospf->t_read);
+ THREAD_OFF(ospf->t_write);
+ THREAD_OFF(ospf->t_spf_calc);
+ THREAD_OFF(ospf->t_ase_calc);
+ THREAD_OFF(ospf->t_maxage);
+ THREAD_OFF(ospf->t_maxage_walker);
+ THREAD_OFF(ospf->t_abr_task);
+ THREAD_OFF(ospf->t_asbr_check);
+ THREAD_OFF(ospf->t_asbr_nssa_redist_update);
+ THREAD_OFF(ospf->t_distribute_update);
+ THREAD_OFF(ospf->t_lsa_refresher);
+ THREAD_OFF(ospf->t_opaque_lsa_self);
+ THREAD_OFF(ospf->t_sr_update);
+ THREAD_OFF(ospf->t_default_routemap_timer);
+ THREAD_OFF(ospf->t_external_aggr);
+ THREAD_OFF(ospf->gr_info.t_grace_period);
LSDB_LOOP (OPAQUE_AS_LSDB(ospf), rn, lsa)
ospf_discard_from_db(ospf, ospf->lsdb, lsa);
free(IMPORT_NAME(area));
/* Cancel timer. */
- OSPF_TIMER_OFF(area->t_stub_router);
- OSPF_TIMER_OFF(area->t_opaque_lsa_self);
+ THREAD_OFF(area->t_stub_router);
+ THREAD_OFF(area->t_opaque_lsa_self);
if (OSPF_IS_AREA_BACKBONE(area))
area->ospf->backbone = NULL;
}
/* remove update event */
- thread_cancel(&oi->t_ls_upd_event);
+ THREAD_OFF(oi->t_ls_upd_event);
}
void ospf_if_update(struct ospf *ospf, struct interface *ifp)
- (monotime(NULL) - ospf->lsa_refresher_started);
if (time_left > interval) {
- OSPF_TIMER_OFF(ospf->t_lsa_refresher);
+ THREAD_OFF(ospf->t_lsa_refresher);
thread_add_timer(master, ospf_lsa_refresh_walker, ospf,
interval, &ospf->t_lsa_refresher);
}
- (monotime(NULL) - ospf->lsa_refresher_started);
if (time_left > OSPF_LSA_REFRESH_INTERVAL_DEFAULT) {
- OSPF_TIMER_OFF(ospf->t_lsa_refresher);
+ THREAD_OFF(ospf->t_lsa_refresher);
ospf->t_lsa_refresher = NULL;
thread_add_timer(master, ospf_lsa_refresh_walker, ospf,
OSPF_LSA_REFRESH_INTERVAL_DEFAULT,
static void ospf_nbr_nbma_down(struct ospf_nbr_nbma *nbr_nbma)
{
- OSPF_TIMER_OFF(nbr_nbma->t_poll);
+ THREAD_OFF(nbr_nbma->t_poll);
if (nbr_nbma->nbr) {
nbr_nbma->nbr->nbr_nbma = NULL;
if (nbr_nbma->v_poll != interval) {
nbr_nbma->v_poll = interval;
if (nbr_nbma->oi && ospf_if_is_up(nbr_nbma->oi)) {
- OSPF_TIMER_OFF(nbr_nbma->t_poll);
+ THREAD_OFF(nbr_nbma->t_poll);
OSPF_POLL_TIMER_ON(nbr_nbma->t_poll, ospf_poll_timer,
nbr_nbma->v_poll);
}
if (IS_DEBUG_OSPF_EVENT)
zlog_debug("%s: ospf old_vrf_id %d unlinked", __func__,
old_vrf_id);
- thread_cancel(&ospf->t_read);
+ THREAD_OFF(ospf->t_read);
close(ospf->fd);
ospf->fd = -1;
}
#define OSPF_TIMER_ON(T,F,V) thread_add_timer (master,(F),ospf,(V),&(T))
#define OSPF_AREA_TIMER_ON(T,F,V) thread_add_timer (master, (F), area, (V), &(T))
#define OSPF_POLL_TIMER_ON(T,F,V) thread_add_timer (master, (F), nbr_nbma, (V), &(T))
-#define OSPF_POLL_TIMER_OFF(X) OSPF_TIMER_OFF((X))
-#define OSPF_TIMER_OFF(X) thread_cancel(&(X))
/* Extern variables. */
extern struct ospf_master *om;
* possibly disconnect and blacklist */
flog_warn(EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE,
"Unsupported PCEP protocol feature: %s", err);
- pcep_free_path(path);
send_pcep_error(pcc_state, PCEP_ERRT_INVALID_OPERATION,
PCEP_ERRV_LSP_NOT_PCE_INITIATED, path);
+ pcep_free_path(path);
}
}
/* Connect to the LM. */
path_zebra_label_manager_connect();
}
+
+void path_zebra_stop(void)
+{
+ zclient_stop(zclient);
+ zclient_free(zclient);
+}
int path_zebra_request_label(mpls_label_t label);
void path_zebra_release_label(mpls_label_t label);
void path_zebra_init(struct thread_master *master);
+void path_zebra_stop(void);
#endif /* _FRR_PATH_MPLS_H_ */
RB_FOREACH_SAFE (policy, srte_policy_head, &srte_policies, safe_pol)
srte_policy_del(policy);
+
+ path_zebra_stop();
}
/**
{
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
if (pbrms->dst && pbrms->family && prefix->family != pbrms->family) {
vty_out(vty, "Cannot mismatch families within match src/dst\n");
return CMD_WARNING_CONFIG_FAILED;
{
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
if (pbrms->src && pbrms->family && prefix->family != pbrms->family) {
vty_out(vty, "Cannot mismatch families within match src/dst\n");
return CMD_WARNING_CONFIG_FAILED;
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
struct protoent *p;
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
if (!no) {
p = getprotobyname(ip_proto);
if (!p) {
{
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
if (!no) {
if (pbrms->src_prt == port)
return CMD_SUCCESS;
{
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
if (!no) {
if (pbrms->dst_prt == port)
return CMD_SUCCESS;
char dscpname[100];
uint8_t rawDscp;
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
/* Discriminate dscp enums (cs0, cs1 etc.) and numbers */
bool isANumber = true;
for (int i = 0; i < (int)strlen(dscp); i++) {
{
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
if (!no) {
if ((pbrms->dsfield & PBR_DSFIELD_ECN) == ecn)
return CMD_SUCCESS;
{
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
#ifndef GNU_LINUX
vty_out(vty, "pbr marks are not supported on this platform\n");
return CMD_WARNING_CONFIG_FAILED;
{
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
if (!no)
pbrms->action_queue_id = queue_id;
else if ((uint32_t)queue_id == pbrms->action_queue_id)
{
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
if (!no)
pbrms->action_pcp = pcp;
else if (pcp == pbrms->action_pcp)
{
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
if (!no)
pbrms->action_vlan_id = vlan_id;
else if (pbrms->action_vlan_id == vlan_id)
{
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
if (!no)
pbrms->action_vlan_flags = PBR_MAP_STRIP_INNER_ANY;
else
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
struct nexthop_group_cmd *nhgc;
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
nhgc = nhgc_find(name);
if (!nhgc) {
vty_out(vty, "Specified nexthop-group %s does not exist\n",
{
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
pbrms_clear_set_config(pbrms);
return CMD_SUCCESS;
struct nexthop nhop;
struct nexthop *nh = NULL;
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
if (vrf_name)
vrf = vrf_lookup_by_name(vrf_name);
else
{
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
pbrms_clear_set_config(pbrms);
return CMD_SUCCESS;
{
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
/*
* If an equivalent set vrf * exists, just return success.
*/
{
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
pbrms_clear_set_config(pbrms);
return CMD_SUCCESS;
const struct rtnl_dump_filter_arg *arg)
{
struct sockaddr_nl nladdr;
- struct iovec iov;
+ char buf[16384];
+ struct iovec iov = {
+ .iov_base = buf,
+ .iov_len = sizeof(buf),
+ };
struct msghdr msg = {
.msg_name = &nladdr,
.msg_namelen = sizeof(nladdr),
.msg_iov = &iov,
.msg_iovlen = 1,
};
- char buf[16384];
- iov.iov_base = buf;
while (1) {
int status;
const struct rtnl_dump_filter_arg *a;
}
for (a = arg; a->filter; a++) {
- struct nlmsghdr *h = (struct nlmsghdr *)buf;
+ struct nlmsghdr *h = (struct nlmsghdr *)iov.iov_base;
msglen = status;
while (NLMSG_OK(h, (uint32_t)msglen)) {
msg.msg_namelen);
exit(1);
}
- for (h = (struct nlmsghdr *)buf; status >= (int)sizeof(*h);) {
+ for (h = (struct nlmsghdr *)iov.iov_base;
+ status >= (int)sizeof(*h);) {
int err;
int len = h->nlmsg_len;
int l = len - sizeof(*h);
int status;
struct nlmsghdr *h;
struct sockaddr_nl nladdr;
- struct iovec iov;
+ char buf[8192];
+ struct iovec iov = {
+ .iov_base = buf,
+ .iov_len = sizeof(buf),
+ };
struct msghdr msg = {
.msg_name = &nladdr,
.msg_namelen = sizeof(nladdr),
.msg_iov = &iov,
.msg_iovlen = 1,
};
- char buf[8192];
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = 0;
nladdr.nl_groups = 0;
- iov.iov_base = buf;
while (1) {
iov.iov_len = sizeof(buf);
status = recvmsg(rtnl->fd, &msg, 0);
DEFPY (interface_no_ipv6_pim_drprio,
interface_no_ipv6_pim_drprio_cmd,
- "no ip pim drpriority [(1-4294967295)]",
+ "no ipv6 pim drpriority [(1-4294967295)]",
NO_STR
IPV6_STR
PIM_STR
"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;
}
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;
}
DEFPY (show_ipv6_pim_nexthop,
show_ipv6_pim_nexthop_cmd,
- "show ipv6 pim [vrf NAME] nexthop",
+ "show ipv6 pim [vrf NAME] nexthop [json$json]",
SHOW_STR
IPV6_STR
PIM_STR
VRF_CMD_HELP_STR
- "PIM cached nexthop rpf information\n")
+ "PIM cached nexthop rpf information\n"
+ JSON_STR)
{
- return pim_show_nexthop_cmd_helper(vrf, vty);
+ return pim_show_nexthop_cmd_helper(vrf, vty, !!json);
}
DEFPY (show_ipv6_pim_nexthop_lookup,
return CMD_SUCCESS;
}
+DEFPY (clear_ipv6_pim_interface_traffic,
+ clear_ipv6_pim_interface_traffic_cmd,
+ "clear ipv6 pim [vrf NAME] interface traffic",
+ CLEAR_STR
+ IPV6_STR
+ CLEAR_IP_PIM_STR
+ VRF_CMD_HELP_STR
+ "Reset PIM interfaces\n"
+ "Reset Protocol Packet counters\n")
+{
+ return clear_pim_interface_traffic(vrf, vty);
+}
+
DEFPY (clear_ipv6_mroute,
clear_ipv6_mroute_cmd,
"clear ipv6 mroute [vrf NAME]$name",
CLEAR_STR
IPV6_STR
- "Reset multicast routes\n"
+ MROUTE_STR
VRF_CMD_HELP_STR)
{
struct vrf *v = pim_cmd_lookup(vty, name);
return clear_ip_mroute_count_command(vty, name);
}
+DEFPY (clear_ipv6_pim_interfaces,
+ clear_ipv6_pim_interfaces_cmd,
+ "clear ipv6 pim [vrf NAME] interfaces",
+ CLEAR_STR
+ IPV6_STR
+ CLEAR_IP_PIM_STR
+ VRF_CMD_HELP_STR
+ "Reset PIM interfaces\n")
+{
+ struct vrf *v = pim_cmd_lookup(vty, vrf);
+
+ if (!v)
+ return CMD_WARNING;
+
+ clear_pim_interfaces(v->info);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (clear_ipv6_pim_bsr_db,
+ clear_ipv6_pim_bsr_db_cmd,
+ "clear ipv6 pim [vrf NAME] bsr-data",
+ CLEAR_STR
+ IPV6_STR
+ CLEAR_IP_PIM_STR
+ VRF_CMD_HELP_STR
+ "Reset pim bsr data\n")
+{
+ struct vrf *v;
+
+ v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
+ if (!v)
+ return CMD_WARNING;
+
+ pim_bsm_clear(v->info);
+
+ return CMD_SUCCESS;
+}
+
DEFPY (debug_pimv6,
debug_pimv6_cmd,
"[no] debug pimv6",
return CMD_SUCCESS;
}
+DEFPY (debug_mroute6,
+ debug_mroute6_cmd,
+ "[no] debug mroute6",
+ NO_STR
+ DEBUG_STR
+ DEBUG_MROUTE6_STR)
+{
+ if (!no)
+ PIM_DO_DEBUG_MROUTE;
+ else
+ PIM_DONT_DEBUG_MROUTE;
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (debug_mroute6_detail,
+ debug_mroute6_detail_cmd,
+ "[no] debug mroute6 detail",
+ NO_STR
+ DEBUG_STR
+ DEBUG_MROUTE6_STR
+ "detailed\n")
+{
+ if (!no)
+ PIM_DO_DEBUG_MROUTE_DETAIL;
+ else
+ PIM_DONT_DEBUG_MROUTE_DETAIL;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_NOSH (show_debugging_pimv6,
+ show_debugging_pimv6_cmd,
+ "show debugging [pimv6]",
+ SHOW_STR
+ DEBUG_STR
+ "PIMv6 Information\n")
+{
+ vty_out(vty, "PIMv6 debugging status\n");
+
+ pim_debug_config_write(vty);
+
+ return CMD_SUCCESS;
+}
+
void pim_cmd_init(void)
{
if_cmd_init(pim_interface_config_write);
install_element(ENABLE_NODE, &clear_ipv6_mroute_cmd);
install_element(ENABLE_NODE, &clear_ipv6_pim_oil_cmd);
install_element(ENABLE_NODE, &clear_ipv6_mroute_count_cmd);
+ install_element(ENABLE_NODE, &clear_ipv6_pim_bsr_db_cmd);
+ install_element(ENABLE_NODE, &clear_ipv6_pim_interfaces_cmd);
+ install_element(ENABLE_NODE, &clear_ipv6_pim_interface_traffic_cmd);
+
+ install_element(ENABLE_NODE, &show_debugging_pimv6_cmd);
+
install_element(ENABLE_NODE, &debug_pimv6_cmd);
install_element(ENABLE_NODE, &debug_pimv6_nht_cmd);
install_element(ENABLE_NODE, &debug_pimv6_nht_det_cmd);
install_element(ENABLE_NODE, &debug_pimv6_trace_cmd);
install_element(ENABLE_NODE, &debug_pimv6_trace_detail_cmd);
install_element(ENABLE_NODE, &debug_pimv6_zebra_cmd);
+ install_element(ENABLE_NODE, &debug_mroute6_cmd);
+ install_element(ENABLE_NODE, &debug_mroute6_detail_cmd);
install_element(CONFIG_NODE, &debug_pimv6_cmd);
install_element(CONFIG_NODE, &debug_pimv6_nht_cmd);
install_element(CONFIG_NODE, &debug_pimv6_trace_cmd);
install_element(CONFIG_NODE, &debug_pimv6_trace_detail_cmd);
install_element(CONFIG_NODE, &debug_pimv6_zebra_cmd);
+ install_element(CONFIG_NODE, &debug_mroute6_cmd);
+ install_element(CONFIG_NODE, &debug_mroute6_detail_cmd);
}
#define DEBUG_PIMV6_PACKETDUMP_RECV_STR "Dump received packets\n"
#define DEBUG_PIMV6_TRACE_STR "PIMv6 internal daemon activity\n"
#define DEBUG_PIMV6_ZEBRA_STR "ZEBRA protocol activity\n"
+#define DEBUG_MROUTE6_STR "PIMv6 interaction with kernel MFC cache\n"
void pim_cmd_init(void);
}
pim_router_init();
- /* TODO PIM6: temporary enable all debugs, remove later in PIMv6 work */
- router->debugs = ~0U;
access_list_init();
prefix_list_init();
}
}
+void gm_group_delete(struct gm_if *gm_ifp)
+{
+ struct gm_sg *sg, *sg_start;
+
+ sg_start = gm_sgs_first(gm_ifp->sgs);
+
+ /* clean up all mld groups */
+ frr_each_from (gm_sgs, gm_ifp->sgs, sg, sg_start) {
+ THREAD_OFF(sg->t_sg_expire);
+ if (sg->oil)
+ pim_channel_oil_del(sg->oil, __func__);
+ gm_sgs_del(gm_ifp->sgs, sg);
+ gm_sg_free(sg);
+ }
+}
+
/*
* CLI (show commands only)
*/
#if PIM_IPV == 6
extern void gm_ifp_update(struct interface *ifp);
extern void gm_ifp_teardown(struct interface *ifp);
+extern void gm_group_delete(struct gm_if *gm_ifp);
#else
static inline void gm_ifp_update(struct interface *ifp)
{
+++ /dev/null
-/*
- * PIMv6 temporary stubs
- * Copyright (C) 2022 David Lamparter for NetDEF, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <zebra.h>
-
-#include "pimd.h"
-#include "pim_nht.h"
-#include "pim_zlookup.h"
-#include "pim_pim.h"
-#include "pim_register.h"
-#include "pim_cmd.h"
-#include "pim_bsm.h"
-
-/*
- * NH lookup / NHT
- */
-void pim_nht_bsr_add(struct pim_instance *pim, struct in_addr addr)
-{
-}
-
-void pim_nht_bsr_del(struct pim_instance *pim, struct in_addr addr)
-{
-}
-
-bool pim_bsm_new_nbr_fwd(struct pim_neighbor *neigh, struct interface *ifp)
-{
- return false;
-}
-
-void pim_bsm_proc_free(struct pim_instance *pim)
-{
-}
-
-void pim_bsm_proc_init(struct pim_instance *pim)
-{
-}
-
-struct bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope,
- struct prefix *grp)
-{
- return NULL;
-}
-
-void pim_bsm_write_config(struct vty *vty, struct interface *ifp)
-{
-}
-
-int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
- uint32_t buf_size, bool no_fwd)
-{
- return 0;
-}
#define ipaddr_pim ipaddr_v4
#define PIM_MAX_BITLEN IPV4_MAX_BITLEN
#define PIM_AF_NAME "ip"
+#define PIM_AF_DBG "pim"
+#define PIM_MROUTE_DBG "mroute"
#define PIMREG "pimreg"
#define GM "IGMP"
#define ipaddr_pim ipaddr_v6
#define PIM_MAX_BITLEN IPV6_MAX_BITLEN
#define PIM_AF_NAME "ipv6"
+#define PIM_AF_DBG "pimv6"
+#define PIM_MROUTE_DBG "mroute6"
#define PIMREG "pim6reg"
#define GM "MLD"
return 1;
if (node1->hash > node2->hash)
return -1;
- if (node1->rp_address.s_addr < node2->rp_address.s_addr)
- return 1;
- if (node1->rp_address.s_addr > node2->rp_address.s_addr)
- return -1;
- return 0;
+ return pim_addr_cmp(node2->rp_address, node1->rp_address);
}
static struct bsgrp_node *pim_bsm_new_bsgrp_node(struct route_table *rt,
__func__, scope->sz_id);
pim_nht_bsr_del(scope->pim, scope->current_bsr);
-
/* Reset scope zone data */
scope->accept_nofwd_bsm = false;
scope->state = ACCEPT_ANY;
- scope->current_bsr.s_addr = INADDR_ANY;
+ scope->current_bsr = PIMADDR_ANY;
scope->current_bsr_prio = 0;
scope->current_bsr_first_ts = 0;
scope->current_bsr_last_ts = 0;
THREAD_OFF(bsrp->g2rp_timer);
if (PIM_DEBUG_BSM)
zlog_debug(
- "%s : starting g2rp timer for grp: %pFX - rp: %pI4 with timeout %d secs(Actual Hold time : %d secs)",
- __func__, &bsrp->bsgrp_node->group,
- &bsrp->rp_address, hold_time,
- bsrp->rp_holdtime);
+ "%s : starting g2rp timer for grp: %pFX - rp: %pPAs with timeout %d secs(Actual Hold time : %d secs)",
+ __func__, &bsrp->bsgrp_node->group, &bsrp->rp_address,
+ hold_time, bsrp->rp_holdtime);
thread_add_timer(router->master, pim_on_g2rp_timer, bsrp, hold_time,
&bsrp->g2rp_timer);
return;
if (PIM_DEBUG_BSM)
- zlog_debug("%s : stopping g2rp timer for grp: %pFX - rp: %pI4",
+ zlog_debug("%s : stopping g2rp timer for grp: %pFX - rp: %pPAs",
__func__, &bsrp->bsgrp_node->group,
&bsrp->rp_address);
route_unlock_node(rn);
if (active && pend) {
- if ((active->rp_address.s_addr
- != pend->rp_address.s_addr))
+ if (pim_addr_cmp(active->rp_address, pend->rp_address))
pim_rp_change(pim, pend->rp_address,
bsgrp_node->group, RP_SRC_BSR);
}
pim_bsm_rpinfos_free(bsgrp_node->partial_bsrp_list);
}
-static bool is_preferred_bsr(struct pim_instance *pim, struct in_addr bsr,
+static bool is_preferred_bsr(struct pim_instance *pim, pim_addr bsr,
uint32_t bsr_prio)
{
- if (bsr.s_addr == pim->global_scope.current_bsr.s_addr)
+ if (!pim_addr_cmp(bsr, pim->global_scope.current_bsr))
return true;
if (bsr_prio > pim->global_scope.current_bsr_prio)
return true;
else if (bsr_prio == pim->global_scope.current_bsr_prio) {
- if (ntohl(bsr.s_addr)
- >= ntohl(pim->global_scope.current_bsr.s_addr))
+ if (pim_addr_cmp(bsr, pim->global_scope.current_bsr) >= 0)
return true;
else
return false;
return false;
}
-static void pim_bsm_update(struct pim_instance *pim, struct in_addr bsr,
+static void pim_bsm_update(struct pim_instance *pim, pim_addr bsr,
uint32_t bsr_prio)
{
- if (bsr.s_addr != pim->global_scope.current_bsr.s_addr) {
+ if (pim_addr_cmp(bsr, pim->global_scope.current_bsr)) {
pim_nht_bsr_del(pim, pim->global_scope.current_bsr);
pim_nht_bsr_add(pim, bsr);
struct route_node *rn;
struct route_node *rpnode;
struct bsgrp_node *bsgrp;
- struct prefix nht_p;
+ pim_addr nht_p;
struct prefix g_all;
struct rp_info *rp_all;
struct pim_upstream *up;
/* Reset scope zone data */
pim->global_scope.accept_nofwd_bsm = false;
pim->global_scope.state = ACCEPT_ANY;
- pim->global_scope.current_bsr.s_addr = INADDR_ANY;
+ pim->global_scope.current_bsr = PIMADDR_ANY;
pim->global_scope.current_bsr_prio = 0;
pim->global_scope.current_bsr_first_ts = 0;
pim->global_scope.current_bsr_last_ts = 0;
}
/* Deregister addr with Zebra NHT */
- nht_p.family = AF_INET;
- nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
+ nht_p = rp_info->rp.rpf_addr;
if (PIM_DEBUG_PIM_NHT_RP) {
- zlog_debug("%s: Deregister RP addr %pFX with Zebra ",
+ zlog_debug("%s: Deregister RP addr %pPA with Zebra ",
__func__, &nht_p);
}
- pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info);
+ pim_delete_tracked_nexthop(pim, nht_p, NULL, rp_info);
if (!pim_get_all_mcast_group(&g_all))
return;
rp_all = pim_rp_find_match_group(pim, &g_all);
if (rp_all == rp_info) {
- pim_addr_to_prefix(&rp_all->rp.rpf_addr, PIMADDR_ANY);
+ rp_all->rp.rpf_addr = PIMADDR_ANY;
rp_all->i_am_rp = 0;
} else {
/* Delete the rp_info from rp-list */
struct pim_interface *pim_ifp;
struct bsm_scope *scope;
struct bsm_frag *bsfrag;
- char neigh_src_str[INET_ADDRSTRLEN];
uint32_t pim_mtu;
bool no_fwd = true;
bool ret = false;
if (!pim_ifp->ucast_bsm_accept) {
dst_addr = qpim_all_pim_routers_addr;
if (PIM_DEBUG_BSM)
- zlog_debug("%s: Sending BSM mcast to %s", __func__,
- neigh_src_str);
+ zlog_debug("%s: Sending BSM mcast to %pPA", __func__,
+ &neigh->source_addr);
} else {
dst_addr = neigh->source_addr;
if (PIM_DEBUG_BSM)
- zlog_debug("%s: Sending BSM ucast to %s", __func__,
- neigh_src_str);
+ zlog_debug("%s: Sending BSM ucast to %pPA", __func__,
+ &neigh->source_addr);
}
pim_mtu = ifp->mtu - MAX_IP_HDR_LEN;
pim_hello_require(ifp);
return bsgrp;
}
-static uint32_t hash_calc_on_grp_rp(struct prefix group, struct in_addr rp,
+static uint32_t hash_calc_on_grp_rp(struct prefix group, pim_addr rp,
uint8_t hashmasklen)
{
uint64_t temp;
/* in_addr stores ip in big endian, hence network byte order
* convert to uint32 before processing hash
*/
+#if PIM_IPV == 4
grpaddr = ntohl(group.u.prefix4.s_addr);
+#else
+ grpaddr = group.u.prefix6.s6_addr32[0] ^ group.u.prefix6.s6_addr32[1] ^
+ group.u.prefix6.s6_addr32[2] ^ group.u.prefix6.s6_addr32[3];
+#endif
/* Avoid shifting by 32 bit on a 32 bit register */
if (hashmasklen)
grpaddr = grpaddr & ((mask << (32 - hashmasklen)));
else
grpaddr = grpaddr & mask;
+
+#if PIM_IPV == 4
rp_add = ntohl(rp.s_addr);
+#else
+ rp_add = rp.s6_addr32[0] ^ rp.s6_addr32[1] ^ rp.s6_addr32[2] ^
+ rp.s6_addr32[3];
+#endif
temp = 1103515245 * ((1103515245 * (uint64_t)grpaddr + 12345) ^ rp_add)
+ 12345;
hash = temp & (0x7fffffff);
bsm_rpinfo->rp_prio = rp->rp_pri;
bsm_rpinfo->rp_holdtime = rp->rp_holdtime;
- memcpy(&bsm_rpinfo->rp_address, &rp->rpaddr.addr,
- sizeof(struct in_addr));
+ bsm_rpinfo->rp_address = rp->rpaddr.addr;
bsm_rpinfo->elapse_time = 0;
/* Back pointer to the group node. */
int frag_rp_cnt = 0;
int offset = 0;
int ins_count = 0;
+ pim_addr grp_addr;
while (buflen > offset) {
if (offset + (int)sizeof(struct bsmmsg_grpinfo) > buflen) {
}
/* Extract Group tlv from BSM */
memcpy(&grpinfo, buf, sizeof(struct bsmmsg_grpinfo));
+ grp_addr = grpinfo.group.addr;
- if (PIM_DEBUG_BSM) {
- char grp_str[INET_ADDRSTRLEN];
-
- pim_inet4_dump("<Group?>", grpinfo.group.addr, grp_str,
- sizeof(grp_str));
+ if (PIM_DEBUG_BSM)
zlog_debug(
- "%s, Group %s Rpcount:%d Fragment-Rp-count:%d",
- __func__, grp_str, grpinfo.rp_count,
+ "%s, Group %pPAs Rpcount:%d Fragment-Rp-count:%d",
+ __func__, &grp_addr, grpinfo.rp_count,
grpinfo.frag_rp_count);
- }
buf += sizeof(struct bsmmsg_grpinfo);
offset += sizeof(struct bsmmsg_grpinfo);
- group.family = AF_INET;
- if (grpinfo.group.mask > IPV4_MAX_BITLEN) {
+ group.family = PIM_AF;
+ if (grpinfo.group.mask > PIM_MAX_BITLEN) {
if (PIM_DEBUG_BSM)
zlog_debug(
- "%s, v4 prefix length specified: %d is too long",
+ "%s, prefix length specified: %d is too long",
__func__, grpinfo.group.mask);
return false;
}
+
+ pim_addr_to_prefix(&group, grp_addr);
group.prefixlen = grpinfo.group.mask;
- group.u.prefix4.s_addr = grpinfo.group.addr.s_addr;
/* Get the Group node for the BSM rp table */
bsgrp = pim_bsm_get_bsgrp_node(scope, &group);
if (!bsgrp)
continue;
- if (PIM_DEBUG_BSM) {
- char grp_str[INET_ADDRSTRLEN];
-
- pim_inet4_dump("<Group?>", grpinfo.group.addr,
- grp_str, sizeof(grp_str));
- zlog_debug("%s, Rp count is zero for group: %s",
- __func__, grp_str);
- }
+ if (PIM_DEBUG_BSM)
+ zlog_debug(
+ "%s, Rp count is zero for group: %pPAs",
+ __func__, &grp_addr);
old_rpinfo = bsm_rpinfos_first(bsgrp->bsrp_list);
if (old_rpinfo)
offset += sizeof(struct bsmmsg_rpinfo);
if (PIM_DEBUG_BSM) {
- char rp_str[INET_ADDRSTRLEN];
+ pim_addr rp_addr;
- pim_inet4_dump("<Rpaddr?>", rpinfo.rpaddr.addr,
- rp_str, sizeof(rp_str));
+ rp_addr = rpinfo.rpaddr.addr;
zlog_debug(
- "%s, Rp address - %s; pri:%d hold:%d",
- __func__, rp_str, rpinfo.rp_pri,
+ "%s, Rp address - %pPAs; pri:%d hold:%d",
+ __func__, &rp_addr, rpinfo.rp_pri,
rpinfo.rp_holdtime);
}
struct pim_interface *pim_ifp = NULL;
struct bsm_frag *bsfrag;
struct pim_instance *pim;
- char bsr_str[INET_ADDRSTRLEN];
uint16_t frag_tag;
+ pim_addr bsr_addr;
bool empty_bsm = false;
/* BSM Packet acceptance validation */
}
bshdr = (struct bsm_hdr *)(buf + PIM_MSG_HEADER_LEN);
- pim_inet4_dump("<bsr?>", bshdr->bsr_addr.addr, bsr_str,
- sizeof(bsr_str));
- if (bshdr->hm_len > IPV4_MAX_BITLEN) {
- zlog_warn("Bad hashmask length for IPv4; got %hhu, expected value in range 0-32",
- bshdr->hm_len);
+ if (bshdr->hm_len > PIM_MAX_BITLEN) {
+ zlog_warn(
+ "Bad hashmask length for %s; got %hhu, expected value in range 0-32",
+ PIM_AF_NAME, bshdr->hm_len);
pim->bsm_dropped++;
return -1;
}
pim->global_scope.hashMasklen = bshdr->hm_len;
frag_tag = ntohs(bshdr->frag_tag);
+ /* NB: bshdr->bsr_addr.addr is packed/unaligned => memcpy */
+ memcpy(&bsr_addr, &bshdr->bsr_addr.addr, sizeof(bsr_addr));
/* Identify empty BSM */
if ((buf_size - PIM_BSM_HDR_LEN - PIM_MSG_HEADER_LEN) < PIM_BSM_GRP_LEN)
}
/* Drop if bsr is not preferred bsr */
- if (!is_preferred_bsr(pim, bshdr->bsr_addr.addr, bshdr->bsr_prio)) {
+ if (!is_preferred_bsr(pim, bsr_addr, bshdr->bsr_prio)) {
if (PIM_DEBUG_BSM)
zlog_debug("%s : Received a non-preferred BSM",
__func__);
} else {
if (PIM_DEBUG_BSM)
zlog_debug(
- "%s : nofwd_bsm received on %s when accpt_nofwd_bsm false",
- __func__, bsr_str);
+ "%s : nofwd_bsm received on %pPAs when accpt_nofwd_bsm false",
+ __func__, &bsr_addr);
pim->bsm_dropped++;
pim_ifp->pim_ifstat_ucast_bsm_cfg_miss++;
return -1;
}
}
-#if PIM_IPV == 4
- if (!pim_addr_cmp(sg->grp, qpim_all_pim_routers_addr))
-#else
- if (0)
-#endif
- {
+ if (!pim_addr_cmp(sg->grp, qpim_all_pim_routers_addr)) {
/* Multicast BSMs are only accepted if source interface & IP
* match RPF towards the BSR's IP address, or they have
* no-forward set
*/
- if (!no_fwd && !pim_nht_bsr_rpf_check(pim, bshdr->bsr_addr.addr,
- ifp, sg->src)) {
+ if (!no_fwd &&
+ !pim_nht_bsr_rpf_check(pim, bsr_addr, ifp, sg->src)) {
if (PIM_DEBUG_BSM)
zlog_debug(
- "BSM check: RPF to BSR %s is not %pPA%%%s",
- bsr_str, &sg->src, ifp->name);
+ "BSM check: RPF to BSR %pPAs is not %pPA%%%s",
+ &bsr_addr, &sg->src, ifp->name);
pim->bsm_dropped++;
return -1;
}
}
/* update the scope information from bsm */
- pim_bsm_update(pim, bshdr->bsr_addr.addr, bshdr->bsr_prio);
+ pim_bsm_update(pim, bsr_addr, bshdr->bsr_prio);
if (!no_fwd) {
pim_bsm_fwd_whole_sz(pim_ifp->pim, buf, buf_size, sz);
int sz_id; /* scope zone id */
enum ncbsr_state state; /* non candidate BSR state */
bool accept_nofwd_bsm; /* no fwd bsm accepted for scope */
- struct in_addr current_bsr; /* current elected BSR for the sz */
+ pim_addr current_bsr; /* current elected BSR for the sz */
uint32_t current_bsr_prio; /* current BSR priority */
int64_t current_bsr_first_ts; /* current BSR elected time */
int64_t current_bsr_last_ts; /* Last BSM received from E-BSR */
uint16_t frag_tag;
uint8_t hm_len;
uint8_t bsr_prio;
+#if PIM_IPV == 4
struct pim_encoded_ipv4_unicast bsr_addr;
+#else
+ struct pim_encoded_ipv6_unicast bsr_addr;
+#endif
} __attribute__((packed));
struct bsmmsg_grpinfo {
+#if PIM_IPV == 4
struct pim_encoded_group_ipv4 group;
+#else
+ struct pim_encoded_group_ipv6 group;
+#endif
uint8_t rp_count;
uint8_t frag_rp_count;
uint16_t reserved;
} __attribute__((packed));
struct bsmmsg_rpinfo {
+#if PIM_IPV == 4
struct pim_encoded_ipv4_unicast rpaddr;
+#else
+ struct pim_encoded_ipv6_unicast rpaddr;
+#endif
uint16_t rp_holdtime;
uint8_t rp_pri;
uint8_t reserved;
frr_each (bsm_frags, pim->global_scope.bsm_frags, bsfrag) {
char grp_str[PREFIX_STRLEN];
- char rp_str[INET_ADDRSTRLEN];
- char bsr_str[INET_ADDRSTRLEN];
struct bsmmsg_grpinfo *group;
- struct bsmmsg_rpinfo *rpaddr;
+ struct bsmmsg_rpinfo *bsm_rpinfo;
struct prefix grp;
struct bsm_hdr *hdr;
+ pim_addr bsr_addr;
uint32_t offset = 0;
uint8_t *buf;
uint32_t len = 0;
len -= PIM_MSG_HEADER_LEN;
hdr = (struct bsm_hdr *)buf;
+ /* NB: bshdr->bsr_addr.addr is packed/unaligned => memcpy */
+ memcpy(&bsr_addr, &hdr->bsr_addr.addr, sizeof(bsr_addr));
/* BSM starts with bsr header */
buf += sizeof(struct bsm_hdr);
len -= sizeof(struct bsm_hdr);
- pim_inet4_dump("<BSR Address?>", hdr->bsr_addr.addr, bsr_str,
- sizeof(bsr_str));
-
-
if (uj) {
- json_object_string_add(json, "BSR address", bsr_str);
+ json_object_string_addf(json, "BSR address", "%pPA",
+ &bsr_addr);
json_object_int_add(json, "BSR priority",
hdr->bsr_prio);
json_object_int_add(json, "Hashmask Length",
vty_out(vty, "------------------\n");
vty_out(vty, "%-15s %-15s %-15s %-15s\n", "BSR-Address",
"BSR-Priority", "Hashmask-len", "Fragment-Tag");
- vty_out(vty, "%-15s %-15d %-15d %-15d\n", bsr_str,
+ vty_out(vty, "%-15pPA %-15d %-15d %-15d\n", &bsr_addr,
hdr->bsr_prio, hdr->hm_len,
ntohs(hdr->frag_tag));
}
if (group->group.family == PIM_MSG_ADDRESS_FAMILY_IPV4)
grp.family = AF_INET;
+ else if (group->group.family ==
+ PIM_MSG_ADDRESS_FAMILY_IPV6)
+ grp.family = AF_INET6;
grp.prefixlen = group->group.mask;
- grp.u.prefix4.s_addr = group->group.addr.s_addr;
+#if PIM_IPV == 4
+ grp.u.prefix4 = group->group.addr;
+#else
+ grp.u.prefix6 = group->group.addr;
+#endif
prefix2str(&grp, grp_str, sizeof(grp_str));
"RpAddress HoldTime Priority\n");
while (frag_rp_cnt--) {
- rpaddr = (struct bsmmsg_rpinfo *)buf;
+ pim_addr rp_addr;
+
+ bsm_rpinfo = (struct bsmmsg_rpinfo *)buf;
+ /* unaligned, again */
+ memcpy(&rp_addr, &bsm_rpinfo->rpaddr,
+ sizeof(rp_addr));
buf += sizeof(struct bsmmsg_rpinfo);
offset += sizeof(struct bsmmsg_rpinfo);
- pim_inet4_dump("<Rp addr?>",
- rpaddr->rpaddr.addr, rp_str,
- sizeof(rp_str));
-
if (uj) {
json_row = json_object_new_object();
- json_object_string_add(
- json_row, "Rp Address", rp_str);
+ json_object_string_addf(
+ json_row, "Rp Address", "%pPA",
+ &rp_addr);
json_object_int_add(
json_row, "Rp HoldTime",
- ntohs(rpaddr->rp_holdtime));
+ ntohs(bsm_rpinfo->rp_holdtime));
json_object_int_add(json_row,
"Rp Priority",
- rpaddr->rp_pri);
- json_object_object_add(
- json_group, rp_str, json_row);
+ bsm_rpinfo->rp_pri);
+ json_object_object_addf(
+ json_group, json_row, "%pPA",
+ &rp_addr);
} else {
- vty_out(vty, "%-15s %-12d %d\n", rp_str,
- ntohs(rpaddr->rp_holdtime),
- rpaddr->rp_pri);
+ vty_out(vty, "%-15pPA %-12d %d\n",
+ &rp_addr,
+ ntohs(bsm_rpinfo->rp_holdtime),
+ bsm_rpinfo->rp_pri);
}
}
vty_out(vty, "\n");
struct bsgrp_node *bsgrp;
struct bsm_rpinfo *bsm_rp;
struct route_node *rn;
- char bsr_str[INET_ADDRSTRLEN];
json_object *json = NULL;
json_object *json_group = NULL;
json_object *json_row = NULL;
- if (pim->global_scope.current_bsr.s_addr == INADDR_ANY)
- strlcpy(bsr_str, "0.0.0.0", sizeof(bsr_str));
-
- else
- pim_inet4_dump("<bsr?>", pim->global_scope.current_bsr, bsr_str,
- sizeof(bsr_str));
-
if (uj) {
json = json_object_new_object();
- json_object_string_add(json, "BSR Address", bsr_str);
- } else {
- vty_out(vty, "BSR Address %s\n", bsr_str);
- }
+ json_object_string_addf(json, "BSR Address", "%pPA",
+ &pim->global_scope.current_bsr);
+ } else
+ vty_out(vty, "BSR Address %pPA\n",
+ &pim->global_scope.current_bsr);
for (rn = route_top(pim->global_scope.bsrp_table); rn;
rn = route_next(rn)) {
}
frr_each (bsm_rpinfos, bsgrp->bsrp_list, bsm_rp) {
- char rp_str[INET_ADDRSTRLEN];
-
- pim_inet4_dump("<Rp Address?>", bsm_rp->rp_address,
- rp_str, sizeof(rp_str));
-
if (uj) {
json_row = json_object_new_object();
- json_object_string_add(json_row, "Rp Address",
- rp_str);
+ json_object_string_addf(json_row, "Rp Address",
+ "%pPA",
+ &bsm_rp->rp_address);
json_object_int_add(json_row, "Rp HoldTime",
bsm_rp->rp_holdtime);
json_object_int_add(json_row, "Rp Priority",
bsm_rp->rp_prio);
json_object_int_add(json_row, "Hash Val",
bsm_rp->hash);
- json_object_object_add(json_group, rp_str,
- json_row);
+ json_object_object_addf(json_group, json_row,
+ "%pPA",
+ &bsm_rp->rp_address);
} else {
- vty_out(vty, "%-15s %-15u %-15u %-15u\n",
- rp_str, bsm_rp->rp_prio,
+ vty_out(vty, "%-15pPA %-15u %-15u %-15u\n",
+ &bsm_rp->rp_address, bsm_rp->rp_prio,
bsm_rp->rp_holdtime, bsm_rp->hash);
}
}
}
frr_each (bsm_rpinfos, bsgrp->partial_bsrp_list, bsm_rp) {
- char rp_str[INET_ADDRSTRLEN];
-
- pim_inet4_dump("<Rp Addr?>", bsm_rp->rp_address, rp_str,
- sizeof(rp_str));
-
if (uj) {
json_row = json_object_new_object();
- json_object_string_add(json_row, "Rp Address",
- rp_str);
+ json_object_string_addf(json_row, "Rp Address",
+ "%pPA",
+ &bsm_rp->rp_address);
json_object_int_add(json_row, "Rp HoldTime",
bsm_rp->rp_holdtime);
json_object_int_add(json_row, "Rp Priority",
bsm_rp->rp_prio);
json_object_int_add(json_row, "Hash Val",
bsm_rp->hash);
- json_object_object_add(json_group, rp_str,
- json_row);
+ json_object_object_addf(json_group, json_row,
+ "%pPA",
+ &bsm_rp->rp_address);
} else {
- vty_out(vty, "%-15s %-15u %-15u %-15u\n",
- rp_str, bsm_rp->rp_prio,
+ vty_out(vty, "%-15pPA %-15u %-15u %-15u\n",
+ &bsm_rp->rp_address, bsm_rp->rp_prio,
bsm_rp->rp_holdtime, bsm_rp->hash);
}
}
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");
}
char last_bsm_seen[10];
time_t now;
char bsr_state[20];
- char bsr_str[PREFIX_STRLEN];
json_object *json = NULL;
- if (pim->global_scope.current_bsr.s_addr == INADDR_ANY) {
- strlcpy(bsr_str, "0.0.0.0", sizeof(bsr_str));
+ if (pim_addr_is_any(pim->global_scope.current_bsr)) {
pim_time_uptime(uptime, sizeof(uptime),
pim->global_scope.current_bsr_first_ts);
pim_time_uptime(last_bsm_seen, sizeof(last_bsm_seen),
}
else {
- pim_inet4_dump("<bsr?>", pim->global_scope.current_bsr,
- bsr_str, sizeof(bsr_str));
now = pim_time_monotonic_sec();
pim_time_uptime(uptime, sizeof(uptime),
(now - pim->global_scope.current_bsr_first_ts));
strlcpy(bsr_state, "", sizeof(bsr_state));
}
+
if (uj) {
json = json_object_new_object();
- json_object_string_add(json, "bsr", bsr_str);
+ json_object_string_addf(json, "bsr", "%pPA",
+ &pim->global_scope.current_bsr);
json_object_int_add(json, "priority",
pim->global_scope.current_bsr_prio);
json_object_int_add(json, "fragmentTag",
else {
vty_out(vty, "PIMv2 Bootstrap information\n");
- vty_out(vty, "Current preferred BSR address: %s\n", bsr_str);
+ vty_out(vty, "Current preferred BSR address: %pPA\n",
+ &pim->global_scope.current_bsr);
vty_out(vty,
"Priority Fragment-Tag State UpTime\n");
vty_out(vty, " %-12d %-12d %-13s %7s\n",
pim_if_addr_add_all(ifp);
}
-static void clear_pim_interfaces(struct pim_instance *pim)
-{
- struct interface *ifp;
-
- FOR_ALL_INTERFACES (pim->vrf, ifp) {
- if (ifp->info) {
- pim_neighbor_delete_all(ifp, "interface cleared");
- }
- }
-}
-
static void clear_interfaces(struct pim_instance *pim)
{
clear_igmp_interfaces(pim);
"clear ip mroute [vrf NAME]$name",
CLEAR_STR
IP_STR
- "Reset multicast routes\n"
+ MROUTE_STR
VRF_CMD_HELP_STR)
{
struct vrf *v = pim_cmd_lookup(vty, name);
return CMD_SUCCESS;
}
-DEFUN (clear_ip_pim_interfaces,
+DEFPY (clear_ip_pim_interfaces,
clear_ip_pim_interfaces_cmd,
"clear ip pim [vrf NAME] interfaces",
CLEAR_STR
VRF_CMD_HELP_STR
"Reset PIM interfaces\n")
{
- int idx = 2;
- struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+ struct vrf *v = pim_cmd_lookup(vty, vrf);
- if (!vrf)
+ if (!v)
return CMD_WARNING;
- clear_pim_interfaces(vrf->info);
+ clear_pim_interfaces(v->info);
return CMD_SUCCESS;
}
-DEFUN (clear_ip_pim_interface_traffic,
+DEFPY (clear_ip_pim_interface_traffic,
clear_ip_pim_interface_traffic_cmd,
"clear ip pim [vrf NAME] interface traffic",
- "Reset functions\n"
- "IP information\n"
- "PIM clear commands\n"
+ CLEAR_STR
+ IP_STR
+ CLEAR_IP_PIM_STR
VRF_CMD_HELP_STR
"Reset PIM interfaces\n"
"Reset Protocol Packet counters\n")
{
- int idx = 2;
- struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
- struct interface *ifp = NULL;
- struct pim_interface *pim_ifp = NULL;
-
- if (!vrf)
- return CMD_WARNING;
-
- FOR_ALL_INTERFACES (vrf, ifp) {
- pim_ifp = ifp->info;
-
- if (!pim_ifp)
- continue;
-
- pim_ifp->pim_ifstat_hello_recv = 0;
- pim_ifp->pim_ifstat_hello_sent = 0;
- pim_ifp->pim_ifstat_join_recv = 0;
- pim_ifp->pim_ifstat_join_send = 0;
- pim_ifp->pim_ifstat_prune_recv = 0;
- pim_ifp->pim_ifstat_prune_send = 0;
- pim_ifp->pim_ifstat_reg_recv = 0;
- pim_ifp->pim_ifstat_reg_send = 0;
- pim_ifp->pim_ifstat_reg_stop_recv = 0;
- pim_ifp->pim_ifstat_reg_stop_send = 0;
- pim_ifp->pim_ifstat_assert_recv = 0;
- pim_ifp->pim_ifstat_assert_send = 0;
- pim_ifp->pim_ifstat_bsm_rx = 0;
- pim_ifp->pim_ifstat_bsm_tx = 0;
- pim_ifp->igmp_ifstat_joins_sent = 0;
- pim_ifp->igmp_ifstat_joins_failed = 0;
- pim_ifp->igmp_peak_group_count = 0;
- }
-
- return CMD_SUCCESS;
+ return clear_pim_interface_traffic(vrf, vty);
}
DEFPY (clear_ip_pim_oil,
DEFPY (show_ip_pim_nexthop,
show_ip_pim_nexthop_cmd,
- "show ip pim [vrf NAME] nexthop",
+ "show ip pim [vrf NAME] nexthop [json$json]",
SHOW_STR
IP_STR
PIM_STR
VRF_CMD_HELP_STR
- "PIM cached nexthop rpf information\n")
+ "PIM cached nexthop rpf information\n"
+ JSON_STR)
{
- return pim_show_nexthop_cmd_helper(vrf, vty);
+ return pim_show_nexthop_cmd_helper(vrf, vty, !!json);
}
DEFPY (show_ip_pim_nexthop_lookup,
"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;
}
IGNORED_IN_NO_STR)
{
PIM_DECLVAR_CONTEXT_VRF(vrf, pim);
- pim->igmp_watermark_limit = 0;
+ pim->gm_watermark_limit = 0;
return CMD_SUCCESS;
}
"The Group we are resetting\n")
{
struct pim_upstream *up;
+ struct vrf *vrf;
struct pim_instance *pim;
pim_sgaddr sg;
sg.src = source;
sg.grp = group;
- if (!name)
- pim = pim_get_pim_instance(VRF_DEFAULT);
- else {
- struct vrf *vrf = vrf_lookup_by_name(name);
-
- if (!vrf) {
- vty_out(vty, "%% Vrf specified: %s does not exist\n",
- name);
- return CMD_WARNING;
- }
-
- pim = pim_get_pim_instance(vrf->vrf_id);
+ vrf = vrf_lookup_by_name(name ? name : VRF_DEFAULT_NAME);
+ if (!vrf) {
+ vty_out(vty, "%% Vrf specified: %s does not exist\n", name);
+ return CMD_WARNING;
}
+ pim = vrf->info;
+
if (!pim) {
vty_out(vty, "%% Unable to find pim instance\n");
return CMD_WARNING;
int idx = 2;
struct pim_msdp_mg *mg;
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
- struct pim_instance *pim = vrf->info;
+ struct pim_instance *pim;
struct json_object *json = NULL;
if (!vrf)
return CMD_WARNING;
+ pim = vrf->info;
/* Quick case: list is empty. */
if (SLIST_EMPTY(&pim->msdp.mglist)) {
if (uj)
#include "ferr.h"
#include "lib/srcdest_table.h"
#include "lib/linklist.h"
+#include "termtable.h"
#include "pimd.h"
#include "pim_instance.h"
#include "pim_addr.h"
#include "pim_static.h"
#include "pim_util.h"
+#include "pim6_mld.h"
/**
* Get current node VRF name.
{
struct pim_upstream *up;
time_t now = pim_time_monotonic_sec();
+ struct ttable *tt = NULL;
+ char *table = NULL;
json_object *json_group = NULL;
json_object *json_row = NULL;
if (!json) {
vty_out(vty, "\n");
- vty_out(vty,
- "Source Group RpfIface RpfAddress RibNextHop Metric Pref\n");
+
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(
+ tt,
+ "Source|Group|RpfIface|RpfAddress|RibNextHop|Metric|Pref");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
}
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
- char rpf_addr_str[PREFIX_STRLEN];
const char *rpf_ifname;
struct pim_rpf *rpf = &up->rpf;
- pim_addr_dump("<rpf?>", &rpf->rpf_addr, rpf_addr_str,
- sizeof(rpf_addr_str));
-
rpf_ifname =
rpf->source_nexthop.interface ? rpf->source_nexthop
.interface->name
json_object_string_add(json_row, "group", grp_str);
json_object_string_add(json_row, "rpfInterface",
rpf_ifname);
- json_object_string_add(json_row, "rpfAddress",
- rpf_addr_str);
+ json_object_string_addf(json_row, "rpfAddress", "%pPA",
+ &rpf->rpf_addr);
json_object_string_addf(
json_row, "ribNexthop", "%pPAs",
&rpf->source_nexthop.mrib_nexthop_addr);
json_object_object_add(json_group, src_str, json_row);
} else {
- vty_out(vty,
- "%-15pPAs %-15pPAs %-16s %-15s %-15pPAs %6d %4d\n",
+ ttable_add_row(
+ tt, "%pPAs|%pPAs|%s|%pPA|%pPAs|%d|%d",
&up->sg.src, &up->sg.grp, rpf_ifname,
- rpf_addr_str,
+ &rpf->rpf_addr,
&rpf->source_nexthop.mrib_nexthop_addr,
rpf->source_nexthop.mrib_route_metric,
rpf->source_nexthop.mrib_metric_preference);
}
}
+ /* Dump the generated table. */
+ if (!json) {
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+ }
}
void pim_show_neighbors_secondary(struct pim_instance *pim, struct vty *vty)
{
struct interface *ifp;
+ struct ttable *tt = NULL;
+ char *table = NULL;
- vty_out(vty,
- "Interface Address Neighbor Secondary \n");
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "Interface|Address|Neighbor|Secondary");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
FOR_ALL_INTERFACES (pim->vrf, ifp) {
struct pim_interface *pim_ifp;
for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list,
prefix_node, p))
- vty_out(vty,
- "%-16s %-15pPAs %-15pPAs %-15pFX\n",
- ifp->name, &ifaddr, &neigh->source_addr,
- p);
+ ttable_add_row(tt, "%s|%pPAs|%pPAs|%pFX",
+ ifp->name, &ifaddr,
+ &neigh->source_addr, p);
}
}
+ /* Dump the generated table. */
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
}
void pim_show_state(struct pim_instance *pim, struct vty *vty,
pim_sgaddr *sg, json_object *json)
{
struct pim_upstream *up;
+ struct ttable *tt = NULL;
+ char *table = NULL;
time_t now;
json_object *json_group = NULL;
json_object *json_row = NULL;
now = pim_time_monotonic_sec();
- if (!json)
- vty_out(vty,
- "Iif Source Group State Uptime JoinTimer RSTimer KATimer RefCnt\n");
+ if (!json) {
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(
+ tt,
+ "Iif|Source|Group|State|Uptime|JoinTimer|RSTimer|KATimer|RefCnt");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+ }
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
char uptime[10];
if (!up->t_join_timer && up->rpf.source_nexthop.interface) {
struct pim_neighbor *nbr;
- nbr = pim_neighbor_find_prefix(
+ nbr = pim_neighbor_find(
up->rpf.source_nexthop.interface,
- &up->rpf.rpf_addr);
+ up->rpf.rpf_addr);
if (nbr)
pim_time_timer_to_hhmmss(join_timer,
sizeof(join_timer),
rpg = RP(pim, up->sg.grp);
json_object_string_addf(json_row, "rpfAddress",
- "%pFX", &rpg->rpf_addr);
+ "%pPA", &rpg->rpf_addr);
} else {
json_object_string_add(json_row, "rpfAddress",
src_str);
json_object_int_add(json_row, "sptBit", up->sptbit);
json_object_object_add(json_group, src_str, json_row);
} else {
- vty_out(vty,
- "%-16s%-15pPAs %-15pPAs %-11s %-8s %-9s %-9s %-9s %6d\n",
+ ttable_add_row(tt,
+ "%s|%pPAs|%pPAs|%s|%s|%s|%s|%s|%d",
up->rpf.source_nexthop.interface
? up->rpf.source_nexthop.interface->name
: "Unknown",
join_timer, rs_timer, ka_timer, up->ref_count);
}
}
+ /* Dump the generated table. */
+ if (!json) {
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+ }
}
static void pim_show_join_desired_helper(struct pim_instance *pim,
struct vty *vty,
struct pim_upstream *up,
- json_object *json, bool uj)
+ json_object *json, bool uj,
+ struct ttable *tt)
{
json_object *json_group = NULL;
json_object *json_row = NULL;
json_object_object_add(json_group, src_str, json_row);
} else {
- vty_out(vty, "%-15pPAs %-15pPAs %-6s\n", &up->sg.src,
- &up->sg.grp,
- pim_upstream_evaluate_join_desired(pim, up) ? "yes"
- : "no");
+ ttable_add_row(tt, "%pPAs|%pPAs|%s", &up->sg.src, &up->sg.grp,
+ pim_upstream_evaluate_join_desired(pim, up)
+ ? "yes"
+ : "no");
}
}
void pim_show_join_desired(struct pim_instance *pim, struct vty *vty, bool uj)
{
struct pim_upstream *up;
+ struct ttable *tt = NULL;
+ char *table = NULL;
json_object *json = NULL;
if (uj)
json = json_object_new_object();
- else
- vty_out(vty, "Source Group EvalJD\n");
+ else {
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "Source|Group|EvalJD");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+ }
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
/* scan all interfaces */
- pim_show_join_desired_helper(pim, vty, up, json, uj);
+ pim_show_join_desired_helper(pim, vty, up, json, uj, tt);
}
if (uj)
vty_json(vty, json);
+ else {
+ /* Dump the generated table. */
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+ }
}
void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, bool uj)
{
struct pim_upstream *up;
+ struct ttable *tt = NULL;
+ char *table = NULL;
json_object *json = NULL;
json_object *json_group = NULL;
json_object *json_row = NULL;
if (uj)
json = json_object_new_object();
- else
- vty_out(vty,
- "Source Group RpfIface RibNextHop RpfAddress \n");
+ else {
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt,
+ "Source|Group|RpfIface|RibNextHop|RpfAddress");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+ }
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
- char rpf_addr_str[PREFIX_STRLEN];
struct pim_rpf *rpf;
const char *rpf_ifname;
rpf = &up->rpf;
- pim_addr_dump("<rpf?>", &rpf->rpf_addr, rpf_addr_str,
- sizeof(rpf_addr_str));
-
rpf_ifname =
rpf->source_nexthop.interface ? rpf->source_nexthop
.interface->name
json_object_string_addf(
json_row, "ribNexthop", "%pPAs",
&rpf->source_nexthop.mrib_nexthop_addr);
- json_object_string_add(json_row, "rpfAddress",
- rpf_addr_str);
+ json_object_string_addf(json_row, "rpfAddress", "%pPA",
+ &rpf->rpf_addr);
json_object_object_add(json_group, src_str, json_row);
} else {
- vty_out(vty, "%-15pPAs %-15pPAs %-16s %-15pPA %-15s\n",
- &up->sg.src, &up->sg.grp, rpf_ifname,
- &rpf->source_nexthop.mrib_nexthop_addr,
- rpf_addr_str);
+ ttable_add_row(tt, "%pPAs|%pPAs|%s|%pPA|%pPA",
+ &up->sg.src, &up->sg.grp, rpf_ifname,
+ &rpf->source_nexthop.mrib_nexthop_addr,
+ &rpf->rpf_addr);
}
}
if (uj)
vty_json(vty, json);
+ else {
+ /* Dump the generated table. */
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+ }
}
static void pim_show_join_helper(struct vty *vty, struct pim_interface *pim_ifp,
vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
return CMD_WARNING;
}
- pim = pim_get_pim_instance(v->vrf_id);
+ pim = v->info;
if (!pim) {
vty_out(vty, "%% Unable to find pim instance\n");
vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
return CMD_WARNING;
}
- pim = pim_get_pim_instance(v->vrf_id);
+ pim = v->info;
if (!pim) {
vty_out(vty, "%% Unable to find pim instance\n");
int pim_nbrs = 0;
int pim_ifchannels = 0;
bool uj = true;
+ struct ttable *tt = NULL;
+ char *table = NULL;
json_object *json_row = NULL;
json_object *json_tmp;
}
if (!uj) {
- vty_out(vty,
- "Interface State Address PIM Nbrs PIM DR FHR IfChannels\n");
+
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(
+ tt,
+ "Interface|State|Address|PIM Nbrs|PIM DR|FHR|IfChannels");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
json_object_object_foreach(json, key, val)
{
- vty_out(vty, "%-16s ", key);
+ const char *state, *address, *pimdr;
+ int neighbors, firsthpr, pimifchnl;
json_object_object_get_ex(val, "state", &json_tmp);
- vty_out(vty, "%5s ", json_object_get_string(json_tmp));
+ state = json_object_get_string(json_tmp);
json_object_object_get_ex(val, "address", &json_tmp);
- vty_out(vty, "%15s ",
- json_object_get_string(json_tmp));
+ address = json_object_get_string(json_tmp);
json_object_object_get_ex(val, "pimNeighbors",
&json_tmp);
- vty_out(vty, "%8d ", json_object_get_int(json_tmp));
+ neighbors = json_object_get_int(json_tmp);
if (json_object_object_get_ex(
val, "pimDesignatedRouterLocal",
&json_tmp)) {
- vty_out(vty, "%15s ", "local");
+ pimdr = "local";
} else {
json_object_object_get_ex(
val, "pimDesignatedRouter", &json_tmp);
- vty_out(vty, "%15s ",
- json_object_get_string(json_tmp));
+ pimdr = json_object_get_string(json_tmp);
}
json_object_object_get_ex(val, "firstHopRouter",
&json_tmp);
- vty_out(vty, "%3d ", json_object_get_int(json_tmp));
+ firsthpr = json_object_get_int(json_tmp);
json_object_object_get_ex(val, "pimIfChannels",
&json_tmp);
- vty_out(vty, "%9d\n", json_object_get_int(json_tmp));
+ pimifchnl = json_object_get_int(json_tmp);
+
+ ttable_add_row(tt, "%s|%s|%s|%d|%s|%d|%d", key, state,
+ address, neighbors, pimdr, firsthpr,
+ pimifchnl);
}
+
+ /* Dump the generated table. */
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+
+ ttable_del(tt);
}
}
vty_out(vty, "SSM group range : %s\n", range_str);
}
-struct pnc_cache_walk_data {
+struct vty_pnc_cache_walk_data {
struct vty *vty;
struct pim_instance *pim;
};
-static int pim_print_pnc_cache_walkcb(struct hash_bucket *bucket, void *arg)
+struct json_pnc_cache_walk_data {
+ json_object *json_obj;
+ struct pim_instance *pim;
+};
+
+static int pim_print_vty_pnc_cache_walkcb(struct hash_bucket *bucket, void *arg)
{
struct pim_nexthop_cache *pnc = bucket->data;
- struct pnc_cache_walk_data *cwd = arg;
+ struct vty_pnc_cache_walk_data *cwd = arg;
struct vty *vty = cwd->vty;
struct pim_instance *pim = cwd->pim;
struct nexthop *nh_node = NULL;
ifindex_t first_ifindex;
struct interface *ifp = NULL;
- char buf[PREFIX_STRLEN];
for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
first_ifindex = nh_node->ifindex;
+
ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
- vty_out(vty, "%-15s ",
- inet_ntop(AF_INET, &pnc->rpf.rpf_addr.u.prefix4, buf,
- sizeof(buf)));
+ vty_out(vty, "%-15pPA ", &pnc->rpf.rpf_addr);
vty_out(vty, "%-16s ", ifp ? ifp->name : "NULL");
+#if PIM_IPV == 4
vty_out(vty, "%pI4 ", &nh_node->gate.ipv4);
+#else
+ vty_out(vty, "%pI6 ", &nh_node->gate.ipv6);
+#endif
vty_out(vty, "\n");
}
return CMD_SUCCESS;
}
+static int pim_print_json_pnc_cache_walkcb(struct hash_bucket *backet,
+ void *arg)
+{
+ struct pim_nexthop_cache *pnc = backet->data;
+ struct json_pnc_cache_walk_data *cwd = arg;
+ struct pim_instance *pim = cwd->pim;
+ struct nexthop *nh_node = NULL;
+ ifindex_t first_ifindex;
+ struct interface *ifp = NULL;
+ char addr_str[PIM_ADDRSTRLEN];
+ json_object *json_row = NULL;
+ json_object *json_ifp = NULL;
+ json_object *json_arr = NULL;
+
+ for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
+ first_ifindex = nh_node->ifindex;
+ ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
+ snprintfrr(addr_str, sizeof(addr_str), "%pPA",
+ &pnc->rpf.rpf_addr);
+ json_object_object_get_ex(cwd->json_obj, addr_str, &json_row);
+ if (!json_row) {
+ json_row = json_object_new_object();
+ json_object_string_addf(json_row, "address", "%pPA",
+ &pnc->rpf.rpf_addr);
+ json_object_object_addf(cwd->json_obj, json_row, "%pPA",
+ &pnc->rpf.rpf_addr);
+ json_arr = json_object_new_array();
+ json_object_object_add(json_row, "nexthops", json_arr);
+ }
+ json_ifp = json_object_new_object();
+ json_object_string_add(json_ifp, "interface",
+ ifp ? ifp->name : "NULL");
+#if PIM_IPV == 4
+ json_object_string_addf(json_ifp, "nexthop", "%pI4",
+ &nh_node->gate.ipv4);
+#else
+ json_object_string_addf(json_ifp, "nexthop", "%pI6",
+ &nh_node->gate.ipv6);
+#endif
+ json_object_array_add(json_arr, json_ifp);
+ }
+ return CMD_SUCCESS;
+}
+
int pim_show_nexthop_lookup_cmd_helper(const char *vrf, struct vty *vty,
pim_addr source, pim_addr group)
{
- struct prefix nht_p;
int result = 0;
pim_addr vif_source;
struct prefix grp;
if (!pim_rp_set_upstream_addr(v->info, &vif_source, source, group))
return CMD_SUCCESS;
- pim_addr_to_prefix(&nht_p, vif_source);
pim_addr_to_prefix(&grp, group);
memset(&nexthop, 0, sizeof(nexthop));
- result = pim_ecmp_nexthop_lookup(v->info, &nexthop, &nht_p, &grp, 0);
+ result =
+ pim_ecmp_nexthop_lookup(v->info, &nexthop, vif_source, &grp, 0);
if (!result) {
vty_out(vty,
return CMD_SUCCESS;
}
-int pim_show_nexthop_cmd_helper(const char *vrf, struct vty *vty)
+int pim_show_nexthop_cmd_helper(const char *vrf, struct vty *vty, bool uj)
{
struct vrf *v;
if (!v)
return CMD_WARNING;
- pim_show_nexthop(v->info, vty);
+ pim_show_nexthop(v->info, vty, uj);
return CMD_SUCCESS;
}
-void pim_show_nexthop(struct pim_instance *pim, struct vty *vty)
+void pim_show_nexthop(struct pim_instance *pim, struct vty *vty, bool uj)
{
- struct pnc_cache_walk_data cwd;
+ struct vty_pnc_cache_walk_data cwd;
+ struct json_pnc_cache_walk_data jcwd;
cwd.vty = vty;
cwd.pim = pim;
- vty_out(vty, "Number of registered addresses: %lu\n",
- pim->rpf_hash->count);
- vty_out(vty, "Address Interface Nexthop\n");
- vty_out(vty, "---------------------------------------------\n");
+ jcwd.pim = pim;
+
+ if (uj) {
+ jcwd.json_obj = json_object_new_object();
+ } else {
+ vty_out(vty, "Number of registered addresses: %lu\n",
+ pim->rpf_hash->count);
+ vty_out(vty, "Address Interface Nexthop\n");
+ vty_out(vty, "---------------------------------------------\n");
+ }
- hash_walk(pim->rpf_hash, pim_print_pnc_cache_walkcb, &cwd);
+ if (uj) {
+ hash_walk(pim->rpf_hash, pim_print_json_pnc_cache_walkcb,
+ &jcwd);
+ vty_json(vty, jcwd.json_obj);
+ } else
+ hash_walk(pim->rpf_hash, pim_print_vty_pnc_cache_walkcb, &cwd);
}
int pim_show_neighbors_cmd_helper(const char *vrf, struct vty *vty,
json_object *json)
{
struct interface *ifp;
+ struct ttable *tt = NULL;
+ char *table = NULL;
json_object *json_row = NULL;
vty_out(vty, "\n");
- if (!json)
- vty_out(vty,
- "Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut\n");
+ if (!json) {
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(
+ tt,
+ "Interface|Address|ifi|Vif|PktsIn|PktsOut|BytesIn|BytesOut");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+ }
FOR_ALL_INTERFACES (pim->vrf, ifp) {
struct pim_interface *pim_ifp;
(unsigned long)vreq.obytes);
json_object_object_add(json, ifp->name, json_row);
} else {
- vty_out(vty,
- "%-16s %-15pPAs %3d %3d %7lu %7lu %10lu %10lu\n",
- ifp->name, &pim_ifp->primary_address,
- ifp->ifindex, pim_ifp->mroute_vif_index,
- (unsigned long)vreq.icount,
- (unsigned long)vreq.ocount,
- (unsigned long)vreq.ibytes,
- (unsigned long)vreq.obytes);
+ ttable_add_row(tt, "%s|%pPAs|%d|%d|%lu|%lu|%lu|%lu",
+ ifp->name, &pim_ifp->primary_address,
+ ifp->ifindex, pim_ifp->mroute_vif_index,
+ (unsigned long)vreq.icount,
+ (unsigned long)vreq.ocount,
+ (unsigned long)vreq.ibytes,
+ (unsigned long)vreq.obytes);
}
}
+ /* Dump the generated table. */
+ if (!json) {
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+ }
}
void pim_cmd_show_ip_multicast_helper(struct pim_instance *pim, struct vty *vty)
vty_out(vty, "Mroute socket descriptor:");
vty_out(vty, " %d(%s)\n", pim->mroute_socket, vrf->name);
+ vty_out(vty, "PIM Register socket descriptor:");
+ vty_out(vty, " %d(%s)\n", pim->reg_sock, vrf->name);
pim_time_uptime(uptime, sizeof(uptime),
now - pim->mroute_socket_creation);
struct listnode *node;
struct channel_oil *c_oil;
struct static_route *s_route;
+ struct ttable *tt = NULL;
+ char *table = NULL;
time_t now;
json_object *json_group = NULL;
json_object *json_source = NULL;
vty_out(vty, "Flags: S - Sparse, C - Connected, P - Pruned\n");
vty_out(vty,
" R - SGRpt Pruned, F - Register flag, T - SPT-bit set\n");
- vty_out(vty,
- "\nSource Group Flags Proto Input Output TTL Uptime\n");
+
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(
+ tt, "Source|Group|Flags|Proto|Input|Output|TTL|Uptime");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
}
now = pim_time_monotonic_sec();
strlcpy(proto, "STAR", sizeof(proto));
}
- vty_out(vty,
- "%-15s %-15s %-8s %-6s %-16s %-16s %-3d %8s\n",
- src_str, grp_str, state_str, proto,
- in_ifname, out_ifname, ttl,
- mroute_uptime);
+ ttable_add_row(tt, "%s|%s|%s|%s|%s|%s|%d|%s",
+ src_str, grp_str, state_str,
+ proto, in_ifname, out_ifname,
+ ttl, mroute_uptime);
if (first) {
src_str[0] = '\0';
}
if (!json && !found_oif) {
- vty_out(vty,
- "%-15pPAs %-15pPAs %-8s %-6s %-16s %-16s %-3d %8s\n",
- oil_origin(c_oil), oil_mcastgrp(c_oil),
- state_str, "none", in_ifname, "none", 0,
- "--:--:--");
+ ttable_add_row(tt, "%pPAs|%pPAs|%s|%s|%s|%s|%d|%s",
+ oil_origin(c_oil), oil_mcastgrp(c_oil),
+ state_str, "none", in_ifname, "none", 0,
+ "--:--:--");
}
}
json_object_object_add(json_oil, out_ifname,
json_ifp_out);
} else {
- vty_out(vty,
- "%-15pPAs %-15pPAs %-8s %-6s %-16s %-16s %-3d %8s\n",
+ ttable_add_row(
+ tt, "%pPAs|%pPAs|%s|%s|%s|%s|%d|%s",
&s_route->source, &s_route->group, "-",
proto, in_ifname, out_ifname, ttl,
oif_uptime);
}
if (!json && !found_oif) {
- vty_out(vty,
- "%-15pPAs %-15pPAs %-8s %-6s %-16s %-16s %-3d %8s\n",
- &s_route->source, &s_route->group, "-", proto,
- in_ifname, "none", 0, "--:--:--");
+ ttable_add_row(tt, "%pPAs|%pPAs|%s|%s|%s|%s|%d|%s",
+ &s_route->source, &s_route->group, "-",
+ proto, in_ifname, "none", 0, "--:--:--");
}
}
+ /* Dump the generated table. */
+ if (!json) {
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+ }
}
static void show_mroute_count_per_channel_oil(struct channel_oil *c_oil,
json_object *json,
- struct vty *vty)
+ struct vty *vty,
+ struct ttable *tt)
{
json_object *json_group = NULL;
json_object *json_source = NULL;
json_object_int_add(json_source, "wrongIf", c_oil->cc.wrong_if);
} else {
- vty_out(vty, "%-15pPAs %-15pPAs %-8llu %-7ld %-10ld %-7ld\n",
- oil_origin(c_oil), oil_mcastgrp(c_oil),
- c_oil->cc.lastused / 100,
- c_oil->cc.pktcnt - c_oil->cc.origpktcnt,
- c_oil->cc.bytecnt - c_oil->cc.origbytecnt,
- c_oil->cc.wrong_if - c_oil->cc.origwrong_if);
+ ttable_add_row(tt, "%pPAs|%pPAs|%llu|%ld|%ld|%ld",
+ oil_origin(c_oil), oil_mcastgrp(c_oil),
+ c_oil->cc.lastused / 100,
+ c_oil->cc.pktcnt - c_oil->cc.origpktcnt,
+ c_oil->cc.bytecnt - c_oil->cc.origbytecnt,
+ c_oil->cc.wrong_if - c_oil->cc.origwrong_if);
}
}
struct listnode *node;
struct channel_oil *c_oil;
struct static_route *sr;
+ struct ttable *tt = NULL;
+ char *table = NULL;
if (!json) {
vty_out(vty, "\n");
- vty_out(vty,
- "Source Group LastUsed Packets Bytes WrongIf \n");
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt,
+ "Source|Group|LastUsed|Packets|Bytes|WrongIf");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
}
/* Print PIM and IGMP route counts */
frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil)
- show_mroute_count_per_channel_oil(c_oil, json, vty);
+ show_mroute_count_per_channel_oil(c_oil, json, vty, tt);
for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sr))
- show_mroute_count_per_channel_oil(&sr->c_oil, json, vty);
+ show_mroute_count_per_channel_oil(&sr->c_oil, json, vty, tt);
+
+ /* Dump the generated table. */
+ if (!json) {
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+ }
}
void show_mroute_summary(struct pim_instance *pim, struct vty *vty,
igmp_group_delete(grp);
}
}
+#else
+ struct gm_if *gm_ifp;
+
+ gm_ifp = pim_ifp->mld;
+ if (gm_ifp)
+ gm_group_delete(gm_ifp);
#endif
}
}
}
+int clear_pim_interface_traffic(const char *vrf, struct vty *vty)
+{
+ struct interface *ifp = NULL;
+ struct pim_interface *pim_ifp = NULL;
+
+ struct vrf *v = pim_cmd_lookup(vty, vrf);
+
+ if (!v)
+ return CMD_WARNING;
+
+ FOR_ALL_INTERFACES (v, ifp) {
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ continue;
+
+ pim_ifp->pim_ifstat_hello_recv = 0;
+ pim_ifp->pim_ifstat_hello_sent = 0;
+ pim_ifp->pim_ifstat_join_recv = 0;
+ pim_ifp->pim_ifstat_join_send = 0;
+ pim_ifp->pim_ifstat_prune_recv = 0;
+ pim_ifp->pim_ifstat_prune_send = 0;
+ pim_ifp->pim_ifstat_reg_recv = 0;
+ pim_ifp->pim_ifstat_reg_send = 0;
+ pim_ifp->pim_ifstat_reg_stop_recv = 0;
+ pim_ifp->pim_ifstat_reg_stop_send = 0;
+ pim_ifp->pim_ifstat_assert_recv = 0;
+ pim_ifp->pim_ifstat_assert_send = 0;
+ pim_ifp->pim_ifstat_bsm_rx = 0;
+ pim_ifp->pim_ifstat_bsm_tx = 0;
+#if PIM_IPV == 4
+ pim_ifp->igmp_ifstat_joins_sent = 0;
+ pim_ifp->igmp_ifstat_joins_failed = 0;
+ pim_ifp->igmp_peak_group_count = 0;
+#endif
+ }
+
+ return CMD_SUCCESS;
+}
+
int pim_debug_pim_cmd(void)
{
PIM_DO_DEBUG_PIM_EVENTS;
PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND;
PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV;
+ PIM_DONT_DEBUG_BSM;
+ PIM_DONT_DEBUG_VXLAN;
return CMD_SUCCESS;
}
if (!v)
return CMD_WARNING;
- pim = pim_get_pim_instance(v->vrf_id);
+ pim = v->info;
if (!pim) {
vty_out(vty, "%% Unable to find pim instance\n");
if (!v)
return CMD_WARNING;
- pim = pim_get_pim_instance(v->vrf_id);
+ pim = v->info;
if (!pim) {
vty_out(vty, "%% Unable to find pim instance\n");
if (!v)
return CMD_WARNING;
- pim = pim_get_pim_instance(v->vrf_id);
+ pim = v->info;
if (!pim) {
vty_out(vty, "%% Unable to find pim instance\n");
if (!v)
return CMD_WARNING;
- pim = pim_get_pim_instance(v->vrf_id);
+ pim = v->info;
if (!pim) {
vty_out(vty, "%% Unable to find pim instance\n");
vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
return CMD_WARNING;
}
- pim = pim_get_pim_instance(v->vrf_id);
+ pim = v->info;
if (!pim) {
vty_out(vty, "%% Unable to find pim instance\n");
if (!v)
return CMD_WARNING;
- pim = pim_get_pim_instance(v->vrf_id);
+ pim = v->info;
if (!pim) {
vty_out(vty, "%% Unable to find pim instance\n");
if (!v)
return CMD_WARNING;
- pim = pim_get_pim_instance(v->vrf_id);
+ pim = v->info;
if (!pim) {
vty_out(vty, "%% Unable to find pim instance\n");
if (!v)
return CMD_WARNING;
- pim = pim_get_pim_instance(v->vrf_id);
+ pim = v->info;
if (!pim) {
vty_out(vty, "%% Unable to find pim instance\n");
if (!v)
return CMD_WARNING;
- pim = pim_get_pim_instance(v->vrf_id);
+ pim = v->info;
if (!pim) {
vty_out(vty, "%% Unable to find pim instance\n");
if (!v)
return CMD_WARNING;
- pim = pim_get_pim_instance(v->vrf_id);
+ pim = v->info;
if (!pim) {
vty_out(vty, "%% Unable to find pim instance\n");
if (!v)
return CMD_WARNING;
- pim = pim_get_pim_instance(v->vrf_id);
+ pim = v->info;
if (!pim) {
vty_out(vty, "%% Unable to find pim instance\n");
if (!v)
return CMD_WARNING;
- pim = pim_get_pim_instance(v->vrf_id);
+ pim = v->info;
if (!pim) {
vty_out(vty, "%% Unable to find pim instance\n");
if (!v)
return CMD_WARNING;
- pim = pim_get_pim_instance(v->vrf_id);
+ pim = v->info;
if (!pim) {
vty_out(vty, "%% Unable to find pim instance\n");
pim_ifp->pim_ifstat_join_recv);
json_object_int_add(json_row, "joinTx",
pim_ifp->pim_ifstat_join_send);
- json_object_int_add(json_row, "pruneTx",
- pim_ifp->pim_ifstat_prune_send);
json_object_int_add(json_row, "pruneRx",
pim_ifp->pim_ifstat_prune_recv);
+ json_object_int_add(json_row, "pruneTx",
+ pim_ifp->pim_ifstat_prune_send);
json_object_int_add(json_row, "registerRx",
pim_ifp->pim_ifstat_reg_recv);
json_object_int_add(json_row, "registerTx",
if (!v)
return CMD_WARNING;
- pim = pim_get_pim_instance(v->vrf_id);
+ pim = v->info;
if (!pim) {
vty_out(vty, "%% Unable to find pim instance\n");
return CMD_SUCCESS;
}
+
+void clear_pim_interfaces(struct pim_instance *pim)
+{
+ struct interface *ifp;
+
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ if (ifp->info)
+ pim_neighbor_delete_all(ifp, "interface cleared");
+ }
+}
struct pim_upstream;
struct pim_instance;
-/* duplicated from pim_instance.h - needed to avoid dependency mess */
-struct pim_instance *pim_get_pim_instance(vrf_id_t vrf_id);
-
const char *pim_cli_get_vrf_name(struct vty *vty);
int pim_process_join_prune_cmd(struct vty *vty, const char *jpi_str);
int pim_process_no_join_prune_cmd(struct vty *vty);
bool uj);
int pim_show_nexthop_lookup_cmd_helper(const char *vrf, struct vty *vty,
pim_addr source, pim_addr group);
-int pim_show_nexthop_cmd_helper(const char *vrf, struct vty *vty);
-void pim_show_nexthop(struct pim_instance *pim, struct vty *vty);
+int pim_show_nexthop_cmd_helper(const char *vrf, struct vty *vty, bool uj);
+void pim_show_nexthop(struct pim_instance *pim, struct vty *vty, bool uj);
int pim_show_neighbors_cmd_helper(const char *vrf, struct vty *vty,
const char *json, const char *interface);
int pim_show_neighbors_vrf_all_cmd_helper(struct vty *vty, const char *json,
struct vrf *pim_cmd_lookup(struct vty *vty, const char *name);
void clear_mroute(struct pim_instance *pim);
void clear_pim_statistics(struct pim_instance *pim);
+int clear_pim_interface_traffic(const char *vrf, struct vty *vty);
int pim_debug_pim_cmd(void);
int pim_no_debug_pim_cmd(void);
int pim_debug_pim_packets_cmd(const char *hello, const char *joins,
bool uj);
int pim_show_interface_traffic_helper(const char *vrf, const char *if_name,
struct vty *vty, bool uj);
+void clear_pim_interfaces(struct pim_instance *pim);
/*
* Special Macro to allow us to get the correct pim_instance;
*/
with RNH address to receive update and add the
interface as nexthop. */
memset(&rpf, 0, sizeof(struct pim_rpf));
- rpf.rpf_addr.family = AF_INET;
- rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN;
- rpf.rpf_addr.u.prefix4 = ifc->address->u.prefix4;
+ rpf.rpf_addr = pim_addr_from_prefix(ifc->address);
pnc = pim_nexthop_cache_find(pim_ifp->pim, &rpf);
if (pnc)
pim_sendmsg_zebra_rnh(pim_ifp->pim, zclient,
pim_if_addr_add(ifc);
}
- if (!v4_addrs && v6_addrs && !if_is_loopback(ifp)) {
- if (pim_ifp->pim_enable) {
-
- /* Interface has a valid primary address ? */
- if (!pim_addr_is_any(pim_ifp->primary_address)) {
-
- /* Interface has a valid socket ? */
- if (pim_ifp->pim_sock_fd < 0) {
- if (pim_sock_add(ifp)) {
- zlog_warn(
- "Failure creating PIM socket for interface %s",
- ifp->name);
- }
- }
- }
- } /* pim */
+ if (!v4_addrs && v6_addrs && !if_is_loopback(ifp) &&
+ pim_ifp->pim_enable && !pim_addr_is_any(pim_ifp->primary_address) &&
+ pim_ifp->pim_sock_fd < 0 && pim_sock_add(ifp)) {
+ /* Interface has a valid primary address ? */
+ /* Interface has a valid socket ? */
+ zlog_warn("Failure creating PIM socket for interface %s",
+ ifp->name);
}
/*
* PIM or IGMP/MLD is enabled on interface, and there is at least one
if (ifp->info) {
pim_if_del_vif(ifp);
-#if PIM_IPV == 4
pim_ifstat_reset(ifp);
-#endif
}
return 0;
if (up_flags == PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
PIM_IF_FLAG_SET_PROTO_IGMP(ch->flags);
- if (ch->upstream)
- ch->upstream->flags |= up_flags;
- else if (PIM_DEBUG_EVENTS)
- zlog_debug("%s:%pSG No Upstream found", __func__, sg);
+ ch->upstream->flags |= up_flags;
return ch;
}
pim_ifchannel_ifjoin_switch(__func__, ch, PIM_IFJOIN_NOINFO);
pim_forward_stop(ch);
- if (ch->upstream)
- PIM_UPSTREAM_FLAG_UNSET_SRC_PIM(ch->upstream->flags);
+ PIM_UPSTREAM_FLAG_UNSET_SRC_PIM(ch->upstream->flags);
PIM_IF_FLAG_UNSET_PROTO_PIM(ch->flags);
struct pim_rpf rpf;
rpf.source_nexthop.interface = ifp;
- pim_addr_to_prefix(&rpf.rpf_addr,
- pim_ifp->primary_address);
+ rpf.rpf_addr = pim_ifp->primary_address;
pim_jp_agg_single_upstream_send(
&rpf, ch->upstream, 0);
}
* message on RP path upon prune timer expiry.
*/
ch->ifjoin_state = PIM_IFJOIN_PRUNE;
- if (ch->upstream) {
- struct pim_upstream *parent =
- ch->upstream->parent;
+ struct pim_upstream *parent =
+ ch->upstream->parent;
- pim_upstream_update_join_desired(pim_ifp->pim,
- ch->upstream);
+ pim_upstream_update_join_desired(pim_ifp->pim,
+ ch->upstream);
- pim_jp_agg_single_upstream_send(&parent->rpf,
- parent, true);
- /*
- * SGRpt prune pending expiry has to install
- * SG entry with empty olist to drop the SG
- * traffic incase no other intf exists.
- * On that scenario, SG entry wouldn't have
- * got installed until Prune pending timer
- * expired. So install now.
- */
- pim_channel_del_oif(
- ch->upstream->channel_oil, ifp,
- PIM_OIF_FLAG_PROTO_STAR, __func__);
- if (!ch->upstream->channel_oil->installed)
- pim_upstream_mroute_add(
- ch->upstream->channel_oil,
- __func__);
- }
+ pim_jp_agg_single_upstream_send(&parent->rpf,
+ parent, true);
+ /*
+ * SGRpt prune pending expiry has to install
+ * SG entry with empty olist to drop the SG
+ * traffic incase no other intf exists.
+ * On that scenario, SG entry wouldn't have
+ * got installed until Prune pending timer
+ * expired. So install now.
+ */
+ pim_channel_del_oif(
+ ch->upstream->channel_oil, ifp,
+ PIM_OIF_FLAG_PROTO_STAR, __func__);
+ if (!ch->upstream->channel_oil->installed)
+ pim_upstream_mroute_add(
+ ch->upstream->channel_oil,
+ __func__);
}
/* from here ch may have been deleted */
}
return;
}
- rpf_addr = pim_addr_from_prefix(&up->rpf.rpf_addr);
+ rpf_addr = up->rpf.rpf_addr;
/* upstream directed to RPF'(S,G) ? */
if (pim_addr_cmp(upstream, rpf_addr)) {
* time; the same router keeps sending the Group-Specific
* Queries.
*/
- struct gm_group *group;
+ const struct gm_group *group;
+ const struct listnode *grpnode;
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode,
+ group)) {
+ if (!group->t_group_query_retransmit_timer)
+ continue;
- group = find_group_by_addr(igmp, group_addr);
- if (group && group->t_group_query_retransmit_timer) {
if (PIM_DEBUG_IGMP_TRACE)
zlog_debug(
"%s: lower address query packet from %s is ignored when last member query interval timer is running",
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,
#include "pim_vty.h"
#include "pim_bsm.h"
#include "pim_mlag.h"
+#include "pim_sock.h"
static void pim_instance_terminate(struct pim_instance *pim)
{
pim_msdp_exit(pim);
+ close(pim->reg_sock);
+
pim_mroute_socket_disable(pim);
XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist);
pim->last_route_change_time = -1;
+ pim->reg_sock = pim_reg_sock();
+ if (pim->reg_sock < 0)
+ assert(0);
+
/* MSDP global timer defaults. */
pim->msdp.hold_time = PIM_MSDP_PEER_HOLD_TIME;
pim->msdp.keep_alive = PIM_MSDP_PEER_KA_TIME;
struct thread *thread;
int mroute_socket;
+ int reg_sock; /* Socket to send register msg */
int64_t mroute_socket_creation;
int64_t mroute_add_events;
int64_t mroute_add_last;
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;
* If the RP sent in the message is not
* our RP for the group, drop the message
*/
- rpf_addr = pim_addr_from_prefix(&rp->rpf_addr);
+ rpf_addr = rp->rpf_addr;
if (pim_addr_cmp(sg->src, rpf_addr)) {
zlog_warn(
"%s: Specified RP(%pPAs) in join is different than our configured RP(%pPAs)",
size_t packet_left = 0;
size_t packet_size = 0;
size_t group_size = 0;
- pim_addr rpf_addr;
if (rpf->source_nexthop.interface)
pim_ifp = rpf->source_nexthop.interface->info;
return -1;
}
- rpf_addr = pim_addr_from_prefix(&rpf->rpf_addr);
- on_trace(__func__, rpf->source_nexthop.interface, rpf_addr);
+ on_trace(__func__, rpf->source_nexthop.interface, rpf->rpf_addr);
if (!pim_ifp) {
zlog_warn("%s: multicast not enabled on interface %s", __func__,
return -1;
}
- if (pim_addr_is_any(rpf_addr)) {
+ if (pim_addr_is_any(rpf->rpf_addr)) {
if (PIM_DEBUG_PIM_J_P)
zlog_debug(
"%s: upstream=%pPA is myself on interface %s",
- __func__, &rpf_addr,
+ __func__, &rpf->rpf_addr,
rpf->source_nexthop.interface->name);
return 0;
}
memset(msg, 0, sizeof(*msg));
pim_msg_addr_encode_ucast((uint8_t *)&msg->addr,
- rpf_addr);
+ rpf->rpf_addr);
msg->reserved = 0;
msg->holdtime = htons(PIM_JP_HOLDTIME);
if (PIM_DEBUG_PIM_J_P)
zlog_debug(
"%s: sending (G)=%pPAs to upstream=%pPA on interface %s",
- __func__, &group->group, &rpf_addr,
+ __func__, &group->group, &rpf->rpf_addr,
rpf->source_nexthop.interface->name);
group_size = pim_msg_get_jp_group_size(group->sources);
memset(msg, 0, sizeof(*msg));
pim_msg_addr_encode_ucast((uint8_t *)&msg->addr,
- rpf_addr);
+ rpf->rpf_addr);
msg->reserved = 0;
msg->holdtime = htons(PIM_JP_HOLDTIME);
struct pim_interface *pim_ifp;
struct pim_iface_upstream_switch *pius;
struct listnode *node, *nnode;
- pim_addr rpf_addr;
if (!ifp)
return NULL;
if (!pim_ifp)
return NULL;
- rpf_addr = pim_addr_from_prefix(&rpf->rpf_addr);
-
for (ALL_LIST_ELEMENTS(pim_ifp->upstream_switch_list, node, nnode,
pius)) {
- if (!pim_addr_cmp(pius->address, rpf_addr))
+ if (!pim_addr_cmp(pius->address, rpf->rpf_addr))
break;
}
if (!pius) {
pius = XCALLOC(MTYPE_PIM_JP_AGG_GROUP,
sizeof(struct pim_iface_upstream_switch));
- pius->address = rpf_addr;
+ pius->address = rpf->rpf_addr;
pius->us = list_new();
listnode_add_sort(pim_ifp->upstream_switch_list, pius);
}
struct pim_rpf *rpf = pim_rp_g(pim, source->up->sg.grp);
bits = PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_WC_BIT
| PIM_ENCODE_RPT_BIT;
- stosend = pim_addr_from_prefix(&rpf->rpf_addr);
+ stosend = rpf->rpf_addr;
/* Only Send SGRpt in case of *,G Join */
if (source->is_join)
up = source->up;
pim_enable_dnode =
yang_dnode_getf(dnode,
"%s/frr-pim:pim/address-family[address-family='%s']/pim-enable",
- if_xpath, "frr-routing:ipv4");
+ if_xpath, FRR_PIM_AF_XPATH_VAL);
igmp_enable_dnode = yang_dnode_getf(dnode,
"%s/frr-gmp:gmp/address-family[address-family='%s']/enable",
- if_xpath, "frr-routing:ipv4");
+ if_xpath, FRR_PIM_AF_XPATH_VAL);
if (((pim_enable_dnode) &&
(yang_dnode_get_bool(pim_enable_dnode, "."))) ||
neigh->upstream_jp_agg->count);
rpf.source_nexthop.interface = neigh->interface;
- pim_addr_to_prefix(&rpf.rpf_addr, neigh->source_addr);
+ rpf.rpf_addr = neigh->source_addr;
pim_joinprune_send(&rpf, neigh->upstream_jp_agg);
thread_add_timer(router->master, on_neighbor_jp_timer, neigh,
void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient,
struct pim_nexthop_cache *pnc, int command)
{
- struct prefix *p;
+ struct prefix p;
int ret;
- p = &(pnc->rpf.rpf_addr);
- ret = zclient_send_rnh(zclient, command, p, SAFI_UNICAST, false, false,
+ pim_addr_to_prefix(&p, pnc->rpf.rpf_addr);
+ ret = zclient_send_rnh(zclient, command, &p, SAFI_UNICAST, false, false,
pim->vrf->vrf_id);
if (ret == ZCLIENT_SEND_FAILURE)
zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
zlog_debug(
"%s: NHT %sregistered addr %pFX(%s) with Zebra ret:%d ",
__func__,
- (command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", p,
+ (command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", &p,
pim->vrf->name, ret);
return;
pnc->rp_list = list_new();
pnc->rp_list->cmp = pim_rp_list_cmp;
- snprintfrr(hash_name, sizeof(hash_name), "PNC %pFX(%s) Upstream Hash",
+ snprintfrr(hash_name, sizeof(hash_name), "PNC %pPA(%s) Upstream Hash",
&pnc->rpf.rpf_addr, pim->vrf->name);
pnc->upstream_hash = hash_create_size(8192, pim_upstream_hash_key,
pim_upstream_equal, hash_name);
}
static struct pim_nexthop_cache *pim_nht_get(struct pim_instance *pim,
- struct prefix *addr)
+ pim_addr addr)
{
struct pim_nexthop_cache *pnc = NULL;
struct pim_rpf rpf;
zclient = pim_zebra_zclient_get();
memset(&rpf, 0, sizeof(rpf));
- rpf.rpf_addr = *addr;
+ rpf.rpf_addr = addr;
pnc = pim_nexthop_cache_find(pim, &rpf);
if (!pnc) {
ZEBRA_NEXTHOP_REGISTER);
if (PIM_DEBUG_PIM_NHT_DETAIL)
zlog_debug(
- "%s: NHT cache and zebra notification added for %pFX(%s)",
- __func__, addr, pim->vrf->name);
+ "%s: NHT cache and zebra notification added for %pPA(%s)",
+ __func__, &addr, pim->vrf->name);
}
return pnc;
/* TBD: this does several distinct things and should probably be split up.
* (checking state vs. returning pnc vs. adding upstream vs. adding rp)
*/
-int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr,
+int pim_find_or_track_nexthop(struct pim_instance *pim, pim_addr addr,
struct pim_upstream *up, struct rp_info *rp,
struct pim_nexthop_cache *out_pnc)
{
pnc = pim_nht_get(pim, addr);
- assertf(up || rp, "addr=%pFX", addr);
+ assertf(up || rp, "addr=%pPA", &addr);
if (rp != NULL) {
ch_node = listnode_lookup(pnc->rp_list, rp);
return 0;
}
-#if PIM_IPV == 4
-void pim_nht_bsr_add(struct pim_instance *pim, struct in_addr addr)
+void pim_nht_bsr_add(struct pim_instance *pim, pim_addr addr)
{
struct pim_nexthop_cache *pnc;
- struct prefix pfx;
-
- pfx.family = AF_INET;
- pfx.prefixlen = IPV4_MAX_BITLEN;
- pfx.u.prefix4 = addr;
- pnc = pim_nht_get(pim, &pfx);
+ pnc = pim_nht_get(pim, addr);
pnc->bsr_count++;
}
-#endif /* PIM_IPV == 4 */
static void pim_nht_drop_maybe(struct pim_instance *pim,
struct pim_nexthop_cache *pnc)
{
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: NHT %pFX(%s) rp_list count:%d upstream count:%ld BSR count:%u",
+ "%s: NHT %pPA(%s) rp_list count:%d upstream count:%ld BSR count:%u",
__func__, &pnc->rpf.rpf_addr, pim->vrf->name,
pnc->rp_list->count, pnc->upstream_hash->count,
pnc->bsr_count);
}
}
-void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
+void pim_delete_tracked_nexthop(struct pim_instance *pim, pim_addr addr,
struct pim_upstream *up, struct rp_info *rp)
{
struct pim_nexthop_cache *pnc = NULL;
struct pim_upstream *upstream = NULL;
/* Remove from RPF hash if it is the last entry */
- lookup.rpf.rpf_addr = *addr;
+ lookup.rpf.rpf_addr = addr;
pnc = hash_lookup(pim->rpf_hash, &lookup);
if (!pnc) {
- zlog_warn("attempting to delete nonexistent NHT entry %pFX",
- addr);
+ zlog_warn("attempting to delete nonexistent NHT entry %pPA",
+ &addr);
return;
}
pim_nht_drop_maybe(pim, pnc);
}
-#if PIM_IPV == 4
-void pim_nht_bsr_del(struct pim_instance *pim, struct in_addr addr)
+void pim_nht_bsr_del(struct pim_instance *pim, pim_addr addr)
{
struct pim_nexthop_cache *pnc = NULL;
struct pim_nexthop_cache lookup;
* is 0.0.0.0 as that the BSR has not been registered
* for tracking yet.
*/
- if (addr.s_addr == INADDR_ANY)
+ if (pim_addr_is_any(addr))
return;
- lookup.rpf.rpf_addr.family = AF_INET;
- lookup.rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN;
- lookup.rpf.rpf_addr.u.prefix4 = addr;
+ lookup.rpf.rpf_addr = addr;
pnc = hash_lookup(pim->rpf_hash, &lookup);
if (!pnc) {
- zlog_warn("attempting to delete nonexistent NHT BSR entry %pI4",
+ zlog_warn("attempting to delete nonexistent NHT BSR entry %pPA",
&addr);
return;
}
- assertf(pnc->bsr_count > 0, "addr=%pI4", &addr);
+ assertf(pnc->bsr_count > 0, "addr=%pPA", &addr);
pnc->bsr_count--;
pim_nht_drop_maybe(pim, pnc);
}
-bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr,
+bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr,
struct interface *src_ifp, pim_addr src_ip)
{
struct pim_nexthop_cache *pnc = NULL;
struct nexthop *nh;
struct interface *ifp;
- lookup.rpf.rpf_addr.family = AF_INET;
- lookup.rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN;
- lookup.rpf.rpf_addr.u.prefix4 = bsr_addr;
+ lookup.rpf.rpf_addr = bsr_addr;
pnc = hash_lookup(pim->rpf_hash, &lookup);
if (!pnc || !CHECK_FLAG(pnc->flags, PIM_NEXTHOP_ANSWER_RECEIVED)) {
if (!nbr)
continue;
- return nh->ifindex == src_ifp->ifindex
- && nhaddr.s_addr == src_ip.s_addr;
+ return nh->ifindex == src_ifp->ifindex &&
+ (!pim_addr_cmp(nhaddr, src_ip));
}
return false;
}
-#endif /* PIM_IPV == 4 */
void pim_rp_nexthop_del(struct rp_info *rp_info)
{
// Compute PIM RPF using cached nexthop
if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
- &rp_info->rp.rpf_addr,
+ rp_info->rp.rpf_addr,
&rp_info->group, 1))
pim_rp_nexthop_del(rp_info);
}
* RPF nbr is now unreachable the MFC has already been updated
* by pim_rpf_clear
*/
- if (rpf_result != PIM_RPF_FAILURE)
+ if (rpf_result == PIM_RPF_CHANGED)
pim_upstream_mroute_iif_update(up->channel_oil, __func__);
if (rpf_result == PIM_RPF_CHANGED ||
static int pim_ecmp_nexthop_search(struct pim_instance *pim,
struct pim_nexthop_cache *pnc,
- struct pim_nexthop *nexthop,
- struct prefix *src, struct prefix *grp,
- int neighbor_needed)
+ struct pim_nexthop *nexthop, pim_addr src,
+ struct prefix *grp, int neighbor_needed)
{
struct pim_neighbor *nbrs[router->multipath], *nbr = NULL;
struct interface *ifps[router->multipath];
uint8_t nh_iter = 0, found = 0;
uint32_t i, num_nbrs = 0;
pim_addr nh_addr = nexthop->mrib_nexthop_addr;
- pim_addr src_addr = pim_addr_from_prefix(src);
pim_addr grp_addr = pim_addr_from_prefix(grp);
if (!pnc || !pnc->nexthop_num || !nexthop)
if (curr_route_valid &&
!pim_if_connected_to_source(nexthop->interface,
- src_addr)) {
+ src)) {
nbr = pim_neighbor_find(
nexthop->interface,
nexthop->mrib_nexthop_addr);
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
"%s: (%pPA,%pPA)(%s) current nexthop %s is valid, skipping new path selection",
- __func__, &src_addr,
+ __func__, &src,
&grp_addr,
pim->vrf->name,
nexthop->interface->name);
pim_addr nhaddr = nh_node->gate.ipv6;
#endif
nbrs[i] = pim_neighbor_find(ifps[i], nhaddr);
- if (nbrs[i] ||
- pim_if_connected_to_source(ifps[i], src_addr))
+ if (nbrs[i] || pim_if_connected_to_source(ifps[i], src))
num_nbrs++;
}
}
if (pim->ecmp_enable) {
+ struct prefix src_pfx;
uint32_t consider = pnc->nexthop_num;
if (neighbor_needed && num_nbrs < consider)
return 0;
// PIM ECMP flag is enable then choose ECMP path.
- hash_val = pim_compute_ecmp_hash(src, grp);
+ pim_addr_to_prefix(&src_pfx, src);
+ hash_val = pim_compute_ecmp_hash(&src_pfx, grp);
mod_val = hash_val % consider;
}
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
"%s %s: could not find interface for ifindex %d (address %pPA(%s))",
- __FILE__, __func__, first_ifindex,
- &src_addr, pim->vrf->name);
+ __FILE__, __func__, first_ifindex, &src,
+ pim->vrf->name);
if (nh_iter == mod_val)
mod_val++; // Select nexthpath
nh_iter++;
zlog_debug(
"%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
__func__, ifp->name, pim->vrf->name,
- first_ifindex, &src_addr);
+ first_ifindex, &src);
if (nh_iter == mod_val)
mod_val++; // Select nexthpath
nh_iter++;
continue;
}
- if (neighbor_needed &&
- !pim_if_connected_to_source(ifp, src_addr)) {
+ if (neighbor_needed && !pim_if_connected_to_source(ifp, src)) {
nbr = nbrs[nh_iter];
if (!nbr && !if_is_loopback(ifp)) {
if (PIM_DEBUG_PIM_NHT)
#endif
nexthop->mrib_metric_preference = pnc->distance;
nexthop->mrib_route_metric = pnc->metric;
- nexthop->last_lookup = src_addr;
+ nexthop->last_lookup = src;
nexthop->last_lookup_time = pim_time_monotonic_usec();
nexthop->nbr = nbr;
found = 1;
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
"%s: (%pPA,%pPA)(%s) selected nhop interface %s addr %pPAs mod_val %u iter %d ecmp %d",
- __func__, &src_addr, &grp_addr,
+ __func__, &src, &grp_addr,
pim->vrf->name, ifp->name, &nh_addr,
mod_val, nh_iter, pim->ecmp_enable);
}
}
if (cmd == ZEBRA_NEXTHOP_UPDATE) {
- prefix_copy(&rpf.rpf_addr, &match);
+ rpf.rpf_addr = pim_addr_from_prefix(&match);
pnc = pim_nexthop_cache_find(pim, &rpf);
if (!pnc) {
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: Skipping NHT update, addr %pFX is not in local cached DB.",
+ "%s: Skipping NHT update, addr %pPA is not in local cached DB.",
__func__, &rpf.rpf_addr);
return 0;
}
*/
#if PIM_IPV == 4
nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
- nexthop->gate.ipv4 =
- pnc->rpf.rpf_addr.u.prefix4;
+ nexthop->gate.ipv4 = pnc->rpf.rpf_addr;
#else
nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
- nexthop->gate.ipv6 =
- pnc->rpf.rpf_addr.u.prefix6;
+ nexthop->gate.ipv6 = pnc->rpf.rpf_addr;
#endif
break;
#if PIM_IPV == 4
}
int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
- struct pim_nexthop *nexthop, struct prefix *src,
+ struct pim_nexthop *nexthop, pim_addr src,
struct prefix *grp, int neighbor_needed)
{
struct pim_nexthop_cache *pnc;
uint8_t i = 0;
uint32_t hash_val = 0, mod_val = 0;
uint32_t num_nbrs = 0;
- pim_addr src_addr = pim_addr_from_prefix(src);
if (PIM_DEBUG_PIM_NHT_DETAIL)
zlog_debug("%s: Looking up: %pPA(%s), last lookup time: %lld",
- __func__, &src_addr, pim->vrf->name,
+ __func__, &src, pim->vrf->name,
nexthop->last_lookup_time);
- rpf.rpf_addr = *src;
+ rpf.rpf_addr = src;
pnc = pim_nexthop_cache_find(pim, &rpf);
if (pnc) {
memset(nexthop_tab, 0,
sizeof(struct pim_zlookup_nexthop) * router->multipath);
num_ifindex =
- zclient_lookup_nexthop(pim, nexthop_tab, router->multipath,
- src_addr, PIM_NEXTHOP_LOOKUP_MAX);
+ zclient_lookup_nexthop(pim, nexthop_tab, router->multipath, src,
+ PIM_NEXTHOP_LOOKUP_MAX);
if (num_ifindex < 1) {
if (PIM_DEBUG_PIM_NHT)
zlog_warn(
"%s: could not find nexthop ifindex for address %pPA(%s)",
- __func__, &src_addr, pim->vrf->name);
+ __func__, &src, pim->vrf->name);
return 0;
}
if (ifps[i]) {
nbrs[i] = pim_neighbor_find(
ifps[i], nexthop_tab[i].nexthop_addr);
- if (nbrs[i] ||
- pim_if_connected_to_source(ifps[i], src_addr))
+ if (nbrs[i] || pim_if_connected_to_source(ifps[i], src))
num_nbrs++;
}
}
// If PIM ECMP enable then choose ECMP path.
if (pim->ecmp_enable) {
+ struct prefix src_pfx;
uint32_t consider = num_ifindex;
if (neighbor_needed && num_nbrs < consider)
if (consider == 0)
return 0;
- hash_val = pim_compute_ecmp_hash(src, grp);
+ pim_addr_to_prefix(&src_pfx, src);
+ hash_val = pim_compute_ecmp_hash(&src_pfx, grp);
mod_val = hash_val % consider;
if (PIM_DEBUG_PIM_NHT_DETAIL)
zlog_debug("%s: hash_val %u mod_val %u", __func__,
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
"%s %s: could not find interface for ifindex %d (address %pPA(%s))",
- __FILE__, __func__, first_ifindex,
- &src_addr, pim->vrf->name);
+ __FILE__, __func__, first_ifindex, &src,
+ pim->vrf->name);
if (i == mod_val)
mod_val++;
i++;
zlog_debug(
"%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
__func__, ifp->name, pim->vrf->name,
- first_ifindex, &src_addr);
+ first_ifindex, &src);
if (i == mod_val)
mod_val++;
i++;
continue;
}
- if (neighbor_needed &&
- !pim_if_connected_to_source(ifp, src_addr)) {
+ if (neighbor_needed && !pim_if_connected_to_source(ifp, src)) {
nbr = nbrs[i];
if (PIM_DEBUG_PIM_NHT_DETAIL)
zlog_debug("ifp name: %s(%s), pim nbr: %p",
__func__,
&nexthop_tab[i].nexthop_addr,
ifp->name, pim->vrf->name,
- &src_addr);
+ &src);
i++;
continue;
}
zlog_debug(
"%s: found nhop %pPA for addr %pPA interface %s(%s) metric %d dist %d",
__func__, &nexthop_tab[i].nexthop_addr,
- &src_addr, ifp->name, pim->vrf->name,
+ &src, ifp->name, pim->vrf->name,
nexthop_tab[i].route_metric,
nexthop_tab[i].protocol_distance);
/* update nexthop data */
nexthop_tab[i].protocol_distance;
nexthop->mrib_route_metric =
nexthop_tab[i].route_metric;
- nexthop->last_lookup = src_addr;
+ nexthop->last_lookup = src;
nexthop->last_lookup_time = pim_time_monotonic_usec();
nexthop->nbr = nbr;
found = 1;
return 0;
}
-int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim,
- struct prefix *src, struct prefix *grp)
+int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim, pim_addr src,
+ struct prefix *grp)
{
struct pim_nexthop nhop;
int vif_index;
ifindex_t ifindex;
- pim_addr src_addr;
-
- if (PIM_DEBUG_PIM_NHT_DETAIL) {
- src_addr = pim_addr_from_prefix(src);
- }
memset(&nhop, 0, sizeof(nhop));
if (!pim_ecmp_nexthop_lookup(pim, &nhop, src, grp, 1)) {
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
"%s: could not find nexthop ifindex for address %pPA(%s)",
- __func__, &src_addr, pim->vrf->name);
+ __func__, &src, pim->vrf->name);
return -1;
}
"%s: found nexthop ifindex=%d (interface %s(%s)) for address %pPA",
__func__, ifindex,
ifindex2ifname(ifindex, pim->vrf->vrf_id),
- pim->vrf->name, &src_addr);
+ pim->vrf->name, &src);
vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex);
if (PIM_DEBUG_PIM_NHT) {
zlog_debug(
"%s: low vif_index=%d(%s) < 1 nexthop for address %pPA",
- __func__, vif_index, pim->vrf->name, &src_addr);
+ __func__, vif_index, pim->vrf->name, &src);
}
return -2;
}
};
int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS);
-int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr,
+int pim_find_or_track_nexthop(struct pim_instance *pim, pim_addr addr,
struct pim_upstream *up, struct rp_info *rp,
struct pim_nexthop_cache *out_pnc);
-void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
+void pim_delete_tracked_nexthop(struct pim_instance *pim, pim_addr addr,
struct pim_upstream *up, struct rp_info *rp);
struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_instance *pim,
struct pim_rpf *rpf);
uint32_t pim_compute_ecmp_hash(struct prefix *src, struct prefix *grp);
int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
- struct pim_nexthop *nexthop, struct prefix *src,
+ struct pim_nexthop *nexthop, pim_addr src,
struct prefix *grp, int neighbor_needed);
void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient,
struct pim_nexthop_cache *pnc, int command);
-int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim,
- struct prefix *src, struct prefix *grp);
+int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim, pim_addr src,
+ struct prefix *grp);
void pim_rp_nexthop_del(struct rp_info *rp_info);
/* for RPF check on BSM message receipt */
-void pim_nht_bsr_add(struct pim_instance *pim, struct in_addr bsr_addr);
-void pim_nht_bsr_del(struct pim_instance *pim, struct in_addr bsr_addr);
+void pim_nht_bsr_add(struct pim_instance *pim, pim_addr bsr_addr);
+void pim_nht_bsr_del(struct pim_instance *pim, pim_addr bsr_addr);
/* RPF(bsr_addr) == src_ip%src_ifp? */
-bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr,
+bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr,
struct interface *src_ifp, pim_addr src_ip);
#endif
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);
struct pim_instance *pim = pim_ifp->pim;
struct pim_upstream *up = NULL;
struct pim_rpf *rp;
- pim_addr rpf_addr;
pim_sgaddr sg;
struct listnode *up_node;
struct pim_upstream *child;
rp = RP(pim_ifp->pim, sg.grp);
if (rp) {
- rpf_addr = pim_addr_from_prefix(&rp->rpf_addr);
/* As per RFC 7761, Section 4.9.4:
* A special wildcard value consisting of an address field of
* all zeros can be used to indicate any source.
*/
- if ((pim_addr_cmp(sg.src, rpf_addr) == 0) ||
+ if ((pim_addr_cmp(sg.src, rp->rpf_addr) == 0) ||
pim_addr_is_any(sg.src)) {
handling_star = true;
sg.src = PIMADDR_ANY;
unsigned char *b1;
struct pim_interface *pinfo;
struct interface *ifp;
- pim_addr dst = pim_addr_from_prefix(&rpg->rpf_addr);
if (PIM_DEBUG_PIM_REG) {
zlog_debug("Sending %s %sRegister Packet to %pPA", up->sg_str,
- null_register ? "NULL " : "", &dst);
+ null_register ? "NULL " : "", &rpg->rpf_addr);
}
ifp = rpg->source_nexthop.interface;
if (PIM_DEBUG_PIM_REG) {
zlog_debug("%s: Sending %s %sRegister Packet to %pPA on %s",
__func__, up->sg_str, null_register ? "NULL " : "",
- &dst, ifp->name);
+ &rpg->rpf_addr, ifp->name);
}
memset(buffer, 0, 10000);
*/
src = pim_register_get_unicast_v6_addr(pinfo);
#endif
- pim_msg_build_header(src, dst, buffer, buf_size + PIM_MSG_REGISTER_LEN,
+ pim_msg_build_header(src, rpg->rpf_addr, buffer,
+ buf_size + PIM_MSG_REGISTER_LEN,
PIM_MSG_TYPE_REGISTER, false);
if (!pinfo->pim_passive_enable)
++pinfo->pim_ifstat_reg_send;
- if (pim_msg_send(pinfo->pim_sock_fd, src, dst, buffer,
+ if (pim_msg_send(pinfo->pim->reg_sock, src, rpg->rpf_addr, buffer,
buf_size + PIM_MSG_REGISTER_LEN, ifp)) {
if (PIM_DEBUG_PIM_TRACE) {
zlog_debug(
}
}
- rp_addr = pim_addr_from_prefix(&(RP(pim, sg.grp))->rpf_addr);
+ rp_addr = (RP(pim, sg.grp))->rpf_addr;
if (i_am_rp && (!pim_addr_cmp(dest_addr, rp_addr))) {
sentRegisterStop = 0;
#include "pim_bsm.h"
#include "pim_util.h"
#include "pim_ssm.h"
+#include "termtable.h"
/* Cleanup pim->rpf_hash each node data */
void pim_rp_list_hash_clean(void *data)
/*
* Sort by RP IP address
*/
- ret = prefix_cmp(&rp1->rp.rpf_addr, &rp2->rp.rpf_addr);
+ ret = pim_addr_cmp(rp1->rp.rpf_addr, rp2->rp.rpf_addr);
if (ret)
return ret;
XFREE(MTYPE_PIM_RP, rp_info);
return;
}
- pim_addr_to_prefix(&rp_info->rp.rpf_addr, PIMADDR_ANY);
+ rp_info->rp.rpf_addr = PIMADDR_ANY;
listnode_add(pim->rp_list, rp_info);
{
struct listnode *node;
struct rp_info *rp_info;
- struct prefix rp_prefix;
-
- pim_addr_to_prefix(&rp_prefix, rp);
for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
- if (prefix_same(&rp_prefix, &rp_info->rp.rpf_addr) &&
+ if ((!pim_addr_cmp(rp, rp_info->rp.rpf_addr)) &&
rp_info->plist && strcmp(rp_info->plist, plist) == 0) {
return rp_info;
}
{
struct listnode *node;
struct rp_info *rp_info;
- struct prefix rp_prefix;
- pim_addr_to_prefix(&rp_prefix, rp);
for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
- if (prefix_same(&rp_prefix, &rp_info->rp.rpf_addr) &&
+ if ((!pim_addr_cmp(rp, rp_info->rp.rpf_addr)) &&
prefix_same(&rp_info->group, group))
return rp_info;
}
{
struct listnode *node;
struct pim_secondary_addr *sec_addr;
- pim_addr rpf_addr;
-
- rpf_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr);
+ pim_addr sec_paddr;
- if (!pim_addr_cmp(pim_ifp->primary_address, rpf_addr))
+ if (!pim_addr_cmp(pim_ifp->primary_address, rp_info->rp.rpf_addr))
return 1;
if (!pim_ifp->sec_addr_list) {
}
for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
- if (prefix_same(&sec_addr->addr, &rp_info->rp.rpf_addr)) {
+ sec_paddr = pim_addr_from_prefix(&sec_addr->addr);
+ /* If an RP-address is self, It should be enough to say
+ * I am RP the prefix-length should not matter here */
+ if (!pim_addr_cmp(sec_paddr, rp_info->rp.rpf_addr))
return 1;
- }
}
return 0;
enum pim_rpf_result rpf_result;
pim_addr old_upstream_addr;
pim_addr new_upstream_addr;
- struct prefix nht_p;
old_upstream_addr = up->upstream_addr;
pim_rp_set_upstream_addr(pim, &new_upstream_addr, up->sg.src,
*/
if (!pim_addr_is_any(old_upstream_addr)) {
/* Deregister addr with Zebra NHT */
- pim_addr_to_prefix(&nht_p, old_upstream_addr);
if (PIM_DEBUG_PIM_TRACE)
zlog_debug(
- "%s: Deregister upstream %s addr %pFX with Zebra NHT",
- __func__, up->sg_str, &nht_p);
- pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
+ "%s: Deregister upstream %s addr %pPA with Zebra NHT",
+ __func__, up->sg_str, &old_upstream_addr);
+ pim_delete_tracked_nexthop(pim, old_upstream_addr, up, NULL);
}
/* Update the upstream address */
struct listnode *node, *nnode;
struct rp_info *tmp_rp_info;
char buffer[BUFSIZ];
- struct prefix nht_p;
+ pim_addr nht_p;
struct route_node *rn = NULL;
struct pim_upstream *up;
bool upstream_updated = false;
rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info));
- pim_addr_to_prefix(&rp_info->rp.rpf_addr, rp_addr);
+ rp_info->rp.rpf_addr = rp_addr;
prefix_copy(&rp_info->group, &group);
rp_info->rp_src = rp_src_flag;
*/
for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode,
tmp_rp_info)) {
- if (prefix_same(&rp_info->rp.rpf_addr,
- &tmp_rp_info->rp.rpf_addr)) {
+ if (!pim_addr_cmp(rp_info->rp.rpf_addr,
+ tmp_rp_info->rp.rpf_addr)) {
if (tmp_rp_info->plist)
pim_rp_del_config(pim, rp_addr, NULL,
tmp_rp_info->plist);
for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode,
tmp_rp_info)) {
if (tmp_rp_info->plist &&
- prefix_same(&rp_info->rp.rpf_addr,
- &tmp_rp_info->rp.rpf_addr)) {
+ (!pim_addr_cmp(rp_info->rp.rpf_addr,
+ tmp_rp_info->rp.rpf_addr))) {
pim_rp_del_config(pim, rp_addr, NULL,
tmp_rp_info->plist);
}
nht_p = rp_all->rp.rpf_addr;
if (PIM_DEBUG_PIM_NHT_RP)
zlog_debug(
- "%s: NHT Register rp_all addr %pFX grp %pFX ",
+ "%s: NHT Register rp_all addr %pPA grp %pFX ",
__func__, &nht_p, &rp_all->group);
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
pim_rp_check_interfaces(pim, rp_all);
pim_rp_refresh_group_to_rp_mapping(pim);
- pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_all,
+ pim_find_or_track_nexthop(pim, nht_p, NULL, rp_all,
NULL);
if (!pim_ecmp_nexthop_lookup(pim,
&rp_all->rp.source_nexthop,
- &nht_p, &rp_all->group, 1))
+ nht_p, &rp_all->group, 1))
return PIM_RP_NO_PATH;
return PIM_SUCCESS;
}
/* Register addr with Zebra NHT */
nht_p = rp_info->rp.rpf_addr;
if (PIM_DEBUG_PIM_NHT_RP)
- zlog_debug("%s: NHT Register RP addr %pFX grp %pFX with Zebra ",
+ zlog_debug("%s: NHT Register RP addr %pPA grp %pFX with Zebra ",
__func__, &nht_p, &rp_info->group);
- pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, NULL);
- if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, &nht_p,
+ pim_find_or_track_nexthop(pim, nht_p, NULL, rp_info, NULL);
+ if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, nht_p,
&rp_info->group, 1))
return PIM_RP_NO_PATH;
struct prefix g_all;
struct rp_info *rp_info;
struct rp_info *rp_all;
- struct prefix nht_p;
+ pim_addr nht_p;
struct route_node *rn;
bool was_plist = false;
struct rp_info *trp_info;
/* Deregister addr with Zebra NHT */
nht_p = rp_info->rp.rpf_addr;
if (PIM_DEBUG_PIM_NHT_RP)
- zlog_debug("%s: Deregister RP addr %pFX with Zebra ", __func__,
+ zlog_debug("%s: Deregister RP addr %pPA with Zebra ", __func__,
&nht_p);
- pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info);
+ pim_delete_tracked_nexthop(pim, nht_p, NULL, rp_info);
if (!pim_get_all_mcast_group(&g_all))
return PIM_RP_BAD_ADDRESS;
*/
pim_addr rpf_addr;
- rpf_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr);
+ rpf_addr = rp_info->rp.rpf_addr;
if (!pim_addr_cmp(up->upstream_addr, rpf_addr) &&
pim_addr_is_any(up->sg.src)) {
struct prefix grp;
}
}
}
- pim_addr_to_prefix(&rp_all->rp.rpf_addr, PIMADDR_ANY);
+ rp_all->rp.rpf_addr = PIMADDR_ANY;
rp_all->i_am_rp = 0;
return PIM_SUCCESS;
}
*/
pim_addr rpf_addr;
- rpf_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr);
+ rpf_addr = rp_info->rp.rpf_addr;
if (!pim_addr_cmp(up->upstream_addr, rpf_addr) &&
pim_addr_is_any(up->sg.src)) {
struct prefix grp;
int pim_rp_change(struct pim_instance *pim, pim_addr new_rp_addr,
struct prefix group, enum rp_source rp_src_flag)
{
- struct prefix nht_p;
+ pim_addr nht_p;
struct route_node *rn;
int result = 0;
struct rp_info *rp_info = NULL;
return result;
}
- old_rp_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr);
+ old_rp_addr = rp_info->rp.rpf_addr;
if (!pim_addr_cmp(new_rp_addr, old_rp_addr)) {
if (rp_info->rp_src != rp_src_flag) {
rp_info->rp_src = rp_src_flag;
}
}
- nht_p.family = PIM_AF;
- nht_p.prefixlen = PIM_MAX_BITLEN;
-
/* Deregister old RP addr with Zebra NHT */
if (!pim_addr_is_any(old_rp_addr)) {
nht_p = rp_info->rp.rpf_addr;
if (PIM_DEBUG_PIM_NHT_RP)
- zlog_debug("%s: Deregister RP addr %pFX with Zebra ",
+ zlog_debug("%s: Deregister RP addr %pPA with Zebra ",
__func__, &nht_p);
- pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info);
+ pim_delete_tracked_nexthop(pim, nht_p, NULL, rp_info);
}
pim_rp_nexthop_del(rp_info);
listnode_delete(pim->rp_list, rp_info);
/* Update the new RP address*/
- pim_addr_to_prefix(&rp_info->rp.rpf_addr, new_rp_addr);
+ rp_info->rp.rpf_addr = new_rp_addr;
rp_info->rp_src = rp_src_flag;
rp_info->i_am_rp = 0;
/* Register new RP addr with Zebra NHT */
nht_p = rp_info->rp.rpf_addr;
if (PIM_DEBUG_PIM_NHT_RP)
- zlog_debug("%s: NHT Register RP addr %pFX grp %pFX with Zebra ",
+ zlog_debug("%s: NHT Register RP addr %pPA grp %pFX with Zebra ",
__func__, &nht_p, &rp_info->group);
- pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, NULL);
- if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, &nht_p,
+ pim_find_or_track_nexthop(pim, nht_p, NULL, rp_info, NULL);
+ if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, nht_p,
&rp_info->group, 1)) {
route_unlock_node(rn);
return PIM_RP_NO_PATH;
{
struct listnode *node;
struct rp_info *rp_info;
- struct prefix nht_p;
+ pim_addr nht_p;
for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
nht_p = rp_info->rp.rpf_addr;
- pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, NULL);
+ pim_find_or_track_nexthop(pim, nht_p, NULL, rp_info, NULL);
if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
- &nht_p, &rp_info->group, 1))
+ nht_p, &rp_info->group, 1))
if (PIM_DEBUG_PIM_NHT_RP)
zlog_debug(
"Unable to lookup nexthop for rp specified");
if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
i_am_rp_changed = true;
rp_info->i_am_rp = 1;
- if (PIM_DEBUG_PIM_NHT_RP) {
- char rp[PREFIX_STRLEN];
- pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr,
- rp, sizeof(rp));
- zlog_debug("%s: %s: i am rp", __func__, rp);
- }
+ if (PIM_DEBUG_PIM_NHT_RP)
+ zlog_debug("%s: %pPA: i am rp", __func__,
+ &rp_info->rp.rpf_addr);
}
}
if (old_i_am_rp != rp_info->i_am_rp) {
i_am_rp_changed = true;
if (PIM_DEBUG_PIM_NHT_RP) {
- char rp[PREFIX_STRLEN];
- pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr,
- rp, sizeof(rp));
- if (rp_info->i_am_rp) {
- zlog_debug("%s: %s: i am rp", __func__,
- rp);
- } else {
- zlog_debug("%s: %s: i am no longer rp",
- __func__, rp);
- }
+ if (rp_info->i_am_rp)
+ zlog_debug("%s: %pPA: i am rp",
+ __func__,
+ &rp_info->rp.rpf_addr);
+ else
+ zlog_debug(
+ "%s: %pPA: i am no longer rp",
+ __func__,
+ &rp_info->rp.rpf_addr);
}
}
}
rp_info = pim_rp_find_match_group(pim, &g);
if (rp_info) {
- struct prefix nht_p;
+ pim_addr nht_p;
/* Register addr with Zebra NHT */
nht_p = rp_info->rp.rpf_addr;
if (PIM_DEBUG_PIM_NHT_RP)
zlog_debug(
- "%s: NHT Register RP addr %pFX grp %pFX with Zebra",
+ "%s: NHT Register RP addr %pPA grp %pFX with Zebra",
__func__, &nht_p, &rp_info->group);
- pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, NULL);
+ pim_find_or_track_nexthop(pim, nht_p, NULL, rp_info, NULL);
pim_rpf_set_refresh_time(pim);
(void)pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
- &nht_p, &rp_info->group, 1);
+ nht_p, &rp_info->group, 1);
return (&rp_info->rp);
}
}
if (pim_addr_is_any(source))
- *up = pim_addr_from_prefix(&rp_info->rp.rpf_addr);
+ *up = rp_info->rp.rpf_addr;
else
*up = source;
if (rp_info->rp_src == RP_SRC_BSR)
continue;
- rp_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr);
+ rp_addr = rp_info->rp.rpf_addr;
if (rp_info->plist)
vty_out(vty,
"%s" PIM_AF_NAME
struct rp_info *rp_info;
struct rp_info *prev_rp_info = NULL;
struct listnode *node;
+ struct ttable *tt = NULL;
+ char *table = NULL;
char source[7];
+ char grp[INET6_ADDRSTRLEN];
json_object *json_rp_rows = NULL;
json_object *json_row = NULL;
- if (!json)
- vty_out(vty,
- "RP address group/prefix-list OIF I am RP Source Group-Type\n");
+ if (!json) {
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(
+ tt,
+ "RP address|group/prefix-list|OIF|I am RP|Source|Group-Type");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+ }
+
for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
continue;
* entry for the previous RP
*/
if (prev_rp_info &&
- prefix_cmp(&prev_rp_info->rp.rpf_addr,
- &rp_info->rp.rpf_addr)) {
+ (pim_addr_cmp(prev_rp_info->rp.rpf_addr,
+ rp_info->rp.rpf_addr))) {
json_object_object_addf(
- json, json_rp_rows, "%pFXh",
+ json, json_rp_rows, "%pPA",
&prev_rp_info->rp.rpf_addr);
json_rp_rows = NULL;
}
json_rp_rows = json_object_new_array();
json_row = json_object_new_object();
- json_object_string_addf(json_row, "rpAddress", "%pFXh",
+ json_object_string_addf(json_row, "rpAddress", "%pPA",
&rp_info->rp.rpf_addr);
if (rp_info->rp.source_nexthop.interface)
json_object_string_add(
json_object_array_add(json_rp_rows, json_row);
} else {
- vty_out(vty, "%-15pFXh ", &rp_info->rp.rpf_addr);
-
- if (rp_info->plist)
- vty_out(vty, "%-18s ", rp_info->plist);
- else
- vty_out(vty, "%-18pFX ", &rp_info->group);
-
- if (rp_info->rp.source_nexthop.interface)
- vty_out(vty, "%-16s ",
- rp_info->rp.source_nexthop
- .interface->name);
- else
- vty_out(vty, "%-16s ", "(Unknown)");
-
- if (rp_info->i_am_rp)
- vty_out(vty, "yes");
- else
- vty_out(vty, "no");
-
- vty_out(vty, "%14s", source);
- vty_out(vty, "%6s\n", group_type);
+ prefix2str(&rp_info->group, grp, sizeof(grp));
+ ttable_add_row(tt, "%pPA|%s|%s|%s|%s|%s",
+ &rp_info->rp.rpf_addr,
+ rp_info->plist
+ ? rp_info->plist
+ : grp,
+ rp_info->rp.source_nexthop.interface
+ ? rp_info->rp.source_nexthop
+ .interface->name
+ : "Unknown",
+ rp_info->i_am_rp
+ ? "yes"
+ : "no",
+ source, group_type);
}
prev_rp_info = rp_info;
}
- if (json) {
+ /* Dump the generated table. */
+ if (!json) {
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+ } else {
if (prev_rp_info && json_rp_rows)
- json_object_object_addf(json, json_rp_rows, "%pFXh",
+ json_object_object_addf(json, json_rp_rows, "%pPA",
&prev_rp_info->rp.rpf_addr);
}
}
struct listnode *node = NULL;
struct rp_info *rp_info = NULL;
struct nexthop *nh_node = NULL;
- struct prefix nht_p;
+ pim_addr nht_p;
struct pim_nexthop_cache pnc;
for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
nht_p = rp_info->rp.rpf_addr;
memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
- if (!pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info,
- &pnc))
+ if (!pim_find_or_track_nexthop(pim, nht_p, NULL, rp_info, &pnc))
continue;
for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) {
#endif
if (PIM_DEBUG_PIM_NHT_RP)
zlog_debug(
- "%s: addr %pFXh new nexthop addr %pPAs interface %s",
+ "%s: addr %pPA new nexthop addr %pPAs interface %s",
__func__, &nht_p, &nbr->source_addr,
ifp1->name);
}
{
struct pim_rpf *rpf = &up->rpf;
struct pim_rpf saved;
- struct prefix nht_p;
- struct prefix src, grp;
+ pim_addr src;
+ struct prefix grp;
bool neigh_needed = true;
uint32_t saved_mrib_route_metric;
- pim_addr rpf_addr;
if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags))
return PIM_RPF_OK;
old->rpf_addr = saved.rpf_addr;
}
- pim_addr_to_prefix(&nht_p, up->upstream_addr);
-
- pim_addr_to_prefix(&src, up->upstream_addr); // RP or Src address
+ src = up->upstream_addr; // RP or Src address
pim_addr_to_prefix(&grp, up->sg.grp);
if ((pim_addr_is_any(up->sg.src) && I_am_RP(pim, up->sg.grp)) ||
PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
neigh_needed = false;
- pim_find_or_track_nexthop(pim, &nht_p, up, NULL, NULL);
- if (!pim_ecmp_nexthop_lookup(pim, &rpf->source_nexthop, &src, &grp,
- neigh_needed)) {
+ pim_find_or_track_nexthop(pim, up->upstream_addr, up, NULL, NULL);
+ if (!pim_ecmp_nexthop_lookup(pim, &rpf->source_nexthop, src, &grp,
+ neigh_needed)) {
/* Route is Deleted in Zebra, reset the stored NH data */
pim_upstream_rpf_clear(pim, up);
pim_rpf_cost_change(pim, up, saved_mrib_route_metric);
return PIM_RPF_FAILURE;
}
- rpf_addr = pim_rpf_find_rpf_addr(up);
- pim_addr_to_prefix(&rpf->rpf_addr, rpf_addr);
+ rpf->rpf_addr = pim_rpf_find_rpf_addr(up);
if (pim_rpf_addr_is_inaddr_any(rpf) && PIM_DEBUG_ZEBRA) {
/* RPF'(S,G) not found */
}
/* detect change in RPF'(S,G) */
- if (!prefix_same(&saved.rpf_addr, &rpf->rpf_addr) ||
+ if (pim_addr_cmp(saved.rpf_addr, rpf->rpf_addr) ||
saved.source_nexthop.interface != rpf->source_nexthop.interface) {
pim_rpf_cost_change(pim, up, saved_mrib_route_metric);
return PIM_RPF_CHANGED;
router->infinite_assert_metric.metric_preference;
up->rpf.source_nexthop.mrib_route_metric =
router->infinite_assert_metric.route_metric;
- pim_addr_to_prefix(&up->rpf.rpf_addr, PIMADDR_ANY);
+ up->rpf.rpf_addr = PIMADDR_ANY;
pim_upstream_mroute_iif_update(up->channel_oil, __func__);
}
}
int pim_rpf_addr_is_inaddr_any(struct pim_rpf *rpf)
{
- pim_addr rpf_addr = pim_addr_from_prefix(&rpf->rpf_addr);
-
- switch (rpf->rpf_addr.family) {
- case AF_INET:
- case AF_INET6:
- return pim_addr_is_any(rpf_addr);
- default:
- return 0;
- }
+ return pim_addr_is_any(rpf->rpf_addr);
}
int pim_rpf_is_same(struct pim_rpf *rpf1, struct pim_rpf *rpf2)
const struct pim_nexthop_cache *r = arg;
#if PIM_IPV == 4
- return jhash_1word(r->rpf.rpf_addr.u.prefix4.s_addr, 0);
+ return jhash_1word(r->rpf.rpf_addr.s_addr, 0);
#else
- return jhash2(r->rpf.rpf_addr.u.prefix6.s6_addr32,
- array_size(r->rpf.rpf_addr.u.prefix6.s6_addr32), 0);
+ return jhash2(r->rpf.rpf_addr.s6_addr32,
+ array_size(r->rpf.rpf_addr.s6_addr32), 0);
#endif
}
const struct pim_nexthop_cache *r2 =
(const struct pim_nexthop_cache *)arg2;
- return prefix_same(&r1->rpf.rpf_addr, &r2->rpf.rpf_addr);
+ return (!pim_addr_cmp(r1->rpf.rpf_addr, r2->rpf.rpf_addr));
}
struct pim_rpf {
struct pim_nexthop source_nexthop;
- struct prefix rpf_addr; /* RPF'(S,G) */
+ pim_addr rpf_addr; /* RPF'(S,G) */
};
enum pim_rpf_result { PIM_RPF_OK = 0, PIM_RPF_CHANGED, PIM_RPF_FAILURE };
}
#endif
+int pim_reg_sock(void)
+{
+ int fd;
+ long flags;
+
+ frr_with_privs (&pimd_privs) {
+ fd = socket(PIM_AF, SOCK_RAW, IPPROTO_RAW);
+ }
+
+ if (fd < 0) {
+ zlog_warn("Could not create raw socket: errno=%d: %s", errno,
+ safe_strerror(errno));
+ return PIM_SOCK_ERR_SOCKET;
+ }
+
+ if (sockopt_reuseaddr(fd)) {
+ close(fd);
+ return PIM_SOCK_ERR_REUSE;
+ }
+
+ flags = fcntl(fd, F_GETFL, 0);
+ if (flags < 0) {
+ zlog_warn(
+ "Could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
+ fd, errno, safe_strerror(errno));
+ close(fd);
+ return PIM_SOCK_ERR_NONBLOCK_GETFL;
+ }
+
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
+ zlog_warn(
+ "Could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
+ fd, errno, safe_strerror(errno));
+ close(fd);
+ return PIM_SOCK_ERR_NONBLOCK_SETFL;
+ }
+
+ return fd;
+}
+
int pim_socket_mcast(int protocol, pim_addr ifaddr, struct interface *ifp,
uint8_t loop)
{
int pim_socket_getsockname(int fd, struct sockaddr *name, socklen_t *namelen);
+int pim_reg_sock(void);
+
#endif /* PIM_SOCK_H */
}
for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
- if (!pim_addr_cmp(s_route->group, group)
- && !pim_addr_cmp(s_route->source, source)) {
- if (s_route->iif == iif_index
- && s_route->oif_ttls[oif_index]) {
+ if (!pim_addr_cmp(s_route->group, group) &&
+ !pim_addr_cmp(s_route->source, source) &&
+ (s_route->iif == iif_index)) {
+
+ if (s_route->oif_ttls[oif_index]) {
zlog_warn(
"%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%pPAs,source=%pPAs)",
__FILE__, __func__, iif_index,
/* Route exists and has the same input interface, but
* adding a new output interface */
- if (s_route->iif == iif_index) {
- s_route->oif_ttls[oif_index] = 1;
- oil_if_set(&s_route->c_oil, oif_index, 1);
- s_route->c_oil.oif_creation[oif_index] =
- pim_time_monotonic_sec();
- ++s_route->c_oil.oil_ref_count;
- } else {
- /* input interface changed */
- s_route->iif = iif_index;
- pim_static_mroute_iif_update(
- &s_route->c_oil, iif_index, __func__);
-
-#ifdef PIM_ENFORCE_LOOPFREE_MFC
- /* check to make sure the new input was not an
- * old output */
- if (s_route->oif_ttls[iif_index]) {
- s_route->oif_ttls[iif_index] = 0;
- s_route->c_oil.oif_creation[iif_index] =
- 0;
- oil_if_set(&s_route->c_oil, iif_index,
- 0);
- --s_route->c_oil.oil_ref_count;
- }
-#endif
-
- /* now add the new output, if it is new */
- if (!s_route->oif_ttls[oif_index]) {
- s_route->oif_ttls[oif_index] = 1;
- s_route->c_oil.oif_creation[oif_index] =
- pim_time_monotonic_sec();
- oil_if_set(&s_route->c_oil, oif_index,
- 1);
- ++s_route->c_oil.oil_ref_count;
- }
- }
-
+ s_route->oif_ttls[oif_index] = 1;
+ oil_if_set(&s_route->c_oil, oif_index, 1);
+ s_route->c_oil.oif_creation[oif_index] =
+ pim_time_monotonic_sec();
+ ++s_route->c_oil.oil_ref_count;
break;
}
}
#include "prefix.h"
#include "pim_addr.h"
-#include "pim_addr.h"
-
+#if PIM_IPV == 4
/*
- * Longest possible length of a (S,G) string is 36 bytes
+ * Longest possible length of a IPV4 (S,G) string is 34 bytes
* 123.123.123.123 = 16 * 2
* (,) = 3
* NULL Character at end = 1
- * (123.123.123.123,123,123,123,123)
+ * (123.123.123.123,123.123.123.123)
*/
#define PIM_SG_LEN PREFIX_SG_STR_LEN
+#else
+/*
+ * Longest possible length of a IPV6 (S,G) string is 94 bytes
+ * INET6_ADDRSTRLEN * 2 = 46 * 2
+ * (,) = 3
+ * NULL Character at end = 1
+ */
+#define PIM_SG_LEN 96
+#endif
+
#define pim_inet4_dump prefix_mcast_inet4_dump
void pim_addr_dump(const char *onfail, struct prefix *p, char *buf,
struct pim_interface *pim_oif = oif->info;
int input_iface_vif_index = 0;
pim_addr vif_source;
- struct prefix src, grp;
+ struct prefix grp;
struct pim_nexthop nexthop;
struct pim_upstream *up = NULL;
return pim_channel_oil_add(pim, &sg, __func__);
}
- pim_addr_to_prefix(&src, vif_source); // RP or Src addr
pim_addr_to_prefix(&grp, sg.grp);
up = pim_upstream_find(pim, &sg);
if (up) {
memcpy(&nexthop, &up->rpf.source_nexthop,
sizeof(struct pim_nexthop));
- pim_ecmp_nexthop_lookup(pim, &nexthop, &src, &grp, 0);
+ pim_ecmp_nexthop_lookup(pim, &nexthop, vif_source, &grp, 0);
if (nexthop.interface)
input_iface_vif_index = pim_if_find_vifindex_by_ifindex(
pim, nexthop.interface->ifindex);
} else
input_iface_vif_index =
- pim_ecmp_fib_lookup_if_vif_index(pim, &src, &grp);
+ pim_ecmp_fib_lookup_if_vif_index(pim, vif_source, &grp);
if (PIM_DEBUG_ZEBRA)
zlog_debug("%s: NHT %pSG vif_source %pPAs vif_index:%d",
*buf++ = PIM_MSG_ADDRESS_FAMILY;
*buf++ = 0;
*buf++ = flags;
- *buf++ = sizeof(group) / 8;
+ *buf++ = sizeof(group) * 8;
memcpy(buf, &group, sizeof(group));
buf += sizeof(group);
struct listnode *node, *nnode;
struct pim_ifchannel *ch;
bool notify_msdp = false;
- struct prefix nht_p;
if (PIM_DEBUG_PIM_TRACE)
zlog_debug(
*/
if (!pim_addr_is_any(up->upstream_addr)) {
/* Deregister addr with Zebra NHT */
- pim_addr_to_prefix(&nht_p, up->upstream_addr);
if (PIM_DEBUG_PIM_TRACE)
zlog_debug(
- "%s: Deregister upstream %s addr %pFX with Zebra NHT",
- __func__, up->sg_str, &nht_p);
- pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
+ "%s: Deregister upstream %s addr %pPA with Zebra NHT",
+ __func__, up->sg_str, &up->upstream_addr);
+ pim_delete_tracked_nexthop(pim, up->upstream_addr, up, NULL);
}
XFREE(MTYPE_PIM_UPSTREAM, up);
}
if (PIM_DEBUG_PIM_TRACE) {
- char rpf_str[PREFIX_STRLEN];
- pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str,
- sizeof(rpf_str));
- zlog_debug("%s: RPF'%s=%s(%s) for Interface %s", __func__,
- up->sg_str, rpf_str,
+ zlog_debug("%s: RPF'%s=%pPA(%s) for Interface %s", __func__,
+ up->sg_str, &up->rpf.rpf_addr,
pim_upstream_state2str(up->join_state),
up->rpf.source_nexthop.interface->name);
if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
- zlog_debug("%s: can't send join upstream: RPF'%s=%s",
- __func__, up->sg_str, rpf_str);
+ zlog_debug("%s: can't send join upstream: RPF'%s=%pPA",
+ __func__, up->sg_str, &up->rpf.rpf_addr);
/* warning only */
}
}
THREAD_OFF(up->t_join_timer);
if (up->rpf.source_nexthop.interface)
- nbr = pim_neighbor_find_prefix(up->rpf.source_nexthop.interface,
- &up->rpf.rpf_addr);
+ nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
+ up->rpf.rpf_addr);
if (nbr)
pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr);
struct pim_neighbor *nbr = NULL;
if (up->rpf.source_nexthop.interface) {
- nbr = pim_neighbor_find_prefix(up->rpf.source_nexthop.interface,
- &up->rpf.rpf_addr);
+ nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
+ up->rpf.rpf_addr);
if (PIM_DEBUG_PIM_EVENTS) {
zlog_debug(
}
}
-void pim_upstream_join_suppress(struct pim_upstream *up, struct prefix rpf,
+void pim_upstream_join_suppress(struct pim_upstream *up, pim_addr rpf,
int holdtime)
{
long t_joinsuppress_msec;
pim_time_timer_remain_msec(up->t_join_timer);
else {
/* Remove it from jp agg from the nbr for suppression */
- nbr = pim_neighbor_find_prefix(up->rpf.source_nexthop.interface,
- &up->rpf.rpf_addr);
+ nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
+ up->rpf.rpf_addr);
if (nbr) {
join_timer_remain_msec =
pim_time_timer_remain_msec(nbr->jp_timer);
}
}
- if (PIM_DEBUG_PIM_TRACE) {
- char rpf_str[INET_ADDRSTRLEN];
-
- pim_addr_dump("<rpf?>", &rpf, rpf_str, sizeof(rpf_str));
+ if (PIM_DEBUG_PIM_TRACE)
zlog_debug(
- "%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
- __FILE__, __func__, up->sg_str, rpf_str,
+ "%s %s: detected Join%s to RPF'(S,G)=%pPA: join_timer=%ld msec t_joinsuppress=%ld msec",
+ __FILE__, __func__, up->sg_str, &rpf,
join_timer_remain_msec, t_joinsuppress_msec);
- }
if (join_timer_remain_msec < t_joinsuppress_msec) {
if (PIM_DEBUG_PIM_TRACE) {
/* upstream join tracked with neighbor jp timer */
struct pim_neighbor *nbr;
- nbr = pim_neighbor_find_prefix(up->rpf.source_nexthop.interface,
- &up->rpf.rpf_addr);
+ nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
+ up->rpf.rpf_addr);
if (nbr)
join_timer_remain_msec =
pim_time_timer_remain_msec(nbr->jp_timer);
join_timer_remain_msec = t_override_msec + 1;
}
- if (PIM_DEBUG_PIM_TRACE) {
- char rpf_str[INET_ADDRSTRLEN];
-
- pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str,
- sizeof(rpf_str));
-
+ if (PIM_DEBUG_PIM_TRACE)
zlog_debug(
- "%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
- debug_label, up->sg_str, rpf_str,
+ "%s: to RPF'%s=%pPA: join_timer=%ld msec t_override=%d msec",
+ debug_label, up->sg_str, &up->rpf.rpf_addr,
join_timer_remain_msec, t_override_msec);
- }
if (join_timer_remain_msec > t_override_msec) {
if (PIM_DEBUG_PIM_TRACE) {
up->rpf.source_nexthop.mrib_metric_preference =
ZEBRA_CONNECT_DISTANCE_DEFAULT;
up->rpf.source_nexthop.mrib_route_metric = 0;
- up->rpf.rpf_addr.family = AF_INET;
- up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
-
+ up->rpf.rpf_addr = PIMADDR_ANY;
}
static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
router->infinite_assert_metric.metric_preference;
up->rpf.source_nexthop.mrib_route_metric =
router->infinite_assert_metric.route_metric;
- pim_addr_to_prefix(&up->rpf.rpf_addr, PIMADDR_ANY);
+ up->rpf.rpf_addr = PIMADDR_ANY;
up->ifchannels = list_new();
up->ifchannels->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
__func__, up->sg_str);
}
- if (up->rpf.source_nexthop.interface) {
+ /* Consider a case where (S,G,rpt) prune is received and this
+ * upstream is getting created due to that, then as per RFC
+ * until prune pending time we need to behave same as NOINFO
+ * state, therefore do not install if OIF is NULL until then
+ * This is for PIM Conformance PIM-SM 16.3 fix
+ * When the prune pending timer pop, this mroute will get
+ * installed with none as OIF */
+ if (up->rpf.source_nexthop.interface &&
+ !(pim_upstream_empty_inherited_olist(up) && (ch != NULL) &&
+ PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))) {
pim_upstream_mroute_iif_update(up->channel_oil,
__func__);
}
}
if (PIM_DEBUG_PIM_TRACE) {
- if (up)
- zlog_debug("%s(%s): %s, iif %pFX (%s) found: %d: ref_count: %d",
- __func__, name,
- up->sg_str, &up->rpf.rpf_addr, up->rpf.source_nexthop.interface ?
- up->rpf.source_nexthop.interface->name : "Unknown" ,
- found, up->ref_count);
- else
- zlog_debug("%s(%s): (%pSG) failure to create", __func__,
- name, sg);
+ zlog_debug(
+ "%s(%s): %s, iif %pPA (%s) found: %d: ref_count: %d",
+ __func__, name, up->sg_str, &up->rpf.rpf_addr,
+ up->rpf.source_nexthop.interface ? up->rpf.source_nexthop
+ .interface->name
+ : "Unknown",
+ found, up->ref_count);
}
return up;
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
pim_addr rpf_addr;
- rpf_addr = pim_addr_from_prefix(&up->rpf.rpf_addr);
+ rpf_addr = up->rpf.rpf_addr;
if (PIM_DEBUG_PIM_TRACE)
zlog_debug(
struct pim_upstream *up);
void pim_update_suppress_timers(uint32_t suppress_time);
-void pim_upstream_join_suppress(struct pim_upstream *up, struct prefix rpf,
+void pim_upstream_join_suppress(struct pim_upstream *up, pim_addr rpf,
int holdtime);
void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
/* PIM_DEBUG_MROUTE catches _DETAIL too */
if (router->debugs & PIM_MASK_MROUTE) {
- vty_out(vty, "debug mroute\n");
+ vty_out(vty, "debug " PIM_MROUTE_DBG "\n");
++writes;
}
if (PIM_DEBUG_MROUTE_DETAIL) {
- vty_out(vty, "debug mroute detail\n");
+ vty_out(vty, "debug " PIM_MROUTE_DBG " detail\n");
++writes;
}
}
if (PIM_DEBUG_PIM_EVENTS) {
- vty_out(vty, "debug pim events\n");
+ vty_out(vty, "debug " PIM_AF_DBG " events\n");
++writes;
}
if (PIM_DEBUG_PIM_PACKETS) {
- vty_out(vty, "debug pim packets\n");
+ vty_out(vty, "debug " PIM_AF_DBG " packets\n");
++writes;
}
if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
- vty_out(vty, "debug pim packet-dump send\n");
+ vty_out(vty, "debug " PIM_AF_DBG " packet-dump send\n");
++writes;
}
if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
- vty_out(vty, "debug pim packet-dump receive\n");
+ vty_out(vty, "debug " PIM_AF_DBG " packet-dump receive\n");
++writes;
}
/* PIM_DEBUG_PIM_TRACE catches _DETAIL too */
if (router->debugs & PIM_MASK_PIM_TRACE) {
- vty_out(vty, "debug pim trace\n");
+ vty_out(vty, "debug " PIM_AF_DBG " trace\n");
++writes;
}
if (PIM_DEBUG_PIM_TRACE_DETAIL) {
- vty_out(vty, "debug pim trace detail\n");
+ vty_out(vty, "debug " PIM_AF_DBG " trace detail\n");
++writes;
}
if (PIM_DEBUG_ZEBRA) {
- vty_out(vty, "debug pim zebra\n");
+ vty_out(vty, "debug " PIM_AF_DBG " zebra\n");
++writes;
}
}
if (PIM_DEBUG_BSM) {
- vty_out(vty, "debug pim bsm\n");
+ vty_out(vty, "debug " PIM_AF_DBG " bsm\n");
++writes;
}
if (PIM_DEBUG_VXLAN) {
- vty_out(vty, "debug pim vxlan\n");
+ vty_out(vty, "debug " PIM_AF_DBG " vxlan\n");
++writes;
}
}
if (PIM_DEBUG_PIM_HELLO) {
- vty_out(vty, "debug pim packets hello\n");
+ vty_out(vty, "debug " PIM_AF_DBG " packets hello\n");
++writes;
}
if (PIM_DEBUG_PIM_J_P) {
- vty_out(vty, "debug pim packets joins\n");
+ vty_out(vty, "debug " PIM_AF_DBG " packets joins\n");
++writes;
}
if (PIM_DEBUG_PIM_REG) {
- vty_out(vty, "debug pim packets register\n");
+ vty_out(vty, "debug " PIM_AF_DBG " packets register\n");
++writes;
}
}
if (PIM_DEBUG_PIM_NHT) {
- vty_out(vty, "debug pim nht\n");
+ vty_out(vty, "debug " PIM_AF_DBG " nht\n");
++writes;
}
}
if (PIM_DEBUG_PIM_NHT_DETAIL) {
- vty_out(vty, "debug pim nht detail\n");
+ vty_out(vty, "debug " PIM_AF_DBG " nht detail\n");
++writes;
}
++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;
}
struct pim_upstream *up;
struct pim_interface *term_ifp;
int flags = 0;
- struct prefix nht_p;
struct pim_instance *pim = vxlan_sg->pim;
if (vxlan_sg->up) {
* iif
*/
if (!PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)) {
- pim_addr_to_prefix(&nht_p, up->upstream_addr);
- pim_delete_tracked_nexthop(vxlan_sg->pim, &nht_p, up,
- NULL);
+ pim_delete_tracked_nexthop(vxlan_sg->pim,
+ up->upstream_addr, up, NULL);
}
/* We are acting FHR; clear out use_rpt setting if any */
pim_upstream_update_use_rpt(up, false /*update_mroute*/);
struct pim_rpf rpf;
rpf.source_nexthop.interface = ifp;
- pim_addr_to_prefix(&rpf.rpf_addr, us->address);
+ rpf.rpf_addr = us->address;
pim_joinprune_send(&rpf, us->us);
pim_jp_agg_clear_group(us->us);
}
if (old->source_nexthop.interface) {
struct pim_neighbor *nbr;
- nbr = pim_neighbor_find_prefix(old->source_nexthop.interface,
- &old->rpf_addr);
+ nbr = pim_neighbor_find(old->source_nexthop.interface,
+ old->rpf_addr);
if (nbr)
pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr);
void pim_zebra_init(void);
void pim_zebra_zclient_update(struct vty *vty);
-void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index);
void pim_scan_oil(struct pim_instance *pim_matcher);
void pim_forward_start(struct pim_ifchannel *ch);
pimd/pim_assert.c \
pimd/pim_bfd.c \
pimd/pim_br.c \
+ pimd/pim_bsm.c \
pimd/pim_cmd_common.c \
pimd/pim_errors.c \
pimd/pim_hello.c \
pimd_pimd_SOURCES = \
$(pim_common) \
- pimd/pim_bsm.c \
pimd/pim_cmd.c \
pimd/pim_igmp.c \
pimd/pim_igmp_mtrace.c \
$(pim_common) \
pimd/pim6_main.c \
pimd/pim6_mld.c \
- pimd/pim6_stubs.c \
pimd/pim6_cmd.c \
# end
pimd_pimd_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=4
pimd_pimd_LDADD = lib/libfrr.la $(LIBCAP)
-if PIMD
-if DEV_BUILD
-#
-# pim6d is only enabled for --enable-dev-build, and NOT installed currently
-# (change noinst_ to sbin_ below to install it.)
-#
-noinst_PROGRAMS += pimd/pim6d
+if PIM6D
+sbin_PROGRAMS += pimd/pim6d
pimd_pim6d_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=6
pimd_pim6d_LDADD = lib/libfrr.la $(LIBCAP)
endif
-endif
pimd_test_igmpv3_join_LDADD = lib/libfrr.la
pimd_test_igmpv3_join_SOURCES = pimd/test_igmpv3_join.c
switch (family) {
case AF_INET:
- memset(prefix, 0, sizeof(struct prefix_ipv4));
+ memset((struct prefix_ipv4 *)prefix, 0,
+ sizeof(struct prefix_ipv4));
break;
case AF_INET6:
- memset(prefix, 0, sizeof(struct prefix_ipv6));
+ memset((struct prefix_ipv6 *)prefix, 0,
+ sizeof(struct prefix_ipv6));
break;
default:
endscript
}
+/var/log/frr/pim6d.log {
+ notifempty
+ missingok
+ postrotate
+ /bin/kill -USR1 `cat /var/run/frr/pim6d.pid 2> /dev/null` 2> /dev/null || true
+ endscript
+}
+
/var/log/frr/sharpd.log {
notifempty
missingok
%{!?with_pam: %global with_pam 0 }
%{!?with_pbrd: %global with_pbrd 1 }
%{!?with_pimd: %global with_pimd 1 }
+%{!?with_pim6d: %global with_pim6d 0 }
%{!?with_vrrpd: %global with_vrrpd 1 }
%{!?with_rtadv: %global with_rtadv 1 }
%{!?with_watchfrr: %global with_watchfrr 1 }
# if CentOS / RedHat and version < 7, then disable PIMd (too old, won't work)
%if 0%{?rhel} && 0%{?rhel} < 7
%global with_pimd 0
+ %global with_pim6d 0
%endif
# misc internal defines
%define daemon_pimd ""
%endif
+%if %{with_pim6d}
+ %define daemon_pim6d pim6d
+%else
+ %define daemon_pim6d ""
+%endif
+
%if %{with_pbrd}
%define daemon_pbrd pbrd
%else
%define daemon_pathd ""
%endif
-%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_eigrpd} %{daemon_babeld} %{daemon_watchfrr} %{daemon_pbrd} %{daemon_bfdd} %{daemon_vrrpd} %{daemon_pathd}
+%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_pimd} %{daemon_pim6d} %{daemon_nhrpd} %{daemon_eigrpd} %{daemon_babeld} %{daemon_watchfrr} %{daemon_pbrd} %{daemon_bfdd} %{daemon_vrrpd} %{daemon_pathd}
#release sub-revision (the two digits after the CONFDATE)
%{!?release_rev: %global release_rev 01 }
%else
--disable-pimd \
%endif
+%if %{with_pim6d}
+ --enable-pim6d \
+%else
+ --disable-pim6d \
+%endif
%if %{with_pbrd}
--enable-pbrd \
%else
--disable-bgp-vnc \
%endif
--enable-isisd \
-%if "%{initsystem}" == "systemd"
- --enable-systemd \
-%endif
--enable-rpki \
%if %{with_bfdd}
--enable-bfdd \
%if %{with_pimd}
%{_sbindir}/pimd
%endif
+%if %{with_pim6d}
+ %{_sbindir}/pim6d
+%endif
%if %{with_pbrd}
%{_sbindir}/pbrd
%endif
%changelog
-* Tue Jun 7 2022 Donatas Abraitis <donatas@opensourcerouting.org> - %{version}
+
+* Wed Jul 20 2022 Martin Winter <mwinter@opensourcerouting.org> - %{version}
+
+* Wed Jul 13 2022 Jafar Al-Gharaibeh <jafar@atcorp.com> - 8.3
+- General:
+- Add camelcase json keys in addition to pascalcase (Wrong JSON keys will be depracated)
+- Fix corruption when route-map delete/add sequence happens (fast re-add)
+- Reworked gRPC
+- RFC5424 & journald extended syslog target
+- bfdd:
+- Fix broken FSM in active/passive modes
+- bgpd:
+- Notification Message Support for BGP Graceful Restart (rfc8538)
+- BGP Cease Notification Subcode For BFD
+- Send Hold Timer for BGP (own implementation without an additional knob)
+- New `set as-path replace` command for BGP route-map
+- New `match peer` command for BGP route-map
+- New `ead-es-frag evi-limit` command for EVPN
+- New `match evpn route-type` command for EVPN route-map to match Type-1/Type-4
+- JSON outputs for all RPKI show commands
+- Set attributes via route-map for BGP conditional advertisements
+- Pass non-transitive extended communities between RS and RS-clients
+- Send MED attribute when aggregate prefix is created
+- Fix aspath memory leak in aggr_suppress_map_test
+- Fix crash for `show ip bgp vrf all all neighbors 192.168.0.1 ...`
+- Fix crash for `show ip bgp vrf all all`
+- Fix memory leak for BGP Community Alias in CLI
+- Fix memory leak when setting BGP community at egress
+- Fix memory leak when setting BGP large-community at egress
+- Fix SR color nexthop processing in BGP
+- Fix setting local-preference in route-map using +/-
+- Fix crash using Lua and route-map to set attributes via scripts
+- Fix crash when issuing various forms of `bgp no-rib`
+- isisd:
+- JSON output for show summary command
+- Fix crash when MTU mismatch occurs
+- Fix crash with xfrm interface type
+- Fix infinite loop when parsing LSPs
+- Fix router capability TLV parsing issues
+- vtysh:
+- New `show thread timers` command
+- ospfd6:
+- Add LSA statistics to LSA database
+- Add LSA stats to `show area json` output
+- Show time left in hello timer for `show ipv6 ospf6 int`
+- Restart SPF when distance is updated
+- Support keychain for ospf6 authentication
+- ospfd:
+- New `show ip ospf reachable-routers` command
+- Restart SPF when distance is updated
+- Use consistent JSON keys for `show ip ospf neighbor` and detail version
+- pimd:
+- Add additional IGMP stats
+- Add IGMP join sent/failed statistics
+- Add IGMP total groups and total source groups to statistics
+- New `debug igmp trace detail` command
+- New `ip pim passive` command
+- JSON support added for command `show ip igmp sources`
+- Allow the LPM match work properly with prefix lists and normal RPs
+- Do not allow 224.0.0.0/24 range in IGMP join
+- Fix IGMP packet/query check
+- Handle PIM join/prune receive flow for IPv6
+- Handle receive of (*,G) register stop with source address as 0
+- Handle of exclude mode IGMPv3 report messages for SSM-aware group
+- Handle of IGMPv2 report message for SSM-aware group range
+- Send immediate join with possible sg rpt prune bit set
+- Show group-type under `show ip pim rp-info`
+- Show total received messages IGMP stats
+- staticd:
+- Capture zebra advertised ECMP limit
+- Do not register existing nexthop to Zebra
+- Reject route config with too many nexthops
+- Track nexthops per-safi
+- watchfrr:
+- Add some more information to `show watchfrr`
+- Send operational state to systemd
+- zebra:
+- Add ability to know when FRR is not ASIC offloaded
+- Add command for setting protodown bit
+- Add dplane type for netconf data
+- Add ECMP supported to `show zebra`
+- Add EVPN status to `show zebra`
+- Add if v4/v6 forwarding is turned on/off to `show zebra`
+- Add initial zebra tracepoint support
+- Add kernel nexthop group support to `show zebra`
+- Add knowledge about ra and rfc 5549 to `show zebra`
+- Add mpls status to `show zebra`
+- Add netlink debug dump for netconf messages
+- Add netlink debugs for ip rules
+- Add OS and version to `show zebra`
+- Add support for end.dt4
+- Add to `show zebra` the type of vrf devices being used
+- Allow *BSD to specify a receive buffer size
+- Allow multiple connected routes to be choosen for kernel routes
+- Allow system routes to recurse through themselves
+- Do not send RAs w/o link-local v6 or on bridge-ports
+- Evpn disable remove l2vni from l3vni list
+- Evpn-mh bonds protodown check for set
+- Evpn-mh use protodown update reason api
+- Fix cleanup of meta queues on vrf disable
+- Fix crash in evpn neigh cleanup all
+- Fix missing delete vtep during vni transition
+- Fix missing vrf change of l2vni on vxlan interface
+- Fix rtadv startup when config read in is before interface up
+- Fix use after deletion event in FreeBSD
+- Fix v6 route replace failure turned into success
+- Get zebra graceful restart working when restarting on *BSD
+- Handle FreeBSD routing socket enobufs
+- Handle protodown netlink for vxlan device
+- Include mpls enabled status in interface output
+- Include old reason in evpn-mh bond update
+- Keep the interface flags safe on multiple ioctl calls
+- Let /32 host route with same ip cross vrf
+- Make router advertisement warnings show up once every 6 hours
+- Prevent crash if zebra_route_all is used for a route type
+- Prevent installation of connected multiple times
+- Protodown-up event trigger interface up
+- Register nht nexthops with proper safi
+- Update advertise-svi-ip macips w/ new mac
+- When handling unprocessed messages from kernel print usable string
+- New `show ip nht mrib` command
+- Handle ENOBUFS errors for FreeBSD
* Tue Mar 1 2022 Jafar Al-Gharaibeh <jafar@atcorp.com> - 8.2
- The FRRouting community would like to announce FRR Release 8.2.
ri->enable_interface = 0;
ri->running = 0;
- thread_cancel(&ri->t_wakeup);
+ THREAD_OFF(ri->t_wakeup);
}
void rip_interfaces_clean(struct rip *rip)
}
if (rinfo) {
- RIP_TIMER_OFF(rinfo->t_timeout);
- RIP_TIMER_OFF(rinfo->t_garbage_collect);
+ THREAD_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_garbage_collect);
listnode_delete(list, rinfo);
rip_info_free(rinfo);
}
static void rip_peer_free(struct rip_peer *peer)
{
- RIP_TIMER_OFF(peer->t_timeout);
+ THREAD_OFF(peer->t_timeout);
XFREE(MTYPE_RIP_PEER, peer);
}
peer = rip_peer_lookup(rip, addr);
if (peer) {
- thread_cancel(&peer->t_timeout);
+ THREAD_OFF(peer->t_timeout);
} else {
peer = rip_peer_new();
peer->rip = rip;
rinfo = THREAD_ARG(t);
/* Off timeout timer. */
- RIP_TIMER_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_timeout);
/* Get route_node pointer. */
rp = rinfo->rp;
if (tmp_rinfo == rinfo)
continue;
- RIP_TIMER_OFF(tmp_rinfo->t_timeout);
- RIP_TIMER_OFF(tmp_rinfo->t_garbage_collect);
+ THREAD_OFF(tmp_rinfo->t_timeout);
+ THREAD_OFF(tmp_rinfo->t_garbage_collect);
list_delete_node(list, node);
rip_info_free(tmp_rinfo);
}
- RIP_TIMER_OFF(rinfo->t_timeout);
- RIP_TIMER_OFF(rinfo->t_garbage_collect);
+ THREAD_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_garbage_collect);
memcpy(rinfo, rinfo_new, sizeof(struct rip_info));
if (rip_route_rte(rinfo)) {
struct route_node *rp = rinfo->rp;
struct list *list = (struct list *)rp->info;
- RIP_TIMER_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_timeout);
if (listcount(list) > 1) {
/* Some other ECMP entries still exist. Just delete this entry.
*/
- RIP_TIMER_OFF(rinfo->t_garbage_collect);
+ THREAD_OFF(rinfo->t_garbage_collect);
listnode_delete(list, rinfo);
if (rip_route_rte(rinfo)
&& CHECK_FLAG(rinfo->flags, RIP_RTF_FIB))
static void rip_timeout_update(struct rip *rip, struct rip_info *rinfo)
{
if (rinfo->metric != RIP_METRIC_INFINITY) {
- RIP_TIMER_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_timeout);
thread_add_timer(master, rip_timeout, rinfo, rip->timeout_time,
&rinfo->t_timeout);
}
assert(newinfo.metric
!= RIP_METRIC_INFINITY);
- RIP_TIMER_OFF(rinfo->t_timeout);
- RIP_TIMER_OFF(rinfo->t_garbage_collect);
+ THREAD_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_garbage_collect);
memcpy(rinfo, &newinfo,
sizeof(struct rip_info));
rip_timeout_update(rip, rinfo);
RIP_TIMER_ON(rinfo->t_garbage_collect,
rip_garbage_collect,
rip->garbage_time);
- RIP_TIMER_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_timeout);
rinfo->flags |= RIP_RTF_CHANGED;
if (IS_RIP_DEBUG_EVENT)
/* Triggered updates may be suppressed if a regular update is due by
the time the triggered update would be sent. */
- RIP_TIMER_OFF(rip->t_triggered_interval);
+ THREAD_OFF(rip->t_triggered_interval);
rip->trigger = 0;
/* Register myself. */
int interval;
/* Cancel interval timer. */
- RIP_TIMER_OFF(rip->t_triggered_interval);
+ THREAD_OFF(rip->t_triggered_interval);
rip->trigger = 0;
/* Logging triggered update. */
rinfo->metric = RIP_METRIC_INFINITY;
RIP_TIMER_ON(rinfo->t_garbage_collect, rip_garbage_collect,
rip->garbage_time);
- RIP_TIMER_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_timeout);
rinfo->flags |= RIP_RTF_CHANGED;
if (IS_RIP_DEBUG_EVENT) {
thread_add_read(master, rip_read, rip, sock, &rip->t_read);
break;
case RIP_UPDATE_EVENT:
- RIP_TIMER_OFF(rip->t_update);
+ THREAD_OFF(rip->t_update);
jitter = rip_update_jitter(rip->update_time);
thread_add_timer(master, rip_update, rip,
sock ? 2 : rip->update_time + jitter,
if (tmp_rinfo == rinfo)
continue;
- RIP_TIMER_OFF(tmp_rinfo->t_timeout);
- RIP_TIMER_OFF(tmp_rinfo->t_garbage_collect);
+ THREAD_OFF(tmp_rinfo->t_timeout);
+ THREAD_OFF(tmp_rinfo->t_garbage_collect);
list_delete_node(list, node);
rip_info_free(tmp_rinfo);
}
rip_zebra_ipv4_delete(rip, rp);
for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
- RIP_TIMER_OFF(rinfo->t_timeout);
- RIP_TIMER_OFF(rinfo->t_garbage_collect);
+ THREAD_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_garbage_collect);
rip_info_free(rinfo);
}
list_delete(&list);
rip_redistribute_disable(rip);
/* Cancel RIP related timers. */
- RIP_TIMER_OFF(rip->t_update);
- RIP_TIMER_OFF(rip->t_triggered_update);
- RIP_TIMER_OFF(rip->t_triggered_interval);
+ THREAD_OFF(rip->t_update);
+ THREAD_OFF(rip->t_triggered_update);
+ THREAD_OFF(rip->t_triggered_interval);
/* Cancel read thread. */
- thread_cancel(&rip->t_read);
+ THREAD_OFF(rip->t_read);
/* Close RIP socket. */
close(rip->sock);
/* Macro for timer turn on. */
#define RIP_TIMER_ON(T,F,V) thread_add_timer (master, (F), rinfo, (V), &(T))
-/* Macro for timer turn off. */
-#define RIP_TIMER_OFF(X) thread_cancel(&(X))
-
#define RIP_OFFSET_LIST_IN 0
#define RIP_OFFSET_LIST_OUT 1
#define RIP_OFFSET_LIST_MAX 2
ri->enable_interface = 0;
ri->running = 0;
- thread_cancel(&ri->t_wakeup);
+ THREAD_OFF(ri->t_wakeup);
}
}
}
if (rinfo) {
- RIPNG_TIMER_OFF(rinfo->t_timeout);
- RIPNG_TIMER_OFF(rinfo->t_garbage_collect);
+ THREAD_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_garbage_collect);
listnode_delete(list, rinfo);
ripng_info_free(rinfo);
}
static void ripng_peer_free(struct ripng_peer *peer)
{
- RIPNG_TIMER_OFF(peer->t_timeout);
+ THREAD_OFF(peer->t_timeout);
XFREE(MTYPE_RIPNG_PEER, peer);
}
peer = ripng_peer_lookup(ripng, addr);
if (peer) {
- thread_cancel(&peer->t_timeout);
+ THREAD_OFF(peer->t_timeout);
} else {
peer = ripng_peer_new();
peer->ripng = ripng;
rinfo = THREAD_ARG(t);
/* Off timeout timer. */
- RIPNG_TIMER_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_timeout);
/* Get route_node pointer. */
rp = rinfo->rp;
/* Re-use the first entry, and delete the others. */
for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo))
if (tmp_rinfo != rinfo) {
- RIPNG_TIMER_OFF(tmp_rinfo->t_timeout);
- RIPNG_TIMER_OFF(tmp_rinfo->t_garbage_collect);
+ THREAD_OFF(tmp_rinfo->t_timeout);
+ THREAD_OFF(tmp_rinfo->t_garbage_collect);
list_delete_node(list, node);
ripng_info_free(tmp_rinfo);
}
- RIPNG_TIMER_OFF(rinfo->t_timeout);
- RIPNG_TIMER_OFF(rinfo->t_garbage_collect);
+ THREAD_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_garbage_collect);
memcpy(rinfo, rinfo_new, sizeof(struct ripng_info));
if (ripng_route_rte(rinfo)) {
struct agg_node *rp = rinfo->rp;
struct list *list = (struct list *)rp->info;
- RIPNG_TIMER_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_timeout);
if (rinfo->metric != RIPNG_METRIC_INFINITY)
ripng_aggregate_decrement(rp, rinfo);
if (listcount(list) > 1) {
/* Some other ECMP entries still exist. Just delete this entry.
*/
- RIPNG_TIMER_OFF(rinfo->t_garbage_collect);
+ THREAD_OFF(rinfo->t_garbage_collect);
listnode_delete(list, rinfo);
if (ripng_route_rte(rinfo)
&& CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB))
static void ripng_timeout_update(struct ripng *ripng, struct ripng_info *rinfo)
{
if (rinfo->metric != RIPNG_METRIC_INFINITY) {
- RIPNG_TIMER_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_timeout);
thread_add_timer(master, ripng_timeout, rinfo,
ripng->timeout_time, &rinfo->t_timeout);
}
RIPNG_TIMER_ON(rinfo->t_garbage_collect,
ripng_garbage_collect,
ripng->garbage_time);
- RIPNG_TIMER_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_timeout);
/* Aggregate count decrement. */
ripng_aggregate_decrement(rp, rinfo);
RIPNG_TIMER_ON(rinfo->t_garbage_collect,
ripng_garbage_collect,
ripng->garbage_time);
- RIPNG_TIMER_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_timeout);
/* Aggregate count decrement. */
ripng_aggregate_decrement(rp, rinfo);
/* Triggered updates may be suppressed if a regular update is due by
the time the triggered update would be sent. */
- thread_cancel(&ripng->t_triggered_interval);
+ THREAD_OFF(ripng->t_triggered_interval);
ripng->trigger = 0;
/* Reset flush event. */
int interval;
/* Cancel interval timer. */
- thread_cancel(&ripng->t_triggered_interval);
+ THREAD_OFF(ripng->t_triggered_interval);
ripng->trigger = 0;
/* Logging triggered update. */
&ripng->t_read);
break;
case RIPNG_UPDATE_EVENT:
- thread_cancel(&ripng->t_update);
+ THREAD_OFF(ripng->t_update);
/* Update timer jitter. */
jitter = ripng_update_jitter(ripng->update_time);
/* Drop all other entries, except the first one. */
for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo))
if (tmp_rinfo != rinfo) {
- RIPNG_TIMER_OFF(tmp_rinfo->t_timeout);
- RIPNG_TIMER_OFF(
+ THREAD_OFF(tmp_rinfo->t_timeout);
+ THREAD_OFF(
tmp_rinfo->t_garbage_collect);
list_delete_node(list, node);
ripng_info_free(tmp_rinfo);
ripng_zebra_ipv6_delete(ripng, rp);
for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
- RIPNG_TIMER_OFF(rinfo->t_timeout);
- RIPNG_TIMER_OFF(rinfo->t_garbage_collect);
+ THREAD_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_garbage_collect);
ripng_info_free(rinfo);
}
list_delete(&list);
ripng_redistribute_disable(ripng);
/* Cancel the RIPng timers */
- RIPNG_TIMER_OFF(ripng->t_update);
- RIPNG_TIMER_OFF(ripng->t_triggered_update);
- RIPNG_TIMER_OFF(ripng->t_triggered_interval);
+ THREAD_OFF(ripng->t_update);
+ THREAD_OFF(ripng->t_triggered_update);
+ THREAD_OFF(ripng->t_triggered_interval);
/* Cancel the read thread */
- thread_cancel(&ripng->t_read);
+ THREAD_OFF(ripng->t_read);
/* Close the RIPng socket */
if (ripng->sock >= 0) {
/* RIPng timer on/off macro. */
#define RIPNG_TIMER_ON(T,F,V) thread_add_timer (master, (F), rinfo, (V), &(T))
-#define RIPNG_TIMER_OFF(T) thread_cancel(&(T))
-
#define RIPNG_OFFSET_LIST_IN 0
#define RIPNG_OFFSET_LIST_OUT 1
#define RIPNG_OFFSET_LIST_MAX 2
name: frr
-version: @VERSION@
+version: '@VERSION@'
summary: FRRouting BGP/OSPFv2/OSPFv3/ISIS/RIP/RIPng/PIM/LDP/EIGRP/BFD routing daemon
description: BGP/OSPFv2/OSPFv3/ISIS/RIP/RIPng/PIM/LDP/EIGRP/BFD routing daemon
FRRouting (FRR) is free software which manages TCP/IP based routing
struct static_nexthop *nh;
uint32_t pos;
uint8_t index;
+ uint old_num_labels;
switch (args->event) {
case NB_EV_VALIDATE:
return NB_ERR;
}
index = pos - 1;
+ old_num_labels = nh->snh_label.num_labels;
nh->snh_label.label[index] = 0;
nh->snh_label.num_labels--;
+
+ if (old_num_labels != nh->snh_label.num_labels)
+ nh->state = STATIC_START;
break;
}
struct static_nexthop *nh;
uint32_t pos;
uint8_t index;
+ mpls_label_t old_label;
nh = nb_running_get_entry(args->dnode, NULL, true);
pos = yang_get_list_pos(lyd_parent(args->dnode));
}
/* Mapping to array = list-index -1 */
index = pos - 1;
+
+ old_label = nh->snh_label.label[index];
nh->snh_label.label[index] = yang_dnode_get_uint32(args->dnode, NULL);
+ if (old_label != nh->snh_label.label[index])
+ nh->state = STATIC_START;
+
return NB_OK;
}
{
struct static_nexthop *nh;
enum static_nh_type nh_type;
+ bool old_onlink;
switch (args->event) {
case NB_EV_VALIDATE:
break;
case NB_EV_APPLY:
nh = nb_running_get_entry(args->dnode, NULL, true);
+ old_onlink = nh->onlink;
nh->onlink = yang_dnode_get_bool(args->dnode, NULL);
+
+ if (old_onlink != nh->onlink)
+ nh->state = STATIC_START;
break;
}
static int static_nexthop_color_modify(struct nb_cb_modify_args *args)
{
struct static_nexthop *nh;
+ uint32_t old_color;
nh = nb_running_get_entry(args->dnode, NULL, true);
+ old_color = nh->color;
nh->color = yang_dnode_get_uint32(args->dnode, NULL);
+ if (old_color != nh->color)
+ nh->state = STATIC_START;
+
return NB_OK;
}
static int static_nexthop_color_destroy(struct nb_cb_destroy_args *args)
{
struct static_nexthop *nh;
+ uint32_t old_color;
nh = nb_running_unset_entry(args->dnode);
+ old_color = nh->color;
nh->color = 0;
+ if (old_color != nh->color)
+ nh->state = STATIC_START;
+
return NB_OK;
}
for key, val in testcase.items():
if isinstance(val, str) or isinstance(val, float) or isinstance(val, int):
s += "{}: {}\n".format(key, val)
+ elif isinstance(val, list):
+ for k2, v2 in enumerate(val):
+ s += "{}: {}\n".format(k2, v2)
else:
for k2, v2 in val.items():
s += "{}: {}\n".format(k2, v2)
ip ospf area 0
ip ospf hello-interval 2
ip ospf dead-interval 10
+ ip ospf bfd
ip ospf bfd profile slowtx
!
router ospf
!
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
!
!
[
{
"remote-receive-interval": 1000,
- "remote-transmit-interval": 500,
+ "remote-transmit-interval": 1000,
"peer": "192.168.0.2",
"status": "up"
}
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
!
!
"status": "up"
},
{
- "remote-echo-receive-interval": 100,
+ "remote-echo-receive-interval": 1000,
"peer": "192.168.1.1",
"status": "up"
},
!
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
!
--- /dev/null
+[
+ {
+ "multihop":false,
+ "peer":"192.168.0.2",
+ "vrf":"vrf1",
+ "passive-mode":false,
+ "status":"up",
+ "diagnostic":"ok",
+ "remote-diagnostic":"ok",
+ "receive-interval":1000,
+ "transmit-interval":1000,
+ "echo-receive-interval":50,
+ "echo-transmit-interval":0,
+ "detect-multiplier":3,
+ "remote-receive-interval":1000,
+ "remote-transmit-interval":1000,
+ "remote-echo-receive-interval":50,
+ "remote-detect-multiplier":3
+ },
+ {
+ "multihop":true,
+ "peer":"192.0.2.2",
+ "local":"192.0.2.1",
+ "vrf":"vrf2",
+ "passive-mode":false,
+ "minimum-ttl":254,
+ "status":"up",
+ "diagnostic":"ok",
+ "remote-diagnostic":"ok",
+ "receive-interval":1000,
+ "transmit-interval":1000,
+ "echo-receive-interval":50,
+ "echo-transmit-interval":0,
+ "detect-multiplier":3,
+ "remote-receive-interval":1000,
+ "remote-transmit-interval":1000,
+ "remote-echo-receive-interval":50,
+ "remote-detect-multiplier":3
+ },
+ {
+ "multihop":false,
+ "peer":"192.168.0.2",
+ "vrf":"vrf2",
+ "passive-mode":false,
+ "status":"up",
+ "diagnostic":"ok",
+ "remote-diagnostic":"ok",
+ "receive-interval":1000,
+ "transmit-interval":1000,
+ "echo-receive-interval":50,
+ "echo-transmit-interval":0,
+ "detect-multiplier":3,
+ "remote-receive-interval":1000,
+ "remote-transmit-interval":1000,
+ "remote-echo-receive-interval":50,
+ "remote-detect-multiplier":3
+ },
+ {
+ "multihop":false,
+ "peer":"192.168.0.2",
+ "vrf":"default",
+ "passive-mode":false,
+ "status":"up",
+ "diagnostic":"ok",
+ "remote-diagnostic":"ok",
+ "receive-interval":1000,
+ "transmit-interval":1000,
+ "echo-receive-interval":50,
+ "echo-transmit-interval":0,
+ "detect-multiplier":3,
+ "remote-receive-interval":1000,
+ "remote-transmit-interval":1000,
+ "remote-echo-receive-interval":50,
+ "remote-detect-multiplier":3
+ },
+ {
+ "multihop":true,
+ "peer":"192.0.2.2",
+ "local":"192.0.2.1",
+ "vrf":"vrf1",
+ "passive-mode":false,
+ "minimum-ttl":254,
+ "status":"up",
+ "diagnostic":"ok",
+ "remote-diagnostic":"ok",
+ "receive-interval":1000,
+ "transmit-interval":1000,
+ "echo-receive-interval":50,
+ "echo-transmit-interval":0,
+ "detect-multiplier":3,
+ "remote-receive-interval":1000,
+ "remote-transmit-interval":1000,
+ "remote-echo-receive-interval":50,
+ "remote-detect-multiplier":3
+ }
+]
--- /dev/null
+!
+! debug bfd network
+! debug bfd peer
+! debug bfd zebra
+!
+bfd
+ peer 192.168.0.2 vrf vrf1
+ transmit-interval 1000
+ receive-interval 1000
+ !
+ peer 192.168.0.2 vrf vrf2
+ transmit-interval 1000
+ receive-interval 1000
+ !
+ peer 192.168.0.2
+ transmit-interval 1000
+ receive-interval 1000
+ !
+ peer 192.0.2.2 multihop local-address 192.0.2.1 vrf vrf1
+ transmit-interval 1000
+ receive-interval 1000
+ !
+ peer 192.0.2.2 multihop local-address 192.0.2.1 vrf vrf2
+ transmit-interval 1000
+ receive-interval 1000
+ !
\ No newline at end of file
--- /dev/null
+vrf vrf1
+ ip route 192.0.2.2/32 192.168.0.2
+!
+vrf vrf2
+ ip route 192.0.2.2/32 192.168.0.2
+!
+interface r1-eth0 vrf vrf3
+ ip address 192.168.0.1/24
+!
+interface r1-eth0.100 vrf vrf1
+ ip address 192.168.0.1/24
+!
+interface r1-eth0.200 vrf vrf2
+ ip address 192.168.0.1/24
+!
+interface r1-eth0.300
+ ip address 192.168.0.1/24
+!
+interface r1-loop1 vrf vrf1
+ ip address 192.0.2.1/32
+!
+interface r1-loop2 vrf vrf2
+ ip address 192.0.2.1/32
+!
\ No newline at end of file
--- /dev/null
+!
+! debug bfd network
+! debug bfd peer
+! debug bfd zebra
+!
+bfd
+ peer 192.168.0.1 vrf vrf1
+ transmit-interval 1000
+ receive-interval 1000
+ !
+ peer 192.168.0.1 vrf vrf2
+ transmit-interval 1000
+ receive-interval 1000
+ !
+ peer 192.168.0.1
+ transmit-interval 1000
+ receive-interval 1000
+ !
+ peer 192.0.2.1 multihop local-address 192.0.2.2 vrf vrf1
+ transmit-interval 1000
+ receive-interval 1000
+ !
+ peer 192.0.2.1 multihop local-address 192.0.2.2 vrf vrf2
+ transmit-interval 1000
+ receive-interval 1000
+ !
\ No newline at end of file
--- /dev/null
+vrf vrf1
+ ip route 192.0.2.1/32 192.168.0.1
+!
+vrf vrf2
+ ip route 192.0.2.1/32 192.168.0.1
+!
+interface r2-eth0 vrf vrf3
+ ip address 192.168.0.2/24
+!
+interface r2-eth0.100 vrf vrf1
+ ip address 192.168.0.2/24
+!
+interface r2-eth0.200 vrf vrf2
+ ip address 192.168.0.2/24
+!
+interface r2-eth0.300
+ ip address 192.168.0.2/24
+!
+interface r2-loop1 vrf vrf1
+ ip address 192.0.2.2/32
+!
+interface r2-loop2 vrf vrf2
+ ip address 192.0.2.2/32
+!
\ No newline at end of file
--- /dev/null
+#!/usr/bin/env python
+
+#
+# test_bfd_vrflite_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2018 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+# Copyright (c) 2022 by 6WIND
+#
+# 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.
+#
+
+"""
+test_bfd_vrflite_topo1.py: Test the FRR BFD daemon.
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+
+pytestmark = [pytest.mark.bfdd, pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ # Create 2 routers
+ 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"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r1"])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ logger.info("Testing with Linux VRF support and udp_l3mdev=0")
+ if os.system("echo 0 > /proc/sys/net/ipv4/udp_l3mdev_accept") != 0:
+ return pytest.skip(
+ "Skipping BFD vrflite Topo1 Test. Linux VRF not available on System"
+ )
+
+ for rname, router in router_list.items():
+ router.net.add_l3vrf("vrf1", 10)
+ router.net.add_l3vrf("vrf2", 20)
+ router.net.add_l3vrf("vrf3", 30)
+ router.net.add_vlan(rname + "-eth0.100", rname + "-eth0", 100)
+ router.net.add_vlan(rname + "-eth0.200", rname + "-eth0", 200)
+ router.net.add_vlan(rname + "-eth0.300", rname + "-eth0", 300)
+ router.net.attach_iface_to_l3vrf(rname + "-eth0.100", "vrf1")
+ router.net.attach_iface_to_l3vrf(rname + "-eth0.200", "vrf2")
+ router.net.add_loop(rname + "-loop1")
+ router.net.add_loop(rname + "-loop2")
+ router.net.attach_iface_to_l3vrf(rname + "-loop1", "vrf1")
+ router.net.attach_iface_to_l3vrf(rname + "-loop2", "vrf2")
+ router.net.attach_iface_to_l3vrf(rname + "-eth0", "vrf3")
+
+ for rname, router in router_list.items():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BFD, os.path.join(CWD, "{}/bfdd.conf".format(rname))
+ )
+
+ # Initialize all routers.
+ tgen.start_router()
+
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ # Move interfaces out of vrf namespace and delete the namespace
+ router_list = tgen.routers()
+ for rname, router in router_list.items():
+ router.net.del_iface(rname + "-eth0.100")
+ router.net.del_iface(rname + "-eth0.200")
+ router.net.del_iface(rname + "-eth0.300")
+ router.net.del_iface(rname + "-loop1")
+ router.net.del_iface(rname + "-loop2")
+
+ tgen.stop_topology()
+
+
+def test_bfd_connection():
+ "Assert that the BFD peers can find themselves."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ logger.info("waiting for bfd peers to go up")
+ router = tgen.gears['r1']
+ json_file = "{}/{}/bfd_peers_status.json".format(CWD, 'r1')
+ expected = json.loads(open(json_file).read())
+
+ test_func = partial(
+ topotest.router_json_cmp, router, "show bfd peers json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=16, wait=1)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
--- /dev/null
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+ address-family ipv4
+ redistribute connected
+ exit-address-family
+!
--- /dev/null
+!
+interface lo
+ ip address 172.16.255.1/32
+!
+interface r1-eth0
+ ip address 192.168.1.2/30
+!
+ip forwarding
+!
--- /dev/null
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+ neighbor 192.168.1.2 timers 1 3
+ neighbor 192.168.1.2 timers connect 1
+ neighbor 192.168.2.2 remote-as external
+ neighbor 192.168.2.2 timers 1 3
+ neighbor 192.168.2.2 timers connect 1
+!
--- /dev/null
+!
+interface r2-eth0
+ ip address 192.168.1.1/30
+!
+interface r2-eth1
+ ip address 192.168.2.1/30
+!
+ip forwarding
+!
--- /dev/null
+!
+router bgp 65003
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.1 remote-as external
+ neighbor 192.168.2.1 timers 1 3
+ neighbor 192.168.2.1 timers connect 1
+ neighbor 192.168.3.1 remote-as external
+ neighbor 192.168.3.1 timers 1 3
+ neighbor 192.168.3.1 timers connect 1
+ address-family ipv4 unicast
+ neighbor 192.168.3.1 as-override
+ exit-address-family
+!
--- /dev/null
+!
+interface r3-eth0
+ ip address 192.168.2.2/30
+!
+interface r3-eth1
+ ip address 192.168.3.2/30
+!
+ip forwarding
+!
--- /dev/null
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.3.2 remote-as external
+ neighbor 192.168.3.2 timers 1 3
+ neighbor 192.168.3.2 timers connect 1
+!
--- /dev/null
+!
+interface r4-eth0
+ ip address 192.168.3.1/30
+!
+ip forwarding
+!
--- /dev/null
+#!/usr/bin/env python
+
+#
+# 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.
+#
+
+"""
+"""
+
+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, 7):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r3"])
+ switch.add_link(tgen.gears["r4"])
+
+
+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_as_override():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r3 = tgen.gears["r3"]
+ r4 = tgen.gears["r4"]
+
+ def _bgp_converge():
+ output = json.loads(r3.vtysh_cmd("show ip bgp neighbor 192.168.2.1 json"))
+ expected = {
+ "192.168.2.1": {
+ "bgpState": "Established",
+ "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 2}},
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_as_override():
+ output = json.loads(r4.vtysh_cmd("show bgp ipv4 unicast json"))
+ expected = {
+ "routes": {
+ "172.16.255.1/32": [{"valid": True, "path": "65003 65002 65003"}]
+ }
+ }
+ 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 R4"
+
+ step("Check if BGP as-override from R3 works")
+ test_func = functools.partial(_bgp_as_override)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to see overriden ASN (65001) from R3"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
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)
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 - '
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(
"""
)
- 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 - '
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(
"""
)
- 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 - '
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(
"""
)
- 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 - '
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(
"""
)
- 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 - '
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(
"""
)
- 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" - '
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(
"""
)
- 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" - '
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(
"""
)
- 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 - "
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(
"""
)
- 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 - "
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(
"""
)
- 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 - "
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(
"""
)
- 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 - "
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(
"""
)
- 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 - "
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(
"""
)
- 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 - "
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(
"""
)
- 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 - "
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(
)
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)
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(
"""
)
- 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 - "
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(
"""
)
- 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 - "
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(
"""
)
- 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 - "
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(
"""
)
- 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 - "
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(
"""
)
- 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 - "
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(
"""
)
- 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 - "
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(
)
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)
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(
)
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)
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(
"""
)
- 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 - "
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(
"""
)
- 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 - "
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(
)
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)
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(
)
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)
--- /dev/null
+{
+ "address_types": [
+ "ipv4",
+ "ipv6"
+ ],
+ "ipv4base": "192.168.0.0",
+ "ipv4mask": 3024,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "192.168.0.0",
+ "v4mask": 24,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r0": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r0": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": [
+ {
+ "local_as": "1000",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r0": {
+ "dest_link": {
+ "r1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r0": {
+ "dest_link": {
+ "r1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "vrf": "RED"
+ }
+ },
+ "vrfs": [
+ {
+ "name": "RED",
+ "id": "1"
+ }
+ ],
+ "bgp": [
+ {
+ "local_as": "2000",
+ "vrf": "RED",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "1000",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback",
+ "vrf": "RED"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "vrf": "RED"
+ },
+ "r4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "vrfs": [
+ {
+ "name": "RED",
+ "id": "1"
+ }
+ ],
+ "bgp": [
+ {
+ "local_as": "3000",
+ "vrf": "RED",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r4": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": [
+ {
+ "local_as": "500",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+{
+ "address_types": ["ipv4", "ipv6"],
+ "ipv4base": "192.168.0.0",
+ "ipv4mask": 3024,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "192.168.0.0",
+ "v4mask": 24,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:db8:f::", "v6mask": 128},
+ "routers": {
+ "r0": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {"neighbor": {"r1": {"dest_link": {"r0": {}}}}}
+ },
+ "ipv6": {
+ "unicast": {"neighbor": {"r1": {"dest_link": {"r0": {}}}}}
+ }
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r0": {"ipv4": "auto", "ipv6": "auto"},
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r2-link2": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r0": {"dest_link": {"r1": {}}},
+ "r2": {"dest_link": {"r1-link1": {}, "r1-link2": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r0": {"dest_link": {"r1": {}}},
+ "r2": {"dest_link": {"r1-link1": {}, "r1-link2": {}}}
+ }
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r1-link2": {"ipv4": "auto", "ipv6": "auto"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r2-link1": {}, "r2-link2": {}}},
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r2-link1": {}, "r2-link2": {}}},
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r2": {"ipv4": "auto", "ipv6": "auto"},
+ "r4": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {}}},
+ "r4": {"dest_link": {"r3": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {}}},
+ "r4": {"dest_link": {"r3": {}}}
+ }
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "500",
+ "address_family": {
+ "ipv4": {
+ "unicast": {"neighbor": {"r3": {"dest_link": {"r4": {}}}}}
+ },
+ "ipv6": {
+ "unicast": {"neighbor": {"r3": {"dest_link": {"r4": {}}}}}
+ }
+ }
+ }
+ }
+ }
+}
--- /dev/null
+#!/usr/bin/env python
+#
+# Copyright (c) 2022 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. ("NetDEF")
+# in this file.
+#
+# 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.
+# Shreenidhi A R <rshreenidhi@vmware.com>
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+"""
+Following tests are covered.
+1. Verify default-originate route with default static and network command
+2. Verify default-originate route with aggregate summary command
+"""
+import os
+import sys
+import time
+import pytest
+import datetime
+from copy import deepcopy
+from lib.topolog import logger
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topojson import build_config_from_json
+from lib.topolog import logger
+
+from lib.bgp import (
+ verify_bgp_convergence,
+ create_router_bgp,
+ verify_bgp_rib,
+ get_dut_as_number,
+ verify_rib_default_route,
+ verify_fib_default_route,
+)
+from lib.common_config import (
+ verify_fib_routes,
+ step,
+ run_frr_cmd,
+ get_frr_ipv6_linklocal,
+ start_topology,
+ apply_raw_config,
+ write_test_header,
+ check_address_types,
+ write_test_footer,
+ reset_config_on_routers,
+ create_static_routes,
+ check_router_status,
+)
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+
+# Global variables
+topo = None
+NETWORK1_1 = {"ipv4": "198.51.1.1/32", "ipv6": "2001:DB8::1:1/128"}
+NETWORK1_2 = {"ipv4": "198.51.1.2/32", "ipv6": "2001:DB8::1:2/128"}
+NETWORK1_3 = {"ipv4": "198.51.1.3/32", "ipv6": "2001:DB8::1:3/128"}
+NETWORK1_4 = {"ipv4": "198.51.1.4/32", "ipv6": "2001:DB8::1:4/128"}
+NETWORK1_5 = {"ipv4": "198.51.1.5/32", "ipv6": "2001:DB8::1:5/128"}
+
+ipv4_uptime_dict = {
+ "r2": {
+ "static_routes": [
+ {"network": "0.0.0.0/0"},
+ ]
+ }
+}
+
+ipv6_uptime_dict = {
+ "r2": {
+ "static_routes": [
+ {"network": "::/0"},
+ ]
+ }
+}
+
+DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ json_file = "{}/bgp_default_originate_2links.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ global ADDR_TYPES
+ global BGP_CONVERGENCE
+ global DEFAULT_ROUTES
+ global DEFAULT_ROUTE_NXT_HOP_LINK1, DEFAULT_ROUTE_NXT_HOP_LINK2
+ ADDR_TYPES = check_address_types()
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+
+ interface = topo["routers"]["r1"]["links"]["r2-link1"]["interface"]
+ ipv6_link_local = get_frr_ipv6_linklocal(tgen, "r1", intf=interface)
+ ipv4_nxt_hop = topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0]
+ ipv6_nxt_hop = topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0]
+ DEFAULT_ROUTE_NXT_HOP_LINK1 = {"ipv4": ipv4_nxt_hop, "ipv6": ipv6_link_local}
+
+ interface = topo["routers"]["r1"]["links"]["r2-link2"]["interface"]
+ ipv6_link_local = get_frr_ipv6_linklocal(tgen, "r1", intf=interface)
+ ipv4_nxt_hop = topo["routers"]["r1"]["links"]["r2-link2"]["ipv4"].split("/")[0]
+ ipv6_nxt_hop = topo["routers"]["r1"]["links"]["r2-link2"]["ipv6"].split("/")[0]
+ DEFAULT_ROUTE_NXT_HOP_LINK2 = {"ipv4": ipv4_nxt_hop, "ipv6": ipv6_link_local}
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Local API's
+#
+#####################################################
+
+
+def get_rib_route_uptime(tgen, addr_type, dut, input_dict):
+ """
+ Verify route uptime in RIB using "show ip route"
+
+ Parameters
+ ----------
+ * `tgen` : topogen object
+ * `addr_type` : ip type, ipv4/ipv6
+ * `dut`: Device Under Test, for which user wants to test the data
+ * `input_dict` : input dict, has details of static routes
+ * `route_uptime`: uptime of the routes
+
+ Usage
+ -----
+ # Creating static routes for r1
+ input_dict_r1 = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": "147.10.13.4/32"
+ },
+ {
+ "network": "147.10.12.0/24"
+ },
+ {
+ "network": "147.10.13.4/32"
+ },
+ {
+ "network": "147.10.13.4/32"
+ },
+ {
+ "network": "147.10.13.4/32"
+ }
+ ]
+ }
+ }
+
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.info("Entering lib API: get_rib_route_uptime()")
+ route_time = []
+ out_route_dict = {}
+ router_list = tgen.routers()
+ for routerInput in input_dict.keys():
+ for router, rnode in router_list.items():
+ if router != dut:
+ continue
+
+ logger.info("Checking router %s RIB:", router)
+
+ # Verifying RIB routes
+ if addr_type == "ipv4":
+ command = "show ip route"
+ else:
+ command = "show ipv6 route"
+
+ if "static_routes" in input_dict[routerInput]:
+ static_routes = input_dict[routerInput]["static_routes"]
+
+ for static_route in static_routes:
+ if "vrf" in static_route and static_route["vrf"] is not None:
+
+ logger.info(
+ "[DUT: {}]: Verifying routes for VRF:"
+ " {}".format(router, static_route["vrf"])
+ )
+ cmd = "{} vrf {}".format(command, static_route["vrf"])
+
+ else:
+ cmd = "{}".format(command)
+
+ cmd = "{} json".format(cmd)
+
+ rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ if bool(rib_routes_json) is False:
+ errormsg = "No route found in rib of router {}..".format(router)
+ return errormsg
+ network = static_route["network"]
+ route_time.append(rib_routes_json[network][0]["uptime"])
+
+ logger.info("Exiting lib API: get_rib_route_uptime()")
+ return route_time
+
+
+def verify_the_uptime(time_stamp_before, time_stamp_after, incremented=None):
+ """
+ time_stamp_before : string the time stamp captured
+ time_stamp_after : string the time stamp captured
+ """
+ uptime_before = datetime.datetime.strptime(time_stamp_before[0], "%H:%M:%S")
+ uptime_after = datetime.datetime.strptime(time_stamp_after[0], "%H:%M:%S")
+
+ if incremented == True:
+ if uptime_before < uptime_after:
+ logger.info(
+ " The Uptime [{}] is incremented than [{}].......PASSED ".format(
+ time_stamp_before, time_stamp_after
+ )
+ )
+ return True
+ else:
+ logger.error(
+ " The Uptime [{}] is expected to be incremented than [{}].......FAILED ".format(
+ time_stamp_before, time_stamp_after
+ )
+ )
+ return False
+ else:
+ logger.info(
+ " The Uptime [{}] is not incremented than [{}] ".format(
+ time_stamp_before, time_stamp_after
+ )
+ )
+ return True
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def test_verify_bgp_default_originate_with_default_static_route_p1(request):
+ """
+ Summary: "Verify default-originate route with default static and network command "
+
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE, DEFAULT_ROUTE_NXT_HOP_LINK1, DEFAULT_ROUTE_NXT_HOP_LINK2, DEFAULT_ROUTES
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Configure 2 link between R1 and R2")
+ step("Configure IPV4 and IPV6 EBGP between R1 and R2 both the links")
+ step("Configure default-originate on R1 IPv4 and IPv6 BGP session link-1 only ")
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "default_originate": {"r2": {"dest-link": "r1-link1"}}
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "default_originate": {"r2": {"dest-link": "r1-link1"}}
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify IPv4/IPv6 default originate routes present on R2 nexthop as link-1")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "next_hop": DEFAULT_ROUTE_NXT_HOP_LINK1[addr_type],
+ }
+ ]
+ }
+ }
+
+ result = verify_fib_routes(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_LINK1[addr_type],
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_LINK1[addr_type],
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure network command on R1 (0.0.0.0/0 and 0::0/0) for IPv4 and IPv6 address family "
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ for addr_type in ADDR_TYPES:
+ input_advertise = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {"network": [DEFAULT_ROUTES[addr_type]]}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_advertise)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("No change on IPv4/IPv6 default-originate route advertised from link1")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("verify 0.0.0.0/0 and 0::0/0 route also get advertised from link-2 ")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Before removing default originate from R1 link -1 IPv4 and IPv6 address family taking the uptime snapshot"
+ )
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("Remove default originate from R1 link -1 IPv4 and IPv6 address family ")
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "default_originate": {
+ "r2": {"dest-link": "r1-link1", "delete": True}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "default_originate": {
+ "r2": {"dest-link": "r1-link1", "delete": True}
+ }
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Routes must be learned from network command")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("After removing the default originate on R1 taking the uptime snapshot")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "After removing the default-originate uptime should get reset for link-1 learn route"
+ )
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Taking uptime snapshot before configuring default - originate")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "Configure default-originate on R1 link-1 again for IPv4 and IPv6 address family"
+ )
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "default_originate": {
+ "r2": {
+ "dest-link": "r1-link1",
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "default_originate": {
+ "r2": {
+ "dest-link": "r1-link1",
+ }
+ }
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify No change on R2 routing and BGP table for both the links ")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Taking snapshot after configuring default - originate")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "After configuring the default-originate uptime should not get reset for link-1 learn route"
+ )
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=True)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=True)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Taking uptime snapshot before removing network 0.0.0.0 ")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("Remove network command from R1 IPv4/IPv6 address family ")
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ for addr_type in ADDR_TYPES:
+ input_advertise = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_advertise)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify 0.0.0.0/0 and 0::0/0 route get removed from link-2 and default-originate IPv4/IPv6 route learn on link-1"
+ )
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Route from link2 is not expected \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed\n Route from link2 is not expected \n Error: {}".format(
+ tc_name, result
+ )
+
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "After removing default originate command on R1 verify that the uptime got reset on R2"
+ )
+
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Taking uptime snapshot before configuring static route network")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "Configure static default route for IPv4 and IPv6 (0.0.0.0/0 next-hop Null0 and 0::0/0 next-hop Null0) on R1"
+ )
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": "0.0.0.0/0",
+ "next_hop": NEXT_HOP_IP["ipv4"],
+ },
+ {
+ "network": "0::0/0",
+ "next_hop": NEXT_HOP_IP["ipv6"],
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verifyIPv4 and IPv6 static routes are configure and up on R1 ")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": "0.0.0.0/0",
+ "next_hop": NEXT_HOP_IP["ipv4"],
+ },
+ {
+ "network": "0::0/0",
+ "next_hop": NEXT_HOP_IP["ipv6"],
+ },
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r1", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure redistribute static on IPv4 and IPv6 address family")
+ redistribute_static = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ "ipv6": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, redistribute_static)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify No change on IPv4/IPv6 default-originate route advertised from link1")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("verify 0.0.0.0/0 and 0::0/0 route also get advertised from link-2 ")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed\n Best Path sould be advertised in routes\n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Taking uptime snapshot before removing default originate")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("Remove default-originate from link-1 from IPv4 and IPv6 neighbor ")
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "default_originate": {
+ "r2": {"dest-link": "r1-link1", "delete": True}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "default_originate": {
+ "r2": {"dest-link": "r1-link1", "delete": True}
+ }
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Taking uptime snapshot after removing default originate")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("verify the up time , up time should get reset ")
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify No change on IPv4/IPv6 default-originate route advertised from link1")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Taking uptime snapshot before configuring default originate")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ " Configure default-originate on link-1 again for IPv4 and IPv6 address family"
+ )
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "default_originate": {
+ "r2": {
+ "dest-link": "r1-link1",
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "default_originate": {
+ "r2": {
+ "dest-link": "r1-link1",
+ }
+ }
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify No change on IPv4/IPv6 default-originate route advertised from link1")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Taking uptime snapshot after configuring default originate")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("After configuring the default originate the uptime should not get reset ")
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Taking uptime snapshot before removing redisctribute static ")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("Remove redistribute static from IPv4 and IPv6 address family ")
+ input_dict_1 = {
+ "r1": {
+ "bgp": {
+ "local_as": get_dut_as_number(tgen, dut="r1"),
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [{"redist_type": "static", "delete": True}]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [{"redist_type": "static", "delete": True}]
+ }
+ },
+ },
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify No change on IPv4/IPv6 default-originate route advertised from link1")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Taking uptime snapshot before removing redisctribute static ")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("After removing default originate the route uptime should get reset ")
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=True)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=True)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_default_originate_with_aggregate_summary_p1(request):
+ """
+ Summary: "Verify default-originate route with aggregate summary command"
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ step("After changing the BGP AS Path Verify the BGP Convergence")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Configure default-originate on R1 IPv4 and IPv6 BGP session link-1 only")
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "default_originate": {"r2": {"dest-link": "r1-link1"}}
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "default_originate": {"r2": {"dest-link": "r1-link1"}}
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify IPv4/IPv6 default originate routes present on R2 nexthop as link-1,on R2"
+ )
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Configure 5 static route for IPv4 and IPv6 on R0")
+ for addr_type in ADDR_TYPES:
+ input_advertise = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK1_3[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK1_4[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK1_5[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_advertise)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Before configuring the aggregate route taking uptime snapshot ")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("Configure aggregate summary command for IPv4 and IPv6 address family ")
+ local_as = get_dut_as_number(tgen, dut="r1")
+ raw_config = {
+ "r1": {
+ "raw_config": [
+ "router bgp {}".format(local_as),
+ "address-family ipv4 unicast",
+ "aggregate-address {} summary-only".format("0.0.0.0/0 "),
+ "exit-address-family",
+ "address-family ipv6 unicast",
+ "aggregate-address {} summary-only".format("0::0/0"),
+ "exit-address-family",
+ ]
+ }
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "verify that no change on IPv4/IPv6 default-originate route advertised from link1 0.0.0.0/0 and 0::0/0 route also get advertised from link-2 on R2"
+ )
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("After configuring the aggregate route taking uptime snapshot ")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "After Configuring the aggregate route uptime should get reset for link-1 learn route"
+ )
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Before removing default originate taking uptime snapshot ")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("Remove default originate from R1 link -1 IPv4 and IPv6 address family")
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "default_originate": {
+ "r2": {"dest-link": "r1-link1", "delete": True}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "default_originate": {
+ "r2": {"dest-link": "r1-link1", "delete": True}
+ }
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "verify that no change on IPv4/IPv6 default-originate route advertised from link1 0.0.0.0/0 and 0::0/0 route also get advertised from link-2 on R2"
+ )
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("After removing default origin taking uptime snapshot ")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "After removing the default-originate uptime should get reset for link-1 learn route"
+ )
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Before Configuring default origin taking uptime snapshot ")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "Configure default-originate on R1 link-1 again for IPv4 and IPv6 address family"
+ )
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "default_originate": {
+ "r2": {
+ "dest-link": "r1-link1",
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "default_originate": {
+ "r2": {
+ "dest-link": "r1-link1",
+ }
+ }
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("After Configuring default originate taking uptime snapshot")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "After Configuring the default-originate uptime should get reset for link-1 learn route"
+ )
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Before removing aggregate -summary command taking the uptime snapshot ")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("remove aggregate summary command for IPv4 and IPv6 address family ")
+ local_as = get_dut_as_number(tgen, dut="r1")
+ raw_config = {
+ "r1": {
+ "raw_config": [
+ "router bgp {}".format(local_as),
+ "address-family ipv4 unicast",
+ "no aggregate-address {} summary-only".format("0.0.0.0/0"),
+ "exit-address-family",
+ "address-family ipv6 unicast",
+ "no aggregate-address {} summary-only".format("0::0/0"),
+ "exit-address-family",
+ ]
+ }
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify Default-originate IPv4/IPv6 route learn on link-1 ")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify 0.0.0.0/0 and 0::0/0 route get removed from link-2 ")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("After removing aggregate -summary command taking the uptime snapshot ")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("After removing aggregate command uptime should get reset ")
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
)
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
)
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
--- /dev/null
+#!/usr/bin/env python
+#
+# Copyright (c) 2022 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. ("NetDEF")
+# in this file.
+#
+# 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.
+# Shreenidhi A R <rshreenidhi@vmware.com>
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+"""
+Following tests are covered.
+10. Verify default-originate route after BGP and FRR process restart
+11. Verify default-originate route after shut/no shut and clear BGP neighbor
+"""
+import os
+import sys
+import time
+import pytest
+from lib.topolog import logger
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topojson import build_config_from_json
+from lib.topolog import logger
+
+from lib.bgp import (
+ verify_bgp_convergence,
+ create_router_bgp,
+ modify_as_number,
+ clear_bgp,
+ verify_bgp_rib,
+ get_dut_as_number,
+ verify_rib_default_route,
+ verify_fib_default_route,
+)
+from lib.common_config import (
+ interface_status,
+ verify_prefix_lists,
+ verify_fib_routes,
+ kill_router_daemons,
+ start_router_daemons,
+ shutdown_bringup_interface,
+ step,
+ required_linux_kernel_version,
+ stop_router,
+ start_router,
+ create_route_maps,
+ create_prefix_lists,
+ get_frr_ipv6_linklocal,
+ start_topology,
+ write_test_header,
+ check_address_types,
+ write_test_footer,
+ reset_config_on_routers,
+ create_static_routes,
+ check_router_status,
+)
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+
+# Global variables
+topo = None
+KEEPALIVETIMER = 1
+HOLDDOWNTIMER = 3
+# Global variables
+NETWORK1_1 = {"ipv4": "198.51.1.1/32", "ipv6": "2001:DB8::1:1/128"}
+NETWORK2_1 = {"ipv4": "198.51.1.2/32", "ipv6": "2001:DB8::1:2/128"}
+DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+
+r0_connected_address_ipv4 = "192.168.0.0/24"
+r0_connected_address_ipv6 = "fd00::/64"
+r1_connected_address_ipv4 = "192.168.1.0/24"
+r1_connected_address_ipv6 = "fd00:0:0:1::/64"
+r3_connected_address_ipv4 = "192.168.2.0/24"
+r3_connected_address_ipv6 = "fd00:0:0:2::/64"
+r4_connected_address_ipv4 = "192.168.3.0/24"
+r4_connected_address_ipv6 = "fd00:0:0:3::/64"
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ # Required linux kernel version for this suite to run.
+ result = required_linux_kernel_version("4.15")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ json_file = "{}/bgp_default_originate_topo1.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls micronet initialization functions.
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons and then start routers
+ start_topology(tgen)
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ global ADDR_TYPES
+ global BGP_CONVERGENCE
+ global DEFAULT_ROUTES
+ global DEFAULT_ROUTE_NXT_HOP_R1, DEFAULT_ROUTE_NXT_HOP_R3
+ global R0_NETWORK_LOOPBACK, R0_NETWORK_LOOPBACK_NXTHOP, R1_NETWORK_LOOPBACK
+ global R0_NETWORK_CONNECTED, R0_NETWORK_CONNECTED_NXTHOP, R1_NETWORK_CONNECTED, R1_NETWORK_CONNECTED_NXTHOP
+ global R4_NETWORK_LOOPBACK, R4_NETWORK_LOOPBACK_NXTHOP, R3_NETWORK_LOOPBACK
+ global R4_NETWORK_CONNECTED, R4_NETWORK_CONNECTED_NXTHOP, R3_NETWORK_CONNECTED, R3_NETWORK_CONNECTED_NXTHOP
+
+ ADDR_TYPES = check_address_types()
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+ # There are the global varibles used through out the file these are acheived only after building the topology.
+
+ r0_loopback_address_ipv4 = topo["routers"]["r0"]["links"]["lo"]["ipv4"]
+ r0_loopback_address_ipv4_nxt_hop = topo["routers"]["r0"]["links"]["r1"][
+ "ipv4"
+ ].split("/")[0]
+ r0_loopback_address_ipv6 = topo["routers"]["r0"]["links"]["lo"]["ipv6"]
+ r0_loopback_address_ipv6_nxt_hop = topo["routers"]["r0"]["links"]["r1"][
+ "ipv6"
+ ].split("/")[0]
+
+ r1_loopback_address_ipv4 = topo["routers"]["r1"]["links"]["lo"]["ipv4"]
+ r1_loopback_address_ipv4_nxt_hop = topo["routers"]["r1"]["links"]["r2"][
+ "ipv4"
+ ].split("/")[0]
+ r1_loopback_address_ipv6 = topo["routers"]["r1"]["links"]["lo"]["ipv6"]
+ r1_loopback_address_ipv6_nxt_hop = topo["routers"]["r1"]["links"]["r2"][
+ "ipv6"
+ ].split("/")[0]
+
+ r4_loopback_address_ipv4 = topo["routers"]["r4"]["links"]["lo"]["ipv4"]
+ r4_loopback_address_ipv4_nxt_hop = topo["routers"]["r4"]["links"]["r3"][
+ "ipv4"
+ ].split("/")[0]
+ r4_loopback_address_ipv6 = topo["routers"]["r4"]["links"]["lo"]["ipv6"]
+ r4_loopback_address_ipv6_nxt_hop = topo["routers"]["r4"]["links"]["r3"][
+ "ipv6"
+ ].split("/")[0]
+
+ r3_loopback_address_ipv4 = topo["routers"]["r3"]["links"]["lo"]["ipv4"]
+ r3_loopback_address_ipv4_nxt_hop = topo["routers"]["r3"]["links"]["r2"][
+ "ipv4"
+ ].split("/")[0]
+ r3_loopback_address_ipv6 = topo["routers"]["r3"]["links"]["lo"]["ipv6"]
+ r3_loopback_address_ipv6_nxt_hop = topo["routers"]["r3"]["links"]["r2"][
+ "ipv6"
+ ].split("/")[0]
+
+ R0_NETWORK_LOOPBACK = {
+ "ipv4": r0_loopback_address_ipv4,
+ "ipv6": r0_loopback_address_ipv6,
+ }
+ R0_NETWORK_LOOPBACK_NXTHOP = {
+ "ipv4": r0_loopback_address_ipv4_nxt_hop,
+ "ipv6": r0_loopback_address_ipv6_nxt_hop,
+ }
+
+ R1_NETWORK_LOOPBACK = {
+ "ipv4": r1_loopback_address_ipv4,
+ "ipv6": r1_loopback_address_ipv6,
+ }
+
+ R0_NETWORK_CONNECTED = {
+ "ipv4": r0_connected_address_ipv4,
+ "ipv6": r0_connected_address_ipv6,
+ }
+ R0_NETWORK_CONNECTED_NXTHOP = {
+ "ipv4": r0_loopback_address_ipv4_nxt_hop,
+ "ipv6": r0_loopback_address_ipv6_nxt_hop,
+ }
+
+ R1_NETWORK_CONNECTED = {
+ "ipv4": r1_connected_address_ipv4,
+ "ipv6": r1_connected_address_ipv6,
+ }
+ R1_NETWORK_CONNECTED_NXTHOP = {
+ "ipv4": r1_loopback_address_ipv4_nxt_hop,
+ "ipv6": r1_loopback_address_ipv6_nxt_hop,
+ }
+
+ R4_NETWORK_LOOPBACK = {
+ "ipv4": r4_loopback_address_ipv4,
+ "ipv6": r4_loopback_address_ipv6,
+ }
+ R4_NETWORK_LOOPBACK_NXTHOP = {
+ "ipv4": r4_loopback_address_ipv4_nxt_hop,
+ "ipv6": r4_loopback_address_ipv6_nxt_hop,
+ }
+
+ R3_NETWORK_LOOPBACK = {
+ "ipv4": r3_loopback_address_ipv4,
+ "ipv6": r3_loopback_address_ipv6,
+ }
+ R4_NETWORK_CONNECTED = {
+ "ipv4": r4_connected_address_ipv4,
+ "ipv6": r4_connected_address_ipv6,
+ }
+ R4_NETWORK_CONNECTED_NXTHOP = {
+ "ipv4": r4_loopback_address_ipv4_nxt_hop,
+ "ipv6": r4_loopback_address_ipv6_nxt_hop,
+ }
+
+ R3_NETWORK_CONNECTED = {
+ "ipv4": r3_connected_address_ipv4,
+ "ipv6": r3_connected_address_ipv6,
+ }
+ R3_NETWORK_CONNECTED_NXTHOP = {
+ "ipv4": r3_loopback_address_ipv4_nxt_hop,
+ "ipv6": r3_loopback_address_ipv6_nxt_hop,
+ }
+
+ # populating the nexthop for default routes
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+
+ interface = topo["routers"]["r1"]["links"]["r2"]["interface"]
+ ipv6_link_local = get_frr_ipv6_linklocal(tgen, "r1", intf=interface)
+ ipv4_nxt_hop = topo["routers"]["r1"]["links"]["r2"]["ipv4"].split("/")[0]
+ ipv6_nxt_hop = topo["routers"]["r1"]["links"]["r2"]["ipv6"].split("/")[0]
+ DEFAULT_ROUTE_NXT_HOP_R1 = {"ipv4": ipv4_nxt_hop, "ipv6": ipv6_link_local}
+
+ interface = topo["routers"]["r3"]["links"]["r2"]["interface"]
+ ipv6_link_local = get_frr_ipv6_linklocal(tgen, "r3", intf=interface)
+ ipv4_nxt_hop = topo["routers"]["r3"]["links"]["r2"]["ipv4"].split("/")[0]
+ ipv6_nxt_hop = topo["routers"]["r3"]["links"]["r2"]["ipv6"].split("/")[0]
+ DEFAULT_ROUTE_NXT_HOP_R3 = {"ipv4": ipv4_nxt_hop, "ipv6": ipv6_link_local}
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def test_verify_default_originate_after_BGP_and_FRR_restart_p2(request):
+ """
+ Summary: "Verify default-originate route after BGP and FRR process restart "
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ global topo
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ step("Configure EBGP between R0 to R1 and IBGP between R1 to R2")
+ step("Configure EBGP between R2 to R3 and IBGP between R3 to R4")
+ input_dict = {
+ "r0": {
+ "bgp": {
+ "local_as": 999,
+ }
+ },
+ "r1": {
+ "bgp": {
+ "local_as": 1000,
+ }
+ },
+ "r2": {
+ "bgp": {
+ "local_as": 1000,
+ }
+ },
+ "r3": {
+ "bgp": {
+ "local_as": 4000,
+ }
+ },
+ "r4": {
+ "bgp": {
+ "local_as": 4000,
+ }
+ },
+ }
+ result = modify_as_number(tgen, topo, input_dict)
+ try:
+ assert result is True
+ except AssertionError:
+ logger.info("Expected behaviour: {}".format(result))
+ logger.info("BGP config is not created because of invalid ASNs")
+ step("After changing the BGP AS Path Verify the BGP Convergence")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert (
+ BGP_CONVERGENCE is True
+ ), " Failed convergence after chaning the AS number :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Configure IPv4 and IPv6 static route (Sv4 , Sv6) on R0 and (S1v4, S1v6)on R4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the static route on R0 \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the static route on R4 \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("verify IPv4 and IPv6 static route are configured and up on R0")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r0", static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Failed Route {} not found in R0 FIB \n Error: {}".format(
+ tc_name, NETWORK1_1, result
+ )
+
+ step("verify IPv4 and IPv6 static route are configured and up on R4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r4", static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Failed Route {} not found in R4 FIB \n Error: {}".format(
+ tc_name, NETWORK2_1, result
+ )
+
+ step(
+ "Configure redistribute connected and static on R0 (R0-R1) on R4 ( R4-R3) IPv4 and IPv6 address family"
+ )
+ redistribute_static = {
+ "r0": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"},
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"},
+ ]
+ }
+ },
+ }
+ }
+ },
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"},
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"},
+ ]
+ }
+ },
+ }
+ }
+ },
+ }
+ result = create_router_bgp(tgen, topo, redistribute_static)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the static route \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("verify IPv4 and IPv6 static route are configured and up on R1")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R0_NETWORK_LOOPBACK[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R0_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+ result = verify_bgp_rib(tgen, addr_type, "r1", static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Failed : Redistributed routes from R0 is not learned in Router R1 RIB \n Error: {}".format(
+ tc_name, result
+ )
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R0_NETWORK_LOOPBACK[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R0_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ {
+ "network": [R1_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R1_NETWORK_LOOPBACK[addr_type],
+ },
+ {
+ "network": [R1_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R1_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_fib_routes(tgen, addr_type, "r1", static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Failed : Redistributed routes from R0 is not learned in Router R1 FIB \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("verify IPv4 and IPv6 static route are configured and up on R3")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R4_NETWORK_LOOPBACK[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R4_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+ result = verify_bgp_rib(tgen, addr_type, "r3", static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Failed : Redistributed routes from R4 is not learned in Router R3 RIB \n Error: {}".format(
+ tc_name, result
+ )
+ static_routes_input = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R3_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R3_NETWORK_LOOPBACK[addr_type],
+ },
+ {
+ "network": [R3_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R3_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R4_NETWORK_LOOPBACK[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R4_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_fib_routes(tgen, addr_type, "r3", static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Redistributed routes from R4 is not learned in Router R3 FIB \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure IPv4 and IPv6 prefix-list on R1 for (Sv4 , Sv6) route")
+ input_dict_3 = {
+ "r1": {
+ "prefix_lists": {
+ "ipv4": {
+ "Pv4": [
+ {
+ "seqid": "1",
+ "network": NETWORK1_1["ipv4"],
+ "action": "permit",
+ }
+ ]
+ },
+ "ipv6": {
+ "Pv6": [
+ {
+ "seqid": "1",
+ "network": NETWORK1_1["ipv6"],
+ "action": "permit",
+ }
+ ]
+ },
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_3)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the prefix lists \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify the Prefix - lists")
+ input_dict = {"r3": {"prefix_lists": ["Pv4", "Pv6"]}}
+ result = verify_prefix_lists(tgen, input_dict)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to verify the prefix lists in router R3 \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure IPv4 (RMv4) and IPv6 (RMv6) route-map on R1")
+ input_dict_3 = {
+ "r1": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv4": {"prefix_lists": "Pv4"}},
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv6": {"prefix_lists": "Pv6"}},
+ },
+ ],
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the route-map \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ " Configure default originate with route-map RMv4 and RMv6 for IPv4 and IPv6 bgp neighbors on R1 ( R1-R2) "
+ )
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"default_originate": {"r2": {"route_map": "RMv4"}}}
+ },
+ "ipv6": {
+ "unicast": {"default_originate": {"r2": {"route_map": "RMv6"}}}
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the default-originate in R1 towards R2 \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("verify IPv4 and IPv6 default route received on R2 with R1 nexthop ")
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ )
+ assert (
+ result is True
+ ), "Testcase {} : Failed : Default routes are not learned in R2 FIB \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ )
+ assert (
+ result is True
+ ), "Testcase {} : Failed : Default routes are not learned in R2 RIB\n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure redistribute connected and static on R1 IPv4 and IPv6 address family"
+ )
+ redistribute_static = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ },
+ }
+ }
+ },
+ }
+ result = create_router_bgp(tgen, topo, redistribute_static)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify IPv4 and IPv6 static and loopback route advertised from R4 and R0 are received on R2"
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R0_NETWORK_LOOPBACK[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R0_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R4_NETWORK_LOOPBACK[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R4_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(" Configure default-originate on R3 for R3 to R2 IPv4 and IPv6 BGP neighbors ")
+ local_as = get_dut_as_number(tgen, dut="r3")
+ default_originate_config = {
+ "r3": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {"unicast": {"default_originate": {"r2": {}}}},
+ "ipv6": {"unicast": {"default_originate": {"r2": {}}}},
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ STEP = """After configuring the Default Originate From R3 --> R2
+ Both Default routes from R1 and R3 Should present in R2 BGP RIB.
+ 'The Deafult Route from iBGP is preffered over EBGP' thus
+ Default Route From R1->r2 should only present in R2 FIB """
+ step(STEP)
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n IBGP default route should be preffered over EBGP default-originate \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify the default route from R1 is recieved both on RIB and FIB on R2")
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=False,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify the static and loopback route advertised from R0 and R4 are received on R2 "
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R0_NETWORK_LOOPBACK[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R0_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R4_NETWORK_LOOPBACK[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R4_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(" BGP Daemon restart operation")
+ routers = ["r1", "r2"]
+ for dut in routers:
+ step(
+ "Restart BGPD process on {}, when all the processes are running use watchfrr ".format(
+ dut
+ )
+ )
+ kill_router_daemons(tgen, dut, ["bgpd"])
+ start_router_daemons(tgen, dut, ["bgpd"])
+
+ step("After restarting the BGP daomon Verify the default originate ")
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n IBGP default route should be prefeered over EBGP \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify the default route from R1 is is recieved both on RIB and FIB on R2"
+ )
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=False,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify the static and loopback route advertised from R0 and R4 are received on R2 "
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R0_NETWORK_LOOPBACK[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R0_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R4_NETWORK_LOOPBACK[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R4_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(" Restarting FRR routers operation")
+ """
+ NOTE : Verify that iBGP default route is preffered over eBGP default route
+ """
+ routers = ["r1", "r2"]
+ for dut in routers:
+ step(
+ "Restart FRR router process on {}, when all the processes are running use watchfrr ".format(
+ dut
+ )
+ )
+
+ stop_router(tgen, dut)
+ start_router(tgen, dut)
+
+ result = verify_bgp_convergence(tgen, topo)
+ assert (
+ result is True
+ ), " Testcase {} : After Restarting {} Convergence Failed".format(tc_name, dut)
+
+ step("After restarting the FRR Router Verify the default originate ")
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify the default route from R1 is is recieved both on RIB and FIB on R2"
+ )
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed\n IBGP default route should be preffered over EBGP default route \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify the static and loopback route advertised from R0 and R4 are received on R2 "
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R0_NETWORK_LOOPBACK[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R0_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R4_NETWORK_LOOPBACK[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R4_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_default_originate_after_shut_no_shut_bgp_neighbor_p1(request):
+ """
+ Summary: "Verify default-originate route after shut/no shut and clear BGP neighbor "
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ global topo
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ step("Configure EBGP between R0 to R1 and IBGP between R1 to R2")
+ step("Configure EBGP between R2 to R3 and IBGP between R3 to R4")
+ input_dict = {
+ "r0": {
+ "bgp": {
+ "local_as": 999,
+ }
+ },
+ "r1": {
+ "bgp": {
+ "local_as": 1000,
+ }
+ },
+ "r2": {
+ "bgp": {
+ "local_as": 1000,
+ }
+ },
+ "r3": {
+ "bgp": {
+ "local_as": 4000,
+ }
+ },
+ "r4": {
+ "bgp": {
+ "local_as": 4000,
+ }
+ },
+ }
+ result = modify_as_number(tgen, topo, input_dict)
+ try:
+ assert result is True
+ except AssertionError:
+ logger.info("Expected behaviour: {}".format(result))
+ logger.info("BGP config is not created because of invalid ASNs")
+ step("After changing the BGP AS Path Verify the BGP Convergence")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Configure one IPv4 and one IPv6 static route on R0 and R4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify IPv4 and IPv6 static route configured on R0 and R4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r0", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r4", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure redistribute connected and static on R0 (R0-R1) on R4 ( R4-R3) IPv4 and IPv6 address family"
+ )
+ redistribute_static = {
+ "r0": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ },
+ {
+ "redist_type": "connected",
+ },
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ },
+ {
+ "redist_type": "connected",
+ },
+ ]
+ }
+ },
+ }
+ }
+ },
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ },
+ {
+ "redist_type": "connected",
+ },
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ },
+ {
+ "redist_type": "connected",
+ },
+ ]
+ }
+ },
+ }
+ }
+ },
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "connected",
+ }
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "connected",
+ }
+ ]
+ }
+ },
+ }
+ }
+ },
+ }
+ result = create_router_bgp(tgen, topo, redistribute_static)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify IPv4 and IPv6 static route configured on R1 from R0")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R0_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R0_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+ result = verify_bgp_rib(tgen, addr_type, "r1", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_routes(tgen, addr_type, "r1", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify IPv4 and IPv6 static route configured on R3 from R4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R4_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R4_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+ result = verify_bgp_rib(tgen, addr_type, "r3", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_routes(tgen, addr_type, "r3", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure default-originate on R1 for R1 to R2 neighbor for IPv4 and IPv6 peer "
+ )
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {"unicast": {"default_originate": {"r2": {}}}},
+ "ipv6": {"unicast": {"default_originate": {"r2": {}}}},
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify IPv4 and IPv6 bgp default route received on R2 nexthop as R1")
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ step(
+ "After configuring default-originate command , verify default routes are advertised on R2 from R0 and R4"
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "next_hop": DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_fib_routes(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R0_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R0_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R4_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R4_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure default-originate on R3 for R3 to R2 neighbor for IPv4 and IPv6 peer"
+ )
+ local_as = get_dut_as_number(tgen, dut="r3")
+ default_originate_config = {
+ "r3": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {"unicast": {"default_originate": {"r2": {}}}},
+ "ipv6": {"unicast": {"default_originate": {"r2": {}}}},
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ STEP = """After configuring the Default Originate From R3 --> R2
+ Both Default routes from R1 and R3 Should present in R2 BGP RIB.
+ 'The Deafult Route from iBGP is preffered over EBGP' thus
+ Default Route From R1->r2 should only present in R2 FIB """
+ step(STEP)
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n IBGP default route should be preffered over EBGP \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify the default route from R1 is recieved both on RIB and FIB on R2")
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "After configuring default-originate command , verify static ,connected and loopback routes are advertised on R2 from R0 and R4"
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R0_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R0_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R4_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R4_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ # updating the topology with the updated AS-Number to avoid conflict in con configuring the AS
+ updated_topo = topo
+ updated_topo["routers"]["r0"]["bgp"]["local_as"] = get_dut_as_number(tgen, "r0")
+ updated_topo["routers"]["r1"]["bgp"]["local_as"] = get_dut_as_number(tgen, "r1")
+ updated_topo["routers"]["r2"]["bgp"]["local_as"] = get_dut_as_number(tgen, "r2")
+ updated_topo["routers"]["r3"]["bgp"]["local_as"] = get_dut_as_number(tgen, "r3")
+ updated_topo["routers"]["r4"]["bgp"]["local_as"] = get_dut_as_number(tgen, "r4")
+
+ step(
+ "Shut R1 to R2 IPv4 and IPv6 BGP neighbor from R1 IPv4 and IPv6 address family "
+ )
+
+ local_as = get_dut_as_number(tgen, dut="r1")
+ shut_neighbor = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r1": {"shutdown": True}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r1": {"shutdown": True}}}
+ }
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, updated_topo, shut_neighbor)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ interface = topo["routers"]["r2"]["links"]["r1"]["interface"]
+ input_dict = {"r2": {"interface_list": [interface], "status": "down"}}
+
+ result = interface_status(tgen, topo, input_dict)
+ assert (
+ result is True
+ ), "Testcase {} : Bring down interface failed ! \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify IPv4 and IPv6 default static and loopback route which received from R1 are deleted from R2"
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R0_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R0_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+ result = verify_bgp_rib(
+ tgen, addr_type, "r2", static_routes_input, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n after shutting down interface routes are not expected \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_routes(
+ tgen, addr_type, "r2", static_routes_input, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n after shutting down interface routes are not expected \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("verify that No impact on IPv4 IPv6 and default route received from R3 ")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R4_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R4_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step(
+ "No-Shut R1 to R2 IPv4 and IPv6 BGP neighbor from R1 IPv4 and IPv6 address family "
+ )
+ local_as = get_dut_as_number(tgen, dut="r1")
+ shut_neighbor = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r1": {"shutdown": False}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r1": {"shutdown": False}}}
+ }
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, updated_topo, shut_neighbor)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ interface = topo["routers"]["r2"]["links"]["r1"]["interface"]
+ input_dict = {"r2": {"interface_list": [interface], "status": "up"}}
+
+ result = interface_status(tgen, topo, input_dict)
+ assert (
+ result is True
+ ), "Testcase {} : Bring up interface failed ! \n Error: {}".format(tc_name, result)
+
+ step(
+ "After no shut Verify IPv4 and IPv6 bgp default route next hop as R1 , static ,connected and loopback received on R2 from r0 and r4 "
+ )
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "next_hop": DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_fib_routes(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R0_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R0_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R4_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R4_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step(
+ "Shut R3 to R2 IPv4 and IPv6 BGP neighbor from R2 IPv4 and IPv6 address family"
+ )
+ local_as = get_dut_as_number(tgen, dut="r3")
+ shut_neighbor = {
+ "r3": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {"shutdown": True}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {"shutdown": True}}}
+ }
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, updated_topo, shut_neighbor)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ interface = topo["routers"]["r2"]["links"]["r3"]["interface"]
+ input_dict = {"r2": {"interface_list": [interface], "status": "down"}}
+
+ result = interface_status(tgen, topo, input_dict)
+ assert (
+ result is True
+ ), "Testcase {} : Bring down interface failed ! \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify IPv4 and IPv6 default static and loopback route which received from R3 are deleted from R2 "
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R4_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R4_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+ result = verify_bgp_rib(
+ tgen, addr_type, "r2", static_routes_input, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed\n After shutting down the interface routes are not expected \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_routes(
+ tgen, addr_type, "r2", static_routes_input, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n After shutting down the interface routes are not expected \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Default route is removed i.e advertised from R3")
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n After shutting down the interface Default route are not expected \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n After shutting down the interface Default route are not expected \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that No impact on IPv4 IPv6 and default route received from R1")
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "next_hop": DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_fib_routes(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R0_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R0_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "No-Shut R3 to R2 IPv4 and IPv6 BGP neighbor from R2 IPv4 and IPv6 address family"
+ )
+ local_as = get_dut_as_number(tgen, dut="r3")
+ shut_neighbor = {
+ "r3": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {"shutdown": False}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {"shutdown": False}}}
+ }
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, updated_topo, shut_neighbor)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ interface = topo["routers"]["r2"]["links"]["r3"]["interface"]
+ input_dict = {"r2": {"interface_list": [interface], "status": "up"}}
+
+ result = interface_status(tgen, topo, input_dict)
+ assert (
+ result is True
+ ), "Testcase {} : Bring up interface failed ! \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that a static ,connected and loopback routes are received from R0 and R4 on R2 "
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R0_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R0_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R4_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R4_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("verify that default route is received on R2 from R1")
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify that default route is received on R2 from R3")
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("Clear IPv4 and IP6 BGP session from R2 and R1 one by one ")
+ routers = ["r1", "r2"]
+ for dut in routers:
+ for addr_type in ADDR_TYPES:
+
+ clear_bgp(tgen, addr_type, dut)
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("verify that default route is received on R2 from R3")
+
+ interface = topo["routers"]["r3"]["links"]["r2"]["interface"]
+ ipv6_link_local = get_frr_ipv6_linklocal(tgen, "r3", intf=interface)
+ ipv4_nxt_hop = topo["routers"]["r3"]["links"]["r2"]["ipv4"].split("/")[0]
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ DEFAULT_ROUTE_NXT_HOP = {"ipv4": ipv4_nxt_hop, "ipv6": ipv6_link_local}
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify the static , loopback and connected routes received from r0 and r4"
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R0_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R0_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R4_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R4_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Shut BGP neighbor interface R2 (R2 to R1) link ")
+ intf_r2_r1 = topo["routers"]["r2"]["links"]["r1"]["interface"]
+ shutdown_bringup_interface(tgen, "r2", intf_r2_r1, False)
+
+ step("Verify the bgp Convergence ")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo, expected=False)
+ assert (
+ BGP_CONVERGENCE is not True
+ ), " :Failed After shutting interface BGP convergence is expected to be faileed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify that default route from R1 got deleted from BGP and RIB table")
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed\n After shuting interface default route should be removed from RIB \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("No - Shut BGP neighbor interface R2 (R2 to R1) link ")
+ intf_r2_r1 = topo["routers"]["r2"]["links"]["r1"]["interface"]
+ shutdown_bringup_interface(tgen, "r2", intf_r2_r1, True)
+
+ step("Verify the bgp Convergence ")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ step("verify that default route is received on R2 from R3")
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify the static , loopback and connected routes received from r0 and r4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R0_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R0_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R4_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R4_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Shut link from R3 to R2 from R3")
+ intf_r3_r2 = topo["routers"]["r3"]["links"]["r2"]["interface"]
+ shutdown_bringup_interface(tgen, "r3", intf_r3_r2, False)
+
+ step("Verify the bgp Convergence ")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo, expected=False)
+ assert (
+ BGP_CONVERGENCE is not True
+ ), " :Failed \nAfter Shuting the interface BGP convegence is expected to be failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify that default route from R3 got deleted from BGP and RIB table")
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("No-Shut link from R3 to R2 from R3")
+
+ ipv4_nxt_hop = topo["routers"]["r1"]["links"]["r2"]["ipv4"].split("/")[0]
+ ipv6_nxt_hop = topo["routers"]["r1"]["links"]["r2"]["ipv6"].split("/")[0]
+
+ DEFAULT_ROUTE_NXT_HOP_1 = {"ipv4": ipv4_nxt_hop, "ipv6": ipv6_nxt_hop}
+
+ ipv4_nxt_hop = topo["routers"]["r1"]["links"]["r2"]["ipv4"].split("/")[0]
+ ipv6_nxt_hop = topo["routers"]["r1"]["links"]["r2"]["ipv6"].split("/")[0]
+
+ DEFAULT_ROUTE_NXT_HOP_3 = {"ipv4": ipv4_nxt_hop, "ipv6": ipv6_nxt_hop}
+
+ intf_r3_r2 = topo["routers"]["r3"]["links"]["r2"]["interface"]
+ shutdown_bringup_interface(tgen, "r3", intf_r3_r2, True)
+
+ step("Verify the bgp Convergence ")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo, expected=True)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ step("verify that default route is received on R2 from R3")
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify the static , loopback and connected routes received from r0 and r4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R0_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R0_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R0_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R4_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R4_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R4_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
--- /dev/null
+#!/usr/bin/env python
+#
+# Copyright (c) 2022 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. ("NetDEF")
+# in this file.
+#
+# 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.
+# Shreenidhi A R <rshreenidhi@vmware.com>
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+import os
+import sys
+import time
+import pytest
+from time import sleep
+from copy import deepcopy
+from lib.topolog import logger
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topojson import build_config_from_json
+from lib.topolog import logger
+
+from lib.bgp import (
+ verify_bgp_convergence,
+ verify_graceful_restart,
+ create_router_bgp,
+ verify_router_id,
+ modify_as_number,
+ verify_as_numbers,
+ clear_bgp_and_verify,
+ clear_bgp,
+ verify_bgp_rib,
+ get_prefix_count_route,
+ get_dut_as_number,
+ verify_rib_default_route,
+ verify_fib_default_route,
+ verify_bgp_advertised_routes_from_neighbor,
+ verify_bgp_received_routes_from_neighbor,
+)
+from lib.common_config import (
+ interface_status,
+ verify_prefix_lists,
+ verify_rib,
+ kill_router_daemons,
+ start_router_daemons,
+ shutdown_bringup_interface,
+ step,
+ required_linux_kernel_version,
+ stop_router,
+ start_router,
+ create_route_maps,
+ create_prefix_lists,
+ get_frr_ipv6_linklocal,
+ start_topology,
+ write_test_header,
+ check_address_types,
+ write_test_footer,
+ reset_config_on_routers,
+ create_static_routes,
+ check_router_status,
+ delete_route_maps,
+)
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# Required to instantiate the topology builder class.
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+
+# Global variables
+topo = None
+KEEPALIVETIMER = 1
+HOLDDOWNTIMER = 3
+
+
+# Global variables
+NETWORK1_1 = {"ipv4": "198.51.1.1/32", "ipv6": "2001:DB8::1:1/128"}
+NETWORK2_1 = {"ipv4": "198.51.1.2/32", "ipv6": "2001:DB8::1:2/128"}
+NETWORK5_1 = {"ipv4": "198.51.1.3/32", "ipv6": "2001:DB8::1:3/128"}
+NETWORK5_2 = {"ipv4": "198.51.1.4/32", "ipv6": "2001:DB8::1:4/128"}
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+
+
+r0_connected_address_ipv4 = "192.168.0.0/24"
+r0_connected_address_ipv6 = "fd00::/64"
+r1_connected_address_ipv4 = "192.168.1.0/24"
+r1_connected_address_ipv6 = "fd00:0:0:1::/64"
+r3_connected_address_ipv4 = "192.168.2.0/24"
+r3_connected_address_ipv6 = "fd00:0:0:2::/64"
+r4_connected_address_ipv4 = "192.168.3.0/24"
+r4_connected_address_ipv6 = "fd00:0:0:3::/64"
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ # Required linux kernel version for this suite to run.
+ result = required_linux_kernel_version("4.15")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ json_file = "{}/bgp_default_orginate_vrf.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ global ADDR_TYPES
+ global BGP_CONVERGENCE
+ global DEFAULT_ROUTES
+ global DEFAULT_ROUTE_NXT_HOP_R1, DEFAULT_ROUTE_NXT_HOP_R3
+ global R1_NETWORK_LOOPBACK, R1_NETWORK_LOOPBACK_NXTHOP
+ global R0_NETWORK_CONNECTED_NXTHOP, R1_NETWORK_CONNECTED, R1_NETWORK_CONNECTED_NXTHOP
+ global R3_NETWORK_LOOPBACK, R3_NETWORK_LOOPBACK_NXTHOP
+ global R3_NETWORK_CONNECTED, R3_NETWORK_CONNECTED_NXTHOP
+
+ ADDR_TYPES = check_address_types()
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+ # There are the global varibles used through out the file these are acheived only after building the topology.
+
+ r0_loopback_address_ipv4 = topo["routers"]["r0"]["links"]["lo"]["ipv4"]
+ r0_loopback_address_ipv4_nxt_hop = topo["routers"]["r0"]["links"]["r1"][
+ "ipv4"
+ ].split("/")[0]
+ r0_loopback_address_ipv6 = topo["routers"]["r0"]["links"]["lo"]["ipv6"]
+ r0_loopback_address_ipv6_nxt_hop = topo["routers"]["r0"]["links"]["r1"][
+ "ipv6"
+ ].split("/")[0]
+
+ r1_loopback_address_ipv4 = topo["routers"]["r1"]["links"]["lo"]["ipv4"]
+ r1_loopback_address_ipv4_nxt_hop = topo["routers"]["r1"]["links"]["r2"][
+ "ipv4"
+ ].split("/")[0]
+ r1_loopback_address_ipv6 = topo["routers"]["r1"]["links"]["lo"]["ipv6"]
+ r1_loopback_address_ipv6_nxt_hop = topo["routers"]["r1"]["links"]["r2"][
+ "ipv6"
+ ].split("/")[0]
+
+ r4_loopback_address_ipv4 = topo["routers"]["r4"]["links"]["lo"]["ipv4"]
+ r4_loopback_address_ipv4_nxt_hop = topo["routers"]["r4"]["links"]["r3"][
+ "ipv4"
+ ].split("/")[0]
+ r4_loopback_address_ipv6 = topo["routers"]["r4"]["links"]["lo"]["ipv6"]
+ r4_loopback_address_ipv6_nxt_hop = topo["routers"]["r4"]["links"]["r3"][
+ "ipv6"
+ ].split("/")[0]
+
+ r3_loopback_address_ipv4 = topo["routers"]["r3"]["links"]["lo"]["ipv4"]
+ r3_loopback_address_ipv4_nxt_hop = topo["routers"]["r3"]["links"]["r2"][
+ "ipv4"
+ ].split("/")[0]
+ r3_loopback_address_ipv6 = topo["routers"]["r3"]["links"]["lo"]["ipv6"]
+ r3_loopback_address_ipv6_nxt_hop = topo["routers"]["r3"]["links"]["r2"][
+ "ipv6"
+ ].split("/")[0]
+
+ R1_NETWORK_LOOPBACK = {
+ "ipv4": r1_loopback_address_ipv4,
+ "ipv6": r1_loopback_address_ipv6,
+ }
+ R1_NETWORK_LOOPBACK_NXTHOP = {
+ "ipv4": r1_loopback_address_ipv4_nxt_hop,
+ "ipv6": r1_loopback_address_ipv6_nxt_hop,
+ }
+
+ R1_NETWORK_CONNECTED = {
+ "ipv4": r1_connected_address_ipv4,
+ "ipv6": r1_connected_address_ipv6,
+ }
+ R1_NETWORK_CONNECTED_NXTHOP = {
+ "ipv4": r1_loopback_address_ipv4_nxt_hop,
+ "ipv6": r1_loopback_address_ipv6_nxt_hop,
+ }
+
+ R3_NETWORK_LOOPBACK = {
+ "ipv4": r3_loopback_address_ipv4,
+ "ipv6": r3_loopback_address_ipv6,
+ }
+ R3_NETWORK_LOOPBACK_NXTHOP = {
+ "ipv4": r3_loopback_address_ipv4_nxt_hop,
+ "ipv6": r3_loopback_address_ipv6_nxt_hop,
+ }
+
+ R3_NETWORK_CONNECTED = {
+ "ipv4": r3_connected_address_ipv4,
+ "ipv6": r3_connected_address_ipv6,
+ }
+ R3_NETWORK_CONNECTED_NXTHOP = {
+ "ipv4": r3_loopback_address_ipv4_nxt_hop,
+ "ipv6": r3_loopback_address_ipv6_nxt_hop,
+ }
+
+ # populating the nexthop for default routes
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+
+ interface = topo["routers"]["r1"]["links"]["r2"]["interface"]
+ ipv6_link_local = get_frr_ipv6_linklocal(tgen, "r1", intf=interface)
+ ipv4_nxt_hop = topo["routers"]["r1"]["links"]["r2"]["ipv4"].split("/")[0]
+ ipv6_nxt_hop = topo["routers"]["r1"]["links"]["r2"]["ipv6"].split("/")[0]
+ DEFAULT_ROUTE_NXT_HOP_R1 = {"ipv4": ipv4_nxt_hop, "ipv6": ipv6_link_local}
+
+ interface = topo["routers"]["r3"]["links"]["r2"]["interface"]
+ ipv6_link_local = get_frr_ipv6_linklocal(tgen, "r3", intf=interface)
+ ipv4_nxt_hop = topo["routers"]["r3"]["links"]["r2"]["ipv4"].split("/")[0]
+ ipv6_nxt_hop = topo["routers"]["r3"]["links"]["r2"]["ipv6"].split("/")[0]
+ DEFAULT_ROUTE_NXT_HOP_R3 = {"ipv4": ipv4_nxt_hop, "ipv6": ipv6_link_local}
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+def test_verify_default_originate_route_with_non_default_VRF_p1(request):
+ """
+ "Verify default-originate route with non-default VRF"
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ # these steps are implemented as base toplopgy setup
+ step("Configure IPV4 and IPV6 IBGP between R1 and R2 default VRF")
+ step("Configure IPV4 and IPV6 EBGP between R2 to R3 non-default VRF (RED)")
+ step(
+ "Configure IPv4 and IP6 loopback address on R1 default and R3 non-default (RED) VRF"
+ )
+ step("After changing the BGP AS Path Verify the BGP Convergence")
+
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+ step(
+ "Configure IPv4 and IPv6 static route on R1 default and R3 non-default (RED) VRF with nexthop as Null ( different static route on each side)"
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the static routes in router R1 default vrf \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure static route in R3 non default vrf RED \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify IPv4 and IPv6 static route configured on R1 default vrf and R3 non-default (RED) vrf"
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_rib(tgen, addr_type, "r1", static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Failed: Routes configured on vrf is not seen in R1 default VRF FIB \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED",
+ }
+ ]
+ }
+ }
+ result = verify_rib(tgen, addr_type, "r3", static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Failed : Routes configured in non-defaul vrf in R3 FIB is \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure redistribute connected and static on R1 (R1-R2) and on R3 ( R2-R3 RED VRF) IPv4 and IPv6 address family "
+ )
+ redistribute_static = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"},
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"},
+ ]
+ }
+ },
+ }
+ }
+ },
+ "r3": {
+ "bgp": {
+ "local_as": 3000,
+ "vrf": "RED",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"},
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"},
+ ]
+ }
+ },
+ },
+ }
+ },
+ }
+ result = create_router_bgp(tgen, topo, redistribute_static)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the redistribute on R1 and R3 \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify IPv4 and IPv6 static route configured on R1 received as BGP routes on R2 default VRF "
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R1_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R1_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R1_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R1_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step(
+ "Verify IPv4 and IPv6 static route configured on R3 received as BGP routes on R2 non-default VRF "
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED",
+ },
+ {
+ "network": [R3_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R3_NETWORK_CONNECTED_NXTHOP[addr_type],
+ "vrf": "RED",
+ },
+ ]
+ }
+ }
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure default-originate on R1 for R1 to R2 neighbor for IPv4 and IPv6 peer"
+ )
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {"unicast": {"default_originate": {"r2": {}}}},
+ "ipv6": {"unicast": {"default_originate": {"r2": {}}}},
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the default originate \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After configuring default-originate command , verify default routes are advertised on R2 "
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "next_hop": DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R1_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R1_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R1_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R1_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ snapshot1 = get_prefix_count_route(tgen, topo, dut="r2", peer="r3", vrf="RED")
+
+ step(
+ "Configure default-originate on R3 for R3 to R2 neighbor (RED VRF) for IPv4 and IPv6 peer"
+ )
+
+ default_originate_config = {
+ "r3": {
+ "bgp": {
+ "local_as": "3000",
+ "vrf": "RED",
+ "address_family": {
+ "ipv4": {"unicast": {"default_originate": {"r2": {}}}},
+ "ipv6": {"unicast": {"default_originate": {"r2": {}}}},
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify IPv4 and IPv6 bgp default route and static route received on R2 VRF red nexthop as R3"
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED",
+ },
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "next_hop": DEFAULT_ROUTE_NXT_HOP_R3[addr_type],
+ "vrf": "RED",
+ },
+ ]
+ }
+ }
+ result = verify_rib(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_R3[addr_type],
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_bgp_rib(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_R3[addr_type],
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("verify Out-prefix count incremented for IPv4/IPv6 default route on VRF red")
+ snapshot2 = get_prefix_count_route(tgen, topo, dut="r2", peer="r3", vrf="RED")
+ step("verifying the prefix count incrementing or not ")
+ isIPv4prefix_incremented = False
+ isIPv6prefix_incremented = False
+ if snapshot1["ipv4_count"] < snapshot2["ipv4_count"]:
+ isIPv4prefix_incremented = True
+ if snapshot1["ipv6_count"] < snapshot2["ipv6_count"]:
+ isIPv6prefix_incremented = True
+
+ assert (
+ isIPv4prefix_incremented is True
+ ), "Testcase {} : Failed Error: IPV4 Prefix is not incremented on receiveing ".format(
+ tc_name
+ )
+
+ step("Configure import VRF red on R2 for IPV4 and IPV6 BGP peer")
+ step("Importing the non-default vrf in default VRF ")
+ local_as = get_dut_as_number(tgen, "r2")
+ input_import_vrf = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {"unicast": {"import": {"vrf": "RED"}}},
+ "ipv6": {"unicast": {"import": {"vrf": "RED"}}},
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_import_vrf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ step(
+ "Verify VRF RED IPv4 and IPv6, default-originate, \n static and loopback route are imported to R2 default VRF table ,\n default-originate route coming from VRF red should not active on R2 default VRF table"
+ )
+ step("verifying the static routes connected and loop back routes")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R1_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R1_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R1_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R1_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ {
+ "network": [R3_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R3_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ STEP = """ After importing non defualt VRF into default vrf .
+ verify that the default originate from R1 --> R2(non -default) is preffered over R3 --> R2
+ because the Default Route prefers iBGP over eBGP over
+ Default Route from R1 Should be present in BGP RIB and FIB
+ Default Route from R3 Should be present only in BGP RIB not in FIB
+ """
+ step(STEP)
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "next_hop": DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "next_hop": DEFAULT_ROUTE_NXT_HOP_R3[addr_type],
+ },
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "next_hop": DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step(
+ "Configure import VRF default on R2 (R2-R3) RED VRF for IPV4 and IPV6 BGP peer"
+ )
+ step("Importing the default vrf in non-default VRF ")
+ local_as = "2000"
+ input_import_vrf = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": local_as,
+ "vrf": "RED",
+ "address_family": {
+ "ipv4": {"unicast": {"import": {"vrf": "default"}}},
+ "ipv6": {"unicast": {"import": {"vrf": "default"}}},
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_import_vrf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ step(
+ "Default VR, IPv4 and IPv6 , default-originate, \n static and loopback route are imported to R2 VRF RED table \n, default-originate route coming from VRF red should not active on R2 default VRF table"
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED",
+ },
+ {
+ "network": [R1_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R1_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ "vrf": "RED",
+ },
+ {
+ "network": [R1_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R1_NETWORK_CONNECTED_NXTHOP[addr_type],
+ "vrf": "RED",
+ },
+ {
+ "network": [R3_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R3_NETWORK_CONNECTED_NXTHOP[addr_type],
+ "vrf": "RED",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ STEP = """ After importing defualt VRF into non default vrf .
+ verify that the default originate from R1 --> R2(non -default) is preffered over R3 --> R2
+ because the Default Route prefers iBGP over eBGP over
+ Default Route from R1 Should be present in BGP RIB and FIB
+ Default Route from R3 Should be present only in BGP RIB not in FIB
+ """
+ step(STEP)
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "next_hop": DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ "vrf": "RED",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "next_hop": DEFAULT_ROUTE_NXT_HOP_R3[addr_type],
+ "vrf": "RED",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_R3[addr_type],
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed {} \n Error: {}".format(
+ tc_name, STEP, result
+ )
+
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "next_hop": DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ "vrf": "RED",
+ },
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "next_hop": DEFAULT_ROUTE_NXT_HOP_R3[addr_type],
+ "vrf": "RED",
+ },
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Remove import VRF configure in step 8 and then remove import VRF configured on step 9"
+ )
+ local_as = get_dut_as_number(tgen, "r2")
+ input_import_vrf = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {"unicast": {"import": {"vrf": "RED", "delete": True}}},
+ "ipv6": {"unicast": {"import": {"vrf": "RED", "delete": True}}},
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_import_vrf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that the routes imported from non default VRF - RED is removed")
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [R3_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R3_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ },
+ {
+ "network": [R3_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R3_NETWORK_CONNECTED_NXTHOP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, "r2", static_routes_input, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n routes imported from non default VRF is not expected Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(
+ tgen, addr_type, "r2", static_routes_input, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n routes imported from non default VRF is not expected \nError: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Remove import VRF configure in step 8 and then remove import VRF configured on step 9"
+ )
+ local_as = "2000"
+ input_import_vrf = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": local_as,
+ "vrf": "RED",
+ "address_family": {
+ "ipv4": {
+ "unicast": {"import": {"vrf": "default", "delete": True}}
+ },
+ "ipv6": {
+ "unicast": {"import": {"vrf": "default", "delete": True}}
+ },
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_import_vrf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ step("Verify that the routes impoted from default VRF is removed")
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED",
+ },
+ {
+ "network": [R1_NETWORK_LOOPBACK[addr_type]],
+ "next_hop": R1_NETWORK_LOOPBACK_NXTHOP[addr_type],
+ "vrf": "RED",
+ },
+ {
+ "network": [R1_NETWORK_CONNECTED[addr_type]],
+ "next_hop": R1_NETWORK_CONNECTED_NXTHOP[addr_type],
+ "vrf": "RED",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, "r2", static_routes_input, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n routes impoted from default VRF is not expected \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(
+ tgen, addr_type, "r2", static_routes_input, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n routes impoted from default VRF is not expected \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_default_originate_route_with_non_default_VRF_with_route_map_p1(request):
+ """
+ "Verify default-originate route with non-default VRF with route-map import "
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Configure IPV4 and IPV6 static route on R0 with Null nexthop")
+ STEP = """
+ Configure IPV4 and IPV6 EBGP session between R0 and R1
+ Configure IPV4 and IPV6 static route on R0 with Null nexthop """
+ step(STEP)
+ input_dict = {
+ "r0": {"bgp": {"local_as": 222, "vrf": "default"}},
+ "r1": {"bgp": {"local_as": 333, "vrf": "default"}},
+ }
+ result = modify_as_number(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ try:
+ assert result is True
+ except AssertionError:
+ logger.info("Expected behaviour: {}".format(result))
+ logger.info("BGP config is not created because of invalid ASNs")
+ step("After changing the BGP AS Path Verify the BGP Convergence")
+
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Configuring static route at R0")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": [NETWORK5_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step(" Configure re-distribute static on R0 for R0 to R1 for IPV4 and IPV6 peer ")
+ redistribute_static = {
+ "r0": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"},
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"},
+ ]
+ }
+ },
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, redistribute_static)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Configure default-originate on R1 for R1 to R2 neighbor for IPv4 and IPv6 peer"
+ )
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {"unicast": {"default_originate": {"r2": {}}}},
+ "ipv6": {"unicast": {"default_originate": {"r2": {}}}},
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ snapshot1 = get_prefix_count_route(tgen, topo, dut="r2", peer="r3", vrf="RED")
+
+ step("Verify IPv4 and IPv6 static received on R2 default VRF as BGP routes")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK5_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "next_hop": DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step(
+ " Configure IPv4 and IPv6 prefix-list of of route received from R1 on R2 and for 0.0.0.0/0 0::0/0 route"
+ )
+ input_dict_3 = {
+ "r2": {
+ "prefix_lists": {
+ "ipv4": {
+ "Pv4": [
+ {
+ "seqid": "1",
+ "network": NETWORK5_1["ipv4"],
+ "action": "permit",
+ },
+ {"seqid": "2", "network": "0.0.0.0/0", "action": "permit"},
+ {
+ "seqid": "3",
+ "network": NETWORK2_1["ipv4"],
+ "action": "permit",
+ },
+ ]
+ },
+ "ipv6": {
+ "Pv6": [
+ {
+ "seqid": "1",
+ "network": NETWORK5_1["ipv6"],
+ "action": "permit",
+ },
+ {"seqid": "2", "network": "0::0/0", "action": "permit"},
+ {
+ "seqid": "3",
+ "network": NETWORK2_1["ipv6"],
+ "action": "permit",
+ },
+ ]
+ },
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify IPv4 and IPv6 Prefix list got configured on R3")
+ input_dict = {"r2": {"prefix_lists": ["Pv4", "Pv6"]}}
+ result = verify_prefix_lists(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Configure IPv4/IPv6 route-map on R2 with deny sequence using above prefix-list"
+ )
+ input_dict_3 = {
+ "r2": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "deny",
+ "seq_id": "1",
+ "match": {"ipv4": {"prefix_lists": "Pv4"}},
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "deny",
+ "seq_id": "1",
+ "match": {"ipv6": {"prefix_lists": "Pv6"}},
+ },
+ ],
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ STEP = """
+ import Route-map anf non-default VRF into defailt vrf
+ import vrf route-map RM1
+ import vrf red
+ """
+ step(STEP)
+
+ local_as = get_dut_as_number(tgen, "r2")
+ input_import_vrf = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {"unicast": {"import": {"vrf": "RED"}}},
+ "ipv6": {"unicast": {"import": {"vrf": "RED"}}},
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_import_vrf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ step(STEP)
+ input_import_vrf = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {"unicast": {"import": {"vrf": "route-map RMv4"}}},
+ "ipv6": {"unicast": {"import": {"vrf": "route-map RMv6"}}},
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_import_vrf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ step(
+ "Verify IPv4 and IPv6 routes present on VRF red ( static , default-originate) should not get advertised to default VRF "
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "next_hop": DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, "r2", static_routes_input, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n VRF red ( static , default-originate) should not get advertised to default VRF \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(
+ tgen, addr_type, "r2", static_routes_input, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n VRF red ( static , default-originate) should not get advertised to default VRF \nError: {}".format(
+ tc_name, result
+ )
+
+ step("Change route-map sequence deny to permit")
+ input_dict_3 = {
+ "r2": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv4": {"prefix_lists": "Pv4"}},
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv6": {"prefix_lists": "Pv6"}},
+ },
+ ],
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "IPv4 and IPv6 routes present on VRF red ( static , default-originate) should get advertised to default VRF"
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "next_hop": DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("verify Out-prefix count incremented for IPv4/IPv6 default route on VRF red")
+ snapshot2 = get_prefix_count_route(tgen, topo, dut="r2", peer="r3", vrf="RED")
+ step("verifying the prefix count incrementing or not ")
+ isIPv4prefix_incremented = False
+ isIPv6prefix_incremented = False
+ if snapshot1["ipv4_count"] <= snapshot2["ipv4_count"]:
+ isIPv4prefix_incremented = True
+ if snapshot1["ipv6_count"] <= snapshot2["ipv6_count"]:
+ isIPv6prefix_incremented = True
+
+ assert (
+ isIPv4prefix_incremented is True
+ ), "Testcase {} : Failed Error: IPV4 Prefix is not incremented on receiveing ".format(
+ tc_name
+ )
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
--- /dev/null
+#!/usr/bin/env python
+#
+# Copyright (c) 2022 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. ("NetDEF")
+# in this file.
+#
+# 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.
+# Shreenidhi A R <rshreenidhi@vmware.com>
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+"""
+Following scenerios are covered.
+1. When there is change in route-map policy associated with default-originate, changes does not reflect.
+2. When route-map associated with default-originate is deleted, default route doesn't get withdrawn
+3. Update message is not being sent when only route-map is removed from the default-originate config.
+4. SNT counter gets incremented on change of every policy associated with default-originate
+5. Route-map with multiple match clauses causes inconsistencies with default-originate.
+6. BGP-Default originate behaviour with BGP attributes
+"""
+import os
+import sys
+import time
+import pytest
+from copy import deepcopy
+from lib.topolog import logger
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topojson import build_config_from_json
+from lib.topolog import logger
+
+from lib.bgp import (
+ verify_bgp_convergence,
+ create_router_bgp,
+ get_prefix_count_route,
+ modify_as_number,
+ verify_bgp_rib,
+ get_dut_as_number,
+ verify_rib_default_route,
+ verify_fib_default_route,
+)
+from lib.common_config import (
+ verify_fib_routes,
+ step,
+ required_linux_kernel_version,
+ create_route_maps,
+ interface_status,
+ create_prefix_lists,
+ get_frr_ipv6_linklocal,
+ start_topology,
+ write_test_header,
+ verify_prefix_lists,
+ check_address_types,
+ write_test_footer,
+ reset_config_on_routers,
+ create_static_routes,
+ check_router_status,
+ delete_route_maps,
+)
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+
+# Global variables
+topo = None
+NETWORK1_1 = {"ipv4": "198.51.1.1/32", "ipv6": "2001:DB8::1:1/128"}
+DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ # Required linux kernel version for this suite to run.
+ result = required_linux_kernel_version("4.15")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ json_file = "{}/bgp_default_originate_topo1.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ global ADDR_TYPES
+ global BGP_CONVERGENCE
+ global DEFAULT_ROUTES
+ global DEFAULT_ROUTE_NXT_HOP_R1, DEFAULT_ROUTE_NXT_HOP_R3
+ ADDR_TYPES = check_address_types()
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+
+ interface = topo["routers"]["r1"]["links"]["r2"]["interface"]
+ ipv6_link_local = get_frr_ipv6_linklocal(tgen, "r1", intf=interface)
+ ipv4_nxt_hop = topo["routers"]["r1"]["links"]["r2"]["ipv4"].split("/")[0]
+ ipv6_nxt_hop = topo["routers"]["r1"]["links"]["r2"]["ipv6"].split("/")[0]
+ DEFAULT_ROUTE_NXT_HOP_R1 = {"ipv4": ipv4_nxt_hop, "ipv6": ipv6_link_local}
+
+ interface = topo["routers"]["r3"]["links"]["r2"]["interface"]
+ ipv6_link_local = get_frr_ipv6_linklocal(tgen, "r3", intf=interface)
+ ipv4_nxt_hop = topo["routers"]["r3"]["links"]["r2"]["ipv4"].split("/")[0]
+ ipv6_nxt_hop = topo["routers"]["r3"]["links"]["r2"]["ipv6"].split("/")[0]
+ DEFAULT_ROUTE_NXT_HOP_R3 = {"ipv4": ipv4_nxt_hop, "ipv6": ipv6_link_local}
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def test_default_originate_delete_conditional_routemap(request):
+ """
+ "scenerio covered":
+ 1. When there is change in route-map policy associated with default-originate, changes does not reflect.
+ 2. When route-map associated with default-originate is deleted, default route doesn't get withdrawn
+ 3. Update message is not being sent when only route-map is removed from the default-originate config.
+ 4. SNT counter gets incremented on change of every policy associated with default-originate
+ 5. Route-map with multiple match clauses causes inconsistencies with default-originate.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ global topo
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ step("Configure IPv4 and IPv6 , IBGP neighbor between R1 and R2")
+ step("Configure IPv4 and IPv6 , EBGP neighbor between R1 and R0")
+ input_dict = {
+ "r0": {
+ "bgp": {
+ "local_as": 999,
+ }
+ },
+ "r1": {
+ "bgp": {
+ "local_as": 1000,
+ }
+ },
+ "r2": {
+ "bgp": {
+ "local_as": 1000,
+ }
+ },
+ "r3": {
+ "bgp": {
+ "local_as": 2000,
+ }
+ },
+ "r4": {
+ "bgp": {
+ "local_as": 3000,
+ }
+ },
+ }
+ result = modify_as_number(tgen, topo, input_dict)
+ try:
+ assert result is True
+ except AssertionError:
+ logger.info("Expected behaviour: {}".format(result))
+ logger.info("BGP config is not created because of invalid ASNs")
+
+ step("After changing the BGP remote as , Verify the BGP Convergence")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert (
+ BGP_CONVERGENCE is True
+ ), "Complete convergence is expected after changing ASN ....! ERROR :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Configure 1 IPv4 and 1 IPv6 Static route on R0 with next-hop as Null0")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the static route \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("verify IPv4 and IPv6 static route are configured and up on R0")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r0", static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : routes {} not found in R0 FIB \n Error: {}".format(
+ tc_name, static_routes_input, result
+ )
+
+ step(
+ "Configure redistribute static on IPv4 and IPv6 address family on R0 for R0 to R1 neighbor "
+ )
+ redistribute_static = {
+ "r0": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ "ipv6": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, redistribute_static)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure redistribute configuration....! \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("verify IPv4 and IPv6 static route are received on R1")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r1", static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Failed... Routes {} expected in r1 FIB after configuring the redistribute config on R0 \n Error: {}".format(
+ tc_name, static_routes_input, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Failed... Routes {} expected in r1 RIB after configuring the redistribute config on R0\n Error: {}".format(
+ tc_name, static_routes_input, result
+ )
+
+ step(
+ "Configure IPv4 prefix-list 'Pv4' and and IPv6 prefix-list 'Pv6' on R1 to match BGP route Sv41, IPv6 route Sv61 permit "
+ )
+ input_dict_3 = {
+ "r1": {
+ "prefix_lists": {
+ "ipv4": {
+ "Pv4": [
+ {
+ "seqid": "1",
+ "network": NETWORK1_1["ipv4"],
+ "action": "permit",
+ },
+ ]
+ },
+ "ipv6": {
+ "Pv6": [
+ {
+ "seqid": "1",
+ "network": NETWORK1_1["ipv6"],
+ "action": "permit",
+ },
+ ]
+ },
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_3)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the prefix list \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure IPV4 and IPv6 route-map (RMv4 and RMv6) matching prefix-list (Pv4 and Pv6) respectively on R1"
+ )
+ input_dict_3 = {
+ "r1": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv4": {"prefix_lists": "Pv4"}},
+ "set": {
+ "path": {
+ "as_num": "5555",
+ "as_action": "prepend",
+ }
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv6": {"prefix_lists": "Pv6"}},
+ "set": {
+ "path": {
+ "as_num": "5555",
+ "as_action": "prepend",
+ }
+ },
+ },
+ ],
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the route map \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure default-originate with route-map (RMv4 and RMv6) on R1, on BGP IPv4 and IPv6 address family "
+ )
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"default_originate": {"r2": {"route_map": "RMv4"}}}
+ },
+ "ipv6": {
+ "unicast": {"default_originate": {"r2": {"route_map": "RMv6"}}}
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the default originate \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After configuring default-originate command , verify default routes are advertised on R2 "
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ metric=0,
+ expected_aspath="5555",
+ )
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the default originate \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the default originate \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Changing the as-path policy of the existing route-map")
+ input_dict_3 = {
+ "r1": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv4": {"prefix_lists": "Pv4"}},
+ "set": {
+ "path": {
+ "as_num": "6666",
+ "as_action": "prepend",
+ }
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv6": {"prefix_lists": "Pv6"}},
+ "set": {
+ "path": {
+ "as_num": "6666",
+ "as_action": "prepend",
+ }
+ },
+ },
+ ],
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the route map \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify prefix sent count on R1 towards R2 \n Send count shoud not be incremented on change of existing (AS-path) policy "
+ )
+ snapshot = get_prefix_count_route(
+ tgen, topo, dut="r1", peer="r2", link="r1", sent=True, received=False
+ )
+
+ ipv4_prefix_count = False
+ ipv6_prefix_count = False
+ if snapshot["ipv4_count"] == 2:
+ ipv4_prefix_count = True
+ if snapshot["ipv6_count"] == 2:
+ ipv6_prefix_count = True
+
+ assert (
+ ipv4_prefix_count is True
+ ), "Testcase {} : Failed Error: Expected sent Prefix is 2 but obtained {} ".format(
+ tc_name, ipv4_prefix_count
+ )
+ assert (
+ ipv6_prefix_count is True
+ ), "Testcase {} : Failed Error: Expected sent Prefix is 2 but obtained {} ".format(
+ tc_name, ipv6_prefix_count
+ )
+
+ step(
+ "After changing the as-path policy verify the new policy is advertised to router R2"
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ metric=0,
+ expected_aspath="6666",
+ )
+ assert (
+ result is True
+ ), "Testcase {} : Default route with expected attributes is not found in BGP RIB \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert (
+ result is True
+ ), "Testcase {} : Default route with expected attributes is not found in BGP FIB \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Remove the as-path policy from the route-map")
+ input_dict_3 = {
+ "r1": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv4": {"prefix_lists": "Pv4"}},
+ "set": {
+ "path": {
+ "as_num": "6666",
+ "as_action": "prepend",
+ "delete": True,
+ }
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv6": {"prefix_lists": "Pv6"}},
+ "set": {
+ "path": {
+ "as_num": "6666",
+ "as_action": "prepend",
+ "delete": True,
+ }
+ },
+ },
+ ],
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the route map \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After removing the route policy (AS-Path) verify that as-path is removed in r2 "
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ )
+ assert result is True, "Testcase {} : Failed ... ! \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed .... !\n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Delete the route-map ")
+
+ delete_routemap = {"r1": {"route_maps": ["RMv4", "RMv6"]}}
+ result = delete_route_maps(tgen, delete_routemap)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to delete the route-map\n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After deleting route-map , verify the default route in FIB and RIB are removed "
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ metric=0,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : After removing the route-map the default-route is not removed from R2 RIB\n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : After removing the route-map the default-route is not removed from R2 FIB \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Create route-map with with sequnce number 10 ")
+ input_dict_3 = {
+ "r1": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "match": {"ipv4": {"prefix_lists": "Pv4"}},
+ "set": {
+ "path": {
+ "as_num": "9999",
+ "as_action": "prepend",
+ }
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "match": {"ipv6": {"prefix_lists": "Pv6"}},
+ "set": {
+ "path": {
+ "as_num": "9999",
+ "as_action": "prepend",
+ }
+ },
+ },
+ ],
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the route map \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After Configuring the route-map the dut is expected to receive the route policy (as-path) as 99999"
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ metric=0,
+ expected_aspath="9999",
+ )
+ assert result is True, "Testcase {} : Failed...! \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed ...!\n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Create another route-map with seq number less than the previous i. <10 ")
+ input_dict_3 = {
+ "r1": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "5",
+ "match": {"ipv4": {"prefix_lists": "Pv4"}},
+ "set": {
+ "path": {
+ "as_num": "7777",
+ "as_action": "prepend",
+ }
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "5",
+ "match": {"ipv6": {"prefix_lists": "Pv6"}},
+ "set": {
+ "path": {
+ "as_num": "7777",
+ "as_action": "prepend",
+ }
+ },
+ },
+ ],
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the route map \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "On creating new route-map the route-map with lower seq id should be considered "
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ metric=0,
+ expected_aspath="7777",
+ )
+ assert (
+ result is True
+ ), "Testcase {} : Route-map with lowest prefix is not considered \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert (
+ result is True
+ ), "Testcase {} : Route-map with lowest prefix is not considered \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_default_originate_after_BGP_attributes_p1(request):
+ """
+ "Verify different BGP attributes with default-originate route "
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ global topo
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ step("Configure IPv4 and IPv6 , EBGP neighbor between R3 and R2")
+ step("Configure IPv4 and IPv6 IBGP neighbor between R3 and R4")
+ r0_local_as = topo['routers']['r0']['bgp']['local_as']
+ r1_local_as = topo['routers']['r1']['bgp']['local_as']
+ r2_local_as = topo['routers']['r2']['bgp']['local_as']
+ r3_local_as = topo['routers']['r3']['bgp']['local_as']
+ r4_local_as = topo['routers']['r4']['bgp']['local_as']
+ input_dict = {
+ "r0": {
+ "bgp": {
+ "local_as": r0_local_as,
+ }
+ },
+ "r1": {
+ "bgp": {
+ "local_as": r1_local_as,
+ }
+ },
+ "r2": {
+ "bgp": {
+ "local_as": r2_local_as,
+ }
+ },
+ "r3": {
+ "bgp": {
+ "local_as": 4000,
+ }
+ },
+ "r4": {
+ "bgp": {
+ "local_as": 4000,
+ }
+ },
+ }
+ result = modify_as_number(tgen, topo, input_dict)
+
+ try:
+ assert result is True
+ except AssertionError:
+ logger.info("Expected behaviour: {}".format(result))
+ logger.info("BGP config is not created because of invalid ASNs")
+ step("After changing the BGP AS Path Verify the BGP Convergence")
+
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step(
+ "Configure one IPv4 and one IPv6, Static route on R4 with next-hop as Null0 IPv4 route Sv41, IPv6 route Sv61 "
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("Verify IPv4 and IPv6 static routes configured on R4 in FIB")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r4", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure redistribute static knob on R4 , for R4 to R3 neighbor for IPv4 and IPv6 address family "
+ )
+ redistribute_static = {
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ "ipv6": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, redistribute_static)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify After configuring redistribute static , verify route received in BGP table of R3"
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r3", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r3", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ NOTE = """Configure 2 IPv4 prefix-list Pv41 Pv42 and and 2 IPv6 prefix-list Pv61 Pv62 on R3 to match BGP IPv4 route Sv41, 200.1.1.1/24 , IPv6 route Sv61 and 200::1/64"""
+ step(NOTE)
+ input_dict_3 = {
+ "r3": {
+ "prefix_lists": {
+ "ipv4": {
+ "Pv41": [
+ {
+ "seqid": "1",
+ "network": NETWORK1_1["ipv4"],
+ "action": "permit",
+ }
+ ],
+ "Pv42": [
+ {"seqid": "1", "network": "200.1.1.1/24", "action": "permit"}
+ ],
+ },
+ "ipv6": {
+ "Pv61": [
+ {
+ "seqid": "1",
+ "network": NETWORK1_1["ipv6"],
+ "action": "permit",
+ }
+ ],
+ "Pv62": [
+ {"seqid": " 1", "network": "200::1/64", "action": "permit"}
+ ],
+ },
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify IPv4 and IPv6 Prefix list got configured on R3")
+ input_dict = {"r3": {"prefix_lists": ["Pv41", "Pv61", "Pv42", "Pv62"]}}
+ result = verify_prefix_lists(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Configure 2 sequence of route-map for IPv4 seq1 permit Pv41 and seq2 permit Pv42 and for IPv6 seq1 permit Pv61 , seq2 permit Pv62 on R3"
+ )
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv4": {"prefix_lists": "Pv41"}},
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "match": {"ipv4": {"prefix_lists": "Pv42"}},
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv6": {"prefix_lists": "Pv61"}},
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "match": {"ipv6": {"prefix_lists": "Pv62"}},
+ },
+ ],
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Apply on route-map seq1 set as-path prepend to 200 and route-map seq2 set as-path prepend to 300 for IPv4 and IPv6 route-map "
+ )
+ route_map = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "path": {
+ "as_num": "200",
+ "as_action": "prepend",
+ }
+ }
+
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "path": {
+ "as_num": "300",
+ "as_action": "prepend",
+ }
+ }
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "path": {
+ "as_num": "200",
+ "as_action": "prepend",
+ }
+ }
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "path": {
+ "as_num": "300",
+ "as_action": "prepend",
+ }
+ }
+ },
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ " Configure default-originate with IPv4 and IPv6 route-map on R3 for R3-R2 IPv4 and IPv6 BGP neighbor"
+ )
+
+ local_as = get_dut_as_number(tgen, dut="r3")
+ default_originate_config = {
+ "r3": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"default_originate": {"r2": {"route_map": "RMv4"}}}
+ },
+ "ipv6": {
+ "unicast": {"default_originate": {"r2": {"route_map": "RMv6"}}}
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify IPv4 and IPv6 default route received on R2 with both the AS path on R2"
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ metric=0,
+ expected_aspath="4000 200",
+ )
+
+ step(
+ "Modify AS prepend path adding one more value 500 in route-map sequence 1 and 600 for route-map sequence 2 for IPv4 and IPv6 route-map"
+ )
+ route_map = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "path": {
+ "as_num": "500",
+ "as_action": "prepend",
+ }
+ }
+
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "path": {
+ "as_num": "600",
+ "as_action": "prepend",
+ }
+ }
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "path": {
+ "as_num": "500",
+ "as_action": "prepend",
+ }
+ }
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "path": {
+ "as_num": "600",
+ "as_action": "prepend",
+ }
+ }
+ },
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+
+ step("As path 500 added to IPv4 and IPv6 default -originate route received on R2")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ metric=0,
+ expected_aspath="4000 500",
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Apply on route-map seq1 set metric value to 70 and route-map seq2 set metric 80 IPv4 and IPv6 route-map"
+ )
+ route_map = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "metric": 70,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "metric": 80,
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "metric": 70,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "metric": 80,
+ },
+ },
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify Configured metric value received on R2 along with as-path for IPv4 and IPv6 default routes "
+ )
+
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "::/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ metric=70,
+ expected_aspath="4000 500",
+ )
+
+
+ step(
+ "Modify route-map seq1 configure metric 50 and route-map seq2 configure metric 100 IPv4 and IPv6 route-map "
+ )
+ route_map = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "metric": 50,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "metric": 100,
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "metric": 50,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "metric": 100,
+ },
+ },
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify Configured metric value received on R2 along with as-path for IPv4 and IPv6 default routes "
+ )
+
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ metric=50,
+ expected_aspath="4000 500",
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Delete AS-prepend from IP4 and IPv6 route-map configured on R3 ")
+ route_map = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+
+ "set": {
+ "path": {
+ "as_num": "500",
+ "as_action": "prepend",
+ "delete": True,
+ },
+ "delete": True,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "path": {
+ "as_num": "600",
+ "as_action": "prepend",
+ "delete": True,
+ },
+ "delete": True,
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "path": {
+ "as_num": "500",
+ "as_action": "prepend",
+ "delete": True,
+ },
+ "delete": True,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "path": {
+ "as_num": "600",
+ "as_action": "prepend",
+ "delete": True,
+ },
+ "delete": True,
+ },
+ },
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify AS-prepend is deleted from default originate route and metric value only present on R2 for IPv4 and IPv6 default routes "
+ )
+
+
+
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ metric=50,
+ expected_aspath="4000",
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+
+ step("Delete metric value from IP4 and IPv6 route-map configured on R3 ")
+ route_map = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {"metric": 50, "delete": True},
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {"metric": 100, "delete": True},
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {"metric": 50, "delete": True},
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {"metric": 100, "delete": True},
+ },
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify Metric value deleted from IPv4 and IPv6 default route on R2 ,verify default routes "
+ )
+
+
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ metric=0,
+ expected_aspath="4000",
+ )
+
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ step("Change IPv4 and IPv6 , EBGP to IBGP neighbor between R3 and R2")
+ step("Change IPv4 and IPv6 IBGP to EBGP neighbor between R3 and R4")
+ r0_local_as = topo['routers']['r0']['bgp']['local_as']
+ r1_local_as = topo['routers']['r1']['bgp']['local_as']
+ r2_local_as = topo['routers']['r2']['bgp']['local_as']
+ r3_local_as = topo['routers']['r3']['bgp']['local_as']
+ r4_local_as = topo['routers']['r4']['bgp']['local_as']
+ input_dict = {
+ "r0": {
+ "bgp": {
+ "local_as": r0_local_as,
+ }
+ },
+ "r1": {
+ "bgp": {
+ "local_as": r1_local_as,
+ }
+ },
+
+ "r2": {
+ "bgp": {
+ "local_as": 1111,
+ }
+ },
+ "r3": {
+ "bgp": {
+ "local_as": 1111,
+ }
+ },
+ "r4": {
+ "bgp": {
+ "local_as": 5555,
+ }
+ },
+ }
+ result = modify_as_number(tgen, topo, input_dict)
+ try:
+ assert result is True
+ except AssertionError:
+ logger.info("Expected behaviour: {}".format(result))
+ logger.info("BGP config is not created because of invalid ASNs")
+ step("After changing the BGP AS Path Verify the BGP Convergence")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+ step(
+ "Configure one IPv4 and one IPv6, Static route on R4 with next-hop as Null0 IPv4 route Sv41, IPv6 route Sv61 "
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("Verify IPv4 and IPv6 static routes configured on R4 in FIB")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r4", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure redistribute static knob on R4 , for R4 to R3 neighbor for IPv4 and IPv6 address family "
+ )
+ redistribute_static = {
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ "ipv6": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, redistribute_static)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify After configuring redistribute static , verify route received in BGP table of R3"
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r3", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r3", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step(
+ " Configure default-originate with IPv4 and IPv6 route-map on R3 for R3-R2 IPv4 and IPv6 BGP neighbor"
+ )
+ local_as = get_dut_as_number(tgen, dut="r3")
+ default_originate_config = {
+ "r3": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"default_originate": {"r2": {"route_map": "RMv4"}}}
+ },
+ "ipv6": {
+ "unicast": {"default_originate": {"r2": {"route_map": "RMv6"}}}
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify IPv4 and IPv6 default route received on R2 with both the AS path on R2"
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Configure local -preference to 50 on IPv4 and IPv6 route map seq1 and 60 on seq2"
+ )
+ route_map = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "locPrf": 50,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "locPrf": 60,
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "locPrf": 50,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "locPrf": 60,
+ },
+ },
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify Configured metric value received on R2 along with as-path for IPv4 and IPv6 default routes "
+ )
+
+
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ locPrf=50,
+ )
+
+
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Modify local preference value to 150 on IPv4 and IPv6 route map seq1 and 160 on seq2"
+ )
+ route_map = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "locPrf": 150,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "locPrf": 160,
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "locPrf": 150,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "locPrf": 160,
+ },
+ },
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify Modified local-preference value received on R2 for IPv4 and IPv6 default routes "
+ )
+
+
+
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "::/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ locPrf=150,
+ )
+
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ # updating the topology with the updated AS-Number to avoid conflict in con configuring the AS
+ updated_topo = topo
+ updated_topo['routers']['r0']['bgp']['local_as']=get_dut_as_number(tgen,"r0")
+ updated_topo['routers']['r1']['bgp']['local_as']=get_dut_as_number(tgen,"r1")
+ updated_topo['routers']['r2']['bgp']['local_as']=get_dut_as_number(tgen,"r2")
+ updated_topo['routers']['r3']['bgp']['local_as']=get_dut_as_number(tgen,"r3")
+ updated_topo['routers']['r4']['bgp']['local_as']=get_dut_as_number(tgen,"r4")
+
+ step("Shut IPv4/IPv6 BGP neighbor from R4 ( R4-R3) using 'neighbor x.x.x.x shut' command ")
+ local_as = get_dut_as_number(tgen, dut="r4")
+ shut_neighbor = {
+ "r4": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {"shutdown":True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {"shutdown":True}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, updated_topo, shut_neighbor)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ interface = topo['routers']['r3']['links']['r4']['interface']
+ input_dict = {
+ "r1": {
+ "interface_list": [interface],
+ "status": "down"
+ }
+ }
+
+ result = interface_status(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Shut down the interface failed ! \n Error: {}".format(tc_name, result)
+
+ step("After shutting the interface verify the BGP convergence")
+ result = verify_bgp_convergence(tgen,topo,expected=False)
+ assert result is not True, "Testcase {} : Failed \n After shutting Down BGP convergence should Fail and return False \n Error: {}".format(tc_name, result)
+
+ step("verify default route deleted from R2 ")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: After Shut down interface the default route is NOT expected but found in RIB -> {}".format( tc_name, result)
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: After Shut down interface the default route is NOT expected but found in FIB -> {}".format( tc_name, result)
+
+
+ step("no Shut IPv4/IPv6 BGP neighbor from R4 ( R4-R3) using 'neighbor x.x.x.x shut' command ")
+ local_as = get_dut_as_number(tgen, dut="r4")
+ shut_neighbor = {
+ "r4": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {"shutdown":False}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {"shutdown":False}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, updated_topo, shut_neighbor)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ interface = topo['routers']['r3']['links']['r4']['interface']
+ input_dict = {
+ "r1": {
+ "interface_list": [interface],
+ "status": "up"
+ }
+ }
+
+ result = interface_status(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Bring up interface failed ! \n Error: {}".format(tc_name, result)
+
+ step("After no shutting the interface verify the BGP convergence")
+ result = verify_bgp_convergence(tgen,topo,expected=True)
+ assert result is True, "Testcase {} : Failed \n After shutting Down BGP convergence should Fail and return False \n Error: {}".format(tc_name, result)
+
+ step("After no shut neighbor , verify default route relearn on R2")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=True)
+ assert result is True, "Testcase {} : Failed \n Error: After no Shut down interface the default route is expected but found in RIB -> {}".format( tc_name, result)
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=True)
+ assert result is True, "Testcase {} : Failed \n Error: After Shut down interface the default route is expected but found in FIB -> {}".format( tc_name, result)
+
+
+
+ step("Remove IPv4/IPv6 static route configure on R4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "delete": True
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("Verify IPv4 and IPv6 static routes removed on R4 in FIB")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r4", static_routes_input, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_bgp_rib(tgen, addr_type, "r4", static_routes_input, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("After removing static route , verify default route removed on R2")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected= False)
+ assert result is not True, "Testcase {} : Failed \n Error: After removing static the default route is NOT expected but found in RIB -> {}".format( tc_name, result)
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected= False)
+ assert result is not True, "Testcase {} : Failed \n Error: After removing static the default route is NOT expected but found in FIB -> {}".format( tc_name, result)
+
+
+ step("Configuring the static route back in r4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("Verify IPv4 and IPv6 static routes configured on R4 in FIB")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r4", static_routes_input, expected=True)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_bgp_rib(tgen, addr_type, "r4", static_routes_input, expected=True)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("After adding static route back , verify default route learned on R2")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected= True)
+ assert result is True, "Testcase {} : Failed \n Error: After removing static the default route is expected but found in RIB -> {}".format( tc_name, result)
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected= True)
+ assert result is True, "Testcase {} : Failed \n Error: After removing static the default route is expected but found in FIB -> {}".format( tc_name, result)
+
+ step("Deactivate IPv4 and IPv6 neighbor configured from R4 ( R4-R3)")
+
+ configure_bgp_on_r1 = {
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {"deactivate": "ipv4"}}}
+ }
+ },
+
+ },"ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {"deactivate": "ipv6"}}}
+ }
+ },
+
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, updated_topo, configure_bgp_on_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("After deactivating the BGP neighbor , verify default route removed on R2")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected= False)
+ assert result is not True, "Testcase {} : Failed \n Error: After Deactivating the BGP neighbor the default route is NOT expected but found in RIB -> {}".format( tc_name, result)
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected= False)
+ assert result is not True, "Testcase {} : Failed \n Error: After Deactivating the BGP neighbor the default route is NOT expected but found in FIB -> {}".format( tc_name, result)
+
+ step("Activate IPv4 and IPv6 neighbor configured from R4 ( R4-R3)")
+
+ configure_bgp_on_r1 = {
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {"activate": "ipv4"}}}
+ }
+ },
+
+ },"ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {"activate": "ipv6"}}}
+ }
+ },
+
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, updated_topo, configure_bgp_on_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify bgp convergence.")
+ bgp_convergence = verify_bgp_convergence(tgen, updated_topo)
+ assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, bgp_convergence
+ )
+ step("After Activating the BGP neighbor , verify default route learned on R2")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected= True)
+ assert result is True, "Testcase {} : Failed \n Error: After Deactivating the BGP neighbor the default route is expected but found in RIB -> {}".format( tc_name, result)
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected= True)
+ assert result is True, "Testcase {} : Failed \n Error: After Deactivating the BGP neighbor the default route is expected but found in FIB -> {}".format( tc_name, result)
+ write_test_footer(tc_name)
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
interface r1-eth0
ip address 192.168.255.1/24
!
-ip route 192.168.13.0./24 Null0
-!
ip forwarding
!
interface r1-eth0
ip address 192.168.255.1/24
!
-ip route 192.168.13.0./24 Null0
-!
ip forwarding
!
--- /dev/null
+!
+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
+!
--- /dev/null
+!
+allow-reserved-ranges
+!
+interface lo
+ ip address 172.16.255.1/32
+!
+interface r1-eth0
+ ip address 240.0.0.1/24
+!
+ip forwarding
+!
--- /dev/null
+!
+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
+!
--- /dev/null
+!
+allow-reserved-ranges
+!
+interface r2-eth0
+ ip address 240.0.0.2/24
+!
+ip forwarding
+!
--- /dev/null
+#!/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))
)
from lib.topojson import build_config_from_json
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
# Global variables
topo = None
)
from lib.topojson import build_config_from_json
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
# Global variables
topo = None
from lib.topojson import build_config_from_json
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
# Global variables
topo = None
)
from lib.topojson import build_config_from_json
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
# Global variables
topo = None
-
# Global variables
NETWORK = {
"ipv4": [
# Global variables
topo = None
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
# Global variables
NETWORK_CMD_IP = "1.0.1.17/32"
if tgen.hasmpls != True:
logger.info("MPLS not available, skipping setup")
return False
- # configure r2 mpls interfaces
- intfs = ["lo", "r2-eth0", "r2-eth1", "r2-eth2"]
- for intf in intfs:
- cc.doCmd(tgen, "r2", "echo 1 > /proc/sys/net/mpls/conf/{}/input".format(intf))
- # configure MPLS
- rtrs = ["r1", "r3", "r4"]
- cmds = ["echo 1 > /proc/sys/net/mpls/conf/lo/input"]
- for rtr in rtrs:
- router = tgen.gears[rtr]
- for cmd in cmds:
- cc.doCmd(tgen, rtr, cmd)
- intfs = ["lo", rtr + "-eth0", rtr + "-eth4"]
- for intf in intfs:
- cc.doCmd(
- tgen, rtr, "echo 1 > /proc/sys/net/mpls/conf/{}/input".format(intf)
- )
logger.info("setup mpls input")
return True
hostname r1
!
interface lo
+ mpls
ip address 1.1.1.1/32
!
interface r1-eth0
description to sw0
+ mpls
ip address 10.0.1.1/24
no link-detect
!
interface r1-eth4
description to ce1
+ mpls
ip address 192.168.1.1/24
no link-detect
!
hostname r2
!
interface lo
+ mpls
ip address 2.2.2.2/32
!
interface r2-eth0
description to sw0
+ mpls
ip address 10.0.1.2/24
no link-detect
!
interface r2-eth1
description to sw1
+ mpls
ip address 10.0.2.2/24
no link-detect
!
interface r2-eth2
description to sw2
+ mpls
ip address 10.0.3.2/24
no link-detect
!
hostname r3
!
interface lo
+ mpls
ip address 3.3.3.3/32
!
interface r3-eth0
description to sw1
+ mpls
ip address 10.0.2.3/24
no link-detect
!
!
interface r3-eth4
description to ce2
+ mpls
ip address 192.168.1.1/24
no link-detect
!
hostname r4
!
interface lo
+ mpls
ip address 4.4.4.4/32
!
interface r4-eth0
description to sw1
+ mpls
ip address 10.0.2.4/24
no link-detect
!
interface r4-eth4
description to ce3
+ mpls
ip address 192.168.1.1/24
no link-detect
!
--- /dev/null
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+ address-family ipv4 unicast
+ redistribute connected
+ neighbor 192.168.1.2 capability orf prefix-list both
+ exit-address-family
+!
--- /dev/null
+!
+int lo
+ ip address 10.10.10.1/32
+ ip address 10.10.10.2/32
+!
+int r1-eth0
+ ip address 192.168.1.1/24
+!
--- /dev/null
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ address-family ipv4 unicast
+ neighbor 192.168.1.1 capability orf prefix-list both
+ neighbor 192.168.1.1 prefix-list r1 in
+ exit-address-family
+!
+ip prefix-list r1 seq 5 permit 10.10.10.1/32
--- /dev/null
+!
+int r2-eth0
+ ip address 192.168.1.2/24
+!
--- /dev/null
+#!/usr/bin/env python
+
+# 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.
+#
+
+"""
+Test if BGP ORF filtering is working correctly when modifying
+prefix-list.
+
+Initially advertise 10.10.10.1/32 from R1 to R2. Add new prefix
+10.10.10.2/32 to r1 prefix list on R2. Test if we updated ORF
+prefix-list correctly.
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+pytestmark = pytest.mark.bgpd
+
+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
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def setup_module(mod):
+ topodef = {"s1": ("r1", "r2")}
+ tgen = Topogen(topodef, 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_orf():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+ r2 = tgen.gears["r2"]
+
+ def _bgp_converge_r1():
+ output = json.loads(
+ r1.vtysh_cmd(
+ "show bgp ipv4 unicast neighbor 192.168.1.2 advertised-routes json"
+ )
+ )
+ expected = {"advertisedRoutes": {"10.10.10.1/32": {}, "10.10.10.2/32": None}}
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge_r1)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Can't apply ORF from R1 to R2"
+
+ def _bgp_converge_r2():
+ output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast summary json"))
+ expected = {
+ "peers": {
+ "192.168.1.1": {
+ "pfxRcd": 1,
+ "pfxSnt": 1,
+ "state": "Established",
+ "peerState": "OK",
+ }
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge_r2)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "ORF filtering is not working from R1 to R2"
+
+ r2.vtysh_cmd(
+ """
+ configure terminal
+ ip prefix-list r1 seq 10 permit 10.10.10.2/32
+ """
+ )
+
+ def _bgp_orf_changed_r1():
+ output = json.loads(
+ r1.vtysh_cmd(
+ "show bgp ipv4 unicast neighbor 192.168.1.2 advertised-routes json"
+ )
+ )
+ expected = {"advertisedRoutes": {"10.10.10.1/32": {}, "10.10.10.2/32": {}}}
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_orf_changed_r1)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Can't apply new ORF from R1 to R2"
+
+ def _bgp_orf_changed_r2():
+ output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast json"))
+ expected = {
+ "routes": {
+ "10.10.10.1/32": [{"valid": True}],
+ "10.10.10.2/32": [{"valid": True}],
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_orf_changed_r2)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "New ORF filtering is not working from R1 to R2"
+
+ r2.vtysh_cmd(
+ """
+ configure terminal
+ no ip prefix-list r1 seq 10 permit 10.10.10.2/32
+ """
+ )
+
+ test_func = functools.partial(_bgp_converge_r1)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Can't apply initial ORF from R1 to R2"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
bgp router-id 192.168.2.1
network 192.0.2.0/24
! Correct role pair
- neighbor 192.168.2.2 remote-as 64502
+ neighbor 192.168.2.2 remote-as external
neighbor 192.168.2.2 local-role provider
neighbor 192.168.2.2 timers 3 10
! Incorrect role pair
- neighbor 192.168.3.2 remote-as 64503
+ neighbor 192.168.3.2 remote-as external
neighbor 192.168.3.2 local-role provider
neighbor 192.168.3.2 timers 3 10
! Missed neighbor role
- neighbor 192.168.4.2 remote-as 64504
+ neighbor 192.168.4.2 remote-as external
neighbor 192.168.4.2 local-role provider
neighbor 192.168.4.2 timers 3 10
! Missed neighbor role with strict-mode
- neighbor 192.168.5.2 remote-as 64505
+ neighbor 192.168.5.2 remote-as external
neighbor 192.168.5.2 local-role provider strict-mode
neighbor 192.168.5.2 timers 3 10
+! Testing peer-groups
+ neighbor PG peer-group
+ neighbor PG remote-as external
+ neighbor PG local-role provider
+ neighbor PG timers 3 10
+ neighbor 192.168.6.2 peer-group PG
interface r1-eth3
ip address 192.168.5.1/24
!
+interface r1-eth4
+ ip address 192.168.6.1/24
+!
ip forwarding
!
router bgp 64502
bgp router-id 192.168.2.2
- neighbor 192.168.2.1 remote-as 64501
+ neighbor 192.168.2.1 remote-as external
neighbor 192.168.2.1 local-role customer
neighbor 192.168.2.1 timers 3 10
router bgp 64503
- neighbor 192.168.3.1 remote-as 64501
+ neighbor 192.168.3.1 remote-as external
neighbor 192.168.3.1 local-role peer
neighbor 192.168.3.1 timers 3 10
router bgp 64504
- neighbor 192.168.4.1 remote-as 64501
+ neighbor 192.168.4.1 remote-as external
neighbor 192.168.4.1 timers 3 10
router bgp 64505
- neighbor 192.168.5.1 remote-as 64501
+ neighbor 192.168.5.1 remote-as external
neighbor 192.168.5.1 timers 3 10
--- /dev/null
+router bgp 64506
+ neighbor 192.168.6.1 remote-as external
+ neighbor 192.168.6.1 local-role customer
+ neighbor 192.168.6.1 timers 3 10
--- /dev/null
+!
+interface r6-eth0
+ ip address 192.168.6.2/24
+!
+ip forwarding
+!
pytestmark = [pytest.mark.bgpd]
-topodef = {f"s{i}": ("r1", f"r{i}") for i in range(2, 6)}
+topodef = {f"s{i}": ("r1", f"r{i}") for i in range(2, 7)}
@pytest.fixture(scope="module")
assert success, "Session between r1 and r5 was not correctly closed"
+def test_correct_pair_peer_group(tgen):
+ # provider-customer pair (using peer-groups)
+ router = tgen.gears["r1"]
+ neighbor_ip = "192.168.6.2"
+ check_r6_established = functools.partial(
+ check_session_established, router, neighbor_ip
+ )
+ success, _ = topotest.run_and_expect(check_r6_established, True, count=20, wait=3)
+ assert success, "Session with r6 is not Established"
+
+ neighbor_status = find_neighbor_status(router, neighbor_ip)
+ assert neighbor_status["localRole"] == "provider"
+ assert neighbor_status["remoteRole"] == "customer"
+ assert (
+ neighbor_status["neighborCapabilities"].get("role") == "advertisedAndReceived"
+ )
+
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
# Import topogen and topotest helpers
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.snmptest import SnmpTester
+from lib import topotest
# Required to instantiate the topology builder class.
tgen = get_topogen()
r1 = tgen.gears["r1"]
- r1_snmp = SnmpTester(r1, "10.1.1.1", "public", "2c")
+ def _convergence():
+ r1 = tgen.gears["r1"]
+ r1_snmp = SnmpTester(r1, "10.1.1.1", "public", "2c")
+
+ return r1_snmp.test_oid("bgpVersion", "10")
+
+ _, result = topotest.run_and_expect(_convergence, True, count=20, wait=1)
assertmsg = "BGP SNMP does not seem to be running"
- assert r1_snmp.test_oid("bgpVersion", "10"), assertmsg
+ assert result, assertmsg
+
+ r1_snmp = SnmpTester(r1, "10.1.1.1", "public", "2c")
count = 0
passed = False
while count < 125:
--- /dev/null
+router bgp 65500
+ bgp router-id 1.1.1.1
+ neighbor 10.125.0.2 remote-as 65500
+ address-family ipv4 unicast
+ no neighbor 10.125.0.2 activate
+ exit-address-family
+ address-family ipv4 vpn
+ neighbor 10.125.0.2 activate
+ no bgp retain route-target all
+ exit-address-family
+!
+router bgp 65500 vrf vrf1
+ bgp router-id 1.1.1.1
+ address-family ipv4 unicast
+ redistribute connected
+ label vpn export 101
+ rd vpn export 444:1
+ rt vpn import 51:100 52:100
+ rt vpn export 51:100
+ export vpn
+ import vpn
+ exit-address-family
+!
+
--- /dev/null
+{
+ "vrfId":0,
+ "vrfName":"default",
+ "tableVersion":1,
+ "routerId":"1.1.1.1",
+ "defaultLocPrf":100,
+ "localAS":65500,
+ "routes":{
+ "routeDistinguishers":{
+ "444:1":{
+ "10.201.0.0/24":[
+ {
+ "valid":true,
+ "bestpath":true,
+ "selectionReason":"First path received",
+ "pathFrom":"external",
+ "prefix":"10.201.0.0",
+ "prefixLen":24,
+ "network":"10.201.0.0\/24",
+ "version":1,
+ "metric":0,
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"incomplete",
+ "announceNexthopSelf":true,
+ "nhVrfName":"vrf1",
+ "nexthops":[
+ {
+ "ip":"0.0.0.0",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ },
+ "444:2":{
+ "10.200.0.0/24":[
+ {
+ "valid":true,
+ "bestpath":true,
+ "selectionReason":"First path received",
+ "pathFrom":"internal",
+ "prefix":"10.200.0.0",
+ "prefixLen":24,
+ "network":"10.200.0.0\/24",
+ "version":1,
+ "metric":0,
+ "locPrf":100,
+ "weight":0,
+ "peerId":"10.125.0.2",
+ "path":"",
+ "origin":"incomplete",
+ "nexthops":[
+ {
+ "ip":"10.125.0.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ },
+ "444:3":{
+ }
+ }
+ }
+}
--- /dev/null
+{
+ "vrfId":0,
+ "vrfName":"default",
+ "tableVersion":1,
+ "routerId":"1.1.1.1",
+ "defaultLocPrf":100,
+ "localAS":65500,
+ "routes":{
+ "routeDistinguishers":{
+ "444:1":{
+ "10.201.0.0/24":[
+ {
+ "valid":true,
+ "bestpath":true,
+ "selectionReason":"First path received",
+ "pathFrom":"external",
+ "prefix":"10.201.0.0",
+ "prefixLen":24,
+ "network":"10.201.0.0\/24",
+ "version":1,
+ "metric":0,
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"incomplete",
+ "announceNexthopSelf":true,
+ "nhVrfName":"vrf1",
+ "nexthops":[
+ {
+ "ip":"0.0.0.0",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ },
+ "444:2":{
+ "10.200.0.0/24":[
+ {
+ "valid":true,
+ "bestpath":true,
+ "selectionReason":"First path received",
+ "pathFrom":"internal",
+ "prefix":"10.200.0.0",
+ "prefixLen":24,
+ "network":"10.200.0.0\/24",
+ "version":1,
+ "metric":0,
+ "locPrf":100,
+ "weight":0,
+ "peerId":"10.125.0.2",
+ "path":"",
+ "origin":"incomplete",
+ "nexthops":[
+ {
+ "ip":"10.125.0.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ },
+ "444:3":{
+ "10.210.0.0/24":[
+ {
+ "valid":true,
+ "bestpath":true,
+ "selectionReason":"First path received",
+ "pathFrom":"internal",
+ "prefix":"10.210.0.0",
+ "prefixLen":24,
+ "network":"10.210.0.0\/24",
+ "version":1,
+ "metric":0,
+ "locPrf":100,
+ "weight":0,
+ "peerId":"10.125.0.2",
+ "path":"",
+ "origin":"incomplete",
+ "nexthops":[
+ {
+ "ip":"10.125.0.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
--- /dev/null
+interface r1-eth0
+ ip router isis 1
+ isis circuit-type level-1
+!
+interface lo
+ ip router isis 1
+ isis passive
+!
+router isis 1
+ is-type level-1
+ net 49.0002.0000.1994.00
+ segment-routing on
+ segment-routing prefix 1.1.1.1/32 index 11
+!
--- /dev/null
+log stdout
+interface lo
+ ip address 1.1.1.1/32
+!
+interface r1-gre0
+ ip address 192.168.0.1/24
+!
+interface r1-eth1 vrf vrf1
+ ip address 10.201.0.1/24
+!
+interface r1-eth0
+ ip address 10.125.0.1/24
+!
--- /dev/null
+router bgp 65500
+ bgp router-id 2.2.2.2
+ neighbor 10.125.0.1 remote-as 65500
+ address-family ipv4 unicast
+ no neighbor 10.125.0.1 activate
+ exit-address-family
+ address-family ipv4 vpn
+ neighbor 10.125.0.1 activate
+ no bgp retain route-target all
+ exit-address-family
+!
+router bgp 65500 vrf vrf1
+ bgp router-id 2.2.2.2
+ address-family ipv4 unicast
+ redistribute connected
+ label vpn export 102
+ rd vpn export 444:2
+ rt vpn import 53:100 52:100 51:100
+ rt vpn export 52:100
+ export vpn
+ import vpn
+ exit-address-family
+!
+router bgp 65500 vrf vrf2
+ bgp router-id 2.2.2.2
+ address-family ipv4 unicast
+ redistribute connected
+ label vpn export 102
+ rd vpn export 444:3
+ rt vpn both 53:100 52:100 51:100
+ rt vpn both 53:100
+ export vpn
+ import vpn
+ exit-address-family
+!
--- /dev/null
+interface r2-eth0
+ ip router isis 1
+ isis circuit-type level-1
+!
+interface lo
+ ip router isis 1
+ isis passive
+!
+router isis 1
+ is-type level-1
+ net 49.0002.0000.1995.00
+ segment-routing on
+ segment-routing prefix 2.2.2.2/32 index 22
+!
--- /dev/null
+log stdout
+interface lo
+ ip address 2.2.2.2/32
+!
+interface r2-gre0
+ ip address 192.168.0.2/24
+!
+interface r2-eth1 vrf vrf1
+ ip address 10.200.0.2/24
+!
+interface r2-eth2 vrf vrf2
+ ip address 10.210.0.2/24
+!
+interface r2-eth0
+ ip address 10.125.0.2/24
+!
--- /dev/null
+#!/usr/bin/env python
+
+#
+# test_bgp_vpnv4_noretain.py
+# Part of NetDEF Topology Tests
+#
+# Copyright 2022 6WIND S.A.
+#
+# 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.
+#
+
+"""
+ test_bgp_vpnv4_noretain.py: Do not keep the VPNvx entries when no
+ VRF matches incoming VPNVx entries
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+
+
+pytestmark = [pytest.mark.bgpd]
+
+def build_topo(tgen):
+ "Build function"
+
+ tgen.add_router("r1")
+ tgen.add_router("r2")
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r1"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["r2"])
+
+
+def _populate_iface():
+ tgen = get_topogen()
+ cmds_list = [
+ 'modprobe mpls_router',
+ 'echo 100000 > /proc/sys/net/mpls/platform_labels',
+ 'ip link add vrf1 type vrf table 10',
+ 'ip link set dev vrf1 up',
+ 'ip link set dev {0}-eth1 master vrf1',
+ 'echo 1 > /proc/sys/net/mpls/conf/vrf1/input',
+ ]
+ cmds_list_extra = [
+ 'ip link add vrf2 type vrf table 20',
+ 'ip link set dev vrf2 up',
+ 'ip link set dev {0}-eth2 master vrf2',
+ 'echo 1 > /proc/sys/net/mpls/conf/vrf2/input',
+ ]
+
+ for cmd in cmds_list:
+ input = cmd.format('r1', '1', '2')
+ logger.info('input: ' + cmd)
+ output = tgen.net['r1'].cmd(cmd.format('r1', '1', '2'))
+ logger.info('output: ' + output)
+
+ for cmd in cmds_list:
+ input = cmd.format('r2', '2', '1')
+ logger.info('input: ' + cmd)
+ output = tgen.net['r2'].cmd(cmd.format('r2', '2', '1'))
+ logger.info('output: ' + output)
+
+ for cmd in cmds_list_extra:
+ input = cmd.format('r2', '2', '1')
+ logger.info('input: ' + cmd)
+ output = tgen.net['r2'].cmd(cmd.format('r2', '2', '1'))
+ logger.info('output: ' + output)
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ _populate_iface()
+
+ for rname, router in router_list.items():
+ 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))
+ )
+ router.load_config(
+ TopoRouter.RD_ISIS, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ # Initialize all routers.
+ tgen.start_router()
+
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ tgen.stop_topology()
+
+
+def test_protocols_convergence():
+ """
+ Assert that all protocols have converged
+ statuses as they depend on it.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Check IPv4 VPN routing tables on r1
+ logger.info("Checking IPv4 routes for convergence on r1")
+ router = tgen.gears['r1']
+ json_file = "{}/{}/ipv4_vpn_routes.json".format(CWD, router.name)
+ if not os.path.isfile(json_file):
+ logger.info("skipping file {}".format(json_file))
+ assert 0, 'ipv4_vpn_routes.json file not found'
+ return
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp,
+ router,
+ "show bgp ipv4 vpn json",
+ expected,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+ # Check BGP IPv4 routing tables after unsetting no retain flag
+ logger.info("Checking BGP IPv4 routes for convergence on r2")
+ router = tgen.gears['r1']
+ router.vtysh_cmd("configure\nrouter bgp 65500\naddress-family ipv4 vpn\nbgp retain route-target all\n")
+
+ # Check IPv4 VPN routing tables on r1
+ logger.info("Checking IPv4 routes for convergence on r1")
+ router = tgen.gears['r1']
+ json_file = "{}/{}/ipv4_vpn_routes_unfiltered.json".format(CWD, router.name)
+ if not os.path.isfile(json_file):
+ logger.info("skipping file {}".format(json_file))
+ assert 0, 'ipv4_vpn_routes_unfiltered.json file not found'
+ return
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp,
+ router,
+ "show bgp ipv4 vpn json",
+ expected,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
"""
Topotest conftest.py file.
"""
+# pylint: disable=consider-using-f-string
import glob
import os
assert topotest_extra_config["valgrind_memleaks"]
leaks = []
- tgen = get_topogen()
+ tgen = get_topogen() # pylint: disable=redefined-outer-name
latest = []
existing = []
if tgen is not None:
if hasattr(tgen, "valgrind_existing_files"):
existing = tgen.valgrind_existing_files
latest = glob.glob(os.path.join(logdir, "*.valgrind.*"))
+ latest = [x for x in latest if "core" not in x]
daemons = set()
for vfile in latest:
if vfile in existing:
continue
- existing.append(vfile)
+ # do not consider memleaks from parent fork (i.e., owned by root)
+ if os.stat(vfile).st_uid == 0:
+ existing.append(vfile) # do not check again
+ logger.debug("Skipping valgrind file %s owned by root", vfile)
+ continue
+ logger.debug("Checking valgrind file %s not owned by root", vfile)
with open(vfile, encoding="ascii") as vf:
vfcontent = vf.read()
match = re.search(r"ERROR SUMMARY: (\d+) errors", vfcontent)
+ if match:
+ existing.append(vfile) # have summary don't check again
if match and match.group(1) != "0":
emsg = "{} in {}".format(match.group(1), vfile)
leaks.append(emsg)
- daemons.add(re.match(r".*\.valgrind\.(.*)\.\d+", vfile).group(1))
+ daemon = re.match(r".*\.valgrind\.(.*)\.\d+", vfile).group(1)
+ daemons.add("{}({})".format(daemon, match.group(1)))
if tgen is not None:
tgen.valgrind_existing_files = existing
pytest.fail("valgrind memleaks found for daemons: " + " ".join(daemons))
+@pytest.fixture(autouse=True, scope="module")
+def module_check_memtest(request):
+ del request # disable unused warning
+ yield
+ if topotest_extra_config["valgrind_memleaks"]:
+ if get_topogen() is not None:
+ check_for_memleaks()
+
+
def pytest_runtest_logstart(nodeid, location):
# location is (filename, lineno, testname)
topolog.logstart(nodeid, location, topotest_extra_config["rundir"])
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_call(item: pytest.Item) -> None:
"Hook the function that is called to execute the test."
+ del item # disable unused warning
# For topology only run the CLI then exit
if topotest_extra_config["topology_only"]:
)
# (topogen) Set topology error to avoid advancing in the test.
- tgen = get_topogen()
+ tgen = get_topogen() # pylint: disable=redefined-outer-name
if tgen is not None:
# This will cause topogen to report error on `routers_have_failure`.
tgen.set_error("{}/{}".format(modname, item.name))
if user == "cli":
cli(Mininet.g_mnet_inst)
elif user == "pdb":
- pdb.set_trace()
+ pdb.set_trace() # pylint: disable=forgotten-debug-statement
elif user:
print('Unrecognized input: "%s"' % user)
else:
# Remove bgp configuration
router_dict.update({router: {"bgp": {"delete": True}}})
-
- new_topo[router]["bgp"]["local_as"] = input_dict[router]["bgp"]["local_as"]
-
+ try:
+ new_topo[router]["bgp"]["local_as"] = input_dict[router]["bgp"][
+ "local_as"
+ ]
+ except TypeError:
+ new_topo[router]["bgp"][0]["local_as"] = input_dict[router]["bgp"][
+ "local_as"
+ ]
logger.info("Removing bgp configuration")
create_router_bgp(tgen, topo, router_dict)
daemons.append("zebra")
if "pimd" in result:
daemons.append("pimd")
+ if "pim6d" in result:
+ daemons.append("pim6d")
if "ospfd" in result:
daemons.append("ospfd")
if "ospf6d" in result:
TopoRouter.RD_PIM, "{}/{}/pimd.conf".format(tgen.logdir, rname)
)
+ if daemon and "pim6d" in daemon:
+ # Loading empty pimd.conf file to router, to start the pim6d deamon
+ router.load_config(
+ TopoRouter.RD_PIM6, "{}/{}/pim6d.conf".format(tgen.logdir, rname)
+ )
+
# Starting routers
logger.info("Starting all routers once topology is created")
tgen.start_router()
for val in topo["routers"][rtr]["links"].values():
if "pim" in val and "pimd" not in daemon_list:
daemon_list.append("pimd")
+ if "pim6" in val and "pim6d" not in daemon_list:
+ daemon_list.append("pim6d")
if "ospf" in val and "ospfd" not in daemon_list:
daemon_list.append("ospfd")
if "ospf6" in val and "ospf6d" not in daemon_list:
return True
+def socat_send_igmp_join_traffic(
+ tgen,
+ server,
+ protocol_option,
+ igmp_groups,
+ send_from_intf,
+ send_from_intf_ip=None,
+ port=12345,
+ reuseaddr=True,
+ join=False,
+ traffic=False,
+):
+ """
+ API to send IGMP join using SOCAT tool
+
+ Parameters:
+ -----------
+ * `tgen` : Topogen object
+ * `server`: iperf server, from where IGMP join would be sent
+ * `protocol_option`: Protocol options, ex: UDP6-RECV
+ * `igmp_groups`: IGMP group for which join has to be sent
+ * `send_from_intf`: Interface from which join would be sent
+ * `send_from_intf_ip`: Interface IP, default is None
+ * `port`: Port to be used, default is 12345
+ * `reuseaddr`: True|False, bydefault True
+ * `join`: If join needs to be sent
+ * `traffic`: If traffic needs to be sent
+
+ returns:
+ --------
+ errormsg or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ rnode = tgen.routers()[server]
+ socat_cmd = "socat -u "
+
+ # UDP4/TCP4/UDP6/UDP6-RECV
+ if protocol_option:
+ socat_cmd += "{}".format(protocol_option)
+
+ if port:
+ socat_cmd += ":{},".format(port)
+
+ if reuseaddr:
+ socat_cmd += "{},".format("reuseaddr")
+
+ # Group address range to cover
+ if igmp_groups:
+ if not isinstance(igmp_groups, list):
+ igmp_groups = [igmp_groups]
+
+ for igmp_group in igmp_groups:
+ if join:
+ join_traffic_option = "ipv6-join-group"
+ elif traffic:
+ join_traffic_option = "ipv6-join-group-source"
+
+ if send_from_intf and not send_from_intf_ip:
+ socat_cmd += "{}='[{}]:{}'".format(
+ join_traffic_option, igmp_group, send_from_intf
+ )
+ else:
+ socat_cmd += "{}='[{}]:{}:[{}]'".format(
+ join_traffic_option, igmp_group, send_from_intf, send_from_intf_ip
+ )
+
+ socat_cmd += " STDOUT"
+
+ socat_cmd += " &>{}/socat.logs &".format(tgen.logdir)
+
+ # Run socat command to send IGMP join
+ logger.info("[DUT: {}]: Running command: [{}]".format(server, socat_cmd))
+ output = rnode.run("set +m; {} sleep 0.5".format(socat_cmd))
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
+
+
#############################################
# Verification APIs
#############################################
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):
self.cmd_raises("mkdir -p " + inner)
self.cmd_raises("mount --rbind {} {} ".format(outer, inner))
+ def add_vlan(self, vlanname, linkiface, vlanid):
+ self.logger.debug("Adding VLAN interface: %s (%s)", vlanname, vlanid)
+ ip_path = self.get_exec_path("ip")
+ assert ip_path, "XXX missing ip command!"
+ self.cmd_raises(
+ [
+ ip_path,
+ "link",
+ "add",
+ "link",
+ linkiface,
+ "name",
+ vlanname,
+ "type",
+ "vlan",
+ "id",
+ vlanid,
+ ]
+ )
+ self.cmd_raises([ip_path, "link", "set", "dev", vlanname, "up"])
+
+ def add_loop(self, loopname):
+ self.logger.debug("Adding Linux iface: %s", loopname)
+ ip_path = self.get_exec_path("ip")
+ assert ip_path, "XXX missing ip command!"
+ self.cmd_raises([ip_path, "link", "add", loopname, "type", "dummy"])
+ self.cmd_raises([ip_path, "link", "set", "dev", loopname, "up"])
+
+ def add_l3vrf(self, vrfname, tableid):
+ self.logger.debug("Adding Linux VRF: %s", vrfname)
+ ip_path = self.get_exec_path("ip")
+ assert ip_path, "XXX missing ip command!"
+ self.cmd_raises(
+ [ip_path, "link", "add", vrfname, "type", "vrf", "table", tableid]
+ )
+ self.cmd_raises([ip_path, "link", "set", "dev", vrfname, "up"])
+
+ def del_iface(self, iface):
+ self.logger.debug("Removing Linux Iface: %s", iface)
+ ip_path = self.get_exec_path("ip")
+ assert ip_path, "XXX missing ip command!"
+ self.cmd_raises([ip_path, "link", "del", iface])
+
+ def attach_iface_to_l3vrf(self, ifacename, vrfname):
+ self.logger.debug("Attaching Iface %s to Linux VRF %s", ifacename, vrfname)
+ ip_path = self.get_exec_path("ip")
+ assert ip_path, "XXX missing ip command!"
+ if vrfname:
+ self.cmd_raises(
+ [ip_path, "link", "set", "dev", ifacename, "master", vrfname]
+ )
+ else:
+ self.cmd_raises([ip_path, "link", "set", "dev", ifacename, "nomaster"])
+
def add_netns(self, ns):
self.logger.debug("Adding network namespace %s", ns)
InvalidCLIError,
retry,
run_frr_cmd,
+ validate_ip_address,
)
from lib.micronet import get_exec_path
from lib.topolog import logger
def create_pim_config(tgen, topo, input_dict=None, build=False, load_config=True):
"""
- API to configure pim on router
+ API to configure pim/pimv6 on router
Parameters
----------
"prefix-list": "pf_list_1"
"delete": True
}]
+ },
+ "pim6": {
+ "disable" : ["l1-i1-eth1"],
+ "rp": [{
+ "rp_addr" : "2001:db8:f::5:17".
+ "keep-alive-timer": "100"
+ "group_addr_range": ["FF00::/8"]
+ "prefix-list": "pf_list_1"
+ "delete": True
+ }]
}
}
}
# Now add RP config to all routers
for router in input_dict.keys():
- if "pim" not in input_dict[router]:
- continue
- if "rp" not in input_dict[router]["pim"]:
- continue
- _add_pim_rp_config(tgen, topo, input_dict, router, build, config_data_dict)
-
+ if "pim" in input_dict[router] or "pim6" in input_dict[router]:
+ _add_pim_rp_config(tgen, topo, input_dict, router, build, config_data_dict)
try:
result = create_common_configurations(
tgen, config_data_dict, "pim", build, load_config
"""
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+ rp_data = []
+
+ # PIMv4
+ pim_data = None
+ if "pim" in input_dict[router]:
+ pim_data = input_dict[router]["pim"]
+ if "rp" in input_dict[router]["pim"]:
+ rp_data += pim_data["rp"]
- pim_data = input_dict[router]["pim"]
- rp_data = pim_data["rp"]
+ # PIMv6
+ pim6_data = None
+ if "pim6" in input_dict[router]:
+ pim6_data = input_dict[router]["pim6"]
+ if "rp" in input_dict[router]["pim6"]:
+ rp_data += pim6_data["rp"]
# Configure this RP on every router.
for dut in tgen.routers():
# At least one interface must be enabled for PIM on the router
pim_if_enabled = False
+ pim6_if_enabled = False
for destLink, data in topo[dut]["links"].items():
if "pim" in data:
pim_if_enabled = True
- if not pim_if_enabled:
+ if "pim6" in data:
+ pim6_if_enabled = True
+ if not pim_if_enabled and pim_data:
+ continue
+ if not pim6_if_enabled and pim6_data:
continue
config_data = []
- for rp_dict in deepcopy(rp_data):
- # ip address of RP
- if "rp_addr" not in rp_dict and build:
- logger.error(
- "Router %s: 'ip address of RP' not " "present in input_dict/JSON",
- router,
- )
-
- return False
- rp_addr = rp_dict.setdefault("rp_addr", None)
-
- # Keep alive Timer
- keep_alive_timer = rp_dict.setdefault("keep_alive_timer", None)
-
- # Group Address range to cover
- if "group_addr_range" not in rp_dict and build:
- logger.error(
- "Router %s:'Group Address range to cover'"
- " not present in input_dict/JSON",
- router,
- )
-
- return False
- group_addr_range = rp_dict.setdefault("group_addr_range", None)
+ if rp_data:
+ for rp_dict in deepcopy(rp_data):
+ # ip address of RP
+ if "rp_addr" not in rp_dict and build:
+ logger.error(
+ "Router %s: 'ip address of RP' not "
+ "present in input_dict/JSON",
+ router,
+ )
- # Group prefix-list filter
- prefix_list = rp_dict.setdefault("prefix_list", None)
+ return False
+ rp_addr = rp_dict.setdefault("rp_addr", None)
+ if rp_addr:
+ addr_type = validate_ip_address(rp_addr)
+ # Keep alive Timer
+ keep_alive_timer = rp_dict.setdefault("keep_alive_timer", None)
+
+ # Group Address range to cover
+ if "group_addr_range" not in rp_dict and build:
+ logger.error(
+ "Router %s:'Group Address range to cover'"
+ " not present in input_dict/JSON",
+ router,
+ )
- # Delete rp config
- del_action = rp_dict.setdefault("delete", False)
+ return False
+ group_addr_range = rp_dict.setdefault("group_addr_range", None)
- if keep_alive_timer:
- cmd = "ip pim rp keep-alive-timer {}".format(keep_alive_timer)
- if del_action:
- cmd = "no {}".format(cmd)
- config_data.append(cmd)
+ # Group prefix-list filter
+ prefix_list = rp_dict.setdefault("prefix_list", None)
- if rp_addr:
- if group_addr_range:
- if type(group_addr_range) is not list:
- group_addr_range = [group_addr_range]
+ # Delete rp config
+ del_action = rp_dict.setdefault("delete", False)
- for grp_addr in group_addr_range:
- cmd = "ip pim rp {} {}".format(rp_addr, grp_addr)
+ if keep_alive_timer:
+ if addr_type == "ipv4":
+ cmd = "ip pim rp keep-alive-timer {}".format(keep_alive_timer)
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+ if addr_type == "ipv6":
+ cmd = "ipv6 pim rp keep-alive-timer {}".format(keep_alive_timer)
if del_action:
cmd = "no {}".format(cmd)
config_data.append(cmd)
- if prefix_list:
- cmd = "ip pim rp {} prefix-list {}".format(rp_addr, prefix_list)
- if del_action:
- cmd = "no {}".format(cmd)
- config_data.append(cmd)
+ if rp_addr:
+ if group_addr_range:
+ if type(group_addr_range) is not list:
+ group_addr_range = [group_addr_range]
- if config_data:
- if dut not in config_data_dict:
- config_data_dict[dut] = config_data
- else:
- config_data_dict[dut].extend(config_data)
+ for grp_addr in group_addr_range:
+ if addr_type == "ipv4":
+ cmd = "ip pim rp {} {}".format(rp_addr, grp_addr)
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+ if addr_type == "ipv6":
+ cmd = "ipv6 pim rp {} {}".format(rp_addr, grp_addr)
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ if prefix_list:
+ if addr_type == "ipv4":
+ cmd = "ip pim rp {} prefix-list {}".format(
+ rp_addr, prefix_list
+ )
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+ if addr_type == "ipv6":
+ cmd = "ipv6 pim rp {} prefix-list {}".format(
+ rp_addr, prefix_list
+ )
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ if config_data:
+ if dut not in config_data_dict:
+ config_data_dict[dut] = config_data
+ else:
+ config_data_dict[dut].extend(config_data)
def create_igmp_config(tgen, topo, input_dict=None, build=False):
return result
+def create_mld_config(tgen, topo, input_dict=None, build=False):
+ """
+ API to configure mld for PIMv6 on router
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `topo` : json file data
+ * `input_dict` : Input dict data, required when configuring from
+ testcase
+ * `build` : Only for initial setup phase this is set as True.
+
+ Usage
+ -----
+ input_dict = {
+ "r1": {
+ "mld": {
+ "interfaces": {
+ "r1-r0-eth0" :{
+ "mld":{
+ "version": "2",
+ "delete": True
+ "query": {
+ "query-interval" : 100,
+ "query-max-response-time": 200
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Returns
+ -------
+ True or False
+ """
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+ result = False
+ if not input_dict:
+ input_dict = deepcopy(topo)
+ else:
+ topo = topo["routers"]
+ input_dict = deepcopy(input_dict)
+ for router in input_dict.keys():
+ if "mld" not in input_dict[router]:
+ logger.debug("Router %s: 'mld' is not present in " "input_dict", router)
+ continue
+
+ mld_data = input_dict[router]["mld"]
+
+ if "interfaces" in mld_data:
+ config_data = []
+ intf_data = mld_data["interfaces"]
+
+ for intf_name in intf_data.keys():
+ cmd = "interface {}".format(intf_name)
+ config_data.append(cmd)
+ protocol = "mld"
+ del_action = intf_data[intf_name]["mld"].setdefault("delete", False)
+ cmd = "ipv6 mld"
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ del_attr = intf_data[intf_name]["mld"].setdefault("delete_attr", False)
+ join = intf_data[intf_name]["mld"].setdefault("join", None)
+ source = intf_data[intf_name]["mld"].setdefault("source", None)
+ version = intf_data[intf_name]["mld"].setdefault("version", False)
+ query = intf_data[intf_name]["mld"].setdefault("query", {})
+
+ if version:
+ cmd = "ipv6 {} version {}".format(protocol, version)
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ if source and join:
+ for group in join:
+ cmd = "ipv6 {} join {} {}".format(protocol, group, source)
+
+ if del_attr:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ elif join:
+ for group in join:
+ cmd = "ipv6 {} join {}".format(protocol, group)
+
+ if del_attr:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ if query:
+ for _query, value in query.items():
+ if _query != "delete":
+ cmd = "ipv6 {} {} {}".format(protocol, _query, value)
+
+ if "delete" in intf_data[intf_name][protocol]["query"]:
+ cmd = "no {}".format(cmd)
+
+ config_data.append(cmd)
+ try:
+ result = create_common_configuration(
+ tgen, router, config_data, "interface_config", build=build
+ )
+ except InvalidCLIError:
+ errormsg = traceback.format_exc()
+ logger.error(errormsg)
+ return errormsg
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return result
+
+
def _enable_disable_pim_config(tgen, topo, input_dict, router, build=False):
"""
Helper API to enable or disable pim on interfaces
config_data = []
- # Enable pim on interfaces
+ # Enable pim/pim6 on interfaces
for destRouterLink, data in sorted(topo[router]["links"].items()):
if "pim" in data and data["pim"] == "enable":
# Loopback interfaces
config_data.append(cmd)
config_data.append("ip pim")
+ if "pim6" in data and data["pim6"] == "enable":
+ # Loopback interfaces
+ if "type" in data and data["type"] == "loopback":
+ interface_name = destRouterLink
+ else:
+ interface_name = data["interface"]
+
+ cmd = "interface {}".format(interface_name)
+ config_data.append(cmd)
+ config_data.append("ipv6 pim")
+
# pim global config
if "pim" in input_dict[router]:
pim_data = input_dict[router]["pim"]
cmd = "no {}".format(cmd)
config_data.append(cmd)
+ # pim6 global config
+ if "pim6" in input_dict[router]:
+ pim6_data = input_dict[router]["pim6"]
+ del_action = pim6_data.setdefault("delete", False)
+ for t in [
+ "join-prune-interval",
+ "keep-alive-timer",
+ "register-suppress-time",
+ ]:
+ if t in pim6_data:
+ cmd = "ipv6 pim {} {}".format(t, pim6_data[t])
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
return config_data
"[DUT: %s]: Verifying upstream Inbound Interface" " for IGMP groups received:",
dut,
)
- show_ip_pim_upstream_json = run_frr_cmd(
- rnode, "show ip pim upstream json", isjson=True
- )
if type(group_addresses) is not list:
group_addresses = [group_addresses]
if type(iif) is not list:
iif = [iif]
+ for grp in group_addresses:
+ addr_type = validate_ip_address(grp)
+
+ if addr_type == "ipv4":
+ ip_cmd = "ip"
+ elif addr_type == "ipv6":
+ ip_cmd = "ipv6"
+
+ cmd = "show {} pim upstream json".format(ip_cmd)
+ show_ip_pim_upstream_json = run_frr_cmd(rnode, cmd, isjson=True)
+
for grp_addr in group_addresses:
# Verify group address
if grp_addr not in show_ip_pim_upstream_json:
"[DUT: %s]: Verifying Join state and Join Timer" " for IGMP groups received:",
dut,
)
- show_ip_pim_upstream_json = run_frr_cmd(
- rnode, "show ip pim upstream json", isjson=True
- )
if type(group_addresses) is not list:
group_addresses = [group_addresses]
+ for grp in group_addresses:
+ addr_type = validate_ip_address(grp)
+
+ if addr_type == "ipv4":
+ cmd = "show ip pim upstream json"
+ elif addr_type == "ipv6":
+ cmd = "show ipv6 pim upstream json"
+ show_ip_pim_upstream_json = run_frr_cmd(rnode, cmd, isjson=True)
+
for grp_addr in group_addresses:
# Verify group address
if grp_addr not in show_ip_pim_upstream_json:
rnode = tgen.routers()[dut]
+ if not isinstance(group_addresses, list):
+ group_addresses = [group_addresses]
+
+ if not isinstance(iif, list) and iif != "none":
+ iif = [iif]
+
+ if not isinstance(oil, list) and oil != "none":
+ oil = [oil]
+
+ for grp in group_addresses:
+ addr_type = validate_ip_address(grp)
+
+ if addr_type == "ipv4":
+ ip_cmd = "ip"
+ elif addr_type == "ipv6":
+ ip_cmd = "ipv6"
+
if return_uptime:
logger.info("Sleeping for %s sec..", mwait)
sleep(mwait)
logger.info("[DUT: %s]: Verifying ip mroutes", dut)
- show_ip_mroute_json = run_frr_cmd(rnode, "show ip mroute json", isjson=True)
+ show_ip_mroute_json = run_frr_cmd(
+ rnode, "show {} mroute json".format(ip_cmd), isjson=True
+ )
if return_uptime:
uptime_dict = {}
error_msg = "[DUT %s]: mroutes are not present or flushed out !!" % (dut)
return error_msg
- if not isinstance(group_addresses, list):
- group_addresses = [group_addresses]
-
- if not isinstance(iif, list) and iif != "none":
- iif = [iif]
-
- if not isinstance(oil, list) and oil != "none":
- oil = [oil]
-
for grp_addr in group_addresses:
if grp_addr not in show_ip_mroute_json:
errormsg = "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! " % (
rnode = tgen.routers()[dut]
- logger.info("[DUT: %s]: Verifying ip rp info", dut)
- show_ip_rp_info_json = run_frr_cmd(rnode, "show ip pim rp-info json", isjson=True)
-
if type(group_addresses) is not list:
group_addresses = [group_addresses]
if type(oif) is not list:
oif = [oif]
+ for grp in group_addresses:
+ addr_type = validate_ip_address(grp)
+
+ if addr_type == "ipv4":
+ ip_cmd = "ip"
+ elif addr_type == "ipv6":
+ ip_cmd = "ipv6"
+
for grp_addr in group_addresses:
if rp is None:
rp_details = find_rp_details(tgen, topo)
else:
iamRP = False
else:
- show_ip_route_json = run_frr_cmd(
- rnode, "show ip route connected json", isjson=True
- )
+ if addr_type == "ipv4":
+ show_ip_route_json = run_frr_cmd(
+ rnode, "show ip route connected json", isjson=True
+ )
+ elif addr_type == "ipv6":
+ show_ip_route_json = run_frr_cmd(
+ rnode, "show ipv6 route connected json", isjson=True
+ )
for _rp in show_ip_route_json.keys():
if rp == _rp.split("/")[0]:
iamRP = True
else:
iamRP = False
+ logger.info("[DUT: %s]: Verifying ip rp info", dut)
+ cmd = "show {} pim rp-info json".format(ip_cmd)
+ show_ip_rp_info_json = run_frr_cmd(rnode, cmd, isjson=True)
+
if rp not in show_ip_rp_info_json:
- errormsg = "[DUT %s]: Verifying rp-info" "for rp_address %s [FAILED]!! " % (
- dut,
- rp,
+ errormsg = (
+ "[DUT %s]: Verifying rp-info "
+ "for rp_address %s [FAILED]!! " % (dut, rp)
)
return errormsg
else:
group_addr_json = show_ip_rp_info_json[rp]
for rp_json in group_addr_json:
+ if "rpAddress" not in rp_json:
+ errormsg = "[DUT %s]: %s key not " "present in rp-info " % (
+ dut,
+ "rpAddress",
+ )
+ return errormsg
+
if oif is not None:
found = False
if rp_json["outboundInterface"] not in oif:
rnode = tgen.routers()[dut]
logger.info("[DUT: %s]: Verifying pim state", dut)
- show_pim_state_json = run_frr_cmd(rnode, "show ip pim state json", isjson=True)
-
- if installed_fl is None:
- installed_fl = 1
if type(group_addresses) is not list:
group_addresses = [group_addresses]
+ for grp in group_addresses:
+ addr_type = validate_ip_address(grp)
+
+ if addr_type == "ipv4":
+ ip_cmd = "ip"
+ elif addr_type == "ipv6":
+ ip_cmd = "ipv6"
+
+ logger.info("[DUT: %s]: Verifying pim state", dut)
+ show_pim_state_json = run_frr_cmd(
+ rnode, "show {} pim state json".format(ip_cmd), isjson=True
+ )
+
+ if installed_fl is None:
+ installed_fl = 1
+
for grp_addr in group_addresses:
if src_address is None:
src_address = "*"
return True
-def verify_pim_interface_traffic(tgen, input_dict, return_stats=True):
+def verify_pim_interface_traffic(tgen, input_dict, return_stats=True, addr_type="ipv4"):
"""
Verify ip pim interface traffice by running
"show ip pim interface traffic" cli
* `tgen`: topogen object
* `input_dict(dict)`: defines DUT, what and from which interfaces
traffic needs to be verified
+ * [optional]`addr_type`: specify address-family, default is ipv4
+
Usage
-----
input_dict = {
rnode = tgen.routers()[dut]
logger.info("[DUT: %s]: Verifying pim interface traffic", dut)
- show_pim_intf_traffic_json = run_frr_cmd(
- rnode, "show ip pim interface traffic json", isjson=True
- )
+
+ if addr_type == "ipv4":
+ cmd = "show ip pim interface traffic json"
+ elif addr_type == "ipv6":
+ cmd = "show ipv6 pim interface traffic json"
+
+ show_pim_intf_traffic_json = run_frr_cmd(rnode, cmd, isjson=True)
output_dict[dut] = {}
for intf, data in input_dict[dut].items():
RD_PBRD = 16
RD_PATH = 17
RD_SNMP = 18
+ RD_PIM6 = 19
RD = {
RD_FRR: "frr",
RD_ZEBRA: "zebra",
RD_ISIS: "isisd",
RD_BGP: "bgpd",
RD_PIM: "pimd",
+ RD_PIM6: "pim6d",
RD_LDP: "ldpd",
RD_EIGRP: "eigrpd",
RD_NHRP: "nhrpd",
Possible daemon values are: TopoRouter.RD_ZEBRA, TopoRouter.RD_RIP,
TopoRouter.RD_RIPNG, TopoRouter.RD_OSPF, TopoRouter.RD_OSPF6,
TopoRouter.RD_ISIS, TopoRouter.RD_BGP, TopoRouter.RD_LDP,
- TopoRouter.RD_PIM, TopoRouter.RD_PBR, TopoRouter.RD_SNMP.
+ TopoRouter.RD_PIM, TopoRouter.RD_PIM6, TopoRouter.RD_PBR,
+ TopoRouter.RD_SNMP.
Possible `source` values are `None` for an empty config file, a path name which is
used directly, or a file name with no path components which is first looked for
"ripngd",
"isisd",
"pimd",
+ "pim6d",
"ldpd",
"pbrd",
]:
number_to_column,
)
from lib.ospf import create_router_ospf
-from lib.pim import create_igmp_config, create_pim_config
+from lib.pim import (
+ create_igmp_config,
+ create_pim_config,
+ create_mld_config,
+)
from lib.topolog import logger
("route_maps", create_route_maps),
("pim", create_pim_config),
("igmp", create_igmp_config),
+ ("mld", create_mld_config),
("bgp", create_router_bgp),
("ospf", create_router_ospf),
]
logger.info("build_config_from_json: failed to configure topology")
pytest.exit(1)
- logger.info("Built config now clearing ospf neighbors as that router-id might not be what is used")
+ logger.info(
+ "Built config now clearing ospf neighbors as that router-id might not be what is used"
+ )
for ospf in ["ospf", "ospf6"]:
for router in data:
if ospf not in data[router]:
"isisd": 0,
"bgpd": 0,
"pimd": 0,
+ "pim6d": 0,
"ldpd": 0,
"eigrpd": 0,
"nhrpd": 0,
# Add static routes
input_dict = {
- fhr: {"static_routes": [{"network": bsr_route, "next_hop": next_hop}]},
rp: {"static_routes": [{"network": bsr_route, "next_hop": next_hop_rp}]},
lhr: {"static_routes": [{"network": bsr_route, "next_hop": next_hop_lhr}]},
}
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
# Verifying static routes are installed
- for dut, _nexthop in zip([fhr, rp, lhr], [next_hop, next_hop_rp, next_hop_lhr]):
+ for dut, _nexthop in zip([rp, lhr], [next_hop_rp, next_hop_lhr]):
input_routes = {dut: input_dict[dut]}
- result = verify_rib(tgen, "ipv4", dut, input_routes, _nexthop)
+ result = verify_rib(
+ tgen, "ipv4", dut, input_routes, _nexthop, protocol="static"
+ )
assert result is True, "Testcase {} : Failed \n Error {}".format(
tc_name, result
)
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
# Verifying static routes are installed
- result = verify_rib(tgen, "ipv4", fhr, input_dict, next_hop_fhr)
+ result = verify_rib(
+ tgen, "ipv4", fhr, input_dict, next_hop_fhr, protocol="static"
+ )
assert result is True, "Testcase {} : Failed \n Error {}".format(
tc_name, result
)
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
# Verifying static routes are installed
- result = verify_rib(tgen, "ipv4", lhr, input_dict, next_hop_lhr)
+ result = verify_rib(
+ tgen, "ipv4", lhr, input_dict, next_hop_lhr, protocol="static"
+ )
assert result is True, "Testcase {} : Failed \n Error {}".format(
tc_name, result
)
# Verifying static routes are installed
for dut, _nexthop in zip(["i1", "l1"], [next_hop_rp, next_hop_lhr]):
input_routes = {dut: input_dict[dut]}
- result = verify_rib(tgen, "ipv4", dut, input_routes, _nexthop)
+ result = verify_rib(
+ tgen, "ipv4", dut, input_routes, _nexthop, protocol="static"
+ )
assert result is True, "Testcase {} : Failed \n Error {}".format(
tc_name, result
)
input_routes = {
"f1": {"static_routes": [{"network": bsr_add, "next_hop": next_hop}]}
}
- result = verify_rib(tgen, "ipv4", "f1", input_routes, next_hop)
+ result = verify_rib(
+ tgen, "ipv4", "f1", input_routes, next_hop, protocol="static"
+ )
assert result is True, "Testcase {} : Failed \n Error {}".format(
tc_name, result
)
# Verifying static routes are installed
for dut, _nexthop in zip(["i1", "l1"], [next_hop_rp, next_hop_lhr]):
input_routes = {dut: input_dict[dut]}
- result = verify_rib(tgen, "ipv4", dut, input_routes, _nexthop)
+ result = verify_rib(
+ tgen, "ipv4", dut, input_routes, _nexthop, protocol="static"
+ )
assert result is True, "Testcase {} : Failed \n Error {}".format(
tc_name, result
)
input_routes = {
"f1": {"static_routes": [{"network": CRP, "next_hop": next_hop_fhr}]}
}
- result = verify_rib(tgen, "ipv4", "f1", input_routes, expected=False)
+ result = verify_rib(
+ tgen, "ipv4", "f1", input_routes, protocol="static", expected=False
+ )
assert (
result is not True
), "Testcase {} : Failed \n " "Route is still present \n Error {}".format(
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
# Verifying static routes are installed
- result = verify_rib(tgen, "ipv4", "f1", input_dict)
+ result = verify_rib(tgen, "ipv4", "f1", input_dict, protocol="static")
assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
intf_f1_i1 = topo["routers"]["f1"]["links"]["i1"]["interface"]
input_dict = {
"f1": {"static_routes": [{"network": BSR1_ADDR, "next_hop": NEXT_HOP1}]}
}
- result = verify_rib(tgen, "ipv4", "f1", input_dict, NEXT_HOP1)
+ result = verify_rib(tgen, "ipv4", "f1", input_dict, NEXT_HOP1, protocol="static")
assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
input_dict = {
]
}
}
- result = verify_rib(tgen, "ipv4", "f1", input_dict, expected=False)
+ result = verify_rib(
+ tgen, "ipv4", "f1", input_dict, protocol="static", expected=False
+ )
assert result is not True, (
"Testcase {} : Failed \n "
"Routes:[{}, {}] are still present \n Error {}".format(
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
# Verifying static routes are installed
- result = verify_rib(tgen, "ipv4", "l1", input_dict, expected=False)
+ result = verify_rib(
+ tgen, "ipv4", "l1", input_dict, protocol="static", expected=False
+ )
assert (
result is not True
), "Testcase {} : Failed \n " "Routes:{} are still present \n Error {}".format(
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
# Verifying static routes are installed
- result = verify_rib(tgen, "ipv4", "l1", input_dict, next_hop_lhr)
+ result = verify_rib(tgen, "ipv4", "l1", input_dict, next_hop_lhr, protocol="static")
assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result)
# Verify that (*,G) installed in mroute again
# Add static routes
input_dict = {
- fhr: {"static_routes": [{"network": bsr_route, "next_hop": next_hop}]},
rp: {"static_routes": [{"network": bsr_route, "next_hop": next_hop_rp}]},
lhr: {"static_routes": [{"network": bsr_route, "next_hop": next_hop_lhr}]},
}
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
# Verifying static routes are installed
- for dut, _nexthop in zip([fhr, rp, lhr], [next_hop, next_hop_rp, next_hop_lhr]):
+ for dut, _nexthop in zip([rp, lhr], [next_hop_rp, next_hop_lhr]):
input_routes = {dut: input_dict[dut]}
- result = verify_rib(tgen, "ipv4", dut, input_routes, _nexthop)
+ result = verify_rib(
+ tgen, "ipv4", dut, input_routes, _nexthop, protocol="static"
+ )
assert result is True, "Testcase {} : Failed \n Error {}".format(
tc_name, result
)
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
# Verifying static routes are installed
- result = verify_rib(tgen, "ipv4", fhr, input_dict, next_hop_fhr)
+ result = verify_rib(
+ tgen, "ipv4", fhr, input_dict, next_hop_fhr, protocol="static"
+ )
assert result is True, "Testcase {} : Failed \n Error {}".format(
tc_name, result
)
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
# Verifying static routes are installed
- result = verify_rib(tgen, "ipv4", lhr, input_dict, next_hop_lhr)
+ result = verify_rib(
+ tgen, "ipv4", lhr, input_dict, next_hop_lhr, protocol="static"
+ )
assert result is True, "Testcase {} : Failed \n Error {}".format(
tc_name, result
)
--- /dev/null
+{
+ "address_types": ["ipv6"],
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "r1": {"ipv6": "auto"}
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {"ipv6": "auto", "type": "loopback", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r0": {"ipv6": "auto", "pim6": "enable"},
+ "r2": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r3": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r4": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }}
+ },
+ "ospf6": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r2": {},
+ "r3": {},
+ "r4": {}
+ },
+ "redistribute": [
+ {
+ "redist_type": "static"
+ },
+ {
+ "redist_type": "connected"
+ }
+ ]
+ },
+ "mld": {
+ "interfaces": {
+ "r1-r0-eth0" :{
+ "mld":{
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {"ipv6": "auto", "type": "loopback", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r1": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r3": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }}
+ },
+ "ospf6": {
+ "router_id": "100.1.1.1",
+ "neighbors": {
+ "r1": {},
+ "r3": {}
+ },
+ "redistribute": [
+ {
+ "redist_type": "static"
+ },
+ {
+ "redist_type": "connected"
+ }
+ ]
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {"ipv6": "auto", "type": "loopback", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r1": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r2": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r4": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r5": {"ipv6": "auto", "pim6": "enable"}
+ },
+ "ospf6": {
+ "router_id": "100.1.1.2",
+ "neighbors": {
+ "r1": {},
+ "r2": {},
+ "r4": {}
+ },
+ "redistribute": [
+ {
+ "redist_type": "static"
+ },
+ {
+ "redist_type": "connected"
+ }
+ ]
+ }
+ },
+ "r4": {
+ "links": {
+ "lo": {"ipv6": "auto", "type": "loopback", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r1": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r3": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }}
+ },
+ "ospf6": {
+ "router_id": "100.1.1.3",
+ "neighbors": {
+ "r1": {},
+ "r3": {}
+ },
+ "redistribute": [
+ {
+ "redist_type": "static"
+ },
+ {
+ "redist_type": "connected"
+ }
+ ]
+ }
+ },
+ "r5": {
+ "links": {
+ "r3": {"ipv6": "auto"}
+ }
+ }
+ }
+}
write_test_footer(tc_name)
-def test_RP_configured_as_LHR_1_p1(request):
- """
- TC_21_1_P1: Verify OIF and RPF for (*,G) and (S,G) when static RP configure
- in LHR router
-
- Topology used:
- ________r2_____
- | |
- iperf | | iperf
- r0-----r1-------------r3-----r5
-
- r1 : LHR/RP
- r3 : FHR
- """
-
- tgen = get_topogen()
- tc_name = request.node.name
- write_test_header(tc_name)
-
- # Don"t run this test if we have any failure.
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- step("Creating configuration from JSON")
- reset_config_on_routers(tgen)
- app_helper.stop_all_hosts()
- clear_mroute(tgen)
- clear_pim_interface_traffic(tgen, TOPO)
-
- step("Enable IGMP on r1 interface")
- step("Configure RP on r1 (loopback interface) for the group range" " 224.0.0.0/4")
- step("Enable the PIM on all the interfaces of r1, r2, r3 and r4 routers")
- step("Send the IGMP join from r0")
- step("Send multicast traffic from r5")
-
- step("r1 , r2, r3, r4: Delete existing RP configuration" "configure r1(LHR) as RP")
- input_dict = {
- "r1": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- },
- "r2": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- },
- "r3": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- },
- "r4": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- },
- }
-
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Configure r1(LHR) as RP")
- input_dict = {
- "r1": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.1.17",
- "group_addr_range": GROUP_RANGE_ALL,
- }
- ]
- }
- },
- "r2": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.1.17",
- "group_addr_range": GROUP_RANGE_ALL,
- }
- ]
- }
- },
- "r3": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.1.17",
- "group_addr_range": GROUP_RANGE_ALL,
- }
- ]
- }
- },
- "r4": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.1.17",
- "group_addr_range": GROUP_RANGE_ALL,
- }
- ]
- }
- },
- }
-
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- shutdown_bringup_interface(tgen, "r1", "lo", False)
- sleep(5)
- shutdown_bringup_interface(tgen, "r1", "lo", True)
- sleep(5)
-
- step("r1: Verify RP info")
- dut = "r1"
- rp_address = "1.0.1.17"
- iif = "lo"
- result = verify_pim_rp_info(
- tgen, TOPO, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r0: Send IGMP join")
- result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify IGMP groups")
- oif = "r1-r0-eth0"
- result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r5: Send multicast traffic for group 225.1.1.1")
- result = app_helper.run_traffic("r5", GROUP_ADDRESS, "r3")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream IIF interface")
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) ip mroutes")
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream IIF interface")
- iif = "r1-r3-eth2"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) ip mroutes")
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream IIF interface")
- dut = "r3"
- iif = "r3-r5-eth3"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r3: (S, G) upstream join state is joined and join"
- " timer is running \n Error: {}".format(tc_name, result)
- )
-
- step("r3: Verify (S, G) ip mroutes")
- oif = "r3-r1-eth0"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- # Uncomment next line for debugging
- # tgen.mininet_cli()
-
- write_test_footer(tc_name)
-
-
-def test_RP_configured_as_LHR_2_p1(request):
- """
- TC_21_2_P1: Verify OIF and RPF for (*,G) and (S,G) when static RP configure
- in LHR router
-
- Topology used:
- ________r2_____
- | |
- iperf | | iperf
- r0-----r1-------------r3-----r5
-
- r1 : LHR/RP
- r3 : FHR
-
- """
- tgen = get_topogen()
- tc_name = request.node.name
- write_test_header(tc_name)
-
- # Don"t run this test if we have any failure.
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- step("Creating configuration from JSON")
- reset_config_on_routers(tgen)
- app_helper.stop_all_hosts()
- clear_mroute(tgen)
- clear_pim_interface_traffic(tgen, TOPO)
-
- step("Enable IGMP on r1 interface")
- step("Configure RP on r1 (loopback interface) for the group range" " 224.0.0.0/4")
- step("Enable the PIM on all the interfaces of r1, r2, r3 and r4 routers")
- step("Send multicast traffic from r5")
- step("Send the IGMP join from r0")
-
- step("r1, r2, r3, r4: Delete existing RP configuration," "configure r1(LHR) as RP")
- input_dict = {
- "r1": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- },
- "r2": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- },
- "r3": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- },
- "r4": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- },
- }
-
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1, r2, r3, r4: Configure r1(LHR) as RP")
- input_dict = {
- "r1": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.1.17",
- "group_addr_range": GROUP_RANGE_ALL,
- }
- ]
- }
- },
- "r2": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.1.17",
- "group_addr_range": GROUP_RANGE_ALL,
- }
- ]
- }
- },
- "r3": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.1.17",
- "group_addr_range": GROUP_RANGE_ALL,
- }
- ]
- }
- },
- "r4": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.1.17",
- "group_addr_range": GROUP_RANGE_ALL,
- }
- ]
- }
- },
- }
-
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify RP info")
- dut = "r1"
- rp_address = "1.0.1.17"
- iif = "lo"
- result = verify_pim_rp_info(tgen, TOPO, dut, GROUP_ADDRESS, iif, rp_address, SOURCE)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r5: Send multicast traffic for group 225.1.1.1")
- result = app_helper.run_traffic("r5", GROUP_ADDRESS, "r3")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r0: Send IGMP join")
- result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify IGMP groups")
- oif = "r1-r0-eth0"
- result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream IIF interface")
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) ip mroutes")
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream IIF interface")
- iif = "r1-r3-eth2"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) ip mroutes")
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream IIF interface")
- dut = "r3"
- iif = "r3-r5-eth3"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r3: Verify (S, G) ip mroutes")
- oif = "r3-r1-eth0"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- # Uncomment next line for debugging
- # tgen.mininet_cli()
-
- write_test_footer(tc_name)
-
-
-def test_RP_configured_as_FHR_1_p1(request):
- """
- TC_22_1_P1: Verify OIF and RFP for (*,G) and (S,G) when static RP configure
- in FHR router
-
- Topology used:
- ________r2_____
- | |
- iperf | | iperf
- r0-----r1-------------r3-----r5
-
- r1 : LHR
- r3 : FHR/RP
- """
-
- tgen = get_topogen()
- tc_name = request.node.name
- write_test_header(tc_name)
-
- # Don"t run this test if we have any failure.
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- step("Creating configuration from JSON")
- reset_config_on_routers(tgen)
- app_helper.stop_all_hosts()
- clear_mroute(tgen)
- clear_pim_interface_traffic(tgen, TOPO)
-
- step("Enable IGMP on r1 interface")
- step("Configure RP on r2 (loopback interface) for the group range" " 225.1.1.0/24")
- step("Enable the PIM on all the interfaces of r1, r2, r3 and r4 routers")
- step("Send the IGMP join from r0")
- step("Send multicast traffic from r5")
-
- step("r1, r2, r3, r4: Delete existing RP configuration" "configure r3(FHR) as RP")
- input_dict = {
- "r1": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- },
- "r2": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- },
- "r3": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- },
- "r4": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- },
- }
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1, r2, r3, r4: Configure r3(FHR) as RP")
- input_dict = {
- "r1": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.3.17",
- "group_addr_range": GROUP_RANGE_ALL,
- }
- ]
- }
- },
- "r2": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.3.17",
- "group_addr_range": GROUP_RANGE_ALL,
- }
- ]
- }
- },
- "r3": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.3.17",
- "group_addr_range": GROUP_RANGE_ALL,
- }
- ]
- }
- },
- "r4": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.3.17",
- "group_addr_range": GROUP_RANGE_ALL,
- }
- ]
- }
- },
- }
-
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify RP info")
- dut = "r1"
- rp_address = "1.0.3.17"
- iif = "r1-r3-eth2"
- result = verify_pim_rp_info(
- tgen, TOPO, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r0: Send IGMP join")
- result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r0: Verify IGMP groups")
- oif = "r1-r0-eth0"
- result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r5: Send multicast traffic for group 225.1.1.1")
- result = app_helper.run_traffic("r5", GROUP_ADDRESS, "r3")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream IIF interface")
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) ip mroutes")
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream IIF interface")
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) ip mroutes")
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream IIF interface")
- dut = "r3"
- iif = "r3-r5-eth3"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r3: Verify (S, G) ip mroutes")
- oif = "r3-r1-eth0"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- # Uncomment next line for debugging
- # tgen.mininet_cli()
-
- write_test_footer(tc_name)
-
-
-def test_RP_configured_as_FHR_2_p2(request):
- """
- TC_22_2_P2: Verify OIF and RFP for (*,G) and (S,G) when static RP configure
- in FHR router
-
- Topology used:
- ________r2_____
- | |
- iperf | | iperf
- r0-----r1-------------r3-----r5
-
- r1 : LHR
- r3 : FHR/RP
- """
- tgen = get_topogen()
- tc_name = request.node.name
- write_test_header(tc_name)
-
- # Don"t run this test if we have any failure.
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- step("Creating configuration from JSON")
- reset_config_on_routers(tgen)
- app_helper.stop_all_hosts()
- clear_mroute(tgen)
- clear_pim_interface_traffic(tgen, TOPO)
-
- step("Enable IGMP on r1 interface")
- step("Configure RP on r2 (loopback interface) for the group range" " 225.1.1.0/24")
- step("Enable the PIM on all the interfaces of r1, r2, r3 and r4 routers")
- step("Send multicast traffic from r5")
- step("Send the IGMP join from r0")
-
- step("r1, r2, r3, r4: Delete existing RP configuration" "configure r3(FHR) as RP")
- input_dict = {
- "r1": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- },
- "r2": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- },
- "r3": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- },
- "r4": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- },
- }
-
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1, r2, r3, r4: Configure r3(FHR) as RP")
- input_dict = {
- "r1": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.3.17",
- "group_addr_range": GROUP_RANGE_ALL,
- }
- ]
- }
- },
- "r2": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.3.17",
- "group_addr_range": GROUP_RANGE_ALL,
- }
- ]
- }
- },
- "r3": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.3.17",
- "group_addr_range": GROUP_RANGE_ALL,
- }
- ]
- }
- },
- "r4": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.3.17",
- "group_addr_range": GROUP_RANGE_ALL,
- }
- ]
- }
- },
- }
-
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify RP info")
- dut = "r1"
- rp_address = "1.0.3.17"
- iif = "r1-r3-eth2"
- result = verify_pim_rp_info(
- tgen, TOPO, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r5: Send multicast traffic for group 225.1.1.1")
- result = app_helper.run_traffic("r5", GROUP_ADDRESS, "r3")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r0: Send IGMP join")
- result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r0: Verify IGMP groups")
- oif = "r1-r0-eth0"
- result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream IIF interface")
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) ip mroutes")
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream IIF interface")
- iif = "r1-r3-eth2"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) ip mroutes")
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream IIF interface")
- dut = "r3"
- iif = "r3-r5-eth3"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r3: Verify (S, G) ip mroutes")
- oif = "r3-r1-eth0"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- # Uncomment next line for debugging
- # tgen.mininet_cli()
-
- write_test_footer(tc_name)
-
-
-def test_SPT_RPT_path_different_p1(request):
- """
- TC_23_P1: Verify (*,G) and (S,G) populated correctly when RPT and SPT path
- are different
-
- Topology used:
- ________r2_____
- | |
- iperf | | iperf
- r0-----r1-------------r3-----r5
-
- r1: LHR
- r2: RP
- r3: FHR
- """
-
- tgen = get_topogen()
- tc_name = request.node.name
- write_test_header(tc_name)
-
- # Don"t run this test if we have any failure.
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- step("Creating configuration from JSON")
- reset_config_on_routers(tgen)
- app_helper.stop_all_hosts()
- clear_mroute(tgen)
- clear_pim_interface_traffic(tgen, TOPO)
-
- step("Enable IGMP on r1 interface and send IGMP join (225.1.1.1) to r1")
- step("Configure RP on r2 (loopback interface) for the group range" " 224.0.0.0/4")
- step("Enable the PIM on all the interfaces of r1, r2, r3 and r4 routers")
- step("Send multicast traffic from r3")
-
- step("r2: Verify RP info")
- dut = "r2"
- rp_address = "1.0.2.17"
- iif = "lo"
- result = verify_pim_rp_info(tgen, TOPO, dut, GROUP_ADDRESS, iif, rp_address, SOURCE)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r0: Send IGMP join")
- result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify IGMP groups")
- dut = "r1"
- oif = "r1-r0-eth0"
- result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r5: Send multicast traffic for group 225.1.1.1")
- result = app_helper.run_traffic("r5", GROUP_ADDRESS, "r3")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream IIF interface")
- iif = "r1-r2-eth1"
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) ip mroutes")
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream IIF interface")
- iif = "r1-r3-eth2"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) ip mroutes")
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) upstream IIF interface")
- dut = "r2"
- iif = "lo"
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) ip mroutes")
- oif = "r2-r1-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream IIF interface")
- dut = "r3"
- iif = "r3-r5-eth3"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r3: Verify (S, G) ip mroutes")
- oif = "r3-r1-eth0"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (S, G) upstream IIF interface")
- dut = "r2"
- iif = "r2-r3-eth1"
- result = verify_upstream_iif(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, joinState="NotJoined"
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r2: Verify (S, G) ip mroutes")
- oif = "none"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- # Uncomment next line for debugging
- # tgen.mininet_cli()
-
- write_test_footer(tc_name)
-
-
-def test_clear_pim_configuration_p1(request):
- """
- TC_25_P1: Verify (*,G) and (S,G) populated correctly after clearing the
- PIM,IGMP and mroutes joins
-
- Topology used:
- ________r2_____
- | |
- iperf | | iperf
- r0-----r1-------------r3-----r5
- | |
- |_____________|
- r4
- r1 : LHR
- r2 : RP
- r3 : FHR
- """
-
- tgen = get_topogen()
- tc_name = request.node.name
- write_test_header(tc_name)
-
- # Don"t run this test if we have any failure.
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- step("Creating configuration from JSON")
- reset_config_on_routers(tgen)
- app_helper.stop_all_hosts()
- clear_mroute(tgen)
- clear_pim_interface_traffic(tgen, TOPO)
-
- step("Enable IGMP on r1 interface")
- step("Configure RP on r2 (loopback interface) for the group range" " 224.0.0.0/4")
- step("Enable the PIM on all the interfaces of r1, r2, r3 and r4 routers")
- step("Send the IGMP join from r0")
- step("Send multicast traffic from r5")
-
- step("r2: Verify RP info")
- dut = "r2"
- rp_address = "1.0.2.17"
- oif = "lo"
- result = verify_pim_rp_info(
- tgen, TOPO, dut, GROUP_RANGE_ALL, oif, rp_address, SOURCE
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r0: Send IGMP join")
- result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify IGMP groups")
- dut = "r1"
- iif = "r1-r0-eth0"
- result = verify_igmp_groups(tgen, dut, iif, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r5: Send multicast traffic for group 225.1.1.1")
- result = app_helper.run_traffic("r5", GROUP_ADDRESS, "r3")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream IIF interface")
- dut = "r1"
- iif = "r1-r2-eth1"
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) ip mroutes")
- oif = "r1-r0-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify IGMP groups timer restarted")
- result = clear_igmp_interfaces(tgen, dut)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify PIM neighbor timer restarted")
- result = clear_pim_interfaces(tgen, dut)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify PIM mroute timer restarted")
- result = clear_mroute_verify(tgen, dut)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- # Uncomment next line for debugging
- # tgen.mininet_cli()
-
- write_test_footer(tc_name)
-
-
-def test_restart_pimd_process_p2(request):
- """
- TC_26_P2: Restart the PIMd process and verify PIM upstream and mroutes
- entries
- Topology used:
- ________r2_____
- | |
- iperf | | iperf
- r0-----r1-------------r3-----r5
- | |
- |_____________|
- r4
- r1 : LHR
- r2 : RP
- r3 : FHR
- """
-
- tgen = get_topogen()
- tc_name = request.node.name
- write_test_header(tc_name)
-
- # Don"t run this test if we have any failure.
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- step("Creating configuration from JSON")
- reset_config_on_routers(tgen)
- app_helper.stop_all_hosts()
- clear_mroute(tgen)
- clear_pim_interface_traffic(tgen, TOPO)
-
- step("Enable IGMP on r1 interface and send IGMP join (225.1.1.1) to R1")
- step("Configure RP on r3 (loopback interface) for the group range" " 224.0.0.0/4")
- step("Enable the PIM on all the interfaces of r1, r2, r3 and r4 routers")
- step("Send multicast traffic from R3")
- step("Restart the PIMd process")
-
- step("r2: Verify RP info")
- dut = "r2"
- rp_address = "1.0.2.17"
- oif = "lo"
- result = verify_pim_rp_info(
- tgen, TOPO, dut, GROUP_RANGE_ALL, oif, rp_address, SOURCE
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r0: Send IGMP join")
- result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify IGMP groups")
- dut = "r1"
- oif = "r1-r0-eth0"
- result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r5: Send multicast traffic for group 225.1.1.1")
- result = app_helper.run_traffic("r5", GROUP_ADDRESS, "r3")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream IIF interface")
- iif = "r1-r2-eth1"
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) ip mroutes")
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream IIF interface")
- iif = "r1-r3-eth2"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) ip mroutes")
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) upstream IIF interface")
- dut = "r2"
- iif = "lo"
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) ip mroutes")
- oif = "r2-r1-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream IIF interface")
- dut = "r3"
- iif = "r3-r5-eth3"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r3: Verify (S, G) ip mroutes")
- oif = "r3-r1-eth0"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- dut = "r1"
- iif = "r1-r2-eth1"
- oil = "r1-r0-eth0"
- logger.info("waiting for 10 sec to make sure old mroute time is higher")
- sleep(10)
- # Why do we then wait 60 seconds below before checking the routes?
- uptime_before = verify_mroutes(
- tgen, dut, STAR, GROUP_ADDRESS, iif, oil, return_uptime=True, mwait=60
- )
- assert isinstance(uptime_before, dict), "Testcase{} : Failed Error: {}".format(
- tc_name, result
- )
-
- step("r1: Kill pimd process")
- kill_router_daemons(tgen, "r1", ["pimd"])
-
- step("r1 : Start pimd process")
- start_router_daemons(tgen, "r1", ["pimd"])
-
- logger.info("Waiting for 5sec to get PIMd restarted and mroute" " re-learned..")
- sleep(5)
-
- # Why do we then wait 10 seconds below before checking the routes?
- uptime_after = verify_mroutes(
- tgen, dut, STAR, GROUP_ADDRESS, iif, oil, return_uptime=True, mwait=10
- )
- assert isinstance(uptime_after, dict), "Testcase{} : Failed Error: {}".format(
- tc_name, result
- )
-
- result = verify_mroute_repopulated(uptime_before, uptime_after)
- assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
-
- write_test_footer(tc_name)
-
-
-def test_multiple_groups_same_RP_address_p2(request):
- """
- TC_27_P2: Configure multiple groups (10 grps) with same RP address
-
- Topology used:
- ________r2_____
- | |
- iperf | | iperf
- r0-----r1-------------r3-----r5
-
- r1 : LHR
- r2 : RP
- r3 : FHR
- """
-
- tgen = get_topogen()
- tc_name = request.node.name
- write_test_header(tc_name)
-
- # Don"t run this test if we have any failure.
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- step("Creating configuration from JSON")
- reset_config_on_routers(tgen)
- app_helper.stop_all_hosts()
- clear_mroute(tgen)
- clear_pim_interface_traffic(tgen, TOPO)
-
- step("Enable IGMP on r1 interface and send IGMP join (225.1.1.1) to r1")
- step("Configure RP on r2 (loopback interface) for the group range" "225.1.1.0/24")
- step("Enable the PIM on all the interfaces of r1-r2-r3")
- step("Send multicast traffic from r5 to all the groups")
- step("r1 : Remove the groups to RP mapping one by one")
- step("r1: Shut the upstream interfaces")
- step("r1: No shut the upstream interfaces")
- step("r1: Configure the RP again")
- step("r1: Shut the receiver interfaces")
- step("r1: No Shut the receiver interfaces")
- step("r2: Verify RP info")
-
- step("r2: verify rp-info")
- dut = "r2"
- rp_address = "1.0.2.17"
- oif = "lo"
- result = verify_pim_rp_info(
- tgen, TOPO, dut, GROUP_RANGE_ALL, oif, rp_address, SOURCE
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- group_address_list = GROUP_ADDRESS_LIST_1 + GROUP_ADDRESS_LIST_2
- step("r0: Send IGMP join for 10 groups")
- result = app_helper.run_join("r0", group_address_list, "r1")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify IGMP groups")
- dut = "r1"
- oif = "r1-r0-eth0"
- result = verify_igmp_groups(tgen, dut, oif, group_address_list)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r5: Send multicast traffic for group 225.1.1.1")
- result = app_helper.run_traffic("r5", group_address_list, "r3")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream IIF interface")
- dut = "r1"
- iif = "r1-r2-eth1"
- result = verify_upstream_iif(tgen, dut, iif, STAR, group_address_list)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, group_address_list)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) ip mroutes")
- oif = "r1-r0-eth0"
- result = verify_mroutes(tgen, dut, STAR, group_address_list, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream IIF interface")
- iif = "r1-r3-eth2"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, group_address_list)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, group_address_list
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) ip mroutes")
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, group_address_list, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) upstream IIF interface")
- dut = "r2"
- iif = "lo"
- result = verify_upstream_iif(tgen, dut, iif, STAR, group_address_list)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, group_address_list)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) ip mroutes")
- oif = "r2-r1-eth0"
- result = verify_mroutes(tgen, dut, STAR, group_address_list, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream IIF interface")
- dut = "r3"
- iif = "r3-r5-eth3"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, group_address_list)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, group_address_list, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r3: Verify (S, G) ip mroutes")
- oif = "r3-r1-eth0"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, group_address_list, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (S, G) upstream IIF interface")
- dut = "r2"
- iif = "r2-r3-eth1"
- result = verify_upstream_iif(
- tgen, dut, iif, SOURCE_ADDRESS, group_address_list, joinState="NotJoined"
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, group_address_list, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r2: Verify (S, G) ip mroutes")
- oif = "none"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, group_address_list, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Delete RP configuration")
- input_dict = {
- "r1": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- }
- }
-
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Shut the interface r1-r2-eth1 from R1 to R2")
- dut = "r1"
- intf = "r1-r2-eth1"
- shutdown_bringup_interface(tgen, dut, intf, False)
-
- step("r1: No Shut the interface r1-r2-eth1 from R1 to R2")
- intf = "r1-r2-eth1"
- shutdown_bringup_interface(tgen, dut, intf, True)
-
- step("r1: Configure RP")
- input_dict = {
- "r1": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- }
- ]
- }
- }
- }
-
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Shut the interface r1-r0-eth0 from R1 to R2")
- intf = "r1-r0-eth0"
- shutdown_bringup_interface(tgen, dut, intf, False)
-
- step("r1: No Shut the interface r1-r0-eth0 from R1 to R2")
- intf = "r1-r0-eth0"
- shutdown_bringup_interface(tgen, dut, intf, True)
-
- step("r1: Verify (*, G) upstream IIF interface")
- dut = "r1"
- iif = "r1-r2-eth1"
- result = verify_upstream_iif(tgen, dut, iif, STAR, group_address_list)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, group_address_list)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) ip mroutes")
- oif = "r1-r0-eth0"
- result = verify_mroutes(tgen, dut, STAR, group_address_list, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream IIF interface")
- iif = "r1-r3-eth2"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, group_address_list)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, group_address_list
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) ip mroutes")
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, group_address_list, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) upstream IIF interface")
- dut = "r2"
- iif = "lo"
- result = verify_upstream_iif(tgen, dut, iif, STAR, group_address_list)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, group_address_list)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) ip mroutes")
- oif = "r2-r1-eth0"
- result = verify_mroutes(tgen, dut, STAR, group_address_list, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (S, G) upstream IIF interface")
- dut = "r2"
- iif = "r2-r3-eth1"
- result = verify_upstream_iif(
- tgen, dut, iif, SOURCE_ADDRESS, group_address_list, joinState="NotJoined"
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, group_address_list, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r2: Verify (S, G) ip mroutes")
- oif = "none"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, group_address_list, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream IIF interface")
- dut = "r3"
- iif = "r3-r5-eth3"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, group_address_list)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, group_address_list, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r3: Verify (S, G) ip mroutes")
- oif = "r3-r1-eth0"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, group_address_list, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- write_test_footer(tc_name)
-
-
-def test_multiple_groups_different_RP_address_p2(request):
- """
- TC_28_P2: Verify IIF and OIL in updated in mroute when upstream interface
- configure as RP
-
- Topology used:
- ________r2_____
- | |
- iperf | | iperf
- r0-----r1-------------r3-----r5
- | |
- |_____________|
- r4
- r1 : LHR
- r2 & r4 : RP
- r3 : FHR
- """
-
- tgen = get_topogen()
- tc_name = request.node.name
- write_test_header(tc_name)
-
- # Don"t run this test if we have any failure.
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- step("Creating configuration from JSON")
- reset_config_on_routers(tgen)
- app_helper.stop_all_hosts()
- clear_mroute(tgen)
- clear_pim_interface_traffic(tgen, TOPO)
-
- step("Delete existing RP configuration")
- input_dict = {
- "r2": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- }
- }
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- input_dict = {
- "r2": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_LIST_1,
- }
- ]
- }
- },
- "r4": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.4.17",
- "group_addr_range": GROUP_RANGE_LIST_2,
- }
- ]
- }
- },
- }
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify RP info")
- dut = "r2"
- rp_address = "1.0.2.17"
- oif = "lo"
- result = verify_pim_rp_info(
- tgen, TOPO, dut, GROUP_RANGE_LIST_1, oif, rp_address, SOURCE
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r4: Verify RP info")
- dut = "r4"
- rp_address = "1.0.4.17"
- result = verify_pim_rp_info(
- tgen, TOPO, dut, GROUP_RANGE_LIST_2, oif, rp_address, SOURCE
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- group_address_list = GROUP_ADDRESS_LIST_1 + GROUP_ADDRESS_LIST_2
- step("r0: Send IGMP join")
- result = app_helper.run_join("r0", group_address_list, "r1")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify IGMP groups")
- dut = "r1"
- oif = "r1-r0-eth0"
- result = verify_igmp_groups(tgen, dut, oif, group_address_list)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r5: Send multicast traffic for group 225.1.1.1")
- result = app_helper.run_traffic("r5", group_address_list, "r3")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream IIF interface")
- dut = "r1"
- iif = "r1-r2-eth1"
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) ip mroutes")
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_1, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream IIF interface")
- iif = "r1-r3-eth2"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) ip mroutes")
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) upstream IIF interface")
- dut = "r2"
- iif = "lo"
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) ip mroutes")
- oif = "r2-r1-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_1, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (S, G) upstream IIF interface")
- iif = "r2-r3-eth1"
- result = verify_upstream_iif(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, joinState="NotJoined"
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r2: Verify (S, G) ip mroutes")
- oif = "none"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream IIF interface")
- dut = "r3"
- iif = "r3-r5-eth3"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r3: Verify (S, G) ip mroutes")
- oif = "r3-r1-eth0"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream IIF interface")
- dut = "r1"
- iif = "r1-r4-eth3"
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) ip mroutes")
- oif = "r1-r0-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_2, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream IIF interface")
- iif = "r1-r3-eth2"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) ip mroutes")
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r4: Verify (*, G) upstream IIF interface")
- dut = "r4"
- iif = "lo"
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r4: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r4: Verify (*, G) ip mroutes")
- oif = "r4-r1-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_2, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r4: Verify (S, G) upstream IIF interface")
- iif = "r4-r3-eth1"
- result = verify_upstream_iif(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, joinState="NotJoined"
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r4: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r4: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r4: Verify (S, G) ip mroutes")
- oif = "none"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream IIF interface")
- dut = "r3"
- iif = "r3-r5-eth3"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False
- )
- assert result is not True, "Testcase {} :Failed \n Error: {}".format(
- tc_name, result
- )
-
- step("r3: Verify (S, G) ip mroutes")
- oif = "r3-r1-eth0"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("Delete RP configuration")
- input_dict = {
- "r2": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_LIST_1,
- "delete": True,
- }
- ]
- }
- },
- "r4": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.4.17",
- "group_addr_range": GROUP_RANGE_LIST_2,
- "delete": True,
- }
- ]
- }
- },
- }
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1, r2, r3, r4: Re-configure RP")
- input_dict = {
- "r2": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_LIST_1,
- }
- ]
- }
- },
- "r4": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.4.17",
- "group_addr_range": GROUP_RANGE_LIST_2,
- }
- ]
- }
- },
- }
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Shut the interface r1-r2-eth1 from R1 to R2")
- dut = "r1"
- intf = "r1-r2-eth1"
- shutdown_bringup_interface(tgen, dut, intf, False)
-
- step("r1: No shut the interface r1-r2-eth1 from R1 to R2")
- dut = "r1"
- intf = "r1-r2-eth1"
- shutdown_bringup_interface(tgen, dut, intf, True)
-
- step("r1: Shut the interface r1-r2-eth1 from R1 to R4")
- dut = "r1"
- intf = "r1-r4-eth3"
- shutdown_bringup_interface(tgen, dut, intf, False)
-
- step("r1: No shut the interface r1-r2-eth1 from R1 to r4")
- dut = "r1"
- intf = "r1-r4-eth3"
- shutdown_bringup_interface(tgen, dut, intf, True)
-
- step("r1: Shut the interface r1-r0-eth0 from R1 to R0")
- dut = "r1"
- intf = "r1-r0-eth0"
- shutdown_bringup_interface(tgen, dut, intf, False)
-
- step("r1: No Shut the interface r1-r0-eth0 from R1 to R0")
- dut = "r1"
- intf = "r1-r0-eth0"
- shutdown_bringup_interface(tgen, dut, intf, True)
-
- step("r1: Verify (*, G) upstream IIF interface")
- dut = "r1"
- iif = "r1-r2-eth1"
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) ip mroutes")
- oif = "r1-r0-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_1, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream IIF interface")
- iif = "r1-r3-eth2"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) ip mroutes")
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) upstream IIF interface")
- dut = "r2"
- iif = "lo"
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) ip mroutes")
- oif = "r2-r1-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_1, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (S, G) upstream IIF interface")
- iif = "r2-r3-eth1"
- result = verify_upstream_iif(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, joinState="NotJoined"
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r2: Verify (S, G) ip mroutes")
- oif = "none"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream IIF interface")
- dut = "r3"
- iif = "r3-r5-eth3"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r3: Verify (S, G) ip mroutes")
- oif = "r3-r1-eth0"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream IIF interface")
- dut = "r1"
- iif = "r1-r4-eth3"
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) ip mroutes")
- oif = "r1-r0-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_2, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream IIF interface")
- iif = "r1-r3-eth2"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (S, G) ip mroutes")
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r4: Verify (*, G) upstream IIF interface")
- dut = "r4"
- iif = "lo"
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r4: Verify (*, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r4: Verify (*, G) ip mroutes")
- oif = "r4-r1-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_2, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r4: Verify (S, G) upstream IIF interface")
- iif = "r4-r3-eth1"
- result = verify_upstream_iif(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, joinState="NotJoined"
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r4: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r4: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r4: Verify (S, G) ip mroutes")
- oif = "none"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream IIF interface")
- dut = "r3"
- iif = "r3-r5-eth3"
- result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r3: Verify (S, G) ip mroutes")
- oif = "r3-r1-eth0"
- result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- write_test_footer(tc_name)
-
-
-def test_shutdown_primary_path_p1(request):
- """
- TC_30_P1: Verify IIF and OIL change to other path after shut the primary
- path
-
- Topology used:
- ________r2_____
- | |
- iperf | |
- r0-----r1-------------r3
- """
-
- tgen = get_topogen()
- tc_name = request.node.name
- write_test_header(tc_name)
-
- # Don"t run this test if we have any failure.
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- step("Creating configuration from JSON")
- reset_config_on_routers(tgen)
- app_helper.stop_all_hosts()
- clear_mroute(tgen)
- clear_pim_interface_traffic(tgen, TOPO)
-
- # Steps to execute
- step("Enable IGMP on r1 interface")
- step("Configure RP on r2 (loopback interface) for the group range" " 224.0.0.0/4")
- step("r1: Shut the link from r1 to r2")
- step("r3: Shut the link from r1 to r3")
- step("r1: No shut the link from r1 to r2")
- step("r3: No shut the link from r1 to r3")
-
- step("r1: Verify RP info")
- dut = "r1"
- rp_address = "1.0.2.17"
- iif = "r1-r2-eth1"
- result = verify_pim_rp_info(
- tgen, TOPO, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r0: Send IGMP join")
- result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify IGMP groups")
- oif = "r1-r0-eth0"
- result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) ip mroutes")
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) ip mroutes")
- dut = "r2"
- iif = "lo"
- oif = "r2-r1-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Shut the interface r1-r2-eth1 from R1 to R2")
- dut = "r1"
- intf = "r1-r2-eth1"
- shutdown_bringup_interface(tgen, dut, intf, False)
-
- step(
- "Verify after shut the R1 to R2 link , verify join is reaching to RP"
- "via other path"
- )
-
- logger.info("Waiting for 110 sec only if test run with crucible")
-
- step("r1: Verify (*, G) ip mroutes")
- dut = "r1"
- iif = "r1-r3-eth2"
- oif = "r1-r0-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) ip mroutes")
- dut = "r2"
- iif = "lo"
- oif = "r2-r3-eth1"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (*, G) ip mroutes")
- dut = "r3"
- iif = "r3-r2-eth1"
- oif = "r3-r1-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Shut the link from R1 to R3 from R3 node")
- dut = "r3"
- intf = "r3-r1-eth0"
- shutdown_bringup_interface(tgen, dut, intf, False)
-
- step(
- "Verify after shut of R1 to R3 link , verify (*,G) entries got"
- " cleared from all the node R1, R2, R3"
- )
-
- step("r1: Verify (*, G) ip mroutes")
- dut = "r1"
- iif = "r1-r3-eth2"
- oif = "r1-r0-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r1: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r2: Verify (*, G) ip mroutes")
- dut = "r2"
- iif = "lo"
- oif = "r2-r3-eth1"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r2: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r3: Verify (*, G) ip mroutes")
- dut = "r3"
- iif = "r3-r2-eth1"
- oif = "r3-r1-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r3: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r3: No shutdown the link from R1 to R3 from R3 node")
- dut = "r3"
- intf = "r3-r1-eth0"
- shutdown_bringup_interface(tgen, dut, intf, True)
-
- step("r1: Verify (*, G) ip mroutes")
- dut = "r1"
- iif = "r1-r3-eth2"
- oif = "r1-r0-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) ip mroutes")
- dut = "r2"
- iif = "lo"
- oif = "r2-r3-eth1"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r3: Verify (*, G) ip mroutes")
- dut = "r3"
- iif = "r3-r2-eth1"
- oif = "r3-r1-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: No shutdown the link from R1 to R2 from R1 node")
- dut = "r1"
- intf = "r1-r2-eth1"
- shutdown_bringup_interface(tgen, dut, intf, True)
-
- step("r1: Verify (*, G) ip mroutes")
- dut = "r1"
- iif = "r1-r2-eth1"
- oif = "r1-r0-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) ip mroutes")
- dut = "r2"
- iif = "lo"
- oif = "r2-r1-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- write_test_footer(tc_name)
-
-
-def test_delete_RP_shut_noshut_upstream_interface_p1(request):
- """
- TC_31_P1: Verify RP info and (*,G) mroute after deleting the RP and shut /
- no shut the RPF interface.
- Topology used:
- ________r2_____
- | |
- iperf | |
- r0-----r1-------------r3
- """
-
- tgen = get_topogen()
- tc_name = request.node.name
- write_test_header(tc_name)
-
- # Don"t run this test if we have any failure.
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- step("Creating configuration from JSON")
- reset_config_on_routers(tgen)
- app_helper.stop_all_hosts()
- clear_mroute(tgen)
- clear_pim_interface_traffic(tgen, TOPO)
-
- step("Enable IGMP on r1 interface")
- step("Configure RP on r2 (loopback interface) for the group range" " 224.0.0.0/4")
- step("r1: Delete the RP config")
- step("r1: Shut and no shut the upstream interface (R1-R2) connected link")
- step("r1: Shut and no shut the OIL interface")
-
- step("r1: Verify RP info")
- dut = "r1"
- rp_address = "1.0.2.17"
- iif = "r1-r2-eth1"
- result = verify_pim_rp_info(
- tgen, TOPO, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r0: Send IGMP join")
- result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify IGMP groups")
- dut = "r1"
- oif = "r1-r0-eth0"
- result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) ip mroutes created")
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) ip mroutes created")
- dut = "r2"
- iif = "lo"
- oif = "r2-r1-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Delete RP configuration")
-
- # Delete RP configuration
- input_dict = {
- "r1": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- }
- }
-
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Shut the interface r1-r2-eth1 from R1 to R2")
- dut = "r1"
- intf = "r1-r2-eth1"
- shutdown_bringup_interface(tgen, dut, intf, False)
-
- step("r1: No shutdown the interface r1-r2-eth1 from R1 to R2")
- dut = "r1"
- intf = "r1-r2-eth1"
- shutdown_bringup_interface(tgen, dut, intf, True)
-
- step("r1: Shutdown the OIL interface r1-r0-eth0 from R1 to R0 ")
- dut = "r1"
- intf = "r1-r0-eth0"
- shutdown_bringup_interface(tgen, dut, intf, False)
-
- step("r1: No shutdown the OIL interface r1-r0-eth0 from R1 to R0")
- dut = "r1"
- intf = "r1-r0-eth0"
- shutdown_bringup_interface(tgen, dut, intf, True)
-
- step("r1: Verify (*, G) ip mroutes cleared")
- dut = "r1"
- iif = "r1-r2-eth1"
- oif = "r1-r0-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r1: (*,G) mroutes are not cleared after shut of R1 to R0 link\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r2: Verify (*, G) ip mroutes cleared")
- dut = "r2"
- iif = "lo"
- oif = "r2-r1-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r2: (*,G) mroutes are not cleared after shut of R1 to R0 link\n Error: {}".format(
- tc_name, result
- )
- )
-
- write_test_footer(tc_name)
-
-
-def test_delete_RP_shut_noshut_RP_interface_p1(request):
- """
- TC_32_P1: Verify RP info and (*,G) mroute after deleting the RP and shut/
- no shut the RPF interface
-
- Topology used:
- ________r2_____
- | |
- iperf | |
- r0-----r1-------------r3
- """
-
- tgen = get_topogen()
- tc_name = request.node.name
- write_test_header(tc_name)
-
- # Don"t run this test if we have any failure.
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- step("Creating configuration from JSON")
- reset_config_on_routers(tgen)
- app_helper.stop_all_hosts()
- clear_mroute(tgen)
- clear_pim_interface_traffic(tgen, TOPO)
-
- step("Enable IGMP on r1 interface")
- step("Configure RP on r2 (lo) for the group range" " 224.0.0.0/4")
- step("r2: Delete the RP configuration")
- step("r2: Shut the RP interface (lo)")
- step("r1: Shut the interface(r1-r2-eth1, r1-r3-eth2) towards rp")
-
- step("r1: Verify RP info")
- dut = "r1"
- rp_address = "1.0.2.17"
- iif = "r1-r2-eth1"
- result = verify_pim_rp_info(
- tgen, TOPO, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r0: Send IGMP join")
- result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify IGMP groups")
- oif = "r1-r0-eth0"
- result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify (*, G) ip mroutes created")
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Verify (*, G) ip mroutes created")
- dut = "r2"
- iif = "lo"
- oif = "r2-r1-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Delete RP configuration")
-
- # Delete RP configuration
- input_dict = {
- "r2": {
- "pim": {
- "rp": [
- {
- "rp_addr": "1.0.2.17",
- "group_addr_range": GROUP_RANGE_ALL,
- "delete": True,
- }
- ]
- }
- }
- }
-
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r2: Shut the RP interface lo")
- dut = "r2"
- intf = "lo"
- shutdown_bringup_interface(tgen, dut, intf, False)
-
- step("r1: Shut the interface r1-r2-eth1 towards RP")
- dut = "r1"
- intf = "r1-r2-eth1"
- shutdown_bringup_interface(tgen, dut, intf, False)
-
- step("r1: Shut the interface r1-r3-eth2 towards RP")
- dut = "r1"
- intf = "r1-r3-eth2"
- shutdown_bringup_interface(tgen, dut, intf, False)
-
- step("r1: Verify (*, G) ip mroutes cleared")
- dut = "r1"
- iif = "r1-r2-eth1"
- oif = "r1-r0-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r1: (*,G) mroutes are not cleared after shut of R1 to R2 and R3 link\n Error: {}".format(
- tc_name, result
- )
- )
-
- step("r2: Verify (*, G) ip mroutes cleared")
- dut = "r2"
- iif = "lo"
- oif = "r2-r1-eth0"
- result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r2: (*,G) mroutes are not cleared after shut of R1 to R2 and R3 link\n Error: {}".format(
- tc_name, result
- )
- )
-
- write_test_footer(tc_name)
-
-
if __name__ == "__main__":
ARGS = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(ARGS))
--- /dev/null
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2019 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# 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 VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+
+"""
+Following tests are covered to test Multicast basic functionality:
+
+Topology:
+
+ _______r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+ | |
+ |_____________|
+ r4
+
+Test steps
+- Create topology (setup module)
+- Bring up topology
+
+TC_1 : Verify upstream interfaces(IIF) and join state are updated properly
+ after adding and deleting the static RP
+TC_2 : Verify IIF and OIL in "show ip pim state" updated properly after
+ adding and deleting the static RP
+TC_3: (*, G) Mroute entry are cleared when static RP gets deleted
+TC_4: Verify (*,G) prune is send towards the RP after deleting the static RP
+TC_5: Verify OIF entry for RP is cleared when RP becomes unreachable
+TC_6: Verify IIF and OIL in "show ip pim state" updated properly when RP
+ becomes unreachable
+TC_7 : Verify upstream interfaces(IIF) and join state are updated properly
+ after adding and deleting the static RP
+TC_8: Verify (*,G) prune is send towards the RP when RP becomes unreachable
+TC_9 : Verify RP configured after IGMP join received, PIM join towards RP is
+ sent immediately
+TC_10 : Verify RP becomes reachable after IGMP join received, PIM join
+ towards RP is sent immediately
+TC_11 : Verify PIM join send towards the higher preferred RP
+TC_12 : Verify PIM prune send towards the lower preferred RP
+TC_13 : Verify RPF interface is updated in mroute (kernel) when higher
+ preferred overlapping RP configured
+TC_14 : Verify IIF and OIL in "show ip pim state" updated properly when higher
+ preferred overlapping RP configured
+TC_15 : Verify upstream interfaces(IIF) and join state are updated when higher
+ preferred overlapping RP is configured
+TC_16 : Verify join is send to lower preferred RP, when higher preferred RP
+ gets deleted
+TC_17 : Verify prune is send to higher preferred RP when higher preferred RP
+ gets deleted
+TC_18 : Verify RPF interface updated in mroute when higher preferred RP gets
+ deleted
+TC_19 : Verify IIF and OIL in "show ip pim state" updated when higher
+ preferred overlapping RP is deleted
+TC_20 : Verify PIM upstream IIF updated when higher preferred overlapping RP
+ deleted
+TC_21_1 : Verify OIF and RFP for (*,G) and (S,G) when static RP configure in
+ LHR router
+TC_21_2 : Verify OIF and RFP for (*,G) and (S,G) when static RP configure in
+ LHR router
+TC_22_1 : Verify OIF and RPF for (*,G) and (S,G) when static RP configure in
+ FHR router
+TC_22_2 : Verify OIF and RPF for (*,G) and (S,G) when static RP configure in
+ FHR router
+TC_23 : Verify (*,G) and (S,G) populated correctly when RPT and SPT path are
+ different
+TC_24 : Verify (*,G) and (S,G) populated correctly when SPT and RPT share the
+ same path
+TC_25 : Verify (*,G) and (S,G) populated correctly after clearing the PIM ,
+ IGMP and mroutes joins
+TC_26 : Restart the PIMd process and verify PIM joins , and mroutes entries
+TC_27 : Configure multiple groups (10 grps) with same RP address
+TC_28 : Configure multiple groups (10 grps) with different RP address
+TC_29 : Verify IIF and OIL in updated in mroute when upstream interface
+ configure as RP
+TC_30 : Verify IIF and OIL change to other path after shut the primary path
+TC_31 : Verify RP info and (*,G) mroute after deleting the RP and shut / no
+ shut the RPF interface.
+TC_32 : Verify RP info and (*,G) mroute after deleting the RP and shut / no
+ shut the RPF interface
+"""
+
+import os
+import sys
+import time
+from time import sleep
+import datetime
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+
+from lib.topogen import Topogen, get_topogen
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ step,
+ shutdown_bringup_interface,
+ kill_router_daemons,
+ start_router_daemons,
+ create_static_routes,
+ topo_daemons,
+)
+from lib.pim import (
+ create_pim_config,
+ verify_igmp_groups,
+ verify_upstream_iif,
+ verify_join_state_and_timer,
+ verify_mroutes,
+ verify_pim_neighbors,
+ get_pim_interface_traffic,
+ verify_pim_rp_info,
+ verify_pim_state,
+ clear_pim_interface_traffic,
+ clear_igmp_interfaces,
+ clear_pim_interfaces,
+ clear_mroute,
+ clear_mroute_verify,
+ McastTesterHelper,
+)
+
+pytestmark = [pytest.mark.pimd, pytest.mark.staticd]
+
+
+# Global variables
+GROUP_RANGE_ALL = "224.0.0.0/4"
+GROUP_RANGE = "225.1.1.1/32"
+GROUP_RANGE_LIST_1 = [
+ "225.1.1.1/32",
+ "225.1.1.2/32",
+ "225.1.1.3/32",
+ "225.1.1.4/32",
+ "225.1.1.5/32",
+]
+GROUP_RANGE_LIST_2 = [
+ "225.1.1.6/32",
+ "225.1.1.7/32",
+ "225.1.1.8/32",
+ "225.1.1.9/32",
+ "225.1.1.10/32",
+]
+GROUP_ADDRESS = "225.1.1.1"
+GROUP_ADDRESS_LIST_1 = ["225.1.1.1", "225.1.1.2", "225.1.1.3", "225.1.1.4", "225.1.1.5"]
+GROUP_ADDRESS_LIST_2 = [
+ "225.1.1.6",
+ "225.1.1.7",
+ "225.1.1.8",
+ "225.1.1.9",
+ "225.1.1.10",
+]
+STAR = "*"
+SOURCE_ADDRESS = "10.0.6.2"
+SOURCE = "Static"
+
+
+def build_topo(tgen):
+ """Build function"""
+
+ # Building topology from json file
+ build_topo_from_json(tgen, TOPO)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: %s", testsuite_run_time)
+ logger.info("=" * 40)
+
+ topology = """
+
+ _______r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+ | |
+ |_____________|
+ r4
+
+ """
+ logger.info("Master Topology: \n %s", topology)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ json_file = "{}/multicast_pim_static_rp.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global TOPO
+ TOPO = tgen.json_topo
+
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, TOPO)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons and then start routers
+ start_topology(tgen, daemons)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, TOPO)
+
+ # Verify PIM neighbors
+ result = verify_pim_neighbors(tgen, TOPO)
+ assert result is True, "setup_module :Failed \n Error:" " {}".format(result)
+
+ # XXX Replace this using "with McastTesterHelper()... " in each test if possible.
+ global app_helper
+ app_helper = McastTesterHelper(tgen)
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ app_helper.cleanup()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info("Testsuite end time: %s", time.asctime(time.localtime(time.time())))
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def verify_mroute_repopulated(uptime_before, uptime_after):
+ """
+ API to compare uptime for mroutes
+
+ Parameters
+ ----------
+ * `uptime_before` : Uptime dictionary for any particular instance
+ * `uptime_after` : Uptime dictionary for any particular instance
+ """
+
+ for group in uptime_before.keys():
+ for source in uptime_before[group].keys():
+ if set(uptime_before[group]) != set(uptime_after[group]):
+ errormsg = (
+ "mroute (%s, %s) has not come"
+ " up after mroute clear [FAILED!!]" % (source, group)
+ )
+ return errormsg
+
+ d_1 = datetime.datetime.strptime(uptime_before[group][source], "%H:%M:%S")
+ d_2 = datetime.datetime.strptime(uptime_after[group][source], "%H:%M:%S")
+ if d_2 >= d_1:
+ errormsg = "mroute (%s, %s) is not " "repopulated [FAILED!!]" % (
+ source,
+ group,
+ )
+ return errormsg
+
+ logger.info("mroute (%s, %s) is " "repopulated [PASSED!!]", source, group)
+
+ return True
+
+
+def verify_state_incremented(state_before, state_after):
+ """
+ API to compare interface traffic state incrementing
+
+ Parameters
+ ----------
+ * `state_before` : State dictionary for any particular instance
+ * `state_after` : State dictionary for any particular instance
+ """
+
+ for router, state_data in state_before.items():
+ for state, _ in state_data.items():
+ if state_before[router][state] >= state_after[router][state]:
+ errormsg = (
+ "[DUT: %s]: state %s value has not"
+ " incremented, Initial value: %s, "
+ "Current value: %s [FAILED!!]"
+ % (
+ router,
+ state,
+ state_before[router][state],
+ state_after[router][state],
+ )
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT: %s]: State %s value is "
+ "incremented, Initial value: %s, Current value: %s"
+ " [PASSED!!]",
+ router,
+ state,
+ state_before[router][state],
+ state_after[router][state],
+ )
+
+ return True
+
+
+def test_RP_configured_as_LHR_1_p1(request):
+ """
+ TC_21_1_P1: Verify OIF and RPF for (*,G) and (S,G) when static RP configure
+ in LHR router
+
+ Topology used:
+ ________r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+
+ r1 : LHR/RP
+ r3 : FHR
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Creating configuration from JSON")
+ reset_config_on_routers(tgen)
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ clear_pim_interface_traffic(tgen, TOPO)
+
+ step("Enable IGMP on r1 interface")
+ step("Configure RP on r1 (loopback interface) for the group range" " 224.0.0.0/4")
+ step("Enable the PIM on all the interfaces of r1, r2, r3 and r4 routers")
+ step("Send the IGMP join from r0")
+ step("Send multicast traffic from r5")
+
+ step("r1 , r2, r3, r4: Delete existing RP configuration" "configure r1(LHR) as RP")
+ input_dict = {
+ "r1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ "r3": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ "r4": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Configure r1(LHR) as RP")
+ input_dict = {
+ "r1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.1.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ }
+ ]
+ }
+ },
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.1.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ }
+ ]
+ }
+ },
+ "r3": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.1.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ }
+ ]
+ }
+ },
+ "r4": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.1.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ }
+ ]
+ }
+ },
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ shutdown_bringup_interface(tgen, "r1", "lo", False)
+ sleep(5)
+ shutdown_bringup_interface(tgen, "r1", "lo", True)
+ sleep(5)
+
+ step("r1: Verify RP info")
+ dut = "r1"
+ rp_address = "1.0.1.17"
+ iif = "lo"
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r0: Send IGMP join")
+ result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify IGMP groups")
+ oif = "r1-r0-eth0"
+ result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r5: Send multicast traffic for group 225.1.1.1")
+ result = app_helper.run_traffic("r5", GROUP_ADDRESS, "r3")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ iif = "r1-r3-eth2"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = "r3-r5-eth3"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S, G) upstream join state is joined and join"
+ " timer is running \n Error: {}".format(tc_name, result)
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = "r3-r1-eth0"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+ write_test_footer(tc_name)
+
+
+def test_RP_configured_as_LHR_2_p1(request):
+ """
+ TC_21_2_P1: Verify OIF and RPF for (*,G) and (S,G) when static RP configure
+ in LHR router
+
+ Topology used:
+ ________r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+
+ r1 : LHR/RP
+ r3 : FHR
+
+ """
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Creating configuration from JSON")
+ reset_config_on_routers(tgen)
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ clear_pim_interface_traffic(tgen, TOPO)
+
+ step("Enable IGMP on r1 interface")
+ step("Configure RP on r1 (loopback interface) for the group range" " 224.0.0.0/4")
+ step("Enable the PIM on all the interfaces of r1, r2, r3 and r4 routers")
+ step("Send multicast traffic from r5")
+ step("Send the IGMP join from r0")
+
+ step("r1, r2, r3, r4: Delete existing RP configuration," "configure r1(LHR) as RP")
+ input_dict = {
+ "r1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ "r3": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ "r4": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1, r2, r3, r4: Configure r1(LHR) as RP")
+ input_dict = {
+ "r1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.1.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ }
+ ]
+ }
+ },
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.1.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ }
+ ]
+ }
+ },
+ "r3": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.1.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ }
+ ]
+ }
+ },
+ "r4": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.1.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ }
+ ]
+ }
+ },
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify RP info")
+ dut = "r1"
+ rp_address = "1.0.1.17"
+ iif = "lo"
+ result = verify_pim_rp_info(tgen, TOPO, dut, GROUP_ADDRESS, iif, rp_address, SOURCE)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r5: Send multicast traffic for group 225.1.1.1")
+ result = app_helper.run_traffic("r5", GROUP_ADDRESS, "r3")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r0: Send IGMP join")
+ result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify IGMP groups")
+ oif = "r1-r0-eth0"
+ result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ iif = "r1-r3-eth2"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = "r3-r5-eth3"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = "r3-r1-eth0"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+ write_test_footer(tc_name)
+
+
+def test_RP_configured_as_FHR_1_p1(request):
+ """
+ TC_22_1_P1: Verify OIF and RFP for (*,G) and (S,G) when static RP configure
+ in FHR router
+
+ Topology used:
+ ________r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+
+ r1 : LHR
+ r3 : FHR/RP
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Creating configuration from JSON")
+ reset_config_on_routers(tgen)
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ clear_pim_interface_traffic(tgen, TOPO)
+
+ step("Enable IGMP on r1 interface")
+ step("Configure RP on r2 (loopback interface) for the group range" " 225.1.1.0/24")
+ step("Enable the PIM on all the interfaces of r1, r2, r3 and r4 routers")
+ step("Send the IGMP join from r0")
+ step("Send multicast traffic from r5")
+
+ step("r1, r2, r3, r4: Delete existing RP configuration" "configure r3(FHR) as RP")
+ input_dict = {
+ "r1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ "r3": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ "r4": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ }
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1, r2, r3, r4: Configure r3(FHR) as RP")
+ input_dict = {
+ "r1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.3.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ }
+ ]
+ }
+ },
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.3.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ }
+ ]
+ }
+ },
+ "r3": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.3.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ }
+ ]
+ }
+ },
+ "r4": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.3.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ }
+ ]
+ }
+ },
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify RP info")
+ dut = "r1"
+ rp_address = "1.0.3.17"
+ iif = "r1-r3-eth2"
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r0: Send IGMP join")
+ result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r0: Verify IGMP groups")
+ oif = "r1-r0-eth0"
+ result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r5: Send multicast traffic for group 225.1.1.1")
+ result = app_helper.run_traffic("r5", GROUP_ADDRESS, "r3")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = "r3-r5-eth3"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = "r3-r1-eth0"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+ write_test_footer(tc_name)
+
+
+def test_RP_configured_as_FHR_2_p2(request):
+ """
+ TC_22_2_P2: Verify OIF and RFP for (*,G) and (S,G) when static RP configure
+ in FHR router
+
+ Topology used:
+ ________r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+
+ r1 : LHR
+ r3 : FHR/RP
+ """
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Creating configuration from JSON")
+ reset_config_on_routers(tgen)
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ clear_pim_interface_traffic(tgen, TOPO)
+
+ step("Enable IGMP on r1 interface")
+ step("Configure RP on r2 (loopback interface) for the group range" " 225.1.1.0/24")
+ step("Enable the PIM on all the interfaces of r1, r2, r3 and r4 routers")
+ step("Send multicast traffic from r5")
+ step("Send the IGMP join from r0")
+
+ step("r1, r2, r3, r4: Delete existing RP configuration" "configure r3(FHR) as RP")
+ input_dict = {
+ "r1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ "r3": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ "r4": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1, r2, r3, r4: Configure r3(FHR) as RP")
+ input_dict = {
+ "r1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.3.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ }
+ ]
+ }
+ },
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.3.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ }
+ ]
+ }
+ },
+ "r3": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.3.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ }
+ ]
+ }
+ },
+ "r4": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.3.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ }
+ ]
+ }
+ },
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify RP info")
+ dut = "r1"
+ rp_address = "1.0.3.17"
+ iif = "r1-r3-eth2"
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r5: Send multicast traffic for group 225.1.1.1")
+ result = app_helper.run_traffic("r5", GROUP_ADDRESS, "r3")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r0: Send IGMP join")
+ result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r0: Verify IGMP groups")
+ oif = "r1-r0-eth0"
+ result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ iif = "r1-r3-eth2"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = "r3-r5-eth3"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = "r3-r1-eth0"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+ write_test_footer(tc_name)
+
+
+def test_SPT_RPT_path_different_p1(request):
+ """
+ TC_23_P1: Verify (*,G) and (S,G) populated correctly when RPT and SPT path
+ are different
+
+ Topology used:
+ ________r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+
+ r1: LHR
+ r2: RP
+ r3: FHR
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Creating configuration from JSON")
+ reset_config_on_routers(tgen)
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ clear_pim_interface_traffic(tgen, TOPO)
+
+ step("Enable IGMP on r1 interface and send IGMP join (225.1.1.1) to r1")
+ step("Configure RP on r2 (loopback interface) for the group range" " 224.0.0.0/4")
+ step("Enable the PIM on all the interfaces of r1, r2, r3 and r4 routers")
+ step("Send multicast traffic from r3")
+
+ step("r2: Verify RP info")
+ dut = "r2"
+ rp_address = "1.0.2.17"
+ iif = "lo"
+ result = verify_pim_rp_info(tgen, TOPO, dut, GROUP_ADDRESS, iif, rp_address, SOURCE)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r0: Send IGMP join")
+ result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify IGMP groups")
+ dut = "r1"
+ oif = "r1-r0-eth0"
+ result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r5: Send multicast traffic for group 225.1.1.1")
+ result = app_helper.run_traffic("r5", GROUP_ADDRESS, "r3")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ iif = "r1-r2-eth1"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ iif = "r1-r3-eth2"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream IIF interface")
+ dut = "r2"
+ iif = "lo"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes")
+ oif = "r2-r1-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = "r3-r5-eth3"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = "r3-r1-eth0"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream IIF interface")
+ dut = "r2"
+ iif = "r2-r3-eth1"
+ result = verify_upstream_iif(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, joinState="NotJoined"
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r2: Verify (S, G) ip mroutes")
+ oif = "none"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+ write_test_footer(tc_name)
+
+
+def test_clear_pim_configuration_p1(request):
+ """
+ TC_25_P1: Verify (*,G) and (S,G) populated correctly after clearing the
+ PIM,IGMP and mroutes joins
+
+ Topology used:
+ ________r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+ | |
+ |_____________|
+ r4
+ r1 : LHR
+ r2 : RP
+ r3 : FHR
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Creating configuration from JSON")
+ reset_config_on_routers(tgen)
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ clear_pim_interface_traffic(tgen, TOPO)
+
+ step("Enable IGMP on r1 interface")
+ step("Configure RP on r2 (loopback interface) for the group range" " 224.0.0.0/4")
+ step("Enable the PIM on all the interfaces of r1, r2, r3 and r4 routers")
+ step("Send the IGMP join from r0")
+ step("Send multicast traffic from r5")
+
+ step("r2: Verify RP info")
+ dut = "r2"
+ rp_address = "1.0.2.17"
+ oif = "lo"
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_ALL, oif, rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r0: Send IGMP join")
+ result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify IGMP groups")
+ dut = "r1"
+ iif = "r1-r0-eth0"
+ result = verify_igmp_groups(tgen, dut, iif, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r5: Send multicast traffic for group 225.1.1.1")
+ result = app_helper.run_traffic("r5", GROUP_ADDRESS, "r3")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ dut = "r1"
+ iif = "r1-r2-eth1"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ oif = "r1-r0-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify IGMP groups timer restarted")
+ result = clear_igmp_interfaces(tgen, dut)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify PIM neighbor timer restarted")
+ result = clear_pim_interfaces(tgen, dut)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify PIM mroute timer restarted")
+ result = clear_mroute_verify(tgen, dut)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+ write_test_footer(tc_name)
+
+
+
+
+if __name__ == "__main__":
+ ARGS = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(ARGS))
--- /dev/null
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2019 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# 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 VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+
+"""
+Following tests are covered to test Multicast basic functionality:
+
+Topology:
+
+ _______r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+ | |
+ |_____________|
+ r4
+
+Test steps
+- Create topology (setup module)
+- Bring up topology
+
+TC_1 : Verify upstream interfaces(IIF) and join state are updated properly
+ after adding and deleting the static RP
+TC_2 : Verify IIF and OIL in "show ip pim state" updated properly after
+ adding and deleting the static RP
+TC_3: (*, G) Mroute entry are cleared when static RP gets deleted
+TC_4: Verify (*,G) prune is send towards the RP after deleting the static RP
+TC_5: Verify OIF entry for RP is cleared when RP becomes unreachable
+TC_6: Verify IIF and OIL in "show ip pim state" updated properly when RP
+ becomes unreachable
+TC_7 : Verify upstream interfaces(IIF) and join state are updated properly
+ after adding and deleting the static RP
+TC_8: Verify (*,G) prune is send towards the RP when RP becomes unreachable
+TC_9 : Verify RP configured after IGMP join received, PIM join towards RP is
+ sent immediately
+TC_10 : Verify RP becomes reachable after IGMP join received, PIM join
+ towards RP is sent immediately
+TC_11 : Verify PIM join send towards the higher preferred RP
+TC_12 : Verify PIM prune send towards the lower preferred RP
+TC_13 : Verify RPF interface is updated in mroute (kernel) when higher
+ preferred overlapping RP configured
+TC_14 : Verify IIF and OIL in "show ip pim state" updated properly when higher
+ preferred overlapping RP configured
+TC_15 : Verify upstream interfaces(IIF) and join state are updated when higher
+ preferred overlapping RP is configured
+TC_16 : Verify join is send to lower preferred RP, when higher preferred RP
+ gets deleted
+TC_17 : Verify prune is send to higher preferred RP when higher preferred RP
+ gets deleted
+TC_18 : Verify RPF interface updated in mroute when higher preferred RP gets
+ deleted
+TC_19 : Verify IIF and OIL in "show ip pim state" updated when higher
+ preferred overlapping RP is deleted
+TC_20 : Verify PIM upstream IIF updated when higher preferred overlapping RP
+ deleted
+TC_21_1 : Verify OIF and RFP for (*,G) and (S,G) when static RP configure in
+ LHR router
+TC_21_2 : Verify OIF and RFP for (*,G) and (S,G) when static RP configure in
+ LHR router
+TC_22_1 : Verify OIF and RPF for (*,G) and (S,G) when static RP configure in
+ FHR router
+TC_22_2 : Verify OIF and RPF for (*,G) and (S,G) when static RP configure in
+ FHR router
+TC_23 : Verify (*,G) and (S,G) populated correctly when RPT and SPT path are
+ different
+TC_24 : Verify (*,G) and (S,G) populated correctly when SPT and RPT share the
+ same path
+TC_25 : Verify (*,G) and (S,G) populated correctly after clearing the PIM ,
+ IGMP and mroutes joins
+TC_26 : Restart the PIMd process and verify PIM joins , and mroutes entries
+TC_27 : Configure multiple groups (10 grps) with same RP address
+TC_28 : Configure multiple groups (10 grps) with different RP address
+TC_29 : Verify IIF and OIL in updated in mroute when upstream interface
+ configure as RP
+TC_30 : Verify IIF and OIL change to other path after shut the primary path
+TC_31 : Verify RP info and (*,G) mroute after deleting the RP and shut / no
+ shut the RPF interface.
+TC_32 : Verify RP info and (*,G) mroute after deleting the RP and shut / no
+ shut the RPF interface
+"""
+
+import os
+import sys
+import time
+from time import sleep
+import datetime
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+
+from lib.topogen import Topogen, get_topogen
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ step,
+ shutdown_bringup_interface,
+ kill_router_daemons,
+ start_router_daemons,
+ create_static_routes,
+ topo_daemons,
+)
+from lib.pim import (
+ create_pim_config,
+ verify_igmp_groups,
+ verify_upstream_iif,
+ verify_join_state_and_timer,
+ verify_mroutes,
+ verify_pim_neighbors,
+ get_pim_interface_traffic,
+ verify_pim_rp_info,
+ verify_pim_state,
+ clear_pim_interface_traffic,
+ clear_igmp_interfaces,
+ clear_pim_interfaces,
+ clear_mroute,
+ clear_mroute_verify,
+ McastTesterHelper,
+)
+
+pytestmark = [pytest.mark.pimd, pytest.mark.staticd]
+
+
+# Global variables
+GROUP_RANGE_ALL = "224.0.0.0/4"
+GROUP_RANGE = "225.1.1.1/32"
+GROUP_RANGE_LIST_1 = [
+ "225.1.1.1/32",
+ "225.1.1.2/32",
+ "225.1.1.3/32",
+ "225.1.1.4/32",
+ "225.1.1.5/32",
+]
+GROUP_RANGE_LIST_2 = [
+ "225.1.1.6/32",
+ "225.1.1.7/32",
+ "225.1.1.8/32",
+ "225.1.1.9/32",
+ "225.1.1.10/32",
+]
+GROUP_ADDRESS = "225.1.1.1"
+GROUP_ADDRESS_LIST_1 = ["225.1.1.1", "225.1.1.2", "225.1.1.3", "225.1.1.4", "225.1.1.5"]
+GROUP_ADDRESS_LIST_2 = [
+ "225.1.1.6",
+ "225.1.1.7",
+ "225.1.1.8",
+ "225.1.1.9",
+ "225.1.1.10",
+]
+STAR = "*"
+SOURCE_ADDRESS = "10.0.6.2"
+SOURCE = "Static"
+
+
+def build_topo(tgen):
+ """Build function"""
+
+ # Building topology from json file
+ build_topo_from_json(tgen, TOPO)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: %s", testsuite_run_time)
+ logger.info("=" * 40)
+
+ topology = """
+
+ _______r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+ | |
+ |_____________|
+ r4
+
+ """
+ logger.info("Master Topology: \n %s", topology)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ json_file = "{}/multicast_pim_static_rp.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global TOPO
+ TOPO = tgen.json_topo
+
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, TOPO)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons and then start routers
+ start_topology(tgen, daemons)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, TOPO)
+
+ # Verify PIM neighbors
+ result = verify_pim_neighbors(tgen, TOPO)
+ assert result is True, "setup_module :Failed \n Error:" " {}".format(result)
+
+ # XXX Replace this using "with McastTesterHelper()... " in each test if possible.
+ global app_helper
+ app_helper = McastTesterHelper(tgen)
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ app_helper.cleanup()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info("Testsuite end time: %s", time.asctime(time.localtime(time.time())))
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def verify_mroute_repopulated(uptime_before, uptime_after):
+ """
+ API to compare uptime for mroutes
+
+ Parameters
+ ----------
+ * `uptime_before` : Uptime dictionary for any particular instance
+ * `uptime_after` : Uptime dictionary for any particular instance
+ """
+
+ for group in uptime_before.keys():
+ for source in uptime_before[group].keys():
+ if set(uptime_before[group]) != set(uptime_after[group]):
+ errormsg = (
+ "mroute (%s, %s) has not come"
+ " up after mroute clear [FAILED!!]" % (source, group)
+ )
+ return errormsg
+
+ d_1 = datetime.datetime.strptime(uptime_before[group][source], "%H:%M:%S")
+ d_2 = datetime.datetime.strptime(uptime_after[group][source], "%H:%M:%S")
+ if d_2 >= d_1:
+ errormsg = "mroute (%s, %s) is not " "repopulated [FAILED!!]" % (
+ source,
+ group,
+ )
+ return errormsg
+
+ logger.info("mroute (%s, %s) is " "repopulated [PASSED!!]", source, group)
+
+ return True
+
+
+def verify_state_incremented(state_before, state_after):
+ """
+ API to compare interface traffic state incrementing
+
+ Parameters
+ ----------
+ * `state_before` : State dictionary for any particular instance
+ * `state_after` : State dictionary for any particular instance
+ """
+
+ for router, state_data in state_before.items():
+ for state, _ in state_data.items():
+ if state_before[router][state] >= state_after[router][state]:
+ errormsg = (
+ "[DUT: %s]: state %s value has not"
+ " incremented, Initial value: %s, "
+ "Current value: %s [FAILED!!]"
+ % (
+ router,
+ state,
+ state_before[router][state],
+ state_after[router][state],
+ )
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT: %s]: State %s value is "
+ "incremented, Initial value: %s, Current value: %s"
+ " [PASSED!!]",
+ router,
+ state,
+ state_before[router][state],
+ state_after[router][state],
+ )
+
+ return True
+
+
+def test_restart_pimd_process_p2(request):
+ """
+ TC_26_P2: Restart the PIMd process and verify PIM upstream and mroutes
+ entries
+ Topology used:
+ ________r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+ | |
+ |_____________|
+ r4
+ r1 : LHR
+ r2 : RP
+ r3 : FHR
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Creating configuration from JSON")
+ reset_config_on_routers(tgen)
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ clear_pim_interface_traffic(tgen, TOPO)
+
+ step("Enable IGMP on r1 interface and send IGMP join (225.1.1.1) to R1")
+ step("Configure RP on r3 (loopback interface) for the group range" " 224.0.0.0/4")
+ step("Enable the PIM on all the interfaces of r1, r2, r3 and r4 routers")
+ step("Send multicast traffic from R3")
+ step("Restart the PIMd process")
+
+ step("r2: Verify RP info")
+ dut = "r2"
+ rp_address = "1.0.2.17"
+ oif = "lo"
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_ALL, oif, rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r0: Send IGMP join")
+ result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify IGMP groups")
+ dut = "r1"
+ oif = "r1-r0-eth0"
+ result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r5: Send multicast traffic for group 225.1.1.1")
+ result = app_helper.run_traffic("r5", GROUP_ADDRESS, "r3")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ iif = "r1-r2-eth1"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ iif = "r1-r3-eth2"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream IIF interface")
+ dut = "r2"
+ iif = "lo"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes")
+ oif = "r2-r1-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = "r3-r5-eth3"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = "r3-r1-eth0"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r1"
+ iif = "r1-r2-eth1"
+ oil = "r1-r0-eth0"
+ logger.info("waiting for 10 sec to make sure old mroute time is higher")
+ sleep(10)
+ # Why do we then wait 60 seconds below before checking the routes?
+ uptime_before = verify_mroutes(
+ tgen, dut, STAR, GROUP_ADDRESS, iif, oil, return_uptime=True, mwait=60
+ )
+ assert isinstance(uptime_before, dict), "Testcase{} : Failed Error: {}".format(
+ tc_name, result
+ )
+
+ step("r1: Kill pimd process")
+ kill_router_daemons(tgen, "r1", ["pimd"])
+
+ step("r1 : Start pimd process")
+ start_router_daemons(tgen, "r1", ["pimd"])
+
+ logger.info("Waiting for 5sec to get PIMd restarted and mroute" " re-learned..")
+ sleep(5)
+
+ # Why do we then wait 10 seconds below before checking the routes?
+ uptime_after = verify_mroutes(
+ tgen, dut, STAR, GROUP_ADDRESS, iif, oil, return_uptime=True, mwait=10
+ )
+ assert isinstance(uptime_after, dict), "Testcase{} : Failed Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_mroute_repopulated(uptime_before, uptime_after)
+ assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_multiple_groups_same_RP_address_p2(request):
+ """
+ TC_27_P2: Configure multiple groups (10 grps) with same RP address
+
+ Topology used:
+ ________r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+
+ r1 : LHR
+ r2 : RP
+ r3 : FHR
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Creating configuration from JSON")
+ reset_config_on_routers(tgen)
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ clear_pim_interface_traffic(tgen, TOPO)
+
+ step("Enable IGMP on r1 interface and send IGMP join (225.1.1.1) to r1")
+ step("Configure RP on r2 (loopback interface) for the group range" "225.1.1.0/24")
+ step("Enable the PIM on all the interfaces of r1-r2-r3")
+ step("Send multicast traffic from r5 to all the groups")
+ step("r1 : Remove the groups to RP mapping one by one")
+ step("r1: Shut the upstream interfaces")
+ step("r1: No shut the upstream interfaces")
+ step("r1: Configure the RP again")
+ step("r1: Shut the receiver interfaces")
+ step("r1: No Shut the receiver interfaces")
+ step("r2: Verify RP info")
+
+ step("r2: verify rp-info")
+ dut = "r2"
+ rp_address = "1.0.2.17"
+ oif = "lo"
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_ALL, oif, rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ group_address_list = GROUP_ADDRESS_LIST_1 + GROUP_ADDRESS_LIST_2
+ step("r0: Send IGMP join for 10 groups")
+ result = app_helper.run_join("r0", group_address_list, "r1")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify IGMP groups")
+ dut = "r1"
+ oif = "r1-r0-eth0"
+ result = verify_igmp_groups(tgen, dut, oif, group_address_list)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r5: Send multicast traffic for group 225.1.1.1")
+ result = app_helper.run_traffic("r5", group_address_list, "r3")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ dut = "r1"
+ iif = "r1-r2-eth1"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, group_address_list)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, group_address_list)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ oif = "r1-r0-eth0"
+ result = verify_mroutes(tgen, dut, STAR, group_address_list, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ iif = "r1-r3-eth2"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, group_address_list)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, group_address_list
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, group_address_list, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream IIF interface")
+ dut = "r2"
+ iif = "lo"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, group_address_list)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, group_address_list)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes")
+ oif = "r2-r1-eth0"
+ result = verify_mroutes(tgen, dut, STAR, group_address_list, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = "r3-r5-eth3"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, group_address_list)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, group_address_list, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = "r3-r1-eth0"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, group_address_list, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream IIF interface")
+ dut = "r2"
+ iif = "r2-r3-eth1"
+ result = verify_upstream_iif(
+ tgen, dut, iif, SOURCE_ADDRESS, group_address_list, joinState="NotJoined"
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, group_address_list, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r2: Verify (S, G) ip mroutes")
+ oif = "none"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, group_address_list, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Delete RP configuration")
+ input_dict = {
+ "r1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Shut the interface r1-r2-eth1 from R1 to R2")
+ dut = "r1"
+ intf = "r1-r2-eth1"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("r1: No Shut the interface r1-r2-eth1 from R1 to R2")
+ intf = "r1-r2-eth1"
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step("r1: Configure RP")
+ input_dict = {
+ "r1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Shut the interface r1-r0-eth0 from R1 to R2")
+ intf = "r1-r0-eth0"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("r1: No Shut the interface r1-r0-eth0 from R1 to R2")
+ intf = "r1-r0-eth0"
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ dut = "r1"
+ iif = "r1-r2-eth1"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, group_address_list)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, group_address_list)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ oif = "r1-r0-eth0"
+ result = verify_mroutes(tgen, dut, STAR, group_address_list, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ iif = "r1-r3-eth2"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, group_address_list)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, group_address_list
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, group_address_list, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream IIF interface")
+ dut = "r2"
+ iif = "lo"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, group_address_list)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, group_address_list)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes")
+ oif = "r2-r1-eth0"
+ result = verify_mroutes(tgen, dut, STAR, group_address_list, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream IIF interface")
+ dut = "r2"
+ iif = "r2-r3-eth1"
+ result = verify_upstream_iif(
+ tgen, dut, iif, SOURCE_ADDRESS, group_address_list, joinState="NotJoined"
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, group_address_list, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r2: Verify (S, G) ip mroutes")
+ oif = "none"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, group_address_list, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = "r3-r5-eth3"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, group_address_list)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, group_address_list, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = "r3-r1-eth0"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, group_address_list, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_multiple_groups_different_RP_address_p2(request):
+ """
+ TC_28_P2: Verify IIF and OIL in updated in mroute when upstream interface
+ configure as RP
+
+ Topology used:
+ ________r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+ | |
+ |_____________|
+ r4
+ r1 : LHR
+ r2 & r4 : RP
+ r3 : FHR
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Creating configuration from JSON")
+ reset_config_on_routers(tgen)
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ clear_pim_interface_traffic(tgen, TOPO)
+
+ step("Delete existing RP configuration")
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_LIST_1,
+ }
+ ]
+ }
+ },
+ "r4": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.4.17",
+ "group_addr_range": GROUP_RANGE_LIST_2,
+ }
+ ]
+ }
+ },
+ }
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify RP info")
+ dut = "r2"
+ rp_address = "1.0.2.17"
+ oif = "lo"
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_LIST_1, oif, rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r4: Verify RP info")
+ dut = "r4"
+ rp_address = "1.0.4.17"
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_LIST_2, oif, rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ group_address_list = GROUP_ADDRESS_LIST_1 + GROUP_ADDRESS_LIST_2
+ step("r0: Send IGMP join")
+ result = app_helper.run_join("r0", group_address_list, "r1")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify IGMP groups")
+ dut = "r1"
+ oif = "r1-r0-eth0"
+ result = verify_igmp_groups(tgen, dut, oif, group_address_list)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r5: Send multicast traffic for group 225.1.1.1")
+ result = app_helper.run_traffic("r5", group_address_list, "r3")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ dut = "r1"
+ iif = "r1-r2-eth1"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ iif = "r1-r3-eth2"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream IIF interface")
+ dut = "r2"
+ iif = "lo"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes")
+ oif = "r2-r1-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream IIF interface")
+ iif = "r2-r3-eth1"
+ result = verify_upstream_iif(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, joinState="NotJoined"
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r2: Verify (S, G) ip mroutes")
+ oif = "none"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = "r3-r5-eth3"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = "r3-r1-eth0"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ dut = "r1"
+ iif = "r1-r4-eth3"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ oif = "r1-r0-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ iif = "r1-r3-eth2"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r4: Verify (*, G) upstream IIF interface")
+ dut = "r4"
+ iif = "lo"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r4: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r4: Verify (*, G) ip mroutes")
+ oif = "r4-r1-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r4: Verify (S, G) upstream IIF interface")
+ iif = "r4-r3-eth1"
+ result = verify_upstream_iif(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, joinState="NotJoined"
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r4: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r4: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r4: Verify (S, G) ip mroutes")
+ oif = "none"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = "r3-r5-eth3"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False
+ )
+ assert result is not True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = "r3-r1-eth0"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Delete RP configuration")
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_LIST_1,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ "r4": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.4.17",
+ "group_addr_range": GROUP_RANGE_LIST_2,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ }
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1, r2, r3, r4: Re-configure RP")
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_LIST_1,
+ }
+ ]
+ }
+ },
+ "r4": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.4.17",
+ "group_addr_range": GROUP_RANGE_LIST_2,
+ }
+ ]
+ }
+ },
+ }
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Shut the interface r1-r2-eth1 from R1 to R2")
+ dut = "r1"
+ intf = "r1-r2-eth1"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("r1: No shut the interface r1-r2-eth1 from R1 to R2")
+ dut = "r1"
+ intf = "r1-r2-eth1"
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step("r1: Shut the interface r1-r2-eth1 from R1 to R4")
+ dut = "r1"
+ intf = "r1-r4-eth3"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("r1: No shut the interface r1-r2-eth1 from R1 to r4")
+ dut = "r1"
+ intf = "r1-r4-eth3"
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step("r1: Shut the interface r1-r0-eth0 from R1 to R0")
+ dut = "r1"
+ intf = "r1-r0-eth0"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("r1: No Shut the interface r1-r0-eth0 from R1 to R0")
+ dut = "r1"
+ intf = "r1-r0-eth0"
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ dut = "r1"
+ iif = "r1-r2-eth1"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ oif = "r1-r0-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ iif = "r1-r3-eth2"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream IIF interface")
+ dut = "r2"
+ iif = "lo"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes")
+ oif = "r2-r1-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream IIF interface")
+ iif = "r2-r3-eth1"
+ result = verify_upstream_iif(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, joinState="NotJoined"
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r2: Verify (S, G) ip mroutes")
+ oif = "none"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = "r3-r5-eth3"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = "r3-r1-eth0"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ dut = "r1"
+ iif = "r1-r4-eth3"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ oif = "r1-r0-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ iif = "r1-r3-eth2"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r4: Verify (*, G) upstream IIF interface")
+ dut = "r4"
+ iif = "lo"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r4: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r4: Verify (*, G) ip mroutes")
+ oif = "r4-r1-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r4: Verify (S, G) upstream IIF interface")
+ iif = "r4-r3-eth1"
+ result = verify_upstream_iif(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, joinState="NotJoined"
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r4: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r4: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r4: Verify (S, G) ip mroutes")
+ oif = "none"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = "r3-r5-eth3"
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = "r3-r1-eth0"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_shutdown_primary_path_p1(request):
+ """
+ TC_30_P1: Verify IIF and OIL change to other path after shut the primary
+ path
+
+ Topology used:
+ ________r2_____
+ | |
+ iperf | |
+ r0-----r1-------------r3
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Creating configuration from JSON")
+ reset_config_on_routers(tgen)
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ clear_pim_interface_traffic(tgen, TOPO)
+
+ # Steps to execute
+ step("Enable IGMP on r1 interface")
+ step("Configure RP on r2 (loopback interface) for the group range" " 224.0.0.0/4")
+ step("r1: Shut the link from r1 to r2")
+ step("r3: Shut the link from r1 to r3")
+ step("r1: No shut the link from r1 to r2")
+ step("r3: No shut the link from r1 to r3")
+
+ step("r1: Verify RP info")
+ dut = "r1"
+ rp_address = "1.0.2.17"
+ iif = "r1-r2-eth1"
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r0: Send IGMP join")
+ result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify IGMP groups")
+ oif = "r1-r0-eth0"
+ result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes")
+ dut = "r2"
+ iif = "lo"
+ oif = "r2-r1-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Shut the interface r1-r2-eth1 from R1 to R2")
+ dut = "r1"
+ intf = "r1-r2-eth1"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step(
+ "Verify after shut the R1 to R2 link , verify join is reaching to RP"
+ "via other path"
+ )
+
+ logger.info("Waiting for 110 sec only if test run with crucible")
+
+ step("r1: Verify (*, G) ip mroutes")
+ dut = "r1"
+ iif = "r1-r3-eth2"
+ oif = "r1-r0-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes")
+ dut = "r2"
+ iif = "lo"
+ oif = "r2-r3-eth1"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (*, G) ip mroutes")
+ dut = "r3"
+ iif = "r3-r2-eth1"
+ oif = "r3-r1-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Shut the link from R1 to R3 from R3 node")
+ dut = "r3"
+ intf = "r3-r1-eth0"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step(
+ "Verify after shut of R1 to R3 link , verify (*,G) entries got"
+ " cleared from all the node R1, R2, R3"
+ )
+
+ step("r1: Verify (*, G) ip mroutes")
+ dut = "r1"
+ iif = "r1-r3-eth2"
+ oif = "r1-r0-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r1: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r2: Verify (*, G) ip mroutes")
+ dut = "r2"
+ iif = "lo"
+ oif = "r2-r3-eth1"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r2: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (*, G) ip mroutes")
+ dut = "r3"
+ iif = "r3-r2-eth1"
+ oif = "r3-r1-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: No shutdown the link from R1 to R3 from R3 node")
+ dut = "r3"
+ intf = "r3-r1-eth0"
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step("r1: Verify (*, G) ip mroutes")
+ dut = "r1"
+ iif = "r1-r3-eth2"
+ oif = "r1-r0-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes")
+ dut = "r2"
+ iif = "lo"
+ oif = "r2-r3-eth1"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r3: Verify (*, G) ip mroutes")
+ dut = "r3"
+ iif = "r3-r2-eth1"
+ oif = "r3-r1-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: No shutdown the link from R1 to R2 from R1 node")
+ dut = "r1"
+ intf = "r1-r2-eth1"
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step("r1: Verify (*, G) ip mroutes")
+ dut = "r1"
+ iif = "r1-r2-eth1"
+ oif = "r1-r0-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes")
+ dut = "r2"
+ iif = "lo"
+ oif = "r2-r1-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_delete_RP_shut_noshut_upstream_interface_p1(request):
+ """
+ TC_31_P1: Verify RP info and (*,G) mroute after deleting the RP and shut /
+ no shut the RPF interface.
+ Topology used:
+ ________r2_____
+ | |
+ iperf | |
+ r0-----r1-------------r3
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Creating configuration from JSON")
+ reset_config_on_routers(tgen)
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ clear_pim_interface_traffic(tgen, TOPO)
+
+ step("Enable IGMP on r1 interface")
+ step("Configure RP on r2 (loopback interface) for the group range" " 224.0.0.0/4")
+ step("r1: Delete the RP config")
+ step("r1: Shut and no shut the upstream interface (R1-R2) connected link")
+ step("r1: Shut and no shut the OIL interface")
+
+ step("r1: Verify RP info")
+ dut = "r1"
+ rp_address = "1.0.2.17"
+ iif = "r1-r2-eth1"
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r0: Send IGMP join")
+ result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify IGMP groups")
+ dut = "r1"
+ oif = "r1-r0-eth0"
+ result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes created")
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes created")
+ dut = "r2"
+ iif = "lo"
+ oif = "r2-r1-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Delete RP configuration")
+
+ # Delete RP configuration
+ input_dict = {
+ "r1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Shut the interface r1-r2-eth1 from R1 to R2")
+ dut = "r1"
+ intf = "r1-r2-eth1"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("r1: No shutdown the interface r1-r2-eth1 from R1 to R2")
+ dut = "r1"
+ intf = "r1-r2-eth1"
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step("r1: Shutdown the OIL interface r1-r0-eth0 from R1 to R0 ")
+ dut = "r1"
+ intf = "r1-r0-eth0"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("r1: No shutdown the OIL interface r1-r0-eth0 from R1 to R0")
+ dut = "r1"
+ intf = "r1-r0-eth0"
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step("r1: Verify (*, G) ip mroutes cleared")
+ dut = "r1"
+ iif = "r1-r2-eth1"
+ oif = "r1-r0-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r1: (*,G) mroutes are not cleared after shut of R1 to R0 link\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r2: Verify (*, G) ip mroutes cleared")
+ dut = "r2"
+ iif = "lo"
+ oif = "r2-r1-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r2: (*,G) mroutes are not cleared after shut of R1 to R0 link\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_delete_RP_shut_noshut_RP_interface_p1(request):
+ """
+ TC_32_P1: Verify RP info and (*,G) mroute after deleting the RP and shut/
+ no shut the RPF interface
+
+ Topology used:
+ ________r2_____
+ | |
+ iperf | |
+ r0-----r1-------------r3
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Creating configuration from JSON")
+ reset_config_on_routers(tgen)
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ clear_pim_interface_traffic(tgen, TOPO)
+
+ step("Enable IGMP on r1 interface")
+ step("Configure RP on r2 (lo) for the group range" " 224.0.0.0/4")
+ step("r2: Delete the RP configuration")
+ step("r2: Shut the RP interface (lo)")
+ step("r1: Shut the interface(r1-r2-eth1, r1-r3-eth2) towards rp")
+
+ step("r1: Verify RP info")
+ dut = "r1"
+ rp_address = "1.0.2.17"
+ iif = "r1-r2-eth1"
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r0: Send IGMP join")
+ result = app_helper.run_join("r0", GROUP_ADDRESS, "r1")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify IGMP groups")
+ oif = "r1-r0-eth0"
+ result = verify_igmp_groups(tgen, dut, oif, GROUP_ADDRESS)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes created")
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes created")
+ dut = "r2"
+ iif = "lo"
+ oif = "r2-r1-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Delete RP configuration")
+
+ # Delete RP configuration
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": "1.0.2.17",
+ "group_addr_range": GROUP_RANGE_ALL,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r2: Shut the RP interface lo")
+ dut = "r2"
+ intf = "lo"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("r1: Shut the interface r1-r2-eth1 towards RP")
+ dut = "r1"
+ intf = "r1-r2-eth1"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("r1: Shut the interface r1-r3-eth2 towards RP")
+ dut = "r1"
+ intf = "r1-r3-eth2"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("r1: Verify (*, G) ip mroutes cleared")
+ dut = "r1"
+ iif = "r1-r2-eth1"
+ oif = "r1-r0-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r1: (*,G) mroutes are not cleared after shut of R1 to R2 and R3 link\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r2: Verify (*, G) ip mroutes cleared")
+ dut = "r2"
+ iif = "lo"
+ oif = "r2-r1-eth0"
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r2: (*,G) mroutes are not cleared after shut of R1 to R2 and R3 link\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ ARGS = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(ARGS))
--- /dev/null
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# 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 VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+
+"""
+Following tests are covered to test Multicast basic functionality:
+
+Topology:
+
+ _______r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+ | |
+ |_____________|
+ r4
+
+Test steps
+- Create topology (setup module)
+- Bring up topology
+
+TC_1 : Verify upstream interfaces(IIF) and join state are updated properly
+ after adding and deleting the static RP
+TC_2 : Verify IIF and OIL in "show ip pim state" updated properly after
+ adding and deleting the static RP
+TC_3: (*, G) Mroute entry are cleared when static RP gets deleted
+TC_4: Verify (*,G) prune is send towards the RP after deleting the static RP
+TC_24 : Verify (*,G) and (S,G) populated correctly when SPT and RPT share the
+ same path
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+from time import sleep
+import datetime
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ step,
+ shutdown_bringup_interface,
+ kill_router_daemons,
+ start_router_daemons,
+ create_static_routes,
+ check_router_status,
+ socat_send_igmp_join_traffic,
+ topo_daemons
+)
+from lib.pim import (
+ create_pim_config,
+ verify_igmp_groups,
+ verify_upstream_iif,
+ verify_join_state_and_timer,
+ verify_mroutes,
+ verify_pim_neighbors,
+ verify_pim_interface_traffic,
+ verify_pim_rp_info,
+ verify_pim_state,
+ clear_pim_interface_traffic,
+ clear_igmp_interfaces,
+ clear_pim_interfaces,
+ clear_mroute,
+ clear_mroute_verify,
+)
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Global variables
+GROUP_RANGE_V6 = "ff08::/64"
+IGMP_JOIN_V6 = "ff08::1"
+STAR = "*"
+SOURCE = "Static"
+
+pytestmark = [pytest.mark.pimd]
+
+
+def build_topo(tgen):
+ """Build function"""
+
+ # Building topology from json file
+ build_topo_from_json(tgen, TOPO)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: %s", testsuite_run_time)
+ logger.info("=" * 40)
+
+ topology = """
+
+ _______r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+ | |
+ |_____________|
+ r4
+
+ """
+ logger.info("Master Topology: \n %s", topology)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ json_file = "{}/multicast_pimv6_static_rp.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global TOPO
+ TOPO = tgen.json_topo
+
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, TOPO)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons and then start routers
+ start_topology(tgen, daemons)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, TOPO)
+
+ # Verify PIM neighbors
+ result = verify_pim_neighbors(tgen, TOPO)
+ assert result is True, "setup_module :Failed \n Error:" " {}".format(result)
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info("Testsuite end time: %s", time.asctime(time.localtime(time.time())))
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def verify_state_incremented(state_before, state_after):
+ """
+ API to compare interface traffic state incrementing
+
+ Parameters
+ ----------
+ * `state_before` : State dictionary for any particular instance
+ * `state_after` : State dictionary for any particular instance
+ """
+
+ for router, state_data in state_before.items():
+ for state, value in state_data.items():
+ if state_before[router][state] >= state_after[router][state]:
+ errormsg = (
+ "[DUT: %s]: state %s value has not"
+ " incremented, Initial value: %s, "
+ "Current value: %s [FAILED!!]"
+ % (
+ router,
+ state,
+ state_before[router][state],
+ state_after[router][state],
+ )
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT: %s]: State %s value is "
+ "incremented, Initial value: %s, Current value: %s"
+ " [PASSED!!]",
+ router,
+ state,
+ state_before[router][state],
+ state_after[router][state],
+ )
+
+ return True
+
+
+#####################################################
+
+def test_pimv6_add_delete_static_RP_p0(request):
+ """
+ TC_1: Verify upstream interfaces(IIF) and join state are updated
+ properly after adding and deleting the static RP
+ TC_2: Verify IIF and OIL in "show ip pim state" updated properly
+ after adding and deleting the static RP
+ TC_3: (*, G) Mroute entry are cleared when static RP gets deleted
+ TC_4: Verify (*,G) prune is send towards the RP after deleting the
+ static RP
+
+ TOPOlogy used:
+ r0------r1-----r2
+ iperf DUT RP
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step("Shut link b/w R1 and R3 and R1 and R4 as per tescase topology")
+ intf_r1_r3 = TOPO["routers"]["r1"]["links"]["r3"]["interface"]
+ intf_r1_r4 = TOPO["routers"]["r1"]["links"]["r4"]["interface"]
+ for intf in [intf_r1_r3, intf_r1_r4]:
+ shutdown_bringup_interface(tgen, "r1", intf, ifaceaction=False)
+
+ step("Enable PIM between r1 and r2")
+ step("Enable MLD on r1 interface and send IGMP " "join (FF08::1) to r1")
+ step("Configure r2 loopback interface as RP")
+ input_dict = {
+ "r2": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_V6,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify show ip pim interface traffic without any mld join")
+ state_dict = {
+ "r1": {TOPO["routers"]["r1"]["links"]["r2"]["interface"]: ["pruneTx"]}
+ }
+
+ state_before = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6")
+ assert isinstance(
+ state_before, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
+ tc_name, result
+ )
+
+ step("send mld join (FF08::1) to R1")
+ intf = TOPO["routers"]["r0"]["links"]["r1"]["interface"]
+ intf_ip = TOPO["routers"]["r0"]["links"]["r1"]["ipv6"].split("/")[0]
+ result = socat_send_igmp_join_traffic(
+ tgen, "r0", "UDP6-RECV", IGMP_JOIN_V6, intf, intf_ip, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify RP info")
+ dut = "r1"
+ oif = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
+ iif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ rp_address = TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0]
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_V6, oif, rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify upstream IIF interface")
+ result = verify_upstream_iif(tgen, dut, oif, STAR, IGMP_JOIN_V6)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, oif, STAR, IGMP_JOIN_V6)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify PIM state")
+ result = verify_pim_state(tgen, dut, oif, iif, IGMP_JOIN_V6)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify ip mroutes")
+ result = verify_mroutes(tgen, dut, STAR, IGMP_JOIN_V6, oif, iif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Delete RP configuration")
+ input_dict = {
+ "r2": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_V6,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify RP info")
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_V6, oif, rp_address, SOURCE, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} :Failed \n " "RP: {} info is still present \n Error: {}".format(
+ tc_name, rp_address, result
+ )
+
+ step("r1: Verify upstream IIF interface")
+ result = verify_upstream_iif(tgen, dut, oif, STAR, IGMP_JOIN_V6, expected=False)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "Upstream ({}, {}) is still in join state \n Error: {}".format(
+ tc_name, STAR, IGMP_JOIN_V6, result
+ )
+ )
+
+ step("r1: Verify upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, oif, STAR, IGMP_JOIN_V6, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "Upstream ({}, {}) timer is still running \n Error: {}".format(
+ tc_name, STAR, IGMP_JOIN_V6, result
+ )
+ )
+
+ step("r1: Verify PIM state")
+ result = verify_pim_state(tgen, dut, oif, iif, IGMP_JOIN_V6, expected=False)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "PIM state for group: {} is still Active \n Error: {}".format(
+ tc_name, IGMP_JOIN_V6, result
+ )
+ )
+
+ step("r1: Verify ip mroutes")
+ result = verify_mroutes(tgen, dut, STAR, IGMP_JOIN_V6, oif, iif, expected=False)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "mroute ({}, {}) is still present \n Error: {}".format(
+ tc_name, STAR, IGMP_JOIN_V6, result
+ )
+ )
+
+ step("r1: Verify show ip pim interface traffic without any IGMP join")
+ state_after = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6")
+ assert isinstance(
+ state_after, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_state_incremented(state_before, state_after)
+ assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
create_router_ospf,
)
+pytestmark = [pytest.mark.ospfd]
+
# Global variables
topo = None
Iters = 5
create_router_ospf,
)
+pytestmark = [pytest.mark.ospfd]
+
# Global variables
topo = None
Iters = 5
create_router_ospf,
)
+pytestmark = [pytest.mark.ospfd]
+
# Global variables
topo = None
Iters = 5
for router in rlist:
logger.info('Checking OSPF IPv6 kernel routes in "%s"', router.name)
- routes = topotest.ip6_route(router)
- expected = {
- "2001:db8:1::/64": {},
- "2001:db8:2::/64": {},
- "2001:db8:3::/64": {},
- "2001:db8:100::/64": {},
- "2001:db8:200::/64": {},
- "2001:db8:300::/64": {},
- }
+ def _routes_in_fib6():
+ routes = topotest.ip6_route(router)
+ expected = {
+ "2001:db8:1::/64": {},
+ "2001:db8:2::/64": {},
+ "2001:db8:3::/64": {},
+ "2001:db8:100::/64": {},
+ "2001:db8:200::/64": {},
+ "2001:db8:300::/64": {},
+ }
+ logger.info("Routes:")
+ logger.info(routes)
+ logger.info(topotest.json_cmp(routes, expected))
+ logger.info("ENd:")
+ return topotest.json_cmp(routes, expected)
+
+ _, result = topotest.run_and_expect(_routes_in_fib6, None, count=20, wait=1)
+
assertmsg = 'OSPF IPv6 route mismatch in router "{}"'.format(router.name)
- assert topotest.json_cmp(routes, expected) is None, assertmsg
+ assert result is None, assertmsg
def test_ospf_json():
for rnum in range(1, 5):
router = tgen.gears["r{}".format(rnum)]
+ logger.info(router.vtysh_cmd("show ip ospf database"))
logger.info('Comparing router "%s" "show ip ospf json" output', router.name)
expected = {
"routerId": "10.0.255.{}".format(rnum),
verify_ospf_summary,
)
+pytestmark = [pytest.mark.ospfd, pytest.mark.staticd]
# Global variables
topo = None
step("Verify that interface is enabled in ospf.")
step("Verify that config is successful.")
dut = "r0"
- input_dict = {"r0": {"links": {"r3": {"ospf6": {"ospf6Enabled": True}}}}}
+ input_dict = {"r0": {"links": {"r3": {"ospf6": {}}}}}
result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("Verify that interface is enabled in ospf.")
dut = "r0"
- input_dict = {"r0": {"links": {"r3": {"ospf6": {"ospf6Enabled": True}}}}}
+ input_dict = {"r0": {"links": {"r3": {"ospf6": {}}}}}
result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Verify that interface is enabled in ospf.")
dut = "r0"
- input_dict = {"r0": {"links": {"r3": {"ospf6": {"ospf6Enabled": True}}}}}
+ input_dict = {"r0": {"links": {"r3": {"ospf6": {}}}}}
result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
"ospf6": {
"status": "up",
"type": "BROADCAST",
- "ospf6Enabled": True,
"attachedToArea": True,
"instanceId": 0,
"interfaceMtu": 1500,
ripngd=no
isisd=no
pimd=no
+pim6d=no
ldpd=no
nhrpd=no
eigrpd=no
ripngd_options=" -A ::1"
isisd_options=" -A 127.0.0.1"
pimd_options=" -A 127.0.0.1"
+pim6d_options=" -A ::1"
ldpd_options=" -A 127.0.0.1"
nhrpd_options=" -A 127.0.0.1"
eigrpd_options=" -A 127.0.0.1"
$outchannel frr_log,/var/log/frr/frr.log
if $programname == 'babeld' or
$programname == 'bgpd' or
+ $programname == 'bfdd' or
$programname == 'eigrpd' or
$programname == 'frr' or
$programname == 'isisd' or
$programname == 'ospf6d' or
$programname == 'ospfd' or
$programname == 'pimd' or
+ $programname == 'pim6d' or
$programname == 'pathd' or
$programname == 'ripd' or
$programname == 'ripngd' or
if $programname == 'babeld' or
$programname == 'bgpd' or
+ $programname == 'bfdd' or
$programname == 'eigrpd' or
$programname == 'frr' or
$programname == 'isisd' or
$programname == 'ospf6d' or
$programname == 'ospfd' or
$programname == 'pimd' or
+ $programname == 'pim6d' or
$programname == 'pathd' or
$programname == 'ripd' or
$programname == 'ripngd' or
"ospfd",
"pbrd",
"pimd",
+ "pim6d",
"ripd",
"ripngd",
"sharpd",
# Local Daemon selection may be done by using /etc/frr/daemons.
# See /usr/share/doc/frr/README.Debian.gz for further information.
# Keep zebra first and do not list watchfrr!
-DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
+DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd pim6d ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
MAX_INSTANCES=5
RELOAD_SCRIPT="$D_PATH/frr-reload.py"
# - keep zebra first
# - watchfrr does NOT belong in this list
-DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
+DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd pim6d ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
RELOAD_SCRIPT="$D_PATH/frr-reload.py"
#
[ -r "$pidfile" ] || fail="pid file not found"
$all && [ -n "$fail" ] && return 0
- [ -z "$fail" ] && pid="$(cat \"$pidfile\")"
+ [ -z "$fail" ] && pid="$(cat "$pidfile")"
[ -z "$fail" -a -z "$pid" ] && fail="pid file is empty"
[ -n "$fail" ] || kill -0 "$pid" 2>/dev/null || fail="pid $pid not running"
pidfile="$V_PATH/$daemon${inst:+-$inst}.pid"
[ -r "$pidfile" ] || return 3
- pid="$(cat \"$pidfile\")"
+ pid="$(cat "$pidfile")"
[ -z "$pid" ] && return 1
kill -0 "$pid" 2>/dev/null || return 1
return 0
}
all_stop() {
- local pids reversed
+ local pids reversed need_zebra
daemon_list enabled_daemons disabled_daemons
[ "$1" = "--reallyall" ] && enabled_daemons="$enabled_daemons $disabled_daemons"
reversed="$dmninst $reversed"
done
+ # Stop zebra last, after trying to stop the other daemons
for dmninst in $reversed; do
+ if [ "$dmninst" = "zebra" ]; then
+ need_zebra="yes"
+ continue
+ fi
+
daemon_stop "$dmninst" "$1" &
pids="$pids $!"
done
for pid in $pids; do
wait $pid
done
+
+ if [ -n "$need_zebra" ]; then
+ daemon_stop "zebra"
+ fi
}
all_status() {
format_ctx.arglocs = arglocs;
check_function_arguments_recurse (check_format_arg, &format_ctx,
- format_tree, arg_num);
+ format_tree, arg_num, OPT_Wformat_);
location_t loc = format_ctx.res->format_string_loc;
#define SET_DECL_MODE(decl, mode) DECL_MODE(decl) = (mode)
#endif
+#if BUILDING_GCC_VERSION < 12000
+#define check_function_arguments_recurse(arg, ctx, tree, num, opt) \
+ check_function_arguments_recurse(arg, ctx, tree, num)
+#endif
+
#endif
*/
static void vrrp_read(struct thread *thread)
{
- struct vrrp_router *r = thread->arg;
+ struct vrrp_router *r = THREAD_ARG(thread);
struct vrrp_pkt *pkt;
ssize_t pktsize;
*/
static void vrrp_adver_timer_expire(struct thread *thread)
{
- struct vrrp_router *r = thread->arg;
+ struct vrrp_router *r = THREAD_ARG(thread);
DEBUGD(&vrrp_dbg_proto,
VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
*/
static void vrrp_master_down_timer_expire(struct thread *thread)
{
- struct vrrp_router *r = thread->arg;
+ struct vrrp_router *r = THREAD_ARG(thread);
zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
"Master_Down_Timer expired",
#include "frrstr.h"
#include "json.h"
#include "ferr.h"
+#include "bgpd/bgp_vty.h"
DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy");
int lineno = 0;
/* once we have an error, we remember & return that */
int retcode = CMD_SUCCESS;
+ char *vty_buf_copy = XCALLOC(MTYPE_VTYSH_CMD, VTY_BUFSIZ);
+ char *vty_buf_trimmed = NULL;
while (fgets(vty->buf, VTY_BUFSIZ, fp)) {
lineno++;
+ strlcpy(vty_buf_copy, vty->buf, VTY_BUFSIZ);
+ vty_buf_trimmed = trim(vty_buf_copy);
+
+ /*
+ * Ignore the "end" lines, we will generate these where
+ * appropriate, otherwise we never execute
+ * XFRR_end_configuration, and start/end markers do not work.
+ */
+ if (strmatch(vty_buf_trimmed, "end"))
+ continue;
+
ret = command_config_read_one_line(vty, &cmd, lineno, 1);
switch (ret) {
}
}
+ XFREE(MTYPE_VTYSH_CMD, vty_buf_copy);
+
return (retcode);
}
DEFUNSH(VTYSH_BGPD, address_family_vpnv4, address_family_vpnv4_cmd,
"address-family vpnv4 [unicast]",
"Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family modifier\n")
+ BGP_AF_STR
+ BGP_AF_MODIFIER_STR)
{
vty->node = BGP_VPNV4_NODE;
return CMD_SUCCESS;
DEFUNSH(VTYSH_BGPD, address_family_vpnv6, address_family_vpnv6_cmd,
"address-family vpnv6 [unicast]",
"Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family modifier\n")
+ BGP_AF_STR
+ BGP_AF_MODIFIER_STR)
{
vty->node = BGP_VPNV6_NODE;
return CMD_SUCCESS;
DEFUNSH(VTYSH_BGPD, address_family_ipv4, address_family_ipv4_cmd,
"address-family ipv4 [unicast]",
"Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family Modifier\n")
+ BGP_AF_STR
+ BGP_AF_MODIFIER_STR)
{
vty->node = BGP_IPV4_NODE;
return CMD_SUCCESS;
DEFUNSH(VTYSH_BGPD, address_family_flowspecv4, address_family_flowspecv4_cmd,
"address-family ipv4 flowspec",
"Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family Modifier\n")
+ BGP_AF_STR
+ BGP_AF_MODIFIER_STR)
{
vty->node = BGP_FLOWSPECV4_NODE;
return CMD_SUCCESS;
DEFUNSH(VTYSH_BGPD, address_family_flowspecv6, address_family_flowspecv6_cmd,
"address-family ipv6 flowspec",
"Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family Modifier\n")
+ BGP_AF_STR
+ BGP_AF_MODIFIER_STR)
{
vty->node = BGP_FLOWSPECV6_NODE;
return CMD_SUCCESS;
DEFUNSH(VTYSH_BGPD, address_family_ipv4_multicast,
address_family_ipv4_multicast_cmd, "address-family ipv4 multicast",
"Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family modifier\n")
+ BGP_AF_STR
+ BGP_AF_MODIFIER_STR)
{
vty->node = BGP_IPV4M_NODE;
return CMD_SUCCESS;
DEFUNSH(VTYSH_BGPD, address_family_ipv4_vpn, address_family_ipv4_vpn_cmd,
"address-family ipv4 vpn",
"Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family modifier\n")
+ BGP_AF_STR
+ BGP_AF_MODIFIER_STR)
{
vty->node = BGP_VPNV4_NODE;
return CMD_SUCCESS;
address_family_ipv4_labeled_unicast_cmd,
"address-family ipv4 labeled-unicast",
"Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family modifier\n")
+ BGP_AF_STR
+ BGP_AF_MODIFIER_STR)
{
vty->node = BGP_IPV4L_NODE;
return CMD_SUCCESS;
DEFUNSH(VTYSH_BGPD, address_family_ipv6, address_family_ipv6_cmd,
"address-family ipv6 [unicast]",
"Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family modifier\n")
+ BGP_AF_STR
+ BGP_AF_MODIFIER_STR)
{
vty->node = BGP_IPV6_NODE;
return CMD_SUCCESS;
DEFUNSH(VTYSH_BGPD, address_family_ipv6_multicast,
address_family_ipv6_multicast_cmd, "address-family ipv6 multicast",
"Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family modifier\n")
+ BGP_AF_STR
+ BGP_AF_MODIFIER_STR)
{
vty->node = BGP_IPV6M_NODE;
return CMD_SUCCESS;
DEFUNSH(VTYSH_BGPD, address_family_ipv6_vpn, address_family_ipv6_vpn_cmd,
"address-family ipv6 vpn",
"Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family modifier\n")
+ BGP_AF_STR
+ BGP_AF_MODIFIER_STR)
{
vty->node = BGP_VPNV6_NODE;
return CMD_SUCCESS;
address_family_ipv6_labeled_unicast_cmd,
"address-family ipv6 labeled-unicast",
"Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family modifier\n")
+ BGP_AF_STR
+ BGP_AF_MODIFIER_STR)
{
vty->node = BGP_IPV6L_NODE;
return CMD_SUCCESS;
DEFUNSH(VTYSH_BGPD, address_family_evpn, address_family_evpn_cmd,
"address-family <l2vpn evpn>",
"Enter Address Family command mode\n"
- "Address Family\n"
- "Address Family modifier\n")
+ BGP_AF_STR
+ BGP_AF_MODIFIER_STR)
{
vty->node = BGP_EVPN_NODE;
return CMD_SUCCESS;
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"
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);
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);
/* Flag to indicate if in user/unprivileged mode. */
int user_mode;
-/* For sigsetjmp() & siglongjmp(). */
-static sigjmp_buf jmpbuf;
-
-/* Flag for avoid recursive siglongjmp() call. */
-static int jmpflag = 0;
-
/* Master of threads. */
struct thread_master *master;
/* Command logging */
FILE *logfile;
+static void vtysh_rl_callback(char *line_read)
+{
+ HIST_ENTRY *last;
+
+ rl_callback_handler_remove();
+
+ if (!line_read) {
+ vtysh_loop_exited = true;
+ return;
+ }
+
+ /* If the line has any text in it, save it on the history. But only if
+ * last command in history isn't the same one.
+ */
+ if (*line_read) {
+ using_history();
+ last = previous_history();
+ if (!last || strcmp(last->line, line_read) != 0) {
+ add_history(line_read);
+ append_history(1, history_file);
+ }
+ }
+
+ vtysh_execute(line_read);
+
+ if (!vtysh_loop_exited)
+ rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
+}
+
/* SIGTSTP handler. This function care user's ^Z input. */
static void sigtstp(int sig)
{
+ rl_callback_handler_remove();
+
/* Execute "end" command. */
vtysh_execute("end");
+ if (!vtysh_loop_exited)
+ rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
+
/* Initialize readline. */
rl_initialize();
printf("\n");
-
- /* Check jmpflag for duplicate siglongjmp(). */
- if (!jmpflag)
- return;
-
- jmpflag = 0;
-
- /* Back to main command loop. */
- siglongjmp(jmpbuf, 1);
+ rl_forced_update_display();
}
/* SIGINT handler. This function care user's ^Z input. */
bool vtysh_loop_exited;
-static void vtysh_rl_callback(char *line_read)
-{
- HIST_ENTRY *last;
-
- rl_callback_handler_remove();
-
- if (!line_read) {
- vtysh_loop_exited = true;
- return;
- }
-
- /* If the line has any text in it, save it on the history. But only if
- * last command in history isn't the same one. */
- if (*line_read) {
- using_history();
- last = previous_history();
- if (!last || strcmp(last->line, line_read) != 0) {
- add_history(line_read);
- append_history(1, history_file);
- }
- }
-
- vtysh_execute(line_read);
-
- if (!vtysh_loop_exited)
- rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
-}
-
static struct thread *vtysh_rl_read_thread;
static void vtysh_rl_read(struct thread *thread)
vtysh_add_timestamp = ts_flag;
- /* Preparation for longjmp() in sigtstp(). */
- sigsetjmp(jmpbuf, 1);
- jmpflag = 1;
-
/* Main command loop. */
vtysh_rl_run();
if ((sscanf(optarg, "%ld%1s", &gs.operational_timeout,
garbage) != 1) ||
- (gs.max_restart_interval < 0)) {
+ (gs.operational_timeout < 0)) {
fprintf(stderr,
"Invalid Operational_timeout argument: %s\n",
optarg);
return "MFC_STATS";
case RTA_NH_ID:
return "NH_ID";
+ case RTA_EXPIRES:
+ return "EXPIRES";
default:
return "UNKNOWN";
}
static void nlroute_dump(struct rtmsg *rtm, size_t msglen)
{
+ struct rta_mfc_stats *mfc_stats;
struct rtattr *rta;
size_t plen;
uint32_t u32v;
+ uint64_t u64v;
/* Get the first attribute and go from there. */
rta = RTM_RTA(rtm);
zlog_debug(" %u", u32v);
break;
+ case RTA_EXPIRES:
+ u64v = *(uint64_t *)RTA_DATA(rta);
+ zlog_debug(" %" PRIu64, u64v);
+ break;
+
case RTA_GATEWAY:
case RTA_DST:
case RTA_SRC:
}
break;
+ case RTA_MFC_STATS:
+ mfc_stats = (struct rta_mfc_stats *)RTA_DATA(rta);
+ zlog_debug(" pkts=%ju bytes=%ju wrong_if=%ju",
+ (uintmax_t)mfc_stats->mfcs_packets,
+ (uintmax_t)mfc_stats->mfcs_bytes,
+ (uintmax_t)mfc_stats->mfcs_wrong_if);
+ break;
+
default:
/* NOTHING: unhandled. */
break;
goto next_rta;
}
+static const char *tcm_nltype2str(int nltype)
+{
+ switch (nltype) {
+ case RTM_NEWQDISC:
+ case RTM_DELQDISC:
+ return "qdisc";
+ case RTM_NEWTCLASS:
+ case RTM_DELTCLASS:
+ return "tclass";
+ case RTM_NEWTFILTER:
+ case RTM_DELTFILTER:
+ return "tfilter";
+ default:
+ /* should never hit */
+ return "unknown";
+ }
+}
+
static void nlncm_dump(const struct netconfmsg *ncm, size_t msglen)
{
const struct rtattr *rta;
struct ifinfomsg *ifi;
struct tunnel_msg *tnlm;
struct fib_rule_hdr *frh;
+ struct tcmsg *tcm;
+
char fbuf[128];
char ibuf[128];
nlncm_dump(ncm, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ncm)));
break;
+ case RTM_NEWQDISC:
+ case RTM_DELQDISC:
+ case RTM_NEWTCLASS:
+ case RTM_DELTCLASS:
+ case RTM_NEWTFILTER:
+ case RTM_DELTFILTER:
+ tcm = NLMSG_DATA(nlmsg);
+ zlog_debug(
+ " tcm [type=%s family=%s (%d) ifindex=%d handle=%04x:%04x]",
+ tcm_nltype2str(nlmsg->nlmsg_type),
+ af_type2str(tcm->tcm_family), tcm->tcm_family,
+ tcm->tcm_ifindex, tcm->tcm_handle >> 16,
+ tcm->tcm_handle & 0xffff);
+ break;
+
default:
break;
}
case DPLANE_OP_INTF_INSTALL:
case DPLANE_OP_INTF_UPDATE:
case DPLANE_OP_INTF_DELETE:
+ case DPLANE_OP_TC_INSTALL:
+ case DPLANE_OP_TC_UPDATE:
+ case DPLANE_OP_TC_DELETE:
case DPLANE_OP_NONE:
break;
ifp = if_lookup_by_name(ifap->ifa_name, VRF_DEFAULT);
if (ifp == NULL) {
flog_err(EC_LIB_INTERFACE,
- "if_getaddrs(): Can't lookup interface %s\n",
+ "if_getaddrs(): Can't lookup interface %s",
ifap->ifa_name);
continue;
}
ecmd.cmd = ETHTOOL_GSET; /* ETHTOOL_GLINK */
ifdata.ifr_data = (caddr_t)&ecmd;
- /* use ioctl to get IP address of an interface */
+ /* use ioctl to get speed of an interface */
frr_with_privs(&zserv_privs) {
sd = vrf_socket(PF_INET, SOCK_DGRAM, IPPROTO_IP,
interface->vrf->vrf_id, NULL);
*error = -1;
return 0;
}
- /* Get the current link state for the interface */
+ /* Get the current link state for the interface */
rc = vrf_ioctl(interface->vrf->vrf_id, sd, SIOCETHTOOL,
(char *)&ifdata);
}
return ZEBRA_DPLANE_REQUEST_FAILURE;
}
+enum zebra_dplane_result
+kernel_intf_netconf_update(struct zebra_dplane_ctx *ctx)
+{
+ const char *ifname = dplane_ctx_get_ifname(ctx);
+ enum dplane_netconf_status_e mpls_on = dplane_ctx_get_netconf_mpls(ctx);
+
+ zlog_warn("%s: Unable to set kernel mpls state for interface %s(%d)",
+ __func__, ifname, mpls_on);
+
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
+}
#endif
zebra_if = XCALLOC(MTYPE_ZINFO, sizeof(struct zebra_if));
zebra_if->ifp = ifp;
- zebra_if->multicast = IF_ZEBRA_MULTICAST_UNSPEC;
- zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_OFF;
+ zebra_if->multicast = IF_ZEBRA_DATA_UNSPEC;
+ zebra_if->shutdown = IF_ZEBRA_DATA_OFF;
zebra_if_nhg_dependents_init(zebra_if);
if_data = ifp->info;
assert(if_data);
- if (if_data->multicast == IF_ZEBRA_MULTICAST_ON)
+ if (if_data->multicast == IF_ZEBRA_DATA_ON)
if_set_flags(ifp, IFF_MULTICAST);
- else if (if_data->multicast == IF_ZEBRA_MULTICAST_OFF)
+ else if (if_data->multicast == IF_ZEBRA_DATA_OFF)
if_unset_flags(ifp, IFF_MULTICAST);
zebra_ptm_if_set_ptm_state(ifp, if_data);
if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
SET_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE);
- if (if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON) {
+ if (if_data->shutdown == IF_ZEBRA_DATA_ON) {
if (IS_ZEBRA_DEBUG_KERNEL) {
zlog_debug(
"interface %s vrf %s(%u) index %d is shutdown. Won't wake it up.",
/* Send out notification on interface VRF change. */
/* This is to issue an ADD, if needed. */
zebra_interface_vrf_update_add(ifp, old_vrf_id);
-
- /* Install connected routes (in new VRF). */
- if (if_is_operative(ifp))
- if_install_connected(ifp);
}
static void ipv6_ll_address_to_mac(struct in6_addr *address, uint8_t *mac)
/*
* mpls netconf data is neither v4 or v6 it's AF_MPLS!
*/
- if (mpls == DPLANE_NETCONF_STATUS_ENABLED)
+ if (mpls == DPLANE_NETCONF_STATUS_ENABLED) {
zif->mpls = true;
- else if (mpls == DPLANE_NETCONF_STATUS_DISABLED)
+ zebra_mpls_turned_on();
+ } else if (mpls == DPLANE_NETCONF_STATUS_DISABLED)
zif->mpls = false;
}
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);
"%s: can't find ifp at nsid %u index %d",
__func__, ns_id, ifindex);
- goto done;
+ return;
}
}
case DPLANE_OP_IPSET_ENTRY_DELETE:
case DPLANE_OP_NEIGH_TABLE_UPDATE:
case DPLANE_OP_GRE_SET:
+ case DPLANE_OP_TC_INSTALL:
+ case DPLANE_OP_TC_UPDATE:
+ case DPLANE_OP_TC_DELETE:
break; /* should never hit here */
}
-done:
- dplane_ctx_fini(&ctx);
}
/* Dump if address information to vty. */
if_refresh(ifp);
}
if_data = ifp->info;
- if_data->multicast = IF_ZEBRA_MULTICAST_ON;
+ if_data->multicast = IF_ZEBRA_DATA_ON;
return 0;
}
if_refresh(ifp);
}
if_data = ifp->info;
- if_data->multicast = IF_ZEBRA_MULTICAST_ON;
+ if_data->multicast = IF_ZEBRA_DATA_ON;
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (mpls,
+ mpls_cmd,
+ "[no] mpls enable",
+ NO_STR
+ MPLS_STR
+ "Set mpls to be on for the interface\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct zebra_if *if_data = ifp->info;
+
+ if (no) {
+ dplane_intf_mpls_modify_state(ifp, false);
+ if_data->mpls = IF_ZEBRA_DATA_UNSPEC;
+ } else {
+ dplane_intf_mpls_modify_state(ifp, true);
+ if_data->mpls = IF_ZEBRA_DATA_ON;
+ }
return CMD_SUCCESS;
}
if_refresh(ifp);
}
if_data = ifp->info;
- if_data->multicast = IF_ZEBRA_MULTICAST_OFF;
+ if_data->multicast = IF_ZEBRA_DATA_OFF;
return 0;
}
if_refresh(ifp);
}
if_data = ifp->info;
- if_data->multicast = IF_ZEBRA_MULTICAST_OFF;
+ if_data->multicast = IF_ZEBRA_DATA_OFF;
return CMD_SUCCESS;
}
if_refresh(ifp);
}
if_data = ifp->info;
- if_data->shutdown = IF_ZEBRA_SHUTDOWN_ON;
+ if_data->shutdown = IF_ZEBRA_DATA_ON;
return 0;
}
if_refresh(ifp);
}
if_data = ifp->info;
- if_data->shutdown = IF_ZEBRA_SHUTDOWN_ON;
+ if_data->shutdown = IF_ZEBRA_DATA_ON;
return CMD_SUCCESS;
}
}
if_data = ifp->info;
- if_data->shutdown = IF_ZEBRA_SHUTDOWN_OFF;
+ if_data->shutdown = IF_ZEBRA_DATA_OFF;
return 0;
}
}
if_data = ifp->info;
- if_data->shutdown = IF_ZEBRA_SHUTDOWN_OFF;
+ if_data->shutdown = IF_ZEBRA_DATA_OFF;
return CMD_SUCCESS;
}
SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
/* In case of this route need to install kernel. */
- if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED)
- && CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)
- && !(if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)) {
+ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) &&
+ CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) &&
+ !(if_data && if_data->shutdown == IF_ZEBRA_DATA_ON)) {
/* Some system need to up the interface to set IP address. */
if (!if_is_up(ifp)) {
if_set_flags(ifp, IFF_UP | IFF_RUNNING);
SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
/* In case of this route need to install kernel. */
- if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED)
- && CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)
- && !(if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)) {
+ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) &&
+ CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) &&
+ !(if_data && if_data->shutdown == IF_ZEBRA_DATA_ON)) {
/* Some system need to up the interface to set IP address. */
if (!if_is_up(ifp)) {
if_set_flags(ifp, IFF_UP | IFF_RUNNING);
SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
/* In case of this route need to install kernel. */
- if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED)
- && CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)
- && !(if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)) {
+ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) &&
+ CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) &&
+ !(if_data && if_data->shutdown == IF_ZEBRA_DATA_ON)) {
/* Some system need to up the interface to set IP address. */
if (!if_is_up(ifp)) {
if_set_flags(ifp, IFF_UP | IFF_RUNNING);
SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
/* In case of this route need to install kernel. */
- if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED)
- && CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)
- && !(if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)) {
+ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) &&
+ CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) &&
+ !(if_data && if_data->shutdown == IF_ZEBRA_DATA_ON)) {
/* Some system need to up the interface to set IP address. */
if (!if_is_up(ifp)) {
if_set_flags(ifp, IFF_UP | IFF_RUNNING);
if_vty_config_start(vty, ifp);
if (if_data) {
- if (if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)
+ if (if_data->shutdown == IF_ZEBRA_DATA_ON)
vty_out(vty, " shutdown\n");
zebra_ptm_if_write(vty, if_data);
}
if (if_data) {
- if (if_data->multicast
- != IF_ZEBRA_MULTICAST_UNSPEC)
+ if (if_data->multicast != IF_ZEBRA_DATA_UNSPEC)
vty_out(vty, " %smulticast\n",
- if_data->multicast
- == IF_ZEBRA_MULTICAST_ON
+ if_data->multicast ==
+ IF_ZEBRA_DATA_ON
? ""
: "no ");
+ if (if_data->mpls == IF_ZEBRA_DATA_ON)
+ vty_out(vty, " mpls\n");
}
hook_call(zebra_if_config_wr, vty, ifp);
install_element(ENABLE_NODE, &show_interface_desc_vrf_all_cmd);
install_element(INTERFACE_NODE, &multicast_cmd);
install_element(INTERFACE_NODE, &no_multicast_cmd);
+ install_element(INTERFACE_NODE, &mpls_cmd);
install_element(INTERFACE_NODE, &linkdetect_cmd);
install_element(INTERFACE_NODE, &no_linkdetect_cmd);
install_element(INTERFACE_NODE, &shutdown_if_cmd);
extern "C" {
#endif
-/* For interface multicast configuration. */
-#define IF_ZEBRA_MULTICAST_UNSPEC 0
-#define IF_ZEBRA_MULTICAST_ON 1
-#define IF_ZEBRA_MULTICAST_OFF 2
-
-/* For interface shutdown configuration. */
-#define IF_ZEBRA_SHUTDOWN_OFF 0
-#define IF_ZEBRA_SHUTDOWN_ON 1
+/* For interface configuration. */
+#define IF_ZEBRA_DATA_UNSPEC 0
+#define IF_ZEBRA_DATA_ON 1
+#define IF_ZEBRA_DATA_OFF 2
#define IF_VLAN_BITMAP_MAX 4096
if (!irdp)
return;
- thread_cancel(&irdp->t_advertise);
+ THREAD_OFF(irdp->t_advertise);
if (ifp->connected)
for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) {
return;
irdp->flags |= IF_SOLICIT;
- thread_cancel(&irdp->t_advertise);
+ THREAD_OFF(irdp->t_advertise);
timer = (frr_weak_random() % MAX_RESPONSE_DELAY) + 1;
#include "zebra/rt_netlink.h"
#include "zebra/if_netlink.h"
#include "zebra/rule_netlink.h"
+#include "zebra/tc_netlink.h"
#include "zebra/netconf_netlink.h"
#include "zebra/zebra_errors.h"
{RTM_NEWTUNNEL, "RTM_NEWTUNNEL"},
{RTM_DELTUNNEL, "RTM_DELTUNNEL"},
{RTM_GETTUNNEL, "RTM_GETTUNNEL"},
+ {RTM_NEWQDISC, "RTM_NEWQDISC"},
+ {RTM_DELQDISC, "RTM_DELQDISC"},
+ {RTM_GETQDISC, "RTM_GETQDISC"},
+ {RTM_NEWTCLASS, "RTM_NEWTCLASS"},
+ {RTM_DELTCLASS, "RTM_DELTCLASS"},
+ {RTM_GETTCLASS, "RTM_GETTCLASS"},
+ {RTM_NEWTFILTER, "RTM_NEWTFILTER"},
+ {RTM_DELTFILTER, "RTM_DELTFILTER"},
+ {RTM_GETTFILTER, "RTM_GETTFILTER"},
{0}};
static const struct message rtproto_str[] = {
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;
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));
case DPLANE_OP_INTF_ADDR_ADD:
case DPLANE_OP_INTF_ADDR_DEL:
- case DPLANE_OP_INTF_NETCONFIG:
case DPLANE_OP_NONE:
return FRR_NETLINK_ERROR;
+ case DPLANE_OP_INTF_NETCONFIG:
+ return netlink_put_intf_netconfig(bth, ctx);
+
case DPLANE_OP_INTF_INSTALL:
case DPLANE_OP_INTF_UPDATE:
case DPLANE_OP_INTF_DELETE:
return netlink_put_intf_update_msg(bth, ctx);
+
+ case DPLANE_OP_TC_INSTALL:
+ case DPLANE_OP_TC_UPDATE:
+ case DPLANE_OP_TC_DELETE:
+ return netlink_put_tc_update_msg(bth, ctx);
}
return FRR_NETLINK_ERROR;
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);
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);
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);
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);
void kernel_terminate(struct zebra_ns *zns, bool complete)
{
- thread_cancel(&zns->t_netlink);
+ THREAD_OFF(zns->t_netlink);
kernel_nlsock_fini(&zns->netlink);
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));
* recover zebra at this point.
*/
exit(-1);
+#endif
}
if (errno != EAGAIN && errno != EWOULDBLOCK)
flog_err_sys(EC_LIB_SOCKET, "routing socket error: %s",
{
struct zebra_dplane_ctx *ctx;
struct dplane_ctx_q handled_list;
- enum zebra_dplane_result res;
+ enum zebra_dplane_result res = ZEBRA_DPLANE_REQUEST_SUCCESS;
TAILQ_INIT(&handled_list);
res = kernel_intf_update(ctx);
break;
+ case DPLANE_OP_TC_INSTALL:
+ case DPLANE_OP_TC_UPDATE:
+ case DPLANE_OP_TC_DELETE:
+ res = kernel_tc_update(ctx);
+ break;
+
/* Ignore 'notifications' - no-op */
case DPLANE_OP_SYS_ROUTE_ADD:
case DPLANE_OP_SYS_ROUTE_DELETE:
res = ZEBRA_DPLANE_REQUEST_SUCCESS;
break;
- default:
- res = ZEBRA_DPLANE_REQUEST_FAILURE;
+ case DPLANE_OP_INTF_NETCONFIG:
+ res = kernel_intf_netconf_update(ctx);
break;
+
+ case DPLANE_OP_NONE:
+ case DPLANE_OP_BR_PORT_UPDATE:
+ case DPLANE_OP_IPTABLE_ADD:
+ case DPLANE_OP_IPTABLE_DELETE:
+ case DPLANE_OP_IPSET_ADD:
+ case DPLANE_OP_IPSET_DELETE:
+ case DPLANE_OP_IPSET_ENTRY_ADD:
+ case DPLANE_OP_IPSET_ENTRY_DELETE:
+ case DPLANE_OP_NEIGH_IP_INSTALL:
+ case DPLANE_OP_NEIGH_IP_DELETE:
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
+ case DPLANE_OP_GRE_SET:
+ case DPLANE_OP_INTF_ADDR_ADD:
+ case DPLANE_OP_INTF_ADDR_DEL:
+ zlog_err("Unhandled dplane data for %s",
+ dplane_op2str(dplane_ctx_get_op(ctx)));
+ res = ZEBRA_DPLANE_REQUEST_FAILURE;
}
skip_one:
/* 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;
// batch_mode = 1;
break;
case 'a':
- allow_delete = 1;
+ zrouter.allow_delete = true;
break;
case 'e': {
unsigned long int parsed_multipath =
#include "linux/netconf.h"
+#include "lib/lib_errors.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_dplane.h"
#include "zebra/kernel_netlink.h"
return netlink_request(nls, &req);
}
+extern struct zebra_privs_t zserv_privs;
+/*
+ * Currently netconf has no ability to set from netlink.
+ * So we've received a request to do this work in the data plane.
+ * as such we need to set the value via the /proc system
+ */
+enum netlink_msg_status netlink_put_intf_netconfig(struct nl_batch *bth,
+ struct zebra_dplane_ctx *ctx)
+{
+ const char *ifname = dplane_ctx_get_ifname(ctx);
+ enum dplane_netconf_status_e mpls_on = dplane_ctx_get_netconf_mpls(ctx);
+ char set[64];
+ char mpls_proc[PATH_MAX];
+ int fd, ret = FRR_NETLINK_ERROR;
+
+ snprintf(mpls_proc, sizeof(mpls_proc),
+ "/proc/sys/net/mpls/conf/%s/input", ifname);
+
+ if (mpls_on == DPLANE_NETCONF_STATUS_ENABLED)
+ snprintf(set, sizeof(set), "1\n");
+ else if (mpls_on == DPLANE_NETCONF_STATUS_DISABLED)
+ snprintf(set, sizeof(set), "0\n");
+ else {
+ flog_err_sys(
+ EC_LIB_DEVELOPMENT,
+ "%s: Expected interface %s to be set to ENABLED or DISABLED was %d",
+ __func__, ifname, mpls_on);
+ return ret;
+ }
+
+ frr_with_privs (&zserv_privs) {
+ fd = open(mpls_proc, O_WRONLY);
+ if (fd < 0) {
+ flog_err_sys(
+ EC_LIB_SOCKET,
+ "%s: Unable to open %s for writing: %s(%d)",
+ __func__, mpls_proc, safe_strerror(errno),
+ errno);
+ return ret;
+ }
+ if (write(fd, set, 2) == 2)
+ ret = FRR_NETLINK_SUCCESS;
+ else
+ flog_err_sys(EC_LIB_SOCKET,
+ "%s: Unsuccessful write to %s: %s(%d)",
+ __func__, mpls_proc, safe_strerror(errno),
+ errno);
+ close(fd);
+ }
+ return ret;
+}
+
#endif /* HAVE_NETLINK */
/* Request info from the host OS. */
int netlink_request_netconf(int sockfd);
+struct nl_batch;
+
+extern enum netlink_msg_status
+netlink_put_intf_netconfig(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
#ifdef __cplusplus
}
int zebra_rib_queue_evpn_rem_vtep_del(vrf_id_t vrf_id, vni_t vni,
struct in_addr vtep_ip);
-extern void meta_queue_free(struct meta_queue *mq);
-extern void rib_meta_queue_free_vrf(struct meta_queue *mq,
- struct zebra_vrf *zvrf);
+extern void meta_queue_free(struct meta_queue *mq, struct zebra_vrf *zvrf);
extern int zebra_rib_labeled_unicast(struct route_entry *re);
extern struct route_table *rib_table_ipv6;
extern enum zebra_dplane_result
kernel_intf_update(struct zebra_dplane_ctx *ctx);
+extern enum zebra_dplane_result
+kernel_intf_netconf_update(struct zebra_dplane_ctx *ctx);
+extern enum zebra_dplane_result kernel_tc_update(struct zebra_dplane_ctx *ctx);
+
#endif /* !HAVE_NETLINK */
extern int kernel_neigh_update(int cmd, int ifindex, void *addr, char *lla,
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;
parse_encap_seg6local(struct rtattr *tb,
struct seg6local_context *ctx)
{
- struct rtattr *tb_encap[256] = {};
+ struct rtattr *tb_encap[SEG6_LOCAL_MAX + 1] = {};
enum seg6local_action_t act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC;
- netlink_parse_rtattr_nested(tb_encap, 256, tb);
+ netlink_parse_rtattr_nested(tb_encap, SEG6_LOCAL_MAX, tb);
if (tb_encap[SEG6_LOCAL_ACTION])
act = *(uint32_t *)RTA_DATA(tb_encap[SEG6_LOCAL_ACTION]);
static int parse_encap_seg6(struct rtattr *tb, struct in6_addr *segs)
{
- struct rtattr *tb_encap[256] = {};
+ struct rtattr *tb_encap[SEG6_IPTUNNEL_MAX + 1] = {};
struct seg6_iptunnel_encap *ipt = NULL;
struct in6_addr *segments = NULL;
- netlink_parse_rtattr_nested(tb_encap, 256, tb);
+ netlink_parse_rtattr_nested(tb_encap, SEG6_IPTUNNEL_MAX, tb);
/*
* TODO: It's not support multiple SID list.
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) {
struct rtmsg *rtm;
struct rtattr *tb[RTA_MAX + 1];
struct mcast_route_data *m;
- struct mcast_route_data mr;
int iif = 0;
int count;
int oif[256];
vrf_id_t vrf;
int table;
- if (mroute)
- m = mroute;
- else {
- memset(&mr, 0, sizeof(mr));
- m = &mr;
- }
+ assert(mroute);
+ m = mroute;
rtm = NLMSG_DATA(h);
return 0;
}
- if (!(rtm->rtm_family == AF_INET ||
- rtm->rtm_family == AF_INET6 ||
- rtm->rtm_family == RTNL_FAMILY_IPMR )) {
+ switch (rtm->rtm_family) {
+ case AF_INET:
+ case AF_INET6:
+ break;
+
+ case RTNL_FAMILY_IPMR:
+ case RTNL_FAMILY_IP6MR:
+ /* notifications on IPMR are irrelevant to zebra, we only care
+ * about responses to RTM_GETROUTE requests we sent.
+ */
+ return 0;
+
+ default:
flog_warn(
EC_ZEBRA_UNKNOWN_FAMILY,
"Invalid address family: %u received from kernel route change: %s",
return -1;
}
+ /* these are "magic" kernel-managed *unicast* routes used for
+ * outputting locally generated multicast traffic (which uses unicast
+ * handling on Linux because ~reasons~.
+ */
if (rtm->rtm_type == RTN_MULTICAST)
- netlink_route_change_read_multicast(h, ns_id, startup);
- else
- netlink_route_change_read_unicast(h, ns_id, startup);
+ return 0;
+
+ netlink_route_change_read_unicast(h, ns_id, startup);
return 0;
}
struct mcast_route_data *mr = (struct mcast_route_data *)in;
struct {
struct nlmsghdr n;
- struct ndmsg ndm;
+ struct rtmsg rtm;
char buf[256];
} req;
zns = zvrf->zns;
memset(&req, 0, sizeof(req));
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid;
req.n.nlmsg_type = RTM_GETROUTE;
- nl_attr_put32(&req.n, sizeof(req), RTA_IIF, mroute->ifindex);
- nl_attr_put32(&req.n, sizeof(req), RTA_OIF, mroute->ifindex);
-
if (mroute->family == AF_INET) {
- req.ndm.ndm_family = RTNL_FAMILY_IPMR;
+ req.rtm.rtm_family = RTNL_FAMILY_IPMR;
+ req.rtm.rtm_dst_len = IPV4_MAX_BITLEN;
+ req.rtm.rtm_src_len = IPV4_MAX_BITLEN;
+
nl_attr_put(&req.n, sizeof(req), RTA_SRC,
&mroute->src.ipaddr_v4,
sizeof(mroute->src.ipaddr_v4));
&mroute->grp.ipaddr_v4,
sizeof(mroute->grp.ipaddr_v4));
} else {
- req.ndm.ndm_family = RTNL_FAMILY_IP6MR;
+ req.rtm.rtm_family = RTNL_FAMILY_IP6MR;
+ req.rtm.rtm_dst_len = IPV6_MAX_BITLEN;
+ req.rtm.rtm_src_len = IPV6_MAX_BITLEN;
+
nl_attr_put(&req.n, sizeof(req), RTA_SRC,
&mroute->src.ipaddr_v6,
sizeof(mroute->src.ipaddr_v6));
* and the kernel goes screw you and the delicious cookies you
* are trying to give me. So now we have this little hack.
*/
- actual_table = (zvrf->table_id == RT_TABLE_MAIN) ? RT_TABLE_DEFAULT :
- zvrf->table_id;
+ if (mroute->family == AF_INET)
+ actual_table = (zvrf->table_id == RT_TABLE_MAIN)
+ ? RT_TABLE_DEFAULT
+ : zvrf->table_id;
+ else
+ actual_table = zvrf->table_id;
+
nl_attr_put32(&req.n, sizeof(req), RTA_TABLE, actual_table);
suc = netlink_talk(netlink_route_change_read_multicast, &req.n,
int sock = -1;
int ret = 0;
struct icmp6_filter filter;
+ int error;
frr_with_privs(&zserv_privs) {
sock = ns_socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, ns_id);
-
+ /*
+ * with privs might set errno too if it fails save
+ * to the side
+ */
+ error = errno;
}
if (sock < 0) {
+ zlog_warn("RTADV socket for ns: %u failure to create: %s(%u)",
+ ns_id, safe_strerror(error), error);
return -1;
}
ret = setsockopt_ipv6_pktinfo(sock, 1);
if (ret < 0) {
+ zlog_warn("RTADV failure to set Packet Information");
close(sock);
return ret;
}
ret = setsockopt_ipv6_multicast_loop(sock, 0);
if (ret < 0) {
+ zlog_warn("RTADV failure to set multicast Loop detection");
close(sock);
return ret;
}
ret = setsockopt_ipv6_unicast_hops(sock, 255);
if (ret < 0) {
+ zlog_warn("RTADV failure to set maximum unicast hops");
close(sock);
return ret;
}
ret = setsockopt_ipv6_multicast_hops(sock, 255);
if (ret < 0) {
+ zlog_warn("RTADV failure to set maximum multicast hops");
close(sock);
return ret;
}
ret = setsockopt_ipv6_hoplimit(sock, 1);
if (ret < 0) {
+ zlog_warn("RTADV failure to set maximum incoming hop limit");
close(sock);
return ret;
}
zebra/rule_netlink.c \
zebra/rule_socket.c \
zebra/table_manager.c \
+ zebra/tc_netlink.c \
+ zebra/tc_socket.c \
zebra/zapi_msg.c \
zebra/zebra_dplane.c \
zebra/zebra_errors.c \
zebra/rtadv.h \
zebra/rule_netlink.h \
zebra/table_manager.h \
+ zebra/tc_netlink.h \
zebra/zapi_msg.h \
zebra/zebra_dplane.h \
zebra/zebra_errors.h \
--- /dev/null
+/*
+ * Zebra Traffic Control (TC) interaction with the kernel using netlink.
+ *
+ * Copyright (C) 2022 Shichu Yang
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#ifdef HAVE_NETLINK
+
+#include <linux/if_ether.h>
+#include <sys/socket.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "vrf.h"
+
+#include <linux/fib_rules.h>
+#include <linux/pkt_cls.h>
+#include <linux/pkt_sched.h>
+#include "zebra/zserv.h"
+#include "zebra/zebra_ns.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/rt.h"
+#include "zebra/interface.h"
+#include "zebra/debug.h"
+#include "zebra/rtadv.h"
+#include "zebra/kernel_netlink.h"
+#include "zebra/tc_netlink.h"
+#include "zebra/zebra_errors.h"
+#include "zebra/zebra_dplane.h"
+#include "zebra/zebra_trace.h"
+
+/* TODO: move these bitflags to zebra_tc.h */
+#define TC_FILTER_SRC_IP (1 << 0)
+#define TC_FILTER_DST_IP (1 << 1)
+#define TC_FILTER_IP_PROTOCOL (1 << 9)
+
+#define TC_FREQ_DEFAULT (100)
+
+#define TC_MAJOR_BASE (0x1000u)
+#define TC_MINOR_NOCLASS (0xffffu)
+
+#define TC_FILTER_MASK (0x8000u)
+
+#define TIME_UNITS_PER_SEC (1000000)
+#define xmittime(r, s) (TIME_UNITS_PER_SEC * ((double)(s) / (double)(r)))
+
+static uint32_t tc_get_freq(void)
+{
+ int freq = 0;
+ FILE *fp = fopen("/proc/net/psched", "r");
+
+ if (fp) {
+ uint32_t nom, denom;
+
+ if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2) {
+ if (nom == 1000000)
+ freq = denom;
+ }
+ fclose(fp);
+ }
+
+ return freq == 0 ? TC_FREQ_DEFAULT : freq;
+}
+
+static inline uint32_t tc_make_handle(uint16_t major, uint16_t minor)
+{
+ return (major) << 16 | (minor);
+}
+
+static inline uint32_t tc_get_handle(struct zebra_dplane_ctx *ctx,
+ uint16_t minor)
+{
+ uint16_t major = TC_MAJOR_BASE + (uint16_t)dplane_ctx_get_ifindex(ctx);
+
+ return tc_make_handle(major, minor);
+}
+
+static void tc_calc_rate_table(struct tc_ratespec *ratespec, uint32_t *table,
+ uint32_t mtu)
+{
+ if (mtu == 0)
+ mtu = 2047;
+
+ int cell_log = -1;
+
+ if (cell_log < 0) {
+ cell_log = 0;
+ while ((mtu >> cell_log) > 255)
+ cell_log++;
+ }
+
+ for (int i = 0; i < 256; i++)
+ table[i] = xmittime(ratespec->rate, (i + 1) << cell_log);
+
+ ratespec->cell_align = -1;
+ ratespec->cell_log = cell_log;
+ ratespec->linklayer = TC_LINKLAYER_ETHERNET;
+}
+
+static int tc_flower_get_inet_prefix(const struct prefix *prefix,
+ struct inet_prefix *addr)
+{
+ addr->family = prefix->family;
+
+ if (addr->family == AF_INET) {
+ addr->bytelen = 4;
+ addr->bitlen = prefix->prefixlen;
+ addr->flags = 0;
+ addr->flags |= PREFIXLEN_SPECIFIED;
+ addr->flags |= ADDRTYPE_INET;
+ memcpy(addr->data, prefix->u.val32, sizeof(prefix->u.val32));
+ } else if (addr->family == AF_INET6) {
+ addr->bytelen = 16;
+ addr->bitlen = prefix->prefixlen;
+ addr->flags = 0;
+ addr->flags |= PREFIXLEN_SPECIFIED;
+ addr->flags |= ADDRTYPE_INET;
+ memcpy(addr->data, prefix->u.val, sizeof(prefix->u.val));
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int tc_flower_get_inet_mask(const struct prefix *prefix,
+ struct inet_prefix *addr)
+{
+ addr->family = prefix->family;
+
+ if (addr->family == AF_INET) {
+ addr->bytelen = 4;
+ addr->bitlen = prefix->prefixlen;
+ addr->flags = 0;
+ addr->flags |= PREFIXLEN_SPECIFIED;
+ addr->flags |= ADDRTYPE_INET;
+ } else if (addr->family == AF_INET6) {
+ addr->bytelen = 16;
+ addr->bitlen = prefix->prefixlen;
+ addr->flags = 0;
+ addr->flags |= PREFIXLEN_SPECIFIED;
+ addr->flags |= ADDRTYPE_INET;
+ } else {
+ return -1;
+ }
+
+ memset(addr->data, 0xff, addr->bytelen);
+
+ int rest = prefix->prefixlen;
+
+ for (int i = 0; i < addr->bytelen / 4; i++) {
+ if (!rest) {
+ addr->data[i] = 0;
+ } else if (rest / 32 >= 1) {
+ rest -= 32;
+ } else {
+ addr->data[i] <<= 32 - rest;
+ addr->data[i] = htonl(addr->data[i]);
+ rest = 0;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Traffic control queue discipline encoding (only "htb" supported)
+ */
+static ssize_t netlink_qdisc_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
+ void *data, size_t datalen)
+{
+ struct nlsock *nl;
+
+ const char *kind = "htb";
+
+ struct tc_htb_glob htb_glob = {
+ .rate2quantum = 10, .version = 3, .defcls = TC_MINOR_NOCLASS};
+
+ struct rtattr *nest;
+
+ struct {
+ struct nlmsghdr n;
+ struct tcmsg t;
+ char buf[0];
+ } *req = (void *)data;
+
+ if (datalen < sizeof(*req))
+ return 0;
+
+ nl = kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx));
+
+ memset(req, 0, sizeof(*req));
+
+ req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
+ req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+
+ req->n.nlmsg_flags |= NLM_F_REPLACE;
+
+ req->n.nlmsg_type = cmd;
+
+ req->n.nlmsg_pid = nl->snl.nl_pid;
+
+ req->t.tcm_family = AF_UNSPEC;
+ req->t.tcm_ifindex = dplane_ctx_get_ifindex(ctx);
+ req->t.tcm_handle = tc_get_handle(ctx, 0);
+ req->t.tcm_parent = TC_H_ROOT;
+
+ nl_attr_put(&req->n, datalen, TCA_KIND, kind, strlen(kind) + 1);
+
+ nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS);
+
+ nl_attr_put(&req->n, datalen, TCA_HTB_INIT, &htb_glob,
+ sizeof(htb_glob));
+ nl_attr_nest_end(&req->n, nest);
+
+ return NLMSG_ALIGN(req->n.nlmsg_len);
+}
+
+/*
+ * Traffic control class encoding
+ */
+static ssize_t netlink_tclass_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
+ void *data, size_t datalen)
+{
+ struct nlsock *nl;
+ struct tc_htb_opt htb_opt = {};
+
+ uint64_t rate, ceil;
+ uint64_t buffer, cbuffer;
+
+ /* TODO: fetch mtu from interface */
+ uint32_t mtu = 0;
+
+ uint32_t rtab[256];
+ uint32_t ctab[256];
+
+ struct rtattr *nest;
+
+ struct {
+ struct nlmsghdr n;
+ struct tcmsg t;
+ char buf[0];
+ } *req = (void *)data;
+
+ if (datalen < sizeof(*req))
+ return 0;
+
+ nl = kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx));
+
+ memset(req, 0, sizeof(*req));
+
+ req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
+ req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+
+ req->n.nlmsg_type = cmd;
+
+ req->n.nlmsg_pid = nl->snl.nl_pid;
+
+ req->t.tcm_family = AF_UNSPEC;
+ req->t.tcm_ifindex = dplane_ctx_get_ifindex(ctx);
+ req->t.tcm_handle = tc_get_handle(ctx, 1);
+ req->t.tcm_parent = tc_get_handle(ctx, 0);
+
+ rate = dplane_ctx_tc_get_rate(ctx);
+ ceil = dplane_ctx_tc_get_ceil(ctx);
+
+ ceil = ceil < rate ? rate : ceil;
+
+ htb_opt.rate.rate = (rate >> 32 != 0) ? ~0U : rate;
+ htb_opt.ceil.rate = (ceil >> 32 != 0) ? ~0U : ceil;
+
+ buffer = rate / tc_get_freq(), cbuffer = ceil / tc_get_freq();
+
+ htb_opt.buffer = buffer;
+ htb_opt.cbuffer = cbuffer;
+
+ tc_calc_rate_table(&htb_opt.rate, rtab, mtu);
+ tc_calc_rate_table(&htb_opt.ceil, ctab, mtu);
+
+ htb_opt.ceil.mpu = htb_opt.rate.mpu = 0;
+ htb_opt.ceil.overhead = htb_opt.rate.overhead = 0;
+
+ nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS);
+
+ if (rate >> 32 != 0) {
+ nl_attr_put(&req->n, datalen, TCA_HTB_CEIL64, &rate,
+ sizeof(rate));
+ }
+
+ if (ceil >> 32 != 0) {
+ nl_attr_put(&req->n, datalen, TCA_HTB_CEIL64, &ceil,
+ sizeof(ceil));
+ }
+
+ nl_attr_put(&req->n, datalen, TCA_HTB_PARMS, &htb_opt, sizeof(htb_opt));
+
+ nl_attr_put(&req->n, datalen, TCA_HTB_RTAB, rtab, sizeof(rtab));
+ nl_attr_put(&req->n, datalen, TCA_HTB_CTAB, ctab, sizeof(ctab));
+ nl_attr_nest_end(&req->n, nest);
+
+ return NLMSG_ALIGN(req->n.nlmsg_len);
+}
+
+/*
+ * Traffic control filter encoding (only "flower" supported)
+ */
+static ssize_t netlink_tfilter_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
+ void *data, size_t datalen)
+{
+ struct nlsock *nl;
+ struct rtattr *nest;
+
+ const char *kind = "flower";
+
+ uint16_t priority;
+ uint16_t protocol;
+ uint32_t classid;
+ uint32_t filter_bm;
+ uint32_t flags = 0;
+
+ struct inet_prefix addr;
+
+ struct {
+ struct nlmsghdr n;
+ struct tcmsg t;
+ char buf[0];
+ } *req = (void *)data;
+
+ if (datalen < sizeof(*req))
+ return 0;
+
+ nl = kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx));
+
+ memset(req, 0, sizeof(*req));
+
+ req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
+ req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+
+ req->n.nlmsg_flags |= NLM_F_EXCL;
+
+ req->n.nlmsg_type = cmd;
+
+ req->n.nlmsg_pid = nl->snl.nl_pid;
+
+ req->t.tcm_family = AF_UNSPEC;
+ req->t.tcm_ifindex = dplane_ctx_get_ifindex(ctx);
+
+ /* TODO: priority and layer-3 protocol support */
+ priority = 0;
+ protocol = htons(ETH_P_IP);
+ classid = tc_get_handle(ctx, 1);
+ filter_bm = dplane_ctx_tc_get_filter_bm(ctx);
+
+ req->t.tcm_info = tc_make_handle(priority, protocol);
+
+ req->t.tcm_handle = 1;
+ req->t.tcm_parent = tc_get_handle(ctx, 0);
+
+ nl_attr_put(&req->n, datalen, TCA_KIND, kind, strlen(kind) + 1);
+ nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS);
+
+ nl_attr_put(&req->n, datalen, TCA_FLOWER_CLASSID, &classid,
+ sizeof(classid));
+
+ if (filter_bm & TC_FILTER_SRC_IP) {
+ const struct prefix *src_p = dplane_ctx_tc_get_src_ip(ctx);
+
+ if (tc_flower_get_inet_prefix(src_p, &addr) != 0)
+ return 0;
+
+ nl_attr_put(&req->n, datalen,
+ (addr.family == AF_INET) ? TCA_FLOWER_KEY_IPV4_SRC
+ : TCA_FLOWER_KEY_IPV6_SRC,
+ addr.data, addr.bytelen);
+
+ if (tc_flower_get_inet_mask(src_p, &addr) != 0)
+ return 0;
+
+ nl_attr_put(&req->n, datalen,
+ (addr.family == AF_INET)
+ ? TCA_FLOWER_KEY_IPV4_SRC_MASK
+ : TCA_FLOWER_KEY_IPV6_SRC_MASK,
+ addr.data, addr.bytelen);
+ }
+
+ if (filter_bm & TC_FILTER_DST_IP) {
+ const struct prefix *dst_p = dplane_ctx_tc_get_dst_ip(ctx);
+
+ if (tc_flower_get_inet_prefix(dst_p, &addr) != 0)
+ return 0;
+
+ nl_attr_put(&req->n, datalen,
+ (addr.family == AF_INET) ? TCA_FLOWER_KEY_IPV4_DST
+ : TCA_FLOWER_KEY_IPV6_DST,
+ addr.data, addr.bytelen);
+
+ if (tc_flower_get_inet_mask(dst_p, &addr) != 0)
+ return 0;
+
+ nl_attr_put(&req->n, datalen,
+ (addr.family == AF_INET)
+ ? TCA_FLOWER_KEY_IPV4_DST_MASK
+ : TCA_FLOWER_KEY_IPV6_DST_MASK,
+ addr.data, addr.bytelen);
+ }
+
+ if (filter_bm & TC_FILTER_IP_PROTOCOL) {
+ nl_attr_put8(&req->n, datalen, TCA_FLOWER_KEY_IP_PROTO,
+ dplane_ctx_tc_get_ip_proto(ctx));
+ }
+
+ nl_attr_put32(&req->n, datalen, TCA_FLOWER_FLAGS, flags);
+
+ nl_attr_put16(&req->n, datalen, TCA_FLOWER_KEY_ETH_TYPE, protocol);
+ nl_attr_nest_end(&req->n, nest);
+
+ return NLMSG_ALIGN(req->n.nlmsg_len);
+}
+
+static ssize_t netlink_newqdisc_msg_encoder(struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen)
+{
+ return netlink_qdisc_msg_encode(RTM_NEWQDISC, ctx, buf, buflen);
+}
+
+static ssize_t netlink_newtclass_msg_encoder(struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen)
+{
+ return netlink_tclass_msg_encode(RTM_NEWTCLASS, ctx, buf, buflen);
+}
+
+static ssize_t netlink_newtfilter_msg_encoder(struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen)
+{
+ return netlink_tfilter_msg_encode(RTM_NEWTFILTER, ctx, buf, buflen);
+}
+
+enum netlink_msg_status netlink_put_tc_update_msg(struct nl_batch *bth,
+ struct zebra_dplane_ctx *ctx)
+{
+ /* TODO: error handling and other actions (delete, replace, ...) */
+
+ netlink_batch_add_msg(bth, ctx, netlink_newqdisc_msg_encoder, false);
+ netlink_batch_add_msg(bth, ctx, netlink_newtclass_msg_encoder, false);
+ return netlink_batch_add_msg(bth, ctx, netlink_newtfilter_msg_encoder,
+ false);
+}
+
+#endif /* HAVE_NETLINK */
--- /dev/null
+/*
+ * Zebra Traffic Control (TC) interaction with the kernel using netlink.
+ *
+ * Copyright (C) 2022 Shichu Yang
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_TC_NETLINK_H
+#define _ZEBRA_TC_NETLINK_H
+
+#ifdef HAVE_NETLINK
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Represent a prefixed address in flower filter */
+
+struct inet_prefix {
+ uint16_t flags;
+ uint16_t bytelen;
+ uint16_t bitlen;
+ uint16_t family;
+ uint32_t data[64];
+};
+
+enum {
+ PREFIXLEN_SPECIFIED = (1 << 0),
+ ADDRTYPE_INET = (1 << 1),
+ ADDRTYPE_UNSPEC = (1 << 2),
+ ADDRTYPE_MULTI = (1 << 3),
+
+ ADDRTYPE_INET_UNSPEC = ADDRTYPE_INET | ADDRTYPE_UNSPEC,
+ ADDRTYPE_INET_MULTI = ADDRTYPE_INET | ADDRTYPE_MULTI
+};
+
+extern enum netlink_msg_status
+netlink_put_tc_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAVE_NETLINK */
+
+#endif /* _ZEBRA_TC_NETLINK_H */
--- /dev/null
+/*
+ * Zebra Traffic Control (TC) interaction with the kernel using socket.
+ *
+ * Copyright (C) 2022 Shichu Yang
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#ifndef HAVE_NETLINK
+
+#include "lib_errors.h"
+
+#include "zebra/rt.h"
+#include "zebra/zebra_dplane.h"
+#include "zebra/zebra_errors.h"
+
+enum zebra_dplane_result kernel_tc_update(struct zebra_dplane_ctx *ctx)
+{
+ flog_err(EC_LIB_UNAVAILABLE, "%s not Implemented for this platform",
+ __func__);
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
+}
+
+#endif /* !HAVE_NETLINK */
{
struct stream *s;
struct zapi_labels zl;
- int ret;
/* Get input stream. */
s = msg;
if (zapi_labels_validate(&zl) < 0)
return;
- ret = mpls_zapi_labels_process(true, zvrf, &zl);
- if (ret < 0) {
- if (IS_ZEBRA_DEBUG_RECV)
- zlog_debug("%s: Error processing zapi request",
- __func__);
- }
+ mpls_zapi_labels_process(true, zvrf, &zl);
}
/*
{
struct stream *s;
struct zapi_labels zl;
- int ret;
/* Get input stream. */
s = msg;
return;
if (zl.nexthop_num > 0) {
- ret = mpls_zapi_labels_process(false /*delete*/, zvrf, &zl);
- if (ret < 0) {
- if (IS_ZEBRA_DEBUG_RECV)
- zlog_debug("%s: Error processing zapi request",
- __func__);
- }
+ mpls_zapi_labels_process(false /*delete*/, zvrf, &zl);
} else {
mpls_lsp_uninstall_all_vrf(zvrf, zl.type, zl.local_label);
enum dplane_netconf_status_e linkdown_val;
};
+/*
+ * Traffic control contexts for the dplane
+ */
+struct dplane_tc_info {
+ /* Rate spec (unit: Bytes/s) */
+ uint64_t rate;
+ uint64_t ceil;
+
+ /* TODO: custom burst */
+
+ /* Filter components for "tfilter" */
+ uint32_t filter_bm;
+ struct prefix src_ip;
+ struct prefix dst_ip;
+ uint8_t ip_proto;
+
+ /* TODO: more filter components */
+};
+
/*
* The context block used to exchange info about route updates across
* the boundary between the zebra main context (and pthread) and the
struct dplane_mac_info macinfo;
struct dplane_neigh_info neigh;
struct dplane_rule_info rule;
+ struct dplane_tc_info tc;
struct zebra_pbr_iptable iptable;
struct zebra_pbr_ipset ipset;
struct {
_Atomic uint32_t dg_intf_addrs_in;
_Atomic uint32_t dg_intf_addr_errors;
+ _Atomic uint32_t dg_intf_changes;
+ _Atomic uint32_t dg_intf_changes_errors;
_Atomic uint32_t dg_macs_in;
_Atomic uint32_t dg_mac_errors;
_Atomic uint32_t dg_intfs_in;
_Atomic uint32_t dg_intf_errors;
+ _Atomic uint32_t dg_tcs_in;
+ _Atomic uint32_t dg_tcs_errors;
+
/* Dataplane pthread */
struct frr_pthread *dg_pthread;
case DPLANE_OP_INTF_INSTALL:
case DPLANE_OP_INTF_UPDATE:
case DPLANE_OP_INTF_DELETE:
+ case DPLANE_OP_TC_INSTALL:
+ case DPLANE_OP_TC_UPDATE:
+ case DPLANE_OP_TC_DELETE:
break;
case DPLANE_OP_IPSET_ENTRY_ADD:
case DPLANE_OP_INTF_DELETE:
ret = "INTF_DELETE";
break;
+
+ case DPLANE_OP_TC_INSTALL:
+ ret = "TC_INSTALL";
+ break;
+ case DPLANE_OP_TC_UPDATE:
+ ret = "TC_UPDATE";
+ break;
+ case DPLANE_OP_TC_DELETE:
+ ret = "TC_DELETE";
+ break;
}
return ret;
return ctx->u.rinfo.zd_old_distance;
}
+uint64_t dplane_ctx_tc_get_rate(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc.rate;
+}
+
+uint64_t dplane_ctx_tc_get_ceil(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc.ceil;
+}
+
+uint32_t dplane_ctx_tc_get_filter_bm(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc.filter_bm;
+}
+
+const struct prefix *
+dplane_ctx_tc_get_src_ip(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.tc.src_ip);
+}
+
+const struct prefix *
+dplane_ctx_tc_get_dst_ip(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.tc.dst_ip);
+}
+
+uint8_t dplane_ctx_tc_get_ip_proto(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc.ip_proto;
+}
+
/*
* Set the nexthops associated with a context: note that processing code
* may well expect that nexthops are in canonical (sorted) order, so we
return ret;
}
+int dplane_ctx_tc_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op)
+{
+ int ret = EINVAL;
+
+ struct zebra_ns *zns = NULL;
+
+ ctx->zd_op = op;
+ ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
+
+ /* TODO: init traffic control qdisc */
+ zns = zebra_ns_lookup(NS_DEFAULT);
+
+ dplane_ctx_ns_init(ctx, zns, true);
+
+ ret = AOK;
+
+ return ret;
+}
+
/**
* dplane_ctx_nexthop_init() - Initialize a context block for a nexthop update
*
return result;
}
+static enum zebra_dplane_result dplane_tc_update_internal(enum dplane_op_e op)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ int ret = EINVAL;
+ struct zebra_dplane_ctx *ctx = NULL;
+
+ /* Obtain context block */
+ ctx = dplane_ctx_alloc();
+
+ if (!ctx) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Init context with info from zebra data structs */
+ ret = dplane_ctx_tc_init(ctx, op);
+
+ if (ret == AOK)
+ ret = dplane_update_enqueue(ctx);
+
+done:
+ /* Update counter */
+ atomic_fetch_add_explicit(&zdplane_info.dg_tcs_in, 1,
+ memory_order_relaxed);
+ if (ret == AOK) {
+ result = ZEBRA_DPLANE_REQUEST_QUEUED;
+ } else {
+ atomic_fetch_add_explicit(&zdplane_info.dg_tcs_errors, 1,
+ memory_order_relaxed);
+ if (ctx)
+ dplane_ctx_free(&ctx);
+ }
+
+ return result;
+}
+
+enum zebra_dplane_result dplane_tc_update(void)
+{
+ return dplane_tc_update_internal(DPLANE_OP_TC_UPDATE);
+}
+
/**
* dplane_nexthop_update_internal() - Helper for enqueuing nexthop changes
*
dplane_nexthop_update_internal(struct nhg_hash_entry *nhe, enum dplane_op_e op)
{
enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
- int ret = EINVAL;
+ int ret;
struct zebra_dplane_ctx *ctx = NULL;
/* Obtain context block */
struct zebra_dplane_ctx *notif_ctx)
{
enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
- int ret = EINVAL;
+ int ret;
struct zebra_dplane_ctx *ctx = NULL;
struct nhlfe_list_head *head;
struct zebra_nhlfe *nhlfe, *new_nhlfe;
return result;
}
+enum zebra_dplane_result
+dplane_intf_mpls_modify_state(const struct interface *ifp, bool set)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ struct zebra_dplane_ctx *ctx;
+ struct zebra_ns *zns;
+ int ret = EINVAL;
+
+ ctx = dplane_ctx_alloc();
+ ctx->zd_op = DPLANE_OP_INTF_NETCONFIG;
+ ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
+ ctx->zd_vrf_id = ifp->vrf->vrf_id;
+ strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
+
+ zns = zebra_ns_lookup(ifp->vrf->vrf_id);
+ dplane_ctx_ns_init(ctx, zns, false);
+
+ ctx->zd_ifindex = ifp->ifindex;
+ if (set)
+ dplane_ctx_set_netconf_mpls(ctx, DPLANE_NETCONF_STATUS_ENABLED);
+ else
+ dplane_ctx_set_netconf_mpls(ctx,
+ DPLANE_NETCONF_STATUS_DISABLED);
+ /* Increment counter */
+ atomic_fetch_add_explicit(&zdplane_info.dg_intf_changes, 1,
+ memory_order_relaxed);
+
+ ret = dplane_update_enqueue(ctx);
+
+ if (ret == AOK)
+ result = ZEBRA_DPLANE_REQUEST_QUEUED;
+ else {
+ /* Error counter */
+ atomic_fetch_add_explicit(&zdplane_info.dg_intf_changes_errors,
+ 1, memory_order_relaxed);
+ dplane_ctx_free(&ctx);
+ }
+
+ return result;
+}
+
/*
* Enqueue interface address add for the dataplane.
*/
dplane_intf_update_internal(const struct interface *ifp, enum dplane_op_e op)
{
enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
- int ret = EINVAL;
+ int ret;
struct zebra_dplane_ctx *ctx = NULL;
/* Obtain context block */
vty_out(vty, "Intf addr updates: %"PRIu64"\n", incoming);
vty_out(vty, "Intf addr errors: %"PRIu64"\n", errs);
+ incoming = atomic_load_explicit(&zdplane_info.dg_intf_changes,
+ memory_order_relaxed);
+ errs = atomic_load_explicit(&zdplane_info.dg_intf_changes_errors,
+ memory_order_relaxed);
+ vty_out(vty, "Intf change updates: %" PRIu64 "\n", incoming);
+ vty_out(vty, "Intf change errors: %" PRIu64 "\n", errs);
+
incoming = atomic_load_explicit(&zdplane_info.dg_macs_in,
memory_order_relaxed);
errs = atomic_load_explicit(&zdplane_info.dg_mac_errors,
dplane_ctx_get_ifindex(ctx),
dplane_ctx_intf_is_protodown(ctx));
break;
+
+ /* TODO: more detailed log */
+ case DPLANE_OP_TC_INSTALL:
+ case DPLANE_OP_TC_UPDATE:
+ case DPLANE_OP_TC_DELETE:
+ zlog_debug("Dplane tc ifidx %u", dplane_ctx_get_ifindex(ctx));
+ break;
}
}
1, memory_order_relaxed);
break;
+ case DPLANE_OP_TC_INSTALL:
+ case DPLANE_OP_TC_UPDATE:
+ case DPLANE_OP_TC_DELETE:
+ if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
+ atomic_fetch_add_explicit(&zdplane_info.dg_tcs_errors,
+ 1, memory_order_relaxed);
+ break;
+
/* Ignore 'notifications' - no-op */
case DPLANE_OP_SYS_ROUTE_ADD:
case DPLANE_OP_SYS_ROUTE_DELETE:
zns_info_list_del(&zdplane_info.dg_zns_list, zi);
if (zdplane_info.dg_master) {
- thread_cancel(&zi->t_read);
- thread_cancel(&zi->t_request);
+ THREAD_OFF(zi->t_read);
+ THREAD_OFF(zi->t_request);
}
XFREE(MTYPE_DP_NS, zi);
DPLANE_OP_INTF_INSTALL,
DPLANE_OP_INTF_UPDATE,
DPLANE_OP_INTF_DELETE,
+
+ /* Traffic control */
+ DPLANE_OP_TC_INSTALL,
+ DPLANE_OP_TC_UPDATE,
+ DPLANE_OP_TC_DELETE,
};
/*
void dplane_ctx_set_distance(struct zebra_dplane_ctx *ctx, uint8_t distance);
uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx);
+/* Accessors for traffic control context */
+uint64_t dplane_ctx_tc_get_rate(const struct zebra_dplane_ctx *ctx);
+uint64_t dplane_ctx_tc_get_ceil(const struct zebra_dplane_ctx *ctx);
+uint32_t dplane_ctx_tc_get_filter_bm(const struct zebra_dplane_ctx *ctx);
+const struct prefix *
+dplane_ctx_tc_get_src_ip(const struct zebra_dplane_ctx *ctx);
+const struct prefix *
+dplane_ctx_tc_get_dst_ip(const struct zebra_dplane_ctx *ctx);
+uint8_t dplane_ctx_tc_get_ip_proto(const struct zebra_dplane_ctx *ctx);
+
void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh);
void dplane_ctx_set_backup_nhg(struct zebra_dplane_ctx *ctx,
const struct nexthop_group *nhg);
enum zebra_dplane_result dplane_pw_install(struct zebra_pw *pw);
enum zebra_dplane_result dplane_pw_uninstall(struct zebra_pw *pw);
+enum zebra_dplane_result
+dplane_intf_mpls_modify_state(const struct interface *ifp, const bool set);
/*
* Enqueue interface address changes for the dataplane.
*/
enum zebra_dplane_result dplane_intf_update(const struct interface *ifp);
enum zebra_dplane_result dplane_intf_delete(const struct interface *ifp);
+/*
+ * Enqueue interface link changes for the dataplane.
+ */
+enum zebra_dplane_result dplane_tc_add(void);
+enum zebra_dplane_result dplane_tc_update(void);
+enum zebra_dplane_result dplane_tc_delete(void);
+
/*
* Link layer operations for the dataplane.
*/
int dplane_ctx_intf_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
const struct interface *ifp);
+/* Encode traffic control information into data plane context. */
+int dplane_ctx_tc_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op);
+
/* Retrieve the limit on the number of pending, unprocessed updates. */
uint32_t dplane_get_in_queue_limit(void);
: "",
CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE) ? "DUP " : "",
CHECK_FLAG(mac->flags, ZEBRA_MAC_FPM_SENT) ? "FPM " : "",
- CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE) ? "LOC Active "
- : "",
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE)
+ ? "PEER Active "
+ : "",
CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY) ? "PROXY " : "",
CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)
? "LOC Inactive "
n->flags |= ZEBRA_NEIGH_LOCAL_INACTIVE;
}
- if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
- SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY);
- else
- SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE);
-
if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) {
SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY);
/* if the neigh was peer-active previously we
*/
static inline void zfpm_read_off(void)
{
- thread_cancel(&zfpm_g->t_read);
+ THREAD_OFF(zfpm_g->t_read);
}
/*
*/
static inline void zfpm_write_off(void)
{
- thread_cancel(&zfpm_g->t_write);
+ THREAD_OFF(zfpm_g->t_write);
}
static inline void zfpm_connect_off(void)
{
- thread_cancel(&zfpm_g->t_connect);
+ THREAD_OFF(zfpm_g->t_connect);
}
/*
/*
* Start thread to push existing routes to the FPM.
*/
- thread_cancel(&zfpm_g->t_conn_up);
+ THREAD_OFF(zfpm_g->t_conn_up);
zfpm_rnodes_iter_init(&zfpm_g->t_conn_up_state.iter);
zfpm_g->fpm_mac_dump_done = false;
return;
zfpm_debug("Stopping existing stats timer");
- thread_cancel(&zfpm_g->t_stats);
+ THREAD_OFF(zfpm_g->t_stats);
}
/*
DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object");
DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object");
-int mpls_enabled;
+bool mpls_enabled;
bool mpls_pw_reach_strict; /* Strict reachability checking */
/* static function declarations */
struct zebra_lsp *lsp;
struct hash *lsp_table;
struct zebra_nhlfe *nhlfe;
- bool in_shutdown = false;
/* If zebra is shutting down, don't delete any structs,
* just ignore this callback. The LSPs will be cleaned up
* during the shutdown processing.
*/
- in_shutdown = atomic_load_explicit(&zrouter.in_shutdown,
- memory_order_relaxed);
- if (in_shutdown)
+ if (zebra_router_in_shutdown())
return;
zvrf = vrf_info_lookup(VRF_DEFAULT);
lsp_free(lsp_table, plsp);
}
+static void lsp_free_nhlfe(struct zebra_lsp *lsp)
+{
+ struct zebra_nhlfe *nhlfe;
+
+ while ((nhlfe = nhlfe_list_first(&lsp->nhlfe_list))) {
+ nhlfe_list_del(&lsp->nhlfe_list, nhlfe);
+ nhlfe_free(nhlfe);
+ }
+
+ while ((nhlfe = nhlfe_list_first(&lsp->backup_nhlfe_list))) {
+ nhlfe_list_del(&lsp->backup_nhlfe_list, nhlfe);
+ nhlfe_free(nhlfe);
+ }
+}
+
/*
* Dtor for an LSP: remove from ile hash, release any internal allocations,
* free LSP object.
static void lsp_free(struct hash *lsp_table, struct zebra_lsp **plsp)
{
struct zebra_lsp *lsp;
- struct zebra_nhlfe *nhlfe;
if (plsp == NULL || *plsp == NULL)
return;
zlog_debug("Free LSP in-label %u flags 0x%x",
lsp->ile.in_label, lsp->flags);
- /* Free nhlfes, if any. */
- frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe)
- nhlfe_del(nhlfe);
-
- /* Free backup nhlfes, if any. */
- frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe)
- nhlfe_del(nhlfe);
+ lsp_free_nhlfe(lsp);
hash_release(lsp_table, &lsp->ile);
XFREE(MTYPE_LSP, lsp);
/*
* Initialize work queue for processing changed LSPs.
*/
-static int mpls_processq_init(void)
+static void mpls_processq_init(void)
{
zrouter.lsp_process_q = work_queue_new(zrouter.master, "LSP processing");
- if (!zrouter.lsp_process_q) {
- flog_err(EC_ZEBRA_WQ_NONEXISTENT,
- "%s: could not initialise work queue!", __func__);
- return -1;
- }
zrouter.lsp_process_q->spec.workfunc = &lsp_process;
zrouter.lsp_process_q->spec.del_item_data = &lsp_processq_del;
zrouter.lsp_process_q->spec.completion_func = &lsp_processq_complete;
zrouter.lsp_process_q->spec.max_retries = 0;
zrouter.lsp_process_q->spec.hold = 10;
-
- return 0;
}
break;
} /* Switch */
-
- dplane_ctx_fini(&ctx);
}
/*
/* Look for zebra LSP object */
zvrf = vrf_info_lookup(VRF_DEFAULT);
if (zvrf == NULL)
- goto done;
+ return;
lsp_table = zvrf->lsp_table;
if (is_debug)
zlog_debug("dplane LSP notif: in-label %u not found",
dplane_ctx_get_in_label(ctx));
- goto done;
+ return;
}
/*
UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
clear_nhlfe_installed(lsp);
}
-
-done:
- dplane_ctx_fini(&ctx);
}
/*
return true;
}
-int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
- struct prefix *prefix, uint8_t route_type,
- unsigned short route_instance)
+void mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
+ struct prefix *prefix, uint8_t route_type,
+ unsigned short route_instance)
{
struct route_table *table;
struct route_node *rn;
/* Lookup table. */
table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
if (!table)
- return -1;
+ return;
/* Lookup existing route */
rn = route_node_get(table, prefix);
break;
}
if (re == NULL)
- return -1;
+ return;
/*
* Nexthops are now shared by multiple routes, so we have to make
zebra_nhg_free(new_nhe);
rib_queue_add(rn);
-
- return 0;
}
/*
* There are several changes that need to be made, in several zebra
* data structures, so we want to do all the work required at once.
*/
-int mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
- const struct zapi_labels *zl)
+void mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
+ const struct zapi_labels *zl)
{
int i, counter, ret = 0;
char buf[NEXTHOP_STRLEN];
/* Lookup table. */
lsp_table = zvrf->lsp_table;
if (!lsp_table)
- return -1;
+ return;
/* Find or create LSP object */
tmp_ile.in_label = zl->local_label;
if (new_nhe)
zebra_nhg_free(new_nhe);
-
- return ret;
}
/*
*/
if (nhlfe_list_first(&lsp->nhlfe_list) == NULL) {
lsp = hash_release(slsp_table, &tmp_ile);
+ lsp_free_nhlfe(lsp);
XFREE(MTYPE_LSP, lsp);
}
}
}
+static void lsp_table_free(void *p)
+{
+ struct zebra_lsp *lsp = p;
+
+ lsp_free_nhlfe(lsp);
+
+ XFREE(MTYPE_LSP, lsp);
+}
+
/*
* Called upon process exiting, need to delete LSP forwarding
* entries from the kernel.
void zebra_mpls_close_tables(struct zebra_vrf *zvrf)
{
hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
- hash_clean(zvrf->lsp_table, NULL);
+ hash_clean(zvrf->lsp_table, lsp_table_free);
hash_free(zvrf->lsp_table);
- hash_clean(zvrf->slsp_table, NULL);
+ hash_clean(zvrf->slsp_table, lsp_table_free);
hash_free(zvrf->slsp_table);
route_table_finish(zvrf->fec_table[AFI_IP]);
route_table_finish(zvrf->fec_table[AFI_IP6]);
zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
}
+void zebra_mpls_turned_on(void)
+{
+ if (!mpls_enabled) {
+ mpls_processq_init();
+ mpls_enabled = true;
+ }
+
+ hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client);
+ hook_register(zserv_client_close, zebra_mpls_cleanup_zclient_labels);
+}
+
/*
* Global MPLS initialization.
*/
void zebra_mpls_init(void)
{
- mpls_enabled = 0;
+ mpls_enabled = false;
mpls_pw_reach_strict = false;
if (mpls_kernel_init() < 0) {
return;
}
- if (!mpls_processq_init())
- mpls_enabled = 1;
-
- hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client);
- hook_register(zserv_client_close, zebra_mpls_cleanup_zclient_labels);
+ zebra_mpls_turned_on();
}
* Handle zapi request to install/uninstall LSP and
* (optionally) FEC-To-NHLFE (FTN) bindings.
*/
-int mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
- const struct zapi_labels *zl);
+void mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
+ const struct zapi_labels *zl);
/*
* Uninstall all NHLFEs bound to a single FEC.
*/
-int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
- struct prefix *prefix, uint8_t route_type,
- unsigned short route_instance);
+void mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
+ struct prefix *prefix, uint8_t route_type,
+ unsigned short route_instance);
/*
* Install/update a NHLFE for an LSP in the forwarding table. This may be
*/
void zebra_mpls_init_tables(struct zebra_vrf *zvrf);
+/*
+ * If mpls is turned on *after* FRR is brought
+ * up let's actually notice this and turn on
+ * the relevant bits to make it work.
+ */
+void zebra_mpls_turned_on(void);
+
/*
* Global MPLS initialization.
*/
}
/* Global variables. */
-extern int mpls_enabled;
+extern bool mpls_enabled;
extern bool mpls_pw_reach_strict; /* Strict pseudowire reachability checking */
#ifdef __cplusplus
void zebra_neigh_terminate(void)
{
+ struct zebra_neigh_ent *n, *next;
+
if (!zrouter.neigh_info)
return;
+ RB_FOREACH_SAFE (n, zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree,
+ next)
+ zebra_neigh_free(n);
XFREE(MTYPE_ZNEIGH_INFO, zneigh_info);
}
fd = zebra_netns_notify_current->u.fd;
if (zebra_netns_notify_current->master != NULL)
- thread_cancel(&zebra_netns_notify_current);
+ THREAD_OFF(zebra_netns_notify_current);
/* auto-removal of notify items */
if (fd > 0)
/* If we're in shutdown, this interface event needs to clean
* up installed NHGs, so don't clear that flag directly.
*/
- if (!zrouter.in_shutdown)
+ if (!zebra_router_in_shutdown())
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
/* Update validity of nexthops depending on it */
nhe->nhg.nexthop);
}
- if (nhe->refcnt)
- zlog_debug("nhe_id=%pNG hash refcnt=%d", nhe, nhe->refcnt);
+ THREAD_OFF(nhe->timer);
zebra_nhg_free_members(nhe);
XFREE(MTYPE_NHG, nhe);
}
+/*
+ * Let's just drop the memory associated with each item
+ */
void zebra_nhg_hash_free(void *p)
{
- zebra_nhg_release_all_deps((struct nhg_hash_entry *)p);
- zebra_nhg_free((struct nhg_hash_entry *)p);
+ struct nhg_hash_entry *nhe = p;
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
+ /* Group or singleton? */
+ if (nhe->nhg.nexthop && nhe->nhg.nexthop->next)
+ zlog_debug("%s: nhe %p (%u), refcnt %d", __func__, nhe,
+ nhe->id, nhe->refcnt);
+ else
+ zlog_debug("%s: nhe %p (%pNG), refcnt %d, NH %pNHv",
+ __func__, nhe, nhe, nhe->refcnt,
+ nhe->nhg.nexthop);
+ }
+
+ THREAD_OFF(nhe->timer);
+
+ nexthops_free(nhe->nhg.nexthop);
+
+ XFREE(MTYPE_NHG, nhe);
+}
+
+/*
+ * On cleanup there are nexthop groups that have not
+ * been resolved at all( a nhe->id of 0 ). As such
+ * zebra needs to clean up the memory associated with
+ * those entries.
+ */
+void zebra_nhg_hash_free_zero_id(struct hash_bucket *b, void *arg)
+{
+ struct nhg_hash_entry *nhe = b->data;
+ struct nhg_connected *dep;
+
+ while ((dep = nhg_connected_tree_pop(&nhe->nhg_depends))) {
+ if (dep->nhe->id == 0)
+ zebra_nhg_hash_free(dep->nhe);
+
+ nhg_connected_free(dep);
+ }
+
+ while ((dep = nhg_connected_tree_pop(&nhe->nhg_dependents)))
+ nhg_connected_free(dep);
+
+ if (nhe->backup_info && nhe->backup_info->nhe->id == 0) {
+ while ((dep = nhg_connected_tree_pop(
+ &nhe->backup_info->nhe->nhg_depends)))
+ nhg_connected_free(dep);
+
+ zebra_nhg_hash_free(nhe->backup_info->nhe);
+
+ XFREE(MTYPE_NHG, nhe->backup_info);
+ }
}
static void zebra_nhg_timer(struct thread *thread)
nhe->refcnt--;
- if (!zrouter.in_shutdown && nhe->refcnt <= 0 &&
+ if (!zebra_router_in_shutdown() && nhe->refcnt <= 0 &&
CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) &&
!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_KEEP_AROUND)) {
nhe->refcnt = 1;
SET_FLAG(nhe->flags, NEXTHOP_GROUP_KEEP_AROUND);
thread_add_timer(zrouter.master, zebra_nhg_timer, nhe,
zrouter.nhg_keep, &nhe->timer);
+ return;
}
if (!zebra_nhg_depends_is_empty(nhe))
case DPLANE_OP_INTF_INSTALL:
case DPLANE_OP_INTF_UPDATE:
case DPLANE_OP_INTF_DELETE:
+ case DPLANE_OP_TC_INSTALL:
+ case DPLANE_OP_TC_UPDATE:
+ case DPLANE_OP_TC_DELETE:
break;
}
-
- dplane_ctx_fini(&ctx);
}
static int zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg)
void zebra_nhg_free(struct nhg_hash_entry *nhe);
/* In order to clear a generic hash, we need a generic api, sigh. */
void zebra_nhg_hash_free(void *p);
+void zebra_nhg_hash_free_zero_id(struct hash_bucket *b, void *arg);
/* Init an nhe, for use in a hash lookup for example. There's some fuzziness
* if the nhe represents only a single nexthop, so we try to capture that
/* Dequeue messages from the incoming batch, and save them
* on the module fifo.
*/
- frr_with_mutex(&zo_info.mutex) {
+ frr_with_mutex (&zo_info.mutex) {
msg = stream_fifo_pop(batch);
while (msg) {
stream_fifo_push(&zo_info.in_fifo, msg);
* Dequeue some messages from the incoming queue, temporarily
* save them on the local fifo
*/
- frr_with_mutex(&zo_info.mutex) {
+ frr_with_mutex (&zo_info.mutex) {
for (i = 0; i < zo_info.msgs_per_cycle; i++) {
msg = stream_fifo_pop(&zo_info.in_fifo);
EC_ZEBRA_PBR_RULE_UPDATE,
"Context received in pbr rule dplane result handler with incorrect OP code (%u)",
op);
-
-
- dplane_ctx_fini(&ctx);
}
/*
free(ptm_cb.in_data);
/* Cancel events. */
- thread_cancel(&ptm_cb.t_read);
- thread_cancel(&ptm_cb.t_write);
- thread_cancel(&ptm_cb.t_timer);
+ THREAD_OFF(ptm_cb.t_read);
+ THREAD_OFF(ptm_cb.t_write);
+ THREAD_OFF(ptm_cb.t_timer);
if (ptm_cb.wb)
buffer_free(ptm_cb.wb);
ptm_cb.reconnect_time, &ptm_cb.t_timer);
return -1;
case BUFFER_EMPTY:
- thread_cancel(&ptm_cb.t_write);
+ THREAD_OFF(ptm_cb.t_write);
break;
case BUFFER_PENDING:
thread_add_write(zrouter.master, zebra_ptm_flush_messages, NULL,
if (pw->status == PW_FORWARDING) {
hook_call(pw_uninstall, pw);
dplane_pw_uninstall(pw);
- } else if (pw->install_retry_timer)
- thread_cancel(&pw->install_retry_timer);
+ }
+
+ THREAD_OFF(pw->install_retry_timer);
/* unlink and release memory */
RB_REMOVE(zebra_pw_head, &zvrf->pseudowires, pw);
if (pw->protocol == ZEBRA_ROUTE_STATIC)
RB_REMOVE(zebra_static_pw_head, &zvrf->static_pseudowires, pw);
+
XFREE(MTYPE_PW, pw);
}
pw->vrf_id, pw->ifname, PW_INSTALL_RETRY_INTERVAL);
/* schedule to retry later */
- thread_cancel(&pw->install_retry_timer);
+ THREAD_OFF(pw->install_retry_timer);
thread_add_timer(zrouter.master, zebra_pw_install_retry, pw,
PW_INSTALL_RETRY_INTERVAL, &pw->install_retry_timer);
{
struct zebra_pw *pw = THREAD_ARG(thread);
- pw->install_retry_timer = NULL;
zebra_pw_install(pw);
}
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;
+/* Meta Q's specific names */
+enum meta_queue_indexes {
+ META_QUEUE_NHG,
+ META_QUEUE_EVPN,
+ META_QUEUE_CONNECTED,
+ META_QUEUE_KERNEL,
+ META_QUEUE_STATIC,
+ META_QUEUE_NOTBGP,
+ META_QUEUE_BGP,
+ META_QUEUE_OTHER,
+};
/* Each route type's string and default distance value. */
static const struct {
int key;
uint8_t distance;
- uint8_t meta_q_map;
+ enum meta_queue_indexes meta_q_map;
} route_info[ZEBRA_ROUTE_MAX] = {
- [ZEBRA_ROUTE_NHG] = {ZEBRA_ROUTE_NHG, 255 /* Unneeded for nhg's */, 0},
- [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, 7},
- [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, 3},
- [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, 2},
- [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, 4},
- [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, 5},
- [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, 5},
- [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, 5},
- [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, 5},
- [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, 5},
- [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */, 6},
- [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, 7},
- [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, 5},
- [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, 5},
- [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, 7},
- [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, 7},
- [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, 4},
- [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, 7},
- [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, 6},
- [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, 6},
- [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20, 6},
- [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, 6},
- [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20, 6},
- [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, 5},
- [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, 7},
- [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, 7},
- [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, 7},
- [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, 5},
- [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 7},
- [ZEBRA_ROUTE_SRTE] = {ZEBRA_ROUTE_SRTE, 255, 7},
- [ZEBRA_ROUTE_ALL] = {ZEBRA_ROUTE_ALL, 255, 7},
+ [ZEBRA_ROUTE_NHG] = {ZEBRA_ROUTE_NHG, 255 /* Unneeded for nhg's */,
+ META_QUEUE_NHG},
+ [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, META_QUEUE_KERNEL},
+ [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, META_QUEUE_KERNEL},
+ [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, META_QUEUE_CONNECTED},
+ [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, META_QUEUE_STATIC},
+ [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */,
+ META_QUEUE_BGP},
+ [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, META_QUEUE_STATIC},
+ [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, META_QUEUE_BGP},
+ [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, META_QUEUE_BGP},
+ [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20,
+ META_QUEUE_BGP},
+ [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, META_QUEUE_BGP},
+ [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20,
+ META_QUEUE_BGP},
+ [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115,
+ META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_SRTE] = {ZEBRA_ROUTE_SRTE, 255, META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_ALL] = {ZEBRA_ROUTE_ALL, 255, META_QUEUE_OTHER},
/* Any new route type added to zebra, should be mirrored here */
/* no entry/default: 150 */
};
-/* EVPN/VXLAN subqueue is number 1 */
-#define META_QUEUE_EVPN 1
-
/* Wrapper struct for nhg workqueue items; a 'ctx' is an incoming update
* from the OS, and an 'nhe' is a nhe update.
*/
#pragma FRR printfrr_ext "%pZN" (struct route_node *)
#endif
+static const char *subqueue2str(enum meta_queue_indexes index)
+{
+ switch (index) {
+ case META_QUEUE_NHG:
+ return "NHG Objects";
+ case META_QUEUE_EVPN:
+ return "EVPN/VxLan Objects";
+ case META_QUEUE_CONNECTED:
+ return "Connected Routes";
+ case META_QUEUE_KERNEL:
+ return "Kernel Routes";
+ case META_QUEUE_STATIC:
+ return "Static Routes";
+ case META_QUEUE_NOTBGP:
+ return "RIP/OSPF/ISIS/EIGRP/NHRP Routes";
+ case META_QUEUE_BGP:
+ return "BGP Routes";
+ case META_QUEUE_OTHER:
+ 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)
if (rn)
route_unlock_node(rn);
-
- /* Return context to dataplane module */
- dplane_ctx_fini(&ctx);
}
/*
done:
if (rn)
route_unlock_node(rn);
-
- /* Return context to dataplane module */
- dplane_ctx_fini(&ctx);
}
/*
struct nhg_ctx *ctx;
struct nhg_hash_entry *nhe, *newnhe;
struct wq_nhg_wrapper *w;
- uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map;
+ uint8_t qindex = META_QUEUE_NHG;
w = listgetdata(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 */
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,
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)
* Examine the specified subqueue; process one entry and return 1 if
* there is a node, return 0 otherwise.
*/
-static unsigned int process_subq(struct list *subq, uint8_t qindex)
+static unsigned int process_subq(struct list *subq,
+ enum meta_queue_indexes qindex)
{
struct listnode *lnode = listhead(subq);
if (!lnode)
return 0;
- if (qindex == META_QUEUE_EVPN)
+ switch (qindex) {
+ case META_QUEUE_EVPN:
process_subq_evpn(lnode);
- else if (qindex == route_info[ZEBRA_ROUTE_NHG].meta_q_map)
+ break;
+ case META_QUEUE_NHG:
process_subq_nhg(lnode);
- else
+ break;
+ case META_QUEUE_CONNECTED:
+ case META_QUEUE_KERNEL:
+ case META_QUEUE_STATIC:
+ case META_QUEUE_NOTBGP:
+ case META_QUEUE_BGP:
+ case META_QUEUE_OTHER:
process_subq_route(lnode, qindex);
+ break;
+ }
list_delete_node(subq, lnode);
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;
}
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;
}
static int rib_meta_queue_nhg_ctx_add(struct meta_queue *mq, void *data)
{
struct nhg_ctx *ctx = NULL;
- uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map;
+ uint8_t qindex = META_QUEUE_NHG;
struct wq_nhg_wrapper *w;
ctx = (struct nhg_ctx *)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;
}
static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data)
{
struct nhg_hash_entry *nhe = NULL;
- uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map;
+ uint8_t qindex = META_QUEUE_NHG;
struct wq_nhg_wrapper *w;
nhe = (struct nhg_hash_entry *)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;
}
return mq_add_handler(w, rib_meta_queue_evpn_add);
}
+
+/* Create new meta queue.
+ A destructor function doesn't seem to be necessary here.
+ */
+static struct meta_queue *meta_queue_new(void)
+{
+ struct meta_queue *new;
+ unsigned i;
+
+ new = XCALLOC(MTYPE_WORK_QUEUE, sizeof(struct meta_queue));
+
+ for (i = 0; i < MQ_SIZE; i++) {
+ new->subq[i] = list_new();
+ assert(new->subq[i]);
+ }
+
+ return new;
+}
+
/* Clean up the EVPN meta-queue list */
-static void evpn_meta_queue_free(struct list *l)
+static void evpn_meta_queue_free(struct meta_queue *mq, struct list *l,
+ struct zebra_vrf *zvrf)
{
- struct listnode *node;
+ struct listnode *node, *nnode;
struct wq_evpn_wrapper *w;
/* Free the node wrapper object, and the struct it wraps */
- while ((node = listhead(l)) != NULL) {
- w = node->data;
+ for (ALL_LIST_ELEMENTS(l, node, nnode, w)) {
+ if (zvrf) {
+ vrf_id_t vrf_id = zvrf->vrf->vrf_id;
+
+ if (w->vrf_id != vrf_id)
+ continue;
+ }
+
node->data = NULL;
XFREE(MTYPE_WQ_WRAPPER, w);
list_delete_node(l, node);
+ mq->size--;
}
}
/* Clean up the nhg meta-queue list */
-static void nhg_meta_queue_free(struct list *l)
+static void nhg_meta_queue_free(struct meta_queue *mq, struct list *l,
+ struct zebra_vrf *zvrf)
{
struct wq_nhg_wrapper *w;
- struct listnode *node;
+ struct listnode *node, *nnode;
/* Free the node wrapper object, and the struct it wraps */
- while ((node = listhead(l)) != NULL) {
- w = node->data;
- node->data = NULL;
+ for (ALL_LIST_ELEMENTS(l, node, nnode, w)) {
+ if (zvrf) {
+ vrf_id_t vrf_id = zvrf->vrf->vrf_id;
+ if (w->type == WQ_NHG_WRAPPER_TYPE_CTX &&
+ w->u.ctx->vrf_id != vrf_id)
+ continue;
+ else if (w->type == WQ_NHG_WRAPPER_TYPE_NHG &&
+ w->u.nhe->vrf_id != vrf_id)
+ continue;
+ }
if (w->type == WQ_NHG_WRAPPER_TYPE_CTX)
nhg_ctx_free(&w->u.ctx);
else if (w->type == WQ_NHG_WRAPPER_TYPE_NHG)
zebra_nhg_free(w->u.nhe);
+ node->data = NULL;
XFREE(MTYPE_WQ_WRAPPER, w);
list_delete_node(l, node);
+ mq->size--;
}
}
-/* Create new meta queue.
- A destructor function doesn't seem to be necessary here.
- */
-static struct meta_queue *meta_queue_new(void)
+static void rib_meta_queue_free(struct meta_queue *mq, struct list *l,
+ struct zebra_vrf *zvrf)
{
- struct meta_queue *new;
- unsigned i;
+ struct route_node *rnode;
+ struct listnode *node, *nnode;
- new = XCALLOC(MTYPE_WORK_QUEUE, sizeof(struct meta_queue));
+ for (ALL_LIST_ELEMENTS(l, node, nnode, rnode)) {
+ rib_dest_t *dest = rib_dest_from_rnode(rnode);
- for (i = 0; i < MQ_SIZE; i++) {
- new->subq[i] = list_new();
- assert(new->subq[i]);
- }
-
- return new;
-}
-
-void meta_queue_free(struct meta_queue *mq)
-{
- unsigned i;
-
- for (i = 0; i < MQ_SIZE; i++) {
- /* Some subqueues may need cleanup - nhgs for example */
- if (i == route_info[ZEBRA_ROUTE_NHG].meta_q_map)
- nhg_meta_queue_free(mq->subq[i]);
- else if (i == META_QUEUE_EVPN)
- evpn_meta_queue_free(mq->subq[i]);
+ if (dest && rib_dest_vrf(dest) != zvrf)
+ continue;
- list_delete(&mq->subq[i]);
+ route_unlock_node(rnode);
+ node->data = NULL;
+ list_delete_node(l, node);
+ mq->size--;
}
-
- XFREE(MTYPE_WORK_QUEUE, mq);
}
-void rib_meta_queue_free_vrf(struct meta_queue *mq, struct zebra_vrf *zvrf)
+
+void meta_queue_free(struct meta_queue *mq, struct zebra_vrf *zvrf)
{
- vrf_id_t vrf_id = zvrf->vrf->vrf_id;
- unsigned int i;
+ enum meta_queue_indexes i;
for (i = 0; i < MQ_SIZE; i++) {
- struct listnode *lnode, *nnode;
- void *data;
- bool del;
-
- for (ALL_LIST_ELEMENTS(mq->subq[i], lnode, nnode, data)) {
- del = false;
-
- if (i == META_QUEUE_EVPN) {
- struct wq_evpn_wrapper *w = data;
-
- if (w->vrf_id == vrf_id) {
- XFREE(MTYPE_WQ_WRAPPER, w);
- del = true;
- }
- } else if (i ==
- route_info[ZEBRA_ROUTE_NHG].meta_q_map) {
- struct wq_nhg_wrapper *w = data;
-
- if (w->type == WQ_NHG_WRAPPER_TYPE_CTX &&
- w->u.ctx->vrf_id == vrf_id) {
- nhg_ctx_free(&w->u.ctx);
- XFREE(MTYPE_WQ_WRAPPER, w);
- del = true;
- } else if (w->type == WQ_NHG_WRAPPER_TYPE_NHG &&
- w->u.nhe->vrf_id == vrf_id) {
- zebra_nhg_free(w->u.nhe);
- XFREE(MTYPE_WQ_WRAPPER, w);
- del = true;
- }
- } else {
- struct route_node *rnode = data;
- rib_dest_t *dest = rib_dest_from_rnode(rnode);
-
- if (dest && rib_dest_vrf(dest) == zvrf) {
- route_unlock_node(rnode);
- del = true;
- }
- }
-
- if (del) {
- list_delete_node(mq->subq[i], lnode);
- mq->size--;
- }
+ /* Some subqueues may need cleanup - nhgs for example */
+ switch (i) {
+ case META_QUEUE_NHG:
+ nhg_meta_queue_free(mq, mq->subq[i], zvrf);
+ break;
+ case META_QUEUE_EVPN:
+ evpn_meta_queue_free(mq, mq->subq[i], zvrf);
+ break;
+ case META_QUEUE_CONNECTED:
+ case META_QUEUE_KERNEL:
+ case META_QUEUE_STATIC:
+ case META_QUEUE_NOTBGP:
+ case META_QUEUE_BGP:
+ case META_QUEUE_OTHER:
+ rib_meta_queue_free(mq, mq->subq[i], zvrf);
+ break;
}
+ if (!zvrf)
+ list_delete(&mq->subq[i]);
}
+
+ if (!zvrf)
+ XFREE(MTYPE_WORK_QUEUE, mq);
}
/* initialise zebra rib work queue */
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;
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);
/*
* 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;
* 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));
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.
TAILQ_INIT(&ctxlist);
/* Take lock controlling queue of results */
- frr_with_mutex(&dplane_mutex) {
+ frr_with_mutex (&dplane_mutex) {
/* Dequeue list of context structs */
dplane_ctx_list_append(&ctxlist, &rib_dplane_q);
}
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
*/
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);
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);
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:
zebra_if_dplane_result(ctx);
break;
+ case DPLANE_OP_TC_INSTALL:
+ case DPLANE_OP_TC_UPDATE:
+ case DPLANE_OP_TC_DELETE:
+ break;
+
/* Some op codes not handled here */
case DPLANE_OP_ADDR_INSTALL:
case DPLANE_OP_ADDR_UNINSTALL:
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);
}
static int rib_dplane_results(struct dplane_ctx_q *ctxlist)
{
/* Take lock controlling queue of results */
- frr_with_mutex(&dplane_mutex) {
+ frr_with_mutex (&dplane_mutex) {
/* Enqueue context blocks */
dplane_ctx_list_append(&rib_dplane_q, ctxlist);
}
zebra_router_free_table(zrt);
work_queue_free_and_null(&zrouter.ribq);
- meta_queue_free(zrouter.mq);
+ meta_queue_free(zrouter.mq, NULL);
zebra_vxlan_disable();
zebra_mlag_terminate();
zebra_neigh_terminate();
/* Free NHE in ID table only since it has unhashable entries as well */
+ hash_iterate(zrouter.nhgs_id, zebra_nhg_hash_free_zero_id, NULL);
hash_clean(zrouter.nhgs_id, zebra_nhg_hash_free);
hash_free(zrouter.nhgs_id);
hash_clean(zrouter.nhgs, NULL);
{
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;
#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
zrouter.supports_nhgs = support;
}
+static inline bool zebra_router_in_shutdown(void)
+{
+ return atomic_load_explicit(&zrouter.in_shutdown, memory_order_relaxed);
+}
+
/* zebra_northbound.c */
extern const struct frr_yang_module_info frr_zebra_info;
lua_setfield(L, -2, "ipset");
break;
}
- case DPLANE_OP_ADDR_INSTALL:
- case DPLANE_OP_ADDR_UNINSTALL:
- case DPLANE_OP_INTF_ADDR_ADD:
- case DPLANE_OP_INTF_ADDR_DEL:
- case DPLANE_OP_INTF_INSTALL:
- case DPLANE_OP_INTF_UPDATE:
- case DPLANE_OP_INTF_DELETE:
- break;
case DPLANE_OP_NEIGH_INSTALL:
case DPLANE_OP_NEIGH_UPDATE:
case DPLANE_OP_NEIGH_DELETE:
}
lua_setfield(L, -2, "gre");
+ case DPLANE_OP_ADDR_INSTALL:
+ case DPLANE_OP_ADDR_UNINSTALL:
+ case DPLANE_OP_INTF_ADDR_ADD:
+ case DPLANE_OP_INTF_ADDR_DEL:
+ case DPLANE_OP_INTF_INSTALL:
+ case DPLANE_OP_INTF_UPDATE:
+ case DPLANE_OP_INTF_DELETE:
+ case DPLANE_OP_TC_INSTALL:
+ case DPLANE_OP_TC_UPDATE:
+ case DPLANE_OP_TC_DELETE:
+ /* Not currently handled */
case DPLANE_OP_INTF_NETCONFIG: /*NYI*/
case DPLANE_OP_NONE:
break;
if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp);
/* clean-up work queues */
- rib_meta_queue_free_vrf(zrouter.mq, zvrf);
+ meta_queue_free(zrouter.mq, zvrf);
/* Cleanup (free) routing tables and NHT tables. */
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
table_manager_disable(zvrf);
/* clean-up work queues */
- rib_meta_queue_free_vrf(zrouter.mq, zvrf);
+ meta_queue_free(zrouter.mq, zvrf);
/* Free Vxlan and MPLS. */
zebra_vxlan_close_tables(zvrf);
#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 */
"allow-external-route-update",
"Allow FRR routes to be overwritten by external processes\n")
{
- allow_delete = 1;
+ zrouter.allow_delete = true;
return CMD_SUCCESS;
}
NO_STR
"Allow FRR routes to be overwritten by external processes\n")
{
- allow_delete = 0;
+ zrouter.allow_delete = false;
return CMD_SUCCESS;
}
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)
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",
vty_out(vty, "%s\n", out);
XFREE(MTYPE_TMP, out);
+ ttable_del(table);
vty_out(vty,
" Route Route Neighbor LSP LSP\n");
vty_out(vty,
struct zebra_evpn_es *es;
struct interface *acc_ifp;
+ /* If netlink message is with vid, it will have no nexthop.
+ * So skip it.
+ */
+ if (vid) {
+ if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("dpAdd MAC %pEA VID %u - ignore as no nhid",
+ macaddr, vid);
+ return 0;
+ }
+
+ /* Get vxlan's vid for netlink message has no it. */
+ vid = ((struct zebra_if *)ifp->info)->l2info.vxl.access_vlan;
+
/* if remote mac delete the local entry */
if (!nhg_id || !zebra_evpn_nhg_is_local_es(nhg_id, &es)
|| !zebra_evpn_es_local_mac_via_network_port(es)) {
}
/* If local MAC on a down local ES translate the network-mac-add
- * to a local-inactive-mac-add
+ * to a local-active-mac-add
*/
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug("dpAdd local-nw-MAC %pEA VID %u", macaddr, vid);
*/
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 */
cache = stream_fifo_new();
- frr_with_mutex(&client->obuf_mtx) {
+ frr_with_mutex (&client->obuf_mtx) {
while (stream_fifo_head(client->obuf_fifo))
stream_fifo_push(cache,
stream_fifo_pop(client->obuf_fifo));
memory_order_relaxed);
/* publish read packets on client's input queue */
- frr_with_mutex(&client->ibuf_mtx) {
+ frr_with_mutex (&client->ibuf_mtx) {
while (cache->head)
stream_fifo_push(client->ibuf_fifo,
stream_fifo_pop(cache));
uint32_t p2p = zrouter.packets_to_process;
bool need_resched = false;
- frr_with_mutex(&client->ibuf_mtx) {
+ frr_with_mutex (&client->ibuf_mtx) {
uint32_t i;
for (i = 0; i < p2p && stream_fifo_head(client->ibuf_fifo);
++i) {
int zserv_send_message(struct zserv *client, struct stream *msg)
{
- frr_with_mutex(&client->obuf_mtx) {
+ frr_with_mutex (&client->obuf_mtx) {
stream_fifo_push(client->obuf_fifo, msg);
}
{
struct stream *msg;
- frr_with_mutex(&client->obuf_mtx) {
+ frr_with_mutex (&client->obuf_mtx) {
msg = stream_fifo_pop(fifo);
while (msg) {
stream_fifo_push(client->obuf_fifo, msg);
* Final check in case the client struct is in use in another
* pthread: if not in-use, continue and free the client
*/
- frr_with_mutex(&client_mutex) {
+ frr_with_mutex (&client_mutex) {
if (client->busy_count <= 0) {
/* remove from client list */
listnode_delete(zrouter.client_list, client);
}
/* Add this client to linked list. */
- frr_with_mutex(&client_mutex) {
+ frr_with_mutex (&client_mutex) {
listnode_add(zrouter.client_list, client);
}
{
struct zserv *client = NULL;
- frr_with_mutex(&client_mutex) {
+ frr_with_mutex (&client_mutex) {
client = find_client_internal(proto, instance, session_id);
if (client) {
/* Don't return a dead/closed client object */
* for it to be deleted as soon as we release the lock, so we won't
* touch the object again.
*/
- frr_with_mutex(&client_mutex) {
+ frr_with_mutex (&client_mutex) {
client->busy_count--;
if (client->busy_count <= 0) {
{
struct zserv *client;
- frr_with_mutex(&client_mutex) {
+ frr_with_mutex (&client_mutex) {
client = find_client_internal(proto, instance, 0);
}
{
struct zserv *client;
- frr_with_mutex(&client_mutex) {
+ frr_with_mutex (&client_mutex) {
client = find_client_internal(proto, instance, session_id);
}