]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_zebra.c
lib, bgpd: implement pthread lifecycle management
[mirror_frr.git] / bgpd / bgp_zebra.c
index 9a092404d58297b539508a0c0e9452c09b9fa5f8..1cf04abfce69a32c7a9682133cdaaf5784aa9548 100644 (file)
 /* All information about zebra. */
 struct zclient *zclient = NULL;
 
-/* These array buffers are used in making a copy of the attributes for
-   route-map apply. Arrays are being used here to minimize mallocs and
-   frees for the temporary copy of the attributes.
-   Given the zapi api expects the nexthop buffer to contain pointer to
-   pointers for nexthops, we couldnt have used a single nexthop variable
-   on the stack, hence we had two options:
-     1. maintain a linked-list and free it after zapi_*_route call
-     2. use an array to avoid number of mallocs.
-   Number of supported next-hops are finite, use of arrays should be ok. */
-struct attr attr_cp[MULTIPATH_NUM];
-unsigned int attr_index = 0;
-
-/* Once per address-family initialization of the attribute array */
-#define BGP_INFO_ATTR_BUF_INIT()                                               \
-       do {                                                                   \
-               memset(attr_cp, 0, MULTIPATH_NUM * sizeof(struct attr));       \
-               attr_index = 0;                                                \
-       } while (0)
-
-#define BGP_INFO_ATTR_BUF_COPY(info_src, info_dst)                             \
-       do {                                                                   \
-               *info_dst = *info_src;                                         \
-               assert(attr_index != multipath_num);                           \
-               bgp_attr_dup(&attr_cp[attr_index], info_src->attr);            \
-               bgp_attr_deep_dup(&attr_cp[attr_index], info_src->attr);       \
-               info_dst->attr = &attr_cp[attr_index];                         \
-               attr_index++;                                                  \
-       } while (0)
-
-#define BGP_INFO_ATTR_BUF_FREE(info)                                           \
-       do {                                                                   \
-               bgp_attr_deep_free(info->attr);                                \
-       } while (0)
-
-
 /* Can we install into zebra? */
 static inline int bgp_install_info_to_zebra(struct bgp *bgp)
 {
@@ -259,6 +224,10 @@ static int bgp_interface_delete(int command, struct zclient *zclient,
        struct interface *ifp;
        struct bgp *bgp;
 
+       bgp = bgp_lookup_by_vrf_id(vrf_id);
+       if (!bgp)
+               return 0;
+
        s = zclient->ibuf;
        ifp = zebra_interface_state_read(s, vrf_id);
        if (!ifp) /* This may happen if we've just unregistered for a VRF. */
@@ -267,13 +236,9 @@ static int bgp_interface_delete(int command, struct zclient *zclient,
        if (BGP_DEBUG(zebra, ZEBRA))
                zlog_debug("Rx Intf del VRF %u IF %s", vrf_id, ifp->name);
 
-       bgp = bgp_lookup_by_vrf_id(vrf_id);
-       if (!bgp)
-               return 0;
-
        bgp_update_interface_nbrs(bgp, ifp, NULL);
 
-       ifp->ifindex = IFINDEX_DELETED;
+       if_set_index(ifp, IFINDEX_INTERNAL);
        return 0;
 }
 
@@ -287,6 +252,10 @@ static int bgp_interface_up(int command, struct zclient *zclient,
        struct listnode *node, *nnode;
        struct bgp *bgp;
 
+       bgp = bgp_lookup_by_vrf_id(vrf_id);
+       if (!bgp)
+               return 0;
+
        s = zclient->ibuf;
        ifp = zebra_interface_state_read(s, vrf_id);
 
@@ -296,10 +265,6 @@ static int bgp_interface_up(int command, struct zclient *zclient,
        if (BGP_DEBUG(zebra, ZEBRA))
                zlog_debug("Rx Intf up VRF %u IF %s", vrf_id, ifp->name);
 
-       bgp = bgp_lookup_by_vrf_id(vrf_id);
-       if (!bgp)
-               return 0;
-
        for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, c))
                bgp_connected_add(bgp, c);
 
@@ -319,6 +284,10 @@ static int bgp_interface_down(int command, struct zclient *zclient,
        struct listnode *node, *nnode;
        struct bgp *bgp;
 
+       bgp = bgp_lookup_by_vrf_id(vrf_id);
+       if (!bgp)
+               return 0;
+
        s = zclient->ibuf;
        ifp = zebra_interface_state_read(s, vrf_id);
        if (!ifp)
@@ -327,10 +296,6 @@ static int bgp_interface_down(int command, struct zclient *zclient,
        if (BGP_DEBUG(zebra, ZEBRA))
                zlog_debug("Rx Intf down VRF %u IF %s", vrf_id, ifp->name);
 
-       bgp = bgp_lookup_by_vrf_id(vrf_id);
-       if (!bgp)
-               return 0;
-
        for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, c))
                bgp_connected_delete(bgp, c);
 
@@ -373,6 +338,11 @@ static int bgp_interface_address_add(int command, struct zclient *zclient,
                                     zebra_size_t length, vrf_id_t vrf_id)
 {
        struct connected *ifc;
+       struct bgp *bgp;
+
+       bgp = bgp_lookup_by_vrf_id(vrf_id);
+       if (!bgp)
+               return 0;
 
        ifc = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
 
@@ -387,13 +357,8 @@ static int bgp_interface_address_add(int command, struct zclient *zclient,
        }
 
        if (if_is_operative(ifc->ifp)) {
-               struct bgp *bgp;
-
-               bgp = bgp_lookup_by_vrf_id(vrf_id);
-               if (!bgp)
-                       return 0;
-
                bgp_connected_add(bgp, ifc);
+
                /* If we have learnt of any neighbors on this interface,
                 * check to kick off any BGP interface-based neighbors,
                 * but only if this is a link-local address.
@@ -412,6 +377,10 @@ static int bgp_interface_address_delete(int command, struct zclient *zclient,
        struct connected *ifc;
        struct bgp *bgp;
 
+       bgp = bgp_lookup_by_vrf_id(vrf_id);
+       if (!bgp)
+               return 0;
+
        ifc = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
 
        if (ifc == NULL)
@@ -425,9 +394,7 @@ static int bgp_interface_address_delete(int command, struct zclient *zclient,
        }
 
        if (if_is_operative(ifc->ifp)) {
-               bgp = bgp_lookup_by_vrf_id(vrf_id);
-               if (bgp)
-                       bgp_connected_delete(bgp, ifc);
+               bgp_connected_delete(bgp, ifc);
        }
 
        connected_free(ifc);
@@ -557,9 +524,10 @@ static int bgp_interface_vrf_update(int command, struct zclient *zclient,
 static int zebra_read_route(int command, struct zclient *zclient,
                            zebra_size_t length, vrf_id_t vrf_id)
 {
+       enum nexthop_types_t nhtype;
        struct zapi_route api;
        union g_addr nexthop;
-       unsigned int ifindex;
+       ifindex_t ifindex;
        int add, i;
        struct bgp *bgp;
 
@@ -581,6 +549,7 @@ static int zebra_read_route(int command, struct zclient *zclient,
 
        nexthop = api.nexthops[0].gate;
        ifindex = api.nexthops[0].ifindex;
+       nhtype = api.nexthops[0].type;
 
        add = (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD);
        if (add) {
@@ -601,8 +570,8 @@ static int zebra_read_route(int command, struct zclient *zclient,
 
                /* Now perform the add/update. */
                bgp_redistribute_add(bgp, &api.prefix, &nexthop, ifindex,
-                                    api.metric, api.type, api.instance,
-                                    api.tag);
+                                    nhtype, api.metric, api.type,
+                                    api.instance, api.tag);
        } else {
                bgp_redistribute_delete(bgp, &api.prefix, api.type,
                                        api.instance);
@@ -626,18 +595,22 @@ static int zebra_read_route(int command, struct zclient *zclient,
 
 struct interface *if_lookup_by_ipv4(struct in_addr *addr, vrf_id_t vrf_id)
 {
-       struct listnode *ifnode;
+       struct vrf *vrf;
        struct listnode *cnode;
        struct interface *ifp;
        struct connected *connected;
        struct prefix_ipv4 p;
        struct prefix *cp;
 
+       vrf = vrf_lookup_by_id(vrf_id);
+       if (!vrf)
+               return NULL;
+
        p.family = AF_INET;
        p.prefix = *addr;
        p.prefixlen = IPV4_MAX_BITLEN;
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(vrf_id), ifnode, ifp)) {
+       FOR_ALL_INTERFACES (vrf, ifp) {
                for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) {
                        cp = connected->address;
 
@@ -651,13 +624,17 @@ 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 listnode *ifnode;
+       struct vrf *vrf;
        struct listnode *cnode;
        struct interface *ifp;
        struct connected *connected;
        struct prefix *cp;
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(vrf_id), ifnode, ifp)) {
+       vrf = vrf_lookup_by_id(vrf_id);
+       if (!vrf)
+               return NULL;
+
+       FOR_ALL_INTERFACES (vrf, ifp) {
                for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) {
                        cp = connected->address;
 
@@ -672,18 +649,22 @@ struct interface *if_lookup_by_ipv4_exact(struct in_addr *addr, vrf_id_t vrf_id)
 struct interface *if_lookup_by_ipv6(struct in6_addr *addr, ifindex_t ifindex,
                                    vrf_id_t vrf_id)
 {
-       struct listnode *ifnode;
+       struct vrf *vrf;
        struct listnode *cnode;
        struct interface *ifp;
        struct connected *connected;
        struct prefix_ipv6 p;
        struct prefix *cp;
 
+       vrf = vrf_lookup_by_id(vrf_id);
+       if (!vrf)
+               return NULL;
+
        p.family = AF_INET6;
        p.prefix = *addr;
        p.prefixlen = IPV6_MAX_BITLEN;
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(vrf_id), ifnode, ifp)) {
+       FOR_ALL_INTERFACES (vrf, ifp) {
                for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) {
                        cp = connected->address;
 
@@ -704,13 +685,17 @@ struct interface *if_lookup_by_ipv6(struct in6_addr *addr, ifindex_t ifindex,
 struct interface *if_lookup_by_ipv6_exact(struct in6_addr *addr,
                                          ifindex_t ifindex, vrf_id_t vrf_id)
 {
-       struct listnode *ifnode;
+       struct vrf *vrf;
        struct listnode *cnode;
        struct interface *ifp;
        struct connected *connected;
        struct prefix *cp;
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(vrf_id), ifnode, ifp)) {
+       vrf = vrf_lookup_by_id(vrf_id);
+       if (!vrf)
+               return NULL;
+
+       FOR_ALL_INTERFACES (vrf, ifp) {
                for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) {
                        cp = connected->address;
 
@@ -950,7 +935,12 @@ static struct in6_addr *bgp_info_to_ipv6_nexthop(struct bgp_info *info)
 static int bgp_table_map_apply(struct route_map *map, struct prefix *p,
                               struct bgp_info *info)
 {
-       if (route_map_apply(map, p, RMAP_BGP, info) != RMAP_DENYMATCH)
+       route_map_result_t ret;
+
+       ret = route_map_apply(map, p, RMAP_BGP, info);
+       bgp_attr_flush(info->attr);
+
+       if (ret != RMAP_DENYMATCH)
                return 1;
 
        if (bgp_debug_zebra(p)) {
@@ -986,14 +976,15 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
        struct zapi_route api;
        struct zapi_nexthop *api_nh;
        int nh_family;
-       int valid_nh_count = 0;
+       unsigned int valid_nh_count = 0;
        int has_valid_label = 0;
        u_char distance;
        struct peer *peer;
        struct bgp_info *mpinfo;
        u_int32_t metric;
+       struct attr local_attr;
        struct bgp_info local_info;
-       struct bgp_info *info_cp = &local_info;
+       struct bgp_info *mpinfo_cp = &local_info;
        route_tag_t tag;
        mpls_label_t label;
 
@@ -1022,7 +1013,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
         * in
         * the RIB */
        if (info->sub_type == BGP_ROUTE_AGGREGATE)
-               SET_FLAG(api.flags, ZEBRA_FLAG_BLACKHOLE);
+               zapi_route_set_blackhole(&api, BLACKHOLE_NULL);
 
        if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED
            || info->sub_type == BGP_ROUTE_AGGREGATE) {
@@ -1036,47 +1027,48 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
 
                SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
 
-       /* Get nexthop address-family */
-       if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(info->attr))
-               nh_family = AF_INET;
-       else if (p->family == AF_INET6
-                || (p->family == AF_INET
-                    && BGP_ATTR_NEXTHOP_AFI_IP6(info->attr)))
-               nh_family = AF_INET6;
-       else
-               return;
-
-       if (bgp->table_map[afi][safi].name)
-               BGP_INFO_ATTR_BUF_INIT();
-
        /* Metric is currently based on the best-path only */
        metric = info->attr->med;
        for (mpinfo = info; mpinfo; mpinfo = bgp_info_mpath_next(mpinfo)) {
+               if (valid_nh_count >= multipath_num)
+                       break;
+
+               *mpinfo_cp = *mpinfo;
+
+               /* Get nexthop address-family */
+               if (p->family == AF_INET
+                   && !BGP_ATTR_NEXTHOP_AFI_IP6(mpinfo_cp->attr))
+                       nh_family = AF_INET;
+               else if (p->family == AF_INET6
+                        || (p->family == AF_INET
+                            && BGP_ATTR_NEXTHOP_AFI_IP6(mpinfo_cp->attr)))
+                       nh_family = AF_INET6;
+               else
+                       continue;
+
                if (nh_family == AF_INET) {
                        struct in_addr *nexthop;
 
-                       nexthop = NULL;
-
                        if (bgp->table_map[afi][safi].name) {
                                /* Copy info and attributes, so the route-map
-                                  apply doesn't modify the
-                                  BGP route info. */
-                               BGP_INFO_ATTR_BUF_COPY(mpinfo, info_cp);
-                               if (bgp_table_map_apply(
+                                  apply doesn't modify the BGP route info. */
+                               local_attr = *mpinfo->attr;
+                               mpinfo_cp->attr = &local_attr;
+
+                               if (!bgp_table_map_apply(
                                            bgp->table_map[afi][safi].map, p,
-                                           info_cp)) {
-                                       if (mpinfo == info) {
-                                               metric = info_cp->attr->med;
-                                               tag = info_cp->attr->tag;
-                                       }
-                                       nexthop = &info_cp->attr->nexthop;
+                                           mpinfo_cp))
+                                       continue;
+
+                               /* metric/tag is only allowed to be
+                                * overridden on 1st nexthop */
+                               if (mpinfo == info) {
+                                       metric = mpinfo_cp->attr->med;
+                                       tag = mpinfo_cp->attr->tag;
                                }
-                               BGP_INFO_ATTR_BUF_FREE(info_cp);
-                       } else
-                               nexthop = &mpinfo->attr->nexthop;
+                       }
 
-                       if (nexthop == NULL)
-                               continue;
+                       nexthop = &mpinfo_cp->attr->nexthop;
 
                        api_nh = &api.nexthops[valid_nh_count];
                        api_nh->gate.ipv4 = *nexthop;
@@ -1086,29 +1078,26 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
                        struct in6_addr *nexthop;
 
                        ifindex = 0;
-                       nexthop = NULL;
 
                        if (bgp->table_map[afi][safi].name) {
                                /* Copy info and attributes, so the route-map
-                                  apply doesn't modify the
-                                  BGP route info. */
-                               BGP_INFO_ATTR_BUF_COPY(mpinfo, info_cp);
-                               if (bgp_table_map_apply(
+                                  apply doesn't modify the BGP route info. */
+                               local_attr = *mpinfo->attr;
+                               mpinfo_cp->attr = &local_attr;
+
+                               if (!bgp_table_map_apply(
                                            bgp->table_map[afi][safi].map, p,
-                                           info_cp)) {
-                                       if (mpinfo == info) {
-                                               metric = info_cp->attr->med;
-                                               tag = info_cp->attr->tag;
-                                       }
-                                       nexthop = bgp_info_to_ipv6_nexthop(
-                                               info_cp);
+                                           mpinfo_cp))
+                                       continue;
+
+                               /* metric/tag is only allowed to be
+                                * overridden on 1st nexthop */
+                               if (mpinfo == info) {
+                                       metric = mpinfo_cp->attr->med;
+                                       tag = mpinfo_cp->attr->tag;
                                }
-                               BGP_INFO_ATTR_BUF_FREE(info_cp);
-                       } else
-                               nexthop = bgp_info_to_ipv6_nexthop(mpinfo);
-
-                       if (nexthop == NULL)
-                               continue;
+                       }
+                       nexthop = bgp_info_to_ipv6_nexthop(mpinfo_cp);
 
                        if ((mpinfo == info)
                            && mpinfo->attr->mp_nexthop_len
@@ -1118,12 +1107,11 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
                                                          ->ifindex;
 
                        if (!ifindex) {
-                               if (mpinfo->peer->conf_if
-                                   || mpinfo->peer->ifname)
+                               if (mpinfo->peer->conf_if)
+                                       ifindex = mpinfo->peer->ifp->ifindex;
+                               else if (mpinfo->peer->ifname)
                                        ifindex = ifname2ifindex(
-                                               mpinfo->peer->conf_if
-                                                       ? mpinfo->peer->conf_if
-                                                       : mpinfo->peer->ifname,
+                                               mpinfo->peer->ifname,
                                                bgp->vrf_id);
                                else if (mpinfo->peer->nexthop.ifp)
                                        ifindex = mpinfo->peer->nexthop.ifp
@@ -1152,7 +1140,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
        if (has_valid_label)
                SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
 
-       if (!CHECK_FLAG(api.flags, ZEBRA_FLAG_BLACKHOLE))
+       if (info->sub_type != BGP_ROUTE_AGGREGATE)
                api.nexthop_num = valid_nh_count;
 
        SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
@@ -1183,6 +1171,10 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
                for (i = 0; i < api.nexthop_num; i++) {
                        api_nh = &api.nexthops[i];
 
+                       if (api_nh->type == NEXTHOP_TYPE_IPV4)
+                               nh_family = AF_INET;
+                       else
+                               nh_family = AF_INET6;
                        inet_ntop(nh_family, &api_nh->gate, nh_buf,
                                  sizeof(nh_buf));
 
@@ -1317,10 +1309,8 @@ static void bgp_redist_del(struct bgp *bgp, afi_t afi, u_char type,
        if (red) {
                listnode_delete(bgp->redist[afi][type], red);
                XFREE(MTYPE_BGP_REDIST, red);
-               if (!bgp->redist[afi][type]->count) {
-                       list_free(bgp->redist[afi][type]);
-                       bgp->redist[afi][type] = NULL;
-               }
+               if (!bgp->redist[afi][type]->count)
+                       list_delete_and_null(&bgp->redist[afi][type]);
        }
 }
 
@@ -1350,12 +1340,14 @@ int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type, u_short instance)
                vrf_bitmap_set(zclient->redist[afi][type], bgp->vrf_id);
        }
 
-       /* Don't try to register if we're not connected to Zebra or Zebra
-        * doesn't
-        * know of this instance.
+       /*
+        * Don't try to register if we're not connected to Zebra or Zebra
+        * doesn't know of this instance.
+        *
+        * When we come up later well resend if needed.
         */
        if (!bgp_install_info_to_zebra(bgp))
-               return CMD_WARNING_CONFIG_FAILED;
+               return CMD_SUCCESS;
 
        if (BGP_DEBUG(zebra, ZEBRA))
                zlog_debug("Tx redistribute add VRF %u afi %d %s %d",
@@ -1760,13 +1752,15 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient,
                return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip);
 }
 
+extern struct zebra_privs_t bgpd_privs;
+
 void bgp_zebra_init(struct thread_master *master)
 {
        zclient_num_connects = 0;
 
        /* Set default values. */
-       zclient = zclient_new(master);
-       zclient_init(zclient, ZEBRA_ROUTE_BGP, 0);
+       zclient = zclient_new_notify(master, &zclient_options_default);
+       zclient_init(zclient, ZEBRA_ROUTE_BGP, 0, &bgpd_privs);
        zclient->zebra_connected = bgp_zebra_connected;
        zclient->router_id_update = bgp_router_id_update;
        zclient->interface_add = bgp_interface_add;