summaryrefslogtreecommitdiffstats
path: root/scripts/automation/trex_control_plane/stl/services/scapy_server/scapy_service.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/automation/trex_control_plane/stl/services/scapy_server/scapy_service.py')
-rwxr-xr-xscripts/automation/trex_control_plane/stl/services/scapy_server/scapy_service.py209
1 files changed, 205 insertions, 4 deletions
diff --git a/scripts/automation/trex_control_plane/stl/services/scapy_server/scapy_service.py b/scripts/automation/trex_control_plane/stl/services/scapy_server/scapy_service.py
index 8d99fe92..e5f1b20c 100755
--- a/scripts/automation/trex_control_plane/stl/services/scapy_server/scapy_service.py
+++ b/scripts/automation/trex_control_plane/stl/services/scapy_server/scapy_service.py
@@ -1,17 +1,20 @@
import os
import sys
+
stl_pathname = os.path.abspath(os.path.join(os.pardir, os.pardir))
sys.path.append(stl_pathname)
from trex_stl_lib.api import *
+import trex_stl_lib.trex_stl_packet_builder_scapy
import tempfile
import hashlib
import base64
import numbers
import random
-import inspect
+from inspect import getdoc
import json
+import re
from pprint import pprint
# add some layers as an example
@@ -121,6 +124,45 @@ class Scapy_service_api():
"""
pass
+ def build_pkt_ex(self, client_v_handler, pkt_model_descriptor, extra_options):
+ """ build_pkt_ex(self,client_v_handler,pkt_model_descriptor, extra_options) -> Dictionary (of Offsets,Show2 and Buffer)
+ Performs calculations on the given packet and returns results for that packet.
+
+ Parameters
+ ----------
+ pkt_descriptor - An array of dictionaries describing a network packet
+ extra_options - A dictionary of extra options required for building packet
+
+ Returns
+ -------
+ - The packets offsets: each field in every layer is mapped inside the Offsets Dictionary
+ - The Show2: A description of each field and its value in every layer of the packet
+ - The Buffer: The Hexdump of packet encoded in base64
+
+ Raises
+ ------
+ will raise an exception when the Scapy string format is illegal, contains syntax error, contains non-supported
+ protocl, etc.
+ """
+ pass
+
+ def load_instruction_parameter_values(self, client_v_handler, pkt_model_descriptor, vm_instructions_model, parameter_id):
+ """ load_instruction_parameter_values(self,client_v_handler,pkt_model_descriptor, vm_instructions_model, parameter_id) -> Dictionary (of possible parameter values)
+ Returns possible valies for given pararameter id depends on current pkt structure and vm_instructions
+ model.
+
+ Parameters
+ ----------
+ pkt_descriptor - An array of dictionaries describing a network packet
+ vm_instructions_model - A dictionary of extra options required for building packet
+ parameter_id - A string of parameter id
+
+ Returns
+ -------
+ Possible parameter values map.
+
+ """
+ pass
def get_tree(self,client_v_handler):
""" get_tree(self) -> Dictionary describing an example of hierarchy in layers
@@ -372,7 +414,15 @@ class Scapy_service(Scapy_service_api):
self.version_minor = '01'
self.server_v_hashed = self._generate_version_hash(self.version_major,self.version_minor)
self.protocol_definitions = {} # protocolId -> prococol definition overrides data
+ self.field_engine_supported_protocols = {}
+ self.instruction_parameter_meta_definitions = []
+ self.field_engine_parameter_meta_definitions = []
+ self.field_engine_templates_definitions = []
+ self.field_engine_instructions_meta = []
+ self.field_engine_instruction_expressions = []
self._load_definitions_from_json()
+ self._load_field_engine_meta_from_json()
+ self._vm_instructions = dict([m for m in inspect.getmembers(trex_stl_lib.trex_stl_packet_builder_scapy, inspect.isclass) if m[1].__module__ == 'trex_stl_lib.trex_stl_packet_builder_scapy'])
def _load_definitions_from_json(self):
# load protocol definitions from a json file
@@ -382,6 +432,27 @@ class Scapy_service(Scapy_service_api):
for protocol in protocols:
self.protocol_definitions[ protocol['id'] ] = protocol
+ def _load_field_engine_meta_from_json(self):
+ # load protocol definitions from a json file
+ self.instruction_parameter_meta_definitions = []
+ self.field_engine_supported_protocols = {}
+ self.field_engine_parameter_meta_definitions = []
+ self.field_engine_templates_definitions = []
+ with open('field_engine.json', 'r') as f:
+ metas = json.load(f)
+ self.instruction_parameter_meta_definitions = metas["instruction_params_meta"]
+ self.field_engine_instructions_meta = metas["instructions"]
+ self._append_intructions_help()
+ self.field_engine_supported_protocols = metas["supported_protocols"]
+ self.field_engine_parameter_meta_definitions = metas["global_params_meta"]
+ self.field_engine_templates_definitions = metas["templates"]
+
+
+ def _append_intructions_help(self):
+ for instruction_meta in self.field_engine_instructions_meta:
+ clazz = eval(instruction_meta['id'])
+ instruction_meta['help'] = base64.b64encode(getdoc(clazz.__init__)).decode('ascii')
+
def _all_protocol_structs(self):
old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()
@@ -708,6 +779,134 @@ class Scapy_service(Scapy_service_api):
pkt = self._packet_model_to_scapy_packet(pkt_model_descriptor)
return self._pkt_data(pkt)
+
+ def build_pkt_ex(self, client_v_handler, pkt_model_descriptor, extra_options):
+ res = self.build_pkt(client_v_handler, pkt_model_descriptor)
+ pkt = self._packet_model_to_scapy_packet(pkt_model_descriptor)
+
+ field_engine = {}
+ field_engine['instructions'] = []
+ field_engine['error'] = None
+ try:
+ field_engine['instructions'] = self._generate_vm_instructions(pkt, extra_options['field_engine'])
+ except AssertionError as e:
+ field_engine['error'] = e.message
+ except CTRexPacketBuildException as e:
+ field_engine['error'] = e.message
+
+ field_engine['vm_instructions_expressions'] = self.field_engine_instruction_expressions
+ res['field_engine'] = field_engine
+ return res
+
+ def load_instruction_parameter_values(self, client_v_handler, pkt_model_descriptor, vm_instructions_model, parameter_id):
+
+ given_protocol_ids = [str(proto['id']) for proto in pkt_model_descriptor]
+
+ values = {}
+ if parameter_id == "name":
+ values = self._curent_pkt_protocol_fields(given_protocol_ids, "_")
+
+ if parameter_id == "fv_name":
+ values = self._existed_flow_var_names(vm_instructions_model['field_engine']['instructions'])
+
+ if parameter_id == "pkt_offset":
+ values = self._curent_pkt_protocol_fields(given_protocol_ids, ".")
+
+ if parameter_id == "offset":
+ for ip_idx in range(given_protocol_ids.count("IP")):
+ value = "IP:{0}".format(ip_idx)
+ values[value] = value
+
+ return {"map": values}
+
+ def _existed_flow_var_names(self, instructions):
+ return dict((instruction['parameters']['name'], instruction['parameters']['name']) for instruction in instructions if self._nameParamterExist(instruction))
+
+ def _nameParamterExist(self, instruction):
+ try:
+ instruction['parameters']['name']
+ return True
+ except KeyError:
+ return False
+
+ def _curent_pkt_protocol_fields(self, given_protocol_ids, delimiter):
+ given_protocol_classes = [c for c in Packet.__subclasses__() if c.__name__ in given_protocol_ids]
+ protocol_fields = {}
+ for protocol_class in given_protocol_classes:
+ protocol_name = protocol_class.__name__
+ protocol_count = given_protocol_ids.count(protocol_name)
+ for field_desc in protocol_class.fields_desc:
+ if delimiter == '.' and protocol_count > 1:
+ for idx in range(protocol_count):
+ formatted_name = "{0}:{1}{2}{3}".format(protocol_name, idx, delimiter, field_desc.name)
+ protocol_fields[formatted_name] = formatted_name
+ else:
+ formatted_name = "{0}{1}{2}".format(protocol_name, delimiter, field_desc.name)
+ protocol_fields[formatted_name] = formatted_name
+
+ return protocol_fields
+
+ def _generate_vm_instructions(self, pkt, field_engine_model_descriptor):
+ self.field_engine_instruction_expressions = []
+ instructions = []
+ instructions_def = field_engine_model_descriptor['instructions']
+ for instruction_def in instructions_def:
+ instruction_id = instruction_def['id']
+ instruction_class = self._vm_instructions[instruction_id]
+ parameters = {k: self._sanitize_value(k, v) for (k, v) in instruction_def['parameters'].iteritems()}
+ instructions.append(instruction_class(**parameters))
+
+ fe_parameters = field_engine_model_descriptor['global_parameters']
+
+ cache_size = None
+ if "cache_size" in fe_parameters:
+ assert self._is_int(fe_parameters['cache_size']), 'Cache size must be a number'
+ cache_size = int(fe_parameters['cache_size'])
+
+
+ pkt_builder = STLPktBuilder(pkt=pkt, vm=STLScVmRaw(instructions, cache_size=cache_size))
+ pkt_builder.compile()
+ return pkt_builder.get_vm_data()
+
+ def _sanitize_value(self, param_id, val):
+ if param_id == "pkt_offset":
+ if self._is_int(val):
+ return int(val)
+ elif val == "Ether.src":
+ return 0
+ elif val == "Ether.dst":
+ return 6
+ elif val == "Ether.type":
+ return 12
+ else:
+ if val == "None" or val == "none":
+ return None
+ if val == "true":
+ return True
+ elif val == "false":
+ return False
+ elif re.match("[0-9a-f]{2}([-:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", str(val.lower())):
+ return int(str(val).replace(":", ""), 16)
+
+ if self._is_int(val):
+ return int(val)
+
+ str_val = str(val)
+ return int(str_val, 16) if str_val.startswith("0x") else str_val
+
+ def _get_instruction_parameter_meta(self, param_id):
+ for meta in self.instruction_parameter_meta_definitions:
+ if meta['id'] == param_id:
+ return meta
+ raise Scapy_Exception("Unable to get meta for {0}" % param_id)
+
+ def _is_int(self, val):
+ try:
+ int(val)
+ return True
+ except ValueError:
+ return False
+
# @deprecated. to be removed
def get_all(self,client_v_handler):
if not (self._verify_version_handler(client_v_handler)):
@@ -796,7 +995,11 @@ class Scapy_service(Scapy_service_api):
"name": protoDef.get('name') or pkt_class.name,
"fields": self._get_fields_definition(pkt_class, protoDef.get('fields') or [])
})
- res = {"protocols": protocols}
+ res = {"protocols": protocols,
+ "feInstructionParameters": self.instruction_parameter_meta_definitions,
+ "feInstructions": self.field_engine_instructions_meta,
+ "feParameters": self.field_engine_parameter_meta_definitions,
+ "feTemplates": self.field_engine_templates_definitions}
return res
def get_payload_classes(self,client_v_handler, pkt_model_descriptor):
@@ -889,8 +1092,6 @@ class Scapy_service(Scapy_service_api):
pcap_bin = tmpPcap.read()
return bytes_to_b64(pcap_bin)
-
-
#---------------------------------------------------------------------------