diff options
Diffstat (limited to 'bgpd/bgp_zebra.c')
| -rw-r--r-- | bgpd/bgp_zebra.c | 1230 |
1 files changed, 745 insertions, 485 deletions
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 96b1f3e00f..dbba1dc71a 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* zebra client * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + * Copyright (c) 2023 LabN Consulting, L.L.C. */ #include <zebra.h> @@ -23,6 +24,7 @@ #include "mpls.h" #include "vxlan.h" #include "pbr.h" +#include "frrdistance.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" @@ -55,6 +57,8 @@ /* All information about zebra. */ struct zclient *zclient = NULL; +struct zclient *zclient_sync; +static bool bgp_zebra_label_manager_connect(void); /* hook to indicate vrf status change for SNMP */ DEFINE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp), @@ -69,9 +73,10 @@ static inline bool bgp_install_info_to_zebra(struct bgp *bgp) return false; if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) { - zlog_debug( - "%s: No zebra instance to talk to, not installing information", - __func__); + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug( + "%s: No zebra instance to talk to, not installing information", + __func__); return false; } @@ -95,13 +100,6 @@ static int bgp_router_id_update(ZAPI_CALLBACK_ARGS) return 0; } -/* Nexthop update message from zebra. */ -static int bgp_read_nexthop_update(ZAPI_CALLBACK_ARGS) -{ - bgp_parse_nexthop_update(cmd, vrf_id); - return 0; -} - /* Set or clear interface on which unnumbered neighbor is configured. This * would in turn cause BGP to initiate or turn off IPv6 RAs on this * interface. @@ -137,18 +135,17 @@ static void bgp_start_interface_nbrs(struct bgp *bgp, struct interface *ifp) struct peer *peer; for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (peer->conf_if && (strcmp(peer->conf_if, ifp->name) == 0) - && !peer_established(peer)) { + if (peer->conf_if && (strcmp(peer->conf_if, ifp->name) == 0) && + !peer_established(peer->connection)) { if (peer_active(peer)) - BGP_EVENT_ADD(peer, BGP_Stop); - BGP_EVENT_ADD(peer, BGP_Start); + BGP_EVENT_ADD(peer->connection, BGP_Stop); + BGP_EVENT_ADD(peer->connection, BGP_Start); } } } static void bgp_nbr_connected_add(struct bgp *bgp, struct nbr_connected *ifc) { - struct listnode *node; struct connected *connected; struct interface *ifp; struct prefix *p; @@ -157,7 +154,7 @@ static void bgp_nbr_connected_add(struct bgp *bgp, struct nbr_connected *ifc) * valid local address on the interface. */ ifp = ifc->ifp; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { + frr_each (if_connected, ifp->connected, connected) { p = connected->address; if (p->family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) @@ -180,7 +177,7 @@ static void bgp_nbr_connected_delete(struct bgp *bgp, struct nbr_connected *ifc, if (peer->conf_if && (strcmp(peer->conf_if, ifc->ifp->name) == 0)) { peer->last_reset = PEER_DOWN_NBR_ADDR_DEL; - BGP_EVENT_ADD(peer, BGP_Stop); + BGP_EVENT_ADD(peer->connection, BGP_Stop); } } /* Free neighbor also, if we're asked to. */ @@ -229,7 +226,7 @@ static int bgp_ifp_up(struct interface *ifp) if (!bgp) return 0; - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, c)) + frr_each (if_connected, ifp->connected, c) bgp_connected_add(bgp, c); for (ALL_LIST_ELEMENTS(ifp->nbr_connected, node, nnode, nc)) @@ -238,6 +235,14 @@ static int bgp_ifp_up(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_up(ifp); + if (bgp_get_default() && if_is_loopback(ifp)) { + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } @@ -260,7 +265,7 @@ static int bgp_ifp_down(struct interface *ifp) if (!bgp) return 0; - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, c)) + frr_each (if_connected, ifp->connected, c) bgp_connected_delete(bgp, c); for (ALL_LIST_ELEMENTS(ifp->nbr_connected, node, nnode, nc)) @@ -276,7 +281,7 @@ static int bgp_ifp_down(struct interface *ifp) continue; if (ifp == peer->nexthop.ifp) { - BGP_EVENT_ADD(peer, BGP_Stop); + BGP_EVENT_ADD(peer->connection, BGP_Stop); peer->last_reset = PEER_DOWN_IF_DOWN; } } @@ -285,6 +290,14 @@ static int bgp_ifp_down(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_down(ifp); + if (bgp_get_default() && if_is_loopback(ifp)) { + vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } @@ -474,65 +487,6 @@ static int bgp_interface_nbr_address_delete(ZAPI_CALLBACK_ARGS) return 0; } -/* VRF update for an interface. */ -static int bgp_interface_vrf_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - vrf_id_t new_vrf_id; - struct connected *c; - struct nbr_connected *nc; - struct listnode *node, *nnode; - struct bgp *bgp; - struct peer *peer; - - ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, - &new_vrf_id); - if (!ifp) - return 0; - - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf VRF change VRF %u IF %s NewVRF %u", vrf_id, - ifp->name, new_vrf_id); - - bgp = bgp_lookup_by_vrf_id(vrf_id); - - if (bgp) { - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, c)) - bgp_connected_delete(bgp, c); - - for (ALL_LIST_ELEMENTS(ifp->nbr_connected, node, nnode, nc)) - bgp_nbr_connected_delete(bgp, nc, 1); - - /* Fast external-failover */ - if (!CHECK_FLAG(bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) { - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if ((peer->ttl != BGP_DEFAULT_TTL) - && (peer->gtsm_hops - != BGP_GTSM_HOPS_CONNECTED)) - continue; - - if (ifp == peer->nexthop.ifp) - BGP_EVENT_ADD(peer, BGP_Stop); - } - } - } - - if_update_to_new_vrf(ifp, new_vrf_id); - - bgp = bgp_lookup_by_vrf_id(new_vrf_id); - if (!bgp) - return 0; - - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, c)) - bgp_connected_add(bgp, c); - - for (ALL_LIST_ELEMENTS(ifp->nbr_connected, node, nnode, nc)) - bgp_nbr_connected_add(bgp, nc); - - hook_call(bgp_vrf_status_changed, bgp, ifp); - return 0; -} - /* Zebra route add and delete treatment. */ static int zebra_read_route(ZAPI_CALLBACK_ARGS) { @@ -620,7 +574,6 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS) struct interface *if_lookup_by_ipv4(struct in_addr *addr, vrf_id_t vrf_id) { struct vrf *vrf; - struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix_ipv4 p; @@ -635,7 +588,7 @@ struct interface *if_lookup_by_ipv4(struct in_addr *addr, vrf_id_t vrf_id) p.prefixlen = IPV4_MAX_BITLEN; FOR_ALL_INTERFACES (vrf, ifp) { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET) @@ -649,7 +602,6 @@ struct interface *if_lookup_by_ipv4(struct in_addr *addr, vrf_id_t vrf_id) struct interface *if_lookup_by_ipv4_exact(struct in_addr *addr, vrf_id_t vrf_id) { struct vrf *vrf; - struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix *cp; @@ -659,7 +611,7 @@ struct interface *if_lookup_by_ipv4_exact(struct in_addr *addr, vrf_id_t vrf_id) return NULL; FOR_ALL_INTERFACES (vrf, ifp) { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET) @@ -674,7 +626,6 @@ struct interface *if_lookup_by_ipv6(struct in6_addr *addr, ifindex_t ifindex, vrf_id_t vrf_id) { struct vrf *vrf; - struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix_ipv6 p; @@ -689,7 +640,7 @@ struct interface *if_lookup_by_ipv6(struct in6_addr *addr, ifindex_t ifindex, p.prefixlen = IPV6_MAX_BITLEN; FOR_ALL_INTERFACES (vrf, ifp) { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET6) @@ -710,7 +661,6 @@ struct interface *if_lookup_by_ipv6_exact(struct in6_addr *addr, ifindex_t ifindex, vrf_id_t vrf_id) { struct vrf *vrf; - struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix *cp; @@ -720,7 +670,7 @@ struct interface *if_lookup_by_ipv6_exact(struct in6_addr *addr, return NULL; FOR_ALL_INTERFACES (vrf, ifp) { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET6) @@ -739,11 +689,10 @@ struct interface *if_lookup_by_ipv6_exact(struct in6_addr *addr, static int if_get_ipv6_global(struct interface *ifp, struct in6_addr *addr) { - struct listnode *cnode; struct connected *connected; struct prefix *cp; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET6) @@ -757,11 +706,10 @@ static int if_get_ipv6_global(struct interface *ifp, struct in6_addr *addr) static bool if_get_ipv6_local(struct interface *ifp, struct in6_addr *addr) { - struct listnode *cnode; struct connected *connected; struct prefix *cp; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET6) @@ -775,11 +723,10 @@ static bool if_get_ipv6_local(struct interface *ifp, struct in6_addr *addr) static int if_get_ipv4_address(struct interface *ifp, struct in_addr *addr) { - struct listnode *cnode; struct connected *connected; struct prefix *cp; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if ((cp->family == AF_INET) && !ipv4_martian(&(cp->u.prefix4))) { @@ -996,7 +943,8 @@ bgp_path_info_to_ipv6_nexthop(struct bgp_path_info *path, ifindex_t *ifindex) || path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { /* Check if route-map is set to prefer global over link-local */ - if (path->attr->mp_nexthop_prefer_global) { + if (CHECK_FLAG(path->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) { nexthop = &path->attr->mp_nexthop_global; if (IN6_IS_ADDR_LINKLOCAL(nexthop)) *ifindex = path->attr->nh_ifindex; @@ -1073,14 +1021,17 @@ static void bgp_zebra_tm_connect(struct event *t) ret = tm_table_manager_connect(zclient); } if (ret < 0) { - zlog_info("Error connecting to table manager!"); + zlog_err("Error connecting to table manager!"); bgp_tm_status_connected = false; } else { - if (!bgp_tm_status_connected) - zlog_debug("Connecting to table manager. Success"); + if (!bgp_tm_status_connected) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug( + "Connecting to table manager. Success"); + } bgp_tm_status_connected = true; if (!bgp_tm_chunk_obtained) { - if (bgp_zebra_get_table_range(bgp_tm_chunk_size, + if (bgp_zebra_get_table_range(zclient, bgp_tm_chunk_size, &bgp_tm_min, &bgp_tm_max) >= 0) { bgp_tm_chunk_obtained = true; @@ -1120,18 +1071,18 @@ void bgp_zebra_init_tm_connect(struct bgp *bgp) bgp_tm_min = bgp_tm_max = 0; bgp_tm_chunk_size = BGP_FLOWSPEC_TABLE_CHUNK; bgp_tm_bgp = bgp; - event_add_timer(bm->master, bgp_zebra_tm_connect, zclient, delay, + event_add_timer(bm->master, bgp_zebra_tm_connect, zclient_sync, delay, &bgp_tm_thread_connect); } -int bgp_zebra_get_table_range(uint32_t chunk_size, +int bgp_zebra_get_table_range(struct zclient *zc, uint32_t chunk_size, uint32_t *start, uint32_t *end) { int ret; if (!bgp_tm_status_connected) return -1; - ret = tm_get_table_chunk(zclient, chunk_size, start, end); + ret = tm_get_table_chunk(zc, chunk_size, start, end); if (ret < 0) { flog_err(EC_BGP_TABLE_CHUNK, "BGP: Error getting table chunk %u", chunk_size); @@ -1260,145 +1211,61 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, } static bool bgp_zebra_use_nhop_weighted(struct bgp *bgp, struct attr *attr, - uint64_t tot_bw, uint32_t *nh_weight) + uint32_t *nh_weight) { - uint32_t bw; - uint64_t tmp; - - bw = attr->link_bw; /* zero link-bandwidth and link-bandwidth not present are treated * as the same situation. */ - if (!bw) { + if (!attr->link_bw) { /* the only situations should be if we're either told * to skip or use default weight. */ if (bgp->lb_handling == BGP_LINK_BW_SKIP_MISSING) return false; *nh_weight = BGP_ZEBRA_DEFAULT_NHOP_WEIGHT; - } else { - tmp = (uint64_t)bw * 100; - *nh_weight = ((uint32_t)(tmp / tot_bw)); - } + } else + *nh_weight = attr->link_bw; return true; } -void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, - struct bgp_path_info *info, struct bgp *bgp, afi_t afi, - safi_t safi) +static void bgp_zebra_announce_parse_nexthop( + struct bgp_path_info *info, const struct prefix *p, struct bgp *bgp, + struct zapi_route *api, unsigned int *valid_nh_count, afi_t afi, + safi_t safi, uint32_t *nhg_id, uint32_t *metric, route_tag_t *tag, + bool *allow_recursion) { - struct zapi_route api = { 0 }; struct zapi_nexthop *api_nh; int nh_family; - unsigned int valid_nh_count = 0; - bool allow_recursion = false; - uint8_t distance; - struct peer *peer; struct bgp_path_info *mpinfo; struct bgp *bgp_orig; - uint32_t metric; struct attr local_attr; struct bgp_path_info local_info; struct bgp_path_info *mpinfo_cp = &local_info; - route_tag_t tag; - struct bgp_sid_info *sid_info; mpls_label_t *labels; uint32_t num_labels = 0; mpls_label_t nh_label; int nh_othervrf = 0; bool nh_updated = false; bool do_wt_ecmp; - uint64_t cum_bw = 0; - uint32_t nhg_id = 0; - bool is_add; uint32_t ttl = 0; uint32_t bos = 0; uint32_t exp = 0; - /* - * BGP is installing this route and bgp has been configured - * to suppress announcements until the route has been installed - * let's set the fact that we expect this route to be installed - */ - if (BGP_SUPPRESS_FIB_ENABLED(bgp)) - SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); - - /* Don't try to install if we're not connected to Zebra or Zebra doesn't - * know of this instance. - */ - if (!bgp_install_info_to_zebra(bgp)) - return; - - if (bgp->main_zebra_update_hold) - return; - - if (safi == SAFI_FLOWSPEC) { - bgp_pbr_update_entry(bgp, bgp_dest_get_prefix(dest), info, afi, - safi, true); - return; - } + /* Determine if we're doing weighted ECMP or not */ + do_wt_ecmp = bgp_path_info_mpath_chkwtd(bgp, info); /* * vrf leaking support (will have only one nexthop) */ - if (info->extra && info->extra->bgp_orig) + if (info->extra && info->extra->vrfleak && + info->extra->vrfleak->bgp_orig) nh_othervrf = 1; - /* Make Zebra API structure. */ - api.vrf_id = bgp->vrf_id; - api.type = ZEBRA_ROUTE_BGP; - api.safi = safi; - api.prefix = *p; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - - peer = info->peer; - - if (info->type == ZEBRA_ROUTE_BGP - && info->sub_type == BGP_ROUTE_IMPORTED) { - - /* Obtain peer from parent */ - if (info->extra && info->extra->parent) - peer = ((struct bgp_path_info *)(info->extra->parent)) - ->peer; - } - - tag = info->attr->tag; - - if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED - || info->sub_type == BGP_ROUTE_AGGREGATE) { - SET_FLAG(api.flags, ZEBRA_FLAG_IBGP); - SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); - } - - if ((peer->sort == BGP_PEER_EBGP && peer->ttl != BGP_DEFAULT_TTL) - || CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) - || CHECK_FLAG(bgp->flags, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) - - allow_recursion = true; - - if (info->attr->rmap_table_id) { - SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID); - api.tableid = info->attr->rmap_table_id; - } - - if (CHECK_FLAG(info->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR))) - SET_FLAG(api.message, ZAPI_MESSAGE_SRTE); - - /* Metric is currently based on the best-path only */ - metric = info->attr->med; - - /* Determine if we're doing weighted ECMP or not */ - do_wt_ecmp = bgp_path_info_mpath_chkwtd(bgp, info); - if (do_wt_ecmp) - cum_bw = bgp_path_info_mpath_cumbw(info); - /* EVPN MAC-IP routes are installed with a L3 NHG id */ - if (bgp_evpn_path_es_use_nhg(bgp, info, &nhg_id)) { + if (nhg_id && bgp_evpn_path_es_use_nhg(bgp, info, nhg_id)) { mpinfo = NULL; - api.nhgid = nhg_id; - if (nhg_id) - SET_FLAG(api.message, ZAPI_MESSAGE_NHG); + zapi_route_set_nhg_id(api, nhg_id); } else { mpinfo = info; } @@ -1410,7 +1277,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, bool is_evpn; bool is_parent_evpn; - if (valid_nh_count >= multipath_num) + if (*valid_nh_count >= multipath_num) break; *mpinfo_cp = *mpinfo; @@ -1433,16 +1300,19 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, */ if (do_wt_ecmp) { if (!bgp_zebra_use_nhop_weighted(bgp, mpinfo->attr, - cum_bw, &nh_weight)) + &nh_weight)) continue; } - api_nh = &api.nexthops[valid_nh_count]; + if (CHECK_FLAG(info->flags, BGP_PATH_SELECTED)) + api_nh = &api->nexthops[*valid_nh_count]; + else + api_nh = &api->backup_nexthops[*valid_nh_count]; if (CHECK_FLAG(info->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR))) - api_nh->srte_color = info->attr->srte_color; + api_nh->srte_color = bgp_attr_get_color(info->attr); - if (bgp_debug_zebra(&api.prefix)) { + if (bgp_debug_zebra(&api->prefix)) { if (mpinfo->extra) { zlog_debug("%s: p=%pFX, bgp_is_valid_label: %d", __func__, p, @@ -1467,8 +1337,10 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, /* metric/tag is only allowed to be * overridden on 1st nexthop */ if (mpinfo == info) { - metric = mpinfo_cp->attr->med; - tag = mpinfo_cp->attr->tag; + if (metric) + *metric = mpinfo_cp->attr->med; + if (tag) + *tag = mpinfo_cp->attr->tag; } } @@ -1509,11 +1381,11 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, /* Allow recursion if it is a multipath group with both * eBGP and iBGP paths. */ - if (!allow_recursion - && CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX) - && (mpinfo->peer->sort == BGP_PEER_IBGP - || mpinfo->peer->sort == BGP_PEER_CONFED)) - allow_recursion = true; + if (allow_recursion && !*allow_recursion && + CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX) && + (mpinfo->peer->sort == BGP_PEER_IBGP || + mpinfo->peer->sort == BGP_PEER_CONFED)) + *allow_recursion = true; if (mpinfo->extra) { labels = mpinfo->extra->label; @@ -1547,36 +1419,178 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, api_nh->weight = nh_weight; - if (mpinfo->extra && !is_evpn && - bgp_is_valid_label(&labels[0]) && - !sid_zero(&mpinfo->extra->sid[0].sid)) { - sid_info = &mpinfo->extra->sid[0]; - - memcpy(&api_nh->seg6_segs, &sid_info->sid, - sizeof(api_nh->seg6_segs)); - - if (sid_info->transposition_len != 0) { + if (((mpinfo->attr->srv6_l3vpn && + !sid_zero_ipv6(&mpinfo->attr->srv6_l3vpn->sid)) || + (mpinfo->attr->srv6_vpn && + !sid_zero_ipv6(&mpinfo->attr->srv6_vpn->sid))) && + !is_evpn && bgp_is_valid_label(&labels[0])) { + struct in6_addr *sid_tmp = + mpinfo->attr->srv6_l3vpn + ? (&mpinfo->attr->srv6_l3vpn->sid) + : (&mpinfo->attr->srv6_vpn->sid); + + memcpy(&api_nh->seg6_segs[0], sid_tmp, + sizeof(api_nh->seg6_segs[0])); + + if (mpinfo->attr->srv6_l3vpn && + mpinfo->attr->srv6_l3vpn->transposition_len != 0) { mpls_lse_decode(labels[0], &nh_label, &ttl, &exp, &bos); if (nh_label < MPLS_LABEL_UNRESERVED_MIN) { - if (bgp_debug_zebra(&api.prefix)) + if (bgp_debug_zebra(&api->prefix)) zlog_debug( "skip invalid SRv6 routes: transposition scheme is used, but label is too small"); continue; } - transpose_sid(&api_nh->seg6_segs, nh_label, - sid_info->transposition_offset, - sid_info->transposition_len); + transpose_sid(&api_nh->seg6_segs[0], nh_label, + mpinfo->attr->srv6_l3vpn + ->transposition_offset, + mpinfo->attr->srv6_l3vpn + ->transposition_len); } + api_nh->seg_num = 1; SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6); } - valid_nh_count++; + (*valid_nh_count)++; + } +} + +static void bgp_debug_zebra_nh(struct zapi_route *api) +{ + int i; + int nh_family; + char nh_buf[INET6_ADDRSTRLEN]; + char eth_buf[ETHER_ADDR_STRLEN + 7] = { '\0' }; + char buf1[ETHER_ADDR_STRLEN]; + char label_buf[20]; + char sid_buf[20]; + char segs_buf[256]; + struct zapi_nexthop *api_nh; + int count; + + count = api->nexthop_num; + for (i = 0; i < count; i++) { + api_nh = &api->nexthops[i]; + switch (api_nh->type) { + case NEXTHOP_TYPE_IFINDEX: + nh_buf[0] = '\0'; + break; + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + nh_family = AF_INET; + inet_ntop(nh_family, &api_nh->gate, nh_buf, + sizeof(nh_buf)); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + nh_family = AF_INET6; + inet_ntop(nh_family, &api_nh->gate, nh_buf, + sizeof(nh_buf)); + break; + case NEXTHOP_TYPE_BLACKHOLE: + strlcpy(nh_buf, "blackhole", sizeof(nh_buf)); + break; + default: + /* Note: add new nexthop case */ + assert(0); + break; + } + + label_buf[0] = '\0'; + eth_buf[0] = '\0'; + segs_buf[0] = '\0'; + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL) && + !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) + snprintf(label_buf, sizeof(label_buf), "label %u", + api_nh->labels[0]); + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6) && + !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) { + inet_ntop(AF_INET6, &api_nh->seg6_segs[0], sid_buf, + sizeof(sid_buf)); + snprintf(segs_buf, sizeof(segs_buf), "segs %s", sid_buf); + } + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN) && + !is_zero_mac(&api_nh->rmac)) + snprintf(eth_buf, sizeof(eth_buf), " RMAC %s", + prefix_mac2str(&api_nh->rmac, buf1, + sizeof(buf1))); + zlog_debug(" nhop [%d]: %s if %u VRF %u wt %u %s %s %s", i + 1, + nh_buf, api_nh->ifindex, api_nh->vrf_id, + api_nh->weight, label_buf, segs_buf, eth_buf); + } +} + +static enum zclient_send_status +bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, + struct bgp *bgp) +{ + struct bgp_path_info *bpi_ultimate; + struct zapi_route api = { 0 }; + unsigned int valid_nh_count = 0; + bool allow_recursion = false; + uint8_t distance; + struct peer *peer; + uint32_t metric; + route_tag_t tag; + bool is_add; + uint32_t nhg_id = 0; + uint32_t recursion_flag = 0; + struct bgp_table *table = bgp_dest_table(dest); + const struct prefix *p = bgp_dest_get_prefix(dest); + + if (table->safi == SAFI_FLOWSPEC) { + bgp_pbr_update_entry(bgp, p, info, table->afi, table->safi, + true); + return ZCLIENT_SEND_SUCCESS; } + /* Make Zebra API structure. */ + api.vrf_id = bgp->vrf_id; + api.type = ZEBRA_ROUTE_BGP; + api.safi = table->safi; + api.prefix = *p; + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + + peer = info->peer; + + if (info->type == ZEBRA_ROUTE_BGP) { + bpi_ultimate = bgp_get_imported_bpi_ultimate(info); + peer = bpi_ultimate->peer; + } + + tag = info->attr->tag; + + if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED + || info->sub_type == BGP_ROUTE_AGGREGATE) { + SET_FLAG(api.flags, ZEBRA_FLAG_IBGP); + SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); + } + + if ((peer->sort == BGP_PEER_EBGP && peer->ttl != BGP_DEFAULT_TTL) + || CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) + || CHECK_FLAG(bgp->flags, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) + + allow_recursion = true; + + if (info->attr->rmap_table_id) { + SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID); + api.tableid = info->attr->rmap_table_id; + } + + if (CHECK_FLAG(info->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR))) + SET_FLAG(api.message, ZAPI_MESSAGE_SRTE); + + /* Metric is currently based on the best-path only */ + metric = info->attr->med; + + bgp_zebra_announce_parse_nexthop(info, p, bgp, &api, &valid_nh_count, + table->afi, table->safi, &nhg_id, + &metric, &tag, &allow_recursion); + is_add = (valid_nh_count || nhg_id) ? true : false; if (is_add && CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) { @@ -1628,82 +1642,19 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, api.tag = tag; } - distance = bgp_distance_apply(p, info, afi, safi, bgp); + distance = bgp_distance_apply(p, info, table->afi, table->safi, bgp); if (distance) { SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); api.distance = distance; } if (bgp_debug_zebra(p)) { - char nh_buf[INET6_ADDRSTRLEN]; - char eth_buf[ETHER_ADDR_STRLEN + 7] = {'\0'}; - char buf1[ETHER_ADDR_STRLEN]; - char label_buf[20]; - char sid_buf[20]; - char segs_buf[256]; - int i; - zlog_debug( "Tx route %s VRF %u %pFX metric %u tag %" ROUTE_TAG_PRI " count %d nhg %d", is_add ? "add" : "delete", bgp->vrf_id, &api.prefix, api.metric, api.tag, api.nexthop_num, nhg_id); - for (i = 0; i < api.nexthop_num; i++) { - api_nh = &api.nexthops[i]; - - switch (api_nh->type) { - case NEXTHOP_TYPE_IFINDEX: - nh_buf[0] = '\0'; - break; - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - nh_family = AF_INET; - inet_ntop(nh_family, &api_nh->gate, nh_buf, - sizeof(nh_buf)); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - nh_family = AF_INET6; - inet_ntop(nh_family, &api_nh->gate, nh_buf, - sizeof(nh_buf)); - break; - case NEXTHOP_TYPE_BLACKHOLE: - strlcpy(nh_buf, "blackhole", sizeof(nh_buf)); - break; - default: - /* Note: add new nexthop case */ - assert(0); - break; - } - - label_buf[0] = '\0'; - eth_buf[0] = '\0'; - segs_buf[0] = '\0'; - if (CHECK_FLAG(api_nh->flags, - ZAPI_NEXTHOP_FLAG_LABEL) && - !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) - snprintf(label_buf, sizeof(label_buf), - "label %u", api_nh->labels[0]); - if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6) && - !CHECK_FLAG(api_nh->flags, - ZAPI_NEXTHOP_FLAG_EVPN)) { - inet_ntop(AF_INET6, &api_nh->seg6_segs, - sid_buf, sizeof(sid_buf)); - snprintf(segs_buf, sizeof(segs_buf), "segs %s", - sid_buf); - } - if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN) && - !is_zero_mac(&api_nh->rmac)) - snprintf(eth_buf, sizeof(eth_buf), " RMAC %s", - prefix_mac2str(&api_nh->rmac, - buf1, sizeof(buf1))); - zlog_debug(" nhop [%d]: %s if %u VRF %u wt %u %s %s %s", - i + 1, nh_buf, api_nh->ifindex, - api_nh->vrf_id, api_nh->weight, - label_buf, segs_buf, eth_buf); - } - - int recursion_flag = 0; + bgp_debug_zebra_nh(&api); if (CHECK_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION)) recursion_flag = 1; @@ -1711,10 +1662,11 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, zlog_debug("%s: %pFX: announcing to zebra (recursion %sset)", __func__, p, (recursion_flag ? "" : "NOT ")); } - zclient_route_send(is_add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, - zclient, &api); + return zclient_route_send(is_add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, + zclient, &api); } + /* Announce all routes of a table to zebra */ void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi) { @@ -1735,14 +1687,11 @@ void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi) for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) && - (pi->type == ZEBRA_ROUTE_BGP && (pi->sub_type == BGP_ROUTE_NORMAL || pi->sub_type == BGP_ROUTE_IMPORTED))) - - bgp_zebra_announce(dest, - bgp_dest_get_prefix(dest), - pi, bgp, afi, safi); + bgp_zebra_route_install(dest, pi, bgp, true, + NULL, false); } /* Announce routes of any bgp subtype of a table to zebra */ @@ -1764,39 +1713,30 @@ void bgp_zebra_announce_table_all_subtypes(struct bgp *bgp, afi_t afi, for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) && pi->type == ZEBRA_ROUTE_BGP) - bgp_zebra_announce(dest, - bgp_dest_get_prefix(dest), - pi, bgp, afi, safi); + bgp_zebra_route_install(dest, pi, bgp, true, + NULL, false); } -void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info, - struct bgp *bgp, safi_t safi) +enum zclient_send_status bgp_zebra_withdraw_actual(struct bgp_dest *dest, + struct bgp_path_info *info, + struct bgp *bgp) { struct zapi_route api; struct peer *peer; + struct bgp_table *table = bgp_dest_table(dest); + const struct prefix *p = bgp_dest_get_prefix(dest); - /* - * If we are withdrawing the route, we don't need to have this - * flag set. So unset it. - */ - UNSET_FLAG(info->net->flags, BGP_NODE_FIB_INSTALL_PENDING); - - /* Don't try to install if we're not connected to Zebra or Zebra doesn't - * know of this instance. - */ - if (!bgp_install_info_to_zebra(bgp)) - return; - - if (safi == SAFI_FLOWSPEC) { + if (table->safi == SAFI_FLOWSPEC) { peer = info->peer; - bgp_pbr_update_entry(peer->bgp, p, info, AFI_IP, safi, false); - return; + bgp_pbr_update_entry(peer->bgp, p, info, table->afi, + table->safi, false); + return ZCLIENT_SEND_SUCCESS; } memset(&api, 0, sizeof(api)); api.vrf_id = bgp->vrf_id; api.type = ZEBRA_ROUTE_BGP; - api.safi = safi; + api.safi = table->safi; api.prefix = *p; if (info->attr->rmap_table_id) { @@ -1808,7 +1748,206 @@ void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info, zlog_debug("Tx route delete VRF %u %pFX", bgp->vrf_id, &api.prefix); - zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); + return zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); +} + +/* + * Walk the new Fifo list one by one and invoke bgp_zebra_announce/withdraw + * to install/withdraw the routes to zebra. + * + * If status = ZCLIENT_SEND_SUCCESS (Buffer empt)y i.e. Zebra is free to + * receive more incoming data, then pick the next item on the list and + * continue processing. + * + * If status = ZCLIENT_SEND_BUFFERED (Buffer pending) i.e. Zebra is busy, + * break and bail out of the function because once at some point when zebra + * is free, a callback is triggered which inturn call this same function and + * continue processing items on list. + */ +#define ZEBRA_ANNOUNCEMENTS_LIMIT 1000 +static void bgp_handle_route_announcements_to_zebra(struct event *e) +{ + bool is_evpn = false; + uint32_t count = 0; + struct bgp_dest *dest = NULL; + struct bgp_table *table = NULL; + enum zclient_send_status status = ZCLIENT_SEND_SUCCESS; + bool install; + + while (count < ZEBRA_ANNOUNCEMENTS_LIMIT) { + dest = zebra_announce_pop(&bm->zebra_announce_head); + + if (!dest) + break; + + table = bgp_dest_table(dest); + install = CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL); + if (table && table->afi == AFI_L2VPN && table->safi == SAFI_EVPN) + is_evpn = true; + + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("BGP %s route %pBD(%s) with dest %p and flags 0x%x to zebra", + install ? "announcing" : "withdrawing", dest, + table->bgp->name_pretty, dest, dest->flags); + + if (install) { + if (is_evpn) + status = + evpn_zebra_install(table->bgp, + dest->za_vpn, + (const struct prefix_evpn + *) + bgp_dest_get_prefix( + dest), + dest->za_bgp_pi); + else + status = bgp_zebra_announce_actual(dest, + dest->za_bgp_pi, + table->bgp); + UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL); + } else { + if (is_evpn) + status = evpn_zebra_uninstall( + table->bgp, dest->za_vpn, + (const struct prefix_evpn *) + bgp_dest_get_prefix(dest), + dest->za_bgp_pi, false); + else + status = bgp_zebra_withdraw_actual(dest, + dest->za_bgp_pi, + table->bgp); + + UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE); + } + + bgp_path_info_unlock(dest->za_bgp_pi); + dest->za_bgp_pi = NULL; + dest->za_vpn = NULL; + bgp_dest_unlock_node(dest); + + if (status == ZCLIENT_SEND_BUFFERED) + break; + + count++; + } + + if (status != ZCLIENT_SEND_BUFFERED && + zebra_announce_count(&bm->zebra_announce_head)) + event_add_event(bm->master, + bgp_handle_route_announcements_to_zebra, NULL, + 0, &bm->t_bgp_zebra_route); +} + +/* + * Callback function invoked when zclient_flush_data() receives a BUFFER_EMPTY + * i.e. zebra is free to receive more incoming data. + */ +static void bgp_zebra_buffer_write_ready(void) +{ + bgp_handle_route_announcements_to_zebra(NULL); +} + +/* + * BGP is now keeping a list of dests with the dest having a pointer + * to the bgp_path_info that it will be working on. + * Here is the sequence of events that should happen: + * + * Current State New State Action + * ------------- --------- ------ + * ---- Install Place dest on list, save pi, mark + * as going to be installed + * ---- Withdrawal Place dest on list, save pi, mark + * as going to be deleted + * + * Install Install Leave dest on list, release old pi, + * save new pi, mark as going to be + * Installed + * Install Withdrawal Leave dest on list, release old pi, + * save new pi, mark as going to be + * withdrawan, remove install flag + * + * Withdrawal Install Special case, send withdrawal immediately + * Leave dest on list, release old pi, + * save new pi, mark as going to be + * installed. <see note about evpn + * in bgp_route.c in bgp_process_main_one> + * Withdrawal Withdrawal Leave dest on list, release old pi, + * save new pi, mark as going to be + * withdrawn. + */ +void bgp_zebra_route_install(struct bgp_dest *dest, struct bgp_path_info *info, + struct bgp *bgp, bool install, struct bgpevpn *vpn, + bool is_sync) +{ + bool is_evpn = false; + struct bgp_table *table = NULL; + + table = bgp_dest_table(dest); + if (table && table->afi == AFI_L2VPN && table->safi == SAFI_EVPN) + is_evpn = true; + + /* + * BGP is installing this route and bgp has been configured + * to suppress announcements until the route has been installed + * let's set the fact that we expect this route to be installed + */ + if (install) { + if (BGP_SUPPRESS_FIB_ENABLED(bgp)) + SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); + + if (bgp->main_zebra_update_hold && !is_evpn) + return; + } else { + UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); + } + + /* + * Don't try to install if we're not connected to Zebra or Zebra doesn't + * know of this instance. + */ + if (!bgp_install_info_to_zebra(bgp) && !is_evpn) + return; + + if (!CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL) && + !CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE)) { + zebra_announce_add_tail(&bm->zebra_announce_head, dest); + /* + * If neither flag is set and za_bgp_pi is not set then it is a bug + */ + assert(!dest->za_bgp_pi); + bgp_path_info_lock(info); + bgp_dest_lock_node(dest); + dest->za_bgp_pi = info; + } else if (CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL)) { + assert(dest->za_bgp_pi); + bgp_path_info_unlock(dest->za_bgp_pi); + bgp_path_info_lock(info); + dest->za_bgp_pi = info; + } else if (CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE)) { + assert(dest->za_bgp_pi); + if (install & !is_evpn) + bgp_zebra_withdraw_actual(dest, dest->za_bgp_pi, bgp); + + bgp_path_info_unlock(dest->za_bgp_pi); + bgp_path_info_lock(info); + dest->za_bgp_pi = info; + } + + if (is_evpn) { + dest->za_vpn = vpn; + dest->za_is_sync = is_sync; + } + + if (install) { + UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE); + SET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL); + } else { + UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL); + SET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE); + } + + event_add_event(bm->master, bgp_handle_route_announcements_to_zebra, + NULL, 0, &bm->t_bgp_zebra_route); } /* Withdraw all entries in a BGP instances RIB table from Zebra */ @@ -1829,8 +1968,8 @@ void bgp_zebra_withdraw_table_all_subtypes(struct bgp *bgp, afi_t afi, safi_t sa for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) && (pi->type == ZEBRA_ROUTE_BGP)) - bgp_zebra_withdraw(bgp_dest_get_prefix(dest), - pi, bgp, safi); + bgp_zebra_route_install(dest, pi, bgp, false, + NULL, false); } } } @@ -1909,7 +2048,7 @@ int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type, redist_add_instance(&zclient->mi_redist[afi][type], instance); } else { - if (vrf_bitmap_check(zclient->redist[afi][type], bgp->vrf_id)) + if (vrf_bitmap_check(&zclient->redist[afi][type], bgp->vrf_id)) return CMD_WARNING; #ifdef ENABLE_BGP_VNC @@ -1919,7 +2058,7 @@ int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type, } #endif - vrf_bitmap_set(zclient->redist[afi][type], bgp->vrf_id); + vrf_bitmap_set(&zclient->redist[afi][type], bgp->vrf_id); } /* @@ -2040,9 +2179,9 @@ int bgp_redistribute_unreg(struct bgp *bgp, afi_t afi, int type, return CMD_WARNING; redist_del_instance(&zclient->mi_redist[afi][type], instance); } else { - if (!vrf_bitmap_check(zclient->redist[afi][type], bgp->vrf_id)) + if (!vrf_bitmap_check(&zclient->redist[afi][type], bgp->vrf_id)) return CMD_WARNING; - vrf_bitmap_unset(zclient->redist[afi][type], bgp->vrf_id); + vrf_bitmap_unset(&zclient->redist[afi][type], bgp->vrf_id); } if (bgp_install_info_to_zebra(bgp)) { @@ -2062,8 +2201,8 @@ int bgp_redistribute_unreg(struct bgp *bgp, afi_t afi, int type, } /* Unset redistribution. */ -int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, - unsigned short instance) +static void _bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, + unsigned short instance) { struct bgp_redist *red; @@ -2080,7 +2219,7 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, red = bgp_redist_lookup(bgp, afi, type, instance); if (!red) - return CMD_SUCCESS; + return; bgp_redistribute_unreg(bgp, afi, type, instance); @@ -2094,8 +2233,24 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, red->redist_metric = 0; bgp_redist_del(bgp, afi, type, instance); +} - return CMD_SUCCESS; +void bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, + unsigned short instance) +{ + struct listnode *node, *nnode; + struct bgp_redist *red; + + if ((type != ZEBRA_ROUTE_TABLE && type != ZEBRA_ROUTE_TABLE_DIRECT) || + instance != 0) + return _bgp_redistribute_unset(bgp, afi, type, instance); + + /* walk over instance */ + if (!bgp->redist[afi][type]) + return; + + for (ALL_LIST_ELEMENTS(bgp->redist[afi][type], node, nnode, red)) + _bgp_redistribute_unset(bgp, afi, type, red->instance); } void bgp_redistribute_redo(struct bgp *bgp) @@ -2386,7 +2541,7 @@ static int rule_notify_owner(ZAPI_CALLBACK_ARGS) enum zapi_rule_notify_owner note; struct bgp_pbr_action *bgp_pbra; struct bgp_pbr_rule *bgp_pbr = NULL; - char ifname[INTERFACE_NAMSIZ + 1]; + char ifname[IFNAMSIZ + 1]; if (!zapi_rule_notify_decode(zclient->ibuf, &seqno, &priority, &unique, ifname, ¬e)) @@ -2430,8 +2585,14 @@ static int rule_notify_owner(ZAPI_CALLBACK_ARGS) /* link bgp_info to bgp_pbr */ path = (struct bgp_path_info *)bgp_pbr->path; extra = bgp_path_info_extra_get(path); - listnode_add_force(&extra->bgp_fs_iprule, - bgp_pbr); + if (!extra->flowspec) { + extra->flowspec = + XCALLOC(MTYPE_BGP_ROUTE_EXTRA_FS, + sizeof(struct bgp_path_info_extra_fs)); + extra->flowspec->bgp_fs_iprule = NULL; + extra->flowspec->bgp_fs_pbr = NULL; + } + listnode_add_force(&extra->flowspec->bgp_fs_iprule, bgp_pbr); } if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("%s: Received RULE_INSTALLED", __func__); @@ -2533,7 +2694,14 @@ static int ipset_entry_notify_owner(ZAPI_CALLBACK_ARGS) /* link bgp_path_info to bpme */ path = (struct bgp_path_info *)bgp_pbime->path; extra = bgp_path_info_extra_get(path); - listnode_add_force(&extra->bgp_fs_pbr, bgp_pbime); + if (!extra->flowspec) { + extra->flowspec = + XCALLOC(MTYPE_BGP_ROUTE_EXTRA_FS, + sizeof(struct bgp_path_info_extra_fs)); + extra->flowspec->bgp_fs_iprule = NULL; + extra->flowspec->bgp_fs_pbr = NULL; + } + listnode_add_force(&extra->flowspec->bgp_fs_pbr, bgp_pbime); } break; case ZAPI_IPSET_ENTRY_FAIL_REMOVE: @@ -2619,8 +2787,12 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, /* Find the bgp route node */ dest = bgp_safi_node_lookup(bgp->rib[afi][safi], safi, &p, &bgp->vrf_prd); - if (!dest) + if (!dest) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s: %pFX does not exist in the BGP table, nothing to do for %u", + __func__, &p, note); return -1; + } switch (note) { case ZAPI_ROUTE_INSTALLED: @@ -2629,7 +2801,7 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("route %pRN : INSTALLED", dest); + zlog_debug("route %pBD : INSTALLED", dest); /* Find the best route */ for (pi = dest->info; pi; pi = pi->next) { /* Process aggregate route */ @@ -2642,7 +2814,7 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, group_announce_route(bgp, afi, safi, dest, new_select); else { flog_err(EC_BGP_INVALID_ROUTE, - "selected route %pRN not found", dest); + "selected route %pBD not found", dest); bgp_dest_unlock_node(dest); return -1; @@ -2655,12 +2827,12 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, */ UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("route %pRN: Removed from Fib", dest); + zlog_debug("route %pBD: Removed from Fib", dest); break; case ZAPI_ROUTE_FAIL_INSTALL: new_select = NULL; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("route: %pRN Failed to Install into Fib", + zlog_debug("route: %pBD Failed to Install into Fib", dest); UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); @@ -2674,7 +2846,7 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, break; case ZAPI_ROUTE_BETTER_ADMIN_WON: if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("route: %pRN removed due to better admin won", + zlog_debug("route: %pBD removed due to better admin won", dest); new_select = NULL; UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); @@ -2689,8 +2861,7 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, /* No action required */ break; case ZAPI_ROUTE_REMOVE_FAIL: - zlog_warn("%s: Route %pRN failure to remove", - __func__, dest); + zlog_warn("%s: Route %pBD failure to remove", __func__, dest); break; } @@ -2706,17 +2877,20 @@ static void bgp_encode_pbr_rule_action(struct stream *s, struct bgp_pbr_action *pbra, struct bgp_pbr_rule *pbr) { - struct prefix pfx; uint8_t fam = AF_INET; - char ifname[INTERFACE_NAMSIZ]; + struct pbr_rule r; if (pbra->nh.type == NEXTHOP_TYPE_IPV6) fam = AF_INET6; - stream_putl(s, 0); /* seqno unused */ + + /* + * Convert to canonical form + */ + memset(&r, 0, sizeof(r)); + /* r.seq unused */ if (pbr) - stream_putl(s, pbr->priority); - else - stream_putl(s, 0); + r.priority = pbr->priority; + /* ruleno unused - priority change * ruleno permits distinguishing various FS PBR entries * - FS PBR entries based on ipset/iptables @@ -2724,49 +2898,38 @@ static void bgp_encode_pbr_rule_action(struct stream *s, * the latter may contain default routing information injected by FS */ if (pbr) - stream_putl(s, pbr->unique); + r.unique = pbr->unique; else - stream_putl(s, pbra->unique); - stream_putc(s, 0); /* ip protocol being used */ - if (pbr && pbr->flags & MATCH_IP_SRC_SET) - memcpy(&pfx, &(pbr->src), sizeof(struct prefix)); - else { - memset(&pfx, 0, sizeof(pfx)); - pfx.family = fam; - } - stream_putc(s, pfx.family); - stream_putc(s, pfx.prefixlen); - stream_put(s, &pfx.u.prefix, prefix_blen(&pfx)); - - stream_putw(s, 0); /* src port */ + r.unique = pbra->unique; - if (pbr && pbr->flags & MATCH_IP_DST_SET) - memcpy(&pfx, &(pbr->dst), sizeof(struct prefix)); - else { - memset(&pfx, 0, sizeof(pfx)); - pfx.family = fam; - } - stream_putc(s, pfx.family); - stream_putc(s, pfx.prefixlen); - stream_put(s, &pfx.u.prefix, prefix_blen(&pfx)); + r.family = fam; - stream_putw(s, 0); /* dst port */ - stream_putc(s, 0); /* dsfield */ - /* if pbr present, fwmark is not used */ - if (pbr) - stream_putl(s, 0); - else - stream_putl(s, pbra->fwmark); /* fwmark */ + /* filter */ - stream_putl(s, 0); /* queue id */ - stream_putw(s, 0); /* vlan_id */ - stream_putw(s, 0); /* vlan_flags */ - stream_putw(s, 0); /* pcp */ + if (pbr && pbr->flags & MATCH_IP_SRC_SET) { + SET_FLAG(r.filter.filter_bm, PBR_FILTER_SRC_IP); + r.filter.src_ip = pbr->src; + } else { + /* ??? */ + r.filter.src_ip.family = fam; + } + if (pbr && pbr->flags & MATCH_IP_DST_SET) { + SET_FLAG(r.filter.filter_bm, PBR_FILTER_DST_IP); + r.filter.dst_ip = pbr->dst; + } else { + /* ??? */ + r.filter.dst_ip.family = fam; + } + /* src_port, dst_port, pcp, dsfield not used */ + if (!pbr) { + SET_FLAG(r.filter.filter_bm, PBR_FILTER_FWMARK); + r.filter.fwmark = pbra->fwmark; + } - stream_putl(s, pbra->table_id); + SET_FLAG(r.action.flags, PBR_ACTION_TABLE); /* always valid */ + r.action.table = pbra->table_id; - memset(ifname, 0, sizeof(ifname)); - stream_put(s, ifname, INTERFACE_NAMSIZ); /* ifname unused */ + zapi_pbr_rule_encode(s, &r); } static void bgp_encode_pbr_ipset_match(struct stream *s, @@ -2854,9 +3017,6 @@ static void bgp_zebra_connected(struct zclient *zclient) bgp_zebra_instance_register(bgp); - /* tell label pool that zebra is connected */ - bgp_lp_event_zebra_up(); - /* TODO - What if we have peers and networks configured, do we have to * kick-start them? */ @@ -2983,12 +3143,11 @@ static int bgp_zebra_process_local_l3vni(ZAPI_CALLBACK_ARGS) is_anycast_mac = stream_getl(s); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug( - "Rx L3-VNI ADD VRF %s VNI %u RMAC svi-mac %pEA vrr-mac %pEA filter %s svi-if %u", - vrf_id_to_name(vrf_id), l3vni, &svi_rmac, - &vrr_rmac, - filter ? "prefix-routes-only" : "none", - svi_ifindex); + zlog_debug("Rx L3VNI ADD VRF %s VNI %u Originator-IP %pI4 RMAC svi-mac %pEA vrr-mac %pEA filter %s svi-if %u", + vrf_id_to_name(vrf_id), l3vni, + &originator_ip, &svi_rmac, &vrr_rmac, + filter ? "prefix-routes-only" : "none", + svi_ifindex); frrtrace(8, frr_bgp, evpn_local_l3vni_add_zrecv, l3vni, vrf_id, &svi_rmac, &vrr_rmac, filter, originator_ip, @@ -2999,7 +3158,7 @@ static int bgp_zebra_process_local_l3vni(ZAPI_CALLBACK_ARGS) is_anycast_mac); } else { if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx L3-VNI DEL VRF %s VNI %u", + zlog_debug("Rx L3VNI DEL VRF %s VNI %u", vrf_id_to_name(vrf_id), l3vni); frrtrace(2, frr_bgp, evpn_local_l3vni_del_zrecv, l3vni, vrf_id); @@ -3161,54 +3320,6 @@ static int bgp_zebra_process_local_ip_prefix(ZAPI_CALLBACK_ARGS) return 0; } -static int bgp_zebra_process_label_chunk(ZAPI_CALLBACK_ARGS) -{ - struct stream *s = NULL; - uint8_t response_keep; - uint32_t first; - uint32_t last; - uint8_t proto; - unsigned short instance; - - s = zclient->ibuf; - STREAM_GETC(s, proto); - STREAM_GETW(s, instance); - STREAM_GETC(s, response_keep); - STREAM_GETL(s, first); - STREAM_GETL(s, last); - - if (zclient->redist_default != proto) { - flog_err(EC_BGP_LM_ERROR, "Got LM msg with wrong proto %u", - proto); - return 0; - } - if (zclient->instance != instance) { - flog_err(EC_BGP_LM_ERROR, "Got LM msg with wrong instance %u", - proto); - return 0; - } - - if (first > last || - first < MPLS_LABEL_UNRESERVED_MIN || - last > MPLS_LABEL_UNRESERVED_MAX) { - - flog_err(EC_BGP_LM_ERROR, "%s: Invalid Label chunk: %u - %u", - __func__, first, last); - return 0; - } - if (BGP_DEBUG(zebra, ZEBRA)) { - zlog_debug("Label Chunk assign: %u - %u (%u) ", - first, last, response_keep); - } - - bgp_lp_event_chunk(response_keep, first, last); - - return 0; - -stream_failure: /* for STREAM_GETX */ - return -1; -} - extern struct zebra_privs_t bgpd_privs; static int bgp_ifp_create(struct interface *ifp) @@ -3227,6 +3338,15 @@ static int bgp_ifp_create(struct interface *ifp) bgp_update_interface_nbrs(bgp, ifp, ifp); hook_call(bgp_vrf_status_changed, bgp, ifp); + + if (bgp_get_default() && if_is_loopback(ifp)) { + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } @@ -3308,7 +3428,7 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS) if (prefix_match((struct prefix *)&loc.prefix, (struct prefix *)&tmp_prefi)) { listnode_delete(bgp->srv6_functions, func); - XFREE(MTYPE_BGP_SRV6_FUNCTION, func); + srv6_function_free(func); } } @@ -3410,10 +3530,8 @@ static zclient_handler *const bgp_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_DELETE] = bgp_interface_address_delete, [ZEBRA_INTERFACE_NBR_ADDRESS_ADD] = bgp_interface_nbr_address_add, [ZEBRA_INTERFACE_NBR_ADDRESS_DELETE] = bgp_interface_nbr_address_delete, - [ZEBRA_INTERFACE_VRF_UPDATE] = bgp_interface_vrf_update, [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = zebra_read_route, [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = zebra_read_route, - [ZEBRA_NEXTHOP_UPDATE] = bgp_read_nexthop_update, [ZEBRA_FEC_UPDATE] = bgp_read_fec_update, [ZEBRA_LOCAL_ES_ADD] = bgp_zebra_process_local_es_add, [ZEBRA_LOCAL_ES_DEL] = bgp_zebra_process_local_es_del, @@ -3427,7 +3545,6 @@ static zclient_handler *const bgp_handlers[] = { [ZEBRA_L3VNI_DEL] = bgp_zebra_process_local_l3vni, [ZEBRA_IP_PREFIX_ROUTE_ADD] = bgp_zebra_process_local_ip_prefix, [ZEBRA_IP_PREFIX_ROUTE_DEL] = bgp_zebra_process_local_ip_prefix, - [ZEBRA_GET_LABEL_CHUNK] = bgp_zebra_process_label_chunk, [ZEBRA_RULE_NOTIFY_OWNER] = rule_notify_owner, [ZEBRA_IPSET_NOTIFY_OWNER] = ipset_notify_owner, [ZEBRA_IPSET_ENTRY_NOTIFY_OWNER] = ipset_entry_notify_owner, @@ -3464,19 +3581,90 @@ void bgp_if_init(void) hook_register_prio(if_del, 0, bgp_if_delete_hook); } +static void bgp_start_label_manager(struct event *start) +{ + bgp_zebra_label_manager_connect(); +} + +static bool bgp_zebra_label_manager_ready(void) +{ + return (zclient_sync->sock > 0); +} + +static bool bgp_zebra_label_manager_connect(void) +{ + /* Connect to label manager. */ + if (zclient_socket_connect(zclient_sync) < 0) { + zlog_warn("%s: failed connecting synchronous zclient!", + __func__); + return false; + } + /* make socket non-blocking */ + set_nonblocking(zclient_sync->sock); + + /* Send hello to notify zebra this is a synchronous client */ + if (zclient_send_hello(zclient_sync) == ZCLIENT_SEND_FAILURE) { + zlog_warn("%s: failed sending hello for synchronous zclient!", + __func__); + close(zclient_sync->sock); + zclient_sync->sock = -1; + return false; + } + + /* Connect to label manager */ + if (lm_label_manager_connect(zclient_sync, 0) != 0) { + zlog_warn("%s: failed connecting to label manager!", __func__); + if (zclient_sync->sock > 0) { + close(zclient_sync->sock); + zclient_sync->sock = -1; + } + return false; + } + + /* tell label pool that zebra is connected */ + bgp_lp_event_zebra_up(); + + /* tell BGP L3VPN that label manager is available */ + if (bgp_get_default()) + vpn_leak_postchange_all(); + return true; +} + +static void bgp_zebra_capabilities(struct zclient_capabilities *cap) +{ + bm->v6_with_v4_nexthops = cap->v6_with_v4_nexthop; +} + void bgp_zebra_init(struct event_loop *master, unsigned short instance) { zclient_num_connects = 0; - if_zapi_callbacks(bgp_ifp_create, bgp_ifp_up, - bgp_ifp_down, bgp_ifp_destroy); + hook_register_prio(if_real, 0, bgp_ifp_create); + hook_register_prio(if_up, 0, bgp_ifp_up); + hook_register_prio(if_down, 0, bgp_ifp_down); + hook_register_prio(if_unreal, 0, bgp_ifp_destroy); /* Set default values. */ zclient = zclient_new(master, &zclient_options_default, bgp_handlers, array_size(bgp_handlers)); zclient_init(zclient, ZEBRA_ROUTE_BGP, 0, &bgpd_privs); + zclient->zebra_buffer_write_ready = bgp_zebra_buffer_write_ready; zclient->zebra_connected = bgp_zebra_connected; + zclient->zebra_capabilities = bgp_zebra_capabilities; + zclient->nexthop_update = bgp_nexthop_update; zclient->instance = instance; + + /* Initialize special zclient for synchronous message exchanges. */ + zclient_sync = zclient_new(master, &zclient_options_sync, NULL, 0); + zclient_sync->sock = -1; + zclient_sync->redist_default = ZEBRA_ROUTE_BGP; + zclient_sync->instance = instance; + zclient_sync->session_id = 1; + zclient_sync->privs = &bgpd_privs; + + if (!bgp_zebra_label_manager_ready()) + event_add_timer(master, bgp_start_label_manager, NULL, 1, + &bm->t_bgp_start_label_manager); } void bgp_zebra_destroy(void) @@ -3486,6 +3674,12 @@ void bgp_zebra_destroy(void) zclient_stop(zclient); zclient_free(zclient); zclient = NULL; + + if (zclient_sync == NULL) + return; + zclient_stop(zclient_sync); + zclient_free(zclient_sync); + zclient_sync = NULL; } int bgp_zebra_num_connects(void) @@ -3517,11 +3711,9 @@ void bgp_send_pbr_rule_action(struct bgp_pbr_action *pbra, zclient_create_header(s, install ? ZEBRA_RULE_ADD : ZEBRA_RULE_DELETE, VRF_DEFAULT); - stream_putl(s, 1); /* send one pbr action */ bgp_encode_pbr_rule_action(s, pbra, pbr); - stream_putw_at(s, 0, stream_get_endp(s)); if ((zclient_send_message(zclient) != ZCLIENT_SEND_FAILURE) && install) { if (!pbr) @@ -3704,38 +3896,26 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh, api.distance = ZEBRA_EBGP_DISTANCE_DEFAULT; SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); + api_nh->vrf_id = nh->vrf_id; + + if (BGP_DEBUG(zebra, ZEBRA)) { + struct vrf *vrf; + + vrf = vrf_lookup_by_id(nh->vrf_id); + zlog_debug("%s: %s default route to %pNHvv(%s) table %d", + bgp->name_pretty, announce ? "adding" : "withdrawing", + nh, VRF_LOGNAME(vrf), table_id); + } + /* redirect IP */ if (afi == AFI_IP && nh->gate.ipv4.s_addr != INADDR_ANY) { - api_nh->vrf_id = nh->vrf_id; api_nh->gate.ipv4 = nh->gate.ipv4; api_nh->type = NEXTHOP_TYPE_IPV4; - - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug( - "BGP: %s default route to %pI4 table %d (redirect IP)", - announce ? "adding" : "withdrawing", - &nh->gate.ipv4, table_id); - - zclient_route_send(announce ? ZEBRA_ROUTE_ADD - : ZEBRA_ROUTE_DELETE, - zclient, &api); - } else if (afi == AFI_IP6 && - memcmp(&nh->gate.ipv6, - &in6addr_any, sizeof(struct in6_addr))) { - api_nh->vrf_id = nh->vrf_id; + } else if (afi == AFI_IP6 && memcmp(&nh->gate.ipv6, &in6addr_any, + sizeof(struct in6_addr))) { memcpy(&api_nh->gate.ipv6, &nh->gate.ipv6, sizeof(struct in6_addr)); api_nh->type = NEXTHOP_TYPE_IPV6; - - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug( - "BGP: %s default route to %pI6 table %d (redirect IP)", - announce ? "adding" : "withdrawing", - &nh->gate.ipv6, table_id); - - zclient_route_send(announce ? ZEBRA_ROUTE_ADD - : ZEBRA_ROUTE_DELETE, - zclient, &api); } else if (nh->vrf_id != bgp->vrf_id) { struct vrf *vrf; struct interface *ifp; @@ -3749,18 +3929,12 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh, ifp = if_lookup_by_name_vrf(vrf->name, vrf); if (!ifp) return; - api_nh->vrf_id = nh->vrf_id; api_nh->type = NEXTHOP_TYPE_IFINDEX; api_nh->ifindex = ifp->ifindex; - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_info("BGP: %s default route to %s table %d (redirect VRF)", - announce ? "adding" : "withdrawing", - vrf->name, table_id); - zclient_route_send(announce ? ZEBRA_ROUTE_ADD - : ZEBRA_ROUTE_DELETE, - zclient, &api); - return; } + + zclient_route_send(announce ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, + zclient, &api); } /* Send capabilities to RIB */ @@ -3911,3 +4085,89 @@ int bgp_zebra_srv6_manager_release_locator_chunk(const char *name) { return srv6_manager_release_locator_chunk(zclient, name); } + +void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label, + ifindex_t ifindex, vrf_id_t vrf_id, + enum lsp_types_t ltype, struct prefix *p, + uint32_t num_labels, + mpls_label_t out_labels[]) +{ + struct zapi_labels zl = {}; + struct zapi_nexthop *znh; + int i = 0; + + zl.type = ltype; + zl.local_label = label; + zl.nexthop_num = 1; + znh = &zl.nexthops[0]; + if (p->family == AF_INET) + IPV4_ADDR_COPY(&znh->gate.ipv4, &p->u.prefix4); + else + IPV6_ADDR_COPY(&znh->gate.ipv6, &p->u.prefix6); + if (ifindex == IFINDEX_INTERNAL) + znh->type = (p->family == AF_INET) ? NEXTHOP_TYPE_IPV4 + : NEXTHOP_TYPE_IPV6; + else + znh->type = (p->family == AF_INET) ? NEXTHOP_TYPE_IPV4_IFINDEX + : NEXTHOP_TYPE_IPV6_IFINDEX; + znh->ifindex = ifindex; + znh->vrf_id = vrf_id; + if (num_labels == 0) + znh->label_num = 0; + else { + if (num_labels > MPLS_MAX_LABELS) + znh->label_num = MPLS_MAX_LABELS; + else + znh->label_num = num_labels; + for (i = 0; i < znh->label_num; i++) + znh->labels[i] = out_labels[i]; + } + /* vrf_id is DEFAULT_VRF */ + zebra_send_mpls_labels(zclient, cmd, &zl); +} + +bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size, + bool label_auto) +{ + int ret; + uint32_t start, end; + + if (!zclient_sync || !bgp_zebra_label_manager_ready()) + return false; + + ret = lm_get_label_chunk(zclient_sync, 0, base, chunk_size, &start, + &end); + if (ret < 0) { + zlog_warn("%s: error getting label range!", __func__); + return false; + } + + if (start > end || start < MPLS_LABEL_UNRESERVED_MIN || + end > MPLS_LABEL_UNRESERVED_MAX) { + flog_err(EC_BGP_LM_ERROR, "%s: Invalid Label chunk: %u - %u", + __func__, start, end); + return false; + } + + if (label_auto) + /* label automatic is serviced by the bgp label pool + * manager, which allocates label chunks in + * pre-pools, and which needs to be notified about + * new chunks availability + */ + bgp_lp_event_chunk(start, end); + + return true; +} + +void bgp_zebra_release_label_range(uint32_t start, uint32_t end) +{ + int ret; + + if (!zclient_sync || !bgp_zebra_label_manager_ready()) + return; + + ret = lm_release_label_chunk(zclient_sync, start, end); + if (ret < 0) + zlog_warn("%s: error releasing label range!", __func__); +} |
