]>
Commit | Line | Data |
---|---|---|
9f95a23c | 1 | #!/usr/bin/env python2 |
7c673cae FG |
2 | # |
3 | # BSD LICENSE | |
4 | # | |
5 | # Copyright(c) 2010-2014 Intel Corporation. All rights reserved. | |
6 | # All rights reserved. | |
7 | # | |
8 | # Redistribution and use in source and binary forms, with or without | |
9 | # modification, are permitted provided that the following conditions | |
10 | # are met: | |
11 | # | |
12 | # * Redistributions of source code must retain the above copyright | |
13 | # notice, this list of conditions and the following disclaimer. | |
14 | # * Redistributions in binary form must reproduce the above copyright | |
15 | # notice, this list of conditions and the following disclaimer in | |
16 | # the documentation and/or other materials provided with the | |
17 | # distribution. | |
18 | # * Neither the name of Intel Corporation nor the names of its | |
19 | # contributors may be used to endorse or promote products derived | |
20 | # from this software without specific prior written permission. | |
21 | # | |
22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | # | |
34 | ||
11fdf7f2 | 35 | import sys, os, getopt, subprocess |
7c673cae FG |
36 | from os.path import exists, abspath, dirname, basename |
37 | ||
11fdf7f2 TL |
38 | |
39 | # The PCI device class for ETHERNET devices | |
40 | ETHERNET_CLASS = "0200" | |
7c673cae FG |
41 | |
42 | # global dict ethernet devices present. Dictionary indexed by PCI address. | |
43 | # Each device within this is itself a dictionary of device properties | |
44 | devices = {} | |
45 | # list of supported DPDK drivers | |
11fdf7f2 | 46 | dpdk_drivers = [ "igb_uio", "vfio-pci", "uio_pci_generic" ] |
7c673cae FG |
47 | |
48 | # command-line arg flags | |
49 | b_flag = None | |
50 | status_flag = False | |
51 | force_flag = False | |
52 | args = [] | |
53 | ||
7c673cae FG |
54 | def usage(): |
55 | '''Print usage information for the program''' | |
56 | argv0 = basename(sys.argv[0]) | |
11fdf7f2 | 57 | print """ |
7c673cae FG |
58 | Usage: |
59 | ------ | |
60 | ||
61 | %(argv0)s [options] DEVICE1 DEVICE2 .... | |
62 | ||
63 | where DEVICE1, DEVICE2 etc, are specified via PCI "domain:bus:slot.func" syntax | |
64 | or "bus:slot.func" syntax. For devices bound to Linux kernel drivers, they may | |
65 | also be referred to by Linux interface name e.g. eth0, eth1, em0, em1, etc. | |
66 | ||
67 | Options: | |
68 | --help, --usage: | |
69 | Display usage information and quit | |
70 | ||
11fdf7f2 TL |
71 | --status: |
72 | Print the current status of all known network interfaces. | |
7c673cae FG |
73 | For each device, it displays the PCI domain, bus, slot and function, |
74 | along with a text description of the device. Depending upon whether the | |
75 | device is being used by a kernel driver, the igb_uio driver, or no | |
76 | driver, other relevant information will be displayed: | |
77 | * the Linux interface name e.g. if=eth0 | |
78 | * the driver being used e.g. drv=igb_uio | |
79 | * any suitable drivers not currently using that device | |
80 | e.g. unused=igb_uio | |
11fdf7f2 TL |
81 | NOTE: if this flag is passed along with a bind/unbind option, the status |
82 | display will always occur after the other operations have taken place. | |
7c673cae FG |
83 | |
84 | -b driver, --bind=driver: | |
85 | Select the driver to use or \"none\" to unbind the device | |
86 | ||
87 | -u, --unbind: | |
88 | Unbind a device (Equivalent to \"-b none\") | |
89 | ||
90 | --force: | |
11fdf7f2 | 91 | By default, devices which are used by Linux - as indicated by having |
7c673cae FG |
92 | routes in the routing table - cannot be modified. Using the --force |
93 | flag overrides this behavior, allowing active links to be forcibly | |
94 | unbound. | |
95 | WARNING: This can lead to loss of network connection and should be used | |
96 | with caution. | |
97 | ||
98 | Examples: | |
99 | --------- | |
100 | ||
101 | To display current device status: | |
102 | %(argv0)s --status | |
103 | ||
104 | To bind eth1 from the current driver and move to use igb_uio | |
105 | %(argv0)s --bind=igb_uio eth1 | |
106 | ||
107 | To unbind 0000:01:00.0 from using any driver | |
108 | %(argv0)s -u 0000:01:00.0 | |
109 | ||
110 | To bind 0000:02:00.0 and 0000:02:00.1 to the ixgbe kernel driver | |
111 | %(argv0)s -b ixgbe 02:00.0 02:00.1 | |
112 | ||
11fdf7f2 | 113 | """ % locals() # replace items from local variables |
7c673cae FG |
114 | |
115 | # This is roughly compatible with check_output function in subprocess module | |
116 | # which is only available in python 2.7. | |
117 | def check_output(args, stderr=None): | |
118 | '''Run a command and capture its output''' | |
119 | return subprocess.Popen(args, stdout=subprocess.PIPE, | |
120 | stderr=stderr).communicate()[0] | |
121 | ||
7c673cae FG |
122 | def find_module(mod): |
123 | '''find the .ko file for kernel module named mod. | |
124 | Searches the $RTE_SDK/$RTE_TARGET directory, the kernel | |
125 | modules directory and finally under the parent directory of | |
126 | the script ''' | |
127 | # check $RTE_SDK/$RTE_TARGET directory | |
128 | if 'RTE_SDK' in os.environ and 'RTE_TARGET' in os.environ: | |
11fdf7f2 | 129 | path = "%s/%s/kmod/%s.ko" % (os.environ['RTE_SDK'],\ |
7c673cae FG |
130 | os.environ['RTE_TARGET'], mod) |
131 | if exists(path): | |
132 | return path | |
133 | ||
134 | # check using depmod | |
135 | try: | |
11fdf7f2 | 136 | depmod_out = check_output(["modinfo", "-n", mod], \ |
7c673cae FG |
137 | stderr=subprocess.STDOUT).lower() |
138 | if "error" not in depmod_out: | |
139 | path = depmod_out.strip() | |
140 | if exists(path): | |
141 | return path | |
11fdf7f2 | 142 | except: # if modinfo can't find module, it fails, so continue |
7c673cae FG |
143 | pass |
144 | ||
145 | # check for a copy based off current path | |
146 | tools_dir = dirname(abspath(sys.argv[0])) | |
147 | if (tools_dir.endswith("tools")): | |
148 | base_dir = dirname(tools_dir) | |
149 | find_out = check_output(["find", base_dir, "-name", mod + ".ko"]) | |
11fdf7f2 | 150 | if len(find_out) > 0: #something matched |
7c673cae FG |
151 | path = find_out.splitlines()[0] |
152 | if exists(path): | |
153 | return path | |
154 | ||
7c673cae FG |
155 | def check_modules(): |
156 | '''Checks that igb_uio is loaded''' | |
157 | global dpdk_drivers | |
158 | ||
11fdf7f2 TL |
159 | fd = file("/proc/modules") |
160 | loaded_mods = fd.readlines() | |
161 | fd.close() | |
162 | ||
7c673cae | 163 | # list of supported modules |
11fdf7f2 | 164 | mods = [{"Name" : driver, "Found" : False} for driver in dpdk_drivers] |
7c673cae FG |
165 | |
166 | # first check if module is loaded | |
11fdf7f2 | 167 | for line in loaded_mods: |
7c673cae | 168 | for mod in mods: |
11fdf7f2 TL |
169 | if line.startswith(mod["Name"]): |
170 | mod["Found"] = True | |
171 | # special case for vfio_pci (module is named vfio-pci, | |
172 | # but its .ko is named vfio_pci) | |
173 | elif line.replace("_", "-").startswith(mod["Name"]): | |
7c673cae | 174 | mod["Found"] = True |
7c673cae FG |
175 | |
176 | # check if we have at least one loaded module | |
177 | if True not in [mod["Found"] for mod in mods] and b_flag is not None: | |
178 | if b_flag in dpdk_drivers: | |
11fdf7f2 | 179 | print "Error - no supported modules(DPDK driver) are loaded" |
7c673cae FG |
180 | sys.exit(1) |
181 | else: | |
11fdf7f2 | 182 | print "Warning - no supported modules(DPDK driver) are loaded" |
7c673cae FG |
183 | |
184 | # change DPDK driver list to only contain drivers that are loaded | |
185 | dpdk_drivers = [mod["Name"] for mod in mods if mod["Found"]] | |
186 | ||
7c673cae FG |
187 | def has_driver(dev_id): |
188 | '''return true if a device is assigned to a driver. False otherwise''' | |
189 | return "Driver_str" in devices[dev_id] | |
190 | ||
7c673cae FG |
191 | def get_pci_device_details(dev_id): |
192 | '''This function gets additional details for a PCI device''' | |
193 | device = {} | |
194 | ||
195 | extra_info = check_output(["lspci", "-vmmks", dev_id]).splitlines() | |
196 | ||
197 | # parse lspci details | |
198 | for line in extra_info: | |
199 | if len(line) == 0: | |
200 | continue | |
11fdf7f2 | 201 | name, value = line.split("\t", 1) |
7c673cae FG |
202 | name = name.strip(":") + "_str" |
203 | device[name] = value | |
204 | # check for a unix interface name | |
11fdf7f2 TL |
205 | sys_path = "/sys/bus/pci/devices/%s/net/" % dev_id |
206 | if exists(sys_path): | |
207 | device["Interface"] = ",".join(os.listdir(sys_path)) | |
208 | else: | |
209 | device["Interface"] = "" | |
7c673cae FG |
210 | # check if a port is used for ssh connection |
211 | device["Ssh_if"] = False | |
212 | device["Active"] = "" | |
213 | ||
214 | return device | |
215 | ||
7c673cae FG |
216 | def get_nic_details(): |
217 | '''This function populates the "devices" dictionary. The keys used are | |
218 | the pci addresses (domain:bus:slot.func). The values are themselves | |
219 | dictionaries - one for each NIC.''' | |
220 | global devices | |
221 | global dpdk_drivers | |
222 | ||
223 | # clear any old data | |
224 | devices = {} | |
225 | # first loop through and read details for all devices | |
226 | # request machine readable format, with numeric IDs | |
11fdf7f2 | 227 | dev = {}; |
7c673cae FG |
228 | dev_lines = check_output(["lspci", "-Dvmmn"]).splitlines() |
229 | for dev_line in dev_lines: | |
230 | if (len(dev_line) == 0): | |
11fdf7f2 TL |
231 | if dev["Class"] == ETHERNET_CLASS: |
232 | #convert device and vendor ids to numbers, then add to global | |
233 | dev["Vendor"] = int(dev["Vendor"],16) | |
234 | dev["Device"] = int(dev["Device"],16) | |
235 | devices[dev["Slot"]] = dict(dev) # use dict to make copy of dev | |
7c673cae | 236 | else: |
11fdf7f2 | 237 | name, value = dev_line.split("\t", 1) |
7c673cae FG |
238 | dev[name.rstrip(":")] = value |
239 | ||
240 | # check what is the interface if any for an ssh connection if | |
241 | # any to this host, so we can mark it later. | |
242 | ssh_if = [] | |
243 | route = check_output(["ip", "-o", "route"]) | |
244 | # filter out all lines for 169.254 routes | |
245 | route = "\n".join(filter(lambda ln: not ln.startswith("169.254"), | |
11fdf7f2 | 246 | route.splitlines())) |
7c673cae | 247 | rt_info = route.split() |
11fdf7f2 | 248 | for i in xrange(len(rt_info) - 1): |
7c673cae FG |
249 | if rt_info[i] == "dev": |
250 | ssh_if.append(rt_info[i+1]) | |
251 | ||
252 | # based on the basic info, get extended text details | |
253 | for d in devices.keys(): | |
254 | # get additional info and add it to existing data | |
11fdf7f2 TL |
255 | devices[d] = dict(devices[d].items() + |
256 | get_pci_device_details(d).items()) | |
7c673cae FG |
257 | |
258 | for _if in ssh_if: | |
259 | if _if in devices[d]["Interface"].split(","): | |
260 | devices[d]["Ssh_if"] = True | |
261 | devices[d]["Active"] = "*Active*" | |
11fdf7f2 | 262 | break; |
7c673cae FG |
263 | |
264 | # add igb_uio to list of supporting modules if needed | |
265 | if "Module_str" in devices[d]: | |
266 | for driver in dpdk_drivers: | |
267 | if driver not in devices[d]["Module_str"]: | |
11fdf7f2 | 268 | devices[d]["Module_str"] = devices[d]["Module_str"] + ",%s" % driver |
7c673cae FG |
269 | else: |
270 | devices[d]["Module_str"] = ",".join(dpdk_drivers) | |
271 | ||
272 | # make sure the driver and module strings do not have any duplicates | |
273 | if has_driver(d): | |
274 | modules = devices[d]["Module_str"].split(",") | |
275 | if devices[d]["Driver_str"] in modules: | |
276 | modules.remove(devices[d]["Driver_str"]) | |
277 | devices[d]["Module_str"] = ",".join(modules) | |
278 | ||
7c673cae FG |
279 | def dev_id_from_dev_name(dev_name): |
280 | '''Take a device "name" - a string passed in by user to identify a NIC | |
281 | device, and determine the device id - i.e. the domain:bus:slot.func - for | |
282 | it, which can then be used to index into the devices array''' | |
11fdf7f2 | 283 | dev = None |
7c673cae FG |
284 | # check if it's already a suitable index |
285 | if dev_name in devices: | |
286 | return dev_name | |
287 | # check if it's an index just missing the domain part | |
288 | elif "0000:" + dev_name in devices: | |
289 | return "0000:" + dev_name | |
290 | else: | |
291 | # check if it's an interface name, e.g. eth1 | |
292 | for d in devices.keys(): | |
293 | if dev_name in devices[d]["Interface"].split(","): | |
294 | return devices[d]["Slot"] | |
295 | # if nothing else matches - error | |
11fdf7f2 TL |
296 | print "Unknown device: %s. " \ |
297 | "Please specify device in \"bus:slot.func\" format" % dev_name | |
7c673cae FG |
298 | sys.exit(1) |
299 | ||
7c673cae FG |
300 | def unbind_one(dev_id, force): |
301 | '''Unbind the device identified by "dev_id" from its current driver''' | |
302 | dev = devices[dev_id] | |
303 | if not has_driver(dev_id): | |
11fdf7f2 TL |
304 | print "%s %s %s is not currently managed by any driver\n" % \ |
305 | (dev["Slot"], dev["Device_str"], dev["Interface"]) | |
7c673cae FG |
306 | return |
307 | ||
308 | # prevent us disconnecting ourselves | |
309 | if dev["Ssh_if"] and not force: | |
11fdf7f2 TL |
310 | print "Routing table indicates that interface %s is active" \ |
311 | ". Skipping unbind" % (dev_id) | |
7c673cae FG |
312 | return |
313 | ||
314 | # write to /sys to unbind | |
315 | filename = "/sys/bus/pci/drivers/%s/unbind" % dev["Driver_str"] | |
316 | try: | |
317 | f = open(filename, "a") | |
318 | except: | |
11fdf7f2 TL |
319 | print "Error: unbind failed for %s - Cannot open %s" % (dev_id, filename) |
320 | sys/exit(1) | |
7c673cae FG |
321 | f.write(dev_id) |
322 | f.close() | |
323 | ||
7c673cae FG |
324 | def bind_one(dev_id, driver, force): |
325 | '''Bind the device given by "dev_id" to the driver "driver". If the device | |
326 | is already bound to a different driver, it will be unbound first''' | |
327 | dev = devices[dev_id] | |
11fdf7f2 | 328 | saved_driver = None # used to rollback any unbind in case of failure |
7c673cae FG |
329 | |
330 | # prevent disconnection of our ssh session | |
331 | if dev["Ssh_if"] and not force: | |
11fdf7f2 TL |
332 | print "Routing table indicates that interface %s is active" \ |
333 | ". Not modifying" % (dev_id) | |
7c673cae FG |
334 | return |
335 | ||
336 | # unbind any existing drivers we don't want | |
337 | if has_driver(dev_id): | |
338 | if dev["Driver_str"] == driver: | |
11fdf7f2 | 339 | print "%s already bound to driver %s, skipping\n" % (dev_id, driver) |
7c673cae FG |
340 | return |
341 | else: | |
342 | saved_driver = dev["Driver_str"] | |
343 | unbind_one(dev_id, force) | |
11fdf7f2 | 344 | dev["Driver_str"] = "" # clear driver string |
7c673cae FG |
345 | |
346 | # if we are binding to one of DPDK drivers, add PCI id's to that driver | |
347 | if driver in dpdk_drivers: | |
348 | filename = "/sys/bus/pci/drivers/%s/new_id" % driver | |
349 | try: | |
350 | f = open(filename, "w") | |
351 | except: | |
11fdf7f2 | 352 | print "Error: bind failed for %s - Cannot open %s" % (dev_id, filename) |
7c673cae FG |
353 | return |
354 | try: | |
355 | f.write("%04x %04x" % (dev["Vendor"], dev["Device"])) | |
356 | f.close() | |
357 | except: | |
11fdf7f2 TL |
358 | print "Error: bind failed for %s - Cannot write new PCI ID to " \ |
359 | "driver %s" % (dev_id, driver) | |
7c673cae FG |
360 | return |
361 | ||
362 | # do the bind by writing to /sys | |
363 | filename = "/sys/bus/pci/drivers/%s/bind" % driver | |
364 | try: | |
365 | f = open(filename, "a") | |
366 | except: | |
11fdf7f2 TL |
367 | print "Error: bind failed for %s - Cannot open %s" % (dev_id, filename) |
368 | if saved_driver is not None: # restore any previous driver | |
7c673cae FG |
369 | bind_one(dev_id, saved_driver, force) |
370 | return | |
371 | try: | |
372 | f.write(dev_id) | |
373 | f.close() | |
374 | except: | |
375 | # for some reason, closing dev_id after adding a new PCI ID to new_id | |
376 | # results in IOError. however, if the device was successfully bound, | |
377 | # we don't care for any errors and can safely ignore IOError | |
378 | tmp = get_pci_device_details(dev_id) | |
379 | if "Driver_str" in tmp and tmp["Driver_str"] == driver: | |
380 | return | |
11fdf7f2 TL |
381 | print "Error: bind failed for %s - Cannot bind to driver %s" % (dev_id, driver) |
382 | if saved_driver is not None: # restore any previous driver | |
7c673cae FG |
383 | bind_one(dev_id, saved_driver, force) |
384 | return | |
385 | ||
386 | ||
387 | def unbind_all(dev_list, force=False): | |
388 | """Unbind method, takes a list of device locations""" | |
389 | dev_list = map(dev_id_from_dev_name, dev_list) | |
390 | for d in dev_list: | |
391 | unbind_one(d, force) | |
392 | ||
7c673cae FG |
393 | def bind_all(dev_list, driver, force=False): |
394 | """Bind method, takes a list of device locations""" | |
395 | global devices | |
396 | ||
397 | dev_list = map(dev_id_from_dev_name, dev_list) | |
398 | ||
399 | for d in dev_list: | |
400 | bind_one(d, driver, force) | |
401 | ||
402 | # when binding devices to a generic driver (i.e. one that doesn't have a | |
403 | # PCI ID table), some devices that are not bound to any other driver could | |
404 | # be bound even if no one has asked them to. hence, we check the list of | |
405 | # drivers again, and see if some of the previously-unbound devices were | |
406 | # erroneously bound. | |
407 | for d in devices.keys(): | |
408 | # skip devices that were already bound or that we know should be bound | |
409 | if "Driver_str" in devices[d] or d in dev_list: | |
410 | continue | |
411 | ||
412 | # update information about this device | |
413 | devices[d] = dict(devices[d].items() + | |
414 | get_pci_device_details(d).items()) | |
415 | ||
416 | # check if updated information indicates that the device was bound | |
417 | if "Driver_str" in devices[d]: | |
418 | unbind_one(d, force) | |
419 | ||
11fdf7f2 TL |
420 | def display_devices(title, dev_list, extra_params = None): |
421 | '''Displays to the user the details of a list of devices given in "dev_list" | |
422 | The "extra_params" parameter, if given, should contain a string with | |
423 | %()s fields in it for replacement by the named fields in each device's | |
424 | dictionary.''' | |
425 | strings = [] # this holds the strings to print. We sort before printing | |
426 | print "\n%s" % title | |
427 | print "="*len(title) | |
7c673cae FG |
428 | if len(dev_list) == 0: |
429 | strings.append("<none>") | |
430 | else: | |
431 | for dev in dev_list: | |
432 | if extra_params is not None: | |
11fdf7f2 TL |
433 | strings.append("%s '%s' %s" % (dev["Slot"], \ |
434 | dev["Device_str"], extra_params % dev)) | |
7c673cae FG |
435 | else: |
436 | strings.append("%s '%s'" % (dev["Slot"], dev["Device_str"])) | |
437 | # sort before printing, so that the entries appear in PCI order | |
438 | strings.sort() | |
11fdf7f2 | 439 | print "\n".join(strings) # print one per line |
7c673cae FG |
440 | |
441 | def show_status(): | |
11fdf7f2 TL |
442 | '''Function called when the script is passed the "--status" option. Displays |
443 | to the user what devices are bound to the igb_uio driver, the kernel driver | |
444 | or to no driver''' | |
7c673cae FG |
445 | global dpdk_drivers |
446 | kernel_drv = [] | |
447 | dpdk_drv = [] | |
448 | no_drv = [] | |
449 | ||
11fdf7f2 | 450 | # split our list of devices into the three categories above |
7c673cae | 451 | for d in devices.keys(): |
11fdf7f2 TL |
452 | if not has_driver(d): |
453 | no_drv.append(devices[d]) | |
454 | continue | |
455 | if devices[d]["Driver_str"] in dpdk_drivers: | |
456 | dpdk_drv.append(devices[d]) | |
457 | else: | |
458 | kernel_drv.append(devices[d]) | |
7c673cae FG |
459 | |
460 | # print each category separately, so we can clearly see what's used by DPDK | |
11fdf7f2 | 461 | display_devices("Network devices using DPDK-compatible driver", dpdk_drv, \ |
7c673cae FG |
462 | "drv=%(Driver_str)s unused=%(Module_str)s") |
463 | display_devices("Network devices using kernel driver", kernel_drv, | |
11fdf7f2 TL |
464 | "if=%(Interface)s drv=%(Driver_str)s unused=%(Module_str)s %(Active)s") |
465 | display_devices("Other network devices", no_drv,\ | |
7c673cae | 466 | "unused=%(Module_str)s") |
7c673cae FG |
467 | |
468 | def parse_args(): | |
469 | '''Parses the command-line arguments given by the user and takes the | |
470 | appropriate action for each''' | |
471 | global b_flag | |
472 | global status_flag | |
473 | global force_flag | |
474 | global args | |
475 | if len(sys.argv) <= 1: | |
476 | usage() | |
477 | sys.exit(0) | |
478 | ||
479 | try: | |
11fdf7f2 TL |
480 | opts, args = getopt.getopt(sys.argv[1:], "b:u", |
481 | ["help", "usage", "status", "force", | |
482 | "bind=", "unbind"]) | |
483 | except getopt.GetoptError, error: | |
484 | print str(error) | |
485 | print "Run '%s --usage' for further information" % sys.argv[0] | |
7c673cae FG |
486 | sys.exit(1) |
487 | ||
488 | for opt, arg in opts: | |
489 | if opt == "--help" or opt == "--usage": | |
490 | usage() | |
491 | sys.exit(0) | |
11fdf7f2 | 492 | if opt == "--status": |
7c673cae FG |
493 | status_flag = True |
494 | if opt == "--force": | |
495 | force_flag = True | |
496 | if opt == "-b" or opt == "-u" or opt == "--bind" or opt == "--unbind": | |
497 | if b_flag is not None: | |
11fdf7f2 | 498 | print "Error - Only one bind or unbind may be specified\n" |
7c673cae FG |
499 | sys.exit(1) |
500 | if opt == "-u" or opt == "--unbind": | |
501 | b_flag = "none" | |
502 | else: | |
503 | b_flag = arg | |
504 | ||
7c673cae FG |
505 | def do_arg_actions(): |
506 | '''do the actual action requested by the user''' | |
507 | global b_flag | |
508 | global status_flag | |
509 | global force_flag | |
510 | global args | |
511 | ||
512 | if b_flag is None and not status_flag: | |
11fdf7f2 TL |
513 | print "Error: No action specified for devices. Please give a -b or -u option" |
514 | print "Run '%s --usage' for further information" % sys.argv[0] | |
7c673cae FG |
515 | sys.exit(1) |
516 | ||
517 | if b_flag is not None and len(args) == 0: | |
11fdf7f2 TL |
518 | print "Error: No devices specified." |
519 | print "Run '%s --usage' for further information" % sys.argv[0] | |
7c673cae FG |
520 | sys.exit(1) |
521 | ||
522 | if b_flag == "none" or b_flag == "None": | |
523 | unbind_all(args, force_flag) | |
524 | elif b_flag is not None: | |
525 | bind_all(args, b_flag, force_flag) | |
526 | if status_flag: | |
527 | if b_flag is not None: | |
11fdf7f2 | 528 | get_nic_details() # refresh if we have changed anything |
7c673cae FG |
529 | show_status() |
530 | ||
7c673cae FG |
531 | def main(): |
532 | '''program main function''' | |
533 | parse_args() | |
534 | check_modules() | |
535 | get_nic_details() | |
7c673cae FG |
536 | do_arg_actions() |
537 | ||
538 | if __name__ == "__main__": | |
539 | main() |