LCOV - code coverage report
Current view: top level - plugins/acl - public_inlines.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 225 274 82.1 %
Date: 2023-10-26 01:39:38 Functions: 16 16 100.0 %

          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             : #ifndef included_acl_inlines_h
      17             : #define included_acl_inlines_h
      18             : 
      19             : #include <stdint.h>
      20             : 
      21             : #include <vlib/unix/plugin.h>
      22             : #include <plugins/acl/acl.h>
      23             : #include <plugins/acl/fa_node.h>
      24             : #include <plugins/acl/hash_lookup_private.h>
      25             : 
      26             : #include <plugins/acl/exported_types.h>
      27             : 
      28             : #define LOAD_SYMBOL_FROM_PLUGIN_TO(p, s, st)                              \
      29             : ({                                                                        \
      30             :     st = vlib_get_plugin_symbol(p, #s);                                    \
      31             :     if (!st)                                                               \
      32             :         return clib_error_return(0,                                       \
      33             :                 "Plugin %s and/or symbol %s not found.", p, #s);          \
      34             : })
      35             : 
      36             : #define LOAD_SYMBOL(s) LOAD_SYMBOL_FROM_PLUGIN_TO("acl_plugin.so", s, s)
      37             : 
      38             : 
      39        1150 : static inline clib_error_t * acl_plugin_exports_init (acl_plugin_methods_t *m)
      40             : {
      41             :     acl_plugin_methods_vtable_init_fn_t mvi;
      42             : 
      43        1150 :     LOAD_SYMBOL_FROM_PLUGIN_TO("acl_plugin.so", acl_plugin_methods_vtable_init, mvi);
      44        1150 :     return (mvi(m));
      45             : }
      46             : 
      47             : always_inline void *
      48         626 : get_ptr_to_offset (vlib_buffer_t * b0, int offset)
      49             : {
      50         626 :   u8 *p = vlib_buffer_get_current (b0) + offset;
      51         626 :   return p;
      52             : }
      53             : 
      54             : always_inline int
      55       10548 : offset_within_packet (vlib_buffer_t * b0, int offset)
      56             : {
      57             :   /* For the purposes of this code, "within" means we have at least 8 bytes after it */
      58       10548 :   return (offset <= (b0->current_length - 8));
      59             : }
      60             : 
      61             : always_inline int
      62             : offset_beyond_packet (vlib_buffer_t * b0, int offset)
      63             : {
      64             :   /* For the purposes of this code, "within" means we have at least 8 bytes after it */
      65             :   return (offset > (b0->current_length - 8));
      66             : }
      67             : 
      68             : 
      69             : always_inline void
      70       10235 : acl_fill_5tuple_l3_data (acl_main_t * am, vlib_buffer_t * b0, int is_ip6,
      71             :                  int l3_offset, fa_5tuple_t * p5tuple_pkt)
      72             : {
      73       10235 :   if (is_ip6)
      74             :     {
      75        1467 :       ip6_header_t *ip6 = vlib_buffer_get_current (b0) + l3_offset;
      76        1467 :       p5tuple_pkt->ip6_addr[0] = ip6->src_address;
      77        1467 :       p5tuple_pkt->ip6_addr[1] = ip6->dst_address;
      78             :     }
      79             :   else
      80             :     {
      81             :       int ii;
      82       61376 :       for(ii=0; ii<6; ii++) {
      83       52608 :         p5tuple_pkt->l3_zero_pad[ii] = 0;
      84             :       }
      85        8768 :       ip4_header_t *ip4 = vlib_buffer_get_current (b0) + l3_offset;
      86        8768 :       p5tuple_pkt->ip4_addr[0] = ip4->src_address;
      87        8768 :       p5tuple_pkt->ip4_addr[1] = ip4->dst_address;
      88             :     }
      89       10235 : }
      90             : 
      91             : always_inline void
      92       10235 : acl_fill_5tuple_l4_and_pkt_data (acl_main_t * am, u32 sw_if_index0, vlib_buffer_t * b0, int is_ip6, int is_input,
      93             :                  int l3_offset, fa_session_l4_key_t *p5tuple_l4, fa_packet_info_t *p5tuple_pkt)
      94             : {
      95             :   /* IP4 and IP6 protocol numbers of ICMP */
      96             :   static u8 icmp_protos_v4v6[] = { IP_PROTOCOL_ICMP, IP_PROTOCOL_ICMP6 };
      97             : 
      98             :   int l4_offset;
      99       10235 :   u16 ports[2] = { 0 };
     100             :   u8 proto;
     101             : 
     102       10235 :   u8 tmp_l4_flags = 0;
     103       10235 :   fa_packet_info_t tmp_pkt = { .is_ip6 = is_ip6, .mask_type_index_lsb = ~0 };
     104             : 
     105       10235 :   if (is_ip6)
     106             :     {
     107        1467 :       ip6_header_t *ip6 = vlib_buffer_get_current (b0) + l3_offset;
     108        1467 :       proto = ip6->protocol;
     109             : 
     110        1467 :       l4_offset = l3_offset + sizeof (ip6_header_t);
     111             : 
     112             :       /* IP6 EH handling is here, increment l4_offset if needs to, update the proto */
     113        1467 :       int need_skip_eh = clib_bitmap_get (am->fa_ipv6_known_eh_bitmap, proto);
     114        1467 :       if (PREDICT_FALSE (need_skip_eh))
     115             :         {
     116         442 :           while (need_skip_eh && offset_within_packet (b0, l4_offset))
     117             :             {
     118             :               /* Fragment header needs special handling */
     119         313 :               if (PREDICT_FALSE(ACL_EH_FRAGMENT == proto))
     120             :                 {
     121         127 :                   proto = *(u8 *) get_ptr_to_offset (b0, l4_offset);
     122         127 :                   u16 frag_offset = *(u16 *) get_ptr_to_offset (b0, 2 + l4_offset);
     123         127 :                   frag_offset = clib_net_to_host_u16(frag_offset) >> 3;
     124         127 :                   if (frag_offset)
     125             :                     {
     126          35 :                       tmp_pkt.is_nonfirst_fragment = 1;
     127             :                       /* invalidate L4 offset so we don't try to find L4 info */
     128          35 :                       l4_offset += b0->current_length;
     129             :                     }
     130             :                   else
     131             :                     {
     132             :                       /* First fragment: skip the frag header and move on. */
     133          92 :                       l4_offset += 8;
     134             :                     }
     135             :                 }
     136             :               else
     137             :                 {
     138         186 :                   u8 nwords = *(u8 *) get_ptr_to_offset (b0, 1 + l4_offset);
     139         186 :                   proto = *(u8 *) get_ptr_to_offset (b0, l4_offset);
     140         186 :                   l4_offset += 8 * (1 + (u16) nwords);
     141             :                 }
     142         313 :               need_skip_eh =
     143         313 :                 clib_bitmap_get (am->fa_ipv6_known_eh_bitmap, proto);
     144             :             }
     145             :         }
     146             :     }
     147             :   else
     148             :     {
     149        8768 :       ip4_header_t *ip4 = vlib_buffer_get_current (b0) + l3_offset;
     150        8768 :       proto = ip4->protocol;
     151        8768 :       l4_offset = l3_offset + ip4_header_bytes(ip4);
     152             : 
     153             :       /* non-initial fragments have non-zero offset */
     154        8768 :       if (PREDICT_FALSE(ip4_get_fragment_offset(ip4)))
     155             :         {
     156          29 :           tmp_pkt.is_nonfirst_fragment = 1;
     157             :           /* invalidate L4 offset so we don't try to find L4 info */
     158          29 :           l4_offset += b0->current_length;
     159             :         }
     160             : 
     161             :     }
     162       10235 :   tmp_l4_flags |= is_input ? FA_SK_L4_FLAG_IS_INPUT : 0;
     163             : 
     164       10235 :   if (PREDICT_TRUE (offset_within_packet (b0, l4_offset)))
     165             :     {
     166       10171 :       tcp_header_t *tcph = vlib_buffer_get_current (b0) + l4_offset;
     167       10171 :       udp_header_t *udph = vlib_buffer_get_current (b0) + l4_offset;
     168       10171 :       tmp_pkt.l4_valid = 1;
     169             : 
     170       10171 :       if (PREDICT_FALSE(icmp_protos_v4v6[is_ip6] == proto))
     171             :         {
     172         737 :           icmp46_header_t *icmph = vlib_buffer_get_current (b0) + l4_offset;
     173         737 :           ports[0] = icmph->type;
     174         737 :           ports[1] = icmph->code;
     175             :           /* ICMP needs special handling */
     176         737 :           tmp_l4_flags |= FA_SK_L4_FLAG_IS_SLOWPATH;
     177             :         }
     178        9434 :       else if (IP_PROTOCOL_TCP == proto)
     179             :         {
     180         614 :           ports[0] = clib_net_to_host_u16(tcph->src_port);
     181         614 :           ports[1] = clib_net_to_host_u16(tcph->dst_port);
     182         614 :           tmp_pkt.tcp_flags = tcph->flags;
     183         614 :           tmp_pkt.tcp_flags_valid = 1;
     184             :         }
     185        8820 :       else if (IP_PROTOCOL_UDP == proto)
     186             :         {
     187        5605 :           ports[0] = clib_net_to_host_u16(udph->src_port);
     188        5605 :           ports[1] = clib_net_to_host_u16(udph->dst_port);
     189             :         }
     190             :       else
     191             :         {
     192        3215 :           tmp_l4_flags |= FA_SK_L4_FLAG_IS_SLOWPATH;
     193             :         }
     194             :     }
     195             : 
     196       10235 :   p5tuple_pkt->as_u64 = tmp_pkt.as_u64;
     197             : 
     198       10235 :   fa_session_l4_key_t tmp_l4 = { .port = { ports[0], ports[1] },
     199             :                                  .proto = proto,
     200             :                                  .l4_flags = tmp_l4_flags,
     201             :                                  .lsb_of_sw_if_index = sw_if_index0 & 0xffff };
     202             : 
     203       10235 :   p5tuple_l4->as_u64 = tmp_l4.as_u64;
     204       10235 : }
     205             : 
     206             : always_inline void
     207       10235 : acl_fill_5tuple (acl_main_t * am, u32 sw_if_index0, vlib_buffer_t * b0, int is_ip6,
     208             :                  int is_input, int is_l2_path, fa_5tuple_t * p5tuple_pkt)
     209             : {
     210             :   int l3_offset;
     211             : 
     212       10235 :   if (is_l2_path)
     213             :     {
     214        2338 :       l3_offset = ethernet_buffer_header_size(b0);
     215             :     }
     216             :   else
     217             :     {
     218        7897 :       if (is_input)
     219        1072 :         l3_offset = 0;
     220             :       else
     221        6825 :         l3_offset = vnet_buffer(b0)->ip.save_rewrite_length;
     222             :     }
     223             : 
     224             :   /* key[0..3] contains src/dst address and is cleared/set below */
     225             :   /* Remainder of the key and per-packet non-key data */
     226       10235 :   acl_fill_5tuple_l3_data(am, b0, is_ip6, l3_offset, p5tuple_pkt);
     227       10235 :   acl_fill_5tuple_l4_and_pkt_data(am, sw_if_index0, b0, is_ip6, is_input, l3_offset, &p5tuple_pkt->l4, &p5tuple_pkt->pkt);
     228       10235 : }
     229             : 
     230             : always_inline void
     231         737 : acl_plugin_fill_5tuple_inline (void *p_acl_main, u32 lc_index, vlib_buffer_t * b0, int is_ip6,
     232             :                  int is_input, int is_l2_path, fa_5tuple_opaque_t * p5tuple_pkt)
     233             : {
     234         737 :   acl_main_t *am = p_acl_main;
     235         737 :   acl_fill_5tuple(am, 0, b0, is_ip6, is_input, is_l2_path, (fa_5tuple_t *)p5tuple_pkt);
     236         737 : }
     237             : 
     238             : 
     239             : 
     240             : always_inline int
     241       17692 : fa_acl_match_ip4_addr (ip4_address_t * addr1, ip4_address_t * addr2,
     242             :                    int prefixlen)
     243             : {
     244       17692 :   if (prefixlen == 0)
     245             :     {
     246             :       /* match any always succeeds */
     247       15284 :       return 1;
     248             :     }
     249        2408 :       uint32_t a1 = clib_net_to_host_u32 (addr1->as_u32);
     250        2408 :       uint32_t a2 = clib_net_to_host_u32 (addr2->as_u32);
     251        2408 :       uint32_t mask0 = 0xffffffff - ((1 << (32 - prefixlen)) - 1);
     252        2408 :       return (a1 & mask0) == a2;
     253             : }
     254             : 
     255             : always_inline int
     256        3240 : fa_acl_match_ip6_addr (ip6_address_t * addr1, ip6_address_t * addr2,
     257             :                    int prefixlen)
     258             : {
     259        3240 :   if (prefixlen == 0)
     260             :     {
     261             :       /* match any always succeeds */
     262        2038 :       return 1;
     263             :     }
     264        1202 :       if (memcmp (addr1, addr2, prefixlen / 8))
     265             :         {
     266             :           /* If the starting full bytes do not match, no point in bittwidling the thumbs further */
     267           0 :           return 0;
     268             :         }
     269        1202 :       if (prefixlen % 8)
     270             :         {
     271           0 :           u8 b1 = *((u8 *) addr1 + 1 + prefixlen / 8);
     272           0 :           u8 b2 = *((u8 *) addr2 + 1 + prefixlen / 8);
     273           0 :           u8 mask0 = (0xff - ((1 << (8 - (prefixlen % 8))) - 1));
     274           0 :           return (b1 & mask0) == b2;
     275             :         }
     276             :       else
     277             :         {
     278             :           /* The prefix fits into integer number of bytes, so nothing left to do */
     279        1202 :           return 1;
     280             :         }
     281             : }
     282             : 
     283             : always_inline int
     284        7188 : fa_acl_match_port (u16 port, u16 port_first, u16 port_last, int is_ip6)
     285             : {
     286        7188 :   return ((port >= port_first) && (port <= port_last));
     287             : }
     288             : 
     289             : always_inline int
     290          64 : single_acl_match_5tuple (acl_main_t * am, u32 acl_index, fa_5tuple_t * pkt_5tuple,
     291             :                   int is_ip6, u8 * r_action, u32 * r_acl_match_p,
     292             :                   u32 * r_rule_match_p, u32 * trace_bitmap)
     293             : {
     294             :   int i;
     295             :   acl_rule_t *r;
     296             :   acl_rule_t *acl_rules;
     297             : 
     298          64 :   if (pool_is_free_index (am->acls, acl_index))
     299             :     {
     300           0 :       if (r_acl_match_p)
     301           0 :         *r_acl_match_p = acl_index;
     302           0 :       if (r_rule_match_p)
     303           0 :         *r_rule_match_p = -1;
     304             :       /* the ACL does not exist but is used for policy. Block traffic. */
     305           0 :       return 0;
     306             :     }
     307          64 :   acl_rules = am->acls[acl_index].rules;
     308          99 :   for (i = 0; i < vec_len(acl_rules); i++)
     309             :     {
     310          99 :       r = &acl_rules[i];
     311          99 :       if (is_ip6 != r->is_ipv6)
     312             :         {
     313          35 :           continue;
     314             :         }
     315          64 :       if (is_ip6) {
     316          35 :         if (!fa_acl_match_ip6_addr
     317          35 :           (&pkt_5tuple->ip6_addr[1], &r->dst.ip6, r->dst_prefixlen))
     318           0 :         continue;
     319          35 :         if (!fa_acl_match_ip6_addr
     320          35 :           (&pkt_5tuple->ip6_addr[0], &r->src.ip6, r->src_prefixlen))
     321           0 :         continue;
     322             :       } else {
     323          29 :         if (!fa_acl_match_ip4_addr
     324          29 :           (&pkt_5tuple->ip4_addr[1], &r->dst.ip4, r->dst_prefixlen))
     325           0 :         continue;
     326          29 :         if (!fa_acl_match_ip4_addr
     327          29 :           (&pkt_5tuple->ip4_addr[0], &r->src.ip4, r->src_prefixlen))
     328           0 :         continue;
     329             :       }
     330             : 
     331          64 :       if (r->proto)
     332             :         {
     333          64 :           if (pkt_5tuple->l4.proto != r->proto)
     334           0 :             continue;
     335             : 
     336          64 :           if (PREDICT_FALSE (pkt_5tuple->pkt.is_nonfirst_fragment &&
     337             :                      am->l4_match_nonfirst_fragment))
     338             :           {
     339             :             /* non-initial fragment with frag match configured - match this rule */
     340          64 :             *trace_bitmap |= 0x80000000;
     341          64 :             *r_action = r->is_permit;
     342          64 :             if (r_acl_match_p)
     343          64 :               *r_acl_match_p = acl_index;
     344          64 :             if (r_rule_match_p)
     345          64 :               *r_rule_match_p = i;
     346          64 :             return 1;
     347             :           }
     348             : 
     349             :           /* A sanity check just to ensure we are about to match the ports extracted from the packet */
     350           0 :           if (PREDICT_FALSE (!pkt_5tuple->pkt.l4_valid))
     351           0 :             continue;
     352             : 
     353             : #ifdef FA_NODE_VERBOSE_DEBUG
     354             :           clib_warning
     355             :             ("ACL_FA_NODE_DBG acl %d rule %d pkt proto %d match rule %d",
     356             :              acl_index, i, pkt_5tuple->l4.proto, r->proto);
     357             : #endif
     358             : 
     359           0 :           if (!fa_acl_match_port
     360           0 :               (pkt_5tuple->l4.port[0], r->src_port_or_type_first,
     361           0 :                r->src_port_or_type_last, is_ip6))
     362           0 :             continue;
     363             : 
     364             : #ifdef FA_NODE_VERBOSE_DEBUG
     365             :           clib_warning
     366             :             ("ACL_FA_NODE_DBG acl %d rule %d pkt sport %d match rule [%d..%d]",
     367             :              acl_index, i, pkt_5tuple->l4.port[0], r->src_port_or_type_first,
     368             :              r->src_port_or_type_last);
     369             : #endif
     370             : 
     371           0 :           if (!fa_acl_match_port
     372           0 :               (pkt_5tuple->l4.port[1], r->dst_port_or_code_first,
     373           0 :                r->dst_port_or_code_last, is_ip6))
     374           0 :             continue;
     375             : 
     376             : #ifdef FA_NODE_VERBOSE_DEBUG
     377             :           clib_warning
     378             :             ("ACL_FA_NODE_DBG acl %d rule %d pkt dport %d match rule [%d..%d]",
     379             :              acl_index, i, pkt_5tuple->l4.port[1], r->dst_port_or_code_first,
     380             :              r->dst_port_or_code_last);
     381             : #endif
     382           0 :           if (pkt_5tuple->pkt.tcp_flags_valid
     383           0 :               && ((pkt_5tuple->pkt.tcp_flags & r->tcp_flags_mask) !=
     384           0 :                   r->tcp_flags_value))
     385           0 :             continue;
     386             :         }
     387             :       /* everything matches! */
     388             : #ifdef FA_NODE_VERBOSE_DEBUG
     389             :       clib_warning ("ACL_FA_NODE_DBG acl %d rule %d FULL-MATCH, action %d",
     390             :                     acl_index, i, r->is_permit);
     391             : #endif
     392           0 :       *r_action = r->is_permit;
     393           0 :       if (r_acl_match_p)
     394           0 :         *r_acl_match_p = acl_index;
     395           0 :       if (r_rule_match_p)
     396           0 :         *r_rule_match_p = i;
     397           0 :       return 1;
     398             :     }
     399           0 :   return 0;
     400             : }
     401             : 
     402             : always_inline int
     403             : acl_plugin_single_acl_match_5tuple (void *p_acl_main, u32 acl_index, fa_5tuple_t * pkt_5tuple,
     404             :                   int is_ip6, u8 * r_action, u32 * r_acl_match_p,
     405             :                   u32 * r_rule_match_p, u32 * trace_bitmap)
     406             : {
     407             :   acl_main_t * am = p_acl_main;
     408             :   return single_acl_match_5tuple(am, acl_index, pkt_5tuple, is_ip6, r_action,
     409             :                                  r_acl_match_p, r_rule_match_p, trace_bitmap);
     410             : }
     411             : 
     412             : always_inline int
     413          64 : linear_multi_acl_match_5tuple (void *p_acl_main, u32 lc_index, fa_5tuple_t * pkt_5tuple,
     414             :                        int is_ip6, u8 *r_action, u32 *acl_pos_p, u32 * acl_match_p,
     415             :                        u32 * rule_match_p, u32 * trace_bitmap)
     416             : {
     417          64 :   acl_main_t *am = p_acl_main;
     418             :   int i;
     419             :   u32 *acl_vector;
     420          64 :   u8 action = 0;
     421          64 :   acl_lookup_context_t *acontext = pool_elt_at_index(am->acl_lookup_contexts, lc_index);
     422             : 
     423          64 :   acl_vector = acontext->acl_indices;
     424             : 
     425          64 :   for (i = 0; i < vec_len (acl_vector); i++)
     426             :     {
     427             : #ifdef FA_NODE_VERBOSE_DEBUG
     428             :       clib_warning ("ACL_FA_NODE_DBG: Trying to match ACL: %d",
     429             :                     acl_vector[i]);
     430             : #endif
     431          64 :       if (single_acl_match_5tuple
     432          64 :           (am, acl_vector[i], pkt_5tuple, is_ip6, &action,
     433             :            acl_match_p, rule_match_p, trace_bitmap))
     434             :         {
     435          64 :           *r_action = action;
     436          64 :           *acl_pos_p = i;
     437          64 :           return 1;
     438             :         }
     439             :     }
     440           0 :   if (vec_len (acl_vector) > 0)
     441             :     {
     442           0 :       return 0;
     443             :     }
     444             : #ifdef FA_NODE_VERBOSE_DEBUG
     445             :   clib_warning ("ACL_FA_NODE_DBG: No ACL on lc_index %d", lc_index);
     446             : #endif
     447             :   /* If there are no ACLs defined we should not be here. */
     448           0 :   return 0;
     449             : }
     450             : 
     451             : 
     452             : 
     453             : /*
     454             :  * This returns true if there is indeed a match on the portranges.
     455             :  * With all these levels of indirections, this is not going to be very fast,
     456             :  * so, best use the individual ports or wildcard ports for performance.
     457             :  */
     458             : always_inline int
     459             : match_portranges(acl_main_t *am, fa_5tuple_t *match, u32 index)
     460             : {
     461             : 
     462             :   applied_hash_ace_entry_t **applied_hash_aces = vec_elt_at_index(am->hash_entry_vec_by_lc_index, match->pkt.lc_index);
     463             :   applied_hash_ace_entry_t *pae = vec_elt_at_index((*applied_hash_aces), index);
     464             : 
     465             :   acl_rule_t *r = &(am->acls[pae->acl_index].rules[pae->ace_index]);
     466             : 
     467             : #ifdef FA_NODE_VERBOSE_DEBUG
     468             :   clib_warning("PORTMATCH: %d <= %d <= %d && %d <= %d <= %d ?",
     469             :                 r->src_port_or_type_first, match->l4.port[0], r->src_port_or_type_last,
     470             :                 r->dst_port_or_code_first, match->l4.port[1], r->dst_port_or_code_last);
     471             : #endif
     472             : 
     473             :   return ( ((r->src_port_or_type_first <= match->l4.port[0]) && r->src_port_or_type_last >= match->l4.port[0]) &&
     474             :            ((r->dst_port_or_code_first <= match->l4.port[1]) && r->dst_port_or_code_last >= match->l4.port[1]) );
     475             : }
     476             : 
     477             : always_inline int
     478       10469 : single_rule_match_5tuple (acl_rule_t * r, int is_ip6, fa_5tuple_t * pkt_5tuple)
     479             : {
     480       10469 :   if (is_ip6 != r->is_ipv6)
     481             :     {
     482           0 :       return 0;
     483             :     }
     484             : 
     485       10469 :   if (is_ip6)
     486             :     {
     487        1585 :       if (!fa_acl_match_ip6_addr
     488        1585 :           (&pkt_5tuple->ip6_addr[1], &r->dst.ip6, r->dst_prefixlen))
     489           0 :         return 0;
     490        1585 :       if (!fa_acl_match_ip6_addr
     491        1585 :           (&pkt_5tuple->ip6_addr[0], &r->src.ip6, r->src_prefixlen))
     492           0 :         return 0;
     493             :     }
     494             :   else
     495             :     {
     496        8884 :       if (!fa_acl_match_ip4_addr
     497        8884 :           (&pkt_5tuple->ip4_addr[1], &r->dst.ip4, r->dst_prefixlen))
     498         134 :         return 0;
     499        8750 :       if (!fa_acl_match_ip4_addr
     500        8750 :           (&pkt_5tuple->ip4_addr[0], &r->src.ip4, r->src_prefixlen))
     501           0 :         return 0;
     502             :     }
     503             : 
     504       10335 :   if (r->proto)
     505             :     {
     506        3786 :       if (pkt_5tuple->l4.proto != r->proto)
     507           0 :         return 0;
     508             : 
     509             :       /* A sanity check just to ensure we are about to match the ports extracted from the packet */
     510        3786 :       if (PREDICT_FALSE (!pkt_5tuple->pkt.l4_valid))
     511           0 :         return 0;
     512             : 
     513             : 
     514        3786 :       if (!fa_acl_match_port
     515        3786 :           (pkt_5tuple->l4.port[0], r->src_port_or_type_first,
     516        3786 :            r->src_port_or_type_last, pkt_5tuple->pkt.is_ip6))
     517         384 :         return 0;
     518             : 
     519             : 
     520        3402 :       if (!fa_acl_match_port
     521        3402 :           (pkt_5tuple->l4.port[1], r->dst_port_or_code_first,
     522        3402 :            r->dst_port_or_code_last, pkt_5tuple->pkt.is_ip6))
     523           0 :         return 0;
     524             : 
     525        3402 :       if (pkt_5tuple->pkt.tcp_flags_valid
     526         608 :           && ((pkt_5tuple->pkt.tcp_flags & r->tcp_flags_mask) !=
     527         608 :               r->tcp_flags_value))
     528           0 :         return 0;
     529             :     }
     530             :   /* everything matches! */
     531        9951 :   return 1;
     532             : }
     533             : 
     534             : always_inline u32
     535       10087 : multi_acl_match_get_applied_ace_index (acl_main_t * am, int is_ip6, fa_5tuple_t * match)
     536             : {
     537             :   clib_bihash_kv_48_8_t kv;
     538             :   clib_bihash_kv_48_8_t result;
     539       10087 :   fa_5tuple_t *kv_key = (fa_5tuple_t *) kv.key;
     540       10087 :   hash_acl_lookup_value_t *result_val =
     541             :     (hash_acl_lookup_value_t *) & result.value;
     542       10087 :   u64 *pmatch = (u64 *) match;
     543             :   u64 *pmask;
     544             :   u64 *pkey;
     545             :   int mask_type_index, order_index;
     546       10087 :   u32 curr_match_index = (~0 - 1);
     547             : 
     548             : 
     549             : 
     550       10087 :   u32 lc_index = match->pkt.lc_index;
     551       10087 :   applied_hash_ace_entry_t **applied_hash_aces =
     552       10087 :     vec_elt_at_index (am->hash_entry_vec_by_lc_index, lc_index);
     553             : 
     554       10087 :   hash_applied_mask_info_t **hash_applied_mask_info_vec =
     555       10087 :     vec_elt_at_index (am->hash_applied_mask_info_vec_by_lc_index, lc_index);
     556             : 
     557             :   hash_applied_mask_info_t *minfo;
     558             : 
     559             :   DBG ("TRYING TO MATCH: %016llx %016llx %016llx %016llx %016llx %016llx",
     560             :        pmatch[0], pmatch[1], pmatch[2], pmatch[3], pmatch[4], pmatch[5]);
     561             : 
     562       20462 :   for (order_index = 0; order_index < vec_len ((*hash_applied_mask_info_vec));
     563       10375 :        order_index++)
     564             :     {
     565       12123 :       minfo = vec_elt_at_index ((*hash_applied_mask_info_vec), order_index);
     566       12123 :       if (minfo->first_rule_index > curr_match_index)
     567             :         {
     568             :           /* Index in this and following (by construction) partitions are greater than our candidate, Avoid trying to match! */
     569        1748 :           break;
     570             :         }
     571             : 
     572       10375 :       mask_type_index = minfo->mask_type_index;
     573       10375 :       ace_mask_type_entry_t *mte =
     574       10375 :         vec_elt_at_index (am->ace_mask_type_pool, mask_type_index);
     575       10375 :       pmatch = (u64 *) match;
     576       10375 :       pmask = (u64 *) & mte->mask;
     577       10375 :       pkey = (u64 *) kv.key;
     578             :       /*
     579             :        * unrolling the below loop results in a noticeable performance increase.
     580             :        int i;
     581             :        for(i=0; i<6; i++) {
     582             :        kv.key[i] = pmatch[i] & pmask[i];
     583             :        }
     584             :        */
     585             : 
     586       10375 :       *pkey++ = *pmatch++ & *pmask++;
     587       10375 :       *pkey++ = *pmatch++ & *pmask++;
     588       10375 :       *pkey++ = *pmatch++ & *pmask++;
     589       10375 :       *pkey++ = *pmatch++ & *pmask++;
     590       10375 :       *pkey++ = *pmatch++ & *pmask++;
     591       10375 :       *pkey++ = *pmatch++ & *pmask++;
     592             : 
     593             :       /*
     594             :        * The use of temporary variable convinces the compiler
     595             :        * to make a u64 write, avoiding the stall on crc32 operation
     596             :        * just a bit later.
     597             :        */
     598       10375 :       fa_packet_info_t tmp_pkt = kv_key->pkt;
     599       10375 :       tmp_pkt.mask_type_index_lsb = mask_type_index;
     600       10375 :       kv_key->pkt.as_u64 = tmp_pkt.as_u64;
     601             : 
     602             :       int res =
     603       10375 :         clib_bihash_search_inline_2_48_8 (&am->acl_lookup_hash, &kv, &result);
     604             : 
     605       10375 :       if (res == 0)
     606             :         {
     607             :           /* There is a hit in the hash, so check the collision vector */
     608       10085 :           u32 curr_index = result_val->applied_entry_index;
     609       10085 :           applied_hash_ace_entry_t *pae =
     610       10085 :             vec_elt_at_index ((*applied_hash_aces), curr_index);
     611       10085 :           collision_match_rule_t *crs = pae->colliding_rules;
     612             :           int i;
     613       20554 :           for (i = 0; i < vec_len (crs); i++)
     614             :             {
     615       10469 :               if (crs[i].applied_entry_index >= curr_match_index)
     616             :                 {
     617           0 :                   continue;
     618             :                 }
     619       10469 :               if (single_rule_match_5tuple (&crs[i].rule, is_ip6, match))
     620             :                 {
     621        9951 :                   curr_match_index = crs[i].applied_entry_index;
     622             :                 }
     623             :             }
     624             :         }
     625             :     }
     626             :   DBG ("MATCH-RESULT: %d", curr_match_index);
     627       10087 :   return curr_match_index;
     628             : }
     629             : 
     630             : always_inline int
     631       10087 : hash_multi_acl_match_5tuple (void *p_acl_main, u32 lc_index, fa_5tuple_t * pkt_5tuple,
     632             :                        int is_ip6, u8 *action, u32 *acl_pos_p, u32 * acl_match_p,
     633             :                        u32 * rule_match_p, u32 * trace_bitmap)
     634             : {
     635       10087 :   acl_main_t *am = p_acl_main;
     636       10087 :   applied_hash_ace_entry_t **applied_hash_aces = vec_elt_at_index(am->hash_entry_vec_by_lc_index, lc_index);
     637       10087 :   u32 match_index = multi_acl_match_get_applied_ace_index(am, is_ip6, pkt_5tuple);
     638       10087 :   if (match_index < vec_len((*applied_hash_aces))) {
     639        9951 :     applied_hash_ace_entry_t *pae = vec_elt_at_index((*applied_hash_aces), match_index);
     640        9951 :     pae->hitcount++;
     641        9951 :     *acl_pos_p = pae->acl_position;
     642        9951 :     *acl_match_p = pae->acl_index;
     643        9951 :     *rule_match_p = pae->ace_index;
     644        9951 :     *action = pae->action;
     645        9951 :     return 1;
     646             :   }
     647         136 :   return 0;
     648             : }
     649             : 
     650             : 
     651             : 
     652             : always_inline int
     653       10151 : acl_plugin_match_5tuple_inline (void *p_acl_main, u32 lc_index,
     654             :                                            fa_5tuple_opaque_t * pkt_5tuple,
     655             :                                            int is_ip6, u8 * r_action,
     656             :                                            u32 * r_acl_pos_p,
     657             :                                            u32 * r_acl_match_p,
     658             :                                            u32 * r_rule_match_p,
     659             :                                            u32 * trace_bitmap)
     660             : {
     661       10151 :   acl_main_t *am = p_acl_main;
     662       10151 :   fa_5tuple_t * pkt_5tuple_internal = (fa_5tuple_t *)pkt_5tuple;
     663       10151 :   pkt_5tuple_internal->pkt.lc_index = lc_index;
     664       10151 :   if (PREDICT_TRUE(am->use_hash_acl_matching)) {
     665       10151 :     if (PREDICT_FALSE(pkt_5tuple_internal->pkt.is_nonfirst_fragment)) {
     666             :       /*
     667             :        * tuplemerge does not take fragments into account,
     668             :        * and in general making fragments first class citizens has
     669             :        * proved more overhead than it's worth - so just fall back to linear
     670             :        * matching in that case.
     671             :        */
     672          64 :       return linear_multi_acl_match_5tuple(p_acl_main, lc_index, pkt_5tuple_internal, is_ip6, r_action,
     673             :                                  r_acl_pos_p, r_acl_match_p, r_rule_match_p, trace_bitmap);
     674             :     } else {
     675       10087 :       return hash_multi_acl_match_5tuple(p_acl_main, lc_index, pkt_5tuple_internal, is_ip6, r_action,
     676             :                                  r_acl_pos_p, r_acl_match_p, r_rule_match_p, trace_bitmap);
     677             :     }
     678             :   } else {
     679           0 :     return linear_multi_acl_match_5tuple(p_acl_main, lc_index, pkt_5tuple_internal, is_ip6, r_action,
     680             :                                  r_acl_pos_p, r_acl_match_p, r_rule_match_p, trace_bitmap);
     681             :   }
     682             : }
     683             : 
     684             : 
     685             : always_inline int
     686             : acl_plugin_match_5tuple_inline_and_count (void *p_acl_main, u32 lc_index,
     687             :                                            fa_5tuple_opaque_t * pkt_5tuple,
     688             :                                            int is_ip6, u8 * r_action,
     689             :                                            u32 * r_acl_pos_p,
     690             :                                            u32 * r_acl_match_p,
     691             :                                            u32 * r_rule_match_p,
     692             :                                            u32 * trace_bitmap,
     693             :                                            u32 packet_size)
     694             : {
     695             :   acl_main_t *am = p_acl_main;
     696             :   int ret = 0;
     697             :   fa_5tuple_t * pkt_5tuple_internal = (fa_5tuple_t *)pkt_5tuple;
     698             :   pkt_5tuple_internal->pkt.lc_index = lc_index;
     699             :   if (PREDICT_TRUE(am->use_hash_acl_matching)) {
     700             :     if (PREDICT_FALSE(pkt_5tuple_internal->pkt.is_nonfirst_fragment)) {
     701             :       /*
     702             :        * tuplemerge does not take fragments into account,
     703             :        * and in general making fragments first class citizens has
     704             :        * proved more overhead than it's worth - so just fall back to linear
     705             :        * matching in that case.
     706             :        */
     707             :       ret = linear_multi_acl_match_5tuple(p_acl_main, lc_index, pkt_5tuple_internal, is_ip6, r_action,
     708             :                                  r_acl_pos_p, r_acl_match_p, r_rule_match_p, trace_bitmap);
     709             :     } else {
     710             :       ret = hash_multi_acl_match_5tuple(p_acl_main, lc_index, pkt_5tuple_internal, is_ip6, r_action,
     711             :                                  r_acl_pos_p, r_acl_match_p, r_rule_match_p, trace_bitmap);
     712             :     }
     713             :   } else {
     714             :     ret = linear_multi_acl_match_5tuple(p_acl_main, lc_index, pkt_5tuple_internal, is_ip6, r_action,
     715             :                                  r_acl_pos_p, r_acl_match_p, r_rule_match_p, trace_bitmap);
     716             :   }
     717             :   if (PREDICT_TRUE(ret)) {
     718             :           u16 thread_index = os_get_thread_index ();
     719             :           vlib_increment_combined_counter(am->combined_acl_counters + *r_acl_match_p, thread_index, *r_rule_match_p, 1, packet_size);
     720             :   }
     721             :   return ret;
     722             : }
     723             : 
     724             : 
     725             : 
     726             : 
     727             : #endif

Generated by: LCOV version 1.14