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 StringOutputVisitor *ov; 141 142 if (!nf->netdev_id) { 143 error_setg(errp, "Parameter 'netdev' is required"); 144 return; 145 } 146 147 queues = qemu_find_net_clients_except(nf->netdev_id, ncs, 148 NET_CLIENT_OPTIONS_KIND_NIC, 149 MAX_QUEUE_NUM); 150 if (queues < 1) { 151 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "netdev", 152 "a network backend id"); 153 return; 154 } else if (queues > 1) { 155 error_setg(errp, "multiqueue is not supported"); 156 return; 157 } 158 159 if (get_vhost_net(ncs[0])) { 160 error_setg(errp, "Vhost is not supported"); 161 return; 162 } 163 164 nf->netdev = ncs[0]; 165 166 if (nfc->setup) { 167 nfc->setup(nf, &local_err); 168 if (local_err) { 169 error_propagate(errp, local_err); 170 return; 171 } 172 } 173 QTAILQ_INSERT_TAIL(&nf->netdev->filters, nf, next); 174 175 /* generate info str */ 176 QTAILQ_FOREACH(prop, &OBJECT(nf)->properties, node) { 177 if (!strcmp(prop->name, "type")) { 178 continue; 179 } 180 ov = string_output_visitor_new(false); 181 object_property_get(OBJECT(nf), string_output_get_visitor(ov), 182 prop->name, errp); 183 str = string_output_get_string(ov); 184 string_output_visitor_cleanup(ov); 185 info = g_strdup_printf(",%s=%s", prop->name, str); 186 g_strlcat(nf->info_str, info, sizeof(nf->info_str)); 187 g_free(str); 188 g_free(info); 189 } 190 } 191 192 static void netfilter_finalize(Object *obj) 193 { 194 NetFilterState *nf = NETFILTER(obj); 195 NetFilterClass *nfc = NETFILTER_GET_CLASS(obj); 196 197 if (nfc->cleanup) { 198 nfc->cleanup(nf); 199 } 200 201 if (nf->netdev && !QTAILQ_EMPTY(&nf->netdev->filters)) { 202 QTAILQ_REMOVE(&nf->netdev->filters, nf, next); 203 } 204 } 205 206 static void netfilter_class_init(ObjectClass *oc, void *data) 207 { 208 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); 209 210 ucc->complete = netfilter_complete; 211 } 212 213 static const TypeInfo netfilter_info = { 214 .name = TYPE_NETFILTER, 215 .parent = TYPE_OBJECT, 216 .abstract = true, 217 .class_size = sizeof(NetFilterClass), 218 .class_init = netfilter_class_init, 219 .instance_size = sizeof(NetFilterState), 220 .instance_init = netfilter_init, 221 .instance_finalize = netfilter_finalize, 222 .interfaces = (InterfaceInfo[]) { 223 { TYPE_USER_CREATABLE }, 224 { } 225 } 226 }; 227 228 static void register_types(void) 229 { 230 type_register_static(&netfilter_info); 231 } 232 233 type_init(register_types); 234