dpdk_setup_ports.py revision e939511a
1#! /usr/bin/python
2# hhaim
3import sys
4import os
5python_ver = 'python%s' % sys.version_info[0]
6sys.path.append(os.path.join('external_libs', 'pyyaml-3.11', python_ver))
7import yaml
8import dpdk_nic_bind
9import re
10import argparse
11import copy
12import shlex
13import traceback
14from collections import defaultdict, OrderedDict
15from distutils.util import strtobool
16
17class ConfigCreator(object):
18    mandatory_interface_fields = ['Slot_str', 'src_mac', 'dest_mac', 'Device_str', 'NUMA']
19    _2hex_re = '[\da-fA-F]{2}'
20    mac_re = re.compile('^({0}:){{5}}{0}$'.format(_2hex_re))
21
22    # cpu_topology - dict: physical processor -> physical core -> logical processing unit (thread)
23    # interfaces - array of dicts per interface, should include "mandatory_interface_fields" values
24    def __init__(self, cpu_topology, interfaces, include_lcores = [], exclude_lcores = [], only_first_thread = False, zmq_rpc_port = None, zmq_pub_port = None, prefix = None, ignore_numa = False):
25        self.cpu_topology = copy.deepcopy(cpu_topology)
26        self.interfaces   = copy.deepcopy(interfaces)
27        del cpu_topology
28        del interfaces
29        assert isinstance(self.cpu_topology, dict), 'Type of cpu_topology should be dict, got: %s' % type(self.cpu_topology)
30        assert len(self.cpu_topology.keys()) > 0, 'cpu_topology should contain at least one processor'
31        assert isinstance(self.interfaces, list), 'Type of interfaces should be list, got: %s' % type(list)
32        assert len(self.interfaces) % 2 == 0, 'Should be even number of interfaces, got: %s' % len(self.interfaces)
33        assert len(self.interfaces) >= 2, 'Should be at least two interfaces, got: %s' % len(self.interfaces)
34        assert isinstance(include_lcores, list), 'include_lcores should be list, got: %s' % type(include_lcores)
35        assert isinstance(exclude_lcores, list), 'exclude_lcores should be list, got: %s' % type(exclude_lcores)
36        assert len(self.interfaces) >= 2, 'Should be at least two interfaces, got: %s' % len(self.interfaces)
37        if only_first_thread:
38            for cores in self.cpu_topology.values():
39                for core in cores.keys():
40                    cores[core] = cores[core][:1]
41        include_lcores = [int(x) for x in include_lcores]
42        exclude_lcores = [int(x) for x in exclude_lcores]
43        self.has_zero_lcore = False
44        for numa, cores in self.cpu_topology.items():
45            for core, lcores in cores.items():
46                for lcore in copy.copy(lcores):
47                    if include_lcores and lcore not in include_lcores:
48                        cores[core].remove(lcore)
49                    if exclude_lcores and lcore in exclude_lcores:
50                        cores[core].remove(lcore)
51                if 0 in lcores:
52                    self.has_zero_lcore = True
53                    cores[core].remove(0)
54                    zero_lcore_numa = numa
55                    zero_lcore_core = core
56                    zero_lcore_siblings = cores[core]
57        if self.has_zero_lcore:
58            del self.cpu_topology[zero_lcore_numa][zero_lcore_core]
59            self.cpu_topology[zero_lcore_numa][zero_lcore_core] = zero_lcore_siblings
60        Device_str = None
61        for interface in self.interfaces:
62            for mandatory_interface_field in ConfigCreator.mandatory_interface_fields:
63                if mandatory_interface_field not in interface:
64                    raise DpdkSetup("Expected '%s' field in interface dictionary, got: %s" % (mandatory_interface_field, interface))
65            if Device_str is None:
66                Device_str = interface['Device_str']
67            elif Device_str != interface['Device_str']:
68                raise DpdkSetup('Interfaces should be of same type, got:\n\t* %s\n\t* %s' % (Device_str, interface['Device_str']))
69        if '40Gb' in Device_str:
70            self.speed = 40
71        else:
72            self.speed = 10
73        lcores_per_numa = OrderedDict()
74        system_lcores = int(self.has_zero_lcore)
75        for numa, core in self.cpu_topology.items():
76            for lcores in core.values():
77                if numa not in lcores_per_numa:
78                    lcores_per_numa[numa] = []
79                lcores_per_numa[numa].extend(lcores)
80                system_lcores += len(lcores)
81        minimum_required_lcores = len(self.interfaces) / 2 + 2
82        if system_lcores < minimum_required_lcores:
83            raise DpdkSetup('Your system should have at least %s cores for %s interfaces, and it has: %s.' %
84                    (minimum_required_lcores, len(self.interfaces), system_lcores + (0 if self.has_zero_lcore else 1)))
85        interfaces_per_numa = defaultdict(int)
86        for i in range(0, len(self.interfaces), 2):
87            if self.interfaces[i]['NUMA'] != self.interfaces[i+1]['NUMA'] and not ignore_numa:
88                raise DpdkSetup('NUMA of each pair of interfaces should be same, got NUMA %s for client interface %s, NUMA %s for server interface %s' %
89                        (self.interfaces[i]['NUMA'], self.interfaces[i]['Slot_str'], self.interfaces[i+1]['NUMA'], self.interfaces[i+1]['Slot_str']))
90            interfaces_per_numa[self.interfaces[i]['NUMA']] += 2
91        self.lcores_per_numa     = lcores_per_numa
92        self.interfaces_per_numa = interfaces_per_numa
93        self.prefix              = prefix
94        self.zmq_pub_port        = zmq_pub_port
95        self.zmq_rpc_port        = zmq_rpc_port
96        self.ignore_numa         = ignore_numa
97
98    def _convert_mac(self, mac_string):
99        if not ConfigCreator.mac_re.match(mac_string):
100            raise DpdkSetup('MAC address should be in format of 12:34:56:78:9a:bc, got: %s' % mac_string)
101        return ', '.join([('0x%s' % elem).lower() for elem in mac_string.split(':')])
102
103    def create_config(self, filename = None, print_config = False):
104        config_str = '### Config file generated by dpdk_setup_ports.py ###\n\n'
105        config_str += '- port_limit: %s\n' % len(self.interfaces)
106        config_str += '  version: 2\n'
107        config_str += "  interfaces: ['%s']\n" % "', '".join([interface['Slot_str'] for interface in self.interfaces])
108        if self.speed > 10:
109            config_str += '  port_bandwidth_gb: %s\n' % self.speed
110        if self.prefix:
111            config_str += '  prefix: %s\n' % self.prefix
112        if self.zmq_pub_port:
113            config_str += '  zmq_pub_port: %s\n' % self.zmq_pub_port
114        if self.zmq_rpc_port:
115            config_str += '  zmq_rpc_port: %s\n' % self.zmq_rpc_port
116        config_str += '  port_info:\n'
117        for index, interface in enumerate(self.interfaces):
118            config_str += ' '*6 + '- dest_mac: [%s]' % self._convert_mac(interface['dest_mac'])
119            if interface.get('loopback_dest'):
120                config_str += " # MAC OF LOOPBACK TO IT'S DUAL INTERFACE\n"
121            else:
122                config_str += '\n'
123            config_str += ' '*8 + 'src_mac:  [%s]\n' % self._convert_mac(interface['src_mac'])
124            if index % 2:
125                config_str += '\n' # dual if barrier
126        if not self.ignore_numa:
127            config_str += '  platform:\n'
128            if len(self.interfaces_per_numa.keys()) == 1 and -1 in self.interfaces_per_numa: # VM, use any cores, 1 core per dual_if
129                lcores_pool = sorted([lcore for lcores in self.lcores_per_numa.values() for lcore in lcores])
130                config_str += ' '*6 + 'master_thread_id: %s\n' % (0 if self.has_zero_lcore else lcores_pool.pop())
131                config_str += ' '*6 + 'latency_thread_id: %s\n' % lcores_pool.pop(0)
132                config_str += ' '*6 + 'dual_if:\n'
133                for i in range(0, len(self.interfaces), 2):
134                    config_str += ' '*8 + '- socket: 0\n'
135                    config_str += ' '*10 + 'threads: [%s]\n\n' % lcores_pool.pop(0)
136            else:
137                # we will take common minimum among all NUMAs, to satisfy all
138                lcores_per_dual_if = 99
139                extra_lcores = 1 if self.has_zero_lcore else 2
140                # worst case 3 iterations, to ensure master and "rx" have cores left
141                while (lcores_per_dual_if * sum(self.interfaces_per_numa.values()) / 2) + extra_lcores > sum([len(lcores) for lcores in self.lcores_per_numa.values()]):
142                    lcores_per_dual_if -= 1
143                    for numa, cores in self.lcores_per_numa.items():
144                        if not self.interfaces_per_numa[numa]:
145                            continue
146                        lcores_per_dual_if = min(lcores_per_dual_if, int(2 * len(cores) / self.interfaces_per_numa[numa]))
147                lcores_pool = copy.deepcopy(self.lcores_per_numa)
148                # first, allocate lcores for dual_if section
149                dual_if_section = ' '*6 + 'dual_if:\n'
150                for i in range(0, len(self.interfaces), 2):
151                    numa = self.interfaces[i]['NUMA']
152                    dual_if_section += ' '*8 + '- socket: %s\n' % numa
153                    lcores_for_this_dual_if = [str(lcores_pool[numa].pop(0)) for _ in range(lcores_per_dual_if)]
154                    if not lcores_for_this_dual_if:
155                        raise DpdkSetup('Not enough cores at NUMA %s. This NUMA has %s processing units and %s interfaces.' % (numa, len(self.lcores_per_numa[numa]), self.interfaces_per_numa[numa]))
156                    dual_if_section += ' '*10 + 'threads: [%s]\n\n' % ','.join(lcores_for_this_dual_if)
157                # take the cores left to master and rx
158                lcores_pool_left = [lcore for lcores in lcores_pool.values() for lcore in lcores]
159                config_str += ' '*6 + 'master_thread_id: %s\n' % (0 if self.has_zero_lcore else lcores_pool_left.pop(0))
160                config_str += ' '*6 + 'latency_thread_id: %s\n' % lcores_pool_left.pop(0)
161                # add the dual_if section
162                config_str += dual_if_section
163
164        # verify config is correct YAML format
165        try:
166            yaml.safe_load(config_str)
167        except Exception as e:
168            raise DpdkSetup('Could not create correct yaml config.\nGenerated YAML:\n%s\nEncountered error:\n%s' % (config_str, e))
169
170        if filename:
171            if os.path.exists(filename):
172                result = None
173                try:
174                    result = strtobool(raw_input('File %s already exist, overwrite? (y/N)' % filename))
175                except:
176                    pass
177                finally:
178                    if not result:
179                        print('Skipping.')
180                        return config_str
181            with open(filename, 'w') as f:
182                f.write(config_str)
183            print('Saved.')
184        if print_config:
185            print(config_str)
186        return config_str
187
188
189class map_driver(object):
190    args=None;
191    cfg_file='/etc/trex_cfg.yaml'
192    parent_cfg = None
193    dump_interfaces = None
194
195class DpdkSetup(Exception):
196    pass
197
198class CIfMap:
199
200    def __init__(self, cfg_file):
201        self.m_cfg_file =cfg_file;
202        self.m_cfg_dict={};
203        self.m_devices={};
204
205    def dump_error (self,err):
206        s="""%s
207From this TRex version a configuration file must exist in /etc/ folder "
208The name of the configuration file should be /etc/trex_cfg.yaml "
209The minimum configuration file should include something like this
210- version       : 2 # version 2 of the configuration file
211  interfaces    : ["03:00.0","03:00.1","13:00.1","13:00.0"]  # list of the interfaces to bind run ./dpdk_nic_bind.py --status to see the list
212  port_limit      : 2 # number of ports to use valid is 2,4,6,8,10,12
213
214example of already bind devices
215
216$ ./dpdk_nic_bind.py --status
217
218Network devices using DPDK-compatible driver
219============================================
2200000:03:00.0 '82599ES 10-Gigabit SFI/SFP+ Network Connection' drv=igb_uio unused=
2210000:03:00.1 '82599ES 10-Gigabit SFI/SFP+ Network Connection' drv=igb_uio unused=
2220000:13:00.0 '82599ES 10-Gigabit SFI/SFP+ Network Connection' drv=igb_uio unused=
2230000:13:00.1 '82599ES 10-Gigabit SFI/SFP+ Network Connection' drv=igb_uio unused=
224
225Network devices using kernel driver
226===================================
2270000:02:00.0 '82545EM Gigabit Ethernet Controller (Copper)' if=eth2 drv=e1000 unused=igb_uio *Active*
228
229Other network devices
230=====================
231
232
233          """ % (err);
234        return s;
235
236
237    def raise_error  (self,err):
238        s= self.dump_error (err)
239        raise DpdkSetup(s)
240
241    def load_config_file (self):
242
243        fcfg=self.m_cfg_file
244
245        if not os.path.isfile(fcfg) :
246            self.raise_error ("There is no valid configuration file %s " % fcfg)
247
248        try:
249          stream = open(fcfg, 'r')
250          self.m_cfg_dict= yaml.safe_load(stream)
251        except Exception as e:
252          print(e);
253          raise e
254
255        stream.close();
256        cfg_dict = self.m_cfg_dict[0]
257        if 'version' not in cfg_dict:
258            self.raise_error ("Configuration file %s is old, should include version field\n" % fcfg )
259
260        if int(cfg_dict['version'])<2 :
261            self.raise_error ("Configuration file %s is old, should include version field with value greater than 2\n" % fcfg)
262
263        if 'interfaces' not in self.m_cfg_dict[0]:
264            self.raise_error ("Configuration file %s is old, should include interfaces field even number of elemets" % fcfg)
265
266        if_list=self.m_cfg_dict[0]['interfaces']
267        l=len(if_list);
268        if (l>20):
269            self.raise_error ("Configuration file %s should include interfaces field with maximum of number of elemets" % (fcfg,l))
270        if ((l % 2)==1):
271            self.raise_error ("Configuration file %s should include even number of interfaces " % (fcfg,l))
272        if 'port_limit' in cfg_dict and cfg_dict['port_limit'] > len(if_list):
273            self.raise_error ('Error: port_limit should not be higher than number of interfaces in config file: %s\n' % fcfg)
274
275
276    def do_bind_one (self,key):
277        cmd='%s dpdk_nic_bind.py --bind=igb_uio %s ' % (sys.executable, key)
278        print(cmd)
279        res=os.system(cmd);
280        if res!=0:
281            raise DpdkSetup('')
282
283
284
285    def pci_name_to_full_name (self,pci_name):
286          c='[0-9A-Fa-f]';
287          sp='[:]'
288          s_short=c+c+sp+c+c+'[.]'+c;
289          s_full=c+c+c+c+sp+s_short
290          re_full = re.compile(s_full)
291          re_short = re.compile(s_short)
292
293          if re_short.match(pci_name):
294              return '0000:'+pci_name
295
296          if re_full.match(pci_name):
297              return pci_name
298
299          err=" %s is not a valid pci address \n" %pci_name;
300          raise DpdkSetup(err)
301
302
303    def run_dpdk_lspci (self):
304        dpdk_nic_bind.get_nic_details()
305        self.m_devices= dpdk_nic_bind.devices
306
307    def do_run (self):
308        self.run_dpdk_lspci ()
309        if map_driver.dump_interfaces is None or (map_driver.dump_interfaces == [] and map_driver.parent_cfg):
310            self.load_config_file()
311            if_list=self.m_cfg_dict[0]['interfaces']
312        else:
313            if_list = map_driver.dump_interfaces
314            if not if_list:
315                for dev in self.m_devices.values():
316                    if dev.get('Driver_str') in dpdk_nic_bind.dpdk_drivers:
317                        if_list.append(dev['Slot'])
318
319        if_list = list(map(self.pci_name_to_full_name, if_list))
320        for key in if_list:
321            if key not in self.m_devices:
322                err=" %s does not exist " %key;
323                raise DpdkSetup(err)
324
325
326            if 'Driver_str' in self.m_devices[key]:
327                if self.m_devices[key]['Driver_str'] not in dpdk_nic_bind.dpdk_drivers :
328                    self.do_bind_one (key)
329            else:
330                self.do_bind_one (key)
331
332        if if_list and map_driver.args.parent and dpdk_nic_bind.get_igb_uio_usage():
333            pid = dpdk_nic_bind.get_pid_using_pci(if_list)
334            cmdline = dpdk_nic_bind.read_pid_cmdline(pid)
335            print('Some or all of given interfaces are in use by following process:\n%s' % cmdline)
336            if not dpdk_nic_bind.confirm('Ignore and proceed (y/N):'):
337                sys.exit(1)
338
339
340    def do_return_to_linux(self):
341        if not self.m_devices:
342            self.run_dpdk_lspci()
343        dpdk_interfaces = []
344        for device in self.m_devices.values():
345            if device.get('Driver_str') in dpdk_nic_bind.dpdk_drivers:
346                dpdk_interfaces.append(device['Slot'])
347        if not dpdk_interfaces:
348            print('No DPDK bound interfaces.')
349            return
350        if dpdk_nic_bind.get_igb_uio_usage():
351            pid = dpdk_nic_bind.get_pid_using_pci(dpdk_interfaces)
352            if pid:
353                cmdline = dpdk_nic_bind.read_pid_cmdline(pid)
354                print('DPDK interfaces are in use. Unbinding them might cause following process to hang:\n%s' % cmdline)
355                if not dpdk_nic_bind.confirm('Confirm (y/N):'):
356                    return
357        print('TODO: unbind %s' % dpdk_interfaces)
358
359    def do_create(self):
360        create_interfaces = map_driver.args.create_interfaces
361        if type(create_interfaces) is not list:
362            raise DpdkSetup('type of map_driver.args.create_interfaces should be list')
363        if not len(create_interfaces):
364            raise DpdkSetup('Please specify interfaces to use in the config')
365        if len(create_interfaces) % 2:
366            raise DpdkSetup('Please specify even number of interfaces')
367        # gather info about NICS from dpdk_nic_bind.py
368        if not self.m_devices:
369            self.run_dpdk_lspci()
370        wanted_interfaces = []
371        for interface in copy.copy(create_interfaces):
372            for m_device in self.m_devices.values():
373                if interface in (m_device['Interface'], m_device['Slot'], m_device['Slot_str']):
374                    if m_device in wanted_interfaces:
375                        raise DpdkSetup('Interface %s is specified twice' % interface)
376                    m_device['Interface_argv'] = interface
377                    wanted_interfaces.append(m_device)
378                    create_interfaces.remove(interface)
379                    break
380        # verify all interfaces identified
381        if len(create_interfaces):
382            raise DpdkSetup('Could not find information about those interfaces: %s' % create_interfaces)
383
384        dpdk_bound = []
385        for interface in wanted_interfaces:
386            if 'Driver_str' not in interface:
387                self.do_bind_one(interface['Slot'])
388                dpdk_bound.append(interface['Slot'])
389            elif interface['Driver_str'] in dpdk_nic_bind.dpdk_drivers:
390                dpdk_bound.append(interface['Slot'])
391        if dpdk_bound:
392            for pci, mac in dpdk_nic_bind.get_macs_from_trex(dpdk_bound).items():
393                self.m_devices[pci]['MAC'] = mac
394
395        dest_macs = map_driver.args.dest_macs
396        for i, interface in enumerate(wanted_interfaces):
397            if 'MAC' not in interface:
398                raise DpdkSetup('Cound not determine MAC of interface: %s. Please verify with -t flag.' % wanted_interfaces[i]['Interface_argv'])
399            interface['src_mac'] = interface['MAC']
400            if isinstance(dest_macs, list) and len(dest_macs) > i:
401                interface['dest_mac'] = dest_macs[i]
402            dual_index = i + 1 - (i % 2) * 2
403            if 'dest_mac' not in wanted_interfaces[dual_index]:
404                wanted_interfaces[dual_index]['dest_mac'] = interface['MAC'] # loopback
405                wanted_interfaces[dual_index]['loopback_dest'] = True
406
407        cpu_topology_file = '/proc/cpuinfo'
408        # physical processor -> physical core -> logical processing units (threads)
409        cpu_topology = OrderedDict()
410        if not os.path.exists(cpu_topology_file):
411            raise DpdkSetup('File with CPU topology (%s) does not exist.' % cpu_topology_file)
412        with open(cpu_topology_file) as f:
413            for lcore in f.read().split('\n\n'):
414                if not lcore:
415                    continue
416                lcore_dict = OrderedDict()
417                for line in lcore.split('\n'):
418                    key, val = line.split(':', 1)
419                    lcore_dict[key.strip()] = val.strip()
420                numa = int(lcore_dict['physical id'])
421                if numa not in cpu_topology:
422                    cpu_topology[numa] = OrderedDict()
423                core = int(lcore_dict['core id'])
424                if core not in cpu_topology[numa]:
425                    cpu_topology[numa][core] = []
426                cpu_topology[numa][core].append(int(lcore_dict['processor']))
427
428        config = ConfigCreator(cpu_topology, wanted_interfaces, include_lcores = map_driver.args.create_include, exclude_lcores = map_driver.args.create_exclude,
429                               only_first_thread = map_driver.args.no_ht, ignore_numa = map_driver.args.ignore_numa,
430                               prefix = map_driver.args.prefix, zmq_rpc_port = map_driver.args.zmq_rpc_port, zmq_pub_port = map_driver.args.zmq_pub_port)
431        config.create_config(filename = map_driver.args.o, print_config = map_driver.args.dump)
432
433def parse_parent_cfg (parent_cfg):
434    parent_parser = argparse.ArgumentParser()
435    parent_parser.add_argument('--cfg', default='')
436    parent_parser.add_argument('--dump-interfaces', nargs='*', default=None)
437    args, unkown = parent_parser.parse_known_args(shlex.split(parent_cfg))
438    return (args.cfg, args.dump_interfaces)
439
440def process_options ():
441    parser = argparse.ArgumentParser(usage="""
442
443Examples:
444---------
445
446To return to Linux the DPDK bound interfaces (for ifconfig etc.)
447  sudo ./dpdk_set_ports.py -l
448
449To create a default config file (example1)
450  sudo ./dpdk_setup_ports.py -c 02:00.0 02:00.1 -o /etc/trex_cfg.yaml
451
452To create a default config file (example2)
453  sudo ./dpdk_setup_ports.py -c eth1 eth2 --dest-macs 11:11:11:11:11:11 22:22:22:22:22:22 --dump
454
455To show interfaces status
456  sudo ./dpdk_set_ports.py -s
457
458To see more detailed info on interfaces (table):
459  sudo ./dpdk_set_ports.py -t
460
461    """,
462    description=" unbind dpdk interfaces ",
463    epilog=" written by hhaim");
464
465    parser.add_argument("-l", "--linux", action='store_true',
466                      help=""" Return all DPDK interfaces to Linux driver """,
467     )
468
469    parser.add_argument("--cfg",
470                      help=""" configuration file name  """,
471     )
472
473    parser.add_argument("--parent",
474                      help=argparse.SUPPRESS
475     )
476
477    parser.add_argument("-c", "--create", nargs='*', default=None, dest='create_interfaces', metavar='<interface>',
478                      help="""Try to create a configuration file by specifying needed interfaces by PCI address or Linux names: eth1 etc.""",
479     )
480
481    parser.add_argument("--ci", "--cores-include", nargs='*', default=[], dest='create_include', metavar='<cores>',
482                      help="""White list of cores to use. Make sure there is enough for each NUMA.""",
483     )
484
485    parser.add_argument("--ce", "--cores-exclude", nargs='*', default=[], dest='create_exclude', metavar='<cores>',
486                      help="""Black list of cores to exclude. Make sure there will be enough for each NUMA.""",
487     )
488
489    parser.add_argument("--dump", default=False, action='store_true',
490                      help="""Dump created config to screen.""",
491     )
492
493    parser.add_argument("--no-ht", default=False, dest='no_ht', action='store_true',
494                      help="""Use only one thread of each Core in created config yaml (No Hyper-Threading).""",
495     )
496
497    parser.add_argument("--dest-macs", nargs='*', default=[], action='store',
498                      help="""Destination MACs to be used in created yaml file. Without them, will be assumed loopback (0<->1, 2<->3 etc.)""",
499     )
500
501    parser.add_argument("-o", default=None, action='store', metavar='PATH',
502                      help="""Output the config to this file.""",
503     )
504
505    parser.add_argument("--prefix", default=None, action='store',
506                      help="""Advanced option: prefix to be used in TRex config in case of parallel instances.""",
507     )
508
509    parser.add_argument("--zmq-pub-port", default=None, action='store',
510                      help="""Advanced option: ZMQ Publisher port to be used in TRex config in case of parallel instances.""",
511     )
512
513    parser.add_argument("--zmq-rpc-port", default=None, action='store',
514                      help="""Advanced option: ZMQ RPC port to be used in TRex config in case of parallel instances.""",
515     )
516
517    parser.add_argument("--ignore-numa", default=False, action='store_true',
518                      help="""Advanced option: Ignore NUMAs for config creation. Use this option only if you have to, as it will reduce performance.""",
519     )
520
521    parser.add_argument("-s", "--show", action='store_true',
522                      help=""" show the status """,
523     )
524
525    parser.add_argument("-t", "--table", action='store_true',
526                      help=""" show table with NICs info """,
527     )
528
529    parser.add_argument('--version', action='version',
530                        version="0.2" )
531
532    map_driver.args = parser.parse_args();
533    if map_driver.args.parent :
534        map_driver.parent_cfg, map_driver.dump_interfaces = parse_parent_cfg (map_driver.args.parent)
535        if map_driver.parent_cfg != '':
536            map_driver.cfg_file = map_driver.parent_cfg;
537    if  map_driver.args.cfg :
538        map_driver.cfg_file = map_driver.args.cfg;
539
540def main ():
541    try:
542        process_options ()
543
544        if map_driver.args.show:
545            res=os.system('%s dpdk_nic_bind.py --status' % sys.executable);
546            return(res);
547
548        if map_driver.args.table:
549            res=os.system('%s dpdk_nic_bind.py -t' % sys.executable);
550            return(res);
551
552        obj =CIfMap(map_driver.cfg_file);
553
554        if map_driver.args.create_interfaces is not None:
555            obj.do_create();
556        elif map_driver.args.linux:
557            obj.do_return_to_linux();
558        else:
559            obj.do_run();
560    except DpdkSetup as e:
561        print(e)
562        exit(-1)
563
564if __name__ == '__main__':
565    main()
566
567