Exercise the alt_actions parameter added to the netdev_hw_post_process()
callback.  When a flow contains only OUTPUT actions with a mix of
dummy-pmd and non-dummy-pmd egress ports, the dummy driver executes the
dummy-pmd outputs in the simulated hardware pipeline and returns the
non-dummy-pmd outputs as alternative actions for the PMD thread.
A new test case validates the new API.

Signed-off-by: Eelco Chaudron <[email protected]>
---
 lib/dpif-offload-dummy.c | 133 ++++++++++++++++++++++++++++++++-------
 tests/dpif-netdev.at     | 103 +++++++++++++++++++++++++++++-
 tests/ofproto-dpif.at    |  65 ++++++++++++-------
 3 files changed, 255 insertions(+), 46 deletions(-)

diff --git a/lib/dpif-offload-dummy.c b/lib/dpif-offload-dummy.c
index 022c48ede..309158fbd 100644
--- a/lib/dpif-offload-dummy.c
+++ b/lib/dpif-offload-dummy.c
@@ -45,6 +45,7 @@ struct dummy_offloaded_flow {
     struct match match;
     const struct nlattr *actions;
     size_t actions_len;
+    struct offload_actions *alt_actions;
     ovs_u128 ufid;
     uint32_t mark;
     struct dpif_flow_stats stats;
@@ -74,6 +75,7 @@ struct dummy_offload_port {
     uint64_t rx_offload_full OVS_GUARDED; /* Fully offloaded, CPU bypassed. */
     uint64_t rx_offload_miss OVS_GUARDED; /* No HW offload rule matched. */
     uint64_t rx_offload_pipe_abort OVS_GUARDED; /* Pipeline abort. */
+    uint64_t rx_offload_alt_actions OVS_GUARDED; /* Partial action offload. */
 };
 
 struct hw_pkt_node {
@@ -246,6 +248,7 @@ dummy_free_flow(struct dummy_offload_port *port,
 
     hmap_destroy(&off_flow->pmd_id_map);
     free(CONST_CAST(struct nlattr *, off_flow->actions));
+    ovsrcu_postpone(free, off_flow->alt_actions);
     free(off_flow);
 }
 
@@ -489,6 +492,8 @@ dummy_offload_get_debug(const struct dpif_offload *offload, 
struct ds *ds,
                             json_integer_create(port->rx_offload_miss));
             json_object_put(json_port, "rx_offload_pipe_abort",
                             json_integer_create(port->rx_offload_pipe_abort));
+            json_object_put(json_port, "rx_offload_alt_actions",
+                            json_integer_create(port->rx_offload_alt_actions));
             ovs_mutex_unlock(&port->port_mutex);
 
             json_object_put(json_ports, netdev_get_name(port_->netdev),
@@ -509,13 +514,15 @@ dummy_offload_get_debug(const struct dpif_offload 
*offload, struct ds *ds,
             ovs_mutex_lock(&port->port_mutex);
             ds_put_format(ds,
                           "  - %s: port_no: %u\n"
-                          "    rx_offload_partial   : %" PRIu64 "\n"
-                          "    rx_offload_full      : %" PRIu64 "\n"
-                          "    rx_offload_miss      : %" PRIu64 "\n"
-                          "    rx_offload_pipe_abort: %" PRIu64 "\n",
+                          "    rx_offload_partial    : %" PRIu64 "\n"
+                          "    rx_offload_full       : %" PRIu64 "\n"
+                          "    rx_offload_miss       : %" PRIu64 "\n"
+                          "    rx_offload_pipe_abort : %" PRIu64 "\n"
+                          "    rx_offload_alt_actions: %" PRIu64 "\n",
                           netdev_get_name(port_->netdev), port_->port_no,
                           port->rx_offload_partial, port->rx_offload_full,
-                          port->rx_offload_miss, port->rx_offload_pipe_abort);
+                          port->rx_offload_miss, port->rx_offload_pipe_abort,
+                          port->rx_offload_alt_actions);
             ovs_mutex_unlock(&port->port_mutex);
         }
     }
@@ -589,10 +596,10 @@ dummy_offload_hw_post_process(const struct dpif_offload 
*offload_,
     void *flow_reference = NULL;
     uint32_t flow_mark;
 
+    *alt_actions = NULL;
     port = dummy_offload_get_port_by_netdev(offload_, netdev);
     if (!port || !dp_packet_has_flow_mark(packet, &flow_mark)) {
         *flow_reference_ = NULL;
-        *alt_actions = NULL;
         return 0;
     }
 
@@ -605,13 +612,15 @@ dummy_offload_hw_post_process(const struct dpif_offload 
*offload_,
             if (pmd_data) {
                 flow_reference = pmd_data->flow_reference;
             }
+            if (off_flow->alt_actions) {
+                *alt_actions = off_flow->alt_actions;
+            }
             break;
         }
     }
     ovs_mutex_unlock(&port->port_mutex);
 
     *flow_reference_ = flow_reference;
-    *alt_actions = NULL;
     return 0;
 }
 
@@ -724,22 +733,23 @@ dummy_offload_are_all_actions_supported(const struct 
dpif_offload *offload_,
     return true;
 }
 
-static bool
+static int
 dummy_offload_hw_process_pkt(const struct dpif_offload *offload_,
                              struct dummy_offloaded_flow *flow,
                              struct dp_packet *pkt)
 {
+    bool partial_act = flow->alt_actions != NULL;
     uint32_t hash = dp_packet_get_rss_hash(pkt);
     uint32_t pkt_size = dp_packet_size(pkt);
     const struct nlattr *nla;
     size_t left;
 
     if (!flow->actions) {
-        return false;
+        return -ENOENT;
     }
 
     NL_ATTR_FOR_EACH (nla, left, flow->actions, flow->actions_len) {
-        bool last_action = (left <= NLA_ALIGN(nla->nla_len));
+        bool last_action = !partial_act && (left <= NLA_ALIGN(nla->nla_len));
         enum ovs_action_attr action = nl_attr_type(nla);
 
         switch (action) {
@@ -751,7 +761,14 @@ dummy_offload_hw_process_pkt(const struct dpif_offload 
*offload_,
 
             port = dummy_offload_get_port_by_odp_port(offload_, odp_port);
             if (!port) {
-                return false;
+                return -ENODEV;
+            }
+
+            /* Skip non-dummy-pmd ports here, as they are handled via the
+             * alternative actions returned by the hw_post_process callback. */
+            if (partial_act && strcmp("dummy-pmd",
+                                      netdev_get_type(port->pm_port.netdev))) {
+                break;
             }
 
             n_txq = netdev_n_txq(port->pm_port.netdev);
@@ -817,7 +834,60 @@ dummy_offload_hw_process_pkt(const struct dpif_offload 
*offload_,
     flow->stats.n_bytes += pkt_size;
     flow->stats.n_packets++;
     flow->stats.used = time_msec();
-    return true;
+
+    /* For mixed offload, return -EAGAIN so the caller re-injects the packet
+     * to the CPU for alt_actions processing. */
+    return partial_act ? -EAGAIN : 0;
+}
+
+/* Build a set of alternative actions to exercise the alt_actions support in
+ * the netdev_hw_post_process() API.  The dummy implementation returns
+ * alternative actions only when the action list consists solely of
+ * OVS_ACTION_ATTR_OUTPUT actions, and at least one egress port is not of
+ * type dummy-pmd.  In that case, the dummy-pmd outputs are handled in
+ * 'hardware', while the non-dummy-pmd outputs are returned as alternative
+ * actions to be executed by the PMD thread. */
+static struct offload_actions *
+dummy_build_alt_actions(const struct dpif_offload *offload_,
+                        odp_port_t in_odp,
+                        const struct nlattr *actions,
+                        size_t actions_len)
+{
+    struct offload_actions *alt_actions = NULL;
+    const struct nlattr *nla;
+    struct ofpbuf buf;
+    size_t left;
+
+    ofpbuf_init(&buf, 0);
+
+    NL_ATTR_FOR_EACH (nla, left, actions, actions_len) {
+        enum ovs_action_attr action = nl_attr_type(nla);
+        struct dummy_offload_port *out_port;
+        odp_port_t out_odp;
+
+        if (action != OVS_ACTION_ATTR_OUTPUT) {
+            goto out;
+        }
+
+        out_odp = nl_attr_get_odp_port(nla);
+        out_port = dummy_offload_get_port_by_odp_port(offload_, out_odp);
+        if (out_odp != in_odp
+            && (!out_port
+                || strcmp("dummy-pmd",
+                          netdev_get_type(out_port->pm_port.netdev)))) {
+            ofpbuf_put(&buf, nla, NLA_ALIGN(nla->nla_len));
+        }
+    }
+
+    if (buf.size) {
+        alt_actions = xmalloc(sizeof *alt_actions + buf.size);
+        alt_actions->size = buf.size;
+        memcpy(alt_actions->actions, buf.data, buf.size);
+    }
+
+out:
+    ofpbuf_uninit(&buf);
+    return alt_actions;
 }
 
 static int
@@ -864,12 +934,24 @@ dummy_flow_put(const struct dpif_offload *offload_, 
struct netdev *netdev,
     }
     memcpy(&off_flow->match, put->match, sizeof *put->match);
     free(CONST_CAST(struct nlattr *, off_flow->actions));
+    ovsrcu_postpone(free, off_flow->alt_actions);
+    off_flow->alt_actions = NULL;
     if (full_offload) {
         off_flow->actions = xmemdup(put->actions, put->actions_len);
         off_flow->actions_len = put->actions_len;
     } else {
-        off_flow->actions = NULL;
-        off_flow->actions_len = 0;
+        off_flow->alt_actions = dummy_build_alt_actions(
+            offload_, put->match->flow.in_port.odp_port,
+            put->actions, put->actions_len);
+        if (off_flow->alt_actions) {
+            /* Partial action offload to test the alt_actions API. */
+            off_flow->actions = xmemdup(put->actions, put->actions_len);
+            off_flow->actions_len = put->actions_len;
+        } else {
+            /* Classic partial offload, i.e., only flow matching. */
+            off_flow->actions = NULL;
+            off_flow->actions_len = 0;
+        }
     }
 
     /* As we have per-netdev 'offloaded_flows', we don't need to match
@@ -1028,6 +1110,7 @@ dummy_netdev_simulate_offload(struct netdev *netdev, 
struct dp_packet *packet,
     struct dummy_offload_port *port;
     bool packet_stolen = false;
     struct flow packet_flow;
+    uint32_t existing_mark;
     bool offloaded = false;
 
     if (!dpif_offload_enabled() || !offload
@@ -1040,6 +1123,12 @@ dummy_netdev_simulate_offload(struct netdev *netdev, 
struct dp_packet *packet,
         return false;
     }
 
+    /* If the packet already has a flow mark, it was re-injected, so let it
+     * continue to the CPU so hw_post_process can return alt_actions. */
+    if (dp_packet_has_flow_mark(packet, &existing_mark)) {
+        return false;
+    }
+
     if (!flow) {
         flow = &packet_flow;
         flow_extract(packet, flow);
@@ -1072,9 +1161,6 @@ dummy_netdev_simulate_offload(struct netdev *netdev, 
struct dp_packet *packet,
             }
 
             if (data->actions) {
-                /* Perform hardware offload simulation.  The packet is stolen
-                 * here and handed off to the PMD thread callback for
-                 * processing. */
                 struct hw_pkt_node *pkt_node = xmalloc(sizeof *pkt_node);
 
                 pkt_node->pkt = packet;
@@ -1124,7 +1210,7 @@ dummy_netdev_hw_offload_run(struct netdev *netdev)
         LIST_FOR_EACH_POP (pkt_node, list_node, &port->hw_recv_queue) {
             struct dummy_offloaded_flow *offloaded_flow;
             struct dp_packet *pkt = pkt_node->pkt;
-            bool processed = false;
+            int err = -ENOENT;
             struct flow flow;
 
             flow_extract(pkt, &flow);
@@ -1132,13 +1218,18 @@ dummy_netdev_hw_offload_run(struct netdev *netdev)
                 if (flow_equal_except(&flow, &offloaded_flow->match.flow,
                                       &offloaded_flow->match.wc)) {
 
-                    processed = dummy_offload_hw_process_pkt(
-                                    offload, offloaded_flow, pkt);
+                    err = dummy_offload_hw_process_pkt(offload, offloaded_flow,
+                                                       pkt);
                     break;
                 }
             }
 
-            if (!processed) {
+            if (err == -EAGAIN) {
+                /* We failed full processing as we have alt_actions. */
+                port->rx_offload_alt_actions++;
+                netdev_dummy_queue_simulate_offload_packet(
+                    port->pm_port.netdev, pkt, pkt_node->queue_id);
+            } else if (err) {
                 VLOG_DBG("Failed HW pipeline, sent to sw!");
                 port->rx_offload_pipe_abort++;
                 netdev_dummy_queue_simulate_offload_packet(
diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at
index 14f238e62..b14cc6d27 100644
--- a/tests/dpif-netdev.at
+++ b/tests/dpif-netdev.at
@@ -728,7 +728,7 @@ p1: flow del: mark: 1
 AT_CHECK([ovs-appctl dpif-netdev/pmd-perf-show \
           | grep -q "PHWOL hits:                  0 "])
 
-# Verify two packets where received.
+# Verify two packets were received.
 AT_CHECK([[[ $(ovs-pcap p2.pcap | grep -c "$packet_hex") -eq 2 ]]])
 
 # Verify that we observe one miss, one packet processed by hardware,
@@ -737,6 +737,7 @@ AT_CHECK(
   [ovs-appctl --format json dpif/offload/show \
      | sed 's/.*"p1":{\([[^}]]*\)}.*/\1/; s/,/\n/g; s/"//g' \
      | sed -n '/^rx_offload_/p' | sort], [0], [dnl
+rx_offload_alt_actions:0
 rx_offload_full:1
 rx_offload_miss:1
 rx_offload_partial:0
@@ -759,6 +760,7 @@ AT_CHECK(
   [ovs-appctl --format json dpif/offload/show \
      | sed 's/.*"p1":{\([[^}]]*\)}.*/\1/; s/,/\n/g; s/"//g' \
      | sed -n '/^rx_offload_/p' | sort], [0], [dnl
+rx_offload_alt_actions:0
 rx_offload_full:2
 rx_offload_miss:2
 rx_offload_partial:0
@@ -768,6 +770,104 @@ rx_offload_pipe_abort:1
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([dpif-netdev - full hw offload - alt actions - dummy-pmd])
+OVS_VSWITCHD_START(
+  [add-port br0 p1 -- \
+   add-port br0 p2 -- \
+   set interface br0 options:tx_pcap=br0.pcap -- \
+   set interface p1 type=dummy-pmd ofport_request=1 options:ifindex=1100 -- \
+   set interface p2 type=dummy-pmd ofport_request=2 options:ifindex=1200 \
+     options:tx_pcap=p2.pcap -- \
+   set bridge br0 datapath-type=dummy other-config:datapath-id=1234 \
+     fail-mode=secure], [], [], [--dummy-numa="0,0,0,0,1,1,1,1"])
+AT_CHECK([ovs-appctl vlog/set dpif:file:dbg dpif_netdev:file:dbg \
+          dpif_offload_dummy:file:dbg])
+
+AT_CHECK([ovs-vsctl set Open_vSwitch . other_config:hw-offload=true])
+OVS_WAIT_UNTIL([grep "Flow HW offload is enabled" ovs-vswitchd.log])
+
+# Install a flow that outputs to both a dummy-pmd port (p2, offloadable
+# in hardware) and the bridge's internal LOCAL port (br0, dummy-internal,
+# not offloadable).  Hardware handles the match; the dummy-pmd output is
+# treated as the HW-side action, while the LOCAL output is returned as
+# alt_actions for the CPU to execute.
+AT_CHECK([ovs-ofctl del-flows br0])
+AT_CHECK([ovs-ofctl add-flow br0 in_port=1,actions=p2,LOCAL])
+
+packet="\
+  eth_src=00:06:07:08:09:0a,eth_dst=00:01:02:03:04:05,\
+  udp,ip_src=127.0.0.1,ip_dst=127.0.0.1,nw_ttl=64,\
+  udp_src=54392,udp_dst=5201"
+packet_hex=$(ovs-ofctl compose-packet --bare "${packet}")
+
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 $packet_hex], [0])
+
+OVS_WAIT_UNTIL([grep "miss upcall" ovs-vswitchd.log])
+AT_CHECK([grep -A 1 'miss upcall' ovs-vswitchd.log | tail -n 1], [0], [dnl
+recirc_id(0),dp_hash(0),skb_priority(0),in_port(1),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),packet_type(ns=0,id=0),eth(src=00:06:07:08:09:0a,dst=00:01:02:03:04:05),eth_type(0x0800),ipv4(src=127.0.0.1,dst=127.0.0.1,proto=17,tos=0,ttl=64,frag=no),udp(src=54392,dst=5201)
+])
+
+# Check that flow successfully offloaded.
+OVS_WAIT_UNTIL([grep "succeed to add netdev flow" ovs-vswitchd.log])
+AT_CHECK([filter_hw_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
+p1: flow put[[create]]: flow match: 
recirc_id=0,eth,ip,in_port=1,vlan_tci=0x0000/0x1fff,nw_frag=no, mark: 1
+])
+
+# Check that datapath flow installed successfully.
+AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), 
actions: <del>
+])
+
+# Inject the same packet again.
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 $packet_hex], [0])
+
+# Check for successful packet matching with installed offloaded flow.
+AT_CHECK([filter_hw_packet_netdev_dummy < ovs-vswitchd.log | strip_xout], [0], 
[dnl
+p1: packet: 
udp,vlan_tci=0x0000,dl_src=00:06:07:08:09:0a,dl_dst=00:01:02:03:04:05,nw_src=127.0.0.1,nw_dst=127.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,nw_frag=no,tp_src=54392,tp_dst=5201
 matches with flow: recirc_id=0,eth,ip,vlan_tci=0x0000/0x1fff,nw_frag=no with 
mark: 1
+])
+
+# Dump the datapath flow to see that actions was executed for a packet.
+AT_CHECK([ovs-appctl dpctl/dump-flows -m | strip_hw_offload], [0], [dnl
+recirc_id(0),in_port(p1),packet_type(ns=0,id=0),eth(),eth_type(0x0800),ipv4(),udp(),
 packets:2, bytes:212, used:0.0s, offloaded:yes, dp:dummy, actions:p2,br0
+])
+
+# Wait for datapath flow expiration.
+ovs-appctl time/stop
+ovs-appctl time/warp 15000
+ovs-appctl revalidator/wait
+
+# Check that flow successfully deleted from HW.
+OVS_WAIT_UNTIL([grep "succeed to delete netdev flow" ovs-vswitchd.log])
+AT_CHECK([filter_hw_flow_del < ovs-vswitchd.log | strip_xout], [0], [dnl
+p1: flow del: mark: 1
+])
+
+# Check if we hit partial hw offload.
+AT_CHECK([ovs-appctl dpif-netdev/pmd-perf-show \
+          | grep -q "PHWOL hits:                  1 "])
+
+# Verify two packets were received.
+AT_CHECK([[[ $(ovs-pcap p2.pcap | grep -c "$packet_hex") -eq 2 ]]])
+
+# Verify we received the packet on br0.
+AT_CHECK([[[ $(ovs-pcap br0.pcap | grep -c "$packet_hex") -eq 2 ]]])
+
+# Verify offload statistics: one miss (first packet), one full (second
+# packet matched in HW), and one alt_actions return from hw_post_process.
+AT_CHECK(
+  [ovs-appctl --format json dpif/offload/show \
+     | sed 's/.*"p1":{\([[^}]]*\)}.*/\1/; s/,/\n/g; s/"//g' \
+     | sed -n '/^rx_offload_/p' | sort], [0], [dnl
+rx_offload_alt_actions:1
+rx_offload_full:1
+rx_offload_miss:1
+rx_offload_partial:0
+rx_offload_pipe_abort:0
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([dpif-netdev - full hw offload - tunnel entropy - dummy-pmd])
 OVS_VSWITCHD_START(
   [add-br br1 -- set bridge br1 datapath-type=dummy -- \
@@ -838,6 +938,7 @@ AT_CHECK(
   [ovs-appctl --format json dpif/offload/show \
      | sed 's/.*"p1":{\([[^}]]*\)}.*/\1/; s/,/\n/g; s/"//g' \
      | sed -n '/^rx_offload_/p' | sort], [0], [dnl
+rx_offload_alt_actions:0
 rx_offload_full:1
 rx_offload_miss:1
 rx_offload_partial:0
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index efb36e058..2cba6c81d 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -10485,18 +10485,21 @@ Globally enabled: false
 Datapaths:
 dummy@ovs-dummy:
   dummy
-    rx_offload_partial   : 0
-    rx_offload_full      : 0
-    rx_offload_miss      : 0
-    rx_offload_pipe_abort: 0
-    rx_offload_partial   : 0
-    rx_offload_full      : 0
-    rx_offload_miss      : 0
-    rx_offload_pipe_abort: 0
-    rx_offload_partial   : 0
-    rx_offload_full      : 0
-    rx_offload_miss      : 0
-    rx_offload_pipe_abort: 0
+    rx_offload_partial    : 0
+    rx_offload_full       : 0
+    rx_offload_miss       : 0
+    rx_offload_pipe_abort : 0
+    rx_offload_alt_actions: 0
+    rx_offload_partial    : 0
+    rx_offload_full       : 0
+    rx_offload_miss       : 0
+    rx_offload_pipe_abort : 0
+    rx_offload_alt_actions: 0
+    rx_offload_partial    : 0
+    rx_offload_full       : 0
+    rx_offload_miss       : 0
+    rx_offload_pipe_abort : 0
+    rx_offload_alt_actions: 0
   dummy_x
   - br0: port_no: 100
   - br1: port_no: 101
@@ -10514,18 +10517,21 @@ AT_CHECK([ovs-appctl --format json --pretty 
dpif/offload/show], [0], [dnl
         "ports": {
           "br0": {
             "port_no": 100,
+            "rx_offload_alt_actions": 0,
             "rx_offload_full": 0,
             "rx_offload_miss": 0,
             "rx_offload_partial": 0,
             "rx_offload_pipe_abort": 0},
           "br1": {
             "port_no": 101,
+            "rx_offload_alt_actions": 0,
             "rx_offload_full": 0,
             "rx_offload_miss": 0,
             "rx_offload_partial": 0,
             "rx_offload_pipe_abort": 0},
           "ovs-dummy": {
             "port_no": 0,
+            "rx_offload_alt_actions": 0,
             "rx_offload_full": 0,
             "rx_offload_miss": 0,
             "rx_offload_partial": 0,
@@ -10561,18 +10567,21 @@ Globally enabled: false
 Datapaths:
 dummy@ovs-dummy:
   dummy_x
-    rx_offload_partial   : 0
-    rx_offload_full      : 0
-    rx_offload_miss      : 0
-    rx_offload_pipe_abort: 0
-    rx_offload_partial   : 0
-    rx_offload_full      : 0
-    rx_offload_miss      : 0
-    rx_offload_pipe_abort: 0
-    rx_offload_partial   : 0
-    rx_offload_full      : 0
-    rx_offload_miss      : 0
-    rx_offload_pipe_abort: 0
+    rx_offload_partial    : 0
+    rx_offload_full       : 0
+    rx_offload_miss       : 0
+    rx_offload_pipe_abort : 0
+    rx_offload_alt_actions: 0
+    rx_offload_partial    : 0
+    rx_offload_full       : 0
+    rx_offload_miss       : 0
+    rx_offload_pipe_abort : 0
+    rx_offload_alt_actions: 0
+    rx_offload_partial    : 0
+    rx_offload_full       : 0
+    rx_offload_miss       : 0
+    rx_offload_pipe_abort : 0
+    rx_offload_alt_actions: 0
   dummy
   - br0: port_no: 100
   - br1: port_no: 101
@@ -10592,18 +10601,21 @@ AT_CHECK([ovs-appctl --format json --pretty 
dpif/offload/show], [0], [dnl
         "ports": {
           "br0": {
             "port_no": 100,
+            "rx_offload_alt_actions": 0,
             "rx_offload_full": 0,
             "rx_offload_miss": 0,
             "rx_offload_partial": 0,
             "rx_offload_pipe_abort": 0},
           "br1": {
             "port_no": 101,
+            "rx_offload_alt_actions": 0,
             "rx_offload_full": 0,
             "rx_offload_miss": 0,
             "rx_offload_partial": 0,
             "rx_offload_pipe_abort": 0},
           "ovs-dummy": {
             "port_no": 0,
+            "rx_offload_alt_actions": 0,
             "rx_offload_full": 0,
             "rx_offload_miss": 0,
             "rx_offload_partial": 0,
@@ -10640,18 +10652,21 @@ AT_CHECK([ovs-appctl --format json --pretty 
dpif/offload/show], [0], [dnl
         "ports": {
           "br0": {
             "port_no": 100,
+            "rx_offload_alt_actions": 0,
             "rx_offload_full": 0,
             "rx_offload_miss": 0,
             "rx_offload_partial": 0,
             "rx_offload_pipe_abort": 0},
           "ovs-dummy": {
             "port_no": 0,
+            "rx_offload_alt_actions": 0,
             "rx_offload_full": 0,
             "rx_offload_miss": 0,
             "rx_offload_partial": 0,
             "rx_offload_pipe_abort": 0},
           "p4": {
             "port_no": 4,
+            "rx_offload_alt_actions": 0,
             "rx_offload_full": 0,
             "rx_offload_miss": 0,
             "rx_offload_partial": 0,
@@ -10660,12 +10675,14 @@ AT_CHECK([ovs-appctl --format json --pretty 
dpif/offload/show], [0], [dnl
         "ports": {
           "p1": {
             "port_no": 1,
+            "rx_offload_alt_actions": 0,
             "rx_offload_full": 0,
             "rx_offload_miss": 0,
             "rx_offload_partial": 0,
             "rx_offload_pipe_abort": 0},
           "p3": {
             "port_no": 3,
+            "rx_offload_alt_actions": 0,
             "rx_offload_full": 0,
             "rx_offload_miss": 0,
             "rx_offload_partial": 0,
-- 
2.55.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to