ipip: Multi-point interface 43/24143/5
authorNeale Ranns <nranns@cisco.com>
Sun, 29 Dec 2019 23:55:18 +0000 (23:55 +0000)
committerDamjan Marion <dmarion@me.com>
Mon, 27 Jan 2020 20:40:30 +0000 (20:40 +0000)
Type: feature

plus fixes for gre

Signed-off-by: Neale Ranns <nranns@cisco.com>
Change-Id: I0eca5f94b8b8ea0fcfb058162cafea4491708db6

25 files changed:
src/plugins/ikev2/ikev2.c
src/vnet/adj/adj.c
src/vnet/adj/adj_delegate.c
src/vnet/adj/adj_midchain.c
src/vnet/adj/adj_nbr.c
src/vnet/fib/fib_path.c
src/vnet/gre/gre.c
src/vnet/gre/gre.h
src/vnet/gre/interface.c
src/vnet/ipip/ipip.api
src/vnet/ipip/ipip.c
src/vnet/ipip/ipip.h
src/vnet/ipip/ipip_api.c
src/vnet/ipip/ipip_cli.c
src/vnet/ipip/node.c
src/vnet/ipip/sixrd.c
src/vnet/ipsec/ipsec_api.c
src/vnet/ipsec/ipsec_cli.c
src/vnet/nhrp/nhrp.c
src/vnet/tunnel/tunnel.c
src/vnet/tunnel/tunnel.h
src/vnet/tunnel/tunnel_types.api
test/test_gre.py
test/test_ipip.py
test/vpp_ipip_tun_interface.py

index 6e3ca7d..03448b9 100644 (file)
@@ -1546,7 +1546,7 @@ ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a)
   rv = ipip_add_tunnel (IPIP_TRANSPORT_IP4, ~0,
                        &a->local_ip, &a->remote_ip, 0,
                        TUNNEL_ENCAP_DECAP_FLAG_NONE, IP_DSCP_CS0,
-                       &sw_if_index);
+                       TUNNEL_MODE_P2P, &sw_if_index);
 
   if (rv == VNET_API_ERROR_IF_ALREADY_EXISTS)
     {
index a603925..c758ebe 100644 (file)
@@ -182,7 +182,7 @@ format_ip_adjacency (u8 * s, va_list * args)
         s = format (s, "\n   flags:%U", format_adj_flags, adj->ia_flags);
         s = format (s, "\n   counts:[%Ld:%Ld]", counts.packets, counts.bytes);
        s = format (s, "\n   locks:%d", adj->ia_node.fn_locks);
-       s = format(s, "\n delegates:\n  ");
+       s = format(s, "\n delegates:");
         s = adj_delegate_format(s, adj);
 
        s = format(s, "\n children:");
index 68232c5..87a83fb 100644 (file)
@@ -163,13 +163,13 @@ adj_delegate_format (u8* s, ip_adjacency_t *adj)
     {
         if (ad_vfts[aed->ad_type].adv_format)
         {
-            s = format(s, "{");
+            s = format(s, "\n  {");
             s = ad_vfts[aed->ad_type].adv_format(aed, s);
             s = format(s, "}");
         }
         else
         {
-            s = format(s, "{unknown delegate}");
+            s = format(s, "\n  {unknown delegate}");
         }
     }
 
index 542b5a1..33da0ed 100644 (file)
@@ -513,12 +513,11 @@ adj_nbr_midchain_update_rewrite (adj_index_t adj_index,
      * one time only update. since we don't support changing the tunnel
      * src,dst, this is all we need.
      */
-    ASSERT((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP) ||
-           (adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN) ||
-           (adj->lookup_next_index == IP_LOOKUP_NEXT_MCAST) ||
-           (adj->lookup_next_index == IP_LOOKUP_NEXT_BCAST));
-
-    adj_midchain_setup(adj_index, fixup, fixup_data, flags);
+    if (adj->lookup_next_index != IP_LOOKUP_NEXT_MIDCHAIN ||
+        adj->lookup_next_index != IP_LOOKUP_NEXT_MCAST_MIDCHAIN)
+    {
+        adj_midchain_setup(adj_index, fixup, fixup_data, flags);
+    }
 
     /*
      * update the rewrite with the workers paused.
index 9e990e0..7531326 100644 (file)
@@ -907,15 +907,19 @@ adj_nbr_show (vlib_main_t * vm,
              vlib_cli_command_t * cmd)
 {
     adj_index_t ai = ADJ_INDEX_INVALID;
+    ip46_address_t nh = ip46_address_initializer;
     u32 sw_if_index = ~0;
 
     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
-       if (unformat (input, "%d", &ai))
+       if (unformat (input, "%U",
+                      unformat_vnet_sw_interface, vnet_get_main(),
+                      &sw_if_index))
            ;
        else if (unformat (input, "%U",
-                          unformat_vnet_sw_interface, vnet_get_main(),
-                          &sw_if_index))
+                          unformat_ip46_address, &nh, IP46_TYPE_ANY))
+           ;
+       else if (unformat (input, "%d", &ai))
            ;
        else
            break;
@@ -932,12 +936,24 @@ adj_nbr_show (vlib_main_t * vm,
     {
        fib_protocol_t proto;
 
-       for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
-       {
-           adj_nbr_walk(sw_if_index, proto,
-                        adj_nbr_show_one,
-                        vm);
-       }
+        if (ip46_address_is_zero(&nh))
+        {
+            for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
+            {
+                adj_nbr_walk(sw_if_index, proto,
+                             adj_nbr_show_one,
+                             vm);
+            }
+        }
+        else
+        {
+            proto = (ip46_address_is_ip4(&nh) ?
+                     FIB_PROTOCOL_IP4 :
+                     FIB_PROTOCOL_IP6);
+            adj_nbr_walk_nh(sw_if_index, proto, &nh,
+                            adj_nbr_show_one,
+                            vm);
+        }
     }
     else
     {
index c8a2a09..a640480 100644 (file)
@@ -1870,7 +1870,8 @@ fib_path_recursive_loop_detect (fib_node_index_t path_index,
     }
     case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
     case FIB_PATH_TYPE_ATTACHED:
-       if (adj_recursive_loop_detect(path->fp_dpo.dpoi_index,
+       if (dpo_is_adj(&path->fp_dpo) &&
+            adj_recursive_loop_detect(path->fp_dpo.dpoi_index,
                                       entry_indicies))
        {
            FIB_PATH_DBG(path, "recursive loop formed");
index f06f19f..2b95d99 100644 (file)
@@ -18,7 +18,6 @@
 #include <vnet/vnet.h>
 #include <vnet/gre/gre.h>
 #include <vnet/adj/adj_midchain.h>
-#include <vnet/nhrp/nhrp.h>
 
 extern gre_main_t gre_main;
 
@@ -331,10 +330,38 @@ gre_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
   gre_tunnel_stack (ai);
 }
 
-static adj_walk_rc_t
-mgre_mk_complete_walk (adj_index_t ai, void *ctx)
+adj_walk_rc_t
+mgre_mk_complete_walk (adj_index_t ai, void *data)
 {
-  nhrp_entry_adj_stack (ctx, ai);
+  mgre_walk_ctx_t *ctx = data;
+  adj_midchain_fixup_t f;
+
+  f = (ctx->t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP4 ?
+       gre4_fixup : gre6_fixup);
+
+  adj_nbr_midchain_update_rewrite
+    (ai, f, NULL, ADJ_FLAG_MIDCHAIN_IP_STACK,
+     gre_build_rewrite (vnet_get_main (),
+                       ctx->t->sw_if_index,
+                       adj_get_link_type (ai),
+                       &nhrp_entry_get_nh (ctx->ne)->fp_addr));
+
+  nhrp_entry_adj_stack (ctx->ne, ai);
+
+  return (ADJ_WALK_RC_CONTINUE);
+}
+
+adj_walk_rc_t
+mgre_mk_incomplete_walk (adj_index_t ai, void *data)
+{
+  gre_tunnel_t *t = data;
+  adj_midchain_fixup_t f;
+
+  f = (t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP4 ? gre4_fixup : gre6_fixup);
+
+  adj_nbr_midchain_update_rewrite (ai, f, NULL, ADJ_FLAG_NONE, NULL);
+
+  adj_midchain_delegate_unstack (ai);
 
   return (ADJ_WALK_RC_CONTINUE);
 }
@@ -346,20 +373,11 @@ mgre_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
   ip_adjacency_t *adj;
   nhrp_entry_t *ne;
   gre_tunnel_t *t;
-  adj_flags_t af;
-  u8 is_ipv6;
   u32 ti;
 
   adj = adj_get (ai);
   ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
   t = pool_elt_at_index (gm->tunnels, ti);
-  is_ipv6 = t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6 ? 1 : 0;
-  af = ADJ_FLAG_MIDCHAIN_IP_STACK;
-
-  adj_nbr_midchain_update_rewrite
-    (ai, !is_ipv6 ? gre4_fixup : gre6_fixup, NULL, af,
-     gre_build_rewrite (vnm, sw_if_index, adj_get_link_type (ai),
-                       &adj->sub_type.nbr.next_hop));
 
   ne = nhrp_entry_find (sw_if_index, &adj->sub_type.nbr.next_hop);
 
@@ -367,8 +385,13 @@ mgre_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
     // no NHRP entry to provide the next-hop
     return;
 
-  adj_nbr_walk_nh (sw_if_index, t->tunnel_dst.fp_proto,
-                  &adj->sub_type.nbr.next_hop, mgre_mk_complete_walk, ne);
+  mgre_walk_ctx_t ctx = {
+    .t = t,
+    .ne = ne
+  };
+  adj_nbr_walk_nh (sw_if_index,
+                  adj->ia_nh_proto,
+                  &adj->sub_type.nbr.next_hop, mgre_mk_complete_walk, &ctx);
 }
 #endif /* CLIB_MARCH_VARIANT */
 
index 7f6ff0b..70f6241 100644 (file)
@@ -25,6 +25,7 @@
 #include <vnet/ip/format.h>
 #include <vnet/adj/adj_types.h>
 #include <vnet/tunnel/tunnel.h>
+#include <vnet/nhrp/nhrp.h>
 
 extern vnet_hw_interface_class_t gre_hw_interface_class;
 extern vnet_hw_interface_class_t mgre_hw_interface_class;
@@ -323,6 +324,15 @@ extern void gre_tunnel_stack (adj_index_t ai);
 extern void gre_update_adj (vnet_main_t * vnm,
                            u32 sw_if_index, adj_index_t ai);
 
+typedef struct mgre_walk_ctx_t_
+{
+  const gre_tunnel_t *t;
+  const nhrp_entry_t *ne;
+} mgre_walk_ctx_t;
+
+adj_walk_rc_t mgre_mk_complete_walk (adj_index_t ai, void *data);
+adj_walk_rc_t mgre_mk_incomplete_walk (adj_index_t ai, void *data);
+
 format_function_t format_gre_protocol;
 format_function_t format_gre_header;
 format_function_t format_gre_header_with_length;
index 59bf21d..178b080 100644 (file)
@@ -203,10 +203,14 @@ gre_nhrp_mk_key (const gre_tunnel_t * t,
                 t->type, TUNNEL_MODE_P2P, 0, &key->gtk_v6);
 }
 
+/**
+ * An NHRP entry has been added
+ */
 static void
 gre_nhrp_entry_added (const nhrp_entry_t * ne)
 {
   gre_main_t *gm = &gre_main;
+  const ip46_address_t *nh;
   gre_tunnel_key_t key;
   gre_tunnel_t *t;
   u32 sw_if_index;
@@ -221,16 +225,35 @@ gre_nhrp_entry_added (const nhrp_entry_t * ne)
   if (INDEX_INVALID == t_idx)
     return;
 
+  /* entry has been added on an interface for which there is a GRE tunnel */
   t = pool_elt_at_index (gm->tunnels, t_idx);
 
+  if (t->mode != TUNNEL_MODE_MP)
+    return;
+
+  /* the next-hop (underlay) of the NHRP entry will form part of the key for
+   * ingress lookup to match packets to this interface */
   gre_nhrp_mk_key (t, ne, &key);
   gre_tunnel_db_add (t, &key);
+
+  /* update the rewrites for each of the adjacencies for this peer (overlay)
+   * using  the next-hop (underlay) */
+  mgre_walk_ctx_t ctx = {
+    .t = t,
+    .ne = ne
+  };
+  nh = nhrp_entry_get_peer (ne);
+  adj_nbr_walk_nh (nhrp_entry_get_sw_if_index (ne),
+                  (ip46_address_is_ip4 (nh) ?
+                   FIB_PROTOCOL_IP4 :
+                   FIB_PROTOCOL_IP6), nh, mgre_mk_complete_walk, &ctx);
 }
 
 static void
 gre_nhrp_entry_deleted (const nhrp_entry_t * ne)
 {
   gre_main_t *gm = &gre_main;
+  const ip46_address_t *nh;
   gre_tunnel_key_t key;
   gre_tunnel_t *t;
   u32 sw_if_index;
@@ -247,8 +270,17 @@ gre_nhrp_entry_deleted (const nhrp_entry_t * ne)
 
   t = pool_elt_at_index (gm->tunnels, t_idx);
 
+  /* remove the next-hop as an ingress lookup key */
   gre_nhrp_mk_key (t, ne, &key);
   gre_tunnel_db_remove (t, &key);
+
+  nh = nhrp_entry_get_peer (ne);
+
+  /* make all the adjacencies incomplete */
+  adj_nbr_walk_nh (nhrp_entry_get_sw_if_index (ne),
+                  (ip46_address_is_ip4 (nh) ?
+                   FIB_PROTOCOL_IP4 :
+                   FIB_PROTOCOL_IP6), nh, mgre_mk_incomplete_walk, t);
 }
 
 static walk_rc_t
index 8ba3136..4fbfa1d 100644 (file)
@@ -67,6 +67,7 @@ typedef ipip_tunnel
                                           details/dump */
   u32 table_id;
   vl_api_tunnel_encap_decap_flags_t flags;
+  vl_api_tunnel_mode_t mode;
   vl_api_ip_dscp_t dscp; /* DSCP value for the tunnel encap,
                             ignored if ECNAP_COPY_DSCP flag is set */
 };
index 05460fb..aa8d8da 100644 (file)
@@ -25,6 +25,7 @@
 #include <vnet/fib/ip6_fib.h>
 #include <vnet/ip/format.h>
 #include <vnet/ipip/ipip.h>
+#include <vnet/nhrp/nhrp.h>
 
 ipip_main_t ipip_main;
 
@@ -55,10 +56,14 @@ static u8 *
 ipip_build_rewrite (vnet_main_t * vnm, u32 sw_if_index,
                    vnet_link_t link_type, const void *dst_address)
 {
+  const ip46_address_t *dst;
   ip4_header_t *ip4;
   ip6_header_t *ip6;
   u8 *rewrite = NULL;
-  ipip_tunnel_t *t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
+  ipip_tunnel_t *t;
+
+  dst = dst_address;
+  t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
 
   if (!t)
     /* not one of ours */
@@ -73,12 +78,12 @@ ipip_build_rewrite (vnet_main_t * vnm, u32 sw_if_index,
       ip4->ttl = 64;
       /* fixup ip4 header length, protocol and checksum after-the-fact */
       ip4->src_address.as_u32 = t->tunnel_src.ip4.as_u32;
-      ip4->dst_address.as_u32 = t->tunnel_dst.ip4.as_u32;
-      ip4->checksum = ip4_header_checksum (ip4);
+      ip4->dst_address.as_u32 = dst->ip4.as_u32;
       if (!(t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP))
        ip4_header_set_dscp (ip4, t->dscp);
       if (t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_SET_DF)
        ip4_header_set_df (ip4);
+      ip4->checksum = ip4_header_checksum (ip4);
       break;
 
     case IPIP_TRANSPORT_IP6:
@@ -90,15 +95,11 @@ ipip_build_rewrite (vnet_main_t * vnm, u32 sw_if_index,
       /* fixup ip6 header length and protocol after-the-fact */
       ip6->src_address.as_u64[0] = t->tunnel_src.ip6.as_u64[0];
       ip6->src_address.as_u64[1] = t->tunnel_src.ip6.as_u64[1];
-      ip6->dst_address.as_u64[0] = t->tunnel_dst.ip6.as_u64[0];
-      ip6->dst_address.as_u64[1] = t->tunnel_dst.ip6.as_u64[1];
+      ip6->dst_address.as_u64[0] = dst->ip6.as_u64[0];
+      ip6->dst_address.as_u64[1] = dst->ip6.as_u64[1];
       if (!(t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP))
        ip6_set_dscp_network_order (ip6, t->dscp);
       break;
-
-    default:
-      /* pass through */
-      ;
     }
   return (rewrite);
 }
@@ -107,8 +108,10 @@ static void
 ipip4_fixup (vlib_main_t * vm, const ip_adjacency_t * adj, vlib_buffer_t * b,
             const void *data)
 {
+  tunnel_encap_decap_flags_t flags;
   ip4_header_t *ip4;
-  const ipip_tunnel_t *t = data;
+
+  flags = pointer_to_uword (data);
 
   ip4 = vlib_buffer_get_current (b);
   ip4->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
@@ -116,11 +119,11 @@ ipip4_fixup (vlib_main_t * vm, const ip_adjacency_t * adj, vlib_buffer_t * b,
     {
     case VNET_LINK_IP6:
       ip4->protocol = IP_PROTOCOL_IPV6;
-      if (t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
+      if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
        ip4_header_set_dscp (ip4,
                             ip6_dscp_network_order ((ip6_header_t *) (ip4 +
                                                                       1)));
-      if (t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)
+      if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)
        ip4_header_set_ecn (ip4,
                            ip6_ecn_network_order ((ip6_header_t *) (ip4 +
                                                                     1)));
@@ -128,11 +131,11 @@ ipip4_fixup (vlib_main_t * vm, const ip_adjacency_t * adj, vlib_buffer_t * b,
 
     case VNET_LINK_IP4:
       ip4->protocol = IP_PROTOCOL_IP_IN_IP;
-      if (t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
+      if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
        ip4_header_set_dscp (ip4, ip4_header_get_dscp (ip4 + 1));
-      if (t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)
+      if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)
        ip4_header_set_ecn (ip4, ip4_header_get_ecn (ip4 + 1));
-      if ((t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DF) &&
+      if ((flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DF) &&
          ip4_header_get_df (ip4 + 1))
        ip4_header_set_df (ip4);
       break;
@@ -148,8 +151,10 @@ static void
 ipip6_fixup (vlib_main_t * vm, const ip_adjacency_t * adj, vlib_buffer_t * b,
             const void *data)
 {
+  tunnel_encap_decap_flags_t flags;
   ip6_header_t *ip6;
-  const ipip_tunnel_t *t = data;
+
+  flags = pointer_to_uword (data);
 
   /* Must set locally originated otherwise we're not allowed to
      fragment the packet later */
@@ -163,18 +168,18 @@ ipip6_fixup (vlib_main_t * vm, const ip_adjacency_t * adj, vlib_buffer_t * b,
     {
     case VNET_LINK_IP6:
       ip6->protocol = IP_PROTOCOL_IPV6;
-      if (t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
+      if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
        ip6_set_dscp_network_order (ip6, ip6_dscp_network_order (ip6 + 1));
-      if (t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)
+      if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)
        ip6_set_ecn_network_order (ip6, ip6_ecn_network_order (ip6 + 1));
       break;
 
     case VNET_LINK_IP4:
       ip6->protocol = IP_PROTOCOL_IP_IN_IP;
-      if (t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
+      if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
        ip6_set_dscp_network_order
          (ip6, ip4_header_get_dscp ((ip4_header_t *) (ip6 + 1)));
-      if (t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)
+      if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)
        ip6_set_ecn_network_order
          (ip6, ip4_header_get_ecn ((ip4_header_t *) (ip6 + 1)));
       break;
@@ -257,14 +262,89 @@ ipip_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
   if (VNET_LINK_ETHERNET == adj_get_link_type (ai))
     af |= ADJ_FLAG_MIDCHAIN_NO_COUNT;
 
-  adj_nbr_midchain_update_rewrite (ai, f, t, af,
-                                  ipip_build_rewrite (vnm,
-                                                      sw_if_index,
-                                                      adj_get_link_type
-                                                      (ai), NULL));
+  adj_nbr_midchain_update_rewrite
+    (ai, f, uword_to_pointer (t->flags, void *), af,
+     ipip_build_rewrite (vnm, sw_if_index,
+                        adj_get_link_type (ai), &t->tunnel_dst));
   ipip_tunnel_stack (ai);
 }
 
+typedef struct mipip_walk_ctx_t_
+{
+  const ipip_tunnel_t *t;
+  const nhrp_entry_t *ne;
+} mipip_walk_ctx_t;
+
+static adj_walk_rc_t
+mipip_mk_complete_walk (adj_index_t ai, void *data)
+{
+  mipip_walk_ctx_t *ctx = data;
+  adj_midchain_fixup_t f;
+
+  f = ctx->t->transport == IPIP_TRANSPORT_IP6 ? ipip6_fixup : ipip4_fixup;
+
+  adj_nbr_midchain_update_rewrite
+    (ai, f, uword_to_pointer (ctx->t->flags, void *),
+     ADJ_FLAG_MIDCHAIN_IP_STACK, ipip_build_rewrite (vnet_get_main (),
+                                                    ctx->t->sw_if_index,
+                                                    adj_get_link_type (ai),
+                                                    &nhrp_entry_get_nh
+                                                    (ctx->ne)->fp_addr));
+
+  nhrp_entry_adj_stack (ctx->ne, ai);
+
+  return (ADJ_WALK_RC_CONTINUE);
+}
+
+static adj_walk_rc_t
+mipip_mk_incomplete_walk (adj_index_t ai, void *data)
+{
+  ipip_tunnel_t *t = data;
+  adj_midchain_fixup_t f;
+
+  f = t->transport == IPIP_TRANSPORT_IP6 ? ipip6_fixup : ipip4_fixup;
+
+  adj_nbr_midchain_update_rewrite (ai, f, NULL, ADJ_FLAG_NONE, NULL);
+
+  adj_midchain_delegate_unstack (ai);
+
+  return (ADJ_WALK_RC_CONTINUE);
+}
+
+void
+mipip_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
+{
+  ipip_main_t *gm = &ipip_main;
+  adj_midchain_fixup_t f;
+  ip_adjacency_t *adj;
+  nhrp_entry_t *ne;
+  ipip_tunnel_t *t;
+  u32 ti;
+
+  adj = adj_get (ai);
+  ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
+  t = pool_elt_at_index (gm->tunnels, ti);
+  f = t->transport == IPIP_TRANSPORT_IP6 ? ipip6_fixup : ipip4_fixup;
+
+  ne = nhrp_entry_find (sw_if_index, &adj->sub_type.nbr.next_hop);
+
+  if (NULL == ne)
+    {
+      // no NHRP entry to provide the next-hop
+      adj_nbr_midchain_update_rewrite
+       (ai, f, uword_to_pointer (t->flags, void *), ADJ_FLAG_NONE, NULL);
+      return;
+    }
+
+  mipip_walk_ctx_t ctx = {
+    .t = t,
+    .ne = ne
+  };
+  adj_nbr_walk_nh (sw_if_index,
+                  adj->ia_nh_proto,
+                  &adj->sub_type.nbr.next_hop, mipip_mk_complete_walk, &ctx);
+}
+
 static u8 *
 format_ipip_tunnel_name (u8 * s, va_list * args)
 {
@@ -350,10 +430,19 @@ VNET_HW_INTERFACE_CLASS(ipip_hw_interface_class) = {
     .update_adjacency = ipip_update_adj,
     .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
 };
+
+VNET_HW_INTERFACE_CLASS(mipip_hw_interface_class) = {
+    .name = "mIPIP",
+    //.format_header = format_ipip_header_with_length,
+    //.unformat_header = unformat_ipip_header,
+    .build_rewrite = ipip_build_rewrite,
+    .update_adjacency = mipip_update_adj,
+    .flags = VNET_HW_INTERFACE_CLASS_FLAG_NBMA,
+};
 /* *INDENT-ON* */
 
 ipip_tunnel_t *
-ipip_tunnel_db_find (ipip_tunnel_key_t * key)
+ipip_tunnel_db_find (const ipip_tunnel_key_t * key)
 {
   ipip_main_t *gm = &ipip_main;
   uword *p;
@@ -377,30 +466,155 @@ ipip_tunnel_db_find_by_sw_if_index (u32 sw_if_index)
 }
 
 void
-ipip_tunnel_db_add (ipip_tunnel_t * t, ipip_tunnel_key_t * key)
+ipip_tunnel_db_add (ipip_tunnel_t * t, const ipip_tunnel_key_t * key)
 {
   ipip_main_t *gm = &ipip_main;
 
-  t->key = clib_mem_alloc (sizeof (*t->key));
-  clib_memcpy (t->key, key, sizeof (*key));
-  hash_set_mem (gm->tunnel_by_key, t->key, t->dev_instance);
+  hash_set_mem_alloc (&gm->tunnel_by_key, key, t->dev_instance);
 }
 
 void
-ipip_tunnel_db_remove (ipip_tunnel_t * t)
+ipip_tunnel_db_remove (ipip_tunnel_t * t, const ipip_tunnel_key_t * key)
 {
   ipip_main_t *gm = &ipip_main;
 
-  hash_unset_mem (gm->tunnel_by_key, t->key);
-  clib_mem_free (t->key);
-  t->key = NULL;
+  hash_unset_mem_free (&gm->tunnel_by_key, key);
+}
+
+void
+ipip_mk_key_i (ipip_transport_t transport,
+              ipip_mode_t mode,
+              const ip46_address_t * src,
+              const ip46_address_t * dst,
+              u32 fib_index, ipip_tunnel_key_t * key)
+{
+  key->transport = transport;
+  key->mode = mode;
+  key->src = *src;
+  key->dst = *dst;
+  key->fib_index = fib_index;
+  key->__pad = 0;;
+}
+
+void
+ipip_mk_key (const ipip_tunnel_t * t, ipip_tunnel_key_t * key)
+{
+  ipip_mk_key_i (t->transport, t->mode,
+                &t->tunnel_src, &t->tunnel_dst, t->fib_index, key);
+}
+
+static void
+ipip_nhrp_mk_key (const ipip_tunnel_t * t,
+                 const nhrp_entry_t * ne, ipip_tunnel_key_t * key)
+{
+  const fib_prefix_t *nh;
+
+  nh = nhrp_entry_get_nh (ne);
+
+  /* construct the key using mode P2P so it can be found in the DP */
+  ipip_mk_key_i (t->transport, IPIP_MODE_P2P,
+                &t->tunnel_src, &nh->fp_addr,
+                nhrp_entry_get_fib_index (ne), key);
+}
+
+static void
+ipip_nhrp_entry_added (const nhrp_entry_t * ne)
+{
+  ipip_main_t *gm = &ipip_main;
+  const ip46_address_t *nh;
+  ipip_tunnel_key_t key;
+  ipip_tunnel_t *t;
+  u32 sw_if_index;
+  u32 t_idx;
+
+  sw_if_index = nhrp_entry_get_sw_if_index (ne);
+  if (vec_len (gm->tunnel_index_by_sw_if_index) < sw_if_index)
+    return;
+
+  t_idx = gm->tunnel_index_by_sw_if_index[sw_if_index];
+
+  if (INDEX_INVALID == t_idx)
+    return;
+
+  t = pool_elt_at_index (gm->tunnels, t_idx);
+
+  ipip_nhrp_mk_key (t, ne, &key);
+  ipip_tunnel_db_add (t, &key);
+
+  // update the rewrites for each of the adjacencies for this next-hop
+  mipip_walk_ctx_t ctx = {
+    .t = t,
+    .ne = ne
+  };
+  nh = nhrp_entry_get_peer (ne);
+  adj_nbr_walk_nh (nhrp_entry_get_sw_if_index (ne),
+                  (ip46_address_is_ip4 (nh) ?
+                   FIB_PROTOCOL_IP4 :
+                   FIB_PROTOCOL_IP6), nh, mipip_mk_complete_walk, &ctx);
+}
+
+static void
+ipip_nhrp_entry_deleted (const nhrp_entry_t * ne)
+{
+  ipip_main_t *gm = &ipip_main;
+  const ip46_address_t *nh;
+  ipip_tunnel_key_t key;
+  ipip_tunnel_t *t;
+  u32 sw_if_index;
+  u32 t_idx;
+
+  sw_if_index = nhrp_entry_get_sw_if_index (ne);
+  if (vec_len (gm->tunnel_index_by_sw_if_index) < sw_if_index)
+    return;
+
+  t_idx = gm->tunnel_index_by_sw_if_index[sw_if_index];
+
+  if (INDEX_INVALID == t_idx)
+    return;
+
+  t = pool_elt_at_index (gm->tunnels, t_idx);
+
+  ipip_nhrp_mk_key (t, ne, &key);
+  ipip_tunnel_db_remove (t, &key);
+
+  nh = nhrp_entry_get_peer (ne);
+
+  /* make all the adjacencies incomplete */
+  adj_nbr_walk_nh (nhrp_entry_get_sw_if_index (ne),
+                  (ip46_address_is_ip4 (nh) ?
+                   FIB_PROTOCOL_IP4 :
+                   FIB_PROTOCOL_IP6), nh, mipip_mk_incomplete_walk, t);
+}
+
+static walk_rc_t
+ipip_tunnel_delete_nhrp_walk (index_t nei, void *ctx)
+{
+  ipip_tunnel_t *t = ctx;
+  ipip_tunnel_key_t key;
+
+  ipip_nhrp_mk_key (t, nhrp_entry_get (nei), &key);
+  ipip_tunnel_db_remove (t, &key);
+
+  return (WALK_CONTINUE);
+}
+
+static walk_rc_t
+ipip_tunnel_add_nhrp_walk (index_t nei, void *ctx)
+{
+  ipip_tunnel_t *t = ctx;
+  ipip_tunnel_key_t key;
+
+  ipip_nhrp_mk_key (t, nhrp_entry_get (nei), &key);
+  ipip_tunnel_db_add (t, &key);
+
+  return (WALK_CONTINUE);
 }
 
 int
 ipip_add_tunnel (ipip_transport_t transport,
                 u32 instance, ip46_address_t * src, ip46_address_t * dst,
                 u32 fib_index, tunnel_encap_decap_flags_t flags,
-                ip_dscp_t dscp, u32 * sw_if_indexp)
+                ip_dscp_t dscp, tunnel_mode_t tmode, u32 * sw_if_indexp)
 {
   ipip_main_t *gm = &ipip_main;
   vnet_main_t *vnm = gm->vnet_main;
@@ -409,11 +623,15 @@ ipip_add_tunnel (ipip_transport_t transport,
   ipip_tunnel_t *t;
   vnet_hw_interface_t *hi;
   u32 hw_if_index, sw_if_index;
-  ipip_tunnel_key_t key = {.transport = transport,
-    .fib_index = fib_index,
-    .src = *src,
-    .dst = *dst
-  };
+  ipip_tunnel_key_t key;
+  ipip_mode_t mode;
+
+  if (tmode == TUNNEL_MODE_MP && !ip46_address_is_zero (dst))
+    return (VNET_API_ERROR_INVALID_DST_ADDRESS);
+
+  mode = (tmode == TUNNEL_MODE_P2P ? IPIP_MODE_P2P : IPIP_MODE_P2MP);
+  ipip_mk_key_i (transport, mode, src, dst, fib_index, &key);
+
   t = ipip_tunnel_db_find (&key);
   if (t)
     {
@@ -441,12 +659,15 @@ ipip_add_tunnel (ipip_transport_t transport,
   t->user_instance = u_idx;    /* name */
 
   hw_if_index = vnet_register_interface (vnm, ipip_device_class.index, t_idx,
-                                        ipip_hw_interface_class.index,
+                                        (mode == IPIP_MODE_P2P ?
+                                         ipip_hw_interface_class.index :
+                                         mipip_hw_interface_class.index),
                                         t_idx);
 
   hi = vnet_get_hw_interface (vnm, hw_if_index);
   sw_if_index = hi->sw_if_index;
 
+  t->mode = mode;
   t->hw_if_index = hw_if_index;
   t->fib_index = fib_index;
   t->sw_if_index = sw_if_index;
@@ -476,6 +697,9 @@ ipip_add_tunnel (ipip_transport_t transport,
 
   ipip_tunnel_db_add (t, &key);
 
+  if (t->mode == IPIP_MODE_P2MP)
+    nhrp_walk_itf (t->sw_if_index, ipip_tunnel_add_nhrp_walk, t);
+
   if (sw_if_indexp)
     *sw_if_indexp = sw_if_index;
 
@@ -500,22 +724,32 @@ ipip_del_tunnel (u32 sw_if_index)
   ipip_main_t *gm = &ipip_main;
   vnet_main_t *vnm = gm->vnet_main;
   ipip_tunnel_t *t;
-
+  ipip_tunnel_key_t key;
 
   t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
   if (t == NULL)
     return VNET_API_ERROR_NO_SUCH_ENTRY;
 
+  if (t->mode == IPIP_MODE_P2MP)
+    nhrp_walk_itf (t->sw_if_index, ipip_tunnel_delete_nhrp_walk, t);
+
   vnet_sw_interface_set_flags (vnm, sw_if_index, 0 /* down */ );
   gm->tunnel_index_by_sw_if_index[sw_if_index] = ~0;
   vnet_delete_hw_interface (vnm, t->hw_if_index);
   hash_unset (gm->instance_used, t->user_instance);
-  ipip_tunnel_db_remove (t);
+
+  ipip_mk_key (t, &key);
+  ipip_tunnel_db_remove (t, &key);
   pool_put (gm->tunnels, t);
 
   return 0;
 }
 
+const static nhrp_vft_t ipip_nhrp_vft = {
+  .nv_added = ipip_nhrp_entry_added,
+  .nv_deleted = ipip_nhrp_entry_deleted,
+};
+
 static clib_error_t *
 ipip_init (vlib_main_t * vm)
 {
@@ -527,6 +761,8 @@ ipip_init (vlib_main_t * vm)
   gm->tunnel_by_key =
     hash_create_mem (0, sizeof (ipip_tunnel_key_t), sizeof (uword));
 
+  nhrp_register (&ipip_nhrp_vft);
+
   return 0;
 }
 
index a3732f7..fef5aab 100644 (file)
@@ -48,21 +48,26 @@ typedef enum
 {
   IPIP_TRANSPORT_IP4,
   IPIP_TRANSPORT_IP6,
-} ipip_transport_t;
+} __clib_packed ipip_transport_t;
+
+typedef enum
+{
+  IPIP_MODE_P2P = 0,
+  IPIP_MODE_P2MP,
+  IPIP_MODE_6RD,
+} __clib_packed ipip_mode_t;
 
 typedef struct
 {
   ip46_address_t src;
   ip46_address_t dst;
-  ipip_transport_t transport;
   u32 fib_index;
-} __attribute__ ((packed)) ipip_tunnel_key_t;
+  ipip_transport_t transport;
+  ipip_mode_t mode;
+  u16 __pad;
+} __clib_packed ipip_tunnel_key_t;
 
-typedef enum
-{
-  IPIP_MODE_P2P = 0,
-  IPIP_MODE_6RD,
-} ipip_mode_t;
+STATIC_ASSERT_SIZEOF (ipip_tunnel_key_t, 5 * sizeof (u64));
 
 /**
  * @brief A representation of a IPIP tunnel
@@ -74,7 +79,6 @@ typedef struct
 
   ipip_mode_t mode;
   ipip_transport_t transport;
-  ipip_tunnel_key_t *key;
   ip46_address_t tunnel_src;
   ip46_address_t tunnel_dst;
   u32 fib_index;
@@ -145,7 +149,7 @@ sixrd_get_addr_net (const ipip_tunnel_t * t, u64 dal)
 int ipip_add_tunnel (ipip_transport_t transport, u32 instance,
                     ip46_address_t * src, ip46_address_t * dst,
                     u32 fib_index, tunnel_encap_decap_flags_t flags,
-                    ip_dscp_t dscp, u32 * sw_if_indexp);
+                    ip_dscp_t dscp, tunnel_mode_t mode, u32 * sw_if_indexp);
 int ipip_del_tunnel (u32 sw_if_index);
 int sixrd_add_tunnel (ip6_address_t * ip6_prefix, u8 ip6_prefix_len,
                      ip4_address_t * ip4_prefix, u8 ip4_prefix_len,
@@ -153,10 +157,16 @@ int sixrd_add_tunnel (ip6_address_t * ip6_prefix, u8 ip6_prefix_len,
                      u32 ip4_fib_index, u32 ip6_fib_index,
                      u32 * sw_if_index);
 int sixrd_del_tunnel (u32 sw_if_index);
-void ipip_tunnel_db_add (ipip_tunnel_t * t, ipip_tunnel_key_t * key);
-void ipip_tunnel_db_remove (ipip_tunnel_t * t);
-ipip_tunnel_t *ipip_tunnel_db_find (ipip_tunnel_key_t * key);
+void ipip_tunnel_db_add (ipip_tunnel_t * t, const ipip_tunnel_key_t * key);
+void ipip_tunnel_db_remove (ipip_tunnel_t * t, const ipip_tunnel_key_t * key);
+ipip_tunnel_t *ipip_tunnel_db_find (const ipip_tunnel_key_t * key);
 ipip_tunnel_t *ipip_tunnel_db_find_by_sw_if_index (u32 sw_if_index);
+void ipip_mk_key (const ipip_tunnel_t * t, ipip_tunnel_key_t * key);
+void ipip_mk_key_i (ipip_transport_t transport,
+                   ipip_mode_t mode,
+                   const ip46_address_t * src,
+                   const ip46_address_t * dst,
+                   u32 fib_index, ipip_tunnel_key_t * key);
 
 #endif
 
index 4f6aa7f..97fff15 100644 (file)
@@ -40,6 +40,7 @@ vl_api_ipip_add_tunnel_t_handler (vl_api_ipip_add_tunnel_t * mp)
   tunnel_encap_decap_flags_t flags;
   ip46_address_t src, dst;
   ip46_type_t itype[2];
+  tunnel_mode_t mode;
 
   itype[0] = ip_address_decode (&mp->tunnel.src, &src);
   itype[1] = ip_address_decode (&mp->tunnel.dst, &dst);
@@ -58,6 +59,11 @@ vl_api_ipip_add_tunnel_t_handler (vl_api_ipip_add_tunnel_t * mp)
 
   rv = tunnel_encap_decap_flags_decode (mp->tunnel.flags, &flags);
 
+  if (rv)
+    goto out;
+
+  rv = tunnel_mode_decode (mp->tunnel.mode, &mode);
+
   if (rv)
     goto out;
 
@@ -75,7 +81,8 @@ vl_api_ipip_add_tunnel_t_handler (vl_api_ipip_add_tunnel_t * mp)
                             IPIP_TRANSPORT_IP4),
                            ntohl (mp->tunnel.instance), &src, &dst,
                            fib_index, flags,
-                           ip_dscp_decode (mp->tunnel.dscp), &sw_if_index);
+                           ip_dscp_decode (mp->tunnel.dscp), mode,
+                           &sw_if_index);
     }
 
 out:
index 09f2eba..d341055 100644 (file)
@@ -31,6 +31,7 @@ static clib_error_t *create_ipip_tunnel_command_fn(vlib_main_t *vm,
   u32 sw_if_index;
   clib_error_t *error = NULL;
   bool ip4_set = false, ip6_set = false;
+  tunnel_mode_t mode = TUNNEL_MODE_P2P;
 
   /* Get a line of input. */
   if (!unformat_user(input, unformat_line_input, line_input))
@@ -51,6 +52,8 @@ static clib_error_t *create_ipip_tunnel_command_fn(vlib_main_t *vm,
     } else if (unformat(line_input, "dst %U", unformat_ip6_address, &dst.ip6)) {
       num_m_args++;
       ip6_set = true;
+    } else if (unformat(line_input, "%U", unformat_tunnel_mode, &mode)) {
+      num_m_args++;
     } else if (unformat(line_input, "outer-table-id %d", &table_id))
       ;
     else {
@@ -84,6 +87,7 @@ static clib_error_t *create_ipip_tunnel_command_fn(vlib_main_t *vm,
                            fib_index,
                            TUNNEL_ENCAP_DECAP_FLAG_NONE,
                            IP_DSCP_CS0,
+                           mode,
                            &sw_if_index);
     }
 
@@ -104,6 +108,9 @@ static clib_error_t *create_ipip_tunnel_command_fn(vlib_main_t *vm,
   case VNET_API_ERROR_INSTANCE_IN_USE:
     error = clib_error_return(0, "Instance is in use");
     goto done;
+  case VNET_API_ERROR_INVALID_DST_ADDRESS:
+    error = clib_error_return(0, "destination IP address when mode is multi-point");
+    goto done;
   default:
     error = clib_error_return(0, "vnet_ipip_add_del_tunnel returned %d", rv);
     goto done;
@@ -182,12 +189,16 @@ static u8 *format_ipip_tunnel(u8 *s, va_list *args) {
               format_ip6_address, &t->sixrd.ip6_prefix, t->sixrd.ip6_prefix_len);
     break;
   case IPIP_MODE_P2P:
-  default:
     s = format(s, "[%d] instance %d src %U dst %U ",
               t->dev_instance, t->user_instance,
               format_ip46_address, &t->tunnel_src, type,
               format_ip46_address, &t->tunnel_dst, type);
     break;
+  case IPIP_MODE_P2MP:
+    s = format(s, "[%d] instance %d p2mp src %U ",
+              t->dev_instance, t->user_instance,
+              format_ip46_address, &t->tunnel_src, type);
+    break;
   }
 
   s = format(s, "table-ID %d sw-if-idx %d flags [%U] dscp %U",
@@ -235,6 +246,50 @@ VLIB_CLI_COMMAND(show_ipip_tunnel_command, static) = {
 };
 /* *INDENT-ON* */
 
+static u8 *
+format_ipip_tunnel_key (u8 *s, va_list *args)
+{
+  ipip_tunnel_key_t *t = va_arg(*args, ipip_tunnel_key_t *);
+
+  s = format (s, "src:%U dst:%U fib:%d transport:%d mode:%d",
+              format_ip46_address, &t->src, IP46_TYPE_ANY,
+              format_ip46_address, &t->dst, IP46_TYPE_ANY,
+              t->fib_index, t->transport, t->mode);
+
+  return (s);
+}
+
+static clib_error_t *
+ipip_tunnel_hash_show (vlib_main_t * vm,
+                       unformat_input_t * input,
+                       vlib_cli_command_t * cmd)
+{
+  ipip_main_t *im = &ipip_main;
+  ipip_tunnel_key_t *key;
+  u32 index;
+
+  /* *INDENT-OFF* */
+  hash_foreach(key, index, im->tunnel_by_key,
+  ({
+      vlib_cli_output (vm, " %U -> %d", format_ipip_tunnel_key, key, index);
+  }));
+  /* *INDENT-ON* */
+
+  return NULL;
+}
+
+/**
+ * show IPSEC tunnel protection hash tables
+ */
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (ipip_tunnel_hash_show_node, static) =
+{
+  .path = "show ipip tunnel-hash",
+  .function = ipip_tunnel_hash_show,
+  .short_help =  "show ipip tunnel-hash",
+};
+/* *INDENT-ON* */
+
 static clib_error_t *create_sixrd_tunnel_command_fn(vlib_main_t *vm,
                                                     unformat_input_t *input,
                                                     vlib_cli_command_t *cmd) {
index bc0250a..0f47f26 100644 (file)
@@ -83,9 +83,6 @@ ipip_input (vlib_main_t * vm, vlib_node_runtime_t * node,
          ip4_header_t *ip40;
          ip6_header_t *ip60;
          u32 next0 = IPIP_INPUT_NEXT_DROP;
-         ip46_address_t src0 = ip46_address_initializer, dst0 =
-           ip46_address_initializer;
-         ipip_transport_t transport0;
          u8 inner_protocol0;
 
          bi0 = to_next[0] = from[0];
@@ -96,6 +93,11 @@ ipip_input (vlib_main_t * vm, vlib_node_runtime_t * node,
 
          b0 = vlib_get_buffer (vm, bi0);
 
+         ipip_tunnel_key_t key0 = {
+           .fib_index = vnet_buffer (b0)->ip.fib_index,
+           .mode = IPIP_MODE_P2P,
+         };
+
          if (is_ipv6)
            {
              ip60 = vlib_buffer_get_current (b0);
@@ -108,10 +110,10 @@ ipip_input (vlib_main_t * vm, vlib_node_runtime_t * node,
                }
 
              vlib_buffer_advance (b0, sizeof (*ip60));
-             ip_set (&src0, &ip60->src_address, false);
-             ip_set (&dst0, &ip60->dst_address, false);
+             ip_set (&key0.dst, &ip60->src_address, false);
+             ip_set (&key0.src, &ip60->dst_address, false);
              inner_protocol0 = ip60->protocol;
-             transport0 = IPIP_TRANSPORT_IP6;
+             key0.transport = IPIP_TRANSPORT_IP6;
            }
          else
            {
@@ -125,25 +127,21 @@ ipip_input (vlib_main_t * vm, vlib_node_runtime_t * node,
                  goto drop;
                }
              vlib_buffer_advance (b0, sizeof (*ip40));
-             ip_set (&src0, &ip40->src_address, true);
-             ip_set (&dst0, &ip40->dst_address, true);
+             ip_set (&key0.dst, &ip40->src_address, true);
+             ip_set (&key0.src, &ip40->dst_address, true);
              inner_protocol0 = ip40->protocol;
-             transport0 = IPIP_TRANSPORT_IP4;
+             key0.transport = IPIP_TRANSPORT_IP4;
            }
 
          /*
           * Find tunnel. First a lookup for P2P tunnels, then a lookup
           * for multipoint tunnels
           */
-         ipip_tunnel_key_t key0 = {.transport = transport0,
-           .fib_index = vnet_buffer (b0)->ip.fib_index,
-           .src = dst0,
-           .dst = src0
-         };
          ipip_tunnel_t *t0 = ipip_tunnel_db_find (&key0);
          if (!t0)
            {
              ip46_address_reset (&key0.dst);
+             key0.mode = IPIP_MODE_6RD;
              t0 = ipip_tunnel_db_find (&key0);
              if (!t0)
                {
index 04df0ee..492b4f8 100644 (file)
@@ -283,12 +283,10 @@ sixrd_add_tunnel (ip6_address_t * ip6_prefix, u8 ip6_prefix_len,
   ip46_address_t src = ip46_address_initializer, dst =
     ip46_address_initializer;
   ip_set (&src, ip4_src, true);
-  ipip_tunnel_key_t key = {
-    .transport = IPIP_TRANSPORT_IP4,
-    .fib_index = ip4_fib_index,
-    .src = src,
-    .dst = dst
-  };
+  ipip_tunnel_key_t key;
+
+  ipip_mk_key_i (IPIP_TRANSPORT_IP4, IPIP_MODE_6RD, &src, &dst, ip4_fib_index,
+                &key);
 
   t = ipip_tunnel_db_find (&key);
   if (t)
@@ -377,6 +375,7 @@ sixrd_del_tunnel (u32 sw_if_index)
 {
   ipip_main_t *gm = &ipip_main;
   ipip_tunnel_t *t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
+  ipip_tunnel_key_t key;
 
   if (!t)
     {
@@ -408,7 +407,8 @@ sixrd_del_tunnel (u32 sw_if_index)
   gm->tunnel_index_by_sw_if_index[t->sw_if_index] = ~0;
 
   vnet_delete_hw_interface (vnet_get_main (), t->hw_if_index);
-  ipip_tunnel_db_remove (t);
+  ipip_mk_key (t, &key);
+  ipip_tunnel_db_remove (t, &key);
   pool_put (gm->tunnels, t);
 
   return 0;
index 87f5931..a80c604 100644 (file)
@@ -647,7 +647,7 @@ vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t *
                            &local_ip,
                            &remote_ip, fib_index,
                            TUNNEL_ENCAP_DECAP_FLAG_NONE, IP_DSCP_CS0,
-                           &sw_if_index);
+                           TUNNEL_MODE_P2P, &sw_if_index);
 
       if (rv)
        goto done;
index f04ccc8..b054155 100644 (file)
@@ -843,7 +843,7 @@ create_ipsec_tunnel_command_fn (vlib_main_t * vm,
        ipip_add_tunnel (ipv6_set ? IPIP_TRANSPORT_IP6 : IPIP_TRANSPORT_IP4,
                         instance, &local_ip, &remote_ip, fib_index,
                         TUNNEL_ENCAP_DECAP_FLAG_NONE, IP_DSCP_CS0,
-                        &sw_if_index);
+                        TUNNEL_MODE_P2P, &sw_if_index);
       rv |=
        ipsec_sa_add_and_lock (ipsec_tun_mk_local_sa_id (sw_if_index),
                               local_spi, IPSEC_PROTOCOL_ESP, crypto_alg,
index e97fbe0..11d2c2b 100644 (file)
@@ -76,22 +76,6 @@ nhrp_entry_adj_stack (const nhrp_entry_t * ne, adj_index_t ai)
   adj_midchain_delegate_stack (ai, ne->ne_fib_index, &ne->ne_nh);
 }
 
-static adj_walk_rc_t
-nhrp_entry_add_adj_walk (adj_index_t ai, void *ctx)
-{
-  nhrp_entry_adj_stack (ctx, ai);
-
-  return (ADJ_WALK_RC_CONTINUE);
-}
-
-static adj_walk_rc_t
-nhrp_entry_del_adj_walk (adj_index_t ai, void *ctx)
-{
-  adj_midchain_delegate_unstack (ai);
-
-  return (ADJ_WALK_RC_CONTINUE);
-}
-
 nhrp_entry_t *
 nhrp_entry_get (index_t nei)
 {
@@ -157,10 +141,6 @@ nhrp_entry_add (u32 sw_if_index,
 
       hash_set_mem (nhrp_db, ne->ne_key, nei);
 
-      adj_nbr_walk_nh (sw_if_index,
-                      ne->ne_nh.fp_proto,
-                      &ne->ne_key->nk_peer, nhrp_entry_add_adj_walk, ne);
-
       NHRP_NOTIFY (ne, nv_added);
     }
   else
@@ -180,10 +160,6 @@ nhrp_entry_del (u32 sw_if_index, const ip46_address_t * peer)
     {
       hash_unset_mem (nhrp_db, ne->ne_key);
 
-      adj_nbr_walk_nh (sw_if_index,
-                      ne->ne_nh.fp_proto,
-                      &ne->ne_key->nk_peer, nhrp_entry_del_adj_walk, ne);
-
       NHRP_NOTIFY (ne, nv_deleted);
 
       clib_mem_free (ne->ne_key);
index 83b1046..96d7fd1 100644 (file)
@@ -34,6 +34,20 @@ format_tunnel_mode (u8 * s, va_list * args)
   return (s);
 }
 
+uword
+unformat_tunnel_mode (unformat_input_t * input, va_list * args)
+{
+  tunnel_mode_t *m = va_arg (*args, tunnel_mode_t *);
+
+  if (unformat (input, "p2p"))
+    *m = TUNNEL_MODE_P2P;
+  else if (unformat (input, "p2mp") || unformat (input, "mp"))
+    *m = TUNNEL_MODE_MP;
+  else
+    return 0;
+  return 1;
+}
+
 u8 *
 format_tunnel_encap_decap_flags (u8 * s, va_list * args)
 {
index e3390f5..f23a3d4 100644 (file)
@@ -20,7 +20,7 @@
 
 #include <vlib/vlib.h>
 
-#define foreach_tunnel_mode \
+#define foreach_tunnel_mode     \
   _(P2P, "point-to-point")      \
   _(MP, "multi-point")          \
 
@@ -32,11 +32,12 @@ typedef enum tunnel_mode_t_
 } __clib_packed tunnel_mode_t;
 
 extern u8 *format_tunnel_mode (u8 * s, va_list * args);
+extern uword unformat_tunnel_mode (unformat_input_t * input, va_list * args);
 
 /**
  * Keep these idenitical to those in ipip.api
  */
-#define forech_tunnel_encap_decap_flag                     \
+#define forech_tunnel_encap_decap_flag              \
   _(NONE, "none", 0x0)                              \
   _(ENCAP_COPY_DF, "encap-copy-df", 0x1)            \
   _(ENCAP_SET_DF, "encap-set-df", 0x2)              \
index 103948d..9835489 100644 (file)
@@ -38,7 +38,7 @@ enum tunnel_encap_decap_flags : u8
 enum tunnel_mode : u8
 {
   /** point-to-point */
-  TUNNEL_API_MODE_P2P,
+  TUNNEL_API_MODE_P2P = 0,
   /** multi-point */
   TUNNEL_API_MODE_MP,
 };
index f8c4100..e3e21c0 100644 (file)
@@ -1066,7 +1066,7 @@ class TestGRE(VppTestCase):
                 rx = self.send_and_expect(self.pg0, tx_e, itf)
                 self.verify_tunneled_4o4(self.pg0, rx, tx_e,
                                          itf.local_ip4,
-                                         gre_if._remote_hosts[ii].ip4)
+                                         itf._remote_hosts[ii].ip4)
 
                 tx_i = self.create_tunnel_stream_4o4(self.pg0,
                                                      itf._remote_hosts[ii].ip4,
@@ -1087,7 +1087,7 @@ class TestGRE(VppTestCase):
                 rx = self.send_and_expect(self.pg0, tx_e, itf)
                 self.verify_tunneled_4o4(self.pg0, rx, tx_e,
                                          itf.local_ip4,
-                                         gre_if._remote_hosts[ii].ip4)
+                                         itf._remote_hosts[ii].ip4)
                 rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
                 self.verify_decapped_4o4(self.pg0, rx, tx_i)
 
@@ -1130,6 +1130,14 @@ class TestGRE(VppTestCase):
             for ii in range(1, 4):
                 route_addr = "4::%d" % ii
 
+                #
+                # Add a NHRP entry resolves the peer
+                #
+                nhrp = VppNhrp(self, gre_if,
+                               gre_if._remote_hosts[ii].ip6,
+                               itf._remote_hosts[ii].ip6)
+                nhrp.add_vpp_config()
+
                 #
                 # route traffic via the peer
                 #
@@ -1139,14 +1147,6 @@ class TestGRE(VppTestCase):
                                   gre_if.sw_if_index)])
                 route_via_tun.add_vpp_config()
 
-                #
-                # Add a NHRP entry resolves the peer
-                #
-                nhrp = VppNhrp(self, gre_if,
-                               gre_if._remote_hosts[ii].ip6,
-                               itf._remote_hosts[ii].ip6)
-                nhrp.add_vpp_config()
-
                 #
                 # Send a packet stream that is routed into the tunnel
                 #  - packets are GRE encapped
@@ -1155,7 +1155,7 @@ class TestGRE(VppTestCase):
                 rx = self.send_and_expect(self.pg0, tx_e, itf)
                 self.verify_tunneled_6o6(self.pg0, rx, tx_e,
                                          itf.local_ip6,
-                                         gre_if._remote_hosts[ii].ip6)
+                                         itf._remote_hosts[ii].ip6)
                 tx_i = self.create_tunnel_stream_6o6(self.pg0,
                                                      itf._remote_hosts[ii].ip6,
                                                      itf.local_ip6,
@@ -1174,7 +1174,7 @@ class TestGRE(VppTestCase):
                 rx = self.send_and_expect(self.pg0, tx_e, itf)
                 self.verify_tunneled_6o6(self.pg0, rx, tx_e,
                                          itf.local_ip6,
-                                         gre_if._remote_hosts[ii].ip6)
+                                         itf._remote_hosts[ii].ip6)
                 rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
                 self.verify_decapped_6o6(self.pg0, rx, tx_i)
 
index 869dbaa..511164f 100644 (file)
@@ -8,6 +8,7 @@ from framework import VppTestCase, VppTestRunner
 from vpp_ip import DpoProto
 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, FibPathProto
 from vpp_ipip_tun_interface import VppIpIpTunInterface
+from vpp_nhrp import VppNhrp
 from vpp_papi import VppEnum
 from socket import AF_INET, AF_INET6, inet_pton
 from util import reassemble4
@@ -471,6 +472,116 @@ class TestIPIP(VppTestCase):
     def payload(self, len):
         return 'x' * len
 
+    def test_mipip4(self):
+        """ p2mp IPv4 tunnel Tests """
+
+        for itf in self.pg_interfaces:
+            #
+            # one underlay nh for each overlay/tunnel peer
+            #
+            itf.generate_remote_hosts(4)
+            itf.configure_ipv4_neighbors()
+
+            #
+            # Create an p2mo IPIP tunnel.
+            #  - set it admin up
+            #  - assign an IP Addres
+            #  - Add a route via the tunnel
+            #
+            ipip_if = VppIpIpTunInterface(self, itf,
+                                          itf.local_ip4,
+                                          "0.0.0.0",
+                                          mode=(VppEnum.vl_api_tunnel_mode_t.
+                                                TUNNEL_API_MODE_MP))
+            ipip_if.add_vpp_config()
+            ipip_if.admin_up()
+            ipip_if.config_ip4()
+            ipip_if.generate_remote_hosts(4)
+
+            self.logger.info(self.vapi.cli("sh adj"))
+            self.logger.info(self.vapi.cli("sh ip fib"))
+
+            #
+            # ensure we don't match to the tunnel if the source address
+            # is all zeros
+            #
+            # tx = self.create_tunnel_stream_4o4(self.pg0,
+            #                                    "0.0.0.0",
+            #                                    itf.local_ip4,
+            #                                    self.pg0.local_ip4,
+            #                                    self.pg0.remote_ip4)
+            # self.send_and_assert_no_replies(self.pg0, tx)
+
+            #
+            # for-each peer
+            #
+            for ii in range(1, 4):
+                route_addr = "4.4.4.%d" % ii
+
+                #
+                # route traffic via the peer
+                #
+                route_via_tun = VppIpRoute(
+                    self, route_addr, 32,
+                    [VppRoutePath(ipip_if._remote_hosts[ii].ip4,
+                                  ipip_if.sw_if_index)])
+                route_via_tun.add_vpp_config()
+
+                #
+                # Add a NHRP entry resolves the peer
+                #
+                nhrp = VppNhrp(self, ipip_if,
+                               ipip_if._remote_hosts[ii].ip4,
+                               itf._remote_hosts[ii].ip4)
+                nhrp.add_vpp_config()
+                self.logger.info(self.vapi.cli("sh adj nbr ipip0 %s" %
+                                               ipip_if._remote_hosts[ii].ip4))
+
+                #
+                # Send a packet stream that is routed into the tunnel
+                #  - packets are IPIP encapped
+                #
+                inner = (IP(dst=route_addr, src="5.5.5.5") /
+                         UDP(sport=1234, dport=1234) /
+                         Raw(b'0x44' * 100))
+                tx_e = [(Ether(dst=self.pg0.local_mac,
+                               src=self.pg0.remote_mac) /
+                         inner) for x in range(63)]
+
+                rxs = self.send_and_expect(self.pg0, tx_e, itf)
+
+                for rx in rxs:
+                    self.assertEqual(rx[IP].src, itf.local_ip4)
+                    self.assertEqual(rx[IP].dst, itf._remote_hosts[ii].ip4)
+
+                tx_i = [(Ether(dst=self.pg0.local_mac,
+                               src=self.pg0.remote_mac) /
+                         IP(src=itf._remote_hosts[ii].ip4,
+                            dst=itf.local_ip4) /
+                         IP(src=self.pg0.local_ip4, dst=self.pg0.remote_ip4) /
+                         UDP(sport=1234, dport=1234) /
+                         Raw(b'0x44' * 100)) for x in range(63)]
+
+                self.logger.info(self.vapi.cli("sh ipip tunnel-hash"))
+                rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
+
+                #
+                # delete and re-add the NHRP
+                #
+                nhrp.remove_vpp_config()
+                self.send_and_assert_no_replies(self.pg0, tx_e)
+                self.send_and_assert_no_replies(self.pg0, tx_i)
+
+                nhrp.add_vpp_config()
+                rx = self.send_and_expect(self.pg0, tx_e, itf)
+                for rx in rxs:
+                    self.assertEqual(rx[IP].src, itf.local_ip4)
+                    self.assertEqual(rx[IP].dst, itf._remote_hosts[ii].ip4)
+                rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
+
+            ipip_if.admin_down()
+            ipip_if.unconfig_ip4()
+
 
 class TestIPIP6(VppTestCase):
     """ IPIP6 Test Case """
index ea5cfa1..67cc1b5 100644 (file)
@@ -1,5 +1,6 @@
 from vpp_tunnel_interface import VppTunnelInterface
 from ipaddress import ip_address
+from vpp_papi import VppEnum
 
 
 class VppIpIpTunInterface(VppTunnelInterface):
@@ -9,13 +10,17 @@ class VppIpIpTunInterface(VppTunnelInterface):
 
     def __init__(self, test, parent_if, src, dst,
                  table_id=0, dscp=0x0,
-                 flags=0):
+                 flags=0, mode=None):
         super(VppIpIpTunInterface, self).__init__(test, parent_if)
         self.src = src
         self.dst = dst
         self.table_id = table_id
         self.dscp = dscp
         self.flags = flags
+        self.mode = mode
+        if not self.mode:
+            self.mode = (VppEnum.vl_api_tunnel_mode_t.
+                         TUNNEL_API_MODE_P2P)
 
     def add_vpp_config(self):
         r = self.test.vapi.ipip_add_tunnel(
@@ -26,6 +31,7 @@ class VppIpIpTunInterface(VppTunnelInterface):
                 'flags': self.flags,
                 'dscp': self.dscp,
                 'instance': 0xffffffff,
+                'mode': self.mode,
             })
         self.set_sw_if_index(r.sw_if_index)
         self.test.registry.register(self, self.test.logger)