70057b41e7a7e29bcb3148e4509c2be876552995
[samplevnf.git] / VNFs / vFW / pipeline / pipeline_vfw_be.c
1 /*
2 // Copyright (c) 2017 Intel Corporation
3 //
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
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
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.
15 */
16
17 /**
18  * @file
19  * Pipeline VFW BE Implementation.
20  *
21  * Implementation of Pipeline VFW Back End (BE).
22  * Responsible for packet processing.
23  *
24  */
25
26 #define EN_SWP_ACL 1
27 #define EN_SWP_ARP 1
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <stddef.h>
33 #include <string.h>
34 #include <unistd.h>
35
36 #include <rte_common.h>
37 #include <rte_malloc.h>
38 #include <rte_ether.h>
39 #include <rte_ethdev.h>
40 #include <rte_ip.h>
41 #include <rte_udp.h>
42 #include <rte_icmp.h>
43 #include <rte_byteorder.h>
44
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"
63
64 #include "lib_arp.h"
65 #include "lib_icmpv6.h"
66 #include "pipeline_common_fe.h"
67
68 uint32_t timer_lcore;
69
70 uint8_t firewall_flag = 1;
71 uint8_t VFW_DEBUG;
72 uint8_t cnxn_tracking_is_active = 1;
73 /**
74  * A structure defining the VFW pipeline input port per thread data.
75  */
76 struct vfw_ports_in_args {
77        struct pipeline *pipe;
78        struct rte_ct_cnxn_tracker *cnxn_tracker;
79 } __rte_cache_aligned;
80 /**
81  * A structure defining the VFW pipeline per thread data.
82  */
83 struct pipeline_vfw {
84        struct pipeline pipe;
85        pipeline_msg_req_handler custom_handlers[PIPELINE_VFW_MSG_REQS];
86
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 */
92        uint32_t n_flows;
93        uint8_t pipeline_num;
94        uint8_t traffic_type;
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;
104
105 } __rte_cache_aligned;
106 /**
107  * A structure defining the mbuf meta data for VFW.
108  */
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;
114
115 #define DONT_CARE_TCP_PACKET 0
116 #define IS_NOT_TCP_PACKET 0
117 #define IS_TCP_PACKET 1
118
119 #define META_DATA_OFFSET 128
120
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)
125
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
131
132 #define TCP_PROTOCOL 6
133 #define UDP_PROTOCOL 17
134
135 #define DELETE_BUFFERED_PACKETS 0
136 #define FORWARD_BUFFERED_PACKETS 1
137 #define DO_ARP 1
138 #define NO_ARP 0
139
140 #define IPv4_HEADER_SIZE 20
141 #define IPv6_HEADER_SIZE 40
142
143 #define IP_VERSION_4 4
144 #define IP_VERSION_6 6
145 #define MIX 10
146 /* IPv6 */
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]
155 __rte_cache_aligned;
156 int rte_VFW_hi_counter_block_in_use = -1;
157
158 /* a spin lock used during vfw initialization only */
159 rte_spinlock_t rte_VFW_init_lock = RTE_SPINLOCK_INITIALIZER;
160
161 /* Action Array */
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]
169 __rte_cache_aligned;
170 /*
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
178   */
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
183 };
184
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} }
202 };
203
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;
212 }
213
214 /* End TSC measurement */
215 static inline void end_tsc_measure(
216        struct pipeline_vfw *vfw_pipe,
217        uint8_t n_pkts)
218 {
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++;
225        } else {
226               /* small counts skew results, ignore */
227               vfw_pipe->counters->exit_timestamp = 0;
228        }
229 }
230
231 static struct ether_addr *get_local_link_hw_addr(uint8_t out_port)
232 {
233        return &link_hw_laddr[out_port];
234 }
235
236 static uint8_t local_dest_mac_present(uint8_t out_port)
237 {
238        return link_hw_laddr_valid[out_port];
239 }
240
241 static uint32_t local_get_nh_ipv4(
242        uint32_t ip,
243        uint32_t *port,
244        uint32_t *nhip,
245        struct pipeline_vfw *vfw_pipe)
246 {
247        int i;
248
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;
254
255                      *nhip = vfw_pipe->local_lib_arp_route_table[i].nh;
256                      return 1;
257               }
258        }
259        return 0;
260 }
261
262 static void do_local_nh_ipv4_cache(uint32_t dest_if,
263               struct pipeline_vfw *vfw_pipe)
264 {
265
266        /* Search for the entry and do local copy */
267        int i;
268
269        for (i = 0; i < MAX_ARP_RT_ENTRY; i++) {
270               if (lib_arp_route_table[i].port == dest_if) {
271
272                      struct lib_arp_route_table_entry *lentry =
273                             &vfw_pipe->
274                             local_lib_arp_route_table[vfw_pipe->
275                             local_lib_arp_route_ent_cnt];
276
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;
281
282                      vfw_pipe->local_lib_arp_route_ent_cnt++;
283                      break;
284               }
285        }
286 }
287 static uint32_t local_get_nh_ipv6(
288        uint8_t *ip,
289        uint32_t *port,
290        uint8_t nhip[],
291         struct pipeline_vfw *vfw_pipe)
292 {
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));
299
300        for (i = 0; i < vfw_pipe->local_lib_nd_route_ent_cnt; i++) {
301
302               convert_prefixlen_to_netmask_ipv6(
303                      vfw_pipe->local_lib_nd_route_table[i].depth,
304                      netmask_ipv6);
305
306               for (k = 0; k < IPV6_ADD_SIZE; k++)
307                      if (vfw_pipe->local_lib_nd_route_table[i].ipv6[k] &
308                                    netmask_ipv6[k]) {
309                             depthflags++;
310                             netip_nd[k] = vfw_pipe->
311                                    local_lib_nd_route_table[i].ipv6[k];
312                      }
313
314               for (l = 0; l < IPV6_ADD_SIZE; l++)
315                      if (ip[l] & netmask_ipv6[l]) {
316                             depthflags1++;
317                             netip_in[l] = ip[l];
318                      }
319
320
321               if ((depthflags == depthflags1) && (memcmp(netip_nd, netip_in,
322                                           sizeof(netip_nd)) == 0)) {
323
324                      *port = vfw_pipe->local_lib_nd_route_table[i].port;
325
326                      for (j = 0; j < IPV6_ADD_SIZE; j++)
327                             nhip[j] = vfw_pipe->
328                                    local_lib_nd_route_table[i].nhipv6[j];
329                      return 1;
330               }
331
332               depthflags = 0;
333               depthflags1 = 0;
334                      }
335                      return 0;
336 }
337
338 static void do_local_nh_ipv6_cache(uint32_t dest_if,
339               struct pipeline_vfw *vfw_pipe)
340 {
341               /* Search for the entry and do local copy */
342        int i, l;
343
344        for (i = 0; i < MAX_ND_RT_ENTRY; i++) {
345
346               if (lib_nd_route_table[i].port == dest_if) {
347
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];
351
352                      for (l = 0; l < IPV6_ADD_SIZE; l++) {
353                             lentry->ipv6[l]   =
354                                    lib_nd_route_table[i].ipv6[l];
355                             lentry->nhipv6[l] =
356                                    lib_nd_route_table[i].nhipv6[l];
357                      }
358                      lentry->depth = lib_nd_route_table[i].depth;
359                      lentry->port  = lib_nd_route_table[i].port;
360
361                      vfw_pipe->local_lib_nd_route_ent_cnt++;
362                      break;
363                      } /* if */
364               } /* for */
365 }
366 /**
367  * Print packet for debugging.
368  *
369  * @param pkt
370  *  A pointer to the packet.
371  *
372  */
373 static __rte_unused  void print_pkt(struct rte_mbuf *pkt)
374 {
375        int i;
376        int size = (int)sizeof(struct mbuf_tcp_meta_data);
377        uint8_t *rd = RTE_MBUF_METADATA_UINT8_PTR(pkt, META_DATA_OFFSET);
378
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)
383                      printf("\n");
384        }
385        printf("\n");
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)
391                      printf("\n");
392        }
393        printf("\n");
394 }
395
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
401
402 /**
403  * Return ethernet header structure form packet.
404  *
405  * @param pkt
406  *  A pointer to the packet.
407  *
408  */
409 static inline struct ether_hdr *rte_vfw_get_ether_addr(struct rte_mbuf *pkt)
410 {
411        return (struct ether_hdr *)RTE_MBUF_METADATA_UINT32_PTR(pkt,
412                                                         ETHERNET_START);
413 }
414
415 /**
416  * Return IPV4 header structure form packet.
417  *
418  * @param pkt
419  *  A pointer to the packet.
420  *
421  */
422
423 static inline struct ipv4_hdr *rte_vfw_get_IPv4_hdr_addr(
424               struct rte_mbuf *pkt)
425 {
426        return (struct ipv4_hdr *)RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
427 }
428
429 static inline int rte_vfw_is_IPv4(struct rte_mbuf *pkt)
430 {
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)
434               >> VERSION_NO_BYTE;
435
436        return ip_type == IPv4_HDR_VERSION;
437 }
438
439 static inline int rte_vfw_is_IPv6(struct rte_mbuf *pkt)
440 {
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)
444               >> VERSION_NO_BYTE;
445
446        return ip_type == IPv6_HDR_VERSION;
447 }
448
449 static inline void rte_vfw_incr_drop_ctr(uint64_t *counter)
450 {
451        if (likely(firewall_flag))
452               (*counter)++;
453 }
454
455 static uint8_t check_arp_icmp(
456               struct rte_mbuf *pkt,
457               struct pipeline_vfw *vfw_pipe)
458 {
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};
464
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];
470
471        ehdr = rte_vfw_get_ether_addr(pkt);
472        switch (rte_be_to_cpu_16(ehdr->ether_type)) {
473
474        case ETH_TYPE_ARP:
475               rte_pipeline_port_out_packet_insert(
476                             vfw_pipe->pipe.p,
477                             out_port,
478                             pkt);
479
480               vfw_pipe->counters->arpicmpPktCount++;
481
482               return 0;
483        case ETH_TYPE_IPV4:
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) &&
487                             link->ip ==
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(
491                                           vfw_pipe->pipe.p,
492                                           out_port,
493                                           pkt);
494
495                      vfw_pipe->counters->arpicmpPktCount++;
496                             return 0;
497                      }
498               }
499               break;
500 #ifdef IPV6
501         case ETH_TYPE_IPV6:
502                 ipv6_h = (struct ipv6_hdr *)
503                         RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
504
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)) {
510
511                                 rte_pipeline_port_out_packet_insert(
512                                                 vfw_pipe->pipe.p,
513                                                 out_port,
514                                                 pkt);
515
516                                 vfw_pipe->counters->arpicmpPktCount++;
517
518                         } else
519                                 vfw_pipe->counters->
520                                         pkts_drop_unsupported_type++;
521
522                         return 0;
523                 }
524                 break;
525 #endif
526        default:
527               break;
528 }
529        return 1;
530 }
531
532 /**
533  * Performs basic VFW ipv4 packet filtering.
534  * @param pkts
535  *  A pointer to the packets.
536  * @param pkts_mask
537  *  packet mask.
538  * @param vfw_pipe
539  *  A pointer to VFW pipeline.
540  */
541
542 static uint64_t
543 rte_vfw_ipv4_packet_filter_and_process(struct rte_mbuf **pkts,
544                                  uint64_t pkts_mask,
545                                  struct pipeline_vfw *vfw_pipe)
546 {
547
548        /*
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.
556         */
557
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;
564
565        if (unlikely(pkts_mask == 0))
566               return pkts_mask;
567        pos = (uint8_t) __builtin_ctzll(pkts_mask);
568        pkt_mask = 1LLU << pos;       /* bitmask representing only this packet */
569        pkt = pkts[pos];
570
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;
576
577        rte_prefetch0(pkt);
578        /* prefetch counters, updated below. Most likely counters to update
579         * at beginnning */
580        rte_prefetch0(&vfw_pipe->counters);
581
582        do {                     /* always execute at least once */
583
584               /* remove this packet from remaining list */
585               uint64_t next_pkts_to_process = pkts_to_process &= ~pkt_mask;
586
587               if (likely(next_pkts_to_process)) {
588                      /* another packet to process after this, prefetch it */
589
590                      next_pos =
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,
594                                    IP_START);
595                      rte_prefetch0(next_iphdr);
596               }
597
598               int discard = 0;
599               /* remove this packet from remaining list */
600               pkts_to_process &= ~pkt_mask;
601
602               if (enable_hwlb)
603                      if (!check_arp_icmp(pkt, vfw_pipe))
604                             discard = 1;
605
606               uint32_t packet_length = rte_pktmbuf_pkt_len(pkt);
607
608               bytes_processed += packet_length;
609
610               ihdr4 = (struct ipv4_hdr *)
611                      RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
612
613               /* verify that packet size according to mbuf is at least
614                * as large as the size according to the IP header.
615                */
616
617               uint32_t ip_length = rte_bswap16(ihdr4->total_length);
618
619               if (unlikely
620                             (ip_length > (packet_length - ETH_HDR_SIZE))) {
621                      discard = 1;
622                      vfw_pipe->counters->pkts_drop_bad_size++;
623               }
624
625               /*
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.
630                */
631
632               int fragmented = (ihdr4->fragment_offset & 0xff3f) != 0;
633               uint8_t ttl = ihdr4->time_to_live;
634
635               if (unlikely(fragmented)) {
636                      discard = 1;
637                      vfw_pipe->counters->pkts_drop_fragmented++;
638               }
639
640               /*
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.
646                */
647
648               if (unlikely(ttl <= 1)) {
649                      /*
650                       * about to decrement to zero (or is somehow
651                       * already zero), so discard
652                       */
653                      discard = 1;
654                      vfw_pipe->counters->pkts_drop_ttl++;
655               }
656
657               /*
658                * Dropping the packets other than TCP AND UDP.
659                */
660
661               uint8_t proto = ihdr4->next_proto_id;
662
663               if (unlikely(!(proto == IP_TCP_PROTOCOL ||
664                                           proto == IP_UDP_PROTOCOL ||
665                                           proto == IP_ICMP_PROTOCOL))) {
666                      discard = 1;
667                      vfw_pipe->counters->
668                             pkts_drop_unsupported_type++;
669               }
670
671               if (unlikely(discard)) {
672                      valid_packets &= ~pkt_mask;
673               } else {
674                      ihdr4->time_to_live = ttl - 1;
675
676                      /* update header checksum, from rfc 1141 */
677                      uint32_t sum;
678                      uint16_t checksum = rte_bswap16(
679                                    ihdr4->hdr_checksum);
680                      /* increment checksum high byte */
681                      sum = checksum + 0x100;
682                      /* add carry */
683                      checksum = (sum + (sum >> BIT_CARRY));
684                      ihdr4->hdr_checksum = rte_bswap16(checksum);
685               }
686
687               /* make next packet data the current */
688               pkts_to_process = next_pkts_to_process;
689               pos = next_pos;
690               pkt = next_pkt;
691               ihdr4 = next_iphdr;
692               pkt_mask = 1LLU << pos;
693
694        } while (pkts_to_process);
695
696        /* finalize counters, etc. */
697        vfw_pipe->counters->bytes_processed += bytes_processed;
698
699        if (likely(firewall_flag))
700               return valid_packets;
701        else
702               return pkts_mask;
703 }
704 /**
705  * Performs basic VFW IPV6 packet filtering.
706  * @param pkts
707  *  A pointer to the packets.
708  * @param pkts_mask
709  *  packet mask.
710  * @param vfw_pipe
711  *  A pointer to VFW pipeline.
712  */
713        static uint64_t
714 rte_vfw_ipv6_packet_filter_and_process(struct rte_mbuf **pkts,
715               uint64_t pkts_mask,
716               struct pipeline_vfw *vfw_pipe)
717 {
718
719        /*
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.
727         */
728
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;
735
736        if (unlikely(pkts_mask == 0))
737               return pkts_mask;
738        pos = (uint8_t) __builtin_ctzll(pkts_mask);
739        pkt_mask = 1LLU << pos;       /* bitmask representing only this packet */
740        pkt = pkts[pos];
741
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;
747
748        /* prefetch counters, updated below. Most likely counters to update
749         * at beginnning */
750        rte_prefetch0(&vfw_pipe->counters);
751
752        do {                     /* always execute at least once */
753
754               /* remove this packet from remaining list */
755               uint64_t next_pkts_to_process = pkts_to_process &= ~pkt_mask;
756
757               if (likely(next_pkts_to_process)) {
758                      /* another packet to process after this, prefetch it */
759
760                      next_pos =
761                          (uint8_t) __builtin_ctzll(next_pkts_to_process);
762                      next_pkt = pkts[next_pos];
763                      next_iphdr =
764                          RTE_MBUF_METADATA_UINT32_PTR(next_pkt, IP_START);
765                      rte_prefetch0(next_iphdr);
766               }
767
768               int discard = 0;
769               /* remove this packet from remaining list */
770               pkts_to_process &= ~pkt_mask;
771
772               if (enable_hwlb)
773                      if (!check_arp_icmp(pkt, vfw_pipe))
774                             discard = 1;
775
776               uint32_t packet_length = rte_pktmbuf_pkt_len(pkt);
777
778               bytes_processed += packet_length;
779
780               ihdr6 = (struct ipv6_hdr *)
781                      RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
782
783               /*
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
788                */
789
790               uint32_t ip_length =
791                      rte_bswap16(ihdr6->payload_len) + IPv6_HEADER_SIZE;
792
793               if (unlikely
794                             (ip_length > (packet_length - ETH_HDR_SIZE))) {
795                      discard = 1;
796                      vfw_pipe->counters->pkts_drop_bad_size++;
797               }
798
799               /*
800                * Dropping the packets other than TCP AND UDP.
801                */
802
803               uint8_t proto = ihdr6->proto;
804
805               if (unlikely(!(proto == IP_TCP_PROTOCOL ||
806                                           proto == IP_UDP_PROTOCOL ||
807                                           proto == IP_ICMP_PROTOCOL))) {
808                      discard = 1;
809                      if (proto == IPv6_FRAGMENT_HEADER)
810                             vfw_pipe->counters->
811                                    pkts_drop_fragmented++;
812                      else
813                             vfw_pipe->counters->
814                                    pkts_drop_unsupported_type++;
815               }
816
817               /*
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.
823                */
824
825               if (unlikely(ihdr6->hop_limits <= 1)) {
826                      /*
827                       * about to decrement to zero (or is somehow
828                       * already zero), so discard
829                       */
830                      discard = 1;
831                      vfw_pipe->counters->pkts_drop_ttl++;
832               }
833
834               if (unlikely(discard))
835                      valid_packets &= ~pkt_mask;
836               else
837                      ihdr6->hop_limits--;
838
839               /* make next packet data the current */
840               pkts_to_process = next_pkts_to_process;
841               pos = next_pos;
842               pkt = next_pkt;
843               ihdr6 = next_iphdr;
844               pkt_mask = 1LLU << pos;
845
846        } while (pkts_to_process);
847
848        /* finalize counters, etc. */
849        vfw_pipe->counters->bytes_processed += bytes_processed;
850
851        if (likely(firewall_flag))
852               return valid_packets;
853        else
854               return pkts_mask;
855 }
856
857 /**
858  * exchange the mac address so source becomes destination and vice versa.
859  *
860  * @param ehdr
861  *  A pointer to the ethernet header.
862  *
863  */
864 static inline void rte_sp_exchange_mac_addresses(struct ether_hdr *ehdr)
865 {
866        struct ether_addr saved_copy;
867
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);
871 }
872 #ifdef EN_SWP_ARP
873
874 /**
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
880  *
881  * @param pkts
882  *  A pointer to the packet array.
883  * @param pkt_num
884  *  Packet num to start processing
885  * @param pkts_mask
886  *  Packet mask
887  * @param synproxy_reply_mask
888  *  Reply Packet mask for Synproxy
889  * @param vfw_pipe
890  *  A pointer to VFW pipeline.
891  */
892 static void
893 pkt4_work_vfw_arp_ipv4_packets(struct rte_mbuf **pkts,
894               uint16_t pkt_num,
895               uint64_t *pkts_mask,
896               uint64_t synproxy_reply_mask,
897               struct pipeline_vfw *vfw_pipe)
898 {
899
900        uint32_t ret;
901        int ret_mac;
902        uint8_t i;
903
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;
908        uint16_t phy_port;
909
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);
914
915               pkt = pkts[i];
916
917               if(!(*pkts_mask & pkt_mask))
918                      continue;
919
920               int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
921
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);
926
927
928               struct ipv4_hdr *ihdr = (struct ipv4_hdr *)
929                      RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
930               uint32_t nhip = 0;
931
932               uint32_t dest_address = rte_bswap32(ihdr->dst_addr);
933
934               ret = local_get_nh_ipv4(dest_address, &dest_if,
935                             &nhip, vfw_pipe);
936               if (must_reverse) {
937                      rte_sp_exchange_mac_addresses(ehdr);
938                      if (is_phy_port_privte(phy_port)) {
939                             if (!ret) {
940                                    dest_if = get_pub_to_prv_port(
941                                                  &dest_address,
942                                                  IP_VERSION_4);
943                                    if (dest_if == INVALID_DESTIF) {
944                                           *pkts_mask &= ~pkt_mask;
945                                           vfw_pipe->counters->
946                                           pkts_drop_without_arp_entry++;
947                                    }
948                                    do_local_nh_ipv4_cache(
949                                                  dest_if, vfw_pipe);
950                             }
951
952                      } else {
953                             if (!ret) {
954                                    dest_if = get_prv_to_pub_port(
955                                                  &dest_address,
956                                                  IP_VERSION_4);
957                                    if (dest_if == INVALID_DESTIF) {
958                                           *pkts_mask &= ~pkt_mask;
959                                           vfw_pipe->counters->
960                                           pkts_drop_without_arp_entry++;
961                                    }
962                                    do_local_nh_ipv4_cache(dest_if,
963                                                  vfw_pipe);
964                             }
965                      }
966               } else if (is_phy_port_privte(phy_port)) {
967                      if (!ret) {
968                             dest_if = get_prv_to_pub_port(&dest_address,
969                                           IP_VERSION_4);
970                             if (dest_if == INVALID_DESTIF) {
971                                    *pkts_mask &= ~pkt_mask;
972                                    vfw_pipe->counters->
973                                           pkts_drop_without_arp_entry++;
974                             }
975                             do_local_nh_ipv4_cache(dest_if, vfw_pipe);
976                      }
977
978               } else {
979                      if (!ret) {
980                             dest_if = get_pub_to_prv_port(&dest_address,
981                                           IP_VERSION_4);
982                             if (dest_if == INVALID_DESTIF) {
983                                    *pkts_mask &= ~pkt_mask;
984                                    vfw_pipe->counters->
985                                           pkts_drop_without_arp_entry++;
986                             }
987                             do_local_nh_ipv4_cache(dest_if, vfw_pipe);
988                      }
989
990               }
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),
994                                    &ehdr->d_addr);
995                      ether_addr_copy(get_link_hw_addr(dest_if),
996                                    &ehdr->s_addr);
997               } else {
998                      ret_mac = get_dest_mac_addr_port(dest_address,
999                                    &dest_if, &hw_addr);
1000                      if (ret_mac == ARP_FOUND) {
1001
1002                             link_hw_laddr_valid[dest_if] = 1;
1003                             memcpy(&link_hw_laddr[dest_if], &hw_addr,
1004                                           sizeof(struct ether_addr));
1005
1006                             ether_addr_copy(&hw_addr, &ehdr->d_addr);
1007                             ether_addr_copy(get_link_hw_addr(dest_if),
1008                                           &ehdr->s_addr);
1009
1010                             if (vfw_debug >= DEBUG_LEVEL_4) {
1011                                    char buf[HW_ADDR_SIZE];
1012
1013                                    ether_format_addr(buf, sizeof(buf),
1014                                                  &hw_addr);
1015                                    printf("MAC found for ip 0x%"
1016                                           PRIx32", dest_if %d: %s, ",
1017                                           dest_address,
1018                                           dest_if, buf);
1019                                    ether_format_addr(buf, sizeof(buf),
1020                                                  &ehdr->s_addr);
1021                                    printf("new eth hdr src: %s, ", buf);
1022                                    ether_format_addr(buf, sizeof(buf),
1023                                                  &ehdr->d_addr);
1024                                    printf("new eth hdr dst: %s\n", buf);
1025                             }
1026
1027                      } else {
1028
1029                             if (vfw_debug >= DEBUG_LEVEL_4) {
1030                                    char buf[HW_ADDR_SIZE];
1031
1032                                    ether_format_addr(buf, sizeof(buf),
1033                                           &hw_addr);
1034                                    printf("MAC NOT FOUND for ip 0x%"
1035                                           PRIx32", dest_if %"
1036                                           PRId16": %s, ",
1037                                           dest_address,
1038                                           dest_if, buf);
1039                             }
1040                             /* ICMP req sent, drop packet by
1041                              * changing the mask */
1042                             *pkts_mask &= ~pkt_mask;
1043                             vfw_pipe->
1044                                    counters->pkts_drop_without_arp_entry++;
1045                      }
1046               }
1047        }
1048 }
1049
1050
1051 /**
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
1057  *
1058  * @param pkts
1059  *  A pointer to the packet.
1060  * @param packet_num
1061  *  Packet number to process
1062  * @param pkts_mask
1063  *  Packet mask pointer
1064  * @param synproxy_reply_mask
1065  *  Reply Packet mask for Synproxy
1066  * @param vfw_pipe
1067  *  A pointer to VFW pipeline.
1068  */
1069 static void
1070 pkt_work_vfw_arp_ipv4_packets(struct rte_mbuf *pkts,
1071               uint16_t pkt_num,
1072               uint64_t *pkts_mask,
1073               uint64_t synproxy_reply_mask,
1074               struct pipeline_vfw *vfw_pipe)
1075 {
1076
1077        uint32_t ret;
1078        uint32_t dest_if = INVALID_DESTIF;
1079        int ret_mac;
1080
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;
1085        uint16_t phy_port;
1086        uint64_t pkt_mask = 1LLU << pkt_num;
1087
1088        pkt = pkts;
1089
1090        if(*pkts_mask & pkt_mask) {
1091
1092               int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
1093
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);
1098
1099
1100               struct ipv4_hdr *ihdr = (struct ipv4_hdr *)
1101                      RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
1102               uint32_t nhip = 0;
1103
1104               uint32_t dest_address = rte_bswap32(ihdr->dst_addr);
1105
1106               ret = local_get_nh_ipv4(dest_address, &dest_if,
1107                             &nhip, vfw_pipe);
1108               if (must_reverse) {
1109                      rte_sp_exchange_mac_addresses(ehdr);
1110                      if (is_phy_port_privte(phy_port)) {
1111                             if (!ret) {
1112                                    dest_if = get_pub_to_prv_port(
1113                                                  &dest_address,
1114                                                  IP_VERSION_4);
1115                                    if (dest_if == INVALID_DESTIF) {
1116                                           *pkts_mask &= ~pkt_mask;
1117                                           vfw_pipe->counters->
1118                                           pkts_drop_without_arp_entry++;
1119                                    }
1120                                    do_local_nh_ipv4_cache(
1121                                                  dest_if, vfw_pipe);
1122                             }
1123
1124                      } else {
1125                             if (!ret) {
1126                                    dest_if = get_prv_to_pub_port(
1127                                                  &dest_address,
1128                                                  IP_VERSION_4);
1129                                    if (dest_if == INVALID_DESTIF) {
1130                                           *pkts_mask &= ~pkt_mask;
1131                                           vfw_pipe->counters->
1132                                           pkts_drop_without_arp_entry++;
1133                                    }
1134                                    do_local_nh_ipv4_cache(dest_if,
1135                                                  vfw_pipe);
1136                             }
1137                      }
1138               } else if (is_phy_port_privte(phy_port)) {
1139                      if (!ret) {
1140                             dest_if = get_prv_to_pub_port(&dest_address,
1141                                           IP_VERSION_4);
1142                             if (dest_if == INVALID_DESTIF) {
1143                                    *pkts_mask &= ~pkt_mask;
1144                                    vfw_pipe->counters->
1145                                           pkts_drop_without_arp_entry++;
1146                             }
1147                             do_local_nh_ipv4_cache(dest_if, vfw_pipe);
1148                      }
1149
1150               } else {
1151                      if (!ret) {
1152                             dest_if = get_pub_to_prv_port(&dest_address,
1153                                           IP_VERSION_4);
1154                             if (dest_if == INVALID_DESTIF) {
1155                                    *pkts_mask &= ~pkt_mask;
1156                                    vfw_pipe->counters->
1157                                           pkts_drop_without_arp_entry++;
1158                             }
1159                             do_local_nh_ipv4_cache(dest_if, vfw_pipe);
1160                      }
1161
1162               }
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),
1166                                    &ehdr->d_addr);
1167                      ether_addr_copy(get_link_hw_addr(dest_if),
1168                                    &ehdr->s_addr);
1169               } else {
1170                      ret_mac = get_dest_mac_addr_port(dest_address,
1171                                    &dest_if, &hw_addr);
1172                      if (ret_mac) {
1173                             link_hw_laddr_valid[dest_if] = 1;
1174                             memcpy(&link_hw_laddr[dest_if], &hw_addr,
1175                                           sizeof(struct ether_addr));
1176
1177                             ether_addr_copy(&hw_addr, &ehdr->d_addr);
1178                             ether_addr_copy(get_link_hw_addr(dest_if),
1179                                           &ehdr->s_addr);
1180
1181                             if (vfw_debug >= DEBUG_LEVEL_4) {
1182                                    char buf[HW_ADDR_SIZE];
1183
1184                                    ether_format_addr(buf, sizeof(buf),
1185                                                  &hw_addr);
1186                                    printf("MAC found for ip 0x%"
1187                                           PRIx32", dest_if %d: %s, ",
1188                                           dest_address,
1189                                           dest_if, buf);
1190                                    ether_format_addr(buf, sizeof(buf),
1191                                                  &ehdr->s_addr);
1192                                    printf("new eth hdr src: %s, ", buf);
1193                                    ether_format_addr(buf, sizeof(buf),
1194                                                  &ehdr->d_addr);
1195                                    printf("new eth hdr dst: %s\n", buf);
1196                             }
1197
1198                      } else {
1199                             if (vfw_debug >= DEBUG_LEVEL_4) {
1200                                    char buf[HW_ADDR_SIZE];
1201
1202                                    ether_format_addr(buf, sizeof(buf),
1203                                                  &hw_addr);
1204                                    printf("MAC NOT FOUND for ip 0x%"
1205                                                  PRIx32", dest_if %"
1206                                                  PRId16": %s, ",
1207                                                  dest_address,
1208                                                  dest_if, buf);
1209                             }
1210                             /* ICMP req sent, drop packet by
1211                              * changing the mask */
1212                             *pkts_mask &= ~pkt_mask;
1213                             vfw_pipe->
1214                                    counters->pkts_drop_without_arp_entry++;
1215                      }
1216               }
1217
1218        }
1219 }
1220
1221
1222 /**
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
1228  *
1229  * @param pkts
1230  *  A pointer to the packets array.
1231  * @param pkt_num
1232  *  Packet number to start processing.
1233  * @param pkts_mask
1234  *  Packet mask pointer
1235  * @param synproxy_reply_mask
1236  *  Reply Packet mask for Synproxy
1237  * @param vfw_pipe
1238  *  A pointer to VFW pipeline.
1239  */
1240
1241 static void
1242 pkt4_work_vfw_arp_ipv6_packets(struct rte_mbuf **pkts,
1243               uint16_t pkt_num,
1244               uint64_t *pkts_mask,
1245               uint64_t synproxy_reply_mask,
1246               struct pipeline_vfw *vfw_pipe)
1247 {
1248        uint8_t nh_ipv6[IPV6_ADD_SIZE];
1249        uint32_t ret;
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;
1254        uint16_t phy_port;
1255        uint8_t i;
1256
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);
1261
1262               pkt = pkts[i];
1263
1264               if(!(*pkts_mask & pkt_mask))
1265                      continue;
1266               int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
1267
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);
1272
1273               struct ipv6_hdr *ihdr = (struct ipv6_hdr *)
1274                      RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
1275
1276               uint8_t nhip[IPV6_ADD_SIZE];
1277               uint8_t dest_address[IPV6_ADD_SIZE];
1278
1279               memset(nhip, 0, IPV6_ADD_SIZE);
1280
1281               rte_mov16(dest_address, ihdr->dst_addr);
1282               ret = local_get_nh_ipv6(&dest_address[0], &dest_if,
1283                             &nhip[0], vfw_pipe);
1284               if (must_reverse) {
1285                      rte_sp_exchange_mac_addresses(ehdr);
1286                      if (is_phy_port_privte(phy_port)) {
1287                             if (!ret) {
1288                                    dest_if = get_pub_to_prv_port(
1289                                                  (uint32_t *)
1290                                                  &dest_address[0],
1291                                                  IP_VERSION_6);
1292                                    if (dest_if == INVALID_DESTIF) {
1293                                           *pkts_mask &= ~pkt_mask;
1294                                           vfw_pipe->counters->
1295                                           pkts_drop_without_arp_entry++;
1296                                    }
1297                                    do_local_nh_ipv6_cache(dest_if,
1298                                                  vfw_pipe);
1299                             }
1300
1301                      } else {
1302                             if (!ret) {
1303                                    dest_if = get_prv_to_pub_port(
1304                                                  (uint32_t *)
1305                                                  &dest_address[0],
1306                                                  IP_VERSION_6);
1307                                    if (dest_if == INVALID_DESTIF) {
1308                                           *pkts_mask &= ~pkt_mask;
1309                                           vfw_pipe->counters->
1310                                           pkts_drop_without_arp_entry++;
1311                                    }
1312                                    do_local_nh_ipv6_cache(dest_if,
1313                                                  vfw_pipe);
1314                             }
1315                      }
1316
1317               } else if (is_phy_port_privte(phy_port)) {
1318                      if (!ret) {
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++;
1325                             }
1326                             do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1327                      }
1328
1329               } else {
1330                      if (!ret) {
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++;
1337
1338                             }
1339                             do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1340                      }
1341
1342               }
1343
1344               meta_data_addr->output_port = vfw_pipe->outport_id[dest_if];
1345
1346               memset(nh_ipv6, 0, IPV6_ADD_SIZE);
1347               if (get_dest_mac_address_ipv6_port(
1348                                    &dest_address[0],
1349                                    &dest_if,
1350                                    &hw_addr,
1351                                    &nh_ipv6[0])) {
1352                      ether_addr_copy(&hw_addr, &ehdr->d_addr);
1353                      ether_addr_copy(get_link_hw_addr(dest_if),
1354                                    &ehdr->s_addr);
1355
1356                      if (vfw_debug >= DEBUG_LEVEL_4) {
1357                             char buf[HW_ADDR_SIZE];
1358
1359                             ether_format_addr(buf, sizeof(buf),
1360                                           &hw_addr);
1361                             printf("MAC found for  dest_if %d: %s, ",
1362                                           dest_if, buf);
1363                             ether_format_addr(buf, sizeof(buf),
1364                                           &ehdr->s_addr);
1365                             printf("new eth hdr src: %s, ", buf);
1366                             ether_format_addr(buf, sizeof(buf),
1367                                           &ehdr->d_addr);
1368                             printf("new eth hdr dst: %s\n", buf);
1369                      }
1370
1371               } else {
1372                      printf("deleting ipv6\n");
1373                      *pkts_mask &= ~pkt_mask;
1374                      /*Next Neighbor is not yet implemented
1375                       * for ipv6.*/
1376                      vfw_pipe->counters->
1377                             pkts_drop_without_arp_entry++;
1378               }
1379
1380        }
1381 }
1382
1383
1384 /**
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
1390  *
1391  * @param pkts
1392  *  A pointer to the packets.
1393  * @param pkt_num
1394  *  Packet number to process.
1395  * @param pkts_mask
1396  *  Packet mask pointer
1397  * @param synproxy_reply_mask
1398  *  Reply Packet mask for Synproxy
1399  * @param vfw_pipe
1400  *  A pointer to VFW pipeline.
1401  */
1402
1403 static void
1404 pkt_work_vfw_arp_ipv6_packets(struct rte_mbuf *pkts,
1405               uint16_t pkt_num,
1406               uint64_t *pkts_mask,
1407               uint64_t synproxy_reply_mask,
1408               struct pipeline_vfw *vfw_pipe)
1409 {
1410        uint8_t nh_ipv6[IPV6_ADD_SIZE];
1411        uint32_t ret;
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;
1416        uint16_t phy_port;
1417
1418        uint32_t dest_if = INVALID_DESTIF;
1419        /* bitmask representing only this packet */
1420        uint64_t pkt_mask = 1LLU << pkt_num;
1421
1422        pkt = pkts;
1423
1424        if(*pkts_mask & pkt_mask) {
1425
1426               int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
1427
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);
1432
1433               struct ipv6_hdr *ihdr = (struct ipv6_hdr *)
1434                      RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
1435
1436               uint8_t nhip[IPV6_ADD_SIZE];
1437               uint8_t dest_address[IPV6_ADD_SIZE];
1438
1439               memset(nhip, 0, IPV6_ADD_SIZE);
1440
1441               rte_mov16(dest_address, ihdr->dst_addr);
1442               ret = local_get_nh_ipv6(&dest_address[0], &dest_if,
1443                             &nhip[0], vfw_pipe);
1444               if (must_reverse) {
1445                      rte_sp_exchange_mac_addresses(ehdr);
1446                      if (is_phy_port_privte(phy_port)) {
1447                             if (!ret) {
1448                                    dest_if = get_pub_to_prv_port(
1449                                                  (uint32_t *)
1450                                                  &dest_address[0],
1451                                                  IP_VERSION_6);
1452                                    if (dest_if == INVALID_DESTIF) {
1453                                           *pkts_mask &= ~pkt_mask;
1454                                           vfw_pipe->counters->
1455                                           pkts_drop_without_arp_entry++;
1456                                    }
1457                                    do_local_nh_ipv6_cache(dest_if,
1458                                                  vfw_pipe);
1459                             }
1460
1461                      } else {
1462                             if (!ret) {
1463                                    dest_if = get_prv_to_pub_port(
1464                                                  (uint32_t *)
1465                                                  &dest_address[0],
1466                                                  IP_VERSION_6);
1467                                    if (dest_if == INVALID_DESTIF) {
1468                                           *pkts_mask &= ~pkt_mask;
1469                                           vfw_pipe->counters->
1470                                           pkts_drop_without_arp_entry++;
1471                                    }
1472                                    do_local_nh_ipv6_cache(dest_if,
1473                                                  vfw_pipe);
1474                             }
1475                      }
1476
1477               } else if (is_phy_port_privte(phy_port)) {
1478                      if (!ret) {
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++;
1485                             }
1486                             do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1487                      }
1488
1489               } else {
1490                      if (!ret) {
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++;
1497
1498                             }
1499                             do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1500                      }
1501
1502               }
1503
1504               meta_data_addr->output_port = vfw_pipe->outport_id[dest_if];
1505
1506               memset(nh_ipv6, 0, IPV6_ADD_SIZE);
1507               if (get_dest_mac_address_ipv6_port(
1508                                    &dest_address[0],
1509                                    &dest_if,
1510                                    &hw_addr,
1511                                    &nh_ipv6[0])) {
1512                      ether_addr_copy(&hw_addr, &ehdr->d_addr);
1513                      ether_addr_copy(get_link_hw_addr(dest_if),
1514                                    &ehdr->s_addr);
1515
1516                      if (vfw_debug >= DEBUG_LEVEL_4) {
1517                             char buf[HW_ADDR_SIZE];
1518
1519                             ether_format_addr(buf, sizeof(buf),
1520                                           &hw_addr);
1521                             printf("MAC found for  dest_if %d: %s, ",
1522                                           dest_if, buf);
1523                             ether_format_addr(buf, sizeof(buf),
1524                                           &ehdr->s_addr);
1525                             printf("new eth hdr src: %s, ", buf);
1526                             ether_format_addr(buf, sizeof(buf),
1527                                           &ehdr->d_addr);
1528                             printf("new eth hdr dst: %s\n", buf);
1529                      }
1530
1531               } else {
1532                      printf("deleting ipv6\n");
1533                      *pkts_mask &= ~pkt_mask;
1534                      /*Next Neighbor is not yet implemented
1535                       * for ipv6.*/
1536                      vfw_pipe->counters->
1537                             pkts_drop_without_arp_entry++;
1538               }
1539
1540        }
1541
1542 }
1543
1544 #else
1545
1546 /**
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
1552  *
1553  * @param pkts
1554  *  A pointer to the packet.
1555  * @param pkts_mask
1556  *  Packet mask
1557  * @param synproxy_reply_mask
1558  *  Reply Packet mask for Synproxy
1559  * @param vfw_pipe
1560  *  A pointer to VFW pipeline.
1561  */
1562 static uint64_t
1563 rte_vfw_arp_ipv4_packets(struct rte_mbuf **pkts,
1564               uint64_t pkts_mask,
1565               uint64_t synproxy_reply_mask,
1566               struct pipeline_vfw *vfw_pipe)
1567 {
1568        uint64_t pkts_to_arp = pkts_mask;
1569
1570        uint32_t ret;
1571        uint32_t dest_if = INVALID_DESTIF;
1572        int ret_mac;
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;
1578               uint16_t phy_port;
1579
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;
1585               pkt = pkts[pos];
1586               int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
1587
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);
1592
1593
1594               struct ipv4_hdr *ihdr = (struct ipv4_hdr *)
1595                      RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
1596               uint32_t nhip = 0;
1597
1598               uint32_t dest_address = rte_bswap32(ihdr->dst_addr);
1599
1600               ret = local_get_nh_ipv4(dest_address, &dest_if,
1601                             &nhip, vfw_pipe);
1602               if (must_reverse) {
1603                      rte_sp_exchange_mac_addresses(ehdr);
1604                      if (is_phy_port_privte(phy_port)) {
1605                             if (!ret) {
1606                                    dest_if = get_pub_to_prv_port(
1607                                                  &dest_address,
1608                                                  IP_VERSION_4);
1609                                    if (dest_if == INVALID_DESTIF) {
1610                                           pkts_mask &= ~pkt_mask;
1611                                           vfw_pipe->counters->
1612                                           pkts_drop_without_arp_entry++;
1613                                    }
1614                                    do_local_nh_ipv4_cache(
1615                                                  dest_if, vfw_pipe);
1616                             }
1617
1618                      } else {
1619                             if (!ret) {
1620                                    dest_if = get_prv_to_pub_port(
1621                                                  &dest_address,
1622                                                  IP_VERSION_4);
1623                                    if (dest_if == INVALID_DESTIF) {
1624                                           pkts_mask &= ~pkt_mask;
1625                                           vfw_pipe->counters->
1626                                           pkts_drop_without_arp_entry++;
1627                                    }
1628                                    do_local_nh_ipv4_cache(dest_if,
1629                                                  vfw_pipe);
1630                             }
1631                      }
1632               } else if (is_phy_port_privte(phy_port)) {
1633                      if (!ret) {
1634                             dest_if = get_prv_to_pub_port(&dest_address,
1635                                           IP_VERSION_4);
1636                             if (dest_if == INVALID_DESTIF) {
1637                                    pkts_mask &= ~pkt_mask;
1638                                    vfw_pipe->counters->
1639                                           pkts_drop_without_arp_entry++;
1640                             }
1641                             do_local_nh_ipv4_cache(dest_if, vfw_pipe);
1642                      }
1643
1644               } else {
1645                      if (!ret) {
1646                             dest_if = get_pub_to_prv_port(&dest_address,
1647                                           IP_VERSION_4);
1648                             if (dest_if == INVALID_DESTIF) {
1649                                    pkts_mask &= ~pkt_mask;
1650                                    vfw_pipe->counters->
1651                                           pkts_drop_without_arp_entry++;
1652                             }
1653                             do_local_nh_ipv4_cache(dest_if, vfw_pipe);
1654                      }
1655
1656               }
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),
1660                                    &ehdr->d_addr);
1661                      ether_addr_copy(get_link_hw_addr(dest_if),
1662                                    &ehdr->s_addr);
1663               } else {
1664                      ret_mac = get_dest_mac_addr_port(dest_address,
1665                                    &dest_if, &hw_addr);
1666                      if (ret_mac) {
1667                             link_hw_laddr_valid[dest_if] = 1;
1668                             memcpy(&link_hw_laddr[dest_if], &hw_addr,
1669                                           sizeof(struct ether_addr));
1670
1671                             ether_addr_copy(&hw_addr, &ehdr->d_addr);
1672                             ether_addr_copy(get_link_hw_addr(dest_if),
1673                                           &ehdr->s_addr);
1674
1675                             if (vfw_debug >= DEBUG_LEVEL_4) {
1676                                    char buf[HW_ADDR_SIZE];
1677
1678                                    ether_format_addr(buf, sizeof(buf),
1679                                                  &hw_addr);
1680                                    printf("MAC found for ip 0x%"
1681                                           PRIx32", dest_if %d: %s, ",
1682                                           dest_address,
1683                                           dest_if, buf);
1684                                    ether_format_addr(buf, sizeof(buf),
1685                                                  &ehdr->s_addr);
1686                                    printf("new eth hdr src: %s, ", buf);
1687                                    ether_format_addr(buf, sizeof(buf),
1688                                                  &ehdr->d_addr);
1689                                    printf("new eth hdr dst: %s\n", buf);
1690                             }
1691
1692                      } else {
1693                             if (unlikely(ret_mac == 0))
1694                                    request_arp(meta_data_addr->output_port,
1695                                           nhip);
1696
1697                             if (vfw_debug >= DEBUG_LEVEL_4) {
1698                                    char buf[HW_ADDR_SIZE];
1699
1700                             ether_format_addr(buf, sizeof(buf),
1701                                           &hw_addr);
1702                             printf("MAC NOT FOUND for ip 0x%"
1703                                           PRIx32", dest_if %"
1704                                           PRId16": %s, ",
1705                                           dest_address,
1706                                           dest_if, buf);
1707                      }
1708                      /* ICMP req sent, drop packet by
1709                       * changing the mask */
1710                      pkts_mask &= ~pkt_mask;
1711                      vfw_pipe->
1712                             counters->pkts_drop_without_arp_entry++;
1713               }
1714 }
1715
1716        }
1717
1718        return pkts_mask;
1719 }
1720 /**
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
1726  *
1727  * @param pkts
1728  *  A pointer to the packet.
1729  * @param pkts_mask
1730  *  Packet mask
1731  * @param synproxy_reply_mask
1732  *  Reply Packet mask for Synproxy
1733  * @param vfw_pipe
1734  *  A pointer to VFW pipeline.
1735  */
1736
1737        static uint64_t
1738 rte_vfw_arp_ipv6_packets(struct rte_mbuf **pkts,
1739               uint64_t pkts_mask,
1740               uint64_t synproxy_reply_mask,
1741               struct pipeline_vfw *vfw_pipe)
1742 {
1743        uint64_t pkts_to_arp = pkts_mask;
1744        uint8_t nh_ipv6[IPV6_ADD_SIZE];
1745        uint32_t ret;
1746        uint32_t dest_if = INVALID_DESTIF;
1747
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;
1753               uint16_t phy_port;
1754
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;
1760               pkt = pkts[pos];
1761               int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
1762
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);
1767
1768               struct ipv6_hdr *ihdr = (struct ipv6_hdr *)
1769                      RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
1770
1771               uint8_t nhip[IPV6_ADD_SIZE];
1772               uint8_t dest_address[IPV6_ADD_SIZE];
1773
1774               memset(nhip, 0, IPV6_ADD_SIZE);
1775
1776               rte_mov16(dest_address, ihdr->dst_addr);
1777               ret = local_get_nh_ipv6(&dest_address[0], &dest_if,
1778                             &nhip[0], vfw_pipe);
1779               if (must_reverse) {
1780                      rte_sp_exchange_mac_addresses(ehdr);
1781                      if (is_phy_port_privte(phy_port)) {
1782                             if (!ret) {
1783                                    dest_if = get_pub_to_prv_port(
1784                                                  (uint32_t *)
1785                                                  &dest_address[0],
1786                                                  IP_VERSION_6);
1787                                    if (dest_if == INVALID_DESTIF) {
1788                                           pkts_mask &= ~pkt_mask;
1789                                           vfw_pipe->counters->
1790                                           pkts_drop_without_arp_entry++;
1791                                    }
1792                                    do_local_nh_ipv6_cache(dest_if,
1793                                                  vfw_pipe);
1794                             }
1795
1796                      } else {
1797                             if (!ret) {
1798                                    dest_if = get_prv_to_pub_port(
1799                                                  (uint32_t *)
1800                                                  &dest_address[0],
1801                                                  IP_VERSION_6);
1802                                    if (dest_if == INVALID_DESTIF) {
1803                                           pkts_mask &= ~pkt_mask;
1804                                           vfw_pipe->counters->
1805                                           pkts_drop_without_arp_entry++;
1806                                    }
1807                                    do_local_nh_ipv6_cache(dest_if,
1808                                                  vfw_pipe);
1809                             }
1810                      }
1811
1812               } else if (is_phy_port_privte(phy_port)) {
1813                      if (!ret) {
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++;
1820                             }
1821                             do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1822                      }
1823
1824               } else {
1825                      if (!ret) {
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++;
1832
1833                             }
1834                             do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1835                      }
1836
1837               }
1838
1839               meta_data_addr->output_port = vfw_pipe->outport_id[dest_if];
1840
1841               memset(nh_ipv6, 0, IPV6_ADD_SIZE);
1842               if (get_dest_mac_address_ipv6_port(
1843                                    &dest_address[0],
1844                                    &dest_if,
1845                                    &hw_addr,
1846                                    &nh_ipv6[0])) {
1847                      ether_addr_copy(&hw_addr, &ehdr->d_addr);
1848                      ether_addr_copy(get_link_hw_addr(dest_if),
1849                                    &ehdr->s_addr);
1850
1851                      if (vfw_debug >= DEBUG_LEVEL_4) {
1852                             char buf[HW_ADDR_SIZE];
1853
1854                             ether_format_addr(buf, sizeof(buf),
1855                                           &hw_addr);
1856                             printf("MAC found for  dest_if %d: %s, ",
1857                                           dest_if, buf);
1858                             ether_format_addr(buf, sizeof(buf),
1859                                           &ehdr->s_addr);
1860                             printf("new eth hdr src: %s, ", buf);
1861                             ether_format_addr(buf, sizeof(buf),
1862                                           &ehdr->d_addr);
1863                             printf("new eth hdr dst: %s\n", buf);
1864                      }
1865
1866               } else {
1867                      printf("deleting ipv6\n");
1868                      pkts_mask &= ~pkt_mask;
1869                      /*Next Neighbor is not yet implemented
1870                       * for ipv6.*/
1871                      vfw_pipe->counters->
1872                             pkts_drop_without_arp_entry++;
1873               }
1874
1875
1876        }
1877
1878        return pkts_mask;
1879 }
1880
1881 #endif
1882 /**
1883  * Packets processing for connection tracking.
1884  *
1885  * @param vfw_pipe
1886  *  A pointer to the pipeline.
1887  * @param ct
1888  *  A pointer to the connetion tracker .
1889  * @param pkts
1890  *  A pointer to a burst of packets.
1891  * @param packet_mask_in
1892  *  Input packets Mask.
1893  */
1894
1895        static  uint64_t
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)
1899 {
1900        uint64_t keep_mask = packet_mask_in;
1901        struct rte_synproxy_helper sp_helper;       /* for synproxy */
1902
1903        keep_mask =
1904            rte_ct_cnxn_tracker_batch_lookup_with_synproxy(ct, pkts, keep_mask,
1905                                                     &sp_helper);
1906
1907        if (unlikely(sp_helper.hijack_mask))
1908               printf("buffered hijack pkts severe error\n");
1909
1910        if (unlikely(sp_helper.reply_pkt_mask))
1911               printf("buffered reply pkts severe error\n");
1912
1913        return keep_mask;
1914 }
1915
1916 /**
1917  * Free Packets from mbuf.
1918  *
1919  * @param ct
1920  *  A pointer to the connection tracker to increment drop counter.
1921  *
1922  * @param pkt
1923  *  Packet to be free.
1924  */
1925 static inline void
1926 vfw_pktmbuf_free(struct rte_ct_cnxn_tracker *ct, struct rte_mbuf *pkt)
1927 {
1928        ct->counters->pkts_drop++;
1929        rte_pktmbuf_free(pkt);
1930 }
1931
1932 static void
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)
1937 {
1938        int i;
1939        struct mbuf_tcp_meta_data *meta_data_addr;
1940        uint64_t pkt_mask = 1;
1941
1942        /* any clear bits in low-order num_pkts bit of
1943         * pkt_mask must be discarded */
1944
1945        for (i = 0; i < num_pkts; i++) {
1946               struct rte_mbuf *pkt = pkts[i];
1947
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);
1954
1955               } else {
1956                      vfw_pktmbuf_free(ct, pkt);
1957               }
1958
1959               pkt_mask = pkt_mask << 1;
1960        }
1961 }
1962
1963 /**
1964  *Packet buffered for synproxy.
1965  *
1966  * @param p
1967  *  A pointer to the pipeline.
1968  * @param vfw_pipe
1969  *  A pointer to the vfw pipeline.
1970  * @param ct
1971  *  A pointer to the connection tracker.
1972  * @param forward_pkts
1973  *  Packet forwarded by synproxy.
1974  *
1975  */
1976 static void
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)
1980 {
1981        struct rte_mbuf *pkt_list = rte_ct_get_buffered_synproxy_packets(ct);
1982
1983        if (likely(pkt_list == NULL))       /* only during proxy setup is != NULL */
1984               return;
1985
1986        int pkt_count = 0;
1987        uint64_t keep_mask = 0;
1988        struct rte_mbuf **pkts = vfw_pipe->pkt_buffer;
1989        struct rte_mbuf *pkt;
1990
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);
1995
1996               /* detach head of list and advance list */
1997               pkt = pkt_list;
1998               pkt_list = meta_data->next;
1999
2000               if (forward_pkts) {
2001
2002                      pkts[pkt_count++] = pkt;
2003
2004                      if (pkt_count == PKT_BUFFER_SIZE) {
2005                             /* need to send out packets */
2006                             /* currently 0, set all bits */
2007                             keep_mask = ~keep_mask;
2008
2009                             keep_mask =
2010                                 vfw_process_buffered_pkts(vfw_pipe,
2011                                                          ct, pkts,
2012                                                          keep_mask);
2013                             vfw_output_or_delete_buffered_packets(
2014                                           ct, p,
2015                                           pkts,
2016                                           PKT_BUFFER_SIZE,
2017                                           keep_mask);
2018                             pkt_count = 0;
2019                             keep_mask = 0;
2020                      }
2021
2022               } else {
2023                      vfw_pktmbuf_free(ct, pkt);
2024               }
2025        }
2026
2027        if (pkt_count != 0) {
2028               /* need to send out packets */
2029               keep_mask = RTE_LEN2MASK(pkt_count, uint64_t);
2030
2031               keep_mask =
2032                      vfw_process_buffered_pkts(vfw_pipe, ct, pkts,
2033                                    keep_mask);
2034
2035               vfw_output_or_delete_buffered_packets(ct, p, pkts, pkt_count,
2036                             keep_mask);
2037
2038               pkt_count = 0;
2039               keep_mask = 0;
2040        }
2041 }
2042 /**
2043  * The pipeline port-in action is used to do all the firewall and
2044  * connection tracking work for IPV4 packets.
2045  *
2046  * @param p
2047  *  A pointer to the pipeline.
2048   * @param pkts
2049  *  A pointer to a burst of packets.
2050  * @param n_pkts
2051  *  Number of packets to process.
2052  * @param arg
2053  *  A pointer to pipeline specific data.
2054  *
2055  * @return
2056  *  0 on success, negative on error.
2057  */
2058
2059 static int
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)
2063 {
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;
2069
2070        start_tsc_measure(vfw_pipe);
2071
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;
2077
2078        uint64_t conntrack_mask = 0, connexist_mask = 0;
2079        struct rte_CT_helper ct_helper;
2080        uint8_t j;
2081
2082        /*
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
2093         */
2094
2095        rte_prefetch0(& vfw_pipe->counters);
2096
2097 #ifdef EN_SWP_ACL
2098        /* Pre-fetch all rte_mbuf header */
2099        for(j = 0; j < n_pkts; j++)
2100               rte_prefetch0(pkts[j]);
2101 #endif
2102        memset(&ct_helper, 0, sizeof(struct rte_CT_helper));
2103 #ifdef EN_SWP_ACL
2104        rte_prefetch0(& vfw_pipe->counters->pkts_drop_ttl);
2105        rte_prefetch0(& vfw_pipe->counters->sum_latencies);
2106 #endif
2107
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;
2113
2114        if (unlikely(VFW_DEBUG))
2115               printf("vfw_port_in_action_ipv4 pkts_received: %" PRIu64
2116                             " n_pkts: %u\n",
2117                             vfw_pipe->counters->pkts_received, n_pkts);
2118
2119        /* first handle handle any previously buffered packets now released */
2120        vfw_handle_buffered_packets(p, vfw_pipe, ct,
2121                      FORWARD_BUFFERED_PACKETS);
2122
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);
2129        }
2130 #ifdef ACL_ENABLE
2131 #ifdef EN_SWP_ACL
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;
2148        } else
2149               cnxn_tracking_is_active = 0;
2150 #endif /* ACL_ENABLE */
2151
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;
2157
2158        }
2159
2160 #ifdef EN_SWP_ARP
2161        for(j = 0; j < (n_pkts & 0x3LLU); j++) {
2162                rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2163                                    META_DATA_OFFSET));
2164                rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2165                                    ETHERNET_START));
2166        }
2167        rte_prefetch0((void*)in_port_dir_a);
2168        rte_prefetch0((void*)prv_to_pub_map);
2169
2170        uint8_t i;
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],
2174                                           META_DATA_OFFSET));
2175                      rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2176                                           ETHERNET_START));
2177               }
2178               pkt4_work_vfw_arp_ipv4_packets(&pkts[i], i, &keep_mask,
2179                             synproxy_reply_mask, vfw_pipe);
2180        }
2181        for (j = i; j < n_pkts; j++) {
2182               rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2183                                    META_DATA_OFFSET));
2184               rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2185                                    ETHERNET_START));
2186        }
2187        for (; i < n_pkts; i++) {
2188               pkt_work_vfw_arp_ipv4_packets(pkts[i], i, &keep_mask,
2189                             synproxy_reply_mask, vfw_pipe);
2190        }
2191 #else
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);
2197 #endif
2198
2199        if (vfw_debug > 1) {
2200               printf("  Exit in-port action with %p packet mask\n",
2201                             (void *)keep_mask);
2202               if (keep_mask != packet_mask_in)
2203                      printf("dropped packets, %p in, %p out\n",
2204                                    (void *)packet_mask_in,
2205                                    (void *)keep_mask);
2206        }
2207
2208        /* Update mask before returning, so that bad packets are dropped */
2209
2210        pkts_drop_mask = packet_mask_in & ~keep_mask;
2211
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);
2215        }
2216
2217        if (unlikely(hijack_mask != 0))
2218               rte_pipeline_ah_packet_hijack(p, hijack_mask);
2219
2220        vfw_pipe->counters->num_batch_pkts_sum += n_pkts;
2221        vfw_pipe->counters->num_pkts_measurements++;
2222
2223        end_tsc_measure(vfw_pipe, n_pkts);
2224
2225        return 0;
2226 }
2227 /**
2228  * The pipeline port-in action is used to do all the firewall and
2229  * connection tracking work for IPV6 packet.
2230  *
2231  * @param p
2232  *  A pointer to the pipeline.
2233   * @param pkts
2234  *  A pointer to a burst of packets.
2235  * @param n_pkts
2236  *  Number of packets to process.
2237  * @param arg
2238  *  A pointer to pipeline specific data.
2239  *
2240  * @return
2241  *  0 on success, negative on error.
2242  */
2243
2244 static int
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)
2248 {
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;
2254
2255        start_tsc_measure(vfw_pipe);
2256
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;
2262
2263        uint64_t conntrack_mask = 0, connexist_mask = 0;
2264        struct rte_CT_helper ct_helper;
2265        uint32_t j;
2266
2267        /*
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
2278         */
2279
2280        rte_prefetch0(& vfw_pipe->counters);
2281
2282        /* Pre-fetch all rte_mbuf header */
2283        for(j = 0; j < n_pkts; j++)
2284                rte_prefetch0(pkts[j]);
2285
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);
2289
2290        if (vfw_debug > 1)
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;
2295        if (VFW_DEBUG)
2296               printf("vfw_port_in_action pkts_received: %" PRIu64
2297                             " n_pkts: %u\n",
2298                             vfw_pipe->counters->pkts_received, n_pkts);
2299
2300        /* first handle handle any previously buffered packets now released */
2301        vfw_handle_buffered_packets(p, vfw_pipe, ct,
2302                      FORWARD_BUFFERED_PACKETS);
2303
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);
2310        }
2311 #ifdef ACL_ENABLE
2312
2313 #ifdef EN_SWP_ACL
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;
2330        } else
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;
2338
2339        }
2340
2341 #ifdef EN_SWP_ARP
2342        for(j = 0; j < (n_pkts & 0x3LLU); j++) {
2343                rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2344                                    META_DATA_OFFSET));
2345                rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2346                                    ETHERNET_START));
2347        }
2348        rte_prefetch0((void*)in_port_dir_a);
2349        rte_prefetch0(vfw_pipe->local_lib_nd_route_table);
2350        uint32_t i;
2351
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],
2355                                           META_DATA_OFFSET));
2356                      rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2357                                           ETHERNET_START));
2358               }
2359               pkt4_work_vfw_arp_ipv6_packets(&pkts[i], i, &keep_mask,
2360                             synproxy_reply_mask, vfw_pipe);
2361        }
2362        for (j = i; j < n_pkts; j++) {
2363               rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2364                                    META_DATA_OFFSET));
2365               rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2366                                    ETHERNET_START));
2367        }
2368        for (; i < n_pkts; i++) {
2369               pkt_work_vfw_arp_ipv6_packets(pkts[i], i, &keep_mask,
2370                             synproxy_reply_mask, vfw_pipe);
2371        }
2372 #else
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);
2377 #endif
2378
2379        if (vfw_debug > 1) {
2380               printf("  Exit in-port action with %p packet mask\n",
2381                             (void *)keep_mask);
2382               if (keep_mask != packet_mask_in)
2383                      printf("dropped packets, %p in, %p out\n",
2384                                    (void *)packet_mask_in,
2385                                    (void *)keep_mask);
2386        }
2387
2388        /* Update mask before returning, so that bad packets are dropped */
2389
2390        pkts_drop_mask = packet_mask_in & ~keep_mask;
2391
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);
2395        }
2396
2397        if (unlikely(hijack_mask != 0))
2398               rte_pipeline_ah_packet_hijack(p, hijack_mask);
2399
2400        vfw_pipe->counters->num_batch_pkts_sum += n_pkts;
2401        vfw_pipe->counters->num_pkts_measurements++;
2402
2403        end_tsc_measure(vfw_pipe, n_pkts);
2404
2405        return 0;
2406 }
2407
2408
2409 /**
2410  * Parse arguments in config file.
2411  *
2412  * @param vfw_pipe
2413  *  A pointer to the pipeline.
2414  * @param params
2415  *  A pointer to pipeline specific parameters.
2416  *
2417  * @return
2418  *  0 on success, negative on error.
2419  */
2420 static int
2421 pipeline_vfw_parse_args(struct pipeline_vfw *vfw_pipe,
2422               struct pipeline_params *params)
2423 {
2424        uint32_t i;
2425        int status;
2426
2427        if (vfw_debug)
2428               printf("VFW pipeline_vfw_parse_args params->n_args: %d\n",
2429                             params->n_args);
2430
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];
2434
2435               printf("VFW args[%d]: %s %d, %s\n", i, arg_name,
2436                             atoi(arg_value), arg_value);
2437 #ifdef ACL_ENABLE
2438               status = lib_acl_parse_config(vfw_pipe->plib_acl,
2439                                    arg_name, arg_value, &vfw_n_rules);
2440               if (status < 0) {
2441                      printf("rte_ct_set_configuration_options =%s,%s",
2442                                    arg_name, arg_value);
2443                      return -1;
2444               } else if (status == 0)
2445                      continue;
2446
2447 #endif              /* traffic_type */
2448               if (strcmp(arg_name, "traffic_type") == 0) {
2449                      int traffic_type = atoi(arg_value);
2450
2451                      if (traffic_type == 0 ||
2452                                    !(traffic_type == IP_VERSION_4 ||
2453                                           traffic_type == IP_VERSION_6)) {
2454                             printf("not IPV4/IPV6");
2455                             return -1;
2456                      }
2457
2458                      vfw_pipe->traffic_type = traffic_type;
2459                      continue;
2460               }
2461
2462
2463               /* n_flows */
2464               if (strcmp(arg_name, "n_flows") == 0) {
2465                      int n_flows = atoi(arg_value);
2466
2467                      if (n_flows == 0)
2468                             return -1;
2469
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);
2473
2474                      vfw_pipe->n_flows = n_flows;
2475                      continue;
2476               }
2477
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);
2482               if (status < 0) {
2483                      printf("rte_ct_set_configuration_options =%s,%s",
2484                                    arg_name, arg_value);
2485                      return -1;
2486               } else if (status == 0)
2487                      continue;
2488
2489        }
2490
2491        return 0;
2492 }
2493
2494 static void *pipeline_vfw_msg_req_custom_handler(struct pipeline *p,
2495                                               void *msg);
2496
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,
2509 };
2510
2511 static void *pipeline_vfw_msg_req_synproxy_flag_handler(struct pipeline *p,
2512                                                     void *msg);
2513 static pipeline_msg_req_handler custom_handlers[] = {
2514
2515        [PIPELINE_VFW_MSG_REQ_SYNPROXY_FLAGS] =
2516            pipeline_vfw_msg_req_synproxy_flag_handler
2517 };
2518
2519 /**
2520  * Create and initialize Pipeline Back End (BE).
2521  *
2522  * @param params
2523  *  A pointer to the pipeline specific parameters..
2524  * @param arg
2525  *  A pointer to pipeline specific data.
2526  *
2527  * @return
2528  *  A pointer to the pipeline create, NULL on error.
2529  */
2530 static void
2531 *pipeline_vfw_init(struct pipeline_params *params, __rte_unused void *arg)
2532 {
2533        uint32_t size, i;
2534
2535        /* Check input arguments */
2536        if ((params == NULL) ||
2537                      (params->n_ports_in == 0) || (params->n_ports_out == 0))
2538               return NULL;
2539
2540        if (vfw_debug)
2541               printf("num ports in %d / num ports out %d\n",
2542                             params->n_ports_in, params->n_ports_out);
2543
2544        /* Create a single pipeline instance and initialize. */
2545        struct pipeline_vfw *pipe_vfw;
2546
2547        size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_vfw));
2548        pipe_vfw = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
2549
2550        if (pipe_vfw == NULL)
2551               return NULL;
2552
2553        struct pipeline *pipe;
2554
2555        pipe = &pipe_vfw->pipe;
2556
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;
2565        }
2566        PLOG(pipe, HIGH, "VFW");
2567
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);
2572
2573        if (pipe_vfw->cnxn_tracker == NULL)
2574               return NULL;
2575 #ifdef ACL_ENABLE
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);
2580
2581        if (pipe_vfw->plib_acl == NULL)
2582               return NULL;
2583 #endif
2584        timer_lcore = rte_lcore_id();
2585        /*
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.
2589         */
2590        struct rte_VFW_counter_block *counter_ptr;
2591
2592        if (rte_VFW_hi_counter_block_in_use == MAX_VFW_INSTANCES)
2593               /* error, exceeded table bounds */
2594               return NULL;
2595
2596        rte_VFW_hi_counter_block_in_use++;
2597        counter_ptr =
2598               &rte_vfw_counter_table[rte_VFW_hi_counter_block_in_use];
2599        strncpy(counter_ptr->name, params->name, sizeof(counter_ptr->name));
2600
2601        pipe_vfw->counters = counter_ptr;
2602
2603        rte_ct_initialize_default_timeouts(pipe_vfw->cnxn_tracker);
2604        /* Parse arguments */
2605        if (pipeline_vfw_parse_args(pipe_vfw, params))
2606               return NULL;
2607
2608        uint16_t pointers_offset =
2609               META_DATA_OFFSET + offsetof(struct mbuf_tcp_meta_data, next);
2610
2611        if (pipe_vfw->n_flows > 0)
2612               rte_ct_initialize_cnxn_tracker_with_synproxy(
2613                             pipe_vfw->cnxn_tracker,
2614                             pipe_vfw->n_flows,
2615                             params->name,
2616                             pointers_offset);
2617
2618        pipe_vfw->counters->ct_counters =
2619               rte_ct_get_counter_address(pipe_vfw->cnxn_tracker);
2620
2621        /* Pipeline */
2622        {
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)
2628               };
2629
2630               pipe->p = rte_pipeline_create(&pipeline_params);
2631               if (pipe->p == NULL) {
2632                      rte_free(pipe_vfw);
2633                      return NULL;
2634               }
2635        }
2636
2637        /* Input ports */
2638
2639        /*
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
2643         */
2644
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);
2651
2652        if (port_in_args == NULL)
2653               return NULL;
2654
2655        pipe->n_ports_in = params->n_ports_in;
2656        for (i = 0; i < pipe->n_ports_in; i++) {
2657
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;
2661
2662               struct rte_pipeline_port_in_params port_params = {
2663                      .ops =
2664                             pipeline_port_in_params_get_ops(&params->port_in
2665                                           [i]),
2666                      .arg_create =
2667                             pipeline_port_in_params_convert(&params->port_in
2668                                           [i]),
2669                      .f_action = vfw_port_in_action_ipv4,
2670                      .arg_ah = &(port_in_args[i]),
2671                      .burst_size = params->port_in[i].burst_size,
2672               };
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]);
2677
2678               if (status) {
2679                      rte_pipeline_free(pipe->p);
2680                      rte_free(pipe_vfw);
2681                      return NULL;
2682               }
2683        }
2684
2685        /* Output ports */
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                                    &params->port_out[i]),
2691                      .arg_create = pipeline_port_out_params_convert(
2692                                    &params->port_out[i]),
2693                      .f_action = NULL,
2694                      .arg_ah = NULL,
2695               };
2696
2697               int status = rte_pipeline_port_out_create(pipe->p, &port_params,
2698                             &pipe->port_out_id[i]);
2699
2700               if (status) {
2701                      rte_pipeline_free(pipe->p);
2702                      rte_free(pipe_vfw);
2703                      return NULL;
2704               }
2705        }
2706
2707        int pipeline_num = 0;
2708        int dont_care = sscanf(params->name, "PIPELINE%d", &pipeline_num);
2709
2710        if (dont_care < 0)
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);
2718 #ifdef ACL_ENABLE
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,
2723                                    &vfw_n_rules);
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);
2729                      rte_free(pipe_vfw);
2730                      return NULL;
2731               }
2732               vfw_rule_table_ipv4_standby =
2733                      lib_acl_create_active_standby_table_ipv4(2,
2734                                    &vfw_n_rules);
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);
2740                      rte_free(pipe_vfw);
2741                      return NULL;
2742               }
2743
2744               vfw_rule_table_ipv6_active =
2745                      lib_acl_create_active_standby_table_ipv6(1,
2746                                    &vfw_n_rules);
2747
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);
2753                      rte_free(pipe_vfw);
2754                      return NULL;
2755               }
2756               vfw_rule_table_ipv6_standby =
2757                      lib_acl_create_active_standby_table_ipv6(2,
2758                                    &vfw_n_rules);
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);
2764                      rte_free(pipe_vfw);
2765                      return NULL;
2766               }
2767        }
2768
2769 #endif
2770
2771        /* Tables */
2772
2773        pipe->n_tables = 1;
2774
2775        struct rte_pipeline_table_params table_params = {
2776               .ops = &rte_table_stub_ops,
2777               .arg_create = NULL,
2778               .f_action_hit = NULL,
2779               .f_action_miss = NULL,
2780               .arg_ah = NULL,
2781               .action_data_size = 0,
2782        };
2783
2784        int status = rte_pipeline_table_create(pipe->p,
2785                      &table_params,
2786                      &pipe->table_id[0]);
2787
2788        if (status) {
2789               rte_pipeline_free(pipe->p);
2790               rte_free(pipe);
2791               return NULL;
2792        }
2793
2794        struct rte_pipeline_table_entry default_entry = {
2795               .action = RTE_PIPELINE_ACTION_PORT_META
2796        };
2797
2798        struct rte_pipeline_table_entry *default_entry_ptr;
2799
2800        status = rte_pipeline_table_default_entry_add(pipe->p,
2801                                                 pipe->table_id[0],
2802                                                 &default_entry,
2803                                                 &default_entry_ptr);
2804
2805        if (status) {
2806               rte_pipeline_free(pipe->p);
2807               rte_free(pipe);
2808               return NULL;
2809        }
2810        for (i = 0; i < pipe->n_ports_in; i++) {
2811               int status = rte_pipeline_port_in_connect_to_table(
2812                             pipe->p,
2813                             pipe->port_in_id[i],
2814                             pipe->table_id[0]);
2815
2816               if (status) {
2817                      rte_pipeline_free(pipe->p);
2818                      rte_free(pipe_vfw);
2819                      return NULL;
2820               }
2821        }
2822
2823        /* Enable input ports */
2824        for (i = 0; i < pipe->n_ports_in; i++) {
2825               int status =
2826                   rte_pipeline_port_in_enable(pipe->p, pipe->port_in_id[i]);
2827
2828               if (status) {
2829                      rte_pipeline_free(pipe->p);
2830                      rte_free(pipe_vfw);
2831                      return NULL;
2832               }
2833        }
2834
2835        /* Check pipeline consistency */
2836        if (rte_pipeline_check(pipe->p) < 0) {
2837               rte_pipeline_free(pipe->p);
2838               rte_free(pipe_vfw);
2839               return NULL;
2840        }
2841
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];
2846
2847        for (i = 0; i < pipe->n_msgq; i++)
2848               pipe->msgq_out[i] = params->msgq_out[i];
2849
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));
2854
2855        return pipe_vfw;
2856 }
2857
2858 /**
2859  * Free resources and delete pipeline.
2860  *
2861  * @param pipeline
2862  *  A pointer to the pipeline.
2863  *
2864  * @return
2865  *  0 on success, negative on error.
2866  */
2867 static int pipeline_vfw_free(void *pipeline)
2868 {
2869        struct pipeline *p = (struct pipeline *)pipeline;
2870
2871        /* Check input arguments */
2872        if (p == NULL)
2873               return -1;
2874
2875        /* Free resources */
2876        rte_pipeline_free(p->p);
2877        rte_free(p);
2878        return 0;
2879 }
2880
2881 /**
2882  * Callback function to map input/output ports.
2883  *
2884  * @param pipeline
2885  *  A pointer to the pipeline.
2886  * @param port_in
2887  *  Input port ID
2888  * @param port_out
2889  *  A pointer to the Output port.
2890  *
2891  * @return
2892  *  0 on success, negative on error.
2893  */
2894 static int
2895 pipeline_vfw_track(void *pipeline, __rte_unused uint32_t port_in,
2896                     uint32_t *port_out)
2897 {
2898        struct pipeline *p = (struct pipeline *)pipeline;
2899
2900        /* Check input arguments */
2901        if ((p == NULL) || (port_in >= p->n_ports_in) || (port_out == NULL))
2902               return -1;
2903
2904        if (p->n_ports_in == 1) {
2905               *port_out = 0;
2906               return 0;
2907        }
2908
2909        return -1;
2910 }
2911
2912 /**
2913  * Callback function to process timers.
2914  *
2915  * @param pipeline
2916  *  A pointer to the pipeline.
2917  *
2918  * @return
2919  *  0 on success, negative on error.
2920  */
2921 static int pipeline_vfw_timer(void *pipeline)
2922 {
2923        struct pipeline_vfw *p = (struct pipeline_vfw *)pipeline;
2924
2925        /*
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
2929         */
2930
2931        vfw_handle_buffered_packets(p->pipe.p, p, p->cnxn_tracker,
2932                                    FORWARD_BUFFERED_PACKETS);
2933
2934        pipeline_msg_req_handle(&p->pipe);
2935        rte_pipeline_flush(p->pipe.p);
2936
2937        rte_ct_handle_expired_timers(p->cnxn_tracker);
2938
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);
2942
2943        return 0;
2944 }
2945
2946 /**
2947  * Callback function to process CLI commands from FE.
2948  *
2949  * @param p
2950  *  A pointer to the pipeline.
2951  * @param msg
2952  *  A pointer to command specific data.
2953  *
2954  * @return
2955  *  A pointer to message handler on success,
2956  *  pipeline_msg_req_invalid_hander on error.
2957  */
2958 void *pipeline_vfw_msg_req_custom_handler(struct pipeline *p, void *msg)
2959 {
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;
2963
2964        f_handle = (req->subtype < PIPELINE_VFW_MSG_REQS) ?
2965            pipe_vfw->custom_handlers[req->subtype] :
2966            pipeline_msg_req_invalid_handler;
2967
2968        if (f_handle == NULL)
2969               f_handle = pipeline_msg_req_invalid_handler;
2970
2971        return f_handle(p, req);
2972 }
2973
2974 /**
2975  * Handler for synproxy ON/OFF CLI command.
2976  *
2977  * @param p
2978  *  A pointer to the pipeline.
2979  * @param msg
2980  *  A pointer to command specific data.
2981  *
2982  * @return
2983  *  Response message contains status.
2984  */
2985
2986 void *pipeline_vfw_msg_req_synproxy_flag_handler(struct pipeline *p,
2987                                               void *msg)
2988 {
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;
2992
2993        if (req->synproxy_flag == 0) {
2994               rte_ct_disable_synproxy(pipe_vfw->cnxn_tracker);
2995               rsp->status = 0;
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);
2999               rsp->status = 0;
3000               printf("synproxy turned ON for %s\n", p->name);
3001        } else {
3002               printf("Invalid synproxy setting\n");
3003               rsp->status = -1;
3004        }
3005
3006        return rsp;
3007 }
3008
3009 struct pipeline_be_ops pipeline_vfw_be_ops = {
3010        .f_init = pipeline_vfw_init,
3011        .f_free = pipeline_vfw_free,
3012        .f_run = NULL,
3013        .f_timer = pipeline_vfw_timer,
3014        .f_track = pipeline_vfw_track,
3015 };