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