| @@ -135,7 +135,7 @@ struct vxlan_dev { · 134 unmodified lines |
| 135 | 135 | __u16 port_max; |
| 136 | 136 | __u8 tos; /* TOS override */ |
| 137 | 137 | __u8 ttl; |
| 138 | | − u32 flags; /* VXLAN_F_* below */ |
| 138 | + u32 flags; /* VXLAN_F_* in vxlan.h */ |
| 139 | 139 | |
| 140 | 140 | struct work_struct sock_work; |
| 141 | 141 | struct work_struct igmp_join; |
| @@ -150,13 +150,6 @@ struct vxlan_dev { · 8 unmodified lines |
| 150 | 150 | struct hlist_head fdb_head[FDB_HASH_SIZE]; |
| 151 | 151 | }; |
| 152 | 152 | |
| 153 | | −#define VXLAN_F_LEARN 0x01 |
| 154 | | −#define VXLAN_F_PROXY 0x02 |
| 155 | | −#define VXLAN_F_RSC 0x04 |
| 156 | | −#define VXLAN_F_L2MISS 0x08 |
| 157 | | −#define VXLAN_F_L3MISS 0x10 |
| 158 | | −#define VXLAN_F_IPV6 0x20 /* internal flag */ |
| 159 | | − |
| 160 | 153 | /* salt for hash table */ |
| 161 | 154 | static u32 vxlan_salt __read_mostly; |
| 162 | 155 | static struct workqueue_struct *vxlan_wq; |
| @@ -1601,18 +1594,11 @@ __be16 vxlan_src_port(__u16 port_min, __u16 port_max, struct sk_buff *skb) · 1438 unmodified lines |
| 1601 | 1594 | } |
| 1602 | 1595 | EXPORT_SYMBOL_GPL(vxlan_src_port); |
| 1603 | 1596 | |
| 1604 | | −static int handle_offloads(struct sk_buff *skb) |
| 1597 | +static inline struct sk_buff *vxlan_handle_offloads(struct sk_buff *skb, |
| 1598 | + bool udp_csum) |
| 1605 | 1599 | { |
| 1606 | | − if (skb_is_gso(skb)) { |
| 1607 | | − int err = skb_unclone(skb, GFP_ATOMIC); |
| 1608 | | − if (unlikely(err)) |
| 1609 | | − return err; |
| 1610 | | − |
| 1611 | | − skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL; |
| 1612 | | − } else if (skb->ip_summed != CHECKSUM_PARTIAL) |
| 1613 | | − skb->ip_summed = CHECKSUM_NONE; |
| 1614 | | − |
| 1615 | | − return 0; |
| 1600 | + int type = udp_csum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; |
| 1601 | + return iptunnel_handle_offloads(skb, udp_csum, type); |
| 1616 | 1602 | } |
| 1617 | 1603 | |
| 1618 | 1604 | #if IS_ENABLED(CONFIG_IPV6) |
| @@ -1629,10 +1615,9 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, · 10 unmodified lines |
| 1629 | 1615 | int min_headroom; |
| 1630 | 1616 | int err; |
| 1631 | 1617 | |
| 1632 | | − if (!skb->encapsulation) { |
| 1633 | | − skb_reset_inner_headers(skb); |
| 1634 | | − skb->encapsulation = 1; |
| 1635 | | − } |
| 1618 | + skb = vxlan_handle_offloads(skb, !udp_get_no_check6_tx(vs->sock->sk)); |
| 1619 | + if (IS_ERR(skb)) |
| 1620 | + return -EINVAL; |
| 1636 | 1621 | |
| 1637 | 1622 | skb_scrub_packet(skb, xnet); |
| 1638 | 1623 | |
| @@ -1666,27 +1651,14 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, · 27 unmodified lines |
| 1666 | 1651 | uh->source = src_port; |
| 1667 | 1652 | |
| 1668 | 1653 | uh->len = htons(skb->len); |
| 1669 | | − uh->check = 0; |
| 1670 | 1654 | |
| 1671 | 1655 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); |
| 1672 | 1656 | IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | |
| 1673 | 1657 | IPSKB_REROUTED); |
| 1674 | 1658 | skb_dst_set(skb, dst); |
| 1675 | 1659 | |
| 1676 | | − if (!skb_is_gso(skb) && !(dst->dev->features & NETIF_F_IPV6_CSUM)) { |
| 1677 | | − __wsum csum = skb_checksum(skb, 0, skb->len, 0); |
| 1678 | | − skb->ip_summed = CHECKSUM_UNNECESSARY; |
| 1679 | | − uh->check = csum_ipv6_magic(saddr, daddr, skb->len, |
| 1680 | | − IPPROTO_UDP, csum); |
| 1681 | | − if (uh->check == 0) |
| 1682 | | − uh->check = CSUM_MANGLED_0; |
| 1683 | | − } else { |
| 1684 | | − skb->ip_summed = CHECKSUM_PARTIAL; |
| 1685 | | − skb->csum_start = skb_transport_header(skb) - skb->head; |
| 1686 | | − skb->csum_offset = offsetof(struct udphdr, check); |
| 1687 | | − uh->check = ~csum_ipv6_magic(saddr, daddr, |
| 1688 | | − skb->len, IPPROTO_UDP, 0); |
| 1689 | | − } |
| 1660 | + udp6_set_csum(udp_get_no_check6_tx(vs->sock->sk), skb, |
| 1661 | + saddr, daddr, skb->len); |
| 1690 | 1662 | |
| 1691 | 1663 | __skb_push(skb, sizeof(*ip6h)); |
| 1692 | 1664 | skb_reset_network_header(skb); |
| @@ -1702,10 +1674,6 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, · 9 unmodified lines |
| 1702 | 1674 | ip6h->daddr = *daddr; |
| 1703 | 1675 | ip6h->saddr = *saddr; |
| 1704 | 1676 | |
| 1705 | | − err = handle_offloads(skb); |
| 1706 | | − if (err) |
| 1707 | | − return err; |
| 1708 | | − |
| 1709 | 1677 | ip6tunnel_xmit(skb, dev); |
| 1710 | 1678 | return 0; |
| 1711 | 1679 | } |
| @@ -1721,10 +1689,9 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, · 9 unmodified lines |
| 1721 | 1689 | int min_headroom; |
| 1722 | 1690 | int err; |
| 1723 | 1691 | |
| 1724 | | − if (!skb->encapsulation) { |
| 1725 | | − skb_reset_inner_headers(skb); |
| 1726 | | − skb->encapsulation = 1; |
| 1727 | | − } |
| 1692 | + skb = vxlan_handle_offloads(skb, !vs->sock->sk->sk_no_check_tx); |
| 1693 | + if (IS_ERR(skb)) |
| 1694 | + return -EINVAL; |
| 1728 | 1695 | |
| 1729 | 1696 | min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len |
| 1730 | 1697 | + VXLAN_HLEN + sizeof(struct iphdr) |
| @@ -1756,11 +1723,9 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, · 25 unmodified lines |
| 1756 | 1723 | uh->source = src_port; |
| 1757 | 1724 | |
| 1758 | 1725 | uh->len = htons(skb->len); |
| 1759 | | − uh->check = 0; |
| 1760 | 1726 | |
| 1761 | | − err = handle_offloads(skb); |
| 1762 | | − if (err) |
| 1763 | | − return err; |
| 1727 | + udp_set_csum(vs->sock->sk->sk_no_check_tx, skb, |
| 1728 | + src, dst, skb->len); |
| 1764 | 1729 | |
| 1765 | 1730 | return iptunnel_xmit(vs->sock->sk, rt, skb, src, dst, IPPROTO_UDP, |
| 1766 | 1731 | tos, ttl, df, xnet); |
| @@ -2405,7 +2370,7 @@ static void vxlan_del_work(struct work_struct *work) · 638 unmodified lines |
| 2405 | 2370 | * could be used for both IPv4 and IPv6 communications, but |
| 2406 | 2371 | * users may set bindv6only=1. |
| 2407 | 2372 | */ |
| 2408 | | −static struct socket *create_v6_sock(struct net *net, __be16 port) |
| 2373 | +static struct socket *create_v6_sock(struct net *net, __be16 port, u32 flags) |
| 2409 | 2374 | { |
| 2410 | 2375 | struct sock *sk; |
| 2411 | 2376 | struct socket *sock; |
| @@ -2442,18 +2407,25 @@ static struct socket *create_v6_sock(struct net *net, __be16 port) · 30 unmodified lines |
| 2442 | 2407 | |
| 2443 | 2408 | /* Disable multicast loopback */ |
| 2444 | 2409 | inet_sk(sk)->mc_loop = 0; |
| 2410 | + |
| 2411 | + if (flags & VXLAN_F_UDP_ZERO_CSUM6_TX) |
| 2412 | + udp_set_no_check6_tx(sk, true); |
| 2413 | + |
| 2414 | + if (flags & VXLAN_F_UDP_ZERO_CSUM6_RX) |
| 2415 | + udp_set_no_check6_rx(sk, true); |
| 2416 | + |
| 2445 | 2417 | return sock; |
| 2446 | 2418 | } |
| 2447 | 2419 | |
| 2448 | 2420 | #else |
| 2449 | 2421 | |
| 2450 | | −static struct socket *create_v6_sock(struct net *net, __be16 port) |
| 2422 | +static struct socket *create_v6_sock(struct net *net, __be16 port, u32 flags) |
| 2451 | 2423 | { |
| 2452 | 2424 | return ERR_PTR(-EPFNOSUPPORT); |
| 2453 | 2425 | } |
| 2454 | 2426 | #endif |
| 2455 | 2427 | |
| 2456 | | −static struct socket *create_v4_sock(struct net *net, __be16 port) |
| 2428 | +static struct socket *create_v4_sock(struct net *net, __be16 port, u32 flags) |
| 2457 | 2429 | { |
| 2458 | 2430 | struct sock *sk; |
| 2459 | 2431 | struct socket *sock; |
| @@ -2486,18 +2458,24 @@ static struct socket *create_v4_sock(struct net *net, __be16 port) · 26 unmodified lines |
| 2486 | 2458 | |
| 2487 | 2459 | /* Disable multicast loopback */ |
| 2488 | 2460 | inet_sk(sk)->mc_loop = 0; |
| 2461 | + |
| 2462 | + if (!(flags & VXLAN_F_UDP_CSUM)) |
| 2463 | + sock->sk->sk_no_check_tx = 1; |
| 2464 | + |
| 2489 | 2465 | return sock; |
| 2490 | 2466 | } |
| 2491 | 2467 | |
| 2492 | 2468 | /* Create new listen socket if needed */ |
| 2493 | 2469 | static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port, |
| 2494 | | − vxlan_rcv_t *rcv, void *data, bool ipv6) |
| 2470 | + vxlan_rcv_t *rcv, void *data, |
| 2471 | + u32 flags) |
| 2495 | 2472 | { |
| 2496 | 2473 | struct vxlan_net *vn = net_generic(net, vxlan_net_id); |
| 2497 | 2474 | struct vxlan_sock *vs; |
| 2498 | 2475 | struct socket *sock; |
| 2499 | 2476 | struct sock *sk; |
| 2500 | 2477 | unsigned int h; |
| 2478 | + bool ipv6 = !!(flags & VXLAN_F_IPV6); |
| 2501 | 2479 | |
| 2502 | 2480 | vs = kzalloc(sizeof(*vs), GFP_KERNEL); |
| 2503 | 2481 | if (!vs) |
| @@ -2509,9 +2487,9 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port, · 5 unmodified lines |
| 2509 | 2487 | INIT_WORK(&vs->del_work, vxlan_del_work); |
| 2510 | 2488 | |
| 2511 | 2489 | if (ipv6) |
| 2512 | | − sock = create_v6_sock(net, port); |
| 2490 | + sock = create_v6_sock(net, port, flags); |
| 2513 | 2491 | else |
| 2514 | | − sock = create_v4_sock(net, port); |
| 2492 | + sock = create_v4_sock(net, port, flags); |
| 2515 | 2493 | if (IS_ERR(sock)) { |
| 2516 | 2494 | kfree(vs); |
| 2517 | 2495 | return ERR_CAST(sock); |
| @@ -2549,12 +2527,12 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port, · 31 unmodified lines |
| 2549 | 2527 | |
| 2550 | 2528 | struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, |
| 2551 | 2529 | vxlan_rcv_t *rcv, void *data, |
| 2552 | | − bool no_share, bool ipv6) |
| 2530 | + bool no_share, u32 flags) |
| 2553 | 2531 | { |
| 2554 | 2532 | struct vxlan_net *vn = net_generic(net, vxlan_net_id); |
| 2555 | 2533 | struct vxlan_sock *vs; |
| 2556 | 2534 | |
| 2557 | | − vs = vxlan_socket_create(net, port, rcv, data, ipv6); |
| 2535 | + vs = vxlan_socket_create(net, port, rcv, data, flags); |
| 2558 | 2536 | if (!IS_ERR(vs)) |
| 2559 | 2537 | return vs; |
| 2560 | 2538 | |
| @@ -2587,7 +2565,7 @@ static void vxlan_sock_work(struct work_struct *work) · 26 unmodified lines |
| 2587 | 2565 | __be16 port = vxlan->dst_port; |
| 2588 | 2566 | struct vxlan_sock *nvs; |
| 2589 | 2567 | |
| 2590 | | − nvs = vxlan_sock_add(net, port, vxlan_rcv, NULL, false, vxlan->flags & VXLAN_F_IPV6); |
| 2568 | + nvs = vxlan_sock_add(net, port, vxlan_rcv, NULL, false, vxlan->flags); |
| 2591 | 2569 | spin_lock(&vn->sock_lock); |
| 2592 | 2570 | if (!IS_ERR(nvs)) |
| 2593 | 2571 | vxlan_vs_add_dev(nvs, vxlan); |
| @@ -2711,6 +2689,17 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, · 117 unmodified lines |
| 2711 | 2689 | if (data[IFLA_VXLAN_PORT]) |
| 2712 | 2690 | vxlan->dst_port = nla_get_be16(data[IFLA_VXLAN_PORT]); |
| 2713 | 2691 | |
| 2692 | + if (data[IFLA_VXLAN_UDP_CSUM] && nla_get_u8(data[IFLA_VXLAN_UDP_CSUM])) |
| 2693 | + vxlan->flags |= VXLAN_F_UDP_CSUM; |
| 2694 | + |
| 2695 | + if (data[IFLA_VXLAN_UDP_ZERO_CSUM6_TX] && |
| 2696 | + nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_TX])) |
| 2697 | + vxlan->flags |= VXLAN_F_UDP_ZERO_CSUM6_TX; |
| 2698 | + |
| 2699 | + if (data[IFLA_VXLAN_UDP_ZERO_CSUM6_RX] && |
| 2700 | + nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_RX])) |
| 2701 | + vxlan->flags |= VXLAN_F_UDP_ZERO_CSUM6_RX; |
| 2702 | + |
| 2714 | 2703 | if (vxlan_find_vni(net, vni, vxlan->dst_port)) { |
| 2715 | 2704 | pr_info("duplicate VNI %u\n", vni); |
| 2716 | 2705 | return -EEXIST; |
| @@ -2774,7 +2763,10 @@ static size_t vxlan_get_size(const struct net_device *dev) · 57 unmodified lines |
| 2774 | 2763 | nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_AGEING */ |
| 2775 | 2764 | nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_LIMIT */ |
| 2776 | 2765 | nla_total_size(sizeof(struct ifla_vxlan_port_range)) + |
| 2777 | | − nla_total_size(sizeof(__be16))+ /* IFLA_VXLAN_PORT */ |
| 2766 | + nla_total_size(sizeof(__be16)) + /* IFLA_VXLAN_PORT */ |
| 2767 | + nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_CSUM */ |
| 2768 | + nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_TX */ |
| 2769 | + nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_RX */ |
| 2778 | 2770 | 0; |
| 2779 | 2771 | } |
| 2780 | 2772 | |
| @@ -2834,7 +2826,13 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) · 53 unmodified lines |
| 2834 | 2826 | !!(vxlan->flags & VXLAN_F_L3MISS)) || |
| 2835 | 2827 | nla_put_u32(skb, IFLA_VXLAN_AGEING, vxlan->age_interval) || |
| 2836 | 2828 | nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->addrmax) || |
| 2837 | | − nla_put_be16(skb, IFLA_VXLAN_PORT, vxlan->dst_port)) |
| 2829 | + nla_put_be16(skb, IFLA_VXLAN_PORT, vxlan->dst_port) || |
| 2830 | + nla_put_u8(skb, IFLA_VXLAN_UDP_CSUM, |
| 2831 | + !!(vxlan->flags & VXLAN_F_UDP_CSUM)) || |
| 2832 | + nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, |
| 2833 | + !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_TX)) || |
| 2834 | + nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, |
| 2835 | + !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_RX))) |
| 2838 | 2836 | goto nla_put_failure; |
| 2839 | 2837 | |
| 2840 | 2838 | if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports)) |