1 # Copyright 2016 Red Hat Inc & Xena Networks.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
16 # Dan Amzulescu, Xena Networks
17 # Christian Trautman, Red Hat Inc.
19 # Usage can be seen below in unit test. This implementation is designed for one
20 # module two port Xena chassis runs only.
27 from collections import OrderedDict
33 import scapy.layers.inet as inet
35 _LOGGER = logging.getLogger(__name__)
36 _LOCALE = locale.getlocale()[1]
39 class XenaJSON(object):
41 Class to modify and read Xena JSON configuration files.
43 def __init__(self, json_path='./profiles/baseconfig.x2544'):
46 :param json_path: path to JSON file to read. Expected files must have
47 two module ports with each port having its own stream config profile.
48 :return: XenaJSON object
50 self.json_data = read_json_file(json_path)
52 self.packet_data = OrderedDict()
53 self.packet_data['layer2'] = None
54 self.packet_data['vlan'] = None
55 self.packet_data['layer3'] = None
56 self.packet_data['layer4'] = None
58 def _add_multistream_layer(self, entity, seg_uuid, stop_value, layer):
60 Add the multi stream layers to the json file based on the layer provided
61 :param entity: Entity to append the segment to in entity list
62 :param seg_uuid: The UUID to attach the multistream layer to
63 :param stop_value: The number of flows to configure
64 :param layer: the layer that the multistream will be attached to
68 2: ('Dst MAC addr', 'Src MAC addr'),
69 3: ('Dest IP Addr', 'Src IP Addr'),
70 4: ('Dest Port', 'Src Port')
75 "Mask": "//8=", # mask of 255/255
78 "StopValue": stop_value,
81 "SegmentId": seg_uuid,
82 "FieldName": field_name[int(layer)][0]
86 "Mask": "//8=", # mask of 255/255
89 "StopValue": stop_value,
92 "SegmentId": seg_uuid,
93 "FieldName": field_name[int(layer)][1]
97 self.json_data['StreamProfileHandler']['EntityList'][entity][
98 'StreamConfig']['HwModifiers'] = (segments)
100 def _create_packet_header(self):
102 Create the scapy packet header based on what has been built in this
103 instance using the set header methods. Return tuple of the two byte
104 arrays, one for each port.
105 :return: Scapy packet headers as bytearrays
107 if not self.packet_data['layer2']:
108 _LOGGER.warning('Using dummy info for layer 2 in Xena JSON file')
109 self.set_header_layer2()
110 packet1, packet2 = (self.packet_data['layer2'][0],
111 self.packet_data['layer2'][1])
112 for packet_header in list(self.packet_data.copy().values())[1:]:
114 packet1 /= packet_header[0]
115 packet2 /= packet_header[1]
116 ret = (bytes(packet1), bytes(packet2))
119 def add_header_segments(self, flows=0, multistream_layer=None):
121 Build the header segments to write to the JSON file.
122 :param flows: Number of flows to configure for multistream if enabled
123 :param multistream_layer: layer to set multistream flows as string.
124 Acceptable values are L2, L3 or L4
127 packet = self._create_packet_header()
131 if self.packet_data['layer2']:
132 # slice out the layer 2 bytes from the packet header byte array
133 layer2 = packet[0][header_pos: len(self.packet_data['layer2'][0])]
134 seg = create_segment(
135 "ETHERNET", encode_byte_array(layer2).decode(_LOCALE))
136 if multistream_layer == 'L2' and flows > 0:
137 self._add_multistream_layer(entity=0, seg_uuid=seg['ItemID'],
138 stop_value=flows, layer=2)
140 # now do the other port data with reversed src, dst info
141 layer2 = packet[1][header_pos: len(self.packet_data['layer2'][1])]
142 seg = create_segment(
143 "ETHERNET", encode_byte_array(layer2).decode(_LOCALE))
145 if multistream_layer == 'L2' and flows > 0:
146 self._add_multistream_layer(entity=1, seg_uuid=seg['ItemID'],
147 stop_value=flows, layer=2)
148 header_pos = len(layer2)
149 if self.packet_data['vlan']:
150 # slice out the vlan bytes from the packet header byte array
151 vlan = packet[0][header_pos: len(
152 self.packet_data['vlan'][0]) + header_pos]
153 segment1.append(create_segment(
154 "VLAN", encode_byte_array(vlan).decode(_LOCALE)))
155 segment2.append(create_segment(
156 "VLAN", encode_byte_array(vlan).decode(_LOCALE)))
157 header_pos += len(vlan)
158 if self.packet_data['layer3']:
159 # slice out the layer 3 bytes from the packet header byte array
160 layer3 = packet[0][header_pos: len(
161 self.packet_data['layer3'][0]) + header_pos]
162 seg = create_segment(
163 "IP", encode_byte_array(layer3).decode(_LOCALE))
165 if multistream_layer == 'L3' and flows > 0:
166 self._add_multistream_layer(entity=0, seg_uuid=seg['ItemID'],
167 stop_value=flows, layer=3)
168 # now do the other port data with reversed src, dst info
169 layer3 = packet[1][header_pos: len(
170 self.packet_data['layer3'][1]) + header_pos]
171 seg = create_segment(
172 "IP", encode_byte_array(layer3).decode(_LOCALE))
174 if multistream_layer == 'L3' and flows > 0:
175 self._add_multistream_layer(entity=1, seg_uuid=seg['ItemID'],
176 stop_value=flows, layer=3)
177 header_pos += len(layer3)
178 if self.packet_data['layer4']:
179 # slice out the layer 4 bytes from the packet header byte array
180 layer4 = packet[0][header_pos: len(
181 self.packet_data['layer4'][0]) + header_pos]
182 seg = create_segment(
183 "UDP", encode_byte_array(layer4).decode(_LOCALE))
185 if multistream_layer == 'L4' and flows > 0:
186 self._add_multistream_layer(entity=0, seg_uuid=seg['ItemID'],
187 stop_value=flows, layer=4)
188 # now do the other port data with reversed src, dst info
189 layer4 = packet[1][header_pos: len(
190 self.packet_data['layer4'][1]) + header_pos]
191 seg = create_segment(
192 "UDP", encode_byte_array(layer4).decode(_LOCALE))
194 if multistream_layer == 'L4' and flows > 0:
195 self._add_multistream_layer(entity=1, seg_uuid=seg['ItemID'],
196 stop_value=flows, layer=4)
197 header_pos += len(layer4)
199 self.json_data['StreamProfileHandler']['EntityList'][0][
200 'StreamConfig']['HeaderSegments'] = segment1
201 self.json_data['StreamProfileHandler']['EntityList'][1][
202 'StreamConfig']['HeaderSegments'] = segment2
204 def disable_back2back_test(self):
206 Disable the rfc2544 back to back test
209 self.json_data['TestOptions']['TestTypeOptionMap']['Back2Back'][
212 def disable_throughput_test(self):
214 Disable the rfc2544 throughput test
217 self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][
220 def enable_back2back_test(self):
222 Enable the rfc2544 back to back test
225 self.json_data['TestOptions']['TestTypeOptionMap']['Back2Back'][
228 def enable_throughput_test(self):
230 Enable the rfc2544 throughput test
233 self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][
236 def modify_2544_tput_options(self, initial_value, minimum_value,
237 maximum_value, value_resolution,
238 use_pass_threshhold, pass_threshhold):
239 self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][
240 'RateIterationOptions']['InitialValue'] = initial_value
241 self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][
242 'RateIterationOptions']['MinimumValue'] = minimum_value
243 self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][
244 'RateIterationOptions']['MaximumValue'] = maximum_value
245 self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][
246 'RateIterationOptions']['ValueResolution'] = value_resolution
247 self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][
248 'RateIterationOptions']['UsePassThreshold'] = use_pass_threshhold
249 self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][
250 'RateIterationOptions']['PassThreshold'] = pass_threshhold
252 def set_chassis_info(self, hostname, pwd):
255 :param hostname: hostname as string of ip
256 :param pwd: password to chassis as string
259 self.json_data['ChassisManager']['ChassisList'][0][
260 'HostName'] = hostname
261 self.json_data['ChassisManager']['ChassisList'][0][
264 def set_header_layer2(self, dst_mac='cc:cc:cc:cc:cc:cc',
265 src_mac='bb:bb:bb:bb:bb:bb', **kwargs):
267 Build a scapy Ethernet L2 objects inside instance packet_data structure
268 :param dst_mac: destination mac as string. Example "aa:aa:aa:aa:aa:aa"
269 :param src_mac: source mac as string. Example "bb:bb:bb:bb:bb:bb"
270 :param kwargs: Extra params per scapy usage.
273 self.packet_data['layer2'] = [
274 inet.Ether(dst=dst_mac, src=src_mac, **kwargs),
275 inet.Ether(dst=src_mac, src=dst_mac, **kwargs)]
277 def set_header_layer3(self, src_ip='192.168.0.2', dst_ip='192.168.0.3',
278 protocol='UDP', **kwargs):
280 Build scapy IPV4 L3 objects inside instance packet_data structure
281 :param src_ip: source IP as string in dot notation format
282 :param dst_ip: destination IP as string in dot notation format
283 :param protocol: protocol for l4
284 :param kwargs: Extra params per scapy usage
287 self.packet_data['layer3'] = [
288 inet.IP(src=src_ip, dst=dst_ip, proto=protocol.lower(), **kwargs),
289 inet.IP(src=dst_ip, dst=src_ip, proto=protocol.lower(), **kwargs)]
291 def set_header_layer4_udp(self, source_port, destination_port, **kwargs):
293 Build scapy UDP L4 objects inside instance packet_data structure
294 :param source_port: Source port as int
295 :param destination_port: Destination port as int
296 :param kwargs: Extra params per scapy usage
299 self.packet_data['layer4'] = [
300 inet.UDP(sport=source_port, dport=destination_port, **kwargs),
301 inet.UDP(sport=source_port, dport=destination_port, **kwargs)]
303 def set_header_vlan(self, vlan_id=1, **kwargs):
305 Build a Dot1Q scapy object inside instance packet_data structure
306 :param vlan_id: The VLAN ID
307 :param kwargs: Extra params per scapy usage
310 self.packet_data['vlan'] = [
311 inet.Dot1Q(vlan=vlan_id, **kwargs),
312 inet.Dot1Q(vlan=vlan_id, **kwargs)]
314 def set_port(self, index, module, port):
316 Set the module and port for the 0 index port to use with the test
317 :param index: Index of port to set, 0 = port1, 1=port2, etc..
318 :param module: module location as int
319 :param port: port location in module as int
322 self.json_data['PortHandler']['EntityList'][index]['PortRef'][
323 'ModuleIndex'] = module
324 self.json_data['PortHandler']['EntityList'][index]['PortRef'][
327 def set_port_ip_v4(self, port, ip_addr, netmask, gateway):
330 :param port: port number as int of port to set ip info
331 :param ip_addr: ip address in dot notation format as string
332 :param netmask: cidr number for netmask (ie 24/16/8) as int
333 :param gateway: gateway address in dot notation format
336 available_ports = range(len(
337 self.json_data['PortHandler']['EntityList']))
338 if port not in available_ports:
339 raise ValueError("{}{}{}".format(
340 'Port assignment must be an available port ',
341 'number in baseconfig file. Port=', port))
342 self.json_data['PortHandler']['EntityList'][
343 port]["IpV4Address"] = ip_addr
344 self.json_data['PortHandler']['EntityList'][
345 port]["IpV4Gateway"] = gateway
346 self.json_data['PortHandler']['EntityList'][
347 port]["IpV4RoutingPrefix"] = int(netmask)
349 def set_port_ip_v6(self, port, ip_addr, netmask, gateway):
352 :param port: port number as int of port to set ip info
353 :param ip_addr: ip address as 8 groups of 4 hexadecimal groups separated
355 :param netmask: cidr number for netmask (ie 24/16/8) as int
356 :param gateway: gateway address as string in 8 group of 4 hexadecimal
357 groups separated by a colon.
360 available_ports = range(len(
361 self.json_data['PortHandler']['EntityList']))
362 if port not in available_ports:
363 raise ValueError("{}{}{}".format(
364 'Port assignment must be an available port ',
365 'number in baseconfig file. Port=', port))
366 self.json_data['PortHandler']['EntityList'][
367 port]["IpV6Address"] = ip_addr
368 self.json_data['PortHandler']['EntityList'][
369 port]["IpV6Gateway"] = gateway
370 self.json_data['PortHandler']['EntityList'][
371 port]["IpV6RoutingPrefix"] = int(netmask)
373 def set_test_options_tput(self, packet_sizes, duration, iterations,
374 loss_rate, micro_tpld=False):
376 Set the tput test options
377 :param packet_sizes: List of packet sizes to test, single int entry is
378 acceptable for one packet size testing
379 :param duration: time for each test in seconds as int
380 :param iterations: number of iterations of testing as int
381 :param loss_rate: acceptable loss rate as float
382 :param micro_tpld: boolean if micro_tpld should be enabled or disabled
385 if isinstance(packet_sizes, int):
386 packet_sizes = [packet_sizes]
387 self.json_data['TestOptions']['PacketSizes'][
388 'CustomPacketSizes'] = packet_sizes
389 self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][
390 'Duration'] = duration
391 self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][
392 'RateIterationOptions']['AcceptableLoss'] = loss_rate
393 self.json_data['TestOptions']['FlowCreationOptions'][
394 'UseMicroTpldOnDemand'] = 'true' if micro_tpld else 'false'
395 self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][
396 'Iterations'] = iterations
398 def set_test_options_back2back(self, packet_sizes, duration,
399 iterations, startvalue, endvalue,
402 Set the back2back test options
403 :param packet_sizes: List of packet sizes to test, single int entry is
404 acceptable for one packet size testing
405 :param duration: time for each test in seconds as int
406 :param iterations: number of iterations of testing as int
407 :param micro_tpld: boolean if micro_tpld should be enabled or disabled
408 :param StartValue: start value
409 :param EndValue: end value
412 if isinstance(packet_sizes, int):
413 packet_sizes = [packet_sizes]
414 self.json_data['TestOptions']['PacketSizes'][
415 'CustomPacketSizes'] = packet_sizes
416 self.json_data['TestOptions']['TestTypeOptionMap']['Back2Back'][
417 'Duration'] = duration
418 self.json_data['TestOptions']['FlowCreationOptions'][
419 'UseMicroTpldOnDemand'] = 'true' if micro_tpld else 'false'
420 self.json_data['TestOptions']['TestTypeOptionMap']['Back2Back'][
421 'Iterations'] = iterations
422 self.json_data['TestOptions']['TestTypeOptionMap']['Back2Back'][
423 'RateSweepOptions']['StartValue'] = startvalue
424 self.json_data['TestOptions']['TestTypeOptionMap']['Back2Back'][
425 'RateSweepOptions']['EndValue'] = endvalue
427 def set_topology_blocks(self):
429 Set the test topology to a West to East config for half duplex flow with
430 port 0 as the sender and port 1 as the receiver.
433 self.json_data['TestOptions']['TopologyConfig']['Topology'] = 'BLOCKS'
434 self.json_data['TestOptions']['TopologyConfig'][
435 'Direction'] = 'WEST_EAST'
436 self.json_data['PortHandler']['EntityList'][0][
437 'PortGroup'] = "WEST"
438 self.json_data['PortHandler']['EntityList'][1][
439 'PortGroup'] = "EAST"
441 def set_topology_mesh(self):
443 Set the test topology to Mesh for bi directional full duplex flow
446 self.json_data['TestOptions']['TopologyConfig']['Topology'] = 'MESH'
447 self.json_data['TestOptions']['TopologyConfig']['Direction'] = 'BIDIR'
448 self.json_data['PortHandler']['EntityList'][0][
449 'PortGroup'] = "UNDEFINED"
450 self.json_data['PortHandler']['EntityList'][1][
451 'PortGroup'] = "UNDEFINED"
453 def write_config(self, path='./2bUsed.x2544'):
455 Write the config to out as file
456 :param path: Output file to export the json data to
459 if not write_json_file(self.json_data, path):
460 raise RuntimeError("Could not write out file, please check config")
463 def create_segment(header_type, encode_64_string):
465 Create segment for JSON file
466 :param header_type: Type of header as string
467 :param encode_64_string: 64 byte encoded string value of the hex bytes
468 :return: segment as dictionary
471 "SegmentType": header_type.upper(),
472 "SegmentValue": encode_64_string,
473 "ItemID": str(uuid.uuid4()),
478 def decode_byte_array(enc_str):
479 """ Decodes the base64-encoded string to a byte array
480 :param enc_str: The base64-encoded string representing a byte array
481 :return: The decoded byte array
483 dec_string = base64.b64decode(enc_str)
485 barray.extend(dec_string)
489 def encode_byte_array(byte_arr):
490 """ Encodes the byte array as a base64-encoded string
491 :param byte_arr: A bytearray containing the bytes to convert
492 :return: A base64 encoded string
494 enc_string = base64.b64encode(bytes(byte_arr))
498 def print_json_report(json_data):
500 Print out info from the json data for testing purposes only.
501 :param json_data: json loaded data from json.loads
504 print("<<Xena JSON Config Report>>\n")
506 print("### Chassis Info ###")
507 print("Chassis IP: {}".format(json_data['ChassisManager'][
508 'ChassisList'][0]['HostName']))
509 print("Chassis Password: {}".format(json_data['ChassisManager'][
510 'ChassisList'][0]['Password']))
511 print("### Port Configuration ###")
512 print("Port 1 IPv4:{}/{} gateway:{}".format(
513 json_data['PortHandler']['EntityList'][0]["IpV4Address"],
514 json_data['PortHandler']['EntityList'][0]["IpV4RoutingPrefix"],
515 json_data['PortHandler']['EntityList'][0]["IpV4Gateway"]))
516 print("Port 1 IPv6:{}/{} gateway:{}".format(
517 json_data['PortHandler']['EntityList'][0]["IpV6Address"],
518 json_data['PortHandler']['EntityList'][0]["IpV6RoutingPrefix"],
519 json_data['PortHandler']['EntityList'][0]["IpV6Gateway"]))
520 print("Port 2 IPv4:{}/{} gateway:{}".format(
521 json_data['PortHandler']['EntityList'][1]["IpV4Address"],
522 json_data['PortHandler']['EntityList'][1]["IpV4RoutingPrefix"],
523 json_data['PortHandler']['EntityList'][1]["IpV4Gateway"]))
524 print("Port 2 IPv6:{}/{} gateway:{}".format(
525 json_data['PortHandler']['EntityList'][1]["IpV6Address"],
526 json_data['PortHandler']['EntityList'][1]["IpV6RoutingPrefix"],
527 json_data['PortHandler']['EntityList'][1]["IpV6Gateway"]))
528 print("Port 1: {}/{} group: {}".format(
529 json_data['PortHandler']['EntityList'][0]['PortRef']['ModuleIndex'],
530 json_data['PortHandler']['EntityList'][0]['PortRef']['PortIndex'],
531 json_data['PortHandler']['EntityList'][0]['PortGroup']))
532 print("Port 2: {}/{} group: {}".format(
533 json_data['PortHandler']['EntityList'][1]['PortRef']['ModuleIndex'],
534 json_data['PortHandler']['EntityList'][1]['PortRef']['PortIndex'],
535 json_data['PortHandler']['EntityList'][1]['PortGroup']))
536 print("### Tests Enabled ###")
537 print("Back2Back Enabled: {}".format(json_data['TestOptions'][
538 'TestTypeOptionMap']['Back2Back']['Enabled']))
539 print("Throughput Enabled: {}".format(json_data['TestOptions'][
540 'TestTypeOptionMap']['Throughput']['Enabled']))
541 print("### Test Options ###")
542 print("Test topology: {}/{}".format(
543 json_data['TestOptions']['TopologyConfig']['Topology'],
544 json_data['TestOptions']['TopologyConfig']['Direction']))
545 print("Packet Sizes: {}".format(json_data['TestOptions'][
546 'PacketSizes']['CustomPacketSizes']))
547 print("Test duration: {}".format(json_data['TestOptions'][
548 'TestTypeOptionMap']['Throughput']['Duration']))
549 print("Acceptable loss rate: {}".format(json_data['TestOptions'][
550 'TestTypeOptionMap']['Throughput']['RateIterationOptions'][
552 print("Micro TPLD enabled: {}".format(json_data['TestOptions'][
553 'FlowCreationOptions']['UseMicroTpldOnDemand']))
554 print("Test iterations: {}".format(json_data['TestOptions'][
555 'TestTypeOptionMap']['Throughput']['Iterations']))
556 if 'StreamConfig' in json_data['StreamProfileHandler']['EntityList'][0]:
557 print("### Header segments ###")
558 for seg in json_data['StreamProfileHandler']['EntityList']:
559 for header in seg['StreamConfig']['HeaderSegments']:
560 print("Type: {}".format(
561 header['SegmentType']))
562 print("Value: {}".format(decode_byte_array(
563 header['SegmentValue'])))
564 print("### Multi Stream config ###")
565 for seg in json_data['StreamProfileHandler']['EntityList']:
566 for header in seg['StreamConfig']['HwModifiers']:
568 except KeyError as exc:
569 print("Error setting not found in JSON data: {}".format(exc))
572 def read_json_file(json_file):
574 Read the json file path and return a dictionary of the data
575 :param json_file: path to json file
576 :return: dictionary of json data
579 with open(json_file, 'r', encoding=_LOCALE) as data_file:
580 file_data = json.loads(data_file.read())
581 except ValueError as exc:
582 # general json exception, Python 3.5 adds new exception type
583 _LOGGER.exception("Exception with json read: %s", exc)
585 except IOError as exc:
587 'Exception during file open: %s file=%s', exc, json_file)
592 def write_json_file(json_data, output_path):
594 Write out the dictionary of data to a json file
595 :param json_data: dictionary of json data
596 :param output_path: file path to write output
597 :return: Boolean if success
600 with open(output_path, 'w', encoding=_LOCALE) as fileh:
601 json.dump(json_data, fileh, indent=2, sort_keys=True,
604 except ValueError as exc:
605 # general json exception, Python 3.5 adds new exception type
607 "Exception with json write: %s", exc)
609 except IOError as exc:
611 'Exception during file write: %s file=%s', exc, output_path)
615 if __name__ == "__main__":
616 print("Running UnitTest for XenaJSON")
618 print_json_report(JSON.json_data)
619 JSON.set_chassis_info('192.168.0.5', 'vsperf')
620 JSON.set_port(0, 1, 0)
621 JSON.set_port(1, 1, 1)
622 JSON.set_port_ip_v4(0, '192.168.240.10', 32, '192.168.240.1')
623 JSON.set_port_ip_v4(1, '192.168.240.11', 32, '192.168.240.1')
624 JSON.set_port_ip_v6(0, 'a1a1:a2a2:a3a3:a4a4:a5a5:a6a6:a7a7:a8a8', 128,
625 'a1a1:a2a2:a3a3:a4a4:a5a5:a6a6:a7a7:1111')
626 JSON.set_port_ip_v6(1, 'b1b1:b2b2:b3b3:b4b4:b5b5:b6b6:b7b7:b8b8', 128,
627 'b1b1:b2b2:b3b3:b4b4:b5b5:b6b6:b7b7:1111')
628 JSON.set_header_layer2(dst_mac='dd:dd:dd:dd:dd:dd',
629 src_mac='ee:ee:ee:ee:ee:ee')
630 JSON.set_header_vlan(vlan_id=5)
631 JSON.set_header_layer3(src_ip='192.168.100.2', dst_ip='192.168.100.3',
633 JSON.set_header_layer4_udp(source_port=3000, destination_port=3001)
634 JSON.set_test_options_tput(packet_sizes=[64], duration=10, iterations=1,
635 loss_rate=0.0, micro_tpld=True)
636 JSON.add_header_segments(flows=4000, multistream_layer='L4')
637 JSON.set_topology_blocks()
638 write_json_file(JSON.json_data, './testthis.x2544')
639 JSON = XenaJSON('./testthis.x2544')
640 print_json_report(JSON.json_data)