blob: 40b24ede78804340300bc22a8d2e68bb698c2494 [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 Lane32bf9482013-01-03 17:26:30 -080047 return 0 # for backwards compatibility
Dan Talayco41eae8b2010-03-10 13:57:06 -080048
Ed Swierk99a74de2012-08-22 06:40:54 -070049def required_wildcards(parent):
Rich Lane2014f9b2012-10-05 15:29:40 -070050 w = test_param_get('required_wildcards', default='default')
Ed Swierk99a74de2012-08-22 06:40:54 -070051 if w == 'l3-l4':
Rich Lanee717c6e2013-03-12 10:25:50 -070052 return (ofp.OFPFW_NW_SRC_ALL | ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS
53 | ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST)
Ed Swierk99a74de2012-08-22 06:40:54 -070054 else:
55 return 0
56
Dan Talayco41eae8b2010-03-10 13:57:06 -080057def simple_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -070058 eth_dst='00:01:02:03:04:05',
59 eth_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070060 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -070061 vlan_vid=0,
62 vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070063 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080064 ip_src='192.168.0.1',
65 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070066 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -080067 ip_ttl=64,
Dan Talayco41eae8b2010-03-10 13:57:06 -080068 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070069 tcp_dport=80,
70 ip_ihl=None,
71 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080072 ):
73 """
74 Return a simple dataplane TCP packet
75
76 Supports a few parameters:
77 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -070078 @param eth_dst Destinatino MAC
79 @param eth_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070080 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -070081 @param vlan_vid VLAN ID
82 @param vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080083 @param ip_src IP source
84 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070085 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -080086 @param ip_ttl IP TTL
Dan Talayco41eae8b2010-03-10 13:57:06 -080087 @param tcp_dport TCP destination port
88 @param ip_sport TCP source port
89
90 Generates a simple TCP request. Users
91 shouldn't assume anything about this packet other than that
92 it is a valid ethernet/IP/TCP frame.
93 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000094
95 if MINSIZE > pktlen:
96 pktlen = MINSIZE
97
Dan Talayco551befa2010-07-15 17:05:32 -070098 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -080099 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700100 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
101 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800102 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700103 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
104 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700105 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700106 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800107 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700108 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
109 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700110 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800111 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 -0700112 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700113
Dan Talayco41eae8b2010-03-10 13:57:06 -0800114 pkt = pkt/("D" * (pktlen - len(pkt)))
115
116 return pkt
117
Rich Lane6ee7bea2012-10-26 16:19:29 -0700118def simple_udp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700119 eth_dst='00:01:02:03:04:05',
120 eth_src='00:06:07:08:09:0a',
Rich Lane6ee7bea2012-10-26 16:19:29 -0700121 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700122 vlan_vid=0,
123 vlan_pcp=0,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700124 dl_vlan_cfi=0,
125 ip_src='192.168.0.1',
126 ip_dst='192.168.0.2',
127 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800128 ip_ttl=64,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700129 udp_sport=1234,
130 udp_dport=80,
131 ip_ihl=None,
132 ip_options=False
133 ):
134 """
135 Return a simple dataplane UDP packet
136
137 Supports a few parameters:
138 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700139 @param eth_dst Destination MAC
140 @param eth_src Source MAC
Rich Lane6ee7bea2012-10-26 16:19:29 -0700141 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700142 @param vlan_vid VLAN ID
143 @param vlan_pcp VLAN priority
Rich Lane6ee7bea2012-10-26 16:19:29 -0700144 @param ip_src IP source
145 @param ip_dst IP destination
146 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800147 @param ip_ttl IP TTL
Rich Lane6ee7bea2012-10-26 16:19:29 -0700148 @param udp_dport UDP destination port
149 @param udp_sport UDP source port
150
151 Generates a simple UDP packet. Users shouldn't assume anything about
152 this packet other than that it is a valid ethernet/IP/UDP frame.
153 """
154
155 if MINSIZE > pktlen:
156 pktlen = MINSIZE
157
158 # Note Dot1Q.id is really CFI
159 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700160 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
161 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800162 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700163 scapy.UDP(sport=udp_sport, dport=udp_dport)
164 else:
165 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700166 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800167 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700168 scapy.UDP(sport=udp_sport, dport=udp_dport)
169 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700170 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800171 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 -0700172 scapy.UDP(sport=udp_sport, dport=udp_dport)
173
174 pkt = pkt/("D" * (pktlen - len(pkt)))
175
176 return pkt
177
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700178def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700179 eth_dst='00:01:02:03:04:05',
180 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700181 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700182 vlan_vid=0,
183 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700184 ip_src='192.168.0.1',
185 ip_dst='192.168.0.2',
186 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800187 ip_ttl=64,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700188 icmp_type=8,
189 icmp_code=0
190 ):
191 """
192 Return a simple ICMP packet
193
194 Supports a few parameters:
195 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700196 @param eth_dst Destinatino MAC
197 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700198 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700199 @param vlan_vid VLAN ID
200 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700201 @param ip_src IP source
202 @param ip_dst IP destination
203 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800204 @param ip_ttl IP TTL
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700205 @param icmp_type ICMP type
206 @param icmp_code ICMP code
207
208 Generates a simple ICMP ECHO REQUEST. Users
209 shouldn't assume anything about this packet other than that
210 it is a valid ethernet/ICMP frame.
211 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000212
213 if MINSIZE > pktlen:
214 pktlen = MINSIZE
215
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700216 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700217 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
218 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800219 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700220 scapy.ICMP(type=icmp_type, code=icmp_code)
221 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700222 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800223 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700224 scapy.ICMP(type=icmp_type, code=icmp_code)
225
226 pkt = pkt/("0" * (pktlen - len(pkt)))
227
228 return pkt
229
Shudong Zhouc7562b12013-02-06 01:12:18 -0800230def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700231 eth_dst='ff:ff:ff:ff:ff:ff',
232 eth_src='00:06:07:08:09:0a',
Shudong Zhouc7562b12013-02-06 01:12:18 -0800233 arp_op=1,
234 ip_snd='192.168.0.1',
235 ip_tgt='192.168.0.2',
236 hw_snd='00:06:07:08:09:0a',
237 hw_tgt='00:00:00:00:00:00',
238 ):
239 """
240 Return a simple ARP packet
241
242 Supports a few parameters:
243 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700244 @param eth_dst Destinatino MAC
245 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800246 @param arp_op Operation (1=request, 2=reply)
247 @param ip_snd Sender IP
248 @param ip_tgt Target IP
249 @param hw_snd Sender hardware address
250 @param hw_tgt Target hardware address
251
252 Generates a simple ARP REQUEST. Users
253 shouldn't assume anything about this packet other than that
254 it is a valid ethernet/ARP frame.
255 """
256
257 if MINSIZE > pktlen:
258 pktlen = MINSIZE
259
Rich Laned0478ff2013-03-11 12:46:58 -0700260 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhouc7562b12013-02-06 01:12:18 -0800261 scapy.ARP(hwsrc=hw_snd, hwdst=hw_tgt, pdst=ip_tgt, psrc=ip_snd, op=arp_op)
262
263 pkt = pkt/("0" * (pktlen - len(pkt)))
264
265 return pkt
266
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700267def simple_eth_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700268 eth_dst='00:01:02:03:04:05',
269 eth_src='01:80:c2:00:00:00',
270 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000271
272 if MINSIZE > pktlen:
273 pktlen = MINSIZE
274
Rich Laned0478ff2013-03-11 12:46:58 -0700275 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700276
277 pkt = pkt/("0" * (pktlen - len(pkt)))
278
279 return pkt
280
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800281def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700282 eth_dst='00:01:02:03:04:05',
283 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800284 dl_vlan_outer=20,
285 dl_vlan_pcp_outer=0,
286 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700287 vlan_vid=10,
288 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800289 dl_vlan_cfi=0,
290 ip_src='192.168.0.1',
291 ip_dst='192.168.0.2',
292 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800293 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800294 tcp_sport=1234,
295 tcp_dport=80,
296 ip_ihl=None,
297 ip_options=False
298 ):
299 """
300 Return a doubly tagged dataplane TCP packet
301
302 Supports a few parameters:
303 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700304 @param eth_dst Destinatino MAC
305 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800306 @param dl_vlan_outer Outer VLAN ID
307 @param dl_vlan_pcp_outer Outer VLAN priority
308 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700309 @param vlan_vid Inner VLAN ID
310 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800311 @param dl_vlan_cfi VLAN cfi bit
312 @param ip_src IP source
313 @param ip_dst IP destination
314 @param ip_tos IP ToS
315 @param tcp_dport TCP destination port
316 @param ip_sport TCP source port
317
318 Generates a TCP request. Users
319 shouldn't assume anything about this packet other than that
320 it is a valid ethernet/IP/TCP frame.
321 """
322
323 if MINSIZE > pktlen:
324 pktlen = MINSIZE
325
326 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700327 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800328 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700329 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800330 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800331 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
332
333 pkt = pkt/("D" * (pktlen - len(pkt)))
334
335 return pkt
336
Shudong Zhoub7f12462012-11-20 13:01:12 -0800337def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700338 """
339 Do a barrier command
340 Return 0 on success, -1 on error
341 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700342 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800343 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800344 if resp is None:
345 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700346 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800347 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700348
Rich Lane9a003812012-10-04 17:17:59 -0700349def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700350 """
351 Get a port's configuration
352
353 Gets the switch feature configuration and grabs one port's
354 configuration
355
356 @returns (hwaddr, config, advert) The hwaddress, configuration and
357 advertised values
358 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700359 request = ofp.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700360 reply, pkt = controller.transact(request)
Rich Lane9a003812012-10-04 17:17:59 -0700361 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700362 if reply is None:
Rich Lane9a003812012-10-04 17:17:59 -0700363 logging.warn("Get feature request failed")
Dan Talayco92c99122010-06-03 13:53:18 -0700364 return None, None, None
365 for idx in range(len(reply.ports)):
366 if reply.ports[idx].port_no == port_no:
367 return (reply.ports[idx].hw_addr, reply.ports[idx].config,
368 reply.ports[idx].advertised)
369
Rich Lane9a003812012-10-04 17:17:59 -0700370 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700371 return None, None, None
372
Rich Lane9a003812012-10-04 17:17:59 -0700373def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700374 """
375 Set the port configuration according the given parameters
376
377 Gets the switch feature configuration and updates one port's
378 configuration value according to config and mask
379 """
Rich Lane9a003812012-10-04 17:17:59 -0700380 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lanee717c6e2013-03-12 10:25:50 -0700381 request = ofp.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700382 reply, pkt = controller.transact(request)
Dan Talayco92c99122010-06-03 13:53:18 -0700383 if reply is None:
384 return -1
Rich Lane9a003812012-10-04 17:17:59 -0700385 logging.debug(reply.show())
Ed Swierk8d84ce02012-12-27 15:36:48 -0800386 p = None
Dan Talayco92c99122010-06-03 13:53:18 -0700387 for idx in range(len(reply.ports)):
388 if reply.ports[idx].port_no == port_no:
Ed Swierk8d84ce02012-12-27 15:36:48 -0800389 p = reply.ports[idx]
Dan Talayco92c99122010-06-03 13:53:18 -0700390 break
Rich Lanee717c6e2013-03-12 10:25:50 -0700391 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700392 mod.port_no = port_no
Ed Swierk8d84ce02012-12-27 15:36:48 -0800393 if p:
394 mod.hw_addr = p.hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700395 mod.config = config
396 mod.mask = mask
Ed Swierk8d84ce02012-12-27 15:36:48 -0800397 if p:
398 mod.advertise = p.advertised
Rich Lane5c3151c2013-01-03 17:15:41 -0800399 controller.message_send(mod)
400 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700401
Rich Lane2014f9b2012-10-05 15:29:40 -0700402def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700403 """
404 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700405 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700406 @param pkt Expected packet; may be None if yes_ports is empty
407 @param yes_ports Set or list of ports that should recieve packet
408 @param no_ports Set or list of ports that should not receive packet
409 @param assert_if Object that implements assertXXX
410 """
Rich Lane91765672012-12-06 16:33:04 -0800411
412 # Wait this long for packets that we don't expect to receive.
413 # 100ms is (rarely) too short for positive tests on slow
414 # switches but is definitely not too short for a negative test.
415 negative_timeout = 0.1
416
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700417 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800418 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700419 exp_pkt_arg = pkt
420
Dan Talayco92c99122010-06-03 13:53:18 -0700421 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700422 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700423 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700424 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700425 assert_if.assertTrue(rcv_pkt is not None,
426 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800427 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800428 logging.debug("Expected %s" % format_packet(pkt))
429 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800430 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800431 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700432 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700433 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800434 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700435 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700436 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700437 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800438 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700439 assert_if.assertTrue(rcv_pkt is None,
440 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700441
442
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700443def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700444 """
445 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700446 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700447
448 parent must implement dataplane, assertTrue and assertEqual
449 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700450 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800451 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700452 exp_pkt_arg = exp_pkt
453
Dan Talaycof6e76c02012-03-23 10:56:12 -0700454 if type(egr_ports) == type([]):
455 egr_port_list = egr_ports
456 else:
457 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700458
Dan Talaycof6e76c02012-03-23 10:56:12 -0700459 # Expect a packet from each port on egr port list
460 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700461 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700462 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700463 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700464 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700465 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700466
Dan Talaycof6e76c02012-03-23 10:56:12 -0700467 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700468 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700469 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700470
Dan Talaycof6e76c02012-03-23 10:56:12 -0700471 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700472 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700473 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700474 str(rcv_port))
475
476 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700477 logging.error("ERROR: Packet match failed.")
478 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700479 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700480 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700481 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700482 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
483 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700484 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700485 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700486
Dan Talayco551befa2010-07-15 17:05:32 -0700487def match_verify(parent, req_match, res_match):
488 """
489 Verify flow matches agree; if they disagree, report where
490
491 parent must implement assertEqual
492 Use str() to ensure content is compared and not pointers
493 """
494
495 parent.assertEqual(req_match.wildcards, res_match.wildcards,
496 'Match failed: wildcards: ' + hex(req_match.wildcards) +
497 " != " + hex(res_match.wildcards))
498 parent.assertEqual(req_match.in_port, res_match.in_port,
499 'Match failed: in_port: ' + str(req_match.in_port) +
500 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700501 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
502 'Match failed: eth_src: ' + str(req_match.eth_src) +
503 " != " + str(res_match.eth_src))
504 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
505 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
506 " != " + str(res_match.eth_dst))
507 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
508 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
509 " != " + str(res_match.vlan_vid))
510 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
511 'Match failed: vlan_pcp: ' +
512 str(req_match.vlan_pcp) + " != " +
513 str(res_match.vlan_pcp))
514 parent.assertEqual(req_match.eth_type, res_match.eth_type,
515 'Match failed: eth_type: ' + str(req_match.eth_type) +
516 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700517
Rich Lanee717c6e2013-03-12 10:25:50 -0700518 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700519 and (req_match.eth_type == IP_ETHERTYPE)):
520 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
521 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
522 " != " + str(res_match.ip_dscp))
523 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
524 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
525 " != " + str(res_match.ip_proto))
526 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
527 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
528 " != " + str(res_match.ipv4_src))
529 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
530 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
531 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700532
Rich Lanee717c6e2013-03-12 10:25:50 -0700533 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700534 and ((req_match.ip_proto == TCP_PROTOCOL)
535 or (req_match.ip_proto == UDP_PROTOCOL))):
536 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
537 'Match failed: tcp_src: ' +
538 str(req_match.tcp_src) +
539 " != " + str(res_match.tcp_src))
540 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
541 'Match failed: tcp_dst: ' +
542 str(req_match.tcp_dst) +
543 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700544
Ed Swierk99a74de2012-08-22 06:40:54 -0700545def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700546 match = oftest.parse.packet_to_flow_match(packet)
Ed Swierk99a74de2012-08-22 06:40:54 -0700547 match.wildcards |= required_wildcards(parent)
548 return match
549
550def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700551 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700552 """
553 Create a flow message
554
555 Match on packet with given wildcards.
556 See flow_match_test for other parameter descriptoins
557 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700558 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700559 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700560 """
Rich Lanef6883512013-03-11 17:00:09 -0700561 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700562 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700563 if wildcards is None:
564 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700565 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700566 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700567 match.wildcards = wildcards
568 match.in_port = ing_port
569
Dan Talaycof6e76c02012-03-23 10:56:12 -0700570 if type(egr_ports) == type([]):
571 egr_port_list = egr_ports
572 else:
573 egr_port_list = [egr_ports]
574
Rich Lanee717c6e2013-03-12 10:25:50 -0700575 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700576 request.match = match
577 request.buffer_id = 0xffffffff
578 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700579 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700580 request.hard_timeout = 1
581
582 if action_list is not None:
583 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700584 logging.debug("Adding action " + act.show())
Rich Lanec495d9e2013-03-08 17:43:36 -0800585 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700586
587 # Set up output/enqueue action if directed
588 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700589 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700590 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700591 for egr_port in egr_port_list:
592 act.port = egr_port
593 act.queue_id = egr_queue
Rich Lanec495d9e2013-03-08 17:43:36 -0800594 request.actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700595 elif egr_ports is not None:
596 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700597 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700598 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800599 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700600
Rich Lane9a003812012-10-04 17:17:59 -0700601 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700602
603 return request
604
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700605def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700606 """
607 Install a flow mod message in the switch
608
609 @param parent Must implement controller, assertEqual, assertTrue
610 @param request The request, all set to go
611 @param clear_table If true, clear the flow table before installing
612 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700613
Rich Lane2014f9b2012-10-05 15:29:40 -0700614 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700615 if(clear_table_override != None):
616 clear_table = clear_table_override
617
618 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700619 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800620 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700621
Rich Lane9a003812012-10-04 17:17:59 -0700622 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800623 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800624
Rich Lane3a261d52013-01-03 17:45:08 -0800625 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700626
Ed Swierk99a74de2012-08-22 06:40:54 -0700627def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700628 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700629 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700630 """
631 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700632 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700633
634 Run test with packet through switch from ing_port to egr_port
635 See flow_match_test for parameter descriptions
636 """
637
Ed Swierk99a74de2012-08-22 06:40:54 -0700638 if wildcards is None:
639 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700640 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700641 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700642 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700643 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700644 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Dan Talayco551befa2010-07-15 17:05:32 -0700645
646 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700647 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700648 action_list=action_list)
649
650 flow_msg_install(parent, request)
651
Rich Lane9a003812012-10-04 17:17:59 -0700652 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700653 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700654 parent.dataplane.send(ing_port, str(pkt))
655
656 if exp_pkt is None:
657 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700658 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700659
Rich Lane89725bb2012-12-03 16:23:27 -0800660def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700661 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800662 action_list=None):
663 """
664 Packet-out test on single TCP packet
665 @param egr_ports A single port or list of ports
666
667 Run test sending packet-out to egr_ports. The goal is to test the actions
668 taken on the packet, not the matching which is of course irrelevant.
669 See flow_match_test for parameter descriptions
670 """
671
672 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700673 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lane89725bb2012-12-03 16:23:27 -0800674
Rich Lanee717c6e2013-03-12 10:25:50 -0700675 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800676 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700677 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800678 msg.data = str(pkt)
679 if action_list is not None:
680 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800681 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800682
683 # Set up output action
684 if egr_ports is not None:
685 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700686 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800687 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800688 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800689
690 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800691 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800692
693 if exp_pkt is None:
694 exp_pkt = pkt
695 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
696
Dan Talaycof6e76c02012-03-23 10:56:12 -0700697def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
698 """
699 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700700 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700701 @param of_ports List of OF port numbers
702 @param how_many Number of ports to be added to the list
703 @param exclude_list List of ports not to be used
704 @returns An empty list if unable to find enough ports
705 """
706
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700707 if how_many == 0:
708 return []
709
Dan Talaycof6e76c02012-03-23 10:56:12 -0700710 count = 0
711 egr_ports = []
712 for egr_idx in range(len(of_ports)):
713 if of_ports[egr_idx] not in exclude_list:
714 egr_ports.append(of_ports[egr_idx])
715 count += 1
716 if count >= how_many:
717 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700718 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700719 return []
720
Rich Laned0478ff2013-03-11 12:46:58 -0700721def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700722 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700723 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700724 """
Rich Lane89725bb2012-12-03 16:23:27 -0800725 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700726
727 @param max_test If > 0 no more than this number of tests are executed.
728 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700729 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700730 @param pkt If not None, use this packet for ingress
731 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700732 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700733 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
734 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700735 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700736 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700737 if wildcards is None:
738 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700739 of_ports = port_map.keys()
740 of_ports.sort()
741 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
742 test_count = 0
743
Dan Talaycocfa172f2012-03-23 12:03:00 -0700744 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700745 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700746
Dan Talayco551befa2010-07-15 17:05:32 -0700747 for ing_idx in range(len(of_ports)):
748 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700749 egr_ports = get_egr_list(parent, of_ports, egr_count,
750 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700751 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700752 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700753 if len(egr_ports) == 0:
754 parent.assertTrue(0, "Failed to generate egress port list")
755
756 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700757 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700758 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700759 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700760 test_count += 1
761 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700762 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800763 break
764
Ed Swierk38eea082013-01-02 19:46:20 -0800765 if not test_param_get('pktout_actions', default=True):
766 return
Rich Lane89725bb2012-12-03 16:23:27 -0800767
768 ingress_port = of_ports[0]
769 egr_ports = get_egr_list(parent, of_ports, egr_count,
770 exclude_list=[ingress_port])
771 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700772 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800773 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700774 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800775 pkt=pkt, exp_pkt=exp_pkt,
776 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700777
Rich Lane2014f9b2012-10-05 15:29:40 -0700778def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700779 """
780 Return value passed via test-params if present
781
Dan Talayco4b2bee62010-07-20 14:10:05 -0700782 @param key The lookup key
783 @param default Default value to use if not found
784
785 If the pair 'key=val' appeared in the string passed to --test-params
786 on the command line, return val (as interpreted by exec). Otherwise
787 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700788
789 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
790 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700791 """
792 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800793 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700794 except:
795 return default
796
797 s = "val = " + str(key)
798 try:
799 exec s
800 return val
801 except:
802 return default
803
804def action_generate(parent, field_to_mod, mod_field_vals):
805 """
806 Create an action to modify the field indicated in field_to_mod
807
808 @param parent Must implement, assertTrue
809 @param field_to_mod The field to modify as a string name
810 @param mod_field_vals Hash of values to use for modified values
811 """
812
813 act = None
814
815 if field_to_mod in ['pktlen']:
816 return None
817
Rich Laned0478ff2013-03-11 12:46:58 -0700818 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700819 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700820 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700821 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700822 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700823 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700824 elif field_to_mod == 'dl_vlan_enable':
825 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -0700826 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -0700827 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -0700828 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -0700829 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -0700830 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -0700831 act.vlan_vid = mod_field_vals['vlan_vid']
832 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -0700833 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -0700834 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700835 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700836 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -0700837 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700838 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700839 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700840 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700841 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -0700842 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700843 act.nw_tos = mod_field_vals['ip_tos']
844 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700845 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700846 act.tp_port = mod_field_vals['tcp_sport']
847 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700848 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700849 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700850 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700851 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -0700852 act.tp_port = mod_field_vals['udp_sport']
853 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700854 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -0700855 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700856 else:
857 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
858
859 return act
860
861def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -0700862 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700863 """
864 Set up the ingress and expected packet and action list for a test
865
Rich Lane2014f9b2012-10-05 15:29:40 -0700866 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700867 @param start_field_values Field values to use for ingress packet (optional)
868 @param mod_field_values Field values to use for modified packet (optional)
869 @param mod_fields The list of fields to be modified by the switch in the test.
870 @params check_test_params If True, will check the parameters vid, add_vlan
871 and strip_vlan from the command line.
872
873 Returns a triple: pkt-to-send, expected-pkt, action-list
874 """
875
876 new_actions = []
877
Dan Talayco4b2bee62010-07-20 14:10:05 -0700878 base_pkt_params = {}
879 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -0700880 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
881 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -0700882 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -0700883 base_pkt_params['vlan_vid'] = 2
884 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -0700885 base_pkt_params['ip_src'] = '192.168.0.1'
886 base_pkt_params['ip_dst'] = '192.168.0.2'
887 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -0700888 if tp == "tcp":
889 base_pkt_params['tcp_sport'] = 1234
890 base_pkt_params['tcp_dport'] = 80
891 elif tp == "udp":
892 base_pkt_params['udp_sport'] = 1234
893 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -0700894 for keyname in start_field_vals.keys():
895 base_pkt_params[keyname] = start_field_vals[keyname]
896
897 mod_pkt_params = {}
898 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -0700899 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
900 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -0700901 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -0700902 mod_pkt_params['vlan_vid'] = 3
903 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -0700904 mod_pkt_params['ip_src'] = '10.20.30.40'
905 mod_pkt_params['ip_dst'] = '50.60.70.80'
906 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -0700907 if tp == "tcp":
908 mod_pkt_params['tcp_sport'] = 4321
909 mod_pkt_params['tcp_dport'] = 8765
910 elif tp == "udp":
911 mod_pkt_params['udp_sport'] = 4321
912 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -0700913 for keyname in mod_field_vals.keys():
914 mod_pkt_params[keyname] = mod_field_vals[keyname]
915
916 # Check for test param modifications
917 strip = False
918 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700919 add_vlan = test_param_get('add_vlan')
920 strip_vlan = test_param_get('strip_vlan')
921 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700922
923 if add_vlan and strip_vlan:
924 parent.assertTrue(0, "Add and strip VLAN both specified")
925
926 if vid:
927 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -0700928 base_pkt_params['vlan_vid'] = vid
929 if 'vlan_vid' in mod_fields:
930 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -0700931
932 if add_vlan:
933 base_pkt_params['dl_vlan_enable'] = False
934 mod_pkt_params['dl_vlan_enable'] = True
935 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
936 mod_fields.append('pktlen')
937 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -0700938 if 'vlan_vid' not in mod_fields:
939 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700940 elif strip_vlan:
941 base_pkt_params['dl_vlan_enable'] = True
942 mod_pkt_params['dl_vlan_enable'] = False
943 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
944 mod_fields.append('dl_vlan_enable')
945 mod_fields.append('pktlen')
946
Rich Lane110e0e32012-10-26 16:21:46 -0700947 if tp == "tcp":
948 packet_builder = simple_tcp_packet
949 elif tp == "udp":
950 packet_builder = simple_udp_packet
951 else:
952 raise NotImplementedError("unknown transport protocol %s" % tp)
953
Dan Talayco4b2bee62010-07-20 14:10:05 -0700954 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -0700955 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700956
957 # Build the expected packet, modifying the indicated fields
958 for item in mod_fields:
959 base_pkt_params[item] = mod_pkt_params[item]
960 act = action_generate(parent, item, mod_pkt_params)
961 if act:
962 new_actions.append(act)
963
Rich Lane110e0e32012-10-26 16:21:46 -0700964 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700965
966 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700967
968# Generate a simple "drop" flow mod
969# If in_band is true, then only drop from first test port
970def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -0700971 request = ofp.message.flow_add()
972 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -0700973 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700974 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -0700975 for of_port, ifname in port_map.items(): # Grab first port
976 break
977 request.match.in_port = of_port
978 request.buffer_id = 0xffffffff
979 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700980
981def skip_message_emit(parent, s):
982 """
983 Print out a 'skipped' message to stderr
984
985 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -0700986 """
987 global skipped_test_count
988
989 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -0700990 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -0800991 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700992 sys.stderr.write("(skipped) ")
993 else:
994 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -0700995
Dan Talayco8a64e332012-03-28 14:53:20 -0700996
997def all_stats_get(parent):
998 """
999 Get the aggregate stats for all flows in the table
1000 @param parent Test instance with controller connection and assert
1001 @returns dict with keys flows, packets, bytes, active (flows),
1002 lookups, matched
1003 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001004 stat_req = ofp.message.aggregate_stats_request()
1005 stat_req.match = ofp.match()
1006 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001007 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001008 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001009
1010 rv = {}
1011
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001012 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001013 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001014
Rich Lane5fd6faf2013-03-11 13:30:20 -07001015 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001016 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1017 obj.packet_count, obj.byte_count)
1018 break
1019
Rich Lanee717c6e2013-03-12 10:25:50 -07001020 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001021 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001022
1023
1024 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001025 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001026 rv["active"] += obj.active_count
1027 rv["lookups"] += obj.lookup_count
1028 rv["matched"] += obj.matched_count
1029
1030 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001031
Rich Lane7744e112013-01-11 17:23:57 -08001032_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001033FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1034 for x in range(256)])
1035
1036def hex_dump_buffer(src, length=16):
1037 """
1038 Convert src to a hex dump string and return the string
1039 @param src The source buffer
1040 @param length The number of bytes shown in each line
1041 @returns A string showing the hex dump
1042 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001043 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001044 for i in xrange(0, len(src), length):
1045 chars = src[i:i+length]
1046 hex = ' '.join(["%02x" % ord(x) for x in chars])
1047 printable = ''.join(["%s" % ((ord(x) <= 127 and
1048 FILTER[ord(x)]) or '.') for x in chars])
1049 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1050 return ''.join(result)
1051
1052def format_packet(pkt):
1053 return "Packet length %d \n%s" % (len(str(pkt)),
1054 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001055
1056def inspect_packet(pkt):
1057 """
1058 Wrapper around scapy's show() method.
1059 @returns A string showing the dissected packet.
1060 """
1061 from cStringIO import StringIO
1062 out = None
1063 backup = sys.stdout
1064 try:
1065 sys.stdout = StringIO()
1066 pkt.show2()
1067 out = sys.stdout.getvalue()
1068 sys.stdout.close()
1069 finally:
1070 sys.stdout = backup
1071 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001072
1073def nonstandard(cls):
1074 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001075 Testcase decorator that marks the test as being non-standard.
1076 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001077 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001078 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001079 return cls
1080
1081def disabled(cls):
1082 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001083 Testcase decorator that marks the test as being disabled.
1084 These tests are not automatically added to the "standard" group or
1085 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001086 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001087 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001088 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001089
1090def group(name):
1091 """
1092 Testcase decorator that adds the test to a group.
1093 """
1094 def fn(cls):
1095 if not hasattr(cls, "_groups"):
1096 cls._groups = []
1097 cls._groups.append(name)
1098 return cls
1099 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001100
1101def version(ver):
1102 """
1103 Testcase decorator that specifies which versions of OpenFlow the test
1104 supports. The default is 1.0+. This decorator may only be used once.
1105
1106 Supported syntax:
1107 1.0 -> 1.0
1108 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1109 1.0+ -> 1.0, 1.1, 1.2, 1.3
1110 """
1111 versions = parse_version(ver)
1112 def fn(cls):
1113 cls._versions = versions
1114 return cls
1115 return fn
1116
1117def parse_version(ver):
1118 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1119 if re.match("^1\.\d+$", ver):
1120 versions = set([ver])
1121 elif re.match("^(1\.\d+)\+$", ver):
1122 if not ver[:-1] in allowed_versions:
1123 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1124 versions = set()
1125 if ver != "1.1+": versions.add("1.0")
1126 if ver != "1.2+": versions.add("1.1")
1127 if ver != "1.3+": versions.add("1.2")
1128 versions.add("1.3")
1129 else:
1130 versions = set(ver.split(','))
1131
1132 for version in versions:
1133 if not version in allowed_versions:
1134 raise ValueError("invalid OpenFlow version %s" % version)
1135
1136 return versions
1137
1138assert(parse_version("1.0") == set(["1.0"]))
1139assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1140assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001141
Rich Laneae3428c2013-03-07 14:37:42 -08001142def get_stats(test, req):
1143 """
1144 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1145 """
1146 stats = []
1147 reply, _ = test.controller.transact(req)
1148 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001149 stats.extend(reply.entries)
Rich Lanee717c6e2013-03-12 10:25:50 -07001150 while reply.flags & ofp.OFPSF_REPLY_MORE != 0:
1151 reply, pkt = self.controller.poll(exp_msg=ofp.OFPT_STATS_REPLY)
Rich Laneae3428c2013-03-07 14:37:42 -08001152 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001153 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001154 return stats
1155
Rich Lanef3bc48c2013-05-03 17:39:35 -07001156def get_flow_stats(test, match, table_id=0xff, out_port=None):
Rich Laneae3428c2013-03-07 14:37:42 -08001157 """
1158 Retrieve a list of flow stats entries.
1159 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001160 if out_port == None:
1161 out_port = ofp.OFPP_NONE
Rich Lanee717c6e2013-03-12 10:25:50 -07001162 req = ofp.message.flow_stats_request(match=match,
Rich Laneae3428c2013-03-07 14:37:42 -08001163 table_id=table_id,
1164 out_port=out_port)
1165 return get_stats(test, req)
1166
Rich Lane968b6192013-03-07 15:34:43 -08001167def get_port_stats(test, port_no):
1168 """
1169 Retrieve a list of port stats entries.
1170 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001171 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001172 return get_stats(test, req)
1173
Rich Lane6a334922013-03-07 16:14:52 -08001174def get_queue_stats(test, port_no, queue_id):
1175 """
1176 Retrieve a list of queue stats entries.
1177 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001178 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001179 return get_stats(test, req)
1180
Rich Laneae3428c2013-03-07 14:37:42 -08001181def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001182 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001183 initial=[],
1184 pkts=None, bytes=None):
1185 """
1186 Verify that flow stats changed as expected.
1187
1188 Optionally takes an 'initial' list of stats entries, as returned by
1189 get_flow_stats(). If 'initial' is not given the counters are assumed to
1190 begin at 0.
1191 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001192 if out_port == None:
1193 out_port = ofp.OFPP_NONE
1194
Rich Laneae3428c2013-03-07 14:37:42 -08001195 def accumulate(stats):
1196 pkts_acc = bytes_acc = 0
1197 for stat in stats:
1198 pkts_acc += stat.packet_count
1199 bytes_acc += stat.byte_count
1200 return (pkts_acc, bytes_acc)
1201
1202 pkts_before, bytes_before = accumulate(initial)
1203
1204 # Wait 10s for counters to update
1205 pkt_diff = byte_diff = None
1206 for i in range(0, 100):
1207 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1208 pkts_after, bytes_after = accumulate(stats)
1209 pkt_diff = pkts_after - pkts_before
1210 byte_diff = bytes_after - bytes_before
1211 if (pkts == None or pkt_diff >= pkts) and \
1212 (bytes == None or byte_diff >= bytes):
1213 break
Dan Talayco53724732013-03-08 23:54:02 -08001214 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001215
1216 if pkts != None:
1217 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1218
1219 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001220 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1221 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001222
Rich Lane968b6192013-03-07 15:34:43 -08001223def verify_port_stats(test, port,
1224 initial=[],
1225 tx_pkts=None, rx_pkts=None,
1226 tx_bytes=None, rx_bytes=None):
1227 """
1228 Verify that port stats changed as expected.
1229
1230 Optionally takes an 'initial' list of stats entries, as returned by
1231 get_port_stats(). If 'initial' is not given the counters are assumed to
1232 begin at 0.
1233 """
1234 def accumulate(stats):
1235 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1236 for stat in stats:
1237 tx_pkts_acc += stat.tx_packets
1238 rx_pkts_acc += stat.rx_packets
1239 tx_bytes_acc += stat.tx_bytes
1240 rx_bytes_acc += stat.rx_bytes
1241 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1242
1243 tx_pkts_before, rx_pkts_before, \
1244 tx_bytes_before, rx_bytes_before = accumulate(initial)
1245
1246 # Wait 10s for counters to update
1247 for i in range(0, 100):
1248 stats = get_port_stats(test, port)
1249 tx_pkts_after, rx_pkts_after, \
1250 tx_bytes_after, rx_bytes_after = accumulate(stats)
1251 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1252 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1253 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1254 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1255 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1256 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001257 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1258 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001259 break
1260 time.sleep(0.1)
1261
1262 if (tx_pkts != None):
1263 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))
1264 if (rx_pkts != None):
1265 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))
1266 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001267 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1268 "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 -08001269 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001270 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1271 "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 -08001272
Rich Lane6a334922013-03-07 16:14:52 -08001273def verify_queue_stats(test, port_no, queue_id,
1274 initial=[],
1275 pkts=None, bytes=None):
1276 """
1277 Verify that queue stats changed as expected.
1278
1279 Optionally takes an 'initial' list of stats entries, as returned by
1280 get_queue_stats(). If 'initial' is not given the counters are assumed to
1281 begin at 0.
1282 """
1283 def accumulate(stats):
1284 pkts_acc = bytes_acc = 0
1285 for stat in stats:
1286 pkts_acc += stat.tx_packets
1287 bytes_acc += stat.tx_bytes
1288 return (pkts_acc, bytes_acc)
1289
1290 pkts_before, bytes_before = accumulate(initial)
1291
1292 # Wait 10s for counters to update
1293 pkt_diff = byte_diff = None
1294 for i in range(0, 100):
1295 stats = get_queue_stats(test, port_no, queue_id)
1296 pkts_after, bytes_after = accumulate(stats)
1297 pkt_diff = pkts_after - pkts_before
1298 byte_diff = bytes_after - bytes_before
1299 if (pkts == None or pkt_diff >= pkts) and \
1300 (bytes == None or byte_diff >= bytes):
1301 break
Dan Talayco53724732013-03-08 23:54:02 -08001302 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001303
1304 if pkts != None:
1305 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1306
1307 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001308 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1309 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001310
Rich Lane4c504f32013-06-07 17:24:14 -07001311def packet_in_match(msg, data, in_port=None, reason=None):
1312 """
1313 Check whether the packet_in message 'msg' has fields matching 'data',
1314 'in_port', and 'reason'.
1315
1316 This function handles truncated packet_in data. The 'in_port' and 'reason'
1317 parameters are optional.
1318
1319 @param msg packet_in message
1320 @param data Expected packet_in data
1321 @param in_port Expected packet_in in_port, or None
1322 @param reason Expected packet_in reason, or None
1323 """
1324
1325 if in_port and in_port != msg.in_port:
1326 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, msg.in_port)
1327 return False
1328
1329 if reason and reason != msg.reason:
1330 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1331 return False
1332
1333 # Check that one of the packets is a prefix of the other.
1334 # The received packet may be either truncated or padded, but not both.
1335 # (Some of the padding may be truncated but that's irrelevant). We
1336 # need to check that the smaller packet is a prefix of the larger one.
1337 # Note that this check succeeds if the switch sends a zero-length
1338 # packet-in.
1339 compare_len = min(len(msg.data), len(data))
1340 if data[:compare_len] != msg.data[:compare_len]:
1341 logging.debug("Incorrect packet_in data")
1342 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1343 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1344 return False
1345
1346 return True
1347
1348def verify_packet_in(test, data, in_port, reason, controller=None):
1349 """
1350 Assert that the controller receives a packet_in message matching data 'data'
1351 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1352 itself, that's up to the test case.
1353
1354 @param test Instance of base_tests.SimpleProtocol
1355 @param pkt String to expect as the packet_in data
1356 @param in_port OpenFlow port number to expect as the packet_in in_port
1357 @param reason One of OFPR_* to expect as the packet_in reason
1358 @param controller Controller instance, defaults to test.controller
1359 @returns The received packet-in message
1360 """
1361
1362 if controller == None:
1363 controller = test.controller
1364
1365 end_time = time.time() + oftest.ofutils.default_timeout
1366
1367 while True:
1368 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1369 if not msg:
1370 # Timeout
1371 break
1372 elif packet_in_match(msg, data, in_port, reason):
1373 # Found a matching message
1374 break
1375
1376 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1377 return msg
1378
1379def verify_no_packet_in(test, data, in_port, controller=None):
1380 """
1381 Assert that the controller does not receive a packet_in message matching
1382 data 'data' from port 'in_port'.
1383
1384 @param test Instance of base_tests.SimpleProtocol
1385 @param pkt String to expect as the packet_in data
1386 @param in_port OpenFlow port number to expect as the packet_in in_port
1387 @param controller Controller instance, defaults to test.controller
1388 """
1389
1390 if controller == None:
1391 controller = test.controller
1392
1393 # Negative test, need to wait a short amount of time before checking we
1394 # didn't receive the message.
1395 time.sleep(0.5)
1396
1397 # Check every packet_in queued in the controller
1398 while True:
1399 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1400 if msg == None:
1401 # No more queued packet_in messages
1402 break
1403 elif packet_in_match(msg, data, in_port, None):
1404 # Found a matching message
1405 break
1406
1407 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
1408
Rich Lane7744e112013-01-11 17:23:57 -08001409__all__ = list(set(locals()) - _import_blacklist)