blob: 821f9628d8f3b9d8fefadabc4e12d600b1922b13 [file] [log] [blame]
Dan Talaycod2ca1032010-03-10 14:40:26 -08001import sys
Dan Talayco92c99122010-06-03 13:53:18 -07002import copy
Rich Lane6242d9f2013-01-06 17:35:39 -08003import logging
4import types
5import time
Rich Lane5a9a1922013-01-11 14:29:30 -08006import re
Dan Talaycod2ca1032010-03-10 14:40:26 -08007
8try:
9 import scapy.all as scapy
10except:
11 try:
12 import scapy as scapy
13 except:
14 sys.exit("Need to install scapy for packet parsing")
Dan Talayco41eae8b2010-03-10 13:57:06 -080015
Rich Lanecd97d3d2013-01-07 18:50:06 -080016import oftest
17import oftest.controller
18import oftest.dataplane
Rich Lanef6883512013-03-11 17:00:09 -070019import oftest.parse
Rich Lane4c504f32013-06-07 17:24:14 -070020import oftest.ofutils
Rich Lanee717c6e2013-03-12 10:25:50 -070021import ofp
Dan Talaycoc901f4d2010-03-07 21:55:45 -080022
Dan Talaycoba3745c2010-07-21 21:51:08 -070023global skipped_test_count
24skipped_test_count = 0
25
Rich Lane7744e112013-01-11 17:23:57 -080026_import_blacklist = set(locals().keys())
27
Dan Talayco551befa2010-07-15 17:05:32 -070028# Some useful defines
29IP_ETHERTYPE = 0x800
30TCP_PROTOCOL = 0x6
31UDP_PROTOCOL = 0x11
32
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000033MINSIZE = 0
34
Rich Lane9a003812012-10-04 17:17:59 -070035def delete_all_flows(ctrl):
Dan Talayco41eae8b2010-03-10 13:57:06 -080036 """
37 Delete all flows on the switch
38 @param ctrl The controller object for the test
Dan Talayco41eae8b2010-03-10 13:57:06 -080039 """
40
Rich Lane9a003812012-10-04 17:17:59 -070041 logging.info("Deleting all flows")
Rich Lanee717c6e2013-03-12 10:25:50 -070042 msg = ofp.message.flow_delete()
43 msg.match.wildcards = ofp.OFPFW_ALL
44 msg.out_port = ofp.OFPP_NONE
Dan Talaycoc901f4d2010-03-07 21:55:45 -080045 msg.buffer_id = 0xffffffff
Rich Lane5c3151c2013-01-03 17:15:41 -080046 ctrl.message_send(msg)
Rich Lane44c4e3f2013-07-08 10:17:49 -070047 do_barrier(ctrl)
Rich Lane32bf9482013-01-03 17:26:30 -080048 return 0 # for backwards compatibility
Dan Talayco41eae8b2010-03-10 13:57:06 -080049
Ed Swierk99a74de2012-08-22 06:40:54 -070050def required_wildcards(parent):
Rich Lane2014f9b2012-10-05 15:29:40 -070051 w = test_param_get('required_wildcards', default='default')
Ed Swierk99a74de2012-08-22 06:40:54 -070052 if w == 'l3-l4':
Rich Lanee717c6e2013-03-12 10:25:50 -070053 return (ofp.OFPFW_NW_SRC_ALL | ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS
54 | ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST)
Ed Swierk99a74de2012-08-22 06:40:54 -070055 else:
56 return 0
57
Dan Talayco41eae8b2010-03-10 13:57:06 -080058def simple_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -070059 eth_dst='00:01:02:03:04:05',
60 eth_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070061 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -070062 vlan_vid=0,
63 vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070064 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080065 ip_src='192.168.0.1',
66 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070067 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -080068 ip_ttl=64,
Dan Talayco41eae8b2010-03-10 13:57:06 -080069 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070070 tcp_dport=80,
71 ip_ihl=None,
72 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080073 ):
74 """
75 Return a simple dataplane TCP packet
76
77 Supports a few parameters:
78 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -070079 @param eth_dst Destinatino MAC
80 @param eth_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070081 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -070082 @param vlan_vid VLAN ID
83 @param vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080084 @param ip_src IP source
85 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070086 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -080087 @param ip_ttl IP TTL
Dan Talayco41eae8b2010-03-10 13:57:06 -080088 @param tcp_dport TCP destination port
89 @param ip_sport TCP source port
90
91 Generates a simple TCP request. Users
92 shouldn't assume anything about this packet other than that
93 it is a valid ethernet/IP/TCP frame.
94 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000095
96 if MINSIZE > pktlen:
97 pktlen = MINSIZE
98
Dan Talayco551befa2010-07-15 17:05:32 -070099 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800100 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700101 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
102 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800103 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700104 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
105 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700106 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700107 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800108 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700109 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
110 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700111 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800112 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700113 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700114
Dan Talayco41eae8b2010-03-10 13:57:06 -0800115 pkt = pkt/("D" * (pktlen - len(pkt)))
116
117 return pkt
118
Rich Lane6ee7bea2012-10-26 16:19:29 -0700119def simple_udp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700120 eth_dst='00:01:02:03:04:05',
121 eth_src='00:06:07:08:09:0a',
Rich Lane6ee7bea2012-10-26 16:19:29 -0700122 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700123 vlan_vid=0,
124 vlan_pcp=0,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700125 dl_vlan_cfi=0,
126 ip_src='192.168.0.1',
127 ip_dst='192.168.0.2',
128 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800129 ip_ttl=64,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700130 udp_sport=1234,
131 udp_dport=80,
132 ip_ihl=None,
133 ip_options=False
134 ):
135 """
136 Return a simple dataplane UDP packet
137
138 Supports a few parameters:
139 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700140 @param eth_dst Destination MAC
141 @param eth_src Source MAC
Rich Lane6ee7bea2012-10-26 16:19:29 -0700142 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700143 @param vlan_vid VLAN ID
144 @param vlan_pcp VLAN priority
Rich Lane6ee7bea2012-10-26 16:19:29 -0700145 @param ip_src IP source
146 @param ip_dst IP destination
147 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800148 @param ip_ttl IP TTL
Rich Lane6ee7bea2012-10-26 16:19:29 -0700149 @param udp_dport UDP destination port
150 @param udp_sport UDP source port
151
152 Generates a simple UDP packet. Users shouldn't assume anything about
153 this packet other than that it is a valid ethernet/IP/UDP frame.
154 """
155
156 if MINSIZE > pktlen:
157 pktlen = MINSIZE
158
159 # Note Dot1Q.id is really CFI
160 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700161 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
162 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800163 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700164 scapy.UDP(sport=udp_sport, dport=udp_dport)
165 else:
166 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700167 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800168 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700169 scapy.UDP(sport=udp_sport, dport=udp_dport)
170 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700171 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800172 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700173 scapy.UDP(sport=udp_sport, dport=udp_dport)
174
175 pkt = pkt/("D" * (pktlen - len(pkt)))
176
177 return pkt
178
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700179def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700180 eth_dst='00:01:02:03:04:05',
181 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700182 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700183 vlan_vid=0,
184 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700185 ip_src='192.168.0.1',
186 ip_dst='192.168.0.2',
187 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800188 ip_ttl=64,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700189 icmp_type=8,
190 icmp_code=0
191 ):
192 """
193 Return a simple ICMP packet
194
195 Supports a few parameters:
196 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700197 @param eth_dst Destinatino MAC
198 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700199 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700200 @param vlan_vid VLAN ID
201 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700202 @param ip_src IP source
203 @param ip_dst IP destination
204 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800205 @param ip_ttl IP TTL
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700206 @param icmp_type ICMP type
207 @param icmp_code ICMP code
208
209 Generates a simple ICMP ECHO REQUEST. Users
210 shouldn't assume anything about this packet other than that
211 it is a valid ethernet/ICMP frame.
212 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000213
214 if MINSIZE > pktlen:
215 pktlen = MINSIZE
216
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700217 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700218 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
219 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800220 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700221 scapy.ICMP(type=icmp_type, code=icmp_code)
222 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700223 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800224 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700225 scapy.ICMP(type=icmp_type, code=icmp_code)
226
227 pkt = pkt/("0" * (pktlen - len(pkt)))
228
229 return pkt
230
Shudong Zhouc7562b12013-02-06 01:12:18 -0800231def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700232 eth_dst='ff:ff:ff:ff:ff:ff',
233 eth_src='00:06:07:08:09:0a',
Shudong Zhouc7562b12013-02-06 01:12:18 -0800234 arp_op=1,
235 ip_snd='192.168.0.1',
236 ip_tgt='192.168.0.2',
237 hw_snd='00:06:07:08:09:0a',
238 hw_tgt='00:00:00:00:00:00',
239 ):
240 """
241 Return a simple ARP packet
242
243 Supports a few parameters:
244 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700245 @param eth_dst Destinatino MAC
246 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800247 @param arp_op Operation (1=request, 2=reply)
248 @param ip_snd Sender IP
249 @param ip_tgt Target IP
250 @param hw_snd Sender hardware address
251 @param hw_tgt Target hardware address
252
253 Generates a simple ARP REQUEST. Users
254 shouldn't assume anything about this packet other than that
255 it is a valid ethernet/ARP frame.
256 """
257
258 if MINSIZE > pktlen:
259 pktlen = MINSIZE
260
Rich Laned0478ff2013-03-11 12:46:58 -0700261 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhouc7562b12013-02-06 01:12:18 -0800262 scapy.ARP(hwsrc=hw_snd, hwdst=hw_tgt, pdst=ip_tgt, psrc=ip_snd, op=arp_op)
263
264 pkt = pkt/("0" * (pktlen - len(pkt)))
265
266 return pkt
267
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700268def simple_eth_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700269 eth_dst='00:01:02:03:04:05',
270 eth_src='01:80:c2:00:00:00',
271 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000272
273 if MINSIZE > pktlen:
274 pktlen = MINSIZE
275
Rich Laned0478ff2013-03-11 12:46:58 -0700276 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700277
278 pkt = pkt/("0" * (pktlen - len(pkt)))
279
280 return pkt
281
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800282def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700283 eth_dst='00:01:02:03:04:05',
284 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800285 dl_vlan_outer=20,
286 dl_vlan_pcp_outer=0,
287 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700288 vlan_vid=10,
289 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800290 dl_vlan_cfi=0,
291 ip_src='192.168.0.1',
292 ip_dst='192.168.0.2',
293 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800294 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800295 tcp_sport=1234,
296 tcp_dport=80,
297 ip_ihl=None,
298 ip_options=False
299 ):
300 """
301 Return a doubly tagged dataplane TCP packet
302
303 Supports a few parameters:
304 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700305 @param eth_dst Destinatino MAC
306 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800307 @param dl_vlan_outer Outer VLAN ID
308 @param dl_vlan_pcp_outer Outer VLAN priority
309 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700310 @param vlan_vid Inner VLAN ID
311 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800312 @param dl_vlan_cfi VLAN cfi bit
313 @param ip_src IP source
314 @param ip_dst IP destination
315 @param ip_tos IP ToS
316 @param tcp_dport TCP destination port
317 @param ip_sport TCP source port
318
319 Generates a TCP request. Users
320 shouldn't assume anything about this packet other than that
321 it is a valid ethernet/IP/TCP frame.
322 """
323
324 if MINSIZE > pktlen:
325 pktlen = MINSIZE
326
327 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700328 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800329 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700330 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800331 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800332 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
333
334 pkt = pkt/("D" * (pktlen - len(pkt)))
335
336 return pkt
337
Shudong Zhoub7f12462012-11-20 13:01:12 -0800338def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700339 """
340 Do a barrier command
341 Return 0 on success, -1 on error
342 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700343 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800344 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800345 if resp is None:
346 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700347 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800348 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700349
Rich Lane9a003812012-10-04 17:17:59 -0700350def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700351 """
352 Get a port's configuration
353
354 Gets the switch feature configuration and grabs one port's
355 configuration
356
357 @returns (hwaddr, config, advert) The hwaddress, configuration and
358 advertised values
359 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700360 request = ofp.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700361 reply, pkt = controller.transact(request)
Rich Lane9a003812012-10-04 17:17:59 -0700362 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700363 if reply is None:
Rich Lane9a003812012-10-04 17:17:59 -0700364 logging.warn("Get feature request failed")
Dan Talayco92c99122010-06-03 13:53:18 -0700365 return None, None, None
366 for idx in range(len(reply.ports)):
367 if reply.ports[idx].port_no == port_no:
368 return (reply.ports[idx].hw_addr, reply.ports[idx].config,
369 reply.ports[idx].advertised)
370
Rich Lane9a003812012-10-04 17:17:59 -0700371 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700372 return None, None, None
373
Rich Lane9a003812012-10-04 17:17:59 -0700374def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700375 """
376 Set the port configuration according the given parameters
377
378 Gets the switch feature configuration and updates one port's
379 configuration value according to config and mask
380 """
Rich Lane9a003812012-10-04 17:17:59 -0700381 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lanee717c6e2013-03-12 10:25:50 -0700382 request = ofp.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700383 reply, pkt = controller.transact(request)
Dan Talayco92c99122010-06-03 13:53:18 -0700384 if reply is None:
385 return -1
Rich Lane9a003812012-10-04 17:17:59 -0700386 logging.debug(reply.show())
Ed Swierk8d84ce02012-12-27 15:36:48 -0800387 p = None
Dan Talayco92c99122010-06-03 13:53:18 -0700388 for idx in range(len(reply.ports)):
389 if reply.ports[idx].port_no == port_no:
Ed Swierk8d84ce02012-12-27 15:36:48 -0800390 p = reply.ports[idx]
Dan Talayco92c99122010-06-03 13:53:18 -0700391 break
Rich Lanee717c6e2013-03-12 10:25:50 -0700392 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700393 mod.port_no = port_no
Ed Swierk8d84ce02012-12-27 15:36:48 -0800394 if p:
395 mod.hw_addr = p.hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700396 mod.config = config
397 mod.mask = mask
Ed Swierk8d84ce02012-12-27 15:36:48 -0800398 if p:
399 mod.advertise = p.advertised
Rich Lane5c3151c2013-01-03 17:15:41 -0800400 controller.message_send(mod)
401 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700402
Rich Lane2014f9b2012-10-05 15:29:40 -0700403def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700404 """
405 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700406 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700407 @param pkt Expected packet; may be None if yes_ports is empty
408 @param yes_ports Set or list of ports that should recieve packet
409 @param no_ports Set or list of ports that should not receive packet
410 @param assert_if Object that implements assertXXX
411 """
Rich Lane91765672012-12-06 16:33:04 -0800412
413 # Wait this long for packets that we don't expect to receive.
414 # 100ms is (rarely) too short for positive tests on slow
415 # switches but is definitely not too short for a negative test.
416 negative_timeout = 0.1
417
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700418 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800419 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700420 exp_pkt_arg = pkt
421
Dan Talayco92c99122010-06-03 13:53:18 -0700422 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700423 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700424 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700425 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700426 assert_if.assertTrue(rcv_pkt is not None,
427 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800428 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800429 logging.debug("Expected %s" % format_packet(pkt))
430 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800431 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800432 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700433 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700434 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800435 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700436 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700437 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700438 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800439 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700440 assert_if.assertTrue(rcv_pkt is None,
441 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700442
443
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700444def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700445 """
446 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700447 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700448
449 parent must implement dataplane, assertTrue and assertEqual
450 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700451 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800452 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700453 exp_pkt_arg = exp_pkt
454
Dan Talaycof6e76c02012-03-23 10:56:12 -0700455 if type(egr_ports) == type([]):
456 egr_port_list = egr_ports
457 else:
458 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700459
Dan Talaycof6e76c02012-03-23 10:56:12 -0700460 # Expect a packet from each port on egr port list
461 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700462 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700463 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700464 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700465 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700466 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700467
Dan Talaycof6e76c02012-03-23 10:56:12 -0700468 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700469 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700470 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700471
Dan Talaycof6e76c02012-03-23 10:56:12 -0700472 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700473 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700474 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700475 str(rcv_port))
476
477 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700478 logging.error("ERROR: Packet match failed.")
479 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700480 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700481 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700482 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700483 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
484 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700485 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700486 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700487
Dan Talayco551befa2010-07-15 17:05:32 -0700488def match_verify(parent, req_match, res_match):
489 """
490 Verify flow matches agree; if they disagree, report where
491
492 parent must implement assertEqual
493 Use str() to ensure content is compared and not pointers
494 """
495
496 parent.assertEqual(req_match.wildcards, res_match.wildcards,
497 'Match failed: wildcards: ' + hex(req_match.wildcards) +
498 " != " + hex(res_match.wildcards))
499 parent.assertEqual(req_match.in_port, res_match.in_port,
500 'Match failed: in_port: ' + str(req_match.in_port) +
501 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700502 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
503 'Match failed: eth_src: ' + str(req_match.eth_src) +
504 " != " + str(res_match.eth_src))
505 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
506 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
507 " != " + str(res_match.eth_dst))
508 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
509 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
510 " != " + str(res_match.vlan_vid))
511 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
512 'Match failed: vlan_pcp: ' +
513 str(req_match.vlan_pcp) + " != " +
514 str(res_match.vlan_pcp))
515 parent.assertEqual(req_match.eth_type, res_match.eth_type,
516 'Match failed: eth_type: ' + str(req_match.eth_type) +
517 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700518
Rich Lanee717c6e2013-03-12 10:25:50 -0700519 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700520 and (req_match.eth_type == IP_ETHERTYPE)):
521 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
522 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
523 " != " + str(res_match.ip_dscp))
524 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
525 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
526 " != " + str(res_match.ip_proto))
527 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
528 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
529 " != " + str(res_match.ipv4_src))
530 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
531 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
532 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700533
Rich Lanee717c6e2013-03-12 10:25:50 -0700534 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700535 and ((req_match.ip_proto == TCP_PROTOCOL)
536 or (req_match.ip_proto == UDP_PROTOCOL))):
537 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
538 'Match failed: tcp_src: ' +
539 str(req_match.tcp_src) +
540 " != " + str(res_match.tcp_src))
541 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
542 'Match failed: tcp_dst: ' +
543 str(req_match.tcp_dst) +
544 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700545
Ed Swierk99a74de2012-08-22 06:40:54 -0700546def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700547 match = oftest.parse.packet_to_flow_match(packet)
Ed Swierk99a74de2012-08-22 06:40:54 -0700548 match.wildcards |= required_wildcards(parent)
549 return match
550
551def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700552 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700553 """
554 Create a flow message
555
556 Match on packet with given wildcards.
557 See flow_match_test for other parameter descriptoins
558 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700559 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700560 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700561 """
Rich Lanef6883512013-03-11 17:00:09 -0700562 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700563 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700564 if wildcards is None:
565 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700566 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700567 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700568 match.wildcards = wildcards
569 match.in_port = ing_port
570
Dan Talaycof6e76c02012-03-23 10:56:12 -0700571 if type(egr_ports) == type([]):
572 egr_port_list = egr_ports
573 else:
574 egr_port_list = [egr_ports]
575
Rich Lanee717c6e2013-03-12 10:25:50 -0700576 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700577 request.match = match
578 request.buffer_id = 0xffffffff
579 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700580 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700581 request.hard_timeout = 1
582
583 if action_list is not None:
584 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700585 logging.debug("Adding action " + act.show())
Rich Lanec495d9e2013-03-08 17:43:36 -0800586 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700587
588 # Set up output/enqueue action if directed
589 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700590 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700591 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700592 for egr_port in egr_port_list:
593 act.port = egr_port
594 act.queue_id = egr_queue
Rich Lanec495d9e2013-03-08 17:43:36 -0800595 request.actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700596 elif egr_ports is not None:
597 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700598 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700599 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800600 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700601
Rich Lane9a003812012-10-04 17:17:59 -0700602 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700603
604 return request
605
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700606def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700607 """
608 Install a flow mod message in the switch
609
610 @param parent Must implement controller, assertEqual, assertTrue
611 @param request The request, all set to go
612 @param clear_table If true, clear the flow table before installing
613 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700614
Rich Lane2014f9b2012-10-05 15:29:40 -0700615 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700616 if(clear_table_override != None):
617 clear_table = clear_table_override
618
619 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700620 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800621 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700622
Rich Lane9a003812012-10-04 17:17:59 -0700623 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800624 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800625
Rich Lane3a261d52013-01-03 17:45:08 -0800626 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700627
Ed Swierk99a74de2012-08-22 06:40:54 -0700628def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700629 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700630 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700631 """
632 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700633 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700634
635 Run test with packet through switch from ing_port to egr_port
636 See flow_match_test for parameter descriptions
637 """
638
Ed Swierk99a74de2012-08-22 06:40:54 -0700639 if wildcards is None:
640 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700641 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700642 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700643 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700644 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700645 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Dan Talayco551befa2010-07-15 17:05:32 -0700646
647 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700648 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700649 action_list=action_list)
650
651 flow_msg_install(parent, request)
652
Rich Lane9a003812012-10-04 17:17:59 -0700653 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700654 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700655 parent.dataplane.send(ing_port, str(pkt))
656
657 if exp_pkt is None:
658 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700659 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700660
Rich Lane89725bb2012-12-03 16:23:27 -0800661def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700662 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800663 action_list=None):
664 """
665 Packet-out test on single TCP packet
666 @param egr_ports A single port or list of ports
667
668 Run test sending packet-out to egr_ports. The goal is to test the actions
669 taken on the packet, not the matching which is of course irrelevant.
670 See flow_match_test for parameter descriptions
671 """
672
673 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700674 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lane89725bb2012-12-03 16:23:27 -0800675
Rich Lanee717c6e2013-03-12 10:25:50 -0700676 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800677 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700678 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800679 msg.data = str(pkt)
680 if action_list is not None:
681 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800682 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800683
684 # Set up output action
685 if egr_ports is not None:
686 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700687 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800688 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800689 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800690
691 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800692 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800693
694 if exp_pkt is None:
695 exp_pkt = pkt
696 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
697
Dan Talaycof6e76c02012-03-23 10:56:12 -0700698def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
699 """
700 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700701 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700702 @param of_ports List of OF port numbers
703 @param how_many Number of ports to be added to the list
704 @param exclude_list List of ports not to be used
705 @returns An empty list if unable to find enough ports
706 """
707
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700708 if how_many == 0:
709 return []
710
Dan Talaycof6e76c02012-03-23 10:56:12 -0700711 count = 0
712 egr_ports = []
713 for egr_idx in range(len(of_ports)):
714 if of_ports[egr_idx] not in exclude_list:
715 egr_ports.append(of_ports[egr_idx])
716 count += 1
717 if count >= how_many:
718 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700719 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700720 return []
721
Rich Laned0478ff2013-03-11 12:46:58 -0700722def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700723 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700724 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700725 """
Rich Lane89725bb2012-12-03 16:23:27 -0800726 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700727
728 @param max_test If > 0 no more than this number of tests are executed.
729 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700730 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700731 @param pkt If not None, use this packet for ingress
732 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700733 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700734 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
735 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700736 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700737 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700738 if wildcards is None:
739 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700740 of_ports = port_map.keys()
741 of_ports.sort()
742 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
743 test_count = 0
744
Dan Talaycocfa172f2012-03-23 12:03:00 -0700745 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700746 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700747
Dan Talayco551befa2010-07-15 17:05:32 -0700748 for ing_idx in range(len(of_ports)):
749 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700750 egr_ports = get_egr_list(parent, of_ports, egr_count,
751 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700752 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700753 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700754 if len(egr_ports) == 0:
755 parent.assertTrue(0, "Failed to generate egress port list")
756
757 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700758 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700759 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700760 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700761 test_count += 1
762 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700763 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800764 break
765
Ed Swierk38eea082013-01-02 19:46:20 -0800766 if not test_param_get('pktout_actions', default=True):
767 return
Rich Lane89725bb2012-12-03 16:23:27 -0800768
769 ingress_port = of_ports[0]
770 egr_ports = get_egr_list(parent, of_ports, egr_count,
771 exclude_list=[ingress_port])
772 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700773 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800774 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700775 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800776 pkt=pkt, exp_pkt=exp_pkt,
777 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700778
Rich Lane2014f9b2012-10-05 15:29:40 -0700779def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700780 """
781 Return value passed via test-params if present
782
Dan Talayco4b2bee62010-07-20 14:10:05 -0700783 @param key The lookup key
784 @param default Default value to use if not found
785
786 If the pair 'key=val' appeared in the string passed to --test-params
787 on the command line, return val (as interpreted by exec). Otherwise
788 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700789
790 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
791 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700792 """
793 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800794 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700795 except:
796 return default
797
798 s = "val = " + str(key)
799 try:
800 exec s
801 return val
802 except:
803 return default
804
805def action_generate(parent, field_to_mod, mod_field_vals):
806 """
807 Create an action to modify the field indicated in field_to_mod
808
809 @param parent Must implement, assertTrue
810 @param field_to_mod The field to modify as a string name
811 @param mod_field_vals Hash of values to use for modified values
812 """
813
814 act = None
815
816 if field_to_mod in ['pktlen']:
817 return None
818
Rich Laned0478ff2013-03-11 12:46:58 -0700819 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700820 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700821 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700822 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700823 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700824 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700825 elif field_to_mod == 'dl_vlan_enable':
826 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -0700827 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -0700828 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -0700829 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -0700830 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -0700831 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -0700832 act.vlan_vid = mod_field_vals['vlan_vid']
833 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -0700834 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -0700835 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700836 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700837 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -0700838 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700839 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700840 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700841 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700842 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -0700843 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700844 act.nw_tos = mod_field_vals['ip_tos']
845 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700846 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700847 act.tp_port = mod_field_vals['tcp_sport']
848 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700849 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700850 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700851 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700852 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -0700853 act.tp_port = mod_field_vals['udp_sport']
854 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700855 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -0700856 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700857 else:
858 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
859
860 return act
861
862def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -0700863 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700864 """
865 Set up the ingress and expected packet and action list for a test
866
Rich Lane2014f9b2012-10-05 15:29:40 -0700867 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700868 @param start_field_values Field values to use for ingress packet (optional)
869 @param mod_field_values Field values to use for modified packet (optional)
870 @param mod_fields The list of fields to be modified by the switch in the test.
871 @params check_test_params If True, will check the parameters vid, add_vlan
872 and strip_vlan from the command line.
873
874 Returns a triple: pkt-to-send, expected-pkt, action-list
875 """
876
877 new_actions = []
878
Dan Talayco4b2bee62010-07-20 14:10:05 -0700879 base_pkt_params = {}
880 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -0700881 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
882 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -0700883 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -0700884 base_pkt_params['vlan_vid'] = 2
885 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -0700886 base_pkt_params['ip_src'] = '192.168.0.1'
887 base_pkt_params['ip_dst'] = '192.168.0.2'
888 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -0700889 if tp == "tcp":
890 base_pkt_params['tcp_sport'] = 1234
891 base_pkt_params['tcp_dport'] = 80
892 elif tp == "udp":
893 base_pkt_params['udp_sport'] = 1234
894 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -0700895 for keyname in start_field_vals.keys():
896 base_pkt_params[keyname] = start_field_vals[keyname]
897
898 mod_pkt_params = {}
899 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -0700900 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
901 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -0700902 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -0700903 mod_pkt_params['vlan_vid'] = 3
904 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -0700905 mod_pkt_params['ip_src'] = '10.20.30.40'
906 mod_pkt_params['ip_dst'] = '50.60.70.80'
907 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -0700908 if tp == "tcp":
909 mod_pkt_params['tcp_sport'] = 4321
910 mod_pkt_params['tcp_dport'] = 8765
911 elif tp == "udp":
912 mod_pkt_params['udp_sport'] = 4321
913 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -0700914 for keyname in mod_field_vals.keys():
915 mod_pkt_params[keyname] = mod_field_vals[keyname]
916
917 # Check for test param modifications
918 strip = False
919 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700920 add_vlan = test_param_get('add_vlan')
921 strip_vlan = test_param_get('strip_vlan')
922 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700923
924 if add_vlan and strip_vlan:
925 parent.assertTrue(0, "Add and strip VLAN both specified")
926
927 if vid:
928 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -0700929 base_pkt_params['vlan_vid'] = vid
930 if 'vlan_vid' in mod_fields:
931 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -0700932
933 if add_vlan:
934 base_pkt_params['dl_vlan_enable'] = False
935 mod_pkt_params['dl_vlan_enable'] = True
936 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
937 mod_fields.append('pktlen')
938 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -0700939 if 'vlan_vid' not in mod_fields:
940 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700941 elif strip_vlan:
942 base_pkt_params['dl_vlan_enable'] = True
943 mod_pkt_params['dl_vlan_enable'] = False
944 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
945 mod_fields.append('dl_vlan_enable')
946 mod_fields.append('pktlen')
947
Rich Lane110e0e32012-10-26 16:21:46 -0700948 if tp == "tcp":
949 packet_builder = simple_tcp_packet
950 elif tp == "udp":
951 packet_builder = simple_udp_packet
952 else:
953 raise NotImplementedError("unknown transport protocol %s" % tp)
954
Dan Talayco4b2bee62010-07-20 14:10:05 -0700955 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -0700956 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700957
958 # Build the expected packet, modifying the indicated fields
959 for item in mod_fields:
960 base_pkt_params[item] = mod_pkt_params[item]
961 act = action_generate(parent, item, mod_pkt_params)
962 if act:
963 new_actions.append(act)
964
Rich Lane110e0e32012-10-26 16:21:46 -0700965 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700966
967 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700968
969# Generate a simple "drop" flow mod
970# If in_band is true, then only drop from first test port
971def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -0700972 request = ofp.message.flow_add()
973 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -0700974 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700975 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -0700976 for of_port, ifname in port_map.items(): # Grab first port
977 break
978 request.match.in_port = of_port
979 request.buffer_id = 0xffffffff
980 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700981
982def skip_message_emit(parent, s):
983 """
984 Print out a 'skipped' message to stderr
985
986 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -0700987 """
988 global skipped_test_count
989
990 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -0700991 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -0800992 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700993 sys.stderr.write("(skipped) ")
994 else:
995 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -0700996
Dan Talayco8a64e332012-03-28 14:53:20 -0700997
998def all_stats_get(parent):
999 """
1000 Get the aggregate stats for all flows in the table
1001 @param parent Test instance with controller connection and assert
1002 @returns dict with keys flows, packets, bytes, active (flows),
1003 lookups, matched
1004 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001005 stat_req = ofp.message.aggregate_stats_request()
1006 stat_req.match = ofp.match()
1007 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001008 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001009 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001010
1011 rv = {}
1012
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001013 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001014 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001015
Rich Lane5fd6faf2013-03-11 13:30:20 -07001016 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001017 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1018 obj.packet_count, obj.byte_count)
1019 break
1020
Rich Lanee717c6e2013-03-12 10:25:50 -07001021 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001022 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001023
1024
1025 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001026 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001027 rv["active"] += obj.active_count
1028 rv["lookups"] += obj.lookup_count
1029 rv["matched"] += obj.matched_count
1030
1031 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001032
Rich Lane7744e112013-01-11 17:23:57 -08001033_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001034FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1035 for x in range(256)])
1036
1037def hex_dump_buffer(src, length=16):
1038 """
1039 Convert src to a hex dump string and return the string
1040 @param src The source buffer
1041 @param length The number of bytes shown in each line
1042 @returns A string showing the hex dump
1043 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001044 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001045 for i in xrange(0, len(src), length):
1046 chars = src[i:i+length]
1047 hex = ' '.join(["%02x" % ord(x) for x in chars])
1048 printable = ''.join(["%s" % ((ord(x) <= 127 and
1049 FILTER[ord(x)]) or '.') for x in chars])
1050 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1051 return ''.join(result)
1052
1053def format_packet(pkt):
1054 return "Packet length %d \n%s" % (len(str(pkt)),
1055 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001056
1057def inspect_packet(pkt):
1058 """
1059 Wrapper around scapy's show() method.
1060 @returns A string showing the dissected packet.
1061 """
1062 from cStringIO import StringIO
1063 out = None
1064 backup = sys.stdout
1065 try:
1066 sys.stdout = StringIO()
1067 pkt.show2()
1068 out = sys.stdout.getvalue()
1069 sys.stdout.close()
1070 finally:
1071 sys.stdout = backup
1072 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001073
1074def nonstandard(cls):
1075 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001076 Testcase decorator that marks the test as being non-standard.
1077 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001078 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001079 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001080 return cls
1081
1082def disabled(cls):
1083 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001084 Testcase decorator that marks the test as being disabled.
1085 These tests are not automatically added to the "standard" group or
1086 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001087 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001088 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001089 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001090
1091def group(name):
1092 """
1093 Testcase decorator that adds the test to a group.
1094 """
1095 def fn(cls):
1096 if not hasattr(cls, "_groups"):
1097 cls._groups = []
1098 cls._groups.append(name)
1099 return cls
1100 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001101
1102def version(ver):
1103 """
1104 Testcase decorator that specifies which versions of OpenFlow the test
1105 supports. The default is 1.0+. This decorator may only be used once.
1106
1107 Supported syntax:
1108 1.0 -> 1.0
1109 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1110 1.0+ -> 1.0, 1.1, 1.2, 1.3
1111 """
1112 versions = parse_version(ver)
1113 def fn(cls):
1114 cls._versions = versions
1115 return cls
1116 return fn
1117
1118def parse_version(ver):
1119 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1120 if re.match("^1\.\d+$", ver):
1121 versions = set([ver])
1122 elif re.match("^(1\.\d+)\+$", ver):
1123 if not ver[:-1] in allowed_versions:
1124 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1125 versions = set()
1126 if ver != "1.1+": versions.add("1.0")
1127 if ver != "1.2+": versions.add("1.1")
1128 if ver != "1.3+": versions.add("1.2")
1129 versions.add("1.3")
1130 else:
1131 versions = set(ver.split(','))
1132
1133 for version in versions:
1134 if not version in allowed_versions:
1135 raise ValueError("invalid OpenFlow version %s" % version)
1136
1137 return versions
1138
1139assert(parse_version("1.0") == set(["1.0"]))
1140assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1141assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001142
Rich Laneae3428c2013-03-07 14:37:42 -08001143def get_stats(test, req):
1144 """
1145 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1146 """
1147 stats = []
1148 reply, _ = test.controller.transact(req)
1149 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001150 stats.extend(reply.entries)
Rich Lanee717c6e2013-03-12 10:25:50 -07001151 while reply.flags & ofp.OFPSF_REPLY_MORE != 0:
1152 reply, pkt = self.controller.poll(exp_msg=ofp.OFPT_STATS_REPLY)
Rich Laneae3428c2013-03-07 14:37:42 -08001153 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001154 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001155 return stats
1156
Rich Lanef3bc48c2013-05-03 17:39:35 -07001157def get_flow_stats(test, match, table_id=0xff, out_port=None):
Rich Laneae3428c2013-03-07 14:37:42 -08001158 """
1159 Retrieve a list of flow stats entries.
1160 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001161 if out_port == None:
1162 out_port = ofp.OFPP_NONE
Rich Lanee717c6e2013-03-12 10:25:50 -07001163 req = ofp.message.flow_stats_request(match=match,
Rich Laneae3428c2013-03-07 14:37:42 -08001164 table_id=table_id,
1165 out_port=out_port)
1166 return get_stats(test, req)
1167
Rich Lane968b6192013-03-07 15:34:43 -08001168def get_port_stats(test, port_no):
1169 """
1170 Retrieve a list of port stats entries.
1171 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001172 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001173 return get_stats(test, req)
1174
Rich Lane6a334922013-03-07 16:14:52 -08001175def get_queue_stats(test, port_no, queue_id):
1176 """
1177 Retrieve a list of queue stats entries.
1178 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001179 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001180 return get_stats(test, req)
1181
Rich Laneae3428c2013-03-07 14:37:42 -08001182def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001183 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001184 initial=[],
1185 pkts=None, bytes=None):
1186 """
1187 Verify that flow stats changed as expected.
1188
1189 Optionally takes an 'initial' list of stats entries, as returned by
1190 get_flow_stats(). If 'initial' is not given the counters are assumed to
1191 begin at 0.
1192 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001193 if out_port == None:
1194 out_port = ofp.OFPP_NONE
1195
Rich Laneae3428c2013-03-07 14:37:42 -08001196 def accumulate(stats):
1197 pkts_acc = bytes_acc = 0
1198 for stat in stats:
1199 pkts_acc += stat.packet_count
1200 bytes_acc += stat.byte_count
1201 return (pkts_acc, bytes_acc)
1202
1203 pkts_before, bytes_before = accumulate(initial)
1204
1205 # Wait 10s for counters to update
1206 pkt_diff = byte_diff = None
1207 for i in range(0, 100):
1208 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1209 pkts_after, bytes_after = accumulate(stats)
1210 pkt_diff = pkts_after - pkts_before
1211 byte_diff = bytes_after - bytes_before
1212 if (pkts == None or pkt_diff >= pkts) and \
1213 (bytes == None or byte_diff >= bytes):
1214 break
Dan Talayco53724732013-03-08 23:54:02 -08001215 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001216
1217 if pkts != None:
1218 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1219
1220 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001221 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1222 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001223
Rich Lane968b6192013-03-07 15:34:43 -08001224def verify_port_stats(test, port,
1225 initial=[],
1226 tx_pkts=None, rx_pkts=None,
1227 tx_bytes=None, rx_bytes=None):
1228 """
1229 Verify that port stats changed as expected.
1230
1231 Optionally takes an 'initial' list of stats entries, as returned by
1232 get_port_stats(). If 'initial' is not given the counters are assumed to
1233 begin at 0.
1234 """
1235 def accumulate(stats):
1236 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1237 for stat in stats:
1238 tx_pkts_acc += stat.tx_packets
1239 rx_pkts_acc += stat.rx_packets
1240 tx_bytes_acc += stat.tx_bytes
1241 rx_bytes_acc += stat.rx_bytes
1242 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1243
1244 tx_pkts_before, rx_pkts_before, \
1245 tx_bytes_before, rx_bytes_before = accumulate(initial)
1246
1247 # Wait 10s for counters to update
1248 for i in range(0, 100):
1249 stats = get_port_stats(test, port)
1250 tx_pkts_after, rx_pkts_after, \
1251 tx_bytes_after, rx_bytes_after = accumulate(stats)
1252 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1253 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1254 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1255 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1256 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1257 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001258 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1259 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001260 break
1261 time.sleep(0.1)
1262
1263 if (tx_pkts != None):
1264 test.assertEqual(tx_pkts,tx_pkts_diff,"Port TX packet counter is not updated correctly (expected increase of %d, got increase of %d)" % (tx_pkts, tx_pkts_diff))
1265 if (rx_pkts != None):
1266 test.assertEqual(rx_pkts,rx_pkts_diff,"Port RX packet counter is not updated correctly (expected increase of %d, got increase of %d)" % (rx_pkts, rx_pkts_diff))
1267 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001268 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1269 "Port TX byte counter is not updated correctly (expected increase of %d, got increase of %d)" % (tx_bytes, tx_bytes_diff))
Rich Lane968b6192013-03-07 15:34:43 -08001270 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001271 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1272 "Port RX byte counter is not updated correctly (expected increase of %d, got increase of %d)" % (rx_bytes, rx_bytes_diff))
Rich Lane968b6192013-03-07 15:34:43 -08001273
Rich Lane6a334922013-03-07 16:14:52 -08001274def verify_queue_stats(test, port_no, queue_id,
1275 initial=[],
1276 pkts=None, bytes=None):
1277 """
1278 Verify that queue stats changed as expected.
1279
1280 Optionally takes an 'initial' list of stats entries, as returned by
1281 get_queue_stats(). If 'initial' is not given the counters are assumed to
1282 begin at 0.
1283 """
1284 def accumulate(stats):
1285 pkts_acc = bytes_acc = 0
1286 for stat in stats:
1287 pkts_acc += stat.tx_packets
1288 bytes_acc += stat.tx_bytes
1289 return (pkts_acc, bytes_acc)
1290
1291 pkts_before, bytes_before = accumulate(initial)
1292
1293 # Wait 10s for counters to update
1294 pkt_diff = byte_diff = None
1295 for i in range(0, 100):
1296 stats = get_queue_stats(test, port_no, queue_id)
1297 pkts_after, bytes_after = accumulate(stats)
1298 pkt_diff = pkts_after - pkts_before
1299 byte_diff = bytes_after - bytes_before
1300 if (pkts == None or pkt_diff >= pkts) and \
1301 (bytes == None or byte_diff >= bytes):
1302 break
Dan Talayco53724732013-03-08 23:54:02 -08001303 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001304
1305 if pkts != None:
1306 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1307
1308 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001309 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1310 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001311
Rich Lane4c504f32013-06-07 17:24:14 -07001312def packet_in_match(msg, data, in_port=None, reason=None):
1313 """
1314 Check whether the packet_in message 'msg' has fields matching 'data',
1315 'in_port', and 'reason'.
1316
1317 This function handles truncated packet_in data. The 'in_port' and 'reason'
1318 parameters are optional.
1319
1320 @param msg packet_in message
1321 @param data Expected packet_in data
1322 @param in_port Expected packet_in in_port, or None
1323 @param reason Expected packet_in reason, or None
1324 """
1325
1326 if in_port and in_port != msg.in_port:
1327 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, msg.in_port)
1328 return False
1329
1330 if reason and reason != msg.reason:
1331 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1332 return False
1333
1334 # Check that one of the packets is a prefix of the other.
1335 # The received packet may be either truncated or padded, but not both.
1336 # (Some of the padding may be truncated but that's irrelevant). We
1337 # need to check that the smaller packet is a prefix of the larger one.
1338 # Note that this check succeeds if the switch sends a zero-length
1339 # packet-in.
1340 compare_len = min(len(msg.data), len(data))
1341 if data[:compare_len] != msg.data[:compare_len]:
1342 logging.debug("Incorrect packet_in data")
1343 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1344 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1345 return False
1346
1347 return True
1348
1349def verify_packet_in(test, data, in_port, reason, controller=None):
1350 """
1351 Assert that the controller receives a packet_in message matching data 'data'
1352 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1353 itself, that's up to the test case.
1354
1355 @param test Instance of base_tests.SimpleProtocol
1356 @param pkt String to expect as the packet_in data
1357 @param in_port OpenFlow port number to expect as the packet_in in_port
1358 @param reason One of OFPR_* to expect as the packet_in reason
1359 @param controller Controller instance, defaults to test.controller
1360 @returns The received packet-in message
1361 """
1362
1363 if controller == None:
1364 controller = test.controller
1365
1366 end_time = time.time() + oftest.ofutils.default_timeout
1367
1368 while True:
1369 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1370 if not msg:
1371 # Timeout
1372 break
1373 elif packet_in_match(msg, data, in_port, reason):
1374 # Found a matching message
1375 break
1376
1377 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1378 return msg
1379
1380def verify_no_packet_in(test, data, in_port, controller=None):
1381 """
1382 Assert that the controller does not receive a packet_in message matching
1383 data 'data' from port 'in_port'.
1384
1385 @param test Instance of base_tests.SimpleProtocol
1386 @param pkt String to expect as the packet_in data
1387 @param in_port OpenFlow port number to expect as the packet_in in_port
1388 @param controller Controller instance, defaults to test.controller
1389 """
1390
1391 if controller == None:
1392 controller = test.controller
1393
1394 # Negative test, need to wait a short amount of time before checking we
1395 # didn't receive the message.
1396 time.sleep(0.5)
1397
1398 # Check every packet_in queued in the controller
1399 while True:
1400 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1401 if msg == None:
1402 # No more queued packet_in messages
1403 break
1404 elif packet_in_match(msg, data, in_port, None):
1405 # Found a matching message
1406 break
1407
1408 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
1409
Rich Lane7744e112013-01-11 17:23:57 -08001410__all__ = list(set(locals()) - _import_blacklist)