mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-19 22:49:55 +07:00
Merge branch 'AF_PACKET-transport_offset-fix'
Maxim Mikityanskiy says: ==================== AF_PACKET transport_offset fix This patch series contains the implementation of the RFC that was posted on this mailing list previously: https://www.spinics.net/lists/netdev/msg541709.html It fixes having incorrect skb->transport_header values in cases when dissect fails. Having correct values set by the kernel fixes mlx5 operation and allows to remove some unnecessary code flows in mlx5. v2 changes: - Rebase against the fresh net-next. - Don't return bool from skb_probe_transport_header (and don't rename the function). - WARN_ON_ONCE and error path in case of GSO without the L4 header. ==================== Acked-by: Willem de Bruijn <willemb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
d29d1c4957
@ -148,12 +148,8 @@ static inline int mlx5e_skb_l2_header_offset(struct sk_buff *skb)
|
||||
|
||||
static inline int mlx5e_skb_l3_header_offset(struct sk_buff *skb)
|
||||
{
|
||||
struct flow_keys keys;
|
||||
|
||||
if (skb_transport_header_was_set(skb))
|
||||
return skb_transport_offset(skb);
|
||||
else if (skb_flow_dissect_flow_keys(skb, &keys, 0))
|
||||
return keys.control.thoff;
|
||||
else
|
||||
return mlx5e_skb_l2_header_offset(skb);
|
||||
}
|
||||
@ -172,15 +168,8 @@ static inline u16 mlx5e_calc_min_inline(enum mlx5_inline_modes mode,
|
||||
hlen += VLAN_HLEN;
|
||||
break;
|
||||
case MLX5_INLINE_MODE_IP:
|
||||
/* When transport header is set to zero, it means no transport
|
||||
* header. When transport header is set to 0xff's, it means
|
||||
* transport header wasn't set.
|
||||
*/
|
||||
if (skb_transport_offset(skb)) {
|
||||
hlen = mlx5e_skb_l3_header_offset(skb);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
hlen = mlx5e_skb_l3_header_offset(skb);
|
||||
break;
|
||||
case MLX5_INLINE_MODE_L2:
|
||||
default:
|
||||
hlen = mlx5e_skb_l2_header_offset(skb);
|
||||
|
@ -712,7 +712,7 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
|
||||
goto err_kfree;
|
||||
}
|
||||
|
||||
skb_probe_transport_header(skb, ETH_HLEN);
|
||||
skb_probe_transport_header(skb);
|
||||
|
||||
/* Move network header to the right position for VLAN tagged packets */
|
||||
if ((skb->protocol == htons(ETH_P_8021Q) ||
|
||||
@ -1187,7 +1187,7 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp)
|
||||
tap = rcu_dereference(q->tap);
|
||||
if (tap) {
|
||||
skb->dev = tap->dev;
|
||||
skb_probe_transport_header(skb, ETH_HLEN);
|
||||
skb_probe_transport_header(skb);
|
||||
dev_queue_xmit(skb);
|
||||
} else {
|
||||
kfree_skb(skb);
|
||||
|
@ -1929,7 +1929,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
|
||||
}
|
||||
|
||||
skb_reset_network_header(skb);
|
||||
skb_probe_transport_header(skb, 0);
|
||||
skb_probe_transport_header(skb);
|
||||
|
||||
if (skb_xdp) {
|
||||
struct bpf_prog *xdp_prog;
|
||||
@ -2482,7 +2482,7 @@ static int tun_xdp_one(struct tun_struct *tun,
|
||||
|
||||
skb->protocol = eth_type_trans(skb, tun->dev);
|
||||
skb_reset_network_header(skb);
|
||||
skb_probe_transport_header(skb, 0);
|
||||
skb_probe_transport_header(skb);
|
||||
|
||||
if (skb_xdp) {
|
||||
err = do_xdp_generic(xdp_prog, skb);
|
||||
|
@ -1169,15 +1169,24 @@ static int xenvif_tx_submit(struct xenvif_queue *queue)
|
||||
continue;
|
||||
}
|
||||
|
||||
skb_probe_transport_header(skb, 0);
|
||||
skb_probe_transport_header(skb);
|
||||
|
||||
/* If the packet is GSO then we will have just set up the
|
||||
* transport header offset in checksum_setup so it's now
|
||||
* straightforward to calculate gso_segs.
|
||||
*/
|
||||
if (skb_is_gso(skb)) {
|
||||
int mss = skb_shinfo(skb)->gso_size;
|
||||
int hdrlen = skb_transport_header(skb) -
|
||||
int mss, hdrlen;
|
||||
|
||||
/* GSO implies having the L4 header. */
|
||||
WARN_ON_ONCE(!skb_transport_header_was_set(skb));
|
||||
if (unlikely(!skb_transport_header_was_set(skb))) {
|
||||
kfree_skb(skb);
|
||||
continue;
|
||||
}
|
||||
|
||||
mss = skb_shinfo(skb)->gso_size;
|
||||
hdrlen = skb_transport_header(skb) -
|
||||
skb_mac_header(skb) +
|
||||
tcp_hdrlen(skb);
|
||||
|
||||
|
@ -44,6 +44,7 @@ int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh,
|
||||
__be16 type);
|
||||
void eth_header_cache_update(struct hh_cache *hh, const struct net_device *dev,
|
||||
const unsigned char *haddr);
|
||||
__be16 eth_header_parse_protocol(const struct sk_buff *skb);
|
||||
int eth_prepare_mac_addr_change(struct net_device *dev, void *p);
|
||||
void eth_commit_mac_addr_change(struct net_device *dev, void *p);
|
||||
int eth_mac_addr(struct net_device *dev, void *p);
|
||||
|
@ -274,6 +274,7 @@ struct header_ops {
|
||||
const struct net_device *dev,
|
||||
const unsigned char *haddr);
|
||||
bool (*validate)(const char *ll_header, unsigned int len);
|
||||
__be16 (*parse_protocol)(const struct sk_buff *skb);
|
||||
};
|
||||
|
||||
/* These flag bits are private to the generic network queueing
|
||||
@ -2939,6 +2940,15 @@ static inline int dev_parse_header(const struct sk_buff *skb,
|
||||
return dev->header_ops->parse(skb, haddr);
|
||||
}
|
||||
|
||||
static inline __be16 dev_parse_header_protocol(const struct sk_buff *skb)
|
||||
{
|
||||
const struct net_device *dev = skb->dev;
|
||||
|
||||
if (!dev->header_ops || !dev->header_ops->parse_protocol)
|
||||
return 0;
|
||||
return dev->header_ops->parse_protocol(skb);
|
||||
}
|
||||
|
||||
/* ll_header must have at least hard_header_len allocated */
|
||||
static inline bool dev_validate_header(const struct net_device *dev,
|
||||
char *ll_header, int len)
|
||||
|
@ -2429,8 +2429,7 @@ static inline void skb_pop_mac_header(struct sk_buff *skb)
|
||||
skb->mac_header = skb->network_header;
|
||||
}
|
||||
|
||||
static inline void skb_probe_transport_header(struct sk_buff *skb,
|
||||
const int offset_hint)
|
||||
static inline void skb_probe_transport_header(struct sk_buff *skb)
|
||||
{
|
||||
struct flow_keys_basic keys;
|
||||
|
||||
@ -2439,8 +2438,6 @@ static inline void skb_probe_transport_header(struct sk_buff *skb,
|
||||
|
||||
if (skb_flow_dissect_flow_keys_basic(skb, &keys, NULL, 0, 0, 0, 0))
|
||||
skb_set_transport_header(skb, keys.control.thoff);
|
||||
else if (offset_hint >= 0)
|
||||
skb_set_transport_header(skb, offset_hint);
|
||||
}
|
||||
|
||||
static inline void skb_mac_header_rebuild(struct sk_buff *skb)
|
||||
|
@ -62,7 +62,7 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
|
||||
* probe and drop if does not match one of the above types.
|
||||
*/
|
||||
if (gso_type) {
|
||||
skb_probe_transport_header(skb, -1);
|
||||
skb_probe_transport_header(skb);
|
||||
if (!skb_transport_header_was_set(skb))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -264,6 +264,18 @@ void eth_header_cache_update(struct hh_cache *hh,
|
||||
}
|
||||
EXPORT_SYMBOL(eth_header_cache_update);
|
||||
|
||||
/**
|
||||
* eth_header_parser_protocol - extract protocol from L2 header
|
||||
* @skb: packet to extract protocol from
|
||||
*/
|
||||
__be16 eth_header_parse_protocol(const struct sk_buff *skb)
|
||||
{
|
||||
const struct ethhdr *eth = eth_hdr(skb);
|
||||
|
||||
return eth->h_proto;
|
||||
}
|
||||
EXPORT_SYMBOL(eth_header_parse_protocol);
|
||||
|
||||
/**
|
||||
* eth_prepare_mac_addr_change - prepare for mac change
|
||||
* @dev: network device
|
||||
@ -346,6 +358,7 @@ const struct header_ops eth_header_ops ____cacheline_aligned = {
|
||||
.parse = eth_header_parse,
|
||||
.cache = eth_header_cache,
|
||||
.cache_update = eth_header_cache_update,
|
||||
.parse_protocol = eth_header_parse_protocol,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1850,6 +1850,15 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void packet_parse_headers(struct sk_buff *skb, struct socket *sock)
|
||||
{
|
||||
if (!skb->protocol && sock->type == SOCK_RAW) {
|
||||
skb_reset_mac_header(skb);
|
||||
skb->protocol = dev_parse_header_protocol(skb);
|
||||
}
|
||||
|
||||
skb_probe_transport_header(skb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a raw packet to a device layer. This bypasses all the other
|
||||
@ -1970,7 +1979,7 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg,
|
||||
if (unlikely(extra_len == 4))
|
||||
skb->no_fcs = 1;
|
||||
|
||||
skb_probe_transport_header(skb, 0);
|
||||
packet_parse_headers(skb, sock);
|
||||
|
||||
dev_queue_xmit(skb);
|
||||
rcu_read_unlock();
|
||||
@ -2404,15 +2413,6 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
|
||||
sock_wfree(skb);
|
||||
}
|
||||
|
||||
static void tpacket_set_protocol(const struct net_device *dev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
if (dev->type == ARPHRD_ETHER) {
|
||||
skb_reset_mac_header(skb);
|
||||
skb->protocol = eth_hdr(skb)->h_proto;
|
||||
}
|
||||
}
|
||||
|
||||
static int __packet_snd_vnet_parse(struct virtio_net_hdr *vnet_hdr, size_t len)
|
||||
{
|
||||
if ((vnet_hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
|
||||
@ -2483,8 +2483,6 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
|
||||
return err;
|
||||
if (!dev_validate_header(dev, skb->data, hdrlen))
|
||||
return -EINVAL;
|
||||
if (!skb->protocol)
|
||||
tpacket_set_protocol(dev, skb);
|
||||
|
||||
data += hdrlen;
|
||||
to_write -= hdrlen;
|
||||
@ -2519,7 +2517,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
|
||||
len = ((to_write > len_max) ? len_max : to_write);
|
||||
}
|
||||
|
||||
skb_probe_transport_header(skb, 0);
|
||||
packet_parse_headers(skb, sock);
|
||||
|
||||
return tp_len;
|
||||
}
|
||||
@ -2925,7 +2923,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
|
||||
virtio_net_hdr_set_proto(skb, &vnet_hdr);
|
||||
}
|
||||
|
||||
skb_probe_transport_header(skb, reserve);
|
||||
packet_parse_headers(skb, sock);
|
||||
|
||||
if (unlikely(extra_len == 4))
|
||||
skb->no_fcs = 1;
|
||||
|
Loading…
Reference in New Issue
Block a user