LCOV - code coverage report
Current view: top level - vnet/ip6-nd - ip6_nd_mirror_proxy.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 95 145 65.5 %
Date: 2023-07-05 22:20:52 Functions: 19 20 95.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2021 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include <vlib/vlib.h>
      17             : 
      18             : #include <vnet/vnet.h>
      19             : #include <vnet/ethernet/ethernet.h>
      20             : #include <vnet/feature/feature.h>
      21             : #include <vnet/ip/ip6_packet.h>
      22             : #include <vnet/ip-neighbor/ip6_neighbor.h>
      23             : #include <vnet/ip-neighbor/ip_neighbor.h>
      24             : #include <vnet/ip-neighbor/ip_neighbor_dp.h>
      25             : #include <vnet/ip6-nd/ip6_nd_inline.h>
      26             : #include <vnet/fib/ip6_fib.h>
      27             : #include <vnet/ip/ip6_ll_table.h>
      28             : 
      29             : #include <vppinfra/error.h>
      30             : 
      31             : int
      32           2 : ip6_nd_proxy_enable_disable (u32 sw_if_index, u8 enable)
      33             : {
      34             : 
      35           2 :   if (enable)
      36             :     {
      37           1 :       vnet_feature_enable_disable ("ip6-unicast", "ip6-unicast-nd-proxy",
      38             :                                    sw_if_index, 1, NULL, 0);
      39           1 :       vnet_feature_enable_disable ("ip6-multicast", "ip6-multicast-nd-proxy",
      40             :                                    sw_if_index, 1, NULL, 0);
      41             :     }
      42             :   else
      43             :     {
      44           1 :       vnet_feature_enable_disable ("ip6-unicast", "ip6-unicast-nd-proxy",
      45             :                                    sw_if_index, 0, NULL, 0);
      46           1 :       vnet_feature_enable_disable ("ip6-multicast", "ip6-multicast-nd-proxy",
      47             :                                    sw_if_index, 0, NULL, 0);
      48             :     }
      49           2 :   return 0;
      50             : }
      51             : 
      52             : static clib_error_t *
      53           0 : set_int_ip6_nd_proxy_command_fn (vlib_main_t *vm, unformat_input_t *input,
      54             :                                  vlib_cli_command_t *cmd)
      55             : {
      56           0 :   vnet_main_t *vnm = vnet_get_main ();
      57             :   u32 sw_if_index;
      58           0 :   int enable = 0;
      59             : 
      60           0 :   sw_if_index = ~0;
      61             : 
      62           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
      63             :     {
      64           0 :       if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
      65             :                     &sw_if_index))
      66             :         ;
      67           0 :       else if (unformat (input, "enable"))
      68           0 :         enable = 1;
      69           0 :       else if (unformat (input, "disable"))
      70           0 :         enable = 0;
      71             :       else
      72           0 :         break;
      73             :     }
      74             : 
      75           0 :   if (~0 == sw_if_index)
      76           0 :     return clib_error_return (0, "unknown input '%U'", format_unformat_error,
      77             :                               input);
      78             : 
      79           0 :   ip6_nd_proxy_enable_disable (sw_if_index, enable);
      80             : 
      81           0 :   return 0;
      82             : }
      83             : 
      84      272887 : VLIB_CLI_COMMAND (set_int_ip6_nd_proxy_enable_command, static) = {
      85             :   .path = "set interface ip6-nd proxy",
      86             :   .short_help = "set interface ip6-nd proxy <intfc> [enable|disable]",
      87             :   .function = set_int_ip6_nd_proxy_command_fn,
      88             : };
      89             : 
      90             : typedef struct
      91             : {
      92             :   u8 is_multicast;
      93             :   u32 sw_if_index;
      94             : } vnet_ip6_nd_proxy_trace_t;
      95             : 
      96             : static u8 *
      97           3 : format_ip6_nd_proxy_trace (u8 *s, va_list *args)
      98             : {
      99           3 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
     100           3 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
     101           3 :   vnet_main_t *vnm = vnet_get_main ();
     102           3 :   vnet_ip6_nd_proxy_trace_t *t = va_arg (*args, vnet_ip6_nd_proxy_trace_t *);
     103           3 :   u32 indent = format_get_indent (s);
     104             : 
     105           3 :   if (t->is_multicast)
     106           1 :     s = format (s, "%U %U multicast ", format_white_space, indent,
     107             :                 format_vnet_sw_if_index_name, vnm, t->sw_if_index);
     108             :   else
     109           2 :     s = format (s, "%U %U unicast ", format_white_space, indent,
     110             :                 format_vnet_sw_if_index_name, vnm, t->sw_if_index);
     111             : 
     112           3 :   return s;
     113             : }
     114             : 
     115             : static_always_inline void
     116           3 : ip6_nd_proxy_unicast (vlib_main_t *vm, vlib_node_runtime_t *node,
     117             :                       vlib_buffer_t *b0, ip6_header_t *ip6, u32 *next0)
     118             : {
     119           3 :   if (PREDICT_FALSE (ip6->protocol == IP_PROTOCOL_ICMP6))
     120             :     {
     121             :       icmp46_header_t *icmp0;
     122             :       icmp6_type_t type0;
     123             : 
     124           3 :       icmp0 = ip6_next_header (ip6);
     125           3 :       type0 = icmp0->type;
     126           3 :       if (type0 == ICMP6_neighbor_solicitation ||
     127             :           type0 == ICMP6_neighbor_advertisement)
     128             :         {
     129             :           icmp6_neighbor_solicitation_or_advertisement_header_t *icmp6_nsa;
     130             :           icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
     131             :             *icmp6_nd_ell_addr;
     132             :           u32 sw_if_index0;
     133             : 
     134           2 :           icmp6_nsa = (void *) icmp0;
     135           2 :           icmp6_nd_ell_addr = (void *) (icmp6_nsa + 1);
     136             : 
     137           2 :           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     138             : 
     139             :           /* unicast neighbor solicitation */
     140             :           fib_node_index_t fei;
     141             :           u32 fib_index;
     142             : 
     143           2 :           fib_index = ip6_fib_table_get_index_for_sw_if_index (sw_if_index0);
     144             : 
     145           2 :           if (~0 == fib_index)
     146             :             {
     147           0 :               *next0 = ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP;
     148             :             }
     149             :           else
     150             :             {
     151           2 :               if (ip6_address_is_link_local_unicast (&ip6->dst_address))
     152             :                 {
     153           0 :                   fei = ip6_fib_table_lookup_exact_match (
     154           0 :                     ip6_ll_fib_get (sw_if_index0), &ip6->dst_address, 128);
     155             :                 }
     156             :               else
     157             :                 {
     158           2 :                   fei = ip6_fib_table_lookup_exact_match (
     159           2 :                     fib_index, &ip6->dst_address, 128);
     160             :                 }
     161             : 
     162           2 :               if (FIB_NODE_INDEX_INVALID != fei)
     163             :                 {
     164           1 :                   *next0 = ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY;
     165           1 :                   icmp6_send_neighbor_advertisement (
     166             :                     vm, b0, ip6, icmp6_nsa, icmp6_nd_ell_addr, sw_if_index0);
     167             :                 }
     168             :             }
     169           2 :           if (b0->flags & VLIB_BUFFER_IS_TRACED)
     170             :             {
     171             :               vnet_ip6_nd_proxy_trace_t *t;
     172           2 :               t = vlib_add_trace (vm, node, b0, sizeof (t[0]));
     173           2 :               t->sw_if_index = sw_if_index0;
     174           2 :               t->is_multicast = 0;
     175             :             }
     176             :         }
     177             :     }
     178           3 : }
     179             : 
     180             : static_always_inline void
     181           1 : ip6_nd_proxy_multicast (vlib_main_t *vm, vlib_node_runtime_t *node,
     182             :                         vlib_buffer_t *b0, ip6_header_t *ip6, u32 *next0)
     183             : {
     184           1 :   if (PREDICT_FALSE (ip6->protocol == IP_PROTOCOL_ICMP6))
     185             :     {
     186             :       icmp46_header_t *icmp0;
     187             :       icmp6_type_t type0;
     188             : 
     189           1 :       icmp0 = ip6_next_header (ip6);
     190           1 :       type0 = icmp0->type;
     191           1 :       if (type0 == ICMP6_neighbor_solicitation ||
     192             :           type0 == ICMP6_neighbor_advertisement)
     193             :         {
     194             :           icmp6_neighbor_solicitation_or_advertisement_header_t *icmp6_nsa;
     195             :           icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
     196             :             *icmp6_nd_ell_addr;
     197             :           u32 sw_if_index0;
     198             : 
     199           1 :           icmp6_nsa = (void *) icmp0;
     200           1 :           icmp6_nd_ell_addr = (void *) (icmp6_nsa + 1);
     201             : 
     202           1 :           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     203           1 :           if (type0 == ICMP6_neighbor_solicitation)
     204             :             {
     205           1 :               if (
     206           1 :                 (icmp6_nd_ell_addr->header.type ==
     207           1 :                  ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address) &&
     208           2 :                 (!ip6_address_is_unspecified (&ip6->src_address)) &&
     209           1 :                 (!ip6_address_is_link_local_unicast (&ip6->src_address)))
     210             :                 {
     211           1 :                   ip_neighbor_learn_t learn = { .sw_if_index = sw_if_index0,
     212             :                                                 .ip = {
     213             :                                                   .version = AF_IP6,
     214             :                                                   .ip.ip6 = ip6->src_address,
     215             :                                                 } };
     216           1 :                   clib_memcpy (&learn.mac, icmp6_nd_ell_addr->ethernet_address,
     217             :                                sizeof (learn.mac));
     218           1 :                   ip_neighbor_learn_dp (&learn);
     219             : 
     220           1 :                   *next0 = ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY;
     221           1 :                   icmp6_send_neighbor_advertisement (
     222             :                     vm, b0, ip6, icmp6_nsa, icmp6_nd_ell_addr, sw_if_index0);
     223             :                 }
     224             :             }
     225             :           else // type0 = ICMP6_neighbor_advertisement
     226             :             {
     227             :               icmp6_neighbor_solicitation_or_advertisement_header_t
     228           0 :                 *icmp6_nsa = (void *) icmp0;
     229             :               icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
     230           0 :                 *icmp6_nd_ell_addr = (void *) (icmp6_nsa + 1);
     231           0 :               if (
     232           0 :                 (icmp6_nd_ell_addr->header.type ==
     233           0 :                  ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address) &&
     234           0 :                 (!ip6_address_is_unspecified (&ip6->src_address)) &&
     235           0 :                 (!ip6_address_is_link_local_unicast (&ip6->src_address)))
     236             :                 {
     237           0 :                   ip_neighbor_learn_t learn = { .sw_if_index = sw_if_index0,
     238             :                                                 .ip = {
     239             :                                                   .version = AF_IP6,
     240             :                                                   .ip.ip6 =
     241             :                                                     icmp6_nsa->target_address,
     242             :                                                 } };
     243           0 :                   clib_memcpy (&learn.mac, icmp6_nd_ell_addr->ethernet_address,
     244             :                                sizeof (learn.mac));
     245           0 :                   ip_neighbor_learn_dp (&learn);
     246             : 
     247           0 :                   *next0 = ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP;
     248             :                 }
     249             :             }
     250             : 
     251           1 :           if (b0->flags & VLIB_BUFFER_IS_TRACED)
     252             :             {
     253             :               vnet_ip6_nd_proxy_trace_t *t;
     254           1 :               t = vlib_add_trace (vm, node, b0, sizeof (t[0]));
     255           1 :               t->sw_if_index = sw_if_index0;
     256           1 :               t->is_multicast = 1;
     257             :             }
     258             :         }
     259             :     }
     260           1 : }
     261             : 
     262             : static_always_inline uword
     263           4 : ip6_nd_proxy_node_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
     264             :                           vlib_frame_t *frame, u8 is_multicast)
     265             : {
     266             :   u32 n_left_from, *from, *to_next;
     267             :   u32 next_index, n_left_to_next;
     268           4 :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
     269             : 
     270           4 :   from = vlib_frame_vector_args (frame);
     271           4 :   n_left_from = frame->n_vectors;
     272           4 :   next_index = node->cached_next_index;
     273             : 
     274           4 :   vlib_get_buffers (vm, from, bufs, n_left_from);
     275             : 
     276           8 :   while (n_left_from > 0)
     277             :     {
     278           4 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     279             : 
     280           4 :       while (n_left_from > 4 && n_left_to_next > 2)
     281             :         {
     282             :           ip6_header_t *ip6_0, *ip6_1;
     283             :           u32 next0, next1;
     284             :           u32 bi0, bi1;
     285             : 
     286             :           /* Prefetch next iteration. */
     287             :           {
     288           0 :             vlib_prefetch_buffer_header (b[2], LOAD);
     289           0 :             vlib_prefetch_buffer_header (b[3], LOAD);
     290             : 
     291           0 :             vlib_prefetch_buffer_data (b[2], LOAD);
     292           0 :             vlib_prefetch_buffer_data (b[3], LOAD);
     293             :           }
     294             : 
     295             :           /*
     296             :            * speculatively enqueue b0 and b1 to the current next frame
     297             :            */
     298           0 :           to_next[0] = bi0 = from[0];
     299           0 :           to_next[1] = bi1 = from[1];
     300           0 :           to_next += 2;
     301           0 :           n_left_to_next -= 2;
     302             : 
     303           0 :           vnet_feature_next (&next0, b[0]);
     304           0 :           vnet_feature_next (&next1, b[1]);
     305             : 
     306           0 :           ip6_0 = vlib_buffer_get_current (b[0]);
     307           0 :           ip6_1 = vlib_buffer_get_current (b[1]);
     308             : 
     309           0 :           if (is_multicast)
     310             :             {
     311           0 :               ip6_nd_proxy_multicast (vm, node, b[0], ip6_0, &next0);
     312           0 :               ip6_nd_proxy_multicast (vm, node, b[1], ip6_1, &next1);
     313             :             }
     314             :           else
     315             :             {
     316           0 :               ip6_nd_proxy_unicast (vm, node, b[0], ip6_0, &next0);
     317           0 :               ip6_nd_proxy_unicast (vm, node, b[1], ip6_1, &next1);
     318             :             }
     319           0 :           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
     320             :                                            n_left_to_next, bi0, bi1, next0,
     321             :                                            next1);
     322             : 
     323           0 :           b += 2;
     324           0 :           from += 2;
     325           0 :           n_left_from -= 2;
     326             :         }
     327             : 
     328           8 :       while (n_left_from > 0 && n_left_to_next > 0)
     329             :         {
     330             :           ip6_header_t *ip6_0;
     331             :           u32 next0, bi0;
     332             : 
     333             :           /* speculatively enqueue b0 to the current next frame */
     334           4 :           to_next[0] = bi0 = from[0];
     335           4 :           to_next += 1;
     336           4 :           n_left_to_next -= 1;
     337             : 
     338           4 :           vnet_feature_next (&next0, b[0]);
     339           4 :           ip6_0 = vlib_buffer_get_current (b[0]);
     340             : 
     341           4 :           if (is_multicast)
     342           1 :             ip6_nd_proxy_multicast (vm, node, b[0], ip6_0, &next0);
     343             :           else
     344           3 :             ip6_nd_proxy_unicast (vm, node, b[0], ip6_0, &next0);
     345             : 
     346           4 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     347             :                                            n_left_to_next, bi0, next0);
     348           4 :           b += 1;
     349           4 :           from += 1;
     350           4 :           n_left_from -= 1;
     351             :         }
     352           4 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     353             :     }
     354             : 
     355           4 :   return frame->n_vectors;
     356             : }
     357             : 
     358         562 : VLIB_NODE_FN (ip6_unicast_nd_proxy_node)
     359             : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
     360             : {
     361           3 :   return ip6_nd_proxy_node_inline (vm, node, frame, 0 /* is_multicast */);
     362             : }
     363             : 
     364      178120 : VLIB_REGISTER_NODE (ip6_unicast_nd_proxy_node) = {
     365             :   .vector_size = sizeof (u32),
     366             :   .format_trace = format_ip6_nd_proxy_trace,
     367             :   .type = VLIB_NODE_TYPE_INTERNAL,
     368             :   .n_errors = 0,
     369             :   .n_next_nodes = ICMP6_NEIGHBOR_SOLICITATION_N_NEXT,
     370             :   .next_nodes = {
     371             :     [ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP] = "ip6-drop",
     372             :     [ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY] = "interface-output",
     373             :   },
     374             :   .name = "ip6-unicast-nd-proxy",
     375             : };
     376             : 
     377         560 : VLIB_NODE_FN (ip6_multicast_nd_proxy_node)
     378             : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
     379             : {
     380           1 :   return ip6_nd_proxy_node_inline (vm, node, frame, 1 /* is_multicast */);
     381             : }
     382             : 
     383      178120 : VLIB_REGISTER_NODE (ip6_multicast_nd_proxy_node) = {
     384             :   .vector_size = sizeof (u32),
     385             :   .format_trace = format_ip6_nd_proxy_trace,
     386             :   .type = VLIB_NODE_TYPE_INTERNAL,
     387             :   .n_errors = 0,
     388             :   .n_next_nodes = ICMP6_NEIGHBOR_SOLICITATION_N_NEXT,
     389             :   .next_nodes = {
     390             :     [ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP] = "ip6-drop",
     391             :     [ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY] = "interface-output",
     392             :   },
     393             :   .name = "ip6-multicast-nd-proxy",
     394             : };
     395             : 
     396       70583 : VNET_FEATURE_INIT (ip6_unicast_nd_proxy_node, static) = {
     397             :   .arc_name = "ip6-unicast",
     398             :   .node_name = "ip6-unicast-nd-proxy",
     399             :   .runs_before = VNET_FEATURES ("ip6-lookup"),
     400             : };
     401             : 
     402       70583 : VNET_FEATURE_INIT (ip6_multicast_nd_proxy_node, static) = {
     403             :   .arc_name = "ip6-multicast",
     404             :   .node_name = "ip6-multicast-nd-proxy",
     405             :   .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
     406             : };
     407             : 
     408             : /*
     409             :  * fd.io coding-style-patch-verification: ON
     410             :  *
     411             :  * Local Variables:
     412             :  * eval: (c-set-style "gnu")
     413             :  * End:
     414             :  */

Generated by: LCOV version 1.14