API Reference¶
Before getting into all the details, it is important to note that all the below API features can be imported through the module switchyard.lib.userlib
.
This is a wrapper module to facilitate easy import of the various modules, functions, classes, and other items needed from the perspective of a user program in Switchyard.
Unless you are concerned about namespace pollution, importing all Switchyard symbols into your program can be done with the following:
from switchyard.lib.userlib import *
Net object reference¶
The net object is used for sending and receiving packets on network interfaces/ports. The API documentation below is for a base class that defines the various methods on a net object; there are two classes that derive from this base class which help to implement Switchyard’s test mode and Switchyard’s live network mode.
- class switchyard.llnetbase.LLNetBase(name=None)[source]¶
Base class for the low-level networking library in Python. “net” objects are constructed from classes derived from this class.
An object of this class is passed into the main function of a user’s Switchyard program. Using methods on this object, a user can send/receive packets and query the device for what interfaces are available and how they are configured.
- interface_by_ipaddr(ipaddr)[source]¶
Given an IP address, return the interface that ‘owns’ this address
- interface_by_macaddr(macaddr)[source]¶
Given a MAC address, return the interface that ‘owns’ this address
- interfaces()[source]¶
Return a list of interfaces incident on this node/router. Each item in the list is an Interface object, each of which includes name, ethaddr, ipaddr, and netmask attributes.
- abstract recv_packet(timeout=None)[source]¶
Receive a packet on any port/interface. If a non-None timeout is given, the method will block for up to timeout seconds. If no packet is available, the exception NoPackets will be raised. If the Switchyard framework is being shut down, the Shutdown exception will be raised. If a packet is available, the ReceivedPacket named tuple (timestamp, input_port, packet) will be returned.
- abstract send_packet(output_port, packet)[source]¶
Send a packet out the given output port/interface. Returns None.
- property testmode¶
Returns True if running in test mode and False if running in live/real mode.
Interface and InterfaceType reference¶
The InterfaceType
enumeration is referred to by the Interface
class, which encapsulates information about a network interface/port. The InterfaceType
defines some basic options for types of interfaces:
- class switchyard.lib.interface.InterfaceType(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]¶
- Unknown=1
- Loopback=2
- Wired=3
- Wireless=4
The Interface
class is used to encapsulate information about a network interface:
- class switchyard.lib.interface.Interface(name, ethaddr, ifnum=None, iftype=InterfaceType.Unknown)[source]¶
- assign_ipaddr(value)[source]¶
Assign a new IP address (v4 or v6) to this interface. Address can either be a IPv4Interface object, IPv6Interface object, or string in the form ‘addr/prefix’ (i.e., something that ipaddress.ip_interface will parse).
- property ethaddr¶
Get the Ethernet address associated with the interface
- property ifnum¶
Get the interface number (integer) associated with the interface
- property iftype¶
Get the type of the interface as a value from the InterfaceType enumeration.
- property ipaddrs¶
Get the IP addresses associated with the interface, as a (frozen) set of ipaddress.IPv4Interface or ipaddress.IPv6Interface objects
- property name¶
Get the name of the interface
Ethernet and IP addresses¶
Switchyard uses the built-in ipaddress
module to the extent possible. Refer to the Python library documentation for details on the IPv4Address
class and related classes. As noted in the source code, the EthAddr
class based on source code from the POX Openflow controller.
- class switchyard.lib.address.EthAddr(addr=None)[source]¶
An Ethernet (MAC) address type.
- isBridgeFiltered()[source]¶
Checks if address is an IEEE 802.1D MAC Bridge Filtered MAC Group Address
This range is 01-80-C2-00-00-00 to 01-80-C2-00-00-0F. MAC frames that have a destination MAC address within this range are not relayed by bridges conforming to IEEE 802.1D
- property is_bridge_filtered¶
- property is_global¶
- property is_local¶
- property is_multicast¶
- property packed¶
- property raw¶
Returns the address as a 6-long bytes object.
There are two enumeration classes that hold special values for the IPv4 and IPv6 address families. Note that since these classes derive from enum
, you must use name
to access the name attribute and value
to access the value (address) attribute.
- class switchyard.lib.address.SpecialIPv4Addr(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]¶
- IP_ANY = ip_address("0.0.0.0")
- IP_BROADCAST = ip_address("255.255.255.255")
- class switchyard.lib.address.SpecialIPv6Addr(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]¶
- UNDEFINED = ip_address('::')
- ALL_NODES_LINK_LOCAL = ip_address('ff02::1')
- ALL_ROUTERS_LINK_LOCAL = ip_address('ff02::2')
- ALL_NODES_INTERFACE_LOCAL = ip_address('ff01::1')
- ALL_ROUTERS_INTERFACE_LOCAL = ip_address('ff01::2')
Packet parsing and construction reference¶
- class switchyard.lib.packet.Packet(raw=None, first_header=None)[source]¶
Base class for packet headers.
The Packet class acts as a container for packet headers. The + and += operators are defined for use with the Packet class to add on headers (to the end of the packet). Indexing can also be done with Packet objects to access individual header objects. Indexes may be integers (from 0 up to, but not including, the number of packet headers), or indexes may also be packet header class names. Exceptions are raised for invaliding indexing of either kind.
The optional raw parameter can accept a bytes object, which assumed to be a serialized packet to be reconstructed. The optional parameter first_header indicates the first header of the packet to be reconstructed, which defaults to Ethernet.
>>> p = Packet() >>> p += Ethernet() >>> p[0] <switchyard.lib.packet.ethernet.Ethernet object at 0x10632bb08> >>> p[Ethernet] <switchyard.lib.packet.ethernet.Ethernet object at 0x10632bb08> >>> str(p) 'Ethernet 00:00:00:00:00:00->00:00:00:00:00:00 IP' >>> str(p[0]) 'Ethernet 00:00:00:00:00:00->00:00:00:00:00:00 IP' >>> str(p[Ethernet]) 'Ethernet 00:00:00:00:00:00->00:00:00:00:00:00 IP' >>>
- add_header(ph)[source]¶
Add a PacketHeaderBase derived class object, or a raw bytes object as the next “header” item in this packet. Note that ‘header’ may be a slight misnomer since the last portion of a packet is considered application payload and not a header per se.
- static from_bytes(raw, first_header)[source]¶
Create a new packet by parsing the contents of a bytestring
- get_header(hdrclass, returnval=None)[source]¶
Return the first header object that is of class hdrclass, or None if the header class isn’t found.
- get_header_by_name(hdrname)[source]¶
Return the header object that has the given (string) header class name. Returns None if no such header exists.
- get_header_index(hdrclass, startidx=0)[source]¶
Return the first index of the header class hdrclass starting at startidx (default=0), or -1 if the header class isn’t found in the list of headers.
- has_header(hdrclass)[source]¶
Return True if the packet has a header of the given hdrclass, False otherwise.
- insert_header(idx, ph)[source]¶
Insert a PacketHeaderBase-derived object at index idx the list of headers. Any headers previously in the Packet from index idx:len(ph) are shifted to make room for the new packet.
To delete/remove a header, you can use the del
operator as if the packet
object is a Python list:
>>> del p[0] # delete/remove first header in packet
>>>
You can assign new header objects to a packet by integer index, but not by packet header class index:
>>> p[0] = Ethernet() # assign a new Ethernet header to index 0
>>>
Header classes¶
In this section, detailed documentation for all packet header classes is given. For each header class, there are three common instance methods that may be useful and which are not documented below for clarity. They are defined in the base class PacketHeaderBase
. Note that any new packet header classes that derive from PacketHeaderBase
must implement these three methods.
- class switchyard.lib.packet.PacketHeaderBase(**kwargs)[source]¶
Base class for packet headers.
- abstract from_bytes(raw)[source]¶
Reconstruct the attributes of a header given the bytes object named raw. The method returns any bytes that are not used to reconstruct a header. An exception (typically a ValueError) is raised if there is some kind of problem deserializing the bytes object into packet header attributes.
There are also three common class methods that are used when creating a new packet header class (see Creating new packet header types).
- class switchyard.lib.packet.PacketHeaderBase(**kwargs)[source]¶
Base class for packet headers.
- classmethod add_next_header_class(attr, hdrcls)[source]¶
Add a new mapping between a next header type value and a Python class that implements that header type.
Ethernet header¶
- class switchyard.lib.packet.Ethernet(**kwargs)[source]¶
Represents an Ethernet header with fields src (source Ethernet address), dst (destination Ethernet address), and ethertype (type of header to come in the packet after the Ethernet header). All valid ethertypes are defined below.
- property dst¶
- property ethertype¶
- property src¶
- class switchyard.lib.packet.common.EtherType(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]¶
- IP = 0x0800
- IPv4 = 0x0800
- ARP = 0x0806
- x8021Q = 0x8100
- IPv6 = 0x86dd
- SLOW = 0x8809
- MPLS = 0x8847
- x8021AD = 0x88a8
- LLDP = 0x88cc
- x8021AH = 0x88e7
- IEEE8023 = 0x05dc
The EtherType class is derived from the built-in Python Enumerated class type. Note that some values start with ‘x’ since they must start with an alphabetic character to be valid in the enum.
By default, the Ethernet header addresses are all zeroes (“00:00:00:00:00:00”), and the ethertype is IPv4. Here is an example of creating an Ethernet header and setting the header fields to non-default values:
>>> e = Ethernet()
>>> e.src = "de:ad:00:00:be:ef"
>>> e.dst = "ff:ff:ff:ff:ff:ff"
>>> e.ethertype = EtherType.ARP
As with all packet header classes, keyword parameters can be used to initialize header attributes:
>>> e = Ethernet(src="de:ad:00:00:be:ef", dst="ff:ff:ff:ff:ff:ff", ethertype=EtherType.ARP)
ARP (address resolution protocol) header¶
- class switchyard.lib.packet.Arp(**kwargs)[source]¶
- property hardwaretype¶
- property operation¶
- property protocoltype¶
- property senderhwaddr¶
- property senderprotoaddr¶
- property targethwaddr¶
- property targetprotoaddr¶
- class switchyard.lib.packet.common.ArpOperation(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]¶
- Request = 1
- Reply = 2
The Arp
class is used for constructing ARP (address resolution protocol)
requests and replies. The hardwaretype
property defaults to Ethernet
,
so you don’t need to set that when an Arp
object is instantiated. The
operation can be set using the enumerated type ArpOperation
, as indicated
above. The remaining fields hold either EthAddr
or IPv4Address
objects,
and can be initialized using string representations of Ethernet or IPv4
addresses as appropriate. Below is an example of creating an ARP request.
You can assume in the example that the senders Ethernet and IPv4
addresses are srchw
and srcip
, respectively. You can also
assume that the IPv4 address for which we are requesting the Ethernet
address is targetip
.
ether = Ethernet()
ether.src = srchw
ether.dst = 'ff:ff:ff:ff:ff:ff'
ether.ethertype = EtherType.ARP
arp = Arp(operation=ArpOperation.Request,
senderhwaddr=srchw,
senderprotoaddr=srcip,
targethwaddr='ff:ff:ff:ff:ff:ff',
targetprotoaddr=targetip)
arppacket = ether + arp
IP version 4 header¶
- class switchyard.lib.packet.IPv4(**kwargs)[source]¶
Represents an IP version 4 packet header. All properties relate to specific fields in the header and can be inspected and/or modified.
Note that the field named “hl” (“h-ell”) stands for “header length”. It is the size of the header in 4-octet quantities. It is a read-only property (cannot be set).
Note also that some IPv4 header option classes are available in Switchyard, but are currently undocumented.
- property dscp¶
- property dst¶
- property ecn¶
- property flags¶
- property fragment_offset¶
- property hl¶
- property ipid¶
- property options¶
- property protocol¶
- property src¶
- property tos¶
- property total_length¶
- property ttl¶
- class switchyard.lib.packet.common.IPProtocol(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]¶
- ICMP = 1
- TCP = 6
- UDP = 17
The IPProtocol class derives from the Python 3-builtin Enumerated class type. There are other protocol numbers defined. See
switchyard.lib.packet.common
for all defined values.
A just-constructed IPv4 header defaults to having all zeroes for the source and destination addresses (‘0.0.0.0’) and the protocol number defaults to ICMP. An example of creating an IPv4 header and setting various fields is shown below:
>>> ip = IPv4()
>>> ip.src = '10.0.1.1'
>>> ip.dst = '10.0.2.42'
>>> ip.protocol = IPProtocol.UDP
>>> ip.ttl = 64
IP version 6 header¶
- class switchyard.lib.packet.IPv6(**kwargs)[source]¶
- property dst¶
- property flowlabel¶
- property hoplimit¶
- property nextheader¶
- property src¶
- property trafficclass¶
- property ttl¶
Represents an IP version 6 packet header. All properties relate to specific fields in the header and can be inspected and/or modified.
As with IPv4, header values generally default to zeroes. The nextheader
for IPv6 defaults to ICMPv6.
>>> ip6 = IPv6()
>>> print(ip6)
IPv6 ::->:: ICMPv6
>>> ip6.src = 'fe80::1'
>>> ip6.dst = 'fe80::2'
>>> print(ip6)
IPv6 fe80::1->fe80::2 ICMPv6
UDP (user datagram protocol) header¶
- class switchyard.lib.packet.UDP(**kwargs)[source]¶
The UDP header contains just source and destination port fields.
- property dst¶
- property length¶
- property src¶
To construct a packet that includes an UDP header as well as some application data, the same pattern of packet construction can be followed:
>>> p = Ethernet() + IPv4(protocol=IPProtocol.UDP) + UDP()
>>> p[UDP].src = 4444
>>> p[UDP].dst = 5555
>>> p += b'These are some application data bytes'
>>> print (p)
Ethernet 00:00:00:00:00:00->00:00:00:00:00:00 IP | IPv4 0.0.0.0->0.0.0.0 UDP | UDP 4444->5555 | RawPacketContents (37 bytes) b'These are '...
>>>
Note that we didn’t set the IP addresses or Ethernet addresses above, but
did set the IP protocol to correctly match the next header (UDP). Adding
a payload to a packet is as simple as tacking on a Python bytes
object.
You can also construct a RawPacketContents
header, which is just a
packet header class that wraps a set of raw bytes.
TCP (transmission control protocol) header¶
- class switchyard.lib.packet.TCP(**kwargs)[source]¶
Represents a TCP header. Includes properties to access/modify TCP header fields.
- property ACK¶
- property CWR¶
- property ECE¶
- property FIN¶
- property NS¶
- property PSH¶
- property RST¶
- property SYN¶
- property URG¶
- property ack¶
- property dst¶
- property flags¶
- property flagstr¶
- property offset¶
- property options¶
- property seq¶
- property src¶
- property urgent_pointer¶
- property window¶
Setting TCP header flags can be done by assigning 1 to any of the mnemonic flag properties:
>>> t = TCP()
>>> t.SYN = 1
To check whether a flag has been set, you can simply inspect the the flag value:
>>> if t.SYN:
>>> ...
ICMP (Internet control message protocol) header (v4)¶
- class switchyard.lib.packet.ICMP(**kwargs)[source]¶
A mother class for all ICMP message types. It holds a reference to another object that contains the specific ICMP data (icmpdata), given a particular ICMP type. Just setting the icmptype causes the data object to change (the change happens automatically when you set the icmptype). The icmpcode field will also change, but it only changes to some valid code given the new icmptype.
Represents an ICMP packet header for IPv4.
- property icmpcode¶
- property icmpdata¶
- property icmptype¶
- class switchyard.lib.packet.common.ICMPType(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]¶
- EchoReply = 0
- DestinationUnreachable = 3
- SourceQuench = 4
- Redirect = 5
- EchoRequest = 8
- TimeExceeded = 11
The icmptype and icmpcode header fields determine the value stored in the icmpdata property. When the icmptype is set to a new value, the icmpdata field is automatically set to the correct object.
>>> i = ICMP()
>>> print (i)
ICMP EchoRequest 0 0 (0 data bytes)
>>> i.icmptype = ICMPType.TimeExceeded
>>> print (i)
ICMP TimeExceeded:TTLExpired 0 bytes of raw payload (b'') OrigDgramLen: 0
>>> i.icmpcode
<ICMPCodeTimeExceeded.TTLExpired: 0>
>>> i.icmpdata
<switchyard.lib.packet.icmp.ICMPTimeExceeded object at 0x10d3a3308>
Notice above that when the icmptype changes, other contents in the ICMP header object change appropriately.
To access and/or modify the payload (i.e., data) that comes after the ICMP header, use icmpdata.data
. This object is a raw bytes object and can be accessed and or set. For example, with many ICMP error messages, up to the first 28 bytes of the “dead” packet should be included, starting with the IPv4 header. To do that, you must set the icmpdata.data
attribute with the byte-level representation of the IP header data you want to include, as follows:
>>> i.icmpdata.data
b''
>>> i.icmpdata.data = pkt.to_bytes()[:28]
>>> i.icmpdata.origdgramlen = len(pkt)
>>> print (i)
ICMP TimeExceeded:TTLExpired 28 bytes of raw payload (b'E\x00\x00\x14\x00\x00\x00\x00\x00\x01') OrigDgramLen: 42
>>>
In the above code segment, pkt
should be a Packet object that just contains the IPv4 header and any subsequent headers and data. It must not include an Ethernet header. If you need to strip an Ethernet header, you can get its index (pkt.get_header_index(Ethernet)
), then remove the header by index (del pkt[index]
).
Notice that above, the to_bytes
method returns the byte-level representation of the IP header we’re including as the payload. The to_bytes
method can be called on any packet header, or on an packet object (in which case all packet headers will be byte-serialized).
To set the icmpcode, a dictionary called ICMPTypeCodeMap
is defined
in switchyard.lib.packet
. Keys in the dictionary are of type ICMPType
, and values for each key is another enumerated type indicating the valid
codes for the given type.
>>> from switchyard.lib.packet import *
>>> ICMPTypeCodeMap[ICMPType.DestinationUnreachable]
<enum 'DestinationUnreachable'>
Just getting the dictionary value isn’t particularly helpful, but if you coerce the enum to a list, you can see all valid values:
>>> list(ICMPTypeCodeMap[ICMPType.DestinationUnreachable])
[ <DestinationUnreachable.ProtocolUnreachable: 2>,
<DestinationUnreachable.SourceHostIsolated: 8>,
<DestinationUnreachable.FragmentationRequiredDFSet: 4>,
<DestinationUnreachable.HostUnreachable: 1>,
<DestinationUnreachable.DestinationNetworkUnknown: 6>,
<DestinationUnreachable.NetworkUnreachableForTOS: 11>,
<DestinationUnreachable.HostAdministrativelyProhibited: 10>,
<DestinationUnreachable.DestinationHostUnknown: 7>,
<DestinationUnreachable.HostPrecedenceViolation: 14>,
<DestinationUnreachable.PrecedenceCutoffInEffect: 15>,
<DestinationUnreachable.NetworkAdministrativelyProhibited: 9>,
<DestinationUnreachable.NetworkUnreachable: 0>,
<DestinationUnreachable.SourceRouteFailed: 5>,
<DestinationUnreachable.PortUnreachable: 3>,
<DestinationUnreachable.CommunicationAdministrativelyProhibited: 13>,
<DestinationUnreachable.HostUnreachableForTOS: 12> ]
Another example, but with the much simpler EchoRequest:
>>> list(ICMPTypeCodeMap[ICMPType.EchoRequest])
[<EchoRequest.EchoRequest: 0>]
If you try to set the icmpcode to an invalid value, an exception will be raised:
>>> i = ICMP()
>>> i.icmptype = ICMPType.DestinationUnreachable
>>> i.icmpcode = 44
Traceback (most recent call last):
...
>>>
You can either (validly) set the code using an integer, or a valid enumerated type value:
>>> i.icmpcode = 2
>>> print(i)
ICMP DestinationUnreachable:ProtocolUnreachable 0 bytes of raw payload (b'') NextHopMTU: 0
>>> i.icmpcode = ICMPTypeCodeMap[i.icmptype].HostUnreachable
>>> print (i)
ICMP DestinationUnreachable:HostUnreachable 0 bytes of raw payload (b'') NextHopMTU: 0
Below are shown the ICMP data classes, as well as any properties that can be inspected and/or modified on them.
- class switchyard.lib.packet.ICMPEchoReply[source]¶
- property data¶
- property identifier¶
- property sequence¶
- class switchyard.lib.packet.ICMPDestinationUnreachable[source]¶
- property data¶
- property nexthopmtu¶
- property origdgramlen¶
ICMP (Internet control message protocol) header (v6)¶
- class switchyard.lib.packet.ICMPv6(**kwargs)[source]¶
Represents an ICMPv6 packet header.
- property icmp6code¶
- property icmp6type¶
Additional ICMPv6 headers to support the Neighbor Discovery Protocol, [RFC4861](http://tools.ietf.org/html/rfc4861) are also available in Switchyard:
ICMPv6NeighborSolicitation
ICMPv6NeighborAdvertisement
ICMPv6RedirectMessage
ICMPv6 Headers to support router advertisement and solicitation are also available:
ICMPv6RouterSolicitation
ICMPv6RouterAdvertisement
To create an ICMPv6 packet an instance of type ICMPv6
can be created. You will want (and need) to set its icmptype
appropriately, too. For example:
>>> icmpv6 = ICMPv6()
>>> icmpv6.icmptype = ICMPv6Type.RedirectMessage
>>> print(icmpv6)
ICMPv6 RedirectMessage ICMPv6RedirectMessage Target: :: Destination: ::
>>>
>>> ## OR Directly when initializing the ICMPv6 header
>>> # icmpv6 = ICMPv6(icmptype=ICMPv6Type.RedirectMessage)
>>>
>>> r = ICMPv6RedirectMessage()
>>> # or r = icmpv6.icmpdata if already assigned to ICMPv6 object
>>> r.targetaddr = IPv6Address( "::0" )
>>> r.options.append( ICMPv6OptionRedirectedHeader( header=p ))
>>> r.options.append( ICMPv6OptionTargetLinkLayerAddress( address="00:00:00:00:00:00" ))
>>>
>>> icmpv6.icmpdata = r
>>> print(icmpv6)
ICMPv6 RedirectMessage ICMPv6RedirectMessage Target: :: Destination: :: | ICMPv6OptionList (ICMPv6OptionRedirectedHeader redirected packet (6 bytes), ICMPv6OptionTargetLinkLayerAddress 00:00:00:00:00:00)
It’s possible, too, to construct the ICMPv6 packet in one go:
>>> p = Ethernet(ethertype=EtherType.IPv6, src='58:ac:78:93:da:00', dst='33:33:00:00:00:01') + \
IPv6(nextheader=IPProtocol.ICMPv6, hoplimit=255, src='fe80::1', dst='ff02::1') + \
ICMPv6(icmptype=ICMPv6Type.RouterSolicitation,
icmpdata=ICMPv6RouterSolicitation(options=(
ICMPv6OptionSourceLinkLayerAddress('00:50:56:af:97:68'),
ICMPv6OptionMTU(1250),
ICMPv6OptionPrefixInformation(prefix='fd00::/64'))))
There are several ICMPv6 options which can be attached to these:
ICMPv6OptionSourceLinkLayerAddress
ICMPv6OptionTargetLinkLayerAddress
ICMPv6OptionRedirectedHeader
ICMPv6OptionMTU
ICMPv6OptionPrefixInformation
- class switchyard.lib.packet.ICMPv6NeighborSolicitation(**kwargs)[source]¶
- property data¶
- property options¶
- property targetaddr¶
- class switchyard.lib.packet.ICMPv6NeighborAdvertisement(**kwargs)[source]¶
- property data¶
- property o¶
- property options¶
- property r¶
- property s¶
- property targetaddr¶
- class switchyard.lib.packet.ICMPv6RedirectMessage(**kwargs)[source]¶
- property data¶
- property destaddr¶
- property options¶
- property targetaddr¶
- class switchyard.lib.packet.ICMPv6RouterAdvertisement(**kwargs)[source]¶
- property curhoplimit¶
- property data¶
- property h¶
- property m¶
- property o¶
- property options¶
- property p¶
- property reachable_time¶
- property retrans_timer¶
- property router_lifetime¶
Test scenario creation¶
- class switchyard.lib.testing.TestScenario(name)[source]¶
Test scenario definition. Given a list of packetio event objects, generates input events and tests/verifies output events.
- add_interface(interface_name, macaddr, *ipaddrs, **kwargs)[source]¶
Add an interface to the test scenario.
(str, str/EthAddr, ipaddrs (str/IPAddr), kwargs) -> None
- expect(event, description)[source]¶
Add a new event and description to the expected set of events to occur for this test scenario.
(Event object, str) -> None
- property name¶
- class switchyard.lib.testing.PacketInputEvent(device, packet, display=None, copyfromlastout=None)[source]¶
Test event that models a packet arriving at a router/switch (e.g., a packet that we generate).
- class switchyard.lib.testing.PacketInputTimeoutEvent(timeout)[source]¶
Test event that models a timeout when trying to receive a packet. No packet arrives, so the switchy app should handle a NoPackets exception and continue
Application-layer¶
Two static methods on the ApplicationLayer
class are used to send messages up a socket application and to receive messages from socket applications.
- class switchyard.lib.socket.ApplicationLayer[source]¶
- static recv_from_app(timeout=None)[source]¶
Called by a network stack implementer to receive application-layer data for sending on to a remote location.
Can optionally take a timeout value. If no data are available, raises NoPackets exception.
Returns a 2-tuple: flowaddr and data. The flowaddr consists of 5 items: protocol, localaddr, localport, remoteaddr, remoteport.
- static send_to_app(proto, local_addr, remote_addr, data)[source]¶
Called by a network stack implementer to push application-layer data “up” from the stack.
Arguments are protocol number, local_addr (a 2-tuple of IP address and port), remote_addr (a 2-tuple of IP address and port), and the message.
Returns True if a socket was found to which to deliver the message, and False otherwise. When False is returned, a log warning is also emitted.
Switchyard’s socket emulation module is intended to follow, relatively closely, the methods and attributes available in the built-in socket
module.
- class switchyard.lib.socket.socket(family, socktype, proto=0, fileno=0)[source]¶
A socket object, emulated by Switchyard.
- bind(address)[source]¶
Alter the local address with which this socket is associated. The address parameter is a 2-tuple consisting of an IP address and port number.
NB: this method fails and returns -1 if the requested port to bind to is already in use but does not check that the address is valid.
- connect(address)[source]¶
Set the remote address (IP address and port) with which this socket is used to communicate.
- connect_ex(address)[source]¶
Set the remote address (IP address and port) with which this socket is used to communicate.
- property family¶
Get the address family of the socket.
- getpeername()[source]¶
Return a 2-tuple containing the remote IP address and port associated with the socket, if any.
- getsockname()[source]¶
Return a 2-tuple containing the local IP address and port associated with the socket.
- property proto¶
Get the protocol of the socket.
- recv(buffersize, flags=0)[source]¶
Receive data on the socket. The buffersize and flags arguments are currently ignored. Only returns the data.
- recvfrom(buffersize, flags=0)[source]¶
Receive data on the socket. The buffersize and flags arguments are currently ignored. Returns the data and an address tuple (IP address and port) of the remote host.
- send(data, flags=0)[source]¶
Send data on the socket. A call to connect() must have been previously made for this call to succeed. Flags is currently ignored.
- sendto(data, *args)[source]¶
Send data on the socket. Accepts the same parameters as the built-in socket sendto: data[, flags], address where address is a 2-tuple of IP address and port. Any flags are currently ignored.
- property timeout¶
Obtain the currently set timeout value.
- property type¶
Get the type of the socket.