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 "qapi/error.h" 11 #include "qemu-common.h" 12 #include "qapi/qmp/qerror.h" 13 #include "qemu/error-report.h" 14 15 #include "net/filter.h" 16 #include "net/net.h" 17 #include "net/vhost_net.h" 18 #include "qom/object_interfaces.h" 19 #include "qemu/iov.h" 20 21 static inline bool qemu_can_skip_netfilter(NetFilterState *nf) 22 { 23 return !nf->on; 24 } 25 26 ssize_t qemu_netfilter_receive(NetFilterState *nf, 27 NetFilterDirection direction, 28 NetClientState *sender, 29 unsigned flags, 30 const struct iovec *iov, 31 int iovcnt, 32 NetPacketSent *sent_cb) 33 { 34 if (qemu_can_skip_netfilter(nf)) { 35 return 0; 36 } 37 if (nf->direction == direction || 38 nf->direction == NET_FILTER_DIRECTION_ALL) { 39 return NETFILTER_GET_CLASS(OBJECT(nf))->receive_iov( 40 nf, sender, flags, iov, iovcnt, sent_cb); 41 } 42 43 return 0; 44 } 45 46 static NetFilterState *netfilter_next(NetFilterState *nf, 47 NetFilterDirection dir) 48 { 49 NetFilterState *next; 50 51 if (dir == NET_FILTER_DIRECTION_TX) { 52 /* forward walk through filters */ 53 next = QTAILQ_NEXT(nf, next); 54 } else { 55 /* reverse order */ 56 next = QTAILQ_PREV(nf, NetFilterHead, next); 57 } 58 59 return next; 60 } 61 62 ssize_t qemu_netfilter_pass_to_next(NetClientState *sender, 63 unsigned flags, 64 const struct iovec *iov, 65 int iovcnt, 66 void *opaque) 67 { 68 int ret = 0; 69 int direction; 70 NetFilterState *nf = opaque; 71 NetFilterState *next = NULL; 72 73 if (!sender || !sender->peer) { 74 /* no receiver, or sender been deleted, no need to pass it further */ 75 goto out; 76 } 77 78 if (nf->direction == NET_FILTER_DIRECTION_ALL) { 79 if (sender == nf->netdev) { 80 /* This packet is sent by netdev itself */ 81 direction = NET_FILTER_DIRECTION_TX; 82 } else { 83 direction = NET_FILTER_DIRECTION_RX; 84 } 85 } else { 86 direction = nf->direction; 87 } 88 89 next = netfilter_next(nf, direction); 90 while (next) { 91 /* 92 * if qemu_netfilter_pass_to_next been called, means that 93 * the packet has been hold by filter and has already retured size 94 * to the sender, so sent_cb shouldn't be called later, just 95 * pass NULL to next. 96 */ 97 ret = qemu_netfilter_receive(next, direction, sender, flags, iov, 98 iovcnt, NULL); 99 if (ret) { 100 return ret; 101 } 102 next = netfilter_next(next, direction); 103 } 104 105 /* 106 * We have gone through all filters, pass it to receiver. 107 * Do the valid check again incase sender or receiver been 108 * deleted while we go through filters. 109 */ 110 if (sender && sender->peer) { 111 qemu_net_queue_send_iov(sender->peer->incoming_queue, 112 sender, flags, iov, iovcnt, NULL); 113 } 114 115 out: 116 /* no receiver, or sender been deleted */ 117 return iov_size(iov, iovcnt); 118 } 119 120 static char *netfilter_get_netdev_id(Object *obj, Error **errp) 121 { 122 NetFilterState *nf = NETFILTER(obj); 123 124 return g_strdup(nf->netdev_id); 125 } 126 127 static void netfilter_set_netdev_id(Object *obj, const char *str, Error **errp) 128 { 129 NetFilterState *nf = NETFILTER(obj); 130 131 nf->netdev_id = g_strdup(str); 132 } 133 134 static int netfilter_get_direction(Object *obj, Error **errp G_GNUC_UNUSED) 135 { 136 NetFilterState *nf = NETFILTER(obj); 137 return nf->direction; 138 } 139 140 static void netfilter_set_direction(Object *obj, int direction, Error **errp) 141 { 142 NetFilterState *nf = NETFILTER(obj); 143 nf->direction = direction; 144 } 145 146 static char *netfilter_get_status(Object *obj, Error **errp) 147 { 148 NetFilterState *nf = NETFILTER(obj); 149 150 return nf->on ? g_strdup("on") : g_strdup("off"); 151 } 152 153 static void netfilter_set_status(Object *obj, const char *str, Error **errp) 154 { 155 NetFilterState *nf = NETFILTER(obj); 156 NetFilterClass *nfc = NETFILTER_GET_CLASS(obj); 157 158 if (strcmp(str, "on") && strcmp(str, "off")) { 159 error_setg(errp, "Invalid value for netfilter status, " 160 "should be 'on' or 'off'"); 161 return; 162 } 163 if (nf->on == !strcmp(str, "on")) { 164 return; 165 } 166 nf->on = !nf->on; 167 if (nf->netdev && nfc->status_changed) { 168 nfc->status_changed(nf, errp); 169 } 170 } 171 172 static void netfilter_init(Object *obj) 173 { 174 NetFilterState *nf = NETFILTER(obj); 175 176 nf->on = true; 177 178 object_property_add_str(obj, "netdev", 179 netfilter_get_netdev_id, netfilter_set_netdev_id, 180 NULL); 181 object_property_add_enum(obj, "queue", "NetFilterDirection", 182 &NetFilterDirection_lookup, 183 netfilter_get_direction, netfilter_set_direction, 184 NULL); 185 object_property_add_str(obj, "status", 186 netfilter_get_status, netfilter_set_status, 187 NULL); 188 } 189 190 static void netfilter_complete(UserCreatable *uc, Error **errp) 191 { 192 NetFilterState *nf = NETFILTER(uc); 193 NetClientState *ncs[MAX_QUEUE_NUM]; 194 NetFilterClass *nfc = NETFILTER_GET_CLASS(uc); 195 int queues; 196 Error *local_err = NULL; 197 198 if (!nf->netdev_id) { 199 error_setg(errp, "Parameter 'netdev' is required"); 200 return; 201 } 202 203 queues = qemu_find_net_clients_except(nf->netdev_id, ncs, 204 NET_CLIENT_DRIVER_NIC, 205 MAX_QUEUE_NUM); 206 if (queues < 1) { 207 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "netdev", 208 "a network backend id"); 209 return; 210 } else if (queues > 1) { 211 error_setg(errp, "multiqueue is not supported"); 212 return; 213 } 214 215 if (get_vhost_net(ncs[0])) { 216 error_setg(errp, "Vhost is not supported"); 217 return; 218 } 219 220 nf->netdev = ncs[0]; 221 222 if (nfc->setup) { 223 nfc->setup(nf, &local_err); 224 if (local_err) { 225 error_propagate(errp, local_err); 226 return; 227 } 228 } 229 QTAILQ_INSERT_TAIL(&nf->netdev->filters, nf, next); 230 } 231 232 static void netfilter_finalize(Object *obj) 233 { 234 NetFilterState *nf = NETFILTER(obj); 235 NetFilterClass *nfc = NETFILTER_GET_CLASS(obj); 236 237 if (nfc->cleanup) { 238 nfc->cleanup(nf); 239 } 240 241 if (nf->netdev && !QTAILQ_EMPTY(&nf->netdev->filters) && 242 QTAILQ_IN_USE(nf, next)) { 243 QTAILQ_REMOVE(&nf->netdev->filters, nf, next); 244 } 245 g_free(nf->netdev_id); 246 } 247 248 static void netfilter_class_init(ObjectClass *oc, void *data) 249 { 250 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); 251 252 ucc->complete = netfilter_complete; 253 } 254 255 static const TypeInfo netfilter_info = { 256 .name = TYPE_NETFILTER, 257 .parent = TYPE_OBJECT, 258 .abstract = true, 259 .class_size = sizeof(NetFilterClass), 260 .class_init = netfilter_class_init, 261 .instance_size = sizeof(NetFilterState), 262 .instance_init = netfilter_init, 263 .instance_finalize = netfilter_finalize, 264 .interfaces = (InterfaceInfo[]) { 265 { TYPE_USER_CREATABLE }, 266 { } 267 } 268 }; 269 270 static void register_types(void) 271 { 272 type_register_static(&netfilter_info); 273 } 274 275 type_init(register_types); 276