]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd, zebra: rfc-5549-generic.patch
authorDonald Sharp <sharpd@cumulusnetworks.com>
Thu, 11 Jun 2015 16:19:12 +0000 (09:19 -0700)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Thu, 11 Jun 2015 16:19:12 +0000 (09:19 -0700)
This adds support for BGP RFC 5549 (Extended Next Hop Encoding capability)

     * send and receive of the capability
     * processing of IPv4->IPv6 next-hops
     * for resolving these IPv6 next-hops, itsworks with the current
       next-hop-tracking support
     * added a new message type between BGP and Zebra for such route
       install/uninstall
     * zserv side of changes to process IPv4 prefix ->IPv6 next-hops
     * required show command changes for IPv4 prefix having IPv6 next-hops

Few points to note about the implementation:

     * It does an implicit next-hop-self when a [IPv4 prefix -> IPv6 LL next-hop]
       is to be considered for advertisement to IPv4 peering (or IPv6 peering
       without Extended next-hop capability negotiated)

     * Currently feature is off by default, enable it by configuring
       'neighbor <> capability extended-nexthop'

     * Current support is for IPv4 Unicast prefixes only.

IMPORTANT NOTE:

     This patch alone isn't enough to have IPv4->IPv6 routes installed into
     the kernel. A separate patch is needed for that to work for the netlink
     interface.

Signed-off-by: Vipin Kumar <vipin@cumulusnetworks.com>
Reviewed-by: Daniel Walton <dwalton@cumulusnetworks.com>
             Vivek Venkatraman <vivek@cumulusnetworks.com>
             Donald Sharp <sharpd@cumulusnetworks.com>

20 files changed:
bgpd/bgp_attr.c
bgpd/bgp_attr.h
bgpd/bgp_nht.c
bgpd/bgp_open.c
bgpd/bgp_open.h
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_updgrp.h
bgpd/bgp_updgrp_packet.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgpd.c
bgpd/bgpd.h
lib/zclient.c
lib/zclient.h
lib/zebra.h
zebra/rib.h
zebra/zebra_rib.c
zebra/zebra_vty.c
zebra/zserv.c

index 3a63cd2244343fbbf64660d921f79f16443a74c3..de4c6c79f4ffddcdf3152e6f866edc80cab2cb62 100644 (file)
@@ -2137,7 +2137,7 @@ bgp_attr_check (struct peer *peer, struct attr *attr)
 int stream_put_prefix (struct stream *, struct prefix *);
 
 size_t
-bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi,
+bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,
                         struct bpacket_attr_vec_arr *vecarr,
                         struct attr *attr)
 {
@@ -2152,7 +2152,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi,
   stream_putc (s, safi);       /* SAFI */
 
   /* Nexthop */
-  switch (afi)
+  switch (nh_afi)
     {
     case AFI_IP:
       switch (safi)
@@ -2255,9 +2255,12 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
   /* Remember current pointer. */
   cp = stream_get_endp (s);
 
-  if (p && !(afi == AFI_IP && safi == SAFI_UNICAST))
+  if (p && !((afi == AFI_IP && safi == SAFI_UNICAST) &&
+              !peer_cap_enhe(peer)))
     {
-      mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi, vecarr, attr);
+      mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi,
+                                    (peer_cap_enhe(peer) ? AFI_IP6 : afi),
+                                    vecarr, attr);
       bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag);
       bgp_packet_mpattr_end(s, mpattrlen_pos);
     }
@@ -2330,13 +2333,31 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
       send_as4_path = 1; /* we'll do this later, at the correct place */
   
   /* Nexthop attribute. */
-  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
+  if (afi == AFI_IP && !peer_cap_enhe(peer))
     {
-      stream_putc (s, BGP_ATTR_FLAG_TRANS);
-      stream_putc (s, BGP_ATTR_NEXT_HOP);
-      bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
-      stream_putc (s, 4);
-      stream_put_ipv4 (s, attr->nexthop.s_addr);
+      if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))
+        {
+          stream_putc (s, BGP_ATTR_FLAG_TRANS);
+          stream_putc (s, BGP_ATTR_NEXT_HOP);
+          bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
+          stream_putc (s, 4);
+          stream_put_ipv4 (s, attr->nexthop.s_addr);
+        }
+      else if (safi == SAFI_UNICAST && peer_cap_enhe(from))
+        {
+          /*
+           * Likely this is the case when an IPv4 prefix was received with
+           * Extended Next-hop capability and now being advertised to
+           * non-ENHE peers.
+           * Setting the mandatory (ipv4) next-hop attribute here to enable
+           * implicit next-hop self with correct (ipv4 address family).
+           */
+          stream_putc (s, BGP_ATTR_FLAG_TRANS);
+          stream_putc (s, BGP_ATTR_NEXT_HOP);
+          bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, NULL);
+          stream_putc (s, 4);
+          stream_put_ipv4 (s, 0);
+        }
     }
 
   /* MED attribute. */
index 4fbfcb900dc3927f1026e5ec097383b0212ca228..8c36ce0be1b2206e7f120c03fd713a2fb26f3aa6 100644 (file)
@@ -232,7 +232,8 @@ extern int bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
  * finally the _end() function.
  */
 extern size_t bgp_packet_mpattr_start(struct stream *s, afi_t afi, safi_t safi,
-                                     struct bpacket_attr_vec_arr *vecarr,
+                                      afi_t nh_afi,
+                                      struct bpacket_attr_vec_arr *vecarr,
                                      struct attr *attr);
 extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
                                     struct prefix *p, struct prefix_rd *prd,
index da52064aeb16ee136fb3cb6d7e35b1b5784f162c..397b379fafa307171880234b322f29fd2ddc8eb6 100644 (file)
@@ -103,11 +103,17 @@ bgp_find_or_add_nexthop (struct bgp *bgp, afi_t afi, struct bgp_info *ri,
 
   if (ri)
     {
+      is_bgp_static_route = ((ri->type == ZEBRA_ROUTE_BGP) &&
+                            (ri->sub_type == BGP_ROUTE_STATIC)) ? 1 : 0;
+
+      /* Since Extended Next-hop Encoding (RFC5549) support, we want to derive
+         address-family from the next-hop. */
+      if (!is_bgp_static_route)
+        afi = BGP_ATTR_NEXTHOP_AFI_IP6(ri->attr) ? AFI_IP6 : AFI_IP;
+
       /* This will return TRUE if the global IPv6 NH is a link local addr */
       if (make_prefix(afi, ri, &p) < 0)
        return 1;
-      is_bgp_static_route = ((ri->type == ZEBRA_ROUTE_BGP) &&
-                            (ri->sub_type == BGP_ROUTE_STATIC)) ? 1 : 0;
     }
   else if (peer)
     {
index 9fcd64bd2dca9491fc3bf329746e09a6cef3675d..ddc8f9e8a62da02be92ce4751e1327b82138feef 100644 (file)
@@ -530,6 +530,48 @@ bgp_capability_hostname (struct peer *peer, struct capability_header *hdr)
   return 0;
 }
 
+static int
+bgp_capability_enhe (struct peer *peer, struct capability_header *hdr)
+{
+  struct stream *s = BGP_INPUT (peer);
+  size_t end = stream_get_getp (s) + hdr->length;
+
+  while (stream_get_getp (s) + 6 <= end)
+    {
+      afi_t afi = stream_getw (s);
+      safi_t safi = stream_getw (s);
+      afi_t nh_afi = stream_getw (s);
+
+      if (bgp_debug_neighbor_events(peer))
+        zlog_debug ("%s   Received with value triple (afi/safi/next-hop afi): %u/%u/%u",
+                    peer->host, afi, safi, nh_afi);
+
+      if (!bgp_afi_safi_valid_indices (afi, &safi))
+        return -1;
+
+      if (afi != AFI_IP || nh_afi != AFI_IP6)
+        {
+          zlog_warn ("%s Extended Next-hop capability, wrong afi/next-hop afi: %u/%u",
+                     peer->host, afi, nh_afi);
+          return -1;
+        }
+
+      /* Until SAFIs other than SAFI_UNICAST are supported */
+      if (safi != SAFI_UNICAST)
+        zlog_warn ("%s Extended Next-hop capability came with unsupported SAFI: %u",
+                   peer->host, safi);
+
+      SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ENHE_AF_RCV);
+
+      if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ENHE_AF_ADV))
+        SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ENHE_AF_NEGO);
+    }
+
+  SET_FLAG (peer->cap, PEER_CAP_ENHE_RCV);
+
+  return 0;
+}
+
   static const struct message capcode_str[] =
 {
   { CAPABILITY_CODE_MP,                        "MultiProtocol Extensions"      },
@@ -539,6 +581,7 @@ bgp_capability_hostname (struct peer *peer, struct capability_header *hdr)
   { CAPABILITY_CODE_AS4,               "4-octet AS number"             },
   { CAPABILITY_CODE_ADDPATH,            "AddPath"                       },
   { CAPABILITY_CODE_DYNAMIC,           "Dynamic"                       },
+  { CAPABILITY_CODE_ENHE,               "Extended Next Hop Encoding"    },
   { CAPABILITY_CODE_DYNAMIC_OLD,       "Dynamic (Old)"                 },
   { CAPABILITY_CODE_REFRESH_OLD,       "Route Refresh (Old)"           },
   { CAPABILITY_CODE_ORF_OLD,           "ORF (Old)"                     },
@@ -557,6 +600,7 @@ static const size_t cap_minsizes[] =
   [CAPABILITY_CODE_ADDPATH]     = CAPABILITY_CODE_ADDPATH_LEN,
   [CAPABILITY_CODE_DYNAMIC]    = CAPABILITY_CODE_DYNAMIC_LEN,
   [CAPABILITY_CODE_DYNAMIC_OLD]        = CAPABILITY_CODE_DYNAMIC_LEN,
+  [CAPABILITY_CODE_ENHE]        = CAPABILITY_CODE_ENHE_LEN,
   [CAPABILITY_CODE_REFRESH_OLD]        = CAPABILITY_CODE_REFRESH_LEN,
   [CAPABILITY_CODE_ORF_OLD]    = sizeof (struct capability_orf_entry),
   [CAPABILITY_CODE_HOSTNAME]    = CAPABILITY_CODE_MIN_HOSTNAME_LEN,
@@ -624,6 +668,7 @@ bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability,
           case CAPABILITY_CODE_ADDPATH:
           case CAPABILITY_CODE_DYNAMIC:
           case CAPABILITY_CODE_DYNAMIC_OLD:
+          case CAPABILITY_CODE_ENHE:
          case CAPABILITY_CODE_HOSTNAME:
               /* Check length. */
               if (caphdr.length < cap_minsizes[caphdr.code])
@@ -703,6 +748,10 @@ bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability,
             if (bgp_capability_hostname (peer, &caphdr))
               return -1;
             break;
+          case CAPABILITY_CODE_ENHE:
+            if (bgp_capability_enhe (peer, &caphdr))
+              return -1;
+            break;
           default:
             if (caphdr.code > 128)
               {
@@ -1087,6 +1136,26 @@ bgp_open_capability (struct stream *s, struct peer *peer)
       stream_putc (s, SAFI_MPLS_LABELED_VPN);
     }
 #ifdef HAVE_IPV6
+  /* Currently supporting RFC-5549 for Link-Local peering only */
+  if (CHECK_FLAG (peer->flags, PEER_FLAG_CAPABILITY_ENHE) &&
+      peer->su.sa.sa_family == AF_INET6 &&
+      IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr))
+    {
+      /* RFC 5549 Extended Next Hop Encoding */
+      SET_FLAG (peer->cap, PEER_CAP_ENHE_ADV);
+      stream_putc (s, BGP_OPEN_OPT_CAP);
+      stream_putc (s, CAPABILITY_CODE_ENHE_LEN + 2);
+      stream_putc (s, CAPABILITY_CODE_ENHE);
+      stream_putc (s, CAPABILITY_CODE_ENHE_LEN);
+      /* Currently supporting for SAFI_UNICAST only */
+      SET_FLAG (peer->af_cap[AFI_IP][SAFI_UNICAST], PEER_CAP_ENHE_AF_ADV);
+      stream_putw (s, AFI_IP);
+      stream_putw (s, SAFI_UNICAST);
+      stream_putw (s, AFI_IP6);
+
+      if (CHECK_FLAG (peer->af_cap[AFI_IP][SAFI_UNICAST], PEER_CAP_ENHE_AF_RCV))
+        SET_FLAG (peer->af_cap[AFI_IP][SAFI_UNICAST], PEER_CAP_ENHE_AF_NEGO);
+    }
   /* IPv6 unicast. */
   if (peer->afc[AFI_IP6][SAFI_UNICAST])
     {
index a818141fc3723e8fbb303cc41068d68ab45ed6d6..6ef857284e0585c4df5e39c4a16c5ca2eb89dd27 100644 (file)
@@ -77,6 +77,7 @@ struct capability_gr
 #define CAPABILITY_CODE_DYNAMIC_OLD    66 /* Dynamic Capability, deprecated since 2003 */
 #define CAPABILITY_CODE_DYNAMIC        67 /* Dynamic Capability */
 #define CAPABILITY_CODE_ADDPATH        69 /* Addpath Capability */
+#define CAPABILITY_CODE_ENHE            5 /* Extended Next Hop Encoding */
 #define CAPABILITY_CODE_REFRESH_OLD   128 /* Route Refresh Capability(cisco) */
 #define CAPABILITY_CODE_ORF_OLD       130 /* Cooperative Route Filtering Capability(cisco) */
 #define CAPABILITY_CODE_HOSTNAME      131 /* Advertise hostname capabilty */
@@ -89,6 +90,7 @@ struct capability_gr
 #define CAPABILITY_CODE_AS4_LEN         4
 #define CAPABILITY_CODE_ADDPATH_LEN     4
 #define CAPABILITY_CODE_MIN_HOSTNAME_LEN 2
+#define CAPABILITY_CODE_ENHE_LEN        6 /* NRLI AFI = 2, SAFI = 2, Nexthop AFI = 2 */
 
 /* Cooperative Route Filtering Capability.  */
 
index b1061e96ff9e26378716b3626025422b2854f449..5a93410bc89bf8b9ea95dfbab789e6c1512927cb 100644 (file)
@@ -1396,7 +1396,7 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
    * Of course, the operator can always set it through the route-map, if
    * so desired.
    */
-  if (p->family == AF_INET6)
+  if (p->family == AF_INET6 || peer_cap_enhe(peer))
     {
       attr->extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
       if (!reflect)
@@ -1481,7 +1481,7 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
           if (!reflect ||
               CHECK_FLAG (peer->af_flags[afi][safi],
                           PEER_FLAG_NEXTHOP_SELF_ALL))
-            subgroup_announce_reset_nhop (p->family, attr);
+            subgroup_announce_reset_nhop ((peer_cap_enhe(peer) ? AF_INET6 : p->family), attr);
         }
       else if (peer->sort == BGP_PEER_EBGP)
         {
@@ -1491,7 +1491,7 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
                 break;
             }
           if (!paf)
-            subgroup_announce_reset_nhop (p->family, attr);
+            subgroup_announce_reset_nhop ((peer_cap_enhe(peer) ? AF_INET6 : p->family), attr);
         }
     }
 
@@ -1600,9 +1600,10 @@ subgroup_announce_check_rsclient (struct bgp_info *ri,
   bgp_attr_dup (attr, riattr);
 
   /* next-hop-set */
-  if ((p->family == AF_INET && attr->nexthop.s_addr == 0)
+  if ((p->family == AF_INET && !peer_cap_enhe(rsclient)
+       && attr->nexthop.s_addr == 0)
 #ifdef HAVE_IPV6
-          || (p->family == AF_INET6 &&
+          || ((p->family == AF_INET6 || peer_cap_enhe(rsclient)) &&
               IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global))
 #endif /* HAVE_IPV6 */
      )
@@ -1613,12 +1614,12 @@ subgroup_announce_check_rsclient (struct bgp_info *ri,
         if (safi == SAFI_MPLS_VPN)
           memcpy (&attr->extra->mp_nexthop_global_in, &rsclient->nexthop.v4,
                   IPV4_MAX_BYTELEN);
-        else
+        else if (!peer_cap_enhe(rsclient))
           memcpy (&attr->nexthop, &rsclient->nexthop.v4, IPV4_MAX_BYTELEN);
       }
 #ifdef HAVE_IPV6
     /* Set IPv6 nexthop. */
-    if (p->family == AF_INET6)
+    if (p->family == AF_INET6 || peer_cap_enhe(rsclient))
       {
         /* IPv6 global nexthop must be included. */
         memcpy (&attr->extra->mp_nexthop_global, &rsclient->nexthop.v6_global,
@@ -1629,7 +1630,7 @@ subgroup_announce_check_rsclient (struct bgp_info *ri,
   }
 
 #ifdef HAVE_IPV6
-  if (p->family == AF_INET6)
+  if (p->family == AF_INET6 || peer_cap_enhe(rsclient))
     {
       struct attr_extra *attre = attr->extra;
 
@@ -2471,7 +2472,8 @@ bgp_update_rsclient (struct peer *rsclient, u_int32_t addpath_id,
   bgp_attr_unintern (&attr_new2);
 
   /* IPv4 unicast next hop check.  */
-  if ((afi == AFI_IP) && ((safi == SAFI_UNICAST) || safi == SAFI_MULTICAST))
+  if ((afi == AFI_IP) && ((safi == SAFI_UNICAST && !peer_cap_enhe(peer))
+                           || safi == SAFI_MULTICAST))
     {
      /* Next hop must not be 0.0.0.0 nor Class D/E address. */
       if (new_attr.nexthop.s_addr == 0
@@ -2720,7 +2722,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
     }
 
   /* IPv4 unicast next hop check.  */
-  if (afi == AFI_IP && safi == SAFI_UNICAST)
+  if (afi == AFI_IP && safi == SAFI_UNICAST && !peer_cap_enhe(peer))
     {
       /* Next hop must not be 0.0.0.0 nor Class D/E address. */
       if (new_attr.nexthop.s_addr == 0
@@ -6553,7 +6555,8 @@ route_vty_out (struct vty *vty, struct prefix *p,
     {
 
       /* IPv4 Next Hop */
-      if (p->family == AF_INET)
+      if (p->family == AF_INET
+          && (safi == SAFI_MPLS_VPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
        {
           if (json_paths)
             {
@@ -6580,7 +6583,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
 
 #ifdef HAVE_IPV6
       /* IPv6 Next Hop */
-      else if (p->family == AF_INET6)
+      else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr))
        {
          int len;
          char buf[BUFSIZ];
@@ -6691,7 +6694,8 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p,
   /* Print attribute */
   if (attr) 
     {
-      if (p->family == AF_INET)
+      if (p->family == AF_INET
+          && (safi == SAFI_MPLS_VPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
        {
          if (safi == SAFI_MPLS_VPN)
            vty_out (vty, "%-16s",
@@ -6700,7 +6704,7 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p,
            vty_out (vty, "%-16s", inet_ntoa (attr->nexthop));
        }
 #ifdef HAVE_IPV6
-      else if (p->family == AF_INET6)
+      else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr))
         {
           int len;
           char buf[BUFSIZ];
@@ -6764,7 +6768,8 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
   attr = binfo->attr;
   if (attr) 
     {
-      if (p->family == AF_INET)
+      if (p->family == AF_INET
+          && (safi == SAFI_MPLS_VPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
        {
          if (safi == SAFI_MPLS_VPN)
            vty_out (vty, "%-16s",
@@ -6773,7 +6778,7 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
            vty_out (vty, "%-16s", inet_ntoa (attr->nexthop));
        }
 #ifdef HAVE_IPV6      
-      else if (p->family == AF_INET6)
+      else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr))
        {
          assert (attr->extra);
          char buf[BUFSIZ];
@@ -7026,7 +7031,8 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
         vty_out (vty, "%s", VTY_NEWLINE);
          
       /* Line2 display Next-hop, Neighbor, Router-id */
-      if (p->family == AF_INET)
+      if (p->family == AF_INET
+          && (safi == SAFI_MPLS_VPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
        {
           if (safi == SAFI_MPLS_VPN)
             {
@@ -7068,7 +7074,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
       if (binfo->peer == bgp->peer_self)
        {
 
-          if (p->family == AF_INET)
+          if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))
             {
               if (json_paths)
                 json_string = json_object_new_string("0.0.0.0");
index b6c5a2511a902fbf427598d3c1165696fd0dba05..124ac4ea1d8be8e4c3c23b5079289a0fba5b0f2d 100644 (file)
@@ -150,6 +150,10 @@ struct bgp_static
   u_char tag[3];
 };
 
+#define BGP_ATTR_NEXTHOP_AFI_IP6(attr) \
+  (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)) && \
+   (attr)->extra && ((attr)->extra->mp_nexthop_len == 16 || \
+    (attr)->extra->mp_nexthop_len == 32))
 #define BGP_INFO_COUNTABLE(BI) \
   (! CHECK_FLAG ((BI)->flags, BGP_INFO_HISTORY) \
    && ! CHECK_FLAG ((BI)->flags, BGP_INFO_REMOVED))
index 7a980f0612e6239ce23f845424635a1655d4afa4..e2a59e324bb0adedba9c602022c504bdd7603852 100644 (file)
@@ -52,7 +52,8 @@
 #define PEER_UPDGRP_CAP_FLAGS (PEER_CAP_AS4_RCV)
 
 #define PEER_UPDGRP_AF_CAP_FLAGS (PEER_CAP_ORF_PREFIX_SM_RCV | \
-                                 PEER_CAP_ORF_PREFIX_SM_OLD_RCV)
+                                 PEER_CAP_ORF_PREFIX_SM_OLD_RCV |\
+                                  PEER_CAP_ENHE_AF_NEGO)
 
 typedef enum
 {
index 3174da53062bdca75d1b5802630a51becabcabba..d2fce799a8ed26247cb593dda0946c39191c519b 100644 (file)
@@ -421,7 +421,7 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf)
       route_map_sets_nh = CHECK_FLAG (vec->flags,
                                       BPACKET_ATTRVEC_FLAGS_RMAP_CHANGED);
 
-      if (paf->afi == AFI_IP)
+      if (paf->afi == AFI_IP && !peer_cap_enhe(paf->peer))
        {
          struct in_addr v4nh;
 
@@ -501,7 +501,7 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf)
 #endif
 
        }
-      else if (paf->afi == AFI_IP6)
+      else if (paf->afi == AFI_IP6 || peer_cap_enhe(paf->peer))
        {
           struct in6_addr v6nhglobal;
           struct in6_addr v6nhlocal;
@@ -698,7 +698,8 @@ subgroup_update_packet (struct update_subgroup *subgrp)
             }
        }
 
-      if (afi == AFI_IP && safi == SAFI_UNICAST)
+      if ((afi == AFI_IP && safi == SAFI_UNICAST) &&
+          !peer_cap_enhe(peer))
        stream_put_prefix (s, &rn->p);
       else
        {
@@ -713,7 +714,8 @@ subgroup_update_packet (struct update_subgroup *subgrp)
 
          if (stream_empty (snlri))
            mpattrlen_pos = bgp_packet_mpattr_start (snlri, afi, safi,
-                                                    &vecarr, adv->baa->attr);
+                                         (peer_cap_enhe(peer) ? AFI_IP6 : afi),
+                                         &vecarr, adv->baa->attr);
          bgp_packet_mpattr_prefix (snlri, afi, safi, &rn->p, prd, tag);
        }
 
@@ -795,6 +797,7 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
   struct stream *s;
   struct bgp_adj_out *adj;
   struct bgp_advertise *adv;
+  struct peer *peer;
   struct bgp_node *rn;
   bgp_size_t unfeasible_len;
   bgp_size_t total_attr_len;
@@ -814,6 +817,7 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
   if (bpacket_queue_is_full (SUBGRP_INST (subgrp), SUBGRP_PKTQ (subgrp)))
     return NULL;
 
+  peer = SUBGRP_PEER (subgrp);
   afi = SUBGRP_AFI (subgrp);
   safi = SUBGRP_SAFI (subgrp);
   s = subgrp->work;
@@ -841,7 +845,8 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
       else
        first_time = 0;
 
-      if (afi == AFI_IP && safi == SAFI_UNICAST)
+      if (afi == AFI_IP && safi == SAFI_UNICAST &&
+          !peer_cap_enhe(peer))
        stream_put_prefix (s, &rn->p);
       else
        {
@@ -883,7 +888,8 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
 
   if (!stream_empty (s))
     {
-      if (afi == AFI_IP && safi == SAFI_UNICAST)
+      if (afi == AFI_IP && safi == SAFI_UNICAST &&
+          !peer_cap_enhe(peer))
        {
          unfeasible_len
            = stream_get_endp (s) - BGP_HEADER_SIZE - BGP_UNFEASIBLE_LEN;
@@ -976,7 +982,8 @@ subgroup_default_update_packet (struct update_subgroup *subgrp,
   stream_putw_at (s, pos, total_attr_len);
 
   /* NLRI set. */
-  if (p.family == AF_INET && safi == SAFI_UNICAST)
+  if (p.family == AF_INET && safi == SAFI_UNICAST &&
+      !peer_cap_enhe(peer))
     stream_put_prefix (s, &p);
 
   /* Set size. */
@@ -991,6 +998,7 @@ subgroup_default_update_packet (struct update_subgroup *subgrp,
 void
 subgroup_default_withdraw_packet (struct update_subgroup *subgrp)
 {
+  struct peer *peer;
   struct stream *s;
   struct stream *packet;
   struct prefix p;
@@ -1006,6 +1014,7 @@ subgroup_default_withdraw_packet (struct update_subgroup *subgrp)
   if (DISABLE_BGP_ANNOUNCE)
     return;
 
+  peer = SUBGRP_PEER (subgrp);
   afi = SUBGRP_AFI (subgrp);
   safi = SUBGRP_SAFI (subgrp);
 
@@ -1041,7 +1050,8 @@ subgroup_default_withdraw_packet (struct update_subgroup *subgrp)
   stream_putw (s, 0);
 
   /* Withdrawn Routes. */
-  if (p.family == AF_INET && safi == SAFI_UNICAST)
+  if (p.family == AF_INET && safi == SAFI_UNICAST &&
+      !peer_cap_enhe(peer))
     {
       stream_put_prefix (s, &p);
 
index 28643419b21494c566903d8805544c2ae500377d..2491cc4c5f1571ffd31d1e7a55999b8fce005a43 100644 (file)
@@ -3328,6 +3328,30 @@ DEFUN (no_neighbor_dont_capability_negotiate,
   return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DONT_CAPABILITY);
 }
 
+/* neighbor capability extended next hop encoding */
+DEFUN (neighbor_capability_enhe,
+       neighbor_capability_enhe_cmd,
+       NEIGHBOR_CMD2 "capability extended-nexthop",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Advertise capability to the peer\n"
+       "Advertise extended next-hop capability to the peer\n")
+{
+  return peer_flag_set_vty (vty, argv[0], PEER_FLAG_CAPABILITY_ENHE);
+}
+
+DEFUN (no_neighbor_capability_enhe,
+       no_neighbor_capability_enhe_cmd,
+       NO_NEIGHBOR_CMD2 "capability extended-nexthop",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Advertise capability to the peer\n"
+       "Advertise extended next-hop capability to the peer\n")
+{
+  return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_CAPABILITY_ENHE);
+}
+
 static int
 peer_af_flag_modify_vty (struct vty *vty, const char *peer_str, afi_t afi,
                         safi_t safi, u_int32_t flag, int set)
@@ -9546,6 +9570,28 @@ bgp_show_peer (struct vty *vty, struct peer *p)
              vty_out (vty, "%s", VTY_NEWLINE);
            }
 
+         /* Extended nexthop */
+         if (CHECK_FLAG (p->cap, PEER_CAP_ENHE_RCV)
+             || CHECK_FLAG (p->cap, PEER_CAP_ENHE_ADV))
+           {
+             vty_out (vty, "    Extended nexthop:");
+             if (CHECK_FLAG (p->cap, PEER_CAP_ENHE_ADV))
+               vty_out (vty, " advertised");
+             if (CHECK_FLAG (p->cap, PEER_CAP_ENHE_RCV))
+               vty_out (vty, " %sreceived",
+                        CHECK_FLAG (p->cap, PEER_CAP_ENHE_ADV) ? "and " : "");
+             vty_out (vty, "%s", VTY_NEWLINE);
+
+              if (CHECK_FLAG (p->cap, PEER_CAP_ENHE_RCV))
+               {
+                 vty_out (vty, "      Address families by peer:%s        ", VTY_NEWLINE);
+                  for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
+                    if (CHECK_FLAG (p->af_cap[AFI_IP][safi], PEER_CAP_ENHE_AF_RCV))
+                      vty_out (vty, "           %s%s",
+                               afi_safi_print (AFI_IP, safi), VTY_NEWLINE);
+                }
+           }
+
          /* Route Refresh */
          if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV)
              || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_NEW_RCV)
@@ -12242,6 +12288,10 @@ bgp_vty_init (void)
   install_element (BGP_NODE, &neighbor_capability_route_refresh_cmd);
   install_element (BGP_NODE, &no_neighbor_capability_route_refresh_cmd);
 
+  /* "neighbor capability extended-nexthop" commands.*/
+  install_element (BGP_NODE, &neighbor_capability_enhe_cmd);
+  install_element (BGP_NODE, &no_neighbor_capability_enhe_cmd);
+
   /* "neighbor capability orf prefix-list" commands.*/
   install_element (BGP_NODE, &neighbor_capability_orf_prefix_cmd);
   install_element (BGP_NODE, &no_neighbor_capability_orf_prefix_cmd);
index d482d9b38356e8d68f09fd2f07f7762def85caa2..c91a25679dce728e2b7e0ed9fdeb9889d95045ca 100644 (file)
@@ -1020,7 +1020,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
 
   nhcount = 1 + bgp_info_mpath_count (info);
 
-  if (p->family == AF_INET)
+  if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(info->attr))
     {
       struct zapi_ipv4 api;
       struct in_addr *nexthop;
@@ -1153,7 +1153,8 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
 #ifdef HAVE_IPV6
 
   /* We have to think about a IPv6 link-local address curse. */
-  if (p->family == AF_INET6)
+  if (p->family == AF_INET6 ||
+      (p->family == AF_INET && BGP_ATTR_NEXTHOP_AFI_IP6(info->attr)))
     {
       unsigned int ifindex;
       struct in6_addr *nexthop;
@@ -1310,20 +1311,45 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
           api.tag = tag;
         }
 
-      if (bgp_debug_zebra(p))
+      if (p->family == AF_INET)
         {
-          int i;
-          zlog_debug("Zebra send: IPv6 route %s %s/%d metric %u tag %d",
-                   valid_nh_count ? "add" : "delete",
-                   inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
-                   p->prefixlen, api.metric, api.tag);
-          for (i = 0; i < api.nexthop_num; i++)
-            zlog_debug("  IPv6 [nexthop %d] %s", i+1,
-                       inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])));
+          if (bgp_debug_zebra(p))
+            {
+              int i;
+              zlog_debug("Zebra send: IPv4 route %s %s/%d metric %u tag %d",
+                         valid_nh_count ? "add" : "delete",
+                         inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
+                         p->prefixlen, api.metric, api.tag);
+              for (i = 0; i < api.nexthop_num; i++)
+                zlog_debug("  IPv6 [nexthop %d] %s", i+1,
+                           inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])));
+            }
+
+          if (valid_nh_count)
+            zapi_ipv4_route_ipv6_nexthop (ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD,
+                                          zclient, (struct prefix_ipv4 *) p, &api);
+          else
+            zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE,
+                             zclient, (struct prefix_ipv4 *) p, &api);
         }
+      else
+        {
+          if (bgp_debug_zebra(p))
+            {
+              int i;
+              zlog_debug("Zebra send: IPv6 route %s %s/%d metric %u tag %d",
+                         valid_nh_count ? "add" : "delete",
+                         inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
+                         p->prefixlen, api.metric, api.tag);
+              for (i = 0; i < api.nexthop_num; i++)
+                zlog_debug("  IPv6 [nexthop %d] %s", i+1,
+                           inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])));
+            }
 
-      zapi_ipv6_route (valid_nh_count ? ZEBRA_IPV6_ROUTE_ADD : ZEBRA_IPV6_ROUTE_DELETE,
-                       zclient, (struct prefix_ipv6 *) p, &api);
+          zapi_ipv6_route (valid_nh_count ?
+                           ZEBRA_IPV6_ROUTE_ADD : ZEBRA_IPV6_ROUTE_DELETE,
+                           zclient, (struct prefix_ipv6 *) p, &api);
+        }
     }
 #endif /* HAVE_IPV6 */
 }
index 0f99fcc4555a2d380fde6914efc2dab557f4e60f..e8bb2eb4441d7329a83634e8124539d5f545e529 100644 (file)
@@ -3157,6 +3157,7 @@ static const struct peer_flag_action peer_flag_action_list[] =
     { PEER_FLAG_STRICT_CAP_MATCH,         0, peer_change_none },
     { PEER_FLAG_DYNAMIC_CAPABILITY,       0, peer_change_reset },
     { PEER_FLAG_DISABLE_CONNECTED_CHECK,  0, peer_change_reset },
+    { PEER_FLAG_CAPABILITY_ENHE,          0, peer_change_reset },
     { PEER_FLAG_BFD,                      0, peer_change_none },
     { 0, 0, 0 }
   };
@@ -6090,6 +6091,13 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
        vty_out (vty, " neighbor %s capability dynamic%s", addr,
             VTY_NEWLINE);
 
+      /* Extended next-hop capability.  */
+      if (CHECK_FLAG (peer->flags, PEER_FLAG_CAPABILITY_ENHE))
+        if (! peer_group_active (peer) ||
+           ! CHECK_FLAG (g_peer->flags, PEER_FLAG_CAPABILITY_ENHE))
+       vty_out (vty, " neighbor %s capability extended-nexthop%s", addr,
+            VTY_NEWLINE);
+
       /* dont capability negotiation. */
       if (CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY))
         if (! peer_group_active (peer) ||
index 7bdd3e1f3b90c4b1ead2328beab6401347f61b30..e0deec7309cc5f81a742d41ab6ab12c79c8f0717 100644 (file)
@@ -581,6 +581,8 @@ struct peer
 #define PEER_CAP_ADDPATH_RCV                (1 << 12) /* addpath received */
 #define PEER_CAP_HOSTNAME_ADV               (1 << 13) /* hostname advertised */
 #define PEER_CAP_HOSTNAME_RCV               (1 << 14) /* hostname received */
+#define PEER_CAP_ENHE_ADV                   (1 << 15) /* Extended nexthop advertised */
+#define PEER_CAP_ENHE_RCV                   (1 << 16) /* Extended nexthop received */
 
   /* Capability flags (reset in bgp_stop) */
   u_int16_t af_cap[AFI_MAX][SAFI_MAX];
@@ -596,6 +598,9 @@ struct peer
 #define PEER_CAP_ADDPATH_AF_TX_RCV          (1 << 9) /* addpath tx received */
 #define PEER_CAP_ADDPATH_AF_RX_ADV          (1 << 10) /* addpath rx advertised */
 #define PEER_CAP_ADDPATH_AF_RX_RCV          (1 << 11) /* addpath rx received */
+#define PEER_CAP_ENHE_AF_ADV                (1 << 12) /* Extended nexthopi afi/safi advertised */
+#define PEER_CAP_ENHE_AF_RCV                (1 << 13) /* Extended nexthop afi/safi received */
+#define PEER_CAP_ENHE_AF_NEGO               (1 << 14) /* Extended nexthop afi/safi negotiated */
 
   /* Global configuration flags. */
   u_int32_t flags;
@@ -613,6 +618,7 @@ struct peer
 #define PEER_FLAG_BFD                      (1 << 11) /* bfd */
 #define PEER_FLAG_LONESOUL                  (1 << 12)
 #define PEER_FLAG_DYNAMIC_NEIGHBOR          (1 << 13) /* dynamic neighbor */
+#define PEER_FLAG_CAPABILITY_ENHE           (1 << 14) /* Extended next-hop (rfc 5549)*/
 
   /* NSF mode (graceful restart) */
   u_char nsf[AFI_MAX][SAFI_MAX];
@@ -1393,4 +1399,16 @@ peer_dynamic_neighbor (struct peer *peer)
   return (CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_NEIGHBOR)) ? 1 : 0;
 }
 
+/*
+ * Currently supporting RFC 5549 for AFI_IP/SAFI_UNICAST only.
+ *
+ * Note: When other RFC-5549 applicable SAFIs to be supported, that should
+ * come as an argument to this routine.
+ */
+static inline int
+peer_cap_enhe (struct peer *peer)
+{
+  return (CHECK_FLAG(peer->af_cap[AFI_IP][SAFI_UNICAST], PEER_CAP_ENHE_AF_NEGO));
+}
+
 #endif /* _QUAGGA_BGPD_H */
index a848df1ec804715836dc1be77862a2ee481e1294..722075adab67ebf8fc5dc6a65ac1c49fdaf57848 100644 (file)
@@ -629,6 +629,70 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
 }
 
 #ifdef HAVE_IPV6
+int
+zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient,
+                              struct prefix_ipv4 *p, struct zapi_ipv6 *api)
+{
+  int i;
+  int psize;
+  struct stream *s;
+
+  /* Reset stream. */
+  s = zclient->obuf;
+  stream_reset (s);
+
+  zclient_create_header (s, cmd);
+
+  /* Put type and nexthop. */
+  stream_putc (s, api->type);
+  stream_putw (s, api->instance);
+  stream_putc (s, api->flags);
+  stream_putc (s, api->message);
+  stream_putw (s, api->safi);
+
+  /* Put prefix information. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *) & p->prefix, psize);
+
+  /* Nexthop, ifindex, distance and metric information. */
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
+        {
+          stream_putc (s, 1);
+          stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE);
+          /* XXX assert(api->nexthop_num == 0); */
+          /* XXX assert(api->ifindex_num == 0); */
+        }
+      else
+       stream_putc (s, api->nexthop_num + api->ifindex_num);
+
+      for (i = 0; i < api->nexthop_num; i++)
+       {
+         stream_putc (s, ZEBRA_NEXTHOP_IPV6);
+         stream_write (s, (u_char *)api->nexthop[i], 16);
+       }
+      for (i = 0; i < api->ifindex_num; i++)
+       {
+         stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
+         stream_putl (s, api->ifindex[i]);
+       }
+    }
+
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE))
+    stream_putc (s, api->distance);
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
+    stream_putl (s, api->metric);
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG))
+    stream_putw (s, api->tag);
+
+  /* Put length at the first point of the stream. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return zclient_send_message(zclient);
+}
+
 int
 zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
               struct zapi_ipv6 *api)
index bb8a87b1456e61bfe4a974fa7dcd381db54d620a..bd4d06647dcc1cd2452e6c615cde780787ecae0a 100644 (file)
@@ -212,6 +212,8 @@ struct zapi_ipv6
 
 extern int zapi_ipv6_route (u_char cmd, struct zclient *zclient, 
                      struct prefix_ipv6 *p, struct zapi_ipv6 *api);
+extern int zapi_ipv4_route_ipv6_nexthop (u_char, struct zclient *,
+                                         struct prefix_ipv4 *, struct zapi_ipv6 *);
 #endif /* HAVE_IPV6 */
 
 #endif /* _ZEBRA_ZCLIENT_H */
index 05e7013c568260a41a3884c81c868031ec99b618..c1231e4c8b8f623572de07e91b7fa4dee107b231 100644 (file)
@@ -433,7 +433,8 @@ struct in_pktinfo
 #define ZEBRA_IMPORT_ROUTE_REGISTER       30
 #define ZEBRA_IMPORT_ROUTE_UNREGISTER     31
 #define ZEBRA_IMPORT_CHECK_UPDATE         32
-#define ZEBRA_MESSAGE_MAX                 33
+#define ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD 33
+#define ZEBRA_MESSAGE_MAX                 34
 
 /* Marker value used in new Zserv, in the byte location corresponding
  * the command value in the old zserv header. To allow old and new
index a05bd8c1960ca94ea43e3f799bc131df9d496205..45daad0fede3c82299c93f5356a673766a4c698d 100644 (file)
@@ -452,7 +452,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
                  u_char distance, u_int32_t vrf_id);
 
 extern int
-rib_add_ipv6_multipath (struct prefix_ipv6 *, struct rib *, safi_t,
+rib_add_ipv6_multipath (struct prefix *, struct rib *, safi_t,
                         unsigned long);
 
 extern int
index db679e85755ab8ff5549bac02a85ff8a5c06e62b..7adbcbe5347f2dbe4d62192a117f01368cea8b5e 100644 (file)
@@ -3221,7 +3221,7 @@ rib_add_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p,
 }
 
 int
-rib_add_ipv6_multipath (struct prefix_ipv6 *p, struct rib *rib, safi_t safi,
+rib_add_ipv6_multipath (struct prefix *p, struct rib *rib, safi_t safi,
                        unsigned long ifindex)
 {
   struct route_table *table;
@@ -3231,26 +3231,41 @@ rib_add_ipv6_multipath (struct prefix_ipv6 *p, struct rib *rib, safi_t safi,
   int ret = 0;
   unsigned int table_id = 0;
 
-  if (rib)
-    table_id = rib->table;
-  else
-    return 0;                  /* why are we getting called with NULL rib */
-
-  /* Lookup table.  */
-  if ((table_id == RT_TABLE_MAIN) || (table_id == zebrad.rtm_table_default))
+  if (p->family == AF_INET)
     {
-      table = vrf_table (AFI_IP6, safi, 0);
+      if (!rib)
+        return 0;
+
+      table = vrf_table (AFI_IP, safi, 0);
+      if (!table)
+        return 0;
+      /* Make it sure prefixlen is applied to the prefix. */
+      apply_mask_ipv4 (p);
     }
   else
     {
-      table = vrf_other_route_table(AFI_IP6, table_id, 0);
-    }
+      if (rib)
+        table_id = rib->table;
+      else
+        return 0;                      /* why are we getting called with NULL rib */
 
-  if (! table)
-    return 0;
+      /* Lookup table.  */
+      if ((table_id == RT_TABLE_MAIN) || (table_id == zebrad.rtm_table_default))
+        {
+          table = vrf_table (AFI_IP6, safi, 0);
+        }
+      else
+        {
+          table = vrf_other_route_table(AFI_IP6, table_id, 0);
+        }
 
-  /* Make sure mask is applied. */
-  apply_mask_ipv6 (p);
+      if (! table)
+        return 0;
+
+      /* Make sure mask is applied. */
+      apply_mask_ipv6 (p);
+
+    }
 
   /* Set default distance by route type. */
   if (rib->distance == 0)
index a36f8600b2e3f2639e719faf95f865cdcc2925d8..c95322a5696ac89f25d84e9e2d9bd50f0c461c33 100644 (file)
@@ -888,6 +888,7 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
   struct rib *rib;
   struct nexthop *nexthop, *tnexthop;
   int recursing;
+  char buf[BUFSIZ];
 
   RNODE_FOREACH_RIB (rn, rib)
     {
@@ -958,6 +959,18 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
              if (nexthop->ifindex)
                vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
              break;
+#ifdef HAVE_IPV6
+           case NEXTHOP_TYPE_IPV6:
+           case NEXTHOP_TYPE_IPV6_IFINDEX:
+           case NEXTHOP_TYPE_IPV6_IFNAME:
+             vty_out (vty, " %s",
+                      inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
+             if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+               vty_out (vty, ", %s", nexthop->ifname);
+             else if (nexthop->ifindex)
+               vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
+             break;
+#endif /* HAVE_IPV6 */
            case NEXTHOP_TYPE_IFINDEX:
              vty_out (vty, " directly connected, %s",
                       ifindex2ifname (nexthop->ifindex));
@@ -1058,6 +1071,19 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib)
          if (nexthop->ifindex)
            vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
          break;
+#ifdef HAVE_IPV6
+        case NEXTHOP_TYPE_IPV6:
+       case NEXTHOP_TYPE_IPV6_IFINDEX:
+       case NEXTHOP_TYPE_IPV6_IFNAME:
+         vty_out (vty, " via %s",
+                  inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
+         if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+           vty_out (vty, ", %s", nexthop->ifname);
+         else if (nexthop->ifindex)
+           vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
+         break;
+#endif /* HAVE_IPV6 */
+
        case NEXTHOP_TYPE_IFINDEX:
          vty_out (vty, " is directly connected, %s",
                   ifindex2ifname (nexthop->ifindex));
@@ -1168,7 +1194,7 @@ DEFUN (show_ip_route,
            vty_out (vty, SHOW_ROUTE_V4_HEADER);
            first = 0;
          }
-       vty_show_ip_route (vty, rn, rib);
+        vty_show_ip_route (vty, rn, rib);
       }
   return CMD_SUCCESS;
 }
index 79c469cfc2ab2fc1468dae9369db3a5235af47d2..61d3a0a55ebe9a96fe9fb380267b284e1121f88a 100644 (file)
@@ -1266,6 +1266,127 @@ zread_ipv4_import_lookup (struct zserv *client, u_short length)
 }
 
 #ifdef HAVE_IPV6
+/* Zebra server IPv6 prefix add function. */
+static int
+zread_ipv4_route_ipv6_nexthop_add (struct zserv *client, u_short length)
+{
+  int i;
+  struct stream *s;
+  struct in6_addr nexthop;
+  struct rib *rib;
+  u_char message;
+  u_char nexthop_num;
+  u_char nexthop_type;
+  unsigned long ifindex;
+  struct prefix_ipv4 p;
+  u_char ifname_len;
+  safi_t safi;
+  static struct in6_addr nexthops[MULTIPATH_NUM];
+  static unsigned int ifindices[MULTIPATH_NUM];
+  int ret;
+
+  /* Get input stream.  */
+  s = client->ibuf;
+
+  ifindex = 0;
+  memset (&nexthop, 0, sizeof (struct in6_addr));
+
+  /* Allocate new rib. */
+  rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
+
+  /* Type, flags, message. */
+  rib->type = stream_getc (s);
+  rib->instance = stream_getw (s);
+  rib->flags = stream_getc (s);
+  message = stream_getc (s);
+  safi = stream_getw (s);
+  rib->uptime = time (NULL);
+
+  /* IPv4 prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = stream_getc (s);
+  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+
+  /* We need to give nh-addr, nh-ifindex with the same next-hop object
+   * to the rib to ensure that IPv6 multipathing works; need to coalesce
+   * these. Clients should send the same number of paired set of
+   * next-hop-addr/next-hop-ifindices. */
+  if (CHECK_FLAG (message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      int nh_count = 0;
+      int if_count = 0;
+      int max_nh_if = 0;
+
+      nexthop_num = stream_getc (s);
+      for (i = 0; i < nexthop_num; i++)
+       {
+         nexthop_type = stream_getc (s);
+
+         switch (nexthop_type)
+           {
+           case ZEBRA_NEXTHOP_IPV6:
+             stream_get (&nexthop, s, 16);
+              if (nh_count < MULTIPATH_NUM) {
+               nexthops[nh_count++] = nexthop;
+              }
+             break;
+           case ZEBRA_NEXTHOP_IFINDEX:
+              if (if_count < MULTIPATH_NUM) {
+               ifindices[if_count++] = stream_getl (s);
+              }
+             break;
+            case ZEBRA_NEXTHOP_BLACKHOLE:
+              nexthop_blackhole_add (rib);
+              break;
+           }
+       }
+
+      max_nh_if = (nh_count > if_count) ? nh_count : if_count;
+      for (i = 0; i < max_nh_if; i++)
+        {
+         if ((i < nh_count) && !IN6_IS_ADDR_UNSPECIFIED (&nexthops[i])) {
+            if ((i < if_count) && ifindices[i]) {
+              nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]);
+            }
+            else {
+             nexthop_ipv6_add (rib, &nexthops[i]);
+            }
+          }
+          else {
+            if ((i < if_count) && ifindices[i]) {
+             nexthop_ifindex_add (rib, ifindices[i]);
+           }
+          }
+       }
+    }
+
+  /* Distance. */
+  if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE))
+    rib->distance = stream_getc (s);
+
+  /* Metric. */
+  if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
+    rib->metric = stream_getl (s);
+
+  /* Tag */
+  if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG))
+    rib->tag = stream_getw (s);
+  else
+    rib->tag = 0;
+
+  /* Table */
+  rib->table=zebrad.rtm_table_default;
+  ret = rib_add_ipv6_multipath ((struct prefix *)&p, rib, safi, ifindex);
+  /* Stats */
+  if (ret > 0)
+    client->v4_route_add_cnt++;
+  else if (ret < 0)
+    client->v4_route_upd8_cnt++;
+
+  return 0;
+}
+
 /* Zebra server IPv6 prefix add function. */
 static int
 zread_ipv6_add (struct zserv *client, u_short length)
@@ -1385,7 +1506,7 @@ zread_ipv6_add (struct zserv *client, u_short length)
 
   /* Table */
   rib->table=zebrad.rtm_table_default;
-  ret = rib_add_ipv6_multipath (&p, rib, safi, ifindex);
+  ret = rib_add_ipv6_multipath ((struct prefix *)&p, rib, safi, ifindex);
   /* Stats */
   if (ret > 0)
     client->v6_route_add_cnt++;
@@ -1731,6 +1852,9 @@ zebra_client_read (struct thread *thread)
       zread_ipv4_delete (client, length);
       break;
 #ifdef HAVE_IPV6
+    case ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD:
+      zread_ipv4_route_ipv6_nexthop_add (client, length);
+      break;
     case ZEBRA_IPV6_ROUTE_ADD:
       zread_ipv6_add (client, length);
       break;