# Description # # Customers who has legacy IxExplorer-FT HL API scripts and need to # convert scripts to IxNetwork. # # Mainly because the IxExplorer-FT scripts are not supported in IxNetwork # after version 6.80. # # The solution is to use IxNetwork Quick Flow Group, which is designed for # IxExplorer usage in IxNetwork. # # This script is a sample to show how to use customer's existing HL API parameters/values # and automatically ... # - Create a Quick Flow Group (Traffic Item) # - Get all the configured vports and add all vports to the HLAPI parameter -port_handle2 # as receiving ports. # - Enable traffic item Ingress tracking. # - Regenerate Traffic Item. # - Start traffic # - Get Port Statistics stats. # - Look for all the ports that received traffic. # # All you need to get out of this script are: # - ConfigQuickFlowGroup() # - GetVportConnectedToPortPy() # Supports Python2.7 and Python3 from __future__ import absolute_import, print_function, division import sys, os import time, re from ixiatcl import IxiaTcl from ixiahlt import IxiaHlt from ixiangpf import IxiaNgpf from ixiaerror import IxiaError ixia_tcl = IxiaTcl() ixia_hlt = IxiaHlt(ixia_tcl) ixia_ngpf = IxiaNgpf(ixia_hlt) ixNet = ixia_ngpf.ixnet ;# For low level Python API commands ixnetwork_tcl_server = '192.168.70.3' port_1 = '1/1/1' port_2 = '1/2/1' username = 'hgee' # Convert vport to physical port def GetVportConnectedToPortPy(vport): # Return the physical port of the vport # ::ixNet::OBJ-/availableHardware/chassis:"10.205.4.35"/card:1/port:1 connectedTo = ixNet.getAttribute(vport, '-connectedTo') connectedTo = connectedTo.split('/')[3:] card = connectedTo[0].split(':')[1] port = connectedTo[1].split(':')[1] return '1/'+card+'/'+port def ConfigQuickFlowGroup(**trafficParams): """ Desciption Using IxExplorer-FT HL APIs to configure IxNetwork Quick Flow Group. For Quick Flow Group, only one QFG is allowed and required. If you have multiple streams, they all fall under this QFG. """ print('\nExisting Traffic Item:', ixNet.getList(ixNet.getRoot()+'/traffic', 'trafficItem') ) portHandle = trafficParams['port_handle'] if ixNet.getList(ixNet.getRoot()+'/traffic', 'trafficItem') == []: print('\nCreating new traffic item for Quick Flow Group') quickFlowGroupObj = ixNet.add(ixNet.getRoot()+'/traffic', 'trafficItem') ixNet.setMultiAttribute(quickFlowGroupObj ,'-trafficItemType', 'quick', '-trafficType', 'raw') ixNet.commit() quickFlowGroupObj = ixNet.remapIds(quickFlowGroupObj)[0] print('QuickFlowGroupObj:', quickFlowGroupObj) print('ConfigQuickFlowGroup:', trafficParams['name']) # Get a list of all the configured ports as the receiving ports. portList = [] for eachVport in ixNet.getList(ixNet.getRoot(), 'vport'): port = GetVportConnectedToPortPy(eachVport) # Don't include the Tx port into the receiving list of ports if portHandle != port: portList.append(port) print('\nAll vport list for Rx ports:', portList) # Insert additional parameters to make Quick Flow Group work trafficParams.update({'port_handle': portHandle, 'port_handle2': ' '.join(portList), 'circuit_type':'quick_flows'}) print('\nConfiguring HLT params:', trafficParams) result = ixia_hlt.traffic_config(**trafficParams) print('\nResult:', result) # Enable ingress tracking print('\nEnabling Quick Flow Group statistics tracking') quickFlowGroupObj = ixNet.getList(ixNet.getRoot()+'/traffic', 'trafficItem')[0] status = ixNet.setAttribute(quickFlowGroupObj + '/tracking', '-trackBy', ['trackingenabled0']) print('\n--- ingregressTracking status:', status) ixNet.commit() def RegenerateAllTrafficItemsPy(): for trafficItem in ixNet.getList(ixNet.getRoot()+'/traffic', 'trafficItem'): result = ixNet.execute('generate', trafficItem) if result != '::ixNet::OK': print('\nRegenerate_All_TrafficItems failed: ', trafficItem) ixNet.disconnect() sys.exit() def StartTrafficNgpfHlPy(): print('\nStartTrafficNgpfHlPy') status = ixia_ngpf.traffic_control(action = 'run') if status == 1: print('\nStartTrafficNgpfHlPy failed: ', status['log']) return 1 return status def GetStatsPy( getStatsBy='Flow Statistics', csvFile=None, csvEnableFileTimestamp=False): ''' Description: This API will return you a Python Dict of all the stats based on your specified stats. The exact stat name could be found on your IxNetwork GUI statistic tablets. Parameters: getStatsBy = The exact name of the stat that could be found on the IxNetwork GUI. csvFile = The name of the CSV file that you want to store stats in. csvEnableFileTimestamp = Append a timestamp to the CSV file so they don't get overwritten. This should only be used for getting the final stat result such as when the traffic has completely stopped. getStatsBy options (case sensitive): "Port Statistics" "Tx-Rx Frame Rate Statistics" "Port CPU Statistics" "Global Protocol Statistics" "Protocols Summary" "Port Summary" "OSPFv2-RTR Drill Down" "OSPFv2-RTR Per Port" "IPv4 Drill Down" "L2-L3 Test Summary Statistics" "Flow Statistics" "Traffic Item Statistics" ''' viewList = ixNet.getList(ixNet.getRoot()+'/statistics', 'view') statViewSelection = getStatsBy try: statsViewIndex = viewList.index('::ixNet::OBJ-/statistics/view:"' + getStatsBy +'"') except Exception as errMsg: sys.exit('\nNo such statistic name: %s' % getStatsBy) # ::ixNet::OBJ-/statistics/view:"Flow Statistics" view = viewList[statsViewIndex] columnList = ixNet.getAttribute(view+'/page', '-columnCaptions') #print '\n', columnList if csvFile != None: import csv csvFileName = csvFile.replace(' ', '_') if csvEnableFileTimestamp: import datetime timestamp = datetime.datetime.now().strftime('%H%M%S') if '.' in csvFileName: csvFileNameTemp = csvFileName.split('.')[0] csvFileNameExtension = csvFileName.split('.')[1] csvFileName = csvFileNameTemp+'_'+timestamp+'.'+csvFileNameExtension else: csvFileName = csvFileName+'_'+timestamp csvFile = open(csvFileName, 'w') csvWriteObj = csv.writer(csvFile) csvWriteObj.writerow(columnList) startTime = 1 stopTime = 30 for timer in range(startTime, stopTime + 1): totalPages = ixNet.getAttribute(view+'/page', '-totalPages') if totalPages == 'null': print('GetStatView: Getting total pages for %s is not ready: %s/%s' % (getStatsBy, startTime, stopTime)) time.sleep(2) else: break row = 0 statDict = {} print('\nPlease wait for all the stats to be queried ...') for currentPage in range(1, int(totalPages)+1): ixNet.setAttribute(view+'/page', '-currentPage', currentPage) ixNet.commit() whileLoopStopCounter = 0 while (ixNet.getAttribute(view+'/page', '-isReady')) != 'true': if whileLoopStopCounter == 5: print('\nGetStatView: Could not get stats') return 1 if whileLoopStopCounter < 5: print('\nGetStatView: Not ready yet. Waiting %s/5 seconds ...' % whileLoopStopCounter) time.sleep(1) whileLoopStopCounter += 1 pageList = ixNet.getAttribute(view+'/page', '-rowValues') totalFlowStatistics = len(pageList) for pageListIndex in range(0, totalFlowStatistics): rowList = pageList[pageListIndex] if csvFile != None: csvWriteObj.writerow(rowList[0]) for rowIndex in range(0, len(rowList)): row += 1 cellList = rowList[rowIndex] statDict[row] = {} # CellList: ['Ethernet - 002', 'Ethernet - 001', 'OSPF T1 to T2', '206.27.0.0-201.27.0.0', 'OSPF T1 to T2-FlowGroup-1 - Flow Group 0002', '1225', '1225', '0', '0', '0', '0', '0', '0', '156800', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '00:00:00.781', '00:00:00.849'] index = 0 for statValue in cellList: statDict[row].update({columnList[index]: statValue}) index += 1 if csvFile != None: csvFile.close() return statDict def PrintDict(obj, nested_level=0, output=sys.stdout): """ Description Print each dict key with indentions for human readability. """ spacing = ' ' spacing2 = ' ' if type(obj) == dict: print( '%s' % ((nested_level) * spacing), file=output) for k, v in obj.items(): if hasattr(v, '__iter__'): print('%s%s:' % ( (nested_level+1) * spacing, k), file=output, end='') PrintDict(v, nested_level+1, output) else: print('%s%s: %s' % ( (nested_level + 1) * spacing, k, v), file=output) print('%s' % (nested_level * spacing), file=output) elif type(obj) == list: print('%s[' % ((nested_level) * spacing), file=output) for v in obj: if hasattr(v, '__iter__'): PrintDict(v, nested_level + 1, file=output) else: print('%s%s' % ((nested_level + 1) * spacing, v), file=output) print('%s]' % ((nested_level) * spacing), output) else: print('%s%s' % ((nested_level * spacing2), obj), file=output) trafficItem1 = { 'name': 'rule1', 'port_handle': port_1, 'mode': 'create', 'mac_dst_mode' : 'fixed', 'mac_src_mode' : 'fixed', 'mac_src' : '00:0C:29:AA:86:E0', 'mac_dst' : '00:0C:29:84:37:16', 'transmit_mode': 'single_burst', 'rate_pps' : 1000, 'l3_protocol': 'ipv4', 'ip_src_addr': '1.1.1.1', 'ip_src_mode': 'increment', 'ip_src_step': '0.0.0.1', 'ip_src_count': '1', 'ip_dst_addr': '1.1.1.2', 'ip_dst_mode':'increment', 'ip_dst_step': '0.0.0.1', 'ip_dst_count': '1', 'rate_percent': '10', 'frame_size': '1000', 'bidirectional': '0', 'number_of_packets_per_stream': 50000 } trafficItem2 = { 'name': 'rule2', 'port_handle': port_1, 'mode': 'create', 'mac_dst_mode' : 'fixed', 'mac_src_mode' : 'fixed', 'mac_src' : '00:0C:29:84:37:16', 'mac_dst' : '00:0C:29:AA:86:E0', 'transmit_mode': 'single_burst', 'rate_pps' : 1000, 'l3_protocol': 'ipv4', 'ip_src_addr': '1.1.1.2', 'ip_src_mode': 'increment', 'ip_src_step': '0.0.0.1', 'ip_src_count': '1', 'ip_dst_addr': '1.1.1.1', 'ip_dst_mode':'increment', 'ip_dst_step': '0.0.0.1', 'ip_dst_count': '1', 'rate_percent': '10', 'frame_size': '1000', 'bidirectional': '0', 'number_of_packets_per_stream': 50000 } connect_result = ixia_ngpf.connect ( ixnetwork_tcl_server = ixnetwork_tcl_server, username = username, break_locks = '1' ) PrintDict(connect_result) ConfigQuickFlowGroup(**trafficItem1) #ConfigQuickFlowGroup(**trafficItem2) RegenerateAllTrafficItemsPy() StartTrafficNgpfHlPy() time.sleep(15) traffic_stats = GetStatsPy(getStatsBy='Port Statistics') PrintDict(traffic_stats) # TODO: Look for all the ports that received traffic