LCOV - code coverage report
Current view: top level - plugins/nat/nat44-ed - nat44_ed_classify.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 123 129 95.3 %
Date: 2023-10-26 01:39:38 Functions: 17 23 73.9 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018 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             :  * @file
      17             :  * @brief Classify for one armed NAT44 (in+out interface)
      18             :  */
      19             : 
      20             : #include <vlib/vlib.h>
      21             : #include <vnet/vnet.h>
      22             : #include <vnet/fib/ip4_fib.h>
      23             : 
      24             : #include <nat/nat44-ed/nat44_ed.h>
      25             : #include <nat/nat44-ed/nat44_ed_inlines.h>
      26             : 
      27             : #define foreach_nat44_classify_error                      \
      28             : _(NEXT_IN2OUT, "next in2out")                             \
      29             : _(NEXT_OUT2IN, "next out2in")                             \
      30             : _(FRAG_CACHED, "fragment cached")
      31             : 
      32             : typedef enum
      33             : {
      34             : #define _(sym,str) NAT44_CLASSIFY_ERROR_##sym,
      35             :   foreach_nat44_classify_error
      36             : #undef _
      37             :     NAT44_CLASSIFY_N_ERROR,
      38             : } nat44_classify_error_t;
      39             : 
      40             : typedef enum
      41             : {
      42             :   NAT44_CLASSIFY_NEXT_IN2OUT,
      43             :   NAT44_CLASSIFY_NEXT_OUT2IN,
      44             :   NAT44_CLASSIFY_NEXT_DROP,
      45             :   NAT44_CLASSIFY_N_NEXT,
      46             : } nat44_classify_next_t;
      47             : 
      48             : typedef struct
      49             : {
      50             :   u8 next_in2out;
      51             :   u8 cached;
      52             : } nat44_classify_trace_t;
      53             : 
      54             : static u8 *
      55          29 : format_nat44_classify_trace (u8 * s, va_list * args)
      56             : {
      57          29 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      58          29 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      59          29 :   nat44_classify_trace_t *t = va_arg (*args, nat44_classify_trace_t *);
      60             :   char *next;
      61             : 
      62          29 :   if (t->cached)
      63           0 :     s = format (s, "nat44-classify: fragment cached");
      64             :   else
      65             :     {
      66          29 :       next = t->next_in2out ? "nat44-ed-in2out" : "nat44-ed-out2in";
      67          29 :       s = format (s, "nat44-classify: next %s", next);
      68             :     }
      69             : 
      70          29 :   return s;
      71             : }
      72             : 
      73             : static inline uword
      74          49 : nat44_handoff_classify_node_fn_inline (vlib_main_t * vm,
      75             :                                        vlib_node_runtime_t * node,
      76             :                                        vlib_frame_t * frame)
      77             : {
      78             :   u32 n_left_from, *from, *to_next;
      79             :   nat44_classify_next_t next_index;
      80          49 :   snat_main_t *sm = &snat_main;
      81             :   snat_static_mapping_t *m;
      82          49 :   u32 next_in2out = 0, next_out2in = 0;
      83             : 
      84          49 :   from = vlib_frame_vector_args (frame);
      85          49 :   n_left_from = frame->n_vectors;
      86          49 :   next_index = node->cached_next_index;
      87             : 
      88          98 :   while (n_left_from > 0)
      89             :     {
      90             :       u32 n_left_to_next;
      91             : 
      92          49 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
      93             : 
      94         152 :       while (n_left_from > 0 && n_left_to_next > 0)
      95             :         {
      96             :           u32 bi0;
      97             :           vlib_buffer_t *b0;
      98         103 :           u32 next0 = NAT_NEXT_IN2OUT_CLASSIFY;
      99             :           ip4_header_t *ip0;
     100             :           snat_address_t *ap;
     101             : 
     102             :           /* speculatively enqueue b0 to the current next frame */
     103         103 :           bi0 = from[0];
     104         103 :           to_next[0] = bi0;
     105         103 :           from += 1;
     106         103 :           to_next += 1;
     107         103 :           n_left_from -= 1;
     108         103 :           n_left_to_next -= 1;
     109             : 
     110         103 :           b0 = vlib_get_buffer (vm, bi0);
     111         103 :           ip0 = vlib_buffer_get_current (b0);
     112             : 
     113         156 :           vec_foreach (ap, sm->addresses)
     114             :             {
     115          92 :               if (ip0->dst_address.as_u32 == ap->addr.as_u32)
     116             :                 {
     117          39 :                   next0 = NAT_NEXT_OUT2IN_CLASSIFY;
     118          39 :                   goto enqueue0;
     119             :                 }
     120             :             }
     121             : 
     122          64 :           if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
     123             :             {
     124             :               /* try to classify the fragment based on IP header alone */
     125          64 :               m = nat44_ed_sm_o2i_lookup (sm, ip0->dst_address, 0, 0, 0);
     126          64 :               if (m)
     127             :                 {
     128           9 :                   if (m->local_addr.as_u32 != m->external_addr.as_u32)
     129           0 :                     next0 = NAT_NEXT_OUT2IN_CLASSIFY;
     130           9 :                   goto enqueue0;
     131             :                 }
     132          55 :               m = nat44_ed_sm_o2i_lookup (
     133          55 :                 sm, ip0->dst_address, vnet_buffer (b0)->ip.reass.l4_dst_port,
     134          55 :                 0, ip0->protocol);
     135          55 :               if (m)
     136             :                 {
     137           3 :                   if (m->local_addr.as_u32 != m->external_addr.as_u32)
     138           3 :                     next0 = NAT_NEXT_OUT2IN_CLASSIFY;
     139             :                 }
     140             :             }
     141             : 
     142          52 :         enqueue0:
     143         103 :           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
     144             :                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
     145             :             {
     146             :               nat44_classify_trace_t *t =
     147         103 :                 vlib_add_trace (vm, node, b0, sizeof (*t));
     148         103 :               t->cached = 0;
     149         103 :               t->next_in2out = next0 == NAT_NEXT_IN2OUT_CLASSIFY ? 1 : 0;
     150             :             }
     151             : 
     152         103 :           next_in2out += next0 == NAT_NEXT_IN2OUT_CLASSIFY;
     153         103 :           next_out2in += next0 == NAT_NEXT_OUT2IN_CLASSIFY;
     154             : 
     155             :           /* verify speculative enqueue, maybe switch current next frame */
     156         103 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     157             :                                            to_next, n_left_to_next,
     158             :                                            bi0, next0);
     159             :         }
     160             : 
     161          49 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     162             :     }
     163             : 
     164          49 :   vlib_node_increment_counter (vm, node->node_index,
     165             :                                NAT44_CLASSIFY_ERROR_NEXT_IN2OUT, next_in2out);
     166          49 :   vlib_node_increment_counter (vm, node->node_index,
     167             :                                NAT44_CLASSIFY_ERROR_NEXT_OUT2IN, next_out2in);
     168          49 :   return frame->n_vectors;
     169             : }
     170             : 
     171             : static inline uword
     172          21 : nat44_ed_classify_node_fn_inline (vlib_main_t * vm,
     173             :                                   vlib_node_runtime_t * node,
     174             :                                   vlib_frame_t * frame)
     175             : {
     176             :   u32 n_left_from, *from, *to_next;
     177             :   nat44_classify_next_t next_index;
     178          21 :   snat_main_t *sm = &snat_main;
     179             :   snat_static_mapping_t *m;
     180          21 :   u32 next_in2out = 0, next_out2in = 0;
     181             : 
     182          21 :   from = vlib_frame_vector_args (frame);
     183          21 :   n_left_from = frame->n_vectors;
     184          21 :   next_index = node->cached_next_index;
     185             : 
     186          42 :   while (n_left_from > 0)
     187             :     {
     188             :       u32 n_left_to_next;
     189             : 
     190          21 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     191             : 
     192          42 :       while (n_left_from > 0 && n_left_to_next > 0)
     193             :         {
     194             :           u32 bi0;
     195             :           vlib_buffer_t *b0;
     196          21 :           u32 next0 = NAT_NEXT_IN2OUT_ED_FAST_PATH;
     197             :           u32 sw_if_index0, rx_fib_index0;
     198             :           ip4_header_t *ip0;
     199             :           snat_address_t *ap;
     200             :           clib_bihash_kv_16_8_t ed_kv0, ed_value0;
     201             : 
     202             :           /* speculatively enqueue b0 to the current next frame */
     203          21 :           bi0 = from[0];
     204          21 :           to_next[0] = bi0;
     205          21 :           from += 1;
     206          21 :           to_next += 1;
     207          21 :           n_left_from -= 1;
     208          21 :           n_left_to_next -= 1;
     209             : 
     210          21 :           b0 = vlib_get_buffer (vm, bi0);
     211          21 :           ip0 = vlib_buffer_get_current (b0);
     212             : 
     213             :           u32 arc_next;
     214          21 :           vnet_feature_next (&arc_next, b0);
     215          21 :           vnet_buffer2 (b0)->nat.arc_next = arc_next;
     216             : 
     217          21 :           if (ip0->protocol != IP_PROTOCOL_ICMP)
     218             :             {
     219             :               /* process leading fragment/whole packet (with L4 header) */
     220          21 :               sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     221             :               rx_fib_index0 =
     222          21 :                 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
     223             :                                                      sw_if_index0);
     224          21 :               init_ed_k (&ed_kv0, ip0->src_address.as_u32,
     225          21 :                          vnet_buffer (b0)->ip.reass.l4_src_port,
     226             :                          ip0->dst_address.as_u32,
     227          21 :                          vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
     228          21 :                          ip0->protocol);
     229             :               /* process whole packet */
     230          21 :               if (!clib_bihash_search_16_8 (&sm->flow_hash, &ed_kv0,
     231             :                                             &ed_value0))
     232             :                 {
     233          11 :                   ASSERT (vm->thread_index ==
     234             :                           ed_value_get_thread_index (&ed_value0));
     235          11 :                   snat_main_per_thread_data_t *tsm =
     236          11 :                     &sm->per_thread_data[vm->thread_index];
     237          11 :                   snat_session_t *s = pool_elt_at_index (
     238             :                     tsm->sessions, ed_value_get_session_index (&ed_value0));
     239             :                   clib_bihash_kv_16_8_t i2o_kv;
     240          11 :                   nat_6t_flow_to_ed_k (&i2o_kv, &s->i2o);
     241          22 :                   vnet_buffer2 (b0)->nat.cached_session_index =
     242          11 :                     ed_value_get_session_index (&ed_value0);
     243          11 :                   if (i2o_kv.key[0] == ed_kv0.key[0] &&
     244          11 :                       i2o_kv.key[1] == ed_kv0.key[1])
     245             :                     {
     246          11 :                       next0 = NAT_NEXT_IN2OUT_ED_FAST_PATH;
     247             :                     }
     248             :                   else
     249             :                     {
     250           0 :                       next0 = NAT_NEXT_OUT2IN_ED_FAST_PATH;
     251             :                     }
     252             : 
     253          11 :                   goto enqueue0;
     254             :                 }
     255             :               /* session doesn't exist so continue in code */
     256             :             }
     257             : 
     258          13 :           vec_foreach (ap, sm->addresses)
     259             :             {
     260           5 :               if (ip0->dst_address.as_u32 == ap->addr.as_u32)
     261             :                 {
     262           2 :                   next0 = NAT_NEXT_OUT2IN_ED_FAST_PATH;
     263           2 :                   goto enqueue0;
     264             :                 }
     265             :             }
     266             : 
     267           8 :           if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
     268             :             {
     269             :               /* try to classify the fragment based on IP header alone */
     270           7 :               m = nat44_ed_sm_o2i_lookup (sm, ip0->dst_address, 0, 0, 0);
     271           7 :               if (m)
     272             :                 {
     273           0 :                   if (m->local_addr.as_u32 != m->external_addr.as_u32)
     274           0 :                     next0 = NAT_NEXT_OUT2IN_ED_FAST_PATH;
     275           0 :                   goto enqueue0;
     276             :                 }
     277           7 :               m = nat44_ed_sm_o2i_lookup (
     278           7 :                 sm, ip0->dst_address, vnet_buffer (b0)->ip.reass.l4_dst_port,
     279           7 :                 0, ip0->protocol);
     280           7 :               if (m)
     281             :                 {
     282           1 :                   if (m->local_addr.as_u32 != m->external_addr.as_u32)
     283           1 :                     next0 = NAT_NEXT_OUT2IN_ED_FAST_PATH;
     284             :                 }
     285             :             }
     286             : 
     287           7 :         enqueue0:
     288          21 :           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
     289             :                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
     290             :             {
     291             :               nat44_classify_trace_t *t =
     292          21 :                 vlib_add_trace (vm, node, b0, sizeof (*t));
     293          21 :               t->cached = 0;
     294          21 :               t->next_in2out = next0 == NAT_NEXT_IN2OUT_ED_FAST_PATH ? 1 : 0;
     295             :             }
     296             : 
     297          21 :           next_in2out += next0 == NAT_NEXT_IN2OUT_ED_FAST_PATH;
     298          21 :           next_out2in += next0 == NAT_NEXT_OUT2IN_ED_FAST_PATH;
     299             : 
     300             :           /* verify speculative enqueue, maybe switch current next frame */
     301          21 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     302             :                                            to_next, n_left_to_next,
     303             :                                            bi0, next0);
     304             :         }
     305             : 
     306          21 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     307             :     }
     308             : 
     309          21 :   vlib_node_increment_counter (vm, node->node_index,
     310             :                                NAT44_CLASSIFY_ERROR_NEXT_IN2OUT, next_in2out);
     311          21 :   vlib_node_increment_counter (vm, node->node_index,
     312             :                                NAT44_CLASSIFY_ERROR_NEXT_OUT2IN, next_out2in);
     313          21 :   return frame->n_vectors;
     314             : }
     315             : 
     316        2321 : VLIB_NODE_FN (nat44_ed_classify_node) (vlib_main_t * vm,
     317             :                                        vlib_node_runtime_t * node,
     318             :                                        vlib_frame_t * frame)
     319             : {
     320          21 :   return nat44_ed_classify_node_fn_inline (vm, node, frame);
     321             : }
     322             : 
     323       58202 : VLIB_REGISTER_NODE (nat44_ed_classify_node) = {
     324             :   .name = "nat44-ed-classify",
     325             :   .vector_size = sizeof (u32),
     326             :   .sibling_of = "nat-default",
     327             :   .format_trace = format_nat44_classify_trace,
     328             :   .type = VLIB_NODE_TYPE_INTERNAL,
     329             : };
     330             : 
     331        2349 : VLIB_NODE_FN (nat44_handoff_classify_node) (vlib_main_t * vm,
     332             :                                             vlib_node_runtime_t * node,
     333             :                                             vlib_frame_t * frame)
     334             : {
     335          49 :   return nat44_handoff_classify_node_fn_inline (vm, node, frame);
     336             : }
     337             : 
     338       58202 : VLIB_REGISTER_NODE (nat44_handoff_classify_node) = {
     339             :   .name = "nat44-handoff-classify",
     340             :   .vector_size = sizeof (u32),
     341             :   .sibling_of = "nat-default",
     342             :   .format_trace = format_nat44_classify_trace,
     343             :   .type = VLIB_NODE_TYPE_INTERNAL,
     344             : };
     345             : 
     346             : /*
     347             :  * fd.io coding-style-patch-verification: ON
     348             :  *
     349             :  * Local Variables:
     350             :  * eval: (c-set-style "gnu")
     351             :  * End:
     352             :  */

Generated by: LCOV version 1.14