Thanks Romain. I’m actually talking about an array of *pointers* to classifiers. That comes out to 2040 bytes.
=========================== Shashank Shanbhag =========================== On Jun 19, 2015, at 5:32 PM, Romain Lenglet <romain.leng...@oracle.com> wrote: > > On June 18, 2015 at 2:39:31 PM, Shashank Shanbhag > (shashank.shanb...@gmail.com(mailto:shashank.shanb...@gmail.com)) wrote: > >> Hi Ben, >> >> Please review when you get a chance. We would really like this to be in the >> 2.4 release. :-) >> >> This patch has the following changes suggested by you in the last review: >> 1. ovs-ofctl replace-flow and diff-flow queries the switch for visible tables >> >> You also suggested that we move to using an array rather than a hash. >> http://openvswitch.org/pipermail/dev/2015-June/055998.html >> >> An array of 255 pointers to classifiers would lead to 2040 bytes (64-bit >> system). I'd like to avoid that especially when there are a handful of >> tables. > > I believe you meant something like 2MB here? > > -- > Romain Lenglet > >> >> >> >> Please let me know, >> Thanks, >> >> --------------------------------------------------------- >> Shashank Shanbhag, >> --------------------------------------------------------- >> On Thu, Jun 18, 2015 at 2:31 PM, Shashank Shanbhag wrote: >>> From: Shashank Shanbhag >>> >>> Fix replace-flows and diff-flows to modify/diff flows in multiple tables. >>> Add a --tables(-T) option that allows the user to specify a comma-separated >>> list of table indexes to replace/diff. >>> Fix replace-flows to support OF1.3 and above. >>> Add/change ovs-ofctl replace-flows and diff-flows tests. >>> >>> Signed-off-by: Shashank Shanbhag >>> Acked-by: Romain Lenglet >>> --- >>> AUTHORS | 1 + >>> NEWS | 7 +- >>> tests/ofproto-dpif.at(http://ofproto-dpif.at) | 6 +- >>> tests/ofproto.at(http://ofproto.at) | 2 +- >>> tests/ovs-ofctl.at(http://ovs-ofctl.at) | 141 ++++++++++---- >>> utilities/ovs-ofctl.8.in(http://ovs-ofctl.8.in) | 20 +- >>> utilities/ovs-ofctl.c | 465 ++++++++++++++++++++++++++++++++++++++++------- >>> 7 files changed, 533 insertions(+), 109 deletions(-) >>> >>> diff --git a/AUTHORS b/AUTHORS >>> index cebab48..96a00f1 100644 >>> --- a/AUTHORS >>> +++ b/AUTHORS >>> @@ -155,6 +155,7 @@ Scott Lowe >>> scott.l...@scottlowe.org(mailto:scott.l...@scottlowe.org) >>> Scott Mann sdm...@gmail.com(mailto:sdm...@gmail.com) >>> Selvamuthukumar smku...@merunetworks.com(mailto:smku...@merunetworks.com) >>> Shan Wei davids...@tencent.com(mailto:davids...@tencent.com) >>> +Shashank Shanbhag >>> shashank.shanb...@gmail.com(mailto:shashank.shanb...@gmail.com) >>> Shih-Hao Li s...@nicira.com(mailto:s...@nicira.com) >>> Shu Shen shu.s...@radisys.com(mailto:shu.s...@radisys.com) >>> Simon Horman ho...@verge.net.au(mailto:ho...@verge.net.au) >>> diff --git a/NEWS b/NEWS >>> index 831bf5f..99545ad 100644 >>> --- a/NEWS >>> +++ b/NEWS >>> @@ -108,7 +108,12 @@ v2.4.0 - xx xxx xxxx >>> openvswitch.ko but built and loaded automatically as individual kernel >>> modules (vport-*.ko). >>> - Support for STT tunneling. >>> - >>> + - ovs-ofctl: replace-flows and diff-flows now operate on multiple tables. >>> + - ovs-ofctl: --tables option added to replace-flows and diff-flows to >>> allow >>> + specific tables to be replaced or diffed. >>> + - ovs-ofctl: replace-flows and diff-flows now query the switch for visible >>> + tables. Hidden tables are ignored. >>> + - ovs-ofctl works for OF version 1.3 and above. >>> >>> v2.3.0 - 14 Aug 2014 >>> --------------------- >>> diff --git a/tests/ofproto-dpif.at(http://ofproto-dpif.at) >>> b/tests/ofproto-dpif.at(http://ofproto-dpif.at) >>> index bd1b21c..0567dab 100644 >>> --- a/tests/ofproto-dpif.at(http://ofproto-dpif.at) >>> +++ b/tests/ofproto-dpif.at(http://ofproto-dpif.at) >>> @@ -3693,7 +3693,7 @@ priority=50 tcp ip_frag=no >>> actions=move:OXM_OF_TCP_DST[[]]->OXM_OF_ >>> priority=50 tcp ip_frag=first >>> actions=move:OXM_OF_TCP_DST[[]]->OXM_OF_TCP_SRC[[]],output:5 >>> priority=50 tcp ip_frag=later actions=output:6 >>> ]) >>> -AT_CHECK([ovs-ofctl replace-flows br0 flows.txt]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 replace-flows br0 flows.txt]) >>> >>> base_flow="in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=128" >>> no_flow="$base_flow,frag=no),tcp(src=12345,dst=80)" >>> @@ -3742,7 +3742,7 @@ priority=50 tcp ip_frag=no >>> actions=set_field:81->tcp_dst,output:4 >>> priority=50 tcp ip_frag=first actions=set_field:81->tcp_dst,output:5 >>> priority=50 tcp ip_frag=later actions=output:6 >>> ]) >>> -AT_CHECK([ovs-ofctl replace-flows br0 flows.txt]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 replace-flows br0 flows.txt]) >>> >>> base_flow="in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=128" >>> no_flow="$base_flow,frag=no),tcp(src=12345,dst=80)" >>> @@ -3856,7 +3856,7 @@ ovs-ofctl: actions are invalid with specified match >>> (OFPBAC_MATCH_INCONSISTENT) >>> AT_DATA([flows.txt], [dnl >>> priority=75 tcp actions=load:42->OXM_OF_TCP_SRC[[0..7]],output:1 >>> ]) >>> -AT_CHECK([ovs-ofctl -O OpenFlow12 replace-flows br0 flows.txt]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 replace-flows br0 flows.txt]) >>> >>> AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg]) >>> >>> diff --git a/tests/ofproto.at(http://ofproto.at) >>> b/tests/ofproto.at(http://ofproto.at) >>> index 9c5f0bb..16bbf78 100644 >>> --- a/tests/ofproto.at(http://ofproto.at) >>> +++ b/tests/ofproto.at(http://ofproto.at) >>> @@ -3066,7 +3066,7 @@ ${PERL} -e ' >>> ') > flows.txt >>> AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) >>> # Check that multipart flow dumps work properly: >>> -AT_CHECK([ovs-ofctl diff-flows br0 flows.txt]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 diff-flows br0 flows.txt]) >>> AT_CHECK([ovs-ofctl add-flow br0 in_port=1,cookie=3,actions=drop]) >>> AT_CHECK([ovs-ofctl mod-flows br0 in_port=2,cookie=2,actions=output:2]) >>> AT_CHECK([ovs-ofctl del-flows br0 cookie=1/-1]) >>> diff --git a/tests/ovs-ofctl.at(http://ovs-ofctl.at) >>> b/tests/ovs-ofctl.at(http://ovs-ofctl.at) >>> index 6c48569..8bb42e0 100644 >>> --- a/tests/ovs-ofctl.at(http://ovs-ofctl.at) >>> +++ b/tests/ovs-ofctl.at(http://ovs-ofctl.at) >>> @@ -2622,15 +2622,15 @@ AT_CHECK([ovs-ofctl add-flows br0 add-flows.txt]) >>> for i in `seq 0 1023`; do echo " dl_vlan=$i actions=drop"; done | sort > >>> expout >>> AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sed '/NXST_FLOW/d' | >>> sort], >>> [0], [expout]) >>> -AT_CHECK([ovs-ofctl diff-flows br0 add-flows.txt]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 diff-flows br0 add-flows.txt]) >>> >>> # Remove even-numbered flows, compare again. >>> for i in `seq 0 1023 2`; do echo "dl_vlan=$i"; done > del-flows.txt >>> AT_CHECK([ovs-ofctl del-flows br0 - < del-flows.txt]) >>> for i in `seq 0 1023 2`; do echo "+dl_vlan=$i actions=drop"; done | sort > >>> expout >>> -AT_CHECK([ovs-ofctl diff-flows br0 add-flows.txt | sort], [0], [expout]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 diff-flows br0 add-flows.txt | sort], >>> [0], [expout]) >>> for i in `seq 0 1023 2`; do echo "-dl_vlan=$i actions=drop"; done | sort > >>> expout >>> -AT_CHECK([ovs-ofctl diff-flows add-flows.txt br0 | sort], [0], [expout]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 diff-flows add-flows.txt br0 | sort], >>> [0], [expout]) >>> >>> OVS_VSWITCHD_STOP >>> AT_CLEANUP >>> @@ -2648,13 +2648,13 @@ OVS_VSWITCHD_START >>> AT_DATA([flows.txt], [actions=resubmit(,1) >>> ]) >>> AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) >>> -AT_CHECK([ovs-ofctl diff-flows br0 flows.txt]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 diff-flows br0 flows.txt]) >>> AT_CHECK([ovs-ofctl add-flow br0 >>> idle_timeout=60,dl_vlan=9,actions=output:1]) >>> -AT_CHECK([ovs-ofctl diff-flows br0 flows.txt], [2], [dnl >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 diff-flows br0 flows.txt], [2], [dnl >>> -dl_vlan=9 idle_timeout=60 actions=output:1 >>> ]) >>> AT_CHECK([ovs-ofctl add-flow br0 >>> hard_timeout=120,cookie=1234,dl_vlan=9,actions=output:1]) >>> -AT_CHECK([ovs-ofctl diff-flows flows.txt br0], [2], [dnl >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 diff-flows flows.txt br0], [2], [dnl >>> +dl_vlan=9 cookie=0x4d2 hard_timeout=120 actions=output:1 >>> ]) >>> OVS_VSWITCHD_STOP >>> @@ -2789,27 +2789,82 @@ AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | >>> sed '/ST_FLOW reply/d' | sort >>> OVS_VSWITCHD_STOP >>> AT_CLEANUP >>> >>> - >>> dnl Importance parameter added in OF1.4. >>> dnl This validates whether flows with importance >>> dnl parameter are getting replaced with "replace-flows" or >>> dnl not by validating dump-flows output after replace with the expected >>> output. >>> +dnl MOD_FLOW does not modify importance field - ONF EXT-496. >>> >>> AT_SETUP([ovs-ofctl replace-flows with importance]) >>> OVS_VSWITCHD_START >>> >>> dnl Add flows to br0 with importance via OF1.4+. For more details refer >>> "ovs-ofctl rule with importance" test case. >>> -for i in 1 2 3 4 5 6 7 8; do echo "dl_vlan=$i,importance=$i,actions=drop"; >>> done > add-flows.txt >>> +for i in 1 2 3 4 5 6 7 8; do echo "dl_vlan=$i,importance=$i actions=drop"; >>> done | sort > add-flows.txt >>> AT_CHECK([ovs-ofctl -O OpenFlow14 add-flows br0 add-flows.txt]) >>> >>> -dnl Replace some flows in the bridge. >>> -for i in 1 3 5 7; do echo "dl_vlan=$i,importance=`expr $i + >>> 10`,actions=drop"; done > replace-flows.txt >>> +dnl Modify odd numbered flows. Leave even numbered ones alone. >>> +for i in 1 2 3 4 5 6 7 8; do if [[ `expr $i % 2` -eq 1 ]]; then >>> importance=`expr $i + 10`; else importance=$i; fi; echo " >>> importance=$importance, dl_vlan=$i actions=drop"; done | sort > >>> replace-flows.txt >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 replace-flows br0 replace-flows.txt]) >>> + >>> +dnl Dump the flows and compare them against expected output. >>> + >>> +for i in 1 2 3 4 5 6 7 8; do echo " importance=$i, dl_vlan=$i >>> actions=drop"; done | sort > expout >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sed >>> '/OFPST_FLOW/d' | sort], [0], [expout]) >>> + >>> +dnl Replace some flows in the bridge. Delete flows that are not present in >>> replace-flows.txt >>> +dnl for i in 1 3 5 7; do echo "dl_vlan=$i,importance=`expr $i + 10` >>> actions=drop"; done | sort > replace-flows.txt >>> + >>> +for i in 1 3 5 7; do echo "dl_vlan=$i,importance=$i actions=drop"; done | >>> sort > replace-flows.txt >>> AT_CHECK([ovs-ofctl -O OpenFlow14 replace-flows br0 replace-flows.txt]) >>> >>> dnl Dump them and compare the dump flows output against the expected output. >>> -for i in 1 2 3 4 5 6 7 8; do if [[ `expr $i % 2` -eq 1 ]]; then >>> importance=`expr $i + 10`; else importance=$i; fi; echo " >>> importance=$importance, dl_vlan=$i actions=drop"; done | sort > expout >>> -AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sed >>> '/OFPST_FLOW/d' | sort], >>> - [0], [expout]) >>> +for i in 1 3 5 7; do echo " importance=$i, dl_vlan=$i actions=drop"; done >>> | sort > expout >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sed >>> '/OFPST_FLOW/d' | sort], [0], [expout]) >>> + >>> +OVS_VSWITCHD_STOP >>> +AT_CLEANUP >>> + >>> +dnl --tables option added to ovs-ofctl "replace-flows" and "diff-flows". >>> +dnl This validates whether flows in table IDs specified with --tables >>> +dnl are getting replaced with "replace-flows" or not by validating >>> +dnl dump-flows output after replace with the expected output. >>> + >>> +AT_SETUP([ovs-ofctl replace-flows with --tables]) >>> +OVS_VSWITCHD_START >>> + >>> +dnl Add flows to br0 for tables 1 to 8. >>> +for i in 1 2 3 4 5 6 7 8; do echo "table=$i,dl_vlan=$i,actions=drop"; done >>> > add-flows.txt >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 add-flows br0 add-flows.txt]) >>> + >>> +dnl Replace flows from tables 1,3,5,7 in the bridge. >>> +for i in 1 3 5 7; do echo >>> "table=$i,ip,nw_dst=192.168.1.$i,dl_vlan=$i,actions=drop"; done > >>> replace-flows.txt >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 replace-flows br0 replace-flows.txt >>> --tables 1,5,7,3]) >>> + >>> +dnl Generate the expout. >>> +for i in 1 2 3 4 5 6 7 8; do if [[ `expr $i % 2` -eq 1 ]]; then echo " >>> table=$i, ip,dl_vlan=$i,nw_dst=192.168.1.$i actions=drop"; else echo " >>> table=$i, dl_vlan=$i actions=drop"; fi; done | sort > expout >>> +dnl Dump the flows and check. >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sed >>> '/OFPST_FLOW/d' | sort], [0], [expout]) >>> + >>> +AT_DATA([oneflow.txt], [[ >>> +table=4,ip,nw_dst=10.0.0.4,actions=output:100 >>> +]]) >>> + >>> +dnl Check that all flows except the ones in the replacement file are >>> present after >>> +dnl replace-flows is executed. >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 del-flows br0]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 add-flows br0 add-flows.txt]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 replace-flows br0 oneflow.txt]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sed >>> '/OFPST_FLOW/d' | sort], [0], [dnl >>> + table=4, ip,nw_dst=10.0.0.4 actions=output:100 >>> +]) >>> + >>> +dnl Check that tables that do not have flows are not replaced. >>> +dnl Check that existing flows in other tables are not replaced as well. >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 del-flows br0]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 add-flows br0 add-flows.txt]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 replace-flows br0 oneflow.txt --tables >>> 100]) >>> +for i in 1 2 3 4 5 6 7 8; do echo " table=$i, dl_vlan=$i actions=drop"; >>> done | sort > expout >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sed >>> '/OFPST_FLOW/d' | sort], [0], [expout]) >>> >>> OVS_VSWITCHD_STOP >>> AT_CLEANUP >>> @@ -2821,14 +2876,14 @@ AT_CHECK([ovs-appctl vlog/set vconn:dbg]) >>> >>> dnl Add flows to br0 with importance via OF1.4+, using an OF1.4+ bundle. >>> For more details refer "ovs-ofctl rule with importance" test case. >>> for i in 1 2 3 4 5 6 7 8; do echo "dl_vlan=$i,importance=$i,actions=drop"; >>> done > add-flows.txt >>> -AT_CHECK([ovs-ofctl --bundle add-flows br0 add-flows.txt]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 --bundle add-flows br0 add-flows.txt]) >>> >>> dnl Replace some flows in the bridge. >>> for i in 1 3 5 7; do echo "dl_vlan=$i,importance=`expr $i + >>> 10`,actions=drop"; done > replace-flows.txt >>> -AT_CHECK([ovs-ofctl --bundle replace-flows br0 replace-flows.txt]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow14 --bundle replace-flows br0 >>> replace-flows.txt]) >>> >>> dnl Dump them and compare the dump flows output against the expected output. >>> -for i in 1 2 3 4 5 6 7 8; do if [[ `expr $i % 2` -eq 1 ]]; then >>> importance=`expr $i + 10`; else importance=$i; fi; echo " >>> importance=$importance, dl_vlan=$i actions=drop"; done | sort > expout >>> +for i in 1 3 5 7; do echo " importance=$i, dl_vlan=$i actions=drop"; done >>> | sort > expout >>> AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sed >>> '/OFPST_FLOW/d' | sort], >>> [0], [expout]) >>> >>> @@ -2836,12 +2891,10 @@ dnl Check logs for OpenFlow trace >>> # Prevent race. >>> OVS_WAIT_UNTIL([test `grep -- "|vconn|DBG|unix: sent (Success): OFPST_FLOW >>> reply" ovs-vswitchd.log | wc -l` -ge 2]) >>> # AT_CHECK([sed -n "s/^.*\(|vconn|DBG|.*xid=.*:\).*$/\1/p" >>> ovs-vswitchd.log], [0], [dnl >>> -AT_CHECK([print_vconn_debug | ofctl_strip], [0], [dnl >>> +AT_CHECK([print_vconn_debug | ofctl_strip | awk 'NF && >>> $1!~/^(table|active|version)/'], [0], [dnl >>> vconn|DBG|unix: sent (Success): OFPT_HELLO (OF1.5): >>> - version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 >>> vconn|DBG|unix: received: OFPT_HELLO (OF1.4): >>> - version bitmap: 0x01, 0x05 >>> -vconn|DBG|unix: negotiated OpenFlow version 0x05 (we support version 0x06 >>> and earlier, peer supports versions 0x01, 0x05) >>> +vconn|DBG|unix: negotiated OpenFlow version 0x05 (we support version 0x06 >>> and earlier, peer supports version 0x05) >>> vconn|DBG|unix: received: OFPT_BUNDLE_CONTROL (OF1.4): >>> bundle_id=0 type=OPEN_REQUEST flags=atomic ordered >>> vconn|DBG|unix: sent (Success): OFPT_BUNDLE_CONTROL (OF1.4): >>> @@ -2875,47 +2928,61 @@ vconn|DBG|unix: received: OFPT_BUNDLE_CONTROL >>> (OF1.4): >>> vconn|DBG|unix: sent (Success): OFPT_BUNDLE_CONTROL (OF1.4): >>> bundle_id=0 type=COMMIT_REPLY flags=0 >>> vconn|DBG|unix: sent (Success): OFPT_HELLO (OF1.5): >>> - version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 >>> vconn|DBG|unix: received: OFPT_HELLO (OF1.4): >>> - version bitmap: 0x01, 0x05 >>> -vconn|DBG|unix: negotiated OpenFlow version 0x05 (we support version 0x06 >>> and earlier, peer supports versions 0x01, 0x05) >>> +vconn|DBG|unix: negotiated OpenFlow version 0x05 (we support version 0x06 >>> and earlier, peer supports version 0x05) >>> +vconn|DBG|unix: received: OFPST_TABLE request (OF1.4): >>> +vconn|DBG|unix: sent (Success): OFPST_TABLE reply (OF1.4): >>> vconn|DBG|unix: received: OFPST_FLOW request (OF1.4): >>> vconn|DBG|unix: sent (Success): OFPST_FLOW reply (OF1.4): >>> + importance=1, dl_vlan=1 actions=drop >>> + importance=2, dl_vlan=2 actions=drop >>> + importance=3, dl_vlan=3 actions=drop >>> + importance=4, dl_vlan=4 actions=drop >>> + importance=5, dl_vlan=5 actions=drop >>> + importance=6, dl_vlan=6 actions=drop >>> + importance=7, dl_vlan=7 actions=drop >>> + importance=8, dl_vlan=8 actions=drop >>> vconn|DBG|unix: received: OFPT_BUNDLE_CONTROL (OF1.4): >>> bundle_id=0 type=OPEN_REQUEST flags=atomic ordered >>> vconn|DBG|unix: sent (Success): OFPT_BUNDLE_CONTROL (OF1.4): >>> bundle_id=0 type=OPEN_REPLY flags=0 >>> vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4): >>> bundle_id=0 flags=atomic ordered >>> -OFPT_FLOW_MOD (OF1.4): ADD dl_vlan=1 importance:11 actions=drop >>> +OFPT_FLOW_MOD (OF1.4): MOD_STRICT dl_vlan=1 actions=drop >>> vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4): >>> bundle_id=0 flags=atomic ordered >>> -OFPT_FLOW_MOD (OF1.4): ADD dl_vlan=3 importance:13 actions=drop >>> +OFPT_FLOW_MOD (OF1.4): MOD_STRICT dl_vlan=3 actions=drop >>> vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4): >>> bundle_id=0 flags=atomic ordered >>> -OFPT_FLOW_MOD (OF1.4): ADD dl_vlan=5 importance:15 actions=drop >>> +OFPT_FLOW_MOD (OF1.4): MOD_STRICT dl_vlan=5 actions=drop >>> vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4): >>> bundle_id=0 flags=atomic ordered >>> -OFPT_FLOW_MOD (OF1.4): ADD dl_vlan=7 importance:17 actions=drop >>> +OFPT_FLOW_MOD (OF1.4): MOD_STRICT dl_vlan=7 actions=drop >>> +vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4): >>> + bundle_id=0 flags=atomic ordered >>> +OFPT_FLOW_MOD (OF1.4): DEL_STRICT dl_vlan=2 actions=drop >>> +vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4): >>> + bundle_id=0 flags=atomic ordered >>> +OFPT_FLOW_MOD (OF1.4): DEL_STRICT dl_vlan=4 actions=drop >>> +vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4): >>> + bundle_id=0 flags=atomic ordered >>> +OFPT_FLOW_MOD (OF1.4): DEL_STRICT dl_vlan=6 actions=drop >>> +vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4): >>> + bundle_id=0 flags=atomic ordered >>> +OFPT_FLOW_MOD (OF1.4): DEL_STRICT dl_vlan=8 actions=drop >>> vconn|DBG|unix: received: OFPT_BUNDLE_CONTROL (OF1.4): >>> bundle_id=0 type=COMMIT_REQUEST flags=atomic ordered >>> vconn|DBG|unix: sent (Success): OFPT_BUNDLE_CONTROL (OF1.4): >>> bundle_id=0 type=COMMIT_REPLY flags=0 >>> vconn|DBG|unix: sent (Success): OFPT_HELLO (OF1.5): >>> - version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 >>> vconn|DBG|unix: received: OFPT_HELLO (OF1.4): >>> - version bitmap: 0x05 >>> vconn|DBG|unix: negotiated OpenFlow version 0x05 (we support version 0x06 >>> and earlier, peer supports version 0x05) >>> vconn|DBG|unix: received: OFPST_FLOW request (OF1.4): >>> vconn|DBG|unix: sent (Success): OFPST_FLOW reply (OF1.4): >>> - importance=2, dl_vlan=2 actions=drop >>> - importance=4, dl_vlan=4 actions=drop >>> - importance=6, dl_vlan=6 actions=drop >>> - importance=8, dl_vlan=8 actions=drop >>> - importance=11, dl_vlan=1 actions=drop >>> - importance=13, dl_vlan=3 actions=drop >>> - importance=15, dl_vlan=5 actions=drop >>> - importance=17, dl_vlan=7 actions=drop >>> + importance=1, dl_vlan=1 actions=drop >>> + importance=3, dl_vlan=3 actions=drop >>> + importance=5, dl_vlan=5 actions=drop >>> + importance=7, dl_vlan=7 actions=drop >>> ]) >>> >>> OVS_VSWITCHD_STOP >>> diff --git a/utilities/ovs-ofctl.8.in(http://ovs-ofctl.8.in) >>> b/utilities/ovs-ofctl.8.in(http://ovs-ofctl.8.in) >>> index 63c2ecc..1bf5041 100644 >>> --- a/utilities/ovs-ofctl.8.in(http://ovs-ofctl.8.in) >>> +++ b/utilities/ovs-ofctl.8.in(http://ovs-ofctl.8.in) >>> @@ -328,7 +328,7 @@ Deletes entries from \fIswitch\fR's flow table. With >>> only a >>> entries that match the specified flows. With \fB\-\-strict\fR, >>> wildcards are not treated as active for matching purposes. >>> . >>> -.IP "[\fB\-\-bundle\fR] [\fB\-\-readd\fR] \fBreplace\-flows \fIswitch >>> file\fR" >>> +.IP "[\fB\-\-bundle\fR] [\fB\-\-readd\fR] [\fB\-\-tables \fltable-ids\fR] >>> \fBreplace\-flows \fIswitch file\fR" >>> Reads flow entries from \fIfile\fR (or \fBstdin\fR if \fIfile\fR is >>> \fB\-\fR) and queries the flow table from \fIswitch\fR. Then it fixes >>> up any differences, adding flows from \fIflow\fR that are missing on >>> @@ -337,12 +337,21 @@ up any differences, adding flows from \fIflow\fR that >>> are missing on >>> or timeouts differ in \fIfile\fR. >>> . >>> .IP >>> +With \fB\-\-tables\fR, \fBovs\-ofctl\fR only considers flows from the >>> +comma-separated table IDs specified. The tables are replaced >>> +in the specified order, e.g. (\fB\-\-tables 1,3,4,2\fR). The valid >>> +range of table IDs is 0 to 254. If a table ID is not specified, >>> +the table with that ID is ignored and no flows are replaced in that >>> +table in the switch. If \fB\-\-tables\fR is not specified, all tables, >>> +0 - 254, will be replaced. >>> +. >>> +.IP >>> With \fB\-\-readd\fR, \fBovs\-ofctl\fR adds all the flows from >>> \fIfile\fR, even those that exist with the same actions, cookie, and >>> timeout in \fIswitch\fR. This resets all the flow packet and byte >>> counters to 0, which can be useful for debugging. >>> . >>> -.IP "\fBdiff\-flows \fIsource1 source2\fR" >>> +.IP "[\fB\-\-tables \fltable-ids\fR] \fBdiff\-flows \fIsource1 source2\fR" >>> Reads flow entries from \fIsource1\fR and \fIsource2\fR and prints the >>> differences. A flow that is in \fIsource1\fR but not in \fIsource2\fR >>> is printed preceded by a \fB\-\fR, and a flow that is in \fIsource2\fR >>> @@ -357,6 +366,13 @@ file name. A name that contains \fB:\fR is considered >>> to be a switch. >>> Otherwise, it is a file if a file by that name exists, a switch if >>> not. >>> .IP >>> +With \fB\-\-tables\fR, \fBovs\-ofctl\fR only considers flows from the >>> +comma-separated table IDs specified, e.g. (\fB\-\-tables 1,3,4,2\fR). >>> +The valid range of table IDs is 0 to 254. Unlike \fBreplace\-flows\fR, >>> +the order of table IDs is ignored. If an ID is not specified, the table >>> +with that ID is ignored and is diffed. If \fB\-\-tables\fR is not >>> +specified, all tables are diffed. >>> +.IP >>> For this command, an exit status of 0 means that no differences were >>> found, 1 means that an error occurred, and 2 means that some >>> differences were found. >>> diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c >>> index 8df79b8..f0c05b9 100644 >>> --- a/utilities/ovs-ofctl.c >>> +++ b/utilities/ovs-ofctl.c >>> @@ -13,7 +13,6 @@ >>> * See the License for the specific language governing permissions and >>> * limitations under the License. >>> */ >>> - >>> #include >>> #include >>> #include >>> @@ -29,6 +28,7 @@ >>> #include >>> #include >>> >>> +#include "bitmap.h" >>> #include "byte-order.h" >>> #include "classifier.h" >>> #include "command-line.h" >>> @@ -37,6 +37,8 @@ >>> #include "dirs.h" >>> #include "dynamic-string.h" >>> #include "fatal-signal.h" >>> +#include "hmap.h" >>> +#include "list.h" >>> #include "nx-match.h" >>> #include "odp-util.h" >>> #include "ofp-actions.h" >>> @@ -50,6 +52,7 @@ >>> #include "ofproto/ofproto.h" >>> #include "openflow/nicira-ext.h" >>> #include "openflow/openflow.h" >>> +#include "openflow/openflow-common.h" >>> #include "dp-packet.h" >>> #include "packets.h" >>> #include "pcap-file.h" >>> @@ -67,6 +70,8 @@ >>> >>> VLOG_DEFINE_THIS_MODULE(ofctl); >>> >>> +#define TABLE_IDS_BITMAP_LEN (OFPTT_MAX + 1) >>> + >>> /* --bundle: Use OpenFlow 1.4 bundle for making the flow table change >>> atomic. >>> * NOTE: Also the flow mod will use OpenFlow 1.4, so the semantics may be >>> * different (see the comment in parse_options() for details). >>> @@ -102,6 +107,21 @@ static bool timestamp; >>> commands. */ >>> static char *unixctl_path; >>> >>> +/* -T, --tables: Comma-separated list of OF flow table IDs to replace >>> flows in. >>> + * tables is a ovs_list of table IDs specified in --tables. */ >>> +static struct ovs_list tables; >>> + >>> +/* bmtables is a bitmap where an offset is set if the corresponding table >>> + * ID needs to be operated on by replace-flows or diff-flows command. >>> + * If a table ID is hidden, the corresponding offset is unset even if >>> specified >>> + * in -T, --tables. */ >>> +static unsigned long *bmtables; >>> + >>> +/* >>> + * visible_tables is a bitmap where an offset is set if the corresponding >>> table >>> + * is not a hidden table. */ >>> +static unsigned long *visible_tables; >>> + >>> /* --sort, --rsort: Sort order. */ >>> enum sort_order { SORT_ASC, SORT_DESC }; >>> struct sort_criterion { >>> @@ -120,6 +140,154 @@ static bool recv_flow_stats_reply(struct vconn *, >>> ovs_be32 send_xid, >>> struct ofpbuf **replyp, >>> struct ofputil_flow_stats *, >>> struct ofpbuf *ofpacts); >>> + >>> +static void perform_stats_transaction(struct vconn *, struct ofpbuf >>> *request, bool dump); >>> + >>> +static int table_ids_list_and_bitmap_from_string(struct ovs_list *tables, >>> + unsigned long **bmtables, >>> + const char *s); >>> + >>> +static void update_bitmaps_with_supported_table_ids(struct vconn *vconn); >>> + >>> +static void populate_visible_tables_bitmap(struct vconn *vconn, >>> + const struct ofp_header *oh); >>> + >>> +bool print_diff_flows(struct classifier *cls); >>> + >>> + /* >>> + * An element in the list of table_ids. The list has table ids in the order >>> + * specified in --tables passed to replace-flows. >>> + */ >>> +struct tables_node { >>> + struct ovs_list lnode; >>> + uint8_t table_id; >>> +}; >>> + >>> +/* Holds the hmap_node with hash and the actual classifier. */ >>> +struct hmap_table_classifier_node { >>> + struct hmap_node hnode; >>> + struct classifier cls; >>> + uint8_t table_id; >>> +}; >>> + >>> +/* >>> + * Creates a classifier for table_id and adds it into the hmap. The >>> table_id >>> + * is used as the hash. >>> + */ >>> +static struct classifier * >>> +insert_new_table_classifier(struct hmap *ht_cls, uint8_t table_id) >>> +{ >>> + struct hmap_table_classifier_node *ht_cls_node; >>> + >>> + ht_cls_node = xzalloc(sizeof(struct hmap_table_classifier_node)); >>> + ht_cls_node->table_id = table_id; >>> + classifier_init(&ht_cls_node->cls, NULL); >>> + /* Use the table_id as the hash. */ >>> + hmap_insert(ht_cls, &ht_cls_node->hnode, table_id); >>> + return &ht_cls_node->cls; >>> +} >>> + >>> +/* >>> + * Get the classifier for table_id. The table_id is used as the hash. >>> + */ >>> +static struct classifier * >>> +get_table_classifier(struct hmap *ht_cls, uint8_t table_id) >>> +{ >>> + struct hmap_table_classifier_node *ht_cls_node; >>> + HMAP_FOR_EACH_IN_BUCKET (ht_cls_node, hnode, table_id, ht_cls) { >>> + if (ht_cls_node->table_id == table_id) { >>> + return &ht_cls_node->cls; >>> + } >>> + } >>> + return NULL; >>> +} >>> + >>> +/* >>> + * Takes a string of comma-separated table IDs, creates a list >>> + * containing the table_ids in the order specified in the --tables >>> argument. >>> + * Also creates a bitmap of specified table IDs. >>> + */ >>> +static int >>> +table_ids_list_and_bitmap_from_string(struct ovs_list *tables, >>> + unsigned long **bmtables, >>> + const char *s) >>> +{ >>> + char *stemp = xstrdup(s); >>> + char *tok, *temp; >>> + unsigned int table_id; >>> + struct tables_node *tnode; >>> + >>> + *bmtables = bitmap_allocate(TABLE_IDS_BITMAP_LEN); >>> + >>> + temp = stemp; >>> + while(stemp) { >>> + tok = strsep(&stemp, ","); >>> + if(!str_to_uint(tok, 10, &table_id) >>> + || table_id > TABLE_IDS_BITMAP_LEN-1) { >>> + LIST_FOR_EACH (tnode, lnode, tables) { >>> + free(tnode); >>> + } >>> + bitmap_free(*bmtables); >>> + free(temp); >>> + return -1; >>> + } >>> + tnode = xzalloc(sizeof(struct tables_node)); >>> + tnode->table_id = table_id; >>> + list_push_back(tables, &tnode->lnode); >>> + >>> + bitmap_set(*bmtables, table_id, true); >>> + } >>> + free(temp); >>> + return 0; >>> +} >>> + >>> +/* >>> + * Make sure a bmtables offset is set only if the corresponding >>> + * table ID is supported (not hidden) in the switch. */ >>> +static void >>> +update_bitmaps_with_supported_table_ids(struct vconn *vconn) >>> +{ >>> + struct ofpbuf *request; >>> + >>> + visible_tables = bitmap_allocate(TABLE_IDS_BITMAP_LEN); >>> + >>> + if(list_is_empty(&tables)) { >>> + /* Initialize the bitmap bmtables and set all bits. */ >>> + bmtables = bitmap_allocate1(TABLE_IDS_BITMAP_LEN); >>> + } >>> + >>> + request = ofpraw_alloc(OFPRAW_OFPST_TABLE_REQUEST, >>> vconn_get_version(vconn), 0); >>> + perform_stats_transaction(vconn, request, false); >>> + bitmap_and(bmtables, visible_tables, TABLE_IDS_BITMAP_LEN); >>> +} >>> + >>> +/* >>> + * Get all visible table IDs and set offsets in visible_tables bitmap that >>> + * correspond to the table IDs. */ >>> +static void >>> +populate_visible_tables_bitmap(struct vconn *vconn, const struct >>> ofp_header *oh) >>> +{ >>> + struct ofpbuf msg; >>> + ofpbuf_use_const(&msg, oh, ntohs(oh->length)); >>> + ofpraw_pull_assert(&msg); >>> + >>> + for(;;) { >>> + struct ofputil_table_features features; >>> + struct ofputil_table_stats stats; >>> + int retval; >>> + >>> + retval = ofputil_decode_table_stats_reply(&msg, &stats, &features); >>> + if (retval) { >>> + if (retval != EOF) { >>> + ovs_fatal(0, "%s: Error while decoding table features: %s", >>> + vconn_get_name(vconn), ofperr_get_name(retval)); >>> + } >>> + return; >>> + } >>> + bitmap_set(visible_tables, features.table_id, true); >>> + } >>> +} >>> + >>> int >>> main(int argc, char *argv[]) >>> { >>> @@ -171,6 +339,7 @@ parse_options(int argc, char *argv[]) >>> VLOG_OPTION_ENUMS >>> }; >>> static const struct option long_options[] = { >>> + {"tables", required_argument, NULL, 'T'}, >>> {"timeout", required_argument, NULL, 't'}, >>> {"strict", no_argument, NULL, OPT_STRICT}, >>> {"readd", no_argument, NULL, OPT_READD}, >>> @@ -211,9 +380,13 @@ parse_options(int argc, char *argv[]) >>> */ >>> set_allowed_ofp_versions("OpenFlow10"); >>> >>> + /* Initialize ovs_list tables. */ >>> + list_init(&tables); >>> + >>> for (;;) { >>> unsigned long int timeout; >>> int c; >>> + int retval = 0; >>> >>> c = getopt_long(argc, argv, short_options, long_options, NULL); >>> if (c == -1) { >>> @@ -231,6 +404,17 @@ parse_options(int argc, char *argv[]) >>> } >>> break; >>> >>> + case 'T': >>> + retval = table_ids_list_and_bitmap_from_string(&tables, >>> + &bmtables, >>> + optarg); >>> + if (retval < 0) { >>> + ovs_fatal(0, "one of the passed table IDs %s for " >>> + "-T or --tables is invalid", optarg); >>> + } >>> + break; >>> + >>> + >>> case 'F': >>> allowed_protocols = ofputil_protocols_from_string(optarg); >>> if (!allowed_protocols) { >>> @@ -392,6 +576,7 @@ usage(void) >>> ofp_version_usage(); >>> vlog_usage(); >>> printf("\nOther options:\n" >>> + " -T, --tables=TABLES replace or diff flows in specified TABLES\n" >>> " --strict use strict match for flow commands\n" >>> " --readd replace flows that haven't changed\n" >>> " -F, --flow-format=FORMAT force particular flow format\n" >>> @@ -541,7 +726,7 @@ dump_trivial_transaction(const char *vconn_name, enum >>> ofpraw raw) >>> } >>> >>> static void >>> -dump_stats_transaction(struct vconn *vconn, struct ofpbuf *request) >>> +perform_stats_transaction(struct vconn *vconn, struct ofpbuf *request, >>> bool dump) >>> { >>> const struct ofp_header *request_oh = request->data; >>> ovs_be32 send_xid = request_oh->xid; >>> @@ -562,9 +747,13 @@ dump_stats_transaction(struct vconn *vconn, struct >>> ofpbuf *request) >>> recv_xid = ((struct ofp_header *) reply->data)->xid; >>> if (send_xid == recv_xid) { >>> enum ofpraw raw; >>> - >>> - ofp_print(stdout, reply->data, reply->size, verbosity + 1); >>> - >>> + if (dump) { >>> + ofp_print(stdout, reply->data, reply->size, verbosity + 1); >>> + } >>> + else { >>> + /* Update bmtables - set offset = table ID. */ >>> + populate_visible_tables_bitmap(vconn, (struct ofp_header *) reply->data); >>> + } >>> ofpraw_decode(&raw, reply->data); >>> if (ofptype_from_ofpraw(raw) == OFPTYPE_ERROR) { >>> done = true; >>> @@ -584,6 +773,12 @@ dump_stats_transaction(struct vconn *vconn, struct >>> ofpbuf *request) >>> } >>> >>> static void >>> +dump_stats_transaction(struct vconn *vconn, struct ofpbuf *request) >>> +{ >>> + perform_stats_transaction(vconn, request, true); >>> +} >>> + >>> +static void >>> dump_trivial_stats_transaction(const char *vconn_name, enum ofpraw raw) >>> { >>> struct ofpbuf *request; >>> @@ -2455,6 +2650,7 @@ fte_insert(struct classifier *cls, const struct match >>> *match, >>> int priority, struct fte_version *version, int index) >>> { >>> struct fte *old, *fte; >>> + classifier_defer(cls); >>> >>> fte = xzalloc(sizeof *fte); >>> cls_rule_init(&fte->rule, match, priority, CLS_MIN_VERSION); >>> @@ -2473,12 +2669,13 @@ fte_insert(struct classifier *cls, const struct >>> match *match, >>> * with the specified 'index'. Returns the flow formats able to represent the >>> * flows that were read. */ >>> static enum ofputil_protocol >>> -read_flows_from_file(const char *filename, struct classifier *cls, int >>> index) >>> +read_flows_from_file(const char *filename, struct hmap *ht_cls, int index) >>> { >>> enum ofputil_protocol usable_protocols; >>> int line_number; >>> struct ds s; >>> FILE *file; >>> + struct classifier *cls; >>> >>> file = !strcmp(filename, "-") ? stdin : fopen(filename, "r"); >>> if (file == NULL) { >>> @@ -2488,7 +2685,7 @@ read_flows_from_file(const char *filename, struct >>> classifier *cls, int index) >>> ds_init(&s); >>> usable_protocols = OFPUTIL_P_ANY; >>> line_number = 0; >>> - classifier_defer(cls); >>> + >>> while (!ds_get_preprocessed_line(&s, file, &line_number)) { >>> struct fte_version *version; >>> struct ofputil_flow_mod fm; >>> @@ -2510,10 +2707,27 @@ read_flows_from_file(const char *filename, struct >>> classifier *cls, int index) >>> | OFPUTIL_FF_EMERG); >>> version->ofpacts = fm.ofpacts; >>> version->ofpacts_len = fm.ofpacts_len; >>> + if (fm.table_id == 0xff) { >>> + fm.table_id = 0x0; >>> + } >>> + >>> + if (!list_is_empty(&tables) >>> + && bmtables >>> + && !bitmap_is_set(bmtables, fm.table_id)) { >>> + /* >>> + * Ignore this flow if --tables is specified but does >>> + * not contain the table_id. >>> + */ >>> + continue; >>> + } >>> >>> + cls = get_table_classifier(ht_cls, fm.table_id); >>> + if (cls == NULL) { >>> + cls = insert_new_table_classifier(ht_cls, fm.table_id); >>> + } >>> fte_insert(cls, &fm.match, fm.priority, version, index); >>> } >>> - classifier_publish(cls); >>> + >>> ds_destroy(&s); >>> >>> if (file != stdin) { >>> @@ -2582,8 +2796,9 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 >>> send_xid, >>> static void >>> read_flows_from_switch(struct vconn *vconn, >>> enum ofputil_protocol protocol, >>> - struct classifier *cls, int index) >>> + struct hmap *ht_cls, int index) >>> { >>> + struct classifier *cls; >>> struct ofputil_flow_stats_request fsr; >>> struct ofputil_flow_stats fs; >>> struct ofpbuf *request; >>> @@ -2593,16 +2808,29 @@ read_flows_from_switch(struct vconn *vconn, >>> >>> fsr.aggregate = false; >>> match_init_catchall(&fsr.match); >>> - fsr.out_port = OFPP_ANY; >>> - fsr.table_id = 0xff; >>> + >>> + /* Only get tables that are not hidden. */ >>> + update_bitmaps_with_supported_table_ids(vconn); >>> + >>> + if (list_size(&tables) == 1) { >>> + /* Only retrieve flows from the specified table. */ >>> + struct tables_node * tnode; >>> + tnode = CONTAINER_OF(list_front(&tables), struct tables_node, lnode); >>> + fsr.table_id = tnode->table_id; >>> + } >>> + else { >>> + fsr.table_id = 0xff; >>> + } >>> fsr.cookie = fsr.cookie_mask = htonll(0); >>> + fsr.out_group = OFPG11_ANY; >>> + fsr.out_port = OFPP_ANY; >>> + >>> request = ofputil_encode_flow_stats_request(&fsr, protocol); >>> send_xid = ((struct ofp_header *) request->data)->xid; >>> send_openflow_buffer(vconn, request); >>> >>> reply = NULL; >>> ofpbuf_init(&ofpacts, 0); >>> - classifier_defer(cls); >>> while (recv_flow_stats_reply(vconn, send_xid, &reply, &fs, &ofpacts)) { >>> struct fte_version *version; >>> >>> @@ -2614,35 +2842,48 @@ read_flows_from_switch(struct vconn *vconn, >>> version->flags = 0; >>> version->ofpacts_len = fs.ofpacts_len; >>> version->ofpacts = xmemdup(fs.ofpacts, fs.ofpacts_len); >>> - >>> + if (!list_is_empty(&tables) >>> + && bmtables >>> + && !bitmap_is_set(bmtables, fs.table_id)) { >>> + /* >>> + * Ignore this flow if --tables is specified but does >>> + * not contain the table_id. >>> + */ >>> + continue; >>> + } >>> + cls = get_table_classifier(ht_cls, fs.table_id); >>> + if (cls == NULL) { >>> + cls = insert_new_table_classifier(ht_cls, fs.table_id); >>> + } >>> fte_insert(cls, &fs.match, fs.priority, version, index); >>> } >>> - classifier_publish(cls); >>> ofpbuf_uninit(&ofpacts); >>> } >>> >>> static void >>> -fte_make_flow_mod(const struct fte *fte, int index, uint16_t command, >>> - enum ofputil_protocol protocol, struct ovs_list *packets) >>> +fte_make_flow_mod(const struct fte *fte, >>> + int index, uint16_t command, >>> + enum ofputil_protocol protocol, >>> + struct ovs_list *packets, uint8_t table_id) >>> { >>> const struct fte_version *version = fte->versions[index]; >>> struct ofputil_flow_mod fm; >>> struct ofpbuf *ofm; >>> - >>> minimatch_expand(&fte->rule.match, &fm.match); >>> fm.priority = fte->rule.priority; >>> fm.cookie = htonll(0); >>> fm.cookie_mask = htonll(0); >>> fm.new_cookie = version->cookie; >>> fm.modify_cookie = true; >>> - fm.table_id = 0xff; >>> + fm.table_id = table_id; >>> fm.command = command; >>> fm.idle_timeout = version->idle_timeout; >>> fm.hard_timeout = version->hard_timeout; >>> - fm.importance = version->importance; >>> fm.buffer_id = UINT32_MAX; >>> fm.out_port = OFPP_ANY; >>> + fm.out_group = OFPG_ANY; >>> fm.flags = version->flags; >>> + fm.importance = version->importance; >>> if (command == OFPFC_ADD || command == OFPFC_MODIFY || >>> command == OFPFC_MODIFY_STRICT) { >>> fm.ofpacts = version->ofpacts; >>> @@ -2657,93 +2898,153 @@ fte_make_flow_mod(const struct fte *fte, int >>> index, uint16_t command, >>> list_push_back(packets, &ofm->list_node); >>> } >>> >>> + >>> +static void >>> +construct_flow_mods(struct ovs_list *requests, >>> + enum ofputil_protocol protocol, >>> + struct fte *fte, >>> + uint8_t table_id) >>> +{ >>> + enum { FILE_IDX = 0, SWITCH_IDX = 1 }; >>> + struct fte_version *file_ver = fte->versions[FILE_IDX]; >>> + struct fte_version *sw_ver = fte->versions[SWITCH_IDX]; >>> + >>> + if (sw_ver && !file_ver) { >>> + fte_make_flow_mod(fte, SWITCH_IDX, >>> + OFPFC_DELETE_STRICT, >>> + protocol, requests, >>> + table_id); >>> + } >>> + else if (file_ver >>> + && (readd || !sw_ver)) { >>> + fte_make_flow_mod(fte, FILE_IDX, OFPFC_ADD, >>> + protocol, requests, >>> + table_id); >>> + } >>> + else if (file_ver >>> + && sw_ver && !fte_version_equals(sw_ver, file_ver)) { >>> + fte_make_flow_mod(fte, FILE_IDX, >>> + OFPFC_MODIFY_STRICT, >>> + protocol, requests, >>> + table_id); >>> + } >>> +} >>> + >>> +static void >>> +add_update_delete_switch_flows(struct ovs_list *requests, >>> + struct hmap *ht_cls, >>> + enum ofputil_protocol protocol) >>> +{ >>> + struct classifier *cls; >>> + struct fte *fte; >>> + >>> + if (!list_is_empty(&tables)) { >>> + struct tables_node *tnode; >>> + LIST_FOR_EACH (tnode, lnode, &tables) { >>> + cls = get_table_classifier(ht_cls, tnode->table_id); >>> + if (cls == NULL) { >>> + /* Trying to get a flow that does not exist. */ >>> + continue; >>> + } >>> + classifier_publish(cls); >>> + CLS_FOR_EACH (fte, rule, cls) { >>> + construct_flow_mods(requests, protocol, fte, tnode->table_id); >>> + } >>> + fte_free_all(cls); >>> + } >>> + } >>> + else { >>> + struct hmap_table_classifier_node *ht_cls_node; >>> + HMAP_FOR_EACH (ht_cls_node, hnode, ht_cls) { >>> + cls = get_table_classifier(ht_cls, ht_cls_node->table_id); >>> + if (cls == NULL) { >>> + /* Trying to get a flow that does not exist. */ >>> + continue; >>> + } >>> + classifier_publish(cls); >>> + CLS_FOR_EACH (fte, rule, cls) { >>> + construct_flow_mods(requests, >>> + protocol, >>> + fte, >>> + ht_cls_node->table_id); >>> + } >>> + fte_free_all(cls); >>> + } >>> + } >>> +} >>> + >>> static void >>> ofctl_replace_flows(struct ovs_cmdl_context *ctx) >>> { >>> enum { FILE_IDX = 0, SWITCH_IDX = 1 }; >>> enum ofputil_protocol usable_protocols, protocol; >>> - struct classifier cls; >>> + >>> + struct hmap ht_cls; >>> struct ovs_list requests; >>> struct vconn *vconn; >>> - struct fte *fte; >>> >>> - classifier_init(&cls, NULL); >>> - usable_protocols = read_flows_from_file(ctx->argv[2], &cls, FILE_IDX); >>> >>> - protocol = open_vconn(ctx->argv[1], &vconn); >>> - protocol = set_protocol_for_flow_dump(vconn, protocol, usable_protocols); >>> + /* Initialize the hash map. */ >>> + hmap_init(&ht_cls); >>> >>> - read_flows_from_switch(vconn, protocol, &cls, SWITCH_IDX); >>> + /* Read flows from the file. */ >>> + usable_protocols = read_flows_from_file(ctx->argv[2], &ht_cls, FILE_IDX); >>> >>> - list_init(&requests); >>> + /* Setup connection to the switch. */ >>> + protocol = open_vconn_for_flow_mod(ctx->argv[1], &vconn, >>> usable_protocols); >>> + protocol = set_protocol_for_flow_dump(vconn, protocol, usable_protocols); >>> >>> - /* Delete flows that exist on the switch but not in the file. */ >>> - CLS_FOR_EACH (fte, rule, &cls) { >>> - struct fte_version *file_ver = fte->versions[FILE_IDX]; >>> - struct fte_version *sw_ver = fte->versions[SWITCH_IDX]; >>> + /* Generate switch dump request. */ >>> + read_flows_from_switch(vconn, protocol, &ht_cls, SWITCH_IDX); >>> >>> - if (sw_ver && !file_ver) { >>> - fte_make_flow_mod(fte, SWITCH_IDX, OFPFC_DELETE_STRICT, >>> - protocol, &requests); >>> - } >>> - } >>> + list_init(&requests); >>> >>> - /* Add flows that exist in the file but not on the switch. >>> - * Update flows that exist in both places but differ. */ >>> - CLS_FOR_EACH (fte, rule, &cls) { >>> - struct fte_version *file_ver = fte->versions[FILE_IDX]; >>> - struct fte_version *sw_ver = fte->versions[SWITCH_IDX]; >>> + /* Delete flows that exist on the switch but not in the file. >>> + * Add flows that exist in the file but not on the switch. >>> + * Update the flows that exist in both places but differ. >>> + * If --tables is specified, iterate through tables, >>> + * perform deletion in order. */ >>> + add_update_delete_switch_flows(&requests, &ht_cls, protocol); >>> >>> - if (file_ver >>> - && (readd || !sw_ver || !fte_version_equals(sw_ver, file_ver))) { >>> - fte_make_flow_mod(fte, FILE_IDX, OFPFC_ADD, protocol, &requests); >>> - } >>> - } >>> if (bundle) { >>> bundle_transact(vconn, &requests, OFPBF_ORDERED | OFPBF_ATOMIC); >>> } else { >>> transact_multiple_noreply(vconn, &requests); >>> } >>> + hmap_destroy(&ht_cls); >>> vconn_close(vconn); >>> - >>> - fte_free_all(&cls); >>> } >>> >>> static void >>> -read_flows_from_source(const char *source, struct classifier *cls, int >>> index) >>> +read_flows_from_source(const char *source, struct hmap *ht_cls, int index) >>> { >>> struct stat s; >>> - >>> if (source[0] == '/' || source[0] == '.' >>> || (!strchr(source, ':') && !stat(source, &s))) { >>> - read_flows_from_file(source, cls, index); >>> + read_flows_from_file(source, ht_cls, index); >>> } else { >>> enum ofputil_protocol protocol; >>> struct vconn *vconn; >>> >>> + /* Setup connection to switch and generate dump request. */ >>> protocol = open_vconn(source, &vconn); >>> protocol = set_protocol_for_flow_dump(vconn, protocol, OFPUTIL_P_ANY); >>> - read_flows_from_switch(vconn, protocol, cls, index); >>> + read_flows_from_switch(vconn, protocol, ht_cls, index); >>> vconn_close(vconn); >>> } >>> } >>> >>> -static void >>> -ofctl_diff_flows(struct ovs_cmdl_context *ctx) >>> +bool >>> +print_diff_flows(struct classifier *cls) >>> { >>> - bool differences = false; >>> - struct classifier cls; >>> struct ds a_s, b_s; >>> struct fte *fte; >>> - >>> - classifier_init(&cls, NULL); >>> - read_flows_from_source(ctx->argv[1], &cls, 0); >>> - read_flows_from_source(ctx->argv[2], &cls, 1); >>> + bool differences = false; >>> >>> ds_init(&a_s); >>> ds_init(&b_s); >>> - >>> - CLS_FOR_EACH (fte, rule, &cls) { >>> + classifier_publish(cls); >>> + CLS_FOR_EACH (fte, rule, cls) { >>> struct fte_version *a = fte->versions[0]; >>> struct fte_version *b = fte->versions[1]; >>> >>> @@ -2761,12 +3062,46 @@ ofctl_diff_flows(struct ovs_cmdl_context *ctx) >>> } >>> } >>> } >>> - >>> + fte_free_all(cls); >>> ds_destroy(&a_s); >>> ds_destroy(&b_s); >>> + return differences; >>> +} >>> >>> - fte_free_all(&cls); >>> - >>> +static void >>> +ofctl_diff_flows(struct ovs_cmdl_context *ctx) >>> +{ >>> + bool differences = false; >>> + struct classifier *cls; >>> + struct hmap ht_cls; >>> + >>> + hmap_init(&ht_cls); >>> + read_flows_from_source(ctx->argv[1], &ht_cls, 0); >>> + read_flows_from_source(ctx->argv[2], &ht_cls, 1); >>> + >>> + if (!list_is_empty(&tables)) { >>> + struct tables_node *tnode; >>> + LIST_FOR_EACH (tnode, lnode, &tables) { >>> + cls = get_table_classifier(&ht_cls, tnode->table_id); >>> + if (cls == NULL) { >>> + /* Trying to diff a flow that does not exist. */ >>> + continue; >>> + } >>> + differences = print_diff_flows(cls); >>> + } >>> + } >>> + else { >>> + struct hmap_table_classifier_node *ht_cls_node; >>> + HMAP_FOR_EACH (ht_cls_node, hnode, &ht_cls) { >>> + cls = get_table_classifier(&ht_cls, ht_cls_node->table_id); >>> + if (cls == NULL) { >>> + /* Trying to diff a flow that does not exist. */ >>> + continue; >>> + } >>> + differences = print_diff_flows(cls); >>> + } >>> + } >>> + hmap_destroy(&ht_cls); >>> if (differences) { >>> exit(2); >>> } >>> -- >>> 2.3.5 >>> >> > > _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev