diff options
author | Ben Pfaff <blp@nicira.com> | 2014-06-05 21:53:34 -0700 |
---|---|---|
committer | Ben Pfaff <blp@nicira.com> | 2014-06-12 14:47:22 -0700 |
commit | 35f48b8bd9b3b3491d79418878ef70dc54b0a8f0 (patch) | |
tree | 423a72ba1b6efbf159afb6356d0c15fb6a66cd63 /tests/learn.at | |
parent | 9ca4a86fffcda89098588cbdd9ba0c21aa60a9c8 (diff) | |
download | openvswitch-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.at | 138 |
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 |