tests: Use the 'LARGE_MSECS' variation of time/warp at more places.
[cascardo/ovs.git] / tests / learn.at
1 AT_BANNER([learning action])
2
3 AT_SETUP([learning action - parsing and formatting])
4 AT_DATA([flows.txt], [[
5 actions=learn()
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])
11 ]])
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])
21 ]])
22 AT_CLEANUP
23
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)']],
26   [1], [], [stderr])
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
30 ]], [[]])
31 AT_CLEANUP
32
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[])
37 ]])
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[])
43 ]])
44 AT_CLEANUP
45
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
53 ]])
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
61 ]])
62 AT_CLEANUP
63
64 AT_SETUP([learning action - satisfied prerequisites])
65 AT_DATA([flows.txt],
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[])
69 ]])
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[])
76 ]])
77 AT_CLEANUP
78
79 AT_SETUP([learning action - invalid prerequisites])
80 AT_CHECK([[ovs-ofctl parse-flow 'actions=learn(load:5->NXM_OF_IP_DST[])']],
81   [1], [], [stderr])
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)
85 ]], [[]])
86 AT_CHECK([[ovs-ofctl parse-flow 'actions=learn(load:NXM_OF_IP_DST[]->NXM_NX_REG1[])']],
87   [1], [], [stderr])
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)
91 ]])
92 AT_CLEANUP
93
94 AT_SETUP([learning action - standard VLAN+MAC learning])
95 OVS_VSWITCHD_START(
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
103 ]])
104 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
105
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: //'`
110
111 expected="1,2,100"
112 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
113 mv stdout expout
114 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
115
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
120 NXST_FLOW reply:
121 ])
122
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
127 ])
128
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
134 NXST_FLOW reply:
135 ])
136
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: //'`
141
142 expected="1,3,100"
143 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
144 mv stdout expout
145 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
146
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
152 NXST_FLOW reply:
153 ])
154 OVS_VSWITCHD_STOP
155 AT_CLEANUP
156
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])
164 OVS_VSWITCHD_START(
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])
168
169 ovs-appctl time/stop
170
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
175 ]])
176 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
177
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: //'`
182
183 expected="1,2,100"
184 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
185 mv stdout expout
186 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
187
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
192 NXST_FLOW reply:
193 ])
194
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])
200
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
206 NXST_FLOW reply:
207 ])
208
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],
216                  [0], [1
217 ])
218     fi
219 done
220
221 # Make sure that 15 seconds without refreshing makes the flow time out.
222 ovs-appctl time/warp 15000 5000
223 sleep 1
224 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
225  table=1, priority=0 actions=FLOOD
226 NXST_FLOW reply:
227 ])
228 OVS_VSWITCHD_STOP
229 AT_CLEANUP
230
231 AT_SETUP([learning action - TCPv4 port learning])
232 OVS_VSWITCHD_START(
233   [add-port br0 p1 -- set Interface p1 type=dummy -- \
234    add-port br0 p2 -- set Interface p2 type=dummy -- \
235    add-port br0 p3 -- set Interface p3 type=dummy])
236 # Set up flow table for TCPv4 port learning.
237 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']])
238
239 # Trace a TCPv4 packet arriving on port 3.
240 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)"
241 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow" -generate], [0], [stdout])
242 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
243
244 expected="1,2,100"
245 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
246 mv stdout expout
247 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
248
249 # Check for the learning entry.
250 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
251  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
252 NXST_FLOW reply:
253 ])
254 OVS_VSWITCHD_STOP
255 AT_CLEANUP
256
257 AT_SETUP([learning action - TCPv6 port learning])
258 OVS_VSWITCHD_START(
259   [add-port br0 p1 -- set Interface p1 type=dummy -- \
260    add-port br0 p2 -- set Interface p2 type=dummy -- \
261    add-port br0 p3 -- set Interface p3 type=dummy])
262 # Set up flow table for TCPv6 port learning.
263 # Also add a 128-bit-wide "load" action and a 128-bit literal match to check
264 # that they work.
265 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']])
266
267 # Trace a TCPv6 packet arriving on port 3.
268 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)"
269 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow" -generate], [0], [stdout])
270 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
271
272 expected="1,2,100"
273 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
274 mv stdout expout
275 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
276
277 # Check for the learning entry.
278 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
279  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]]
280  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
281 NXST_FLOW reply:
282 ])
283 OVS_VSWITCHD_STOP
284 AT_CLEANUP
285
286 # In this use of a learn action, the first packet in the flow creates
287 # a new flow that changes the behavior of subsequent packets in the
288 # flow.
289 AT_SETUP([learning action - self-modifying flow])
290 OVS_VSWITCHD_START
291 ADD_OF_PORTS([br0], 1, 2, 3)
292
293 ovs-appctl time/stop
294 # Set up flow table for TCPv4 port learning.
295 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']])
296
297 # Trace some packets arriving.  The particular packets don't matter.
298 for i in 1 2 3 4 5 6 7 8 9 10; do
299     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)'
300     ovs-appctl time/warp 10
301     if [[ $i -eq 1 ]]; then
302         sleep 1
303     fi
304 done
305
306 # Check for the learning entry.
307 ovs-appctl time/warp 1000
308 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0],
309 [[ 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
310  n_packets=9, n_bytes=540, priority=65535,vlan_tci=0x0000/0x0fff,dl_src=50:54:00:00:00:05 actions=output:3
311 NXST_FLOW reply:
312 ]])
313
314 # Check that the first packet went out port 2 and the rest out port 3.
315 AT_CHECK(
316   [(ovs-ofctl dump-ports br0 2; ovs-ofctl dump-ports br0 3) | STRIP_XIDS], [0],
317   [OFPST_PORT reply: 1 ports
318   port  2: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
319            tx pkts=1, bytes=60, drop=0, errs=0, coll=0
320 OFPST_PORT reply: 1 ports
321   port  3: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
322            tx pkts=9, bytes=540, drop=0, errs=0, coll=0
323 ])
324
325 OVS_VSWITCHD_STOP
326 AT_CLEANUP
327
328 # This test is much like the previous, but adds idle timeouts and sends
329 # two different flows to the bridge. This tests that the statistics are
330 # attributed correctly.
331 AT_SETUP([learning action - self-modifying flow with idle_timeout])
332 OVS_VSWITCHD_START
333 ADD_OF_PORTS([br0], 1, 2, 3)
334
335 ovs-appctl time/stop
336 # Set up flow table for TCPv4 port learning.
337 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']])
338
339 # Trace some packets arriving.  The particular packets don't matter.
340 for i in `seq 1 10`; do
341     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)'
342     ovs-appctl time/warp 10
343     if [[ $i -eq 1 ]]; then
344         sleep 1
345     fi
346 done
347
348 # Trace some packets arriving.  This is is a different flow from the previous.
349 # Note that we advance time by 1 second between each packet here.
350 for i in `seq 1 10`; do
351     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)'
352     ovs-appctl time/warp 1000
353     # Note: netdev-dummy/receive merely queues the packet.
354     # We need to wait for other thread to process the packet
355     # and update the flow's 'used' for the packet.
356     # (i % 3 == 0) below is somehow arbitrary but chosen to ensure
357     # that we update the flow's 'used' frequently enough to prevent
358     # idle_timeout.
359     if [[ $i -eq 1 -o $((i % 3)) -eq 0 ]]; then
360         sleep 1
361     fi
362 done
363
364 # Check that the first packet of each flow went out port 2 and the rest out
365 # port 3.
366 AT_CHECK(
367   [(ovs-ofctl dump-ports br0 2; ovs-ofctl dump-ports br0 3) | STRIP_XIDS], [0],
368   [OFPST_PORT reply: 1 ports
369   port  2: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
370            tx pkts=2, bytes=120, drop=0, errs=0, coll=0
371 OFPST_PORT reply: 1 ports
372   port  3: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
373            tx pkts=18, bytes=1080, drop=0, errs=0, coll=0
374 ])
375
376 # Check for the learning entry.
377 ovs-appctl time/warp 1000
378 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0],
379 [[ 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
380  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
381 NXST_FLOW reply:
382 ]])
383 OVS_VSWITCHD_STOP
384 AT_CLEANUP
385
386 # This test is much like the previous, but adds hard timeouts and sends
387 # two different flows to the bridge. This tests that the statistics are
388 # attributed correctly.
389 AT_SETUP([learning action - self-modifying flow with hard_timeout])
390 OVS_VSWITCHD_START
391 ADD_OF_PORTS([br0], 1, 2, 3)
392
393 ovs-appctl time/stop
394 # Set up flow table for TCPv4 port learning.
395 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']])
396
397 # Trace some packets arriving.  The particular packets don't matter.
398 for i in `seq 1 10`; do
399     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)'
400     if [[ $i -eq 1 ]]; then
401         sleep 1
402     fi
403     ovs-appctl time/warp 10
404 done
405
406 # Trace some packets arriving.  This is is a different flow from the previous.
407 # Note that we advance time by 2 second between each packet here.
408 for i in `seq 1 10`; do
409     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)'
410     # Note: hard_timeout should fire immediately after #6 packet.
411     # #7 packet re-install the flow and the following 3 packets
412     # (#8, #9, #10) use the flow.
413     # it's difficult to predict the exact timing of rule expiry
414     # because it's affected by flow dumper thread via udpif_dump_seq.
415     # hard_timeout value for this test was chosen to overcome the uncertainty.
416     #
417     # receive #1  learn, install flow with hard_timeout=10
418     #  sleep to ensure the flow installation
419     #  (warp, timeout left 8s)
420     # receive #2   the learned flow
421     #  (warp, timeout left 6s)
422     # receive #3
423     #  (warp, timeout left 4s)
424     # receive #4
425     #  (warp, timeout left 2s)
426     # receive #5
427     #  (warp, timeout left 0s)
428     #  NOTE: OVS does not consider this expired yet.  cf. rule_expire()
429     # receive #6
430     #  (warp, timeout left -2s)
431     #  sleep to ensure flow expiration
432     # receive #7  learn, install flow with hard_timeout=10
433     #  sleep to ensure the flow installation
434     #  (warp, timeout left 8s)
435     # receive #8
436     #  (warp, timeout left 6s)
437     # receive #9
438     #  (warp, timeout left 4s)
439     # receive #10
440     #  (warp, timeout left 2s)
441     if [[ $i -eq 1 -o $i -eq 7 ]]; then
442         sleep 1
443     fi
444     ovs-appctl time/warp 2000
445     if [[ $i -eq 6 ]]; then
446         sleep 1
447     fi
448 done
449
450 # Check that the first packet of each flow went out port 2 and the rest out
451 # port 3.
452 AT_CHECK(
453   [(ovs-ofctl dump-ports br0 2; ovs-ofctl dump-ports br0 3) | STRIP_XIDS], [0],
454   [OFPST_PORT reply: 1 ports
455   port  2: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
456            tx pkts=3, bytes=180, drop=0, errs=0, coll=0
457 OFPST_PORT reply: 1 ports
458   port  3: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
459            tx pkts=17, bytes=1020, drop=0, errs=0, coll=0
460 ])
461
462 # Check for the learning entry.
463 ovs-appctl time/warp 1000
464 sleep 1
465 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0],
466 [[ 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
467  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
468 NXST_FLOW reply:
469 ]])
470 OVS_VSWITCHD_STOP
471 AT_CLEANUP
472
473 AT_SETUP([learning action - fin_timeout feature])
474 # This is a totally artificial use of the "learn" action.  The only purpose
475 # is to check that specifying fin_idle_timeout or fin_hard_timeout causes
476 # a corresponding fin_timeout action to end up in the learned flows.
477 OVS_VSWITCHD_START(
478     [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1])
479 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[])']])
480 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])
481 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip], [0],
482 [NXST_FLOW reply:
483  table=1, dl_dst=50:54:00:00:00:05 actions=fin_timeout(idle_timeout=5,hard_timeout=10),output:1
484 ])
485 OVS_VSWITCHD_STOP
486 AT_CLEANUP
487
488 AT_SETUP([learning action - delete_learned feature])
489 OVS_VSWITCHD_START
490
491 # Add some initial flows and check that it was successful.
492 AT_DATA([flows.txt], [dnl
493                        reg0=0x1 actions=learn(delete_learned,cookie=0x123)
494                        reg0=0x2 actions=learn(delete_learned,cookie=0x123)
495 cookie=0x123, table=1, reg0=0x3 actions=drop
496 cookie=0x123, table=1, reg0=0x4 actions=drop
497 cookie=0x123, table=2, reg0=0x5 actions=drop
498 cookie=0x234, table=1, reg0=0x6 actions=drop
499 ])
500 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
501 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
502  cookie=0x123, table=1, reg0=0x3 actions=drop
503  cookie=0x123, table=1, reg0=0x4 actions=drop
504  cookie=0x123, table=2, reg0=0x5 actions=drop
505  cookie=0x234, table=1, reg0=0x6 actions=drop
506  reg0=0x1 actions=learn(table=1,delete_learned,cookie=0x123)
507  reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x123)
508 NXST_FLOW reply:
509 ])
510
511 # Delete one of the learn actions.  The learned flows should stay, since there
512 # is another learn action with the identical target.
513 AT_CHECK([ovs-ofctl del-flows br0 'table=0 reg0=1'])
514 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
515  cookie=0x123, table=1, reg0=0x3 actions=drop
516  cookie=0x123, table=1, reg0=0x4 actions=drop
517  cookie=0x123, table=2, reg0=0x5 actions=drop
518  cookie=0x234, table=1, reg0=0x6 actions=drop
519  reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x123)
520 NXST_FLOW reply:
521 ])
522
523 # Change the flow with the learn action by adding a second action.  The learned
524 # flows should stay because the learn action is still there.
525 AT_CHECK([ovs-ofctl mod-flows br0 'table=0 reg0=2 actions=output:1,learn(delete_learned,cookie=0x123)'])
526 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
527  cookie=0x123, table=1, reg0=0x3 actions=drop
528  cookie=0x123, table=1, reg0=0x4 actions=drop
529  cookie=0x123, table=2, reg0=0x5 actions=drop
530  cookie=0x234, table=1, reg0=0x6 actions=drop
531  reg0=0x2 actions=output:1,learn(table=1,delete_learned,cookie=0x123)
532 NXST_FLOW reply:
533 ])
534
535 # Change the flow with the learn action by replacing its learn action by one
536 # with a different target.  The (previous) learned flows disappear.
537 AT_CHECK([ovs-ofctl mod-flows br0 'table=0 reg0=2 actions=learn(delete_learned,cookie=0x234)'])
538 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
539  cookie=0x123, table=2, reg0=0x5 actions=drop
540  cookie=0x234, table=1, reg0=0x6 actions=drop
541  reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x234)
542 NXST_FLOW reply:
543 ])
544
545 # Use add-flow to replace the flow with the learn action by one with the
546 # same learn action and an extra action.  The (new) learned flow remains.
547 AT_CHECK([ovs-ofctl add-flow br0 'table=0 reg0=2 actions=learn(delete_learned,cookie=0x234),output:2'])
548 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
549  cookie=0x123, table=2, reg0=0x5 actions=drop
550  cookie=0x234, table=1, reg0=0x6 actions=drop
551  reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x234),output:2
552 NXST_FLOW reply:
553 ])
554
555 # Delete the flow with the learn action.  The learned flow disappears too.
556 AT_CHECK([ovs-ofctl del-flows br0 table=0])
557 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
558  cookie=0x123, table=2, reg0=0x5 actions=drop
559 NXST_FLOW reply:
560 ])
561
562 # Add a new set of flows to check on a corner case: the learned flows
563 # contain their own learn actions which cascade to further deletions.
564 # This can't happen if the learned flows were actually created by a
565 # learn action, since the learn action has very restricted action
566 # support, but there's no restriction that the deleted flows were
567 # created by a learn action.
568 AT_DATA([flows.txt], [dnl
569                        reg0=0x1 actions=learn(table=1,delete_learned,cookie=0x123)
570                        reg0=0x2 actions=learn(table=2,delete_learned,cookie=0x234)
571 cookie=0x123, table=1, reg0=0x3 actions=learn(table=3,delete_learned,cookie=0x345)
572 cookie=0x234, table=2, reg0=0x3 actions=learn(table=4,delete_learned,cookie=0x456)
573 cookie=0x345, table=3, reg0=0x4 actions=learn(table=5,delete_learned,cookie=0x567)
574 cookie=0x456, table=4, reg0=0x5 actions=learn(table=5,delete_learned,cookie=0x567)
575 cookie=0x567, table=5, reg0=0x6 actions=drop
576 cookie=0x567, table=5, reg0=0x7 actions=drop
577 cookie=0x567, table=5, reg0=0x8 actions=drop
578 ])
579 AT_CHECK([ovs-ofctl del-flows br0])
580 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
581 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
582  cookie=0x123, table=1, reg0=0x3 actions=learn(table=3,delete_learned,cookie=0x345)
583  cookie=0x234, table=2, reg0=0x3 actions=learn(table=4,delete_learned,cookie=0x456)
584  cookie=0x345, table=3, reg0=0x4 actions=learn(table=5,delete_learned,cookie=0x567)
585  cookie=0x456, table=4, reg0=0x5 actions=learn(table=5,delete_learned,cookie=0x567)
586  cookie=0x567, table=5, reg0=0x6 actions=drop
587  cookie=0x567, table=5, reg0=0x7 actions=drop
588  cookie=0x567, table=5, reg0=0x8 actions=drop
589  reg0=0x1 actions=learn(table=1,delete_learned,cookie=0x123)
590  reg0=0x2 actions=learn(table=2,delete_learned,cookie=0x234)
591 NXST_FLOW reply:
592 ])
593
594 # Deleting the flow with reg0=1 should cascade to delete a few levels
595 # of learned flows, but the ones with cookie=0x567 stick around
596 # because of the flow with cookie=0x456.
597 AT_CHECK([ovs-ofctl del-flows br0 'table=0 reg0=1'])
598 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
599  cookie=0x234, table=2, reg0=0x3 actions=learn(table=4,delete_learned,cookie=0x456)
600  cookie=0x456, table=4, reg0=0x5 actions=learn(table=5,delete_learned,cookie=0x567)
601  cookie=0x567, table=5, reg0=0x6 actions=drop
602  cookie=0x567, table=5, reg0=0x7 actions=drop
603  cookie=0x567, table=5, reg0=0x8 actions=drop
604  reg0=0x2 actions=learn(table=2,delete_learned,cookie=0x234)
605 NXST_FLOW reply:
606 ])
607
608 # Deleting the flow with reg0=2 should cascade to delete all the rest:
609 AT_CHECK([ovs-ofctl del-flows br0 'table=0 reg0=2'])
610 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
611 NXST_FLOW reply:
612 ])
613 OVS_VSWITCHD_STOP
614 AT_CLEANUP