]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: Handle kernel routes appropriately
authorDonald Sharp <sharpd@nvidia.com>
Fri, 7 Jun 2024 17:50:07 +0000 (13:50 -0400)
committerDonald Sharp <sharpd@nvidia.com>
Tue, 27 Aug 2024 10:25:34 +0000 (06:25 -0400)
Current code intentionally ignores kernel routes.  Modify
zebra to allow these routes to be read in on linux.  Also
modify zebra to look to see if a route should be treated
as a connected and mark it as such.

Additionally this should properly handle some of the issues
being seen with NOPREFIXROUTE.

Signed-off-by: Donald Sharp <sharpd@nvidia.com>
zebra/interface.c
zebra/rib.h
zebra/rt_netlink.c
zebra/zebra_rib.c

index 03b710e1a0f91ff08242d40af2f6e5f933c93410..d146004781a53ad0edd20eafa2f0c18d3167344d 100644 (file)
@@ -1058,6 +1058,8 @@ void if_down(struct interface *ifp)
 
        /* Delete all neighbor addresses learnt through IPv6 RA */
        if_down_del_nbr_connected(ifp);
+
+       rib_update_handle_vrf_all(RIB_UPDATE_INTERFACE_DOWN, ZEBRA_ROUTE_KERNEL);
 }
 
 void if_refresh(struct interface *ifp)
index 8792fb7908acce988a755687a0794298497f07f8..cd6efbfb36dd97e8fe958bfd0e9e0a24a9dde5e0 100644 (file)
@@ -326,6 +326,7 @@ typedef struct rib_tables_iter_t_ {
 
 /* Events/reasons triggering a RIB update. */
 enum rib_update_event {
+       RIB_UPDATE_INTERFACE_DOWN,
        RIB_UPDATE_KERNEL,
        RIB_UPDATE_RMAP_CHANGE,
        RIB_UPDATE_OTHER,
index c22145be693b368ec804beb30404d4ec60e22914..ddcb83cd8ce7e48bd9c4e24084146df12ebc317f 100644 (file)
@@ -799,8 +799,6 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
                return 0;
        if (rtm->rtm_protocol == RTPROT_REDIRECT)
                return 0;
-       if (rtm->rtm_protocol == RTPROT_KERNEL)
-               return 0;
 
        selfroute = is_selfroute(rtm->rtm_protocol);
 
index 649450b5c63c464812449c0d9f3d2a3da6100e62..2d6c5148833afab15d2d80b3d1f4cb817e02fe5c 100644 (file)
@@ -1619,6 +1619,10 @@ static bool rib_compare_routes(const struct route_entry *re1,
         * v6 link-locals, and we also support multiple addresses in the same
         * subnet on a single interface.
         */
+       if (re1->type == ZEBRA_ROUTE_CONNECT &&
+           (re1->nhe->nhg.nexthop->ifindex == re2->nhe->nhg.nexthop->ifindex))
+               return true;
+
        if (re1->type != ZEBRA_ROUTE_CONNECT && re1->type != ZEBRA_ROUTE_LOCAL)
                return true;
 
@@ -2863,10 +2867,11 @@ static void process_subq_early_route_add(struct zebra_early_route *ere)
 
        /* Link new re to node.*/
        if (IS_ZEBRA_DEBUG_RIB) {
-               rnode_debug(
-                       rn, re->vrf_id,
-                       "Inserting route rn %p, re %p (%s) existing %p, same_count %d",
-                       rn, re, zebra_route_string(re->type), same, same_count);
+               rnode_debug(rn, re->vrf_id,
+                           "Inserting route rn %p, re %p (%s/%s/%s) existing %p, same_count %d",
+                           rn, re, zebra_route_string(re->type),
+                           afi2str(ere->afi), safi2str(ere->safi), same,
+                           same_count);
 
                if (IS_ZEBRA_DEBUG_RIB_DETAILED)
                        route_entry_dump(
@@ -4383,6 +4388,34 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
                nhe.id = re->nhe_id;
 
        n = zebra_nhe_copy(&nhe, 0);
+
+       if (re->type == ZEBRA_ROUTE_KERNEL) {
+               struct interface *ifp;
+               struct connected *connected;
+
+               if (p->family == AF_INET6 &&
+                   IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) {
+                       zebra_nhg_free(n);
+                       zebra_rib_route_entry_free(re);
+                       return -1;
+               }
+
+               ifp = if_lookup_prefix(p, re->vrf_id);
+               if (ifp) {
+                       connected = connected_lookup_prefix(ifp, p);
+
+                       if (connected && !CHECK_FLAG(connected->flags,
+                                                    ZEBRA_IFA_NOPREFIXROUTE)) {
+                               zebra_nhg_free(n);
+                               zebra_rib_route_entry_free(re);
+                               return -1;
+                       }
+
+                       if (ifp->ifindex == ng->nexthop->ifindex)
+                               re->type = ZEBRA_ROUTE_CONNECT;
+               }
+       }
+
        ret = rib_add_multipath_nhe(afi, safi, p, src_p, re, n, startup);
 
        /* In error cases, free the route also */
@@ -4458,6 +4491,9 @@ static const char *rib_update_event2str(enum rib_update_event event)
        const char *ret = "UNKNOWN";
 
        switch (event) {
+       case RIB_UPDATE_INTERFACE_DOWN:
+               ret = "RIB_UPDATE_INTERFACE_DOWN";
+               break;
        case RIB_UPDATE_KERNEL:
                ret = "RIB_UPDATE_KERNEL";
                break;
@@ -4474,15 +4510,56 @@ static const char *rib_update_event2str(enum rib_update_event event)
        return ret;
 }
 
+/*
+ * We now keep kernel routes, but we don't have any
+ * trigger events for them when they are implicitly
+ * deleted.  Since we are already walking the
+ * entire table on a down event let's look at
+ * the few kernel routes we may have
+ */
+static void
+rib_update_handle_kernel_route_down_possibility(struct route_node *rn,
+                                               struct route_entry *re)
+{
+       struct nexthop *nexthop = NULL;
+       bool alive = false;
+
+       for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
+               struct interface *ifp = if_lookup_by_index(nexthop->ifindex,
+                                                          nexthop->vrf_id);
+
+               if (ifp && if_is_up(ifp)) {
+                       alive = true;
+                       break;
+               }
+       }
+
+       if (!alive) {
+               struct rib_table_info *rib_table = srcdest_rnode_table_info(rn);
+               const struct prefix *p;
+               const struct prefix_ipv6 *src_p;
+
+               srcdest_rnode_prefixes(rn, &p, (const struct prefix **)&src_p);
+
+               rib_delete(rib_table->afi, rib_table->safi, re->vrf_id,
+                          re->type, re->instance, re->flags, p, src_p, NULL, 0,
+                          re->table, re->metric, re->distance, true);
+       }
+}
+
 
 /* Schedule route nodes to be processed if they match the type */
-static void rib_update_route_node(struct route_node *rn, int type)
+static void rib_update_route_node(struct route_node *rn, int type,
+                                 enum rib_update_event event)
 {
        struct route_entry *re, *next;
        bool re_changed = false;
 
        RNODE_FOREACH_RE_SAFE (rn, re, next) {
-               if (type == ZEBRA_ROUTE_ALL || type == re->type) {
+               if (event == RIB_UPDATE_INTERFACE_DOWN && type == re->type &&
+                   type == ZEBRA_ROUTE_KERNEL)
+                       rib_update_handle_kernel_route_down_possibility(rn, re);
+               else if (type == ZEBRA_ROUTE_ALL || type == re->type) {
                        SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
                        re_changed = true;
                }
@@ -4522,20 +4599,24 @@ void rib_update_table(struct route_table *table, enum rib_update_event event,
                /*
                 * If we are looking at a route node and the node
                 * has already been queued  we don't
-                * need to queue it up again
+                * need to queue it up again, unless it is
+                * an interface down event as that we need
+                * to process this no matter what.
                 */
-               if (rn->info
-                   && CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
-                                 RIB_ROUTE_ANY_QUEUED))
+               if (rn->info &&
+                   CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
+                              RIB_ROUTE_ANY_QUEUED) &&
+                   event != RIB_UPDATE_INTERFACE_DOWN)
                        continue;
 
                switch (event) {
+               case RIB_UPDATE_INTERFACE_DOWN:
                case RIB_UPDATE_KERNEL:
-                       rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL);
+                       rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL, event);
                        break;
                case RIB_UPDATE_RMAP_CHANGE:
                case RIB_UPDATE_OTHER:
-                       rib_update_route_node(rn, rtype);
+                       rib_update_route_node(rn, rtype, event);
                        break;
                case RIB_UPDATE_MAX:
                        break;