Line data Source code
1 : /*
2 : * lcp_enthernet_node.c : linux control plane ethernet node
3 : *
4 : * Copyright (c) 2021 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 <sys/socket.h>
19 : #include <linux/if.h>
20 :
21 : #include <plugins/linux-cp/lcp_interface.h>
22 : #include <plugins/linux-cp/lcp_adj.h>
23 : #include <linux-cp/lcp.api_enum.h>
24 :
25 : #include <vnet/feature/feature.h>
26 : #include <vnet/ip/ip4_packet.h>
27 : #include <vnet/ethernet/arp_packet.h>
28 : #include <vnet/ethernet/ethernet.h>
29 : #include <vnet/ip/ip_types.h>
30 : #include <vnet/ip/lookup.h>
31 : #include <vnet/ip/ip4.h>
32 : #include <vnet/ip/ip6.h>
33 : #include <vnet/l2/l2_input.h>
34 : #include <vnet/mpls/mpls.h>
35 :
36 : #define foreach_lip_punt \
37 : _ (IO, "punt to host") \
38 : _ (DROP, "unknown input interface")
39 :
40 : typedef enum
41 : {
42 : #define _(sym, str) LIP_PUNT_NEXT_##sym,
43 : foreach_lip_punt
44 : #undef _
45 : LIP_PUNT_N_NEXT,
46 : } lip_punt_next_t;
47 :
48 : typedef struct lip_punt_trace_t_
49 : {
50 : u32 phy_sw_if_index;
51 : u32 host_sw_if_index;
52 : } lip_punt_trace_t;
53 :
54 : /* packet trace format function */
55 : static u8 *
56 0 : format_lip_punt_trace (u8 *s, va_list *args)
57 : {
58 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
59 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
60 0 : lip_punt_trace_t *t = va_arg (*args, lip_punt_trace_t *);
61 :
62 : s =
63 0 : format (s, "lip-punt: %u -> %u", t->phy_sw_if_index, t->host_sw_if_index);
64 :
65 0 : return s;
66 : }
67 :
68 : /**
69 : * Pass punted packets from the PHY to the HOST.
70 : */
71 2 : VLIB_NODE_FN (lip_punt_node)
72 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
73 : {
74 : u32 n_left_from, *from, *to_next, n_left_to_next;
75 : lip_punt_next_t next_index;
76 :
77 0 : next_index = node->cached_next_index;
78 0 : n_left_from = frame->n_vectors;
79 0 : from = vlib_frame_vector_args (frame);
80 :
81 0 : while (n_left_from > 0)
82 : {
83 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
84 :
85 0 : while (n_left_from > 0 && n_left_to_next > 0)
86 : {
87 : vlib_buffer_t *b0;
88 0 : const lcp_itf_pair_t *lip0 = NULL;
89 0 : u32 next0 = ~0;
90 : u32 bi0, lipi0;
91 : u32 sw_if_index0;
92 : u8 len0;
93 :
94 0 : bi0 = to_next[0] = from[0];
95 :
96 0 : from += 1;
97 0 : to_next += 1;
98 0 : n_left_from -= 1;
99 0 : n_left_to_next -= 1;
100 0 : next0 = LIP_PUNT_NEXT_DROP;
101 :
102 0 : b0 = vlib_get_buffer (vm, bi0);
103 :
104 0 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
105 0 : lipi0 = lcp_itf_pair_find_by_phy (sw_if_index0);
106 0 : if (PREDICT_FALSE (lipi0 == INDEX_INVALID))
107 0 : goto trace0;
108 :
109 0 : lip0 = lcp_itf_pair_get (lipi0);
110 0 : next0 = LIP_PUNT_NEXT_IO;
111 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = lip0->lip_host_sw_if_index;
112 :
113 0 : if (PREDICT_TRUE (lip0->lip_host_type == LCP_ITF_HOST_TAP))
114 : {
115 : /*
116 : * rewind to ethernet header
117 : */
118 0 : len0 = ((u8 *) vlib_buffer_get_current (b0) -
119 0 : (u8 *) ethernet_buffer_get_header (b0));
120 0 : vlib_buffer_advance (b0, -len0);
121 : }
122 : /* Tun packets don't need any special treatment, just need to
123 : * be escorted past the TTL decrement. If we still want to use
124 : * ip[46]-punt-redirect with these, we could just set the
125 : * VNET_BUFFER_F_LOCALLY_ORIGINATED in an 'else {}' here and
126 : * then pass to the next node on the ip[46]-punt feature arc
127 : */
128 :
129 0 : trace0:
130 0 : if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
131 : {
132 0 : lip_punt_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
133 0 : t->phy_sw_if_index = sw_if_index0;
134 0 : t->host_sw_if_index =
135 0 : (lipi0 == INDEX_INVALID) ? ~0 : lip0->lip_host_sw_if_index;
136 : }
137 :
138 0 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
139 : n_left_to_next, bi0, next0);
140 : }
141 :
142 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
143 : }
144 :
145 0 : return frame->n_vectors;
146 : }
147 :
148 354 : VLIB_REGISTER_NODE (lip_punt_node) = {
149 : .name = "linux-cp-punt",
150 : .vector_size = sizeof (u32),
151 : .format_trace = format_lip_punt_trace,
152 : .type = VLIB_NODE_TYPE_INTERNAL,
153 :
154 : .n_next_nodes = LIP_PUNT_N_NEXT,
155 : .next_nodes = {
156 : [LIP_PUNT_NEXT_DROP] = "error-drop",
157 : [LIP_PUNT_NEXT_IO] = "interface-output",
158 : },
159 : };
160 :
161 : #define foreach_lcp_punt_l3 _ (DROP, "unknown error")
162 :
163 : typedef enum
164 : {
165 : #define _(sym, str) LCP_LOCAL_NEXT_##sym,
166 : foreach_lcp_punt_l3
167 : #undef _
168 : LCP_LOCAL_N_NEXT,
169 : } lcp_punt_l3_next_t;
170 :
171 : typedef struct lcp_punt_l3_trace_t_
172 : {
173 : u32 phy_sw_if_index;
174 : } lcp_punt_l3_trace_t;
175 :
176 : /* packet trace format function */
177 : static u8 *
178 155 : format_lcp_punt_l3_trace (u8 *s, va_list *args)
179 : {
180 155 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
181 155 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
182 155 : lcp_punt_l3_trace_t *t = va_arg (*args, lcp_punt_l3_trace_t *);
183 :
184 155 : s = format (s, "linux-cp-punt-l3: %u", t->phy_sw_if_index);
185 :
186 155 : return s;
187 : }
188 :
189 5 : VLIB_NODE_FN (lcp_punt_l3_node)
190 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
191 : {
192 : u32 n_left_from, *from, *to_next, n_left_to_next;
193 : lip_punt_next_t next_index;
194 :
195 3 : next_index = node->cached_next_index;
196 3 : n_left_from = frame->n_vectors;
197 3 : from = vlib_frame_vector_args (frame);
198 :
199 6 : while (n_left_from > 0)
200 : {
201 3 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
202 :
203 96 : while (n_left_from > 0 && n_left_to_next > 0)
204 : {
205 : vlib_buffer_t *b0;
206 93 : u32 next0 = LCP_LOCAL_NEXT_DROP;
207 : u32 bi0;
208 : index_t lipi0;
209 : lcp_itf_pair_t *lip0;
210 :
211 93 : bi0 = to_next[0] = from[0];
212 :
213 93 : from += 1;
214 93 : to_next += 1;
215 93 : n_left_from -= 1;
216 93 : n_left_to_next -= 1;
217 :
218 93 : b0 = vlib_get_buffer (vm, bi0);
219 93 : vnet_feature_next (&next0, b0);
220 :
221 : lipi0 =
222 93 : lcp_itf_pair_find_by_phy (vnet_buffer (b0)->sw_if_index[VLIB_RX]);
223 93 : if (lipi0 != INDEX_INVALID)
224 : {
225 : /*
226 : * Avoid TTL check for packets which arrived on a tunnel and
227 : * are being punted to the local host.
228 : */
229 93 : lip0 = lcp_itf_pair_get (lipi0);
230 93 : if (lip0->lip_host_type == LCP_ITF_HOST_TUN)
231 93 : b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
232 : }
233 :
234 93 : if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
235 : {
236 : lcp_punt_l3_trace_t *t =
237 93 : vlib_add_trace (vm, node, b0, sizeof (*t));
238 93 : t->phy_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
239 : }
240 :
241 93 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
242 : n_left_to_next, bi0, next0);
243 : }
244 :
245 3 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
246 : }
247 :
248 3 : return frame->n_vectors;
249 : }
250 :
251 354 : VLIB_REGISTER_NODE (lcp_punt_l3_node) = {
252 : .name = "linux-cp-punt-l3",
253 : .vector_size = sizeof (u32),
254 : .format_trace = format_lcp_punt_l3_trace,
255 : .type = VLIB_NODE_TYPE_INTERNAL,
256 :
257 : .n_next_nodes = 1,
258 : .next_nodes = {
259 : [LCP_LOCAL_NEXT_DROP] = "error-drop",
260 : },
261 : };
262 :
263 174 : VNET_FEATURE_INIT (lcp_punt_l3_ip4, static) = {
264 : .arc_name = "ip4-punt",
265 : .node_name = "linux-cp-punt-l3",
266 : .runs_before = VNET_FEATURES ("ip4-punt-redirect"),
267 : };
268 :
269 174 : VNET_FEATURE_INIT (lip_punt_l3_ip6, static) = {
270 : .arc_name = "ip6-punt",
271 : .node_name = "linux-cp-punt-l3",
272 : .runs_before = VNET_FEATURES ("ip6-punt-redirect"),
273 : };
274 :
275 : #define foreach_lcp_xc \
276 : _ (DROP, "drop") \
277 : _ (XC_IP4, "x-connnect-ip4") \
278 : _ (XC_IP6, "x-connnect-ip6")
279 :
280 : typedef enum
281 : {
282 : #define _(sym, str) LCP_XC_NEXT_##sym,
283 : foreach_lcp_xc
284 : #undef _
285 : LCP_XC_N_NEXT,
286 : } lcp_xc_next_t;
287 :
288 : typedef struct lcp_xc_trace_t_
289 : {
290 : u32 phy_sw_if_index;
291 : adj_index_t adj_index;
292 : } lcp_xc_trace_t;
293 :
294 : /* packet trace format function */
295 : static u8 *
296 101 : format_lcp_xc_trace (u8 *s, va_list *args)
297 : {
298 101 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
299 101 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
300 101 : lcp_xc_trace_t *t = va_arg (*args, lcp_xc_trace_t *);
301 :
302 101 : s = format (s, "lcp-xc: itf:%d adj:%d", t->phy_sw_if_index, t->adj_index);
303 :
304 101 : return s;
305 : }
306 :
307 : /**
308 : * X-connect all packets from the HOST to the PHY.
309 : *
310 : * This runs in either the IP4 or IP6 path. The MAC rewrite on the received
311 : * packet from the host is used as a key to find the adjacency used on the phy.
312 : * This allows this code to start the feature arc on that adjacency.
313 : * Consequently, all packet sent from the host are also subject to output
314 : * features, which is symmetric w.r.t. to input features.
315 : */
316 : static_always_inline u32
317 8 : lcp_xc_inline (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame,
318 : ip_address_family_t af)
319 : {
320 : u32 n_left_from, *from, *to_next, n_left_to_next;
321 : lcp_xc_next_t next_index;
322 : ip_lookup_main_t *lm;
323 :
324 8 : next_index = 0;
325 8 : n_left_from = frame->n_vectors;
326 8 : from = vlib_frame_vector_args (frame);
327 :
328 8 : if (AF_IP4 == af)
329 8 : lm = &ip4_main.lookup_main;
330 : else
331 0 : lm = &ip6_main.lookup_main;
332 :
333 16 : while (n_left_from > 0)
334 : {
335 8 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
336 :
337 16 : while (n_left_from > 0 && n_left_to_next > 0)
338 : {
339 : const ethernet_header_t *eth;
340 : const lcp_itf_pair_t *lip;
341 : u32 next0, bi0, lipi, ai;
342 : vlib_buffer_t *b0;
343 : const ip_adjacency_t *adj;
344 :
345 8 : bi0 = to_next[0] = from[0];
346 :
347 8 : from += 1;
348 8 : to_next += 1;
349 8 : n_left_from -= 1;
350 8 : n_left_to_next -= 1;
351 :
352 8 : b0 = vlib_get_buffer (vm, bi0);
353 :
354 : lipi =
355 8 : lcp_itf_pair_find_by_host (vnet_buffer (b0)->sw_if_index[VLIB_RX]);
356 8 : lip = lcp_itf_pair_get (lipi);
357 :
358 8 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = lip->lip_phy_sw_if_index;
359 8 : vlib_buffer_advance (b0, -lip->lip_rewrite_len);
360 8 : eth = vlib_buffer_get_current (b0);
361 :
362 8 : ai = ADJ_INDEX_INVALID;
363 8 : if (!ethernet_address_cast (eth->dst_address))
364 8 : ai = lcp_adj_lkup ((u8 *) eth, lip->lip_rewrite_len,
365 8 : vnet_buffer (b0)->sw_if_index[VLIB_TX]);
366 8 : if (ai == ADJ_INDEX_INVALID)
367 8 : ai = lip->lip_phy_adjs.adj_index[af];
368 :
369 8 : adj = adj_get (ai);
370 8 : vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ai;
371 8 : next0 = adj->rewrite_header.next_index;
372 8 : vnet_buffer (b0)->ip.save_rewrite_length = lip->lip_rewrite_len;
373 :
374 8 : if (PREDICT_FALSE (adj->rewrite_header.flags &
375 : VNET_REWRITE_HAS_FEATURES))
376 0 : vnet_feature_arc_start_w_cfg_index (
377 0 : lm->output_feature_arc_index,
378 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX], &next0, b0,
379 : adj->ia_cfg_index);
380 :
381 8 : if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
382 : {
383 8 : lcp_xc_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
384 8 : t->phy_sw_if_index = lip->lip_phy_sw_if_index;
385 8 : t->adj_index = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
386 : }
387 :
388 8 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
389 : n_left_to_next, bi0, next0);
390 : }
391 :
392 8 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
393 : }
394 :
395 8 : return frame->n_vectors;
396 : }
397 :
398 10 : VLIB_NODE_FN (lcp_xc_ip4)
399 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
400 : {
401 8 : return (lcp_xc_inline (vm, node, frame, AF_IP4));
402 : }
403 :
404 2 : VLIB_NODE_FN (lcp_xc_ip6)
405 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
406 : {
407 0 : return (lcp_xc_inline (vm, node, frame, AF_IP6));
408 : }
409 :
410 354 : VLIB_REGISTER_NODE (lcp_xc_ip4) = { .name = "linux-cp-xc-ip4",
411 : .vector_size = sizeof (u32),
412 : .format_trace = format_lcp_xc_trace,
413 : .type = VLIB_NODE_TYPE_INTERNAL,
414 : .sibling_of = "ip4-rewrite" };
415 :
416 174 : VNET_FEATURE_INIT (lcp_xc_ip4_ucast_node, static) = {
417 : .arc_name = "ip4-unicast",
418 : .node_name = "linux-cp-xc-ip4",
419 : };
420 174 : VNET_FEATURE_INIT (lcp_xc_ip4_mcast_node, static) = {
421 : .arc_name = "ip4-multicast",
422 : .node_name = "linux-cp-xc-ip4",
423 : };
424 :
425 354 : VLIB_REGISTER_NODE (lcp_xc_ip6) = { .name = "linux-cp-xc-ip6",
426 : .vector_size = sizeof (u32),
427 : .format_trace = format_lcp_xc_trace,
428 : .type = VLIB_NODE_TYPE_INTERNAL,
429 : .sibling_of = "ip6-rewrite" };
430 :
431 174 : VNET_FEATURE_INIT (lcp_xc_ip6_ucast_node, static) = {
432 : .arc_name = "ip6-unicast",
433 : .node_name = "linux-cp-xc-ip6",
434 : };
435 174 : VNET_FEATURE_INIT (lcp_xc_ip6_mcast_node, static) = {
436 : .arc_name = "ip6-multicast",
437 : .node_name = "linux-cp-xc-ip6",
438 : };
439 :
440 : typedef enum
441 : {
442 : LCP_XC_MPLS_NEXT_DROP,
443 : LCP_XC_MPLS_NEXT_IO,
444 : LCP_XC_MPLS_N_NEXT,
445 : } lcp_xc_mpls_next_t;
446 :
447 : static_always_inline uword
448 0 : lcp_xc_mpls_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
449 : vlib_frame_t *frame)
450 : {
451 : u32 n_left_from, *from, *to_next, n_left_to_next;
452 : lcp_xc_next_t next_index;
453 :
454 0 : next_index = 0;
455 0 : n_left_from = frame->n_vectors;
456 0 : from = vlib_frame_vector_args (frame);
457 :
458 0 : while (n_left_from > 0)
459 : {
460 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
461 :
462 0 : while (n_left_from > 0 && n_left_to_next > 0)
463 : {
464 : const ethernet_header_t *eth;
465 : const lcp_itf_pair_t *lip;
466 : u32 next0, bi0, lipi, ai;
467 : vlib_buffer_t *b0;
468 : // const ip_adjacency_t *adj;
469 :
470 0 : bi0 = to_next[0] = from[0];
471 :
472 0 : from += 1;
473 0 : to_next += 1;
474 0 : n_left_from -= 1;
475 0 : n_left_to_next -= 1;
476 :
477 0 : b0 = vlib_get_buffer (vm, bi0);
478 :
479 : lipi =
480 0 : lcp_itf_pair_find_by_host (vnet_buffer (b0)->sw_if_index[VLIB_RX]);
481 0 : lip = lcp_itf_pair_get (lipi);
482 :
483 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = lip->lip_phy_sw_if_index;
484 0 : vlib_buffer_advance (b0, -lip->lip_rewrite_len);
485 0 : eth = vlib_buffer_get_current (b0);
486 :
487 0 : ai = ADJ_INDEX_INVALID;
488 0 : next0 = LCP_XC_MPLS_NEXT_DROP;
489 0 : if (!ethernet_address_cast (eth->dst_address))
490 0 : ai = lcp_adj_lkup ((u8 *) eth, lip->lip_rewrite_len,
491 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX]);
492 0 : if (ai != ADJ_INDEX_INVALID)
493 : {
494 0 : vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ai;
495 0 : next0 = LCP_XC_MPLS_NEXT_IO;
496 : }
497 :
498 0 : if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
499 : {
500 0 : lcp_xc_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
501 0 : t->phy_sw_if_index = lip->lip_phy_sw_if_index;
502 0 : t->adj_index = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
503 : }
504 :
505 0 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
506 : n_left_to_next, bi0, next0);
507 : }
508 :
509 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
510 : }
511 :
512 0 : return frame->n_vectors;
513 : }
514 :
515 2 : VLIB_NODE_FN (lcp_xc_mpls)
516 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
517 : {
518 0 : return (lcp_xc_mpls_inline (vm, node, frame));
519 : }
520 :
521 354 : VLIB_REGISTER_NODE (
522 : lcp_xc_mpls) = { .name = "linux-cp-xc-mpls",
523 : .vector_size = sizeof (u32),
524 : .format_trace = format_lcp_xc_trace,
525 : .type = VLIB_NODE_TYPE_INTERNAL,
526 : .n_next_nodes = LCP_XC_MPLS_N_NEXT,
527 : .next_nodes = {
528 : [LCP_XC_MPLS_NEXT_DROP] = "error-drop",
529 : [LCP_XC_MPLS_NEXT_IO] = "interface-output",
530 : } };
531 :
532 174 : VNET_FEATURE_INIT (lcp_xc_mpls_node, static) = {
533 : .arc_name = "mpls-input",
534 : .node_name = "linux-cp-xc-mpls",
535 : };
536 :
537 : typedef enum
538 : {
539 : LCP_XC_L3_NEXT_XC,
540 : LCP_XC_L3_NEXT_LOOKUP,
541 : LCP_XC_L3_N_NEXT,
542 : } lcp_xc_l3_next_t;
543 :
544 : /**
545 : * X-connect all packets from the HOST to the PHY on L3 interfaces
546 : *
547 : * There's only one adjacency that can be used on these links.
548 : */
549 : static_always_inline u32
550 3 : lcp_xc_l3_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
551 : vlib_frame_t *frame, ip_address_family_t af)
552 : {
553 : u32 n_left_from, *from, *to_next, n_left_to_next;
554 : lcp_xc_next_t next_index;
555 3 : vnet_main_t *vnm = vnet_get_main ();
556 :
557 3 : next_index = 0;
558 3 : n_left_from = frame->n_vectors;
559 3 : from = vlib_frame_vector_args (frame);
560 :
561 6 : while (n_left_from > 0)
562 : {
563 3 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
564 :
565 96 : while (n_left_from > 0 && n_left_to_next > 0)
566 : {
567 : vlib_buffer_t *b0;
568 : const lcp_itf_pair_t *lip;
569 93 : u32 next0 = ~0;
570 : u32 bi0, lipi;
571 :
572 93 : bi0 = to_next[0] = from[0];
573 :
574 93 : from += 1;
575 93 : to_next += 1;
576 93 : n_left_from -= 1;
577 93 : n_left_to_next -= 1;
578 :
579 93 : b0 = vlib_get_buffer (vm, bi0);
580 :
581 : /* Flag buffers as locally originated. Otherwise their TTL will
582 : * be checked & decremented. That would break services like BGP
583 : * which set a TTL of 1 by default.
584 : */
585 93 : b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
586 :
587 : lipi =
588 93 : lcp_itf_pair_find_by_host (vnet_buffer (b0)->sw_if_index[VLIB_RX]);
589 93 : lip = lcp_itf_pair_get (lipi);
590 :
591 : /* P2P tunnels can use generic adjacency */
592 93 : if (PREDICT_TRUE (
593 : vnet_sw_interface_is_p2p (vnm, lip->lip_phy_sw_if_index)))
594 : {
595 93 : vnet_buffer (b0)->sw_if_index[VLIB_TX] =
596 93 : lip->lip_phy_sw_if_index;
597 93 : vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
598 93 : lip->lip_phy_adjs.adj_index[af];
599 93 : next0 = LCP_XC_L3_NEXT_XC;
600 : }
601 : /* P2MP tunnels require a fib lookup to find the right adjacency */
602 : else
603 : {
604 : /* lookup should use FIB table associated with phy interface */
605 0 : vnet_buffer (b0)->sw_if_index[VLIB_RX] =
606 0 : lip->lip_phy_sw_if_index;
607 0 : next0 = LCP_XC_L3_NEXT_LOOKUP;
608 : }
609 :
610 93 : if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
611 : {
612 93 : lcp_xc_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
613 93 : t->phy_sw_if_index = lip->lip_phy_sw_if_index;
614 93 : t->adj_index = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
615 : }
616 :
617 93 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
618 : n_left_to_next, bi0, next0);
619 : }
620 :
621 3 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
622 : }
623 :
624 3 : return frame->n_vectors;
625 : }
626 :
627 : /**
628 : * X-connect all packets from the HOST to the PHY.
629 : */
630 4 : VLIB_NODE_FN (lcp_xc_l3_ip4_node)
631 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
632 : {
633 2 : return (lcp_xc_l3_inline (vm, node, frame, AF_IP4));
634 : }
635 :
636 3 : VLIB_NODE_FN (lcp_xc_l3_ip6_node)
637 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
638 : {
639 1 : return (lcp_xc_l3_inline (vm, node, frame, AF_IP6));
640 : }
641 :
642 354 : VLIB_REGISTER_NODE (lcp_xc_l3_ip4_node) = {
643 : .name = "linux-cp-xc-l3-ip4",
644 : .vector_size = sizeof (u32),
645 : .format_trace = format_lcp_xc_trace,
646 : .type = VLIB_NODE_TYPE_INTERNAL,
647 :
648 : .n_next_nodes = LCP_XC_L3_N_NEXT,
649 : .next_nodes = {
650 : [LCP_XC_L3_NEXT_XC] = "ip4-midchain",
651 : [LCP_XC_L3_NEXT_LOOKUP] = "ip4-lookup",
652 : },
653 : };
654 :
655 174 : VNET_FEATURE_INIT (lcp_xc_node_l3_ip4_unicast, static) = {
656 : .arc_name = "ip4-unicast",
657 : .node_name = "linux-cp-xc-l3-ip4",
658 : };
659 :
660 174 : VNET_FEATURE_INIT (lcp_xc_node_l3_ip4_multicaast, static) = {
661 : .arc_name = "ip4-multicast",
662 : .node_name = "linux-cp-xc-l3-ip4",
663 : };
664 :
665 354 : VLIB_REGISTER_NODE (lcp_xc_l3_ip6_node) = {
666 : .name = "linux-cp-xc-l3-ip6",
667 : .vector_size = sizeof (u32),
668 : .format_trace = format_lcp_xc_trace,
669 : .type = VLIB_NODE_TYPE_INTERNAL,
670 :
671 : .n_next_nodes = LCP_XC_L3_N_NEXT,
672 : .next_nodes = {
673 : [LCP_XC_L3_NEXT_XC] = "ip6-midchain",
674 : [LCP_XC_L3_NEXT_LOOKUP] = "ip6-lookup",
675 : },
676 : };
677 :
678 174 : VNET_FEATURE_INIT (lcp_xc_node_l3_ip6_unicast, static) = {
679 : .arc_name = "ip6-unicast",
680 : .node_name = "linux-cp-xc-l3-ip6",
681 : };
682 :
683 174 : VNET_FEATURE_INIT (lcp_xc_node_l3_ip6_multicast, static) = {
684 : .arc_name = "ip6-multicast",
685 : .node_name = "linux-cp-xc-l3-ip6",
686 : };
687 :
688 : #define foreach_lcp_arp \
689 : _ (DROP, "error-drop") \
690 : _ (IO, "interface-output")
691 :
692 : typedef enum
693 : {
694 : #define _(sym, str) LCP_ARP_NEXT_##sym,
695 : foreach_lcp_arp
696 : #undef _
697 : LCP_ARP_N_NEXT,
698 : } lcp_arp_next_t;
699 :
700 : typedef struct lcp_arp_trace_t_
701 : {
702 : u32 rx_sw_if_index;
703 : u16 arp_opcode;
704 : } lcp_arp_trace_t;
705 :
706 : /* packet trace format function */
707 : static u8 *
708 17 : format_lcp_arp_trace (u8 *s, va_list *args)
709 : {
710 17 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
711 17 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
712 17 : lcp_arp_trace_t *t = va_arg (*args, lcp_arp_trace_t *);
713 :
714 17 : s = format (s, "rx-sw-if-index: %u opcode: %u", t->rx_sw_if_index,
715 17 : t->arp_opcode);
716 :
717 17 : return s;
718 : }
719 :
720 : /**
721 : * punt ARP replies to the host
722 : */
723 10 : VLIB_NODE_FN (lcp_arp_phy_node)
724 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
725 : {
726 : u32 n_left_from, *from, *to_next, n_left_to_next;
727 : lcp_arp_next_t next_index;
728 : u32 reply_copies[VLIB_FRAME_SIZE];
729 8 : u32 n_copies = 0;
730 :
731 8 : next_index = node->cached_next_index;
732 8 : n_left_from = frame->n_vectors;
733 8 : from = vlib_frame_vector_args (frame);
734 :
735 16 : while (n_left_from > 0)
736 : {
737 8 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
738 :
739 8 : while (n_left_from >= 2 && n_left_to_next >= 2)
740 : {
741 : u32 next0, next1, bi0, bi1;
742 : vlib_buffer_t *b0, *b1;
743 : ethernet_arp_header_t *arp0, *arp1;
744 :
745 0 : bi0 = to_next[0] = from[0];
746 0 : bi1 = to_next[1] = from[1];
747 :
748 0 : from += 2;
749 0 : n_left_from -= 2;
750 0 : to_next += 2;
751 0 : n_left_to_next -= 2;
752 :
753 0 : next0 = next1 = LCP_ARP_NEXT_DROP;
754 :
755 0 : b0 = vlib_get_buffer (vm, bi0);
756 0 : b1 = vlib_get_buffer (vm, bi1);
757 :
758 0 : arp0 = vlib_buffer_get_current (b0);
759 0 : arp1 = vlib_buffer_get_current (b1);
760 :
761 0 : vnet_feature_next (&next0, b0);
762 0 : vnet_feature_next (&next1, b1);
763 :
764 : /*
765 : * Replies might need to be received by the host, so we
766 : * make a copy of them.
767 : */
768 0 : if (arp0->opcode == clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply))
769 : {
770 0 : lcp_itf_pair_t *lip0 = 0;
771 : u32 lipi0;
772 : vlib_buffer_t *c0;
773 : u8 len0;
774 :
775 0 : lipi0 = lcp_itf_pair_find_by_phy (
776 0 : vnet_buffer (b0)->sw_if_index[VLIB_RX]);
777 0 : lip0 = lcp_itf_pair_get (lipi0);
778 :
779 0 : if (lip0)
780 : {
781 : /*
782 : * rewind to eth header, copy, advance back to current
783 : */
784 0 : len0 = ((u8 *) vlib_buffer_get_current (b0) -
785 0 : (u8 *) ethernet_buffer_get_header (b0));
786 0 : vlib_buffer_advance (b0, -len0);
787 0 : c0 = vlib_buffer_copy (vm, b0);
788 0 : vlib_buffer_advance (b0, len0);
789 :
790 0 : if (c0)
791 : {
792 : /* Send to the host */
793 0 : vnet_buffer (c0)->sw_if_index[VLIB_TX] =
794 0 : lip0->lip_host_sw_if_index;
795 0 : reply_copies[n_copies++] =
796 0 : vlib_get_buffer_index (vm, c0);
797 : }
798 : }
799 : }
800 0 : if (arp1->opcode == clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply))
801 : {
802 0 : lcp_itf_pair_t *lip1 = 0;
803 : u32 lipi1;
804 : vlib_buffer_t *c1;
805 : u8 len1;
806 :
807 0 : lipi1 = lcp_itf_pair_find_by_phy (
808 0 : vnet_buffer (b1)->sw_if_index[VLIB_RX]);
809 0 : lip1 = lcp_itf_pair_get (lipi1);
810 :
811 0 : if (lip1)
812 : {
813 : /*
814 : * rewind to reveal the ethernet header
815 : */
816 0 : len1 = ((u8 *) vlib_buffer_get_current (b1) -
817 0 : (u8 *) ethernet_buffer_get_header (b1));
818 0 : vlib_buffer_advance (b1, -len1);
819 0 : c1 = vlib_buffer_copy (vm, b1);
820 0 : vlib_buffer_advance (b1, len1);
821 :
822 0 : if (c1)
823 : {
824 : /* Send to the host */
825 0 : vnet_buffer (c1)->sw_if_index[VLIB_TX] =
826 0 : lip1->lip_host_sw_if_index;
827 0 : reply_copies[n_copies++] =
828 0 : vlib_get_buffer_index (vm, c1);
829 : }
830 : }
831 : }
832 :
833 0 : if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
834 : {
835 0 : lcp_arp_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
836 0 : t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
837 : }
838 0 : if (PREDICT_FALSE ((b1->flags & VLIB_BUFFER_IS_TRACED)))
839 : {
840 0 : lcp_arp_trace_t *t = vlib_add_trace (vm, node, b1, sizeof (*t));
841 0 : t->rx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];
842 : }
843 :
844 0 : vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
845 : n_left_to_next, bi0, bi1, next0,
846 : next1);
847 : }
848 :
849 16 : while (n_left_from > 0 && n_left_to_next > 0)
850 : {
851 : u32 next0, bi0;
852 : vlib_buffer_t *b0;
853 : ethernet_arp_header_t *arp0;
854 : u16 arp_opcode;
855 :
856 8 : bi0 = to_next[0] = from[0];
857 :
858 8 : from += 1;
859 8 : n_left_from -= 1;
860 8 : to_next += 1;
861 8 : n_left_to_next -= 1;
862 8 : next0 = LCP_ARP_NEXT_DROP;
863 :
864 8 : b0 = vlib_get_buffer (vm, bi0);
865 8 : arp0 = vlib_buffer_get_current (b0);
866 :
867 8 : vnet_feature_next (&next0, b0);
868 :
869 : /*
870 : * Replies might need to be received by the host, so we
871 : * make a copy of them.
872 : */
873 8 : arp_opcode = clib_host_to_net_u16 (arp0->opcode);
874 :
875 8 : if (arp_opcode == ETHERNET_ARP_OPCODE_reply)
876 : {
877 8 : lcp_itf_pair_t *lip0 = 0;
878 : vlib_buffer_t *c0;
879 : u32 lipi0;
880 : u8 len0;
881 :
882 8 : lipi0 = lcp_itf_pair_find_by_phy (
883 8 : vnet_buffer (b0)->sw_if_index[VLIB_RX]);
884 8 : lip0 = lcp_itf_pair_get (lipi0);
885 :
886 8 : if (lip0)
887 : {
888 :
889 : /*
890 : * rewind to reveal the ethernet header
891 : */
892 8 : len0 = ((u8 *) vlib_buffer_get_current (b0) -
893 8 : (u8 *) ethernet_buffer_get_header (b0));
894 8 : vlib_buffer_advance (b0, -len0);
895 8 : c0 = vlib_buffer_copy (vm, b0);
896 8 : vlib_buffer_advance (b0, len0);
897 :
898 8 : if (c0)
899 : {
900 : /* Send to the host */
901 8 : vnet_buffer (c0)->sw_if_index[VLIB_TX] =
902 8 : lip0->lip_host_sw_if_index;
903 8 : reply_copies[n_copies++] =
904 8 : vlib_get_buffer_index (vm, c0);
905 : }
906 : }
907 : }
908 :
909 8 : if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
910 : {
911 8 : lcp_arp_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
912 8 : t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
913 8 : t->arp_opcode = arp_opcode;
914 : }
915 :
916 8 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
917 : n_left_to_next, bi0, next0);
918 : }
919 :
920 8 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
921 : }
922 :
923 8 : if (n_copies)
924 8 : vlib_buffer_enqueue_to_single_next (vm, node, reply_copies,
925 : LCP_ARP_NEXT_IO, n_copies);
926 :
927 8 : return frame->n_vectors;
928 : }
929 :
930 354 : VLIB_REGISTER_NODE (lcp_arp_phy_node) = {
931 : .name = "linux-cp-arp-phy",
932 : .vector_size = sizeof (u32),
933 : .format_trace = format_lcp_arp_trace,
934 : .type = VLIB_NODE_TYPE_INTERNAL,
935 :
936 : .n_errors = LINUXCP_N_ERROR,
937 : .error_counters = linuxcp_error_counters,
938 :
939 : .n_next_nodes = LCP_ARP_N_NEXT,
940 : .next_nodes = {
941 : [LCP_ARP_NEXT_DROP] = "error-drop",
942 : [LCP_ARP_NEXT_IO] = "interface-output",
943 : },
944 : };
945 :
946 174 : VNET_FEATURE_INIT (lcp_arp_phy_arp_feat, static) = {
947 : .arc_name = "arp",
948 : .node_name = "linux-cp-arp-phy",
949 : .runs_before = VNET_FEATURES ("arp-reply"),
950 : };
951 :
952 : /**
953 : * x-connect ARP packets from the host to the phy
954 : */
955 10 : VLIB_NODE_FN (lcp_arp_host_node)
956 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
957 : {
958 : u32 n_left_from, *from, *to_next, n_left_to_next;
959 : lcp_arp_next_t next_index;
960 :
961 8 : next_index = node->cached_next_index;
962 8 : n_left_from = frame->n_vectors;
963 8 : from = vlib_frame_vector_args (frame);
964 :
965 16 : while (n_left_from > 0)
966 : {
967 8 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
968 :
969 16 : while (n_left_from > 0 && n_left_to_next > 0)
970 : {
971 : const lcp_itf_pair_t *lip0;
972 : lcp_arp_next_t next0;
973 : vlib_buffer_t *b0;
974 : u32 bi0, lipi0;
975 : u8 len0;
976 :
977 8 : bi0 = to_next[0] = from[0];
978 :
979 8 : from += 1;
980 8 : n_left_from -= 1;
981 8 : to_next += 1;
982 8 : n_left_to_next -= 1;
983 8 : next0 = LCP_ARP_NEXT_IO;
984 :
985 8 : b0 = vlib_get_buffer (vm, bi0);
986 :
987 : lipi0 =
988 8 : lcp_itf_pair_find_by_host (vnet_buffer (b0)->sw_if_index[VLIB_RX]);
989 8 : lip0 = lcp_itf_pair_get (lipi0);
990 :
991 : /* Send to the phy */
992 8 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = lip0->lip_phy_sw_if_index;
993 :
994 8 : len0 = ((u8 *) vlib_buffer_get_current (b0) -
995 8 : (u8 *) ethernet_buffer_get_header (b0));
996 8 : vlib_buffer_advance (b0, -len0);
997 :
998 8 : if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
999 : {
1000 8 : lcp_arp_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
1001 8 : t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1002 : }
1003 :
1004 8 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1005 : n_left_to_next, bi0, next0);
1006 : }
1007 :
1008 8 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1009 : }
1010 :
1011 8 : return frame->n_vectors;
1012 : }
1013 :
1014 354 : VLIB_REGISTER_NODE (lcp_arp_host_node) = {
1015 : .name = "linux-cp-arp-host",
1016 : .vector_size = sizeof (u32),
1017 : .format_trace = format_lcp_arp_trace,
1018 : .type = VLIB_NODE_TYPE_INTERNAL,
1019 :
1020 : .n_errors = LINUXCP_N_ERROR,
1021 : .error_counters = linuxcp_error_counters,
1022 :
1023 : .n_next_nodes = LCP_ARP_N_NEXT,
1024 : .next_nodes = {
1025 : [LCP_ARP_NEXT_DROP] = "error-drop",
1026 : [LCP_ARP_NEXT_IO] = "interface-output",
1027 : },
1028 : };
1029 :
1030 174 : VNET_FEATURE_INIT (lcp_arp_host_arp_feat, static) = {
1031 : .arc_name = "arp",
1032 : .node_name = "linux-cp-arp-host",
1033 : .runs_before = VNET_FEATURES ("arp-reply"),
1034 : };
1035 :
1036 : /*
1037 : * fd.io coding-style-patch-verification: ON
1038 : *
1039 : * Local Variables:
1040 : * eval: (c-set-style "gnu")
1041 : * End:
1042 : */
|