summaryrefslogtreecommitdiffstats
path: root/scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services
diff options
context:
space:
mode:
authorYaroslav Brustinov <ybrustin@cisco.com>2017-01-29 17:14:41 +0200
committerYaroslav Brustinov <ybrustin@cisco.com>2017-02-02 13:42:36 +0200
commit39000f461de6b85877db85488b1cc7f1fad9d359 (patch)
tree8ffa214f3876009bf8778881c63b6c245244ac41 /scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services
parent790059069915a700905f4746b22a9a4a6cadc6ad (diff)
ipv6 scan & ping
Change-Id: I4f8112b4c942d149da5ea3f0ee01ac82d7fe32cc Signed-off-by: Yaroslav Brustinov <ybrustin@cisco.com>
Diffstat (limited to 'scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services')
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_api.py32
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_arp.py8
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_icmp.py6
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_ipv6.py179
4 files changed, 204 insertions, 21 deletions
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_api.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_api.py
index b0904382..d6a620aa 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_api.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_api.py
@@ -9,10 +9,16 @@ class RXServiceAPI(object):
LAYER_MODE_L2 = 1
LAYER_MODE_L3 = 2
- def __init__ (self, port, layer_mode = LAYER_MODE_ANY, queue_size = 100):
+ def __init__(self, port, layer_mode = LAYER_MODE_ANY, queue_size = 100, timeout = None, retries = None, retry_delay = 0.1):
self.port = port
self.queue_size = queue_size
self.layer_mode = layer_mode
+ self.timeout = timeout
+ self.retries = retries
+ if retries is None and timeout is None:
+ self.retries = 0
+ self.retry_delay = retry_delay
+ self.init_ts = time.time()
################### virtual methods ######################
@@ -47,7 +53,7 @@ class RXServiceAPI(object):
"""
raise NotImplementedError()
- def on_pkt_rx (self, pkt, start_ts):
+ def on_pkt_rx(self, pkt, start_ts):
"""
called for each packet arriving on RX
@@ -65,13 +71,10 @@ class RXServiceAPI(object):
raise NotImplementedError()
- def on_timeout_err (self, retries):
+ def on_timeout(self):
"""
called when a timeout occurs
- :parameters:
- retries - how many times was the service retring before failing
-
:returns:
RC object
@@ -80,7 +83,7 @@ class RXServiceAPI(object):
##################### API ######################
- def execute (self, retries = 0):
+ def execute(self, *a, **k):
# sanity check
rc = self.__sanity()
@@ -97,12 +100,12 @@ class RXServiceAPI(object):
try:
# add the stream(s)
- self.port.add_streams(self.generate_request())
+ self.port.add_streams(self.generate_request(*a, **k))
rc = self.port.set_rx_queue(size = self.queue_size)
if not rc:
return rc
- return self.__execute_internal(retries)
+ return self.__execute_internal()
finally:
# best effort restore
@@ -137,20 +140,21 @@ class RXServiceAPI(object):
# main resolve function
- def __execute_internal (self, retries):
+ def __execute_internal (self):
- # retry for 'retries'
+ # retry for 'retries' or until timeout
index = 0
while True:
rc = self.execute_iteration()
if rc is not None:
return rc
- if index >= retries:
- return self.on_timeout_err(retries)
+ if (self.retries is not None and index >= self.retries or
+ self.timeout is not None and time.time() - self.init_ts >= self.timeout):
+ return self.on_timeout()
index += 1
- time.sleep(0.1)
+ time.sleep(self.retry_delay)
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_arp.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_arp.py
index 3cf97045..a82c66d4 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_arp.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_arp.py
@@ -8,8 +8,8 @@ from scapy.layers.l2 import Ether, ARP
class RXServiceARP(RXServiceAPI):
- def __init__ (self, port_id):
- super(RXServiceARP, self).__init__(port_id, layer_mode = RXServiceAPI.LAYER_MODE_L3)
+ def __init__(self, port_id, *a, **k):
+ super(RXServiceARP, self).__init__(port_id, layer_mode = RXServiceAPI.LAYER_MODE_L3, *a, **k)
def get_name (self):
return "ARP"
@@ -49,8 +49,8 @@ class RXServiceARP(RXServiceAPI):
return self.port.ok({'psrc' : arp.psrc, 'hwsrc': arp.hwsrc})
- def on_timeout_err (self, retries):
- return self.port.err('failed to receive ARP response ({0} retries)'.format(retries))
+ def on_timeout(self):
+ return self.port.err('failed to receive ARP response ({0} retries)'.format(self.retries))
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_icmp.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_icmp.py
index ae57b161..612b6a2d 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_icmp.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_icmp.py
@@ -9,9 +9,9 @@ from scapy.layers.inet import IP, ICMP
class RXServiceICMP(RXServiceAPI):
- def __init__ (self, port, ping_ip, pkt_size):
+ def __init__ (self, port, ping_ip, pkt_size, *a, **k):
- super(RXServiceICMP, self).__init__(port, layer_mode = RXServiceAPI.LAYER_MODE_L3)
+ super(RXServiceICMP, self).__init__(port, layer_mode = RXServiceAPI.LAYER_MODE_L3, *a, **k)
self.ping_ip = ping_ip
self.pkt_size = pkt_size
@@ -78,6 +78,6 @@ class RXServiceICMP(RXServiceAPI):
# return the str of a timeout err
- def on_timeout_err (self, retries):
+ def on_timeout(self):
return self.port.ok('Request timed out.')
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_ipv6.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_ipv6.py
new file mode 100755
index 00000000..c2c8ebc1
--- /dev/null
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/rx_services/trex_stl_rx_service_ipv6.py
@@ -0,0 +1,179 @@
+from .trex_stl_rx_service_api import RXServiceAPI
+
+from ..trex_stl_streams import STLStream, STLTXSingleBurst
+from ..trex_stl_packet_builder_scapy import *
+from ..trex_stl_types import *
+
+from scapy.layers.l2 import Ether
+from scapy.layers.inet6 import *
+import time
+
+
+class RXServiceIPv6(RXServiceAPI):
+
+ def __init__(self, port, dst_ip, *a, **k):
+ RXServiceAPI.__init__(self, port, *a, **k)
+ self.attr = port.get_ts_attr()
+ self.src_mac = self.attr['layer_cfg']['ether']['src']
+ mac_for_ip = port.info.get('hw_mac', self.src_mac)
+ self.src_ip = generate_ipv6(mac_for_ip)
+ self.mld_ip = generate_ipv6_solicited_node(mac_for_ip)
+ self.dst_ip = dst_ip
+ self.responses = {}
+
+ def pre_execute(self):
+ return self.port.ok()
+
+ def send_intermediate(self, streams):
+ self.port.remove_all_streams()
+ self.port.add_streams(streams)
+ mult = {'op': 'abs', 'type' : 'percentage', 'value': 100}
+ self.port.start(mul = mult, force = True, duration = -1, mask = 0xffffffff)
+
+ def generate_ns(self, dst_mac, dst_ip):
+ pkt = (Ether(src = self.src_mac, dst = dst_mac) /
+ IPv6(src = self.src_ip, dst = dst_ip) /
+ ICMPv6ND_NS(tgt = dst_ip) /
+ ICMPv6NDOptSrcLLAddr(lladdr = self.src_mac))
+ return STLStream(packet = STLPktBuilder(pkt = pkt), mode = STLTXSingleBurst(total_pkts = 2))
+
+ def generate_na(self, dst_mac, dst_ip):
+ pkt = (Ether(src = self.src_mac, dst = dst_mac) /
+ IPv6(src = self.src_ip, dst = dst_ip) /
+ ICMPv6ND_NA(tgt = self.src_ip, R = 0, S = 1, O = 1))
+ return STLStream(packet = STLPktBuilder(pkt = pkt), mode = STLTXSingleBurst(total_pkts = 2))
+
+ def generate_ns_na(self, dst_mac, dst_ip):
+ return [self.generate_ns(dst_mac, dst_ip), self.generate_na(dst_mac, dst_ip)]
+
+ def execute(self, *a, **k):
+ mult = self.attr['multicast']['enabled']
+ try:
+ if mult != True:
+ self.port.set_attr(multicast = True) # response might be multicast
+ return RXServiceAPI.execute(self, *a, **k)
+ finally:
+ if mult != True:
+ self.port.set_attr(multicast = False)
+
+
+class RXServiceIPv6Scan(RXServiceIPv6):
+ ''' Ping with given IPv6 (usually all nodes address) and wait for responses until timeout '''
+
+ def get_name(self):
+ return 'IPv6 scanning'
+
+ def generate_request(self):
+ dst_mac = multicast_mac_from_ipv6(self.dst_ip)
+ dst_mld_ip = 'ff02::16'
+ dst_mld_mac = multicast_mac_from_ipv6(dst_mld_ip)
+
+ mld_pkt = (Ether(src = self.src_mac, dst = dst_mld_mac) /
+ IPv6(src = self.src_ip, dst = dst_mld_ip, hlim = 1) /
+ IPv6ExtHdrHopByHop(options = [RouterAlert(), PadN()]) /
+ ICMPv6MLReportV2() /
+ MLDv2Addr(type = 4, len = 0, multicast_addr = 'ff02::2'))
+ ping_pkt = (Ether(src = self.src_mac, dst = dst_mac) /
+ IPv6(src = self.src_ip, dst = self.dst_ip, hlim = 1) /
+ ICMPv6EchoRequest())
+
+ mld_stream = STLStream(packet = STLPktBuilder(pkt = mld_pkt),
+ mode = STLTXSingleBurst(total_pkts = 2))
+ ping_stream = STLStream(packet = STLPktBuilder(pkt = ping_pkt),
+ mode = STLTXSingleBurst(total_pkts = 2))
+ return [mld_stream, ping_stream]
+
+
+ def on_pkt_rx(self, pkt, start_ts):
+ # convert to scapy
+ scapy_pkt = Ether(pkt['binary'])
+
+ if scapy_pkt.haslayer('ICMPv6ND_NS') and scapy_pkt.haslayer('ICMPv6NDOptSrcLLAddr'):
+ node_mac = scapy_pkt.getlayer(ICMPv6NDOptSrcLLAddr).lladdr
+ node_ip = scapy_pkt.getlayer(IPv6).src
+ if node_ip not in self.responses:
+ self.send_intermediate(self.generate_ns_na(node_mac, node_ip))
+
+ elif scapy_pkt.haslayer('ICMPv6ND_NA'):
+ is_router = scapy_pkt.getlayer(ICMPv6ND_NA).R
+ node_ip = scapy_pkt.getlayer(ICMPv6ND_NA).tgt
+ dst_ip = scapy_pkt.getlayer(IPv6).dst
+ node_mac = scapy_pkt.src
+ if node_ip not in self.responses and dst_ip == self.src_ip:
+ self.responses[node_ip] = {'type': 'Router' if is_router else 'Host', 'mac': node_mac}
+
+ elif scapy_pkt.haslayer('ICMPv6EchoReply'):
+ node_mac = scapy_pkt.src
+ node_ip = scapy_pkt.getlayer(IPv6).src
+ if node_ip == self.dst_ip:
+ return self.port.ok([{'ipv6': node_ip, 'mac': node_mac}])
+ if node_ip not in self.responses:
+ self.send_intermediate(self.generate_ns_na(node_mac, node_ip))
+
+
+ def on_timeout(self):
+ return self.port.ok([{'type': v['type'], 'mac': v['mac'], 'ipv6': k} for k, v in self.responses.items()])
+
+
+class RXServiceICMPv6(RXServiceIPv6):
+ '''
+ Ping some IPv6 location.
+ If the dest MAC is found from scanning, use it.
+ Otherwise, send to default port dest.
+ '''
+
+ def __init__(self, port, pkt_size, dst_mac = None, *a, **k):
+ super(RXServiceICMPv6, self).__init__(port, *a, **k)
+ self.pkt_size = pkt_size
+ self.dst_mac = dst_mac
+
+ def get_name(self):
+ return 'PING6'
+
+ def pre_execute(self):
+ if self.dst_mac is None and not self.port.is_resolved():
+ return self.port.err('ping - port has an unresolved destination, cannot determine next hop MAC address')
+ return self.port.ok()
+
+
+ # return a list of streams for request
+ def generate_request(self):
+ attrs = self.port.get_ts_attr()
+
+ if self.dst_mac is None:
+ self.dst_mac = attrs['layer_cfg']['ether']['dst']
+
+ ping_pkt = (Ether(src = self.src_mac, dst = self.dst_mac) /
+ IPv6(src = self.src_ip, dst = self.dst_ip) /
+ ICMPv6EchoRequest())
+ pad = max(0, self.pkt_size - len(ping_pkt))
+ ping_pkt /= pad * 'x'
+
+ return STLStream( packet = STLPktBuilder(pkt = ping_pkt), mode = STLTXSingleBurst(total_pkts = 2) )
+
+
+ def on_pkt_rx(self, pkt, start_ts):
+ scapy_pkt = Ether(pkt['binary'])
+
+ if scapy_pkt.haslayer('ICMPv6EchoReply'):
+ node_ip = scapy_pkt.getlayer(IPv6).src
+ hlim = scapy_pkt.getlayer(IPv6).hlim
+ dst_ip = scapy_pkt.getlayer(IPv6).dst
+
+ if dst_ip != self.src_ip: # not our ping
+ return
+
+ dt = pkt['ts'] - start_ts
+ return self.port.ok('Reply from {0}: bytes={1}, time={2:.2f}ms, hlim={3}'.format(node_ip, len(pkt['binary']), dt * 1000, hlim))
+
+ if scapy_pkt.haslayer('ICMPv6ND_NS') and scapy_pkt.haslayer('ICMPv6NDOptSrcLLAddr'):
+ node_mac = scapy_pkt.getlayer(ICMPv6NDOptSrcLLAddr).lladdr
+ node_ip = scapy_pkt.getlayer(IPv6).src
+ self.send_intermediate(self.generate_ns_na(node_mac, node_ip))
+
+
+ # return the str of a timeout err
+ def on_timeout(self):
+ return self.port.ok('Request timed out.')
+
+