3 from __future__ import print_function
9 from six.moves import socketserver
15 from ryu.ofproto import ofproto_parser
16 from ryu.ofproto import ofproto_v1_0
17 from ryu.ofproto import ofproto_v1_0_parser
18 from ryu.ofproto import ofproto_v1_5
19 from ryu.ofproto import ofproto_v1_5_parser
20 from ryu.ofproto import ofproto_protocol
23 TimeoutExpired = subprocess.TimeoutExpired
25 # As python2 doesn't have timeout for subprocess.call,
26 # this script may hang.
32 'dl_dst=aa:bb:cc:99:88:77',
33 'dl_type=0x0800', # ETH_TYPE_IP
35 'tun_src=192.168.2.3',
36 'tun_dst=192.168.2.4',
40 {'name': 'action_learn',
44 'importance=39032'] + STD_MATCH + [
45 'actions=strip_vlan,mod_nw_dst:192.168.2.9,' +
46 'learn(table=99,priority=1,hard_timeout=300,' +
47 'OXM_OF_VLAN_VID[0..11],' +
48 'OXM_OF_ETH_DST[]=OXM_OF_ETH_SRC[],' +
49 'load:0->OXM_OF_VLAN_VID[],' +
50 'load:OXM_OF_TUNNEL_ID[]->OXM_OF_TUNNEL_ID[],' +
51 'output:OXM_OF_IN_PORT[]),goto_table:100']},
52 {'name': 'match_conj',
56 'cookie=0x123456789abcdef0/0xffffffffffffffff',
59 'actions=strip_vlan,goto_table:100']},
60 {'name': 'match_pkt_mark',
64 'cookie=0x123456789abcdef0/0xffffffffffffffff',
67 'actions=strip_vlan,goto_table:100']},
68 {'name': 'match_pkt_mark_masked',
72 'cookie=0x123456789abcdef0/0xffffffffffffffff',
74 'pkt_mark=0xd431/0xffff',
75 'actions=strip_vlan,goto_table:100']},
76 {'name': 'action_conjunction',
80 'cookie=0x123456789abcdef0/0xffffffffffffffff'] +
82 ['actions=conjunction(0xabcdef,1/2)'])},
83 {'name': 'match_load_nx_register',
87 'cookie=0x123456789abcdef0/0xffffffffffffffff',
90 'actions=load:0xdeadbee->NXM_NX_REG0[4..31]']},
91 {'name': 'match_move_nx_register',
95 'cookie=0x123456789abcdef0/0xffffffffffffffff',
98 'actions=move:NXM_NX_REG0[10..15]->NXM_NX_REG1[0..5]']},
99 {'name': 'action_resubmit',
103 'importance=39032'] +
105 ['actions=resubmit(1234,99)'])},
106 {'name': 'action_ct',
109 'args': (['table=3,',
110 'importance=39032'] +
111 ['dl_type=0x0800,ct_state=-trk'] +
112 ['actions=ct(table=4,zone=NXM_NX_REG0[4..31])'])},
113 {'name': 'action_ct_exec',
116 'args': (['table=3,',
117 'importance=39032'] +
118 ['dl_type=0x0800,ct_state=+trk+est'] +
119 ['actions=ct(commit,exec(set_field:0x654321->ct_mark))'])},
120 {'name': 'action_ct_nat',
123 'args': (['table=3,',
124 'importance=39032'] +
126 ['actions=ct(commit,nat(src=10.1.12.0-10.1.13.255:1-1023)'])},
127 {'name': 'action_ct_nat_v6',
130 'args': (['table=3,',
131 'importance=39032'] +
133 ['actions=ct(commit,nat(dst=2001:1::1-2001:1::ffff)'])},
134 {'name': 'action_ct_clear',
137 'args': (['table=3,',
138 'importance=39032'] +
139 ['dl_type=0x0800,ct_state=+trk'] +
140 ['actions=ct_clear'])},
141 {'name': 'action_note',
144 'args': (['priority=100'] +
145 ['actions=note:04.05.06.07.00.00'])},
146 {'name': 'action_controller',
149 'args': (['priority=100'] +
150 ['actions=controller(reason=packet_out,max_len=1024,id=1)'])},
151 {'name': 'action_fintimeout',
154 'args': (['priority=100,tcp'] +
155 ['actions=fin_timeout(idle_timeout=30,hard_timeout=60)'])},
156 {'name': 'action_dec_nw_ttl',
159 'args': (['priority=100,mpls'] +
160 ['actions=dec_ttl'])},
161 {'name': 'action_push_mpls',
164 'args': (['priority=100,ip'] +
165 ['actions=push_mpls:0x8847'])},
166 {'name': 'action_pop_mpls',
169 'args': (['priority=100,mpls'] +
170 ['actions=pop_mpls:0x0800'])},
171 {'name': 'action_set_mpls_ttl',
174 'args': (['priority=100,mpls'] +
175 ['actions=set_mpls_ttl(127)'])},
176 {'name': 'action_dec_mpls_ttl',
179 'args': (['priority=100,mpls'] +
180 ['actions=dec_mpls_ttl'])},
181 {'name': 'action_set_mpls_label',
184 'args': (['priority=100,mpls'] +
185 ['actions=set_mpls_label(10)'])},
186 {'name': 'action_set_mpls_tc',
189 'args': (['priority=100,mpls'] +
190 ['actions=set_mpls_tc(10)'])},
191 {'name': 'action_dec_ttl_cnt_ids',
194 'args': (['priority=100,tcp'] +
195 ['actions=dec_ttl(1,2,3,4,5)'])},
196 {'name': 'action_stack_push',
199 'args': (['priority=100'] +
200 ['actions=push:NXM_NX_REG2[1..5]'])},
201 {'name': 'action_stack_pop',
204 'args': (['priority=100'] +
205 ['actions=pop:NXM_NX_REG2[1..5]'])},
206 {'name': 'action_sample',
209 'args': (['priority=100'] +
210 ['actions=sample(probability=3,collector_set_id=1,' +
211 'obs_domain_id=2,obs_point_id=3)'])},
212 {'name': 'action_sample2',
215 'args': (['priority=100'] +
216 ['actions=sample(probability=3,collector_set_id=1,' +
217 'obs_domain_id=2,obs_point_id=3,sampling_port=8080)'])},
218 {'name': 'action_controller2',
221 'args': (['priority=100'] +
222 ['actions=controller(reason=packet_out,max_len=1024,' +
223 'id=10,userdata=01.02.03.04.05,pause)'])},
224 {'name': 'action_output_trunc',
227 'args': (['priority=100'] +
228 ['actions=output(port=8080,max_len=1024)'])},
230 {'name': 'bundle-add',
236 'actions=strip_vlan,goto_table:100']},
239 # ToDo: The following actions are not eligible
240 # {'name': 'action_regload2'},
241 # {'name': 'action_outputreg2'},
247 class MyHandler(socketserver.BaseRequestHandler):
251 def _add_msg_to_buf(data, msg_len):
252 # HACK: Clear xid into zero
253 buf.append(data[:4] + b'\x00\x00\x00\x00' + data[8:msg_len])
256 desc = ofproto_protocol.ProtocolDesc()
263 data = self.request.recv(1024)
268 h = ofproto_parser.header(data)
271 version, msg_type, msg_len, xid = h
272 residue = data[msg_len:]
273 desc.set_version(version=version)
274 if msg_type == desc.ofproto.OFPT_HELLO:
275 hello = desc.ofproto_parser.OFPHello(desc)
277 self.request.send(hello.buf)
278 elif msg_type == desc.ofproto.OFPT_FLOW_MOD:
279 self._add_msg_to_buf(data, msg_len)
280 elif version == 4 and msg_type == desc.ofproto.OFPT_EXPERIMENTER:
281 # This is for OF13 Ext-230 bundle
282 # TODO: support bundle for OF>1.3
283 exp = desc.ofproto_parser.OFPExperimenter.parser(
284 object(), version, msg_type, msg_len, xid, data)
285 self._add_msg_to_buf(data, msg_len)
286 if isinstance(exp, desc.ofproto_parser.ONFBundleCtrlMsg):
287 ctrlrep = desc.ofproto_parser.ONFBundleCtrlMsg(
288 desc, exp.bundle_id, exp.type + 1, 0, [])
291 self.request.send(ctrlrep.buf)
292 elif msg_type == desc.ofproto.OFPT_BARRIER_REQUEST:
293 brep = desc.ofproto_parser.OFPBarrierReply(desc)
296 self.request.send(brep.buf)
299 class MyVerboseHandler(MyHandler):
303 if __name__ == '__main__':
304 optlist, args = getopt.getopt(sys.argv[1:], 'dvo:')
306 ofctl_cmd = '/usr/bin/ovs-ofctl'
316 if not os.access(ofctl_cmd, os.X_OK):
317 raise Exception("%s is not executable" % ofctl_cmd)
318 ovs_version = subprocess.Popen([ofctl_cmd, '--version'],
319 stdout=subprocess.PIPE)
322 ver_tuple = re.search(r'\s(\d+)\.(\d+)(\.\d*|\s*$)',
323 ovs_version.stdout.readline().decode()).groups()
324 if int(ver_tuple[0]) > 2 or \
325 int(ver_tuple[0]) == 2 and int(ver_tuple[1]) >= 8:
327 except AttributeError:
330 outpath = '../packet_data'
331 socketdir = tempfile.mkdtemp()
332 socketname = os.path.join(socketdir, 'ovs')
333 server = socketserver.UnixStreamServer(socketname,
334 MyVerboseHandler if verbose else
337 print("Serving at %s" % socketname)
340 bundled = msg.get('bundled', False)
341 for v in msg['versions']:
342 cmdargs = [ofctl_cmd, '-O', 'OpenFlow%2d' % (v + 9)]
346 cmdargs.append('--no-names')
348 cmdargs.append('--bundle')
349 cmdargs.append(msg['cmd'])
350 cmdargs.append('unix:%s' % socketname)
351 cmdargs.append('\n'.join(msg['args']))
353 print("Running cmd: " + ' '.join(cmdargs) + "\n")
354 t = threading.Thread(target=subprocess.call, args=[cmdargs],
355 kwargs={'timeout': 5})
357 server.handle_request()
363 for i, buf1 in enumerate(buf):
364 suffix = ('-%d' % (i + 1)) if i else ''
366 outpath, "of%d" % (v + 9),
367 "ovs-ofctl-of%d-%s%s.packet" % (
368 v + 9, msg['name'], suffix))
369 print("Writing %s..." % outf)
370 with open(outf, 'wb') as f:
375 except TimeoutExpired as e:
380 server.handle_request()
383 os.unlink(socketname)