4bc29b2c5f
W605 invalid escape sequence, which was recently added in pycodestyle, would be a syntax error in future python3 versions. Signed-off-by: IWAMOTO Toshihiro <iwamoto@valinux.co.jp> Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
385 lines
13 KiB
Python
385 lines
13 KiB
Python
#! /usr/bin/env python
|
|
|
|
from __future__ import print_function
|
|
|
|
import getopt
|
|
import os
|
|
import re
|
|
import six
|
|
from six.moves import socketserver
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import threading
|
|
|
|
from ryu.ofproto import ofproto_parser
|
|
from ryu.ofproto import ofproto_v1_0
|
|
from ryu.ofproto import ofproto_v1_0_parser
|
|
from ryu.ofproto import ofproto_v1_5
|
|
from ryu.ofproto import ofproto_v1_5_parser
|
|
from ryu.ofproto import ofproto_protocol
|
|
|
|
if six.PY3:
|
|
TimeoutExpired = subprocess.TimeoutExpired
|
|
else:
|
|
# As python2 doesn't have timeout for subprocess.call,
|
|
# this script may hang.
|
|
TimeoutExpired = None
|
|
|
|
STD_MATCH = [
|
|
'in_port=43981',
|
|
'dl_vlan=999',
|
|
'dl_dst=aa:bb:cc:99:88:77',
|
|
'dl_type=0x0800', # ETH_TYPE_IP
|
|
'nw_dst=192.168.2.1',
|
|
'tun_src=192.168.2.3',
|
|
'tun_dst=192.168.2.4',
|
|
'tun_id=50000']
|
|
|
|
MESSAGES = [
|
|
{'name': 'action_learn',
|
|
'versions': [4],
|
|
'cmd': 'add-flow',
|
|
'args': ['table=2',
|
|
'importance=39032'] + STD_MATCH + [
|
|
'actions=strip_vlan,mod_nw_dst:192.168.2.9,' +
|
|
'learn(table=99,priority=1,hard_timeout=300,' +
|
|
'OXM_OF_VLAN_VID[0..11],' +
|
|
'OXM_OF_ETH_DST[]=OXM_OF_ETH_SRC[],' +
|
|
'load:0->OXM_OF_VLAN_VID[],' +
|
|
'load:OXM_OF_TUNNEL_ID[]->OXM_OF_TUNNEL_ID[],' +
|
|
'output:OXM_OF_IN_PORT[]),goto_table:100']},
|
|
{'name': 'match_conj',
|
|
'versions': [4],
|
|
'cmd': 'mod-flows',
|
|
'args': ['table=3',
|
|
'cookie=0x123456789abcdef0/0xffffffffffffffff',
|
|
'dl_vlan=1234',
|
|
'conj_id=0xabcdef',
|
|
'actions=strip_vlan,goto_table:100']},
|
|
{'name': 'match_pkt_mark',
|
|
'versions': [4],
|
|
'cmd': 'mod-flows',
|
|
'args': ['table=3',
|
|
'cookie=0x123456789abcdef0/0xffffffffffffffff',
|
|
'dl_vlan=1234',
|
|
'pkt_mark=54321',
|
|
'actions=strip_vlan,goto_table:100']},
|
|
{'name': 'match_pkt_mark_masked',
|
|
'versions': [4],
|
|
'cmd': 'mod-flows',
|
|
'args': ['table=3',
|
|
'cookie=0x123456789abcdef0/0xffffffffffffffff',
|
|
'dl_vlan=1234',
|
|
'pkt_mark=0xd431/0xffff',
|
|
'actions=strip_vlan,goto_table:100']},
|
|
{'name': 'action_conjunction',
|
|
'versions': [4],
|
|
'cmd': 'mod-flows',
|
|
'args': (['table=2',
|
|
'cookie=0x123456789abcdef0/0xffffffffffffffff'] +
|
|
STD_MATCH +
|
|
['actions=conjunction(0xabcdef,1/2)'])},
|
|
{'name': 'match_load_nx_register',
|
|
'versions': [4],
|
|
'cmd': 'mod-flows',
|
|
'args': ['table=3',
|
|
'cookie=0x123456789abcdef0/0xffffffffffffffff',
|
|
'reg0=0x1234',
|
|
'reg5=0xabcd/0xffff',
|
|
'actions=load:0xdeadbee->NXM_NX_REG0[4..31]']},
|
|
{'name': 'match_move_nx_register',
|
|
'versions': [4],
|
|
'cmd': 'mod-flows',
|
|
'args': ['table=3',
|
|
'cookie=0x123456789abcdef0/0xffffffffffffffff',
|
|
'reg0=0x1234',
|
|
'reg5=0xabcd/0xffff',
|
|
'actions=move:NXM_NX_REG0[10..15]->NXM_NX_REG1[0..5]']},
|
|
{'name': 'action_resubmit',
|
|
'versions': [4],
|
|
'cmd': 'add-flow',
|
|
'args': (['table=3',
|
|
'importance=39032'] +
|
|
STD_MATCH +
|
|
['actions=resubmit(1234,99)'])},
|
|
{'name': 'action_ct',
|
|
'versions': [4],
|
|
'cmd': 'add-flow',
|
|
'args': (['table=3,',
|
|
'importance=39032'] +
|
|
['dl_type=0x0800,ct_state=-trk'] +
|
|
['actions=ct(table=4,zone=NXM_NX_REG0[4..31])'])},
|
|
{'name': 'action_ct_exec',
|
|
'versions': [4],
|
|
'cmd': 'add-flow',
|
|
'args': (['table=3,',
|
|
'importance=39032'] +
|
|
['dl_type=0x0800,ct_state=+trk+est'] +
|
|
['actions=ct(commit,exec(set_field:0x654321->ct_mark))'])},
|
|
{'name': 'action_ct_nat',
|
|
'versions': [4],
|
|
'cmd': 'add-flow',
|
|
'args': (['table=3,',
|
|
'importance=39032'] +
|
|
['dl_type=0x0800'] +
|
|
['actions=ct(commit,nat(src=10.1.12.0-10.1.13.255:1-1023)'])},
|
|
{'name': 'action_ct_nat_v6',
|
|
'versions': [4],
|
|
'cmd': 'add-flow',
|
|
'args': (['table=3,',
|
|
'importance=39032'] +
|
|
['dl_type=0x86dd'] +
|
|
['actions=ct(commit,nat(dst=2001:1::1-2001:1::ffff)'])},
|
|
{'name': 'action_ct_clear',
|
|
'versions': [4],
|
|
'cmd': 'add-flow',
|
|
'args': (['table=3,',
|
|
'importance=39032'] +
|
|
['dl_type=0x0800,ct_state=+trk'] +
|
|
['actions=ct_clear'])},
|
|
{'name': 'action_note',
|
|
'versions': [4],
|
|
'cmd': 'add-flow',
|
|
'args': (['priority=100'] +
|
|
['actions=note:04.05.06.07.00.00'])},
|
|
{'name': 'action_controller',
|
|
'versions': [4],
|
|
'cmd': 'add-flow',
|
|
'args': (['priority=100'] +
|
|
['actions=controller(reason=packet_out,max_len=1024,id=1)'])},
|
|
{'name': 'action_fintimeout',
|
|
'versions': [4],
|
|
'cmd': 'add-flow',
|
|
'args': (['priority=100,tcp'] +
|
|
['actions=fin_timeout(idle_timeout=30,hard_timeout=60)'])},
|
|
{'name': 'action_dec_nw_ttl',
|
|
'versions': [1],
|
|
'cmd': 'add-flow',
|
|
'args': (['priority=100,mpls'] +
|
|
['actions=dec_ttl'])},
|
|
{'name': 'action_push_mpls',
|
|
'versions': [1],
|
|
'cmd': 'add-flow',
|
|
'args': (['priority=100,ip'] +
|
|
['actions=push_mpls:0x8847'])},
|
|
{'name': 'action_pop_mpls',
|
|
'versions': [1],
|
|
'cmd': 'add-flow',
|
|
'args': (['priority=100,mpls'] +
|
|
['actions=pop_mpls:0x0800'])},
|
|
{'name': 'action_set_mpls_ttl',
|
|
'versions': [1],
|
|
'cmd': 'add-flow',
|
|
'args': (['priority=100,mpls'] +
|
|
['actions=set_mpls_ttl(127)'])},
|
|
{'name': 'action_dec_mpls_ttl',
|
|
'versions': [1],
|
|
'cmd': 'add-flow',
|
|
'args': (['priority=100,mpls'] +
|
|
['actions=dec_mpls_ttl'])},
|
|
{'name': 'action_set_mpls_label',
|
|
'versions': [1],
|
|
'cmd': 'add-flow',
|
|
'args': (['priority=100,mpls'] +
|
|
['actions=set_mpls_label(10)'])},
|
|
{'name': 'action_set_mpls_tc',
|
|
'versions': [1],
|
|
'cmd': 'add-flow',
|
|
'args': (['priority=100,mpls'] +
|
|
['actions=set_mpls_tc(10)'])},
|
|
{'name': 'action_dec_ttl_cnt_ids',
|
|
'versions': [4],
|
|
'cmd': 'add-flow',
|
|
'args': (['priority=100,tcp'] +
|
|
['actions=dec_ttl(1,2,3,4,5)'])},
|
|
{'name': 'action_stack_push',
|
|
'versions': [4],
|
|
'cmd': 'add-flow',
|
|
'args': (['priority=100'] +
|
|
['actions=push:NXM_NX_REG2[1..5]'])},
|
|
{'name': 'action_stack_pop',
|
|
'versions': [4],
|
|
'cmd': 'add-flow',
|
|
'args': (['priority=100'] +
|
|
['actions=pop:NXM_NX_REG2[1..5]'])},
|
|
{'name': 'action_sample',
|
|
'versions': [4],
|
|
'cmd': 'add-flow',
|
|
'args': (['priority=100'] +
|
|
['actions=sample(probability=3,collector_set_id=1,' +
|
|
'obs_domain_id=2,obs_point_id=3)'])},
|
|
{'name': 'action_sample2',
|
|
'versions': [4],
|
|
'cmd': 'add-flow',
|
|
'args': (['priority=100'] +
|
|
['actions=sample(probability=3,collector_set_id=1,' +
|
|
'obs_domain_id=2,obs_point_id=3,sampling_port=8080)'])},
|
|
{'name': 'action_controller2',
|
|
'versions': [4],
|
|
'cmd': 'add-flow',
|
|
'args': (['priority=100'] +
|
|
['actions=controller(reason=packet_out,max_len=1024,' +
|
|
'id=10,userdata=01.02.03.04.05,pause)'])},
|
|
{'name': 'action_output_trunc',
|
|
'versions': [4],
|
|
'cmd': 'add-flow',
|
|
'args': (['priority=100'] +
|
|
['actions=output(port=8080,max_len=1024)'])},
|
|
|
|
{'name': 'bundle-add',
|
|
'versions': [4],
|
|
'bundled': True,
|
|
'cmd': 'add-flow',
|
|
'args': ['table=33',
|
|
'dl_vlan=1234',
|
|
'actions=strip_vlan,goto_table:100']},
|
|
|
|
|
|
# ToDo: The following actions are not eligible
|
|
# {'name': 'action_regload2'},
|
|
# {'name': 'action_outputreg2'},
|
|
]
|
|
|
|
buf = []
|
|
|
|
|
|
class MyHandler(socketserver.BaseRequestHandler):
|
|
verbose = False
|
|
|
|
@staticmethod
|
|
def _add_msg_to_buf(data, msg_len):
|
|
# HACK: Clear xid into zero
|
|
buf.append(data[:4] + b'\x00\x00\x00\x00' + data[8:msg_len])
|
|
|
|
def handle(self):
|
|
desc = ofproto_protocol.ProtocolDesc()
|
|
residue = b''
|
|
while True:
|
|
if residue:
|
|
data = residue
|
|
residue = b''
|
|
else:
|
|
data = self.request.recv(1024)
|
|
if data == b'':
|
|
break
|
|
if self.verbose:
|
|
print(data)
|
|
h = ofproto_parser.header(data)
|
|
if self.verbose:
|
|
print(h)
|
|
version, msg_type, msg_len, xid = h
|
|
residue = data[msg_len:]
|
|
desc.set_version(version=version)
|
|
if msg_type == desc.ofproto.OFPT_HELLO:
|
|
hello = desc.ofproto_parser.OFPHello(desc)
|
|
hello.serialize()
|
|
self.request.send(hello.buf)
|
|
elif msg_type == desc.ofproto.OFPT_FLOW_MOD:
|
|
self._add_msg_to_buf(data, msg_len)
|
|
elif version == 4 and msg_type == desc.ofproto.OFPT_EXPERIMENTER:
|
|
# This is for OF13 Ext-230 bundle
|
|
# TODO: support bundle for OF>1.3
|
|
exp = desc.ofproto_parser.OFPExperimenter.parser(
|
|
object(), version, msg_type, msg_len, xid, data)
|
|
self._add_msg_to_buf(data, msg_len)
|
|
if isinstance(exp, desc.ofproto_parser.ONFBundleCtrlMsg):
|
|
ctrlrep = desc.ofproto_parser.ONFBundleCtrlMsg(
|
|
desc, exp.bundle_id, exp.type + 1, 0, [])
|
|
ctrlrep.xid = xid
|
|
ctrlrep.serialize()
|
|
self.request.send(ctrlrep.buf)
|
|
elif msg_type == desc.ofproto.OFPT_BARRIER_REQUEST:
|
|
brep = desc.ofproto_parser.OFPBarrierReply(desc)
|
|
brep.xid = xid
|
|
brep.serialize()
|
|
self.request.send(brep.buf)
|
|
|
|
|
|
class MyVerboseHandler(MyHandler):
|
|
verbose = True
|
|
|
|
|
|
if __name__ == '__main__':
|
|
optlist, args = getopt.getopt(sys.argv[1:], 'dvo:')
|
|
debug = False
|
|
ofctl_cmd = '/usr/bin/ovs-ofctl'
|
|
verbose = False
|
|
for o, a in optlist:
|
|
if o == '-d':
|
|
debug = True
|
|
elif o == '-v':
|
|
verbose = True
|
|
elif o == '-o':
|
|
ofctl_cmd = a
|
|
|
|
if not os.access(ofctl_cmd, os.X_OK):
|
|
raise Exception("%s is not executable" % ofctl_cmd)
|
|
ovs_version = subprocess.Popen([ofctl_cmd, '--version'],
|
|
stdout=subprocess.PIPE)
|
|
has_names = False
|
|
try:
|
|
ver_tuple = re.search(r'\s(\d+)\.(\d+)(\.\d*|\s*$)',
|
|
ovs_version.stdout.readline().decode()).groups()
|
|
if int(ver_tuple[0]) > 2 or \
|
|
int(ver_tuple[0]) == 2 and int(ver_tuple[1]) >= 8:
|
|
has_names = True
|
|
except AttributeError:
|
|
pass
|
|
|
|
outpath = '../packet_data'
|
|
socketdir = tempfile.mkdtemp()
|
|
socketname = os.path.join(socketdir, 'ovs')
|
|
server = socketserver.UnixStreamServer(socketname,
|
|
MyVerboseHandler if verbose else
|
|
MyHandler)
|
|
if debug or verbose:
|
|
print("Serving at %s" % socketname)
|
|
|
|
for msg in MESSAGES:
|
|
bundled = msg.get('bundled', False)
|
|
for v in msg['versions']:
|
|
cmdargs = [ofctl_cmd, '-O', 'OpenFlow%2d' % (v + 9)]
|
|
if verbose:
|
|
cmdargs.append('-v')
|
|
if has_names:
|
|
cmdargs.append('--no-names')
|
|
if bundled:
|
|
cmdargs.append('--bundle')
|
|
cmdargs.append(msg['cmd'])
|
|
cmdargs.append('unix:%s' % socketname)
|
|
cmdargs.append('\n'.join(msg['args']))
|
|
if verbose:
|
|
print("Running cmd: " + ' '.join(cmdargs) + "\n")
|
|
t = threading.Thread(target=subprocess.call, args=[cmdargs],
|
|
kwargs={'timeout': 5})
|
|
t.start()
|
|
server.handle_request()
|
|
if debug:
|
|
for buf1 in buf:
|
|
print(buf1)
|
|
buf = []
|
|
else:
|
|
for i, buf1 in enumerate(buf):
|
|
suffix = ('-%d' % (i + 1)) if i else ''
|
|
outf = os.path.join(
|
|
outpath, "of%d" % (v + 9),
|
|
"ovs-ofctl-of%d-%s%s.packet" % (
|
|
v + 9, msg['name'], suffix))
|
|
print("Writing %s..." % outf)
|
|
with open(outf, 'wb') as f:
|
|
f.write(buf1)
|
|
buf = []
|
|
try:
|
|
t.join()
|
|
except TimeoutExpired as e:
|
|
print(e)
|
|
|
|
if debug:
|
|
while True:
|
|
server.handle_request()
|
|
print(buf.pop())
|
|
|
|
os.unlink(socketname)
|
|
os.rmdir(socketdir)
|