misc: Break the big IP header files to improve compile time

Type: refactor

Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
Change-Id: Id1801519638a9b97175847d7ed58824fb83433d6
diff --git a/src/vnet/ip/icmp6.h b/src/vnet/ip/icmp6.h
index 628d225..7a5eef5 100644
--- a/src/vnet/ip/icmp6.h
+++ b/src/vnet/ip/icmp6.h
@@ -15,6 +15,8 @@
 #ifndef included_vnet_icmp6_h
 #define included_vnet_icmp6_h
 
+#include <vnet/ip/icmp46_packet.h>
+
 #define foreach_icmp6_error                                             \
   _ (NONE, "valid packets")                                             \
   _ (UNKNOWN_TYPE, "unknown type")                                      \
diff --git a/src/vnet/ip/ip4.h b/src/vnet/ip/ip4.h
index cb78bfb..22de22f 100644
--- a/src/vnet/ip/ip4.h
+++ b/src/vnet/ip/ip4.h
@@ -41,12 +41,13 @@
 #define included_ip_ip4_h
 
 #include <vnet/ip/ip4_packet.h>
+#include <vnet/ip/ip_flow_hash.h>
+
 #include <vnet/ip/lookup.h>
 #include <vnet/ip/ip_interface.h>
 #include <vnet/buffer.h>
 #include <vnet/feature/feature.h>
 #include <vnet/ip/icmp46_packet.h>
-#include <vnet/util/throttle.h>
 
 typedef struct ip4_mfib_t
 {
@@ -163,10 +164,6 @@
 
     u8 pad[2];
   } host_config;
-
-  /** ARP throttling */
-  throttle_t arp_throttle;
-
 } ip4_main_t;
 
 #define ARP_THROTTLE_BITS	(512)
@@ -295,56 +292,6 @@
 
 void ip4_punt_redirect_del (u32 rx_sw_if_index);
 
-/* Compute flow hash.  We'll use it to select which adjacency to use for this
-   flow.  And other things. */
-always_inline u32
-ip4_compute_flow_hash (const ip4_header_t * ip,
-		       flow_hash_config_t flow_hash_config)
-{
-  tcp_header_t *tcp = (void *) (ip + 1);
-  u32 a, b, c, t1, t2;
-  uword is_tcp_udp = (ip->protocol == IP_PROTOCOL_TCP
-		      || ip->protocol == IP_PROTOCOL_UDP);
-
-  t1 = (flow_hash_config & IP_FLOW_HASH_SRC_ADDR)
-    ? ip->src_address.data_u32 : 0;
-  t2 = (flow_hash_config & IP_FLOW_HASH_DST_ADDR)
-    ? ip->dst_address.data_u32 : 0;
-
-  a = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ? t2 : t1;
-  b = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ? t1 : t2;
-
-  t1 = is_tcp_udp ? tcp->src : 0;
-  t2 = is_tcp_udp ? tcp->dst : 0;
-
-  t1 = (flow_hash_config & IP_FLOW_HASH_SRC_PORT) ? t1 : 0;
-  t2 = (flow_hash_config & IP_FLOW_HASH_DST_PORT) ? t2 : 0;
-
-  if (flow_hash_config & IP_FLOW_HASH_SYMMETRIC)
-    {
-      if (b < a)
-	{
-	  c = a;
-	  a = b;
-	  b = c;
-	}
-      if (t2 < t1)
-	{
-	  t2 += t1;
-	  t1 = t2 - t1;
-	  t2 = t2 - t1;
-	}
-    }
-
-  b ^= (flow_hash_config & IP_FLOW_HASH_PROTO) ? ip->protocol : 0;
-  c = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ?
-    (t1 << 16) | t2 : (t2 << 16) | t1;
-
-  hash_v3_mix32 (a, b, c);
-  hash_v3_finalize32 (a, b, c);
-
-  return c;
-}
 
 void
 ip4_forward_next_trace (vlib_main_t * vm,
@@ -356,66 +303,6 @@
 
 u32 ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0);
 
-#define IP_DF 0x4000		/* don't fragment */
-
-always_inline void *
-vlib_buffer_push_ip4_custom (vlib_main_t * vm, vlib_buffer_t * b,
-			     ip4_address_t * src, ip4_address_t * dst,
-			     int proto, u8 csum_offload, u8 is_df)
-{
-  ip4_header_t *ih;
-
-  /* make some room */
-  ih = vlib_buffer_push_uninit (b, sizeof (ip4_header_t));
-
-  ih->ip_version_and_header_length = 0x45;
-  ih->tos = 0;
-  ih->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
-
-  /* No fragments */
-  ih->flags_and_fragment_offset = is_df ? clib_host_to_net_u16 (IP_DF) : 0;
-  ih->ttl = 255;
-  ih->protocol = proto;
-  ih->src_address.as_u32 = src->as_u32;
-  ih->dst_address.as_u32 = dst->as_u32;
-
-  vnet_buffer (b)->l3_hdr_offset = (u8 *) ih - b->data;
-  b->flags |= VNET_BUFFER_F_IS_IP4 | VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
-
-  /* Offload ip4 header checksum generation */
-  if (csum_offload)
-    {
-      ih->checksum = 0;
-      b->flags |= VNET_BUFFER_F_OFFLOAD_IP_CKSUM;
-    }
-  else
-    ih->checksum = ip4_header_checksum (ih);
-
-  return ih;
-}
-
-/**
- * Push IPv4 header to buffer
- *
- * This does not support fragmentation.
- *
- * @param vm - vlib_main
- * @param b - buffer to write the header to
- * @param src - source IP
- * @param dst - destination IP
- * @param prot - payload proto
- *
- * @return - pointer to start of IP header
- */
-always_inline void *
-vlib_buffer_push_ip4 (vlib_main_t * vm, vlib_buffer_t * b,
-		      ip4_address_t * src, ip4_address_t * dst, int proto,
-		      u8 csum_offload)
-{
-  return vlib_buffer_push_ip4_custom (vm, b, src, dst, proto, csum_offload,
-				      1 /* is_df */ );
-}
-
 always_inline u32
 vlib_buffer_get_ip4_fib_index (vlib_buffer_t * b)
 {
@@ -425,6 +312,7 @@
   return (fib_index == (u32) ~ 0) ?
     vec_elt (ip4_main.fib_index_by_sw_if_index, sw_if_index) : fib_index;
 }
+
 #endif /* included_ip_ip4_h */
 
 /*
diff --git a/src/vnet/ip/ip4_forward.h b/src/vnet/ip/ip4_forward.h
index 1750ac6..8779d2d 100644
--- a/src/vnet/ip/ip4_forward.h
+++ b/src/vnet/ip/ip4_forward.h
@@ -43,6 +43,7 @@
 #include <vppinfra/cache.h>
 #include <vnet/fib/ip4_fib.h>
 #include <vnet/dpo/load_balance_map.h>
+#include <vnet/ip/ip4_inlines.h>
 
 /**
  * @file
diff --git a/src/vnet/ip/ip4_inlines.h b/src/vnet/ip/ip4_inlines.h
new file mode 100644
index 0000000..bdb82af
--- /dev/null
+++ b/src/vnet/ip/ip4_inlines.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * ip/ip4.h: ip4 main include file
+ *
+ * Copyright (c) 2008 Eliot Dresselhaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef included_ip_ip4_inlines_h
+#define included_ip_ip4_inlines_h
+
+#include <vnet/ip/ip_flow_hash.h>
+#include <vnet/ip/ip4_packet.h>
+
+#define IP_DF 0x4000		/* don't fragment */
+
+/* Compute flow hash.  We'll use it to select which adjacency to use for this
+   flow.  And other things. */
+always_inline u32
+ip4_compute_flow_hash (const ip4_header_t * ip,
+		       flow_hash_config_t flow_hash_config)
+{
+  tcp_header_t *tcp = (void *) (ip + 1);
+  u32 a, b, c, t1, t2;
+  uword is_tcp_udp = (ip->protocol == IP_PROTOCOL_TCP
+		      || ip->protocol == IP_PROTOCOL_UDP);
+
+  t1 = (flow_hash_config & IP_FLOW_HASH_SRC_ADDR)
+    ? ip->src_address.data_u32 : 0;
+  t2 = (flow_hash_config & IP_FLOW_HASH_DST_ADDR)
+    ? ip->dst_address.data_u32 : 0;
+
+  a = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ? t2 : t1;
+  b = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ? t1 : t2;
+
+  t1 = is_tcp_udp ? tcp->src : 0;
+  t2 = is_tcp_udp ? tcp->dst : 0;
+
+  t1 = (flow_hash_config & IP_FLOW_HASH_SRC_PORT) ? t1 : 0;
+  t2 = (flow_hash_config & IP_FLOW_HASH_DST_PORT) ? t2 : 0;
+
+  if (flow_hash_config & IP_FLOW_HASH_SYMMETRIC)
+    {
+      if (b < a)
+	{
+	  c = a;
+	  a = b;
+	  b = c;
+	}
+      if (t2 < t1)
+	{
+	  t2 += t1;
+	  t1 = t2 - t1;
+	  t2 = t2 - t1;
+	}
+    }
+
+  b ^= (flow_hash_config & IP_FLOW_HASH_PROTO) ? ip->protocol : 0;
+  c = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ?
+    (t1 << 16) | t2 : (t2 << 16) | t1;
+
+  hash_v3_mix32 (a, b, c);
+  hash_v3_finalize32 (a, b, c);
+
+  return c;
+}
+
+always_inline void *
+vlib_buffer_push_ip4_custom (vlib_main_t * vm, vlib_buffer_t * b,
+			     ip4_address_t * src, ip4_address_t * dst,
+			     int proto, u8 csum_offload, u8 is_df)
+{
+  ip4_header_t *ih;
+
+  /* make some room */
+  ih = vlib_buffer_push_uninit (b, sizeof (ip4_header_t));
+
+  ih->ip_version_and_header_length = 0x45;
+  ih->tos = 0;
+  ih->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
+
+  /* No fragments */
+  ih->flags_and_fragment_offset = is_df ? clib_host_to_net_u16 (IP_DF) : 0;
+  ih->ttl = 255;
+  ih->protocol = proto;
+  ih->src_address.as_u32 = src->as_u32;
+  ih->dst_address.as_u32 = dst->as_u32;
+
+  vnet_buffer (b)->l3_hdr_offset = (u8 *) ih - b->data;
+  b->flags |= VNET_BUFFER_F_IS_IP4 | VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
+
+  /* Offload ip4 header checksum generation */
+  if (csum_offload)
+    {
+      ih->checksum = 0;
+      b->flags |= VNET_BUFFER_F_OFFLOAD_IP_CKSUM;
+    }
+  else
+    ih->checksum = ip4_header_checksum (ih);
+
+  return ih;
+}
+
+/**
+ * Push IPv4 header to buffer
+ *
+ * This does not support fragmentation.
+ *
+ * @param vm - vlib_main
+ * @param b - buffer to write the header to
+ * @param src - source IP
+ * @param dst - destination IP
+ * @param prot - payload proto
+ *
+ * @return - pointer to start of IP header
+ */
+always_inline void *
+vlib_buffer_push_ip4 (vlib_main_t * vm, vlib_buffer_t * b,
+		      ip4_address_t * src, ip4_address_t * dst, int proto,
+		      u8 csum_offload)
+{
+  return vlib_buffer_push_ip4_custom (vm, b, src, dst, proto, csum_offload,
+				      1 /* is_df */ );
+}
+
+#endif /* included_ip_ip4_inlines_h */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/ip/ip4_input.c b/src/vnet/ip/ip4_input.c
index 4d48db8..bf8e05c 100644
--- a/src/vnet/ip/ip4_input.c
+++ b/src/vnet/ip/ip4_input.c
@@ -451,20 +451,6 @@
 
 VLIB_INIT_FUNCTION (ip4_init);
 
-static clib_error_t *
-ip4_main_loop_enter (vlib_main_t * vm)
-{
-  ip4_main_t *im = &ip4_main;
-  vlib_thread_main_t *tm = &vlib_thread_main;
-  u32 n_vlib_mains = tm->n_vlib_mains;
-
-  throttle_init (&im->arp_throttle, n_vlib_mains, 1e-3);
-
-  return (NULL);
-}
-
-VLIB_MAIN_LOOP_ENTER_FUNCTION (ip4_main_loop_enter);
-
 /*
  * fd.io coding-style-patch-verification: ON
  *
diff --git a/src/vnet/ip/ip6.h b/src/vnet/ip/ip6.h
index fcb1803..a0fa3b4 100644
--- a/src/vnet/ip/ip6.h
+++ b/src/vnet/ip/ip6.h
@@ -40,17 +40,16 @@
 #ifndef included_ip_ip6_h
 #define included_ip_ip6_h
 
+#include <stdbool.h>
+
 #include <vlib/buffer.h>
-#include <vnet/ethernet/packet.h>
-#include <vnet/ethernet/mac_address.h>
+
 #include <vnet/ip/ip6_packet.h>
 #include <vnet/ip/ip46_address.h>
 #include <vnet/ip/ip6_hop_by_hop_packet.h>
 #include <vnet/ip/lookup.h>
 #include <vnet/ip/ip_interface.h>
-#include <stdbool.h>
-#include <vnet/util/radix.h>
-#include <vnet/util/throttle.h>
+#include <vnet/ip/ip_flow_hash.h>
 
 typedef struct
 {
@@ -164,9 +163,6 @@
 
   /* HBH processing enabled? */
   u8 hbh_enabled;
-
-  /** ND throttling */
-  throttle_t nd_throttle;
 } ip6_main_t;
 
 #define ND_THROTTLE_BITS 512
@@ -304,153 +300,6 @@
 				 u32 table_index);
 extern vlib_node_registration_t ip6_lookup_node;
 
-/* Compute flow hash.  We'll use it to select which Sponge to use for this
-   flow.  And other things. */
-always_inline u32
-ip6_compute_flow_hash (const ip6_header_t * ip,
-		       flow_hash_config_t flow_hash_config)
-{
-  tcp_header_t *tcp;
-  u64 a, b, c;
-  u64 t1, t2;
-  uword is_tcp_udp = 0;
-  u8 protocol = ip->protocol;
-
-  if (PREDICT_TRUE
-      ((ip->protocol == IP_PROTOCOL_TCP)
-       || (ip->protocol == IP_PROTOCOL_UDP)))
-    {
-      is_tcp_udp = 1;
-      tcp = (void *) (ip + 1);
-    }
-  else if (ip->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
-    {
-      ip6_hop_by_hop_header_t *hbh = (ip6_hop_by_hop_header_t *) (ip + 1);
-      if ((hbh->protocol == IP_PROTOCOL_TCP) ||
-	  (hbh->protocol == IP_PROTOCOL_UDP))
-	{
-	  is_tcp_udp = 1;
-	  tcp = (tcp_header_t *) ((u8 *) hbh + ((hbh->length + 1) << 3));
-	}
-      protocol = hbh->protocol;
-    }
-
-  t1 = (ip->src_address.as_u64[0] ^ ip->src_address.as_u64[1]);
-  t1 = (flow_hash_config & IP_FLOW_HASH_SRC_ADDR) ? t1 : 0;
-
-  t2 = (ip->dst_address.as_u64[0] ^ ip->dst_address.as_u64[1]);
-  t2 = (flow_hash_config & IP_FLOW_HASH_DST_ADDR) ? t2 : 0;
-
-  a = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ? t2 : t1;
-  b = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ? t1 : t2;
-
-  t1 = is_tcp_udp ? tcp->src : 0;
-  t2 = is_tcp_udp ? tcp->dst : 0;
-
-  t1 = (flow_hash_config & IP_FLOW_HASH_SRC_PORT) ? t1 : 0;
-  t2 = (flow_hash_config & IP_FLOW_HASH_DST_PORT) ? t2 : 0;
-
-  if (flow_hash_config & IP_FLOW_HASH_SYMMETRIC)
-    {
-      if (b < a)
-	{
-	  c = a;
-	  a = b;
-	  b = c;
-	}
-      if (t2 < t1)
-	{
-	  t2 += t1;
-	  t1 = t2 - t1;
-	  t2 = t2 - t1;
-	}
-    }
-
-  b ^= (flow_hash_config & IP_FLOW_HASH_PROTO) ? protocol : 0;
-  c = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ?
-    ((t1 << 16) | t2) : ((t2 << 16) | t1);
-
-  hash_mix64 (a, b, c);
-  return (u32) c;
-}
-
-/* ip6_locate_header
- *
- * This function is to search for the header specified by the protocol number
- * in find_hdr_type.
- * This is used to locate a specific IPv6 extension header
- * or to find transport layer header.
- *   1. If the find_hdr_type < 0 then it finds and returns the protocol number and
- *   offset stored in *offset of the transport or ESP header in the chain if
- *   found.
- *   2. If a header with find_hdr_type > 0 protocol number is found then the
- *      offset is stored in *offset and protocol number of the header is
- *      returned.
- *   3. If find_hdr_type is not found or packet is malformed or
- *      it is a non-first fragment -1 is returned.
- */
-always_inline int
-ip6_locate_header (vlib_buffer_t * p0,
-		   ip6_header_t * ip0, int find_hdr_type, u32 * offset)
-{
-  u8 next_proto = ip0->protocol;
-  u8 *next_header;
-  u8 done = 0;
-  u32 cur_offset;
-  u8 *temp_nxthdr = 0;
-  u32 exthdr_len = 0;
-
-  next_header = ip6_next_header (ip0);
-  cur_offset = sizeof (ip6_header_t);
-  while (1)
-    {
-      done = (next_proto == find_hdr_type);
-      if (PREDICT_FALSE
-	  (next_header >=
-	   (u8 *) vlib_buffer_get_current (p0) + p0->current_length))
-	{
-	  //A malicious packet could set an extension header with a too big size
-	  return (-1);
-	}
-      if (done)
-	break;
-      if ((!ip6_ext_hdr (next_proto)) || next_proto == IP_PROTOCOL_IP6_NONXT)
-	{
-	  if (find_hdr_type < 0)
-	    break;
-	  return -1;
-	}
-      if (next_proto == IP_PROTOCOL_IPV6_FRAGMENTATION)
-	{
-	  ip6_frag_hdr_t *frag_hdr = (ip6_frag_hdr_t *) next_header;
-	  u16 frag_off = ip6_frag_hdr_offset (frag_hdr);
-	  /* Non first fragment return -1 */
-	  if (frag_off)
-	    return (-1);
-	  exthdr_len = sizeof (ip6_frag_hdr_t);
-	  temp_nxthdr = next_header + exthdr_len;
-	}
-      else if (next_proto == IP_PROTOCOL_IPSEC_AH)
-	{
-	  exthdr_len =
-	    ip6_ext_authhdr_len (((ip6_ext_header_t *) next_header));
-	  temp_nxthdr = next_header + exthdr_len;
-	}
-      else
-	{
-	  exthdr_len =
-	    ip6_ext_header_len (((ip6_ext_header_t *) next_header));
-	  temp_nxthdr = next_header + exthdr_len;
-	}
-      next_proto = ((ip6_ext_header_t *) next_header)->next_hdr;
-      next_header = temp_nxthdr;
-      cur_offset += exthdr_len;
-    }
-
-  *offset = cur_offset;
-  return (next_proto);
-}
-
 u8 *format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args);
 /*
  * Hop-by-Hop handling
@@ -475,70 +324,6 @@
 int ip6_hbh_unregister_option (u8 option);
 void ip6_hbh_set_next_override (uword next);
 
-/**
- * Push IPv6 header to buffer
- *
- * @param vm - vlib_main
- * @param b - buffer to write the header to
- * @param src - source IP
- * @param dst - destination IP
- * @param prot - payload proto
- * @param flow_label - flow label
- *
- * @return - pointer to start of IP header
- */
-always_inline void *
-vlib_buffer_push_ip6_custom (vlib_main_t * vm, vlib_buffer_t * b,
-			     ip6_address_t * src, ip6_address_t * dst,
-			     int proto, u32 flow_label)
-{
-  ip6_header_t *ip6h;
-  u16 payload_length;
-
-  /* make some room */
-  ip6h = vlib_buffer_push_uninit (b, sizeof (ip6_header_t));
-  ASSERT (flow_label < 1 << 20);
-  ip6h->ip_version_traffic_class_and_flow_label =
-    clib_host_to_net_u32 ((0x6 << 28) | flow_label);
-
-  /* calculate ip6 payload length */
-  payload_length = vlib_buffer_length_in_chain (vm, b);
-  payload_length -= sizeof (*ip6h);
-
-  ip6h->payload_length = clib_host_to_net_u16 (payload_length);
-
-  ip6h->hop_limit = 0xff;
-  ip6h->protocol = proto;
-  clib_memcpy_fast (ip6h->src_address.as_u8, src->as_u8,
-		    sizeof (ip6h->src_address));
-  clib_memcpy_fast (ip6h->dst_address.as_u8, dst->as_u8,
-		    sizeof (ip6h->src_address));
-  vnet_buffer (b)->l3_hdr_offset = (u8 *) ip6h - b->data;
-  b->flags |= VNET_BUFFER_F_IS_IP6 | VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
-
-  return ip6h;
-}
-
-/**
- * Push IPv6 header to buffer
- *
- * @param vm - vlib_main
- * @param b - buffer to write the header to
- * @param src - source IP
- * @param dst - destination IP
- * @param prot - payload proto
- *
- * @return - pointer to start of IP header
- */
-always_inline void *
-vlib_buffer_push_ip6 (vlib_main_t * vm, vlib_buffer_t * b,
-		      ip6_address_t * src, ip6_address_t * dst, int proto)
-{
-  return vlib_buffer_push_ip6_custom (vm, b, src, dst, proto,
-				      0 /* flow label */ );
-
-}
-
 always_inline u32
 vlib_buffer_get_ip6_fib_index (vlib_buffer_t * b)
 {
diff --git a/src/vnet/ip/ip6_forward.h b/src/vnet/ip/ip6_forward.h
index 7f6eb0c..8e5dd25 100644
--- a/src/vnet/ip/ip6_forward.h
+++ b/src/vnet/ip/ip6_forward.h
@@ -42,6 +42,7 @@
 
 #include <vnet/fib/ip6_fib.h>
 #include <vnet/dpo/load_balance_map.h>
+#include <vnet/ip/ip6_inlines.h>
 
 /**
  * @file
diff --git a/src/vnet/ip/ip6_inlines.h b/src/vnet/ip/ip6_inlines.h
new file mode 100644
index 0000000..ae7b7a1
--- /dev/null
+++ b/src/vnet/ip/ip6_inlines.h
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * ip/ip6.h: ip6 main include file
+ *
+ * Copyright (c) 2008 Eliot Dresselhaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef included_ip_ip6_inlines_h
+#define included_ip_ip6_inlines_h
+
+#include <vnet/ip/ip6_packet.h>
+#include <vnet/ip/ip6_hop_by_hop_packet.h>
+
+/* Compute flow hash.  We'll use it to select which Sponge to use for this
+   flow.  And other things. */
+always_inline u32
+ip6_compute_flow_hash (const ip6_header_t * ip,
+		       flow_hash_config_t flow_hash_config)
+{
+  tcp_header_t *tcp;
+  u64 a, b, c;
+  u64 t1, t2;
+  uword is_tcp_udp = 0;
+  u8 protocol = ip->protocol;
+
+  if (PREDICT_TRUE
+      ((ip->protocol == IP_PROTOCOL_TCP)
+       || (ip->protocol == IP_PROTOCOL_UDP)))
+    {
+      is_tcp_udp = 1;
+      tcp = (void *) (ip + 1);
+    }
+  else if (ip->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
+    {
+      ip6_hop_by_hop_header_t *hbh = (ip6_hop_by_hop_header_t *) (ip + 1);
+      if ((hbh->protocol == IP_PROTOCOL_TCP) ||
+	  (hbh->protocol == IP_PROTOCOL_UDP))
+	{
+	  is_tcp_udp = 1;
+	  tcp = (tcp_header_t *) ((u8 *) hbh + ((hbh->length + 1) << 3));
+	}
+      protocol = hbh->protocol;
+    }
+
+  t1 = (ip->src_address.as_u64[0] ^ ip->src_address.as_u64[1]);
+  t1 = (flow_hash_config & IP_FLOW_HASH_SRC_ADDR) ? t1 : 0;
+
+  t2 = (ip->dst_address.as_u64[0] ^ ip->dst_address.as_u64[1]);
+  t2 = (flow_hash_config & IP_FLOW_HASH_DST_ADDR) ? t2 : 0;
+
+  a = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ? t2 : t1;
+  b = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ? t1 : t2;
+
+  t1 = is_tcp_udp ? tcp->src : 0;
+  t2 = is_tcp_udp ? tcp->dst : 0;
+
+  t1 = (flow_hash_config & IP_FLOW_HASH_SRC_PORT) ? t1 : 0;
+  t2 = (flow_hash_config & IP_FLOW_HASH_DST_PORT) ? t2 : 0;
+
+  if (flow_hash_config & IP_FLOW_HASH_SYMMETRIC)
+    {
+      if (b < a)
+	{
+	  c = a;
+	  a = b;
+	  b = c;
+	}
+      if (t2 < t1)
+	{
+	  t2 += t1;
+	  t1 = t2 - t1;
+	  t2 = t2 - t1;
+	}
+    }
+
+  b ^= (flow_hash_config & IP_FLOW_HASH_PROTO) ? protocol : 0;
+  c = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ?
+    ((t1 << 16) | t2) : ((t2 << 16) | t1);
+
+  hash_mix64 (a, b, c);
+  return (u32) c;
+}
+
+/* ip6_locate_header
+ *
+ * This function is to search for the header specified by the protocol number
+ * in find_hdr_type.
+ * This is used to locate a specific IPv6 extension header
+ * or to find transport layer header.
+ *   1. If the find_hdr_type < 0 then it finds and returns the protocol number and
+ *   offset stored in *offset of the transport or ESP header in the chain if
+ *   found.
+ *   2. If a header with find_hdr_type > 0 protocol number is found then the
+ *      offset is stored in *offset and protocol number of the header is
+ *      returned.
+ *   3. If find_hdr_type is not found or packet is malformed or
+ *      it is a non-first fragment -1 is returned.
+ */
+always_inline int
+ip6_locate_header (vlib_buffer_t * p0,
+		   ip6_header_t * ip0, int find_hdr_type, u32 * offset)
+{
+  u8 next_proto = ip0->protocol;
+  u8 *next_header;
+  u8 done = 0;
+  u32 cur_offset;
+  u8 *temp_nxthdr = 0;
+  u32 exthdr_len = 0;
+
+  next_header = ip6_next_header (ip0);
+  cur_offset = sizeof (ip6_header_t);
+  while (1)
+    {
+      done = (next_proto == find_hdr_type);
+      if (PREDICT_FALSE
+	  (next_header >=
+	   (u8 *) vlib_buffer_get_current (p0) + p0->current_length))
+	{
+	  //A malicious packet could set an extension header with a too big size
+	  return (-1);
+	}
+      if (done)
+	break;
+      if ((!ip6_ext_hdr (next_proto)) || next_proto == IP_PROTOCOL_IP6_NONXT)
+	{
+	  if (find_hdr_type < 0)
+	    break;
+	  return -1;
+	}
+      if (next_proto == IP_PROTOCOL_IPV6_FRAGMENTATION)
+	{
+	  ip6_frag_hdr_t *frag_hdr = (ip6_frag_hdr_t *) next_header;
+	  u16 frag_off = ip6_frag_hdr_offset (frag_hdr);
+	  /* Non first fragment return -1 */
+	  if (frag_off)
+	    return (-1);
+	  exthdr_len = sizeof (ip6_frag_hdr_t);
+	  temp_nxthdr = next_header + exthdr_len;
+	}
+      else if (next_proto == IP_PROTOCOL_IPSEC_AH)
+	{
+	  exthdr_len =
+	    ip6_ext_authhdr_len (((ip6_ext_header_t *) next_header));
+	  temp_nxthdr = next_header + exthdr_len;
+	}
+      else
+	{
+	  exthdr_len =
+	    ip6_ext_header_len (((ip6_ext_header_t *) next_header));
+	  temp_nxthdr = next_header + exthdr_len;
+	}
+      next_proto = ((ip6_ext_header_t *) next_header)->next_hdr;
+      next_header = temp_nxthdr;
+      cur_offset += exthdr_len;
+    }
+
+  *offset = cur_offset;
+  return (next_proto);
+}
+
+
+/**
+ * Push IPv6 header to buffer
+ *
+ * @param vm - vlib_main
+ * @param b - buffer to write the header to
+ * @param src - source IP
+ * @param dst - destination IP
+ * @param prot - payload proto
+ * @param flow_label - flow label
+ *
+ * @return - pointer to start of IP header
+ */
+always_inline void *
+vlib_buffer_push_ip6_custom (vlib_main_t * vm, vlib_buffer_t * b,
+			     ip6_address_t * src, ip6_address_t * dst,
+			     int proto, u32 flow_label)
+{
+  ip6_header_t *ip6h;
+  u16 payload_length;
+
+  /* make some room */
+  ip6h = vlib_buffer_push_uninit (b, sizeof (ip6_header_t));
+  ASSERT (flow_label < 1 << 20);
+  ip6h->ip_version_traffic_class_and_flow_label =
+    clib_host_to_net_u32 ((0x6 << 28) | flow_label);
+
+  /* calculate ip6 payload length */
+  payload_length = vlib_buffer_length_in_chain (vm, b);
+  payload_length -= sizeof (*ip6h);
+
+  ip6h->payload_length = clib_host_to_net_u16 (payload_length);
+
+  ip6h->hop_limit = 0xff;
+  ip6h->protocol = proto;
+  clib_memcpy_fast (ip6h->src_address.as_u8, src->as_u8,
+		    sizeof (ip6h->src_address));
+  clib_memcpy_fast (ip6h->dst_address.as_u8, dst->as_u8,
+		    sizeof (ip6h->src_address));
+  vnet_buffer (b)->l3_hdr_offset = (u8 *) ip6h - b->data;
+  b->flags |= VNET_BUFFER_F_IS_IP6 | VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
+
+  return ip6h;
+}
+
+/**
+ * Push IPv6 header to buffer
+ *
+ * @param vm - vlib_main
+ * @param b - buffer to write the header to
+ * @param src - source IP
+ * @param dst - destination IP
+ * @param prot - payload proto
+ *
+ * @return - pointer to start of IP header
+ */
+always_inline void *
+vlib_buffer_push_ip6 (vlib_main_t * vm, vlib_buffer_t * b,
+		      ip6_address_t * src, ip6_address_t * dst, int proto)
+{
+  return vlib_buffer_push_ip6_custom (vm, b, src, dst, proto,
+				      0 /* flow label */ );
+
+}
+
+#endif /* included_ip_ip6_h */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/ip/ip6_input.c b/src/vnet/ip/ip6_input.c
index ebcfd5a..65d39eb 100644
--- a/src/vnet/ip/ip6_input.c
+++ b/src/vnet/ip/ip6_input.c
@@ -280,19 +280,6 @@
 
 VLIB_INIT_FUNCTION (ip6_init);
 
-static clib_error_t *
-ip6_main_loop_enter (vlib_main_t * vm)
-{
-  ip6_main_t *im = &ip6_main;
-  vlib_thread_main_t *tm = &vlib_thread_main;
-
-  throttle_init (&im->nd_throttle, tm->n_vlib_mains, 1e-3);
-
-  return 0;
-}
-
-VLIB_MAIN_LOOP_ENTER_FUNCTION (ip6_main_loop_enter);
-
 /*
  * fd.io coding-style-patch-verification: ON
  *
diff --git a/src/vnet/ip/ip_api.c b/src/vnet/ip/ip_api.c
index 448b36c..3bdb53c 100644
--- a/src/vnet/ip/ip_api.c
+++ b/src/vnet/ip/ip_api.c
@@ -45,6 +45,7 @@
 #include <vnet/ip/reass/ip6_sv_reass.h>
 #include <vnet/ip/reass/ip6_full_reass.h>
 #include <vnet/ip/ip_table.h>
+#include <vnet/ip/ip_container_proxy.h>
 
 #include <vnet/vnet_msg_enum.h>
 
diff --git a/src/vnet/ip/ip_container_proxy.c b/src/vnet/ip/ip_container_proxy.c
new file mode 100644
index 0000000..e90be8b
--- /dev/null
+++ b/src/vnet/ip/ip_container_proxy.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * ip/ip_lookup.c: ip4/6 adjacency and lookup table management
+ *
+ * Copyright (c) 2008 Eliot Dresselhaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <vnet/ip/ip_container_proxy.h>
+#include <vnet/ip/format.h>
+#include <vnet/fib/fib_table.h>
+#include <vnet/dpo/l3_proxy_dpo.h>
+#include <vnet/dpo/load_balance.h>
+
+clib_error_t *
+vnet_ip_container_proxy_add_del (vnet_ip_container_proxy_args_t * args)
+{
+  u32 fib_index;
+
+  if (!vnet_sw_interface_is_api_valid (vnet_get_main (), args->sw_if_index))
+    return clib_error_return_code (0, VNET_API_ERROR_INVALID_INTERFACE, 0,
+				   "invalid sw_if_index");
+
+  fib_index = fib_table_get_table_id_for_sw_if_index (args->prefix.fp_proto,
+						      args->sw_if_index);
+  if (args->is_add)
+    {
+      dpo_id_t proxy_dpo = DPO_INVALID;
+      l3_proxy_dpo_add_or_lock (fib_proto_to_dpo (args->prefix.fp_proto),
+				args->sw_if_index, &proxy_dpo);
+      fib_table_entry_special_dpo_add (fib_index,
+				       &args->prefix,
+				       FIB_SOURCE_PROXY,
+				       FIB_ENTRY_FLAG_EXCLUSIVE, &proxy_dpo);
+      dpo_reset (&proxy_dpo);
+    }
+  else
+    {
+      fib_table_entry_special_remove (fib_index, &args->prefix,
+				      FIB_SOURCE_PROXY);
+    }
+  return 0;
+}
+
+u8
+ip_container_proxy_is_set (fib_prefix_t * pfx, u32 sw_if_index)
+{
+  u32 fib_index;
+  fib_node_index_t fei;
+  const dpo_id_t *dpo;
+  l3_proxy_dpo_t *l3p;
+  load_balance_t *lb0;
+
+  fib_index = fib_table_get_table_id_for_sw_if_index (pfx->fp_proto,
+						      sw_if_index);
+  if (fib_index == ~0)
+    return 0;
+
+  fei = fib_table_lookup_exact_match (fib_index, pfx);
+  if (fei == FIB_NODE_INDEX_INVALID)
+    return 0;
+
+  dpo = fib_entry_contribute_ip_forwarding (fei);
+  lb0 = load_balance_get (dpo->dpoi_index);
+  dpo = load_balance_get_bucket_i (lb0, 0);
+  if (dpo->dpoi_type != DPO_L3_PROXY)
+    return 0;
+
+  l3p = l3_proxy_dpo_get (dpo->dpoi_index);
+  return (l3p->l3p_sw_if_index == sw_if_index);
+}
+
+typedef struct ip_container_proxy_walk_ctx_t_
+{
+  ip_container_proxy_cb_t cb;
+  void *ctx;
+} ip_container_proxy_walk_ctx_t;
+
+static fib_table_walk_rc_t
+ip_container_proxy_fib_table_walk (fib_node_index_t fei, void *arg)
+{
+  ip_container_proxy_walk_ctx_t *ctx = arg;
+  const fib_prefix_t *pfx;
+  const dpo_id_t *dpo;
+  load_balance_t *lb;
+  l3_proxy_dpo_t *l3p;
+
+  pfx = fib_entry_get_prefix (fei);
+  if (fib_entry_is_sourced (fei, FIB_SOURCE_PROXY))
+    {
+      dpo = fib_entry_contribute_ip_forwarding (fei);
+      lb = load_balance_get (dpo->dpoi_index);
+      dpo = load_balance_get_bucket_i (lb, 0);
+      l3p = l3_proxy_dpo_get (dpo->dpoi_index);
+      ctx->cb (pfx, l3p->l3p_sw_if_index, ctx->ctx);
+    }
+
+  return FIB_TABLE_WALK_CONTINUE;
+}
+
+void
+ip_container_proxy_walk (ip_container_proxy_cb_t cb, void *ctx)
+{
+  fib_table_t *fib_table;
+  ip_container_proxy_walk_ctx_t wctx = {
+    .cb = cb,
+    .ctx = ctx,
+  };
+
+  /* *INDENT-OFF* */
+  pool_foreach (fib_table, ip4_main.fibs,
+  ({
+    fib_table_walk(fib_table->ft_index,
+                   FIB_PROTOCOL_IP4,
+                   ip_container_proxy_fib_table_walk,
+                   &wctx);
+  }));
+  pool_foreach (fib_table, ip6_main.fibs,
+  ({
+    fib_table_walk(fib_table->ft_index,
+                   FIB_PROTOCOL_IP6,
+                   ip_container_proxy_fib_table_walk,
+                   &wctx);
+  }));
+  /* *INDENT-ON* */
+}
+
+clib_error_t *
+ip_container_cmd (vlib_main_t * vm,
+		  unformat_input_t * main_input, vlib_cli_command_t * cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  fib_prefix_t pfx;
+  u32 is_del, addr_set = 0;
+  vnet_main_t *vnm;
+  u32 sw_if_index;
+
+  vnm = vnet_get_main ();
+  is_del = 0;
+  sw_if_index = ~0;
+  clib_memset (&pfx, 0, sizeof (pfx));
+
+  /* Get a line of input. */
+  if (!unformat_user (main_input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "%U", unformat_ip4_address, &pfx.fp_addr.ip4))
+	{
+	  pfx.fp_proto = FIB_PROTOCOL_IP4;
+	  pfx.fp_len = 32;
+	  addr_set = 1;
+	}
+      else if (unformat (line_input, "%U",
+			 unformat_ip6_address, &pfx.fp_addr.ip6))
+	{
+	  pfx.fp_proto = FIB_PROTOCOL_IP6;
+	  pfx.fp_len = 128;
+	  addr_set = 1;
+	}
+      else if (unformat (line_input, "%U",
+			 unformat_vnet_sw_interface, vnm, &sw_if_index))
+	;
+      else if (unformat (line_input, "del"))
+	is_del = 1;
+      else
+	{
+	  unformat_free (line_input);
+	  return (clib_error_return (0, "unknown input '%U'",
+				     format_unformat_error, line_input));
+	}
+    }
+
+  if (~0 == sw_if_index || !addr_set)
+    {
+      unformat_free (line_input);
+      vlib_cli_output (vm, "interface and address must be set");
+      return 0;
+    }
+
+  vnet_ip_container_proxy_args_t args = {
+    .prefix = pfx,
+    .sw_if_index = sw_if_index,
+    .is_add = !is_del,
+  };
+  vnet_ip_container_proxy_add_del (&args);
+  unformat_free (line_input);
+  return (NULL);
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (ip_container_command_node, static) = {
+  .path = "ip container",
+  .function = ip_container_cmd,
+  .short_help = "ip container <address> <interface>",
+  .is_mp_safe = 1,
+};
+/* *INDENT-ON* */
+
+clib_error_t *
+show_ip_container_cmd_fn (vlib_main_t * vm, unformat_input_t * main_input,
+			  vlib_cli_command_t * cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  vnet_main_t *vnm = vnet_get_main ();
+  fib_prefix_t pfx;
+  u32 sw_if_index = ~0;
+  u8 has_proxy;
+
+  if (!unformat_user (main_input, unformat_line_input, line_input))
+    return 0;
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "%U", unformat_ip4_address, &pfx.fp_addr.ip4))
+	{
+	  pfx.fp_proto = FIB_PROTOCOL_IP4;
+	  pfx.fp_len = 32;
+	}
+      else if (unformat (line_input, "%U",
+			 unformat_ip6_address, &pfx.fp_addr.ip6))
+	{
+	  pfx.fp_proto = FIB_PROTOCOL_IP6;
+	  pfx.fp_len = 128;
+	}
+      else if (unformat (line_input, "%U",
+			 unformat_vnet_sw_interface, vnm, &sw_if_index))
+	;
+      else
+	{
+	  unformat_free (line_input);
+	  return (clib_error_return (0, "unknown input '%U'",
+				     format_unformat_error, line_input));
+	}
+    }
+
+  if (~0 == sw_if_index)
+    {
+      unformat_free (line_input);
+      vlib_cli_output (vm, "no interface");
+      return (clib_error_return (0, "no interface"));
+    }
+
+  has_proxy = ip_container_proxy_is_set (&pfx, sw_if_index);
+  vlib_cli_output (vm, "ip container proxy is: %s", has_proxy ? "on" : "off");
+
+  unformat_free (line_input);
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_ip_container_command, static) = {
+  .path = "show ip container",
+  .function = show_ip_container_cmd_fn,
+  .short_help = "show ip container <address> <interface>",
+  .is_mp_safe = 1,
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/ip/ip_container_proxy.h b/src/vnet/ip/ip_container_proxy.h
new file mode 100644
index 0000000..4aee56c
--- /dev/null
+++ b/src/vnet/ip/ip_container_proxy.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef included_ip_container_proxy_h
+#define included_ip_container_proxy_h
+
+#include <vnet/fib/fib_types.h>
+
+typedef struct _vnet_ip_container_proxy_args
+{
+  fib_prefix_t prefix;
+  u32 sw_if_index;
+  u8 is_add;
+} vnet_ip_container_proxy_args_t;
+
+clib_error_t *vnet_ip_container_proxy_add_del (vnet_ip_container_proxy_args_t
+					       * args);
+
+typedef int (*ip_container_proxy_cb_t) (const fib_prefix_t * pfx,
+					u32 sw_if_index, void *ctx);
+void ip_container_proxy_walk (ip_container_proxy_cb_t cb, void *ctx);
+
+#endif
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/ip/ip_flow_hash.h b/src/vnet/ip/ip_flow_hash.h
new file mode 100644
index 0000000..0477732
--- /dev/null
+++ b/src/vnet/ip/ip_flow_hash.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __IP_FLOW_HASH_H__
+#define __IP_FLOW_HASH_H__
+
+/** Flow hash configuration */
+#define IP_FLOW_HASH_SRC_ADDR (1<<0)
+#define IP_FLOW_HASH_DST_ADDR (1<<1)
+#define IP_FLOW_HASH_PROTO (1<<2)
+#define IP_FLOW_HASH_SRC_PORT (1<<3)
+#define IP_FLOW_HASH_DST_PORT (1<<4)
+#define IP_FLOW_HASH_REVERSE_SRC_DST (1<<5)
+#define IP_FLOW_HASH_SYMMETRIC (1<<6)
+
+/** Default: 5-tuple without the "reverse" bit */
+#define IP_FLOW_HASH_DEFAULT (0x1F)
+
+#define foreach_flow_hash_bit                   \
+_(src, IP_FLOW_HASH_SRC_ADDR)                   \
+_(dst, IP_FLOW_HASH_DST_ADDR)                   \
+_(sport, IP_FLOW_HASH_SRC_PORT)                 \
+_(dport, IP_FLOW_HASH_DST_PORT)                 \
+_(proto, IP_FLOW_HASH_PROTO)	                \
+_(reverse, IP_FLOW_HASH_REVERSE_SRC_DST)	\
+_(symmetric, IP_FLOW_HASH_SYMMETRIC)
+
+/**
+ * A flow hash configuration is a mask of the flow hash options
+ */
+typedef u32 flow_hash_config_t;
+
+#endif /* __IP_TYPES_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/ip/ip_table.h b/src/vnet/ip/ip_table.h
index 1f75c15..dfdd27a 100644
--- a/src/vnet/ip/ip_table.h
+++ b/src/vnet/ip/ip_table.h
@@ -16,14 +16,7 @@
 #ifndef included_ip_table_h
 #define included_ip_table_h
 
-#include <vlib/vlib.h>
-
-/* ip table add delete callback */
-typedef struct _vnet_ip_table_function_list_elt
-{
-  struct _vnet_ip_table_function_list_elt *next_ip_table_function;
-  clib_error_t *(*fp) (struct vnet_main_t * vnm, u32 table_id, u32 flags);
-} _vnet_ip_table_function_list_elt_t;
+#include <vnet/vnet.h>
 
 typedef enum vnet_ip_table_function_priority_t_
 {
diff --git a/src/vnet/ip/lookup.c b/src/vnet/ip/lookup.c
index 63bd281..b356b27 100644
--- a/src/vnet/ip/lookup.c
+++ b/src/vnet/ip/lookup.c
@@ -49,7 +49,6 @@
 #include <vnet/dpo/punt_dpo.h>
 #include <vnet/dpo/receive_dpo.h>
 #include <vnet/dpo/ip_null_dpo.h>
-#include <vnet/dpo/l3_proxy_dpo.h>
 
 /**
  * @file
@@ -899,251 +898,6 @@
 };
 /* *INDENT-ON* */
 
-clib_error_t *
-vnet_ip_container_proxy_add_del (vnet_ip_container_proxy_args_t * args)
-{
-  u32 fib_index;
-
-  if (!vnet_sw_interface_is_api_valid (vnet_get_main (), args->sw_if_index))
-    return clib_error_return_code (0, VNET_API_ERROR_INVALID_INTERFACE, 0,
-				   "invalid sw_if_index");
-
-  fib_index = fib_table_get_table_id_for_sw_if_index (args->prefix.fp_proto,
-						      args->sw_if_index);
-  if (args->is_add)
-    {
-      dpo_id_t proxy_dpo = DPO_INVALID;
-      l3_proxy_dpo_add_or_lock (fib_proto_to_dpo (args->prefix.fp_proto),
-				args->sw_if_index, &proxy_dpo);
-      fib_table_entry_special_dpo_add (fib_index,
-				       &args->prefix,
-				       FIB_SOURCE_PROXY,
-				       FIB_ENTRY_FLAG_EXCLUSIVE, &proxy_dpo);
-      dpo_reset (&proxy_dpo);
-    }
-  else
-    {
-      fib_table_entry_special_remove (fib_index, &args->prefix,
-				      FIB_SOURCE_PROXY);
-    }
-  return 0;
-}
-
-u8
-ip_container_proxy_is_set (fib_prefix_t * pfx, u32 sw_if_index)
-{
-  u32 fib_index;
-  fib_node_index_t fei;
-  const dpo_id_t *dpo;
-  l3_proxy_dpo_t *l3p;
-  load_balance_t *lb0;
-
-  fib_index = fib_table_get_table_id_for_sw_if_index (pfx->fp_proto,
-						      sw_if_index);
-  if (fib_index == ~0)
-    return 0;
-
-  fei = fib_table_lookup_exact_match (fib_index, pfx);
-  if (fei == FIB_NODE_INDEX_INVALID)
-    return 0;
-
-  dpo = fib_entry_contribute_ip_forwarding (fei);
-  lb0 = load_balance_get (dpo->dpoi_index);
-  dpo = load_balance_get_bucket_i (lb0, 0);
-  if (dpo->dpoi_type != DPO_L3_PROXY)
-    return 0;
-
-  l3p = l3_proxy_dpo_get (dpo->dpoi_index);
-  return (l3p->l3p_sw_if_index == sw_if_index);
-}
-
-typedef struct ip_container_proxy_walk_ctx_t_
-{
-  ip_container_proxy_cb_t cb;
-  void *ctx;
-} ip_container_proxy_walk_ctx_t;
-
-static fib_table_walk_rc_t
-ip_container_proxy_fib_table_walk (fib_node_index_t fei, void *arg)
-{
-  ip_container_proxy_walk_ctx_t *ctx = arg;
-  const fib_prefix_t *pfx;
-  const dpo_id_t *dpo;
-  load_balance_t *lb;
-  l3_proxy_dpo_t *l3p;
-
-  pfx = fib_entry_get_prefix (fei);
-  if (fib_entry_is_sourced (fei, FIB_SOURCE_PROXY))
-    {
-      dpo = fib_entry_contribute_ip_forwarding (fei);
-      lb = load_balance_get (dpo->dpoi_index);
-      dpo = load_balance_get_bucket_i (lb, 0);
-      l3p = l3_proxy_dpo_get (dpo->dpoi_index);
-      ctx->cb (pfx, l3p->l3p_sw_if_index, ctx->ctx);
-    }
-
-  return FIB_TABLE_WALK_CONTINUE;
-}
-
-void
-ip_container_proxy_walk (ip_container_proxy_cb_t cb, void *ctx)
-{
-  fib_table_t *fib_table;
-  ip_container_proxy_walk_ctx_t wctx = {
-    .cb = cb,
-    .ctx = ctx,
-  };
-
-  /* *INDENT-OFF* */
-  pool_foreach (fib_table, ip4_main.fibs,
-  ({
-    fib_table_walk(fib_table->ft_index,
-                   FIB_PROTOCOL_IP4,
-                   ip_container_proxy_fib_table_walk,
-                   &wctx);
-  }));
-  pool_foreach (fib_table, ip6_main.fibs,
-  ({
-    fib_table_walk(fib_table->ft_index,
-                   FIB_PROTOCOL_IP6,
-                   ip_container_proxy_fib_table_walk,
-                   &wctx);
-  }));
-  /* *INDENT-ON* */
-}
-
-clib_error_t *
-ip_container_cmd (vlib_main_t * vm,
-		  unformat_input_t * main_input, vlib_cli_command_t * cmd)
-{
-  unformat_input_t _line_input, *line_input = &_line_input;
-  fib_prefix_t pfx;
-  u32 is_del, addr_set = 0;
-  vnet_main_t *vnm;
-  u32 sw_if_index;
-
-  vnm = vnet_get_main ();
-  is_del = 0;
-  sw_if_index = ~0;
-  clib_memset (&pfx, 0, sizeof (pfx));
-
-  /* Get a line of input. */
-  if (!unformat_user (main_input, unformat_line_input, line_input))
-    return 0;
-
-  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
-    {
-      if (unformat (line_input, "%U", unformat_ip4_address, &pfx.fp_addr.ip4))
-	{
-	  pfx.fp_proto = FIB_PROTOCOL_IP4;
-	  pfx.fp_len = 32;
-	  addr_set = 1;
-	}
-      else if (unformat (line_input, "%U",
-			 unformat_ip6_address, &pfx.fp_addr.ip6))
-	{
-	  pfx.fp_proto = FIB_PROTOCOL_IP6;
-	  pfx.fp_len = 128;
-	  addr_set = 1;
-	}
-      else if (unformat (line_input, "%U",
-			 unformat_vnet_sw_interface, vnm, &sw_if_index))
-	;
-      else if (unformat (line_input, "del"))
-	is_del = 1;
-      else
-	{
-	  unformat_free (line_input);
-	  return (clib_error_return (0, "unknown input '%U'",
-				     format_unformat_error, line_input));
-	}
-    }
-
-  if (~0 == sw_if_index || !addr_set)
-    {
-      unformat_free (line_input);
-      vlib_cli_output (vm, "interface and address must be set");
-      return 0;
-    }
-
-  vnet_ip_container_proxy_args_t args = {
-    .prefix = pfx,
-    .sw_if_index = sw_if_index,
-    .is_add = !is_del,
-  };
-  vnet_ip_container_proxy_add_del (&args);
-  unformat_free (line_input);
-  return (NULL);
-}
-
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (ip_container_command_node, static) = {
-  .path = "ip container",
-  .function = ip_container_cmd,
-  .short_help = "ip container <address> <interface>",
-  .is_mp_safe = 1,
-};
-/* *INDENT-ON* */
-
-clib_error_t *
-show_ip_container_cmd_fn (vlib_main_t * vm, unformat_input_t * main_input,
-			  vlib_cli_command_t * cmd)
-{
-  unformat_input_t _line_input, *line_input = &_line_input;
-  vnet_main_t *vnm = vnet_get_main ();
-  fib_prefix_t pfx;
-  u32 sw_if_index = ~0;
-  u8 has_proxy;
-
-  if (!unformat_user (main_input, unformat_line_input, line_input))
-    return 0;
-  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
-    {
-      if (unformat (line_input, "%U", unformat_ip4_address, &pfx.fp_addr.ip4))
-	{
-	  pfx.fp_proto = FIB_PROTOCOL_IP4;
-	  pfx.fp_len = 32;
-	}
-      else if (unformat (line_input, "%U",
-			 unformat_ip6_address, &pfx.fp_addr.ip6))
-	{
-	  pfx.fp_proto = FIB_PROTOCOL_IP6;
-	  pfx.fp_len = 128;
-	}
-      else if (unformat (line_input, "%U",
-			 unformat_vnet_sw_interface, vnm, &sw_if_index))
-	;
-      else
-	{
-	  unformat_free (line_input);
-	  return (clib_error_return (0, "unknown input '%U'",
-				     format_unformat_error, line_input));
-	}
-    }
-
-  if (~0 == sw_if_index)
-    {
-      unformat_free (line_input);
-      vlib_cli_output (vm, "no interface");
-      return (clib_error_return (0, "no interface"));
-    }
-
-  has_proxy = ip_container_proxy_is_set (&pfx, sw_if_index);
-  vlib_cli_output (vm, "ip container proxy is: %s", has_proxy ? "on" : "off");
-
-  unformat_free (line_input);
-  return 0;
-}
-
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (show_ip_container_command, static) = {
-  .path = "show ip container",
-  .function = show_ip_container_cmd_fn,
-  .short_help = "show ip container <address> <interface>",
-  .is_mp_safe = 1,
-};
-/* *INDENT-ON* */
-
 /*
  * fd.io coding-style-patch-verification: ON
  *
diff --git a/src/vnet/ip/lookup.h b/src/vnet/ip/lookup.h
index 49ed0bb..48ba468 100644
--- a/src/vnet/ip/lookup.h
+++ b/src/vnet/ip/lookup.h
@@ -48,40 +48,16 @@
 #ifndef included_ip_lookup_h
 #define included_ip_lookup_h
 
-#include <vnet/vnet.h>
+//#include <vnet/vnet.h>
+#include <vlib/vlib.h>
 #include <vlib/buffer.h>
 #include <vnet/ip/ip4_packet.h>
 #include <vnet/ip/ip6_packet.h>
+#include <vnet/ip/ip_types.h>
 #include <vnet/fib/fib_node.h>
 #include <vnet/adj/adj.h>
 #include <vnet/dpo/dpo.h>
-#include <vnet/feature/feature.h>
-
-/** Flow hash configuration */
-#define IP_FLOW_HASH_SRC_ADDR (1<<0)
-#define IP_FLOW_HASH_DST_ADDR (1<<1)
-#define IP_FLOW_HASH_PROTO (1<<2)
-#define IP_FLOW_HASH_SRC_PORT (1<<3)
-#define IP_FLOW_HASH_DST_PORT (1<<4)
-#define IP_FLOW_HASH_REVERSE_SRC_DST (1<<5)
-#define IP_FLOW_HASH_SYMMETRIC (1<<6)
-
-/** Default: 5-tuple without the "reverse" bit */
-#define IP_FLOW_HASH_DEFAULT (0x1F)
-
-#define foreach_flow_hash_bit                   \
-_(src, IP_FLOW_HASH_SRC_ADDR)                   \
-_(dst, IP_FLOW_HASH_DST_ADDR)                   \
-_(sport, IP_FLOW_HASH_SRC_PORT)                 \
-_(dport, IP_FLOW_HASH_DST_PORT)                 \
-_(proto, IP_FLOW_HASH_PROTO)	                \
-_(reverse, IP_FLOW_HASH_REVERSE_SRC_DST)	\
-_(symmetric, IP_FLOW_HASH_SYMMETRIC)
-
-/**
- * A flow hash configuration is a mask of the flow hash options
- */
-typedef u32 flow_hash_config_t;
+///#include <vnet/feature/feature.h>
 
 /* An all zeros address */
 extern const ip46_address_t zero_addr;
@@ -202,20 +178,6 @@
   /* *INDENT-ON* */
 }
 
-typedef struct _vnet_ip_container_proxy_args
-{
-  fib_prefix_t prefix;
-  u32 sw_if_index;
-  u8 is_add;
-} vnet_ip_container_proxy_args_t;
-
-clib_error_t *vnet_ip_container_proxy_add_del (vnet_ip_container_proxy_args_t
-					       * args);
-
-typedef int (*ip_container_proxy_cb_t) (const fib_prefix_t * pfx,
-					u32 sw_if_index, void *ctx);
-void ip_container_proxy_walk (ip_container_proxy_cb_t cb, void *ctx);
-
 void ip_lookup_init (ip_lookup_main_t * lm, u32 ip_lookup_node_index);
 
 #endif /* included_ip_lookup_h */
diff --git a/src/vnet/ip/vtep.h b/src/vnet/ip/vtep.h
index 345b6db..0fdc4c5 100644
--- a/src/vnet/ip/vtep.h
+++ b/src/vnet/ip/vtep.h
@@ -18,8 +18,7 @@
 
 #include <vppinfra/hash.h>
 #include <vnet/ip/ip.h>
-#include <vnet/ip/ip4.h>
-#include <vnet/ip/ip6.h>
+#include <vnet/ip/ip46_address.h>
 
 /**
  * @brief Tunnel endpoint key (IPv4)