ring: return free space when enqueuing
[dpdk.git] / examples / performance-thread / l3fwd-thread / main.c
index db6cb64..b4c0df1 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
 #define APP_LOOKUP_METHOD             APP_LOOKUP_LPM
 #endif
 
+static int
+check_ptype(int portid)
+{
+       int i, ret;
+       int ipv4 = 0, ipv6 = 0;
+
+       ret = rte_eth_dev_get_supported_ptypes(portid, RTE_PTYPE_L3_MASK, NULL,
+                       0);
+       if (ret <= 0)
+               return 0;
+
+       uint32_t ptypes[ret];
+
+       ret = rte_eth_dev_get_supported_ptypes(portid, RTE_PTYPE_L3_MASK,
+                       ptypes, ret);
+       for (i = 0; i < ret; ++i) {
+               if (ptypes[i] & RTE_PTYPE_L3_IPV4)
+                       ipv4 = 1;
+               if (ptypes[i] & RTE_PTYPE_L3_IPV6)
+                       ipv6 = 1;
+       }
+
+       if (ipv4 && ipv6)
+               return 1;
+
+       return 0;
+}
+
+static inline void
+parse_ptype(struct rte_mbuf *m)
+{
+       struct ether_hdr *eth_hdr;
+       uint32_t packet_type = RTE_PTYPE_UNKNOWN;
+       uint16_t ether_type;
+
+       eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
+       ether_type = eth_hdr->ether_type;
+       if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4))
+               packet_type |= RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
+       else if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv6))
+               packet_type |= RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
+
+       m->packet_type = packet_type;
+}
+
+static uint16_t
+cb_parse_ptype(__rte_unused uint8_t port, __rte_unused uint16_t queue,
+               struct rte_mbuf *pkts[], uint16_t nb_pkts,
+               __rte_unused uint16_t max_pkts, __rte_unused void *user_param)
+{
+       unsigned int i;
+
+       for (i = 0; i < nb_pkts; i++)
+               parse_ptype(pkts[i]);
+
+       return nb_pkts;
+}
+
 /*
  *  When set to zero, simple forwaring path is eanbled.
  *  When set to one, optimized forwarding path is enabled.
@@ -170,8 +228,9 @@ static __m128i val_eth[RTE_MAX_ETHPORTS];
 
 /* mask of enabled ports */
 static uint32_t enabled_port_mask;
-static int promiscuous_on; /**< $et in promiscuous mode off by default. */
+static int promiscuous_on; /**< Set in promiscuous mode off by default. */
 static int numa_on = 1;    /**< NUMA is enabled by default. */
+static int parse_ptype_on;
 
 #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
 static int ipv6;           /**< ipv6 is false by default. */
@@ -655,7 +714,8 @@ send_single_packet(struct rte_mbuf *m, uint8_t port)
        return 0;
 }
 
-#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
+#if ((APP_LOOKUP_METHOD == APP_LOOKUP_LPM) && \
+       (ENABLE_MULTI_BUFFER_OPTIMIZE == 1))
 static inline __attribute__((always_inline)) void
 send_packetsx4(uint8_t port,
        struct rte_mbuf *m[], uint32_t num)
@@ -838,7 +898,7 @@ static inline uint8_t
 get_ipv4_dst_port(void *ipv4_hdr, uint8_t portid,
                lookup_struct_t *ipv4_l3fwd_lookup_struct)
 {
-       uint8_t next_hop;
+       uint32_t next_hop;
 
        return (uint8_t)((rte_lpm_lookup(ipv4_l3fwd_lookup_struct,
                rte_be_to_cpu_32(((struct ipv4_hdr *)ipv4_hdr)->dst_addr),
@@ -849,7 +909,7 @@ static inline uint8_t
 get_ipv6_dst_port(void *ipv6_hdr,  uint8_t portid,
                lookup6_struct_t *ipv6_l3fwd_lookup_struct)
 {
-       uint8_t next_hop;
+       uint32_t next_hop;
 
        return (uint8_t) ((rte_lpm6_lookup(ipv6_l3fwd_lookup_struct,
                        ((struct ipv6_hdr *)ipv6_hdr)->dst_addr, &next_hop) == 0) ?
@@ -995,7 +1055,7 @@ simple_ipv4_fwd_8pkts(struct rte_mbuf *m[8], uint8_t portid)
        const void *key_array[8] = {&key[0], &key[1], &key[2], &key[3],
                        &key[4], &key[5], &key[6], &key[7]};
 
-       rte_hash_lookup_multi(RTE_PER_LCORE(lcore_conf)->ipv4_lookup_struct,
+       rte_hash_lookup_bulk(RTE_PER_LCORE(lcore_conf)->ipv4_lookup_struct,
                        &key_array[0], 8, 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]]);
@@ -1149,7 +1209,7 @@ simple_ipv6_fwd_8pkts(struct rte_mbuf *m[8], uint8_t portid)
        const void *key_array[8] = {&key[0], &key[1], &key[2], &key[3],
                        &key[4], &key[5], &key[6], &key[7]};
 
-       rte_hash_lookup_multi(RTE_PER_LCORE(lcore_conf)->ipv6_lookup_struct,
+       rte_hash_lookup_bulk(RTE_PER_LCORE(lcore_conf)->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]]);
@@ -1325,7 +1385,7 @@ rfc1812_process(struct ipv4_hdr *ipv4_hdr, uint16_t *dp, uint32_t ptype)
 }
 
 #else
-#define        rfc1812_process(mb, dp) do { } while (0)
+#define        rfc1812_process(mb, dp, ptype)  do { } while (0)
 #endif /* DO_RFC_1812_CHECKS */
 #endif /* APP_LOOKUP_LPM && ENABLE_MULTI_BUFFER_OPTIMIZE */
 
@@ -1336,25 +1396,28 @@ rfc1812_process(struct ipv4_hdr *ipv4_hdr, uint16_t *dp, uint32_t ptype)
 static inline __attribute__((always_inline)) uint16_t
 get_dst_port(struct rte_mbuf *pkt, uint32_t dst_ipv4, uint8_t portid)
 {
-       uint8_t next_hop;
+       uint32_t next_hop;
        struct ipv6_hdr *ipv6_hdr;
        struct ether_hdr *eth_hdr;
 
        if (RTE_ETH_IS_IPV4_HDR(pkt->packet_type)) {
-               if (rte_lpm_lookup(RTE_PER_LCORE(lcore_conf)->ipv4_lookup_struct,
-                               dst_ipv4, &next_hop) != 0)
-                       next_hop = portid;
+               return (uint16_t) ((rte_lpm_lookup(
+                               RTE_PER_LCORE(lcore_conf)->ipv4_lookup_struct, dst_ipv4,
+                               &next_hop) == 0) ? next_hop : portid);
+
        } else if (RTE_ETH_IS_IPV6_HDR(pkt->packet_type)) {
+
                eth_hdr = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
                ipv6_hdr = (struct ipv6_hdr *)(eth_hdr + 1);
-               if (rte_lpm6_lookup(RTE_PER_LCORE(lcore_conf)->ipv6_lookup_struct,
-                               ipv6_hdr->dst_addr, &next_hop) != 0)
-                       next_hop = portid;
-       } else {
-               next_hop = portid;
+
+               return (uint16_t) ((rte_lpm6_lookup(
+                               RTE_PER_LCORE(lcore_conf)->ipv6_lookup_struct,
+                               ipv6_hdr->dst_addr, &next_hop) == 0) ?
+                               next_hop : portid);
+
        }
 
-       return next_hop;
+       return portid;
 }
 
 static inline void
@@ -1439,7 +1502,11 @@ processx4_step2(__m128i dip,
        /* if all 4 packets are IPV4. */
        if (likely(ipv4_flag)) {
                rte_lpm_lookupx4(RTE_PER_LCORE(lcore_conf)->ipv4_lookup_struct, dip,
-                               dprt, portid);
+                               dst.u32, portid);
+
+               /* get rid of unused upper 16 bit for each dport. */
+               dst.x = _mm_packs_epi32(dst.x, dst.x);
+               *(uint64_t *)dprt = dst.u64[0];
        } else {
                dst.x = dip;
                dprt[0] = get_dst_port(pkt[0], dst.u32[0], portid);
@@ -1652,9 +1719,9 @@ port_groupx4(uint16_t pn[FWDSTEP + 1], uint16_t *lp, __m128i dp1, __m128i dp2)
 
        /* if dest port value has changed. */
        if (v != GRPMSK) {
-               lp = pnum->u16 + gptbl[v].idx;
-               lp[0] = 1;
                pnum->u64 = gptbl[v].pnum;
+               pnum->u16[FWDSTEP] = 1;
+               lp = pnum->u16 + gptbl[v].idx;
        }
 
        return lp;
@@ -1833,12 +1900,12 @@ process_burst(struct rte_mbuf *pkts_burst[MAX_PKT_BURST], int nb_rx,
        for (j = 0; j < (nb_rx - PREFETCH_OFFSET); j++) {
                rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[
                                j + PREFETCH_OFFSET], void *));
-               l3fwd_simple_forward(pkts_burst[j], portid, qconf);
+               l3fwd_simple_forward(pkts_burst[j], portid);
        }
 
        /* Forward remaining prefetched packets */
        for (; j < nb_rx; j++)
-               l3fwd_simple_forward(pkts_burst[j], portid, qconf);
+               l3fwd_simple_forward(pkts_burst[j], portid);
 
 #endif /* ENABLE_MULTI_BUFFER_OPTIMIZE */
 
@@ -2146,7 +2213,7 @@ lthread_rx(void *dummy)
                                ret = rte_ring_sp_enqueue_burst(
                                                rx_conf->ring[worker_id],
                                                (void **) pkts_burst,
-                                               nb_rx);
+                                               nb_rx, NULL);
 
                                new_len = old_len + ret;
 
@@ -2386,7 +2453,7 @@ pthread_rx(void *dummy)
                        SET_CPU_BUSY(rx_conf, CPU_PROCESS);
                        worker_id = (worker_id + 1) % rx_conf->n_ring;
                        n = rte_ring_sp_enqueue_burst(rx_conf->ring[worker_id],
-                                       (void **)pkts_burst, nb_rx);
+                                       (void **)pkts_burst, nb_rx, NULL);
 
                        if (unlikely(n != nb_rx)) {
                                uint32_t k;
@@ -2601,6 +2668,7 @@ print_usage(const char *prgname)
                "  [--rx (port,queue,lcore,thread)[,(port,queue,lcore,thread]]"
                "  [--tx (lcore,thread)[,(lcore,thread]]"
                "  [--enable-jumbo [--max-pkt-len PKTLEN]]\n"
+               "  [--parse-ptype]\n\n"
                "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
                "  -P : enable promiscuous mode\n"
                "  --rx (port,queue,lcore,thread): rx queues configuration\n"
@@ -2612,7 +2680,8 @@ print_usage(const char *prgname)
                "  --enable-jumbo: enable jumbo frame"
                " which max packet len is PKTLEN in decimal (64-9600)\n"
                "  --hash-entry-num: specify the hash entry number in hexadecimal to be setup\n"
-               "  --no-lthreads: turn off lthread model\n",
+               "  --no-lthreads: turn off lthread model\n"
+               "  --parse-ptype: set to use software to analyze packet type\n\n",
                prgname);
 }
 
@@ -2831,6 +2900,7 @@ parse_eth_dest(const char *optarg)
 #define CMD_LINE_OPT_ENABLE_JUMBO "enable-jumbo"
 #define CMD_LINE_OPT_HASH_ENTRY_NUM "hash-entry-num"
 #define CMD_LINE_OPT_NO_LTHREADS "no-lthreads"
+#define CMD_LINE_OPT_PARSE_PTYPE "parse-ptype"
 
 /* Parse the argument given in the command line of the application */
 static int
@@ -2850,6 +2920,7 @@ parse_args(int argc, char **argv)
                {CMD_LINE_OPT_ENABLE_JUMBO, 0, 0, 0},
                {CMD_LINE_OPT_HASH_ENTRY_NUM, 1, 0, 0},
                {CMD_LINE_OPT_NO_LTHREADS, 0, 0, 0},
+               {CMD_LINE_OPT_PARSE_PTYPE, 0, 0, 0},
                {NULL, 0, 0, 0}
        };
 
@@ -2926,6 +2997,12 @@ parse_args(int argc, char **argv)
                                lthreads_on = 0;
                        }
 
+                       if (!strncmp(lgopts[option_index].name, CMD_LINE_OPT_PARSE_PTYPE,
+                                       sizeof(CMD_LINE_OPT_PARSE_PTYPE))) {
+                               printf("software packet type parsing enabled\n");
+                               parse_ptype_on = 1;
+                       }
+
                        if (!strncmp(lgopts[option_index].name, CMD_LINE_OPT_ENABLE_JUMBO,
                                sizeof(CMD_LINE_OPT_ENABLE_JUMBO))) {
                                struct option lenopts = {"max-pkt-len", required_argument, 0,
@@ -2974,7 +3051,7 @@ parse_args(int argc, char **argv)
                argv[optind-1] = prgname;
 
        ret = optind-1;
-       optind = 0; /* reset getopt lib */
+       optind = 1; /* reset getopt lib */
        return ret;
 }
 
@@ -3244,14 +3321,18 @@ static void
 setup_lpm(int socketid)
 {
        struct rte_lpm6_config config;
+       struct rte_lpm_config lpm_ipv4_config;
        unsigned i;
        int ret;
        char s[64];
 
        /* create the LPM table */
        snprintf(s, sizeof(s), "IPV4_L3FWD_LPM_%d", socketid);
-       ipv4_l3fwd_lookup_struct[socketid] = rte_lpm_create(s, socketid,
-                               IPV4_L3FWD_LPM_MAX_RULES, 0);
+       lpm_ipv4_config.max_rules = IPV4_L3FWD_LPM_MAX_RULES;
+       lpm_ipv4_config.number_tbl8s = 256;
+       lpm_ipv4_config.flags = 0;
+       ipv4_l3fwd_lookup_struct[socketid] =
+                       rte_lpm_create(s, socketid, &lpm_ipv4_config);
        if (ipv4_l3fwd_lookup_struct[socketid] == NULL)
                rte_exit(EXIT_FAILURE, "Unable to create the l3fwd LPM table"
                                " on socket %d\n", socketid);
@@ -3398,7 +3479,7 @@ check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
                                continue;
                        }
                        /* clear all_ports_up flag if any link down */
-                       if (link.link_status == 0) {
+                       if (link.link_status == ETH_LINK_DOWN) {
                                all_ports_up = 0;
                                break;
                        }
@@ -3472,8 +3553,6 @@ main(int argc, char **argv)
                rte_exit(EXIT_FAILURE, "init_rx_rings failed\n");
 
        nb_ports = rte_eth_dev_count();
-       if (nb_ports > RTE_MAX_ETHPORTS)
-               nb_ports = RTE_MAX_ETHPORTS;
 
        if (check_port_config(nb_ports) < 0)
                rte_exit(EXIT_FAILURE, "check_port_config failed\n");
@@ -3612,6 +3691,31 @@ main(int argc, char **argv)
                        rte_eth_promiscuous_enable(portid);
        }
 
+       for (i = 0; i < n_rx_thread; i++) {
+               lcore_id = rx_thread[i].conf.lcore_id;
+               if (rte_lcore_is_enabled(lcore_id) == 0)
+                       continue;
+
+               /* check if hw packet type is supported */
+               for (queue = 0; queue < rx_thread[i].n_rx_queue; ++queue) {
+                       portid = rx_thread[i].rx_queue_list[queue].port_id;
+                       queueid = rx_thread[i].rx_queue_list[queue].queue_id;
+
+                       if (parse_ptype_on) {
+                               if (!rte_eth_add_rx_callback(portid, queueid,
+                                               cb_parse_ptype, NULL))
+                                       rte_exit(EXIT_FAILURE,
+                                               "Failed to add rx callback: "
+                                               "port=%d\n", portid);
+                       } else if (!check_ptype(portid))
+                               rte_exit(EXIT_FAILURE,
+                                       "Port %d cannot parse packet type.\n\n"
+                                       "Please add --parse-ptype to use sw "
+                                       "packet type analyzer.\n\n",
+                                       portid);
+               }
+       }
+
        check_all_ports_link_status((uint8_t)nb_ports, enabled_port_mask);
 
        if (lthreads_on) {