summaryrefslogtreecommitdiff
path: root/tests/learn.at
diff options
context:
space:
mode:
authorBen Pfaff <blp@nicira.com>2014-06-05 21:53:34 -0700
committerBen Pfaff <blp@nicira.com>2014-06-12 14:47:22 -0700
commit35f48b8bd9b3b3491d79418878ef70dc54b0a8f0 (patch)
tree423a72ba1b6efbf159afb6356d0c15fb6a66cd63 /tests/learn.at
parent9ca4a86fffcda89098588cbdd9ba0c21aa60a9c8 (diff)
downloadopenvswitch-35f48b8bd9b3b3491d79418878ef70dc54b0a8f0.tar.gz
Implement learned flow deletion.
When a flow with a "learn" action is deleted, one often wants the flows that it created (the "learned flows") to be deleted as well. This commit makes that possible. I am aware of a race condition that could lead to a learned flow not being properly deleted. Suppose thread A deletes a flow with a "learn" action. Meanwhile, thread B obtains the actions for this flow and translates and executes them. Thread B could obtain the actions for the flow before it is deleted, but execute them after the "learn" flow and its learned flows are deleted. The result is that the flow created by thread B persists despite its "learn" flow having been deleted. This race can and should be fixed, but I think that this commit is worth reviewing without it. VMware-BZ: #1254021 Signed-off-by: Ben Pfaff <blp@nicira.com> Acked-by: Thomas Graf <tgraf@suug.ch> Acked-by: Ethan Jackson <ethan@nicira.com>
Diffstat (limited to 'tests/learn.at')
-rw-r--r--tests/learn.at138
1 files changed, 136 insertions, 2 deletions
diff --git a/tests/learn.at b/tests/learn.at
index 3c304d10c..2ca58fc22 100644
--- a/tests/learn.at
+++ b/tests/learn.at
@@ -3,6 +3,9 @@ AT_BANNER([learning action])
AT_SETUP([learning action - parsing and formatting])
AT_DATA([flows.txt], [[
actions=learn()
+actions=learn(send_flow_rem)
+actions=learn(delete_learned)
+actions=learn(send_flow_rem,delete_learned)
actions=learn(NXM_OF_VLAN_TCI[0..11], NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], output:NXM_OF_IN_PORT[], load:10->NXM_NX_REG0[5..10])
actions=learn(table=1,idle_timeout=10, hard_timeout=20, fin_idle_timeout=5, fin_hard_timeout=10, priority=10, cookie=0xfedcba9876543210, in_port=99,NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG1[16..31])
]])
@@ -10,8 +13,11 @@ AT_CHECK([ovs-ofctl parse-flows flows.txt], [0],
[[usable protocols: any
chosen protocol: OpenFlow10-table_id
OFPT_FLOW_MOD (xid=0x1): ADD actions=learn(table=1)
-OFPT_FLOW_MOD (xid=0x2): ADD actions=learn(table=1,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],output:NXM_OF_IN_PORT[],load:0xa->NXM_NX_REG0[5..10])
-OFPT_FLOW_MOD (xid=0x3): ADD actions=learn(table=1,idle_timeout=10,hard_timeout=20,fin_idle_timeout=5,fin_hard_timeout=10,priority=10,cookie=0xfedcba9876543210,in_port=99,NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG1[16..31])
+OFPT_FLOW_MOD (xid=0x2): ADD actions=learn(table=1,send_flow_rem)
+OFPT_FLOW_MOD (xid=0x3): ADD actions=learn(table=1,delete_learned)
+OFPT_FLOW_MOD (xid=0x4): ADD actions=learn(table=1,send_flow_rem,delete_learned)
+OFPT_FLOW_MOD (xid=0x5): ADD actions=learn(table=1,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],output:NXM_OF_IN_PORT[],load:0xa->NXM_NX_REG0[5..10])
+OFPT_FLOW_MOD (xid=0x6): ADD actions=learn(table=1,idle_timeout=10,hard_timeout=20,fin_idle_timeout=5,fin_hard_timeout=10,priority=10,cookie=0xfedcba9876543210,in_port=99,NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG1[16..31])
]])
AT_CLEANUP
@@ -480,3 +486,131 @@ AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip], [0],
])
OVS_VSWITCHD_STOP
AT_CLEANUP
+
+AT_SETUP([learning action - delete_learned feature])
+OVS_VSWITCHD_START
+
+# Add some initial flows and check that it was successful.
+AT_DATA([flows.txt], [dnl
+ reg0=0x1 actions=learn(delete_learned,cookie=0x123)
+ reg0=0x2 actions=learn(delete_learned,cookie=0x123)
+cookie=0x123, table=1, reg0=0x3 actions=drop
+cookie=0x123, table=1, reg0=0x4 actions=drop
+cookie=0x123, table=2, reg0=0x5 actions=drop
+cookie=0x234, table=1, reg0=0x6 actions=drop
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ cookie=0x123, table=1, reg0=0x3 actions=drop
+ cookie=0x123, table=1, reg0=0x4 actions=drop
+ cookie=0x123, table=2, reg0=0x5 actions=drop
+ cookie=0x234, table=1, reg0=0x6 actions=drop
+ reg0=0x1 actions=learn(table=1,delete_learned,cookie=0x123)
+ reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x123)
+NXST_FLOW reply:
+])
+
+# Delete one of the learn actions. The learned flows should stay, since there
+# is another learn action with the identical target.
+AT_CHECK([ovs-ofctl del-flows br0 'table=0 reg0=1'])
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ cookie=0x123, table=1, reg0=0x3 actions=drop
+ cookie=0x123, table=1, reg0=0x4 actions=drop
+ cookie=0x123, table=2, reg0=0x5 actions=drop
+ cookie=0x234, table=1, reg0=0x6 actions=drop
+ reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x123)
+NXST_FLOW reply:
+])
+
+# Change the flow with the learn action by adding a second action. The learned
+# flows should stay because the learn action is still there.
+AT_CHECK([ovs-ofctl mod-flows br0 'table=0 reg0=2 actions=output:1,learn(delete_learned,cookie=0x123)'])
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ cookie=0x123, table=1, reg0=0x3 actions=drop
+ cookie=0x123, table=1, reg0=0x4 actions=drop
+ cookie=0x123, table=2, reg0=0x5 actions=drop
+ cookie=0x234, table=1, reg0=0x6 actions=drop
+ reg0=0x2 actions=output:1,learn(table=1,delete_learned,cookie=0x123)
+NXST_FLOW reply:
+])
+
+# Change the flow with the learn action by replacing its learn action by one
+# with a different target. The (previous) learned flows disappear.
+AT_CHECK([ovs-ofctl mod-flows br0 'table=0 reg0=2 actions=learn(delete_learned,cookie=0x234)'])
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ cookie=0x123, table=2, reg0=0x5 actions=drop
+ cookie=0x234, table=1, reg0=0x6 actions=drop
+ reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x234)
+NXST_FLOW reply:
+])
+
+# Use add-flow to replace the flow with the learn action by one with the
+# same learn action and an extra action. The (new) learned flow remains.
+AT_CHECK([ovs-ofctl add-flow br0 'table=0 reg0=2 actions=learn(delete_learned,cookie=0x234),output:2'])
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ cookie=0x123, table=2, reg0=0x5 actions=drop
+ cookie=0x234, table=1, reg0=0x6 actions=drop
+ reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x234),output:2
+NXST_FLOW reply:
+])
+
+# Delete the flow with the learn action. The learned flow disappears too.
+AT_CHECK([ovs-ofctl del-flows br0 table=0])
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ cookie=0x123, table=2, reg0=0x5 actions=drop
+NXST_FLOW reply:
+])
+
+# Add a new set of flows to check on a corner case: the learned flows
+# contain their own learn actions which cascade to further deletions.
+# This can't happen if the learned flows were actually created by a
+# learn action, since the learn action has very restricted action
+# support, but there's no restriction that the deleted flows were
+# created by a learn action.
+AT_DATA([flows.txt], [dnl
+ reg0=0x1 actions=learn(table=1,delete_learned,cookie=0x123)
+ reg0=0x2 actions=learn(table=2,delete_learned,cookie=0x234)
+cookie=0x123, table=1, reg0=0x3 actions=learn(table=3,delete_learned,cookie=0x345)
+cookie=0x234, table=2, reg0=0x3 actions=learn(table=4,delete_learned,cookie=0x456)
+cookie=0x345, table=3, reg0=0x4 actions=learn(table=5,delete_learned,cookie=0x567)
+cookie=0x456, table=4, reg0=0x5 actions=learn(table=5,delete_learned,cookie=0x567)
+cookie=0x567, table=5, reg0=0x6 actions=drop
+cookie=0x567, table=5, reg0=0x7 actions=drop
+cookie=0x567, table=5, reg0=0x8 actions=drop
+])
+AT_CHECK([ovs-ofctl del-flows br0])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ cookie=0x123, table=1, reg0=0x3 actions=learn(table=3,delete_learned,cookie=0x345)
+ cookie=0x234, table=2, reg0=0x3 actions=learn(table=4,delete_learned,cookie=0x456)
+ cookie=0x345, table=3, reg0=0x4 actions=learn(table=5,delete_learned,cookie=0x567)
+ cookie=0x456, table=4, reg0=0x5 actions=learn(table=5,delete_learned,cookie=0x567)
+ cookie=0x567, table=5, reg0=0x6 actions=drop
+ cookie=0x567, table=5, reg0=0x7 actions=drop
+ cookie=0x567, table=5, reg0=0x8 actions=drop
+ reg0=0x1 actions=learn(table=1,delete_learned,cookie=0x123)
+ reg0=0x2 actions=learn(table=2,delete_learned,cookie=0x234)
+NXST_FLOW reply:
+])
+
+# Deleting the flow with reg0=1 should cascade to delete a few levels
+# of learned flows, but the ones with cookie=0x567 stick around
+# because of the flow with cookie=0x456.
+AT_CHECK([ovs-ofctl del-flows br0 'table=0 reg0=1'])
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ cookie=0x234, table=2, reg0=0x3 actions=learn(table=4,delete_learned,cookie=0x456)
+ cookie=0x456, table=4, reg0=0x5 actions=learn(table=5,delete_learned,cookie=0x567)
+ cookie=0x567, table=5, reg0=0x6 actions=drop
+ cookie=0x567, table=5, reg0=0x7 actions=drop
+ cookie=0x567, table=5, reg0=0x8 actions=drop
+ reg0=0x2 actions=learn(table=2,delete_learned,cookie=0x234)
+NXST_FLOW reply:
+])
+
+# Deleting the flow with reg0=2 should cascade to delete all the rest:
+AT_CHECK([ovs-ofctl del-flows br0 'table=0 reg0=2'])
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+NXST_FLOW reply:
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP