#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 = QTAILQ_NEXT(nf, next);
} else {
/* reverse order */
- next = QTAILQ_PREV(nf, NetFilterHead, next);
+ next = QTAILQ_PREV(nf, next);
}
return next;
}
}
+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;
+ nf->insert_before_flag = false;
+ nf->position = g_strdup("tail");
object_property_add_str(obj, "netdev",
- netfilter_get_netdev_id, netfilter_set_netdev_id,
- NULL);
+ netfilter_get_netdev_id, netfilter_set_netdev_id);
object_property_add_enum(obj, "queue", "NetFilterDirection",
&NetFilterDirection_lookup,
- netfilter_get_direction, netfilter_set_direction,
- NULL);
+ netfilter_get_direction, netfilter_set_direction);
object_property_add_str(obj, "status",
- netfilter_get_status, netfilter_set_status,
- NULL);
+ netfilter_get_status, netfilter_set_status);
+ object_property_add_str(obj, "position",
+ netfilter_get_position, netfilter_set_position);
+ object_property_add_str(obj, "insert",
+ netfilter_get_insert, netfilter_set_insert);
}
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;