aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/l2/l2_input_vtr.c
blob: ded23095849efd335d0630a0677d24e5714118c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133<
/*
 * 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.
 */
/*
 * global_funcs.h: global data structure access functions
 */

#ifndef included_vlib_global_funcs_h_
#define included_vlib_global_funcs_h_

always_inline u32
vlib_get_n_threads ()
{
  return vec_len (vlib_global_main.vlib_mains);
}

always_inline vlib_main_t *
vlib_get_main_by_index (u32 thread_index)
{
  vlib_main_t *vm;
  vm = vlib_global_main.vlib_mains[thread_index];
  ASSERT (vm);
  return vm;
}

always_inline vlib_main_t *
vlib_get_main (void)
{
  return vlib_get_main_by_index (vlib_get_thread_index ());
}

always_inline vlib_main_t *
vlib_get_first_main (void)
{
  return vlib_get_main_by_index (0);
}

always_inline vlib_global_main_t *
vlib_get_global_main (void)
{
  return &vlib_global_main;
}

always_inline vlib_thread_main_t *
vlib_get_thread_main ()
{
  return &vlib_thread_main.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/*
 * l2_input_vtr.c : layer 2 input vlan tag rewrite processing
 *
 * Copyright (c) 2013 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.
 */

#include <vlib/vlib.h>
#include <vnet/vnet.h>
#include <vnet/ethernet/ethernet.h>
#include <vnet/ethernet/packet.h>
#include <vnet/l2/l2_input.h>
#include <vnet/l2/feat_bitmap.h>
#include <vnet/l2/l2_vtr.h>
#include <vnet/l2/l2_input_vtr.h>
#include <vnet/l2/l2_output.h>

#include <vppinfra/error.h>
#include <vppinfra/cache.h>


typedef struct
{
  /* per-pkt trace data */
  u8 src[6];
  u8 dst[6];
  u8 raw[12];			/* raw data (vlans) */
  u32 sw_if_index;
} l2_invtr_trace_t;

/* packet trace format function */
static u8 *
format_l2_invtr_trace (u8 * s, va_list * args)
{
  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
  l2_invtr_trace_t *t = va_arg (*args, l2_invtr_trace_t *);

  s = format (s, "l2-input-vtr: sw_if_index %d dst %U src %U data "
	      "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
	      t->sw_if_index,
	      format_ethernet_address, t->dst,
	      format_ethernet_address, t->src,
	      t->raw[0], t->raw[1], t->raw[2], t->raw[3], t->raw[4],
	      t->raw[5], t->raw[6], t->raw[7], t->raw[8], t->raw[9],
	      t->raw[10], t->raw[11]);
  return s;
}

l2_invtr_main_t l2_invtr_main;

static vlib_node_registration_t l2_invtr_node;

#define foreach_l2_invtr_error			\
_(L2_INVTR,    "L2 inverter packets")		\
_(DROP,        "L2 input tag rewrite drops")

typedef enum
{
#define _(sym,str) L2_INVTR_ERROR_##sym,
  foreach_l2_invtr_error
#undef _
    L2_INVTR_N_ERROR,
} l2_invtr_error_t;

static char *l2_invtr_error_strings[] = {
#define _(sym,string) string,
  foreach_l2_invtr_error
#undef _
};

typedef enum
{
  L2_INVTR_NEXT_DROP,
  L2_INVTR_N_NEXT,
} l2_invtr_next_t;


static uword
l2_invtr_node_fn (vlib_main_t * vm,
		  vlib_node_runtime_t * node, vlib_frame_t * frame)
{
  u32 n_left_from, *from, *to_next;
  l2_invtr_next_t next_index;
  l2_invtr_main_t *msm = &l2_invtr_main;

  from = vlib_frame_vector_args (frame);
  n_left_from = frame->n_vectors;	/* number of packets to process */
  next_index = node->cached_next_index;

  while (n_left_from > 0)
    {
      u32 n_left_to_next;

      /* get space to enqueue frame to graph node "next_index" */
      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);

      while (n_left_from >= 6 && n_left_to_next >= 2)
	{
	  u32 bi0, bi1;
	  vlib_buffer_t *b0, *b1;
	  u32 next0, next1;
	  u32 sw_if_index0, sw_if_index1;
	  u32 feature_bitmap0, feature_bitmap1;

	  /* Prefetch next iteration. */
	  {
	    vlib_buffer_t *p2, *p3, *p4, *p5;
	    u32 sw_if_index2, sw_if_index3;

	    p2 = vlib_get_buffer (vm, from[2]);
	    p3 = vlib_get_buffer (vm, from[3]);
	    p4 = vlib_get_buffer (vm, from[4]);
	    p5 = vlib_get_buffer (vm, from[5]);

	    /* Prefetch the buffer header and packet for the N+2 loop iteration */
	    vlib_prefetch_buffer_header (p4, LOAD);
	    vlib_prefetch_buffer_header (p5, LOAD);

	    CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
	    CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);

	    /*
	     * Prefetch the input config for the N+1 loop iteration
	     * This depends on the buffer header above
	     */
	    sw_if_index2 = vnet_buffer (p2)->sw_if_index[VLIB_RX];
	    sw_if_index3 = vnet_buffer (p3)->sw_if_index[VLIB_RX];
	    CLIB_PREFETCH (vec_elt_at_index
			   (l2output_main.configs, sw_if_index2),
			   CLIB_CACHE_LINE_BYTES, LOAD);
	    CLIB_PREFETCH (vec_elt_at_index
			   (l2output_main.configs, sw_if_index3),
			   CLIB_CACHE_LINE_BYTES, LOAD);
	  }

	  /* speculatively enqueue b0 and b1 to the current next frame */
	  /* bi is "buffer index", b is pointer to the buffer */
	  to_next[0] = bi0 = from[0];
	  to_next[1] = bi1 = from[1];
	  from += 2;
	  to_next += 2;
	  n_left_from -= 2;
	  n_left_to_next -= 2;

	  b0 = vlib_get_buffer (vm, bi0);
	  b1 = vlib_get_buffer (vm, bi1);

	  /* RX interface handles */
	  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
	  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];

	  /* process 2 packets */

	  /* Remove ourself from the feature bitmap */
	  feature_bitmap0 =
	    vnet_buffer (b0)->l2.feature_bitmap & ~L2INPUT_FEAT_VTR;
	  feature_bitmap1 =
	    vnet_buffer (b1)->l2.feature_bitmap & ~L2INPUT_FEAT_VTR;

	  /* save for next feature graph nodes */
	  vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap0;
	  vnet_buffer (b1)->l2.feature_bitmap = feature_bitmap1;

	  /* Determine the next node */
	  next0 = feat_bitmap_get_next_node_index (msm->feat_next_node_index,
						   feature_bitmap0);
	  next1 = feat_bitmap_get_next_node_index (msm->feat_next_node_index,
						   feature_bitmap1);

	  l2_output_config_t *config0;
	  l2_output_config_t *config1;
	  config0 = vec_elt_at_index (l2output_main.configs, sw_if_index0);
	  config1 = vec_elt_at_index (l2output_main.configs, sw_if_index1);

	  if (PREDICT_FALSE (config0->out_vtr_flag))
	    {
	      if (config0->output_vtr.push_and_pop_bytes)
		{
		  /* perform the tag rewrite on two packets */
		  if (l2_vtr_process (b0, &config0->input_vtr))
		    {
		      /* Drop packet */
		      next0 = L2_INVTR_NEXT_DROP;
		      b0->error = node->errors[L2_INVTR_ERROR_DROP];
		    }
		}
	      else if (config0->output_pbb_vtr.push_and_pop_bytes)
		{
		  if (l2_pbb_process (b0, &(config0->input_pbb_vtr)))
		    {
		      /* Drop packet */
		      next0 = L2_INVTR_NEXT_DROP;
		      b0->error = node->errors[L2_INVTR_ERROR_DROP];
		    }
		}
	    }
	  if (PREDICT_FALSE (config1->out_vtr_flag))
	    {
	      if (config1->output_vtr.push_and_pop_bytes)
		{
		  if (l2_vtr_process (b1, &config1->input_vtr))
		    {
		      /* Drop packet */
		      next1 = L2_INVTR_NEXT_DROP;
		      b1->error = node->errors[L2_INVTR_ERROR_DROP];
		    }
		}
	      else if (config1->output_pbb_vtr.push_and_pop_bytes)
		{
		  if (l2_pbb_process (b1, &(config1->input_pbb_vtr)))
		    {
		      /* Drop packet */
		      next1 = L2_INVTR_NEXT_DROP;
		      b1->error = node->errors[L2_INVTR_ERROR_DROP];
		    }
		}
	    }

	  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
	    {
	      if (b0->flags & VLIB_BUFFER_IS_TRACED)
		{
		  l2_invtr_trace_t *t =
		    vlib_add_trace (vm, node, b0, sizeof (*t));
		  ethernet_header_t *h0 = vlib_buffer_get_current (b0);
		  t->sw_if_index = sw_if_index0;
		  clib_memcpy (t->src, h0->src_address, 6);
		  clib_memcpy (t->dst, h0->dst_address, 6);
		  clib_memcpy (t->raw, &h0->type, sizeof (t->raw));
		}
	      if (b1->flags & VLIB_BUFFER_IS_TRACED)
		{
		  l2_invtr_trace_t *t =
		    vlib_add_trace (vm, node, b1, sizeof (*t));
		  ethernet_header_t *h1 = vlib_buffer_get_current (b1);
		  t->sw_if_index = sw_if_index0;
		  clib_memcpy (t->src, h1->src_address, 6);
		  clib_memcpy (t->dst, h1->dst_address, 6);
		  clib_memcpy (t->raw, &h1->type, sizeof (t->raw));
		}
	    }

	  /* verify speculative enqueues, maybe switch current next frame */
	  /* if next0==next1==next_index then nothing special needs to be done */
	  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
					   to_next, n_left_to_next,
					   bi0, bi1, next0, next1);
	}

      while (n_left_from > 0 && n_left_to_next > 0)
	{
	  u32 bi0;
	  vlib_buffer_t *b0;
	  u32 next0;
	  u32 sw_if_index0;
	  u32 feature_bitmap0;

	  /* speculatively enqueue b0 to the current next frame */
	  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);

	  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];

	  /* process 1 packet */

	  /* Remove ourself from the feature bitmap */
	  feature_bitmap0 =
	    vnet_buffer (b0)->l2.feature_bitmap & ~L2INPUT_FEAT_VTR;

	  /* save for next feature graph nodes */
	  vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap0;

	  /* Determine the next node */
	  next0 = feat_bitmap_get_next_node_index (msm->feat_next_node_index,
						   feature_bitmap0);

	  l2_output_config_t *config0;
	  config0 = vec_elt_at_index (l2output_main.configs, sw_if_index0);

	  if (PREDICT_FALSE (config0->out_vtr_flag))
	    {
	      if (config0->output_vtr.push_and_pop_bytes)
		{
		  /* perform the tag rewrite on one packet */
		  if (l2_vtr_process (b0, &config0->input_vtr))
		    {
		      /* Drop packet */
		      next0 = L2_INVTR_NEXT_DROP;
		      b0->error = node->errors[L2_INVTR_ERROR_DROP];
		    }
		}
	      else if (config0->output_pbb_vtr.push_and_pop_bytes)
		{
		  if (l2_pbb_process (b0, &(config0->input_pbb_vtr)))
		    {
		      /* Drop packet */
		      next0 = L2_INVTR_NEXT_DROP;
		      b0->error = node->errors[L2_INVTR_ERROR_DROP];
		    }
		}
	    }

	  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
			     && (b0->flags & VLIB_BUFFER_IS_TRACED)))
	    {
	      l2_invtr_trace_t *t =
		vlib_add_trace (vm, node, b0, sizeof (*t));
	      ethernet_header_t *h0 = vlib_buffer_get_current (b0);
	      t->sw_if_index = sw_if_index0;
	      clib_memcpy (t->src, h0->src_address, 6);
	      clib_memcpy (t->dst, h0->dst_address, 6);
	      clib_memcpy (t->raw, &h0->type, sizeof (t->raw));
	    }

	  /* verify speculative enqueue, maybe switch current next frame */
	  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
					   to_next, n_left_to_next,
					   bi0, next0);
	}

      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    }

  return frame->n_vectors;
}


/* *INDENT-OFF* */
VLIB_REGISTER_NODE (l2_invtr_node,static) = {
  .function = l2_invtr_node_fn,
  .name = "l2-input-vtr",
  .vector_size = sizeof (u32),
  .format_trace = format_l2_invtr_trace,
  .type = VLIB_NODE_TYPE_INTERNAL,

  .n_errors = ARRAY_LEN(l2_invtr_error_strings),
  .error_strings = l2_invtr_error_strings,

  .n_next_nodes = L2_INVTR_N_NEXT,

  /* edit / add dispositions here */
  .next_nodes = {
       [L2_INVTR_NEXT_DROP]  = "error-drop",
  },
};
/* *INDENT-ON* */

VLIB_NODE_FUNCTION_MULTIARCH (l2_invtr_node, l2_invtr_node_fn)
     clib_error_t *l2_invtr_init (vlib_main_t * vm)
{
  l2_invtr_main_t *mp = &l2_invtr_main;

  mp->vlib_main = vm;
  mp->vnet_main = vnet_get_main ();

  /* Initialize the feature next-node indexes */
  feat_bitmap_init_next_nodes (vm,
			       l2_invtr_node.index,
			       L2INPUT_N_FEAT,
			       l2input_get_feat_names (),
			       mp->feat_next_node_index);

  return 0;
}

VLIB_INIT_FUNCTION (l2_invtr_init);


/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */