]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: add srcdest support to rib
authorChristian Franke <chris@opensourcerouting.org>
Mon, 5 Dec 2016 19:05:30 +0000 (20:05 +0100)
committerChristian Franke <chris@opensourcerouting.org>
Mon, 30 Jan 2017 12:54:46 +0000 (13:54 +0100)
Add srcdest support to the zebra rib and to the kernel
and redistribution interfaces.

Signed-off-by: Christian Franke <chris@opensourcerouting.org>
14 files changed:
zebra/kernel_null.c
zebra/redistribute.c
zebra/redistribute.h
zebra/redistribute_null.c
zebra/rib.h
zebra/rt.h
zebra/rt_netlink.c
zebra/rt_socket.c
zebra/zebra_rib.c
zebra/zebra_static.c
zebra/zebra_vrf.c
zebra/zebra_vty.c
zebra/zserv.c
zebra/zserv.h

index 896ca96b487f8038e3b9839ae0c6920578b08707..fea79ffe8cabe10118196da58e0f3851e5ab4f92 100644 (file)
@@ -32,7 +32,8 @@
 #include "zebra/rt_netlink.h"
 #include "zebra/rib.h"
 
-int kernel_route_rib (struct prefix *a, struct rib *old, struct rib *new) { return 0; }
+int kernel_route_rib (struct prefix *a, struct prefix *b,
+                      struct rib *old, struct rib *new) { return 0; }
 
 int kernel_address_add_ipv4 (struct interface *a, struct connected *b)
 {
index 435122cfe704b440519a4343c6d9365a0c02b3bf..c7ed209d3c862b0cb61dd7a67cfccfdf122c5683 100644 (file)
@@ -31,6 +31,7 @@
 #include "linklist.h"
 #include "log.h"
 #include "vrf.h"
+#include "srcdest_table.h"
 
 #include "zebra/rib.h"
 #include "zebra/zserv.h"
@@ -98,7 +99,7 @@ zebra_redistribute_default (struct zserv *client, vrf_id_t vrf_id)
       RNODE_FOREACH_RIB (rn, newrib)
        if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
            && newrib->distance != DISTANCE_INFINITY)
-         zsend_redistribute_route (1, client, &rn->p, newrib);
+         zsend_redistribute_route (1, client, &rn->p, NULL, newrib);
 
       route_unlock_node (rn);
     }
@@ -122,12 +123,15 @@ zebra_redistribute (struct zserv *client, int type, u_short instance, vrf_id_t v
       for (rn = route_top (table); rn; rn = route_next (rn))
        RNODE_FOREACH_RIB (rn, newrib)
          {
+           struct prefix *dst_p, *src_p;
+           srcdest_rnode_prefixes(rn, &dst_p, &src_p);
+
            if (IS_ZEBRA_DEBUG_EVENT)
              zlog_debug("%s: checking: selected=%d, type=%d, distance=%d, "
                         "zebra_check_addr=%d", __func__,
                         CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED),
                         newrib->type, newrib->distance,
-                        zebra_check_addr (&rn->p));
+                        zebra_check_addr (dst_p));
 
            if (! CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED))
              continue;
@@ -136,10 +140,10 @@ zebra_redistribute (struct zserv *client, int type, u_short instance, vrf_id_t v
              continue;
            if (newrib->distance == DISTANCE_INFINITY)
              continue;
-           if (! zebra_check_addr (&rn->p))
+           if (! zebra_check_addr (dst_p))
              continue;
 
-           zsend_redistribute_route (1, client, &rn->p, newrib);
+           zsend_redistribute_route (1, client, dst_p, src_p, newrib);
          }
     }
 }
@@ -147,7 +151,8 @@ zebra_redistribute (struct zserv *client, int type, u_short instance, vrf_id_t v
 /* Either advertise a route for redistribution to registered clients or */
 /* withdraw redistribution if add cannot be done for client */
 void
-redistribute_update (struct prefix *p, struct rib *rib, struct rib *prev_rib)
+redistribute_update (struct prefix *p, struct prefix *src_p,
+                     struct rib *rib, struct rib *prev_rib)
 {
   struct listnode *node, *nnode;
   struct zserv *client;
@@ -186,7 +191,7 @@ redistribute_update (struct prefix *p, struct rib *rib, struct rib *prev_rib)
 
       if (send_redistribute)
        {
-         zsend_redistribute_route (1, client, p, rib);
+         zsend_redistribute_route (1, client, p, src_p, rib);
        }
       else if (prev_rib &&
               ((rib->instance &&
@@ -194,13 +199,13 @@ redistribute_update (struct prefix *p, struct rib *rib, struct rib *prev_rib)
                                       rib->instance)) ||
                 vrf_bitmap_check (client->redist[afi][prev_rib->type], rib->vrf_id))) 
        {
-         zsend_redistribute_route (0, client, p, prev_rib);
+         zsend_redistribute_route (0, client, p, src_p, prev_rib);
        }
     }
 }
 
 void
-redistribute_delete (struct prefix *p, struct rib *rib)
+redistribute_delete (struct prefix *p, struct prefix *src_p, struct rib *rib)
 {
   struct listnode *node, *nnode;
   struct zserv *client;
@@ -235,7 +240,7 @@ redistribute_delete (struct prefix *p, struct rib *rib)
                                  rib->instance)) ||
           vrf_bitmap_check (client->redist[afi][rib->type], rib->vrf_id))
        {
-         zsend_redistribute_route (0, client, p, rib);
+         zsend_redistribute_route (0, client, p, src_p, rib);
        }
     }
 }
index e3bce7af4665ef3678d847c31f6c96904522d5d8..06afc726d155894a2762cd17e58d0512ea875a50 100644 (file)
@@ -36,8 +36,9 @@ extern void zebra_redistribute_default_add (int, struct zserv *, int,
 extern void zebra_redistribute_default_delete (int, struct zserv *, int,
                                               struct zebra_vrf *zvrf);
 
-extern void redistribute_update (struct prefix *, struct rib *, struct rib *);
-extern void redistribute_delete (struct prefix *, struct rib *);
+extern void redistribute_update (struct prefix *, struct prefix *,
+                                 struct rib *, struct rib *);
+extern void redistribute_delete (struct prefix *, struct prefix *, struct rib *);
 
 extern void zebra_interface_up_update (struct interface *);
 extern void zebra_interface_down_update (struct interface *);
index 4446627dd332c826a34746815cd9d8eb4ee6948b..ffde8ed77386f24554da0526ca0802ccdd43d466 100644 (file)
@@ -39,9 +39,10 @@ void zebra_redistribute_default_delete (int a, struct zserv *b, int c,
                                        struct zebra_vrf *zvrf)
 { return; }
 
-void redistribute_update (struct prefix *a, struct rib *b, struct rib *c)
+void redistribute_update (struct prefix *a, struct prefix *b,
+                          struct rib *c, struct rib *d)
 { return; }
-void redistribute_delete (struct prefix *a, struct rib *b)
+void redistribute_delete (struct prefix *a, struct prefix *b, struct rib *c)
 { return; }
 
 void zebra_interface_up_update (struct interface *a)
index fceab93d1a2d1165ef4d1a426aa244847f3d756b..db564144160fc071f4a4e42dba1c2b51744f9bdd 100644 (file)
@@ -32,6 +32,7 @@
 #include "vrf.h"
 #include "if.h"
 #include "mpls.h"
+#include "srcdest_table.h"
 
 #define DISTANCE_INFINITY  255
 #define ZEBRA_KERNEL_TABLE_MAX 252 /* support for no more than this rt tables */
@@ -311,8 +312,9 @@ extern enum multicast_mode multicast_mode_ipv4_get (void);
 extern int nexthop_has_fib_child(struct nexthop *);
 extern void rib_lookup_and_dump (struct prefix_ipv4 *, vrf_id_t);
 extern void rib_lookup_and_pushup (struct prefix_ipv4 *, vrf_id_t);
-#define rib_dump(prefix ,rib) _rib_dump(__func__, prefix, rib)
+#define rib_dump(prefix, src, rib) _rib_dump(__func__, prefix, src, rib)
 extern void _rib_dump (const char *,
+                      union prefix46constptr,
                       union prefix46constptr, const struct rib *);
 extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *,
                                   vrf_id_t);
@@ -444,7 +446,7 @@ rib_dest_af (rib_dest_t *dest)
 static inline struct route_table *
 rib_dest_table (rib_dest_t *dest)
 {
-  return dest->rnode->table;
+  return srcdest_rnode_table(dest->rnode);
 }
 
 /*
index 40beb6a45fb61ada3e61f42de3f6528a7171cf5a..75d234ce839c6f87f2000ab3dd190543370932d2 100644 (file)
@@ -29,7 +29,8 @@
 #include "zebra/zebra_ns.h"
 #include "zebra/zebra_mpls.h"
 
-extern int kernel_route_rib (struct prefix *, struct rib *, struct rib *);
+extern int kernel_route_rib (struct prefix *, struct prefix *,
+                             struct rib *, struct rib *);
 
 extern int kernel_address_add_ipv4 (struct interface *, struct connected *);
 extern int kernel_address_delete_ipv4 (struct interface *, struct connected *);
index 585b80f9794efad099e519ccaa9f5200f6ef8a03..17b5a6e6d831b47abd2b59538c281a517d0d05a9 100644 (file)
@@ -134,18 +134,20 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
   struct rtattr *tb[RTA_MAX + 1];
   u_char flags = 0;
   struct prefix p;
+  struct prefix_ipv6 src_p;
   vrf_id_t vrf_id = VRF_DEFAULT;
 
   char anyaddr[16] = { 0 };
 
-  int index;
+  int index = 0;
   int table;
-  int metric;
+  int metric = 0;
   u_int32_t mtu = 0;
 
-  void *dest;
-  void *gate;
-  void *src;
+  void *dest = NULL;
+  void *gate = NULL;
+  void *prefsrc = NULL;                /* IPv4 preferred source host address */
+  void *src = NULL;            /* IPv6 srcdest   source prefix */
 
   rtm = NLMSG_DATA (h);
 
@@ -168,9 +170,6 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
   if (rtm->rtm_protocol == RTPROT_KERNEL)
     return 0;
 
-  if (rtm->rtm_src_len != 0)
-    return 0;
-
   /* We don't care about change notifications for the MPLS table. */
   /* TODO: Revisit this. */
   if (rtm->rtm_family == AF_MPLS)
@@ -195,12 +194,6 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
   if (rtm->rtm_protocol == RTPROT_ZEBRA)
     flags |= ZEBRA_FLAG_SELFROUTE;
 
-  index = 0;
-  metric = 0;
-  dest = NULL;
-  gate = NULL;
-  src = NULL;
-
   if (tb[RTA_OIF])
     index = *(int *) RTA_DATA (tb[RTA_OIF]);
 
@@ -209,8 +202,13 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
   else
     dest = anyaddr;
 
+  if (tb[RTA_SRC])
+    src = RTA_DATA (tb[RTA_SRC]);
+  else
+    src = anyaddr;
+
   if (tb[RTA_PREFSRC])
-    src = RTA_DATA (tb[RTA_PREFSRC]);
+    prefsrc = RTA_DATA (tb[RTA_PREFSRC]);
 
   if (tb[RTA_GATEWAY])
     gate = RTA_DATA (tb[RTA_GATEWAY]);
@@ -236,9 +234,12 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
       memcpy (&p.u.prefix4, dest, 4);
       p.prefixlen = rtm->rtm_dst_len;
 
+      if (rtm->rtm_src_len != 0)
+       return 0;
+
       if (!tb[RTA_MULTIPATH])
        rib_add (AFI_IP, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
-                0, flags, &p, NULL, gate, src, index,
+                0, flags, &p, NULL, gate, prefsrc, index,
                 table, metric, mtu, 0);
       else
         {
@@ -280,9 +281,9 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
               if (gate)
                 {
                   if (index)
-                    rib_nexthop_ipv4_ifindex_add (rib, gate, src, index);
+                    rib_nexthop_ipv4_ifindex_add (rib, gate, prefsrc, index);
                   else
-                    rib_nexthop_ipv4_add (rib, gate, src);
+                    rib_nexthop_ipv4_add (rib, gate, prefsrc);
                 }
               else
                 rib_nexthop_ifindex_add (rib, index);
@@ -305,8 +306,12 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
       memcpy (&p.u.prefix6, dest, 16);
       p.prefixlen = rtm->rtm_dst_len;
 
+      src_p.family = AF_INET6;
+      memcpy (&src_p.prefix, src, 16);
+      src_p.prefixlen = rtm->rtm_src_len;
+
       rib_add (AFI_IP6, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
-              0, flags, &p, NULL, gate, src, index,
+               0, flags, &p, &src_p, gate, prefsrc, index,
               table, metric, mtu, 0);
     }
 
@@ -326,14 +331,15 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
   vrf_id_t vrf_id = VRF_DEFAULT;
   char anyaddr[16] = { 0 };
 
-  int index;
+  int index = 0;
   int table;
-  int metric;
+  int metric = 0;
   u_int32_t mtu = 0;
 
-  void *dest;
-  void *gate;
-  void *src;
+  void *dest = NULL;
+  void *gate = NULL;
+  void *prefsrc = NULL;                /* IPv4 preferred source host address */
+  void *src = NULL;            /* IPv6 srcdest   source prefix */
 
   rtm = NLMSG_DATA (h);
 
@@ -354,12 +360,6 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
   if (rtm->rtm_protocol == RTPROT_ZEBRA)
     SET_FLAG(zebra_flags, ZEBRA_FLAG_SELFROUTE);
 
-  if (rtm->rtm_src_len != 0)
-    {
-      zlog_warn ("netlink_route_change(): no src len");
-      return 0;
-    }
-
   /* Table corresponding to route. */
   if (tb[RTA_TABLE])
     table = *(int *) RTA_DATA (tb[RTA_TABLE]);
@@ -375,12 +375,6 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
         return 0;
     }
 
-  index = 0;
-  metric = 0;
-  dest = NULL;
-  gate = NULL;
-  src = NULL;
-
   if (tb[RTA_OIF])
     index = *(int *) RTA_DATA (tb[RTA_OIF]);
 
@@ -389,11 +383,16 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
   else
     dest = anyaddr;
 
+  if (tb[RTA_SRC])
+    src = RTA_DATA (tb[RTA_SRC]);
+  else
+    src = anyaddr;
+
   if (tb[RTA_GATEWAY])
     gate = RTA_DATA (tb[RTA_GATEWAY]);
 
   if (tb[RTA_PREFSRC])
-    src = RTA_DATA (tb[RTA_PREFSRC]);
+    prefsrc = RTA_DATA (tb[RTA_PREFSRC]);
 
   if (h->nlmsg_type == RTM_NEWROUTE)
     {
@@ -419,6 +418,13 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
       memcpy (&p.u.prefix4, dest, 4);
       p.prefixlen = rtm->rtm_dst_len;
 
+      if (rtm->rtm_src_len != 0)
+       {
+         zlog_warn ("unsupported IPv4 sourcedest route (dest %s/%d)",
+                    inet_ntoa (p.u.prefix4), p.prefixlen);
+         return 0;
+       }
+
       if (IS_ZEBRA_DEBUG_KERNEL)
         {
           char buf[PREFIX_STRLEN];
@@ -431,8 +437,8 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
         {
           if (!tb[RTA_MULTIPATH])
             rib_add (AFI_IP, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
-                    0, 0, &p, NULL, gate, src, index,
-                    table, metric, mtu, 0);
+                     0, 0, &p, NULL, gate, prefsrc, index,
+                     table, metric, mtu, 0);
           else
             {
               /* This is a multipath route */
@@ -473,9 +479,9 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
                   if (gate)
                     {
                       if (index)
-                        rib_nexthop_ipv4_ifindex_add (rib, gate, src, index);
+                        rib_nexthop_ipv4_ifindex_add (rib, gate, prefsrc, index);
                       else
-                        rib_nexthop_ipv4_add (rib, gate, src);
+                        rib_nexthop_ipv4_add (rib, gate, prefsrc);
                     }
                   else
                     rib_nexthop_ifindex_add (rib, index);
@@ -501,26 +507,35 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
   if (rtm->rtm_family == AF_INET6)
     {
       struct prefix p;
+      struct prefix_ipv6 src_p;
 
       p.family = AF_INET6;
       memcpy (&p.u.prefix6, dest, 16);
       p.prefixlen = rtm->rtm_dst_len;
 
+      src_p.family = AF_INET6;
+      memcpy (&src_p.prefix, src, 16);
+      src_p.prefixlen = rtm->rtm_src_len;
+
       if (IS_ZEBRA_DEBUG_KERNEL)
         {
          char buf[PREFIX_STRLEN];
-          zlog_debug ("%s %s vrf %u",
+         char buf2[PREFIX_STRLEN];
+          zlog_debug ("%s %s%s%s vrf %u",
                       nl_msg_type_to_str (h->nlmsg_type),
-                      prefix2str (&p, buf, sizeof(buf)), vrf_id);
+                      prefix2str (&p, buf, sizeof(buf)),
+                      src_p.prefixlen ? " from " : "",
+                      src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2)) : "",
+                      vrf_id);
         }
 
       if (h->nlmsg_type == RTM_NEWROUTE)
         rib_add (AFI_IP6, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
-                0, 0, &p, NULL, gate, src, index,
+                0, 0, &p, &src_p, gate, prefsrc, index,
                 table, metric, mtu, 0);
       else
         rib_delete (AFI_IP6, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
-                   0, zebra_flags, &p, NULL, gate, index, table);
+                   0, zebra_flags, &p, &src_p, gate, index, table);
     }
 
   return 0;
@@ -1233,8 +1248,8 @@ netlink_neigh_update (int cmd, int ifindex, uint32_t addr, char *lla, int llalen
 /* Routing table change via netlink interface. */
 /* Update flag indicates whether this is a "replace" or not. */
 static int
-netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
-                         int update)
+netlink_route_multipath (int cmd, struct prefix *p, struct prefix *src_p,
+                         struct rib *rib, int update)
 {
   int bytelen;
   struct sockaddr_nl snl;
@@ -1268,6 +1283,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
   req.n.nlmsg_type = cmd;
   req.r.rtm_family = family;
   req.r.rtm_dst_len = p->prefixlen;
+  req.r.rtm_src_len = src_p ? src_p->prefixlen : 0;
   req.r.rtm_protocol = RTPROT_ZEBRA;
   req.r.rtm_scope = RT_SCOPE_UNIVERSE;
 
@@ -1292,6 +1308,8 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
     }
 
   addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
+  if (src_p)
+    addattr_l (&req.n, sizeof req, RTA_SRC, &src_p->u.prefix, bytelen);
 
   /* Metric. */
   /* Hardcode the metric for all routes coming from zebra. Metric isn't used
@@ -1559,14 +1577,15 @@ kernel_get_ipmr_sg_stats (void *in)
 }
 
 int
-kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new)
+kernel_route_rib (struct prefix *p, struct prefix *src_p,
+                  struct rib *old, struct rib *new)
 {
   if (!old && new)
-    return netlink_route_multipath (RTM_NEWROUTE, p, new, 0);
+    return netlink_route_multipath (RTM_NEWROUTE, p, src_p, new, 0);
   if (old && !new)
-    return netlink_route_multipath (RTM_DELROUTE, p, old, 0);
+    return netlink_route_multipath (RTM_DELROUTE, p, src_p, old, 0);
 
-  return netlink_route_multipath (RTM_NEWROUTE, p, new, 1);
+  return netlink_route_multipath (RTM_NEWROUTE, p, src_p, new, 1);
 }
 
 int
index f65ec887dd303331e923d5ed8adf3240b9657b14..a4cc4eed062c5037e024ae528517f860f066c306 100644 (file)
@@ -182,7 +182,7 @@ kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib)
              {
                zlog_debug ("%s: %s: attention! gate not found for rib %p",
                  __func__, prefix_buf, rib);
-               rib_dump (p, rib);
+               rib_dump (p, NULL, rib);
              }
              else
                inet_ntop (AF_INET, &sin_gate.sin_addr, gate_buf, INET_ADDRSTRLEN);
@@ -391,10 +391,17 @@ kernel_rtm (int cmd, struct prefix *p, struct rib *rib)
 }
 
 int
-kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new)
+kernel_route_rib (struct prefix *p, struct prefix *src_p,
+                  struct rib *old, struct rib *new)
 {
   int route = 0;
 
+  if (src_p && src_p->prefixlen)
+    {
+      zlog (NULL, LOG_ERR, "route add: IPv6 sourcedest routes unsupported!");
+      return 1;
+    }
+
   if (zserv_privs.change(ZPRIVS_RAISE))
     zlog (NULL, LOG_ERR, "Can't raise privileges");
 
index d638ceab7f4c5f9eaaaff407d7db9683a58da841..b0b58b738cc52ff47547bb72e4fb142fb083396a 100644 (file)
@@ -37,6 +37,7 @@
 #include "nexthop.h"
 #include "vrf.h"
 #include "mpls.h"
+#include "srcdest_table.h"
 
 #include "zebra/rib.h"
 #include "zebra/rt.h"
@@ -88,7 +89,7 @@ static void __attribute__((format (printf, 5, 6)))
 _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn, int priority,
            const char *msgfmt, ...)
 {
-  char buf[PREFIX_STRLEN + 8];
+  char buf[SRCDEST2STR_BUFFER + sizeof(" (MRIB)")];
   char msgbuf[512];
   va_list ap;
 
@@ -98,9 +99,9 @@ _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn, int prior
 
   if (rn)
     {
-      rib_table_info_t *info = rn->table->info;
+      rib_table_info_t *info = srcdest_rnode_table_info (rn);
+      srcdest_rnode2str(rn, buf, sizeof(buf));
 
-      prefix2str(&rn->p, buf, sizeof(buf));
       if (info->safi == SAFI_MULTICAST)
         strcat(buf, " (MRIB)");
     }
@@ -1051,11 +1052,12 @@ static unsigned
 nexthop_active_check (struct route_node *rn, struct rib *rib,
                      struct nexthop *nexthop, int set)
 {
-  rib_table_info_t *info = rn->table->info;
   struct interface *ifp;
   route_map_result_t ret = RMAP_MATCH;
   int family;
-  char buf[INET6_ADDRSTRLEN+1];
+  char buf[SRCDEST2STR_BUFFER];
+  struct prefix *p, *src_p;
+  srcdest_rnode_prefixes (rn, &p, &src_p);
 
   if (rn->p.family == AF_INET)
     family = AFI_IP;
@@ -1119,8 +1121,8 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
   /* XXX: What exactly do those checks do? Do we support
    * e.g. IPv4 routes with IPv6 nexthops or vice versa? */
   if (RIB_SYSTEM_ROUTE(rib) ||
-      (family == AFI_IP && rn->p.family != AF_INET) ||
-      (family == AFI_IP6 && rn->p.family != AF_INET6))
+      (family == AFI_IP && p->family != AF_INET) ||
+      (family == AFI_IP6 && p->family != AF_INET6))
     return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
 
   /* The original code didn't determine the family correctly
@@ -1130,20 +1132,25 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
    * in every case.
    */
   if (!family)
-    family = info->afi;
+    {
+      rib_table_info_t *info;
+
+      info = srcdest_rnode_table_info(rn);
+      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,
+  ret = zebra_route_map_check(family, rib->type, p, nexthop, rib->vrf_id,
                               rib->tag);
   if (ret == RMAP_DENYMATCH)
     {
       if (IS_ZEBRA_DEBUG_RIB)
        {
-         inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf));
-         zlog_debug("%u:%s/%d: Filtering out with NH out %s due to route map",
-                    rib->vrf_id, buf, rn->p.prefixlen,
+         srcdest_rnode2str(rn, buf, sizeof(buf));
+         zlog_debug("%u:%s: Filtering out with NH out %s due to route map",
+                    rib->vrf_id, buf,
                     ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id));
        }
       UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
@@ -1216,8 +1223,11 @@ rib_install_kernel (struct route_node *rn, struct rib *rib, struct rib *old)
 {
   int ret = 0;
   struct nexthop *nexthop, *tnexthop;
-  rib_table_info_t *info = rn->table->info;
+  rib_table_info_t *info = srcdest_rnode_table_info(rn);
   int recursing;
+  struct prefix *p, *src_p;
+
+  srcdest_rnode_prefixes (rn, &p, &src_p);
 
   if (info->safi != SAFI_UNICAST)
     {
@@ -1231,7 +1241,7 @@ rib_install_kernel (struct route_node *rn, struct rib *rib, struct rib *old)
    * the kernel.
    */
   zfpm_trigger_update (rn, "installing in kernel");
-  ret = kernel_route_rib (&rn->p, old, rib);
+  ret = kernel_route_rib (p, src_p, old, rib);
 
   /* If install succeeds, update FIB flag for nexthops. */
   if (!ret)
@@ -1257,8 +1267,11 @@ rib_uninstall_kernel (struct route_node *rn, struct rib *rib)
 {
   int ret = 0;
   struct nexthop *nexthop, *tnexthop;
-  rib_table_info_t *info = rn->table->info;
+  rib_table_info_t *info = srcdest_rnode_table_info(rn);
   int recursing;
+  struct prefix *p, *src_p;
+
+  srcdest_rnode_prefixes (rn, &p, &src_p);
 
   if (info->safi != SAFI_UNICAST)
     {
@@ -1272,7 +1285,7 @@ rib_uninstall_kernel (struct route_node *rn, struct rib *rib)
    * the kernel.
    */
   zfpm_trigger_update (rn, "uninstalling from kernel");
-  ret = kernel_route_rib (&rn->p, rib, NULL);
+  ret = kernel_route_rib (p, src_p, rib, NULL);
 
   for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
     UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
@@ -1284,7 +1297,7 @@ rib_uninstall_kernel (struct route_node *rn, struct rib *rib)
 static void
 rib_uninstall (struct route_node *rn, struct rib *rib)
 {
-  rib_table_info_t *info = rn->table->info;
+  rib_table_info_t *info = srcdest_rnode_table_info(rn);
 
   if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
     {
@@ -1298,7 +1311,10 @@ rib_uninstall (struct route_node *rn, struct rib *rib)
 
   if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
     {
-      redistribute_delete (&rn->p, rib);
+      struct prefix *p, *src_p;
+      srcdest_rnode_prefixes (rn, &p, &src_p);
+
+      redistribute_delete (p, src_p, rib);
       UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED);
     }
 }
@@ -1367,8 +1383,6 @@ static void
 rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
                     struct rib *new)
 {
-  char buf[INET6_ADDRSTRLEN];
-
   zfpm_trigger_update (rn, "new route selected");
 
   /* Update real nexthop. This may actually determine if nexthop is active or not. */
@@ -1381,18 +1395,20 @@ rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
   SET_FLAG (new->status, RIB_ENTRY_SELECTED_FIB);
   if (IS_ZEBRA_DEBUG_RIB)
     {
-      inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN);
-      zlog_debug ("%u:%s/%d: Adding route rn %p, rib %p (type %d)",
-                   zvrf_id (zvrf), buf, rn->p.prefixlen, rn, new, new->type);
+      char buf[SRCDEST2STR_BUFFER];
+      srcdest_rnode2str(rn, buf, sizeof(buf));
+      zlog_debug ("%u:%s: Adding route rn %p, rib %p (type %d)",
+                   zvrf_id (zvrf), buf, rn, new, new->type);
     }
 
   if (!RIB_SYSTEM_ROUTE (new))
     {
       if (rib_install_kernel (rn, new, NULL))
         {
-          inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN);
-          zlog_warn ("%u:%s/%d: Route install failed",
-                     zvrf_id (zvrf), buf, rn->p.prefixlen);
+          char buf[SRCDEST2STR_BUFFER];
+          srcdest_rnode2str(rn, buf, sizeof(buf));
+          zlog_warn ("%u:%s: Route install failed",
+                     zvrf_id (zvrf), buf);
         }
     }
 
@@ -1403,16 +1419,15 @@ static void
 rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
                     struct rib *old)
 {
-  char buf[INET6_ADDRSTRLEN];
-
   zfpm_trigger_update (rn, "removing existing route");
 
   /* Uninstall from kernel. */
   if (IS_ZEBRA_DEBUG_RIB)
     {
-      inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN);
-      zlog_debug ("%u:%s/%d: Deleting route rn %p, rib %p (type %d)",
-                  zvrf_id (zvrf), buf, rn->p.prefixlen, rn, old, old->type);
+      char buf[SRCDEST2STR_BUFFER];
+      srcdest_rnode2str(rn, buf, sizeof(buf));
+      zlog_debug ("%u:%s: Deleting route rn %p, rib %p (type %d)",
+                  zvrf_id (zvrf), buf, rn, old, old->type);
     }
 
   if (!RIB_SYSTEM_ROUTE (old))
@@ -1429,15 +1444,11 @@ static void
 rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn,
                         struct rib *old, struct rib *new)
 {
-  char buf[INET6_ADDRSTRLEN];
   struct nexthop *nexthop = NULL, *tnexthop;
   int recursing;
   int nh_active = 0;
   int installed = 1;
 
-  if (IS_ZEBRA_DEBUG_RIB)
-    inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN);
-
   /*
    * We have to install or update if a new route has been selected or
    * something has changed.
@@ -1459,23 +1470,25 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn,
         {
           if (IS_ZEBRA_DEBUG_RIB)
             {
+              char buf[SRCDEST2STR_BUFFER];
+              srcdest_rnode2str(rn, buf, sizeof(buf));
               if (new != old)
-                zlog_debug ("%u:%s/%d: Updating route rn %p, rib %p (type %d) "
-                            "old %p (type %d)", zvrf_id (zvrf), buf, rn->p.prefixlen,
+                zlog_debug ("%u:%s: Updating route rn %p, rib %p (type %d) "
+                            "old %p (type %d)", zvrf_id (zvrf), buf,
                             rn, new, new->type, old, old->type);
               else
-                zlog_debug ("%u:%s/%d: Updating route rn %p, rib %p (type %d)",
-                        zvrf_id (zvrf), buf, rn->p.prefixlen, rn, new, new->type);
+                zlog_debug ("%u:%s: Updating route rn %p, rib %p (type %d)",
+                            zvrf_id (zvrf), buf, rn, new, new->type);
             }
           /* Non-system route should be installed. */
           if (!RIB_SYSTEM_ROUTE (new))
             {
               if (rib_install_kernel (rn, new, old))
                 {
+                  char buf[SRCDEST2STR_BUFFER];
+                  srcdest_rnode2str(rn, buf, sizeof(buf));
                   installed = 0;
-                  inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN);
-                  zlog_warn ("%u:%s/%d: Route install failed",
-                             zvrf_id (zvrf), buf, rn->p.prefixlen);
+                  zlog_warn ("%u:%s: Route install failed", zvrf_id (zvrf), buf);
                 }
             }
 
@@ -1507,14 +1520,16 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn,
         {
           if (IS_ZEBRA_DEBUG_RIB)
             {
+              char buf[SRCDEST2STR_BUFFER];
+              srcdest_rnode2str(rn, buf, sizeof(buf));
               if (new != old)
-                zlog_debug ("%u:%s/%d: Deleting route rn %p, rib %p (type %d) "
-                            "old %p (type %d) - %s", zvrf_id (zvrf), buf, rn->p.prefixlen,
+                zlog_debug ("%u:%s: Deleting route rn %p, rib %p (type %d) "
+                            "old %p (type %d) - %s", zvrf_id (zvrf), buf,
                             rn, new, new->type, old, old->type,
                             nh_active ? "install failed" : "nexthop inactive");
               else
-                zlog_debug ("%u:%s/%d: Deleting route rn %p, rib %p (type %d) - %s",
-                            zvrf_id (zvrf), buf, rn->p.prefixlen, rn, new, new->type,
+                zlog_debug ("%u:%s: Deleting route rn %p, rib %p (type %d) - %s",
+                            zvrf_id (zvrf), buf, rn, new, new->type,
                             nh_active ? "install failed" : "nexthop inactive");
             }
 
@@ -1613,9 +1628,11 @@ rib_process (struct route_node *rn)
   struct rib *old_fib = NULL;
   struct rib *new_fib = NULL;
   struct rib *best = NULL;
-  char buf[INET6_ADDRSTRLEN];
+  char buf[SRCDEST2STR_BUFFER];
   rib_dest_t *dest;
   struct zebra_vrf *zvrf = NULL;
+  struct prefix *p, *src_p;
+  srcdest_rnode_prefixes(rn, &p, &src_p);
   vrf_id_t vrf_id = VRF_UNKNOWN;
 
   assert (rn);
@@ -1628,17 +1645,17 @@ rib_process (struct route_node *rn)
     }
 
   if (IS_ZEBRA_DEBUG_RIB)
-    inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN);
+    srcdest_rnode2str(rn, buf, sizeof(buf));
 
   if (IS_ZEBRA_DEBUG_RIB_DETAILED)
-    zlog_debug ("%u:%s/%d: Processing rn %p", vrf_id, buf, rn->p.prefixlen, rn);
+    zlog_debug ("%u:%s: Processing rn %p", vrf_id, buf, rn);
 
   RNODE_FOREACH_RIB_SAFE (rn, rib, next)
     {
       if (IS_ZEBRA_DEBUG_RIB_DETAILED)
-        zlog_debug ("%u:%s/%d: Examine rib %p (type %d) status %x flags %x "
+        zlog_debug ("%u:%s: Examine rib %p (type %d) status %x flags %x "
                     "dist %d metric %d",
-                    vrf_id, buf, rn->p.prefixlen, rib, rib->type, rib->status,
+                    vrf_id, buf, rib, rib->type, rib->status,
                     rib->flags, rib->distance, rib->metric);
 
       UNSET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
@@ -1687,9 +1704,9 @@ rib_process (struct route_node *rn)
              if (rib != old_selected)
                {
                  if (IS_ZEBRA_DEBUG_RIB)
-                   zlog_debug ("%s: %s/%d: imported via import-table but denied "
+                   zlog_debug ("%s: %s: imported via import-table but denied "
                                "by the ip protocol table route-map",
-                               __func__, buf, rn->p.prefixlen);
+                               __func__, buf);
                  rib_unlink (rn, rib);
                }
              else
@@ -1740,8 +1757,8 @@ rib_process (struct route_node *rn)
 
   if (IS_ZEBRA_DEBUG_RIB_DETAILED)
     {
-    zlog_debug ("%u:%s/%d: After processing: old_selected %p new_selected %p old_fib %p new_fib %p",
-                vrf_id, buf, rn->p.prefixlen,
+    zlog_debug ("%u:%s: After processing: old_selected %p new_selected %p old_fib %p new_fib %p",
+                vrf_id, buf,
                 (void *)old_selected,
                 (void *)new_selected,
                 (void *)old_fib,
@@ -1789,7 +1806,7 @@ rib_process (struct route_node *rn)
       if (old_selected)
         {
           if (!new_selected)
-            redistribute_delete(&rn->p, old_selected);
+            redistribute_delete(p, src_p, old_selected);
           if (old_selected != new_selected)
             UNSET_FLAG (old_selected->flags, ZEBRA_FLAG_SELECTED);
         }
@@ -1798,7 +1815,7 @@ rib_process (struct route_node *rn)
         {
           /* Install new or replace existing redistributed entry */
           SET_FLAG (new_selected->flags, ZEBRA_FLAG_SELECTED);
-          redistribute_update (&rn->p, new_selected, old_selected);
+          redistribute_update (p, src_p, new_selected, old_selected);
         }
     }
 
@@ -2006,7 +2023,6 @@ process_subq (struct list * subq, u_char qindex)
 {
   struct listnode *lnode  = listhead (subq);
   struct route_node *rnode;
-  char buf[INET6_ADDRSTRLEN];
   rib_dest_t *dest;
   struct zebra_vrf *zvrf = NULL;
 
@@ -2022,9 +2038,10 @@ process_subq (struct list * subq, u_char qindex)
 
   if (IS_ZEBRA_DEBUG_RIB_DETAILED)
     {
-      inet_ntop (rnode->p.family, &rnode->p.u.prefix, buf, INET6_ADDRSTRLEN);
-      zlog_debug ("%u:%s/%d: rn %p dequeued from sub-queue %u",
-                  zvrf ? zvrf_id (zvrf) : 0, buf, rnode->p.prefixlen, rnode, qindex);
+      char buf[SRCDEST2STR_BUFFER];
+      srcdest_rnode2str(rnode, buf, sizeof(buf));
+      zlog_debug ("%u:%s: rn %p dequeued from sub-queue %u",
+                  zvrf ? zvrf_id (zvrf) : 0, buf, rnode, qindex);
     }
 
   if (rnode->info)
@@ -2405,13 +2422,10 @@ rib_delnode (struct route_node *rn, struct rib *rib)
       /* Just clean up if non main table */
       if (IS_ZEBRA_DEBUG_RIB)
         {
-          char buf[INET6_ADDRSTRLEN];
-          if (IS_ZEBRA_DEBUG_RIB)
-            {
-              inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN);
-              zlog_debug ("%u:%s/%d: Freeing route rn %p, rib %p (type %d)",
-                          rib->vrf_id, buf, rn->p.prefixlen, rn, rib, rib->type);
-            }
+          char buf[SRCDEST2STR_BUFFER];
+          srcdest_rnode2str(rn, buf, sizeof(buf));
+          zlog_debug ("%u:%s: Freeing route rn %p, rib %p (type %d)",
+                      rib->vrf_id, buf, rn, rib, rib->type);
         }
 
       rib_unlink(rn, rib);
@@ -2428,15 +2442,23 @@ rib_delnode (struct route_node *rn, struct rib *rib)
  */
 
 void _rib_dump (const char * func,
-               union prefix46constptr pp, const struct rib * rib)
+                union prefix46constptr pp,
+                union prefix46constptr src_pp,
+                const struct rib * rib)
 {
   const struct prefix *p = pp.p;
+  const struct prefix *src_p = src_pp.p;
+  bool is_srcdst = src_p && src_p->prefixlen;
   char straddr[PREFIX_STRLEN];
+  char srcaddr[PREFIX_STRLEN];
   struct nexthop *nexthop, *tnexthop;
   int recursing;
 
-  zlog_debug ("%s: dumping RIB entry %p for %s vrf %u", func, (const void *)rib,
-              prefix2str(pp, straddr, sizeof(straddr)), rib->vrf_id);
+  zlog_debug ("%s: dumping RIB entry %p for %s%s%s vrf %u", func, (const void *)rib,
+              prefix2str(pp, straddr, sizeof(straddr)),
+              is_srcdst ? " from " : "",
+              is_srcdst ? prefix2str(src_pp, srcaddr, sizeof(srcaddr)) : "",
+              rib->vrf_id);
   zlog_debug
   (
     "%s: refcnt == %lu, uptime == %lu, type == %u, instance == %d, table == %d",
@@ -2527,7 +2549,7 @@ void rib_lookup_and_dump (struct prefix_ipv4 * p, vrf_id_t vrf_id)
       (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED) ? "removed" : "NOT removed"),
       (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) ? "selected" : "NOT selected")
     );
-    rib_dump (p, rib);
+    rib_dump (p, NULL, rib);
   }
 }
 
@@ -2574,7 +2596,7 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p, vrf_id_t vrf_id)
         char buf[PREFIX_STRLEN];
         zlog_debug ("%u:%s: freeing way for connected prefix",
                     rib->vrf_id, prefix2str(&rn->p, buf, sizeof(buf)));
-        rib_dump (&rn->p, rib);
+        rib_dump (&rn->p, NULL, rib);
       }
       rib_uninstall (rn, rib);
     }
@@ -2602,6 +2624,8 @@ rib_add_multipath (afi_t afi, safi_t safi, struct prefix *p,
   else
     family = AFI_IP6;
 
+  assert(!src_p || family == AFI_IP6);
+
   /* Lookup table.  */
   table = zebra_vrf_table_with_table_id (family, safi, rib->vrf_id, rib->table);
   if (! table)
@@ -2609,6 +2633,8 @@ rib_add_multipath (afi_t afi, safi_t safi, struct prefix *p,
 
   /* Make it sure prefixlen is applied to the prefix. */
   apply_mask (p);
+  if (src_p)
+    apply_mask_ipv6 (src_p);
 
   /* Set default distance by route type. */
   if (rib->distance == 0)
@@ -2622,7 +2648,7 @@ rib_add_multipath (afi_t afi, safi_t safi, struct prefix *p,
     }
 
   /* Lookup route node.*/
-  rn = route_node_get (table, p);
+  rn = srcdest_rnode_get (table, p, src_p);
 
   /* If same type of route are installed, treat it as a implicit
      withdraw. */
@@ -2645,18 +2671,11 @@ rib_add_multipath (afi_t afi, safi_t safi, struct prefix *p,
   /* Link new rib to node.*/
   if (IS_ZEBRA_DEBUG_RIB)
     {
-      char buf[INET6_ADDRSTRLEN];
-      if (IS_ZEBRA_DEBUG_RIB)
-        {
-          inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN);
-          zlog_debug ("%u:%s/%d: Inserting route rn %p, rib %p (type %d) "
-                      "existing %p",
-                      rib->vrf_id, buf, p->prefixlen, (void *)rn,
-                     (void *)rib, rib->type, (void *)same);
-        }
+      rnode_debug(rn, rib->vrf_id, "Inserting route rn %p, rib %p (type %d) existing %p",
+                  (void *)rn, (void *)rib, rib->type, (void *)same);
 
       if (IS_ZEBRA_DEBUG_RIB_DETAILED)
-        rib_dump ((struct prefix *)p, rib);
+        rib_dump (p, src_p, rib);
     }
   rib_addnode (rn, rib, 1);
   ret = 1;
@@ -2684,9 +2703,10 @@ rib_delete (afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance,
   struct rib *same = NULL;
   struct nexthop *nexthop, *tnexthop;
   int recursing;
-  char buf1[PREFIX_STRLEN];
   char buf2[INET6_ADDRSTRLEN];
 
+  assert(!src_p || afi == AFI_IP6);
+
   /* Lookup table.  */
   table = zebra_vrf_table_with_table_id (afi, safi, vrf_id, table_id);
   if (! table)
@@ -2694,14 +2714,26 @@ rib_delete (afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance,
 
   /* Apply mask. */
   apply_mask (p);
+  if (src_p)
+    apply_mask_ipv6 (src_p);
 
   /* Lookup route node. */
-  rn = route_node_lookup (table, p);
+  rn = srcdest_rnode_lookup (table, p, src_p);
   if (! rn)
     {
+      char dst_buf[PREFIX_STRLEN], src_buf[PREFIX_STRLEN];
+
+      prefix2str(p, dst_buf, sizeof(dst_buf));
+      if (src_p && src_p->prefixlen)
+        prefix2str(src_p, src_buf, sizeof(src_buf));
+      else
+        src_buf[0] = '\0';
+
       if (IS_ZEBRA_DEBUG_RIB)
-        zlog_debug ("%u:%s: doesn't exist in rib",
-                    vrf_id, prefix2str (p, buf1, sizeof(buf1)));
+        zlog_debug ("%u:%s%s%s doesn't exist in rib",
+                    vrf_id, dst_buf,
+                    (src_buf[0] != '\0') ? " from " : "",
+                    src_buf);
       return ZEBRA_ERR_RTNOEXIST;
     }
 
@@ -2761,10 +2793,8 @@ rib_delete (afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance,
         {
           if (IS_ZEBRA_DEBUG_RIB)
             {
-              zlog_debug ("%u:%s: rn %p, rib %p (type %d) was deleted "
-                          "from kernel, adding",
-                         vrf_id, prefix2str(p, buf1, INET6_ADDRSTRLEN),
-                          rn, fib, fib->type);
+              rnode_debug (rn, vrf_id, "rn %p, rib %p (type %d) was deleted from kernel, adding",
+                           rn, fib, fib->type);
             }
          if (allow_delete)
            {
@@ -2786,15 +2816,13 @@ rib_delete (afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance,
          if (IS_ZEBRA_DEBUG_RIB)
            {
              if (gate)
-               zlog_debug ("%u:%s: via %s ifindex %d type %d "
+               rnode_debug(rn, vrf_id, "via %s ifindex %d type %d "
                           "doesn't exist in rib",
-                           vrf_id, prefix2str (p, buf1, sizeof(buf1)),
-                           inet_ntop (family2afi(afi), gate, buf2, INET_ADDRSTRLEN),
+                           inet_ntop (family2afi(afi), gate, buf2, INET_ADDRSTRLEN), /* FIXME */
                            ifindex,
                            type);
              else
-               zlog_debug ("%u:%s: ifindex %d type %d doesn't exist in rib",
-                           vrf_id, prefix2str (p, buf1, sizeof(buf1)),
+               rnode_debug (rn, vrf_id, "ifindex %d type %d doesn't exist in rib",
                            ifindex,
                            type);
            }
@@ -2826,6 +2854,8 @@ rib_add (afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
   struct route_node *rn;
   struct nexthop *nexthop;
 
+  assert(!src_p || afi == AFI_IP6);
+
   /* Lookup table.  */
   table = zebra_vrf_table_with_table_id (afi, safi, vrf_id, table_id);
   if (! table)
@@ -2833,6 +2863,8 @@ rib_add (afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
 
   /* Make sure mask is applied. */
   apply_mask (p);
+  if (src_p)
+    apply_mask_ipv6 (src_p);
 
   /* Set default distance by route type. */
   if (distance == 0)
@@ -2848,7 +2880,7 @@ rib_add (afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
     }
 
   /* Lookup route node.*/
-  rn = route_node_get (table,  p);
+  rn = srcdest_rnode_get (table,  p, src_p);
 
   /* If same type of route are installed, treat it as a implicit
      withdraw. */
@@ -2920,18 +2952,11 @@ rib_add (afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
   /* Link new rib to node.*/
   if (IS_ZEBRA_DEBUG_RIB)
     {
-      char buf[INET6_ADDRSTRLEN];
-      if (IS_ZEBRA_DEBUG_RIB)
-        {
-          inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN);
-          zlog_debug ("%u:%s/%d: Inserting route rn %p, rib %p (type %d) "
-                      "existing %p",
-                      vrf_id, buf, p->prefixlen, (void *)rn,
-                     (void *)rib, rib->type, (void *)same);
-        }
+      rnode_debug (rn, vrf_id, "Inserting route rn %p, rib %p (type %d) existing %p",
+                   (void *)rn, (void *)rib, rib->type, (void *)same);
 
       if (IS_ZEBRA_DEBUG_RIB_DETAILED)
-        rib_dump (p, rib);
+        rib_dump (p, src_p, rib);
     }
   rib_addnode (rn, rib, 1);
 
@@ -2953,7 +2978,7 @@ rib_update_table (struct route_table *table, rib_update_event_t event)
   /* Walk all routes and queue for processing, if appropriate for
    * the trigger event.
    */
-  for (rn = route_top (table); rn; rn = route_next (rn))
+  for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
     {
       switch (event)
         {
@@ -3029,7 +3054,7 @@ rib_weed_table (struct route_table *table)
   struct rib *next;
 
   if (table)
-    for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
       RNODE_FOREACH_RIB_SAFE (rn, rib, next)
        {
          if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
@@ -3066,7 +3091,7 @@ rib_sweep_table (struct route_table *table)
   int ret = 0;
 
   if (table)
-    for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
       RNODE_FOREACH_RIB_SAFE (rn, rib, next)
        {
          if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
@@ -3107,7 +3132,7 @@ rib_score_proto_table (u_char proto, u_short instance, struct route_table *table
   unsigned long n = 0;
 
   if (table)
-    for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
       RNODE_FOREACH_RIB_SAFE (rn, rib, next)
         {
           if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
@@ -3118,7 +3143,6 @@ rib_score_proto_table (u_char proto, u_short instance, struct route_table *table
               n++;
             }
         }
-
   return n;
 }
 
@@ -3147,7 +3171,7 @@ rib_close_table (struct route_table *table)
   struct rib *rib;
 
   if (table)
-    for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
       RNODE_FOREACH_RIB (rn, rib)
         {
           if (!CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
index 7d104f30d98a7e0fc494d1df56fed30fb8f254e3..33f0a2bd7216927b4e68d18b4a1a3628e3c54eec 100644 (file)
@@ -328,13 +328,13 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_
                 rib_install_kernel (rn, rib, rib);
               /* Update redistribution if it's selected */
               if (CHECK_FLAG(rib->flags, ZEBRA_FLAG_SELECTED))
-              redistribute_update (&rn->p, rib, NULL);
+                redistribute_update (&rn->p, NULL, rib, NULL);
             }
           else
             {
               /* Remove from redistribute if selected route becomes inactive */
               if (CHECK_FLAG(rib->flags, ZEBRA_FLAG_SELECTED))
-              redistribute_delete (&rn->p, rib);
+                redistribute_delete (&rn->p, NULL, rib);
               /* Remove from kernel if fib route becomes inactive */
               if (CHECK_FLAG(rib->status, RIB_ENTRY_SELECTED_FIB))
               rib_uninstall_kernel (rn, rib);
index 929743859e76e119f07d378b1b0551439ca7fe67..bc86e4a10b99dbedadde104106908d54650878eb 100644 (file)
@@ -25,6 +25,7 @@
 #include "linklist.h"
 #include "command.h"
 #include "memory.h"
+#include "srcdest_table.h"
 
 #include "vty.h"
 #include "zebra/debug.h"
@@ -331,8 +332,7 @@ zebra_vrf_table_with_table_id (afi_t afi, safi_t safi,
 }
 
 static void
-zebra_rtable_node_destroy (route_table_delegate_t *delegate,
-                          struct route_table *table, struct route_node *node)
+zebra_rtable_node_cleanup (struct route_table *table, struct route_node *node)
 {
   struct rib *rib, *next;
 
@@ -341,8 +341,6 @@ zebra_rtable_node_destroy (route_table_delegate_t *delegate,
 
   if (node->info)
     XFREE (MTYPE_RIB_DEST, node->info);
-
-  route_node_destroy (delegate, table, node);
 }
 
 static void
@@ -362,30 +360,17 @@ zebra_stable_node_destroy (route_table_delegate_t *delegate,
 }
 
 static void
-zebra_rnhtable_node_destroy (route_table_delegate_t *delegate,
-                            struct route_table *table, struct route_node *node)
+zebra_rnhtable_node_cleanup (struct route_table *table, struct route_node *node)
 {
   if (node->info)
     zebra_free_rnh (node->info);
-
-  route_node_destroy (delegate, table, node);
 }
 
-route_table_delegate_t zebra_rtable_delegate = {
-  .create_node = route_node_create,
-  .destroy_node = zebra_rtable_node_destroy
-};
-
 route_table_delegate_t zebra_stable_delegate = {
   .create_node = route_node_create,
   .destroy_node = zebra_stable_node_destroy
 };
 
-route_table_delegate_t zebra_rnhtable_delegate = {
-  .create_node = route_node_create,
-  .destroy_node = zebra_rnhtable_node_destroy
-};
-
 /*
  * Create a routing table for the specific AFI/SAFI in the given VRF.
  */
@@ -397,7 +382,11 @@ zebra_vrf_table_create (struct zebra_vrf *zvrf, afi_t afi, safi_t safi)
 
   assert (!zvrf->table[afi][safi]);
 
-  table = route_table_init_with_delegate (&zebra_rtable_delegate);
+  if (afi == AFI_IP6)
+    table = srcdest_table_init();
+  else
+    table = route_table_init();
+  table->cleanup = zebra_rtable_node_cleanup;
   zvrf->table[afi][safi] = table;
 
   info = XCALLOC (MTYPE_RIB_TABLE_INFO, sizeof (*info));
@@ -414,6 +403,7 @@ zebra_vrf_alloc (void)
   struct zebra_vrf *zvrf;
   afi_t afi;
   safi_t safi;
+  struct route_table *table;
 
   zvrf = XCALLOC (MTYPE_ZEBRA_VRF, sizeof (struct zebra_vrf));
 
@@ -426,10 +416,13 @@ zebra_vrf_alloc (void)
                route_table_init_with_delegate (&zebra_stable_delegate);
        }
 
-      zvrf->rnh_table[afi] =
-       route_table_init_with_delegate (&zebra_rnhtable_delegate);
-      zvrf->import_check_table[afi] =
-       route_table_init_with_delegate (&zebra_rnhtable_delegate);
+      table = route_table_init();
+      table->cleanup = zebra_rnhtable_node_cleanup;
+      zvrf->rnh_table[afi] = table;
+
+      table = route_table_init();
+      table->cleanup = zebra_rnhtable_node_cleanup;
+      zvrf->import_check_table[afi] = table;
     }
 
   zebra_mpls_init_tables (zvrf);
@@ -509,7 +502,7 @@ zebra_vrf_other_route_table (afi_t afi, u_int32_t table_id, vrf_id_t vrf_id)
     {
       if (zvrf->other_table[afi][table_id] == NULL)
         {
-          table = route_table_init();
+          table = (afi == AFI_IP6) ? srcdest_table_init() : route_table_init();
           info = XCALLOC (MTYPE_RIB_TABLE_INFO, sizeof (*info));
           info->zvrf = zvrf;
           info->afi = afi;
index f0756775755b9166f8d954f83e41a5e2de5b0b63..bba0571c9ee5c32f514652771b158bcb3dc5dde7 100644 (file)
@@ -32,6 +32,7 @@
 #include "vrf.h"
 #include "mpls.h"
 #include "routemap.h"
+#include "srcdest_table.h"
 
 #include "zebra/zserv.h"
 #include "zebra/zebra_vrf.h"
@@ -639,7 +640,7 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast)
   struct rib *rib;
   struct nexthop *nexthop, *tnexthop;
   int recursing;
-  char buf[PREFIX_STRLEN];
+  char buf[SRCDEST2STR_BUFFER];
   struct zebra_vrf *zvrf;
 
   RNODE_FOREACH_RIB (rn, rib)
@@ -647,14 +648,14 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast)
       const char *mcast_info = "";
       if (mcast)
         {
-          rib_table_info_t *info = rn->table->info;
+          rib_table_info_t *info = srcdest_rnode_table_info(rn);
           mcast_info = (info->safi == SAFI_MULTICAST)
                        ? " using Multicast RIB"
                        : " using Unicast RIB";
         }
 
       vty_out (vty, "Routing entry for %s%s%s",
-              prefix2str (&rn->p, buf, sizeof(buf)), mcast_info,
+              srcdest_rnode2str(rn, buf, sizeof(buf)), mcast_info,
               VTY_NEWLINE);
       vty_out (vty, "  Known via \"%s", zebra_route_string (rib->type));
       if (rib->instance)
@@ -797,7 +798,7 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib,
   struct nexthop *nexthop, *tnexthop;
   int recursing;
   int len = 0;
-  char buf[BUFSIZ];
+  char buf[SRCDEST2STR_BUFFER];
   json_object *json_nexthops = NULL;
   json_object *json_nexthop = NULL;
   json_object *json_route = NULL;
@@ -807,7 +808,7 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib,
       json_route = json_object_new_object();
       json_nexthops = json_object_new_array();
 
-      json_object_string_add(json_route, "prefix", prefix2str (&rn->p, buf, sizeof buf));
+      json_object_string_add(json_route, "prefix", srcdest_rnode2str (rn, buf, sizeof buf));
       json_object_string_add(json_route, "protocol", zebra_route_string(rib->type));
 
       if (rib->instance)
@@ -951,7 +952,7 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib,
                          ? '>' : ' ',
                          CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
                          ? '*' : ' ',
-                         prefix2str (&rn->p, buf, sizeof buf));
+                         srcdest_rnode2str (rn, buf, sizeof buf));
 
          /* Distance and metric display. */
          if (rib->type != ZEBRA_ROUTE_CONNECT
@@ -1665,7 +1666,7 @@ vty_show_ip_route_summary (struct vty *vty, struct route_table *table)
 
   memset (&rib_cnt, 0, sizeof(rib_cnt));
   memset (&fib_cnt, 0, sizeof(fib_cnt));
-  for (rn = route_top (table); rn; rn = route_next (rn))
+  for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
     RNODE_FOREACH_RIB (rn, rib)
       {
         is_ibgp = (rib->type == ZEBRA_ROUTE_BGP &&
@@ -1741,7 +1742,7 @@ vty_show_ip_route_summary_prefix (struct vty *vty, struct route_table *table)
 
   memset (&rib_cnt, 0, sizeof(rib_cnt));
   memset (&fib_cnt, 0, sizeof(fib_cnt));
-  for (rn = route_top (table); rn; rn = route_next (rn))
+  for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
     RNODE_FOREACH_RIB (rn, rib)
       {
 
@@ -2767,7 +2768,7 @@ DEFUN (show_ipv6_route,
   int first = 1;
   vrf_id_t vrf_id = VRF_DEFAULT;
   struct zebra_vrf *zvrf = NULL;
-  char buf[BUFSIZ];
+  char buf[SRCDEST2STR_BUFFER];
   json_object *json = NULL;
   json_object *json_prefix = NULL;
 
@@ -2811,7 +2812,7 @@ DEFUN (show_ipv6_route,
       json = json_object_new_object();
 
       /* Show all IPv6 route. */
-      for (rn = route_top (table); rn; rn = route_next (rn))
+      for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
         {
           RNODE_FOREACH_RIB (rn, rib)
             {
@@ -2822,7 +2823,7 @@ DEFUN (show_ipv6_route,
 
           if (json_prefix)
             {
-              prefix2str (&rn->p, buf, sizeof buf);
+              srcdest_rnode2str (rn, buf, sizeof buf);
               json_object_object_add(json, buf, json_prefix);
               json_prefix = NULL;
             }
@@ -2834,7 +2835,7 @@ DEFUN (show_ipv6_route,
   else
     {
       /* Show all IPv6 route. */
-      for (rn = route_top (table); rn; rn = route_next (rn))
+      for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
         {
           RNODE_FOREACH_RIB (rn, rib)
             {
@@ -2887,7 +2888,7 @@ DEFUN (show_ipv6_route_tag,
     return CMD_SUCCESS;
 
   /* Show all IPv6 routes with matching tag value. */
-  for (rn = route_top (table); rn; rn = route_next (rn))
+  for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
     RNODE_FOREACH_RIB (rn, rib)
       {
         if (rib->tag != tag)
@@ -2942,17 +2943,22 @@ DEFUN (show_ipv6_route_prefix_longer,
     return CMD_SUCCESS;
 
   /* Show matched type IPv6 routes. */
-  for (rn = route_top (table); rn; rn = route_next (rn))
+  for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
     RNODE_FOREACH_RIB (rn, rib)
-      if (prefix_match (&p, &rn->p))
-       {
-         if (first)
-           {
-             vty_out (vty, SHOW_ROUTE_V6_HEADER);
-             first = 0;
-           }
-         vty_show_ip_route (vty, rn, rib, NULL);
-       }
+      {
+        struct prefix *p, *src_p;
+        srcdest_rnode_prefixes(rn, &p, &src_p);
+
+        if (prefix_match (p, &rn->p))
+          {
+            if (first)
+              {
+                vty_out (vty, SHOW_ROUTE_V6_HEADER);
+                first = 0;
+              }
+            vty_show_ip_route (vty, rn, rib, NULL);
+          }
+      }
   return CMD_SUCCESS;
 }
 
@@ -2990,7 +2996,7 @@ DEFUN (show_ipv6_route_protocol,
     return CMD_SUCCESS;
 
   /* Show matched type IPv6 routes. */
-  for (rn = route_top (table); rn; rn = route_next (rn))
+  for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
     RNODE_FOREACH_RIB (rn, rib)
       if (rib->type == type)
        {
@@ -3180,7 +3186,7 @@ DEFUN (show_ipv6_mroute,
     return CMD_SUCCESS;
 
   /* Show all IPv6 route. */
-  for (rn = route_top (table); rn; rn = route_next (rn))
+  for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
     RNODE_FOREACH_RIB (rn, rib)
       {
        if (first)
@@ -3217,7 +3223,7 @@ DEFUN (show_ipv6_route_vrf_all,
         continue;
 
       /* Show all IPv6 route. */
-      for (rn = route_top (table); rn; rn = route_next (rn))
+      for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
         RNODE_FOREACH_RIB (rn, rib)
           {
             if (first)
@@ -3269,7 +3275,7 @@ DEFUN (show_ipv6_route_vrf_all_tag,
         continue;
 
       /* Show all IPv6 routes with matching tag value. */
-      for (rn = route_top (table); rn; rn = route_next (rn))
+      for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
         RNODE_FOREACH_RIB (rn, rib)
           {
             if (rib->tag != tag)
@@ -3329,23 +3335,27 @@ DEFUN (show_ipv6_route_vrf_all_prefix_longer,
         continue;
 
       /* Show matched type IPv6 routes. */
-      for (rn = route_top (table); rn; rn = route_next (rn))
+      for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
         RNODE_FOREACH_RIB (rn, rib)
-          if (prefix_match (&p, &rn->p))
-            {
-              if (first)
-                {
-                  vty_out (vty, SHOW_ROUTE_V6_HEADER);
-                  first = 0;
-                }
-
-            if (vrf_header)
+          {
+            struct prefix *p, *src_p;
+            srcdest_rnode_prefixes(rn, &p, &src_p);
+            if (prefix_match (p, &rn->p))
               {
-                vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf_name (zvrf), VTY_NEWLINE);
-                vrf_header = 0;
+                if (first)
+                  {
+                    vty_out (vty, SHOW_ROUTE_V6_HEADER);
+                    first = 0;
+                  }
+
+                if (vrf_header)
+                  {
+                    vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf_name (zvrf), VTY_NEWLINE);
+                    vrf_header = 0;
+                  }
+                vty_show_ip_route (vty, rn, rib, NULL);
               }
-              vty_show_ip_route (vty, rn, rib, NULL);
-            }
+          }
       vrf_header = 1;
     }
 
@@ -3386,7 +3396,7 @@ DEFUN (show_ipv6_route_vrf_all_protocol,
         continue;
 
       /* Show matched type IPv6 routes. */
-      for (rn = route_top (table); rn; rn = route_next (rn))
+      for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
         RNODE_FOREACH_RIB (rn, rib)
           if (rib->type == type)
             {
@@ -3539,7 +3549,7 @@ DEFUN (show_ipv6_mroute_vrf_all,
         continue;
 
       /* Show all IPv6 route. */
-      for (rn = route_top (table); rn; rn = route_next (rn))
+      for (rn = route_top (table); rn; rn = srcdest_route_next (rn))
         RNODE_FOREACH_RIB (rn, rib)
           {
            if (first)
index fd40ed123b2ab0b4b4743104a284e3bdad19a1d1..9749efb75d8e9752ec334efc09cf5ed54606008b 100644 (file)
@@ -601,7 +601,7 @@ zsend_interface_update (int cmd, struct zserv *client, struct interface *ifp)
  */
 int
 zsend_redistribute_route (int add, struct zserv *client, struct prefix *p,
-                         struct rib *rib)
+                          struct prefix *src_p, struct rib *rib)
 {
   afi_t afi;
   int cmd;
@@ -667,6 +667,14 @@ zsend_redistribute_route (int add, struct zserv *client, struct prefix *p,
   stream_putc (s, p->prefixlen);
   stream_write (s, (u_char *) & p->u.prefix, psize);
 
+  if (src_p)
+    {
+      SET_FLAG (zapi_flags, ZAPI_MESSAGE_SRCPFX);
+      psize = PSIZE (src_p->prefixlen);
+      stream_putc (s, src_p->prefixlen);
+      stream_write (s, (u_char *) & src_p->u.prefix, psize);
+    }
+
   for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
     {
       /* We don't send any nexthops when there's a multipath */
index d17a28eb6a9f50c6b9c11d9f6944412d2cac49ef..a5a9979468b28db42cfb6835ec68e4bc6cb97175 100644 (file)
@@ -162,7 +162,7 @@ extern void nbr_connected_add_ipv6 (struct interface *, struct in6_addr *);
 extern void nbr_connected_delete_ipv6 (struct interface *, struct in6_addr *);
 extern int zsend_interface_update (int, struct zserv *, struct interface *);
 extern int zsend_redistribute_route (int, struct zserv *, struct prefix *,
-                                    struct rib *);
+                                     struct prefix *, struct rib *);
 extern int zsend_router_id_update (struct zserv *, struct prefix *,
                                    vrf_id_t);
 extern int zsend_interface_vrf_update (struct zserv *, struct interface *,