srv6-mobile
[vpp.git] / src / plugins / srv6-ad / node.c
index 2985196..dbd68cf 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * node.c
+ *
  * 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.
@@ -12,6 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include <vlib/vlib.h>
 #include <vnet/vnet.h>
 #include <vppinfra/error.h>
@@ -92,6 +95,7 @@ typedef enum
   SRV6_AD_LOCALSID_NEXT_ERROR,
   SRV6_AD_LOCALSID_NEXT_REWRITE4,
   SRV6_AD_LOCALSID_NEXT_REWRITE6,
+  SRV6_AD_LOCALSID_NEXT_INTERFACE,
   SRV6_AD_LOCALSID_N_NEXT,
 } srv6_ad_localsid_next_t;
 
@@ -149,9 +153,10 @@ end_ad_processing (vlib_buffer_t * b0,
       next_ext_header = ip6_ext_next_header (next_ext_header);
     }
 
-  /* Make sure next header is IP */
-  if (PREDICT_FALSE
-      (next_hdr != IP_PROTOCOL_IPV6 && next_hdr != IP_PROTOCOL_IP_IN_IP))
+  /* Make sure next header is valid */
+  if (PREDICT_FALSE (next_hdr != IP_PROTOCOL_IPV6 &&
+                    next_hdr != IP_PROTOCOL_IP_IN_IP &&
+                    next_hdr != IP_PROTOCOL_IP6_NONXT))
     {
       return;
     }
@@ -164,19 +169,29 @@ end_ad_processing (vlib_buffer_t * b0,
     {
       vec_validate (ls0_mem->rewrite, total_size - 1);
     }
-  clib_memcpy (ls0_mem->rewrite, ip0, total_size);
+  clib_memcpy_fast (ls0_mem->rewrite, ip0, total_size);
   ls0_mem->rw_len = total_size;
 
   /* Remove IP header and extensions */
   vlib_buffer_advance (b0, total_size);
 
-  /* Set Xconnect adjacency to VNF */
-  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0_mem->nh_adj;
+  if (next_hdr == IP_PROTOCOL_IP6_NONXT)
+    {
+      /* Set output interface */
+      vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0_mem->sw_if_index_out;
 
-  if (ls0_mem->ip_version == DA_IP4)
-    *next0 = SRV6_AD_LOCALSID_NEXT_REWRITE4;
-  else if (ls0_mem->ip_version == DA_IP6)
-    *next0 = SRV6_AD_LOCALSID_NEXT_REWRITE6;
+      /* Set next node to interface-output */
+      *next0 = SRV6_AD_LOCALSID_NEXT_INTERFACE;
+    }
+  else
+    {
+      /* Set Xconnect adjacency to VNF */
+      vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0_mem->nh_adj;
+
+      /* Set next node to ip-rewrite */
+      *next0 = (next_hdr == IP_PROTOCOL_IPV6) ?
+       SRV6_AD_LOCALSID_NEXT_REWRITE6 : SRV6_AD_LOCALSID_NEXT_REWRITE4;
+    }
 }
 
 /**
@@ -194,8 +209,6 @@ srv6_ad_localsid_fn (vlib_main_t * vm,
   n_left_from = frame->n_vectors;
   next_index = node->cached_next_index;
 
-  u32 thread_index = vm->thread_index;
-
   while (n_left_from > 0)
     {
       u32 n_left_to_next;
@@ -243,9 +256,10 @@ srv6_ad_localsid_fn (vlib_main_t * vm,
                                             SRV6_AD_LOCALSID_NEXT_ERROR) ?
                                            &(sm->sr_ls_invalid_counters) :
                                            &(sm->sr_ls_valid_counters)),
-                                          thread_index, ls0 - sm->localsids,
-                                          1, vlib_buffer_length_in_chain (vm,
-                                                                          b0));
+                                          vm->thread_index,
+                                          ls0 - sm->localsids, 1,
+                                          vlib_buffer_length_in_chain (vm,
+                                                                       b0));
 
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
                                           n_left_to_next, bi0, next0);
@@ -270,6 +284,7 @@ VLIB_REGISTER_NODE (srv6_ad_localsid_node) = {
   .next_nodes = {
     [SRV6_AD_LOCALSID_NEXT_REWRITE4] = "ip4-rewrite",
     [SRV6_AD_LOCALSID_NEXT_REWRITE6] = "ip6-rewrite",
+    [SRV6_AD_LOCALSID_NEXT_INTERFACE] = "interface-output",
     [SRV6_AD_LOCALSID_NEXT_ERROR] = "error-drop",
   },
 };
@@ -278,6 +293,140 @@ VLIB_REGISTER_NODE (srv6_ad_localsid_node) = {
 
 /******************************* Rewriting node *******************************/
 
+/**
+ * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
+ */
+static uword
+srv6_ad2_rewrite_fn (vlib_main_t * vm,
+                    vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  ip6_sr_main_t *srm = &sr_main;
+  srv6_ad_main_t *sm = &srv6_ad_main;
+  u32 n_left_from, next_index, *from, *to_next;
+  u32 cnt_packets = 0;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+
+  while (n_left_from > 0)
+    {
+      u32 n_left_to_next;
+
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      /* TODO: Dual/quad loop */
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         u32 bi0;
+         vlib_buffer_t *b0;
+         ethernet_header_t *en0;
+         ip6_header_t *ip0 = 0;
+         ip6_sr_localsid_t *ls0;
+         srv6_ad_localsid_t *ls0_mem;
+         u32 next0 = SRV6_AD_REWRITE_NEXT_LOOKUP;
+
+         bi0 = from[0];
+         to_next[0] = bi0;
+         from += 1;
+         to_next += 1;
+         n_left_from -= 1;
+         n_left_to_next -= 1;
+
+         b0 = vlib_get_buffer (vm, bi0);
+         en0 = vlib_buffer_get_current (b0);
+         ls0 = pool_elt_at_index (srm->localsids,
+                                  sm->sw_iface_localsid2[vnet_buffer
+                                                         (b0)->sw_if_index
+                                                         [VLIB_RX]]);
+         ls0_mem = ls0->plugin_mem;
+
+         if (PREDICT_FALSE (ls0_mem == NULL || ls0_mem->rewrite == NULL))
+           {
+             next0 = SRV6_AD_REWRITE_NEXT_ERROR;
+             b0->error = node->errors[SRV6_AD_REWRITE_COUNTER_NO_RW];
+           }
+         else
+           {
+             ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
+                     (ls0_mem->rw_len + b0->current_data));
+
+             clib_memcpy_fast (((u8 *) en0) - ls0_mem->rw_len,
+                               ls0_mem->rewrite, ls0_mem->rw_len);
+             vlib_buffer_advance (b0, -(word) ls0_mem->rw_len);
+
+             ip0 = vlib_buffer_get_current (b0);
+
+             ip0->payload_length =
+               clib_host_to_net_u16 (b0->current_length -
+                                     sizeof (ip6_header_t));
+           }
+
+         if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
+             PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+           {
+             srv6_ad_rewrite_trace_t *tr =
+               vlib_add_trace (vm, node, b0, sizeof *tr);
+             tr->error = 0;
+
+             if (next0 == SRV6_AD_REWRITE_NEXT_ERROR)
+               {
+                 tr->error = 1;
+               }
+             else
+               {
+                 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
+                                   sizeof tr->src.as_u8);
+                 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
+                                   sizeof tr->dst.as_u8);
+               }
+           }
+
+         /* Increment per-SID AD rewrite counters */
+         vlib_increment_combined_counter (((next0 ==
+                                            SRV6_AD_LOCALSID_NEXT_ERROR) ?
+                                           &(sm->invalid_counters) :
+                                           &(sm->valid_counters)),
+                                          vm->thread_index, ls0_mem->index,
+                                          1, vlib_buffer_length_in_chain (vm,
+                                                                          b0));
+
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, next0);
+
+         cnt_packets++;
+       }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  /* Update counters */
+  vlib_node_increment_counter (vm, srv6_ad4_rewrite_node.index,
+                              SRV6_AD_REWRITE_COUNTER_PROCESSED,
+                              cnt_packets);
+
+  return frame->n_vectors;
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (srv6_ad2_rewrite_node) = {
+  .function = srv6_ad2_rewrite_fn,
+  .name = "srv6-ad2-rewrite",
+  .vector_size = sizeof (u32),
+  .format_trace = format_srv6_ad_rewrite_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = SRV6_AD_REWRITE_N_COUNTERS,
+  .error_strings = srv6_ad_rewrite_counter_strings,
+  .n_next_nodes = SRV6_AD_REWRITE_N_NEXT,
+  .next_nodes = {
+    [SRV6_AD_REWRITE_NEXT_LOOKUP] = "ip6-lookup",
+    [SRV6_AD_REWRITE_NEXT_ERROR] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+
 /**
  * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
  */
@@ -338,8 +487,8 @@ srv6_ad4_rewrite_fn (vlib_main_t * vm,
              ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
                      (ls0_mem->rw_len + b0->current_data));
 
-             clib_memcpy (((u8 *) ip0_encap) - ls0_mem->rw_len,
-                          ls0_mem->rewrite, ls0_mem->rw_len);
+             clib_memcpy_fast (((u8 *) ip0_encap) - ls0_mem->rw_len,
+                               ls0_mem->rewrite, ls0_mem->rw_len);
              vlib_buffer_advance (b0, -(word) ls0_mem->rw_len);
 
              ip0 = vlib_buffer_get_current (b0);
@@ -370,13 +519,22 @@ srv6_ad4_rewrite_fn (vlib_main_t * vm,
                }
              else
                {
-                 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
-                              sizeof tr->src.as_u8);
-                 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
-                              sizeof tr->dst.as_u8);
+                 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
+                                   sizeof tr->src.as_u8);
+                 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
+                                   sizeof tr->dst.as_u8);
                }
            }
 
+         /* Increment per-SID AD rewrite counters */
+         vlib_increment_combined_counter (((next0 ==
+                                            SRV6_AD_LOCALSID_NEXT_ERROR) ?
+                                           &(sm->invalid_counters) :
+                                           &(sm->valid_counters)),
+                                          vm->thread_index, ls0_mem->index,
+                                          1, vlib_buffer_length_in_chain (vm,
+                                                                          b0));
+
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
                                           n_left_to_next, bi0, next0);
 
@@ -471,8 +629,8 @@ srv6_ad6_rewrite_fn (vlib_main_t * vm,
              ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
                      (ls0_mem->rw_len + b0->current_data));
 
-             clib_memcpy (((u8 *) ip0_encap) - ls0_mem->rw_len,
-                          ls0_mem->rewrite, ls0_mem->rw_len);
+             clib_memcpy_fast (((u8 *) ip0_encap) - ls0_mem->rw_len,
+                               ls0_mem->rewrite, ls0_mem->rw_len);
              vlib_buffer_advance (b0, -(word) ls0_mem->rw_len);
 
              ip0 = vlib_buffer_get_current (b0);
@@ -499,13 +657,22 @@ srv6_ad6_rewrite_fn (vlib_main_t * vm,
                }
              else
                {
-                 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
-                              sizeof tr->src.as_u8);
-                 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
-                              sizeof tr->dst.as_u8);
+                 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
+                                   sizeof tr->src.as_u8);
+                 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
+                                   sizeof tr->dst.as_u8);
                }
            }
 
+         /* Increment per-SID AD rewrite counters */
+         vlib_increment_combined_counter (((next0 ==
+                                            SRV6_AD_LOCALSID_NEXT_ERROR) ?
+                                           &(sm->invalid_counters) :
+                                           &(sm->valid_counters)),
+                                          vm->thread_index, ls0_mem->index,
+                                          1, vlib_buffer_length_in_chain (vm,
+                                                                          b0));
+
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
                                           n_left_to_next, bi0, next0);
 
@@ -541,9 +708,9 @@ VLIB_REGISTER_NODE (srv6_ad6_rewrite_node) = {
 /* *INDENT-ON* */
 
 /*
-* fd.io coding-style-patch-verification: ON
-*
-* Local Variables:
-* eval: (c-set-style "gnu")
-* End:
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
 */