diff --git a/ryu/lib/packet/__init__.py b/ryu/lib/packet/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ryu/lib/packet/arp.py b/ryu/lib/packet/arp.py new file mode 100644 index 00000000..f05bd398 --- /dev/null +++ b/ryu/lib/packet/arp.py @@ -0,0 +1,48 @@ +# Copyright (C) 2012 Nippon Telegraph and Telephone Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import struct +from . import packet_base +from ryu.ofproto.ofproto_parser import msg_pack_into + + +class arp(packet_base.PacketBase): + _PACK_STR = '!HHBBH6sI6sI' + + def __init__(self, hwtype, proto, hlen, plen, opcode, + src_mac, src_ip, dst_mac, dst_ip): + super(arp, self).__init__() + self.hwtype = hwtype + self.proto = proto + self.hlen = hlen + self.plen = plen + self.opcode = opcode + self.src_mac = src_mac + self.src_ip = src_ip + self.dst_mac = dst_mac + self.dst_ip = dst_ip + self.length = struct.calcsize(arp._PACK_STR) + + @classmethod + def parser(cls, buf): + (hwtype, proto, hlen, plen, opcode, src_mac, src_ip, + dst_mac, dst_ip) = struct.unpack_from(cls._PACK_STR, buf) + return cls(hwtype, proto, hlen, plen, opcode, src_mac, src_ip, + dst_mac, dst_ip), None + + def serialize(self, buf, offset): + msg_pack_into(arp._PACK_STR, buf, offset, self.hwtype, self.proto, + self.hlen, self.plen, self.opcode, + self.src_mac, self.src_ip, self.dst_mac, self.dst_ip) diff --git a/ryu/lib/packet/ethernet.py b/ryu/lib/packet/ethernet.py new file mode 100644 index 00000000..2b594d07 --- /dev/null +++ b/ryu/lib/packet/ethernet.py @@ -0,0 +1,45 @@ +# Copyright (C) 2012 Nippon Telegraph and Telephone Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import struct +from . import packet_base +from . import vlan +from ryu.ofproto import ether +from ryu.ofproto.ofproto_parser import msg_pack_into + + +class ethernet(packet_base.PacketBase): + _PACK_STR = '!6s6sH' + + def __init__(self, dst, src, ethertype): + super(ethernet, self).__init__() + self.dst = dst + self.src = src + self.ethertype = ethertype + self.length = struct.calcsize(ethernet._PACK_STR) + + @classmethod + def parser(cls, buf): + dst, src, ethertype = struct.unpack_from(cls._PACK_STR, buf) + return cls(dst, src, ethertype), ethernet.get_packet_type(ethertype) + + def serialize(self, buf, offset): + msg_pack_into(ethernet._PACK_STR, buf, offset, + self.dst, self.src, self.ethertype) + + +# copy vlan _TYPES +ethernet._TYPES = vlan.vlan._TYPES +ethernet.register_packet_type(vlan.vlan, ether.ETH_TYPE_8021Q) diff --git a/ryu/lib/packet/ipv4.py b/ryu/lib/packet/ipv4.py new file mode 100644 index 00000000..9edb49ea --- /dev/null +++ b/ryu/lib/packet/ipv4.py @@ -0,0 +1,80 @@ +# Copyright (C) 2012 Nippon Telegraph and Telephone Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import struct +from . import packet_base +from . import udp +from ryu.ofproto.ofproto_parser import msg_pack_into +from ryu.ofproto import inet + +class ipv4(packet_base.PacketBase): + _PACK_STR = '!BBHHHBBHII' + + def __init__(self, version, header_length, tos, total_length, + identification, flags, offset, ttl, proto, csum, + src, dst): + super(ipv4, self).__init__() + self.version = version + self.header_length = header_length + self.tos = tos + self.total_length = total_length + self.identification = identification + self.flags = flags + self.offset = offset + self.ttl = ttl + self.proto = proto + self.csum = csum + self.src = src + self.dst = dst + self.length = header_length * 4 + + @classmethod + def parser(cls, buf): + (version, tos, total_length, identification, flags, ttl, proto, csum, + src, dst) = struct.unpack_from(cls._PACK_STR, buf) + header_length = version & 0xf + version = version >> 4 + offset = flags & ((1 << 15) - 1) + flags = flags >> 15 + msg = cls(version, header_length, tos, total_length, identification, + flags, offset, ttl, proto, csum, src, dst) + + if msg.length > struct.calcsize(ipv4._PACK_STR): + self.extra = buf[struct.calcsize(ipv4._PACK_STR):msg.length] + + return msg, ipv4.get_packet_type(proto) + + @staticmethod + def carry_around_add(a, b): + c = a + b + return (c & 0xffff) + (c >> 16) + + def checksum(self, data): + s = 0 + for i in range(0, len(data), 2): + w = data[i] + (data[i+1] << 8) + s = self.carry_around_add(s, w) + return ~s & 0xffff + + def serialize(self, buf, offset): + version = self.version << 4 | self.header_length + flags = self.flags << 15 | self.offset + msg_pack_into(ipv4._PACK_STR, buf, offset, version, self.tos, + self.total_length, self.identification, flags, + self.ttl, self.proto, 0, self.src, self.dst) + self.csum = self.checksum(buf[offset:offset+self.length]) + msg_pack_into('H', buf, offset + 10, self.csum) + +ipv4.register_packet_type(udp.udp, inet.IPPROTO_UDP) diff --git a/ryu/lib/packet/packet.py b/ryu/lib/packet/packet.py new file mode 100644 index 00000000..ea7300a1 --- /dev/null +++ b/ryu/lib/packet/packet.py @@ -0,0 +1,49 @@ +# Copyright (C) 2012 Nippon Telegraph and Telephone Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from . import ethernet + + +class Packet(object): + def __init__(self, data=None): + super(Packet, self).__init__() + self.data = data + self.protocols = [] + self.parsed_bytes = 0 + if self.data: + # Do we need to handle non ethernet? + self.parser(ethernet.ethernet) + + def parser(self, cls): + while cls: + proto, cls = cls.parser(self.data[self.parsed_bytes:]) + if proto: + self.parsed_bytes += proto.length + self.protocols.append(proto) + + def serialize(self): + offset = 0 + self.data = bytearray() + for p in self.protocols: + p.serialize(self.data, offset) + offset += p.length + + def add_protocol(self, proto): + self.protocols.append(proto) + + def find_protocol(self, name): + for p in self.protocols: + if p.__class__.__name__ == name: + return p diff --git a/ryu/lib/packet/packet_base.py b/ryu/lib/packet/packet_base.py new file mode 100644 index 00000000..20964580 --- /dev/null +++ b/ryu/lib/packet/packet_base.py @@ -0,0 +1,37 @@ +# Copyright (C) 2012 Nippon Telegraph and Telephone Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +class PacketBase(object): + _TYPES = {} + + @classmethod + def get_packet_type(cls, type_): + return cls._TYPES.get(type_) + + @classmethod + def register_packet_type(cls, cls_, type_): + cls._TYPES[type_] = cls_ + + def __init__(self): + super(PacketBase, self).__init__() + self.length = 0 + + @classmethod + def parser(cls): + pass + + def serialize(self): + pass diff --git a/ryu/lib/packet/udp.py b/ryu/lib/packet/udp.py new file mode 100644 index 00000000..d4cd0f9a --- /dev/null +++ b/ryu/lib/packet/udp.py @@ -0,0 +1,44 @@ +# Copyright (C) 2012 Nippon Telegraph and Telephone Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import struct +from . import packet_base +from ryu.ofproto.ofproto_parser import msg_pack_into + + +class udp(packet_base.PacketBase): + _PACK_STR = '!HHHH' + + def __init__(self, src_port, dst_port, length, csum=0, data=None): + super(udp, self).__init__() + self.src_port = src_port + self.dst_port = dst_port + self.length = length + self.csum = csum + self.data = data + + @classmethod + def parser(cls, buf): + (src_port, dst_port, length, csum) = struct.unpack_from(cls._PACK_STR, + buf) + msg = cls(src_port, dst_port, length, csum) + if length > struct.calcsize(cls._PACK_STR): + msg.data = buf[struct.calcsize(cls._PACK_STR):length] + + return msg, None + + def serialize(self, buf, offset): + msg_pack_into(udp._PACK_STR, buf, offset, self.src_port, self.dst_port, + self.length, self.csum) diff --git a/ryu/lib/packet/vlan.py b/ryu/lib/packet/vlan.py new file mode 100644 index 00000000..ddc651cd --- /dev/null +++ b/ryu/lib/packet/vlan.py @@ -0,0 +1,48 @@ +# Copyright (C) 2012 Nippon Telegraph and Telephone Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import struct +from . import packet_base +from . import arp +from . import ipv4 +from ryu.ofproto import ether +from ryu.ofproto.ofproto_parser import msg_pack_into + + +class vlan(packet_base.PacketBase): + _PACK_STR = "!HH" + + def __init__(self, pcp, cfi, vid, ethertype): + super(vlan, self).__init__() + self.pcp = pcp + self.cfi = cfi + self.vid = vid + self.ethertype = ethertype + self.length = struct.calcsize(vlan._PACK_STR) + + @classmethod + def parser(cls, buf): + tci, ethertype = struct.unpack_from(cls._PACK_STR, buf) + pcp = tci >> 15 + cfi = (tci >> 12) & 1 + vid = tci & ((1 << 12) - 1) + return cls(pcp, cfi, vid, ethertype), vlan.get_packet_type(ethertype) + + def serialize(self, buf, offset): + tci = self.pcp << 15 | self.cfi << 12 | self.vid + msg_pack_into(vlan._PACK_STR, buf, offset, tci, self.ethertype) + +vlan.register_packet_type(arp.arp, ether.ETH_TYPE_ARP) +vlan.register_packet_type(ipv4.ipv4, ether.ETH_TYPE_IP)