2 // Copyright (c) 2017 Intel Corporation
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
19 * Pipeline VFW BE Implementation.
21 * Implementation of Pipeline VFW Back End (BE).
22 * Responsible for packet processing.
36 #include <rte_common.h>
37 #include <rte_malloc.h>
38 #include <rte_ether.h>
39 #include <rte_ethdev.h>
43 #include <rte_byteorder.h>
45 #include <rte_table_lpm.h>
46 #include <rte_table_hash.h>
47 #include <rte_table_array.h>
48 #include <rte_table_acl.h>
49 #include <rte_table_stub.h>
50 #include <rte_timer.h>
51 #include <rte_cycles.h>
52 #include <rte_pipeline.h>
53 #include <rte_spinlock.h>
54 #include <rte_prefetch.h>
55 #include "pipeline_actions_common.h"
56 #include "hash_func.h"
57 #include "pipeline_vfw.h"
58 #include "pipeline_vfw_be.h"
59 #include "rte_cnxn_tracking.h"
60 #include "pipeline_arpicmp_be.h"
61 #include "vnf_common.h"
62 #include "vnf_define.h"
65 #include "lib_icmpv6.h"
66 #include "pipeline_common_fe.h"
70 uint8_t firewall_flag = 1;
72 uint8_t cnxn_tracking_is_active = 1;
74 * A structure defining the VFW pipeline input port per thread data.
76 struct vfw_ports_in_args {
77 struct pipeline *pipe;
78 struct rte_ct_cnxn_tracker *cnxn_tracker;
79 } __rte_cache_aligned;
81 * A structure defining the VFW pipeline per thread data.
85 pipeline_msg_req_handler custom_handlers[PIPELINE_VFW_MSG_REQS];
87 struct rte_ct_cnxn_tracker *cnxn_tracker;
88 struct rte_VFW_counter_block *counters;
89 struct rte_mbuf *pkt_buffer[PKT_BUFFER_SIZE];
90 struct lib_acl *plib_acl;
91 /* timestamp retrieved during in-port computations */
95 uint8_t links_map[PIPELINE_MAX_PORT_IN];
96 uint8_t outport_id[PIPELINE_MAX_PORT_IN];
97 /* Local ARP & ND Tables */
98 struct lib_arp_route_table_entry
99 local_lib_arp_route_table[MAX_ARP_RT_ENTRY];
100 uint8_t local_lib_arp_route_ent_cnt;
101 struct lib_nd_route_table_entry
102 local_lib_nd_route_table[MAX_ND_RT_ENTRY];
103 uint8_t local_lib_nd_route_ent_cnt;
105 } __rte_cache_aligned;
107 * A structure defining the mbuf meta data for VFW.
109 struct mbuf_tcp_meta_data {
110 /* output port stored for RTE_PIPELINE_ACTION_PORT_META */
111 uint32_t output_port;
112 struct rte_mbuf *next; /* next pointer for chained buffers */
113 } __rte_cache_aligned;
115 #define DONT_CARE_TCP_PACKET 0
116 #define IS_NOT_TCP_PACKET 0
117 #define IS_TCP_PACKET 1
119 #define META_DATA_OFFSET 128
121 #define RTE_PKTMBUF_HEADROOM 128 /* where is this defined ? */
122 #define ETHERNET_START (META_DATA_OFFSET + RTE_PKTMBUF_HEADROOM)
123 #define ETH_HDR_SIZE 14
124 #define PROTOCOL_START (IP_START + 9)
126 #define TCP_START (IP_START + 20)
127 #define RTE_LB_PORT_OFFSET 204 /* TODO: Need definition in LB header */
128 #define TCP_START_IPV6 (IP_START + 40)
129 #define PROTOCOL_START_IPV6 (IP_START + 6)
130 #define IP_HDR_DSCP_OFST 1
132 #define TCP_PROTOCOL 6
133 #define UDP_PROTOCOL 17
135 #define DELETE_BUFFERED_PACKETS 0
136 #define FORWARD_BUFFERED_PACKETS 1
140 #define IPv4_HEADER_SIZE 20
141 #define IPv6_HEADER_SIZE 40
143 #define IP_VERSION_4 4
144 #define IP_VERSION_6 6
147 #define IP_HDR_SIZE_IPV6 40
148 #define IP_HDR_DSCP_OFST_IPV6 0
149 #define IP_HDR_LENGTH_OFST_IPV6 4
150 #define IP_HDR_PROTOCOL_OFST_IPV6 6
151 #define IP_HDR_DST_ADR_OFST_IPV6 24
152 #define MAX_NUM_LOCAL_MAC_ADDRESS 16
153 /** The counter table for VFW pipeline per thread data.*/
154 struct rte_VFW_counter_block rte_vfw_counter_table[MAX_VFW_INSTANCES]
156 int rte_VFW_hi_counter_block_in_use = -1;
158 /* a spin lock used during vfw initialization only */
159 rte_spinlock_t rte_VFW_init_lock = RTE_SPINLOCK_INITIALIZER;
162 struct pipeline_action_key *action_array_a;
163 struct pipeline_action_key *action_array_b;
164 struct pipeline_action_key *action_array_active;
165 struct pipeline_action_key *action_array_standby;
166 uint32_t action_array_size;
167 struct action_counter_block
168 action_counter_table[MAX_VFW_INSTANCES][action_array_max]
171 * Pipeline table strategy for firewall. Unfortunately, there does not seem to
172 * be any use for the built-in table lookup of ip_pipeline for the firewall.
173 * The main table requirement of the firewall is the hash table to maintain
174 * connection info, but that is implemented seperately in the connection
175 * tracking library. So a "dummy" table lookup will be performed.
176 * TODO: look into "stub" table and see if that can be used
177 * to avoid useless table lookup
179 /***** ARP local cache *****/
180 uint8_t link_hw_laddr_valid[MAX_NUM_LOCAL_MAC_ADDRESS] = {
181 0, 0, 0, 0, 0, 0, 0, 0,
182 0, 0, 0, 0, 0, 0, 0, 0
185 static struct ether_addr link_hw_laddr[MAX_NUM_LOCAL_MAC_ADDRESS] = {
186 {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
187 {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
188 {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
189 {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
190 {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
191 {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
192 {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
193 {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
194 {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
195 {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
196 {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
197 {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
198 {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
199 {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
200 {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
201 {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }
204 /* Start TSC measurement */
205 /* Prefetch counters and pipe before this function */
206 static inline void start_tsc_measure(struct pipeline_vfw *vfw_pipe) {
207 vfw_pipe->counters->entry_timestamp = rte_get_tsc_cycles();
208 if (likely(vfw_pipe->counters->exit_timestamp))
209 vfw_pipe->counters->external_time_sum +=
210 vfw_pipe->counters->entry_timestamp -
211 vfw_pipe->counters->exit_timestamp;
214 /* End TSC measurement */
215 static inline void end_tsc_measure(
216 struct pipeline_vfw *vfw_pipe,
219 if (likely(n_pkts > 1)) {
220 vfw_pipe->counters->exit_timestamp = rte_get_tsc_cycles();
221 vfw_pipe->counters->internal_time_sum +=
222 vfw_pipe->counters->exit_timestamp -
223 vfw_pipe->counters->entry_timestamp;
224 vfw_pipe->counters->time_measurements++;
226 /* small counts skew results, ignore */
227 vfw_pipe->counters->exit_timestamp = 0;
231 static struct ether_addr *get_local_link_hw_addr(uint8_t out_port)
233 return &link_hw_laddr[out_port];
236 static uint8_t local_dest_mac_present(uint8_t out_port)
238 return link_hw_laddr_valid[out_port];
241 static uint32_t local_get_nh_ipv4(
245 struct pipeline_vfw *vfw_pipe)
249 for (i = 0; i < vfw_pipe->local_lib_arp_route_ent_cnt; i++) {
250 if (((vfw_pipe->local_lib_arp_route_table[i].ip &
251 vfw_pipe->local_lib_arp_route_table[i].mask) ==
252 (ip & vfw_pipe->local_lib_arp_route_table[i].mask))) {
253 *port = vfw_pipe->local_lib_arp_route_table[i].port;
255 *nhip = vfw_pipe->local_lib_arp_route_table[i].nh;
262 static void do_local_nh_ipv4_cache(uint32_t dest_if,
263 struct pipeline_vfw *vfw_pipe)
266 /* Search for the entry and do local copy */
269 for (i = 0; i < MAX_ARP_RT_ENTRY; i++) {
270 if (lib_arp_route_table[i].port == dest_if) {
272 struct lib_arp_route_table_entry *lentry =
274 local_lib_arp_route_table[vfw_pipe->
275 local_lib_arp_route_ent_cnt];
277 lentry->ip = lib_arp_route_table[i].ip;
278 lentry->mask = lib_arp_route_table[i].mask;
279 lentry->port = lib_arp_route_table[i].port;
280 lentry->nh = lib_arp_route_table[i].nh;
282 vfw_pipe->local_lib_arp_route_ent_cnt++;
287 static uint32_t local_get_nh_ipv6(
291 struct pipeline_vfw *vfw_pipe)
293 uint8_t netmask_ipv6[IPV6_ADD_SIZE], netip_nd[IPV6_ADD_SIZE],
294 netip_in[IPV6_ADD_SIZE];
295 uint8_t i = 0, j = 0, k = 0, l = 0, depthflags = 0, depthflags1 = 0;
296 memset(netmask_ipv6, 0, sizeof(netmask_ipv6));
297 memset(netip_nd, 0, sizeof(netip_nd));
298 memset(netip_in, 0, sizeof(netip_in));
300 for (i = 0; i < vfw_pipe->local_lib_nd_route_ent_cnt; i++) {
302 convert_prefixlen_to_netmask_ipv6(
303 vfw_pipe->local_lib_nd_route_table[i].depth,
306 for (k = 0; k < IPV6_ADD_SIZE; k++)
307 if (vfw_pipe->local_lib_nd_route_table[i].ipv6[k] &
310 netip_nd[k] = vfw_pipe->
311 local_lib_nd_route_table[i].ipv6[k];
314 for (l = 0; l < IPV6_ADD_SIZE; l++)
315 if (ip[l] & netmask_ipv6[l]) {
321 if ((depthflags == depthflags1) && (memcmp(netip_nd, netip_in,
322 sizeof(netip_nd)) == 0)) {
324 *port = vfw_pipe->local_lib_nd_route_table[i].port;
326 for (j = 0; j < IPV6_ADD_SIZE; j++)
328 local_lib_nd_route_table[i].nhipv6[j];
338 static void do_local_nh_ipv6_cache(uint32_t dest_if,
339 struct pipeline_vfw *vfw_pipe)
341 /* Search for the entry and do local copy */
344 for (i = 0; i < MAX_ND_RT_ENTRY; i++) {
346 if (lib_nd_route_table[i].port == dest_if) {
348 struct lib_nd_route_table_entry *lentry = &vfw_pipe->
349 local_lib_nd_route_table[vfw_pipe->
350 local_lib_nd_route_ent_cnt];
352 for (l = 0; l < IPV6_ADD_SIZE; l++) {
354 lib_nd_route_table[i].ipv6[l];
356 lib_nd_route_table[i].nhipv6[l];
358 lentry->depth = lib_nd_route_table[i].depth;
359 lentry->port = lib_nd_route_table[i].port;
361 vfw_pipe->local_lib_nd_route_ent_cnt++;
367 * Print packet for debugging.
370 * A pointer to the packet.
373 static __rte_unused void print_pkt(struct rte_mbuf *pkt)
376 int size = (int)sizeof(struct mbuf_tcp_meta_data);
377 uint8_t *rd = RTE_MBUF_METADATA_UINT8_PTR(pkt, META_DATA_OFFSET);
379 printf("Meta-data:\n");
380 for (i = 0; i < size; i++) {
381 printf("%02x ", rd[i]);
382 if ((i & TWO_BYTE_PRINT) == TWO_BYTE_PRINT)
386 printf("IP and TCP/UDP headers:\n");
387 rd = RTE_MBUF_METADATA_UINT8_PTR(pkt, IP_START);
388 for (i = 0; i < IP_HDR_SIZE_IPV6; i++) {
389 printf("%02x ", rd[i]);
390 if ((i & TWO_BYTE_PRINT) == TWO_BYTE_PRINT)
396 /* TODO: are the protocol numbers defined somewhere with meaningful names? */
397 #define IP_ICMP_PROTOCOL 1
398 #define IP_TCP_PROTOCOL 6
399 #define IP_UDP_PROTOCOL 17
400 #define IPv6_FRAGMENT_HEADER 44
403 * Return ethernet header structure form packet.
406 * A pointer to the packet.
409 static inline struct ether_hdr *rte_vfw_get_ether_addr(struct rte_mbuf *pkt)
411 return (struct ether_hdr *)RTE_MBUF_METADATA_UINT32_PTR(pkt,
416 * Return IPV4 header structure form packet.
419 * A pointer to the packet.
423 static inline struct ipv4_hdr *rte_vfw_get_IPv4_hdr_addr(
424 struct rte_mbuf *pkt)
426 return (struct ipv4_hdr *)RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
429 static inline int rte_vfw_is_IPv4(struct rte_mbuf *pkt)
431 /* NOTE: Only supporting IP headers with no options,
432 * so header is fixed size */
433 uint8_t ip_type = RTE_MBUF_METADATA_UINT8(pkt, IP_START)
436 return ip_type == IPv4_HDR_VERSION;
439 static inline int rte_vfw_is_IPv6(struct rte_mbuf *pkt)
441 /* NOTE: Only supporting IP headers with no options,
442 * so header is fixed size */
443 uint8_t ip_type = RTE_MBUF_METADATA_UINT8(pkt, IP_START)
446 return ip_type == IPv6_HDR_VERSION;
449 static inline void rte_vfw_incr_drop_ctr(uint64_t *counter)
451 if (likely(firewall_flag))
455 static uint8_t check_arp_icmp(
456 struct rte_mbuf *pkt,
457 struct pipeline_vfw *vfw_pipe)
459 struct ether_hdr *ehdr;
460 struct app_link_params *link;
461 uint8_t solicited_node_multicast_addr[IPV6_ADD_SIZE] = {
462 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
463 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00};
465 /* ARP outport number */
466 uint16_t out_port = vfw_pipe->pipe.n_ports_out - 1;
467 struct ipv4_hdr *ipv4_h;
468 struct ipv6_hdr *ipv6_h;
469 link = &myApp->link_params[pkt->port];
471 ehdr = rte_vfw_get_ether_addr(pkt);
472 switch (rte_be_to_cpu_16(ehdr->ether_type)) {
475 rte_pipeline_port_out_packet_insert(
480 vfw_pipe->counters->arpicmpPktCount++;
484 ipv4_h = (struct ipv4_hdr *)
485 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
486 if ((ipv4_h->next_proto_id == IP_PROTOCOL_ICMP) &&
488 rte_be_to_cpu_32(ipv4_h->dst_addr)) {
489 if (is_phy_port_privte(pkt->port)) {
490 rte_pipeline_port_out_packet_insert(
495 vfw_pipe->counters->arpicmpPktCount++;
502 ipv6_h = (struct ipv6_hdr *)
503 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
505 if (ipv6_h->proto == ICMPV6_PROTOCOL_ID) {
506 if (!memcmp(ipv6_h->dst_addr, link->ipv6, IPV6_ADD_SIZE)
507 || !memcmp(ipv6_h->dst_addr,
508 solicited_node_multicast_addr,
509 IPV6_ADD_CMP_MULTI)) {
511 rte_pipeline_port_out_packet_insert(
516 vfw_pipe->counters->arpicmpPktCount++;
520 pkts_drop_unsupported_type++;
533 * Performs basic VFW ipv4 packet filtering.
535 * A pointer to the packets.
539 * A pointer to VFW pipeline.
543 rte_vfw_ipv4_packet_filter_and_process(struct rte_mbuf **pkts,
545 struct pipeline_vfw *vfw_pipe)
549 * Make use of cache prefetch. At beginning of loop, want to prefetch
550 * mbuf data for next iteration (not current one).
551 * Note that ethernet header (14 bytes) is cache aligned. IPv4 header
552 * is 20 bytes (extensions not supported), while the IPv6 header is 40
553 * bytes. TCP header is 20 bytes, UDP is 8. One cache line prefetch
554 * will cover IPv4 and TCP or UDP, but to get IPv6 and TCP,
555 * need two pre-fetches.
558 uint8_t pos, next_pos = 0;
559 uint64_t pkt_mask; /* bitmask representing a single packet */
560 struct rte_mbuf *pkt;
561 struct rte_mbuf *next_pkt = NULL;
562 struct ipv4_hdr *ihdr4;
563 void *next_iphdr = NULL;
565 if (unlikely(pkts_mask == 0))
567 pos = (uint8_t) __builtin_ctzll(pkts_mask);
568 pkt_mask = 1LLU << pos; /* bitmask representing only this packet */
571 uint64_t bytes_processed = 0;
572 /* bitmap of packets left to process */
573 uint64_t pkts_to_process = pkts_mask;
574 /* bitmap of valid packets to return */
575 uint64_t valid_packets = pkts_mask;
578 /* prefetch counters, updated below. Most likely counters to update
580 rte_prefetch0(&vfw_pipe->counters);
582 do { /* always execute at least once */
584 /* remove this packet from remaining list */
585 uint64_t next_pkts_to_process = pkts_to_process &= ~pkt_mask;
587 if (likely(next_pkts_to_process)) {
588 /* another packet to process after this, prefetch it */
591 (uint8_t) __builtin_ctzll(next_pkts_to_process);
592 next_pkt = pkts[next_pos];
593 next_iphdr = RTE_MBUF_METADATA_UINT32_PTR(next_pkt,
595 rte_prefetch0(next_iphdr);
599 /* remove this packet from remaining list */
600 pkts_to_process &= ~pkt_mask;
603 if (!check_arp_icmp(pkt, vfw_pipe))
606 uint32_t packet_length = rte_pktmbuf_pkt_len(pkt);
608 bytes_processed += packet_length;
610 ihdr4 = (struct ipv4_hdr *)
611 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
613 /* verify that packet size according to mbuf is at least
614 * as large as the size according to the IP header.
617 uint32_t ip_length = rte_bswap16(ihdr4->total_length);
620 (ip_length > (packet_length - ETH_HDR_SIZE))) {
622 vfw_pipe->counters->pkts_drop_bad_size++;
626 * IPv4 fragmented if: MF (more fragments) or Fragment
627 * Offset are non-zero. Header in Intel order, so flip
628 * constant to compensate. Note that IPv6 uses a header
629 * extension for identifying fragments.
632 int fragmented = (ihdr4->fragment_offset & 0xff3f) != 0;
633 uint8_t ttl = ihdr4->time_to_live;
635 if (unlikely(fragmented)) {
637 vfw_pipe->counters->pkts_drop_fragmented++;
641 * Behave like a router, and decrement the TTL of an
642 * IP packet. If this causes the TTL to become zero,
643 * the packet will be discarded. Unlike a router,
644 * no ICMP code 11 (Time * Exceeded) message will be
645 * sent back to the packet originator.
648 if (unlikely(ttl <= 1)) {
650 * about to decrement to zero (or is somehow
651 * already zero), so discard
654 vfw_pipe->counters->pkts_drop_ttl++;
658 * Dropping the packets other than TCP AND UDP.
661 uint8_t proto = ihdr4->next_proto_id;
663 if (unlikely(!(proto == IP_TCP_PROTOCOL ||
664 proto == IP_UDP_PROTOCOL ||
665 proto == IP_ICMP_PROTOCOL))) {
668 pkts_drop_unsupported_type++;
671 if (unlikely(discard)) {
672 valid_packets &= ~pkt_mask;
674 ihdr4->time_to_live = ttl - 1;
676 /* update header checksum, from rfc 1141 */
678 uint16_t checksum = rte_bswap16(
679 ihdr4->hdr_checksum);
680 /* increment checksum high byte */
681 sum = checksum + 0x100;
683 checksum = (sum + (sum >> BIT_CARRY));
684 ihdr4->hdr_checksum = rte_bswap16(checksum);
687 /* make next packet data the current */
688 pkts_to_process = next_pkts_to_process;
692 pkt_mask = 1LLU << pos;
694 } while (pkts_to_process);
696 /* finalize counters, etc. */
697 vfw_pipe->counters->bytes_processed += bytes_processed;
699 if (likely(firewall_flag))
700 return valid_packets;
705 * Performs basic VFW IPV6 packet filtering.
707 * A pointer to the packets.
711 * A pointer to VFW pipeline.
714 rte_vfw_ipv6_packet_filter_and_process(struct rte_mbuf **pkts,
716 struct pipeline_vfw *vfw_pipe)
720 * Make use of cache prefetch. At beginning of loop, want to prefetch
721 * mbuf data for next iteration (not current one).
722 * Note that ethernet header (14 bytes) is cache aligned. IPv4 header
723 * is 20 bytes (extensions not supported), while the IPv6 header is 40
724 * bytes. TCP header is 20 bytes, UDP is 8. One cache line prefetch
725 * will cover IPv4 and TCP or UDP, but to get IPv6 and TCP,
726 * need two pre-fetches.
729 uint8_t pos, next_pos = 0;
730 uint64_t pkt_mask; /* bitmask representing a single packet */
731 struct rte_mbuf *pkt;
732 struct rte_mbuf *next_pkt = NULL;
733 struct ipv6_hdr *ihdr6;
734 void *next_iphdr = NULL;
736 if (unlikely(pkts_mask == 0))
738 pos = (uint8_t) __builtin_ctzll(pkts_mask);
739 pkt_mask = 1LLU << pos; /* bitmask representing only this packet */
742 uint64_t bytes_processed = 0;
743 /* bitmap of packets left to process */
744 uint64_t pkts_to_process = pkts_mask;
745 /* bitmap of valid packets to return */
746 uint64_t valid_packets = pkts_mask;
748 /* prefetch counters, updated below. Most likely counters to update
750 rte_prefetch0(&vfw_pipe->counters);
752 do { /* always execute at least once */
754 /* remove this packet from remaining list */
755 uint64_t next_pkts_to_process = pkts_to_process &= ~pkt_mask;
757 if (likely(next_pkts_to_process)) {
758 /* another packet to process after this, prefetch it */
761 (uint8_t) __builtin_ctzll(next_pkts_to_process);
762 next_pkt = pkts[next_pos];
764 RTE_MBUF_METADATA_UINT32_PTR(next_pkt, IP_START);
765 rte_prefetch0(next_iphdr);
769 /* remove this packet from remaining list */
770 pkts_to_process &= ~pkt_mask;
773 if (!check_arp_icmp(pkt, vfw_pipe))
776 uint32_t packet_length = rte_pktmbuf_pkt_len(pkt);
778 bytes_processed += packet_length;
780 ihdr6 = (struct ipv6_hdr *)
781 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
784 * verify that packet size according to mbuf is at least
785 * as large as the size according to the IP header.
786 * For IPv6, note that size includes header extensions
787 * but not the base header size
791 rte_bswap16(ihdr6->payload_len) + IPv6_HEADER_SIZE;
794 (ip_length > (packet_length - ETH_HDR_SIZE))) {
796 vfw_pipe->counters->pkts_drop_bad_size++;
800 * Dropping the packets other than TCP AND UDP.
803 uint8_t proto = ihdr6->proto;
805 if (unlikely(!(proto == IP_TCP_PROTOCOL ||
806 proto == IP_UDP_PROTOCOL ||
807 proto == IP_ICMP_PROTOCOL))) {
809 if (proto == IPv6_FRAGMENT_HEADER)
811 pkts_drop_fragmented++;
814 pkts_drop_unsupported_type++;
818 * Behave like a router, and decrement the TTL of an
819 * IP packet. If this causes the TTL to become zero,
820 * the packet will be discarded. Unlike a router,
821 * no ICMP code 11 (Time * Exceeded) message will be
822 * sent back to the packet originator.
825 if (unlikely(ihdr6->hop_limits <= 1)) {
827 * about to decrement to zero (or is somehow
828 * already zero), so discard
831 vfw_pipe->counters->pkts_drop_ttl++;
834 if (unlikely(discard))
835 valid_packets &= ~pkt_mask;
839 /* make next packet data the current */
840 pkts_to_process = next_pkts_to_process;
844 pkt_mask = 1LLU << pos;
846 } while (pkts_to_process);
848 /* finalize counters, etc. */
849 vfw_pipe->counters->bytes_processed += bytes_processed;
851 if (likely(firewall_flag))
852 return valid_packets;
858 * exchange the mac address so source becomes destination and vice versa.
861 * A pointer to the ethernet header.
864 static inline void rte_sp_exchange_mac_addresses(struct ether_hdr *ehdr)
866 struct ether_addr saved_copy;
868 ether_addr_copy(&ehdr->d_addr, &saved_copy);
869 ether_addr_copy(&ehdr->s_addr, &ehdr->d_addr);
870 ether_addr_copy(&saved_copy, &ehdr->s_addr);
875 * walk every valid mbuf (denoted by pkts_mask) and apply arp to the packet.
876 * To support synproxy, some (altered) packets may need to be sent back where
877 * they came from. The ip header has already been adjusted, but the ethernet
878 * header has not, so this must be performed here.
879 * Return an updated pkts_mask, since arp may drop some packets
882 * A pointer to the packet array.
884 * Packet num to start processing
887 * @param synproxy_reply_mask
888 * Reply Packet mask for Synproxy
890 * A pointer to VFW pipeline.
893 pkt4_work_vfw_arp_ipv4_packets(struct rte_mbuf **pkts,
896 uint64_t synproxy_reply_mask,
897 struct pipeline_vfw *vfw_pipe)
904 struct ether_addr hw_addr;
905 struct mbuf_tcp_meta_data *meta_data_addr;
906 struct ether_hdr *ehdr;
907 struct rte_mbuf *pkt;
910 for (i = 0; i < 4; i++) {
911 uint32_t dest_if = INVALID_DESTIF;
912 /* bitmask representing only this packet */
913 uint64_t pkt_mask = 1LLU << (pkt_num + i);
917 if(!(*pkts_mask & pkt_mask))
920 int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
922 phy_port = pkt->port;
923 meta_data_addr = (struct mbuf_tcp_meta_data *)
924 RTE_MBUF_METADATA_UINT32_PTR(pkt, META_DATA_OFFSET);
925 ehdr = rte_vfw_get_ether_addr(pkt);
928 struct ipv4_hdr *ihdr = (struct ipv4_hdr *)
929 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
932 uint32_t dest_address = rte_bswap32(ihdr->dst_addr);
934 ret = local_get_nh_ipv4(dest_address, &dest_if,
937 rte_sp_exchange_mac_addresses(ehdr);
938 if (is_phy_port_privte(phy_port)) {
940 dest_if = get_pub_to_prv_port(
943 if (dest_if == INVALID_DESTIF) {
944 *pkts_mask &= ~pkt_mask;
946 pkts_drop_without_arp_entry++;
948 do_local_nh_ipv4_cache(
954 dest_if = get_prv_to_pub_port(
957 if (dest_if == INVALID_DESTIF) {
958 *pkts_mask &= ~pkt_mask;
960 pkts_drop_without_arp_entry++;
962 do_local_nh_ipv4_cache(dest_if,
966 } else if (is_phy_port_privte(phy_port)) {
968 dest_if = get_prv_to_pub_port(&dest_address,
970 if (dest_if == INVALID_DESTIF) {
971 *pkts_mask &= ~pkt_mask;
973 pkts_drop_without_arp_entry++;
975 do_local_nh_ipv4_cache(dest_if, vfw_pipe);
980 dest_if = get_pub_to_prv_port(&dest_address,
982 if (dest_if == INVALID_DESTIF) {
983 *pkts_mask &= ~pkt_mask;
985 pkts_drop_without_arp_entry++;
987 do_local_nh_ipv4_cache(dest_if, vfw_pipe);
991 meta_data_addr->output_port = vfw_pipe->outport_id[dest_if];
992 if (local_dest_mac_present(dest_if)) {
993 ether_addr_copy(get_local_link_hw_addr(dest_if),
995 ether_addr_copy(get_link_hw_addr(dest_if),
998 ret_mac = get_dest_mac_addr_port(dest_address,
1000 if (ret_mac == ARP_FOUND) {
1002 link_hw_laddr_valid[dest_if] = 1;
1003 memcpy(&link_hw_laddr[dest_if], &hw_addr,
1004 sizeof(struct ether_addr));
1006 ether_addr_copy(&hw_addr, &ehdr->d_addr);
1007 ether_addr_copy(get_link_hw_addr(dest_if),
1010 if (vfw_debug >= DEBUG_LEVEL_4) {
1011 char buf[HW_ADDR_SIZE];
1013 ether_format_addr(buf, sizeof(buf),
1015 printf("MAC found for ip 0x%"
1016 PRIx32", dest_if %d: %s, ",
1019 ether_format_addr(buf, sizeof(buf),
1021 printf("new eth hdr src: %s, ", buf);
1022 ether_format_addr(buf, sizeof(buf),
1024 printf("new eth hdr dst: %s\n", buf);
1029 if (vfw_debug >= DEBUG_LEVEL_4) {
1030 char buf[HW_ADDR_SIZE];
1032 ether_format_addr(buf, sizeof(buf),
1034 printf("MAC NOT FOUND for ip 0x%"
1040 /* ICMP req sent, drop packet by
1041 * changing the mask */
1042 *pkts_mask &= ~pkt_mask;
1044 counters->pkts_drop_without_arp_entry++;
1052 * walk every valid mbuf (denoted by pkts_mask) and apply arp to the packet.
1053 * To support synproxy, some (altered) packets may need to be sent back where
1054 * they came from. The ip header has already been adjusted, but the ethernet
1055 * header has not, so this must be performed here.
1056 * Return an updated pkts_mask, since arp may drop some packets
1059 * A pointer to the packet.
1061 * Packet number to process
1063 * Packet mask pointer
1064 * @param synproxy_reply_mask
1065 * Reply Packet mask for Synproxy
1067 * A pointer to VFW pipeline.
1070 pkt_work_vfw_arp_ipv4_packets(struct rte_mbuf *pkts,
1072 uint64_t *pkts_mask,
1073 uint64_t synproxy_reply_mask,
1074 struct pipeline_vfw *vfw_pipe)
1078 uint32_t dest_if = INVALID_DESTIF;
1081 struct ether_addr hw_addr;
1082 struct mbuf_tcp_meta_data *meta_data_addr;
1083 struct ether_hdr *ehdr;
1084 struct rte_mbuf *pkt;
1086 uint64_t pkt_mask = 1LLU << pkt_num;
1090 if(*pkts_mask & pkt_mask) {
1092 int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
1094 phy_port = pkt->port;
1095 meta_data_addr = (struct mbuf_tcp_meta_data *)
1096 RTE_MBUF_METADATA_UINT32_PTR(pkt, META_DATA_OFFSET);
1097 ehdr = rte_vfw_get_ether_addr(pkt);
1100 struct ipv4_hdr *ihdr = (struct ipv4_hdr *)
1101 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
1104 uint32_t dest_address = rte_bswap32(ihdr->dst_addr);
1106 ret = local_get_nh_ipv4(dest_address, &dest_if,
1109 rte_sp_exchange_mac_addresses(ehdr);
1110 if (is_phy_port_privte(phy_port)) {
1112 dest_if = get_pub_to_prv_port(
1115 if (dest_if == INVALID_DESTIF) {
1116 *pkts_mask &= ~pkt_mask;
1117 vfw_pipe->counters->
1118 pkts_drop_without_arp_entry++;
1120 do_local_nh_ipv4_cache(
1126 dest_if = get_prv_to_pub_port(
1129 if (dest_if == INVALID_DESTIF) {
1130 *pkts_mask &= ~pkt_mask;
1131 vfw_pipe->counters->
1132 pkts_drop_without_arp_entry++;
1134 do_local_nh_ipv4_cache(dest_if,
1138 } else if (is_phy_port_privte(phy_port)) {
1140 dest_if = get_prv_to_pub_port(&dest_address,
1142 if (dest_if == INVALID_DESTIF) {
1143 *pkts_mask &= ~pkt_mask;
1144 vfw_pipe->counters->
1145 pkts_drop_without_arp_entry++;
1147 do_local_nh_ipv4_cache(dest_if, vfw_pipe);
1152 dest_if = get_pub_to_prv_port(&dest_address,
1154 if (dest_if == INVALID_DESTIF) {
1155 *pkts_mask &= ~pkt_mask;
1156 vfw_pipe->counters->
1157 pkts_drop_without_arp_entry++;
1159 do_local_nh_ipv4_cache(dest_if, vfw_pipe);
1163 meta_data_addr->output_port = vfw_pipe->outport_id[dest_if];
1164 if (local_dest_mac_present(dest_if)) {
1165 ether_addr_copy(get_local_link_hw_addr(dest_if),
1167 ether_addr_copy(get_link_hw_addr(dest_if),
1170 ret_mac = get_dest_mac_addr_port(dest_address,
1171 &dest_if, &hw_addr);
1173 link_hw_laddr_valid[dest_if] = 1;
1174 memcpy(&link_hw_laddr[dest_if], &hw_addr,
1175 sizeof(struct ether_addr));
1177 ether_addr_copy(&hw_addr, &ehdr->d_addr);
1178 ether_addr_copy(get_link_hw_addr(dest_if),
1181 if (vfw_debug >= DEBUG_LEVEL_4) {
1182 char buf[HW_ADDR_SIZE];
1184 ether_format_addr(buf, sizeof(buf),
1186 printf("MAC found for ip 0x%"
1187 PRIx32", dest_if %d: %s, ",
1190 ether_format_addr(buf, sizeof(buf),
1192 printf("new eth hdr src: %s, ", buf);
1193 ether_format_addr(buf, sizeof(buf),
1195 printf("new eth hdr dst: %s\n", buf);
1199 if (vfw_debug >= DEBUG_LEVEL_4) {
1200 char buf[HW_ADDR_SIZE];
1202 ether_format_addr(buf, sizeof(buf),
1204 printf("MAC NOT FOUND for ip 0x%"
1210 /* ICMP req sent, drop packet by
1211 * changing the mask */
1212 *pkts_mask &= ~pkt_mask;
1214 counters->pkts_drop_without_arp_entry++;
1223 * walk every valid mbuf (denoted by pkts_mask) and apply arp to the packet.
1224 * To support synproxy, some (altered) packets may need to be sent back where
1225 * they came from. The ip header has already been adjusted, but the ethernet
1226 * header has not, so this must be performed here.
1227 * Return an updated pkts_mask, since arp may drop some packets
1230 * A pointer to the packets array.
1232 * Packet number to start processing.
1234 * Packet mask pointer
1235 * @param synproxy_reply_mask
1236 * Reply Packet mask for Synproxy
1238 * A pointer to VFW pipeline.
1242 pkt4_work_vfw_arp_ipv6_packets(struct rte_mbuf **pkts,
1244 uint64_t *pkts_mask,
1245 uint64_t synproxy_reply_mask,
1246 struct pipeline_vfw *vfw_pipe)
1248 uint8_t nh_ipv6[IPV6_ADD_SIZE];
1250 struct ether_addr hw_addr;
1251 struct mbuf_tcp_meta_data *meta_data_addr;
1252 struct ether_hdr *ehdr;
1253 struct rte_mbuf *pkt;
1257 for (i = 0; i < 4; i++) {
1258 uint32_t dest_if = INVALID_DESTIF;
1259 /* bitmask representing only this packet */
1260 uint64_t pkt_mask = 1LLU << (pkt_num + i);
1264 if(!(*pkts_mask & pkt_mask))
1266 int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
1268 phy_port = pkt->port;
1269 meta_data_addr = (struct mbuf_tcp_meta_data *)
1270 RTE_MBUF_METADATA_UINT32_PTR(pkt, META_DATA_OFFSET);
1271 ehdr = rte_vfw_get_ether_addr(pkt);
1273 struct ipv6_hdr *ihdr = (struct ipv6_hdr *)
1274 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
1276 uint8_t nhip[IPV6_ADD_SIZE];
1277 uint8_t dest_address[IPV6_ADD_SIZE];
1279 memset(nhip, 0, IPV6_ADD_SIZE);
1281 rte_mov16(dest_address, ihdr->dst_addr);
1282 ret = local_get_nh_ipv6(&dest_address[0], &dest_if,
1283 &nhip[0], vfw_pipe);
1285 rte_sp_exchange_mac_addresses(ehdr);
1286 if (is_phy_port_privte(phy_port)) {
1288 dest_if = get_pub_to_prv_port(
1292 if (dest_if == INVALID_DESTIF) {
1293 *pkts_mask &= ~pkt_mask;
1294 vfw_pipe->counters->
1295 pkts_drop_without_arp_entry++;
1297 do_local_nh_ipv6_cache(dest_if,
1303 dest_if = get_prv_to_pub_port(
1307 if (dest_if == INVALID_DESTIF) {
1308 *pkts_mask &= ~pkt_mask;
1309 vfw_pipe->counters->
1310 pkts_drop_without_arp_entry++;
1312 do_local_nh_ipv6_cache(dest_if,
1317 } else if (is_phy_port_privte(phy_port)) {
1319 dest_if = get_prv_to_pub_port((uint32_t *)
1320 &dest_address[0], IP_VERSION_6);
1321 if (dest_if == INVALID_DESTIF) {
1322 *pkts_mask &= ~pkt_mask;
1323 vfw_pipe->counters->
1324 pkts_drop_without_arp_entry++;
1326 do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1331 dest_if = get_pub_to_prv_port((uint32_t *)
1332 &dest_address[0], IP_VERSION_6);
1333 if (dest_if == INVALID_DESTIF) {
1334 *pkts_mask &= ~pkt_mask;
1335 vfw_pipe->counters->
1336 pkts_drop_without_arp_entry++;
1339 do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1344 meta_data_addr->output_port = vfw_pipe->outport_id[dest_if];
1346 memset(nh_ipv6, 0, IPV6_ADD_SIZE);
1347 if (get_dest_mac_address_ipv6_port(
1352 ether_addr_copy(&hw_addr, &ehdr->d_addr);
1353 ether_addr_copy(get_link_hw_addr(dest_if),
1356 if (vfw_debug >= DEBUG_LEVEL_4) {
1357 char buf[HW_ADDR_SIZE];
1359 ether_format_addr(buf, sizeof(buf),
1361 printf("MAC found for dest_if %d: %s, ",
1363 ether_format_addr(buf, sizeof(buf),
1365 printf("new eth hdr src: %s, ", buf);
1366 ether_format_addr(buf, sizeof(buf),
1368 printf("new eth hdr dst: %s\n", buf);
1372 printf("deleting ipv6\n");
1373 *pkts_mask &= ~pkt_mask;
1374 /*Next Neighbor is not yet implemented
1376 vfw_pipe->counters->
1377 pkts_drop_without_arp_entry++;
1385 * walk every valid mbuf (denoted by pkts_mask) and apply arp to the packet.
1386 * To support synproxy, some (altered) packets may need to be sent back where
1387 * they came from. The ip header has already been adjusted, but the ethernet
1388 * header has not, so this must be performed here.
1389 * Return an updated pkts_mask, since arp may drop some packets
1392 * A pointer to the packets.
1394 * Packet number to process.
1396 * Packet mask pointer
1397 * @param synproxy_reply_mask
1398 * Reply Packet mask for Synproxy
1400 * A pointer to VFW pipeline.
1404 pkt_work_vfw_arp_ipv6_packets(struct rte_mbuf *pkts,
1406 uint64_t *pkts_mask,
1407 uint64_t synproxy_reply_mask,
1408 struct pipeline_vfw *vfw_pipe)
1410 uint8_t nh_ipv6[IPV6_ADD_SIZE];
1412 struct ether_addr hw_addr;
1413 struct mbuf_tcp_meta_data *meta_data_addr;
1414 struct ether_hdr *ehdr;
1415 struct rte_mbuf *pkt;
1418 uint32_t dest_if = INVALID_DESTIF;
1419 /* bitmask representing only this packet */
1420 uint64_t pkt_mask = 1LLU << pkt_num;
1424 if(*pkts_mask & pkt_mask) {
1426 int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
1428 phy_port = pkt->port;
1429 meta_data_addr = (struct mbuf_tcp_meta_data *)
1430 RTE_MBUF_METADATA_UINT32_PTR(pkt, META_DATA_OFFSET);
1431 ehdr = rte_vfw_get_ether_addr(pkt);
1433 struct ipv6_hdr *ihdr = (struct ipv6_hdr *)
1434 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
1436 uint8_t nhip[IPV6_ADD_SIZE];
1437 uint8_t dest_address[IPV6_ADD_SIZE];
1439 memset(nhip, 0, IPV6_ADD_SIZE);
1441 rte_mov16(dest_address, ihdr->dst_addr);
1442 ret = local_get_nh_ipv6(&dest_address[0], &dest_if,
1443 &nhip[0], vfw_pipe);
1445 rte_sp_exchange_mac_addresses(ehdr);
1446 if (is_phy_port_privte(phy_port)) {
1448 dest_if = get_pub_to_prv_port(
1452 if (dest_if == INVALID_DESTIF) {
1453 *pkts_mask &= ~pkt_mask;
1454 vfw_pipe->counters->
1455 pkts_drop_without_arp_entry++;
1457 do_local_nh_ipv6_cache(dest_if,
1463 dest_if = get_prv_to_pub_port(
1467 if (dest_if == INVALID_DESTIF) {
1468 *pkts_mask &= ~pkt_mask;
1469 vfw_pipe->counters->
1470 pkts_drop_without_arp_entry++;
1472 do_local_nh_ipv6_cache(dest_if,
1477 } else if (is_phy_port_privte(phy_port)) {
1479 dest_if = get_prv_to_pub_port((uint32_t *)
1480 &dest_address[0], IP_VERSION_6);
1481 if (dest_if == INVALID_DESTIF) {
1482 *pkts_mask &= ~pkt_mask;
1483 vfw_pipe->counters->
1484 pkts_drop_without_arp_entry++;
1486 do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1491 dest_if = get_pub_to_prv_port((uint32_t *)
1492 &dest_address[0], IP_VERSION_6);
1493 if (dest_if == INVALID_DESTIF) {
1494 *pkts_mask &= ~pkt_mask;
1495 vfw_pipe->counters->
1496 pkts_drop_without_arp_entry++;
1499 do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1504 meta_data_addr->output_port = vfw_pipe->outport_id[dest_if];
1506 memset(nh_ipv6, 0, IPV6_ADD_SIZE);
1507 if (get_dest_mac_address_ipv6_port(
1512 ether_addr_copy(&hw_addr, &ehdr->d_addr);
1513 ether_addr_copy(get_link_hw_addr(dest_if),
1516 if (vfw_debug >= DEBUG_LEVEL_4) {
1517 char buf[HW_ADDR_SIZE];
1519 ether_format_addr(buf, sizeof(buf),
1521 printf("MAC found for dest_if %d: %s, ",
1523 ether_format_addr(buf, sizeof(buf),
1525 printf("new eth hdr src: %s, ", buf);
1526 ether_format_addr(buf, sizeof(buf),
1528 printf("new eth hdr dst: %s\n", buf);
1532 printf("deleting ipv6\n");
1533 *pkts_mask &= ~pkt_mask;
1534 /*Next Neighbor is not yet implemented
1536 vfw_pipe->counters->
1537 pkts_drop_without_arp_entry++;
1547 * walk every valid mbuf (denoted by pkts_mask) and apply arp to the packet.
1548 * To support synproxy, some (altered) packets may need to be sent back where
1549 * they came from. The ip header has already been adjusted, but the ethernet
1550 * header has not, so this must be performed here.
1551 * Return an updated pkts_mask, since arp may drop some packets
1554 * A pointer to the packet.
1557 * @param synproxy_reply_mask
1558 * Reply Packet mask for Synproxy
1560 * A pointer to VFW pipeline.
1563 rte_vfw_arp_ipv4_packets(struct rte_mbuf **pkts,
1565 uint64_t synproxy_reply_mask,
1566 struct pipeline_vfw *vfw_pipe)
1568 uint64_t pkts_to_arp = pkts_mask;
1571 uint32_t dest_if = INVALID_DESTIF;
1573 for (; pkts_to_arp;) {
1574 struct ether_addr hw_addr;
1575 struct mbuf_tcp_meta_data *meta_data_addr;
1576 struct ether_hdr *ehdr;
1577 struct rte_mbuf *pkt;
1580 uint8_t pos = (uint8_t) __builtin_ctzll(pkts_to_arp);
1581 /* bitmask representing only this packet */
1582 uint64_t pkt_mask = 1LLU << pos;
1583 /* remove this packet from remaining list */
1584 pkts_to_arp &= ~pkt_mask;
1586 int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
1588 phy_port = pkt->port;
1589 meta_data_addr = (struct mbuf_tcp_meta_data *)
1590 RTE_MBUF_METADATA_UINT32_PTR(pkt, META_DATA_OFFSET);
1591 ehdr = rte_vfw_get_ether_addr(pkt);
1594 struct ipv4_hdr *ihdr = (struct ipv4_hdr *)
1595 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
1598 uint32_t dest_address = rte_bswap32(ihdr->dst_addr);
1600 ret = local_get_nh_ipv4(dest_address, &dest_if,
1603 rte_sp_exchange_mac_addresses(ehdr);
1604 if (is_phy_port_privte(phy_port)) {
1606 dest_if = get_pub_to_prv_port(
1609 if (dest_if == INVALID_DESTIF) {
1610 pkts_mask &= ~pkt_mask;
1611 vfw_pipe->counters->
1612 pkts_drop_without_arp_entry++;
1614 do_local_nh_ipv4_cache(
1620 dest_if = get_prv_to_pub_port(
1623 if (dest_if == INVALID_DESTIF) {
1624 pkts_mask &= ~pkt_mask;
1625 vfw_pipe->counters->
1626 pkts_drop_without_arp_entry++;
1628 do_local_nh_ipv4_cache(dest_if,
1632 } else if (is_phy_port_privte(phy_port)) {
1634 dest_if = get_prv_to_pub_port(&dest_address,
1636 if (dest_if == INVALID_DESTIF) {
1637 pkts_mask &= ~pkt_mask;
1638 vfw_pipe->counters->
1639 pkts_drop_without_arp_entry++;
1641 do_local_nh_ipv4_cache(dest_if, vfw_pipe);
1646 dest_if = get_pub_to_prv_port(&dest_address,
1648 if (dest_if == INVALID_DESTIF) {
1649 pkts_mask &= ~pkt_mask;
1650 vfw_pipe->counters->
1651 pkts_drop_without_arp_entry++;
1653 do_local_nh_ipv4_cache(dest_if, vfw_pipe);
1657 meta_data_addr->output_port = vfw_pipe->outport_id[dest_if];
1658 if (local_dest_mac_present(dest_if)) {
1659 ether_addr_copy(get_local_link_hw_addr(dest_if),
1661 ether_addr_copy(get_link_hw_addr(dest_if),
1664 ret_mac = get_dest_mac_addr_port(dest_address,
1665 &dest_if, &hw_addr);
1667 link_hw_laddr_valid[dest_if] = 1;
1668 memcpy(&link_hw_laddr[dest_if], &hw_addr,
1669 sizeof(struct ether_addr));
1671 ether_addr_copy(&hw_addr, &ehdr->d_addr);
1672 ether_addr_copy(get_link_hw_addr(dest_if),
1675 if (vfw_debug >= DEBUG_LEVEL_4) {
1676 char buf[HW_ADDR_SIZE];
1678 ether_format_addr(buf, sizeof(buf),
1680 printf("MAC found for ip 0x%"
1681 PRIx32", dest_if %d: %s, ",
1684 ether_format_addr(buf, sizeof(buf),
1686 printf("new eth hdr src: %s, ", buf);
1687 ether_format_addr(buf, sizeof(buf),
1689 printf("new eth hdr dst: %s\n", buf);
1693 if (unlikely(ret_mac == 0))
1694 request_arp(meta_data_addr->output_port,
1697 if (vfw_debug >= DEBUG_LEVEL_4) {
1698 char buf[HW_ADDR_SIZE];
1700 ether_format_addr(buf, sizeof(buf),
1702 printf("MAC NOT FOUND for ip 0x%"
1708 /* ICMP req sent, drop packet by
1709 * changing the mask */
1710 pkts_mask &= ~pkt_mask;
1712 counters->pkts_drop_without_arp_entry++;
1721 * walk every valid mbuf (denoted by pkts_mask) and apply arp to the packet.
1722 * To support synproxy, some (altered) packets may need to be sent back where
1723 * they came from. The ip header has already been adjusted, but the ethernet
1724 * header has not, so this must be performed here.
1725 * Return an updated pkts_mask, since arp may drop some packets
1728 * A pointer to the packet.
1731 * @param synproxy_reply_mask
1732 * Reply Packet mask for Synproxy
1734 * A pointer to VFW pipeline.
1738 rte_vfw_arp_ipv6_packets(struct rte_mbuf **pkts,
1740 uint64_t synproxy_reply_mask,
1741 struct pipeline_vfw *vfw_pipe)
1743 uint64_t pkts_to_arp = pkts_mask;
1744 uint8_t nh_ipv6[IPV6_ADD_SIZE];
1746 uint32_t dest_if = INVALID_DESTIF;
1748 for (; pkts_to_arp;) {
1749 struct ether_addr hw_addr;
1750 struct mbuf_tcp_meta_data *meta_data_addr;
1751 struct ether_hdr *ehdr;
1752 struct rte_mbuf *pkt;
1755 uint8_t pos = (uint8_t) __builtin_ctzll(pkts_to_arp);
1756 /* bitmask representing only this packet */
1757 uint64_t pkt_mask = 1LLU << pos;
1758 /* remove this packet from remaining list */
1759 pkts_to_arp &= ~pkt_mask;
1761 int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
1763 phy_port = pkt->port;
1764 meta_data_addr = (struct mbuf_tcp_meta_data *)
1765 RTE_MBUF_METADATA_UINT32_PTR(pkt, META_DATA_OFFSET);
1766 ehdr = rte_vfw_get_ether_addr(pkt);
1768 struct ipv6_hdr *ihdr = (struct ipv6_hdr *)
1769 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
1771 uint8_t nhip[IPV6_ADD_SIZE];
1772 uint8_t dest_address[IPV6_ADD_SIZE];
1774 memset(nhip, 0, IPV6_ADD_SIZE);
1776 rte_mov16(dest_address, ihdr->dst_addr);
1777 ret = local_get_nh_ipv6(&dest_address[0], &dest_if,
1778 &nhip[0], vfw_pipe);
1780 rte_sp_exchange_mac_addresses(ehdr);
1781 if (is_phy_port_privte(phy_port)) {
1783 dest_if = get_pub_to_prv_port(
1787 if (dest_if == INVALID_DESTIF) {
1788 pkts_mask &= ~pkt_mask;
1789 vfw_pipe->counters->
1790 pkts_drop_without_arp_entry++;
1792 do_local_nh_ipv6_cache(dest_if,
1798 dest_if = get_prv_to_pub_port(
1802 if (dest_if == INVALID_DESTIF) {
1803 pkts_mask &= ~pkt_mask;
1804 vfw_pipe->counters->
1805 pkts_drop_without_arp_entry++;
1807 do_local_nh_ipv6_cache(dest_if,
1812 } else if (is_phy_port_privte(phy_port)) {
1814 dest_if = get_prv_to_pub_port((uint32_t *)
1815 &dest_address[0], IP_VERSION_6);
1816 if (dest_if == INVALID_DESTIF) {
1817 pkts_mask &= ~pkt_mask;
1818 vfw_pipe->counters->
1819 pkts_drop_without_arp_entry++;
1821 do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1826 dest_if = get_pub_to_prv_port((uint32_t *)
1827 &dest_address[0], IP_VERSION_6);
1828 if (dest_if == INVALID_DESTIF) {
1829 pkts_mask &= ~pkt_mask;
1830 vfw_pipe->counters->
1831 pkts_drop_without_arp_entry++;
1834 do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1839 meta_data_addr->output_port = vfw_pipe->outport_id[dest_if];
1841 memset(nh_ipv6, 0, IPV6_ADD_SIZE);
1842 if (get_dest_mac_address_ipv6_port(
1847 ether_addr_copy(&hw_addr, &ehdr->d_addr);
1848 ether_addr_copy(get_link_hw_addr(dest_if),
1851 if (vfw_debug >= DEBUG_LEVEL_4) {
1852 char buf[HW_ADDR_SIZE];
1854 ether_format_addr(buf, sizeof(buf),
1856 printf("MAC found for dest_if %d: %s, ",
1858 ether_format_addr(buf, sizeof(buf),
1860 printf("new eth hdr src: %s, ", buf);
1861 ether_format_addr(buf, sizeof(buf),
1863 printf("new eth hdr dst: %s\n", buf);
1867 printf("deleting ipv6\n");
1868 pkts_mask &= ~pkt_mask;
1869 /*Next Neighbor is not yet implemented
1871 vfw_pipe->counters->
1872 pkts_drop_without_arp_entry++;
1883 * Packets processing for connection tracking.
1886 * A pointer to the pipeline.
1888 * A pointer to the connetion tracker .
1890 * A pointer to a burst of packets.
1891 * @param packet_mask_in
1892 * Input packets Mask.
1896 vfw_process_buffered_pkts(__rte_unused struct pipeline_vfw *vfw_pipe,
1897 struct rte_ct_cnxn_tracker *ct,
1898 struct rte_mbuf **pkts, uint64_t packet_mask_in)
1900 uint64_t keep_mask = packet_mask_in;
1901 struct rte_synproxy_helper sp_helper; /* for synproxy */
1904 rte_ct_cnxn_tracker_batch_lookup_with_synproxy(ct, pkts, keep_mask,
1907 if (unlikely(sp_helper.hijack_mask))
1908 printf("buffered hijack pkts severe error\n");
1910 if (unlikely(sp_helper.reply_pkt_mask))
1911 printf("buffered reply pkts severe error\n");
1917 * Free Packets from mbuf.
1920 * A pointer to the connection tracker to increment drop counter.
1923 * Packet to be free.
1926 vfw_pktmbuf_free(struct rte_ct_cnxn_tracker *ct, struct rte_mbuf *pkt)
1928 ct->counters->pkts_drop++;
1929 rte_pktmbuf_free(pkt);
1933 vfw_output_or_delete_buffered_packets(struct rte_ct_cnxn_tracker *ct,
1934 struct rte_pipeline *p,
1935 struct rte_mbuf **pkts,
1936 int num_pkts, uint64_t pkts_mask)
1939 struct mbuf_tcp_meta_data *meta_data_addr;
1940 uint64_t pkt_mask = 1;
1942 /* any clear bits in low-order num_pkts bit of
1943 * pkt_mask must be discarded */
1945 for (i = 0; i < num_pkts; i++) {
1946 struct rte_mbuf *pkt = pkts[i];
1948 if (pkts_mask & pkt_mask) {
1949 printf("vfw_output_or_delete_buffered_packets\n");
1950 meta_data_addr = (struct mbuf_tcp_meta_data *)
1951 RTE_MBUF_METADATA_UINT32_PTR(pkt, META_DATA_OFFSET);
1952 rte_pipeline_port_out_packet_insert(
1953 p, meta_data_addr->output_port, pkt);
1956 vfw_pktmbuf_free(ct, pkt);
1959 pkt_mask = pkt_mask << 1;
1964 *Packet buffered for synproxy.
1967 * A pointer to the pipeline.
1969 * A pointer to the vfw pipeline.
1971 * A pointer to the connection tracker.
1972 * @param forward_pkts
1973 * Packet forwarded by synproxy.
1977 vfw_handle_buffered_packets(struct rte_pipeline *p,
1978 struct pipeline_vfw *vfw_pipe,
1979 struct rte_ct_cnxn_tracker *ct, int forward_pkts)
1981 struct rte_mbuf *pkt_list = rte_ct_get_buffered_synproxy_packets(ct);
1983 if (likely(pkt_list == NULL)) /* only during proxy setup is != NULL */
1987 uint64_t keep_mask = 0;
1988 struct rte_mbuf **pkts = vfw_pipe->pkt_buffer;
1989 struct rte_mbuf *pkt;
1991 while (pkt_list != NULL) {
1992 struct mbuf_tcp_meta_data *meta_data =
1993 (struct mbuf_tcp_meta_data *)
1994 RTE_MBUF_METADATA_UINT32_PTR(pkt_list, META_DATA_OFFSET);
1996 /* detach head of list and advance list */
1998 pkt_list = meta_data->next;
2002 pkts[pkt_count++] = pkt;
2004 if (pkt_count == PKT_BUFFER_SIZE) {
2005 /* need to send out packets */
2006 /* currently 0, set all bits */
2007 keep_mask = ~keep_mask;
2010 vfw_process_buffered_pkts(vfw_pipe,
2013 vfw_output_or_delete_buffered_packets(
2023 vfw_pktmbuf_free(ct, pkt);
2027 if (pkt_count != 0) {
2028 /* need to send out packets */
2029 keep_mask = RTE_LEN2MASK(pkt_count, uint64_t);
2032 vfw_process_buffered_pkts(vfw_pipe, ct, pkts,
2035 vfw_output_or_delete_buffered_packets(ct, p, pkts, pkt_count,
2043 * The pipeline port-in action is used to do all the firewall and
2044 * connection tracking work for IPV4 packets.
2047 * A pointer to the pipeline.
2049 * A pointer to a burst of packets.
2051 * Number of packets to process.
2053 * A pointer to pipeline specific data.
2056 * 0 on success, negative on error.
2060 vfw_port_in_action_ipv4(struct rte_pipeline *p,
2061 struct rte_mbuf **pkts,
2062 __rte_unused uint32_t n_pkts, __rte_unused void *arg)
2064 struct vfw_ports_in_args *port_in_args =
2065 (struct vfw_ports_in_args *)arg;
2066 struct pipeline_vfw *vfw_pipe =
2067 (struct pipeline_vfw *)port_in_args->pipe;
2068 struct rte_ct_cnxn_tracker *ct = port_in_args->cnxn_tracker;
2070 start_tsc_measure(vfw_pipe);
2072 uint64_t packet_mask_in = RTE_LEN2MASK(n_pkts, uint64_t);
2073 uint64_t pkts_drop_mask;
2074 uint64_t hijack_mask = 0;
2075 uint64_t synproxy_reply_mask = 0; /* for synproxy */
2076 uint64_t keep_mask = packet_mask_in;
2078 uint64_t conntrack_mask = 0, connexist_mask = 0;
2079 struct rte_CT_helper ct_helper;
2083 * This routine uses a bit mask to represent which packets in the
2084 * "pkts" table are considered valid. Any table entry which exists
2085 * and is considered valid has the corresponding bit in the mask set.
2086 * Otherwise, it is cleared. Note that the mask is 64 bits,
2087 * but the number of packets in the table may be considerably less.
2088 * Any mask bits which do correspond to actual packets are cleared.
2089 * Various routines are called which may determine that an existing
2090 * packet is somehow invalid. The routine will return an altered bit
2091 * mask, with the bit cleared. At the end of all the checks,
2092 * packets are dropped if their mask bit is a zero
2095 rte_prefetch0(& vfw_pipe->counters);
2098 /* Pre-fetch all rte_mbuf header */
2099 for(j = 0; j < n_pkts; j++)
2100 rte_prefetch0(pkts[j]);
2102 memset(&ct_helper, 0, sizeof(struct rte_CT_helper));
2104 rte_prefetch0(& vfw_pipe->counters->pkts_drop_ttl);
2105 rte_prefetch0(& vfw_pipe->counters->sum_latencies);
2108 if (unlikely(vfw_debug > 1))
2109 printf("Enter in-port action IPV4 with %p packet mask\n",
2110 (void *)packet_mask_in);
2111 vfw_pipe->counters->pkts_received =
2112 vfw_pipe->counters->pkts_received + n_pkts;
2114 if (unlikely(VFW_DEBUG))
2115 printf("vfw_port_in_action_ipv4 pkts_received: %" PRIu64
2117 vfw_pipe->counters->pkts_received, n_pkts);
2119 /* first handle handle any previously buffered packets now released */
2120 vfw_handle_buffered_packets(p, vfw_pipe, ct,
2121 FORWARD_BUFFERED_PACKETS);
2123 /* now handle any new packets on input ports */
2124 if (likely(firewall_flag)) {
2125 keep_mask = rte_vfw_ipv4_packet_filter_and_process(pkts,
2126 keep_mask, vfw_pipe);
2127 vfw_pipe->counters->pkts_fw_forwarded +=
2128 __builtin_popcountll(keep_mask);
2132 rte_prefetch0((void*)vfw_pipe->plib_acl);
2133 rte_prefetch0((void*)vfw_rule_table_ipv4_active);
2134 #endif /* EN_SWP_ACL */
2135 keep_mask = lib_acl_ipv4_pkt_work_key(
2136 vfw_pipe->plib_acl, pkts, keep_mask,
2137 &vfw_pipe->counters->pkts_drop_without_rule,
2138 vfw_rule_table_ipv4_active,
2139 action_array_active,
2140 action_counter_table,
2141 &conntrack_mask, &connexist_mask);
2142 vfw_pipe->counters->pkts_acl_forwarded +=
2143 __builtin_popcountll(keep_mask);
2144 if (conntrack_mask > 0) {
2145 keep_mask = conntrack_mask;
2146 ct_helper.no_new_cnxn_mask = connexist_mask;
2147 cnxn_tracking_is_active = 1;
2149 cnxn_tracking_is_active = 0;
2150 #endif /* ACL_ENABLE */
2152 if (likely(cnxn_tracking_is_active)) {
2153 rte_ct_cnxn_tracker_batch_lookup_type(ct, pkts,
2154 &keep_mask, &ct_helper, IPv4_HEADER_SIZE);
2155 synproxy_reply_mask = ct_helper.reply_pkt_mask;
2156 hijack_mask = ct_helper.hijack_mask;
2161 for(j = 0; j < (n_pkts & 0x3LLU); j++) {
2162 rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2164 rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2167 rte_prefetch0((void*)in_port_dir_a);
2168 rte_prefetch0((void*)prv_to_pub_map);
2171 for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) {
2172 for (j = i+4; ((j < n_pkts) && (j < i+8)); j++) {
2173 rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2175 rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2178 pkt4_work_vfw_arp_ipv4_packets(&pkts[i], i, &keep_mask,
2179 synproxy_reply_mask, vfw_pipe);
2181 for (j = i; j < n_pkts; j++) {
2182 rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2184 rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2187 for (; i < n_pkts; i++) {
2188 pkt_work_vfw_arp_ipv4_packets(pkts[i], i, &keep_mask,
2189 synproxy_reply_mask, vfw_pipe);
2192 rte_prefetch0((void*)in_port_dir_a);
2193 rte_prefetch0((void*)prv_to_pub_map);
2194 rte_prefetch0((void*) & vfw_pipe->local_lib_arp_route_table);
2195 keep_mask = rte_vfw_arp_ipv4_packets(pkts, keep_mask,
2196 synproxy_reply_mask, vfw_pipe);
2199 if (vfw_debug > 1) {
2200 printf(" Exit in-port action with %p packet mask\n",
2202 if (keep_mask != packet_mask_in)
2203 printf("dropped packets, %p in, %p out\n",
2204 (void *)packet_mask_in,
2208 /* Update mask before returning, so that bad packets are dropped */
2210 pkts_drop_mask = packet_mask_in & ~keep_mask;
2212 if (unlikely(pkts_drop_mask != 0)) {
2213 /* printf("drop %p\n", (void *) pkts_drop_mask); */
2214 rte_pipeline_ah_packet_drop(p, pkts_drop_mask);
2217 if (unlikely(hijack_mask != 0))
2218 rte_pipeline_ah_packet_hijack(p, hijack_mask);
2220 vfw_pipe->counters->num_batch_pkts_sum += n_pkts;
2221 vfw_pipe->counters->num_pkts_measurements++;
2223 end_tsc_measure(vfw_pipe, n_pkts);
2228 * The pipeline port-in action is used to do all the firewall and
2229 * connection tracking work for IPV6 packet.
2232 * A pointer to the pipeline.
2234 * A pointer to a burst of packets.
2236 * Number of packets to process.
2238 * A pointer to pipeline specific data.
2241 * 0 on success, negative on error.
2245 vfw_port_in_action_ipv6(struct rte_pipeline *p,
2246 struct rte_mbuf **pkts,
2247 __rte_unused uint32_t n_pkts, __rte_unused void *arg)
2249 struct vfw_ports_in_args *port_in_args =
2250 (struct vfw_ports_in_args *)arg;
2251 struct pipeline_vfw *vfw_pipe =
2252 (struct pipeline_vfw *)port_in_args->pipe;
2253 struct rte_ct_cnxn_tracker *ct = port_in_args->cnxn_tracker;
2255 start_tsc_measure(vfw_pipe);
2257 uint64_t packet_mask_in = RTE_LEN2MASK(n_pkts, uint64_t);
2258 uint64_t pkts_drop_mask;
2259 uint64_t hijack_mask = 0;
2260 uint64_t synproxy_reply_mask = 0; /* for synproxy */
2261 uint64_t keep_mask = packet_mask_in;
2263 uint64_t conntrack_mask = 0, connexist_mask = 0;
2264 struct rte_CT_helper ct_helper;
2268 * This routine uses a bit mask to represent which packets in the
2269 * "pkts" table are considered valid. Any table entry which exists
2270 * and is considered valid has the corresponding bit in the mask set.
2271 * Otherwise, it is cleared. Note that the mask is 64 bits,
2272 * but the number of packets in the table may be considerably less.
2273 * Any mask bits which do correspond to actual packets are cleared.
2274 * Various routines are called which may determine that an existing
2275 * packet is somehow invalid. The routine will return an altered bit
2276 * mask, with the bit cleared. At the end of all the checks,
2277 * packets are dropped if their mask bit is a zero
2280 rte_prefetch0(& vfw_pipe->counters);
2282 /* Pre-fetch all rte_mbuf header */
2283 for(j = 0; j < n_pkts; j++)
2284 rte_prefetch0(pkts[j]);
2286 memset(&ct_helper, 0, sizeof(struct rte_CT_helper));
2287 rte_prefetch0(& vfw_pipe->counters->pkts_drop_ttl);
2288 rte_prefetch0(& vfw_pipe->counters->sum_latencies);
2291 printf("Enter in-port action with %p packet mask\n",
2292 (void *)packet_mask_in);
2293 vfw_pipe->counters->pkts_received =
2294 vfw_pipe->counters->pkts_received + n_pkts;
2296 printf("vfw_port_in_action pkts_received: %" PRIu64
2298 vfw_pipe->counters->pkts_received, n_pkts);
2300 /* first handle handle any previously buffered packets now released */
2301 vfw_handle_buffered_packets(p, vfw_pipe, ct,
2302 FORWARD_BUFFERED_PACKETS);
2304 /* now handle any new packets on input ports */
2305 if (likely(firewall_flag)) {
2306 keep_mask = rte_vfw_ipv6_packet_filter_and_process(pkts,
2307 keep_mask, vfw_pipe);
2308 vfw_pipe->counters->pkts_fw_forwarded +=
2309 __builtin_popcountll(keep_mask);
2314 rte_prefetch0((void*)vfw_pipe->plib_acl);
2315 rte_prefetch0((void*)vfw_rule_table_ipv6_active);
2316 #endif /* EN_SWP_ACL */
2317 keep_mask = lib_acl_ipv6_pkt_work_key(
2318 vfw_pipe->plib_acl, pkts, keep_mask,
2319 &vfw_pipe->counters->pkts_drop_without_rule,
2320 vfw_rule_table_ipv6_active,
2321 action_array_active,
2322 action_counter_table,
2323 &conntrack_mask, &connexist_mask);
2324 vfw_pipe->counters->pkts_acl_forwarded +=
2325 __builtin_popcountll(keep_mask);
2326 if (conntrack_mask > 0) {
2327 keep_mask = conntrack_mask;
2328 ct_helper.no_new_cnxn_mask = connexist_mask;
2329 cnxn_tracking_is_active = 1;
2331 cnxn_tracking_is_active = 0;
2332 #endif /* ACL_ENABLE */
2333 if (likely(cnxn_tracking_is_active)) {
2334 rte_ct_cnxn_tracker_batch_lookup_type(ct, pkts,
2335 &keep_mask, &ct_helper, IPv6_HEADER_SIZE);
2336 synproxy_reply_mask = ct_helper.reply_pkt_mask;
2337 hijack_mask = ct_helper.hijack_mask;
2342 for(j = 0; j < (n_pkts & 0x3LLU); j++) {
2343 rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2345 rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2348 rte_prefetch0((void*)in_port_dir_a);
2349 rte_prefetch0(vfw_pipe->local_lib_nd_route_table);
2352 for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) {
2353 for (j = i+4; ((j < n_pkts) && (j < i+8)); j++) {
2354 rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2356 rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2359 pkt4_work_vfw_arp_ipv6_packets(&pkts[i], i, &keep_mask,
2360 synproxy_reply_mask, vfw_pipe);
2362 for (j = i; j < n_pkts; j++) {
2363 rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2365 rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2368 for (; i < n_pkts; i++) {
2369 pkt_work_vfw_arp_ipv6_packets(pkts[i], i, &keep_mask,
2370 synproxy_reply_mask, vfw_pipe);
2373 rte_prefetch0((void*)in_port_dir_a);
2374 rte_prefetch0((void*) & vfw_pipe->local_lib_arp_route_table);
2375 keep_mask = rte_vfw_arp_ipv6_packets(pkts, keep_mask,
2376 synproxy_reply_mask, vfw_pipe);
2379 if (vfw_debug > 1) {
2380 printf(" Exit in-port action with %p packet mask\n",
2382 if (keep_mask != packet_mask_in)
2383 printf("dropped packets, %p in, %p out\n",
2384 (void *)packet_mask_in,
2388 /* Update mask before returning, so that bad packets are dropped */
2390 pkts_drop_mask = packet_mask_in & ~keep_mask;
2392 if (unlikely(pkts_drop_mask != 0)) {
2393 /* printf("drop %p\n", (void *) pkts_drop_mask); */
2394 rte_pipeline_ah_packet_drop(p, pkts_drop_mask);
2397 if (unlikely(hijack_mask != 0))
2398 rte_pipeline_ah_packet_hijack(p, hijack_mask);
2400 vfw_pipe->counters->num_batch_pkts_sum += n_pkts;
2401 vfw_pipe->counters->num_pkts_measurements++;
2403 end_tsc_measure(vfw_pipe, n_pkts);
2410 * Parse arguments in config file.
2413 * A pointer to the pipeline.
2415 * A pointer to pipeline specific parameters.
2418 * 0 on success, negative on error.
2421 pipeline_vfw_parse_args(struct pipeline_vfw *vfw_pipe,
2422 struct pipeline_params *params)
2428 printf("VFW pipeline_vfw_parse_args params->n_args: %d\n",
2431 for (i = 0; i < params->n_args; i++) {
2432 char *arg_name = params->args_name[i];
2433 char *arg_value = params->args_value[i];
2435 printf("VFW args[%d]: %s %d, %s\n", i, arg_name,
2436 atoi(arg_value), arg_value);
2438 status = lib_acl_parse_config(vfw_pipe->plib_acl,
2439 arg_name, arg_value, &vfw_n_rules);
2441 printf("rte_ct_set_configuration_options =%s,%s",
2442 arg_name, arg_value);
2444 } else if (status == 0)
2447 #endif /* traffic_type */
2448 if (strcmp(arg_name, "traffic_type") == 0) {
2449 int traffic_type = atoi(arg_value);
2451 if (traffic_type == 0 ||
2452 !(traffic_type == IP_VERSION_4 ||
2453 traffic_type == IP_VERSION_6)) {
2454 printf("not IPV4/IPV6");
2458 vfw_pipe->traffic_type = traffic_type;
2464 if (strcmp(arg_name, "n_flows") == 0) {
2465 int n_flows = atoi(arg_value);
2470 /* must be power of 2, round up if not */
2471 if (!rte_is_power_of_2(n_flows))
2472 n_flows = rte_align32pow2(n_flows);
2474 vfw_pipe->n_flows = n_flows;
2478 /* not firewall option, process as cnxn tracking option */
2479 status = rte_ct_set_configuration_options(
2480 vfw_pipe->cnxn_tracker,
2481 arg_name, arg_value);
2483 printf("rte_ct_set_configuration_options =%s,%s",
2484 arg_name, arg_value);
2486 } else if (status == 0)
2494 static void *pipeline_vfw_msg_req_custom_handler(struct pipeline *p,
2497 static pipeline_msg_req_handler handlers[] = {
2498 [PIPELINE_MSG_REQ_PING] = pipeline_msg_req_ping_handler,
2499 [PIPELINE_MSG_REQ_STATS_PORT_IN] =
2500 pipeline_msg_req_stats_port_in_handler,
2501 [PIPELINE_MSG_REQ_STATS_PORT_OUT] =
2502 pipeline_msg_req_stats_port_out_handler,
2503 [PIPELINE_MSG_REQ_STATS_TABLE] = pipeline_msg_req_stats_table_handler,
2504 [PIPELINE_MSG_REQ_PORT_IN_ENABLE] =
2505 pipeline_msg_req_port_in_enable_handler,
2506 [PIPELINE_MSG_REQ_PORT_IN_DISABLE] =
2507 pipeline_msg_req_port_in_disable_handler,
2508 [PIPELINE_MSG_REQ_CUSTOM] = pipeline_vfw_msg_req_custom_handler,
2511 static void *pipeline_vfw_msg_req_synproxy_flag_handler(struct pipeline *p,
2513 static pipeline_msg_req_handler custom_handlers[] = {
2515 [PIPELINE_VFW_MSG_REQ_SYNPROXY_FLAGS] =
2516 pipeline_vfw_msg_req_synproxy_flag_handler
2520 * Create and initialize Pipeline Back End (BE).
2523 * A pointer to the pipeline specific parameters..
2525 * A pointer to pipeline specific data.
2528 * A pointer to the pipeline create, NULL on error.
2531 *pipeline_vfw_init(struct pipeline_params *params, __rte_unused void *arg)
2535 /* Check input arguments */
2536 if ((params == NULL) ||
2537 (params->n_ports_in == 0) || (params->n_ports_out == 0))
2541 printf("num ports in %d / num ports out %d\n",
2542 params->n_ports_in, params->n_ports_out);
2544 /* Create a single pipeline instance and initialize. */
2545 struct pipeline_vfw *pipe_vfw;
2547 size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_vfw));
2548 pipe_vfw = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
2550 if (pipe_vfw == NULL)
2553 struct pipeline *pipe;
2555 pipe = &pipe_vfw->pipe;
2557 strncpy(pipe->name, params->name, sizeof(pipe->name));
2558 pipe->log_level = params->log_level;
2559 pipe_vfw->n_flows = 4096; /* small default value */
2560 pipe_vfw->traffic_type = MIX;
2561 pipe_vfw->pipeline_num = 0xff;
2562 for (i = 0; i < PIPELINE_MAX_PORT_IN; i++) {
2563 pipe_vfw->links_map[i] = 0xff;
2564 pipe_vfw->outport_id[i] = 0xff;
2566 PLOG(pipe, HIGH, "VFW");
2568 /* Create a firewall instance and initialize. */
2569 pipe_vfw->cnxn_tracker =
2570 rte_zmalloc(NULL, rte_ct_get_cnxn_tracker_size(),
2571 RTE_CACHE_LINE_SIZE);
2573 if (pipe_vfw->cnxn_tracker == NULL)
2576 /* Create a acl instance and initialize. */
2577 pipe_vfw->plib_acl =
2578 rte_zmalloc(NULL, sizeof(struct lib_acl),
2579 RTE_CACHE_LINE_SIZE);
2581 if (pipe_vfw->plib_acl == NULL)
2584 timer_lcore = rte_lcore_id();
2586 * Now allocate a counter block entry. It appears that the
2587 * initialization of all instances is serialized on core 0,
2588 * so no lock is necessary.
2590 struct rte_VFW_counter_block *counter_ptr;
2592 if (rte_VFW_hi_counter_block_in_use == MAX_VFW_INSTANCES)
2593 /* error, exceeded table bounds */
2596 rte_VFW_hi_counter_block_in_use++;
2598 &rte_vfw_counter_table[rte_VFW_hi_counter_block_in_use];
2599 strncpy(counter_ptr->name, params->name, sizeof(counter_ptr->name));
2601 pipe_vfw->counters = counter_ptr;
2603 rte_ct_initialize_default_timeouts(pipe_vfw->cnxn_tracker);
2604 /* Parse arguments */
2605 if (pipeline_vfw_parse_args(pipe_vfw, params))
2608 uint16_t pointers_offset =
2609 META_DATA_OFFSET + offsetof(struct mbuf_tcp_meta_data, next);
2611 if (pipe_vfw->n_flows > 0)
2612 rte_ct_initialize_cnxn_tracker_with_synproxy(
2613 pipe_vfw->cnxn_tracker,
2618 pipe_vfw->counters->ct_counters =
2619 rte_ct_get_counter_address(pipe_vfw->cnxn_tracker);
2623 struct rte_pipeline_params pipeline_params = {
2624 .name = params->name,
2625 .socket_id = params->socket_id,
2626 .offset_port_id = META_DATA_OFFSET +
2627 offsetof(struct mbuf_tcp_meta_data, output_port)
2630 pipe->p = rte_pipeline_create(&pipeline_params);
2631 if (pipe->p == NULL) {
2640 * create a different "arg_ah" for each input port.
2641 * They differ only in the recorded port number. Unfortunately,
2642 * IP_PIPELINE does not pass port number in to input port handler
2645 uint32_t in_ports_arg_size =
2646 RTE_CACHE_LINE_ROUNDUP((sizeof(struct vfw_ports_in_args)) *
2647 (params->n_ports_in));
2648 struct vfw_ports_in_args *port_in_args =
2649 (struct vfw_ports_in_args *)
2650 rte_zmalloc(NULL, in_ports_arg_size, RTE_CACHE_LINE_SIZE);
2652 if (port_in_args == NULL)
2655 pipe->n_ports_in = params->n_ports_in;
2656 for (i = 0; i < pipe->n_ports_in; i++) {
2658 /* initialize this instance of port_in_args as necessary */
2659 port_in_args[i].pipe = pipe;
2660 port_in_args[i].cnxn_tracker = pipe_vfw->cnxn_tracker;
2662 struct rte_pipeline_port_in_params port_params = {
2664 pipeline_port_in_params_get_ops(¶ms->port_in
2667 pipeline_port_in_params_convert(¶ms->port_in
2669 .f_action = vfw_port_in_action_ipv4,
2670 .arg_ah = &(port_in_args[i]),
2671 .burst_size = params->port_in[i].burst_size,
2673 if (pipe_vfw->traffic_type == IP_VERSION_6)
2674 port_params.f_action = vfw_port_in_action_ipv6;
2675 int status = rte_pipeline_port_in_create(pipe->p, &port_params,
2676 &pipe->port_in_id[i]);
2679 rte_pipeline_free(pipe->p);
2686 pipe->n_ports_out = params->n_ports_out;
2687 for (i = 0; i < pipe->n_ports_out; i++) {
2688 struct rte_pipeline_port_out_params port_params = {
2689 .ops = pipeline_port_out_params_get_ops(
2690 ¶ms->port_out[i]),
2691 .arg_create = pipeline_port_out_params_convert(
2692 ¶ms->port_out[i]),
2697 int status = rte_pipeline_port_out_create(pipe->p, &port_params,
2698 &pipe->port_out_id[i]);
2701 rte_pipeline_free(pipe->p);
2707 int pipeline_num = 0;
2708 int dont_care = sscanf(params->name, "PIPELINE%d", &pipeline_num);
2711 printf("sscanf unble to read pipeline id\n");
2712 pipe_vfw->pipeline_num = (uint8_t) pipeline_num;
2713 register_pipeline_Qs(pipe_vfw->pipeline_num, pipe);
2714 set_link_map(pipe_vfw->pipeline_num, pipe, pipe_vfw->links_map);
2715 set_outport_id(pipe_vfw->pipeline_num, pipe,
2716 pipe_vfw->outport_id);
2717 printf("pipeline_num=%d\n", pipeline_num);
2719 /*If this is the first VFW thread, create common VFW Rule tables*/
2720 if (rte_VFW_hi_counter_block_in_use == 0) {
2721 vfw_rule_table_ipv4_active =
2722 lib_acl_create_active_standby_table_ipv4(1,
2724 if (vfw_rule_table_ipv4_active == NULL) {
2725 printf("Failed to create active table for IPV4\n");
2726 rte_pipeline_free(pipe->p);
2727 rte_free(pipe_vfw->cnxn_tracker);
2728 rte_free(pipe_vfw->plib_acl);
2732 vfw_rule_table_ipv4_standby =
2733 lib_acl_create_active_standby_table_ipv4(2,
2735 if (vfw_rule_table_ipv4_standby == NULL) {
2736 printf("Failed to create standby table for IPV4\n");
2737 rte_pipeline_free(pipe->p);
2738 rte_free(pipe_vfw->cnxn_tracker);
2739 rte_free(pipe_vfw->plib_acl);
2744 vfw_rule_table_ipv6_active =
2745 lib_acl_create_active_standby_table_ipv6(1,
2748 if (vfw_rule_table_ipv6_active == NULL) {
2749 printf("Failed to create active table for IPV6\n");
2750 rte_pipeline_free(pipe->p);
2751 rte_free(pipe_vfw->cnxn_tracker);
2752 rte_free(pipe_vfw->plib_acl);
2756 vfw_rule_table_ipv6_standby =
2757 lib_acl_create_active_standby_table_ipv6(2,
2759 if (vfw_rule_table_ipv6_standby == NULL) {
2760 printf("Failed to create standby table for IPV6\n");
2761 rte_pipeline_free(pipe->p);
2762 rte_free(pipe_vfw->cnxn_tracker);
2763 rte_free(pipe_vfw->plib_acl);
2775 struct rte_pipeline_table_params table_params = {
2776 .ops = &rte_table_stub_ops,
2778 .f_action_hit = NULL,
2779 .f_action_miss = NULL,
2781 .action_data_size = 0,
2784 int status = rte_pipeline_table_create(pipe->p,
2786 &pipe->table_id[0]);
2789 rte_pipeline_free(pipe->p);
2794 struct rte_pipeline_table_entry default_entry = {
2795 .action = RTE_PIPELINE_ACTION_PORT_META
2798 struct rte_pipeline_table_entry *default_entry_ptr;
2800 status = rte_pipeline_table_default_entry_add(pipe->p,
2803 &default_entry_ptr);
2806 rte_pipeline_free(pipe->p);
2810 for (i = 0; i < pipe->n_ports_in; i++) {
2811 int status = rte_pipeline_port_in_connect_to_table(
2813 pipe->port_in_id[i],
2817 rte_pipeline_free(pipe->p);
2823 /* Enable input ports */
2824 for (i = 0; i < pipe->n_ports_in; i++) {
2826 rte_pipeline_port_in_enable(pipe->p, pipe->port_in_id[i]);
2829 rte_pipeline_free(pipe->p);
2835 /* Check pipeline consistency */
2836 if (rte_pipeline_check(pipe->p) < 0) {
2837 rte_pipeline_free(pipe->p);
2842 /* Message queues */
2843 pipe->n_msgq = params->n_msgq;
2844 for (i = 0; i < pipe->n_msgq; i++)
2845 pipe->msgq_in[i] = params->msgq_in[i];
2847 for (i = 0; i < pipe->n_msgq; i++)
2848 pipe->msgq_out[i] = params->msgq_out[i];
2850 /* Message handlers */
2851 memcpy(pipe->handlers, handlers, sizeof(pipe->handlers));
2852 memcpy(pipe_vfw->custom_handlers, custom_handlers,
2853 sizeof(pipe_vfw->custom_handlers));
2859 * Free resources and delete pipeline.
2862 * A pointer to the pipeline.
2865 * 0 on success, negative on error.
2867 static int pipeline_vfw_free(void *pipeline)
2869 struct pipeline *p = (struct pipeline *)pipeline;
2871 /* Check input arguments */
2875 /* Free resources */
2876 rte_pipeline_free(p->p);
2882 * Callback function to map input/output ports.
2885 * A pointer to the pipeline.
2889 * A pointer to the Output port.
2892 * 0 on success, negative on error.
2895 pipeline_vfw_track(void *pipeline, __rte_unused uint32_t port_in,
2898 struct pipeline *p = (struct pipeline *)pipeline;
2900 /* Check input arguments */
2901 if ((p == NULL) || (port_in >= p->n_ports_in) || (port_out == NULL))
2904 if (p->n_ports_in == 1) {
2913 * Callback function to process timers.
2916 * A pointer to the pipeline.
2919 * 0 on success, negative on error.
2921 static int pipeline_vfw_timer(void *pipeline)
2923 struct pipeline_vfw *p = (struct pipeline_vfw *)pipeline;
2926 * handle any good buffered packets released by synproxy before checking
2927 * for packets relased by synproxy due to timeout.
2928 * Don't want packets missed
2931 vfw_handle_buffered_packets(p->pipe.p, p, p->cnxn_tracker,
2932 FORWARD_BUFFERED_PACKETS);
2934 pipeline_msg_req_handle(&p->pipe);
2935 rte_pipeline_flush(p->pipe.p);
2937 rte_ct_handle_expired_timers(p->cnxn_tracker);
2939 /* now handle packets released by synproxy due to timeout. */
2940 vfw_handle_buffered_packets(p->pipe.p, p, p->cnxn_tracker,
2941 DELETE_BUFFERED_PACKETS);
2947 * Callback function to process CLI commands from FE.
2950 * A pointer to the pipeline.
2952 * A pointer to command specific data.
2955 * A pointer to message handler on success,
2956 * pipeline_msg_req_invalid_hander on error.
2958 void *pipeline_vfw_msg_req_custom_handler(struct pipeline *p, void *msg)
2960 struct pipeline_vfw *pipe_vfw = (struct pipeline_vfw *)p;
2961 struct pipeline_custom_msg_req *req = msg;
2962 pipeline_msg_req_handler f_handle;
2964 f_handle = (req->subtype < PIPELINE_VFW_MSG_REQS) ?
2965 pipe_vfw->custom_handlers[req->subtype] :
2966 pipeline_msg_req_invalid_handler;
2968 if (f_handle == NULL)
2969 f_handle = pipeline_msg_req_invalid_handler;
2971 return f_handle(p, req);
2975 * Handler for synproxy ON/OFF CLI command.
2978 * A pointer to the pipeline.
2980 * A pointer to command specific data.
2983 * Response message contains status.
2986 void *pipeline_vfw_msg_req_synproxy_flag_handler(struct pipeline *p,
2989 struct pipeline_vfw *pipe_vfw = (struct pipeline_vfw *)p;
2990 struct pipeline_vfw_synproxy_flag_msg_req *req = msg;
2991 struct pipeline_vfw_synproxy_flag_msg_rsp *rsp = msg;
2993 if (req->synproxy_flag == 0) {
2994 rte_ct_disable_synproxy(pipe_vfw->cnxn_tracker);
2996 printf("synproxy turned OFF for %s\n", p->name);
2997 } else if (req->synproxy_flag == 1) {
2998 rte_ct_enable_synproxy(pipe_vfw->cnxn_tracker);
3000 printf("synproxy turned ON for %s\n", p->name);
3002 printf("Invalid synproxy setting\n");
3009 struct pipeline_be_ops pipeline_vfw_be_ops = {
3010 .f_init = pipeline_vfw_init,
3011 .f_free = pipeline_vfw_free,
3013 .f_timer = pipeline_vfw_timer,
3014 .f_track = pipeline_vfw_track,