bonding: support custom interface IDs
[vpp.git] / src / vnet / ipip / ipip.c
index 9b808d4..a5e46c4 100644 (file)
@@ -74,6 +74,8 @@ ipip_build_rewrite (vnet_main_t * vnm, u32 sw_if_index,
       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);
+      if (t->tc_tos != 0xFF)
+       ip4->tos = t->tc_tos;
       break;
 
     case IPIP_TRANSPORT_IP6:
@@ -81,6 +83,8 @@ ipip_build_rewrite (vnet_main_t * vnm, u32 sw_if_index,
       ip6 = (ip6_header_t *) rewrite;
       ip6->ip_version_traffic_class_and_flow_label =
        clib_host_to_net_u32 (6 << 28);
+      if (t->tc_tos != 0xFF)
+       ip6_set_traffic_class_network_order (ip6, t->tc_tos);
       ip6->hop_limit = 64;
       /* fixup ip6 header length and protocol after-the-fact */
       ip6->src_address.as_u64[0] = t->tunnel_src.ip6.as_u64[0];
@@ -88,6 +92,7 @@ ipip_build_rewrite (vnet_main_t * vnm, u32 sw_if_index,
       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];
       break;
+
     default:
       /* pass through */
       ;
@@ -100,11 +105,29 @@ ipip4_fixup (vlib_main_t * vm, ip_adjacency_t * adj, vlib_buffer_t * b,
             const void *data)
 {
   ip4_header_t *ip4;
+  const ipip_tunnel_t *t = data;
 
   ip4 = vlib_buffer_get_current (b);
   ip4->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
-  ip4->protocol =
-    adj->ia_link == VNET_LINK_IP6 ? IP_PROTOCOL_IPV6 : IP_PROTOCOL_IP_IN_IP;
+  switch (adj->ia_link)
+    {
+    case VNET_LINK_IP6:
+      ip4->protocol = IP_PROTOCOL_IPV6;
+      if (t->tc_tos == 0xFF)
+       ip4->tos =
+         ip6_traffic_class_network_order ((const ip6_header_t *) (ip4 + 1));
+      break;
+
+    case VNET_LINK_IP4:
+      ip4->protocol = IP_PROTOCOL_IP_IN_IP;
+      if (t->tc_tos == 0xFF)
+       ip4->tos = ((ip4_header_t *) (ip4 + 1))->tos;
+      break;
+
+    default:
+      break;
+    }
+
   ip4->checksum = ip4_header_checksum (ip4);
 }
 
@@ -113,13 +136,36 @@ ipip6_fixup (vlib_main_t * vm, ip_adjacency_t * adj, vlib_buffer_t * b,
             const void *data)
 {
   ip6_header_t *ip6;
+  const ipip_tunnel_t *t = data;
+
+  /* Must set locally originated otherwise we're not allowed to
+     fragment the packet later */
+  b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
 
   ip6 = vlib_buffer_get_current (b);
   ip6->payload_length =
     clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b) -
                          sizeof (*ip6));
-  ip6->protocol =
-    adj->ia_link == VNET_LINK_IP6 ? IP_PROTOCOL_IPV6 : IP_PROTOCOL_IP_IN_IP;
+  switch (adj->ia_link)
+    {
+    case VNET_LINK_IP6:
+      ip6->protocol = IP_PROTOCOL_IPV6;
+      if (t->tc_tos == 0xFF)
+       ip6_set_traffic_class_network_order (ip6,
+                                            ip6_traffic_class_network_order ((const ip6_header_t *) (ip6 + 1)));
+      break;
+
+    case VNET_LINK_IP4:
+      ip6->protocol = IP_PROTOCOL_IP_IN_IP;
+      if (t->tc_tos == 0xFF)
+       ip6_set_traffic_class_network_order (ip6,
+                                            ((ip4_header_t *) (ip6 +
+                                                               1))->tos);
+      break;
+
+    default:
+      break;
+    }
 }
 
 static void
@@ -140,46 +186,15 @@ ipip_tunnel_stack (adj_index_t ai)
        VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
     {
       adj_nbr_midchain_unstack (ai);
-      return;
     }
-
-  dpo_id_t tmp = DPO_INVALID;
-  fib_forward_chain_type_t fib_fwd =
-    t->transport ==
-    IPIP_TRANSPORT_IP6 ? FIB_FORW_CHAIN_TYPE_UNICAST_IP6 :
-    FIB_FORW_CHAIN_TYPE_UNICAST_IP4;
-
-  fib_entry_contribute_forwarding (t->p2p.fib_entry_index, fib_fwd, &tmp);
-  if (DPO_LOAD_BALANCE == tmp.dpoi_type)
+  else
     {
-      /*
-       * post IPIP rewrite we will load-balance. However, the IPIP encap
-       * is always the same for this adjacency/tunnel and hence the IP/IPIP
-       * src,dst hash is always the same result too. So we do that hash now and
-       * stack on the choice.
-       * If the choice is an incomplete adj then we will need a poke when
-       * it becomes complete. This happens since the adj update walk propagates
-       * as far a recursive paths.
-       */
-      const dpo_id_t *choice;
-      load_balance_t *lb;
-      int hash;
-
-      lb = load_balance_get (tmp.dpoi_index);
-
-      if (fib_fwd == FIB_FORW_CHAIN_TYPE_UNICAST_IP4)
-       hash = ip4_compute_flow_hash ((ip4_header_t *) adj_get_rewrite (ai),
-                                     lb->lb_hash_config);
-      else
-       hash = ip6_compute_flow_hash ((ip6_header_t *) adj_get_rewrite (ai),
-                                     lb->lb_hash_config);
-      choice =
-       load_balance_get_bucket_i (lb, hash & lb->lb_n_buckets_minus_1);
-      dpo_copy (&tmp, choice);
+      adj_nbr_midchain_stack_on_fib_entry
+       (ai,
+        t->p2p.fib_entry_index,
+        (t->transport == IPIP_TRANSPORT_IP6) ?
+        FIB_FORW_CHAIN_TYPE_UNICAST_IP6 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
     }
-
-  adj_nbr_midchain_stack (ai, &tmp);
-  dpo_reset (&tmp);
 }
 
 static adj_walk_rc_t
@@ -207,24 +222,24 @@ ipip_tunnel_restack (ipip_tunnel_t * gt)
 void
 ipip_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
 {
-  ipip_tunnel_t *t;
   adj_midchain_fixup_t f;
+  ipip_tunnel_t *t;
+  adj_flags_t af;
 
   t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
   if (!t)
     return;
 
   f = t->transport == IPIP_TRANSPORT_IP6 ? ipip6_fixup : ipip4_fixup;
-
-  adj_nbr_midchain_update_rewrite (ai, f, NULL,
-                                  (VNET_LINK_ETHERNET ==
-                                   adj_get_link_type (ai) ?
-                                   ADJ_FLAG_MIDCHAIN_NO_COUNT :
-                                   ADJ_FLAG_NONE), ipip_build_rewrite (vnm,
-                                                                       sw_if_index,
-                                                                       adj_get_link_type
-                                                                       (ai),
-                                                                       NULL));
+  af = ADJ_FLAG_MIDCHAIN_IP_STACK;
+  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));
   ipip_tunnel_stack (ai);
 }
 
@@ -313,7 +328,7 @@ ipip_tunnel_t *
 ipip_tunnel_db_find_by_sw_if_index (u32 sw_if_index)
 {
   ipip_main_t *gm = &ipip_main;
-  if (vec_len (gm->tunnel_index_by_sw_if_index) < sw_if_index)
+  if (vec_len (gm->tunnel_index_by_sw_if_index) <= sw_if_index)
     return NULL;
   u32 ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
   if (ti == ~0)
@@ -420,7 +435,7 @@ ipip_fib_delete (ipip_tunnel_t * t)
 int
 ipip_add_tunnel (ipip_transport_t transport,
                 u32 instance, ip46_address_t * src, ip46_address_t * dst,
-                u32 fib_index, u32 * sw_if_indexp)
+                u32 fib_index, u8 tc_tos, u32 * sw_if_indexp)
 {
   ipip_main_t *gm = &ipip_main;
   vnet_main_t *vnm = gm->vnet_main;
@@ -439,7 +454,7 @@ ipip_add_tunnel (ipip_transport_t transport,
     return VNET_API_ERROR_IF_ALREADY_EXISTS;
 
   pool_get_aligned (gm->tunnels, t, CLIB_CACHE_LINE_BYTES);
-  memset (t, 0, sizeof (*t));
+  clib_memset (t, 0, sizeof (*t));
 
   /* Reconcile the real dev_instance and a possible requested instance */
   u32 t_idx = t - gm->tunnels; /* tunnel index (or instance) */
@@ -467,6 +482,7 @@ ipip_add_tunnel (ipip_transport_t transport,
   t->hw_if_index = hw_if_index;
   t->fib_index = fib_index;
   t->sw_if_index = sw_if_index;
+  t->tc_tos = tc_tos;
 
   t->transport = transport;
   vec_validate_init_empty (gm->tunnel_index_by_sw_if_index, sw_if_index, ~0);
@@ -476,16 +492,15 @@ ipip_add_tunnel (ipip_transport_t transport,
     {
       vec_validate (im4->fib_index_by_sw_if_index, sw_if_index);
       hi->min_packet_bytes = 64 + sizeof (ip4_header_t);
-      hi->max_packet_bytes = 65536 - sizeof (ip4_header_t);
     }
   else
     {
       vec_validate (im6->fib_index_by_sw_if_index, sw_if_index);
       hi->min_packet_bytes = 64 + sizeof (ip6_header_t);
-      hi->max_packet_bytes = 65536 - sizeof (ip6_header_t);
     }
 
-  vnet_sw_interface_set_mtu (vnm, sw_if_index, hi->max_packet_bytes);
+  /* Standard default ipip MTU. */
+  vnet_sw_interface_set_mtu (vnm, sw_if_index, 9000);
 
   t->tunnel_src = *src;
   t->tunnel_dst = *dst;
@@ -544,7 +559,7 @@ ipip_init (vlib_main_t * vm)
 {
   ipip_main_t *gm = &ipip_main;
 
-  memset (gm, 0, sizeof (gm[0]));
+  clib_memset (gm, 0, sizeof (gm[0]));
   gm->vlib_main = vm;
   gm->vnet_main = vnet_get_main ();
   gm->tunnel_by_key =