xref: /dpdk/usertools/dpdk-devbind.py (revision f4bc0010)
1c6dab2a8SThomas Monjalon#! /usr/bin/env python
29d7c01f8SBruce Richardson# SPDX-License-Identifier: BSD-3-Clause
39d7c01f8SBruce Richardson# Copyright(c) 2010-2014 Intel Corporation
4c6dab2a8SThomas Monjalon#
5c6dab2a8SThomas Monjalon
6c6dab2a8SThomas Monjalonimport sys
7c6dab2a8SThomas Monjalonimport os
8c6dab2a8SThomas Monjalonimport getopt
9c6dab2a8SThomas Monjalonimport subprocess
10c6dab2a8SThomas Monjalonfrom os.path import exists, abspath, dirname, basename
11c6dab2a8SThomas Monjalon
128ad08a28SGuduri Prathyusha# The PCI base class for all devices
138ad08a28SGuduri Prathyushanetwork_class = {'Class': '02', 'Vendor': None, 'Device': None,
148ad08a28SGuduri Prathyusha                    'SVendor': None, 'SDevice': None}
158ad08a28SGuduri Prathyushaencryption_class = {'Class': '10', 'Vendor': None, 'Device': None,
168ad08a28SGuduri Prathyusha                   'SVendor': None, 'SDevice': None}
178ad08a28SGuduri Prathyushaintel_processor_class = {'Class': '0b', 'Vendor': '8086', 'Device': None,
188ad08a28SGuduri Prathyusha                   'SVendor': None, 'SDevice': None}
1932a02dbfSGuduri Prathyushacavium_sso = {'Class': '08', 'Vendor': '177d', 'Device': 'a04b,a04d',
2032a02dbfSGuduri Prathyusha              'SVendor': None, 'SDevice': None}
2180a1858dSGuduri Prathyushacavium_fpa = {'Class': '08', 'Vendor': '177d', 'Device': 'a053',
2280a1858dSGuduri Prathyusha              'SVendor': None, 'SDevice': None}
23156c42eaSJerin Jacobcavium_pkx = {'Class': '08', 'Vendor': '177d', 'Device': 'a0dd,a049',
24156c42eaSJerin Jacob              'SVendor': None, 'SDevice': None}
25*f4bc0010SPavan Nikhileshcavium_tim = {'Class': '08', 'Vendor': '177d', 'Device': 'a051',
26*f4bc0010SPavan Nikhilesh              'SVendor': None, 'SDevice': None}
2720526313SXiaohua Zhangavp_vnic = {'Class': '05', 'Vendor': '1af4', 'Device': '1110',
2820526313SXiaohua Zhang              'SVendor': None, 'SDevice': None}
298ad08a28SGuduri Prathyusha
3020526313SXiaohua Zhangnetwork_devices = [network_class, cavium_pkx, avp_vnic]
318ad08a28SGuduri Prathyushacrypto_devices = [encryption_class, intel_processor_class]
32*f4bc0010SPavan Nikhilesheventdev_devices = [cavium_sso, cavium_tim]
3380a1858dSGuduri Prathyushamempool_devices = [cavium_fpa]
34c6dab2a8SThomas Monjalon
35c6dab2a8SThomas Monjalon# global dict ethernet devices present. Dictionary indexed by PCI address.
36c6dab2a8SThomas Monjalon# Each device within this is itself a dictionary of device properties
37c6dab2a8SThomas Monjalondevices = {}
38c6dab2a8SThomas Monjalon# list of supported DPDK drivers
39c6dab2a8SThomas Monjalondpdk_drivers = ["igb_uio", "vfio-pci", "uio_pci_generic"]
40c6dab2a8SThomas Monjalon
41c6dab2a8SThomas Monjalon# command-line arg flags
42c6dab2a8SThomas Monjalonb_flag = None
43c6dab2a8SThomas Monjalonstatus_flag = False
44c6dab2a8SThomas Monjalonforce_flag = False
45c6dab2a8SThomas Monjalonargs = []
46c6dab2a8SThomas Monjalon
47c6dab2a8SThomas Monjalon
48c6dab2a8SThomas Monjalondef usage():
49c6dab2a8SThomas Monjalon    '''Print usage information for the program'''
50c6dab2a8SThomas Monjalon    argv0 = basename(sys.argv[0])
51c6dab2a8SThomas Monjalon    print("""
52c6dab2a8SThomas MonjalonUsage:
53c6dab2a8SThomas Monjalon------
54c6dab2a8SThomas Monjalon
55c6dab2a8SThomas Monjalon     %(argv0)s [options] DEVICE1 DEVICE2 ....
56c6dab2a8SThomas Monjalon
57c6dab2a8SThomas Monjalonwhere DEVICE1, DEVICE2 etc, are specified via PCI "domain:bus:slot.func" syntax
58c6dab2a8SThomas Monjalonor "bus:slot.func" syntax. For devices bound to Linux kernel drivers, they may
59c6dab2a8SThomas Monjalonalso be referred to by Linux interface name e.g. eth0, eth1, em0, em1, etc.
60c6dab2a8SThomas Monjalon
61c6dab2a8SThomas MonjalonOptions:
62c6dab2a8SThomas Monjalon    --help, --usage:
63c6dab2a8SThomas Monjalon        Display usage information and quit
64c6dab2a8SThomas Monjalon
65c6dab2a8SThomas Monjalon    -s, --status:
66b153c00bSFerruh Yigit        Print the current status of all known network, crypto, event
67b153c00bSFerruh Yigit        and mempool devices.
68c6dab2a8SThomas Monjalon        For each device, it displays the PCI domain, bus, slot and function,
69c6dab2a8SThomas Monjalon        along with a text description of the device. Depending upon whether the
70c6dab2a8SThomas Monjalon        device is being used by a kernel driver, the igb_uio driver, or no
71c6dab2a8SThomas Monjalon        driver, other relevant information will be displayed:
72c6dab2a8SThomas Monjalon        * the Linux interface name e.g. if=eth0
73c6dab2a8SThomas Monjalon        * the driver being used e.g. drv=igb_uio
74c6dab2a8SThomas Monjalon        * any suitable drivers not currently using that device
75c6dab2a8SThomas Monjalon            e.g. unused=igb_uio
76c6dab2a8SThomas Monjalon        NOTE: if this flag is passed along with a bind/unbind option, the
77c6dab2a8SThomas Monjalon        status display will always occur after the other operations have taken
78c6dab2a8SThomas Monjalon        place.
79c6dab2a8SThomas Monjalon
80b153c00bSFerruh Yigit    --status-dev:
81b153c00bSFerruh Yigit        Print the status of given device group. Supported device groups are:
82b153c00bSFerruh Yigit        "net", "crypto", "event" and "mempool"
83b153c00bSFerruh Yigit
84c6dab2a8SThomas Monjalon    -b driver, --bind=driver:
85c6dab2a8SThomas Monjalon        Select the driver to use or \"none\" to unbind the device
86c6dab2a8SThomas Monjalon
87c6dab2a8SThomas Monjalon    -u, --unbind:
88c6dab2a8SThomas Monjalon        Unbind a device (Equivalent to \"-b none\")
89c6dab2a8SThomas Monjalon
90c6dab2a8SThomas Monjalon    --force:
91c6dab2a8SThomas Monjalon        By default, network devices which are used by Linux - as indicated by
92c6dab2a8SThomas Monjalon        having routes in the routing table - cannot be modified. Using the
93c6dab2a8SThomas Monjalon        --force flag overrides this behavior, allowing active links to be
94c6dab2a8SThomas Monjalon        forcibly unbound.
95c6dab2a8SThomas Monjalon        WARNING: This can lead to loss of network connection and should be used
96c6dab2a8SThomas Monjalon        with caution.
97c6dab2a8SThomas Monjalon
98c6dab2a8SThomas MonjalonExamples:
99c6dab2a8SThomas Monjalon---------
100c6dab2a8SThomas Monjalon
101c6dab2a8SThomas MonjalonTo display current device status:
102c6dab2a8SThomas Monjalon        %(argv0)s --status
103c6dab2a8SThomas Monjalon
104b153c00bSFerruh YigitTo display current network device status:
105b153c00bSFerruh Yigit        %(argv0)s --status-dev net
106b153c00bSFerruh Yigit
107c6dab2a8SThomas MonjalonTo bind eth1 from the current driver and move to use igb_uio
108c6dab2a8SThomas Monjalon        %(argv0)s --bind=igb_uio eth1
109c6dab2a8SThomas Monjalon
110c6dab2a8SThomas MonjalonTo unbind 0000:01:00.0 from using any driver
111c6dab2a8SThomas Monjalon        %(argv0)s -u 0000:01:00.0
112c6dab2a8SThomas Monjalon
113c6dab2a8SThomas MonjalonTo bind 0000:02:00.0 and 0000:02:00.1 to the ixgbe kernel driver
114c6dab2a8SThomas Monjalon        %(argv0)s -b ixgbe 02:00.0 02:00.1
115c6dab2a8SThomas Monjalon
116c6dab2a8SThomas Monjalon    """ % locals())  # replace items from local variables
117c6dab2a8SThomas Monjalon
118c6dab2a8SThomas Monjalon
119c6dab2a8SThomas Monjalon# This is roughly compatible with check_output function in subprocess module
120c6dab2a8SThomas Monjalon# which is only available in python 2.7.
121c6dab2a8SThomas Monjalondef check_output(args, stderr=None):
122c6dab2a8SThomas Monjalon    '''Run a command and capture its output'''
123c6dab2a8SThomas Monjalon    return subprocess.Popen(args, stdout=subprocess.PIPE,
124c6dab2a8SThomas Monjalon                            stderr=stderr).communicate()[0]
125c6dab2a8SThomas Monjalon
126c6dab2a8SThomas Monjalon
127c6dab2a8SThomas Monjalondef check_modules():
128c6dab2a8SThomas Monjalon    '''Checks that igb_uio is loaded'''
129c6dab2a8SThomas Monjalon    global dpdk_drivers
130c6dab2a8SThomas Monjalon
131c6dab2a8SThomas Monjalon    # list of supported modules
132c6dab2a8SThomas Monjalon    mods = [{"Name": driver, "Found": False} for driver in dpdk_drivers]
133c6dab2a8SThomas Monjalon
134c6dab2a8SThomas Monjalon    # first check if module is loaded
135c6dab2a8SThomas Monjalon    try:
136c6dab2a8SThomas Monjalon        # Get list of sysfs modules (both built-in and dynamically loaded)
137c6dab2a8SThomas Monjalon        sysfs_path = '/sys/module/'
138c6dab2a8SThomas Monjalon
139c6dab2a8SThomas Monjalon        # Get the list of directories in sysfs_path
140c6dab2a8SThomas Monjalon        sysfs_mods = [os.path.join(sysfs_path, o) for o
141c6dab2a8SThomas Monjalon                      in os.listdir(sysfs_path)
142c6dab2a8SThomas Monjalon                      if os.path.isdir(os.path.join(sysfs_path, o))]
143c6dab2a8SThomas Monjalon
144c6dab2a8SThomas Monjalon        # Extract the last element of '/sys/module/abc' in the array
145c6dab2a8SThomas Monjalon        sysfs_mods = [a.split('/')[-1] for a in sysfs_mods]
146c6dab2a8SThomas Monjalon
147c6dab2a8SThomas Monjalon        # special case for vfio_pci (module is named vfio-pci,
148c6dab2a8SThomas Monjalon        # but its .ko is named vfio_pci)
1498fab26f8SOmri Mor        sysfs_mods = [a if a != 'vfio_pci' else 'vfio-pci' for a in sysfs_mods]
150c6dab2a8SThomas Monjalon
151c6dab2a8SThomas Monjalon        for mod in mods:
152c6dab2a8SThomas Monjalon            if mod["Name"] in sysfs_mods:
153c6dab2a8SThomas Monjalon                mod["Found"] = True
154c6dab2a8SThomas Monjalon    except:
155c6dab2a8SThomas Monjalon        pass
156c6dab2a8SThomas Monjalon
157c6dab2a8SThomas Monjalon    # check if we have at least one loaded module
158c6dab2a8SThomas Monjalon    if True not in [mod["Found"] for mod in mods] and b_flag is not None:
159c6dab2a8SThomas Monjalon        if b_flag in dpdk_drivers:
160c6dab2a8SThomas Monjalon            print("Error - no supported modules(DPDK driver) are loaded")
161c6dab2a8SThomas Monjalon            sys.exit(1)
162c6dab2a8SThomas Monjalon        else:
163c6dab2a8SThomas Monjalon            print("Warning - no supported modules(DPDK driver) are loaded")
164c6dab2a8SThomas Monjalon
165c6dab2a8SThomas Monjalon    # change DPDK driver list to only contain drivers that are loaded
166c6dab2a8SThomas Monjalon    dpdk_drivers = [mod["Name"] for mod in mods if mod["Found"]]
167c6dab2a8SThomas Monjalon
168c6dab2a8SThomas Monjalon
169c6dab2a8SThomas Monjalondef has_driver(dev_id):
170c6dab2a8SThomas Monjalon    '''return true if a device is assigned to a driver. False otherwise'''
171c6dab2a8SThomas Monjalon    return "Driver_str" in devices[dev_id]
172c6dab2a8SThomas Monjalon
173c6dab2a8SThomas Monjalon
174c3ce205dSGuduri Prathyushadef get_pci_device_details(dev_id, probe_lspci):
175c6dab2a8SThomas Monjalon    '''This function gets additional details for a PCI device'''
176c6dab2a8SThomas Monjalon    device = {}
177c6dab2a8SThomas Monjalon
178c3ce205dSGuduri Prathyusha    if probe_lspci:
179c6dab2a8SThomas Monjalon        extra_info = check_output(["lspci", "-vmmks", dev_id]).splitlines()
180c6dab2a8SThomas Monjalon
181c6dab2a8SThomas Monjalon        # parse lspci details
182c6dab2a8SThomas Monjalon        for line in extra_info:
183c6dab2a8SThomas Monjalon            if len(line) == 0:
184c6dab2a8SThomas Monjalon                continue
185c6dab2a8SThomas Monjalon            name, value = line.decode().split("\t", 1)
186c6dab2a8SThomas Monjalon            name = name.strip(":") + "_str"
187c6dab2a8SThomas Monjalon            device[name] = value
188c6dab2a8SThomas Monjalon    # check for a unix interface name
189c6dab2a8SThomas Monjalon    device["Interface"] = ""
190c6dab2a8SThomas Monjalon    for base, dirs, _ in os.walk("/sys/bus/pci/devices/%s/" % dev_id):
191c6dab2a8SThomas Monjalon        if "net" in dirs:
192c6dab2a8SThomas Monjalon            device["Interface"] = \
193c6dab2a8SThomas Monjalon                ",".join(os.listdir(os.path.join(base, "net")))
194c6dab2a8SThomas Monjalon            break
195c6dab2a8SThomas Monjalon    # check if a port is used for ssh connection
196c6dab2a8SThomas Monjalon    device["Ssh_if"] = False
197c6dab2a8SThomas Monjalon    device["Active"] = ""
198c6dab2a8SThomas Monjalon
199c6dab2a8SThomas Monjalon    return device
200c6dab2a8SThomas Monjalon
201ea9f00f7SGuduri Prathyushadef clear_data():
202ea9f00f7SGuduri Prathyusha    '''This function clears any old data'''
203ea9f00f7SGuduri Prathyusha    devices = {}
204c6dab2a8SThomas Monjalon
205ea9f00f7SGuduri Prathyushadef get_device_details(devices_type):
206c6dab2a8SThomas Monjalon    '''This function populates the "devices" dictionary. The keys used are
207c6dab2a8SThomas Monjalon    the pci addresses (domain:bus:slot.func). The values are themselves
208c6dab2a8SThomas Monjalon    dictionaries - one for each NIC.'''
209c6dab2a8SThomas Monjalon    global devices
210c6dab2a8SThomas Monjalon    global dpdk_drivers
211c6dab2a8SThomas Monjalon
212c6dab2a8SThomas Monjalon    # first loop through and read details for all devices
213c3ce205dSGuduri Prathyusha    # request machine readable format, with numeric IDs and String
214c6dab2a8SThomas Monjalon    dev = {}
215c3ce205dSGuduri Prathyusha    dev_lines = check_output(["lspci", "-Dvmmnnk"]).splitlines()
216c6dab2a8SThomas Monjalon    for dev_line in dev_lines:
217c6dab2a8SThomas Monjalon        if len(dev_line) == 0:
2188ad08a28SGuduri Prathyusha            if device_type_match(dev, devices_type):
2198ad08a28SGuduri Prathyusha                # Replace "Driver" with "Driver_str" to have consistency of
2208ad08a28SGuduri Prathyusha                # of dictionary key names
221c3ce205dSGuduri Prathyusha                if "Driver" in dev.keys():
222c3ce205dSGuduri Prathyusha                    dev["Driver_str"] = dev.pop("Driver")
223c76a10ecSAnatoly Burakov                if "Module" in dev.keys():
224c76a10ecSAnatoly Burakov                    dev["Module_str"] = dev.pop("Module")
225c6dab2a8SThomas Monjalon                # use dict to make copy of dev
226c6dab2a8SThomas Monjalon                devices[dev["Slot"]] = dict(dev)
227c3ce205dSGuduri Prathyusha            # Clear previous device's data
228c3ce205dSGuduri Prathyusha            dev = {}
229c6dab2a8SThomas Monjalon        else:
230c6dab2a8SThomas Monjalon            name, value = dev_line.decode().split("\t", 1)
231c3ce205dSGuduri Prathyusha            value_list = value.rsplit(' ', 1)
232c3ce205dSGuduri Prathyusha            if len(value_list) > 1:
233c3ce205dSGuduri Prathyusha                # String stored in <name>_str
234c3ce205dSGuduri Prathyusha                dev[name.rstrip(":") + '_str'] = value_list[0]
235c3ce205dSGuduri Prathyusha            # Numeric IDs
236c3ce205dSGuduri Prathyusha            dev[name.rstrip(":")] = value_list[len(value_list) - 1] \
237c3ce205dSGuduri Prathyusha                .rstrip("]").lstrip("[")
238c6dab2a8SThomas Monjalon
2398ad08a28SGuduri Prathyusha    if devices_type == network_devices:
240c6dab2a8SThomas Monjalon        # check what is the interface if any for an ssh connection if
241c6dab2a8SThomas Monjalon        # any to this host, so we can mark it later.
242c6dab2a8SThomas Monjalon        ssh_if = []
243c6dab2a8SThomas Monjalon        route = check_output(["ip", "-o", "route"])
244c6dab2a8SThomas Monjalon        # filter out all lines for 169.254 routes
245c6dab2a8SThomas Monjalon        route = "\n".join(filter(lambda ln: not ln.startswith("169.254"),
246c6dab2a8SThomas Monjalon                             route.decode().splitlines()))
247c6dab2a8SThomas Monjalon        rt_info = route.split()
248c6dab2a8SThomas Monjalon        for i in range(len(rt_info) - 1):
249c6dab2a8SThomas Monjalon            if rt_info[i] == "dev":
250c6dab2a8SThomas Monjalon                ssh_if.append(rt_info[i+1])
251c6dab2a8SThomas Monjalon
252c6dab2a8SThomas Monjalon    # based on the basic info, get extended text details
253c6dab2a8SThomas Monjalon    for d in devices.keys():
2548ad08a28SGuduri Prathyusha        if not device_type_match(devices[d], devices_type):
255617d9052SYoni Gilad            continue
256617d9052SYoni Gilad
257c6dab2a8SThomas Monjalon        # get additional info and add it to existing data
258c6dab2a8SThomas Monjalon        devices[d] = devices[d].copy()
259c3ce205dSGuduri Prathyusha        # No need to probe lspci
260c3ce205dSGuduri Prathyusha        devices[d].update(get_pci_device_details(d, False).items())
261c6dab2a8SThomas Monjalon
2628ad08a28SGuduri Prathyusha        if devices_type == network_devices:
263ea9f00f7SGuduri Prathyusha            for _if in ssh_if:
264ea9f00f7SGuduri Prathyusha                if _if in devices[d]["Interface"].split(","):
265ea9f00f7SGuduri Prathyusha                    devices[d]["Ssh_if"] = True
266ea9f00f7SGuduri Prathyusha                    devices[d]["Active"] = "*Active*"
267ea9f00f7SGuduri Prathyusha                    break
268ea9f00f7SGuduri Prathyusha
269c6dab2a8SThomas Monjalon        # add igb_uio to list of supporting modules if needed
270c6dab2a8SThomas Monjalon        if "Module_str" in devices[d]:
271c6dab2a8SThomas Monjalon            for driver in dpdk_drivers:
272c6dab2a8SThomas Monjalon                if driver not in devices[d]["Module_str"]:
273c6dab2a8SThomas Monjalon                    devices[d]["Module_str"] = \
274c6dab2a8SThomas Monjalon                        devices[d]["Module_str"] + ",%s" % driver
275c6dab2a8SThomas Monjalon        else:
276c6dab2a8SThomas Monjalon            devices[d]["Module_str"] = ",".join(dpdk_drivers)
277c6dab2a8SThomas Monjalon
278c6dab2a8SThomas Monjalon        # make sure the driver and module strings do not have any duplicates
279c6dab2a8SThomas Monjalon        if has_driver(d):
280c6dab2a8SThomas Monjalon            modules = devices[d]["Module_str"].split(",")
281c6dab2a8SThomas Monjalon            if devices[d]["Driver_str"] in modules:
282c6dab2a8SThomas Monjalon                modules.remove(devices[d]["Driver_str"])
283c6dab2a8SThomas Monjalon                devices[d]["Module_str"] = ",".join(modules)
284c6dab2a8SThomas Monjalon
285c6dab2a8SThomas Monjalon
2868ad08a28SGuduri Prathyushadef device_type_match(dev, devices_type):
2878ad08a28SGuduri Prathyusha    for i in range(len(devices_type)):
2888ad08a28SGuduri Prathyusha        param_count = len(
2898ad08a28SGuduri Prathyusha            [x for x in devices_type[i].values() if x is not None])
2908ad08a28SGuduri Prathyusha        match_count = 0
2918ad08a28SGuduri Prathyusha        if dev["Class"][0:2] == devices_type[i]["Class"]:
2928ad08a28SGuduri Prathyusha            match_count = match_count + 1
2938ad08a28SGuduri Prathyusha            for key in devices_type[i].keys():
2948ad08a28SGuduri Prathyusha                if key != 'Class' and devices_type[i][key]:
2958ad08a28SGuduri Prathyusha                    value_list = devices_type[i][key].split(',')
2968ad08a28SGuduri Prathyusha                    for value in value_list:
2978ad08a28SGuduri Prathyusha                        if value.strip(' ') == dev[key]:
2988ad08a28SGuduri Prathyusha                            match_count = match_count + 1
2998ad08a28SGuduri Prathyusha            # count must be the number of non None parameters to match
3008ad08a28SGuduri Prathyusha            if match_count == param_count:
3018ad08a28SGuduri Prathyusha                return True
3028ad08a28SGuduri Prathyusha    return False
3038ad08a28SGuduri Prathyusha
304c6dab2a8SThomas Monjalondef dev_id_from_dev_name(dev_name):
305c6dab2a8SThomas Monjalon    '''Take a device "name" - a string passed in by user to identify a NIC
306c6dab2a8SThomas Monjalon    device, and determine the device id - i.e. the domain:bus:slot.func - for
307c6dab2a8SThomas Monjalon    it, which can then be used to index into the devices array'''
308c6dab2a8SThomas Monjalon
309c6dab2a8SThomas Monjalon    # check if it's already a suitable index
310c6dab2a8SThomas Monjalon    if dev_name in devices:
311c6dab2a8SThomas Monjalon        return dev_name
312c6dab2a8SThomas Monjalon    # check if it's an index just missing the domain part
313c6dab2a8SThomas Monjalon    elif "0000:" + dev_name in devices:
314c6dab2a8SThomas Monjalon        return "0000:" + dev_name
315c6dab2a8SThomas Monjalon    else:
316c6dab2a8SThomas Monjalon        # check if it's an interface name, e.g. eth1
317c6dab2a8SThomas Monjalon        for d in devices.keys():
318c6dab2a8SThomas Monjalon            if dev_name in devices[d]["Interface"].split(","):
319c6dab2a8SThomas Monjalon                return devices[d]["Slot"]
320c6dab2a8SThomas Monjalon    # if nothing else matches - error
321c6dab2a8SThomas Monjalon    print("Unknown device: %s. "
322c6dab2a8SThomas Monjalon          "Please specify device in \"bus:slot.func\" format" % dev_name)
323c6dab2a8SThomas Monjalon    sys.exit(1)
324c6dab2a8SThomas Monjalon
325c6dab2a8SThomas Monjalon
326c6dab2a8SThomas Monjalondef unbind_one(dev_id, force):
327c6dab2a8SThomas Monjalon    '''Unbind the device identified by "dev_id" from its current driver'''
328c6dab2a8SThomas Monjalon    dev = devices[dev_id]
329c6dab2a8SThomas Monjalon    if not has_driver(dev_id):
330c6dab2a8SThomas Monjalon        print("%s %s %s is not currently managed by any driver\n" %
331c6dab2a8SThomas Monjalon              (dev["Slot"], dev["Device_str"], dev["Interface"]))
332c6dab2a8SThomas Monjalon        return
333c6dab2a8SThomas Monjalon
334c6dab2a8SThomas Monjalon    # prevent us disconnecting ourselves
335c6dab2a8SThomas Monjalon    if dev["Ssh_if"] and not force:
336c6dab2a8SThomas Monjalon        print("Routing table indicates that interface %s is active. "
337c6dab2a8SThomas Monjalon              "Skipping unbind" % (dev_id))
338c6dab2a8SThomas Monjalon        return
339c6dab2a8SThomas Monjalon
340c6dab2a8SThomas Monjalon    # write to /sys to unbind
341c6dab2a8SThomas Monjalon    filename = "/sys/bus/pci/drivers/%s/unbind" % dev["Driver_str"]
342c6dab2a8SThomas Monjalon    try:
343c6dab2a8SThomas Monjalon        f = open(filename, "a")
344c6dab2a8SThomas Monjalon    except:
345c6dab2a8SThomas Monjalon        print("Error: unbind failed for %s - Cannot open %s"
346c6dab2a8SThomas Monjalon              % (dev_id, filename))
347c6dab2a8SThomas Monjalon        sys.exit(1)
348c6dab2a8SThomas Monjalon    f.write(dev_id)
349c6dab2a8SThomas Monjalon    f.close()
350c6dab2a8SThomas Monjalon
351c6dab2a8SThomas Monjalon
352c6dab2a8SThomas Monjalondef bind_one(dev_id, driver, force):
353c6dab2a8SThomas Monjalon    '''Bind the device given by "dev_id" to the driver "driver". If the device
354c6dab2a8SThomas Monjalon    is already bound to a different driver, it will be unbound first'''
355c6dab2a8SThomas Monjalon    dev = devices[dev_id]
356c6dab2a8SThomas Monjalon    saved_driver = None  # used to rollback any unbind in case of failure
357c6dab2a8SThomas Monjalon
358c6dab2a8SThomas Monjalon    # prevent disconnection of our ssh session
359c6dab2a8SThomas Monjalon    if dev["Ssh_if"] and not force:
360c6dab2a8SThomas Monjalon        print("Routing table indicates that interface %s is active. "
361c6dab2a8SThomas Monjalon              "Not modifying" % (dev_id))
362c6dab2a8SThomas Monjalon        return
363c6dab2a8SThomas Monjalon
364c6dab2a8SThomas Monjalon    # unbind any existing drivers we don't want
365c6dab2a8SThomas Monjalon    if has_driver(dev_id):
366c6dab2a8SThomas Monjalon        if dev["Driver_str"] == driver:
367c6dab2a8SThomas Monjalon            print("%s already bound to driver %s, skipping\n"
368c6dab2a8SThomas Monjalon                  % (dev_id, driver))
369c6dab2a8SThomas Monjalon            return
370c6dab2a8SThomas Monjalon        else:
371c6dab2a8SThomas Monjalon            saved_driver = dev["Driver_str"]
372c6dab2a8SThomas Monjalon            unbind_one(dev_id, force)
373c6dab2a8SThomas Monjalon            dev["Driver_str"] = ""  # clear driver string
374c6dab2a8SThomas Monjalon
3752fc35029SGuduri Prathyusha    # For kernels >= 3.15 driver_override can be used to specify the driver
3762fc35029SGuduri Prathyusha    # for a device rather than relying on the driver to provide a positive
3772fc35029SGuduri Prathyusha    # match of the device.  The existing process of looking up
3782fc35029SGuduri Prathyusha    # the vendor and device ID, adding them to the driver new_id,
3792fc35029SGuduri Prathyusha    # will erroneously bind other devices too which has the additional burden
3802fc35029SGuduri Prathyusha    # of unbinding those devices
381c6dab2a8SThomas Monjalon    if driver in dpdk_drivers:
3822fc35029SGuduri Prathyusha        filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id
3832fc35029SGuduri Prathyusha        if os.path.exists(filename):
3842fc35029SGuduri Prathyusha            try:
3852fc35029SGuduri Prathyusha                f = open(filename, "w")
3862fc35029SGuduri Prathyusha            except:
3872fc35029SGuduri Prathyusha                print("Error: bind failed for %s - Cannot open %s"
3882fc35029SGuduri Prathyusha                      % (dev_id, filename))
3892fc35029SGuduri Prathyusha                return
3902fc35029SGuduri Prathyusha            try:
3912fc35029SGuduri Prathyusha                f.write("%s" % driver)
3922fc35029SGuduri Prathyusha                f.close()
3932fc35029SGuduri Prathyusha            except:
3942fc35029SGuduri Prathyusha                print("Error: bind failed for %s - Cannot write driver %s to "
3952fc35029SGuduri Prathyusha                      "PCI ID " % (dev_id, driver))
3962fc35029SGuduri Prathyusha                return
3972fc35029SGuduri Prathyusha        # For kernels < 3.15 use new_id to add PCI id's to the driver
3982fc35029SGuduri Prathyusha        else:
399c6dab2a8SThomas Monjalon            filename = "/sys/bus/pci/drivers/%s/new_id" % driver
400c6dab2a8SThomas Monjalon            try:
401c6dab2a8SThomas Monjalon                f = open(filename, "w")
402c6dab2a8SThomas Monjalon            except:
403c6dab2a8SThomas Monjalon                print("Error: bind failed for %s - Cannot open %s"
404c6dab2a8SThomas Monjalon                      % (dev_id, filename))
405c6dab2a8SThomas Monjalon                return
406c6dab2a8SThomas Monjalon            try:
4078ad08a28SGuduri Prathyusha                # Convert Device and Vendor Id to int to write to new_id
4088ad08a28SGuduri Prathyusha                f.write("%04x %04x" % (int(dev["Vendor"],16),
4098ad08a28SGuduri Prathyusha                        int(dev["Device"], 16)))
410c6dab2a8SThomas Monjalon                f.close()
411c6dab2a8SThomas Monjalon            except:
412c6dab2a8SThomas Monjalon                print("Error: bind failed for %s - Cannot write new PCI ID to "
413c6dab2a8SThomas Monjalon                      "driver %s" % (dev_id, driver))
414c6dab2a8SThomas Monjalon                return
415c6dab2a8SThomas Monjalon
416c6dab2a8SThomas Monjalon    # do the bind by writing to /sys
417c6dab2a8SThomas Monjalon    filename = "/sys/bus/pci/drivers/%s/bind" % driver
418c6dab2a8SThomas Monjalon    try:
419c6dab2a8SThomas Monjalon        f = open(filename, "a")
420c6dab2a8SThomas Monjalon    except:
421c6dab2a8SThomas Monjalon        print("Error: bind failed for %s - Cannot open %s"
422c6dab2a8SThomas Monjalon              % (dev_id, filename))
423c6dab2a8SThomas Monjalon        if saved_driver is not None:  # restore any previous driver
424c6dab2a8SThomas Monjalon            bind_one(dev_id, saved_driver, force)
425c6dab2a8SThomas Monjalon        return
426c6dab2a8SThomas Monjalon    try:
427c6dab2a8SThomas Monjalon        f.write(dev_id)
428c6dab2a8SThomas Monjalon        f.close()
429c6dab2a8SThomas Monjalon    except:
430c6dab2a8SThomas Monjalon        # for some reason, closing dev_id after adding a new PCI ID to new_id
431c6dab2a8SThomas Monjalon        # results in IOError. however, if the device was successfully bound,
432c6dab2a8SThomas Monjalon        # we don't care for any errors and can safely ignore IOError
433c3ce205dSGuduri Prathyusha        tmp = get_pci_device_details(dev_id, True)
434c6dab2a8SThomas Monjalon        if "Driver_str" in tmp and tmp["Driver_str"] == driver:
435c6dab2a8SThomas Monjalon            return
436c6dab2a8SThomas Monjalon        print("Error: bind failed for %s - Cannot bind to driver %s"
437c6dab2a8SThomas Monjalon              % (dev_id, driver))
438c6dab2a8SThomas Monjalon        if saved_driver is not None:  # restore any previous driver
439c6dab2a8SThomas Monjalon            bind_one(dev_id, saved_driver, force)
440c6dab2a8SThomas Monjalon        return
441c6dab2a8SThomas Monjalon
442720b7a05SGuduri Prathyusha    # For kernels > 3.15 driver_override is used to bind a device to a driver.
443720b7a05SGuduri Prathyusha    # Before unbinding it, overwrite driver_override with empty string so that
444720b7a05SGuduri Prathyusha    # the device can be bound to any other driver
445720b7a05SGuduri Prathyusha    filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id
446720b7a05SGuduri Prathyusha    if os.path.exists(filename):
447720b7a05SGuduri Prathyusha        try:
448720b7a05SGuduri Prathyusha            f = open(filename, "w")
449720b7a05SGuduri Prathyusha        except:
450720b7a05SGuduri Prathyusha            print("Error: unbind failed for %s - Cannot open %s"
451720b7a05SGuduri Prathyusha                  % (dev_id, filename))
452720b7a05SGuduri Prathyusha            sys.exit(1)
453720b7a05SGuduri Prathyusha        try:
454720b7a05SGuduri Prathyusha            f.write("\00")
455720b7a05SGuduri Prathyusha            f.close()
456720b7a05SGuduri Prathyusha        except:
457720b7a05SGuduri Prathyusha            print("Error: unbind failed for %s - Cannot open %s"
458720b7a05SGuduri Prathyusha                  % (dev_id, filename))
459720b7a05SGuduri Prathyusha            sys.exit(1)
460720b7a05SGuduri Prathyusha
461c6dab2a8SThomas Monjalon
462c6dab2a8SThomas Monjalondef unbind_all(dev_list, force=False):
463c6dab2a8SThomas Monjalon    """Unbind method, takes a list of device locations"""
464657c7133SFerruh Yigit
465657c7133SFerruh Yigit    if dev_list[0] == "dpdk":
466657c7133SFerruh Yigit        for d in devices.keys():
467657c7133SFerruh Yigit            if "Driver_str" in devices[d]:
468657c7133SFerruh Yigit                if devices[d]["Driver_str"] in dpdk_drivers:
469657c7133SFerruh Yigit                    unbind_one(devices[d]["Slot"], force)
470657c7133SFerruh Yigit        return
471657c7133SFerruh Yigit
472c6dab2a8SThomas Monjalon    dev_list = map(dev_id_from_dev_name, dev_list)
473c6dab2a8SThomas Monjalon    for d in dev_list:
474c6dab2a8SThomas Monjalon        unbind_one(d, force)
475c6dab2a8SThomas Monjalon
476c6dab2a8SThomas Monjalon
477c6dab2a8SThomas Monjalondef bind_all(dev_list, driver, force=False):
478c6dab2a8SThomas Monjalon    """Bind method, takes a list of device locations"""
479c6dab2a8SThomas Monjalon    global devices
480c6dab2a8SThomas Monjalon
481c6dab2a8SThomas Monjalon    dev_list = map(dev_id_from_dev_name, dev_list)
482c6dab2a8SThomas Monjalon
483c6dab2a8SThomas Monjalon    for d in dev_list:
484c6dab2a8SThomas Monjalon        bind_one(d, driver, force)
485c6dab2a8SThomas Monjalon
486e4839614SPavel Shirshov    # For kernels < 3.15 when binding devices to a generic driver
4872fc35029SGuduri Prathyusha    # (i.e. one that doesn't have a PCI ID table) using new_id, some devices
4882fc35029SGuduri Prathyusha    # that are not bound to any other driver could be bound even if no one has
4892fc35029SGuduri Prathyusha    # asked them to. hence, we check the list of drivers again, and see if
4902fc35029SGuduri Prathyusha    # some of the previously-unbound devices were erroneously bound.
4912fc35029SGuduri Prathyusha    if not os.path.exists("/sys/bus/pci/devices/%s/driver_override" % d):
492c6dab2a8SThomas Monjalon        for d in devices.keys():
493c6dab2a8SThomas Monjalon            # skip devices that were already bound or that we know should be bound
494c6dab2a8SThomas Monjalon            if "Driver_str" in devices[d] or d in dev_list:
495c6dab2a8SThomas Monjalon                continue
496c6dab2a8SThomas Monjalon
497c6dab2a8SThomas Monjalon            # update information about this device
498c6dab2a8SThomas Monjalon            devices[d] = dict(devices[d].items() +
499c3ce205dSGuduri Prathyusha                              get_pci_device_details(d, True).items())
500c6dab2a8SThomas Monjalon
501c6dab2a8SThomas Monjalon            # check if updated information indicates that the device was bound
502c6dab2a8SThomas Monjalon            if "Driver_str" in devices[d]:
503c6dab2a8SThomas Monjalon                unbind_one(d, force)
504c6dab2a8SThomas Monjalon
505c6dab2a8SThomas Monjalon
506c6dab2a8SThomas Monjalondef display_devices(title, dev_list, extra_params=None):
507c6dab2a8SThomas Monjalon    '''Displays to the user the details of a list of devices given in
508c6dab2a8SThomas Monjalon    "dev_list". The "extra_params" parameter, if given, should contain a string
509c6dab2a8SThomas Monjalon     with %()s fields in it for replacement by the named fields in each
510c6dab2a8SThomas Monjalon     device's dictionary.'''
511c6dab2a8SThomas Monjalon    strings = []  # this holds the strings to print. We sort before printing
512c6dab2a8SThomas Monjalon    print("\n%s" % title)
513c6dab2a8SThomas Monjalon    print("="*len(title))
514c6dab2a8SThomas Monjalon    if len(dev_list) == 0:
515c6dab2a8SThomas Monjalon        strings.append("<none>")
516c6dab2a8SThomas Monjalon    else:
517c6dab2a8SThomas Monjalon        for dev in dev_list:
518c6dab2a8SThomas Monjalon            if extra_params is not None:
519c3ce205dSGuduri Prathyusha                strings.append("%s '%s %s' %s" % (dev["Slot"],
520c6dab2a8SThomas Monjalon                                               dev["Device_str"],
521c3ce205dSGuduri Prathyusha                                               dev["Device"],
522c6dab2a8SThomas Monjalon                                               extra_params % dev))
523c6dab2a8SThomas Monjalon            else:
524c6dab2a8SThomas Monjalon                strings.append("%s '%s'" % (dev["Slot"], dev["Device_str"]))
525c6dab2a8SThomas Monjalon    # sort before printing, so that the entries appear in PCI order
526c6dab2a8SThomas Monjalon    strings.sort()
527c6dab2a8SThomas Monjalon    print("\n".join(strings))  # print one per line
528c6dab2a8SThomas Monjalon
529c7dd412bSGuduri Prathyushadef show_device_status(devices_type, device_name):
530c6dab2a8SThomas Monjalon    global dpdk_drivers
531c6dab2a8SThomas Monjalon    kernel_drv = []
532c6dab2a8SThomas Monjalon    dpdk_drv = []
533c6dab2a8SThomas Monjalon    no_drv = []
534c6dab2a8SThomas Monjalon
535c6dab2a8SThomas Monjalon    # split our list of network devices into the three categories above
536c6dab2a8SThomas Monjalon    for d in devices.keys():
5378ad08a28SGuduri Prathyusha        if device_type_match(devices[d], devices_type):
538c6dab2a8SThomas Monjalon            if not has_driver(d):
539c6dab2a8SThomas Monjalon                no_drv.append(devices[d])
540c6dab2a8SThomas Monjalon                continue
541c6dab2a8SThomas Monjalon            if devices[d]["Driver_str"] in dpdk_drivers:
542c6dab2a8SThomas Monjalon                dpdk_drv.append(devices[d])
543c6dab2a8SThomas Monjalon            else:
544c6dab2a8SThomas Monjalon                kernel_drv.append(devices[d])
545c6dab2a8SThomas Monjalon
546c6dab2a8SThomas Monjalon    # print each category separately, so we can clearly see what's used by DPDK
5478ad08a28SGuduri Prathyusha    display_devices("%s devices using DPDK-compatible driver" % device_name,
5488ad08a28SGuduri Prathyusha                    dpdk_drv, "drv=%(Driver_str)s unused=%(Module_str)s")
549c7dd412bSGuduri Prathyusha    display_devices("%s devices using kernel driver" % device_name, kernel_drv,
550c6dab2a8SThomas Monjalon                    "if=%(Interface)s drv=%(Driver_str)s "
551c6dab2a8SThomas Monjalon                    "unused=%(Module_str)s %(Active)s")
5528ad08a28SGuduri Prathyusha    display_devices("Other %s devices" % device_name, no_drv,
5538ad08a28SGuduri Prathyusha                    "unused=%(Module_str)s")
554c6dab2a8SThomas Monjalon
555c7dd412bSGuduri Prathyushadef show_status():
556c7dd412bSGuduri Prathyusha    '''Function called when the script is passed the "--status" option.
557c7dd412bSGuduri Prathyusha    Displays to the user what devices are bound to the igb_uio driver, the
558c7dd412bSGuduri Prathyusha    kernel driver or to no driver'''
559c6dab2a8SThomas Monjalon
560b153c00bSFerruh Yigit    if status_dev == "net" or status_dev == "all":
561c7dd412bSGuduri Prathyusha        show_device_status(network_devices, "Network")
562b153c00bSFerruh Yigit
563b153c00bSFerruh Yigit    if status_dev == "crypto" or status_dev == "all":
564c7dd412bSGuduri Prathyusha        show_device_status(crypto_devices, "Crypto")
565b153c00bSFerruh Yigit
566b153c00bSFerruh Yigit    if status_dev == "event" or status_dev == "all":
56732a02dbfSGuduri Prathyusha        show_device_status(eventdev_devices, "Eventdev")
568b153c00bSFerruh Yigit
569b153c00bSFerruh Yigit    if status_dev == "mempool" or status_dev == "all":
57080a1858dSGuduri Prathyusha        show_device_status(mempool_devices, "Mempool")
571c6dab2a8SThomas Monjalon
572c6dab2a8SThomas Monjalondef parse_args():
573c6dab2a8SThomas Monjalon    '''Parses the command-line arguments given by the user and takes the
574c6dab2a8SThomas Monjalon    appropriate action for each'''
575c6dab2a8SThomas Monjalon    global b_flag
576c6dab2a8SThomas Monjalon    global status_flag
577b153c00bSFerruh Yigit    global status_dev
578c6dab2a8SThomas Monjalon    global force_flag
579c6dab2a8SThomas Monjalon    global args
580c6dab2a8SThomas Monjalon    if len(sys.argv) <= 1:
581c6dab2a8SThomas Monjalon        usage()
582c6dab2a8SThomas Monjalon        sys.exit(0)
583c6dab2a8SThomas Monjalon
584c6dab2a8SThomas Monjalon    try:
585c6dab2a8SThomas Monjalon        opts, args = getopt.getopt(sys.argv[1:], "b:us",
586b153c00bSFerruh Yigit                                   ["help", "usage", "status", "status-dev=",
587b153c00bSFerruh Yigit                                    "force", "bind=", "unbind", ])
588c6dab2a8SThomas Monjalon    except getopt.GetoptError as error:
589c6dab2a8SThomas Monjalon        print(str(error))
590c6dab2a8SThomas Monjalon        print("Run '%s --usage' for further information" % sys.argv[0])
591c6dab2a8SThomas Monjalon        sys.exit(1)
592c6dab2a8SThomas Monjalon
593c6dab2a8SThomas Monjalon    for opt, arg in opts:
594c6dab2a8SThomas Monjalon        if opt == "--help" or opt == "--usage":
595c6dab2a8SThomas Monjalon            usage()
596c6dab2a8SThomas Monjalon            sys.exit(0)
597b153c00bSFerruh Yigit        if opt == "--status-dev":
598b153c00bSFerruh Yigit            status_flag = True
599b153c00bSFerruh Yigit            status_dev = arg
600c6dab2a8SThomas Monjalon        if opt == "--status" or opt == "-s":
601c6dab2a8SThomas Monjalon            status_flag = True
602b153c00bSFerruh Yigit            status_dev = "all"
603c6dab2a8SThomas Monjalon        if opt == "--force":
604c6dab2a8SThomas Monjalon            force_flag = True
605c6dab2a8SThomas Monjalon        if opt == "-b" or opt == "-u" or opt == "--bind" or opt == "--unbind":
606c6dab2a8SThomas Monjalon            if b_flag is not None:
607c6dab2a8SThomas Monjalon                print("Error - Only one bind or unbind may be specified\n")
608c6dab2a8SThomas Monjalon                sys.exit(1)
609c6dab2a8SThomas Monjalon            if opt == "-u" or opt == "--unbind":
610c6dab2a8SThomas Monjalon                b_flag = "none"
611c6dab2a8SThomas Monjalon            else:
612c6dab2a8SThomas Monjalon                b_flag = arg
613c6dab2a8SThomas Monjalon
614c6dab2a8SThomas Monjalon
615c6dab2a8SThomas Monjalondef do_arg_actions():
616c6dab2a8SThomas Monjalon    '''do the actual action requested by the user'''
617c6dab2a8SThomas Monjalon    global b_flag
618c6dab2a8SThomas Monjalon    global status_flag
619c6dab2a8SThomas Monjalon    global force_flag
620c6dab2a8SThomas Monjalon    global args
621c6dab2a8SThomas Monjalon
622c6dab2a8SThomas Monjalon    if b_flag is None and not status_flag:
623c6dab2a8SThomas Monjalon        print("Error: No action specified for devices."
624c6dab2a8SThomas Monjalon              "Please give a -b or -u option")
625c6dab2a8SThomas Monjalon        print("Run '%s --usage' for further information" % sys.argv[0])
626c6dab2a8SThomas Monjalon        sys.exit(1)
627c6dab2a8SThomas Monjalon
628c6dab2a8SThomas Monjalon    if b_flag is not None and len(args) == 0:
629c6dab2a8SThomas Monjalon        print("Error: No devices specified.")
630c6dab2a8SThomas Monjalon        print("Run '%s --usage' for further information" % sys.argv[0])
631c6dab2a8SThomas Monjalon        sys.exit(1)
632c6dab2a8SThomas Monjalon
633c6dab2a8SThomas Monjalon    if b_flag == "none" or b_flag == "None":
634c6dab2a8SThomas Monjalon        unbind_all(args, force_flag)
635c6dab2a8SThomas Monjalon    elif b_flag is not None:
636c6dab2a8SThomas Monjalon        bind_all(args, b_flag, force_flag)
637c6dab2a8SThomas Monjalon    if status_flag:
638c6dab2a8SThomas Monjalon        if b_flag is not None:
639ea9f00f7SGuduri Prathyusha            clear_data()
6408ad08a28SGuduri Prathyusha            # refresh if we have changed anything
6418ad08a28SGuduri Prathyusha            get_device_details(network_devices)
6428ad08a28SGuduri Prathyusha            get_device_details(crypto_devices)
64332a02dbfSGuduri Prathyusha            get_device_details(eventdev_devices)
64480a1858dSGuduri Prathyusha            get_device_details(mempool_devices)
645c6dab2a8SThomas Monjalon        show_status()
646c6dab2a8SThomas Monjalon
647c6dab2a8SThomas Monjalon
648c6dab2a8SThomas Monjalondef main():
649c6dab2a8SThomas Monjalon    '''program main function'''
650c6dab2a8SThomas Monjalon    parse_args()
651c6dab2a8SThomas Monjalon    check_modules()
652ea9f00f7SGuduri Prathyusha    clear_data()
6538ad08a28SGuduri Prathyusha    get_device_details(network_devices)
6548ad08a28SGuduri Prathyusha    get_device_details(crypto_devices)
65532a02dbfSGuduri Prathyusha    get_device_details(eventdev_devices)
65680a1858dSGuduri Prathyusha    get_device_details(mempool_devices)
657c6dab2a8SThomas Monjalon    do_arg_actions()
658c6dab2a8SThomas Monjalon
659c6dab2a8SThomas Monjalonif __name__ == "__main__":
660c6dab2a8SThomas Monjalon    main()
661