diff options
| -rw-r--r-- | bfdd/bfd.c | 18 | ||||
| -rw-r--r-- | bfdd/bfd.h | 8 | ||||
| -rw-r--r-- | bfdd/bfd_packet.c | 415 | ||||
| -rw-r--r-- | bfdd/bfdd_cli.c | 11 | ||||
| -rw-r--r-- | pimd/pim6_cmd.c | 8 | ||||
| -rw-r--r-- | pimd/pim_cmd.c | 10 | ||||
| -rw-r--r-- | pimd/pim_igmp.c | 4 | ||||
| -rw-r--r-- | pimd/pim_instance.h | 2 | ||||
| -rw-r--r-- | pimd/pim_oil.h | 3 | ||||
| -rw-r--r-- | pimd/pim_vty.c | 11 | ||||
| -rw-r--r-- | tests/topotests/bfd_vrf_topo1/r1/bfdd.conf | 4 | ||||
| -rw-r--r-- | tests/topotests/bfd_vrf_topo1/r1/peers.json | 2 | ||||
| -rw-r--r-- | tests/topotests/bfd_vrf_topo1/r2/bfdd.conf | 8 | ||||
| -rw-r--r-- | tests/topotests/bfd_vrf_topo1/r2/peers.json | 2 | ||||
| -rw-r--r-- | tests/topotests/bfd_vrf_topo1/r3/bfdd.conf | 4 | ||||
| -rw-r--r-- | tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py | 679 | ||||
| -rw-r--r-- | zebra/kernel_netlink.c | 50 | ||||
| -rw-r--r-- | zebra/kernel_socket.c | 11 | ||||
| -rw-r--r-- | zebra/main.c | 5 | ||||
| -rw-r--r-- | zebra/rt_netlink.c | 29 | ||||
| -rw-r--r-- | zebra/zebra_rib.c | 63 | ||||
| -rw-r--r-- | zebra/zebra_router.c | 2 | ||||
| -rw-r--r-- | zebra/zebra_router.h | 3 | ||||
| -rw-r--r-- | zebra/zebra_vty.c | 10 |
24 files changed, 1084 insertions, 278 deletions
diff --git a/bfdd/bfd.c b/bfdd/bfd.c index d52eeeddba..483beb1b17 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -454,7 +454,17 @@ void ptm_bfd_start_xmt_timer(struct bfd_session *bfd, bool is_echo) static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd) { /* Send the scheduled echo packet */ - ptm_bfd_echo_snd(bfd); + /* if ipv4 use the new echo implementation that causes + * the packet to be looped in forwarding plane of peer + */ + if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6) == 0) +#ifdef BFD_LINUX + ptm_bfd_echo_fp_snd(bfd); +#else + ptm_bfd_echo_snd(bfd); +#endif + else + ptm_bfd_echo_snd(bfd); /* Restart the timer for next time */ ptm_bfd_start_xmt_timer(bfd, true); @@ -558,6 +568,12 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag) state_list[bfd->ses_state].str, get_diag_str(bfd->local_diag)); } + + /* clear peer's mac address */ + UNSET_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET); + memset(bfd->peer_hw_addr, 0, sizeof(bfd->peer_hw_addr)); + /* reset local address ,it might has been be changed after bfd is up*/ + memset(&bfd->local_address, 0, sizeof(bfd->local_address)); } static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa, diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 6aa9e00586..48a1e0bc31 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -168,9 +168,10 @@ enum bfd_session_flags { * expires */ BFD_SESS_FLAG_SHUTDOWN = 1 << 7, /* disable BGP peer function */ - BFD_SESS_FLAG_CONFIG = 1 << 8, /* Session configured with bfd NB API */ - BFD_SESS_FLAG_CBIT = 1 << 9, /* CBIT is set */ + BFD_SESS_FLAG_CONFIG = 1 << 8, /* Session configured with bfd NB API */ + BFD_SESS_FLAG_CBIT = 1 << 9, /* CBIT is set */ BFD_SESS_FLAG_PASSIVE = 1 << 10, /* Passive mode */ + BFD_SESS_FLAG_MAC_SET = 1 << 11, /* MAC of peer known */ }; /* @@ -290,6 +291,8 @@ struct bfd_session { struct peer_label *pl; struct bfd_dplane_ctx *bdc; + struct sockaddr_any local_address; + uint8_t peer_hw_addr[ETH_ALEN]; struct interface *ifp; struct vrf *vrf; @@ -554,6 +557,7 @@ int bp_echov6_socket(const struct vrf *vrf); void ptm_bfd_snd(struct bfd_session *bfd, int fbit); void ptm_bfd_echo_snd(struct bfd_session *bfd); +void ptm_bfd_echo_fp_snd(struct bfd_session *bfd); void bfd_recv_cb(struct thread *t); diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index c717a333a6..6b0afef65f 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -34,6 +34,8 @@ #include <netinet/udp.h> #include "lib/sockopt.h" +#include "lib/checksum.h" +#include "lib/network.h" #include "bfd.h" @@ -55,6 +57,18 @@ int bp_udp_send(int sd, uint8_t ttl, uint8_t *data, size_t datalen, struct sockaddr *to, socklen_t tolen); int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd, uint8_t *ttl, uint32_t *my_discr); +#ifdef BFD_LINUX +ssize_t bfd_recv_ipv4_fp(int sd, uint8_t *msgbuf, size_t msgbuflen, + uint8_t *ttl, ifindex_t *ifindex, + struct sockaddr_any *local, struct sockaddr_any *peer); +void bfd_peer_mac_set(int sd, struct bfd_session *bfd, + struct sockaddr_any *peer, struct interface *ifp); +int bp_udp_send_fp(int sd, uint8_t *data, size_t datalen, + struct bfd_session *bfd); +ssize_t bfd_recv_fp_echo(int sd, uint8_t *msgbuf, size_t msgbuflen, + uint8_t *ttl, ifindex_t *ifindex, + struct sockaddr_any *local, struct sockaddr_any *peer); +#endif /* socket related prototypes */ static void bp_set_ipopts(int sd); @@ -126,6 +140,142 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data, return 0; } +#ifdef BFD_LINUX +/* + * Compute the UDP checksum. + * + * Checksum is not set in the packet, just computed. + * + * pkt + * Packet, fully filled out except for checksum field. + * + * pktsize + * sizeof(*pkt) + * + * ip + * IP address that pkt will be transmitted from and too. + * + * Returns: + * Checksum in network byte order. + */ +static uint16_t bfd_pkt_checksum(struct udphdr *pkt, size_t pktsize, + struct in6_addr *ip, sa_family_t family) +{ + uint16_t chksum; + + pkt->check = 0; + + if (family == AF_INET6) { + struct ipv6_ph ph = {}; + + memcpy(&ph.src, ip, sizeof(ph.src)); + memcpy(&ph.dst, ip, sizeof(ph.dst)); + ph.ulpl = htons(pktsize); + ph.next_hdr = IPPROTO_UDP; + chksum = in_cksum_with_ph6(&ph, pkt, pktsize); + } else { + struct ipv4_ph ph = {}; + + memcpy(&ph.src, ip, sizeof(ph.src)); + memcpy(&ph.dst, ip, sizeof(ph.dst)); + ph.proto = IPPROTO_UDP; + ph.len = htons(pktsize); + chksum = in_cksum_with_ph4(&ph, pkt, pktsize); + } + + return chksum; +} + +/* + * This routine creates the entire ECHO packet so that it will be looped + * in the forwarding plane of the peer router instead of going up the + * stack in BFD to be looped. If we haven't learned the peers MAC yet + * no echo is sent. + * + * echo packet with src/dst IP equal to local IP + * dest MAC as peer's MAC + * + * currently support ipv4 + */ +void ptm_bfd_echo_fp_snd(struct bfd_session *bfd) +{ + int sd; + struct bfd_vrf_global *bvrf = bfd_vrf_look_by_session(bfd); + int total_len = 0; + struct ethhdr *eth; + struct udphdr *uh; + struct iphdr *iph; + struct bfd_echo_pkt *beph; + static char sendbuff[100]; + + if (!bvrf) + return; + if (!CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET)) + return; + if (!CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) + SET_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE); + + memset(sendbuff, 0, sizeof(sendbuff)); + + /* add eth hdr */ + eth = (struct ethhdr *)(sendbuff); + memcpy(eth->h_source, bfd->ifp->hw_addr, sizeof(bfd->ifp->hw_addr)); + memcpy(eth->h_dest, bfd->peer_hw_addr, sizeof(bfd->peer_hw_addr)); + + total_len += sizeof(struct ethhdr); + + sd = bvrf->bg_echo; + eth->h_proto = htons(ETH_P_IP); + + /* add ip hdr */ + iph = (struct iphdr *)(sendbuff + sizeof(struct ethhdr)); + + iph->ihl = sizeof(struct ip) >> 2; + iph->version = IPVERSION; + iph->tos = IPTOS_PREC_INTERNETCONTROL; + iph->id = (uint16_t)frr_weak_random(); + iph->ttl = BFD_TTL_VAL; + iph->protocol = IPPROTO_UDP; + memcpy(&iph->saddr, &bfd->local_address.sa_sin.sin_addr, + sizeof(bfd->local_address.sa_sin.sin_addr)); + memcpy(&iph->daddr, &bfd->local_address.sa_sin.sin_addr, + sizeof(bfd->local_address.sa_sin.sin_addr)); + total_len += sizeof(struct iphdr); + + /* add udp hdr */ + uh = (struct udphdr *)(sendbuff + sizeof(struct iphdr) + + sizeof(struct ethhdr)); + uh->source = htons(BFD_DEF_ECHO_PORT); + uh->dest = htons(BFD_DEF_ECHO_PORT); + + total_len += sizeof(struct udphdr); + + /* add bfd echo */ + beph = (struct bfd_echo_pkt *)(sendbuff + sizeof(struct udphdr) + + sizeof(struct iphdr) + + sizeof(struct ethhdr)); + + beph->ver = BFD_ECHO_VERSION; + beph->len = BFD_ECHO_PKT_LEN; + beph->my_discr = htonl(bfd->discrs.my_discr); + + total_len += sizeof(struct bfd_echo_pkt); + uh->len = + htons(total_len - sizeof(struct iphdr) - sizeof(struct ethhdr)); + uh->check = bfd_pkt_checksum( + uh, (total_len - sizeof(struct iphdr) - sizeof(struct ethhdr)), + (struct in6_addr *)&iph->saddr, AF_INET); + + iph->tot_len = htons(total_len - sizeof(struct ethhdr)); + iph->check = in_cksum((const void *)iph, sizeof(struct iphdr)); + + if (bp_udp_send_fp(sd, (uint8_t *)&sendbuff, total_len, bfd) == -1) + return; + + bfd->stats.tx_echo_pkt++; +} +#endif + void ptm_bfd_echo_snd(struct bfd_session *bfd) { struct sockaddr *sa; @@ -275,6 +425,94 @@ void ptm_bfd_snd(struct bfd_session *bfd, int fbit) bfd->stats.tx_ctrl_pkt++; } +#ifdef BFD_LINUX +/* + * receive the ipv4 echo packet that was loopback in the peers forwarding plane + */ +ssize_t bfd_recv_ipv4_fp(int sd, uint8_t *msgbuf, size_t msgbuflen, + uint8_t *ttl, ifindex_t *ifindex, + struct sockaddr_any *local, struct sockaddr_any *peer) +{ + ssize_t mlen; + struct sockaddr_ll msgaddr; + struct msghdr msghdr; + struct iovec iov[1]; + uint16_t recv_checksum; + uint16_t checksum; + struct iphdr *ip; + struct udphdr *uh; + + /* Prepare the recvmsg params. */ + iov[0].iov_base = msgbuf; + iov[0].iov_len = msgbuflen; + + memset(&msghdr, 0, sizeof(msghdr)); + msghdr.msg_name = &msgaddr; + msghdr.msg_namelen = sizeof(msgaddr); + msghdr.msg_iov = iov; + msghdr.msg_iovlen = 1; + + mlen = recvmsg(sd, &msghdr, MSG_DONTWAIT); + if (mlen == -1) { + if (errno != EAGAIN || errno != EWOULDBLOCK || errno != EINTR) + zlog_err("%s: recv failed: %s", __func__, + strerror(errno)); + + return -1; + } + + ip = (struct iphdr *)(msgbuf + sizeof(struct ethhdr)); + + /* verify ip checksum */ + recv_checksum = ip->check; + ip->check = 0; + checksum = in_cksum((const void *)ip, sizeof(struct iphdr)); + if (recv_checksum != checksum) { + if (bglobal.debug_network) + zlog_debug( + "%s: invalid iphdr checksum expected 0x%x rcvd 0x%x", + __func__, checksum, recv_checksum); + return -1; + } + + *ttl = ip->ttl; + if (*ttl != 254) { + /* Echo should be looped in peer's forwarding plane, but it also + * comes up to BFD so silently drop it + */ + if (ip->daddr == ip->saddr) + return -1; + + if (bglobal.debug_network) + zlog_debug("%s: invalid TTL: %u", __func__, *ttl); + return -1; + } + + local->sa_sin.sin_family = AF_INET; + memcpy(&local->sa_sin.sin_addr, &ip->saddr, sizeof(ip->saddr)); + peer->sa_sin.sin_family = AF_INET; + memcpy(&peer->sa_sin.sin_addr, &ip->daddr, sizeof(ip->daddr)); + + *ifindex = msgaddr.sll_ifindex; + + /* verify udp checksum */ + uh = (struct udphdr *)(msgbuf + sizeof(struct iphdr) + + sizeof(struct ethhdr)); + recv_checksum = uh->check; + uh->check = 0; + checksum = bfd_pkt_checksum(uh, ntohs(uh->len), + (struct in6_addr *)&ip->saddr, AF_INET); + if (recv_checksum != checksum) { + if (bglobal.debug_network) + zlog_debug( + "%s: invalid udphdr checksum expected 0x%x rcvd 0x%x", + __func__, checksum, recv_checksum); + return -1; + } + return mlen; +} +#endif + ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, ifindex_t *ifindex, struct sockaddr_any *local, struct sockaddr_any *peer) @@ -649,6 +887,8 @@ void bfd_recv_cb(struct thread *t) /* * Multi hop: validate packet TTL. + * Single hop: set local address that received the packet. + * set peers mac address for echo packets */ if (is_mhop) { if (ttl < bfd->mh_ttl) { @@ -657,6 +897,14 @@ void bfd_recv_cb(struct thread *t) bfd->mh_ttl, ttl); return; } + } else { + + if (bfd->local_address.sa_sin.sin_family == AF_UNSPEC) + bfd->local_address = local; +#ifdef BFD_LINUX + if (ifp) + bfd_peer_mac_set(sd, bfd, &peer, ifp); +#endif } bfd->stats.rx_ctrl_pkt++; @@ -756,13 +1004,30 @@ int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd, ifindex_t ifindex = IFINDEX_INTERNAL; vrf_id_t vrfid = VRF_DEFAULT; uint8_t msgbuf[1516]; + size_t bfd_offset = 0; + + if (sd == bvrf->bg_echo) { +#ifdef BFD_LINUX + rlen = bfd_recv_ipv4_fp(sd, msgbuf, sizeof(msgbuf), ttl, + &ifindex, &local, &peer); - if (sd == bvrf->bg_echo) + /* silently drop echo packet that is looped in fastpath but + * still comes up to BFD + */ + if (rlen == -1) + return -1; + bfd_offset = sizeof(struct udphdr) + sizeof(struct iphdr) + + sizeof(struct ethhdr); +#else rlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), ttl, &ifindex, &local, &peer); - else + bfd_offset = 0; +#endif + } else { rlen = bfd_recv_ipv6(sd, msgbuf, sizeof(msgbuf), ttl, &ifindex, &local, &peer); + bfd_offset = 0; + } /* Short packet, better not risk reading it. */ if (rlen < (ssize_t)sizeof(*bep)) { @@ -771,8 +1036,8 @@ int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd, return -1; } - /* Test for loopback. */ - if (*ttl == BFD_TTL_VAL) { + /* Test for loopback for ipv6, ipv4 is looped in forwarding plane */ + if ((*ttl == BFD_TTL_VAL) && (sd == bvrf->bg_echov6)) { bp_udp_send(sd, *ttl - 1, msgbuf, rlen, (struct sockaddr *)&peer, (sd == bvrf->bg_echo) ? sizeof(peer.sa_sin) @@ -781,7 +1046,7 @@ int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd, } /* Read my discriminator from BFD Echo packet. */ - bep = (struct bfd_echo_pkt *)msgbuf; + bep = (struct bfd_echo_pkt *)(msgbuf + bfd_offset); *my_discr = ntohl(bep->my_discr); if (*my_discr == 0) { cp_debug(false, &peer, &local, ifindex, vrfid, @@ -792,6 +1057,56 @@ int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd, return 0; } +#ifdef BFD_LINUX +/* + * send a bfd packet with src/dst same IP so that the peer will receive + * the packet and forward it back to sender in the forwarding plane + */ +int bp_udp_send_fp(int sd, uint8_t *data, size_t datalen, + struct bfd_session *bfd) +{ + ssize_t wlen; + struct msghdr msg; + struct iovec iov[1]; + uint8_t msgctl[255]; + struct sockaddr_ll sadr_ll; + + + sadr_ll.sll_ifindex = bfd->ifp->ifindex; + sadr_ll.sll_halen = ETH_ALEN; + memcpy(sadr_ll.sll_addr, bfd->peer_hw_addr, sizeof(bfd->peer_hw_addr)); + sadr_ll.sll_protocol = htons(ETH_P_IP); + + /* Prepare message data. */ + iov[0].iov_base = data; + iov[0].iov_len = datalen; + + memset(&msg, 0, sizeof(msg)); + memset(msgctl, 0, sizeof(msgctl)); + msg.msg_name = &sadr_ll; + msg.msg_namelen = sizeof(sadr_ll); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + + /* Send echo to peer */ + wlen = sendmsg(sd, &msg, 0); + + if (wlen <= 0) { + if (bglobal.debug_network) + zlog_debug("udp-send: loopback failure: (%d) %s", errno, + strerror(errno)); + return -1; + } else if (wlen < (ssize_t)datalen) { + if (bglobal.debug_network) + zlog_debug("udp-send: partial send: %zd expected %zu", + wlen, datalen); + return -1; + } + + return 0; +} +#endif + int bp_udp_send(int sd, uint8_t ttl, uint8_t *data, size_t datalen, struct sockaddr *to, socklen_t tolen) { @@ -1219,6 +1534,57 @@ int bp_udp6_mhop(const struct vrf *vrf) return sd; } +#ifdef BFD_LINUX +/* tcpdump -dd udp dst port 3785 */ +struct sock_filter my_filterudp[] = { + {0x28, 0, 0, 0x0000000c}, {0x15, 0, 8, 0x00000800}, + {0x30, 0, 0, 0x00000017}, {0x15, 0, 6, 0x00000011}, + {0x28, 0, 0, 0x00000014}, {0x45, 4, 0, 0x00001fff}, + {0xb1, 0, 0, 0x0000000e}, {0x48, 0, 0, 0x00000010}, + {0x15, 0, 1, 0x00000ec9}, {0x6, 0, 0, 0x00040000}, + {0x6, 0, 0, 0x00000000}, +}; + +#define MY_FILTER_LENGTH 11 + +int bp_echo_socket(const struct vrf *vrf) +{ + int s; + + frr_with_privs (&bglobal.bfdd_privs) { + s = vrf_socket(AF_PACKET, SOCK_RAW, ETH_P_IP, vrf->vrf_id, + vrf->name); + } + + if (s == -1) + zlog_fatal("echo-socket: socket: %s", strerror(errno)); + + struct sock_fprog pf; + struct sockaddr_ll sll; + + /* adjust filter for socket to only receive ECHO packets */ + pf.filter = my_filterudp; + pf.len = MY_FILTER_LENGTH; + if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &pf, sizeof(pf)) == + -1) { + zlog_warn("%s: setsockopt(SO_ATTACH_FILTER): %s", __func__, + strerror(errno)); + return -1; + } + + + sll.sll_family = AF_PACKET; + sll.sll_protocol = htons(ETH_P_IP); + sll.sll_ifindex = 0; + if (bind(s, (struct sockaddr *)&sll, sizeof(sll)) < 0) { + zlog_warn("Failed to bind echo socket: %s", + safe_strerror(errno)); + return -1; + } + + return s; +} +#else int bp_echo_socket(const struct vrf *vrf) { int s; @@ -1234,6 +1600,7 @@ int bp_echo_socket(const struct vrf *vrf) return s; } +#endif int bp_echov6_socket(const struct vrf *vrf) { @@ -1257,3 +1624,41 @@ int bp_echov6_socket(const struct vrf *vrf) return s; } + +#ifdef BFD_LINUX +/* get peer's mac address to be used with Echo packets when they are looped in + * peers forwarding plane + */ +void bfd_peer_mac_set(int sd, struct bfd_session *bfd, + struct sockaddr_any *peer, struct interface *ifp) +{ + struct arpreq arpreq_; + + if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET)) + return; + + if (peer->sa_sin.sin_family == AF_INET) { + /* IPV4 */ + struct sockaddr_in *addr = + (struct sockaddr_in *)&arpreq_.arp_pa; + + memset(&arpreq_, 0, sizeof(struct arpreq)); + addr->sin_family = AF_INET; + memcpy(&addr->sin_addr.s_addr, &peer->sa_sin.sin_addr, + sizeof(addr->sin_addr)); + strlcpy(arpreq_.arp_dev, ifp->name, sizeof(arpreq_.arp_dev)); + + if (ioctl(sd, SIOCGARP, &arpreq_) < 0) { + zlog_warn("BFD: getting peer's mac failed error %s", + strerror(errno)); + UNSET_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET); + memset(bfd->peer_hw_addr, 0, sizeof(bfd->peer_hw_addr)); + + } else { + memcpy(bfd->peer_hw_addr, arpreq_.arp_ha.sa_data, + sizeof(bfd->peer_hw_addr)); + SET_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET); + } + } +} +#endif diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c index d4e12e4f1a..69424c45d9 100644 --- a/bfdd/bfdd_cli.c +++ b/bfdd/bfdd_cli.c @@ -423,12 +423,19 @@ DEFPY_YANG( "Configure echo mode\n") { if (!bfd_cli_is_profile(vty) && !bfd_cli_is_single_hop(vty)) { - vty_out(vty, "%% Echo mode is only available for single hop sessions.\n"); + vty_out(vty, + "%% Echo mode is only available for single hop sessions.\n"); return CMD_WARNING_CONFIG_FAILED; } if (!no && !bglobal.bg_use_dplane) { - vty_out(vty, "%% Current implementation of echo mode works only when the peer is also FRR.\n"); +#ifdef BFD_LINUX + vty_out(vty, + "%% Echo mode works correctly for IPv4, but only works when the peer is also FRR for IPv6.\n"); +#else + vty_out(vty, + "%% Current implementation of echo mode works only when the peer is also FRR.\n"); +#endif /* BFD_LINUX */ } nb_cli_enqueue_change(vty, "./echo-mode", NB_OP_MODIFY, diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c index 4f0758cf6a..1a2829f962 100644 --- a/pimd/pim6_cmd.c +++ b/pimd/pim6_cmd.c @@ -686,9 +686,7 @@ DEFPY (ipv6_mld_group_watermark, "Group count to generate watermark warning\n") { PIM_DECLVAR_CONTEXT_VRF(vrf, pim); - - /* TBD Depends on MLD data structure changes */ - (void)pim; + pim->gm_watermark_limit = limit; return CMD_SUCCESS; } @@ -703,9 +701,7 @@ DEFPY (no_ipv6_mld_group_watermark, IGNORED_IN_NO_STR) { PIM_DECLVAR_CONTEXT_VRF(vrf, pim); - - /* TBD Depends on MLD data structure changes */ - (void)pim; + pim->gm_watermark_limit = 0; return CMD_SUCCESS; } diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 817ebcc256..91cc3aa79b 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1135,12 +1135,12 @@ static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj) json = json_object_new_object(); json_object_int_add(json, "totalGroups", pim->igmp_group_count); json_object_int_add(json, "watermarkLimit", - pim->igmp_watermark_limit); + pim->gm_watermark_limit); } else { vty_out(vty, "Total IGMP groups: %u\n", pim->igmp_group_count); vty_out(vty, "Watermark warn limit(%s): %u\n", - pim->igmp_watermark_limit ? "Set" : "Not Set", - pim->igmp_watermark_limit); + pim->gm_watermark_limit ? "Set" : "Not Set", + pim->gm_watermark_limit); vty_out(vty, "Interface Group Mode Timer Srcs V Uptime \n"); } @@ -3334,7 +3334,7 @@ DEFPY (ip_igmp_group_watermark, "Group count to generate watermark warning\n") { PIM_DECLVAR_CONTEXT_VRF(vrf, pim); - pim->igmp_watermark_limit = limit; + pim->gm_watermark_limit = limit; return CMD_SUCCESS; } @@ -3349,7 +3349,7 @@ DEFPY (no_ip_igmp_group_watermark, IGNORED_IN_NO_STR) { PIM_DECLVAR_CONTEXT_VRF(vrf, pim); - pim->igmp_watermark_limit = 0; + pim->gm_watermark_limit = 0; return CMD_SUCCESS; } diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 849216af62..6ffeeb9657 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -1009,8 +1009,8 @@ static void igmp_group_count_incr(struct pim_interface *pim_ifp) uint32_t group_count = listcount(pim_ifp->gm_group_list); ++pim_ifp->pim->igmp_group_count; - if (pim_ifp->pim->igmp_group_count - == pim_ifp->pim->igmp_watermark_limit) { + if (pim_ifp->pim->igmp_group_count == + pim_ifp->pim->gm_watermark_limit) { zlog_warn( "IGMP group count reached watermark limit: %u(vrf: %s)", pim_ifp->pim->igmp_group_count, diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h index 23b9df4aff..684785dd13 100644 --- a/pimd/pim_instance.h +++ b/pimd/pim_instance.h @@ -173,7 +173,7 @@ struct pim_instance { struct thread *t_gm_recv; unsigned int igmp_group_count; - unsigned int igmp_watermark_limit; + unsigned int gm_watermark_limit; unsigned int keep_alive_time; unsigned int rp_keep_alive_time; diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h index d0c4921d07..5a2647b93f 100644 --- a/pimd/pim_oil.h +++ b/pimd/pim_oil.h @@ -187,9 +187,6 @@ extern int pim_channel_oil_compare(const struct channel_oil *c1, DECLARE_RBTREE_UNIQ(rb_pim_oil, struct channel_oil, oil_rb, pim_channel_oil_compare); - -extern struct list *pim_channel_oil_list; - void pim_oil_init(struct pim_instance *pim); void pim_oil_terminate(struct pim_instance *pim); diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 4dd1398733..43d9c29278 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -260,9 +260,14 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) ++writes; } - if (pim->igmp_watermark_limit != 0) { - vty_out(vty, "%sip igmp watermark-warn %u\n", spaces, - pim->igmp_watermark_limit); + if (pim->gm_watermark_limit != 0) { +#if PIM_IPV == 4 + vty_out(vty, "%s" PIM_AF_NAME " igmp watermark-warn %u\n", + spaces, pim->gm_watermark_limit); +#else + vty_out(vty, "%s" PIM_AF_NAME " mld watermark-warn %u\n", + spaces, pim->gm_watermark_limit); +#endif ++writes; } diff --git a/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf index 8fca099686..0476df740a 100644 --- a/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf +++ b/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf @@ -5,7 +5,11 @@ ! bfd peer 192.168.0.2 vrf r1-bfd-cust1 + receive-interval 1000 + transmit-interval 1000 echo-mode + echo transmit-interval 1000 + echo receive-interval 1000 no shutdown ! ! diff --git a/tests/topotests/bfd_vrf_topo1/r1/peers.json b/tests/topotests/bfd_vrf_topo1/r1/peers.json index f49768ff75..57cea71e53 100644 --- a/tests/topotests/bfd_vrf_topo1/r1/peers.json +++ b/tests/topotests/bfd_vrf_topo1/r1/peers.json @@ -1,7 +1,7 @@ [ { "remote-receive-interval": 1000, - "remote-transmit-interval": 500, + "remote-transmit-interval": 1000, "peer": "192.168.0.2", "status": "up" } diff --git a/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf index 4490090ec6..69edd1536b 100644 --- a/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf +++ b/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf @@ -6,12 +6,18 @@ bfd peer 192.168.0.1 vrf r2-bfd-cust1 receive-interval 1000 - transmit-interval 500 + transmit-interval 1000 echo-mode + echo transmit-interval 1000 + echo receive-interval 1000 no shutdown ! peer 192.168.1.1 vrf r2-bfd-cust1 + receive-interval 1000 + transmit-interval 1000 echo-mode + echo transmit-interval 1000 + echo receive-interval 1000 no shutdown ! ! diff --git a/tests/topotests/bfd_vrf_topo1/r2/peers.json b/tests/topotests/bfd_vrf_topo1/r2/peers.json index 267459c7a8..0a1c34224b 100644 --- a/tests/topotests/bfd_vrf_topo1/r2/peers.json +++ b/tests/topotests/bfd_vrf_topo1/r2/peers.json @@ -4,7 +4,7 @@ "status": "up" }, { - "remote-echo-receive-interval": 100, + "remote-echo-receive-interval": 1000, "peer": "192.168.1.1", "status": "up" }, diff --git a/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf index 0333320898..00162b5247 100644 --- a/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf +++ b/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf @@ -5,7 +5,9 @@ ! bfd peer 192.168.1.2 vrf r3-bfd-cust1 - echo-interval 100 + receive-interval 1000 + transmit-interval 1000 + echo-interval 1000 echo-mode no shutdown ! diff --git a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py index 6153aee418..1097be3d70 100644 --- a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py +++ b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py @@ -197,11 +197,199 @@ def teardown_module(mod): logger.info("=" * 40) -def test_bgp_conditional_advertisement(): - """ - Test BGP conditional advertisement functionality. - """ +def all_routes_advertised(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": [{"protocol": "bgp"}], + "192.0.2.1/32": [{"protocol": "bgp"}], + "192.0.2.5/32": [{"protocol": "bgp"}], + "10.139.224.0/20": [{"protocol": "bgp"}], + "203.0.113.1/32": [{"protocol": "bgp"}], + } + return topotest.json_cmp(output, expected) + + +def all_routes_withdrawn(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": None, + "192.0.2.1/32": None, + "192.0.2.5/32": None, + "10.139.224.0/20": None, + "203.0.113.1/32": None, + } + return topotest.json_cmp(output, expected) + + +# BGP conditional advertisement with route-maps +# EXIST-MAP, ADV-MAP-1 and RMAP-1 +def exist_map_routes_present(router): + return all_routes_advertised(router) + + +def exist_map_routes_not_present(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": None, + "192.0.2.1/32": None, + "192.0.2.5/32": [{"protocol": "bgp"}], + "10.139.224.0/20": None, + "203.0.113.1/32": [{"protocol": "bgp"}], + } + return topotest.json_cmp(output, expected) + + +def non_exist_map_routes_present(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": [{"protocol": "bgp"}], + "192.0.2.1/32": None, + "192.0.2.5/32": [{"protocol": "bgp"}], + "10.139.224.0/20": None, + "203.0.113.1/32": [{"protocol": "bgp"}], + } + return topotest.json_cmp(output, expected) + + +def non_exist_map_routes_not_present(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": None, + "192.0.2.1/32": [{"protocol": "bgp"}], + "192.0.2.5/32": [{"protocol": "bgp"}], + "10.139.224.0/20": [{"protocol": "bgp"}], + "203.0.113.1/32": [{"protocol": "bgp"}], + } + return topotest.json_cmp(output, expected) + + +def exist_map_no_condition_route_map(router): + return non_exist_map_routes_present(router) + + +def non_exist_map_no_condition_route_map(router): + return all_routes_advertised(router) + + +def exist_map_routes_present_rmap_filter(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": None, + "192.0.2.1/32": [{"protocol": "bgp"}], + "192.0.2.5/32": None, + "10.139.224.0/20": [{"protocol": "bgp"}], + "203.0.113.1/32": None, + } + return topotest.json_cmp(output, expected) + + +def exist_map_routes_present_no_rmap_filter(router): + return all_routes_advertised(router) + + +def non_exist_map_routes_present_rmap_filter(router): + return all_routes_withdrawn(router) + + +def non_exist_map_routes_present_no_rmap_filter(router): + return non_exist_map_routes_present(router) + + +def exist_map_routes_not_present_rmap_filter(router): + return all_routes_withdrawn(router) + + +def exist_map_routes_not_present_no_rmap_filter(router): + return exist_map_routes_not_present(router) + + +def non_exist_map_routes_not_present_rmap_filter(router): + return exist_map_routes_present_rmap_filter(router) + + +def non_exist_map_routes_not_present_no_rmap_filter(router): + return non_exist_map_routes_not_present(router) + + +# BGP conditional advertisement with route-maps +# EXIST-MAP, ADV-MAP-2 and RMAP-2 +def exist_map_routes_not_present_rmap2_filter(router): + return all_routes_withdrawn(router) + + +def exist_map_routes_not_present_no_rmap2_filter(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": None, + "192.0.2.1/32": [{"protocol": "bgp"}], + "192.0.2.5/32": [{"protocol": "bgp"}], + "10.139.224.0/20": [{"protocol": "bgp"}], + "203.0.113.1/32": None, + } + return topotest.json_cmp(output, expected) + + +def non_exist_map_routes_not_present_rmap2_filter(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": None, + "192.0.2.1/32": None, + "192.0.2.5/32": None, + "10.139.224.0/20": None, + "203.0.113.1/32": [{"protocol": "bgp", "metric": 911}], + } + return topotest.json_cmp(output, expected) + +def non_exist_map_routes_not_present_no_rmap2_filter(router): + return non_exist_map_routes_not_present(router) + + +def exist_map_routes_present_rmap2_filter(router): + return non_exist_map_routes_not_present_rmap2_filter(router) + + +def exist_map_routes_present_no_rmap2_filter(router): + return all_routes_advertised(router) + + +def non_exist_map_routes_present_rmap2_filter(router): + return all_routes_withdrawn(router) + + +def non_exist_map_routes_present_no_rmap2_filter(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": [{"protocol": "bgp"}], + "192.0.2.1/32": [{"protocol": "bgp"}], + "192.0.2.5/32": [{"protocol": "bgp"}], + "10.139.224.0/20": [{"protocol": "bgp"}], + "203.0.113.1/32": None, + } + return topotest.json_cmp(output, expected) + + +def exist_map_routes_present_rmap2_network(router): + return non_exist_map_routes_not_present_rmap2_filter(router) + + +def exist_map_routes_present_rmap2_no_network(router): + return all_routes_withdrawn(router) + + +def non_exist_map_routes_not_present_rmap2_network(router): + return non_exist_map_routes_not_present_rmap2_filter(router) + + +def non_exist_map_routes_not_present_rmap2_no_network(router): + return all_routes_withdrawn(router) + + +passed = "PASSED!!!" +failed = "FAILED!!!" + + +def test_bgp_conditional_advertisement_step1(): tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) @@ -210,172 +398,9 @@ def test_bgp_conditional_advertisement(): router2 = tgen.gears["r2"] router3 = tgen.gears["r3"] - passed = "PASSED!!!" - failed = "FAILED!!!" - - def _all_routes_advertised(router): - output = json.loads(router.vtysh_cmd("show ip route json")) - expected = { - "0.0.0.0/0": [{"protocol": "bgp"}], - "192.0.2.1/32": [{"protocol": "bgp"}], - "192.0.2.5/32": [{"protocol": "bgp"}], - "10.139.224.0/20": [{"protocol": "bgp"}], - "203.0.113.1/32": [{"protocol": "bgp"}], - } - return topotest.json_cmp(output, expected) - - def _all_routes_withdrawn(router): - output = json.loads(router.vtysh_cmd("show ip route json")) - expected = { - "0.0.0.0/0": None, - "192.0.2.1/32": None, - "192.0.2.5/32": None, - "10.139.224.0/20": None, - "203.0.113.1/32": None, - } - return topotest.json_cmp(output, expected) - - # BGP conditional advertisement with route-maps - # EXIST-MAP, ADV-MAP-1 and RMAP-1 - def _exist_map_routes_present(router): - return _all_routes_advertised(router) - - def _exist_map_routes_not_present(router): - output = json.loads(router.vtysh_cmd("show ip route json")) - expected = { - "0.0.0.0/0": None, - "192.0.2.1/32": None, - "192.0.2.5/32": [{"protocol": "bgp"}], - "10.139.224.0/20": None, - "203.0.113.1/32": [{"protocol": "bgp"}], - } - return topotest.json_cmp(output, expected) - - def _non_exist_map_routes_present(router): - output = json.loads(router.vtysh_cmd("show ip route json")) - expected = { - "0.0.0.0/0": [{"protocol": "bgp"}], - "192.0.2.1/32": None, - "192.0.2.5/32": [{"protocol": "bgp"}], - "10.139.224.0/20": None, - "203.0.113.1/32": [{"protocol": "bgp"}], - } - return topotest.json_cmp(output, expected) - - def _non_exist_map_routes_not_present(router): - output = json.loads(router.vtysh_cmd("show ip route json")) - expected = { - "0.0.0.0/0": None, - "192.0.2.1/32": [{"protocol": "bgp"}], - "192.0.2.5/32": [{"protocol": "bgp"}], - "10.139.224.0/20": [{"protocol": "bgp"}], - "203.0.113.1/32": [{"protocol": "bgp"}], - } - return topotest.json_cmp(output, expected) - - def _exist_map_no_condition_route_map(router): - return _non_exist_map_routes_present(router) - - def _non_exist_map_no_condition_route_map(router): - return _all_routes_advertised(router) - - def _exist_map_routes_present_rmap_filter(router): - output = json.loads(router.vtysh_cmd("show ip route json")) - expected = { - "0.0.0.0/0": None, - "192.0.2.1/32": [{"protocol": "bgp"}], - "192.0.2.5/32": None, - "10.139.224.0/20": [{"protocol": "bgp"}], - "203.0.113.1/32": None, - } - return topotest.json_cmp(output, expected) - - def _exist_map_routes_present_no_rmap_filter(router): - return _all_routes_advertised(router) - - def _non_exist_map_routes_present_rmap_filter(router): - return _all_routes_withdrawn(router) - - def _non_exist_map_routes_present_no_rmap_filter(router): - return _non_exist_map_routes_present(router) - - def _exist_map_routes_not_present_rmap_filter(router): - return _all_routes_withdrawn(router) - - def _exist_map_routes_not_present_no_rmap_filter(router): - return _exist_map_routes_not_present(router) - - def _non_exist_map_routes_not_present_rmap_filter(router): - return _exist_map_routes_present_rmap_filter(router) - - def _non_exist_map_routes_not_present_no_rmap_filter(router): - return _non_exist_map_routes_not_present(router) - - # BGP conditional advertisement with route-maps - # EXIST-MAP, ADV-MAP-2 and RMAP-2 - def _exist_map_routes_not_present_rmap2_filter(router): - return _all_routes_withdrawn(router) - - def _exist_map_routes_not_present_no_rmap2_filter(router): - output = json.loads(router.vtysh_cmd("show ip route json")) - expected = { - "0.0.0.0/0": None, - "192.0.2.1/32": [{"protocol": "bgp"}], - "192.0.2.5/32": [{"protocol": "bgp"}], - "10.139.224.0/20": [{"protocol": "bgp"}], - "203.0.113.1/32": None, - } - return topotest.json_cmp(output, expected) - - def _non_exist_map_routes_not_present_rmap2_filter(router): - output = json.loads(router.vtysh_cmd("show ip route json")) - expected = { - "0.0.0.0/0": None, - "192.0.2.1/32": None, - "192.0.2.5/32": None, - "10.139.224.0/20": None, - "203.0.113.1/32": [{"protocol": "bgp", "metric": 911}], - } - return topotest.json_cmp(output, expected) - - def _non_exist_map_routes_not_present_no_rmap2_filter(router): - return _non_exist_map_routes_not_present(router) - - def _exist_map_routes_present_rmap2_filter(router): - return _non_exist_map_routes_not_present_rmap2_filter(router) - - def _exist_map_routes_present_no_rmap2_filter(router): - return _all_routes_advertised(router) - - def _non_exist_map_routes_present_rmap2_filter(router): - return _all_routes_withdrawn(router) - - def _non_exist_map_routes_present_no_rmap2_filter(router): - output = json.loads(router.vtysh_cmd("show ip route json")) - expected = { - "0.0.0.0/0": [{"protocol": "bgp"}], - "192.0.2.1/32": [{"protocol": "bgp"}], - "192.0.2.5/32": [{"protocol": "bgp"}], - "10.139.224.0/20": [{"protocol": "bgp"}], - "203.0.113.1/32": None, - } - return topotest.json_cmp(output, expected) - - def _exist_map_routes_present_rmap2_network(router): - return _non_exist_map_routes_not_present_rmap2_filter(router) - - def _exist_map_routes_present_rmap2_no_network(router): - return _all_routes_withdrawn(router) - - def _non_exist_map_routes_not_present_rmap2_network(router): - return _non_exist_map_routes_not_present_rmap2_filter(router) - - def _non_exist_map_routes_not_present_rmap2_no_network(router): - return _all_routes_withdrawn(router) - # TC11: R3 BGP convergence, without advertise-map configuration. # All routes are advertised to R3. - test_func = functools.partial(_all_routes_advertised, router3) + test_func = functools.partial(all_routes_advertised, router3) success, result = topotest.run_and_expect(test_func, None, count=130, wait=1) msg = 'TC11: "router3" BGP convergence - ' @@ -383,6 +408,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step2(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC21: exist-map routes present in R2's BGP table. # advertise-map routes present in R2's BGP table are advertised to R3. router2.vtysh_cmd( @@ -394,7 +429,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_exist_map_routes_present, router3) + test_func = functools.partial(exist_map_routes_present, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC21: exist-map routes present in "router2" BGP table - ' @@ -402,6 +437,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step3(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC22: exist-map routes not present in R2's BGP table # advertise-map routes present in R2's BGP table are withdrawn from R3. router1.vtysh_cmd( @@ -413,7 +458,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_exist_map_routes_not_present, router3) + test_func = functools.partial(exist_map_routes_not_present, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC22: exist-map routes not present in "router2" BGP table - ' @@ -421,6 +466,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step4(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC31: non-exist-map routes not present in R2's BGP table # advertise-map routes present in R2's BGP table are advertised to R3. router2.vtysh_cmd( @@ -432,7 +487,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_non_exist_map_routes_not_present, router3) + test_func = functools.partial(non_exist_map_routes_not_present, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC31: non-exist-map routes not present in "router2" BGP table - ' @@ -440,6 +495,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step5(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC32: non-exist-map routes present in R2's BGP table # advertise-map routes present in R2's BGP table are withdrawn from R3. router1.vtysh_cmd( @@ -451,7 +516,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_non_exist_map_routes_present, router3) + test_func = functools.partial(non_exist_map_routes_present, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC32: non-exist-map routes present in "router2" BGP table - ' @@ -459,6 +524,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step6(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC41: non-exist-map route-map configuration removed in R2. # advertise-map routes present in R2's BGP table are advertised to R3. router2.vtysh_cmd( @@ -468,7 +543,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_non_exist_map_no_condition_route_map, router3) + test_func = functools.partial(non_exist_map_no_condition_route_map, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC41: non-exist-map route-map removed in "router2" - ' @@ -476,6 +551,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step7(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC42: exist-map route-map configuration removed in R2 # advertise-map routes present in R2's BGP table are withdrawn from R3. router2.vtysh_cmd( @@ -487,7 +572,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_exist_map_no_condition_route_map, router3) + test_func = functools.partial(exist_map_no_condition_route_map, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC42: exist-map route-map removed in "router2" - ' @@ -495,6 +580,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step8(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC51: exist-map routes present in R2's BGP table, with route-map filter. # All routes are withdrawn from R3 except advertise-map routes. router2.vtysh_cmd( @@ -510,7 +605,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_exist_map_routes_present_rmap_filter, router3) + test_func = functools.partial(exist_map_routes_present_rmap_filter, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC51: exist-map routes present with route-map filter - " @@ -518,6 +613,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step9(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC52: exist-map routes present in R2's BGP table, no route-map filter. # All routes are advertised to R3 including advertise-map routes. router2.vtysh_cmd( @@ -529,7 +634,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_exist_map_routes_present_no_rmap_filter, router3) + test_func = functools.partial(exist_map_routes_present_no_rmap_filter, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC52: exist-map routes present, no route-map filter - " @@ -537,6 +642,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step10(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC53: non-exist-map routes present in R2's BGP table, with route-map filter. # All routes are withdrawn from R3 including advertise-map routes. router2.vtysh_cmd( @@ -549,7 +664,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_non_exist_map_routes_present_rmap_filter, router3) + test_func = functools.partial(non_exist_map_routes_present_rmap_filter, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC53: non-exist-map routes present, with route-map filter - " @@ -557,6 +672,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step11(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC54: non-exist-map routes present in R2's BGP table, no route-map filter. # All routes are advertised to R3 except advertise-map routes. router2.vtysh_cmd( @@ -568,7 +693,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_non_exist_map_routes_present_no_rmap_filter, router3) + test_func = functools.partial(non_exist_map_routes_present_no_rmap_filter, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC54: non-exist-map routes present, no route-map filter - " @@ -576,6 +701,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step12(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC61: exist-map routes not present in R2's BGP table, with route-map filter. # All routes are withdrawn from R3 including advertise-map routes. router1.vtysh_cmd( @@ -596,7 +731,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_exist_map_routes_not_present_rmap_filter, router3) + test_func = functools.partial(exist_map_routes_not_present_rmap_filter, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC61: exist-map routes not present, route-map filter - " @@ -604,6 +739,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step13(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC62: exist-map routes not present in R2's BGP table, without route-map filter. # All routes are advertised to R3 except advertise-map routes. router2.vtysh_cmd( @@ -615,7 +760,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_exist_map_routes_not_present_no_rmap_filter, router3) + test_func = functools.partial(exist_map_routes_not_present_no_rmap_filter, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC62: exist-map routes not present, no route-map filter - " @@ -623,6 +768,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step14(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC63: non-exist-map routes not present in R2's BGP table, with route-map filter. # All routes are withdrawn from R3 except advertise-map routes. router2.vtysh_cmd( @@ -635,9 +790,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial( - _non_exist_map_routes_not_present_rmap_filter, router3 - ) + test_func = functools.partial(non_exist_map_routes_not_present_rmap_filter, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC63: non-exist-map routes not present, route-map filter - " @@ -645,6 +798,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step15(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC64: non-exist-map routes not present in R2's BGP table, without route-map filter. # All routes are advertised to R3 including advertise-map routes. router2.vtysh_cmd( @@ -657,7 +820,7 @@ def test_bgp_conditional_advertisement(): ) test_func = functools.partial( - _non_exist_map_routes_not_present_no_rmap_filter, router3 + non_exist_map_routes_not_present_no_rmap_filter, router3 ) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) @@ -666,6 +829,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step16(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC71: exist-map routes present in R2's BGP table, with route-map filter. # All routes are withdrawn from R3 except advertise-map routes. router1.vtysh_cmd( @@ -686,7 +859,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_exist_map_routes_present_rmap2_filter, router3) + test_func = functools.partial(exist_map_routes_present_rmap2_filter, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC71: exist-map routes present, route-map filter - " @@ -694,6 +867,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step17(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC72: exist-map routes present in R2's BGP table, without route-map filter. # All routes are advertised to R3 including advertise-map routes. router2.vtysh_cmd( @@ -705,7 +888,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_exist_map_routes_present_no_rmap2_filter, router3) + test_func = functools.partial(exist_map_routes_present_no_rmap2_filter, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC72: exist-map routes present, no route-map filter - " @@ -713,6 +896,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step18(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC73: non-exist-map routes present in R2's BGP table, with route-map filter. # All routes are advertised to R3 including advertise-map routes. router2.vtysh_cmd( @@ -725,7 +918,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_non_exist_map_routes_present_rmap2_filter, router3) + test_func = functools.partial(non_exist_map_routes_present_rmap2_filter, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC73: non-exist-map routes present, route-map filter - " @@ -733,6 +926,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step19(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC74: non-exist-map routes present in R2's BGP table, without route-map filter. # All routes are advertised to R3 including advertise-map routes. router2.vtysh_cmd( @@ -744,9 +947,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial( - _non_exist_map_routes_present_no_rmap2_filter, router3 - ) + test_func = functools.partial(non_exist_map_routes_present_no_rmap2_filter, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC74: non-exist-map routes present, no route-map filter - " @@ -754,6 +955,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step20(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC81: exist-map routes not present in R2's BGP table, with route-map filter. # All routes are withdrawn from R3 including advertise-map routes. router1.vtysh_cmd( @@ -774,7 +985,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_exist_map_routes_not_present_rmap2_filter, router3) + test_func = functools.partial(exist_map_routes_not_present_rmap2_filter, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC81: exist-map routes not present, route-map filter - " @@ -782,6 +993,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step21(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC82: exist-map routes not present in R2's BGP table, without route-map filter. # All routes are advertised to R3 except advertise-map routes. router2.vtysh_cmd( @@ -793,9 +1014,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial( - _exist_map_routes_not_present_no_rmap2_filter, router3 - ) + test_func = functools.partial(exist_map_routes_not_present_no_rmap2_filter, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC82: exist-map routes not present, no route-map filter - " @@ -803,6 +1022,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step22(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC83: non-exist-map routes not present in R2's BGP table, with route-map filter. # All routes are advertised to R3 including advertise-map routes. router2.vtysh_cmd( @@ -816,7 +1045,7 @@ def test_bgp_conditional_advertisement(): ) test_func = functools.partial( - _non_exist_map_routes_not_present_rmap2_filter, router3 + non_exist_map_routes_not_present_rmap2_filter, router3 ) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) @@ -825,6 +1054,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step23(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC84: non-exist-map routes not present in R2's BGP table, without route-map filter. # All routes are advertised to R3 including advertise-map routes. router2.vtysh_cmd( @@ -837,7 +1076,7 @@ def test_bgp_conditional_advertisement(): ) test_func = functools.partial( - _non_exist_map_routes_not_present_no_rmap2_filter, router3 + non_exist_map_routes_not_present_no_rmap2_filter, router3 ) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) @@ -846,6 +1085,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step24(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC91: exist-map routes present in R2's BGP table, with route-map filter and network. # All routes are advertised to R3 including advertise-map routes. router1.vtysh_cmd( @@ -866,7 +1115,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_exist_map_routes_present_rmap2_network, router3) + test_func = functools.partial(exist_map_routes_present_rmap2_network, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC91: exist-map routes present, route-map filter and network - " @@ -874,6 +1123,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step25(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC92: exist-map routes present in R2's BGP table, with route-map filter and no network. # All routes are advertised to R3 except advertise-map routes. router2.vtysh_cmd( @@ -885,7 +1144,7 @@ def test_bgp_conditional_advertisement(): """ ) - test_func = functools.partial(_exist_map_routes_present_rmap2_no_network, router3) + test_func = functools.partial(exist_map_routes_present_rmap2_no_network, router3) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC92: exist-map routes present, route-map filter and no network - " @@ -893,6 +1152,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step26(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC93: non-exist-map routes not present in R2's BGP table, with route-map filter and network. # All routes are advertised to R3 including advertise-map routes. router1.vtysh_cmd( @@ -914,7 +1183,7 @@ def test_bgp_conditional_advertisement(): ) test_func = functools.partial( - _non_exist_map_routes_not_present_rmap2_network, router3 + non_exist_map_routes_not_present_rmap2_network, router3 ) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) @@ -923,6 +1192,16 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + +def test_bgp_conditional_advertisement_step27(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + # TC94: non-exist-map routes not present in R2's BGP table, with route-map filter and no network. # All routes are advertised to R3 except advertise-map routes. router2.vtysh_cmd( @@ -935,7 +1214,7 @@ def test_bgp_conditional_advertisement(): ) test_func = functools.partial( - _non_exist_map_routes_not_present_rmap2_no_network, router3 + non_exist_map_routes_not_present_rmap2_no_network, router3 ) success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 4bd0ac27f6..31d8294a0f 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -290,9 +290,20 @@ static int netlink_recvbuf(struct nlsock *nl, uint32_t newsize) return 0; } +static const char *group2str(uint32_t group) +{ + switch (group) { + case RTNLGRP_TUNNEL: + return "RTNLGRP_TUNNEL"; + default: + return "UNKNOWN"; + } +} + /* Make socket for Linux netlink interface. */ static int netlink_socket(struct nlsock *nl, unsigned long groups, - unsigned long ext_groups, ns_id_t ns_id) + uint32_t ext_groups[], uint8_t ext_group_size, + ns_id_t ns_id) { int ret; struct sockaddr_nl snl; @@ -311,18 +322,30 @@ static int netlink_socket(struct nlsock *nl, unsigned long groups, snl.nl_family = AF_NETLINK; snl.nl_groups = groups; + if (ext_group_size) { + uint8_t i; + + for (i = 0; i < ext_group_size; i++) { #if defined SOL_NETLINK - if (ext_groups) { - ret = setsockopt(sock, SOL_NETLINK, - NETLINK_ADD_MEMBERSHIP, &ext_groups, - sizeof(ext_groups)); - if (ret < 0) { + ret = setsockopt(sock, SOL_NETLINK, + NETLINK_ADD_MEMBERSHIP, + &ext_groups[i], + sizeof(ext_groups[i])); + if (ret < 0) { + zlog_notice( + "can't setsockopt NETLINK_ADD_MEMBERSHIP for group %s(%u), this linux kernel does not support it: %s(%d)", + group2str(ext_groups[i]), + ext_groups[i], + safe_strerror(errno), errno); + } +#else zlog_notice( - "can't setsockopt NETLINK_ADD_MEMBERSHIP: %s(%d)", - safe_strerror(errno), errno); + "Unable to use NETLINK_ADD_MEMBERSHIP via SOL_NETLINK for %s(%u) since the linux kernel does not support the socket option", + group2str(ext_groups[i]), + ext_groups[i]); +#endif } } -#endif /* Bind the socket to the netlink structure for anything. */ ret = bind(sock, (struct sockaddr *)&snl, sizeof(snl)); @@ -1734,7 +1757,8 @@ void kernel_init(struct zebra_ns *zns) snprintf(zns->netlink.name, sizeof(zns->netlink.name), "netlink-listen (NS %u)", zns->ns_id); zns->netlink.sock = -1; - if (netlink_socket(&zns->netlink, groups, ext_groups, zns->ns_id) < 0) { + if (netlink_socket(&zns->netlink, groups, &ext_groups, 1, zns->ns_id) < + 0) { zlog_err("Failure to create %s socket", zns->netlink.name); exit(-1); @@ -1745,7 +1769,7 @@ void kernel_init(struct zebra_ns *zns) snprintf(zns->netlink_cmd.name, sizeof(zns->netlink_cmd.name), "netlink-cmd (NS %u)", zns->ns_id); zns->netlink_cmd.sock = -1; - if (netlink_socket(&zns->netlink_cmd, 0, 0, zns->ns_id) < 0) { + if (netlink_socket(&zns->netlink_cmd, 0, 0, 0, zns->ns_id) < 0) { zlog_err("Failure to create %s socket", zns->netlink_cmd.name); exit(-1); @@ -1758,7 +1782,7 @@ void kernel_init(struct zebra_ns *zns) sizeof(zns->netlink_dplane_out.name), "netlink-dp (NS %u)", zns->ns_id); zns->netlink_dplane_out.sock = -1; - if (netlink_socket(&zns->netlink_dplane_out, 0, 0, zns->ns_id) < 0) { + if (netlink_socket(&zns->netlink_dplane_out, 0, 0, 0, zns->ns_id) < 0) { zlog_err("Failure to create %s socket", zns->netlink_dplane_out.name); exit(-1); @@ -1771,7 +1795,7 @@ void kernel_init(struct zebra_ns *zns) sizeof(zns->netlink_dplane_in.name), "netlink-dp-in (NS %u)", zns->ns_id); zns->netlink_dplane_in.sock = -1; - if (netlink_socket(&zns->netlink_dplane_in, dplane_groups, 0, + if (netlink_socket(&zns->netlink_dplane_in, dplane_groups, 0, 0, zns->ns_id) < 0) { zlog_err("Failure to create %s socket", zns->netlink_dplane_in.name); diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 57fd304ae8..2741a23242 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1354,6 +1354,16 @@ static void kernel_read(struct thread *thread) if (nbytes < 0) { if (errno == ENOBUFS) { +#ifdef __FreeBSD__ + /* + * ENOBUFS indicates a temporary resource + * shortage and is not harmful for consistency of + * reading the routing socket. Ignore it. + */ + thread_add_read(zrouter.master, kernel_read, NULL, sock, + NULL); + return; +#else flog_err(EC_ZEBRA_RECVMSG_OVERRUN, "routing socket overrun: %s", safe_strerror(errno)); @@ -1363,6 +1373,7 @@ static void kernel_read(struct thread *thread) * recover zebra at this point. */ exit(-1); +#endif } if (errno != EAGAIN && errno != EWOULDBLOCK) flog_err_sys(EC_LIB_SOCKET, "routing socket error: %s", diff --git a/zebra/main.c b/zebra/main.c index e516688a19..46cf2eea7d 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -71,9 +71,6 @@ struct thread_master *master; /* Route retain mode flag. */ int retain_mode = 0; -/* Allow non-frr entities to delete frr routes */ -int allow_delete = 0; - int graceful_restart; bool v6_rr_semantics = false; @@ -336,7 +333,7 @@ int main(int argc, char **argv) // batch_mode = 1; break; case 'a': - allow_delete = 1; + zrouter.allow_delete = true; break; case 'e': { unsigned long int parsed_multipath = diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 21c991c7db..ce06f1683d 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -341,6 +341,22 @@ static inline int proto2zebra(int proto, int family, bool is_nexthop) case RTPROT_SRTE: proto = ZEBRA_ROUTE_SRTE; break; + case RTPROT_UNSPEC: + case RTPROT_REDIRECT: + case RTPROT_KERNEL: + case RTPROT_BOOT: + case RTPROT_GATED: + case RTPROT_RA: + case RTPROT_MRT: + case RTPROT_BIRD: + case RTPROT_DNROUTED: + case RTPROT_XORP: + case RTPROT_NTK: + case RTPROT_MROUTED: + case RTPROT_KEEPALIVED: + case RTPROT_OPENR: + proto = ZEBRA_ROUTE_KERNEL; + break; case RTPROT_ZEBRA: if (is_nexthop) { proto = ZEBRA_ROUTE_NHG; @@ -977,8 +993,19 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, if (nhe_id || ng) rib_add_multipath(afi, SAFI_UNICAST, &p, &src_p, re, ng, startup); - else + else { + /* + * I really don't see how this is possible + * but since we are testing for it let's + * let the end user know why the route + * that was just received was swallowed + * up and forgotten + */ + zlog_err( + "%s: %pFX multipath RTM_NEWROUTE has a invalid nexthop group from the kernel", + __func__, &p); XFREE(MTYPE_RE, re); + } } } else { if (nhe_id) { diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 63f15b0f20..adfd3174e3 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -77,9 +77,6 @@ static struct dplane_ctx_q rib_dplane_q; DEFINE_HOOK(rib_update, (struct route_node * rn, const char *reason), (rn, reason)); -/* Should we allow non FRR processes to delete our routes */ -extern int allow_delete; - /* Each route type's string and default distance value. */ static const struct { int key; @@ -167,6 +164,30 @@ struct wq_evpn_wrapper { #pragma FRR printfrr_ext "%pZN" (struct route_node *) #endif +static const char *subqueue2str(uint8_t index) +{ + switch (index) { + case 0: + return "NHG Objects"; + case 1: + return "EVPN/VxLan Objects"; + case 2: + return "Connected Routes"; + case 3: + return "Kernel Routes"; + case 4: + return "Static Routes"; + case 5: + return "RIP/OSPF/ISIS/EIGRP/NHRP Routes"; + case 6: + return "BGP Routes"; + case 7: + return "Other Routes"; + } + + return "Unknown"; +} + printfrr_ext_autoreg_p("ZN", printfrr_zebra_node); static ssize_t printfrr_zebra_node(struct fbuf *buf, struct printfrr_eargs *ea, const void *ptr) @@ -2407,8 +2428,8 @@ static void process_subq_nhg(struct listnode *lnode) if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( - "NHG Context id=%u dequeued from sub-queue %u", - ctx->id, qindex); + "NHG Context id=%u dequeued from sub-queue %s", + ctx->id, subqueue2str(qindex)); /* Process nexthop group updates coming 'up' from the OS */ @@ -2418,8 +2439,8 @@ static void process_subq_nhg(struct listnode *lnode) nhe = w->u.nhe; if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug("NHG %u dequeued from sub-queue %u", - nhe->id, qindex); + zlog_debug("NHG %u dequeued from sub-queue %s", nhe->id, + subqueue2str(qindex)); /* Process incoming nhg update, probably from a proto daemon */ newnhe = zebra_nhg_proto_add(nhe->id, nhe->type, @@ -2465,9 +2486,9 @@ static void process_subq_route(struct listnode *lnode, uint8_t qindex) if (dest) re = re_list_first(&dest->routes); - zlog_debug("%s(%u:%u):%pRN rn %p dequeued from sub-queue %u", + zlog_debug("%s(%u:%u):%pRN rn %p dequeued from sub-queue %s", zvrf_name(zvrf), zvrf_id(zvrf), re ? re->table : 0, - rnode, rnode, qindex); + rnode, rnode, subqueue2str(qindex)); } if (rnode->info) @@ -2578,8 +2599,8 @@ static int rib_meta_queue_add(struct meta_queue *mq, void *data) RIB_ROUTE_QUEUED(qindex))) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) rnode_debug(rn, re->vrf_id, - "rn %p is already queued in sub-queue %u", - (void *)rn, qindex); + "rn %p is already queued in sub-queue %s", + (void *)rn, subqueue2str(qindex)); return -1; } @@ -2589,8 +2610,8 @@ static int rib_meta_queue_add(struct meta_queue *mq, void *data) mq->size++; if (IS_ZEBRA_DEBUG_RIB_DETAILED) - rnode_debug(rn, re->vrf_id, "queued rn %p into sub-queue %u", - (void *)rn, qindex); + rnode_debug(rn, re->vrf_id, "queued rn %p into sub-queue %s", + (void *)rn, subqueue2str(qindex)); return 0; } @@ -2615,8 +2636,8 @@ static int rib_meta_queue_nhg_ctx_add(struct meta_queue *mq, void *data) mq->size++; if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug("NHG Context id=%u queued into sub-queue %u", - ctx->id, qindex); + zlog_debug("NHG Context id=%u queued into sub-queue %s", + ctx->id, subqueue2str(qindex)); return 0; } @@ -2641,8 +2662,8 @@ static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data) mq->size++; if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug("NHG id=%u queued into sub-queue %u", - nhe->id, qindex); + zlog_debug("NHG id=%u queued into sub-queue %s", nhe->id, + subqueue2str(qindex)); return 0; } @@ -3722,8 +3743,8 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, rn, fib, zebra_route_string(fib->type)); } - if (allow_delete - || CHECK_FLAG(dest->flags, RIB_ROUTE_ANY_QUEUED)) { + if (zrouter.allow_delete || + CHECK_FLAG(dest->flags, RIB_ROUTE_ANY_QUEUED)) { UNSET_FLAG(fib->status, ROUTE_ENTRY_INSTALLED); /* Unset flags. */ for (rtnh = fib->nhe->nhg.nexthop; rtnh; @@ -3768,8 +3789,8 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, if (same) { struct nexthop *tmp_nh; - if (fromkernel && CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE) - && !allow_delete) { + if (fromkernel && CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE) && + !zrouter.allow_delete) { rib_install_kernel(rn, same, NULL); route_unlock_node(rn); diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 9fccda9e08..f7ad30b41f 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -278,6 +278,8 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack) { zrouter.sequence_num = 0; + zrouter.allow_delete = false; + zrouter.packets_to_process = ZEBRA_ZAPI_PACKETS_TO_PROCESS; zrouter.nhg_keep = ZEBRA_DEFAULT_NHG_KEEP_TIMER; diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index d51e7a2b7d..0e2725c977 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -229,6 +229,9 @@ struct zebra_router { #define ZEBRA_DEFAULT_NHG_KEEP_TIMER 180 uint32_t nhg_keep; + + /* Should we allow non FRR processes to delete our routes */ + bool allow_delete; }; #define GRACEFUL_RESTART_TIME 60 diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 6ae55cdba4..e6038d0bc2 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -66,8 +66,6 @@ #include "zebra/rtadv.h" #include "zebra/zebra_neigh.h" -extern int allow_delete; - /* context to manage dumps in multiple tables or vrfs */ struct route_show_ctx { bool multi; /* dump multiple tables or vrf */ @@ -2699,7 +2697,7 @@ DEFUN (allow_external_route_update, "allow-external-route-update", "Allow FRR routes to be overwritten by external processes\n") { - allow_delete = 1; + zrouter.allow_delete = true; return CMD_SUCCESS; } @@ -2710,7 +2708,7 @@ DEFUN (no_allow_external_route_update, NO_STR "Allow FRR routes to be overwritten by external processes\n") { - allow_delete = 0; + zrouter.allow_delete = false; return CMD_SUCCESS; } @@ -3911,7 +3909,7 @@ DEFPY (zebra_nexthop_group_keep, static int config_write_protocol(struct vty *vty) { - if (allow_delete) + if (zrouter.allow_delete) vty_out(vty, "allow-external-route-update\n"); if (zrouter.nhg_keep != ZEBRA_DEFAULT_NHG_KEEP_TIMER) @@ -4011,6 +4009,8 @@ DEFUN (show_zebra, ttable_add_row(table, "Kernel NHG|%s", zrouter.supports_nhgs ? "Available" : "Unavailable"); + ttable_add_row(table, "Allow Non FRR route deletion|%s", + zrouter.allow_delete ? "Yes" : "No"); ttable_add_row(table, "v4 All LinkDown Routes|%s", zrouter.all_linkdownv4 ? "On" : "Off"); ttable_add_row(table, "v4 Default LinkDown Routes|%s", |
