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