ofproto: Properly refresh rule modified time when nothing else changes.
[sliver-openvswitch.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(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])
8 ]])
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])
15 ]])
16 AT_CLEANUP
17
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
25 ]])
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
33 ]])
34 AT_CLEANUP
35
36 AT_SETUP([learning action - satisfied prerequisites])
37 AT_DATA([flows.txt],
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[])
41 ]])
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[])
48 ]])
49 AT_CLEANUP
50
51 AT_SETUP([learning action - invalid prerequisites])
52 AT_CHECK([[ovs-ofctl parse-flow 'actions=learn(load:5->NXM_OF_IP_DST[])']],
53   [1], [],
54   [[ovs-ofctl: load:5->NXM_OF_IP_DST[]: cannot specify destination field ip_dst because prerequisites are not satisfied
55 ]])
56 AT_CHECK([[ovs-ofctl parse-flow 'actions=learn(load:NXM_OF_IP_DST[]->NXM_NX_REG1[])']],
57   [1], [],
58   [[ovs-ofctl: load:NXM_OF_IP_DST[]->NXM_NX_REG1[]: cannot specify source field ip_dst because prerequisites are not satisfied
59 ]])
60 AT_CLEANUP
61
62 AT_SETUP([learning action - standard VLAN+MAC learning])
63 OVS_VSWITCHD_START(
64   [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 -- \
65    add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2 -- \
66    add-port br0 p3 -- set Interface p3 type=dummy ofport_request=3])
67 # Set up flow table for VLAN+MAC learning.
68 AT_DATA([flows.txt], [[
69 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)
70 table=1 priority=0 actions=flood
71 ]])
72 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
73
74 # Trace an ARP packet arriving on port 3, to create a MAC learning entry.
75 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)"
76 AT_CHECK([ovs-appctl ofproto/trace br0 "$flow" -generate], [0], [stdout])
77 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
78
79 expected="1,2,100"
80 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
81 mv stdout expout
82 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
83
84 # Check for the MAC learning entry.
85 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
86  table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:05 actions=output:3
87  table=1, priority=0 actions=FLOOD
88 NXST_FLOW reply:
89 ])
90
91 # Trace a packet arrival destined for the learned MAC.
92 # (This will also learn a MAC.)
93 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])
94 AT_CHECK([tail -1 stdout], [0], [Datapath actions: 3
95 ])
96
97 # Check for both MAC learning entries.
98 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip |sort], [0], [dnl
99  table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:05 actions=output:3
100  table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:06 actions=output:1
101  table=1, priority=0 actions=FLOOD
102 NXST_FLOW reply:
103 ])
104
105 # Trace a packet arrival that updates the first learned MAC entry.
106 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)"
107 AT_CHECK([ovs-appctl ofproto/trace br0 "$flow" -generate], [0], [stdout])
108 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
109
110 expected="1,3,100"
111 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
112 mv stdout expout
113 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
114
115 # Check that the MAC learning entry was updated.
116 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
117  table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:05 actions=output:2
118  table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:06 actions=output:1
119  table=1, priority=0 actions=FLOOD
120 NXST_FLOW reply:
121 ])
122 OVS_VSWITCHD_STOP
123 AT_CLEANUP
124
125 dnl This test checks that repeated uses of a "learn" action cause the
126 dnl modified time of the learned flow to advance.  Otherwise, the
127 dnl learned flow will expire after its hard timeout even though it's
128 dnl supposed to be refreshed.  (The expiration can be hard to see since
129 dnl it gets re-learned again the next time a packet appears, but
130 dnl sometimes the expiration can cause temporary flooding etc.)
131 AT_SETUP([learning action - learn refreshes hard_age])
132 OVS_VSWITCHD_START(
133   [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 -- \
134    add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2 -- \
135    add-port br0 p3 -- set Interface p3 type=dummy ofport_request=3])
136
137 ovs-appctl time/stop
138
139 # Set up flow table for MAC learning.
140 AT_DATA([flows.txt], [[
141 table=0 actions=learn(table=1, hard_timeout=10, NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], output:NXM_OF_IN_PORT[]), resubmit(,1)
142 table=1 priority=0 actions=flood
143 ]])
144 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
145
146 # Trace an ICMP packet arriving on port 3, to create a MAC learning entry.
147 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)"
148 AT_CHECK([ovs-appctl ofproto/trace br0 "$flow" -generate], [0], [stdout])
149 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
150
151 expected="1,2,100"
152 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
153 mv stdout expout
154 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
155
156 # Check that the MAC learning entry appeared.
157 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
158  table=1, hard_timeout=10, dl_dst=50:54:00:00:00:07 actions=output:3
159  table=1, priority=0 actions=FLOOD
160 NXST_FLOW reply:
161 ])
162
163 # For 25 seconds, make sure that the MAC learning entry doesn't
164 # disappear as long as we refresh it every second.
165 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
166     ovs-appctl time/warp 1000
167     AT_CHECK([ovs-appctl ofproto/trace br0 "$flow" -generate], [0], [stdout])
168
169     # Check that the entry is there.
170     AT_CHECK([ovs-ofctl dump-flows br0 table=1], [0], [stdout])
171     AT_CHECK([ofctl_strip < stdout | sort], [0], [dnl
172  table=1, hard_timeout=10, dl_dst=50:54:00:00:00:07 actions=output:3
173  table=1, priority=0 actions=FLOOD
174 NXST_FLOW reply:
175 ])
176
177     if test $i != 1; then
178         # Check that hard_age has appeared.  We need to do this separately
179         # from the above check because ofctl_strip removes it.  dump-flows
180         # only prints hard_age when it is different from the flow's duration
181         # (that is, the number of seconds from the time it was created),
182         # so we only check for it after we've refreshed the flow once.
183         AT_CHECK([grep dl_dst=50:54:00:00:00:07 stdout | grep -c hard_age],
184                  [0], [1
185 ])
186     fi
187 done
188
189 # Make sure that 15 seconds without refreshing makes the flow time out.
190 ovs-appctl time/warp 5000
191 ovs-appctl time/warp 5000
192 ovs-appctl time/warp 5000
193     AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
194  table=1, priority=0 actions=FLOOD
195 NXST_FLOW reply:
196 ])
197 OVS_VSWITCHD_STOP
198 AT_CLEANUP
199
200 AT_SETUP([learning action - TCPv4 port learning])
201 OVS_VSWITCHD_START(
202   [add-port br0 p1 -- set Interface p1 type=dummy -- \
203    add-port br0 p2 -- set Interface p2 type=dummy -- \
204    add-port br0 p3 -- set Interface p3 type=dummy])
205 # Set up flow table for TCPv4 port learning.
206 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']])
207
208 # Trace a TCPv4 packet arriving on port 3.
209 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)"
210 AT_CHECK([ovs-appctl ofproto/trace br0 "$flow" -generate], [0], [stdout])
211 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
212
213 expected="1,2,100"
214 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
215 mv stdout expout
216 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
217
218 # Check for the learning entry.
219 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
220  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
221 NXST_FLOW reply:
222 ])
223 OVS_VSWITCHD_STOP
224 AT_CLEANUP
225
226 AT_SETUP([learning action - TCPv6 port learning])
227 OVS_VSWITCHD_START(
228   [add-port br0 p1 -- set Interface p1 type=dummy -- \
229    add-port br0 p2 -- set Interface p2 type=dummy -- \
230    add-port br0 p3 -- set Interface p3 type=dummy])
231 # Set up flow table for TCPv6 port learning.
232 # Also add a 128-bit-wide "load" action and a 128-bit literal match to check
233 # that they work.
234 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']])
235
236 # Trace a TCPv6 packet arriving on port 3.
237 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)"
238 AT_CHECK([ovs-appctl ofproto/trace br0 "$flow" -generate], [0], [stdout])
239 actual=`tail -1 stdout | sed 's/Datapath actions: //'`
240
241 expected="1,2,100"
242 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
243 mv stdout expout
244 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
245
246 # Check for the learning entry.
247 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
248  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]]
249  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
250 NXST_FLOW reply:
251 ])
252 OVS_VSWITCHD_STOP
253 AT_CLEANUP
254
255 AT_SETUP([learning action - fin_timeout feature])
256 # This is a totally artificial use of the "learn" action.  The only purpose
257 # is to check that specifying fin_idle_timeout or fin_hard_timeout causes
258 # a corresponding fin_timeout action to end up in the learned flows.
259 OVS_VSWITCHD_START(
260     [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1])
261 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[])']])
262 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])
263 AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip], [0],
264 [NXST_FLOW reply:
265  table=1, dl_dst=50:54:00:00:00:05 actions=fin_timeout(idle_timeout=5,hard_timeout=10),output:1
266 ])
267 OVS_VSWITCHD_STOP
268 AT_CLEANUP