diff mbox series

[ovs-dev] controller: reconfigure ovs meters for ovn meters updates

Message ID 92b1a7982c5ae9f4875e532ea125ca7415ab5b56.1637859790.git.lorenzo.bianconi@redhat.com
State Changes Requested
Headers show
Series [ovs-dev] controller: reconfigure ovs meters for ovn meters updates | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test success github build: passed
ovsrobot/github-robot-_ovn-kubernetes success github build: passed

Commit Message

Lorenzo Bianconi Nov. 25, 2021, 5:05 p.m. UTC
At the moment ovs meters are reconfigured by ovn just when a
new a meter is allocated while updates for an already allocated meter are
ignored. This issue can be easily verified with the following reproducer:

$ovn-nbctl meter-add meter0 drop 10 pktps
$ovn-nbctl --log --meter=meter0 acl-add sw0 to-lport 1000 'tcp.dst == 80' drop
$ovn-nbctl --may-exist meter-add meter0 drop 20 pktps
$ovs-ofctl -O OpenFlow15 dump-meters br-int

Fix the issue reconfiguring ovs meters even for ovn meters updates.
Related bz: https://bugzilla.redhat.com/show_bug.cgi?id=1939524

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
---
 controller/ofctrl.c         | 70 +++++++++++++++++++++++++++----------
 controller/ofctrl.h         |  2 ++
 controller/ovn-controller.c | 56 ++++++++++++++++++++++++++++-
 tests/system-ovn.at         | 17 +++++++++
 4 files changed, 126 insertions(+), 19 deletions(-)

Comments

Numan Siddique Dec. 1, 2021, 3:50 p.m. UTC | #1
On Thu, Nov 25, 2021 at 12:05 PM Lorenzo Bianconi
<lorenzo.bianconi@redhat.com> wrote:
>
> At the moment ovs meters are reconfigured by ovn just when a
> new a meter is allocated while updates for an already allocated meter are
> ignored. This issue can be easily verified with the following reproducer:
>
> $ovn-nbctl meter-add meter0 drop 10 pktps
> $ovn-nbctl --log --meter=meter0 acl-add sw0 to-lport 1000 'tcp.dst == 80' drop
> $ovn-nbctl --may-exist meter-add meter0 drop 20 pktps
> $ovs-ofctl -O OpenFlow15 dump-meters br-int
>
> Fix the issue reconfiguring ovs meters even for ovn meters updates.
> Related bz: https://bugzilla.redhat.com/show_bug.cgi?id=1939524
>
> Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>

Hi Lorenzo,

Thanks for the fix.  Please see below for a few comments.

Numan

> ---
>  controller/ofctrl.c         | 70 +++++++++++++++++++++++++++----------
>  controller/ofctrl.h         |  2 ++
>  controller/ovn-controller.c | 56 ++++++++++++++++++++++++++++-
>  tests/system-ovn.at         | 17 +++++++++
>  4 files changed, 126 insertions(+), 19 deletions(-)
>
> diff --git a/controller/ofctrl.c b/controller/ofctrl.c
> index 08fcfed8b..25c939fa3 100644
> --- a/controller/ofctrl.c
> +++ b/controller/ofctrl.c
> @@ -1802,26 +1802,13 @@ add_meter_string(struct ovn_extend_table_info *m_desired,
>  }
>
>  static void
> -add_meter(struct ovn_extend_table_info *m_desired,
> -          const struct sbrec_meter_table *meter_table,
> -          struct ovs_list *msgs)
> +alloc_meter_mod(struct ovn_extend_table_info *m,
> +                const struct sbrec_meter *sb_meter,
> +                struct ovs_list *msgs, bool update)
>  {
> -    const struct sbrec_meter *sb_meter;
> -    SBREC_METER_TABLE_FOR_EACH (sb_meter, meter_table) {
> -        if (!strcmp(m_desired->name, sb_meter->name)) {
> -            break;
> -        }
> -    }
> -
> -    if (!sb_meter) {
> -        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
> -        VLOG_ERR_RL(&rl, "could not find meter named \"%s\"", m_desired->name);
> -        return;
> -    }
> -
>      struct ofputil_meter_mod mm;
> -    mm.command = OFPMC13_ADD;
> -    mm.meter.meter_id = m_desired->table_id;
> +    mm.command = update ? OFPMC13_MODIFY : OFPMC13_ADD;
> +    mm.meter.meter_id = m->table_id;
>      mm.meter.flags = OFPMF13_STATS;
>
>      if (!strcmp(sb_meter->unit, "pktps")) {
> @@ -1854,6 +1841,53 @@ add_meter(struct ovn_extend_table_info *m_desired,
>      free(mm.meter.bands);
>  }
>
> +void
> +update_meter(const struct sbrec_meter *meter)
> +{
> +    struct ovs_list msgs = OVS_LIST_INITIALIZER(&msgs);
> +    struct ovn_extend_table_info *m_iter;
> +
> +    HMAP_FOR_EACH (m_iter, hmap_node, &meters->desired) {
> +        if (!strcmp(meter->name, m_iter->name) &&
> +            ovn_extend_table_lookup(&meters->existing, m_iter)) {
> +            alloc_meter_mod(m_iter, meter, &msgs, true);
> +        }
> +    }
> +
> +    if (!ovs_list_is_empty(&msgs)) {
> +        /* Add a barrier to the list of messages. */
> +        struct ofpbuf *barrier = ofputil_encode_barrier_request(OFP15_VERSION);
> +
> +        ovs_list_push_back(&msgs, &barrier->list_node);
> +        /* Queue the messages. */
> +        struct ofpbuf *msg;
> +        LIST_FOR_EACH_POP (msg, list_node, &msgs) {
> +            queue_msg(msg);
> +        }
> +    }
> +}
> +
> +static void
> +add_meter(struct ovn_extend_table_info *m_desired,
> +          const struct sbrec_meter_table *meter_table,
> +          struct ovs_list *msgs)
> +{
> +    const struct sbrec_meter *sb_meter;
> +    SBREC_METER_TABLE_FOR_EACH (sb_meter, meter_table) {
> +        if (!strcmp(m_desired->name, sb_meter->name)) {
> +            break;
> +        }
> +    }
> +
> +    if (!sb_meter) {
> +        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
> +        VLOG_ERR_RL(&rl, "could not find meter named \"%s\"", m_desired->name);
> +        return;
> +    }
> +
> +    alloc_meter_mod(m_desired, sb_meter, msgs, false);
> +}
> +
>  static void
>  installed_flow_add(struct ovn_flow *d,
>                     struct ofputil_bundle_ctrl_msg *bc,
> diff --git a/controller/ofctrl.h b/controller/ofctrl.h
> index 014de210d..60eeb9dbb 100644
> --- a/controller/ofctrl.h
> +++ b/controller/ofctrl.h
> @@ -29,6 +29,7 @@ struct match;
>  struct ofpbuf;
>  struct ovsrec_bridge;
>  struct sbrec_meter_table;
> +struct sbrec_meter;
>  struct shash;
>
>  struct ovn_desired_flow_table {
> @@ -129,5 +130,6 @@ void ofctrl_check_and_add_flow_metered(struct ovn_desired_flow_table *,
>  bool ofctrl_is_connected(void);
>  void ofctrl_set_probe_interval(int probe_interval);
>  void ofctrl_get_memory_usage(struct simap *usage);
> +void update_meter(const struct sbrec_meter *meter);
>
>  #endif /* controller/ofctrl.h */
> diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
> index 29c1a05b2..f2fa6aee8 100644
> --- a/controller/ovn-controller.c
> +++ b/controller/ovn-controller.c
> @@ -76,6 +76,7 @@
>  #include "stopwatch.h"
>  #include "lib/inc-proc-eng.h"
>  #include "hmapx.h"
> +#include "openvswitch/ofp-util.h"
>
>  VLOG_DEFINE_THIS_MODULE(main);
>
> @@ -957,7 +958,8 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl)
>      SB_NODE(dhcpv6_options, "dhcpv6_options") \
>      SB_NODE(dns, "dns") \
>      SB_NODE(load_balancer, "load_balancer") \
> -    SB_NODE(fdb, "fdb")
> +    SB_NODE(fdb, "fdb") \
> +    SB_NODE(meter, "meter")
>
>  enum sb_engine_node {
>  #define SB_NODE(NAME, NAME_STR) SB_##NAME,
> @@ -1500,6 +1502,55 @@ addr_sets_sb_address_set_handler(struct engine_node *node, void *data)
>      return true;
>  }
>
> +struct ed_type_meter {
> +    bool change_tracked;
> +};
> +
> +static void *
> +en_meter_init(struct engine_node *node OVS_UNUSED,
> +              struct engine_arg *arg OVS_UNUSED)
> +{
> +    struct ed_type_meter *m = xzalloc(sizeof *m);
> +
> +    m->change_tracked = false;
> +    return m;
> +}
> +
> +static void
> +en_meter_cleanup(void *data OVS_UNUSED)
> +{
> +}
> +
> +static void
> +en_meter_run(struct engine_node *node, void *data)
> +{
> +    struct ed_type_meter *m = data;
> +
> +    engine_set_node_state(node, EN_UPDATED);
> +    m->change_tracked = false;
> +}
> +
> +static bool
> +meter_sb_meter_handler(struct engine_node *node, void *data)
> +{
> +    struct ovs_list msgs = OVS_LIST_INITIALIZER(&msgs);
> +    struct ed_type_meter *m = data;
> +
> +    struct sbrec_meter_table *m_table =
> +        (struct sbrec_meter_table *)EN_OVSDB_GET(
> +            engine_get_input("SB_meter", node));
> +
> +    const struct sbrec_meter *iter;
> +    SBREC_METER_TABLE_FOR_EACH_TRACKED (iter, m_table) {
> +        if (!sbrec_meter_is_deleted(iter) && !sbrec_meter_is_new(iter)) {
> +            update_meter(iter);
> +        }
> +    }
> +    m->change_tracked = true;
> +
> +    return true;
> +}
> +
>  struct ed_type_port_groups{
>      /* A copy of SB port_groups, each converted as a sset for efficient lport
>       * lookup. */
> @@ -3202,6 +3253,7 @@ main(int argc, char *argv[])
>      ENGINE_NODE(lflow_output, "logical_flow_output");
>      ENGINE_NODE(flow_output, "flow_output");
>      ENGINE_NODE(addr_sets, "addr_sets");
> +    ENGINE_NODE(meter, "meter");
>      ENGINE_NODE_WITH_CLEAR_TRACK_DATA(port_groups, "port_groups");
>
>  #define SB_NODE(NAME, NAME_STR) ENGINE_NODE_SB(NAME, NAME_STR);
> @@ -3216,6 +3268,7 @@ main(int argc, char *argv[])
>
>      engine_add_input(&en_addr_sets, &en_sb_address_set,
>                       addr_sets_sb_address_set_handler);
> +    engine_add_input(&en_meter, &en_sb_meter, meter_sb_meter_handler);

What is the reason to add a new meter engine node ?


>      engine_add_input(&en_port_groups, &en_sb_port_group,
>                       port_groups_sb_port_group_handler);
>      /* port_groups computation requires runtime_data's lbinding_data for the
> @@ -3289,6 +3342,7 @@ main(int argc, char *argv[])
>                       lflow_output_sb_load_balancer_handler);
>      engine_add_input(&en_lflow_output, &en_sb_fdb,
>                       lflow_output_sb_fdb_handler);
> +    engine_add_input(&en_lflow_output, &en_meter, NULL);

Instead of adding a new engine node,  you could have just added a
handler here i.e en_lflow_output_meter_handler().

What is the reason ?  Is it because when a sb meter is updated along
with some other sb change ( which results in a full
recompute) then the OF flow for the updated meter is not MODIFIED ?

If that is so,  then I think your approach makes sense.

Can you please add a test case scenario where in ovn-controller has to
process a sb meter update and an another update (which
results in full recompute, for example a chassis is added)  in the
same loop and the meter flow is updated accordingly ?

Numan

>
>      engine_add_input(&en_ct_zones, &en_ovs_open_vswitch, NULL);
>      engine_add_input(&en_ct_zones, &en_ovs_bridge, NULL);
> diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> index 7f6cb32dc..80d5192ca 100644
> --- a/tests/system-ovn.at
> +++ b/tests/system-ovn.at
> @@ -6667,8 +6667,25 @@ OVS_WAIT_UNTIL([
>      test "${n_reject}" = "2"
>  ])
>  kill $(pidof tcpdump)
> +rm -f reject.pcap
> +
> +# Let's update the meter
> +NS_EXEC([sw01], [tcpdump -l -n -i sw01 icmp -Q in > reject.pcap &])
> +check ovn-nbctl --may-exist meter-add acl-meter drop 10 pktps 0
> +ip netns exec sw01 scapy -H <<-EOF
> +p = IP(src="192.168.1.2", dst="192.168.1.1") / UDP(dport = 12345) / Raw(b"X"*64)
> +send (p, iface='sw01', loop = 0, verbose = 0, count = 100)
> +EOF
>
> +# 10pps + 1 burst size
> +OVS_WAIT_UNTIL([
> +    n_reject=$(grep unreachable reject.pcap | wc -l)
> +    test "${n_reject}" = "20"
> +])
> +
> +kill $(pidof tcpdump)
>  rm -f reject.pcap
> +
>  NS_EXEC([sw01], [tcpdump -l -n -i sw01 icmp -Q in > reject.pcap &])
>  check ovn-nbctl --wait=hv ls-copp-del sw0 reject
>
> --
> 2.31.1
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
Lorenzo Bianconi Dec. 3, 2021, 11:44 p.m. UTC | #2
> On Thu, Nov 25, 2021 at 12:05 PM Lorenzo Bianconi
> <lorenzo.bianconi@redhat.com> wrote:
> >
> > At the moment ovs meters are reconfigured by ovn just when a
> > new a meter is allocated while updates for an already allocated meter are
> > ignored. This issue can be easily verified with the following reproducer:
> >
> > $ovn-nbctl meter-add meter0 drop 10 pktps
> > $ovn-nbctl --log --meter=meter0 acl-add sw0 to-lport 1000 'tcp.dst == 80' drop
> > $ovn-nbctl --may-exist meter-add meter0 drop 20 pktps
> > $ovs-ofctl -O OpenFlow15 dump-meters br-int
> >
> > Fix the issue reconfiguring ovs meters even for ovn meters updates.
> > Related bz: https://bugzilla.redhat.com/show_bug.cgi?id=1939524
> >
> > Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
> 
> Hi Lorenzo,
> 
> Thanks for the fix.  Please see below for a few comments.

Hi Numan,

thx for review. I posted a RFC series to introduce a dedicated IP engine for ovn meters
(doing so we remove possible issues due to a full recompute).

https://patchwork.ozlabs.org/project/ovn/cover/cover.1638574680.git.lorenzo.bianconi@redhat.com/

Regards,
Lorenzo


> 
> Numan
> 
> > ---
> >  controller/ofctrl.c         | 70 +++++++++++++++++++++++++++----------
> >  controller/ofctrl.h         |  2 ++
> >  controller/ovn-controller.c | 56 ++++++++++++++++++++++++++++-
> >  tests/system-ovn.at         | 17 +++++++++
> >  4 files changed, 126 insertions(+), 19 deletions(-)
> >
> > diff --git a/controller/ofctrl.c b/controller/ofctrl.c
> > index 08fcfed8b..25c939fa3 100644
> > --- a/controller/ofctrl.c
> > +++ b/controller/ofctrl.c
> > @@ -1802,26 +1802,13 @@ add_meter_string(struct ovn_extend_table_info *m_desired,
> >  }
> >
> >  static void
> > -add_meter(struct ovn_extend_table_info *m_desired,
> > -          const struct sbrec_meter_table *meter_table,
> > -          struct ovs_list *msgs)
> > +alloc_meter_mod(struct ovn_extend_table_info *m,
> > +                const struct sbrec_meter *sb_meter,
> > +                struct ovs_list *msgs, bool update)
> >  {
> > -    const struct sbrec_meter *sb_meter;
> > -    SBREC_METER_TABLE_FOR_EACH (sb_meter, meter_table) {
> > -        if (!strcmp(m_desired->name, sb_meter->name)) {
> > -            break;
> > -        }
> > -    }
> > -
> > -    if (!sb_meter) {
> > -        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
> > -        VLOG_ERR_RL(&rl, "could not find meter named \"%s\"", m_desired->name);
> > -        return;
> > -    }
> > -
> >      struct ofputil_meter_mod mm;
> > -    mm.command = OFPMC13_ADD;
> > -    mm.meter.meter_id = m_desired->table_id;
> > +    mm.command = update ? OFPMC13_MODIFY : OFPMC13_ADD;
> > +    mm.meter.meter_id = m->table_id;
> >      mm.meter.flags = OFPMF13_STATS;
> >
> >      if (!strcmp(sb_meter->unit, "pktps")) {
> > @@ -1854,6 +1841,53 @@ add_meter(struct ovn_extend_table_info *m_desired,
> >      free(mm.meter.bands);
> >  }
> >
> > +void
> > +update_meter(const struct sbrec_meter *meter)
> > +{
> > +    struct ovs_list msgs = OVS_LIST_INITIALIZER(&msgs);
> > +    struct ovn_extend_table_info *m_iter;
> > +
> > +    HMAP_FOR_EACH (m_iter, hmap_node, &meters->desired) {
> > +        if (!strcmp(meter->name, m_iter->name) &&
> > +            ovn_extend_table_lookup(&meters->existing, m_iter)) {
> > +            alloc_meter_mod(m_iter, meter, &msgs, true);
> > +        }
> > +    }
> > +
> > +    if (!ovs_list_is_empty(&msgs)) {
> > +        /* Add a barrier to the list of messages. */
> > +        struct ofpbuf *barrier = ofputil_encode_barrier_request(OFP15_VERSION);
> > +
> > +        ovs_list_push_back(&msgs, &barrier->list_node);
> > +        /* Queue the messages. */
> > +        struct ofpbuf *msg;
> > +        LIST_FOR_EACH_POP (msg, list_node, &msgs) {
> > +            queue_msg(msg);
> > +        }
> > +    }
> > +}
> > +
> > +static void
> > +add_meter(struct ovn_extend_table_info *m_desired,
> > +          const struct sbrec_meter_table *meter_table,
> > +          struct ovs_list *msgs)
> > +{
> > +    const struct sbrec_meter *sb_meter;
> > +    SBREC_METER_TABLE_FOR_EACH (sb_meter, meter_table) {
> > +        if (!strcmp(m_desired->name, sb_meter->name)) {
> > +            break;
> > +        }
> > +    }
> > +
> > +    if (!sb_meter) {
> > +        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
> > +        VLOG_ERR_RL(&rl, "could not find meter named \"%s\"", m_desired->name);
> > +        return;
> > +    }
> > +
> > +    alloc_meter_mod(m_desired, sb_meter, msgs, false);
> > +}
> > +
> >  static void
> >  installed_flow_add(struct ovn_flow *d,
> >                     struct ofputil_bundle_ctrl_msg *bc,
> > diff --git a/controller/ofctrl.h b/controller/ofctrl.h
> > index 014de210d..60eeb9dbb 100644
> > --- a/controller/ofctrl.h
> > +++ b/controller/ofctrl.h
> > @@ -29,6 +29,7 @@ struct match;
> >  struct ofpbuf;
> >  struct ovsrec_bridge;
> >  struct sbrec_meter_table;
> > +struct sbrec_meter;
> >  struct shash;
> >
> >  struct ovn_desired_flow_table {
> > @@ -129,5 +130,6 @@ void ofctrl_check_and_add_flow_metered(struct ovn_desired_flow_table *,
> >  bool ofctrl_is_connected(void);
> >  void ofctrl_set_probe_interval(int probe_interval);
> >  void ofctrl_get_memory_usage(struct simap *usage);
> > +void update_meter(const struct sbrec_meter *meter);
> >
> >  #endif /* controller/ofctrl.h */
> > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
> > index 29c1a05b2..f2fa6aee8 100644
> > --- a/controller/ovn-controller.c
> > +++ b/controller/ovn-controller.c
> > @@ -76,6 +76,7 @@
> >  #include "stopwatch.h"
> >  #include "lib/inc-proc-eng.h"
> >  #include "hmapx.h"
> > +#include "openvswitch/ofp-util.h"
> >
> >  VLOG_DEFINE_THIS_MODULE(main);
> >
> > @@ -957,7 +958,8 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl)
> >      SB_NODE(dhcpv6_options, "dhcpv6_options") \
> >      SB_NODE(dns, "dns") \
> >      SB_NODE(load_balancer, "load_balancer") \
> > -    SB_NODE(fdb, "fdb")
> > +    SB_NODE(fdb, "fdb") \
> > +    SB_NODE(meter, "meter")
> >
> >  enum sb_engine_node {
> >  #define SB_NODE(NAME, NAME_STR) SB_##NAME,
> > @@ -1500,6 +1502,55 @@ addr_sets_sb_address_set_handler(struct engine_node *node, void *data)
> >      return true;
> >  }
> >
> > +struct ed_type_meter {
> > +    bool change_tracked;
> > +};
> > +
> > +static void *
> > +en_meter_init(struct engine_node *node OVS_UNUSED,
> > +              struct engine_arg *arg OVS_UNUSED)
> > +{
> > +    struct ed_type_meter *m = xzalloc(sizeof *m);
> > +
> > +    m->change_tracked = false;
> > +    return m;
> > +}
> > +
> > +static void
> > +en_meter_cleanup(void *data OVS_UNUSED)
> > +{
> > +}
> > +
> > +static void
> > +en_meter_run(struct engine_node *node, void *data)
> > +{
> > +    struct ed_type_meter *m = data;
> > +
> > +    engine_set_node_state(node, EN_UPDATED);
> > +    m->change_tracked = false;
> > +}
> > +
> > +static bool
> > +meter_sb_meter_handler(struct engine_node *node, void *data)
> > +{
> > +    struct ovs_list msgs = OVS_LIST_INITIALIZER(&msgs);
> > +    struct ed_type_meter *m = data;
> > +
> > +    struct sbrec_meter_table *m_table =
> > +        (struct sbrec_meter_table *)EN_OVSDB_GET(
> > +            engine_get_input("SB_meter", node));
> > +
> > +    const struct sbrec_meter *iter;
> > +    SBREC_METER_TABLE_FOR_EACH_TRACKED (iter, m_table) {
> > +        if (!sbrec_meter_is_deleted(iter) && !sbrec_meter_is_new(iter)) {
> > +            update_meter(iter);
> > +        }
> > +    }
> > +    m->change_tracked = true;
> > +
> > +    return true;
> > +}
> > +
> >  struct ed_type_port_groups{
> >      /* A copy of SB port_groups, each converted as a sset for efficient lport
> >       * lookup. */
> > @@ -3202,6 +3253,7 @@ main(int argc, char *argv[])
> >      ENGINE_NODE(lflow_output, "logical_flow_output");
> >      ENGINE_NODE(flow_output, "flow_output");
> >      ENGINE_NODE(addr_sets, "addr_sets");
> > +    ENGINE_NODE(meter, "meter");
> >      ENGINE_NODE_WITH_CLEAR_TRACK_DATA(port_groups, "port_groups");
> >
> >  #define SB_NODE(NAME, NAME_STR) ENGINE_NODE_SB(NAME, NAME_STR);
> > @@ -3216,6 +3268,7 @@ main(int argc, char *argv[])
> >
> >      engine_add_input(&en_addr_sets, &en_sb_address_set,
> >                       addr_sets_sb_address_set_handler);
> > +    engine_add_input(&en_meter, &en_sb_meter, meter_sb_meter_handler);
> 
> What is the reason to add a new meter engine node ?
> 
> 
> >      engine_add_input(&en_port_groups, &en_sb_port_group,
> >                       port_groups_sb_port_group_handler);
> >      /* port_groups computation requires runtime_data's lbinding_data for the
> > @@ -3289,6 +3342,7 @@ main(int argc, char *argv[])
> >                       lflow_output_sb_load_balancer_handler);
> >      engine_add_input(&en_lflow_output, &en_sb_fdb,
> >                       lflow_output_sb_fdb_handler);
> > +    engine_add_input(&en_lflow_output, &en_meter, NULL);
> 
> Instead of adding a new engine node,  you could have just added a
> handler here i.e en_lflow_output_meter_handler().
> 
> What is the reason ?  Is it because when a sb meter is updated along
> with some other sb change ( which results in a full
> recompute) then the OF flow for the updated meter is not MODIFIED ?
> 
> If that is so,  then I think your approach makes sense.
> 
> Can you please add a test case scenario where in ovn-controller has to
> process a sb meter update and an another update (which
> results in full recompute, for example a chassis is added)  in the
> same loop and the meter flow is updated accordingly ?
> 
> Numan
> 
> >
> >      engine_add_input(&en_ct_zones, &en_ovs_open_vswitch, NULL);
> >      engine_add_input(&en_ct_zones, &en_ovs_bridge, NULL);
> > diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> > index 7f6cb32dc..80d5192ca 100644
> > --- a/tests/system-ovn.at
> > +++ b/tests/system-ovn.at
> > @@ -6667,8 +6667,25 @@ OVS_WAIT_UNTIL([
> >      test "${n_reject}" = "2"
> >  ])
> >  kill $(pidof tcpdump)
> > +rm -f reject.pcap
> > +
> > +# Let's update the meter
> > +NS_EXEC([sw01], [tcpdump -l -n -i sw01 icmp -Q in > reject.pcap &])
> > +check ovn-nbctl --may-exist meter-add acl-meter drop 10 pktps 0
> > +ip netns exec sw01 scapy -H <<-EOF
> > +p = IP(src="192.168.1.2", dst="192.168.1.1") / UDP(dport = 12345) / Raw(b"X"*64)
> > +send (p, iface='sw01', loop = 0, verbose = 0, count = 100)
> > +EOF
> >
> > +# 10pps + 1 burst size
> > +OVS_WAIT_UNTIL([
> > +    n_reject=$(grep unreachable reject.pcap | wc -l)
> > +    test "${n_reject}" = "20"
> > +])
> > +
> > +kill $(pidof tcpdump)
> >  rm -f reject.pcap
> > +
> >  NS_EXEC([sw01], [tcpdump -l -n -i sw01 icmp -Q in > reject.pcap &])
> >  check ovn-nbctl --wait=hv ls-copp-del sw0 reject
> >
> > --
> > 2.31.1
> >
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
>
diff mbox series

Patch

diff --git a/controller/ofctrl.c b/controller/ofctrl.c
index 08fcfed8b..25c939fa3 100644
--- a/controller/ofctrl.c
+++ b/controller/ofctrl.c
@@ -1802,26 +1802,13 @@  add_meter_string(struct ovn_extend_table_info *m_desired,
 }
 
 static void
-add_meter(struct ovn_extend_table_info *m_desired,
-          const struct sbrec_meter_table *meter_table,
-          struct ovs_list *msgs)
+alloc_meter_mod(struct ovn_extend_table_info *m,
+                const struct sbrec_meter *sb_meter,
+                struct ovs_list *msgs, bool update)
 {
-    const struct sbrec_meter *sb_meter;
-    SBREC_METER_TABLE_FOR_EACH (sb_meter, meter_table) {
-        if (!strcmp(m_desired->name, sb_meter->name)) {
-            break;
-        }
-    }
-
-    if (!sb_meter) {
-        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
-        VLOG_ERR_RL(&rl, "could not find meter named \"%s\"", m_desired->name);
-        return;
-    }
-
     struct ofputil_meter_mod mm;
-    mm.command = OFPMC13_ADD;
-    mm.meter.meter_id = m_desired->table_id;
+    mm.command = update ? OFPMC13_MODIFY : OFPMC13_ADD;
+    mm.meter.meter_id = m->table_id;
     mm.meter.flags = OFPMF13_STATS;
 
     if (!strcmp(sb_meter->unit, "pktps")) {
@@ -1854,6 +1841,53 @@  add_meter(struct ovn_extend_table_info *m_desired,
     free(mm.meter.bands);
 }
 
+void
+update_meter(const struct sbrec_meter *meter)
+{
+    struct ovs_list msgs = OVS_LIST_INITIALIZER(&msgs);
+    struct ovn_extend_table_info *m_iter;
+
+    HMAP_FOR_EACH (m_iter, hmap_node, &meters->desired) {
+        if (!strcmp(meter->name, m_iter->name) &&
+            ovn_extend_table_lookup(&meters->existing, m_iter)) {
+            alloc_meter_mod(m_iter, meter, &msgs, true);
+        }
+    }
+
+    if (!ovs_list_is_empty(&msgs)) {
+        /* Add a barrier to the list of messages. */
+        struct ofpbuf *barrier = ofputil_encode_barrier_request(OFP15_VERSION);
+
+        ovs_list_push_back(&msgs, &barrier->list_node);
+        /* Queue the messages. */
+        struct ofpbuf *msg;
+        LIST_FOR_EACH_POP (msg, list_node, &msgs) {
+            queue_msg(msg);
+        }
+    }
+}
+
+static void
+add_meter(struct ovn_extend_table_info *m_desired,
+          const struct sbrec_meter_table *meter_table,
+          struct ovs_list *msgs)
+{
+    const struct sbrec_meter *sb_meter;
+    SBREC_METER_TABLE_FOR_EACH (sb_meter, meter_table) {
+        if (!strcmp(m_desired->name, sb_meter->name)) {
+            break;
+        }
+    }
+
+    if (!sb_meter) {
+        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+        VLOG_ERR_RL(&rl, "could not find meter named \"%s\"", m_desired->name);
+        return;
+    }
+
+    alloc_meter_mod(m_desired, sb_meter, msgs, false);
+}
+
 static void
 installed_flow_add(struct ovn_flow *d,
                    struct ofputil_bundle_ctrl_msg *bc,
diff --git a/controller/ofctrl.h b/controller/ofctrl.h
index 014de210d..60eeb9dbb 100644
--- a/controller/ofctrl.h
+++ b/controller/ofctrl.h
@@ -29,6 +29,7 @@  struct match;
 struct ofpbuf;
 struct ovsrec_bridge;
 struct sbrec_meter_table;
+struct sbrec_meter;
 struct shash;
 
 struct ovn_desired_flow_table {
@@ -129,5 +130,6 @@  void ofctrl_check_and_add_flow_metered(struct ovn_desired_flow_table *,
 bool ofctrl_is_connected(void);
 void ofctrl_set_probe_interval(int probe_interval);
 void ofctrl_get_memory_usage(struct simap *usage);
+void update_meter(const struct sbrec_meter *meter);
 
 #endif /* controller/ofctrl.h */
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index 29c1a05b2..f2fa6aee8 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -76,6 +76,7 @@ 
 #include "stopwatch.h"
 #include "lib/inc-proc-eng.h"
 #include "hmapx.h"
+#include "openvswitch/ofp-util.h"
 
 VLOG_DEFINE_THIS_MODULE(main);
 
@@ -957,7 +958,8 @@  ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl)
     SB_NODE(dhcpv6_options, "dhcpv6_options") \
     SB_NODE(dns, "dns") \
     SB_NODE(load_balancer, "load_balancer") \
-    SB_NODE(fdb, "fdb")
+    SB_NODE(fdb, "fdb") \
+    SB_NODE(meter, "meter")
 
 enum sb_engine_node {
 #define SB_NODE(NAME, NAME_STR) SB_##NAME,
@@ -1500,6 +1502,55 @@  addr_sets_sb_address_set_handler(struct engine_node *node, void *data)
     return true;
 }
 
+struct ed_type_meter {
+    bool change_tracked;
+};
+
+static void *
+en_meter_init(struct engine_node *node OVS_UNUSED,
+              struct engine_arg *arg OVS_UNUSED)
+{
+    struct ed_type_meter *m = xzalloc(sizeof *m);
+
+    m->change_tracked = false;
+    return m;
+}
+
+static void
+en_meter_cleanup(void *data OVS_UNUSED)
+{
+}
+
+static void
+en_meter_run(struct engine_node *node, void *data)
+{
+    struct ed_type_meter *m = data;
+
+    engine_set_node_state(node, EN_UPDATED);
+    m->change_tracked = false;
+}
+
+static bool
+meter_sb_meter_handler(struct engine_node *node, void *data)
+{
+    struct ovs_list msgs = OVS_LIST_INITIALIZER(&msgs);
+    struct ed_type_meter *m = data;
+
+    struct sbrec_meter_table *m_table =
+        (struct sbrec_meter_table *)EN_OVSDB_GET(
+            engine_get_input("SB_meter", node));
+
+    const struct sbrec_meter *iter;
+    SBREC_METER_TABLE_FOR_EACH_TRACKED (iter, m_table) {
+        if (!sbrec_meter_is_deleted(iter) && !sbrec_meter_is_new(iter)) {
+            update_meter(iter);
+        }
+    }
+    m->change_tracked = true;
+
+    return true;
+}
+
 struct ed_type_port_groups{
     /* A copy of SB port_groups, each converted as a sset for efficient lport
      * lookup. */
@@ -3202,6 +3253,7 @@  main(int argc, char *argv[])
     ENGINE_NODE(lflow_output, "logical_flow_output");
     ENGINE_NODE(flow_output, "flow_output");
     ENGINE_NODE(addr_sets, "addr_sets");
+    ENGINE_NODE(meter, "meter");
     ENGINE_NODE_WITH_CLEAR_TRACK_DATA(port_groups, "port_groups");
 
 #define SB_NODE(NAME, NAME_STR) ENGINE_NODE_SB(NAME, NAME_STR);
@@ -3216,6 +3268,7 @@  main(int argc, char *argv[])
 
     engine_add_input(&en_addr_sets, &en_sb_address_set,
                      addr_sets_sb_address_set_handler);
+    engine_add_input(&en_meter, &en_sb_meter, meter_sb_meter_handler);
     engine_add_input(&en_port_groups, &en_sb_port_group,
                      port_groups_sb_port_group_handler);
     /* port_groups computation requires runtime_data's lbinding_data for the
@@ -3289,6 +3342,7 @@  main(int argc, char *argv[])
                      lflow_output_sb_load_balancer_handler);
     engine_add_input(&en_lflow_output, &en_sb_fdb,
                      lflow_output_sb_fdb_handler);
+    engine_add_input(&en_lflow_output, &en_meter, NULL);
 
     engine_add_input(&en_ct_zones, &en_ovs_open_vswitch, NULL);
     engine_add_input(&en_ct_zones, &en_ovs_bridge, NULL);
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index 7f6cb32dc..80d5192ca 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -6667,8 +6667,25 @@  OVS_WAIT_UNTIL([
     test "${n_reject}" = "2"
 ])
 kill $(pidof tcpdump)
+rm -f reject.pcap
+
+# Let's update the meter
+NS_EXEC([sw01], [tcpdump -l -n -i sw01 icmp -Q in > reject.pcap &])
+check ovn-nbctl --may-exist meter-add acl-meter drop 10 pktps 0
+ip netns exec sw01 scapy -H <<-EOF
+p = IP(src="192.168.1.2", dst="192.168.1.1") / UDP(dport = 12345) / Raw(b"X"*64)
+send (p, iface='sw01', loop = 0, verbose = 0, count = 100)
+EOF
 
+# 10pps + 1 burst size
+OVS_WAIT_UNTIL([
+    n_reject=$(grep unreachable reject.pcap | wc -l)
+    test "${n_reject}" = "20"
+])
+
+kill $(pidof tcpdump)
 rm -f reject.pcap
+
 NS_EXEC([sw01], [tcpdump -l -n -i sw01 icmp -Q in > reject.pcap &])
 check ovn-nbctl --wait=hv ls-copp-del sw0 reject