1
The following changes since commit 92f8c6fef13b31ba222c4d20ad8afd2b79c4c28e:
1
The following changes since commit f670b3eec7f5d1ed8c4573ef244e7b8c6b32001b:
2
2
3
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20210525' into staging (2021-05-25 16:17:06 +0100)
3
Merge tag 'migration-20230213-pull-request' of https://gitlab.com/juan.quintela/qemu into staging (2023-02-13 11:54:05 +0000)
4
4
5
are available in the git repository at:
5
are available in the git repository at:
6
6
7
https://github.com/jasowang/qemu.git tags/net-pull-request
7
https://github.com/jasowang/qemu.git tags/net-pull-request
8
8
9
for you to fetch changes up to 90322e646e87c1440661cb3ddbc0cc94309d8a4f:
9
for you to fetch changes up to e4b953a26da11d214f91516cb9b0542eab5afaa0:
10
10
11
MAINTAINERS: Added eBPF maintainers information. (2021-06-04 15:25:46 +0800)
11
vdpa: fix VHOST_BACKEND_F_IOTLB_ASID flag check (2023-02-14 14:00:30 +0800)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
14
15
----------------------------------------------------------------
15
----------------------------------------------------------------
16
Andrew Melnychenko (7):
16
Christian Svensson (1):
17
net/tap: Added TUNSETSTEERINGEBPF code.
17
net: Increase L2TPv3 buffer to fit jumboframes
18
net: Added SetSteeringEBPF method for NetClientState.
19
ebpf: Added eBPF RSS program.
20
ebpf: Added eBPF RSS loader.
21
virtio-net: Added eBPF RSS to virtio-net.
22
docs: Added eBPF documentation.
23
MAINTAINERS: Added eBPF maintainers information.
24
18
25
MAINTAINERS | 8 +
19
Eugenio Pérez (1):
26
configure | 8 +-
20
vdpa: fix VHOST_BACKEND_F_IOTLB_ASID flag check
27
docs/devel/ebpf_rss.rst | 125 +++++++++
21
28
docs/devel/index.rst | 1 +
22
Fiona Ebner (1):
29
ebpf/ebpf_rss-stub.c | 40 +++
23
hw/net/vmxnet3: allow VMXNET3_MAX_MTU itself as a value
30
ebpf/ebpf_rss.c | 165 ++++++++++++
24
31
ebpf/ebpf_rss.h | 44 ++++
25
Joelle van Dyne (1):
32
ebpf/meson.build | 1 +
26
vmnet: stop recieving events when VM is stopped
33
ebpf/rss.bpf.skeleton.h | 431 +++++++++++++++++++++++++++++++
27
34
ebpf/trace-events | 4 +
28
Laurent Vivier (1):
35
ebpf/trace.h | 1 +
29
net: stream: add a new option to automatically reconnect
36
hw/net/vhost_net.c | 3 +
30
37
hw/net/virtio-net.c | 116 ++++++++-
31
Qiang Liu (2):
38
include/hw/virtio/virtio-net.h | 4 +
32
hw/net/lan9118: log [read|write]b when mode_16bit is enabled rather than abort
39
include/net/net.h | 2 +
33
hw/net/can/xlnx-zynqmp-can: fix assertion failures in transfer_fifo()
40
meson.build | 23 ++
34
41
meson_options.txt | 2 +
35
Thomas Huth (3):
42
net/tap-bsd.c | 5 +
36
net: Move the code to collect available NIC models to a separate function
43
net/tap-linux.c | 13 +
37
net: Restore printing of the help text with "-nic help"
44
net/tap-linux.h | 1 +
38
net: Replace "Supported NIC models" with "Available NIC models"
45
net/tap-solaris.c | 5 +
39
46
net/tap-stub.c | 5 +
40
hw/net/can/xlnx-zynqmp-can.c | 9 +++-
47
net/tap.c | 9 +
41
hw/net/lan9118.c | 17 ++++----
48
net/tap_int.h | 1 +
42
hw/net/vmxnet3.c | 2 +-
49
net/vhost-vdpa.c | 2 +
43
hw/pci/pci.c | 29 +------------
50
tools/ebpf/Makefile.ebpf | 21 ++
44
include/net/net.h | 14 ++++++
51
tools/ebpf/rss.bpf.c | 571 +++++++++++++++++++++++++++++++++++++++++
45
net/l2tpv3.c | 2 +-
52
27 files changed, 1607 insertions(+), 4 deletions(-)
46
net/net.c | 50 +++++++++++++++++++--
53
create mode 100644 docs/devel/ebpf_rss.rst
47
net/stream.c | 53 ++++++++++++++++++++++-
54
create mode 100644 ebpf/ebpf_rss-stub.c
48
net/vhost-vdpa.c | 2 +-
55
create mode 100644 ebpf/ebpf_rss.c
49
net/vmnet-common.m | 48 ++++++++++++++------
56
create mode 100644 ebpf/ebpf_rss.h
50
net/vmnet_int.h | 2 +
57
create mode 100644 ebpf/meson.build
51
qapi/net.json | 7 ++-
58
create mode 100644 ebpf/rss.bpf.skeleton.h
52
qemu-options.hx | 6 +--
59
create mode 100644 ebpf/trace-events
53
tests/qtest/netdev-socket.c | 101 +++++++++++++++++++++++++++++++++++++++++++
60
create mode 100644 ebpf/trace.h
54
14 files changed, 280 insertions(+), 62 deletions(-)
61
create mode 100755 tools/ebpf/Makefile.ebpf
62
create mode 100644 tools/ebpf/rss.bpf.c
63
55
64
56
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
For now, that method supported only by Linux TAP.
3
The code that collects the available NIC models is not really specific
4
Linux TAP uses TUNSETSTEERINGEBPF ioctl.
4
to PCI anymore and will be required in the next patch, too, so let's
5
move this into a new separate function in net.c instead.
5
6
6
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
7
Signed-off-by: Thomas Huth <thuth@redhat.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
9
---
9
include/net/net.h | 2 ++
10
hw/pci/pci.c | 29 +----------------------------
10
net/tap-bsd.c | 5 +++++
11
include/net/net.h | 14 ++++++++++++++
11
net/tap-linux.c | 13 +++++++++++++
12
net/net.c | 34 ++++++++++++++++++++++++++++++++++
12
net/tap-solaris.c | 5 +++++
13
3 files changed, 49 insertions(+), 28 deletions(-)
13
net/tap-stub.c | 5 +++++
14
net/tap.c | 9 +++++++++
15
net/tap_int.h | 1 +
16
7 files changed, 40 insertions(+)
17
14
15
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/pci/pci.c
18
+++ b/hw/pci/pci.c
19
@@ -XXX,XX +XXX,XX @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
20
const char *default_devaddr)
21
{
22
const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr;
23
- GSList *list;
24
GPtrArray *pci_nic_models;
25
PCIBus *bus;
26
PCIDevice *pci_dev;
27
@@ -XXX,XX +XXX,XX @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
28
nd->model = g_strdup("virtio-net-pci");
29
}
30
31
- list = object_class_get_list_sorted(TYPE_PCI_DEVICE, false);
32
- pci_nic_models = g_ptr_array_new();
33
- while (list) {
34
- DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, list->data,
35
- TYPE_DEVICE);
36
- GSList *next;
37
- if (test_bit(DEVICE_CATEGORY_NETWORK, dc->categories) &&
38
- dc->user_creatable) {
39
- const char *name = object_class_get_name(list->data);
40
- /*
41
- * A network device might also be something else than a NIC, see
42
- * e.g. the "rocker" device. Thus we have to look for the "netdev"
43
- * property, too. Unfortunately, some devices like virtio-net only
44
- * create this property during instance_init, so we have to create
45
- * a temporary instance here to be able to check it.
46
- */
47
- Object *obj = object_new_with_class(OBJECT_CLASS(dc));
48
- if (object_property_find(obj, "netdev")) {
49
- g_ptr_array_add(pci_nic_models, (gpointer)name);
50
- }
51
- object_unref(obj);
52
- }
53
- next = list->next;
54
- g_slist_free_1(list);
55
- list = next;
56
- }
57
- g_ptr_array_add(pci_nic_models, NULL);
58
+ pci_nic_models = qemu_get_nic_models(TYPE_PCI_DEVICE);
59
60
if (qemu_show_nic_models(nd->model, (const char **)pci_nic_models->pdata)) {
61
exit(0);
18
diff --git a/include/net/net.h b/include/net/net.h
62
diff --git a/include/net/net.h b/include/net/net.h
19
index XXXXXXX..XXXXXXX 100644
63
index XXXXXXX..XXXXXXX 100644
20
--- a/include/net/net.h
64
--- a/include/net/net.h
21
+++ b/include/net/net.h
65
+++ b/include/net/net.h
22
@@ -XXX,XX +XXX,XX @@ typedef int (SetVnetBE)(NetClientState *, bool);
66
@@ -XXX,XX +XXX,XX @@ void net_socket_rs_init(SocketReadState *rs,
23
typedef struct SocketReadState SocketReadState;
67
bool vnet_hdr);
24
typedef void (SocketReadStateFinalize)(SocketReadState *rs);
68
NetClientState *qemu_get_peer(NetClientState *nc, int queue_index);
25
typedef void (NetAnnounce)(NetClientState *);
69
26
+typedef bool (SetSteeringEBPF)(NetClientState *, int);
70
+/**
27
71
+ * qemu_get_nic_models:
28
typedef struct NetClientInfo {
72
+ * @device_type: Defines which devices should be taken into consideration
29
NetClientDriver type;
73
+ * (e.g. TYPE_DEVICE for all devices, or TYPE_PCI_DEVICE for PCI)
30
@@ -XXX,XX +XXX,XX @@ typedef struct NetClientInfo {
74
+ *
31
SetVnetLE *set_vnet_le;
75
+ * Get an array of pointers to names of NIC devices that are available in
32
SetVnetBE *set_vnet_be;
76
+ * the QEMU binary. The array is terminated with a NULL pointer entry.
33
NetAnnounce *announce;
77
+ * The caller is responsible for freeing the memory when it is not required
34
+ SetSteeringEBPF *set_steering_ebpf;
78
+ * anymore, e.g. with g_ptr_array_free(..., true).
35
} NetClientInfo;
79
+ *
36
80
+ * Returns: Pointer to the array that contains the pointers to the names.
37
struct NetClientState {
81
+ */
38
diff --git a/net/tap-bsd.c b/net/tap-bsd.c
82
+GPtrArray *qemu_get_nic_models(const char *device_type);
83
+
84
/* NIC info */
85
86
#define MAX_NICS 8
87
diff --git a/net/net.c b/net/net.c
39
index XXXXXXX..XXXXXXX 100644
88
index XXXXXXX..XXXXXXX 100644
40
--- a/net/tap-bsd.c
89
--- a/net/net.c
41
+++ b/net/tap-bsd.c
90
+++ b/net/net.c
42
@@ -XXX,XX +XXX,XX @@ int tap_fd_get_ifname(int fd, char *ifname)
91
@@ -XXX,XX +XXX,XX @@ static int nic_get_free_idx(void)
43
{
44
return -1;
92
return -1;
45
}
93
}
94
95
+GPtrArray *qemu_get_nic_models(const char *device_type)
96
+{
97
+ GPtrArray *nic_models = g_ptr_array_new();
98
+ GSList *list = object_class_get_list_sorted(device_type, false);
46
+
99
+
47
+int tap_fd_set_steering_ebpf(int fd, int prog_fd)
100
+ while (list) {
48
+{
101
+ DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, list->data,
49
+ return -1;
102
+ TYPE_DEVICE);
50
+}
103
+ GSList *next;
51
diff --git a/net/tap-linux.c b/net/tap-linux.c
104
+ if (test_bit(DEVICE_CATEGORY_NETWORK, dc->categories) &&
52
index XXXXXXX..XXXXXXX 100644
105
+ dc->user_creatable) {
53
--- a/net/tap-linux.c
106
+ const char *name = object_class_get_name(list->data);
54
+++ b/net/tap-linux.c
107
+ /*
55
@@ -XXX,XX +XXX,XX @@ int tap_fd_get_ifname(int fd, char *ifname)
108
+ * A network device might also be something else than a NIC, see
56
pstrcpy(ifname, sizeof(ifr.ifr_name), ifr.ifr_name);
109
+ * e.g. the "rocker" device. Thus we have to look for the "netdev"
57
return 0;
110
+ * property, too. Unfortunately, some devices like virtio-net only
58
}
111
+ * create this property during instance_init, so we have to create
112
+ * a temporary instance here to be able to check it.
113
+ */
114
+ Object *obj = object_new_with_class(OBJECT_CLASS(dc));
115
+ if (object_property_find(obj, "netdev")) {
116
+ g_ptr_array_add(nic_models, (gpointer)name);
117
+ }
118
+ object_unref(obj);
119
+ }
120
+ next = list->next;
121
+ g_slist_free_1(list);
122
+ list = next;
123
+ }
124
+ g_ptr_array_add(nic_models, NULL);
59
+
125
+
60
+int tap_fd_set_steering_ebpf(int fd, int prog_fd)
126
+ return nic_models;
61
+{
62
+ if (ioctl(fd, TUNSETSTEERINGEBPF, (void *) &prog_fd) != 0) {
63
+ error_report("Issue while setting TUNSETSTEERINGEBPF:"
64
+ " %s with fd: %d, prog_fd: %d",
65
+ strerror(errno), fd, prog_fd);
66
+
67
+ return -1;
68
+ }
69
+
70
+ return 0;
71
+}
72
diff --git a/net/tap-solaris.c b/net/tap-solaris.c
73
index XXXXXXX..XXXXXXX 100644
74
--- a/net/tap-solaris.c
75
+++ b/net/tap-solaris.c
76
@@ -XXX,XX +XXX,XX @@ int tap_fd_get_ifname(int fd, char *ifname)
77
{
78
return -1;
79
}
80
+
81
+int tap_fd_set_steering_ebpf(int fd, int prog_fd)
82
+{
83
+ return -1;
84
+}
85
diff --git a/net/tap-stub.c b/net/tap-stub.c
86
index XXXXXXX..XXXXXXX 100644
87
--- a/net/tap-stub.c
88
+++ b/net/tap-stub.c
89
@@ -XXX,XX +XXX,XX @@ int tap_fd_get_ifname(int fd, char *ifname)
90
{
91
return -1;
92
}
93
+
94
+int tap_fd_set_steering_ebpf(int fd, int prog_fd)
95
+{
96
+ return -1;
97
+}
98
diff --git a/net/tap.c b/net/tap.c
99
index XXXXXXX..XXXXXXX 100644
100
--- a/net/tap.c
101
+++ b/net/tap.c
102
@@ -XXX,XX +XXX,XX @@ static void tap_poll(NetClientState *nc, bool enable)
103
tap_write_poll(s, enable);
104
}
105
106
+static bool tap_set_steering_ebpf(NetClientState *nc, int prog_fd)
107
+{
108
+ TAPState *s = DO_UPCAST(TAPState, nc, nc);
109
+ assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
110
+
111
+ return tap_fd_set_steering_ebpf(s->fd, prog_fd) == 0;
112
+}
127
+}
113
+
128
+
114
int tap_get_fd(NetClientState *nc)
129
int qemu_show_nic_models(const char *arg, const char *const *models)
115
{
130
{
116
TAPState *s = DO_UPCAST(TAPState, nc, nc);
131
int i;
117
@@ -XXX,XX +XXX,XX @@ static NetClientInfo net_tap_info = {
118
.set_vnet_hdr_len = tap_set_vnet_hdr_len,
119
.set_vnet_le = tap_set_vnet_le,
120
.set_vnet_be = tap_set_vnet_be,
121
+ .set_steering_ebpf = tap_set_steering_ebpf,
122
};
123
124
static TAPState *net_tap_fd_init(NetClientState *peer,
125
diff --git a/net/tap_int.h b/net/tap_int.h
126
index XXXXXXX..XXXXXXX 100644
127
--- a/net/tap_int.h
128
+++ b/net/tap_int.h
129
@@ -XXX,XX +XXX,XX @@ int tap_fd_set_vnet_be(int fd, int vnet_is_be);
130
int tap_fd_enable(int fd);
131
int tap_fd_disable(int fd);
132
int tap_fd_get_ifname(int fd, char *ifname);
133
+int tap_fd_set_steering_ebpf(int fd, int prog_fd);
134
135
#endif /* NET_TAP_INT_H */
136
--
132
--
137
2.7.4
133
2.7.4
138
139
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
3
Running QEMU with "-nic help" used to work in QEMU 5.2 and earlier versions
4
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
4
(it showed the available netdev backends), but this feature got broken during
5
some refactoring in version 6.0. Let's restore the old behavior, and while
6
we're at it, let's also print the available NIC models here now since this
7
option can be used to configure both, netdev backend and model in one go.
8
9
Fixes: ad6f932fe8 ("net: do not exit on "netdev_add help" monitor command")
10
Signed-off-by: Thomas Huth <thuth@redhat.com>
5
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
6
---
12
---
7
MAINTAINERS | 8 ++++++++
13
net/net.c | 14 ++++++++++++--
8
1 file changed, 8 insertions(+)
14
1 file changed, 12 insertions(+), 2 deletions(-)
9
15
10
diff --git a/MAINTAINERS b/MAINTAINERS
16
diff --git a/net/net.c b/net/net.c
11
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
12
--- a/MAINTAINERS
18
--- a/net/net.c
13
+++ b/MAINTAINERS
19
+++ b/net/net.c
14
@@ -XXX,XX +XXX,XX @@ F: include/hw/remote/proxy-memory-listener.h
20
@@ -XXX,XX +XXX,XX @@ static int net_param_nic(void *dummy, QemuOpts *opts, Error **errp)
15
F: hw/remote/iohub.c
21
const char *type;
16
F: include/hw/remote/iohub.h
22
17
23
type = qemu_opt_get(opts, "type");
18
+EBPF:
24
- if (type && g_str_equal(type, "none")) {
19
+M: Jason Wang <jasowang@redhat.com>
25
- return 0; /* Nothing to do, default_net is cleared in vl.c */
20
+R: Andrew Melnychenko <andrew@daynix.com>
26
+ if (type) {
21
+R: Yuri Benditovich <yuri.benditovich@daynix.com>
27
+ if (g_str_equal(type, "none")) {
22
+S: Maintained
28
+ return 0; /* Nothing to do, default_net is cleared in vl.c */
23
+F: ebpf/*
29
+ }
24
+F: tools/ebpf/*
30
+ if (is_help_option(type)) {
25
+
31
+ GPtrArray *nic_models = qemu_get_nic_models(TYPE_DEVICE);
26
Build and test automation
32
+ show_netdevs();
27
-------------------------
33
+ printf("\n");
28
Build and test automation, general continuous integration
34
+ qemu_show_nic_models(type, (const char **)nic_models->pdata);
35
+ g_ptr_array_free(nic_models, true);
36
+ exit(0);
37
+ }
38
}
39
40
idx = nic_get_free_idx();
29
--
41
--
30
2.7.4
42
2.7.4
31
32
diff view generated by jsdifflib
New patch
1
From: Thomas Huth <thuth@redhat.com>
1
2
3
Just because a NIC model is compiled into the QEMU binary does not
4
necessary mean that it can be used with each and every machine.
5
So let's rather talk about "available" models instead of "supported"
6
models, just to avoid confusion.
7
8
Reviewed-by: Claudio Fontana <cfontana@suse.de>
9
Signed-off-by: Thomas Huth <thuth@redhat.com>
10
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
---
12
net/net.c | 2 +-
13
1 file changed, 1 insertion(+), 1 deletion(-)
14
15
diff --git a/net/net.c b/net/net.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/net/net.c
18
+++ b/net/net.c
19
@@ -XXX,XX +XXX,XX @@ int qemu_show_nic_models(const char *arg, const char *const *models)
20
return 0;
21
}
22
23
- printf("Supported NIC models:\n");
24
+ printf("Available NIC models:\n");
25
for (i = 0 ; models[i]; i++) {
26
printf("%s\n", models[i]);
27
}
28
--
29
2.7.4
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Qiang Liu <cyruscyliu@gmail.com>
2
2
3
When RSS is enabled the device tries to load the eBPF program
3
This patch replaces hw_error to guest error log for [read|write]b
4
to select RX virtqueue in the TUN. If eBPF can be loaded
4
accesses when mode_16bit is enabled. This avoids aborting qemu.
5
the RSS will function also with vhost (works with kernel 5.8 and later).
6
Software RSS is used as a fallback with vhost=off when eBPF can't be loaded
7
or when hash population requested by the guest.
8
5
9
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
6
Fixes: 1248f8d4cbc3 ("hw/lan9118: Add basic 16-bit mode support.")
10
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
7
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1433
8
Reported-by: Qiang Liu <cyruscyliu@gmail.com>
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
10
Signed-off-by: Qiang Liu <cyruscyliu@gmail.com>
11
Suggested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
13
---
13
hw/net/vhost_net.c | 3 ++
14
hw/net/lan9118.c | 17 ++++++++---------
14
hw/net/virtio-net.c | 116 +++++++++++++++++++++++++++++++++++++++--
15
1 file changed, 8 insertions(+), 9 deletions(-)
15
include/hw/virtio/virtio-net.h | 4 ++
16
net/vhost-vdpa.c | 2 +
17
4 files changed, 122 insertions(+), 3 deletions(-)
18
16
19
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
17
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
20
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/net/vhost_net.c
19
--- a/hw/net/lan9118.c
22
+++ b/hw/net/vhost_net.c
20
+++ b/hw/net/lan9118.c
23
@@ -XXX,XX +XXX,XX @@ static const int kernel_feature_bits[] = {
21
@@ -XXX,XX +XXX,XX @@
24
VIRTIO_NET_F_MTU,
22
#include "migration/vmstate.h"
25
VIRTIO_F_IOMMU_PLATFORM,
23
#include "net/net.h"
26
VIRTIO_F_RING_PACKED,
24
#include "net/eth.h"
27
+ VIRTIO_NET_F_HASH_REPORT,
25
-#include "hw/hw.h"
28
VHOST_INVALID_FEATURE_BIT
26
#include "hw/irq.h"
29
};
27
#include "hw/net/lan9118.h"
30
28
#include "hw/ptimer.h"
31
@@ -XXX,XX +XXX,XX @@ static const int user_feature_bits[] = {
29
@@ -XXX,XX +XXX,XX @@
32
VIRTIO_NET_F_MTU,
30
#ifdef DEBUG_LAN9118
33
VIRTIO_F_IOMMU_PLATFORM,
31
#define DPRINTF(fmt, ...) \
34
VIRTIO_F_RING_PACKED,
32
do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0)
35
+ VIRTIO_NET_F_RSS,
33
-#define BADF(fmt, ...) \
36
+ VIRTIO_NET_F_HASH_REPORT,
34
-do { hw_error("lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
37
35
#else
38
/* This bit implies RARP isn't sent by QEMU out of band */
36
#define DPRINTF(fmt, ...) do {} while(0)
39
VIRTIO_NET_F_GUEST_ANNOUNCE,
37
-#define BADF(fmt, ...) \
40
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
38
-do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
41
index XXXXXXX..XXXXXXX 100644
39
#endif
42
--- a/hw/net/virtio-net.c
40
43
+++ b/hw/net/virtio-net.c
41
/* The tx and rx fifo ports are a range of aliased 32-bit registers */
44
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
42
@@ -XXX,XX +XXX,XX @@ static uint32_t do_phy_read(lan9118_state *s, int reg)
45
return features;
43
case 30: /* Interrupt mask */
46
}
44
return s->phy_int_mask;
47
45
default:
48
- virtio_clear_feature(&features, VIRTIO_NET_F_RSS);
46
- BADF("PHY read reg %d\n", reg);
49
- virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT);
47
+ qemu_log_mask(LOG_GUEST_ERROR,
50
+ if (!ebpf_rss_is_loaded(&n->ebpf_rss)) {
48
+ "do_phy_read: PHY read reg %d\n", reg);
51
+ virtio_clear_feature(&features, VIRTIO_NET_F_RSS);
49
return 0;
52
+ }
53
features = vhost_net_get_features(get_vhost_net(nc->peer), features);
54
vdev->backend_features = features;
55
56
@@ -XXX,XX +XXX,XX @@ static int virtio_net_handle_announce(VirtIONet *n, uint8_t cmd,
57
}
50
}
58
}
51
}
59
52
@@ -XXX,XX +XXX,XX @@ static void do_phy_write(lan9118_state *s, int reg, uint32_t val)
60
+static void virtio_net_detach_epbf_rss(VirtIONet *n);
53
phy_update_irq(s);
61
+
54
break;
62
static void virtio_net_disable_rss(VirtIONet *n)
55
default:
63
{
56
- BADF("PHY write reg %d = 0x%04x\n", reg, val);
64
if (n->rss_data.enabled) {
57
+ qemu_log_mask(LOG_GUEST_ERROR,
65
trace_virtio_net_rss_disable();
58
+ "do_phy_write: PHY write reg %d = 0x%04x\n", reg, val);
66
}
59
}
67
n->rss_data.enabled = false;
68
+
69
+ virtio_net_detach_epbf_rss(n);
70
+}
71
+
72
+static bool virtio_net_attach_ebpf_to_backend(NICState *nic, int prog_fd)
73
+{
74
+ NetClientState *nc = qemu_get_peer(qemu_get_queue(nic), 0);
75
+ if (nc == NULL || nc->info->set_steering_ebpf == NULL) {
76
+ return false;
77
+ }
78
+
79
+ return nc->info->set_steering_ebpf(nc, prog_fd);
80
+}
81
+
82
+static void rss_data_to_rss_config(struct VirtioNetRssData *data,
83
+ struct EBPFRSSConfig *config)
84
+{
85
+ config->redirect = data->redirect;
86
+ config->populate_hash = data->populate_hash;
87
+ config->hash_types = data->hash_types;
88
+ config->indirections_len = data->indirections_len;
89
+ config->default_queue = data->default_queue;
90
+}
91
+
92
+static bool virtio_net_attach_epbf_rss(VirtIONet *n)
93
+{
94
+ struct EBPFRSSConfig config = {};
95
+
96
+ if (!ebpf_rss_is_loaded(&n->ebpf_rss)) {
97
+ return false;
98
+ }
99
+
100
+ rss_data_to_rss_config(&n->rss_data, &config);
101
+
102
+ if (!ebpf_rss_set_all(&n->ebpf_rss, &config,
103
+ n->rss_data.indirections_table, n->rss_data.key)) {
104
+ return false;
105
+ }
106
+
107
+ if (!virtio_net_attach_ebpf_to_backend(n->nic, n->ebpf_rss.program_fd)) {
108
+ return false;
109
+ }
110
+
111
+ return true;
112
+}
113
+
114
+static void virtio_net_detach_epbf_rss(VirtIONet *n)
115
+{
116
+ virtio_net_attach_ebpf_to_backend(n->nic, -1);
117
+}
118
+
119
+static bool virtio_net_load_ebpf(VirtIONet *n)
120
+{
121
+ if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
122
+ /* backend does't support steering ebpf */
123
+ return false;
124
+ }
125
+
126
+ return ebpf_rss_load(&n->ebpf_rss);
127
+}
128
+
129
+static void virtio_net_unload_ebpf(VirtIONet *n)
130
+{
131
+ virtio_net_attach_ebpf_to_backend(n->nic, -1);
132
+ ebpf_rss_unload(&n->ebpf_rss);
133
}
60
}
134
61
135
static uint16_t virtio_net_handle_rss(VirtIONet *n,
62
@@ -XXX,XX +XXX,XX @@ static void lan9118_16bit_mode_write(void *opaque, hwaddr offset,
136
@@ -XXX,XX +XXX,XX @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
63
return;
137
goto error;
138
}
64
}
139
n->rss_data.enabled = true;
65
140
+
66
- hw_error("lan9118_write: Bad size 0x%x\n", size);
141
+ if (!n->rss_data.populate_hash) {
67
+ qemu_log_mask(LOG_GUEST_ERROR,
142
+ if (!virtio_net_attach_epbf_rss(n)) {
68
+ "lan9118_16bit_mode_write: Bad size 0x%x\n", size);
143
+ /* EBPF must be loaded for vhost */
69
}
144
+ if (get_vhost_net(qemu_get_queue(n->nic)->peer)) {
70
145
+ warn_report("Can't load eBPF RSS for vhost");
71
static uint64_t lan9118_readl(void *opaque, hwaddr offset,
146
+ goto error;
72
@@ -XXX,XX +XXX,XX @@ static uint64_t lan9118_16bit_mode_read(void *opaque, hwaddr offset,
147
+ }
73
return lan9118_readl(opaque, offset, size);
148
+ /* fallback to software RSS */
149
+ warn_report("Can't load eBPF RSS - fallback to software RSS");
150
+ n->rss_data.enabled_software_rss = true;
151
+ }
152
+ } else {
153
+ /* use software RSS for hash populating */
154
+ /* and detach eBPF if was loaded before */
155
+ virtio_net_detach_epbf_rss(n);
156
+ n->rss_data.enabled_software_rss = true;
157
+ }
158
+
159
trace_virtio_net_rss_enable(n->rss_data.hash_types,
160
n->rss_data.indirections_len,
161
temp.b);
162
@@ -XXX,XX +XXX,XX @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
163
return -1;
164
}
74
}
165
75
166
- if (!no_rss && n->rss_data.enabled) {
76
- hw_error("lan9118_read: Bad size 0x%x\n", size);
167
+ if (!no_rss && n->rss_data.enabled && n->rss_data.enabled_software_rss) {
77
+ qemu_log_mask(LOG_GUEST_ERROR,
168
int index = virtio_net_process_rss(nc, buf, size);
78
+ "lan9118_16bit_mode_read: Bad size 0x%x\n", size);
169
if (index >= 0) {
79
return 0;
170
NetClientState *nc2 = qemu_get_subqueue(n->nic, index);
171
@@ -XXX,XX +XXX,XX @@ static int virtio_net_post_load_device(void *opaque, int version_id)
172
}
173
174
if (n->rss_data.enabled) {
175
+ n->rss_data.enabled_software_rss = n->rss_data.populate_hash;
176
+ if (!n->rss_data.populate_hash) {
177
+ if (!virtio_net_attach_epbf_rss(n)) {
178
+ if (get_vhost_net(qemu_get_queue(n->nic)->peer)) {
179
+ warn_report("Can't post-load eBPF RSS for vhost");
180
+ } else {
181
+ warn_report("Can't post-load eBPF RSS - "
182
+ "fallback to software RSS");
183
+ n->rss_data.enabled_software_rss = true;
184
+ }
185
+ }
186
+ }
187
+
188
trace_virtio_net_rss_enable(n->rss_data.hash_types,
189
n->rss_data.indirections_len,
190
sizeof(n->rss_data.key));
191
@@ -XXX,XX +XXX,XX @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
192
n->qdev = dev;
193
194
net_rx_pkt_init(&n->rx_pkt, false);
195
+
196
+ if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
197
+ virtio_net_load_ebpf(n);
198
+ }
199
}
80
}
200
81
201
static void virtio_net_device_unrealize(DeviceState *dev)
202
@@ -XXX,XX +XXX,XX @@ static void virtio_net_device_unrealize(DeviceState *dev)
203
VirtIONet *n = VIRTIO_NET(dev);
204
int i, max_queues;
205
206
+ if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
207
+ virtio_net_unload_ebpf(n);
208
+ }
209
+
210
/* This will stop vhost backend if appropriate. */
211
virtio_net_set_status(vdev, 0);
212
213
@@ -XXX,XX +XXX,XX @@ static void virtio_net_instance_init(Object *obj)
214
device_add_bootindex_property(obj, &n->nic_conf.bootindex,
215
"bootindex", "/ethernet-phy@0",
216
DEVICE(n));
217
+
218
+ ebpf_rss_init(&n->ebpf_rss);
219
}
220
221
static int virtio_net_pre_save(void *opaque)
222
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
223
index XXXXXXX..XXXXXXX 100644
224
--- a/include/hw/virtio/virtio-net.h
225
+++ b/include/hw/virtio/virtio-net.h
226
@@ -XXX,XX +XXX,XX @@
227
#include "qemu/option_int.h"
228
#include "qom/object.h"
229
230
+#include "ebpf/ebpf_rss.h"
231
+
232
#define TYPE_VIRTIO_NET "virtio-net-device"
233
OBJECT_DECLARE_SIMPLE_TYPE(VirtIONet, VIRTIO_NET)
234
235
@@ -XXX,XX +XXX,XX @@ typedef struct VirtioNetRscChain {
236
237
typedef struct VirtioNetRssData {
238
bool enabled;
239
+ bool enabled_software_rss;
240
bool redirect;
241
bool populate_hash;
242
uint32_t hash_types;
243
@@ -XXX,XX +XXX,XX @@ struct VirtIONet {
244
Notifier migration_state;
245
VirtioNetRssData rss_data;
246
struct NetRxPkt *rx_pkt;
247
+ struct EBPFRSSContext ebpf_rss;
248
};
249
250
void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
251
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
252
index XXXXXXX..XXXXXXX 100644
253
--- a/net/vhost-vdpa.c
254
+++ b/net/vhost-vdpa.c
255
@@ -XXX,XX +XXX,XX @@ const int vdpa_feature_bits[] = {
256
VIRTIO_NET_F_MTU,
257
VIRTIO_F_IOMMU_PLATFORM,
258
VIRTIO_F_RING_PACKED,
259
+ VIRTIO_NET_F_RSS,
260
+ VIRTIO_NET_F_HASH_REPORT,
261
VIRTIO_NET_F_GUEST_ANNOUNCE,
262
VIRTIO_NET_F_STATUS,
263
VHOST_INVALID_FEATURE_BIT
264
--
82
--
265
2.7.4
83
2.7.4
266
84
267
85
diff view generated by jsdifflib
New patch
1
From: Fiona Ebner <f.ebner@proxmox.com>
1
2
3
Currently, VMXNET3_MAX_MTU itself (being 9000) is not considered a
4
valid value for the MTU, but a guest running ESXi 7.0 might try to
5
set it and fail the assert [0].
6
7
In the Linux kernel, dev->max_mtu itself is a valid value for the MTU
8
and for the vmxnet3 driver it's 9000, so a guest running Linux will
9
also fail the assert when trying to set an MTU of 9000.
10
11
VMXNET3_MAX_MTU and s->mtu don't seem to be used in relation to buffer
12
allocations/accesses, so allowing the upper limit itself as a value
13
should be fine.
14
15
[0]: https://forum.proxmox.com/threads/114011/
16
17
Fixes: d05dcd94ae ("net: vmxnet3: validate configuration values during activate (CVE-2021-20203)")
18
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
19
Signed-off-by: Jason Wang <jasowang@redhat.com>
20
---
21
hw/net/vmxnet3.c | 2 +-
22
1 file changed, 1 insertion(+), 1 deletion(-)
23
24
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/hw/net/vmxnet3.c
27
+++ b/hw/net/vmxnet3.c
28
@@ -XXX,XX +XXX,XX @@ static void vmxnet3_activate_device(VMXNET3State *s)
29
vmxnet3_setup_rx_filtering(s);
30
/* Cache fields from shared memory */
31
s->mtu = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, devRead.misc.mtu);
32
- assert(VMXNET3_MIN_MTU <= s->mtu && s->mtu < VMXNET3_MAX_MTU);
33
+ assert(VMXNET3_MIN_MTU <= s->mtu && s->mtu <= VMXNET3_MAX_MTU);
34
VMW_CFPRN("MTU is %u", s->mtu);
35
36
s->max_rx_frags =
37
--
38
2.7.4
diff view generated by jsdifflib
New patch
1
From: Christian Svensson <blue@cmd.nu>
1
2
3
Increase the allocated buffer size to fit larger packets.
4
Given that jumboframes can commonly be up to 9000 bytes the closest suitable
5
value seems to be 16 KiB.
6
7
Tested by running qemu towards a Linux L2TPv3 endpoint and pushing
8
jumboframe traffic through the interfaces.
9
10
Signed-off-by: Christian Svensson <blue@cmd.nu>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
13
net/l2tpv3.c | 2 +-
14
1 file changed, 1 insertion(+), 1 deletion(-)
15
16
diff --git a/net/l2tpv3.c b/net/l2tpv3.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/net/l2tpv3.c
19
+++ b/net/l2tpv3.c
20
@@ -XXX,XX +XXX,XX @@
21
*/
22
23
#define BUFFER_ALIGN sysconf(_SC_PAGESIZE)
24
-#define BUFFER_SIZE 2048
25
+#define BUFFER_SIZE 16384
26
#define IOVSIZE 2
27
#define MAX_L2TPV3_MSGCNT 64
28
#define MAX_L2TPV3_IOVCNT (MAX_L2TPV3_MSGCNT * IOVSIZE)
29
--
30
2.7.4
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Joelle van Dyne <j@getutm.app>
2
2
3
Added function that loads RSS eBPF program.
3
When the VM is stopped using the HMP command "stop", soon the handler will
4
Added stub functions for RSS eBPF loader.
4
stop reading from the vmnet interface. This causes a flood of
5
Added meson and configuration options.
5
`VMNET_INTERFACE_PACKETS_AVAILABLE` events to arrive and puts the host CPU
6
at 100%. We fix this by removing the event handler from vmnet when the VM
7
is no longer in a running state and restore it when we return to a running
8
state.
6
9
7
By default, eBPF feature enabled if libbpf is present in the build system.
10
Signed-off-by: Joelle van Dyne <j@getutm.app>
8
libbpf checked in configuration shell script and meson script.
9
10
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
11
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
12
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
13
---
12
---
14
configure | 8 +-
13
net/vmnet-common.m | 48 +++++++++++++++++++++++++++++++++++-------------
15
ebpf/ebpf_rss-stub.c | 40 +++++
14
net/vmnet_int.h | 2 ++
16
ebpf/ebpf_rss.c | 165 ++++++++++++++++++
15
2 files changed, 37 insertions(+), 13 deletions(-)
17
ebpf/ebpf_rss.h | 44 +++++
18
ebpf/meson.build | 1 +
19
ebpf/rss.bpf.skeleton.h | 431 ++++++++++++++++++++++++++++++++++++++++++++++++
20
ebpf/trace-events | 4 +
21
ebpf/trace.h | 1 +
22
meson.build | 23 +++
23
meson_options.txt | 2 +
24
10 files changed, 718 insertions(+), 1 deletion(-)
25
create mode 100644 ebpf/ebpf_rss-stub.c
26
create mode 100644 ebpf/ebpf_rss.c
27
create mode 100644 ebpf/ebpf_rss.h
28
create mode 100644 ebpf/meson.build
29
create mode 100644 ebpf/rss.bpf.skeleton.h
30
create mode 100644 ebpf/trace-events
31
create mode 100644 ebpf/trace.h
32
16
33
diff --git a/configure b/configure
17
diff --git a/net/vmnet-common.m b/net/vmnet-common.m
34
index XXXXXXX..XXXXXXX 100755
18
index XXXXXXX..XXXXXXX 100644
35
--- a/configure
19
--- a/net/vmnet-common.m
36
+++ b/configure
20
+++ b/net/vmnet-common.m
37
@@ -XXX,XX +XXX,XX @@ vhost_vsock="$default_feature"
38
vhost_user="no"
39
vhost_user_blk_server="auto"
40
vhost_user_fs="$default_feature"
41
+bpf="auto"
42
kvm="auto"
43
hax="auto"
44
hvf="auto"
45
@@ -XXX,XX +XXX,XX @@ for opt do
46
;;
47
--enable-membarrier) membarrier="yes"
48
;;
49
+ --disable-bpf) bpf="disabled"
50
+ ;;
51
+ --enable-bpf) bpf="enabled"
52
+ ;;
53
--disable-blobs) blobs="false"
54
;;
55
--with-pkgversion=*) pkgversion="$optarg"
56
@@ -XXX,XX +XXX,XX @@ disabled with --disable-FEATURE, default is enabled if available
57
vhost-user vhost-user backend support
58
vhost-user-blk-server vhost-user-blk server support
59
vhost-vdpa vhost-vdpa kernel backend support
60
+ bpf BPF kernel support
61
spice spice
62
spice-protocol spice-protocol
63
rbd rados block device (rbd)
64
@@ -XXX,XX +XXX,XX @@ if test "$skip_meson" = no; then
65
-Dattr=$attr -Ddefault_devices=$default_devices \
66
-Ddocs=$docs -Dsphinx_build=$sphinx_build -Dinstall_blobs=$blobs \
67
-Dvhost_user_blk_server=$vhost_user_blk_server -Dmultiprocess=$multiprocess \
68
- -Dfuse=$fuse -Dfuse_lseek=$fuse_lseek -Dguest_agent_msi=$guest_agent_msi \
69
+ -Dfuse=$fuse -Dfuse_lseek=$fuse_lseek -Dguest_agent_msi=$guest_agent_msi -Dbpf=$bpf\
70
$(if test "$default_features" = no; then echo "-Dauto_features=disabled"; fi) \
71
    -Dtcg_interpreter=$tcg_interpreter \
72
$cross_arg \
73
diff --git a/ebpf/ebpf_rss-stub.c b/ebpf/ebpf_rss-stub.c
74
new file mode 100644
75
index XXXXXXX..XXXXXXX
76
--- /dev/null
77
+++ b/ebpf/ebpf_rss-stub.c
78
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@
79
+/*
22
#include "clients.h"
80
+ * eBPF RSS stub file
23
#include "qemu/error-report.h"
81
+ *
24
#include "qapi/error.h"
82
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
25
+#include "sysemu/runstate.h"
83
+ *
26
84
+ * Authors:
27
#include <vmnet/vmnet.h>
85
+ * Yuri Benditovich <yuri.benditovich@daynix.com>
28
#include <dispatch/dispatch.h>
86
+ *
29
@@ -XXX,XX +XXX,XX @@ static void vmnet_bufs_init(VmnetState *s)
87
+ * This work is licensed under the terms of the GNU GPL, version 2. See
30
}
88
+ * the COPYING file in the top-level directory.
31
}
32
33
+/**
34
+ * Called on state change to un-register/re-register handlers
89
+ */
35
+ */
36
+static void vmnet_vm_state_change_cb(void *opaque, bool running, RunState state)
37
+{
38
+ VmnetState *s = opaque;
90
+
39
+
91
+#include "qemu/osdep.h"
40
+ if (running) {
92
+#include "ebpf/ebpf_rss.h"
41
+ vmnet_interface_set_event_callback(
93
+
42
+ s->vmnet_if,
94
+void ebpf_rss_init(struct EBPFRSSContext *ctx)
43
+ VMNET_INTERFACE_PACKETS_AVAILABLE,
95
+{
44
+ s->if_queue,
96
+
45
+ ^(interface_event_t event_id, xpc_object_t event) {
97
+}
46
+ assert(event_id == VMNET_INTERFACE_PACKETS_AVAILABLE);
98
+
47
+ /*
99
+bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx)
48
+ * This function is being called from a non qemu thread, so
100
+{
49
+ * we only schedule a BH, and do the rest of the io completion
101
+ return false;
50
+ * handling from vmnet_send_bh() which runs in a qemu context.
102
+}
51
+ */
103
+
52
+ qemu_bh_schedule(s->send_bh);
104
+bool ebpf_rss_load(struct EBPFRSSContext *ctx)
53
+ });
105
+{
54
+ } else {
106
+ return false;
55
+ vmnet_interface_set_event_callback(
107
+}
56
+ s->vmnet_if,
108
+
57
+ VMNET_INTERFACE_PACKETS_AVAILABLE,
109
+bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
58
+ NULL,
110
+ uint16_t *indirections_table, uint8_t *toeplitz_key)
59
+ NULL);
111
+{
112
+ return false;
113
+}
114
+
115
+void ebpf_rss_unload(struct EBPFRSSContext *ctx)
116
+{
117
+
118
+}
119
diff --git a/ebpf/ebpf_rss.c b/ebpf/ebpf_rss.c
120
new file mode 100644
121
index XXXXXXX..XXXXXXX
122
--- /dev/null
123
+++ b/ebpf/ebpf_rss.c
124
@@ -XXX,XX +XXX,XX @@
125
+/*
126
+ * eBPF RSS loader
127
+ *
128
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
129
+ *
130
+ * Authors:
131
+ * Andrew Melnychenko <andrew@daynix.com>
132
+ * Yuri Benditovich <yuri.benditovich@daynix.com>
133
+ *
134
+ * This work is licensed under the terms of the GNU GPL, version 2. See
135
+ * the COPYING file in the top-level directory.
136
+ */
137
+
138
+#include "qemu/osdep.h"
139
+#include "qemu/error-report.h"
140
+
141
+#include <bpf/libbpf.h>
142
+#include <bpf/bpf.h>
143
+
144
+#include "hw/virtio/virtio-net.h" /* VIRTIO_NET_RSS_MAX_TABLE_LEN */
145
+
146
+#include "ebpf/ebpf_rss.h"
147
+#include "ebpf/rss.bpf.skeleton.h"
148
+#include "trace.h"
149
+
150
+void ebpf_rss_init(struct EBPFRSSContext *ctx)
151
+{
152
+ if (ctx != NULL) {
153
+ ctx->obj = NULL;
154
+ }
60
+ }
155
+}
61
+}
62
63
int vmnet_if_create(NetClientState *nc,
64
xpc_object_t if_desc,
65
@@ -XXX,XX +XXX,XX @@ int vmnet_if_create(NetClientState *nc,
66
s->packets_send_current_pos = 0;
67
s->packets_send_end_pos = 0;
68
69
- vmnet_interface_set_event_callback(
70
- s->vmnet_if,
71
- VMNET_INTERFACE_PACKETS_AVAILABLE,
72
- s->if_queue,
73
- ^(interface_event_t event_id, xpc_object_t event) {
74
- assert(event_id == VMNET_INTERFACE_PACKETS_AVAILABLE);
75
- /*
76
- * This function is being called from a non qemu thread, so
77
- * we only schedule a BH, and do the rest of the io completion
78
- * handling from vmnet_send_bh() which runs in a qemu context.
79
- */
80
- qemu_bh_schedule(s->send_bh);
81
- });
82
+ vmnet_vm_state_change_cb(s, 1, RUN_STATE_RUNNING);
156
+
83
+
157
+bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx)
84
+ s->change = qemu_add_vm_change_state_handler(vmnet_vm_state_change_cb, s);
158
+{
85
159
+ return ctx != NULL && ctx->obj != NULL;
86
return 0;
160
+}
87
}
88
@@ -XXX,XX +XXX,XX @@ void vmnet_cleanup_common(NetClientState *nc)
89
return;
90
}
91
92
+ vmnet_vm_state_change_cb(s, 0, RUN_STATE_SHUTDOWN);
93
+ qemu_del_vm_change_state_handler(s->change);
94
if_stopped_sem = dispatch_semaphore_create(0);
95
vmnet_stop_interface(
96
s->vmnet_if,
97
diff --git a/net/vmnet_int.h b/net/vmnet_int.h
98
index XXXXXXX..XXXXXXX 100644
99
--- a/net/vmnet_int.h
100
+++ b/net/vmnet_int.h
101
@@ -XXX,XX +XXX,XX @@ typedef struct VmnetState {
102
int packets_send_end_pos;
103
104
struct iovec iov_buf[VMNET_PACKETS_LIMIT];
161
+
105
+
162
+bool ebpf_rss_load(struct EBPFRSSContext *ctx)
106
+ VMChangeStateEntry *change;
163
+{
107
} VmnetState;
164
+ struct rss_bpf *rss_bpf_ctx;
108
165
+
109
const char *vmnet_status_map_str(vmnet_return_t status);
166
+ if (ctx == NULL) {
167
+ return false;
168
+ }
169
+
170
+ rss_bpf_ctx = rss_bpf__open();
171
+ if (rss_bpf_ctx == NULL) {
172
+ trace_ebpf_error("eBPF RSS", "can not open eBPF RSS object");
173
+ goto error;
174
+ }
175
+
176
+ bpf_program__set_socket_filter(rss_bpf_ctx->progs.tun_rss_steering_prog);
177
+
178
+ if (rss_bpf__load(rss_bpf_ctx)) {
179
+ trace_ebpf_error("eBPF RSS", "can not load RSS program");
180
+ goto error;
181
+ }
182
+
183
+ ctx->obj = rss_bpf_ctx;
184
+ ctx->program_fd = bpf_program__fd(
185
+ rss_bpf_ctx->progs.tun_rss_steering_prog);
186
+ ctx->map_configuration = bpf_map__fd(
187
+ rss_bpf_ctx->maps.tap_rss_map_configurations);
188
+ ctx->map_indirections_table = bpf_map__fd(
189
+ rss_bpf_ctx->maps.tap_rss_map_indirection_table);
190
+ ctx->map_toeplitz_key = bpf_map__fd(
191
+ rss_bpf_ctx->maps.tap_rss_map_toeplitz_key);
192
+
193
+ return true;
194
+error:
195
+ rss_bpf__destroy(rss_bpf_ctx);
196
+ ctx->obj = NULL;
197
+
198
+ return false;
199
+}
200
+
201
+static bool ebpf_rss_set_config(struct EBPFRSSContext *ctx,
202
+ struct EBPFRSSConfig *config)
203
+{
204
+ uint32_t map_key = 0;
205
+
206
+ if (!ebpf_rss_is_loaded(ctx)) {
207
+ return false;
208
+ }
209
+ if (bpf_map_update_elem(ctx->map_configuration,
210
+ &map_key, config, 0) < 0) {
211
+ return false;
212
+ }
213
+ return true;
214
+}
215
+
216
+static bool ebpf_rss_set_indirections_table(struct EBPFRSSContext *ctx,
217
+ uint16_t *indirections_table,
218
+ size_t len)
219
+{
220
+ uint32_t i = 0;
221
+
222
+ if (!ebpf_rss_is_loaded(ctx) || indirections_table == NULL ||
223
+ len > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
224
+ return false;
225
+ }
226
+
227
+ for (; i < len; ++i) {
228
+ if (bpf_map_update_elem(ctx->map_indirections_table, &i,
229
+ indirections_table + i, 0) < 0) {
230
+ return false;
231
+ }
232
+ }
233
+ return true;
234
+}
235
+
236
+static bool ebpf_rss_set_toepliz_key(struct EBPFRSSContext *ctx,
237
+ uint8_t *toeplitz_key)
238
+{
239
+ uint32_t map_key = 0;
240
+
241
+ /* prepare toeplitz key */
242
+ uint8_t toe[VIRTIO_NET_RSS_MAX_KEY_SIZE] = {};
243
+
244
+ if (!ebpf_rss_is_loaded(ctx) || toeplitz_key == NULL) {
245
+ return false;
246
+ }
247
+ memcpy(toe, toeplitz_key, VIRTIO_NET_RSS_MAX_KEY_SIZE);
248
+ *(uint32_t *)toe = ntohl(*(uint32_t *)toe);
249
+
250
+ if (bpf_map_update_elem(ctx->map_toeplitz_key, &map_key, toe,
251
+ 0) < 0) {
252
+ return false;
253
+ }
254
+ return true;
255
+}
256
+
257
+bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
258
+ uint16_t *indirections_table, uint8_t *toeplitz_key)
259
+{
260
+ if (!ebpf_rss_is_loaded(ctx) || config == NULL ||
261
+ indirections_table == NULL || toeplitz_key == NULL) {
262
+ return false;
263
+ }
264
+
265
+ if (!ebpf_rss_set_config(ctx, config)) {
266
+ return false;
267
+ }
268
+
269
+ if (!ebpf_rss_set_indirections_table(ctx, indirections_table,
270
+ config->indirections_len)) {
271
+ return false;
272
+ }
273
+
274
+ if (!ebpf_rss_set_toepliz_key(ctx, toeplitz_key)) {
275
+ return false;
276
+ }
277
+
278
+ return true;
279
+}
280
+
281
+void ebpf_rss_unload(struct EBPFRSSContext *ctx)
282
+{
283
+ if (!ebpf_rss_is_loaded(ctx)) {
284
+ return;
285
+ }
286
+
287
+ rss_bpf__destroy(ctx->obj);
288
+ ctx->obj = NULL;
289
+}
290
diff --git a/ebpf/ebpf_rss.h b/ebpf/ebpf_rss.h
291
new file mode 100644
292
index XXXXXXX..XXXXXXX
293
--- /dev/null
294
+++ b/ebpf/ebpf_rss.h
295
@@ -XXX,XX +XXX,XX @@
296
+/*
297
+ * eBPF RSS header
298
+ *
299
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
300
+ *
301
+ * Authors:
302
+ * Andrew Melnychenko <andrew@daynix.com>
303
+ * Yuri Benditovich <yuri.benditovich@daynix.com>
304
+ *
305
+ * This work is licensed under the terms of the GNU GPL, version 2. See
306
+ * the COPYING file in the top-level directory.
307
+ */
308
+
309
+#ifndef QEMU_EBPF_RSS_H
310
+#define QEMU_EBPF_RSS_H
311
+
312
+struct EBPFRSSContext {
313
+ void *obj;
314
+ int program_fd;
315
+ int map_configuration;
316
+ int map_toeplitz_key;
317
+ int map_indirections_table;
318
+};
319
+
320
+struct EBPFRSSConfig {
321
+ uint8_t redirect;
322
+ uint8_t populate_hash;
323
+ uint32_t hash_types;
324
+ uint16_t indirections_len;
325
+ uint16_t default_queue;
326
+} __attribute__((packed));
327
+
328
+void ebpf_rss_init(struct EBPFRSSContext *ctx);
329
+
330
+bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx);
331
+
332
+bool ebpf_rss_load(struct EBPFRSSContext *ctx);
333
+
334
+bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
335
+ uint16_t *indirections_table, uint8_t *toeplitz_key);
336
+
337
+void ebpf_rss_unload(struct EBPFRSSContext *ctx);
338
+
339
+#endif /* QEMU_EBPF_RSS_H */
340
diff --git a/ebpf/meson.build b/ebpf/meson.build
341
new file mode 100644
342
index XXXXXXX..XXXXXXX
343
--- /dev/null
344
+++ b/ebpf/meson.build
345
@@ -0,0 +1 @@
346
+common_ss.add(when: libbpf, if_true: files('ebpf_rss.c'), if_false: files('ebpf_rss-stub.c'))
347
diff --git a/ebpf/rss.bpf.skeleton.h b/ebpf/rss.bpf.skeleton.h
348
new file mode 100644
349
index XXXXXXX..XXXXXXX
350
--- /dev/null
351
+++ b/ebpf/rss.bpf.skeleton.h
352
@@ -XXX,XX +XXX,XX @@
353
+/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
354
+
355
+/* THIS FILE IS AUTOGENERATED! */
356
+#ifndef __RSS_BPF_SKEL_H__
357
+#define __RSS_BPF_SKEL_H__
358
+
359
+#include <stdlib.h>
360
+#include <bpf/libbpf.h>
361
+
362
+struct rss_bpf {
363
+    struct bpf_object_skeleton *skeleton;
364
+    struct bpf_object *obj;
365
+    struct {
366
+        struct bpf_map *tap_rss_map_configurations;
367
+        struct bpf_map *tap_rss_map_indirection_table;
368
+        struct bpf_map *tap_rss_map_toeplitz_key;
369
+    } maps;
370
+    struct {
371
+        struct bpf_program *tun_rss_steering_prog;
372
+    } progs;
373
+    struct {
374
+        struct bpf_link *tun_rss_steering_prog;
375
+    } links;
376
+};
377
+
378
+static void
379
+rss_bpf__destroy(struct rss_bpf *obj)
380
+{
381
+    if (!obj)
382
+        return;
383
+    if (obj->skeleton)
384
+        bpf_object__destroy_skeleton(obj->skeleton);
385
+    free(obj);
386
+}
387
+
388
+static inline int
389
+rss_bpf__create_skeleton(struct rss_bpf *obj);
390
+
391
+static inline struct rss_bpf *
392
+rss_bpf__open_opts(const struct bpf_object_open_opts *opts)
393
+{
394
+    struct rss_bpf *obj;
395
+
396
+    obj = (struct rss_bpf *)calloc(1, sizeof(*obj));
397
+    if (!obj)
398
+        return NULL;
399
+    if (rss_bpf__create_skeleton(obj))
400
+        goto err;
401
+    if (bpf_object__open_skeleton(obj->skeleton, opts))
402
+        goto err;
403
+
404
+    return obj;
405
+err:
406
+    rss_bpf__destroy(obj);
407
+    return NULL;
408
+}
409
+
410
+static inline struct rss_bpf *
411
+rss_bpf__open(void)
412
+{
413
+    return rss_bpf__open_opts(NULL);
414
+}
415
+
416
+static inline int
417
+rss_bpf__load(struct rss_bpf *obj)
418
+{
419
+    return bpf_object__load_skeleton(obj->skeleton);
420
+}
421
+
422
+static inline struct rss_bpf *
423
+rss_bpf__open_and_load(void)
424
+{
425
+    struct rss_bpf *obj;
426
+
427
+    obj = rss_bpf__open();
428
+    if (!obj)
429
+        return NULL;
430
+    if (rss_bpf__load(obj)) {
431
+        rss_bpf__destroy(obj);
432
+        return NULL;
433
+    }
434
+    return obj;
435
+}
436
+
437
+static inline int
438
+rss_bpf__attach(struct rss_bpf *obj)
439
+{
440
+    return bpf_object__attach_skeleton(obj->skeleton);
441
+}
442
+
443
+static inline void
444
+rss_bpf__detach(struct rss_bpf *obj)
445
+{
446
+    return bpf_object__detach_skeleton(obj->skeleton);
447
+}
448
+
449
+static inline int
450
+rss_bpf__create_skeleton(struct rss_bpf *obj)
451
+{
452
+    struct bpf_object_skeleton *s;
453
+
454
+    s = (struct bpf_object_skeleton *)calloc(1, sizeof(*s));
455
+    if (!s)
456
+        return -1;
457
+    obj->skeleton = s;
458
+
459
+    s->sz = sizeof(*s);
460
+    s->name = "rss_bpf";
461
+    s->obj = &obj->obj;
462
+
463
+    /* maps */
464
+    s->map_cnt = 3;
465
+    s->map_skel_sz = sizeof(*s->maps);
466
+    s->maps = (struct bpf_map_skeleton *)calloc(s->map_cnt, s->map_skel_sz);
467
+    if (!s->maps)
468
+        goto err;
469
+
470
+    s->maps[0].name = "tap_rss_map_configurations";
471
+    s->maps[0].map = &obj->maps.tap_rss_map_configurations;
472
+
473
+    s->maps[1].name = "tap_rss_map_indirection_table";
474
+    s->maps[1].map = &obj->maps.tap_rss_map_indirection_table;
475
+
476
+    s->maps[2].name = "tap_rss_map_toeplitz_key";
477
+    s->maps[2].map = &obj->maps.tap_rss_map_toeplitz_key;
478
+
479
+    /* programs */
480
+    s->prog_cnt = 1;
481
+    s->prog_skel_sz = sizeof(*s->progs);
482
+    s->progs = (struct bpf_prog_skeleton *)calloc(s->prog_cnt, s->prog_skel_sz);
483
+    if (!s->progs)
484
+        goto err;
485
+
486
+    s->progs[0].name = "tun_rss_steering_prog";
487
+    s->progs[0].prog = &obj->progs.tun_rss_steering_prog;
488
+    s->progs[0].link = &obj->links.tun_rss_steering_prog;
489
+
490
+    s->data_sz = 8088;
491
+    s->data = (void *)"\
492
+\x7f\x45\x4c\x46\x02\x01\x01\0\0\0\0\0\0\0\0\0\x01\0\xf7\0\x01\0\0\0\0\0\0\0\0\
493
+\0\0\0\0\0\0\0\0\0\0\0\x18\x1d\0\0\0\0\0\0\0\0\0\0\x40\0\0\0\0\0\x40\0\x0a\0\
494
+\x01\0\xbf\x18\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\x4c\xff\0\0\0\0\xbf\xa7\
495
+\0\0\0\0\0\0\x07\x07\0\0\x4c\xff\xff\xff\x18\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
496
+\xbf\x72\0\0\0\0\0\0\x85\0\0\0\x01\0\0\0\xbf\x06\0\0\0\0\0\0\x18\x01\0\0\0\0\0\
497
+\0\0\0\0\0\0\0\0\0\xbf\x72\0\0\0\0\0\0\x85\0\0\0\x01\0\0\0\xbf\x07\0\0\0\0\0\0\
498
+\x18\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0\x15\x06\x66\x02\0\0\0\0\xbf\x79\0\0\
499
+\0\0\0\0\x15\x09\x64\x02\0\0\0\0\x71\x61\0\0\0\0\0\0\x55\x01\x01\0\0\0\0\0\x05\
500
+\0\x5d\x02\0\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\xc0\xff\0\0\0\0\x7b\x1a\xb8\xff\
501
+\0\0\0\0\x7b\x1a\xb0\xff\0\0\0\0\x7b\x1a\xa8\xff\0\0\0\0\x7b\x1a\xa0\xff\0\0\0\
502
+\0\x63\x1a\x98\xff\0\0\0\0\x7b\x1a\x90\xff\0\0\0\0\x7b\x1a\x88\xff\0\0\0\0\x7b\
503
+\x1a\x80\xff\0\0\0\0\x7b\x1a\x78\xff\0\0\0\0\x7b\x1a\x70\xff\0\0\0\0\x7b\x1a\
504
+\x68\xff\0\0\0\0\x7b\x1a\x60\xff\0\0\0\0\x7b\x1a\x58\xff\0\0\0\0\x7b\x1a\x50\
505
+\xff\0\0\0\0\x15\x08\x4c\x02\0\0\0\0\x6b\x1a\xd0\xff\0\0\0\0\xbf\xa3\0\0\0\0\0\
506
+\0\x07\x03\0\0\xd0\xff\xff\xff\xbf\x81\0\0\0\0\0\0\xb7\x02\0\0\x0c\0\0\0\xb7\
507
+\x04\0\0\x02\0\0\0\xb7\x05\0\0\0\0\0\0\x85\0\0\0\x44\0\0\0\x67\0\0\0\x20\0\0\0\
508
+\x77\0\0\0\x20\0\0\0\x55\0\x11\0\0\0\0\0\xb7\x02\0\0\x10\0\0\0\x69\xa1\xd0\xff\
509
+\0\0\0\0\xbf\x13\0\0\0\0\0\0\xdc\x03\0\0\x10\0\0\0\x15\x03\x02\0\0\x81\0\0\x55\
510
+\x03\x0c\0\xa8\x88\0\0\xb7\x02\0\0\x14\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\
511
+\xd0\xff\xff\xff\xbf\x81\0\0\0\0\0\0\xb7\x04\0\0\x02\0\0\0\xb7\x05\0\0\0\0\0\0\
512
+\x85\0\0\0\x44\0\0\0\x69\xa1\xd0\xff\0\0\0\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\
513
+\0\0\0\x15\0\x01\0\0\0\0\0\x05\0\x2f\x02\0\0\0\0\x15\x01\x2e\x02\0\0\0\0\x7b\
514
+\x9a\x30\xff\0\0\0\0\x15\x01\x57\0\x86\xdd\0\0\x55\x01\x3b\0\x08\0\0\0\x7b\x7a\
515
+\x20\xff\0\0\0\0\xb7\x07\0\0\x01\0\0\0\x73\x7a\x50\xff\0\0\0\0\xb7\x01\0\0\0\0\
516
+\0\0\x63\x1a\xe0\xff\0\0\0\0\x7b\x1a\xd8\xff\0\0\0\0\x7b\x1a\xd0\xff\0\0\0\0\
517
+\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xd0\xff\xff\xff\xbf\x81\0\0\0\0\0\0\xb7\x02\0\
518
+\0\0\0\0\0\xb7\x04\0\0\x14\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\x67\
519
+\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x55\0\x1a\x02\0\0\0\0\x69\xa1\xd6\xff\0\0\
520
+\0\0\x55\x01\x01\0\0\0\0\0\xb7\x07\0\0\0\0\0\0\x61\xa1\xdc\xff\0\0\0\0\x63\x1a\
521
+\x5c\xff\0\0\0\0\x61\xa1\xe0\xff\0\0\0\0\x63\x1a\x60\xff\0\0\0\0\x73\x7a\x56\
522
+\xff\0\0\0\0\x71\xa9\xd9\xff\0\0\0\0\x71\xa1\xd0\xff\0\0\0\0\x67\x01\0\0\x02\0\
523
+\0\0\x57\x01\0\0\x3c\0\0\0\x7b\x1a\x40\xff\0\0\0\0\x79\xa7\x20\xff\0\0\0\0\xbf\
524
+\x91\0\0\0\0\0\0\x57\x01\0\0\xff\0\0\0\x15\x01\x19\0\0\0\0\0\x71\xa1\x56\xff\0\
525
+\0\0\0\x55\x01\x17\0\0\0\0\0\x57\x09\0\0\xff\0\0\0\x15\x09\x7a\x01\x11\0\0\0\
526
+\x55\x09\x14\0\x06\0\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x53\xff\0\0\0\0\xb7\x01\
527
+\0\0\0\0\0\0\x63\x1a\xe0\xff\0\0\0\0\x7b\x1a\xd8\xff\0\0\0\0\x7b\x1a\xd0\xff\0\
528
+\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xd0\xff\xff\xff\xbf\x81\0\0\0\0\0\0\x79\
529
+\xa2\x40\xff\0\0\0\0\xb7\x04\0\0\x14\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\
530
+\0\0\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x55\0\xf4\x01\0\0\0\0\x69\xa1\
531
+\xd0\xff\0\0\0\0\x6b\x1a\x58\xff\0\0\0\0\x69\xa1\xd2\xff\0\0\0\0\x6b\x1a\x5a\
532
+\xff\0\0\0\0\x71\xa1\x50\xff\0\0\0\0\x15\x01\xd4\0\0\0\0\0\x71\x62\x03\0\0\0\0\
533
+\0\x67\x02\0\0\x08\0\0\0\x71\x61\x02\0\0\0\0\0\x4f\x12\0\0\0\0\0\0\x71\x63\x04\
534
+\0\0\0\0\0\x71\x61\x05\0\0\0\0\0\x67\x01\0\0\x08\0\0\0\x4f\x31\0\0\0\0\0\0\x67\
535
+\x01\0\0\x10\0\0\0\x4f\x21\0\0\0\0\0\0\x71\xa2\x53\xff\0\0\0\0\x79\xa0\x30\xff\
536
+\0\0\0\0\x15\x02\x06\x01\0\0\0\0\xbf\x12\0\0\0\0\0\0\x57\x02\0\0\x02\0\0\0\x15\
537
+\x02\x03\x01\0\0\0\0\x61\xa1\x5c\xff\0\0\0\0\x63\x1a\xa0\xff\0\0\0\0\x61\xa1\
538
+\x60\xff\0\0\0\0\x63\x1a\xa4\xff\0\0\0\0\x69\xa1\x58\xff\0\0\0\0\x6b\x1a\xa8\
539
+\xff\0\0\0\0\x69\xa1\x5a\xff\0\0\0\0\x6b\x1a\xaa\xff\0\0\0\0\x05\0\x65\x01\0\0\
540
+\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x51\xff\0\0\0\0\xb7\x01\0\0\0\0\0\0\x7b\x1a\
541
+\xf0\xff\0\0\0\0\x7b\x1a\xe8\xff\0\0\0\0\x7b\x1a\xe0\xff\0\0\0\0\x7b\x1a\xd8\
542
+\xff\0\0\0\0\x7b\x1a\xd0\xff\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xd0\xff\
543
+\xff\xff\xb7\x01\0\0\x28\0\0\0\x7b\x1a\x40\xff\0\0\0\0\xbf\x81\0\0\0\0\0\0\xb7\
544
+\x02\0\0\0\0\0\0\xb7\x04\0\0\x28\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\
545
+\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x55\0\x10\x01\0\0\0\0\x79\xa1\xe0\
546
+\xff\0\0\0\0\x63\x1a\x64\xff\0\0\0\0\x77\x01\0\0\x20\0\0\0\x63\x1a\x68\xff\0\0\
547
+\0\0\x79\xa1\xd8\xff\0\0\0\0\x63\x1a\x5c\xff\0\0\0\0\x77\x01\0\0\x20\0\0\0\x63\
548
+\x1a\x60\xff\0\0\0\0\x79\xa1\xe8\xff\0\0\0\0\x63\x1a\x6c\xff\0\0\0\0\x77\x01\0\
549
+\0\x20\0\0\0\x63\x1a\x70\xff\0\0\0\0\x79\xa1\xf0\xff\0\0\0\0\x63\x1a\x74\xff\0\
550
+\0\0\0\x77\x01\0\0\x20\0\0\0\x63\x1a\x78\xff\0\0\0\0\x71\xa9\xd6\xff\0\0\0\0\
551
+\x25\x09\xff\0\x3c\0\0\0\xb7\x01\0\0\x01\0\0\0\x6f\x91\0\0\0\0\0\0\x18\x02\0\0\
552
+\x01\0\0\0\0\0\0\0\0\x18\0\x1c\x5f\x21\0\0\0\0\0\0\x55\x01\x01\0\0\0\0\0\x05\0\
553
+\xf8\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x6b\x1a\xfe\xff\0\0\0\0\xb7\x01\0\0\x28\0\0\
554
+\0\x7b\x1a\x40\xff\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\x8c\xff\xff\xff\x7b\
555
+\x1a\x18\xff\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\x7c\xff\xff\xff\x7b\x1a\
556
+\x10\xff\0\0\0\0\xb7\x01\0\0\0\0\0\0\x7b\x1a\x28\xff\0\0\0\0\x7b\x7a\x20\xff\0\
557
+\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xfe\xff\xff\xff\xbf\x81\0\0\0\0\0\0\x79\
558
+\xa2\x40\xff\0\0\0\0\xb7\x04\0\0\x02\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\
559
+\0\0\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x15\0\x01\0\0\0\0\0\x05\0\x90\
560
+\x01\0\0\0\0\xbf\x91\0\0\0\0\0\0\x15\x01\x23\0\x3c\0\0\0\x15\x01\x59\0\x2c\0\0\
561
+\0\x55\x01\x5a\0\x2b\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\xf8\xff\0\0\0\0\xbf\xa3\
562
+\0\0\0\0\0\0\x07\x03\0\0\xf8\xff\xff\xff\xbf\x81\0\0\0\0\0\0\x79\xa2\x40\xff\0\
563
+\0\0\0\xb7\x04\0\0\x04\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\xbf\x01\
564
+\0\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x55\x01\x03\x01\0\0\0\
565
+\0\x71\xa1\xfa\xff\0\0\0\0\x55\x01\x4b\0\x02\0\0\0\x71\xa1\xf9\xff\0\0\0\0\x55\
566
+\x01\x49\0\x02\0\0\0\x71\xa1\xfb\xff\0\0\0\0\x55\x01\x47\0\x01\0\0\0\x79\xa2\
567
+\x40\xff\0\0\0\0\x07\x02\0\0\x08\0\0\0\xbf\x81\0\0\0\0\0\0\x79\xa3\x18\xff\0\0\
568
+\0\0\xb7\x04\0\0\x10\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\xbf\x01\0\
569
+\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x55\x01\xf2\0\0\0\0\0\
570
+\xb7\x01\0\0\x01\0\0\0\x73\x1a\x55\xff\0\0\0\0\x05\0\x39\0\0\0\0\0\xb7\x01\0\0\
571
+\0\0\0\0\x6b\x1a\xf8\xff\0\0\0\0\xb7\x09\0\0\x02\0\0\0\xb7\x07\0\0\x1e\0\0\0\
572
+\x05\0\x0e\0\0\0\0\0\x79\xa2\x38\xff\0\0\0\0\x0f\x29\0\0\0\0\0\0\xbf\x92\0\0\0\
573
+\0\0\0\x07\x02\0\0\x01\0\0\0\x71\xa3\xff\xff\0\0\0\0\x67\x03\0\0\x03\0\0\0\x2d\
574
+\x23\x02\0\0\0\0\0\x79\xa7\x20\xff\0\0\0\0\x05\0\x2b\0\0\0\0\0\x07\x07\0\0\xff\
575
+\xff\xff\xff\xbf\x72\0\0\0\0\0\0\x67\x02\0\0\x20\0\0\0\x77\x02\0\0\x20\0\0\0\
576
+\x15\x02\xf9\xff\0\0\0\0\x7b\x9a\x38\xff\0\0\0\0\x79\xa1\x40\xff\0\0\0\0\x0f\
577
+\x19\0\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xf8\xff\xff\xff\xbf\x81\0\0\0\
578
+\0\0\0\xbf\x92\0\0\0\0\0\0\xb7\x04\0\0\x02\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\
579
+\0\x44\0\0\0\xbf\x01\0\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\
580
+\x55\x01\x94\0\0\0\0\0\x71\xa2\xf8\xff\0\0\0\0\x55\x02\x0f\0\xc9\0\0\0\x07\x09\
581
+\0\0\x02\0\0\0\xbf\x81\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x79\xa3\x10\xff\0\0\0\0\
582
+\xb7\x04\0\0\x10\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\xbf\x01\0\0\0\
583
+\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x55\x01\x87\0\0\0\0\0\xb7\
584
+\x01\0\0\x01\0\0\0\x73\x1a\x54\xff\0\0\0\0\x79\xa7\x20\xff\0\0\0\0\x05\0\x07\0\
585
+\0\0\0\0\xb7\x09\0\0\x01\0\0\0\x15\x02\xd1\xff\0\0\0\0\x71\xa9\xf9\xff\0\0\0\0\
586
+\x07\x09\0\0\x02\0\0\0\x05\0\xce\xff\0\0\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x56\
587
+\xff\0\0\0\0\x71\xa1\xff\xff\0\0\0\0\x67\x01\0\0\x03\0\0\0\x79\xa2\x40\xff\0\0\
588
+\0\0\x0f\x12\0\0\0\0\0\0\x07\x02\0\0\x08\0\0\0\x7b\x2a\x40\xff\0\0\0\0\x71\xa9\
589
+\xfe\xff\0\0\0\0\x25\x09\x0e\0\x3c\0\0\0\xb7\x01\0\0\x01\0\0\0\x6f\x91\0\0\0\0\
590
+\0\0\x18\x02\0\0\x01\0\0\0\0\0\0\0\0\x18\0\x1c\x5f\x21\0\0\0\0\0\0\x55\x01\x01\
591
+\0\0\0\0\0\x05\0\x07\0\0\0\0\0\x79\xa1\x28\xff\0\0\0\0\x07\x01\0\0\x01\0\0\0\
592
+\x7b\x1a\x28\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x55\x01\
593
+\x82\xff\x0b\0\0\0\x05\0\x10\xff\0\0\0\0\x15\x09\xf8\xff\x87\0\0\0\x05\0\xfd\
594
+\xff\0\0\0\0\x71\xa1\x51\xff\0\0\0\0\x79\xa0\x30\xff\0\0\0\0\x15\x01\x17\x01\0\
595
+\0\0\0\x71\x62\x03\0\0\0\0\0\x67\x02\0\0\x08\0\0\0\x71\x61\x02\0\0\0\0\0\x4f\
596
+\x12\0\0\0\0\0\0\x71\x63\x04\0\0\0\0\0\x71\x61\x05\0\0\0\0\0\x67\x01\0\0\x08\0\
597
+\0\0\x4f\x31\0\0\0\0\0\0\x67\x01\0\0\x10\0\0\0\x4f\x21\0\0\0\0\0\0\x71\xa2\x53\
598
+\xff\0\0\0\0\x15\x02\x3d\0\0\0\0\0\xbf\x12\0\0\0\0\0\0\x57\x02\0\0\x10\0\0\0\
599
+\x15\x02\x3a\0\0\0\0\0\xbf\xa2\0\0\0\0\0\0\x07\x02\0\0\x5c\xff\xff\xff\x71\xa4\
600
+\x54\xff\0\0\0\0\xbf\x23\0\0\0\0\0\0\x15\x04\x02\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\
601
+\x07\x03\0\0\x7c\xff\xff\xff\x67\x01\0\0\x38\0\0\0\xc7\x01\0\0\x38\0\0\0\x65\
602
+\x01\x01\0\xff\xff\xff\xff\xbf\x32\0\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\
603
+\x6c\xff\xff\xff\x71\xa5\x55\xff\0\0\0\0\xbf\x34\0\0\0\0\0\0\x15\x05\x02\0\0\0\
604
+\0\0\xbf\xa4\0\0\0\0\0\0\x07\x04\0\0\x8c\xff\xff\xff\x65\x01\x01\0\xff\xff\xff\
605
+\xff\xbf\x43\0\0\0\0\0\0\x61\x21\x04\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\x24\0\
606
+\0\0\0\0\0\x4f\x41\0\0\0\0\0\0\x7b\x1a\xa0\xff\0\0\0\0\x61\x21\x08\0\0\0\0\0\
607
+\x61\x22\x0c\0\0\0\0\0\x67\x02\0\0\x20\0\0\0\x4f\x12\0\0\0\0\0\0\x7b\x2a\xa8\
608
+\xff\0\0\0\0\x61\x31\0\0\0\0\0\0\x61\x32\x04\0\0\0\0\0\x61\x34\x08\0\0\0\0\0\
609
+\x61\x33\x0c\0\0\0\0\0\x69\xa5\x5a\xff\0\0\0\0\x6b\x5a\xc2\xff\0\0\0\0\x69\xa5\
610
+\x58\xff\0\0\0\0\x6b\x5a\xc0\xff\0\0\0\0\x67\x03\0\0\x20\0\0\0\x4f\x43\0\0\0\0\
611
+\0\0\x7b\x3a\xb8\xff\0\0\0\0\x67\x02\0\0\x20\0\0\0\x4f\x12\0\0\0\0\0\0\x7b\x2a\
612
+\xb0\xff\0\0\0\0\x05\0\x6b\0\0\0\0\0\x71\xa2\x52\xff\0\0\0\0\x15\x02\x04\0\0\0\
613
+\0\0\xbf\x12\0\0\0\0\0\0\x57\x02\0\0\x04\0\0\0\x15\x02\x01\0\0\0\0\0\x05\0\xf7\
614
+\xfe\0\0\0\0\x57\x01\0\0\x01\0\0\0\x15\x01\xd3\0\0\0\0\0\x61\xa1\x5c\xff\0\0\0\
615
+\0\x63\x1a\xa0\xff\0\0\0\0\x61\xa1\x60\xff\0\0\0\0\x63\x1a\xa4\xff\0\0\0\0\x05\
616
+\0\x5e\0\0\0\0\0\x71\xa2\x52\xff\0\0\0\0\x15\x02\x1e\0\0\0\0\0\xbf\x12\0\0\0\0\
617
+\0\0\x57\x02\0\0\x20\0\0\0\x15\x02\x1b\0\0\0\0\0\xbf\xa2\0\0\0\0\0\0\x07\x02\0\
618
+\0\x5c\xff\xff\xff\x71\xa4\x54\xff\0\0\0\0\xbf\x23\0\0\0\0\0\0\x15\x04\x02\0\0\
619
+\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\x7c\xff\xff\xff\x57\x01\0\0\0\x01\0\0\
620
+\x15\x01\x01\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\x6c\
621
+\xff\xff\xff\x71\xa5\x55\xff\0\0\0\0\xbf\x34\0\0\0\0\0\0\x15\x05\x02\0\0\0\0\0\
622
+\xbf\xa4\0\0\0\0\0\0\x07\x04\0\0\x8c\xff\xff\xff\x15\x01\xc3\xff\0\0\0\0\x05\0\
623
+\xc1\xff\0\0\0\0\xb7\x09\0\0\x3c\0\0\0\x79\xa7\x20\xff\0\0\0\0\x67\0\0\0\x20\0\
624
+\0\0\x77\0\0\0\x20\0\0\0\x15\0\xa5\xfe\0\0\0\0\x05\0\xb0\0\0\0\0\0\x15\x09\x07\
625
+\xff\x87\0\0\0\x05\0\xa2\xfe\0\0\0\0\xbf\x12\0\0\0\0\0\0\x57\x02\0\0\x08\0\0\0\
626
+\x15\x02\xab\0\0\0\0\0\xbf\xa2\0\0\0\0\0\0\x07\x02\0\0\x5c\xff\xff\xff\x71\xa4\
627
+\x54\xff\0\0\0\0\xbf\x23\0\0\0\0\0\0\x15\x04\x02\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\
628
+\x07\x03\0\0\x7c\xff\xff\xff\x57\x01\0\0\x40\0\0\0\x15\x01\x01\0\0\0\0\0\xbf\
629
+\x32\0\0\0\0\0\0\x61\x23\x04\0\0\0\0\0\x67\x03\0\0\x20\0\0\0\x61\x24\0\0\0\0\0\
630
+\0\x4f\x43\0\0\0\0\0\0\x7b\x3a\xa0\xff\0\0\0\0\x61\x23\x08\0\0\0\0\0\x61\x22\
631
+\x0c\0\0\0\0\0\x67\x02\0\0\x20\0\0\0\x4f\x32\0\0\0\0\0\0\x7b\x2a\xa8\xff\0\0\0\
632
+\0\x15\x01\x1c\0\0\0\0\0\x71\xa1\x55\xff\0\0\0\0\x15\x01\x1a\0\0\0\0\0\x61\xa1\
633
+\x98\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\xa2\x94\xff\0\0\0\0\x4f\x21\0\0\0\0\
634
+\0\0\x7b\x1a\xb8\xff\0\0\0\0\x61\xa1\x90\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\
635
+\xa2\x8c\xff\0\0\0\0\x05\0\x19\0\0\0\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x52\xff\
636
+\0\0\0\0\xb7\x01\0\0\0\0\0\0\x7b\x1a\xd0\xff\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\
637
+\x03\0\0\xd0\xff\xff\xff\xbf\x81\0\0\0\0\0\0\x79\xa2\x40\xff\0\0\0\0\xb7\x04\0\
638
+\0\x08\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\x67\0\0\0\x20\0\0\0\x77\
639
+\0\0\0\x20\0\0\0\x55\0\x7d\0\0\0\0\0\x05\0\x88\xfe\0\0\0\0\xb7\x09\0\0\x2b\0\0\
640
+\0\x05\0\xc6\xff\0\0\0\0\x61\xa1\x78\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\xa2\
641
+\x74\xff\0\0\0\0\x4f\x21\0\0\0\0\0\0\x7b\x1a\xb8\xff\0\0\0\0\x61\xa1\x70\xff\0\
642
+\0\0\0\x67\x01\0\0\x20\0\0\0\x61\xa2\x6c\xff\0\0\0\0\x4f\x21\0\0\0\0\0\0\x7b\
643
+\x1a\xb0\xff\0\0\0\0\xb7\x01\0\0\0\0\0\0\x07\x07\0\0\x04\0\0\0\x61\x03\0\0\0\0\
644
+\0\0\xb7\x05\0\0\0\0\0\0\x05\0\x4e\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x75\0\0\0\
645
+\0\0\0\x0f\x15\0\0\0\0\0\0\x71\x55\0\0\0\0\0\0\x67\x03\0\0\x01\0\0\0\xbf\x50\0\
646
+\0\0\0\0\0\x77\0\0\0\x07\0\0\0\x4f\x03\0\0\0\0\0\0\xbf\x40\0\0\0\0\0\0\x67\0\0\
647
+\0\x39\0\0\0\xc7\0\0\0\x3f\0\0\0\x5f\x30\0\0\0\0\0\0\xaf\x02\0\0\0\0\0\0\xbf\
648
+\x50\0\0\0\0\0\0\x77\0\0\0\x06\0\0\0\x57\0\0\0\x01\0\0\0\x67\x03\0\0\x01\0\0\0\
649
+\x4f\x03\0\0\0\0\0\0\xbf\x40\0\0\0\0\0\0\x67\0\0\0\x3a\0\0\0\xc7\0\0\0\x3f\0\0\
650
+\0\x5f\x30\0\0\0\0\0\0\xaf\x02\0\0\0\0\0\0\x67\x03\0\0\x01\0\0\0\xbf\x50\0\0\0\
651
+\0\0\0\x77\0\0\0\x05\0\0\0\x57\0\0\0\x01\0\0\0\x4f\x03\0\0\0\0\0\0\xbf\x40\0\0\
652
+\0\0\0\0\x67\0\0\0\x3b\0\0\0\xc7\0\0\0\x3f\0\0\0\x5f\x30\0\0\0\0\0\0\xaf\x02\0\
653
+\0\0\0\0\0\x67\x03\0\0\x01\0\0\0\xbf\x50\0\0\0\0\0\0\x77\0\0\0\x04\0\0\0\x57\0\
654
+\0\0\x01\0\0\0\x4f\x03\0\0\0\0\0\0\xbf\x40\0\0\0\0\0\0\x67\0\0\0\x3c\0\0\0\xc7\
655
+\0\0\0\x3f\0\0\0\x5f\x30\0\0\0\0\0\0\xaf\x02\0\0\0\0\0\0\xbf\x50\0\0\0\0\0\0\
656
+\x77\0\0\0\x03\0\0\0\x57\0\0\0\x01\0\0\0\x67\x03\0\0\x01\0\0\0\x4f\x03\0\0\0\0\
657
+\0\0\xbf\x40\0\0\0\0\0\0\x67\0\0\0\x3d\0\0\0\xc7\0\0\0\x3f\0\0\0\x5f\x30\0\0\0\
658
+\0\0\0\xaf\x02\0\0\0\0\0\0\xbf\x50\0\0\0\0\0\0\x77\0\0\0\x02\0\0\0\x57\0\0\0\
659
+\x01\0\0\0\x67\x03\0\0\x01\0\0\0\x4f\x03\0\0\0\0\0\0\xbf\x40\0\0\0\0\0\0\x67\0\
660
+\0\0\x3e\0\0\0\xc7\0\0\0\x3f\0\0\0\x5f\x30\0\0\0\0\0\0\xaf\x02\0\0\0\0\0\0\xbf\
661
+\x50\0\0\0\0\0\0\x77\0\0\0\x01\0\0\0\x57\0\0\0\x01\0\0\0\x67\x03\0\0\x01\0\0\0\
662
+\x4f\x03\0\0\0\0\0\0\x57\x04\0\0\x01\0\0\0\x87\x04\0\0\0\0\0\0\x5f\x34\0\0\0\0\
663
+\0\0\xaf\x42\0\0\0\0\0\0\x57\x05\0\0\x01\0\0\0\x67\x03\0\0\x01\0\0\0\x4f\x53\0\
664
+\0\0\0\0\0\x07\x01\0\0\x01\0\0\0\xbf\x25\0\0\0\0\0\0\x15\x01\x0b\0\x24\0\0\0\
665
+\xbf\xa2\0\0\0\0\0\0\x07\x02\0\0\xa0\xff\xff\xff\x0f\x12\0\0\0\0\0\0\x71\x24\0\
666
+\0\0\0\0\0\xbf\x40\0\0\0\0\0\0\x67\0\0\0\x38\0\0\0\xc7\0\0\0\x38\0\0\0\xb7\x02\
667
+\0\0\0\0\0\0\x65\0\xa9\xff\xff\xff\xff\xff\xbf\x32\0\0\0\0\0\0\x05\0\xa7\xff\0\
668
+\0\0\0\xbf\x21\0\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x15\x01\
669
+\x0e\0\0\0\0\0\x71\x63\x06\0\0\0\0\0\x71\x64\x07\0\0\0\0\0\x67\x04\0\0\x08\0\0\
670
+\0\x4f\x34\0\0\0\0\0\0\x3f\x41\0\0\0\0\0\0\x2f\x41\0\0\0\0\0\0\x1f\x12\0\0\0\0\
671
+\0\0\x63\x2a\x50\xff\0\0\0\0\xbf\xa2\0\0\0\0\0\0\x07\x02\0\0\x50\xff\xff\xff\
672
+\x18\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x85\0\0\0\x01\0\0\0\x55\0\x05\0\0\0\0\0\
673
+\x71\x61\x08\0\0\0\0\0\x71\x60\x09\0\0\0\0\0\x67\0\0\0\x08\0\0\0\x4f\x10\0\0\0\
674
+\0\0\0\x95\0\0\0\0\0\0\0\x69\0\0\0\0\0\0\0\x05\0\xfd\xff\0\0\0\0\x02\0\0\0\x04\
675
+\0\0\0\x0a\0\0\0\x01\0\0\0\0\0\0\0\x02\0\0\0\x04\0\0\0\x28\0\0\0\x01\0\0\0\0\0\
676
+\0\0\x02\0\0\0\x04\0\0\0\x02\0\0\0\x80\0\0\0\0\0\0\0\x47\x50\x4c\x20\x76\x32\0\
677
+\0\0\0\0\0\x10\0\0\0\0\0\0\0\x01\x7a\x52\0\x08\x7c\x0b\x01\x0c\0\0\0\x18\0\0\0\
678
+\x18\0\0\0\0\0\0\0\0\0\0\0\xd8\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
679
+\0\0\0\0\0\0\0\0\0\0\0\0\xa0\0\0\0\x04\0\xf1\xff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
680
+\0\x60\x02\0\0\0\0\x03\0\x20\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3f\x02\0\0\0\0\
681
+\x03\0\xd0\x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xed\x01\0\0\0\0\x03\0\x10\x10\0\0\0\
682
+\0\0\0\0\0\0\0\0\0\0\0\xd4\x01\0\0\0\0\x03\0\x20\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\
683
+\0\xa3\x01\0\0\0\0\x03\0\xb8\x12\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x63\x01\0\0\0\0\
684
+\x03\0\x48\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2a\x01\0\0\0\0\x03\0\x10\x13\0\0\0\
685
+\0\0\0\0\0\0\0\0\0\0\0\xe1\0\0\0\0\0\x03\0\xa0\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
686
+\x2e\x02\0\0\0\0\x03\0\x28\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x68\x02\0\0\0\0\x03\
687
+\0\xc0\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x36\x02\0\0\0\0\x03\0\xc8\x13\0\0\0\0\0\
688
+\0\0\0\0\0\0\0\0\0\x22\x01\0\0\0\0\x03\0\xe8\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
689
+\x02\x01\0\0\0\0\x03\0\x40\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd9\0\0\0\0\0\x03\0\
690
+\xf8\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x26\x02\0\0\0\0\x03\0\x20\x0e\0\0\0\0\0\0\
691
+\0\0\0\0\0\0\0\0\xcc\x01\0\0\0\0\x03\0\x60\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9b\
692
+\x01\0\0\0\0\x03\0\xc8\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5b\x01\0\0\0\0\x03\0\
693
+\x20\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7c\x01\0\0\0\0\x03\0\x48\x08\0\0\0\0\0\0\
694
+\0\0\0\0\0\0\0\0\x53\x01\0\0\0\0\x03\0\xb8\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1a\
695
+\x01\0\0\0\0\x03\0\xe0\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x84\x01\0\0\0\0\x03\0\
696
+\xb8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1e\x02\0\0\0\0\x03\0\xd8\x09\0\0\0\0\0\0\0\
697
+\0\0\0\0\0\0\0\xc4\x01\0\0\0\0\x03\0\x70\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x93\
698
+\x01\0\0\0\0\x03\0\xa8\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x74\x01\0\0\0\0\x03\0\
699
+\xf0\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4b\x01\0\0\0\0\x03\0\0\x0a\0\0\0\0\0\0\0\
700
+\0\0\0\0\0\0\0\x12\x01\0\0\0\0\x03\0\x10\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xfa\0\
701
+\0\0\0\0\x03\0\xc0\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x58\x02\0\0\0\0\x03\0\x88\
702
+\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x02\0\0\0\0\x03\0\xb8\x0a\0\0\0\0\0\0\0\0\
703
+\0\0\0\0\0\0\xe5\x01\0\0\0\0\x03\0\xc0\x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xbc\x01\
704
+\0\0\0\0\x03\0\0\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8b\x01\0\0\0\0\x03\0\x18\x0e\
705
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd1\0\0\0\0\0\x03\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\
706
+\0\0\x50\x02\0\0\0\0\x03\0\x20\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0e\x02\0\0\0\0\
707
+\x03\0\x48\x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6c\x01\0\0\0\0\x03\0\xb0\x04\0\0\0\
708
+\0\0\0\0\0\0\0\0\0\0\0\x43\x01\0\0\0\0\x03\0\xc8\x0c\0\0\0\0\0\0\0\0\0\0\0\0\0\
709
+\0\xc9\0\0\0\0\0\x03\0\xf8\x0c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x06\x02\0\0\0\0\x03\
710
+\0\xd0\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3b\x01\0\0\0\0\x03\0\x98\x0b\0\0\0\0\0\
711
+\0\0\0\0\0\0\0\0\0\xf2\0\0\0\0\0\x03\0\xb8\x0b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x48\
712
+\x02\0\0\0\0\x03\0\xf0\x0b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xfe\x01\0\0\0\0\x03\0\
713
+\xf8\x0b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xdd\x01\0\0\0\0\x03\0\0\x0c\0\0\0\0\0\0\0\
714
+\0\0\0\0\0\0\0\xb4\x01\0\0\0\0\x03\0\x30\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0a\
715
+\x01\0\0\0\0\x03\0\x90\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc1\0\0\0\0\0\x03\0\xa8\
716
+\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xba\0\0\0\0\0\x03\0\xd0\x01\0\0\0\0\0\0\0\0\0\
717
+\0\0\0\0\0\xf6\x01\0\0\0\0\x03\0\xe0\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xac\x01\0\
718
+\0\0\0\x03\0\x30\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x33\x01\0\0\0\0\x03\0\x80\x0e\
719
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xea\0\0\0\0\0\x03\0\x98\x0e\0\0\0\0\0\0\0\0\0\0\0\
720
+\0\0\0\0\0\0\0\x03\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6b\0\0\0\x11\0\x06\
721
+\0\0\0\0\0\0\0\0\0\x07\0\0\0\0\0\0\0\x25\0\0\0\x11\0\x05\0\0\0\0\0\0\0\0\0\x14\
722
+\0\0\0\0\0\0\0\x82\0\0\0\x11\0\x05\0\x28\0\0\0\0\0\0\0\x14\0\0\0\0\0\0\0\x01\0\
723
+\0\0\x11\0\x05\0\x14\0\0\0\0\0\0\0\x14\0\0\0\0\0\0\0\x40\0\0\0\x12\0\x03\0\0\0\
724
+\0\0\0\0\0\0\xd8\x13\0\0\0\0\0\0\x28\0\0\0\0\0\0\0\x01\0\0\0\x3a\0\0\0\x50\0\0\
725
+\0\0\0\0\0\x01\0\0\0\x3c\0\0\0\x80\x13\0\0\0\0\0\0\x01\0\0\0\x3b\0\0\0\x1c\0\0\
726
+\0\0\0\0\0\x01\0\0\0\x38\0\0\0\0\x74\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\
727
+\x5f\x74\x6f\x65\x70\x6c\x69\x74\x7a\x5f\x6b\x65\x79\0\x2e\x74\x65\x78\x74\0\
728
+\x6d\x61\x70\x73\0\x74\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\x5f\x63\x6f\x6e\
729
+\x66\x69\x67\x75\x72\x61\x74\x69\x6f\x6e\x73\0\x74\x75\x6e\x5f\x72\x73\x73\x5f\
730
+\x73\x74\x65\x65\x72\x69\x6e\x67\x5f\x70\x72\x6f\x67\0\x2e\x72\x65\x6c\x74\x75\
731
+\x6e\x5f\x72\x73\x73\x5f\x73\x74\x65\x65\x72\x69\x6e\x67\0\x5f\x6c\x69\x63\x65\
732
+\x6e\x73\x65\0\x2e\x72\x65\x6c\x2e\x65\x68\x5f\x66\x72\x61\x6d\x65\0\x74\x61\
733
+\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\x5f\x69\x6e\x64\x69\x72\x65\x63\x74\x69\
734
+\x6f\x6e\x5f\x74\x61\x62\x6c\x65\0\x72\x73\x73\x2e\x62\x70\x66\x2e\x63\0\x2e\
735
+\x73\x74\x72\x74\x61\x62\0\x2e\x73\x79\x6d\x74\x61\x62\0\x4c\x42\x42\x30\x5f\
736
+\x39\0\x4c\x42\x42\x30\x5f\x38\x39\0\x4c\x42\x42\x30\x5f\x36\x39\0\x4c\x42\x42\
737
+\x30\x5f\x35\x39\0\x4c\x42\x42\x30\x5f\x31\x39\0\x4c\x42\x42\x30\x5f\x31\x30\
738
+\x39\0\x4c\x42\x42\x30\x5f\x39\x38\0\x4c\x42\x42\x30\x5f\x37\x38\0\x4c\x42\x42\
739
+\x30\x5f\x34\x38\0\x4c\x42\x42\x30\x5f\x31\x38\0\x4c\x42\x42\x30\x5f\x38\x37\0\
740
+\x4c\x42\x42\x30\x5f\x34\x37\0\x4c\x42\x42\x30\x5f\x33\x37\0\x4c\x42\x42\x30\
741
+\x5f\x31\x37\0\x4c\x42\x42\x30\x5f\x31\x30\x37\0\x4c\x42\x42\x30\x5f\x39\x36\0\
742
+\x4c\x42\x42\x30\x5f\x37\x36\0\x4c\x42\x42\x30\x5f\x36\x36\0\x4c\x42\x42\x30\
743
+\x5f\x34\x36\0\x4c\x42\x42\x30\x5f\x33\x36\0\x4c\x42\x42\x30\x5f\x32\x36\0\x4c\
744
+\x42\x42\x30\x5f\x31\x30\x36\0\x4c\x42\x42\x30\x5f\x36\x35\0\x4c\x42\x42\x30\
745
+\x5f\x34\x35\0\x4c\x42\x42\x30\x5f\x33\x35\0\x4c\x42\x42\x30\x5f\x34\0\x4c\x42\
746
+\x42\x30\x5f\x35\x34\0\x4c\x42\x42\x30\x5f\x34\x34\0\x4c\x42\x42\x30\x5f\x32\
747
+\x34\0\x4c\x42\x42\x30\x5f\x31\x30\x34\0\x4c\x42\x42\x30\x5f\x39\x33\0\x4c\x42\
748
+\x42\x30\x5f\x38\x33\0\x4c\x42\x42\x30\x5f\x35\x33\0\x4c\x42\x42\x30\x5f\x34\
749
+\x33\0\x4c\x42\x42\x30\x5f\x32\x33\0\x4c\x42\x42\x30\x5f\x31\x30\x33\0\x4c\x42\
750
+\x42\x30\x5f\x38\x32\0\x4c\x42\x42\x30\x5f\x35\x32\0\x4c\x42\x42\x30\x5f\x31\
751
+\x30\x32\0\x4c\x42\x42\x30\x5f\x39\x31\0\x4c\x42\x42\x30\x5f\x38\x31\0\x4c\x42\
752
+\x42\x30\x5f\x37\x31\0\x4c\x42\x42\x30\x5f\x36\x31\0\x4c\x42\x42\x30\x5f\x35\
753
+\x31\0\x4c\x42\x42\x30\x5f\x34\x31\0\x4c\x42\x42\x30\x5f\x32\x31\0\x4c\x42\x42\
754
+\x30\x5f\x31\x31\0\x4c\x42\x42\x30\x5f\x31\x31\x31\0\x4c\x42\x42\x30\x5f\x31\
755
+\x30\x31\0\x4c\x42\x42\x30\x5f\x38\x30\0\x4c\x42\x42\x30\x5f\x36\x30\0\x4c\x42\
756
+\x42\x30\x5f\x35\x30\0\x4c\x42\x42\x30\x5f\x31\x30\0\x4c\x42\x42\x30\x5f\x31\
757
+\x31\x30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
758
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xaa\
759
+\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa0\x1a\0\0\0\0\0\0\x71\x02\0\
760
+\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1a\0\0\0\x01\0\0\
761
+\0\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
762
+\0\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5a\0\0\0\x01\0\0\0\x06\0\0\0\0\0\0\
763
+\0\0\0\0\0\0\0\0\0\x40\0\0\0\0\0\0\0\xd8\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x08\0\
764
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x56\0\0\0\x09\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
765
+\0\x60\x1a\0\0\0\0\0\0\x30\0\0\0\0\0\0\0\x09\0\0\0\x03\0\0\0\x08\0\0\0\0\0\0\0\
766
+\x10\0\0\0\0\0\0\0\x20\0\0\0\x01\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x18\
767
+\x14\0\0\0\0\0\0\x3c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\
768
+\0\0\0\x6c\0\0\0\x01\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x54\x14\0\0\0\0\0\
769
+\0\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x78\0\0\
770
+\0\x01\0\0\0\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x60\x14\0\0\0\0\0\0\x30\0\0\0\0\
771
+\0\0\0\0\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x74\0\0\0\x09\0\0\0\0\
772
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x1a\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x09\0\0\0\
773
+\x07\0\0\0\x08\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\xb2\0\0\0\x02\0\0\0\0\0\0\0\0\0\
774
+\0\0\0\0\0\0\0\0\0\0\x90\x14\0\0\0\0\0\0\xd0\x05\0\0\0\0\0\0\x01\0\0\0\x39\0\0\
775
+\0\x08\0\0\0\0\0\0\0\x18\0\0\0\0\0\0\0";
776
+
777
+    return 0;
778
+err:
779
+    bpf_object__destroy_skeleton(s);
780
+    return -1;
781
+}
782
+
783
+#endif /* __RSS_BPF_SKEL_H__ */
784
diff --git a/ebpf/trace-events b/ebpf/trace-events
785
new file mode 100644
786
index XXXXXXX..XXXXXXX
787
--- /dev/null
788
+++ b/ebpf/trace-events
789
@@ -XXX,XX +XXX,XX @@
790
+# See docs/devel/tracing.txt for syntax documentation.
791
+
792
+# ebpf-rss.c
793
+ebpf_error(const char *s1, const char *s2) "error in %s: %s"
794
diff --git a/ebpf/trace.h b/ebpf/trace.h
795
new file mode 100644
796
index XXXXXXX..XXXXXXX
797
--- /dev/null
798
+++ b/ebpf/trace.h
799
@@ -0,0 +1 @@
800
+#include "trace/trace-ebpf.h"
801
diff --git a/meson.build b/meson.build
802
index XXXXXXX..XXXXXXX 100644
803
--- a/meson.build
804
+++ b/meson.build
805
@@ -XXX,XX +XXX,XX @@ if not get_option('fuse_lseek').disabled()
806
endif
807
endif
808
809
+# libbpf
810
+libbpf = dependency('libbpf', required: get_option('bpf'), method: 'pkg-config')
811
+if libbpf.found() and not cc.links('''
812
+ #include <bpf/libbpf.h>
813
+ int main(void)
814
+ {
815
+ bpf_object__destroy_skeleton(NULL);
816
+ return 0;
817
+ }''', dependencies: libbpf)
818
+ libbpf = not_found
819
+ if get_option('bpf').enabled()
820
+ error('libbpf skeleton test failed')
821
+ else
822
+ warning('libbpf skeleton test failed, disabling')
823
+ endif
824
+endif
825
+
826
if get_option('cfi')
827
cfi_flags=[]
828
# Check for dependency on LTO
829
@@ -XXX,XX +XXX,XX @@ endif
830
config_host_data.set('CONFIG_GTK', gtk.found())
831
config_host_data.set('CONFIG_LIBATTR', have_old_libattr)
832
config_host_data.set('CONFIG_LIBCAP_NG', libcap_ng.found())
833
+config_host_data.set('CONFIG_EBPF', libbpf.found())
834
config_host_data.set('CONFIG_LIBISCSI', libiscsi.found())
835
config_host_data.set('CONFIG_LIBNFS', libnfs.found())
836
config_host_data.set('CONFIG_RBD', rbd.found())
837
@@ -XXX,XX +XXX,XX @@ if have_system
838
'backends',
839
'backends/tpm',
840
'chardev',
841
+ 'ebpf',
842
'hw/9pfs',
843
'hw/acpi',
844
'hw/adc',
845
@@ -XXX,XX +XXX,XX @@ subdir('accel')
846
subdir('plugins')
847
subdir('bsd-user')
848
subdir('linux-user')
849
+subdir('ebpf')
850
+
851
+common_ss.add(libbpf)
852
853
bsd_user_ss.add(files('gdbstub.c'))
854
specific_ss.add_all(when: 'CONFIG_BSD_USER', if_true: bsd_user_ss)
855
@@ -XXX,XX +XXX,XX @@ summary_info += {'RDMA support': config_host.has_key('CONFIG_RDMA')}
856
summary_info += {'PVRDMA support': config_host.has_key('CONFIG_PVRDMA')}
857
summary_info += {'fdt support': fdt_opt == 'disabled' ? false : fdt_opt}
858
summary_info += {'libcap-ng support': libcap_ng.found()}
859
+summary_info += {'bpf support': libbpf.found()}
860
# TODO: add back protocol and server version
861
summary_info += {'spice support': config_host.has_key('CONFIG_SPICE')}
862
summary_info += {'rbd support': rbd.found()}
863
diff --git a/meson_options.txt b/meson_options.txt
864
index XXXXXXX..XXXXXXX 100644
865
--- a/meson_options.txt
866
+++ b/meson_options.txt
867
@@ -XXX,XX +XXX,XX @@ option('bzip2', type : 'feature', value : 'auto',
868
description: 'bzip2 support for DMG images')
869
option('cap_ng', type : 'feature', value : 'auto',
870
description: 'cap_ng support')
871
+option('bpf', type : 'feature', value : 'auto',
872
+ description: 'eBPF support')
873
option('cocoa', type : 'feature', value : 'auto',
874
description: 'Cocoa user interface (macOS only)')
875
option('curl', type : 'feature', value : 'auto',
876
--
110
--
877
2.7.4
111
2.7.4
878
879
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Qiang Liu <cyruscyliu@gmail.com>
2
2
3
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
3
Check fifos before poping data from and pushing data into it.
4
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
4
5
Fixes: 98e5d7a2b726 ("hw/net/can: Introduce Xilinx ZynqMP CAN controller")
6
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1425
7
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1427
8
Reported-by: Qiang Liu <cyruscyliu@gmail.com>
9
Signed-off-by: Qiang Liu <cyruscyliu@gmail.com>
5
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
Signed-off-by: Jason Wang <jasowang@redhat.com>
6
---
11
---
7
docs/devel/ebpf_rss.rst | 125 ++++++++++++++++++++++++++++++++++++++++++++++++
12
hw/net/can/xlnx-zynqmp-can.c | 9 ++++++++-
8
docs/devel/index.rst | 1 +
13
1 file changed, 8 insertions(+), 1 deletion(-)
9
2 files changed, 126 insertions(+)
10
create mode 100644 docs/devel/ebpf_rss.rst
11
14
12
diff --git a/docs/devel/ebpf_rss.rst b/docs/devel/ebpf_rss.rst
15
diff --git a/hw/net/can/xlnx-zynqmp-can.c b/hw/net/can/xlnx-zynqmp-can.c
13
new file mode 100644
14
index XXXXXXX..XXXXXXX
15
--- /dev/null
16
+++ b/docs/devel/ebpf_rss.rst
17
@@ -XXX,XX +XXX,XX @@
18
+===========================
19
+eBPF RSS virtio-net support
20
+===========================
21
+
22
+RSS(Receive Side Scaling) is used to distribute network packets to guest virtqueues
23
+by calculating packet hash. Usually every queue is processed then by a specific guest CPU core.
24
+
25
+For now there are 2 RSS implementations in qemu:
26
+- 'in-qemu' RSS (functions if qemu receives network packets, i.e. vhost=off)
27
+- eBPF RSS (can function with also with vhost=on)
28
+
29
+eBPF support (CONFIG_EBPF) is enabled by 'configure' script.
30
+To enable eBPF RSS support use './configure --enable-bpf'.
31
+
32
+If steering BPF is not set for kernel's TUN module, the TUN uses automatic selection
33
+of rx virtqueue based on lookup table built according to calculated symmetric hash
34
+of transmitted packets.
35
+If steering BPF is set for TUN the BPF code calculates the hash of packet header and
36
+returns the virtqueue number to place the packet to.
37
+
38
+Simplified decision formula:
39
+
40
+.. code:: C
41
+
42
+ queue_index = indirection_table[hash(<packet data>)%<indirection_table size>]
43
+
44
+
45
+Not for all packets, the hash can/should be calculated.
46
+
47
+Note: currently, eBPF RSS does not support hash reporting.
48
+
49
+eBPF RSS turned on by different combinations of vhost-net, vitrio-net and tap configurations:
50
+
51
+- eBPF is used:
52
+
53
+ tap,vhost=off & virtio-net-pci,rss=on,hash=off
54
+
55
+- eBPF is used:
56
+
57
+ tap,vhost=on & virtio-net-pci,rss=on,hash=off
58
+
59
+- 'in-qemu' RSS is used:
60
+
61
+ tap,vhost=off & virtio-net-pci,rss=on,hash=on
62
+
63
+- eBPF is used, hash population feature is not reported to the guest:
64
+
65
+ tap,vhost=on & virtio-net-pci,rss=on,hash=on
66
+
67
+If CONFIG_EBPF is not set then only 'in-qemu' RSS is supported.
68
+Also 'in-qemu' RSS, as a fallback, is used if the eBPF program failed to load or set to TUN.
69
+
70
+RSS eBPF program
71
+----------------
72
+
73
+RSS program located in ebpf/rss.bpf.skeleton.h generated by bpftool.
74
+So the program is part of the qemu binary.
75
+Initially, the eBPF program was compiled by clang and source code located at tools/ebpf/rss.bpf.c.
76
+Prerequisites to recompile the eBPF program (regenerate ebpf/rss.bpf.skeleton.h):
77
+
78
+ llvm, clang, kernel source tree, bpftool
79
+ Adjust Makefile.ebpf to reflect the location of the kernel source tree
80
+
81
+ $ cd tools/ebpf
82
+ $ make -f Makefile.ebpf
83
+
84
+Current eBPF RSS implementation uses 'bounded loops' with 'backward jump instructions' which present in the last kernels.
85
+Overall eBPF RSS works on kernels 5.8+.
86
+
87
+eBPF RSS implementation
88
+-----------------------
89
+
90
+eBPF RSS loading functionality located in ebpf/ebpf_rss.c and ebpf/ebpf_rss.h.
91
+
92
+The `struct EBPFRSSContext` structure that holds 4 file descriptors:
93
+
94
+- ctx - pointer of the libbpf context.
95
+- program_fd - file descriptor of the eBPF RSS program.
96
+- map_configuration - file descriptor of the 'configuration' map. This map contains one element of 'struct EBPFRSSConfig'. This configuration determines eBPF program behavior.
97
+- map_toeplitz_key - file descriptor of the 'Toeplitz key' map. One element of the 40byte key prepared for the hashing algorithm.
98
+- map_indirections_table - 128 elements of queue indexes.
99
+
100
+`struct EBPFRSSConfig` fields:
101
+
102
+- redirect - "boolean" value, should the hash be calculated, on false - `default_queue` would be used as the final decision.
103
+- populate_hash - for now, not used. eBPF RSS doesn't support hash reporting.
104
+- hash_types - binary mask of different hash types. See `VIRTIO_NET_RSS_HASH_TYPE_*` defines. If for packet hash should not be calculated - `default_queue` would be used.
105
+- indirections_len - length of the indirections table, maximum 128.
106
+- default_queue - the queue index that used for packet that shouldn't be hashed. For some packets, the hash can't be calculated(g.e ARP).
107
+
108
+Functions:
109
+
110
+- `ebpf_rss_init()` - sets ctx to NULL, which indicates that EBPFRSSContext is not loaded.
111
+- `ebpf_rss_load()` - creates 3 maps and loads eBPF program from the rss.bpf.skeleton.h. Returns 'true' on success. After that, program_fd can be used to set steering for TAP.
112
+- `ebpf_rss_set_all()` - sets values for eBPF maps. `indirections_table` length is in EBPFRSSConfig. `toeplitz_key` is VIRTIO_NET_RSS_MAX_KEY_SIZE aka 40 bytes array.
113
+- `ebpf_rss_unload()` - close all file descriptors and set ctx to NULL.
114
+
115
+Simplified eBPF RSS workflow:
116
+
117
+.. code:: C
118
+
119
+ struct EBPFRSSConfig config;
120
+ config.redirect = 1;
121
+ config.hash_types = VIRTIO_NET_RSS_HASH_TYPE_UDPv4 | VIRTIO_NET_RSS_HASH_TYPE_TCPv4;
122
+ config.indirections_len = VIRTIO_NET_RSS_MAX_TABLE_LEN;
123
+ config.default_queue = 0;
124
+
125
+ uint16_t table[VIRTIO_NET_RSS_MAX_TABLE_LEN] = {...};
126
+ uint8_t key[VIRTIO_NET_RSS_MAX_KEY_SIZE] = {...};
127
+
128
+ struct EBPFRSSContext ctx;
129
+ ebpf_rss_init(&ctx);
130
+ ebpf_rss_load(&ctx);
131
+ ebpf_rss_set_all(&ctx, &config, table, key);
132
+ if (net_client->info->set_steering_ebpf != NULL) {
133
+ net_client->info->set_steering_ebpf(net_client, ctx->program_fd);
134
+ }
135
+ ...
136
+ ebpf_unload(&ctx);
137
+
138
+
139
+NetClientState SetSteeringEBPF()
140
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
141
+
142
+For now, `set_steering_ebpf()` method supported by Linux TAP NetClientState. The method requires an eBPF program file descriptor as an argument.
143
diff --git a/docs/devel/index.rst b/docs/devel/index.rst
144
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
145
--- a/docs/devel/index.rst
17
--- a/hw/net/can/xlnx-zynqmp-can.c
146
+++ b/docs/devel/index.rst
18
+++ b/hw/net/can/xlnx-zynqmp-can.c
147
@@ -XXX,XX +XXX,XX @@ Contents:
19
@@ -XXX,XX +XXX,XX @@ static void transfer_fifo(XlnxZynqMPCANState *s, Fifo32 *fifo)
148
qom
20
}
149
block-coroutine-wrapper
21
150
multi-process
22
while (!fifo32_is_empty(fifo)) {
151
+ ebpf_rss
23
+ if (fifo32_num_used(fifo) < (4 * CAN_FRAME_SIZE)) {
24
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
25
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: data left in the fifo is not"
26
+ " enough for transfer.\n", path);
27
+ break;
28
+ }
29
for (i = 0; i < CAN_FRAME_SIZE; i++) {
30
data[i] = fifo32_pop(fifo);
31
}
32
@@ -XXX,XX +XXX,XX @@ static void transfer_fifo(XlnxZynqMPCANState *s, Fifo32 *fifo)
33
* acknowledged. The XlnxZynqMPCAN core receives any message
34
* that it transmits.
35
*/
36
- if (fifo32_is_full(&s->rx_fifo)) {
37
+ if (fifo32_is_full(&s->rx_fifo) ||
38
+ (fifo32_num_free(&s->rx_fifo) < (4 * CAN_FRAME_SIZE))) {
39
ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXOFLW, 1);
40
} else {
41
for (i = 0; i < CAN_FRAME_SIZE; i++) {
152
--
42
--
153
2.7.4
43
2.7.4
154
155
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Laurent Vivier <lvivier@redhat.com>
2
2
3
RSS program and Makefile to build it.
3
In stream mode, if the server shuts down there is currently
4
The bpftool used to generate '.h' file.
4
no way to reconnect the client to a new server without removing
5
The data in that file may be loaded by libbpf.
5
the NIC device and the netdev backend (or to reboot).
6
EBPF compilation is not required for building qemu.
6
7
You can use Makefile if you need to regenerate rss.bpf.skeleton.h.
7
This patch introduces a reconnect option that specifies a delay
8
8
to try to reconnect with the same parameters.
9
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
9
10
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
10
Add a new test in qtest to test the reconnect option and the
11
connect/disconnect events.
12
13
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
14
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
15
---
13
tools/ebpf/Makefile.ebpf | 21 ++
16
net/stream.c | 53 ++++++++++++++++++++++-
14
tools/ebpf/rss.bpf.c | 571 +++++++++++++++++++++++++++++++++++++++++++++++
17
qapi/net.json | 7 ++-
15
2 files changed, 592 insertions(+)
18
qemu-options.hx | 6 +--
16
create mode 100755 tools/ebpf/Makefile.ebpf
19
tests/qtest/netdev-socket.c | 101 ++++++++++++++++++++++++++++++++++++++++++++
17
create mode 100644 tools/ebpf/rss.bpf.c
20
4 files changed, 162 insertions(+), 5 deletions(-)
18
21
19
diff --git a/tools/ebpf/Makefile.ebpf b/tools/ebpf/Makefile.ebpf
22
diff --git a/net/stream.c b/net/stream.c
20
new file mode 100755
23
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX
24
--- a/net/stream.c
22
--- /dev/null
25
+++ b/net/stream.c
23
+++ b/tools/ebpf/Makefile.ebpf
24
@@ -XXX,XX +XXX,XX @@
26
@@ -XXX,XX +XXX,XX @@
25
+OBJS = rss.bpf.o
27
#include "io/channel-socket.h"
26
+
28
#include "io/net-listener.h"
27
+LLC ?= llc
29
#include "qapi/qapi-events-net.h"
28
+CLANG ?= clang
30
+#include "qapi/qapi-visit-sockets.h"
29
+INC_FLAGS = `$(CLANG) -print-file-name=include`
31
+#include "qapi/clone-visitor.h"
30
+EXTRA_CFLAGS ?= -O2 -emit-llvm -fno-stack-protector
32
31
+
33
typedef struct NetStreamState {
32
+all: $(OBJS)
34
NetClientState nc;
33
+
35
@@ -XXX,XX +XXX,XX @@ typedef struct NetStreamState {
34
+.PHONY: clean
36
guint ioc_write_tag;
35
+
37
SocketReadState rs;
36
+clean:
38
unsigned int send_index; /* number of bytes sent*/
37
+    rm -f $(OBJS)
39
+ uint32_t reconnect;
38
+
40
+ guint timer_tag;
39
+$(OBJS): %.o:%.c
41
+ SocketAddress *addr;
40
+    $(CLANG) $(INC_FLAGS) \
42
} NetStreamState;
41
+ -D__KERNEL__ -D__ASM_SYSREG_H \
43
42
+ -I../include $(LINUXINCLUDE) \
44
static void net_stream_listen(QIONetListener *listener,
43
+ $(EXTRA_CFLAGS) -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $@
45
QIOChannelSocket *cioc,
44
+    bpftool gen skeleton rss.bpf.o > rss.bpf.skeleton.h
46
void *opaque);
45
+    cp rss.bpf.skeleton.h ../../ebpf/
47
+static void net_stream_arm_reconnect(NetStreamState *s);
46
diff --git a/tools/ebpf/rss.bpf.c b/tools/ebpf/rss.bpf.c
48
47
new file mode 100644
49
static gboolean net_stream_writable(QIOChannel *ioc,
48
index XXXXXXX..XXXXXXX
50
GIOCondition condition,
49
--- /dev/null
51
@@ -XXX,XX +XXX,XX @@ static gboolean net_stream_send(QIOChannel *ioc,
50
+++ b/tools/ebpf/rss.bpf.c
52
qemu_set_info_str(&s->nc, "%s", "");
53
54
qapi_event_send_netdev_stream_disconnected(s->nc.name);
55
+ net_stream_arm_reconnect(s);
56
57
return G_SOURCE_REMOVE;
58
}
59
@@ -XXX,XX +XXX,XX @@ static gboolean net_stream_send(QIOChannel *ioc,
60
static void net_stream_cleanup(NetClientState *nc)
61
{
62
NetStreamState *s = DO_UPCAST(NetStreamState, nc, nc);
63
+ if (s->timer_tag) {
64
+ g_source_remove(s->timer_tag);
65
+ s->timer_tag = 0;
66
+ }
67
+ if (s->addr) {
68
+ qapi_free_SocketAddress(s->addr);
69
+ s->addr = NULL;
70
+ }
71
if (s->ioc) {
72
if (QIO_CHANNEL_SOCKET(s->ioc)->fd != -1) {
73
if (s->ioc_read_tag) {
74
@@ -XXX,XX +XXX,XX @@ static void net_stream_client_connected(QIOTask *task, gpointer opaque)
75
error:
76
object_unref(OBJECT(s->ioc));
77
s->ioc = NULL;
78
+ net_stream_arm_reconnect(s);
79
+}
80
+
81
+static gboolean net_stream_reconnect(gpointer data)
82
+{
83
+ NetStreamState *s = data;
84
+ QIOChannelSocket *sioc;
85
+
86
+ s->timer_tag = 0;
87
+
88
+ sioc = qio_channel_socket_new();
89
+ s->ioc = QIO_CHANNEL(sioc);
90
+ qio_channel_socket_connect_async(sioc, s->addr,
91
+ net_stream_client_connected, s,
92
+ NULL, NULL);
93
+ return G_SOURCE_REMOVE;
94
+}
95
+
96
+static void net_stream_arm_reconnect(NetStreamState *s)
97
+{
98
+ if (s->reconnect && s->timer_tag == 0) {
99
+ s->timer_tag = g_timeout_add_seconds(s->reconnect,
100
+ net_stream_reconnect, s);
101
+ }
102
}
103
104
static int net_stream_client_init(NetClientState *peer,
105
const char *model,
106
const char *name,
107
SocketAddress *addr,
108
+ uint32_t reconnect,
109
Error **errp)
110
{
111
NetStreamState *s;
112
@@ -XXX,XX +XXX,XX @@ static int net_stream_client_init(NetClientState *peer,
113
s->ioc = QIO_CHANNEL(sioc);
114
s->nc.link_down = true;
115
116
+ s->reconnect = reconnect;
117
+ if (reconnect) {
118
+ s->addr = QAPI_CLONE(SocketAddress, addr);
119
+ }
120
qio_channel_socket_connect_async(sioc, addr,
121
net_stream_client_connected, s,
122
NULL, NULL);
123
@@ -XXX,XX +XXX,XX @@ int net_init_stream(const Netdev *netdev, const char *name,
124
sock = &netdev->u.stream;
125
126
if (!sock->has_server || !sock->server) {
127
- return net_stream_client_init(peer, "stream", name, sock->addr, errp);
128
+ return net_stream_client_init(peer, "stream", name, sock->addr,
129
+ sock->has_reconnect ? sock->reconnect : 0,
130
+ errp);
131
+ }
132
+ if (sock->has_reconnect) {
133
+ error_setg(errp, "'reconnect' option is incompatible with "
134
+ "socket in server mode");
135
+ return -1;
136
}
137
return net_stream_server_init(peer, "stream", name, sock->addr, errp);
138
}
139
diff --git a/qapi/net.json b/qapi/net.json
140
index XXXXXXX..XXXXXXX 100644
141
--- a/qapi/net.json
142
+++ b/qapi/net.json
51
@@ -XXX,XX +XXX,XX @@
143
@@ -XXX,XX +XXX,XX @@
52
+/*
144
# @addr: socket address to listen on (server=true)
53
+ * eBPF RSS program
145
# or connect to (server=false)
54
+ *
146
# @server: create server socket (default: false)
55
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
147
+# @reconnect: For a client socket, if a socket is disconnected,
56
+ *
148
+# then attempt a reconnect after the given number of seconds.
57
+ * Authors:
149
+# Setting this to zero disables this function. (default: 0)
58
+ * Andrew Melnychenko <andrew@daynix.com>
150
+# (since 8.0)
59
+ * Yuri Benditovich <yuri.benditovich@daynix.com>
151
#
60
+ *
152
# Only SocketAddress types 'unix', 'inet' and 'fd' are supported.
61
+ * This work is licensed under the terms of the GNU GPL, version 2. See
153
#
62
+ * the COPYING file in the top-level directory.
154
@@ -XXX,XX +XXX,XX @@
63
+ *
155
{ 'struct': 'NetdevStreamOptions',
64
+ * Prepare:
156
'data': {
65
+ * Requires llvm, clang, bpftool, linux kernel tree
157
'addr': 'SocketAddress',
66
+ *
158
- '*server': 'bool' } }
67
+ * Build rss.bpf.skeleton.h:
159
+ '*server': 'bool',
68
+ * make -f Makefile.ebpf clean all
160
+ '*reconnect': 'uint32' } }
69
+ */
161
70
+
162
##
71
+#include <stddef.h>
163
# @NetdevDgramOptions:
72
+#include <stdbool.h>
164
diff --git a/qemu-options.hx b/qemu-options.hx
73
+#include <linux/bpf.h>
165
index XXXXXXX..XXXXXXX 100644
74
+
166
--- a/qemu-options.hx
75
+#include <linux/in.h>
167
+++ b/qemu-options.hx
76
+#include <linux/if_ether.h>
168
@@ -XXX,XX +XXX,XX @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
77
+#include <linux/ip.h>
169
"-netdev socket,id=str[,fd=h][,udp=host:port][,localaddr=host:port]\n"
78
+#include <linux/ipv6.h>
170
" configure a network backend to connect to another network\n"
79
+
171
" using an UDP tunnel\n"
80
+#include <linux/udp.h>
172
- "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off]\n"
81
+#include <linux/tcp.h>
173
- "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off]\n"
82
+
174
- "-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor\n"
83
+#include <bpf/bpf_helpers.h>
175
+ "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect=seconds]\n"
84
+#include <bpf/bpf_endian.h>
176
+ "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off][,reconnect=seconds]\n"
85
+#include <linux/virtio_net.h>
177
+ "-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor[,reconnect=seconds]\n"
86
+
178
" configure a network backend to connect to another network\n"
87
+#define INDIRECTION_TABLE_SIZE 128
179
" using a socket connection in stream mode.\n"
88
+#define HASH_CALCULATION_BUFFER_SIZE 36
180
"-netdev dgram,id=str,remote.type=inet,remote.host=maddr,remote.port=port[,local.type=inet,local.host=addr]\n"
89
+
181
diff --git a/tests/qtest/netdev-socket.c b/tests/qtest/netdev-socket.c
90
+struct rss_config_t {
182
index XXXXXXX..XXXXXXX 100644
91
+ __u8 redirect;
183
--- a/tests/qtest/netdev-socket.c
92
+ __u8 populate_hash;
184
+++ b/tests/qtest/netdev-socket.c
93
+ __u32 hash_types;
185
@@ -XXX,XX +XXX,XX @@
94
+ __u16 indirections_len;
186
#include <glib/gstdio.h>
95
+ __u16 default_queue;
187
#include "../unit/socket-helpers.h"
96
+} __attribute__((packed));
188
#include "libqtest.h"
97
+
189
+#include "qapi/qmp/qstring.h"
98
+struct toeplitz_key_data_t {
190
+#include "qemu/sockets.h"
99
+ __u32 leftmost_32_bits;
191
+#include "qapi/qobject-input-visitor.h"
100
+ __u8 next_byte[HASH_CALCULATION_BUFFER_SIZE];
192
+#include "qapi/qapi-visit-sockets.h"
101
+};
193
102
+
194
#define CONNECTION_TIMEOUT 60
103
+struct packet_hash_info_t {
195
104
+ __u8 is_ipv4;
196
@@ -XXX,XX +XXX,XX @@ static void test_stream_inet_ipv4(void)
105
+ __u8 is_ipv6;
197
qtest_quit(qts0);
106
+ __u8 is_udp;
198
}
107
+ __u8 is_tcp;
199
108
+ __u8 is_ipv6_ext_src;
200
+static void wait_stream_connected(QTestState *qts, const char *id,
109
+ __u8 is_ipv6_ext_dst;
201
+ SocketAddress **addr)
110
+ __u8 is_fragmented;
202
+{
111
+
203
+ QDict *resp, *data;
112
+ __u16 src_port;
204
+ QString *qstr;
113
+ __u16 dst_port;
205
+ QObject *obj;
114
+
206
+ Visitor *v = NULL;
115
+ union {
207
+
116
+ struct {
208
+ resp = qtest_qmp_eventwait_ref(qts, "NETDEV_STREAM_CONNECTED");
117
+ __be32 in_src;
209
+ g_assert_nonnull(resp);
118
+ __be32 in_dst;
210
+ data = qdict_get_qdict(resp, "data");
119
+ };
211
+ g_assert_nonnull(data);
120
+
212
+
121
+ struct {
213
+ qstr = qobject_to(QString, qdict_get(data, "netdev-id"));
122
+ struct in6_addr in6_src;
214
+ g_assert_nonnull(data);
123
+ struct in6_addr in6_dst;
215
+
124
+ struct in6_addr in6_ext_src;
216
+ g_assert(!strcmp(qstring_get_str(qstr), id));
125
+ struct in6_addr in6_ext_dst;
217
+
126
+ };
218
+ obj = qdict_get(data, "addr");
127
+ };
219
+
128
+};
220
+ v = qobject_input_visitor_new(obj);
129
+
221
+ visit_type_SocketAddress(v, NULL, addr, NULL);
130
+struct bpf_map_def SEC("maps")
222
+ visit_free(v);
131
+tap_rss_map_configurations = {
223
+ qobject_unref(resp);
132
+ .type = BPF_MAP_TYPE_ARRAY,
224
+}
133
+ .key_size = sizeof(__u32),
225
+
134
+ .value_size = sizeof(struct rss_config_t),
226
+static void wait_stream_disconnected(QTestState *qts, const char *id)
135
+ .max_entries = 1,
227
+{
136
+};
228
+ QDict *resp, *data;
137
+
229
+ QString *qstr;
138
+struct bpf_map_def SEC("maps")
230
+
139
+tap_rss_map_toeplitz_key = {
231
+ resp = qtest_qmp_eventwait_ref(qts, "NETDEV_STREAM_DISCONNECTED");
140
+ .type = BPF_MAP_TYPE_ARRAY,
232
+ g_assert_nonnull(resp);
141
+ .key_size = sizeof(__u32),
233
+ data = qdict_get_qdict(resp, "data");
142
+ .value_size = sizeof(struct toeplitz_key_data_t),
234
+ g_assert_nonnull(data);
143
+ .max_entries = 1,
235
+
144
+};
236
+ qstr = qobject_to(QString, qdict_get(data, "netdev-id"));
145
+
237
+ g_assert_nonnull(data);
146
+struct bpf_map_def SEC("maps")
238
+
147
+tap_rss_map_indirection_table = {
239
+ g_assert(!strcmp(qstring_get_str(qstr), id));
148
+ .type = BPF_MAP_TYPE_ARRAY,
240
+ qobject_unref(resp);
149
+ .key_size = sizeof(__u32),
241
+}
150
+ .value_size = sizeof(__u16),
242
+
151
+ .max_entries = INDIRECTION_TABLE_SIZE,
243
+static void test_stream_inet_reconnect(void)
152
+};
244
+{
153
+
245
+ QTestState *qts0, *qts1;
154
+static inline void net_rx_rss_add_chunk(__u8 *rss_input, size_t *bytes_written,
246
+ int port;
155
+ const void *ptr, size_t size) {
247
+ SocketAddress *addr;
156
+ __builtin_memcpy(&rss_input[*bytes_written], ptr, size);
248
+
157
+ *bytes_written += size;
249
+ port = inet_get_free_port(false);
158
+}
250
+ qts0 = qtest_initf("-nodefaults -M none "
159
+
251
+ "-netdev stream,id=st0,server=true,addr.type=inet,"
160
+static inline
252
+ "addr.ipv4=on,addr.ipv6=off,"
161
+void net_toeplitz_add(__u32 *result,
253
+ "addr.host=127.0.0.1,addr.port=%d", port);
162
+ __u8 *input,
254
+
163
+ __u32 len
255
+ EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0);
164
+ , struct toeplitz_key_data_t *key) {
256
+
165
+
257
+ qts1 = qtest_initf("-nodefaults -M none "
166
+ __u32 accumulator = *result;
258
+ "-netdev stream,server=false,id=st0,addr.type=inet,"
167
+ __u32 leftmost_32_bits = key->leftmost_32_bits;
259
+ "addr.ipv4=on,addr.ipv6=off,reconnect=1,"
168
+ __u32 byte;
260
+ "addr.host=127.0.0.1,addr.port=%d", port);
169
+
261
+
170
+ for (byte = 0; byte < HASH_CALCULATION_BUFFER_SIZE; byte++) {
262
+ wait_stream_connected(qts0, "st0", &addr);
171
+ __u8 input_byte = input[byte];
263
+ g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_INET);
172
+ __u8 key_byte = key->next_byte[byte];
264
+ g_assert_cmpstr(addr->u.inet.host, ==, "127.0.0.1");
173
+ __u8 bit;
265
+ qapi_free_SocketAddress(addr);
174
+
266
+
175
+ for (bit = 0; bit < 8; bit++) {
267
+ /* kill server */
176
+ if (input_byte & (1 << 7)) {
268
+ qtest_quit(qts0);
177
+ accumulator ^= leftmost_32_bits;
269
+
178
+ }
270
+ /* check client has been disconnected */
179
+
271
+ wait_stream_disconnected(qts1, "st0");
180
+ leftmost_32_bits =
272
+
181
+ (leftmost_32_bits << 1) | ((key_byte & (1 << 7)) >> 7);
273
+ /* restart server */
182
+
274
+ qts0 = qtest_initf("-nodefaults -M none "
183
+ input_byte <<= 1;
275
+ "-netdev stream,id=st0,server=true,addr.type=inet,"
184
+ key_byte <<= 1;
276
+ "addr.ipv4=on,addr.ipv6=off,"
185
+ }
277
+ "addr.host=127.0.0.1,addr.port=%d", port);
186
+ }
278
+
187
+
279
+ /* wait connection events*/
188
+ *result = accumulator;
280
+ wait_stream_connected(qts0, "st0", &addr);
189
+}
281
+ g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_INET);
190
+
282
+ g_assert_cmpstr(addr->u.inet.host, ==, "127.0.0.1");
191
+
283
+ qapi_free_SocketAddress(addr);
192
+static inline int ip6_extension_header_type(__u8 hdr_type)
284
+
193
+{
285
+ wait_stream_connected(qts1, "st0", &addr);
194
+ switch (hdr_type) {
286
+ g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_INET);
195
+ case IPPROTO_HOPOPTS:
287
+ g_assert_cmpstr(addr->u.inet.host, ==, "127.0.0.1");
196
+ case IPPROTO_ROUTING:
288
+ g_assert_cmpint(atoi(addr->u.inet.port), ==, port);
197
+ case IPPROTO_FRAGMENT:
289
+ qapi_free_SocketAddress(addr);
198
+ case IPPROTO_ICMPV6:
290
+
199
+ case IPPROTO_NONE:
291
+ qtest_quit(qts1);
200
+ case IPPROTO_DSTOPTS:
292
+ qtest_quit(qts0);
201
+ case IPPROTO_MH:
293
+}
202
+ return 1;
294
+
203
+ default:
295
static void test_stream_inet_ipv6(void)
204
+ return 0;
296
{
205
+ }
297
QTestState *qts0, *qts1;
206
+}
298
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
207
+/*
299
#ifndef _WIN32
208
+ * According to
300
qtest_add_func("/netdev/dgram/mcast", test_dgram_mcast);
209
+ * https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml
301
#endif
210
+ * we expect that there are would be no more than 11 extensions in IPv6 header,
302
+ qtest_add_func("/netdev/stream/inet/reconnect",
211
+ * also there is 27 TLV options for Destination and Hop-by-hop extensions.
303
+ test_stream_inet_reconnect);
212
+ * Need to choose reasonable amount of maximum extensions/options we may
304
}
213
+ * check to find ext src/dst.
305
if (has_ipv6) {
214
+ */
306
qtest_add_func("/netdev/stream/inet/ipv6", test_stream_inet_ipv6);
215
+#define IP6_EXTENSIONS_COUNT 11
216
+#define IP6_OPTIONS_COUNT 30
217
+
218
+static inline int parse_ipv6_ext(struct __sk_buff *skb,
219
+ struct packet_hash_info_t *info,
220
+ __u8 *l4_protocol, size_t *l4_offset)
221
+{
222
+ int err = 0;
223
+
224
+ if (!ip6_extension_header_type(*l4_protocol)) {
225
+ return 0;
226
+ }
227
+
228
+ struct ipv6_opt_hdr ext_hdr = {};
229
+
230
+ for (unsigned int i = 0; i < IP6_EXTENSIONS_COUNT; ++i) {
231
+
232
+ err = bpf_skb_load_bytes_relative(skb, *l4_offset, &ext_hdr,
233
+ sizeof(ext_hdr), BPF_HDR_START_NET);
234
+ if (err) {
235
+ goto error;
236
+ }
237
+
238
+ if (*l4_protocol == IPPROTO_ROUTING) {
239
+ struct ipv6_rt_hdr ext_rt = {};
240
+
241
+ err = bpf_skb_load_bytes_relative(skb, *l4_offset, &ext_rt,
242
+ sizeof(ext_rt), BPF_HDR_START_NET);
243
+ if (err) {
244
+ goto error;
245
+ }
246
+
247
+ if ((ext_rt.type == IPV6_SRCRT_TYPE_2) &&
248
+ (ext_rt.hdrlen == sizeof(struct in6_addr) / 8) &&
249
+ (ext_rt.segments_left == 1)) {
250
+
251
+ err = bpf_skb_load_bytes_relative(skb,
252
+ *l4_offset + offsetof(struct rt2_hdr, addr),
253
+ &info->in6_ext_dst, sizeof(info->in6_ext_dst),
254
+ BPF_HDR_START_NET);
255
+ if (err) {
256
+ goto error;
257
+ }
258
+
259
+ info->is_ipv6_ext_dst = 1;
260
+ }
261
+
262
+ } else if (*l4_protocol == IPPROTO_DSTOPTS) {
263
+ struct ipv6_opt_t {
264
+ __u8 type;
265
+ __u8 length;
266
+ } __attribute__((packed)) opt = {};
267
+
268
+ size_t opt_offset = sizeof(ext_hdr);
269
+
270
+ for (unsigned int j = 0; j < IP6_OPTIONS_COUNT; ++j) {
271
+ err = bpf_skb_load_bytes_relative(skb, *l4_offset + opt_offset,
272
+ &opt, sizeof(opt), BPF_HDR_START_NET);
273
+ if (err) {
274
+ goto error;
275
+ }
276
+
277
+ if (opt.type == IPV6_TLV_HAO) {
278
+ err = bpf_skb_load_bytes_relative(skb,
279
+ *l4_offset + opt_offset
280
+ + offsetof(struct ipv6_destopt_hao, addr),
281
+ &info->in6_ext_src, sizeof(info->in6_ext_src),
282
+ BPF_HDR_START_NET);
283
+ if (err) {
284
+ goto error;
285
+ }
286
+
287
+ info->is_ipv6_ext_src = 1;
288
+ break;
289
+ }
290
+
291
+ opt_offset += (opt.type == IPV6_TLV_PAD1) ?
292
+ 1 : opt.length + sizeof(opt);
293
+
294
+ if (opt_offset + 1 >= ext_hdr.hdrlen * 8) {
295
+ break;
296
+ }
297
+ }
298
+ } else if (*l4_protocol == IPPROTO_FRAGMENT) {
299
+ info->is_fragmented = true;
300
+ }
301
+
302
+ *l4_protocol = ext_hdr.nexthdr;
303
+ *l4_offset += (ext_hdr.hdrlen + 1) * 8;
304
+
305
+ if (!ip6_extension_header_type(ext_hdr.nexthdr)) {
306
+ return 0;
307
+ }
308
+ }
309
+
310
+ return 0;
311
+error:
312
+ return err;
313
+}
314
+
315
+static __be16 parse_eth_type(struct __sk_buff *skb)
316
+{
317
+ unsigned int offset = 12;
318
+ __be16 ret = 0;
319
+ int err = 0;
320
+
321
+ err = bpf_skb_load_bytes_relative(skb, offset, &ret, sizeof(ret),
322
+ BPF_HDR_START_MAC);
323
+ if (err) {
324
+ return 0;
325
+ }
326
+
327
+ switch (bpf_ntohs(ret)) {
328
+ case ETH_P_8021AD:
329
+ offset += 4;
330
+ case ETH_P_8021Q:
331
+ offset += 4;
332
+ err = bpf_skb_load_bytes_relative(skb, offset, &ret, sizeof(ret),
333
+ BPF_HDR_START_MAC);
334
+ default:
335
+ break;
336
+ }
337
+
338
+ if (err) {
339
+ return 0;
340
+ }
341
+
342
+ return ret;
343
+}
344
+
345
+static inline int parse_packet(struct __sk_buff *skb,
346
+ struct packet_hash_info_t *info)
347
+{
348
+ int err = 0;
349
+
350
+ if (!info || !skb) {
351
+ return -1;
352
+ }
353
+
354
+ size_t l4_offset = 0;
355
+ __u8 l4_protocol = 0;
356
+ __u16 l3_protocol = bpf_ntohs(parse_eth_type(skb));
357
+ if (l3_protocol == 0) {
358
+ err = -1;
359
+ goto error;
360
+ }
361
+
362
+ if (l3_protocol == ETH_P_IP) {
363
+ info->is_ipv4 = 1;
364
+
365
+ struct iphdr ip = {};
366
+ err = bpf_skb_load_bytes_relative(skb, 0, &ip, sizeof(ip),
367
+ BPF_HDR_START_NET);
368
+ if (err) {
369
+ goto error;
370
+ }
371
+
372
+ info->in_src = ip.saddr;
373
+ info->in_dst = ip.daddr;
374
+ info->is_fragmented = !!ip.frag_off;
375
+
376
+ l4_protocol = ip.protocol;
377
+ l4_offset = ip.ihl * 4;
378
+ } else if (l3_protocol == ETH_P_IPV6) {
379
+ info->is_ipv6 = 1;
380
+
381
+ struct ipv6hdr ip6 = {};
382
+ err = bpf_skb_load_bytes_relative(skb, 0, &ip6, sizeof(ip6),
383
+ BPF_HDR_START_NET);
384
+ if (err) {
385
+ goto error;
386
+ }
387
+
388
+ info->in6_src = ip6.saddr;
389
+ info->in6_dst = ip6.daddr;
390
+
391
+ l4_protocol = ip6.nexthdr;
392
+ l4_offset = sizeof(ip6);
393
+
394
+ err = parse_ipv6_ext(skb, info, &l4_protocol, &l4_offset);
395
+ if (err) {
396
+ goto error;
397
+ }
398
+ }
399
+
400
+ if (l4_protocol != 0 && !info->is_fragmented) {
401
+ if (l4_protocol == IPPROTO_TCP) {
402
+ info->is_tcp = 1;
403
+
404
+ struct tcphdr tcp = {};
405
+ err = bpf_skb_load_bytes_relative(skb, l4_offset, &tcp, sizeof(tcp),
406
+ BPF_HDR_START_NET);
407
+ if (err) {
408
+ goto error;
409
+ }
410
+
411
+ info->src_port = tcp.source;
412
+ info->dst_port = tcp.dest;
413
+ } else if (l4_protocol == IPPROTO_UDP) { /* TODO: add udplite? */
414
+ info->is_udp = 1;
415
+
416
+ struct udphdr udp = {};
417
+ err = bpf_skb_load_bytes_relative(skb, l4_offset, &udp, sizeof(udp),
418
+ BPF_HDR_START_NET);
419
+ if (err) {
420
+ goto error;
421
+ }
422
+
423
+ info->src_port = udp.source;
424
+ info->dst_port = udp.dest;
425
+ }
426
+ }
427
+
428
+ return 0;
429
+
430
+error:
431
+ return err;
432
+}
433
+
434
+static inline __u32 calculate_rss_hash(struct __sk_buff *skb,
435
+ struct rss_config_t *config, struct toeplitz_key_data_t *toe)
436
+{
437
+ __u8 rss_input[HASH_CALCULATION_BUFFER_SIZE] = {};
438
+ size_t bytes_written = 0;
439
+ __u32 result = 0;
440
+ int err = 0;
441
+ struct packet_hash_info_t packet_info = {};
442
+
443
+ err = parse_packet(skb, &packet_info);
444
+ if (err) {
445
+ return 0;
446
+ }
447
+
448
+ if (packet_info.is_ipv4) {
449
+ if (packet_info.is_tcp &&
450
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_TCPv4) {
451
+
452
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
453
+ &packet_info.in_src,
454
+ sizeof(packet_info.in_src));
455
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
456
+ &packet_info.in_dst,
457
+ sizeof(packet_info.in_dst));
458
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
459
+ &packet_info.src_port,
460
+ sizeof(packet_info.src_port));
461
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
462
+ &packet_info.dst_port,
463
+ sizeof(packet_info.dst_port));
464
+ } else if (packet_info.is_udp &&
465
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_UDPv4) {
466
+
467
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
468
+ &packet_info.in_src,
469
+ sizeof(packet_info.in_src));
470
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
471
+ &packet_info.in_dst,
472
+ sizeof(packet_info.in_dst));
473
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
474
+ &packet_info.src_port,
475
+ sizeof(packet_info.src_port));
476
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
477
+ &packet_info.dst_port,
478
+ sizeof(packet_info.dst_port));
479
+ } else if (config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_IPv4) {
480
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
481
+ &packet_info.in_src,
482
+ sizeof(packet_info.in_src));
483
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
484
+ &packet_info.in_dst,
485
+ sizeof(packet_info.in_dst));
486
+ }
487
+ } else if (packet_info.is_ipv6) {
488
+ if (packet_info.is_tcp &&
489
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_TCPv6) {
490
+
491
+ if (packet_info.is_ipv6_ext_src &&
492
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_TCP_EX) {
493
+
494
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
495
+ &packet_info.in6_ext_src,
496
+ sizeof(packet_info.in6_ext_src));
497
+ } else {
498
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
499
+ &packet_info.in6_src,
500
+ sizeof(packet_info.in6_src));
501
+ }
502
+ if (packet_info.is_ipv6_ext_dst &&
503
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_TCP_EX) {
504
+
505
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
506
+ &packet_info.in6_ext_dst,
507
+ sizeof(packet_info.in6_ext_dst));
508
+ } else {
509
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
510
+ &packet_info.in6_dst,
511
+ sizeof(packet_info.in6_dst));
512
+ }
513
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
514
+ &packet_info.src_port,
515
+ sizeof(packet_info.src_port));
516
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
517
+ &packet_info.dst_port,
518
+ sizeof(packet_info.dst_port));
519
+ } else if (packet_info.is_udp &&
520
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_UDPv6) {
521
+
522
+ if (packet_info.is_ipv6_ext_src &&
523
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) {
524
+
525
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
526
+ &packet_info.in6_ext_src,
527
+ sizeof(packet_info.in6_ext_src));
528
+ } else {
529
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
530
+ &packet_info.in6_src,
531
+ sizeof(packet_info.in6_src));
532
+ }
533
+ if (packet_info.is_ipv6_ext_dst &&
534
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) {
535
+
536
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
537
+ &packet_info.in6_ext_dst,
538
+ sizeof(packet_info.in6_ext_dst));
539
+ } else {
540
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
541
+ &packet_info.in6_dst,
542
+ sizeof(packet_info.in6_dst));
543
+ }
544
+
545
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
546
+ &packet_info.src_port,
547
+ sizeof(packet_info.src_port));
548
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
549
+ &packet_info.dst_port,
550
+ sizeof(packet_info.dst_port));
551
+
552
+ } else if (config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_IPv6) {
553
+ if (packet_info.is_ipv6_ext_src &&
554
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_IP_EX) {
555
+
556
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
557
+ &packet_info.in6_ext_src,
558
+ sizeof(packet_info.in6_ext_src));
559
+ } else {
560
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
561
+ &packet_info.in6_src,
562
+ sizeof(packet_info.in6_src));
563
+ }
564
+ if (packet_info.is_ipv6_ext_dst &&
565
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_IP_EX) {
566
+
567
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
568
+ &packet_info.in6_ext_dst,
569
+ sizeof(packet_info.in6_ext_dst));
570
+ } else {
571
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
572
+ &packet_info.in6_dst,
573
+ sizeof(packet_info.in6_dst));
574
+ }
575
+ }
576
+ }
577
+
578
+ if (bytes_written) {
579
+ net_toeplitz_add(&result, rss_input, bytes_written, toe);
580
+ }
581
+
582
+ return result;
583
+}
584
+
585
+SEC("tun_rss_steering")
586
+int tun_rss_steering_prog(struct __sk_buff *skb)
587
+{
588
+
589
+ struct rss_config_t *config;
590
+ struct toeplitz_key_data_t *toe;
591
+
592
+ __u32 key = 0;
593
+ __u32 hash = 0;
594
+
595
+ config = bpf_map_lookup_elem(&tap_rss_map_configurations, &key);
596
+ toe = bpf_map_lookup_elem(&tap_rss_map_toeplitz_key, &key);
597
+
598
+ if (config && toe) {
599
+ if (!config->redirect) {
600
+ return config->default_queue;
601
+ }
602
+
603
+ hash = calculate_rss_hash(skb, config, toe);
604
+ if (hash) {
605
+ __u32 table_idx = hash % config->indirections_len;
606
+ __u16 *queue = 0;
607
+
608
+ queue = bpf_map_lookup_elem(&tap_rss_map_indirection_table,
609
+ &table_idx);
610
+
611
+ if (queue) {
612
+ return *queue;
613
+ }
614
+ }
615
+
616
+ return config->default_queue;
617
+ }
618
+
619
+ return -1;
620
+}
621
+
622
+char _license[] SEC("license") = "GPL v2";
623
--
307
--
624
2.7.4
308
2.7.4
625
626
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Additional code that will be used for eBPF setting steering routine.
3
VHOST_BACKEND_F_IOTLB_ASID is the feature bit, not the bitmask. Since
4
the device under test also provided VHOST_BACKEND_F_IOTLB_MSG_V2 and
5
VHOST_BACKEND_F_IOTLB_BATCH, this went unnoticed.
4
6
5
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
7
Fixes: c1a1008685 ("vdpa: always start CVQ in SVQ mode if possible")
8
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
9
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
10
Acked-by: Jason Wang <jasowang@redhat.com>
6
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
7
---
12
---
8
net/tap-linux.h | 1 +
13
net/vhost-vdpa.c | 2 +-
9
1 file changed, 1 insertion(+)
14
1 file changed, 1 insertion(+), 1 deletion(-)
10
15
11
diff --git a/net/tap-linux.h b/net/tap-linux.h
16
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
12
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
13
--- a/net/tap-linux.h
18
--- a/net/vhost-vdpa.c
14
+++ b/net/tap-linux.h
19
+++ b/net/vhost-vdpa.c
15
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_net_cvq_start(NetClientState *nc)
16
#define TUNSETQUEUE _IOW('T', 217, int)
21
g_strerror(errno), errno);
17
#define TUNSETVNETLE _IOW('T', 220, int)
22
return -1;
18
#define TUNSETVNETBE _IOW('T', 222, int)
23
}
19
+#define TUNSETSTEERINGEBPF _IOR('T', 224, int)
24
- if (!(backend_features & VHOST_BACKEND_F_IOTLB_ASID) ||
20
25
+ if (!(backend_features & BIT_ULL(VHOST_BACKEND_F_IOTLB_ASID)) ||
21
#endif
26
!vhost_vdpa_net_valid_svq_features(v->dev->features, NULL)) {
22
27
return 0;
28
}
23
--
29
--
24
2.7.4
30
2.7.4
25
31
26
32
diff view generated by jsdifflib