From 8a4e9e534fcb1ef718ed5c1089fdc8698b13fb7f Mon Sep 17 00:00:00 2001 From: Bindya Narayan Date: Tue, 18 Apr 2017 12:13:10 +0530 Subject: vACL VNF initial check-in JIRA: SAMPLEVNF-2 Features include: - CLI based Run-time rule configuration. (Add, Delete, List, Display, Clear, Modify) - Ipv4 and ipv6 standard 5 tuple packet Selector support. - Multithread support - Multiple physical port support Change-Id: Ie266be23cd2d81f6d01df508ba44bd0998be13b3 Signed-off-by: Bindya Narayan [Push patch to gerrit] Signed-off-by: Deepak S --- VNFs/vACL/pipeline/pipeline_acl_be.c | 3639 ++++++++++++++++++++++++++++++++++ 1 file changed, 3639 insertions(+) create mode 100644 VNFs/vACL/pipeline/pipeline_acl_be.c (limited to 'VNFs/vACL/pipeline/pipeline_acl_be.c') diff --git a/VNFs/vACL/pipeline/pipeline_acl_be.c b/VNFs/vACL/pipeline/pipeline_acl_be.c new file mode 100644 index 00000000..039d6d59 --- /dev/null +++ b/VNFs/vACL/pipeline/pipeline_acl_be.c @@ -0,0 +1,3639 @@ +/* +// Copyright (c) 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +/** + * @file + * Pipeline ACL BE Implementation. + * + * Implementation of Pipeline ACL Back End (BE). + * Responsible for packet processing. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pipeline_arpicmp_be.h" +#include "vnf_common.h" +#include "pipeline_common_be.h" +#include +#include + +#include +#include + +#include "pipeline_acl.h" +#include "pipeline_acl_be.h" +#include "rte_cnxn_tracking.h" +#include "pipeline_actions_common.h" +#include "lib_arp.h" +#include "lib_icmpv6.h" +static uint8_t acl_prv_que_port_index[PIPELINE_MAX_PORT_IN]; +extern void convert_prefixlen_to_netmask_ipv6(uint32_t depth, + uint8_t netmask_ipv6[]); +enum { + ACL_PUB_PORT_ID, + ACL_PRV_PORT_ID, +}; + +/** + * A structure defining the ACL pipeline per thread data. + */ +struct pipeline_acl { + struct pipeline p; + pipeline_msg_req_handler custom_handlers[PIPELINE_ACL_MSG_REQS]; + + uint32_t n_rules; + uint32_t n_rule_fields; + struct rte_acl_field_def *field_format; + uint32_t field_format_size; + + /* Connection Tracker */ + struct rte_ct_cnxn_tracker *cnxn_tracker; + struct rte_ACL_counter_block *counters; + int action_counter_index; + /* timestamp retrieved during in-port computations */ + uint64_t in_port_time_stamp; + uint32_t n_flows; + + uint8_t pipeline_num; + uint8_t traffic_type; + uint8_t links_map[PIPELINE_MAX_PORT_IN]; + uint8_t port_out_id[PIPELINE_MAX_PORT_IN]; + uint64_t arpPktCount; + struct acl_table_entry *acl_entries_ipv4[RTE_PORT_IN_BURST_SIZE_MAX]; + struct acl_table_entry *acl_entries_ipv6[RTE_PORT_IN_BURST_SIZE_MAX]; + + /* Local ARP & ND Tables */ + struct lib_arp_route_table_entry + local_lib_arp_route_table[MAX_ARP_RT_ENTRY]; + uint8_t local_lib_arp_route_ent_cnt; + struct lib_nd_route_table_entry + local_lib_nd_route_table[MAX_ND_RT_ENTRY]; + uint8_t local_lib_nd_route_ent_cnt; + +} __rte_cache_aligned; + +/** + * A structure defining the mbuf meta data for ACL. + */ +struct mbuf_acl_meta_data { + /* output port stored for RTE_PIPELINE_ACTION_PORT_META */ + uint32_t output_port; + /* next hop ip address used by ARP code */ + uint8_t nhip[16]; +} __rte_cache_aligned; + +#define META_DATA_OFFSET 128 + +struct rte_ACL_counter_block rte_acl_counter_table[MAX_ACL_INSTANCES] + __rte_cache_aligned; +int rte_ACL_hi_counter_block_in_use = -1; + +/* a spin lock used during acl initialization only */ +rte_spinlock_t rte_ACL_init_lock = RTE_SPINLOCK_INITIALIZER; + +/* Action Array */ +struct pipeline_action_key *action_array_a; +struct pipeline_action_key *action_array_b; +struct pipeline_action_key *action_array_active; +struct pipeline_action_key *action_array_standby; +uint32_t action_array_size; + +struct action_counter_block + action_counter_table[MAX_ACL_INSTANCES][action_array_max] + __rte_cache_aligned; + +static void *pipeline_acl_msg_req_custom_handler(struct pipeline *p, void *msg); + +static pipeline_msg_req_handler handlers[] = { + [PIPELINE_MSG_REQ_PING] = pipeline_msg_req_ping_handler, + [PIPELINE_MSG_REQ_STATS_PORT_IN] = + pipeline_msg_req_stats_port_in_handler, + [PIPELINE_MSG_REQ_STATS_PORT_OUT] = + pipeline_msg_req_stats_port_out_handler, + [PIPELINE_MSG_REQ_STATS_TABLE] = pipeline_msg_req_stats_table_handler, + [PIPELINE_MSG_REQ_PORT_IN_ENABLE] = + pipeline_msg_req_port_in_enable_handler, + [PIPELINE_MSG_REQ_PORT_IN_DISABLE] = + pipeline_msg_req_port_in_disable_handler, + [PIPELINE_MSG_REQ_CUSTOM] = pipeline_acl_msg_req_custom_handler, +}; + +static void *pipeline_acl_msg_req_dbg_handler(struct pipeline *p, void *msg); + +static pipeline_msg_req_handler custom_handlers[] = { + [PIPELINE_ACL_MSG_REQ_DBG] = pipeline_acl_msg_req_dbg_handler, +}; + +uint8_t ACL_DEBUG; +uint32_t local_get_nh_ipv4(uint32_t ip, + uint32_t *port, + uint32_t *nhip, struct pipeline_acl *p_acl) +{ + int i; + + for (i = 0; i < p_acl->local_lib_arp_route_ent_cnt; i++) { + if (((p_acl->local_lib_arp_route_table[i].ip & + p_acl->local_lib_arp_route_table[i].mask) == + (ip & p_acl->local_lib_arp_route_table[i].mask))) { + *port = p_acl->local_lib_arp_route_table[i].port; + + *nhip = p_acl->local_lib_arp_route_table[i].nh; + return 1; + } + } + return 0; +} + +static void do_local_nh_ipv4_cache(uint32_t dest_if, struct pipeline_acl *p_acl) +{ + + /* Search for the entry and do local copy */ + int i; + + for (i = 0; i < MAX_ARP_RT_ENTRY; i++) { + if (lib_arp_route_table[i].port == dest_if) { + + struct lib_arp_route_table_entry *lentry = + &p_acl->local_lib_arp_route_table + [p_acl->local_lib_arp_route_ent_cnt]; + + lentry->ip = lib_arp_route_table[i].ip; + lentry->mask = lib_arp_route_table[i].mask; + lentry->port = lib_arp_route_table[i].port; + lentry->nh = lib_arp_route_table[i].nh; + + p_acl->local_lib_arp_route_ent_cnt++; + break; + } + } +} + +static uint32_t local_get_nh_ipv6(uint8_t *ip, + uint32_t *port, + uint8_t nhip[], struct pipeline_acl *p_acl) +{ + int i = 0; + uint8_t netmask_ipv6[16],netip_nd[16],netip_in[16]; + uint8_t k = 0, l = 0, depthflags = 0, depthflags1 = 0; + memset (netmask_ipv6, 0, sizeof(netmask_ipv6)); + memset (netip_nd, 0, sizeof(netip_nd)); + memset (netip_in, 0, sizeof(netip_in)); + + for (i = 0; i < p_acl->local_lib_nd_route_ent_cnt; i++) { + + convert_prefixlen_to_netmask_ipv6 + (p_acl->local_lib_nd_route_table[i].depth, netmask_ipv6); + + for (k = 0; k < 16; k++) + if (p_acl->local_lib_nd_route_table[i].ipv6[k] & + netmask_ipv6[k]) { + depthflags++; + netip_nd[k] = p_acl-> + local_lib_nd_route_table[i].ipv6[k]; + } + + + for (l = 0; l < 16; l++) + if (ip[l] & netmask_ipv6[l]) { + depthflags1++; + netip_in[l] = ip[l]; + } + + int j = 0; + + if ((depthflags == depthflags1) && (memcmp(netip_nd, netip_in, + sizeof(netip_nd)) == 0)){ + *port = p_acl->local_lib_nd_route_table[i].port; + + for (j = 0; j < 16; j++) + nhip[j] = + p_acl->local_lib_nd_route_table[i]. + nhipv6[j]; + return 1; + } + + depthflags = 0; + depthflags1 = 0; + } + return 0; +} +void do_local_nh_ipv6_cache(uint32_t dest_if, struct pipeline_acl *p_acl) +{ + /* Search for the entry and do local copy */ + int i, l; + + for (i = 0; i < MAX_ND_RT_ENTRY; i++) { + + if (lib_nd_route_table[i].port == dest_if) { + + struct lib_nd_route_table_entry *lentry = + &p_acl->local_lib_nd_route_table + [p_acl->local_lib_nd_route_ent_cnt]; + + for (l = 0; l < 16; l++) { + lentry->ipv6[l] = lib_nd_route_table[i].ipv6[l]; + lentry->nhipv6[l] = + lib_nd_route_table[i].nhipv6[l]; + } + lentry->depth = lib_nd_route_table[i].depth; + lentry->port = lib_nd_route_table[i].port; + + p_acl->local_lib_nd_route_ent_cnt++; + break; + } /* if */ + } /* for */ +} + +static uint8_t check_arp_icmp(struct rte_mbuf *pkt, + uint64_t pkt_mask, struct pipeline_acl *p_acl) +{ + uint32_t eth_proto_offset = MBUF_HDR_ROOM + 12; + struct ipv6_hdr *ipv6_h; + uint16_t *eth_proto = + RTE_MBUF_METADATA_UINT16_PTR(pkt, eth_proto_offset); + struct app_link_params *link; + + //uint32_t *port_out_id = RTE_MBUF_METADATA_UINT32_PTR(pk + // offsetof(struct mbuf_acl_meta_dat + + /* ARP outport number */ + uint16_t out_port = p_acl->p.n_ports_out - 1; + + uint8_t *protocol; + uint32_t prot_offset; + + link = &myApp->link_params[pkt->port]; + + switch (rte_be_to_cpu_16(*eth_proto)) { + + case ETH_TYPE_ARP: + rte_pipeline_port_out_packet_insert(p_acl->p.p, out_port, pkt); + + /* + * Pkt mask should be changed, and not changing the + * drop mask + */ + p_acl->arpPktCount++; + + return 0; +/* break;*/ + case ETH_TYPE_IPV4:{ + /* header room + eth hdr size + + * src_aadr offset in ip header + */ + uint32_t dst_addr_offset = MBUF_HDR_ROOM + + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST; + uint32_t *dst_addr = RTE_MBUF_METADATA_UINT32_PTR(pkt, + dst_addr_offset); + prot_offset = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_PROTOCOL_OFST; + protocol = RTE_MBUF_METADATA_UINT8_PTR(pkt, + prot_offset); + if ((*protocol == IP_PROTOCOL_ICMP) && + link->ip == rte_be_to_cpu_32(*dst_addr)) { + + if (is_phy_port_privte(pkt->port)) { + + rte_pipeline_port_out_packet_insert + (p_acl->p.p, out_port, pkt); + /* + * Pkt mask should be changed, + * and not changing the drop mask + */ + p_acl->arpPktCount++; + + return 0; + } + } + return 1; + } + break; +#if 0 +#ifdef IPV6 + case ETH_TYPE_IPV6:{ + + uint32_t dst_addr_offset = MBUF_HDR_ROOM + + ETH_HDR_SIZE + IPV6_HDR_DST_ADR_OFST; + uint32_t *dst_addr = RTE_MBUF_METADATA_UINT32_PTR(pkt, + dst_addr_offset); + + uint32_t prot_offset_ipv6 = MBUF_HDR_ROOM + + ETH_HDR_SIZE + IPV6_HDR_PROTOCOL_OFST; + struct ipv6_hdr *ipv6_h; + + ipv6_h = (struct ipv6_hdr *)MBUF_HDR_ROOM + + ETH_HDR_SIZE; + protocol = RTE_MBUF_METADATA_UINT8_PTR(pkt, + prot_offset_ipv6); + + if ((ipv6_h->proto == ICMPV6_PROTOCOL_ID) && + (link->ip == rte_be_to_cpu_32(dst_addr[3]))) { + + if (is_phy_port_privte(pkt->port)) { + + rte_pipeline_port_out_packet_insert + (p_acl->p.p, out_port, pkt); + /* + * Pkt mask should be changed, + * and not changing the drop mask + */ + p_acl->arpPktCount++; + + return 0; + } + } + return 1; + } + break; +#endif +#endif +#define IP_START (MBUF_HDR_ROOM + ETH_HDR_SIZE) +#ifdef IPV6 + case ETH_TYPE_IPV6: + ipv6_h = (struct ipv6_hdr *) + RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START); + + if ((ipv6_h->proto == ICMPV6_PROTOCOL_ID) && + (link->ip == + rte_be_to_cpu_32(ipv6_h->dst_addr[3]))) { + + if (is_phy_port_privte(pkt->port)) { + rte_pipeline_port_out_packet_insert( + p_acl->p.p, + out_port, + pkt); + + p_acl->arpPktCount++; + + return 0; + } + } + break; +#endif + default: + break; + return 1; + } + return 1; +} + +/** + * Print packet for debugging. + * + * @param pkt + * A pointer to the packet. + * + */ +void print_pkt_acl(struct rte_mbuf *pkt) +{ + int i = 0, j = 0; + + printf("Packet Contents:\n"); + uint8_t *rd = RTE_MBUF_METADATA_UINT8_PTR(pkt, 0); + + for (i = 0; i < 20; i++) { + for (j = 0; j < 20; j++) + printf("%02x ", rd[(20 * i) + j]); + printf("\n"); + } +} + +/** + * Main packet processing function. + * 64 packet bit mask are used to identify which packets to forward. + * Performs the following: + * - Burst lookup packets in the IPv4 ACL Rule Table. + * - Burst lookup packets in the IPv6 ACL Rule Table. + * - Lookup Action Table, perform actions. + * - Burst lookup Connection Tracking, if enabled. + * - Lookup MAC address. + * - Set bit mask. + * - Packets with bit mask set are forwarded + * + * @param p + * A pointer to the pipeline. + * @param pkts + * A pointer to a burst of packets. + * @param n_pkts + * Number of packets to process. + * @param arg + * A pointer to pipeline specific data. + * + * @return + * 0 on success, negative on error. + */ +static int +pkt_work_acl_key(struct rte_pipeline *p, + struct rte_mbuf **pkts, uint32_t n_pkts, void *arg) +{ + + struct pipeline_acl *p_acl = arg; + + p_acl->counters->pkts_received = + p_acl->counters->pkts_received + n_pkts; + if (ACL_DEBUG) + printf("pkt_work_acl_key pkts_received: %" PRIu64 + " n_pkts: %u\n", p_acl->counters->pkts_received, n_pkts); + + uint64_t lookup_hit_mask = 0; + uint64_t lookup_hit_mask_ipv4 = 0; + uint64_t lookup_hit_mask_ipv6 = 0; + uint64_t lookup_miss_mask = 0; + uint64_t conntrack_mask = 0; + uint64_t connexist_mask = 0; + uint32_t dest_address = 0; + int dest_if = 0; + int status; + uint64_t pkts_drop_mask, pkts_mask = RTE_LEN2MASK(n_pkts, uint64_t); + uint64_t keep_mask = pkts_mask; + uint16_t port; + uint32_t ret; + + p_acl->in_port_time_stamp = rte_get_tsc_cycles(); + + if (acl_ipv4_enabled) { + if (ACL_DEBUG) + printf("ACL IPV4 Lookup Mask Before = %p\n", + (void *)pkts_mask); + status = + rte_table_acl_ops.f_lookup(acl_rule_table_ipv4_active, pkts, + pkts_mask, &lookup_hit_mask_ipv4, + (void **) + p_acl->acl_entries_ipv4); + if (ACL_DEBUG) + printf("ACL IPV4 Lookup Mask After = %p\n", + (void *)lookup_hit_mask_ipv4); + } + + if (acl_ipv6_enabled) { + if (ACL_DEBUG) + printf("ACL IPV6 Lookup Mask Before = %p\n", + (void *)pkts_mask); + status = + rte_table_acl_ops.f_lookup(acl_rule_table_ipv6_active, pkts, + pkts_mask, &lookup_hit_mask_ipv6, + (void **) + p_acl->acl_entries_ipv6); + if (ACL_DEBUG) + printf("ACL IPV6 Lookup Mask After = %p\n", + (void *)lookup_hit_mask_ipv6); + } + + /* Merge lookup results since we process both IPv4 and IPv6 below */ + lookup_hit_mask = lookup_hit_mask_ipv4 | lookup_hit_mask_ipv6; + if (ACL_DEBUG) + printf("ACL Lookup Mask After = %p\n", (void *)lookup_hit_mask); + + lookup_miss_mask = pkts_mask & (~lookup_hit_mask); + pkts_mask = lookup_hit_mask; + p_acl->counters->pkts_drop += __builtin_popcountll(lookup_miss_mask); + if (ACL_DEBUG) + printf("pkt_work_acl_key pkts_drop: %" PRIu64 " n_pkts: %u\n", + p_acl->counters->pkts_drop, + __builtin_popcountll(lookup_miss_mask)); + + uint64_t pkts_to_process = lookup_hit_mask; + /* bitmap of packets left to process for ARP */ + + for (; pkts_to_process;) { + uint8_t pos = (uint8_t) __builtin_ctzll(pkts_to_process); + uint64_t pkt_mask = 1LLU << pos; + /* bitmask representing only this packet */ + + pkts_to_process &= ~pkt_mask; + /* remove this packet from remaining list */ + struct rte_mbuf *pkt = pkts[pos]; + + if (enable_hwlb) + if (!check_arp_icmp(pkt, pkt_mask, p_acl)) { + pkts_mask &= ~(1LLU << pos); + continue; + } + + uint8_t hdr_chk = + RTE_MBUF_METADATA_UINT8(pkt, MBUF_HDR_ROOM + ETH_HDR_SIZE); + hdr_chk = hdr_chk >> IP_VERSION_CHECK; + + if (hdr_chk == IPv4_HDR_VERSION) { + + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv4[pos]; + uint16_t phy_port = entry->head.port_id; + uint32_t action_id = entry->action_id; + + if (ACL_DEBUG) + printf("action_id = %u\n", action_id); + + uint32_t dscp_offset = + MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DSCP_OFST; + + if (action_array_active[action_id].action_bitmap & + acl_action_count) { + action_counter_table + [p_acl->action_counter_index] + [action_id].packetCount++; + action_counter_table + [p_acl->action_counter_index] + [action_id].byteCount += + rte_pktmbuf_pkt_len(pkt); + if (ACL_DEBUG) + printf("Action Count Packet Count: %" + PRIu64 " Byte Count: %" PRIu64 + "\n", + action_counter_table + [p_acl->action_counter_index] + [action_id].packetCount, + action_counter_table + [p_acl->action_counter_index] + [action_id].byteCount); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_packet_drop) { + + /* Drop packet by changing the mask */ + if (ACL_DEBUG) + printf("ACL before drop pkt_mask " + " %lu, pkt_num %d\n", + pkts_mask, pos); + pkts_mask &= ~(1LLU << pos); + if (ACL_DEBUG) + printf("ACL after drop pkt_mask " + "%lu, pkt_num %d\n", + pkts_mask, pos); + p_acl->counters->pkts_drop++; + } + + if (action_array_active[action_id].action_bitmap & + acl_action_fwd) { + phy_port = + action_array_active[action_id].fwd_port; + entry->head.port_id = phy_port; + if (ACL_DEBUG) + printf("Action FWD Port ID: %u\n", + phy_port); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_nat) { + phy_port = + action_array_active[action_id].nat_port; + entry->head.port_id = phy_port; + if (ACL_DEBUG) + printf("Action NAT Port ID: %u\n", + phy_port); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_dscp) { + + /* Set DSCP priority */ + uint8_t *dscp = RTE_MBUF_METADATA_UINT8_PTR(pkt, + dscp_offset); + *dscp = + action_array_active[action_id].dscp_priority + << 2; + if (ACL_DEBUG) + printf + ("Action DSCP DSCP Priority: %u\n", + *dscp); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_packet_accept) { + if (ACL_DEBUG) + printf("Action Accept\n"); + + if (action_array_active[action_id].action_bitmap + & acl_action_conntrack) { + + /* Set conntrack bit for this pkt */ + conntrack_mask |= pkt_mask; + if (ACL_DEBUG) + printf("ACL Conntrack enabled: " + "%p pkt_mask: %p\n", + (void *)conntrack_mask, + (void *)pkt_mask); + } + + if (action_array_active[action_id].action_bitmap + & acl_action_connexist) { + + /* Set conntrack bit for this pkt */ + conntrack_mask |= pkt_mask; + + /* Set connexist bit for this pkt for public -> private */ + /* Private -> public packet will open the connection */ + if (action_array_active + [action_id].private_public == + acl_public_private) + connexist_mask |= pkt_mask; + + if (ACL_DEBUG) + printf("ACL Connexist enabled " + "conntrack: %p connexist: %p pkt_mask: %p\n", + (void *)conntrack_mask, + (void *)connexist_mask, + (void *)pkt_mask); + } + } + } + + if (hdr_chk == IPv6_HDR_VERSION) { + + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv6[pos]; + uint16_t phy_port = entry->head.port_id; + uint32_t action_id = entry->action_id; + + if (ACL_DEBUG) + printf("action_id = %u\n", action_id); + + if (action_array_active[action_id].action_bitmap & + acl_action_count) { + action_counter_table + [p_acl->action_counter_index] + [action_id].packetCount++; + action_counter_table + [p_acl->action_counter_index] + [action_id].byteCount += + rte_pktmbuf_pkt_len(pkt); + if (ACL_DEBUG) + printf("Action Count Packet Count: %" + PRIu64 " Byte Count: %" PRIu64 + "\n", + action_counter_table + [p_acl->action_counter_index] + [action_id].packetCount, + action_counter_table + [p_acl->action_counter_index] + [action_id].byteCount); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_packet_drop) { + /* Drop packet by changing the mask */ + if (ACL_DEBUG) + printf("ACL before drop pkt_mask " + "%lu, pkt_num %d\n", + pkts_mask, pos); + pkts_mask &= ~(1LLU << pos); + if (ACL_DEBUG) + printf("ACL after drop pkt_mask " + "%lu, pkt_num %d\n", + pkts_mask, pos); + p_acl->counters->pkts_drop++; + + } + + if (action_array_active[action_id].action_bitmap & + acl_action_fwd) { + phy_port = + action_array_active[action_id].fwd_port; + entry->head.port_id = phy_port; + if (ACL_DEBUG) + printf("Action FWD Port ID: %u\n", + phy_port); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_nat) { + phy_port = + action_array_active[action_id].nat_port; + entry->head.port_id = phy_port; + if (ACL_DEBUG) + printf("Action NAT Port ID: %u\n", + phy_port); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_dscp) { + + /* Set DSCP priority */ + uint32_t dscp_offset = + MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_DSCP_OFST_IPV6; + uint16_t *dscp = + RTE_MBUF_METADATA_UINT16_PTR(pkt, + dscp_offset); + uint16_t dscp_value = + (rte_bswap16 + (RTE_MBUF_METADATA_UINT16 + (pkt, dscp_offset)) & 0XF00F); + uint8_t dscp_store = + action_array_active[action_id].dscp_priority + << 2; + uint16_t dscp_temp = dscp_store; + + dscp_temp = dscp_temp << 4; + *dscp = rte_bswap16(dscp_temp | dscp_value); + if (ACL_DEBUG) + printf + ("Action DSCP DSCP Priority: %u\n", + *dscp); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_packet_accept) { + if (ACL_DEBUG) + printf("Action Accept\n"); + + if (action_array_active[action_id].action_bitmap + & acl_action_conntrack) { + + /* Set conntrack bit for this pkt */ + conntrack_mask |= pkt_mask; + if (ACL_DEBUG) + printf("ACL Conntrack enabled: " + " %p pkt_mask: %p\n", + (void *)conntrack_mask, + (void *)pkt_mask); + } + + if (action_array_active[action_id].action_bitmap + & acl_action_connexist) { + + /* Set conntrack bit for this pkt */ + conntrack_mask |= pkt_mask; + + /* Set connexist bit for this pkt for public -> private */ + /* Private -> public packet will open the connection */ + if (action_array_active + [action_id].private_public == + acl_public_private) + connexist_mask |= pkt_mask; + + if (ACL_DEBUG) + printf("ACL Connexist enabled " + "conntrack: %p connexist: %p pkt_mask: %p\n", + (void *)conntrack_mask, + (void *)connexist_mask, + (void *)pkt_mask); + } + } + } + } + + /* Only call connection tracker if required */ + if (conntrack_mask > 0) { + if (ACL_DEBUG) + printf + ("ACL Call Conntrack Before = %p Connexist = %p\n", + (void *)conntrack_mask, (void *)connexist_mask); + conntrack_mask = + rte_ct_cnxn_tracker_batch_lookup_with_new_cnxn_control + (p_acl->cnxn_tracker, pkts, conntrack_mask, connexist_mask); + if (ACL_DEBUG) + printf("ACL Call Conntrack After = %p\n", + (void *)conntrack_mask); + + /* Only change pkt mask for pkts that have conntrack enabled */ + /* Need to loop through packets to check if conntrack enabled */ + pkts_to_process = pkts_mask; + for (; pkts_to_process;) { + uint32_t action_id = 0; + uint8_t pos = + (uint8_t) __builtin_ctzll(pkts_to_process); + uint64_t pkt_mask = 1LLU << pos; + /* bitmask representing only this packet */ + + pkts_to_process &= ~pkt_mask; + /* remove this packet from remaining list */ + struct rte_mbuf *pkt = pkts[pos]; + + uint8_t hdr_chk = RTE_MBUF_METADATA_UINT8(pkt, + MBUF_HDR_ROOM + + + ETH_HDR_SIZE); + + hdr_chk = hdr_chk >> IP_VERSION_CHECK; + if (hdr_chk == IPv4_HDR_VERSION) { + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv4[pos]; + action_id = entry->action_id; + } else { + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv6[pos]; + action_id = entry->action_id; + } + + if ((action_array_active[action_id].action_bitmap & + acl_action_conntrack) + || (action_array_active[action_id].action_bitmap & + acl_action_connexist)) { + + if (conntrack_mask & pkt_mask) { + if (ACL_DEBUG) + printf("ACL Conntrack Accept " + "packet = %p\n", + (void *)pkt_mask); + } else { + /* Drop packet by changing the mask */ + if (ACL_DEBUG) + printf("ACL Conntrack Drop " + "packet = %p\n", + (void *)pkt_mask); + pkts_mask &= ~pkt_mask; + p_acl->counters->pkts_drop++; + } + } + } + } + + pkts_to_process = pkts_mask; + /* bitmap of packets left to process for ARP */ + + for (; pkts_to_process;) { + uint8_t pos = (uint8_t) __builtin_ctzll(pkts_to_process); + uint64_t pkt_mask = 1LLU << pos; + /* bitmask representing only this packet */ + + pkts_to_process &= ~pkt_mask; + /* remove this packet from remaining list */ + struct rte_mbuf *pkt = pkts[pos]; + + uint8_t hdr_chk = + RTE_MBUF_METADATA_UINT8(pkt, MBUF_HDR_ROOM + ETH_HDR_SIZE); + hdr_chk = hdr_chk >> IP_VERSION_CHECK; + + if (hdr_chk == IPv4_HDR_VERSION) { + + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv4[pos]; + uint16_t phy_port = pkt->port; + uint32_t *port_out_id = + RTE_MBUF_METADATA_UINT32_PTR(pkt, + META_DATA_OFFSET + + offsetof(struct + mbuf_acl_meta_data, + output_port)); + if (ACL_DEBUG) + printf + ("phy_port = %i, links_map[phy_port] = %i\n", + phy_port, p_acl->links_map[phy_port]); + + /* header room + eth hdr size + dst_adr offset in ip header */ + uint32_t dst_addr_offset = + MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST; + uint32_t *dst_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, dst_addr_offset); + uint8_t *eth_dest = + RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM); + uint8_t *eth_src = + RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM + 6); + struct ether_addr hw_addr; + uint32_t dest_address = rte_bswap32(*dst_addr); + uint32_t *nhip = RTE_MBUF_METADATA_UINT32_PTR(pkt, + META_DATA_OFFSET + + + offsetof + (struct + mbuf_acl_meta_data, + nhip)); + uint32_t packet_length = rte_pktmbuf_pkt_len(pkt); + *nhip = 0; + if (is_phy_port_privte(phy_port)) { + dest_address = rte_bswap32(*dst_addr); + ret = + local_get_nh_ipv4(dest_address, &dest_if, + nhip, p_acl); + if (!ret) { + dest_if = + get_prv_to_pub_port(&dest_address, + IP_VERSION_4); + do_local_nh_ipv4_cache(dest_if, p_acl); + } + *port_out_id = p_acl->port_out_id[dest_if]; + } else { + dest_address = rte_bswap32(*dst_addr); + + ret = local_get_nh_ipv4(dest_address, &dest_if, + nhip, p_acl); + if (!ret) { + dest_if = + get_pub_to_prv_port(&dest_address, + IP_VERSION_4); + do_local_nh_ipv4_cache(dest_if, p_acl); + }; + *port_out_id = p_acl->port_out_id[dest_if]; + } + /* port = ACL_PRV_PORT_ID; */ + + int ret_mac = 0; + + ret_mac = get_dest_mac_addr_port + (dest_address, &dest_if, &hw_addr); + if (ret_mac == ARP_FOUND) { + if (ACL_DEBUG) { + printf("MAC found for ip 0x%x, " + "port %d - %02x:%02x:%02x:%02x:%02x:%02x\n", + dest_address, phy_port, + hw_addr.addr_bytes[0], + hw_addr.addr_bytes[1], + hw_addr.addr_bytes[2], + hw_addr.addr_bytes[3], + hw_addr.addr_bytes[4], + hw_addr.addr_bytes[5]); + printf("Dest MAC before - " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + eth_dest[0], eth_dest[1], + eth_dest[2], eth_dest[3], + eth_dest[4], eth_dest[5]); + } + + memcpy(eth_dest, &hw_addr, + sizeof(struct ether_addr)); + if (ACL_DEBUG) { + printf("PktP %p, dest_macP %p\n", pkt, + eth_dest); + printf("Dest MAC after - " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + eth_dest[0], eth_dest[1], + eth_dest[2], eth_dest[3], + eth_dest[4], eth_dest[5]); + } + if (is_phy_port_privte(phy_port)) + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + else + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + p_acl->counters->tpkts_processed++; + p_acl->counters->bytes_processed += + packet_length; + } + + else { + if (*nhip != 0) { + if (ACL_DEBUG) + printf("ACL requesting ARP for " + "ip %x, port %d\n", + dest_address, phy_port); + if (ret_mac == ARP_NOT_FOUND) + request_arp(dest_if, *nhip); + + /* request_arp(p_acl->links_map[phy_port], *nhip); */ + } + /* Drop packet by changing the mask */ + if (ACL_DEBUG) + printf("ACL before drop pkt_mask " + "%lu, pkt_num %d\n", + pkts_mask, pos); + pkts_mask &= ~(1LLU << pos); + if (ACL_DEBUG) + printf("ACL after drop pkt_mask " + "%lu, pkt_num %d\n", + pkts_mask, pos); + p_acl->counters->pkts_drop++; + } + } + + if (hdr_chk == IPv6_HDR_VERSION) { + + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv6[pos]; + //uint16_t phy_port = entry->head.port_id; + uint16_t phy_port = pkt->port; + uint32_t *port_out_id = + RTE_MBUF_METADATA_UINT32_PTR(pkt, + META_DATA_OFFSET + + offsetof(struct + mbuf_acl_meta_data, + output_port)); + /*if (is_phy_port_privte(phy_port)) + *port_out_id = ACL_PUB_PORT_ID; + else + *port_out_id = ACL_PRV_PORT_ID;*/ + + /* *port_out_id = p_acl->links_map[phy_port]; */ + if (ACL_DEBUG) + printf("phy_port = %i, " + "links_map[phy_port] = %i\n", + phy_port, p_acl->links_map[phy_port]); + + /* header room + eth hdr size + dst_adr offset in ip header */ + uint32_t dst_addr_offset = + MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_DST_ADR_OFST_IPV6; + uint8_t *eth_dest = + RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM); + uint8_t *eth_src = + RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM + 6); + struct ether_addr hw_addr; + uint8_t dest_address[16]; + uint8_t nhip[16]; + + nhip[0] = + RTE_MBUF_METADATA_UINT8(pkt, + META_DATA_OFFSET + + offsetof(struct + mbuf_acl_meta_data, + nhip)); + uint8_t *dst_addr[16]; + uint32_t packet_length = rte_pktmbuf_pkt_len(pkt); + int i = 0; + + for (i = 0; i < 16; i++) { + dst_addr[i] = + RTE_MBUF_METADATA_UINT8_PTR(pkt, + dst_addr_offset + + i); + } + memcpy(dest_address, *dst_addr, sizeof(dest_address)); + memset(nhip, 0, sizeof(nhip)); + ret = local_get_nh_ipv6(&dest_address[0], &dest_if, + &nhip[0], p_acl); + + if (is_phy_port_privte(phy_port)) { + if (!ret) { + dest_if = get_prv_to_pub_port(( + uint32_t + *) + &dest_address[0], IP_VERSION_6); + do_local_nh_ipv6_cache(dest_if, p_acl); + *port_out_id = + p_acl->port_out_id[dest_if]; + } + // port = ACL_PUB_PORT_ID; + + } else { + if (!ret) { + dest_if = get_pub_to_prv_port(( + uint32_t + *) + &dest_address[0], IP_VERSION_6); + do_local_nh_ipv6_cache(dest_if, p_acl); + *port_out_id = + p_acl->port_out_id[dest_if]; + } +// port = ACL_PRV_PORT_ID; + + } + + if (get_dest_mac_address_ipv6_port + (dest_address, &dest_if, &hw_addr, &nhip[0])) { + if (ACL_DEBUG) { + printf("MAC found for port %d - " + " %02x:%02x:%02x:%02x:%02x:%02x\n", + phy_port, hw_addr.addr_bytes[0], + hw_addr.addr_bytes[1], + hw_addr.addr_bytes[2], + hw_addr.addr_bytes[3], + hw_addr.addr_bytes[4], + hw_addr.addr_bytes[5]); + printf("Dest MAC before - " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + eth_dest[0], eth_dest[1], + eth_dest[2], eth_dest[3], + eth_dest[4], eth_dest[5]); + } + memcpy(eth_dest, &hw_addr, + sizeof(struct ether_addr)); + if (ACL_DEBUG) { + printf("PktP %p, dest_macP %p\n", pkt, + eth_dest); + printf("Dest MAC after - " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + eth_dest[0], eth_dest[1], + eth_dest[2], eth_dest[3], + eth_dest[4], eth_dest[5]); + } + if (is_phy_port_privte(phy_port)) + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + else + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + +/* memcpy(eth_src, get_link_hw_addr(p_acl->links_map[phy_port]), */ +/* sizeof(struct ether_addr)); */ + p_acl->counters->tpkts_processed++; + p_acl->counters->bytes_processed += + packet_length; + } + + else { + +#if 0 + /* Request next neighbor for Ipv6 is yet to be done. */ + if (*nhip != 0) { + if (ACL_DEBUG) + printf + ("ACL requesting ARP for ip %x, port %d\n", + dest_address, phy_port); + + /* request_arp(p_acl->links_map[phy_port], *nhip); */ + } +#endif + /* Drop packet by changing the mask */ + if (ACL_DEBUG) + printf("ACL before drop pkt_mask " + "%lu, pkt_num %d\n", + pkts_mask, pos); + pkts_mask &= ~(1LLU << pos); + if (ACL_DEBUG) + printf("ACL after drop pkt_mask " + "%lu, pkt_num %d\n", + pkts_mask, pos); + p_acl->counters->pkts_drop++; + } + } + + } + + pkts_drop_mask = keep_mask & ~pkts_mask; + rte_pipeline_ah_packet_drop(p, pkts_drop_mask); + keep_mask = pkts_mask; + + /* don't bother measuring if traffic very low, might skew stats */ + uint32_t packets_this_iteration = __builtin_popcountll(pkts_mask); + + if (packets_this_iteration > 1) { + uint64_t latency_this_iteration = + rte_get_tsc_cycles() - p_acl->in_port_time_stamp; + + p_acl->counters->sum_latencies += latency_this_iteration; + p_acl->counters->count_latencies++; + } + + if (ACL_DEBUG) + printf("Leaving pkt_work_acl_key pkts_mask = %p\n", + (void *)pkts_mask); + + return 0; +} + +/** + * Main packet processing function. + * 64 packet bit mask are used to identify which packets to forward. + * Performs the following: + * - Burst lookup packets in the IPv4 ACL Rule Table. + * - Burst lookup packets in the IPv6 ACL Rule Table. + * - Lookup Action Table, perform actions. + * - Burst lookup Connection Tracking, if enabled. + * - Lookup MAC address. + * - Set bit mask. + * - Packets with bit mask set are forwarded + * + * @param p + * A pointer to the pipeline. + * @param pkts + * A pointer to a burst of packets. + * @param n_pkts + * Number of packets to process. + * @param arg + * A pointer to pipeline specific data. + * + * @return + * 0 on success, negative on error. + */ +static int +pkt_work_acl_ipv4_key(struct rte_pipeline *p, + struct rte_mbuf **pkts, uint32_t n_pkts, void *arg) +{ + + struct pipeline_acl *p_acl = arg; + + p_acl->counters->pkts_received = + p_acl->counters->pkts_received + n_pkts; + if (ACL_DEBUG) + printf("pkt_work_acl_key pkts_received: %" PRIu64 + " n_pkts: %u\n", p_acl->counters->pkts_received, n_pkts); + + uint64_t lookup_hit_mask = 0; + uint64_t lookup_hit_mask_ipv4 = 0; + uint64_t lookup_hit_mask_ipv6 = 0; + uint64_t lookup_miss_mask = 0; + uint64_t conntrack_mask = 0; + uint64_t connexist_mask = 0; + uint32_t dest_address = 0; + int dest_if = 0; + int status; + uint64_t pkts_drop_mask, pkts_mask = RTE_LEN2MASK(n_pkts, uint64_t); + uint64_t keep_mask = pkts_mask; + uint16_t port; + uint32_t ret; + + p_acl->in_port_time_stamp = rte_get_tsc_cycles(); + + if (acl_ipv4_enabled) { + if (ACL_DEBUG) + printf("ACL IPV4 Lookup Mask Before = %p\n", + (void *)pkts_mask); + status = + rte_table_acl_ops.f_lookup(acl_rule_table_ipv4_active, pkts, + pkts_mask, &lookup_hit_mask_ipv4, + (void **) + p_acl->acl_entries_ipv4); + if (ACL_DEBUG) + printf("ACL IPV4 Lookup Mask After = %p\n", + (void *)lookup_hit_mask_ipv4); + } + + /* Merge lookup results since we process both IPv4 and IPv6 below */ + lookup_hit_mask = lookup_hit_mask_ipv4 | lookup_hit_mask_ipv6; + if (ACL_DEBUG) + printf("ACL Lookup Mask After = %p\n", (void *)lookup_hit_mask); + + lookup_miss_mask = pkts_mask & (~lookup_hit_mask); + pkts_mask = lookup_hit_mask; + p_acl->counters->pkts_drop += __builtin_popcountll(lookup_miss_mask); + if (ACL_DEBUG) + printf("pkt_work_acl_key pkts_drop: %" PRIu64 " n_pkts: %u\n", + p_acl->counters->pkts_drop, + __builtin_popcountll(lookup_miss_mask)); + + uint64_t pkts_to_process = lookup_hit_mask; + /* bitmap of packets left to process for ARP */ + + for (; pkts_to_process;) { + uint8_t pos = (uint8_t) __builtin_ctzll(pkts_to_process); + uint64_t pkt_mask = 1LLU << pos; + /* bitmask representing only this packet */ + + pkts_to_process &= ~pkt_mask; + /* remove this packet from remaining list */ + struct rte_mbuf *pkt = pkts[pos]; + + if (enable_hwlb) + if (!check_arp_icmp(pkt, pkt_mask, p_acl)) { + pkts_mask &= ~(1LLU << pos); + continue; + } + + uint8_t hdr_chk = + RTE_MBUF_METADATA_UINT8(pkt, MBUF_HDR_ROOM + ETH_HDR_SIZE); + hdr_chk = hdr_chk >> IP_VERSION_CHECK; + + if (hdr_chk == IPv4_HDR_VERSION) { + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv4[pos]; + uint16_t phy_port = entry->head.port_id; + uint32_t action_id = entry->action_id; + + if (ACL_DEBUG) + printf("action_id = %u\n", action_id); + + uint32_t dscp_offset = + MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DSCP_OFST; + + if (action_array_active[action_id].action_bitmap & + acl_action_count) { + action_counter_table + [p_acl->action_counter_index] + [action_id].packetCount++; + action_counter_table + [p_acl->action_counter_index] + [action_id].byteCount += + rte_pktmbuf_pkt_len(pkt); + if (ACL_DEBUG) + printf("Action Count Packet Count: %" + PRIu64 " Byte Count: %" PRIu64 + "\n", + action_counter_table + [p_acl->action_counter_index] + [action_id].packetCount, + action_counter_table + [p_acl->action_counter_index] + [action_id].byteCount); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_packet_drop) { + + /* Drop packet by changing the mask */ + if (ACL_DEBUG) + printf("ACL before drop pkt_mask " + "%lu, pkt_num %d\n", + pkts_mask, pos); + pkts_mask &= ~(1LLU << pos); + if (ACL_DEBUG) + printf("ACL after drop pkt_mask " + " %lu, pkt_num %d\n", + pkts_mask, pos); + p_acl->counters->pkts_drop++; + } + + if (action_array_active[action_id].action_bitmap & + acl_action_fwd) { + phy_port = + action_array_active[action_id].fwd_port; + entry->head.port_id = phy_port; + if (ACL_DEBUG) + printf("Action FWD Port ID: %u\n", + phy_port); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_nat) { + phy_port = + action_array_active[action_id].nat_port; + entry->head.port_id = phy_port; + if (ACL_DEBUG) + printf("Action NAT Port ID: %u\n", + phy_port); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_dscp) { + + /* Set DSCP priority */ + uint8_t *dscp = RTE_MBUF_METADATA_UINT8_PTR(pkt, + dscp_offset); + *dscp = + action_array_active[action_id].dscp_priority + << 2; + if (ACL_DEBUG) + printf + ("Action DSCP DSCP Priority: %u\n", + *dscp); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_packet_accept) { + if (ACL_DEBUG) + printf("Action Accept\n"); + + if (action_array_active[action_id].action_bitmap + & acl_action_conntrack) { + + /* Set conntrack bit for this pkt */ + conntrack_mask |= pkt_mask; + if (ACL_DEBUG) + printf("ACL Conntrack " + "enabled: %p pkt_mask: %p\n", + (void *)conntrack_mask, + (void *)pkt_mask); + } + + if (action_array_active[action_id].action_bitmap + & acl_action_connexist) { + + /* Set conntrack bit for this pkt */ + conntrack_mask |= pkt_mask; + + /* Set connexist bit for this pkt for public -> private */ + /* Private -> public packet will open the connection */ + if (action_array_active + [action_id].private_public == + acl_public_private) + connexist_mask |= pkt_mask; + + if (ACL_DEBUG) + printf("ACL Connexist " + "enabled conntrack: %p connexist: %p pkt_mask: %p\n", + (void *)conntrack_mask, + (void *)connexist_mask, + (void *)pkt_mask); + } + } + } +#if 0 + if (hdr_chk == IPv6_HDR_VERSION) { + + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv6[pos]; + uint16_t phy_port = entry->head.port_id; + uint32_t action_id = entry->action_id; + + if (ACL_DEBUG) + printf("action_id = %u\n", action_id); + + if (action_array_active[action_id].action_bitmap & + acl_action_count) { + action_counter_table + [p_acl->action_counter_index] + [action_id].packetCount++; + action_counter_table + [p_acl->action_counter_index] + [action_id].byteCount += + rte_pktmbuf_pkt_len(pkt); + if (ACL_DEBUG) + printf("Action Count Packet Count: %" + PRIu64 " Byte Count: %" PRIu64 + "\n", + action_counter_table + [p_acl->action_counter_index] + [action_id].packetCount, + action_counter_table + [p_acl->action_counter_index] + [action_id].byteCount); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_packet_drop) { + /* Drop packet by changing the mask */ + if (ACL_DEBUG) + printf + ("ACL before drop pkt_mask %lu, pkt_num %d\n", + pkts_mask, pos); + pkts_mask &= ~(1LLU << pos); + if (ACL_DEBUG) + printf + ("ACL after drop pkt_mask %lu, pkt_num %d\n", + pkts_mask, pos); + p_acl->counters->pkts_drop++; + + } + + if (action_array_active[action_id].action_bitmap & + acl_action_fwd) { + phy_port = + action_array_active[action_id].fwd_port; + entry->head.port_id = phy_port; + if (ACL_DEBUG) + printf("Action FWD Port ID: %u\n", + phy_port); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_nat) { + phy_port = + action_array_active[action_id].nat_port; + entry->head.port_id = phy_port; + if (ACL_DEBUG) + printf("Action NAT Port ID: %u\n", + phy_port); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_dscp) { + + /* Set DSCP priority */ + uint32_t dscp_offset = + MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_DSCP_OFST_IPV6; + uint16_t *dscp = + RTE_MBUF_METADATA_UINT16_PTR(pkt, + dscp_offset); + uint16_t dscp_value = + (rte_bswap16 + (RTE_MBUF_METADATA_UINT16 + (pkt, dscp_offset)) & 0XF00F); + uint8_t dscp_store = + action_array_active[action_id].dscp_priority + << 2; + uint16_t dscp_temp = dscp_store; + + dscp_temp = dscp_temp << 4; + *dscp = rte_bswap16(dscp_temp | dscp_value); + if (ACL_DEBUG) + printf + ("Action DSCP DSCP Priority: %u\n", + *dscp); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_packet_accept) { + if (ACL_DEBUG) + printf("Action Accept\n"); + + if (action_array_active[action_id].action_bitmap + & acl_action_conntrack) { + + /* Set conntrack bit for this pkt */ + conntrack_mask |= pkt_mask; + if (ACL_DEBUG) + printf("ACL Conntrack " + "enabled: %p pkt_mask: %p\n", + (void *)conntrack_mask, + (void *)pkt_mask); + } + + if (action_array_active[action_id].action_bitmap + & acl_action_connexist) { + + /* Set conntrack bit for this pkt */ + conntrack_mask |= pkt_mask; + + /* Set connexist bit for this pkt for public -> private */ + /* Private -> public packet will open the connection */ + if (action_array_active + [action_id].private_public == + acl_public_private) + connexist_mask |= pkt_mask; + + if (ACL_DEBUG) + printf("ACL Connexist enabled " + "conntrack: %p connexist: %p pkt_mask: %p\n", + (void *)conntrack_mask, + (void *)connexist_mask, + (void *)pkt_mask); + } + } + } +#endif + } + /* Only call connection tracker if required */ + if (conntrack_mask > 0) { + if (ACL_DEBUG) + printf + ("ACL Call Conntrack Before = %p Connexist = %p\n", + (void *)conntrack_mask, (void *)connexist_mask); + conntrack_mask = + rte_ct_cnxn_tracker_batch_lookup_with_new_cnxn_control + (p_acl->cnxn_tracker, pkts, conntrack_mask, connexist_mask); + if (ACL_DEBUG) + printf("ACL Call Conntrack After = %p\n", + (void *)conntrack_mask); + + /* Only change pkt mask for pkts that have conntrack enabled */ + /* Need to loop through packets to check if conntrack enabled */ + pkts_to_process = pkts_mask; + for (; pkts_to_process;) { + uint32_t action_id = 0; + uint8_t pos = + (uint8_t) __builtin_ctzll(pkts_to_process); + uint64_t pkt_mask = 1LLU << pos; + /* bitmask representing only this packet */ + + pkts_to_process &= ~pkt_mask; + /* remove this packet from remaining list */ + struct rte_mbuf *pkt = pkts[pos]; + + uint8_t hdr_chk = RTE_MBUF_METADATA_UINT8(pkt, + MBUF_HDR_ROOM + + + ETH_HDR_SIZE); + hdr_chk = hdr_chk >> IP_VERSION_CHECK; + if (hdr_chk == IPv4_HDR_VERSION) { + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv4[pos]; + action_id = entry->action_id; + } else { + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv6[pos]; + action_id = entry->action_id; + } + + if ((action_array_active[action_id].action_bitmap & + acl_action_conntrack) + || (action_array_active[action_id].action_bitmap & + acl_action_connexist)) { + + if (conntrack_mask & pkt_mask) { + if (ACL_DEBUG) + printf("ACL Conntrack Accept " + "packet = %p\n", + (void *)pkt_mask); + } else { +/* Drop packet by changing the mask */ + if (ACL_DEBUG) + printf("ACL Conntrack Drop " + "packet = %p\n", + (void *)pkt_mask); + pkts_mask &= ~pkt_mask; + p_acl->counters->pkts_drop++; + } + } + } + } + + pkts_to_process = pkts_mask; + /* bitmap of packets left to process for ARP */ + + for (; pkts_to_process;) { + uint8_t pos = (uint8_t) __builtin_ctzll(pkts_to_process); + uint64_t pkt_mask = 1LLU << pos; + /* bitmask representing only this packet */ + + pkts_to_process &= ~pkt_mask; + /* remove this packet from remaining list */ + struct rte_mbuf *pkt = pkts[pos]; + + uint8_t hdr_chk = + RTE_MBUF_METADATA_UINT8(pkt, MBUF_HDR_ROOM + ETH_HDR_SIZE); + hdr_chk = hdr_chk >> IP_VERSION_CHECK; + + if (hdr_chk == IPv4_HDR_VERSION) { + + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv4[pos]; + //uint16_t phy_port = entry->head.port_id; + uint16_t phy_port = pkt->port; + uint32_t *port_out_id = + RTE_MBUF_METADATA_UINT32_PTR(pkt, + META_DATA_OFFSET + + offsetof(struct + mbuf_acl_meta_data, + output_port)); + /* *port_out_id = p_acl->links_map[phy_port]; */ +/* if (is_phy_port_privte(phy_port)) + *port_out_id = ACL_PUB_PORT_ID; + else + *port_out_id = ACL_PRV_PORT_ID;*/ + if (ACL_DEBUG) + printf + ("phy_port = %i, links_map[phy_port] = %i\n", + phy_port, p_acl->links_map[phy_port]); + + /* header room + eth hdr size + dst_adr offset in ip header */ + uint32_t dst_addr_offset = + MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST; + uint32_t *dst_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, dst_addr_offset); + uint8_t *eth_dest = + RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM); + uint8_t *eth_src = + RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM + 6); + struct ether_addr hw_addr; + uint32_t dest_address = rte_bswap32(*dst_addr); + uint32_t *nhip = RTE_MBUF_METADATA_UINT32_PTR(pkt, + META_DATA_OFFSET + + + offsetof + (struct + mbuf_acl_meta_data, + nhip)); + uint32_t packet_length = rte_pktmbuf_pkt_len(pkt); + *nhip = 0; + if (is_phy_port_privte(phy_port)) { + dest_address = rte_bswap32(*dst_addr); + ret = + local_get_nh_ipv4(dest_address, &dest_if, + nhip, p_acl); + if (!ret) { + dest_if = + get_prv_to_pub_port(&dest_address, + IP_VERSION_4); + do_local_nh_ipv4_cache(dest_if, p_acl); + } + *port_out_id = p_acl->port_out_id[dest_if]; + } + /* port = ACL_PUB_PORT_ID; */ + else { + dest_address = rte_bswap32(*dst_addr); + + ret = local_get_nh_ipv4(dest_address, &dest_if, + nhip, p_acl); + if (!ret) { + dest_if = + get_pub_to_prv_port(&dest_address, + IP_VERSION_4); + do_local_nh_ipv4_cache(dest_if, p_acl); + }; + *port_out_id = p_acl->port_out_id[dest_if]; + } + /* port = ACL_PRV_PORT_ID; */ + int ret_mac = 0; + + ret_mac = get_dest_mac_addr_port + (dest_address, &dest_if, &hw_addr); + + if (ret_mac == ARP_FOUND) { + if (ACL_DEBUG) { + printf("MAC found for ip 0x%x, port " + "%d - %02x:%02x:%02x:%02x:%02x:%02x\n", + dest_address, phy_port, + hw_addr.addr_bytes[0], + hw_addr.addr_bytes[1], + hw_addr.addr_bytes[2], + hw_addr.addr_bytes[3], + hw_addr.addr_bytes[4], + hw_addr.addr_bytes[5]); + printf("Dest MAC before - " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + eth_dest[0], eth_dest[1], + eth_dest[2], eth_dest[3], + eth_dest[4], eth_dest[5]); + } + + memcpy(eth_dest, &hw_addr, + sizeof(struct ether_addr)); + if (ACL_DEBUG) { + printf("PktP %p, dest_macP %p\n", pkt, + eth_dest); + printf("Dest MAC after - " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + eth_dest[0], eth_dest[1], + eth_dest[2], eth_dest[3], + eth_dest[4], eth_dest[5]); + } + if (is_phy_port_privte(phy_port)) + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + else + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + p_acl->counters->tpkts_processed++; + p_acl->counters->bytes_processed += + packet_length; + } + + else { + if (*nhip != 0) { + if (ACL_DEBUG) + printf("ACL requesting ARP for " + "ip %x, port %d\n", + dest_address, phy_port); + if (ret_mac == ARP_NOT_FOUND) + request_arp(dest_if, *nhip); + + /* request_arp(p_acl->links_map[phy_port], *nhip); */ + } + /* Drop packet by changing the mask */ + if (ACL_DEBUG) + printf + ("ACL before drop pkt_mask " + "%lu, pkt_num %d\n", + pkts_mask, pos); + pkts_mask &= ~(1LLU << pos); + if (ACL_DEBUG) + printf("ACL after drop pkt_mask " + "%lu, pkt_num %d\n", + pkts_mask, pos); + p_acl->counters->pkts_drop++; + } + } +#if 0 + if (hdr_chk == IPv6_HDR_VERSION) { + + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv6[pos]; + uint16_t phy_port = entry->head.port_id; + uint32_t *port_out_id = + RTE_MBUF_METADATA_UINT32_PTR(pkt, + META_DATA_OFFSET + + offsetof(struct + mbuf_acl_meta_data, + output_port)); + if (is_phy_port_privte(phy_port)) + *port_out_id = ACL_PUB_PORT_ID; + else + *port_out_id = ACL_PRV_PORT_ID; + + /* *port_out_id = p_acl->links_map[phy_port]; */ + if (ACL_DEBUG) + printf + ("phy_port = %i, links_map[phy_port] = %i\n", + phy_port, p_acl->links_map[phy_port]); + + /* header room + eth hdr size + dst_adr offset in ip header */ + uint32_t dst_addr_offset = + MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_DST_ADR_OFST_IPV6; + uint8_t *eth_dest = + RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM); + uint8_t *eth_src = + RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM + 6); + struct ether_addr hw_addr; + uint8_t dest_address[16]; + uint8_t nhip[16]; + + nhip[0] = + RTE_MBUF_METADATA_UINT8(pkt, + META_DATA_OFFSET + + offsetof(struct + mbuf_acl_meta_data, + nhip)); + uint8_t *dst_addr[16]; + uint32_t packet_length = rte_pktmbuf_pkt_len(pkt); + int i = 0; + + for (i = 0; i < 16; i++) { + dst_addr[i] = + RTE_MBUF_METADATA_UINT8_PTR(pkt, + dst_addr_offset + + i); + } + memcpy(dest_address, *dst_addr, sizeof(dest_address)); + memset(nhip, 0, sizeof(nhip)); + if (is_phy_port_privte(phy_port)) + port = ACL_PUB_PORT_ID; + else + port = ACL_PRV_PORT_ID; + + if (get_dest_mac_address_ipv6_port + (dest_address, port, &hw_addr, &nhip[0])) { + if (ACL_DEBUG) { + + printf + ("MAC found for port %d - %02x:%02x:%02x:%02x:%02x:%02x\n", + phy_port, hw_addr.addr_bytes[0], + hw_addr.addr_bytes[1], + hw_addr.addr_bytes[2], + hw_addr.addr_bytes[3], + hw_addr.addr_bytes[4], + hw_addr.addr_bytes[5]); + printf + ("Dest MAC before - %02x:%02x:%02x:%02x:%02x:%02x\n", + eth_dest[0], eth_dest[1], + eth_dest[2], eth_dest[3], + eth_dest[4], eth_dest[5]); + } + memcpy(eth_dest, &hw_addr, + sizeof(struct ether_addr)); + if (ACL_DEBUG) { + printf("PktP %p, dest_macP %p\n", pkt, + eth_dest); + printf + ("Dest MAC after - %02x:%02x:%02x:%02x:%02x:%02x\n", + eth_dest[0], eth_dest[1], + eth_dest[2], eth_dest[3], + eth_dest[4], eth_dest[5]); + } + if (is_phy_port_privte(phy_port)) + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + else + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + + /* + * memcpy(eth_src, get_link_hw_addr(p_acl->links_map[phy_port]), + * sizeof(struct ether_addr)); + */ + p_acl->counters->tpkts_processed++; + p_acl->counters->bytes_processed += + packet_length; + } + + else { + +#if 0 + /* Request next neighbor for Ipv6 is yet to be done. */ + if (*nhip != 0) { + if (ACL_DEBUG) + printf + ("ACL requesting ARP for ip %x, port %d\n", + dest_address, phy_port); + + /* request_arp(p_acl->links_map[phy_port], *nhip); */ + } +#endif + /* Drop packet by changing the mask */ + if (ACL_DEBUG) + printf("ACL before drop pkt_mask " + " %lu, pkt_num %d\n", + pkts_mask, pos); + pkts_mask &= ~(1LLU << pos); + if (ACL_DEBUG) + printf("ACL after drop pkt_mask " + "%lu, pkt_num %d\n", + pkts_mask, pos); + p_acl->counters->pkts_drop++; + } + } +#endif + + } + + pkts_drop_mask = keep_mask & ~pkts_mask; + rte_pipeline_ah_packet_drop(p, pkts_drop_mask); + keep_mask = pkts_mask; + + /* don't bother measuring if traffic very low, might skew stats */ + uint32_t packets_this_iteration = __builtin_popcountll(pkts_mask); + + if (packets_this_iteration > 1) { + uint64_t latency_this_iteration = + rte_get_tsc_cycles() - p_acl->in_port_time_stamp; + p_acl->counters->sum_latencies += latency_this_iteration; + p_acl->counters->count_latencies++; + } + if (ACL_DEBUG) + printf("Leaving pkt_work_acl_key pkts_mask = %p\n", + (void *)pkts_mask); + + return 0; +} + +/** + * Main packet processing function. + * 64 packet bit mask are used to identify which packets to forward. + * Performs the following: + * - Burst lookup packets in the IPv4 ACL Rule Table. + * - Burst lookup packets in the IPv6 ACL Rule Table. + * - Lookup Action Table, perform actions. + * - Burst lookup Connection Tracking, if enabled. + * - Lookup MAC address. + * - Set bit mask. + * - Packets with bit mask set are forwarded + * + * @param p + * A pointer to the pipeline. + * @param pkts + * A pointer to a burst of packets. + * @param n_pkts + * Number of packets to process. + * @param arg + * A pointer to pipeline specific data. + * + * @return + * 0 on success, negative on error. + */ +static int +pkt_work_acl_ipv6_key(struct rte_pipeline *p, + struct rte_mbuf **pkts, uint32_t n_pkts, void *arg) +{ + + struct pipeline_acl *p_acl = arg; + + p_acl->counters->pkts_received = + p_acl->counters->pkts_received + n_pkts; + if (ACL_DEBUG) + printf("pkt_work_acl_key pkts_received: %" PRIu64 + " n_pkts: %u\n", p_acl->counters->pkts_received, n_pkts); + + uint64_t lookup_hit_mask = 0; + uint64_t lookup_hit_mask_ipv4 = 0; + uint64_t lookup_hit_mask_ipv6 = 0; + uint64_t lookup_miss_mask = 0; + uint64_t conntrack_mask = 0; + uint64_t connexist_mask = 0; + uint32_t dest_address = 0; + int dest_if = 0; + int status; + uint64_t pkts_drop_mask, pkts_mask = RTE_LEN2MASK(n_pkts, uint64_t); + uint64_t keep_mask = pkts_mask; + uint16_t port; + uint32_t ret; + + p_acl->in_port_time_stamp = rte_get_tsc_cycles(); + + if (acl_ipv6_enabled) { + if (ACL_DEBUG) + printf("ACL IPV6 Lookup Mask Before = %p\n", + (void *)pkts_mask); + status = + rte_table_acl_ops.f_lookup(acl_rule_table_ipv6_active, pkts, + pkts_mask, &lookup_hit_mask_ipv6, + (void **) + p_acl->acl_entries_ipv6); + if (ACL_DEBUG) + printf("ACL IPV6 Lookup Mask After = %p\n", + (void *)lookup_hit_mask_ipv6); + } + + /* Merge lookup results since we process both IPv4 and IPv6 below */ + lookup_hit_mask = lookup_hit_mask_ipv4 | lookup_hit_mask_ipv6; + if (ACL_DEBUG) + printf("ACL Lookup Mask After = %p\n", (void *)lookup_hit_mask); + + lookup_miss_mask = pkts_mask & (~lookup_hit_mask); + pkts_mask = lookup_hit_mask; + p_acl->counters->pkts_drop += __builtin_popcountll(lookup_miss_mask); + if (ACL_DEBUG) + printf("pkt_work_acl_key pkts_drop: %" PRIu64 " n_pkts: %u\n", + p_acl->counters->pkts_drop, + __builtin_popcountll(lookup_miss_mask)); + + uint64_t pkts_to_process = lookup_hit_mask; + /* bitmap of packets left to process for ARP */ + + for (; pkts_to_process;) { + uint8_t pos = (uint8_t) __builtin_ctzll(pkts_to_process); + uint64_t pkt_mask = 1LLU << pos; + /* bitmask representing only this packet */ + + pkts_to_process &= ~pkt_mask; + /* remove this packet from remaining list */ + struct rte_mbuf *pkt = pkts[pos]; + + if (enable_hwlb) + if (!check_arp_icmp(pkt, pkt_mask, p_acl)) { + pkts_mask &= ~(1LLU << pos); + continue; + } + uint8_t hdr_chk = + RTE_MBUF_METADATA_UINT8(pkt, MBUF_HDR_ROOM + ETH_HDR_SIZE); + hdr_chk = hdr_chk >> IP_VERSION_CHECK; +#if 0 + if (hdr_chk == IPv4_HDR_VERSION) { + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv4[pos]; + uint16_t phy_port = entry->head.port_id; + uint32_t action_id = entry->action_id; + + if (ACL_DEBUG) + printf("action_id = %u\n", action_id); + + uint32_t dscp_offset = + MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DSCP_OFST; + + if (action_array_active[action_id].action_bitmap & + acl_action_count) { + action_counter_table + [p_acl->action_counter_index] + [action_id].packetCount++; + action_counter_table + [p_acl->action_counter_index] + [action_id].byteCount += + rte_pktmbuf_pkt_len(pkt); + if (ACL_DEBUG) + printf("Action Count Packet Count: %" + PRIu64 " Byte Count: %" PRIu64 + "\n", + action_counter_table + [p_acl->action_counter_index] + [action_id].packetCount, + action_counter_table + [p_acl->action_counter_index] + [action_id].byteCount); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_packet_drop) { + + /* Drop packet by changing the mask */ + if (ACL_DEBUG) + printf + ("ACL before drop pkt_mask %lu, pkt_num %d\n", + pkts_mask, pos); + pkts_mask &= ~(1LLU << pos); + if (ACL_DEBUG) + printf + ("ACL after drop pkt_mask %lu, pkt_num %d\n", + pkts_mask, pos); + p_acl->counters->pkts_drop++; + } + + if (action_array_active[action_id].action_bitmap & + acl_action_fwd) { + phy_port = + action_array_active[action_id].fwd_port; + entry->head.port_id = phy_port; + if (ACL_DEBUG) + printf("Action FWD Port ID: %u\n", + phy_port); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_nat) { + phy_port = + action_array_active[action_id].nat_port; + entry->head.port_id = phy_port; + if (ACL_DEBUG) + printf("Action NAT Port ID: %u\n", + phy_port); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_dscp) { + + /* Set DSCP priority */ + uint8_t *dscp = RTE_MBUF_METADATA_UINT8_PTR(pkt, + dscp_offset); + *dscp = + action_array_active[action_id].dscp_priority + << 2; + if (ACL_DEBUG) + printf + ("Action DSCP DSCP Priority: %u\n", + *dscp); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_packet_accept) { + if (ACL_DEBUG) + printf("Action Accept\n"); + + if (action_array_active[action_id].action_bitmap + & acl_action_conntrack) { + + /* Set conntrack bit for this pkt */ + conntrack_mask |= pkt_mask; + if (ACL_DEBUG) + printf("ACL Conntrack enabled: " + " %p pkt_mask: %p\n", + (void *)conntrack_mask, + (void *)pkt_mask); + } + + if (action_array_active[action_id].action_bitmap + & acl_action_connexist) { + + /* Set conntrack bit for this pkt */ + conntrack_mask |= pkt_mask; + + /* Set connexist bit for this pkt for public -> private */ + /* Private -> public packet will open the connection */ + if (action_array_active + [action_id].private_public == + acl_public_private) + connexist_mask |= pkt_mask; + + if (ACL_DEBUG) + printf("ACL Connexist enabled " + "conntrack: %p connexist: %p pkt_mask: %p\n", + (void *)conntrack_mask, + (void *)connexist_mask, + (void *)pkt_mask); + } + } + } +#endif + + if (hdr_chk == IPv6_HDR_VERSION) { + + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv6[pos]; + uint16_t phy_port = entry->head.port_id; + uint32_t action_id = entry->action_id; + + if (ACL_DEBUG) + printf("action_id = %u\n", action_id); + + if (action_array_active[action_id].action_bitmap & + acl_action_count) { + action_counter_table + [p_acl->action_counter_index] + [action_id].packetCount++; + action_counter_table + [p_acl->action_counter_index] + [action_id].byteCount += + rte_pktmbuf_pkt_len(pkt); + if (ACL_DEBUG) + printf("Action Count Packet Count: %" + PRIu64 " Byte Count: %" PRIu64 + "\n", + action_counter_table + [p_acl->action_counter_index] + [action_id].packetCount, + action_counter_table + [p_acl->action_counter_index] + [action_id].byteCount); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_packet_drop) { + /* Drop packet by changing the mask */ + if (ACL_DEBUG) + printf("ACL before drop pkt_mask " + "%lu, pkt_num %d\n", + pkts_mask, pos); + pkts_mask &= ~(1LLU << pos); + if (ACL_DEBUG) + printf("ACL after drop pkt_mask " + "%lu, pkt_num %d\n", + pkts_mask, pos); + p_acl->counters->pkts_drop++; + + } + + if (action_array_active[action_id].action_bitmap & + acl_action_fwd) { + phy_port = + action_array_active[action_id].fwd_port; + entry->head.port_id = phy_port; + if (ACL_DEBUG) + printf("Action FWD Port ID: %u\n", + phy_port); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_nat) { + phy_port = + action_array_active[action_id].nat_port; + entry->head.port_id = phy_port; + if (ACL_DEBUG) + printf("Action NAT Port ID: %u\n", + phy_port); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_dscp) { + + /* Set DSCP priority */ + uint32_t dscp_offset = + MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_DSCP_OFST_IPV6; + uint16_t *dscp = + RTE_MBUF_METADATA_UINT16_PTR(pkt, + dscp_offset); + uint16_t dscp_value = + (rte_bswap16 + (RTE_MBUF_METADATA_UINT16 + (pkt, dscp_offset)) & 0XF00F); + uint8_t dscp_store = + action_array_active[action_id].dscp_priority + << 2; + uint16_t dscp_temp = dscp_store; + + dscp_temp = dscp_temp << 4; + *dscp = rte_bswap16(dscp_temp | dscp_value); + if (ACL_DEBUG) + printf + ("Action DSCP DSCP Priority: %u\n", + *dscp); + } + + if (action_array_active[action_id].action_bitmap & + acl_action_packet_accept) { + if (ACL_DEBUG) + printf("Action Accept\n"); + + if (action_array_active[action_id].action_bitmap + & acl_action_conntrack) { + + /* Set conntrack bit for this pkt */ + conntrack_mask |= pkt_mask; + if (ACL_DEBUG) + printf("ACL Conntrack enabled: " + " %p pkt_mask: %p\n", + (void *)conntrack_mask, + (void *)pkt_mask); + } + + if (action_array_active[action_id].action_bitmap + & acl_action_connexist) { + + /* Set conntrack bit for this pkt */ + conntrack_mask |= pkt_mask; + + /* Set connexist bit for this pkt for public -> private */ + /* Private -> public packet will open the connection */ + if (action_array_active + [action_id].private_public == + acl_public_private) + connexist_mask |= pkt_mask; + + if (ACL_DEBUG) + printf("ACL Connexist enabled " + "conntrack: %p connexist: %p pkt_mask: %p\n", + (void *)conntrack_mask, + (void *)connexist_mask, + (void *)pkt_mask); + } + } + } + } + /* Only call connection tracker if required */ + if (conntrack_mask > 0) { + if (ACL_DEBUG) + printf + ("ACL Call Conntrack Before = %p Connexist = %p\n", + (void *)conntrack_mask, (void *)connexist_mask); + conntrack_mask = + rte_ct_cnxn_tracker_batch_lookup_with_new_cnxn_control + (p_acl->cnxn_tracker, pkts, conntrack_mask, connexist_mask); + if (ACL_DEBUG) + printf("ACL Call Conntrack After = %p\n", + (void *)conntrack_mask); + + /* Only change pkt mask for pkts that have conntrack enabled */ + /* Need to loop through packets to check if conntrack enabled */ + pkts_to_process = pkts_mask; + for (; pkts_to_process;) { + uint32_t action_id = 0; + uint8_t pos = + (uint8_t) __builtin_ctzll(pkts_to_process); + uint64_t pkt_mask = 1LLU << pos; + /* bitmask representing only this packet */ + + pkts_to_process &= ~pkt_mask; + /* remove this packet from remaining list */ + struct rte_mbuf *pkt = pkts[pos]; + + uint8_t hdr_chk = RTE_MBUF_METADATA_UINT8(pkt, + MBUF_HDR_ROOM + + + ETH_HDR_SIZE); + hdr_chk = hdr_chk >> IP_VERSION_CHECK; + if (hdr_chk == IPv4_HDR_VERSION) { + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv4[pos]; + action_id = entry->action_id; + } else { + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv6[pos]; + action_id = entry->action_id; + } + + if ((action_array_active[action_id].action_bitmap & + acl_action_conntrack) + || (action_array_active[action_id].action_bitmap & + acl_action_connexist)) { + + if (conntrack_mask & pkt_mask) { + if (ACL_DEBUG) + printf("ACL Conntrack Accept " + "packet = %p\n", + (void *)pkt_mask); + } else { +/* Drop packet by changing the mask */ + if (ACL_DEBUG) + printf + ("ACL Conntrack Drop packet = %p\n", + (void *)pkt_mask); + pkts_mask &= ~pkt_mask; + p_acl->counters->pkts_drop++; + } + } + } + } + + pkts_to_process = pkts_mask; + /* bitmap of packets left to process for ARP */ + + for (; pkts_to_process;) { + uint8_t pos = (uint8_t) __builtin_ctzll(pkts_to_process); + uint64_t pkt_mask = 1LLU << pos; + /* bitmask representing only this packet */ + + pkts_to_process &= ~pkt_mask; + /* remove this packet from remaining list */ + struct rte_mbuf *pkt = pkts[pos]; + + uint8_t hdr_chk = + RTE_MBUF_METADATA_UINT8(pkt, MBUF_HDR_ROOM + ETH_HDR_SIZE); + hdr_chk = hdr_chk >> IP_VERSION_CHECK; +#if 0 + if (hdr_chk == IPv4_HDR_VERSION) { + + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv4[pos]; + uint16_t phy_port = entry->head.port_id; + uint32_t *port_out_id = + RTE_MBUF_METADATA_UINT32_PTR(pkt, + META_DATA_OFFSET + + offsetof(struct + mbuf_acl_meta_data, + output_port)); + /* *port_out_id = p_acl->links_map[phy_port]; */ + if (is_phy_port_privte(phy_port)) + *port_out_id = ACL_PUB_PORT_ID; + else + *port_out_id = ACL_PRV_PORT_ID; + if (ACL_DEBUG) + printf + ("phy_port = %i,links_map[phy_port] = %i\n", + phy_port, p_acl->links_map[phy_port]); + + /* header room + eth hdr size + dst_adr offset in ip header */ + uint32_t dst_addr_offset = + MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST; + uint32_t *dst_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, dst_addr_offset); + uint8_t *eth_dest = + RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM); + uint8_t *eth_src = + RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM + 6); + struct ether_addr hw_addr; + uint32_t dest_address = rte_bswap32(*dst_addr); + uint32_t *nhip = RTE_MBUF_METADATA_UINT32_PTR(pkt, + META_DATA_OFFSET + + + offsetof + (struct + mbuf_acl_meta_data, + nhip)); + uint32_t packet_length = rte_pktmbuf_pkt_len(pkt); + *nhip = 0; + if (is_phy_port_privte(phy_port)) { + dest_address = rte_bswap32(*dst_addr); + ret = + local_get_nh_ipv4(dest_address, &dest_if, + nhip, p_acl); + if (!ret) { + dest_if = + get_prv_to_pub_port(&dest_address, + IP_VERSION_4); + do_local_nh_ipv4_cache(dest_if, p_acl); + } + *port_out_id = p_acl->port_out_id[dest_if]; + } + /* port = ACL_PUB_PORT_ID; */ + else { + dest_address = rte_bswap32(*dst_addr); + + ret = local_get_nh_ipv4(dest_address, &dest_if, + nhip, p_acl); + if (!ret) { + dest_if = + get_pub_to_prv_port(&dest_address, + IP_VERSION_4); + do_local_nh_ipv4_cache(dest_if, p_acl); + }; + *port_out_id = p_acl->port_out_id[dest_if]; + } + /* port = ACL_PRV_PORT_ID; */ + + if (get_dest_mac_addr_port + (dest_address, &dest_if, &hw_addr)) { + if (ACL_DEBUG) { + printf("MAC found for ip 0x%x, port " + " %d - %02x:%02x:%02x:%02x:%02x:%02x\n", + dest_address, phy_port, + hw_addr.addr_bytes[0], + hw_addr.addr_bytes[1], + hw_addr.addr_bytes[2], + hw_addr.addr_bytes[3], + hw_addr.addr_bytes[4], + hw_addr.addr_bytes[5]); + printf("Dest MAC before - " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + eth_dest[0], eth_dest[1], + eth_dest[2], eth_dest[3], + eth_dest[4], eth_dest[5]); + } + + memcpy(eth_dest, &hw_addr, + sizeof(struct ether_addr)); + if (ACL_DEBUG) { + printf("PktP %p, dest_macP %p\n", pkt, + eth_dest); + printf("Dest MAC after - " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + eth_dest[0], eth_dest[1], + eth_dest[2], eth_dest[3], + eth_dest[4], eth_dest[5]); + } + if (is_phy_port_privte(phy_port)) + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + else + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + p_acl->counters->tpkts_processed++; + p_acl->counters->bytes_processed += + packet_length; + } + + else { + if (*nhip != 0) { + + if (ACL_DEBUG) + + printf("ACL requesting ARP for " + " ip %x, port %d\n", + dest_address, phy_port); + if (is_phy_port_privte(phy_port)) + request_arp(dest_if, *nhip); + + else + request_arp(dest_if, *nhip); + + /* request_arp(p_acl->links_map[phy_port], *nhip); */ + } + /* Drop packet by changing the mask */ + if (ACL_DEBUG) + printf("ACL before drop pkt_mask " + "%lu, pkt_num %d\n", + pkts_mask, pos); + pkts_mask &= ~(1LLU << pos); + if (ACL_DEBUG) + printf("ACL after drop pkt_mask " + "%lu, pkt_num %d\n", + pkts_mask, pos); + p_acl->counters->pkts_drop++; + } + } +#endif + + if (hdr_chk == IPv6_HDR_VERSION) { + + struct acl_table_entry *entry = + (struct acl_table_entry *) + p_acl->acl_entries_ipv6[pos]; + //uint16_t phy_port = entry->head.port_id; + uint16_t phy_port = pkt->port; + uint32_t *port_out_id = + RTE_MBUF_METADATA_UINT32_PTR(pkt, + META_DATA_OFFSET + + offsetof(struct + mbuf_acl_meta_data, + output_port)); + /* if (is_phy_port_privte(phy_port)) + *port_out_id = ACL_PUB_PORT_ID; + else + *port_out_id = ACL_PRV_PORT_ID;*/ + + /* *port_out_id = p_acl->links_map[phy_port]; */ + if (ACL_DEBUG) + printf + ("phy_port = %i,links_map[phy_port] = %i\n", + phy_port, p_acl->links_map[phy_port]); + + /* header room + eth hdr size + dst_adr offset in ip header */ + uint32_t dst_addr_offset = + MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_DST_ADR_OFST_IPV6; + uint8_t *eth_dest = + RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM); + uint8_t *eth_src = + RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM + 6); + struct ether_addr hw_addr; + uint8_t dest_address[16]; + uint8_t nhip[16]; + + nhip[0] = + RTE_MBUF_METADATA_UINT8(pkt, + META_DATA_OFFSET + + offsetof(struct + mbuf_acl_meta_data, + nhip)); + uint8_t *dst_addr[16]; + uint32_t packet_length = rte_pktmbuf_pkt_len(pkt); + int i = 0; + + for (i = 0; i < 16; i++) { + dst_addr[i] = + RTE_MBUF_METADATA_UINT8_PTR(pkt, + dst_addr_offset + + i); + } + memcpy(dest_address, *dst_addr, sizeof(dest_address)); + memset(nhip, 0, sizeof(nhip)); + ret = local_get_nh_ipv6(&dest_address[0], &dest_if, + &nhip[0], p_acl); + + if (is_phy_port_privte(phy_port)) { + if (!ret) { + dest_if = get_prv_to_pub_port(( + uint32_t + *) + &dest_address[0], IP_VERSION_6); + do_local_nh_ipv6_cache(dest_if, p_acl); + } + // port = ACL_PUB_PORT_ID; + *port_out_id = + p_acl->port_out_id[dest_if]; + + } else { + if (!ret) { + dest_if = get_pub_to_prv_port(( + uint32_t + *) + &dest_address[0], IP_VERSION_6); + do_local_nh_ipv6_cache(dest_if, p_acl); + } + // port = ACL_PRV_PORT_ID; + *port_out_id = + p_acl->port_out_id[dest_if]; + + } + + if (get_dest_mac_address_ipv6_port + (dest_address, &dest_if, &hw_addr, &nhip[0])) { + if (ACL_DEBUG) { + printf("MAC found for port %d " + "- %02x:%02x:%02x:%02x:%02x:%02x\n", + phy_port, hw_addr.addr_bytes[0], + hw_addr.addr_bytes[1], + hw_addr.addr_bytes[2], + hw_addr.addr_bytes[3], + hw_addr.addr_bytes[4], + hw_addr.addr_bytes[5]); + printf("Dest MAC before - " + " %02x:%02x:%02x:%02x:%02x:%02x\n", + eth_dest[0], eth_dest[1], + eth_dest[2], eth_dest[3], + eth_dest[4], eth_dest[5]); + } + memcpy(eth_dest, &hw_addr, + sizeof(struct ether_addr)); + if (ACL_DEBUG) { + printf("PktP %p, dest_macP %p\n", pkt, + eth_dest); + printf("Dest MAC after - " + " %02x:%02x:%02x:%02x:%02x:%02x\n", + eth_dest[0], eth_dest[1], + eth_dest[2], eth_dest[3], + eth_dest[4], eth_dest[5]); + } + if (is_phy_port_privte(phy_port)) + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + else + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + + /* + * memcpy(eth_src, get_link_hw_addr(p_acl->links_map[phy_port]), + * sizeof(struct ether_addr)); + */ + p_acl->counters->tpkts_processed++; + p_acl->counters->bytes_processed += + packet_length; + } + + else { + +#if 0 + /* Request next neighbor for Ipv6 is yet to be done. */ + if (*nhip != 0) { + if (ACL_DEBUG) + printf + ("ACL requesting ARP for ip %x, port %d\n", + dest_address, phy_port); + + /* request_arp(p_acl->links_map[phy_port], *nhip); */ + } +#endif + /* Drop packet by changing the mask */ + if (ACL_DEBUG) + printf("ACL before drop pkt_mask " + " %lu, pkt_num %d\n", + pkts_mask, pos); + pkts_mask &= ~(1LLU << pos); + if (ACL_DEBUG) + printf("ACL after drop pkt_mask " + " %lu, pkt_num %d\n", + pkts_mask, pos); + p_acl->counters->pkts_drop++; + } + } + + } + + pkts_drop_mask = keep_mask & ~pkts_mask; + rte_pipeline_ah_packet_drop(p, pkts_drop_mask); + keep_mask = pkts_mask; + + /* don't bother measuring if traffic very low, might skew stats */ + uint32_t packets_this_iteration = __builtin_popcountll(pkts_mask); + + if (packets_this_iteration > 1) { + uint64_t latency_this_iteration = + rte_get_tsc_cycles() - p_acl->in_port_time_stamp; + p_acl->counters->sum_latencies += latency_this_iteration; + p_acl->counters->count_latencies++; + } + if (ACL_DEBUG) + printf("Leaving pkt_work_acl_key pkts_mask = %p\n", + (void *)pkts_mask); + + return 0; +} + +static struct rte_acl_field_def field_format_ipv4[] = { + /* Protocol */ + [0] = { + .type = RTE_ACL_FIELD_TYPE_BITMASK, + .size = sizeof(uint8_t), + .field_index = 0, + .input_index = 0, + .offset = sizeof(struct ether_hdr) + + offsetof(struct ipv4_hdr, next_proto_id), + }, + + /* Source IP address (IPv4) */ + [1] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 1, + .input_index = 1, + .offset = sizeof(struct ether_hdr) + + offsetof(struct ipv4_hdr, src_addr), + }, + + /* Destination IP address (IPv4) */ + [2] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 2, + .input_index = 2, + .offset = sizeof(struct ether_hdr) + + offsetof(struct ipv4_hdr, dst_addr), + }, + + /* Source Port */ + [3] = { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = 3, + .input_index = 3, + .offset = sizeof(struct ether_hdr) + + sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, src_port), + }, + + /* Destination Port */ + [4] = { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = 4, + .input_index = 3, + .offset = sizeof(struct ether_hdr) + + sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, dst_port), + }, +}; + +#define SIZEOF_VLAN_HDR 4 + +static struct rte_acl_field_def field_format_vlan_ipv4[] = { + /* Protocol */ + [0] = { + .type = RTE_ACL_FIELD_TYPE_BITMASK, + .size = sizeof(uint8_t), + .field_index = 0, + .input_index = 0, + .offset = sizeof(struct ether_hdr) + + SIZEOF_VLAN_HDR + offsetof(struct ipv4_hdr, next_proto_id), + }, + + /* Source IP address (IPv4) */ + [1] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 1, + .input_index = 1, + .offset = sizeof(struct ether_hdr) + + SIZEOF_VLAN_HDR + offsetof(struct ipv4_hdr, src_addr), + }, + + /* Destination IP address (IPv4) */ + [2] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 2, + .input_index = 2, + .offset = sizeof(struct ether_hdr) + + SIZEOF_VLAN_HDR + offsetof(struct ipv4_hdr, dst_addr), + }, + + /* Source Port */ + [3] = { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = 3, + .input_index = 3, + .offset = sizeof(struct ether_hdr) + + SIZEOF_VLAN_HDR + + sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, src_port), + }, + + /* Destination Port */ + [4] = { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = 4, + .input_index = 4, + .offset = sizeof(struct ether_hdr) + + SIZEOF_VLAN_HDR + + sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, dst_port), + }, +}; + +#define SIZEOF_QINQ_HEADER 8 + +static struct rte_acl_field_def field_format_qinq_ipv4[] = { + /* Protocol */ + [0] = { + .type = RTE_ACL_FIELD_TYPE_BITMASK, + .size = sizeof(uint8_t), + .field_index = 0, + .input_index = 0, + .offset = sizeof(struct ether_hdr) + + SIZEOF_QINQ_HEADER + offsetof(struct ipv4_hdr, next_proto_id), + }, + + /* Source IP address (IPv4) */ + [1] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 1, + .input_index = 1, + .offset = sizeof(struct ether_hdr) + + SIZEOF_QINQ_HEADER + offsetof(struct ipv4_hdr, src_addr), + }, + + /* Destination IP address (IPv4) */ + [2] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 2, + .input_index = 2, + .offset = sizeof(struct ether_hdr) + + SIZEOF_QINQ_HEADER + offsetof(struct ipv4_hdr, dst_addr), + }, + + /* Source Port */ + [3] = { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = 3, + .input_index = 3, + .offset = sizeof(struct ether_hdr) + + SIZEOF_QINQ_HEADER + + sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, src_port), + }, + + /* Destination Port */ + [4] = { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = 4, + .input_index = 4, + .offset = sizeof(struct ether_hdr) + + SIZEOF_QINQ_HEADER + + sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, dst_port), + }, +}; + +static struct rte_acl_field_def field_format_ipv6[] = { + /* Protocol */ + [0] = { + .type = RTE_ACL_FIELD_TYPE_BITMASK, + .size = sizeof(uint8_t), + .field_index = 0, + .input_index = 0, + .offset = sizeof(struct ether_hdr) + + offsetof(struct ipv6_hdr, proto), + }, + + /* Source IP address (IPv6) */ + [1] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 1, + .input_index = 1, + .offset = sizeof(struct ether_hdr) + + offsetof(struct ipv6_hdr, src_addr), + }, + + [2] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 2, + .input_index = 2, + .offset = sizeof(struct ether_hdr) + + offsetof(struct ipv6_hdr, src_addr) + sizeof(uint32_t), + } + , + + [3] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 3, + .input_index = 3, + .offset = sizeof(struct ether_hdr) + + offsetof(struct ipv6_hdr, src_addr) + 2 * sizeof(uint32_t), + } + , + + [4] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 4, + .input_index = 4, + .offset = sizeof(struct ether_hdr) + + offsetof(struct ipv6_hdr, src_addr) + 3 * sizeof(uint32_t), + } + , + + /* Destination IP address (IPv6) */ + [5] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 5, + .input_index = 5, + .offset = sizeof(struct ether_hdr) + + offsetof(struct ipv6_hdr, dst_addr), + }, + + [6] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 6, + .input_index = 6, + .offset = sizeof(struct ether_hdr) + + offsetof(struct ipv6_hdr, dst_addr) + sizeof(uint32_t), + } + , + + [7] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 7, + .input_index = 7, + .offset = sizeof(struct ether_hdr) + + offsetof(struct ipv6_hdr, dst_addr) + 2 * sizeof(uint32_t), + } + , + + [8] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 8, + .input_index = 8, + .offset = sizeof(struct ether_hdr) + + offsetof(struct ipv6_hdr, dst_addr) + 3 * sizeof(uint32_t), + } + , + + /* Source Port */ + [9] = { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = 9, + .input_index = 9, + .offset = sizeof(struct ether_hdr) + + sizeof(struct ipv6_hdr) + offsetof(struct tcp_hdr, src_port), + }, + + /* Destination Port */ + [10] = { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = 10, + .input_index = 9, + .offset = sizeof(struct ether_hdr) + + sizeof(struct ipv6_hdr) + offsetof(struct tcp_hdr, dst_port), + }, +}; + +/** + * Parse arguments in config file. + * + * @param p + * A pointer to the pipeline. + * @param params + * A pointer to pipeline specific parameters. + * + * @return + * 0 on success, negative on error. + */ +static int +pipeline_acl_parse_args(struct pipeline_acl *p, struct pipeline_params *params) +{ + uint32_t n_rules_present = 0; + uint32_t pkt_type_present = 0; + uint32_t i; + uint8_t prv_que_handler_present = 0; + uint8_t n_prv_in_port = 0; + + /* defaults */ + p->n_rules = 4 * 1024; + acl_n_rules = 4 * 1024; + p->n_rule_fields = RTE_DIM(field_format_ipv4); + p->field_format = field_format_ipv4; + p->field_format_size = sizeof(field_format_ipv4); + + for (i = 0; i < params->n_args; i++) { + char *arg_name = params->args_name[i]; + char *arg_value = params->args_value[i]; + + if (strcmp(arg_name, "n_rules") == 0) { + if (n_rules_present) + return -1; + n_rules_present = 1; + + p->n_rules = atoi(arg_value); + acl_n_rules = atoi(arg_value); + continue; + } + + if (strcmp(arg_name, "pkt_type") == 0) { + if (pkt_type_present) + return -1; + pkt_type_present = 1; + + /* ipv4 */ + if (strcmp(arg_value, "ipv4") == 0) { + p->n_rule_fields = RTE_DIM(field_format_ipv4); + p->field_format = field_format_ipv4; + p->field_format_size = + sizeof(field_format_ipv4); + continue; + } + + /* vlan_ipv4 */ + if (strcmp(arg_value, "vlan_ipv4") == 0) { + p->n_rule_fields = + RTE_DIM(field_format_vlan_ipv4); + p->field_format = field_format_vlan_ipv4; + p->field_format_size = + sizeof(field_format_vlan_ipv4); + continue; + } + + /* qinq_ipv4 */ + if (strcmp(arg_value, "qinq_ipv4") == 0) { + p->n_rule_fields = + RTE_DIM(field_format_qinq_ipv4); + p->field_format = field_format_qinq_ipv4; + p->field_format_size = + sizeof(field_format_qinq_ipv4); + continue; + } + + /* ipv6 */ + if (strcmp(arg_value, "ipv6") == 0) { + p->n_rule_fields = RTE_DIM(field_format_ipv6); + p->field_format = field_format_ipv6; + p->field_format_size = + sizeof(field_format_ipv6); + continue; + } + + /* other */ + return -1; + } + /* traffic_type */ + if (strcmp(arg_name, "traffic_type") == 0) { + int traffic_type = atoi(arg_value); + + if (traffic_type == 0 + || !(traffic_type == IPv4_HDR_VERSION + || traffic_type == IPv6_HDR_VERSION)) { + printf("not IPVR4/IPVR6"); + return -1; + } + + p->traffic_type = traffic_type; + continue; + } + + if (strcmp(arg_name, "prv_que_handler") == 0) { + + if (prv_que_handler_present) { + printf("Duplicate pktq_in_prv ..\n\n"); + return -1; + } + prv_que_handler_present = 1; + n_prv_in_port = 0; + + char *token; + int rxport = 0; + /* get the first token */ + token = strtok(arg_value, "("); + token = strtok(token, ")"); + token = strtok(token, ","); + printf("***** prv_que_handler *****\n"); + + if (token == NULL){ + printf("string is null\n"); + printf("prv_que_handler is invalid\n"); + return -1; + } + printf("string is :%s\n", token); + + while (token != NULL) { + printf(" %s\n", token); + rxport = atoi(token); + acl_prv_que_port_index[n_prv_in_port++] = + rxport; + token = strtok(NULL, ","); + } + + if (n_prv_in_port == 0) { + printf("VNF common parse err - no prv RX phy port\n"); + return -1; + } + continue; + } + + /* n_flows */ + if (strcmp(arg_name, "n_flows") == 0) { + p->n_flows = atoi(arg_value); + if (p->n_flows == 0) + return -1; + + continue;/* needed when multiple parms are checked */ + } + + } + + return 0; +} + +/** + * Create and initialize Pipeline Back End (BE). + * + * @param params + * A pointer to the pipeline. + * @param arg + * A pointer to pipeline specific data. + * + * @return + * A pointer to the pipeline create, NULL on error. + */ +static void *pipeline_acl_init(struct pipeline_params *params, + __rte_unused void *arg) +{ + struct pipeline *p; + struct pipeline_acl *p_acl; + uint32_t size, i; + + /* Check input arguments */ + if ((params == NULL) || + (params->n_ports_in == 0) || (params->n_ports_out == 0)) + return NULL; + + /* Memory allocation */ + size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_acl)); + p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE); + p_acl = (struct pipeline_acl *)p; + if (p == NULL) + return NULL; + + strcpy(p->name, params->name); + p->log_level = params->log_level; + + PLOG(p, HIGH, "ACL"); + + /* + * p_acl->links_map[0] = 0xff; + * p_acl->links_map[1] = 0xff;] + */ + p_acl->traffic_type = MIX; + for (i = 0; i < PIPELINE_MAX_PORT_IN; i++) { + p_acl->links_map[i] = 0xff; + p_acl->port_out_id[i] = 0xff; + acl_prv_que_port_index[i] = 0; + } + + p_acl->pipeline_num = 0xff; + + /* if(enable_hwlb || enable_flow_dir) */ +// lib_arp_init(params, arg); + + p_acl->n_flows = 4096; /* small default value */ + /* Create a single firewall instance and initialize. */ + p_acl->cnxn_tracker = + rte_zmalloc(NULL, rte_ct_get_cnxn_tracker_size(), + RTE_CACHE_LINE_SIZE); + + if (p_acl->cnxn_tracker == NULL) + return NULL; + + /* + * Now allocate a counter block entry.It appears that the initialization + * of all instances is serialized on core 0, so no lock is necessary. + */ + struct rte_ACL_counter_block *counter_ptr; + + if (rte_ACL_hi_counter_block_in_use == MAX_ACL_INSTANCES) { + /* error, exceeded table bounds */ + return NULL; + } + + rte_ACL_hi_counter_block_in_use++; + counter_ptr = &rte_acl_counter_table[rte_ACL_hi_counter_block_in_use]; + strcpy(counter_ptr->name, params->name); + p_acl->action_counter_index = rte_ACL_hi_counter_block_in_use; + + p_acl->counters = counter_ptr; + + rte_ct_initialize_default_timeouts(p_acl->cnxn_tracker); + p_acl->arpPktCount = 0; + + /* Parse arguments */ + if (pipeline_acl_parse_args(p_acl, params)) + return NULL; + /*n_flows already checked, ignore Klockwork issue */ + if (p_acl->n_flows > 0) { + rte_ct_initialize_cnxn_tracker(p_acl->cnxn_tracker, + p_acl->n_flows, params->name); + p_acl->counters->ct_counters = + rte_ct_get_counter_address(p_acl->cnxn_tracker); + } else { + printf("ACL invalid p_acl->n_flows: %u\n", p_acl->n_flows); + return NULL; + } + + /* Pipeline */ + { + struct rte_pipeline_params pipeline_params = { + .name = params->name, + .socket_id = params->socket_id, + .offset_port_id = META_DATA_OFFSET + + offsetof(struct mbuf_acl_meta_data, output_port), + }; + + p->p = rte_pipeline_create(&pipeline_params); + if (p->p == NULL) { + rte_free(p); + return NULL; + } + } + + /* Input ports */ + p->n_ports_in = params->n_ports_in; + for (i = 0; i < p->n_ports_in; i++) { + struct rte_pipeline_port_in_params port_params = { + .ops = + pipeline_port_in_params_get_ops(¶ms->port_in + [i]), + .arg_create = + pipeline_port_in_params_convert(¶ms->port_in + [i]), + .f_action = pkt_work_acl_key, + .arg_ah = p_acl, + .burst_size = params->port_in[i].burst_size, + }; + if (p_acl->traffic_type == IPv4_HDR_VERSION) + port_params.f_action = pkt_work_acl_ipv4_key; + + if (p_acl->traffic_type == IPv6_HDR_VERSION) + port_params.f_action = pkt_work_acl_ipv6_key; + + int status = rte_pipeline_port_in_create(p->p, + &port_params, + &p->port_in_id[i]); + + if (status) { + rte_pipeline_free(p->p); + rte_free(p); + return NULL; + } + } + + /* Output ports */ + p->n_ports_out = params->n_ports_out; + for (i = 0; i < p->n_ports_out; i++) { + struct rte_pipeline_port_out_params port_params = { + .ops = + pipeline_port_out_params_get_ops(¶ms->port_out + [i]), + .arg_create = + pipeline_port_out_params_convert(¶ms->port_out + [i]), + .f_action = NULL, + .arg_ah = NULL, + }; + + int status = rte_pipeline_port_out_create(p->p, + &port_params, + &p->port_out_id[i]); + + if (status) { + rte_pipeline_free(p->p); + rte_free(p); + return NULL; + } + } + + int pipeline_num = 0; + + int temp = sscanf(params->name, "PIPELINE%d", &pipeline_num); + p_acl->pipeline_num = (uint8_t) pipeline_num; +/* set_phy_outport_map(p_acl->pipeline_num, p_acl->links_map);*/ + register_pipeline_Qs(p_acl->pipeline_num, p); + set_link_map(p_acl->pipeline_num, p, p_acl->links_map); + set_outport_id(p_acl->pipeline_num, p, p_acl->port_out_id); + + /* If this is the first ACL thread, create common ACL Rule tables */ + if (rte_ACL_hi_counter_block_in_use == 0) { + + printf("Create ACL Tables rte_socket_id(): %i\n", + rte_socket_id()); + + /* Create IPV4 ACL Rule Tables */ + struct rte_table_acl_params common_ipv4_table_acl_params = { + .name = "ACLIPV4A", + .n_rules = acl_n_rules, + .n_rule_fields = RTE_DIM(field_format_ipv4), + }; + + memcpy(common_ipv4_table_acl_params.field_format, + field_format_ipv4, sizeof(field_format_ipv4)); + + uint32_t ipv4_entry_size = sizeof(struct acl_table_entry); + + acl_rule_table_ipv4_active = + rte_table_acl_ops.f_create(&common_ipv4_table_acl_params, + rte_socket_id(), + ipv4_entry_size); + + if (acl_rule_table_ipv4_active == NULL) { + printf + ("Failed to create common ACL IPV4A Rule table\n"); + rte_pipeline_free(p->p); + rte_free(p); + return NULL; + } + + /* Create second IPV4 Table */ + common_ipv4_table_acl_params.name = "ACLIPV4B"; + acl_rule_table_ipv4_standby = + rte_table_acl_ops.f_create(&common_ipv4_table_acl_params, + rte_socket_id(), + ipv4_entry_size); + + if (acl_rule_table_ipv4_standby == NULL) { + printf + ("Failed to create common ACL IPV4B Rule table\n"); + rte_pipeline_free(p->p); + rte_free(p); + return NULL; + } + + /* Create IPV6 ACL Rule Tables */ + struct rte_table_acl_params common_ipv6_table_acl_params = { + .name = "ACLIPV6A", + .n_rules = acl_n_rules, + .n_rule_fields = RTE_DIM(field_format_ipv6), + }; + + memcpy(common_ipv6_table_acl_params.field_format, + field_format_ipv6, sizeof(field_format_ipv6)); + + uint32_t ipv6_entry_size = sizeof(struct acl_table_entry); + + acl_rule_table_ipv6_active = + rte_table_acl_ops.f_create(&common_ipv6_table_acl_params, + rte_socket_id(), + ipv6_entry_size); + + if (acl_rule_table_ipv6_active == NULL) { + printf + ("Failed to create common ACL IPV6A Rule table\n"); + rte_pipeline_free(p->p); + rte_free(p); + return NULL; + } + + /* Create second IPV6 table */ + common_ipv6_table_acl_params.name = "ACLIPV6B"; + acl_rule_table_ipv6_standby = + rte_table_acl_ops.f_create(&common_ipv6_table_acl_params, + rte_socket_id(), + ipv6_entry_size); + + if (acl_rule_table_ipv6_standby == NULL) { + printf + ("Failed to create common ACL IPV6B Rule table\n"); + rte_pipeline_free(p->p); + rte_free(p); + return NULL; + } + } + + /* Tables */ + p->n_tables = 1; + { + + struct rte_pipeline_table_params table_params = { + .ops = &rte_table_stub_ops, + .arg_create = NULL, + .f_action_hit = NULL, + .f_action_miss = NULL, + .arg_ah = NULL, + .action_data_size = 0, + }; + + int status = rte_pipeline_table_create(p->p, + &table_params, + &p->table_id[0]); + + if (status) { + rte_pipeline_free(p->p); + rte_free(p); + return NULL; + } + + struct rte_pipeline_table_entry default_entry = { + .action = RTE_PIPELINE_ACTION_PORT_META + }; + + struct rte_pipeline_table_entry *default_entry_ptr; + + status = rte_pipeline_table_default_entry_add(p->p, + p->table_id[0], + &default_entry, + &default_entry_ptr); + + if (status) { + rte_pipeline_free(p->p); + rte_free(p); + return NULL; + } + } + + /* Connecting input ports to tables */ + for (i = 0; i < p->n_ports_in; i++) { + int status = rte_pipeline_port_in_connect_to_table(p->p, + p->port_in_id + [i], + p->table_id + [0]); + + if (status) { + rte_pipeline_free(p->p); + rte_free(p); + return NULL; + } + } + + /* Enable input ports */ + for (i = 0; i < p->n_ports_in; i++) { + int status = rte_pipeline_port_in_enable(p->p, + p->port_in_id[i]); + + if (status) { + rte_pipeline_free(p->p); + rte_free(p); + return NULL; + } + } + + /* Check pipeline consistency */ + if (rte_pipeline_check(p->p) < 0) { + rte_pipeline_free(p->p); + rte_free(p); + return NULL; + } + + /* Message queues */ + p->n_msgq = params->n_msgq; + for (i = 0; i < p->n_msgq; i++) + p->msgq_in[i] = params->msgq_in[i]; + for (i = 0; i < p->n_msgq; i++) + p->msgq_out[i] = params->msgq_out[i]; + + /* Message handlers */ + memcpy(p->handlers, handlers, sizeof(p->handlers)); + memcpy(p_acl->custom_handlers, + custom_handlers, sizeof(p_acl->custom_handlers)); + + return p; +} + +/** + * Free resources and delete pipeline. + * + * @param p + * A pointer to the pipeline. + * + * @return + * 0 on success, negative on error. + */ +static int pipeline_acl_free(void *pipeline) +{ + struct pipeline *p = (struct pipeline *)pipeline; + + /* Check input arguments */ + if (p == NULL) + return -1; + + /* Free resources */ + rte_pipeline_free(p->p); + rte_free(p); + return 0; +} + +/** + * Callback function to map input/output ports. + * + * @param pipeline + * A pointer to the pipeline. + * @param port_in + * Input port ID + * @param port_out + * A pointer to the Output port. + * + * @return + * 0 on success, negative on error. + */ +static int +pipeline_acl_track(void *pipeline, + __rte_unused uint32_t port_in, uint32_t *port_out) +{ + struct pipeline *p = (struct pipeline *)pipeline; + + /* Check input arguments */ + if ((p == NULL) || (port_in >= p->n_ports_in) || (port_out == NULL)) + return -1; + + if (p->n_ports_in == 1) { + *port_out = 0; + return 0; + } + + return -1; +} + +/** + * Callback function to process timers. + * + * @param pipeline + * A pointer to the pipeline. + * + * @return + * 0 on success, negative on error. + */ +static int pipeline_acl_timer(void *pipeline) +{ + + struct pipeline *p = (struct pipeline *)pipeline; + struct pipeline_acl *p_acl = (struct pipeline_acl *)pipeline; + + pipeline_msg_req_handle(p); + rte_pipeline_flush(p->p); + + rte_ct_handle_expired_timers(p_acl->cnxn_tracker); + + return 0; +} + +/** + * Callback function to process CLI commands from FE. + * + * @param p + * A pointer to the pipeline. + * @param msg + * A pointer to command specific data. + * + * @return + * A pointer to message handler on success, + * pipeline_msg_req_invalid_hander on error. + */ +void *pipeline_acl_msg_req_custom_handler(struct pipeline *p, void *msg) +{ + struct pipeline_acl *p_acl = (struct pipeline_acl *)p; + struct pipeline_custom_msg_req *req = msg; + pipeline_msg_req_handler f_handle; + + f_handle = (req->subtype < PIPELINE_ACL_MSG_REQS) ? + p_acl->custom_handlers[req->subtype] : + pipeline_msg_req_invalid_handler; + + if (f_handle == NULL) + f_handle = pipeline_msg_req_invalid_handler; + + return f_handle(p, req); +} + +/** + * Handler for DBG CLI command. + * + * @param p + * A pointer to the pipeline. + * @param msg + * A pointer to command specific data. + * + * @return + * A pointer to response message. + * Response message contains status. + */ +void *pipeline_acl_msg_req_dbg_handler(struct pipeline *p, void *msg) +{ + (void)p; + struct pipeline_acl_dbg_msg_req *req = msg; + struct pipeline_acl_dbg_msg_rsp *rsp = msg; + + if (req->dbg == 0) { + printf("DBG turned OFF\n"); + ACL_DEBUG = 0; + rsp->status = 0; + } else if (req->dbg == 1) { + printf("DBG turned ON\n"); + ACL_DEBUG = 1; + rsp->status = 0; + } else { + printf("Invalid DBG setting\n"); + rsp->status = -1; + } + + return rsp; +} + +struct pipeline_be_ops pipeline_acl_be_ops = { + .f_init = pipeline_acl_init, + .f_free = pipeline_acl_free, + .f_run = NULL, + .f_timer = pipeline_acl_timer, + .f_track = pipeline_acl_track, +}; -- cgit 1.2.3-korg