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