diff options
Diffstat (limited to 'net/core/pktgen.c')
-rw-r--r-- | net/core/pktgen.c | 88 |
1 files changed, 70 insertions, 18 deletions
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index a797fff7f222..fdac61cac1bd 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -389,6 +389,9 @@ struct pktgen_dev { | |||
389 | #ifdef CONFIG_XFRM | 389 | #ifdef CONFIG_XFRM |
390 | __u8 ipsmode; /* IPSEC mode (config) */ | 390 | __u8 ipsmode; /* IPSEC mode (config) */ |
391 | __u8 ipsproto; /* IPSEC type (config) */ | 391 | __u8 ipsproto; /* IPSEC type (config) */ |
392 | __u32 spi; | ||
393 | struct dst_entry dst; | ||
394 | struct dst_ops dstops; | ||
392 | #endif | 395 | #endif |
393 | char result[512]; | 396 | char result[512]; |
394 | }; | 397 | }; |
@@ -654,8 +657,11 @@ static int pktgen_if_show(struct seq_file *seq, void *v) | |||
654 | } | 657 | } |
655 | 658 | ||
656 | #ifdef CONFIG_XFRM | 659 | #ifdef CONFIG_XFRM |
657 | if (pkt_dev->flags & F_IPSEC_ON) | 660 | if (pkt_dev->flags & F_IPSEC_ON) { |
658 | seq_printf(seq, "IPSEC "); | 661 | seq_printf(seq, "IPSEC "); |
662 | if (pkt_dev->spi) | ||
663 | seq_printf(seq, "spi:%u", pkt_dev->spi); | ||
664 | } | ||
659 | #endif | 665 | #endif |
660 | 666 | ||
661 | if (pkt_dev->flags & F_MACSRC_RND) | 667 | if (pkt_dev->flags & F_MACSRC_RND) |
@@ -1434,7 +1440,7 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1434 | if (!mac_pton(valstr, pkt_dev->dst_mac)) | 1440 | if (!mac_pton(valstr, pkt_dev->dst_mac)) |
1435 | return -EINVAL; | 1441 | return -EINVAL; |
1436 | /* Set up Dest MAC */ | 1442 | /* Set up Dest MAC */ |
1437 | memcpy(&pkt_dev->hh[0], pkt_dev->dst_mac, ETH_ALEN); | 1443 | ether_addr_copy(&pkt_dev->hh[0], pkt_dev->dst_mac); |
1438 | 1444 | ||
1439 | sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac); | 1445 | sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac); |
1440 | return count; | 1446 | return count; |
@@ -1451,7 +1457,7 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1451 | if (!mac_pton(valstr, pkt_dev->src_mac)) | 1457 | if (!mac_pton(valstr, pkt_dev->src_mac)) |
1452 | return -EINVAL; | 1458 | return -EINVAL; |
1453 | /* Set up Src MAC */ | 1459 | /* Set up Src MAC */ |
1454 | memcpy(&pkt_dev->hh[6], pkt_dev->src_mac, ETH_ALEN); | 1460 | ether_addr_copy(&pkt_dev->hh[6], pkt_dev->src_mac); |
1455 | 1461 | ||
1456 | sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac); | 1462 | sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac); |
1457 | return count; | 1463 | return count; |
@@ -1476,7 +1482,18 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1476 | sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows); | 1482 | sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows); |
1477 | return count; | 1483 | return count; |
1478 | } | 1484 | } |
1485 | #ifdef CONFIG_XFRM | ||
1486 | if (!strcmp(name, "spi")) { | ||
1487 | len = num_arg(&user_buffer[i], 10, &value); | ||
1488 | if (len < 0) | ||
1489 | return len; | ||
1479 | 1490 | ||
1491 | i += len; | ||
1492 | pkt_dev->spi = value; | ||
1493 | sprintf(pg_result, "OK: spi=%u", pkt_dev->spi); | ||
1494 | return count; | ||
1495 | } | ||
1496 | #endif | ||
1480 | if (!strcmp(name, "flowlen")) { | 1497 | if (!strcmp(name, "flowlen")) { |
1481 | len = num_arg(&user_buffer[i], 10, &value); | 1498 | len = num_arg(&user_buffer[i], 10, &value); |
1482 | if (len < 0) | 1499 | if (len < 0) |
@@ -2043,10 +2060,10 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) | |||
2043 | /* Default to the interface's mac if not explicitly set. */ | 2060 | /* Default to the interface's mac if not explicitly set. */ |
2044 | 2061 | ||
2045 | if (is_zero_ether_addr(pkt_dev->src_mac)) | 2062 | if (is_zero_ether_addr(pkt_dev->src_mac)) |
2046 | memcpy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr, ETH_ALEN); | 2063 | ether_addr_copy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr); |
2047 | 2064 | ||
2048 | /* Set up Dest MAC */ | 2065 | /* Set up Dest MAC */ |
2049 | memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); | 2066 | ether_addr_copy(&(pkt_dev->hh[0]), pkt_dev->dst_mac); |
2050 | 2067 | ||
2051 | if (pkt_dev->flags & F_IPV6) { | 2068 | if (pkt_dev->flags & F_IPV6) { |
2052 | int i, set = 0, err = 1; | 2069 | int i, set = 0, err = 1; |
@@ -2233,13 +2250,21 @@ static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) | |||
2233 | struct xfrm_state *x = pkt_dev->flows[flow].x; | 2250 | struct xfrm_state *x = pkt_dev->flows[flow].x; |
2234 | struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id); | 2251 | struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id); |
2235 | if (!x) { | 2252 | if (!x) { |
2236 | /*slow path: we dont already have xfrm_state*/ | 2253 | |
2237 | x = xfrm_stateonly_find(pn->net, DUMMY_MARK, | 2254 | if (pkt_dev->spi) { |
2238 | (xfrm_address_t *)&pkt_dev->cur_daddr, | 2255 | /* We need as quick as possible to find the right SA |
2239 | (xfrm_address_t *)&pkt_dev->cur_saddr, | 2256 | * Searching with minimum criteria to archieve this. |
2240 | AF_INET, | 2257 | */ |
2241 | pkt_dev->ipsmode, | 2258 | x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET); |
2242 | pkt_dev->ipsproto, 0); | 2259 | } else { |
2260 | /* slow path: we dont already have xfrm_state */ | ||
2261 | x = xfrm_stateonly_find(pn->net, DUMMY_MARK, | ||
2262 | (xfrm_address_t *)&pkt_dev->cur_daddr, | ||
2263 | (xfrm_address_t *)&pkt_dev->cur_saddr, | ||
2264 | AF_INET, | ||
2265 | pkt_dev->ipsmode, | ||
2266 | pkt_dev->ipsproto, 0); | ||
2267 | } | ||
2243 | if (x) { | 2268 | if (x) { |
2244 | pkt_dev->flows[flow].x = x; | 2269 | pkt_dev->flows[flow].x = x; |
2245 | set_pkt_overhead(pkt_dev); | 2270 | set_pkt_overhead(pkt_dev); |
@@ -2475,31 +2500,47 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) | |||
2475 | 2500 | ||
2476 | 2501 | ||
2477 | #ifdef CONFIG_XFRM | 2502 | #ifdef CONFIG_XFRM |
2503 | static u32 pktgen_dst_metrics[RTAX_MAX + 1] = { | ||
2504 | |||
2505 | [RTAX_HOPLIMIT] = 0x5, /* Set a static hoplimit */ | ||
2506 | }; | ||
2507 | |||
2478 | static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) | 2508 | static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) |
2479 | { | 2509 | { |
2480 | struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; | 2510 | struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; |
2481 | int err = 0; | 2511 | int err = 0; |
2512 | struct net *net = dev_net(pkt_dev->odev); | ||
2482 | 2513 | ||
2483 | if (!x) | 2514 | if (!x) |
2484 | return 0; | 2515 | return 0; |
2485 | /* XXX: we dont support tunnel mode for now until | 2516 | /* XXX: we dont support tunnel mode for now until |
2486 | * we resolve the dst issue */ | 2517 | * we resolve the dst issue */ |
2487 | if (x->props.mode != XFRM_MODE_TRANSPORT) | 2518 | if ((x->props.mode != XFRM_MODE_TRANSPORT) && (pkt_dev->spi == 0)) |
2488 | return 0; | 2519 | return 0; |
2489 | 2520 | ||
2490 | spin_lock(&x->lock); | 2521 | /* But when user specify an valid SPI, transformation |
2522 | * supports both transport/tunnel mode + ESP/AH type. | ||
2523 | */ | ||
2524 | if ((x->props.mode == XFRM_MODE_TUNNEL) && (pkt_dev->spi != 0)) | ||
2525 | skb->_skb_refdst = (unsigned long)&pkt_dev->dst | SKB_DST_NOREF; | ||
2491 | 2526 | ||
2527 | rcu_read_lock_bh(); | ||
2492 | err = x->outer_mode->output(x, skb); | 2528 | err = x->outer_mode->output(x, skb); |
2493 | if (err) | 2529 | rcu_read_unlock_bh(); |
2530 | if (err) { | ||
2531 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR); | ||
2494 | goto error; | 2532 | goto error; |
2533 | } | ||
2495 | err = x->type->output(x, skb); | 2534 | err = x->type->output(x, skb); |
2496 | if (err) | 2535 | if (err) { |
2536 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR); | ||
2497 | goto error; | 2537 | goto error; |
2498 | 2538 | } | |
2539 | spin_lock_bh(&x->lock); | ||
2499 | x->curlft.bytes += skb->len; | 2540 | x->curlft.bytes += skb->len; |
2500 | x->curlft.packets++; | 2541 | x->curlft.packets++; |
2542 | spin_unlock_bh(&x->lock); | ||
2501 | error: | 2543 | error: |
2502 | spin_unlock(&x->lock); | ||
2503 | return err; | 2544 | return err; |
2504 | } | 2545 | } |
2505 | 2546 | ||
@@ -3542,6 +3583,17 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) | |||
3542 | #ifdef CONFIG_XFRM | 3583 | #ifdef CONFIG_XFRM |
3543 | pkt_dev->ipsmode = XFRM_MODE_TRANSPORT; | 3584 | pkt_dev->ipsmode = XFRM_MODE_TRANSPORT; |
3544 | pkt_dev->ipsproto = IPPROTO_ESP; | 3585 | pkt_dev->ipsproto = IPPROTO_ESP; |
3586 | |||
3587 | /* xfrm tunnel mode needs additional dst to extract outter | ||
3588 | * ip header protocol/ttl/id field, here creat a phony one. | ||
3589 | * instead of looking for a valid rt, which definitely hurting | ||
3590 | * performance under such circumstance. | ||
3591 | */ | ||
3592 | pkt_dev->dstops.family = AF_INET; | ||
3593 | pkt_dev->dst.dev = pkt_dev->odev; | ||
3594 | dst_init_metrics(&pkt_dev->dst, pktgen_dst_metrics, false); | ||
3595 | pkt_dev->dst.child = &pkt_dev->dst; | ||
3596 | pkt_dev->dst.ops = &pkt_dev->dstops; | ||
3545 | #endif | 3597 | #endif |
3546 | 3598 | ||
3547 | return add_dev_to_thread(t, pkt_dev); | 3599 | return add_dev_to_thread(t, pkt_dev); |