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 "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 #include "qemu/module.h" 20 #include "net/colo.h" 21 #include "migration/colo.h" 22 23 static inline bool qemu_can_skip_netfilter(NetFilterState *nf) 24 { 25 return !nf->on; 26 } 27 28 ssize_t qemu_netfilter_receive(NetFilterState *nf, 29 NetFilterDirection direction, 30 NetClientState *sender, 31 unsigned flags, 32 const struct iovec *iov, 33 int iovcnt, 34 NetPacketSent *sent_cb) 35 { 36 if (qemu_can_skip_netfilter(nf)) { 37 return 0; 38 } 39 if (nf->direction == direction || 40 nf->direction == NET_FILTER_DIRECTION_ALL) { 41 return NETFILTER_GET_CLASS(OBJECT(nf))->receive_iov( 42 nf, sender, flags, iov, iovcnt, sent_cb); 43 } 44 45 return 0; 46 } 47 48 static NetFilterState *netfilter_next(NetFilterState *nf, 49 NetFilterDirection dir) 50 { 51 NetFilterState *next; 52 53 if (dir == NET_FILTER_DIRECTION_TX) { 54 /* forward walk through filters */ 55 next = QTAILQ_NEXT(nf, next); 56 } else { 57 /* reverse order */ 58 next = QTAILQ_PREV(nf, next); 59 } 60 61 return next; 62 } 63 64 ssize_t qemu_netfilter_pass_to_next(NetClientState *sender, 65 unsigned flags, 66 const struct iovec *iov, 67 int iovcnt, 68 void *opaque) 69 { 70 int ret = 0; 71 int direction; 72 NetFilterState *nf = opaque; 73 NetFilterState *next = NULL; 74 75 if (!sender || !sender->peer) { 76 /* no receiver, or sender been deleted, no need to pass it further */ 77 goto out; 78 } 79 80 if (nf->direction == NET_FILTER_DIRECTION_ALL) { 81 if (sender == nf->netdev) { 82 /* This packet is sent by netdev itself */ 83 direction = NET_FILTER_DIRECTION_TX; 84 } else { 85 direction = NET_FILTER_DIRECTION_RX; 86 } 87 } else { 88 direction = nf->direction; 89 } 90 91 next = netfilter_next(nf, direction); 92 while (next) { 93 /* 94 * if qemu_netfilter_pass_to_next been called, means that 95 * the packet has been hold by filter and has already retured size 96 * to the sender, so sent_cb shouldn't be called later, just 97 * pass NULL to next. 98 */ 99 ret = qemu_netfilter_receive(next, direction, sender, flags, iov, 100 iovcnt, NULL); 101 if (ret) { 102 return ret; 103 } 104 next = netfilter_next(next, direction); 105 } 106 107 /* 108 * We have gone through all filters, pass it to receiver. 109 * Do the valid check again incase sender or receiver been 110 * deleted while we go through filters. 111 */ 112 if (sender && sender->peer) { 113 qemu_net_queue_send_iov(sender->peer->incoming_queue, 114 sender, flags, iov, iovcnt, NULL); 115 } 116 117 out: 118 /* no receiver, or sender been deleted */ 119 return iov_size(iov, iovcnt); 120 } 121 122 static char *netfilter_get_netdev_id(Object *obj, Error **errp) 123 { 124 NetFilterState *nf = NETFILTER(obj); 125 126 return g_strdup(nf->netdev_id); 127 } 128 129 static void netfilter_set_netdev_id(Object *obj, const char *str, Error **errp) 130 { 131 NetFilterState *nf = NETFILTER(obj); 132 133 nf->netdev_id = g_strdup(str); 134 } 135 136 static int netfilter_get_direction(Object *obj, Error **errp G_GNUC_UNUSED) 137 { 138 NetFilterState *nf = NETFILTER(obj); 139 return nf->direction; 140 } 141 142 static void netfilter_set_direction(Object *obj, int direction, Error **errp) 143 { 144 NetFilterState *nf = NETFILTER(obj); 145 nf->direction = direction; 146 } 147 148 static char *netfilter_get_status(Object *obj, Error **errp) 149 { 150 NetFilterState *nf = NETFILTER(obj); 151 152 return nf->on ? g_strdup("on") : g_strdup("off"); 153 } 154 155 static void netfilter_set_status(Object *obj, const char *str, Error **errp) 156 { 157 NetFilterState *nf = NETFILTER(obj); 158 NetFilterClass *nfc = NETFILTER_GET_CLASS(obj); 159 160 if (strcmp(str, "on") && strcmp(str, "off")) { 161 error_setg(errp, "Invalid value for netfilter status, " 162 "should be 'on' or 'off'"); 163 return; 164 } 165 if (nf->on == !strcmp(str, "on")) { 166 return; 167 } 168 nf->on = !nf->on; 169 if (nf->netdev && nfc->status_changed) { 170 nfc->status_changed(nf, errp); 171 } 172 } 173 174 static char *netfilter_get_position(Object *obj, Error **errp) 175 { 176 NetFilterState *nf = NETFILTER(obj); 177 178 return g_strdup(nf->position); 179 } 180 181 static void netfilter_set_position(Object *obj, const char *str, Error **errp) 182 { 183 NetFilterState *nf = NETFILTER(obj); 184 185 nf->position = g_strdup(str); 186 } 187 188 static char *netfilter_get_insert(Object *obj, Error **errp) 189 { 190 NetFilterState *nf = NETFILTER(obj); 191 192 return nf->insert_before_flag ? g_strdup("before") : g_strdup("behind"); 193 } 194 195 static void netfilter_set_insert(Object *obj, const char *str, Error **errp) 196 { 197 NetFilterState *nf = NETFILTER(obj); 198 199 if (strcmp(str, "before") && strcmp(str, "behind")) { 200 error_setg(errp, "Invalid value for netfilter insert, " 201 "should be 'before' or 'behind'"); 202 return; 203 } 204 205 nf->insert_before_flag = !strcmp(str, "before"); 206 } 207 208 static void netfilter_init(Object *obj) 209 { 210 NetFilterState *nf = NETFILTER(obj); 211 212 nf->on = true; 213 nf->insert_before_flag = false; 214 nf->position = g_strdup("tail"); 215 216 object_property_add_str(obj, "netdev", 217 netfilter_get_netdev_id, netfilter_set_netdev_id, 218 NULL); 219 object_property_add_enum(obj, "queue", "NetFilterDirection", 220 &NetFilterDirection_lookup, 221 netfilter_get_direction, netfilter_set_direction, 222 NULL); 223 object_property_add_str(obj, "status", 224 netfilter_get_status, netfilter_set_status, 225 NULL); 226 object_property_add_str(obj, "position", 227 netfilter_get_position, netfilter_set_position, 228 NULL); 229 object_property_add_str(obj, "insert", 230 netfilter_get_insert, netfilter_set_insert, 231 NULL); 232 } 233 234 static void netfilter_complete(UserCreatable *uc, Error **errp) 235 { 236 NetFilterState *nf = NETFILTER(uc); 237 NetFilterState *position = NULL; 238 NetClientState *ncs[MAX_QUEUE_NUM]; 239 NetFilterClass *nfc = NETFILTER_GET_CLASS(uc); 240 int queues; 241 Error *local_err = NULL; 242 243 if (!nf->netdev_id) { 244 error_setg(errp, "Parameter 'netdev' is required"); 245 return; 246 } 247 248 queues = qemu_find_net_clients_except(nf->netdev_id, ncs, 249 NET_CLIENT_DRIVER_NIC, 250 MAX_QUEUE_NUM); 251 if (queues < 1) { 252 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "netdev", 253 "a network backend id"); 254 return; 255 } else if (queues > 1) { 256 error_setg(errp, "multiqueue is not supported"); 257 return; 258 } 259 260 if (get_vhost_net(ncs[0])) { 261 error_setg(errp, "Vhost is not supported"); 262 return; 263 } 264 265 if (strcmp(nf->position, "head") && strcmp(nf->position, "tail")) { 266 Object *container; 267 Object *obj; 268 char *position_id; 269 270 if (!g_str_has_prefix(nf->position, "id=")) { 271 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "position", 272 "'head', 'tail' or 'id=<id>'"); 273 return; 274 } 275 276 /* get the id from the string */ 277 position_id = g_strndup(nf->position + 3, strlen(nf->position) - 3); 278 279 /* Search for the position to insert before/behind */ 280 container = object_get_objects_root(); 281 obj = object_resolve_path_component(container, position_id); 282 if (!obj) { 283 error_setg(errp, "filter '%s' not found", position_id); 284 g_free(position_id); 285 return; 286 } 287 288 position = NETFILTER(obj); 289 290 if (position->netdev != ncs[0]) { 291 error_setg(errp, "filter '%s' belongs to a different netdev", 292 position_id); 293 g_free(position_id); 294 return; 295 } 296 297 g_free(position_id); 298 } 299 300 nf->netdev = ncs[0]; 301 302 if (nfc->setup) { 303 nfc->setup(nf, &local_err); 304 if (local_err) { 305 error_propagate(errp, local_err); 306 return; 307 } 308 } 309 310 if (position) { 311 if (nf->insert_before_flag) { 312 QTAILQ_INSERT_BEFORE(position, nf, next); 313 } else { 314 QTAILQ_INSERT_AFTER(&nf->netdev->filters, position, nf, next); 315 } 316 } else if (!strcmp(nf->position, "head")) { 317 QTAILQ_INSERT_HEAD(&nf->netdev->filters, nf, next); 318 } else if (!strcmp(nf->position, "tail")) { 319 QTAILQ_INSERT_TAIL(&nf->netdev->filters, nf, next); 320 } 321 } 322 323 static void netfilter_finalize(Object *obj) 324 { 325 NetFilterState *nf = NETFILTER(obj); 326 NetFilterClass *nfc = NETFILTER_GET_CLASS(obj); 327 328 if (nfc->cleanup) { 329 nfc->cleanup(nf); 330 } 331 332 if (nf->netdev && !QTAILQ_EMPTY(&nf->netdev->filters) && 333 QTAILQ_IN_USE(nf, next)) { 334 QTAILQ_REMOVE(&nf->netdev->filters, nf, next); 335 } 336 g_free(nf->netdev_id); 337 g_free(nf->position); 338 } 339 340 static void default_handle_event(NetFilterState *nf, int event, Error **errp) 341 { 342 switch (event) { 343 case COLO_EVENT_CHECKPOINT: 344 break; 345 case COLO_EVENT_FAILOVER: 346 object_property_set_str(OBJECT(nf), "off", "status", errp); 347 break; 348 default: 349 break; 350 } 351 } 352 353 static void netfilter_class_init(ObjectClass *oc, void *data) 354 { 355 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); 356 NetFilterClass *nfc = NETFILTER_CLASS(oc); 357 358 ucc->complete = netfilter_complete; 359 nfc->handle_event = default_handle_event; 360 } 361 362 static const TypeInfo netfilter_info = { 363 .name = TYPE_NETFILTER, 364 .parent = TYPE_OBJECT, 365 .abstract = true, 366 .class_size = sizeof(NetFilterClass), 367 .class_init = netfilter_class_init, 368 .instance_size = sizeof(NetFilterState), 369 .instance_init = netfilter_init, 370 .instance_finalize = netfilter_finalize, 371 .interfaces = (InterfaceInfo[]) { 372 { TYPE_USER_CREATABLE }, 373 { } 374 } 375 }; 376 377 static void register_types(void) 378 { 379 type_register_static(&netfilter_info); 380 } 381 382 type_init(register_types); 383