From: Dinesh Dutt <[email protected]>

With recursive routes, the ability to set the source IP address of a route
via a routemap has been broken. This patch fixes that.

To allow route map to set a source and then to unapply the route map and
have the source be taken out, I've introduced a new field in the nexthop
data structure called rmap_src. This field is zero'd before invoking the
route map apply function.

Today, no protocol daemon specifies the src in its route update to zebra.
If that happens, I didn't want to stomp on it and so have left the src
field intact instead of reusing that for the routemap to play with.

Signed-off-by: Dinesh G Dutt <[email protected]>
---
 lib/nexthop.h          |  1 +
 zebra/rt_netlink.c     | 82 ++++++++++++++++++++++++++++++++++++++++++--------
 zebra/zebra_rib.c      | 13 +++++++-
 zebra/zebra_routemap.c |  2 +-
 4 files changed, 83 insertions(+), 15 deletions(-)

diff --git a/lib/nexthop.h b/lib/nexthop.h
index 2c317bf..0a3388c 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -69,6 +69,7 @@ struct nexthop
   /* Nexthop address */
   union g_addr gate;
   union g_addr src;
+  union g_addr rmap_src;       /* Src is set via routemap */
 
   /* Nexthops obtained by recursive resolution.
    *
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 5f2bbd8..ca0871a 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -1422,7 +1422,8 @@ _netlink_route_build_singlepath(
         struct nexthop *nexthop,
         struct nlmsghdr *nlmsg,
         struct rtmsg *rtmsg,
-        size_t req_size)
+        size_t req_size,
+       int cmd)
 {
   if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK))
     rtmsg->rtm_flags |= RTNH_F_ONLINK;
@@ -1431,7 +1432,11 @@ _netlink_route_build_singlepath(
     {
       addattr_l (nlmsg, req_size, RTA_GATEWAY,
                  &nexthop->gate.ipv4, bytelen);
-      if (nexthop->src.ipv4.s_addr)
+
+      if (nexthop->rmap_src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
+        addattr_l (nlmsg, req_size, RTA_PREFSRC,
+                   &nexthop->rmap_src.ipv4, bytelen);
+      else if (nexthop->src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
         addattr_l (nlmsg, req_size, RTA_PREFSRC,
                    &nexthop->src.ipv4, bytelen);
 
@@ -1464,7 +1469,10 @@ _netlink_route_build_singlepath(
     {
       addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
 
-      if (nexthop->src.ipv4.s_addr)
+      if (nexthop->rmap_src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
+        addattr_l (nlmsg, req_size, RTA_PREFSRC,
+                   &nexthop->rmap_src.ipv4, bytelen);
+      else if (nexthop->src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
         addattr_l (nlmsg, req_size, RTA_PREFSRC,
                    &nexthop->src.ipv4, bytelen);
 
@@ -1525,8 +1533,10 @@ _netlink_route_build_multipath(
                      &nexthop->gate.ipv4, bytelen);
       rtnh->rtnh_len += sizeof (struct rtattr) + bytelen;
 
-      if (nexthop->src.ipv4.s_addr)
-        *src = &nexthop->src;
+      if (nexthop->rmap_src.ipv4.s_addr)
+        *src = &nexthop->rmap_src;
+      else if (nexthop->src.ipv4.s_addr)
+         *src = &nexthop->src;
 
       if (IS_ZEBRA_DEBUG_KERNEL)
         zlog_debug("netlink_route_multipath() (%s): "
@@ -1558,8 +1568,12 @@ _netlink_route_build_multipath(
       || nexthop->type == NEXTHOP_TYPE_IFNAME)
     {
       rtnh->rtnh_ifindex = nexthop->ifindex;
-      if (nexthop->src.ipv4.s_addr)
+
+      if (nexthop->rmap_src.ipv4.s_addr)
+        *src = &nexthop->rmap_src;
+      else if (nexthop->src.ipv4.s_addr)
         *src = &nexthop->src;
+
       if (IS_ZEBRA_DEBUG_KERNEL)
         zlog_debug("netlink_route_multipath() (%s): "
                    "nexthop via if %u", routedesc, nexthop->ifindex);
@@ -1622,6 +1636,8 @@ netlink_route_multipath (int cmd, struct prefix *p, 
struct rib *rib,
   int nexthop_num;
   int discard;
   const char *routedesc;
+  int setsrc = 0;
+  union g_addr src;
 
   struct
   {
@@ -1725,7 +1741,23 @@ netlink_route_multipath (int cmd, struct prefix *p, 
struct rib *rib,
       for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
         {
           if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
-            continue;
+            {
+              /* This only works for IPv4 now */
+              if (!setsrc)
+                 {
+                  if (nexthop->rmap_src.ipv4.s_addr != 0)
+                    {
+                      src.ipv4 = nexthop->rmap_src.ipv4;
+                      setsrc = 1;
+                    }
+                  else if (nexthop->src.ipv4.s_addr != 0)
+                    {
+                      src.ipv4 = nexthop->src.ipv4;
+                      setsrc = 1;
+                    }
+                 }
+              continue;
+           }
 
           if ((cmd == RTM_NEWROUTE
                && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
@@ -1737,7 +1769,7 @@ netlink_route_multipath (int cmd, struct prefix *p, 
struct rib *rib,
               _netlink_route_debug(cmd, p, nexthop, routedesc, family, zvrf);
               _netlink_route_build_singlepath(routedesc, bytelen,
                                               nexthop, &req.n, &req.r,
-                                              sizeof req);
+                                              sizeof req, cmd);
 
               if (cmd == RTM_NEWROUTE)
                 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
@@ -1746,13 +1778,15 @@ netlink_route_multipath (int cmd, struct prefix *p, 
struct rib *rib,
               break;
             }
         }
+      if (setsrc && (cmd == RTM_NEWROUTE))
+       addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen);
     }
   else
     {
       char buf[NL_PKT_BUF_SIZE];
       struct rtattr *rta = (void *) buf;
       struct rtnexthop *rtnh;
-      union g_addr *src = NULL;
+      union g_addr *src1 = NULL;
 
       rta->rta_type = RTA_MULTIPATH;
       rta->rta_len = RTA_LENGTH (0);
@@ -1765,7 +1799,23 @@ netlink_route_multipath (int cmd, struct prefix *p, 
struct rib *rib,
             break;
 
           if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
-            continue;
+           {
+              /* This only works for IPv4 now */
+              if (!setsrc)
+                 {
+                  if (nexthop->rmap_src.ipv4.s_addr != 0)
+                    {
+                      src.ipv4 = nexthop->rmap_src.ipv4;
+                      setsrc = 1;
+                    }
+                  else if (nexthop->src.ipv4.s_addr != 0)
+                    {
+                      src.ipv4 = nexthop->src.ipv4;
+                      setsrc = 1;
+                    }
+                 }
+             continue;
+           }
 
           if ((cmd == RTM_NEWROUTE
                && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
@@ -1778,15 +1828,21 @@ netlink_route_multipath (int cmd, struct prefix *p, 
struct rib *rib,
               _netlink_route_debug(cmd, p, nexthop,
                                    routedesc, family, zvrf);
               _netlink_route_build_multipath(routedesc, bytelen,
-                                             nexthop, rta, rtnh, &src);
+                                             nexthop, rta, rtnh, &src1);
               rtnh = RTNH_NEXT (rtnh);
 
               if (cmd == RTM_NEWROUTE)
                 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+             if (!setsrc && src1)
+               {
+                 src.ipv4 = src1->ipv4;
+                 setsrc = 1;
+               }
             }
         }
-      if (src)
-        addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
+      if (setsrc && (cmd == RTM_NEWROUTE))
+       addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen);
 
       if (rta->rta_len > RTA_LENGTH (0))
         addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta),
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index c3df67b..a3b915b 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1110,6 +1110,9 @@ nexthop_active_check (struct route_node *rn, struct rib 
*rib,
   if (!family)
     family = info->afi;
 
+  memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
+  /* It'll get set if required inside */
+
   ret = zebra_route_map_check(family, rib->type, &rn->p, nexthop, rib->vrf_id);
   if (ret == RMAP_DENYMATCH)
     {
@@ -1121,6 +1124,7 @@ nexthop_active_check (struct route_node *rn, struct rib 
*rib,
        }
       UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
     }
+
   return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
 }
 
@@ -1137,6 +1141,7 @@ static int
 nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
 {
   struct nexthop *nexthop;
+  union g_addr prev_src;
   unsigned int prev_active, prev_index, new_active, old_num_nh;
 
   old_num_nh = rib->nexthop_active_num;
@@ -1146,12 +1151,18 @@ nexthop_active_update (struct route_node *rn, struct 
rib *rib, int set)
 
   for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
   {
+    /* No protocol daemon provides src and so we're skipping tracking it */
+    prev_src = nexthop->rmap_src;
     prev_active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
     prev_index = nexthop->ifindex;
     if ((new_active = nexthop_active_check (rn, rib, nexthop, set)))
       rib->nexthop_active_num++;
+    /* Don't allow src setting on IPv6 addr for now */
     if (prev_active != new_active ||
-       prev_index != nexthop->ifindex)
+       prev_index != nexthop->ifindex ||
+       ((nexthop->type >= NEXTHOP_TYPE_IFINDEX &&
+         nexthop->type < NEXTHOP_TYPE_IPV6) &&
+        prev_src.ipv4.s_addr != nexthop->rmap_src.ipv4.s_addr))
       SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
   }
 
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index 447863c..29fd60c 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -1312,7 +1312,7 @@ route_set_src (void *rule, struct prefix *prefix,
   if (type == RMAP_ZEBRA)
     {
       nh_data = (struct nh_rmap_obj *)object;
-      nh_data->nexthop->src = *(union g_addr *)rule;
+      nh_data->nexthop->rmap_src = *(union g_addr *)rule;
     }
   return RMAP_OKAY;
 }
-- 
1.9.1


_______________________________________________
Quagga-dev mailing list
[email protected]
https://lists.quagga.net/mailman/listinfo/quagga-dev

Reply via email to