Exemple #1
0
    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)
Exemple #2
0
def _get_ports():
    return [
        PhyPort(port_no=65534,
                hw_addr=HWAddress('0e:d3:98:a5:30:47'),
                name='s1',
                config=PortConfig.OFPPC_PORT_DOWN,
                state=PortState.OFPPS_LINK_DOWN,
                curr=0,
                advertised=0,
                supported=0,
                peer=0),
        PhyPort(port_no=1,
                hw_addr=HWAddress('0a:54:cf:fc:4e:6d'),
                name='s1-eth1',
                config=0,
                state=PortState.OFPPS_STP_LISTEN,
                curr=0x000000c0,
                advertised=0,
                supported=0,
                peer=0),
        PhyPort(port_no=2,
                hw_addr=HWAddress('f6:b6:ab:cc:f8:4f'),
                name='s1-eth2',
                config=0,
                state=PortState.OFPPS_STP_LISTEN,
                curr=0x000000c0,
                advertised=0,
                supported=0,
                peer=0)
    ]
Exemple #3
0
class Ethernet(GenericStruct):
    destination = HWAddress()
    source = HWAddress()
    type = UBInt16()
    data = BinaryData()

    def __init__(self, destination=None, source=None, type=None, data=b''):
        super().__init__()
        self.destination = destination
        self.source = source
        self.type = type
        self.data = data

    def get_hash(self):
        return hash(self.pack())
class PortMod(GenericMessage):
    """Implement messages to modify the physical port behavior."""

    header = Header(message_type=Type.OFPT_PORT_MOD)
    port_no = UBInt32()
    pad = Pad(4)
    hw_addr = HWAddress()
    pad2 = Pad(2)
    config = UBInt32(enum_ref=PortConfig)
    mask = UBInt32(enum_ref=PortConfig)
    advertise = UBInt32(enum_ref=PortFeatures)
    #: Pad to 64-bits.
    pad3 = Pad(4)

    def __init__(self, xid=None, port_no=None, hw_addr=None, config=None,
                 mask=None, advertise=None):
        """The constructor just assings parameters to object attributes.

        Args:
            xid (int): OpenFlow xid to the header.
            port_no (int): Physical port number.
            hw_addr (HWAddress): The hardware address is not configurable.
                This is used to sanity-check the request,
                so it must be the same as returned in an ofp_phy_port struct.
            config (PortConfig): Bitmap of OFPPC_* flags
            mask (PortConfig): Bitmap of OFPPC_* flags to be changed
            advertise (PortFeatures): Bitmap of OFPPF_*. Zero all bits to
                prevent any action taking place.
        """
        super().__init__(xid)
        self.port_no = port_no
        self.hw_addr = hw_addr
        self.config = config
        self.mask = mask
        self.advertise = advertise
 def addPort(self, port_no=0, hw_addr="", port_name="", port_config=0, port_state=PortState.OFPPS_STP_LISTEN, port_curr=0, port_advertised=0, port_supported=0, port_peer=0):
   if(port_no == 0):
     port_no = randint(30000,65534)
   if(hw_addr == ""):
     hw_addr = sdnpwn.generateRandomMacAddress(self.switch_vendor_ouid)
   if(port_name == ""):
     port_name = "OF Port " + str(randint(1,10000))
   
   initQueueID = randint(30000,65534)
                     
   port = PhyPort(port_no=port_no,
                  hw_addr=HWAddress(hw_addr),
                  name=port_name,
                  #config=PortConfig.OFPC_PORT_DOWN,
                  #state=PortState.OFPPS_LINK_DOWN,
                  config=port_config,
                  state=port_state,
                  curr=port_curr,
                  advertised=port_advertised,
                  supported=port_supported,
                  peer=port_peer)
   self.switch_ports.append(port)
   self.switch_features["ports"] = self.switch_ports
   self.switch_stats["port"][str(port_no)] = PortStats(port_no=port_no, rx_packets=0, tx_packets=0, rx_bytes=0, tx_bytes=0,
                                                    rx_dropped=0, tx_dropped=0, rx_errors=0, tx_errors=0, rx_frame_err=0, 
                                                    rx_over_err=0, rx_crc_err=0, collisions=0)
   
   self.switch_stats["queue"][str(port_no) + ":" + str(initQueueID)] = QueueStats(port_no=port_no, queue_id=initQueueID, tx_bytes=0, tx_packets=0, tx_errors=0)
class ActionDLAddr(ActionHeader):
    """Action structure for :attr:`ActionType.OFPAT_SET_DL_SRC` or _DST."""

    dl_addr_type = UBInt16(enum_ref=ActionType)
    length = UBInt16(16)
    dl_addr = HWAddress()
    #: Pad for bit alignment.
    pad = Pad(6)

    def __init__(self, dl_addr_type=None, dl_addr=None):
        """The following constructor parameters are optional.

        Args:
            dl_addr_type (ActionType): :attr:`~ActionType.OFPAT_SET_DL_SRC` or
                :attr:`~ActionType.OFPAT_SET_DL_DST`.
            dl_addr (:class:`~.HWAddress`): Ethernet address.
                Defaults to None.
        """
        super().__init__()
        self.dl_addr_type = dl_addr_type
        self.dl_addr = dl_addr

    def allowed_types():
       """Return the Allowed Action Type

       Returns:
           action_types (list): list of allowed types
       """
       return [ActionType.OFPAT_SET_DL_SRC, ActionType.OFPAT_SET_DL_DST]
class PhyPort(GenericStruct):
    """Description of a physical port.

    The port_no field is a value the datapath associates with a physical port.
    The hw_addr field typically is the MAC address for the port;
    :data:`.OFP_ETH_ALEN` is 6. The name field is a
    null-terminated string containing a human-readable name for the interface.
    The value of :data:`.OFP_MAX_PORT_NAME_LEN` is 16.

    :attr:`curr`, :attr:`advertised`, :attr:`supported` and :attr:`peer` are
    bitmaps of :class:`PortFeatures` enum values that describe features. If
    unsupported or unavailable, set all bits to zero.
    """

    port_no = UBInt16()
    hw_addr = HWAddress()
    name = Char(length=OFP_MAX_PORT_NAME_LEN)
    config = UBInt32(enum_ref=PortConfig)
    state = UBInt32(enum_ref=PortState)
    curr = UBInt32(enum_ref=PortFeatures)
    advertised = UBInt32(enum_ref=PortFeatures)
    supported = UBInt32(enum_ref=PortFeatures)
    peer = UBInt32(enum_ref=PortFeatures)

    def __init__(self,
                 port_no=None,
                 hw_addr=None,
                 name=None,
                 config=None,
                 state=None,
                 curr=None,
                 advertised=None,
                 supported=None,
                 peer=None):
        """The constructor takes the optional parameters below.

        Args:
            port_no (int): Port number.
            hw_addr (HWAddress): Hardware address.
            name(str): Null-terminated name.
            config (PortConfig): Bitmap of OFPPC* flags.
            state (PortState): Bitmap of OFPPS* flags.
            curr (PortFeatures): Current features.
            advertised (PortFeatures): Features being advertised by the port.
            supported (PortFeatures): Features supported by the port.
            peer (PortFeatures): Features advertised by peer.
        """
        super().__init__()
        self.port_no = port_no
        self.hw_addr = hw_addr
        self.name = name
        self.config = config
        self.state = state
        self.curr = curr
        self.advertised = advertised
        self.supported = supported
        self.peer = peer
 def setUp(self):
     """Basic setup for test."""
     self.message = PhyPort()
     self.message.port_no = 1
     self.message.hw_addr = HWAddress('9a:da:11:8a:f4:0c')
     self.message.name = 's1-eth1'
     self.message.state = PortState.OFPPS_STP_LISTEN
     self.message.curr = (PortFeatures.OFPPF_10GB_FD
                          | PortFeatures.OFPPF_COPPER)
Exemple #9
0
 def from_of_tlv(cls, tlv):
     """Return an instance from a pyof OXM TLV."""
     hw_address = HWAddress()
     hw_address.unpack(tlv.oxm_value)
     addr_str = str(hw_address)
     value = addr_str
     if tlv.oxm_hasmask:
         hw_mask = HWAddress()
         hw_mask.unpack(tlv.oxm_value[6:])
         mask_str = str(hw_mask)
         value = f'{addr_str}/{mask_str}'
     return cls(value)
class Ethernet(GenericStruct):
    """Ethernet struct."""

    destination = HWAddress()
    source = HWAddress()
    type = UBInt16()
    data = BinaryData()

    def __init__(self, destination=None, source=None, eth_type=None, data=b''):
        """Create an instance and set its attributes."""
        super().__init__()
        self.destination = destination
        self.source = source
        self.type = eth_type
        self.data = data

    def get_hash(self):
        """Return a hash that identifies this instance."""
        return hash(self.pack())
Exemple #11
0
 def as_of_tlv(self):
     """Return a pyof OXM TLV instance."""
     if '/' in self.value:
         value, mask = self.value.split('/')
         mask = mask.upper()
         if mask == 'FF:FF:FF:FF:FF:FF':
             mask = None
             oxm_hasmask = False
         else:
             oxm_hasmask = True
     else:
         value = self.value
         mask = None
         oxm_hasmask = False
     value_bytes = HWAddress(value).pack()
     if mask:
         value_bytes += HWAddress(mask).pack()
     return OxmTLV(oxm_field=self.oxm_field,
                   oxm_hasmask=oxm_hasmask,
                   oxm_value=value_bytes)
Exemple #12
0
def _new_portstatus():
    """Crate new PortStatus and PhyPort instances."""
    desc_name = 's1-eth1'
    desc = PhyPort(port_no=1,
                   hw_addr=HWAddress('9a:da:11:8a:f4:0c'),
                   name=desc_name,
                   state=PortState.OFPPS_STP_LISTEN,
                   curr=PortFeatures.OFPPF_10GB_FD | PortFeatures.OFPPF_COPPER)
    return PortStatus(xid=0,
                      reason=PortReason.OFPPR_MODIFY,
                      desc=desc)
def _new_portstatus():
    """Crate new PortStatus and PhyPort instances."""
    desc_name = 'X' * OFP_MAX_PORT_NAME_LEN
    desc = PhyPort(port_no=2,
                   hw_addr=HWAddress('0a:0a:12:12:10:10'),
                   name=desc_name,
                   config=PortConfig.OFPPC_NO_STP,
                   state=PortState.OFPPS_STP_FORWARD,
                   curr=PortFeatures.OFPPF_10GB_FD,
                   advertised=PortFeatures.OFPPF_PAUSE,
                   supported=PortFeatures.OFPPF_AUTONEG,
                   peer=PortFeatures.OFPPF_AUTONEG)
    return PortStatus(xid=1, reason=PortReason.OFPPR_ADD, desc=desc)
def _get_body():
    """Return the body used by MultipartReply message."""
    port1 = Port(port_no=PortNo.OFPP_LOCAL,
                 hw_addr=HWAddress('5a:ee:a5:a0:62:4f'),
                 name='s1',
                 config=PortConfig.OFPPC_PORT_DOWN,
                 state=PortState.OFPPS_LINK_DOWN,
                 curr=0,
                 advertised=0,
                 supported=0,
                 peer=0,
                 curr_speed=0,
                 max_speed=0)
    port2 = Port(port_no=1,
                 hw_addr=HWAddress('4e:bf:ca:27:8e:ca'),
                 name='s1-eth1',
                 config=0,
                 state=PortState.OFPPS_LIVE,
                 curr=PortFeatures.OFPPF_10GB_FD | PortFeatures.OFPPF_COPPER,
                 advertised=0,
                 supported=0,
                 peer=0,
                 curr_speed=10000000,
                 max_speed=0)
    port3 = Port(port_no=2,
                 hw_addr=HWAddress('26:1f:b9:5e:3c:c7'),
                 name='s1-eth2',
                 config=0,
                 state=PortState.OFPPS_LIVE,
                 curr=PortFeatures.OFPPF_10GB_FD | PortFeatures.OFPPF_COPPER,
                 advertised=0,
                 supported=0,
                 peer=0,
                 curr_speed=10000000,
                 max_speed=0)
    lop = ListOfPorts([port1, port2, port3])
    return lop
def _new_portstatus():
    """Crate new PortStatus and Port instances."""
    desc_name = 's1-eth1'
    desc = Port(port_no=1,
                hw_addr=HWAddress('62:43:e5:db:35:0a'),
                name=desc_name,
                config=0,
                state=PortState.OFPPS_LIVE,
                curr=PortFeatures.OFPPF_10GB_FD | PortFeatures.OFPPF_COPPER,
                advertised=0,
                supported=0,
                peer=0,
                curr_speed=10000000,
                max_speed=0)
    return PortStatus(xid=0, reason=PortReason.OFPPR_MODIFY, desc=desc)
Exemple #16
0
class PortMod(GenericMessage):
    """Implement messages to modify the physical port behavior."""

    header = Header(message_type=Type.OFPT_PORT_MOD)

    port_no = UBInt32()
    pad = Pad(4)
    #: The hardware address is not configurable. This is used to
    #: sanity-check the request, so it must be the same as returned in an port struct.
    hw_addr = HWAddress()
    #: Pad to 64 bits.
    pad2 = Pad(2)
    #: Bitmap of OFPPC_* flags.
    config = UBInt32(enum_ref=PortConfig)
    #: Bitmap of OFPPC_* flags to be changed.
    mask = UBInt32(enum_ref=PortConfig)
    #: Port mod property list - 0 or more properties
    properties = FixedTypeList(pyof_class=PortModPropHeader)

    def __init__(self,
                 xid=None,
                 port_no=None,
                 hw_addr=None,
                 config=None,
                 mask=None,
                 properties=FixedTypeList(pyof_class=PortModPropHeader)):
        """Create a PortMod with the optional parameters below.

        Args:
            xid (int): OpenFlow xid to the header.
            port_no (int): Physical port number.
            hw_addr (HWAddress): The hardware address is not configurable.
                This is used to sanity-check the request,
                so it must be the same as returned in an ofp_phy_port struct.
            config (~pyof.v0x05.common.port.PortConfig):
                Bitmap of OFPPC_* flags
            mask (~pyof.v0x05.common.port.PortConfig):
                Bitmap of OFPPC_* flags to be changed
            properties (FixedTypeList(pyof_class=PortModPropHeader)):
                Port mod property list - 0 or more properties
        """
        super().__init__(xid)
        self.port_no = port_no
        self.hw_addr = hw_addr
        self.config = config
        self.mask = mask
        self.properties = properties
Exemple #17
0
    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)
Exemple #18
0
 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
Exemple #19
0
class ActionDLAddr(ActionHeader):
    """Action structure for :attr:`ActionType.OFPAT_SET_DL_SRC` or _DST."""

    dl_addr = HWAddress()
    #: Pad for bit alignment.
    pad = Pad(6)

    _allowed_types = (ActionType.OFPAT_SET_DL_SRC, ActionType.OFPAT_SET_DL_DST)

    def __init__(self, action_type=None, dl_addr=None):
        """Create an ActionDLAddr with the optional parameters below.

        Args:
            action_type (:class:`~pyof.v0x01.common.action.ActionType`):
                :attr:`~ActionType.OFPAT_SET_DL_SRC` or
                :attr:`~ActionType.OFPAT_SET_DL_DST`.
            dl_addr (:class:`~.HWAddress`): Ethernet address.
                Defaults to None.
        """
        super().__init__(action_type, length=16)
        self.dl_addr = dl_addr
Exemple #20
0
class PortMod(GenericMessage):
    """Implement messages to modify the physical port behavior."""

    header = Header(message_type=Type.OFPT_PORT_MOD)
    port_no = UBInt16()
    hw_addr = HWAddress()
    config = UBInt32(enum_ref=PortConfig)
    mask = UBInt32(enum_ref=PortConfig)
    advertise = UBInt32(enum_ref=PortFeatures)
    #: Pad to 64-bits.
    pad = Pad(4)

    def __init__(self,
                 xid=None,
                 port_no=None,
                 hw_addr=None,
                 config=None,
                 mask=None,
                 advertise=None):
        """Create a PortMod with the optional parameters below.

        Args:
            xid (int): OpenFlow xid to the header.
            port_no (int): Physical port number.
            hw_addr (HWAddress): The hardware address is not configurable.
                This is used to sanity-check the request,
                so it must be the same as returned in an ofp_phy_port struct.
            config (~pyof.v0x01.common.phy_port.PortConfig):
                Bitmap of OFPPC_* flags
            mask (~pyof.v0x01.common.phy_port.PortConfig):
                Bitmap of OFPPC_* flags to be changed
            advertise (~pyof.v0x01.common.phy_port.PortFeatures):
                Bitmap of "ofp_port_features"s
        """
        super().__init__(xid)
        self.port_no = port_no
        self.hw_addr = hw_addr
        self.config = config
        self.mask = mask
        self.advertise = advertise
Exemple #21
0
 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
Exemple #22
0
class Ethernet(GenericStruct):
    """Ethernet "struct".

    Objects of this class represents an ethernet packet. It contains the
    'Ethernet header', composed by destination (MAC), source (MAC), type
    (EtherType)[1] and the payload of the packet, as binary data.

    This class does not consider the Ethernet 'Preamble' or the 'CRC'.

    There is also a get_hash method, that hashes the binary representation of
    the object so we can have a unique representation of the ethernet packet,
    so we can keep a track of ethernet packets being flooded over the network.

    [1] EtherTypes:
    http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml#ieee-802-numbers-1
    """

    destination = HWAddress()
    source = HWAddress()
    vlan = VLAN()
    ether_type = UBInt16()
    data = BinaryData()

    def __init__(self,
                 destination=None,
                 source=None,
                 vlan=None,
                 ether_type=None,
                 data=b''):
        """Create an instance and set its attributes.

        Args:
            destination (:class:`~pyof.foundation.basic_types.HWAddress`):
                The final destination MAC address.
            source (:class:`~pyof.foundation.basic_types.HWAddress`):
                The source Mac address of the packet.
            ether_type (:class:`~pyof.foundation.basic_types.UBInt16`):
                The EtherType of packet.
            data (:class:`~pyof.foundation.basic_types.BinaryData`):
                The content of the packet in binary format.
        """
        super().__init__()
        self.destination = destination
        self.source = source
        self.vlan = VLAN() if vlan is None else vlan
        self.ether_type = ether_type
        self.data = data

    def get_hash(self):
        """Calculate a hash and returns it.

        Returns:
            int: Integer value that identifies this instance.

        """
        return hash(self.pack())

    def unpack(self, buff, offset=0):
        """Unpack a binary message into this object's attributes.

        Unpack the binary value *buff* and update this object attributes based
        on the results.

        Ethernet headers may have VLAN tags. If no VLAN tag is found, a
        'wildcard VLAN tag' is inserted to assure correct unpacking.

        Args:
            buff (bytes): Binary data package to be unpacked.
            offset (int): Where to begin unpacking.

        Raises:
            UnpackException: If there is a struct unpacking error.

        """
        # Check if the EtherType bytes are actually equal to EtherType.VLAN,
        # indicating that the packet is tagged. If it is not, we insert the
        # equivalent to 'NULL VLAN data' (\x00\x00\x00\x00) to enable the
        # correct unpacking process.
        if buff[12:14] != EtherType.VLAN.to_bytes(2, 'big'):
            buff = buff[0:12] + b'\x00\x00\x00\x00' + buff[12:]

        super().unpack(buff, offset)
Exemple #23
0
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")
Exemple #24
0
class Ethernet(GenericStruct):
    """Ethernet "struct".

    Objects of this class represents an ethernet packet. It contains the
    'Ethernet header', composed by destination (MAC), source (MAC), type
    (EtherType)[1] and the payload of the packet, as binary data.

    This class does not consider the Ethernet 'Preamble' or the 'CRC'.

    There is also a get_hash method, that hashes the binary representation of
    the object so we can have a unique representation of the ethernet packet,
    so we can keep a track of ethernet packets being flooded over the network.

    [1] EtherTypes:
    http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml#ieee-802-numbers-1
    """

    destination = HWAddress()
    source = HWAddress()
    vlans = ListOfVLAN()
    ether_type = UBInt16()
    data = BinaryData()

    def __init__(self,
                 destination=None,
                 source=None,
                 vlans=None,
                 ether_type=None,
                 data=b''):
        """Create an instance and set its attributes.

        Args:
            destination (:class:`~pyof.foundation.basic_types.HWAddress`):
                The final destination MAC address.
            source (:class:`~pyof.foundation.basic_types.HWAddress`):
                The source Mac address of the packet.
            ether_type (:class:`~pyof.foundation.basic_types.UBInt16`):
                The EtherType of packet.
            data (:class:`~pyof.foundation.basic_types.BinaryData`):
                The content of the packet in binary format.
        """
        super().__init__()
        self.destination = destination
        self.source = source
        self.vlans = ListOfVLAN() if vlans is None else vlans
        self.ether_type = ether_type
        self.data = data

    def get_hash(self):
        """Calculate a hash and returns it.

        Returns:
            int: Integer value that identifies this instance.

        """
        return hash(self.pack())

    @staticmethod
    def _get_vlan_length(buff):
        """Return the total length of VLAN tags in a given Ethernet buffer."""
        length = 0
        begin = 12

        while (buff[begin:begin + 2]
               in (EtherType.VLAN.to_bytes(2, 'big'),
                   EtherType.VLAN_QINQ.to_bytes(2, 'big'))):
            length += 4
            begin += 4

        return length

    def unpack(self, buff, offset=0):
        """Unpack a binary message into this object's attributes.

        Unpack the binary value *buff* and update this object attributes based
        on the results.

        Ethernet headers may have VLAN tags. If no VLAN tag is found, a
        'wildcard VLAN tag' is inserted to assure correct unpacking.

        Args:
            buff (bytes): Binary data package to be unpacked.
            offset (int): Where to begin unpacking.

        Raises:
            UnpackException: If there is a struct unpacking error.

        """
        begin = offset

        vlan_length = self._get_vlan_length(buff)

        for attribute_name, class_attribute in self.get_class_attributes():
            attribute = deepcopy(class_attribute)
            if attribute_name == 'vlans':
                attribute.unpack(buff[begin:begin + vlan_length])
            else:
                attribute.unpack(buff, begin)
            setattr(self, attribute_name, attribute)
            begin += attribute.get_size()
Exemple #25
0
class Port(GenericStruct):
    """Description of a port.

    The port_no field uniquely identifies a port within a switch. The hw_addr
    field typically is the MAC address for the port;
    :data:`.OFP_MAX_ETH_ALEN` is 6. The name field is a null-terminated string
    containing a human-readable name for the interface.
    The value of :data:`.OFP_MAX_PORT_NAME_LEN` is 16.

    :attr:`curr`, :attr:`advertised`, :attr:`supported` and :attr:`peer` fields
    indicate link modes (speed and duplexity), link type (copper/fiber) and
    link features (autonegotiation and pause). They are bitmaps of
    :class:`PortFeatures` enum values that describe features.
    Multiple of these flags may be set simultaneously. If none of the port
    speed flags are set, the :attr:`max_speed` or :attr:`curr_speed` are used.
    """

    port_no = UBInt32()
    pad = Pad(4)
    hw_addr = HWAddress()
    pad2 = Pad(2)
    name = Char(length=OFP_MAX_PORT_NAME_LEN)
    config = UBInt32(enum_ref=PortConfig)
    state = UBInt32(enum_ref=PortState)
    curr = UBInt32(enum_ref=PortFeatures)
    advertised = UBInt32(enum_ref=PortFeatures)
    supported = UBInt32(enum_ref=PortFeatures)
    peer = UBInt32(enum_ref=PortFeatures)
    curr_speed = UBInt32()
    max_speed = UBInt32()

    def __init__(self,
                 port_no=None,
                 hw_addr=None,
                 name=None,
                 config=None,
                 state=None,
                 curr=None,
                 advertised=None,
                 supported=None,
                 peer=None,
                 curr_speed=None,
                 max_speed=None):
        """The constructor takes the optional parameters below.

        Args:
            port_no (int): Port number.
            hw_addr (HWAddress): Hardware address.
            name (str): Null-terminated name.
            config (PortConfig): Bitmap of OFPPC* flags.
            state (PortState): Bitmap of OFPPS* flags.
            curr (PortFeatures): Current features.
            advertised (PortFeatures): Features being advertised by the port.
            supported (PortFeatures): Features supported by the port.
            peer (PortFeatures): Features advertised by peer.
            curr_speed (int): Current port bitrate in kbps.
            max_speed (int): Max port bitrate in kbps.
        """
        super().__init__()
        self.port_no = port_no
        self.hw_addr = hw_addr
        self.name = name
        self.config = config
        self.state = state
        self.curr = curr
        self.advertised = advertised
        self.supported = supported
        self.peer = peer
        self.curr_speed = curr_speed
        self.max_speed = max_speed
Exemple #26
0
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
Exemple #27
0
class Port(GenericStruct):
    """Description of a port.

    The port_no field uniquely identifies a port within a switch. The hw_addr
    field typically is the MAC address for the port;
    :data:`.OFP_MAX_ETH_ALEN` is 6. The name field is a null-terminated string
    containing a human-readable name for the interface.
    The value of :data:`.OFP_MAX_PORT_NAME_LEN` is 16.

    :attr:`curr`, :attr:`advertised`, :attr:`supported` and :attr:`peer` fields
    indicate link modes (speed and duplexity), link type (copper/fiber) and
    link features (autonegotiation and pause). They are bitmaps of
    :class:`PortFeatures` enum values that describe features.
    Multiple of these flags may be set simultaneously. If none of the port
    speed flags are set, the :attr:`max_speed` or :attr:`curr_speed` are used.
    """

    port_no = UBInt32()

    length = UBInt16()
    pad = Pad(2)
    hw_addr = HWAddress()
    pad2 = Pad(2)                               # Align to 64 bits
    name = Char(length=OFP_MAX_PORT_NAME_LEN)   # Null terminated
    config = UBInt32(enum_ref=PortConfig)       # Bitmap of OFPPC_* flags
    state = UBInt32(enum_ref=PortState)         # Bitmap of OFPPS_* flags

    #pad = Pad(4)
    #hw_addr = HWAddress()
    #pad2 = Pad(2)

    """
    These are not existed in version 1.4 specifications
    
    curr = UBInt32(enum_ref=PortFeatures)
    advertised = UBInt32(enum_ref=PortFeatures)
    supported = UBInt32(enum_ref=PortFeatures)
    peer = UBInt32(enum_ref=PortFeatures)
    curr_speed = UBInt32()
    max_speed = UBInt32()

    
    """

    def __init__(self, port_no=None, hw_addr=None, name=None, config=None,
                 state=None):
        """Create a Port with the optional parameters below.

        Args:
            port_no (int): Port number.
            hw_addr (HWAddress): Hardware address.
            name (str): Null-terminated name.

            config (~pyof.v0x05.common.port.PortConfig):
                Bitmap of OFPPC* flags.
            state (~pyof.v0x05.common.port.PortState): Bitmap of OFPPS* flags.

        """
        super().__init__()
        self.port_no = port_no
        self.hw_addr = hw_addr
        self.name = name
        self.config = config
        self.state = state
Exemple #28
0
 def as_of_tlv(self):
     """Return a pyof OXM TLV instance."""
     value_bytes = HWAddress(self.value).pack()
     return OxmTLV(oxm_field=self.oxm_field, oxm_value=value_bytes)
Exemple #29
0
 def from_of_tlv(cls, tlv):
     """Return an instance from a pyof OXM TLV."""
     hw_address = HWAddress()
     hw_address.unpack(tlv.oxm_value)
     addr_str = str(hw_address)
     return cls(addr_str)
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