ofproto: Honour out_port of flow monitors
[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 5000
223 ovs-appctl time/warp 5000
224 ovs-appctl time/warp 5000
225 sleep 1
226 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
227  table=1, priority=0 actions=FLOOD
228 NXST_FLOW reply:
229 ])
230 OVS_VSWITCHD_STOP
231 AT_CLEANUP
232
233 AT_SETUP([learning action - TCPv4 port learning])
234 OVS_VSWITCHD_START(
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']])
240
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: //'`
245
246 expected="1,2,100"
247 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
248 mv stdout expout
249 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
250
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
254 NXST_FLOW reply:
255 ])
256 OVS_VSWITCHD_STOP
257 AT_CLEANUP
258
259 AT_SETUP([learning action - TCPv6 port learning])
260 OVS_VSWITCHD_START(
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
266 # that they work.
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']])
268
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: //'`
273
274 expected="1,2,100"
275 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
276 mv stdout expout
277 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
278
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
283 NXST_FLOW reply:
284 ])
285 OVS_VSWITCHD_STOP
286 AT_CLEANUP
287
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
290 # flow.
291 AT_SETUP([learning action - self-modifying flow])
292 OVS_VSWITCHD_START
293 ADD_OF_PORTS([br0], 1, 2, 3)
294
295 ovs-appctl time/stop
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']])
298
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
304         sleep 1
305     fi
306 done
307
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
313 NXST_FLOW reply:
314 ]])
315
316 # Check that the first packet went out port 2 and the rest out port 3.
317 AT_CHECK(
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
325 ])
326
327 OVS_VSWITCHD_STOP
328 AT_CLEANUP
329
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])
334 OVS_VSWITCHD_START
335 ADD_OF_PORTS([br0], 1, 2, 3)
336
337 ovs-appctl time/stop
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']])
340
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
346         sleep 1
347     fi
348 done
349
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
360     # idle_timeout.
361     if [[ $i -eq 1 -o $((i % 3)) -eq 0 ]]; then
362         sleep 1
363     fi
364 done
365
366 # Check that the first packet of each flow went out port 2 and the rest out
367 # port 3.
368 AT_CHECK(
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
376 ])
377
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
383 NXST_FLOW reply:
384 ]])
385 OVS_VSWITCHD_STOP
386 AT_CLEANUP
387
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])
392 OVS_VSWITCHD_START
393 ADD_OF_PORTS([br0], 1, 2, 3)
394
395 ovs-appctl time/stop
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']])
398
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
403         sleep 1
404     fi
405     ovs-appctl time/warp 10
406 done
407
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.
418     #
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)
424     # receive #3
425     #  (warp, timeout left 4s)
426     # receive #4
427     #  (warp, timeout left 2s)
428     # receive #5
429     #  (warp, timeout left 0s)
430     #  NOTE: OVS does not consider this expired yet.  cf. rule_expire()
431     # receive #6
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)
437     # receive #8
438     #  (warp, timeout left 6s)
439     # receive #9
440     #  (warp, timeout left 4s)
441     # receive #10
442     #  (warp, timeout left 2s)
443     if [[ $i -eq 1 -o $i -eq 7 ]]; then
444         sleep 1
445     fi
446     ovs-appctl time/warp 2000
447     if [[ $i -eq 6 ]]; then
448         sleep 1
449     fi
450 done
451
452 # Check that the first packet of each flow went out port 2 and the rest out
453 # port 3.
454 AT_CHECK(
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
462 ])
463
464 # Check for the learning entry.
465 ovs-appctl time/warp 1000
466 sleep 1
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
470 NXST_FLOW reply:
471 ]])
472 OVS_VSWITCHD_STOP
473 AT_CLEANUP
474
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.
479 OVS_VSWITCHD_START(
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],
484 [NXST_FLOW reply:
485  table=1, dl_dst=50:54:00:00:00:05 actions=fin_timeout(idle_timeout=5,hard_timeout=10),output:1
486 ])
487 OVS_VSWITCHD_STOP
488 AT_CLEANUP
489
490 AT_SETUP([learning action - delete_learned feature])
491 OVS_VSWITCHD_START
492
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
501 ])
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)
510 NXST_FLOW reply:
511 ])
512
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)
522 NXST_FLOW reply:
523 ])
524
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)
534 NXST_FLOW reply:
535 ])
536
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)
544 NXST_FLOW reply:
545 ])
546
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
554 NXST_FLOW reply:
555 ])
556
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
561 NXST_FLOW reply:
562 ])
563
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
580 ])
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)
593 NXST_FLOW reply:
594 ])
595
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)
607 NXST_FLOW reply:
608 ])
609
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
613 NXST_FLOW reply:
614 ])
615 OVS_VSWITCHD_STOP
616 AT_CLEANUP