Re: [ovs-dev] [PATCH] ovn: Discard flows for non-local ports.
Wow, amazing, that makes sense. I also ran manual tests locally and everything seemed fine. On Tue, Sep 19, 2017 at 6:22 PM, Russell Bryantwrote: > On Tue, Sep 19, 2017 at 9:38 AM, Russell Bryant wrote: > > On Mon, Sep 18, 2017 at 7:31 PM, Han Zhou wrote: > >> Thanks Russell for the quick work! > >> > >> On Mon, Sep 18, 2017 at 8:24 AM, Russell Bryant > wrote: > >> > >>> @@ -301,6 +305,22 @@ consider_logical_flow(struct controller_ctx *ctx, > >>> if (m->match.wc.masks.conj_id) { > >>> m->match.flow.conj_id += *conj_id_ofs; > >>> } > >>> +if (is_switch(ldp)) { > >>> +unsigned int reg_index > >>> += (ingress ? MFF_LOG_INPORT : MFF_LOG_OUTPORT) - > >>> MFF_REG0; > >>> +int64_t port_id = m->match.flow.regs[reg_index]; > >>> +if (port_id) { > >>> +int64_t dp_id = lflow->logical_datapath->tunnel_key; > >>> +char buf[16]; > >>> +snprintf(buf, sizeof(buf), "%"PRId64"_%"PRId64, dp_id, > >>> port_id); > >>> +if (!sset_contains(local_lport_ids, buf)) { > >>> +//VLOG_INFO("Matching on port id %"PRId64" dp > >>> %"PRId64", is NOT local", port_id, dp_id); > >>> +continue; > >>> +} else { > >>> +//VLOG_INFO("Matching on port id %"PRId64" dp > >>> %"PRId64", is local", port_id, dp_id); > >>> +} > >>> +} > >>> +} > >>> if (!m->n) { > >>> ofctrl_add_flow(flow_table, ptable, lflow->priority, > >>> lflow->header_.uuid.parts[0], >match, > >>> ); > >> > >> I remember the expr_parse_string() is one of the biggest cost in > >> ovn-controller, so I wonder would it be better to move the check for > >> local_lport_ids before the parse happens, i.e. check against logical > flows > >> instead of ovs flows? > > > > Yes, that may be better. This was just a quick fix for the memory > > consumption issue. There is also a small improvement to CPU usage in > > my basic testing. I created 1000 ports with ACLs that used a 1000 > > member address set. Only one port was local. It finished about 10% > > faster with the patch. > > > > Moving this to before the logical flow to OpenFlow translation would > > obviously be better, but it's not quite straight forward. It's easy > > if you make assumptions about what the expression looks like, but > > doing it in a general way seems just as complicated as the existing > > expression parser. > > > >> Acked-by: Han Zhou > > > > Thanks! > > > > I think I'll do a bit more testing before applying this. I'm also not > > sure how far this should be backported. The memory usage is bad > > enough with the default OpenStack security groups on large networks > > that I tend to think this should go back to 2.8 and 2.7 as well. > > I ran this patch through OpenStack CI and it works there too. I > applied this to master, branch-2.8, and branch-2.7. > > I think the next piece that makes sense is looking at improving use of > conjunctive flows. > > -- > Russell Bryant > ___ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev
Re: [ovs-dev] [PATCH] ovn: Discard flows for non-local ports.
On Tue, Sep 19, 2017 at 9:38 AM, Russell Bryantwrote: > On Mon, Sep 18, 2017 at 7:31 PM, Han Zhou wrote: >> Thanks Russell for the quick work! >> >> On Mon, Sep 18, 2017 at 8:24 AM, Russell Bryant wrote: >> >>> @@ -301,6 +305,22 @@ consider_logical_flow(struct controller_ctx *ctx, >>> if (m->match.wc.masks.conj_id) { >>> m->match.flow.conj_id += *conj_id_ofs; >>> } >>> +if (is_switch(ldp)) { >>> +unsigned int reg_index >>> += (ingress ? MFF_LOG_INPORT : MFF_LOG_OUTPORT) - >>> MFF_REG0; >>> +int64_t port_id = m->match.flow.regs[reg_index]; >>> +if (port_id) { >>> +int64_t dp_id = lflow->logical_datapath->tunnel_key; >>> +char buf[16]; >>> +snprintf(buf, sizeof(buf), "%"PRId64"_%"PRId64, dp_id, >>> port_id); >>> +if (!sset_contains(local_lport_ids, buf)) { >>> +//VLOG_INFO("Matching on port id %"PRId64" dp >>> %"PRId64", is NOT local", port_id, dp_id); >>> +continue; >>> +} else { >>> +//VLOG_INFO("Matching on port id %"PRId64" dp >>> %"PRId64", is local", port_id, dp_id); >>> +} >>> +} >>> +} >>> if (!m->n) { >>> ofctrl_add_flow(flow_table, ptable, lflow->priority, >>> lflow->header_.uuid.parts[0], >match, >>> ); >> >> I remember the expr_parse_string() is one of the biggest cost in >> ovn-controller, so I wonder would it be better to move the check for >> local_lport_ids before the parse happens, i.e. check against logical flows >> instead of ovs flows? > > Yes, that may be better. This was just a quick fix for the memory > consumption issue. There is also a small improvement to CPU usage in > my basic testing. I created 1000 ports with ACLs that used a 1000 > member address set. Only one port was local. It finished about 10% > faster with the patch. > > Moving this to before the logical flow to OpenFlow translation would > obviously be better, but it's not quite straight forward. It's easy > if you make assumptions about what the expression looks like, but > doing it in a general way seems just as complicated as the existing > expression parser. > >> Acked-by: Han Zhou > > Thanks! > > I think I'll do a bit more testing before applying this. I'm also not > sure how far this should be backported. The memory usage is bad > enough with the default OpenStack security groups on large networks > that I tend to think this should go back to 2.8 and 2.7 as well. I ran this patch through OpenStack CI and it works there too. I applied this to master, branch-2.8, and branch-2.7. I think the next piece that makes sense is looking at improving use of conjunctive flows. -- Russell Bryant ___ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev
Re: [ovs-dev] [PATCH] ovn: Discard flows for non-local ports.
On Mon, Sep 18, 2017 at 7:31 PM, Han Zhouwrote: > Thanks Russell for the quick work! > > On Mon, Sep 18, 2017 at 8:24 AM, Russell Bryant wrote: > >> @@ -301,6 +305,22 @@ consider_logical_flow(struct controller_ctx *ctx, >> if (m->match.wc.masks.conj_id) { >> m->match.flow.conj_id += *conj_id_ofs; >> } >> +if (is_switch(ldp)) { >> +unsigned int reg_index >> += (ingress ? MFF_LOG_INPORT : MFF_LOG_OUTPORT) - >> MFF_REG0; >> +int64_t port_id = m->match.flow.regs[reg_index]; >> +if (port_id) { >> +int64_t dp_id = lflow->logical_datapath->tunnel_key; >> +char buf[16]; >> +snprintf(buf, sizeof(buf), "%"PRId64"_%"PRId64, dp_id, >> port_id); >> +if (!sset_contains(local_lport_ids, buf)) { >> +//VLOG_INFO("Matching on port id %"PRId64" dp >> %"PRId64", is NOT local", port_id, dp_id); >> +continue; >> +} else { >> +//VLOG_INFO("Matching on port id %"PRId64" dp >> %"PRId64", is local", port_id, dp_id); >> +} >> +} >> +} >> if (!m->n) { >> ofctrl_add_flow(flow_table, ptable, lflow->priority, >> lflow->header_.uuid.parts[0], >match, >> ); > > I remember the expr_parse_string() is one of the biggest cost in > ovn-controller, so I wonder would it be better to move the check for > local_lport_ids before the parse happens, i.e. check against logical flows > instead of ovs flows? Yes, that may be better. This was just a quick fix for the memory consumption issue. There is also a small improvement to CPU usage in my basic testing. I created 1000 ports with ACLs that used a 1000 member address set. Only one port was local. It finished about 10% faster with the patch. Moving this to before the logical flow to OpenFlow translation would obviously be better, but it's not quite straight forward. It's easy if you make assumptions about what the expression looks like, but doing it in a general way seems just as complicated as the existing expression parser. > Acked-by: Han Zhou Thanks! I think I'll do a bit more testing before applying this. I'm also not sure how far this should be backported. The memory usage is bad enough with the default OpenStack security groups on large networks that I tend to think this should go back to 2.8 and 2.7 as well. -- Russell Bryant ___ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev
Re: [ovs-dev] [PATCH] ovn: Discard flows for non-local ports.
Thanks Russell for the quick work! On Mon, Sep 18, 2017 at 8:24 AM, Russell Bryantwrote: > @@ -301,6 +305,22 @@ consider_logical_flow(struct controller_ctx *ctx, > if (m->match.wc.masks.conj_id) { > m->match.flow.conj_id += *conj_id_ofs; > } > +if (is_switch(ldp)) { > +unsigned int reg_index > += (ingress ? MFF_LOG_INPORT : MFF_LOG_OUTPORT) - MFF_REG0; > +int64_t port_id = m->match.flow.regs[reg_index]; > +if (port_id) { > +int64_t dp_id = lflow->logical_datapath->tunnel_key; > +char buf[16]; > +snprintf(buf, sizeof(buf), "%"PRId64"_%"PRId64, dp_id, port_id); > +if (!sset_contains(local_lport_ids, buf)) { > +//VLOG_INFO("Matching on port id %"PRId64" dp %"PRId64", is NOT local", port_id, dp_id); > +continue; > +} else { > +//VLOG_INFO("Matching on port id %"PRId64" dp %"PRId64", is local", port_id, dp_id); > +} > +} > +} > if (!m->n) { > ofctrl_add_flow(flow_table, ptable, lflow->priority, > lflow->header_.uuid.parts[0], >match, ); I remember the expr_parse_string() is one of the biggest cost in ovn-controller, so I wonder would it be better to move the check for local_lport_ids before the parse happens, i.e. check against logical flows instead of ovs flows? Acked-by: Han Zhou ___ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev
Re: [ovs-dev] [PATCH] ovn: Discard flows for non-local ports.
On Mon, Sep 18, 2017 at 11:24 AM, Russell Bryantwrote: > Discard some OpenFlow flows that will never match. This includes > flows that match on a non-local inport in the ingress pipeline or a > non-local outport in the egress pipeline of a logical switch. > > This is most useful for networks with a large number of ports or ACLs > that use large address sets. > > Signed-off-by: Russell Bryant > Tested-by: Miguel Angel Ajo Pelayo > --- > ovn/controller/binding.c| 29 + > ovn/controller/binding.h| 2 +- > ovn/controller/lflow.c | 33 +++-- > ovn/controller/lflow.h | 3 ++- > ovn/controller/ovn-controller.c | 9 +++-- > 5 files changed, 62 insertions(+), 14 deletions(-) > > diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c > index ca1d43395..3532c6014 100644 > --- a/ovn/controller/binding.c > +++ b/ovn/controller/binding.c > @@ -371,6 +371,17 @@ setup_qos(const char *egress_iface, struct hmap > *queue_map) > } > > static void > +update_local_lport_ids(struct sset *local_lport_ids, > + const struct sbrec_port_binding *binding_rec) > +{ > +char buf[16]; > +snprintf(buf, sizeof(buf), "%"PRId64"_%"PRId64, > + binding_rec->datapath->tunnel_key, > + binding_rec->tunnel_key); > +sset_add(local_lport_ids, buf); > +} > + > +static void > consider_local_datapath(struct controller_ctx *ctx, > const struct chassis_index *chassis_index, > struct sset *active_tunnels, > @@ -379,7 +390,8 @@ consider_local_datapath(struct controller_ctx *ctx, > struct hmap *qos_map, > struct hmap *local_datapaths, > struct shash *lport_to_iface, > -struct sset *local_lports) > +struct sset *local_lports, > +struct sset *local_lport_ids) > { > const struct ovsrec_interface *iface_rec > = shash_find_data(lport_to_iface, binding_rec->logical_port); > @@ -399,7 +411,7 @@ consider_local_datapath(struct controller_ctx *ctx, > get_qos_params(binding_rec, qos_map); > } > /* This port is in our chassis unless it is a localport. */ > - if (strcmp(binding_rec->type, "localport")) { > +if (strcmp(binding_rec->type, "localport")) { > our_chassis = true; > } > } else if (!strcmp(binding_rec->type, "l2gateway")) { > @@ -439,6 +451,14 @@ consider_local_datapath(struct controller_ctx *ctx, > our_chassis = false; > } > > +if (our_chassis > +|| !strcmp(binding_rec->type, "patch") > +|| !strcmp(binding_rec->type, "localport") > +|| !strcmp(binding_rec->type, "vtep") > +|| !strcmp(binding_rec->type, "localnet")) { > +update_local_lport_ids(local_lport_ids, binding_rec); > +} > + > if (ctx->ovnsb_idl_txn) { > const char *vif_chassis = smap_get(_rec->options, > "requested-chassis"); > @@ -508,7 +528,8 @@ binding_run(struct controller_ctx *ctx, const struct > ovsrec_bridge *br_int, > const struct sbrec_chassis *chassis_rec, > const struct chassis_index *chassis_index, > struct sset *active_tunnels, > -struct hmap *local_datapaths, struct sset *local_lports) > +struct hmap *local_datapaths, struct sset *local_lports, > +struct sset *local_lport_ids) > { > if (!chassis_rec) { > return; > @@ -533,7 +554,7 @@ binding_run(struct controller_ctx *ctx, const struct > ovsrec_bridge *br_int, > active_tunnels, chassis_rec, binding_rec, > sset_is_empty(_ifaces) ? NULL : > _map, local_datapaths, _to_iface, > -local_lports); > +local_lports, local_lport_ids); > > } > > diff --git a/ovn/controller/binding.h b/ovn/controller/binding.h > index c78f8d932..89fc2ec8f 100644 > --- a/ovn/controller/binding.h > +++ b/ovn/controller/binding.h > @@ -32,7 +32,7 @@ void binding_run(struct controller_ctx *, const struct > ovsrec_bridge *br_int, > const struct sbrec_chassis *, > const struct chassis_index *, > struct sset *active_tunnels, struct hmap *local_datapaths, > - struct sset *all_lports); > + struct sset *local_lports, struct sset *local_lport_ids); > bool binding_cleanup(struct controller_ctx *, const struct sbrec_chassis *); > > #endif /* ovn/binding.h */ > diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c > index 6d9f02cb2..c1f5de2ab 100644 > --- a/ovn/controller/lflow.c > +++
[ovs-dev] [PATCH] ovn: Discard flows for non-local ports.
Discard some OpenFlow flows that will never match. This includes flows that match on a non-local inport in the ingress pipeline or a non-local outport in the egress pipeline of a logical switch. This is most useful for networks with a large number of ports or ACLs that use large address sets. Signed-off-by: Russell BryantTested-by: Miguel Angel Ajo Pelayo --- ovn/controller/binding.c| 29 + ovn/controller/binding.h| 2 +- ovn/controller/lflow.c | 33 +++-- ovn/controller/lflow.h | 3 ++- ovn/controller/ovn-controller.c | 9 +++-- 5 files changed, 62 insertions(+), 14 deletions(-) diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c index ca1d43395..3532c6014 100644 --- a/ovn/controller/binding.c +++ b/ovn/controller/binding.c @@ -371,6 +371,17 @@ setup_qos(const char *egress_iface, struct hmap *queue_map) } static void +update_local_lport_ids(struct sset *local_lport_ids, + const struct sbrec_port_binding *binding_rec) +{ +char buf[16]; +snprintf(buf, sizeof(buf), "%"PRId64"_%"PRId64, + binding_rec->datapath->tunnel_key, + binding_rec->tunnel_key); +sset_add(local_lport_ids, buf); +} + +static void consider_local_datapath(struct controller_ctx *ctx, const struct chassis_index *chassis_index, struct sset *active_tunnels, @@ -379,7 +390,8 @@ consider_local_datapath(struct controller_ctx *ctx, struct hmap *qos_map, struct hmap *local_datapaths, struct shash *lport_to_iface, -struct sset *local_lports) +struct sset *local_lports, +struct sset *local_lport_ids) { const struct ovsrec_interface *iface_rec = shash_find_data(lport_to_iface, binding_rec->logical_port); @@ -399,7 +411,7 @@ consider_local_datapath(struct controller_ctx *ctx, get_qos_params(binding_rec, qos_map); } /* This port is in our chassis unless it is a localport. */ - if (strcmp(binding_rec->type, "localport")) { +if (strcmp(binding_rec->type, "localport")) { our_chassis = true; } } else if (!strcmp(binding_rec->type, "l2gateway")) { @@ -439,6 +451,14 @@ consider_local_datapath(struct controller_ctx *ctx, our_chassis = false; } +if (our_chassis +|| !strcmp(binding_rec->type, "patch") +|| !strcmp(binding_rec->type, "localport") +|| !strcmp(binding_rec->type, "vtep") +|| !strcmp(binding_rec->type, "localnet")) { +update_local_lport_ids(local_lport_ids, binding_rec); +} + if (ctx->ovnsb_idl_txn) { const char *vif_chassis = smap_get(_rec->options, "requested-chassis"); @@ -508,7 +528,8 @@ binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int, const struct sbrec_chassis *chassis_rec, const struct chassis_index *chassis_index, struct sset *active_tunnels, -struct hmap *local_datapaths, struct sset *local_lports) +struct hmap *local_datapaths, struct sset *local_lports, +struct sset *local_lport_ids) { if (!chassis_rec) { return; @@ -533,7 +554,7 @@ binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int, active_tunnels, chassis_rec, binding_rec, sset_is_empty(_ifaces) ? NULL : _map, local_datapaths, _to_iface, -local_lports); +local_lports, local_lport_ids); } diff --git a/ovn/controller/binding.h b/ovn/controller/binding.h index c78f8d932..89fc2ec8f 100644 --- a/ovn/controller/binding.h +++ b/ovn/controller/binding.h @@ -32,7 +32,7 @@ void binding_run(struct controller_ctx *, const struct ovsrec_bridge *br_int, const struct sbrec_chassis *, const struct chassis_index *, struct sset *active_tunnels, struct hmap *local_datapaths, - struct sset *all_lports); + struct sset *local_lports, struct sset *local_lport_ids); bool binding_cleanup(struct controller_ctx *, const struct sbrec_chassis *); #endif /* ovn/binding.h */ diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c index 6d9f02cb2..c1f5de2ab 100644 --- a/ovn/controller/lflow.c +++ b/ovn/controller/lflow.c @@ -68,7 +68,8 @@ static void consider_logical_flow(struct controller_ctx *ctx, uint32_t *conj_id_ofs, const struct shash *addr_sets, struct hmap *flow_table, -