Line data Source code
1 : /*
2 : * Copyright (c) 2016 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 :
16 : #include <vnet/dpo/interface_rx_dpo.h>
17 : #include <vnet/fib/fib_node.h>
18 : #include <vnet/l2/l2_input.h>
19 :
20 : #ifndef CLIB_MARCH_VARIANT
21 : interface_rx_dpo_t *interface_rx_dpo_pool;
22 :
23 : /*
24 : * The 'DB' of interface DPOs.
25 : * There is only one per-interface per-protocol, so this is a per-interface
26 : * vector
27 : */
28 : static index_t *interface_rx_dpo_db[DPO_PROTO_NUM];
29 :
30 : static interface_rx_dpo_t *
31 6 : interface_rx_dpo_alloc (void)
32 : {
33 : interface_rx_dpo_t *ido;
34 :
35 6 : pool_get(interface_rx_dpo_pool, ido);
36 :
37 6 : return (ido);
38 : }
39 :
40 : static inline interface_rx_dpo_t *
41 146 : interface_rx_dpo_get_from_dpo (const dpo_id_t *dpo)
42 : {
43 146 : ASSERT(DPO_INTERFACE_RX == dpo->dpoi_type);
44 :
45 146 : return (interface_rx_dpo_get(dpo->dpoi_index));
46 : }
47 :
48 : static inline index_t
49 36 : interface_rx_dpo_get_index (interface_rx_dpo_t *ido)
50 : {
51 36 : return (ido - interface_rx_dpo_pool);
52 : }
53 :
54 : static void
55 73 : interface_rx_dpo_lock (dpo_id_t *dpo)
56 : {
57 : interface_rx_dpo_t *ido;
58 :
59 73 : ido = interface_rx_dpo_get_from_dpo(dpo);
60 73 : ido->ido_locks++;
61 73 : }
62 :
63 : static void
64 73 : interface_rx_dpo_unlock (dpo_id_t *dpo)
65 : {
66 : interface_rx_dpo_t *ido;
67 :
68 73 : ido = interface_rx_dpo_get_from_dpo(dpo);
69 73 : ido->ido_locks--;
70 :
71 73 : if (0 == ido->ido_locks)
72 : {
73 6 : interface_rx_dpo_db[ido->ido_proto][ido->ido_sw_if_index] =
74 : INDEX_INVALID;
75 6 : pool_put(interface_rx_dpo_pool, ido);
76 : }
77 73 : }
78 :
79 : /*
80 : * interface_rx_dpo_add_or_lock
81 : *
82 : * Add/create and lock a new or lock an existing for the interface DPO
83 : * on the interface and protocol given
84 : */
85 : void
86 30 : interface_rx_dpo_add_or_lock (dpo_proto_t proto,
87 : u32 sw_if_index,
88 : dpo_id_t *dpo)
89 : {
90 : interface_rx_dpo_t *ido;
91 :
92 40 : vec_validate_init_empty(interface_rx_dpo_db[proto],
93 : sw_if_index,
94 : INDEX_INVALID);
95 :
96 30 : if (INDEX_INVALID == interface_rx_dpo_db[proto][sw_if_index])
97 : {
98 6 : ido = interface_rx_dpo_alloc();
99 :
100 6 : ido->ido_sw_if_index = sw_if_index;
101 6 : ido->ido_proto = proto;
102 :
103 6 : interface_rx_dpo_db[proto][sw_if_index] =
104 6 : interface_rx_dpo_get_index(ido);
105 : }
106 : else
107 : {
108 24 : ido = interface_rx_dpo_get(interface_rx_dpo_db[proto][sw_if_index]);
109 : }
110 :
111 30 : dpo_set(dpo, DPO_INTERFACE_RX, proto, interface_rx_dpo_get_index(ido));
112 30 : }
113 : #endif /* CLIB_MARCH_VARIANT */
114 :
115 :
116 : static clib_error_t *
117 13514 : interface_rx_dpo_interface_state_change (vnet_main_t * vnm,
118 : u32 sw_if_index,
119 : u32 flags)
120 : {
121 : /*
122 : */
123 13514 : return (NULL);
124 : }
125 :
126 2881 : VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(
127 : interface_rx_dpo_interface_state_change);
128 :
129 : /**
130 : * @brief Registered callback for HW interface state changes
131 : */
132 : static clib_error_t *
133 13336 : interface_rx_dpo_hw_interface_state_change (vnet_main_t * vnm,
134 : u32 hw_if_index,
135 : u32 flags)
136 : {
137 13336 : return (NULL);
138 : }
139 :
140 2881 : VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION(
141 : interface_rx_dpo_hw_interface_state_change);
142 :
143 : static clib_error_t *
144 11798 : interface_rx_dpo_interface_delete (vnet_main_t * vnm,
145 : u32 sw_if_index,
146 : u32 is_add)
147 : {
148 11798 : return (NULL);
149 : }
150 :
151 3459 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION(
152 : interface_rx_dpo_interface_delete);
153 :
154 : #ifndef CLIB_MARCH_VARIANT
155 : static u8*
156 259 : format_interface_rx_dpo (u8* s, va_list *ap)
157 : {
158 259 : index_t index = va_arg(*ap, index_t);
159 259 : CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
160 259 : vnet_main_t * vnm = vnet_get_main();
161 259 : interface_rx_dpo_t *ido = interface_rx_dpo_get(index);
162 :
163 259 : return (format(s, "%U-rx-dpo: %U",
164 : format_vnet_sw_interface_name,
165 : vnm,
166 : vnet_get_sw_interface(vnm, ido->ido_sw_if_index),
167 259 : format_dpo_proto, ido->ido_proto));
168 : }
169 :
170 : static void
171 0 : interface_rx_dpo_mem_show (void)
172 : {
173 0 : fib_show_memory_usage("Interface",
174 0 : pool_elts(interface_rx_dpo_pool),
175 0 : pool_len(interface_rx_dpo_pool),
176 : sizeof(interface_rx_dpo_t));
177 0 : }
178 :
179 :
180 : const static dpo_vft_t interface_rx_dpo_vft = {
181 : .dv_lock = interface_rx_dpo_lock,
182 : .dv_unlock = interface_rx_dpo_unlock,
183 : .dv_format = format_interface_rx_dpo,
184 : .dv_mem_show = interface_rx_dpo_mem_show,
185 : };
186 :
187 : /**
188 : * @brief The per-protocol VLIB graph nodes that are assigned to a glean
189 : * object.
190 : *
191 : * this means that these graph nodes are ones from which a glean is the
192 : * parent object in the DPO-graph.
193 : */
194 : const static char* const interface_rx_dpo_ip4_nodes[] =
195 : {
196 : "interface-rx-dpo-ip4",
197 : NULL,
198 : };
199 : const static char* const interface_rx_dpo_ip6_nodes[] =
200 : {
201 : "interface-rx-dpo-ip6",
202 : NULL,
203 : };
204 : const static char* const interface_rx_dpo_l2_nodes[] =
205 : {
206 : "interface-rx-dpo-l2",
207 : NULL,
208 : };
209 :
210 : const static char* const * const interface_rx_dpo_nodes[DPO_PROTO_NUM] =
211 : {
212 : [DPO_PROTO_IP4] = interface_rx_dpo_ip4_nodes,
213 : [DPO_PROTO_IP6] = interface_rx_dpo_ip6_nodes,
214 : [DPO_PROTO_ETHERNET] = interface_rx_dpo_l2_nodes,
215 : [DPO_PROTO_MPLS] = NULL,
216 : };
217 :
218 : void
219 575 : interface_rx_dpo_module_init (void)
220 : {
221 575 : dpo_register(DPO_INTERFACE_RX,
222 : &interface_rx_dpo_vft,
223 : interface_rx_dpo_nodes);
224 575 : }
225 : #endif /* CLIB_MARCH_VARIANT */
226 :
227 : /**
228 : * @brief Interface DPO trace data
229 : */
230 : typedef struct interface_rx_dpo_trace_t_
231 : {
232 : u32 sw_if_index;
233 : } interface_rx_dpo_trace_t;
234 :
235 : typedef enum interface_rx_dpo_next_t_
236 : {
237 : INTERFACE_RX_DPO_DROP = 0,
238 : INTERFACE_RX_DPO_INPUT = 1,
239 : } interface_rx_dpo_next_t;
240 :
241 : always_inline uword
242 9 : interface_rx_dpo_inline (vlib_main_t * vm,
243 : vlib_node_runtime_t * node,
244 : vlib_frame_t * from_frame,
245 : u8 is_l2)
246 : {
247 : u32 n_left_from, next_index, * from, * to_next;
248 9 : u32 thread_index = vm->thread_index;
249 : vnet_interface_main_t *im;
250 :
251 9 : im = &vnet_get_main ()->interface_main;
252 9 : from = vlib_frame_vector_args (from_frame);
253 9 : n_left_from = from_frame->n_vectors;
254 :
255 9 : next_index = INTERFACE_RX_DPO_INPUT;
256 :
257 18 : while (n_left_from > 0)
258 : {
259 : u32 n_left_to_next;
260 :
261 9 : vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
262 :
263 359 : while (n_left_from >= 4 && n_left_to_next > 2)
264 : {
265 : const interface_rx_dpo_t *ido0, *ido1;
266 : u32 bi0, idoi0, bi1, idoi1;
267 : vlib_buffer_t *b0, *b1;
268 :
269 350 : bi0 = from[0];
270 350 : to_next[0] = bi0;
271 350 : bi1 = from[1];
272 350 : to_next[1] = bi1;
273 350 : from += 2;
274 350 : to_next += 2;
275 350 : n_left_from -= 2;
276 350 : n_left_to_next -= 2;
277 :
278 350 : b0 = vlib_get_buffer (vm, bi0);
279 350 : b1 = vlib_get_buffer (vm, bi1);
280 :
281 350 : idoi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
282 350 : idoi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
283 350 : ido0 = interface_rx_dpo_get(idoi0);
284 350 : ido1 = interface_rx_dpo_get(idoi1);
285 :
286 350 : vnet_buffer(b0)->sw_if_index[VLIB_RX] = ido0->ido_sw_if_index;
287 350 : vnet_buffer(b1)->sw_if_index[VLIB_RX] = ido1->ido_sw_if_index;
288 :
289 350 : if (is_l2)
290 : {
291 96 : vnet_update_l2_len (b0);
292 96 : vnet_update_l2_len (b1);
293 : }
294 :
295 350 : vlib_increment_combined_counter (im->combined_sw_if_counters
296 : + VNET_INTERFACE_COUNTER_RX,
297 : thread_index,
298 : ido0->ido_sw_if_index,
299 : 1,
300 : vlib_buffer_length_in_chain (vm, b0));
301 350 : vlib_increment_combined_counter (im->combined_sw_if_counters
302 : + VNET_INTERFACE_COUNTER_RX,
303 : thread_index,
304 : ido1->ido_sw_if_index,
305 : 1,
306 : vlib_buffer_length_in_chain (vm, b1));
307 :
308 350 : if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
309 : {
310 : interface_rx_dpo_trace_t *tr0;
311 :
312 350 : tr0 = vlib_add_trace (vm, node, b0, sizeof (*tr0));
313 350 : tr0->sw_if_index = ido0->ido_sw_if_index;
314 : }
315 350 : if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
316 : {
317 : interface_rx_dpo_trace_t *tr1;
318 :
319 350 : tr1 = vlib_add_trace (vm, node, b1, sizeof (*tr1));
320 350 : tr1->sw_if_index = ido1->ido_sw_if_index;
321 : }
322 : }
323 :
324 26 : while (n_left_from > 0 && n_left_to_next > 0)
325 : {
326 : const interface_rx_dpo_t * ido0;
327 : vlib_buffer_t * b0;
328 : u32 bi0, idoi0;
329 :
330 17 : bi0 = from[0];
331 17 : to_next[0] = bi0;
332 17 : from += 1;
333 17 : to_next += 1;
334 17 : n_left_from -= 1;
335 17 : n_left_to_next -= 1;
336 :
337 17 : b0 = vlib_get_buffer (vm, bi0);
338 :
339 17 : idoi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
340 17 : ido0 = interface_rx_dpo_get(idoi0);
341 :
342 : /* Swap the RX interface of the packet to the one the
343 : * interface DPR represents */
344 17 : vnet_buffer(b0)->sw_if_index[VLIB_RX] = ido0->ido_sw_if_index;
345 :
346 : /* Update l2_len to make l2 tag rewrite work */
347 17 : if (is_l2)
348 11 : vnet_update_l2_len (b0);
349 :
350 : /* Bump the interface's RX coutners */
351 17 : vlib_increment_combined_counter (im->combined_sw_if_counters
352 : + VNET_INTERFACE_COUNTER_RX,
353 : thread_index,
354 : ido0->ido_sw_if_index,
355 : 1,
356 : vlib_buffer_length_in_chain (vm, b0));
357 :
358 17 : if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
359 : {
360 : interface_rx_dpo_trace_t *tr;
361 :
362 17 : tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
363 17 : tr->sw_if_index = ido0->ido_sw_if_index;
364 : }
365 : }
366 9 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
367 : }
368 9 : return from_frame->n_vectors;
369 : }
370 :
371 : static u8 *
372 783 : format_interface_rx_dpo_trace (u8 * s, va_list * args)
373 : {
374 783 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
375 783 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
376 783 : interface_rx_dpo_trace_t * t = va_arg (*args, interface_rx_dpo_trace_t *);
377 783 : u32 indent = format_get_indent (s);
378 783 : s = format (s, "%U sw_if_index:%d",
379 : format_white_space, indent,
380 : t->sw_if_index);
381 783 : return s;
382 : }
383 :
384 2304 : VLIB_NODE_FN (interface_rx_dpo_ip4_node) (vlib_main_t * vm,
385 : vlib_node_runtime_t * node,
386 : vlib_frame_t * from_frame)
387 : {
388 4 : return (interface_rx_dpo_inline(vm, node, from_frame, 0));
389 : }
390 :
391 2300 : VLIB_NODE_FN (interface_rx_dpo_ip6_node) (vlib_main_t * vm,
392 : vlib_node_runtime_t * node,
393 : vlib_frame_t * from_frame)
394 : {
395 0 : return (interface_rx_dpo_inline(vm, node, from_frame, 0));
396 : }
397 :
398 2305 : VLIB_NODE_FN (interface_rx_dpo_l2_node) (vlib_main_t * vm,
399 : vlib_node_runtime_t * node,
400 : vlib_frame_t * from_frame)
401 : {
402 5 : return (interface_rx_dpo_inline(vm, node, from_frame, 1));
403 : }
404 :
405 183788 : VLIB_REGISTER_NODE (interface_rx_dpo_ip4_node) = {
406 : .name = "interface-rx-dpo-ip4",
407 : .vector_size = sizeof (u32),
408 : .format_trace = format_interface_rx_dpo_trace,
409 :
410 : .n_next_nodes = 2,
411 : .next_nodes = {
412 : [INTERFACE_RX_DPO_DROP] = "ip4-drop",
413 : [INTERFACE_RX_DPO_INPUT] = "ip4-input",
414 : },
415 : };
416 :
417 :
418 183788 : VLIB_REGISTER_NODE (interface_rx_dpo_ip6_node) = {
419 : .name = "interface-rx-dpo-ip6",
420 : .vector_size = sizeof (u32),
421 : .format_trace = format_interface_rx_dpo_trace,
422 :
423 : .n_next_nodes = 2,
424 : .next_nodes = {
425 : [INTERFACE_RX_DPO_DROP] = "ip6-drop",
426 : [INTERFACE_RX_DPO_INPUT] = "ip6-input",
427 : },
428 : };
429 :
430 :
431 183788 : VLIB_REGISTER_NODE (interface_rx_dpo_l2_node) = {
432 : .name = "interface-rx-dpo-l2",
433 : .vector_size = sizeof (u32),
434 : .format_trace = format_interface_rx_dpo_trace,
435 :
436 : .n_next_nodes = 2,
437 : .next_nodes = {
438 : [INTERFACE_RX_DPO_DROP] = "error-drop",
439 : [INTERFACE_RX_DPO_INPUT] = "l2-input",
440 : },
441 : };
442 :
|