Message ID | 20241015135305.2140051-1-xsimonar@redhat.com |
---|---|
State | Accepted |
Headers | show |
Series | [ovs-dev] controller: Delete flows on port delete/add. | expand |
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 |
On Tue, Oct 15, 2024 at 3:53 PM Xavier Simonart <xsimonar@redhat.com> wrote: > When a logical_port is deleted and added back, in two sb transactions > being handled within one ovn-controller loop, some flows belonging to > the deleted pb (such as flows in OFTABLE_CHK_IN_PORT_SEC) were not > properly deleted. > > Reported-at: https://issues.redhat.com/browse/FDP-873 > Signed-off-by: Xavier Simonart <xsimonar@redhat.com> > --- > controller/lflow.c | 3 +++ > controller/local_data.c | 26 ++++++++++++++++++++++++-- > tests/ovn.at | 40 ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 67 insertions(+), 2 deletions(-) > > diff --git a/controller/lflow.c b/controller/lflow.c > index 13c3a0d73..987de3f06 100644 > --- a/controller/lflow.c > +++ b/controller/lflow.c > @@ -2287,6 +2287,9 @@ lflow_handle_flows_for_lport(const struct > sbrec_port_binding *pb, > * port binding'uuid', then this function should handle it properly. > */ > ofctrl_remove_flows(l_ctx_out->flow_table, &pb->header_.uuid); > + if (sbrec_port_binding_is_deleted(pb)) { > + return true; > + } > > if (pb->n_port_security && shash_find(l_ctx_in->binding_lports, > pb->logical_port)) { > diff --git a/controller/local_data.c b/controller/local_data.c > index f889fb76b..9ee5d9171 100644 > --- a/controller/local_data.c > +++ b/controller/local_data.c > @@ -359,15 +359,37 @@ tracked_datapath_lport_add(const struct > sbrec_port_binding *pb, > } > > /* Check if the lport is already present or not. > - * If it is already present, then just update the 'pb' field. */ > + * If it is already present, then check whether it is the same pb. > + * We might have two different pb with the same logical_port if it was > + * deleted and added back within the same loop. > + * If the same pb was already present, just update the 'pb' field. > + * Otherwise, add the second pb */ > struct tracked_lport *lport = > shash_find_data(&tracked_dp->lports, pb->logical_port); > > if (!lport) { > lport = xmalloc(sizeof *lport); > shash_add(&tracked_dp->lports, pb->logical_port, lport); > + } else if (pb != lport->pb) { > + bool found = false; > + /* There is at least another pb with the same logical_port. > + * However, our pb might already be shash_added (e.g. pb1 > deleted, pb2 > + * added, pb2 deleted). This is not really optimal, but this loop > + * only runs in a very uncommon race condition (same logical port > + * deleted and added within same loop */ > + struct shash_node *node; > + SHASH_FOR_EACH (node, &tracked_dp->lports) { > + lport = (struct tracked_lport *) node->data; > + if (lport->pb == pb) { > + found = true; > + break; > + } > + } > + if (!found) { > + lport = xmalloc(sizeof *lport); > + shash_add(&tracked_dp->lports, pb->logical_port, lport); > + } > } > - > nit: Unrelated > lport->pb = pb; > lport->tracked_type = tracked_type; > } > diff --git a/tests/ovn.at b/tests/ovn.at > index d7f01169c..4835612ce 100644 > --- a/tests/ovn.at > +++ b/tests/ovn.at > @@ -39233,3 +39233,43 @@ OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) > OVN_CLEANUP([hv1]) > AT_CLEANUP > ]) > + > +OVN_FOR_EACH_NORTHD([ > +AT_SETUP([Port Deleted and added back]) > +ovn_start > + > +net_add n1 > + > +sim_add hv1 > +as hv1 > +ovs-vsctl add-br br-phys > +ovn_attach n1 br-phys 192.168.0.1 > +ovn-appctl vlog/set dbg > +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ > + set interface hv1-vif1 external-ids:iface-id=sw0-p1 \ > + options:tx_pcap=hv1/vif1-tx.pcap \ > + options:rxq_pcap=hv1/vif1-rx.pcap \ > + ofport-request=1 > + > +check ovn-nbctl ls-add sw0 > +check ovn-nbctl lsp-add sw0 sw0-p1 > +check ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03 2001::3" > +check ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03 2001::3" > + > +OVN_POPULATE_ARP > +wait_for_ports_up > +check ovn-nbctl --wait=hv sync > + > +# Delete sw0-p1 > +sleep_controller hv1 > +check ovn-nbctl --wait=sb lsp-del sw0-p1 > + > +# Add back sw0-p1 but without any address set. > +check ovn-nbctl --wait=sb lsp-add sw0 sw0-p1 > +wake_up_controller hv1 > + > +CHECK_FLOWS_AFTER_RECOMPUTE([hv1], [hv1]) > + > +OVN_CLEANUP([hv1]) > +AT_CLEANUP > +]) > -- > 2.31.1 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > Other than that it looks good to me. Acked-by: Ales Musil <amusil@redhat.com> Thanks, Ales
On Thu, Nov 7, 2024 at 3:20 AM Ales Musil <amusil@redhat.com> wrote: > > On Tue, Oct 15, 2024 at 3:53 PM Xavier Simonart <xsimonar@redhat.com> wrote: > > > When a logical_port is deleted and added back, in two sb transactions > > being handled within one ovn-controller loop, some flows belonging to > > the deleted pb (such as flows in OFTABLE_CHK_IN_PORT_SEC) were not > > properly deleted. > > > > Reported-at: https://issues.redhat.com/browse/FDP-873 > > Signed-off-by: Xavier Simonart <xsimonar@redhat.com> > > --- > > controller/lflow.c | 3 +++ > > controller/local_data.c | 26 ++++++++++++++++++++++++-- > > tests/ovn.at | 40 ++++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 67 insertions(+), 2 deletions(-) > > > > diff --git a/controller/lflow.c b/controller/lflow.c > > index 13c3a0d73..987de3f06 100644 > > --- a/controller/lflow.c > > +++ b/controller/lflow.c > > @@ -2287,6 +2287,9 @@ lflow_handle_flows_for_lport(const struct > > sbrec_port_binding *pb, > > * port binding'uuid', then this function should handle it properly. > > */ > > ofctrl_remove_flows(l_ctx_out->flow_table, &pb->header_.uuid); > > + if (sbrec_port_binding_is_deleted(pb)) { It doesn't seem right to check if 'pb' is deleted or not in this handler. So I did the below changes and applied this patch to main. ---- diff --git a/controller/lflow.c b/controller/lflow.c index 764200f357..6c49484f14 100644 --- a/controller/lflow.c +++ b/controller/lflow.c @@ -2269,7 +2269,8 @@ lflow_add_flows_for_datapath(const struct sbrec_datapath_binding *dp, bool lflow_handle_flows_for_lport(const struct sbrec_port_binding *pb, struct lflow_ctx_in *l_ctx_in, - struct lflow_ctx_out *l_ctx_out) + struct lflow_ctx_out *l_ctx_out, + bool deleted) { bool changed; @@ -2290,7 +2291,7 @@ lflow_handle_flows_for_lport(const struct sbrec_port_binding *pb, * port binding'uuid', then this function should handle it properly. */ ofctrl_remove_flows(l_ctx_out->flow_table, &pb->header_.uuid); - if (sbrec_port_binding_is_deleted(pb)) { + if (deleted) { return true; } diff --git a/controller/lflow.h b/controller/lflow.h index 58a12ee0fe..206328f9ec 100644 --- a/controller/lflow.h +++ b/controller/lflow.h @@ -190,7 +190,8 @@ bool lflow_add_flows_for_datapath(const struct sbrec_datapath_binding *, struct lflow_ctx_out *); bool lflow_handle_flows_for_lport(const struct sbrec_port_binding *, struct lflow_ctx_in *, - struct lflow_ctx_out *); + struct lflow_ctx_out *, + bool deleted); bool lflow_handle_changed_mc_groups(struct lflow_ctx_in *, struct lflow_ctx_out *); bool lflow_handle_changed_port_bindings(struct lflow_ctx_in *, diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 41db47fac8..187f600b1f 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -4271,8 +4271,9 @@ lflow_output_runtime_data_handler(struct engine_node *node, struct shash_node *shash_node; SHASH_FOR_EACH (shash_node, &tdp->lports) { struct tracked_lport *lport = shash_node->data; - if (!lflow_handle_flows_for_lport(lport->pb, &l_ctx_in, - &l_ctx_out)) { + if (!lflow_handle_flows_for_lport( + lport->pb, &l_ctx_in, &l_ctx_out, + lport->tracked_type == TRACKED_RESOURCE_REMOVED)) { return false; } } ---------------------- Thanks Numan > > + return true; > > + } > > > > if (pb->n_port_security && shash_find(l_ctx_in->binding_lports, > > pb->logical_port)) { > > diff --git a/controller/local_data.c b/controller/local_data.c > > index f889fb76b..9ee5d9171 100644 > > --- a/controller/local_data.c > > +++ b/controller/local_data.c > > @@ -359,15 +359,37 @@ tracked_datapath_lport_add(const struct > > sbrec_port_binding *pb, > > } > > > > /* Check if the lport is already present or not. > > - * If it is already present, then just update the 'pb' field. */ > > + * If it is already present, then check whether it is the same pb. > > + * We might have two different pb with the same logical_port if it was > > + * deleted and added back within the same loop. > > + * If the same pb was already present, just update the 'pb' field. > > + * Otherwise, add the second pb */ > > struct tracked_lport *lport = > > shash_find_data(&tracked_dp->lports, pb->logical_port); > > > > if (!lport) { > > lport = xmalloc(sizeof *lport); > > shash_add(&tracked_dp->lports, pb->logical_port, lport); > > + } else if (pb != lport->pb) { > > + bool found = false; > > + /* There is at least another pb with the same logical_port. > > + * However, our pb might already be shash_added (e.g. pb1 > > deleted, pb2 > > + * added, pb2 deleted). This is not really optimal, but this loop > > + * only runs in a very uncommon race condition (same logical port > > + * deleted and added within same loop */ > > + struct shash_node *node; > > + SHASH_FOR_EACH (node, &tracked_dp->lports) { > > + lport = (struct tracked_lport *) node->data; > > + if (lport->pb == pb) { > > + found = true; > > + break; > > + } > > + } > > + if (!found) { > > + lport = xmalloc(sizeof *lport); > > + shash_add(&tracked_dp->lports, pb->logical_port, lport); > > + } > > } > > - > > > > nit: Unrelated > > > > lport->pb = pb; > > lport->tracked_type = tracked_type; > > } > > diff --git a/tests/ovn.at b/tests/ovn.at > > index d7f01169c..4835612ce 100644 > > --- a/tests/ovn.at > > +++ b/tests/ovn.at > > @@ -39233,3 +39233,43 @@ OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) > > OVN_CLEANUP([hv1]) > > AT_CLEANUP > > ]) > > + > > +OVN_FOR_EACH_NORTHD([ > > +AT_SETUP([Port Deleted and added back]) > > +ovn_start > > + > > +net_add n1 > > + > > +sim_add hv1 > > +as hv1 > > +ovs-vsctl add-br br-phys > > +ovn_attach n1 br-phys 192.168.0.1 > > +ovn-appctl vlog/set dbg > > +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ > > + set interface hv1-vif1 external-ids:iface-id=sw0-p1 \ > > + options:tx_pcap=hv1/vif1-tx.pcap \ > > + options:rxq_pcap=hv1/vif1-rx.pcap \ > > + ofport-request=1 > > + > > +check ovn-nbctl ls-add sw0 > > +check ovn-nbctl lsp-add sw0 sw0-p1 > > +check ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03 2001::3" > > +check ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03 2001::3" > > + > > +OVN_POPULATE_ARP > > +wait_for_ports_up > > +check ovn-nbctl --wait=hv sync > > + > > +# Delete sw0-p1 > > +sleep_controller hv1 > > +check ovn-nbctl --wait=sb lsp-del sw0-p1 > > + > > +# Add back sw0-p1 but without any address set. > > +check ovn-nbctl --wait=sb lsp-add sw0 sw0-p1 > > +wake_up_controller hv1 > > + > > +CHECK_FLOWS_AFTER_RECOMPUTE([hv1], [hv1]) > > + > > +OVN_CLEANUP([hv1]) > > +AT_CLEANUP > > +]) > > -- > > 2.31.1 > > > > _______________________________________________ > > dev mailing list > > dev@openvswitch.org > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > > > > Other than that it looks good to me. > > Acked-by: Ales Musil <amusil@redhat.com> > > Thanks, > Ales > > -- > > Ales Musil > > Senior Software Engineer - OVN Core > > Red Hat EMEA <https://www.redhat.com> > > amusil@redhat.com > <https://red.ht/sig> > _______________________________________________ > dev mailing list > dev@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
diff --git a/controller/lflow.c b/controller/lflow.c index 13c3a0d73..987de3f06 100644 --- a/controller/lflow.c +++ b/controller/lflow.c @@ -2287,6 +2287,9 @@ lflow_handle_flows_for_lport(const struct sbrec_port_binding *pb, * port binding'uuid', then this function should handle it properly. */ ofctrl_remove_flows(l_ctx_out->flow_table, &pb->header_.uuid); + if (sbrec_port_binding_is_deleted(pb)) { + return true; + } if (pb->n_port_security && shash_find(l_ctx_in->binding_lports, pb->logical_port)) { diff --git a/controller/local_data.c b/controller/local_data.c index f889fb76b..9ee5d9171 100644 --- a/controller/local_data.c +++ b/controller/local_data.c @@ -359,15 +359,37 @@ tracked_datapath_lport_add(const struct sbrec_port_binding *pb, } /* Check if the lport is already present or not. - * If it is already present, then just update the 'pb' field. */ + * If it is already present, then check whether it is the same pb. + * We might have two different pb with the same logical_port if it was + * deleted and added back within the same loop. + * If the same pb was already present, just update the 'pb' field. + * Otherwise, add the second pb */ struct tracked_lport *lport = shash_find_data(&tracked_dp->lports, pb->logical_port); if (!lport) { lport = xmalloc(sizeof *lport); shash_add(&tracked_dp->lports, pb->logical_port, lport); + } else if (pb != lport->pb) { + bool found = false; + /* There is at least another pb with the same logical_port. + * However, our pb might already be shash_added (e.g. pb1 deleted, pb2 + * added, pb2 deleted). This is not really optimal, but this loop + * only runs in a very uncommon race condition (same logical port + * deleted and added within same loop */ + struct shash_node *node; + SHASH_FOR_EACH (node, &tracked_dp->lports) { + lport = (struct tracked_lport *) node->data; + if (lport->pb == pb) { + found = true; + break; + } + } + if (!found) { + lport = xmalloc(sizeof *lport); + shash_add(&tracked_dp->lports, pb->logical_port, lport); + } } - lport->pb = pb; lport->tracked_type = tracked_type; } diff --git a/tests/ovn.at b/tests/ovn.at index d7f01169c..4835612ce 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -39233,3 +39233,43 @@ OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) OVN_CLEANUP([hv1]) AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([Port Deleted and added back]) +ovn_start + +net_add n1 + +sim_add hv1 +as hv1 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +ovn-appctl vlog/set dbg +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ + set interface hv1-vif1 external-ids:iface-id=sw0-p1 \ + options:tx_pcap=hv1/vif1-tx.pcap \ + options:rxq_pcap=hv1/vif1-rx.pcap \ + ofport-request=1 + +check ovn-nbctl ls-add sw0 +check ovn-nbctl lsp-add sw0 sw0-p1 +check ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03 2001::3" +check ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03 2001::3" + +OVN_POPULATE_ARP +wait_for_ports_up +check ovn-nbctl --wait=hv sync + +# Delete sw0-p1 +sleep_controller hv1 +check ovn-nbctl --wait=sb lsp-del sw0-p1 + +# Add back sw0-p1 but without any address set. +check ovn-nbctl --wait=sb lsp-add sw0 sw0-p1 +wake_up_controller hv1 + +CHECK_FLOWS_AFTER_RECOMPUTE([hv1], [hv1]) + +OVN_CLEANUP([hv1]) +AT_CLEANUP +])
When a logical_port is deleted and added back, in two sb transactions being handled within one ovn-controller loop, some flows belonging to the deleted pb (such as flows in OFTABLE_CHK_IN_PORT_SEC) were not properly deleted. Reported-at: https://issues.redhat.com/browse/FDP-873 Signed-off-by: Xavier Simonart <xsimonar@redhat.com> --- controller/lflow.c | 3 +++ controller/local_data.c | 26 ++++++++++++++++++++++++-- tests/ovn.at | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 2 deletions(-)