#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qemu-common.h"
#include "qapi/qmp/qerror.h"
#include "qemu/error-report.h"
#include "net/vhost_net.h"
#include "qom/object_interfaces.h"
#include "qemu/iov.h"
+#include "qemu/module.h"
#include "net/colo.h"
#include "migration/colo.h"
next = netfilter_next(nf, direction);
while (next) {
/*
- * if qemu_netfilter_pass_to_next been called, means that
- * the packet has been hold by filter and has already retured size
+ * if qemu_netfilter_pass_to_next has been called, it means that
+ * the packet was held by a filter and has already returned size
* to the sender, so sent_cb shouldn't be called later, just
* pass NULL to next.
*/
/*
* We have gone through all filters, pass it to receiver.
- * Do the valid check again incase sender or receiver been
+ * Do the valid check again in case sender or receiver been
* deleted while we go through filters.
*/
if (sender && sender->peer) {
}
}
+static char *netfilter_get_position(Object *obj, Error **errp)
+{
+ NetFilterState *nf = NETFILTER(obj);
+
+ return g_strdup(nf->position);
+}
+
+static void netfilter_set_position(Object *obj, const char *str, Error **errp)
+{
+ NetFilterState *nf = NETFILTER(obj);
+
+ nf->position = g_strdup(str);
+}
+
+static char *netfilter_get_insert(Object *obj, Error **errp)
+{
+ NetFilterState *nf = NETFILTER(obj);
+
+ return nf->insert_before_flag ? g_strdup("before") : g_strdup("behind");
+}
+
+static void netfilter_set_insert(Object *obj, const char *str, Error **errp)
+{
+ NetFilterState *nf = NETFILTER(obj);
+
+ if (strcmp(str, "before") && strcmp(str, "behind")) {
+ error_setg(errp, "Invalid value for netfilter insert, "
+ "should be 'before' or 'behind'");
+ return;
+ }
+
+ nf->insert_before_flag = !strcmp(str, "before");
+}
+
static void netfilter_init(Object *obj)
{
NetFilterState *nf = NETFILTER(obj);
nf->on = true;
-
- object_property_add_str(obj, "netdev",
- netfilter_get_netdev_id, netfilter_set_netdev_id,
- NULL);
- object_property_add_enum(obj, "queue", "NetFilterDirection",
- &NetFilterDirection_lookup,
- netfilter_get_direction, netfilter_set_direction,
- NULL);
- object_property_add_str(obj, "status",
- netfilter_get_status, netfilter_set_status,
- NULL);
+ nf->insert_before_flag = false;
+ nf->position = g_strdup("tail");
}
static void netfilter_complete(UserCreatable *uc, Error **errp)
{
NetFilterState *nf = NETFILTER(uc);
+ NetFilterState *position = NULL;
NetClientState *ncs[MAX_QUEUE_NUM];
NetFilterClass *nfc = NETFILTER_GET_CLASS(uc);
int queues;
return;
}
+ if (strcmp(nf->position, "head") && strcmp(nf->position, "tail")) {
+ Object *container;
+ Object *obj;
+ char *position_id;
+
+ if (!g_str_has_prefix(nf->position, "id=")) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "position",
+ "'head', 'tail' or 'id=<id>'");
+ return;
+ }
+
+ /* get the id from the string */
+ position_id = g_strndup(nf->position + 3, strlen(nf->position) - 3);
+
+ /* Search for the position to insert before/behind */
+ container = object_get_objects_root();
+ obj = object_resolve_path_component(container, position_id);
+ if (!obj) {
+ error_setg(errp, "filter '%s' not found", position_id);
+ g_free(position_id);
+ return;
+ }
+
+ position = NETFILTER(obj);
+
+ if (position->netdev != ncs[0]) {
+ error_setg(errp, "filter '%s' belongs to a different netdev",
+ position_id);
+ g_free(position_id);
+ return;
+ }
+
+ g_free(position_id);
+ }
+
nf->netdev = ncs[0];
if (nfc->setup) {
return;
}
}
- QTAILQ_INSERT_TAIL(&nf->netdev->filters, nf, next);
+
+ if (position) {
+ if (nf->insert_before_flag) {
+ QTAILQ_INSERT_BEFORE(position, nf, next);
+ } else {
+ QTAILQ_INSERT_AFTER(&nf->netdev->filters, position, nf, next);
+ }
+ } else if (!strcmp(nf->position, "head")) {
+ QTAILQ_INSERT_HEAD(&nf->netdev->filters, nf, next);
+ } else if (!strcmp(nf->position, "tail")) {
+ QTAILQ_INSERT_TAIL(&nf->netdev->filters, nf, next);
+ }
}
static void netfilter_finalize(Object *obj)
QTAILQ_REMOVE(&nf->netdev->filters, nf, next);
}
g_free(nf->netdev_id);
+ g_free(nf->position);
}
static void default_handle_event(NetFilterState *nf, int event, Error **errp)
case COLO_EVENT_CHECKPOINT:
break;
case COLO_EVENT_FAILOVER:
- object_property_set_str(OBJECT(nf), "off", "status", errp);
+ object_property_set_str(OBJECT(nf), "status", "off", errp);
break;
default:
break;
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
NetFilterClass *nfc = NETFILTER_CLASS(oc);
+ object_class_property_add_str(oc, "netdev",
+ netfilter_get_netdev_id, netfilter_set_netdev_id);
+ object_class_property_add_enum(oc, "queue", "NetFilterDirection",
+ &NetFilterDirection_lookup,
+ netfilter_get_direction, netfilter_set_direction);
+ object_class_property_add_str(oc, "status",
+ netfilter_get_status, netfilter_set_status);
+ object_class_property_add_str(oc, "position",
+ netfilter_get_position, netfilter_set_position);
+ object_class_property_add_str(oc, "insert",
+ netfilter_get_insert, netfilter_set_insert);
+
ucc->complete = netfilter_complete;
nfc->handle_event = default_handle_event;
}