diff mbox series

[ovs-dev] Improved Packet Drop Statistics in OVS.

Message ID 4B8854D1-170B-4D2C-99EA-E05472F1391F@ericsson.com
State Changes Requested
Delegated to: Ian Stokes
Headers show
Series [ovs-dev] Improved Packet Drop Statistics in OVS. | expand

Commit Message

Rohith Basavaraja May 23, 2018, 10:15 a.m. UTC
Currently OVS maintains explicit packet drop/error counters only on port
    level. Packets that are dropped as part of normal OpenFlow processing are
    counted in flow stats of “drop” flows or as table misses in table stats.
    These can only be interpreted by controllers that know the semantics of
    the configured OpenFlow pipeline. Without that knowledge, it is impossible
    for an OVS user to obtain e.g. the total number of packets dropped due to
    OpenFlow rules.

    Furthermore, there are numerous other reasons for which packets can be
    dropped by OVS slow path that are not related to the OpenFlow pipeline.
    The generated datapath flow entries include a drop action to avoid further
    expensive upcalls to the slow path, but subsequent packets dropped by the
    datapath are not accounted anywhere.

    Finally, the datapath itself drops packets in certain error situations.
    Also, these drops are today not accounted for.

    This makes it difficult for OVS users to monitor packet drop in an OVS
    instance and to alert a management system in case of a unexpected increase
    of such drops. Also OVS trouble-shooters face difficulties in analysing
    packet drops.

    With this patch we implement following changes to address the issues
    mentioned above.

    1. Account and categorize all the packet drops in OVS.
    2. Account & classify “drop” action packet drops according to the drop
       reason.
    3. Identify and account all the silent packet drop scenarios.
    4. Have new cli command to display consolidated packet drop output
    5. Modified ovs-appctl dpcls/dump-flows and ovs-appctl dpif/dump-flows
       to print drop reason along with drop action

    A detailed presentation on this was presented at OvS conference 2017 and
    link for the corresponding presentation is available at:
    https://www.slideshare.net/LF_OpenvSwitch/lfovs17troubleshooting-the-data-plane-in-ovs-82280329

    In the subsequent commits plan to add the corresponding tests.

    Sample ovs-appctl dpcls/dump-flows & ovs-appctl dpif/dump-flows
    displaying drop reason along with drop action.
    ---------------------------------------------------------------

    $ ovs-appctl dpctl/dump-flows netdev@ovs-netdev
    flow-dump from pmd on cpu core: 0
    recirc_id(0),in_port(5),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:12, bytes:1176, used:0.884s, actions:drop:recursion too deep

    $ ovs-appctl dpif/dump-flows br-int
    recirc_id(0),in_port(5),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:25, bytes:2450, used:5.008s, actions:drop:recursion too deep
    recirc_id(0),in_port(5),packet_type(ns=0,id=0),eth_type(0x0806), packets:7, bytes:294, used:0.009s, actions:drop:recursion too deep

    Sample drop stats summary output.
    ---------------------------------
    $ ovs-appctl dpif/show-drop-stats
    netdev:
    rx-drops                    :0
    dataplane-processing-drops  :59
         drop action            :59
         upcall drops           :0
         dp error drops         :0
    tx-drops                    :0

    Sample detailed drop stats output.
    ---------------------------------
    $ ovs-appctl dpif/show-drop-stats --detail
    netdev:
    rx-drops:
    [IDX]   Drop Reason                            Packets
    -------  ------------------------------------- ------------
    0       interface & policer                    0
    1       parsing error/invalid packet           0
    dataplane-processing-drops:
    "drop" action:
    2       pipeline drop                          0
    3       bridge not found                       0
    4       recursion too deep                     68
    5       too many resubmits                     0
    6       stack too deep                         0
    7       no recirculation context               0
    8       recirculation conflict                 0
    9       too many mpls labels                   0
    10      invalid tunnel metadata                0
    11      unsupported packet type                0
    12      ecn mismatch at tunnel decapsulation   0
    13      forwarding disabled (stp/rstp)         0
    upcall drops:
    14      upcall lock contention drop            0
    15      upcall error drops                     0
    dp drops:
    16      tunnel pop action errors               0
    17      tunnel push action errors              0
    18      nsh decap errors                       0
    19      recirculation errors                   0
    20      sampling error                         0
    21      meter drop                             0
    22      user space action error                0
    23      invalid port                           0
    24      invalid tunnel port                    0
    tx-drops:
    25      interface & policer                    0

    Drop stats clear command.
    ---------------------------------
    $ ovs-appctl dpif/clear-drop-stats
    $ ovs-appctl dpif/show-drop-stats
    netdev:
    rx-drops                    :0
    dataplane-processing-drops  :0
         drop action            :0
         upcall drops           :0
         dp error drops         :0
    tx-drops                    :0

Signed-off-by: Rohith Basavaraja <rohith.basavaraja@ericsson.com>
---
 datapath/linux/compat/include/linux/openvswitch.h |  51 ++++++
 lib/dpif-netdev-perf.c                            |  50 ++++++
 lib/dpif-netdev-perf.h                            |  52 ++++++
 lib/dpif-netdev.c                                 | 133 ++++++++++++++-
 lib/dpif-provider.h                               |   7 +
 lib/dpif.c                                        | 191 +++++++++++++++++++++-
 lib/dpif.h                                        |  64 +++++++-
 lib/odp-execute.c                                 |  50 +++++-
 lib/odp-execute.h                                 |   9 +-
 lib/odp-util.c                                    |  53 +++++-
 lib/ovs-atomic.h                                  |  20 +++
 ofproto/ofproto-dpif-ipfix.c                      |   1 +
 ofproto/ofproto-dpif-sflow.c                      |   1 +
 ofproto/ofproto-dpif-upcall.c                     |   4 +-
 ofproto/ofproto-dpif-xlate.c                      |  64 ++++++++
 ofproto/ofproto-dpif-xlate.h                      |   4 +
 ofproto/ofproto-dpif.c                            |  84 ++++++++++
 ofproto/ofproto-dpif.h                            |   8 +-
 tests/bundle.at                                   |   2 +-
 tests/classifier.at                               |  10 +-
 tests/ofproto-dpif.at                             | 172 +++++++++----------
 tests/ovs-ofctl.at                                |  22 +--
 tests/packet-type-aware.at                        |  10 +-
 tests/tunnel.at                                   |   7 +-
 24 files changed, 939 insertions(+), 130 deletions(-)

Comments

Ben Pfaff May 23, 2018, 8:33 p.m. UTC | #1
I see that this adds code to the OVS kernel module.  Are these changes
upstream already in Linux?  Usually we use an "upstream first"
philosophy regarding the kernel module.
Rohith Basavaraja May 24, 2018, 2:19 a.m. UTC | #2
Hi Ben,

Only  changes in 
datapath/linux/compat/include/linux/openvswitch.h
are related to OvS Kernel module.  

The changes in openvswitch.h are not upstreamed yet.
Can you please let me know the procedure for submitting the
Changes for OvS Kernel Module?.

In the meanwhile can I get code review feedback for the changes, while I 
Figure out how to commit changes in datapath/linux/compat/include/linux/openvswitch.h.

Thanks
Rohith 


On 24/05/18, 2:03 AM, "Ben Pfaff" <blp@ovn.org> wrote:

    I see that this adds code to the OVS kernel module.  Are these changes
    upstream already in Linux?  Usually we use an "upstream first"
    philosophy regarding the kernel module.
Gregory Rose May 24, 2018, 3:35 p.m. UTC | #3
On 5/23/2018 7:19 PM, Rohith Basavaraja wrote:
> Hi Ben,
>
> Only  changes in
> datapath/linux/compat/include/linux/openvswitch.h
> are related to OvS Kernel module.
>
> The changes in openvswitch.h are not upstreamed yet.
> Can you please let me know the procedure for submitting the
> Changes for OvS Kernel Module?.
>
> In the meanwhile can I get code review feedback for the changes, while I
> Figure out how to commit changes in datapath/linux/compat/include/linux/openvswitch.h.
>
> Thanks
> Rohith

You need to submit changes to openvswitch.h to the Linux network mail list.

https://www.kernel.org/doc/Documentation/networking/netdev-FAQ.txt

After acceptance upstream we can then pull in the change.

And this might help as well.

https://www.kernel.org/doc/html/v4.16/process/submitting-patches.html

Thanks,

- Greg

>
>
> On 24/05/18, 2:03 AM, "Ben Pfaff" <blp@ovn.org> wrote:
>
>      I see that this adds code to the OVS kernel module.  Are these changes
>      upstream already in Linux?  Usually we use an "upstream first"
>      philosophy regarding the kernel module.
>      
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
Ben Pfaff May 24, 2018, 9:22 p.m. UTC | #4
On Thu, May 24, 2018 at 02:19:06AM +0000, Rohith Basavaraja wrote:
> Only  changes in 
> datapath/linux/compat/include/linux/openvswitch.h
> are related to OvS Kernel module.  

On a second look, I see that the new stuff here is only for the DPDK
datapath.  If you don't intend to add this feature to the kernel
datapath, there should be no problem.  Never mind.
Rohith Basavaraja May 25, 2018, 5:37 a.m. UTC | #5
Thanks Ben for the clarification. Yes this new stuff is used only in the
DPDK datapath and it’s not used in the kernel datapath.

Thanks
Rohith

On 25/05/18, 2:52 AM, "Ben Pfaff" <blp@ovn.org> wrote:

    On Thu, May 24, 2018 at 02:19:06AM +0000, Rohith Basavaraja wrote:
    > Only  changes in 
    > datapath/linux/compat/include/linux/openvswitch.h
    > are related to OvS Kernel module.  
    
    On a second look, I see that the new stuff here is only for the DPDK
    datapath.  If you don't intend to add this feature to the kernel
    datapath, there should be no problem.  Never mind.
Rohith Basavaraja May 25, 2018, 5:44 a.m. UTC | #6
Hi Greg,

Thanks a lot for sharing the info.
Ben clarified that it should be ok if this new stuff is used only in the
DPDK datapath and it’s not used in the kernel datapath.

Thanks
Rohith



On 24/05/18, 9:05 PM, "Gregory Rose" <gvrose8192@gmail.com> wrote:

    On 5/23/2018 7:19 PM, Rohith Basavaraja wrote:
    > Hi Ben,
    >
    > Only  changes in
    > datapath/linux/compat/include/linux/openvswitch.h
    > are related to OvS Kernel module.
    >
    > The changes in openvswitch.h are not upstreamed yet.
    > Can you please let me know the procedure for submitting the
    > Changes for OvS Kernel Module?.
    >
    > In the meanwhile can I get code review feedback for the changes, while I
    > Figure out how to commit changes in datapath/linux/compat/include/linux/openvswitch.h.
    >
    > Thanks
    > Rohith
    
    You need to submit changes to openvswitch.h to the Linux network mail list.
    
    https://www.kernel.org/doc/Documentation/networking/netdev-FAQ.txt
    
    After acceptance upstream we can then pull in the change.
    
    And this might help as well.
    
    https://www.kernel.org/doc/html/v4.16/process/submitting-patches.html
    
    Thanks,
    
    - Greg
    
    >
    >
    > On 24/05/18, 2:03 AM, "Ben Pfaff" <blp@ovn.org> wrote:
    >
    >      I see that this adds code to the OVS kernel module.  Are these changes
    >      upstream already in Linux?  Usually we use an "upstream first"
    >      philosophy regarding the kernel module.
    >      
    >
    > _______________________________________________
    > dev mailing list
    > dev@openvswitch.org
    > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
Federico Iezzi May 25, 2018, 7:34 a.m. UTC | #7
Hello everyone,

May I ask to provide some (even brief) documentation about each specific
drop counter?
That would really help understanding why a specific drop is happening.

Thanks,
Federico

On 25 May 2018 at 07:44, Rohith Basavaraja <rohith.basavaraja@ericsson.com>
wrote:

> Hi Greg,
>
> Thanks a lot for sharing the info.
> Ben clarified that it should be ok if this new stuff is used only in the
> DPDK datapath and it’s not used in the kernel datapath.
>
> Thanks
> Rohith
>
>
>
> On 24/05/18, 9:05 PM, "Gregory Rose" <gvrose8192@gmail.com> wrote:
>
>     On 5/23/2018 7:19 PM, Rohith Basavaraja wrote:
>     > Hi Ben,
>     >
>     > Only  changes in
>     > datapath/linux/compat/include/linux/openvswitch.h
>     > are related to OvS Kernel module.
>     >
>     > The changes in openvswitch.h are not upstreamed yet.
>     > Can you please let me know the procedure for submitting the
>     > Changes for OvS Kernel Module?.
>     >
>     > In the meanwhile can I get code review feedback for the changes,
> while I
>     > Figure out how to commit changes in datapath/linux/compat/include/
> linux/openvswitch.h.
>     >
>     > Thanks
>     > Rohith
>
>     You need to submit changes to openvswitch.h to the Linux network mail
> list.
>
>     https://www.kernel.org/doc/Documentation/networking/netdev-FAQ.txt
>
>     After acceptance upstream we can then pull in the change.
>
>     And this might help as well.
>
>     https://www.kernel.org/doc/html/v4.16/process/submitting-patches.html
>
>     Thanks,
>
>     - Greg
>
>     >
>     >
>     > On 24/05/18, 2:03 AM, "Ben Pfaff" <blp@ovn.org> wrote:
>     >
>     >      I see that this adds code to the OVS kernel module.  Are these
> changes
>     >      upstream already in Linux?  Usually we use an "upstream first"
>     >      philosophy regarding the kernel module.
>     >
>     >
>     > _______________________________________________
>     > dev mailing list
>     > dev@openvswitch.org
>     > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
Jan Scheurich June 6, 2018, 3:37 p.m. UTC | #8
The user-space part for packet drop stats should be generic and work with any dpif datapath. 
So, if someone implemented the equivalent drop stats functionality in the kernel datapath that would be very welcome.
We in Ericsson cannot do that currently due to license restrictions.

Regards, Jan

> -----Original Message-----
> From: ovs-dev-bounces@openvswitch.org <ovs-dev-bounces@openvswitch.org> On Behalf Of Rohith Basavaraja
> Sent: Friday, 25 May, 2018 07:37
> To: Ben Pfaff <blp@ovn.org>
> Cc: dev@openvswitch.org
> Subject: Re: [ovs-dev] [PATCH] Improved Packet Drop Statistics in OVS.
> 
> Thanks Ben for the clarification. Yes this new stuff is used only in the
> DPDK datapath and it’s not used in the kernel datapath.
> 
> Thanks
> Rohith
> 
> On 25/05/18, 2:52 AM, "Ben Pfaff" <blp@ovn.org> wrote:
> 
>     On Thu, May 24, 2018 at 02:19:06AM +0000, Rohith Basavaraja wrote:
>     > Only  changes in
>     > datapath/linux/compat/include/linux/openvswitch.h
>     > are related to OvS Kernel module.
> 
>     On a second look, I see that the new stuff here is only for the DPDK
>     datapath.  If you don't intend to add this feature to the kernel
>     datapath, there should be no problem.  Never mind.
> 
> 
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
Federico Iezzi June 8, 2018, 1:01 p.m. UTC | #9
I'm very sorry for double posting.
I believe this patch would represent a major feature in term of OVS's
usability.
Has anyone got any time for reviewing it?

Thanks,
Federico

On 6 June 2018 at 17:37, Jan Scheurich <jan.scheurich@ericsson.com> wrote:

> The user-space part for packet drop stats should be generic and work with
> any dpif datapath.
> So, if someone implemented the equivalent drop stats functionality in the
> kernel datapath that would be very welcome.
> We in Ericsson cannot do that currently due to license restrictions.
>
> Regards, Jan
>
> > -----Original Message-----
> > From: ovs-dev-bounces@openvswitch.org <ovs-dev-bounces@openvswitch.org>
> On Behalf Of Rohith Basavaraja
> > Sent: Friday, 25 May, 2018 07:37
> > To: Ben Pfaff <blp@ovn.org>
> > Cc: dev@openvswitch.org
> > Subject: Re: [ovs-dev] [PATCH] Improved Packet Drop Statistics in OVS.
> >
> > Thanks Ben for the clarification. Yes this new stuff is used only in the
> > DPDK datapath and it’s not used in the kernel datapath.
> >
> > Thanks
> > Rohith
> >
> > On 25/05/18, 2:52 AM, "Ben Pfaff" <blp@ovn.org> wrote:
> >
> >     On Thu, May 24, 2018 at 02:19:06AM +0000, Rohith Basavaraja wrote:
> >     > Only  changes in
> >     > datapath/linux/compat/include/linux/openvswitch.h
> >     > are related to OvS Kernel module.
> >
> >     On a second look, I see that the new stuff here is only for the DPDK
> >     datapath.  If you don't intend to add this feature to the kernel
> >     datapath, there should be no problem.  Never mind.
> >
> >
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
Stokes, Ian June 11, 2018, 8:33 a.m. UTC | #10
> I'm very sorry for double posting.
> I believe this patch would represent a major feature in term of OVS's
> usability.
> Has anyone got any time for reviewing it?
> 

I'm planning to look at it this week.

Thanks
Ian

> Thanks,
> Federico
> 
> On 6 June 2018 at 17:37, Jan Scheurich <jan.scheurich@ericsson.com> wrote:
> 
> > The user-space part for packet drop stats should be generic and work
> > with any dpif datapath.
> > So, if someone implemented the equivalent drop stats functionality in
> > the kernel datapath that would be very welcome.
> > We in Ericsson cannot do that currently due to license restrictions.
> >
> > Regards, Jan
> >
> > > -----Original Message-----
> > > From: ovs-dev-bounces@openvswitch.org
> > > <ovs-dev-bounces@openvswitch.org>
> > On Behalf Of Rohith Basavaraja
> > > Sent: Friday, 25 May, 2018 07:37
> > > To: Ben Pfaff <blp@ovn.org>
> > > Cc: dev@openvswitch.org
> > > Subject: Re: [ovs-dev] [PATCH] Improved Packet Drop Statistics in OVS.
> > >
> > > Thanks Ben for the clarification. Yes this new stuff is used only in
> > > the DPDK datapath and it’s not used in the kernel datapath.
> > >
> > > Thanks
> > > Rohith
> > >
> > > On 25/05/18, 2:52 AM, "Ben Pfaff" <blp@ovn.org> wrote:
> > >
> > >     On Thu, May 24, 2018 at 02:19:06AM +0000, Rohith Basavaraja wrote:
> > >     > Only  changes in
> > >     > datapath/linux/compat/include/linux/openvswitch.h
> > >     > are related to OvS Kernel module.
> > >
> > >     On a second look, I see that the new stuff here is only for the
> DPDK
> > >     datapath.  If you don't intend to add this feature to the kernel
> > >     datapath, there should be no problem.  Never mind.
> > >
> > >
> > > _______________________________________________
> > > dev mailing list
> > > dev@openvswitch.org
> > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
Federico Iezzi July 10, 2018, 7:45 a.m. UTC | #11
I see it doesn't merge anymore, I have very little hopes to see it in with
2.10 ...

On Mon, 11 Jun 2018 at 10:33, Stokes, Ian <ian.stokes@intel.com> wrote:

> > I'm very sorry for double posting.
> > I believe this patch would represent a major feature in term of OVS's
> > usability.
> > Has anyone got any time for reviewing it?
> >
>
> I'm planning to look at it this week.
>
> Thanks
> Ian
>
> > Thanks,
> > Federico
> >
> > On 6 June 2018 at 17:37, Jan Scheurich <jan.scheurich@ericsson.com>
> wrote:
> >
> > > The user-space part for packet drop stats should be generic and work
> > > with any dpif datapath.
> > > So, if someone implemented the equivalent drop stats functionality in
> > > the kernel datapath that would be very welcome.
> > > We in Ericsson cannot do that currently due to license restrictions.
> > >
> > > Regards, Jan
> > >
> > > > -----Original Message-----
> > > > From: ovs-dev-bounces@openvswitch.org
> > > > <ovs-dev-bounces@openvswitch.org>
> > > On Behalf Of Rohith Basavaraja
> > > > Sent: Friday, 25 May, 2018 07:37
> > > > To: Ben Pfaff <blp@ovn.org>
> > > > Cc: dev@openvswitch.org
> > > > Subject: Re: [ovs-dev] [PATCH] Improved Packet Drop Statistics in
> OVS.
> > > >
> > > > Thanks Ben for the clarification. Yes this new stuff is used only in
> > > > the DPDK datapath and it’s not used in the kernel datapath.
> > > >
> > > > Thanks
> > > > Rohith
> > > >
> > > > On 25/05/18, 2:52 AM, "Ben Pfaff" <blp@ovn.org> wrote:
> > > >
> > > >     On Thu, May 24, 2018 at 02:19:06AM +0000, Rohith Basavaraja
> wrote:
> > > >     > Only  changes in
> > > >     > datapath/linux/compat/include/linux/openvswitch.h
> > > >     > are related to OvS Kernel module.
> > > >
> > > >     On a second look, I see that the new stuff here is only for the
> > DPDK
> > > >     datapath.  If you don't intend to add this feature to the kernel
> > > >     datapath, there should be no problem.  Never mind.
> > > >
> > > >
> > > > _______________________________________________
> > > > dev mailing list
> > > > dev@openvswitch.org
> > > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> > > _______________________________________________
> > > dev mailing list
> > > dev@openvswitch.org
> > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> > >
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
Federico Iezzi July 24, 2018, 7:52 a.m. UTC | #12
Hi all,

It seems Rohith Basavaraja email has been disabled.
I believe it's too late for someone else to pick up Rohith's work, right?

Federico

On Mon, 11 Jun 2018 at 10:33, Stokes, Ian <ian.stokes@intel.com> wrote:

> > I'm very sorry for double posting.
> > I believe this patch would represent a major feature in term of OVS's
> > usability.
> > Has anyone got any time for reviewing it?
> >
>
> I'm planning to look at it this week.
>
> Thanks
> Ian
>
> > Thanks,
> > Federico
> >
> > On 6 June 2018 at 17:37, Jan Scheurich <jan.scheurich@ericsson.com>
> wrote:
> >
> > > The user-space part for packet drop stats should be generic and work
> > > with any dpif datapath.
> > > So, if someone implemented the equivalent drop stats functionality in
> > > the kernel datapath that would be very welcome.
> > > We in Ericsson cannot do that currently due to license restrictions.
> > >
> > > Regards, Jan
> > >
> > > > -----Original Message-----
> > > > From: ovs-dev-bounces@openvswitch.org
> > > > <ovs-dev-bounces@openvswitch.org>
> > > On Behalf Of Rohith Basavaraja
> > > > Sent: Friday, 25 May, 2018 07:37
> > > > To: Ben Pfaff <blp@ovn.org>
> > > > Cc: dev@openvswitch.org
> > > > Subject: Re: [ovs-dev] [PATCH] Improved Packet Drop Statistics in
> OVS.
> > > >
> > > > Thanks Ben for the clarification. Yes this new stuff is used only in
> > > > the DPDK datapath and it’s not used in the kernel datapath.
> > > >
> > > > Thanks
> > > > Rohith
> > > >
> > > > On 25/05/18, 2:52 AM, "Ben Pfaff" <blp@ovn.org> wrote:
> > > >
> > > >     On Thu, May 24, 2018 at 02:19:06AM +0000, Rohith Basavaraja
> wrote:
> > > >     > Only  changes in
> > > >     > datapath/linux/compat/include/linux/openvswitch.h
> > > >     > are related to OvS Kernel module.
> > > >
> > > >     On a second look, I see that the new stuff here is only for the
> > DPDK
> > > >     datapath.  If you don't intend to add this feature to the kernel
> > > >     datapath, there should be no problem.  Never mind.
> > > >
> > > >
> > > > _______________________________________________
> > > > dev mailing list
> > > > dev@openvswitch.org
> > > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> > > _______________________________________________
> > > dev mailing list
> > > dev@openvswitch.org
> > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> > >
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
Keshav Gupta July 24, 2018, 12:01 p.m. UTC | #13
Hi Federico and all
     I will work on this Rohitha's patch to take it forward.

Thanks
Keshav

-----Original Message-----
From: ovs-dev-bounces@openvswitch.org [mailto:ovs-dev-bounces@openvswitch.org] On Behalf Of Federico Iezzi
Sent: Tuesday, July 24, 2018 1:23 PM
To: ian.stokes@intel.com
Cc: dev@openvswitch.org
Subject: Re: [ovs-dev] [PATCH] Improved Packet Drop Statistics in OVS.

Hi all,

It seems Rohith Basavaraja email has been disabled.
I believe it's too late for someone else to pick up Rohith's work, right?

Federico

On Mon, 11 Jun 2018 at 10:33, Stokes, Ian <ian.stokes@intel.com> wrote:

> > I'm very sorry for double posting.
> > I believe this patch would represent a major feature in term of 
> > OVS's usability.
> > Has anyone got any time for reviewing it?
> >
>
> I'm planning to look at it this week.
>
> Thanks
> Ian
>
> > Thanks,
> > Federico
> >
> > On 6 June 2018 at 17:37, Jan Scheurich <jan.scheurich@ericsson.com>
> wrote:
> >
> > > The user-space part for packet drop stats should be generic and 
> > > work with any dpif datapath.
> > > So, if someone implemented the equivalent drop stats functionality 
> > > in the kernel datapath that would be very welcome.
> > > We in Ericsson cannot do that currently due to license restrictions.
> > >
> > > Regards, Jan
> > >
> > > > -----Original Message-----
> > > > From: ovs-dev-bounces@openvswitch.org 
> > > > <ovs-dev-bounces@openvswitch.org>
> > > On Behalf Of Rohith Basavaraja
> > > > Sent: Friday, 25 May, 2018 07:37
> > > > To: Ben Pfaff <blp@ovn.org>
> > > > Cc: dev@openvswitch.org
> > > > Subject: Re: [ovs-dev] [PATCH] Improved Packet Drop Statistics 
> > > > in
> OVS.
> > > >
> > > > Thanks Ben for the clarification. Yes this new stuff is used 
> > > > only in the DPDK datapath and it’s not used in the kernel datapath.
> > > >
> > > > Thanks
> > > > Rohith
> > > >
> > > > On 25/05/18, 2:52 AM, "Ben Pfaff" <blp@ovn.org> wrote:
> > > >
> > > >     On Thu, May 24, 2018 at 02:19:06AM +0000, Rohith Basavaraja
> wrote:
> > > >     > Only  changes in
> > > >     > datapath/linux/compat/include/linux/openvswitch.h
> > > >     > are related to OvS Kernel module.
> > > >
> > > >     On a second look, I see that the new stuff here is only for 
> > > > the
> > DPDK
> > > >     datapath.  If you don't intend to add this feature to the kernel
> > > >     datapath, there should be no problem.  Never mind.
> > > >
> > > >
> > > > _______________________________________________
> > > > dev mailing list
> > > > dev@openvswitch.org
> > > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> > > _______________________________________________
> > > dev mailing list
> > > dev@openvswitch.org
> > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> > >
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
diff mbox series

Patch

diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index 6f4fa01..b28d68d 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -815,6 +815,56 @@  struct ovs_action_push_eth {
 };
 
 /**
+ * enum ovs_drop_reason - Reasons for installing %OVS_ACTION_ATTR_DROP. 
+ * @OVS_DROP_REASON_OF_PIPELINE: Explicit drop action in the pipeline.
+ * @OVS_DROP_REASON_BRIDGE_NOT_FOUND: Xlation error generated due to
+ * unable to determine bridge.
+ * @OVS_DROP_REASON_RECURSION_TOO_DEEP: Xlation error generated due to
+ * recursion reached maximum depth.
+ * @OVS_DROP_REASON_TOO_MANY_RESUBMITS: Xlation error generated due to
+ * too many resubmits.
+ * @OVS_DROP_REASON_STACK_TOO_DEEP: Xlation error generated due to stack
+ * too deep.
+ * @OVS_DROP_REASON_NO_RECIRCULATION_CONTEXT: Xlation error generated
+ * due to no recirculation context.
+ * @OVS_DROP_REASON_RECIRCULATION_CONFLICT: Xlation error generated due to
+ * conflict in recirculation context.
+ * @OVS_DROP_REASON_TOO_MANY_MPLS_LABELS: Xlation error generated due to 
+ * too many mpls labels.
+ * @OVS_DROP_REASON_INVALID_TUNNEL_METADATA: Xlation error generated due to
+ * invalid tunnel metadata.
+ * @OVS_DROP_REASON_UNSUPPORTED_PACKET_TYPE: Xlation error generated due to
+ * unsupported packet type.
+ * @OVS_DROP_REASON_CONGESTION: Xlation error generated due to ecn mismatch
+ * during tunnel decapsulation.
+ * @OVS_DROP_REASON_FORWARDING_DISABLED: Xlation error generated due to
+ * forwarding is disabled.
+ */
+enum ovs_drop_reason {
+    OVS_DROP_REASON_OF_PIPELINE = 0,
+    OVS_DROP_REASON_BRIDGE_NOT_FOUND,
+    OVS_DROP_REASON_RECURSION_TOO_DEEP,
+    OVS_DROP_REASON_TOO_MANY_RESUBMITS,
+    OVS_DROP_REASON_STACK_TOO_DEEP,
+    OVS_DROP_REASON_NO_RECIRCULATION_CONTEXT,
+    OVS_DROP_REASON_RECIRCULATION_CONFLICT,
+    OVS_DROP_REASON_TOO_MANY_MPLS_LABELS,
+    OVS_DROP_REASON_INVALID_TUNNEL_METADATA,
+    OVS_DROP_REASON_UNSUPPORTED_PACKET_TYPE,
+    OVS_DROP_REASON_CONGESTION,
+    OVS_DROP_REASON_FORWARDING_DISABLED,
+    OVS_DROP_REASON_MAX,
+};
+
+/*
+ * struct ovs_action_drop - %OVS_ACTION_ATTR_DROP action argument.
+ * @drop_reason: Reason for installing drop action.
+ */
+struct ovs_action_drop {
+    enum ovs_drop_reason drop_reason;    
+};
+
+/**
  * enum ovs_nat_attr - Attributes for %OVS_CT_ATTR_NAT.
  *
  * @OVS_NAT_ATTR_SRC: Flag for Source NAT (mangle source address/port).
@@ -936,6 +986,7 @@  enum ovs_action_attr {
 	OVS_ACTION_ATTR_TUNNEL_POP,    /* u32 port number. */
 	OVS_ACTION_ATTR_CLONE,         /* Nested OVS_CLONE_ATTR_*.  */
 	OVS_ACTION_ATTR_METER,         /* u32 meter number. */
+        OVS_ACTION_ATTR_DROP,          /* explicit drop action. */
 #endif
 	__OVS_ACTION_ATTR_MAX,	      /* Nothing past this will be accepted
 				       * from userspace. */
diff --git a/lib/dpif-netdev-perf.c b/lib/dpif-netdev-perf.c
index 13f1010..9b3b9e4 100644
--- a/lib/dpif-netdev-perf.c
+++ b/lib/dpif-netdev-perf.c
@@ -388,6 +388,33 @@  pmd_perf_read_counters(struct pmd_perf_stats *s,
     }
 }
 
+void
+pmd_perf_read_drop_counters(struct pmd_perf_stats *s,
+                            struct dpif_dp_drop_stats *drop_stats)
+{
+    uint64_t val;
+    int i;
+
+    for (i = 0; i < DPIF_RX_MAX_DROP; i++) {
+        atomic_read_relaxed(&s->drop_counters.n.rx_drops[i], &val);
+        drop_stats->rx_drops[i] += val - s->drop_counters.zero.rx_drops[i];
+    }
+    for (i = 0; i < OVS_DROP_REASON_MAX; i++) {
+        atomic_read_relaxed(&s->drop_counters.n.drop_action_drops[i], &val);
+        drop_stats->drop_action_drops[i] += val -
+                                s->drop_counters.zero.drop_action_drops[i];
+    }
+    for (i = 0; i < DPIF_DP_MAX_DROP; i++) {
+        atomic_read_relaxed(&s->drop_counters.n.dp_drops[i], &val);
+        drop_stats->dp_drops[i] += val - s->drop_counters.zero.dp_drops[i];
+    }
+    for (i = 0; i < DPIF_TX_MAX_DROP; i++) {
+        atomic_read_relaxed(&s->drop_counters.n.tx_drops[i], &val);
+        drop_stats->tx_drops[i] += val - s->drop_counters.zero.tx_drops[i];
+    }
+
+}
+
 /* This function clears the PMD performance counters from within the PMD
  * thread or from another thread when the PMD thread is not executing its
  * poll loop. */
@@ -438,6 +465,29 @@  pmd_perf_stats_clear(struct pmd_perf_stats *s)
     }
 }
 
+void
+pmd_perf_drop_stats_clear(struct pmd_perf_stats *s)
+{
+    int i;
+
+    for (i = 0; i < DPIF_RX_MAX_DROP; i++) {
+        atomic_read_relaxed(&s->drop_counters.n.rx_drops[i],
+                            &s->drop_counters.zero.rx_drops[i]);
+    }
+    for (i = 0; i < OVS_DROP_REASON_MAX; i++) {
+        atomic_read_relaxed(&s->drop_counters.n.drop_action_drops[i],
+                            &s->drop_counters.zero.drop_action_drops[i]);
+    }
+    for (i = 0; i < DPIF_DP_MAX_DROP; i++) {
+        atomic_read_relaxed(&s->drop_counters.n.dp_drops[i],
+                            &s->drop_counters.zero.dp_drops[i]);
+    }
+    for (i = 0; i < DPIF_TX_MAX_DROP; i++) {
+        atomic_read_relaxed(&s->drop_counters.n.tx_drops[i],
+                            &s->drop_counters.zero.tx_drops[i]);
+    }
+}
+
 /* Functions recording PMD metrics per iteration. */
 
 void
diff --git a/lib/dpif-netdev-perf.h b/lib/dpif-netdev-perf.h
index b8aa4e3..8996fea 100644
--- a/lib/dpif-netdev-perf.h
+++ b/lib/dpif-netdev-perf.h
@@ -33,6 +33,7 @@ 
 #include "timeval.h"
 #include "unixctl.h"
 #include "util.h"
+#include "dpif.h"
 
 #ifdef  __cplusplus
 extern "C" {
@@ -90,6 +91,21 @@  struct pmd_counters {
     uint64_t zero[PMD_N_STATS];         /* Value at last _clear().  */
 };
 
+/* Drop statistics maintained at per PMD level.
+ * It uses the same update/clear frame work used for other pmd_counters. */
+struct pmd_drop_stats {
+    atomic_uint64_t rx_drops[DPIF_RX_MAX_DROP];
+    atomic_uint64_t drop_action_drops[OVS_DROP_REASON_MAX];
+    atomic_uint64_t dp_drops[DPIF_DP_MAX_DROP];
+    atomic_uint64_t tx_drops[DPIF_TX_MAX_DROP];
+};
+
+struct pmd_drop_counters {
+    struct pmd_drop_stats n;      /* Value since _init(). */
+    struct pmd_drop_stats zero;   /* Value at last _clear().  */
+};
+
+
 /* Data structure to collect statistical distribution of an integer measurement
  * type in form of a histogram. The wall[] array contains the inclusive
  * upper boundaries of the bins, while the bin[] array contains the actual
@@ -159,6 +175,8 @@  struct pmd_perf_stats {
     struct cycle_timer *cur_timer;
     /* Set of PMD counters with their zero offsets. */
     struct pmd_counters counters;
+    /* Set of PMD drop counters with their zero offsets. */
+    struct pmd_drop_counters drop_counters;
     /* Statistics of the current iteration. */
     struct iter_stats current;
     /* Totals for the current millisecond. */
@@ -276,6 +294,12 @@  void pmd_perf_stats_clear_lock(struct pmd_perf_stats *s);
 void pmd_perf_read_counters(struct pmd_perf_stats *s,
                             uint64_t stats[PMD_N_STATS]);
 
+void pmd_perf_drop_stats_init(struct pmd_perf_stats *s);
+void pmd_perf_drop_stats_clear(struct pmd_perf_stats *s);
+void pmd_perf_read_drop_counters(struct pmd_perf_stats *s,
+                                 struct dpif_dp_drop_stats *drops);
+
+
 /* PMD performance counters are updated lock-less. For real PMDs
  * they are only updated from the PMD thread itself. In the case of the
  * NON-PMD they might be updated from multiple threads, but we can live
@@ -397,6 +421,34 @@  void pmd_perf_log_set_cmd(struct unixctl_conn *conn,
                           int argc, const char *argv[],
                           void *aux OVS_UNUSED);
 
+static inline void
+pmd_perf_update_drop_counter(struct pmd_perf_stats *s,
+                             struct dpif_drop_counter *cntr, int delta)
+{
+    unsigned long val;
+    switch (cntr->type) {
+        case DPIF_DROP_TYPE_RX:
+            atomic_add_relaxed(&s->drop_counters.n.rx_drops[cntr->counter.rx],
+                               delta, &val);
+            break;
+        case DPIF_DROP_TYPE_DP:
+            atomic_add_relaxed(&s->drop_counters.n.dp_drops[cntr->counter.dp],
+                               delta, &val);
+            break;
+        case DPIF_DROP_TYPE_DA:
+            atomic_add_relaxed(
+                      &s->drop_counters.n.drop_action_drops[cntr->counter.da],
+                      delta, &val);
+            break;
+        case DPIF_DROP_TYPE_TX:
+            atomic_add_relaxed(&s->drop_counters.n.tx_drops[cntr->counter.tx],
+                               delta, &val);
+            break;
+        OVS_NOT_REACHED();
+    }
+}
+
+
 #ifdef  __cplusplus
 }
 #endif
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index f86ed2a..31badd8 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -1244,6 +1244,46 @@  dpif_netdev_init(void)
 }
 
 static int
+dpif_netdev_get_drop_stats(const struct dpif *dpif,
+                           struct dpif_dp_drop_stats *drop_stats)
+{
+    struct dp_netdev *dp = get_dp_netdev(dpif);
+    struct dp_netdev_pmd_thread *pmd;
+    struct dp_netdev_port *port;
+    struct netdev_stats stats;
+
+    memset(drop_stats, 0 , sizeof(*drop_stats));
+    CMAP_FOR_EACH (pmd, node, &dp->poll_threads) {
+        pmd_perf_read_drop_counters(&pmd->perf_stats, drop_stats);
+    }
+    ovs_mutex_lock(&dp->port_mutex);
+    HMAP_FOR_EACH (port, node, &dp->ports) {
+        if (!netdev_is_pmd(port->netdev)) {
+            continue;
+        }
+
+        port->netdev->netdev_class->get_stats(port->netdev,
+                                              &stats);
+        drop_stats->iface_rx_drops += stats.rx_dropped;
+        drop_stats->iface_tx_drops += stats.tx_dropped;
+    }
+    ovs_mutex_unlock(&dp->port_mutex);
+
+    return 0;
+}
+
+static int
+dpif_netdev_clear_drop_stats(const struct dpif *dpif)
+{
+    struct dp_netdev *dp = get_dp_netdev(dpif);
+    struct dp_netdev_pmd_thread *pmd;
+    CMAP_FOR_EACH (pmd, node, &dp->poll_threads) {
+        pmd_perf_drop_stats_clear(&pmd->perf_stats);
+    }
+    return 0;
+}
+
+static int
 dpif_netdev_enumerate(struct sset *all_dps,
                       const struct dpif_class *dpif_class)
 {
@@ -4375,7 +4415,8 @@  dpif_netdev_meter_get_features(const struct dpif * dpif OVS_UNUSED,
 
 /* Returns false when packet needs to be dropped. */
 static void
-dp_netdev_run_meter(struct dp_netdev *dp, struct dp_packet_batch *packets_,
+dp_netdev_run_meter(struct dp_netdev_pmd_thread *pmd,
+                    struct dp_netdev *dp, struct dp_packet_batch *packets_,
                     uint32_t meter_id, long long int now)
 {
     struct dp_meter *meter;
@@ -4499,12 +4540,16 @@  dp_netdev_run_meter(struct dp_netdev *dp, struct dp_packet_batch *packets_,
     size_t j;
     DP_PACKET_BATCH_REFILL_FOR_EACH (j, cnt, packet, packets_) {
         if (exceeded_band[j] >= 0) {
+            struct dpif_drop_counter cntr;
             /* Meter drop packet. */
             band = &meter->bands[exceeded_band[j]];
             band->packet_count += 1;
             band->byte_count += dp_packet_size(packet);
 
             dp_packet_delete(packet);
+            cntr.type = DPIF_DROP_TYPE_DP;
+            cntr.counter.dp = DPIF_DP_METER_DROP;
+            pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr, 1);
         } else {
             /* Meter accepts packet. */
             dp_packet_batch_refill(packets_, packet, j);
@@ -5158,6 +5203,7 @@  emc_processing(struct dp_netdev_pmd_thread *pmd,
     const size_t cnt = dp_packet_batch_size(packets_);
     uint32_t cur_min;
     int i;
+    struct dpif_drop_counter cntr;
 
     atomic_read_relaxed(&pmd->dp->emc_insert_min, &cur_min);
     pmd_perf_update_counter(&pmd->perf_stats,
@@ -5169,6 +5215,9 @@  emc_processing(struct dp_netdev_pmd_thread *pmd,
 
         if (OVS_UNLIKELY(dp_packet_size(packet) < ETH_HEADER_LEN)) {
             dp_packet_delete(packet);
+            cntr.type = DPIF_DROP_TYPE_RX;
+            cntr.counter.rx = DPIF_RX_INVALID_PACKET_DROP;
+            pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr, 1);
             n_dropped++;
             continue;
         }
@@ -5229,6 +5278,7 @@  handle_packet_upcall(struct dp_netdev_pmd_thread *pmd,
     ovs_u128 ufid;
     int error;
     uint64_t cycles = cycles_counter_update(&pmd->perf_stats);
+    struct dpif_drop_counter cntr;
 
     match.tun_md.valid = false;
     miniflow_expand(&key->mf, &match.flow);
@@ -5242,6 +5292,9 @@  handle_packet_upcall(struct dp_netdev_pmd_thread *pmd,
                              put_actions);
     if (OVS_UNLIKELY(error && error != ENOSPC)) {
         dp_packet_delete(packet);
+        cntr.type = DPIF_DROP_TYPE_DP;
+        cntr.counter.dp = DPIF_DP_UPCALL_ERROR_DROP;
+        pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr, 1);
         return error;
     }
 
@@ -5315,6 +5368,7 @@  fast_path_processing(struct dp_netdev_pmd_thread *pmd,
     int upcall_ok_cnt = 0, upcall_fail_cnt = 0;
     int lookup_cnt = 0, add_lookup_cnt;
     bool any_miss;
+    struct dpif_drop_counter cntr;
 
     for (size_t i = 0; i < cnt; i++) {
         /* Key length is needed in all the cases, hash computed on demand. */
@@ -5370,6 +5424,9 @@  fast_path_processing(struct dp_netdev_pmd_thread *pmd,
         DP_PACKET_BATCH_FOR_EACH (i, packet, packets_) {
             if (OVS_UNLIKELY(!rules[i])) {
                 dp_packet_delete(packet);
+                cntr.type = DPIF_DROP_TYPE_DP;
+                cntr.counter.dp = DPIF_DP_UPCALL_LOCK_ERROR_DROP;
+                pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr, 1);
                 upcall_fail_cnt++;
             }
         }
@@ -5601,6 +5658,7 @@  dp_execute_userspace_action(struct dp_netdev_pmd_thread *pmd,
 {
     struct dp_packet_batch b;
     int error;
+    struct dpif_drop_counter cntr;
 
     ofpbuf_clear(actions);
 
@@ -5613,10 +5671,23 @@  dp_execute_userspace_action(struct dp_netdev_pmd_thread *pmd,
                                   actions->data, actions->size);
     } else if (may_steal) {
         dp_packet_delete(packet);
+        cntr.type = DPIF_DROP_TYPE_DP;
+        cntr.counter.dp = DPIF_DP_USER_SPACE_ACTION_ERROR_DROP;
+        pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr, 1);
     }
 }
 
 static void
+dp_update_drop_counter_cb(void *aux_, struct dpif_drop_counter *cntr,
+                       int delta)
+    OVS_NO_THREAD_SAFETY_ANALYSIS
+{
+    struct dp_netdev_execute_aux *aux = aux_;
+    struct dp_netdev_pmd_thread *pmd = aux->pmd;
+    pmd_perf_update_drop_counter(&pmd->perf_stats, cntr, delta);
+}
+
+static void
 dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
               const struct nlattr *a, bool may_steal)
     OVS_NO_THREAD_SAFETY_ANALYSIS
@@ -5627,6 +5698,8 @@  dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
     struct dp_netdev *dp = pmd->dp;
     int type = nl_attr_type(a);
     struct tx_port *p;
+    uint32_t packet_count, packet_dropped;
+    struct dpif_drop_counter cntr;
 
     switch ((enum ovs_action_attr)type) {
     case OVS_ACTION_ATTR_OUTPUT:
@@ -5668,14 +5741,31 @@  dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
                 dp_packet_batch_add(&p->output_pkts, packet);
             }
             return;
+        } else {
+            cntr.type = DPIF_DROP_TYPE_DP;
+            cntr.counter.dp = DPIF_DP_INVALID_PORT_DROP;
+            pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr,
+                                         packets_->count);
         }
         break;
 
     case OVS_ACTION_ATTR_TUNNEL_PUSH:
         if (*depth < MAX_RECIRC_DEPTH) {
+            int err;
             dp_packet_batch_apply_cutlen(packets_);
-            push_tnl_action(pmd, a, packets_);
+            err = push_tnl_action(pmd, a, packets_);
+            if (err) {
+                cntr.type = DPIF_DROP_TYPE_DP;
+                cntr.counter.dp = DPIF_DP_TUNNEL_PUSH_ERROR_DROP;
+                pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr,
+                                             packets_->count);
+            }
             return;
+        } else {
+            cntr.type = DPIF_DROP_TYPE_DP;
+            cntr.counter.dp = DPIF_DP_RECIRC_ERROR_DROP;
+            pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr,
+                                             packets_->count);
         }
         break;
 
@@ -5696,7 +5786,16 @@  dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
 
                 dp_packet_batch_apply_cutlen(packets_);
 
+                packet_count = packets_->count;
                 netdev_pop_header(p->port->netdev, packets_);
+                packet_dropped = packet_count - packets_->count;
+                if (packet_dropped) {
+                    cntr.type = DPIF_DROP_TYPE_DP;
+                    cntr.counter.dp = DPIF_DP_TUNNEL_POP_ERROR_DROP;
+                    pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr,
+                                                 packet_dropped);
+                }
+
                 if (dp_packet_batch_is_empty(packets_)) {
                     return;
                 }
@@ -5710,7 +5809,17 @@  dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
                 dp_netdev_recirculate(pmd, packets_);
                 (*depth)--;
                 return;
-            }
+            } else {
+                cntr.type = DPIF_DROP_TYPE_DP;
+                cntr.counter.dp = DPIF_DP_INVALID_TNL_PORT_DROP;
+                pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr,
+                                             packets_->count);
+            }    
+        } else {
+            cntr.type = DPIF_DROP_TYPE_DP;
+            cntr.counter.dp = DPIF_DP_RECIRC_ERROR_DROP;
+            pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr,
+                                             packets_->count);
         }
         break;
 
@@ -5754,6 +5863,11 @@  dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
             fat_rwlock_unlock(&dp->upcall_rwlock);
 
             return;
+        } else {
+            cntr.type = DPIF_DROP_TYPE_DP;
+            cntr.counter.dp = DPIF_DP_UPCALL_LOCK_ERROR_DROP;
+            pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr,
+                                             packets_->count);
         }
         break;
 
@@ -5776,6 +5890,11 @@  dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
             (*depth)--;
 
             return;
+        } else {
+            cntr.type = DPIF_DROP_TYPE_DP;
+            cntr.counter.dp = DPIF_DP_RECIRC_ERROR_DROP;
+            pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr,
+                                         packets_->count);
         }
 
         VLOG_WARN("Packet dropped. Max recirculation depth exceeded.");
@@ -5910,7 +6029,7 @@  dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
     }
 
     case OVS_ACTION_ATTR_METER:
-        dp_netdev_run_meter(pmd->dp, packets_, nl_attr_get_u32(a),
+        dp_netdev_run_meter(pmd, pmd->dp, packets_, nl_attr_get_u32(a),
                             pmd->ctx.now);
         break;
 
@@ -5930,6 +6049,7 @@  dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
     case OVS_ACTION_ATTR_PUSH_NSH:
     case OVS_ACTION_ATTR_POP_NSH:
     case OVS_ACTION_ATTR_CT_CLEAR:
+    case OVS_ACTION_ATTR_DROP:
     case __OVS_ACTION_ATTR_MAX:
         OVS_NOT_REACHED();
     }
@@ -5946,7 +6066,8 @@  dp_netdev_execute_actions(struct dp_netdev_pmd_thread *pmd,
     struct dp_netdev_execute_aux aux = { pmd, flow };
 
     odp_execute_actions(&aux, packets, may_steal, actions,
-                        actions_len, dp_execute_cb);
+                        actions_len, dp_execute_cb,
+                        dp_update_drop_counter_cb);
 }
 
 struct dp_netdev_ct_dump {
@@ -6049,6 +6170,8 @@  const struct dpif_class dpif_netdev_class = {
     dpif_netdev_run,
     dpif_netdev_wait,
     dpif_netdev_get_stats,
+    dpif_netdev_get_drop_stats,
+    dpif_netdev_clear_drop_stats,
     dpif_netdev_port_add,
     dpif_netdev_port_del,
     dpif_netdev_port_set_config,
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 62b3598..d1b4b2c 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -156,6 +156,13 @@  struct dpif_class {
     /* Retrieves statistics for 'dpif' into 'stats'. */
     int (*get_stats)(const struct dpif *dpif, struct dpif_dp_stats *stats);
 
+    /* Retrieves drop statistics for 'dpif' into 'drop_stats'. */
+    int (*get_drop_stats)(const struct dpif *dpif,
+                          struct dpif_dp_drop_stats *drop_stats);
+
+    /* Clears drop statistics for 'dpif'. */
+    int (*clear_drop_stats)(const struct dpif *dpif);
+
     /* Adds 'netdev' as a new port in 'dpif'.  If '*port_no' is not
      * ODPP_NONE, attempts to use that as the port's port number.
      *
diff --git a/lib/dpif.c b/lib/dpif.c
index b098a4c..6eb54a7 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -538,6 +538,38 @@  dpif_get_dp_stats(const struct dpif *dpif, struct dpif_dp_stats *stats)
     return error;
 }
 
+/* Retrieves drop statistics for 'dpif' into 'drop_stats'.  Returns 0
+ * if successful, otherwise a positive errno value. */
+int
+dpif_get_dp_drop_stats(const struct dpif *dpif,
+                  struct dpif_dp_drop_stats *drop_stats)
+{
+    int error = 0;
+    if (dpif->dpif_class->get_drop_stats) {
+        error = dpif->dpif_class->get_drop_stats(dpif, drop_stats);
+        if (error) {
+            memset(drop_stats, 0, sizeof *drop_stats);
+        }
+        log_operation(dpif, "get_drop_stats", error);
+    } else {
+        log_operation(dpif, "get_drop_stats not supported", error);
+    }
+    return error;
+}
+
+/* Clears drop statistics in 'dpif' into 'drop_stats'. */
+int
+dpif_clear_dp_drop_stats(const struct dpif *dpif)
+{
+    int error = 0;
+    if (dpif->dpif_class->clear_drop_stats) {
+        error = dpif->dpif_class->clear_drop_stats(dpif);
+    } else {
+        log_operation(dpif, "clear_drop_stats not supported", error);
+    }
+    return error;
+}
+
 const char *
 dpif_port_open_type(const char *datapath_type, const char *port_type)
 {
@@ -1275,6 +1307,7 @@  dpif_execute_helper_cb(void *aux_, struct dp_packet_batch *packets_,
     case OVS_ACTION_ATTR_PUSH_NSH:
     case OVS_ACTION_ATTR_POP_NSH:
     case OVS_ACTION_ATTR_CT_CLEAR:
+    case OVS_ACTION_ATTR_DROP:
     case OVS_ACTION_ATTR_UNSPEC:
     case __OVS_ACTION_ATTR_MAX:
         OVS_NOT_REACHED();
@@ -1297,7 +1330,7 @@  dpif_execute_with_help(struct dpif *dpif, struct dpif_execute *execute)
 
     dp_packet_batch_init_packet(&pb, execute->packet);
     odp_execute_actions(&aux, &pb, false, execute->actions,
-                        execute->actions_len, dpif_execute_helper_cb);
+                        execute->actions_len, dpif_execute_helper_cb, NULL);
     return aux.error;
 }
 
@@ -1870,6 +1903,12 @@  dpif_supports_tnl_push_pop(const struct dpif *dpif)
     return dpif_is_netdev(dpif);
 }
 
+bool
+dpif_supports_explicit_drop_action(const struct dpif *dpif)
+{
+    return dpif_is_netdev(dpif);
+}
+
 /* Meters */
 void
 dpif_meter_get_features(const struct dpif *dpif,
@@ -1953,3 +1992,153 @@  dpif_meter_del(struct dpif *dpif, ofproto_meter_id meter_id,
     }
     return error;
 }
+
+static void
+dpif_show_drop_stats(struct ds *reply,
+                    struct dpif_dp_drop_stats *drop_stats)
+{
+    uint64_t rx_drops,tx_drops,dp_drops,drop_action_drops;
+    int i;
+
+    rx_drops = 0;
+    tx_drops = 0;
+    dp_drops = 0;
+    drop_action_drops = 0;
+    for (i = 0; i < DPIF_RX_MAX_DROP; i++) {
+        rx_drops += drop_stats->rx_drops[i];
+    }
+    for (i = 0; i < OVS_DROP_REASON_MAX; i++) {
+        drop_action_drops += drop_stats->drop_action_drops[i];
+    }
+    for (i = 0; i < DPIF_DP_MAX_DROP; i++) {
+        dp_drops += drop_stats->dp_drops[i];
+    }
+    for (i = 0; i < DPIF_TX_MAX_DROP; i++) {
+        tx_drops += drop_stats->tx_drops[i];
+    }
+    dp_drops += drop_action_drops;
+    rx_drops += drop_stats->iface_rx_drops;
+    tx_drops += drop_stats->iface_tx_drops;
+
+    ds_put_format(reply, "%-28s:%-12"PRIu64"\n", "rx-drops", rx_drops);
+    ds_put_format(reply, "%-28s:%-12"PRIu64"\n",
+                  "dataplane-processing-drops", dp_drops);
+    ds_put_format(reply, "     %-23s:%-12"PRIu64"\n", "drop action",
+                  drop_action_drops);
+    ds_put_format(reply, "     %-23s:%-12"PRIu64"\n", "upcall drops",
+                  drop_stats->dp_drops[DPIF_DP_UPCALL_ERROR_DROP] +
+                  drop_stats->dp_drops[DPIF_DP_UPCALL_LOCK_ERROR_DROP]);
+    ds_put_format(reply, "     %-23s:%-12"PRIu64"\n", "dp error drops",
+                  dp_drops -
+                  drop_action_drops -
+                  drop_stats->dp_drops[DPIF_DP_UPCALL_ERROR_DROP] -
+                  drop_stats->dp_drops[DPIF_DP_UPCALL_LOCK_ERROR_DROP]);
+    ds_put_format(reply, "%-28s:%-12"PRIu64"\n", "tx-drops",
+                  tx_drops);
+}
+
+static void
+dpif_show_drop_stats_detail(struct ds *reply,
+                    struct dpif_dp_drop_stats *drop_stats)
+{
+    uint32_t idx = 0;
+    ds_put_format(reply, "rx-drops: \n");
+    ds_put_format(reply, "%-7s %-38s %-12s\n", "[IDX]", "Drop Reason",
+                  "Packets");
+    ds_put_format(reply, "-------  ------------------------------------- "
+                         "------------\n");
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "interface & policer", drop_stats->iface_rx_drops);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "parsing error/invalid packet",
+                  drop_stats->rx_drops[DPIF_RX_INVALID_PACKET_DROP]);
+    ds_put_format(reply, "dataplane-processing-drops: \n");
+    ds_put_format(reply, "\"drop\" action:\n");
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "pipeline drop",
+                  drop_stats->drop_action_drops[OVS_DROP_REASON_OF_PIPELINE]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+              "bridge not found",
+              drop_stats->drop_action_drops[OVS_DROP_REASON_BRIDGE_NOT_FOUND]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+            "recursion too deep",
+            drop_stats->drop_action_drops[OVS_DROP_REASON_RECURSION_TOO_DEEP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+            "too many resubmits",
+            drop_stats->drop_action_drops[OVS_DROP_REASON_TOO_MANY_RESUBMITS]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++, "stack too deep",
+             drop_stats->drop_action_drops[OVS_DROP_REASON_STACK_TOO_DEEP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+      "no recirculation context",
+      drop_stats->drop_action_drops[OVS_DROP_REASON_NO_RECIRCULATION_CONTEXT]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+        "recirculation conflict",
+        drop_stats->drop_action_drops[OVS_DROP_REASON_RECIRCULATION_CONFLICT]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+          "too many mpls labels",
+          drop_stats->drop_action_drops[OVS_DROP_REASON_TOO_MANY_MPLS_LABELS]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+       "invalid tunnel metadata",
+       drop_stats->drop_action_drops[OVS_DROP_REASON_INVALID_TUNNEL_METADATA]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+       "unsupported packet type",
+       drop_stats->drop_action_drops[OVS_DROP_REASON_UNSUPPORTED_PACKET_TYPE]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+              "ecn mismatch at tunnel decapsulation",
+               drop_stats->drop_action_drops[OVS_DROP_REASON_CONGESTION]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+           "forwarding disabled (stp/rstp)",
+           drop_stats->drop_action_drops[OVS_DROP_REASON_FORWARDING_DISABLED]);
+    ds_put_format(reply, "upcall drops:\n");
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "upcall lock contention drop",
+                  drop_stats->dp_drops[DPIF_DP_UPCALL_LOCK_ERROR_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "upcall error drops",
+                  drop_stats->dp_drops[DPIF_DP_UPCALL_ERROR_DROP]);
+    ds_put_format(reply, "dp drops:\n");
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "tunnel pop action errors",
+                  drop_stats->dp_drops[DPIF_DP_TUNNEL_POP_ERROR_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "tunnel push action errors",
+                  drop_stats->dp_drops[DPIF_DP_TUNNEL_PUSH_ERROR_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "nsh decap errors",
+                  drop_stats->dp_drops[DPIF_DP_NSH_DECAP_ERROR_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "recirculation errors",
+                  drop_stats->dp_drops[DPIF_DP_RECIRC_ERROR_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++, "sampling error",
+                         drop_stats->dp_drops[DPIF_DP_SAMPLE_ERROR_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++, "meter drop",
+                         drop_stats->dp_drops[DPIF_DP_METER_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "user space action error",
+                  drop_stats->dp_drops[DPIF_DP_USER_SPACE_ACTION_ERROR_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++, "invalid port",
+                         drop_stats->dp_drops[DPIF_DP_INVALID_PORT_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "invalid tunnel port",
+                  drop_stats->dp_drops[DPIF_DP_INVALID_TNL_PORT_DROP]);
+    ds_put_format(reply, "tx-drops: \n");
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "interface & policer", drop_stats->iface_tx_drops);
+}
+
+int
+dpif_show_drop_stats_support(struct dpif *dpif, bool detail, struct ds *reply)
+{
+    struct dpif_dp_drop_stats drop_stats;
+    int error = 0;
+    error = dpif_get_dp_drop_stats(dpif, &drop_stats);
+    if (error) {
+        return error;
+    }
+    if (detail) {
+        dpif_show_drop_stats_detail(reply, &drop_stats);
+    } else {
+        dpif_show_drop_stats(reply, &drop_stats);
+    }
+    return 0;
+}
diff --git a/lib/dpif.h b/lib/dpif.h
index 94f89ec..b51b2c5 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -773,6 +773,66 @@  enum dpif_upcall_type {
     DPIF_N_UC_TYPES
 };
 
+/* Drop counter types */
+enum dpif_drop_type {
+    DPIF_DROP_TYPE_RX,      /* Rx drops */
+    DPIF_DROP_TYPE_DP,      /* Data path processing drops */
+    DPIF_DROP_TYPE_TX,      /* Tx drops */
+    DPIF_DROP_TYPE_DA,      /* Drop action drops */
+};
+
+/* Rx drop counters */
+enum dpif_rx_drops {
+    DPIF_RX_INVALID_PACKET_DROP = 0,
+    DPIF_RX_MAX_DROP,
+};
+
+/* Tx drop counters */
+enum dpif_tx_drops {
+    DPIF_TX_MAX_DROP,
+};
+
+/* Data path processing drop counters */
+enum dpif_dp_drops {
+    DPIF_DP_METER_DROP = 0,
+    DPIF_DP_UPCALL_ERROR_DROP,
+    DPIF_DP_UPCALL_LOCK_ERROR_DROP,
+    DPIF_DP_USER_SPACE_ACTION_ERROR_DROP,
+    DPIF_DP_TUNNEL_PUSH_ERROR_DROP,
+    DPIF_DP_TUNNEL_POP_ERROR_DROP,
+    DPIF_DP_SAMPLE_ERROR_DROP,
+    DPIF_DP_NSH_DECAP_ERROR_DROP,
+    DPIF_DP_RECIRC_ERROR_DROP,
+    DPIF_DP_INVALID_PORT_DROP,
+    DPIF_DP_INVALID_TNL_PORT_DROP,
+    DPIF_DP_MAX_DROP,
+};
+
+/* Structure used to define any drop counter */
+struct dpif_drop_counter {
+    enum dpif_drop_type type;
+    union {
+        enum dpif_rx_drops   rx;
+        enum dpif_dp_drops   dp;
+        enum ovs_drop_reason da;
+        enum dpif_tx_drops   tx;
+    } counter;
+};
+
+/* Drop statistics for a dpif as a whole.*/
+struct dpif_dp_drop_stats {
+    uint64_t iface_rx_drops;
+    uint64_t rx_drops[DPIF_RX_MAX_DROP];
+    uint64_t drop_action_drops[OVS_DROP_REASON_MAX];
+    uint64_t dp_drops[DPIF_DP_MAX_DROP];
+    uint64_t iface_tx_drops;
+    uint64_t tx_drops[DPIF_TX_MAX_DROP];
+};
+
+int dpif_get_dp_drop_stats(const struct dpif *, struct dpif_dp_drop_stats *);
+int dpif_clear_dp_drop_stats(const struct dpif *);
+
+
 const char *dpif_upcall_type_to_string(enum dpif_upcall_type);
 
 /* A packet passed up from the datapath to userspace.
@@ -883,7 +943,9 @@  int dpif_get_pmds_for_port(const struct dpif * dpif, odp_port_t port_no,
 
 char *dpif_get_dp_version(const struct dpif *);
 bool dpif_supports_tnl_push_pop(const struct dpif *);
-
+bool dpif_supports_explicit_drop_action(const struct dpif *);
+int dpif_show_drop_stats_support(struct dpif *dpif, bool detail,
+                                 struct ds *reply);
 /* Log functions. */
 struct vlog_module;
 
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 1969f02..6c72612 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -575,12 +575,14 @@  odp_execute_masked_set_action(struct dp_packet *packet,
 static void
 odp_execute_sample(void *dp, struct dp_packet *packet, bool steal,
                    const struct nlattr *action,
-                   odp_execute_cb dp_execute_action)
+                   odp_execute_cb dp_execute_action,
+                   odp_update_drop_counter_cb dp_update_drop_counter)
 {
     const struct nlattr *subactions = NULL;
     const struct nlattr *a;
     struct dp_packet_batch pb;
     size_t left;
+    struct dpif_drop_counter cntr;
 
     NL_NESTED_FOR_EACH_UNSAFE (a, left, action) {
         int type = nl_attr_type(a);
@@ -589,6 +591,11 @@  odp_execute_sample(void *dp, struct dp_packet *packet, bool steal,
         case OVS_SAMPLE_ATTR_PROBABILITY:
             if (random_uint32() >= nl_attr_get_u32(a)) {
                 if (steal) {
+                    if (dp_update_drop_counter) {
+                        cntr.type = DPIF_DROP_TYPE_DP;
+                        cntr.counter.dp = DPIF_DP_SAMPLE_ERROR_DROP;
+                        dp_update_drop_counter(dp, &cntr, 1);
+                    }
                     dp_packet_delete(packet);
                 }
                 return;
@@ -616,13 +623,15 @@  odp_execute_sample(void *dp, struct dp_packet *packet, bool steal,
     }
     dp_packet_batch_init_packet(&pb, packet);
     odp_execute_actions(dp, &pb, true, nl_attr_get(subactions),
-                        nl_attr_get_size(subactions), dp_execute_action);
+                        nl_attr_get_size(subactions), dp_execute_action,
+                        dp_update_drop_counter);
 }
 
 static void
 odp_execute_clone(void *dp, struct dp_packet_batch *batch, bool steal,
                    const struct nlattr *actions,
-                   odp_execute_cb dp_execute_action)
+                   odp_execute_cb dp_execute_action,
+                   odp_update_drop_counter_cb dp_update_drop_counter)
 {
     if (!steal) {
         /* The 'actions' may modify the packet, but the modification
@@ -634,11 +643,13 @@  odp_execute_clone(void *dp, struct dp_packet_batch *batch, bool steal,
         dp_packet_batch_clone(&clone_pkt_batch, batch);
         dp_packet_batch_reset_cutlen(batch);
         odp_execute_actions(dp, &clone_pkt_batch, true, nl_attr_get(actions),
-                        nl_attr_get_size(actions), dp_execute_action);
+                        nl_attr_get_size(actions), dp_execute_action,
+                        dp_update_drop_counter);
     }
     else {
         odp_execute_actions(dp, batch, true, nl_attr_get(actions),
-                            nl_attr_get_size(actions), dp_execute_action);
+                            nl_attr_get_size(actions), dp_execute_action,
+                            dp_update_drop_counter);
     }
 }
 
@@ -673,6 +684,7 @@  requires_datapath_assistance(const struct nlattr *a)
     case OVS_ACTION_ATTR_PUSH_NSH:
     case OVS_ACTION_ATTR_POP_NSH:
     case OVS_ACTION_ATTR_CT_CLEAR:
+    case OVS_ACTION_ATTR_DROP:
         return false;
 
     case OVS_ACTION_ATTR_UNSPEC:
@@ -695,11 +707,14 @@  requires_datapath_assistance(const struct nlattr *a)
 void
 odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,
                     const struct nlattr *actions, size_t actions_len,
-                    odp_execute_cb dp_execute_action)
+                    odp_execute_cb dp_execute_action,
+                    odp_update_drop_counter_cb dp_update_drop_counter)
 {
     struct dp_packet *packet;
     const struct nlattr *a;
     unsigned int left;
+    struct dpif_drop_counter cntr;
+
 
     NL_ATTR_FOR_EACH_UNSAFE (a, left, actions, actions_len) {
         int type = nl_attr_type(a);
@@ -801,7 +816,7 @@  odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,
         case OVS_ACTION_ATTR_SAMPLE:
             DP_PACKET_BATCH_FOR_EACH (i, packet, batch) {
                 odp_execute_sample(dp, packet, steal && last_action, a,
-                                   dp_execute_action);
+                                   dp_execute_action, dp_update_drop_counter);
             }
 
             if (last_action) {
@@ -824,7 +839,8 @@  odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,
 
         case OVS_ACTION_ATTR_CLONE:
             odp_execute_clone(dp, batch, steal && last_action, a,
-                                                dp_execute_action);
+                                         dp_execute_action,
+                                         dp_update_drop_counter);
             if (last_action) {
                 /* We do not need to free the packets. odp_execute_clone() has
                  * stolen them.  */
@@ -868,6 +884,11 @@  odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,
                 if (pop_nsh(packet)) {
                     dp_packet_batch_refill(batch, packet, i);
                 } else {
+                    if (dp_update_drop_counter) {
+                        cntr.type = DPIF_DROP_TYPE_DP;
+                        cntr.counter.dp = DPIF_DP_NSH_DECAP_ERROR_DROP;
+                        dp_update_drop_counter(dp, &cntr, 1);
+                    }
                     dp_packet_delete(packet);
                 }
             }
@@ -879,6 +900,19 @@  odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,
             }
             break;
 
+        case OVS_ACTION_ATTR_DROP: {
+            const struct ovs_action_drop *drop_action = nl_attr_get(a);
+            enum ovs_drop_reason drop_reason = drop_action->drop_reason;
+            if ((drop_reason < OVS_DROP_REASON_MAX) &&
+                 dp_update_drop_counter) {
+                 cntr.type = DPIF_DROP_TYPE_DA;
+                 cntr.counter.da = drop_reason;
+                 dp_update_drop_counter(dp, &cntr, batch->count);
+            }
+            dp_packet_delete_batch(batch, steal);
+            return;
+        }
+
         case OVS_ACTION_ATTR_OUTPUT:
         case OVS_ACTION_ATTR_TUNNEL_PUSH:
         case OVS_ACTION_ATTR_TUNNEL_POP:
diff --git a/lib/odp-execute.h b/lib/odp-execute.h
index 7223fe8..2f9f3c9 100644
--- a/lib/odp-execute.h
+++ b/lib/odp-execute.h
@@ -22,6 +22,8 @@ 
 #include <stddef.h>
 #include <stdint.h>
 #include "openvswitch/types.h"
+#include "ovs-atomic.h"
+#include "dpif.h"
 
 struct nlattr;
 struct dp_packet;
@@ -31,6 +33,10 @@  struct dp_packet_batch;
 typedef void (*odp_execute_cb)(void *dp, struct dp_packet_batch *batch,
                                const struct nlattr *action, bool may_steal);
 
+typedef void (*odp_update_drop_counter_cb) (void *aux_,
+                                           struct dpif_drop_counter *cntr,
+                                           int delta);
+
 /* Actions that need to be executed in the context of a datapath are handed
  * to 'dp_execute_action', if non-NULL.  Currently this is called only for
  * actions OVS_ACTION_ATTR_OUTPUT and OVS_ACTION_ATTR_USERSPACE so
@@ -38,5 +44,6 @@  typedef void (*odp_execute_cb)(void *dp, struct dp_packet_batch *batch,
 void odp_execute_actions(void *dp, struct dp_packet_batch *batch,
                          bool steal,
                          const struct nlattr *actions, size_t actions_len,
-                         odp_execute_cb dp_execute_action);
+                         odp_execute_cb dp_execute_action,
+                         odp_update_drop_counter_cb dp_update_drop_counter_cb);
 #endif
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 105ac80..ddb7984 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -124,6 +124,7 @@  odp_action_len(uint16_t type)
     case OVS_ACTION_ATTR_CLONE: return ATTR_LEN_VARIABLE;
     case OVS_ACTION_ATTR_PUSH_NSH: return ATTR_LEN_VARIABLE;
     case OVS_ACTION_ATTR_POP_NSH: return 0;
+    case OVS_ACTION_ATTR_DROP: return sizeof(struct ovs_action_drop);
 
     case OVS_ACTION_ATTR_UNSPEC:
     case __OVS_ACTION_ATTR_MAX:
@@ -338,6 +339,48 @@  format_nsh_key_mask(struct ds *ds, const struct ovs_key_nsh *key,
     }
 }
 
+static const char *
+dropreason_str(enum ovs_drop_reason reason)
+{
+    switch (reason) {
+    case OVS_DROP_REASON_OF_PIPELINE:
+        return "pipeline-drop";
+    case OVS_DROP_REASON_BRIDGE_NOT_FOUND:
+        return "bridge not found";
+    case OVS_DROP_REASON_RECURSION_TOO_DEEP:
+        return "recursion too deep";
+    case OVS_DROP_REASON_TOO_MANY_RESUBMITS:
+        return "too many resubmits";
+    case OVS_DROP_REASON_STACK_TOO_DEEP:
+        return "stack too deep";
+    case OVS_DROP_REASON_NO_RECIRCULATION_CONTEXT:
+        return "no recirculation context";
+    case OVS_DROP_REASON_RECIRCULATION_CONFLICT:
+        return "recirculation conflict";
+    case OVS_DROP_REASON_TOO_MANY_MPLS_LABELS:
+        return "too many mpls labels";
+    case OVS_DROP_REASON_INVALID_TUNNEL_METADATA:
+        return "invalid tunnel metadata";
+    case OVS_DROP_REASON_UNSUPPORTED_PACKET_TYPE:
+        return "unsupported packet type";
+    case OVS_DROP_REASON_CONGESTION:
+        return "ecn mismatch at tunnel decapsulation";
+    case OVS_DROP_REASON_FORWARDING_DISABLED:
+        return "forwarding disabled (stp/rstp)";
+    default:
+        return "unknown reason";
+    }
+    return "unknown reason";
+}
+
+static void
+format_odp_drop_action(struct ds *ds,
+                      const struct ovs_action_drop *drop_action)
+{
+    ds_put_format(ds, "drop:%s",
+                  dropreason_str(drop_action->drop_reason));
+}
+
 static void
 format_odp_push_nsh_action(struct ds *ds,
                            const struct nsh_hdr *nsh_hdr)
@@ -1172,6 +1215,9 @@  format_odp_action(struct ds *ds, const struct nlattr *a,
     case OVS_ACTION_ATTR_POP_NSH:
         ds_put_cstr(ds, "pop_nsh()");
         break;
+    case OVS_ACTION_ATTR_DROP:
+        format_odp_drop_action(ds, nl_attr_get(a));
+        break;
     case OVS_ACTION_ATTR_UNSPEC:
     case __OVS_ACTION_ATTR_MAX:
     default:
@@ -2410,8 +2456,13 @@  odp_actions_from_string(const char *s, const struct simap *port_names,
                         struct ofpbuf *actions)
 {
     size_t old_size;
+    struct ovs_action_drop drop_action;
 
-    if (!strcasecmp(s, "drop")) {
+    if ((!strcasecmp(s, "drop") ||
+        !strcasecmp(s, "drop:pipeline-drop"))) {
+        drop_action.drop_reason = OVS_DROP_REASON_OF_PIPELINE;
+        nl_msg_put_unspec(actions, OVS_ACTION_ATTR_DROP,
+                          &drop_action, sizeof drop_action);
         return 0;
     }
 
diff --git a/lib/ovs-atomic.h b/lib/ovs-atomic.h
index 4664eef..296d541 100644
--- a/lib/ovs-atomic.h
+++ b/lib/ovs-atomic.h
@@ -463,6 +463,26 @@  atomic_count_dec(atomic_count *count)
     return old;
 }
 
+static inline uint64_t
+atomic_ullong_inc(atomic_ullong *count)
+{
+    uint64_t old;
+
+    atomic_add_relaxed(count, 1, &old);
+
+    return old;
+}
+
+static inline uint64_t
+atomic_ullong_dec(atomic_ullong *count)
+{
+    uint64_t old;
+
+    atomic_sub_relaxed(count, 1, &old);
+
+    return old;
+}
+
 static inline unsigned int
 atomic_count_get(atomic_count *count)
 {
diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c
index 4d9fe78..33c5367 100644
--- a/ofproto/ofproto-dpif-ipfix.c
+++ b/ofproto/ofproto-dpif-ipfix.c
@@ -3015,6 +3015,7 @@  dpif_ipfix_read_actions(const struct flow *flow,
         case OVS_ACTION_ATTR_PUSH_NSH:
         case OVS_ACTION_ATTR_POP_NSH:
         case OVS_ACTION_ATTR_UNSPEC:
+        case OVS_ACTION_ATTR_DROP:
         case __OVS_ACTION_ATTR_MAX:
         default:
             break;
diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
index bbec30e..4114a8c 100644
--- a/ofproto/ofproto-dpif-sflow.c
+++ b/ofproto/ofproto-dpif-sflow.c
@@ -1221,6 +1221,7 @@  dpif_sflow_read_actions(const struct flow *flow,
         case OVS_ACTION_ATTR_PUSH_NSH:
         case OVS_ACTION_ATTR_POP_NSH:
 	case OVS_ACTION_ATTR_UNSPEC:
+        case OVS_ACTION_ATTR_DROP:
 	case __OVS_ACTION_ATTR_MAX:
 	default:
 	    break;
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index d26f201..5cafee0 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -1119,7 +1119,7 @@  upcall_receive(struct upcall *upcall, const struct dpif_backer *backer,
     return 0;
 }
 
-static void
+static enum xlate_error
 upcall_xlate(struct udpif *udpif, struct upcall *upcall,
              struct ofpbuf *odp_actions, struct flow_wildcards *wc)
 {
@@ -1209,6 +1209,7 @@  upcall_xlate(struct udpif *udpif, struct upcall *upcall,
     if (upcall->type == MISS_UPCALL) {
         upcall->ukey = ukey_create_from_upcall(upcall, wc);
     }
+    return xerr;
 }
 
 static void
@@ -1279,6 +1280,7 @@  upcall_cb(const struct dp_packet *packet, const struct flow *flow, ovs_u128 *ufi
 
     upcall.fitness = ODP_FIT_PERFECT;
     error = process_upcall(udpif, &upcall, actions, wc);
+
     if (error) {
         goto out;
     }
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index c7c9df5..a0ed7bc 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -445,10 +445,46 @@  const char *xlate_strerror(enum xlate_error error)
         return "Invalid tunnel metadata";
     case XLATE_UNSUPPORTED_PACKET_TYPE:
         return "Unsupported packet type";
+    case XLATE_CONGESTION_DROP:
+        return "CONGESTION DROP";
+    case XLATE_FORWARDING_DISABLED:
+        return "Forwarding is disabled";
+
     }
     return "Unknown error";
 }
 
+enum ovs_drop_reason  xlate_error_to_drop_reason(enum xlate_error error)
+{
+     switch (error) {
+        case XLATE_OK:
+            return OVS_DROP_REASON_OF_PIPELINE;
+        case XLATE_BRIDGE_NOT_FOUND:
+            return OVS_DROP_REASON_BRIDGE_NOT_FOUND;
+        case XLATE_RECURSION_TOO_DEEP:
+            return OVS_DROP_REASON_RECURSION_TOO_DEEP;
+        case XLATE_TOO_MANY_RESUBMITS:
+            return OVS_DROP_REASON_TOO_MANY_RESUBMITS;
+        case XLATE_STACK_TOO_DEEP:
+            return OVS_DROP_REASON_STACK_TOO_DEEP;
+        case XLATE_NO_RECIRCULATION_CONTEXT:
+            return OVS_DROP_REASON_NO_RECIRCULATION_CONTEXT;
+        case XLATE_RECIRCULATION_CONFLICT:
+            return OVS_DROP_REASON_RECIRCULATION_CONFLICT;
+        case XLATE_TOO_MANY_MPLS_LABELS:
+            return OVS_DROP_REASON_TOO_MANY_MPLS_LABELS;
+        case XLATE_INVALID_TUNNEL_METADATA:
+            return OVS_DROP_REASON_INVALID_TUNNEL_METADATA;
+        case XLATE_UNSUPPORTED_PACKET_TYPE:
+            return OVS_DROP_REASON_UNSUPPORTED_PACKET_TYPE;
+        case XLATE_CONGESTION_DROP:
+            return OVS_DROP_REASON_CONGESTION;
+        case XLATE_FORWARDING_DISABLED:
+            return OVS_DROP_REASON_MAX;
+     }
+     return OVS_DROP_REASON_OF_PIPELINE;
+}
+
 static void xlate_action_set(struct xlate_ctx *ctx);
 static void xlate_commit_actions(struct xlate_ctx *ctx);
 
@@ -5789,6 +5825,17 @@  put_ct_label(const struct flow *flow, struct ofpbuf *odp_actions,
 }
 
 static void
+put_drop_action(struct ofpbuf *odp_actions, enum xlate_error error)
+{
+    struct ovs_action_drop drop_action;
+
+    drop_action.drop_reason = xlate_error_to_drop_reason(error);
+    nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_DROP,
+                          &drop_action, sizeof drop_action);
+
+}
+
+static void
 put_ct_helper(struct xlate_ctx *ctx,
               struct ofpbuf *odp_actions, struct ofpact_conntrack *ofc)
 {
@@ -7246,6 +7293,10 @@  xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
         }
         size_t sample_actions_len = ctx.odp_actions->size;
 
+        if (!tnl_process_ecn(flow)) {
+            ctx.error = XLATE_CONGESTION_DROP;
+        }
+
         if (tnl_process_ecn(flow)
             && (!in_port || may_receive(in_port, &ctx))) {
             const struct ofpact *ofpacts;
@@ -7278,6 +7329,7 @@  xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
                 ctx.odp_actions->size = sample_actions_len;
                 ctx_cancel_freeze(&ctx);
                 ofpbuf_clear(&ctx.action_set);
+                ctx.error = XLATE_FORWARDING_DISABLED;
             }
 
             if (!ctx.freezing) {
@@ -7385,6 +7437,18 @@  exit:
             ofpbuf_clear(xin->odp_actions);
         }
     }
+
+    /*
+     * If we are going to install "drop" action, check whether
+     * datapath supports explicit "drop"action. If datapath
+     * supports explicit "drop"action then install the "drop"
+     * action containing the drop reason.
+     */
+    if (xin->odp_actions && !xin->odp_actions->size &&
+         ovs_explicit_drop_action_supported(ctx.xbridge->ofproto)) {
+        put_drop_action(xin->odp_actions, ctx.error);
+    }
+
     return ctx.error;
 }
 
diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h
index 2cbb3c9..e1ce027 100644
--- a/ofproto/ofproto-dpif-xlate.h
+++ b/ofproto/ofproto-dpif-xlate.h
@@ -216,12 +216,16 @@  enum xlate_error {
     XLATE_TOO_MANY_MPLS_LABELS,
     XLATE_INVALID_TUNNEL_METADATA,
     XLATE_UNSUPPORTED_PACKET_TYPE,
+    XLATE_CONGESTION_DROP,
+    XLATE_FORWARDING_DISABLED,
 };
 
 const char *xlate_strerror(enum xlate_error error);
 
 enum xlate_error xlate_actions(struct xlate_in *, struct xlate_out *);
 
+uint32_t xlate_error_to_drop_reason(enum xlate_error error);
+
 void xlate_in_init(struct xlate_in *, struct ofproto_dpif *, ovs_version_t,
                    const struct flow *, ofp_port_t in_port, struct rule_dpif *,
                    uint16_t tcp_flags, const struct dp_packet *packet,
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 1ed82d0..afd0ebd 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -828,6 +828,12 @@  ovs_native_tunneling_is_on(struct ofproto_dpif *ofproto)
         && atomic_count_get(&ofproto->backer->tnl_count);
 }
 
+bool
+ovs_explicit_drop_action_supported(struct ofproto_dpif *ofproto)
+{
+    return ofproto->backer->rt_support.explicit_drop_action;
+}
+
 /* Tests whether 'backer''s datapath supports recirculation.  Only newer
  * datapaths support OVS_KEY_ATTR_RECIRC_ID in keys.  We need to disable some
  * features on older datapaths that don't support this feature.
@@ -1353,6 +1359,10 @@  check_support(struct dpif_backer *backer)
     backer->rt_support.sample_nesting = check_max_sample_nesting(backer);
     backer->rt_support.ct_eventmask = check_ct_eventmask(backer);
     backer->rt_support.ct_clear = check_ct_clear(backer);
+    backer->rt_support.explicit_drop_action =
+        dpif_supports_explicit_drop_action(backer->dpif);
+
+
 
     /* Flow fields. */
     backer->rt_support.odp.ct_state = check_ct_state(backer);
@@ -5516,6 +5526,76 @@  ofproto_unixctl_dpif_set_dp_features(struct unixctl_conn *conn,
 }
 
 static void
+ofproto_unixctl_dpif_show_drop_stats(struct unixctl_conn *conn,
+                                int argc OVS_UNUSED, const char *argv[],
+                                void *aux OVS_UNUSED)
+{
+    struct ds ds = DS_EMPTY_INITIALIZER;
+    int error, i;
+    const struct shash_node **backers;
+    struct dpif_backer *backer;
+    bool detail = false;
+
+    for (int i = 1; i < argc; i++) {
+        if (!strcmp(argv[i], "--detail")) {
+            detail = true;
+        }
+    }
+
+    ds_init(&ds);
+    backers = shash_sort(&all_dpif_backers);
+    for (i = 0; i < shash_count(&all_dpif_backers); i++) {
+        backer = (struct dpif_backer *)backers[i]->data;
+        ds_put_format(&ds, "%s:\n", backer->type);
+        error = dpif_show_drop_stats_support(backer->dpif,
+                                             detail, &ds);
+        if (error) {
+            break;
+        }
+    }
+    if (error) {
+        ds_clear(&ds);
+        ds_put_format(&ds, "dpif/show-drop-stats failed");
+        unixctl_command_reply_error(conn, ds_cstr(&ds));
+    } else {
+        unixctl_command_reply(conn, ds_cstr(&ds));
+    }
+    free(backers);
+    ds_destroy(&ds);
+}
+
+
+static void
+ofproto_unixctl_dpif_clear_drop_stats(struct unixctl_conn *conn,
+                                int argc OVS_UNUSED, const char *argv[],
+                                void *aux OVS_UNUSED)
+{
+    struct ds ds = DS_EMPTY_INITIALIZER;
+    int error, i;
+    const struct shash_node **backers;
+    struct dpif_backer *backer;
+
+    ds_init(&ds);
+    backers = shash_sort(&all_dpif_backers);
+    for (i = 0; i < shash_count(&all_dpif_backers); i++) {
+        backer = (struct dpif_backer *)backers[i]->data;
+        error = dpif_clear_dp_drop_stats(backer->dpif);
+        if (error) {
+            break;
+        }
+    }
+    if (error) {
+        ds_clear(&ds);
+        ds_put_format(&ds, "dpif/clear-drop-stats failed");
+        unixctl_command_reply_error(conn, ds_cstr(&ds));
+    } else {
+        unixctl_command_reply(conn, ds_cstr(&ds));
+    }
+    free(backers);
+    ds_destroy(&ds);
+}
+
+static void
 ofproto_unixctl_init(void)
 {
     static bool registered;
@@ -5542,6 +5622,10 @@  ofproto_unixctl_init(void)
                              ofproto_unixctl_dpif_dump_flows, NULL);
     unixctl_command_register("dpif/set-dp-features", "bridge", 1, 3 ,
                              ofproto_unixctl_dpif_set_dp_features, NULL);
+    unixctl_command_register("dpif/show-drop-stats", "[--detail]", 0, 1,
+                             ofproto_unixctl_dpif_show_drop_stats, NULL);
+    unixctl_command_register("dpif/clear-drop-stats", "", 0, 0,
+                              ofproto_unixctl_dpif_clear_drop_stats, NULL);
 }
 

 static odp_port_t
diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
index 47bf7f9..c05cf1b 100644
--- a/ofproto/ofproto-dpif.h
+++ b/ofproto/ofproto-dpif.h
@@ -105,6 +105,7 @@  struct rule_dpif *rule_dpif_lookup_from_table(struct ofproto_dpif *,
                                               bool honor_table_miss,
                                               struct xlate_cache *);
 
+
 void rule_dpif_credit_stats(struct rule_dpif *,
                             const struct dpif_flow_stats *);
 
@@ -175,7 +176,10 @@  struct group_dpif *group_dpif_lookup(struct ofproto_dpif *,
     DPIF_SUPPORT_FIELD(bool, ct_eventmask, "Conntrack eventmask")           \
                                                                             \
     /* True if the datapath supports OVS_ACTION_ATTR_CT_CLEAR action. */    \
-    DPIF_SUPPORT_FIELD(bool, ct_clear, "Conntrack clear")
+    DPIF_SUPPORT_FIELD(bool, ct_clear, "Conntrack clear")                   \
+                                                                            \
+    /* True if the datapath supports explicit drop action. */               \
+    DPIF_SUPPORT_FIELD(bool, explicit_drop_action, "Explicit Drop action")
 
 /* Stores the various features which the corresponding backer supports. */
 struct dpif_backer_support {
@@ -344,4 +348,6 @@  int ofproto_dpif_delete_internal_flow(struct ofproto_dpif *, struct match *,
 
 bool ovs_native_tunneling_is_on(struct ofproto_dpif *);
 
+bool ovs_explicit_drop_action_supported(struct ofproto_dpif *);
+
 #endif /* ofproto-dpif.h */
diff --git a/tests/bundle.at b/tests/bundle.at
index 40dfbea..deb54ba 100644
--- a/tests/bundle.at
+++ b/tests/bundle.at
@@ -241,7 +241,7 @@  AT_CHECK([tail -1 stdout], [0],
 AT_CHECK([ovs-ofctl mod-port br0 p2 down])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=LOCAL,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: drop
+  [Datapath actions: drop:pipeline-drop
 ])
 AT_CHECK([ovs-ofctl mod-port br0 p1 up])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=LOCAL,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06'], [0], [stdout])
diff --git a/tests/classifier.at b/tests/classifier.at
index 2362948..3b276d2 100644
--- a/tests/classifier.at
+++ b/tests/classifier.at
@@ -50,12 +50,12 @@  Datapath actions: 1
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=11.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
   [Megaflow: recirc_id=0,eth,ip,in_port=1,nw_dst=11.0.0.0/8,nw_frag=no
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
   [Megaflow: recirc_id=0,eth,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=80
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=79'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
@@ -88,7 +88,7 @@  AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
   [Megaflow: recirc_id=0,eth,tcp,in_port=1,nw_dst=192.168.0.0/16,nw_frag=no
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-vsctl set Flow_Table t0 prefixes=ipv6_label], [0])
@@ -103,7 +103,7 @@  AT_CHECK([ovs-vsctl set Flow_Table t0 prefixes=nw_dst], [0])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
   [Megaflow: recirc_id=0,eth,tcp,in_port=1,nw_dst=192.168.0.0/16,nw_frag=no
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=2,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
@@ -113,7 +113,7 @@  Datapath actions: 1
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
   [Megaflow: recirc_id=0,eth,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=80
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=79'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 4857eaf..71463fe 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -532,7 +532,7 @@  AT_CHECK([ovs-ofctl -O OpenFlow12 add-group br0 'group_id=1234,type=ff,bucket=wa
 AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 'ip actions=write_actions(group:1234)'])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: drop
+  [Datapath actions: drop:pipeline-drop
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -3305,51 +3305,51 @@  dnl Each of these specifies an in_port by number, a VLAN VID (or "none"),
 dnl a VLAN PCP (used if the VID isn't "none") and the expected set of datapath
 dnl actions.
 for tuple in \
-        "100 none 0 drop" \
-        "100 0    0 drop" \
-        "100 0    1 drop" \
+        "100 none 0 drop:pipeline-drop" \
+        "100 0    0 drop:pipeline-drop" \
+        "100 0    1 drop:pipeline-drop" \
         "100 10   0 1,5,6,7,8,pop_vlan,2,9" \
         "100 10   1 1,5,6,7,8,pop_vlan,2,9" \
         "100 11   0 5,7" \
         "100 11   1 5,7" \
         "100 12   0 1,5,6,pop_vlan,3,4,7,8,11,12" \
         "100 12   1 1,5,6,pop_vlan,4,7,11,push_vlan(vid=0,pcp=1),3,8,12" \
-        "1  none 0 drop" \
-        "1  0    0 drop" \
-        "1  0    1 drop" \
+        "1  none 0 drop:pipeline-drop" \
+        "1  0    0 drop:pipeline-drop" \
+        "1  0    1 drop:pipeline-drop" \
         "1  10   0 5,6,7,8,100,pop_vlan,2,9" \
         "1  10   1 5,6,7,8,100,pop_vlan,2,9" \
-        "1  11   0 drop" \
-        "1  11   1 drop" \
+        "1  11   0 drop:pipeline-drop" \
+        "1  11   1 drop:pipeline-drop" \
         "1  12   0 5,6,100,pop_vlan,3,4,7,8,11,12" \
         "1  12   1 5,6,100,pop_vlan,4,7,11,push_vlan(vid=0,pcp=1),3,8,12" \
         "2  none 0 9,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
         "2  0    0 pop_vlan,9,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
         "2  0    1 pop_vlan,9,push_vlan(vid=10,pcp=1),1,5,6,7,8,100" \
-        "2  10   0 drop" \
-        "2  10   1 drop" \
-        "2  11   0 drop" \
-        "2  11   1 drop" \
-        "2  12   0 drop" \
-        "2  12   1 drop" \
+        "2  10   0 drop:pipeline-drop" \
+        "2  10   1 drop:pipeline-drop" \
+        "2  11   0 drop:pipeline-drop" \
+        "2  11   1 drop:pipeline-drop" \
+        "2  12   0 drop:pipeline-drop" \
+        "2  12   1 drop:pipeline-drop" \
         "3  none 0 4,7,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
         "3  0    0 pop_vlan,4,7,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
         "3  0    1 8,12,pop_vlan,4,7,11,push_vlan(vid=12,pcp=1),1,5,6,100" \
-        "3  10   0 drop" \
-        "3  10   1 drop" \
-        "3  11   0 drop" \
-        "3  11   1 drop" \
-        "3  12   0 drop" \
-        "3  12   1 drop" \
+        "3  10   0 drop:pipeline-drop" \
+        "3  10   1 drop:pipeline-drop" \
+        "3  11   0 drop:pipeline-drop" \
+        "3  11   1 drop:pipeline-drop" \
+        "3  12   0 drop:pipeline-drop" \
+        "3  12   1 drop:pipeline-drop" \
         "4  none 0 3,7,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
         "4  0    0 pop_vlan,3,7,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
         "4  0    1 3,8,12,pop_vlan,7,11,push_vlan(vid=12,pcp=1),1,5,6,100" \
-        "4  10   0 drop" \
-        "4  10   1 drop" \
-        "4  11   0 drop" \
-        "4  11   1 drop" \
-        "4  12   0 drop" \
-        "4  12   1 drop" \
+        "4  10   0 drop:pipeline-drop" \
+        "4  10   1 drop:pipeline-drop" \
+        "4  11   0 drop:pipeline-drop" \
+        "4  11   1 drop:pipeline-drop" \
+        "4  12   0 drop:pipeline-drop" \
+        "4  12   1 drop:pipeline-drop" \
         "5  none 0 2,9,push_vlan(vid=10,pcp=0),1,6,7,8,100" \
         "5  0    0 pop_vlan,2,9,push_vlan(vid=10,pcp=0),1,6,7,8,100" \
         "5  0    1 pop_vlan,2,9,push_vlan(vid=10,pcp=1),1,6,7,8,100" \
@@ -3364,8 +3364,8 @@  for tuple in \
         "6  0    1 pop_vlan,2,9,push_vlan(vid=10,pcp=1),1,5,7,8,100" \
         "6  10   0 1,5,7,8,100,pop_vlan,2,9" \
         "6  10   1 1,5,7,8,100,pop_vlan,2,9" \
-        "6  11   0 drop" \
-        "6  11   1 drop" \
+        "6  11   0 drop:pipeline-drop" \
+        "6  11   1 drop:pipeline-drop" \
         "6  12   0 1,5,100,pop_vlan,3,4,7,8,11,12" \
         "6  12   1 1,5,100,pop_vlan,4,7,11,push_vlan(vid=0,pcp=1),3,8,12" \
         "7  none 0 3,4,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
@@ -3382,16 +3382,16 @@  for tuple in \
         "8  0    1 3,12,pop_vlan,4,7,11,push_vlan(vid=12,pcp=1),1,5,6,100" \
         "8  10   0 1,5,6,7,100,pop_vlan,2,9" \
         "8  10   1 1,5,6,7,100,pop_vlan,2,9" \
-        "8  11   0 drop" \
-        "8  11   1 drop" \
+        "8  11   0 drop:pipeline-drop" \
+        "8  11   1 drop:pipeline-drop" \
         "8  12   0 1,5,6,100,pop_vlan,3,4,7,11,12" \
         "8  12   1 1,5,6,100,pop_vlan,4,7,11,push_vlan(vid=0,pcp=1),3,12" \
         "9  none 0 2,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
         "9  10   0 10,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
         "9  11   0 push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
-        "10 none 0 drop" \
-        "10 0    0 drop" \
-        "10 11   0 drop" \
+        "10 none 0 drop:pipeline-drop" \
+        "10 0    0 drop:pipeline-drop" \
+        "10 11   0 drop:pipeline-drop" \
         "10 12   0 9,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
         "11 10   0 7,8,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
         "11 10   1 7,8,12,push_vlan(vid=12,pcp=0),1,5,6,100"
@@ -4131,11 +4131,11 @@  no_flow="$base_flow,frag=no),tcp(src=12345,dst=80)"
 first_flow="$base_flow,frag=first),tcp(src=12345,dst=80)"
 later_flow="$base_flow,frag=later)"
 
-    # mode    no  first  later
+    # mode    no     first                later
 for tuple in \
-    'normal    1     5      6' \
-    'drop      1  drop   drop' \
-    'nx-match  1     2      6'
+    'normal    1     5                    6' \
+    'drop      1     drop:pipeline-drop   drop:pipeline-drop' \
+    'nx-match  1     2                    6'
 do
   set $tuple
   mode=$1
@@ -4213,8 +4213,8 @@  done
 AT_CHECK([ovs-appctl dpctl/dump-flows], [0], [dnl
 flow-dump from non-dpdk interfaces:
 recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=no),tcp(dst=80), packets:0, bytes:0, used:never, actions:set(tcp(dst=81)),1
-recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=first), packets:0, bytes:0, used:never, actions:drop
-recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=later), packets:0, bytes:0, used:never, actions:drop
+recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=first), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
+recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=later), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
 ])
 
 mode=nx-match
@@ -5492,7 +5492,7 @@  bridge("br0")
 
 Final flow: <cleared>
 Megaflow: <cleared>
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 
 dnl Now, try again without megaflows:
@@ -5513,7 +5513,7 @@  bridge("br0")
 
 Final flow: <cleared>
 Megaflow: <cleared>
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 
 OVS_VSWITCHD_STOP
@@ -6807,7 +6807,7 @@  for i in `seq 1 3`; do
 done
 AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/.*\(packets:\)/\1/' | sed 's/used:[[0-9]].[[0-9]]*s/used:0.001s/'], [0], [dnl
 flow-dump from non-dpdk interfaces:
-packets:2, bytes:68, used:0.001s, actions:drop
+packets:2, bytes:68, used:0.001s, actions:drop:pipeline-drop
 ])
 
 OVS_VSWITCHD_STOP(["/sending to collector failed/d"])
@@ -6899,7 +6899,7 @@  for i in `seq 1 3`; do
 done
 AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/.*\(packets:\)/\1/' | sed 's/used:[[0-9]].[[0-9]]*s/used:0.001s/'], [0], [dnl
 flow-dump from non-dpdk interfaces:
-packets:2, bytes:68, used:0.001s, actions:drop
+packets:2, bytes:68, used:0.001s, actions:drop:pipeline-drop
 ])
 
 OVS_VSWITCHD_STOP(["/sending to collector failed/d
@@ -7573,21 +7573,21 @@  AT_CHECK([ovs-appctl netdev-dummy/receive p2 'in_port(2),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p3 'in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 ovs-appctl revalidator/wait
 AT_CHECK([ovs-appctl dpif/dump-flows br0 | strip_ufid | strip_used | sort], [0], [dnl
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
-recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
+recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-appctl dpif/dump-flows br1 | strip_ufid | strip_used | sort], [0], [dnl
-recirc_id(0),in_port(3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
+recirc_id(0),in_port(3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-appctl dpif/dump-flows -m br0 | strip_ufid | strip_used | sort], [0], [dnl
-skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
-skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p2),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=0/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
+skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
+skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p2),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=0/0,code=0/0), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-appctl dpif/dump-flows -m br1 | strip_ufid | strip_used | sort], [0], [dnl
-skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p3),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
+skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p3),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
 ])
 
 OVS_VSWITCHD_STOP
@@ -7610,7 +7610,7 @@  m4_define([OFPROTO_DPIF_GET_FLOW],
 
    UFID=`sed -n 's/\(ufid:[[-0-9a-fA-F]]*\).*/\1/p' stdout`
    AT_CHECK([ovs-appctl dpctl/get-flow $UFID], [0], [dnl
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
 ])
 
    OVS_VSWITCHD_STOP
@@ -8340,7 +8340,7 @@  m4_define([OFPROTO_DPIF_MEGAFLOW_DISABLED],
    add_${func}of_ports br0 1 2
    AT_DATA([flows.txt], [dnl
 table=0 in_port=1,ip,nw_dst=10.0.0.1 actions=output(2)
-table=0 in_port=1,ip,nw_dst=10.0.0.3 actions=drop
+table=0 in_port=1,ip,nw_dst=10.0.0.3 actions=drop:pipeline-drop
 ])
    AT_CHECK([ovs-appctl upcall/disable-megaflows], [0], [megaflows disabled
 ], [])
@@ -8358,11 +8358,11 @@  table=0 in_port=1,ip,nw_dst=10.0.0.3 actions=drop
    sleep 1
    AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_install | strip_used], [0], [dnl
 skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-dnat),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), actions:2
-skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-dnat),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), actions:drop
+skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-dnat),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), actions:drop:pipeline-drop
 ])
    AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_dump | grep 'packets:3'], [0], [dnl
 skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:318, used:0.0s, actions:2
-skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:318, used:0.0s, actions:drop
+skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:318, used:0.0s, actions:drop:pipeline-drop
 ])
    OVS_VSWITCHD_STOP
    AT_CLEANUP])
@@ -9092,7 +9092,7 @@  for i in 1 2 3; do
 done
 
 AT_CHECK([ovs-appctl dpif/dump-flows br0 | strip_ufid | strip_used | sort], [0], [dnl
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), packets:5, bytes:70, used:0.0s, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), packets:5, bytes:70, used:0.0s, actions:drop:pipeline-drop
 ])
 
 # Add a flow that matches the non-presence of a vlan tag, and check
@@ -9121,16 +9121,16 @@  done
 
 AT_CHECK([ovs-appctl dpif/dump-flows br0 | strip_ufid | strip_used | sort], [0], [dnl
 recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), packets:8, bytes:112, used:0.0s, actions:100
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)), packets:2, bytes:36, used:0.0s, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)), packets:2, bytes:36, used:0.0s, actions:drop:pipeline-drop
 ])
 
 # Check that the new flow matches the CFI bit, while both vid and pcp
 # are wildcarded.
 AT_CHECK([grep '\(modify\)\|\(flow_add\)' ovs-vswitchd.log | strip_ufid ], [0], [dnl
 dpif_netdev|DBG|flow_add: recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), actions:100
-dpif|DBG|dummy@ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234)
+dpif|DBG|dummy@ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234), actions:drop:pipeline-drop
 dpif|DBG|dummy@ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234), actions:100
-dpif_netdev|DBG|flow_add: recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)), actions:drop
+dpif_netdev|DBG|flow_add: recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)), actions:drop:pipeline-drop
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -9162,7 +9162,7 @@  dnl
 table=0,priority=100,arp,action=normal
 table=0,priority=10,in_port=1,ip,action=set_field:1->reg4,set_field:1->reg3,ct(zone=NXM_NX_REG4[[0..15]],table=1)
 table=0,priority=10,in_port=2,ip,action=set_field:1->reg4,set_field:2->reg3,ct(zone=NXM_NX_REG4[[0..15]],table=1)
-table=0,priority=1,action=drop
+table=0,priority=1,action=drop:pipeline-drop
 dnl
 dnl Pass tracked traffic through ACL, drop everything else.
 dnl Non-REPLY/RELATED packets get the ACL lookup with the packet headers
@@ -9183,7 +9183,7 @@  dnl
 dnl Related packet (CT ACL in the direction of the master connection.)
 table=1 ip, ct_state=+rel+trk-inv, action=move:NXM_NX_CT_MARK[[]]->NXM_NX_REG0[[]],resubmit(,3,ct),goto_table:4
 dnl Drop everything else.
-table=1 priority=0, action=drop
+table=1 priority=0, action=drop:pipeline-drop
 dnl
 dnl "ACL table"
 dnl
@@ -9209,7 +9209,7 @@  dnl
 dnl Handle stateful (reg2=1) / stateless (reg2=2) accepts and drops (reg2=0)
 dnl
 dnl Drop all non-accepted packets.
-table=5 reg2=0 priority=1000 action=drop
+table=5 reg2=0 priority=1000 action=drop:pipeline-drop
 dnl Commit new non-related IP connections.
 table=5 priority=10 reg2=1 ct_state=+new-rel, ip, action=ct(zone=NXM_NX_REG4[[0..15]],commit,exec(move:NXM_NX_REG3[[0..31]]->NXM_NX_CT_MARK[[0..31]],move:NXM_NX_REG1[[0..31]]->NXM_NX_CT_LABEL[[96..127]])),goto_table:6
 dnl Commit new related connections in either direction, which inherit the mark
@@ -9287,12 +9287,12 @@  dnl
 table=0,priority=100,arp,action=normal
 table=0,priority=10,in_port=1,udp,action=ct(commit),controller
 table=0,priority=10,in_port=2,udp,action=ct(table=1)
-table=0,priority=1,action=drop
+table=0,priority=1,action=drop:pipeline-drop
 dnl
 dnl Table 1
 dnl
 table=1,priority=10,in_port=2,ct_state=+est,udp,action=ct(force,commit),controller
-table=1,priority=1,action=drop
+table=1,priority=1,action=drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
@@ -9369,11 +9369,11 @@  dnl
 table=0,priority=100,arp,action=normal
 table=0,priority=10,in_port=1,udp6,action=ct(commit,zone=0),controller
 table=0,priority=10,in_port=2,udp6,action=ct(table=1,zone=0)
-table=0,priority=1,action=drop
+table=0,priority=1,action=drop:pipeline-drop
 dnl Table 1
 dnl
 table=1,priority=10,in_port=2,ct_state=+trk+est-new,udp6,action=controller
-table=1,priority=1,action=drop
+table=1,priority=1,action=drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
@@ -9428,12 +9428,12 @@  dnl
 table=0,priority=100,arp,action=normal
 table=0,priority=10,in_port=1,udp,action=ct(commit,zone=0),2
 table=0,priority=10,in_port=2,udp,action=ct(table=1,zone=0)
-table=0,priority=1,action=drop
+table=0,priority=1,action=drop:pipeline-drop
 dnl
 dnl Table 1
 dnl
 table=1,priority=10,in_port=2,ct_state=+trk+est-new,udp,action=1
-table=1,priority=1,action=drop
+table=1,priority=1,action=drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
@@ -9455,7 +9455,7 @@  AT_CHECK([ovs-appctl netdev-dummy/receive p2 'in_port(2),eth(src=50:54:00:00:00:
 
 
 AT_CHECK([cat ovs-vswitchd.log | strip_ufid | filter_flow_install], [0], [dnl
-ct_state(+new-est+trk),recirc_id(0x1),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions:drop
+ct_state(+new-est+trk),recirc_id(0x1),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions:drop:pipeline-drop
 ct_state(-new+est+trk),recirc_id(0x1),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=no), actions:1
 recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=no), actions:ct(commit),2
 recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=no), actions:ct,recirc(0x1)
@@ -9478,12 +9478,12 @@  dnl
 table=0,priority=100,arp,action=normal
 table=0,priority=10,in_port=1,udp,action=ct(commit,zone=0)
 table=0,priority=10,in_port=2,udp,action=ct(table=1,zone=0)
-table=0,priority=1,action=drop
+table=0,priority=1,action=drop:pipeline-drop
 dnl
 dnl Table 1
 dnl
 table=1,priority=10,in_port=2,ct_state=+trk+est-new,udp,action=controller
-table=1,priority=1,action=drop
+table=1,priority=1,action=drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
@@ -9568,13 +9568,13 @@  table=0,priority=10,in_port=1,udp,action=ct(commit,zone=0),controller
 table=0,priority=10,in_port=2,udp,action=ct(table=1,zone=0)
 table=0,priority=10,in_port=3,udp,action=ct(commit,zone=1),controller
 table=0,priority=10,in_port=4,udp,action=ct(table=1,zone=1)
-table=0,priority=1,action=drop
+table=0,priority=1,action=drop:pipeline-drop
 dnl
 dnl Table 1
 dnl
 table=1,priority=10,in_port=2,ct_state=+trk+est-new,udp,action=controller
 table=1,priority=10,in_port=4,ct_state=+trk+est-new,udp,action=controller
-table=1,priority=1,action=drop
+table=1,priority=1,action=drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
@@ -9628,13 +9628,13 @@  dnl Table 0
 dnl
 table=0,priority=100,arp,action=normal
 table=0,priority=10,udp,action=ct(table=1,zone=0)
-table=0,priority=1,action=drop
+table=0,priority=1,action=drop:pipeline-drop
 dnl
 dnl Table 1
 dnl
 table=1,priority=10,in_port=1,ct_state=+trk+new,udp,action=ct(commit,zone=0),controller
 table=1,priority=10,ct_state=+trk+est,udp,action=controller
-table=1,priority=1,action=drop
+table=1,priority=1,action=drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
@@ -9677,13 +9677,13 @@  dnl
 table=0,priority=100,arp,action=normal
 table=0,priority=10,ip,in_port=1,udp,action=ct(commit,table=1)
 table=0,priority=10,ip,in_port=2,action=ct(table=1)
-table=0,priority=1,action=drop
+table=0,priority=1,action=drop:pipeline-drop
 dnl
 dnl Table 1
 dnl
 table=1,priority=10,in_port=1,ct_state=+trk,action=controller
 table=1,priority=10,in_port=2,ct_state=+trk-inv-new,action=controller
-table=1,priority=1,action=drop
+table=1,priority=1,action=drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
@@ -9731,12 +9731,12 @@  table=0,ip,in_port=1,udp,tp_src=1,action=ct(commit,exec(set_field:1->ct_mark)),c
 table=0,ip,in_port=1,udp,tp_src=3,action=ct(commit,exec(set_field:3->ct_mark)),controller
 table=0,ip,in_port=1,udp,tp_src=5,action=ct(commit,exec(set_field:5->ct_mark)),controller
 table=0,ip,in_port=2,actions=ct(table=1)
-table=0,priority=0,action=drop
+table=0,priority=0,action=drop:pipeline-drop
 dnl
 dnl Table 1
 dnl
 table=1,priority=100,ct_state=+trk+rpl,ct_mark=0/4,actions=controller
-table=1,priority=1,action=drop
+table=1,priority=1,action=drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
@@ -9795,7 +9795,7 @@  dnl
 dnl Table 1
 dnl
 table=1,priority=10,ct_state=+trk+rpl,actions=controller
-table=1,priority=1,action=drop
+table=1,priority=1,action=drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
@@ -9847,12 +9847,12 @@  dnl
 table=0,arp,action=normal
 table=0,ip,in_port=1,udp,tp_src=1,action=ct(commit,exec(set_field:1->ct_label)),2
 table=0,ip,in_port=2,actions=ct(table=1)
-table=0,priority=0,action=drop
+table=0,priority=0,action=drop:pipeline-drop
 dnl
 dnl Table 1
 dnl
 table=1,priority=10,ct_state=+trk+rpl,ct_label=0x1,actions=1
-table=1,priority=1,action=drop
+table=1,priority=1,action=drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
@@ -9910,7 +9910,7 @@  dnl
 table=0,priority=100,arp,action=normal
 table=0,priority=10,in_port=1,ip,action=ct(commit,table=1)
 table=0,priority=10,in_port=2,ip,action=ct(table=1)
-table=0,priority=1,action=drop
+table=0,priority=1,action=drop:pipeline-drop
 dnl
 dnl Table 1
 dnl
@@ -9920,7 +9920,7 @@  table=1,priority=100,cookie=0x1,in_port=1,ip,ct_state=+trk+new-inv-rpl,action=2
 table=1,priority=100,in_port=1,ip,ct_state=+trk-new-inv-rpl,action=2
 dnl
 table=1,priority=100,in_port=2,ip,ct_state=+trk+est+rpl-new-inv,action=1
-table=1,ip,ct_state=+trk+inv,action=drop
+table=1,ip,ct_state=+trk+inv,action=drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
@@ -10142,7 +10142,7 @@  AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=2,udp'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: drop
+  [Datapath actions: drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,udp'], [0], [stdout])
@@ -10234,11 +10234,11 @@  AT_CHECK([ovs-appctl netdev-dummy/receive p1 'recirc_id(0),in_port(1),eth_type(0
 ovs-appctl time/warp 5000
 
 AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_install | strip_used], [0], [dnl
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=later), actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=later), actions:drop:pipeline-drop
 ])
 
 dnl Change the flow table.  This will trigger revalidation of all the flows.
-AT_CHECK([ovs-ofctl add-flow br0 priority=5,in_port=1,action=drop])
+AT_CHECK([ovs-ofctl add-flow br0 priority=5,in_port=1,action=drop:pipeline-drop])
 AT_CHECK([ovs-appctl revalidator/wait], [0])
 
 dnl We don't want revalidators to delete any flow.  If the flow has been
diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
index e1fc829..590af85 100644
--- a/tests/ovs-ofctl.at
+++ b/tests/ovs-ofctl.at
@@ -165,13 +165,13 @@  do
     echo
     echo "### test case: '$1' should have usable protocols '$2'"
     if test "$2" = none; then
-      AT_CHECK([ovs-ofctl parse-flow "$1,actions=drop"], [1],
+      AT_CHECK([ovs-ofctl parse-flow "$1,actions=drop:pipeline-drop"], [1],
                [dnl
 ],
                [ovs-ofctl: actions are invalid with specified match (OFPBAC_MATCH_INCONSISTENT)
 ])
     else
-      AT_CHECK_UNQUOTED([ovs-ofctl parse-flow "$1,actions=drop" | sed 1q], [0],
+      AT_CHECK_UNQUOTED([ovs-ofctl parse-flow "$1,actions=drop:pipeline-drop" | sed 1q], [0],
                         [usable protocols: $2
 ])
     fi
@@ -368,7 +368,7 @@  do
     else
         prereq= field=$1 value=$2
     fi
-    AT_CHECK_UNQUOTED([ovs-ofctl parse-flow "$prereq$field=$value,actions=drop"], [1], [],
+    AT_CHECK_UNQUOTED([ovs-ofctl parse-flow "$prereq$field=$value,actions=drop:pipeline-drop"], [1], [],
 [ovs-ofctl: $value: invalid mask for field $field
 ])
 done
@@ -2601,10 +2601,10 @@  dnl Check that "-F openflow10" rejects a flow_mod with unsupported features,
 dnl such as tunnels and metadata.
 AT_SETUP([ovs-ofctl -F option and NXM features])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-ofctl -F openflow10 add-flow br0 tun_id=123,actions=drop],
+AT_CHECK([ovs-ofctl -F openflow10 add-flow br0 tun_id=123,actions=drop:pipeline-drop],
   [1], [], [ovs-ofctl: none of the usable flow formats (NXM,OXM) is among the allowed flow formats (OpenFlow10)
 ])
-AT_CHECK([ovs-ofctl -F openflow10 add-flow br0 metadata=123,actions=drop],
+AT_CHECK([ovs-ofctl -F openflow10 add-flow br0 metadata=123,actions=drop:pipeline-drop],
   [1], [], [ovs-ofctl: none of the usable flow formats (NXM,OXM,OpenFlow11) is among the allowed flow formats (OpenFlow10)
 ])
 OVS_VSWITCHD_STOP
@@ -2778,18 +2778,18 @@  OVS_VSWITCHD_START([\
 AT_CHECK([ovs-ofctl add-flow br0 in_port=xyzzy,actions=x-y,abc123])
 
 # reallyverylongportname is accepted truncated, but not in full.
-AT_CHECK([ovs-ofctl add-flow br0 in_port=reallyverylongp,actions=drop])
-AT_CHECK([ovs-ofctl add-flow br0 in_port=reallyverylongportname,actions=drop],
+AT_CHECK([ovs-ofctl add-flow br0 in_port=reallyverylongp,actions=drop:pipeline-drop])
+AT_CHECK([ovs-ofctl add-flow br0 in_port=reallyverylongportname,actions=drop:pipeline-drop],
   [1], [], [ovs-ofctl: reallyverylongportname: invalid or unknown port for in_port
 ])
 
 # conflictinglongportname1 and 2 can't be accepted even truncated, since
 # they conflict when truncated.
-AT_CHECK([ovs-ofctl add-flow br0 in_port=conflictinglongportname1,actions=drop], [1], [], [ovs-ofctl: conflictinglongportname1: invalid or unknown port for in_port
+AT_CHECK([ovs-ofctl add-flow br0 in_port=conflictinglongportname1,actions=drop:pipeline-drop], [1], [], [ovs-ofctl: conflictinglongportname1: invalid or unknown port for in_port
 ])
-AT_CHECK([ovs-ofctl add-flow br0 in_port=conflictinglongportname2,actions=drop], [1], [], [ovs-ofctl: conflictinglongportname2: invalid or unknown port for in_port
+AT_CHECK([ovs-ofctl add-flow br0 in_port=conflictinglongportname2,actions=drop:pipeline-drop], [1], [], [ovs-ofctl: conflictinglongportname2: invalid or unknown port for in_port
 ])
-AT_CHECK([ovs-ofctl add-flow br0 in_port=conflictinglong,actions=drop], [1], [], [ovs-ofctl: conflictinglong: invalid or unknown port for in_port
+AT_CHECK([ovs-ofctl add-flow br0 in_port=conflictinglong,actions=drop:pipeline-drop], [1], [], [ovs-ofctl: conflictinglong: invalid or unknown port for in_port
 ])
 
 # Show that the port names get displayed properly and that port names that
@@ -2974,7 +2974,7 @@  AT_CHECK([tail -1 stdout], [0],
 dnl Inbound web traffic with SYN bit without ACK or RST bits
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=6,tos=0,ttl=64,frag=no),tcp(src=80,dst=8),tcp_flags(0xfeb)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: drop
+  [Datapath actions: drop:pipeline-drop
 ])
 
 OVS_VSWITCHD_STOP
diff --git a/tests/packet-type-aware.at b/tests/packet-type-aware.at
index 23f9037..ed20576 100644
--- a/tests/packet-type-aware.at
+++ b/tests/packet-type-aware.at
@@ -505,7 +505,7 @@  AT_CHECK([
     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
 ], [0], [flow-dump from non-dpdk interfaces:
 recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys))
-tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),ipv4(dst=192.168.10.20,frag=no), packets:1, bytes:84, used:0.0s, actions:drop
+tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),ipv4(dst=192.168.10.20,frag=no), packets:1, bytes:84, used:0.0s, actions:drop:pipeline-drop
 ])
 
 OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
@@ -565,7 +565,7 @@  ovs-appctl time/warp 1000
 AT_CHECK([
     ovs-appctl dpctl/dump-flows | strip_used | grep -v ipv6 | sort
 ], [0], [flow-dump from non-dpdk interfaces:
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop:unsupported packet type
 ])
 
 # Encap(ethernet) on Ethernet frame -> should be droped
@@ -587,7 +587,7 @@  ovs-appctl time/warp 1000
 AT_CHECK([
     ovs-appctl dpctl/dump-flows | strip_used | grep -v ipv6 | sort
 ], [0], [flow-dump from non-dpdk interfaces:
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop:pipeline-drop
 ])
 
 # Encap(ethernet) on VLAN tagged Ethernet frame -> should be droped
@@ -609,7 +609,7 @@  ovs-appctl time/warp 1000
 AT_CHECK([
     ovs-appctl dpctl/dump-flows | strip_used | grep -v ipv6 | sort
 ], [0], [flow-dump from non-dpdk interfaces:
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop:unsupported packet type
 ])
 
 OVS_VSWITCHD_STOP
@@ -770,7 +770,7 @@  ovs-appctl time/warp 1000
 AT_CHECK([
     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
 ], [0], [flow-dump from non-dpdk interfaces:
-recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop
+recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop:pipeline-drop
 ])
 
 AT_CHECK([
diff --git a/tests/tunnel.at b/tests/tunnel.at
index 2bc004c..48aeb99 100644
--- a/tests/tunnel.at
+++ b/tests/tunnel.at
@@ -102,9 +102,10 @@  Datapath actions: set(ipv4(tos=0x3/0x3)),2
 
 dnl Tunnel CE and encapsulated packet Non-ECT
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
-AT_CHECK([tail -2 stdout], [0],
+AT_CHECK([tail -3 stdout], [0],
   [Megaflow: recirc_id=0,eth,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_flags=-df-csum-key,in_port=1,nw_ecn=0,nw_frag=no
-Datapath actions: drop
+Datapath actions: drop:ecn mismatch at tunnel decapsulation
+Translation failed (CONGESTION DROP), packet is dropped.
 ])
 OVS_VSWITCHD_STOP(["/dropping tunnel packet marked ECN CE but is not ECN capable/d"])
 AT_CLEANUP
@@ -364,7 +365,7 @@  Datapath actions: 4,3,5
 
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,ttl=64,flags(key)),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0], [dnl
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 
 OVS_VSWITCHD_STOP