examples/ipsec_secgw: fix security session
[dpdk.git] / examples / ipsec-secgw / ipsec-secgw.c
index caa9d57..c67f79d 100644 (file)
@@ -60,6 +60,7 @@
 
 #define OPTION_CONFIG          "config"
 #define OPTION_SINGLE_SA       "single-sa"
+#define OPTION_CRYPTODEV_MASK  "cryptodev_mask"
 
 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
 
@@ -125,6 +126,7 @@ struct ethaddr_info ethaddr_tbl[RTE_MAX_ETHPORTS] = {
 
 /* mask of enabled ports */
 static uint32_t enabled_port_mask;
+static uint64_t enabled_cryptodev_mask = UINT64_MAX;
 static uint32_t unprotected_port_mask;
 static int32_t promiscuous_on = 1;
 static int32_t numa_on = 1; /**< NUMA is enabled by default. */
@@ -238,6 +240,40 @@ prepare_one_packet(struct rte_mbuf *pkt, struct ipsec_traffic *t)
                RTE_LOG(ERR, IPSEC, "Unsupported packet type\n");
                rte_pktmbuf_free(pkt);
        }
+
+       /* Check if the packet has been processed inline. For inline protocol
+        * processed packets, the metadata in the mbuf can be used to identify
+        * the security processing done on the packet. The metadata will be
+        * used to retrieve the application registered userdata associated
+        * with the security session.
+        */
+
+       if (pkt->ol_flags & PKT_RX_SEC_OFFLOAD) {
+               struct ipsec_sa *sa;
+               struct ipsec_mbuf_metadata *priv;
+               struct rte_security_ctx *ctx = (struct rte_security_ctx *)
+                                               rte_eth_dev_get_sec_ctx(
+                                               pkt->port);
+
+               /* Retrieve the userdata registered. Here, the userdata
+                * registered is the SA pointer.
+                */
+
+               sa = (struct ipsec_sa *)
+                               rte_security_get_userdata(ctx, pkt->udata64);
+
+               if (sa == NULL) {
+                       /* userdata could not be retrieved */
+                       return;
+               }
+
+               /* Save SA as priv member in mbuf. This will be used in the
+                * IPsec selector(SP-SA) check.
+                */
+
+               priv = get_priv(pkt);
+               priv->sa = sa;
+       }
 }
 
 static inline void
@@ -374,13 +410,20 @@ inbound_sp_sa(struct sp_ctx *sp, struct sa_ctx *sa, struct traffic_type *ip,
                        ip->pkts[j++] = m;
                        continue;
                }
-               if (res & DISCARD || i < lim) {
+               if (res & DISCARD) {
                        rte_pktmbuf_free(m);
                        continue;
                }
+
                /* Only check SPI match for processed IPSec packets */
+               if (i < lim && ((m->ol_flags & PKT_RX_SEC_OFFLOAD) == 0)) {
+                       rte_pktmbuf_free(m);
+                       continue;
+               }
+
                sa_idx = ip->res[i] & PROTECT_MASK;
-               if (sa_idx == 0 || !inbound_sa_check(sa, m, sa_idx)) {
+               if (sa_idx >= IPSEC_SA_MAX_ENTRIES ||
+                               !inbound_sa_check(sa, m, sa_idx)) {
                        rte_pktmbuf_free(m);
                        continue;
                }
@@ -445,9 +488,9 @@ outbound_sp(struct sp_ctx *sp, struct traffic_type *ip,
        for (i = 0; i < ip->num; i++) {
                m = ip->pkts[i];
                sa_idx = ip->res[i] & PROTECT_MASK;
-               if ((ip->res[i] == 0) || (ip->res[i] & DISCARD))
+               if (ip->res[i] & DISCARD)
                        rte_pktmbuf_free(m);
-               else if (sa_idx != 0) {
+               else if (sa_idx < IPSEC_SA_MAX_ENTRIES) {
                        ipsec->res[ipsec->num] = sa_idx;
                        ipsec->pkts[ipsec->num++] = m;
                } else /* BYPASS */
@@ -894,6 +937,8 @@ print_usage(const char *prgname)
                "rx queues configuration\n"
                "  --single-sa SAIDX: use single SA index for outbound, "
                "bypassing the SP\n"
+               "  --cryptodev_mask MASK: hexadecimal bitmask of the "
+               "crypto devices to configure\n"
                "  -f CONFIG_FILE: Configuration file path\n",
                prgname);
 }
@@ -1008,6 +1053,14 @@ parse_args_long_options(struct option *lgopts, int32_t option_index)
                }
        }
 
+       if (__STRNCMP(optname, OPTION_CRYPTODEV_MASK)) {
+               ret = parse_portmask(optarg);
+               if (ret != -1) {
+                       enabled_cryptodev_mask = ret;
+                       ret = 0;
+               }
+       }
+
        return ret;
 }
 #undef __STRNCMP
@@ -1022,6 +1075,7 @@ parse_args(int32_t argc, char **argv)
        static struct option lgopts[] = {
                {OPTION_CONFIG, 1, 0, 0},
                {OPTION_SINGLE_SA, 1, 0, 0},
+               {OPTION_CRYPTODEV_MASK, 1, 0, 0},
                {NULL, 0, 0, 0}
        };
        int32_t f_present = 0;
@@ -1284,13 +1338,23 @@ add_cdev_mapping(struct rte_cryptodev_info *dev_info, uint16_t cdev_id,
        return ret;
 }
 
+/* Check if the device is enabled by cryptodev_mask */
+static int
+check_cryptodev_mask(uint8_t cdev_id)
+{
+       if (enabled_cryptodev_mask & (1 << cdev_id))
+               return 0;
+
+       return -1;
+}
+
 static int32_t
 cryptodevs_init(void)
 {
        struct rte_cryptodev_config dev_conf;
        struct rte_cryptodev_qp_conf qp_conf;
        uint16_t idx, max_nb_qps, qp, i;
-       int16_t cdev_id;
+       int16_t cdev_id, port_id;
        struct rte_hash_parameters params = { 0 };
 
        params.entries = CDEV_MAP_ENTRIES;
@@ -1319,12 +1383,28 @@ cryptodevs_init(void)
                if (sess_sz > max_sess_sz)
                        max_sess_sz = sess_sz;
        }
+       for (port_id = 0; port_id < rte_eth_dev_count(); port_id++) {
+               void *sec_ctx;
+
+               if ((enabled_port_mask & (1 << port_id)) == 0)
+                       continue;
+
+               sec_ctx = rte_eth_dev_get_sec_ctx(port_id);
+               if (sec_ctx == NULL)
+                       continue;
+
+               sess_sz = rte_security_session_get_size(sec_ctx);
+               if (sess_sz > max_sess_sz)
+                       max_sess_sz = sess_sz;
+       }
 
        idx = 0;
-       /* Start from last cdev id to give HW priority */
-       for (cdev_id = rte_cryptodev_count() - 1; cdev_id >= 0; cdev_id--) {
+       for (cdev_id = 0; cdev_id < rte_cryptodev_count(); cdev_id++) {
                struct rte_cryptodev_info cdev_info;
 
+               if (check_cryptodev_mask((uint8_t)cdev_id))
+                       continue;
+
                rte_cryptodev_info_get(cdev_id, &cdev_info);
 
                if (nb_lcore_params > cdev_info.max_nb_queue_pairs)
@@ -1389,6 +1469,38 @@ cryptodevs_init(void)
                                        cdev_id);
        }
 
+       /* create session pools for eth devices that implement security */
+       for (port_id = 0; port_id < rte_eth_dev_count(); port_id++) {
+               if ((enabled_port_mask & (1 << port_id)) &&
+                               rte_eth_dev_get_sec_ctx(port_id)) {
+                       int socket_id = rte_eth_dev_socket_id(port_id);
+
+                       if (!socket_ctx[socket_id].session_pool) {
+                               char mp_name[RTE_MEMPOOL_NAMESIZE];
+                               struct rte_mempool *sess_mp;
+
+                               snprintf(mp_name, RTE_MEMPOOL_NAMESIZE,
+                                               "sess_mp_%u", socket_id);
+                               sess_mp = rte_mempool_create(mp_name,
+                                               CDEV_MP_NB_OBJS,
+                                               max_sess_sz,
+                                               CDEV_MP_CACHE_SZ,
+                                               0, NULL, NULL, NULL,
+                                               NULL, socket_id,
+                                               0);
+                               if (sess_mp == NULL)
+                                       rte_exit(EXIT_FAILURE,
+                                               "Cannot create session pool "
+                                               "on socket %d\n", socket_id);
+                               else
+                                       printf("Allocated session pool "
+                                               "on socket %d\n", socket_id);
+                               socket_ctx[socket_id].session_pool = sess_mp;
+                       }
+               }
+       }
+
+
        printf("\n");
 
        return 0;