Skip to content
This repository was archived by the owner on Apr 22, 2024. It is now read-only.

Commit d8fb6c4

Browse files
authored
Merge pull request #371 from renanrodrigo/add_ip_4
Add IPv4 network type class
2 parents 43feaed + bcdf6fc commit d8fb6c4

90 files changed

Lines changed: 265 additions & 150 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ All notable changes to the python-openflow project is documented in this file.
77
********************************
88
Added
99
=====
10+
- IPv4 packet pack/unpack support.
1011

1112
Changed
1213
=======

pyof/foundation/base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
from enum import Enum, IntEnum
2424

2525
# Local source tree imports
26-
from pyof.foundation.exceptions import (BadValueException, PackException,
27-
UnpackException, ValidationError)
26+
from pyof.foundation.exceptions import (
27+
BadValueException, PackException, UnpackException, ValidationError)
2828

2929
# Third-party imports
3030

pyof/foundation/network_types.py

Lines changed: 137 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
"""
55

66
from pyof.foundation.base import GenericStruct
7-
from pyof.foundation.basic_types import BinaryData, HWAddress, UBInt8, UBInt16
7+
from pyof.foundation.basic_types import (
8+
BinaryData, HWAddress, IPAddress, UBInt8, UBInt16)
89
from pyof.foundation.exceptions import PackException
910

10-
__all__ = ('Ethernet', 'GenericTLV', 'TLVWithSubType', 'LLDP')
11+
__all__ = ('Ethernet', 'GenericTLV', 'IPv4', 'TLVWithSubType', 'LLDP')
1112

1213

1314
class Ethernet(GenericStruct):
@@ -138,6 +139,140 @@ def get_size(self, value=None):
138139
return 2 + self.length
139140

140141

142+
class IPv4(GenericStruct):
143+
"""IPv4 packet "struct".
144+
145+
Contains all fields of an IP version 4 packet header, plus the upper layer
146+
content as binary data.
147+
Some of the fields were merged together because of their size being
148+
inferior to 8 bits. They are represented as a single class attribute, but
149+
pack/unpack methods will take into account the values in individual
150+
instance attributes.
151+
"""
152+
153+
#: _version_ihl (:class:`UBInt8`): IP protocol version + Internet Header
154+
#: Length (words)
155+
_version_ihl = UBInt8()
156+
#: _dscp_ecn (:class:`UBInt8`): Differentiated Services Code Point
157+
#: (ToS - Type of Service) + Explicit Congestion Notification
158+
_dscp_ecn = UBInt8()
159+
#: length (:class:`UBInt16`): IP packet length (bytes)
160+
length = UBInt16()
161+
#: identification (:class:`UBInt16`): Packet ID - common to all fragments
162+
identification = UBInt16()
163+
#: _flags_offset (:class:`UBInt16`): Fragmentation flags + fragmentation
164+
#: offset
165+
_flags_offset = UBInt16()
166+
#: ttl (:class:`UBInt8`): Packet time-to-live
167+
ttl = UBInt8()
168+
#: protocol (:class:`UBInt8`): Upper layer protocol number
169+
protocol = UBInt8()
170+
#: checksum (:class:`UBInt16`): Header checksum
171+
checksum = UBInt16()
172+
#: source (:class:`IPAddress`): Source IPv4 address
173+
source = IPAddress()
174+
#: destination (:class:`IPAddress`): Destination IPv4 address
175+
destination = IPAddress()
176+
#: options (:class:`BinaryData`): IP Options - up to 320 bits, always
177+
#: padded to 32 bits
178+
options = BinaryData()
179+
#: data (:class:`BinaryData`): Packet data
180+
data = BinaryData()
181+
182+
def __init__(self, version=4, ihl=5, dscp=0, ecn=0, length=0, # noqa
183+
identification=0, flags=0, offset=0, ttl=255, protocol=0,
184+
checksum=0, source="0.0.0.0", destination="0.0.0.0",
185+
options=b'', data=b''):
186+
"""Create the Packet and set instance attributes."""
187+
super().__init__()
188+
self.version = version
189+
self.ihl = ihl
190+
self.dscp = dscp
191+
self.ecn = ecn
192+
self.length = length
193+
self.identification = identification
194+
self.flags = flags
195+
self.offset = offset
196+
self.ttl = ttl
197+
self.protocol = protocol
198+
self.checksum = checksum
199+
self.source = source
200+
self.destination = destination
201+
self.options = options
202+
self.data = data
203+
204+
def _update_checksum(self):
205+
"""Update the packet checksum to enable integrity check."""
206+
source_list = [int(octet) for octet in self.source.split(".")]
207+
destination_list = [int(octet) for octet in
208+
self.destination.split(".")]
209+
source_upper = (source_list[0] << 8) + source_list[1]
210+
source_lower = (source_list[2] << 8) + source_list[3]
211+
destination_upper = (destination_list[0] << 8) + destination_list[1]
212+
destination_lower = (destination_list[2] << 8) + destination_list[3]
213+
214+
block_sum = ((self._version_ihl << 8 | self._dscp_ecn) + self.length +
215+
self.identification + self._flags_offset +
216+
(self.ttl << 8 | self.protocol) + source_upper +
217+
source_lower + destination_upper + destination_lower)
218+
219+
while block_sum > 65535:
220+
carry = block_sum >> 16
221+
block_sum = (block_sum & 65535) + carry
222+
223+
self.checksum = ~block_sum & 65535
224+
225+
def pack(self, value=None):
226+
"""Pack the struct in a binary representation.
227+
228+
Merge some fields to ensure correct packing.
229+
"""
230+
# Set the correct IHL based on options size
231+
if self.options:
232+
self.ihl += int(len(self.options) / 4)
233+
234+
# Set the correct packet length based on header length and data
235+
self.length = int(self.ihl * 4 + len(self.data))
236+
237+
self._version_ihl = self.version << 4 | self.ihl
238+
self._dscp_ecn = self.dscp << 2 | self.ecn
239+
self._flags_offset = self.flags << 13 | self.offset
240+
241+
# Set the checksum field before packing
242+
self._update_checksum()
243+
244+
return super().pack()
245+
246+
def unpack(self, buff, offset=0):
247+
"""Unpack a binary struct into this object's attributes.
248+
249+
Return the values instead of the lib's basic types.
250+
"""
251+
super().unpack(buff, offset)
252+
253+
self.version = self._version_ihl.value >> 4
254+
self.ihl = self._version_ihl.value & 15
255+
self.dscp = self._dscp_ecn.value >> 2
256+
self.ecn = self._dscp_ecn.value & 3
257+
self.length = self.length.value
258+
self.identification = self.identification.value
259+
self.flags = self._flags_offset.value >> 13
260+
self.offset = self._flags_offset.value & 8191
261+
self.ttl = self.ttl.value
262+
self.protocol = self.protocol.value
263+
self.checksum = self.checksum.value
264+
self.source = self.source.value
265+
self.destination = self.destination.value
266+
267+
if self.ihl > 5:
268+
options_size = (self.ihl - 5) * 4
269+
self.data = self.options.value[options_size:]
270+
self.options = self.options.value[:options_size]
271+
else:
272+
self.data = self.options.value
273+
self.options = b''
274+
275+
141276
class TLVWithSubType(GenericTLV):
142277
"""Modify the :class:`GenericTLV` to a Organization Specific TLV structure.
143278

pyof/v0x01/asynchronous/packet_in.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
from enum import IntEnum
55

66
from pyof.foundation.base import GenericMessage
7-
from pyof.foundation.basic_types import (BinaryData, Pad, UBInt8, UBInt16,
8-
UBInt32)
7+
from pyof.foundation.basic_types import (
8+
BinaryData, Pad, UBInt8, UBInt16, UBInt32)
99
from pyof.v0x01.common.constants import NO_BUFFER
1010
from pyof.v0x01.common.header import Header, Type
1111

pyof/v0x01/common/action.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
# Local source tree imports
66
from pyof.foundation.base import GenericBitMask, GenericStruct
7-
from pyof.foundation.basic_types import (FixedTypeList, HWAddress, Pad, UBInt8,
8-
UBInt16, UBInt32)
7+
from pyof.foundation.basic_types import (
8+
FixedTypeList, HWAddress, Pad, UBInt8, UBInt16, UBInt32)
99
from pyof.foundation.constants import UBINT16_MAX_VALUE
1010

1111
# Third-party imports

pyof/v0x01/common/flow_match.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
# Local source tree imports
88
from pyof.foundation.base import GenericBitMask, GenericStruct
9-
from pyof.foundation.basic_types import (HWAddress, IPAddress, Pad, UBInt8,
10-
UBInt16, UBInt32)
9+
from pyof.foundation.basic_types import (
10+
HWAddress, IPAddress, Pad, UBInt8, UBInt16, UBInt32)
1111

1212
__all__ = ('Match', 'FlowWildCards')
1313

pyof/v0x01/common/phy_port.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
# Local source tree imports
77
from pyof.foundation.base import GenericBitMask, GenericStruct
8-
from pyof.foundation.basic_types import (Char, FixedTypeList, HWAddress,
9-
UBInt16, UBInt32)
8+
from pyof.foundation.basic_types import (
9+
Char, FixedTypeList, HWAddress, UBInt16, UBInt32)
1010
from pyof.foundation.constants import OFP_MAX_PORT_NAME_LEN
1111

1212
# Third-party imports

pyof/v0x01/common/utils.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
from pyof.v0x01.controller2switch.get_config_request import GetConfigRequest
2222
from pyof.v0x01.controller2switch.packet_out import PacketOut
2323
from pyof.v0x01.controller2switch.port_mod import PortMod
24-
from pyof.v0x01.controller2switch.queue_get_config_reply import \
25-
QueueGetConfigReply
26-
from pyof.v0x01.controller2switch.queue_get_config_request import \
27-
QueueGetConfigRequest
24+
from pyof.v0x01.controller2switch.queue_get_config_reply import (
25+
QueueGetConfigReply)
26+
from pyof.v0x01.controller2switch.queue_get_config_request import (
27+
QueueGetConfigRequest)
2828
from pyof.v0x01.controller2switch.set_config import SetConfig
2929
from pyof.v0x01.controller2switch.stats_reply import StatsReply
3030
from pyof.v0x01.controller2switch.stats_request import StatsRequest

pyof/v0x01/controller2switch/common.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
from enum import IntEnum
55

66
from pyof.foundation.base import GenericMessage, GenericStruct
7-
from pyof.foundation.basic_types import (Char, Pad, UBInt8, UBInt16, UBInt32,
8-
UBInt64)
9-
from pyof.foundation.constants import (DESC_STR_LEN, OFP_MAX_TABLE_NAME_LEN,
10-
SERIAL_NUM_LEN)
7+
from pyof.foundation.basic_types import (
8+
Char, Pad, UBInt8, UBInt16, UBInt32, UBInt64)
9+
from pyof.foundation.constants import (
10+
DESC_STR_LEN, OFP_MAX_TABLE_NAME_LEN, SERIAL_NUM_LEN)
1111
# Local source tree imports
1212
from pyof.v0x01.common.action import ListOfActions
1313
from pyof.v0x01.common.flow_match import FlowWildCards, Match

pyof/v0x04/asynchronous/packet_in.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
from enum import IntEnum
55

66
from pyof.foundation.base import GenericMessage
7-
from pyof.foundation.basic_types import (BinaryData, Pad, UBInt8, UBInt16,
8-
UBInt32, UBInt64)
7+
from pyof.foundation.basic_types import (
8+
BinaryData, Pad, UBInt8, UBInt16, UBInt32, UBInt64)
99
from pyof.v0x04.common.flow_match import Match
1010
from pyof.v0x04.common.header import Header, Type
1111

0 commit comments

Comments
 (0)