On Tue, 1 Apr 2025 at 23:21, Aaron Conole <acon...@redhat.com> wrote:
> Daniel Ding <danieldin...@gmail.com> writes: > > > 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 | 43 ++++++++++++++++-------------------------- > > tests/system-dpdk.at | 45 ++++++++++++++++++++++++++++++++++++++++++++ > > 2 files changed, 61 insertions(+), 27 deletions(-) > > > > diff --git a/lib/dpif.c b/lib/dpif.c > > index d07241f1e..05dfd2919 100644 > > --- a/lib/dpif.c > > +++ b/lib/dpif.c > > @@ -1158,11 +1158,14 @@ dpif_flow_dump_next(struct dpif_flow_dump_thread > *thread, > > return n; > > } > > > > +enum { EXECUTE_HELPER_MAX_METER = 32 }; > > + > > struct dpif_execute_helper_aux { > > struct dpif *dpif; > > const struct flow *flow; > > int error; > > - const struct nlattr *meter_action; /* Non-NULL, if have a meter > action. */ > > + size_t meter_count; > > + const struct nlattr *meter_actions[EXECUTE_HELPER_MAX_METER + 1]; > > }; > > > > /* This is called for actions that need the context of the datapath to > be > > @@ -1179,9 +1182,9 @@ dpif_execute_helper_cb(void *aux_, struct > dp_packet_batch *packets_, > > > > switch ((enum ovs_action_attr)type) { > > case OVS_ACTION_ATTR_METER: > > - /* Maintain a pointer to the first meter action seen. */ > > - if (!aux->meter_action) { > > - aux->meter_action = action; > > + /* Records the meter actions. */ > > + if (aux->meter_count < EXECUTE_HELPER_MAX_METER) { > > + aux->meter_actions[aux->meter_count++] = action; > > } > > Can we have a coverage counter that trips for the else case? Maybe a > rate limited warning log as well. At least if we're not going to do the > search as described by Ilya in: > > I add a dpif_execute_meters_discard coverage counter to record it. The warning log may not have some valuaful information. And the else case is not an actual impact for the packet_out message. https://patchwork.ozlabs.org/comment/3487109/ > > > break; > > > > @@ -1197,27 +1200,15 @@ dpif_execute_helper_cb(void *aux_, struct > dp_packet_batch *packets_, > > uint64_t stub[256 / 8]; > > struct pkt_metadata *md = &packet->md; > > > > - if (flow_tnl_dst_is_set(&md->tunnel) || aux->meter_action) { > > + if (flow_tnl_dst_is_set(&md->tunnel) || aux->meter_count) { > > ofpbuf_use_stub(&execute_actions, stub, sizeof stub); > > > > - 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 { > > + if (aux->meter_count) { > > + size_t i; > > + for (i = 0; i < aux->meter_count; i++) { > > + const struct nlattr *a = aux->meter_actions[i]; > > 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); > > + } > > } > > > > /* The Linux kernel datapath throws away the tunnel > information > > @@ -1261,11 +1252,9 @@ dpif_execute_helper_cb(void *aux_, struct > dp_packet_batch *packets_, > > > > dp_packet_delete(clone); > > > > - if (flow_tnl_dst_is_set(&md->tunnel) || aux->meter_action) { > > + if (flow_tnl_dst_is_set(&md->tunnel) || aux->meter_count) { > > ofpbuf_uninit(&execute_actions); > > - > > - /* Do not re-use the same meters for later output actions. > */ > > - aux->meter_action = NULL; > > + aux->meter_count = 0; > > } > > break; > > } > > @@ -1303,7 +1292,7 @@ dpif_execute_helper_cb(void *aux_, struct > dp_packet_batch *packets_, > > static int > > dpif_execute_with_help(struct dpif *dpif, struct dpif_execute *execute) > > { > > - struct dpif_execute_helper_aux aux = {dpif, execute->flow, 0, NULL}; > > + struct dpif_execute_helper_aux aux = {dpif, execute->flow, 0, 0, > {NULL}}; > > struct dp_packet_batch pb; > > > > COVERAGE_INC(dpif_execute_with_help); > > diff --git a/tests/system-dpdk.at b/tests/system-dpdk.at > > index 1c97bf777..43b41a9f2 100644 > > --- a/tests/system-dpdk.at > > +++ b/tests/system-dpdk.at > > The test suite you've submitted is broken on my system. Additionally, > it will only run for DPDK testing, but it really can be run on all > users of the userspace datapath. > > I think it should be written for system-traffic.at rather than as DPDK > specific suite. I didn't actually test with the supplied fix, but the > test suite below will invoke a hang with ``make check-system-userspace`` > like: > > Thread 1 (LWP 4033950 "ovs-vswitchd"): > #0 0x00000000004bf397 in nl_attr_type (nla=nla@entry=0x2cf879d8) at > lib/netlink.c:642 > #1 0x0000000000490778 in dpif_execute_helper_cb > (aux_=aux_@entry=0x7ffc1e9b0d60, > packets_=packets_@entry=0x7ffc1e9b0a80, action=action@entry=0x2cf7d2d4, > should_steal=should_steal@entry=false) at lib/dpif.c:1222 > ... > > You are right, and I will try to write this case for ofproto.at. > Ex suite: > > --- a/tests/system-traffic.at > +++ b/tests/system-traffic.at > @@ -2813,6 +2813,40 @@ OVS_WAIT_UNTIL([test $(ovs-pcap p1.pcap | grep -c > "${packet}") -eq 5]) > OVS_TRAFFIC_VSWITCHD_STOP > AT_CLEANUP > > +dnl Setup dpif collecting meters > +AT_SETUP([datapath - meter execution helpers]) > +AT_KEYWORDS([meter meters]) > +OVS_TRAFFIC_VSWITCHD_START() > + > +ADD_BR([br-vm]) > + > +dnl Active vxlan egress network > +AT_CHECK([ip link set up dev br0]) > +AT_CHECK([ip addr add 1.1.1.2/24 dev br0]) > +AT_CHECK([ovs-vsctl add-port br-vm p1 -- set Interface p1 type=vxlan > options:remote_ip=1.1.1.1 options:local_ip=1.1.1.2]) > + > +ADD_NAMESPACES(at_ns1) > +NS_CHECK_EXEC([at_ns1], [sysctl -w net.ipv6.conf.all.disable_ipv6=1], > [0], [ignore]) > + > +ADD_VETH(p0, at_ns1, br0, "1.1.1.1/24", "e4:11:22:33:44:55") > + > +AT_CHECK([ovs-ofctl add-flow br0 "table=0,priority=0 actions=NORMAL"]) > +AT_CHECK([ovs-ofctl add-flow br-vm "table=0,priority=0 actions=NORMAL"]) > + > +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`"]) > + > +dnl Force arps 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,p1,br-vm']) > + > +dnl Send an arp packet-out message > +AT_CHECK([ovs-ofctl packet-out br-vm 'in_port=controller > packet=ffffffffffff000000010102080600010800060400010000000101020101010300000000000001010102 > actions=resubmit(,2)']) > + > +dnl Clean up > +OVS_TRAFFIC_VSWITCHD_STOP > +AT_CLEANUP > + > AT_BANNER([MPLS]) > > AT_SETUP([mpls - encap header dp-support]) > > _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev