diff --git a/.gitignore b/.gitignore index f7c731b4bc..c5fd0ced9b 100644 --- a/.gitignore +++ b/.gitignore @@ -82,3 +82,6 @@ GPATH *.lo compile_commands.json .dirstamp + +# clippy generated source +*_clippy.c diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in new file mode 100644 index 0000000000..33c2859245 --- /dev/null +++ b/alpine/APKBUILD.in @@ -0,0 +1,36 @@ +# Maintainer: Arthur Jones +pkgname=frr +pkgver=@VERSION@ +pkgrel=0 +pkgdesc="Free Range Routing is a fork of quagga" +url="https://frrouting.org/" +arch="all" +license="GPL-2.0" +depends="iproute2 json-c c-ares ipsec-tools iproute2" +makedepends="ncurses-dev net-snmp-dev gawk texinfo perl + acct autoconf automake bash + binutils binutils-libs bison bsd-compat-headers build-base + c-ares c-ares-dev ca-certificates cryptsetup-libs curl + device-mapper-libs expat fakeroot flex fortify-headers gdbm + git gmp isl json-c-dev kmod lddtree libacl libatomic libattr + libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc + libgomp libisoburn libisofs libltdl libressl libssh2 + libstdc++ libtool libuuid linux-headers lzip lzo m4 make mkinitfs mpc1 + mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base + patch pax-utils pcre perl pkgconf python2 python2-dev readline + readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs" +subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg" +source="$pkgname-$pkgver.tar.gz" + +builddir="$srcdir"/$pkgname-$pkgver + +build() { + cd "$builddir" + ./configure --prefix=/usr || return 1 + make || return 1 +} + +package() { + cd "$builddir" + make DESTDIR="$pkgdir" install || return 1 +} diff --git a/bgpd/.gitignore b/bgpd/.gitignore index a97bdb83d3..105be22995 100644 --- a/bgpd/.gitignore +++ b/bgpd/.gitignore @@ -16,4 +16,3 @@ TAGS .arch-ids *~ *.loT -*clippy.c diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 7f69aed5cf..94d9cb465b 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -474,6 +474,17 @@ static void derive_rd_rt_for_vni(struct bgp *bgp, struct bgpevpn *vpn) bgp_evpn_derive_auto_rt_export(bgp, vpn); } +/* + * Convert nexthop (remote VTEP IP) into an IPv6 address. + */ +static void evpn_convert_nexthop_to_ipv6(struct attr *attr) +{ + if (BGP_ATTR_NEXTHOP_AFI_IP6(attr)) + return; + ipv4_to_ipv4_mapped_ipv6(&attr->mp_nexthop_global, attr->nexthop); + attr->mp_nexthop_len = IPV6_MAX_BYTELEN; +} + /* * Add (update) or delete MACIP from zebra. */ @@ -622,17 +633,17 @@ static void build_evpn_type5_route_extcomm(struct bgp *bgp_vrf, } /* - * Build extended communities for EVPN route. RT and ENCAP are - * applicable to all routes. - * TODO: currently kernel doesnt support ipv6 routes with ipv4 nexthops. - * This means that we can't do symmetric routing for ipv6 hosts routes - * in the same way as ipv4 host routes. - * We wont attach l3-vni related RTs for ipv6 routes. - * For now, We will only adevrtise ipv4 host routes - * with L3-VNI related ext-comm. + * Build extended communities for EVPN route. + * This function is applicable for type-2 and type-3 routes. The layer-2 RT + * and ENCAP extended communities are applicable for all routes. + * The default gateway extended community and MAC mobility (sticky) extended + * community are added as needed based on passed settings - only for type-2 + * routes. Likewise, the layer-3 RT and Router MAC extended communities are + * added, if present, based on passed settings - only for non-link-local + * type-2 routes. */ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, - afi_t afi) + int add_l3_ecomm) { struct ecommunity ecom_encap; struct ecommunity ecom_sticky; @@ -662,11 +673,10 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom)) attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom); - /* - * only attach l3-vni export rts for ipv4 address family and if we are - * advertising both the labels in type-2 routes + /* Add the export RTs for L3VNI if told to - caller determines + * when this should be done. */ - if (afi == AFI_IP && CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) { + if (add_l3_ecomm) { vrf_export_rtl = bgpevpn_get_vrf_export_rtl(vpn); if (vrf_export_rtl && !list_isempty(vrf_export_rtl)) { for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode, @@ -676,6 +686,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, } } + /* Add MAC mobility (sticky) if needed. */ if (attr->sticky) { seqnum = 0; memset(&ecom_sticky, 0, sizeof(ecom_sticky)); @@ -686,12 +697,8 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, ecommunity_merge(attr->ecommunity, &ecom_sticky); } - /* - * only attach l3-vni rmac for ipv4 address family and if we are - * advertising both the labels in type-2 routes - */ - if (afi == AFI_IP && !is_zero_mac(&attr->rmac) - && CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) { + /* Add RMAC, if told to. */ + if (add_l3_ecomm) { memset(&ecom_rmac, 0, sizeof(ecom_rmac)); encode_rmac_extcomm(&eval_rmac, &attr->rmac); ecom_rmac.size = 1; @@ -700,6 +707,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, ecommunity_merge(attr->ecommunity, &ecom_rmac); } + /* Add default gateway, if needed. */ if (attr->default_gw) { memset(&ecom_default_gw, 0, sizeof(ecom_default_gw)); encode_default_gw_extcomm(&eval_default_gw); @@ -1260,6 +1268,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, struct bgp_node *rn; struct attr attr; struct attr *attr_new; + int add_l3_ecomm = 0; struct bgp_info *ri; afi_t afi = AFI_L2VPN; safi_t safi = SAFI_EVPN; @@ -1279,14 +1288,23 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL); - /* router mac is only needed for type-2 and type-5 routes */ + /* router mac is only needed for type-2 routes here. */ if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) bgpevpn_get_rmac(vpn, &attr.rmac); vni2label(vpn->vni, &(attr.label)); - /* Set up RT and ENCAP extended community. */ - build_evpn_route_extcomm( - vpn, &attr, IS_EVPN_PREFIX_IPADDR_V4(p) ? AFI_IP : AFI_IP6); + /* Include L3 VNI related RTs and RMAC for type-2 routes, if they're + * IPv4 or IPv6 global addresses and we're advertising L3VNI with + * these routes. + */ + if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && + (IS_EVPN_PREFIX_IPADDR_V4(p) || + !IN6_IS_ADDR_LINKLOCAL(&p->prefix.ip.ipaddr_v6)) && + CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) + add_l3_ecomm = 1; + + /* Set up extended community. */ + build_evpn_route_extcomm(vpn, &attr, add_l3_ecomm); /* First, create (or fetch) route node within the VNI. */ /* NOTE: There is no RD here. */ @@ -1466,22 +1484,20 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) struct attr attr; struct attr attr_sticky; struct attr attr_def_gw; - struct attr attr_ip6; - struct attr attr_sticky_ip6; - struct attr attr_def_gw_ip6; + struct attr attr_ip6_ll; struct attr *attr_new; + int add_l3_ecomm = 0; afi = AFI_L2VPN; safi = SAFI_EVPN; memset(&attr, 0, sizeof(struct attr)); memset(&attr_sticky, 0, sizeof(struct attr)); memset(&attr_def_gw, 0, sizeof(struct attr)); - memset(&attr_ip6, 0, sizeof(struct attr)); - memset(&attr_sticky_ip6, 0, sizeof(struct attr)); - memset(&attr_def_gw_ip6, 0, sizeof(struct attr)); + memset(&attr_ip6_ll, 0, sizeof(struct attr)); - /* Build path-attribute - all type-2 routes for this VNI will share the - * same path attribute. + /* Build path-attribute - multiple type-2 routes for this VNI will share + * the same path attribute, but we need separate structures for sticky + * MACs, default gateway and IPv6 link-local addresses (no L3 RT/RMAC). */ bgp_attr_default_set(&attr, BGP_ORIGIN_IGP); bgp_attr_default_set(&attr_sticky, BGP_ORIGIN_IGP); @@ -1500,31 +1516,21 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) attr_def_gw.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; attr_def_gw.default_gw = 1; bgpevpn_get_rmac(vpn, &attr_def_gw.rmac); - bgp_attr_default_set(&attr_ip6, BGP_ORIGIN_IGP); - bgp_attr_default_set(&attr_sticky_ip6, BGP_ORIGIN_IGP); - bgp_attr_default_set(&attr_def_gw_ip6, BGP_ORIGIN_IGP); - attr_ip6.nexthop = vpn->originator_ip; - attr_ip6.mp_nexthop_global_in = vpn->originator_ip; - attr_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - bgpevpn_get_rmac(vpn, &attr_ip6.rmac); - attr_sticky_ip6.nexthop = vpn->originator_ip; - attr_sticky_ip6.mp_nexthop_global_in = vpn->originator_ip; - attr_sticky_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr_sticky_ip6.sticky = 1; - bgpevpn_get_rmac(vpn, &attr_sticky_ip6.rmac); - attr_def_gw_ip6.nexthop = vpn->originator_ip; - attr_def_gw_ip6.mp_nexthop_global_in = vpn->originator_ip; - attr_def_gw_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr_def_gw_ip6.default_gw = 1; - bgpevpn_get_rmac(vpn, &attr_def_gw_ip6.rmac); + bgp_attr_default_set(&attr_ip6_ll, BGP_ORIGIN_IGP); + attr_ip6_ll.nexthop = vpn->originator_ip; + attr_ip6_ll.mp_nexthop_global_in = vpn->originator_ip; + attr_ip6_ll.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - /* Set up RT, ENCAP and sticky MAC extended community. */ - build_evpn_route_extcomm(vpn, &attr, AFI_IP); - build_evpn_route_extcomm(vpn, &attr_sticky, AFI_IP); - build_evpn_route_extcomm(vpn, &attr_def_gw, AFI_IP); - build_evpn_route_extcomm(vpn, &attr_ip6, AFI_IP6); - build_evpn_route_extcomm(vpn, &attr_sticky_ip6, AFI_IP6); - build_evpn_route_extcomm(vpn, &attr_def_gw_ip6, AFI_IP); + /* Add L3 VNI RTs and RMAC for non IPv6 link-local attributes if + * using L3 VNI for type-2 routes also. + */ + if (CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) + add_l3_ecomm = 1; + + build_evpn_route_extcomm(vpn, &attr, add_l3_ecomm); + build_evpn_route_extcomm(vpn, &attr_sticky, add_l3_ecomm); + build_evpn_route_extcomm(vpn, &attr_def_gw, add_l3_ecomm); + build_evpn_route_extcomm(vpn, &attr_ip6_ll, 0); /* Walk this VNI's route table and update local type-2 routes. For any * routes updated, update corresponding entry in the global table too. @@ -1538,7 +1544,11 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) continue; - if (IS_EVPN_PREFIX_IPADDR_V4(evp)) { + if (IS_EVPN_PREFIX_IPADDR_V6(evp) && + IN6_IS_ADDR_LINKLOCAL(&evp->prefix.ip.ipaddr_v6)) + update_evpn_route_entry(bgp, vpn, afi, safi, rn, + &attr_ip6_ll, 0, 1, &ri, 0); + else { if (evpn_route_is_sticky(bgp, rn)) update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr_sticky, 0, 1, &ri, @@ -1550,19 +1560,6 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) else update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr, 0, 1, &ri, 0); - } else { - if (evpn_route_is_sticky(bgp, rn)) - update_evpn_route_entry(bgp, vpn, afi, safi, rn, - &attr_sticky_ip6, 0, 1, - &ri, 0); - else if (evpn_route_is_def_gw(bgp, rn)) - update_evpn_route_entry(bgp, vpn, afi, safi, rn, - &attr_def_gw_ip6, 0, 1, - &ri, 0); - else - update_evpn_route_entry(bgp, vpn, afi, safi, rn, - &attr_ip6, 0, 1, &ri, - 0); } /* If a local route exists for this prefix, we need to update @@ -1593,11 +1590,9 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) /* Unintern temporary. */ aspath_unintern(&attr.aspath); - aspath_unintern(&attr_ip6.aspath); aspath_unintern(&attr_sticky.aspath); - aspath_unintern(&attr_sticky_ip6.aspath); aspath_unintern(&attr_def_gw.aspath); - aspath_unintern(&attr_def_gw_ip6.aspath); + aspath_unintern(&attr_ip6_ll.aspath); return 0; } @@ -1791,6 +1786,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, { struct bgp_node *rn; struct bgp_info *ri; + struct attr attr; struct attr *attr_new; int ret = 0; struct prefix p; @@ -1827,6 +1823,15 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, } else return 0; + /* EVPN routes currently only support a IPv4 next hop which corresponds + * to the remote VTEP. When importing into a VRF, if it is IPv6 host + * route, we have to convert the next hop to an IPv4-mapped address + * for the rest of the code to flow through. + */ + bgp_attr_dup(&attr, parent_ri->attr); + if (afi == AFI_IP6) + evpn_convert_nexthop_to_ipv6(&attr); + /* Check if route entry is already present. */ for (ri = rn->info; ri; ri = ri->next) if (ri->extra @@ -1835,7 +1840,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, if (!ri) { /* Add (or update) attribute to hash. */ - attr_new = bgp_attr_intern(parent_ri->attr); + attr_new = bgp_attr_intern(&attr); /* Create new route with its attribute. */ ri = info_make(parent_ri->type, parent_ri->sub_type, 0, @@ -1850,21 +1855,25 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, } bgp_info_add(rn, ri); } else { - if (attrhash_cmp(ri->attr, parent_ri->attr) + if (attrhash_cmp(ri->attr, &attr) && !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { bgp_unlock_node(rn); return 0; } /* The attribute has changed. */ /* Add (or update) attribute to hash. */ - attr_new = bgp_attr_intern(parent_ri->attr); + attr_new = bgp_attr_intern(&attr); /* Restore route, if needed. */ if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) bgp_info_restore(rn, ri); /* Mark if nexthop has changed. */ - if (!IPV4_ADDR_SAME(&ri->attr->nexthop, &attr_new->nexthop)) + if ((afi == AFI_IP && + !IPV4_ADDR_SAME(&ri->attr->nexthop, &attr_new->nexthop)) || + (afi == AFI_IP6 && + !IPV6_ADDR_SAME(&ri->attr->mp_nexthop_global, + &attr_new->mp_nexthop_global))) SET_FLAG(ri->flags, BGP_INFO_IGP_CHANGED); /* Unintern existing, set to new. */ @@ -2577,10 +2586,12 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi, static void delete_withdraw_vrf_routes(struct bgp *bgp_vrf) { /* delete all ipv4 routes and withdraw from peers */ - bgp_evpn_withdraw_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST); + if (advertise_type5_routes(bgp_vrf, AFI_IP)) + bgp_evpn_withdraw_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST); /* delete all ipv6 routes and withdraw from peers */ - bgp_evpn_withdraw_type5_routes(bgp_vrf, AFI_IP6, SAFI_UNICAST); + if (advertise_type5_routes(bgp_vrf, AFI_IP6)) + bgp_evpn_withdraw_type5_routes(bgp_vrf, AFI_IP6, SAFI_UNICAST); } /* update and advertise all ipv4 and ipv6 routes in thr vrf table as type-5 @@ -2588,10 +2599,12 @@ static void delete_withdraw_vrf_routes(struct bgp *bgp_vrf) static void update_advertise_vrf_routes(struct bgp *bgp_vrf) { /* update all ipv4 routes */ - bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST); + if (advertise_type5_routes(bgp_vrf, AFI_IP)) + bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST); /* update all ipv6 routes */ - bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP6, SAFI_UNICAST); + if (advertise_type5_routes(bgp_vrf, AFI_IP6)) + bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP6, SAFI_UNICAST); } /* @@ -3227,10 +3240,6 @@ void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct prefix *p, struct prefix_evpn evp; char buf[PREFIX_STRLEN]; - /* NOTE: Check needed as this is called per-route also. */ - if (!advertise_type5_routes(bgp_vrf, afi)) - return; - build_type5_prefix_from_ip_prefix(&evp, p); ret = delete_evpn_type5_route(bgp_vrf, &evp); if (ret) { @@ -3248,10 +3257,6 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi) struct bgp_node *rn = NULL; struct bgp_info *ri; - /* Bail out early if we don't have to advertise type-5 routes. */ - if (!advertise_type5_routes(bgp_vrf, afi)) - return; - table = bgp_vrf->rib[afi][safi]; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { /* Only care about "selected" routes - non-imported. */ @@ -3280,11 +3285,7 @@ void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p, int ret = 0; struct prefix_evpn evp; char buf[PREFIX_STRLEN]; - - /* NOTE: Check needed as this is called per-route also. */ - if (!advertise_type5_routes(bgp_vrf, afi)) - return; - + build_type5_prefix_from_ip_prefix(&evp, p); ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr); if (ret) @@ -3303,10 +3304,6 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi, struct bgp_node *rn = NULL; struct bgp_info *ri; - /* Bail out early if we don't have to advertise type-5 routes. */ - if (!advertise_type5_routes(bgp_vrf, afi)) - return; - table = bgp_vrf->rib[afi][safi]; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { /* Need to identify the "selected" route entry to use its diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index bf6150e648..7c0d638327 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -55,6 +55,25 @@ static inline vni_t label2vni(mpls_label_t *label) return vni; } +static inline int advertise_type5_routes(struct bgp *bgp_vrf, + afi_t afi) +{ + if (!bgp_vrf->l3vni) + return 0; + + if (afi == AFI_IP && + CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST)) + return 1; + + if (afi == AFI_IP6 && + CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST)) + return 1; + + return 0; +} + extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p, struct attr *src_attr, afi_t afi, diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 63dd581845..ce279005dc 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -285,6 +285,14 @@ static inline void ip_prefix_from_type5_prefix(struct prefix_evpn *evp, } } +static inline int is_evpn_prefix_default(struct prefix *evp) +{ + if (evp->family != AF_EVPN) + return 0; + + return ((evp->u.prefix_evpn.ip_prefix_length == 0) ? 1 : 0); +} + static inline void ip_prefix_from_type2_prefix(struct prefix_evpn *evp, struct prefix *ip) { @@ -352,19 +360,17 @@ static inline void build_evpn_type3_prefix(struct prefix_evpn *p, p->prefix.ip.ipaddr_v4 = originator_ip; } -static inline int advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi) +static inline int evpn_default_originate_set(struct bgp *bgp, afi_t afi, + safi_t safi) { - if (!bgp_vrf->l3vni) - return 0; - - if (afi == AFI_IP - && CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_ADVERTISE_IPV4_IN_EVPN)) + if (afi == AFI_IP && + CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4)) return 1; - - if (afi == AFI_IP6 - && CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_ADVERTISE_IPV6_IN_EVPN)) + else if (afi == AFI_IP6 && + CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6)) return 1; - return 0; } diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index d42da23f52..58487a682c 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -2419,7 +2419,50 @@ static void evpn_unset_advertise_default_gw(struct bgp *bgp, /* * evpn - enable advertisement of default g/w */ -static void evpn_set_advertise_subnet(struct bgp *bgp, struct bgpevpn *vpn) +static void evpn_process_default_originate_cmd(struct bgp *bgp_vrf, + afi_t afi, int add) +{ + struct prefix ip_prefix; + safi_t safi = SAFI_UNICAST; /* ipv4/ipv6 unicast */ + + /* form the default prefix 0.0.0.0/0 */ + memset(&ip_prefix, 0, sizeof(struct prefix)); + ip_prefix.family = afi2family(afi); + ip_prefix.prefixlen = 0; + + if (add) { + /* bail if we are already advertising default route */ + if (evpn_default_originate_set(bgp_vrf, afi, safi)) + return; + + if (afi == AFI_IP) + SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4); + else if (afi == AFI_IP6) + SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6); + bgp_evpn_advertise_type5_route(bgp_vrf, &ip_prefix, + NULL, afi, safi); + } else { + /* bail out if we havent advertised the default route */ + if (!evpn_default_originate_set(bgp_vrf, afi, safi)) + return; + if (afi == AFI_IP) + UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4); + else if (afi == AFI_IP6) + UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6); + bgp_evpn_withdraw_type5_route(bgp_vrf, &ip_prefix, + afi, safi); + } +} + +/* + * evpn - enable advertisement of default g/w + */ +static void evpn_set_advertise_subnet(struct bgp *bgp, + struct bgpevpn *vpn) { if (vpn->advertise_subnet) return; @@ -2612,6 +2655,43 @@ DEFUN (no_bgp_evpn_advertise_all_vni, return CMD_SUCCESS; } +DEFUN (bgp_evpn_default_originate, + bgp_evpn_default_originate_cmd, + "default-originate ", + "originate a default route\n" + "ipv4 address family\n" + "ipv6 address family\n") +{ + afi_t afi = 0; + int idx_afi = 0; + struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp); + + if (!bgp_vrf) + return CMD_WARNING; + argv_find_and_parse_afi(argv, argc, &idx_afi, &afi); + evpn_process_default_originate_cmd(bgp_vrf, afi, 1); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_evpn_default_originate, + no_bgp_evpn_default_originate_cmd, + "no default-originate ", + NO_STR + "withdraw a default route\n" + "ipv4 address family\n" + "ipv6 address family\n") +{ + afi_t afi = 0; + int idx_afi = 0; + struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp); + + if (!bgp_vrf) + return CMD_WARNING; + argv_find_and_parse_afi(argv, argc, &idx_afi, &afi); + evpn_process_default_originate_cmd(bgp_vrf, afi, 0); + return CMD_SUCCESS; +} + DEFUN (bgp_evpn_advertise_vni_subnet, bgp_evpn_advertise_vni_subnet_cmd, "advertise-subnet", @@ -2631,14 +2711,6 @@ DEFUN (bgp_evpn_advertise_vni_subnet, if (!bgp_vrf) return CMD_WARNING; - if (!(advertise_type5_routes(bgp_vrf, AFI_IP) - || advertise_type5_routes(bgp_vrf, AFI_IP6))) { - vty_out(vty, - "%%Please enable ip prefix advertisement under l2vpn evpn in %s", - vrf_id_to_name(bgp_vrf->vrf_id)); - return CMD_WARNING; - } - evpn_set_advertise_subnet(bgp, vpn); return CMD_SUCCESS; } @@ -2711,19 +2783,23 @@ DEFUN (bgp_evpn_advertise_type5, /* if we are already advertising ipv4 prefix as type-5 * nothing to do */ - if (!rmap_changed && CHECK_FLAG(bgp_vrf->vrf_flags, - BGP_VRF_ADVERTISE_IPV4_IN_EVPN)) + if (!rmap_changed && + CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST)) return CMD_WARNING; - SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_ADVERTISE_IPV4_IN_EVPN); + SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST); } else { /* if we are already advertising ipv6 prefix as type-5 * nothing to do */ - if (!rmap_changed && CHECK_FLAG(bgp_vrf->vrf_flags, - BGP_VRF_ADVERTISE_IPV6_IN_EVPN)) + if (!rmap_changed && + CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST)) return CMD_WARNING; - SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_ADVERTISE_IPV6_IN_EVPN); + SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST); } if (rmap_changed) { @@ -2766,7 +2842,7 @@ DEFUN (no_bgp_evpn_advertise_type5, argv_find_and_parse_afi(argv, argc, &idx_afi, &afi); argv_find_and_parse_safi(argv, argc, &idx_safi, &safi); - if (!(afi == AFI_IP) || (afi == AFI_IP6)) { + if (!(afi == AFI_IP || afi == AFI_IP6)) { vty_out(vty, "%%only ipv4 or ipv6 address families are supported"); return CMD_WARNING; @@ -2780,25 +2856,25 @@ DEFUN (no_bgp_evpn_advertise_type5, if (afi == AFI_IP) { - /* if we are already advertising ipv4 prefix as type-5 + /* if we are not advertising ipv4 prefix as type-5 * nothing to do */ - if (CHECK_FLAG(bgp_vrf->vrf_flags, - BGP_VRF_ADVERTISE_IPV4_IN_EVPN)) { + if (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST)) { bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi); - UNSET_FLAG(bgp_vrf->vrf_flags, - BGP_VRF_ADVERTISE_IPV4_IN_EVPN); + UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST); } } else { - /* if we are already advertising ipv6 prefix as type-5 + /* if we are not advertising ipv6 prefix as type-5 * nothing to do */ - if (CHECK_FLAG(bgp_vrf->vrf_flags, - BGP_VRF_ADVERTISE_IPV6_IN_EVPN)) { + if (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST)) { bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi); UNSET_FLAG(bgp_vrf->vrf_flags, - BGP_VRF_ADVERTISE_IPV6_IN_EVPN); + BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST); } } @@ -4305,12 +4381,22 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi, if (bgp->advertise_gw_macip) vty_out(vty, " advertise-default-gw\n"); - if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_ADVERTISE_IPV4_IN_EVPN)) + if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST)) vty_out(vty, " advertise ipv4 unicast\n"); - if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_ADVERTISE_IPV6_IN_EVPN)) + if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST)) vty_out(vty, " advertise ipv6 unicast\n"); + if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4)) + vty_out(vty, " default-originate ipv4\n"); + + if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6)) + vty_out(vty, " default-originate ipv6\n"); + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD)) vty_out(vty, " rd %s\n", prefix_rd2str(&bgp->vrf_prd, buf1, sizeof(buf1))); @@ -4373,6 +4459,8 @@ void bgp_ethernetvpn_init(void) install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_default_gw_cmd); install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_type5_cmd); install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_type5_cmd); + install_element(BGP_EVPN_NODE, &bgp_evpn_default_originate_cmd); + install_element(BGP_EVPN_NODE, &no_bgp_evpn_default_originate_cmd); /* "show bgp l2vpn evpn" commands. */ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index c27af7ed68..88e93f5710 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2227,12 +2227,13 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, /* advertise/withdraw type-5 routes */ if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { - if (new_select - && (!new_select->extra || !new_select->extra->parent)) - bgp_evpn_advertise_type5_route( - bgp, &rn->p, new_select->attr, afi, safi); - else if (old_select - && (!old_select->extra || !old_select->extra->parent)) + if (advertise_type5_routes(bgp, afi) && new_select && + (!new_select->extra || !new_select->extra->parent)) + bgp_evpn_advertise_type5_route(bgp, &rn->p, + new_select->attr, + afi, safi); + else if (advertise_type5_routes(bgp, afi) && old_select && + (!old_select->extra || !old_select->extra->parent)) bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi); } diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 5371b37239..b6910a222d 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -594,6 +594,24 @@ struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd = { route_match_ip_route_source_prefix_list_compile, route_match_ip_route_source_prefix_list_free}; +/* `match evpn default-route' */ + +/* Match function should return 1 if match is success else 0 */ +static route_map_result_t route_match_evpn_default_route(void *rule, + struct prefix *p, + route_map_object_t + type, void *object) +{ + if (type == RMAP_BGP && is_evpn_prefix_default(p)) + return RMAP_MATCH; + + return RMAP_NOMATCH; +} + +/* Route map commands for default-route matching. */ +struct route_map_rule_cmd route_match_evpn_default_route_cmd = { + "evpn default-route", route_match_evpn_default_route, NULL, NULL}; + /* `match mac address MAC_ACCESS_LIST' */ /* Match function should return 1 if match is success else return @@ -3249,6 +3267,29 @@ DEFUN (no_match_evpn_vni, RMAP_EVENT_MATCH_DELETED); } +DEFUN (match_evpn_default_route, + match_evpn_default_route_cmd, + "match evpn default-route", + MATCH_STR + EVPN_HELP_STR + "default EVPN type-5 route\n") +{ + return bgp_route_match_add(vty, "evpn default-route", NULL, + RMAP_EVENT_MATCH_ADDED); +} + +DEFUN (no_match_evpn_default_route, + no_match_evpn_default_route_cmd, + "no match evpn default-route", + NO_STR + MATCH_STR + EVPN_HELP_STR + "default EVPN type-5 route\n") +{ + return bgp_route_match_delete(vty, "evpn default-route", NULL, + RMAP_EVENT_MATCH_DELETED); +} + DEFUN (match_peer, match_peer_cmd, "match peer ", @@ -4628,6 +4669,7 @@ void bgp_route_map_init(void) route_map_install_match(&route_match_mac_address_cmd); route_map_install_match(&route_match_evpn_vni_cmd); route_map_install_match(&route_match_evpn_route_type_cmd); + route_map_install_match(&route_match_evpn_default_route_cmd); route_map_install_set(&route_set_ip_nexthop_cmd); route_map_install_set(&route_set_local_pref_cmd); @@ -4664,6 +4706,8 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &no_match_evpn_vni_cmd); install_element(RMAP_NODE, &match_evpn_route_type_cmd); install_element(RMAP_NODE, &no_match_evpn_route_type_cmd); + install_element(RMAP_NODE, &match_evpn_default_route_cmd); + install_element(RMAP_NODE, &no_match_evpn_default_route_cmd); install_element(RMAP_NODE, &match_aspath_cmd); install_element(RMAP_NODE, &no_match_aspath_cmd); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index e265da803f..9e1d279091 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -312,6 +312,13 @@ struct bgp { u_int16_t af_flags[AFI_MAX][SAFI_MAX]; #define BGP_CONFIG_DAMPENING (1 << 0) +/* l2vpn evpn flags - 1 << 0 is used for DAMPENNG */ +#define BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST (1 << 1) +#define BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST (1 << 2) +#define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4 (1 << 3) +#define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6 (1 << 4) + + /* Route table for next-hop lookup cache. */ struct bgp_table *nexthop_cache_table[AFI_MAX]; @@ -423,12 +430,11 @@ struct bgp { /* vrf flags */ uint32_t vrf_flags; #define BGP_VRF_AUTO (1 << 0) -#define BGP_VRF_ADVERTISE_IPV4_IN_EVPN (1 << 1) -#define BGP_VRF_ADVERTISE_IPV6_IN_EVPN (1 << 2) -#define BGP_VRF_IMPORT_RT_CFGD (1 << 3) -#define BGP_VRF_EXPORT_RT_CFGD (1 << 4) -#define BGP_VRF_RD_CFGD (1 << 5) -#define BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY (1 << 6) +#define BGP_VRF_IMPORT_RT_CFGD (1 << 1) +#define BGP_VRF_EXPORT_RT_CFGD (1 << 2) +#define BGP_VRF_RD_CFGD (1 << 3) +#define BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY (1 << 4) + /* unique ID for auto derivation of RD for this vrf */ uint16_t vrf_rd_id; diff --git a/configure.ac b/configure.ac index 0d6c99acfa..e85d19f687 100755 --- a/configure.ac +++ b/configure.ac @@ -396,6 +396,8 @@ AC_ARG_ENABLE(rpki, AS_HELP_STRING([--enable-rpki], [enable RPKI prefix validation support])) AC_ARG_ENABLE([clippy-only], AS_HELP_STRING([--enable-clippy-only], [Only build clippy])) +AC_ARG_ENABLE([numeric_version], + AS_HELP_STRING([--enable-numeric-version], [Only numeric digits allowed in version (for Alpine)])) AS_IF([test "${enable_clippy_only}" != "yes"], [ AC_CHECK_HEADERS(json-c/json.h) @@ -647,6 +649,14 @@ AC_DEFINE_UNQUOTED(MULTIPATH_NUM, $MPATH_NUM, Maximum number of paths for a rout AC_DEFINE_UNQUOTED(VTYSH_PAGER, "$VTYSH_PAGER", [What pager to use]) +dnl ------------------------------------ +dnl Alpine only accepts numeric versions +dnl ------------------------------------ +if test "x${enable_numeric_version}" != "x" ; then + VERSION="`echo ${VERSION} | tr -c -d '[[.0-9]]'`" + PACKAGE_VERSION="`echo ${PACKAGE_VERSION} | tr -c -d '[[.0-9]]'`" +fi + dnl ----------------------------------- dnl Add extra version string to package dnl name, string and version fields. @@ -1872,6 +1882,7 @@ AC_CONFIG_FILES([Makefile redhat/frr.spec debianpkg/Makefile debianpkg/changelog + alpine/APKBUILD snapcraft/snapcraft.yaml lib/version.h tests/lib/cli/test_cli.refout diff --git a/doc/install.texi b/doc/install.texi index d0d56804b0..e6d4be61dd 100644 --- a/doc/install.texi +++ b/doc/install.texi @@ -109,6 +109,10 @@ of grammar sandbox. Turn on some compile options to allow you to run fuzzing tools against the system. This tools is intended as a developer only tool and should not be used for normal operations +@item --enable-numeric-version +Alpine Linux does not allow non-numeric characters in the version +string. With this option, we provide a way to strip out these +characters for apk dev package builds. @end table You may specify any combination of the above options to the configure diff --git a/ldpd/.gitignore b/ldpd/.gitignore index eee96c636f..a2f4b51698 100644 --- a/ldpd/.gitignore +++ b/ldpd/.gitignore @@ -15,4 +15,3 @@ TAGS .arch-ids *~ *.loT -ldp_vty_cmds_clippy.c diff --git a/lib/.gitignore b/lib/.gitignore index 94f401ebe6..072146dbd5 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -24,4 +24,3 @@ refix grammar_sandbox clippy defun_lex.c -plist_clippy.c diff --git a/lib/debug.h b/lib/debug.h index 3e6772aacf..d0fa27d3fe 100644 --- a/lib/debug.h +++ b/lib/debug.h @@ -104,76 +104,77 @@ struct debug_callbacks { * * MT-Safe */ -#define DEBUG_MODE_CHECK(name, type) \ - CHECK_FLAG_ATOMIC(&(name)->flags, (type)&DEBUG_MODE_ALL) +#define DEBUG_MODE_CHECK(name, mode) \ + CHECK_FLAG_ATOMIC(&(name)->flags, (mode)&DEBUG_MODE_ALL) /* * Check if an option bit is set for a debug. * * MT-Safe */ -#define DEBUG_OPT_CHECK(name, type) \ - CHECK_FLAG_ATOMIC(&(name)->flags, (type)&DEBUG_OPT_ALL) +#define DEBUG_OPT_CHECK(name, opt) \ + CHECK_FLAG_ATOMIC(&(name)->flags, (opt)&DEBUG_OPT_ALL) /* * Check if bits are set for a debug. * * MT-Safe */ -#define DEBUG_FLAGS_CHECK(name, type) CHECK_FLAG_ATOMIC(&(name)->flags, (type)) - -/* - * Check if any mode is on for a debug. - * - * MT-Safe - */ -#define DEBUG(name) DEBUG_MODE_CHECK((name), DEBUG_MODE_ALL) +#define DEBUG_FLAGS_CHECK(name, fl) CHECK_FLAG_ATOMIC(&(name)->flags, (fl)) /* * Set modes on a debug. * * MT-Safe */ -#define DEBUG_MODE_SET(name, type) \ - SET_FLAG_ATOMIC(&(name)->flags, (type)&DEBUG_MODE_ALL) +#define DEBUG_MODE_SET(name, mode, onoff) \ + do { \ + if (onoff) \ + SET_FLAG_ATOMIC(&(name)->flags, \ + (mode)&DEBUG_MODE_ALL); \ + else \ + UNSET_FLAG_ATOMIC(&(name)->flags, \ + (mode)&DEBUG_MODE_ALL); \ + } while (0) -/* - * Unset modes on a debug. - * - * MT-Safe - */ -#define DEBUG_MODE_UNSET(name, type) \ - UNSET_FLAG_ATOMIC(&(name)->flags, (type)&DEBUG_MODE_ALL) +/* Convenience macros for specific set operations. */ +#define DEBUG_MODE_ON(name, mode) DEBUG_MODE_SET(name, mode, true) +#define DEBUG_MODE_OFF(name, mode) DEBUG_MODE_SET(name, mode, false) /* * Set options on a debug. * * MT-Safe */ -#define DEBUG_OPT_SET(name, type) \ - SET_FLAG_ATOMIC(&(name)->flags, (type)&DEBUG_OPT_ALL) +#define DEBUG_OPT_SET(name, opt, onoff) \ + do { \ + if (onoff) \ + SET_FLAG_ATOMIC(&(name)->flags, (opt)&DEBUG_OPT_ALL); \ + else \ + UNSET_FLAG_ATOMIC(&(name)->flags, \ + (opt)&DEBUG_OPT_ALL); \ + } while (0) -/* - * Unset options on a debug. - * - * MT-Safe - */ -#define DEBUG_OPT_UNSET(name, type) \ - UNSET_FLAG_ATOMIC(&(name)->flags, (type)&DEBUG_OPT_ALL) +/* Convenience macros for specific set operations. */ +#define DEBUG_OPT_ON(name, opt) DEBUG_OPT_SET(name, opt, true) +#define DEBUG_OPT_OFF(name, opt) DEBUG_OPT_SET(name, opt, true) /* * Set bits on a debug. * * MT-Safe */ -#define DEBUG_FLAGS_SET(name, type) SET_FLAG_ATOMIC(&(name)->flags, (type)) +#define DEBUG_FLAGS_SET(name, fl, onoff) \ + do { \ + if (onoff) \ + SET_FLAG_ATOMIC(&(name)->flags, (fl)); \ + else \ + UNSET_FLAG_ATOMIC(&(name)->flags, (fl)); \ + } while (0) -/* - * Unset bits on a debug. - * - * MT-Safe - */ -#define DEBUG_FLAGS_UNSET(name, type) UNSET_FLAG_ATOMIC(&(name)->flags, (type)) +/* Convenience macros for specific set operations. */ +#define DEBUG_FLAGS_ON(name, fl) DEBUG_FLAGS_SET(&(name)->flags, (type), true) +#define DEBUG_FLAGS_OFF(name, fl) DEBUG_FLAGS_SET(&(name)->flags, (type), false) /* * Unset all modes and options on a debug. @@ -201,6 +202,23 @@ struct debug_callbacks { #define DEBUG_NODE2MODE(vtynode) \ (((vtynode) == CONFIG_NODE) ? DEBUG_MODE_ALL : DEBUG_MODE_TERM) +/* + * Debug at the given level to the default logging destination. + * + * MT-Safe + */ +#define DEBUG(level, name, fmt, ...) \ + do { \ + if (DEBUG_MODE_CHECK(name, DEBUG_MODE_ALL)) \ + zlog_##level(fmt, ##__VA_ARGS__); \ + } while (0) + +/* Convenience macros for the various levels. */ +#define DEBUGE(name, fmt, ...) DEBUG(err, name, fmt, ##__VA_ARGS__) +#define DEBUGW(name, fmt, ...) DEBUG(warn, name, fmt, ##__VA_ARGS__) +#define DEBUGI(name, fmt, ...) DEBUG(info, name, fmt, ##__VA_ARGS__) +#define DEBUGN(name, fmt, ...) DEBUG(notice, name, fmt, ##__VA_ARGS__) +#define DEBUGD(name, fmt, ...) DEBUG(debug, name, fmt, ##__VA_ARGS__) /* * Optional initializer for debugging. Highly recommended. diff --git a/lib/ipaddr.h b/lib/ipaddr.h index 98c28008dc..44bde45add 100644 --- a/lib/ipaddr.h +++ b/lib/ipaddr.h @@ -85,4 +85,21 @@ static inline char *ipaddr2str(struct ipaddr *ip, char *buf, int size) } return buf; } + +/* + * Convert IPv4 address to IPv4-mapped IPv6 address which is of the + * form ::FFFF: (RFC 4291). This IPv6 address can then + * be used to represent the IPv4 address, wherever only an IPv6 address + * is required. + */ +static inline void ipv4_to_ipv4_mapped_ipv6(struct in6_addr *in6, + struct in_addr in) +{ + u_int32_t addr_type = htonl(0xFFFF); + + memset(in6, 0, sizeof(struct in6_addr)); + memcpy((char *)in6 + 8, &addr_type, sizeof(addr_type)); + memcpy((char *)in6 + 12, &in, sizeof(struct in_addr)); +} + #endif /* __IPADDR_H__ */ diff --git a/lib/log.c b/lib/log.c index 9e33ef9102..74e7be7c7d 100644 --- a/lib/log.c +++ b/lib/log.c @@ -1092,41 +1092,52 @@ void zlog_hexdump(const void *mem, unsigned int len) unsigned long i = 0; unsigned int j = 0; unsigned int columns = 8; - char buf[(len * 4) + ((len / 4) * 20) + 30]; + /* + * 19 bytes for 0xADDRESS: + * 24 bytes for data; 2 chars plus a space per data byte + * 1 byte for space + * 8 bytes for ASCII representation + * 1 byte for a newline + * ===================== + * 53 bytes per 8 bytes of data + * 1 byte for null term + */ + size_t bs = ((len / 8) + 1) * 53 + 1; + char buf[bs]; char *s = buf; + memset(buf, 0, sizeof(buf)); + for (i = 0; i < len + ((len % columns) ? (columns - len % columns) : 0); i++) { /* print offset */ if (i % columns == 0) - s += sprintf(s, "0x%016lx: ", (unsigned long)mem + i); + s += snprintf(s, bs - (s - buf), + "0x%016lx: ", (unsigned long)mem + i); /* print hex data */ if (i < len) - s += sprintf(s, "%02x ", 0xFF & ((const char *)mem)[i]); + s += snprintf(s, bs - (s - buf), "%02x ", + 0xFF & ((const char *)mem)[i]); /* end of block, just aligning for ASCII dump */ else - s += sprintf(s, " "); + s += snprintf(s, bs - (s - buf), " "); /* print ASCII dump */ if (i % columns == (columns - 1)) { for (j = i - (columns - 1); j <= i; j++) { - if (j >= len) /* end of block, not really - printing */ - s += sprintf(s, " "); - - else if (isprint((int)((const char *)mem) - [j])) /* printable char - */ - s += sprintf( - s, "%c", + /* end of block not really printing */ + if (j >= len) + s += snprintf(s, bs - (s - buf), " "); + else if (isprint((int)((const char *)mem)[j])) + s += snprintf( + s, bs - (s - buf), "%c", 0xFF & ((const char *)mem)[j]); - else /* other char */ - s += sprintf(s, "."); + s += snprintf(s, bs - (s - buf), "."); } - s += sprintf(s, "\n"); + s += snprintf(s, bs - (s - buf), "\n"); } } zlog_debug("\n%s", buf); diff --git a/lib/zclient.c b/lib/zclient.c index fa3a5f6691..c720e2519b 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -322,6 +322,18 @@ stream_failure: return 0; } +bool zapi_parse_header(struct stream *zmsg, struct zmsghdr *hdr) +{ + STREAM_GETW(zmsg, hdr->length); + STREAM_GETC(zmsg, hdr->marker); + STREAM_GETC(zmsg, hdr->version); + STREAM_GETL(zmsg, hdr->vrf_id); + STREAM_GETW(zmsg, hdr->command); + return true; +stream_failure: + return false; +} + /* Send simple Zebra message. */ static int zebra_message_send(struct zclient *zclient, int command, vrf_id_t vrf_id) diff --git a/lib/zclient.h b/lib/zclient.h index 1aa94b641c..8033488444 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -237,14 +237,13 @@ struct zclient { */ #define ZAPI_MESSAGE_TABLEID 0x80 +#define ZSERV_VERSION 5 /* Zserv protocol message header */ -struct zserv_header { +struct zmsghdr { uint16_t length; - uint8_t marker; /* corresponds to command field in old zserv - * always set to 255 in new zserv. - */ + /* Always set to 255 in new zserv */ + uint8_t marker; uint8_t version; -#define ZSERV_VERSION 5 vrf_id_t vrf_id; uint16_t command; }; @@ -380,9 +379,11 @@ struct zclient_options { /* Prototypes of zebra client service functions. */ extern struct zclient *zclient_new(struct thread_master *); +/* clang-format off */ #if CONFDATE > 20181101 CPP_NOTICE("zclient_new_notify can take over or zclient_new now"); #endif +/* clang-format on */ extern struct zclient_options zclient_options_default; @@ -449,9 +450,58 @@ extern int zclient_send_message(struct zclient *); /* create header for command, length to be filled in by user later */ extern void zclient_create_header(struct stream *, uint16_t, vrf_id_t); +/* + * Read sizeof(struct zmsghdr) bytes from the provided socket and parse the + * received data into the specified fields. If this is successful, read the + * rest of the packet into the provided stream. + * + * s + * The stream to read into + * + * sock + * The socket to read from + * + * size + * Parsed message size will be placed in the pointed-at integer + * + * marker + * Parsed marker will be placed in the pointed-at byte + * + * version + * Parsed version will be placed in the pointed-at byte + * + * vrf_id + * Parsed VRF ID will be placed in the pointed-at vrf_id_t + * + * cmd + * Parsed command number will be placed in the pointed-at integer + * + * Returns: + * -1 if: + * - insufficient data for header was read + * - a version mismatch was detected + * - a marker mismatch was detected + * - header size field specified more data than could be read + */ extern int zclient_read_header(struct stream *s, int sock, u_int16_t *size, u_char *marker, u_char *version, vrf_id_t *vrf_id, u_int16_t *cmd); +/* + * Parse header from ZAPI message stream into struct zmsghdr. + * This function assumes the stream getp points at the first byte of the header. + * If the function is successful then the stream getp will point to the byte + * immediately after the last byte of the header. + * + * zmsg + * The stream containing the header + * + * hdr + * The header struct to parse into. + * + * Returns: + * true if parsing succeeded, false otherwise + */ +extern bool zapi_parse_header(struct stream *zmsg, struct zmsghdr *hdr); extern void zclient_interface_set_master(struct zclient *client, struct interface *master, @@ -468,10 +518,11 @@ extern struct interface *zebra_interface_vrf_update_read(struct stream *s, extern void zebra_interface_if_set_value(struct stream *, struct interface *); extern void zebra_router_id_update_read(struct stream *s, struct prefix *rid); +/* clang-format off */ #if CONFDATE > 20180823 -CPP_NOTICE( - "zapi_ipv4_route, zapi_ipv6_route, zapi_ipv4_route_ipv6_nexthop as well as the zapi_ipv4 and zapi_ipv6 data structures should be removed now"); +CPP_NOTICE("zapi_ipv4_route, zapi_ipv6_route, zapi_ipv4_route_ipv6_nexthop as well as the zapi_ipv4 and zapi_ipv6 data structures should be removed now"); #endif +/* clang-format on */ extern int zapi_ipv4_route(u_char, struct zclient *, struct prefix_ipv4 *, struct zapi_ipv4 *) __attribute__((deprecated)); diff --git a/ospfd/.gitignore b/ospfd/.gitignore index f0d800efb4..752c875a62 100644 --- a/ospfd/.gitignore +++ b/ospfd/.gitignore @@ -15,4 +15,3 @@ TAGS *~ *.loT *.a -*clippy.c diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 6002794658..803e7bb013 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -604,11 +604,18 @@ static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty, json_object_object_add(json, ifp->name, json_row); + if (igmp->mtrace_only) { + json_object_boolean_true_add( + json_row, "mtraceOnly"); + } } else { vty_out(vty, "%-9s %5s %15s %d %7s %11s %8s\n", ifp->name, - if_is_up(ifp) ? "up" : "down", + if_is_up(ifp) + ? (igmp->mtrace_only ? "mtrc" + : "up") + : "down", inet_ntoa(igmp->ifaddr), pim_ifp->igmp_version, igmp->t_igmp_query_timer ? "local" @@ -758,10 +765,17 @@ static void igmp_show_interfaces_single(struct pim_instance *pim, json_object_object_add(json, ifp->name, json_row); + if (igmp->mtrace_only) { + json_object_boolean_true_add( + json_row, "mtraceOnly"); + } } else { vty_out(vty, "Interface : %s\n", ifp->name); vty_out(vty, "State : %s\n", - if_is_up(ifp) ? "up" : "down"); + if_is_up(ifp) + ? (igmp->mtrace_only ? "mtrace" + : "up") + : "down"); vty_out(vty, "Address : %s\n", inet_ntoa(pim_ifp->primary_address)); vty_out(vty, "Uptime : %s\n", uptime); diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 998f8fc2ca..ff7238ae97 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -574,7 +574,11 @@ void pim_if_addr_add(struct connected *ifc) /* if addr new, add IGMP socket */ if (ifc->address->family == AF_INET) pim_igmp_sock_add(pim_ifp->igmp_socket_list, - ifaddr, ifp); + ifaddr, ifp, false); + } else if (igmp->mtrace_only) { + igmp_sock_delete(igmp); + pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, + ifp, false); } /* Replay Static IGMP groups */ @@ -611,6 +615,20 @@ void pim_if_addr_add(struct connected *ifc) } } } /* igmp */ + else { + struct igmp_sock *igmp; + + /* lookup IGMP socket */ + igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, + ifaddr); + if (ifc->address->family == AF_INET) { + if (igmp) + igmp_sock_delete(igmp); + /* if addr new, add IGMP socket */ + pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, + ifp, true); + } + } /* igmp mtrace only */ if (PIM_IF_TEST_PIM(pim_ifp->options)) { diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index c0a58516d9..5e1aecc3a3 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -281,6 +281,9 @@ static int igmp_recv_query(struct igmp_sock *igmp, int query_version, uint16_t recv_checksum; uint16_t checksum; + if (igmp->mtrace_only) + return 0; + memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); ifp = igmp->interface; @@ -387,6 +390,9 @@ static int igmp_v1_recv_report(struct igmp_sock *igmp, struct in_addr from, on_trace(__PRETTY_FUNCTION__, igmp->interface, from); + if (igmp->mtrace_only) + return 0; + if (igmp_msg_len != IGMP_V12_MSG_SIZE) { zlog_warn( "Recv IGMP report v1 from %s on %s: size=%d other than correct=%d", @@ -510,7 +516,6 @@ int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len) return igmp_mtrace_recv_response(igmp, ip_hdr, ip_hdr->ip_src, from_str, igmp_msg, igmp_msg_len); - break; case PIM_IGMP_MTRACE_QUERY_REQUEST: return igmp_mtrace_recv_qry_req(igmp, ip_hdr, ip_hdr->ip_src, from_str, igmp_msg, @@ -819,7 +824,7 @@ static int igmp_group_hash_equal(const void *arg1, const void *arg2) } static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr, - struct interface *ifp) + struct interface *ifp, int mtrace_only) { struct pim_interface *pim_ifp; struct igmp_sock *igmp; @@ -862,6 +867,13 @@ static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr, pim_ifp->igmp_default_robustness_variable; igmp->sock_creation = pim_time_monotonic_sec(); + if (mtrace_only) { + igmp->mtrace_only = mtrace_only; + return igmp; + } + + igmp->mtrace_only = false; + /* igmp_startup_mode_on() will reset QQI: @@ -919,7 +931,8 @@ static void igmp_read_on(struct igmp_sock *igmp) struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list, struct in_addr ifaddr, - struct interface *ifp) + struct interface *ifp, + bool mtrace_only) { struct pim_interface *pim_ifp; struct igmp_sock *igmp; @@ -934,7 +947,7 @@ struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list, return 0; } - igmp = igmp_sock_new(fd, ifaddr, ifp); + igmp = igmp_sock_new(fd, ifaddr, ifp, mtrace_only); if (!igmp) { zlog_err("%s %s: igmp_sock_new() failure", __FILE__, __PRETTY_FUNCTION__); diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h index 962c50e76a..561a127d0f 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -90,6 +90,8 @@ struct igmp_sock { int querier_robustness_variable; /* QRV */ int startup_query_count; + bool mtrace_only; + struct list *igmp_group_list; /* list of struct igmp_group */ struct hash *igmp_group_hash; }; @@ -99,7 +101,8 @@ struct igmp_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list, struct igmp_sock *igmp_sock_lookup_by_fd(struct list *igmp_sock_list, int fd); struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list, struct in_addr ifaddr, - struct interface *ifp); + struct interface *ifp, + bool mtrace_only); void igmp_sock_delete(struct igmp_sock *igmp); void igmp_sock_free(struct igmp_sock *igmp); void igmp_sock_delete_all(struct interface *ifp); diff --git a/pimd/pim_igmpv2.c b/pimd/pim_igmpv2.c index efa36e618f..dbbe83a965 100644 --- a/pimd/pim_igmpv2.c +++ b/pimd/pim_igmpv2.c @@ -111,6 +111,9 @@ int igmp_v2_recv_report(struct igmp_sock *igmp, struct in_addr from, on_trace(__PRETTY_FUNCTION__, igmp->interface, from); + if (igmp->mtrace_only) + return 0; + if (igmp_msg_len != IGMP_V12_MSG_SIZE) { zlog_warn( "Recv IGMPv2 REPORT from %s on %s: size=%d other than correct=%d", @@ -154,6 +157,9 @@ int igmp_v2_recv_leave(struct igmp_sock *igmp, struct in_addr from, on_trace(__PRETTY_FUNCTION__, igmp->interface, from); + if (igmp->mtrace_only) + return 0; + if (igmp_msg_len != IGMP_V12_MSG_SIZE) { zlog_warn( "Recv IGMPv2 LEAVE from %s on %s: size=%d other than correct=%d", diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index ecde546c06..3360e36b4a 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -1874,6 +1874,9 @@ int igmp_v3_recv_report(struct igmp_sock *igmp, struct in_addr from, int local_ncb = 0; struct pim_interface *pim_ifp; + if (igmp->mtrace_only) + return 0; + pim_ifp = igmp->interface->info; if (igmp_msg_len < IGMP_V3_MSG_MIN_SIZE) { diff --git a/sharpd/.gitignore b/sharpd/.gitignore index c396f3ef94..cc33cfc188 100644 --- a/sharpd/.gitignore +++ b/sharpd/.gitignore @@ -13,6 +13,5 @@ TAGS .arch-ids *~ *.loT -*clippy.c sharpd sharpd.conf diff --git a/tests/Makefile.am b/tests/Makefile.am index f4ab2a126a..0c9a5684da 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -73,6 +73,7 @@ check_PROGRAMS = \ lib/test_timer_correctness \ lib/test_timer_performance \ lib/test_ttable \ + lib/test_zlog \ lib/cli/test_cli \ lib/cli/test_commands \ $(TESTS_BGPD) \ @@ -115,9 +116,9 @@ lib_test_heavy_SOURCES = lib/test_heavy.c helpers/c/main.c lib_test_memory_SOURCES = lib/test_memory.c lib_test_nexthop_iter_SOURCES = lib/test_nexthop_iter.c helpers/c/prng.c lib_test_privs_SOURCES = lib/test_privs.c +lib_test_ringbuf_SOURCES = lib/test_ringbuf.c lib_test_srcdest_table_SOURCES = lib/test_srcdest_table.c \ helpers/c/prng.c -lib_test_ringbuf_SOURCES = lib/test_ringbuf.c lib_test_segv_SOURCES = lib/test_segv.c lib_test_sig_SOURCES = lib/test_sig.c lib_test_stream_SOURCES = lib/test_stream.c @@ -127,6 +128,7 @@ lib_test_timer_correctness_SOURCES = lib/test_timer_correctness.c \ lib_test_timer_performance_SOURCES = lib/test_timer_performance.c \ helpers/c/prng.c lib_test_ttable_SOURCES = lib/test_ttable.c +lib_test_zlog_SOURCES = lib/test_zlog.c lib_test_zmq_SOURCES = lib/test_zmq.c lib_test_zmq_CFLAGS = $(AM_CFLAGS) $(ZEROMQ_CFLAGS) lib_cli_test_cli_SOURCES = lib/cli/test_cli.c lib/cli/common_cli.c @@ -167,6 +169,7 @@ lib_test_table_LDADD = $(ALL_TESTS_LDADD) -lm lib_test_timer_correctness_LDADD = $(ALL_TESTS_LDADD) lib_test_timer_performance_LDADD = $(ALL_TESTS_LDADD) lib_test_ttable_LDADD = $(ALL_TESTS_LDADD) +lib_test_zlog_LDADD = $(ALL_TESTS_LDADD) lib_test_zmq_LDADD = ../lib/libfrrzmq.la $(ALL_TESTS_LDADD) $(ZEROMQ_LIBS) lib_cli_test_cli_LDADD = $(ALL_TESTS_LDADD) lib_cli_test_commands_LDADD = $(ALL_TESTS_LDADD) @@ -207,6 +210,7 @@ EXTRA_DIST = \ lib/test_timer_correctness.py \ lib/test_ttable.py \ lib/test_ttable.refout \ + lib/test_zlog.py \ ospf6d/test_lsdb.py \ ospf6d/test_lsdb.in \ ospf6d/test_lsdb.refout \ diff --git a/tests/lib/test_zlog.c b/tests/lib/test_zlog.c new file mode 100644 index 0000000000..790e65cfe9 --- /dev/null +++ b/tests/lib/test_zlog.c @@ -0,0 +1,61 @@ +/* + * Zlog tests. + * Copyright (C) 2018 Cumulus Networks, Inc. + * Quentin Young + * + * 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 +#include +#include "log.h" + +/* maximum amount of data to hexdump */ +#define MAXDATA 16384 + +/* + * Test hexdump functionality. + * + * At the moment, not crashing is considered success. + */ +static bool test_zlog_hexdump(void) +{ + unsigned int nl = 1; + + do { + long d[nl]; + + for (unsigned int i = 0; i < nl; i++) + d[i] = random(); + zlog_hexdump(d, nl * sizeof(long)); + } while (++nl * sizeof(long) <= MAXDATA); + + return true; +} + +bool (*tests[])(void) = { + test_zlog_hexdump, +}; + +int main(int argc, char **argv) +{ + openzlog("testzlog", "NONE", 0, LOG_CONS | LOG_NDELAY | LOG_PID, + LOG_ERR); + zlog_set_file("test_zlog.log", LOG_DEBUG); + + for (unsigned int i = 0; i < array_size(tests); i++) + if (!tests[i]()) + return 1; + return 0; +} diff --git a/tests/lib/test_zlog.py b/tests/lib/test_zlog.py new file mode 100644 index 0000000000..2ca2585886 --- /dev/null +++ b/tests/lib/test_zlog.py @@ -0,0 +1,4 @@ +import frrtest + +class TestZlog(frrtest.TestMultiOut): + program = './test_zlog' diff --git a/zebra/.gitignore b/zebra/.gitignore index 7a1321e546..4a06756a2d 100644 --- a/zebra/.gitignore +++ b/zebra/.gitignore @@ -13,4 +13,3 @@ TAGS .arch-ids *~ *.loT -zebra_vty_clippy.c diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index bb0a0e052e..a37d74416b 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -30,6 +30,7 @@ */ #define _LINUX_IN6_H +#include #include #include #include @@ -362,7 +363,7 @@ static int get_iflink_speed(struct interface *interface) /* initialize ethtool interface */ memset(&ecmd, 0, sizeof(ecmd)); ecmd.cmd = ETHTOOL_GSET; /* ETHTOOL_GLINK */ - ifdata.ifr_data = (__caddr_t)&ecmd; + ifdata.ifr_data = (caddr_t)&ecmd; /* use ioctl to get IP address of an interface */ if (zserv_privs.change(ZPRIVS_RAISE)) diff --git a/zebra/label_manager.c b/zebra/label_manager.c index 5bf0fce094..b58f0c9ff8 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -50,6 +50,8 @@ DEFINE_MTYPE_STATIC(LBL_MGR, LM_CHUNK, "Label Manager Chunk"); * it will be a proxy to relay messages to external label manager * This zclient thus is to connect to it */ +static struct stream *ibuf; +static struct stream *obuf; static struct zclient *zclient; bool lm_is_external; @@ -69,7 +71,7 @@ static int relay_response_back(struct zserv *zserv) u_int16_t resp_cmd; src = zclient->ibuf; - dst = zserv->obuf; + dst = obuf; stream_reset(src); @@ -87,7 +89,7 @@ static int relay_response_back(struct zserv *zserv) /* send response back */ stream_copy(dst, src); - ret = writen(zserv->sock, dst->data, stream_get_endp(dst)); + ret = writen(zserv->sock, src->data, stream_get_endp(src)); if (ret <= 0) { zlog_err("%s: Error sending Label Manager response back: %s", __func__, strerror(errno)); @@ -116,10 +118,10 @@ static int lm_zclient_read(struct thread *t) static int reply_error(int cmd, struct zserv *zserv, vrf_id_t vrf_id) { + int ret; struct stream *s; - s = zserv->obuf; - stream_reset(s); + s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, cmd, vrf_id); @@ -129,7 +131,10 @@ static int reply_error(int cmd, struct zserv *zserv, vrf_id_t vrf_id) /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); - return writen(zserv->sock, s->data, stream_get_endp(s)); + ret = writen(zserv->sock, s->data, stream_get_endp(s)); + + stream_free(s); + return ret; } /** * Receive a request to get or release a label chunk and forward it to external @@ -161,7 +166,7 @@ int zread_relay_label_manager_request(int cmd, struct zserv *zserv, ret = relay_response_back(zserv); /* Send request to external label manager */ - src = zserv->ibuf; + src = ibuf; dst = zclient->obuf; stream_copy(dst, src); @@ -247,6 +252,9 @@ void label_manager_init(char *lm_zserv_path) lm_is_external = true; lm_zclient_init(lm_zserv_path); } + + ibuf = stream_new(ZEBRA_MAX_PACKET_SIZ); + obuf = stream_new(ZEBRA_MAX_PACKET_SIZ); } /** @@ -379,4 +387,6 @@ int release_daemon_chunks(u_char proto, u_short instance) void label_manager_close() { list_delete_and_null(&lbl_mgr.lc_list); + stream_free(ibuf); + stream_free(obuf); } diff --git a/zebra/redistribute.c b/zebra/redistribute.c index a7b2361ac6..5a239306fb 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -243,16 +243,15 @@ void redistribute_delete(struct prefix *p, struct prefix *src_p, } } -void zebra_redistribute_add(int command, struct zserv *client, int length, - struct zebra_vrf *zvrf) +void zebra_redistribute_add(ZAPI_HANDLER_ARGS) { afi_t afi = 0; int type = 0; u_short instance; - STREAM_GETC(client->ibuf, afi); - STREAM_GETC(client->ibuf, type); - STREAM_GETW(client->ibuf, instance); + STREAM_GETC(msg, afi); + STREAM_GETC(msg, type); + STREAM_GETW(msg, instance); if (afi == 0 || afi > AFI_MAX) { zlog_warn("%s: Specified afi %d does not exist", @@ -287,16 +286,15 @@ stream_failure: return; } -void zebra_redistribute_delete(int command, struct zserv *client, int length, - struct zebra_vrf *zvrf) +void zebra_redistribute_delete(ZAPI_HANDLER_ARGS) { afi_t afi = 0; int type = 0; u_short instance; - STREAM_GETC(client->ibuf, afi); - STREAM_GETC(client->ibuf, type); - STREAM_GETW(client->ibuf, instance); + STREAM_GETC(msg, afi); + STREAM_GETC(msg, type); + STREAM_GETW(msg, instance); if (afi == 0 || afi > AFI_MAX) { zlog_warn("%s: Specified afi %d does not exist", @@ -325,15 +323,13 @@ stream_failure: return; } -void zebra_redistribute_default_add(int command, struct zserv *client, - int length, struct zebra_vrf *zvrf) +void zebra_redistribute_default_add(ZAPI_HANDLER_ARGS) { vrf_bitmap_set(client->redist_default, zvrf_id(zvrf)); zebra_redistribute_default(client, zvrf_id(zvrf)); } -void zebra_redistribute_default_delete(int command, struct zserv *client, - int length, struct zebra_vrf *zvrf) +void zebra_redistribute_default_delete(ZAPI_HANDLER_ARGS) { vrf_bitmap_unset(client->redist_default, zvrf_id(zvrf)); } diff --git a/zebra/redistribute.h b/zebra/redistribute.h index 5edb06c3da..e551f820cc 100644 --- a/zebra/redistribute.h +++ b/zebra/redistribute.h @@ -27,15 +27,12 @@ #include "vty.h" #include "vrf.h" -extern void zebra_redistribute_add(int, struct zserv *, int, - struct zebra_vrf *zvrf); -extern void zebra_redistribute_delete(int, struct zserv *, int, - struct zebra_vrf *zvrf); - -extern void zebra_redistribute_default_add(int, struct zserv *, int, - struct zebra_vrf *zvrf); -extern void zebra_redistribute_default_delete(int, struct zserv *, int, - struct zebra_vrf *zvrf); +/* ZAPI command handlers */ +extern void zebra_redistribute_add(ZAPI_HANDLER_ARGS); +extern void zebra_redistribute_delete(ZAPI_HANDLER_ARGS); +extern void zebra_redistribute_default_add(ZAPI_HANDLER_ARGS); +extern void zebra_redistribute_default_delete(ZAPI_HANDLER_ARGS); +/* ----------------- */ extern void redistribute_update(struct prefix *, struct prefix *, struct route_entry *, struct route_entry *); diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 5eebca163b..d0b821bfd2 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -801,8 +801,7 @@ static void ipv6_nd_suppress_ra_set(struct interface *ifp, * if the operator has explicitly enabled RA. The enable request can also * specify a RA interval (in seconds). */ -void zebra_interface_radv_set(struct zserv *client, u_short length, - struct zebra_vrf *zvrf, int enable) +static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable) { struct stream *s; ifindex_t ifindex; @@ -810,7 +809,7 @@ void zebra_interface_radv_set(struct zserv *client, u_short length, struct zebra_if *zif; int ra_interval; - s = client->ibuf; + s = msg; /* Get interface index and RA interval. */ STREAM_GETL(s, ifindex); @@ -859,6 +858,15 @@ stream_failure: return; } +void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS) +{ + zebra_interface_radv_set(client, hdr, msg, zvrf, 0); +} +void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS) +{ + zebra_interface_radv_set(client, hdr, msg, zvrf, 1); +} + DEFUN (ipv6_nd_suppress_ra, ipv6_nd_suppress_ra_cmd, "ipv6 nd suppress-ra", diff --git a/zebra/rtadv.h b/zebra/rtadv.h index 2cae6d06f9..8fd67c8a63 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -103,7 +103,8 @@ typedef enum { extern void rtadv_init(struct zebra_ns *); extern void rtadv_terminate(struct zebra_ns *); extern void rtadv_cmd_init(void); -extern void zebra_interface_radv_set(struct zserv *client, u_short length, - struct zebra_vrf *zvrf, int enable); +extern void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS); +extern void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS); + #endif /* _ZEBRA_RTADV_H */ diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 0af06806d3..1868b4676d 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -455,8 +455,7 @@ static int fec_send(zebra_fec_t *fec, struct zserv *client) rn = fec->rn; /* Get output stream. */ - s = client->obuf; - stream_reset(s); + s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_FEC_UPDATE, VRF_DEFAULT); @@ -464,7 +463,7 @@ static int fec_send(zebra_fec_t *fec, struct zserv *client) stream_put_prefix(s, &rn->p); stream_putl(s, fec->label); stream_putw_at(s, 0, stream_get_endp(s)); - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } /* diff --git a/zebra/zebra_mroute.c b/zebra/zebra_mroute.c index e9cd19ebe0..042bd3769e 100644 --- a/zebra/zebra_mroute.c +++ b/zebra/zebra_mroute.c @@ -32,17 +32,16 @@ #include "zebra/rt.h" #include "zebra/debug.h" -int zebra_ipmr_route_stats(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +void zebra_ipmr_route_stats(ZAPI_HANDLER_ARGS) { struct mcast_route_data mroute; struct stream *s; int suc = -1; memset(&mroute, 0, sizeof(mroute)); - STREAM_GET(&mroute.sg.src, client->ibuf, 4); - STREAM_GET(&mroute.sg.grp, client->ibuf, 4); - STREAM_GETL(client->ibuf, mroute.ifindex); + STREAM_GET(&mroute.sg.src, msg, 4); + STREAM_GET(&mroute.sg.grp, msg, 4); + STREAM_GETL(msg, mroute.ifindex); if (IS_ZEBRA_DEBUG_KERNEL) { char sbuf[40]; @@ -57,7 +56,7 @@ int zebra_ipmr_route_stats(struct zserv *client, u_short length, suc = kernel_get_ipmr_sg_stats(zvrf, &mroute); stream_failure: - s = client->obuf; + s = stream_new(ZEBRA_MAX_PACKET_SIZ); stream_reset(s); @@ -68,6 +67,5 @@ stream_failure: stream_putl(s, suc); stream_putw_at(s, 0, stream_get_endp(s)); - zebra_server_send_message(client); - return 0; + zebra_server_send_message(client, s); } diff --git a/zebra/zebra_mroute.h b/zebra/zebra_mroute.h index 616c3a83ab..3385153600 100644 --- a/zebra/zebra_mroute.h +++ b/zebra/zebra_mroute.h @@ -22,13 +22,14 @@ #ifndef __ZEBRA_MROUTE_H__ #define __ZEBRA_MROUTE_H__ +#include "zebra/zserv.h" + struct mcast_route_data { struct prefix_sg sg; unsigned int ifindex; unsigned long long lastused; }; -int zebra_ipmr_route_stats(struct zserv *client, u_short length, - struct zebra_vrf *zvf); +void zebra_ipmr_route_stats(ZAPI_HANDLER_ARGS); #endif diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index f6775fa0b1..67c7220b6f 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -661,8 +661,7 @@ int zebra_ptm_sock_read(struct thread *thread) } /* BFD peer/dst register/update */ -int zebra_ptm_bfd_dst_register(struct zserv *client, u_short length, - int command, struct zebra_vrf *zvrf) +void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS) { struct stream *s; struct prefix src_p; @@ -680,20 +679,20 @@ int zebra_ptm_bfd_dst_register(struct zserv *client, u_short length, int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF; unsigned int pid; - if (command == ZEBRA_BFD_DEST_UPDATE) + if (hdr->command == ZEBRA_BFD_DEST_UPDATE) client->bfd_peer_upd8_cnt++; else client->bfd_peer_add_cnt++; if (IS_ZEBRA_DEBUG_EVENT) zlog_debug("bfd_dst_register msg from client %s: length=%d", - zebra_route_string(client->proto), length); + zebra_route_string(client->proto), hdr->length); if (ptm_cb.ptm_sock == -1) { ptm_cb.t_timer = NULL; thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); - return -1; + return; } ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt); @@ -703,7 +702,7 @@ int zebra_ptm_bfd_dst_register(struct zserv *client, u_short length, ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD, tmp_buf); - s = client->ibuf; + s = msg; STREAM_GETL(s, pid); sprintf(tmp_buf, "%d", pid); @@ -816,16 +815,14 @@ int zebra_ptm_bfd_dst_register(struct zserv *client, u_short length, ptm_cb.out_data); zebra_ptm_send_message(ptm_cb.out_data, data_len); - return 0; + return; stream_failure: ptm_lib_cleanup_msg(ptm_hdl, out_ctxt); - return 0; } /* BFD peer/dst deregister */ -int zebra_ptm_bfd_dst_deregister(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS) { struct stream *s; struct prefix src_p; @@ -843,13 +840,13 @@ int zebra_ptm_bfd_dst_deregister(struct zserv *client, u_short length, if (IS_ZEBRA_DEBUG_EVENT) zlog_debug("bfd_dst_deregister msg from client %s: length=%d", - zebra_route_string(client->proto), length); + zebra_route_string(client->proto), hdr->length); if (ptm_cb.ptm_sock == -1) { ptm_cb.t_timer = NULL; thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); - return -1; + return; } ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt); @@ -861,7 +858,7 @@ int zebra_ptm_bfd_dst_deregister(struct zserv *client, u_short length, ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD, tmp_buf); - s = client->ibuf; + s = msg; STREAM_GETL(s, pid); sprintf(tmp_buf, "%d", pid); @@ -948,15 +945,14 @@ int zebra_ptm_bfd_dst_deregister(struct zserv *client, u_short length, zebra_ptm_send_message(ptm_cb.out_data, data_len); - return 0; + return; stream_failure: ptm_lib_cleanup_msg(ptm_hdl, out_ctxt); - return 0; } /* BFD client register */ -int zebra_ptm_bfd_client_register(struct zserv *client, u_short length) +void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS) { struct stream *s; unsigned int pid; @@ -968,16 +964,16 @@ int zebra_ptm_bfd_client_register(struct zserv *client, u_short length) if (IS_ZEBRA_DEBUG_EVENT) zlog_debug("bfd_client_register msg from client %s: length=%d", - zebra_route_string(client->proto), length); + zebra_route_string(client->proto), hdr->length); - s = client->ibuf; + s = msg; STREAM_GETL(s, pid); if (ptm_cb.ptm_sock == -1) { ptm_cb.t_timer = NULL; thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); - return -1; + return; } ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt); @@ -1003,7 +999,7 @@ int zebra_ptm_bfd_client_register(struct zserv *client, u_short length) SET_FLAG(ptm_cb.client_flags[client->proto], ZEBRA_PTM_BFD_CLIENT_FLAG_REG); - return 0; + return; stream_failure: /* @@ -1013,7 +1009,7 @@ stream_failure: * if (out_ctxt) * ptm_lib_cleanup_msg(ptm_hdl, out_ctxt); */ - return 0; + return; } /* BFD client deregister */ diff --git a/zebra/zebra_ptm.h b/zebra/zebra_ptm.h index 392853b599..0b41410bec 100644 --- a/zebra/zebra_ptm.h +++ b/zebra/zebra_ptm.h @@ -28,6 +28,8 @@ extern const char ZEBRA_PTM_SOCK_NAME[]; #define ZEBRA_PTM_BFD_CLIENT_FLAG_REG (1 << 1) /* client registered with BFD */ +#include "zebra/zserv.h" + /* Zebra ptm context block */ struct zebra_ptm_cb { int ptm_sock; /* ptm file descriptor. */ @@ -62,12 +64,12 @@ int zebra_ptm_connect(struct thread *t); void zebra_ptm_write(struct vty *vty); int zebra_ptm_get_enable_state(void); -int zebra_ptm_bfd_dst_register(struct zserv *client, u_short length, - int command, struct zebra_vrf *zvrf); -int zebra_ptm_bfd_dst_deregister(struct zserv *client, u_short length, - struct zebra_vrf *zvrf); +/* ZAPI message handlers */ +void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS); +void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS); +void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS); + void zebra_ptm_show_status(struct vty *vty, struct interface *ifp); -int zebra_ptm_bfd_client_register(struct zserv *client, u_short length); void zebra_ptm_if_init(struct zebra_if *zebra_ifp); void zebra_ptm_if_set_ptm_state(struct interface *ifp, struct zebra_if *zebra_ifp); diff --git a/zebra/zebra_ptm_redistribute.c b/zebra/zebra_ptm_redistribute.c index 8fddd400cc..fe788ac4d7 100644 --- a/zebra/zebra_ptm_redistribute.c +++ b/zebra/zebra_ptm_redistribute.c @@ -38,8 +38,7 @@ static int zsend_interface_bfd_update(int cmd, struct zserv *client, if (!client->ifinfo) return 0; - s = client->obuf; - stream_reset(s); + s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, cmd, vrf_id); if (ifp) @@ -66,7 +65,7 @@ static int zsend_interface_bfd_update(int cmd, struct zserv *client, stream_putw_at(s, 0, stream_get_endp(s)); client->if_bfd_cnt++; - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } void zebra_interface_bfd_update(struct interface *ifp, struct prefix *dp, @@ -93,8 +92,7 @@ static int zsend_bfd_peer_replay(int cmd, struct zserv *client) { struct stream *s; - s = client->obuf; - stream_reset(s); + s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, cmd, VRF_DEFAULT); @@ -102,7 +100,7 @@ static int zsend_bfd_peer_replay(int cmd, struct zserv *client) stream_putw_at(s, 0, stream_get_endp(s)); client->bfd_peer_replay_cnt++; - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } void zebra_bfd_peer_replay_req(void) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 1204da92fb..72dbfb12fc 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -305,6 +305,8 @@ struct nexthop *route_entry_nexthop_ipv6_ifindex_add(struct route_entry *re, nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; nexthop->gate.ipv6 = *ipv6; nexthop->ifindex = ifindex; + if (CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); route_entry_nexthop_add(re, nexthop); @@ -421,6 +423,10 @@ static int nexthop_active(afi_t afi, struct route_entry *re, re->nexthop_mtu = 0; } + /* Next hops (remote VTEPs) for EVPN routes are fully resolved. */ + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN_RVTEP)) + return 1; + /* Skip nexthops that have been filtered out due to route-map */ /* The nexthops are specific to this route and so the same */ /* nexthop for a different route may not have this flag set */ @@ -859,9 +865,7 @@ static unsigned nexthop_active_check(struct route_node *rn, case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: family = AFI_IP; - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN_RVTEP)) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); - else if (nexthop_active(AFI_IP, re, nexthop, set, rn)) + if (nexthop_active(AFI_IP, re, nexthop, set, rn)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); @@ -2554,10 +2558,17 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, struct ipaddr vtep_ip; memset(&vtep_ip, 0, sizeof(struct ipaddr)); - vtep_ip.ipa_type = IPADDR_V4; - memcpy(&(vtep_ip.ipaddr_v4), - &(tmp_nh->gate.ipv4), - sizeof(struct in_addr)); + if (afi == AFI_IP) { + vtep_ip.ipa_type = IPADDR_V4; + memcpy(&(vtep_ip.ipaddr_v4), + &(tmp_nh->gate.ipv4), + sizeof(struct in_addr)); + } else { + vtep_ip.ipa_type = IPADDR_V6; + memcpy(&(vtep_ip.ipaddr_v6), + &(tmp_nh->gate.ipv6), + sizeof(struct in6_addr)); + } zebra_vxlan_evpn_vrf_route_del(re->vrf_id, rmac, &vtep_ip, p); } diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index dd3fe17702..c9fb782ba6 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -995,8 +995,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, re = rnh->state; /* Get output stream. */ - s = client->obuf; - stream_reset(s); + s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, cmd, vrf_id); @@ -1063,7 +1062,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, client->nh_last_upd_time = monotime(NULL); client->last_write_cmd = cmd; - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } static void print_nh(struct nexthop *nexthop, struct vty *vty) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index d3ede66fb0..256fa9e4b7 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -1157,8 +1157,7 @@ static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr, if (!client) return 0; - s = client->obuf; - stream_reset(s); + s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, cmd, VRF_DEFAULT); stream_putl(s, vni); @@ -1195,7 +1194,7 @@ static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr, else client->macipdel_cnt++; - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } /* @@ -2565,8 +2564,7 @@ static int zvni_send_add_to_client(zebra_vni_t *zvni) if (!client) return 0; - s = client->obuf; - stream_reset(s); + s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_VNI_ADD, VRF_DEFAULT); stream_putl(s, zvni->vni); @@ -2583,7 +2581,7 @@ static int zvni_send_add_to_client(zebra_vni_t *zvni) zebra_route_string(client->proto)); client->vniadd_cnt++; - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } /* @@ -2599,7 +2597,7 @@ static int zvni_send_del_to_client(vni_t vni) if (!client) return 0; - s = client->obuf; + s = stream_new(ZEBRA_MAX_PACKET_SIZ); stream_reset(s); zclient_create_header(s, ZEBRA_VNI_DEL, VRF_DEFAULT); @@ -2613,7 +2611,7 @@ static int zvni_send_del_to_client(vni_t vni) zebra_route_string(client->proto)); client->vnidel_cnt++; - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } /* @@ -3550,8 +3548,7 @@ static int zl3vni_send_add_to_client(zebra_l3vni_t *zl3vni) memset(&rmac, 0, sizeof(struct ethaddr)); zl3vni_get_rmac(zl3vni, &rmac); - s = client->obuf; - stream_reset(s); + s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_L3VNI_ADD, zl3vni_vrf_id(zl3vni)); stream_putl(s, zl3vni->vni); @@ -3574,7 +3571,7 @@ static int zl3vni_send_add_to_client(zebra_l3vni_t *zl3vni) zebra_route_string(client->proto)); client->l3vniadd_cnt++; - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } /* @@ -3590,8 +3587,7 @@ static int zl3vni_send_del_to_client(zebra_l3vni_t *zl3vni) if (!client) return 0; - s = client->obuf; - stream_reset(s); + s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_L3VNI_DEL, zl3vni_vrf_id(zl3vni)); stream_putl(s, zl3vni->vni); @@ -3605,7 +3601,7 @@ static int zl3vni_send_del_to_client(zebra_l3vni_t *zl3vni) zebra_route_string(client->proto)); client->l3vnidel_cnt++; - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni) @@ -3723,8 +3719,7 @@ static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p, if (!client) return 0; - s = client->obuf; - stream_reset(s); + s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, cmd, vrf_id); stream_put(s, p, sizeof(struct prefix)); @@ -3743,7 +3738,7 @@ static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p, else client->prefixdel_cnt++; - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } /* re-add remote rmac if needed */ @@ -4863,8 +4858,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, /* * Handle message from client to delete a remote MACIP for a VNI. */ -int zebra_vxlan_remote_macip_del(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +void zebra_vxlan_remote_macip_del(ZAPI_HANDLER_ARGS) { struct stream *s; vni_t vni; @@ -4884,9 +4878,9 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, u_short length, memset(&ip, 0, sizeof(struct ipaddr)); memset(&vtep_ip, 0, sizeof(struct in_addr)); - s = client->ibuf; + s = msg; - while (l < length) { + while (l < hdr->length) { /* Obtain each remote MACIP and process. */ /* Message contains VNI, followed by MAC followed by IP (if any) * followed by remote VTEP IP. @@ -5008,7 +5002,7 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, u_short length, } stream_failure: - return 0; + return; } /* @@ -5016,8 +5010,7 @@ stream_failure: * could be just the add of a MAC address or the add of a neighbor * (IP+MAC). */ -int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS) { struct stream *s; vni_t vni; @@ -5045,12 +5038,12 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length, zlog_warn( "%s: EVPN Not turned on yet we have received a remote_macip add zapi callback", __PRETTY_FUNCTION__); - return -1; + return; } - s = client->ibuf; + s = msg; - while (l < length) { + while (l < hdr->length) { /* Obtain each remote MACIP and process. */ /* Message contains VNI, followed by MAC followed by IP (if any) * followed by remote VTEP IP. @@ -5159,7 +5152,7 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length, prefix_mac2str(&macaddr, buf, sizeof(buf)), vni, inet_ntoa(vtep_ip)); - return -1; + return; } /* Is this MAC created for a MACIP? */ @@ -5212,7 +5205,7 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length, prefix_mac2str(&macaddr, buf, sizeof(buf)), vni, inet_ntoa(vtep_ip)); - return -1; + return; } } else if (memcmp(&n->emac, &macaddr, sizeof(macaddr)) @@ -5240,7 +5233,7 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length, } stream_failure: - return 0; + return; } /* @@ -5543,8 +5536,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, /* * Handle message from client to delete a remote VTEP for a VNI. */ -int zebra_vxlan_remote_vtep_del(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS) { struct stream *s; u_short l = 0; @@ -5559,18 +5551,18 @@ int zebra_vxlan_remote_vtep_del(struct zserv *client, u_short length, zlog_warn( "%s: EVPN is not enabled yet we have received a vtep del command", __PRETTY_FUNCTION__); - return -1; + return; } if (zvrf_id(zvrf) != VRF_DEFAULT) { zlog_err("Recv MACIP DEL for non-default VRF %u", zvrf_id(zvrf)); - return -1; + return; } - s = client->ibuf; + s = msg; - while (l < length) { + while (l < hdr->length) { /* Obtain each remote VTEP and process. */ STREAM_GETL(s, vni); l += 4; @@ -5623,14 +5615,13 @@ int zebra_vxlan_remote_vtep_del(struct zserv *client, u_short length, } stream_failure: - return 0; + return; } /* * Handle message from client to add a remote VTEP for a VNI. */ -int zebra_vxlan_remote_vtep_add(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS) { struct stream *s; u_short l = 0; @@ -5644,18 +5635,18 @@ int zebra_vxlan_remote_vtep_add(struct zserv *client, u_short length, zlog_warn( "%s: EVPN not enabled yet we received a vtep_add zapi call", __PRETTY_FUNCTION__); - return -1; + return; } if (zvrf_id(zvrf) != VRF_DEFAULT) { zlog_err("Recv MACIP ADD for non-default VRF %u", zvrf_id(zvrf)); - return -1; + return; } - s = client->ibuf; + s = msg; - while (l < length) { + while (l < hdr->length) { /* Obtain each remote VTEP and process. */ STREAM_GETL(s, vni); l += 4; @@ -5705,7 +5696,7 @@ int zebra_vxlan_remote_vtep_add(struct zserv *client, u_short length, } stream_failure: - return 0; + return; } /* @@ -6512,8 +6503,7 @@ int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf) * Handle message from client to enable/disable advertisement of g/w macip * routes */ -int zebra_vxlan_advertise_subnet(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS) { struct stream *s; int advertise; @@ -6527,19 +6517,19 @@ int zebra_vxlan_advertise_subnet(struct zserv *client, u_short length, if (zvrf_id(zvrf) != VRF_DEFAULT) { zlog_err("EVPN GW-MACIP Adv for non-default VRF %u", zvrf_id(zvrf)); - return -1; + return; } - s = client->ibuf; + s = msg; advertise = stream_getc(s); vni = stream_get3(s); zvni = zvni_lookup(vni); if (!zvni) - return 0; + return; if (zvni->advertise_subnet == advertise) - return 0; + return; if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug("EVPN subnet Adv %s on VNI %d , currently %s", @@ -6551,35 +6541,32 @@ int zebra_vxlan_advertise_subnet(struct zserv *client, u_short length, ifp = zvni->vxlan_if; if (!ifp) - return 0; + return; zif = ifp->info; /* If down or not mapped to a bridge, we're done. */ if (!if_is_operative(ifp) || !zif->brslave_info.br_if) - return 0; + return; zl2_info = zif->l2info.vxl; vlan_if = zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if); if (!vlan_if) - return 0; + return; if (zvni->advertise_subnet) zvni_advertise_subnet(zvni, vlan_if, 1); else zvni_advertise_subnet(zvni, vlan_if, 0); - - return 0; } /* * Handle message from client to enable/disable advertisement of g/w macip * routes */ -int zebra_vxlan_advertise_gw_macip(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS) { struct stream *s; int advertise; @@ -6590,10 +6577,10 @@ int zebra_vxlan_advertise_gw_macip(struct zserv *client, u_short length, if (zvrf_id(zvrf) != VRF_DEFAULT) { zlog_err("EVPN GW-MACIP Adv for non-default VRF %u", zvrf_id(zvrf)); - return -1; + return; } - s = client->ibuf; + s = msg; STREAM_GETC(s, advertise); STREAM_GET(&vni, s, 3); @@ -6606,7 +6593,7 @@ int zebra_vxlan_advertise_gw_macip(struct zserv *client, u_short length, : "disabled"); if (zvrf->advertise_gw_macip == advertise) - return 0; + return; zvrf->advertise_gw_macip = advertise; @@ -6625,7 +6612,7 @@ int zebra_vxlan_advertise_gw_macip(struct zserv *client, u_short length, zvni = zvni_lookup(vni); if (!zvni) - return 0; + return; if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( @@ -6635,26 +6622,26 @@ int zebra_vxlan_advertise_gw_macip(struct zserv *client, u_short length, : "disabled"); if (zvni->advertise_gw_macip == advertise) - return 0; + return; zvni->advertise_gw_macip = advertise; ifp = zvni->vxlan_if; if (!ifp) - return 0; + return; zif = ifp->info; /* If down or not mapped to a bridge, we're done. */ if (!if_is_operative(ifp) || !zif->brslave_info.br_if) - return 0; + return; zl2_info = zif->l2info.vxl; vlan_if = zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if); if (!vlan_if) - return 0; + return; if (advertise_gw_macip_enabled(zvni)) { /* Add primary SVI MAC-IP */ @@ -6676,7 +6663,7 @@ int zebra_vxlan_advertise_gw_macip(struct zserv *client, u_short length, } stream_failure: - return 0; + return; } @@ -6686,8 +6673,7 @@ stream_failure: * when disabled, the entries should be deleted and remote VTEPs and MACs * uninstalled from the kernel. */ -int zebra_vxlan_advertise_all_vni(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS) { struct stream *s = NULL; int advertise = 0; @@ -6695,10 +6681,10 @@ int zebra_vxlan_advertise_all_vni(struct zserv *client, u_short length, if (zvrf_id(zvrf) != VRF_DEFAULT) { zlog_err("EVPN VNI Adv for non-default VRF %u", zvrf_id(zvrf)); - return -1; + return; } - s = client->ibuf; + s = msg; STREAM_GETC(s, advertise); if (IS_ZEBRA_DEBUG_VXLAN) @@ -6707,7 +6693,7 @@ int zebra_vxlan_advertise_all_vni(struct zserv *client, u_short length, is_evpn_enabled() ? "enabled" : "disabled"); if (zvrf->advertise_all_vni == advertise) - return 0; + return; zvrf->advertise_all_vni = advertise; if (is_evpn_enabled()) { @@ -6732,13 +6718,13 @@ int zebra_vxlan_advertise_all_vni(struct zserv *client, u_short length, /* cleanup all l3vnis */ zns = zebra_ns_lookup(NS_DEFAULT); if (!zns) - return -1; + return; hash_iterate(zns->l3vni_table, zl3vni_cleanup_all, NULL); } stream_failure: - return 0; + return; } /* diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index 7abf0050fc..6f25ad1e24 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -33,6 +33,7 @@ #include "lib/json.h" #include "zebra/zebra_vrf.h" +#include "zebra/zserv.h" /* Is EVPN enabled? */ #define EVPN_ENABLED(zvrf) (zvrf)->advertise_all_vni @@ -51,6 +52,15 @@ static inline int is_evpn_enabled() #define VNI_STR_LEN 32 +/* ZAPI message handlers */ +extern void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS); +extern void zebra_vxlan_remote_macip_del(ZAPI_HANDLER_ARGS); +extern void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS); +extern void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS); +extern void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS); +extern void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS); +extern void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS); + extern int is_l3vni_for_prefix_routes_only(vni_t vni); extern ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id); extern int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf); @@ -117,10 +127,6 @@ extern int zebra_vxlan_local_neigh_add_update( extern int zebra_vxlan_local_neigh_del(struct interface *ifp, struct interface *link_if, struct ipaddr *ip); -extern int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length, - struct zebra_vrf *zvrf); -extern int zebra_vxlan_remote_macip_del(struct zserv *client, u_short length, - struct zebra_vrf *zvrf); extern int zebra_vxlan_local_mac_add_update(struct interface *ifp, struct interface *br_if, struct ethaddr *mac, vlanid_t vid, @@ -140,16 +146,6 @@ extern int zebra_vxlan_if_down(struct interface *ifp); extern int zebra_vxlan_if_add(struct interface *ifp); extern int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags); extern int zebra_vxlan_if_del(struct interface *ifp); -extern int zebra_vxlan_remote_vtep_add(struct zserv *client, u_short length, - struct zebra_vrf *zvrf); -extern int zebra_vxlan_remote_vtep_del(struct zserv *client, u_short length, - struct zebra_vrf *zvrf); -extern int zebra_vxlan_advertise_subnet(struct zserv *client, u_short length, - struct zebra_vrf *zvrf); -extern int zebra_vxlan_advertise_gw_macip(struct zserv *client, u_short length, - struct zebra_vrf *zvrf); -extern int zebra_vxlan_advertise_all_vni(struct zserv *client, u_short length, - struct zebra_vrf *zvrf); extern int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, char *err, int err_str_sz, int filter, int add); diff --git a/zebra/zserv.c b/zebra/zserv.c index 1a2ad7f8b4..0def903803 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -63,94 +63,23 @@ #include "zebra/zebra_pbr.h" /* Event list of zebra. */ -enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; - -static void zebra_event(enum event event, int sock, struct zserv *client); - +enum event { ZEBRA_READ, ZEBRA_WRITE }; +/* privileges */ extern struct zebra_privs_t zserv_privs; +/* post event into client */ +static void zebra_event(struct zserv *client, enum event event); -static void zebra_client_close(struct zserv *client); -static int zserv_delayed_close(struct thread *thread) +/* Public interface ======================================================== */ + +int zebra_server_send_message(struct zserv *client, struct stream *msg) { - struct zserv *client = THREAD_ARG(thread); - - client->t_suicide = NULL; - zebra_client_close(client); + stream_fifo_push(client->obuf_fifo, msg); + zebra_event(client, ZEBRA_WRITE); return 0; } -static int zserv_flush_data(struct thread *thread) -{ - struct zserv *client = THREAD_ARG(thread); - - client->t_write = NULL; - if (client->t_suicide) { - zebra_client_close(client); - return -1; - } - switch (buffer_flush_available(client->wb, client->sock)) { - case BUFFER_ERROR: - zlog_warn( - "%s: buffer_flush_available failed on zserv client fd %d, " - "closing", - __func__, client->sock); - zebra_client_close(client); - client = NULL; - break; - case BUFFER_PENDING: - client->t_write = NULL; - thread_add_write(zebrad.master, zserv_flush_data, client, - client->sock, &client->t_write); - break; - case BUFFER_EMPTY: - break; - } - - if (client) - client->last_write_time = monotime(NULL); - return 0; -} - -int zebra_server_send_message(struct zserv *client) -{ - if (client->t_suicide) - return -1; - - if (client->is_synchronous) - return 0; - - stream_set_getp(client->obuf, 0); - client->last_write_cmd = stream_getw_from(client->obuf, 6); - switch (buffer_write(client->wb, client->sock, - STREAM_DATA(client->obuf), - stream_get_endp(client->obuf))) { - case BUFFER_ERROR: - zlog_warn( - "%s: buffer_write failed to zserv client fd %d, closing", - __func__, client->sock); - /* Schedule a delayed close since many of the functions that - call this - one do not check the return code. They do not allow for the - possibility that an I/O error may have caused the client to - be - deleted. */ - client->t_suicide = NULL; - thread_add_event(zebrad.master, zserv_delayed_close, client, 0, - &client->t_suicide); - return -1; - case BUFFER_EMPTY: - THREAD_OFF(client->t_write); - break; - case BUFFER_PENDING: - thread_add_write(zebrad.master, zserv_flush_data, client, - client->sock, &client->t_write); - break; - } - - client->last_write_time = monotime(NULL); - return 0; -} +/* Encoding helpers -------------------------------------------------------- */ static void zserv_encode_interface(struct stream *s, struct interface *ifp) { @@ -202,6 +131,34 @@ static void zserv_encode_vrf(struct stream *s, struct zebra_vrf *zvrf) stream_putw_at(s, 0, stream_get_endp(s)); } +static int zserv_encode_nexthop(struct stream *s, struct nexthop *nexthop) +{ + stream_putc(s, nexthop->type); + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + stream_put_in_addr(s, &nexthop->gate.ipv4); + stream_putl(s, nexthop->ifindex); + break; + case NEXTHOP_TYPE_IPV6: + stream_put(s, &nexthop->gate.ipv6, 16); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + stream_put(s, &nexthop->gate.ipv6, 16); + stream_putl(s, nexthop->ifindex); + break; + case NEXTHOP_TYPE_IFINDEX: + stream_putl(s, nexthop->ifindex); + break; + default: + /* do nothing */ + break; + } + return 1; +} + +/* Send handlers ----------------------------------------------------------- */ + /* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */ /* * This function is called in the following situations: @@ -215,65 +172,54 @@ static void zserv_encode_vrf(struct stream *s, struct zebra_vrf *zvrf) */ int zsend_interface_add(struct zserv *client, struct interface *ifp) { - struct stream *s; - - s = client->obuf; - stream_reset(s); + struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_INTERFACE_ADD, ifp->vrf_id); zserv_encode_interface(s, ifp); client->ifadd_cnt++; - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } /* Interface deletion from zebra daemon. */ int zsend_interface_delete(struct zserv *client, struct interface *ifp) { - struct stream *s; - - s = client->obuf; - stream_reset(s); + struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id); zserv_encode_interface(s, ifp); client->ifdel_cnt++; - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } int zsend_vrf_add(struct zserv *client, struct zebra_vrf *zvrf) { - struct stream *s; - - s = client->obuf; - stream_reset(s); + struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_VRF_ADD, zvrf_id(zvrf)); zserv_encode_vrf(s, zvrf); client->vrfadd_cnt++; - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } /* VRF deletion from zebra daemon. */ int zsend_vrf_delete(struct zserv *client, struct zebra_vrf *zvrf) -{ - struct stream *s; - s = client->obuf; - stream_reset(s); +{ + struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_VRF_DELETE, zvrf_id(zvrf)); zserv_encode_vrf(s, zvrf); client->vrfdel_cnt++; - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } int zsend_interface_link_params(struct zserv *client, struct interface *ifp) { - struct stream *s; + struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); /* Check this client need interface information. */ if (!client->ifinfo) @@ -281,8 +227,6 @@ int zsend_interface_link_params(struct zserv *client, struct interface *ifp) if (!ifp->link_params) return 0; - s = client->obuf; - stream_reset(s); zclient_create_header(s, ZEBRA_INTERFACE_LINK_PARAMS, ifp->vrf_id); @@ -296,7 +240,7 @@ int zsend_interface_link_params(struct zserv *client, struct interface *ifp) /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } /* Interface address is added/deleted. Send ZEBRA_INTERFACE_ADDRESS_ADD or @@ -341,11 +285,8 @@ int zsend_interface_address(int cmd, struct zserv *client, struct interface *ifp, struct connected *ifc) { int blen; - struct stream *s; struct prefix *p; - - s = client->obuf; - stream_reset(s); + struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, cmd, ifp->vrf_id); stream_putl(s, ifp->ifindex); @@ -378,7 +319,7 @@ int zsend_interface_address(int cmd, struct zserv *client, stream_putw_at(s, 0, stream_get_endp(s)); client->connected_rt_add_cnt++; - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } static int zsend_interface_nbr_address(int cmd, struct zserv *client, @@ -386,12 +327,9 @@ static int zsend_interface_nbr_address(int cmd, struct zserv *client, struct nbr_connected *ifc) { int blen; - struct stream *s; + struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); struct prefix *p; - s = client->obuf; - stream_reset(s); - zclient_create_header(s, cmd, ifp->vrf_id); stream_putl(s, ifp->ifindex); @@ -412,7 +350,7 @@ static int zsend_interface_nbr_address(int cmd, struct zserv *client, /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } /* Interface address addition. */ @@ -498,10 +436,7 @@ int zsend_interface_addresses(struct zserv *client, struct interface *ifp) int zsend_interface_vrf_update(struct zserv *client, struct interface *ifp, vrf_id_t vrf_id) { - struct stream *s; - - s = client->obuf; - stream_reset(s); + struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_INTERFACE_VRF_UPDATE, ifp->vrf_id); @@ -513,7 +448,7 @@ int zsend_interface_vrf_update(struct zserv *client, struct interface *ifp, stream_putw_at(s, 0, stream_get_endp(s)); client->if_vrfchg_cnt++; - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } /* Add new nbr connected IPv6 address */ @@ -575,10 +510,7 @@ void nbr_connected_delete_ipv6(struct interface *ifp, struct in6_addr *address) */ int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp) { - struct stream *s; - - s = client->obuf; - stream_reset(s); + struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, cmd, ifp->vrf_id); zserv_encode_interface(s, ifp); @@ -588,7 +520,7 @@ int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp) else client->ifdown_cnt++; - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } int zsend_redistribute_route(int cmd, struct zserv *client, struct prefix *p, @@ -660,296 +592,19 @@ int zsend_redistribute_route(int cmd, struct zserv *client, struct prefix *p, SET_FLAG(api.message, ZAPI_MESSAGE_MTU); api.mtu = re->mtu; + struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + /* Encode route and send. */ - if (zapi_route_encode(cmd, client->obuf, &api) < 0) + if (zapi_route_encode(cmd, s, &api) < 0) return -1; - return zebra_server_send_message(client); -} - -static int zsend_write_nexthop(struct stream *s, struct nexthop *nexthop) -{ - stream_putc(s, nexthop->type); - switch (nexthop->type) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - stream_put_in_addr(s, &nexthop->gate.ipv4); - stream_putl(s, nexthop->ifindex); - break; - case NEXTHOP_TYPE_IPV6: - stream_put(s, &nexthop->gate.ipv6, 16); - break; - case NEXTHOP_TYPE_IPV6_IFINDEX: - stream_put(s, &nexthop->gate.ipv6, 16); - stream_putl(s, nexthop->ifindex); - break; - case NEXTHOP_TYPE_IFINDEX: - stream_putl(s, nexthop->ifindex); - break; - default: - /* do nothing */ - break; - } - return 1; -} - -/* Nexthop register */ -static int zserv_rnh_register(struct zserv *client, u_short length, - rnh_type_t type, struct zebra_vrf *zvrf) -{ - struct rnh *rnh; - struct stream *s; - struct prefix p; - u_short l = 0; - u_char flags = 0; - - if (IS_ZEBRA_DEBUG_NHT) - zlog_debug( - "rnh_register msg from client %s: length=%d, type=%s\n", - zebra_route_string(client->proto), length, - (type == RNH_NEXTHOP_TYPE) ? "nexthop" : "route"); - - s = client->ibuf; - - client->nh_reg_time = monotime(NULL); - - while (l < length) { - STREAM_GETC(s, flags); - STREAM_GETW(s, p.family); - STREAM_GETC(s, p.prefixlen); - l += 4; - if (p.family == AF_INET) { - if (p.prefixlen > IPV4_MAX_BITLEN) { - zlog_warn( - "%s: Specified prefix length %d is too large for a v4 address", - __PRETTY_FUNCTION__, p.prefixlen); - return -1; - } - STREAM_GET(&p.u.prefix4.s_addr, s, IPV4_MAX_BYTELEN); - l += IPV4_MAX_BYTELEN; - } else if (p.family == AF_INET6) { - if (p.prefixlen > IPV6_MAX_BITLEN) { - zlog_warn( - "%s: Specified prefix length %d is to large for a v6 address", - __PRETTY_FUNCTION__, p.prefixlen); - return -1; - } - STREAM_GET(&p.u.prefix6, s, IPV6_MAX_BYTELEN); - l += IPV6_MAX_BYTELEN; - } else { - zlog_err( - "rnh_register: Received unknown family type %d\n", - p.family); - return -1; - } - rnh = zebra_add_rnh(&p, zvrf_id(zvrf), type); - if (type == RNH_NEXTHOP_TYPE) { - if (flags - && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) - SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED); - else if (!flags - && CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) - UNSET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED); - } else if (type == RNH_IMPORT_CHECK_TYPE) { - if (flags - && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH)) - SET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH); - else if (!flags && CHECK_FLAG(rnh->flags, - ZEBRA_NHT_EXACT_MATCH)) - UNSET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH); - } - - zebra_add_rnh_client(rnh, client, type, zvrf_id(zvrf)); - /* Anything not AF_INET/INET6 has been filtered out above */ - zebra_evaluate_rnh(zvrf_id(zvrf), p.family, 1, type, &p); - } - -stream_failure: - return 0; -} - -/* Nexthop register */ -static int zserv_rnh_unregister(struct zserv *client, u_short length, - rnh_type_t type, struct zebra_vrf *zvrf) -{ - struct rnh *rnh; - struct stream *s; - struct prefix p; - u_short l = 0; - - if (IS_ZEBRA_DEBUG_NHT) - zlog_debug("rnh_unregister msg from client %s: length=%d\n", - zebra_route_string(client->proto), length); - - s = client->ibuf; - - while (l < length) { - uint8_t flags; - - STREAM_GETC(s, flags); - if (flags != 0) - goto stream_failure; - - STREAM_GETW(s, p.family); - STREAM_GETC(s, p.prefixlen); - l += 4; - if (p.family == AF_INET) { - if (p.prefixlen > IPV4_MAX_BITLEN) { - zlog_warn( - "%s: Specified prefix length %d is to large for a v4 address", - __PRETTY_FUNCTION__, p.prefixlen); - return -1; - } - STREAM_GET(&p.u.prefix4.s_addr, s, IPV4_MAX_BYTELEN); - l += IPV4_MAX_BYTELEN; - } else if (p.family == AF_INET6) { - if (p.prefixlen > IPV6_MAX_BITLEN) { - zlog_warn( - "%s: Specified prefix length %d is to large for a v6 address", - __PRETTY_FUNCTION__, p.prefixlen); - return -1; - } - STREAM_GET(&p.u.prefix6, s, IPV6_MAX_BYTELEN); - l += IPV6_MAX_BYTELEN; - } else { - zlog_err( - "rnh_register: Received unknown family type %d\n", - p.family); - return -1; - } - rnh = zebra_lookup_rnh(&p, zvrf_id(zvrf), type); - if (rnh) { - client->nh_dereg_time = monotime(NULL); - zebra_remove_rnh_client(rnh, client, type); - } - } -stream_failure: - return 0; -} - -#define ZEBRA_MIN_FEC_LENGTH 5 - -/* FEC register */ -static int zserv_fec_register(struct zserv *client, u_short length) -{ - struct stream *s; - struct zebra_vrf *zvrf; - u_short l = 0; - struct prefix p; - u_int16_t flags; - u_int32_t label_index = MPLS_INVALID_LABEL_INDEX; - - s = client->ibuf; - zvrf = vrf_info_lookup(VRF_DEFAULT); - if (!zvrf) - return 0; // unexpected - - /* - * The minimum amount of data that can be sent for one fec - * registration - */ - if (length < ZEBRA_MIN_FEC_LENGTH) { - zlog_err( - "fec_register: Received a fec register of length %d, it is of insufficient size to properly decode", - length); - return -1; - } - - while (l < length) { - STREAM_GETW(s, flags); - memset(&p, 0, sizeof(p)); - STREAM_GETW(s, p.family); - if (p.family != AF_INET && p.family != AF_INET6) { - zlog_err( - "fec_register: Received unknown family type %d\n", - p.family); - return -1; - } - STREAM_GETC(s, p.prefixlen); - if ((p.family == AF_INET && p.prefixlen > IPV4_MAX_BITLEN) - || (p.family == AF_INET6 - && p.prefixlen > IPV6_MAX_BITLEN)) { - zlog_warn( - "%s: Specified prefix length: %d is to long for %d", - __PRETTY_FUNCTION__, p.prefixlen, p.family); - return -1; - } - l += 5; - STREAM_GET(&p.u.prefix, s, PSIZE(p.prefixlen)); - l += PSIZE(p.prefixlen); - if (flags & ZEBRA_FEC_REGISTER_LABEL_INDEX) { - STREAM_GETL(s, label_index); - l += 4; - } else - label_index = MPLS_INVALID_LABEL_INDEX; - zebra_mpls_fec_register(zvrf, &p, label_index, client); - } - -stream_failure: - return 0; -} - -/* FEC unregister */ -static int zserv_fec_unregister(struct zserv *client, u_short length) -{ - struct stream *s; - struct zebra_vrf *zvrf; - u_short l = 0; - struct prefix p; - uint16_t flags; - - s = client->ibuf; - zvrf = vrf_info_lookup(VRF_DEFAULT); - if (!zvrf) - return 0; // unexpected - - /* - * The minimum amount of data that can be sent for one - * fec unregistration - */ - if (length < ZEBRA_MIN_FEC_LENGTH) { - zlog_err( - "fec_unregister: Received a fec unregister of length %d, it is of insufficient size to properly decode", - length); - return -1; - } - - while (l < length) { - STREAM_GETW(s, flags); - if (flags != 0) - goto stream_failure; - - memset(&p, 0, sizeof(p)); - STREAM_GETW(s, p.family); - if (p.family != AF_INET && p.family != AF_INET6) { - zlog_err( - "fec_unregister: Received unknown family type %d\n", - p.family); - return -1; - } - STREAM_GETC(s, p.prefixlen); - if ((p.family == AF_INET && p.prefixlen > IPV4_MAX_BITLEN) - || (p.family == AF_INET6 - && p.prefixlen > IPV6_MAX_BITLEN)) { - zlog_warn( - "%s: Received prefix length %d which is greater than %d can support", - __PRETTY_FUNCTION__, p.prefixlen, p.family); - return -1; - } - l += 5; - STREAM_GET(&p.u.prefix, s, PSIZE(p.prefixlen)); - l += PSIZE(p.prefixlen); - zebra_mpls_fec_unregister(zvrf, &p, client); - } - -stream_failure: - return 0; + return zebra_server_send_message(client, s); } /* - Modified version of zsend_ipv4_nexthop_lookup(): - Query unicast rib if nexthop is not found on mrib. - Returns both route metric and protocol distance. -*/ + * Modified version of zsend_ipv4_nexthop_lookup(): Query unicast rib if + * nexthop is not found on mrib. Returns both route metric and protocol + * distance. + */ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client, struct in_addr addr, struct route_entry *re, @@ -961,7 +616,7 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client, struct nexthop *nexthop; /* Get output stream. */ - s = client->obuf; + s = stream_new(ZEBRA_MAX_PACKET_SIZ); stream_reset(s); /* Fill in result. */ @@ -981,7 +636,7 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client, * chain of nexthops. */ for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - num += zsend_write_nexthop(s, nexthop); + num += zserv_encode_nexthop(s, nexthop); stream_putc_at(s, nump, num); /* store nexthop_num */ } else { @@ -992,7 +647,7 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client, stream_putw_at(s, 0, stream_get_endp(s)); - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } int zsend_route_notify_owner(struct route_entry *re, struct prefix *p, @@ -1023,7 +678,7 @@ int zsend_route_notify_owner(struct route_entry *re, struct prefix *p, re->table, note); } - s = client->obuf; + s = stream_new(ZEBRA_MAX_PACKET_SIZ); stream_reset(s); zclient_create_header(s, ZEBRA_ROUTE_NOTIFY_OWNER, re->vrf_id); @@ -1040,7 +695,7 @@ int zsend_route_notify_owner(struct route_entry *re, struct prefix *p, stream_putw_at(s, 0, stream_get_endp(s)); - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } void zsend_rule_notify_owner(struct zebra_pbr_rule *rule, @@ -1051,8 +706,8 @@ void zsend_rule_notify_owner(struct zebra_pbr_rule *rule, struct stream *s; if (IS_ZEBRA_DEBUG_PACKET) { - zlog_debug("%s: Notifying %u", - __PRETTY_FUNCTION__, rule->unique); + zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__, + rule->unique); } for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) { @@ -1063,7 +718,7 @@ void zsend_rule_notify_owner(struct zebra_pbr_rule *rule, if (!client) return; - s = client->obuf; + s = stream_new(ZEBRA_MAX_PACKET_SIZ); stream_reset(s); zclient_create_header(s, ZEBRA_RULE_NOTIFY_OWNER, VRF_DEFAULT); @@ -1078,22 +733,20 @@ void zsend_rule_notify_owner(struct zebra_pbr_rule *rule, stream_putw_at(s, 0, stream_get_endp(s)); - zebra_server_send_message(client); + zebra_server_send_message(client, s); } /* Router-id is updated. Send ZEBRA_ROUTER_ID_ADD to client. */ int zsend_router_id_update(struct zserv *client, struct prefix *p, vrf_id_t vrf_id) { - struct stream *s; int blen; /* Check this client need interface information. */ if (!vrf_bitmap_check(client->ridinfo, vrf_id)) return 0; - s = client->obuf; - stream_reset(s); + struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); /* Message type. */ zclient_create_header(s, ZEBRA_ROUTER_ID_UPDATE, vrf_id); @@ -1107,7 +760,7 @@ int zsend_router_id_update(struct zserv *client, struct prefix *p, /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } /* @@ -1115,10 +768,7 @@ int zsend_router_id_update(struct zserv *client, struct prefix *p, */ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw) { - struct stream *s; - - s = client->obuf; - stream_reset(s); + struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_PW_STATUS_UPDATE, pw->vrf_id); stream_write(s, pw->ifname, IF_NAMESIZE); @@ -1128,13 +778,324 @@ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw) /* Put length at the first point of the stream. */ stream_putw_at(s, 0, stream_get_endp(s)); - return zebra_server_send_message(client); + return zebra_server_send_message(client, s); } -/* Register zebra server interface information. Send current all - interface and address information. */ -static int zread_interface_add(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +/* Send response to a get label chunk request to client */ +static int zsend_assign_label_chunk_response(struct zserv *client, + vrf_id_t vrf_id, + struct label_manager_chunk *lmc) +{ + int ret; + struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + + zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id); + + if (lmc) { + /* keep */ + stream_putc(s, lmc->keep); + /* start and end labels */ + stream_putl(s, lmc->start); + stream_putl(s, lmc->end); + } + + /* Write packet size. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + ret = writen(client->sock, s->data, stream_get_endp(s)); + stream_free(s); + return ret; +} + +/* Send response to a label manager connect request to client */ +static int zsend_label_manager_connect_response(struct zserv *client, + vrf_id_t vrf_id, u_short result) +{ + int ret; + struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + + zclient_create_header(s, ZEBRA_LABEL_MANAGER_CONNECT, vrf_id); + + /* result */ + stream_putc(s, result); + + /* Write packet size. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + ret = writen(client->sock, s->data, stream_get_endp(s)); + stream_free(s); + + return ret; +} + +/* Inbound message handling ------------------------------------------------ */ + +int cmd2type[] = { + [ZEBRA_NEXTHOP_REGISTER] = RNH_NEXTHOP_TYPE, + [ZEBRA_NEXTHOP_UNREGISTER] = RNH_NEXTHOP_TYPE, + [ZEBRA_IMPORT_ROUTE_REGISTER] = RNH_IMPORT_CHECK_TYPE, + [ZEBRA_IMPORT_ROUTE_UNREGISTER] = RNH_IMPORT_CHECK_TYPE, +}; + +/* Nexthop register */ +static void zread_rnh_register(ZAPI_HANDLER_ARGS) +{ + struct rnh *rnh; + struct stream *s; + struct prefix p; + u_short l = 0; + u_char flags = 0; + uint16_t type = cmd2type[hdr->command]; + + if (IS_ZEBRA_DEBUG_NHT) + zlog_debug( + "rnh_register msg from client %s: hdr->length=%d, type=%s\n", + zebra_route_string(client->proto), hdr->length, + (type == RNH_NEXTHOP_TYPE) ? "nexthop" : "route"); + + s = msg; + + client->nh_reg_time = monotime(NULL); + + while (l < hdr->length) { + STREAM_GETC(s, flags); + STREAM_GETW(s, p.family); + STREAM_GETC(s, p.prefixlen); + l += 4; + if (p.family == AF_INET) { + if (p.prefixlen > IPV4_MAX_BITLEN) { + zlog_warn( + "%s: Specified prefix hdr->length %d is too large for a v4 address", + __PRETTY_FUNCTION__, p.prefixlen); + return; + } + STREAM_GET(&p.u.prefix4.s_addr, s, IPV4_MAX_BYTELEN); + l += IPV4_MAX_BYTELEN; + } else if (p.family == AF_INET6) { + if (p.prefixlen > IPV6_MAX_BITLEN) { + zlog_warn( + "%s: Specified prefix hdr->length %d is to large for a v6 address", + __PRETTY_FUNCTION__, p.prefixlen); + return; + } + STREAM_GET(&p.u.prefix6, s, IPV6_MAX_BYTELEN); + l += IPV6_MAX_BYTELEN; + } else { + zlog_err( + "rnh_register: Received unknown family type %d\n", + p.family); + return; + } + rnh = zebra_add_rnh(&p, zvrf_id(zvrf), type); + if (type == RNH_NEXTHOP_TYPE) { + if (flags + && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) + SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED); + else if (!flags + && CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) + UNSET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED); + } else if (type == RNH_IMPORT_CHECK_TYPE) { + if (flags + && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH)) + SET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH); + else if (!flags + && CHECK_FLAG(rnh->flags, + ZEBRA_NHT_EXACT_MATCH)) + UNSET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH); + } + + zebra_add_rnh_client(rnh, client, type, zvrf_id(zvrf)); + /* Anything not AF_INET/INET6 has been filtered out above */ + zebra_evaluate_rnh(zvrf_id(zvrf), p.family, 1, type, &p); + } + +stream_failure: + return; +} + +/* Nexthop register */ +static void zread_rnh_unregister(ZAPI_HANDLER_ARGS) +{ + struct rnh *rnh; + struct stream *s; + struct prefix p; + u_short l = 0; + uint16_t type = cmd2type[hdr->command]; + + if (IS_ZEBRA_DEBUG_NHT) + zlog_debug( + "rnh_unregister msg from client %s: hdr->length=%d\n", + zebra_route_string(client->proto), hdr->length); + + s = msg; + + while (l < hdr->length) { + uint8_t flags; + + STREAM_GETC(s, flags); + if (flags != 0) + goto stream_failure; + + STREAM_GETW(s, p.family); + STREAM_GETC(s, p.prefixlen); + l += 4; + if (p.family == AF_INET) { + if (p.prefixlen > IPV4_MAX_BITLEN) { + zlog_warn( + "%s: Specified prefix hdr->length %d is to large for a v4 address", + __PRETTY_FUNCTION__, p.prefixlen); + return; + } + STREAM_GET(&p.u.prefix4.s_addr, s, IPV4_MAX_BYTELEN); + l += IPV4_MAX_BYTELEN; + } else if (p.family == AF_INET6) { + if (p.prefixlen > IPV6_MAX_BITLEN) { + zlog_warn( + "%s: Specified prefix hdr->length %d is to large for a v6 address", + __PRETTY_FUNCTION__, p.prefixlen); + return; + } + STREAM_GET(&p.u.prefix6, s, IPV6_MAX_BYTELEN); + l += IPV6_MAX_BYTELEN; + } else { + zlog_err( + "rnh_register: Received unknown family type %d\n", + p.family); + return; + } + rnh = zebra_lookup_rnh(&p, zvrf_id(zvrf), type); + if (rnh) { + client->nh_dereg_time = monotime(NULL); + zebra_remove_rnh_client(rnh, client, type); + } + } +stream_failure: + return; +} + +#define ZEBRA_MIN_FEC_LENGTH 5 + +/* FEC register */ +static void zread_fec_register(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + u_short l = 0; + struct prefix p; + uint16_t flags; + uint32_t label_index = MPLS_INVALID_LABEL_INDEX; + + s = msg; + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (!zvrf) + return; // unexpected + + /* + * The minimum amount of data that can be sent for one fec + * registration + */ + if (hdr->length < ZEBRA_MIN_FEC_LENGTH) { + zlog_err( + "fec_register: Received a fec register of hdr->length %d, it is of insufficient size to properly decode", + hdr->length); + return; + } + + while (l < hdr->length) { + STREAM_GETW(s, flags); + memset(&p, 0, sizeof(p)); + STREAM_GETW(s, p.family); + if (p.family != AF_INET && p.family != AF_INET6) { + zlog_err( + "fec_register: Received unknown family type %d\n", + p.family); + return; + } + STREAM_GETC(s, p.prefixlen); + if ((p.family == AF_INET && p.prefixlen > IPV4_MAX_BITLEN) + || (p.family == AF_INET6 + && p.prefixlen > IPV6_MAX_BITLEN)) { + zlog_warn( + "%s: Specified prefix hdr->length: %d is to long for %d", + __PRETTY_FUNCTION__, p.prefixlen, p.family); + return; + } + l += 5; + STREAM_GET(&p.u.prefix, s, PSIZE(p.prefixlen)); + l += PSIZE(p.prefixlen); + if (flags & ZEBRA_FEC_REGISTER_LABEL_INDEX) { + STREAM_GETL(s, label_index); + l += 4; + } else + label_index = MPLS_INVALID_LABEL_INDEX; + zebra_mpls_fec_register(zvrf, &p, label_index, client); + } + +stream_failure: + return; +} + +/* FEC unregister */ +static void zread_fec_unregister(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + u_short l = 0; + struct prefix p; + uint16_t flags; + + s = msg; + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (!zvrf) + return; // unexpected + + /* + * The minimum amount of data that can be sent for one + * fec unregistration + */ + if (hdr->length < ZEBRA_MIN_FEC_LENGTH) { + zlog_err( + "fec_unregister: Received a fec unregister of hdr->length %d, it is of insufficient size to properly decode", + hdr->length); + return; + } + + while (l < hdr->length) { + STREAM_GETW(s, flags); + if (flags != 0) + goto stream_failure; + + memset(&p, 0, sizeof(p)); + STREAM_GETW(s, p.family); + if (p.family != AF_INET && p.family != AF_INET6) { + zlog_err( + "fec_unregister: Received unknown family type %d\n", + p.family); + return; + } + STREAM_GETC(s, p.prefixlen); + if ((p.family == AF_INET && p.prefixlen > IPV4_MAX_BITLEN) + || (p.family == AF_INET6 + && p.prefixlen > IPV6_MAX_BITLEN)) { + zlog_warn( + "%s: Received prefix hdr->length %d which is greater than %d can support", + __PRETTY_FUNCTION__, p.prefixlen, p.family); + return; + } + l += 5; + STREAM_GET(&p.u.prefix, s, PSIZE(p.prefixlen)); + l += PSIZE(p.prefixlen); + zebra_mpls_fec_unregister(zvrf, &p, client); + } + +stream_failure: + return; +} + + +/* + * Register zebra server interface information. + * Send current all interface and address information. + */ +static void zread_interface_add(ZAPI_HANDLER_ARGS) { struct vrf *vrf; struct interface *ifp; @@ -1148,22 +1109,16 @@ static int zread_interface_add(struct zserv *client, u_short length, if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) continue; - if (zsend_interface_add(client, ifp) < 0) - return -1; - - if (zsend_interface_addresses(client, ifp) < 0) - return -1; + zsend_interface_add(client, ifp); + zsend_interface_addresses(client, ifp); } } - return 0; } /* Unregister zebra server interface information. */ -static int zread_interface_delete(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +static void zread_interface_delete(ZAPI_HANDLER_ARGS) { vrf_bitmap_unset(client->ifinfo, zvrf_id(zvrf)); - return 0; } void zserv_nexthop_num_warn(const char *caller, const struct prefix *p, @@ -1178,8 +1133,7 @@ void zserv_nexthop_num_warn(const char *caller, const struct prefix *p, } } -static int zread_route_add(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +static void zread_route_add(ZAPI_HANDLER_ARGS) { struct stream *s; struct zapi_route api; @@ -1190,10 +1144,10 @@ static int zread_route_add(struct zserv *client, u_short length, struct nexthop *nexthop = NULL; int i, ret; vrf_id_t vrf_id = 0; + struct ipaddr vtep_ip; - s = client->ibuf; - if (zapi_route_decode(s, &api) < 0) - return -1; + s = msg; + zapi_route_decode(s, &api); /* Allocate new route. */ vrf_id = zvrf_id(zvrf); @@ -1223,9 +1177,7 @@ static int zread_route_add(struct zserv *client, u_short length, re, &api_nh->gate.ipv4, NULL, api_nh->vrf_id); break; - case NEXTHOP_TYPE_IPV4_IFINDEX: { - - struct ipaddr vtep_ip; + case NEXTHOP_TYPE_IPV4_IFINDEX: memset(&vtep_ip, 0, sizeof(struct ipaddr)); if (CHECK_FLAG(api.flags, @@ -1240,7 +1192,7 @@ static int zread_route_add(struct zserv *client, u_short length, api_nh->vrf_id); /* if this an EVPN route entry, - program the nh as neigh + * program the nh as neigh */ if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { @@ -1255,15 +1207,41 @@ static int zread_route_add(struct zserv *client, u_short length, &api.prefix); } break; - } case NEXTHOP_TYPE_IPV6: nexthop = route_entry_nexthop_ipv6_add( re, &api_nh->gate.ipv6, api_nh->vrf_id); break; case NEXTHOP_TYPE_IPV6_IFINDEX: + memset(&vtep_ip, 0, sizeof(struct ipaddr)); + if (CHECK_FLAG(api.flags, + ZEBRA_FLAG_EVPN_ROUTE)) { + ifindex = + get_l3vni_svi_ifindex(vrf_id); + } else { + ifindex = api_nh->ifindex; + } + nexthop = route_entry_nexthop_ipv6_ifindex_add( - re, &api_nh->gate.ipv6, api_nh->ifindex, + re, &api_nh->gate.ipv6, ifindex, api_nh->vrf_id); + + /* if this an EVPN route entry, + * program the nh as neigh + */ + if (CHECK_FLAG(api.flags, + ZEBRA_FLAG_EVPN_ROUTE)) { + SET_FLAG(nexthop->flags, + NEXTHOP_FLAG_EVPN_RVTEP); + vtep_ip.ipa_type = IPADDR_V6; + memcpy(&vtep_ip.ipaddr_v6, + &(api_nh->gate.ipv6), + sizeof(struct in6_addr)); + zebra_vxlan_evpn_vrf_route_add( + vrf_id, + &api.rmac, + &vtep_ip, + &api.prefix); + } break; case NEXTHOP_TYPE_BLACKHOLE: nexthop = route_entry_nexthop_blackhole_add( @@ -1277,7 +1255,7 @@ static int zread_route_add(struct zserv *client, u_short length, __PRETTY_FUNCTION__, api.nexthop_num); nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); - return -1; + return; } /* MPLS labels for BGP-LU or Segment Routing */ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_LABEL) @@ -1309,7 +1287,7 @@ static int zread_route_add(struct zserv *client, u_short length, __PRETTY_FUNCTION__); nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); - return -1; + return; } if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) src_p = &api.src_prefix; @@ -1331,27 +1309,24 @@ static int zread_route_add(struct zserv *client, u_short length, client->v6_route_upd8_cnt++; break; } - - return 0; } -static int zread_route_del(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +static void zread_route_del(ZAPI_HANDLER_ARGS) { struct stream *s; struct zapi_route api; afi_t afi; struct prefix_ipv6 *src_p = NULL; - s = client->ibuf; + s = msg; if (zapi_route_decode(s, &api) < 0) - return -1; + return; afi = family2afi(api.prefix.family); if (afi != AFI_IP6 && CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) { zlog_warn("%s: Received a src prefix while afi is not v6", __PRETTY_FUNCTION__); - return -1; + return; } if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) src_p = &api.src_prefix; @@ -1369,8 +1344,6 @@ static int zread_route_del(struct zserv *client, u_short length, client->v6_route_del_cnt++; break; } - - return 0; } /* This function support multiple nexthop. */ @@ -1378,8 +1351,7 @@ static int zread_route_del(struct zserv *client, u_short length, * Parse the ZEBRA_IPV4_ROUTE_ADD sent from client. Update re and * add kernel route. */ -static int zread_ipv4_add(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +static void zread_ipv4_add(ZAPI_HANDLER_ARGS) { int i; struct route_entry *re; @@ -1398,7 +1370,7 @@ static int zread_ipv4_add(struct zserv *client, u_short length, enum blackhole_type bh_type = BLACKHOLE_NULL; /* Get input stream. */ - s = client->ibuf; + s = msg; /* Allocate new re. */ re = XCALLOC(MTYPE_RE, sizeof(struct route_entry)); @@ -1409,7 +1381,7 @@ static int zread_ipv4_add(struct zserv *client, u_short length, zlog_warn("%s: Specified route type %d is not a legal value\n", __PRETTY_FUNCTION__, re->type); XFREE(MTYPE_RE, re); - return -1; + return; } STREAM_GETW(s, re->instance); STREAM_GETL(s, re->flags); @@ -1426,7 +1398,7 @@ static int zread_ipv4_add(struct zserv *client, u_short length, "%s: Specified prefix length %d is greater than what v4 can be", __PRETTY_FUNCTION__, p.prefixlen); XFREE(MTYPE_RE, re); - return -1; + return; } STREAM_GET(&p.u.prefix4, s, PSIZE(p.prefixlen)); @@ -1478,7 +1450,7 @@ static int zread_ipv4_add(struct zserv *client, u_short length, __PRETTY_FUNCTION__); nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); - return -1; + return; break; case NEXTHOP_TYPE_BLACKHOLE: route_entry_nexthop_blackhole_add(re, bh_type); @@ -1489,7 +1461,7 @@ static int zread_ipv4_add(struct zserv *client, u_short length, __PRETTY_FUNCTION__, nexthop_type); nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); - return -1; + return; } } } @@ -1524,24 +1496,22 @@ static int zread_ipv4_add(struct zserv *client, u_short length, else if (ret < 0) client->v4_route_upd8_cnt++; - return 0; + return; stream_failure: nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); - return -1; } /* Zebra server IPv4 prefix delete function. */ -static int zread_ipv4_delete(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +static void zread_ipv4_delete(ZAPI_HANDLER_ARGS) { struct stream *s; struct zapi_ipv4 api; struct prefix p; u_int32_t table_id; - s = client->ibuf; + s = msg; /* Type, flags, message. */ STREAM_GETC(s, api.type); @@ -1557,7 +1527,7 @@ static int zread_ipv4_delete(struct zserv *client, u_short length, if (p.prefixlen > IPV4_MAX_BITLEN) { zlog_warn("%s: Passed in prefixlen %d is impossible", __PRETTY_FUNCTION__, p.prefixlen); - return -1; + return; } STREAM_GET(&p.u.prefix4, s, PSIZE(p.prefixlen)); @@ -1568,28 +1538,25 @@ static int zread_ipv4_delete(struct zserv *client, u_short length, client->v4_route_del_cnt++; stream_failure: - return 0; + return; } /* MRIB Nexthop lookup for IPv4. */ -static int zread_ipv4_nexthop_lookup_mrib(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +static void zread_ipv4_nexthop_lookup_mrib(ZAPI_HANDLER_ARGS) { struct in_addr addr; struct route_entry *re; - STREAM_GET(&addr.s_addr, client->ibuf, IPV4_MAX_BYTELEN); + STREAM_GET(&addr.s_addr, msg, IPV4_MAX_BYTELEN); re = rib_match_ipv4_multicast(zvrf_id(zvrf), addr, NULL); - return zsend_ipv4_nexthop_lookup_mrib(client, addr, re, zvrf); + zsend_ipv4_nexthop_lookup_mrib(client, addr, re, zvrf); stream_failure: - return -1; + return; } /* Zebra server IPv6 prefix add function. */ -static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client, - u_short length, - struct zebra_vrf *zvrf) +static void zread_ipv4_route_ipv6_nexthop_add(ZAPI_HANDLER_ARGS) { unsigned int i; struct stream *s; @@ -1610,7 +1577,7 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client, enum blackhole_type bh_type = BLACKHOLE_NULL; /* Get input stream. */ - s = client->ibuf; + s = msg; memset(&nhop_addr, 0, sizeof(struct in6_addr)); @@ -1623,7 +1590,7 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client, zlog_warn("%s: Specified route type: %d is not a legal value\n", __PRETTY_FUNCTION__, re->type); XFREE(MTYPE_RE, re); - return -1; + return; } STREAM_GETW(s, re->instance); STREAM_GETL(s, re->flags); @@ -1640,7 +1607,7 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client, "%s: Prefix Length %d is greater than what a v4 address can use", __PRETTY_FUNCTION__, p.prefixlen); XFREE(MTYPE_RE, re); - return -1; + return; } STREAM_GET(&p.u.prefix4, s, PSIZE(p.prefixlen)); @@ -1695,7 +1662,7 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client, __PRETTY_FUNCTION__); nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); - return -1; + return; } } @@ -1753,16 +1720,14 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client, else if (ret < 0) client->v4_route_upd8_cnt++; - return 0; + return; stream_failure: nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); - return -1; } -static int zread_ipv6_add(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +static void zread_ipv6_add(ZAPI_HANDLER_ARGS) { unsigned int i; struct stream *s; @@ -1785,7 +1750,7 @@ static int zread_ipv6_add(struct zserv *client, u_short length, enum blackhole_type bh_type = BLACKHOLE_NULL; /* Get input stream. */ - s = client->ibuf; + s = msg; memset(&nhop_addr, 0, sizeof(struct in6_addr)); @@ -1798,7 +1763,7 @@ static int zread_ipv6_add(struct zserv *client, u_short length, zlog_warn("%s: Specified route type: %d is not a legal value\n", __PRETTY_FUNCTION__, re->type); XFREE(MTYPE_RE, re); - return -1; + return; } STREAM_GETW(s, re->instance); STREAM_GETL(s, re->flags); @@ -1815,7 +1780,7 @@ static int zread_ipv6_add(struct zserv *client, u_short length, "%s: Specified prefix length %d is to large for v6 prefix", __PRETTY_FUNCTION__, p.prefixlen); XFREE(MTYPE_RE, re); - return -1; + return; } STREAM_GET(&p.u.prefix6, s, PSIZE(p.prefixlen)); @@ -1828,7 +1793,7 @@ static int zread_ipv6_add(struct zserv *client, u_short length, "%s: Specified src prefix length %d is to large for v6 prefix", __PRETTY_FUNCTION__, src_p.prefixlen); XFREE(MTYPE_RE, re); - return -1; + return; } STREAM_GET(&src_p.prefix, s, PSIZE(src_p.prefixlen)); src_pp = &src_p; @@ -1891,7 +1856,7 @@ static int zread_ipv6_add(struct zserv *client, u_short length, __PRETTY_FUNCTION__); nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); - return -1; + return; } } @@ -1947,25 +1912,22 @@ static int zread_ipv6_add(struct zserv *client, u_short length, else if (ret < 0) client->v6_route_upd8_cnt++; - return 0; + return; stream_failure: nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); - - return -1; } /* Zebra server IPv6 prefix delete function. */ -static int zread_ipv6_delete(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +static void zread_ipv6_delete(ZAPI_HANDLER_ARGS) { struct stream *s; struct zapi_ipv6 api; struct prefix p; struct prefix_ipv6 src_p, *src_pp; - s = client->ibuf; + s = msg; /* Type, flags, message. */ STREAM_GETC(s, api.type); @@ -1996,12 +1958,11 @@ static int zread_ipv6_delete(struct zserv *client, u_short length, client->v6_route_del_cnt++; stream_failure: - return 0; + return; } /* Register zebra server router-id information. Send current router-id */ -static int zread_router_id_add(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +static void zread_router_id_add(ZAPI_HANDLER_ARGS) { struct prefix p; @@ -2010,28 +1971,26 @@ static int zread_router_id_add(struct zserv *client, u_short length, router_id_get(&p, zvrf_id(zvrf)); - return zsend_router_id_update(client, &p, zvrf_id(zvrf)); + zsend_router_id_update(client, &p, zvrf_id(zvrf)); } /* Unregister zebra server router-id information. */ -static int zread_router_id_delete(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +static void zread_router_id_delete(ZAPI_HANDLER_ARGS) { vrf_bitmap_unset(client->ridinfo, zvrf_id(zvrf)); - return 0; } /* Tie up route-type and client->sock */ -static void zread_hello(struct zserv *client) +static void zread_hello(ZAPI_HANDLER_ARGS) { /* type of protocol (lib/zebra.h) */ u_char proto; u_short instance; u_char notify; - STREAM_GETC(client->ibuf, proto); - STREAM_GETW(client->ibuf, instance); - STREAM_GETC(client->ibuf, notify); + STREAM_GETC(msg, proto); + STREAM_GETW(msg, instance); + STREAM_GETC(msg, notify); if (notify) client->notify_owner = true; @@ -2052,8 +2011,7 @@ stream_failure: } /* Unregister all information in a VRF. */ -static int zread_vrf_unregister(struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +static void zread_vrf_unregister(ZAPI_HANDLER_ARGS) { int i; afi_t afi; @@ -2064,12 +2022,9 @@ static int zread_vrf_unregister(struct zserv *client, u_short length, vrf_bitmap_unset(client->redist_default, zvrf_id(zvrf)); vrf_bitmap_unset(client->ifinfo, zvrf_id(zvrf)); vrf_bitmap_unset(client->ridinfo, zvrf_id(zvrf)); - - return 0; } -static void zread_mpls_labels(int command, struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +static void zread_mpls_labels(ZAPI_HANDLER_ARGS) { struct stream *s; enum lsp_types_t type; @@ -2081,7 +2036,7 @@ static void zread_mpls_labels(int command, struct zserv *client, u_short length, u_int8_t distance; /* Get input stream. */ - s = client->ibuf; + s = msg; /* Get data. */ STREAM_GETC(s, type); @@ -2139,12 +2094,12 @@ static void zread_mpls_labels(int command, struct zserv *client, u_short length, if (!mpls_enabled) return; - if (command == ZEBRA_MPLS_LABELS_ADD) { + if (hdr->command == ZEBRA_MPLS_LABELS_ADD) { mpls_lsp_install(zvrf, type, in_label, out_label, gtype, &gate, ifindex); mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate, ifindex, distance, out_label); - } else if (command == ZEBRA_MPLS_LABELS_DELETE) { + } else if (hdr->command == ZEBRA_MPLS_LABELS_DELETE) { mpls_lsp_uninstall(zvrf, type, in_label, gtype, &gate, ifindex); mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate, ifindex, distance, out_label); @@ -2152,27 +2107,9 @@ static void zread_mpls_labels(int command, struct zserv *client, u_short length, stream_failure: return; } -/* Send response to a label manager connect request to client */ -static int zsend_label_manager_connect_response(struct zserv *client, - vrf_id_t vrf_id, u_short result) -{ - struct stream *s; - s = client->obuf; - stream_reset(s); - - zclient_create_header(s, ZEBRA_LABEL_MANAGER_CONNECT, vrf_id); - - /* result */ - stream_putc(s, result); - - /* Write packet size. */ - stream_putw_at(s, 0, stream_get_endp(s)); - - return writen(client->sock, s->data, stream_get_endp(s)); -} - -static void zread_label_manager_connect(struct zserv *client, vrf_id_t vrf_id) +static void zread_label_manager_connect(struct zserv *client, + struct stream *msg, vrf_id_t vrf_id) { struct stream *s; /* type of protocol (lib/zebra.h) */ @@ -2180,7 +2117,7 @@ static void zread_label_manager_connect(struct zserv *client, vrf_id_t vrf_id) u_short instance; /* Get input stream. */ - s = client->ibuf; + s = msg; /* Get data. */ STREAM_GETC(s, proto); @@ -2213,33 +2150,9 @@ static void zread_label_manager_connect(struct zserv *client, vrf_id_t vrf_id) stream_failure: return; } -/* Send response to a get label chunk request to client */ -static int zsend_assign_label_chunk_response(struct zserv *client, - vrf_id_t vrf_id, - struct label_manager_chunk *lmc) -{ - struct stream *s; - s = client->obuf; - stream_reset(s); - - zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id); - - if (lmc) { - /* keep */ - stream_putc(s, lmc->keep); - /* start and end labels */ - stream_putl(s, lmc->start); - stream_putl(s, lmc->end); - } - - /* Write packet size. */ - stream_putw_at(s, 0, stream_get_endp(s)); - - return writen(client->sock, s->data, stream_get_endp(s)); -} - -static void zread_get_label_chunk(struct zserv *client, vrf_id_t vrf_id) +static void zread_get_label_chunk(struct zserv *client, struct stream *msg, + vrf_id_t vrf_id) { struct stream *s; u_char keep; @@ -2247,7 +2160,7 @@ static void zread_get_label_chunk(struct zserv *client, vrf_id_t vrf_id) struct label_manager_chunk *lmc; /* Get input stream. */ - s = client->ibuf; + s = msg; /* Get data. */ STREAM_GETC(s, keep); @@ -2267,13 +2180,13 @@ stream_failure: return; } -static void zread_release_label_chunk(struct zserv *client) +static void zread_release_label_chunk(struct zserv *client, struct stream *msg) { struct stream *s; uint32_t start, end; /* Get input stream. */ - s = client->ibuf; + s = msg; /* Get data. */ STREAM_GETL(s, start); @@ -2284,20 +2197,20 @@ static void zread_release_label_chunk(struct zserv *client) stream_failure: return; } -static void zread_label_manager_request(int cmd, struct zserv *client, - struct zebra_vrf *zvrf) +static void zread_label_manager_request(ZAPI_HANDLER_ARGS) { /* to avoid sending other messages like ZERBA_INTERFACE_UP */ - if (cmd == ZEBRA_LABEL_MANAGER_CONNECT) + if (hdr->command == ZEBRA_LABEL_MANAGER_CONNECT) client->is_synchronous = 1; /* external label manager */ if (lm_is_external) - zread_relay_label_manager_request(cmd, client, zvrf_id(zvrf)); + zread_relay_label_manager_request(hdr->command, client, + zvrf_id(zvrf)); /* this is a label manager */ else { - if (cmd == ZEBRA_LABEL_MANAGER_CONNECT) - zread_label_manager_connect(client, zvrf_id(zvrf)); + if (hdr->command == ZEBRA_LABEL_MANAGER_CONNECT) + zread_label_manager_connect(client, msg, zvrf_id(zvrf)); else { /* Sanity: don't allow 'unidentified' requests */ if (!client->proto) { @@ -2305,16 +2218,16 @@ static void zread_label_manager_request(int cmd, struct zserv *client, "Got label request from an unidentified client"); return; } - if (cmd == ZEBRA_GET_LABEL_CHUNK) - zread_get_label_chunk(client, zvrf_id(zvrf)); - else if (cmd == ZEBRA_RELEASE_LABEL_CHUNK) - zread_release_label_chunk(client); + if (hdr->command == ZEBRA_GET_LABEL_CHUNK) + zread_get_label_chunk(client, msg, + zvrf_id(zvrf)); + else if (hdr->command == ZEBRA_RELEASE_LABEL_CHUNK) + zread_release_label_chunk(client, msg); } } } -static int zread_pseudowire(int command, struct zserv *client, u_short length, - struct zebra_vrf *zvrf) +static void zread_pseudowire(ZAPI_HANDLER_ARGS) { struct stream *s; char ifname[IF_NAMESIZE]; @@ -2330,7 +2243,7 @@ static int zread_pseudowire(int command, struct zserv *client, u_short length, struct zebra_pw *pw; /* Get input stream. */ - s = client->ibuf; + s = msg; /* Get data. */ STREAM_GET(ifname, s, IF_NAMESIZE); @@ -2345,7 +2258,7 @@ static int zread_pseudowire(int command, struct zserv *client, u_short length, STREAM_GET(&nexthop.ipv6, s, 16); break; default: - return -1; + return; } STREAM_GETL(s, local_label); STREAM_GETL(s, remote_label); @@ -2354,13 +2267,13 @@ static int zread_pseudowire(int command, struct zserv *client, u_short length, protocol = client->proto; pw = zebra_pw_find(zvrf, ifname); - switch (command) { + switch (hdr->command) { case ZEBRA_PW_ADD: if (pw) { zlog_warn("%s: pseudowire %s already exists [%s]", __func__, ifname, - zserv_command_string(command)); - return -1; + zserv_command_string(hdr->command)); + return; } zebra_pw_add(zvrf, ifname, protocol, client); @@ -2368,8 +2281,8 @@ static int zread_pseudowire(int command, struct zserv *client, u_short length, case ZEBRA_PW_DELETE: if (!pw) { zlog_warn("%s: pseudowire %s not found [%s]", __func__, - ifname, zserv_command_string(command)); - return -1; + ifname, zserv_command_string(hdr->command)); + return; } zebra_pw_del(zvrf, pw); @@ -2378,11 +2291,11 @@ static int zread_pseudowire(int command, struct zserv *client, u_short length, case ZEBRA_PW_UNSET: if (!pw) { zlog_warn("%s: pseudowire %s not found [%s]", __func__, - ifname, zserv_command_string(command)); - return -1; + ifname, zserv_command_string(hdr->command)); + return; } - switch (command) { + switch (hdr->command) { case ZEBRA_PW_SET: pw->enabled = 1; break; @@ -2397,7 +2310,7 @@ static int zread_pseudowire(int command, struct zserv *client, u_short length, } stream_failure: - return 0; + return; } /* Cleanup registered nexthops (across VRFs) upon client disconnect. */ @@ -2427,116 +2340,11 @@ static void zebra_client_close_cleanup_rnh(struct zserv *client) } } -/* free zebra client information. */ -static void zebra_client_free(struct zserv *client) -{ - /* Send client de-registration to BFD */ - zebra_ptm_bfd_client_deregister(client->proto); - - /* Cleanup any registered nexthops - across all VRFs. */ - zebra_client_close_cleanup_rnh(client); - - /* Release Label Manager chunks */ - release_daemon_chunks(client->proto, client->instance); - - /* Cleanup any FECs registered by this client. */ - zebra_mpls_cleanup_fecs_for_client(vrf_info_lookup(VRF_DEFAULT), - client); - - /* Remove pseudowires associated with this client */ - zebra_pw_client_close(client); - - /* Close file descriptor. */ - if (client->sock) { - unsigned long nroutes; - - close(client->sock); - nroutes = rib_score_proto(client->proto, client->instance); - zlog_notice( - "client %d disconnected. %lu %s routes removed from the rib", - client->sock, nroutes, - zebra_route_string(client->proto)); - client->sock = -1; - } - - /* Free stream buffers. */ - if (client->ibuf) - stream_free(client->ibuf); - if (client->obuf) - stream_free(client->obuf); - if (client->wb) - buffer_free(client->wb); - - /* Release threads. */ - if (client->t_read) - thread_cancel(client->t_read); - if (client->t_write) - thread_cancel(client->t_write); - if (client->t_suicide) - thread_cancel(client->t_suicide); - - /* Free bitmaps. */ - for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) - for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) - vrf_bitmap_free(client->redist[afi][i]); - - vrf_bitmap_free(client->redist_default); - vrf_bitmap_free(client->ifinfo); - vrf_bitmap_free(client->ridinfo); - - XFREE(MTYPE_TMP, client); -} - -static void zebra_client_close(struct zserv *client) -{ - listnode_delete(zebrad.client_list, client); - zebra_client_free(client); -} - -/* Make new client. */ -static void zebra_client_create(int sock) -{ - struct zserv *client; - int i; - afi_t afi; - - client = XCALLOC(MTYPE_TMP, sizeof(struct zserv)); - - /* Make client input/output buffer. */ - client->sock = sock; - client->ibuf = stream_new(ZEBRA_MAX_PACKET_SIZ); - client->obuf = stream_new(ZEBRA_MAX_PACKET_SIZ); - client->wb = buffer_new(0); - - /* Set table number. */ - client->rtm_table = zebrad.rtm_table_default; - - client->connect_time = monotime(NULL); - /* Initialize flags */ - for (afi = AFI_IP; afi < AFI_MAX; afi++) - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - client->redist[afi][i] = vrf_bitmap_init(); - client->redist_default = vrf_bitmap_init(); - client->ifinfo = vrf_bitmap_init(); - client->ridinfo = vrf_bitmap_init(); - - /* by default, it's not a synchronous client */ - client->is_synchronous = 0; - - /* Add this client to linked list. */ - listnode_add(zebrad.client_list, client); - - /* Make new read thread. */ - zebra_event(ZEBRA_READ, sock, client); - - zebra_vrf_update_all(client); -} - -static int zread_interface_set_master(struct zserv *client, u_short length) +static void zread_interface_set_master(ZAPI_HANDLER_ARGS) { struct interface *master; struct interface *slave; - struct stream *s = client->ibuf; + struct stream *s = msg; int ifindex; vrf_id_t vrf_id; @@ -2549,16 +2357,16 @@ static int zread_interface_set_master(struct zserv *client, u_short length) slave = if_lookup_by_index(ifindex, vrf_id); if (!master || !slave) - return 0; + return; kernel_interface_set_master(master, slave); stream_failure: - return 1; + return; } -static void zread_vrf_label(struct zserv *client, struct zebra_vrf *zvrf) +static void zread_vrf_label(ZAPI_HANDLER_ARGS) { struct interface *ifp; mpls_label_t nlabel; @@ -2567,7 +2375,7 @@ static void zread_vrf_label(struct zserv *client, struct zebra_vrf *zvrf) struct zebra_vrf *def_zvrf; enum lsp_types_t ltype; - s = client->ibuf; + s = msg; STREAM_GETL(s, nlabel); STREAM_GETC(s, afi); if (nlabel == zvrf->label[afi]) { @@ -2626,15 +2434,14 @@ stream_failure: return; } -static inline void zread_rule(uint16_t command, struct zserv *client, - uint16_t length, struct zebra_vrf *zvrf) +static inline void zread_rule(ZAPI_HANDLER_ARGS) { struct zebra_pbr_rule zpr; struct stream *s; uint32_t total, i; ifindex_t ifindex; - s = client->ibuf; + s = msg; STREAM_GETL(s, total); for (i = 0; i < total; i++) { @@ -2675,7 +2482,7 @@ static inline void zread_rule(uint16_t command, struct zserv *client, if (zpr.filter.dst_port) zpr.filter.filter_bm |= PBR_FILTER_DST_PORT; - if (command == ZEBRA_RULE_ADD) + if (hdr->command == ZEBRA_RULE_ADD) zebra_pbr_add_rule(zvrf->zns, &zpr); else zebra_pbr_del_rule(zvrf->zns, &zpr); @@ -2685,158 +2492,314 @@ stream_failure: return; } -static inline void zserv_handle_commands(struct zserv *client, uint16_t command, - uint16_t length, +void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = { + [ZEBRA_ROUTER_ID_ADD] = zread_router_id_add, + [ZEBRA_ROUTER_ID_DELETE] = zread_router_id_delete, + [ZEBRA_INTERFACE_ADD] = zread_interface_add, + [ZEBRA_INTERFACE_DELETE] = zread_interface_delete, + [ZEBRA_ROUTE_ADD] = zread_route_add, + [ZEBRA_ROUTE_DELETE] = zread_route_del, + [ZEBRA_IPV4_ROUTE_ADD] = zread_ipv4_add, + [ZEBRA_IPV4_ROUTE_DELETE] = zread_ipv4_delete, + [ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD] = zread_ipv4_route_ipv6_nexthop_add, + [ZEBRA_IPV6_ROUTE_ADD] = zread_ipv6_add, + [ZEBRA_IPV6_ROUTE_DELETE] = zread_ipv6_delete, + [ZEBRA_REDISTRIBUTE_ADD] = zebra_redistribute_add, + [ZEBRA_REDISTRIBUTE_DELETE] = zebra_redistribute_delete, + [ZEBRA_REDISTRIBUTE_DEFAULT_ADD] = zebra_redistribute_default_add, + [ZEBRA_REDISTRIBUTE_DEFAULT_DELETE] = zebra_redistribute_default_delete, + [ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB] = zread_ipv4_nexthop_lookup_mrib, + [ZEBRA_HELLO] = zread_hello, + [ZEBRA_NEXTHOP_REGISTER] = zread_rnh_register, + [ZEBRA_NEXTHOP_UNREGISTER] = zread_rnh_unregister, + [ZEBRA_IMPORT_ROUTE_REGISTER] = zread_rnh_register, + [ZEBRA_IMPORT_ROUTE_UNREGISTER] = zread_rnh_unregister, + [ZEBRA_BFD_DEST_UPDATE] = zebra_ptm_bfd_dst_register, + [ZEBRA_BFD_DEST_REGISTER] = zebra_ptm_bfd_dst_register, + [ZEBRA_BFD_DEST_DEREGISTER] = zebra_ptm_bfd_dst_deregister, + [ZEBRA_VRF_UNREGISTER] = zread_vrf_unregister, + [ZEBRA_VRF_LABEL] = zread_vrf_label, + [ZEBRA_BFD_CLIENT_REGISTER] = zebra_ptm_bfd_client_register, +#if defined(HAVE_RTADV) + [ZEBRA_INTERFACE_ENABLE_RADV] = zebra_interface_radv_enable, + [ZEBRA_INTERFACE_DISABLE_RADV] = zebra_interface_radv_disable, +#else + [ZEBRA_INTERFACE_ENABLE_RADV] = NULL, + [ZEBRA_INTERFACE_DISABLE_RADV] = NULL, +#endif + [ZEBRA_MPLS_LABELS_ADD] = zread_mpls_labels, + [ZEBRA_MPLS_LABELS_DELETE] = zread_mpls_labels, + [ZEBRA_IPMR_ROUTE_STATS] = zebra_ipmr_route_stats, + [ZEBRA_LABEL_MANAGER_CONNECT] = zread_label_manager_request, + [ZEBRA_GET_LABEL_CHUNK] = zread_label_manager_request, + [ZEBRA_RELEASE_LABEL_CHUNK] = zread_label_manager_request, + [ZEBRA_FEC_REGISTER] = zread_fec_register, + [ZEBRA_FEC_UNREGISTER] = zread_fec_unregister, + [ZEBRA_ADVERTISE_DEFAULT_GW] = zebra_vxlan_advertise_gw_macip, + [ZEBRA_ADVERTISE_SUBNET] = zebra_vxlan_advertise_subnet, + [ZEBRA_ADVERTISE_ALL_VNI] = zebra_vxlan_advertise_all_vni, + [ZEBRA_REMOTE_VTEP_ADD] = zebra_vxlan_remote_vtep_add, + [ZEBRA_REMOTE_VTEP_DEL] = zebra_vxlan_remote_vtep_del, + [ZEBRA_REMOTE_MACIP_ADD] = zebra_vxlan_remote_macip_add, + [ZEBRA_REMOTE_MACIP_DEL] = zebra_vxlan_remote_macip_del, + [ZEBRA_INTERFACE_SET_MASTER] = zread_interface_set_master, + [ZEBRA_PW_ADD] = zread_pseudowire, + [ZEBRA_PW_DELETE] = zread_pseudowire, + [ZEBRA_PW_SET] = zread_pseudowire, + [ZEBRA_PW_UNSET] = zread_pseudowire, + [ZEBRA_RULE_ADD] = zread_rule, + [ZEBRA_RULE_DELETE] = zread_rule, +}; + +static inline void zserv_handle_commands(struct zserv *client, + struct zmsghdr *hdr, + struct stream *msg, struct zebra_vrf *zvrf) { - switch (command) { - case ZEBRA_ROUTER_ID_ADD: - zread_router_id_add(client, length, zvrf); + if (hdr->command > sizeof(zserv_handlers) + || zserv_handlers[hdr->command] == NULL) + zlog_info("Zebra received unknown command %d", hdr->command); + else + zserv_handlers[hdr->command](client, hdr, msg, zvrf); + + stream_free(msg); +} + +/* Lifecycle ---------------------------------------------------------------- */ + +/* free zebra client information. */ +static void zebra_client_free(struct zserv *client) +{ + /* Send client de-registration to BFD */ + zebra_ptm_bfd_client_deregister(client->proto); + + /* Cleanup any registered nexthops - across all VRFs. */ + zebra_client_close_cleanup_rnh(client); + + /* Release Label Manager chunks */ + release_daemon_chunks(client->proto, client->instance); + + /* Cleanup any FECs registered by this client. */ + zebra_mpls_cleanup_fecs_for_client(vrf_info_lookup(VRF_DEFAULT), + client); + + /* Remove pseudowires associated with this client */ + zebra_pw_client_close(client); + + /* Close file descriptor. */ + if (client->sock) { + unsigned long nroutes; + + close(client->sock); + nroutes = rib_score_proto(client->proto, client->instance); + zlog_notice( + "client %d disconnected. %lu %s routes removed from the rib", + client->sock, nroutes, + zebra_route_string(client->proto)); + client->sock = -1; + } + + /* Free stream buffers. */ + if (client->ibuf_work) + stream_free(client->ibuf_work); + if (client->obuf_work) + stream_free(client->obuf_work); + if (client->ibuf_fifo) + stream_fifo_free(client->ibuf_fifo); + if (client->obuf_fifo) + stream_fifo_free(client->obuf_fifo); + if (client->wb) + buffer_free(client->wb); + + /* Release threads. */ + if (client->t_read) + thread_cancel(client->t_read); + if (client->t_write) + thread_cancel(client->t_write); + if (client->t_suicide) + thread_cancel(client->t_suicide); + + /* Free bitmaps. */ + for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) + for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) + vrf_bitmap_free(client->redist[afi][i]); + + vrf_bitmap_free(client->redist_default); + vrf_bitmap_free(client->ifinfo); + vrf_bitmap_free(client->ridinfo); + + XFREE(MTYPE_TMP, client); +} + +/* + * Called from client thread to terminate itself. + */ +static void zebra_client_close(struct zserv *client) +{ + listnode_delete(zebrad.client_list, client); + zebra_client_free(client); +} + +/* Make new client. */ +static void zebra_client_create(int sock) +{ + struct zserv *client; + int i; + afi_t afi; + + client = XCALLOC(MTYPE_TMP, sizeof(struct zserv)); + + /* Make client input/output buffer. */ + client->sock = sock; + client->ibuf_fifo = stream_fifo_new(); + client->obuf_fifo = stream_fifo_new(); + client->ibuf_work = stream_new(ZEBRA_MAX_PACKET_SIZ); + client->obuf_work = stream_new(ZEBRA_MAX_PACKET_SIZ); + client->wb = buffer_new(0); + + /* Set table number. */ + client->rtm_table = zebrad.rtm_table_default; + + client->connect_time = monotime(NULL); + /* Initialize flags */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + client->redist[afi][i] = vrf_bitmap_init(); + client->redist_default = vrf_bitmap_init(); + client->ifinfo = vrf_bitmap_init(); + client->ridinfo = vrf_bitmap_init(); + + /* by default, it's not a synchronous client */ + client->is_synchronous = 0; + + /* Add this client to linked list. */ + listnode_add(zebrad.client_list, client); + + zebra_vrf_update_all(client); + + /* start read loop */ + zebra_event(client, ZEBRA_READ); +} + +static int zserv_delayed_close(struct thread *thread) +{ + struct zserv *client = THREAD_ARG(thread); + + client->t_suicide = NULL; + zebra_client_close(client); + return 0; +} + +/* + * Log zapi message to zlog. + * + * errmsg (optional) + * Debugging message + * + * msg + * The message + * + * hdr (optional) + * The message header + */ +static void zserv_log_message(const char *errmsg, struct stream *msg, + struct zmsghdr *hdr) +{ + zlog_debug("Rx'd ZAPI message"); + if (errmsg) + zlog_debug("%s", errmsg); + if (hdr) { + zlog_debug(" Length: %d", hdr->length); + zlog_debug("Command: %s", zserv_command_string(hdr->command)); + zlog_debug(" VRF: %u", hdr->vrf_id); + } + zlog_hexdump(msg->data, STREAM_READABLE(msg)); +} + +static int zserv_flush_data(struct thread *thread) +{ + struct zserv *client = THREAD_ARG(thread); + + client->t_write = NULL; + if (client->t_suicide) { + zebra_client_close(client); + return -1; + } + switch (buffer_flush_available(client->wb, client->sock)) { + case BUFFER_ERROR: + zlog_warn( + "%s: buffer_flush_available failed on zserv client fd %d, closing", + __func__, client->sock); + zebra_client_close(client); + client = NULL; break; - case ZEBRA_ROUTER_ID_DELETE: - zread_router_id_delete(client, length, zvrf); + case BUFFER_PENDING: + client->t_write = NULL; + thread_add_write(zebrad.master, zserv_flush_data, client, + client->sock, &client->t_write); break; - case ZEBRA_INTERFACE_ADD: - zread_interface_add(client, length, zvrf); - break; - case ZEBRA_INTERFACE_DELETE: - zread_interface_delete(client, length, zvrf); - break; - case ZEBRA_ROUTE_ADD: - zread_route_add(client, length, zvrf); - break; - case ZEBRA_ROUTE_DELETE: - zread_route_del(client, length, zvrf); - break; - case ZEBRA_IPV4_ROUTE_ADD: - zread_ipv4_add(client, length, zvrf); - break; - case ZEBRA_IPV4_ROUTE_DELETE: - zread_ipv4_delete(client, length, zvrf); - break; - case ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD: - zread_ipv4_route_ipv6_nexthop_add(client, length, zvrf); - break; - case ZEBRA_IPV6_ROUTE_ADD: - zread_ipv6_add(client, length, zvrf); - break; - case ZEBRA_IPV6_ROUTE_DELETE: - zread_ipv6_delete(client, length, zvrf); - break; - case ZEBRA_REDISTRIBUTE_ADD: - zebra_redistribute_add(command, client, length, zvrf); - break; - case ZEBRA_REDISTRIBUTE_DELETE: - zebra_redistribute_delete(command, client, length, zvrf); - break; - case ZEBRA_REDISTRIBUTE_DEFAULT_ADD: - zebra_redistribute_default_add(command, client, length, zvrf); - break; - case ZEBRA_REDISTRIBUTE_DEFAULT_DELETE: - zebra_redistribute_default_delete(command, client, length, - zvrf); - break; - case ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB: - zread_ipv4_nexthop_lookup_mrib(client, length, zvrf); - break; - case ZEBRA_HELLO: - zread_hello(client); - break; - case ZEBRA_NEXTHOP_REGISTER: - zserv_rnh_register(client, length, RNH_NEXTHOP_TYPE, zvrf); - break; - case ZEBRA_NEXTHOP_UNREGISTER: - zserv_rnh_unregister(client, length, RNH_NEXTHOP_TYPE, zvrf); - break; - case ZEBRA_IMPORT_ROUTE_REGISTER: - zserv_rnh_register(client, length, RNH_IMPORT_CHECK_TYPE, zvrf); - break; - case ZEBRA_IMPORT_ROUTE_UNREGISTER: - zserv_rnh_unregister(client, length, RNH_IMPORT_CHECK_TYPE, - zvrf); - break; - case ZEBRA_BFD_DEST_UPDATE: - case ZEBRA_BFD_DEST_REGISTER: - zebra_ptm_bfd_dst_register(client, length, command, zvrf); - break; - case ZEBRA_BFD_DEST_DEREGISTER: - zebra_ptm_bfd_dst_deregister(client, length, zvrf); - break; - case ZEBRA_VRF_UNREGISTER: - zread_vrf_unregister(client, length, zvrf); - break; - case ZEBRA_VRF_LABEL: - zread_vrf_label(client, zvrf); - break; - case ZEBRA_BFD_CLIENT_REGISTER: - zebra_ptm_bfd_client_register(client, length); - break; - case ZEBRA_INTERFACE_ENABLE_RADV: -#if defined(HAVE_RTADV) - zebra_interface_radv_set(client, length, zvrf, 1); -#endif - break; - case ZEBRA_INTERFACE_DISABLE_RADV: -#if defined(HAVE_RTADV) - zebra_interface_radv_set(client, length, zvrf, 0); -#endif - break; - case ZEBRA_MPLS_LABELS_ADD: - case ZEBRA_MPLS_LABELS_DELETE: - zread_mpls_labels(command, client, length, zvrf); - break; - case ZEBRA_IPMR_ROUTE_STATS: - zebra_ipmr_route_stats(client, length, zvrf); - break; - case ZEBRA_LABEL_MANAGER_CONNECT: - case ZEBRA_GET_LABEL_CHUNK: - case ZEBRA_RELEASE_LABEL_CHUNK: - zread_label_manager_request(command, client, zvrf); - break; - case ZEBRA_FEC_REGISTER: - zserv_fec_register(client, length); - break; - case ZEBRA_FEC_UNREGISTER: - zserv_fec_unregister(client, length); - break; - case ZEBRA_ADVERTISE_DEFAULT_GW: - zebra_vxlan_advertise_gw_macip(client, length, zvrf); - break; - case ZEBRA_ADVERTISE_SUBNET: - zebra_vxlan_advertise_subnet(client, length, zvrf); - break; - case ZEBRA_ADVERTISE_ALL_VNI: - zebra_vxlan_advertise_all_vni(client, length, zvrf); - break; - case ZEBRA_REMOTE_VTEP_ADD: - zebra_vxlan_remote_vtep_add(client, length, zvrf); - break; - case ZEBRA_REMOTE_VTEP_DEL: - zebra_vxlan_remote_vtep_del(client, length, zvrf); - break; - case ZEBRA_REMOTE_MACIP_ADD: - zebra_vxlan_remote_macip_add(client, length, zvrf); - break; - case ZEBRA_REMOTE_MACIP_DEL: - zebra_vxlan_remote_macip_del(client, length, zvrf); - break; - case ZEBRA_INTERFACE_SET_MASTER: - zread_interface_set_master(client, length); - break; - case ZEBRA_PW_ADD: - case ZEBRA_PW_DELETE: - case ZEBRA_PW_SET: - case ZEBRA_PW_UNSET: - zread_pseudowire(command, client, length, zvrf); - break; - case ZEBRA_RULE_ADD: - case ZEBRA_RULE_DELETE: - zread_rule(command, client, length, zvrf); - break; - default: - zlog_info("Zebra received unknown command %d", command); + case BUFFER_EMPTY: break; } + + if (client) + client->last_write_time = monotime(NULL); + return 0; +} + +/* + * Write a single packet. + */ +static int zserv_write(struct thread *thread) +{ + struct zserv *client = THREAD_ARG(thread); + struct stream *msg; + int writerv; + + if (client->t_suicide) + return -1; + + if (client->is_synchronous) + return 0; + + msg = stream_fifo_pop(client->obuf_fifo); + stream_set_getp(msg, 0); + client->last_write_cmd = stream_getw_from(msg, 6); + + writerv = buffer_write(client->wb, client->sock, STREAM_DATA(msg), + stream_get_endp(msg)); + + stream_free(msg); + + switch (writerv) { + case BUFFER_ERROR: + zlog_warn( + "%s: buffer_write failed to zserv client fd %d, closing", + __func__, client->sock); + /* + * Schedule a delayed close since many of the functions that + * call this one do not check the return code. They do not + * allow for the possibility that an I/O error may have caused + * the client to be deleted. + */ + client->t_suicide = NULL; + thread_add_event(zebrad.master, zserv_delayed_close, client, 0, + &client->t_suicide); + return -1; + case BUFFER_EMPTY: + THREAD_OFF(client->t_write); + break; + case BUFFER_PENDING: + thread_add_write(zebrad.master, zserv_flush_data, client, + client->sock, &client->t_write); + break; + } + + if (client->obuf_fifo->count) + zebra_event(client, ZEBRA_WRITE); + + client->last_write_time = monotime(NULL); + return 0; } #if defined(HANDLE_ZAPI_FUZZING) @@ -2859,26 +2822,61 @@ static void zserv_write_incoming(struct stream *orig, uint16_t command) } #endif +static int zserv_process_messages(struct thread *thread) +{ + struct zserv *client = THREAD_ARG(thread); + struct zebra_vrf *zvrf; + struct zmsghdr hdr; + struct stream *msg; + bool hdrvalid; + + do { + msg = stream_fifo_pop(client->ibuf_fifo); + + /* break if out of messages */ + if (!msg) + continue; + + /* read & check header */ + hdrvalid = zapi_parse_header(msg, &hdr); + if (!hdrvalid && IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) { + const char *emsg = "Message has corrupt header"; + zserv_log_message(emsg, msg, NULL); + } + if (!hdrvalid) + continue; + + /* lookup vrf */ + zvrf = zebra_vrf_lookup_by_id(hdr.vrf_id); + if (!zvrf && IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) { + const char *emsg = "Message specifies unknown VRF"; + zserv_log_message(emsg, msg, &hdr); + } + if (!zvrf) + continue; + + /* process commands */ + zserv_handle_commands(client, &hdr, msg, zvrf); + + } while (msg); + + return 0; +} + /* Handler of zebra service request. */ -static int zebra_client_read(struct thread *thread) +static int zserv_read(struct thread *thread) { int sock; struct zserv *client; size_t already; - uint16_t length, command; - uint8_t marker, version; - vrf_id_t vrf_id; - struct zebra_vrf *zvrf; #if defined(HANDLE_ZAPI_FUZZING) int packets = 1; #else int packets = zebrad.packets_to_process; #endif - /* Get thread data. Reset reading thread because I'm running. */ sock = THREAD_FD(thread); client = THREAD_ARG(thread); - client->t_read = NULL; if (client->t_suicide) { zebra_client_close(client); @@ -2886,88 +2884,89 @@ static int zebra_client_read(struct thread *thread) } while (packets) { + struct zmsghdr hdr; + ssize_t nb; + bool hdrvalid; + char errmsg[256]; + + already = stream_get_endp(client->ibuf_work); + /* Read length and command (if we don't have it already). */ - if ((already = stream_get_endp(client->ibuf)) - < ZEBRA_HEADER_SIZE) { - ssize_t nbyte; - if (((nbyte = stream_read_try(client->ibuf, sock, - ZEBRA_HEADER_SIZE - - already)) - == 0) - || (nbyte == -1)) { - if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug( - "connection closed socket [%d]", - sock); - zebra_client_close(client); - return -1; - } - if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE - already)) { + if (already < ZEBRA_HEADER_SIZE) { + nb = stream_read_try(client->ibuf_work, sock, + ZEBRA_HEADER_SIZE - already); + if ((nb == 0 || nb == -1) && IS_ZEBRA_DEBUG_EVENT) + zlog_debug("connection closed socket [%d]", + sock); + if ((nb == 0 || nb == -1)) + goto zread_fail; + if (nb != (ssize_t)(ZEBRA_HEADER_SIZE - already)) { /* Try again later. */ - zebra_event(ZEBRA_READ, sock, client); - return 0; + break; } already = ZEBRA_HEADER_SIZE; } /* Reset to read from the beginning of the incoming packet. */ - stream_set_getp(client->ibuf, 0); + stream_set_getp(client->ibuf_work, 0); /* Fetch header values */ - STREAM_GETW(client->ibuf, length); - STREAM_GETC(client->ibuf, marker); - STREAM_GETC(client->ibuf, version); - STREAM_GETL(client->ibuf, vrf_id); - STREAM_GETW(client->ibuf, command); + hdrvalid = zapi_parse_header(client->ibuf_work, &hdr); - if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) { - zlog_err( - "%s: socket %d version mismatch, marker %d, version %d", - __func__, sock, marker, version); - zebra_client_close(client); - return -1; + if (!hdrvalid) { + snprintf(errmsg, sizeof(errmsg), + "%s: Message has corrupt header", __func__); + zserv_log_message(errmsg, client->ibuf_work, NULL); + goto zread_fail; } - if (length < ZEBRA_HEADER_SIZE) { - zlog_warn( - "%s: socket %d message length %u is less than header size %d", - __func__, sock, length, ZEBRA_HEADER_SIZE); - zebra_client_close(client); - return -1; + + /* Validate header */ + if (hdr.marker != ZEBRA_HEADER_MARKER + || hdr.version != ZSERV_VERSION) { + snprintf( + errmsg, sizeof(errmsg), + "Message has corrupt header\n%s: socket %d version mismatch, marker %d, version %d", + __func__, sock, hdr.marker, hdr.version); + zserv_log_message(errmsg, client->ibuf_work, &hdr); + goto zread_fail; } - if (length > STREAM_SIZE(client->ibuf)) { - zlog_warn( - "%s: socket %d message length %u exceeds buffer size %lu", - __func__, sock, length, - (u_long)STREAM_SIZE(client->ibuf)); - zebra_client_close(client); - return -1; + if (hdr.length < ZEBRA_HEADER_SIZE) { + snprintf( + errmsg, sizeof(errmsg), + "Message has corrupt header\n%s: socket %d message length %u is less than header size %d", + __func__, sock, hdr.length, ZEBRA_HEADER_SIZE); + zserv_log_message(errmsg, client->ibuf_work, &hdr); + goto zread_fail; + } + if (hdr.length > STREAM_SIZE(client->ibuf_work)) { + snprintf( + errmsg, sizeof(errmsg), + "Message has corrupt header\n%s: socket %d message length %u exceeds buffer size %lu", + __func__, sock, hdr.length, + (unsigned long)STREAM_SIZE(client->ibuf_work)); + goto zread_fail; } /* Read rest of data. */ - if (already < length) { - ssize_t nbyte; - if (((nbyte = stream_read_try(client->ibuf, sock, - length - already)) - == 0) - || (nbyte == -1)) { - if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug( - "connection closed [%d] when reading zebra data", - sock); - zebra_client_close(client); - return -1; - } - if (nbyte != (ssize_t)(length - already)) { + if (already < hdr.length) { + nb = stream_read_try(client->ibuf_work, sock, + hdr.length - already); + if ((nb == 0 || nb == -1) && IS_ZEBRA_DEBUG_EVENT) + zlog_debug( + "connection closed [%d] when reading zebra data", + sock); + if ((nb == 0 || nb == -1)) + goto zread_fail; + if (nb != (ssize_t)(hdr.length - already)) { /* Try again later. */ - zebra_event(ZEBRA_READ, sock, client); - return 0; + break; } } #if defined(HANDLE_ZAPI_FUZZING) - zserv_write_incoming(client->ibuf, command); + zserv_write_incoming(client->ibuf_work, command); #endif - length -= ZEBRA_HEADER_SIZE; + hdr.length -= ZEBRA_HEADER_SIZE; /* Debug packet information. */ if (IS_ZEBRA_DEBUG_EVENT) @@ -2975,41 +2974,54 @@ static int zebra_client_read(struct thread *thread) sock); if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) - zlog_debug("zebra message received [%s] %d in VRF %u", - zserv_command_string(command), length, - vrf_id); + zserv_log_message(NULL, client->ibuf_work, &hdr); client->last_read_time = monotime(NULL); - client->last_read_cmd = command; + client->last_read_cmd = hdr.command; - zvrf = zebra_vrf_lookup_by_id(vrf_id); - if (!zvrf) { - if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) - zlog_debug("zebra received unknown VRF[%u]", - vrf_id); - goto zclient_read_out; - } + stream_set_getp(client->ibuf_work, 0); + struct stream *msg = stream_dup(client->ibuf_work); - zserv_handle_commands(client, command, length, zvrf); + stream_fifo_push(client->ibuf_fifo, msg); - if (client->t_suicide) { - /* No need to wait for thread callback, just kill - * immediately. - */ - zebra_client_close(client); - return -1; - } - packets -= 1; - stream_reset(client->ibuf); + if (client->t_suicide) + goto zread_fail; + + --packets; + stream_reset(client->ibuf_work); } -stream_failure: -zclient_read_out: - stream_reset(client->ibuf); - zebra_event(ZEBRA_READ, sock, client); + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("Read %d packets", + zebrad.packets_to_process - packets); + + /* Schedule job to process those packets */ + thread_add_event(zebrad.master, &zserv_process_messages, client, 0, + NULL); + + /* Reschedule ourselves */ + zebra_event(client, ZEBRA_READ); + return 0; + +zread_fail: + zebra_client_close(client); + return -1; } +static void zebra_event(struct zserv *client, enum event event) +{ + switch (event) { + case ZEBRA_READ: + thread_add_read(zebrad.master, zserv_read, client, client->sock, + &client->t_read); + break; + case ZEBRA_WRITE: + thread_add_write(zebrad.master, zserv_write, client, + client->sock, &client->t_write); + break; + } +} /* Accept code of zebra server socket. */ static int zebra_accept(struct thread *thread) @@ -3022,7 +3034,7 @@ static int zebra_accept(struct thread *thread) accept_sock = THREAD_FD(thread); /* Reregister myself. */ - zebra_event(ZEBRA_SERV, accept_sock, NULL); + thread_add_read(zebrad.master, zebra_accept, NULL, accept_sock, NULL); len = sizeof(struct sockaddr_in); client_sock = accept(accept_sock, (struct sockaddr *)&client, &len); @@ -3109,26 +3121,7 @@ void zebra_zserv_socket_init(char *path) umask(old_mask); - zebra_event(ZEBRA_SERV, sock, NULL); -} - - -static void zebra_event(enum event event, int sock, struct zserv *client) -{ - switch (event) { - case ZEBRA_SERV: - thread_add_read(zebrad.master, zebra_accept, client, sock, - NULL); - break; - case ZEBRA_READ: - client->t_read = NULL; - thread_add_read(zebrad.master, zebra_client_read, client, sock, - &client->t_read); - break; - case ZEBRA_WRITE: - /**/ - break; - } + thread_add_read(zebrad.master, zebra_accept, NULL, sock, NULL); } #define ZEBRA_TIME_BUF 32 diff --git a/zebra/zserv.h b/zebra/zserv.h index 8519693726..62707510c2 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -47,8 +47,12 @@ struct zserv { int sock; /* Input/output buffer to the client. */ - struct stream *ibuf; - struct stream *obuf; + struct stream_fifo *ibuf_fifo; + struct stream_fifo *obuf_fifo; + + /* Private I/O buffers */ + struct stream *ibuf_work; + struct stream *obuf_work; /* Buffer of data waiting to be written to client. */ struct buffer *wb; @@ -129,6 +133,10 @@ struct zserv { int last_write_cmd; }; +#define ZAPI_HANDLER_ARGS \ + struct zserv *client, struct zmsghdr *hdr, struct stream *msg, \ + struct zebra_vrf *zvrf + /* Zebra instance */ struct zebra_t { /* Thread master */ @@ -185,7 +193,7 @@ extern void zsend_rule_notify_owner(struct zebra_pbr_rule *rule, extern void zserv_nexthop_num_warn(const char *, const struct prefix *, const unsigned int); -extern int zebra_server_send_message(struct zserv *client); +extern int zebra_server_send_message(struct zserv *client, struct stream *msg); extern struct zserv *zebra_find_client(u_char proto, u_short instance);