FD.io VPP  v21.06
Vector Packet Processing
lcp_node.c
Go to the documentation of this file.
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 
23 #include <linux-cp/lcp.api_enum.h>
24 
25 #include <vnet/feature/feature.h>
26 #include <vnet/ip/ip4_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,
43 #undef _
46 
47 typedef struct lip_punt_trace_t_
48 {
52 
53 /* packet trace format function */
54 static u8 *
55 format_lip_punt_trace (u8 *s, va_list *args)
56 {
57  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
58  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
59  lip_punt_trace_t *t = va_arg (*args, lip_punt_trace_t *);
60 
61  s =
62  format (s, "lip-punt: %u -> %u", t->phy_sw_if_index, t->host_sw_if_index);
63 
64  return s;
65 }
66 
67 /**
68  * Pass punted packets from the PHY to the HOST.
69  */
70 VLIB_NODE_FN (lip_punt_node)
72 {
73  u32 n_left_from, *from, *to_next, n_left_to_next;
75 
76  next_index = node->cached_next_index;
77  n_left_from = frame->n_vectors;
79 
80  while (n_left_from > 0)
81  {
82  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
83 
84  while (n_left_from > 0 && n_left_to_next > 0)
85  {
86  vlib_buffer_t *b0;
87  const lcp_itf_pair_t *lip0 = NULL;
88  u32 next0 = ~0;
89  u32 bi0, lipi0;
90  u32 sw_if_index0;
91  u8 len0;
92 
93  bi0 = to_next[0] = from[0];
94 
95  from += 1;
96  to_next += 1;
97  n_left_from -= 1;
98  n_left_to_next -= 1;
99  next0 = LIP_PUNT_NEXT_DROP;
100 
101  b0 = vlib_get_buffer (vm, bi0);
102 
103  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
104  lipi0 = lcp_itf_pair_find_by_phy (sw_if_index0);
105  if (PREDICT_FALSE (lipi0 == INDEX_INVALID))
106  goto trace0;
107 
108  lip0 = lcp_itf_pair_get (lipi0);
109  next0 = LIP_PUNT_NEXT_IO;
110  vnet_buffer (b0)->sw_if_index[VLIB_TX] = lip0->lip_host_sw_if_index;
111 
113  {
114  /*
115  * rewind to ethernet header
116  */
117  len0 = ((u8 *) vlib_buffer_get_current (b0) -
118  (u8 *) ethernet_buffer_get_header (b0));
119  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  trace0:
129  if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
130  {
131  lip_punt_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
132  t->phy_sw_if_index = sw_if_index0;
133  t->host_sw_if_index =
134  (lipi0 == INDEX_INVALID) ? ~0 : lip0->lip_host_sw_if_index;
135  }
136 
137  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
138  n_left_to_next, bi0, next0);
139  }
140 
141  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
142  }
143 
144  return frame->n_vectors;
145 }
146 
147 VLIB_REGISTER_NODE (lip_punt_node) = {
148  .name = "linux-cp-punt",
149  .vector_size = sizeof (u32),
150  .format_trace = format_lip_punt_trace,
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,
166 #undef _
169 
170 typedef struct lcp_punt_l3_trace_t_
171 {
174 
175 /* packet trace format function */
176 static u8 *
177 format_lcp_punt_l3_trace (u8 *s, va_list *args)
178 {
179  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
180  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
181  lcp_punt_l3_trace_t *t = va_arg (*args, lcp_punt_l3_trace_t *);
182 
183  s = format (s, "linux-cp-punt-l3: %u", t->phy_sw_if_index);
184 
185  return s;
186 }
187 
188 VLIB_NODE_FN (lcp_punt_l3_node)
190 {
191  u32 n_left_from, *from, *to_next, n_left_to_next;
193 
194  next_index = node->cached_next_index;
195  n_left_from = frame->n_vectors;
196  from = vlib_frame_vector_args (frame);
197 
198  while (n_left_from > 0)
199  {
200  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
201 
202  while (n_left_from > 0 && n_left_to_next > 0)
203  {
204  vlib_buffer_t *b0;
205  u32 next0 = LCP_LOCAL_NEXT_DROP;
206  u32 bi0;
207  index_t lipi0;
208  lcp_itf_pair_t *lip0;
209 
210  bi0 = to_next[0] = from[0];
211 
212  from += 1;
213  to_next += 1;
214  n_left_from -= 1;
215  n_left_to_next -= 1;
216 
217  b0 = vlib_get_buffer (vm, bi0);
218  vnet_feature_next (&next0, b0);
219 
220  lipi0 =
222  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  lip0 = lcp_itf_pair_get (lipi0);
229  if (lip0->lip_host_type == LCP_ITF_HOST_TUN)
230  b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
231  }
232 
233  if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
234  {
236  vlib_add_trace (vm, node, b0, sizeof (*t));
237  t->phy_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
238  }
239 
240  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
241  n_left_to_next, bi0, next0);
242  }
243 
244  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
245  }
246 
247  return frame->n_vectors;
248 }
249 
250 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,
255 
256  .n_next_nodes = 1,
257  .next_nodes = {
258  [LCP_LOCAL_NEXT_DROP] = "error-drop",
259  },
260 };
261 
262 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 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,
283 #undef _
285 } lcp_xc_next_t;
286 
287 typedef struct lcp_xc_trace_t_
288 {
292 
293 /* packet trace format function */
294 static u8 *
295 format_lcp_xc_trace (u8 *s, va_list *args)
296 {
297  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
298  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
299  lcp_xc_trace_t *t = va_arg (*args, lcp_xc_trace_t *);
300 
301  s = format (s, "lcp-xc: itf:%d adj:%d", t->phy_sw_if_index, t->adj_index);
302 
303  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  */
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  next_index = 0;
324  n_left_from = frame->n_vectors;
325  from = vlib_frame_vector_args (frame);
326 
327  if (AF_IP4 == af)
328  lm = &ip4_main.lookup_main;
329  else
330  lm = &ip6_main.lookup_main;
331 
332  while (n_left_from > 0)
333  {
334  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
335 
336  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 
343  bi0 = to_next[0] = from[0];
344 
345  from += 1;
346  to_next += 1;
347  n_left_from -= 1;
348  n_left_to_next -= 1;
349 
350  b0 = vlib_get_buffer (vm, bi0);
351 
352  lipi =
354  lip = lcp_itf_pair_get (lipi);
355 
356  vnet_buffer (b0)->sw_if_index[VLIB_TX] = lip->lip_phy_sw_if_index;
358  eth = vlib_buffer_get_current (b0);
359 
361  ai = lip->lip_phy_adjs.adj_index[af];
362  else
363  ai = lcp_adj_lkup ((u8 *) eth, lip->lip_rewrite_len,
365 
366  if (ADJ_INDEX_INVALID != ai)
367  {
368  const ip_adjacency_t *adj;
369 
370  adj = adj_get (ai);
371  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ai;
372  next0 = adj->rewrite_header.next_index;
373  vnet_buffer (b0)->ip.save_rewrite_length = lip->lip_rewrite_len;
374 
375  if (PREDICT_FALSE (adj->rewrite_header.flags &
379  vnet_buffer (b0)->sw_if_index[VLIB_TX], &next0, b0,
380  adj->ia_cfg_index);
381  }
382  else
383  next0 = LCP_XC_NEXT_DROP;
384 
385  if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
386  {
387  lcp_xc_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
389  t->adj_index = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
390  }
391 
392  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
393  n_left_to_next, bi0, next0);
394  }
395 
396  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
397  }
398 
399  return frame->n_vectors;
400 }
401 
402 VLIB_NODE_FN (lcp_xc_ip4)
404 {
405  return (lcp_xc_inline (vm, node, frame, AF_IP4));
406 }
407 
408 VLIB_NODE_FN (lcp_xc_ip6)
410 {
411  return (lcp_xc_inline (vm, node, frame, AF_IP6));
412 }
413 
414 VLIB_REGISTER_NODE (lcp_xc_ip4) = { .name = "linux-cp-xc-ip4",
415  .vector_size = sizeof (u32),
416  .format_trace = format_lcp_xc_trace,
418  .sibling_of = "ip4-rewrite" };
419 
420 VNET_FEATURE_INIT (lcp_xc_ip4_ucast_node, static) = {
421  .arc_name = "ip4-unicast",
422  .node_name = "linux-cp-xc-ip4",
423 };
424 VNET_FEATURE_INIT (lcp_xc_ip4_mcast_node, static) = {
425  .arc_name = "ip4-multicast",
426  .node_name = "linux-cp-xc-ip4",
427 };
428 
429 VLIB_REGISTER_NODE (lcp_xc_ip6) = { .name = "linux-cp-xc-ip6",
430  .vector_size = sizeof (u32),
431  .format_trace = format_lcp_xc_trace,
433  .sibling_of = "ip6-rewrite" };
434 
435 VNET_FEATURE_INIT (lcp_xc_ip6_ucast_node, static) = {
436  .arc_name = "ip6-unicast",
437  .node_name = "linux-cp-xc-ip6",
438 };
439 VNET_FEATURE_INIT (lcp_xc_ip6_mcast_node, static) = {
440  .arc_name = "ip6-multicast",
441  .node_name = "linux-cp-xc-ip6",
442 };
443 
444 typedef enum
445 {
449 
450 /**
451  * X-connect all packets from the HOST to the PHY on L3 interfaces
452  *
453  * There's only one adjacency that can be used on thises links.
454  */
458 {
459  u32 n_left_from, *from, *to_next, n_left_to_next;
460  lcp_xc_next_t next_index;
461 
462  next_index = 0;
463  n_left_from = frame->n_vectors;
464  from = vlib_frame_vector_args (frame);
465 
466  while (n_left_from > 0)
467  {
468  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
469 
470  while (n_left_from > 0 && n_left_to_next > 0)
471  {
472  vlib_buffer_t *b0;
473  const lcp_itf_pair_t *lip;
474  u32 next0 = ~0;
475  u32 bi0, lipi;
476 
477  bi0 = to_next[0] = from[0];
478 
479  from += 1;
480  to_next += 1;
481  n_left_from -= 1;
482  n_left_to_next -= 1;
483 
484  b0 = vlib_get_buffer (vm, bi0);
485 
486  /* Flag buffers as locally originated. Otherwise their TTL will
487  * be checked & decremented. That would break services like BGP
488  * which set a TTL of 1 by default.
489  */
490  b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
491 
492  lipi =
494  lip = lcp_itf_pair_get (lipi);
495 
496  vnet_buffer (b0)->sw_if_index[VLIB_TX] = lip->lip_phy_sw_if_index;
497  next0 = LCP_XC_L3_NEXT_XC;
498  vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
499  lip->lip_phy_adjs.adj_index[af];
500 
501  if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
502  {
503  lcp_xc_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
505  t->adj_index = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
506  }
507 
508  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
509  n_left_to_next, bi0, next0);
510  }
511 
512  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
513  }
514 
515  return frame->n_vectors;
516 }
517 
518 /**
519  * X-connect all packets from the HOST to the PHY.
520  */
521 VLIB_NODE_FN (lcp_xc_l3_ip4_node)
523 {
524  return (lcp_xc_l3_inline (vm, node, frame, AF_IP4));
525 }
526 
527 VLIB_NODE_FN (lcp_xc_l3_ip6_node)
529 {
530  return (lcp_xc_l3_inline (vm, node, frame, AF_IP6));
531 }
532 
533 VLIB_REGISTER_NODE (lcp_xc_l3_ip4_node) = {
534  .name = "linux-cp-xc-l3-ip4",
535  .vector_size = sizeof (u32),
536  .format_trace = format_lcp_xc_trace,
538 
539  .n_next_nodes = LCP_XC_L3_N_NEXT,
540  .next_nodes = {
541  [LCP_XC_L3_NEXT_XC] = "ip4-midchain",
542  },
543 };
544 
545 VNET_FEATURE_INIT (lcp_xc_node_l3_ip4_unicast, static) = {
546  .arc_name = "ip4-unicast",
547  .node_name = "linux-cp-xc-l3-ip4",
548 };
549 
550 VNET_FEATURE_INIT (lcp_xc_node_l3_ip4_multicaast, static) = {
551  .arc_name = "ip4-multicast",
552  .node_name = "linux-cp-xc-l3-ip4",
553 };
554 
555 VLIB_REGISTER_NODE (lcp_xc_l3_ip6_node) = {
556  .name = "linux-cp-xc-l3-ip6",
557  .vector_size = sizeof (u32),
558  .format_trace = format_lcp_xc_trace,
560 
561  .n_next_nodes = LCP_XC_L3_N_NEXT,
562  .next_nodes = {
563  [LCP_XC_L3_NEXT_XC] = "ip6-midchain",
564  },
565 };
566 
567 VNET_FEATURE_INIT (lcp_xc_node_l3_ip6_unicast, static) = {
568  .arc_name = "ip6-unicast",
569  .node_name = "linux-cp-xc-l3-ip6",
570 };
571 
572 VNET_FEATURE_INIT (lcp_xc_node_l3_ip6_multicast, static) = {
573  .arc_name = "ip6-multicast",
574  .node_name = "linux-cp-xc-l3-ip6",
575 };
576 
577 #define foreach_lcp_arp \
578  _ (DROP, "error-drop") \
579  _ (IO, "interface-output")
580 
581 typedef enum
582 {
583 #define _(sym, str) LCP_ARP_NEXT_##sym,
585 #undef _
588 
589 typedef struct lcp_arp_trace_t_
590 {
594 
595 /* packet trace format function */
596 static u8 *
597 format_lcp_arp_trace (u8 *s, va_list *args)
598 {
599  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
600  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
601  lcp_arp_trace_t *t = va_arg (*args, lcp_arp_trace_t *);
602 
603  s = format (s, "rx-sw-if-index: %u opcode: %u", t->rx_sw_if_index,
604  t->arp_opcode);
605 
606  return s;
607 }
608 
609 /**
610  * punt ARP replies to the host
611  */
612 VLIB_NODE_FN (lcp_arp_phy_node)
614 {
615  u32 n_left_from, *from, *to_next, n_left_to_next;
616  lcp_arp_next_t next_index;
617  u32 reply_copies[VLIB_FRAME_SIZE];
618  u32 n_copies = 0;
619 
620  next_index = node->cached_next_index;
621  n_left_from = frame->n_vectors;
622  from = vlib_frame_vector_args (frame);
623 
624  while (n_left_from > 0)
625  {
626  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
627 
628  while (n_left_from >= 2 && n_left_to_next >= 2)
629  {
630  u32 next0, next1, bi0, bi1;
631  vlib_buffer_t *b0, *b1;
632  ethernet_arp_header_t *arp0, *arp1;
633 
634  bi0 = to_next[0] = from[0];
635  bi1 = to_next[1] = from[1];
636 
637  from += 2;
638  n_left_from -= 2;
639  to_next += 2;
640  n_left_to_next -= 2;
641 
642  next0 = next1 = LCP_ARP_NEXT_DROP;
643 
644  b0 = vlib_get_buffer (vm, bi0);
645  b1 = vlib_get_buffer (vm, bi1);
646 
647  arp0 = vlib_buffer_get_current (b0);
648  arp1 = vlib_buffer_get_current (b1);
649 
650  vnet_feature_next (&next0, b0);
651  vnet_feature_next (&next1, b1);
652 
653  /*
654  * Replies might need to be received by the host, so we
655  * make a copy of them.
656  */
657  if (arp0->opcode == clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply))
658  {
659  lcp_itf_pair_t *lip0 = 0;
660  u32 lipi0;
661  vlib_buffer_t *c0;
662  u8 len0;
663 
664  lipi0 = lcp_itf_pair_find_by_phy (
666  lip0 = lcp_itf_pair_get (lipi0);
667 
668  if (lip0)
669  {
670  /*
671  * rewind to eth header, copy, advance back to current
672  */
673  len0 = ((u8 *) vlib_buffer_get_current (b0) -
674  (u8 *) ethernet_buffer_get_header (b0));
675  vlib_buffer_advance (b0, -len0);
676  c0 = vlib_buffer_copy (vm, b0);
677  vlib_buffer_advance (b0, len0);
678 
679  /* Send to the host */
680  vnet_buffer (c0)->sw_if_index[VLIB_TX] =
681  lip0->lip_host_sw_if_index;
682  reply_copies[n_copies++] = vlib_get_buffer_index (vm, c0);
683  }
684  }
685  if (arp1->opcode == clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply))
686  {
687  lcp_itf_pair_t *lip1 = 0;
688  u32 lipi1;
689  vlib_buffer_t *c1;
690  u8 len1;
691 
692  lipi1 = lcp_itf_pair_find_by_phy (
694  lip1 = lcp_itf_pair_get (lipi1);
695 
696  if (lip1)
697  {
698  /*
699  * rewind to reveal the ethernet header
700  */
701  len1 = ((u8 *) vlib_buffer_get_current (b1) -
702  (u8 *) ethernet_buffer_get_header (b1));
703  vlib_buffer_advance (b1, -len1);
704  c1 = vlib_buffer_copy (vm, b1);
705  vlib_buffer_advance (b1, len1);
706 
707  /* Send to the host */
708  vnet_buffer (c1)->sw_if_index[VLIB_TX] =
709  lip1->lip_host_sw_if_index;
710  reply_copies[n_copies++] = vlib_get_buffer_index (vm, c1);
711  }
712  }
713 
714  if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
715  {
716  lcp_arp_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
717  t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
718  }
719  if (PREDICT_FALSE ((b1->flags & VLIB_BUFFER_IS_TRACED)))
720  {
721  lcp_arp_trace_t *t = vlib_add_trace (vm, node, b1, sizeof (*t));
722  t->rx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];
723  }
724 
725  vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
726  n_left_to_next, bi0, bi1, next0,
727  next1);
728  }
729 
730  while (n_left_from > 0 && n_left_to_next > 0)
731  {
732  u32 next0, bi0;
733  vlib_buffer_t *b0;
734  ethernet_arp_header_t *arp0;
735  u16 arp_opcode;
736 
737  bi0 = to_next[0] = from[0];
738 
739  from += 1;
740  n_left_from -= 1;
741  to_next += 1;
742  n_left_to_next -= 1;
743  next0 = LCP_ARP_NEXT_DROP;
744 
745  b0 = vlib_get_buffer (vm, bi0);
746  arp0 = vlib_buffer_get_current (b0);
747 
748  vnet_feature_next (&next0, b0);
749 
750  /*
751  * Replies might need to be received by the host, so we
752  * make a copy of them.
753  */
754  arp_opcode = clib_host_to_net_u16 (arp0->opcode);
755 
756  if (arp_opcode == ETHERNET_ARP_OPCODE_reply)
757  {
758  lcp_itf_pair_t *lip0 = 0;
759  vlib_buffer_t *c0;
760  u32 lipi0;
761  u8 len0;
762 
763  lipi0 = lcp_itf_pair_find_by_phy (
765  lip0 = lcp_itf_pair_get (lipi0);
766 
767  if (lip0)
768  {
769 
770  /*
771  * rewind to reveal the ethernet header
772  */
773  len0 = ((u8 *) vlib_buffer_get_current (b0) -
774  (u8 *) ethernet_buffer_get_header (b0));
775  vlib_buffer_advance (b0, -len0);
776  c0 = vlib_buffer_copy (vm, b0);
777  vlib_buffer_advance (b0, len0);
778 
779  /* Send to the host */
780  vnet_buffer (c0)->sw_if_index[VLIB_TX] =
781  lip0->lip_host_sw_if_index;
782  reply_copies[n_copies++] = vlib_get_buffer_index (vm, c0);
783  }
784  }
785 
786  if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
787  {
788  lcp_arp_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
789  t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
790  t->arp_opcode = arp_opcode;
791  }
792 
793  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
794  n_left_to_next, bi0, next0);
795  }
796 
797  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
798  }
799 
800  if (n_copies)
801  vlib_buffer_enqueue_to_single_next (vm, node, reply_copies,
802  LCP_ARP_NEXT_IO, n_copies);
803 
804  return frame->n_vectors;
805 }
806 
807 VLIB_REGISTER_NODE (lcp_arp_phy_node) = {
808  .name = "linux-cp-arp-phy",
809  .vector_size = sizeof (u32),
810  .format_trace = format_lcp_arp_trace,
812 
813  .n_errors = LINUXCP_N_ERROR,
814  .error_counters = linuxcp_error_counters,
815 
816  .n_next_nodes = LCP_ARP_N_NEXT,
817  .next_nodes = {
818  [LCP_ARP_NEXT_DROP] = "error-drop",
819  [LCP_ARP_NEXT_IO] = "interface-output",
820  },
821 };
822 
823 VNET_FEATURE_INIT (lcp_arp_phy_arp_feat, static) = {
824  .arc_name = "arp",
825  .node_name = "linux-cp-arp-phy",
826  .runs_before = VNET_FEATURES ("arp-reply"),
827 };
828 
829 /**
830  * x-connect ARP packets from the host to the phy
831  */
834 {
835  u32 n_left_from, *from, *to_next, n_left_to_next;
836  lcp_arp_next_t next_index;
837 
838  next_index = node->cached_next_index;
839  n_left_from = frame->n_vectors;
840  from = vlib_frame_vector_args (frame);
841 
842  while (n_left_from > 0)
843  {
844  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
845 
846  while (n_left_from > 0 && n_left_to_next > 0)
847  {
848  const lcp_itf_pair_t *lip0;
849  lcp_arp_next_t next0;
850  vlib_buffer_t *b0;
851  u32 bi0, lipi0;
852  u8 len0;
853 
854  bi0 = to_next[0] = from[0];
855 
856  from += 1;
857  n_left_from -= 1;
858  to_next += 1;
859  n_left_to_next -= 1;
860  next0 = LCP_ARP_NEXT_IO;
861 
862  b0 = vlib_get_buffer (vm, bi0);
863 
864  lipi0 =
866  lip0 = lcp_itf_pair_get (lipi0);
867 
868  /* Send to the phy */
869  vnet_buffer (b0)->sw_if_index[VLIB_TX] = lip0->lip_phy_sw_if_index;
870 
871  len0 = ((u8 *) vlib_buffer_get_current (b0) -
872  (u8 *) ethernet_buffer_get_header (b0));
873  vlib_buffer_advance (b0, -len0);
874 
875  if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
876  {
877  lcp_arp_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
878  t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
879  }
880 
881  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
882  n_left_to_next, bi0, next0);
883  }
884 
885  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
886  }
887 
888  return frame->n_vectors;
889 }
890 
892  .name = "linux-cp-arp-host",
893  .vector_size = sizeof (u32),
894  .format_trace = format_lcp_arp_trace,
896 
897  .n_errors = LINUXCP_N_ERROR,
898  .error_counters = linuxcp_error_counters,
899 
900  .n_next_nodes = LCP_ARP_N_NEXT,
901  .next_nodes = {
902  [LCP_ARP_NEXT_DROP] = "error-drop",
903  [LCP_ARP_NEXT_IO] = "interface-output",
904  },
905 };
906 
907 VNET_FEATURE_INIT (lcp_arp_host_arp_feat, static) = {
908  .arc_name = "arp",
909  .node_name = "linux-cp-arp-host",
910  .runs_before = VNET_FEATURES ("arp-reply"),
911 };
912 
913 /*
914  * fd.io coding-style-patch-verification: ON
915  *
916  * Local Variables:
917  * eval: (c-set-style "gnu")
918  * End:
919  */
lip_host_type_t lip_host_type
Definition: lcp_interface.h:56
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:133
#define CLIB_UNUSED(x)
Definition: clib.h:90
static u8 * format_lcp_arp_trace(u8 *s, va_list *args)
Definition: lcp_node.c:597
#define PREDICT_TRUE(x)
Definition: clib.h:125
A pair of interfaces.
Definition: lcp_interface.h:49
Definitions for all things IP (v4|v6) unicast and multicast lookup related.
IP unicast adjacency.
Definition: adj.h:235
from
Definition: lcp_node.c:78
u32 index_t
A Data-Path Object is an object that represents actions that are applied to packets are they are swit...
Definition: dpo.h:43
struct lcp_punt_l3_trace_t_ lcp_punt_l3_trace_t
struct lip_punt_trace_t_ lip_punt_trace_t
ip_lookup_main_t lookup_main
Definition: ip4.h:109
#define VLIB_NODE_FN(node)
Definition: node.h:202
static u8 * format_lcp_xc_trace(u8 *s, va_list *args)
Definition: lcp_node.c:295
struct lcp_arp_trace_t_ lcp_arp_trace_t
unsigned char u8
Definition: types.h:56
lcp_xc_next_t
Definition: lcp_node.c:279
static vlib_buffer_t * vlib_buffer_copy(vlib_main_t *vm, vlib_buffer_t *b)
#define foreach_lip_punt
Definition: lcp_node.c:35
lcp_xc_l3_next_t
Definition: lcp_node.c:444
static index_t lcp_itf_pair_find_by_phy(u32 phy_sw_if_index)
unsigned int u32
Definition: types.h:88
u8 output_feature_arc_index
Definition: lookup.h:145
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: lcp_node.c:72
static ip_adjacency_t * adj_get(adj_index_t adj_index)
Get a pointer to an adjacency object from its index.
Definition: adj.h:470
#define static_always_inline
Definition: clib.h:112
lcp_punt_l3_next_t
Definition: lcp_node.c:162
u8 dst_address[6]
Definition: packet.h:55
description fragment has unexpected format
Definition: map.api:433
static_always_inline void vlib_buffer_enqueue_to_single_next(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, u16 next_index, u32 count)
Definition: buffer_node.h:348
VNET_FEATURE_INIT(lcp_punt_l3_ip4, static)
vlib_node_registration_t lcp_arp_host_node
(constructor) VLIB_REGISTER_NODE (lcp_arp_host_node)
Definition: lcp_node.c:891
lip_punt_next_t
Definition: lcp_node.c:39
#define VLIB_FRAME_SIZE
Definition: node.h:369
static u32 vlib_get_buffer_index(vlib_main_t *vm, void *p)
Translate buffer pointer into buffer index.
Definition: buffer_funcs.h:324
lip_punt_next_t next_index
Definition: lcp_node.c:74
static_always_inline u32 lcp_xc_l3_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, ip_address_family_t af)
X-connect all packets from the HOST to the PHY on L3 interfaces.
Definition: lcp_node.c:456
vl_api_fib_path_type_t type
Definition: fib_types.api:123
#define ADJ_INDEX_INVALID
Invalid ADJ index - used when no adj is known likewise blazoned capitals INVALID speak volumes where ...
Definition: adj_types.h:36
static ethernet_header_t * ethernet_buffer_get_header(vlib_buffer_t *b)
Definition: ethernet.h:419
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
unsigned short u16
Definition: types.h:57
#define foreach_lcp_punt_l3
Definition: lcp_node.c:160
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:257
#define foreach_lcp_arp
Definition: lcp_node.c:577
static_always_inline void * vnet_feature_arc_start_w_cfg_index(u8 arc, u32 sw_if_index, u32 *next, vlib_buffer_t *b, u32 cfg_index)
Definition: feature.h:285
#define PREDICT_FALSE(x)
Definition: clib.h:124
ip6_main_t ip6_main
Definition: ip6_forward.c:2787
lcp_arp_next_t
Definition: lcp_node.c:581
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Finish enqueueing two buffers forward in the graph.
Definition: buffer_node.h:70
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:224
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:395
static u8 * format_lip_punt_trace(u8 *s, va_list *args)
Definition: lcp_node.c:55
static_always_inline adj_index_t lcp_adj_lkup(const u8 *rewrite, u8 len, u32 sw_if_index)
Definition: lcp_adj.h:64
static uword ethernet_address_cast(const u8 *a)
Definition: packet.h:67
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
u16 n_vectors
Definition: node.h:388
static index_t lcp_itf_pair_find_by_host(u32 host_sw_if_index)
static_always_inline void vnet_feature_next(u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:322
struct lcp_xc_trace_t_ lcp_xc_trace_t
u32 adj_index_t
An index for adjacencies.
Definition: adj_types.h:30
adj_index_t adj_index
Definition: lcp_node.c:290
ip_lookup_main_t lookup_main
Definition: ip6.h:112
lcp_itf_phy_adj_t lip_phy_adjs
Definition: lcp_interface.h:57
vlib_put_next_frame(vm, node, next_index, 0)
u32 ia_cfg_index
feature [arc] config index
Definition: adj.h:247
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:276
u32 host_sw_if_index
Definition: lcp_node.c:50
static u8 * format_lcp_punt_l3_trace(u8 *s, va_list *args)
Definition: lcp_node.c:177
#define VNET_FEATURES(...)
Definition: feature.h:470
enum ip_address_family_t_ ip_address_family_t
vlib_main_t vlib_node_runtime_t * node
Definition: lcp_node.c:71
Definition: defs.h:47
#define INDEX_INVALID
Invalid index - used when no index is known blazoned capitals INVALID speak volumes where ~0 does not...
Definition: dpo.h:49
VLIB buffer representation.
Definition: buffer.h:111
adj_index_t adj_index[N_AF]
Definition: lcp_interface.h:43
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:301
static_always_inline u32 lcp_xc_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, ip_address_family_t af)
X-connect all packets from the HOST to the PHY.
Definition: lcp_node.c:316
vlib_main_t * vm
Pass punted packets from the PHY to the HOST.
Definition: lcp_node.c:71
lcp_itf_pair_t * lcp_itf_pair_get(u32 index)
Get an interface-pair object from its VPP index.
#define vnet_buffer(b)
Definition: buffer.h:437
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1105
void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace.c:628
#define foreach_lcp_xc
Definition: lcp_node.c:274
u32 phy_sw_if_index
Definition: lcp_node.c:289
This adjacency/interface has output features configured.
Definition: rewrite.h:57
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:111
n_left_from
Definition: lcp_node.c:77
Definition: defs.h:46