aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2021-03-22 11:24:55 +0000
committerPeter Maydell <peter.maydell@linaro.org>2021-03-22 11:24:55 +0000
commitb184750926812cb78ac0caf4c4b2b13683b5bde3 (patch)
tree52f3351a4acfd6d7fdd93fdc5bd0b19c9eca7ec3 /net
parentf0f20022a0c744930935fdb7020a8c18347d391a (diff)
parentc7274b5ef43614dd133daec1e2018f71d8744088 (diff)
Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging
# gpg: Signature made Mon 22 Mar 2021 09:35:08 GMT # gpg: using RSA key EF04965B398D6211 # gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" [marginal] # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 215D 46F4 8246 689E C77F 3562 EF04 965B 398D 6211 * remotes/jasowang/tags/net-pull-request: net/eth: Add an assert() and invert if() statement to simplify code net/eth: Read ip6_ext_hdr_routing buffer before accessing it net/eth: Check iovec has enough data earlier net/eth: Check size earlier in _eth_get_rss_ex_dst_addr() net/eth: Better describe _eth_get_rss_ex_dst_addr's offset argument net/eth: Simplify _eth_get_rss_ex_dst_addr() net/eth: Use correct in6_address offset in _eth_get_rss_ex_dst_addr() net/colo-compare.c: Optimize removal of secondary packet net/colo-compare.c: Fix memory leak for non-tcp packet hw/net: virtio-net: Initialize nc->do_not_pad to true net: Pad short frames to minimum size before sending from SLiRP/TAP net: Add a 'do_not_pad" to NetClientState net: eth: Add a helper to pad a short Ethernet frame Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'net')
-rw-r--r--net/colo-compare.c3
-rw-r--r--net/eth.c61
-rw-r--r--net/slirp.c10
-rw-r--r--net/tap-win32.c10
-rw-r--r--net/tap.c10
5 files changed, 71 insertions, 23 deletions
diff --git a/net/colo-compare.c b/net/colo-compare.c
index 84db4978ac..9d1ad99941 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -690,7 +690,8 @@ static void colo_compare_packet(CompareState *s, Connection *conn,
if (result) {
colo_release_primary_pkt(s, pkt);
- g_queue_remove(&conn->secondary_list, result->data);
+ packet_destroy(result->data, NULL);
+ g_queue_delete_link(&conn->secondary_list, result);
} else {
/*
* If one packet arrive late, the secondary_list or
diff --git a/net/eth.c b/net/eth.c
index 1e0821c5f8..fe876d1a55 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -401,31 +401,29 @@ eth_is_ip6_extension_header_type(uint8_t hdr_type)
static bool
_eth_get_rss_ex_dst_addr(const struct iovec *pkt, int pkt_frags,
- size_t rthdr_offset,
+ size_t ext_hdr_offset,
struct ip6_ext_hdr *ext_hdr,
struct in6_address *dst_addr)
{
- struct ip6_ext_hdr_routing *rthdr = (struct ip6_ext_hdr_routing *) ext_hdr;
-
- if ((rthdr->rtype == 2) &&
- (rthdr->len == sizeof(struct in6_address) / 8) &&
- (rthdr->segleft == 1)) {
-
- size_t input_size = iov_size(pkt, pkt_frags);
- size_t bytes_read;
-
- if (input_size < rthdr_offset + sizeof(*ext_hdr)) {
- return false;
- }
+ struct ip6_ext_hdr_routing rt_hdr;
+ size_t input_size = iov_size(pkt, pkt_frags);
+ size_t bytes_read;
- bytes_read = iov_to_buf(pkt, pkt_frags,
- rthdr_offset + sizeof(*ext_hdr),
- dst_addr, sizeof(*dst_addr));
+ if (input_size < ext_hdr_offset + sizeof(rt_hdr) + sizeof(*dst_addr)) {
+ return false;
+ }
- return bytes_read == sizeof(*dst_addr);
+ bytes_read = iov_to_buf(pkt, pkt_frags, ext_hdr_offset,
+ &rt_hdr, sizeof(rt_hdr));
+ assert(bytes_read == sizeof(rt_hdr));
+ if ((rt_hdr.rtype != 2) || (rt_hdr.segleft != 1)) {
+ return false;
}
+ bytes_read = iov_to_buf(pkt, pkt_frags, ext_hdr_offset + sizeof(rt_hdr),
+ dst_addr, sizeof(*dst_addr));
+ assert(bytes_read == sizeof(*dst_addr));
- return false;
+ return true;
}
static bool
@@ -528,10 +526,12 @@ bool eth_parse_ipv6_hdr(const struct iovec *pkt, int pkt_frags,
}
if (curr_ext_hdr_type == IP6_ROUTING) {
- info->rss_ex_dst_valid =
- _eth_get_rss_ex_dst_addr(pkt, pkt_frags,
- ip6hdr_off + info->full_hdr_len,
- &ext_hdr, &info->rss_ex_dst);
+ if (ext_hdr.ip6r_len == sizeof(struct in6_address) / 8) {
+ info->rss_ex_dst_valid =
+ _eth_get_rss_ex_dst_addr(pkt, pkt_frags,
+ ip6hdr_off + info->full_hdr_len,
+ &ext_hdr, &info->rss_ex_dst);
+ }
} else if (curr_ext_hdr_type == IP6_DESTINATON) {
info->rss_ex_src_valid =
_eth_get_rss_ex_src_addr(pkt, pkt_frags,
@@ -548,3 +548,20 @@ bool eth_parse_ipv6_hdr(const struct iovec *pkt, int pkt_frags,
info->l4proto = ext_hdr.ip6r_nxt;
return true;
}
+
+bool eth_pad_short_frame(uint8_t *padded_pkt, size_t *padded_buflen,
+ const void *pkt, size_t pkt_size)
+{
+ assert(padded_buflen && *padded_buflen >= ETH_ZLEN);
+
+ if (pkt_size >= ETH_ZLEN) {
+ return false;
+ }
+
+ /* pad to minimum Ethernet frame length */
+ memcpy(padded_pkt, pkt, pkt_size);
+ memset(&padded_pkt[pkt_size], 0, ETH_ZLEN - pkt_size);
+ *padded_buflen = ETH_ZLEN;
+
+ return true;
+}
diff --git a/net/slirp.c b/net/slirp.c
index 9454a673d6..a9fdc7a08f 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -31,6 +31,7 @@
#include <pwd.h>
#include <sys/wait.h>
#endif
+#include "net/eth.h"
#include "net/net.h"
#include "clients.h"
#include "hub.h"
@@ -115,6 +116,15 @@ static ssize_t net_slirp_send_packet(const void *pkt, size_t pkt_len,
void *opaque)
{
SlirpState *s = opaque;
+ uint8_t min_pkt[ETH_ZLEN];
+ size_t min_pktsz = sizeof(min_pkt);
+
+ if (!s->nc.peer->do_not_pad) {
+ if (eth_pad_short_frame(min_pkt, &min_pktsz, pkt, pkt_len)) {
+ pkt = min_pkt;
+ pkt_len = min_pktsz;
+ }
+ }
return qemu_send_packet(&s->nc, pkt, pkt_len);
}
diff --git a/net/tap-win32.c b/net/tap-win32.c
index 21e451107b..d7c2a8759c 100644
--- a/net/tap-win32.c
+++ b/net/tap-win32.c
@@ -31,6 +31,7 @@
#include "qemu-common.h"
#include "clients.h" /* net_init_tap */
+#include "net/eth.h"
#include "net/net.h"
#include "net/tap.h" /* tap_has_ufo, ... */
#include "qemu/error-report.h"
@@ -688,9 +689,18 @@ static void tap_win32_send(void *opaque)
uint8_t *buf;
int max_size = 4096;
int size;
+ uint8_t min_pkt[ETH_ZLEN];
+ size_t min_pktsz = sizeof(min_pkt);
size = tap_win32_read(s->handle, &buf, max_size);
if (size > 0) {
+ if (!s->nc.peer->do_not_pad) {
+ if (eth_pad_short_frame(min_pkt, &min_pktsz, buf, size)) {
+ buf = min_pkt;
+ size = min_pktsz;
+ }
+ }
+
qemu_send_packet(&s->nc, buf, size);
tap_win32_free_buffer(s->handle, buf);
}
diff --git a/net/tap.c b/net/tap.c
index 12a08d54fe..d6d8456188 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -32,6 +32,7 @@
#include <sys/socket.h>
#include <net/if.h>
+#include "net/eth.h"
#include "net/net.h"
#include "clients.h"
#include "monitor/monitor.h"
@@ -189,6 +190,8 @@ static void tap_send(void *opaque)
while (true) {
uint8_t *buf = s->buf;
+ uint8_t min_pkt[ETH_ZLEN];
+ size_t min_pktsz = sizeof(min_pkt);
size = tap_read_packet(s->fd, s->buf, sizeof(s->buf));
if (size <= 0) {
@@ -200,6 +203,13 @@ static void tap_send(void *opaque)
size -= s->host_vnet_hdr_len;
}
+ if (!s->nc.peer->do_not_pad) {
+ if (eth_pad_short_frame(min_pkt, &min_pktsz, buf, size)) {
+ buf = min_pkt;
+ size = min_pktsz;
+ }
+ }
+
size = qemu_send_packet_async(&s->nc, buf, size, tap_send_completed);
if (size == 0) {
tap_read_poll(s, false);