Message ID | 20200716035325.1406919-1-andrew@daynix.com |
---|---|
State | New |
Headers | show |
Series | [v3,1/2] hw/net: Added plen fix for IPv6 | expand |
On 2020/7/16 上午11:53, andrew@daynix.com wrote: > From: Andrew <andrew@daynix.com> > > Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1708065 > With network backend with 'virtual header' - there was an issue > in 'plen' field. Overall, during TSO, 'plen' would be changed, > but with 'vheader' this field should be set to the size of the > payload itself instead of '0'. > > Signed-off-by: Andrew Melnychenko <andrew@daynix.com> Applied. Thanks > --- > hw/net/net_tx_pkt.c | 23 +++++++++++++++++++++++ > hw/net/net_tx_pkt.h | 14 ++++++++++++++ > include/net/eth.h | 1 + > 3 files changed, 38 insertions(+) > > diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c > index 331c73cfc0..9560e4a49e 100644 > --- a/hw/net/net_tx_pkt.c > +++ b/hw/net/net_tx_pkt.c > @@ -626,6 +626,7 @@ bool net_tx_pkt_send(struct NetTxPkt *pkt, NetClientState *nc) > > if (pkt->has_virt_hdr || > pkt->virt_hdr.gso_type == VIRTIO_NET_HDR_GSO_NONE) { > + net_tx_pkt_fix_ip6_payload_len(pkt); > net_tx_pkt_sendv(pkt, nc, pkt->vec, > pkt->payload_frags + NET_TX_PKT_PL_START_FRAG); > return true; > @@ -644,3 +645,25 @@ bool net_tx_pkt_send_loopback(struct NetTxPkt *pkt, NetClientState *nc) > > return res; > } > + > +void net_tx_pkt_fix_ip6_payload_len(struct NetTxPkt *pkt) > +{ > + struct iovec *l2 = &pkt->vec[NET_TX_PKT_L2HDR_FRAG]; > + if (eth_get_l3_proto(l2, 1, l2->iov_len) == ETH_P_IPV6) { > + struct ip6_header *ip6 = (struct ip6_header *) pkt->l3_hdr; > + /* > + * TODO: if qemu would support >64K packets - add jumbo option check > + * something like that: > + * 'if (ip6->ip6_plen == 0 && !has_jumbo_option(ip6)) {' > + */ > + if (ip6->ip6_plen == 0) { > + if (pkt->payload_len <= ETH_MAX_IP_DGRAM_LEN) { > + ip6->ip6_plen = htons(pkt->payload_len); > + } > + /* > + * TODO: if qemu would support >64K packets > + * add jumbo option for packets greater then 65,535 bytes > + */ > + } > + } > +} > diff --git a/hw/net/net_tx_pkt.h b/hw/net/net_tx_pkt.h > index 212ecc62fc..4ec8bbe9bd 100644 > --- a/hw/net/net_tx_pkt.h > +++ b/hw/net/net_tx_pkt.h > @@ -187,4 +187,18 @@ bool net_tx_pkt_parse(struct NetTxPkt *pkt); > */ > bool net_tx_pkt_has_fragments(struct NetTxPkt *pkt); > > +/** > + * Fix IPv6 'plen' field. > + * If ipv6 payload length field is 0 - then there should be Hop-by-Hop > + * option for packets greater than 65,535. > + * For packets with a payload less than 65,535: fix 'plen' field. > + * For backends with vheader, we need just one packet with proper > + * payload size. For now, qemu drops every packet with size greater 64K > + * (see net_tx_pkt_send()) so, there is no reason to add jumbo option to ip6 > + * hop-by-hop extension if it's missed > + * > + * @pkt packet > + */ > +void net_tx_pkt_fix_ip6_payload_len(struct NetTxPkt *pkt); > + > #endif > diff --git a/include/net/eth.h b/include/net/eth.h > index 7f45c678e7..0671be6916 100644 > --- a/include/net/eth.h > +++ b/include/net/eth.h > @@ -186,6 +186,7 @@ struct tcp_hdr { > > #define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt > #define ip6_ecn_acc ip6_ctlun.ip6_un3.ip6_un3_ecn > +#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen > > #define PKT_GET_ETH_HDR(p) \ > ((struct eth_header *)(p))
diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c index 331c73cfc0..9560e4a49e 100644 --- a/hw/net/net_tx_pkt.c +++ b/hw/net/net_tx_pkt.c @@ -626,6 +626,7 @@ bool net_tx_pkt_send(struct NetTxPkt *pkt, NetClientState *nc) if (pkt->has_virt_hdr || pkt->virt_hdr.gso_type == VIRTIO_NET_HDR_GSO_NONE) { + net_tx_pkt_fix_ip6_payload_len(pkt); net_tx_pkt_sendv(pkt, nc, pkt->vec, pkt->payload_frags + NET_TX_PKT_PL_START_FRAG); return true; @@ -644,3 +645,25 @@ bool net_tx_pkt_send_loopback(struct NetTxPkt *pkt, NetClientState *nc) return res; } + +void net_tx_pkt_fix_ip6_payload_len(struct NetTxPkt *pkt) +{ + struct iovec *l2 = &pkt->vec[NET_TX_PKT_L2HDR_FRAG]; + if (eth_get_l3_proto(l2, 1, l2->iov_len) == ETH_P_IPV6) { + struct ip6_header *ip6 = (struct ip6_header *) pkt->l3_hdr; + /* + * TODO: if qemu would support >64K packets - add jumbo option check + * something like that: + * 'if (ip6->ip6_plen == 0 && !has_jumbo_option(ip6)) {' + */ + if (ip6->ip6_plen == 0) { + if (pkt->payload_len <= ETH_MAX_IP_DGRAM_LEN) { + ip6->ip6_plen = htons(pkt->payload_len); + } + /* + * TODO: if qemu would support >64K packets + * add jumbo option for packets greater then 65,535 bytes + */ + } + } +} diff --git a/hw/net/net_tx_pkt.h b/hw/net/net_tx_pkt.h index 212ecc62fc..4ec8bbe9bd 100644 --- a/hw/net/net_tx_pkt.h +++ b/hw/net/net_tx_pkt.h @@ -187,4 +187,18 @@ bool net_tx_pkt_parse(struct NetTxPkt *pkt); */ bool net_tx_pkt_has_fragments(struct NetTxPkt *pkt); +/** + * Fix IPv6 'plen' field. + * If ipv6 payload length field is 0 - then there should be Hop-by-Hop + * option for packets greater than 65,535. + * For packets with a payload less than 65,535: fix 'plen' field. + * For backends with vheader, we need just one packet with proper + * payload size. For now, qemu drops every packet with size greater 64K + * (see net_tx_pkt_send()) so, there is no reason to add jumbo option to ip6 + * hop-by-hop extension if it's missed + * + * @pkt packet + */ +void net_tx_pkt_fix_ip6_payload_len(struct NetTxPkt *pkt); + #endif diff --git a/include/net/eth.h b/include/net/eth.h index 7f45c678e7..0671be6916 100644 --- a/include/net/eth.h +++ b/include/net/eth.h @@ -186,6 +186,7 @@ struct tcp_hdr { #define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt #define ip6_ecn_acc ip6_ctlun.ip6_un3.ip6_un3_ecn +#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen #define PKT_GET_ETH_HDR(p) \ ((struct eth_header *)(p))