aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-01-14 15:20:11 -0500
committerDavid S. Miller <davem@davemloft.net>2015-01-14 15:20:11 -0500
commit2733135329e9bbc306be9f58af1b4be92b359d23 (patch)
treeae1ac810501bacae10209b8faa94595fc10c3884
parentd823ab68fbb0fa504a2490bd499ac921bdf497d8 (diff)
parentdfd8645ea1bd91277f841e74c33e1f4dbbede808 (diff)
Merge branch 'vxlan_rco'
Tom Herbert says: ==================== net: Remote checksum offload for VXLAN This patch set adds support for remote checksum offload in VXLAN. The remote checksum offload is generalized by creating a common function (remcsum_adjust) that does the work of modifying the checksum in remote checksum offload. This function can be called from normal or GRO path. GUE was modified to use this function. To support RCO is VXLAN we use the 9th bit in the reserved flags to indicated remote checksum offload. The start and offset values are encoded n a compressed form in the low order (reserved) byte of the vni field. Remote checksum offload is described in https://tools.ietf.org/html/draft-herbert-remotecsumoffload-01 Changes in v2: - Add udp_offload_callbacks which has GRO functions that take a udp_offload pointer argument. This argument can be used to retrieve a per port structure of the encapsulation for use in gro processing (mostly by doing container_of on the structure). - Use the 10th bit in VXLAN flags for RCO which does not seem to conflict with other proposals at this time (ie. VXLAN-GPE and VXLAN-GPB) - Require that RCO must be explicitly enabled on the receiver as well as the sender. Tested by running 200 TCP_STREAM connections with VXLAN (over IPv4). With UDP checksums and Remote Checksum Offload IPv4 Client 11.84% CPU utilization Server 12.96% CPU utilization 9197 Mbps IPv6 Client 12.46% CPU utilization Server 14.48% CPU utilization 8963 Mbps With UDP checksums, no remote checksum offload IPv4 Client 15.67% CPU utilization Server 14.83% CPU utilization 9094 Mbps IPv6 Client 16.21% CPU utilization Server 14.32% CPU utilization 9058 Mbps No UDP checksums IPv4 Client 15.03% CPU utilization Server 23.09% CPU utilization 9089 Mbps IPv6 Client 16.18% CPU utilization Server 26.57% CPU utilization 8954 Mbps ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/vxlan.c198
-rw-r--r--include/linux/netdevice.h15
-rw-r--r--include/net/vxlan.h11
-rw-r--r--include/uapi/linux/if_link.h2
-rw-r--r--net/ipv4/fou.c12
-rw-r--r--net/ipv4/geneve.c6
-rw-r--r--net/ipv4/udp_offload.c7
7 files changed, 233 insertions, 18 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 985359dd6033..99df0d76157c 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -539,12 +539,57 @@ static int vxlan_fdb_append(struct vxlan_fdb *f,
539 return 1; 539 return 1;
540} 540}
541 541
542static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff *skb) 542static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb,
543 unsigned int off,
544 struct vxlanhdr *vh, size_t hdrlen,
545 u32 data)
546{
547 size_t start, offset, plen;
548 __wsum delta;
549
550 if (skb->remcsum_offload)
551 return vh;
552
553 if (!NAPI_GRO_CB(skb)->csum_valid)
554 return NULL;
555
556 start = (data & VXLAN_RCO_MASK) << VXLAN_RCO_SHIFT;
557 offset = start + ((data & VXLAN_RCO_UDP) ?
558 offsetof(struct udphdr, check) :
559 offsetof(struct tcphdr, check));
560
561 plen = hdrlen + offset + sizeof(u16);
562
563 /* Pull checksum that will be written */
564 if (skb_gro_header_hard(skb, off + plen)) {
565 vh = skb_gro_header_slow(skb, off + plen, off);
566 if (!vh)
567 return NULL;
568 }
569
570 delta = remcsum_adjust((void *)vh + hdrlen,
571 NAPI_GRO_CB(skb)->csum, start, offset);
572
573 /* Adjust skb->csum since we changed the packet */
574 skb->csum = csum_add(skb->csum, delta);
575 NAPI_GRO_CB(skb)->csum = csum_add(NAPI_GRO_CB(skb)->csum, delta);
576
577 skb->remcsum_offload = 1;
578
579 return vh;
580}
581
582static struct sk_buff **vxlan_gro_receive(struct sk_buff **head,
583 struct sk_buff *skb,
584 struct udp_offload *uoff)
543{ 585{
544 struct sk_buff *p, **pp = NULL; 586 struct sk_buff *p, **pp = NULL;
545 struct vxlanhdr *vh, *vh2; 587 struct vxlanhdr *vh, *vh2;
546 unsigned int hlen, off_vx; 588 unsigned int hlen, off_vx;
547 int flush = 1; 589 int flush = 1;
590 struct vxlan_sock *vs = container_of(uoff, struct vxlan_sock,
591 udp_offloads);
592 u32 flags;
548 593
549 off_vx = skb_gro_offset(skb); 594 off_vx = skb_gro_offset(skb);
550 hlen = off_vx + sizeof(*vh); 595 hlen = off_vx + sizeof(*vh);
@@ -555,6 +600,19 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff
555 goto out; 600 goto out;
556 } 601 }
557 602
603 skb_gro_pull(skb, sizeof(struct vxlanhdr)); /* pull vxlan header */
604 skb_gro_postpull_rcsum(skb, vh, sizeof(struct vxlanhdr));
605
606 flags = ntohl(vh->vx_flags);
607
608 if ((flags & VXLAN_HF_RCO) && (vs->flags & VXLAN_F_REMCSUM_RX)) {
609 vh = vxlan_gro_remcsum(skb, off_vx, vh, sizeof(struct vxlanhdr),
610 ntohl(vh->vx_vni));
611
612 if (!vh)
613 goto out;
614 }
615
558 flush = 0; 616 flush = 0;
559 617
560 for (p = *head; p; p = p->next) { 618 for (p = *head; p; p = p->next) {
@@ -568,8 +626,6 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff
568 } 626 }
569 } 627 }
570 628
571 skb_gro_pull(skb, sizeof(struct vxlanhdr));
572 skb_gro_postpull_rcsum(skb, vh, sizeof(struct vxlanhdr));
573 pp = eth_gro_receive(head, skb); 629 pp = eth_gro_receive(head, skb);
574 630
575out: 631out:
@@ -578,7 +634,8 @@ out:
578 return pp; 634 return pp;
579} 635}
580 636
581static int vxlan_gro_complete(struct sk_buff *skb, int nhoff) 637static int vxlan_gro_complete(struct sk_buff *skb, int nhoff,
638 struct udp_offload *uoff)
582{ 639{
583 udp_tunnel_gro_complete(skb, nhoff); 640 udp_tunnel_gro_complete(skb, nhoff);
584 641
@@ -1084,6 +1141,42 @@ static void vxlan_igmp_leave(struct work_struct *work)
1084 dev_put(vxlan->dev); 1141 dev_put(vxlan->dev);
1085} 1142}
1086 1143
1144static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh,
1145 size_t hdrlen, u32 data)
1146{
1147 size_t start, offset, plen;
1148 __wsum delta;
1149
1150 if (skb->remcsum_offload) {
1151 /* Already processed in GRO path */
1152 skb->remcsum_offload = 0;
1153 return vh;
1154 }
1155
1156 start = (data & VXLAN_RCO_MASK) << VXLAN_RCO_SHIFT;
1157 offset = start + ((data & VXLAN_RCO_UDP) ?
1158 offsetof(struct udphdr, check) :
1159 offsetof(struct tcphdr, check));
1160
1161 plen = hdrlen + offset + sizeof(u16);
1162
1163 if (!pskb_may_pull(skb, plen))
1164 return NULL;
1165
1166 vh = (struct vxlanhdr *)(udp_hdr(skb) + 1);
1167
1168 if (unlikely(skb->ip_summed != CHECKSUM_COMPLETE))
1169 __skb_checksum_complete(skb);
1170
1171 delta = remcsum_adjust((void *)vh + hdrlen,
1172 skb->csum, start, offset);
1173
1174 /* Adjust skb->csum since we changed the packet */
1175 skb->csum = csum_add(skb->csum, delta);
1176
1177 return vh;
1178}
1179
1087/* Callback from net/ipv4/udp.c to receive packets */ 1180/* Callback from net/ipv4/udp.c to receive packets */
1088static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) 1181static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
1089{ 1182{
@@ -1108,12 +1201,22 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
1108 1201
1109 if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB))) 1202 if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB)))
1110 goto drop; 1203 goto drop;
1204 vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1);
1111 1205
1112 vs = rcu_dereference_sk_user_data(sk); 1206 vs = rcu_dereference_sk_user_data(sk);
1113 if (!vs) 1207 if (!vs)
1114 goto drop; 1208 goto drop;
1115 1209
1116 if (flags || (vni & 0xff)) { 1210 if ((flags & VXLAN_HF_RCO) && (vs->flags & VXLAN_F_REMCSUM_RX)) {
1211 vxh = vxlan_remcsum(skb, vxh, sizeof(struct vxlanhdr), vni);
1212 if (!vxh)
1213 goto drop;
1214
1215 flags &= ~VXLAN_HF_RCO;
1216 vni &= VXLAN_VID_MASK;
1217 }
1218
1219 if (flags || (vni & ~VXLAN_VID_MASK)) {
1117 /* If there are any unprocessed flags remaining treat 1220 /* If there are any unprocessed flags remaining treat
1118 * this as a malformed packet. This behavior diverges from 1221 * this as a malformed packet. This behavior diverges from
1119 * VXLAN RFC (RFC7348) which stipulates that bits in reserved 1222 * VXLAN RFC (RFC7348) which stipulates that bits in reserved
@@ -1550,8 +1653,23 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,
1550 int min_headroom; 1653 int min_headroom;
1551 int err; 1654 int err;
1552 bool udp_sum = !udp_get_no_check6_tx(vs->sock->sk); 1655 bool udp_sum = !udp_get_no_check6_tx(vs->sock->sk);
1656 int type = udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
1657 u16 hdrlen = sizeof(struct vxlanhdr);
1658
1659 if ((vs->flags & VXLAN_F_REMCSUM_TX) &&
1660 skb->ip_summed == CHECKSUM_PARTIAL) {
1661 int csum_start = skb_checksum_start_offset(skb);
1662
1663 if (csum_start <= VXLAN_MAX_REMCSUM_START &&
1664 !(csum_start & VXLAN_RCO_SHIFT_MASK) &&
1665 (skb->csum_offset == offsetof(struct udphdr, check) ||
1666 skb->csum_offset == offsetof(struct tcphdr, check))) {
1667 udp_sum = false;
1668 type |= SKB_GSO_TUNNEL_REMCSUM;
1669 }
1670 }
1553 1671
1554 skb = udp_tunnel_handle_offloads(skb, udp_sum); 1672 skb = iptunnel_handle_offloads(skb, udp_sum, type);
1555 if (IS_ERR(skb)) { 1673 if (IS_ERR(skb)) {
1556 err = -EINVAL; 1674 err = -EINVAL;
1557 goto err; 1675 goto err;
@@ -1580,6 +1698,22 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,
1580 vxh->vx_flags = htonl(VXLAN_HF_VNI); 1698 vxh->vx_flags = htonl(VXLAN_HF_VNI);
1581 vxh->vx_vni = vni; 1699 vxh->vx_vni = vni;
1582 1700
1701 if (type & SKB_GSO_TUNNEL_REMCSUM) {
1702 u32 data = (skb_checksum_start_offset(skb) - hdrlen) >>
1703 VXLAN_RCO_SHIFT;
1704
1705 if (skb->csum_offset == offsetof(struct udphdr, check))
1706 data |= VXLAN_RCO_UDP;
1707
1708 vxh->vx_vni |= htonl(data);
1709 vxh->vx_flags |= htonl(VXLAN_HF_RCO);
1710
1711 if (!skb_is_gso(skb)) {
1712 skb->ip_summed = CHECKSUM_NONE;
1713 skb->encapsulation = 0;
1714 }
1715 }
1716
1583 skb_set_inner_protocol(skb, htons(ETH_P_TEB)); 1717 skb_set_inner_protocol(skb, htons(ETH_P_TEB));
1584 1718
1585 udp_tunnel6_xmit_skb(vs->sock, dst, skb, dev, saddr, daddr, prio, 1719 udp_tunnel6_xmit_skb(vs->sock, dst, skb, dev, saddr, daddr, prio,
@@ -1600,8 +1734,23 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
1600 int min_headroom; 1734 int min_headroom;
1601 int err; 1735 int err;
1602 bool udp_sum = !vs->sock->sk->sk_no_check_tx; 1736 bool udp_sum = !vs->sock->sk->sk_no_check_tx;
1737 int type = udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
1738 u16 hdrlen = sizeof(struct vxlanhdr);
1739
1740 if ((vs->flags & VXLAN_F_REMCSUM_TX) &&
1741 skb->ip_summed == CHECKSUM_PARTIAL) {
1742 int csum_start = skb_checksum_start_offset(skb);
1743
1744 if (csum_start <= VXLAN_MAX_REMCSUM_START &&
1745 !(csum_start & VXLAN_RCO_SHIFT_MASK) &&
1746 (skb->csum_offset == offsetof(struct udphdr, check) ||
1747 skb->csum_offset == offsetof(struct tcphdr, check))) {
1748 udp_sum = false;
1749 type |= SKB_GSO_TUNNEL_REMCSUM;
1750 }
1751 }
1603 1752
1604 skb = udp_tunnel_handle_offloads(skb, udp_sum); 1753 skb = iptunnel_handle_offloads(skb, udp_sum, type);
1605 if (IS_ERR(skb)) 1754 if (IS_ERR(skb))
1606 return PTR_ERR(skb); 1755 return PTR_ERR(skb);
1607 1756
@@ -1624,6 +1773,22 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
1624 vxh->vx_flags = htonl(VXLAN_HF_VNI); 1773 vxh->vx_flags = htonl(VXLAN_HF_VNI);
1625 vxh->vx_vni = vni; 1774 vxh->vx_vni = vni;
1626 1775
1776 if (type & SKB_GSO_TUNNEL_REMCSUM) {
1777 u32 data = (skb_checksum_start_offset(skb) - hdrlen) >>
1778 VXLAN_RCO_SHIFT;
1779
1780 if (skb->csum_offset == offsetof(struct udphdr, check))
1781 data |= VXLAN_RCO_UDP;
1782
1783 vxh->vx_vni |= htonl(data);
1784 vxh->vx_flags |= htonl(VXLAN_HF_RCO);
1785
1786 if (!skb_is_gso(skb)) {
1787 skb->ip_summed = CHECKSUM_NONE;
1788 skb->encapsulation = 0;
1789 }
1790 }
1791
1627 skb_set_inner_protocol(skb, htons(ETH_P_TEB)); 1792 skb_set_inner_protocol(skb, htons(ETH_P_TEB));
1628 1793
1629 return udp_tunnel_xmit_skb(vs->sock, rt, skb, src, dst, tos, 1794 return udp_tunnel_xmit_skb(vs->sock, rt, skb, src, dst, tos,
@@ -2215,6 +2380,8 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = {
2215 [IFLA_VXLAN_UDP_CSUM] = { .type = NLA_U8 }, 2380 [IFLA_VXLAN_UDP_CSUM] = { .type = NLA_U8 },
2216 [IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 }, 2381 [IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 },
2217 [IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 }, 2382 [IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 },
2383 [IFLA_VXLAN_REMCSUM_TX] = { .type = NLA_U8 },
2384 [IFLA_VXLAN_REMCSUM_RX] = { .type = NLA_U8 },
2218}; 2385};
2219 2386
2220static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[]) 2387static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[])
@@ -2336,6 +2503,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
2336 atomic_set(&vs->refcnt, 1); 2503 atomic_set(&vs->refcnt, 1);
2337 vs->rcv = rcv; 2504 vs->rcv = rcv;
2338 vs->data = data; 2505 vs->data = data;
2506 vs->flags = flags;
2339 2507
2340 /* Initialize the vxlan udp offloads structure */ 2508 /* Initialize the vxlan udp offloads structure */
2341 vs->udp_offloads.port = port; 2509 vs->udp_offloads.port = port;
@@ -2530,6 +2698,14 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
2530 nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_RX])) 2698 nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]))
2531 vxlan->flags |= VXLAN_F_UDP_ZERO_CSUM6_RX; 2699 vxlan->flags |= VXLAN_F_UDP_ZERO_CSUM6_RX;
2532 2700
2701 if (data[IFLA_VXLAN_REMCSUM_TX] &&
2702 nla_get_u8(data[IFLA_VXLAN_REMCSUM_TX]))
2703 vxlan->flags |= VXLAN_F_REMCSUM_TX;
2704
2705 if (data[IFLA_VXLAN_REMCSUM_RX] &&
2706 nla_get_u8(data[IFLA_VXLAN_REMCSUM_RX]))
2707 vxlan->flags |= VXLAN_F_REMCSUM_RX;
2708
2533 if (vxlan_find_vni(net, vni, use_ipv6 ? AF_INET6 : AF_INET, 2709 if (vxlan_find_vni(net, vni, use_ipv6 ? AF_INET6 : AF_INET,
2534 vxlan->dst_port)) { 2710 vxlan->dst_port)) {
2535 pr_info("duplicate VNI %u\n", vni); 2711 pr_info("duplicate VNI %u\n", vni);
@@ -2598,6 +2774,8 @@ static size_t vxlan_get_size(const struct net_device *dev)
2598 nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_CSUM */ 2774 nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_CSUM */
2599 nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_TX */ 2775 nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_TX */
2600 nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_RX */ 2776 nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_RX */
2777 nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_TX */
2778 nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_RX */
2601 0; 2779 0;
2602} 2780}
2603 2781
@@ -2663,7 +2841,11 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
2663 nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, 2841 nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
2664 !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_TX)) || 2842 !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_TX)) ||
2665 nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, 2843 nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
2666 !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_RX))) 2844 !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) ||
2845 nla_put_u8(skb, IFLA_VXLAN_REMCSUM_TX,
2846 !!(vxlan->flags & VXLAN_F_REMCSUM_TX)) ||
2847 nla_put_u8(skb, IFLA_VXLAN_REMCSUM_RX,
2848 !!(vxlan->flags & VXLAN_F_REMCSUM_RX)))
2667 goto nla_put_failure; 2849 goto nla_put_failure;
2668 2850
2669 if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports)) 2851 if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports))
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 679e6e90aa4c..47921c291dd6 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1969,7 +1969,7 @@ struct offload_callbacks {
1969 struct sk_buff *(*gso_segment)(struct sk_buff *skb, 1969 struct sk_buff *(*gso_segment)(struct sk_buff *skb,
1970 netdev_features_t features); 1970 netdev_features_t features);
1971 struct sk_buff **(*gro_receive)(struct sk_buff **head, 1971 struct sk_buff **(*gro_receive)(struct sk_buff **head,
1972 struct sk_buff *skb); 1972 struct sk_buff *skb);
1973 int (*gro_complete)(struct sk_buff *skb, int nhoff); 1973 int (*gro_complete)(struct sk_buff *skb, int nhoff);
1974}; 1974};
1975 1975
@@ -1979,10 +1979,21 @@ struct packet_offload {
1979 struct list_head list; 1979 struct list_head list;
1980}; 1980};
1981 1981
1982struct udp_offload;
1983
1984struct udp_offload_callbacks {
1985 struct sk_buff **(*gro_receive)(struct sk_buff **head,
1986 struct sk_buff *skb,
1987 struct udp_offload *uoff);
1988 int (*gro_complete)(struct sk_buff *skb,
1989 int nhoff,
1990 struct udp_offload *uoff);
1991};
1992
1982struct udp_offload { 1993struct udp_offload {
1983 __be16 port; 1994 __be16 port;
1984 u8 ipproto; 1995 u8 ipproto;
1985 struct offload_callbacks callbacks; 1996 struct udp_offload_callbacks callbacks;
1986}; 1997};
1987 1998
1988/* often modified stats are per cpu, other are shared (netdev->stats) */ 1999/* often modified stats are per cpu, other are shared (netdev->stats) */
diff --git a/include/net/vxlan.h b/include/net/vxlan.h
index a0d80736224f..0a7443b49133 100644
--- a/include/net/vxlan.h
+++ b/include/net/vxlan.h
@@ -19,6 +19,14 @@ struct vxlanhdr {
19 19
20/* VXLAN header flags. */ 20/* VXLAN header flags. */
21#define VXLAN_HF_VNI 0x08000000 21#define VXLAN_HF_VNI 0x08000000
22#define VXLAN_HF_RCO 0x00200000
23
24/* Remote checksum offload header option */
25#define VXLAN_RCO_MASK 0x7f /* Last byte of vni field */
26#define VXLAN_RCO_UDP 0x80 /* Indicate UDP RCO (TCP when not set *) */
27#define VXLAN_RCO_SHIFT 1 /* Left shift of start */
28#define VXLAN_RCO_SHIFT_MASK ((1 << VXLAN_RCO_SHIFT) - 1)
29#define VXLAN_MAX_REMCSUM_START (VXLAN_RCO_MASK << VXLAN_RCO_SHIFT)
22 30
23#define VXLAN_N_VID (1u << 24) 31#define VXLAN_N_VID (1u << 24)
24#define VXLAN_VID_MASK (VXLAN_N_VID - 1) 32#define VXLAN_VID_MASK (VXLAN_N_VID - 1)
@@ -38,6 +46,7 @@ struct vxlan_sock {
38 struct hlist_head vni_list[VNI_HASH_SIZE]; 46 struct hlist_head vni_list[VNI_HASH_SIZE];
39 atomic_t refcnt; 47 atomic_t refcnt;
40 struct udp_offload udp_offloads; 48 struct udp_offload udp_offloads;
49 u32 flags;
41}; 50};
42 51
43#define VXLAN_F_LEARN 0x01 52#define VXLAN_F_LEARN 0x01
@@ -49,6 +58,8 @@ struct vxlan_sock {
49#define VXLAN_F_UDP_CSUM 0x40 58#define VXLAN_F_UDP_CSUM 0x40
50#define VXLAN_F_UDP_ZERO_CSUM6_TX 0x80 59#define VXLAN_F_UDP_ZERO_CSUM6_TX 0x80
51#define VXLAN_F_UDP_ZERO_CSUM6_RX 0x100 60#define VXLAN_F_UDP_ZERO_CSUM6_RX 0x100
61#define VXLAN_F_REMCSUM_TX 0x200
62#define VXLAN_F_REMCSUM_RX 0x400
52 63
53struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, 64struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
54 vxlan_rcv_t *rcv, void *data, 65 vxlan_rcv_t *rcv, void *data,
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index f7d0d2d7173a..b2723f65846f 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -370,6 +370,8 @@ enum {
370 IFLA_VXLAN_UDP_CSUM, 370 IFLA_VXLAN_UDP_CSUM,
371 IFLA_VXLAN_UDP_ZERO_CSUM6_TX, 371 IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
372 IFLA_VXLAN_UDP_ZERO_CSUM6_RX, 372 IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
373 IFLA_VXLAN_REMCSUM_TX,
374 IFLA_VXLAN_REMCSUM_RX,
373 __IFLA_VXLAN_MAX 375 __IFLA_VXLAN_MAX
374}; 376};
375#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) 377#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
index 2197c36f722f..3bc0cf07661c 100644
--- a/net/ipv4/fou.c
+++ b/net/ipv4/fou.c
@@ -174,7 +174,8 @@ drop:
174} 174}
175 175
176static struct sk_buff **fou_gro_receive(struct sk_buff **head, 176static struct sk_buff **fou_gro_receive(struct sk_buff **head,
177 struct sk_buff *skb) 177 struct sk_buff *skb,
178 struct udp_offload *uoff)
178{ 179{
179 const struct net_offload *ops; 180 const struct net_offload *ops;
180 struct sk_buff **pp = NULL; 181 struct sk_buff **pp = NULL;
@@ -195,7 +196,8 @@ out_unlock:
195 return pp; 196 return pp;
196} 197}
197 198
198static int fou_gro_complete(struct sk_buff *skb, int nhoff) 199static int fou_gro_complete(struct sk_buff *skb, int nhoff,
200 struct udp_offload *uoff)
199{ 201{
200 const struct net_offload *ops; 202 const struct net_offload *ops;
201 u8 proto = NAPI_GRO_CB(skb)->proto; 203 u8 proto = NAPI_GRO_CB(skb)->proto;
@@ -254,7 +256,8 @@ static struct guehdr *gue_gro_remcsum(struct sk_buff *skb, unsigned int off,
254} 256}
255 257
256static struct sk_buff **gue_gro_receive(struct sk_buff **head, 258static struct sk_buff **gue_gro_receive(struct sk_buff **head,
257 struct sk_buff *skb) 259 struct sk_buff *skb,
260 struct udp_offload *uoff)
258{ 261{
259 const struct net_offload **offloads; 262 const struct net_offload **offloads;
260 const struct net_offload *ops; 263 const struct net_offload *ops;
@@ -360,7 +363,8 @@ out:
360 return pp; 363 return pp;
361} 364}
362 365
363static int gue_gro_complete(struct sk_buff *skb, int nhoff) 366static int gue_gro_complete(struct sk_buff *skb, int nhoff,
367 struct udp_offload *uoff)
364{ 368{
365 const struct net_offload **offloads; 369 const struct net_offload **offloads;
366 struct guehdr *guehdr = (struct guehdr *)(skb->data + nhoff); 370 struct guehdr *guehdr = (struct guehdr *)(skb->data + nhoff);
diff --git a/net/ipv4/geneve.c b/net/ipv4/geneve.c
index 23744c7a9718..9568594ca2f1 100644
--- a/net/ipv4/geneve.c
+++ b/net/ipv4/geneve.c
@@ -147,7 +147,8 @@ static int geneve_hlen(struct genevehdr *gh)
147} 147}
148 148
149static struct sk_buff **geneve_gro_receive(struct sk_buff **head, 149static struct sk_buff **geneve_gro_receive(struct sk_buff **head,
150 struct sk_buff *skb) 150 struct sk_buff *skb,
151 struct udp_offload *uoff)
151{ 152{
152 struct sk_buff *p, **pp = NULL; 153 struct sk_buff *p, **pp = NULL;
153 struct genevehdr *gh, *gh2; 154 struct genevehdr *gh, *gh2;
@@ -211,7 +212,8 @@ out:
211 return pp; 212 return pp;
212} 213}
213 214
214static int geneve_gro_complete(struct sk_buff *skb, int nhoff) 215static int geneve_gro_complete(struct sk_buff *skb, int nhoff,
216 struct udp_offload *uoff)
215{ 217{
216 struct genevehdr *gh; 218 struct genevehdr *gh;
217 struct packet_offload *ptype; 219 struct packet_offload *ptype;
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index d3e537ef6b7f..d10f6f4ead27 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -339,7 +339,8 @@ unflush:
339 skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */ 339 skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */
340 skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr)); 340 skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr));
341 NAPI_GRO_CB(skb)->proto = uo_priv->offload->ipproto; 341 NAPI_GRO_CB(skb)->proto = uo_priv->offload->ipproto;
342 pp = uo_priv->offload->callbacks.gro_receive(head, skb); 342 pp = uo_priv->offload->callbacks.gro_receive(head, skb,
343 uo_priv->offload);
343 344
344out_unlock: 345out_unlock:
345 rcu_read_unlock(); 346 rcu_read_unlock();
@@ -395,7 +396,9 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff)
395 396
396 if (uo_priv != NULL) { 397 if (uo_priv != NULL) {
397 NAPI_GRO_CB(skb)->proto = uo_priv->offload->ipproto; 398 NAPI_GRO_CB(skb)->proto = uo_priv->offload->ipproto;
398 err = uo_priv->offload->callbacks.gro_complete(skb, nhoff + sizeof(struct udphdr)); 399 err = uo_priv->offload->callbacks.gro_complete(skb,
400 nhoff + sizeof(struct udphdr),
401 uo_priv->offload);
399 } 402 }
400 403
401 rcu_read_unlock(); 404 rcu_read_unlock();