1 AT_BANNER([learning action])
3 AT_SETUP([learning action - parsing and formatting])
4 AT_DATA([flows.txt], [[
6 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])
7 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])
9 AT_CHECK([ovs-ofctl parse-flows flows.txt], [0],
10 [[usable protocols: any
11 chosen protocol: OpenFlow10-table_id
12 OFPT_FLOW_MOD (xid=0x1): ADD actions=learn(table=1)
13 OFPT_FLOW_MOD (xid=0x2): 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])
14 OFPT_FLOW_MOD (xid=0x3): 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])
18 AT_SETUP([learning action - examples])
19 AT_DATA([flows.txt], [[
20 # These are the examples from nicira-ext.h.
21 actions=learn(in_port=99,NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], load:NXM_OF_IN_PORT[]->NXM_NX_REG1[16..31])
22 actions=learn(NXM_OF_VLAN_TCI[0..11], NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],output:NXM_OF_IN_PORT[])
23 table=0 actions=learn(table=1,hard_timeout=10, NXM_OF_VLAN_TCI[0..11],output:NXM_OF_IN_PORT[]), resubmit(,1)
24 table=1 priority=0 actions=flood
26 AT_CHECK([ovs-ofctl parse-flows flows.txt], [0],
27 [[usable protocols: OXM,OpenFlow10+table_id,NXM+table_id
28 chosen protocol: OpenFlow10+table_id
29 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])
30 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[])
31 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)
32 OFPT_FLOW_MOD (xid=0x4): ADD table:1 priority=0 actions=FLOOD
36 AT_SETUP([learning action - satisfied prerequisites])
38 [[actions=learn(eth_type=0x800,load:5->NXM_OF_IP_DST[])
39 ip,actions=learn(load:NXM_OF_IP_DST[]->NXM_NX_REG1[])
40 ip,actions=learn(eth_type=0x800,OXM_OF_IPV4_DST[])
42 AT_CHECK([ovs-ofctl parse-flows flows.txt], [0],
43 [[usable protocols: any
44 chosen protocol: OpenFlow10-table_id
45 OFPT_FLOW_MOD (xid=0x1): ADD actions=learn(table=1,eth_type=0x800,load:0x5->NXM_OF_IP_DST[])
46 OFPT_FLOW_MOD (xid=0x2): ADD ip actions=learn(table=1,load:NXM_OF_IP_DST[]->NXM_NX_REG1[])
47 OFPT_FLOW_MOD (xid=0x3): ADD ip actions=learn(table=1,eth_type=0x800,NXM_OF_IP_DST[])
51 AT_SETUP([learning action - invalid prerequisites])
52 AT_CHECK([[ovs-ofctl parse-flow 'actions=learn(load:5->NXM_OF_IP_DST[])']],
54 AT_CHECK([sed -e 's/.*|meta_flow|WARN|//' < stderr], [0],
55 [[destination field ip_dst lacks correct prerequisites
57 AT_CHECK([[ovs-ofctl parse-flow 'actions=learn(load:NXM_OF_IP_DST[]->NXM_NX_REG1[])']],
59 AT_CHECK([sed -e 's/.*|meta_flow|WARN|//' < stderr], [0],
60 [[source field ip_dst lacks correct prerequisites
64 AT_SETUP([learning action - standard VLAN+MAC learning])
66 [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 -- \
67 add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2 -- \
68 add-port br0 p3 -- set Interface p3 type=dummy ofport_request=3])
69 # Set up flow table for VLAN+MAC learning.
70 AT_DATA([flows.txt], [[
71 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)
72 table=1 priority=0 actions=flood
74 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
76 # Trace an ARP packet arriving on port 3, to create a MAC learning entry.
77 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)"
78 AT_CHECK([ovs-appctl ofproto/trace br0 "$flow" -generate], [0], [stdout])
79 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
82 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
84 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
86 # Check for the MAC learning entry.
87 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
88 table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:05 actions=output:3
89 table=1, priority=0 actions=FLOOD
93 # Trace a packet arrival destined for the learned MAC.
94 # (This will also learn a MAC.)
95 AT_CHECK([ovs-appctl ofproto/trace br0 '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])
96 AT_CHECK([tail -1 stdout], [0], [Datapath actions: 3
99 # Check for both MAC learning entries.
100 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip |sort], [0], [dnl
101 table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:05 actions=output:3
102 table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:06 actions=output:1
103 table=1, priority=0 actions=FLOOD
107 # Trace a packet arrival that updates the first learned MAC entry.
108 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)"
109 AT_CHECK([ovs-appctl ofproto/trace br0 "$flow" -generate], [0], [stdout])
110 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
113 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
115 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
117 # Check that the MAC learning entry was updated.
118 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
119 table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:05 actions=output:2
120 table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:06 actions=output:1
121 table=1, priority=0 actions=FLOOD
127 dnl This test checks that repeated uses of a "learn" action cause the
128 dnl modified time of the learned flow to advance. Otherwise, the
129 dnl learned flow will expire after its hard timeout even though it's
130 dnl supposed to be refreshed. (The expiration can be hard to see since
131 dnl it gets re-learned again the next time a packet appears, but
132 dnl sometimes the expiration can cause temporary flooding etc.)
133 AT_SETUP([learning action - learn refreshes hard_age])
135 [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 -- \
136 add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2 -- \
137 add-port br0 p3 -- set Interface p3 type=dummy ofport_request=3])
141 # Set up flow table for MAC learning.
142 AT_DATA([flows.txt], [[
143 table=0 actions=learn(table=1, hard_timeout=10, NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], output:NXM_OF_IN_PORT[]), resubmit(,1)
144 table=1 priority=0 actions=flood
146 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
148 # Trace an ICMP packet arriving on port 3, to create a MAC learning entry.
149 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)"
150 AT_CHECK([ovs-appctl ofproto/trace br0 "$flow" -generate], [0], [stdout])
151 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
154 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
156 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
158 # Check that the MAC learning entry appeared.
159 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
160 table=1, hard_timeout=10, dl_dst=50:54:00:00:00:07 actions=output:3
161 table=1, priority=0 actions=FLOOD
165 # For 25 seconds, make sure that the MAC learning entry doesn't
166 # disappear as long as we refresh it every second.
167 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
168 ovs-appctl time/warp 1000
169 AT_CHECK([ovs-appctl ofproto/trace br0 "$flow" -generate], [0], [stdout])
171 # Check that the entry is there.
172 AT_CHECK([ovs-ofctl dump-flows br0 table=1], [0], [stdout])
173 AT_CHECK([ofctl_strip < stdout | sort], [0], [dnl
174 table=1, hard_timeout=10, dl_dst=50:54:00:00:00:07 actions=output:3
175 table=1, priority=0 actions=FLOOD
179 if test $i != 1; then
180 # Check that hard_age has appeared. We need to do this separately
181 # from the above check because ofctl_strip removes it. dump-flows
182 # only prints hard_age when it is different from the flow's duration
183 # (that is, the number of seconds from the time it was created),
184 # so we only check for it after we've refreshed the flow once.
185 AT_CHECK([grep dl_dst=50:54:00:00:00:07 stdout | grep -c hard_age],
191 # Make sure that 15 seconds without refreshing makes the flow time out.
192 ovs-appctl time/warp 5000
193 ovs-appctl time/warp 5000
194 ovs-appctl time/warp 5000
195 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
196 table=1, priority=0 actions=FLOOD
202 AT_SETUP([learning action - TCPv4 port learning])
204 [add-port br0 p1 -- set Interface p1 type=dummy -- \
205 add-port br0 p2 -- set Interface p2 type=dummy -- \
206 add-port br0 p3 -- set Interface p3 type=dummy])
207 # Set up flow table for TCPv4 port learning.
208 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']])
210 # Trace a TCPv4 packet arriving on port 3.
211 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)"
212 AT_CHECK([ovs-appctl ofproto/trace br0 "$flow" -generate], [0], [stdout])
213 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
216 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
218 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
220 # Check for the learning entry.
221 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
222 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
228 AT_SETUP([learning action - TCPv6 port learning])
230 [add-port br0 p1 -- set Interface p1 type=dummy -- \
231 add-port br0 p2 -- set Interface p2 type=dummy -- \
232 add-port br0 p3 -- set Interface p3 type=dummy])
233 # Set up flow table for TCPv6 port learning.
234 # Also add a 128-bit-wide "load" action and a 128-bit literal match to check
236 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']])
238 # Trace a TCPv6 packet arriving on port 3.
239 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)"
240 AT_CHECK([ovs-appctl ofproto/trace br0 "$flow" -generate], [0], [stdout])
241 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
244 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
246 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
248 # Check for the learning entry.
249 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
250 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]]
251 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
257 # In this use of a learn action, the first packet in the flow creates
258 # a new flow that changes the behavior of subsequent packets in the
260 AT_SETUP([learning action - self-modifying flow])
262 ADD_OF_PORTS([br0], 1, 2, 3)
264 # Set up flow table for TCPv4 port learning.
265 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']])
267 # Trace some packets arriving. The particular packets don't matter.
268 for i in 1 2 3 4 5 6 7 8 9 10; do
269 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)'
272 # Check for the learning entry.
273 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0],
274 [[ 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
275 priority=65535,vlan_tci=0x0000/0x0fff,dl_src=50:54:00:00:00:05 actions=output:3
279 # Check that the first packet went out port 2 and the rest out port 3.
281 [(ovs-ofctl dump-ports br0 2; ovs-ofctl dump-ports br0 3) | STRIP_XIDS], [0],
282 [OFPST_PORT reply: 1 ports
283 port 2: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
284 tx pkts=1, bytes=60, drop=0, errs=0, coll=0
285 OFPST_PORT reply: 1 ports
286 port 3: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
287 tx pkts=9, bytes=540, drop=0, errs=0, coll=0
292 AT_SETUP([learning action - fin_timeout feature])
293 # This is a totally artificial use of the "learn" action. The only purpose
294 # is to check that specifying fin_idle_timeout or fin_hard_timeout causes
295 # a corresponding fin_timeout action to end up in the learned flows.
297 [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1])
298 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[])']])
299 AT_CHECK([ovs-appctl ofproto/trace br0 '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])
300 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip], [0],
302 table=1, dl_dst=50:54:00:00:00:05 actions=fin_timeout(idle_timeout=5,hard_timeout=10),output:1