acl-plugin: fallback to linear ACL search for fragments
[vpp.git] / src / plugins / acl / hash_lookup.c
index ad55054..935ef26 100644 (file)
@@ -154,6 +154,9 @@ hash_acl_set_heap(acl_main_t *am)
 {
   if (0 == am->hash_lookup_mheap) {
     am->hash_lookup_mheap = mheap_alloc (0 /* use VM */ , am->hash_lookup_mheap_size);
+    if (0 == am->hash_lookup_mheap) {
+      clib_error("ACL plugin failed to allocate hash lookup heap of %U bytes, abort", format_memory_size, am->hash_lookup_mheap_size);
+    }
     mheap_t *h = mheap_header (am->hash_lookup_mheap);
     h->flags |= MHEAP_FLAG_THREAD_SAFE;
   }
@@ -511,15 +514,33 @@ hash_acl_reapply(acl_main_t *am, u32 lc_index, int acl_index)
 }
 
 static void
-make_address_mask(ip46_address_t *addr, u8 is_ipv6, u8 prefix_len)
+make_ip6_address_mask(ip6_address_t *addr, u8 prefix_len)
 {
-  if (is_ipv6) {
-    ip6_address_mask_from_width(&addr->ip6, prefix_len);
-  } else {
-    /* FIXME: this may not be correct way */
-    ip6_address_mask_from_width(&addr->ip6, prefix_len + 3*32);
-    ip46_address_mask_ip4(addr);
-  }
+  ip6_address_mask_from_width(addr, prefix_len);
+}
+
+
+/* Maybe should be moved into the core somewhere */
+always_inline void
+ip4_address_mask_from_width (ip4_address_t * a, u32 width)
+{
+  int i, byte, bit, bitnum;
+  ASSERT (width <= 32);
+  memset (a, 0, sizeof (a[0]));
+  for (i = 0; i < width; i++)
+    {
+      bitnum = (7 - (i & 7));
+      byte = i / 8;
+      bit = 1 << bitnum;
+      a->as_u8[byte] |= bit;
+    }
+}
+
+
+static void
+make_ip4_address_mask(ip4_address_t *addr, u8 prefix_len)
+{
+  ip4_address_mask_from_width(addr, prefix_len);
 }
 
 static u8
@@ -550,7 +571,7 @@ make_port_mask(u16 *portmask, u16 port_first, u16 port_last)
 }
 
 static void
-make_mask_and_match_from_rule(fa_5tuple_t *mask, acl_rule_t *r, hash_ace_info_t *hi, int match_nonfirst_fragment)
+make_mask_and_match_from_rule(fa_5tuple_t *mask, acl_rule_t *r, hash_ace_info_t *hi)
 {
   memset(mask, 0, sizeof(*mask));
   memset(&hi->match, 0, sizeof(hi->match));
@@ -563,39 +584,41 @@ make_mask_and_match_from_rule(fa_5tuple_t *mask, acl_rule_t *r, hash_ace_info_t
 
   mask->pkt.is_ip6 = 1;
   hi->match.pkt.is_ip6 = r->is_ipv6;
-
-  make_address_mask(&mask->addr[0], r->is_ipv6, r->src_prefixlen);
-  hi->match.addr[0] = r->src;
-  make_address_mask(&mask->addr[1], r->is_ipv6, r->dst_prefixlen);
-  hi->match.addr[1] = r->dst;
+  if (r->is_ipv6) {
+    make_ip6_address_mask(&mask->ip6_addr[0], r->src_prefixlen);
+    hi->match.ip6_addr[0] = r->src.ip6;
+    make_ip6_address_mask(&mask->ip6_addr[1], r->dst_prefixlen);
+    hi->match.ip6_addr[1] = r->dst.ip6;
+  } else {
+    memset(hi->match.l3_zero_pad, 0, sizeof(hi->match.l3_zero_pad));
+    make_ip4_address_mask(&mask->ip4_addr[0], r->src_prefixlen);
+    hi->match.ip4_addr[0] = r->src.ip4;
+    make_ip4_address_mask(&mask->ip4_addr[1], r->dst_prefixlen);
+    hi->match.ip4_addr[1] = r->dst.ip4;
+  }
 
   if (r->proto != 0) {
     mask->l4.proto = ~0; /* L4 proto needs to be matched */
     hi->match.l4.proto = r->proto;
-    if (match_nonfirst_fragment) {
-      /* match the non-first fragments only */
-      mask->pkt.is_nonfirst_fragment = 1;
-      hi->match.pkt.is_nonfirst_fragment = 1;
-    } else {
-      /* Calculate the src/dst port masks and make the src/dst port matches accordingly */
-      hi->src_portrange_not_powerof2 = make_port_mask(&mask->l4.port[0], r->src_port_or_type_first, r->src_port_or_type_last);
-      hi->match.l4.port[0] = r->src_port_or_type_first & mask->l4.port[0];
-      hi->dst_portrange_not_powerof2 = make_port_mask(&mask->l4.port[1], r->dst_port_or_code_first, r->dst_port_or_code_last);
-      hi->match.l4.port[1] = r->dst_port_or_code_first & mask->l4.port[1];
-      /* L4 info must be valid in order to match */
-      mask->pkt.l4_valid = 1;
-      hi->match.pkt.l4_valid = 1;
-      /* And we must set the mask to check that it is an initial fragment */
-      mask->pkt.is_nonfirst_fragment = 1;
-      hi->match.pkt.is_nonfirst_fragment = 0;
-      if ((r->proto == IPPROTO_TCP) && (r->tcp_flags_mask != 0)) {
-       /* if we want to match on TCP flags, they must be masked off as well */
-       mask->pkt.tcp_flags = r->tcp_flags_mask;
-       hi->match.pkt.tcp_flags = r->tcp_flags_value;
-       /* and the flags need to be present within the packet being matched */
-       mask->pkt.tcp_flags_valid = 1;
-       hi->match.pkt.tcp_flags_valid = 1;
-      }
+
+    /* Calculate the src/dst port masks and make the src/dst port matches accordingly */
+    hi->src_portrange_not_powerof2 = make_port_mask(&mask->l4.port[0], r->src_port_or_type_first, r->src_port_or_type_last);
+    hi->match.l4.port[0] = r->src_port_or_type_first & mask->l4.port[0];
+    hi->dst_portrange_not_powerof2 = make_port_mask(&mask->l4.port[1], r->dst_port_or_code_first, r->dst_port_or_code_last);
+    hi->match.l4.port[1] = r->dst_port_or_code_first & mask->l4.port[1];
+    /* L4 info must be valid in order to match */
+    mask->pkt.l4_valid = 1;
+    hi->match.pkt.l4_valid = 1;
+    /* And we must set the mask to check that it is an initial fragment */
+    mask->pkt.is_nonfirst_fragment = 1;
+    hi->match.pkt.is_nonfirst_fragment = 0;
+    if ((r->proto == IPPROTO_TCP) && (r->tcp_flags_mask != 0)) {
+      /* if we want to match on TCP flags, they must be masked off as well */
+      mask->pkt.tcp_flags = r->tcp_flags_mask;
+      hi->match.pkt.tcp_flags = r->tcp_flags_value;
+      /* and the flags need to be present within the packet being matched */
+      mask->pkt.tcp_flags_valid = 1;
+      hi->match.pkt.tcp_flags_valid = 1;
     }
   }
   /* Sanitize the mask and the match */
@@ -683,7 +706,7 @@ void hash_acl_add(acl_main_t *am, int acl_index)
     ace_info.acl_index = acl_index;
     ace_info.ace_index = i;
 
-    make_mask_and_match_from_rule(&mask, &a->rules[i], &ace_info, 0);
+    make_mask_and_match_from_rule(&mask, &a->rules[i], &ace_info);
     ace_info.mask_type_index = assign_mask_type_index(am, &mask);
     /* assign the mask type index for matching itself */
     ace_info.match.pkt.mask_type_index_lsb = ace_info.mask_type_index;
@@ -691,16 +714,6 @@ void hash_acl_add(acl_main_t *am, int acl_index)
     /* Ensure a given index is set in the mask type index bitmap for this ACL */
     ha->mask_type_index_bitmap = clib_bitmap_set(ha->mask_type_index_bitmap, ace_info.mask_type_index, 1);
     vec_add1(ha->rules, ace_info);
-    if (am->l4_match_nonfirst_fragment) {
-      /* add the second rule which matches the noninitial fragments with the respective mask */
-      make_mask_and_match_from_rule(&mask, &a->rules[i], &ace_info, 1);
-      ace_info.mask_type_index = assign_mask_type_index(am, &mask);
-      ace_info.match.pkt.mask_type_index_lsb = ace_info.mask_type_index;
-      DBG("ACE: %d (non-initial frags) mask_type_index: %d", i, ace_info.mask_type_index);
-      /* Ensure a given index is set in the mask type index bitmap for this ACL */
-      ha->mask_type_index_bitmap = clib_bitmap_set(ha->mask_type_index_bitmap, ace_info.mask_type_index, 1);
-      vec_add1(ha->rules, ace_info);
-    }
   }
   /*
    * if an ACL is applied somewhere, fill the corresponding lookup data structures.
@@ -776,8 +789,8 @@ acl_plugin_show_tables_mask_type (void)
     ({
       vlib_cli_output(vm, "     %3d: %016llx %016llx %016llx %016llx %016llx %016llx  refcount %d",
                    mte - am->ace_mask_type_pool,
-                   mte->mask.kv.key[0], mte->mask.kv.key[1], mte->mask.kv.key[2],
-                   mte->mask.kv.key[3], mte->mask.kv.key[4], mte->mask.kv.value, mte->refcount);
+                   mte->mask.kv_40_8.key[0], mte->mask.kv_40_8.key[1], mte->mask.kv_40_8.key[2],
+                   mte->mask.kv_40_8.key[3], mte->mask.kv_40_8.key[4], mte->mask.kv_40_8.value, mte->refcount);
     }));
     /* *INDENT-ON* */
 }
@@ -828,67 +841,42 @@ acl_plugin_print_pae (vlib_main_t * vm, int j, applied_hash_ace_entry_t * pae)
 }
 
 void
-acl_plugin_show_tables_applied_info (u32 sw_if_index)
+acl_plugin_show_tables_applied_info (u32 lc_index)
 {
   acl_main_t *am = &acl_main;
   vlib_main_t *vm = am->vlib_main;
-  u32 swi; //, j;
-  vlib_cli_output (vm, "Applied lookup entries for interfaces");
+  u32 lci, j;
+  vlib_cli_output (vm, "Applied lookup entries for lookup contexts");
 
-  for (swi = 0;
-       (swi < vec_len (am->input_lc_index_by_sw_if_index))
-       || (swi < vec_len (am->output_lc_index_by_sw_if_index)); swi++)
+  for (lci = 0;
+       (lci < vec_len(am->applied_hash_acl_info_by_lc_index)); lci++)
     {
-      if ((sw_if_index != ~0) && (sw_if_index != swi))
+      if ((lc_index != ~0) && (lc_index != lci))
        {
          continue;
        }
-/*
-      vlib_cli_output (vm, "sw_if_index %d:", swi);
-      if (swi < vec_len (am->input_applied_hash_acl_info_by_sw_if_index))
+      vlib_cli_output (vm, "lc_index %d:", lci);
+      if (lci < vec_len (am->applied_hash_acl_info_by_lc_index))
        {
          applied_hash_acl_info_t *pal =
-           &am->input_applied_hash_acl_info_by_sw_if_index[swi];
-         vlib_cli_output (vm, "  input lookup mask_type_index_bitmap: %U",
+           &am->applied_hash_acl_info_by_lc_index[lci];
+         vlib_cli_output (vm, "  lookup mask_type_index_bitmap: %U",
                           format_bitmap_hex, pal->mask_type_index_bitmap);
-         vlib_cli_output (vm, "  input applied acls: %U", format_vec32,
+         vlib_cli_output (vm, "  applied acls: %U", format_vec32,
                           pal->applied_acls, "%d");
        }
-      if (swi < vec_len (am->input_hash_entry_vec_by_sw_if_index))
+      if (lci < vec_len (am->hash_entry_vec_by_lc_index))
        {
-         vlib_cli_output (vm, "  input lookup applied entries:");
+         vlib_cli_output (vm, "  lookup applied entries:");
          for (j = 0;
-              j < vec_len (am->input_hash_entry_vec_by_sw_if_index[swi]);
+              j < vec_len (am->hash_entry_vec_by_lc_index[lci]);
               j++)
            {
              acl_plugin_print_pae (vm, j,
-                                   &am->input_hash_entry_vec_by_sw_if_index
-                                   [swi][j]);
+                                   &am->hash_entry_vec_by_lc_index
+                                   [lci][j]);
            }
        }
-
-      if (swi < vec_len (am->output_applied_hash_acl_info_by_sw_if_index))
-       {
-         applied_hash_acl_info_t *pal =
-           &am->output_applied_hash_acl_info_by_sw_if_index[swi];
-         vlib_cli_output (vm, "  output lookup mask_type_index_bitmap: %U",
-                          format_bitmap_hex, pal->mask_type_index_bitmap);
-         vlib_cli_output (vm, "  output applied acls: %U", format_vec32,
-                          pal->applied_acls, "%d");
-       }
-      if (swi < vec_len (am->output_hash_entry_vec_by_sw_if_index))
-       {
-         vlib_cli_output (vm, "  output lookup applied entries:");
-         for (j = 0;
-              j < vec_len (am->output_hash_entry_vec_by_sw_if_index[swi]);
-              j++)
-           {
-             acl_plugin_print_pae (vm, j,
-                                   &am->output_hash_entry_vec_by_sw_if_index
-                                   [swi][j]);
-           }
-       }
-*/
     }
 }