nsh_pop.c revision c323cabf
1/*
2 * nsh_pop.c - nsh POP only processing
3 *
4 * Copyright (c) 2017 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include <vnet/vnet.h>
19#include <vnet/plugin/plugin.h>
20#include <nsh/nsh.h>
21#include <vnet/gre/gre.h>
22#include <vnet/vxlan/vxlan.h>
23#include <vnet/vxlan-gpe/vxlan_gpe.h>
24#include <vnet/l2/l2_classify.h>
25
26#include <vlibapi/api.h>
27#include <vlibmemory/api.h>
28#include <vlibsocket/api.h>
29
30extern nsh_option_map_t * nsh_md2_lookup_option (u16 class, u8 type);
31
32extern u8 * format_nsh_header (u8 * s, va_list * args);
33extern u8 * format_nsh_node_map_trace (u8 * s, va_list * args);
34
35/* format from network order */
36u8 * format_nsh_pop_header (u8 * s, va_list * args)
37{
38  return format_nsh_header(s, args);
39}
40
41
42
43u8 * format_nsh_pop_node_map_trace (u8 * s, va_list * args)
44{
45  return format_nsh_node_map_trace(s, args);
46}
47
48
49static uword
50nsh_pop_inline (vlib_main_t * vm,
51               vlib_node_runtime_t * node,
52               vlib_frame_t * from_frame)
53{
54  u32 n_left_from, next_index, *from, *to_next;
55  nsh_main_t * nm = &nsh_main;
56
57  from = vlib_frame_vector_args(from_frame);
58  n_left_from = from_frame->n_vectors;
59
60  next_index = node->cached_next_index;
61
62  while (n_left_from > 0)
63    {
64      u32 n_left_to_next;
65
66      vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
67
68      while (n_left_from >= 4 && n_left_to_next >= 2)
69	{
70	  u32 bi0, bi1;
71	  vlib_buffer_t * b0, *b1;
72	  u32 next0 = NSH_NODE_NEXT_DROP, next1 = NSH_NODE_NEXT_DROP;
73	  uword * entry0, *entry1;
74	  nsh_base_header_t * hdr0 = 0, *hdr1 = 0;
75	  u32 header_len0 = 0, header_len1 = 0;
76	  u32 nsp_nsi0, nsp_nsi1;
77	  u32 error0, error1;
78	  nsh_map_t * map0 = 0, *map1 = 0;
79
80	  /* Prefetch next iteration. */
81	  {
82	    vlib_buffer_t * p2, *p3;
83
84	    p2 = vlib_get_buffer(vm, from[2]);
85	    p3 = vlib_get_buffer(vm, from[3]);
86
87	    vlib_prefetch_buffer_header(p2, LOAD);
88	    vlib_prefetch_buffer_header(p3, LOAD);
89
90	    CLIB_PREFETCH(p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
91	    CLIB_PREFETCH(p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
92	  }
93
94	  bi0 = from[0];
95	  bi1 = from[1];
96	  to_next[0] = bi0;
97	  to_next[1] = bi1;
98	  from += 2;
99	  to_next += 2;
100	  n_left_from -= 2;
101	  n_left_to_next -= 2;
102
103	  error0 = 0;
104	  error1 = 0;
105
106	  b0 = vlib_get_buffer(vm, bi0);
107	  b1 = vlib_get_buffer(vm, bi1);
108	  hdr0 = vlib_buffer_get_current(b0);
109          nsp_nsi0 = hdr0->nsp_nsi;
110          header_len0 = hdr0->length * 4;
111
112          hdr1 = vlib_buffer_get_current(b1);
113	  nsp_nsi1 = hdr1->nsp_nsi;
114	  header_len1 = hdr1->length * 4;
115
116	  /* Process packet 0 */
117	  entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
118	  if (PREDICT_FALSE(entry0 == 0))
119	    {
120	      error0 = NSH_NODE_ERROR_NO_MAPPING;
121	      goto trace0;
122	    }
123
124	  /* Entry should point to a mapping ...*/
125	  map0 = pool_elt_at_index(nm->nsh_mappings, entry0[0]);
126	  if (PREDICT_FALSE(map0 == 0))
127	    {
128	      error0 = NSH_NODE_ERROR_NO_MAPPING;
129	      goto trace0;
130	    }
131
132	  /* set up things for next node to transmit ie which node to handle it and where */
133	  next0 = map0->next_node;
134	  //vnet_buffer(b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
135
136	  if(PREDICT_FALSE(map0->nsh_action == NSH_ACTION_POP))
137	    {
138	      /* Manipulate MD2 */
139              if(PREDICT_FALSE(hdr0->md_type == 2))
140        	{
141        	  if (PREDICT_FALSE(next0 == NSH_NODE_NEXT_DROP))
142        	    {
143        	      error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
144        	      goto trace0;
145        	    }
146	          //vnet_buffer(b0)->sw_if_index[VLIB_RX] = map0->sw_if_index;
147        	}
148
149              /* Pop NSH header */
150	      vlib_buffer_advance(b0, (word)header_len0);
151	      goto trace0;
152	    }
153
154	  entry0 = hash_get_mem(nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
155	  if (PREDICT_FALSE(entry0 == 0))
156	    {
157	      error0 = NSH_NODE_ERROR_NO_ENTRY;
158	      goto trace0;
159	    }
160
161        trace0: b0->error = error0 ? node->errors[error0] : 0;
162
163          if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
164            {
165              nsh_input_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
166              clib_memcpy ( &(tr->trace_data), hdr0, (hdr0->length*4) );
167            }
168
169	  /* Process packet 1 */
170	  entry1 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi1);
171	  if (PREDICT_FALSE(entry1 == 0))
172	    {
173	      error1 = NSH_NODE_ERROR_NO_MAPPING;
174	      goto trace1;
175	    }
176
177	  /* Entry should point to a mapping ...*/
178	  map1 = pool_elt_at_index(nm->nsh_mappings, entry1[0]);
179	  if (PREDICT_FALSE(map1 == 0))
180	    {
181	      error1 = NSH_NODE_ERROR_NO_MAPPING;
182	      goto trace1;
183	    }
184
185	  /* set up things for next node to transmit ie which node to handle it and where */
186	  next1 = map1->next_node;
187	  //vnet_buffer(b1)->sw_if_index[VLIB_TX] = map1->sw_if_index;
188
189	  if(PREDICT_FALSE(map1->nsh_action == NSH_ACTION_POP))
190	    {
191	      /* Manipulate MD2 */
192              if(PREDICT_FALSE(hdr1->md_type == 2))
193        	{
194        	  if (PREDICT_FALSE(next1 == NSH_NODE_NEXT_DROP))
195        	    {
196        	      error1 = NSH_NODE_ERROR_INVALID_OPTIONS;
197        	      goto trace1;
198        	    }
199	          //vnet_buffer(b1)->sw_if_index[VLIB_RX] = map1->sw_if_index;
200        	}
201
202              /* Pop NSH header */
203	      vlib_buffer_advance(b1, (word)header_len1);
204	      goto trace1;
205	    }
206
207	  entry1 = hash_get_mem(nm->nsh_entry_by_key, &map1->mapped_nsp_nsi);
208	  if (PREDICT_FALSE(entry1 == 0))
209	    {
210	      error1 = NSH_NODE_ERROR_NO_ENTRY;
211	      goto trace1;
212	    }
213
214
215	trace1: b1->error = error1 ? node->errors[error1] : 0;
216
217	  if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
218	    {
219	      nsh_input_trace_t *tr = vlib_add_trace(vm, node, b1, sizeof(*tr));
220	      clib_memcpy ( &(tr->trace_data), hdr1, (hdr1->length*4) );
221	    }
222
223	  vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
224					  n_left_to_next, bi0, bi1, next0, next1);
225
226	}
227
228      while (n_left_from > 0 && n_left_to_next > 0)
229	{
230	  u32 bi0 = 0;
231	  vlib_buffer_t * b0 = NULL;
232	  u32 next0 = NSH_NODE_NEXT_DROP;
233	  uword * entry0;
234	  nsh_base_header_t * hdr0 = 0;
235	  u32 header_len0 = 0;
236	  u32 nsp_nsi0;
237	  u32 error0;
238	  nsh_map_t * map0 = 0;
239
240	  bi0 = from[0];
241	  to_next[0] = bi0;
242	  from += 1;
243	  to_next += 1;
244	  n_left_from -= 1;
245	  n_left_to_next -= 1;
246	  error0 = 0;
247
248	  b0 = vlib_get_buffer(vm, bi0);
249	  hdr0 = vlib_buffer_get_current(b0);
250
251          nsp_nsi0 = hdr0->nsp_nsi;
252          header_len0 = hdr0->length * 4;
253
254	  entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
255
256	  if (PREDICT_FALSE(entry0 == 0))
257	    {
258	      error0 = NSH_NODE_ERROR_NO_MAPPING;
259	      goto trace00;
260	    }
261
262	  /* Entry should point to a mapping ...*/
263	  map0 = pool_elt_at_index(nm->nsh_mappings, entry0[0]);
264
265	  if (PREDICT_FALSE(map0 == 0))
266	    {
267	      error0 = NSH_NODE_ERROR_NO_MAPPING;
268	      goto trace00;
269	    }
270
271	  /* set up things for next node to transmit ie which node to handle it and where */
272	  next0 = map0->next_node;
273	  //vnet_buffer(b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
274
275	  if(PREDICT_FALSE(map0->nsh_action == NSH_ACTION_POP))
276	    {
277	      /* Manipulate MD2 */
278              if(PREDICT_FALSE(hdr0->md_type == 2))
279        	{
280        	  if (PREDICT_FALSE(next0 == NSH_NODE_NEXT_DROP))
281        	    {
282        	      error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
283        	      goto trace00;
284        	    }
285	          //vnet_buffer(b0)->sw_if_index[VLIB_RX] = map0->sw_if_index;
286        	}
287
288              /* Pop NSH header */
289	      vlib_buffer_advance(b0, (word)header_len0);
290	      goto trace00;
291	    }
292
293	  entry0 = hash_get_mem(nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
294	  if (PREDICT_FALSE(entry0 == 0))
295	    {
296	      error0 = NSH_NODE_ERROR_NO_ENTRY;
297	      goto trace00;
298	    }
299
300	  trace00: b0->error = error0 ? node->errors[error0] : 0;
301
302	  if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
303	    {
304	      nsh_input_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
305	      clib_memcpy ( &(tr->trace_data[0]), hdr0, (hdr0->length*4) );
306	    }
307
308	  vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
309					  n_left_to_next, bi0, next0);
310	}
311
312      vlib_put_next_frame(vm, node, next_index, n_left_to_next);
313
314    }
315
316  return from_frame->n_vectors;
317}
318
319/**
320 * @brief Graph processing dispatch function for NSH Input
321 *
322 * @node nsh_input
323 * @param *vm
324 * @param *node
325 * @param *from_frame
326 *
327 * @return from_frame->n_vectors
328 *
329 */
330static uword
331nsh_pop (vlib_main_t * vm, vlib_node_runtime_t * node,
332                  vlib_frame_t * from_frame)
333{
334  return nsh_pop_inline (vm, node, from_frame);
335}
336
337static char * nsh_pop_node_error_strings[] = {
338#define _(sym,string) string,
339  foreach_nsh_node_error
340#undef _
341};
342
343/* register nsh-input node */
344VLIB_REGISTER_NODE (nsh_pop_node) = {
345  .function = nsh_pop,
346  .name = "nsh-pop",
347  .vector_size = sizeof (u32),
348  .format_trace = format_nsh_pop_node_map_trace,
349  .format_buffer = format_nsh_pop_header,
350  .type = VLIB_NODE_TYPE_INTERNAL,
351
352  .n_errors = ARRAY_LEN(nsh_pop_node_error_strings),
353  .error_strings = nsh_pop_node_error_strings,
354
355  .n_next_nodes = NSH_NODE_N_NEXT,
356
357  .next_nodes = {
358#define _(s,n) [NSH_NODE_NEXT_##s] = n,
359    foreach_nsh_node_next
360#undef _
361  },
362};
363
364VLIB_NODE_FUNCTION_MULTIARCH (nsh_pop_node, nsh_pop);
365
366
367