]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: support static srcdest routes
authorChristian Franke <nobody@nowhere.ws>
Thu, 24 Nov 2016 16:10:19 +0000 (17:10 +0100)
committerChristian Franke <chris@opensourcerouting.org>
Mon, 30 Jan 2017 12:54:46 +0000 (13:54 +0100)
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
zebra/zebra_mpls_vty.c
zebra/zebra_static.c
zebra/zebra_static.h
zebra/zebra_vrf.c
zebra/zebra_vty.c

index 0185b555f2cd20bb9d5af9ea48a21b675ec70f1d..fcd0fff32cea1146e2ce15f1a305e82ff3a6d708 100644 (file)
@@ -521,7 +521,7 @@ DEFUN (ipv6_route_label,
        "Specify label(s) for this route\n"
        "One or more labels separated by '/'\n")
 {
-  return static_ipv6_func (vty, 1, argv[2]->arg, argv[3]->arg, NULL, NULL, NULL, NULL, NULL, argv[5]->arg);
+  return static_ipv6_func (vty, 1, argv[2]->arg, NULL, argv[3]->arg, NULL, NULL, NULL, NULL, NULL, argv[5]->arg);
 }
 
 DEFUN (ipv6_route_tag_label,
@@ -537,7 +537,7 @@ DEFUN (ipv6_route_tag_label,
        "Specify label(s) for this route\n"
        "One or more labels separated by '/'\n")
 {
-  return static_ipv6_func (vty, 1, argv[2]->arg, argv[3]->arg, NULL, NULL, argv[5]->arg, NULL, NULL, argv[7]->arg);
+  return static_ipv6_func (vty, 1, argv[2]->arg, NULL, argv[3]->arg, NULL, NULL, argv[5]->arg, NULL, NULL, argv[7]->arg);
 }
 
 DEFUN (ipv6_route_ifname_label,
@@ -551,7 +551,7 @@ DEFUN (ipv6_route_ifname_label,
        "Specify label(s) for this route\n"
        "One or more labels separated by '/'\n")
 {
-  return static_ipv6_func (vty, 1, argv[2]->arg, argv[3]->arg, argv[4]->arg, NULL, NULL, NULL, NULL, argv[6]->arg);
+  return static_ipv6_func (vty, 1, argv[2]->arg, NULL, argv[3]->arg, argv[4]->arg, NULL, NULL, NULL, NULL, argv[6]->arg);
 }
 DEFUN (ipv6_route_ifname_tag_label,
        ipv6_route_ifname_tag_label_cmd,
@@ -566,7 +566,7 @@ DEFUN (ipv6_route_ifname_tag_label,
        "Specify label(s) for this route\n"
        "One or more labels separated by '/'\n")
 {
-  return static_ipv6_func (vty, 1, argv[2]->arg, argv[3]->arg, argv[4]->arg, NULL, argv[6]->arg, NULL, NULL, argv[8]->arg);
+  return static_ipv6_func (vty, 1, argv[2]->arg, NULL, argv[3]->arg, argv[4]->arg, NULL, argv[6]->arg, NULL, NULL, argv[8]->arg);
 }
 
 DEFUN (ipv6_route_pref_label,
@@ -581,7 +581,7 @@ DEFUN (ipv6_route_pref_label,
        "Specify label(s) for this route\n"
        "One or more labels separated by '/'\n")
 {
-  return static_ipv6_func (vty, 1, argv[2]->arg, argv[3]->arg, NULL, NULL, NULL, argv[4]->arg, NULL, argv[6]->arg);
+  return static_ipv6_func (vty, 1, argv[2]->arg, NULL, argv[3]->arg, NULL, NULL, NULL, argv[4]->arg, NULL, argv[6]->arg);
 }
 
 DEFUN (ipv6_route_pref_tag_label,
@@ -598,7 +598,7 @@ DEFUN (ipv6_route_pref_tag_label,
        "Specify label(s) for this route\n"
        "One or more labels separated by '/'\n")
 {
-  return static_ipv6_func (vty, 1, argv[2]->arg, argv[3]->arg, NULL, NULL, argv[5]->arg, argv[6]->arg, NULL, argv[8]->arg);
+  return static_ipv6_func (vty, 1, argv[2]->arg, NULL, argv[3]->arg, NULL, NULL, argv[5]->arg, argv[6]->arg, NULL, argv[8]->arg);
 }
 
 DEFUN (ipv6_route_ifname_pref_label,
@@ -613,7 +613,7 @@ DEFUN (ipv6_route_ifname_pref_label,
        "Specify label(s) for this route\n"
        "One or more labels separated by '/'\n")
 {
-  return static_ipv6_func (vty, 1, argv[2]->arg, argv[3]->arg, argv[4]->arg, NULL, NULL, argv[5]->arg, NULL, argv[7]->arg);
+  return static_ipv6_func (vty, 1, argv[2]->arg, NULL, argv[3]->arg, argv[4]->arg, NULL, NULL, argv[5]->arg, NULL, argv[7]->arg);
 }
 
 DEFUN (ipv6_route_ifname_pref_tag_label,
@@ -630,7 +630,7 @@ DEFUN (ipv6_route_ifname_pref_tag_label,
        "Specify label(s) for this route\n"
        "One or more labels separated by '/'\n")
 {
-  return static_ipv6_func (vty, 1, argv[2]->arg, argv[3]->arg, argv[4]->arg, NULL, argv[6]->arg, argv[7]->arg, NULL, argv[9]->arg);
+  return static_ipv6_func (vty, 1, argv[2]->arg, NULL, argv[3]->arg, argv[4]->arg, NULL, argv[6]->arg, argv[7]->arg, NULL, argv[9]->arg);
 }
 
 DEFUN (no_ipv6_route_label,
@@ -645,7 +645,7 @@ DEFUN (no_ipv6_route_label,
        "Specify label(s) for this route\n"
        "One or more labels separated by '/'\n")
 {
-  return static_ipv6_func (vty, 0, argv[3]->arg, argv[4]->arg, NULL, NULL, NULL, NULL, NULL, argv[6]->arg);
+  return static_ipv6_func (vty, 0, argv[3]->arg, NULL, argv[4]->arg, NULL, NULL, NULL, NULL, NULL, argv[6]->arg);
 }
 
 DEFUN (no_ipv6_route_tag_label,
@@ -662,7 +662,7 @@ DEFUN (no_ipv6_route_tag_label,
        "Specify label(s) for this route\n"
        "One or more labels separated by '/'\n")
 {
-  return static_ipv6_func (vty, 0, argv[3]->arg, argv[4]->arg, NULL, NULL, argv[6]->arg, NULL, NULL, argv[8]->arg);
+  return static_ipv6_func (vty, 0, argv[3]->arg, NULL, argv[4]->arg, NULL, NULL, argv[6]->arg, NULL, NULL, argv[8]->arg);
 }
 
 DEFUN (no_ipv6_route_ifname_label,
@@ -677,7 +677,7 @@ DEFUN (no_ipv6_route_ifname_label,
        "Specify label(s) for this route\n"
        "One or more labels separated by '/'\n")
 {
-  return static_ipv6_func (vty, 0, argv[3]->arg, argv[4]->arg, argv[5]->arg, NULL, NULL, NULL, NULL, argv[7]->arg);
+  return static_ipv6_func (vty, 0, argv[3]->arg, NULL, argv[4]->arg, argv[5]->arg, NULL, NULL, NULL, NULL, argv[7]->arg);
 }
 
 DEFUN (no_ipv6_route_ifname_tag_label,
@@ -694,7 +694,7 @@ DEFUN (no_ipv6_route_ifname_tag_label,
        "Specify label(s) for this route\n"
        "One or more labels separated by '/'\n")
 {
-  return static_ipv6_func (vty, 0, argv[3]->arg, argv[4]->arg, argv[5]->arg, NULL, argv[7]->arg, NULL, NULL, argv[9]->arg);
+  return static_ipv6_func (vty, 0, argv[3]->arg, NULL, argv[4]->arg, argv[5]->arg, NULL, argv[7]->arg, NULL, NULL, argv[9]->arg);
 }
 
 DEFUN (no_ipv6_route_pref_label,
@@ -710,7 +710,7 @@ DEFUN (no_ipv6_route_pref_label,
        "Specify label(s) for this route\n"
        "One or more labels separated by '/'\n")
 {
-  return static_ipv6_func (vty, 0, argv[3]->arg, argv[4]->arg, NULL, NULL, NULL, argv[5]->arg, NULL, argv[7]->arg);
+  return static_ipv6_func (vty, 0, argv[3]->arg, NULL, argv[4]->arg, NULL, NULL, NULL, argv[5]->arg, NULL, argv[7]->arg);
 }
 
 DEFUN (no_ipv6_route_pref_tag_label,
@@ -728,7 +728,7 @@ DEFUN (no_ipv6_route_pref_tag_label,
        "Specify label(s) for this route\n"
        "One or more labels separated by '/'\n")
 {
-  return static_ipv6_func (vty, 0, argv[3]->arg, argv[4]->arg, NULL, NULL, argv[6]->arg, argv[7]->arg, NULL, argv[9]->arg);
+  return static_ipv6_func (vty, 0, argv[3]->arg, NULL, argv[4]->arg, NULL, NULL, argv[6]->arg, argv[7]->arg, NULL, argv[9]->arg);
 }
 
 DEFUN (no_ipv6_route_ifname_pref_label,
@@ -744,7 +744,7 @@ DEFUN (no_ipv6_route_ifname_pref_label,
        "Specify label(s) for this route\n"
        "One or more labels separated by '/'\n")
 {
-  return static_ipv6_func (vty, 0, argv[3]->arg, argv[4]->arg, argv[5]->arg, NULL, NULL, argv[6]->arg, NULL, argv[8]->arg);
+  return static_ipv6_func (vty, 0, argv[3]->arg, NULL, argv[4]->arg, argv[5]->arg, NULL, NULL, argv[6]->arg, NULL, argv[8]->arg);
 }
 
 DEFUN (no_ipv6_route_ifname_pref_tag_label,
@@ -762,7 +762,7 @@ DEFUN (no_ipv6_route_ifname_pref_tag_label,
        "Specify label(s) for this route\n"
        "One or more labels separated by '/'\n")
 {
-  return static_ipv6_func (vty, 0, argv[3]->arg, argv[4]->arg, argv[5]->arg, NULL, argv[7]->arg, argv[8]->arg, NULL, argv[10]->arg);
+  return static_ipv6_func (vty, 0, argv[3]->arg, NULL, argv[4]->arg, argv[5]->arg, NULL, argv[7]->arg, argv[8]->arg, NULL, argv[10]->arg);
 }
 
 /* MPLS LSP configuration write function. */
index 33f0a2bd7216927b4e68d18b4a1a3628e3c54eec..1302f1cd39bbc8051ca42dccc40502fb90934a1b 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <lib/nexthop.h>
 #include <lib/memory.h>
+#include <lib/srcdest_table.h>
 
 #include "vty.h"
 #include "zebra/debug.h"
@@ -37,7 +38,8 @@
 
 /* Install static route into rib. */
 void
-static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si)
+static_install_route (afi_t afi, safi_t safi, struct prefix *p,
+                      struct prefix_ipv6 *src_p, struct static_route *si)
 {
   struct rib *rib;
   struct route_node *rn;
@@ -53,7 +55,7 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro
   memset (&nh_p, 0, sizeof (nh_p));
 
   /* Lookup existing route */
-  rn = route_node_get (table, p);
+  rn = srcdest_rnode_get (table, p, src_p);
   RNODE_FOREACH_RIB (rn, rib)
     {
        if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
@@ -252,7 +254,8 @@ static_nexthop_same (struct nexthop *nexthop, struct static_route *si)
 
 /* Uninstall static route from RIB. */
 void
-static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si)
+static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p,
+                        struct prefix_ipv6 *src_p, struct static_route *si)
 {
   struct route_node *rn;
   struct rib *rib;
@@ -266,7 +269,7 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_
     return;
 
   /* Lookup existing route with type and distance. */
-  rn = route_node_lookup (table, p);
+  rn = srcdest_rnode_lookup (table, p, src_p);
   if (! rn)
     return;
 
@@ -328,13 +331,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, NULL, rib, NULL);
+                redistribute_update (p, (struct prefix*)src_p, rib, NULL);
             }
           else
             {
               /* Remove from redistribute if selected route becomes inactive */
               if (CHECK_FLAG(rib->flags, ZEBRA_FLAG_SELECTED))
-                redistribute_delete (&rn->p, NULL, rib);
+                redistribute_delete (p, (struct prefix*)src_p, rib);
               /* Remove from kernel if fib route becomes inactive */
               if (CHECK_FLAG(rib->status, RIB_ENTRY_SELECTED_FIB))
               rib_uninstall_kernel (rn, rib);
@@ -364,6 +367,7 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_
 
 int
 static_add_route (afi_t afi, safi_t safi, u_char type, struct prefix *p,
+                 struct prefix_ipv6 *src_p,
                  union g_addr *gate, ifindex_t ifindex,
                  const char *ifname, u_char flags, route_tag_t tag,
                  u_char distance, struct zebra_vrf *zvrf,
@@ -391,7 +395,7 @@ static_add_route (afi_t afi, safi_t safi, u_char type, struct prefix *p,
     return -1;
 
   /* Lookup static route prefix. */
-  rn = route_node_get (stable, p);
+  rn = srcdest_rnode_get (stable, p, src_p);
 
   /* Do nothing if there is a same static route.  */
   for (si = rn->info; si; si = si->next)
@@ -416,7 +420,7 @@ static_add_route (afi_t afi, safi_t safi, u_char type, struct prefix *p,
 
   /* Distance or tag or label changed, delete existing first. */
   if (update)
-    static_delete_route (afi, safi, type, p, gate, ifindex, update->tag,
+    static_delete_route (afi, safi, type, p, src_p, gate, ifindex, update->tag,
                         update->distance, zvrf, &update->snh_label);
 
   /* Make new static route structure. */
@@ -477,13 +481,14 @@ static_add_route (afi_t afi, safi_t safi, u_char type, struct prefix *p,
   si->next = cp;
 
   /* Install into rib. */
-  static_install_route (afi, safi, p, si);
+  static_install_route (afi, safi, p, src_p, si);
 
   return 1;
 }
 
 int
 static_delete_route (afi_t afi, safi_t safi, u_char type, struct prefix *p,
+                    struct prefix_ipv6 *src_p,
                     union g_addr *gate, ifindex_t ifindex,
                     route_tag_t tag, u_char distance, struct zebra_vrf *zvrf,
                     struct static_nh_label *snh_label)
@@ -498,7 +503,7 @@ static_delete_route (afi_t afi, safi_t safi, u_char type, struct prefix *p,
     return -1;
 
   /* Lookup static route prefix. */
-  rn = route_node_lookup (stable, p);
+  rn = srcdest_rnode_lookup (stable, p, src_p);
   if (! rn)
     return 0;
 
@@ -522,7 +527,7 @@ static_delete_route (afi_t afi, safi_t safi, u_char type, struct prefix *p,
     }
 
   /* Install into rib. */
-  static_uninstall_route (afi, safi, p, si);
+  static_uninstall_route (afi, safi, p, src_p, si);
 
   /* Unlink static route from linked list. */
   if (si->prev)
index 233436f02d59dd52dda5e2323be2286bcfd1d10b..adc2efff585cb52bf48fd27d5c6f062b638040cd 100644 (file)
@@ -83,12 +83,15 @@ struct static_route
 };
 
 extern void
-static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si);
+static_install_route (afi_t afi, safi_t safi, struct prefix *p,
+                      struct prefix_ipv6 *src_p, struct static_route *si);
 extern void
-static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si);
+static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p,
+                        struct prefix_ipv6 *src_p, struct static_route *si);
 
 extern int
 static_add_route (afi_t, safi_t safi, u_char type, struct prefix *p,
+                 struct prefix_ipv6 *src_p,
                  union g_addr *gate, ifindex_t ifindex,
                  const char *ifname, u_char flags, route_tag_t tag,
                  u_char distance, struct zebra_vrf *zvrf,
@@ -96,6 +99,7 @@ static_add_route (afi_t, safi_t safi, u_char type, struct prefix *p,
 
 extern int
 static_delete_route (afi_t, safi_t safi, u_char type, struct prefix *p,
+                    struct prefix_ipv6 *src_p,
                     union g_addr *gate, ifindex_t ifindex, route_tag_t tag,
                     u_char distance, struct zebra_vrf *zvrf,
                     struct static_nh_label *snh_label);
@@ -109,6 +113,7 @@ zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd,
 
 int
 static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
+                 const char *src_str,
                  const char *gate_str, const char *ifname,
                  const char *flag_str, const char *tag_str,
                   const char *distance_str, const char *vrf_id_str,
index bc86e4a10b99dbedadde104106908d54650878eb..6fc41c3a1486595b573517095a0f0f13835da1cd 100644 (file)
@@ -133,7 +133,7 @@ zebra_vrf_static_route_interface_fixup (struct interface *ifp)
                        (si->ifindex != ifp->ifindex))
                      {
                        si->ifindex = ifp->ifindex;
-                       static_install_route (afi, safi, &rn->p, si);
+                       static_install_route (afi, safi, &rn->p, NULL, si);
                      }   
                  }
              }
@@ -177,7 +177,7 @@ zebra_vrf_enable (struct vrf *vrf)
                  else
                    continue;
                }
-             static_install_route (afi, safi, &rn->p, si);
+             static_install_route (afi, safi, &rn->p, NULL, si);
            }
       }
 
@@ -208,7 +208,7 @@ zebra_vrf_disable (struct vrf *vrf)
 
        for (rn = route_top (stable); rn; rn = route_next (rn))
          for (si = rn->info; si; si = si->next)
-           static_uninstall_route(afi, safi, &rn->p, si);
+           static_uninstall_route(afi, safi, &rn->p, NULL, si);
       }
 
   return 0;
@@ -344,8 +344,7 @@ zebra_rtable_node_cleanup (struct route_table *table, struct route_node *node)
 }
 
 static void
-zebra_stable_node_destroy (route_table_delegate_t *delegate,
-                          struct route_table *table, struct route_node *node)
+zebra_stable_node_cleanup (struct route_table *table, struct route_node *node)
 {
   struct static_route *si, *next;
 
@@ -355,8 +354,6 @@ zebra_stable_node_destroy (route_table_delegate_t *delegate,
        next = si->next;
        XFREE (MTYPE_STATIC_ROUTE, si);
       }
-
-  route_node_destroy (delegate, table, node);
 }
 
 static void
@@ -366,11 +363,6 @@ zebra_rnhtable_node_cleanup (struct route_table *table, struct route_node *node)
     zebra_free_rnh (node->info);
 }
 
-route_table_delegate_t zebra_stable_delegate = {
-  .create_node = route_node_create,
-  .destroy_node = zebra_stable_node_destroy
-};
-
 /*
  * Create a routing table for the specific AFI/SAFI in the given VRF.
  */
@@ -410,11 +402,15 @@ zebra_vrf_alloc (void)
   for (afi = AFI_IP; afi <= AFI_IP6; afi++)
     {
       for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
-       {
-         zebra_vrf_table_create (zvrf, afi, safi);
-         zvrf->stable[afi][safi] =
-               route_table_init_with_delegate (&zebra_stable_delegate);
-       }
+        {
+          zebra_vrf_table_create (zvrf, afi, safi);
+          if (afi == AFI_IP6)
+            table = srcdest_table_init();
+          else
+            table = route_table_init();
+          table->cleanup = zebra_stable_node_cleanup;
+          zvrf->stable[afi][safi] = table;
+        }
 
       table = route_table_init();
       table->cleanup = zebra_rnhtable_node_cleanup;
index bba0571c9ee5c32f514652771b158bcb3dc5dde7..17d8249906b91cc11afbc4ff32cd05533b4453b3 100644 (file)
@@ -142,10 +142,10 @@ zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd,
           return CMD_WARNING;
         }
       if (add_cmd)
-        static_add_route (AFI_IP, safi, type, &p, NULL, ifindex, ifname,
+        static_add_route (AFI_IP, safi, type, &p, NULL, NULL, ifindex, ifname,
                          ZEBRA_FLAG_BLACKHOLE, tag, distance, zvrf, &snh_label);
       else
-        static_delete_route (AFI_IP, safi, type, &p, NULL, ifindex, tag,
+        static_delete_route (AFI_IP, safi, type, &p, NULL, NULL, ifindex, tag,
                             distance, zvrf, &snh_label);
       return CMD_SUCCESS;
     }
@@ -170,10 +170,10 @@ zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd,
   if (gate_str == NULL)
   {
     if (add_cmd)
-      static_add_route (AFI_IP, safi, type, &p, NULL, ifindex, ifname, flag,
+      static_add_route (AFI_IP, safi, type, &p, NULL, NULL, ifindex, ifname, flag,
                        tag, distance, zvrf, &snh_label);
     else
-      static_delete_route (AFI_IP, safi, type, &p, NULL, ifindex, tag, distance,
+      static_delete_route (AFI_IP, safi, type, &p, NULL, NULL, ifindex, tag, distance,
                           zvrf, &snh_label);
 
     return CMD_SUCCESS;
@@ -199,11 +199,11 @@ zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd,
     type = STATIC_IPV4_GATEWAY;
 
   if (add_cmd)
-    static_add_route (AFI_IP, safi, type, &p,
+    static_add_route (AFI_IP, safi, type, &p, NULL,
                      ifindex ? NULL : (union g_addr *)&gate, ifindex, ifname,
                      flag, tag, distance, zvrf, &snh_label);
   else
-    static_delete_route (AFI_IP, safi, type, &p,
+    static_delete_route (AFI_IP, safi, type, &p, NULL,
                         ifindex ? NULL : (union g_addr *)&gate, ifindex, tag,
                         distance, zvrf, &snh_label);
 
@@ -2329,6 +2329,7 @@ static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd)
 /* General fucntion for IPv6 static route. */
 int
 static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
+                  const char *src_str,
                   const char *gate_str, const char *ifname,
                   const char *flag_str, const char *tag_str,
                   const char *distance_str, const char *vrf_id_str,
@@ -2336,7 +2337,8 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
 {
   int ret;
   u_char distance;
-  struct prefix p;
+  struct prefix p, src;
+  struct prefix_ipv6 *src_p = NULL;
   struct in6_addr *gate = NULL;
   struct in6_addr gate_addr;
   u_char type = STATIC_BLACKHOLE;
@@ -2354,6 +2356,17 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
       return CMD_WARNING;
     }
 
+  if (src_str)
+    {
+      ret = str2prefix (src_str, &src);
+      if (ret <= 0 || src.family != AF_INET6)
+        {
+          vty_out (vty, "%% Malformed source address%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+      src_p = (struct prefix_ipv6*)&src;
+    }
+
   /* Apply mask for given prefix. */
   apply_mask (&p);
 
@@ -2407,10 +2420,10 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
           return CMD_WARNING;
         }
       if (add_cmd)
-        static_add_route (AFI_IP6, SAFI_UNICAST, type, &p, NULL, ifindex, ifname,
+        static_add_route (AFI_IP6, SAFI_UNICAST, type, &p, NULL, NULL, ifindex, ifname,
                           ZEBRA_FLAG_BLACKHOLE, tag, distance, zvrf, &snh_label);
       else
-        static_delete_route (AFI_IP6, SAFI_UNICAST, type, &p,  NULL, ifindex, tag,
+        static_delete_route (AFI_IP6, SAFI_UNICAST, type, &p, NULL, NULL, ifindex, tag,
                              distance, zvrf, &snh_label);
       return CMD_SUCCESS;
     }
@@ -2474,10 +2487,10 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
     }
 
   if (add_cmd)
-    static_add_route (AFI_IP6, SAFI_UNICAST, type, &p, (union g_addr *)gate,
+    static_add_route (AFI_IP6, SAFI_UNICAST, type, &p, src_p, (union g_addr *)gate,
                       ifindex, ifname, flag, tag, distance, zvrf, &snh_label);
   else
-    static_delete_route (AFI_IP6, SAFI_UNICAST, type, &p, (union g_addr *)gate,
+    static_delete_route (AFI_IP6, SAFI_UNICAST, type, &p, src_p, (union g_addr *)gate,
                          ifindex, tag, distance, zvrf, &snh_label);
 
   return CMD_SUCCESS;
@@ -2485,10 +2498,12 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
 
 DEFUN (ipv6_route,
        ipv6_route_cmd,
-       "ipv6 route X:X::X:X/M <X:X::X:X|INTERFACE|null0> [tag (1-4294967295)] [(1-255)] [vrf NAME]",
+       "ipv6 route X:X::X:X/M [from X:X::X:X/M] <X:X::X:X|INTERFACE|null0> [tag (1-4294967295)] [(1-255)] [vrf NAME]",
        IP_STR
        "Establish static routes\n"
        "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 source-dest route\n"
+       "IPv6 source prefix\n"
        "IPv6 gateway address\n"
        "IPv6 gateway interface name\n"
        "Null interface\n"
@@ -2501,15 +2516,29 @@ DEFUN (ipv6_route,
        "One or more labels separated by '/'\n")
 {
   int idx_ipv6_prefixlen = 2;
-  int idx_ipv6_ifname = 3;
-  int idx_curr = 4;
-  char *tag, *distance, *vrf;
+  int idx_ipv6_ifname;
+  int idx_curr;
+  char *src, *tag, *distance, *vrf;
+
+  if (!strcmp(argv[3]->text, "from"))
+    {
+      src = argv[4]->arg;
+      idx_ipv6_ifname = 5;
+      idx_curr = 6;
+    }
+  else
+    {
+      src = NULL;
+      idx_ipv6_ifname = 3;
+      idx_curr = 4;
+    }
 
   tag = distance = vrf = NULL;
   zebra_vty_ip_route_tdv_helper (argc, argv, idx_curr, &tag, &distance, &vrf, NULL);
 
   return static_ipv6_func (vty, 1,
                           argv[idx_ipv6_prefixlen]->arg,
+                          src,
                           argv[idx_ipv6_ifname]->arg,
                           NULL, NULL,
                           tag, distance, vrf, NULL);
@@ -2517,10 +2546,12 @@ DEFUN (ipv6_route,
 
 DEFUN (ipv6_route_flags,
        ipv6_route_flags_cmd,
-       "ipv6 route X:X::X:X/M <X:X::X:X|INTERFACE> <reject|blackhole> [tag (1-4294967295)] [(1-255)] [vrf NAME]",
+       "ipv6 route X:X::X:X/M [from X:X::X:X/M] <X:X::X:X|INTERFACE> <reject|blackhole> [tag (1-4294967295)] [(1-255)] [vrf NAME]",
        IP_STR
        "Establish static routes\n"
        "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 source-dest route\n"
+       "IPv6 source prefix\n"
        "IPv6 gateway address\n"
        "IPv6 gateway interface name\n"
        "Emit an ICMP unreachable when matched\n"
@@ -2534,16 +2565,32 @@ DEFUN (ipv6_route_flags,
        "One or more labels separated by '/'\n")
 {
   int idx_ipv6_prefixlen = 2;
-  int idx_ipv6_ifname = 3;
-  int idx_reject_blackhole = 4;
-  int idx_curr = 5;
-  char *tag, *distance, *vrf;
+  int idx_ipv6_ifname;
+  int idx_reject_blackhole;
+  int idx_curr;
+  char *src, *tag, *distance, *vrf;
+
+  if (!strcmp(argv[3]->text, "from"))
+    {
+      src = argv[4]->arg;
+      idx_ipv6_ifname = 5;
+      idx_reject_blackhole = 6;
+      idx_curr = 7;
+    }
+  else
+    {
+      src = NULL;
+      idx_ipv6_ifname = 3;
+      idx_reject_blackhole = 4;
+      idx_curr = 5;
+    }
 
   tag = distance = vrf = NULL;
   zebra_vty_ip_route_tdv_helper (argc, argv, idx_curr, &tag, &distance, &vrf, NULL);
 
   return static_ipv6_func (vty, 1,
                           argv[idx_ipv6_prefixlen]->arg,
+                          src,
                           argv[idx_ipv6_ifname]->arg,
                           NULL,
                           argv[idx_reject_blackhole]->arg,
@@ -2552,10 +2599,12 @@ DEFUN (ipv6_route_flags,
 
 DEFUN (ipv6_route_ifname,
        ipv6_route_ifname_cmd,
-       "ipv6 route X:X::X:X/M X:X::X:X INTERFACE [tag (1-4294967295)] [(1-255)] [vrf NAME]",
+       "ipv6 route X:X::X:X/M [from X:X::X:X/M] X:X::X:X INTERFACE [tag (1-4294967295)] [(1-255)] [vrf NAME]",
        IP_STR
        "Establish static routes\n"
        "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 source-dest route\n"
+       "IPv6 source prefix\n"
        "IPv6 gateway address\n"
        "IPv6 gateway interface name\n"
        "Set tag for this route\n"
@@ -2569,13 +2618,29 @@ DEFUN (ipv6_route_ifname,
   int idx_ipv6 = 3;
   int idx_interface = 4;
   int idx_curr = 5;
-  char *tag, *distance, *vrf;
+  char *src, *tag, *distance, *vrf;
+
+  if (!strcmp(argv[3]->text, "from"))
+    {
+      src = argv[4]->arg;
+      idx_ipv6 = 5;
+      idx_interface = 6;
+      idx_curr = 7;
+    }
+  else
+    {
+      src = NULL;
+      idx_ipv6 = 3;
+      idx_interface = 4;
+      idx_curr = 5;
+    }
 
   tag = distance = vrf = NULL;
   zebra_vty_ip_route_tdv_helper (argc, argv, idx_curr, &tag, &distance, &vrf, NULL);
 
   return static_ipv6_func (vty, 1,
                           argv[idx_ipv6_prefixlen]->arg,
+                          src,
                           argv[idx_ipv6]->arg,
                           argv[idx_interface]->arg,
                           NULL,
@@ -2584,10 +2649,12 @@ DEFUN (ipv6_route_ifname,
 
 DEFUN (ipv6_route_ifname_flags,
        ipv6_route_ifname_flags_cmd,
-       "ipv6 route X:X::X:X/M X:X::X:X INTERFACE <reject|blackhole> [tag (1-4294967295)] [(1-255)] [vrf NAME]",
+       "ipv6 route X:X::X:X/M [from X:X::X:X/M] X:X::X:X INTERFACE <reject|blackhole> [tag (1-4294967295)] [(1-255)] [vrf NAME]",
        IP_STR
        "Establish static routes\n"
        "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 source-dest route\n"
+       "IPv6 source prefix\n"
        "IPv6 gateway address\n"
        "IPv6 gateway interface name\n"
        "Emit an ICMP unreachable when matched\n"
@@ -2600,17 +2667,35 @@ DEFUN (ipv6_route_ifname_flags,
        "One or more labels separated by '/'\n")
 {
   int idx_ipv6_prefixlen = 2;
-  int idx_ipv6 = 3;
-  int idx_interface = 4;
-  int idx_reject_blackhole = 5;
-  int idx_curr = 6;
-  char *tag, *distance, *vrf;
+  int idx_ipv6;
+  int idx_interface;
+  int idx_reject_blackhole;
+  int idx_curr;
+  char *src, *tag, *distance, *vrf;
+
+  if (!strcmp(argv[3]->text, "from"))
+    {
+      src = argv[4]->arg;
+      idx_ipv6 = 5;
+      idx_interface = 6;
+      idx_reject_blackhole = 7;
+      idx_curr = 8;
+    }
+  else
+    {
+      src = NULL;
+      idx_ipv6 = 3;
+      idx_interface = 4;
+      idx_reject_blackhole = 5;
+      idx_curr = 6;
+    }
 
   tag = distance = vrf = NULL;
   zebra_vty_ip_route_tdv_helper (argc, argv, idx_curr, &tag, &distance, &vrf, NULL);
 
   return static_ipv6_func (vty, 1,
                           argv[idx_ipv6_prefixlen]->arg,
+                          src,
                           argv[idx_ipv6]->arg,
                           argv[idx_interface]->arg,
                           argv[idx_reject_blackhole]->arg,
@@ -2619,11 +2704,13 @@ DEFUN (ipv6_route_ifname_flags,
 
 DEFUN (no_ipv6_route,
        no_ipv6_route_cmd,
-       "no ipv6 route X:X::X:X/M <X:X::X:X|INTERFACE|null0> [tag (1-4294967295)] [(1-255)] [vrf NAME]",
+       "no ipv6 route X:X::X:X/M [from X:X::X:X/M] <X:X::X:X|INTERFACE|null0> [tag (1-4294967295)] [(1-255)] [vrf NAME]",
        NO_STR
        IP_STR
        "Establish static routes\n"
        "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 source-dest route\n"
+       "IPv6 source prefix\n"
        "IPv6 gateway address\n"
        "IPv6 gateway interface name\n"
        "Null interface\n"
@@ -2635,15 +2722,29 @@ DEFUN (no_ipv6_route,
        "One or more labels separated by '/'\n")
 {
   int idx_ipv6_prefixlen = 3;
-  int idx_ipv6_ifname = 4;
-  int idx_curr = 5;
-  char *tag, *distance, *vrf;
+  int idx_ipv6_ifname;
+  int idx_curr;
+  char *src, *tag, *distance, *vrf;
+
+  if (!strcmp(argv[4]->text, "from"))
+    {
+      src = argv[5]->arg;
+      idx_ipv6_ifname = 6;
+      idx_curr = 7;
+    }
+  else
+    {
+      src = NULL;
+      idx_ipv6_ifname = 4;
+      idx_curr = 5;
+    }
 
   tag = distance = vrf = NULL;
   zebra_vty_ip_route_tdv_helper (argc, argv, idx_curr, &tag, &distance, &vrf, NULL);
 
   return static_ipv6_func (vty, 0,
                           argv[idx_ipv6_prefixlen]->arg,
+                          src,
                           argv[idx_ipv6_ifname]->arg,
                           NULL, NULL,
                           tag, distance, vrf, NULL);
@@ -2651,11 +2752,13 @@ DEFUN (no_ipv6_route,
 
 DEFUN (no_ipv6_route_flags,
        no_ipv6_route_flags_cmd,
-       "no ipv6 route X:X::X:X/M <X:X::X:X|INTERFACE> <reject|blackhole> [tag (1-4294967295)] [(1-255)] [vrf NAME]",
+       "no ipv6 route X:X::X:X/M [from X:X::X:X/M] <X:X::X:X|INTERFACE> <reject|blackhole> [tag (1-4294967295)] [(1-255)] [vrf NAME]",
        NO_STR
        IP_STR
        "Establish static routes\n"
        "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 source-dest route\n"
+       "IPv6 source prefix\n"
        "IPv6 gateway address\n"
        "IPv6 gateway interface name\n"
        "Emit an ICMP unreachable when matched\n"
@@ -2668,16 +2771,32 @@ DEFUN (no_ipv6_route_flags,
        "One or more labels separated by '/'\n")
 {
   int idx_ipv6_prefixlen = 3;
-  int idx_ipv6_ifname = 4;
-  int idx_reject_blackhole = 5;
-  int idx_curr = 6;
-  char *tag, *distance, *vrf;
+  int idx_ipv6_ifname;
+  int idx_reject_blackhole;
+  int idx_curr;
+  char *src, *tag, *distance, *vrf;
+
+  if (!strcmp(argv[4]->text, "from"))
+    {
+      src = argv[5]->arg;
+      idx_ipv6_ifname = 6;
+      idx_reject_blackhole = 7;
+      idx_curr = 8;
+    }
+  else
+    {
+      src = NULL;
+      idx_ipv6_ifname = 4;
+      idx_reject_blackhole = 5;
+      idx_curr = 6;
+    }
 
   tag = distance = vrf = NULL;
   zebra_vty_ip_route_tdv_helper (argc, argv, idx_curr, &tag, &distance, &vrf, NULL);
 
   return static_ipv6_func (vty, 0,
                           argv[idx_ipv6_prefixlen]->arg,
+                          src,
                           argv[idx_ipv6_ifname]->arg,
                           NULL,
                           argv[idx_reject_blackhole]->arg,
@@ -2686,11 +2805,13 @@ DEFUN (no_ipv6_route_flags,
 
 DEFUN (no_ipv6_route_ifname,
        no_ipv6_route_ifname_cmd,
-       "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE [tag (1-4294967295)] [(1-255)] [vrf NAME]",
+       "no ipv6 route X:X::X:X/M [from X:X::X:X/M] X:X::X:X INTERFACE [tag (1-4294967295)] [(1-255)] [vrf NAME]",
        NO_STR
        IP_STR
        "Establish static routes\n"
        "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 source-dest route\n"
+       "IPv6 source prefix\n"
        "IPv6 gateway address\n"
        "IPv6 gateway interface name\n"
        "Set tag for this route\n"
@@ -2701,16 +2822,32 @@ DEFUN (no_ipv6_route_ifname,
        "One or more labels separated by '/'\n")
 {
   int idx_ipv6_prefixlen = 3;
-  int idx_ipv6 = 4;
-  int idx_interface = 5;
-  int idx_curr = 6;
-  char *tag, *distance, *vrf;
+  int idx_ipv6;
+  int idx_interface;
+  int idx_curr;
+  char *src, *tag, *distance, *vrf;
+
+  if (!strcmp(argv[4]->text, "from"))
+    {
+      src = argv[5]->arg;
+      idx_ipv6 = 6;
+      idx_interface = 7;
+      idx_curr = 8;
+    }
+  else
+    {
+      src = NULL;
+      idx_ipv6 = 4;
+      idx_interface = 5;
+      idx_curr = 6;
+    }
 
   tag = distance = vrf = NULL;
   zebra_vty_ip_route_tdv_helper (argc, argv, idx_curr, &tag, &distance, &vrf, NULL);
 
   return static_ipv6_func (vty, 0,
                           argv[idx_ipv6_prefixlen]->arg,
+                          src,
                           argv[idx_ipv6]->arg,
                           argv[idx_interface]->arg,
                           NULL,
@@ -2719,11 +2856,13 @@ DEFUN (no_ipv6_route_ifname,
 
 DEFUN (no_ipv6_route_ifname_flags,
        no_ipv6_route_ifname_flags_cmd,
-       "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE <reject|blackhole> [tag (1-4294967295)] [(1-255)] [vrf NAME]",
+       "no ipv6 route X:X::X:X/M [from X:X::X:X/M] X:X::X:X INTERFACE <reject|blackhole> [tag (1-4294967295)] [(1-255)] [vrf NAME]",
        NO_STR
        IP_STR
        "Establish static routes\n"
        "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 source-dest route\n"
+       "IPv6 source prefix\n"
        "IPv6 gateway address\n"
        "IPv6 gateway interface name\n"
        "Emit an ICMP unreachable when matched\n"
@@ -2736,17 +2875,35 @@ DEFUN (no_ipv6_route_ifname_flags,
        "One or more labels separated by '/'\n")
 {
   int idx_ipv6_prefixlen = 3;
-  int idx_ipv6 = 4;
-  int idx_interface = 5;
-  int idx_reject_blackhole = 6;
-  int idx_curr = 7;
-  char *tag, *distance, *vrf;
+  int idx_ipv6;
+  int idx_interface;
+  int idx_reject_blackhole;
+  int idx_curr;
+  char *src, *tag, *distance, *vrf;
+
+  if (!strcmp(argv[4]->text, "from"))
+    {
+      src = argv[5]->arg;
+      idx_ipv6 = 6;
+      idx_interface = 7;
+      idx_reject_blackhole = 8;
+      idx_curr = 9;
+    }
+  else
+    {
+      src = NULL;
+      idx_ipv6 = 4;
+      idx_interface = 5;
+      idx_reject_blackhole = 6;
+      idx_curr = 7;
+    }
 
   tag = distance = vrf = NULL;
   zebra_vty_ip_route_tdv_helper (argc, argv, idx_curr, &tag, &distance, &vrf, NULL);
 
   return static_ipv6_func (vty, 0,
                           argv[idx_ipv6_prefixlen]->arg,
+                          src,
                           argv[idx_ipv6]->arg,
                           argv[idx_interface]->arg,
                           argv[idx_reject_blackhole]->arg,
@@ -3590,7 +3747,7 @@ static_config_ipv6 (struct vty *vty)
   struct route_node *rn;
   struct static_route *si;
   int write = 0;
-  char buf[PREFIX_STRLEN];
+  char buf[SRCDEST2STR_BUFFER];
   struct route_table *stable;
   struct vrf *vrf;
   struct zebra_vrf *zvrf;
@@ -3602,10 +3759,10 @@ static_config_ipv6 (struct vty *vty)
       if ((stable = zvrf->stable[AFI_IP6][SAFI_UNICAST]) == NULL)
         continue;
 
-      for (rn = route_top (stable); rn; rn = route_next (rn))
+      for (rn = route_top (stable); rn; rn = srcdest_route_next (rn))
         for (si = rn->info; si; si = si->next)
           {
-            vty_out (vty, "ipv6 route %s", prefix2str (&rn->p, buf, sizeof buf));
+            vty_out (vty, "ipv6 route %s", srcdest_rnode2str (rn, buf, sizeof buf));
 
            switch (si->type)
              {