vfio/pci: Fixup PCI option ROMs
[qemu/ar7.git] / net / filter.c
bloba08ef68ae6658081e24934e3576526fc0fff50fc
1 /*
2 * Copyright (c) 2015 FUJITSU LIMITED
3 * Author: Yang Hongyang <yanghy@cn.fujitsu.com>
5 * This work is licensed under the terms of the GNU GPL, version 2 or
6 * later. See the COPYING file in the top-level directory.
7 */
9 #include "qemu/osdep.h"
10 #include "qemu-common.h"
11 #include "qapi/qmp/qerror.h"
12 #include "qemu/error-report.h"
14 #include "net/filter.h"
15 #include "net/net.h"
16 #include "net/vhost_net.h"
17 #include "qom/object_interfaces.h"
18 #include "qemu/iov.h"
20 static inline bool qemu_can_skip_netfilter(NetFilterState *nf)
22 return !nf->on;
25 ssize_t qemu_netfilter_receive(NetFilterState *nf,
26 NetFilterDirection direction,
27 NetClientState *sender,
28 unsigned flags,
29 const struct iovec *iov,
30 int iovcnt,
31 NetPacketSent *sent_cb)
33 if (qemu_can_skip_netfilter(nf)) {
34 return 0;
36 if (nf->direction == direction ||
37 nf->direction == NET_FILTER_DIRECTION_ALL) {
38 return NETFILTER_GET_CLASS(OBJECT(nf))->receive_iov(
39 nf, sender, flags, iov, iovcnt, sent_cb);
42 return 0;
45 static NetFilterState *netfilter_next(NetFilterState *nf,
46 NetFilterDirection dir)
48 NetFilterState *next;
50 if (dir == NET_FILTER_DIRECTION_TX) {
51 /* forward walk through filters */
52 next = QTAILQ_NEXT(nf, next);
53 } else {
54 /* reverse order */
55 next = QTAILQ_PREV(nf, NetFilterHead, next);
58 return next;
61 ssize_t qemu_netfilter_pass_to_next(NetClientState *sender,
62 unsigned flags,
63 const struct iovec *iov,
64 int iovcnt,
65 void *opaque)
67 int ret = 0;
68 int direction;
69 NetFilterState *nf = opaque;
70 NetFilterState *next = NULL;
72 if (!sender || !sender->peer) {
73 /* no receiver, or sender been deleted, no need to pass it further */
74 goto out;
77 if (nf->direction == NET_FILTER_DIRECTION_ALL) {
78 if (sender == nf->netdev) {
79 /* This packet is sent by netdev itself */
80 direction = NET_FILTER_DIRECTION_TX;
81 } else {
82 direction = NET_FILTER_DIRECTION_RX;
84 } else {
85 direction = nf->direction;
88 next = netfilter_next(nf, direction);
89 while (next) {
91 * if qemu_netfilter_pass_to_next been called, means that
92 * the packet has been hold by filter and has already retured size
93 * to the sender, so sent_cb shouldn't be called later, just
94 * pass NULL to next.
96 ret = qemu_netfilter_receive(next, direction, sender, flags, iov,
97 iovcnt, NULL);
98 if (ret) {
99 return ret;
101 next = netfilter_next(next, direction);
105 * We have gone through all filters, pass it to receiver.
106 * Do the valid check again incase sender or receiver been
107 * deleted while we go through filters.
109 if (sender && sender->peer) {
110 qemu_net_queue_send_iov(sender->peer->incoming_queue,
111 sender, flags, iov, iovcnt, NULL);
114 out:
115 /* no receiver, or sender been deleted */
116 return iov_size(iov, iovcnt);
119 static char *netfilter_get_netdev_id(Object *obj, Error **errp)
121 NetFilterState *nf = NETFILTER(obj);
123 return g_strdup(nf->netdev_id);
126 static void netfilter_set_netdev_id(Object *obj, const char *str, Error **errp)
128 NetFilterState *nf = NETFILTER(obj);
130 nf->netdev_id = g_strdup(str);
133 static int netfilter_get_direction(Object *obj, Error **errp G_GNUC_UNUSED)
135 NetFilterState *nf = NETFILTER(obj);
136 return nf->direction;
139 static void netfilter_set_direction(Object *obj, int direction, Error **errp)
141 NetFilterState *nf = NETFILTER(obj);
142 nf->direction = direction;
145 static char *netfilter_get_status(Object *obj, Error **errp)
147 NetFilterState *nf = NETFILTER(obj);
149 return nf->on ? g_strdup("on") : g_strdup("off");
152 static void netfilter_set_status(Object *obj, const char *str, Error **errp)
154 NetFilterState *nf = NETFILTER(obj);
155 NetFilterClass *nfc = NETFILTER_GET_CLASS(obj);
157 if (strcmp(str, "on") && strcmp(str, "off")) {
158 error_setg(errp, "Invalid value for netfilter status, "
159 "should be 'on' or 'off'");
160 return;
162 if (nf->on == !strcmp(str, "on")) {
163 return;
165 nf->on = !nf->on;
166 if (nfc->status_changed) {
167 nfc->status_changed(nf, errp);
171 static void netfilter_init(Object *obj)
173 NetFilterState *nf = NETFILTER(obj);
175 nf->on = true;
177 object_property_add_str(obj, "netdev",
178 netfilter_get_netdev_id, netfilter_set_netdev_id,
179 NULL);
180 object_property_add_enum(obj, "queue", "NetFilterDirection",
181 NetFilterDirection_lookup,
182 netfilter_get_direction, netfilter_set_direction,
183 NULL);
184 object_property_add_str(obj, "status",
185 netfilter_get_status, netfilter_set_status,
186 NULL);
189 static void netfilter_complete(UserCreatable *uc, Error **errp)
191 NetFilterState *nf = NETFILTER(uc);
192 NetClientState *ncs[MAX_QUEUE_NUM];
193 NetFilterClass *nfc = NETFILTER_GET_CLASS(uc);
194 int queues;
195 Error *local_err = NULL;
197 if (!nf->netdev_id) {
198 error_setg(errp, "Parameter 'netdev' is required");
199 return;
202 queues = qemu_find_net_clients_except(nf->netdev_id, ncs,
203 NET_CLIENT_OPTIONS_KIND_NIC,
204 MAX_QUEUE_NUM);
205 if (queues < 1) {
206 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "netdev",
207 "a network backend id");
208 return;
209 } else if (queues > 1) {
210 error_setg(errp, "multiqueue is not supported");
211 return;
214 if (get_vhost_net(ncs[0])) {
215 error_setg(errp, "Vhost is not supported");
216 return;
219 nf->netdev = ncs[0];
221 if (nfc->setup) {
222 nfc->setup(nf, &local_err);
223 if (local_err) {
224 error_propagate(errp, local_err);
225 return;
228 QTAILQ_INSERT_TAIL(&nf->netdev->filters, nf, next);
231 static void netfilter_finalize(Object *obj)
233 NetFilterState *nf = NETFILTER(obj);
234 NetFilterClass *nfc = NETFILTER_GET_CLASS(obj);
236 if (nfc->cleanup) {
237 nfc->cleanup(nf);
240 if (nf->netdev && !QTAILQ_EMPTY(&nf->netdev->filters) &&
241 nf->next.tqe_prev) {
242 QTAILQ_REMOVE(&nf->netdev->filters, nf, next);
244 g_free(nf->netdev_id);
247 static void netfilter_class_init(ObjectClass *oc, void *data)
249 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
251 ucc->complete = netfilter_complete;
254 static const TypeInfo netfilter_info = {
255 .name = TYPE_NETFILTER,
256 .parent = TYPE_OBJECT,
257 .abstract = true,
258 .class_size = sizeof(NetFilterClass),
259 .class_init = netfilter_class_init,
260 .instance_size = sizeof(NetFilterState),
261 .instance_init = netfilter_init,
262 .instance_finalize = netfilter_finalize,
263 .interfaces = (InterfaceInfo[]) {
264 { TYPE_USER_CREATABLE },
269 static void register_types(void)
271 type_register_static(&netfilter_info);
274 type_init(register_types);