|
|
ebb439 |
From 9ac0a75fd1995dee44f80ba4d7856cbf7b0e456d Mon Sep 17 00:00:00 2001
|
|
|
ebb439 |
From: Han Zhou <hzhou@ovn.org>
|
|
|
ebb439 |
Date: Thu, 1 Oct 2020 22:49:04 -0700
|
|
|
ebb439 |
Subject: [PATCH 1/7] ofctrl.c: Fix duplicated flow handling in I-P while
|
|
|
ebb439 |
merging opposite changes.
|
|
|
ebb439 |
|
|
|
ebb439 |
In a scenario in I-P when a desired flow is removed and an exactly same flow is
|
|
|
ebb439 |
added back in the same iteration, the merge_tracked_flows() function will merge
|
|
|
ebb439 |
the operation without firing any OpenFlow action. However, if there are
|
|
|
ebb439 |
multiple desired flows (e.g. F1 and F2) matching the same installed flow, and
|
|
|
ebb439 |
if the one being re-added (say, F1) is the one currently installed in OVS, the
|
|
|
ebb439 |
current implementation will update the currently installed flow to F2 in the
|
|
|
ebb439 |
data structure while the actual OVS flow is not updated (still F1). So far
|
|
|
ebb439 |
there is still no problem, but the member desired_flow of the installed flow
|
|
|
ebb439 |
is pointing to the wrong desired flow.
|
|
|
ebb439 |
|
|
|
ebb439 |
Now there is only one place where the desired_flow member is consulted, in
|
|
|
ebb439 |
update_installed_flows_by_track() for handling a tracked *modified* flow. In
|
|
|
ebb439 |
reality flow modification happens only when conjunction flows need to be
|
|
|
ebb439 |
combined, which would never happen together with the above scenario of
|
|
|
ebb439 |
merge_tracked_flows(). So this wrong desired_flow pointer doesn't cause any
|
|
|
ebb439 |
real problem yet.
|
|
|
ebb439 |
|
|
|
ebb439 |
However, there is a place that can already utilize this active desired_flow
|
|
|
ebb439 |
information, which is when handling a tracked flow deletion in
|
|
|
ebb439 |
update_installed_flows_by_track(): we can check if the flow being deleted is
|
|
|
ebb439 |
the currently active one installed in OVS. If not, we don't need to send and
|
|
|
ebb439 |
OpenFlow modify to OVS. This optimization is added in this patch, apart from
|
|
|
ebb439 |
fixing the problem of merge_tracked_flows(). Without the fix, this optimization
|
|
|
ebb439 |
would cause the test case added in this patch fail.
|
|
|
ebb439 |
|
|
|
ebb439 |
Fixes: f4e508dd7 ("ofctrl.c: Merge opposite changes of tracked flows before installing.")
|
|
|
ebb439 |
Acked-by: Dumitru Ceara <dceara@redhat.com>
|
|
|
ebb439 |
Signed-off-by: Han Zhou <hzhou@ovn.org>
|
|
|
ebb439 |
(cherry picked from upstream commit 9d2e8d32fb9865513b70408a665184a67564390d)
|
|
|
ebb439 |
|
|
|
ebb439 |
Change-Id: Ieb30dd8f4d07aae472c222920fcb773a1deace4d
|
|
|
ebb439 |
---
|
|
|
ebb439 |
controller/ofctrl.c | 28 +++++++++++++-
|
|
|
ebb439 |
tests/ovn.at | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
ebb439 |
2 files changed, 134 insertions(+), 2 deletions(-)
|
|
|
ebb439 |
|
|
|
ebb439 |
diff --git a/controller/ofctrl.c b/controller/ofctrl.c
|
|
|
ebb439 |
index 81a00c8..e725c00 100644
|
|
|
ebb439 |
--- a/controller/ofctrl.c
|
|
|
ebb439 |
+++ b/controller/ofctrl.c
|
|
|
ebb439 |
@@ -788,6 +788,24 @@ ofctrl_recv(const struct ofp_header *oh, enum ofptype type)
|
|
|
ebb439 |
}
|
|
|
ebb439 |
}
|
|
|
ebb439 |
|
|
|
ebb439 |
+/* Returns true if a desired flow is active (the one currently installed
|
|
|
ebb439 |
+ * among the list of desired flows that are linked to the same installed
|
|
|
ebb439 |
+ * flow). */
|
|
|
ebb439 |
+static inline bool
|
|
|
ebb439 |
+desired_flow_is_active(struct desired_flow *d)
|
|
|
ebb439 |
+{
|
|
|
ebb439 |
+ return (d->installed_flow && d->installed_flow->desired_flow == d);
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+/* Set a desired flow as the active one among the list of desired flows
|
|
|
ebb439 |
+ * that are linked to the same installed flow. */
|
|
|
ebb439 |
+static inline void
|
|
|
ebb439 |
+desired_flow_set_active(struct desired_flow *d)
|
|
|
ebb439 |
+{
|
|
|
ebb439 |
+ ovs_assert(d->installed_flow);
|
|
|
ebb439 |
+ d->installed_flow->desired_flow = d;
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
static void
|
|
|
ebb439 |
link_installed_to_desired(struct installed_flow *i, struct desired_flow *d)
|
|
|
ebb439 |
{
|
|
|
ebb439 |
@@ -1740,6 +1758,8 @@ merge_tracked_flows(struct ovn_desired_flow_table *flow_table)
|
|
|
ebb439 |
/* del_f must have been installed, otherwise it should have been
|
|
|
ebb439 |
* removed during track_flow_add_or_modify. */
|
|
|
ebb439 |
ovs_assert(del_f->installed_flow);
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ bool del_f_was_active = desired_flow_is_active(del_f);
|
|
|
ebb439 |
if (!f->installed_flow) {
|
|
|
ebb439 |
/* f is not installed yet. */
|
|
|
ebb439 |
struct installed_flow *i = del_f->installed_flow;
|
|
|
ebb439 |
@@ -1751,6 +1771,9 @@ merge_tracked_flows(struct ovn_desired_flow_table *flow_table)
|
|
|
ebb439 |
ovs_assert(f->installed_flow == del_f->installed_flow);
|
|
|
ebb439 |
unlink_installed_to_desired(del_f->installed_flow, del_f);
|
|
|
ebb439 |
}
|
|
|
ebb439 |
+ if (del_f_was_active) {
|
|
|
ebb439 |
+ desired_flow_set_active(f);
|
|
|
ebb439 |
+ }
|
|
|
ebb439 |
hmap_remove(&deleted_flows, &del_f->match_hmap_node);
|
|
|
ebb439 |
ovs_list_remove(&del_f->track_list_node);
|
|
|
ebb439 |
desired_flow_destroy(del_f);
|
|
|
ebb439 |
@@ -1778,6 +1801,7 @@ update_installed_flows_by_track(struct ovn_desired_flow_table *flow_table,
|
|
|
ebb439 |
/* The desired flow was deleted */
|
|
|
ebb439 |
if (f->installed_flow) {
|
|
|
ebb439 |
struct installed_flow *i = f->installed_flow;
|
|
|
ebb439 |
+ bool was_active = desired_flow_is_active(f);
|
|
|
ebb439 |
unlink_installed_to_desired(i, f);
|
|
|
ebb439 |
|
|
|
ebb439 |
if (!i->desired_flow) {
|
|
|
ebb439 |
@@ -1786,7 +1810,7 @@ update_installed_flows_by_track(struct ovn_desired_flow_table *flow_table,
|
|
|
ebb439 |
|
|
|
ebb439 |
hmap_remove(&installed_flows, &i->match_hmap_node);
|
|
|
ebb439 |
installed_flow_destroy(i);
|
|
|
ebb439 |
- } else {
|
|
|
ebb439 |
+ } else if (was_active) {
|
|
|
ebb439 |
/* There are other desired flow(s) referencing this
|
|
|
ebb439 |
* installed flow, so update the OVS flow for the new
|
|
|
ebb439 |
* active flow (at least the cookie will be different,
|
|
|
ebb439 |
@@ -1810,7 +1834,7 @@ update_installed_flows_by_track(struct ovn_desired_flow_table *flow_table,
|
|
|
ebb439 |
hmap_insert(&installed_flows, &new_node->match_hmap_node,
|
|
|
ebb439 |
new_node->flow.hash);
|
|
|
ebb439 |
link_installed_to_desired(new_node, f);
|
|
|
ebb439 |
- } else if (i->desired_flow == f) {
|
|
|
ebb439 |
+ } else if (desired_flow_is_active(f)) {
|
|
|
ebb439 |
/* The installed flow is installed for f, but f has change
|
|
|
ebb439 |
* tracked, so it must have been modified. */
|
|
|
ebb439 |
ovn_flow_log(&i->flow, "updating installed (tracked)");
|
|
|
ebb439 |
diff --git a/tests/ovn.at b/tests/ovn.at
|
|
|
ebb439 |
index e3f3153..6f1ab59 100644
|
|
|
ebb439 |
--- a/tests/ovn.at
|
|
|
ebb439 |
+++ b/tests/ovn.at
|
|
|
ebb439 |
@@ -22266,6 +22266,114 @@ OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected])
|
|
|
ebb439 |
OVN_CLEANUP([hv1])
|
|
|
ebb439 |
AT_CLEANUP
|
|
|
ebb439 |
|
|
|
ebb439 |
+# This test cases tests a scenario of ACL confliction with address set update.
|
|
|
ebb439 |
+# It is to cover a corner case when flows are re-processed in the I-P
|
|
|
ebb439 |
+# iteration, combined with the scenario of conflicting ACLs.
|
|
|
ebb439 |
+AT_SETUP([ovn -- conflict ACLs with address set])
|
|
|
ebb439 |
+ovn_start
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ovn-nbctl ls-add ls1
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ovn-nbctl lsp-add ls1 lsp1 \
|
|
|
ebb439 |
+-- lsp-set-addresses lsp1 "f0:00:00:00:00:01 10.0.0.1"
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ovn-nbctl lsp-add ls1 lsp2 \
|
|
|
ebb439 |
+-- lsp-set-addresses lsp2 "f0:00:00:00:00:02 10.0.0.2"
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+net_add n1
|
|
|
ebb439 |
+sim_add hv1
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+as hv1
|
|
|
ebb439 |
+ovs-vsctl add-br br-phys
|
|
|
ebb439 |
+ovn_attach n1 br-phys 192.168.0.1
|
|
|
ebb439 |
+ovs-vsctl -- add-port br-int hv1-vif1 -- \
|
|
|
ebb439 |
+ set interface hv1-vif1 external-ids:iface-id=lsp1 \
|
|
|
ebb439 |
+ options:tx_pcap=hv1/vif1-tx.pcap \
|
|
|
ebb439 |
+ options:rxq_pcap=hv1/vif1-rx.pcap \
|
|
|
ebb439 |
+ ofport-request=1
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ovs-vsctl -- add-port br-int hv1-vif2 -- \
|
|
|
ebb439 |
+ set interface hv1-vif2 external-ids:iface-id=lsp2 \
|
|
|
ebb439 |
+ options:tx_pcap=hv1/vif2-tx.pcap \
|
|
|
ebb439 |
+ options:rxq_pcap=hv1/vif2-rx.pcap \
|
|
|
ebb439 |
+ ofport-request=2
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+# Default drop
|
|
|
ebb439 |
+ovn-nbctl acl-add ls1 to-lport 1000 \
|
|
|
ebb439 |
+'outport == "lsp1" && ip4' drop
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+# test_ip INPORT SRC_MAC DST_MAC SRC_IP DST_IP OUTPORT...
|
|
|
ebb439 |
+#
|
|
|
ebb439 |
+# This shell function causes an ip packet to be received on INPORT.
|
|
|
ebb439 |
+# The packet's content has Ethernet destination DST and source SRC
|
|
|
ebb439 |
+# (each exactly 12 hex digits) and Ethernet type ETHTYPE (4 hex digits).
|
|
|
ebb439 |
+# The OUTPORTs (zero or more) list the VIFs on which the packet should
|
|
|
ebb439 |
+# be received. INPORT and the OUTPORTs are specified as logical switch
|
|
|
ebb439 |
+# port numbers, e.g. 11 for vif11.
|
|
|
ebb439 |
+test_ip() {
|
|
|
ebb439 |
+ # This packet has bad checksums but logical L3 routing doesn't check.
|
|
|
ebb439 |
+ local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5
|
|
|
ebb439 |
+ local packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}\
|
|
|
ebb439 |
+${dst_ip}0035111100080000
|
|
|
ebb439 |
+ shift; shift; shift; shift; shift
|
|
|
ebb439 |
+ as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $packet
|
|
|
ebb439 |
+ for outport; do
|
|
|
ebb439 |
+ echo $packet >> $outport.expected
|
|
|
ebb439 |
+ done
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ip_to_hex() {
|
|
|
ebb439 |
+ printf "%02x%02x%02x%02x" "$@"
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+reset_pcap_file() {
|
|
|
ebb439 |
+ local iface=$1
|
|
|
ebb439 |
+ local pcap_file=$2
|
|
|
ebb439 |
+ ovs-vsctl -- set Interface $iface options:tx_pcap=dummy-tx.pcap \
|
|
|
ebb439 |
+options:rxq_pcap=dummy-rx.pcap
|
|
|
ebb439 |
+ rm -f ${pcap_file}*.pcap
|
|
|
ebb439 |
+ ovs-vsctl -- set Interface $iface options:tx_pcap=${pcap_file}-tx.pcap \
|
|
|
ebb439 |
+options:rxq_pcap=${pcap_file}-rx.pcap
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+# Create an address set
|
|
|
ebb439 |
+ovn-nbctl create Address_Set name=as1 \
|
|
|
ebb439 |
+addresses=\"10.0.0.2\",\"10.0.0.3\"
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+# Create overlapping ACLs resulting in conflict desired OVS flows
|
|
|
ebb439 |
+# Add ACL1 uses the address set
|
|
|
ebb439 |
+ovn-nbctl --wait=hv acl-add ls1 to-lport 1001 \
|
|
|
ebb439 |
+'outport == "lsp1" && ip4 && ip4.src == $as1' allow
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+# Add ACL2 which uses a single IP, which shouldn't take effect because
|
|
|
ebb439 |
+# when it is added incrementally there is already a conflict one installed.
|
|
|
ebb439 |
+ovn-nbctl --wait=hv acl-add ls1 to-lport 1001 \
|
|
|
ebb439 |
+'outport == "lsp1" && ip4 && ip4.src == 10.0.0.2' drop
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+sip=`ip_to_hex 10 0 0 2`
|
|
|
ebb439 |
+dip=`ip_to_hex 10 0 0 1`
|
|
|
ebb439 |
+test_ip 2 f00000000002 f00000000001 $sip $dip 1
|
|
|
ebb439 |
+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected])
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+# Update the address set which causes flow reprocessing but the OVS flow
|
|
|
ebb439 |
+# for allowing 10.0.0.2 should keep unchanged
|
|
|
ebb439 |
+ovn-nbctl --wait=hv set Address_Set as1 addresses=\"10.0.0.2\"
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+test_ip 2 f00000000002 f00000000001 $sip $dip 1
|
|
|
ebb439 |
+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected])
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+# Delete the ACL1 that has "allow" action
|
|
|
ebb439 |
+ovn-nbctl acl-del ls1 to-lport 1001 \
|
|
|
ebb439 |
+'outport == "lsp1" && ip4 && ip4.src == $as1'
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+# ACL2 should take effect and packet should be dropped
|
|
|
ebb439 |
+test_ip 2 f00000000002 f00000000001 $sip $dip
|
|
|
ebb439 |
+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected])
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+OVN_CLEANUP([hv1])
|
|
|
ebb439 |
+AT_CLEANUP
|
|
|
ebb439 |
+
|
|
|
ebb439 |
AT_SETUP([ovn -- port bind/unbind change handling with conj flows - IPv6])
|
|
|
ebb439 |
ovn_start
|
|
|
ebb439 |
|
|
|
ebb439 |
--
|
|
|
ebb439 |
1.8.3.1
|
|
|
ebb439 |
|