acl-plugin: fallback to linear ACL search for fragments
[vpp.git] / src / plugins / acl / hash_lookup.c
index 9a28003..935ef26 100644 (file)
@@ -514,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
@@ -553,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));
@@ -566,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 */
@@ -686,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;
@@ -694,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.
@@ -779,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* */
 }