-static void *
-get_ptr_to_offset (vlib_buffer_t * b0, int offset)
-{
- u8 *p = vlib_buffer_get_current (b0) + offset;
- return p;
-}
-
-static u8
-acl_get_l4_proto (vlib_buffer_t * b0, int node_is_ip6)
-{
- u8 proto;
- int proto_offset;
- if (node_is_ip6)
- {
- proto_offset = 20;
- }
- else
- {
- proto_offset = 23;
- }
- proto = *((u8 *) vlib_buffer_get_current (b0) + proto_offset);
- return proto;
-}
-
-static int
-acl_match_addr (ip46_address_t * addr1, ip46_address_t * addr2, int prefixlen,
- int is_ip6)
-{
- if (prefixlen == 0)
- {
- /* match any always succeeds */
- return 1;
- }
- if (is_ip6)
- {
- if (memcmp (addr1, addr2, prefixlen / 8))
- {
- /* If the starting full bytes do not match, no point in bittwidling the thumbs further */
- return 0;
- }
- if (prefixlen % 8)
- {
- u8 b1 = *((u8 *) addr1 + 1 + prefixlen / 8);
- u8 b2 = *((u8 *) addr2 + 1 + prefixlen / 8);
- u8 mask0 = (0xff - ((1 << (8 - (prefixlen % 8))) - 1));
- return (b1 & mask0) == b2;
- }
- else
- {
- /* The prefix fits into integer number of bytes, so nothing left to do */
- return 1;
- }
- }
- else
- {
- uint32_t a1 = ntohl (addr1->ip4.as_u32);
- uint32_t a2 = ntohl (addr2->ip4.as_u32);
- uint32_t mask0 = 0xffffffff - ((1 << (32 - prefixlen)) - 1);
- return (a1 & mask0) == a2;
- }
-}
-
-static int
-acl_match_port (u16 port, u16 port_first, u16 port_last, int is_ip6)
-{
- return ((port >= port_first) && (port <= port_last));
-}
-
-static int
-acl_packet_match (acl_main_t * am, u32 acl_index, vlib_buffer_t * b0,
- u8 * r_action, int *r_is_ip6, u32 * r_acl_match_p,
- u32 * r_rule_match_p, u32 * trace_bitmap)
-{
- ethernet_header_t *h0;
- u16 type0;
-
- ip46_address_t src, dst;
- int is_ip6;
- int is_ip4;
- u8 proto;
- u16 src_port = 0;
- u16 dst_port = 0;
- u8 tcp_flags = 0;
- int i;
- acl_list_t *a;
- acl_rule_t *r;
-
- h0 = vlib_buffer_get_current (b0);
- type0 = clib_net_to_host_u16 (h0->type);
- is_ip4 = (type0 == ETHERNET_TYPE_IP4);
- is_ip6 = (type0 == ETHERNET_TYPE_IP6);
-
- if (!(is_ip4 || is_ip6))
- {
- return 0;
- }
- /* The bunch of hardcoded offsets here is intentional to get rid of them
- ASAP, when getting to a faster matching code */
- if (is_ip4)
- {
- clib_memcpy (&src.ip4, get_ptr_to_offset (b0, 26), 4);
- clib_memcpy (&dst.ip4, get_ptr_to_offset (b0, 30), 4);
- proto = acl_get_l4_proto (b0, 0);
- if (1 == proto)
- {
- *trace_bitmap |= 0x00000001;
- /* type */
- src_port = ((u16) (*(u8 *) get_ptr_to_offset (b0, 34)));
- /* code */
- dst_port = ((u16) (*(u8 *) get_ptr_to_offset (b0, 35)));
- } else {
- /* assume TCP/UDP */
- src_port = ntohs ((u16) (*(u16 *) get_ptr_to_offset (b0, 34)));
- dst_port = ntohs ((u16) (*(u16 *) get_ptr_to_offset (b0, 36)));
- /* UDP gets ability to check on an oddball data byte as a bonus */
- tcp_flags = *(u8 *) get_ptr_to_offset (b0, 14 + 20 + 13);
- }
- }
- else /* is_ipv6 implicitly */
- {
- clib_memcpy (&src, get_ptr_to_offset (b0, 22), 16);
- clib_memcpy (&dst, get_ptr_to_offset (b0, 38), 16);
- proto = acl_get_l4_proto (b0, 1);
- if (58 == proto)
- {
- *trace_bitmap |= 0x00000002;
- /* type */
- src_port = (u16) (*(u8 *) get_ptr_to_offset (b0, 54));
- /* code */
- dst_port = (u16) (*(u8 *) get_ptr_to_offset (b0, 55));
- }
- else
- {
- /* assume TCP/UDP */
- src_port = ntohs ((u16) (*(u16 *) get_ptr_to_offset (b0, 54)));
- dst_port = ntohs ((u16) (*(u16 *) get_ptr_to_offset (b0, 56)));
- tcp_flags = *(u8 *) get_ptr_to_offset (b0, 14 + 40 + 13);
- }
- }
- if (pool_is_free_index (am->acls, acl_index))
- {
- if (r_acl_match_p)
- *r_acl_match_p = acl_index;
- if (r_rule_match_p)
- *r_rule_match_p = -1;
- /* the ACL does not exist but is used for policy. Block traffic. */
- return 0;
- }
- a = am->acls + acl_index;
- for (i = 0; i < a->count; i++)
- {
- r = a->rules + i;
- if (is_ip6 != r->is_ipv6)
- {
- continue;
- }
- if (!acl_match_addr (&dst, &r->dst, r->dst_prefixlen, is_ip6))
- continue;
- if (!acl_match_addr (&src, &r->src, r->src_prefixlen, is_ip6))
- continue;
- if (r->proto)
- {
- if (proto != r->proto)
- continue;
- if (!acl_match_port
- (src_port, r->src_port_or_type_first, r->src_port_or_type_last,
- is_ip6))
- continue;
- if (!acl_match_port
- (dst_port, r->dst_port_or_code_first, r->dst_port_or_code_last,
- is_ip6))
- continue;
- /* No need for check of proto == TCP, since in other rules both fields should be zero, so this match will succeed */
- if ((tcp_flags & r->tcp_flags_mask) != r->tcp_flags_value)
- continue;
- }
- /* everything matches! */
- *r_action = r->is_permit;
- *r_is_ip6 = is_ip6;
- if (r_acl_match_p)
- *r_acl_match_p = acl_index;
- if (r_rule_match_p)
- *r_rule_match_p = i;
- return 1;
- }
- return 0;
-}
-
-void
-input_acl_packet_match (u32 sw_if_index, vlib_buffer_t * b0, u32 * nextp,
- u32 * acl_match_p, u32 * rule_match_p,
- u32 * trace_bitmap)
-{
- acl_main_t *am = &acl_main;
- uint8_t action = 0;
- int is_ip6 = 0;
- int i;
- vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
- for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
- i++)
- {
- if (acl_packet_match
- (am, am->input_acl_vec_by_sw_if_index[sw_if_index][i], b0, &action,
- &is_ip6, acl_match_p, rule_match_p, trace_bitmap))
- {
- if (is_ip6)
- {
- *nextp = am->acl_in_ip6_match_next[action];
- }
- else
- {
- *nextp = am->acl_in_ip4_match_next[action];
- }
- return;
- }
- }
- if (vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]) > 0)
- {
- /* If there are ACLs and none matched, deny by default */
- *nextp = 0;
- }
-
-}
-
-void
-output_acl_packet_match (u32 sw_if_index, vlib_buffer_t * b0, u32 * nextp,
- u32 * acl_match_p, u32 * rule_match_p,
- u32 * trace_bitmap)
-{
- acl_main_t *am = &acl_main;
- uint8_t action = 0;
- int is_ip6 = 0;
- int i;
- vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
- for (i = 0; i < vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]);
- i++)
- {
- if (acl_packet_match
- (am, am->output_acl_vec_by_sw_if_index[sw_if_index][i], b0, &action,
- &is_ip6, acl_match_p, rule_match_p, trace_bitmap))
- {
- if (is_ip6)
- {
- *nextp = am->acl_out_ip6_match_next[action];
- }
- else
- {
- *nextp = am->acl_out_ip4_match_next[action];
- }
- return;
- }
- }
- if (vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]) > 0)
- {
- /* If there are ACLs and none matched, deny by default */
- *nextp = 0;
- }
-}
-