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