net/net_rx_pkt: Use iovec for net_rx_pkt_set_protocols()

igb does not properly ensure the buffer passed to
net_rx_pkt_set_protocols() is contiguous for the entire L2/L3/L4 header.
Allow it to pass scattered data to net_rx_pkt_set_protocols().

Fixes: 3a977deebe ("Intrdocue igb device emulation")
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Sriram Yagnaraman <sriram.yagnaraman@est.tech>
Signed-off-by: Jason Wang <jasowang@redhat.com>
This commit is contained in:
Akihiko Odaki 2023-05-23 11:42:58 +09:00 committed by Jason Wang
parent f0b1df5c45
commit 2f0fa232b8
7 changed files with 34 additions and 30 deletions

View File

@ -1650,7 +1650,7 @@ igb_receive_internal(IGBCore *core, const struct iovec *iov, int iovcnt,
ehdr = PKT_GET_ETH_HDR(filter_buf); ehdr = PKT_GET_ETH_HDR(filter_buf);
net_rx_pkt_set_packet_type(core->rx_pkt, get_eth_packet_type(ehdr)); net_rx_pkt_set_packet_type(core->rx_pkt, get_eth_packet_type(ehdr));
net_rx_pkt_set_protocols(core->rx_pkt, filter_buf, size); net_rx_pkt_set_protocols(core->rx_pkt, iov, iovcnt, iov_ofs);
queues = igb_receive_assign(core, ehdr, size, &rss_info, external_tx); queues = igb_receive_assign(core, ehdr, size, &rss_info, external_tx);
if (!queues) { if (!queues) {

View File

@ -103,7 +103,7 @@ net_rx_pkt_pull_data(struct NetRxPkt *pkt,
iov, iovcnt, ploff, pkt->tot_len); iov, iovcnt, ploff, pkt->tot_len);
} }
eth_get_protocols(pkt->vec, pkt->vec_len, &pkt->hasip4, &pkt->hasip6, eth_get_protocols(pkt->vec, pkt->vec_len, 0, &pkt->hasip4, &pkt->hasip6,
&pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off, &pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off,
&pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info); &pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info);
@ -186,17 +186,13 @@ size_t net_rx_pkt_get_total_len(struct NetRxPkt *pkt)
return pkt->tot_len; return pkt->tot_len;
} }
void net_rx_pkt_set_protocols(struct NetRxPkt *pkt, const void *data, void net_rx_pkt_set_protocols(struct NetRxPkt *pkt,
size_t len) const struct iovec *iov, size_t iovcnt,
size_t iovoff)
{ {
const struct iovec iov = {
.iov_base = (void *)data,
.iov_len = len
};
assert(pkt); assert(pkt);
eth_get_protocols(&iov, 1, &pkt->hasip4, &pkt->hasip6, eth_get_protocols(iov, iovcnt, iovoff, &pkt->hasip4, &pkt->hasip6,
&pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off, &pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off,
&pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info); &pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info);
} }

View File

@ -55,12 +55,14 @@ size_t net_rx_pkt_get_total_len(struct NetRxPkt *pkt);
* parse and set packet analysis results * parse and set packet analysis results
* *
* @pkt: packet * @pkt: packet
* @data: pointer to the data buffer to be parsed * @iov: received data scatter-gather list
* @len: data length * @iovcnt: number of elements in iov
* @iovoff: data start offset in the iov
* *
*/ */
void net_rx_pkt_set_protocols(struct NetRxPkt *pkt, const void *data, void net_rx_pkt_set_protocols(struct NetRxPkt *pkt,
size_t len); const struct iovec *iov, size_t iovcnt,
size_t iovoff);
/** /**
* fetches packet analysis results * fetches packet analysis results

View File

@ -1834,9 +1834,12 @@ static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf,
VIRTIO_NET_HASH_REPORT_UDPv6, VIRTIO_NET_HASH_REPORT_UDPv6,
VIRTIO_NET_HASH_REPORT_UDPv6_EX VIRTIO_NET_HASH_REPORT_UDPv6_EX
}; };
struct iovec iov = {
.iov_base = (void *)buf,
.iov_len = size
};
net_rx_pkt_set_protocols(pkt, buf + n->host_hdr_len, net_rx_pkt_set_protocols(pkt, &iov, 1, n->host_hdr_len);
size - n->host_hdr_len);
net_rx_pkt_get_protocols(pkt, &hasip4, &hasip6, &l4hdr_proto); net_rx_pkt_get_protocols(pkt, &hasip4, &hasip6, &l4hdr_proto);
net_hash_type = virtio_net_get_hash_type(hasip4, hasip6, l4hdr_proto, net_hash_type = virtio_net_get_hash_type(hasip4, hasip6, l4hdr_proto,
n->rss_data.hash_types); n->rss_data.hash_types);

View File

@ -2001,7 +2001,12 @@ vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size)
get_eth_packet_type(PKT_GET_ETH_HDR(buf))); get_eth_packet_type(PKT_GET_ETH_HDR(buf)));
if (vmxnet3_rx_filter_may_indicate(s, buf, size)) { if (vmxnet3_rx_filter_may_indicate(s, buf, size)) {
net_rx_pkt_set_protocols(s->rx_pkt, buf, size); struct iovec iov = {
.iov_base = (void *)buf,
.iov_len = size
};
net_rx_pkt_set_protocols(s->rx_pkt, &iov, 1, 0);
vmxnet3_rx_need_csum_calculate(s->rx_pkt, buf, size); vmxnet3_rx_need_csum_calculate(s->rx_pkt, buf, size);
net_rx_pkt_attach_data(s->rx_pkt, buf, size, s->rx_vlan_stripping); net_rx_pkt_attach_data(s->rx_pkt, buf, size, s->rx_vlan_stripping);
bytes_indicated = vmxnet3_indicate_packet(s) ? size : -1; bytes_indicated = vmxnet3_indicate_packet(s) ? size : -1;

View File

@ -312,10 +312,10 @@ eth_get_l2_hdr_length(const void *p)
} }
static inline uint32_t static inline uint32_t
eth_get_l2_hdr_length_iov(const struct iovec *iov, int iovcnt) eth_get_l2_hdr_length_iov(const struct iovec *iov, size_t iovcnt, size_t iovoff)
{ {
uint8_t p[sizeof(struct eth_header) + sizeof(struct vlan_header)]; uint8_t p[sizeof(struct eth_header) + sizeof(struct vlan_header)];
size_t copied = iov_to_buf(iov, iovcnt, 0, p, ARRAY_SIZE(p)); size_t copied = iov_to_buf(iov, iovcnt, iovoff, p, ARRAY_SIZE(p));
if (copied < ARRAY_SIZE(p)) { if (copied < ARRAY_SIZE(p)) {
return copied; return copied;
@ -397,7 +397,7 @@ typedef struct eth_l4_hdr_info_st {
bool has_tcp_data; bool has_tcp_data;
} eth_l4_hdr_info; } eth_l4_hdr_info;
void eth_get_protocols(const struct iovec *iov, int iovcnt, void eth_get_protocols(const struct iovec *iov, size_t iovcnt, size_t iovoff,
bool *hasip4, bool *hasip6, bool *hasip4, bool *hasip6,
size_t *l3hdr_off, size_t *l3hdr_off,
size_t *l4hdr_off, size_t *l4hdr_off,

View File

@ -136,7 +136,7 @@ _eth_tcp_has_data(bool is_ip4,
return l4len > TCP_HEADER_DATA_OFFSET(tcp); return l4len > TCP_HEADER_DATA_OFFSET(tcp);
} }
void eth_get_protocols(const struct iovec *iov, int iovcnt, void eth_get_protocols(const struct iovec *iov, size_t iovcnt, size_t iovoff,
bool *hasip4, bool *hasip6, bool *hasip4, bool *hasip6,
size_t *l3hdr_off, size_t *l3hdr_off,
size_t *l4hdr_off, size_t *l4hdr_off,
@ -147,26 +147,24 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt,
{ {
int proto; int proto;
bool fragment = false; bool fragment = false;
size_t l2hdr_len = eth_get_l2_hdr_length_iov(iov, iovcnt);
size_t input_size = iov_size(iov, iovcnt); size_t input_size = iov_size(iov, iovcnt);
size_t copied; size_t copied;
uint8_t ip_p; uint8_t ip_p;
*hasip4 = *hasip6 = false; *hasip4 = *hasip6 = false;
*l3hdr_off = iovoff + eth_get_l2_hdr_length_iov(iov, iovcnt, iovoff);
l4hdr_info->proto = ETH_L4_HDR_PROTO_INVALID; l4hdr_info->proto = ETH_L4_HDR_PROTO_INVALID;
proto = eth_get_l3_proto(iov, iovcnt, l2hdr_len); proto = eth_get_l3_proto(iov, iovcnt, *l3hdr_off);
*l3hdr_off = l2hdr_len;
if (proto == ETH_P_IP) { if (proto == ETH_P_IP) {
struct ip_header *iphdr = &ip4hdr_info->ip4_hdr; struct ip_header *iphdr = &ip4hdr_info->ip4_hdr;
if (input_size < l2hdr_len) { if (input_size < *l3hdr_off) {
return; return;
} }
copied = iov_to_buf(iov, iovcnt, l2hdr_len, iphdr, sizeof(*iphdr)); copied = iov_to_buf(iov, iovcnt, *l3hdr_off, iphdr, sizeof(*iphdr));
if (copied < sizeof(*iphdr) || if (copied < sizeof(*iphdr) ||
IP_HEADER_VERSION(iphdr) != IP_HEADER_VERSION_4) { IP_HEADER_VERSION(iphdr) != IP_HEADER_VERSION_4) {
return; return;
@ -175,17 +173,17 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt,
*hasip4 = true; *hasip4 = true;
ip_p = iphdr->ip_p; ip_p = iphdr->ip_p;
ip4hdr_info->fragment = IP4_IS_FRAGMENT(iphdr); ip4hdr_info->fragment = IP4_IS_FRAGMENT(iphdr);
*l4hdr_off = l2hdr_len + IP_HDR_GET_LEN(iphdr); *l4hdr_off = *l3hdr_off + IP_HDR_GET_LEN(iphdr);
fragment = ip4hdr_info->fragment; fragment = ip4hdr_info->fragment;
} else if (proto == ETH_P_IPV6) { } else if (proto == ETH_P_IPV6) {
if (!eth_parse_ipv6_hdr(iov, iovcnt, l2hdr_len, ip6hdr_info)) { if (!eth_parse_ipv6_hdr(iov, iovcnt, *l3hdr_off, ip6hdr_info)) {
return; return;
} }
*hasip6 = true; *hasip6 = true;
ip_p = ip6hdr_info->l4proto; ip_p = ip6hdr_info->l4proto;
*l4hdr_off = l2hdr_len + ip6hdr_info->full_hdr_len; *l4hdr_off = *l3hdr_off + ip6hdr_info->full_hdr_len;
fragment = ip6hdr_info->fragment; fragment = ip6hdr_info->fragment;
} else { } else {
return; return;