diff --git a/.idea/webServers.xml b/.idea/webServers.xml
new file mode 100644
index 0000000..35f250c
--- /dev/null
+++ b/.idea/webServers.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 4982f1d..635ece6 100644
--- a/README.md
+++ b/README.md
@@ -1,57 +1,53 @@
+
OFP_Sniffer is an OpenFlow sniffer to be used for troubleshooting and
learning purposes.
-Currently on version 0.2, it dissects all OpenFlow 1.0 messages. OpenFlow version 1.3 will
-be available on version 0.3 (to be released soon).
+Currently on version 1.0, it dissects all OpenFlow 1.0 messages.
+OpenFlow version 1.3 will be available on version 1.1 (to be released soon).
It works directly on Linux shell and dissects all OpenFlow messages on the
wire. Using OFP_Sniffer, you can easily track OpenFlow messages and errors
-associated (if any), without openning X11 or Wireshark. OFP_Sniffer was
-written in Python to support the AmLight SDN deployment (www.sdn.amlight.net).
+associated (if any), without opening X11 or Wireshark. OFP_Sniffer was
+written in Python 3.6 to support the AmLight SDN deployment (www.sdn.amlight.net).
AmLight SDN uses Internet2 FlowSpace Firewall, OESS and On.Lab ONOS, and these
-apps were tested and are fully supported (well, they should be ;)).
+apps were tested and are fully supported.
This tool started to be developed after a conversation with Andrew Ragusa
(a.k.a. A.J) from Indiana University along the NITRD - Roadmap to Operating
SDN-based Networks Workshop hosted by ESNET and Internet2. Thanks A.J. for your
-constant support and mentoring!! (Link to NITRD workshop: https://www.nitrd.gov/nitrdgroups/index.php?title=SDN_Operational_Issues_WS)
+constant support! (Link to NITRD workshop:
+https://www.nitrd.gov/nitrdgroups/index.php?title=SDN_Operational_Issues_WS)
As a command line interface tool, it has a few input parameters:
```
# ./ofp_sniffer.py -h
Usage:
./ofp_sniffer.py [-p min|full] [-f pcap_filter] [-F filter_file] [-i dev] [-r pcap_file]
- -p [min|full] or --print=[min|full]: print min or full packet headers. Default: min
- -f pcap_filter or --pcap-filter=pcap_filter : add a libpcap filter
- -F sanitizer_file.json or --sanitizer-file=sanitizerfile.json
- -i interface or --interface=interface. Default: eth0
- -r captured.pcap or --src-file=captured.pcap
- -o or --print-ovs : print using ovs-ofctl format
- -h or --help : prints this guidance
- -c or --no-colors: removes colors
- -v or --version : prints version
-
--p [min|full] gives you the option of printing minimal or full TCP/IP headers
--f pcap_filter gives you the possibility of adding libpcap filters.
- Filter "port 6633 " is already applied. If you want to add more options, just
- add -f and the filter, for example:
- -f " or port 6634 or host 192.168.0.2"
--F sanitizer_file.json gives you the possibility of using specific OpenFlow
- filters, for example, ignore some OpenFlow types (PacketIn, PacketOut,
- etc). An example is shipped with the source code
--i interface gives you the possibility of choosing the interface to sniffer.
- Remember that you will need root powers.
--r capture.pcap gives you the possibility of working on a previously captured libpcap file.
--o gives you the possibility of printing the ovs-ofctl command that generated a
- specific flow-mod message.
+ -p : print full headers packet headers. Default: min
+ -f pcap_filter or --pcap-filter=pcap_filter: add a libpcap filter
+ -F filters_file.json or --filters-file=filters.json
+ -i interface or --interface=interface. Default: eth0
+ -r captured.pcap or --src-file=captured.pcap
+ -P topology.json or --topology-file=topology.json
+ -h or --help : prints this guidance
+ -c or --no-colors: removes colors
+ -v or --version : prints version
+ -O or --oess-fvd: monitor OESS FVD status
+ -S or --enable-statistics: creates statistics
```
+
+Starting on version 1.0, apps are supported to handle specific needs, such as track OESS FVD
+messages, or to creates statistics via REST and be integrated to NMSes (f.i., Zabbix). New apps
+are coming soon to discover the network topology and verify link integrity.
+
+More info: https://amlight.net/wp-content/uploads/2015/03/wpeif-2016-ofpsniffer.pdf
+
##################### Instalation ######################
```
-Required Python 2.7 (2.6 works but with issues)
-apt-get install python-pcapy or yum install pcapy
-git clone https://github.com/jab1982/ofp_sniffer.git
+Requires Python 3.6
+git clone https://github.com/amlight/ofp_sniffer.git
cd ofp_sniffer
-git checkout 0.2
+pip3.6 install docs/requirements.txt
sudo ./ofp_sniffer.py
```
##################### Examples #########################
@@ -104,39 +100,69 @@ OpenFlow Version: 1.0(1) Type: FlowMod(14) Length: 88 XID: 2
# ovs-ofctl del-flows tcp:192.168.56.101:6634 "dl_type=0x88bc,dl_dst=10:00:00:01:20:00, "
-# ofp_sniffer with option -o (to print ovs-ofctl command)
-
2015-09-13 11:50:43.636925 192.168.56.102:37454 -> 192.168.56.101:6634 Size: 138
OpenFlow Version: 1.0(1) Type: FlowMod(14) Length: 72 XID: 2
2 OpenFlow Match - wildcards: 3678439 dl_type: 0x88bc dl_dst: 10:00:00:01:20:00
2 OpenFlow Body - Cookie: 0x00 Command: Delete(3) Idle/Hard Timeouts: 0/0 Priority: 32768 Buffer ID: 0xffffffff Out Port: 65535 Flags: Unknown Flag(0)
-ovs-ofctl del-flows tcp:192.168.56.101:6634 "dl_type=0x88bc,dl_dst=10:00:00:01:20:00, "
# ovs-ofctl add-flow tcp:192.168.56.101:6634 "dl_dst=10:00:00:01:20:00,dl_type=0x88bc actions=mod_vlan_vid:14,output:2"
-# ofp_sniffer with option -o (to print ovs-ofctl command)
-
2015-09-13 11:52:58.563737 192.168.56.102:37455 -> 192.168.56.101:6634 Size: 154
OpenFlow Version: 1.0(1) Type: FlowMod(14) Length: 88 XID: 2
2 OpenFlow Match - wildcards: 3678439 dl_type: 0x88bc dl_dst: 10:00:00:01:20:00
2 OpenFlow Body - Cookie: 0x00 Command: Add(0) Idle/Hard Timeouts: 0/0 Priority: 32768 Buffer ID: 0xffffffff Out Port: 65535 Flags: Unknown Flag(0)
2 OpenFlow Action - Type: SetVLANID Length: 8 VLAN ID: 14 Pad: 0
2 OpenFlow Action - Type: OUTPUT Length: 8 Port: 2 Max Length: 0
-ovs-ofctl add-flow tcp:192.168.56.101:6634 "dl_type=0x88bc,dl_dst=10:00:00:01:20:00, action=mod_vlan_vid:14,output:2,"
```
Using Filters:
-When using option -F ./example_filter.json you will have a few options:
+When using option -F ./filters.json you will have a few options:
-"allowed_of_versions" : used to select what OpenFlow messages you DON'T want to see. You can define different filters
+"rejected_of_types" : used to select what OpenFlow message types you DON'T want to see. You can define different filters
depending of the OpenFlow version
+
+Filters by Ethertype:
+
+If you are looking for a specific Ethertype being transported by PacketOut or PacketIn messages, you can reject all
+others, giving you easy visualization.
+
+Example:
+
+```
+ "filters":{
+ "ethertypes": {
+ "lldp" : 0,
+ "fvd" : 0,
+ "arp" : 1,
+ "others": [ "88b5" ]
+ },
+ "packetIn_filter": {
+ "switch_dpid": "any",
+ "in_port": "any"
+ },
+ "packetOut_filter": {
+ "switch_dpid": "any",
+ "out_port": "any"
+ }
+ }
+}
+```
+
+In the ethertype section, 1 means filter, 0 means print it. In the example provided, ARP messages won't be seen, while
+OESS FVD and LLDP will. You can add the Ethertype hex number (without the 0x) in the "others" section, just adding
+commas (",").
+
"packetIn_filter": used to define what PacketIn + LLDP messages you WANT to see. You can define per switch and/or
+ per port. For switch, you need to use the datapath_id as seen by the application you are using. For example,
+ some apps fill in the field c_id with of:dpid_id, other with dpid:dpid_id. For ports, using the OpenFlow port_id,
+ not the port name. For example, on Brocade, eth1/1 == 1. So use 1 instead of eth1/1.
+
+"packetOut_filter": used to define what PacketOut + LLDP messages you WANT to see. You can define per switch and/or
per port. For switch, you need to use the datapath_id as seen by the application you are using. For example,
some apps fill in the field c_id with of:dpid_id, other with dpid:dpid_id. For ports, using the OpenFlow port_id,
not the name of the port. For example, on Brocade, eth1/1 == 1. So use 1 instead of eth1/1.
-
-Options PacketOut_filter and flowMod_logs are not deployed yet (future use).
+
Support for OpenFlow proxies:
@@ -147,10 +173,9 @@ When using an OpenFlow proxy, depending of the interface you select to sniffer,
IP_Proxy <-> IP_Switch
It is hard to associate which controller is talking to which switch. To ease this troubleshooting, the OpenFlow
- sniffer automatically monitors all PacketOut + LLDP messages to create a dictionary of {IP:port, name_switch}.
- If this is your case, change the file ofp_fsfw_v10.py, under the variable "name" with the DPID and name of
- each switch. Next time you run the sniffer, you are going to see the IP and between paranthesys the device behind
- the proxy. Example:
+ sniffer automatically monitors all PacketOut + LLDP messages to create a dictionary of {(IP, port): name_switch}.
+ If this is your case, change the file docs/topology.json. Next time you run the sniffer, you are going to see
+ the IP and between parentheses the device behind the proxy. Example:
```
2015-12-16 15:37:41.563621 200.0.207.79(andes1):7801 -> 190.103.184.135:6633 Size: 157 Bytes
@@ -173,11 +198,11 @@ OpenFlow Version: 1.0(1) Type: PacketIn(10) Length: 99 XID: 0
0 LLDP: END(0) Length: 0
```
-The name (andes1) represents a switch called "andes1" with DPID cc4e249126000000. Not that the DPID showed in the
+The name (andes1) represents a switch called "andes1" with DPID cc4e249126000000. Note that the DPID showed in the
example is not the same, because a PacketIn message is being used as an example. PacketIn shows the DPID of the
neighbors of "andes1".
-I hope this code helps you. This is the second version, a few changes are already planned for 0.3. Coming soon!
+I hope this code helps you. This is the first stable version, a few changes are already planned for 1.1. Coming soon!
-Questions/Suggestions: Jeronimo Bezerra
+Questions/Suggestions: AmLight Dev Team
diff --git a/TODO b/TODO
deleted file mode 100644
index 9e97cb7..0000000
--- a/TODO
+++ /dev/null
@@ -1,23 +0,0 @@
-TODO List:
-
-Version 0.2:
-
-- Dissects all OpenFlow 1.0 message types
-- Reads from Libpcap files
-- PacketIn filters
-- Integrate with FlowSpace Firewall
-
-Version 0.3:
-
-- Dissects all OpenFlow 1.3 message types
-
-Version 0.4:
-
-- Topology Validator
-- Labels outputs depending of Match and Action
-- Full OpenVSwitch/NICIRA dissector
-- Outputs as text and libcap to different files
-- Reads SSL/TLS sessions
-- Make TAR.GZ available (with Makefile)
-- Create RPM and DEB packages
-
diff --git a/__init__.py b/__init__.py
index 080b343..e69de29 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1,5 +0,0 @@
-import ofp_dissector_v10.py
-import ofp_parser_v10.py
-import ofp_prints_v10.py
-import ofp_fsfw_v10.py
-import termcolor
diff --git a/apps/__init__.py b/apps/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/apps/oess_fvd.py b/apps/oess_fvd.py
new file mode 100644
index 0000000..2fb98c1
--- /dev/null
+++ b/apps/oess_fvd.py
@@ -0,0 +1,148 @@
+"""
+ This app was created to specifically monitor the
+ OESS-FVD communication. It could be used to generate alarms
+ when a packetIn is received with current time sent by the FVD
+ too high compared with the time when the packet was
+ captured.
+"""
+
+from datetime import datetime, timedelta
+from libs.core.topo_reader import TopoReader
+from libs.tcpiplib.process_data import is_protocol
+
+
+OFP_PACKET_IN = 10
+OFP_PACKET_OUT = 13
+WARN = 8
+CRITICAL = 30
+
+
+class OessFvdTracer:
+ """
+ OessFvdTracer is an app to evaluate the OESS FVD app.
+ """
+
+ def __init__(self):
+ self.links = dict()
+ self.layout = '%-20s %-14s %-30s %-30s %s'
+ self.starting()
+ self.last_printed = None
+
+ @staticmethod
+ def starting():
+ """
+ Just print the app name
+ """
+ print('OESS Forwarding Verification Monitoring')
+
+ def process_packet(self, pkt):
+ """
+ Method called by ofp_sniffer to process the IP+OF packet
+ We are only interested in Packet_Ins because these are
+ messages coming from the switch, which means, the end of
+ the OESS FV cycle:
+ (OESS -> packetOut -> dpid -> packetIn -> OESS)
+
+ Args:
+ pkt: Packet class
+ """
+ for msg in pkt.ofmsgs:
+ if msg.ofp.header.message_type in [OFP_PACKET_IN]:
+ fvd = is_protocol(msg.ofp.data, oess=True)
+ if fvd is not False:
+ self.add_link(fvd, pkt.l1.time)
+
+ def add_link(self, fvd, capture_time):
+ """
+ Add detected OESS link to self.links dictionary
+
+ Args:
+ fvd: OESS class
+ capture_time: time when the packet was capture
+ by ofp_sniffer
+ """
+
+ if fvd.side_a not in self.links:
+ self.links[fvd.side_a] = dict()
+
+ capture_time = datetime.strptime(capture_time, '%Y-%m-%d %H:%M:%S.%f')
+
+ time_diff = self.calculate_time_diff(capture_time, fvd.timestamp)
+
+ self.links[fvd.side_a][fvd.port_a] = {'remote': fvd.side_z,
+ 'port': fvd.port_z,
+ 'timestamp': fvd.timestamp,
+ 'last_seen': capture_time,
+ 'diff': time_diff}
+
+ self.print_link_status(fvd.side_a, fvd.port_a)
+
+ @staticmethod
+ def calculate_time_diff(capture_time, oess_time):
+ """
+ Calculate the time difference between packet sent via PacketOut
+ and the packet received via PacketIn.
+
+ Args:
+ capture_time: PacketIn time
+ oess_time: PacketOut time
+ Returns:
+ difference
+ """
+ return capture_time - datetime.fromtimestamp(oess_time)
+
+ def print_link_status(self, dpid, port, alert=False):
+ """
+ Now, just print the OESS link detected. The idea of this method
+ is to generate alarms when time different from the moment packet
+ is seen by ofp_sniffer with the time packet was sent is over
+ many seconds.
+
+ Args:
+ dpid: source DPID in the OESS message
+ port: source port in the OESS message
+ alert: print only warning and critical
+ """
+
+ link = self.links[dpid][port]
+
+ timestamp = str(datetime.fromtimestamp(link['timestamp']))
+ topo_link = TopoReader().get_link_aliases(dpid, port, link['remote'],
+ link['port'], option="Full")
+ source_dpid = TopoReader().get_datapath_name(dpid)
+
+ if timedelta(seconds=CRITICAL) > link['diff'] > timedelta(seconds=WARN):
+ link['diff'] = str(link['diff']) + ' <-- Warning!'
+ alert = True
+
+ elif link['diff'] > timedelta(seconds=CRITICAL):
+ link['diff'] = str(link['diff']) + ' <-- Critical!'
+ alert = True
+
+ if alert:
+ if len(topo_link) > 0:
+ self.print_header(True)
+ print(self.layout % (topo_link, source_dpid, timestamp,
+ link['last_seen'], link['diff']))
+ else:
+ self.print_header()
+ print('%-24s %-4s %-24s %-4s %s\t %s\t %s' %
+ (dpid, port, link['remote'], link['port'], timestamp,
+ link['last_seen'], link['diff']))
+
+ def print_header(self, topo_link=False):
+ """
+ Print headers just once. In case it keeps changing (because link
+ was not found in the topology.json), prints the header again.
+
+ Args:
+ topo_link: indicates if link was found in the topology.json
+ """
+ if topo_link and self.last_printed in [None, 'not_topo_link']:
+ print(self.layout % ('Link', 'Source DPID', 'Sent by OESS-FVD',
+ 'Received by OFP_Sniffer', 'Delay'))
+ self.last_printed = 'topo_link'
+ elif not topo_link and self.last_printed in [None, 'topo_link']:
+ print('%-24s %-4s %-24s %-4s %s\t\t\t\t\t %s\t\t\t\t\t\t %s' %
+ ('DPID', 'Port', 'Neighbor', 'Port', 'Sent', 'Seen', 'Delay'))
+ self.last_printed = 'not_topo_link'
diff --git a/apps/ofp_proxies.py b/apps/ofp_proxies.py
new file mode 100644
index 0000000..485caaa
--- /dev/null
+++ b/apps/ofp_proxies.py
@@ -0,0 +1,123 @@
+"""
+ This code is used to associate IP address seen to a switch when
+ network slicing is in place.
+ If FlowSpace Firewall or FlowVisor is not used, this module
+ is not useful.
+"""
+
+
+from libs.core.singleton import Singleton
+from libs.core.debugging import debugclass
+from libs.core.topo_reader import TopoReader
+from libs.tcpiplib.packet import LLDP
+from libs.tcpiplib.process_data import is_protocol
+from libs.gen.dpid_handling import clear_dpid
+
+
+@debugclass
+class OFProxy(metaclass=Singleton):
+ """
+ This app is used to help identifying switches when openflow
+ proxies are in the middle, such as flowvisor and fsfw. It is
+ not possible to deactivate it.
+ """
+ def __init__(self):
+ self.dpid_dict = dict() # dpid to alias dict
+ self.proxy_db = dict() # [ip, port] to alias dict
+ self.active = False
+ self.load_topology_dpids()
+
+ def load_topology_dpids(self):
+ """
+ Gets all DPIDs and datapath names from the
+ topology.
+ """
+ topo = TopoReader().get_topology()
+
+ try:
+ for switch in topo['switches']:
+ for dpid in topo['switches'][switch]['dpids']:
+ self.add_dpid(dpid, TopoReader().get_datapath_name(dpid))
+ self.active = True
+ except KeyError:
+ pass
+
+
+ def add_dpid(self, dpid, name):
+ """
+ Add dpid found in the topology to a dict
+
+ Args:
+ dpid: datapath_id
+ name: datapath name
+ """
+ self.dpid_dict[dpid] = name
+
+ def get_datapath_name(self, dpid):
+ """
+ Get the switch name using dpid
+
+ Args:
+ dpid: datapath_id
+ Returns:
+ name: datapath name
+ """
+ try:
+ return self.dpid_dict[dpid]
+ except:
+ return 'DPID_' + str(dpid)
+
+ def add_dpid_to_proxy_db(self, ip_addr, port, dpid):
+ """
+ Receives the IP, TCP port and DPID and save them to the
+ proxy_db. IP and TCP port are the indexes.
+
+ Args:
+ ip_addr: IP address
+ port: TCP port
+ dpid: switch datapath id
+ """
+ dpid = clear_dpid(dpid)
+ self.proxy_db[ip_addr, port] = self.get_datapath_name(dpid)
+
+ def process_packet(self, pkt):
+ """
+ Go through all OFMessages in Pkt.
+ IF FeaturesReply or PacketOut, get the DPID
+
+ pkt: packet class
+ """
+
+ if not self.active:
+ return
+
+ for msg in pkt.ofmsgs:
+ if msg.ofp.header.message_type.value == 6:
+ ip_addr = pkt.l3.s_addr
+ port = pkt.l4.source_port
+ self.add_dpid_to_proxy_db(ip_addr, port, msg.ofp.datapath_id.value)
+
+ elif msg.ofp.header.message_type.value == 13:
+ ip_addr = pkt.l3.d_addr
+ port = pkt.l4.dest_port
+ lldp = is_protocol(msg.ofp.data, lldp=True)
+ if isinstance(lldp, LLDP):
+ self.add_dpid_to_proxy_db(ip_addr, port, lldp.c_id)
+
+ def get_name(self, ip_addr, port):
+ """
+ Method used by the tcpiplib printing to associate
+ ip:port to a switch name
+
+ Args:
+ ip_addr: IP address
+ port: TCP port
+ dpid: switch datapath id
+ """
+ if not self.active:
+ return ip_addr
+
+ for ip_port, name in self.proxy_db.items():
+ if ip_port == (ip_addr, port):
+ return '%s(%s)' % (ip_addr, name)
+ return ip_addr
diff --git a/apps/ofp_stats.py b/apps/ofp_stats.py
new file mode 100644
index 0000000..4314827
--- /dev/null
+++ b/apps/ofp_stats.py
@@ -0,0 +1,147 @@
+"""
+ This app process all OF messages to create statistics
+ export via REST. Main user is Zabbix and SDN-LG
+"""
+
+
+import json
+import time
+from datetime import datetime
+from _thread import start_new_thread as new_thread
+from apps.rest import CreateRest
+from libs.core.singleton import Singleton
+
+
+class OFStats(metaclass=Singleton):
+ """
+ This class processes the OF messages for statistics.
+ """
+
+ def __init__(self):
+ self.start_time = str(datetime.now())
+ self.last_msgs = CircularList()
+ self.num_packets = 0
+ self.type_packets = self.init_type_packets()
+ new_thread(self._run_rest, tuple())
+
+ @staticmethod
+ def init_type_packets():
+ """
+ Initialize all dictionaries
+ """
+ types = dict()
+ types['1'] = dict()
+ types['4'] = dict()
+ return types
+
+ @staticmethod
+ def _run_rest():
+ """
+ This app only exports data via REST.
+ So, load up the REST interface
+ """
+ CreateRest()
+
+ @staticmethod
+ def to_json(msg):
+ """
+ Convert dictionaries to JSON to export
+ via REST
+ Args:
+ msg: message to be converted
+ Returns:
+ json.dumps
+ """
+ result = dict()
+ result['result'] = msg
+ return json.dumps(result)
+
+ @staticmethod
+ def get_unix_time():
+ """
+ Returns datetime.now() in unixstamp format.
+ """
+ date = datetime.now()
+ return time.mktime(date.timetuple())
+
+ @staticmethod
+ def get_time():
+ """
+ Returns datetime.now() in string format.
+ """
+ return str(datetime.now())
+
+ # REST Methods
+ def get_start_time(self):
+ """
+ Just return when the ofp_sniffer started
+ """
+ msg = {'start_time': self.start_time}
+ return self.to_json(msg)
+
+ def get_counter(self):
+ """
+ Get counters via REST
+ """
+ msg = dict()
+ msg['current_time'] = self.get_time()
+ msg['total_packets'] = self.num_packets
+ msg['per_types'] = self.type_packets
+ return self.to_json(msg)
+
+ def get_last_msgs(self):
+ """
+ Get the last messages seen
+ """
+ return self.to_json(self.last_msgs.items)
+
+ # Main Methods
+
+ def process_packet(self, pkt):
+ """
+ Method called by ofp_sniffer.py to process the OF message
+ """
+ self.num_packets += 1
+
+ for of_msg in pkt.ofmsgs:
+ version = str(of_msg.ofp.header.version.value)
+ message_type = str(of_msg.ofp.header.message_type)
+ message_type = message_type.split('.')[1]
+ try:
+ self.type_packets[version][message_type] += 1
+ except KeyError:
+ self.type_packets[version][message_type] = 1
+
+ self.last_msgs.add(of_msg.ofp)
+
+
+class CircularList(object):
+ """
+ This class only creates a new type: a CircularList.
+ The idea is to export the last LIMIT messages via REST.
+ """
+ LIMIT = 500
+
+ def __init__(self):
+ self._queue = dict()
+ self._num_items = 0
+
+ @property
+ def items(self):
+ """
+ Return all items
+ """
+ return self._queue
+
+ def add(self, msg):
+ """
+ Add an OF message to the CircularList
+ """
+
+ if self._num_items < self.LIMIT - 1:
+ self._queue[self._num_items] = {'time': str(datetime.now()),
+ 'type': msg.header.message_type}
+ self._num_items += 1
+ elif self._num_items == self.LIMIT - 1:
+ self._queue[self._num_items] = msg
+ self._num_items = 0
diff --git a/apps/rest.py b/apps/rest.py
new file mode 100644
index 0000000..d1a830a
--- /dev/null
+++ b/apps/rest.py
@@ -0,0 +1,34 @@
+"""
+ This app creates the REST interface to be used
+ by all apps that want to.
+"""
+from flask import Flask
+import apps.ofp_stats
+
+
+app = Flask(__name__)
+
+
+class CreateRest(object):
+
+ def __init__(self):
+ self.run()
+
+ @staticmethod
+ @app.route("/ofp_sniffer/ofp_stats/start_time")
+ def start_time():
+ return apps.ofp_stats.OFStats().get_start_time()
+
+ @staticmethod
+ @app.route("/ofp_sniffer/ofp_stats/packet_totals")
+ def index():
+ return apps.ofp_stats.OFStats().get_counter()
+
+ @staticmethod
+ @app.route("/ofp_sniffer/ofp_stats/last_msgs")
+ def last_msgs():
+ return apps.ofp_stats.OFStats().get_last_msgs()
+
+ @staticmethod
+ def run():
+ app.run(host='0.0.0.0')
diff --git a/docs/devices_list.json b/docs/devices_list.json
new file mode 100644
index 0000000..403920c
--- /dev/null
+++ b/docs/devices_list.json
@@ -0,0 +1,9 @@
+{
+ "cc4e249102000000": "andes2",
+ "cc4e249126000000": "andes1",
+ "cc4e244b11000000": "sol2",
+ "0024389406000000": "mct01",
+ "002438af17000000": "mct02",
+ "2438af17000000": "mct02",
+ "24389406000000": "mct01"
+}
\ No newline at end of file
diff --git a/docs/filters.json b/docs/filters.json
new file mode 100644
index 0000000..bd0ac12
--- /dev/null
+++ b/docs/filters.json
@@ -0,0 +1,34 @@
+{
+ "allowed_of_versions": {
+ "1.0": {
+ "rejected_of_types": [
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21
+ ]
+ },
+ "1.3": {
+ "rejected_of_types": [
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29
+ ]
+ }
+ },
+ "filters":{
+ "ethertypes": {
+ "lldp" : 0,
+ "fvd" : 0,
+ "arp" : 0,
+ "others": [ "88b5" ]
+ },
+ "packetIn_filter": {
+ "switch_dpid": "any",
+ "in_port": "any"
+ },
+ "packetOut_filter": {
+ "switch_dpid": "any",
+ "out_port": "any"
+ }
+ }
+}
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 0000000..47438ba
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1,6 @@
+termcolor
+hexdump
+netaddr
+pcapy
+python-openflow
+flask
\ No newline at end of file
diff --git a/docs/topology.json b/docs/topology.json
new file mode 100644
index 0000000..51d367c
--- /dev/null
+++ b/docs/topology.json
@@ -0,0 +1,48 @@
+{
+ "switches": {
+ "sw1": {
+ "aliases": ["sw1", "switch01"],
+ "dpids": ["1", "0000000000000001"],
+ "ports": {
+ "eth1": {"alias": "eth1", "ofport_no": 1, "snmp_no:": 1, "type": "link", "speed": "10G"},
+ "eth2": {"alias": "eth2", "ofport_no": 2, "snmp_no:": 2, "type": "link", "speed": "10G"},
+ "eth3": {"alias": "eth3", "ofport_no": 3, "snmp_no:": 3, "type": "link", "speed": "10G"}
+ }
+ },
+ "sw2": {
+ "aliases": ["sw2", "switch02"],
+ "dpids": ["2", "0000000000000002"],
+ "ports": {
+ "eth1": {"alias": "eth1", "ofport_no": 1, "snmp_no:": 1, "type": "link", "speed": "10G"},
+ "eth2": {"alias": "eth2", "ofport_no": 2, "snmp_no:": 2, "type": "link", "speed": "10G"},
+ "eth3": {"alias": "eth3", "ofport_no": 3, "snmp_no:": 3, "type": "link", "speed": "10G"}
+ }
+ },
+ "sw3": {
+ "aliases": ["sw3", "switch03"],
+ "dpids": ["3", "0000000000000003"],
+ "ports": {
+ "eth1": {"alias": "eth1", "ofport_no": 1, "snmp_no:": 1, "type": "link", "speed": "10G"},
+ "eth2": {"alias": "eth2", "ofport_no": 2, "snmp_no:": 2, "type": "link", "speed": "10G"},
+ "eth3": {"alias": "eth3", "ofport_no": 3, "snmp_no:": 3, "type": "link", "speed": "10G"}
+ }
+ }
+ },
+
+ "links": {
+ "link1": {
+ "aliases": ["link1"],
+ "datapath_a": "sw1",
+ "port_a": "eth1",
+ "datapath_z": "sw2",
+ "port_z": "eth1"
+ },
+ "link2": {
+ "aliases": ["link2"],
+ "datapath_a": "sw2",
+ "port_a": "eth2",
+ "datapath_z": "sw3",
+ "port_z": "eth1"
+ }
+ }
+}
diff --git a/example_filter.json b/example_filter.json
deleted file mode 100644
index b231b6e..0000000
--- a/example_filter.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "allowed_of_versions": {
- "1.0": {
- "rejected_of_types": [
- 2,
- 3,
- 10,
- 13
- ]
- },
- "1.3": {
- "rejected_of_types": [
- 2,
- 3,
- 10,
- 13
- ]
- }
- },
- "packetIn_filter": {
- "switch_dpid": "any",
- "in_port": "any"
- },
- "packetOut_filter": {
- "switch_dpid": "dpid:5",
- "out_port": "any"
- },
- "flowMod_logs": {
- "filter_1": {
- "match": {
- "vlan": "any",
- "in_port": "1"
- },
- "action": {
- "output": "2",
- "mod_dl_src": "14"
- },
- "label": "onos"
- },
- "filter_2": {
- "match": {
- "any": "any"
- },
- "action": {
- "mod_dl_dst": "any"
- },
- "label": "oess_test"
- },
- "filter_3": {
- "match": {
- "in_port": "4"
- },
- "action": {
- "any": "any"
- },
- "label": "fibre"
- },
- "all": {
- "match": {
- "any": "any"
- },
- "action": {
- "any": "any"
- },
- "label": 0
- }
- }
-}
diff --git a/libs/__init__.py b/libs/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/libs/core/__init__.py b/libs/core/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/libs/core/cli.py b/libs/core/cli.py
new file mode 100644
index 0000000..aa1b295
--- /dev/null
+++ b/libs/core/cli.py
@@ -0,0 +1,166 @@
+"""
+ This code handles the CLI parameters
+"""
+
+
+import sys
+import getopt
+import pcapy
+from libs.core.printing import PrintingOptions
+
+
+VERSION = '0.4'
+# Change variable below to activate debugging
+DEBUGGING = False
+
+
+def usage(filename, msg=None):
+ """
+ This funcion prints the Usage in case of errors or help needed.
+ Always ends after printing this lines below.
+ Args:
+ filename: name of the script called (usually ofp_sniffer.py)
+ msg: an error msg
+ """
+ if msg is not None:
+ print(msg)
+
+ print(('Usage: \n %s [-p min|full] [-f pcap_filter] [-F filter_file]'
+ ' [-i dev] [-r pcap_file]\n'
+ '\t -p : print full headers'
+ ' packet headers. Default: min\n'
+ '\t -f pcap_filter or --pcap-filter=pcap_filter: add a libpcap'
+ ' filter\n'
+ '\t -F filters_file.json or --filters-file=filters.json\n'
+ '\t -i interface or --interface=interface. Default: eth0\n'
+ '\t -r captured.pcap or --src-file=captured.pcap\n'
+ '\t -P topology.json or --topology-file=topology.json\n'
+ '\t -o or --print-ovs : print using ovs-ofctl format\n'
+ '\t -h or --help : prints this guidance\n'
+ '\t -c or --no-colors: removes colors\n'
+ '\t -v or --version : prints version\n'
+ '\t -O or --oess-fvd: monitor OESS FVD status\n'
+ '\t -S or --enable-statistics: creates statistics') % filename)
+
+ sys.exit(0)
+
+
+def check_file_position(filename):
+ """
+ Check if -r file was inserted with colon (:)
+ If yes, only read the position specified after colon
+ Args:
+ filename: User's input -r
+ Returns:
+ position number
+ """
+ new_file = filename.partition(":")[0]
+ position = filename.partition(":")[2]
+ return new_file, int(position) if len(position) is not 0 else 0
+
+
+def start_capture(capfile, infilter, dev):
+ """
+ With all information in hand, start capturing packets
+ Args:
+ capfile: in case user provides a pcap file
+ infilter: any tcpdump filters
+ dev: network device to sniffer
+ Returns:
+ cap object
+ position number
+ """
+ position = 0
+ try:
+ if len(capfile) > 0:
+ capfile, position = check_file_position(capfile)
+ print("Using file %s " % capfile)
+ cap = pcapy.open_offline(capfile)
+ else:
+ print("Sniffing device %s" % dev)
+ cap = pcapy.open_live(dev, 65536, 1, 0)
+
+ except Exception as exception:
+ print("Error: %s" % exception)
+ print("Exiting...")
+ sys.exit(3)
+
+ if len(infilter) is 0:
+ infilter = " port 6633 "
+ cap.setfilter(infilter)
+
+ return cap, position
+
+
+def read_params(argv):
+ """
+ Parser params received via CLI
+
+ Args:
+ argv: inputs
+ Return:
+ opts: getopt object
+ """
+ letters = 'f:F:i:r:T:pohvcOSq'
+ keywords = ['pcap-filter=', 'filters-file=', 'interface=',
+ 'src-file=', 'print-ovs', 'help', 'version', 'no-colors',
+ 'topology-file=', 'oess-fvd', 'enable-statistics', 'no-output']
+
+ try:
+ opts, _ = getopt.getopt(argv[1:], letters, keywords)
+ return opts
+ except getopt.GetoptError as err:
+ usage(argv[0], err)
+
+
+def get_params(argv):
+ """
+
+ Get CLI params provided by user
+ Args:
+ argv: CLI params
+ Returns:
+ cap: pcap object
+ position: packet number to read
+ load_apps: apps to load
+ filters_file: filters
+ """
+ # Default Values
+ input_filter, filters_file, dev, captured_file = '', '', 'eth0', ''
+ topology_file = "./docs/topology.json"
+ load_apps = []
+
+ opts = read_params(argv)
+
+ for option, param in opts:
+ if option in ['-p']:
+ PrintingOptions().min = False
+ elif option in ['-f', '--pcap-filter']:
+ input_filter = param
+ elif option in ['-F', '--filters-file']:
+ filters_file = param
+ elif option in ['-i', '--interface']:
+ dev = param
+ elif option in ['-r', '--captured-file']:
+ captured_file = param
+ elif option in ['-o', '--print-ovs']:
+ PrintingOptions().print_ovs = True
+ elif option in ['-T', '--topology-file']:
+ topology_file = param
+ elif option in ['-c', '--no-colors']:
+ PrintingOptions().colors = False
+ elif option in ['-q', '--no-output']:
+ PrintingOptions().set_no_print()
+ elif option in ['-O', '--oess-fvd']:
+ load_apps.append('oess_fvd')
+ elif option in ['-S', '--enable-statistics']:
+ load_apps.append('statistics')
+ elif option in ['-v', '--version']:
+ print('OpenFlow Sniffer version %s' % VERSION)
+ sys.exit(0)
+ else:
+ usage(argv[0])
+
+ cap, position = start_capture(captured_file, input_filter, dev)
+
+ return cap, position, load_apps, filters_file, topology_file
diff --git a/libs/core/debugging.py b/libs/core/debugging.py
new file mode 100644
index 0000000..3a5b5f4
--- /dev/null
+++ b/libs/core/debugging.py
@@ -0,0 +1,41 @@
+"""
+ Module created just to help with debugging
+"""
+
+
+from functools import wraps
+import libs.core.cli
+
+
+def debug(func):
+ """
+ Decorator to help troubleshooting
+ Prints method names
+ Args:
+ func:
+ Returns:
+ """
+ @wraps(func)
+ def wrapper(*args, **kwargs):
+ """
+ Wraps to preserve docs
+ """
+ print('*** %s' % func.__name__)
+ return func(*args, **kwargs)
+ return wrapper
+
+
+def debugclass(cls):
+ """
+ Decorator to help troubleshooting classes
+ Call debug for each method of the cls
+ Args:
+ cls: Any Class to be printed
+ Returns: wrapper with cls, printing all method names
+ """
+ if libs.core.cli.DEBUGGING:
+ for key, val in vars(cls).items():
+ if callable(val):
+ setattr(cls, key, debug(val))
+
+ return cls
diff --git a/libs/core/filters.py b/libs/core/filters.py
new file mode 100644
index 0000000..9eb876f
--- /dev/null
+++ b/libs/core/filters.py
@@ -0,0 +1,220 @@
+"""
+ Filters to be used
+ Any customized print filters should be inserted in this file
+ Filters are provided via CLI option -F json-file
+"""
+
+
+from libs.core.printing import PrintingOptions
+from libs.core.sanitizer import Sanitizer
+from libs.tcpiplib.tcpip import get_ofp_version
+from libs.tcpiplib.process_data import is_protocol
+from libs.tcpiplib.process_data import get_protocol
+from libs.gen.dpid_handling import clear_dpid
+
+
+def filter_msg(msg):
+ """
+ This method will be the core of all filters. Any new filter comes here
+ Args:
+ msg: OFMessage class
+ Returns:
+ False: Don't filter packet
+ True: Filter it (don't print)
+ """
+
+ if PrintingOptions().quiet:
+ # Don't print anything. Used in conjunction with some apps.
+ return True
+
+ if PrintingOptions().filters is 0:
+ # User hasn't selected CLI option -F
+ return False
+
+ # Filter per OF Version
+ if filter_of_version(msg):
+ return True
+
+ # Filter per OF Message Type
+ if filter_of_type(msg):
+ return True
+
+ # Filter Ethertypes from PacketIn/Out messages
+ if ethertype_filters(msg):
+ return True
+
+ # Filter PacketIn/Out based on DPID and Port
+ if dpid_filters(msg):
+ return True
+
+ # Don't filter
+ return False
+
+
+def filter_of_version(msg):
+ """
+ Check if the OpenFlow version is allowed
+ Args:
+ msg: OFMessage class
+ Returns:
+ False: Don't filter packet
+ True: Filter it (don't print)
+ """
+ name_version = get_ofp_version(msg.ofp.header.version.value)
+ supported_versions = []
+ try:
+ for version in Sanitizer().allowed_of_versions:
+ supported_versions.append(version)
+ if name_version not in supported_versions:
+ return True
+ except KeyError:
+ pass
+ return False
+
+
+def filter_of_type(msg):
+ """
+ Filter per OF Message Type
+ Args:
+ msg: OFMessage class
+ Returns:
+ False: Don't filter packet
+ True: Filter it (don't print)
+ """
+ name_version = get_ofp_version(msg.ofp.header.version.value)
+ # OF Types to be ignored through json file (-F)
+ try:
+ rejected_types = Sanitizer().allowed_of_versions[name_version]
+ if msg.ofp.header.message_type in rejected_types['rejected_of_types']:
+ return True
+ except KeyError:
+ pass
+ return False
+
+
+def ethertype_filters(msg):
+ """
+ Filter PacketIn and PacketOut messages based on Ethertype
+ Sanitizer filter (-F), entry "filters", "ethertype"
+ Args:
+ msg: class OFMessage
+ Returns:
+ False: Don't filter packet
+ True: Filter it (don't print)
+ """
+ if msg.ofp.header.message_type in [10, 13]:
+ try:
+ filters = Sanitizer().filters['ethertypes']
+ except KeyError:
+ return False
+
+ if not len(filters):
+ # No filters
+ return False
+
+ # Go to payload
+ try:
+ if is_protocol(msg.ofp.data, lldp=True) and filters['lldp']:
+ return True
+ if is_protocol(msg.ofp.data, oess=True) and filters['fvd']:
+ return True
+ if is_protocol(msg.ofp.data, arp=True) and filters['arp']:
+ return True
+ except KeyError:
+ pass
+
+ # Other Ethertypes listed as hex
+ for protocol in filters['others']:
+ try:
+ if is_protocol(msg.ofp.data) == int(protocol, 16):
+ return True
+ except ValueError:
+ pass
+
+ return False
+
+
+def dpid_filters(msg):
+ """
+ Filter PacketIn and PacketOut messages based on DPID and ports
+ Sanitizer filter (-F), entry "filters", "packetIn_filter" or
+ "packetOut_filter"
+ If switch_dpid AND in_port are Any, don't filter (print it)
+ If switch_dpid OR in_port are NOT Any, print only what matches the
+ most specific (filter everything else)
+ Args:
+ msg: class OFMessage
+ Returns:
+ False: Don' filter packet (print it)
+ True: Filter it (don't print)
+ """
+
+ # It has to be a PacketOut or PacketIn
+ if msg.ofp.header.message_type not in [10, 13]:
+ return False
+
+ # It has to be a LLDP packet
+ if not is_protocol(msg.ofp.data, lldp=True):
+ return False
+
+ try:
+ # If it is a PacketIn ...
+ if msg.ofp.header.message_type in [10]:
+ # It has to have a packetIn_filter filter
+ filters = Sanitizer().filters['packetIn_filter']
+ filter_port = filters['in_port']
+
+ # If it a PacketOut...
+ else:
+ # It has to have a packetOut_filter filter
+ filters = Sanitizer().filters['packetOut_filter']
+ filter_port = filters['out_port']
+
+ filter_dpid = filters['switch_dpid']
+
+ except KeyError:
+ return False
+ if not len(filters):
+ return False
+
+ # Was switch_dpid or in_port specified by user?
+ if filter_dpid in ['any', 'Any', 'ANY']:
+ if filter_port in ['any', 'Any', 'ANY']:
+ return False
+
+ # If we got here, it means we have content to avoid printing
+ print_it = False
+ lldp_msg = get_protocol(msg.ofp.data, lldp=True)
+ switch_dpid = clear_dpid(filter_dpid)
+
+ if print_switch_dpid(switch_dpid, lldp_msg.c_id):
+ if msg.ofp.header.message_type in [10]:
+ if print_port(filter_port, str(msg.ofp.in_port)):
+ print_it = True
+ else:
+ if print_port(filter_port, str(lldp_msg.p_id)):
+ print_it = True
+
+ if print_it:
+ return False
+
+ return True
+
+
+def print_switch_dpid(filter_dpid, packet_dpid):
+ """
+ Confirm if filter_dpid is packet_dpid or any
+ """
+ packet_dpid = clear_dpid(packet_dpid)
+ if filter_dpid in [packet_dpid, 'Any', 'any', 'ANY']:
+ return True
+ return False
+
+
+def print_port(filter_port, packet_port):
+ """
+ Confirm if filter_port is packet_port or any
+ """
+ if filter_port in [packet_port, 'Any', 'any', 'ANY']:
+ return True
+ return False
diff --git a/libs/core/printing.py b/libs/core/printing.py
new file mode 100644
index 0000000..6f5bac9
--- /dev/null
+++ b/libs/core/printing.py
@@ -0,0 +1,25 @@
+"""
+ Class with CLI printing options
+"""
+from libs.core.singleton import Singleton
+
+
+class PrintingOptions(metaclass=Singleton):
+ """
+ This is a Singleton class with all printing
+ options.
+ """
+
+ def __init__(self):
+ self.min = 1 # print minimal headers
+ self.colors = True # print colors
+ self.filters = 0 # apply filters
+ self.proxy = 0 # add proxy support
+ self.print_ovs = False # print ovs format
+ self.quiet = False # don't print anything
+
+ def set_no_print(self):
+ """
+ Set to avoiding printing.
+ """
+ self.quiet = True
diff --git a/libs/core/sanitizer.py b/libs/core/sanitizer.py
new file mode 100644
index 0000000..727a668
--- /dev/null
+++ b/libs/core/sanitizer.py
@@ -0,0 +1,63 @@
+"""
+ Filters/Sanitizer Class
+ Used for filtering specific OpenFlow versions and
+ message types. Filters are provided via JSON file
+ in the cli with option -F or --filters-file
+"""
+
+
+import json
+import sys
+from libs.core.singleton import Singleton
+from libs.core.printing import PrintingOptions
+
+
+class Sanitizer(metaclass=Singleton):
+ """
+ Filters/Sanitizer Class
+ Used for filtering specific OpenFlow versions and
+ message types. Filters are provided via JSON file
+ in the cli with option -F or --filters-file
+ """
+
+ def __init__(self):
+ self.allowed_of_versions = dict()
+ self.filters = dict()
+
+ @staticmethod
+ def read_file(filters_file):
+ """
+ Read the JSON file provided through -F
+ Args:
+ filters_file: file provided
+ Returns:
+ json content of the file provided
+ """
+ try:
+ with open(filters_file) as jfile:
+ json_content = json.loads(jfile.read())
+
+ except Exception as error:
+ msg = 'Error Opening the sanitizer file\n'
+ msg += 'Please check your JSON file. Maybe the permission is wrong'
+ msg += ' or the JSON syntax is incorrect. Try the following:\n'
+ msg += 'cat %s | python -m json.tool'
+ print(msg % filters_file)
+ print("Error seen: %s" % error)
+ sys.exit(0)
+ return json_content
+
+ def process_filters(self, filters_file):
+ """
+ If -F file is provided, read the file and import all filters.
+ Args:
+ filters_file: file with filters
+
+ """
+ if len(filters_file) == 0:
+ return
+ configs = self.read_file(filters_file)
+ if len(configs) != 0:
+ PrintingOptions().filters = 1
+ self.allowed_of_versions = configs['allowed_of_versions']
+ self.filters = configs['filters']
diff --git a/libs/core/singleton.py b/libs/core/singleton.py
new file mode 100644
index 0000000..48a969c
--- /dev/null
+++ b/libs/core/singleton.py
@@ -0,0 +1,16 @@
+"""
+ Metaclass do define singleton classes
+ Taken from http://stackoverflow.com/questions/6760685/creating-a-singleton-in-python
+"""
+
+
+class Singleton(type):
+ """
+ Singleton Class
+ """
+ _instances = {}
+
+ def __call__(cls, *args, **kwargs):
+ if cls not in cls._instances:
+ cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
+ return cls._instances[cls]
diff --git a/libs/core/topo_reader.py b/libs/core/topo_reader.py
new file mode 100644
index 0000000..3d0a713
--- /dev/null
+++ b/libs/core/topo_reader.py
@@ -0,0 +1,171 @@
+"""
+ Class to read the topology.json file in use at AmLight
+"""
+
+
+import json
+from libs.core.singleton import Singleton
+
+
+class TopoReader(metaclass=Singleton):
+ """
+ Under construction
+ """
+
+ def __init__(self):
+ self._dpids = {}
+ self._links = {}
+ self._port_map = {}
+ self._topology = None
+
+ def add_datapath(self, switch):
+ """
+
+ :param switch:
+ :return:
+ """
+ for dpid in switch["dpids"]:
+ self._dpids[dpid] = switch["aliases"][0]
+
+ for port in switch["ports"]:
+ alias = switch["ports"][port]["alias"]
+ ofport_no = switch["ports"][port]["ofport_no"]
+ self._port_map[switch["aliases"][0], ofport_no] = alias
+
+ def add_datapath_port(self, switch, port):
+ """
+
+ :param switch:
+ :param port:
+ :return:
+ """
+ pass
+
+ def add_link(self, link):
+ """
+
+ :param link:
+ :return:
+ """
+ self._links[link["datapath_a"], link["port_a"],
+ link["datapath_z"], link["port_z"]] = link["aliases"]
+ self._links[link["datapath_z"], link["port_z"],
+ link["datapath_a"], link["port_a"]] = link["aliases"]
+
+ def get_datapath_name(self, dpid=None):
+ """
+
+ :param dpid:
+ :return:
+ """
+ try:
+ if dpid.find(":"):
+ dpid = dpid.replace(":", "")
+
+ return self._dpids[dpid]
+ except KeyError:
+ return dpid
+
+ def get_datapath_id(self, alias=None):
+ """
+
+ :param alias:
+ :return:
+ """
+ pass
+
+ def get_port_name(self, dpid=None, port_no=None):
+ """
+
+ :param dpid:
+ :param port_no:
+ :return:
+ """
+ try:
+ return self._port_map[dpid, port_no]
+ except KeyError:
+ return port_no
+
+ def get_port_id(self, dpid=None, alias=None):
+ """
+
+ :param dpid:
+ :param alias:
+ :return:
+ """
+ pass
+
+ def clear_dpid(self, dpid):
+ """
+
+ :param dpid:
+ :return:
+ """
+ return self.get_datapath_name(dpid)
+
+ def get_link_aliases(self, dp_a, port_a, dp_z, port_z, option="Full"):
+ """
+
+ :param dp_a:
+ :param port_a:
+ :param dp_z:
+ :param port_z:
+ :param option:
+ :return:
+ """
+ dp_a = self.clear_dpid(dp_a)
+ dp_z = self.clear_dpid(dp_z)
+
+ port_a = self.get_port_name(dp_a, port_a)
+ port_z = self.get_port_name(dp_z, port_z)
+
+ try:
+ if option == "First":
+ return self._links[dp_a, port_a, dp_z, port_z][0]
+ elif option == "Full":
+ return self._links[dp_a, port_a, dp_z, port_z][1]
+ return self._links[dp_a, port_a, dp_z, port_z]
+ except KeyError:
+ return {}
+
+ def get_link_config(self, alias=None):
+ """
+
+ :param alias:
+ :return:
+ """
+ try:
+ for link in self._topology["links"]:
+
+ if alias in self._topology["links"][link]["aliases"]:
+ link = self._topology["links"][link]
+ return (link["datapath_a"], link["port_a"],
+ link["datapath_z"], link["port_z"])
+ except KeyError:
+ return {}
+
+ def get_topology(self):
+ """
+
+ :return:
+ """
+ return self._topology
+
+ def readfile(self, topo_file):
+ """
+
+ Args:
+ topo_file:
+ """
+ try:
+ with open(topo_file) as jfile:
+ self._topology = json.loads(jfile.read())
+ except Exception as error:
+ print("Error %s " % error)
+ return
+
+ for switch in self._topology['switches']:
+ self.add_datapath(self._topology['switches'][switch])
+
+ for link in self._topology['links']:
+ self.add_link(self._topology['links'][link])
diff --git a/libs/gen/__init__.py b/libs/gen/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/libs/gen/dpid_handling.py b/libs/gen/dpid_handling.py
new file mode 100644
index 0000000..1b10b49
--- /dev/null
+++ b/libs/gen/dpid_handling.py
@@ -0,0 +1,48 @@
+"""
+ This module does all DPID cleaning needed by all other modules,
+ such as removing substrings 'dpid:', removing ':' and others
+"""
+
+
+def clear_dpid(dpid):
+ """
+ clear_dpid removes any non useful info from DPID. Some
+ examples of DPIDs:
+
+ "dpid:11:11:11:11:11:11"
+ "dp:11:11:11:11:11:11"
+ "11:11:11:11:11:11"
+ "111111111111"
+
+ The goal is to return the last one: "111111111111"
+
+ Args:
+ dpid: dpid to be fixed
+
+ Returns:
+ dpid fixed
+
+ >>> clear_dpid("dpid:11:11:11:11:11:11")
+ '111111111111'
+ >>> clear_dpid("dp:11:11:11:11:11:11")
+ '111111111111'
+ >>> clear_dpid("11:11:11:11:11:11")
+ '111111111111'
+ >>> clear_dpid("111111111111")
+ '111111111111'
+ """
+ dpid_names = ["dpid:", "dp:"]
+
+ for dpid_name in dpid_names:
+ pos = dpid.find(dpid_name)
+ if pos != -1:
+ # substring found
+ dpid = dpid[pos+len(dpid_name):]
+
+ if len(dpid.split(":")) == 2:
+ return dpid.split(":")[1]
+
+ elif len(dpid.split(":")) > 2:
+ return dpid.replace(":", "")
+
+ return dpid
diff --git a/libs/gen/ofmessage.py b/libs/gen/ofmessage.py
new file mode 100644
index 0000000..528d3f8
--- /dev/null
+++ b/libs/gen/ofmessage.py
@@ -0,0 +1,54 @@
+"""
+ This is the class for the OpenFlow message. With the python-openflow
+ library, introduced in the version 0.4, this class became much
+ simpler.
+"""
+
+from pyof.v0x01.common.utils import unpack_message
+import libs.core.filters
+import libs.tcpiplib.packet
+import libs.tcpiplib.prints
+from libs.core.debugging import debugclass
+from libs.openflow.of10.prints import prints_ofp
+
+
+@debugclass
+class OFMessage(object):
+ """
+ Used to process all data regarding this OpenFlow message. With
+ the python-openflow (pyof) lib, only one variable became
+ necessary.
+ """
+ def __init__(self, this_packet):
+ """
+ Instantiate OFMessage class
+ Args:
+ self: this class
+ this_packet: OpenFlow msg in binary format
+ """
+ try:
+ self.ofp = unpack_message(this_packet)
+ except:
+ # if there is a problem with the python-openflow
+ # just set the self.ofp to 0. It will be ignored
+ # by the Packet().add_of_msg_to_list
+ self.ofp = 0
+
+ def print_packet(self, pkt):
+ """
+ Generic printing function
+ Args:
+ pkt: Packet class
+ """
+ # Check if there is any printing filter
+ if not libs.core.filters.filter_msg(self):
+ # Only prints TCP/IP header once
+ # A TCP/IP packet might contain multiple OpenFlow messages
+ if pkt.printed_header is False:
+ libs.tcpiplib.prints.print_headers(pkt)
+ pkt.printed_header = True
+ # Print OpenFlow header - version independent
+ libs.tcpiplib.prints.print_openflow_header(self.ofp)
+ # Print OpenFlow message body
+ prints_ofp(self.ofp)
+ print()
diff --git a/libs/gen/packet.py b/libs/gen/packet.py
new file mode 100644
index 0000000..75dbcd6
--- /dev/null
+++ b/libs/gen/packet.py
@@ -0,0 +1,142 @@
+"""
+ Class Packet: used to process EACH IP packet. Each IP packet
+ might have multiple OpenFlow messages (class OFMessage)
+"""
+import libs.tcpiplib.packet
+import libs.tcpiplib.prints
+from libs.core.debugging import debugclass
+from libs.gen.ofmessage import OFMessage
+from libs.tcpiplib.packet import IP_PROTOCOL, TCP_PROTOCOL, TCP_FLAG_PUSH
+from libs.tcpiplib.tcpip import get_openflow_header
+
+
+@debugclass
+class Packet:
+ """
+ Used to save all data about the TCP/IP packet
+ """
+ def __init__(self, packet, packet_number, header):
+ """
+ Instantiate this class
+ Args:
+ packet: the whole captured packet from NIC or pcap file
+ packet_number: position of this packet in the packet capture
+ header: packet header
+ """
+ # Raw packet
+ self.packet = packet
+
+ # Controls
+ self.position = packet_number
+ self.offset = 0
+ self.is_openflow_packet = False
+ self.printed_header = False
+ self.this_packet = None
+ self.remaining_bytes = None
+
+ # Instantiate TCP/IP headers
+ self.l1 = libs.tcpiplib.packet.L1()
+ self.l2 = libs.tcpiplib.packet.Ethernet()
+ self.l3 = libs.tcpiplib.packet.IP()
+ self.l4 = libs.tcpiplib.packet.TCP()
+
+ # OpenFlow messages Array
+ # As multiple OpenFlow messages per packet is possible
+ # an list of messages needs to be created
+ self.cur_msg = 0
+ self.ofmsgs = []
+
+ # Process packet
+ self.process_packet_header(header)
+
+ def process_packet_header(self, header):
+ """
+ Process TCP/IP Header, from Layer 1 to TCP.
+ Each layer has a different class. Methods parse are used
+ per layer to dissect it
+ Args:
+ header: header of the captured packet
+ """
+ self.l1.parse(header)
+ self.offset = self.l2.parse(self.packet)
+ if self.l2.protocol == IP_PROTOCOL:
+ self.offset = self.l3.parse(self.packet, self.offset)
+ if self.l3.protocol == TCP_PROTOCOL:
+ self.offset = self.l4.parse(self.packet, self.offset)
+ if self.l4.flag_psh == TCP_FLAG_PUSH:
+ self.is_openflow_packet = True
+ elif self.l4.flag_fyn and self.l4.flag_ack:
+ libs.tcpiplib.prints.print_connection_restablished(self)
+
+ def process_openflow_messages(self):
+ """
+ Because an IP packet can have multiple OpenFlow messages
+ let's get all of them here.
+ """
+ self.remaining_bytes = self.get_remaining_bytes()
+
+ while self.remaining_bytes >= 8:
+ # self.this_packet is the OpenFlow message
+ # let's get the current OpenFlow message from the packet
+ length = self.get_of_message_length()
+ if length < 8:
+ # MalFormed Packet - it could be a fragment
+ return False
+
+ self.this_packet = self.packet[self.offset:self.offset+length]
+ if len(self.this_packet) != length:
+ # it means packet is smaller than it should be
+ # propably MTU issue or message was cut by the datapath
+ return False
+
+ self.add_of_msg_to_list(OFMessage(self.this_packet))
+
+ self.remaining_bytes -= length
+ self.offset += length
+
+ # If there are other OpenFlow messages, let's continue
+ if self.remaining_bytes >= 8:
+ self.cur_msg += 1
+
+ return True
+
+ def add_of_msg_to_list(self, ofmsg):
+ """
+ Instantiate the OpenFlow message in the ofmsgs array
+ A TCP/IP packet might contain multiple OpenFlow messages
+ Process the content, using cur_msg position of the array of msgs
+ """
+ try:
+ if isinstance(ofmsg, OFMessage):
+ if not isinstance(ofmsg.ofp, int):
+ self.ofmsgs.insert(self.cur_msg, ofmsg)
+
+ else:
+ raise TypeError
+
+ except TypeError as err:
+ print("ERROR on Packet no. %s: " % self.position, end='')
+ print(err)
+ print()
+ return ofmsg
+
+ def print_packet(self):
+ """
+ This method iterate over the self.ofmsgs (array of OF messages),
+ printing each one of them.
+ """
+ for msg in self.ofmsgs:
+ msg.print_packet(self)
+
+ def get_remaining_bytes(self):
+ """
+ Calculate how many bytes to be processed
+ """
+ return self.l1.caplen - self.offset
+
+ def get_of_message_length(self):
+ """
+ Get the openflow header length
+ """
+ of_h = get_openflow_header(self.packet, self.offset)
+ return of_h['length']
diff --git a/libs/gen/prints.py b/libs/gen/prints.py
new file mode 100644
index 0000000..ccfa977
--- /dev/null
+++ b/libs/gen/prints.py
@@ -0,0 +1,72 @@
+"""
+ Generic printing: colors
+"""
+
+
+from termcolor import colored
+from libs.core.printing import PrintingOptions
+
+
+def red(string):
+ """
+ If PrintingOptions().colors, prints string
+ in the color RED
+
+ Args:
+ string: text to be printed
+ """
+ if PrintingOptions().colors is False:
+ return string
+ return colored(string, 'red')
+
+
+def green(string):
+ """
+ If PrintingOptions().colors, prints string
+ in the color GREEN
+
+ Args:
+ string: text to be printed
+ """
+ if PrintingOptions().colors is False:
+ return string
+ return colored(string, 'green')
+
+
+def blue(string):
+ """
+ If PrintingOptions().colors, prints string
+ in the color BLUE
+
+ Args:
+ string: text to be printed
+ """
+ if PrintingOptions().colors is False:
+ return string
+ return colored(string, 'blue')
+
+
+def yellow(string):
+ """
+ If PrintingOptions().colors, prints string
+ in the color YELLOW
+
+ Args:
+ string: text to be printed
+ """
+ if PrintingOptions().colors is False:
+ return string
+ return colored(string, 'yellow')
+
+
+def cyan(string):
+ """
+ If PrintingOptions().colors, prints string
+ in the color CYAN
+
+ Args:
+ string: text to be printed
+ """
+ if PrintingOptions().colors is False:
+ return string
+ return colored(string, 'cyan')
diff --git a/libs/openflow/__init__.py b/libs/openflow/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/libs/openflow/of10/__init__.py b/libs/openflow/of10/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/ofp_dissector_v10.py b/libs/openflow/of10/dissector.py
similarity index 61%
rename from ofp_dissector_v10.py
rename to libs/openflow/of10/dissector.py
index 1453bd6..5684639 100644
--- a/ofp_dissector_v10.py
+++ b/libs/openflow/of10/dissector.py
@@ -1,59 +1,45 @@
-'''
+"""
This is the OpenFlow 1.0 dictionary/dissector
- Here messages, types and codes are converted to names
-'''
-
-
-def get_ofp_version(version):
- of_versions = {0: 'Experimental',
- 1: '1.0',
- 2: '1.1',
- 3: '1.2',
- 4: '1.3',
- 5: '1.4',
- 6: '1.5'}
- try:
- return of_versions[version]
- except:
- return 'Unknown(%s)' % version
+ Here messages, types and codes are converted to names.
+"""
def get_ofp_type(of_type):
- of_types = {0: 'Hello',
- 1: 'Error',
- 2: 'EchoReq',
- 3: 'EchoRes',
- 4: 'Vendor',
- 5: 'FeatureReq',
- 6: 'FeatureRes',
- 7: 'GetConfigReq',
- 8: 'GetConfigRes',
- 9: 'SetConfig',
- 10: 'PacketIn',
- 11: 'FlowRemoved',
- 12: 'PortStatus',
- 13: 'PacketOut',
- 14: 'FlowMod',
- 15: 'PortMod',
- 16: 'StatsReq',
- 17: 'StatsRes',
- 18: 'BarrierReq',
- 19: 'BarrierRes',
- 20: 'QueueGetConfigReq',
- 21: 'QueueGetConfigRes'}
+ of_types = {0: 'OFPT_HELLO',
+ 1: 'OFPT_ERROR',
+ 2: 'OFPT_ECHO_REQUEST',
+ 3: 'OFPT_ECHO_REPLY',
+ 4: 'OFPT_VENDOR',
+ 5: 'OFPT_FEATURES_REQUEST',
+ 6: 'OFPT_FEATURES_REPLY',
+ 7: 'OFPT_GET_CONFIG_REQUEST',
+ 8: 'OFPT_GET_CONFIG_REPLY',
+ 9: 'OFPT_SET_CONFIG',
+ 10: 'OFPT_PACKET_IN',
+ 11: 'OFPT_FLOW_REMOVED',
+ 12: 'OFPT_PORT_STATUS',
+ 13: 'OFPT_PACKET_OUT',
+ 14: 'OFPT_FLOW_MOD',
+ 15: 'OFPT_PORT_MOD',
+ 16: 'OFPT_STATS_REQUEST',
+ 17: 'OFPT_STATS_REPLY',
+ 18: 'OFPT_BARRIER_REQUEST',
+ 19: 'OFPT_BARRIER_REPLY',
+ 20: 'OFPT_QUEUE_GET_CONFIG_REQUEST',
+ 21: 'OFPT_QUEUE_GET_CONFIG_REPLY'}
try:
return of_types[of_type]
- except:
+ except KeyError:
return 'UnknownType(%s)' % of_type
def get_ofp_error(error_type, code):
- errors_types = {}
- codes = {}
+ errors_types = dict()
+ error_codes = dict()
- # Starts with an Error
+ # Starts with an Error - exception
errors_types[error_type] = 'UnknownType(%s)' % error_type
- codes[code] = 'UnknownCode(%s)' % code
+ error_codes[code] = 'UnknownCode(%s)' % code
# Error Types
if error_type in range(0, 6):
@@ -67,60 +53,60 @@ def get_ofp_error(error_type, code):
# Error Codes per Error Type
if error_type == 0:
if code in range(0, 2):
- codes = {0: 'Incompatible(0)',
- 1: 'EPerm(1)'}
+ error_codes = {0: 'Incompatible(0)',
+ 1: 'EPerm(1)'}
elif error_type == 1:
if code in range(0, 9):
- codes = {0: 'BadVersion(0)',
- 1: 'BadType(1)',
- 2: 'BadStat(2)',
- 3: 'BadVendor(3)',
- 4: 'BadSubtype(4)',
- 5: 'EPerm(5)',
- 6: 'BadLength(6)',
- 7: 'BufferEmpty(7)',
- 8: 'BufferUnknown(8)'}
+ error_codes = {0: 'BadVersion(0)',
+ 1: 'BadType(1)',
+ 2: 'BadStat(2)',
+ 3: 'BadVendor(3)',
+ 4: 'BadSubtype(4)',
+ 5: 'EPerm(5)',
+ 6: 'BadLength(6)',
+ 7: 'BufferEmpty(7)',
+ 8: 'BufferUnknown(8)'}
elif error_type == 2:
if code in range(0, 9):
- codes = {0: 'BadType',
- 1: 'BadLength',
- 2: 'BadVendor',
- 3: 'BadVendorType',
- 4: 'BadOutPort',
- 5: 'BadArgument',
- 6: 'EPerm',
- 7: 'TooMany',
- 8: 'BadQueue'}
+ error_codes = {0: 'BadType',
+ 1: 'BadLength',
+ 2: 'BadVendor',
+ 3: 'BadVendorType',
+ 4: 'BadOutPort',
+ 5: 'BadArgument',
+ 6: 'EPerm',
+ 7: 'TooMany',
+ 8: 'BadQueue'}
elif error_type == 3:
if code == 0 or code in range(2, 7):
- codes = {0: 'AllTablesFull(0)',
- 2: 'Overlap(2)',
- 3: 'EPerm(3)',
- 4: 'BadEmergTimeout(4)',
- 5: 'BadCommand(5)',
- 6: 'Unsupported(6)'}
+ error_codes = {0: 'AllTablesFull(0)',
+ 2: 'Overlap(2)',
+ 3: 'EPerm(3)',
+ 4: 'BadEmergTimeout(4)',
+ 5: 'BadCommand(5)',
+ 6: 'Unsupported(6)'}
elif error_type == 4:
if code in range(0, 2):
- codes = {0: 'BadPort(0)',
- 1: 'BadHwAddr(1)'}
+ error_codes = {0: 'BadPort(0)',
+ 1: 'BadHwAddr(1)'}
elif error_type == 5:
if code in range(0, 3):
- codes = {0: 'BadPort(0)',
- 1: 'BadQueue(1)',
- 2: 'EPerm(2)'}
+ error_codes = {0: 'BadPort(0)',
+ 1: 'BadQueue(1)',
+ 2: 'EPerm(2)'}
- return errors_types[error_type], codes[code]
+ return errors_types[error_type], error_codes[code]
def get_ofp_vendor(vendor_id):
# NICIRA / OVS: 0x2320 or 8992
if vendor_id == 8992:
- return 'NICIRA(' + hex(vendor_id) + ')'
+ return "NICIRA(%s)" % (hex(vendor_id))
else:
return str(vendor_id)
@@ -133,10 +119,18 @@ def get_ofp_command(command):
4: 'DeleteStrict(4)'}
try:
return commands[command]
- except:
+ except KeyError:
return 'UnknownCommand(%s)' % command
+def get_vlan(vlan):
+ vlans = {65535: 'Untagged(0xFFFF)'}
+ try:
+ return vlans[vlan]
+ except KeyError:
+ return vlan
+
+
def get_ofp_flags(flag):
flags = {0: 'NoFlagSet(0)',
1: 'SendFlowRem(1)',
@@ -144,7 +138,7 @@ def get_ofp_flags(flag):
3: 'Emerg(3)'}
try:
return flags[flag]
- except:
+ except KeyError:
return 'UnknownFlag(%s)' % flag
@@ -154,7 +148,7 @@ def get_flow_removed_reason(reason):
2: 'Delete(2)'}
try:
return rsn[reason]
- except:
+ except KeyError:
return 'UnknownReason(%s)' % reason
@@ -169,7 +163,7 @@ def get_feature_res_capabilities(cap):
128: 'ARP_MATCH_IP(0x80)'}
try:
return caps[cap]
- except:
+ except KeyError:
return 'UnknownCapability(%s)' % cap
@@ -188,7 +182,7 @@ def get_feature_res_actions(action):
2048: 'ENQUEUE(0x800)'}
try:
return actions[action]
- except:
+ except KeyError:
return 'UnknownAction(%s)' % action
@@ -204,7 +198,7 @@ def get_phy_port_id(p_id):
65535: 'None(0xFFFF)'}
try:
return ids[p_id]
- except:
+ except KeyError:
return '%s' % p_id
@@ -218,7 +212,7 @@ def get_phy_config(p_cfg):
64: 'NoPacketIn(0x40)'}
try:
return cfg[p_cfg]
- except:
+ except KeyError:
return 'UnknownConfig(%s)' % p_cfg
@@ -231,7 +225,7 @@ def get_phy_state(p_state):
16: 'STPMask(0x10)'}
try:
return state[p_state]
- except:
+ except KeyError:
return 'UnknownState(%s)' % p_state
@@ -250,7 +244,7 @@ def get_phy_feature(p_feature):
2048: 'PauseAsym(0x800)'}
try:
return ftr[p_feature]
- except:
+ except KeyError:
return 'UnknownFeature(%s)' % p_feature
@@ -261,24 +255,24 @@ def get_configres_flags(flag):
3: 'FRAG_MASK(3)'}
try:
return flags[flag]
- except:
+ except KeyError:
return 'UnknownFlag(%s)' % flag
-def get_portStatus_reason(reason):
+def get_port_status_reason(reason):
reasons = {0: 'OFPPR_ADD(0)',
1: 'OFPPR_DELETE(1)',
2: 'OFPPR_MODIFY(2)'}
try:
return reasons[reason]
- except:
+ except KeyError:
return 'UnknownReason(%s)' % reason
-def get_packetIn_reason(reason):
+def get_packet_in_reason(reason):
reasons = {0: 'OFPR_NO_MATCH(0)',
1: 'OFPR_ACTION(1)'}
try:
return reasons[reason]
- except:
+ except KeyError:
return 'UnknownReason(%s)' % reason
diff --git a/libs/openflow/of10/prints.py b/libs/openflow/of10/prints.py
new file mode 100644
index 0000000..e3b9930
--- /dev/null
+++ b/libs/openflow/of10/prints.py
@@ -0,0 +1,1037 @@
+"""
+ Prints for OpenFlow 1.0 only
+"""
+from hexdump import hexdump
+from pyof.foundation.basic_types import BinaryData
+from pyof.v0x01.common.phy_port import ListOfPhyPorts
+from libs.gen.prints import red, green, yellow
+import libs.tcpiplib.tcpip
+import libs.openflow.of10.dissector as dissector
+from libs.tcpiplib.prints import print_openflow_header
+from libs.tcpiplib.process_data import dissect_data
+
+
+# ******************** Points to the right printing function ****************
+
+
+def prints_ofp(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ Returns:
+
+ """
+
+ try:
+ of_types = {0: print_ofpt_hello,
+ 1: print_ofpt_error,
+ 2: print_ofpt_echo_request,
+ 3: print_ofpt_echo_reply,
+ 4: print_ofpt_vendor,
+ 5: print_ofpt_features_request,
+ 6: print_ofpt_features_reply,
+ 7: print_ofpt_get_config_request,
+ 8: print_ofpt_get_config_reply,
+ 9: print_ofpt_set_config,
+ 10: print_ofpt_packet_in,
+ 11: print_ofpt_flow_removed,
+ 12: print_ofpt_port_status,
+ 13: print_ofpt_packet_out,
+ 14: print_ofpt_flow_mod,
+ 15: print_ofpt_port_mod,
+ 16: print_ofpt_stats_request,
+ 17: print_ofpt_stats_reply,
+ 18: print_ofpt_barrier_request,
+ 19: print_ofpt_barrier_reply,
+ 20: print_ofpt_queue_get_config_request,
+ 21: print_ofpt_queue_get_config_reply}
+
+ return of_types[msg.header.message_type.value](msg)
+ except Exception as err:
+ print("Error: %s" % err)
+
+
+# *************************** OFPT_HELLO *************************************
+
+
+def print_ofpt_hello(msg):
+ """ OFPT_HELLO has no payload, so it does not print anything.
+ It is here just for educational purposes.
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ pass
+
+
+# *************************** OFPT_ERROR **************************************
+
+
+def print_ofpt_error(msg):
+ """ Prints OFPT_ERROR messages. msg.data is the error payload, which is
+ the OpenFlow message that triggered the error.
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ etype, ecode = dissector.get_ofp_error(msg.error_type.value, msg.code.value)
+ print('OpenFlow Error - Type: %s Code: %s' % (red(etype), red(ecode)))
+
+ if not isinstance(msg.data, BinaryData):
+ print('OpenFlow Error Message:\n------ BEGIN ------')
+ print_openflow_header(msg.data)
+ prints_ofp(msg.data)
+ print('OpenFlow Error Message:\n------- END -------')
+ else:
+ print(red('OpenFlow Error Data could not be processed!!'))
+
+
+# *************************** OFPT_ECHO_REQUEST ******************************
+
+
+def print_ofpt_echo_request(msg):
+ """ Prints OFPT_ECHO_REQUEST messages. msg.data can be any content. The
+ controller that sent the ECHO knows what it means. As a sniffer, we do
+ not know what it means so we print in hex.
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ if len(msg.data.value) > 0:
+ hexdump(msg.data.value)
+
+
+# *************************** OFPT_ECHO_REPLY ********************************
+
+
+def print_ofpt_echo_reply(msg):
+ """ Prints OFPT_ECHO_REPLY messages. msg.data can be any content. The
+ controller that sent the ECHO knows what it means. As a sniffer, we do
+ not know what it means so we print in hex.
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ if len(msg.data.value) > 0:
+ hexdump(msg.data.value)
+
+
+# ****************************** OFPT_VENDOR *********************************
+
+
+def print_ofpt_vendor(msg):
+ """ Prints OFPT_VENDOR messages. Any vendor can extend the OpenFlow
+ specification with new messages. OVS/NICIRA uses this message a lot.
+ We do not dissect vendor-specific messages but it would be great to have
+ such support (which means we are looking for volunteers!).
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ vendor = dissector.get_ofp_vendor(msg.vendor.value)
+ print('OpenFlow Vendor: %s' % vendor)
+
+
+# ************************ OFPT_FEATURES_REQUEST *****************************
+
+
+def print_ofpt_features_request(msg):
+ """ OFPT_FEATURES_REQUEST has no payload, so this function does not print
+ anything. It is here just for educational purposes.
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ pass
+
+
+# ************************* OFPT_FEATURES_REPLY *****************************
+
+
+def print_ofpt_features_reply(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ dpid = msg.datapath_id
+ print('FeatureRes - datapath_id: %s n_buffers: %s n_tables: %s, pad: %s'
+ % (green(dpid), msg.n_buffers, msg.n_tables, msg.pad))
+
+ print('FeatureRes - Capabilities: ', end='')
+ capabilities = _parse_capabilities(msg.capabilities)
+ for i in capabilities:
+ print(dissector.get_feature_res_capabilities(i) + ' ', end='')
+ print()
+
+ print('FeatureRes - Actions: ', end='')
+ actions = _parse_actions(msg.actions)
+ for i in actions:
+ print(dissector.get_feature_res_actions(i) + ' ', end='')
+ print()
+
+ print_of_ports(msg.ports)
+
+
+# ************************* OFPT_GET_CONFIG_REQUEST *****************************
+
+
+def print_ofpt_get_config_request(msg):
+ """ OFPT_GET_CONFIG_REQUEST has no payload, so this function does not print
+ anything. It is here just for educational purposes.
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ pass
+
+
+# ************************* OFPT_GET_CONFIG_REPLY *******************************
+
+
+def print_ofpt_get_config_reply(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ print('OpenFlow GetConfigRes - Flag: %s Miss_send_len: %s' %
+ (msg.flags, msg.miss_send_len))
+
+
+# ************************* OFPT_SET_CONFIG **********************************
+
+
+def print_ofpt_set_config(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ flags = str(msg.flags)
+ print('OpenFlow SetConfig - Flag: %s Miss_send_len: %s' %
+ (yellow(flags.split('.')[1]), msg.miss_send_len))
+
+
+# ************************* OFPT_PACKET_IN ***********************************
+
+
+def print_ofpt_packet_in(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ print('PacketIn: buffer_id: %s total_len: %s in_port: %s reason: %s '
+ 'pad: %s' %
+ (hex(msg.buffer_id.value), msg.total_len.value,
+ green(msg.in_port.value), green(msg.reason.value), msg.pad))
+ print_data(msg.data)
+
+
+def print_data(data):
+ """
+ Print msg.data from both PacketIn and PacketOut
+ Args:
+ data: msg.data - array of protocols
+ """
+ if isinstance(data, BinaryData):
+ data = dissect_data(data)
+
+ try:
+ eth = data.pop(0)
+ libs.tcpiplib.prints.print_layer2(eth)
+ next_protocol = eth.protocol
+
+ if next_protocol in [33024]:
+ vlan = data.pop(0)
+ libs.tcpiplib.prints.print_vlan(vlan)
+ next_protocol = vlan.protocol
+
+ if next_protocol in [35020, 35138]:
+ lldp = data.pop(0)
+ libs.tcpiplib.prints.print_lldp(lldp)
+ elif next_protocol in [34998]:
+ fvd = data.pop(0)
+ libs.tcpiplib.prints.print_oessfvd(fvd)
+ elif next_protocol in [2048]:
+ ip = data.pop(0)
+ libs.tcpiplib.prints.print_layer3(ip)
+ if ip.protocol is 6:
+ tcp = data.pop(0)
+ libs.tcpiplib.prints.print_tcp(tcp)
+ elif next_protocol in [2054]:
+ arp = data.pop(0)
+ libs.tcpiplib.prints.print_arp(arp)
+ except Exception as error:
+ print("ERROR: %s" % error)
+
+
+# ************************* OFPT_FLOW_REMOVED ********************************
+
+
+def print_ofpt_flow_removed(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ print_ofp_match(msg.match)
+
+ string = ('Body - Cookie: %s Priority: %s Reason: %s Pad: %s\nBody - '
+ 'Duration Secs/NSecs: %s/%s Idle Timeout: %s Pad2/Pad3: %s/%s'
+ ' Packet Count: %s Byte Count: %s')
+
+ print(string % (msg.cookie, msg.priority, red(msg.reason),
+ msg.pad, msg.duration_sec, msg.duration_nsec,
+ msg.idle_timeout, msg.pad2,
+ msg.pad3, msg.packet_count, msg.byte_count))
+
+
+# ************************* OFPT_PORT_STATUS ********************************
+
+
+def print_ofpt_port_status(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ print('OpenFlow PortStatus - Reason: %s Pad: %s' %
+ (msg.reason, msg.pad))
+ print_of_ports(msg.desc)
+
+
+# ************************* OFPT_PACKET_OUT ********************************
+
+
+def print_ofpt_packet_out(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ print('PacketOut: buffer_id: %s in_port: %s actions_len: %s' %
+ (hex(msg.buffer_id.value),
+ green(dissector.get_phy_port_id(msg.in_port.value)),
+ msg.actions_len.value))
+ if msg.actions_len is not 0:
+ print_actions(msg.actions)
+ print_data(msg.data)
+
+
+# ************************* OFPT_FLOW_MOD *********************************
+
+
+def print_ofpt_flow_mod(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ print_ofp_match(msg.match)
+ print_ofp_body(msg)
+ print_actions(msg.actions)
+ # Print OVS is deactivated for now
+ # print_ofp_ovs(msg)
+
+
+def print_ofp_match(match):
+ """
+
+ Args:
+ match:
+ """
+ print('Match - ', end='')
+ for match_item in match.__dict__:
+ match_item_value = match.__dict__[match_item]
+ if match_item_value.value not in [0, "00:00:00:00:00:00", "0.0.0.0", 65535]:
+ if match_item is 'dl_vlan' and match_item_value.value not in [65535]:
+ match_item_value = dissector.get_vlan(match_item_value.value)
+ elif match_item is 'wildcards':
+ match_item_value = hex(match_item_value.value)
+ elif match_item is 'dl_type' and match_item_value.value not in [65535]:
+ match_item_value = libs.tcpiplib.tcpip.get_ethertype(match_item_value.value)
+ elif match_item in ['pad1', 'pad2']:
+ continue
+
+ print("%s: %s " % (match_item, green(match_item_value)), end='')
+ print()
+
+
+def print_ofp_body(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ string = ('Body - Cookie: %s Command: %s Idle/Hard Timeouts: '
+ '%s/%s\nBody - Priority: %s Buffer ID: %s Out Port: %s Flags: %s')
+ command = green(dissector.get_ofp_command(msg.command.value))
+ flags = green(dissector.get_ofp_flags(msg.flags.value))
+ out_port = green(dissector.get_phy_port_id(msg.out_port.value))
+
+ print(string % (msg.cookie.value, command, msg.idle_timeout, msg.hard_timeout,
+ green(msg.priority), msg.buffer_id.value, out_port, flags))
+
+
+def print_actions(actions):
+ """
+
+ Args:
+ actions:
+ """
+ for action in actions:
+ print_ofp_action(action)
+
+
+def print_ofp_action(action):
+ """
+
+ Args:
+ action:
+ """
+ if action.action_type == 0:
+ port = dissector.get_phy_port_id(action.port.value)
+ print('Action - Type: %s Length: %s Port: %s '
+ 'Max Length: %s' %
+ (green('OUTPUT'), action.length, green(port), action.max_length))
+
+ elif action.action_type == 1:
+ print('Action - Type: %s Length: %s VLAN ID: %s Pad: %s' %
+ (green('SetVLANID'), action.length, green(str(action.vlan_id.value)), action.pad2))
+
+ elif action.action_type == 2:
+ print('Action - Type: %s Length: %s VLAN PCP: %s Pad: %s' %
+ (green('SetVLANPCP'), action.length, green(str(action.vlan_pcp.value)), action.pad))
+
+ elif action.action_type == 3:
+ print('Action - Type: %s Length: %s' %
+ (green('StripVLAN'), action.length))
+
+ elif action.action_type == 4:
+ print('Action - Type: %s Length: %s SetDLSrc: %s Pad: %s' %
+ (green('SetDLSrc'), action.length, green(action.dl_src),
+ action.pad))
+
+ elif action.action_type == 5:
+ print('Action - Type: %s Length: %s SetDLDst: %s Pad: %s' %
+ (green('SetDLDst'), action.length, green(action.dl_dst),
+ action.pad))
+
+ elif action.action_type == 6:
+ print('Action - Type: %s Length: %s SetNWSrc: %s' %
+ (green('SetNWSrc'), action.length, green(action.nw_addr)))
+
+ elif action.action_type == 7:
+ print('Action - Type: %s Length: %s SetNWDst: %s' %
+ (green('SetNWDst'), action.length, green(action.nw_addr)))
+
+ elif action.action_type == 8:
+ print('Action - Type: %s Length: %s SetNWTos: %s Pad: %s' %
+ (green('SetNWTos'), action.length, green(action.nw_tos.value),
+ action.pad))
+
+ elif action.action_type == 9:
+ print('Action - Type: %s Length: %s SetTPSrc: %s Pad: %s' %
+ (green('SetTPSrc'), action.length, green(action.port_no.value),
+ action.pad))
+
+ elif action.action_type == int('a', 16):
+ print('Action - Type: %s Length: %s SetTPDst: %s Pad: %s' %
+ (green('SetTPDst'), action.length, green(action.port_no.value),
+ action.pad))
+
+ elif action.action_type == int('b', 16):
+ print(('Action - Type: %s Length: %s Enqueue: %s Pad: %s'
+ ' Queue: %s') %
+ (green('Enqueue'), action.length, green(action.port_no.value),
+ action.pad, green(action.queue_id.value)))
+
+ elif action.action_type == int('ffff', 16):
+ print('Action - Type: %s Length: %s Vendor: %s' %
+ (green('VENDOR'), action.length, green(action.vendor)))
+
+ else:
+ print('Unknown Action Type')
+
+
+# ************************* OFPT_PORT_MOD *********************************
+
+
+def print_ofpt_port_mod(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+
+ def _print_port_mod_config_mask(variable, name):
+
+ print('PortMod %s: ' % name, end='')
+ printed = False
+ variable = _parse_phy_curr(variable)
+ for i in variable:
+ print(red(dissector.get_phy_config(i)), end='')
+ printed = True
+ else:
+ _dont_print_0(printed)
+ print()
+
+ print('PortMod Port_no: %s HW_Addr: %s Pad: %s' %
+ (yellow(msg.port_no.value), yellow(msg.hw_addr.value), msg.pad))
+ _print_port_mod_config_mask(msg.config.value, 'config')
+ _print_port_mod_config_mask(msg.mask.value, 'mask')
+ _print_port_mod_config_mask(msg.advertise.value, 'advertise')
+
+
+# ************************* OFPT_STATS_REQUEST **********************************
+
+
+def print_ofpt_stats_request(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ def print_ofpt_stats_request_description(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ body = str(msg.body_type)
+ print('StatReq Type: %s' % body.split('.')[1])
+
+ def print_ofpt_stats_request_flow_aggregate(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ if msg.body_type == 1:
+ type_name = 'Flow'
+ else:
+ type_name = 'Aggregate'
+ body_type = "%s" % msg.body_type
+ print('StatReq Type: %s(%s)' % (type_name, body_type.split('.')[1]))
+ print_ofp_match(msg.body[0].match)
+ out_port = dissector.get_phy_port_id(msg.body[0].out_port.value)
+ print('StatReq Table_id: %s Pad: %s Out_Port: %s' % (msg.body[0].table_id.value,
+ msg.body[0].pad, out_port))
+
+ def print_ofpt_stats_request_table(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ body = "%s" % msg.body_type
+ print('StatReq Type: %s' % body.split('.')[1])
+
+ def print_ofpt_stats_request_port(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ port_number = dissector.get_phy_port_id(msg.body[0].port_no.value)
+ print('StatReq Type: Port(4) Port_Number: %s Pad: %s' %
+ (green(port_number), msg.body[0].pad))
+
+ def print_ofpt_stats_request_queue(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ port_number = dissector.get_phy_port_id(msg.body[0].port_no.value)
+ print('StatReq Type: OFPST_QUEUE: Port_Number: %s Pad: %s Queue_id: %s' %
+ (green(port_number), msg.body[0].pad, msg.body[0].queue_id))
+
+ def print_ofps_stats_request_vendor(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ vendor_id = dissector.get_ofp_vendor(msg.body[0].vendor.value)
+ print('StatReq Type: Vendor(%s): Vendor_ID: %s' %
+ (hex(msg.body_type.value), vendor_id))
+ print("StatReq Vendor Data:")
+ hexdump(msg.body[0].body.value)
+
+ if msg.body_type == 0:
+ print_ofpt_stats_request_description(msg)
+ elif msg.body_type == 1 or msg.body_type == 2:
+ print_ofpt_stats_request_flow_aggregate(msg)
+ elif msg.body_type == 3:
+ print_ofpt_stats_request_table(msg)
+ elif msg.body_type == 4:
+ print_ofpt_stats_request_port(msg)
+ elif msg.body_type == 5:
+ print_ofpt_stats_request_queue(msg)
+ elif msg.body_type == 65535:
+ print_ofps_stats_request_vendor(msg)
+
+
+# ************************* OFPT_STATS_REPLY **********************************
+
+
+def print_ofpt_stats_reply(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+
+ def print_ofpt_stats_reply_description(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ print('StatRes Type: OFPST_DESC')
+ print('StatRes mfr_desc: %s' % msg.body.mfr_desc)
+ print('StatRes hw_desc: %s' % msg.body.hw_desc)
+ print('StatRes sw_desc: %s' % msg.body.sw_desc)
+ print('StatRes serial_num: %s' % msg.body.serial_num)
+ print('StatRes dp_desc: %s' % msg.body.dp_desc)
+
+ def print_ofpt_stats_reply_flow_array(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+
+ def print_ofpt_stats_reply_flow(flow):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ print('StatRes Type: Flow(1)')
+ print('StatRes Length: %s Table_id: %s Pad: %s ' %
+ (flow.length, flow.table_id, flow.pad))
+ print('StatRes ', end='')
+ print_ofp_match(flow.match)
+ print('StatRes duration_sec: %s, duration_nsec: %s, priority: %s,'
+ ' idle_timeout: %s, hard_timeout: %s, pad: %s, cookie: %s,'
+ ' packet_count: %s, byte_count: %s' %
+ (flow.duration_sec, flow.duration_nsec,
+ flow.priority, flow.idle_timeout,
+ flow.hard_timeout, flow.pad,
+ flow.cookie,
+ flow.packet_count, flow.byte_count))
+ print('StatRes ', end='')
+ print_actions(flow.actions)
+
+ if len(msg.body) == 0:
+ print('StatRes Type: Flow(1)\nNo Flows')
+ return
+
+ for flow in msg.body:
+ print_ofpt_stats_reply_flow(flow)
+
+ def print_ofpt_stats_reply_aggregate(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ print('StatRes Type: Aggregate(2)')
+ print('StatRes packet_count: %s, byte_count: %s flow_count: %s '
+ 'pad: %s' %
+ (msg.stats.packet_count, msg.stats.byte_count,
+ msg.stats.flow_count, msg.stats.pad))
+
+ def print_ofpt_stats_reply_table_array(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+
+ def print_ofpt_stats_reply_table(table):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ print('StatRes table_id: %s, pad: %s, name: "%s", wildcards: %s, '
+ 'max_entries: %s, active_count: %s, lookup_count: %s, '
+ 'matched_count: %s' %
+ (table.table_id.value, table.pad, table.name.value, hex(table.wildcards.value),
+ table.max_entries.value, table.active_count.value,
+ table.count_lookup.value, table.count_matched.value))
+
+ if len(msg.body) == 0:
+ print('StatRes Type: Table(3)\nNo Tables')
+ return
+
+ print('StatRes Type: Table(3)')
+ for table in msg.body:
+ print_ofpt_stats_reply_table(table)
+
+ def print_ofp_stats_reply_port_array(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+
+ def print_ofpt_stats_reply_port(port):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ print('StatRes Type: Port(4)')
+ print('StatRes port_number: %s rx_packets: %s rx_bytes: %s rx_errors: %s'
+ ' rx_crc_err: %s rx_dropped: %s rx_over_err: %s rx_frame_err: %s\n'
+ 'StatRes port_number: %s tx_packets: %s tx_bytes: %s tx_errors: %s'
+ ' tx_dropped: %s collisions: %s pad: %s' %
+ (red(port.port_no), port.rx_packets,
+ port.rx_bytes, port.rx_errors, port.rx_crc_err,
+ port.rx_dropped, port.rx_over_err,
+ port.rx_frame_err, red(port.port_no),
+ port.tx_packets, port.tx_bytes, port.tx_errors,
+ port.tx_dropped, port.collisions, port.pad))
+
+ if len(msg.body) == 0:
+ print('StatRes Type: Port(4)\nNo Ports')
+ return
+ for port in msg.body:
+ print_ofpt_stats_reply_port(port)
+
+ def print_ofpt_stats_reply_queue_array(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+
+ def print_ofpt_stats_reply_queue(queue):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ print('StatRes Type: Queue(5)')
+ print('StatRes queue_id: %s length: %s pad: %s'
+ ' tx_bytes: %s tx_packets: %s tx_errors: %s' %
+ (queue.queue_id, queue.length, queue.pad,
+ queue.tx_bytes, queue.tx_packets, queue.tx_errors))
+
+ if len(msg.body) == 0:
+ print('StatRes Type: Queue(5)\nNo Queues')
+ return
+
+ for queue in msg.body:
+ print_ofpt_stats_reply_queue(queue)
+
+ def print_ofpt_stats_reply_vendor(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+
+ def print_ofpt_stats_reply_vendor_data(data):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ print('StatRes Vendor Data: ')
+ hexdump(data)
+
+
+ print('StatRes Type: Vendor(%s)' % hex(msg.body_type.value))
+ print('StatRes Vendor_Id: %s' % red(hex(msg.body[0].vendor.value)))
+ print_ofpt_stats_reply_vendor_data(msg.body[0].body.value)
+
+ if msg.body_type == 0:
+ print_ofpt_stats_reply_description(msg)
+ elif msg.body_type == 1:
+ print_ofpt_stats_reply_flow_array(msg)
+ elif msg.body_type == 2:
+ print_ofpt_stats_reply_aggregate(msg)
+ elif msg.body_type == 3:
+ print_ofpt_stats_reply_table_array(msg)
+ elif msg.body_type == 4:
+ print_ofp_stats_reply_port_array(msg)
+ elif msg.body_type == 5:
+ print_ofpt_stats_reply_queue_array(msg)
+ elif msg.body_type == 65535:
+ print_ofpt_stats_reply_vendor(msg)
+
+
+# ************************* OFPT_BARRIER_REQUEST **********************************
+
+
+def print_ofpt_barrier_request(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ pass
+
+
+# ************************* OFPT_BARRIER_REPLY **********************************
+
+
+def print_ofpt_barrier_reply(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ pass
+
+
+# ************************* OFPT_QUEUE_GET_CONFIG_REQUEST **********************************
+
+
+def print_ofpt_queue_get_config_request(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+ print('QueueGetConfigReq Port: %s Pad: %s' % (msg.port, msg.pad))
+
+
+# ************************* OFPT_QUEUE_GET_CONFIG_REPLY **********************************
+
+
+def print_ofpt_queue_get_config_reply(msg):
+ """
+
+ Args:
+ msg: OpenFlow message unpacked by python-openflow
+ """
+
+ def print_ofpt_queue_reply_prop_payload(payload):
+ print('Payload: Rate %s Pad: %s' % (payload.rate, payload.pad))
+
+ def print_ofpt_queue_reply_properties(qproperty):
+ print('Property: %s Length: %s Pad: %s' %
+ (qproperty.property, qproperty.length, qproperty.pad))
+ print_ofpt_queue_reply_prop_payload(qproperty.payload)
+
+ def print_ofpt_queue_reply_queue(queue):
+ print('Queue_ID: %s Length: %s Pad: %s' %
+ (queue.queue_id, queue.length, queue.pad))
+ if len(queue.properties) == 0:
+ print('QueueGetConfigRes: No Properties')
+ return
+ for property in queue.properties:
+ print_ofpt_queue_reply_properties(property)
+
+ print('QueueGetConfigRes Port: %s Pad: %s' %
+ (msg.port, msg.pad))
+
+ if len(msg.queues) == 0:
+ print('QueueGetConfigRes: No Queues')
+ return
+
+ for queue in msg.queues:
+ print_ofpt_queue_reply_queue(queue)
+
+
+# ******************** Multipurpose port functions *******************************
+
+
+def _dont_print_0(printed):
+ if printed is False:
+ print('0', end='')
+ return False
+
+
+def print_port_field(port_id, variable, name):
+ port_id = '%s' % green(port_id)
+ printed = False
+
+ print('Port_id: %s - %s: ' % (port_id, name), end='')
+ variable = _parse_phy_curr(variable)
+ for i in variable:
+ print(dissector.get_phy_feature(i) + ' ', end='')
+ printed = True
+ else:
+ _dont_print_0(printed)
+ print()
+
+
+def print_ofp_phy_port(port):
+ port_id = '%s' % green(port.port_no)
+
+ print('Port_id: %s - hw_addr: %s name: %s' % (
+ port_id, green(port.hw_addr), green(port.name)))
+
+ print('Port_id: %s - config: ' % port_id, end='')
+ printed = False
+ config = _parse_phy_config(port.config.value)
+ for i in config:
+ print(dissector.get_phy_config(i), end='')
+ printed = True
+ else:
+ printed = _dont_print_0(printed)
+ print()
+
+ print('Port_id: %s - state: ' % port_id, end='')
+ state = _parse_phy_state(port.state.value)
+ for i in state:
+ print(dissector.get_phy_state(i), end='')
+ printed = True
+ else:
+ _dont_print_0(printed)
+ print()
+
+ print_port_field(port_id, port.curr, 'curr')
+ print_port_field(port_id, port.advertised, 'advertised')
+ print_port_field(port_id, port.supported, 'supported')
+ print_port_field(port_id, port.peer, 'peer')
+
+
+def print_of_ports(ports):
+
+ if type(ports) is not ListOfPhyPorts:
+ print_ofp_phy_port(ports)
+ else:
+ for port in ports:
+ print_ofp_phy_port(port)
+
+
+def _parse_bitmask(bitmask, array):
+ size = len(array)
+ for i in range(0, size):
+ mask = 2**i
+ aux = bitmask & mask
+ if aux == 0:
+ array.remove(mask)
+ return array
+
+
+def _parse_capabilities(capabilities):
+ caps = [1, 2, 4, 8, 16, 32, 64, 128]
+ return _parse_bitmask(capabilities, caps)
+
+
+def _parse_actions(actions):
+ acts = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048]
+ return _parse_bitmask(actions, acts)
+
+
+def _parse_phy_config(config):
+ confs = [1, 2, 4, 8, 16, 32, 64]
+ return _parse_bitmask(config, confs)
+
+
+def _parse_phy_state(state):
+ states = [1, 2, 4, 8, 16]
+ return _parse_bitmask(state, states)
+
+
+def _parse_phy_curr(values):
+ confs = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048]
+ return _parse_bitmask(values, confs)
+
+
+# def print_ofp_ovs(msg):
+# """
+# If -o or --print-ovs is provided by user, print a ovs-ofctl add-dump
+# """
+#
+# def get_command(command):
+# commands = {0: 'add-flow', 1: 'mod-flows', 3: 'del-flows'}
+# try:
+# return commands[command]
+# except KeyError:
+# return 0
+#
+# def get_flag(flag):
+# flags = {0: '', 1: 'send_flow_rem', 2: 'check_overlap', 3: 'Emerg'}
+# try:
+# return flags[flag]
+# except KeyError:
+# return 0
+#
+# def get_actions(action_type, action_length, payload):
+# if action_type == 0:
+# port, max_len = libs.openflow.of10.parser.get_action(action_type, payload)
+# return 'output:%s' % (port if port != 65533 else 'CONTROLLER')
+# elif action_type == 1:
+# vlan, pad = libs.openflow.of10.parser.get_action(action_type, payload)
+# return 'mod_vlan_vid:' + str(vlan)
+# elif action_type == 2:
+# vlan_pc, pad = libs.openflow.of10.parser.get_action(action_type, payload)
+# return 'mod_vlan_pcp:' + str(vlan_pc)
+# elif action_type == 3:
+# return 'strip_vlan'
+# elif action_type == 4:
+# setDLSrc, pad = libs.openflow.of10.parser.get_action(action_type, payload)
+# return 'mod_dl_src:' + str(eth_addr(setDLSrc))
+# elif action_type == 5:
+# setDLDst, pad = libs.openflow.of10.parser.get_action(action_type, payload)
+# return 'mod_dl_dst:' + str(eth_addr(setDLDst))
+# elif action_type == 6:
+# nw_addr = libs.openflow.of10.parser.get_action(action_type, payload)
+# return 'mod_nw_src:' + str(nw_addr)
+# elif action_type == 7:
+# nw_addr = libs.openflow.of10.parser.get_action(action_type, payload)
+# return 'mod_nw_src:' + str(nw_addr)
+# elif action_type == 8:
+# nw_tos, pad = libs.openflow.of10.parser.get_action(action_type, payload)
+# return 'mod_nw_tos:' + str(nw_tos)
+# elif action_type == 9:
+# port, pad = libs.openflow.of10.parser.get_action(action_type, payload)
+# return 'mod_tp_src:' + str(port)
+# elif action_type == int('a', 16):
+# port, pad = libs.openflow.of10.parser.get_action(action_type, payload)
+# return 'mod_tp_dst:' + str(port)
+# elif action_type == int('b', 16):
+# port, pad, queue_id = libs.openflow.of10.parser.get_action(action_type, payload)
+# return 'set_queue:' + str(queue_id)
+#
+# if PrintingOptions().print_ovs is not True:
+# return
+#
+# switch_ip = 'SWITCH_IP'
+# switch_port = '6634'
+#
+# ofm = []
+# ofactions = []
+#
+# ovs_command = get_command(msg.command)
+#
+# for K in msg.match.__dict__:
+# if K != 'wildcards':
+# if msg.match.__dict__[K] is not None:
+# value = "%s=%s," % (K, msg.match.__dict__[K])
+# ofm.append(value)
+#
+# matches = ''.join(ofm)
+#
+# if msg.command is not 3:
+# for action in msg.actions:
+# value = get_actions(action.type, action.length, action.payload)
+# value = "%s," % value
+# ofactions.append(value)
+#
+# flag = get_flag(msg.flags)
+# print('ovs-ofctl %s tcp:%s:%s \"' % (ovs_command, switch_ip, switch_port), end='')
+# if msg.flags != 0:
+# print('%s,' % flag, end='')
+# if msg.priority != 32678:
+# print('priority=%s,' % msg.priority, end='')
+# if msg.idle_timeout != 0:
+# print('idle_timeout=%s,' % msg.idle_timeout, end='')
+# if msg.hard_timeout != 0:
+# print('hard_timeout=%s,' % msg.hard_timeout, end='')
+# print('%s ' % matches, end='')
+# print('action=%s\"' % ''.join(ofactions))
+# else:
+# ovs_msg_del = 'ovs-ofctl %s tcp:%s:%s %s '
+# print(ovs_msg_del % (ovs_command, switch_ip, switch_port, matches))
diff --git a/libs/openflow/of13/__init__.py b/libs/openflow/of13/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/libs/openflow/of13/dissector.py b/libs/openflow/of13/dissector.py
new file mode 100644
index 0000000..369bfb8
--- /dev/null
+++ b/libs/openflow/of13/dissector.py
@@ -0,0 +1,450 @@
+"""
+ This is the OpenFlow 1.3 dictionary/dissector
+ Here messages, types and codes are converted to names.
+"""
+
+
+def get_ofp_type(of_type):
+ of_types = {0: 'OFPT_HELLO',
+ 1: 'OFPT_ERROR',
+ 2: 'OFPT_ECHO_REQUEST',
+ 3: 'OFPT_ECHO_REPLY',
+ 4: 'OFPT_EXPERIMENTER',
+ 5: 'OFPT_FEATURES_REQUEST',
+ 6: 'OFPT_FEATURES_REPLY',
+ 7: 'OFPT_GET_CONFIG_REQUEST',
+ 8: 'OFPT_GET_CONFIG_REPLY',
+ 9: 'OFPT_SET_CONFIG',
+ 10: 'OFPT_PACKET_IN',
+ 11: 'OFPT_FLOW_REMOVED',
+ 12: 'OFPT_PORT_STATUS',
+ 13: 'OFPT_PACKET_OUT',
+ 14: 'OFPT_FLOW_MOD',
+ 15: 'OFPT_GROUP_MOD',
+ 16: 'OFPT_PORT_MOD',
+ 17: 'OFPT_TABLE_MOD',
+ 18: 'OFPT_MULTIPART_REQUEST',
+ 19: 'OFPT_MULTIPART_REPLY',
+ 20: 'OFPT_BARRIER_REQUEST',
+ 21: 'OFPT_BARRIER_REPLY',
+ 22: 'OFPT_QUEUE_GET_CONFIG_REQUEST',
+ 23: 'OFPT_QUEUE_GET_CONFIG_REPLY',
+ 24: 'OFPT_ROLE_REQUEST',
+ 25: 'OFPT_ROLE_REPLY',
+ 26: 'OFPT_GET_ASYNC_REQUEST',
+ 27: 'OFPT_GET_ASYNC_REPLY',
+ 28: 'OFPT_SET_ASYNC',
+ 29: 'OFPT_METER_MOD'}
+ try:
+ return of_types[of_type]
+ except KeyError:
+ return 'UnknownType(%s)' % of_type
+
+
+def get_ofp_error(error_type, code):
+ errors_types = dict()
+ codes = dict()
+
+ # Starts with an Error
+ errors_types[error_type] = 'UnknownType(%s)' % error_type
+ codes[code] = 'UnknownCode(%s)' % code
+
+ # Error Types
+ if error_type in range(0, 14) or error_type == 65535:
+ errors_types = {0: 'OFPET_HELLO_FAILED(0)',
+ 1: 'OFPET_BAD_REQUEST(1)',
+ 2: 'OFPET_BAD_ACTION(2)',
+ 3: 'OFPET_BAD_INSTRUCTION(3)',
+ 4: 'OFPET_BAD_MATCH(4)',
+ 5: 'OFPET_FLOW_MOD_FAILED(5)',
+ 6: 'OFPET_GROUP_MOD_FAILED(6)',
+ 7: 'OFPET_PORT_MOD_FAILED(7)',
+ 8: 'OFPET_TABLE_MOD_FAILED(8)',
+ 9: 'OFPET_QUEUE_OP_FAILED(9)',
+ 10: 'OFPET_SWITCH_CONFIG_FAILED(10)',
+ 11: 'OFPET_ROLE_REQUEST_FAILED(11)',
+ 12: 'OFPET_METER_MOD_FAILED(12)',
+ 13: 'OFPET_TABLE_FEATURES_FAILED(13)',
+ 65535: 'Experimenter(0xffff)'}
+
+ # Error Codes per Error Type
+ if error_type == 0:
+ if code in range(0, 2):
+ codes = {0: 'OFPHFC_INCOMPATIBLE(0)',
+ 1: 'OFPHFC_EPERM(1)'}
+
+ elif error_type == 1:
+ if code in range(0, 14):
+ codes = {0: 'OFPBRC_BAD_VERSION(0)',
+ 1: 'OFPBRC_BAD_TYPE(1)',
+ 2: 'OFPBRC_BAD_MULTIPART(2)',
+ 3: 'OFPBRC_BAD_EXPERIMENTER(3)',
+ 4: 'OFPBRC_BAD_EXP_TYPE(4)',
+ 5: 'OFPBRC_EPERM(5)',
+ 6: 'OFPBRC_BAD_LEN(6)',
+ 7: 'OFPBRC_BUFFER_EMPTY(7)',
+ 8: 'OFPBRC_BUFFER_UNKNOWN(8)',
+ 9: 'OFPBRC_BAD_TABLE_ID(9)',
+ 10: 'OFPBRC_IS_SLAVE(10)',
+ 11: 'OFPBRC_BAD_PORT(11)',
+ 12: 'OFPBRC_BAD_PACKET(12)',
+ 13: 'OFPBRC_MULTIPART_BUFFER_OVERFLOW(13)'}
+
+ elif error_type == 2:
+ if code in range(0, 16):
+ codes = {0: 'OFPBAC_BAD_TYPE(0)',
+ 1: 'OFPBAC_BAD_LEN(1)',
+ 2: 'OFPBAC_BAD_EXPERIMENTER(2)',
+ 3: 'OFPBAC_BAD_EXP_TYPE(3)',
+ 4: 'OFPBAC_BAD_OUT_PORT(4)',
+ 5: 'OFPBAC_BAD_ARGUMENT(5)',
+ 6: 'OFPBAC_EPERM(6)',
+ 7: 'OFPBAC_TOO_MANY(7)',
+ 8: 'OFPBAC_BAD_QUEUE(8)',
+ 9: 'OFPBAC_BAD_OUT_GROUP(9)',
+ 10: 'OFPBAC_MATCH_INCONSISTENT(10)',
+ 11: 'OFPBAC_UNSUPPORTED_ORDER(11)',
+ 12: 'OFPBAC_BAD_TAG(12)',
+ 13: 'OFPBAC_BAD_SET_TYPE(13)',
+ 14: 'OFPBAC_BAD_SET_LEN(14)',
+ 15: 'OFPBAC_BAD_SET_ARGUMENT(15)'}
+
+ elif error_type == 3:
+ if code in range(0, 9):
+ codes = {0: 'OFPBIC_UNKNOWN_INST(0)',
+ 1: 'OFPBIC_UNSUP_INST(1)',
+ 2: 'OFPBIC_BAD_TABLE_ID(2)',
+ 3: 'OFPBIC_UNSUP_METADATA(3)',
+ 4: 'OFPBIC_UNSUP_METADATA_MASK(4)',
+ 5: 'OFPBIC_BAD_EXPERIMENTER(5)',
+ 6: 'OFPBIC_BAD_EXP_TYPE(6)',
+ 7: 'OFPBIC_BAD_LEN(7)',
+ 8: 'OFPBIC_EPERM(8)'}
+
+ elif error_type == 4:
+ if code in range(0, 12):
+ codes = {0: 'OFPBMC_BAD_TYPE(0)',
+ 1: 'OFPBMC_BAD_LEN(1)',
+ 2: 'OFPBMC_BAD_TAG(2)',
+ 3: 'OFPBMC_BAD_DL_ADDR_MASK(3)',
+ 4: 'OFPBMC_BAD_NW_ADDR_MASK(4)',
+ 5: 'OFPBMC_BAD_WILDCARDS(5)',
+ 6: 'OFPBMC_BAD_FIELD(6)',
+ 7: 'OFPBMC_BAD_VALUE(7)',
+ 8: 'OFPBMC_BAD_MASK(8)',
+ 9: 'OFPBMC_BAD_PREREQ(9)',
+ 10: 'OFPBMC_DUP_FIELD(10)',
+ 11: 'OFPBMC_EPERM(11)'}
+
+ elif error_type == 5:
+ if code in range(0, 8):
+ codes = {0: 'OFPFMFC_UNKNOWN(0)',
+ 1: 'OFPFMFC_TABLE_FULL(1)',
+ 2: 'OFPFMFC_BAD_TABLE_ID(2)',
+ 3: 'OFPFMFC_OVERLAP(3)',
+ 4: 'OFPFMFC_EPERM(4)',
+ 5: 'OFPFMFC_BAD_TIMEOUT(5)',
+ 6: 'OFPFMFC_BAD_COMMAND(6)',
+ 7: 'OFPFMFC_BAD_FLAGS(7)'}
+
+ elif error_type == 6:
+ if code in range(0, 15):
+ codes = {0: 'OFPGMFC_GROUP_EXISTS(0)',
+ 1: 'OFPGMFC_INVALID_GROUP(1)',
+ 2: 'OFPGMFC_WEIGHT_UNSUPPORTED(2)',
+ 3: 'OFPGMFC_OUT_OF_GROUPS(3)',
+ 4: 'OFPGMFC_OUT_OF_BUCKETS(4)',
+ 5: 'OFPGMFC_CHAINING_UNSUPPORTED(5)',
+ 6: 'OFPGMFC_WATCH_UNSUPPORTED(6)',
+ 7: 'OFPGMFC_LOOP(7)',
+ 8: 'OFPGMFC_UNKNOWN_GROUP(8)',
+ 9: 'OFPGMFC_CHAINED_GROUP(9)',
+ 10: 'OFPGMFC_BAD_TYPE(10)',
+ 11: 'OFPGMFC_BAD_COMMAND(11)',
+ 12: 'OFPGMFC_BAD_BUCKET(12)',
+ 13: 'OFPGMFC_BAD_WATCH(13)',
+ 14: 'OFPGMFC_EPERM(14)'}
+
+ elif error_type == 7:
+ if code in range(0, 5):
+ codes = {0: 'OFPPMFC_BAD_PORT(0)',
+ 1: 'OFPPMFC_BAD_HW_ADDR(1)',
+ 2: 'OFPPMFC_BAD_CONFIG(2)',
+ 3: 'OFPPMFC_BAD_ADVERTISE(3)',
+ 4: 'OFPPMFC_EPERM(4)'}
+
+ elif error_type == 8:
+ if code in range(0, 3):
+ codes = {0: 'OFPTMFC_BAD_TABLE(0)',
+ 1: 'OFPTMFC_BAD_CONFIG(1)',
+ 2: 'OFPTMFC_EPERM(2)'}
+
+ elif error_type == 9:
+ if code in range(0, 3):
+ codes = {0: 'OFPQOFC_BAD_PORT(0)',
+ 1: 'OFPQOFC_BAD_QUEUE(1)',
+ 2: 'OFPQOFC_EPERM(2)'}
+
+ elif error_type == int('A', 16):
+ if code in range(0, 3):
+ codes = {0: 'OFPSCFC_BAD_FLAGS(0)',
+ 1: 'OFPSCFC_BAD_LEN(1)',
+ 2: 'OFPSCFC_EPERM(2)'}
+
+ elif error_type == int('B', 16):
+ if code in range(0, 3):
+ codes = {0: 'OFPRRFC_STALE(0)',
+ 1: 'OFPRRFC_UNSUP(1)',
+ 2: 'OFPRRFC_BAD_ROLE(2)'}
+
+ elif error_type == int('C', 16):
+ if code in range(0, 12):
+ codes = {0: 'OFPMMFC_UNKNOWN(0)',
+ 1: 'OFPMMFC_METER_EXISTS(1)',
+ 2: 'OFPMMFC_INVALID_METER(2)',
+ 3: 'OFPMMFC_UNKNOWN_METER(3)',
+ 4: 'OFPMMFC_BAD_COMMAND(4)',
+ 5: 'OFPMMFC_BAD_FLAGS(5)',
+ 6: 'OFPMMFC_BAD_RATE(6)',
+ 7: 'OFPMMFC_BAD_BURST(7)',
+ 8: 'OFPMMFC_BAD_BAND(8)',
+ 9: 'Bad_BOFPMMFC_BAD_BAND_VALUEand_Value(9)',
+ 10: 'OFPMMFC_OUT_OF_METERS(10)',
+ 11: 'OFPMMFC_OUT_OF_BANDS(11)'}
+
+ elif error_type == int('D', 16):
+ if code in range(0, 6):
+ codes = {0: 'OFPTFFC_BAD_TABLE(0)',
+ 1: 'OFPTFFC_BAD_METADATA(1)',
+ 2: 'OFPTFFC_BAD_TYPE(2)',
+ 3: 'OFPTFFC_BAD_LEN(3)',
+ 4: 'OFPTFFC_BAD_ARGUMENT(4)',
+ 5: 'OFPTFFC_EPERM(5)'}
+
+ return errors_types[error_type], codes[code]
+
+
+def get_feature_res_capabilities(cap):
+ caps = {1: 'FLOW_STATS(0x1)',
+ 2: 'TABLE_STATS(0x2)',
+ 4: 'PORT_STATS(0x4)',
+ 8: 'GROUP_STATS(0x8)',
+ 32: 'IP_REASM(0x20)',
+ 64: 'QUEUE_STATS(0x40)',
+ 256: 'PORT_BLOCKED(0x100)'}
+ try:
+ return caps[cap]
+ except KeyError:
+ return 'UnknownCapability(%s)' % cap
+
+
+def get_config_flags(flag):
+ flags = {0: 'FRAG_NORMAL(0)',
+ 1: 'FRAG_DROP(1)',
+ 2: 'FRAG_REASM(2)',
+ 3: 'FRAG_MASK(3)'}
+ try:
+ return flags[flag]
+ except KeyError:
+ return 'UnknownFlag(%s)' % flag
+
+
+def get_packet_in_reason(reason):
+ reasons = {0: 'OFPR_NO_MATCH(0)',
+ 1: 'OFPR_ACTION(1)',
+ 2: 'OFPR_INVALID_TTL'}
+ try:
+ return reasons[reason]
+ except KeyError:
+ return 'UnknownReason(%s)' % reason
+
+
+def get_flow_removed_reason(reason):
+ rsn = {0: 'OFPRR_IDLE_TIMEOUT(0)',
+ 1: 'OFPRR_HARD_TIMEOUT(1)',
+ 2: 'OFPRR_DELETE(2)',
+ 3: 'OFPRR_GROUP_DELETE'}
+ try:
+ return rsn[reason]
+ except KeyError:
+ return 'UnknownReason(%s)' % reason
+
+
+def get_port_status_reason(reason):
+ reasons = {0: 'OFPPR_ADD(0)',
+ 1: 'OFPPR_DELETE(1)',
+ 2: 'OFPPR_MODIFY(2)'}
+ try:
+ return reasons[reason]
+ except KeyError:
+ return 'UnknownReason(%s)' % reason
+
+
+def get_phy_port_id(p_id):
+ ids = {4294967040: 'OFPP_MAX(OxFFFFFF00)',
+ 4294967288: 'OFPP_IN_PORT(0xFFFFFFF8)',
+ 4294967289: 'OFPP_TABLE(0xFFFFFFF9)',
+ 4294967290: 'OFPP_NORMAL(0xFFFFFFFA)',
+ 4294967291: 'OFPP_FLOOD(0xFFFFFFFB)',
+ 4294967292: 'OFPP_ALL(0xFFFFFFFC)',
+ 4294967293: 'OFPP_CONTROLLER(0xFFFFFFFD)',
+ 4294967294: 'OFPP_LOCAL(0xFFFFFFFE)',
+ 4294967295: 'OFPP_ANY(0xFFFFFFFF)'}
+ try:
+ return ids[p_id]
+ except KeyError:
+ return '%s' % p_id
+
+
+def get_flow_match_fields(value):
+ values = {0: 'In_Port',
+ 1: 'In_Phy_Port',
+ 2: 'Metadata',
+ 3: 'Eth_Dst',
+ 4: 'Eth_Src',
+ 5: 'Eth_Type',
+ 6: 'Vlan_VID',
+ 7: 'Vlan_PCP',
+ 8: 'IP_DSCP',
+ 9: 'IP_ECN',
+ 10: 'IP_PROTO',
+ 11: 'IPv4_Src',
+ 12: 'IPv4_Dst',
+ 13: 'TCP_Src',
+ 14: 'TCP_Dst',
+ 15: 'UDP_Src',
+ 16: 'UDP_Dst',
+ 17: 'SCTP_Src',
+ 18: 'SCTP_Dst',
+ 19: 'ICMPv4_Type',
+ 20: 'ICMPv4_Code',
+ 21: 'ARP_OP',
+ 22: 'ARP_SPA',
+ 23: 'ARP_TPA',
+ 24: 'ARP_SHA',
+ 25: 'ARP_THA',
+ 26: 'IPv6_Src',
+ 27: 'IPv6_Dst',
+ 28: 'IPv6_FLabel',
+ 29: 'ICMPv6_Type',
+ 30: 'ICMPv6_Code',
+ 31: 'IPv6_ND_Target',
+ 32: 'IPv6_ND_SLL',
+ 33: 'IPv6_ND_TLL',
+ 34: 'MPLS_Label',
+ 35: 'MPLS_TC',
+ 36: 'MPLS_BoS',
+ 37: 'PBB_ISID',
+ 38: 'Tunnel_ID',
+ 39: 'IPv6_EXTHDR'}
+
+ try:
+ return '%s(%s)' % (values[value], value)
+ except KeyError:
+ return 'UnknownMatchField(%s)' % value
+
+
+def get_flow_mod_command(command):
+ commands = {0: 'OFPFC_ADD(0)',
+ 1: 'OFPFC_MODIFY(1)',
+ 2: 'OFPFC_MODIFY_STRICT(2)',
+ 3: 'OFPFC_DELETE(3)',
+ 4: 'OFPFC_DELETE_STRICT(4)'}
+ try:
+ return commands[command]
+ except KeyError:
+ return 'UnknownCommand(%s)' % command
+
+
+def get_flow_mod_flags(flag):
+ flags = {0: 'NoFlagSet(0)',
+ 1: 'OFPFF_SEND_FLOW_REM(0x1)',
+ 2: 'OFPFF_CHECK_OVERLAP(0x2)',
+ 4: 'OFPFF_RESET_COUNTS(0x4)',
+ 16: 'OFPFF_NO_PKT_COUNTS(0x10)',
+ 32: 'OFPFF_NO_BYT_COUNTS(0x20)'}
+ try:
+ return flags[flag]
+ except KeyError:
+ return 'UnknownFlag(%s)' % flag
+
+
+def get_ipv6_extension(bit):
+ options = {1: 'NO_NEXT',
+ 2: 'ESP',
+ 4: 'AUTH',
+ 8: 'DEST',
+ 16: 'FRAG',
+ 32: 'ROUTER',
+ 64: 'HOP',
+ 128: 'UNREP',
+ 256: 'UNSEQ'}
+ try:
+ return '%s(%s)' % (options[bit], hex(bit))
+ except KeyError:
+ return 'UnknownBit(%s)' % bit
+
+
+def get_instructions(instruction):
+ instructions = {1: 'GOTO_TABLE',
+ 2: 'WRITE_METADATA',
+ 3: 'WRITE_ACTIONS',
+ 4: 'APPLY_ACTIONS',
+ 5: 'CLEAR_ACTIONS',
+ 6: 'METER',
+ 65535: 'EXPERIMENTER'}
+
+ try:
+ return '%s(%s)' % (instructions[instruction], instruction)
+ except KeyError:
+ return 'UnknownInstruction(%s)' % instruction
+
+
+def get_group_mod_command(command):
+ commands = {0: 'OFPGC_ADD(0)',
+ 1: 'OFPGC_MODIFY(1)',
+ 2: 'OFPGC_DELETE(2)'}
+ try:
+ return commands[command]
+ except KeyError:
+ return 'UnknownCommand(%s)' % command
+
+
+def get_group_mod_type(type):
+ types = {0: 'OFPGT_ALL(0)',
+ 1: 'OFPGT_SELECT(1)',
+ 2: 'OFPGT_INDIRECT(2)',
+ 3: 'OFPGT_FF'}
+ try:
+ return types[type]
+ except KeyError:
+ return 'UnknownType(%s)' % type
+
+
+def get_multipart_request_flags(flag):
+ flags = {0: 'NOT_FLAG_SET(0)',
+ 1: 'OFPMPF_REQ_MORE(1)'}
+ try:
+ return flags[flag]
+ except KeyError:
+ return 'UnknownFlag(%s)' % flag
+
+
+def get_multipart_reply_flags(flag):
+ flags = {0: 'NOT_FLAG_SET(0)',
+ 1: 'OFPMPF_REPLY_MORE(1)'}
+ try:
+ return flags[flag]
+ except KeyError:
+ return 'UnknownFlag(%s)' % flag
+
+
+def get_controller_role(role):
+ roles = {0: 'OFPCR_ROLE_NOCHANGE(0)',
+ 1: 'OFPCR_ROLE_EQUAL(1)',
+ 2: 'OFPCR_ROLE_MASTER(2)',
+ 3: 'OFPCR_ROLE_SLAVE(3)'}
+ try:
+ return roles[role]
+ except KeyError:
+ return 'UnknownRole(%s)' % role
\ No newline at end of file
diff --git a/libs/openflow/of13/prints.py b/libs/openflow/of13/prints.py
new file mode 100644
index 0000000..7ebc346
--- /dev/null
+++ b/libs/openflow/of13/prints.py
@@ -0,0 +1,318 @@
+"""
+ OpenFlow 1.3 prints
+"""
+from hexdump import hexdump
+
+import libs.tcpiplib.prints
+from libs.gen.prints import red, green
+from libs.openflow import of13
+
+
+def print_pad(pad):
+ """
+ Used to print pads as a sequence of 0s: 0, 00, 000..
+ Args:
+ pad: pad in int format
+ Returns: string with '0'
+ """
+ pad_len = pad
+
+ print(type(pad_len))
+ string = '0'
+ if pad_len == 1:
+ return '0'
+ for item in range(0, pad_len-1):
+ string += '0'
+ return string
+
+
+# ################## OFPT_HELLO ############################
+
+
+def print_hello(msg):
+ count = 0
+ for element in msg.elements:
+ count += 1
+ print("Hello - Element: %s Type: %s Length: %s" %
+ (count, element.type, element.length))
+ count_bit = 0
+ for bitmap in element.versiobitmap:
+ count_bit += 1
+ print("Hello - Bitmap: %s Type: %s Length: %s" %
+ (count_bit, bitmap.type, bitmap.length))
+ print('Bitmap: %08d' % int(bitmap.bitmaps.split('b')[1]))
+
+
+# ################## OFPT_ERROR ############################
+
+
+def print_error_msg(msg):
+ print("Error - Type: %s Code: %s" % (msg.error_type, msg.code))
+ if len(msg.data):
+ print(hexdump(msg.data))
+ return 0
+
+
+# ################## OFPT_ECHO_REQUEST ############################
+
+
+def print_echo_request(msg):
+ if len(msg.data) > 1:
+ print("Echo - Data: %s" % msg.data)
+ return 0
+
+
+# ################## OFPT_ECHO_REPLY ############################
+
+
+def ofp_echo_reply(msg):
+ if len(msg.data) > 1:
+ print("Echo - Data: %s" % msg.data)
+ return 0
+
+
+# ################## OFPT_EXPERIMENTER ############################
+
+
+def print_experimenter(msg):
+ return 0
+
+
+# ################## OFPT_FEATURE_REQUEST ############################
+
+def parse_bitmask(bitmask, array):
+ size = len(array)
+ for i in range(0, size):
+ mask = 2**i
+ aux = bitmask & mask
+ if aux == 0:
+ array.remove(mask)
+ return array
+
+
+def parse_capabilities(capabilities):
+ caps = [1, 2, 4, 8, 16, 32, 64, 128, 256]
+ return parse_bitmask(capabilities, caps)
+
+
+def print_switch_features(msg):
+ print("OpenFlow Switch Features:")
+ print("Datapath_id: %s N_Buffers: %s N_Tbls: %s\nAuxiliary_id: %s "
+ "Pad: %s Reserved: %s" %
+ (red(msg.datapath_id),
+ msg.n_buffers, msg.n_tbls, msg.auxiliary_id,
+ msg.pad, green(msg.reserved)))
+ print("Capabilities: "),
+ caps = parse_capabilities(msg.capabilities)
+ for i in caps:
+ print(libs.openflow.of13.dissector.get_feature_res_capabilities(i)),
+ print
+
+# ########## OFPT_GET_CONFIG_REPLY & OFPT_SET_CONFIG ###############
+
+
+def print_switch_config(msg):
+ print('Switch Configuration - Flag: %s Miss_Send_Len: %s' %
+ (msg.flag, msg.miss_send_len))
+ return 0
+
+
+# ################## OFPT_PACKET_IN ############################
+
+
+def print_packet_in(msg):
+ return 0
+
+
+# ################## OFPT_FLOW_REMOVED ############################
+
+
+def print_flow_removed(msg):
+ return 0
+
+
+# ################## OFPT_PORT_STATUS ############################
+
+
+def print_port_status(msg):
+ print(msg.reason.__dict__)
+ print(msg.desc.__dict__)
+ string = ('PortStatus - Reason: %s Desc: %s Pad: %s' %
+ (msg.reason, msg.desc, msg.pad))
+
+ print(string)
+ return 0
+
+
+# ################## OFPT_PACKET_OUT ############################
+
+
+def print_packet_out(msg):
+ return 0
+
+
+# ################## OFPT_FLOW_MOD ############################
+
+
+def print_flow_mod(msg):
+ # Print main flow_mod options
+ string = ('FlowMod - Cookie/Mask: %s/%s Table_id: %s Command: %s '
+ 'Idle/Hard Timeouts: %s/%s\nFlowMod - Priority: %s '
+ 'Buffer ID: %s Out Port: %s Out Group: %s Flags: %s Pad: %s')
+
+ command = green(libs.openflow.of13.dissector.get_flow_mod_command(msg.command))
+ flags = green(libs.openflow.of13.dissector.get_flow_mod_flags(msg.flags))
+ port = green(libs.openflow.of13.dissector.get_phy_port_id(msg.out_port))
+ print(string % (msg.cookie, msg.cookie_mask,
+ msg.table_id, command, msg.idle_timeout,
+ msg.hard_timeout, msg.priority,
+ msg.buffer_id, port, msg.out_group,
+ flags, print_pad(msg.pad)))
+
+ # Print print_match_type(msg)
+ print_match_type(msg.match)
+ print_instruction(msg.instructions)
+
+
+def print_match_type(match):
+ print('Flow Matches - Type: %s Length: %s' % (match.type, match.length))
+ # print oxm_fields
+ print_match_oxm_fields(match.oxm_fields)
+
+
+def print_match_oxm_fields(oxm_fields):
+ for oxm in oxm_fields:
+ print_match_generic(oxm)
+ print_match_oxm(oxm)
+
+
+def print_match_generic(oxm):
+ print(' OXM Match: Class: %s Length: %s HasMask: %s Field: %s:' %
+ (hex(oxm.oxm_class), oxm.length, oxm.hasmask,
+ green(libs.openflow.of13.dissector.get_flow_match_fields(oxm.field)))),
+
+
+def print_match_oxm(oxm):
+ if oxm.hasmask == 0:
+ if oxm.field in [0]:
+ oxm.payload.value = oxm.payload.value & 0xffff
+ oxm.payload.value = libs.openflow.of13.dissector.get_phy_port_id(oxm.payload.value)
+ # DL_DST or DL_SRC
+ elif oxm.field in [3, 4, 24, 25, 32, 33]:
+ print(green(libs.tcpiplib.prints.eth_addr(oxm.payload.value)))
+ return
+ # DL_TYPE
+ elif oxm.field in [5]:
+ oxm.payload.value = hex(oxm.payload.value)
+ # DL_VLAN
+ elif oxm.field == 6:
+ if oxm.payload.value == 0:
+ oxm.payload.value = 'UNTAGGED'
+ else:
+ oxm.payload.value = oxm.payload.value & 0xfff
+ # NW_SRC or NW_DST
+ elif oxm.field in [11, 12, 22, 23]:
+ oxm.payload.value = libs.tcpiplib.prints.get_ip_from_long(oxm.payload.value)
+ # IPv6 Extensions
+ elif oxm.field in [39]:
+ extensions = of13.parser.parse_ipv6_extension_header(oxm.payload.values)
+ for i in extensions:
+ print(green(libs.openflow.of13.dissector.get_ipv6_extension(i))),
+
+ print('%s' % green(oxm.payload.value))
+
+ elif oxm.hasmask == 1:
+ if oxm.field in [3, 4, 24, 25]:
+ oxm.payload.value = libs.tcpiplib.prints.eth_addr(oxm.payload.value)
+ oxm.payload.mask = libs.tcpiplib.prints.eth_addr(oxm.payload.mask)
+ if oxm.field in [11, 12, 22, 23]:
+ oxm.payload.value = libs.tcpiplib.prints.get_ip_from_long(oxm.payload.value)
+ oxm.payload.mask = libs.tcpiplib.prints.get_ip_from_long(oxm.payload.mask)
+
+ print('%s/%s' % (green(oxm.payload.value), green(oxm.payload.mask)))
+
+
+def print_instruction(instructions):
+ print('Flow Instructions:')
+ for instruction in instructions:
+ print(' Instruction: Type %s Length: %s' %
+ (instruction.type, instruction.length))
+ for action in instruction.actions:
+ print(' Action - Type %s Length %s' % (action.type, action.length)),
+ if action.type == 0:
+ print("Port %s Max_Len %s Pad %s" %
+ (action.port, action.max_len, print_pad(action.pad)))
+ if action.type == 1:
+ print("VLAN_VID %s Pad %s" %
+ (action.vlan_vid, print_pad(action.pad)))
+
+
+# ################## OFPT_GROUP_MOD ############################
+
+
+def print_group_mod(msg):
+ return 0
+
+
+# ################## OFPT_PORT_MOD ############################
+
+
+def print_port_mod(msg):
+ return 0
+
+
+# ################## OFPT_TABLE_MOD ############################
+
+
+def print_table_mod(msg):
+ return 0
+
+
+# ################## OFPT_MULTIPART_REQUEST ############################
+
+
+def print_multipart_request(msg):
+ return 0
+
+
+# ################## OFPT_MULTIPART_REPLY ############################
+
+
+def print_multipart_reply(msg):
+ return 0
+
+
+# ################## OFPT_QUEUE_GET_CONFIG_REQUEST ############################
+
+
+def print_queue_get_config_request(msg):
+ return 0
+
+
+# ################## OFPT_QUEUE_GET_CONFIG_REPLY ############################
+
+
+def print_queue_get_config_reply(msg):
+ return 0
+
+
+# ########## OFPT_ROLE_REQUEST & OFPT_ROLE_REPLY ###############
+
+
+def print_role(msg):
+ return 0
+
+
+# ########### OFPT_GET_ASYNC_REPLY & OFPT_SET_ASYNC #####################
+
+
+def print_async_config(msg):
+ return 0
+
+
+# ################## OFPT_METER_MOD ############################
+
+
+def print_meter_mod(msg):
+ return 0
+
diff --git a/libs/tcpiplib/__init__.py b/libs/tcpiplib/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/libs/tcpiplib/packet.py b/libs/tcpiplib/packet.py
new file mode 100644
index 0000000..858d4bc
--- /dev/null
+++ b/libs/tcpiplib/packet.py
@@ -0,0 +1,396 @@
+"""
+ Module to define classes in use by the TCP/IP stack
+"""
+
+from struct import unpack
+import socket
+from datetime import datetime
+
+
+IP_PROTOCOL = 8
+TCP_PROTOCOL = 6
+TCP_FLAG_PUSH = 8
+OF_HEADER_SIZE = 8
+
+
+class L1:
+ """
+ Class to dissect L1 fields
+ """
+ def __init__(self):
+ self.caplen = None
+ self.truncate = None
+ self.time = None
+
+ def parse(self, header):
+ """
+ Parse object
+ """
+ self.caplen = header.getlen()
+ self.truncate = header.getcaplen()
+ self.time = self.set_time(header.getts())
+
+ @staticmethod
+ def set_time(date):
+ """
+ Get the time when the packet was captured
+
+ Args:
+ date: array provided by libpcap
+ Returns:
+ date processed by datetime
+ """
+ date = date[0] + date[1] / 100000
+ date = datetime.fromtimestamp(date)
+ date = date.strftime('%Y-%m-%d %H:%M:%S.%f')
+ return date
+
+
+class Ethernet:
+ """
+ Class to dissect Ethernet fields
+ """
+ def __init__(self):
+ self.src_mac = None
+ self.dst_mac = None
+ self.protocol = None
+ self.length = 14 # Ethernet header has 14 bytes
+
+ def parse(self, packet, host_order=0):
+ """
+ Parses packet, converting from binary to Ethernet
+
+ Args:
+ packet: binary object
+ host_order: just to help defining the host order
+ """
+ eth_raw = packet[:self.length]
+ ethernet = unpack('!6s6sH', eth_raw)
+ self.dst_mac = ethernet[0]
+ self.src_mac = ethernet[1]
+
+ # When Ethernet is captured directly from the wire,
+ # it uses host_order big-endian. When the frame is encapsulated
+ # inside an OpenFlow PacketIn or Out, it is little-endian
+ if not host_order:
+ self.protocol = socket.ntohs(ethernet[2])
+ else:
+ self.protocol = ethernet[2]
+ return self.length
+
+
+class IP:
+ """
+ Class to dissect IP fields
+ """
+ def __init__(self):
+ self.version = None
+ self.ihl = None
+ self.length = 20 # Minimum length
+ self.ttl = None
+ self.protocol = None
+ self.s_addr = None
+ self.d_addr = None
+
+ def parse(self, packet, offset):
+ """
+ Parses packet, converting from binary to IP
+
+ Args:
+ packet: binary object
+ offset: position to start
+ """
+ ip_raw = packet[offset:self.length + offset]
+ iph = unpack('!BBHHHBBH4s4s', ip_raw)
+ version_ihl = iph[0]
+ self.version = version_ihl >> 4
+ self.ihl = version_ihl & 0xF
+ self.length = self.ihl * 4
+ self.ttl = iph[5]
+ self.protocol = iph[6]
+ self.s_addr = socket.inet_ntoa(iph[8])
+ self.d_addr = socket.inet_ntoa(iph[9])
+ return self.length + offset
+
+
+class TCP:
+ """
+ Class to dissect TCP fields
+ """
+ def __init__(self):
+ self.source_port = None
+ self.dest_port = None
+ self.sequence = None
+ self.acknowledgement = None
+ self.length = 20 # minimum length.
+ self.flag_cwr = None
+ self.flag_ece = None
+ self.flag_urg = None
+ self.flag_ack = None
+ self.flag_psh = None
+ self.flag_rst = None
+ self.flag_syn = None
+ self.flag_fyn = None
+
+ def parse(self, packet, offset):
+ """
+ Parses packet, converting from binary to TCP
+
+ Args:
+ packet: binary object
+ offset: position to start
+ """
+ tcp_raw = packet[offset:offset + self.length]
+ tcph = unpack('!HHLLBBHHH', tcp_raw)
+ self.source_port = tcph[0]
+ self.dest_port = tcph[1]
+ self.sequence = tcph[2]
+ self.acknowledgement = tcph[3]
+ doff_reserved = tcph[4]
+ tcph_length = doff_reserved >> 4
+ self.length = tcph_length * 4
+ flags = tcph[5]
+ self.flag_cwr = flags & 0x80
+ self.flag_ece = flags & 0x40
+ self.flag_urg = flags & 0x20
+ self.flag_ack = flags & 0x10
+ self.flag_psh = flags & 0x08
+ self.flag_rst = flags & 0x04
+ self.flag_syn = flags & 0x02
+ self.flag_fyn = flags & 0x01
+ return self.length + offset
+
+
+class VLAN:
+ """
+ Class to dissect VLAN fields
+ """
+ def __init__(self):
+ self.vid = None
+ self.cfi = None
+ self.pcp = None
+ self.protocol = None
+ self.ethertype = None
+
+ def parse(self, packet):
+ """
+ Parses packet, converting from binary to VLAN
+
+ Args:
+ packet: binary object
+ """
+ vlan_length = 2
+ ethertype = 2
+ vlan_raw = packet[:vlan_length + ethertype]
+ vlan_p = unpack('!HH', vlan_raw)
+ self.pcp = vlan_p[0] >> 13
+ self.cfi = (vlan_p[0] & 0x1000) >> 12
+ self.vid = vlan_p[0] & 0xfff
+ self.protocol = vlan_p[1]
+ self.ethertype = self.protocol
+
+
+class LLDP:
+ """
+ Class to dissect LLDP fields
+ This is not a full LLDP dissection, just basic fields
+ The idea is to get the DPID and ports
+ """
+ def __init__(self):
+ self.c_type = None
+ self.c_length = None
+ self.c_subtype = None
+ self.c_id = None
+ self.p_type = None
+ self.p_length = None
+ self.p_subtype = None
+ self.p_id = None
+ self.t_type = None
+ self.t_length = None
+ self.t_ttl = None
+ self.e_type = None
+ self.e_length = None
+
+ def parse(self, packet):
+ """
+ Parses packet, converting from binary to LLDP
+
+ Args:
+ packet: binary object
+ """
+
+ # Chassis
+ # TLV (1) + Length = 2 bytes | Sub-type = 1 Byte
+ chassis_raw = packet[:3]
+ chassis = unpack('!HB', chassis_raw)
+ self.c_type = chassis[0] >> 9
+ if self.c_type is not 1:
+ return {}
+
+ self.c_length = chassis[0] & 0xFF
+ self.c_subtype = chassis[1]
+ length = self.c_length - 1
+ # Get C_ID
+ chassis_raw = packet[3:3 + length]
+ string = '!%ss' % length
+ chassis = unpack(string, chassis_raw)
+ self.c_id = chassis[0].decode("utf-8")
+
+ start = 3 + length
+
+ # Port
+ # TLV (2) + Length = 2 Bytes | Port_id = 1 Byte
+ port_raw = packet[start:start + 3]
+ port = unpack('!HB', port_raw)
+ self.p_type = port[0] >> 9
+ if self.p_type is not 2:
+ return {}
+ self.p_length = port[0] & 0xFF
+ self.p_subtype = port[1]
+ length = self.p_length - 1
+ # Get P_ID
+ port_raw = packet[start + 3:start + 3 + length]
+ # string = '!%ss' % length
+ if length is 1:
+ string = '!B'
+ elif length is 2:
+ string = '!H'
+ elif length is 4:
+ string = '!L'
+ else:
+ string = '!%ss' % length
+ port = unpack(string, port_raw)
+ self.p_id = port[0]
+
+ start = start + 3 + length
+
+ # TTL
+ ttl_raw = packet[start:start + 4]
+ ttl = unpack('!HH', ttl_raw)
+ self.t_type = ttl[0] >> 9
+ if self.t_type is not 3:
+ return {}
+ self.t_length = ttl[0] & 0xFF
+ self.t_ttl = ttl[1]
+
+ start += 4
+
+ # Loop to get User-Specific TLVs
+ while len(packet[start:]) > 2:
+ next_raw = packet[start:start + 2]
+ nraw = unpack('!H', next_raw)
+ n_type = nraw[0] >> 9
+ n_length = nraw[0] & 0xFF
+ length = n_length - 4
+ if n_type == 0:
+ break
+ elif n_type == 127:
+ # We only want TLV 127, OUI a42305 (ONOS)
+ # Then we will look for Subtype 2 and get the content
+ # Skip the OUI - 3 bytes
+ subtype_raw = packet[start + 5:start + 6]
+ subtype = unpack('!B', subtype_raw)
+ if subtype[0] == 2:
+ content_raw = packet[start + 6:start + 6 + length]
+ string = '!%ss' % length
+ content = unpack(string, content_raw)
+ self.c_id = content[0]
+
+ start = start + n_length + 2
+
+ # END
+ end_raw = packet[start:start + 2]
+ end = unpack('!H', end_raw)
+ self.e_type = end[0] >> 9
+ self.e_length = end[0] & 0xFF
+
+
+class ARP:
+ """
+ Class to dissect ARP fields
+ """
+ def __init__(self):
+ self.hw_type = None
+ self.prot_type = None
+ self.hw_len = None
+ self.prot_len = None
+ self.opcode = None
+ self.src_mac = None
+ self.src_ip = None
+ self.dst_mac = None
+ self.dst_ip = None
+
+ def parse(self, packet):
+ """
+ Parses packet, converting from binary to ARP
+
+ Args:
+ packet: binary object
+ """
+ arp_raw = packet[:28]
+ arp = unpack('!HHBBH6sL6sL', arp_raw)
+ self.hw_type = arp[0]
+ self.prot_type = arp[1]
+ self.hw_len = arp[2]
+ self.prot_len = arp[3]
+ self.opcode = arp[4]
+ self.src_mac = arp[5]
+ self.src_ip = arp[6]
+ self.dst_mac = arp[7]
+ self.dst_ip = arp[8]
+
+
+class OessFvd:
+ """
+ OESS' FVD module
+ """
+ def __init__(self):
+ self.side_a = None
+ self.port_a = None
+ self.side_z = None
+ self.port_z = None
+ self.timestamp = None
+
+ def parse(self, packet):
+ """
+ Parses packet, converting from binary to OESS FVD
+
+ Args:
+ packet: binary object
+ """
+ self.side_a = self.get_datapath_id(packet[0:8])
+ self.port_a = self.port_id(packet[8:16])
+ self.side_z = self.get_datapath_id(packet[16:24])
+ self.port_z = self.port_id(packet[24:32])
+ self.timestamp = self.get_timestamp(packet[32:])
+
+ @staticmethod
+ def read_field(value):
+ """
+ Method used to convert from bytes to string
+ Created to work with Python3
+ """
+ string = '%02x' * len(value)
+ return string % tuple(value)[::-1]
+
+ def get_datapath_id(self, dpid):
+ """
+ Convert OpenFlow Datapath ID to human format
+ """
+ dpid = self.read_field(dpid)
+ return ':'.join(dpid[i:i+2] for i in range(0, 16, 2))
+
+ def get_timestamp(self, timestamp):
+ """
+ Convert binary to timestamp
+ """
+ timestamp = self.read_field(timestamp)
+
+ return int(timestamp, base=16) / 1000
+
+ def port_id(self, port):
+ """
+ Convert OpenFlow Port ID to human format
+ """
+ port = self.read_field(port)
+ return int(port, base=16)
diff --git a/libs/tcpiplib/prints.py b/libs/tcpiplib/prints.py
new file mode 100644
index 0000000..c0bfab6
--- /dev/null
+++ b/libs/tcpiplib/prints.py
@@ -0,0 +1,242 @@
+"""
+ Printing TCP/IP classes
+"""
+import socket
+import struct
+from datetime import datetime
+import libs.openflow.of10.dissector
+import libs.tcpiplib.tcpip
+from libs.core.printing import PrintingOptions
+from libs.gen.prints import red, green, blue, yellow, cyan
+from libs.tcpiplib.tcpip import get_ethertype
+from apps.ofp_proxies import OFProxy
+
+
+def eth_addr(a):
+ """
+ Print Mac Address in the human format
+ Args:
+ a: string "6s"
+ Returns:
+ mac in the human format
+ """
+ if isinstance(a, bytes):
+ a = a.decode("latin")
+ string = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"
+ mac = string % (ord(a[0]), ord(a[1]), ord(a[2]),
+ ord(a[3]), ord(a[4]), ord(a[5]))
+ return mac
+
+
+def get_ip_from_long(long_ip):
+ """
+ Get IP from a long int
+ Args:
+ long_ip: IP in the long int format
+
+ Returns: IP in the format x.x.x.x
+ """
+ return socket.inet_ntoa(struct.pack('!L', long_ip))
+
+
+def datapath_id(a):
+ """
+ Convert OpenFlow Datapath ID to human format
+ Args:
+ a: DPID in "8s" format
+ Returns:
+ DPID in human format
+ """
+ string = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"
+ if isinstance(a, bytes):
+ a = a.decode("latin")
+ dpid = string % (ord(a[0]), ord(a[1]), ord(a[2]), ord(a[3]),
+ ord(a[4]), ord(a[5]), ord(a[6]), ord(a[7]))
+ return dpid
+
+
+def print_headers(pkt, overwrite_min=0):
+ """
+ Print TCP/IP header. It uses command line option -p
+ to print 'mininal' or 'full' headers
+ Args:
+ pkt: OFMessage class
+ overwrite_min: in case of problems, overwrite user definition
+ """
+ if PrintingOptions().min == 1 and overwrite_min == 0:
+ print_minimal(pkt.position, pkt.l1.time, pkt.l1.caplen, pkt.l3,
+ pkt.l4)
+ else:
+ print_position(pkt.position)
+ print_layer1(pkt.l1.time, pkt.l1.caplen, pkt.l1.truncate)
+ print_layer2(pkt.l2)
+ print_layer3(pkt.l3)
+ print_tcp(pkt.l4)
+
+
+def print_minimal(position, date, getlen, ip_addr, tcp):
+ """
+ Print TCP/IP header with minimal information
+ Args:
+ position: packet count
+ date: date/time packet was captured
+ getlen: total number of bytes captured
+ ip_addr: IP class
+ tcp: TCP class
+ """
+ string = 'Packet #%s - %s %s:%s -> %s:%s Size: %s Bytes'
+
+ source = OFProxy().get_name(ip_addr.s_addr, tcp.source_port)
+ dest = OFProxy().get_name(ip_addr.d_addr, tcp.dest_port)
+
+ print(string % (position, date, cyan(source), cyan(tcp.source_port),
+ cyan(dest), cyan(tcp.dest_port), getlen))
+
+
+def print_position(position):
+ """
+ Print the packet counter (ctr) number
+ Args:
+ position: number of the packet captured in the sequence
+ """
+ print('Packet Number # %s' % position)
+
+
+def print_layer1(date, getlen, caplen):
+ """
+ Prints information about the captured packet
+ Args:
+ date: date/time when the packet was captured
+ getlen: total packet captured
+ caplen: truncated size of the packet captured
+ """
+ print('%s: captured %d bytes, truncated to %d bytes' %
+ (date, getlen, caplen))
+
+
+def print_layer2(eth):
+ """
+ Prints the Ethernet frame
+ Args:
+ eth: Ethernet class
+ """
+ print('Ethernet: Destination MAC: %s Source MAC: %s Protocol: %s' %
+ (eth_addr(eth.dst_mac), eth_addr(eth.src_mac),
+ red(libs.tcpiplib.tcpip.get_ethertype(eth.protocol))))
+
+
+def print_vlan(vlan):
+ """
+ Print VLAN fields
+ Args:
+ vlan: VLAN class
+ """
+ print('VLAN: PCP: %s CFI: %s VID: %s Protocol: %s' %
+ (vlan.pcp, vlan.cfi, red(vlan.vid),
+ red(get_ethertype(vlan.ethertype))))
+
+
+def print_arp(arp):
+ """
+ Print ARP fields
+ Args:
+ arp: ARP class
+ """
+ print('ARP: Hardware Type: %s Protocol Type: %s '
+ 'HW Length: %s Prot Length: %s Opcode: %s '
+ '\nARP: Source MAC: %s Source IP: %s Destination MAC: %s '
+ 'Destination IP: %s'
+ % (arp.hw_type, arp.prot_type, arp.hw_len,
+ arp.prot_len, arp.opcode,
+ eth_addr(arp.src_mac), get_ip_from_long(arp.src_ip),
+ eth_addr(arp.dst_mac), get_ip_from_long(arp.dst_ip)))
+
+
+def print_layer3(ip_addr):
+ """
+ Prints IP headers
+ Args:
+ ip: IP class
+ """
+ print(('IP Version: %d IP Header Length: %d TTL: %d Protocol: %d '
+ 'Source Address: %s Destination Address: %s') %
+ (ip_addr.version, ip_addr.length, ip_addr.ttl, ip_addr.protocol,
+ blue(ip_addr.s_addr), blue(ip_addr.d_addr)))
+
+
+def print_tcp(tcp):
+ """
+ Print TCP headers
+ Args:
+ tcp: TCP class
+ """
+ print('TCP Source Port: %s Dest Port: %s Sequence Number: %s '
+ 'Acknowledgement: %s TCP header length: %s Flags: CWR: %s '
+ 'ECE: %s URG: %s ACK: %s PSH: %s RST: %s SYN: %s FYN: %s' %
+ (tcp.source_port, tcp.dest_port, tcp.sequence,
+ tcp.acknowledgement, tcp.length, tcp.flag_cwr,
+ tcp.flag_ece, tcp.flag_urg, tcp.flag_ack, tcp.flag_psh,
+ tcp.flag_rst, tcp.flag_syn, tcp.flag_fyn))
+
+
+def print_openflow_header(ofp):
+ """
+ Print OpenFlow header
+ Args:
+ ofp: OFMessage class
+ """
+ version = libs.tcpiplib.tcpip.get_ofp_version(ofp.header.version.value)
+ name_version = '%s(%s)' % (version, ofp.header.version.value)
+
+ name = "%s" % ofp.header.message_type
+ name_type = '%s(%s)' % (name.split('.')[1], ofp.header.message_type.value)
+
+ print('OpenFlow Version: %s Type: %s Length: %s XID: %s' %
+ (name_version, yellow(name_type), ofp.header.length, red(ofp.header.xid)))
+
+
+def print_lldp(lldp):
+ """
+ Print LLDP fields
+ Args:
+ lldp: LLDP class
+ """
+ if lldp.c_type is not 1 or lldp.p_type is not 2 \
+ or lldp.t_type is not 3 or lldp.e_type is not 0:
+ print('LLDP: Malformed packet')
+ return
+
+ if lldp.c_type is 1:
+ print('LLDP: Chassis Type(%s) Length: %s SubType: %s ID: %s' %
+ (lldp.c_type, lldp.c_length, lldp.c_subtype, green(lldp.c_id)))
+ if lldp.p_type is 2:
+ print('LLDP: Port Type(%s) Length: %s SubType: %s ID: %s' %
+ (lldp.p_type, lldp.p_length, lldp.p_subtype, green(lldp.p_id)))
+ if lldp.t_type is 3:
+ print('LLDP: TTL(%s) Length: %s Seconds: %s' %
+ (lldp.t_type, lldp.t_length, lldp.t_ttl))
+
+ if lldp.e_type is 0:
+ print('LLDP: END(%s) Length: %s' % (lldp.e_type, lldp.e_length))
+
+
+def print_oessfvd(fvd):
+ """
+ Print FVD fields
+ Args:
+ fvd: OessFvd class
+ """
+ timestamp = str(datetime.fromtimestamp(fvd.timestamp))
+ print('OESS FVD: %s:%s -> %s:%s time: %s' %
+ (red(fvd.side_a), blue(fvd.port_a), red(fvd.side_z), blue(fvd.port_z),
+ blue(timestamp)))
+
+
+def print_connection_restablished(pkt):
+ """
+ Just prints that the TCP connection was restablished.
+ Args:
+ pkt: Packet class
+ """
+ print_headers(pkt, overwrite_min=0)
+ print(red("!!!! Attention: Connection Re-Established!!\n"))
diff --git a/libs/tcpiplib/process_data.py b/libs/tcpiplib/process_data.py
new file mode 100644
index 0000000..c84c4c8
--- /dev/null
+++ b/libs/tcpiplib/process_data.py
@@ -0,0 +1,182 @@
+"""
+ This module has functions to help processing the data from
+ PacketIn and PacketOut.
+"""
+
+
+from pyof.foundation.basic_types import BinaryData
+from libs.tcpiplib.packet import Ethernet, VLAN, IP, TCP, LLDP, ARP, OessFvd
+
+
+def dissect_data(data, start=0):
+ """
+ This function aims to dissect PacketIn and PacketOut data
+ It assumes it is
+ Ethernet [vlan] (BDDP|LLDP|ARP|IP) [TCP|UDP]
+ Args:
+ data: BinaryData
+ start: offset
+ Returns:
+ payload: array with all classes
+ """
+ packet = data.value
+ payload = []
+ # Ethernet
+ eth = Ethernet()
+ eth.parse(packet[start:start + 14], 1)
+ payload.append(eth)
+
+ # VLAN or not - ETYPE 0x8100 or 33024
+ etype = '0x0000'
+
+ start += 14
+ if eth.protocol in [33024]:
+ # Frame has VLAN
+
+ vlan = VLAN()
+ vlan.parse(packet[start:start + 4])
+ payload.append(vlan)
+ etype = vlan.protocol
+ start += 4
+ else:
+ etype = eth.protocol
+
+ # if there is no content, return
+ if len(packet[start:]) == 0:
+ return payload
+
+ # OESS FVD
+ if etype in [34998]:
+ fvd = OessFvd()
+ try:
+ fvd.parse(packet[start:])
+ except Exception as error:
+ print(error)
+ payload.append(fvd)
+ return payload
+
+ # LLDP - ETYPE 0x88CC or 35020 or
+ # BBDP - ETYPE 0x8942 or 35138
+ if etype in [35020, 35138]:
+ lldp = LLDP()
+ try:
+ lldp.parse(packet[start:])
+ except:
+ pass
+ if not isinstance(lldp, LLDP):
+ lldp.c_id = 0
+ else:
+ payload.append(lldp)
+ return payload
+
+ # IP - ETYPE 0x800 or 2048
+ if etype in [2048]:
+ ip_addr = IP()
+ ip_addr.parse(packet, start)
+ payload.append(ip_addr)
+ if ip_addr.protocol is 6:
+ tcp = TCP()
+ tcp.parse(packet, start + ip_addr.length)
+ payload.append(tcp)
+ return payload
+
+ # ARP - ETYPE 0x806 or 2054
+ if etype in [2054]:
+ arp = ARP()
+ arp.parse(packet[start:])
+ payload.append(arp)
+ return payload
+
+ return payload
+
+
+def is_protocol(data, lldp=False, oess=False, arp=False):
+ """
+ Check if Data is protocol provided
+ Args:
+ data: PacketOut/PacketIn/OESS data
+ lldp: check for lldp
+ oess: check for oess
+ arp: check for arp
+ Returns:
+ protocol class if True
+ False if it is not
+ """
+ protocol = []
+ return_protocol = False
+ if lldp:
+ protocol.append(35020) # LLDP
+ protocol.append(35138) # BDDP
+ elif oess:
+ protocol.append(34998) # Private
+ elif arp:
+ protocol.append(2054) # ARP 0x806
+ else:
+ return_protocol = True
+
+ if isinstance(data, BinaryData):
+ data = dissect_data(data)
+
+ try:
+ eth = data.pop(0)
+ next_protocol = eth.protocol
+
+ if next_protocol in [33024]:
+ vlan = data.pop(0)
+ if return_protocol:
+ return vlan.protocol
+
+ next_protocol = vlan.protocol
+
+ if next_protocol in protocol:
+ return True
+
+ return False
+
+ except Exception as error:
+ print(error)
+ return False
+
+
+def get_protocol(data, lldp=False, oess=False, arp=False):
+ """
+ Get protocol from data
+ Args:
+ data: PacketOut/PacketIn/OESS data
+ lldp: check for lldp
+ oess: check for oess
+ arp: check for arp
+ Returns:
+ protocol class if True
+ False if it is not
+ """
+ protocol = []
+ if lldp:
+ protocol.append(35020) # LLDP
+ protocol.append(35138) # BDDP
+ elif oess:
+ protocol.append(34998) # Private
+ elif arp:
+ protocol.append(2054) # ARP 0x806
+ else:
+ return False
+
+ if isinstance(data, BinaryData):
+ data = dissect_data(data)
+
+ try:
+ eth = data.pop(0)
+ next_protocol = eth.protocol
+
+ if next_protocol in [33024]:
+ vlan = data.pop(0)
+ next_protocol = vlan.protocol
+
+ if next_protocol in protocol:
+ return data.pop(0)
+
+ return False
+
+ except Exception as error:
+ print(error)
+ return False
diff --git a/libs/tcpiplib/tcpip.py b/libs/tcpiplib/tcpip.py
new file mode 100644
index 0000000..cdc9257
--- /dev/null
+++ b/libs/tcpiplib/tcpip.py
@@ -0,0 +1,77 @@
+"""
+ This module helps to translate numbers to names in the
+ TCP/IP stack
+"""
+
+
+from struct import unpack
+
+
+def get_ethertype(etype):
+ """
+ Converts Ethertype from number to name
+ Args:
+ etype: etype number collected
+ Returns:
+ etype name
+ """
+ etypes = {8: 'IP',
+ 2048: 'IP',
+ 2054: 'ARP',
+ 33024: 'VLAN',
+ 34925: 'IPv6',
+ 34887: 'MPLS',
+ 35020: 'LLDP',
+ 35138: 'BBDP',
+ 34998: 'PRIVATE'}
+ try:
+ return '%s(%s)' % (etypes[etype], hex(etype))
+ except KeyError:
+ return hex(etype)
+
+
+def get_ofp_version(version):
+ """
+ Converts OpenFlow version number to a human version
+ Args:
+ version: integer version of the OpenFlow version
+ Returns:
+ human version of the OpenFlow version
+ """
+ of_versions = {0: 'Experimental',
+ 1: '1.0',
+ 2: '1.1',
+ 3: '1.2',
+ 4: '1.3',
+ 5: '1.4',
+ 6: '1.5'}
+ try:
+ return of_versions[version]
+ except KeyError:
+ return 'Unknown(%s)' % version
+
+
+def get_openflow_header(packet, start):
+ """
+ Returns OpenFlow header
+ It is not a version aware
+ Args:
+ packet: packet content
+ start: offset
+ """
+ of_header_length = 8
+ of_header = packet[start:of_header_length+start]
+ try:
+ ofh = unpack('!BBHL', of_header)
+ of_version = ofh[0]
+ of_type = ofh[1]
+ of_length = ofh[2]
+ of_xid = ofh[3]
+ of_header = {'version': of_version, 'type': of_type,
+ 'length': of_length, 'xid': of_xid}
+ return of_header
+
+ except Exception as exception:
+ print(exception)
+ of_header['version'] = -1
+ return of_header
diff --git a/ofp_cli.py b/ofp_cli.py
deleted file mode 100644
index e5e9a37..0000000
--- a/ofp_cli.py
+++ /dev/null
@@ -1,98 +0,0 @@
-import sys
-import getopt
-import json
-
-
-VERSION = '0.2'
-NO_COLOR = False
-
-
-def usage(file):
- """ This funcion prints the Usage in case of errors or help needed.
- Always ends after printing this lines below.
- """
- print (('Usage: \n %s [-p min|full] [-f pcap_filter] [-F filter_file]'
- ' [-i dev] [-r pcap_file]\n'
- '\t -p [min|full] or --print=[min|full]: print min or full'
- ' packet headers. Default: min\n'
- '\t -f pcap_filter or --pcap-filter=pcap_filter : add a libpcap'
- ' filter\n'
- '\t -F sanitizer_file.json or --sanitizer-file=sanitizerfile.json\n'
- '\t -i interface or --interface=interface. Default: eth0\n'
- '\t -r captured.pcap or --src-file=captured.pcap\n'
- '\t -o or --print-ovs : print using ovs-ofctl format\n'
- '\t -h or --help : prints this guidance\n'
- '\t -c or --no-colors: removes colors\n'
- '\t -v or --version : prints version\n') % file)
-
- sys.exit(0)
-
-
-def read_sanitizer(sanitizer_file):
- try:
- jfile = open(sanitizer_file, 'ro')
- json_content = json.loads(jfile.read())
- except:
- msg = 'Error Opening the sanitizer file\n'
- msg += 'Please check your JSON file. Maybe the permission is wrong'
- msg += ' or the JSON syntax is incorrect. Try the following:\n'
- msg += 'cat %s | python -m json.tool'
- print msg % sanitizer_file
- sys.exit(0)
- return (json_content)
-
-
-def get_params(argv):
- # Handle all input params
- letters = 'f:F:i:r:p:ohvc'
- keywords = ['print=', 'pcap-filter=', 'sanitizer-file=', 'interface=',
- 'src-file=', 'print-ovs', 'help', 'version', 'no-colors']
-
- # Default Values
- input_filter, sanitizer_file, dev, captured_file = '', '', 'eth0', ''
-
- try:
- opts, extraparams = getopt.getopt(argv[1:], letters, keywords)
- except getopt.GetoptError as err:
- print str(err)
- usage(argv[0])
-
- print_options = {'min': 1, 'ovs': 0, 'colors': 0}
-
- for option, param in opts:
- if option in ['-p', '--print']:
- if param == 'full':
- print_options['min'] = 0
- elif param != 'min':
- print 'Use min or full for printing'
- usage(argv[0])
- elif option in ['-f', '--pcap-filter']:
- input_filter = param
- elif option in ['-F', '--sanitizer-file']:
- sanitizer_file = param
- elif option in ['-i', '--interface']:
- dev = param
- elif option in ['-r', '--captured-file']:
- captured_file = param
- elif option in ['-h', '--help']:
- usage(argv[0])
- elif option in ['-o', '--print-ovs']:
- print_options['ovs'] = 1
- elif option in ['-v', '--version']:
- print 'OpenFlow Sniffer version %s' % VERSION
- sys.exit(0)
- elif option in ['-c', '--no-colors']:
- global NO_COLOR
- NO_COLOR = True
- else:
- usage(argv[0])
-
- if len(sanitizer_file) == 0:
- sanitizer = {'allowed_of_versions': {},
- 'packetInOut_filter': {},
- 'flowMod_logs': {},
- 'packetIn_filter': {}}
- else:
- sanitizer = read_sanitizer(sanitizer_file)
-
- return print_options, input_filter, sanitizer, dev, captured_file
diff --git a/ofp_fsfw_v10.py b/ofp_fsfw_v10.py
deleted file mode 100644
index 4fb66bb..0000000
--- a/ofp_fsfw_v10.py
+++ /dev/null
@@ -1,38 +0,0 @@
-NET = {}
-name = {"cc4e249102000000": "andes2",
- "cc4e249126000000": "andes1",
- "cc4e244b11000000": "sol2",
- "0024389406000000": "mct01",
- "002438af17000000": "mct02",
- "2438af17000000": "mct02",
- "24389406000000": "mct01"}
-
-
-def support_fsfw(print_options, lldp):
- global NET
-
- ip = print_options['device_ip']
- port = print_options['device_port']
- dpid = lldp['c_id'].split(':')[1]
-
- name = get_name_dpid(dpid)
- NET[ip, port] = name
- return
-
-
-def get_name_dpid(dpid):
- return '%s' % name.get(dpid)
-
-
-def get_ip_name(ip, port):
- for i, j in NET.iteritems():
- if i == (ip, port):
- return '%s(%s)' % (ip, j)
- return ip
-
-
-def close():
- print '\n'
- # Future: send to a file to import faster
- # for i, j in NET.iteritems():
- # print i, j
diff --git a/ofp_parser_v10.py b/ofp_parser_v10.py
deleted file mode 100644
index 3b43009..0000000
--- a/ofp_parser_v10.py
+++ /dev/null
@@ -1,891 +0,0 @@
-from struct import unpack
-import ofp_dissector_v10
-import ofp_prints_v10
-import socket
-import struct
-import ofp_tcpip_parser
-import ofp_vendors_v10
-import ofp_fsfw_v10
-
-
-def process_ofp_type(of_type, packet, h_size, of_xid, print_options, sanitizer):
- if of_type == 0:
- result = parse_Hello(packet, h_size, of_xid)
- elif of_type == 1:
- result = parse_Error(packet, h_size, of_xid)
- elif of_type == 2:
- result = parse_EchoReq(packet, h_size, of_xid)
- elif of_type == 3:
- result = parse_EchoRes(packet, h_size, of_xid)
- elif of_type == 4:
- result = parse_Vendor(packet, h_size, of_xid)
- elif of_type == 5:
- result = parse_FeatureReq(packet, h_size, of_xid)
- elif of_type == 6:
- result = parse_FeatureRes(packet, h_size, of_xid)
- elif of_type == 7:
- result = parse_GetConfigReq(packet, h_size, of_xid)
- elif of_type == 8:
- result = parse_GetConfigRes(packet, h_size, of_xid)
- elif of_type == 9:
- result = parse_SetConfig(packet, h_size, of_xid)
- elif of_type == 10:
- result = parse_PacketIn(packet, h_size, of_xid, sanitizer)
- elif of_type == 11:
- result = parse_FlowRemoved(packet, h_size, of_xid)
- elif of_type == 12:
- result = parse_PortStatus(packet, h_size, of_xid)
- elif of_type == 13:
- result = parse_PacketOut(packet, h_size, of_xid, sanitizer,
- print_options)
- elif of_type == 14:
- result = parse_FlowMod(packet, h_size, of_xid, print_options)
- elif of_type == 15:
- result = parse_PortMod(packet, h_size, of_xid)
- elif of_type == 16:
- result = parse_StatsReq(packet, h_size, of_xid)
- elif of_type == 17:
- result = parse_StatsRes(packet, h_size, of_xid)
- elif of_type == 18:
- result = parse_BarrierReq(packet, h_size, of_xid)
- elif of_type == 19:
- result = parse_BarrierRes(packet, h_size, of_xid)
- elif of_type == 20:
- result = parse_QueueGetConfigReq(packet, h_size, of_xid)
- elif of_type == 21:
- result = parse_QueueGetConfigRes(packet, h_size, of_xid)
- else:
- return 0
- return result
-
-
-# *************** Hello *****************
-def parse_Hello(packet, h_size, of_xid):
- ofp_prints_v10.print_of_hello(of_xid)
- return 1
-
-
-# ************** Error *****************
-def parse_Error(packet, h_size, of_xid):
- of_error = packet[h_size:h_size+4]
- ofe = unpack('!HH', of_error)
- ofe_type = ofe[0]
- ofe_code = ofe[1]
-
- nameCode, typeCode = ofp_dissector_v10.get_ofp_error(ofe_type, ofe_code)
- ofp_prints_v10.print_of_error(of_xid, nameCode, typeCode)
- return 1
-
-
-# ************ EchoReq *****************
-def parse_EchoReq(packet, h_size, of_xid):
- ofp_prints_v10.print_echoreq(of_xid)
- return 1
-
-
-# ************ EchoRes *****************
-def parse_EchoRes(packet, h_size, of_xid):
- ofp_prints_v10.print_echores(of_xid)
- return 1
-
-
-# ************ Vendor ******************
-def parse_Vendor(packet, h_size, of_xid):
- of_vendor = packet[h_size:h_size+4]
- ofv = unpack('!L', of_vendor)
- ofp_prints_v10.print_of_vendor(ofv[0], of_xid)
-
- # If code 8992 = NICIRA
- if ofv[0] == 8992:
- ofp_vendors_v10.parse_nicira(packet, h_size+4, of_xid)
- print
- return 1
-
-
-# *********** FeatureReq ***************
-def parse_FeatureReq(packet, h_size, of_xid):
- ofp_prints_v10.print_of_feature_req(of_xid)
- return 1
-
-
-# *********** FeatureRes ***************
-def _parse_bitmask(bitmask, array):
- size = len(array)
- for i in range(0, size):
- mask = 2**i
- aux = bitmask & mask
- if aux == 0:
- array.remove(mask)
- return array
-
-
-def _parse_capabilities(capabilities):
- caps = [1, 2, 4, 8, 16, 32, 64, 128]
- return _parse_bitmask(capabilities, caps)
-
-
-def _parse_actions(actions):
- acts = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048]
- return _parse_bitmask(actions, acts)
-
-
-def _parse_phy_config(config):
- confs = [1, 2, 4, 8, 16, 32, 64]
- return _parse_bitmask(config, confs)
-
-
-def _parse_phy_state(state):
- states = [1, 2, 4, 8, 16]
- return _parse_bitmask(state, states)
-
-
-def _parse_phy_curr(values):
- confs = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048]
- return _parse_bitmask(values, confs)
-
-
-def _parse_phy_ports(packet, of_xid):
- phy = unpack('!H6s16sLLLLLL', packet)
-
- port_id = ofp_dissector_v10.get_phy_port_id(phy[0])
- hw_addr = ofp_prints_v10.eth_addr(phy[1])
- config = _parse_phy_config(phy[3])
- state = _parse_phy_state(phy[4])
- curr = _parse_phy_curr(phy[5])
- advertised = _parse_phy_curr(phy[6])
- supported = _parse_phy_curr(phy[7])
- peer = _parse_phy_curr(phy[8])
-
- phy_ports = {'port_id': port_id,
- 'hw_addr': hw_addr,
- 'name': phy[2],
- 'config': config,
- 'state': state,
- 'curr': curr,
- 'advertised': advertised,
- 'supported': supported,
- 'peer': peer}
- return phy_ports
-
-
-def parse_FeatureRes(packet, h_size, of_xid):
- of_fres = packet[h_size:h_size+24]
- ofrs = unpack('!8sLB3sLL', of_fres)
- f_res = {'datapath_id': ofrs[0], 'n_buffers': ofrs[1], 'n_tbls': ofrs[2],
- 'pad': ofrs[3]}
- ofp_prints_v10.print_of_feature_res(of_xid, f_res)
-
- # 'capabilities': ofrs[4], 'actions': ofrs[5]}
- caps = []
- caps = _parse_capabilities(ofrs[4])
- actions = []
- actions = _parse_actions(ofrs[5])
- ofp_prints_v10.print_of_feature_res_caps_and_actions(of_xid, caps, actions)
-
- # Ports description?
- start = h_size + 24
- while len(packet[start:]) > 0:
- ports = _parse_phy_ports(packet[start:start+48], of_xid)
- ofp_prints_v10.print_of_feature_res_ports(of_xid, ports)
- start = start + 48
-
- return 1
-
-
-# ***************** GetConfigReq *********************
-def parse_GetConfigReq(packet, h_size, of_xid):
- ofp_prints_v10.print_of_getconfig_req(of_xid)
- return 1
-
-
-# ***************** GetConfigRes ********************
-def _parse_SetGetConfig(packet, h_size):
- pkt_raw = packet[h_size:h_size+4]
- pkt_list = unpack('!HH', pkt_raw)
- flag = ofp_dissector_v10.get_configres_flags(pkt_list[0])
- miss_send_len = pkt_list[1]
- return flag, miss_send_len
-
-
-def parse_GetConfigRes(packet, h_size, of_xid):
- flag, miss_send_len = _parse_SetGetConfig(packet, h_size)
- ofp_prints_v10.print_ofp_getConfigRes(of_xid, flag, miss_send_len)
- return 1
-
-
-# ******************* SetConfig **********************
-def parse_SetConfig(packet, h_size, of_xid):
- flag, miss_send_len = _parse_SetGetConfig(packet, h_size)
- ofp_prints_v10.print_ofp_setConfig(of_xid, flag, miss_send_len)
- return 1
-
-
-# ****************** PacketIn ************************
-def _parse_ethernet_lldp_PacketInOut(packet, start):
- # Ethernet
- eth = ofp_tcpip_parser.get_ethernet_frame(packet[start:start+14], 1)
- start = start + 14
- etype = '0x0000'
- vlan = {}
- # VLAN or not
- if eth['protocol'] in [33024]:
- vlan = ofp_tcpip_parser.get_ethernet_vlan(packet[start:start+2])
- start = start + 2
- # If VLAN exists, there is a next eth['protocol']
- etype = ofp_tcpip_parser.get_next_etype(packet[start:start+2])
- start = start + 2
- else:
- etype = eth['protocol']
- # LLDP
- lldp = {}
- if etype in [35020, 35138]:
- lldp = ofp_tcpip_parser.get_lldp(packet[start:])
- return eth, vlan, lldp, start
- eth['protocol'] = etype
- return eth, vlan, {}, start
-
-
-def _parse_other_types(packet, start, eth):
- # OESS FVD
- if eth['protocol'] in [34998]:
- print 'OESS FVD'
- elif eth['protocol'] in [35020]:
- # If it gets here, means that the LLDP packet is MalFormed
- print 'LLDP Packet MalFormed'
- elif eth['protocol'] in [2048]:
- ip = ofp_tcpip_parser.get_ip_packet(packet, start)
- ofp_prints_v10.print_layer3(ip)
- if ip['protocol'] is 6:
- tcp = ofp_tcpip_parser.get_tcp_stream(packet, start + ip['length'])
- ofp_prints_v10.print_tcp(tcp)
- elif eth['protocol'] in [2054]:
- arp = ofp_tcpip_parser.get_arp(packet[start:])
- ofp_prints_v10.print_arp(arp)
- else:
- print 'Ethertype %s not dissected' % hex(eth['protocol'])
-
-
-def _print_packetIn(of_xid, packetIn, eth, vlan, lldp):
- ofp_prints_v10.print_ofp_packetIn(of_xid, packetIn)
- ofp_prints_v10.print_packetInOut_layer2(of_xid, eth)
- if len(vlan) != 0:
- ofp_prints_v10.print_packetInOut_vlan(of_xid, vlan)
- if len(lldp) != 0:
- ofp_prints_v10.print_packetInOut_lldp(of_xid, lldp)
-
-
-def parse_PacketIn(packet, h_size, of_xid, sanitizer):
- # buffer_id(32), total_len(16), in_port(16), reason(8), pad(8)
- pkt_raw = packet[h_size:h_size+10]
- p_in = unpack('!LHHBB', pkt_raw)
- reason = ofp_dissector_v10.get_packetIn_reason(p_in[3])
- packetIn = {'buffer_id': p_in[0], 'total_len': p_in[1], 'in_port': p_in[2],
- 'reason': reason, 'pad': p_in[4]}
-
- eth, vlan, lldp, offset = _parse_ethernet_lldp_PacketInOut(packet,
- h_size + 10)
- if len(lldp) == 0:
- _print_packetIn(of_xid, packetIn, eth, vlan, {})
- _parse_other_types(packet[offset:], 0, eth)
- return 1
-
- # If we have filters (-F)
- filters = sanitizer['packetIn_filter']
-
- if len(filters) > 0:
- if filters['switch_dpid'] == "any":
- _print_packetIn(of_xid, packetIn, eth, vlan, lldp)
- elif filters['switch_dpid'] == lldp['c_id']:
- if (filters['in_port'] == "any" or
- filters['in_port'] == lldp['in_port']):
- _print_packetIn(of_xid, packetIn, eth, vlan, lldp)
- else:
- _print_packetIn(of_xid, packetIn, eth, vlan, lldp)
-
- return 1
-
-
-# ******************** FlowRemoved ***************************
-def parse_FlowRemoved(packet, h_size, of_xid):
- ofmatch = _parse_OFMatch(packet, h_size)
- ofp_prints_v10.print_ofp_match(of_xid, ofmatch)
-
- of_rem_body = packet[h_size+40:h_size+40+40]
- ofrem = unpack('!8sHBBLLHBBQQ', of_rem_body)
- cookie = ofrem[0] if not len(ofrem[0]) else 0
- cookie = '0x' + format(cookie, '02x')
- reason = ofp_dissector_v10.get_flow_removed_reason(ofrem[2])
-
- ofrem = {'cookie': cookie, 'priority': ofrem[1], 'reason': reason,
- 'pad': ofrem[3], 'duration_sec': ofrem[4],
- 'duration_nsec': ofrem[5], 'idle_timeout': ofrem[6],
- 'pad2': ofrem[7], 'pad3': ofrem[8],
- 'packet_count': ofrem[9], 'byte_count': ofrem[10]}
-
- ofp_prints_v10.print_ofp_flow_removed(of_xid, ofrem)
- return 1
-
-
-# ******************* PortStatus *****************************
-def parse_PortStatus(packet, h_size, of_xid):
- port_raw = packet[h_size:h_size+8]
- port = unpack('!B7s', port_raw)
- reason = ofp_dissector_v10.get_portStatus_reason(port[0])
- pad = port[1]
- ofp_prints_v10.print_portStatus(of_xid, reason, pad)
- ports = _parse_phy_ports(packet[h_size+8:h_size+64], of_xid)
- ofp_prints_v10.print_of_feature_res_ports(of_xid, ports)
- return 1
-
-
-# ******************* PacketOut *****************************
-# Actions need to be handled
-def parse_PacketOut(packet, h_size, of_xid, sanitizer, print_options):
- # buffer_id(32), in_port(16), actions_len(16)
- pkt_raw = packet[h_size:h_size+8]
- p_out = unpack('!LHH', pkt_raw)
- actions_len = p_out[2]
- packetOut = {'buffer_id': p_out[0], 'in_port': p_out[1],
- 'actions_len': actions_len}
-
- ofp_prints_v10.print_ofp_packetOut(of_xid, packetOut)
- # Actions
- start = h_size + 8
- _parse_OFAction(of_xid, packet[start:start+packetOut['actions_len']], 0)
- # Ethernet
- start = h_size + 8 + packetOut['actions_len']
- eth = ofp_tcpip_parser.get_ethernet_frame(packet[start:start+14], 1)
- ofp_prints_v10.print_packetInOut_layer2(of_xid, eth)
- start = start + 14
- etype = '0x0000'
- # VLAN or not
- if eth['protocol'] in [33024]:
- vlan = ofp_tcpip_parser.get_ethernet_vlan(packet[start:start+2])
- ofp_prints_v10.print_packetInOut_vlan(of_xid, vlan)
- start = start + 2
- # If VLAN exists, there is a next eth['protocol']
- etype = ofp_tcpip_parser.get_next_etype(packet[start:start+2])
- start = start + 2
- else:
- etype = eth['protocol']
- if etype in [35020, 35138]:
- # LLDP TLV
- lldp = ofp_tcpip_parser.get_lldp(packet[start:])
- if len(lldp) is 0:
- print 'LLDP Packet MalFormed'
- else:
- # Support for FSFW/Proxy
- ofp_fsfw_v10.support_fsfw(print_options, lldp)
- ofp_prints_v10.print_packetInOut_lldp(of_xid, lldp)
-
- return 1
-
-
-# ********************* FlowMod ***************************
-def process_dst_subnet(wcard):
- OFPFW_NW_DST_SHIFT = 14
- OFPFW_NW_DST_MASK = 1032192
- nw_dst_bits = (wcard & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT
- return ((32 - nw_dst_bits) if nw_dst_bits < 32 else 0)
-
-
-def process_src_subnet(wcard):
- OFPFW_NW_SRC_SHIFT = 8
- OFPFW_NW_SRC_MASK = 16128
- nw_src_bits = (wcard & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT
- return ((32 - nw_src_bits) if nw_src_bits < 32 else 0)
-
-
-def _process_wildcard(wcard):
- wildcard = {1: 'in_port',
- 2: 'dl_vlan',
- 4: 'dl_src',
- 8: 'dl_dst',
- 16: 'dl_type',
- 32: 'nw_prot',
- 64: 'tp_src',
- 128: 'tp_dst',
- 1048576: 'dl_vlan_pcp',
- 2097152: 'nw_tos'}
-
- return wildcard.get(wcard)
-
-
-def get_ip_from_long(long_ip):
- return (socket.inet_ntoa(struct.pack('!L', long_ip)))
-
-
-def _parse_OFMatch(packet, h_size):
- of_match = packet[h_size:h_size+40]
- ofm = unpack('!LH6s6sHBBHBBHLLHH', of_match)
- wildcard = ofm[0]
- dl_src = ofp_prints_v10.eth_addr(ofm[2])
- dl_dst = ofp_prints_v10.eth_addr(ofm[3])
- nw_src = get_ip_from_long(ofm[11])
- nw_dst = get_ip_from_long(ofm[12])
- etype = hex(ofm[7])
-
- ofmatch = {'wildcards': ofm[0], 'in_port': ofm[1], 'dl_src': dl_src,
- 'dl_dst': dl_dst, 'dl_vlan': ofm[4], 'dl_vlan_pcp': ofm[5],
- 'dl_type': etype, 'nw_tos': ofm[8], 'nw_prot': ofm[9],
- 'nw_src': nw_src, 'nw_dst': nw_dst, 'tp_src': ofm[13],
- 'tp_dst': ofm[14]}
-
- if wildcard >= ((1 << 22) - 1):
- ofmatch = {'wildcards': '4194303'}
- return ofmatch
- elif wildcard == 0:
- ofmatch = {'wildcards': '0'}
- return ofmatch
- else:
- src_netmask = process_src_subnet(wildcard)
- if src_netmask == 0:
- ofmatch.pop('nw_src')
- else:
- ofmatch['nw_src'] = str(ofmatch['nw_src']) + '/' + str(src_netmask)
- dst_netmask = process_dst_subnet(wildcard)
- if dst_netmask == 0:
- ofmatch.pop('nw_dst')
- else:
- ofmatch['nw_dst'] = str(ofmatch['nw_dst']) + '/' + str(dst_netmask)
- for i in range(0, 8):
- mask = 2**i
- aux = wildcard & mask
- if aux != 0:
- ofmatch.pop(_process_wildcard(mask))
-
- for i in range(20, 22):
- mask = 2**i
- aux = wildcard & mask
- if aux != 0:
- ofmatch.pop(_process_wildcard(mask))
-
- return ofmatch
-
-
-def _parse_OFBody(packet, h_size):
- of_mod_body = packet[h_size+40:h_size+40+24]
- ofmod = unpack('!8sHHHHLHH', of_mod_body)
- ofmod_cookie = ofmod[0] if not len(ofmod[0]) else 0
- ofmod_cookie = '0x' + format(ofmod_cookie, '02x')
- ofmod_buffer_id = '0x' + format(ofmod[5], '02x')
-
- ofbody = {'cookie': ofmod_cookie, 'command': ofmod[1],
- 'idle_timeout': ofmod[2], 'hard_timeout': ofmod[3],
- 'priority': ofmod[4], 'buffer_id': ofmod[5],
- 'buffer_id': ofmod_buffer_id, 'out_port': ofmod[6],
- 'flags': ofmod[7]}
- return ofbody
-
-
-def get_action(action_type, length, payload):
- # 0 - OUTPUT. Returns port and max_length
- if action_type == 0:
- type_0 = unpack('!HH', payload)
- return type_0[0], type_0[1]
- # 1 - SetVLANID. Returns VID and pad
- elif action_type == 1:
- type_1 = unpack('!HH', payload)
- return type_1[0], type_1[1]
- # 2 - SetVLANPCP
- elif action_type == 2:
- type_2 = unpack('!B3s', payload)
- return type_2[0], type_2[1]
- # 3 - StripVLAN
- elif action_type == 3:
- pass
- # 4 - SetDLSrc
- elif action_type == 4:
- type_4 = unpack('!6s6s', payload)
- return type_4[0], type_4[1]
- # 5 - SetDLDst
- elif action_type == 5:
- type_5 = unpack('!6s6s', payload)
- return type_5[0], type_5[1]
- # 6 - SetNWSrc
- elif action_type == 6:
- type_6 = unpack('!L', payload)
- return get_ip_from_long(type_6[0])
- # 7 - SetNWDst
- elif action_type == 7:
- type_7 = unpack('!L', payload)
- return get_ip_from_long(type_7[0])
- # 8 - SetNWTos
- elif action_type == 8:
- type_8 = unpack('!B3s', payload)
- return type_8[0], type_8[1]
- # 9 - SetTPSrc
- elif action_type == 9:
- type_9 = unpack('!HH', payload)
- return type_9[0], type_9[1]
- # a - SetTPDst
- elif action_type == int('a', 16):
- type_a = unpack('!HH', payload)
- return type_a[0], type_a[1]
- # b - Enqueue
- elif action_type == int('b', 16):
- type_b = unpack('!H6sL', payload)
- return type_b[0], type_b[1], type_b[2]
- # ffff - Vendor
- elif action_type == int('ffff', 16):
- type_f = unpack('!L', payload)
- return type_f[0]
-
-
-def _parse_OFAction(of_xid, packet, start, ofactions=[]):
- '''
- Actions
- '''
- # Actions: Header = 4 , plus each possible action
- # Payload varies:
- # 4 for types 0,1,2,6,7,8,9,a,ffff
- # 0 for type 3
- # 12 for types 4,5,b
- action_header = 4
- while (1):
- ofp_action = packet[start:start + action_header]
- if len(ofp_action) > 0:
- # Get type and length
- ofa = unpack('!HH', ofp_action)
- ofa_type = ofa[0]
- ofa_length = ofa[1]
-
- start = start + action_header
- if ofa_type == 4 or ofa_type == 5 or ofa_type == int('b', 16):
- total_length = 12
- ofa_action_payload = packet[start:start + 12]
- else:
- total_length = 4
- ofa_action_payload = packet[start:start + 4]
-
- ofa_temp = ofp_prints_v10.print_ofp_action(of_xid, ofa_type,
- ofa_length,
- ofa_action_payload)
-
- # Print OVS format
- ofactions.append(ofa_temp)
- ofactions.append(',')
- # Next packet would start at..
- start = start + total_length
- else:
- break
-
- return ofactions
-
-
-def parse_FlowMod(packet, h_size, of_xid, print_options):
-
- ofmatch = _parse_OFMatch(packet, h_size)
- ofp_prints_v10.print_ofp_match(of_xid, ofmatch)
-
- ofbody = _parse_OFBody(packet, h_size)
- ofp_prints_v10.print_ofp_body(of_xid, ofbody)
-
- if ofbody['command'] == 3:
- ovs_command = 'del-flows'
- else:
- ovs_command = 'add-flow'
-
- # Print OVS
- ofactions = []
- ofactions.append("action=")
-
- # Actions: Header = 4 , plus each possible action
- # Payload varies:
- # 4 for types 0,1,2,6,7,8,9,a,ffff
- # 0 for type 3
- # 12 for types 4,5,b
- start = h_size+64
-
- ofactions = _parse_OFAction(of_xid, packet, start, ofactions)
-
- if print_options['ovs'] == 1:
- ofp_prints_v10.print_ofp_ovs(print_options, ofmatch, ofactions,
- ovs_command, ofbody['priority'])
- return 1
-
-
-# ********************* PortMod ****************************
-def parse_PortMod(packet, h_size, of_xid):
- # port(16), hw_addr(48), config(32), mask(32), advertise(32), pad(32)
- pmod_raw = packet[h_size:h_size+24]
- pmod = unpack('!H6sLLLL', pmod_raw)
-
- config = _parse_phy_config(pmod[2])
- mask = _parse_phy_config(pmod[3])
- advertise = _parse_phy_curr(pmod[4])
- portMod = {'port': pmod[0], 'hw_addr': pmod[1], 'config': config,
- 'mask': mask, 'advertise': advertise, 'pad': pmod[5]}
-
- ofp_prints_v10.print_PortMod(of_xid, portMod)
- return 1
-
-
-# ******************** StatReq ****************************
-def parse_StatsReq(packet, h_size, of_xid):
- '''
- Process the StatsReq
- '''
- # Get type = 16bits
- # Get flags = 16bits
- of_stat_req = packet[h_size:h_size+4]
- ofstat = unpack('!HH', of_stat_req)
- stat_type = ofstat[0]
- # FLags were not defined yet. Ignoring.
- # flags = ofstat[1]
- start = h_size+4
-
- # 7 Types available
- if stat_type == 0:
- # Description
- # No extra fields
- ofp_prints_v10.print_ofp_statReqDesc(of_xid, stat_type)
-
- elif stat_type == 1 or stat_type == 2:
- # Flow(1) or Aggregate(2)
- # Fields: match(40), table_id(8), pad(8), out_port(16)
- of_match = _parse_OFMatch(packet, start)
- # 44 Bytes (40B from Match, 4 from header)
- of_stat_req = packet[start+40:start+40+4]
- ofstat = unpack('!BBH', of_stat_req)
- table_id = ofstat[0]
- pad = ofstat[1]
- out_port = ofstat[2]
- ofp_prints_v10.print_ofp_statReqFlowAggregate(of_xid, stat_type,
- of_match, table_id, pad,
- out_port)
- elif stat_type == 3:
- # Table
- # No extra fields
- ofp_prints_v10.print_ofp_statReqTable(of_xid, stat_type)
-
- elif stat_type == 4:
- # Port
- # Fields: port_number(16), pad(48)
- of_stat_req = packet[start:start+8]
- ofstat = unpack('!H6s', of_stat_req)
- port_number = ofstat[0]
- pad = ofstat[1]
- ofp_prints_v10.print_ofp_statReqPort(of_xid, stat_type, port_number,
- pad)
-
- elif stat_type == 5:
- # Queue
- # Fields: port_number(16), pad(16), queue_id(32)
- of_stat_req = packet[start:start+8]
- ofstat = unpack('!HHL', of_stat_req)
- port_number = ofstat[0]
- pad = ofstat[1]
- queue_id = ofstat[2]
- ofp_prints_v10.print_ofp_statReqQueue(of_xid, stat_type, port_number,
- pad, queue_id)
- elif stat_type == 65535:
- # Vendor
- # Fields: vendor_id(32) + data
- of_stat_req = packet[start:start+4]
- ofstat = unpack('!L', of_stat_req)
- vendor_id = ofstat[0]
- ofp_prints_v10.print_ofp_statReqVendor(of_xid, stat_type, vendor_id)
-
- else:
- print ('%s StatReq: Unknown Type: %s' % (of_xid, stat_type))
- return 0
- return 1
-
-
-# *********************** StatsRes ****************************
-# Actions need to be handled
-def parse_StatsRes(packet, h_size, of_xid):
- # Get type = 16bits
- # Get flags = 16bits
- of_stat_req = packet[h_size:h_size+4]
- ofstat = unpack('!HH', of_stat_req)
- stat_type = ofstat[0]
- # flags = ofstat[1]
- start = h_size+4
-
- # 7 Types available
- if stat_type == 0:
- # Description
- # Fields: mfr_desc(2048), hw_desc(2048), sw_desc(2048), serial_num(256),
- # dp_desc(2048)
- desc_raw = packet[start:start+1056]
- desc = unpack('!256s256s256s32s256s', desc_raw)
- mfr_desc = desc[0]
- hw_desc = desc[1]
- sw_desc = desc[2]
- serial_num = desc[3]
- dp_desc = desc[4]
- ofp_prints_v10.print_ofp_statResDesc(of_xid, stat_type, mfr_desc,
- hw_desc, sw_desc, serial_num,
- dp_desc)
-
- elif stat_type == 1:
- # Flow(1)
- # Fields: length(16), table_id(8), pad(8), match(40), duration_sec(32),
- # duration_nsec(32), priority(16), idle_timeout(16), hard_timeout(16),
- # pad(48), cookie(64), packet_count(64), byte_count(64), actions[]
- count = len(packet[h_size:]) - 4
- while (count > 0):
- flow_raw = packet[start:start+4]
- flow = unpack('!HBB', flow_raw)
- res_flow = {'length': flow[0], 'table_id': flow[1], 'pad': flow[2]}
- of_match = _parse_OFMatch(packet, start+4)
- flow_raw = packet[start+44:start+44+44]
- flow = unpack('!LLHHH6sQQQ', flow_raw)
- res_flow.update({'duration_sec': flow[0], 'duration_nsec': flow[1],
- 'priority': flow[2], 'idle_timeout': flow[3],
- 'hard_timeout': flow[4], 'pad2': flow[5],
- 'cookie': flow[6], 'packet_count': flow[7],
- 'byte_count': flow[8]})
-
- ofp_prints_v10.print_ofp_statResFlow(of_xid, stat_type, of_match,
- res_flow)
- # Process Actions[]
- end = res_flow['length'] - (4 + 40 + 44)
- actions = packet[start+88:start+88+end]
- _parse_OFAction(of_xid, actions, 0)
-
- count = count - int(res_flow['length'])
- start = start + int(res_flow['length'])
-
- elif stat_type == 2:
- # Aggregate(2)
- # Fields: packet_count(64), byte_count(64), flow_count(32), pad(32)
- flow_raw = packet[start:start+24]
- flow = unpack('!QQLL', flow_raw)
- res_flow = {'packet_count': flow[0], 'byte_count': flow[1],
- 'flow_count': flow[2], 'pad': flow[3]}
- ofp_prints_v10.print_ofp_statResAggregate(of_xid, stat_type, res_flow)
-
- elif stat_type == 3:
- # Table
- # Fields: table_id(8), pad(24), name(256), wildcards(32),
- # max_entries(32), active_count(32), lookup_count(64),
- # matched_count(64)
- flow_raw = packet[start:start+64]
- flow = unpack('!B3s32sLLLQQ', flow_raw)
- res_flow = {'table_id': flow[0], 'pad': flow[1], 'name': flow[2],
- 'wildcards': flow[3], 'max_entries': flow[4],
- 'active_count': flow[5], 'lookup_count': flow[6],
- 'matched_count': flow[7]}
- ofp_prints_v10.print_ofp_statResTable(of_xid, stat_type, res_flow)
-
- elif stat_type == 4:
- # Port
- # Fields: port_number(16), pad(48), rx_packets(64), tx_packets(64),
- # rx_bytes(64), tx_bytes(64), rx_dropped(64), tx_dropped(64),
- # rx_errors(64), tx_errors(64), rx_frame_err(64), rx_over_err(64),
- # rx_crc_err(64), collisions(64)
- count = len(packet[h_size:]) - 4
- while (count > 0):
- flow_raw = packet[start:start+104]
- flow = unpack('!H6sQQQQQQQQQQQQ', flow_raw)
- res_flow = {'port_number': flow[0], 'pad': flow[1],
- 'rx_packets': flow[2], 'tx_packets': flow[3],
- 'rx_bytes': flow[4], 'tx_bytes': flow[5],
- 'rx_dropped': flow[6], 'tx_dropped': flow[7],
- 'rx_errors': flow[8], 'tx_errors': flow[9],
- 'rx_frame_err': flow[10], 'rx_over_err': flow[11],
- 'rx_crc_err': flow[12], 'collisions': flow[13]}
- ofp_prints_v10.print_ofp_statResPort(of_xid, stat_type, res_flow)
-
- count = count - 104
- start = start + 104
-
- elif stat_type == 5:
- # Queue
- # Fields: length(16), pad(16), queue_id(32), tx_bytes(64),
- # tx_packets(64), tx_errors(64)
- count = len(packet[h_size:]) - 4
- while (count > 0):
- flow_raw = packet[start:start+32]
- flow = unpack('!HHLQQQ', flow_raw)
- res_flow = {'length': flow[0], 'pad': flow[1], 'queue_id': flow[2],
- 'tx_bytes': flow[3], 'tx_packets': flow[4],
- 'tx_errors': flow[5]}
- ofp_prints_v10.print_ofp_statResQueue(of_xid, stat_type, res_flow)
- count = count - 32
- start = start + 32
- else:
- print ('%s StatRes Type: Queue(%s)' % (of_xid, stat_type))
- print ('%s No Queues' % (of_xid))
-
- elif stat_type == 65535:
- # Vendor
- # Fields: vendor_id(32), data(?)
- flow_raw = packet[start:start+4]
- flow = unpack('!L', flow_raw)
- res_flow = {'vendor_id': flow[0]}
- ofp_prints_v10.print_ofp_statResVendor(of_xid, stat_type, res_flow)
-
- start = start + 4
- data = []
- count = len(packet[h_size:])
- while (start < count):
- flow_raw = packet[start:start+1]
- flow = unpack('!B', flow_raw)
- data.append(str(flow[0]))
- start = start + 1
- ofp_prints_v10.print_ofp_statResVendorData(of_xid, ''.join(data))
-
- else:
- print ('%s StatRes: Unknown Type: %s' % (of_xid, stat_type))
- return 0
- return 1
-
-
-# ********************** BarrierReq ***********************
-def parse_BarrierReq(packet, h_size, of_xid):
- ofp_prints_v10.print_of_BarrierReq(of_xid)
- return 1
-
-
-# ********************** BarrierRes ***********************
-def parse_BarrierRes(packet, h_size, of_xid):
- ofp_prints_v10.print_of_BarrierReply(of_xid)
- return 1
-
-
-# ******************* QueueGetConfigReq *******************
-def parse_QueueGetConfigReq(packet, h_size, of_xid):
- queue_raw = packet[h_size:h_size+4]
- queue = unpack('!HH', queue_raw)
- queueConfReq = {'port': queue[0], 'pad': queue[1]}
- ofp_prints_v10.print_queueReq(of_xid, queueConfReq)
- return 1
-
-
-# ****************** QueueGetConfigRes ********************
-def parse_QueueGetConfigRes(packet, h_size, of_xid):
- queue_raw = packet[h_size:h_size+8]
- queue = unpack('!H6s', queue_raw)
- queueConfRes = {'port': queue[0], 'pad': queue[1]}
-
- ofp_prints_v10.print_queueRes(of_xid, queueConfRes)
-
- start = h_size + 8
- while (packet[start:] > 0):
- # Queues - it could be multiple
- # queue_id(32), length(16), pad(16)
- queue_raw = packet[start:start+8]
- queue = unpack('!LHH', queue_raw)
- queues = {'queue_id': queue[0], 'length': queue[1], 'pad': queue[2]}
- ofp_prints_v10.print_queues(of_xid, queues)
-
- q_start = start + 8
-
- # Look of properties
- # property(16), length(16), pad(32), rate(16), pad(48)
- properties = packet[q_start:q_start+queues['length']-8]
-
- while (len(properties[q_start:]) > 0):
- prop_raw = packet[q_start:q_start+8]
- prop = unpack('!HHLH6s', prop_raw)
- properties = {'type': prop[0], 'length': prop[1],
- 'pad': prop[2], 'rate': prop[3], 'pad2': prop[4]}
- ofp_prints_v10.print_queueRes_properties(of_xid, properties)
-
- start = start + queues['length']
-
- return 1
diff --git a/ofp_prints_v10.py b/ofp_prints_v10.py
deleted file mode 100644
index 3d58094..0000000
--- a/ofp_prints_v10.py
+++ /dev/null
@@ -1,590 +0,0 @@
-from termcolor import colored
-import ofp_dissector_v10
-from ofp_parser_v10 import get_action, get_ip_from_long
-import ofp_cli # NO_COLOR variable
-import ofp_fsfw_v10
-
-
-def red(string):
- if ofp_cli.NO_COLOR is True:
- return string
- return colored(string, 'red')
-
-
-def green(string):
- if ofp_cli.NO_COLOR is True:
- return string
- return colored(string, 'green')
-
-
-def blue(string):
- if ofp_cli.NO_COLOR is True:
- return string
- return colored(string, 'blue')
-
-
-def yellow(string):
- if ofp_cli.NO_COLOR is True:
- return string
- return colored(string, 'yellow')
-
-
-def cyan(string):
- if ofp_cli.NO_COLOR is True:
- return string
- return colored(string, 'cyan')
-
-
-def eth_addr(a):
- mac = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" % (ord(a[0]), ord(a[1]), ord(a[2]),
- ord(a[3]), ord(a[4]), ord(a[5]))
- return mac
-
-
-def datapath_id(a):
- dpid = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" % (ord(a[0]), ord(a[1]),
- ord(a[2]), ord(a[3]),
- ord(a[4]), ord(a[5]),
- ord(a[6]), ord(a[7]))
- return dpid
-
-
-def print_headers(print_options, date, getlen, caplen, eth, ip, tcp):
- if print_options['min'] == 1:
- print_minimal(date, getlen, ip, tcp)
- else:
- print_layer1(date, getlen, caplen)
- print_layer2(eth)
- print_layer3(ip)
- print_tcp(tcp)
-
-
-def print_minimal(date, getlen, ip, tcp):
- string = '%s %s:%s -> %s:%s Size: %s Bytes'
-
- source = ofp_fsfw_v10.get_ip_name(ip['s_addr'], tcp['source_port'])
- dest = ofp_fsfw_v10.get_ip_name(ip['d_addr'], tcp['dest_port'])
-
- print string % (date, cyan(source), cyan(tcp['source_port']),
- cyan(dest), cyan(tcp['dest_port']), getlen)
-
-
-def print_layer1(date, getlen, caplen):
- print ('%s: captured %d bytes, truncated to %d bytes' %
- (date, getlen, caplen))
-
-
-def print_layer2(eth):
- print ('Ethernet: Destination MAC: %s Source MAC: %s Protocol: %s' %
- (eth_addr(eth['dst_mac']), eth_addr(eth['src_mac']),
- red(hex(eth['protocol']))))
-
-
-def print_vlan(vlan):
- print ('Prio: %s CFI: %s VID: %s' %
- (vlan['prio'], vlan['cfi'], red(vlan['vid'])))
-
-
-def print_arp(arp):
- print ('ARP: Hardware Type: %s Protocol Type: %s '
- 'HW Length: %s Prot Length: %s Opcode: %s '
- '\nARP: Source MAC: %s Source IP: %s Destination MAC: %s '
- 'Destination IP: %s'
- % (arp['hw_type'], arp['prot_type'], arp['hw_len'], arp['prot_len'],
- arp['opcode'],
- eth_addr(arp['src_mac']), get_ip_from_long(arp['src_ip']),
- eth_addr(arp['dst_mac']), get_ip_from_long(arp['dst_ip'])))
-
-
-def print_layer3(ip):
- print (('IP Version: %d IP Header Length: %d TTL: %d Protocol: %d '
- 'Source Address: %s Destination Address: %s') %
- (ip['version'], (ip['ihl'] * 4), ip['ttl'], ip['protocol'],
- blue(ip['s_addr']), blue(ip['d_addr'])))
-
-
-def print_tcp(tcp):
- print ('TCP Source Port: %s Dest Port: %s Sequence Number: %s '
- 'Acknowledgement: %s TCP header length: %s Flags: (CWR: %s '
- 'ECE: %s URG: %s ACK: %s PSH: %s RST: %s SYN: %s FYN: %s' %
- (tcp['source_port'], tcp['dest_port'], tcp['sequence'],
- tcp['acknowledgement'], (tcp['length']), tcp['flag_cwr'],
- tcp['flag_ece'], tcp['flag_urg'], tcp['flag_ack'], tcp['flag_psh'],
- tcp['flag_rst'], tcp['flag_syn'], tcp['flag_fyn']))
-
-
-def print_openflow_header(of):
- version = ofp_dissector_v10.get_ofp_version(of['version'])
- name_version = '%s(%s)' % (version, of['version'])
- if version == '1.0':
- name = ofp_dissector_v10.get_ofp_type(of['type'])
- name_type = '%s(%s)' % (name, of['type'])
- else:
- name_type = '%s' % (of['type'])
-
- print ('OpenFlow Version: %s Type: %s Length: %s XID: %s' %
- (name_version, yellow(name_type), of['length'], red(of['xid'])))
-
-
-def print_of_hello(of_xid):
- print '%s OpenFlow Hello' % of_xid
-
-
-def print_of_error(of_xid, nameCode, typeCode):
- print ('%s OpenFlow Error - Type: %s Code: %s' %
- (of_xid, red(nameCode), red(typeCode)))
-
-
-def print_of_feature_req(of_xid):
- print '%s OpenFlow Feature Request' % of_xid
-
-
-def print_of_getconfig_req(of_xid):
- print '%s OpenFlow GetConfig Request' % of_xid
-
-
-def print_of_feature_res(of_xid, f_res):
- print '%s OpenFlow Feature Reply' % of_xid
- dpid = datapath_id(f_res['datapath_id'])
- print ('%s FeatureRes - datapath_id: %s n_buffers: %s n_tbls: %s, pad: %s'
- % (of_xid, green(dpid), f_res['n_buffers'], f_res['n_tbls'],
- f_res['pad']))
-
-
-def print_of_feature_res_caps_and_actions(of_xid, caps, actions):
- print ('%s FeatureRes - Capabilities:' % of_xid),
- for i in caps:
- print ofp_dissector_v10.get_feature_res_capabilities(i),
- print
- print ('%s FeatureRes - Actions:' % of_xid),
- for i in actions:
- print ofp_dissector_v10.get_feature_res_actions(i),
- print
-
-
-def _dont_print_0(printed):
- if printed is False:
- print '0',
- return False
-
-
-def print_of_feature_res_ports(of_xid, ports):
- print ('%s FeatureRes - port_id: %s hw_addr: %s name: %s' % (of_xid,
- green(ports['port_id']), green(ports['hw_addr']),
- green(ports['name'])))
- print ('%s FeatureRes - config:' % of_xid),
- printed = False
- for i in ports['config']:
- print ofp_dissector_v10.get_phy_config(i),
- printed = True
- else:
- printed = _dont_print_0(printed)
- print
- print ('%s FeatureRes - state:' % of_xid),
- for i in ports['state']:
- print ofp_dissector_v10.get_phy_state(i),
- printed = True
- else:
- printed = _dont_print_0(printed)
- print
- print ('%s FeatureRes - curr:' % of_xid),
- for i in ports['curr']:
- print ofp_dissector_v10.get_phy_feature(i),
- printed = True
- else:
- printed = _dont_print_0(printed)
- print
- print ('%s FeatureRes - advertised:' % of_xid),
- for i in ports['advertised']:
- print ofp_dissector_v10.get_phy_feature(i),
- printed = True
- else:
- printed = _dont_print_0(printed)
- print
- print ('%s FeatureRes - supported:' % of_xid),
- for i in ports['supported']:
- print ofp_dissector_v10.get_phy_feature(i),
- printed = True
- else:
- printed = _dont_print_0(printed)
- print
- print ('%s FeatureRes - peer:' % of_xid),
- for i in ports['peer']:
- print ofp_dissector_v10.get_phy_feature(i),
- printed = True
- else:
- printed = _dont_print_0(printed)
- print
-
-
-def print_ofp_match(xid, ofmatch):
- if xid == '':
- print 'OpenFlow Match -',
- else:
- print ('%s OpenFlow Match -' % (xid)),
- for K in ofmatch:
- print ("%s: %s" % (K, green(ofmatch[K]))),
- print
-
-
-def print_ofp_body(xid, ofbody):
- string = ('%s OpenFlow Body - Cookie: %s Command: %s Idle/Hard Timeouts: '
- '%s/%s Priority: %s Buffer ID: %s Out Port: %s Flags: %s')
- command = green(ofp_dissector_v10.get_ofp_command(ofbody['command']))
- flags = green(ofp_dissector_v10.get_ofp_flags(ofbody['flags']))
-
- print string % (xid, ofbody['cookie'], command, ofbody['idle_timeout'],
- ofbody['hard_timeout'], ofbody['priority'],
- ofbody['buffer_id'], ofbody['out_port'], flags)
-
-
-def print_ofp_flow_removed(xid, ofrem):
- string = ('%s OpenFlow Body - Cookie: %s Priority: %s Reason: %s Pad: %s '
- 'Duration Secs/NSecs: %s/%s Idle Timeout: %s Pad2/Pad3: %s/%s'
- ' Packet Count: %s Byte Count: %s')
-
- print string % (xid, ofrem['cookie'], ofrem['priority'],
- red(ofrem['reason']), ofrem['pad'], ofrem['duration_sec'],
- ofrem['duration_nsec'], ofrem['idle_timeout'],
- ofrem['pad2'], ofrem['pad3'], ofrem['packet_count'],
- ofrem['byte_count'])
-
-
-def print_ofp_action(xid, action_type, length, payload):
- if action_type == 0:
- port, max_len = get_action(action_type, length, payload)
-
- port = ofp_dissector_v10.get_phy_port_id(port)
- print ('%s OpenFlow Action - Type: %s Length: %s Port: %s '
- 'Max Length: %s' %
- (xid, green('OUTPUT'), length, green(port), max_len))
- return 'output:' + port
-
- elif action_type == 1:
- vlan, pad = get_action(action_type, length, payload)
- print ('%s OpenFlow Action - Type: %s Length: %s VLAN ID: %s Pad: %s' %
- (xid, green('SetVLANID'), length, green(str(vlan)), pad))
- return 'mod_vlan_vid:' + str(vlan)
-
- elif action_type == 2:
- vlan_pc, pad = get_action(action_type, length, payload)
- print ('%s OpenFlow Action - Type: %s Length: %s VLAN PCP: %s Pad: %s' %
- (xid, green('SetVLANPCP'), length, green(str(vlan_pc)), pad))
- return 'mod_vlan_pcp:' + str(vlan_pc)
-
- elif action_type == 3:
- print ('%s OpenFlow Action - Type: %s Length: %s' %
- (xid, green('StripVLAN'), length))
- return 'strip_vlan'
-
- elif action_type == 4:
- setDLSrc, pad = get_action(action_type, length, payload)
- print ('%s OpenFlow Action - Type: %s Length: %s SetDLSrc: %s Pad: %s' %
- (xid, green('SetDLSrc'), length, green(str(eth_addr(setDLSrc))),
- pad))
- return 'mod_dl_src:' + str(eth_addr(setDLSrc))
-
- elif action_type == 5:
- setDLDst, pad = get_action(action_type, length, payload)
- print ('%s OpenFlow Action - Type: %s Length: %s SetDLDst: %s Pad: %s' %
- (xid, green('SetDLDst'), length, green(str(eth_addr(setDLDst))),
- pad))
- return 'mod_dl_dst:' + str(eth_addr(setDLDst))
-
- elif action_type == 6:
- nw_addr = get_action(action_type, length, payload)
- print ('%s OpenFlow Action - Type: %s Length: %s SetNWSrc: %s' %
- (xid, green('SetNWSrc'), length, green(str(nw_addr))))
- return 'mod_nw_src:' + str(nw_addr)
-
- elif action_type == 7:
- nw_addr = get_action(action_type, length, payload)
- print ('%s OpenFlow Action - Type: %s Length: %s SetNWDst: %s' %
- (xid, green('SetNWDst'), length, green(str(nw_addr))))
- return 'mod_nw_src:' + str(nw_addr)
-
- elif action_type == 8:
- nw_tos, pad = get_action(action_type, length, payload)
- print ('%s OpenFlow Action - Type: %s Length: %s SetNWTos: %s Pad: %s' %
- (xid, green('SetNWTos'), length, green(str(nw_tos)), pad))
- return 'mod_nw_tos:' + str(nw_tos)
-
- elif action_type == 9:
- port, pad = get_action(action_type, length, payload)
- print ('%s OpenFlow Action - Type: %s Length: %s SetTPSrc: %s Pad: %s' %
- (xid, green('SetTPSrc'), length, green(str(port)), pad))
- return 'mod_tp_src:' + str(port)
-
- elif action_type == int('a', 16):
- port, pad = get_action(action_type, length, payload)
- print ('%s OpenFlow Action - Type: %s Length: %s SetTPDst: %s Pad: %s' %
- (xid, green('SetTPDst'), length, green(str(port)), pad))
- return 'mod_tp_dst:' + str(port)
-
- elif action_type == int('b', 16):
- port, pad, queue_id = get_action(action_type, length, payload)
- print (('%s OpenFlow Action - Type: %s Length: %s Enqueue: %s Pad: %s'
- ' Queue: %s') %
- (xid, green('Enqueue'), length, green(str(port)), pad,
- green(str(queue_id))))
- return 'set_queue:' + str(queue_id)
-
- elif action_type == int('ffff', 16):
- vendor = get_action(action_type, length, payload)
- print ('%s OpenFlow Action - Type: %s Length: %s Vendor: %s' %
- (xid, green('VENDOR'), length, green(str(vendor))))
- return 'VendorType'
-
- else:
- return 'Error'
-
-
-def print_ofp_ovs(print_options, ofmatch, ofactions, ovs_command, prio):
-
- '''
- If -o or --print-ovs is provided by user, print a ovs-ofctl add-dump
- '''
- switch_ip = print_options['device_ip']
- switch_port = print_options['device_port']
-
- ofm = []
-
- for K in ofmatch:
- if K != 'wildcards':
- value = "%s=%s," % (K, ofmatch[K])
- ofm.append(value)
-
- matches = ''.join(ofm)
- actions = ''.join(ofactions)
-
- print ('ovs-ofctl %s tcp:%s:%s "priority=%s %s %s"' %
- (ovs_command, switch_ip, switch_port, prio, matches,
- (actions if ovs_command != 'del-flows' else '')))
- return
-
-
-def _print_portMod_config_mask(of_xid, array, name):
- print ('%s PortMod %s:' % (of_xid, name)),
- printed = False
- for i in array[name]:
- print ofp_dissector_v10.get_phy_config(i),
- printed = True
- else:
- printed = _dont_print_0(printed)
- print
-
-
-def print_PortMod(of_xid, portMod):
- print ('%s PortMod Port: %s HW Addr %s Pad: %s' %
- (of_xid, portMod['port'], eth_addr(portMod['hw_addr']),
- portMod['pad']))
- _print_portMod_config_mask(of_xid, portMod, 'config')
- _print_portMod_config_mask(of_xid, portMod, 'mask')
- _print_portMod_config_mask(of_xid, portMod, 'advertise')
-
-
-def print_of_BarrierReq(of_xid):
- print '%s OpenFlow Barrier Request' % of_xid
-
-
-def print_of_BarrierReply(of_xid):
- print '%s OpenFlow Barrier Reply' % of_xid
-
-
-def print_of_vendor(of_vendor, of_xid):
- vendor = ofp_dissector_v10.get_ofp_vendor(of_vendor)
- print ('%s OpenFlow Vendor: %s' % (of_xid, vendor))
-
-
-def print_ofp_statReqDesc(of_xid, stat_type):
- print ('%s StatReq Type: Description(%s)' % (of_xid, stat_type))
-
-
-def print_ofp_statReqFlowAggregate(of_xid, stat_type, of_match, table_id, pad,
- out_port):
- if stat_type == 1:
- type_name = 'Flow'
- else:
- type_name = 'Aggregate'
-
- print ('%s StatReq Type: %s(%s)' % (of_xid, type_name, stat_type))
- print_ofp_match(of_xid, of_match)
- print ('%s StatReq Table_id: %s Pad: %d Out_Port: %s' % (of_xid, table_id,
- pad, out_port))
-
-
-def print_ofp_statReqTable(of_xid, stat_type):
- print ('%s StatReq Type: Table(%s)' % (of_xid, stat_type))
-
-
-def print_ofp_statReqPort(of_xid, stat_type, port_number, pad):
- print ('%s StatReq Type: Port(%s): Port_Number: %s Pad: %s' % (of_xid,
- stat_type, green(port_number), pad))
-
-
-def print_ofp_statReqQueue(of_xid, stat_type, port_number, pad, queue_id):
- print ('%s StatReq Type: Queue(%s): Port_Number: %s Pad: %s Queue_id: %s' %
- (of_xid, stat_type, green(port_number), pad, queue_id))
-
-
-def print_ofp_statReqVendor(of_xid, stat_type, vendor_id):
- print ('%s StatReq Type: Vendor(%s): Vendor_ID: %s' % (of_xid, stat_type,
- vendor_id))
-
-
-def print_ofp_statResDesc(of_xid, stat_type, mfr_desc, hw_desc, sw_desc,
- serial_num, dp_desc):
- print ('%s StatRes Type: Description(%s)' % (of_xid, stat_type))
- print ('%s StatRes mfr_desc: %s' % (of_xid, mfr_desc))
- print ('%s StatRes hw_desc: %s' % (of_xid, hw_desc))
- print ('%s StatRes sw_desc: %s' % (of_xid, sw_desc))
- print ('%s StatRes serial_num: %s' % (of_xid, serial_num))
- print ('%s StatRes dp_desc: %s' % (of_xid, dp_desc))
-
-
-def print_ofp_statResFlow(of_xid, stat_type, match, res_flow):
- print ('%s StatRes Type: Flow(%s)' % (of_xid, stat_type))
- print ('%s StatRes Length: %s Table_id: %s Pad: %s ' %
- (of_xid, res_flow['length'], res_flow['table_id'], res_flow['pad']))
- print ('%s StatRes' % of_xid),
- print_ofp_match('', match)
- print ('%s StatRes duration_sec: %s, duration_nsec: %s, priority: %s,'
- ' idle_timeout: %s, hard_timeout: %s, pad: %s, cookie: %s,'
- ' packet_count: %s, byte_count: %s' %
- (of_xid, res_flow['duration_sec'], res_flow['duration_nsec'],
- res_flow['priority'], res_flow['idle_timeout'],
- res_flow['hard_timeout'], res_flow['pad'],
- res_flow['cookie'],
- res_flow['packet_count'], res_flow['byte_count']))
-
-
-def print_ofp_statResAggregate(of_xid, stat_type, res_flow):
- print ('%s StatRes Type: Aggregate(%s)' % (of_xid, stat_type))
- print ('%s StatRes packet_count: %s, byte_count: %s flow_count: %s '
- 'pad: %s' %
- (of_xid, res_flow['packet_count'], res_flow['byte_count'],
- res_flow['flow_count'], res_flow['pad']))
-
-
-def print_ofp_statResTable(of_xid, stat_type, res_flow):
- print ('%s StatRes Type: Table(%s)' % (of_xid, stat_type))
- print ('%s StatRes table_id: %s, pad: %s, name: "%s", wildcards: %s, '
- 'max_entries: %s, active_count: %s, lookup_count: %s, '
- 'matched_count: %s' %
- (of_xid, res_flow['table_id'], res_flow['pad'],
- res_flow['name'], hex(res_flow['wildcards']),
- res_flow['max_entries'], res_flow['active_count'],
- res_flow['lookup_count'], res_flow['matched_count']))
-
-
-def print_ofp_statResPort(of_xid, stat_type, res_flow):
- print ('%s StatRes Type: Port(%s)' % (of_xid, stat_type))
- print ('%s StatRes port_no: %s rx_packets: %s rx_bytes: %s rx_errors: %s'
- ' rx_crc_err: %s rx_dropped: %s rx_over_err: %s rx_frame_err: %s\n'
- '%s StatRes port_no: %s tx_packets: %s tx_bytes: %s tx_errors: %s'
- ' tx_dropped: %s collisions: %s pad: %s' %
- (of_xid, red(res_flow['port_number']), res_flow['rx_packets'],
- res_flow['rx_bytes'], res_flow['rx_errors'], res_flow['rx_crc_err'],
- res_flow['rx_dropped'], res_flow['rx_over_err'],
- res_flow['rx_frame_err'], of_xid, red(res_flow['port_number']),
- res_flow['tx_packets'], res_flow['tx_bytes'], res_flow['tx_errors'],
- res_flow['tx_dropped'], res_flow['collisions'], res_flow['pad']))
-
-
-def print_ofp_statResQueue(of_xid, stat_type, res_flow):
- print ('%s StatRes Type: Queue(%s)' % (of_xid, stat_type))
- print ('%s StatRes queue_id: %s length: %s pad: %s'
- ' tx_bytes: %s tx_packets: %s tx_errors: %s' %
- (of_xid, res_flow['queue_id'], res_flow['length'], res_flow['pad'],
- res_flow['tx_bytes'], res_flow['tx_packets'],
- res_flow['tx_errors']))
-
-
-def print_ofp_statResVendor(of_xid, stat_type, res_flow):
- print ('%s StatRes Type: Vendor(%s)' % (of_xid, stat_type))
- print ('%s StatRes vendor_id: %s' % (of_xid, res_flow['vendor_id']))
-
-
-def print_ofp_statResVendorData(of_xid, data):
- print '%s StatRes Vendor Data: %s' % (of_xid, data)
-
-
-def print_ofp_getConfigRes(of_xid, flag, miss):
- print ('%s OpenFlow GetConfigRes - Flag: %s Miss_send_len: %s' %
- (of_xid, flag, miss))
-
-
-def print_ofp_setConfig(of_xid, flag, miss):
- print ('%s OpenFlow SetConfig - Flag: %s Miss_send_len: %s' %
- (of_xid, flag, miss))
-
-
-def print_echoreq(of_xid):
- print ('%s OpenFlow Echo Request' % (of_xid))
-
-
-def print_echores(of_xid):
- print ('%s OpenFlow Echo Reply' % (of_xid))
-
-
-def print_portStatus(of_xid, reason, pad):
- print ('%s OpenFlow PortStatus - Reason: %s Pad: %s' %
- (of_xid, reason, pad))
-
-
-def print_packetInOut_layer2(of_xid, eth):
- print ('%s' % of_xid),
- print_layer2(eth)
-
-
-def print_packetInOut_vlan(of_xid, vlan):
- print ('%s Ethernet:' % of_xid),
- print_vlan(vlan)
-
-
-def print_ofp_packetIn(of_xid, packetIn):
- print ('%s PacketIn: buffer_id: %s total_len: %s in_port: %s reason: %s '
- 'pad: %s' %
- (of_xid, hex(packetIn['buffer_id']), packetIn['total_len'],
- green(packetIn['in_port']), green(packetIn['reason']),
- packetIn['pad']))
-
-
-def print_packetInOut_lldp(of_xid, lldp):
- print ('%s LLDP: Chassis Type(%s) Length: %s SubType: %s ID: %s\n'
- '%s LLDP: Port Type(%s) Length: %s SubType: %s ID: %s\n'
- '%s LLDP: TTL(%s) Length: %s Seconds: %s\n'
- '%s LLDP: END(%s) Length: %s' %
- (of_xid, lldp['c_type'], lldp['c_length'], lldp['c_subtype'],
- green(lldp['c_id']), of_xid, lldp['p_type'], lldp['p_length'],
- lldp['p_subtype'], green(lldp['p_id']), of_xid, lldp['t_type'],
- lldp['t_length'], lldp['t_ttl'], of_xid, lldp['e_type'],
- lldp['e_length']))
-
-
-def print_ofp_packetOut(of_xid, packetOut):
- print ('%s PacketOut: buffer_id: %s in_port: %s actions_len: %s' %
- (of_xid, hex(packetOut['buffer_id']),
- green(ofp_dissector_v10.get_phy_port_id(packetOut['in_port'])),
- packetOut['actions_len']))
-
-
-def print_queueReq(of_xid, queueConfReq):
- print ('%s QueueGetConfigReq Port: %s Pad: %s' %
- (of_xid, queueConfReq['port'], queueConfReq['pad']))
-
-
-def print_queueRes(of_xid, queueConfRes):
- print ('%s QueueGetConfigRes Port: %s Pad: %s' %
- (of_xid, queueConfRes['port'], queueConfRes['pad']))
-
-
-def print_queueRes_queues(of_xid, queues):
- print ('%s Queue_ID: %s Length: %s Pad: %s' %
- (of_xid, queues['queue_id'], queues['length'], queues['pad']))
-
-
-def print_queueRes_properties(of_xid, properties):
- print ('%s Property: %s Length: %s Pad: %s Rate: %s Pad: %s' %
- (of_xid, properties['type'], properties['length'], properties['pad'],
- properties['rate'], properties['pad2']))
diff --git a/ofp_sniffer.py b/ofp_sniffer.py
index 5d06b1b..ea08044 100755
--- a/ofp_sniffer.py
+++ b/ofp_sniffer.py
@@ -1,177 +1,171 @@
#!/usr/bin/env python
-'''
- This code acts as an OpenFlow troubleshoot toolkit: it acts as a sniffer,
- a topology validator and as an OpenFlow message checker, to make sure the
- ONF standards are being followed.
+"""
+ This code is the AmLight OpenFlow Sniffer
- Despite of ONF standards, this code also supports OpenVSwitch/NICIRA
- OpenFlow type.
+ Current version: 0.4
- More info on how to use it: www.sdn.amlight.net
-
- Current version: 0.2
-
- Author: Jeronimo Bezerra
-
-'''
-
-import datetime
-import pcapy
+ Author: AmLight Dev Team
+"""
+import time
import sys
-from ofp_prints_v10 import print_headers, print_openflow_header
-from ofp_parser_v10 import process_ofp_type
-from ofp_tcpip_parser import get_ethernet_frame, get_ip_packet, \
- get_tcp_stream, get_openflow_header
-import ofp_cli
-import ofp_dissector_v10
-import ofp_fsfw_v10
-
-
-def main(argv):
- '''
- This is the main function
- '''
- print_options, infilter, sanitizer, dev, capfile = ofp_cli.get_params(argv)
- try:
- if len(capfile) > 0:
- print "Using file %s " % capfile
- cap = pcapy.open_offline(capfile)
- else:
- print "Sniffing device %s" % dev
- cap = pcapy.open_live(dev, 65536, 1, 0)
-
- main_filter = " port 6633 "
- cap.setfilter(main_filter + infilter)
-
- # start sniffing packets
- while(1):
- (header, packet) = cap.next()
- parse_packet(packet, datetime.datetime.now(),
- header.getlen(), header.getcaplen(),
- print_options, sanitizer)
- except KeyboardInterrupt:
- print ofp_fsfw_v10.close()
- print 'Exiting...'
- sys.exit(0)
- except Exception as exception:
- print exception
- return
-
-
-def sanitizer_filters(of_header, date, getlen, caplen, header_size,
- eth, ip, tcp, sanitizer):
- '''
- If -F was provided, use filters specified
- '''
- if (of_header['version'] == -1):
- print ('h_size : %s - caplen: %s ' % (header_size, caplen))
- print_headers(1, date, getlen, caplen, eth, ip, tcp)
- print 'OpenFlow header not complete. Ignoring packet.'
- return 0
-
- # OF Versions supported through json file (-F)
- name_version = ofp_dissector_v10.get_ofp_version(of_header['version'])
- supported_versions = []
- for version in sanitizer['allowed_of_versions']:
- supported_versions.append(version)
- if name_version not in supported_versions:
- return 0
-
- # OF Types to be ignored through json file (-F)
- rejected_types = sanitizer['allowed_of_versions'][name_version]
- if of_header['type'] in rejected_types['rejected_of_types']:
- return 0
-
- return 1
-
-
-def parse_packet(packet, date, getlen, caplen, print_options, sanitizer):
- '''
- This functions gets the raw packet and dissassembly it.
- Only TCP + OpenFlow are analysed. Others are discarted
- '''
- eth = get_ethernet_frame(packet)
-
- # If protocol is no IP(8) returns
- if (eth['protocol'] != 8):
- return
-
- ip = get_ip_packet(packet, eth['length'])
-
- # If protocol is not TCP, returns
- if (ip['protocol'] != 6):
- return
-
- header_size = ip['length'] + eth['length']
- tcp = get_tcp_stream(packet, header_size)
-
- # If TCP flag is not PUSH, return
- if (tcp['flag_psh'] != 8):
- return
-
- # Now let's process all OpenFlow packets in the payload
- header_size = header_size + tcp['length']
- remaining_bytes = caplen - header_size
-
- print_header_once = 0
- start = header_size
-
- # If there is less than 8 bytes, it is because it is fragment.
- # There is no support for fragmented packet at this time
- while (remaining_bytes >= 8):
- of_header = get_openflow_header(packet, start)
-
- # If -F was passed...
- if len(sanitizer['allowed_of_versions']) != 0:
- result = sanitizer_filters(of_header, date, getlen, caplen,
- header_size, eth, ip, tcp, sanitizer)
- if result == 0:
- return
-
- # In case there are multiple flow_mods
- remaining_bytes = remaining_bytes - of_header['length']
-
- # Starts printing
- if print_header_once == 0:
- print_headers(print_options, date, getlen, caplen, eth, ip, tcp)
- print_header_once = 1
-
- # Prints the OpenFlow header, it doesn't matter the OF version
- print_openflow_header(of_header)
-
- print_options['device_ip'] = ip['d_addr']
- print_options['device_port'] = tcp['dest_port']
-
- # If OpenFlow version is 1.0
- if of_header['version'] == int('1', 16):
- # Process and Print OF body
- # OF_Header lenght = 8
- start = start + 8
- this_packet = packet[start:start+of_header['length'] - 8]
- if not process_ofp_type(of_header['type'], this_packet, 0,
- of_header['xid'], print_options, sanitizer):
- print ('%s OpenFlow OFP_Type %s not dissected \n' %
- (of_header['xid'], of_header['type']))
- return
- else:
- # Get next packet
- start = start + (of_header['length'] - 8)
- # If OpenFlow version is 1.3
- elif of_header['version'] == int('4', 16):
- print 'Coming soon...'
- return
- else:
- print 'OpenFlow version %s not supported \n' % of_header['version']
- return
-
- # Do not process extra data from Hello and Error.
- # Maybe in the future.
- if (of_header['type'] == 0 or of_header['type'] == 1):
- print
- return
-
- print
+from libs.core.printing import PrintingOptions
+from libs.core.sanitizer import Sanitizer
+from libs.core.topo_reader import TopoReader
+from libs.core.cli import get_params
+from libs.gen.packet import Packet
+from apps.oess_fvd import OessFvdTracer
+from apps.ofp_stats import OFStats
+from apps.ofp_proxies import OFProxy
+
+
+class RunSniffer(object):
+ """
+ The RunSniffer class is the main class for the OpenFlow Sniffer.
+ This class instantiate all auxiliary classes, captures the packets,
+ instantiate new OpenFlow messages and triggers all applications.
+ """
+ def __init__(self):
+ self.printing_options = PrintingOptions()
+ self.sanitizer = Sanitizer()
+ self.oft = None
+ self.stats = None
+ self.cap = None
+ self.packet_number = None
+ self.load_apps = []
+ self.packet_count = 1
+ self.topo_reader = TopoReader()
+ self.ofp_proxy = None
+ self.load_config()
+
+ def load_config(self):
+ """
+ Parses the parameters received and instantiates the
+ apps requested.
+ """
+ # Get CLI params and call the pcapy loop
+ self.cap, self.packet_number, \
+ self.load_apps, sanitizer, topo_file = get_params(sys.argv)
+ self.sanitizer.process_filters(sanitizer)
+
+ # Load TopologyReader
+ self.topo_reader.readfile(topo_file)
+
+ # Start Apps
+ if 'oess_fvd' in self.load_apps:
+ self.oft = OessFvdTracer()
+
+ if 'statistics' in self.load_apps:
+ self.stats = OFStats()
+
+ # Load Proxy
+ self.ofp_proxy = OFProxy()
+
+ def run(self):
+ """
+ cap.loop continuously capture packets w/ pcapy. For every
+ captured packet, self.process_packet method is called.
+
+ Exits:
+ 0 - Normal, reached end of file
+ 1 - Normal, user requested with CRTL + C
+ 2 - Error
+ 3 - Interface or file not found
+ """
+ exit_code = 0
+
+ # Debug:
+ # self.cap.loop(-1, self.process_packet)
+ try:
+ self.cap.loop(-1, self.process_packet)
+
+ if 'statistics' in self.load_apps:
+ # If OFP_Stats is running, set a timer
+ # before closing the app. Useful in cases
+ # where the ofp_sniffer is reading from a
+ # pcap file instead of real time.
+ time.sleep(200)
+
+ except KeyboardInterrupt:
+ exit_code = 1
+
+ except Exception as exception:
+ print('Error on packet %s: %s ' % (self.packet_count, exception))
+ exit_code = 2
+
+ finally:
+ print('Exiting...')
+ sys.exit(exit_code)
+
+ def process_packet(self, header, packet):
+ """
+ Every packet captured by cap.loop is then processed here.
+ If packets are bigger than 62 Bytes, we process them.
+ If it is 0, means there are no more packets. If it is
+ something in between, it is a fragment, we ignore for now.
+
+ Args:
+ header: header of the captured packet
+ packet: packet captured from file or interface
+ """
+ if len(packet) >= 62 and self.packet_number_defined():
+
+ # DEBUG:
+ # print("Packet Number: %s" % self.packet_count)
+ pkt = Packet(packet, self.packet_count, header)
+
+ if pkt.is_openflow_packet:
+ valid_result = pkt.process_openflow_messages()
+ if valid_result:
+
+ # Apps go here:
+ if isinstance(self.oft, OessFvdTracer):
+ # FVD_Tracer does not print the packets
+ self.oft.process_packet(pkt)
+
+ if isinstance(self.ofp_proxy, OFProxy):
+ # OFP_PROXY associates IP:PORT to DPID
+ self.ofp_proxy.process_packet(pkt)
+
+ if isinstance(self.stats, OFStats):
+ # OFStats print the packets
+ self.stats.process_packet(pkt)
+
+ if not isinstance(self.oft, OessFvdTracer):
+ # Print Packets
+ pkt.print_packet()
+
+ del pkt
+
+ elif len(packet) is 0:
+ sys.exit(0)
+
+ self.packet_count += 1
+
+ def packet_number_defined(self):
+ """
+ In case user wants to see a specific packet inside a
+ specific pcap file, provide file name with the specific
+ packet number
+ -r file.pcap:packet_number
+ Returns:
+ True if packet_count matches
+ False: if packet_count does not match
+ """
+ if self.packet_number > 0:
+ return True if self.packet_count == self.packet_number else False
+
+ return True
+
+
+def main():
+ """
+ Main function.
+ Instantiates RunSniffer and run it
+ """
+ sniffer = RunSniffer()
+ sniffer.run()
+
if __name__ == "__main__":
- main(sys.argv)
+ main()
diff --git a/ofp_tcpip_parser.py b/ofp_tcpip_parser.py
deleted file mode 100644
index 9a26e8b..0000000
--- a/ofp_tcpip_parser.py
+++ /dev/null
@@ -1,206 +0,0 @@
-from struct import unpack
-import socket
-
-
-def get_ethernet_frame(packet, host_order=0):
- # Ethernet Header has 14 bytes
- eth_length = 14
- eth_header = packet[:eth_length]
- dst_mac, src_mac, prot = unpack('!6s6sH', eth_header)
- if not host_order:
- eth_protocol = socket.ntohs(prot)
- else:
- eth_protocol = prot
- eth_frame = {'src_mac': src_mac, 'dst_mac': dst_mac,
- 'protocol': eth_protocol, 'length': eth_length}
- return eth_frame
-
-
-def get_ethernet_vlan(packet):
- vlan_length = 2
- vlan_pq = packet[:vlan_length]
- vlan_p = unpack('!H', vlan_pq)
- prio = vlan_p[0] >> 13
- cfi = (vlan_p[0] & 0x1000) >> 12
- vid = vlan_p[0] & 0xfff
- vlan = {'prio': prio, 'cfi': cfi, 'vid': vid}
- return vlan
-
-
-def get_next_etype(packet):
- etype_length = 2
- et = packet[:etype_length]
- return unpack('!H', et)[0]
-
-
-def get_arp(packet):
- arp_raw = packet[:28]
- arp = unpack('!HHBBH6sL6sL', arp_raw)
- src_ip = arp[6]
- dst_ip = arp[8]
- arp_frame = {'hw_type': arp[0], 'prot_type': arp[1], 'hw_len': arp[2],
- 'prot_len': arp[3], 'opcode': arp[4], 'src_mac': arp[5],
- 'src_ip': src_ip, 'dst_mac': arp[7], 'dst_ip': dst_ip}
- return arp_frame
-
-
-def get_ip_packet(packet, eth_length):
- '''
- Returns IP Header fields
- '''
- ip_min_len = 20
- ip_header = packet[eth_length:ip_min_len+eth_length]
- iph = unpack('!BBHHHBBH4s4s', ip_header)
- version_ihl = iph[0]
- version = version_ihl >> 4
- ihl = version_ihl & 0xF
- iph_length = ihl * 4
- ttl = iph[5]
- protocol = iph[6]
- s_addr = socket.inet_ntoa(iph[8])
- d_addr = socket.inet_ntoa(iph[9])
- ip_pkt = {'version': version, 'ihl': ihl, 'length': iph_length,
- 'ttl': ttl, 'protocol': protocol, 's_addr': s_addr,
- 'd_addr': d_addr}
- return ip_pkt
-
-
-def get_tcp_stream(packet, header_size):
- '''
- Returns TCP Header fields
- '''
- tcp_length = 20
- tcp_header = packet[header_size:header_size+tcp_length]
- tcph = unpack('!HHLLBBHHH', tcp_header)
- source_port = tcph[0]
- dest_port = tcph[1]
- sequence = tcph[2]
- acknowledgement = tcph[3]
- doff_reserved = tcph[4]
- tcph_length = doff_reserved >> 4
- tcph_length = tcph_length * 4
- flags = tcph[5] # Ignoring Flag NS
- flag_cwr = flags & 0x80
- flag_ece = flags & 0x40
- flag_urg = flags & 0x20
- flag_ack = flags & 0x10
- flag_psh = flags & 0x08
- flag_rst = flags & 0x04
- flag_syn = flags & 0x02
- flag_fyn = flags & 0x01
- tcp_stream = {'source_port': source_port, 'dest_port': dest_port,
- 'sequence': sequence, 'acknowledgement': acknowledgement,
- 'length': tcph_length, 'flag_cwr': flag_cwr,
- 'flag_ece': flag_ece, 'flag_urg': flag_urg,
- 'flag_ack': flag_ack, 'flag_psh': flag_psh,
- 'flag_rst': flag_rst, 'flag_syn': flag_syn,
- 'flag_fyn': flag_fyn}
- return tcp_stream
-
-
-def get_openflow_header(packet, start):
- '''
- Returns OpenFlow header
- It is non-version aware
- '''
- of_header_length = 8
- of_header = packet[start:of_header_length+start]
- try:
- ofh = unpack('!BBHL', of_header)
- of_version = ofh[0]
- of_type = ofh[1]
- of_length = ofh[2]
- of_xid = ofh[3]
- of_header = {'version': of_version, 'type': of_type,
- 'length': of_length, 'xid': of_xid}
- return of_header
-
- except Exception as exception:
- print exception
- of_header['version'] = -1
- return of_header
-
-
-def get_lldp(packet):
- # Chassis
- # TLV (1) + Length = 2 bytes | Sub-type = 1 Byte
- chassis_raw = packet[:3]
- chassis = unpack('!HB', chassis_raw)
- c_type = chassis[0] >> 9
- if c_type is not 1:
- return {}
- c_length = chassis[0] & 0xFF
- c_subtype = chassis[1]
- length = c_length - 1
- # Get C_ID
- chassis_raw = packet[3:3+length]
- string = '!%ss' % length
- chassis = unpack(string, chassis_raw)
- c_id = chassis[0]
-
- start = 3 + length
-
- # Port
- # TLV (2) + Length = 2 Bytes | Port_id = 1 Byte
- port_raw = packet[start:start+3]
- port = unpack('!HB', port_raw)
- p_type = port[0] >> 9
- if p_type is not 2:
- return {}
- p_length = port[0] & 0xFF
- p_subtype = port[1]
- length = p_length - 1
- # Get P_ID
- port_raw = packet[start+3:start+3+length]
- string = '!%ss' % length
- port = unpack(string, port_raw)
- p_id = port[0]
-
- start = start + 3 + length
-
- # TTL
- ttl_raw = packet[start:start+4]
- ttl = unpack('!HH', ttl_raw)
- t_type = ttl[0] >> 9
- if t_type is not 3:
- return {}
- t_length = ttl[0] & 0xFF
- t_ttl = ttl[1]
-
- start = start + 4
- # Loop to get User-Specific TLVs
- while len(packet[start:]) > 0:
- next_raw = packet[start:start+2]
- nraw = unpack('!H', next_raw)
- n_type = nraw[0] >> 9
- n_length = nraw[0] & 0xFF
- length = n_length - 4
- if n_type == 0:
- break
- elif n_type == 127:
- # We only want TLV 127, OUI a42305 (ONOS)
- # Then we will look for Subtype 2 and get the content
- # Skip the OUI - 3 bytes
- subtype_raw = packet[start+5:start+6]
- subtype = unpack('!B', subtype_raw)
- start = start + 6
- if subtype[0] == 2:
- content_raw = packet[start:start+length]
- string = '!%ss' % length
- content = unpack(string, content_raw)
- c_id = content[0]
- start = start + length
-
- # END
- end_raw = packet[start:start+2]
- end = unpack('!H', end_raw)
- e_type = end[0] >> 9
- e_length = end[0] & 0xFF
-
- lldp = {'c_type': c_type, 'c_length': c_length, 'c_subtype': c_subtype,
- 'c_id': c_id, 'p_type': p_type, 'p_length': p_length,
- 'p_subtype': p_subtype, 'p_id': p_id, 't_type': t_type,
- 't_length': t_length, 't_ttl': t_ttl, 'e_type': e_type,
- 'e_length': e_length}
-
- return lldp
diff --git a/ofp_vendors_v10.py b/ofp_vendors_v10.py
deleted file mode 100644
index 37cf2e1..0000000
--- a/ofp_vendors_v10.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from struct import unpack
-
-
-def parse_nicira(packet, start, of_xid):
- print ('%s OpenFlow Vendor Data: ' % of_xid),
- while len(packet[start:start+4]) > 0:
- ofv_subtype = unpack('!L', packet[start:start+4])
- print ('%s ' % ofv_subtype[0]),
- start = start + 4
diff --git a/termcolor.py b/termcolor.py
deleted file mode 100644
index f11b824..0000000
--- a/termcolor.py
+++ /dev/null
@@ -1,168 +0,0 @@
-# coding: utf-8
-# Copyright (c) 2008-2011 Volvox Development Team
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# Author: Konstantin Lepa
-
-"""ANSII Color formatting for output in terminal."""
-
-from __future__ import print_function
-import os
-
-
-__ALL__ = [ 'colored', 'cprint' ]
-
-VERSION = (1, 1, 0)
-
-ATTRIBUTES = dict(
- list(zip([
- 'bold',
- 'dark',
- '',
- 'underline',
- 'blink',
- '',
- 'reverse',
- 'concealed'
- ],
- list(range(1, 9))
- ))
- )
-del ATTRIBUTES['']
-
-
-HIGHLIGHTS = dict(
- list(zip([
- 'on_grey',
- 'on_red',
- 'on_green',
- 'on_yellow',
- 'on_blue',
- 'on_magenta',
- 'on_cyan',
- 'on_white'
- ],
- list(range(40, 48))
- ))
- )
-
-
-COLORS = dict(
- list(zip([
- 'grey',
- 'red',
- 'green',
- 'yellow',
- 'blue',
- 'magenta',
- 'cyan',
- 'white',
- ],
- list(range(30, 38))
- ))
- )
-
-
-RESET = '\033[0m'
-
-
-def colored(text, color=None, on_color=None, attrs=None):
- """Colorize text.
-
- Available text colors:
- red, green, yellow, blue, magenta, cyan, white.
-
- Available text highlights:
- on_red, on_green, on_yellow, on_blue, on_magenta, on_cyan, on_white.
-
- Available attributes:
- bold, dark, underline, blink, reverse, concealed.
-
- Example:
- colored('Hello, World!', 'red', 'on_grey', ['blue', 'blink'])
- colored('Hello, World!', 'green')
- """
- if os.getenv('ANSI_COLORS_DISABLED') is None:
- fmt_str = '\033[%dm%s'
- if color is not None:
- text = fmt_str % (COLORS[color], text)
-
- if on_color is not None:
- text = fmt_str % (HIGHLIGHTS[on_color], text)
-
- if attrs is not None:
- for attr in attrs:
- text = fmt_str % (ATTRIBUTES[attr], text)
-
- text += RESET
- return text
-
-
-def cprint(text, color=None, on_color=None, attrs=None, **kwargs):
- """Print colorize text.
-
- It accepts arguments of print function.
- """
-
- print((colored(text, color, on_color, attrs)), **kwargs)
-
-
-if __name__ == '__main__':
- print('Current terminal type: %s' % os.getenv('TERM'))
- print('Test basic colors:')
- cprint('Grey color', 'grey')
- cprint('Red color', 'red')
- cprint('Green color', 'green')
- cprint('Yellow color', 'yellow')
- cprint('Blue color', 'blue')
- cprint('Magenta color', 'magenta')
- cprint('Cyan color', 'cyan')
- cprint('White color', 'white')
- print(('-' * 78))
-
- print('Test highlights:')
- cprint('On grey color', on_color='on_grey')
- cprint('On red color', on_color='on_red')
- cprint('On green color', on_color='on_green')
- cprint('On yellow color', on_color='on_yellow')
- cprint('On blue color', on_color='on_blue')
- cprint('On magenta color', on_color='on_magenta')
- cprint('On cyan color', on_color='on_cyan')
- cprint('On white color', color='grey', on_color='on_white')
- print('-' * 78)
-
- print('Test attributes:')
- cprint('Bold grey color', 'grey', attrs=['bold'])
- cprint('Dark red color', 'red', attrs=['dark'])
- cprint('Underline green color', 'green', attrs=['underline'])
- cprint('Blink yellow color', 'yellow', attrs=['blink'])
- cprint('Reversed blue color', 'blue', attrs=['reverse'])
- cprint('Concealed Magenta color', 'magenta', attrs=['concealed'])
- cprint('Bold underline reverse cyan color', 'cyan',
- attrs=['bold', 'underline', 'reverse'])
- cprint('Dark blink concealed white color', 'white',
- attrs=['dark', 'blink', 'concealed'])
- print(('-' * 78))
-
- print('Test mixing:')
- cprint('Underline red on grey color', 'red', 'on_grey',
- ['underline'])
- cprint('Reversed green on red color', 'green', 'on_red', ['reverse'])
-