LCOV - code coverage report
Current view: top level - vnet/ip - ip_punt_drop.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 146 148 98.6 %
Date: 2023-10-26 01:39:38 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 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             : #ifndef __IP_PUNT_DROP_H__
      17             : #define __IP_PUNT_DROP_H__
      18             : 
      19             : #include <vnet/ip/ip.h>
      20             : #include <vnet/policer/policer.h>
      21             : #include <vnet/policer/police_inlines.h>
      22             : 
      23             : /**
      24             :  * IP4 punt policer configuration
      25             :  *   we police the punt rate to prevent overloading the host
      26             :  */
      27             : typedef struct ip_punt_policer_t_
      28             : {
      29             :   u32 policer_index;
      30             :   u32 fq_index;
      31             : } ip_punt_policer_t;
      32             : 
      33             : typedef enum ip_punt_policer_next_t_
      34             : {
      35             :   IP_PUNT_POLICER_NEXT_DROP,
      36             :   IP_PUNT_POLICER_NEXT_HANDOFF,
      37             :   IP_PUNT_POLICER_N_NEXT,
      38             : } ip_punt_policer_next_t;
      39             : 
      40             : typedef struct ip_punt_policer_trace_t_
      41             : {
      42             :   u32 policer_index;
      43             :   u32 next;
      44             : } ip_punt_policer_trace_t;
      45             : 
      46             : #define foreach_ip_punt_policer_error          \
      47             : _(DROP, "ip punt policer drop")
      48             : 
      49             : typedef enum
      50             : {
      51             : #define _(sym,str) IP_PUNT_POLICER_ERROR_##sym,
      52             :   foreach_ip_punt_policer_error
      53             : #undef _
      54             :     IP4_PUNT_POLICER_N_ERROR,
      55             : } ip_punt_policer_error_t;
      56             : 
      57             : extern u8 *format_ip_punt_policer_trace (u8 * s, va_list * args);
      58             : extern vlib_node_registration_t ip4_punt_policer_node;
      59             : extern ip_punt_policer_t ip4_punt_policer_cfg;
      60             : extern vlib_node_registration_t ip6_punt_policer_node;
      61             : extern ip_punt_policer_t ip6_punt_policer_cfg;
      62             : 
      63             : /**
      64             :  * IP punt policing node function
      65             :  */
      66             : always_inline uword
      67          33 : ip_punt_policer (vlib_main_t * vm,
      68             :                  vlib_node_runtime_t * node,
      69             :                  vlib_frame_t * frame, u8 arc_index, u32 policer_index)
      70             : {
      71             :   u32 *from, *to_next, n_left_from, n_left_to_next, next_index;
      72             :   u64 time_in_policer_periods;
      73          33 :   vnet_feature_main_t *fm = &feature_main;
      74          33 :   vnet_feature_config_main_t *cm = &fm->feature_config_mains[arc_index];
      75             : 
      76          33 :   time_in_policer_periods =
      77          33 :     clib_cpu_time_now () >> POLICER_TICKS_PER_PERIOD_SHIFT;
      78             : 
      79          33 :   from = vlib_frame_vector_args (frame);
      80          33 :   n_left_from = frame->n_vectors;
      81          33 :   next_index = node->cached_next_index;
      82             : 
      83          66 :   while (n_left_from > 0)
      84             :     {
      85          33 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
      86             : 
      87        2133 :       while (n_left_from >= 4 && n_left_to_next >= 2)
      88             :         {
      89             :           vlib_buffer_t *b0, *b1;
      90             :           u32 next0, next1;
      91             :           u8 act0, act1;
      92             :           u32 bi0, bi1;
      93             : 
      94        2100 :           next0 = next1 = 0;
      95        2100 :           bi0 = to_next[0] = from[0];
      96        2100 :           bi1 = to_next[1] = from[1];
      97             : 
      98        2100 :           from += 2;
      99        2100 :           n_left_from -= 2;
     100        2100 :           to_next += 2;
     101        2100 :           n_left_to_next -= 2;
     102             : 
     103        2100 :           b0 = vlib_get_buffer (vm, bi0);
     104        2100 :           b1 = vlib_get_buffer (vm, bi1);
     105             : 
     106        2100 :           act0 = vnet_policer_police (vm, b0, policer_index,
     107             :                                       time_in_policer_periods, POLICE_CONFORM,
     108             :                                       true);
     109        2100 :           act1 = vnet_policer_police (vm, b1, policer_index,
     110             :                                       time_in_policer_periods, POLICE_CONFORM,
     111             :                                       true);
     112             : 
     113        2100 :           if (PREDICT_FALSE (act0 == QOS_ACTION_HANDOFF))
     114             :             {
     115         192 :               next0 = next1 = IP_PUNT_POLICER_NEXT_HANDOFF;
     116             :             }
     117             :           else
     118             :             {
     119             : 
     120        1908 :               vnet_get_config_data (&cm->config_main,
     121             :                                     &b0->current_config_index, &next0, 0);
     122        1908 :               vnet_get_config_data (&cm->config_main,
     123             :                                     &b1->current_config_index, &next1, 0);
     124             : 
     125        1908 :               if (PREDICT_FALSE (act0 == QOS_ACTION_DROP))
     126             :                 {
     127        1495 :                   next0 = IP_PUNT_POLICER_NEXT_DROP;
     128        1495 :                   b0->error = node->errors[IP_PUNT_POLICER_ERROR_DROP];
     129             :                 }
     130        1908 :               if (PREDICT_FALSE (act1 == QOS_ACTION_DROP))
     131             :                 {
     132        1499 :                   next1 = IP_PUNT_POLICER_NEXT_DROP;
     133        1499 :                   b1->error = node->errors[IP_PUNT_POLICER_ERROR_DROP];
     134             :                 }
     135             : 
     136        1908 :               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
     137             :                 {
     138             :                   ip_punt_policer_trace_t *t =
     139        1875 :                     vlib_add_trace (vm, node, b0, sizeof (*t));
     140        1875 :                   t->next = next0;
     141        1875 :                   t->policer_index = policer_index;
     142             :                 }
     143        1908 :               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
     144             :                 {
     145             :                   ip_punt_policer_trace_t *t =
     146        1875 :                     vlib_add_trace (vm, node, b1, sizeof (*t));
     147        1875 :                   t->next = next1;
     148        1875 :                   t->policer_index = policer_index;
     149             :                 }
     150             :             }
     151             : 
     152        2100 :           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
     153             :                                            n_left_to_next,
     154             :                                            bi0, bi1, next0, next1);
     155             :         }
     156         114 :       while (n_left_from > 0 && n_left_to_next > 0)
     157             :         {
     158             :           vlib_buffer_t *b0;
     159             :           u32 next0;
     160             :           u32 bi0;
     161             :           u8 act0;
     162             : 
     163          81 :           next0 = 0;
     164          81 :           bi0 = to_next[0] = from[0];
     165             : 
     166          81 :           from += 1;
     167          81 :           n_left_from -= 1;
     168          81 :           to_next += 1;
     169          81 :           n_left_to_next -= 1;
     170             : 
     171          81 :           b0 = vlib_get_buffer (vm, bi0);
     172             : 
     173          81 :           act0 = vnet_policer_police (vm, b0, policer_index,
     174             :                                       time_in_policer_periods, POLICE_CONFORM,
     175             :                                       true);
     176          81 :           if (PREDICT_FALSE (act0 == QOS_ACTION_HANDOFF))
     177             :             {
     178          18 :               next0 = IP_PUNT_POLICER_NEXT_HANDOFF;
     179             :             }
     180             :           else
     181             :             {
     182          63 :               vnet_get_config_data (&cm->config_main,
     183             :                                     &b0->current_config_index, &next0, 0);
     184             : 
     185          63 :               if (PREDICT_FALSE (act0 == QOS_ACTION_DROP))
     186             :                 {
     187          26 :                   next0 = IP_PUNT_POLICER_NEXT_DROP;
     188          26 :                   b0->error = node->errors[IP_PUNT_POLICER_ERROR_DROP];
     189             :                 }
     190             : 
     191          63 :               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
     192             :                 {
     193             :                   ip_punt_policer_trace_t *t =
     194          54 :                     vlib_add_trace (vm, node, b0, sizeof (*t));
     195          54 :                   t->next = next0;
     196          54 :                   t->policer_index = policer_index;
     197             :                 }
     198             :             }
     199          81 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     200             :                                            n_left_to_next, bi0, next0);
     201             :         }
     202          33 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     203             :     }
     204             : 
     205          33 :   return frame->n_vectors;
     206             : }
     207             : 
     208             : /**
     209             :  * IP4 punt redirect per-rx interface configuration
     210             :  *   redirect punted traffic to another location.
     211             :  */
     212             : typedef struct ip_punt_redirect_rx_t_
     213             : {
     214             :   /**
     215             :    * Node linkage into the FIB graph
     216             :    */
     217             :   fib_node_t node;
     218             : 
     219             :   fib_protocol_t fproto;
     220             :   fib_forward_chain_type_t payload_type;
     221             :   fib_node_index_t pl;
     222             :   u32 sibling;
     223             : 
     224             :   /**
     225             :    * redirect forwarding
     226             :    */
     227             :   dpo_id_t dpo;
     228             : } ip_punt_redirect_rx_t;
     229             : 
     230             : /**
     231             :  * IP punt redirect configuration
     232             :  */
     233             : typedef struct ip_punt_redirect_t_
     234             : {
     235             :   ip_punt_redirect_rx_t *pool;
     236             : 
     237             :   /**
     238             :    * per-RX interface configuration.
     239             :    *  sw_if_index = 0 (from which packets are never received) is used to
     240             :    *  indicate 'from-any'
     241             :    */
     242             :   index_t *redirect_by_rx_sw_if_index[FIB_PROTOCOL_IP_MAX];
     243             : } ip_punt_redirect_cfg_t;
     244             : 
     245             : extern ip_punt_redirect_cfg_t ip_punt_redirect_cfg;
     246             : 
     247             : /**
     248             :  * IP punt redirect next nodes
     249             :  */
     250             : typedef enum ip_punt_redirect_next_t_
     251             : {
     252             :   IP_PUNT_REDIRECT_NEXT_DROP,
     253             :   IP_PUNT_REDIRECT_NEXT_TX,
     254             :   IP_PUNT_REDIRECT_NEXT_ARP,
     255             :   IP_PUNT_REDIRECT_N_NEXT,
     256             : } ip_punt_redirect_next_t;
     257             : 
     258             : /**
     259             :  * IP Punt redirect trace
     260             :  */
     261             : typedef struct ip4_punt_redirect_trace_t_
     262             : {
     263             :   index_t rrxi;
     264             :   u32 next;
     265             : } ip_punt_redirect_trace_t;
     266             : 
     267             : /**
     268             :  * Add a punt redirect entry
     269             :  */
     270             : extern void ip_punt_redirect_add (fib_protocol_t fproto, u32 rx_sw_if_index,
     271             :                                   fib_forward_chain_type_t ct,
     272             :                                   const fib_route_path_t *rpaths);
     273             : 
     274             : extern void ip_punt_redirect_del (fib_protocol_t fproto, u32 rx_sw_if_index);
     275             : extern index_t ip_punt_redirect_find (fib_protocol_t fproto,
     276             :                                       u32 rx_sw_if_index);
     277             : extern u8 *format_ip_punt_redirect (u8 * s, va_list * args);
     278             : 
     279             : extern u8 *format_ip_punt_redirect_trace (u8 * s, va_list * args);
     280             : 
     281             : typedef walk_rc_t (*ip_punt_redirect_walk_cb_t) (u32 rx_sw_if_index,
     282             :                                                  const ip_punt_redirect_rx_t *
     283             :                                                  redirect, void *arg);
     284             : extern void ip_punt_redirect_walk (fib_protocol_t fproto,
     285             :                                    ip_punt_redirect_walk_cb_t cb, void *ctx);
     286             : 
     287             : static_always_inline ip_punt_redirect_rx_t *
     288       10346 : ip_punt_redirect_get (index_t rrxi)
     289             : {
     290       10346 :   return (pool_elt_at_index (ip_punt_redirect_cfg.pool, rrxi));
     291             : }
     292             : 
     293             : always_inline uword
     294          94 : ip_punt_redirect (vlib_main_t * vm,
     295             :                   vlib_node_runtime_t * node,
     296             :                   vlib_frame_t * frame, u8 arc_index, fib_protocol_t fproto)
     297             : {
     298             :   u32 *from, *to_next, n_left_from, n_left_to_next, next_index;
     299          94 :   vnet_feature_main_t *fm = &feature_main;
     300          94 :   vnet_feature_config_main_t *cm = &fm->feature_config_mains[arc_index];
     301             :   index_t *redirects;
     302             : 
     303          94 :   from = vlib_frame_vector_args (frame);
     304          94 :   n_left_from = frame->n_vectors;
     305          94 :   next_index = node->cached_next_index;
     306          94 :   redirects = ip_punt_redirect_cfg.redirect_by_rx_sw_if_index[fproto];
     307             : 
     308         188 :   while (n_left_from > 0)
     309             :     {
     310          94 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     311             : 
     312       10308 :       while (n_left_from > 0 && n_left_to_next > 0)
     313             :         {
     314             :           u32 rx_sw_if_index0, rrxi0;
     315             :           ip_punt_redirect_rx_t *rrx0;
     316             :           vlib_buffer_t *b0;
     317             :           u32 next0;
     318             :           u32 bi0;
     319             : 
     320       10214 :           rrxi0 = INDEX_INVALID;
     321       10214 :           next0 = 0;
     322       10214 :           bi0 = to_next[0] = from[0];
     323             : 
     324       10214 :           from += 1;
     325       10214 :           n_left_from -= 1;
     326       10214 :           to_next += 1;
     327       10214 :           n_left_to_next -= 1;
     328             : 
     329       10214 :           b0 = vlib_get_buffer (vm, bi0);
     330             : 
     331       10214 :           vnet_get_config_data (&cm->config_main,
     332             :                                 &b0->current_config_index, &next0, 0);
     333             : 
     334       10214 :           rx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     335             : 
     336             :           /*
     337             :            * If config exists for this particular RX interface use it,
     338             :            * else use the default (at RX = 0)
     339             :            */
     340       10214 :           if (vec_len (redirects) > rx_sw_if_index0)
     341             :             {
     342       10214 :               rrxi0 = redirects[rx_sw_if_index0];
     343       10214 :               if (INDEX_INVALID == rrxi0)
     344        3075 :                 rrxi0 = redirects[0];
     345             :             }
     346           0 :           else if (vec_len (redirects) >= 1)
     347           0 :             rrxi0 = redirects[0];
     348             : 
     349       10214 :           if (PREDICT_TRUE (INDEX_INVALID != rrxi0))
     350             :             {
     351             :               /* prevent ttl decrement on forward */
     352       10214 :               b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
     353       10214 :               rrx0 = ip_punt_redirect_get (rrxi0);
     354       10214 :               vnet_buffer (b0)->ip.adj_index[VLIB_TX] = rrx0->dpo.dpoi_index;
     355       10214 :               next0 = rrx0->dpo.dpoi_next_node;
     356             :             }
     357             : 
     358       10214 :           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
     359             :             {
     360             :               ip_punt_redirect_trace_t *t =
     361        9988 :                 vlib_add_trace (vm, node, b0, sizeof (*t));
     362        9988 :               t->next = next0;
     363        9988 :               t->rrxi = rrxi0;
     364             :             }
     365             : 
     366       10214 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     367             :                                            n_left_to_next, bi0, next0);
     368             :         }
     369             : 
     370          94 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     371             :     }
     372             : 
     373          94 :   return frame->n_vectors;
     374             : }
     375             : 
     376             : always_inline uword
     377        2750 : ip_drop_or_punt (vlib_main_t * vm,
     378             :                  vlib_node_runtime_t * node,
     379             :                  vlib_frame_t * frame, u8 arc_index)
     380             : {
     381             :   u32 *from, *to_next, n_left_from, n_left_to_next, next_index;
     382             : 
     383        2750 :   from = vlib_frame_vector_args (frame);
     384        2750 :   n_left_from = frame->n_vectors;
     385        2750 :   next_index = node->cached_next_index;
     386             : 
     387        5500 :   while (n_left_from > 0)
     388             :     {
     389        2750 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     390             : 
     391       13083 :       while (n_left_from >= 8 && n_left_to_next >= 4)
     392             :         {
     393             :           vlib_buffer_t *b0, *b1, *b2, *b3;
     394             :           u32 next0, next1, next2, next3;
     395             :           u32 bi0, bi1, bi2, bi3;
     396             : 
     397       10333 :           next0 = next1 = next2 = next3 = 0;
     398             : 
     399             :           /* Prefetch next iteration. */
     400             :           {
     401             :             vlib_buffer_t *p4, *p5, *p6, *p7;
     402             : 
     403       10333 :             p4 = vlib_get_buffer (vm, from[4]);
     404       10333 :             p5 = vlib_get_buffer (vm, from[5]);
     405       10333 :             p6 = vlib_get_buffer (vm, from[6]);
     406       10333 :             p7 = vlib_get_buffer (vm, from[7]);
     407             : 
     408       10333 :             vlib_prefetch_buffer_header (p4, LOAD);
     409       10333 :             vlib_prefetch_buffer_header (p5, LOAD);
     410       10333 :             vlib_prefetch_buffer_header (p6, LOAD);
     411       10333 :             vlib_prefetch_buffer_header (p7, LOAD);
     412             :           }
     413             : 
     414       10333 :           bi0 = to_next[0] = from[0];
     415       10333 :           bi1 = to_next[1] = from[1];
     416       10333 :           bi2 = to_next[2] = from[2];
     417       10333 :           bi3 = to_next[3] = from[3];
     418             : 
     419       10333 :           from += 4;
     420       10333 :           n_left_from -= 4;
     421       10333 :           to_next += 4;
     422       10333 :           n_left_to_next -= 4;
     423             : 
     424       10333 :           b0 = vlib_get_buffer (vm, bi0);
     425       10333 :           b1 = vlib_get_buffer (vm, bi1);
     426       10333 :           b2 = vlib_get_buffer (vm, bi2);
     427       10333 :           b3 = vlib_get_buffer (vm, bi3);
     428             : 
     429             :           /* punt and drop features are not associated with a given interface
     430             :            * so the special index 0 is used */
     431       10333 :           vnet_feature_arc_start (arc_index, 0, &next0, b0);
     432       10333 :           vnet_feature_arc_start (arc_index, 0, &next1, b1);
     433       10333 :           vnet_feature_arc_start (arc_index, 0, &next2, b2);
     434       10333 :           vnet_feature_arc_start (arc_index, 0, &next3, b3);
     435             : 
     436       10333 :           vlib_validate_buffer_enqueue_x4 (vm, node, next_index,
     437             :                                            to_next, n_left_to_next,
     438             :                                            bi0, bi1, bi2, bi3,
     439             :                                            next0, next1, next2, next3);
     440             :         }
     441             : 
     442        9394 :       while (n_left_from > 0 && n_left_to_next > 0)
     443             :         {
     444             :           vlib_buffer_t *b0;
     445             :           u32 next0;
     446             :           u32 bi0;
     447             : 
     448        6644 :           next0 = 0;
     449        6644 :           bi0 = to_next[0] = from[0];
     450             : 
     451        6644 :           from += 1;
     452        6644 :           n_left_from -= 1;
     453        6644 :           to_next += 1;
     454        6644 :           n_left_to_next -= 1;
     455             : 
     456        6644 :           b0 = vlib_get_buffer (vm, bi0);
     457             : 
     458        6644 :           vnet_feature_arc_start (arc_index, 0, &next0, b0);
     459             : 
     460        6644 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     461             :                                            n_left_to_next, bi0, next0);
     462             :         }
     463        2750 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     464             :     }
     465             : 
     466        2750 :   return frame->n_vectors;
     467             : }
     468             : 
     469             : #endif
     470             : 
     471             : /*
     472             :  * fd.io coding-style-patch-verification: ON
     473             :  *
     474             :  * Local Variables:
     475             :  * eval: (c-set-style "gnu")
     476             :  * End:
     477             :  */

Generated by: LCOV version 1.14