diff mbox series

[v5,3/4] net/filter.c: Add Options to insert filters anywhere in the filter list

Message ID b4241e918682c83163857da3aaab5c14ec1c81f8.1568574478.git.lukasstraub2@web.de
State New
Headers show
Series colo: Add support for continuous replication | expand

Commit Message

Lukas Straub Sept. 15, 2019, 7:20 p.m. UTC
To switch the Secondary to Primary, we need to insert new filters
before the filter-rewriter.

Add the options insert= and position= to be able to insert filters
anywhere in the filter list.

position should be "head" or "tail" to insert at the head or
tail of the filter list or it should be "id=<id>" to specify
the id of another filter.
insert should be either "before" or "behind" to specify where to
insert the new filter relative to the one specified with position.

Signed-off-by: Lukas Straub <lukasstraub2@web.de>
---
 include/net/filter.h |  2 +
 net/filter.c         | 92 +++++++++++++++++++++++++++++++++++++++++++-
 qemu-options.hx      | 10 ++---
 3 files changed, 98 insertions(+), 6 deletions(-)

--
2.20.1

Comments

Zhang, Chen Sept. 26, 2019, 5:02 p.m. UTC | #1
> -----Original Message-----
> From: Lukas Straub <lukasstraub2@web.de>
> Sent: Monday, September 16, 2019 3:20 AM
> To: qemu-devel <qemu-devel@nongnu.org>
> Cc: Zhang, Chen <chen.zhang@intel.com>; Jason Wang
> <jasowang@redhat.com>; Wen Congyang <wencongyang2@huawei.com>;
> Xie Changlong <xiechanglong.d@gmail.com>; kwolf@redhat.com;
> mreitz@redhat.com
> Subject: [PATCH v5 3/4] net/filter.c: Add Options to insert filters anywhere in
> the filter list
> 
> To switch the Secondary to Primary, we need to insert new filters before the
> filter-rewriter.
> 
> Add the options insert= and position= to be able to insert filters anywhere in
> the filter list.
> 
> position should be "head" or "tail" to insert at the head or tail of the filter list
> or it should be "id=<id>" to specify the id of another filter.
> insert should be either "before" or "behind" to specify where to insert the
> new filter relative to the one specified with position.
> 
> Signed-off-by: Lukas Straub <lukasstraub2@web.de>
> ---
>  include/net/filter.h |  2 +
>  net/filter.c         | 92
> +++++++++++++++++++++++++++++++++++++++++++-
>  qemu-options.hx      | 10 ++---
>  3 files changed, 98 insertions(+), 6 deletions(-)
> 
> diff --git a/include/net/filter.h b/include/net/filter.h index
> 49da666ac0..22a723305b 100644
> --- a/include/net/filter.h
> +++ b/include/net/filter.h
> @@ -62,6 +62,8 @@ struct NetFilterState {
>      NetClientState *netdev;
>      NetFilterDirection direction;
>      bool on;
> +    char *position;
> +    bool insert_before_flag;
>      QTAILQ_ENTRY(NetFilterState) next;
>  };
> 
> diff --git a/net/filter.c b/net/filter.c index 28d1930db7..cd2ef9e979 100644
> --- a/net/filter.c
> +++ b/net/filter.c
> @@ -171,11 +171,47 @@ static void netfilter_set_status(Object *obj, const
> char *str, Error **errp)
>      }
>  }
> 
> +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, @@ -
> 187,11 +223,18 @@ static void netfilter_init(Object *obj)
>      object_property_add_str(obj, "status",
>                              netfilter_get_status, netfilter_set_status,
>                              NULL);
> +    object_property_add_str(obj, "position",
> +                            netfilter_get_position, netfilter_set_position,
> +                            NULL);
> +    object_property_add_str(obj, "insert",
> +                            netfilter_get_insert, netfilter_set_insert,
> +                            NULL);
>  }
> 
>  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;
> @@ -219,6 +262,41 @@ static void netfilter_complete(UserCreatable *uc,
> Error **errp)
>          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) {
> @@ -228,7 +306,18 @@ static void netfilter_complete(UserCreatable *uc,
> Error **errp)
>              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) @@ -245,6 +334,7 @@ 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)
> diff --git a/qemu-options.hx b/qemu-options.hx index
> 08749a3391..23fa5a344e 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -4368,7 +4368,7 @@ applications, they can do this through this
> parameter. Its format is  a gnutls priority string as described at
> @url{https://gnutls.org/manual/html_node/Priority-Strings.html}.
> 
> -@item -object filter-
> buffer,id=@var{id},netdev=@var{netdevid},interval=@var{t}[,queue=@var{
> all|rx|tx}][,status=@var{on|off}]
> +@item -object
> +filter-buffer,id=@var{id},netdev=@var{netdevid},interval=@var{t}[,queue
> +=@var{all|rx|tx}][,status=@var{on|off}][,position=@var{head|tail|id=<id
> +>}][,insert=@var{behind|before}]
> 
>  Interval @var{t} can't be 0, this filter batches the packet delivery: all  packets
> arriving in a given interval on netdev @var{netdevid} are delayed @@ -
> 4387,11 +4387,11 @@ queue @var{all|rx|tx} is an option that can be applied
> to any netfilter.
>  @option{tx}: the filter is attached to the transmit queue of the netdev,
>               where it will receive packets sent by the netdev.
> 
> -@item -object filter-
> mirror,id=@var{id},netdev=@var{netdevid},outdev=@var{chardevid},queue
> =@var{all|rx|tx}[,vnet_hdr_support]
> +@item -object
> +filter-mirror,id=@var{id},netdev=@var{netdevid},outdev=@var{chardevid},
> +queue=@var{all|rx|tx}[,vnet_hdr_support][,position=@var{head|tail|id=<
> i
> +d>}][,insert=@var{behind|before}]
> 
>  filter-mirror on netdev @var{netdevid},mirror net packet to
> chardev@var{chardevid}, if it has the vnet_hdr_support flag, filter-mirror will
> mirror packet with vnet_hdr_len.
> 

Please add description for the newly added parameter in each filter.
After that:
Reviewed-by: Zhang Chen <chen.zhang@intel.com>

Thanks
Zhang Chen


> -@item -object filter-
> redirector,id=@var{id},netdev=@var{netdevid},indev=@var{chardevid},out
> dev=@var{chardevid},queue=@var{all|rx|tx}[,vnet_hdr_support]
> +@item -object
> +filter-redirector,id=@var{id},netdev=@var{netdevid},indev=@var{chardevi
> +d},outdev=@var{chardevid},queue=@var{all|rx|tx}[,vnet_hdr_support][,p
> os
> +ition=@var{head|tail|id=<id>}][,insert=@var{behind|before}]
> 
>  filter-redirector on netdev @var{netdevid},redirect filter's net packet to
> chardev  @var{chardevid},and redirect indev's packet to filter.if it has the
> vnet_hdr_support flag, @@ -4400,7 +4400,7 @@ Create a filter-redirector
> we need to differ outdev id from indev id, id can not  be the same. we can
> just use indev or outdev, but at least one of indev or outdev  need to be
> specified.
> 
> -@item -object filter-
> rewriter,id=@var{id},netdev=@var{netdevid},queue=@var{all|rx|tx},[vnet_
> hdr_support]
> +@item -object
> +filter-rewriter,id=@var{id},netdev=@var{netdevid},queue=@var{all|rx|tx}
> +,[vnet_hdr_support][,position=@var{head|tail|id=<id>}][,insert=@var{beh
> +ind|before}]
> 
>  Filter-rewriter is a part of COLO project.It will rewrite tcp packet to
> secondary from primary to keep secondary tcp connection,and rewrite @@ -
> 4413,7 +4413,7 @@ colo secondary:
>  -object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1
>  -object filter-rewriter,id=rew0,netdev=hn0,queue=all
> 
> -@item -object filter-
> dump,id=@var{id},netdev=@var{dev}[,file=@var{filename}][,maxlen=@var{
> len}]
> +@item -object
> +filter-
> dump,id=@var{id},netdev=@var{dev}[,file=@var{filename}][,maxlen=
> +@var{len}][,position=@var{head|tail|id=<id>}][,insert=@var{behind|befor
> +e}]
> 
>  Dump the network traffic on netdev @var{dev} to the file specified by
> @var{filename}. At most @var{len} bytes (64k by default) per packet are
> stored.
> --
> 2.20.1
Lukas Straub Sept. 28, 2019, 10:44 a.m. UTC | #2
On Thu, 26 Sep 2019 17:02:58 +0000
"Zhang, Chen" <chen.zhang@intel.com> wrote:
> > diff --git a/qemu-options.hx b/qemu-options.hx index
> > 08749a3391..23fa5a344e 100644
> > --- a/qemu-options.hx
> > +++ b/qemu-options.hx
> > @@ -4368,7 +4368,7 @@ applications, they can do this through this
> > parameter. Its format is  a gnutls priority string as described at
> > @url{https://gnutls.org/manual/html_node/Priority-Strings.html}.
> >
> > -@item -object filter-
> > buffer,id=@var{id},netdev=@var{netdevid},interval=@var{t}[,queue=@var{
> > all|rx|tx}][,status=@var{on|off}]
> > +@item -object
> > +filter-buffer,id=@var{id},netdev=@var{netdevid},interval=@var{t}[,queue
> > +=@var{all|rx|tx}][,status=@var{on|off}][,position=@var{head|tail|id=<id
> > +>}][,insert=@var{behind|before}]
> >
> >  Interval @var{t} can't be 0, this filter batches the packet delivery: all  packets
> > arriving in a given interval on netdev @var{netdevid} are delayed @@ -
> > 4387,11 +4387,11 @@ queue @var{all|rx|tx} is an option that can be applied
> > to any netfilter.
> >  @option{tx}: the filter is attached to the transmit queue of the netdev,
> >               where it will receive packets sent by the netdev.
> >
> > -@item -object filter-
> > mirror,id=@var{id},netdev=@var{netdevid},outdev=@var{chardevid},queue
> > =@var{all|rx|tx}[,vnet_hdr_support]
> > +@item -object
> > +filter-mirror,id=@var{id},netdev=@var{netdevid},outdev=@var{chardevid},
> > +queue=@var{all|rx|tx}[,vnet_hdr_support][,position=@var{head|tail|id=<
> > i
> > +d>}][,insert=@var{behind|before}]
> >
> >  filter-mirror on netdev @var{netdevid},mirror net packet to
> > chardev@var{chardevid}, if it has the vnet_hdr_support flag, filter-mirror will
> > mirror packet with vnet_hdr_len.
> >
>
> Please add description for the newly added parameter in each filter.
> After that:
> Reviewed-by: Zhang Chen <chen.zhang@intel.com>
>
> Thanks
> Zhang Chen

Hi,
I will add a single description like its currently done with the "queue" option, noting that
it applies to any netfilter. Is that Ok?

Regards,
Lukas Straub

>
> > -@item -object filter-
> > redirector,id=@var{id},netdev=@var{netdevid},indev=@var{chardevid},out
> > dev=@var{chardevid},queue=@var{all|rx|tx}[,vnet_hdr_support]
> > +@item -object
> > +filter-redirector,id=@var{id},netdev=@var{netdevid},indev=@var{chardevi
> > +d},outdev=@var{chardevid},queue=@var{all|rx|tx}[,vnet_hdr_support][,p
> > os
> > +ition=@var{head|tail|id=<id>}][,insert=@var{behind|before}]
> >
> >  filter-redirector on netdev @var{netdevid},redirect filter's net packet to
> > chardev  @var{chardevid},and redirect indev's packet to filter.if it has the
> > vnet_hdr_support flag, @@ -4400,7 +4400,7 @@ Create a filter-redirector
> > we need to differ outdev id from indev id, id can not  be the same. we can
> > just use indev or outdev, but at least one of indev or outdev  need to be
> > specified.
> >
> > -@item -object filter-
> > rewriter,id=@var{id},netdev=@var{netdevid},queue=@var{all|rx|tx},[vnet_
> > hdr_support]
> > +@item -object
> > +filter-rewriter,id=@var{id},netdev=@var{netdevid},queue=@var{all|rx|tx}
> > +,[vnet_hdr_support][,position=@var{head|tail|id=<id>}][,insert=@var{beh
> > +ind|before}]
> >
> >  Filter-rewriter is a part of COLO project.It will rewrite tcp packet to
> > secondary from primary to keep secondary tcp connection,and rewrite @@ -
> > 4413,7 +4413,7 @@ colo secondary:
> >  -object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1
> >  -object filter-rewriter,id=rew0,netdev=hn0,queue=all
> >
> > -@item -object filter-
> > dump,id=@var{id},netdev=@var{dev}[,file=@var{filename}][,maxlen=@var{
> > len}]
> > +@item -object
> > +filter-
> > dump,id=@var{id},netdev=@var{dev}[,file=@var{filename}][,maxlen=
> > +@var{len}][,position=@var{head|tail|id=<id>}][,insert=@var{behind|befor
> > +e}]
> >
> >  Dump the network traffic on netdev @var{dev} to the file specified by
> > @var{filename}. At most @var{len} bytes (64k by default) per packet are
> > stored.
> > --
> > 2.20.1
>
Zhang, Chen Sept. 30, 2019, 8:13 p.m. UTC | #3
> -----Original Message-----
> From: Lukas Straub <lukasstraub2@web.de>
> Sent: Saturday, September 28, 2019 6:45 PM
> To: Zhang, Chen <chen.zhang@intel.com>
> Cc: qemu-devel <qemu-devel@nongnu.org>; Jason Wang
> <jasowang@redhat.com>; Wen Congyang <wencongyang2@huawei.com>;
> Xie Changlong <xiechanglong.d@gmail.com>; kwolf@redhat.com;
> mreitz@redhat.com
> Subject: Re: [PATCH v5 3/4] net/filter.c: Add Options to insert filters
> anywhere in the filter list
> 
> On Thu, 26 Sep 2019 17:02:58 +0000
> "Zhang, Chen" <chen.zhang@intel.com> wrote:
> > > diff --git a/qemu-options.hx b/qemu-options.hx index
> > > 08749a3391..23fa5a344e 100644
> > > --- a/qemu-options.hx
> > > +++ b/qemu-options.hx
> > > @@ -4368,7 +4368,7 @@ applications, they can do this through this
> > > parameter. Its format is  a gnutls priority string as described at
> > > @url{https://gnutls.org/manual/html_node/Priority-Strings.html}.
> > >
> > > -@item -object filter-
> > >
> buffer,id=@var{id},netdev=@var{netdevid},interval=@var{t}[,queue=@va
> > > r{
> > > all|rx|tx}][,status=@var{on|off}]
> > > +@item -object
> > > +filter-buffer,id=@var{id},netdev=@var{netdevid},interval=@var{t}[,q
> > > +ueue
> > > +=@var{all|rx|tx}][,status=@var{on|off}][,position=@var{head|tail|id
> > > +=<id
> > > +>}][,insert=@var{behind|before}]
> > >
> > >  Interval @var{t} can't be 0, this filter batches the packet
> > > delivery: all  packets arriving in a given interval on netdev
> > > @var{netdevid} are delayed @@ -
> > > 4387,11 +4387,11 @@ queue @var{all|rx|tx} is an option that can be
> > > applied to any netfilter.
> > >  @option{tx}: the filter is attached to the transmit queue of the netdev,
> > >               where it will receive packets sent by the netdev.
> > >
> > > -@item -object filter-
> > >
> mirror,id=@var{id},netdev=@var{netdevid},outdev=@var{chardevid},queu
> > > e
> > > =@var{all|rx|tx}[,vnet_hdr_support]
> > > +@item -object
> > > +filter-
> mirror,id=@var{id},netdev=@var{netdevid},outdev=@var{chardev
> > > +id},
> > > +queue=@var{all|rx|tx}[,vnet_hdr_support][,position=@var{head|tail|i
> > > +d=<
> > > i
> > > +d>}][,insert=@var{behind|before}]
> > >
> > >  filter-mirror on netdev @var{netdevid},mirror net packet to
> > > chardev@var{chardevid}, if it has the vnet_hdr_support flag,
> > > filter-mirror will mirror packet with vnet_hdr_len.
> > >
> >
> > Please add description for the newly added parameter in each filter.
> > After that:
> > Reviewed-by: Zhang Chen <chen.zhang@intel.com>
> >
> > Thanks
> > Zhang Chen
> 
> Hi,
> I will add a single description like its currently done with the "queue" option,
> noting that it applies to any netfilter. Is that Ok?

It is enough for me.

Thanks
Zhang Chen

> 
> Regards,
> Lukas Straub
> 
> >
> > > -@item -object filter-
> > >
> redirector,id=@var{id},netdev=@var{netdevid},indev=@var{chardevid},o
> > > ut dev=@var{chardevid},queue=@var{all|rx|tx}[,vnet_hdr_support]
> > > +@item -object
> > > +filter-redirector,id=@var{id},netdev=@var{netdevid},indev=@var{char
> > > +devi
> > >
> +d},outdev=@var{chardevid},queue=@var{all|rx|tx}[,vnet_hdr_support][
> > > +,p
> > > os
> > > +ition=@var{head|tail|id=<id>}][,insert=@var{behind|before}]
> > >
> > >  filter-redirector on netdev @var{netdevid},redirect filter's net
> > > packet to chardev  @var{chardevid},and redirect indev's packet to
> > > filter.if it has the vnet_hdr_support flag, @@ -4400,7 +4400,7 @@
> > > Create a filter-redirector we need to differ outdev id from indev
> > > id, id can not  be the same. we can just use indev or outdev, but at
> > > least one of indev or outdev  need to be specified.
> > >
> > > -@item -object filter-
> > > rewriter,id=@var{id},netdev=@var{netdevid},queue=@var{all|rx|tx},[vn
> > > et_
> > > hdr_support]
> > > +@item -object
> > > +filter-rewriter,id=@var{id},netdev=@var{netdevid},queue=@var{all|rx
> > > +|tx}
> > > +,[vnet_hdr_support][,position=@var{head|tail|id=<id>}][,insert=@var
> > > +{beh
> > > +ind|before}]
> > >
> > >  Filter-rewriter is a part of COLO project.It will rewrite tcp
> > > packet to secondary from primary to keep secondary tcp
> > > connection,and rewrite @@ -
> > > 4413,7 +4413,7 @@ colo secondary:
> > >  -object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1
> > >  -object filter-rewriter,id=rew0,netdev=hn0,queue=all
> > >
> > > -@item -object filter-
> > >
> dump,id=@var{id},netdev=@var{dev}[,file=@var{filename}][,maxlen=@var
> > > {
> > > len}]
> > > +@item -object
> > > +filter-
> > > dump,id=@var{id},netdev=@var{dev}[,file=@var{filename}][,maxlen=
> > > +@var{len}][,position=@var{head|tail|id=<id>}][,insert=@var{behind|b
> > > +efor
> > > +e}]
> > >
> > >  Dump the network traffic on netdev @var{dev} to the file specified
> > > by @var{filename}. At most @var{len} bytes (64k by default) per
> > > packet are stored.
> > > --
> > > 2.20.1
> >
diff mbox series

Patch

diff --git a/include/net/filter.h b/include/net/filter.h
index 49da666ac0..22a723305b 100644
--- a/include/net/filter.h
+++ b/include/net/filter.h
@@ -62,6 +62,8 @@  struct NetFilterState {
     NetClientState *netdev;
     NetFilterDirection direction;
     bool on;
+    char *position;
+    bool insert_before_flag;
     QTAILQ_ENTRY(NetFilterState) next;
 };

diff --git a/net/filter.c b/net/filter.c
index 28d1930db7..cd2ef9e979 100644
--- a/net/filter.c
+++ b/net/filter.c
@@ -171,11 +171,47 @@  static void netfilter_set_status(Object *obj, const char *str, Error **errp)
     }
 }

+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,
@@ -187,11 +223,18 @@  static void netfilter_init(Object *obj)
     object_property_add_str(obj, "status",
                             netfilter_get_status, netfilter_set_status,
                             NULL);
+    object_property_add_str(obj, "position",
+                            netfilter_get_position, netfilter_set_position,
+                            NULL);
+    object_property_add_str(obj, "insert",
+                            netfilter_get_insert, netfilter_set_insert,
+                            NULL);
 }

 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;
@@ -219,6 +262,41 @@  static void netfilter_complete(UserCreatable *uc, Error **errp)
         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) {
@@ -228,7 +306,18 @@  static void netfilter_complete(UserCreatable *uc, Error **errp)
             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)
@@ -245,6 +334,7 @@  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)
diff --git a/qemu-options.hx b/qemu-options.hx
index 08749a3391..23fa5a344e 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -4368,7 +4368,7 @@  applications, they can do this through this parameter. Its format is
 a gnutls priority string as described at
 @url{https://gnutls.org/manual/html_node/Priority-Strings.html}.

-@item -object filter-buffer,id=@var{id},netdev=@var{netdevid},interval=@var{t}[,queue=@var{all|rx|tx}][,status=@var{on|off}]
+@item -object filter-buffer,id=@var{id},netdev=@var{netdevid},interval=@var{t}[,queue=@var{all|rx|tx}][,status=@var{on|off}][,position=@var{head|tail|id=<id>}][,insert=@var{behind|before}]

 Interval @var{t} can't be 0, this filter batches the packet delivery: all
 packets arriving in a given interval on netdev @var{netdevid} are delayed
@@ -4387,11 +4387,11 @@  queue @var{all|rx|tx} is an option that can be applied to any netfilter.
 @option{tx}: the filter is attached to the transmit queue of the netdev,
              where it will receive packets sent by the netdev.

-@item -object filter-mirror,id=@var{id},netdev=@var{netdevid},outdev=@var{chardevid},queue=@var{all|rx|tx}[,vnet_hdr_support]
+@item -object filter-mirror,id=@var{id},netdev=@var{netdevid},outdev=@var{chardevid},queue=@var{all|rx|tx}[,vnet_hdr_support][,position=@var{head|tail|id=<id>}][,insert=@var{behind|before}]

 filter-mirror on netdev @var{netdevid},mirror net packet to chardev@var{chardevid}, if it has the vnet_hdr_support flag, filter-mirror will mirror packet with vnet_hdr_len.

-@item -object filter-redirector,id=@var{id},netdev=@var{netdevid},indev=@var{chardevid},outdev=@var{chardevid},queue=@var{all|rx|tx}[,vnet_hdr_support]
+@item -object filter-redirector,id=@var{id},netdev=@var{netdevid},indev=@var{chardevid},outdev=@var{chardevid},queue=@var{all|rx|tx}[,vnet_hdr_support][,position=@var{head|tail|id=<id>}][,insert=@var{behind|before}]

 filter-redirector on netdev @var{netdevid},redirect filter's net packet to chardev
 @var{chardevid},and redirect indev's packet to filter.if it has the vnet_hdr_support flag,
@@ -4400,7 +4400,7 @@  Create a filter-redirector we need to differ outdev id from indev id, id can not
 be the same. we can just use indev or outdev, but at least one of indev or outdev
 need to be specified.

-@item -object filter-rewriter,id=@var{id},netdev=@var{netdevid},queue=@var{all|rx|tx},[vnet_hdr_support]
+@item -object filter-rewriter,id=@var{id},netdev=@var{netdevid},queue=@var{all|rx|tx},[vnet_hdr_support][,position=@var{head|tail|id=<id>}][,insert=@var{behind|before}]

 Filter-rewriter is a part of COLO project.It will rewrite tcp packet to
 secondary from primary to keep secondary tcp connection,and rewrite
@@ -4413,7 +4413,7 @@  colo secondary:
 -object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1
 -object filter-rewriter,id=rew0,netdev=hn0,queue=all

-@item -object filter-dump,id=@var{id},netdev=@var{dev}[,file=@var{filename}][,maxlen=@var{len}]
+@item -object filter-dump,id=@var{id},netdev=@var{dev}[,file=@var{filename}][,maxlen=@var{len}][,position=@var{head|tail|id=<id>}][,insert=@var{behind|before}]

 Dump the network traffic on netdev @var{dev} to the file specified by
 @var{filename}. At most @var{len} bytes (64k by default) per packet are stored.