xref: /f-stack/dpdk/usertools/dpdk-devbind.py (revision 2bfe3f2e)
1*2bfe3f2eSlogwang#! /usr/bin/env python
2*2bfe3f2eSlogwang#
3*2bfe3f2eSlogwang#   BSD LICENSE
4*2bfe3f2eSlogwang#
5*2bfe3f2eSlogwang#   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
6*2bfe3f2eSlogwang#   All rights reserved.
7*2bfe3f2eSlogwang#
8*2bfe3f2eSlogwang#   Redistribution and use in source and binary forms, with or without
9*2bfe3f2eSlogwang#   modification, are permitted provided that the following conditions
10*2bfe3f2eSlogwang#   are met:
11*2bfe3f2eSlogwang#
12*2bfe3f2eSlogwang#     * Redistributions of source code must retain the above copyright
13*2bfe3f2eSlogwang#       notice, this list of conditions and the following disclaimer.
14*2bfe3f2eSlogwang#     * Redistributions in binary form must reproduce the above copyright
15*2bfe3f2eSlogwang#       notice, this list of conditions and the following disclaimer in
16*2bfe3f2eSlogwang#       the documentation and/or other materials provided with the
17*2bfe3f2eSlogwang#       distribution.
18*2bfe3f2eSlogwang#     * Neither the name of Intel Corporation nor the names of its
19*2bfe3f2eSlogwang#       contributors may be used to endorse or promote products derived
20*2bfe3f2eSlogwang#       from this software without specific prior written permission.
21*2bfe3f2eSlogwang#
22*2bfe3f2eSlogwang#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23*2bfe3f2eSlogwang#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24*2bfe3f2eSlogwang#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25*2bfe3f2eSlogwang#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26*2bfe3f2eSlogwang#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27*2bfe3f2eSlogwang#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28*2bfe3f2eSlogwang#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29*2bfe3f2eSlogwang#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30*2bfe3f2eSlogwang#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31*2bfe3f2eSlogwang#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32*2bfe3f2eSlogwang#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33*2bfe3f2eSlogwang#
34*2bfe3f2eSlogwang
35*2bfe3f2eSlogwangimport sys
36*2bfe3f2eSlogwangimport os
37*2bfe3f2eSlogwangimport getopt
38*2bfe3f2eSlogwangimport subprocess
39*2bfe3f2eSlogwangfrom os.path import exists, abspath, dirname, basename
40*2bfe3f2eSlogwang
41*2bfe3f2eSlogwang# The PCI base class for all devices
42*2bfe3f2eSlogwangnetwork_class = {'Class': '02', 'Vendor': None, 'Device': None,
43*2bfe3f2eSlogwang                    'SVendor': None, 'SDevice': None}
44*2bfe3f2eSlogwangencryption_class = {'Class': '10', 'Vendor': None, 'Device': None,
45*2bfe3f2eSlogwang                   'SVendor': None, 'SDevice': None}
46*2bfe3f2eSlogwangintel_processor_class = {'Class': '0b', 'Vendor': '8086', 'Device': None,
47*2bfe3f2eSlogwang                   'SVendor': None, 'SDevice': None}
48*2bfe3f2eSlogwangcavium_sso = {'Class': '08', 'Vendor': '177d', 'Device': 'a04b,a04d',
49*2bfe3f2eSlogwang              'SVendor': None, 'SDevice': None}
50*2bfe3f2eSlogwangcavium_fpa = {'Class': '08', 'Vendor': '177d', 'Device': 'a053',
51*2bfe3f2eSlogwang              'SVendor': None, 'SDevice': None}
52*2bfe3f2eSlogwangcavium_pkx = {'Class': '08', 'Vendor': '177d', 'Device': 'a0dd,a049',
53*2bfe3f2eSlogwang              'SVendor': None, 'SDevice': None}
54*2bfe3f2eSlogwang
55*2bfe3f2eSlogwangnetwork_devices = [network_class, cavium_pkx]
56*2bfe3f2eSlogwangcrypto_devices = [encryption_class, intel_processor_class]
57*2bfe3f2eSlogwangeventdev_devices = [cavium_sso]
58*2bfe3f2eSlogwangmempool_devices = [cavium_fpa]
59*2bfe3f2eSlogwang
60*2bfe3f2eSlogwang# global dict ethernet devices present. Dictionary indexed by PCI address.
61*2bfe3f2eSlogwang# Each device within this is itself a dictionary of device properties
62*2bfe3f2eSlogwangdevices = {}
63*2bfe3f2eSlogwang# list of supported DPDK drivers
64*2bfe3f2eSlogwangdpdk_drivers = ["igb_uio", "vfio-pci", "uio_pci_generic"]
65*2bfe3f2eSlogwang
66*2bfe3f2eSlogwang# command-line arg flags
67*2bfe3f2eSlogwangb_flag = None
68*2bfe3f2eSlogwangstatus_flag = False
69*2bfe3f2eSlogwangforce_flag = False
70*2bfe3f2eSlogwangargs = []
71*2bfe3f2eSlogwang
72*2bfe3f2eSlogwang
73*2bfe3f2eSlogwangdef usage():
74*2bfe3f2eSlogwang    '''Print usage information for the program'''
75*2bfe3f2eSlogwang    argv0 = basename(sys.argv[0])
76*2bfe3f2eSlogwang    print("""
77*2bfe3f2eSlogwangUsage:
78*2bfe3f2eSlogwang------
79*2bfe3f2eSlogwang
80*2bfe3f2eSlogwang     %(argv0)s [options] DEVICE1 DEVICE2 ....
81*2bfe3f2eSlogwang
82*2bfe3f2eSlogwangwhere DEVICE1, DEVICE2 etc, are specified via PCI "domain:bus:slot.func" syntax
83*2bfe3f2eSlogwangor "bus:slot.func" syntax. For devices bound to Linux kernel drivers, they may
84*2bfe3f2eSlogwangalso be referred to by Linux interface name e.g. eth0, eth1, em0, em1, etc.
85*2bfe3f2eSlogwang
86*2bfe3f2eSlogwangOptions:
87*2bfe3f2eSlogwang    --help, --usage:
88*2bfe3f2eSlogwang        Display usage information and quit
89*2bfe3f2eSlogwang
90*2bfe3f2eSlogwang    -s, --status:
91*2bfe3f2eSlogwang        Print the current status of all known network, crypto, event
92*2bfe3f2eSlogwang        and mempool devices.
93*2bfe3f2eSlogwang        For each device, it displays the PCI domain, bus, slot and function,
94*2bfe3f2eSlogwang        along with a text description of the device. Depending upon whether the
95*2bfe3f2eSlogwang        device is being used by a kernel driver, the igb_uio driver, or no
96*2bfe3f2eSlogwang        driver, other relevant information will be displayed:
97*2bfe3f2eSlogwang        * the Linux interface name e.g. if=eth0
98*2bfe3f2eSlogwang        * the driver being used e.g. drv=igb_uio
99*2bfe3f2eSlogwang        * any suitable drivers not currently using that device
100*2bfe3f2eSlogwang            e.g. unused=igb_uio
101*2bfe3f2eSlogwang        NOTE: if this flag is passed along with a bind/unbind option, the
102*2bfe3f2eSlogwang        status display will always occur after the other operations have taken
103*2bfe3f2eSlogwang        place.
104*2bfe3f2eSlogwang
105*2bfe3f2eSlogwang    --status-dev:
106*2bfe3f2eSlogwang        Print the status of given device group. Supported device groups are:
107*2bfe3f2eSlogwang        "net", "crypto", "event" and "mempool"
108*2bfe3f2eSlogwang
109*2bfe3f2eSlogwang    -b driver, --bind=driver:
110*2bfe3f2eSlogwang        Select the driver to use or \"none\" to unbind the device
111*2bfe3f2eSlogwang
112*2bfe3f2eSlogwang    -u, --unbind:
113*2bfe3f2eSlogwang        Unbind a device (Equivalent to \"-b none\")
114*2bfe3f2eSlogwang
115*2bfe3f2eSlogwang    --force:
116*2bfe3f2eSlogwang        By default, network devices which are used by Linux - as indicated by
117*2bfe3f2eSlogwang        having routes in the routing table - cannot be modified. Using the
118*2bfe3f2eSlogwang        --force flag overrides this behavior, allowing active links to be
119*2bfe3f2eSlogwang        forcibly unbound.
120*2bfe3f2eSlogwang        WARNING: This can lead to loss of network connection and should be used
121*2bfe3f2eSlogwang        with caution.
122*2bfe3f2eSlogwang
123*2bfe3f2eSlogwangExamples:
124*2bfe3f2eSlogwang---------
125*2bfe3f2eSlogwang
126*2bfe3f2eSlogwangTo display current device status:
127*2bfe3f2eSlogwang        %(argv0)s --status
128*2bfe3f2eSlogwang
129*2bfe3f2eSlogwangTo display current network device status:
130*2bfe3f2eSlogwang        %(argv0)s --status-dev net
131*2bfe3f2eSlogwang
132*2bfe3f2eSlogwangTo bind eth1 from the current driver and move to use igb_uio
133*2bfe3f2eSlogwang        %(argv0)s --bind=igb_uio eth1
134*2bfe3f2eSlogwang
135*2bfe3f2eSlogwangTo unbind 0000:01:00.0 from using any driver
136*2bfe3f2eSlogwang        %(argv0)s -u 0000:01:00.0
137*2bfe3f2eSlogwang
138*2bfe3f2eSlogwangTo bind 0000:02:00.0 and 0000:02:00.1 to the ixgbe kernel driver
139*2bfe3f2eSlogwang        %(argv0)s -b ixgbe 02:00.0 02:00.1
140*2bfe3f2eSlogwang
141*2bfe3f2eSlogwang    """ % locals())  # replace items from local variables
142*2bfe3f2eSlogwang
143*2bfe3f2eSlogwang
144*2bfe3f2eSlogwang# This is roughly compatible with check_output function in subprocess module
145*2bfe3f2eSlogwang# which is only available in python 2.7.
146*2bfe3f2eSlogwangdef check_output(args, stderr=None):
147*2bfe3f2eSlogwang    '''Run a command and capture its output'''
148*2bfe3f2eSlogwang    return subprocess.Popen(args, stdout=subprocess.PIPE,
149*2bfe3f2eSlogwang                            stderr=stderr).communicate()[0]
150*2bfe3f2eSlogwang
151*2bfe3f2eSlogwang
152*2bfe3f2eSlogwangdef find_module(mod):
153*2bfe3f2eSlogwang    '''find the .ko file for kernel module named mod.
154*2bfe3f2eSlogwang    Searches the $RTE_SDK/$RTE_TARGET directory, the kernel
155*2bfe3f2eSlogwang    modules directory and finally under the parent directory of
156*2bfe3f2eSlogwang    the script '''
157*2bfe3f2eSlogwang    # check $RTE_SDK/$RTE_TARGET directory
158*2bfe3f2eSlogwang    if 'RTE_SDK' in os.environ and 'RTE_TARGET' in os.environ:
159*2bfe3f2eSlogwang        path = "%s/%s/kmod/%s.ko" % (os.environ['RTE_SDK'],
160*2bfe3f2eSlogwang                                     os.environ['RTE_TARGET'], mod)
161*2bfe3f2eSlogwang        if exists(path):
162*2bfe3f2eSlogwang            return path
163*2bfe3f2eSlogwang
164*2bfe3f2eSlogwang    # check using depmod
165*2bfe3f2eSlogwang    try:
166*2bfe3f2eSlogwang        with open(os.devnull, "w") as fnull:
167*2bfe3f2eSlogwang            path = check_output(["modinfo", "-n", mod], stderr=fnull).strip()
168*2bfe3f2eSlogwang
169*2bfe3f2eSlogwang        if path and exists(path):
170*2bfe3f2eSlogwang            return path
171*2bfe3f2eSlogwang    except:  # if modinfo can't find module, it fails, so continue
172*2bfe3f2eSlogwang        pass
173*2bfe3f2eSlogwang
174*2bfe3f2eSlogwang    # check for a copy based off current path
175*2bfe3f2eSlogwang    tools_dir = dirname(abspath(sys.argv[0]))
176*2bfe3f2eSlogwang    if tools_dir.endswith("tools"):
177*2bfe3f2eSlogwang        base_dir = dirname(tools_dir)
178*2bfe3f2eSlogwang        find_out = check_output(["find", base_dir, "-name", mod + ".ko"])
179*2bfe3f2eSlogwang        if len(find_out) > 0:  # something matched
180*2bfe3f2eSlogwang            path = find_out.splitlines()[0]
181*2bfe3f2eSlogwang            if exists(path):
182*2bfe3f2eSlogwang                return path
183*2bfe3f2eSlogwang
184*2bfe3f2eSlogwang
185*2bfe3f2eSlogwangdef check_modules():
186*2bfe3f2eSlogwang    '''Checks that igb_uio is loaded'''
187*2bfe3f2eSlogwang    global dpdk_drivers
188*2bfe3f2eSlogwang
189*2bfe3f2eSlogwang    # list of supported modules
190*2bfe3f2eSlogwang    mods = [{"Name": driver, "Found": False} for driver in dpdk_drivers]
191*2bfe3f2eSlogwang
192*2bfe3f2eSlogwang    # first check if module is loaded
193*2bfe3f2eSlogwang    try:
194*2bfe3f2eSlogwang        # Get list of sysfs modules (both built-in and dynamically loaded)
195*2bfe3f2eSlogwang        sysfs_path = '/sys/module/'
196*2bfe3f2eSlogwang
197*2bfe3f2eSlogwang        # Get the list of directories in sysfs_path
198*2bfe3f2eSlogwang        sysfs_mods = [os.path.join(sysfs_path, o) for o
199*2bfe3f2eSlogwang                      in os.listdir(sysfs_path)
200*2bfe3f2eSlogwang                      if os.path.isdir(os.path.join(sysfs_path, o))]
201*2bfe3f2eSlogwang
202*2bfe3f2eSlogwang        # Extract the last element of '/sys/module/abc' in the array
203*2bfe3f2eSlogwang        sysfs_mods = [a.split('/')[-1] for a in sysfs_mods]
204*2bfe3f2eSlogwang
205*2bfe3f2eSlogwang        # special case for vfio_pci (module is named vfio-pci,
206*2bfe3f2eSlogwang        # but its .ko is named vfio_pci)
207*2bfe3f2eSlogwang        sysfs_mods = [a if a != 'vfio_pci' else 'vfio-pci' for a in sysfs_mods]
208*2bfe3f2eSlogwang
209*2bfe3f2eSlogwang        for mod in mods:
210*2bfe3f2eSlogwang            if mod["Name"] in sysfs_mods:
211*2bfe3f2eSlogwang                mod["Found"] = True
212*2bfe3f2eSlogwang    except:
213*2bfe3f2eSlogwang        pass
214*2bfe3f2eSlogwang
215*2bfe3f2eSlogwang    # check if we have at least one loaded module
216*2bfe3f2eSlogwang    if True not in [mod["Found"] for mod in mods] and b_flag is not None:
217*2bfe3f2eSlogwang        if b_flag in dpdk_drivers:
218*2bfe3f2eSlogwang            print("Error - no supported modules(DPDK driver) are loaded")
219*2bfe3f2eSlogwang            sys.exit(1)
220*2bfe3f2eSlogwang        else:
221*2bfe3f2eSlogwang            print("Warning - no supported modules(DPDK driver) are loaded")
222*2bfe3f2eSlogwang
223*2bfe3f2eSlogwang    # change DPDK driver list to only contain drivers that are loaded
224*2bfe3f2eSlogwang    dpdk_drivers = [mod["Name"] for mod in mods if mod["Found"]]
225*2bfe3f2eSlogwang
226*2bfe3f2eSlogwang
227*2bfe3f2eSlogwangdef has_driver(dev_id):
228*2bfe3f2eSlogwang    '''return true if a device is assigned to a driver. False otherwise'''
229*2bfe3f2eSlogwang    return "Driver_str" in devices[dev_id]
230*2bfe3f2eSlogwang
231*2bfe3f2eSlogwang
232*2bfe3f2eSlogwangdef get_pci_device_details(dev_id, probe_lspci):
233*2bfe3f2eSlogwang    '''This function gets additional details for a PCI device'''
234*2bfe3f2eSlogwang    device = {}
235*2bfe3f2eSlogwang
236*2bfe3f2eSlogwang    if probe_lspci:
237*2bfe3f2eSlogwang        extra_info = check_output(["lspci", "-vmmks", dev_id]).splitlines()
238*2bfe3f2eSlogwang
239*2bfe3f2eSlogwang        # parse lspci details
240*2bfe3f2eSlogwang        for line in extra_info:
241*2bfe3f2eSlogwang            if len(line) == 0:
242*2bfe3f2eSlogwang                continue
243*2bfe3f2eSlogwang            name, value = line.decode().split("\t", 1)
244*2bfe3f2eSlogwang            name = name.strip(":") + "_str"
245*2bfe3f2eSlogwang            device[name] = value
246*2bfe3f2eSlogwang    # check for a unix interface name
247*2bfe3f2eSlogwang    device["Interface"] = ""
248*2bfe3f2eSlogwang    for base, dirs, _ in os.walk("/sys/bus/pci/devices/%s/" % dev_id):
249*2bfe3f2eSlogwang        if "net" in dirs:
250*2bfe3f2eSlogwang            device["Interface"] = \
251*2bfe3f2eSlogwang                ",".join(os.listdir(os.path.join(base, "net")))
252*2bfe3f2eSlogwang            break
253*2bfe3f2eSlogwang    # check if a port is used for ssh connection
254*2bfe3f2eSlogwang    device["Ssh_if"] = False
255*2bfe3f2eSlogwang    device["Active"] = ""
256*2bfe3f2eSlogwang
257*2bfe3f2eSlogwang    return device
258*2bfe3f2eSlogwang
259*2bfe3f2eSlogwangdef clear_data():
260*2bfe3f2eSlogwang    '''This function clears any old data'''
261*2bfe3f2eSlogwang    devices = {}
262*2bfe3f2eSlogwang
263*2bfe3f2eSlogwangdef get_device_details(devices_type):
264*2bfe3f2eSlogwang    '''This function populates the "devices" dictionary. The keys used are
265*2bfe3f2eSlogwang    the pci addresses (domain:bus:slot.func). The values are themselves
266*2bfe3f2eSlogwang    dictionaries - one for each NIC.'''
267*2bfe3f2eSlogwang    global devices
268*2bfe3f2eSlogwang    global dpdk_drivers
269*2bfe3f2eSlogwang
270*2bfe3f2eSlogwang    # first loop through and read details for all devices
271*2bfe3f2eSlogwang    # request machine readable format, with numeric IDs and String
272*2bfe3f2eSlogwang    dev = {}
273*2bfe3f2eSlogwang    dev_lines = check_output(["lspci", "-Dvmmnnk"]).splitlines()
274*2bfe3f2eSlogwang    for dev_line in dev_lines:
275*2bfe3f2eSlogwang        if len(dev_line) == 0:
276*2bfe3f2eSlogwang            if device_type_match(dev, devices_type):
277*2bfe3f2eSlogwang                # Replace "Driver" with "Driver_str" to have consistency of
278*2bfe3f2eSlogwang                # of dictionary key names
279*2bfe3f2eSlogwang                if "Driver" in dev.keys():
280*2bfe3f2eSlogwang                    dev["Driver_str"] = dev.pop("Driver")
281*2bfe3f2eSlogwang                if "Module" in dev.keys():
282*2bfe3f2eSlogwang                    dev["Module_str"] = dev.pop("Module")
283*2bfe3f2eSlogwang                # use dict to make copy of dev
284*2bfe3f2eSlogwang                devices[dev["Slot"]] = dict(dev)
285*2bfe3f2eSlogwang            # Clear previous device's data
286*2bfe3f2eSlogwang            dev = {}
287*2bfe3f2eSlogwang        else:
288*2bfe3f2eSlogwang            name, value = dev_line.decode().split("\t", 1)
289*2bfe3f2eSlogwang            value_list = value.rsplit(' ', 1)
290*2bfe3f2eSlogwang            if len(value_list) > 1:
291*2bfe3f2eSlogwang                # String stored in <name>_str
292*2bfe3f2eSlogwang                dev[name.rstrip(":") + '_str'] = value_list[0]
293*2bfe3f2eSlogwang            # Numeric IDs
294*2bfe3f2eSlogwang            dev[name.rstrip(":")] = value_list[len(value_list) - 1] \
295*2bfe3f2eSlogwang                .rstrip("]").lstrip("[")
296*2bfe3f2eSlogwang
297*2bfe3f2eSlogwang    if devices_type == network_devices:
298*2bfe3f2eSlogwang        # check what is the interface if any for an ssh connection if
299*2bfe3f2eSlogwang        # any to this host, so we can mark it later.
300*2bfe3f2eSlogwang        ssh_if = []
301*2bfe3f2eSlogwang        route = check_output(["ip", "-o", "route"])
302*2bfe3f2eSlogwang        # filter out all lines for 169.254 routes
303*2bfe3f2eSlogwang        route = "\n".join(filter(lambda ln: not ln.startswith("169.254"),
304*2bfe3f2eSlogwang                             route.decode().splitlines()))
305*2bfe3f2eSlogwang        rt_info = route.split()
306*2bfe3f2eSlogwang        for i in range(len(rt_info) - 1):
307*2bfe3f2eSlogwang            if rt_info[i] == "dev":
308*2bfe3f2eSlogwang                ssh_if.append(rt_info[i+1])
309*2bfe3f2eSlogwang
310*2bfe3f2eSlogwang    # based on the basic info, get extended text details
311*2bfe3f2eSlogwang    for d in devices.keys():
312*2bfe3f2eSlogwang        if not device_type_match(devices[d], devices_type):
313*2bfe3f2eSlogwang            continue
314*2bfe3f2eSlogwang
315*2bfe3f2eSlogwang        # get additional info and add it to existing data
316*2bfe3f2eSlogwang        devices[d] = devices[d].copy()
317*2bfe3f2eSlogwang        # No need to probe lspci
318*2bfe3f2eSlogwang        devices[d].update(get_pci_device_details(d, False).items())
319*2bfe3f2eSlogwang
320*2bfe3f2eSlogwang        if devices_type == network_devices:
321*2bfe3f2eSlogwang            for _if in ssh_if:
322*2bfe3f2eSlogwang                if _if in devices[d]["Interface"].split(","):
323*2bfe3f2eSlogwang                    devices[d]["Ssh_if"] = True
324*2bfe3f2eSlogwang                    devices[d]["Active"] = "*Active*"
325*2bfe3f2eSlogwang                    break
326*2bfe3f2eSlogwang
327*2bfe3f2eSlogwang        # add igb_uio to list of supporting modules if needed
328*2bfe3f2eSlogwang        if "Module_str" in devices[d]:
329*2bfe3f2eSlogwang            for driver in dpdk_drivers:
330*2bfe3f2eSlogwang                if driver not in devices[d]["Module_str"]:
331*2bfe3f2eSlogwang                    devices[d]["Module_str"] = \
332*2bfe3f2eSlogwang                        devices[d]["Module_str"] + ",%s" % driver
333*2bfe3f2eSlogwang        else:
334*2bfe3f2eSlogwang            devices[d]["Module_str"] = ",".join(dpdk_drivers)
335*2bfe3f2eSlogwang
336*2bfe3f2eSlogwang        # make sure the driver and module strings do not have any duplicates
337*2bfe3f2eSlogwang        if has_driver(d):
338*2bfe3f2eSlogwang            modules = devices[d]["Module_str"].split(",")
339*2bfe3f2eSlogwang            if devices[d]["Driver_str"] in modules:
340*2bfe3f2eSlogwang                modules.remove(devices[d]["Driver_str"])
341*2bfe3f2eSlogwang                devices[d]["Module_str"] = ",".join(modules)
342*2bfe3f2eSlogwang
343*2bfe3f2eSlogwang
344*2bfe3f2eSlogwangdef device_type_match(dev, devices_type):
345*2bfe3f2eSlogwang    for i in range(len(devices_type)):
346*2bfe3f2eSlogwang        param_count = len(
347*2bfe3f2eSlogwang            [x for x in devices_type[i].values() if x is not None])
348*2bfe3f2eSlogwang        match_count = 0
349*2bfe3f2eSlogwang        if dev["Class"][0:2] == devices_type[i]["Class"]:
350*2bfe3f2eSlogwang            match_count = match_count + 1
351*2bfe3f2eSlogwang            for key in devices_type[i].keys():
352*2bfe3f2eSlogwang                if key != 'Class' and devices_type[i][key]:
353*2bfe3f2eSlogwang                    value_list = devices_type[i][key].split(',')
354*2bfe3f2eSlogwang                    for value in value_list:
355*2bfe3f2eSlogwang                        if value.strip(' ') == dev[key]:
356*2bfe3f2eSlogwang                            match_count = match_count + 1
357*2bfe3f2eSlogwang            # count must be the number of non None parameters to match
358*2bfe3f2eSlogwang            if match_count == param_count:
359*2bfe3f2eSlogwang                return True
360*2bfe3f2eSlogwang    return False
361*2bfe3f2eSlogwang
362*2bfe3f2eSlogwangdef dev_id_from_dev_name(dev_name):
363*2bfe3f2eSlogwang    '''Take a device "name" - a string passed in by user to identify a NIC
364*2bfe3f2eSlogwang    device, and determine the device id - i.e. the domain:bus:slot.func - for
365*2bfe3f2eSlogwang    it, which can then be used to index into the devices array'''
366*2bfe3f2eSlogwang
367*2bfe3f2eSlogwang    # check if it's already a suitable index
368*2bfe3f2eSlogwang    if dev_name in devices:
369*2bfe3f2eSlogwang        return dev_name
370*2bfe3f2eSlogwang    # check if it's an index just missing the domain part
371*2bfe3f2eSlogwang    elif "0000:" + dev_name in devices:
372*2bfe3f2eSlogwang        return "0000:" + dev_name
373*2bfe3f2eSlogwang    else:
374*2bfe3f2eSlogwang        # check if it's an interface name, e.g. eth1
375*2bfe3f2eSlogwang        for d in devices.keys():
376*2bfe3f2eSlogwang            if dev_name in devices[d]["Interface"].split(","):
377*2bfe3f2eSlogwang                return devices[d]["Slot"]
378*2bfe3f2eSlogwang    # if nothing else matches - error
379*2bfe3f2eSlogwang    print("Unknown device: %s. "
380*2bfe3f2eSlogwang          "Please specify device in \"bus:slot.func\" format" % dev_name)
381*2bfe3f2eSlogwang    sys.exit(1)
382*2bfe3f2eSlogwang
383*2bfe3f2eSlogwang
384*2bfe3f2eSlogwangdef unbind_one(dev_id, force):
385*2bfe3f2eSlogwang    '''Unbind the device identified by "dev_id" from its current driver'''
386*2bfe3f2eSlogwang    dev = devices[dev_id]
387*2bfe3f2eSlogwang    if not has_driver(dev_id):
388*2bfe3f2eSlogwang        print("%s %s %s is not currently managed by any driver\n" %
389*2bfe3f2eSlogwang              (dev["Slot"], dev["Device_str"], dev["Interface"]))
390*2bfe3f2eSlogwang        return
391*2bfe3f2eSlogwang
392*2bfe3f2eSlogwang    # prevent us disconnecting ourselves
393*2bfe3f2eSlogwang    if dev["Ssh_if"] and not force:
394*2bfe3f2eSlogwang        print("Routing table indicates that interface %s is active. "
395*2bfe3f2eSlogwang              "Skipping unbind" % (dev_id))
396*2bfe3f2eSlogwang        return
397*2bfe3f2eSlogwang
398*2bfe3f2eSlogwang    # write to /sys to unbind
399*2bfe3f2eSlogwang    filename = "/sys/bus/pci/drivers/%s/unbind" % dev["Driver_str"]
400*2bfe3f2eSlogwang    try:
401*2bfe3f2eSlogwang        f = open(filename, "a")
402*2bfe3f2eSlogwang    except:
403*2bfe3f2eSlogwang        print("Error: unbind failed for %s - Cannot open %s"
404*2bfe3f2eSlogwang              % (dev_id, filename))
405*2bfe3f2eSlogwang        sys.exit(1)
406*2bfe3f2eSlogwang    f.write(dev_id)
407*2bfe3f2eSlogwang    f.close()
408*2bfe3f2eSlogwang
409*2bfe3f2eSlogwang
410*2bfe3f2eSlogwangdef bind_one(dev_id, driver, force):
411*2bfe3f2eSlogwang    '''Bind the device given by "dev_id" to the driver "driver". If the device
412*2bfe3f2eSlogwang    is already bound to a different driver, it will be unbound first'''
413*2bfe3f2eSlogwang    dev = devices[dev_id]
414*2bfe3f2eSlogwang    saved_driver = None  # used to rollback any unbind in case of failure
415*2bfe3f2eSlogwang
416*2bfe3f2eSlogwang    # prevent disconnection of our ssh session
417*2bfe3f2eSlogwang    if dev["Ssh_if"] and not force:
418*2bfe3f2eSlogwang        print("Routing table indicates that interface %s is active. "
419*2bfe3f2eSlogwang              "Not modifying" % (dev_id))
420*2bfe3f2eSlogwang        return
421*2bfe3f2eSlogwang
422*2bfe3f2eSlogwang    # unbind any existing drivers we don't want
423*2bfe3f2eSlogwang    if has_driver(dev_id):
424*2bfe3f2eSlogwang        if dev["Driver_str"] == driver:
425*2bfe3f2eSlogwang            print("%s already bound to driver %s, skipping\n"
426*2bfe3f2eSlogwang                  % (dev_id, driver))
427*2bfe3f2eSlogwang            return
428*2bfe3f2eSlogwang        else:
429*2bfe3f2eSlogwang            saved_driver = dev["Driver_str"]
430*2bfe3f2eSlogwang            unbind_one(dev_id, force)
431*2bfe3f2eSlogwang            dev["Driver_str"] = ""  # clear driver string
432*2bfe3f2eSlogwang
433*2bfe3f2eSlogwang    # For kernels >= 3.15 driver_override can be used to specify the driver
434*2bfe3f2eSlogwang    # for a device rather than relying on the driver to provide a positive
435*2bfe3f2eSlogwang    # match of the device.  The existing process of looking up
436*2bfe3f2eSlogwang    # the vendor and device ID, adding them to the driver new_id,
437*2bfe3f2eSlogwang    # will erroneously bind other devices too which has the additional burden
438*2bfe3f2eSlogwang    # of unbinding those devices
439*2bfe3f2eSlogwang    if driver in dpdk_drivers:
440*2bfe3f2eSlogwang        filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id
441*2bfe3f2eSlogwang        if os.path.exists(filename):
442*2bfe3f2eSlogwang            try:
443*2bfe3f2eSlogwang                f = open(filename, "w")
444*2bfe3f2eSlogwang            except:
445*2bfe3f2eSlogwang                print("Error: bind failed for %s - Cannot open %s"
446*2bfe3f2eSlogwang                      % (dev_id, filename))
447*2bfe3f2eSlogwang                return
448*2bfe3f2eSlogwang            try:
449*2bfe3f2eSlogwang                f.write("%s" % driver)
450*2bfe3f2eSlogwang                f.close()
451*2bfe3f2eSlogwang            except:
452*2bfe3f2eSlogwang                print("Error: bind failed for %s - Cannot write driver %s to "
453*2bfe3f2eSlogwang                      "PCI ID " % (dev_id, driver))
454*2bfe3f2eSlogwang                return
455*2bfe3f2eSlogwang        # For kernels < 3.15 use new_id to add PCI id's to the driver
456*2bfe3f2eSlogwang        else:
457*2bfe3f2eSlogwang            filename = "/sys/bus/pci/drivers/%s/new_id" % driver
458*2bfe3f2eSlogwang            try:
459*2bfe3f2eSlogwang                f = open(filename, "w")
460*2bfe3f2eSlogwang            except:
461*2bfe3f2eSlogwang                print("Error: bind failed for %s - Cannot open %s"
462*2bfe3f2eSlogwang                      % (dev_id, filename))
463*2bfe3f2eSlogwang                return
464*2bfe3f2eSlogwang            try:
465*2bfe3f2eSlogwang                # Convert Device and Vendor Id to int to write to new_id
466*2bfe3f2eSlogwang                f.write("%04x %04x" % (int(dev["Vendor"],16),
467*2bfe3f2eSlogwang                        int(dev["Device"], 16)))
468*2bfe3f2eSlogwang                f.close()
469*2bfe3f2eSlogwang            except:
470*2bfe3f2eSlogwang                print("Error: bind failed for %s - Cannot write new PCI ID to "
471*2bfe3f2eSlogwang                      "driver %s" % (dev_id, driver))
472*2bfe3f2eSlogwang                return
473*2bfe3f2eSlogwang
474*2bfe3f2eSlogwang    # do the bind by writing to /sys
475*2bfe3f2eSlogwang    filename = "/sys/bus/pci/drivers/%s/bind" % driver
476*2bfe3f2eSlogwang    try:
477*2bfe3f2eSlogwang        f = open(filename, "a")
478*2bfe3f2eSlogwang    except:
479*2bfe3f2eSlogwang        print("Error: bind failed for %s - Cannot open %s"
480*2bfe3f2eSlogwang              % (dev_id, filename))
481*2bfe3f2eSlogwang        if saved_driver is not None:  # restore any previous driver
482*2bfe3f2eSlogwang            bind_one(dev_id, saved_driver, force)
483*2bfe3f2eSlogwang        return
484*2bfe3f2eSlogwang    try:
485*2bfe3f2eSlogwang        f.write(dev_id)
486*2bfe3f2eSlogwang        f.close()
487*2bfe3f2eSlogwang    except:
488*2bfe3f2eSlogwang        # for some reason, closing dev_id after adding a new PCI ID to new_id
489*2bfe3f2eSlogwang        # results in IOError. however, if the device was successfully bound,
490*2bfe3f2eSlogwang        # we don't care for any errors and can safely ignore IOError
491*2bfe3f2eSlogwang        tmp = get_pci_device_details(dev_id, True)
492*2bfe3f2eSlogwang        if "Driver_str" in tmp and tmp["Driver_str"] == driver:
493*2bfe3f2eSlogwang            return
494*2bfe3f2eSlogwang        print("Error: bind failed for %s - Cannot bind to driver %s"
495*2bfe3f2eSlogwang              % (dev_id, driver))
496*2bfe3f2eSlogwang        if saved_driver is not None:  # restore any previous driver
497*2bfe3f2eSlogwang            bind_one(dev_id, saved_driver, force)
498*2bfe3f2eSlogwang        return
499*2bfe3f2eSlogwang
500*2bfe3f2eSlogwang    # For kernels > 3.15 driver_override is used to bind a device to a driver.
501*2bfe3f2eSlogwang    # Before unbinding it, overwrite driver_override with empty string so that
502*2bfe3f2eSlogwang    # the device can be bound to any other driver
503*2bfe3f2eSlogwang    filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id
504*2bfe3f2eSlogwang    if os.path.exists(filename):
505*2bfe3f2eSlogwang        try:
506*2bfe3f2eSlogwang            f = open(filename, "w")
507*2bfe3f2eSlogwang        except:
508*2bfe3f2eSlogwang            print("Error: unbind failed for %s - Cannot open %s"
509*2bfe3f2eSlogwang                  % (dev_id, filename))
510*2bfe3f2eSlogwang            sys.exit(1)
511*2bfe3f2eSlogwang        try:
512*2bfe3f2eSlogwang            f.write("\00")
513*2bfe3f2eSlogwang            f.close()
514*2bfe3f2eSlogwang        except:
515*2bfe3f2eSlogwang            print("Error: unbind failed for %s - Cannot open %s"
516*2bfe3f2eSlogwang                  % (dev_id, filename))
517*2bfe3f2eSlogwang            sys.exit(1)
518*2bfe3f2eSlogwang
519*2bfe3f2eSlogwang
520*2bfe3f2eSlogwangdef unbind_all(dev_list, force=False):
521*2bfe3f2eSlogwang    """Unbind method, takes a list of device locations"""
522*2bfe3f2eSlogwang
523*2bfe3f2eSlogwang    if dev_list[0] == "dpdk":
524*2bfe3f2eSlogwang        for d in devices.keys():
525*2bfe3f2eSlogwang            if "Driver_str" in devices[d]:
526*2bfe3f2eSlogwang                if devices[d]["Driver_str"] in dpdk_drivers:
527*2bfe3f2eSlogwang                    unbind_one(devices[d]["Slot"], force)
528*2bfe3f2eSlogwang        return
529*2bfe3f2eSlogwang
530*2bfe3f2eSlogwang    dev_list = map(dev_id_from_dev_name, dev_list)
531*2bfe3f2eSlogwang    for d in dev_list:
532*2bfe3f2eSlogwang        unbind_one(d, force)
533*2bfe3f2eSlogwang
534*2bfe3f2eSlogwang
535*2bfe3f2eSlogwangdef bind_all(dev_list, driver, force=False):
536*2bfe3f2eSlogwang    """Bind method, takes a list of device locations"""
537*2bfe3f2eSlogwang    global devices
538*2bfe3f2eSlogwang
539*2bfe3f2eSlogwang    dev_list = map(dev_id_from_dev_name, dev_list)
540*2bfe3f2eSlogwang
541*2bfe3f2eSlogwang    for d in dev_list:
542*2bfe3f2eSlogwang        bind_one(d, driver, force)
543*2bfe3f2eSlogwang
544*2bfe3f2eSlogwang    # For kernels < 3.15 when binding devices to a generic driver
545*2bfe3f2eSlogwang    # (i.e. one that doesn't have a PCI ID table) using new_id, some devices
546*2bfe3f2eSlogwang    # that are not bound to any other driver could be bound even if no one has
547*2bfe3f2eSlogwang    # asked them to. hence, we check the list of drivers again, and see if
548*2bfe3f2eSlogwang    # some of the previously-unbound devices were erroneously bound.
549*2bfe3f2eSlogwang    if not os.path.exists("/sys/bus/pci/devices/%s/driver_override" % d):
550*2bfe3f2eSlogwang        for d in devices.keys():
551*2bfe3f2eSlogwang            # skip devices that were already bound or that we know should be bound
552*2bfe3f2eSlogwang            if "Driver_str" in devices[d] or d in dev_list:
553*2bfe3f2eSlogwang                continue
554*2bfe3f2eSlogwang
555*2bfe3f2eSlogwang            # update information about this device
556*2bfe3f2eSlogwang            devices[d] = dict(devices[d].items() +
557*2bfe3f2eSlogwang                              get_pci_device_details(d, True).items())
558*2bfe3f2eSlogwang
559*2bfe3f2eSlogwang            # check if updated information indicates that the device was bound
560*2bfe3f2eSlogwang            if "Driver_str" in devices[d]:
561*2bfe3f2eSlogwang                unbind_one(d, force)
562*2bfe3f2eSlogwang
563*2bfe3f2eSlogwang
564*2bfe3f2eSlogwangdef display_devices(title, dev_list, extra_params=None):
565*2bfe3f2eSlogwang    '''Displays to the user the details of a list of devices given in
566*2bfe3f2eSlogwang    "dev_list". The "extra_params" parameter, if given, should contain a string
567*2bfe3f2eSlogwang     with %()s fields in it for replacement by the named fields in each
568*2bfe3f2eSlogwang     device's dictionary.'''
569*2bfe3f2eSlogwang    strings = []  # this holds the strings to print. We sort before printing
570*2bfe3f2eSlogwang    print("\n%s" % title)
571*2bfe3f2eSlogwang    print("="*len(title))
572*2bfe3f2eSlogwang    if len(dev_list) == 0:
573*2bfe3f2eSlogwang        strings.append("<none>")
574*2bfe3f2eSlogwang    else:
575*2bfe3f2eSlogwang        for dev in dev_list:
576*2bfe3f2eSlogwang            if extra_params is not None:
577*2bfe3f2eSlogwang                strings.append("%s '%s %s' %s" % (dev["Slot"],
578*2bfe3f2eSlogwang                                               dev["Device_str"],
579*2bfe3f2eSlogwang                                               dev["Device"],
580*2bfe3f2eSlogwang                                               extra_params % dev))
581*2bfe3f2eSlogwang            else:
582*2bfe3f2eSlogwang                strings.append("%s '%s'" % (dev["Slot"], dev["Device_str"]))
583*2bfe3f2eSlogwang    # sort before printing, so that the entries appear in PCI order
584*2bfe3f2eSlogwang    strings.sort()
585*2bfe3f2eSlogwang    print("\n".join(strings))  # print one per line
586*2bfe3f2eSlogwang
587*2bfe3f2eSlogwangdef show_device_status(devices_type, device_name):
588*2bfe3f2eSlogwang    global dpdk_drivers
589*2bfe3f2eSlogwang    kernel_drv = []
590*2bfe3f2eSlogwang    dpdk_drv = []
591*2bfe3f2eSlogwang    no_drv = []
592*2bfe3f2eSlogwang
593*2bfe3f2eSlogwang    # split our list of network devices into the three categories above
594*2bfe3f2eSlogwang    for d in devices.keys():
595*2bfe3f2eSlogwang        if device_type_match(devices[d], devices_type):
596*2bfe3f2eSlogwang            if not has_driver(d):
597*2bfe3f2eSlogwang                no_drv.append(devices[d])
598*2bfe3f2eSlogwang                continue
599*2bfe3f2eSlogwang            if devices[d]["Driver_str"] in dpdk_drivers:
600*2bfe3f2eSlogwang                dpdk_drv.append(devices[d])
601*2bfe3f2eSlogwang            else:
602*2bfe3f2eSlogwang                kernel_drv.append(devices[d])
603*2bfe3f2eSlogwang
604*2bfe3f2eSlogwang    # print each category separately, so we can clearly see what's used by DPDK
605*2bfe3f2eSlogwang    display_devices("%s devices using DPDK-compatible driver" % device_name,
606*2bfe3f2eSlogwang                    dpdk_drv, "drv=%(Driver_str)s unused=%(Module_str)s")
607*2bfe3f2eSlogwang    display_devices("%s devices using kernel driver" % device_name, kernel_drv,
608*2bfe3f2eSlogwang                    "if=%(Interface)s drv=%(Driver_str)s "
609*2bfe3f2eSlogwang                    "unused=%(Module_str)s %(Active)s")
610*2bfe3f2eSlogwang    display_devices("Other %s devices" % device_name, no_drv,
611*2bfe3f2eSlogwang                    "unused=%(Module_str)s")
612*2bfe3f2eSlogwang
613*2bfe3f2eSlogwangdef show_status():
614*2bfe3f2eSlogwang    '''Function called when the script is passed the "--status" option.
615*2bfe3f2eSlogwang    Displays to the user what devices are bound to the igb_uio driver, the
616*2bfe3f2eSlogwang    kernel driver or to no driver'''
617*2bfe3f2eSlogwang
618*2bfe3f2eSlogwang    if status_dev == "net" or status_dev == "all":
619*2bfe3f2eSlogwang        show_device_status(network_devices, "Network")
620*2bfe3f2eSlogwang
621*2bfe3f2eSlogwang    if status_dev == "crypto" or status_dev == "all":
622*2bfe3f2eSlogwang        show_device_status(crypto_devices, "Crypto")
623*2bfe3f2eSlogwang
624*2bfe3f2eSlogwang    if status_dev == "event" or status_dev == "all":
625*2bfe3f2eSlogwang        show_device_status(eventdev_devices, "Eventdev")
626*2bfe3f2eSlogwang
627*2bfe3f2eSlogwang    if status_dev == "mempool" or status_dev == "all":
628*2bfe3f2eSlogwang        show_device_status(mempool_devices, "Mempool")
629*2bfe3f2eSlogwang
630*2bfe3f2eSlogwangdef parse_args():
631*2bfe3f2eSlogwang    '''Parses the command-line arguments given by the user and takes the
632*2bfe3f2eSlogwang    appropriate action for each'''
633*2bfe3f2eSlogwang    global b_flag
634*2bfe3f2eSlogwang    global status_flag
635*2bfe3f2eSlogwang    global status_dev
636*2bfe3f2eSlogwang    global force_flag
637*2bfe3f2eSlogwang    global args
638*2bfe3f2eSlogwang    if len(sys.argv) <= 1:
639*2bfe3f2eSlogwang        usage()
640*2bfe3f2eSlogwang        sys.exit(0)
641*2bfe3f2eSlogwang
642*2bfe3f2eSlogwang    try:
643*2bfe3f2eSlogwang        opts, args = getopt.getopt(sys.argv[1:], "b:us",
644*2bfe3f2eSlogwang                                   ["help", "usage", "status", "status-dev=",
645*2bfe3f2eSlogwang                                    "force", "bind=", "unbind", ])
646*2bfe3f2eSlogwang    except getopt.GetoptError as error:
647*2bfe3f2eSlogwang        print(str(error))
648*2bfe3f2eSlogwang        print("Run '%s --usage' for further information" % sys.argv[0])
649*2bfe3f2eSlogwang        sys.exit(1)
650*2bfe3f2eSlogwang
651*2bfe3f2eSlogwang    for opt, arg in opts:
652*2bfe3f2eSlogwang        if opt == "--help" or opt == "--usage":
653*2bfe3f2eSlogwang            usage()
654*2bfe3f2eSlogwang            sys.exit(0)
655*2bfe3f2eSlogwang        if opt == "--status-dev":
656*2bfe3f2eSlogwang            status_flag = True
657*2bfe3f2eSlogwang            status_dev = arg
658*2bfe3f2eSlogwang        if opt == "--status" or opt == "-s":
659*2bfe3f2eSlogwang            status_flag = True
660*2bfe3f2eSlogwang            status_dev = "all"
661*2bfe3f2eSlogwang        if opt == "--force":
662*2bfe3f2eSlogwang            force_flag = True
663*2bfe3f2eSlogwang        if opt == "-b" or opt == "-u" or opt == "--bind" or opt == "--unbind":
664*2bfe3f2eSlogwang            if b_flag is not None:
665*2bfe3f2eSlogwang                print("Error - Only one bind or unbind may be specified\n")
666*2bfe3f2eSlogwang                sys.exit(1)
667*2bfe3f2eSlogwang            if opt == "-u" or opt == "--unbind":
668*2bfe3f2eSlogwang                b_flag = "none"
669*2bfe3f2eSlogwang            else:
670*2bfe3f2eSlogwang                b_flag = arg
671*2bfe3f2eSlogwang
672*2bfe3f2eSlogwang
673*2bfe3f2eSlogwangdef do_arg_actions():
674*2bfe3f2eSlogwang    '''do the actual action requested by the user'''
675*2bfe3f2eSlogwang    global b_flag
676*2bfe3f2eSlogwang    global status_flag
677*2bfe3f2eSlogwang    global force_flag
678*2bfe3f2eSlogwang    global args
679*2bfe3f2eSlogwang
680*2bfe3f2eSlogwang    if b_flag is None and not status_flag:
681*2bfe3f2eSlogwang        print("Error: No action specified for devices."
682*2bfe3f2eSlogwang              "Please give a -b or -u option")
683*2bfe3f2eSlogwang        print("Run '%s --usage' for further information" % sys.argv[0])
684*2bfe3f2eSlogwang        sys.exit(1)
685*2bfe3f2eSlogwang
686*2bfe3f2eSlogwang    if b_flag is not None and len(args) == 0:
687*2bfe3f2eSlogwang        print("Error: No devices specified.")
688*2bfe3f2eSlogwang        print("Run '%s --usage' for further information" % sys.argv[0])
689*2bfe3f2eSlogwang        sys.exit(1)
690*2bfe3f2eSlogwang
691*2bfe3f2eSlogwang    if b_flag == "none" or b_flag == "None":
692*2bfe3f2eSlogwang        unbind_all(args, force_flag)
693*2bfe3f2eSlogwang    elif b_flag is not None:
694*2bfe3f2eSlogwang        bind_all(args, b_flag, force_flag)
695*2bfe3f2eSlogwang    if status_flag:
696*2bfe3f2eSlogwang        if b_flag is not None:
697*2bfe3f2eSlogwang            clear_data()
698*2bfe3f2eSlogwang            # refresh if we have changed anything
699*2bfe3f2eSlogwang            get_device_details(network_devices)
700*2bfe3f2eSlogwang            get_device_details(crypto_devices)
701*2bfe3f2eSlogwang            get_device_details(eventdev_devices)
702*2bfe3f2eSlogwang            get_device_details(mempool_devices)
703*2bfe3f2eSlogwang        show_status()
704*2bfe3f2eSlogwang
705*2bfe3f2eSlogwang
706*2bfe3f2eSlogwangdef main():
707*2bfe3f2eSlogwang    '''program main function'''
708*2bfe3f2eSlogwang    parse_args()
709*2bfe3f2eSlogwang    check_modules()
710*2bfe3f2eSlogwang    clear_data()
711*2bfe3f2eSlogwang    get_device_details(network_devices)
712*2bfe3f2eSlogwang    get_device_details(crypto_devices)
713*2bfe3f2eSlogwang    get_device_details(eventdev_devices)
714*2bfe3f2eSlogwang    get_device_details(mempool_devices)
715*2bfe3f2eSlogwang    do_arg_actions()
716*2bfe3f2eSlogwang
717*2bfe3f2eSlogwangif __name__ == "__main__":
718*2bfe3f2eSlogwang    main()
719