+simple_ipv4_fwd_4pkts(struct rte_mbuf* m[4], uint8_t portid, struct lcore_conf *qconf)
+{
+ struct ether_hdr *eth_hdr[4];
+ struct ipv4_hdr *ipv4_hdr[4];
+ void *d_addr_bytes[4];
+ uint8_t dst_port[4];
+ int32_t ret[4];
+ union ipv4_5tuple_host key[4];
+ __m128i data[4];
+
+ eth_hdr[0] = rte_pktmbuf_mtod(m[0], struct ether_hdr *);
+ eth_hdr[1] = rte_pktmbuf_mtod(m[1], struct ether_hdr *);
+ eth_hdr[2] = rte_pktmbuf_mtod(m[2], struct ether_hdr *);
+ eth_hdr[3] = rte_pktmbuf_mtod(m[3], struct ether_hdr *);
+
+ /* Handle IPv4 headers.*/
+ ipv4_hdr[0] = (struct ipv4_hdr *)(rte_pktmbuf_mtod(m[0], unsigned char *) +
+ sizeof(struct ether_hdr));
+ ipv4_hdr[1] = (struct ipv4_hdr *)(rte_pktmbuf_mtod(m[1], unsigned char *) +
+ sizeof(struct ether_hdr));
+ ipv4_hdr[2] = (struct ipv4_hdr *)(rte_pktmbuf_mtod(m[2], unsigned char *) +
+ sizeof(struct ether_hdr));
+ ipv4_hdr[3] = (struct ipv4_hdr *)(rte_pktmbuf_mtod(m[3], unsigned char *) +
+ sizeof(struct ether_hdr));
+
+#ifdef DO_RFC_1812_CHECKS
+ /* Check to make sure the packet is valid (RFC1812) */
+ uint8_t valid_mask = MASK_ALL_PKTS;
+ if (is_valid_ipv4_pkt(ipv4_hdr[0], m[0]->pkt_len) < 0) {
+ rte_pktmbuf_free(m[0]);
+ valid_mask &= EXECLUDE_1ST_PKT;
+ }
+ if (is_valid_ipv4_pkt(ipv4_hdr[1], m[1]->pkt_len) < 0) {
+ rte_pktmbuf_free(m[1]);
+ valid_mask &= EXECLUDE_2ND_PKT;
+ }
+ if (is_valid_ipv4_pkt(ipv4_hdr[2], m[2]->pkt_len) < 0) {
+ rte_pktmbuf_free(m[2]);
+ valid_mask &= EXECLUDE_3RD_PKT;
+ }
+ if (is_valid_ipv4_pkt(ipv4_hdr[3], m[3]->pkt_len) < 0) {
+ rte_pktmbuf_free(m[3]);
+ valid_mask &= EXECLUDE_4TH_PKT;
+ }
+ if (unlikely(valid_mask != MASK_ALL_PKTS)) {
+ if (valid_mask == 0){
+ return;
+ } else {
+ uint8_t i = 0;
+ for (i = 0; i < 4; i++) {
+ if ((0x1 << i) & valid_mask) {
+ l3fwd_simple_forward(m[i], portid, qconf);
+ }
+ }
+ return;
+ }
+ }
+#endif // End of #ifdef DO_RFC_1812_CHECKS
+
+ data[0] = _mm_loadu_si128((__m128i*)(rte_pktmbuf_mtod(m[0], unsigned char *) +
+ sizeof(struct ether_hdr) + offsetof(struct ipv4_hdr, time_to_live)));
+ data[1] = _mm_loadu_si128((__m128i*)(rte_pktmbuf_mtod(m[1], unsigned char *) +
+ sizeof(struct ether_hdr) + offsetof(struct ipv4_hdr, time_to_live)));
+ data[2] = _mm_loadu_si128((__m128i*)(rte_pktmbuf_mtod(m[2], unsigned char *) +
+ sizeof(struct ether_hdr) + offsetof(struct ipv4_hdr, time_to_live)));
+ data[3] = _mm_loadu_si128((__m128i*)(rte_pktmbuf_mtod(m[3], unsigned char *) +
+ sizeof(struct ether_hdr) + offsetof(struct ipv4_hdr, time_to_live)));
+
+ key[0].xmm = _mm_and_si128(data[0], mask0);
+ key[1].xmm = _mm_and_si128(data[1], mask0);
+ key[2].xmm = _mm_and_si128(data[2], mask0);
+ key[3].xmm = _mm_and_si128(data[3], mask0);
+
+ const void *key_array[4] = {&key[0], &key[1], &key[2],&key[3]};
+ rte_hash_lookup_multi(qconf->ipv4_lookup_struct, &key_array[0], 4, ret);
+ dst_port[0] = (uint8_t) ((ret[0] < 0) ? portid : ipv4_l3fwd_out_if[ret[0]]);
+ dst_port[1] = (uint8_t) ((ret[1] < 0) ? portid : ipv4_l3fwd_out_if[ret[1]]);
+ dst_port[2] = (uint8_t) ((ret[2] < 0) ? portid : ipv4_l3fwd_out_if[ret[2]]);
+ dst_port[3] = (uint8_t) ((ret[3] < 0) ? portid : ipv4_l3fwd_out_if[ret[3]]);
+
+ if (dst_port[0] >= RTE_MAX_ETHPORTS || (enabled_port_mask & 1 << dst_port[0]) == 0)
+ dst_port[0] = portid;
+ if (dst_port[1] >= RTE_MAX_ETHPORTS || (enabled_port_mask & 1 << dst_port[1]) == 0)
+ dst_port[1] = portid;
+ if (dst_port[2] >= RTE_MAX_ETHPORTS || (enabled_port_mask & 1 << dst_port[2]) == 0)
+ dst_port[2] = portid;
+ if (dst_port[3] >= RTE_MAX_ETHPORTS || (enabled_port_mask & 1 << dst_port[3]) == 0)
+ dst_port[3] = portid;
+
+ /* 02:00:00:00:00:xx */
+ d_addr_bytes[0] = ð_hdr[0]->d_addr.addr_bytes[0];
+ d_addr_bytes[1] = ð_hdr[1]->d_addr.addr_bytes[0];
+ d_addr_bytes[2] = ð_hdr[2]->d_addr.addr_bytes[0];
+ d_addr_bytes[3] = ð_hdr[3]->d_addr.addr_bytes[0];
+ *((uint64_t *)d_addr_bytes[0]) = 0x000000000002 + ((uint64_t)dst_port[0] << 40);
+ *((uint64_t *)d_addr_bytes[1]) = 0x000000000002 + ((uint64_t)dst_port[1] << 40);
+ *((uint64_t *)d_addr_bytes[2]) = 0x000000000002 + ((uint64_t)dst_port[2] << 40);
+ *((uint64_t *)d_addr_bytes[3]) = 0x000000000002 + ((uint64_t)dst_port[3] << 40);
+
+#ifdef DO_RFC_1812_CHECKS
+ /* Update time to live and header checksum */
+ --(ipv4_hdr[0]->time_to_live);
+ --(ipv4_hdr[1]->time_to_live);
+ --(ipv4_hdr[2]->time_to_live);
+ --(ipv4_hdr[3]->time_to_live);
+ ++(ipv4_hdr[0]->hdr_checksum);
+ ++(ipv4_hdr[1]->hdr_checksum);
+ ++(ipv4_hdr[2]->hdr_checksum);
+ ++(ipv4_hdr[3]->hdr_checksum);
+#endif
+
+ /* src addr */
+ ether_addr_copy(&ports_eth_addr[dst_port[0]], ð_hdr[0]->s_addr);
+ ether_addr_copy(&ports_eth_addr[dst_port[1]], ð_hdr[1]->s_addr);
+ ether_addr_copy(&ports_eth_addr[dst_port[2]], ð_hdr[2]->s_addr);
+ ether_addr_copy(&ports_eth_addr[dst_port[3]], ð_hdr[3]->s_addr);
+
+ send_single_packet(m[0], (uint8_t)dst_port[0]);
+ send_single_packet(m[1], (uint8_t)dst_port[1]);
+ send_single_packet(m[2], (uint8_t)dst_port[2]);
+ send_single_packet(m[3], (uint8_t)dst_port[3]);
+
+}
+
+static inline void get_ipv6_5tuple(struct rte_mbuf* m0, __m128i mask0, __m128i mask1,
+ union ipv6_5tuple_host * key)
+{
+ __m128i tmpdata0 = _mm_loadu_si128((__m128i*)(rte_pktmbuf_mtod(m0, unsigned char *)
+ + sizeof(struct ether_hdr) + offsetof(struct ipv6_hdr, payload_len)));
+ __m128i tmpdata1 = _mm_loadu_si128((__m128i*)(rte_pktmbuf_mtod(m0, unsigned char *)
+ + sizeof(struct ether_hdr) + offsetof(struct ipv6_hdr, payload_len)
+ + sizeof(__m128i)));
+ __m128i tmpdata2 = _mm_loadu_si128((__m128i*)(rte_pktmbuf_mtod(m0, unsigned char *)
+ + sizeof(struct ether_hdr) + offsetof(struct ipv6_hdr, payload_len)
+ + sizeof(__m128i) + sizeof(__m128i)));
+ key->xmm[0] = _mm_and_si128(tmpdata0, mask0);
+ key->xmm[1] = tmpdata1;
+ key->xmm[2] = _mm_and_si128(tmpdata2, mask1);
+ return;
+}
+
+static inline void
+simple_ipv6_fwd_4pkts(struct rte_mbuf* m[4], uint8_t portid, struct lcore_conf *qconf)
+{
+ struct ether_hdr *eth_hdr[4];
+ __attribute__((unused)) struct ipv6_hdr *ipv6_hdr[4];
+ void *d_addr_bytes[4];
+ uint8_t dst_port[4];
+ int32_t ret[4];
+ union ipv6_5tuple_host key[4];
+
+ eth_hdr[0] = rte_pktmbuf_mtod(m[0], struct ether_hdr *);
+ eth_hdr[1] = rte_pktmbuf_mtod(m[1], struct ether_hdr *);
+ eth_hdr[2] = rte_pktmbuf_mtod(m[2], struct ether_hdr *);
+ eth_hdr[3] = rte_pktmbuf_mtod(m[3], struct ether_hdr *);
+
+ /* Handle IPv6 headers.*/
+ ipv6_hdr[0] = (struct ipv6_hdr *)(rte_pktmbuf_mtod(m[0], unsigned char *) +
+ sizeof(struct ether_hdr));
+ ipv6_hdr[1] = (struct ipv6_hdr *)(rte_pktmbuf_mtod(m[1], unsigned char *) +
+ sizeof(struct ether_hdr));
+ ipv6_hdr[2] = (struct ipv6_hdr *)(rte_pktmbuf_mtod(m[2], unsigned char *) +
+ sizeof(struct ether_hdr));
+ ipv6_hdr[3] = (struct ipv6_hdr *)(rte_pktmbuf_mtod(m[3], unsigned char *) +
+ sizeof(struct ether_hdr));
+
+ get_ipv6_5tuple(m[0], mask1, mask2, &key[0]);
+ get_ipv6_5tuple(m[1], mask1, mask2, &key[1]);
+ get_ipv6_5tuple(m[2], mask1, mask2, &key[2]);
+ get_ipv6_5tuple(m[3], mask1, mask2, &key[3]);
+
+ const void *key_array[4] = {&key[0], &key[1], &key[2],&key[3]};
+ rte_hash_lookup_multi(qconf->ipv6_lookup_struct, &key_array[0], 4, ret);
+ dst_port[0] = (uint8_t) ((ret[0] < 0)? portid:ipv6_l3fwd_out_if[ret[0]]);
+ dst_port[1] = (uint8_t) ((ret[1] < 0)? portid:ipv6_l3fwd_out_if[ret[1]]);
+ dst_port[2] = (uint8_t) ((ret[2] < 0)? portid:ipv6_l3fwd_out_if[ret[2]]);
+ dst_port[3] = (uint8_t) ((ret[3] < 0)? portid:ipv6_l3fwd_out_if[ret[3]]);
+
+ if (dst_port[0] >= RTE_MAX_ETHPORTS || (enabled_port_mask & 1 << dst_port[0]) == 0)
+ dst_port[0] = portid;
+ if (dst_port[1] >= RTE_MAX_ETHPORTS || (enabled_port_mask & 1 << dst_port[1]) == 0)
+ dst_port[1] = portid;
+ if (dst_port[2] >= RTE_MAX_ETHPORTS || (enabled_port_mask & 1 << dst_port[2]) == 0)
+ dst_port[2] = portid;
+ if (dst_port[3] >= RTE_MAX_ETHPORTS || (enabled_port_mask & 1 << dst_port[3]) == 0)
+ dst_port[3] = portid;
+
+ /* 02:00:00:00:00:xx */
+ d_addr_bytes[0] = ð_hdr[0]->d_addr.addr_bytes[0];
+ d_addr_bytes[1] = ð_hdr[1]->d_addr.addr_bytes[0];
+ d_addr_bytes[2] = ð_hdr[2]->d_addr.addr_bytes[0];
+ d_addr_bytes[3] = ð_hdr[3]->d_addr.addr_bytes[0];
+ *((uint64_t *)d_addr_bytes[0]) = 0x000000000002 + ((uint64_t)dst_port[0] << 40);
+ *((uint64_t *)d_addr_bytes[1]) = 0x000000000002 + ((uint64_t)dst_port[1] << 40);
+ *((uint64_t *)d_addr_bytes[2]) = 0x000000000002 + ((uint64_t)dst_port[2] << 40);
+ *((uint64_t *)d_addr_bytes[3]) = 0x000000000002 + ((uint64_t)dst_port[3] << 40);
+
+ /* src addr */
+ ether_addr_copy(&ports_eth_addr[dst_port[0]], ð_hdr[0]->s_addr);
+ ether_addr_copy(&ports_eth_addr[dst_port[1]], ð_hdr[1]->s_addr);
+ ether_addr_copy(&ports_eth_addr[dst_port[2]], ð_hdr[2]->s_addr);
+ ether_addr_copy(&ports_eth_addr[dst_port[3]], ð_hdr[3]->s_addr);
+
+ send_single_packet(m[0], (uint8_t)dst_port[0]);
+ send_single_packet(m[1], (uint8_t)dst_port[1]);
+ send_single_packet(m[2], (uint8_t)dst_port[2]);
+ send_single_packet(m[3], (uint8_t)dst_port[3]);
+
+}
+#endif /* APP_LOOKUP_METHOD */
+
+static inline __attribute__((always_inline)) void