acl-plugin: split (L3) and (L4/pkt) logic of creation of 5tuple structure, optimize...
[vpp.git] / src / plugins / acl / public_inlines.h
index a2b8fc9..b358f64 100644 (file)
@@ -182,43 +182,46 @@ offset_within_packet (vlib_buffer_t * b0, int offset)
   return (offset <= (b0->current_length - 8));
 }
 
+
 always_inline void
-acl_fill_5tuple (acl_main_t * am, vlib_buffer_t * b0, int is_ip6,
-                int is_input, int is_l2_path, fa_5tuple_t * p5tuple_pkt)
+acl_fill_5tuple_l3_data (acl_main_t * am, vlib_buffer_t * b0, int is_ip6,
+                int l3_offset, fa_5tuple_t * p5tuple_pkt)
 {
-  /* IP4 and IP6 protocol numbers of ICMP */
-  static u8 icmp_protos_v4v6[] = { IP_PROTOCOL_ICMP, IP_PROTOCOL_ICMP6 };
-
-  int l3_offset;
-  int l4_offset;
-  u16 ports[2];
-  u16 proto;
-
-  if (is_l2_path)
+  if (is_ip6)
     {
-      l3_offset = ethernet_buffer_header_size(b0);
+      clib_memcpy (&p5tuple_pkt->ip6_addr,
+                  get_ptr_to_offset (b0,
+                                     offsetof (ip6_header_t,
+                                               src_address) + l3_offset),
+                  sizeof (p5tuple_pkt->ip6_addr));
     }
   else
     {
-      if (is_input)
-        l3_offset = 0;
-      else
-        l3_offset = vnet_buffer(b0)->ip.save_rewrite_length;
+      memset(p5tuple_pkt->l3_zero_pad, 0, sizeof(p5tuple_pkt->l3_zero_pad));
+      clib_memcpy (&p5tuple_pkt->ip4_addr,
+                  get_ptr_to_offset (b0,
+                                     offsetof (ip4_header_t,
+                                               src_address) + l3_offset),
+                  sizeof (p5tuple_pkt->ip4_addr));
     }
+}
 
-  /* key[0..3] contains src/dst address and is cleared/set below */
-  /* Remainder of the key and per-packet non-key data */
-  p5tuple_pkt->kv.key[4] = 0;
-  p5tuple_pkt->kv.value = 0;
-  p5tuple_pkt->pkt.is_ip6 = is_ip6;
+always_inline void
+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,
+                int l3_offset, fa_session_l4_key_t *p5tuple_l4, fa_packet_info_t *p5tuple_pkt)
+{
+  /* IP4 and IP6 protocol numbers of ICMP */
+  static u8 icmp_protos_v4v6[] = { IP_PROTOCOL_ICMP, IP_PROTOCOL_ICMP6 };
+
+  int l4_offset;
+  u16 ports[2];
+  u8 proto;
+
+  fa_session_l4_key_t tmp_l4 = { .lsb_of_sw_if_index = sw_if_index0 & 0xffff };
+  fa_packet_info_t tmp_pkt = { .is_ip6 = is_ip6, .mask_type_index_lsb = ~0 };
 
   if (is_ip6)
     {
-      clib_memcpy (&p5tuple_pkt->addr,
-                  get_ptr_to_offset (b0,
-                                     offsetof (ip6_header_t,
-                                               src_address) + l3_offset),
-                  sizeof (p5tuple_pkt->addr));
       proto =
        *(u8 *) get_ptr_to_offset (b0,
                                   offsetof (ip6_header_t,
@@ -243,7 +246,7 @@ acl_fill_5tuple (acl_main_t * am, vlib_buffer_t * b0, int is_ip6,
                  frag_offset = clib_net_to_host_u16(frag_offset) >> 3;
                  if (frag_offset)
                    {
-                      p5tuple_pkt->pkt.is_nonfirst_fragment = 1;
+                      tmp_pkt.is_nonfirst_fragment = 1;
                       /* invalidate L4 offset so we don't try to find L4 info */
                       l4_offset += b0->current_length;
                    }
@@ -270,20 +273,6 @@ acl_fill_5tuple (acl_main_t * am, vlib_buffer_t * b0, int is_ip6,
     }
   else
     {
-      p5tuple_pkt->kv.key[0] = 0;
-      p5tuple_pkt->kv.key[1] = 0;
-      p5tuple_pkt->kv.key[2] = 0;
-      p5tuple_pkt->kv.key[3] = 0;
-      clib_memcpy (&p5tuple_pkt->addr[0].ip4,
-                  get_ptr_to_offset (b0,
-                                     offsetof (ip4_header_t,
-                                               src_address) + l3_offset),
-                  sizeof (p5tuple_pkt->addr[0].ip4));
-      clib_memcpy (&p5tuple_pkt->addr[1].ip4,
-                  get_ptr_to_offset (b0,
-                                     offsetof (ip4_header_t,
-                                               dst_address) + l3_offset),
-                  sizeof (p5tuple_pkt->addr[1].ip4));
       proto =
        *(u8 *) get_ptr_to_offset (b0,
                                   offsetof (ip4_header_t,
@@ -300,28 +289,31 @@ acl_fill_5tuple (acl_main_t * am, vlib_buffer_t * b0, int is_ip6,
       /* non-initial fragments have non-zero offset */
       if ((PREDICT_FALSE(0xfff & flags_and_fragment_offset)))
         {
-          p5tuple_pkt->pkt.is_nonfirst_fragment = 1;
+          tmp_pkt.is_nonfirst_fragment = 1;
           /* invalidate L4 offset so we don't try to find L4 info */
           l4_offset += b0->current_length;
         }
 
     }
-  p5tuple_pkt->l4.proto = proto;
+  tmp_l4.proto = proto;
+  tmp_l4.is_input = is_input;
+
   if (PREDICT_TRUE (offset_within_packet (b0, l4_offset)))
     {
-      p5tuple_pkt->pkt.l4_valid = 1;
+      tmp_pkt.l4_valid = 1;
       if (icmp_protos_v4v6[is_ip6] == proto)
        {
          /* type */
-         p5tuple_pkt->l4.port[0] =
+         tmp_l4.port[0] =
            *(u8 *) get_ptr_to_offset (b0,
                                       l4_offset + offsetof (icmp46_header_t,
                                                             type));
          /* code */
-         p5tuple_pkt->l4.port[1] =
+         tmp_l4.port[1] =
            *(u8 *) get_ptr_to_offset (b0,
                                       l4_offset + offsetof (icmp46_header_t,
                                                             code));
+          tmp_l4.is_slowpath = 1;
        }
       else if ((IP_PROTOCOL_TCP == proto) || (IP_PROTOCOL_UDP == proto))
        {
@@ -330,30 +322,48 @@ acl_fill_5tuple (acl_main_t * am, vlib_buffer_t * b0, int is_ip6,
                                          l4_offset + offsetof (tcp_header_t,
                                                                src_port)),
                       sizeof (ports));
-         p5tuple_pkt->l4.port[0] = clib_net_to_host_u16 (ports[0]);
-         p5tuple_pkt->l4.port[1] = clib_net_to_host_u16 (ports[1]);
+         tmp_l4.port[0] = clib_net_to_host_u16 (ports[0]);
+         tmp_l4.port[1] = clib_net_to_host_u16 (ports[1]);
 
-         p5tuple_pkt->pkt.tcp_flags =
+         tmp_pkt.tcp_flags =
            *(u8 *) get_ptr_to_offset (b0,
                                       l4_offset + offsetof (tcp_header_t,
                                                             flags));
-         p5tuple_pkt->pkt.tcp_flags_valid = (proto == IP_PROTOCOL_TCP);
+         tmp_pkt.tcp_flags_valid = (proto == IP_PROTOCOL_TCP);
+          tmp_l4.is_slowpath = 0;
        }
-      /*
-       * FIXME: rather than the above conditional, here could
-       * be a nice generic mechanism to extract two L4 values:
-       *
-       * have a per-protocol array of 4 elements like this:
-       *   u8 offset; to take the byte from, off L4 header
-       *   u8 mask; to mask it with, before storing
-       *
-       * this way we can describe UDP, TCP and ICMP[46] semantics,
-       * and add a sort of FPM-type behavior for other protocols.
-       *
-       * Of course, is it faster ? and is it needed ?
-       *
-       */
+      else
+        {
+          tmp_l4.is_slowpath = 1;
+        }
     }
+
+  p5tuple_pkt->as_u64 = tmp_pkt.as_u64;
+  p5tuple_l4->as_u64 = tmp_l4.as_u64;
+}
+
+always_inline void
+acl_fill_5tuple (acl_main_t * am, u32 sw_if_index0, vlib_buffer_t * b0, int is_ip6,
+                int is_input, int is_l2_path, fa_5tuple_t * p5tuple_pkt)
+{
+  int l3_offset;
+
+  if (is_l2_path)
+    {
+      l3_offset = ethernet_buffer_header_size(b0);
+    }
+  else
+    {
+      if (is_input)
+        l3_offset = 0;
+      else
+        l3_offset = vnet_buffer(b0)->ip.save_rewrite_length;
+    }
+
+  /* key[0..3] contains src/dst address and is cleared/set below */
+  /* Remainder of the key and per-packet non-key data */
+  acl_fill_5tuple_l3_data(am, b0, is_ip6, l3_offset, p5tuple_pkt);
+  acl_fill_5tuple_l4_and_pkt_data(am, sw_if_index0, b0, is_ip6, is_input, l3_offset, &p5tuple_pkt->l4, &p5tuple_pkt->pkt);
 }
 
 always_inline void
@@ -361,22 +371,35 @@ acl_plugin_fill_5tuple_inline (u32 lc_index, vlib_buffer_t * b0, int is_ip6,
                 int is_input, int is_l2_path, fa_5tuple_opaque_t * p5tuple_pkt)
 {
   acl_main_t *am = p_acl_main;
-  acl_fill_5tuple(am, b0, is_ip6, is_input, is_l2_path, (fa_5tuple_t *)p5tuple_pkt);
+  acl_fill_5tuple(am, 0, b0, is_ip6, is_input, is_l2_path, (fa_5tuple_t *)p5tuple_pkt);
 }
 
 
 
 always_inline int
-fa_acl_match_addr (ip46_address_t * addr1, ip46_address_t * addr2,
-                  int prefixlen, int is_ip6)
+fa_acl_match_ip4_addr (ip4_address_t * addr1, ip4_address_t * addr2,
+                  int prefixlen)
 {
   if (prefixlen == 0)
     {
       /* match any always succeeds */
       return 1;
     }
-  if (is_ip6)
+      uint32_t a1 = clib_net_to_host_u32 (addr1->as_u32);
+      uint32_t a2 = clib_net_to_host_u32 (addr2->as_u32);
+      uint32_t mask0 = 0xffffffff - ((1 << (32 - prefixlen)) - 1);
+      return (a1 & mask0) == a2;
+}
+
+always_inline int
+fa_acl_match_ip6_addr (ip6_address_t * addr1, ip6_address_t * addr2,
+                  int prefixlen)
+{
+  if (prefixlen == 0)
     {
+      /* match any always succeeds */
+      return 1;
+    }
       if (memcmp (addr1, addr2, prefixlen / 8))
        {
          /* If the starting full bytes do not match, no point in bittwidling the thumbs further */
@@ -394,14 +417,6 @@ fa_acl_match_addr (ip46_address_t * addr1, ip46_address_t * addr2,
          /* The prefix fits into integer number of bytes, so nothing left to do */
          return 1;
        }
-    }
-  else
-    {
-      uint32_t a1 = clib_net_to_host_u32 (addr1->ip4.as_u32);
-      uint32_t a2 = clib_net_to_host_u32 (addr2->ip4.as_u32);
-      uint32_t mask0 = 0xffffffff - ((1 << (32 - prefixlen)) - 1);
-      return (a1 & mask0) == a2;
-    }
 }
 
 always_inline int
@@ -432,41 +447,26 @@ single_acl_match_5tuple (acl_main_t * am, u32 acl_index, fa_5tuple_t * pkt_5tupl
   for (i = 0; i < a->count; i++)
     {
       r = a->rules + i;
-#ifdef FA_NODE_VERBOSE_DEBUG
-      clib_warning("ACL_FA_NODE_DBG acl %d rule %d tag %s", acl_index, i, a->tag);
-#endif
       if (is_ip6 != r->is_ipv6)
        {
          continue;
        }
-      if (!fa_acl_match_addr
-         (&pkt_5tuple->addr[1], &r->dst, r->dst_prefixlen, is_ip6))
+      if (is_ip6) {
+        if (!fa_acl_match_ip6_addr
+         (&pkt_5tuple->ip6_addr[1], &r->dst.ip6, r->dst_prefixlen))
        continue;
-
-#ifdef FA_NODE_VERBOSE_DEBUG
-      clib_warning
-       ("ACL_FA_NODE_DBG acl %d rule %d pkt dst addr %U match rule addr %U/%d",
-        acl_index, i, format_ip46_address, &pkt_5tuple->addr[1],
-        r->is_ipv6 ? IP46_TYPE_IP6: IP46_TYPE_IP4, format_ip46_address,
-         &r->dst, r->is_ipv6 ? IP46_TYPE_IP6: IP46_TYPE_IP4,
-        r->dst_prefixlen);
-#endif
-
-      if (!fa_acl_match_addr
-         (&pkt_5tuple->addr[0], &r->src, r->src_prefixlen, is_ip6))
+        if (!fa_acl_match_ip6_addr
+         (&pkt_5tuple->ip6_addr[0], &r->src.ip6, r->src_prefixlen))
        continue;
+      } else {
+        if (!fa_acl_match_ip4_addr
+         (&pkt_5tuple->ip4_addr[1], &r->dst.ip4, r->dst_prefixlen))
+       continue;
+        if (!fa_acl_match_ip4_addr
+         (&pkt_5tuple->ip4_addr[0], &r->src.ip4, r->src_prefixlen))
+       continue;
+      }
 
-#ifdef FA_NODE_VERBOSE_DEBUG
-      clib_warning
-       ("ACL_FA_NODE_DBG acl %d rule %d pkt src addr %U match rule addr %U/%d",
-        acl_index, i, format_ip46_address, &pkt_5tuple->addr[0],
-        r->is_ipv6 ? IP46_TYPE_IP6: IP46_TYPE_IP4, format_ip46_address,
-         &r->src, r->is_ipv6 ? IP46_TYPE_IP6: IP46_TYPE_IP4,
-        r->src_prefixlen);
-      clib_warning
-       ("ACL_FA_NODE_DBG acl %d rule %d trying to match pkt proto %d with rule %d",
-        acl_index, i, pkt_5tuple->l4.proto, r->proto);
-#endif
       if (r->proto)
        {
          if (pkt_5tuple->l4.proto != r->proto)