LCOV - code coverage report
Current view: top level - plugins/linux-cp - lcp_node.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 212 313 67.7 %
Date: 2023-07-05 22:20:52 Functions: 59 62 95.2 %

          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             :  */

Generated by: LCOV version 1.14