]> git.puffer.fish Git - matthieu/frr.git/commitdiff
Zebra: Add IPv6 protocol filtering support & Setting Src of IPv6 routes
authorDinesh G Dutt <ddutt@cumulusnetworks.com>
Wed, 16 Sep 2015 06:48:00 +0000 (23:48 -0700)
committerDinesh G Dutt <ddutt@cumulusnetworks.com>
Wed, 16 Sep 2015 06:48:00 +0000 (23:48 -0700)
Ticket:
Reviewed By: CCR-3335
Testing Done: bgpsmoke, ENHE tests etc.

    Add support for filtering routes from upper layer protocols to zebra
    via route-maps for IPv6. The same functionality already existed for
    IPv4.

    In addition, add support for setting source of routes via IPv6 protocol
    map.

Signed-off-by: Dinesh G Dutt <ddutt@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Vivek Venkataraman <vivek@cumulusnetworks.com>
Reviewed-by: Vipin Kumar <vipin@cumulusnetworks.com>
lib/if.c
lib/if.h
ospfd/ospf_packet.c
ripd/rip_snmp.c
ripd/ripd.c
zebra/redistribute.c
zebra/redistribute.h
zebra/rib.h
zebra/rt_netlink.c
zebra/zebra_rib.c
zebra/zebra_routemap.c

index 0e88c601f7c697baf9b79d1bf0d1c435dddfdf2b..3003e4c2f4fed6cf82d62706ac57859a1a88d137 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -257,7 +257,7 @@ if_lookup_by_name_len(const char *name, size_t namelen)
 
 /* Lookup interface by IPv4 address. */
 struct interface *
-if_lookup_exact_address (struct in_addr src)
+if_lookup_exact_address (void *src, int family)
 {
   struct listnode *node;
   struct listnode *cnode;
@@ -271,11 +271,19 @@ if_lookup_exact_address (struct in_addr src)
        {
          p = c->address;
 
-         if (p && p->family == AF_INET)
+         if (p && (p->family == family))
            {
-             if (IPV4_ADDR_SAME (&p->u.prefix4, &src))
-               return ifp;
-           }         
+             if (family == AF_INET)
+               {
+                 if (IPV4_ADDR_SAME (&p->u.prefix4, (struct in_addr *)src))
+                   return ifp;
+               }
+             else if (family == AF_INET6)
+               {
+                 if (IPV6_ADDR_SAME (&p->u.prefix4, (struct in6_addr *)src))
+                   return ifp;
+               }
+           }
        }
     }
   return NULL;
@@ -283,7 +291,7 @@ if_lookup_exact_address (struct in_addr src)
 
 /* Lookup interface by IPv4 address. */
 struct interface *
-if_lookup_address (struct in_addr src)
+if_lookup_address (void *matchaddr, int family)
 {
   struct listnode *node;
   struct prefix addr;
@@ -293,9 +301,18 @@ if_lookup_address (struct in_addr src)
   struct connected *c;
   struct interface *match;
 
-  addr.family = AF_INET;
-  addr.u.prefix4 = src;
-  addr.prefixlen = IPV4_MAX_BITLEN;
+  if (family == AF_INET)
+    {
+      addr.family = AF_INET;
+      addr.u.prefix4 = *((struct in_addr *)matchaddr);
+      addr.prefixlen = IPV4_MAX_BITLEN;
+    }
+  else if (family == AF_INET6)
+    {
+      addr.family = AF_INET6;
+      addr.u.prefix6 = *((struct in6_addr *)matchaddr);
+      addr.prefixlen = IPV6_MAX_BITLEN;
+    }
 
   match = NULL;
 
index 8014fb56cd2188590de03a81d012a713072b6d07..6d4ca2f77eeba2fff4dc81f01d47f7ae00b03a99 100644 (file)
--- a/lib/if.h
+++ b/lib/if.h
@@ -266,8 +266,8 @@ struct nbr_connected
 extern int if_cmp_func (struct interface *, struct interface *);
 extern struct interface *if_create (const char *name, int namelen);
 extern struct interface *if_lookup_by_index (unsigned int);
-extern struct interface *if_lookup_exact_address (struct in_addr);
-extern struct interface *if_lookup_address (struct in_addr);
+extern struct interface *if_lookup_exact_address (void *matchaddr, int family);
+extern struct interface *if_lookup_address (void *matchaddr, int family);
 extern struct interface *if_lookup_prefix (struct prefix *prefix);
 extern struct connected *if_anchor_lookup_by_address (struct in_addr src);
 
index 5d2e82d8b79931e722dd6f5f568181d990725380..468810e8a3b4ba1aa0713d2f937f22b3433d3e8f 100644 (file)
@@ -2811,7 +2811,7 @@ ospf_read (struct thread *thread)
     /* Handle cases where the platform does not support retrieving the ifindex,
        and also platforms (such as Solaris 8) that claim to support ifindex
        retrieval but do not. */
-    ifp = if_lookup_address (iph->ip_src);
+    ifp = if_lookup_address ((void *)&iph->ip_src, AF_INET);
   
   if (ifp == NULL)
     return 0;
index 2df815b03f2edfe2228f9fafb69e8468b948567b..9d4e60dbb1922f0a319ae3dd08b90b8b0995b596 100644 (file)
@@ -255,7 +255,7 @@ rip2IfLookup (struct variable *v, oid name[], size_t *length,
 
       oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr);
 
-      return if_lookup_exact_address (*addr);
+      return if_lookup_exact_address ((void *)addr, AF_INET);
     }
   else
     {
index ee7dfc3cba7610c358d0c788f786b19355947edb..fc5b65a0c5cff10bde6e6dba69dc6ed0f6fd7cb1 100644 (file)
@@ -1125,7 +1125,7 @@ rip_response_process (struct rip_packet *packet, int size,
   /* The datagram's IPv4 source address should be checked to see
      whether the datagram is from a valid neighbor; the source of the
      datagram must be on a directly connected network (RFC2453 - Sec. 3.9.2) */
-  if (if_lookup_address(from->sin_addr) == NULL) 
+  if (if_lookup_address((void *)&from->sin_addr, AF_INET) == NULL)
     {
       zlog_info ("This datagram doesn't came from a valid neighbor: %s",
                 inet_ntoa (from->sin_addr));
@@ -1211,7 +1211,7 @@ rip_response_process (struct rip_packet *packet, int size,
              continue;
            }
 
-         if (! if_lookup_address (rte->nexthop))
+         if (! if_lookup_address ((void *)&rte->nexthop, AF_INET))
            {
              struct route_node *rn;
              struct rip_info *rinfo;
@@ -1843,7 +1843,7 @@ rip_read (struct thread *t)
     }
 
   /* Which interface is this packet comes from. */
-  ifp = if_lookup_address (from.sin_addr);
+  ifp = if_lookup_address ((void *)&from.sin_addr, AF_INET);
   
   /* RIP packet received */
   if (IS_RIP_DEBUG_EVENT)
@@ -2525,7 +2525,7 @@ rip_update_process (int route_type)
       {
        p = (struct prefix_ipv4 *) &rp->p;
 
-       ifp = if_lookup_address (p->prefix);
+       ifp = if_lookup_address ((void *)&p->prefix, AF_INET);
        if (! ifp)
          {
            zlog_warn ("Neighbor %s doesnt have connected interface!",
index 6dfb455f41ad0c58eed18b9c995d54879687fbb2..0f4cf9521712e6eab1857a7c62e90224bcf5d742 100644 (file)
@@ -62,33 +62,6 @@ is_zebra_import_table_enabled(afi_t afi, u_int32_t table_id)
   return 0;
 }
 
-int
-zebra_check_addr (struct prefix *p)
-{
-  if (p->family == AF_INET)
-    {
-      u_int32_t addr;
-
-      addr = p->u.prefix4.s_addr;
-      addr = ntohl (addr);
-
-      if (IPV4_NET127 (addr)
-          || IN_CLASSD (addr)
-          || IPV4_LINKLOCAL(addr))
-       return 0;
-    }
-#ifdef HAVE_IPV6
-  if (p->family == AF_INET6)
-    {
-      if (IN6_IS_ADDR_LOOPBACK (&p->u.prefix6))
-       return 0;
-      if (IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6))
-       return 0;
-    }
-#endif /* HAVE_IPV6 */
-  return 1;
-}
-
 static int
 is_default (struct prefix *p)
 {
index a4f321979d30b998113117645937fc25efe92dce..3ee6b9cd4df0f33ae4f4be9e39935eb4b3833d86 100644 (file)
@@ -46,8 +46,6 @@ extern void zebra_interface_address_add_update (struct interface *,
                                                struct connected *);
 extern void zebra_interface_address_delete_update (struct interface *,
                                                   struct connected *c);
-extern int zebra_check_addr (struct prefix *);
-
 extern int zebra_import_table (afi_t afi, u_int32_t table_id,
                               u_int32_t metric, int add);
 
index 45daad0fede3c82299c93f5356a673766a4c698d..7d9e2f7770eb593d79661cd79f84cc04148fbee8 100644 (file)
@@ -393,6 +393,7 @@ extern struct route_table *vrf_other_route_table (afi_t afi, u_int32_t table_id,
                                                  u_int32_t vrf_id);
 extern int is_zebra_valid_kernel_table(u_int32_t table_id);
 extern int is_zebra_main_routing_table(u_int32_t table_id);
+extern int zebra_check_addr (struct prefix *p);
 
 /* NOTE:
  * All rib_add_ipv[46]* functions will not just add prefix into RIB, but
index 99c4ab54f80d7b37b2ccf2349cebb97c88b88a22..e0124dcb49cf73dc8e06d86fe2ae35685ab1ac9f 100644 (file)
@@ -1513,12 +1513,15 @@ _netlink_route_build_singlepath(
       addattr_l (nlmsg, req_size, RTA_GATEWAY,
                  &nexthop->gate.ipv4, bytelen);
 
-      if (nexthop->rmap_src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
-        addattr_l (nlmsg, req_size, RTA_PREFSRC,
-                   &nexthop->rmap_src.ipv4, bytelen);
-      else if (nexthop->src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
-        addattr_l (nlmsg, req_size, RTA_PREFSRC,
-                   &nexthop->src.ipv4, bytelen);
+      if (cmd == RTM_NEWROUTE)
+       {
+         if (nexthop->rmap_src.ipv4.s_addr)
+           addattr_l (nlmsg, req_size, RTA_PREFSRC,
+                      &nexthop->rmap_src.ipv4, bytelen);
+         else if (nexthop->src.ipv4.s_addr)
+           addattr_l (nlmsg, req_size, RTA_PREFSRC,
+                      &nexthop->src.ipv4, bytelen);
+       }
 
       if (IS_ZEBRA_DEBUG_KERNEL)
         zlog_debug("netlink_route_multipath() (%s): "
@@ -1535,6 +1538,16 @@ _netlink_route_build_singlepath(
       addattr_l (nlmsg, req_size, RTA_GATEWAY,
                  &nexthop->gate.ipv6, bytelen);
 
+      if (cmd == RTM_NEWROUTE)
+       {
+         if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
+           addattr_l (nlmsg, req_size, RTA_PREFSRC,
+                      &nexthop->rmap_src.ipv6, bytelen);
+         else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6))
+           addattr_l (nlmsg, req_size, RTA_PREFSRC,
+                      &nexthop->src.ipv6, bytelen);
+       }
+
       if (IS_ZEBRA_DEBUG_KERNEL)
         zlog_debug("netlink_route_multipath() (%s): "
                    "nexthop via %s if %u",
@@ -1549,12 +1562,15 @@ _netlink_route_build_singlepath(
     {
       addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
 
-      if (nexthop->rmap_src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
-        addattr_l (nlmsg, req_size, RTA_PREFSRC,
-                   &nexthop->rmap_src.ipv4, bytelen);
-      else if (nexthop->src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
-        addattr_l (nlmsg, req_size, RTA_PREFSRC,
-                   &nexthop->src.ipv4, bytelen);
+      if (cmd == RTM_NEWROUTE)
+       {
+         if (nexthop->rmap_src.ipv4.s_addr)
+           addattr_l (nlmsg, req_size, RTA_PREFSRC,
+                      &nexthop->rmap_src.ipv4, bytelen);
+         else if (nexthop->src.ipv4.s_addr)
+           addattr_l (nlmsg, req_size, RTA_PREFSRC,
+                      &nexthop->src.ipv4, bytelen);
+       }
 
       if (IS_ZEBRA_DEBUG_KERNEL)
         zlog_debug("netlink_route_multipath() (%s): "
@@ -1566,6 +1582,16 @@ _netlink_route_build_singlepath(
     {
       addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
 
+      if (cmd == RTM_NEWROUTE)
+       {
+         if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
+           addattr_l (nlmsg, req_size, RTA_PREFSRC,
+                      &nexthop->rmap_src.ipv6, bytelen);
+         else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6))
+           addattr_l (nlmsg, req_size, RTA_PREFSRC,
+                      &nexthop->src.ipv6, bytelen);
+       }
+
       if (IS_ZEBRA_DEBUG_KERNEL)
         zlog_debug("netlink_route_multipath() (%s): "
                    "nexthop via if %u", routedesc, nexthop->ifindex);
@@ -1657,6 +1683,12 @@ _netlink_route_build_multipath(
       rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
                      &nexthop->gate.ipv6, bytelen);
       rtnh->rtnh_len += sizeof (struct rtattr) + bytelen;
+
+      if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
+        *src = &nexthop->rmap_src;
+      else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6))
+       *src = &nexthop->src;
+
       if (IS_ZEBRA_DEBUG_KERNEL)
         zlog_debug("netlink_route_multipath() (%s): "
                    "nexthop via %s if %u",
@@ -1860,19 +1892,34 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
         {
           if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
             {
-              /* This only works for IPv4 now */
               if (!setsrc)
                  {
-                  if (nexthop->rmap_src.ipv4.s_addr != 0)
-                    {
-                      src.ipv4 = nexthop->rmap_src.ipv4;
-                      setsrc = 1;
-                    }
-                  else if (nexthop->src.ipv4.s_addr != 0)
-                    {
-                      src.ipv4 = nexthop->src.ipv4;
-                      setsrc = 1;
-                    }
+                  if (family == AF_INET)
+                    {
+                      if (nexthop->rmap_src.ipv4.s_addr != 0)
+                        {
+                          src.ipv4 = nexthop->rmap_src.ipv4;
+                          setsrc = 1;
+                        }
+                      else if (nexthop->src.ipv4.s_addr != 0)
+                        {
+                          src.ipv4 = nexthop->src.ipv4;
+                          setsrc = 1;
+                        }
+                    }
+                  else if (family == AF_INET6)
+                    {
+                      if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
+                        {
+                          src.ipv6 = nexthop->rmap_src.ipv6;
+                          setsrc = 1;
+                        }
+                      else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6))
+                        {
+                          src.ipv6 = nexthop->src.ipv6;
+                          setsrc = 1;
+                        }
+                    }
                  }
               continue;
            }
@@ -1897,7 +1944,12 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
             }
         }
       if (setsrc && (cmd == RTM_NEWROUTE))
-       addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen);
+       {
+         if (family == AF_INET)
+           addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen);
+         else if (family == AF_INET6)
+           addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv6, bytelen);
+       }
     }
   else
     {
@@ -1921,16 +1973,32 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
               /* This only works for IPv4 now */
               if (!setsrc)
                  {
-                  if (nexthop->rmap_src.ipv4.s_addr != 0)
-                    {
-                      src.ipv4 = nexthop->rmap_src.ipv4;
-                      setsrc = 1;
-                    }
-                  else if (nexthop->src.ipv4.s_addr != 0)
-                    {
-                      src.ipv4 = nexthop->src.ipv4;
-                      setsrc = 1;
-                    }
+                  if (family == AF_INET)
+                    {
+                      if (nexthop->rmap_src.ipv4.s_addr != 0)
+                        {
+                          src.ipv4 = nexthop->rmap_src.ipv4;
+                          setsrc = 1;
+                        }
+                      else if (nexthop->src.ipv4.s_addr != 0)
+                        {
+                          src.ipv4 = nexthop->src.ipv4;
+                          setsrc = 1;
+                        }
+                    }
+                  else if (family == AF_INET6)
+                    {
+                      if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
+                        {
+                          src.ipv6 = nexthop->rmap_src.ipv6;
+                          setsrc = 1;
+                        }
+                      else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6))
+                        {
+                          src.ipv6 = nexthop->src.ipv6;
+                          setsrc = 1;
+                        }
+                    }
                  }
              continue;
            }
@@ -1954,13 +2022,23 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
 
              if (!setsrc && src1)
                {
-                 src.ipv4 = src1->ipv4;
+                 if (family == AF_INET)
+                   src.ipv4 = src1->ipv4;
+                 else if (family == AF_INET6)
+                   src.ipv6 = src1->ipv6;
+
                  setsrc = 1;
                }
             }
         }
       if (setsrc && (cmd == RTM_NEWROUTE))
-       addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen);
+       {
+         if (family == AF_INET)
+           addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen);
+         else if (family == AF_INET6)
+           addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv6, bytelen);
+         zlog_debug("Setting source");
+       }
 
       if (rta->rta_len > RTA_LENGTH (0))
         addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta),
index 83ae03eb1f317b3543f48964fc9d5bcc60ac7961..261aed156f4c26a32a4af0aa5fbb9b9d54b5cb30 100644 (file)
@@ -231,6 +231,33 @@ is_zebra_main_routing_table(u_int32_t table_id)
   return 0;
 }
 
+int
+zebra_check_addr (struct prefix *p)
+{
+  if (p->family == AF_INET)
+    {
+      u_int32_t addr;
+
+      addr = p->u.prefix4.s_addr;
+      addr = ntohl (addr);
+
+      if (IPV4_NET127 (addr)
+          || IN_CLASSD (addr)
+          || IPV4_LINKLOCAL(addr))
+       return 0;
+    }
+#ifdef HAVE_IPV6
+  if (p->family == AF_INET6)
+    {
+      if (IN6_IS_ADDR_LOOPBACK (&p->u.prefix6))
+       return 0;
+      if (IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6))
+       return 0;
+    }
+#endif /* HAVE_IPV6 */
+  return 1;
+}
+
 /* Add nexthop to the end of a nexthop list.  */
 static void
 _nexthop_add (struct nexthop **target, struct nexthop *nexthop)
@@ -1298,7 +1325,6 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
        }
       UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
     }
-
   return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
 }
 
@@ -1336,7 +1362,10 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
        prev_index != nexthop->ifindex ||
        ((nexthop->type >= NEXTHOP_TYPE_IFINDEX &&
          nexthop->type < NEXTHOP_TYPE_IPV6) &&
-        prev_src.ipv4.s_addr != nexthop->rmap_src.ipv4.s_addr))
+        prev_src.ipv4.s_addr != nexthop->rmap_src.ipv4.s_addr) ||
+       ((nexthop->type >= NEXTHOP_TYPE_IPV6 &&
+         nexthop->type < NEXTHOP_TYPE_BLACKHOLE) &&
+        !(IPV6_ADDR_SAME (&prev_src.ipv6, &nexthop->rmap_src.ipv6))))
       {
        SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
        SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
index 6648b8a4d518663f2f9b11d19d2e04464d837809..a6ba64372896f7df38e4cdbc7c4ebc6b11e9923f 100644 (file)
@@ -648,32 +648,57 @@ DEFUN (no_match_source_protocol,
 
 DEFUN (set_src,
        set_src_cmd,
-       "set src A.B.C.D",
+       "set src (A.B.C.D|X:X::X:X)",
        SET_STR
        "src address for route\n"
        "src address\n")
 {
-  struct in_addr src;
-  struct interface *pif;
+  union g_addr src;
+  struct interface *pif = NULL;
+  int family;
+  struct prefix p;
 
-  if (inet_pton(AF_INET, argv[0], &src) <= 0)
+  if (inet_pton(AF_INET, argv[0], &src.ipv4) != 1)
+    {
+      if (inet_pton(AF_INET6, argv[0], &src.ipv6) != 1)
+       {
+         vty_out (vty, "%% not a valid IPv4/v6 address%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      p.family = family = AF_INET6;
+      p.u.prefix6 = src.ipv6;
+      p.prefixlen = IPV6_MAX_BITLEN;
+    }
+  else
+    {
+      p.family = family = AF_INET;
+      p.u.prefix4 = src.ipv4;
+      p.prefixlen = IPV4_MAX_BITLEN;
+    }
+
+  if (!zebra_check_addr(&p))
+    {
+         vty_out (vty, "%% not a valid source IPv4/v6 address%s", VTY_NEWLINE);
+         return CMD_WARNING;
+    }
+
+  if (family == AF_INET)
+    pif = if_lookup_exact_address ((void *)&src.ipv4, AF_INET);
+  else if (family == AF_INET6)
+    pif = if_lookup_exact_address ((void *)&src.ipv6, AF_INET6);
+
+  if (!pif)
     {
       vty_out (vty, "%% not a local address%s", VTY_NEWLINE);
       return CMD_WARNING;
     }
-
-    pif = if_lookup_exact_address (src);
-    if (!pif)
-      {
-        vty_out (vty, "%% not a local address%s", VTY_NEWLINE);
-        return CMD_WARNING;
-      }
   return zebra_route_set_add (vty, vty->index, "src", argv[0]);
 }
 
 DEFUN (no_set_src,
        no_set_src_cmd,
-       "no set src",
+       "no set src {A.B.C.D|X:X::X:X}",
        NO_STR
        SET_STR
        "Source address for route\n")
@@ -684,14 +709,6 @@ DEFUN (no_set_src,
   return zebra_route_set_delete (vty, vty->index, "src", argv[0]);
 }
 
-ALIAS (no_set_src,
-       no_set_src_val_cmd,
-       "no set src (A.B.C.D)",
-       NO_STR
-       SET_STR
-       "src address for route\n"
-       "src address\n")
-
 DEFUN (zebra_route_map_timer,
        zebra_route_map_timer_cmd,
        "zebra route-map delay-timer <0-600>",
@@ -822,6 +839,112 @@ DEFUN (show_ip_protocol,
     return CMD_SUCCESS;
 }
 
+DEFUN (ipv6_protocol,
+       ipv6_protocol_cmd,
+       "ipv6 protocol " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
+       IP6_STR
+       "Filter IPv6 routing info exchanged between zebra and protocol\n"
+       QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA
+       "Route map name\n")
+{
+  int i;
+  u_int32_t table_id;
+
+  if (strcasecmp(argv[0], "any") == 0)
+    i = ZEBRA_ROUTE_MAX;
+  else
+    i = proto_name2num(argv[0]);
+  if (i < 0)
+    {
+      vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+               VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if (proto_rm[AFI_IP6][i])
+    {
+      if (strcmp(proto_rm[AFI_IP6][i], argv[1]) == 0)
+       return CMD_SUCCESS;
+
+      XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP6][i]);
+    }
+  proto_rm[AFI_IP6][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]);
+  rib_update();
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_protocol,
+       no_ipv6_protocol_cmd,
+       "no ipv6 protocol " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA,
+       NO_STR
+       IP6_STR
+       "Stop filtering IPv6 routing info between zebra and protocol\n"
+       QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA
+       "Protocol from which to stop filtering routes\n")
+{
+  int i;
+  u_int32_t table_id;
+
+  if (strcasecmp(argv[0], "any") == 0)
+    i = ZEBRA_ROUTE_MAX;
+  else
+    i = proto_name2num(argv[0]);
+  if (i < 0)
+    {
+      vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+               VTY_NEWLINE);
+     return CMD_WARNING;
+    }
+  if (!proto_rm[AFI_IP6][i])
+    return CMD_SUCCESS;
+
+  if ((argc == 2 && strcmp(argv[1], proto_rm[AFI_IP6][i]) == 0) ||
+      (argc < 2))
+    {
+      XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP6][i]);
+      proto_rm[AFI_IP6][i] = NULL;
+      rib_update();
+    }
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ipv6_protocol,
+       no_ipv6_protocol_val_cmd,
+       "no ipv6 protocol " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
+       NO_STR
+       IP6_STR
+       "Stop filtering IPv6 routing info between zebra and protocol\n"
+       QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA
+       "route map name")
+
+DEFUN (show_ipv6_protocol,
+       show_ipv6_protocol_cmd,
+       "show ipv6 protocol",
+        SHOW_STR
+        IP6_STR
+       "IPv6 protocol filtering status\n")
+{
+    int i;
+
+    vty_out(vty, "Protocol    : route-map %s", VTY_NEWLINE);
+    vty_out(vty, "------------------------%s", VTY_NEWLINE);
+    for (i=0;i<ZEBRA_ROUTE_MAX;i++)
+    {
+        if (proto_rm[AFI_IP6][i])
+          vty_out (vty, "%-10s  : %-10s%s", zebra_route_string(i),
+                                       proto_rm[AFI_IP6][i],
+                                       VTY_NEWLINE);
+        else
+          vty_out (vty, "%-10s  : none%s", zebra_route_string(i), VTY_NEWLINE);
+    }
+    if (proto_rm[AFI_IP6][i])
+      vty_out (vty, "%-10s  : %-10s%s", "any", proto_rm[AFI_IP6][i],
+                                       VTY_NEWLINE);
+    else
+      vty_out (vty, "%-10s  : none%s", "any", VTY_NEWLINE);
+
+    return CMD_SUCCESS;
+}
+
 DEFUN (ip_protocol_nht_rmap,
        ip_protocol_nht_rmap_cmd,
        "ip nht " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
@@ -1413,17 +1536,17 @@ route_set_src_compile (const char *arg)
 {
   union g_addr src, *psrc;
 
-  if (inet_pton(AF_INET, arg, &src.ipv4) != 1
+  if (
 #ifdef HAVE_IPV6
-      && inet_pton(AF_INET6, arg, &src.ipv6) != 1
+      (inet_pton(AF_INET6, arg, &src.ipv6) == 1) ||
 #endif /* HAVE_IPV6 */
-     )
-    return NULL;
-
-  psrc = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (union g_addr));
-  *psrc = src;
-
-  return psrc;
+      (src.ipv4.s_addr && (inet_pton(AF_INET, arg, &src.ipv4) == 1)))
+    {
+      psrc = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (union g_addr));
+      *psrc = src;
+      return psrc;
+    }
+  return NULL;
 }
 
 /* Free route map's compiled `set src' value. */
@@ -1570,6 +1693,10 @@ zebra_routemap_config_write_protocol (struct vty *vty)
         vty_out (vty, "ip protocol %s route-map %s%s", zebra_route_string(i),
                  proto_rm[AFI_IP][i], VTY_NEWLINE);
 
+      if (proto_rm[AFI_IP6][i])
+        vty_out (vty, "ipv6 protocol %s route-map %s%s", zebra_route_string(i),
+                 proto_rm[AFI_IP6][i], VTY_NEWLINE);
+
       if (nht_rm[AFI_IP][i])
         vty_out (vty, "ip nht %s route-map %s%s", zebra_route_string(i),
                  nht_rm[AFI_IP][i], VTY_NEWLINE);
@@ -1583,6 +1710,10 @@ zebra_routemap_config_write_protocol (struct vty *vty)
       vty_out (vty, "ip protocol %s route-map %s%s", "any",
                proto_rm[AFI_IP][ZEBRA_ROUTE_MAX], VTY_NEWLINE);
 
+  if (proto_rm[AFI_IP6][ZEBRA_ROUTE_MAX])
+      vty_out (vty, "ipv6 protocol %s route-map %s%s", "any",
+               proto_rm[AFI_IP6][ZEBRA_ROUTE_MAX], VTY_NEWLINE);
+
   if (nht_rm[AFI_IP][ZEBRA_ROUTE_MAX])
       vty_out (vty, "ip nht %s route-map %s%s", "any",
                nht_rm[AFI_IP][ZEBRA_ROUTE_MAX], VTY_NEWLINE);
@@ -1604,6 +1735,11 @@ zebra_route_map_init ()
   install_element (CONFIG_NODE, &no_ip_protocol_val_cmd);
   install_element (VIEW_NODE, &show_ip_protocol_cmd);
   install_element (ENABLE_NODE, &show_ip_protocol_cmd);
+  install_element (CONFIG_NODE, &ipv6_protocol_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_protocol_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_protocol_val_cmd);
+  install_element (VIEW_NODE, &show_ipv6_protocol_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_protocol_cmd);
   install_element (CONFIG_NODE, &ip_protocol_nht_rmap_cmd);
   install_element (CONFIG_NODE, &no_ip_protocol_nht_rmap_cmd);
   install_element (CONFIG_NODE, &no_ip_protocol_nht_rmap_val_cmd);