3 # Copyright (c) 2016 Cisco and/or its affiliates.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 """This script uses IxNetwork Python API to control IxNetwork.
20 - ixnetwork.py library v7.51.1014.17 in /opt/ixnet-7.51
28 sys.path.insert(0, "/opt/ixnet-7.51/")
29 from IxNetwork import IxNet
32 class IxDriverError(Exception):
33 """Ixia-driver error handling."""
36 def add_ports(ixnet, count):
37 """Add ports to configuration.
39 :param ixnet: Instance of IxNet class.
40 :param count: Number of ports to add.
43 :return: List of ports added to configuration.
48 raise ValueError('No Ixnet instance')
49 if count <= 0 or count % 2 != 0:
50 raise ValueError('Port count must be even and higher then zero')
52 for _ in range(count):
53 ixnet.add(ixnet.getRoot(), 'vport')
57 return ixnet.getList(ixnet.getRoot(), 'vport')
60 def configure_endpoints(ixnet, topologies, args):
61 """Configure endpoints with topologies.
63 :param ixnet: Instance of IxNet class.
64 :param topologies: List of topologies.
65 :param args: Arguments from command line.
67 :type topologies: list
68 :type args: ArgumentParser
69 :return: Traffic items
74 raise ValueError('No Ixnet instance')
75 if topologies is None:
76 raise ValueError('No topologies created')
80 if args.traffic_type == 'ethernetVlan':
81 path = '/deviceGroup:1/ethernet:1'
82 elif args.traffic_type == 'ipv4':
83 path = '/deviceGroup:1/ethernet:1/ipv4:1'
84 elif args.traffic_type == 'ipv6':
85 path = '/deviceGroup:1/ethernet:1/ipv6:1'
87 raise ValueError('Traffic type not supported')
89 if args.pairing == 'full':
90 pairing = zip(topologies, topologies[1:])[::2]
91 elif args.pairing == 'half':
92 step = len(args.if_port)/2
93 pairing = zip(topologies, topologies[step:])[::1]
95 raise ValueError('Pairing type not supported')
97 # Pairing endpoints and assigning them into traffic items
98 for topo1, topo2 in pairing:
101 topo1_name = ixnet.getAttribute(topo1, '-name')
102 topo2_name = ixnet.getAttribute(topo2, '-name')
103 traffic_item = configure_traffic_item(ixnet, topo1_name, src, dst,
104 args.frame_size, args.rate,
107 traffic_items.append(traffic_item)
108 traffic_item = configure_traffic_item(ixnet, topo2_name, dst, src,
109 args.frame_size, args.rate,
112 traffic_items.append(traffic_item)
117 def configure_traffic_item(ixnet, name, src_ep, dst_ep, frame_size,
118 rate, rate_units, traffic_type):
119 """Create and configure traffic item.
121 :param ixnet: Instance of IxNet class.
122 :param name: Name of traffic profile.
123 :param src_ep: Source topology endpoint.
124 :param dst_ep: Destination topology endpoint.
125 :param frame_size: L2 frame size.
127 :param rate_units: Rate type (pps, perc, bps).
128 :param traffic_type: Traffic type (ipv4, ipv6, ethernetVlan).
133 :type frame_size: int
135 :type rate_units: str
136 :type traffic_type: str
137 :return: Created traffic item string.
142 raise ValueError('No Ixnet instance')
143 if traffic_type == 'ipv4':
145 raise ValueError('Min. frame size for traffic type is 64B')
146 elif traffic_type == 'ipv6':
148 raise ValueError('Min. frame size for traffic type is 78B')
149 elif traffic_type == 'ethernetVlan':
151 raise ValueError('Min. frame size for traffic type is 64B')
153 raise ValueError('Traffic type not supported')
155 ixnet.add(ixnet.getRoot() + '/traffic', 'trafficItem')
157 traffic_item = ixnet.getList(ixnet.getRoot() + '/traffic',
159 ixnet.setMultiAttribute(traffic_item,
161 '-trafficType', traffic_type,
162 '-allowSelfDestined', False,
163 '-trafficItemType', 'l2L3',
164 '-mergeDestinations', True,
165 '-egressEnabled', False,
166 '-srcDestMesh', 'oneToOne',
168 '-routeMesh', 'oneToOne',
169 '-transmitMode', 'interleaved',
170 '-biDirectional', False,
171 '-hostsPerNetwork', 1)
172 ixnet.setAttribute(traffic_item, '-trafficType', traffic_type)
173 ixnet.add(traffic_item, 'endpointSet',
175 '-destinations', dst_ep,
176 '-name', 'endpointSet1')
177 ixnet.setMultiAttribute(traffic_item + '/configElement:1/frameSize',
179 '-fixedSize', frame_size)
182 # Use 4 Byte Signature
183 ixnet.setAttribute(ixnet.getRoot() + '/traffic', '-enableMinFrameSize',
187 if rate_units == 'pps':
188 ixnet.setMultiAttribute(traffic_item + '/configElement:1/frameRate',
189 '-type', 'framesPerSecond',
191 elif rate_units == '%':
192 ixnet.setMultiAttribute(traffic_item + '/configElement:1/frameRate',
193 '-type', 'percentLineRate',
195 elif rate_units == 'bps':
196 ixnet.setMultiAttribute(traffic_item + '/configElement:1/frameRate',
197 '-type', 'bitsPerSecond',
200 raise ValueError('Rate type not supported')
202 ixnet.setMultiAttribute(traffic_item + '/configElement:1/transmissionControl',
203 '-type', 'continuous')
204 ixnet.setMultiAttribute(traffic_item + "/tracking",
205 '-trackBy', ['trackingenabled0'])
208 # Get Full packet stack
209 flow_group = ixnet.remapIds(traffic_item)[0]
210 highlevel_stream = ixnet.getList(flow_group, 'highLevelStream')[0]
211 traffic_stacks = ixnet.getList(highlevel_stream, 'stack')
216 def configure_protocols(ixnet, vports, args):
217 """Create and configure topologies and protocols.
219 :param ixnet: Instance of IxNet class.
220 :param vports: List of ports added to configuration.
221 :param args: Arguments from command line.
224 :type args: ArgumentParser
225 :return: Topologies list
230 raise ValueError('No Ixnet instance')
232 raise ValueError('Vports is Null')
238 ixnet.add(ixnet.getRoot(), 'topology')
242 topologies = ixnet.getList(ixnet.getRoot(), 'topology')
245 # Pair topology with vport and add device group for each
246 for topology, vport in zip(topologies, vports):
247 # Add ports to topologies
248 ixnet.setAttribute(topology, '-vports', vport)
249 # Add device groups to topologies
250 ixnet.add(topology, 'deviceGroup')
252 device_groups.append(ixnet.getList(topology, 'deviceGroup')[0])
255 # Add ethernet protocol stacks to device groups
256 for device_group, cnt in zip(device_groups, args.port_src_ip_cnt):
257 ixnet.setAttribute(device_group, '-multiplier', cnt)
258 ixnet.add(device_group, 'ethernet')
260 ethernets.append(ixnet.getList(device_group, 'ethernet')[0])
262 for i, ethernet in enumerate(ethernets):
263 mac = ixnet.getAttribute(ethernet, '-mac')
264 ixnet.setAttribute(mac + '/singleValue', \
265 '-value', args.port_src_mac[i])
267 if args.traffic_type == 'ipv4':
269 # Add ipv4 protocol stacks to device groups
270 for ethernet in ethernets:
271 ixnet.add(ethernet, 'ipv4')
273 ipv4s.append(ixnet.getList(ethernet, 'ipv4')[0])
275 configure_ipv4_protocol(ixnet, ipv4s, args)
276 elif args.traffic_type == 'ipv6':
278 # Add ipv6 protocol stacks to device groups
279 for ethernet in ethernets:
280 ixnet.add(ethernet, 'ipv6')
282 ipv6s.append(ixnet.getList(ethernet, 'ipv6')[0])
284 configure_ipv6_protocol(ixnet, ipv6s, args)
285 elif args.traffic_type == 'ethernetVlan':
286 # TODO: fix this profile
288 # Add ipv4 protocol stacks to device groups
289 for ethernet in ethernets:
290 ixnet.add(ethernet, 'ipv4')
292 ipv4s.append(ixnet.getList(ethernet, 'ipv4')[0])
294 configure_ethernetVlan_protocol(ixnet, ipv4s, args)
296 raise ValueError('Traffic type not supported')
301 def configure_ethernetVlan_protocol(ixnet, ipv4s, args):
302 """Configure ethernet protocol.
304 :param ixnet: Instance of IxNet class.
305 :param ipv4s: List of ipv4 protocols.
306 :param args: Args from command line.
307 :type ixnet: IxNetwork
309 :type args: ArgumentParser
314 raise ValueError('No Ixnet instance')
316 for i, ipv4 in enumerate(ipv4s):
317 address = ixnet.getAttribute(ipv4, '-address')
318 gatewayIp = ixnet.getAttribute(ipv4, '-gatewayIp')
319 resolveGateway = ixnet.getAttribute(ipv4, '-resolveGateway')
320 gatewayMac = ixnet.getAttribute(ipv4, '-manualGatewayMac')
322 ixnet.setMultiAttribute(address + '/counter', \
323 '-direction', 'increment', \
324 '-start', args.port_src_ip[i], \
326 ixnet.setMultiAttribute(resolveGateway + '/singleValue', \
332 def configure_ipv4_protocol(ixnet, ipv4s, args):
333 """Configure ipv4 protocol.
335 :param ixnet: Instance of IxNet class.
336 :param ipv4s: List of ipv4 protocols.
337 :param args: Args from command line.
338 :type ixnet: IxNetwork
340 :type args: ArgumentParser
345 raise ValueError('No Ixnet instance')
347 for i, ipv4 in enumerate(ipv4s):
348 address = ixnet.getAttribute(ipv4, '-address')
349 gatewayIp = ixnet.getAttribute(ipv4, '-gatewayIp')
350 resolveGateway = ixnet.getAttribute(ipv4, '-resolveGateway')
351 gatewayMac = ixnet.getAttribute(ipv4, '-manualGatewayMac')
353 ixnet.setMultiAttribute(address + '/counter', \
354 '-direction', 'increment', \
355 '-start', args.port_src_ip[i], \
357 ixnet.setMultiAttribute(gatewayIp + '/singleValue', \
358 '-value', args.port_gw_ip[i])
359 ixnet.setMultiAttribute(resolveGateway + '/singleValue', \
361 ixnet.setMultiAttribute(gatewayMac + '/singleValue', \
362 '-value', args.port_gw_mac[i])
367 def configure_ipv6_protocol(ixnet, ipv6s, args):
368 """Configure ipv6 protocol.
370 :param ixnet: Instance of IxNet class.
371 :param ipv6s: List of ipv6 protocols.
372 :param args: Args from command line.
373 :type ixnet: IxNetwork
375 :type args: ArgumentParser
380 raise ValueError('No Ixnet instance')
382 for i, ipv6 in enumerate(ipv6s):
383 address = ixnet.getAttribute(ipv6, '-address')
384 gatewayIp = ixnet.getAttribute(ipv6, '-gatewayIp')
385 resolveGateway = ixnet.getAttribute(ipv6, '-resolveGateway')
386 gatewayMac = ixnet.getAttribute(ipv6, '-manualGatewayMac')
388 ixnet.setMultiAttribute(address + '/counter', \
389 '-direction', 'increment', \
390 '-start', args.port_src_ip[i], \
392 ixnet.setMultiAttribute(gatewayIp + '/singleValue', \
393 '-value', args.port_gw_ip[i])
394 ixnet.setMultiAttribute(resolveGateway + '/singleValue', \
396 ixnet.setMultiAttribute(gatewayMac + '/singleValue', \
397 '-value', args.port_gw_mac[i])
402 def assign_physical_interfaces(ixnet, ixinterfaces):
403 """Assign physical interfaces on chassis.
405 :param ixnet: Instance of IxNet class.
406 :param ixinterfaces: List of physical interfaces (chassis/card/port).
408 :type ixinterfaces: list
412 vports = ixnet.getList(ixnet.getRoot(), 'vport')
413 assign_ifs = ixnet.execute('assignPorts', ixinterfaces, [],
414 ixnet.getList("/", "vport"), True)
415 if assign_ifs != vports:
416 raise IxDriverError("Assigning ports failed: {}".format(assign_ifs))
419 def apply_traffic(ixnet, traffic_items):
420 """Generate, apply all traffic items.
422 :param ixnet: Instance of IxNet class.
423 :param traffic_items: List of traffic items.
425 :type traffic_items: list
430 raise ValueError('No Ixnet instance')
431 if traffic_items is None:
432 raise ValueError('No traffic items')
434 for traffic_item in traffic_items:
435 ixnet.execute('generate', traffic_item)
437 ixnet.execute('apply', ixnet.getRoot() + '/traffic')
440 def start_traffic(ixnet):
441 """Start traffic on all traffic items.
443 :param ixnet: Instance of IxNet class.
449 raise ValueError('No Ixnet instance')
451 ixnet.execute('start', ixnet.getRoot() + '/traffic')
454 def stop_traffic(ixnet):
455 """Stop traffic on all traffic items.
457 :param ixnet: Instance of IxNet class.
463 raise ValueError('No Ixnet instance')
465 ixnet.execute('stop', ixnet.getRoot() + '/traffic')
468 def process_statistics(ixnet):
469 """Process the statistics.
471 :param ixnet: Instance of IxNet class.
477 raise ValueError('No Ixnet instance')
479 viewName = "Traffic Item Statistics"
480 views = ixnet.getList('/statistics', 'view')
482 editedViewName = '::ixNet::OBJ-/statistics/view:\"' + viewName + '\"'
484 if editedViewName == view:
488 txFrames = ixnet.execute('getColumnValues', viewObj, 'Tx Frames')
489 rxFrames = ixnet.execute('getColumnValues', viewObj, 'Rx Frames')
490 loss = ixnet.execute('getColumnValues', viewObj, 'Loss %')
491 delta = ixnet.execute('getColumnValues', viewObj, 'Frames Delta')
492 SFavg = ixnet.execute('getColumnValues', viewObj,
493 'Store-Forward Avg Latency (ns)')
494 SFmin = ixnet.execute('getColumnValues', viewObj,
495 'Store-Forward Min Latency (ns)')
496 SFmax = ixnet.execute('getColumnValues', viewObj,
497 'Store-Forward Max Latency (ns)')
499 print txFrames, rxFrames, loss, delta, SFavg, SFmin, SFmax
502 def print_error(msg):
503 """Print error message on stderr.
505 :param msg: Error message to print.
510 sys.stderr.write(msg+'\n')
514 """Parse arguments from cmd line.add_ports
516 :return: Parsed arguments.
517 :rtype ArgumentParser
520 parser = argparse.ArgumentParser()
521 parser.add_argument("-i", "--ixia_server", required=True,
522 help="IxNetwork TCL server")
523 parser.add_argument("-p", "--ixia_port", required=True, type=int,
524 help="IxNetwork TCL port")
525 parser.add_argument("-d", "--duration", required=True, type=int,
526 help="Duration of traffic run in seconds")
527 parser.add_argument("-s", "--frame_size", required=True, type=int,
528 help="Size of a Frame without padding and IPG")
529 parser.add_argument("-r", "--rate", required=True,
530 help="Traffic rate with")
531 parser.add_argument("-u", "--rate_units", required=True,
532 choices=['pps', 'perc', 'bps'],
533 help="Traffic rate units")
534 parser.add_argument("-t", "--traffic_type", required=True,
535 choices=['ipv4', 'ipv6', 'ethernetVlan'],
537 parser.add_argument("--async", action="store_true",
539 help="Non-blocking call of the script")
540 parser.add_argument("-w", "--warmup_time", type=int,
542 help="Traffic warmup time in seconds, 0 = disable")
543 parser.add_argument("-x", "--pairing", choices=['full', 'half'],
545 help="Pairing of ports e.g. (1,2)(3,4) or (1,3)(2,4)")
547 parser.add_argument('--if_chassis', nargs='+', default=[],
549 help='Add Ixia chassis to a list')
550 parser.add_argument('--if_card', nargs='+', default=[],
551 required=True, type=int,
552 help='Add Ixia card to a list')
553 parser.add_argument('--if_port', nargs='+', default=[],
554 required=True, type=int,
555 help='Add Ixia port to a list')
556 parser.add_argument('--port_src_mac', nargs='+', default=[],
558 help='Add port source mac address to a list')
559 parser.add_argument('--port_src_mac_cnt', nargs='+', default=[],
561 help='Add port source mac address count to a list')
562 parser.add_argument('--port_src_ip', nargs='+', default=[],
564 help='Add port source IP address to a list')
565 parser.add_argument('--port_src_ip_cnt', nargs='+', default=[],
566 required=True, type=int,
567 help='Add port source IP address count to a list')
568 parser.add_argument('--port_gw_ip', nargs='+', default=[],
569 help='Add port gateway IP address to a list')
570 parser.add_argument('--port_gw_mac', nargs='+', default=[],
571 help='Add port gateway mac address to a list')
573 return parser.parse_args()
579 # Parse comand line arguments
583 for chassis, card, port in zip(args.if_chassis,
586 ix_interfaces.append((chassis, card, port))
589 # Create IXIA instance
595 # Conntect to IxServer
596 ixnet.connect(args.ixia_server, '-port', args.ixia_port, '-version',
599 # Create blank configuration
600 ixnet.execute('newConfig')
602 # Add interfaces to config
603 vports = add_ports(ixnet, len(ix_interfaces))
605 # Configure protocols
606 topologies = configure_protocols(ixnet, vports, args)
608 # Create traffic items
609 traffic_items = configure_endpoints(ixnet, topologies, args)
611 # Assign physical interfaces on chassis
612 assign_physical_interfaces(ixnet, ix_interfaces)
614 # Generate and apply traffic
615 apply_traffic(ixnet, traffic_items)
617 if args.warmup_time > 0:
620 # Wait for warmup time
621 time.sleep(args.warmup_time)
624 # Wait for incomming packets
631 # Wait for duration time
632 time.sleep(args.duration)
635 # Wait for incomming packets
638 process_statistics(ixnet)
639 except Exception as ex_error:
640 print_error(str(ex_error))
647 if __name__ == "__main__":