def setUpClass(cls): """Setup TestStruct.""" reason = FlowRemovedReason.OFPRR_IDLE_TIMEOUT match = Match(in_port=80, dl_vlan=1, dl_vlan_pcp=1, dl_type=1, nw_tos=1, nw_proto=1, tp_src=80, tp_dst=80, dl_src=HWAddress('00:00:00:00:00:00'), dl_dst=HWAddress('00:00:00:00:00:00'), nw_src=IPAddress('192.168.0.1'), nw_dst=IPAddress('192.168.0.2')) super().setUpClass() super().set_raw_dump_file('v0x01', 'ofpt_flow_removed') super().set_raw_dump_object(FlowRemoved, xid=12, match=match, cookie=0, priority=1, reason=reason, duration_sec=4, duration_nsec=23, idle_timeout=9, packet_count=10, byte_count=4) super().set_minimum_size(88)
def from_of_tlv(cls, tlv): """Return an instance from a pyof OXM TLV.""" ip_address = IPAddress() ip_address.unpack(tlv.oxm_value) addr_str = str(ip_address) value = addr_str if tlv.oxm_hasmask: value = f'{addr_str}/{bytes_to_mask(tlv.oxm_value[4:], 32)}' return cls(value)
def as_of_tlv(self): """Return a pyof OXM TLV instance.""" ip_addr = IPAddress(self.value) value_bytes = ip_addr.pack() if ip_addr.netmask < 32: value_bytes += mask_to_bytes(ip_addr.netmask, 32) return OxmTLV(oxm_field=self.oxm_field, oxm_hasmask=ip_addr.netmask < 32, oxm_value=value_bytes)
def __special_convert(self, table): convert = [] IPTYPE = b'\x08\x00' for tr in table: priority = tr[0] match = {"eth_type": IPTYPE} tr1 = tr[1] sip = tr1.get("sip") if sip: match["ip_src"]=IPAddress(sip).pack() dip = tr1.get("dip") if dip: match["ip_dst"]=IPAddress(dip).pack() proto = tr1.get("proto") sport = tr1.get('sport') dport = tr1.get('dport') if proto=="udp": match["ip_proto"] = b'\x11' if sport: match["udp_src"] = UBInt16(sport).pack() if dport: match["udp_dst"] = UBInt16(dport).pack() if proto=="tcp": match["ip_proto"] = b'\x06' if sport: match["tcp_src"] = UBInt16(sport).pack() if dport: match["tcp_dst"] = UBInt16(dport).pack() tr2 = tr[2] seq = [] fmap = {} for n,p in tr2: if n not in fmap: fmap[n]={p} seq.append(n) else: fmap[n].add(p) path = [(n,fmap[n]) for n in seq] convert.append((priority, match, path)) return convert
def __setattr__(self, name, value): # converts string ip_address to IPAddress if isinstance(getattr(Match, name), IPAddress) and \ not isinstance(value, IPAddress): if isinstance(value, list): value = ".".join(str(x) for x in value) value = IPAddress(value) # noqa # convertstring or list of hwaddress to HWAddress elif isinstance(getattr(Match, name), HWAddress) and \ not isinstance(value, HWAddress): if isinstance(value, list): values = ["{0:0{1}x}".format(x, 2) for x in value] value = ":".join(values) value = HWAddress(value) super().__setattr__(name, value) self.fill_wildcards(name, value)
def _match_to_dict(self, flow_stats): match_dict = {} fields = (field for field in flow_stats.match.oxm_match_fields if field.oxm_field in self._match_values) for field in fields: match_field = self._match_values[field.oxm_field] if match_field == 'dl_vlan': data = int.from_bytes(field.oxm_value, 'big') & 4095 elif match_field in ('dl_src', 'dl_dst'): addr = HWAddress() addr.unpack(field.oxm_value) data = str(addr) elif match_field in ('nw_src', 'nw_dst'): addr = IPAddress() addr.unpack(field.oxm_value) data = str(addr) else: data = int.from_bytes(field.oxm_value, 'big') match_dict[match_field] = data return match_dict
def _match_from_dict(self, dictionary): known_fields = ((field, data) for field, data in dictionary.items() if field in self._match_names) for field_name, data in known_fields: tlv = OxmTLV() tlv.oxm_field = self._match_names[field_name] # set oxm_value if field_name in ('dl_vlan_pcp', 'nw_proto'): tlv.oxm_value = data.to_bytes(1, 'big') elif field_name == 'dl_vlan': vid = data | VlanId.OFPVID_PRESENT tlv.oxm_value = vid.to_bytes(2, 'big') elif field_name in ('dl_src', 'dl_dst'): tlv.oxm_value = HWAddress(data).pack() elif field_name in ('nw_src', 'nw_dst'): tlv.oxm_value = IPAddress(data).pack() elif field_name == 'in_port': tlv.oxm_value = data.to_bytes(4, 'big') else: tlv.oxm_value = data.to_bytes(2, 'big') yield tlv
def generate_flow_mod_message(self, xid, srcIpAddress): match = Match(dl_type=2048, nw_src=IPAddress(srcIpAddress)) message = FlowMod(xid=xid, match=match, command=FlowModCommand.OFPFC_ADD) return message.pack()
def from_of_tlv(cls, tlv): """Return an instance from a pyof OXM TLV.""" ip_address = IPAddress() ip_address.unpack(tlv.oxm_value) ip_str = str(ip_address) return cls(ip_str)
def as_of_tlv(self): """Return a pyof OXM TLV instance.""" value_bytes = IPAddress(self.value).pack() return OxmTLV(oxm_field=self.oxm_field, oxm_value=value_bytes)
class Match(GenericStruct): """Describes a flow entry. Fields to match against flows.""" #: Wildcards fields. wildcards = UBInt32(value=FlowWildCards.OFPFW_ALL, enum_ref=FlowWildCards) #: Input switch port. in_port = UBInt16(0) #: Ethernet source address. (default: '00:00:00:00:00:00') dl_src = HWAddress() #: Ethernet destination address. (default: '00:00:00:00:00:00') dl_dst = HWAddress() #: Input VLAN id. (default: 0) dl_vlan = UBInt16(0) #: Input VLAN priority. (default: 0) dl_vlan_pcp = UBInt8(0) #: Align to 64-bits. pad1 = Pad(1) #: Ethernet frame type. (default: 0) dl_type = UBInt16(0) #: IP ToS (actually DSCP field, 6 bits). (default: 0) nw_tos = UBInt8(0) #: IP protocol or lower 8 bits of ARP opcode. (default: 0) nw_proto = UBInt8(0) #: Align to 64-bits. pad2 = Pad(2) #: IP source address. (default: '0.0.0.0/32') nw_src = IPAddress() #: IP destination address. (default: '0.0.0.0/32') nw_dst = IPAddress() #: TCP/UDP source port. (default: 0) tp_src = UBInt16(0) #: TCP/UDP destination port. (default: 0) tp_dst = UBInt16(0) def __init__(self, **kwargs): """All the constructor parameters below are optional. Args: wildcards (FlowWildCards): Wildcards fields. (Default: OFPFW_ALL) in_port (int): Input switch port. (default: 0) dl_src (HWAddress): Ethernet source address. (default: '00:00:00:00:00:00') dl_dst (HWAddress): Ethernet destination address. (default: '00:00:00:00:00:00') dl_vlan (int): Input VLAN id. (default: 0) dl_vlan_pcp (int): Input VLAN priority. (default: 0) dl_type (int): Ethernet frame type. (default: 0) nw_tos (int): IP ToS (actually DSCP field, 6 bits). (default: 0) nw_proto (int): IP protocol or lower 8 bits of ARP opcode. (default: 0) nw_src (IPAddress): IP source address. (default: '0.0.0.0/32') nw_dst (IPAddress): IP destination address. (default: '0.0.0.0/32') tp_src (int): TCP/UDP source port. (default: 0) tp_dst (int): TCP/UDP destination port. (default: 0) """ super().__init__() [setattr(self, field, value) for field, value in kwargs.items()] def __setattr__(self, name, value): # converts string ip_address to IPAddress if isinstance(getattr(Match, name), IPAddress) and \ not isinstance(value, IPAddress): if isinstance(value, list): value = ".".join(str(x) for x in value) value = IPAddress(value) # convertstring or list of hwaddress to HWAddress if isinstance(getattr(Match, name), HWAddress) and \ not isinstance(value, HWAddress): if isinstance(value, list): values = ["{0:0{1}x}".format(x, 2) for x in value] value = ":".join(values) value = HWAddress(value) super().__setattr__(name, value) self.fill_wildcards(name, value) def unpack(self, buff, offset=0): """Unpack *buff* into this object. Do nothing, since the _length is already defined and it is just a Pad. Keep buff and offset just for compability with other unpack methods. Args: buff: Buffer where data is located. offset (int): Where data stream begins. """ super().unpack(buff, offset) self.wildcards = UBInt32(value=FlowWildCards.OFPFW_ALL, enum_ref=FlowWildCards) self.wildcards.unpack(buff, offset) def fill_wildcards(self, field=None, value=0): """Update wildcards attribute. This method update a wildcards considering the attributes of the current instance. Args: field (str): Name of the updated field. value (GenericType): New value used in the field. """ if field in [None, 'wildcards'] or isinstance(value, Pad): return default_value = getattr(Match, field) if isinstance(default_value, IPAddress): if field is 'nw_dst': self.wildcards |= FlowWildCards.OFPFW_NW_DST_MASK shift = FlowWildCards.OFPFW_NW_DST_SHIFT else: self.wildcards |= FlowWildCards.OFPFW_NW_SRC_MASK shift = FlowWildCards.OFPFW_NW_SRC_SHIFT wildcard = (value.max_prefix - value.netmask) << shift self.wildcards -= wildcard else: wildcard_field = "OFPFW_{}".format(field.upper()) wildcard = getattr(FlowWildCards, wildcard_field) if value == default_value and not (self.wildcards & wildcard) or \ value != default_value and (self.wildcards & wildcard): self.wildcards ^= wildcard
class ARP(GenericStruct): """ARP packet "struct". Contains fields for an ARP packet's header and data. Designed for Ethernet and IPv4 only: needs to have some attributes changed for other HTYPE and PTYPE implementations. Must be encapsulated inside an Ethernet frame. """ htype = UBInt16() ptype = UBInt16() hlen = UBInt8() plen = UBInt8() oper = UBInt16() sha = HWAddress() spa = IPAddress() tha = HWAddress() tpa = IPAddress() def __init__(self, htype=1, ptype=EtherType.IPV4, hlen=6, plen=4, oper=1, sha='00:00:00:00:00:00', spa='0.0.0.0', tha="00:00:00:00:00:00", tpa='0.0.0.0'): """Create an ARP with the parameters below. Args: htype (int): Hardware protocol type. Defaults to 1 for Ethernet. ptype (int): Network protocol type. Defaults to 0x800 for IPv4. hlen (int): Length of the hardware address. Defaults to 6 for MAC addresses. plen (int): Length of the networking protocol address. Defaults to 4 for IPv4 addresses. oper (int): Determines the operation for this ARP packet. Must be 1 for ARP request or 2 for ARP reply. Defaults to 1. sha (str): Sender hardware address. Defaults to '00:00:00:00:00:00'. spa (str): Sender protocol address. Defaults to '0.0.0.0'. tha (str): Target hardware address. Defaults to '00:00:00:00:00:00'. tpa (str): Target protocol address. Defaults to '0.0.0.0'. """ super().__init__() self.htype = htype self.ptype = ptype self.hlen = hlen self.plen = plen self.oper = oper self.sha = sha self.spa = spa self.tha = tha self.tpa = tpa def is_valid(self): """Assure the ARP contains Ethernet and IPv4 information.""" return self.htype == 1 and self.ptype == EtherType.IPV4 def unpack(self, buff, offset=0): """Unpack a binary struct into this object's attributes. Return the values instead of the lib's basic types. Check if the protocols involved are Ethernet and IPv4. Other protocols are currently not supported. Args: buff (bytes): Binary buffer. offset (int): Where to begin unpacking. Raises: :exc:`~.exceptions.UnpackException`: If unpack fails. """ super().unpack(buff, offset) if not self.is_valid(): raise UnpackException("Unsupported protocols in ARP packet")
class IPv4(GenericStruct): """IPv4 packet "struct". Contains all fields of an IP version 4 packet header, plus the upper layer content as binary data. Some of the fields were merged together because of their size being inferior to 8 bits. They are represented as a single class attribute, but pack/unpack methods will take into account the values in individual instance attributes. """ #: _version_ihl (:class:`UBInt8`): IP protocol version + Internet Header #: Length (words) _version_ihl = UBInt8() #: _dscp_ecn (:class:`UBInt8`): Differentiated Services Code Point #: (ToS - Type of Service) + Explicit Congestion Notification _dscp_ecn = UBInt8() #: length (:class:`UBInt16`): IP packet length (bytes) length = UBInt16() #: identification (:class:`UBInt16`): Packet ID - common to all fragments identification = UBInt16() #: _flags_offset (:class:`UBInt16`): Fragmentation flags + fragmentation #: offset _flags_offset = UBInt16() #: ttl (:class:`UBInt8`): Packet time-to-live ttl = UBInt8() #: protocol (:class:`UBInt8`): Upper layer protocol number protocol = UBInt8() #: checksum (:class:`UBInt16`): Header checksum checksum = UBInt16() #: source (:class:`IPAddress`): Source IPv4 address source = IPAddress() #: destination (:class:`IPAddress`): Destination IPv4 address destination = IPAddress() #: options (:class:`BinaryData`): IP Options - up to 320 bits, always #: padded to 32 bits options = BinaryData() #: data (:class:`BinaryData`): Packet data data = BinaryData() def __init__(self, version=4, ihl=5, dscp=0, ecn=0, length=0, identification=0, flags=0, offset=0, ttl=255, protocol=0, checksum=0, source="0.0.0.0", destination="0.0.0.0", options=b'', data=b''): """Create an IPv4 with the parameters below. Args: version (int): IP protocol version. Defaults to 4. ihl (int): Internet Header Length. Default is 5. dscp (int): Differentiated Service Code Point. Defaults to 0. ecn (int): Explicit Congestion Notification. Defaults to 0. length (int): IP packet length in bytes. Defaults to 0. identification (int): Packet Id. Defaults to 0. flags (int): IPv4 Flags. Defults 0. offset (int): IPv4 offset. Defaults to 0. ttl (int): Packet time-to-live. Defaults to 255 protocol (int): Upper layer protocol number. Defaults to 0. checksum (int): Header checksum. Defaults to 0. source (str): Source IPv4 address. Defaults to "0.0.0.0" destination (str): Destination IPv4 address. Defaults to "0.0.0.0" options (bytes): IP options. Defaults to empty bytes. data (bytes): Packet data. Defaults to empty bytes. """ super().__init__() self.version = version self.ihl = ihl self.dscp = dscp self.ecn = ecn self.length = length self.identification = identification self.flags = flags self.offset = offset self.ttl = ttl self.protocol = protocol self.checksum = checksum self.source = source self.destination = destination self.options = options self.data = data def _update_checksum(self): """Update the packet checksum to enable integrity check.""" source_list = [int(octet) for octet in self.source.split(".")] destination_list = [ int(octet) for octet in self.destination.split(".") ] source_upper = (source_list[0] << 8) + source_list[1] source_lower = (source_list[2] << 8) + source_list[3] destination_upper = (destination_list[0] << 8) + destination_list[1] destination_lower = (destination_list[2] << 8) + destination_list[3] block_sum = ((self._version_ihl << 8 | self._dscp_ecn) + self.length + self.identification + self._flags_offset + (self.ttl << 8 | self.protocol) + source_upper + source_lower + destination_upper + destination_lower) while block_sum > 65535: carry = block_sum >> 16 block_sum = (block_sum & 65535) + carry self.checksum = ~block_sum & 65535 def pack(self, value=None): """Pack the struct in a binary representation. Merge some fields to ensure correct packing. Returns: bytes: Binary representation of this instance. """ # Set the correct IHL based on options size if self.options: self.ihl += int(len(self.options) / 4) # Set the correct packet length based on header length and data self.length = int(self.ihl * 4 + len(self.data)) self._version_ihl = self.version << 4 | self.ihl self._dscp_ecn = self.dscp << 2 | self.ecn self._flags_offset = self.flags << 13 | self.offset # Set the checksum field before packing self._update_checksum() return super().pack() def unpack(self, buff, offset=0): """Unpack a binary struct into this object's attributes. Return the values instead of the lib's basic types. Args: buff (bytes): Binary buffer. offset (int): Where to begin unpacking. Raises: :exc:`~.exceptions.UnpackException`: If unpack fails. """ super().unpack(buff, offset) self.version = self._version_ihl.value >> 4 self.ihl = self._version_ihl.value & 15 self.dscp = self._dscp_ecn.value >> 2 self.ecn = self._dscp_ecn.value & 3 self.length = self.length.value self.identification = self.identification.value self.flags = self._flags_offset.value >> 13 self.offset = self._flags_offset.value & 8191 self.ttl = self.ttl.value self.protocol = self.protocol.value self.checksum = self.checksum.value self.source = self.source.value self.destination = self.destination.value if self.ihl > 5: options_size = (self.ihl - 5) * 4 self.data = self.options.value[options_size:] self.options = self.options.value[:options_size] else: self.data = self.options.value self.options = b''
def setupPathList(self, path_table): self.__msg_queue.put(path_table) if __name__ == "__main__": from pyof.foundation.basic_types import IPAddress logger.setLevel("DEBUG") plugin = ControllerPlugin() plugin.start() sw = [ "", "00:00:00:00:00:00:00:01", "00:00:00:00:00:00:00:02", "00:00:00:00:00:00:00:03", "00:00:00:00:00:00:00:04" ] ip1 = IPAddress("10.0.0.1/32").pack() ip2 = IPAddress("10.0.0.2/32").pack() IPTYPE = b'\x08\x00' match1_2 = {"eth_type": IPTYPE, "ip_src": ip1, "ip_dst": ip2} match2_1 = {"eth_type": IPTYPE, "ip_src": ip2, "ip_dst": ip1} path1_2 = [[(sw[1], {1}), (sw[2], {1}), (sw[3], {3})], [(sw[1], {2}), (sw[4], {1}), (sw[3], {3})]] path2_1 = [[(sw[3], {1}), (sw[2], {2}), (sw[1], {3})], [(sw[3], {2}), (sw[4], {2}), (sw[1], {3})]] count = 1 while True: import time a = input("wait input: ") plugin.setupPath(10, match1_2, path1_2[count % 2]) plugin.setupPath(10, match2_1, path2_1[count % 2])
class Match(GenericStruct): """Describes a flow entry. Fields to match against flows.""" #: Wildcards fields. wildcards = UBInt32(value=FlowWildCards.OFPFW_ALL, enum_ref=FlowWildCards) #: Input switch port. in_port = UBInt16(0) #: Ethernet source address. (default: '00:00:00:00:00:00') dl_src = HWAddress() #: Ethernet destination address. (default: '00:00:00:00:00:00') dl_dst = HWAddress() #: Input VLAN id. (default: 0) dl_vlan = UBInt16(0) #: Input VLAN priority. (default: 0) dl_vlan_pcp = UBInt8(0) #: Align to 64-bits. pad1 = Pad(1) #: Ethernet frame type. (default: 0) dl_type = UBInt16(0) #: IP ToS (actually DSCP field, 6 bits). (default: 0) nw_tos = UBInt8(0) #: IP protocol or lower 8 bits of ARP opcode. (default: 0) nw_proto = UBInt8(0) #: Align to 64-bits. pad2 = Pad(2) #: IP source address. (default: '0.0.0.0/0') nw_src = IPAddress('0.0.0.0/0') #: IP destination address. (default: '0.0.0.0/0') nw_dst = IPAddress('0.0.0.0/0') #: TCP/UDP source port. (default: 0) tp_src = UBInt16(0) #: TCP/UDP destination port. (default: 0) tp_dst = UBInt16(0) def __init__(self, **kwargs): """All the constructor parameters below are optional. Args: wildcards (FlowWildCards): Wildcards fields. (Default: OFPFW_ALL) in_port (int): Input switch port. (default: 0) dl_src (HWAddress): Ethernet source address. (default: '00:00:00:00:00:00') dl_dst (HWAddress): Ethernet destination address. (default: '00:00:00:00:00:00') dl_vlan (int): Input VLAN id. (default: 0) dl_vlan_pcp (int): Input VLAN priority. (default: 0) dl_type (int): Ethernet frame type. (default: 0) nw_tos (int): IP ToS (actually DSCP field, 6 bits). (default: 0) nw_proto (int): IP protocol or lower 8 bits of ARP opcode. (default: 0) nw_src (IPAddress): IP source address. (default: '0.0.0.0/0') nw_dst (IPAddress): IP destination address. (default: '0.0.0.0/0') tp_src (int): TCP/UDP source port. (default: 0) tp_dst (int): TCP/UDP destination port. (default: 0) """ super().__init__() for field, value in kwargs.items(): setattr(self, field, value) def __setattr__(self, name, value): # converts string ip_address to IPAddress if isinstance(getattr(Match, name), IPAddress) and \ not isinstance(value, IPAddress): if isinstance(value, list): value = ".".join(str(x) for x in value) value = IPAddress(value) # noqa # convertstring or list of hwaddress to HWAddress elif isinstance(getattr(Match, name), HWAddress) and \ not isinstance(value, HWAddress): if isinstance(value, list): values = ["{0:0{1}x}".format(x, 2) for x in value] value = ":".join(values) value = HWAddress(value) super().__setattr__(name, value) self.fill_wildcards(name, value) def unpack(self, buff, offset=0): """Unpack *buff* into this object. Do nothing, since the _length is already defined and it is just a Pad. Keep buff and offset just for compability with other unpack methods. Args: buff (bytes): Binary buffer. offset (int): Where to begin unpacking. Raises: :exc:`~.exceptions.UnpackException`: If unpack fails. """ super().unpack(buff, offset) self.wildcards = UBInt32(value=FlowWildCards.OFPFW_ALL, enum_ref=FlowWildCards) self.wildcards.unpack(buff, offset) def fill_wildcards(self, field=None, value=0): """Update wildcards attribute. This method update a wildcards considering the attributes of the current instance. Args: field (str): Name of the updated field. value (GenericType): New value used in the field. """ if field in [None, 'wildcards'] or isinstance(value, Pad): return default_value = getattr(Match, field) if isinstance(default_value, IPAddress): if field == 'nw_dst': shift = FlowWildCards.OFPFW_NW_DST_SHIFT base_mask = FlowWildCards.OFPFW_NW_DST_MASK else: shift = FlowWildCards.OFPFW_NW_SRC_SHIFT base_mask = FlowWildCards.OFPFW_NW_SRC_MASK # First we clear the nw_dst/nw_src mask related bits on the current # wildcard by setting 0 on all of them while we keep all other bits # as they are. self.wildcards &= FlowWildCards.OFPFW_ALL ^ base_mask # nw_dst and nw_src wildcard fields have 6 bits each. # "base_mask" is the 'all ones' for those 6 bits. # Once we know the netmask, we can calculate the these 6 bits # wildcard value and reverse them in order to insert them at the # correct position in self.wildcards wildcard = (value.max_prefix - value.netmask) << shift self.wildcards |= wildcard else: wildcard_field = "OFPFW_{}".format(field.upper()) wildcard = getattr(FlowWildCards, wildcard_field) if value == default_value and not (self.wildcards & wildcard) or \ value != default_value and (self.wildcards & wildcard): self.wildcards ^= wildcard