Skip to content

Commit 9798b17

Browse files
authored
Merge pull request #250 from harishraghavendra/sctp-support
Added SCTP support
2 parents a269fb4 + 76ffc8f commit 9798b17

File tree

2 files changed

+101
-38
lines changed

2 files changed

+101
-38
lines changed

src/python/oftest/packet.py

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import scapy.route
1313
import scapy.layers.l2
1414
import scapy.layers.inet
15+
import scapy.layers.sctp
1516
if not config["disable_ipv6"]:
1617
import scapy.route6
1718
import scapy.layers.inet6
@@ -28,6 +29,7 @@
2829
TCP = scapy.layers.inet.TCP
2930
UDP = scapy.layers.inet.UDP
3031
ICMP = scapy.layers.inet.ICMP
32+
SCTP = scapy.layers.sctp.SCTP
3133

3234
if not config["disable_ipv6"]:
3335
IPv6 = scapy.layers.inet6.IPv6

src/python/oftest/testutils.py

+99-38
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,68 @@ def required_wildcards(parent):
6767
else:
6868
return 0
6969

70-
def simple_tcp_packet(pktlen=100,
70+
def simple_sctp_packet(pktlen=100,
71+
eth_dst='00:01:02:03:04:05',
72+
eth_src='00:06:07:08:09:0a',
73+
dl_vlan_enable=False,
74+
vlan_vid=0,
75+
vlan_pcp=0,
76+
dl_vlan_cfi=0,
77+
ip_src='192.168.0.1',
78+
ip_dst='192.168.0.2',
79+
ip_tos=0,
80+
ip_ttl=64,
81+
sctp_sport=1234,
82+
sctp_dport=80,
83+
ip_ihl=None,
84+
ip_options=False
85+
):
86+
"""
87+
Return a simple dataplane SCTP packet
88+
89+
Supports a few parameters:
90+
@param len Length of packet in bytes w/o CRC
91+
@param eth_dst Destinatino MAC
92+
@param eth_src Source MAC
93+
@param dl_vlan_enable True if the packet is with vlan, False otherwise
94+
@param vlan_vid VLAN ID
95+
@param vlan_pcp VLAN priority
96+
@param ip_src IP source
97+
@param ip_dst IP destination
98+
@param ip_tos IP ToS
99+
@param ip_ttl IP TTL
100+
@param sctp_dport SCTP destination port
101+
@param sctp_sport SCTP source port
102+
103+
Generates a simple SCTP request. Users
104+
shouldn't assume anything about this packet other than that
105+
it is a valid ethernet/IP/SCTP frame.
106+
"""
107+
108+
if MINSIZE > pktlen:
109+
pktlen = MINSIZE
110+
111+
# Note Dot1Q.id is really CFI
112+
if (dl_vlan_enable):
113+
pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
114+
scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
115+
scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
116+
scapy.SCTP(sport=sctp_sport, dport=sctp_dport)
117+
else:
118+
if not ip_options:
119+
pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
120+
scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
121+
scapy.SCTP(sport=sctp_sport, dport=sctp_dport)
122+
else:
123+
pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
124+
scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
125+
scapy.SCTP(sport=sctp_sport, dport=sctp_dport)
126+
127+
pkt = pkt/("D" * (pktlen - len(pkt)))
128+
129+
return pkt
130+
131+
def simple_tcp_packet(pktlen=100,
71132
eth_dst='00:01:02:03:04:05',
72133
eth_src='00:06:07:08:09:0a',
73134
dl_vlan_enable=False,
@@ -100,7 +161,7 @@ def simple_tcp_packet(pktlen=100,
100161
@param ip_ttl IP TTL
101162
@param tcp_dport TCP destination port
102163
@param tcp_sport TCP source port
103-
@param tcp_flags TCP Control flags
164+
@param tcp_flags TCP Control flags
104165
105166
Generates a simple TCP request. Users
106167
shouldn't assume anything about this packet other than that
@@ -161,7 +222,7 @@ def simple_tcpv6_packet(pktlen=100,
161222
@param ipv6_fl IPv6 flow label
162223
@param tcp_dport TCP destination port
163224
@param tcp_sport TCP source port
164-
@param tcp_flags TCP Control flags
225+
@param tcp_flags TCP Control flags
165226
166227
Generates a simple TCP request. Users shouldn't assume anything about this
167228
packet other than that it is a valid ethernet/IPv6/TCP frame.
@@ -286,7 +347,7 @@ def simple_udpv6_packet(pktlen=100,
286347

287348
return pkt
288349

289-
def simple_icmp_packet(pktlen=60,
350+
def simple_icmp_packet(pktlen=60,
290351
eth_dst='00:01:02:03:04:05',
291352
eth_src='00:06:07:08:09:0a',
292353
dl_vlan_enable=False,
@@ -296,7 +357,7 @@ def simple_icmp_packet(pktlen=60,
296357
ip_dst='192.168.0.2',
297358
ip_tos=0,
298359
ip_ttl=64,
299-
ip_id=1,
360+
ip_id=1,
300361
icmp_type=8,
301362
icmp_code=0,
302363
icmp_data=''):
@@ -452,7 +513,7 @@ def simple_icmpv6_packet(pktlen=100,
452513

453514
return pkt
454515

455-
def simple_arp_packet(pktlen=68,
516+
def simple_arp_packet(pktlen=68,
456517
eth_dst='ff:ff:ff:ff:ff:ff',
457518
eth_src='00:06:07:08:09:0a',
458519
vlan_vid=0,
@@ -507,7 +568,7 @@ def simple_eth_packet(pktlen=60,
507568

508569
return pkt
509570

510-
def qinq_tcp_packet(pktlen=100,
571+
def qinq_tcp_packet(pktlen=100,
511572
eth_dst='00:01:02:03:04:05',
512573
eth_src='00:06:07:08:09:0a',
513574
dl_vlan_outer=20,
@@ -693,7 +754,7 @@ def port_config_get(controller, port_no):
693754
for port in ports:
694755
if port.port_no == port_no:
695756
return (port.hw_addr, port.config, port.advertised)
696-
757+
697758
logging.warn("Did not find port number for port config")
698759
return None, None, None
699760

@@ -738,7 +799,7 @@ def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
738799
logging.debug("Checking for pkt on port " + str(ofport))
739800
(rcv_port, rcv_pkt, pkt_time) = dp.poll(
740801
port_number=ofport, exp_pkt=exp_pkt_arg)
741-
assert_if.assertTrue(rcv_pkt is not None,
802+
assert_if.assertTrue(rcv_pkt is not None,
742803
"Did not receive pkt on " + str(ofport))
743804
if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
744805
logging.debug("Expected %s" % format_packet(pkt))
@@ -752,7 +813,7 @@ def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
752813
logging.debug("Negative check for pkt on port " + str(ofport))
753814
(rcv_port, rcv_pkt, pkt_time) = dp.poll(
754815
port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
755-
assert_if.assertTrue(rcv_pkt is None,
816+
assert_if.assertTrue(rcv_pkt is None,
756817
"Unexpected pkt on port " + str(ofport))
757818

758819

@@ -783,12 +844,12 @@ def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
783844
port_number=check_port, exp_pkt=exp_pkt_arg)
784845

785846
if rcv_pkt is None:
786-
logging.error("ERROR: No packet received from " +
847+
logging.error("ERROR: No packet received from " +
787848
str(check_port))
788849

789850
parent.assertTrue(rcv_pkt is not None,
790851
"Did not receive packet port " + str(check_port))
791-
logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
852+
logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
792853
str(rcv_port))
793854

794855
if str(exp_pkt) != str(rcv_pkt):
@@ -826,8 +887,8 @@ def match_verify(parent, req_match, res_match):
826887
'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
827888
" != " + str(res_match.vlan_vid))
828889
parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
829-
'Match failed: vlan_pcp: ' +
830-
str(req_match.vlan_pcp) + " != " +
890+
'Match failed: vlan_pcp: ' +
891+
str(req_match.vlan_pcp) + " != " +
831892
str(res_match.vlan_pcp))
832893
parent.assertEqual(req_match.eth_type, res_match.eth_type,
833894
'Match failed: eth_type: ' + str(req_match.eth_type) +
@@ -852,11 +913,11 @@ def match_verify(parent, req_match, res_match):
852913
and ((req_match.ip_proto == TCP_PROTOCOL)
853914
or (req_match.ip_proto == UDP_PROTOCOL))):
854915
parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
855-
'Match failed: tcp_src: ' +
916+
'Match failed: tcp_src: ' +
856917
str(req_match.tcp_src) +
857918
" != " + str(res_match.tcp_src))
858919
parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
859-
'Match failed: tcp_dst: ' +
920+
'Match failed: tcp_dst: ' +
860921
str(req_match.tcp_dst) +
861922
" != " + str(res_match.tcp_dst))
862923

@@ -874,7 +935,7 @@ def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None
874935
"""
875936
Create a flow message
876937
877-
Match on packet with given wildcards.
938+
Match on packet with given wildcards.
878939
See flow_match_test for other parameter descriptoins
879940
@param egr_queue if not None, make the output an enqueue action
880941
@param in_band if True, do not wildcard ingress port
@@ -941,7 +1002,7 @@ def flow_msg_install(parent, request, clear_table_override=None):
9411002
if(clear_table_override != None):
9421003
clear_table = clear_table_override
9431004

944-
if clear_table:
1005+
if clear_table:
9451006
logging.debug("Clear flow table")
9461007
delete_all_flows(parent.controller)
9471008

@@ -963,21 +1024,21 @@ def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
9631024

9641025
if wildcards is None:
9651026
wildcards = required_wildcards(parent)
966-
logging.info("Pkt match test: " + str(ing_port) + " to " +
1027+
logging.info("Pkt match test: " + str(ing_port) + " to " +
9671028
str(egr_ports))
9681029
logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
9691030
if pkt is None:
9701031
pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
9711032
if exp_pkt is None:
9721033
exp_pkt = pkt
9731034

974-
request = flow_msg_create(parent, pkt, ing_port=ing_port,
1035+
request = flow_msg_create(parent, pkt, ing_port=ing_port,
9751036
wildcards=wildcards, egr_ports=egr_ports,
9761037
action_list=action_list)
9771038

9781039
flow_msg_install(parent, request)
9791040

980-
logging.debug("Send packet: " + str(ing_port) + " to " +
1041+
logging.debug("Send packet: " + str(ing_port) + " to " +
9811042
str(egr_ports))
9821043
parent.dataplane.send(ing_port, str(pkt))
9831044

@@ -1037,16 +1098,16 @@ def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
10371098

10381099
count = 0
10391100
egr_ports = []
1040-
for egr_idx in range(len(of_ports)):
1101+
for egr_idx in range(len(of_ports)):
10411102
if of_ports[egr_idx] not in exclude_list:
10421103
egr_ports.append(of_ports[egr_idx])
10431104
count += 1
10441105
if count >= how_many:
10451106
return egr_ports
10461107
logging.debug("Could not generate enough egress ports for test")
10471108
return []
1048-
1049-
def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
1109+
1110+
def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
10501111
exp_pkt=None, action_list=None,
10511112
max_test=0, egr_count=1, ing_port=False):
10521113
"""
@@ -1071,18 +1132,18 @@ def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
10711132

10721133
if egr_count == -1:
10731134
egr_count = test_param_get('egr_count', default=2)
1074-
1135+
10751136
for ing_idx in range(len(of_ports)):
10761137
ingress_port = of_ports[ing_idx]
1077-
egr_ports = get_egr_list(parent, of_ports, egr_count,
1138+
egr_ports = get_egr_list(parent, of_ports, egr_count,
10781139
exclude_list=[ingress_port])
10791140
if ing_port:
10801141
egr_ports.append(ofp.OFPP_IN_PORT)
10811142
if len(egr_ports) == 0:
10821143
parent.assertTrue(0, "Failed to generate egress port list")
10831144

1084-
flow_match_test_port_pair(parent, ingress_port, egr_ports,
1085-
wildcards=wildcards, vlan_vid=vlan_vid,
1145+
flow_match_test_port_pair(parent, ingress_port, egr_ports,
1146+
wildcards=wildcards, vlan_vid=vlan_vid,
10861147
pkt=pkt, exp_pkt=exp_pkt,
10871148
action_list=action_list)
10881149
test_count += 1
@@ -1114,7 +1175,7 @@ def test_param_get(key, default=None):
11141175
on the command line, return val (as interpreted by exec). Otherwise
11151176
return default value.
11161177
1117-
WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
1178+
WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
11181179
eg egr_count, not egr-count.
11191180
"""
11201181
try:
@@ -1184,7 +1245,7 @@ def action_generate(parent, field_to_mod, mod_field_vals):
11841245

11851246
return act
11861247

1187-
def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
1248+
def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
11881249
mod_fields=[], tp="tcp", check_test_params=False):
11891250
"""
11901251
Set up the ingress and expected packet and action list for a test
@@ -1324,7 +1385,7 @@ def all_stats_get(parent):
13241385
"""
13251386
Get the aggregate stats for all flows in the table
13261387
@param parent Test instance with controller connection and assert
1327-
@returns dict with keys flows, packets, bytes, active (flows),
1388+
@returns dict with keys flows, packets, bytes, active (flows),
13281389
lookups, matched
13291390
"""
13301391
stat_req = ofp.message.aggregate_stats_request()
@@ -1339,14 +1400,14 @@ def all_stats_get(parent):
13391400
parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
13401401

13411402
for obj in reply.entries:
1342-
(rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1403+
(rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
13431404
obj.packet_count, obj.byte_count)
13441405
break
13451406

13461407
request = ofp.message.table_stats_request()
13471408
(reply , pkt) = parent.controller.transact(request)
13481409

1349-
1410+
13501411
(rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
13511412
for obj in reply.entries:
13521413
rv["active"] += obj.active_count
@@ -1356,7 +1417,7 @@ def all_stats_get(parent):
13561417
return rv
13571418

13581419
_import_blacklist.add('FILTER')
1359-
FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1420+
FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
13601421
for x in range(256)])
13611422

13621423
def hex_dump_buffer(src, length=16):
@@ -1376,7 +1437,7 @@ def hex_dump_buffer(src, length=16):
13761437
return ''.join(result)
13771438

13781439
def format_packet(pkt):
1379-
return "Packet length %d \n%s" % (len(str(pkt)),
1440+
return "Packet length %d \n%s" % (len(str(pkt)),
13801441
hex_dump_buffer(str(pkt)))
13811442

13821443
def inspect_packet(pkt):
@@ -1857,7 +1918,7 @@ def verify_capability(test, capability):
18571918
test.assertIn(capability, ofp.const.ofp_capabilities_map,
18581919
"Capability code %d does not exist." % capability)
18591920
capability_str = ofp.const.ofp_capabilities_map[capability]
1860-
1921+
18611922
logging.info(("Sending features_request to test if capability "
18621923
"%s is supported."), capability_str)
18631924
req = ofp.message.features_request()
@@ -1867,7 +1928,7 @@ def verify_capability(test, capability):
18671928
("Unexpected packet type %d received in response to "
18681929
"OFPT_FEATURES_REQUEST") % res.type)
18691930
logging.info("Received features_reply.")
1870-
1931+
18711932
if (res.capabilities & capability) > 0:
18721933
logging.info("Switch capabilities bitmask claims to support %s",
18731934
capability_str)
@@ -1890,7 +1951,7 @@ def verify_configuration_flag(test, flag):
18901951
"flag %s does not exist." % flag)
18911952
flag_str = ofp.const.ofp_config_flags_map[flag]
18921953

1893-
logging.info("Sending OFPT_GET_CONFIG_REQUEST.")
1954+
logging.info("Sending OFPT_GET_CONFIG_REQUEST.")
18941955
req = ofp.message.get_config_request()
18951956
rv = test.controller.message_send(req)
18961957
test.assertNotEqual(rv, -1, "Not able to send get_config_request.")

0 commit comments

Comments
 (0)