LCOV - code coverage report
Current view: top level - plugins/urpf - urpf_dp.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 108 108 100.0 %
Date: 2023-10-26 01:39:38 Functions: 2 2 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             :  * ip/ip4_source_check.c: IP v4 check source address (unicast RPF check)
      17             :  *
      18             :  * Copyright (c) 2008 Eliot Dresselhaus
      19             :  *
      20             :  * Permission is hereby granted, free of charge, to any person obtaining
      21             :  * a copy of this software and associated documentation files (the
      22             :  * "Software"), to deal in the Software without restriction, including
      23             :  * without limitation the rights to use, copy, modify, merge, publish,
      24             :  * distribute, sublicense, and/or sell copies of the Software, and to
      25             :  * permit persons to whom the Software is furnished to do so, subject to
      26             :  * the following conditions:
      27             :  *
      28             :  * The above copyright notice and this permission notice shall be
      29             :  * included in all copies or substantial portions of the Software.
      30             :  *
      31             :  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      32             :  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      33             :  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      34             :  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      35             :  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
      36             :  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
      37             :  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      38             :  */
      39             : 
      40             : #ifndef __URPF_DP_H__
      41             : #define __URPF_DP_H__
      42             : 
      43             : #include <vnet/fib/ip4_fib.h>
      44             : #include <vnet/fib/ip6_fib.h>
      45             : #include <vnet/fib/fib_urpf_list.h>
      46             : #include <vnet/dpo/load_balance.h>
      47             : 
      48             : #include <urpf/urpf.h>
      49             : 
      50             : /**
      51             :  * @file
      52             :  * @brief Unicast Reverse Path forwarding.
      53             :  *
      54             :  * This file contains the interface unicast source check.
      55             :  */
      56             : typedef struct
      57             : {
      58             :   index_t urpf;
      59             : } urpf_trace_t;
      60             : 
      61             : static u8 *
      62        1426 : format_urpf_trace (u8 * s, va_list * va)
      63             : {
      64        1426 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
      65        1426 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
      66        1426 :   urpf_trace_t *t = va_arg (*va, urpf_trace_t *);
      67             : 
      68        1426 :   s = format (s, "uRPF:%d", t->urpf);
      69             : 
      70        1426 :   return s;
      71             : }
      72             : 
      73             : #define foreach_urpf_error                 \
      74             :   _(DROP, "uRPF Drop")                     \
      75             : 
      76             : typedef enum urpf_error_t_
      77             : {
      78             : #define _(a,b) URPF_ERROR_##a,
      79             :   foreach_urpf_error
      80             : #undef _
      81             :     URPF_N_ERROR,
      82             : } urpf_error_t;
      83             : 
      84             : typedef enum
      85             : {
      86             :   URPF_NEXT_DROP,
      87             :   URPF_N_NEXT,
      88             : } urpf_next_t;
      89             : 
      90             : static_always_inline uword
      91          26 : urpf_inline (vlib_main_t * vm,
      92             :              vlib_node_runtime_t * node,
      93             :              vlib_frame_t * frame,
      94             :              ip_address_family_t af, vlib_dir_t dir, urpf_mode_t mode)
      95             : {
      96             :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
      97             :   u16 nexts[VLIB_FRAME_SIZE], *next;
      98             :   u32 n_left, *from;
      99             : 
     100          26 :   from = vlib_frame_vector_args (frame);
     101          26 :   n_left = frame->n_vectors;
     102          26 :   b = bufs;
     103          26 :   next = nexts;
     104             : 
     105          26 :   vlib_get_buffers (vm, from, bufs, n_left);
     106             : 
     107         806 :   while (n_left >= 4)
     108             :     {
     109             :       u32 pass0, lb_index0, pass1, lb_index1;
     110             :       const load_balance_t *lb0, *lb1;
     111             :       u32 fib_index0, fib_index1;
     112             :       const u8 *h0, *h1;
     113             : 
     114             :       /* Prefetch next iteration. */
     115             :       {
     116         780 :         vlib_prefetch_buffer_header (b[2], LOAD);
     117         780 :         vlib_prefetch_buffer_header (b[3], LOAD);
     118         780 :         vlib_prefetch_buffer_data (b[2], LOAD);
     119         780 :         vlib_prefetch_buffer_data (b[3], LOAD);
     120             :       }
     121             : 
     122         780 :       h0 = (u8 *) vlib_buffer_get_current (b[0]);
     123         780 :       h1 = (u8 *) vlib_buffer_get_current (b[1]);
     124             : 
     125         780 :       if (VLIB_TX == dir)
     126             :         {
     127         420 :           h0 += vnet_buffer (b[0])->ip.save_rewrite_length;
     128         420 :           h1 += vnet_buffer (b[1])->ip.save_rewrite_length;
     129             :         }
     130             : 
     131         780 :       fib_index0 =
     132         780 :         urpf_cfgs[af][dir][vnet_buffer (b[0])->sw_if_index[dir]].fib_index;
     133         780 :       fib_index1 =
     134         780 :         urpf_cfgs[af][dir][vnet_buffer (b[1])->sw_if_index[dir]].fib_index;
     135             : 
     136         780 :       if (AF_IP4 == af)
     137             :         {
     138             :           const ip4_header_t *ip0, *ip1;
     139             : 
     140         390 :           ip0 = (ip4_header_t *) h0;
     141         390 :           ip1 = (ip4_header_t *) h1;
     142             : 
     143         390 :           ip4_fib_forwarding_lookup_x2 (fib_index0,
     144             :                                         fib_index1,
     145             :                                         &ip0->src_address,
     146             :                                         &ip1->src_address,
     147             :                                         &lb_index0, &lb_index1);
     148             :           /* Pass multicast. */
     149         780 :           pass0 = (ip4_address_is_multicast (&ip0->src_address) ||
     150         390 :                    ip4_address_is_global_broadcast (&ip0->src_address));
     151         780 :           pass1 = (ip4_address_is_multicast (&ip1->src_address) ||
     152         390 :                    ip4_address_is_global_broadcast (&ip1->src_address));
     153             :         }
     154             :       else
     155             :         {
     156             :           const ip6_header_t *ip0, *ip1;
     157             : 
     158         390 :           ip0 = (ip6_header_t *) h0;
     159         390 :           ip1 = (ip6_header_t *) h1;
     160             : 
     161         390 :           lb_index0 = ip6_fib_table_fwding_lookup (fib_index0,
     162             :                                                    &ip0->src_address);
     163         390 :           lb_index1 = ip6_fib_table_fwding_lookup (fib_index1,
     164             :                                                    &ip1->src_address);
     165         390 :           pass0 = ip6_address_is_multicast (&ip0->src_address);
     166         390 :           pass1 = ip6_address_is_multicast (&ip1->src_address);
     167             :         }
     168             : 
     169         780 :       lb0 = load_balance_get (lb_index0);
     170         780 :       lb1 = load_balance_get (lb_index1);
     171             : 
     172         780 :       if (URPF_MODE_STRICT == mode)
     173             :         {
     174             :           /* for RX the check is: would this source adddress be forwarded
     175             :            * out of the interface on which it was recieved, if yes allow.
     176             :            * For TX it's; would this source address be forwarded out of the
     177             :            * interface through which it is being sent, if yes drop.
     178             :            */
     179             :           int res0, res1;
     180             : 
     181         420 :           res0 = fib_urpf_check (lb0->lb_urpf,
     182         420 :                                  vnet_buffer (b[0])->sw_if_index[dir]);
     183         420 :           res1 = fib_urpf_check (lb1->lb_urpf,
     184         420 :                                  vnet_buffer (b[1])->sw_if_index[dir]);
     185             : 
     186         420 :           if (VLIB_RX == dir)
     187             :             {
     188         180 :               pass0 |= res0;
     189         180 :               pass1 |= res1;
     190             :             }
     191             :           else
     192             :             {
     193         240 :               pass0 |= !res0 && fib_urpf_check_size (lb0->lb_urpf);
     194         240 :               pass1 |= !res1 && fib_urpf_check_size (lb1->lb_urpf);
     195             : 
     196             :               /* allow locally generated */
     197         240 :               pass0 |= b[0]->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
     198         240 :               pass1 |= b[1]->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
     199             :             }
     200             :         }
     201             :       else
     202             :         {
     203         360 :           pass0 |= fib_urpf_check_size (lb0->lb_urpf);
     204         360 :           pass1 |= fib_urpf_check_size (lb1->lb_urpf);
     205             :         }
     206             : 
     207         780 :       if (PREDICT_TRUE (pass0))
     208         420 :         vnet_feature_next_u16 (&next[0], b[0]);
     209             :       else
     210             :         {
     211         360 :           next[0] = URPF_NEXT_DROP;
     212         360 :           b[0]->error = node->errors[URPF_ERROR_DROP];
     213             :         }
     214         780 :       if (PREDICT_TRUE (pass1))
     215         420 :         vnet_feature_next_u16 (&next[1], b[1]);
     216             :       else
     217             :         {
     218         360 :           next[1] = URPF_NEXT_DROP;
     219         360 :           b[1]->error = node->errors[URPF_ERROR_DROP];
     220             :         }
     221             : 
     222         780 :       if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
     223             :         {
     224             :           urpf_trace_t *t;
     225             : 
     226         780 :           t = vlib_add_trace (vm, node, b[0], sizeof (*t));
     227         780 :           t->urpf = lb0->lb_urpf;
     228             :         }
     229         780 :       if (b[1]->flags & VLIB_BUFFER_IS_TRACED)
     230             :         {
     231             :           urpf_trace_t *t;
     232             : 
     233         780 :           t = vlib_add_trace (vm, node, b[1], sizeof (*t));
     234         780 :           t->urpf = lb1->lb_urpf;
     235             :         }
     236             : 
     237         780 :       b += 2;
     238         780 :       next += 2;
     239         780 :       n_left -= 2;
     240             :     }
     241             : 
     242         104 :   while (n_left)
     243             :     {
     244             :       u32 pass0, lb_index0, fib_index0;
     245             :       const load_balance_t *lb0;
     246             :       const u8 *h0;
     247             : 
     248          78 :       h0 = (u8 *) vlib_buffer_get_current (b[0]);
     249             : 
     250          78 :       if (VLIB_TX == dir)
     251          42 :         h0 += vnet_buffer (b[0])->ip.save_rewrite_length;
     252             : 
     253          78 :       fib_index0 =
     254          78 :         urpf_cfgs[af][dir][vnet_buffer (b[0])->sw_if_index[dir]].fib_index;
     255             : 
     256          78 :       if (AF_IP4 == af)
     257             :         {
     258             :           const ip4_header_t *ip0;
     259             : 
     260          39 :           ip0 = (ip4_header_t *) h0;
     261             : 
     262          39 :           lb_index0 = ip4_fib_forwarding_lookup (fib_index0,
     263             :                                                  &ip0->src_address);
     264             : 
     265             :           /* Pass multicast. */
     266          78 :           pass0 = (ip4_address_is_multicast (&ip0->src_address) ||
     267          39 :                    ip4_address_is_global_broadcast (&ip0->src_address));
     268             :         }
     269             :       else
     270             :         {
     271             :           const ip6_header_t *ip0;
     272             : 
     273          39 :           ip0 = (ip6_header_t *) h0;
     274             : 
     275          39 :           lb_index0 = ip6_fib_table_fwding_lookup (fib_index0,
     276             :                                                    &ip0->src_address);
     277          39 :           pass0 = ip6_address_is_multicast (&ip0->src_address);
     278             :         }
     279             : 
     280          78 :       lb0 = load_balance_get (lb_index0);
     281             : 
     282          78 :       if (URPF_MODE_STRICT == mode)
     283             :         {
     284             :           int res0;
     285             : 
     286          42 :           res0 = fib_urpf_check (lb0->lb_urpf,
     287          42 :                                  vnet_buffer (b[0])->sw_if_index[dir]);
     288          42 :           if (VLIB_RX == dir)
     289          18 :             pass0 |= res0;
     290             :           else
     291             :             {
     292          24 :               pass0 |= !res0 && fib_urpf_check_size (lb0->lb_urpf);
     293          24 :               pass0 |= b[0]->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
     294             :             }
     295             :         }
     296             :       else
     297          36 :         pass0 |= fib_urpf_check_size (lb0->lb_urpf);
     298             : 
     299          78 :       if (PREDICT_TRUE (pass0))
     300          42 :         vnet_feature_next_u16 (&next[0], b[0]);
     301             :       else
     302             :         {
     303          36 :           next[0] = URPF_NEXT_DROP;
     304          36 :           b[0]->error = node->errors[URPF_ERROR_DROP];
     305             :         }
     306             : 
     307          78 :       if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
     308             :         {
     309             :           urpf_trace_t *t;
     310             : 
     311          78 :           t = vlib_add_trace (vm, node, b[0], sizeof (*t));
     312          78 :           t->urpf = lb0->lb_urpf;
     313             :         }
     314          78 :       b++;
     315          78 :       next++;
     316          78 :       n_left--;
     317             :     }
     318             : 
     319          26 :   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
     320             : 
     321          26 :   return frame->n_vectors;
     322             : }
     323             : 
     324             : #endif
     325             : 
     326             : /*
     327             :  * fd.io coding-style-patch-verification: ON
     328             :  *
     329             :  * Local Variables:
     330             :  * eval: (c-set-style "gnu")
     331             :  * End:
     332             :  */

Generated by: LCOV version 1.14