summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorDan Klein <danklein10@gmail.com>2015-10-06 07:28:24 +0300
committerDan Klein <danklein10@gmail.com>2015-10-06 07:28:24 +0300
commit9629c9953516281d4bdaad1ed63d145de336a983 (patch)
tree5ae39833e1e436978911d0d6ffb77cfa265ba8f9 /scripts
parentc7ba20f4f7c4521fdf50238c7e4ccc50f13b248e (diff)
Commiting last night progress
Diffstat (limited to 'scripts')
-rw-r--r--scripts/automation/trex_control_plane/client/trex_stateless_client.py300
-rwxr-xr-xscripts/automation/trex_control_plane/client_utils/packet_builder.py118
2 files changed, 292 insertions, 126 deletions
diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_client.py b/scripts/automation/trex_control_plane/client/trex_stateless_client.py
index 12f6eff6..b7580531 100644
--- a/scripts/automation/trex_control_plane/client/trex_stateless_client.py
+++ b/scripts/automation/trex_control_plane/client/trex_stateless_client.py
@@ -16,135 +16,66 @@ class CTRexStatelessClient(object):
def __init__(self, server="localhost", port=5050, virtual=False):
super(CTRexStatelessClient, self).__init__()
self.tx_link = CTRexStatelessClient.CTxLink(server, port, virtual)
+ self._conn_handler = {}
- def add_stream(self, handler, port_id, stream_id, stream_obj):
- assert isinstance(stream_obj, CTRexStatelessClient.CStream)
- params = {"handler":handler,
+ def owned(func):
+ def wrapper(self, *args, **kwargs ) :
+ if self._conn_handler.get(kwargs.get("port_id")):
+ return func(self, *args, **kwargs)
+ else:
+ raise RuntimeError("The requested method ('{0}') cannot be invoked unless the desired port is owned".
+ format(func.__name__))
+ return wrapper
+
+ def acquire(self, port_id, username, force=False):
+ params = {"port_id": port_id,
+ "user": username,
+ "force": force}
+ self._conn_handler[port_id] = self.transmit("acquire", params)
+ return self._conn_handler
+
+ @owned
+ def release(self, port_id=None):
+ self._conn_handler.pop(port_id)
+ params = {"handler":self._conn_handler.get(port_id),
+ "port_id": port_id}
+ return self.transmit("release", params)
+
+ @owned
+ def add_stream(self, stream_id, stream_obj, port_id=None):
+ assert isinstance(stream_obj, CStream)
+ params = {"handler":self._conn_handler.get(port_id),
"port_id":port_id,
"stream_id":stream_id,
"stream":stream_obj.dump()}
return self.transmit("add_stream", params)
- def transmit(self, method_name, params={}):
- return self.tx_link.transmit(method_name, params)
+ @owned
+ def remove_stream(self, stream_id, port_id=None):
+ params = {"handler":self._conn_handler.get(port_id),
+ "port_id":port_id,
+ "stream_id":stream_id}
+ return self.transmit("remove_stream", params)
+ @owned
+ def get_stream_list(self, port_id=None):
+ params = {"handler":self._conn_handler.get(port_id),
+ "port_id":port_id}
+ return self.transmit("get_stream_list", params)
- # ------ private classes ------ #
- class CStream(object):
- """docstring for CStream"""
- def __init__(self):
- super(CTRexStatelessClient.CStream, self).__init__()
- self.packet = CTRexPktBuilder()
- self.rx_stats = CTRexStatelessClient.CRxStats()
- self.mode = CTRexStatelessClient.CTxMode()
- self.isg
- self._next_stream = -1
- self._self_start
- self._enabled
-
- @property
- def enabled(self):
- return self._enabled
-
- @enabled.setter
- def enabled(self, bool_value):
- self._enabled = bool(bool_value)
-
- @property
- def self_start(self):
- return self._self_start
-
- @self_start.setter
- def self_start(self, bool_value):
- self._self_start = bool(bool_value)
-
- @property
- def next_stream(self):
- return self._next_stream
-
- @next_stream.setter
- def next_stream(self, value):
- self._next_stream = int(bool_value)
-
- def dump(self):
- pass
- return {"enabled":self.enabled,
- "self_start":self.self_start,
- "isg":self.isg,
- "next_stream":self.next_stream,
- "packet":self.packet.dump_pkt(),
- "mode":self.mode.dump(),
- "vm":self.packet.dump_vm_instructions(), # TODO - add this method to packet builder module
- "rx_stats":self.rx_stats.dump()}
-
- class CRxStats(object):
-
- def __init__(self, enabled=False, seq_enabled=False, latency_enabled=False):
- self._rx_dict = {"enabled" : enabled,
- "seq_enabled" : seq_enabled,
- "latency_enabled" : latency_enabled}
-
- @property
- def enabled(self):
- return self._rx_dict.get("enabled")
-
- @enabled.setter
- def enabled(self, bool_value):
- self._rx_dict['enabled'] = bool(bool_value)
-
- @property
- def seq_enabled(self):
- return self._rx_dict.get("seq_enabled")
-
- @seq_enabled.setter
- def seq_enabled(self, bool_value):
- self._rx_dict['seq_enabled'] = bool(bool_value)
-
- @property
- def latency_enabled(self):
- return self._rx_dict.get("latency_enabled")
-
- @latency_enabled.setter
- def latency_enabled(self, bool_value):
- self._rx_dict['latency_enabled'] = bool(bool_value)
-
- def dump(self):
- return {k:v
- for k,v in self._rx_dict.items()
- if v
- }
-
- class CTxMode(object):
- """docstring for CTxMode"""
- def __init__(self, tx_mode, pps):
- super(CTxMode, self).__init__()
- if tx_mode not in ["continuous", "single_burst", "multi_burst"]:
- raise ValueError("Unknown TX mode ('{0}')has been initialized.".format(tx_mode))
- self._tx_mode = tx_mode
- self._fields = {'pps':float(pps)}
- if tx_mode == "single_burst":
- self._fields['total_pkts'] = 0
- elif tx_mode == "multi_burst":
- self._fields['pkts_per_burst'] = 0
- self._fields['ibg'] = 0.0
- self._fields['count'] = 0
- else:
- pass
+ @owned
+ def get_stream(self, stream_id, port_id=None):
+ params = {"handler":self._conn_handler.get(port_id),
+ "port_id":port_id}
+ return self.transmit("get_stream_list", params)
- def set_tx_mode_attr(self, attr, val):
- if attr in self._fields:
- self._fields[attr] = type(self._fields.get(attr))(val)
- else:
- raise ValueError("The provided attribute ('{0}') is not a legal attribute in selected TX mode ('{1}')".
- format(attr, self._tx_mode))
- def dump(self):
- dump = {"type":self._tx_mode}
- dump.update({k:v
- for k, v in self._fields.items()
- })
- return dump
+ def transmit(self, method_name, params={}):
+ return self.tx_link.transmit(method_name, params)
+
+
+ # ------ private classes ------ #
class CTxLink(object):
"""describes the connectivity of the stateless client method"""
def __init__(self, server="localhost", port=5050, virtual=False):
@@ -167,7 +98,140 @@ class CTRexStatelessClient(object):
else:
return self.rpc_link.invoke_rpc_method(method_name, params)
+class CStream(object):
+ """docstring for CStream"""
+ DEFAULTS = {"rx_stats": CRxStats,
+ "mode": CTxMode,
+ "isg": 5.0,
+ "next_stream": -1,
+ "self_start": True,
+ "enabled": True}
+
+ def __init__(self, **kwargs):
+ super(CStream, self).__init__()
+ for k, v in kwargs.items():
+ setattr(self, k, v)
+ # set default values to unset attributes, according to DEFAULTS dict
+ set_keys = set(kwargs.keys())
+ keys_to_set = [x for x in self.DEFAULTS if x not in set_keys]
+ for key in keys_to_set:
+ default = self.DEFAULTS.get(key)
+ if type(default)==type:
+ setattr(self, key, default())
+ else:
+ setattr(self, key, default)
+
+ @property
+ def packet(self):
+ return self._packet
+
+ @packet.setter
+ def packet(self, packet_obj):
+ assert isinstance(packet_obj, CTRexPktBuilder)
+ self._packet = packet_obj
+
+ @property
+ def enabled(self):
+ return self._enabled
+
+ @enabled.setter
+ def enabled(self, bool_value):
+ self._enabled = bool(bool_value)
+
+ @property
+ def self_start(self):
+ return self._self_start
+
+ @self_start.setter
+ def self_start(self, bool_value):
+ self._self_start = bool(bool_value)
+
+ @property
+ def next_stream(self):
+ return self._next_stream
+
+ @next_stream.setter
+ def next_stream(self, value):
+ self._next_stream = int(value)
+
+ def dump(self):
+ pass
+ return {"enabled":self.enabled,
+ "self_start":self.self_start,
+ "isg":self.isg,
+ "next_stream":self.next_stream,
+ "packet":self.packet.dump_pkt(),
+ "mode":self.mode.dump(),
+ "vm":self.packet.get_vm_data(),
+ "rx_stats":self.rx_stats.dump()}
+
+class CRxStats(object):
+
+ def __init__(self, enabled=False, seq_enabled=False, latency_enabled=False):
+ self._rx_dict = {"enabled" : enabled,
+ "seq_enabled" : seq_enabled,
+ "latency_enabled" : latency_enabled}
+
+ @property
+ def enabled(self):
+ return self._rx_dict.get("enabled")
+
+ @enabled.setter
+ def enabled(self, bool_value):
+ self._rx_dict['enabled'] = bool(bool_value)
+
+ @property
+ def seq_enabled(self):
+ return self._rx_dict.get("seq_enabled")
+
+ @seq_enabled.setter
+ def seq_enabled(self, bool_value):
+ self._rx_dict['seq_enabled'] = bool(bool_value)
+
+ @property
+ def latency_enabled(self):
+ return self._rx_dict.get("latency_enabled")
+
+ @latency_enabled.setter
+ def latency_enabled(self, bool_value):
+ self._rx_dict['latency_enabled'] = bool(bool_value)
+
+ def dump(self):
+ return {k:v
+ for k,v in self._rx_dict.items()
+ if v
+ }
+
+class CTxMode(object):
+ """docstring for CTxMode"""
+ def __init__(self, tx_mode, pps):
+ super(CTxMode, self).__init__()
+ if tx_mode not in ["continuous", "single_burst", "multi_burst"]:
+ raise ValueError("Unknown TX mode ('{0}')has been initialized.".format(tx_mode))
+ self._tx_mode = tx_mode
+ self._fields = {'pps':float(pps)}
+ if tx_mode == "single_burst":
+ self._fields['total_pkts'] = 0
+ elif tx_mode == "multi_burst":
+ self._fields['pkts_per_burst'] = 0
+ self._fields['ibg'] = 0.0
+ self._fields['count'] = 0
+ else:
+ pass
+ def set_tx_mode_attr(self, attr, val):
+ if attr in self._fields:
+ self._fields[attr] = type(self._fields.get(attr))(val)
+ else:
+ raise ValueError("The provided attribute ('{0}') is not a legal attribute in selected TX mode ('{1}')".
+ format(attr, self._tx_mode))
+
+ def dump(self):
+ dump = {"type":self._tx_mode}
+ dump.update({k:v
+ for k, v in self._fields.items()
+ })
+ return dump
if __name__ == "__main__":
diff --git a/scripts/automation/trex_control_plane/client_utils/packet_builder.py b/scripts/automation/trex_control_plane/client_utils/packet_builder.py
index 30aede0b..0505d7f1 100755
--- a/scripts/automation/trex_control_plane/client_utils/packet_builder.py
+++ b/scripts/automation/trex_control_plane/client_utils/packet_builder.py
@@ -64,6 +64,36 @@ class CTRexPktBuilder(object):
return
def set_ip_layer_addr(self, layer_name, attr, ip_addr, ip_type="ipv4"):
+ """
+ This method sets the IP address fields of an IP header (source or destination, for both IPv4 and IPv6)
+ using a human readable addressing representation.
+
+ :parameters:
+ layer_name: str
+ a string representing the name of the layer.
+ Example: "l3_ip", etc.
+
+ attr: str
+ a string representation of the sub-field to be set:
+ + "src" for source
+ + "dst" for destination
+
+ ip_addr: str
+ a string representation of the IP address to be set.
+ Example: "10.0.0.1" for IPv4, or "5001::DB8:1:3333:1:1" for IPv6
+
+ ip_type : str
+ a string representation of the IP version to be set:
+ + "ipv4" for IPv4
+ + "ipv6" for IPv6
+
+ Default: **ipv4**
+
+ :raises:
+ + :exc:`ValueError`, in case the desired layer_name is not an IP layer
+ + :exc:`KeyError`, in case the desired layer_name does not exists.
+
+ """
try:
layer = self._pkt_by_hdr[layer_name.lower()]
if not (isinstance(layer, dpkt.ip.IP) or isinstance(layer, dpkt.ip6.IP6)):
@@ -75,9 +105,54 @@ class CTRexPktBuilder(object):
raise KeyError("Specified layer '{0}' doesn't exist on packet.".format(layer_name))
def set_ipv6_layer_addr(self, layer_name, attr, ip_addr):
+ """
+ This method sets the IPv6 address fields of an IP header (source or destination)
+
+ :parameters:
+ layer_name: str
+ a string representing the name of the layer.
+ Example: "l3_ip", etc.
+
+ attr: str
+ a string representation of the sub-field to be set:
+ + "src" for source
+ + "dst" for destination
+
+ ip_addr: str
+ a string representation of the IP address to be set.
+ Example: "5001::DB8:1:3333:1:1"
+
+ :raises:
+ + :exc:`ValueError`, in case the desired layer_name is not an IPv6 layer
+ + :exc:`KeyError`, in case the desired layer_name does not exists.
+
+ """
self.set_ip_layer_addr(layer_name, attr, ip_addr, ip_type="ipv6")
def set_eth_layer_addr(self, layer_name, attr, mac_addr):
+ """
+ This method sets the ethernet address fields of an Ethernet header (source or destination)
+ using a human readable addressing representation.
+
+ :parameters:
+ layer_name: str
+ a string representing the name of the layer.
+ Example: "l2", etc.
+
+ attr: str
+ a string representation of the sub-field to be set:
+ + "src" for source
+ + "dst" for destination
+
+ mac_addr: str
+ a string representation of the MAC address to be set.
+ Example: "00:de:34:ef:2e:f4".
+
+ :raises:
+ + :exc:`ValueError`, in case the desired layer_name is not an Ethernet layer
+ + :exc:`KeyError`, in case the desired layer_name does not exists.
+
+ """
try:
layer = self._pkt_by_hdr[layer_name.lower()]
if not isinstance(layer, dpkt.ethernet.Ethernet):
@@ -136,6 +211,29 @@ class CTRexPktBuilder(object):
raise KeyError("Specified layer '{0}' doesn't exist on packet.".format(layer_name))
def set_layer_bit_attr(self, layer_name, attr, val):
+ """
+ This method enables the user to set the value of a field smaller that 1 Byte in size.
+ This method isn't used to set full-sized fields value (>= 1 byte).
+ Use :func:`packet_builder.CTRexPktBuilder.set_layer_attr` instead.
+
+ :parameters:
+ layer_name: str
+ a string representing the name of the layer.
+ Example: "l2", "l4_tcp", etc.
+
+ attr : str
+ a string representing the attribute to be set on desired layer
+
+ val : int
+ value of attribute.
+ This value will be set "ontop" of the existing value using bitwise "OR" operation.
+ .. tip:: It is very useful to use dpkt constants to define the values of these fields.
+
+ :raises:
+ + :exc:`KeyError`, in case of missing layer (the desired layer isn't part of packet)
+ + :exc:`ValueError`, in case invalid attribute to the specified layer.
+
+ """
return self.set_layer_attr(layer_name, attr, val, True)
def set_pkt_payload(self, payload):
@@ -241,7 +339,7 @@ class CTRexPktBuilder(object):
# VM access methods
def set_vm_ip_range(self, ip_layer_name, ip_field,
ip_init, ip_start, ip_end, add_value,
- operation, is_big_endian=False, val_size = 4,
+ operation, is_big_endian=False, val_size=4,
ip_type="ipv4", add_checksum_inst=True):
if ip_field not in ["src", "dst"]:
raise ValueError("set_vm_ip_range only available for source ('src') or destination ('dst') ip addresses")
@@ -275,7 +373,7 @@ class CTRexPktBuilder(object):
def set_vm_eth_range(self, eth_layer_name, eth_field,
mac_init, mac_start, mac_end, add_value,
- operation, val_size = 4, is_big_endian=False):
+ operation, val_size=4, is_big_endian=False):
if eth_field not in ["src", "dst"]:
raise ValueError("set_vm_eth_range only available for source ('src') or destination ('dst') eth addresses")
self._verify_layer_prop(eth_layer_name, dpkt.ethernet.Ethernet)
@@ -299,15 +397,20 @@ class CTRexPktBuilder(object):
init_val, start_val, end_val, add_val, val_size,
operation, is_big_endian=False, range_name="",
add_checksum_inst=True):
+ # verify input validity for init/start/end values
+ for val in [init_val, start_val, end_val]:
+ if not isinstance(val, int):
+ raise ValueError("init/start/end values are expected integers, but received type '{0}'".
+ format(type(val)))
self._verify_layer_prop(layer_name=layer_name, field_name=hdr_field)
if not range_name:
range_name = "{layer}__{field}".format(layer=layer_name, field=hdr_field)
trim_size = val_size*2
hdr_offset, field_abs_offset = self._calc_offset(layer_name, hdr_field, val_size)
self.vm.add_flow_man_inst(range_name, size=val_size, operation=operation,
- init_value=init_val,
- min_value=start_val,
- max_value=end_val)
+ init_value=str(init_val),
+ min_value=str(start_val),
+ max_value=str(end_val))
self.vm.add_write_flow_inst(range_name, field_abs_offset)
self.vm.set_vm_off_inst_field(range_name, "add_value", add_val)
self.vm.set_vm_off_inst_field(range_name, "is_big_endian", is_big_endian)
@@ -315,7 +418,7 @@ class CTRexPktBuilder(object):
self.vm.add_fix_checksum_inst(self._pkt_by_hdr.get(layer_name), hdr_offset)
def get_vm_data(self):
- pass
+ return self.vm.dump()
def dump_pkt(self):
"""
@@ -369,8 +472,7 @@ class CTRexPktBuilder(object):
except IOError:
raise IOError(2, "The provided path could not be accessed")
- # ----- useful shortcut methods ----- #
- def gen_dns_packet(self):
+ def export_pkt(self, file_path, link_pcap=False, pcap_name=None, pcap_ts=None):
pass
# ----- internal methods ----- #