netdev-dpdk: fix mbuf leaks
[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 - too-long immediate value])
95 dnl 129 bits is too long.
96 AT_CHECK([[ovs-ofctl parse-flow 'actions=learn(load:0x1fedbca9876543210fedbca9876543210->NXM_NX_IPV6_DST[])']],
97   [1], [], [[ovs-ofctl: 0x1fedbca9876543210fedbca9876543210->NXM_NX_IPV6_DST[]: value does not fit into 128 bits
98 ]])
99
100 dnl 128 bits is merely a bad prerequisite.
101 AT_CHECK([[ovs-ofctl parse-flow 'actions=learn(load:0xfedbca9876543210fedbca9876543210->NXM_NX_IPV6_DST[])']], [1], [], [stderr])
102 AT_CHECK([sed -e 's/.*|meta_flow|WARN|//' < stderr], [0],
103   [[destination field ipv6_dst lacks correct prerequisites
104 ovs-ofctl: actions are invalid with specified match (OFPBAC_MATCH_INCONSISTENT)
105 ]], [[]])
106 AT_CLEANUP
107
108 AT_SETUP([learning action - standard VLAN+MAC learning])
109 OVS_VSWITCHD_START(
110   [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 -- \
111    add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2 -- \
112    add-port br0 p3 -- set Interface p3 type=dummy ofport_request=3])
113 # Set up flow table for VLAN+MAC learning.
114 AT_DATA([flows.txt], [[
115 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)
116 table=1 priority=0 actions=flood
117 ]])
118 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
119
120 # Trace an ARP packet arriving on port 3, to create a MAC learning entry.
121 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)"
122 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow" -generate], [0], [stdout])
123 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
124
125 expected="1,2,100"
126 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
127 mv stdout expout
128 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
129
130 # Check for the MAC learning entry.
131 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
132  table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:05 actions=output:3
133  table=1, priority=0 actions=FLOOD
134 NXST_FLOW reply:
135 ])
136
137 # Trace a packet arrival destined for the learned MAC.
138 # (This will also learn a MAC.)
139 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])
140 AT_CHECK([tail -1 stdout], [0], [Datapath actions: 3
141 ])
142
143 # Check for both MAC learning entries.
144 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip |sort], [0], [dnl
145  table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:05 actions=output:3
146  table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:06 actions=output:1
147  table=1, priority=0 actions=FLOOD
148 NXST_FLOW reply:
149 ])
150
151 # Trace a packet arrival that updates the first learned MAC entry.
152 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)"
153 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow" -generate], [0], [stdout])
154 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
155
156 expected="1,3,100"
157 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
158 mv stdout expout
159 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
160
161 # Check that the MAC learning entry was updated.
162 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
163  table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:05 actions=output:2
164  table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:06 actions=output:1
165  table=1, priority=0 actions=FLOOD
166 NXST_FLOW reply:
167 ])
168 OVS_VSWITCHD_STOP
169 AT_CLEANUP
170
171 dnl This test checks that repeated uses of a "learn" action cause the
172 dnl modified time of the learned flow to advance.  Otherwise, the
173 dnl learned flow will expire after its hard timeout even though it's
174 dnl supposed to be refreshed.  (The expiration can be hard to see since
175 dnl it gets re-learned again the next time a packet appears, but
176 dnl sometimes the expiration can cause temporary flooding etc.)
177 AT_SETUP([learning action - learn refreshes hard_age])
178 OVS_VSWITCHD_START(
179   [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 -- \
180    add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2 -- \
181    add-port br0 p3 -- set Interface p3 type=dummy ofport_request=3])
182
183 ovs-appctl time/stop
184
185 # Set up flow table for MAC learning.
186 AT_DATA([flows.txt], [[
187 table=0 actions=learn(table=1, hard_timeout=10, NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], output:NXM_OF_IN_PORT[]), resubmit(,1)
188 table=1 priority=0 actions=flood
189 ]])
190 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
191
192 # Trace an ICMP packet arriving on port 3, to create a MAC learning entry.
193 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)"
194 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow" -generate], [0], [stdout])
195 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
196
197 expected="1,2,100"
198 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
199 mv stdout expout
200 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
201
202 # Check that the MAC learning entry appeared.
203 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | 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 # For 25 seconds, make sure that the MAC learning entry doesn't
210 # disappear as long as we refresh it every second.
211 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
212     ovs-appctl time/warp 1000
213     AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow" -generate], [0], [stdout])
214
215     # Check that the entry is there.
216     AT_CHECK([ovs-ofctl dump-flows br0 table=1], [0], [stdout])
217     AT_CHECK([ofctl_strip < stdout | sort], [0], [dnl
218  table=1, hard_timeout=10, dl_dst=50:54:00:00:00:07 actions=output:3
219  table=1, priority=0 actions=FLOOD
220 NXST_FLOW reply:
221 ])
222
223     if test $i != 1; then
224         # Check that hard_age has appeared.  We need to do this separately
225         # from the above check because ofctl_strip removes it.  dump-flows
226         # only prints hard_age when it is different from the flow's duration
227         # (that is, the number of seconds from the time it was created),
228         # so we only check for it after we've refreshed the flow once.
229         AT_CHECK([grep dl_dst=50:54:00:00:00:07 stdout | grep -c hard_age],
230                  [0], [1
231 ])
232     fi
233 done
234
235 # Make sure that 15 seconds without refreshing makes the flow time out.
236 ovs-appctl time/warp 15000 5000
237 sleep 1
238 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
239  table=1, priority=0 actions=FLOOD
240 NXST_FLOW reply:
241 ])
242 OVS_VSWITCHD_STOP
243 AT_CLEANUP
244
245 AT_SETUP([learning action - TCPv4 port learning])
246 OVS_VSWITCHD_START(
247   [add-port br0 p1 -- set Interface p1 type=dummy -- \
248    add-port br0 p2 -- set Interface p2 type=dummy -- \
249    add-port br0 p3 -- set Interface p3 type=dummy])
250 # Set up flow table for TCPv4 port learning.
251 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']])
252
253 # Trace a TCPv4 packet arriving on port 3.
254 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)"
255 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow" -generate], [0], [stdout])
256 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
257
258 expected="1,2,100"
259 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
260 mv stdout expout
261 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
262
263 # Check for the learning entry.
264 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
265  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
266 NXST_FLOW reply:
267 ])
268 OVS_VSWITCHD_STOP
269 AT_CLEANUP
270
271 AT_SETUP([learning action - TCPv6 port learning])
272 OVS_VSWITCHD_START(
273   [add-port br0 p1 -- set Interface p1 type=dummy -- \
274    add-port br0 p2 -- set Interface p2 type=dummy -- \
275    add-port br0 p3 -- set Interface p3 type=dummy])
276 # Set up flow table for TCPv6 port learning.
277 # Also add a 128-bit-wide "load" action and a 128-bit literal match to check
278 # that they work.
279 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']])
280
281 # Trace a TCPv6 packet arriving on port 3.
282 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)"
283 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow" -generate], [0], [stdout])
284 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
285
286 expected="1,2,100"
287 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
288 mv stdout expout
289 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
290
291 # Check for the learning entry.
292 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
293  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]]
294  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
295 NXST_FLOW reply:
296 ])
297 OVS_VSWITCHD_STOP
298 AT_CLEANUP
299
300 # In this use of a learn action, the first packet in the flow creates
301 # a new flow that changes the behavior of subsequent packets in the
302 # flow.
303 AT_SETUP([learning action - self-modifying flow])
304 OVS_VSWITCHD_START
305 add_of_ports br0 1 2 3
306
307 ovs-appctl time/stop
308 # Set up flow table for TCPv4 port learning.
309 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']])
310
311 # Trace some packets arriving.  The particular packets don't matter.
312 for i in 1 2 3 4 5 6 7 8 9 10; do
313     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)'
314     ovs-appctl time/warp 10
315     if [[ $i -eq 1 ]]; then
316         sleep 1
317     fi
318 done
319
320 # Check for the learning entry.
321 ovs-appctl time/warp 1000
322 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0],
323 [[ 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
324  n_packets=9, n_bytes=540, priority=65535,vlan_tci=0x0000/0x0fff,dl_src=50:54:00:00:00:05 actions=output:3
325 NXST_FLOW reply:
326 ]])
327
328 # Check that the first packet went out port 2 and the rest out port 3.
329 AT_CHECK(
330   [(ovs-ofctl dump-ports br0 2; ovs-ofctl dump-ports br0 3) | strip_xids], [0],
331   [OFPST_PORT reply: 1 ports
332   port  2: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
333            tx pkts=1, bytes=60, drop=0, errs=0, coll=0
334 OFPST_PORT reply: 1 ports
335   port  3: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
336            tx pkts=9, bytes=540, drop=0, errs=0, coll=0
337 ])
338
339 OVS_VSWITCHD_STOP
340 AT_CLEANUP
341
342 # This test is much like the previous, but adds idle timeouts and sends
343 # two different flows to the bridge. This tests that the statistics are
344 # attributed correctly.
345 AT_SETUP([learning action - self-modifying flow with idle_timeout])
346 OVS_VSWITCHD_START
347 add_of_ports br0 1 2 3
348
349 ovs-appctl time/stop
350 # Set up flow table for TCPv4 port learning.
351 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']])
352
353 # Trace some packets arriving.  The particular packets don't matter.
354 for i in `seq 1 10`; do
355     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)'
356     ovs-appctl time/warp 10
357     if [[ $i -eq 1 ]]; then
358         sleep 1
359     fi
360 done
361
362 # Trace some packets arriving.  This is is a different flow from the previous.
363 # Note that we advance time by 1 second between each packet here.
364 for i in `seq 1 10`; do
365     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)'
366     ovs-appctl time/warp 1000
367     # Note: netdev-dummy/receive merely queues the packet.
368     # We need to wait for other thread to process the packet
369     # and update the flow's 'used' for the packet.
370     # (i % 3 == 0) below is somehow arbitrary but chosen to ensure
371     # that we update the flow's 'used' frequently enough to prevent
372     # idle_timeout.
373     if [[ $i -eq 1 -o $((i % 3)) -eq 0 ]]; then
374         sleep 1
375     fi
376 done
377
378 # Check that the first packet of each flow went out port 2 and the rest out
379 # port 3.
380 AT_CHECK(
381   [(ovs-ofctl dump-ports br0 2; ovs-ofctl dump-ports br0 3) | strip_xids], [0],
382   [OFPST_PORT reply: 1 ports
383   port  2: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
384            tx pkts=2, bytes=120, drop=0, errs=0, coll=0
385 OFPST_PORT reply: 1 ports
386   port  3: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
387            tx pkts=18, bytes=1080, drop=0, errs=0, coll=0
388 ])
389
390 # Check for the learning entry.
391 ovs-appctl time/warp 1000
392 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0],
393 [[ 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
394  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
395 NXST_FLOW reply:
396 ]])
397 OVS_VSWITCHD_STOP
398 AT_CLEANUP
399
400 # This test is much like the previous, but adds hard timeouts and sends
401 # two different flows to the bridge. This tests that the statistics are
402 # attributed correctly.
403 AT_SETUP([learning action - self-modifying flow with hard_timeout])
404 OVS_VSWITCHD_START
405 add_of_ports br0 1 2 3
406
407 ovs-appctl time/stop
408 # Set up flow table for TCPv4 port learning.
409 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']])
410
411 # Trace some packets arriving.  The particular packets don't matter.
412 for i in `seq 1 10`; do
413     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)'
414     if [[ $i -eq 1 ]]; then
415         sleep 1
416     fi
417     ovs-appctl time/warp 10
418 done
419
420 # Trace some packets arriving.  This is is a different flow from the previous.
421 # Note that we advance time by 2 second between each packet here.
422 for i in `seq 1 10`; do
423     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)'
424     # Note: hard_timeout should fire immediately after #6 packet.
425     # #7 packet re-install the flow and the following 3 packets
426     # (#8, #9, #10) use the flow.
427     # it's difficult to predict the exact timing of rule expiry
428     # because it's affected by flow dumper thread via udpif_dump_seq.
429     # hard_timeout value for this test was chosen to overcome the uncertainty.
430     #
431     # receive #1  learn, install flow with hard_timeout=10
432     #  sleep to ensure the flow installation
433     #  (warp, timeout left 8s)
434     # receive #2   the learned flow
435     #  (warp, timeout left 6s)
436     # receive #3
437     #  (warp, timeout left 4s)
438     # receive #4
439     #  (warp, timeout left 2s)
440     # receive #5
441     #  (warp, timeout left 0s)
442     #  NOTE: OVS does not consider this expired yet.  cf. rule_expire()
443     # receive #6
444     #  (warp, timeout left -2s)
445     #  sleep to ensure flow expiration
446     # receive #7  learn, install flow with hard_timeout=10
447     #  sleep to ensure the flow installation
448     #  (warp, timeout left 8s)
449     # receive #8
450     #  (warp, timeout left 6s)
451     # receive #9
452     #  (warp, timeout left 4s)
453     # receive #10
454     #  (warp, timeout left 2s)
455     if [[ $i -eq 1 -o $i -eq 7 ]]; then
456         sleep 1
457     fi
458     ovs-appctl time/warp 2000
459     if [[ $i -eq 6 ]]; then
460         sleep 1
461     fi
462 done
463
464 # Check that the first packet of each flow went out port 2 and the rest out
465 # port 3.
466 AT_CHECK(
467   [(ovs-ofctl dump-ports br0 2; ovs-ofctl dump-ports br0 3) | strip_xids], [0],
468   [OFPST_PORT reply: 1 ports
469   port  2: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
470            tx pkts=3, bytes=180, drop=0, errs=0, coll=0
471 OFPST_PORT reply: 1 ports
472   port  3: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
473            tx pkts=17, bytes=1020, drop=0, errs=0, coll=0
474 ])
475
476 # Check for the learning entry.
477 ovs-appctl time/warp 1000
478 sleep 1
479 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0],
480 [[ 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
481  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
482 NXST_FLOW reply:
483 ]])
484 OVS_VSWITCHD_STOP
485 AT_CLEANUP
486
487 AT_SETUP([learning action - fin_timeout feature])
488 # This is a totally artificial use of the "learn" action.  The only purpose
489 # is to check that specifying fin_idle_timeout or fin_hard_timeout causes
490 # a corresponding fin_timeout action to end up in the learned flows.
491 OVS_VSWITCHD_START(
492     [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1])
493 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[])']])
494 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])
495 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip], [0],
496 [NXST_FLOW reply:
497  table=1, dl_dst=50:54:00:00:00:05 actions=fin_timeout(idle_timeout=5,hard_timeout=10),output:1
498 ])
499 OVS_VSWITCHD_STOP
500 AT_CLEANUP
501
502 AT_SETUP([learning action - delete_learned feature])
503 OVS_VSWITCHD_START
504
505 # Add some initial flows and check that it was successful.
506 AT_DATA([flows.txt], [dnl
507                        reg0=0x1 actions=learn(delete_learned,cookie=0x123)
508                        reg0=0x2 actions=learn(delete_learned,cookie=0x123)
509 cookie=0x123, table=1, reg0=0x3 actions=drop
510 cookie=0x123, table=1, reg0=0x4 actions=drop
511 cookie=0x123, table=2, reg0=0x5 actions=drop
512 cookie=0x234, table=1, reg0=0x6 actions=drop
513 ])
514 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
515 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
516  cookie=0x123, table=1, reg0=0x3 actions=drop
517  cookie=0x123, table=1, reg0=0x4 actions=drop
518  cookie=0x123, table=2, reg0=0x5 actions=drop
519  cookie=0x234, table=1, reg0=0x6 actions=drop
520  reg0=0x1 actions=learn(table=1,delete_learned,cookie=0x123)
521  reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x123)
522 NXST_FLOW reply:
523 ])
524
525 # Delete one of the learn actions.  The learned flows should stay, since there
526 # is another learn action with the identical target.
527 AT_CHECK([ovs-ofctl del-flows br0 'table=0 reg0=1'])
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=learn(table=1,delete_learned,cookie=0x123)
534 NXST_FLOW reply:
535 ])
536
537 # Change the flow with the learn action by adding a second action.  The learned
538 # flows should stay because the learn action is still there.
539 AT_CHECK([ovs-ofctl mod-flows br0 'table=0 reg0=2 actions=output:1,learn(delete_learned,cookie=0x123)'])
540 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
541  cookie=0x123, table=1, reg0=0x3 actions=drop
542  cookie=0x123, table=1, reg0=0x4 actions=drop
543  cookie=0x123, table=2, reg0=0x5 actions=drop
544  cookie=0x234, table=1, reg0=0x6 actions=drop
545  reg0=0x2 actions=output:1,learn(table=1,delete_learned,cookie=0x123)
546 NXST_FLOW reply:
547 ])
548
549 # Change the flow with the learn action by replacing its learn action by one
550 # with a different target.  The (previous) learned flows disappear.
551 AT_CHECK([ovs-ofctl mod-flows br0 'table=0 reg0=2 actions=learn(delete_learned,cookie=0x234)'])
552 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
553  cookie=0x123, table=2, reg0=0x5 actions=drop
554  cookie=0x234, table=1, reg0=0x6 actions=drop
555  reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x234)
556 NXST_FLOW reply:
557 ])
558
559 # Use add-flow to replace the flow with the learn action by one with the
560 # same learn action and an extra action.  The (new) learned flow remains.
561 AT_CHECK([ovs-ofctl add-flow br0 'table=0 reg0=2 actions=learn(delete_learned,cookie=0x234),output:2'])
562 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
563  cookie=0x123, table=2, reg0=0x5 actions=drop
564  cookie=0x234, table=1, reg0=0x6 actions=drop
565  reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x234),output:2
566 NXST_FLOW reply:
567 ])
568
569 # Delete the flow with the learn action.  The learned flow disappears too.
570 AT_CHECK([ovs-ofctl del-flows br0 table=0])
571 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
572  cookie=0x123, table=2, reg0=0x5 actions=drop
573 NXST_FLOW reply:
574 ])
575
576 # Add a new set of flows to check on a corner case: the learned flows
577 # contain their own learn actions which cascade to further deletions.
578 # This can't happen if the learned flows were actually created by a
579 # learn action, since the learn action has very restricted action
580 # support, but there's no restriction that the deleted flows were
581 # created by a learn action.
582 AT_DATA([flows.txt], [dnl
583                        reg0=0x1 actions=learn(table=1,delete_learned,cookie=0x123)
584                        reg0=0x2 actions=learn(table=2,delete_learned,cookie=0x234)
585 cookie=0x123, table=1, reg0=0x3 actions=learn(table=3,delete_learned,cookie=0x345)
586 cookie=0x234, table=2, reg0=0x3 actions=learn(table=4,delete_learned,cookie=0x456)
587 cookie=0x345, table=3, reg0=0x4 actions=learn(table=5,delete_learned,cookie=0x567)
588 cookie=0x456, table=4, reg0=0x5 actions=learn(table=5,delete_learned,cookie=0x567)
589 cookie=0x567, table=5, reg0=0x6 actions=drop
590 cookie=0x567, table=5, reg0=0x7 actions=drop
591 cookie=0x567, table=5, reg0=0x8 actions=drop
592 ])
593 AT_CHECK([ovs-ofctl del-flows br0])
594 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
595 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
596  cookie=0x123, table=1, reg0=0x3 actions=learn(table=3,delete_learned,cookie=0x345)
597  cookie=0x234, table=2, reg0=0x3 actions=learn(table=4,delete_learned,cookie=0x456)
598  cookie=0x345, table=3, reg0=0x4 actions=learn(table=5,delete_learned,cookie=0x567)
599  cookie=0x456, table=4, reg0=0x5 actions=learn(table=5,delete_learned,cookie=0x567)
600  cookie=0x567, table=5, reg0=0x6 actions=drop
601  cookie=0x567, table=5, reg0=0x7 actions=drop
602  cookie=0x567, table=5, reg0=0x8 actions=drop
603  reg0=0x1 actions=learn(table=1,delete_learned,cookie=0x123)
604  reg0=0x2 actions=learn(table=2,delete_learned,cookie=0x234)
605 NXST_FLOW reply:
606 ])
607
608 # Deleting the flow with reg0=1 should cascade to delete a few levels
609 # of learned flows, but the ones with cookie=0x567 stick around
610 # because of the flow with cookie=0x456.
611 AT_CHECK([ovs-ofctl del-flows br0 'table=0 reg0=1'])
612 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
613  cookie=0x234, table=2, reg0=0x3 actions=learn(table=4,delete_learned,cookie=0x456)
614  cookie=0x456, table=4, reg0=0x5 actions=learn(table=5,delete_learned,cookie=0x567)
615  cookie=0x567, table=5, reg0=0x6 actions=drop
616  cookie=0x567, table=5, reg0=0x7 actions=drop
617  cookie=0x567, table=5, reg0=0x8 actions=drop
618  reg0=0x2 actions=learn(table=2,delete_learned,cookie=0x234)
619 NXST_FLOW reply:
620 ])
621
622 # Deleting the flow with reg0=2 should cascade to delete all the rest:
623 AT_CHECK([ovs-ofctl del-flows br0 'table=0 reg0=2'])
624 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
625 NXST_FLOW reply:
626 ])
627 OVS_VSWITCHD_STOP
628 AT_CLEANUP