xref: /qemu/net/filter.c (revision 226419d6)
1 /*
2  * Copyright (c) 2015 FUJITSU LIMITED
3  * Author: Yang Hongyang <yanghy@cn.fujitsu.com>
4  *
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  */
8 
9 #include "qemu/osdep.h"
10 #include "qemu-common.h"
11 #include "qapi/qmp/qerror.h"
12 #include "qemu/error-report.h"
13 
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"
19 
20 static inline bool qemu_can_skip_netfilter(NetFilterState *nf)
21 {
22     return !nf->on;
23 }
24 
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)
32 {
33     if (qemu_can_skip_netfilter(nf)) {
34         return 0;
35     }
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);
40     }
41 
42     return 0;
43 }
44 
45 static NetFilterState *netfilter_next(NetFilterState *nf,
46                                       NetFilterDirection dir)
47 {
48     NetFilterState *next;
49 
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);
56     }
57 
58     return next;
59 }
60 
61 ssize_t qemu_netfilter_pass_to_next(NetClientState *sender,
62                                     unsigned flags,
63                                     const struct iovec *iov,
64                                     int iovcnt,
65                                     void *opaque)
66 {
67     int ret = 0;
68     int direction;
69     NetFilterState *nf = opaque;
70     NetFilterState *next = NULL;
71 
72     if (!sender || !sender->peer) {
73         /* no receiver, or sender been deleted, no need to pass it further */
74         goto out;
75     }
76 
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;
83         }
84     } else {
85         direction = nf->direction;
86     }
87 
88     next = netfilter_next(nf, direction);
89     while (next) {
90         /*
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.
95          */
96         ret = qemu_netfilter_receive(next, direction, sender, flags, iov,
97                                      iovcnt, NULL);
98         if (ret) {
99             return ret;
100         }
101         next = netfilter_next(next, direction);
102     }
103 
104     /*
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.
108      */
109     if (sender && sender->peer) {
110         qemu_net_queue_send_iov(sender->peer->incoming_queue,
111                                 sender, flags, iov, iovcnt, NULL);
112     }
113 
114 out:
115     /* no receiver, or sender been deleted */
116     return iov_size(iov, iovcnt);
117 }
118 
119 static char *netfilter_get_netdev_id(Object *obj, Error **errp)
120 {
121     NetFilterState *nf = NETFILTER(obj);
122 
123     return g_strdup(nf->netdev_id);
124 }
125 
126 static void netfilter_set_netdev_id(Object *obj, const char *str, Error **errp)
127 {
128     NetFilterState *nf = NETFILTER(obj);
129 
130     nf->netdev_id = g_strdup(str);
131 }
132 
133 static int netfilter_get_direction(Object *obj, Error **errp G_GNUC_UNUSED)
134 {
135     NetFilterState *nf = NETFILTER(obj);
136     return nf->direction;
137 }
138 
139 static void netfilter_set_direction(Object *obj, int direction, Error **errp)
140 {
141     NetFilterState *nf = NETFILTER(obj);
142     nf->direction = direction;
143 }
144 
145 static char *netfilter_get_status(Object *obj, Error **errp)
146 {
147     NetFilterState *nf = NETFILTER(obj);
148 
149     return nf->on ? g_strdup("on") : g_strdup("off");
150 }
151 
152 static void netfilter_set_status(Object *obj, const char *str, Error **errp)
153 {
154     NetFilterState *nf = NETFILTER(obj);
155     NetFilterClass *nfc = NETFILTER_GET_CLASS(obj);
156 
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;
161     }
162     if (nf->on == !strcmp(str, "on")) {
163         return;
164     }
165     nf->on = !nf->on;
166     if (nfc->status_changed) {
167         nfc->status_changed(nf, errp);
168     }
169 }
170 
171 static void netfilter_init(Object *obj)
172 {
173     NetFilterState *nf = NETFILTER(obj);
174 
175     nf->on = true;
176 
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);
187 }
188 
189 static void netfilter_complete(UserCreatable *uc, Error **errp)
190 {
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;
196 
197     if (!nf->netdev_id) {
198         error_setg(errp, "Parameter 'netdev' is required");
199         return;
200     }
201 
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;
212     }
213 
214     if (get_vhost_net(ncs[0])) {
215         error_setg(errp, "Vhost is not supported");
216         return;
217     }
218 
219     nf->netdev = ncs[0];
220 
221     if (nfc->setup) {
222         nfc->setup(nf, &local_err);
223         if (local_err) {
224             error_propagate(errp, local_err);
225             return;
226         }
227     }
228     QTAILQ_INSERT_TAIL(&nf->netdev->filters, nf, next);
229 }
230 
231 static void netfilter_finalize(Object *obj)
232 {
233     NetFilterState *nf = NETFILTER(obj);
234     NetFilterClass *nfc = NETFILTER_GET_CLASS(obj);
235 
236     if (nfc->cleanup) {
237         nfc->cleanup(nf);
238     }
239 
240     if (nf->netdev && !QTAILQ_EMPTY(&nf->netdev->filters) &&
241         nf->next.tqe_prev) {
242         QTAILQ_REMOVE(&nf->netdev->filters, nf, next);
243     }
244     g_free(nf->netdev_id);
245 }
246 
247 static void netfilter_class_init(ObjectClass *oc, void *data)
248 {
249     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
250 
251     ucc->complete = netfilter_complete;
252 }
253 
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 },
265         { }
266     }
267 };
268 
269 static void register_types(void)
270 {
271     type_register_static(&netfilter_info);
272 }
273 
274 type_init(register_types);
275