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