]> Pileus Git - ~andy/linux/blobdiff - net/core/pktgen.c
random32: assign to network folks in MAINTAINERS
[~andy/linux] / net / core / pktgen.c
index a797fff7f22213f3e5d1be6f97ab632a791079a4..fdac61cac1bd11b15a69f78584029731e9310e4e 100644 (file)
@@ -389,6 +389,9 @@ struct pktgen_dev {
 #ifdef CONFIG_XFRM
        __u8    ipsmode;                /* IPSEC mode (config) */
        __u8    ipsproto;               /* IPSEC type (config) */
+       __u32   spi;
+       struct dst_entry dst;
+       struct dst_ops dstops;
 #endif
        char result[512];
 };
@@ -654,8 +657,11 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
        }
 
 #ifdef CONFIG_XFRM
-       if (pkt_dev->flags & F_IPSEC_ON)
+       if (pkt_dev->flags & F_IPSEC_ON) {
                seq_printf(seq,  "IPSEC  ");
+               if (pkt_dev->spi)
+                       seq_printf(seq, "spi:%u", pkt_dev->spi);
+       }
 #endif
 
        if (pkt_dev->flags & F_MACSRC_RND)
@@ -1434,7 +1440,7 @@ static ssize_t pktgen_if_write(struct file *file,
                if (!mac_pton(valstr, pkt_dev->dst_mac))
                        return -EINVAL;
                /* Set up Dest MAC */
-               memcpy(&pkt_dev->hh[0], pkt_dev->dst_mac, ETH_ALEN);
+               ether_addr_copy(&pkt_dev->hh[0], pkt_dev->dst_mac);
 
                sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac);
                return count;
@@ -1451,7 +1457,7 @@ static ssize_t pktgen_if_write(struct file *file,
                if (!mac_pton(valstr, pkt_dev->src_mac))
                        return -EINVAL;
                /* Set up Src MAC */
-               memcpy(&pkt_dev->hh[6], pkt_dev->src_mac, ETH_ALEN);
+               ether_addr_copy(&pkt_dev->hh[6], pkt_dev->src_mac);
 
                sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac);
                return count;
@@ -1476,7 +1482,18 @@ static ssize_t pktgen_if_write(struct file *file,
                sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows);
                return count;
        }
+#ifdef CONFIG_XFRM
+       if (!strcmp(name, "spi")) {
+               len = num_arg(&user_buffer[i], 10, &value);
+               if (len < 0)
+                       return len;
 
+               i += len;
+               pkt_dev->spi = value;
+               sprintf(pg_result, "OK: spi=%u", pkt_dev->spi);
+               return count;
+       }
+#endif
        if (!strcmp(name, "flowlen")) {
                len = num_arg(&user_buffer[i], 10, &value);
                if (len < 0)
@@ -2043,10 +2060,10 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
        /* Default to the interface's mac if not explicitly set. */
 
        if (is_zero_ether_addr(pkt_dev->src_mac))
-               memcpy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr, ETH_ALEN);
+               ether_addr_copy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr);
 
        /* Set up Dest MAC */
-       memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN);
+       ether_addr_copy(&(pkt_dev->hh[0]), pkt_dev->dst_mac);
 
        if (pkt_dev->flags & F_IPV6) {
                int i, set = 0, err = 1;
@@ -2233,13 +2250,21 @@ static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow)
        struct xfrm_state *x = pkt_dev->flows[flow].x;
        struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id);
        if (!x) {
-               /*slow path: we dont already have xfrm_state*/
-               x = xfrm_stateonly_find(pn->net, DUMMY_MARK,
-                                       (xfrm_address_t *)&pkt_dev->cur_daddr,
-                                       (xfrm_address_t *)&pkt_dev->cur_saddr,
-                                       AF_INET,
-                                       pkt_dev->ipsmode,
-                                       pkt_dev->ipsproto, 0);
+
+               if (pkt_dev->spi) {
+                       /* We need as quick as possible to find the right SA
+                        * Searching with minimum criteria to archieve this.
+                        */
+                       x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET);
+               } else {
+                       /* slow path: we dont already have xfrm_state */
+                       x = xfrm_stateonly_find(pn->net, DUMMY_MARK,
+                                               (xfrm_address_t *)&pkt_dev->cur_daddr,
+                                               (xfrm_address_t *)&pkt_dev->cur_saddr,
+                                               AF_INET,
+                                               pkt_dev->ipsmode,
+                                               pkt_dev->ipsproto, 0);
+               }
                if (x) {
                        pkt_dev->flows[flow].x = x;
                        set_pkt_overhead(pkt_dev);
@@ -2475,31 +2500,47 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
 
 
 #ifdef CONFIG_XFRM
+static u32 pktgen_dst_metrics[RTAX_MAX + 1] = {
+
+       [RTAX_HOPLIMIT] = 0x5, /* Set a static hoplimit */
+};
+
 static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev)
 {
        struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
        int err = 0;
+       struct net *net = dev_net(pkt_dev->odev);
 
        if (!x)
                return 0;
        /* XXX: we dont support tunnel mode for now until
         * we resolve the dst issue */
-       if (x->props.mode != XFRM_MODE_TRANSPORT)
+       if ((x->props.mode != XFRM_MODE_TRANSPORT) && (pkt_dev->spi == 0))
                return 0;
 
-       spin_lock(&x->lock);
+       /* But when user specify an valid SPI, transformation
+        * supports both transport/tunnel mode + ESP/AH type.
+        */
+       if ((x->props.mode == XFRM_MODE_TUNNEL) && (pkt_dev->spi != 0))
+               skb->_skb_refdst = (unsigned long)&pkt_dev->dst | SKB_DST_NOREF;
 
+       rcu_read_lock_bh();
        err = x->outer_mode->output(x, skb);
-       if (err)
+       rcu_read_unlock_bh();
+       if (err) {
+               XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR);
                goto error;
+       }
        err = x->type->output(x, skb);
-       if (err)
+       if (err) {
+               XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR);
                goto error;
-
+       }
+       spin_lock_bh(&x->lock);
        x->curlft.bytes += skb->len;
        x->curlft.packets++;
+       spin_unlock_bh(&x->lock);
 error:
-       spin_unlock(&x->lock);
        return err;
 }
 
@@ -3542,6 +3583,17 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
 #ifdef CONFIG_XFRM
        pkt_dev->ipsmode = XFRM_MODE_TRANSPORT;
        pkt_dev->ipsproto = IPPROTO_ESP;
+
+       /* xfrm tunnel mode needs additional dst to extract outter
+        * ip header protocol/ttl/id field, here creat a phony one.
+        * instead of looking for a valid rt, which definitely hurting
+        * performance under such circumstance.
+        */
+       pkt_dev->dstops.family = AF_INET;
+       pkt_dev->dst.dev = pkt_dev->odev;
+       dst_init_metrics(&pkt_dev->dst, pktgen_dst_metrics, false);
+       pkt_dev->dst.child = &pkt_dev->dst;
+       pkt_dev->dst.ops = &pkt_dev->dstops;
 #endif
 
        return add_dev_to_thread(t, pkt_dev);