1 AT_BANNER([learning action])
3 AT_SETUP([learning action - parsing and formatting])
4 AT_DATA([flows.txt], [[
6 actions=learn(send_flow_rem)
7 actions=learn(delete_learned)
8 actions=learn(send_flow_rem,delete_learned)
9 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])
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])
12 AT_CHECK([ovs-ofctl parse-flows flows.txt], [0],
13 [[usable protocols: any
14 chosen protocol: OpenFlow10-table_id
15 OFPT_FLOW_MOD (xid=0x1): ADD actions=learn(table=1)
16 OFPT_FLOW_MOD (xid=0x2): ADD actions=learn(table=1,send_flow_rem)
17 OFPT_FLOW_MOD (xid=0x3): ADD actions=learn(table=1,delete_learned)
18 OFPT_FLOW_MOD (xid=0x4): ADD actions=learn(table=1,send_flow_rem,delete_learned)
19 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])
20 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])
24 AT_SETUP([learning action - parsing and formatting - illegal in_port_oxm])
25 AT_CHECK([[ovs-ofctl parse-flow 'actions=learn(table=1, in_port_oxm=123456)']],
27 AT_CHECK([sed -e 's/.*|ofp_util|WARN|//' < stderr], [0],
28 [[port 123456 is outside the supported range 0 through ffff or 0xffffff00 through 0xffffffff
29 ovs-ofctl: 123456: port value out of range for in_port_oxm
33 AT_SETUP([learning action - parsing and formatting - OXM])
34 AT_DATA([flows.txt], [[
35 actions=learn(output:OXM_OF_IN_PORT[])
36 actions=learn(table=1, in_port=1, load:OXM_OF_IN_PORT[]->NXM_NX_REG1[], load:0xfffffffe->OXM_OF_IN_PORT[])
38 AT_CHECK([ovs-ofctl -O OpenFlow12 parse-flows flows.txt], [0],
39 [[usable protocols: any
40 chosen protocol: OXM-OpenFlow12
41 OFPT_FLOW_MOD (OF1.2) (xid=0x1): ADD actions=learn(table=1,output:OXM_OF_IN_PORT[])
42 OFPT_FLOW_MOD (OF1.2) (xid=0x2): ADD actions=learn(table=1,in_port=1,load:OXM_OF_IN_PORT[]->NXM_NX_REG1[],load:0xfffffffe->OXM_OF_IN_PORT[])
46 AT_SETUP([learning action - examples])
47 AT_DATA([flows.txt], [[
48 # These are the examples from nicira-ext.h.
49 actions=learn(in_port=99,NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], load:NXM_OF_IN_PORT[]->NXM_NX_REG1[16..31])
50 actions=learn(NXM_OF_VLAN_TCI[0..11], NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],output:NXM_OF_IN_PORT[])
51 table=0 actions=learn(table=1,hard_timeout=10, NXM_OF_VLAN_TCI[0..11],output:NXM_OF_IN_PORT[]), resubmit(,1)
52 table=1 priority=0 actions=flood
54 AT_CHECK([ovs-ofctl parse-flows flows.txt], [0],
55 [[usable protocols: OXM,OpenFlow10+table_id,NXM+table_id,OpenFlow11
56 chosen protocol: OpenFlow10+table_id
57 OFPT_FLOW_MOD (xid=0x1): ADD table:255 actions=learn(table=1,in_port=99,NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG1[16..31])
58 OFPT_FLOW_MOD (xid=0x2): ADD table:255 actions=learn(table=1,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],output:NXM_OF_IN_PORT[])
59 OFPT_FLOW_MOD (xid=0x3): ADD actions=learn(table=1,hard_timeout=10,NXM_OF_VLAN_TCI[0..11],output:NXM_OF_IN_PORT[]),resubmit(,1)
60 OFPT_FLOW_MOD (xid=0x4): ADD table:1 priority=0 actions=FLOOD
64 AT_SETUP([learning action - satisfied prerequisites])
66 [[actions=learn(eth_type=0x800,load:5->NXM_OF_IP_DST[])
67 ip,actions=learn(load:NXM_OF_IP_DST[]->NXM_NX_REG1[])
68 ip,actions=learn(eth_type=0x800,OXM_OF_IPV4_DST[])
70 AT_CHECK([ovs-ofctl parse-flows flows.txt], [0],
71 [[usable protocols: any
72 chosen protocol: OpenFlow10-table_id
73 OFPT_FLOW_MOD (xid=0x1): ADD actions=learn(table=1,eth_type=0x800,load:0x5->NXM_OF_IP_DST[])
74 OFPT_FLOW_MOD (xid=0x2): ADD ip actions=learn(table=1,load:NXM_OF_IP_DST[]->NXM_NX_REG1[])
75 OFPT_FLOW_MOD (xid=0x3): ADD ip actions=learn(table=1,eth_type=0x800,NXM_OF_IP_DST[])
79 AT_SETUP([learning action - invalid prerequisites])
80 AT_CHECK([[ovs-ofctl parse-flow 'actions=learn(load:5->NXM_OF_IP_DST[])']],
82 AT_CHECK([sed -e 's/.*|meta_flow|WARN|//' < stderr], [0],
83 [[destination field ip_dst lacks correct prerequisites
84 ovs-ofctl: actions are invalid with specified match (OFPBAC_MATCH_INCONSISTENT)
86 AT_CHECK([[ovs-ofctl parse-flow 'actions=learn(load:NXM_OF_IP_DST[]->NXM_NX_REG1[])']],
88 AT_CHECK([sed -e 's/.*|meta_flow|WARN|//' < stderr], [0],
89 [[source field ip_dst lacks correct prerequisites
90 ovs-ofctl: actions are invalid with specified match (OFPBAC_MATCH_INCONSISTENT)
94 AT_SETUP([learning action - standard VLAN+MAC learning])
96 [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 -- \
97 add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2 -- \
98 add-port br0 p3 -- set Interface p3 type=dummy ofport_request=3])
99 # Set up flow table for VLAN+MAC learning.
100 AT_DATA([flows.txt], [[
101 table=0 actions=learn(table=1, hard_timeout=60, NXM_OF_VLAN_TCI[0..11], NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], output:NXM_OF_IN_PORT[]), resubmit(,1)
102 table=1 priority=0 actions=flood
104 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
106 # Trace an ARP packet arriving on port 3, to create a MAC learning entry.
107 flow="in_port(3),eth(src=50:54:00:00:00:05,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=192.168.0.1,tip=192.168.0.2,op=1,sha=50:54:00:00:00:05,tha=00:00:00:00:00:00)"
108 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow" -generate], [0], [stdout])
109 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
112 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
114 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
116 # Check for the MAC learning entry.
117 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
118 table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:05 actions=output:3
119 table=1, priority=0 actions=FLOOD
123 # Trace a packet arrival destined for the learned MAC.
124 # (This will also learn a MAC.)
125 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:06,dst=50:54:00:00:00:05),eth_type(0x0806),arp(sip=192.168.0.2,tip=192.168.0.1,op=2,sha=50:54:00:00:00:06,tha=50:54:00:00:00:05)' -generate], [0], [stdout])
126 AT_CHECK([tail -1 stdout], [0], [Datapath actions: 3
129 # Check for both MAC learning entries.
130 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip |sort], [0], [dnl
131 table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:05 actions=output:3
132 table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:06 actions=output:1
133 table=1, priority=0 actions=FLOOD
137 # Trace a packet arrival that updates the first learned MAC entry.
138 flow="in_port(2),eth(src=50:54:00:00:00:05,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=192.168.0.1,tip=192.168.0.2,op=1,sha=50:54:00:00:00:05,tha=00:00:00:00:00:00)"
139 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow" -generate], [0], [stdout])
140 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
143 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
145 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
147 # Check that the MAC learning entry was updated.
148 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
149 table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:05 actions=output:2
150 table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:06 actions=output:1
151 table=1, priority=0 actions=FLOOD
157 dnl This test checks that repeated uses of a "learn" action cause the
158 dnl modified time of the learned flow to advance. Otherwise, the
159 dnl learned flow will expire after its hard timeout even though it's
160 dnl supposed to be refreshed. (The expiration can be hard to see since
161 dnl it gets re-learned again the next time a packet appears, but
162 dnl sometimes the expiration can cause temporary flooding etc.)
163 AT_SETUP([learning action - learn refreshes hard_age])
165 [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 -- \
166 add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2 -- \
167 add-port br0 p3 -- set Interface p3 type=dummy ofport_request=3])
171 # Set up flow table for MAC learning.
172 AT_DATA([flows.txt], [[
173 table=0 actions=learn(table=1, hard_timeout=10, NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], output:NXM_OF_IN_PORT[]), resubmit(,1)
174 table=1 priority=0 actions=flood
176 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
178 # Trace an ICMP packet arriving on port 3, to create a MAC learning entry.
179 flow="in_port(3),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)"
180 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow" -generate], [0], [stdout])
181 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
184 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
186 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
188 # Check that the MAC learning entry appeared.
189 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
190 table=1, hard_timeout=10, dl_dst=50:54:00:00:00:07 actions=output:3
191 table=1, priority=0 actions=FLOOD
195 # For 25 seconds, make sure that the MAC learning entry doesn't
196 # disappear as long as we refresh it every second.
197 for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25; do
198 ovs-appctl time/warp 1000
199 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow" -generate], [0], [stdout])
201 # Check that the entry is there.
202 AT_CHECK([ovs-ofctl dump-flows br0 table=1], [0], [stdout])
203 AT_CHECK([ofctl_strip < stdout | sort], [0], [dnl
204 table=1, hard_timeout=10, dl_dst=50:54:00:00:00:07 actions=output:3
205 table=1, priority=0 actions=FLOOD
209 if test $i != 1; then
210 # Check that hard_age has appeared. We need to do this separately
211 # from the above check because ofctl_strip removes it. dump-flows
212 # only prints hard_age when it is different from the flow's duration
213 # (that is, the number of seconds from the time it was created),
214 # so we only check for it after we've refreshed the flow once.
215 AT_CHECK([grep dl_dst=50:54:00:00:00:07 stdout | grep -c hard_age],
221 # Make sure that 15 seconds without refreshing makes the flow time out.
222 ovs-appctl time/warp 5000
223 ovs-appctl time/warp 5000
224 ovs-appctl time/warp 5000
226 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
227 table=1, priority=0 actions=FLOOD
233 AT_SETUP([learning action - TCPv4 port learning])
235 [add-port br0 p1 -- set Interface p1 type=dummy -- \
236 add-port br0 p2 -- set Interface p2 type=dummy -- \
237 add-port br0 p3 -- set Interface p3 type=dummy])
238 # Set up flow table for TCPv4 port learning.
239 AT_CHECK([[ovs-ofctl add-flow br0 'table=0 tcp actions=learn(table=1, hard_timeout=60, eth_type=0x800, nw_proto=6, NXM_OF_IP_SRC[]=NXM_OF_IP_DST[], NXM_OF_IP_DST[]=NXM_OF_IP_SRC[], NXM_OF_TCP_SRC[]=NXM_OF_TCP_DST[], NXM_OF_TCP_DST[]=NXM_OF_TCP_SRC[]), flood']])
241 # Trace a TCPv4 packet arriving on port 3.
242 flow="in_port(3),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:06),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=6,tos=0,ttl=64,frag=no),tcp(src=40000,dst=80)"
243 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow" -generate], [0], [stdout])
244 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
247 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
249 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
251 # Check for the learning entry.
252 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
253 table=1, hard_timeout=60, tcp,nw_src=192.168.0.1,nw_dst=192.168.0.2,tp_src=80,tp_dst=40000 actions=drop
259 AT_SETUP([learning action - TCPv6 port learning])
261 [add-port br0 p1 -- set Interface p1 type=dummy -- \
262 add-port br0 p2 -- set Interface p2 type=dummy -- \
263 add-port br0 p3 -- set Interface p3 type=dummy])
264 # Set up flow table for TCPv6 port learning.
265 # Also add a 128-bit-wide "load" action and a 128-bit literal match to check
267 AT_CHECK([[ovs-ofctl add-flow br0 'table=0 tcp6 actions=learn(table=1, hard_timeout=60, eth_type=0x86dd, nw_proto=6, NXM_NX_IPV6_SRC[]=NXM_NX_IPV6_DST[], ipv6_dst=2001:0db8:85a3:0000:0000:8a2e:0370:7334, NXM_OF_TCP_SRC[]=NXM_OF_TCP_DST[], NXM_OF_TCP_DST[]=NXM_OF_TCP_SRC[], load(0x20010db885a308d313198a2e03707348->NXM_NX_IPV6_DST[])), flood']])
269 # Trace a TCPv6 packet arriving on port 3.
270 flow="in_port(3),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:06),eth_type(0x86dd),ipv6(src=fec0::2,dst=fec0::1,label=0,proto=6,tclass=0,hlimit=255,frag=no),tcp(src=40000,dst=80)"
271 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow" -generate], [0], [stdout])
272 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
275 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
277 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
279 # Check for the learning entry.
280 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
281 table=1, hard_timeout=60, tcp6,ipv6_src=fec0::1,ipv6_dst=2001:db8:85a3::8a2e:370:7334,tp_src=80,tp_dst=40000 actions=load:0x13198a2e03707348->NXM_NX_IPV6_DST[[0..63]],load:0x20010db885a308d3->NXM_NX_IPV6_DST[[64..127]]
282 tcp6 actions=learn(table=1,hard_timeout=60,eth_type=0x86dd,nw_proto=6,NXM_NX_IPV6_SRC[[]]=NXM_NX_IPV6_DST[[]],ipv6_dst=2001:db8:85a3::8a2e:370:7334,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],NXM_OF_TCP_DST[[]]=NXM_OF_TCP_SRC[[]],load:0x20010db885a308d313198a2e03707348->NXM_NX_IPV6_DST[[]]),FLOOD
288 # In this use of a learn action, the first packet in the flow creates
289 # a new flow that changes the behavior of subsequent packets in the
291 AT_SETUP([learning action - self-modifying flow])
293 ADD_OF_PORTS([br0], 1, 2, 3)
296 # Set up flow table for TCPv4 port learning.
297 AT_CHECK([[ovs-ofctl add-flow br0 'actions=load:3->NXM_NX_REG0[0..15],learn(table=0,priority=65535,NXM_OF_ETH_SRC[],NXM_OF_VLAN_TCI[0..11],output:NXM_NX_REG0[0..15]),output:2']])
299 # Trace some packets arriving. The particular packets don't matter.
300 for i in 1 2 3 4 5 6 7 8 9 10; do
301 ovs-appctl netdev-dummy/receive p1 'in_port(1),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=64,frag=no),tcp(src=8,dst=9)'
302 ovs-appctl time/warp 10
303 if [[ $i -eq 1 ]]; then
308 # Check for the learning entry.
309 ovs-appctl time/warp 1000
310 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0],
311 [[ n_packets=1, n_bytes=60, actions=load:0x3->NXM_NX_REG0[0..15],learn(table=0,priority=65535,NXM_OF_ETH_SRC[],NXM_OF_VLAN_TCI[0..11],output:NXM_NX_REG0[0..15]),output:2
312 n_packets=9, n_bytes=540, priority=65535,vlan_tci=0x0000/0x0fff,dl_src=50:54:00:00:00:05 actions=output:3
316 # Check that the first packet went out port 2 and the rest out port 3.
318 [(ovs-ofctl dump-ports br0 2; ovs-ofctl dump-ports br0 3) | STRIP_XIDS], [0],
319 [OFPST_PORT reply: 1 ports
320 port 2: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
321 tx pkts=1, bytes=60, drop=0, errs=0, coll=0
322 OFPST_PORT reply: 1 ports
323 port 3: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
324 tx pkts=9, bytes=540, drop=0, errs=0, coll=0
330 # This test is much like the previous, but adds idle timeouts and sends
331 # two different flows to the bridge. This tests that the statistics are
332 # attributed correctly.
333 AT_SETUP([learning action - self-modifying flow with idle_timeout])
335 ADD_OF_PORTS([br0], 1, 2, 3)
338 # Set up flow table for TCPv4 port learning.
339 AT_CHECK([[ovs-ofctl add-flow br0 'actions=load:3->NXM_NX_REG0[0..15],learn(table=0,idle_timeout=5,priority=65535,NXM_OF_ETH_SRC[],NXM_OF_VLAN_TCI[0..11],output:NXM_NX_REG0[0..15]),output:2']])
341 # Trace some packets arriving. The particular packets don't matter.
342 for i in `seq 1 10`; do
343 ovs-appctl netdev-dummy/receive p1 'in_port(1),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=64,frag=no),tcp(src=8,dst=9)'
344 ovs-appctl time/warp 10
345 if [[ $i -eq 1 ]]; then
350 # Trace some packets arriving. This is is a different flow from the previous.
351 # Note that we advance time by 1 second between each packet here.
352 for i in `seq 1 10`; do
353 ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:06,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=64,frag=no),tcp(src=8,dst=9)'
354 ovs-appctl time/warp 1000
355 # Note: netdev-dummy/receive merely queues the packet.
356 # We need to wait for other thread to process the packet
357 # and update the flow's 'used' for the packet.
358 # (i % 3 == 0) below is somehow arbitrary but chosen to ensure
359 # that we update the flow's 'used' frequently enough to prevent
361 if [[ $i -eq 1 -o $((i % 3)) -eq 0 ]]; then
366 # Check that the first packet of each flow went out port 2 and the rest out
369 [(ovs-ofctl dump-ports br0 2; ovs-ofctl dump-ports br0 3) | STRIP_XIDS], [0],
370 [OFPST_PORT reply: 1 ports
371 port 2: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
372 tx pkts=2, bytes=120, drop=0, errs=0, coll=0
373 OFPST_PORT reply: 1 ports
374 port 3: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
375 tx pkts=18, bytes=1080, drop=0, errs=0, coll=0
378 # Check for the learning entry.
379 ovs-appctl time/warp 1000
380 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0],
381 [[ n_packets=2, n_bytes=120, actions=load:0x3->NXM_NX_REG0[0..15],learn(table=0,idle_timeout=5,priority=65535,NXM_OF_ETH_SRC[],NXM_OF_VLAN_TCI[0..11],output:NXM_NX_REG0[0..15]),output:2
382 n_packets=9, n_bytes=540, idle_timeout=5, priority=65535,vlan_tci=0x0000/0x0fff,dl_src=50:54:00:00:00:06 actions=output:3
388 # This test is much like the previous, but adds hard timeouts and sends
389 # two different flows to the bridge. This tests that the statistics are
390 # attributed correctly.
391 AT_SETUP([learning action - self-modifying flow with hard_timeout])
393 ADD_OF_PORTS([br0], 1, 2, 3)
396 # Set up flow table for TCPv4 port learning.
397 AT_CHECK([[ovs-ofctl add-flow br0 'actions=load:3->NXM_NX_REG0[0..15],learn(table=0,hard_timeout=10,priority=65535,NXM_OF_ETH_SRC[],NXM_OF_VLAN_TCI[0..11],output:NXM_NX_REG0[0..15]),output:2']])
399 # Trace some packets arriving. The particular packets don't matter.
400 for i in `seq 1 10`; do
401 ovs-appctl netdev-dummy/receive p1 'in_port(1),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=64,frag=no),tcp(src=8,dst=9)'
402 if [[ $i -eq 1 ]]; then
405 ovs-appctl time/warp 10
408 # Trace some packets arriving. This is is a different flow from the previous.
409 # Note that we advance time by 2 second between each packet here.
410 for i in `seq 1 10`; do
411 ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:06,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=64,frag=no),tcp(src=8,dst=9)'
412 # Note: hard_timeout should fire immediately after #6 packet.
413 # #7 packet re-install the flow and the following 3 packets
414 # (#8, #9, #10) use the flow.
415 # it's difficult to predict the exact timing of rule expiry
416 # because it's affected by flow dumper thread via udpif_dump_seq.
417 # hard_timeout value for this test was chosen to overcome the uncertainty.
419 # receive #1 learn, install flow with hard_timeout=10
420 # sleep to ensure the flow installation
421 # (warp, timeout left 8s)
422 # receive #2 the learned flow
423 # (warp, timeout left 6s)
425 # (warp, timeout left 4s)
427 # (warp, timeout left 2s)
429 # (warp, timeout left 0s)
430 # NOTE: OVS does not consider this expired yet. cf. rule_expire()
432 # (warp, timeout left -2s)
433 # sleep to ensure flow expiration
434 # receive #7 learn, install flow with hard_timeout=10
435 # sleep to ensure the flow installation
436 # (warp, timeout left 8s)
438 # (warp, timeout left 6s)
440 # (warp, timeout left 4s)
442 # (warp, timeout left 2s)
443 if [[ $i -eq 1 -o $i -eq 7 ]]; then
446 ovs-appctl time/warp 2000
447 if [[ $i -eq 6 ]]; then
452 # Check that the first packet of each flow went out port 2 and the rest out
455 [(ovs-ofctl dump-ports br0 2; ovs-ofctl dump-ports br0 3) | STRIP_XIDS], [0],
456 [OFPST_PORT reply: 1 ports
457 port 2: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
458 tx pkts=3, bytes=180, drop=0, errs=0, coll=0
459 OFPST_PORT reply: 1 ports
460 port 3: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
461 tx pkts=17, bytes=1020, drop=0, errs=0, coll=0
464 # Check for the learning entry.
465 ovs-appctl time/warp 1000
467 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0],
468 [[ n_packets=3, n_bytes=180, actions=load:0x3->NXM_NX_REG0[0..15],learn(table=0,hard_timeout=10,priority=65535,NXM_OF_ETH_SRC[],NXM_OF_VLAN_TCI[0..11],output:NXM_NX_REG0[0..15]),output:2
469 n_packets=3, n_bytes=180, hard_timeout=10, priority=65535,vlan_tci=0x0000/0x0fff,dl_src=50:54:00:00:00:06 actions=output:3
475 AT_SETUP([learning action - fin_timeout feature])
476 # This is a totally artificial use of the "learn" action. The only purpose
477 # is to check that specifying fin_idle_timeout or fin_hard_timeout causes
478 # a corresponding fin_timeout action to end up in the learned flows.
480 [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1])
481 AT_CHECK([[ovs-ofctl add-flow br0 'actions=learn(fin_hard_timeout=10, fin_idle_timeout=5, NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], output:NXM_OF_IN_PORT[])']])
482 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=192.168.0.1,tip=192.168.0.2,op=1,sha=50:54:00:00:00:05,tha=00:00:00:00:00:00)' -generate], [0], [ignore])
483 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip], [0],
485 table=1, dl_dst=50:54:00:00:00:05 actions=fin_timeout(idle_timeout=5,hard_timeout=10),output:1
490 AT_SETUP([learning action - delete_learned feature])
493 # Add some initial flows and check that it was successful.
494 AT_DATA([flows.txt], [dnl
495 reg0=0x1 actions=learn(delete_learned,cookie=0x123)
496 reg0=0x2 actions=learn(delete_learned,cookie=0x123)
497 cookie=0x123, table=1, reg0=0x3 actions=drop
498 cookie=0x123, table=1, reg0=0x4 actions=drop
499 cookie=0x123, table=2, reg0=0x5 actions=drop
500 cookie=0x234, table=1, reg0=0x6 actions=drop
502 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
503 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
504 cookie=0x123, table=1, reg0=0x3 actions=drop
505 cookie=0x123, table=1, reg0=0x4 actions=drop
506 cookie=0x123, table=2, reg0=0x5 actions=drop
507 cookie=0x234, table=1, reg0=0x6 actions=drop
508 reg0=0x1 actions=learn(table=1,delete_learned,cookie=0x123)
509 reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x123)
513 # Delete one of the learn actions. The learned flows should stay, since there
514 # is another learn action with the identical target.
515 AT_CHECK([ovs-ofctl del-flows br0 'table=0 reg0=1'])
516 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
517 cookie=0x123, table=1, reg0=0x3 actions=drop
518 cookie=0x123, table=1, reg0=0x4 actions=drop
519 cookie=0x123, table=2, reg0=0x5 actions=drop
520 cookie=0x234, table=1, reg0=0x6 actions=drop
521 reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x123)
525 # Change the flow with the learn action by adding a second action. The learned
526 # flows should stay because the learn action is still there.
527 AT_CHECK([ovs-ofctl mod-flows br0 'table=0 reg0=2 actions=output:1,learn(delete_learned,cookie=0x123)'])
528 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
529 cookie=0x123, table=1, reg0=0x3 actions=drop
530 cookie=0x123, table=1, reg0=0x4 actions=drop
531 cookie=0x123, table=2, reg0=0x5 actions=drop
532 cookie=0x234, table=1, reg0=0x6 actions=drop
533 reg0=0x2 actions=output:1,learn(table=1,delete_learned,cookie=0x123)
537 # Change the flow with the learn action by replacing its learn action by one
538 # with a different target. The (previous) learned flows disappear.
539 AT_CHECK([ovs-ofctl mod-flows br0 'table=0 reg0=2 actions=learn(delete_learned,cookie=0x234)'])
540 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
541 cookie=0x123, table=2, reg0=0x5 actions=drop
542 cookie=0x234, table=1, reg0=0x6 actions=drop
543 reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x234)
547 # Use add-flow to replace the flow with the learn action by one with the
548 # same learn action and an extra action. The (new) learned flow remains.
549 AT_CHECK([ovs-ofctl add-flow br0 'table=0 reg0=2 actions=learn(delete_learned,cookie=0x234),output:2'])
550 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
551 cookie=0x123, table=2, reg0=0x5 actions=drop
552 cookie=0x234, table=1, reg0=0x6 actions=drop
553 reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x234),output:2
557 # Delete the flow with the learn action. The learned flow disappears too.
558 AT_CHECK([ovs-ofctl del-flows br0 table=0])
559 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
560 cookie=0x123, table=2, reg0=0x5 actions=drop
564 # Add a new set of flows to check on a corner case: the learned flows
565 # contain their own learn actions which cascade to further deletions.
566 # This can't happen if the learned flows were actually created by a
567 # learn action, since the learn action has very restricted action
568 # support, but there's no restriction that the deleted flows were
569 # created by a learn action.
570 AT_DATA([flows.txt], [dnl
571 reg0=0x1 actions=learn(table=1,delete_learned,cookie=0x123)
572 reg0=0x2 actions=learn(table=2,delete_learned,cookie=0x234)
573 cookie=0x123, table=1, reg0=0x3 actions=learn(table=3,delete_learned,cookie=0x345)
574 cookie=0x234, table=2, reg0=0x3 actions=learn(table=4,delete_learned,cookie=0x456)
575 cookie=0x345, table=3, reg0=0x4 actions=learn(table=5,delete_learned,cookie=0x567)
576 cookie=0x456, table=4, reg0=0x5 actions=learn(table=5,delete_learned,cookie=0x567)
577 cookie=0x567, table=5, reg0=0x6 actions=drop
578 cookie=0x567, table=5, reg0=0x7 actions=drop
579 cookie=0x567, table=5, reg0=0x8 actions=drop
581 AT_CHECK([ovs-ofctl del-flows br0])
582 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
583 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
584 cookie=0x123, table=1, reg0=0x3 actions=learn(table=3,delete_learned,cookie=0x345)
585 cookie=0x234, table=2, reg0=0x3 actions=learn(table=4,delete_learned,cookie=0x456)
586 cookie=0x345, table=3, reg0=0x4 actions=learn(table=5,delete_learned,cookie=0x567)
587 cookie=0x456, table=4, reg0=0x5 actions=learn(table=5,delete_learned,cookie=0x567)
588 cookie=0x567, table=5, reg0=0x6 actions=drop
589 cookie=0x567, table=5, reg0=0x7 actions=drop
590 cookie=0x567, table=5, reg0=0x8 actions=drop
591 reg0=0x1 actions=learn(table=1,delete_learned,cookie=0x123)
592 reg0=0x2 actions=learn(table=2,delete_learned,cookie=0x234)
596 # Deleting the flow with reg0=1 should cascade to delete a few levels
597 # of learned flows, but the ones with cookie=0x567 stick around
598 # because of the flow with cookie=0x456.
599 AT_CHECK([ovs-ofctl del-flows br0 'table=0 reg0=1'])
600 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
601 cookie=0x234, table=2, reg0=0x3 actions=learn(table=4,delete_learned,cookie=0x456)
602 cookie=0x456, table=4, reg0=0x5 actions=learn(table=5,delete_learned,cookie=0x567)
603 cookie=0x567, table=5, reg0=0x6 actions=drop
604 cookie=0x567, table=5, reg0=0x7 actions=drop
605 cookie=0x567, table=5, reg0=0x8 actions=drop
606 reg0=0x2 actions=learn(table=2,delete_learned,cookie=0x234)
610 # Deleting the flow with reg0=2 should cascade to delete all the rest:
611 AT_CHECK([ovs-ofctl del-flows br0 'table=0 reg0=2'])
612 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl