In order to collect meters since the last meter action
to the current action in the dpif_execute_helper_cb,
the next entry is simply obtained using nl_attr_next, and
not considering the wrong nested nl without end_nested.
This will cause memory access to be overflowed.

Gdb debug looks like this:

  (gdb) print a
  $6 = (const struct nlattr *) 0xaaaad175a69c
  (gdb) n
  1206                          a = nl_attr_next(a);
  (gdb) n
  1207                      } while (a != action &&
  (gdb) n
  1206                          a = nl_attr_next(a);
  (gdb) print a
  $7 = (const struct nlattr *) 0xaaaad175a69c
  (gdb) print *a
  $8 = {nla_len = 0, nla_type = 0}
  (gdb)

Fixes: 076caa2fb077 ("ofproto: Meter translation.")
Signed-off-by: Daniel Ding <danieldin...@gmail.com>
---
 lib/dpif.c              | 20 +++----------
 tests/ofproto-dpif.at   | 29 ++++++++++++++++++
 tests/ofproto-macros.at | 66 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 99 insertions(+), 16 deletions(-)

diff --git a/lib/dpif.c b/lib/dpif.c
index d07241f1e..02429a30c 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -71,6 +71,7 @@ COVERAGE_DEFINE(dpif_meter_set);
 COVERAGE_DEFINE(dpif_port_add);
 COVERAGE_DEFINE(dpif_port_del);
 COVERAGE_DEFINE(dpif_purge);
+COVERAGE_DEFINE(dpif_execute_meters_discard);
 
 static const struct dpif_class *base_dpif_classes[] = {
 #if defined(__linux__) || defined(_WIN32)
@@ -1182,6 +1183,8 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet_batch 
*packets_,
         /* Maintain a pointer to the first meter action seen. */
         if (!aux->meter_action) {
             aux->meter_action = action;
+        } else {
+           COVERAGE_INC(dpif_execute_meters_discard);
         }
         break;
 
@@ -1202,22 +1205,7 @@ dpif_execute_helper_cb(void *aux_, struct 
dp_packet_batch *packets_,
 
             if (aux->meter_action) {
                 const struct nlattr *a = aux->meter_action;
-
-                /* XXX: This code collects meter actions since the last action
-                 * execution via the datapath to be executed right before the
-                 * current action that needs to be executed by the datapath.
-                 * This is only an approximation, but better than nothing.
-                 * Fundamentally, we should have a mechanism by which the
-                 * datapath could return the result of the meter action so that
-                 * we could execute them at the right order. */
-                do {
-                    ofpbuf_put(&execute_actions, a, NLA_ALIGN(a->nla_len));
-                    /* Find next meter action before 'action', if any. */
-                    do {
-                        a = nl_attr_next(a);
-                    } while (a != action &&
-                             nl_attr_type(a) != OVS_ACTION_ATTR_METER);
-                } while (a != action);
+                ofpbuf_put(&execute_actions, a, NLA_ALIGN(a->nla_len));
             }
 
             /* The Linux kernel datapath throws away the tunnel information
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index a1393f7f8..f5f665e45 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -12063,3 +12063,32 @@ AT_CHECK([test 1 = `ovs-ofctl parse-pcap p2-tx.pcap | 
wc -l`])
 
 OVS_VSWITCHD_STOP
 AT_CLEANUP
+
+
+AT_SETUP([ofproto-dpif - collecting meters])
+OVS_NETDEV_VSWITCHD_START
+
+AT_CHECK([ovs-vsctl add-br br-vm -- set Bridge br-vm datapath_type=netdev])
+AT_CHECK([ovs-vsctl add-br br-phy -- set Bridge br-phy datapath_type=netdev])
+AT_CHECK([ovs-vsctl add-port br-vm vx1 -- set Interface vx1 type=vxlan 
options:remote_ip=1.1.1.1 options:local_ip=1.1.1.2])
+
+dnl Active vxlan egress network
+ADD_NAMESPACES(ns1)
+ADD_VETH(p1, ns1, br-phy, "1.1.1.1/24")
+AT_CHECK([ip link set up dev br-phy])
+AT_CHECK([ip addr add 1.1.1.2/24 dev br-phy])
+
+dnl Force packet-out into collecting meters
+AT_CHECK([ovs-ofctl -O OpenFlow13 add-meter br-vm 'meter=1 pktps 
bands=type=drop rate=1'])
+AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br-vm 'table=2,arp 
actions=meter:1,set_field:2->arp_op,vx1,br-vm'])
+
+dnl Wait egress network ready
+AT_CHECK([ping -c 3 1.1.1.1], [0], [stdout])
+OVS_WAIT_UNTIL([test -n "`ovs-appctl tnl/arp/show | grep 1.1.1.1`"])
+OVS_WAIT_UNTIL([test -n "`ovs-appctl ovs/route/show | grep 1.1.1.0`"])
+
+dnl Send a arp packet-out message
+AT_CHECK([ovs-ofctl packet-out br-vm 'in_port=controller 
packet=ffffffffffff000000010102080600010800060400010000000101020101010300000000000001010102
 actions=resubmit(,2)'])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
\ No newline at end of file
diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at
index c22fb3c79..50512f08b 100644
--- a/tests/ofproto-macros.at
+++ b/tests/ofproto-macros.at
@@ -384,3 +384,69 @@ m4_define([WAIT_FOR_DUMMY_PORTS], \
                   | grep 'unknown\|disconnected'])])])
 
 
+# DEL_NAMESPACES(ns [, ns ... ])
+#
+# Delete namespaces from the running OS
+m4_define([DEL_NAMESPACES],
+   [m4_foreach([ns], [$@],
+               [ip netns del ns
+])
+   ]
+)
+
+
+# ADD_NAMESPACES(ns [, ns ... ])
+#
+# Add new namespaces, if ns exists, the old one
+# will be remove before new ones are installed.
+m4_define([ADD_NAMESPACES],
+   [m4_foreach([ns], [$@],
+               [DEL_NAMESPACES(ns)
+                AT_CHECK([ip netns add ns || return 77])
+                on_exit 'DEL_NAMESPACES(ns)'
+                ip netns exec ns sysctl -w net.netfilter.nf_conntrack_helper=0
+               ])
+   ]
+)
+# NS_EXEC([namespace], [command])
+#
+# Execute 'command' in 'namespace'
+m4_define([NS_EXEC],
+    [ip netns exec $1 sh << NS_EXEC_HEREDOC
+$2
+NS_EXEC_HEREDOC])
+
+# NS_CHECK_EXEC([namespace], [command], other_params...)
+#
+# Wrapper for AT_CHECK that executes 'command' inside 'namespace'.
+# 'other_params' as passed as they are to AT_CHECK.
+m4_define([NS_CHECK_EXEC],
+    [ AT_CHECK([NS_EXEC([$1], [$2])], m4_shift(m4_shift($@))) ]
+)
+
+m4_define([ADD_VETH],
+    [ AT_CHECK([ip link add $1 type veth peer name ovs-$1 || return 77])
+      AT_CHECK([ip link set $1 netns $2])
+      AT_CHECK([ip link set dev ovs-$1 up])
+      AT_CHECK([ovs-vsctl add-port $3 ovs-$1])
+      NS_CHECK_EXEC([$2], [ip addr add $4 dev $1 $7])
+      NS_CHECK_EXEC([$2], [ip link set dev $1 up])
+      if test -n "$5"; then
+        NS_CHECK_EXEC([$2], [ip link set dev $1 address $5])
+      fi
+      if test -n "$6"; then
+        NS_CHECK_EXEC([$2], [ip route add default via $6])
+      fi
+      on_exit 'ip link del ovs-$1'
+    ]
+)
+
+# OVS_NETDEV_VSWITCHD_START([dbinit-aux-args])
+#
+# Creates a database and starts ovsdb-server, starts ovs-vswitchd
+# connected to that database.
+# 'dbinit-aux-args' are passed as additional commands to 'ovs-vsctl init'
+# before starting ovs-vswitchd.
+m4_define([OVS_NETDEV_VSWITCHD_START],
+  [_OVS_VSWITCHD_START([--disable-system], [$1])
+])
\ No newline at end of file
-- 
2.43.0

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to