diff options
-rw-r--r-- | drivers/net/vxlan.c | 137 |
1 files changed, 26 insertions, 111 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index fe3fd4808f4d..65f52472a52c 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c | |||
@@ -1684,19 +1684,14 @@ static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, u32 vxflags, | |||
1684 | gbp->policy_id = htons(md->gbp & VXLAN_GBP_ID_MASK); | 1684 | gbp->policy_id = htons(md->gbp & VXLAN_GBP_ID_MASK); |
1685 | } | 1685 | } |
1686 | 1686 | ||
1687 | #if IS_ENABLED(CONFIG_IPV6) | 1687 | static int vxlan_build_skb(struct sk_buff *skb, struct dst_entry *dst, |
1688 | static int vxlan6_xmit_skb(struct dst_entry *dst, struct sock *sk, | 1688 | int iphdr_len, __be32 vni, |
1689 | struct sk_buff *skb, | 1689 | struct vxlan_metadata *md, u32 vxflags, |
1690 | struct net_device *dev, struct in6_addr *saddr, | ||
1691 | struct in6_addr *daddr, __u8 prio, __u8 ttl, | ||
1692 | __be16 src_port, __be16 dst_port, __be32 vni, | ||
1693 | struct vxlan_metadata *md, bool xnet, u32 vxflags, | ||
1694 | bool udp_sum) | 1690 | bool udp_sum) |
1695 | { | 1691 | { |
1696 | struct vxlanhdr *vxh; | 1692 | struct vxlanhdr *vxh; |
1697 | int min_headroom; | 1693 | int min_headroom; |
1698 | int err; | 1694 | int err; |
1699 | bool nocheck = !udp_sum; | ||
1700 | int type = udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; | 1695 | int type = udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; |
1701 | u16 hdrlen = sizeof(struct vxlanhdr); | 1696 | u16 hdrlen = sizeof(struct vxlanhdr); |
1702 | 1697 | ||
@@ -1713,93 +1708,8 @@ static int vxlan6_xmit_skb(struct dst_entry *dst, struct sock *sk, | |||
1713 | } | 1708 | } |
1714 | } | 1709 | } |
1715 | 1710 | ||
1716 | skb_scrub_packet(skb, xnet); | ||
1717 | |||
1718 | min_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len | 1711 | min_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len |
1719 | + VXLAN_HLEN + sizeof(struct ipv6hdr) | 1712 | + VXLAN_HLEN + iphdr_len |
1720 | + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0); | ||
1721 | |||
1722 | /* Need space for new headers (invalidates iph ptr) */ | ||
1723 | err = skb_cow_head(skb, min_headroom); | ||
1724 | if (unlikely(err)) { | ||
1725 | kfree_skb(skb); | ||
1726 | goto err; | ||
1727 | } | ||
1728 | |||
1729 | skb = vlan_hwaccel_push_inside(skb); | ||
1730 | if (WARN_ON(!skb)) { | ||
1731 | err = -ENOMEM; | ||
1732 | goto err; | ||
1733 | } | ||
1734 | |||
1735 | skb = iptunnel_handle_offloads(skb, udp_sum, type); | ||
1736 | if (IS_ERR(skb)) { | ||
1737 | err = -EINVAL; | ||
1738 | goto err; | ||
1739 | } | ||
1740 | |||
1741 | vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); | ||
1742 | vxh->vx_flags = htonl(VXLAN_HF_VNI); | ||
1743 | vxh->vx_vni = vni; | ||
1744 | |||
1745 | if (type & SKB_GSO_TUNNEL_REMCSUM) { | ||
1746 | u32 data = (skb_checksum_start_offset(skb) - hdrlen) >> | ||
1747 | VXLAN_RCO_SHIFT; | ||
1748 | |||
1749 | if (skb->csum_offset == offsetof(struct udphdr, check)) | ||
1750 | data |= VXLAN_RCO_UDP; | ||
1751 | |||
1752 | vxh->vx_vni |= htonl(data); | ||
1753 | vxh->vx_flags |= htonl(VXLAN_HF_RCO); | ||
1754 | |||
1755 | if (!skb_is_gso(skb)) { | ||
1756 | skb->ip_summed = CHECKSUM_NONE; | ||
1757 | skb->encapsulation = 0; | ||
1758 | } | ||
1759 | } | ||
1760 | |||
1761 | if (vxflags & VXLAN_F_GBP) | ||
1762 | vxlan_build_gbp_hdr(vxh, vxflags, md); | ||
1763 | |||
1764 | skb_set_inner_protocol(skb, htons(ETH_P_TEB)); | ||
1765 | |||
1766 | udp_tunnel6_xmit_skb(dst, sk, skb, dev, saddr, daddr, prio, | ||
1767 | ttl, src_port, dst_port, nocheck); | ||
1768 | return 0; | ||
1769 | err: | ||
1770 | dst_release(dst); | ||
1771 | return err; | ||
1772 | } | ||
1773 | #endif | ||
1774 | |||
1775 | static int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, | ||
1776 | __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, | ||
1777 | __be16 src_port, __be16 dst_port, __be32 vni, | ||
1778 | struct vxlan_metadata *md, bool xnet, u32 vxflags, | ||
1779 | bool udp_sum) | ||
1780 | { | ||
1781 | struct vxlanhdr *vxh; | ||
1782 | int min_headroom; | ||
1783 | int err; | ||
1784 | bool nocheck = !udp_sum; | ||
1785 | int type = udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; | ||
1786 | u16 hdrlen = sizeof(struct vxlanhdr); | ||
1787 | |||
1788 | if ((vxflags & VXLAN_F_REMCSUM_TX) && | ||
1789 | skb->ip_summed == CHECKSUM_PARTIAL) { | ||
1790 | int csum_start = skb_checksum_start_offset(skb); | ||
1791 | |||
1792 | if (csum_start <= VXLAN_MAX_REMCSUM_START && | ||
1793 | !(csum_start & VXLAN_RCO_SHIFT_MASK) && | ||
1794 | (skb->csum_offset == offsetof(struct udphdr, check) || | ||
1795 | skb->csum_offset == offsetof(struct tcphdr, check))) { | ||
1796 | udp_sum = false; | ||
1797 | type |= SKB_GSO_TUNNEL_REMCSUM; | ||
1798 | } | ||
1799 | } | ||
1800 | |||
1801 | min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len | ||
1802 | + VXLAN_HLEN + sizeof(struct iphdr) | ||
1803 | + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0); | 1713 | + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0); |
1804 | 1714 | ||
1805 | /* Need space for new headers (invalidates iph ptr) */ | 1715 | /* Need space for new headers (invalidates iph ptr) */ |
@@ -1841,9 +1751,6 @@ static int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *sk | |||
1841 | vxlan_build_gbp_hdr(vxh, vxflags, md); | 1751 | vxlan_build_gbp_hdr(vxh, vxflags, md); |
1842 | 1752 | ||
1843 | skb_set_inner_protocol(skb, htons(ETH_P_TEB)); | 1753 | skb_set_inner_protocol(skb, htons(ETH_P_TEB)); |
1844 | |||
1845 | udp_tunnel_xmit_skb(rt, sk, skb, src, dst, tos, ttl, df, | ||
1846 | src_port, dst_port, xnet, nocheck); | ||
1847 | return 0; | 1754 | return 0; |
1848 | } | 1755 | } |
1849 | 1756 | ||
@@ -1960,6 +1867,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, | |||
1960 | int err; | 1867 | int err; |
1961 | u32 flags = vxlan->flags; | 1868 | u32 flags = vxlan->flags; |
1962 | bool udp_sum = false; | 1869 | bool udp_sum = false; |
1870 | bool xnet = !net_eq(vxlan->net, dev_net(vxlan->dev)); | ||
1963 | 1871 | ||
1964 | info = skb_tunnel_info(skb); | 1872 | info = skb_tunnel_info(skb); |
1965 | 1873 | ||
@@ -2064,16 +1972,14 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, | |||
2064 | 1972 | ||
2065 | tos = ip_tunnel_ecn_encap(tos, old_iph, skb); | 1973 | tos = ip_tunnel_ecn_encap(tos, old_iph, skb); |
2066 | ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); | 1974 | ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); |
2067 | err = vxlan_xmit_skb(rt, sk, skb, saddr, | 1975 | err = vxlan_build_skb(skb, &rt->dst, sizeof(struct iphdr), |
2068 | dst->sin.sin_addr.s_addr, tos, ttl, df, | 1976 | htonl(vni << 8), md, flags, udp_sum); |
2069 | src_port, dst_port, htonl(vni << 8), md, | 1977 | if (err < 0) |
2070 | !net_eq(vxlan->net, dev_net(vxlan->dev)), | 1978 | goto xmit_tx_error; |
2071 | flags, udp_sum); | 1979 | |
2072 | if (err < 0) { | 1980 | udp_tunnel_xmit_skb(rt, sk, skb, saddr, |
2073 | /* skb is already freed. */ | 1981 | dst->sin.sin_addr.s_addr, tos, ttl, df, |
2074 | skb = NULL; | 1982 | src_port, dst_port, xnet, !udp_sum); |
2075 | goto rt_tx_error; | ||
2076 | } | ||
2077 | #if IS_ENABLED(CONFIG_IPV6) | 1983 | #if IS_ENABLED(CONFIG_IPV6) |
2078 | } else { | 1984 | } else { |
2079 | struct dst_entry *ndst; | 1985 | struct dst_entry *ndst; |
@@ -2122,10 +2028,16 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, | |||
2122 | udp_sum = !(flags & VXLAN_F_UDP_ZERO_CSUM6_TX); | 2028 | udp_sum = !(flags & VXLAN_F_UDP_ZERO_CSUM6_TX); |
2123 | 2029 | ||
2124 | ttl = ttl ? : ip6_dst_hoplimit(ndst); | 2030 | ttl = ttl ? : ip6_dst_hoplimit(ndst); |
2125 | err = vxlan6_xmit_skb(ndst, sk, skb, dev, &saddr, &dst->sin6.sin6_addr, | 2031 | skb_scrub_packet(skb, xnet); |
2126 | 0, ttl, src_port, dst_port, htonl(vni << 8), md, | 2032 | err = vxlan_build_skb(skb, ndst, sizeof(struct ipv6hdr), |
2127 | !net_eq(vxlan->net, dev_net(vxlan->dev)), | 2033 | htonl(vni << 8), md, flags, udp_sum); |
2128 | flags, udp_sum); | 2034 | if (err < 0) { |
2035 | dst_release(ndst); | ||
2036 | return; | ||
2037 | } | ||
2038 | udp_tunnel6_xmit_skb(ndst, sk, skb, dev, | ||
2039 | &saddr, &dst->sin6.sin6_addr, | ||
2040 | 0, ttl, src_port, dst_port, !udp_sum); | ||
2129 | #endif | 2041 | #endif |
2130 | } | 2042 | } |
2131 | 2043 | ||
@@ -2135,6 +2047,9 @@ drop: | |||
2135 | dev->stats.tx_dropped++; | 2047 | dev->stats.tx_dropped++; |
2136 | goto tx_free; | 2048 | goto tx_free; |
2137 | 2049 | ||
2050 | xmit_tx_error: | ||
2051 | /* skb is already freed. */ | ||
2052 | skb = NULL; | ||
2138 | rt_tx_error: | 2053 | rt_tx_error: |
2139 | ip_rt_put(rt); | 2054 | ip_rt_put(rt); |
2140 | tx_error: | 2055 | tx_error: |