FD.io VPP  v21.10.1-2-g0a485f517
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  */
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 
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 
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 
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;
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 
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 
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;
321  ip_lookup_main_t *lm;
322 
323  next_index = 0;
324  n_left_from = frame->n_vectors;
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  const ip_adjacency_t *adj;
343 
344  bi0 = to_next[0] = from[0];
345 
346  from += 1;
347  to_next += 1;
348  n_left_from -= 1;
349  n_left_to_next -= 1;
350 
351  b0 = vlib_get_buffer (vm, bi0);
352 
353  lipi =
355  lip = lcp_itf_pair_get (lipi);
356 
357  vnet_buffer (b0)->sw_if_index[VLIB_TX] = lip->lip_phy_sw_if_index;
359  eth = vlib_buffer_get_current (b0);
360 
361  ai = ADJ_INDEX_INVALID;
363  ai = lcp_adj_lkup ((u8 *) eth, lip->lip_rewrite_len,
365  if (ai == ADJ_INDEX_INVALID)
366  ai = lip->lip_phy_adjs.adj_index[af];
367 
368  adj = adj_get (ai);
369  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ai;
370  next0 = adj->rewrite_header.next_index;
371  vnet_buffer (b0)->ip.save_rewrite_length = lip->lip_rewrite_len;
372 
373  if (PREDICT_FALSE (adj->rewrite_header.flags &
377  vnet_buffer (b0)->sw_if_index[VLIB_TX], &next0, b0,
378  adj->ia_cfg_index);
379 
380  if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
381  {
382  lcp_xc_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
384  t->adj_index = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
385  }
386 
388  n_left_to_next, bi0, next0);
389  }
390 
391  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
392  }
393 
394  return frame->n_vectors;
395 }
396 
399 {
400  return (lcp_xc_inline (vm, node, frame, AF_IP4));
401 }
402 
405 {
406  return (lcp_xc_inline (vm, node, frame, AF_IP6));
407 }
408 
409 VLIB_REGISTER_NODE (lcp_xc_ip4) = { .name = "linux-cp-xc-ip4",
410  .vector_size = sizeof (u32),
411  .format_trace = format_lcp_xc_trace,
413  .sibling_of = "ip4-rewrite" };
414 
415 VNET_FEATURE_INIT (lcp_xc_ip4_ucast_node, static) = {
416  .arc_name = "ip4-unicast",
417  .node_name = "linux-cp-xc-ip4",
418 };
419 VNET_FEATURE_INIT (lcp_xc_ip4_mcast_node, static) = {
420  .arc_name = "ip4-multicast",
421  .node_name = "linux-cp-xc-ip4",
422 };
423 
424 VLIB_REGISTER_NODE (lcp_xc_ip6) = { .name = "linux-cp-xc-ip6",
425  .vector_size = sizeof (u32),
426  .format_trace = format_lcp_xc_trace,
428  .sibling_of = "ip6-rewrite" };
429 
430 VNET_FEATURE_INIT (lcp_xc_ip6_ucast_node, static) = {
431  .arc_name = "ip6-unicast",
432  .node_name = "linux-cp-xc-ip6",
433 };
434 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 {
444 
445 /**
446  * X-connect all packets from the HOST to the PHY on L3 interfaces
447  *
448  * There's only one adjacency that can be used on thises links.
449  */
453 {
454  u32 n_left_from, *from, *to_next, n_left_to_next;
456 
457  next_index = 0;
458  n_left_from = frame->n_vectors;
460 
461  while (n_left_from > 0)
462  {
463  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
464 
465  while (n_left_from > 0 && n_left_to_next > 0)
466  {
467  vlib_buffer_t *b0;
468  const lcp_itf_pair_t *lip;
469  u32 next0 = ~0;
470  u32 bi0, lipi;
471 
472  bi0 = to_next[0] = from[0];
473 
474  from += 1;
475  to_next += 1;
476  n_left_from -= 1;
477  n_left_to_next -= 1;
478 
479  b0 = vlib_get_buffer (vm, bi0);
480 
481  /* Flag buffers as locally originated. Otherwise their TTL will
482  * be checked & decremented. That would break services like BGP
483  * which set a TTL of 1 by default.
484  */
485  b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
486 
487  lipi =
489  lip = lcp_itf_pair_get (lipi);
490 
491  vnet_buffer (b0)->sw_if_index[VLIB_TX] = lip->lip_phy_sw_if_index;
492  next0 = LCP_XC_L3_NEXT_XC;
493  vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
494  lip->lip_phy_adjs.adj_index[af];
495 
496  if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
497  {
498  lcp_xc_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
500  t->adj_index = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
501  }
502 
504  n_left_to_next, bi0, next0);
505  }
506 
507  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
508  }
509 
510  return frame->n_vectors;
511 }
512 
513 /**
514  * X-connect all packets from the HOST to the PHY.
515  */
518 {
519  return (lcp_xc_l3_inline (vm, node, frame, AF_IP4));
520 }
521 
524 {
525  return (lcp_xc_l3_inline (vm, node, frame, AF_IP6));
526 }
527 
529  .name = "linux-cp-xc-l3-ip4",
530  .vector_size = sizeof (u32),
531  .format_trace = format_lcp_xc_trace,
533 
534  .n_next_nodes = LCP_XC_L3_N_NEXT,
535  .next_nodes = {
536  [LCP_XC_L3_NEXT_XC] = "ip4-midchain",
537  },
538 };
539 
540 VNET_FEATURE_INIT (lcp_xc_node_l3_ip4_unicast, static) = {
541  .arc_name = "ip4-unicast",
542  .node_name = "linux-cp-xc-l3-ip4",
543 };
544 
545 VNET_FEATURE_INIT (lcp_xc_node_l3_ip4_multicaast, static) = {
546  .arc_name = "ip4-multicast",
547  .node_name = "linux-cp-xc-l3-ip4",
548 };
549 
551  .name = "linux-cp-xc-l3-ip6",
552  .vector_size = sizeof (u32),
553  .format_trace = format_lcp_xc_trace,
555 
556  .n_next_nodes = LCP_XC_L3_N_NEXT,
557  .next_nodes = {
558  [LCP_XC_L3_NEXT_XC] = "ip6-midchain",
559  },
560 };
561 
562 VNET_FEATURE_INIT (lcp_xc_node_l3_ip6_unicast, static) = {
563  .arc_name = "ip6-unicast",
564  .node_name = "linux-cp-xc-l3-ip6",
565 };
566 
567 VNET_FEATURE_INIT (lcp_xc_node_l3_ip6_multicast, static) = {
568  .arc_name = "ip6-multicast",
569  .node_name = "linux-cp-xc-l3-ip6",
570 };
571 
572 #define foreach_lcp_arp \
573  _ (DROP, "error-drop") \
574  _ (IO, "interface-output")
575 
576 typedef enum
577 {
578 #define _(sym, str) LCP_ARP_NEXT_##sym,
580 #undef _
583 
584 typedef struct lcp_arp_trace_t_
585 {
589 
590 /* packet trace format function */
591 static u8 *
592 format_lcp_arp_trace (u8 *s, va_list *args)
593 {
594  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
595  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
596  lcp_arp_trace_t *t = va_arg (*args, lcp_arp_trace_t *);
597 
598  s = format (s, "rx-sw-if-index: %u opcode: %u", t->rx_sw_if_index,
599  t->arp_opcode);
600 
601  return s;
602 }
603 
604 /**
605  * punt ARP replies to the host
606  */
607 VLIB_NODE_FN (lcp_arp_phy_node)
609 {
610  u32 n_left_from, *from, *to_next, n_left_to_next;
614 
615  next_index = node->cached_next_index;
616  n_left_from = frame->n_vectors;
618 
619  while (n_left_from > 0)
620  {
621  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
622 
623  while (n_left_from >= 2 && n_left_to_next >= 2)
624  {
625  u32 next0, next1, bi0, bi1;
626  vlib_buffer_t *b0, *b1;
627  ethernet_arp_header_t *arp0, *arp1;
628 
629  bi0 = to_next[0] = from[0];
630  bi1 = to_next[1] = from[1];
631 
632  from += 2;
633  n_left_from -= 2;
634  to_next += 2;
635  n_left_to_next -= 2;
636 
637  next0 = next1 = LCP_ARP_NEXT_DROP;
638 
639  b0 = vlib_get_buffer (vm, bi0);
640  b1 = vlib_get_buffer (vm, bi1);
641 
642  arp0 = vlib_buffer_get_current (b0);
643  arp1 = vlib_buffer_get_current (b1);
644 
645  vnet_feature_next (&next0, b0);
646  vnet_feature_next (&next1, b1);
647 
648  /*
649  * Replies might need to be received by the host, so we
650  * make a copy of them.
651  */
652  if (arp0->opcode == clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply))
653  {
654  lcp_itf_pair_t *lip0 = 0;
655  u32 lipi0;
656  vlib_buffer_t *c0;
657  u8 len0;
658 
659  lipi0 = lcp_itf_pair_find_by_phy (
661  lip0 = lcp_itf_pair_get (lipi0);
662 
663  if (lip0)
664  {
665  /*
666  * rewind to eth header, copy, advance back to current
667  */
668  len0 = ((u8 *) vlib_buffer_get_current (b0) -
669  (u8 *) ethernet_buffer_get_header (b0));
670  vlib_buffer_advance (b0, -len0);
671  c0 = vlib_buffer_copy (vm, b0);
672  vlib_buffer_advance (b0, len0);
673 
674  if (c0)
675  {
676  /* Send to the host */
677  vnet_buffer (c0)->sw_if_index[VLIB_TX] =
678  lip0->lip_host_sw_if_index;
681  }
682  }
683  }
684  if (arp1->opcode == clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply))
685  {
686  lcp_itf_pair_t *lip1 = 0;
687  u32 lipi1;
688  vlib_buffer_t *c1;
689  u8 len1;
690 
691  lipi1 = lcp_itf_pair_find_by_phy (
693  lip1 = lcp_itf_pair_get (lipi1);
694 
695  if (lip1)
696  {
697  /*
698  * rewind to reveal the ethernet header
699  */
700  len1 = ((u8 *) vlib_buffer_get_current (b1) -
701  (u8 *) ethernet_buffer_get_header (b1));
702  vlib_buffer_advance (b1, -len1);
703  c1 = vlib_buffer_copy (vm, b1);
704  vlib_buffer_advance (b1, len1);
705 
706  if (c1)
707  {
708  /* Send to the host */
709  vnet_buffer (c1)->sw_if_index[VLIB_TX] =
710  lip1->lip_host_sw_if_index;
713  }
714  }
715  }
716 
717  if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
718  {
719  lcp_arp_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
720  t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
721  }
722  if (PREDICT_FALSE ((b1->flags & VLIB_BUFFER_IS_TRACED)))
723  {
724  lcp_arp_trace_t *t = vlib_add_trace (vm, node, b1, sizeof (*t));
725  t->rx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];
726  }
727 
729  n_left_to_next, bi0, bi1, next0,
730  next1);
731  }
732 
733  while (n_left_from > 0 && n_left_to_next > 0)
734  {
735  u32 next0, bi0;
736  vlib_buffer_t *b0;
737  ethernet_arp_header_t *arp0;
738  u16 arp_opcode;
739 
740  bi0 = to_next[0] = from[0];
741 
742  from += 1;
743  n_left_from -= 1;
744  to_next += 1;
745  n_left_to_next -= 1;
746  next0 = LCP_ARP_NEXT_DROP;
747 
748  b0 = vlib_get_buffer (vm, bi0);
749  arp0 = vlib_buffer_get_current (b0);
750 
751  vnet_feature_next (&next0, b0);
752 
753  /*
754  * Replies might need to be received by the host, so we
755  * make a copy of them.
756  */
757  arp_opcode = clib_host_to_net_u16 (arp0->opcode);
758 
759  if (arp_opcode == ETHERNET_ARP_OPCODE_reply)
760  {
761  lcp_itf_pair_t *lip0 = 0;
762  vlib_buffer_t *c0;
763  u32 lipi0;
764  u8 len0;
765 
766  lipi0 = lcp_itf_pair_find_by_phy (
768  lip0 = lcp_itf_pair_get (lipi0);
769 
770  if (lip0)
771  {
772 
773  /*
774  * rewind to reveal the ethernet header
775  */
776  len0 = ((u8 *) vlib_buffer_get_current (b0) -
777  (u8 *) ethernet_buffer_get_header (b0));
778  vlib_buffer_advance (b0, -len0);
779  c0 = vlib_buffer_copy (vm, b0);
780  vlib_buffer_advance (b0, len0);
781 
782  if (c0)
783  {
784  /* Send to the host */
785  vnet_buffer (c0)->sw_if_index[VLIB_TX] =
786  lip0->lip_host_sw_if_index;
789  }
790  }
791  }
792 
793  if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
794  {
795  lcp_arp_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
796  t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
797  t->arp_opcode = arp_opcode;
798  }
799 
801  n_left_to_next, bi0, next0);
802  }
803 
804  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
805  }
806 
807  if (n_copies)
809  LCP_ARP_NEXT_IO, n_copies);
810 
811  return frame->n_vectors;
812 }
813 
814 VLIB_REGISTER_NODE (lcp_arp_phy_node) = {
815  .name = "linux-cp-arp-phy",
816  .vector_size = sizeof (u32),
817  .format_trace = format_lcp_arp_trace,
819 
820  .n_errors = LINUXCP_N_ERROR,
821  .error_counters = linuxcp_error_counters,
822 
823  .n_next_nodes = LCP_ARP_N_NEXT,
824  .next_nodes = {
825  [LCP_ARP_NEXT_DROP] = "error-drop",
826  [LCP_ARP_NEXT_IO] = "interface-output",
827  },
828 };
829 
830 VNET_FEATURE_INIT (lcp_arp_phy_arp_feat, static) = {
831  .arc_name = "arp",
832  .node_name = "linux-cp-arp-phy",
833  .runs_before = VNET_FEATURES ("arp-reply"),
834 };
835 
836 /**
837  * x-connect ARP packets from the host to the phy
838  */
841 {
842  u32 n_left_from, *from, *to_next, n_left_to_next;
844 
845  next_index = node->cached_next_index;
846  n_left_from = frame->n_vectors;
848 
849  while (n_left_from > 0)
850  {
851  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
852 
853  while (n_left_from > 0 && n_left_to_next > 0)
854  {
855  const lcp_itf_pair_t *lip0;
856  lcp_arp_next_t next0;
857  vlib_buffer_t *b0;
858  u32 bi0, lipi0;
859  u8 len0;
860 
861  bi0 = to_next[0] = from[0];
862 
863  from += 1;
864  n_left_from -= 1;
865  to_next += 1;
866  n_left_to_next -= 1;
867  next0 = LCP_ARP_NEXT_IO;
868 
869  b0 = vlib_get_buffer (vm, bi0);
870 
871  lipi0 =
873  lip0 = lcp_itf_pair_get (lipi0);
874 
875  /* Send to the phy */
876  vnet_buffer (b0)->sw_if_index[VLIB_TX] = lip0->lip_phy_sw_if_index;
877 
878  len0 = ((u8 *) vlib_buffer_get_current (b0) -
879  (u8 *) ethernet_buffer_get_header (b0));
880  vlib_buffer_advance (b0, -len0);
881 
882  if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
883  {
884  lcp_arp_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
885  t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
886  }
887 
889  n_left_to_next, bi0, next0);
890  }
891 
892  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
893  }
894 
895  return frame->n_vectors;
896 }
897 
899  .name = "linux-cp-arp-host",
900  .vector_size = sizeof (u32),
901  .format_trace = format_lcp_arp_trace,
903 
904  .n_errors = LINUXCP_N_ERROR,
905  .error_counters = linuxcp_error_counters,
906 
907  .n_next_nodes = LCP_ARP_N_NEXT,
908  .next_nodes = {
909  [LCP_ARP_NEXT_DROP] = "error-drop",
910  [LCP_ARP_NEXT_IO] = "interface-output",
911  },
912 };
913 
914 VNET_FEATURE_INIT (lcp_arp_host_arp_feat, static) = {
915  .arc_name = "arp",
916  .node_name = "linux-cp-arp-host",
917  .runs_before = VNET_FEATURES ("arp-reply"),
918 };
919 
920 /*
921  * fd.io coding-style-patch-verification: ON
922  *
923  * Local Variables:
924  * eval: (c-set-style "gnu")
925  * End:
926  */
lcp_arp_trace_t_::rx_sw_if_index
u32 rx_sw_if_index
Definition: lcp_node.c:586
lcp_xc_l3_ip6_node
vlib_node_registration_t lcp_xc_l3_ip6_node
(constructor) VLIB_REGISTER_NODE (lcp_xc_l3_ip6_node)
Definition: lcp_node.c:550
LIP_PUNT_N_NEXT
@ LIP_PUNT_N_NEXT
Definition: lcp_node.c:44
frame
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: lcp_node.c:72
ethernet_arp_header_t::opcode
u16 opcode
Definition: arp_packet.h:139
lcp_itf_pair_find_by_host
static index_t lcp_itf_pair_find_by_host(u32 host_sw_if_index)
Definition: lcp_interface.h:140
lcp_itf_pair_t_
A pair of interfaces.
Definition: lcp_interface.h:49
ip4_main_t::lookup_main
ip_lookup_main_t lookup_main
Definition: ip4.h:109
vlib_buffer_copy
static vlib_buffer_t * vlib_buffer_copy(vlib_main_t *vm, vlib_buffer_t *b)
Definition: buffer_funcs.h:1078
lcp_xc_trace_t_::adj_index
adj_index_t adj_index
Definition: lcp_node.c:290
ip4_main
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1104
vlib_get_buffer
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
ADJ_INDEX_INVALID
#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
format_lip_punt_trace
static u8 * format_lip_punt_trace(u8 *s, va_list *args)
Definition: lcp_node.c:55
ethernet_header_t::dst_address
u8 dst_address[6]
Definition: packet.h:55
VLIB_NODE_TYPE_INTERNAL
@ VLIB_NODE_TYPE_INTERNAL
Definition: node.h:72
VLIB_FRAME_SIZE
#define VLIB_FRAME_SIZE
Definition: node.h:368
u16
unsigned short u16
Definition: types.h:57
n_left_from
n_left_from
Definition: lcp_node.c:77
VNET_REWRITE_HAS_FEATURES
@ VNET_REWRITE_HAS_FEATURES
This adjacency/interface has output features configured.
Definition: rewrite.h:57
AF_IP4
@ AF_IP4
Definition: ip_types.h:23
VLIB_RX
@ VLIB_RX
Definition: defs.h:46
lcp_xc_inline
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
lcp_xc_ip4
vlib_node_registration_t lcp_xc_ip4
(constructor) VLIB_REGISTER_NODE (lcp_xc_ip4)
Definition: lcp_node.c:409
lcp_itf_pair_t_::lip_phy_sw_if_index
u32 lip_phy_sw_if_index
Definition: lcp_interface.h:52
vlib_frame_t
Definition: node.h:372
lcp_itf_pair_t_::lip_phy_adjs
lcp_itf_phy_adj_t lip_phy_adjs
Definition: lcp_interface.h:57
n_copies
u32 n_copies
Definition: lcp_node.c:613
LCP_LOCAL_N_NEXT
@ LCP_LOCAL_N_NEXT
Definition: lcp_node.c:167
ethernet.h
lcp_itf_phy_adj::adj_index
adj_index_t adj_index[N_AF]
Definition: lcp_interface.h:43
vnet_feature_arc_start_w_cfg_index
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
lcp_itf_pair_get
lcp_itf_pair_t * lcp_itf_pair_get(u32 index)
Get an interface-pair object from its VPP index.
Definition: lcp_interface.c:156
ethernet_arp_header_t
Definition: arp_packet.h:133
vlib_buffer_enqueue_to_single_next
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:373
vlib_buffer_advance
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:276
LCP_ARP_N_NEXT
@ LCP_ARP_N_NEXT
Definition: lcp_node.c:581
VLIB_NODE_FN
#define VLIB_NODE_FN(node)
Definition: node.h:202
feature.h
lcp_punt_l3_trace_t_
Definition: lcp_node.c:170
lcp_punt_l3_trace_t
struct lcp_punt_l3_trace_t_ lcp_punt_l3_trace_t
CLIB_UNUSED
#define CLIB_UNUSED(x)
Definition: clib.h:90
vnet_buffer
#define vnet_buffer(b)
Definition: buffer.h:441
PREDICT_FALSE
#define PREDICT_FALSE(x)
Definition: clib.h:124
vnet_feature_next
static_always_inline void vnet_feature_next(u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:322
vlib_get_buffer_index
static u32 vlib_get_buffer_index(vlib_main_t *vm, void *p)
Translate buffer pointer into buffer index.
Definition: buffer_funcs.h:324
vlib_frame_vector_args
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:301
lcp_xc_ip6
vlib_node_registration_t lcp_xc_ip6
(constructor) VLIB_REGISTER_NODE (lcp_xc_ip6)
Definition: lcp_node.c:424
index_t
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
static_always_inline
#define static_always_inline
Definition: clib.h:112
lip_punt_trace_t_
Definition: lcp_node.c:47
ethernet_header_t
Definition: packet.h:52
LCP_XC_L3_NEXT_XC
@ LCP_XC_L3_NEXT_XC
Definition: lcp_node.c:441
lcp_punt_l3_node
vlib_node_registration_t lcp_punt_l3_node
(constructor) VLIB_REGISTER_NODE (lcp_punt_l3_node)
Definition: lcp_node.c:250
lcp_adj.h
format_lcp_punt_l3_trace
static u8 * format_lcp_punt_l3_trace(u8 *s, va_list *args)
Definition: lcp_node.c:177
LCP_XC_L3_N_NEXT
@ LCP_XC_L3_N_NEXT
Definition: lcp_node.c:442
node
vlib_main_t vlib_node_runtime_t * node
Definition: lcp_node.c:71
ip_types.h
ip_adjacency_t_
IP unicast adjacency.
Definition: adj.h:235
from
from
Definition: lcp_node.c:78
lcp_itf_pair_t_::lip_host_sw_if_index
u32 lip_host_sw_if_index
Definition: lcp_interface.h:51
LCP_ITF_HOST_TUN
@ LCP_ITF_HOST_TUN
Definition: lcp_interface.h:36
vlib_node_registration_t
struct _vlib_node_registration vlib_node_registration_t
l2_input.h
lcp_itf_pair_t_::lip_host_type
lip_host_type_t lip_host_type
Definition: lcp_interface.h:56
ip6_main
ip6_main_t ip6_main
Definition: ip6_forward.c:2785
ip4_packet.h
lip_punt_trace_t_::phy_sw_if_index
u32 phy_sw_if_index
Definition: lcp_node.c:49
lip_punt_node
vlib_node_registration_t lip_punt_node
(constructor) VLIB_REGISTER_NODE (lip_punt_node)
Definition: lcp_node.c:147
vlib_validate_buffer_enqueue_x1
#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
next_index
lip_punt_next_t next_index
Definition: lcp_node.c:74
lcp_arp_trace_t_::arp_opcode
u16 arp_opcode
Definition: lcp_node.c:587
foreach_lcp_arp
#define foreach_lcp_arp
Definition: lcp_node.c:572
format
description fragment has unexpected format
Definition: map.api:433
foreach_lcp_punt_l3
#define foreach_lcp_punt_l3
Definition: lcp_node.c:160
foreach_lcp_xc
#define foreach_lcp_xc
Definition: lcp_node.c:274
vlib_put_next_frame
vlib_put_next_frame(vm, node, next_index, 0)
ethernet_address_cast
static uword ethernet_address_cast(const u8 *a)
Definition: packet.h:67
u32
unsigned int u32
Definition: types.h:88
af
vl_api_address_family_t af
Definition: ip.api:619
lcp_punt_l3_trace_t_::phy_sw_if_index
u32 phy_sw_if_index
Definition: lcp_node.c:172
lcp_punt_l3_next_t
lcp_punt_l3_next_t
Definition: lcp_node.c:162
ip_adjacency_t_::ia_cfg_index
u32 ia_cfg_index
feature [arc] config index
Definition: adj.h:247
lcp_arp_next_t
lcp_arp_next_t
Definition: lcp_node.c:576
AF_IP6
@ AF_IP6
Definition: ip_types.h:24
ip6_main_t::lookup_main
ip_lookup_main_t lookup_main
Definition: ip6.h:112
lcp_xc_trace_t_::phy_sw_if_index
u32 phy_sw_if_index
Definition: lcp_node.c:289
lip_punt_next_t
lip_punt_next_t
Definition: lcp_node.c:39
ip4.h
ip_lookup_main_t
Definition: lookup.h:121
adj_index_t
u32 adj_index_t
An index for adjacencies.
Definition: adj_types.h:30
vlib_main_t
Definition: main.h:102
VNET_FEATURE_INIT
VNET_FEATURE_INIT(lcp_punt_l3_ip4, static)
lcp_xc_trace_t
struct lcp_xc_trace_t_ lcp_xc_trace_t
reply_copies
u32 reply_copies[VLIB_FRAME_SIZE]
Definition: lcp_node.c:612
vlib_node_t
Definition: node.h:247
lcp_xc_l3_inline
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:451
vlib_add_trace
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
format_lcp_xc_trace
static u8 * format_lcp_xc_trace(u8 *s, va_list *args)
Definition: lcp_node.c:295
VNET_FEATURES
#define VNET_FEATURES(...)
Definition: feature.h:470
u8
unsigned char u8
Definition: types.h:56
vlib_buffer_get_current
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:257
lookup.h
vm
vlib_main_t * vm
Pass punted packets from the PHY to the HOST.
Definition: lcp_node.c:71
arp_packet.h
lcp_itf_pair_find_by_phy
static index_t lcp_itf_pair_find_by_phy(u32 phy_sw_if_index)
Definition: lcp_interface.h:132
ethernet_buffer_get_header
static ethernet_header_t * ethernet_buffer_get_header(vlib_buffer_t *b)
Definition: ethernet.h:409
lcp_xc_next_t
lcp_xc_next_t
Definition: lcp_node.c:279
foreach_lip_punt
#define foreach_lip_punt
Definition: lcp_node.c:35
lcp_arp_trace_t
struct lcp_arp_trace_t_ lcp_arp_trace_t
lcp_arp_trace_t_
Definition: lcp_node.c:584
lcp_xc_trace_t_
Definition: lcp_node.c:287
lcp_adj_lkup
static_always_inline adj_index_t lcp_adj_lkup(const u8 *rewrite, u8 len, u32 sw_if_index)
Definition: lcp_adj.h:64
lcp_xc_l3_ip4_node
vlib_node_registration_t lcp_xc_l3_ip4_node
(constructor) VLIB_REGISTER_NODE (lcp_xc_l3_ip4_node)
Definition: lcp_node.c:528
vlib_validate_buffer_enqueue_x2
#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
format_lcp_arp_trace
static u8 * format_lcp_arp_trace(u8 *s, va_list *args)
Definition: lcp_node.c:592
vlib_node_runtime_t
Definition: node.h:454
lcp_xc_l3_next_t
lcp_xc_l3_next_t
Definition: lcp_node.c:439
lip_punt_trace_t
struct lip_punt_trace_t_ lip_punt_trace_t
INDEX_INVALID
#define INDEX_INVALID
Invalid index - used when no index is known blazoned capitals INVALID speak volumes where ~0 does not...
Definition: dpo.h:49
PREDICT_TRUE
#define PREDICT_TRUE(x)
Definition: clib.h:125
lip_punt_trace_t_::host_sw_if_index
u32 host_sw_if_index
Definition: lcp_node.c:50
LCP_XC_N_NEXT
@ LCP_XC_N_NEXT
Definition: lcp_node.c:284
sw_if_index
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
vlib_get_next_frame
#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
ip6.h
LCP_ITF_HOST_TAP
@ LCP_ITF_HOST_TAP
Definition: lcp_interface.h:35
VLIB_TX
@ VLIB_TX
Definition: defs.h:47
adj_get
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
lcp_arp_host_node
vlib_node_registration_t lcp_arp_host_node
(constructor) VLIB_REGISTER_NODE (lcp_arp_host_node)
Definition: lcp_node.c:898
type
vl_api_fib_path_type_t type
Definition: fib_types.api:123
ip_lookup_main_t::output_feature_arc_index
u8 output_feature_arc_index
Definition: lookup.h:145
lcp_interface.h
vlib_buffer_t::flags
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index,...
Definition: buffer.h:133
ip_address_family_t
enum ip_address_family_t_ ip_address_family_t
vlib_buffer_t
VLIB buffer representation.
Definition: buffer.h:111
VLIB_REGISTER_NODE
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
lcp_itf_pair_t_::lip_rewrite_len
u8 lip_rewrite_len
Definition: lcp_interface.h:59