/* // 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 = IPv4_HDR_VERSION; 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, };