]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #3477 from donaldsharp/multipath_respect
authorRuss White <russ@riw.us>
Thu, 13 Dec 2018 15:41:26 +0000 (10:41 -0500)
committerGitHub <noreply@github.com>
Thu, 13 Dec 2018 15:41:26 +0000 (10:41 -0500)
zebra: Allow zebra to only mark up to multipath_num nexthops as ACTIVE

lib/zebra.h
zebra/kernel_socket.c
zebra/rib.h
zebra/zebra_rib.c
zebra/zebra_rnh.c

index 46721cc1ab6d32c7b146f8387efc4fa6cf748a22..0f3f45f7ba1807a8344e47ba95c5f769c2ede43e 100644 (file)
@@ -410,18 +410,47 @@ extern const char *zserv_command_string(unsigned int command);
 #define strmatch(a,b) (!strcmp((a), (b)))
 
 /* Zebra message flags */
+
+/*
+ * Cause Zebra to consider this routes nexthops recursively
+ */
 #define ZEBRA_FLAG_ALLOW_RECURSION    0x01
+/*
+ * This is a route that is read in on startup that was left around
+ * from a previous run of FRR
+ */
 #define ZEBRA_FLAG_SELFROUTE          0x02
-#define ZEBRA_FLAG_IBGP               0x08
-#define ZEBRA_FLAG_SELECTED           0x10
-#define ZEBRA_FLAG_STATIC             0x40
-#define ZEBRA_FLAG_SCOPE_LINK         0x100
-#define ZEBRA_FLAG_FIB_OVERRIDE       0x200
-#define ZEBRA_FLAG_EVPN_ROUTE         0x400
-#define ZEBRA_FLAG_RR_USE_DISTANCE    0x800
-#define ZEBRA_FLAG_ONLINK             0x1000
-/* ZEBRA_FLAG_BLACKHOLE was 0x04 */
-/* ZEBRA_FLAG_REJECT was 0x80 */
+/*
+ * This flag is used to tell Zebra that the BGP route being passed
+ * down is a IBGP route
+ */
+#define ZEBRA_FLAG_IBGP               0x04
+/*
+ * This is a route that has been selected for FIB installation.
+ * This flag is set in zebra and can be passed up to routing daemons
+ */
+#define ZEBRA_FLAG_SELECTED           0x08
+/*
+ * This is a route that we are telling Zebra that this route *must*
+ * win and will be installed even over ZEBRA_FLAG_SELECTED
+ */
+#define ZEBRA_FLAG_FIB_OVERRIDE       0x10
+/*
+ * This flag tells Zebra that the route is a EVPN route and should
+ * be treated specially
+ */
+#define ZEBRA_FLAG_EVPN_ROUTE         0x20
+/*
+ * This flag tells Zebra that it should treat the distance passed
+ * down as an additional discriminator for route selection of the
+ * route entry.  This mainly is used for backup static routes.
+ */
+#define ZEBRA_FLAG_RR_USE_DISTANCE    0x40
+/*
+ * This flag tells Zebra that the passed down route is ONLINK and the
+ * kernel install flag for it should be turned on
+ */
+#define ZEBRA_FLAG_ONLINK             0x80
 
 /* Zebra FEC flags. */
 #define ZEBRA_FEC_REGISTER_LABEL_INDEX        0x1
index 8a7cb0e5284cee64eeb96b65c16fd6934a0db32b..4f89d53e399cdbf19e3eb581af5ed288b1d831ec 100644 (file)
@@ -918,6 +918,9 @@ void rtm_read(struct rt_msghdr *rtm)
        char ifname[INTERFACE_NAMSIZ + 1];
        short ifnlen = 0;
        struct nexthop nh;
+       struct prefix p;
+       ifindex_t ifindex = 0;
+       afi_t afi;
 
        zebra_flags = 0;
 
@@ -951,10 +954,6 @@ void rtm_read(struct rt_msghdr *rtm)
        if (flags & RTF_PROTO1)
                SET_FLAG(zebra_flags, ZEBRA_FLAG_SELFROUTE);
 
-       /* This is persistent route. */
-       if (flags & RTF_STATIC)
-               SET_FLAG(zebra_flags, ZEBRA_FLAG_STATIC);
-
        memset(&nh, 0, sizeof(nh));
 
        nh.vrf_id = VRF_DEFAULT;
@@ -967,9 +966,14 @@ void rtm_read(struct rt_msghdr *rtm)
                nh.bh_type = BLACKHOLE_NULL;
        }
 
-       if (dest.sa.sa_family == AF_INET) {
-               struct prefix p;
+       /*
+        * Ignore our own messages.
+        */
+       if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid)
+               return;
 
+       if (dest.sa.sa_family == AF_INET) {
+               afi = AFI_IP;
                p.family = AF_INET;
                p.u.prefix4 = dest.sin.sin_addr;
                if (flags & RTF_HOST)
@@ -977,146 +981,12 @@ void rtm_read(struct rt_msghdr *rtm)
                else
                        p.prefixlen = ip_masklen(mask.sin.sin_addr);
 
-               /* Catch self originated messages and match them against our
-                * current RIB.
-                * At the same time, ignore unconfirmed messages, they should be
-                * tracked
-                * by rtm_write() and kernel_rtm_ipv4().
-                */
-               if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid) {
-                       char buf[PREFIX_STRLEN], gate_buf[INET_ADDRSTRLEN];
-                       int ret;
-                       if (!IS_ZEBRA_DEBUG_RIB)
-                               return;
-                       ret = rib_lookup_ipv4_route((struct prefix_ipv4 *)&p,
-                                                   &gate, VRF_DEFAULT);
-                       prefix2str(&p, buf, sizeof(buf));
-                       switch (rtm->rtm_type) {
-                       case RTM_ADD:
-                       case RTM_GET:
-                       case RTM_CHANGE:
-                               /* The kernel notifies us about a new route in
-                                  FIB created by us.
-                                  Do we have a correspondent entry in our RIB?
-                                  */
-                               switch (ret) {
-                               case ZEBRA_RIB_NOTFOUND:
-                                       zlog_debug(
-                                               "%s: %s %s: desync: RR isn't yet in RIB, while already in FIB",
-                                               __func__,
-                                               lookup_msg(rtm_type_str,
-                                                          rtm->rtm_type, NULL),
-                                               buf);
-                                       break;
-                               case ZEBRA_RIB_FOUND_CONNECTED:
-                               case ZEBRA_RIB_FOUND_NOGATE:
-                                       inet_ntop(AF_INET, &gate.sin.sin_addr,
-                                                 gate_buf, INET_ADDRSTRLEN);
-                                       zlog_debug(
-                                               "%s: %s %s: desync: RR is in RIB, but gate differs (ours is %s)",
-                                               __func__,
-                                               lookup_msg(rtm_type_str,
-                                                          rtm->rtm_type, NULL),
-                                               buf, gate_buf);
-                                       break;
-                               case ZEBRA_RIB_FOUND_EXACT: /* RIB RR == FIB RR
-                                                              */
-                                       zlog_debug(
-                                               "%s: %s %s: done Ok", __func__,
-                                               lookup_msg(rtm_type_str,
-                                                          rtm->rtm_type, NULL),
-                                               buf);
-                                       rib_lookup_and_dump(
-                                               (struct prefix_ipv4 *)&p,
-                                               VRF_DEFAULT);
-                                       return;
-                                       break;
-                               }
-                               break;
-                       case RTM_DELETE:
-                               /* The kernel notifies us about a route deleted
-                                  by us. Do we still
-                                  have it in the RIB? Do we have anything
-                                  instead? */
-                               switch (ret) {
-                               case ZEBRA_RIB_FOUND_EXACT:
-                                       zlog_debug(
-                                               "%s: %s %s: desync: RR is still in RIB, while already not in FIB",
-                                               __func__,
-                                               lookup_msg(rtm_type_str,
-                                                          rtm->rtm_type, NULL),
-                                               buf);
-                                       rib_lookup_and_dump(
-                                               (struct prefix_ipv4 *)&p,
-                                               VRF_DEFAULT);
-                                       break;
-                               case ZEBRA_RIB_FOUND_CONNECTED:
-                               case ZEBRA_RIB_FOUND_NOGATE:
-                                       zlog_debug(
-                                               "%s: %s %s: desync: RR is still in RIB, plus gate differs",
-                                               __func__,
-                                               lookup_msg(rtm_type_str,
-                                                          rtm->rtm_type, NULL),
-                                               buf);
-                                       rib_lookup_and_dump(
-                                               (struct prefix_ipv4 *)&p,
-                                               VRF_DEFAULT);
-                                       break;
-                               case ZEBRA_RIB_NOTFOUND: /* RIB RR == FIB RR */
-                                       zlog_debug(
-                                               "%s: %s %s: done Ok", __func__,
-                                               lookup_msg(rtm_type_str,
-                                                          rtm->rtm_type, NULL),
-                                               buf);
-                                       rib_lookup_and_dump(
-                                               (struct prefix_ipv4 *)&p,
-                                               VRF_DEFAULT);
-                                       return;
-                                       break;
-                               }
-                               break;
-                       default:
-                               zlog_debug(
-                                       "%s: %s: warning: loopback RTM of type %s received",
-                                       __func__, buf,
-                                       lookup_msg(rtm_type_str, rtm->rtm_type,
-                                                  NULL));
-                       }
-                       return;
-               }
-
-               /* Change, delete the old prefix, we have no further information
-                * to specify the route really
-                */
-               if (rtm->rtm_type == RTM_CHANGE)
-                       rib_delete(AFI_IP, SAFI_UNICAST, VRF_DEFAULT,
-                                  ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
-                                  NULL, 0, 0, 0, true);
-
                if (!nh.type) {
                        nh.type = NEXTHOP_TYPE_IPV4;
                        nh.gate.ipv4 = gate.sin.sin_addr;
                }
-
-               if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD
-                   || rtm->rtm_type == RTM_CHANGE)
-                       rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT,
-                               ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
-                               &nh, 0, 0, 0, 0, 0);
-               else
-                       rib_delete(AFI_IP, SAFI_UNICAST, VRF_DEFAULT,
-                                  ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
-                                  &nh, 0, 0, 0, true);
-       }
-       if (dest.sa.sa_family == AF_INET6) {
-               /* One day we might have a debug section here like one in the
-                * IPv4 case above. Just ignore own messages at the moment.
-                */
-               if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid)
-                       return;
-               struct prefix p;
-               ifindex_t ifindex = 0;
-
+       } else if (dest.sa.sa_family == AF_INET6) {
+               afi = AFI_IP6;
                p.family = AF_INET6;
                p.u.prefix6 = dest.sin6.sin6_addr;
                if (flags & RTF_HOST)
@@ -1131,31 +1001,29 @@ void rtm_read(struct rt_msghdr *rtm)
                }
 #endif /* KAME */
 
-               /* CHANGE: delete the old prefix, we have no further information
-                * to specify the route really
-                */
-               if (rtm->rtm_type == RTM_CHANGE)
-                       rib_delete(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT,
-                                  ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
-                                  NULL, 0, 0, 0, true);
-
                if (!nh.type) {
                        nh.type = ifindex ? NEXTHOP_TYPE_IPV6_IFINDEX
                                          : NEXTHOP_TYPE_IPV6;
                        nh.gate.ipv6 = gate.sin6.sin6_addr;
                        nh.ifindex = ifindex;
                }
+       } else
+               return;
 
-               if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD
-                   || rtm->rtm_type == RTM_CHANGE)
-                       rib_add(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT,
-                               ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
-                               &nh, 0, 0, 0, 0, 0);
-               else
-                       rib_delete(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT,
-                                  ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
-                                  &nh, 0, 0, 0, true);
-       }
+       /*
+        * CHANGE: delete the old prefix, we have no further information
+        * to specify the route really
+        */
+       if (rtm->rtm_type == RTM_CHANGE)
+               rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL,
+                          0, zebra_flags, &p, NULL, NULL, 0, 0, 0, true);
+       if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD
+           || rtm->rtm_type == RTM_CHANGE)
+               rib_add(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0,
+                       zebra_flags, &p, NULL, &nh, 0, 0, 0, 0, 0);
+       else
+               rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL,
+                          0, zebra_flags, &p, NULL, &nh, 0, 0, 0, true);
 }
 
 /* Interface function for the kernel routing table updates.  Support
index 97eae79f03c276cf0289d344e3e4f8ae28749383..ae25a0e67980acd6593863782c42d039938197fa 100644 (file)
@@ -282,8 +282,6 @@ extern enum multicast_mode multicast_mode_ipv4_get(void);
 extern void rib_lookup_and_dump(struct prefix_ipv4 *p, vrf_id_t vrf_id);
 extern void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id);
 
-extern int rib_lookup_ipv4_route(struct prefix_ipv4 *p, union sockunion *qgate,
-                                vrf_id_t vrf_id);
 #define ZEBRA_RIB_LOOKUP_ERROR -1
 #define ZEBRA_RIB_FOUND_EXACT 0
 #define ZEBRA_RIB_FOUND_NOGATE 1
index 2dfeb269158460d205910dc1bb90f5cefbf07b00..d628b801a59d31be577eb54c04c0dc25bc1c12f2 100644 (file)
@@ -808,84 +808,6 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id)
        return NULL;
 }
 
-/*
- * This clone function, unlike its original rib_lookup_ipv4(), checks
- * if specified IPv4 route record (prefix/mask -> gate) exists in
- * the whole RIB and has ROUTE_ENTRY_SELECTED_FIB set.
- *
- * Return values:
- * -1: error
- * 0: exact match found
- * 1: a match was found with a different gate
- * 2: connected route found
- * 3: no matches found
- */
-int rib_lookup_ipv4_route(struct prefix_ipv4 *p, union sockunion *qgate,
-                         vrf_id_t vrf_id)
-{
-       struct route_table *table;
-       struct route_node *rn;
-       struct route_entry *match = NULL;
-       struct nexthop *nexthop;
-       int nexthops_active;
-       rib_dest_t *dest;
-
-       /* Lookup table.  */
-       table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id);
-       if (!table)
-               return ZEBRA_RIB_LOOKUP_ERROR;
-
-       /* Scan the RIB table for exactly matching RIB entry. */
-       rn = route_node_lookup(table, (struct prefix *)p);
-
-       /* No route for this prefix. */
-       if (!rn)
-               return ZEBRA_RIB_NOTFOUND;
-
-       /* Unlock node. */
-       route_unlock_node(rn);
-       dest = rib_dest_from_rnode(rn);
-
-       /* Find out if a "selected" RR for the discovered RIB entry exists ever.
-        */
-       if (dest && dest->selected_fib
-           && !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED))
-               match = dest->selected_fib;
-
-       /* None such found :( */
-       if (!match)
-               return ZEBRA_RIB_NOTFOUND;
-
-       if (match->type == ZEBRA_ROUTE_CONNECT)
-               return ZEBRA_RIB_FOUND_CONNECTED;
-
-       /* Ok, we have a cood candidate, let's check it's nexthop list... */
-       nexthops_active = 0;
-       for (ALL_NEXTHOPS(match->ng, nexthop))
-               if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
-                       nexthops_active = 1;
-                       if (nexthop->gate.ipv4.s_addr == sockunion2ip(qgate))
-                               return ZEBRA_RIB_FOUND_EXACT;
-                       if (IS_ZEBRA_DEBUG_RIB) {
-                               char gate_buf[INET_ADDRSTRLEN],
-                                       qgate_buf[INET_ADDRSTRLEN];
-                               inet_ntop(AF_INET, &nexthop->gate.ipv4.s_addr,
-                                         gate_buf, INET_ADDRSTRLEN);
-                               inet_ntop(AF_INET, &sockunion2ip(qgate),
-                                         qgate_buf, INET_ADDRSTRLEN);
-                               zlog_debug("%s: qgate == %s, %s == %s",
-                                          __func__, qgate_buf,
-                                          nexthop->rparent ? "rgate" : "gate",
-                                          gate_buf);
-                       }
-               }
-
-       if (nexthops_active)
-               return ZEBRA_RIB_FOUND_NOGATE;
-
-       return ZEBRA_RIB_NOTFOUND;
-}
-
 #define RIB_SYSTEM_ROUTE(R)                                                    \
        ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT)
 
index e92cd8bb8a2511fec930a73ef1b4c3e7598dc55a..b1fbe8a6536de6dbdf2bf91b6f520ec8664a7266 100644 (file)
@@ -528,8 +528,7 @@ static void zebra_rnh_process_pbr_tables(int family,
  */
 static bool rnh_nexthop_valid(const struct nexthop *nh)
 {
-       return ((CHECK_FLAG(nh->flags, NEXTHOP_FLAG_FIB)
-                || CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
+       return (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_FIB)
                && CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE));
 }
 
@@ -581,8 +580,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, int family,
                        /* Just being SELECTED isn't quite enough - must
                         * have an installed nexthop to be useful.
                         */
-                       for (nexthop = re->ng.nexthop; nexthop;
-                            nexthop = nexthop->next) {
+                       for (ALL_NEXTHOPS(re->ng, nexthop)) {
                                if (rnh_nexthop_valid(nexthop))
                                        break;
                        }
@@ -915,7 +913,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
                num = 0;
                nump = stream_get_endp(s);
                stream_putc(s, 0);
-               for (nh = re->ng.nexthop; nh; nh = nh->next)
+               for (ALL_NEXTHOPS(re->ng, nh))
                        if (rnh_nexthop_valid(nh)) {
                                stream_putl(s, nh->vrf_id);
                                stream_putc(s, nh->type);