Adding ONOS Segment Routing CLI files to new repo
diff --git a/cli/trace.py b/cli/trace.py
new file mode 100755
index 0000000..a456f83
--- /dev/null
+++ b/cli/trace.py
@@ -0,0 +1,220 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2013 Big Switch Networks, Inc.
+#
+# Licensed under the Eclipse Public License, Version 1.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+
+#
+# Copyright (c) 2011,2012 Big Switch Networks, Inc.
+# All rights reserved.
+#
+
+from sys import stderr
+from re import compile, match, search
+from optparse import OptionParser
+from collections import defaultdict
+from subprocess import Popen, PIPE, STDOUT
+
+import socket, fcntl, struct
+def get_ipaddr(ifname):
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ ipaddr = fcntl.ioctl(s.fileno(), 0x8915, struct.pack('256s', ifname[:15])) # SIOCGIFADDR
+ return socket.inet_ntoa(ipaddr[20:24])
+
+import urllib, json
+def get_aliases(controller='localhost', controller_port=6633, ifname='eth0'):
+ url = "http://%s/rest/v1/model/switch/" % controller
+ aliases = {get_ipaddr(ifname)+':%d'%controller_port: 'controller'}
+ for switch in json.loads(urllib.urlopen(url).read()):
+ socketaddr = switch.get('socket-address')
+ if socketaddr:
+ socketaddr = socketaddr[1:]
+ alias = switch.get('alias')
+ if not alias:
+ alias = switch.get('dpid')
+ aliases[socketaddr] = alias
+ return aliases
+
+DEBUG=False
+
+class OpenFlowTracer(object):
+ # Formats
+ SUMMARY = "summary"
+ DETAIL = "detail"
+ ONELINE = "oneline"
+
+ def __init__(self, msg_filters=None, tcpdump_filter='', fmt=SUMMARY, alias=False, printer=None):
+ self.msg_filters = msg_filters
+ self.tcpdump_filter = tcpdump_filter
+ self.detail = (fmt != self.SUMMARY)
+ self.oneline = (fmt == self.ONELINE)
+ self.printer = self.prn
+ if printer:
+ self.printer = printer
+
+ self.pkt = defaultdict(str)
+ self.reading_detail = False
+ self.alias = alias
+ self.aliases = None
+ if self.alias:
+ self.aliases = get_aliases()
+
+ def run(self):
+ self.tcpdump_trace(self.tcpdump_open())
+ return
+
+ # filter packets
+ def filter(self):
+ msg_type = self.pkt['of-msg']
+ if not msg_type:
+ return False
+ if self.msg_filters:
+ return any(map(lambda pattern: search(pattern, msg_type), self.msg_filters))
+ return True
+
+ # format packet output
+ def fmt(self):
+ pkt = self.pkt
+ sep = '\n '
+ if self.oneline: sep = ', '
+
+ src = '%s:%s' % (pkt['src-ip'], pkt['src-port'])
+ dst = '%s:%s' % (pkt['dst-ip'], pkt['dst-port'])
+ if self.alias:
+ if not self.aliases.get(src) or not self.aliases.get(dst):
+ self.aliases = get_aliases()
+ src = self.aliases.get(src, src)
+ dst = self.aliases.get(dst, dst)
+
+ ret = '%-18s %-18s [ %s -> %s ]' % (
+ pkt['timestamp'], pkt['of-msg'], src, dst)
+ if self.detail and pkt['of-data']:
+ for data in pkt['of-data'].split(','):
+ data = data.strip()
+ if data:
+ ret += (sep + data)
+ return ret
+
+ def prn(self, x):
+ print x
+
+ def tcpdump_open(self):
+ tcpdump_cmd = 'sudo /usr/local/sbin/tcpdump -i any \'%s\' %s'
+ tcpdump_args = '-l -nn -vv'
+ self.process = Popen(tcpdump_cmd % (self.tcpdump_filter, tcpdump_args),
+ shell=True, bufsize=1, stdout=PIPE, stderr=STDOUT)
+ return self.process.stdout
+
+ def tcpdump_trace(self, fd):
+ # tcpdump decoder patterns
+ empty_line = compile('^$')
+ tcpdump_line = compile('^tcpdump.*$')
+ ip_line = compile('^(\d{2}\:\d{2}:\d{2}\.\d+) IP .*$')
+ tcp_line = compile('^\s*(\d+\.\d+\.\d+\.\d+)\.(\d+) \> (\d+\.\d+\.\d+\.\d+)\.(\d+)\:.*length \d+(.*)$')
+ of_hdr = compile('^([^ ]*) \(xid\=([^\)]*)\)\:(.*)$')
+ of_line = compile('^(.*in_port\=.*)$')
+ if_cont_line = compile('^\s+current\:')
+ inline_err = compile('^\s*\(\*\*\*.*$')
+ pkt_count = compile('^\d+ packets ')
+
+ # helper fn
+ def of_data(pkt, data):
+ if pkt['of-msg'] == 'packet_out':
+ data = data.replace(' ', ',')
+ pkt['of-data'] += (',' + data)
+
+ # decode packet data
+ line = fd.readline()
+ while line:
+ try:
+ line = line.strip()
+ pkt = self.pkt
+ if empty_line.match(line):
+ pass
+ elif pkt_count.match(line):
+ print>>stderr, line
+ elif tcpdump_line.match(line):
+ pass
+ elif ip_line.match(line):
+ if self.filter(): self.printer(self.fmt())
+ self.pkt = defaultdict(str)
+ self.reading_detail = False
+ pkt = self.pkt
+ pkt['timestamp'] = ip_line.match(line).groups()[0]
+ elif tcp_line.match(line):
+ m = tcp_line.match(line).groups()
+ pkt['src-ip'] = m[0]
+ pkt['src-port'] = m[1]
+ pkt['dst-ip'] = m[2]
+ pkt['dst-port'] = m[3]
+ if of_hdr.match(m[4]):
+ self.reading_detail = True
+ m = of_hdr.match(m[4]).groups()
+ pkt['of-msg'] = m[0].strip()
+ pkt['of-xid'] = m[1]
+ data = m[2]
+ if not inline_err.match(m[2]):
+ of_data(pkt, data)
+ else:
+ if DEBUG:
+ print>>stderr, 'Inline Error', data
+ elif of_line.match(line):
+ of_data(pkt, of_line.match(line).groups()[0])
+ elif if_cont_line.match(line):
+ line = line.replace(',', '; ')
+ of_data(pkt, '; '+line)
+ elif self.reading_detail:
+ line = line.replace(',', '; ')
+ of_data(pkt, line)
+ else:
+ if DEBUG:
+ print>>stderr, 'Unexpected: Line', line
+ line = fd.readline()
+ except KeyboardInterrupt:
+ print
+ if self.process:
+ self.process.terminate()
+ self.process = None
+ else:
+ break
+
+def main():
+ usage = "usage: %prog [--detail] [--oneline] [--filter <tcpdump-filter>] [<msg-type> ...]"
+ optparser = OptionParser(usage=usage)
+ optparser.add_option("-f", "--filter", dest="tcpdump_filter",
+ action="store", type="string", default='((tcp) and (port 6633))',
+ help="tcpdump filter rule", metavar="FILTER")
+ optparser.add_option("-d", "--detail", dest="detail",
+ action="store_true", default=False,
+ help="print message detail")
+ optparser.add_option("-o", "--oneline", dest="oneline",
+ action="store_true", default=False,
+ help="print message detail on one line")
+ optparser.add_option("-a", "--alias", dest="alias",
+ action="store_true", default=False,
+ help="query controller to resolve address to switch-dpid/alias")
+ (options, msg_filters) = optparser.parse_args()
+
+ try:
+ print 'Starting openflow trace, use ^C to quit'
+ fmt = OpenFlowTracer.SUMMARY
+ if options.detail: fmt = OpenFlowTracer.DETAIL
+ if options.oneline: fmt = OpenFlowTracer.ONELINE
+ tracer = OpenFlowTracer(msg_filters, options.tcpdump_filter, fmt=fmt, alias=options.alias)
+ tracer.run()
+ except KeyboardInterrupt:
+ pass
+
+if __name__ == '__main__':
+ main()