pax_global_header00006660000000000000000000000064133464253460014524gustar00rootroot0000000000000052 comment=37b37f9f0653179afede17ff4f2cd61c85efab88 python-ethtool-0.14/000077500000000000000000000000001334642534600144455ustar00rootroot00000000000000python-ethtool-0.14/.gitignore000066400000000000000000000000731334642534600164350ustar00rootroot00000000000000.tox/ build/ dist/ *.so *.pyc *.pyo *.egg-info __pycache__ python-ethtool-0.14/.travis.yml000066400000000000000000000007141334642534600165600ustar00rootroot00000000000000language: python python: - '2.7' - '3.5' - '3.6' - '3.7' dist: xenial sudo: required addons: apt: packages: - libc6-dev - libnl-3-dev - libnl-route-3-dev cache: directories: - $HOME/.cache/pip - $HOME/virtualenv/python$TRAVIS_PYTHON_VERSION/lib/python$TRAVIS_PYTHON_VERSION/site-packages - $HOME/virtualenv/python$TRAVIS_PYTHON_VERSION/bin notifications: email: false install: pip install --upgrade tox tox-travis script: tox python-ethtool-0.14/CHANGES.rst000066400000000000000000000063171334642534600162560ustar00rootroot00000000000000Changelog ========= 0.14 ---- Wed Sep 12 2018 Miro Hrončok - Declared project as bugfix only from now on - Support Python 3.7 - Fix important issues reported by static analysis - Fix installation on non-UTF-8 locales on Python 3.5 and 3.6 - Added set_gso(), get_gro() and set_gro() functions - Added installation instructions 0.13 ---- Tue Jun 13 2017 Miro Hrončok - First release on PyPI - Supports both Python 2.7 and 3.5+ - Dropped support for Python 2.6 - Upstream URL changed to https://github.com/fedora-python/python-ethtool - Introduced a basic README file - PEP7 and PEP8 (code style) improvements - Fix compilation errors on modern Fedoras 0.12 ---- Tue Mar 21 2017 Charalampos Stratakis - First attempt at python3 support 0.11 ---- Thu May 8 2014 David Sommerseth - Improved error handling several places - Ensure that we get a valid libnl NETLINK connection when connecting - URL updates to SPEC file 0.10 ---- Fri Jan 10 2014 David Sommerseth - Not really a full release, but a preliminary release to get more wide testing - FSF Copyright updates - Build fixes - Mostly code cleanup 0.9 --- Wed Dec 11 2013 David Sommerseth - Fixed get_active_devices() for IPv6 only interfaces - Moved from libnl1 to libnl3 - Refactor PyNetlink*Address implementation 0.8 --- Tue Feb 19 2013 David Malcolm - Enable IPv6 in pifethtool example - Code cleanup, fixing buffer overflows, memory leaks, etc 0.7 --- Mon Apr 11 2011 David Sommerseth - Fixed several memory leaks (commit aa2c20e697af, abc7f912f66d) - Improved error checking towards NULL values(commit 4e928d62a8e3) - Fixed typo in pethtool --help (commit 710766dc722) - Only open a NETLINK connection when needed (commit 508ffffbb3c) - Added man page for pifconfig and pethtool (commit 9f0d17aa532, rhbz#638475) - Force NETLINK socket to close on fork() using FD_CLOEXEC (commit 1680cbeb40e) 0.6 --- Wed Jan 19 2011 David Sommerseth - Don't segfault if we don't receive any address from rtnl_link_get_addr() - Remove errornous file from MANIFEST - Added ethtool.version string constant - Avoid duplicating IPv6 address information - import sys module in setup.py (Miroslav Suchy) 0.5 --- Mon Aug 9 2010 David Sommerseth - Fixed double free issue (commit c52ed2cbdc5b851ebc7b) 0.4 --- Wed Apr 28 2010 David Sommerseth - David Sommerseth is now taking over the maintenance of python-ethtool - New URLs for upstream source code - Added new API: ethtool.get_interfaces_info() - returns list of etherinfo objects - Added support retrieving for IPv6 address, using etherinfo::get_ipv6_addresses() 0.3 --- Tue Aug 26 2008 Arnaldo Carvalho de Melo - Add get_flags method from the first python-ethtool contributor, yay - Add pifconfig command, that mimics the ifconfig tool using the bindings available 0.2 --- Wed Aug 20 2008 Arnaldo Carvalho de Melo - Expand description and summary fields, as part of the fedora review process. 0.1 --- Tue Dec 18 2007 Arnaldo Carvalho de Melo - Get ethtool code from rhpl 0.212 python-ethtool-0.14/COPYING000066400000000000000000000431031334642534600155010ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. python-ethtool-0.14/MANIFEST.in000066400000000000000000000002011334642534600161740ustar00rootroot00000000000000include COPYING include *.rst recursive-include man *.asciidoc recursive-include python-ethtool *.h recursive-include tests *.py python-ethtool-0.14/README.rst000066400000000000000000000070261334642534600161410ustar00rootroot00000000000000Python ethtool module ===================== *Python bindings for the ethtool kernel interface* The Python ``ethtool`` module allows querying and partially controlling network interfaces, driver, and hardware settings. .. warning:: This is the new upstream for python-ethtool maintained by Fedora's Python SIG. We ported it to Python 3 and only maintain it for the current tools to keep working. **No new development is happening. This is a deprecated package.** If you are considering to start using this, please don't. We recommend `netifaces `_ instead. Installation ------------ The easiest way to install ``ethtool`` is to use your distribution packages repositories. For example: **Fedora**: ``sudo dnf install python3-ethtool`` or ``sudo dnf install python2-ethtool`` **Ubuntu**: ``sudo apt install python-ethtool`` In order to install ``ethtool`` from source or PyPI install its dependencies first: **Fedora**: ``sudo dnf install libnl3-devel gcc redhat-rpm-config python3-devel`` **Ubuntu**: ``sudo apt install python3 python3-setuptools libpython3.6-dev libnl-route-3-dev`` And then install ``ethtool``: **from PyPI**: ``pip3 install ethtool`` **from source**: ``python3 setup.py install`` Usage ----- ``ethtool`` may be used as a Python library:: >>> import ethtool >>> ethtool.get_active_devices() ['lo', 'enp0s31f6', 'wlp4s0', 'virbr0', 'docker0', 'virbr1', 'eth0', 'tun0'] >>> ethtool.get_ipaddr('lo') '127.0.0.1' The ``ethtool`` package also provides the ``pethtool`` and ``pifconfig`` utilities. More example usage may be gathered from their sources, `pethtool.py `_ and `pifconfig.py `_. ``pethtool`` mimics behavior of the ``ethtool`` utility, but does not support all options. e.g., to get driver information on the ``eth0`` interface:: $ pethtool -i eth0 driver: cdc_ether bus-info: usb-0000:00:14.0-4.1.3 Analogically, ``pifconfig`` mimics ``ifconfig`` in usage. It may be used to view information on an interface:: $ pifconfig lo lo inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope: host UP LOOPBACK RUNNING Further usage information may be found in the respective manpages for `pethtool `_ and `pifconfig `_. Tests ----- Tests may be run by ``tox``. Authors ------- * Andy Grover * Antoni S. Puimedon * Arnaldo Carvalho de Melo * Bohuslav Kabrda * Braňo Náter * Dave Malcolm * David S. Miller * David Sommerseth * Harald Hoyer * Charalampos Stratakis * Jeff Garzik * Lumir Balhar * Miro Hrončok * Miroslav Suchý * Ruben Kerkhof * Sanqui * Yaakov Selkowitz Current maintainers ------------------- * Lumír Balhar * Miro Hrončok * Charalampos Stratakis * Sanqui Contributing ------------ Feel free to help us with improving test coverage, porting to Python 3 or anything else. Issues and PRs `on GitHub `_ are welcome. License ------- The Python ``ethtool`` project is free software distributed under the terms of the GNU General Public License v2.0, see `COPYING `_. python-ethtool-0.14/man/000077500000000000000000000000001334642534600152205ustar00rootroot00000000000000python-ethtool-0.14/man/pethtool.8.asciidoc000066400000000000000000000027241334642534600207310ustar00rootroot00000000000000pethtool(8) =========== NAME ---- pethtool - Display or change ethernet card settings SYNOPSIS -------- pethtool [OPTIONS] [] DESCRIPTION ----------- This script mimic ethtool behavior, but is written purely in python and python module ethtool. OPTIONS ------- INTERFACE:: Is the name of the ethernet device on which pethtool should operate. -h, --help:: Show help message and exit. -c|--show-coalesce:: Show coalesce options -C|--coalesce:: Set coalesce options adaptive-rx on|off adaptive-tx on|off rx-usecs N rx-frames N rx-usecs-irq N rx-frames-irq N tx-usecs N tx-frames N tx-usecs-irq N tx-frames-irq N stats-block-usecs N pkt-rate-low N rx-usecs-low N rx-frames-low N tx-usecs-low N tx-frames-low N pkt-rate-high N rx-usecs-high N rx-frames-high N tx-usecs-high N tx-frames-high N sample-interval N -i|--driver:: Show driver information -k|--show-offload:: Get protocol offload information -K|--offload:: Set protocol offload;; [ tso on|off ] SEE ALSO -------- ethtool(8) AUTHORS ------- Arnaldo Carvalho de Melo Man page written by Miroslav Suchý python-ethtool-0.14/man/pifconfig.8.asciidoc000066400000000000000000000012231334642534600210300ustar00rootroot00000000000000pifconfig(8) ============ NAME ---- pifconfig - display information about a network interface SYNOPSIS -------- pifconfig [INTERFACE [INTERFACE [INTERFACE] ...]] DESCRIPTION ----------- This script mimic ifconfig behavior, but is written purely in python and python module ethtool. OPTIONS ------- INTERFACE:: Display information about only the listed interfaces. If no interface is given all interfaces are displayed. -h, --help:: Show help message and exit. SEE ALSO -------- ifconfig(8) AUTHORS ------- Arnaldo Carvalho de Melo Man page written by Miroslav Suchý , David Sommerseth python-ethtool-0.14/python-ethtool/000077500000000000000000000000001334642534600174425ustar00rootroot00000000000000python-ethtool-0.14/python-ethtool/etherinfo.c000066400000000000000000000177271334642534600216070ustar00rootroot00000000000000/* etherinfo.c - Retrieve ethernet interface info via NETLINK * * Copyright (C) 2009-2013 Red Hat Inc. * * David Sommerseth * Parts of this code is based on ideas and solutions in iproute2 * * This application is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; version 2. * * This application is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ #include #include "include/py3c/compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "etherinfo_struct.h" #include "etherinfo.h" /* * * Internal functions for working with struct etherinfo * */ /** * libnl callback function. * Does the real parsing of a record returned by NETLINK. * This function parses LINK related packets * * @param obj Pointer to a struct nl_object response * @param arg Pointer to a struct etherinfo element where the parse result * will be saved */ static void callback_nl_link(struct nl_object *obj, void *arg) { PyEtherInfo *ethi = (PyEtherInfo *) arg; struct rtnl_link *link = (struct rtnl_link *) obj; char hwaddr[130]; if ((ethi == NULL) || (ethi->hwaddress != NULL)) { return; } memset(&hwaddr, 0, 130); nl_addr2str(rtnl_link_get_addr(link), hwaddr, sizeof(hwaddr)); if (ethi->hwaddress) { Py_XDECREF(ethi->hwaddress); } ethi->hwaddress = PyStr_FromFormat("%s", hwaddr); } /** * libnl callback function. Does the real parsing of a record returned by * NETLINK. This function parses ADDRESS related packets * * @param obj Pointer to a struct nl_object response * @param arg Pointer to a struct etherinfo element where the parse result * will be saved */ static void callback_nl_address(struct nl_object *obj, void *arg) { PyObject *py_addrlist = (PyObject *) arg; struct rtnl_addr *rtaddr = (struct rtnl_addr *) obj; PyObject *addr_obj = NULL; int af_family = -1; if (py_addrlist == NULL) { return; } /* Ensure that we're processing only known address types. * Currently only IPv4 and IPv6 is handled */ af_family = rtnl_addr_get_family(rtaddr); if (af_family != AF_INET && af_family != AF_INET6) { return; } /* Prepare a new Python object with the IP address */ addr_obj = make_python_address_from_rtnl_addr(rtaddr); if (!addr_obj) { return; } /* Append the IP address object to the address list */ PyList_Append(py_addrlist, addr_obj); Py_DECREF(addr_obj); } /** * Sets the etherinfo.index member to the corresponding device set in * etherinfo.device * * @param self A pointer the current PyEtherInfo Python object which contains * the device name and the place where to save the corresponding * index value. * * @return Returns 1 on success, otherwise 0. On error, a Python error * exception is set. */ static int _set_device_index(PyEtherInfo *self) { struct nl_cache *link_cache; struct rtnl_link *link; /* Find the interface index we're looking up. * As we don't expect it to change, we're reusing a "cached" * interface index if we have that */ if (self->index < 0) { if ((errno = rtnl_link_alloc_cache(get_nlc(), AF_UNSPEC, &link_cache)) < 0) { PyErr_SetString(PyExc_OSError, nl_geterror(errno)); return 0; } link = rtnl_link_get_by_name(link_cache, PyStr_AsString(self->device)); if (!link) { errno = ENODEV; PyErr_SetFromErrno(PyExc_IOError); nl_cache_free(link_cache); return 0; } self->index = rtnl_link_get_ifindex(link); if (self->index <= 0) { errno = ENODEV; PyErr_SetFromErrno(PyExc_IOError); rtnl_link_put(link); nl_cache_free(link_cache); return 0; } rtnl_link_put(link); nl_cache_free(link_cache); } return 1; } /* * * Exported functions - API frontend * */ /** * Populate the PyEtherInfo Python object with link information for the current * device * * @param self Pointer to the device object, a PyEtherInfo Python object * * @return Returns 1 on success, otherwise 0 */ int get_etherinfo_link(PyEtherInfo *self) { struct nl_cache *link_cache; struct rtnl_link *link; int err = 0; if (!self) { return 0; } /* Open a NETLINK connection on-the-fly */ if (!open_netlink(self)) { PyErr_Format(PyExc_RuntimeError, "Could not open a NETLINK connection for %s", PyStr_AsString(self->device)); return 0; } if (_set_device_index(self) != 1) { return 0; } /* Extract MAC/hardware address of the interface */ if ((err = rtnl_link_alloc_cache(get_nlc(), AF_UNSPEC, &link_cache)) < 0) { PyErr_SetString(PyExc_OSError, nl_geterror(err)); return 0; } link = rtnl_link_alloc(); if (!link) { errno = ENOMEM; PyErr_SetFromErrno(PyExc_OSError); return 0; } rtnl_link_set_ifindex(link, self->index); nl_cache_foreach_filter(link_cache, OBJ_CAST(link), callback_nl_link, self); rtnl_link_put(link); nl_cache_free(link_cache); return 1; } /** * Query NETLINK for device IP address configuration * * @param self A PyEtherInfo Python object for the current device to retrieve * IP address configuration data from * @param query What to query for. Must be NLQRY_ADDR4 for IPv4 addresses or * NLQRY_ADDR6 for IPv6 addresses. * * @return Returns a Python list containing PyNetlinkIPaddress objects on * success, otherwise NULL */ PyObject * get_etherinfo_address(PyEtherInfo *self, nlQuery query) { struct nl_cache *addr_cache; struct rtnl_addr *addr; PyObject *addrlist = NULL; int err = 0; if (!self) { return NULL; } /* Open a NETLINK connection on-the-fly */ if (!open_netlink(self)) { PyErr_Format(PyExc_RuntimeError, "Could not open a NETLINK connection for %s", PyStr_AsString(self->device)); return NULL; } if(!_set_device_index(self)) { return NULL; } /* Query the for requested info via NETLINK */ /* Extract IP address information */ if ((err = rtnl_addr_alloc_cache(get_nlc(), &addr_cache)) < 0) { PyErr_SetString(PyExc_OSError, nl_geterror(err)); nl_cache_free(addr_cache); return NULL; } addr = rtnl_addr_alloc(); if (!addr) { errno = ENOMEM; PyErr_SetFromErrno(PyExc_OSError); return NULL; } rtnl_addr_set_ifindex(addr, self->index); switch( query) { case NLQRY_ADDR4: rtnl_addr_set_family(addr, AF_INET); break; case NLQRY_ADDR6: rtnl_addr_set_family(addr, AF_INET6); break; default: return NULL; } /* Retrieve all address information */ addrlist = PyList_New(0); /* The list where to put the address object */ assert(addrlist); /* Loop through all configured addresses */ nl_cache_foreach_filter(addr_cache, OBJ_CAST(addr), callback_nl_address, addrlist); rtnl_addr_put(addr); nl_cache_free(addr_cache); return addrlist; } python-ethtool-0.14/python-ethtool/etherinfo.h000066400000000000000000000017011334642534600215750ustar00rootroot00000000000000/* etherinfo.h - Retrieve ethernet interface info via NETLINK * * Copyright (C) 2009-2011 Red Hat Inc. * * David Sommerseth * * This application is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; version 2. * * This application is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ #ifndef _ETHERINFO_H #define _ETHERINFO_H /** Supported query types in the etherinfo code */ typedef enum {NLQRY_ADDR4, NLQRY_ADDR6} nlQuery; int get_etherinfo_link(PyEtherInfo *data); PyObject * get_etherinfo_address(PyEtherInfo *self, nlQuery query); int open_netlink(PyEtherInfo *); struct nl_sock * get_nlc(); void close_netlink(PyEtherInfo *); #endif python-ethtool-0.14/python-ethtool/etherinfo_obj.c000066400000000000000000000217211334642534600224260ustar00rootroot00000000000000/* * Copyright (C) 2009-2013 Red Hat Inc. * * David Sommerseth * * This application is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; version 2. * * This application is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ /** * @file etherinfo_obj.c * @author David Sommerseth * @date Fri Sep 4 18:41:28 2009 * * @brief Python ethtool.etherinfo class functions. * */ #include #include "include/py3c/compat.h" #include #include "structmember.h" #include #include #include "etherinfo_struct.h" #include "etherinfo.h" /** * ethtool.etherinfo deallocator - cleans up when a object is deleted * * @param self PyEtherInfo Python object to deallocate */ static void _ethtool_etherinfo_dealloc(PyEtherInfo *self) { close_netlink(self); Py_XDECREF(self->device); self->device = NULL; Py_XDECREF(self->hwaddress); self->hwaddress = NULL; Py_TYPE(self)->tp_free((PyObject*)self); } /* The old approach of having a single IPv4 address per device meant each result that came in from netlink overwrote the old result. Mimic it by returning the last entry in the list (if any). The return value is a *borrowed reference* (or NULL) */ static PyNetlinkIPaddress * get_last_ipv4_address(PyObject *addrlist) { Py_ssize_t size; if (!addrlist) { return NULL; } if (!PyList_Check(addrlist)) { return NULL; } size = PyList_Size(addrlist); if (size > 0) { PyNetlinkIPaddress *item = (PyNetlinkIPaddress *) PyList_GetItem(addrlist, size - 1); if (Py_TYPE(item) == ðtool_netlink_ip_address_Type) { return item; } } return NULL; } /** * Creates a human readable format of the information when object is being * treated as a string * * @param self Pointer to the current PyEtherInfo device object * * @return Returns a PyObject with a string with all of the information */ PyObject *_ethtool_etherinfo_str(PyEtherInfo *self) { PyObject *ret = NULL; PyObject *ipv4addrs = NULL, *ipv6addrs = NULL; if (!self) { PyErr_SetString(PyExc_AttributeError, "No data available"); return NULL; } get_etherinfo_link(self); ret = PyStr_FromFormat("Device %s:\n", PyStr_AsString(self->device)); if (self->hwaddress) { ret = PyStr_Concat(ret, PyStr_FromFormat("\tMAC address: %s\n", PyStr_AsString(self->hwaddress))); } ipv4addrs = get_etherinfo_address(self, NLQRY_ADDR4); if (ipv4addrs) { Py_ssize_t i; for (i = 0; i < PyList_Size(ipv4addrs); i++) { PyNetlinkIPaddress *py_addr = (PyNetlinkIPaddress *) PyList_GetItem(ipv4addrs, i); PyObject *tmp = PyStr_FromFormat("\tIPv4 address: "); tmp = PyStr_Concat(tmp, py_addr->local); tmp = PyStr_Concat(tmp, PyStr_FromFormat("/%d", py_addr->prefixlen)); if (py_addr->ipv4_broadcast) { tmp = PyStr_Concat( tmp, PyStr_FromFormat("\tBroadcast: %s\n", PyStr_AsString( py_addr->ipv4_broadcast))); } else { tmp = PyStr_Concat(tmp, PyStr_FromFormat("\n")); } ret = PyStr_Concat(ret, tmp); } } ipv6addrs = get_etherinfo_address(self, NLQRY_ADDR6); if (ipv6addrs) { Py_ssize_t i; for (i = 0; i < PyList_Size(ipv6addrs); i++) { PyNetlinkIPaddress *py_addr = (PyNetlinkIPaddress *) PyList_GetItem(ipv6addrs, i); PyObject *tmp = PyStr_FromFormat("\tIPv6 address: [%s] %s/%d\n", PyStr_AsString(py_addr->scope), PyStr_AsString(py_addr->local), py_addr->prefixlen); ret = PyStr_Concat(ret, tmp); } } return ret; } /** * Returns a tuple list of configured IPv4 addresses * * @param self Pointer to the current PyEtherInfo device object to extract * IPv4 info from * @param notused * * @return Returns a Python tuple list of NetlinkIP4Address objects */ static PyObject *_ethtool_etherinfo_get_ipv4_addresses(PyEtherInfo *self, PyObject *notused) { if (!self) { PyErr_SetString(PyExc_AttributeError, "No data available"); return NULL; } return get_etherinfo_address(self, NLQRY_ADDR4); } /** * Returns a tuple list of configured IPv6 addresses * * @param self Pointer to the current PyEtherInfo device object to extract * IPv6 info from * @param notused * * @return Returns a Python tuple list of NetlinkIP6Address objects */ static PyObject *_ethtool_etherinfo_get_ipv6_addresses(PyEtherInfo *self, PyObject *notused) { if (!self) { PyErr_SetString(PyExc_AttributeError, "No data available"); return NULL; } return get_etherinfo_address(self, NLQRY_ADDR6); } /** * Defines all available methods in the ethtool.etherinfo class * */ static PyMethodDef _ethtool_etherinfo_methods[] = { { "get_ipv4_addresses", (PyCFunction)_ethtool_etherinfo_get_ipv4_addresses, METH_NOARGS, "Retrieve configured IPv4 addresses. " "Returns a list of NetlinkIPaddress objects" }, { "get_ipv6_addresses", (PyCFunction)_ethtool_etherinfo_get_ipv6_addresses, METH_NOARGS, "Retrieve configured IPv6 addresses. " "Returns a list of NetlinkIPaddress objects" }, {NULL} /**< No methods defined */ }; static PyObject *get_device(PyObject *obj, void *info) { PyEtherInfo *self = (PyEtherInfo *) obj; if (self->device) { Py_INCREF(self->device); return self->device; } Py_RETURN_NONE; } static PyObject *get_mac_addr(PyObject *obj, void *info) { PyEtherInfo *self = (PyEtherInfo *) obj; get_etherinfo_link(self); if (self->hwaddress) { Py_INCREF(self->hwaddress); } return self->hwaddress; } static PyObject *get_ipv4_addr(PyObject *obj, void *info) { PyEtherInfo *self = (PyEtherInfo *) obj; PyObject *addrlist; PyNetlinkIPaddress *py_addr; addrlist = get_etherinfo_address(self, NLQRY_ADDR4); /* For compatiblity with old approach, return last IPv4 address: */ py_addr = get_last_ipv4_address(addrlist); if (py_addr) { if (py_addr->local) { Py_INCREF(py_addr->local); return py_addr->local; } } if (PyErr_Occurred()) { return NULL; } else { Py_RETURN_NONE; } } static PyObject *get_ipv4_mask(PyObject *obj, void *info) { PyEtherInfo *self = (PyEtherInfo *) obj; PyObject *addrlist; PyNetlinkIPaddress *py_addr; addrlist = get_etherinfo_address(self, NLQRY_ADDR4); py_addr = get_last_ipv4_address(addrlist); if (py_addr) { return PyInt_FromLong(py_addr->prefixlen); } if (PyErr_Occurred()) { return NULL; } else { return PyInt_FromLong(0); } } static PyObject *get_ipv4_bcast(PyObject *obj, void *info) { PyEtherInfo *self = (PyEtherInfo *) obj; PyObject *addrlist; PyNetlinkIPaddress *py_addr; addrlist = get_etherinfo_address(self, NLQRY_ADDR4); py_addr = get_last_ipv4_address(addrlist); if (py_addr) { if (py_addr->ipv4_broadcast) { Py_INCREF(py_addr->ipv4_broadcast); return py_addr->ipv4_broadcast; } } if (PyErr_Occurred()) { return NULL; } else { return PyStr_FromString("0.0.0.0"); } } static PyGetSetDef _ethtool_etherinfo_attributes[] = { {"device", get_device, NULL, "device", NULL}, {"mac_address", get_mac_addr, NULL, "MAC address", NULL}, {"ipv4_address", get_ipv4_addr, NULL, "IPv4 address", NULL}, {"ipv4_netmask", get_ipv4_mask, NULL, "IPv4 netmask", NULL}, {"ipv4_broadcast", get_ipv4_bcast, NULL, "IPv4 broadcast", NULL}, {NULL}, }; /** * Definition of the functions a Python class/object requires. * */ PyTypeObject PyEtherInfo_Type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "ethtool.etherinfo", .tp_basicsize = sizeof(PyEtherInfo), .tp_flags = Py_TPFLAGS_DEFAULT, .tp_dealloc = (destructor)_ethtool_etherinfo_dealloc, .tp_str = (reprfunc)_ethtool_etherinfo_str, .tp_getset = _ethtool_etherinfo_attributes, .tp_methods = _ethtool_etherinfo_methods, .tp_doc = "Contains information about a specific ethernet device" }; python-ethtool-0.14/python-ethtool/etherinfo_obj.h000066400000000000000000000023061334642534600224310ustar00rootroot00000000000000/* * Copyright (C) 2009-2010 Red Hat Inc. * * David Sommerseth * * This application is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; version 2. * * This application is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ /** * @file etherinfo_obj.c * @author David Sommerseth * @date Fri Sep 4 18:41:28 2009 * * @brief Python ethtool.etherinfo class functions (header file). * */ #ifndef __ETHERINFO_OBJ_H #define __ETHERINFO_OBJ_H #include #include "etherinfo_struct.h" void _ethtool_etherinfo_dealloc(PyEtherInfo *); PyObject *_ethtool_etherinfo_new(PyTypeObject *, PyObject *, PyObject *); int _ethtool_etherinfo_init(PyEtherInfo *, PyObject *, PyObject *); PyObject *_ethtool_etherinfo_getter(PyEtherInfo *, PyObject *); int _ethtool_etherinfo_setter(PyEtherInfo *, PyObject *, PyObject *); PyObject *_ethtool_etherinfo_str(PyEtherInfo *self); #endif python-ethtool-0.14/python-ethtool/etherinfo_struct.h000066400000000000000000000035371334642534600232120ustar00rootroot00000000000000/* * Copyright (C) 2009-2013 Red Hat Inc. * * David Sommerseth * * This application is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; version 2. * * This application is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ /** * @file etherinfo_struct.h * @author David Sommerseth * @date Fri Sep 4 19:06:06 2009 * * @brief Contains the internal ethtool.etherinfo data structure * */ #ifndef _ETHERINFO_STRUCT_H #define _ETHERINFO_STRUCT_H #include /* Python object containing data baked from a (struct rtnl_addr) */ typedef struct PyNetlinkIPaddress { PyObject_HEAD int family; /**< int: must be AF_INET or AF_INET6 */ PyObject *local; /**< string: Configured local IP address */ PyObject *peer; /**< string: Configured peer IP address */ PyObject *ipv4_broadcast; /**< string: Configured IPv4 broadcast add. */ int prefixlen; /**< int: Configured network prefix (netmask) */ PyObject *scope; /**< string: IP address scope */ } PyNetlinkIPaddress; extern PyTypeObject ethtool_netlink_ip_address_Type; /** * The Python object containing information about a single interface * */ typedef struct { PyObject_HEAD PyObject *device; /**< Device name */ int index; /**< NETLINK index reference */ PyObject *hwaddress; /**< string: HW address / MAC address of device */ unsigned short nlc_active; /**< Is this instance using NETLINK? */ } PyEtherInfo; PyObject * make_python_address_from_rtnl_addr(struct rtnl_addr *addr); #endif python-ethtool-0.14/python-ethtool/ethtool-copy.h000066400000000000000000000317561334642534600222550ustar00rootroot00000000000000/* * ethtool.h: Defines for Linux ethtool. * * Copyright (C) 1998 David S. Miller (davem@redhat.com) * Copyright 2001 Jeff Garzik * Portions Copyright 2001 Sun Microsystems (thockin@sun.com) * Portions Copyright 2002 Intel (eli.kupermann@intel.com, * christopher.leech@intel.com, * scott.feldman@intel.com) */ #ifndef _LINUX_ETHTOOL_H #define _LINUX_ETHTOOL_H #ifndef __unused #define __unused __attribute__ ((unused)) #endif /* This should work for both 32 and 64 bit userland. */ struct ethtool_cmd { u32 cmd; u32 supported; /* Features this interface supports */ u32 advertising; /* Features this interface advertises */ u16 speed; /* The forced speed, 10Mb, 100Mb, gigabit */ u8 duplex; /* Duplex, half or full */ u8 port; /* Which connector port */ u8 phy_address; u8 transceiver; /* Which tranceiver to use */ u8 autoneg; /* Enable or disable autonegotiation */ u32 maxtxpkt; /* Tx pkts before generating tx int */ u32 maxrxpkt; /* Rx pkts before generating rx int */ u32 reserved[4]; }; #define ETHTOOL_BUSINFO_LEN 32 /* these strings are set to whatever the driver author decides... */ struct ethtool_drvinfo { u32 cmd; char driver[32]; /* driver short name, "tulip", "eepro100" */ char version[32]; /* driver version string */ char fw_version[32]; /* firmware version string, if applicable */ char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */ /* For PCI devices, use pci_dev->slot_name. */ char reserved1[32]; char reserved2[16]; u32 n_stats; /* number of u64's from ETHTOOL_GSTATS */ u32 testinfo_len; u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */ u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */ }; #define SOPASS_MAX 6 /* wake-on-lan settings */ struct ethtool_wolinfo { u32 cmd; u32 supported; u32 wolopts; u8 sopass[SOPASS_MAX]; /* SecureOn(tm) password */ }; /* for passing single values */ struct ethtool_value { u32 cmd; u32 data; }; /* for passing big chunks of data */ struct ethtool_regs { u32 cmd; u32 version; /* driver-specific, indicates different chips/revs */ u32 len; /* bytes */ u8 data[0]; }; /* for passing EEPROM chunks */ struct ethtool_eeprom { u32 cmd; u32 magic; u32 offset; /* in bytes */ u32 len; /* in bytes */ u8 data[0]; }; /* for configuring coalescing parameters of chip */ struct ethtool_coalesce { u32 cmd; /* ETHTOOL_{G,S}COALESCE */ /* How many usecs to delay an RX interrupt after * a packet arrives. If 0, only rx_max_coalesced_frames * is used. */ u32 rx_coalesce_usecs; /* How many packets to delay an RX interrupt after * a packet arrives. If 0, only rx_coalesce_usecs is * used. It is illegal to set both usecs and max frames * to zero as this would cause RX interrupts to never be * generated. */ u32 rx_max_coalesced_frames; /* Same as above two parameters, except that these values * apply while an IRQ is being services by the host. Not * all cards support this feature and the values are ignored * in that case. */ u32 rx_coalesce_usecs_irq; u32 rx_max_coalesced_frames_irq; /* How many usecs to delay a TX interrupt after * a packet is sent. If 0, only tx_max_coalesced_frames * is used. */ u32 tx_coalesce_usecs; /* How many packets to delay a TX interrupt after * a packet is sent. If 0, only tx_coalesce_usecs is * used. It is illegal to set both usecs and max frames * to zero as this would cause TX interrupts to never be * generated. */ u32 tx_max_coalesced_frames; /* Same as above two parameters, except that these values * apply while an IRQ is being services by the host. Not * all cards support this feature and the values are ignored * in that case. */ u32 tx_coalesce_usecs_irq; u32 tx_max_coalesced_frames_irq; /* How many usecs to delay in-memory statistics * block updates. Some drivers do not have an in-memory * statistic block, and in such cases this value is ignored. * This value must not be zero. */ u32 stats_block_coalesce_usecs; /* Adaptive RX/TX coalescing is an algorithm implemented by * some drivers to improve latency under low packet rates and * improve throughput under high packet rates. Some drivers * only implement one of RX or TX adaptive coalescing. Anything * not implemented by the driver causes these values to be * silently ignored. */ u32 use_adaptive_rx_coalesce; u32 use_adaptive_tx_coalesce; /* When the packet rate (measured in packets per second) * is below pkt_rate_low, the {rx,tx}_*_low parameters are * used. */ u32 pkt_rate_low; u32 rx_coalesce_usecs_low; u32 rx_max_coalesced_frames_low; u32 tx_coalesce_usecs_low; u32 tx_max_coalesced_frames_low; /* When the packet rate is below pkt_rate_high but above * pkt_rate_low (both measured in packets per second) the * normal {rx,tx}_* coalescing parameters are used. */ /* When the packet rate is (measured in packets per second) * is above pkt_rate_high, the {rx,tx}_*_high parameters are * used. */ u32 pkt_rate_high; u32 rx_coalesce_usecs_high; u32 rx_max_coalesced_frames_high; u32 tx_coalesce_usecs_high; u32 tx_max_coalesced_frames_high; /* How often to do adaptive coalescing packet rate sampling, * measured in seconds. Must not be zero. */ u32 rate_sample_interval; }; /* for configuring RX/TX ring parameters */ struct ethtool_ringparam { u32 cmd; /* ETHTOOL_{G,S}RINGPARAM */ /* Read only attributes. These indicate the maximum number * of pending RX/TX ring entries the driver will allow the * user to set. */ u32 rx_max_pending; u32 rx_mini_max_pending; u32 rx_jumbo_max_pending; u32 tx_max_pending; /* Values changeable by the user. The valid values are * in the range 1 to the "*_max_pending" counterpart above. */ u32 rx_pending; u32 rx_mini_pending; u32 rx_jumbo_pending; u32 tx_pending; }; /* for configuring link flow control parameters */ struct ethtool_pauseparam { u32 cmd; /* ETHTOOL_{G,S}PAUSEPARAM */ /* If the link is being auto-negotiated (via ethtool_cmd.autoneg * being true) the user may set 'autonet' here non-zero to have the * pause parameters be auto-negotiated too. In such a case, the * {rx,tx}_pause values below determine what capabilities are * advertised. * * If 'autoneg' is zero or the link is not being auto-negotiated, * then {rx,tx}_pause force the driver to use/not-use pause * flow control. */ u32 autoneg; u32 rx_pause; u32 tx_pause; }; #define ETH_GSTRING_LEN 32 enum ethtool_stringset { ETH_SS_TEST = 0, ETH_SS_STATS, }; /* for passing string sets for data tagging */ struct ethtool_gstrings { u32 cmd; /* ETHTOOL_GSTRINGS */ u32 string_set; /* string set id e.c. ETH_SS_TEST, etc*/ u32 len; /* number of strings in the string set */ u8 data[0]; }; enum ethtool_test_flags { ETH_TEST_FL_OFFLINE = (1 << 0), /* online / offline */ ETH_TEST_FL_FAILED = (1 << 1), /* test passed / failed */ }; /* for requesting NIC test and getting results*/ struct ethtool_test { u32 cmd; /* ETHTOOL_TEST */ u32 flags; /* ETH_TEST_FL_xxx */ u32 reserved; u32 len; /* result length, in number of u64 elements */ u64 data[0]; }; /* for dumping NIC-specific statistics */ struct ethtool_stats { u32 cmd; /* ETHTOOL_GSTATS */ u32 n_stats; /* number of u64's being returned */ u64 data[0]; }; /* CMDs currently supported */ #define ETHTOOL_GSET 0x00000001 /* Get settings. */ #define ETHTOOL_SSET 0x00000002 /* Set settings, privileged. */ #define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */ #define ETHTOOL_GREGS 0x00000004 /* Get NIC registers, privileged. */ #define ETHTOOL_GWOL 0x00000005 /* Get wake-on-lan options. */ #define ETHTOOL_SWOL 0x00000006 /* Set wake-on-lan options, priv. */ #define ETHTOOL_GMSGLVL 0x00000007 /* Get driver message level */ #define ETHTOOL_SMSGLVL 0x00000008 /* Set driver msg level, priv. */ #define ETHTOOL_NWAY_RST 0x00000009 /* Restart autonegotiation, priv. */ #define ETHTOOL_GLINK 0x0000000a /* Get link status (ethtool_value) */ #define ETHTOOL_GEEPROM 0x0000000b /* Get EEPROM data */ #define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data, priv. */ #define ETHTOOL_GCOALESCE 0x0000000e /* Get coalesce config */ #define ETHTOOL_SCOALESCE 0x0000000f /* Set coalesce config, priv. */ #define ETHTOOL_GRINGPARAM 0x00000010 /* Get ring parameters */ #define ETHTOOL_SRINGPARAM 0x00000011 /* Set ring parameters, priv. */ #define ETHTOOL_GPAUSEPARAM 0x00000012 /* Get pause parameters */ #define ETHTOOL_SPAUSEPARAM 0x00000013 /* Set pause parameters, priv. */ #define ETHTOOL_GRXCSUM 0x00000014 /* Get RX hw csum enable (e.v.) */ #define ETHTOOL_SRXCSUM 0x00000015 /* Set RX hw csum enable (e.v.) */ #define ETHTOOL_GTXCSUM 0x00000016 /* Get TX hw csum enable (e.v.) */ #define ETHTOOL_STXCSUM 0x00000017 /* Set TX hw csum enable (e.v.) */ #define ETHTOOL_GSG 0x00000018 /* Get scatter-gather enable * (ethtool_value) */ #define ETHTOOL_SSG 0x00000019 /* Set scatter-gather enable * (ethtool_value), priv. */ #define ETHTOOL_TEST 0x0000001a /* execute NIC self-test, priv. */ #define ETHTOOL_GSTRINGS 0x0000001b /* get specified string set */ #define ETHTOOL_PHYS_ID 0x0000001c /* identify the NIC */ #define ETHTOOL_GSTATS 0x0000001d /* get NIC-specific statistics */ #define ETHTOOL_GTSO 0x0000001e /* Get TSO enable (e.v.) */ #define ETHTOOL_STSO 0x0000001f /* Set TSO enable (e.v.) */ #define ETHTOOL_GUFO 0x00000021 /* Get UFO enable (e.v.) */ #define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (e.v.) */ #define ETHTOOL_GGSO 0x00000023 /* Get GSO enable (e.v.) */ #define ETHTOOL_SGSO 0x00000024 /* Set GSO enable (e.v.) */ #define ETHTOOL_GGRO 0x0000002b /* Get GRO enable (e.v.) */ #define ETHTOOL_SGRO 0x0000002c /* Set GRO enable (e.v.) */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET #define SPARC_ETH_SSET ETHTOOL_SSET /* Indicates what features are supported by the interface. */ #define SUPPORTED_10baseT_Half (1 << 0) #define SUPPORTED_10baseT_Full (1 << 1) #define SUPPORTED_100baseT_Half (1 << 2) #define SUPPORTED_100baseT_Full (1 << 3) #define SUPPORTED_1000baseT_Half (1 << 4) #define SUPPORTED_1000baseT_Full (1 << 5) #define SUPPORTED_Autoneg (1 << 6) #define SUPPORTED_TP (1 << 7) #define SUPPORTED_AUI (1 << 8) #define SUPPORTED_MII (1 << 9) #define SUPPORTED_FIBRE (1 << 10) #define SUPPORTED_BNC (1 << 11) #define SUPPORTED_10000baseT_Full (1 << 12) /* Indicates what features are advertised by the interface. */ #define ADVERTISED_10baseT_Half (1 << 0) #define ADVERTISED_10baseT_Full (1 << 1) #define ADVERTISED_100baseT_Half (1 << 2) #define ADVERTISED_100baseT_Full (1 << 3) #define ADVERTISED_1000baseT_Half (1 << 4) #define ADVERTISED_1000baseT_Full (1 << 5) #define ADVERTISED_Autoneg (1 << 6) #define ADVERTISED_TP (1 << 7) #define ADVERTISED_AUI (1 << 8) #define ADVERTISED_MII (1 << 9) #define ADVERTISED_FIBRE (1 << 10) #define ADVERTISED_BNC (1 << 11) #define ADVERTISED_10000baseT_Full (1 << 12) /* The following are all involved in forcing a particular link * mode for the device for setting things. When getting the * devices settings, these indicate the current mode and whether * it was foced up into this mode or autonegotiated. */ /* The forced speed, 10Mb, 100Mb, gigabit, 10GbE. */ #define SPEED_10 10 #define SPEED_100 100 #define SPEED_1000 1000 #define SPEED_10000 10000 /* Duplex, half or full. */ #define DUPLEX_HALF 0x00 #define DUPLEX_FULL 0x01 /* Which connector port. */ #define PORT_TP 0x00 #define PORT_AUI 0x01 #define PORT_MII 0x02 #define PORT_FIBRE 0x03 #define PORT_BNC 0x04 /* Which tranceiver to use. */ #define XCVR_INTERNAL 0x00 #define XCVR_EXTERNAL 0x01 #define XCVR_DUMMY1 0x02 #define XCVR_DUMMY2 0x03 #define XCVR_DUMMY3 0x04 /* Enable or disable autonegotiation. If this is set to enable, * the forced link modes above are completely ignored. */ #define AUTONEG_DISABLE 0x00 #define AUTONEG_ENABLE 0x01 /* Wake-On-Lan options. */ #define WAKE_PHY (1 << 0) #define WAKE_UCAST (1 << 1) #define WAKE_MCAST (1 << 2) #define WAKE_BCAST (1 << 3) #define WAKE_ARP (1 << 4) #define WAKE_MAGIC (1 << 5) #define WAKE_MAGICSECURE (1 << 6) /* only meaningful if WAKE_MAGIC */ #endif /* _LINUX_ETHTOOL_H */ python-ethtool-0.14/python-ethtool/ethtool.c000066400000000000000000000713511334642534600212730ustar00rootroot00000000000000/* * Copyright (C) 2008-2013 Red Hat Inc. * * Arnaldo Carvalho de Melo * David Sommerseth * * First bits from a Red Hat config tool by Harald Hoyer. * * This application is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; version 2. * * This application is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ #include #include "include/py3c/compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #if !defined IFF_UP #include #endif #include "etherinfo_struct.h" #include "etherinfo_obj.h" #include "etherinfo.h" extern PyTypeObject PyEtherInfo_Type; #ifndef IFF_DYNAMIC #define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses*/ #endif typedef unsigned long long u64; typedef __uint32_t u32; typedef __uint16_t u16; typedef __uint8_t u8; #include "ethtool-copy.h" #include /* for SIOCETHTOOL */ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #define _PATH_PROCNET_DEV "/proc/net/dev" static PyObject *get_active_devices(PyObject *self __unused, PyObject *args __unused) { PyObject *list; struct ifaddrs *ifaddr, *ifa; if (getifaddrs(&ifaddr) == -1) return PyErr_SetFromErrno(PyExc_OSError); list = PyList_New(0); for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { PyObject *str = PyStr_FromString(ifa->ifa_name); /* names are not unique (listed for both ipv4 and ipv6) */ if (!PySequence_Contains(list, str) && (ifa->ifa_flags & (IFF_UP))) { PyList_Append(list, str); } Py_DECREF(str); } freeifaddrs(ifaddr); return list; } static PyObject *get_devices(PyObject *self __unused, PyObject *args __unused) { char buffer[256]; char *ret; PyObject *list = PyList_New(0); FILE *fd = fopen(_PATH_PROCNET_DEV, "r"); if (fd == NULL) { return PyErr_SetFromErrno(PyExc_OSError); } /* skip over first two lines */ ret = fgets(buffer, 256, fd); ret = fgets(buffer, 256, fd); if (!ret) { fclose(fd); return PyErr_SetFromErrno(PyExc_OSError); } while (!feof(fd)) { PyObject *str; char *name = buffer; char *end = buffer; if (fgets(buffer, 256, fd) == NULL) break; /* find colon */ while (*end && *end != ':') end++; *end = 0; /* terminate where colon was */ while (*name == ' ') name++; /* skip over leading whitespace if any */ str = PyStr_FromString(name); PyList_Append(list, str); Py_DECREF(str); } fclose(fd); return list; } static PyObject *get_hwaddress(PyObject *self __unused, PyObject *args) { struct ifreq ifr; int fd, err; const char *devname; char hwaddr[20]; if (!PyArg_ParseTuple(args, "s", &devname)) return NULL; /* Setup our request structure. */ memset(&ifr, 0, sizeof(ifr)); strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ); ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Open control socket. */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { return PyErr_SetFromErrno(PyExc_OSError); } /* Get current settings. */ err = ioctl(fd, SIOCGIFHWADDR, &ifr); if (err < 0) { PyErr_SetFromErrno(PyExc_IOError); close(fd); return NULL; } close(fd); sprintf(hwaddr, "%02x:%02x:%02x:%02x:%02x:%02x", (unsigned int)ifr.ifr_hwaddr.sa_data[0] % 256, (unsigned int)ifr.ifr_hwaddr.sa_data[1] % 256, (unsigned int)ifr.ifr_hwaddr.sa_data[2] % 256, (unsigned int)ifr.ifr_hwaddr.sa_data[3] % 256, (unsigned int)ifr.ifr_hwaddr.sa_data[4] % 256, (unsigned int)ifr.ifr_hwaddr.sa_data[5] % 256); return PyStr_FromString(hwaddr); } static PyObject *get_ipaddress(PyObject *self __unused, PyObject *args) { struct ifreq ifr; int fd, err; const char *devname; char ipaddr[20]; if (!PyArg_ParseTuple(args, "s", &devname)) return NULL; /* Setup our request structure. */ memset(&ifr, 0, sizeof(ifr)); strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ); ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Open control socket. */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { return PyErr_SetFromErrno(PyExc_OSError); } /* Get current settings. */ err = ioctl(fd, SIOCGIFADDR, &ifr); if (err < 0) { PyErr_SetFromErrno(PyExc_IOError); close(fd); return NULL; } close(fd); sprintf(ipaddr, "%u.%u.%u.%u", (unsigned int)ifr.ifr_addr.sa_data[2] % 256, (unsigned int)ifr.ifr_addr.sa_data[3] % 256, (unsigned int)ifr.ifr_addr.sa_data[4] % 256, (unsigned int)ifr.ifr_addr.sa_data[5] % 256); return PyStr_FromString(ipaddr); } /** * Retrieves the current information about all interfaces. * All interfaces will be returned as a list of objects per interface. * * @param self Not used * @param args Python arguments - device name(s) as either a string or a list * * @return Python list of objects on success, otherwise NULL. */ static PyObject *get_interfaces_info(PyObject *self __unused, PyObject *args) { PyObject *devlist = NULL; PyObject *inargs = NULL; char **fetch_devs = NULL; int i = 0, fetch_devs_len = 0; if (!PyArg_ParseTuple(args, "|O", &inargs)) { PyErr_SetString(PyExc_LookupError, "Argument must be either a string, list or a tuple"); return NULL; } /* Parse input arguments if we got them */ if (inargs != NULL) { if (PyStr_Check(inargs)) { /* Input argument is just a string */ fetch_devs_len = 1; fetch_devs = calloc(1, sizeof(char *)); fetch_devs[0] = PyStr_AsString(inargs); } else if (PyTuple_Check(inargs)) { /* Input argument is a tuple list with devices */ int j = 0; fetch_devs_len = PyTuple_Size(inargs); fetch_devs = calloc(fetch_devs_len+1, sizeof(char *)); for (i = 0; i < fetch_devs_len; i++) { PyObject *elmt = PyTuple_GetItem(inargs, i); if (elmt && PyStr_Check(elmt)) { fetch_devs[j++] = PyStr_AsString(elmt); } } fetch_devs_len = j; } else if (PyList_Check(inargs)) { /* Input argument is a list with devices */ int j = 0; fetch_devs_len = PyList_Size(inargs); fetch_devs = calloc(fetch_devs_len+1, sizeof(char *)); for (i = 0; i < fetch_devs_len; i++) { PyObject *elmt = PyList_GetItem(inargs, i); if (elmt && PyStr_Check(elmt)) { fetch_devs[j++] = PyStr_AsString(elmt); } } fetch_devs_len = j; } else { PyErr_SetString(PyExc_LookupError, "Argument must be either a string, " "list or a tuple"); return NULL; } } devlist = PyList_New(0); for (i = 0; i < fetch_devs_len; i++) { PyEtherInfo *dev = NULL; /* Store the device name and a reference to the NETLINK connection for * objects to use when quering for device info */ dev = PyObject_New(PyEtherInfo, &PyEtherInfo_Type); if (!dev) { PyErr_SetFromErrno(PyExc_OSError); free(fetch_devs); return NULL; } dev->device = PyStr_FromString(fetch_devs[i]); dev->hwaddress = NULL; dev->index = -1; /* Append device object to the device list */ PyList_Append(devlist, (PyObject *)dev); Py_DECREF(dev); } free(fetch_devs); return devlist; } static PyObject *get_flags (PyObject *self __unused, PyObject *args) { struct ifreq ifr; const char *devname; int fd, err; if (!PyArg_ParseTuple(args, "s", &devname)) return NULL; /* Setup our request structure. */ memset(&ifr, 0, sizeof(ifr)); strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ); ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Open control socket. */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { return PyErr_SetFromErrno(PyExc_OSError); } err = ioctl(fd, SIOCGIFFLAGS, &ifr); if(err < 0) { PyErr_SetFromErrno(PyExc_IOError); close(fd); return NULL; } close(fd); return Py_BuildValue("h", ifr.ifr_flags); } static PyObject *get_netmask (PyObject *self __unused, PyObject *args) { struct ifreq ifr; int fd, err; const char *devname; char netmask[20]; if (!PyArg_ParseTuple(args, "s", &devname)) return NULL; /* Setup our request structure. */ memset(&ifr, 0, sizeof(ifr)); strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ); ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Open control socket. */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { return PyErr_SetFromErrno(PyExc_OSError); } /* Get current settings. */ err = ioctl(fd, SIOCGIFNETMASK, &ifr); if (err < 0) { PyErr_SetFromErrno(PyExc_IOError); close(fd); return NULL; } close(fd); sprintf(netmask, "%u.%u.%u.%u", (unsigned int)ifr.ifr_netmask.sa_data[2] % 256, (unsigned int)ifr.ifr_netmask.sa_data[3] % 256, (unsigned int)ifr.ifr_netmask.sa_data[4] % 256, (unsigned int)ifr.ifr_netmask.sa_data[5] % 256); return PyStr_FromString(netmask); } static PyObject *get_broadcast(PyObject *self __unused, PyObject *args) { struct ifreq ifr; int fd, err; const char *devname; char broadcast[20]; if (!PyArg_ParseTuple(args, "s", &devname)) return NULL; /* Setup our request structure. */ memset(&ifr, 0, sizeof(ifr)); strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ); ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Open control socket. */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { return PyErr_SetFromErrno(PyExc_OSError); } /* Get current settings. */ err = ioctl(fd, SIOCGIFBRDADDR, &ifr); if (err < 0) { PyErr_SetFromErrno(PyExc_IOError); close(fd); return NULL; } close(fd); sprintf(broadcast, "%u.%u.%u.%u", (unsigned int)ifr.ifr_broadaddr.sa_data[2] % 256, (unsigned int)ifr.ifr_broadaddr.sa_data[3] % 256, (unsigned int)ifr.ifr_broadaddr.sa_data[4] % 256, (unsigned int)ifr.ifr_broadaddr.sa_data[5] % 256); return PyStr_FromString(broadcast); } static PyObject *get_module(PyObject *self __unused, PyObject *args) { struct ethtool_cmd ecmd; struct ifreq ifr; int fd, err; char buf[2048]; const char *devname; if (!PyArg_ParseTuple(args, "s", &devname)) return NULL; /* Setup our control structures. */ memset(&ecmd, 0, sizeof(ecmd)); memset(&ifr, 0, sizeof(ifr)); strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ); ifr.ifr_name[IFNAMSIZ - 1] = 0; ifr.ifr_data = (caddr_t) &buf; ecmd.cmd = ETHTOOL_GDRVINFO; memcpy(&buf, &ecmd, sizeof(ecmd)); /* Open control socket. */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { return PyErr_SetFromErrno(PyExc_OSError); } /* Get current settings. */ err = ioctl(fd, SIOCETHTOOL, &ifr); if (err < 0) { /* failed? */ PyErr_SetFromErrno(PyExc_IOError); FILE *file; int found = 0; char driver[101], dev[101]; close(fd); /* Before bailing, maybe it is a PCMCIA/PC Card? */ file = fopen("/var/lib/pcmcia/stab", "r"); if (file == NULL) { return NULL; } while (!feof(file)) { if (fgets(buf, 2048, file) == NULL) break; buf[2047] = '\0'; if (strncmp(buf, "Socket", 6) != 0) { if (sscanf(buf, "%*d\t%*s\t%100s\t%*d\t%100s\n", driver, dev) > 0) { driver[99] = '\0'; dev[99] = '\0'; if (strcmp(devname, dev) == 0) { found = 1; break; } } } } fclose(file); if (!found) { return NULL; } else { PyErr_Clear(); return PyStr_FromString(driver); } } close(fd); return PyStr_FromString(((struct ethtool_drvinfo *)buf)->driver); } static PyObject *get_businfo(PyObject *self __unused, PyObject *args) { struct ethtool_cmd ecmd; struct ifreq ifr; int fd, err; char buf[1024]; const char *devname; if (!PyArg_ParseTuple(args, "s", &devname)) return NULL; /* Setup our control structures. */ memset(&ecmd, 0, sizeof(ecmd)); memset(&ifr, 0, sizeof(ifr)); strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ); ifr.ifr_name[IFNAMSIZ - 1] = 0; ifr.ifr_data = (caddr_t) &buf; ecmd.cmd = ETHTOOL_GDRVINFO; memcpy(&buf, &ecmd, sizeof(ecmd)); /* Open control socket. */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { return PyErr_SetFromErrno(PyExc_OSError); } /* Get current settings. */ err = ioctl(fd, SIOCETHTOOL, &ifr); if (err < 0) { /* failed? */ PyErr_SetFromErrno(PyExc_IOError); close(fd); return NULL; } close(fd); return PyStr_FromString(((struct ethtool_drvinfo *)buf)->bus_info); } static int send_command(int cmd, const char *devname, void *value) { /* Setup our request structure. */ int fd, err; struct ifreq ifr; struct ethtool_value *eval = value; memset(&ifr, 0, sizeof(ifr)); strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ); ifr.ifr_name[IFNAMSIZ - 1] = 0; ifr.ifr_data = (caddr_t)eval; eval->cmd = cmd; /* Open control socket. */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { PyErr_SetFromErrno(PyExc_OSError); return -1; } /* Get current settings. */ err = ioctl(fd, SIOCETHTOOL, &ifr); if (err < 0) { PyErr_SetFromErrno(PyExc_IOError); } close(fd); return err; } static int get_dev_value(int cmd, PyObject *args, void *value) { const char *devname; int err = -1; if (PyArg_ParseTuple(args, "s", &devname)) err = send_command(cmd, devname, value); return err; } static int get_dev_int_value(int cmd, PyObject *args, int *value) { struct ethtool_value eval; int rc = get_dev_value(cmd, args, &eval); if (rc == 0) *value = *(int *)&eval.data; return rc; } static int dev_set_int_value(int cmd, PyObject *args) { struct ethtool_value eval; const char *devname; if (!PyArg_ParseTuple(args, "si", &devname, &eval.data)) return -1; return send_command(cmd, devname, &eval); } static PyObject *get_tso(PyObject *self __unused, PyObject *args) { int value = 0; if (get_dev_int_value(ETHTOOL_GTSO, args, &value) < 0) return NULL; return Py_BuildValue("b", value); } static PyObject *set_tso(PyObject *self __unused, PyObject *args) { if (dev_set_int_value(ETHTOOL_STSO, args) < 0) return NULL; Py_RETURN_NONE; } static PyObject *get_ufo(PyObject *self __unused, PyObject *args) { int value = 0; if (get_dev_int_value(ETHTOOL_GUFO, args, &value) < 0) return NULL; return Py_BuildValue("b", value); } static PyObject *get_gso(PyObject *self __unused, PyObject *args) { int value = 0; if (get_dev_int_value(ETHTOOL_GGSO, args, &value) < 0) return NULL; return Py_BuildValue("b", value); } static PyObject *set_gso(PyObject *self __unused, PyObject *args) { if (dev_set_int_value(ETHTOOL_SGSO, args) < 0) return NULL; Py_RETURN_NONE; } static PyObject *get_gro(PyObject *self __unused, PyObject *args) { int value = 0; if (get_dev_int_value(ETHTOOL_GGRO, args, &value) < 0) return NULL; return Py_BuildValue("b", value); } static PyObject *set_gro(PyObject *self __unused, PyObject *args) { if (dev_set_int_value(ETHTOOL_SGRO, args) < 0) return NULL; Py_RETURN_NONE; } static PyObject *get_sg(PyObject *self __unused, PyObject *args) { int value = 0; if (get_dev_int_value(ETHTOOL_GSG, args, &value) < 0) return NULL; return Py_BuildValue("b", value); } static PyObject *get_wireless_protocol (PyObject *self __unused, PyObject *args) { struct iwreq iwr; const char *devname; int fd, err; if (!PyArg_ParseTuple(args, "s", &devname)) return NULL; /* Setup our request structure. */ memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, devname, IFNAMSIZ-1); iwr.ifr_name[IFNAMSIZ-1] = 0; /* Open control socket. */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } err = ioctl(fd, SIOCGIWNAME, &iwr); if(err < 0) { PyErr_SetFromErrno(PyExc_IOError); close(fd); return NULL; } close(fd); return PyStr_FromString(iwr.u.name); } struct struct_desc { char *name; unsigned short offset; unsigned short size; }; #define member_desc(type, member_name) { \ .name = #member_name, \ .offset = offsetof(type, member_name), \ .size = sizeof(((type *)0)->member_name), } struct struct_desc ethtool_coalesce_desc[] = { member_desc(struct ethtool_coalesce, rx_coalesce_usecs), member_desc(struct ethtool_coalesce, rx_max_coalesced_frames), member_desc(struct ethtool_coalesce, rx_coalesce_usecs_irq), member_desc(struct ethtool_coalesce, rx_max_coalesced_frames_irq), member_desc(struct ethtool_coalesce, tx_coalesce_usecs), member_desc(struct ethtool_coalesce, tx_max_coalesced_frames), member_desc(struct ethtool_coalesce, tx_coalesce_usecs_irq), member_desc(struct ethtool_coalesce, tx_max_coalesced_frames_irq), member_desc(struct ethtool_coalesce, stats_block_coalesce_usecs), member_desc(struct ethtool_coalesce, use_adaptive_rx_coalesce), member_desc(struct ethtool_coalesce, use_adaptive_tx_coalesce), member_desc(struct ethtool_coalesce, pkt_rate_low), member_desc(struct ethtool_coalesce, rx_coalesce_usecs_low), member_desc(struct ethtool_coalesce, rx_max_coalesced_frames_low), member_desc(struct ethtool_coalesce, tx_coalesce_usecs_low), member_desc(struct ethtool_coalesce, tx_max_coalesced_frames_low), member_desc(struct ethtool_coalesce, pkt_rate_high), member_desc(struct ethtool_coalesce, rx_coalesce_usecs_high), member_desc(struct ethtool_coalesce, rx_max_coalesced_frames_high), member_desc(struct ethtool_coalesce, tx_coalesce_usecs_high), member_desc(struct ethtool_coalesce, tx_max_coalesced_frames_high), member_desc(struct ethtool_coalesce, rate_sample_interval), }; static PyObject *__struct_desc_create_dict(struct struct_desc *table, int nr_entries, void *values) { int i; PyObject *dict = PyDict_New(); if (dict == NULL) return NULL; for (i = 0; i < nr_entries; ++i) { struct struct_desc *d = &table[i]; PyObject *objval = NULL; void *val = values + d->offset; switch (d->size) { case sizeof(uint32_t): objval = PyLong_FromLong(*(uint32_t *)val); break; } if (objval == NULL) { Py_DECREF(dict); return NULL; } if (PyDict_SetItemString(dict, d->name, objval) != 0) { Py_DECREF(objval); Py_DECREF(dict); return NULL; } Py_DECREF(objval); } return dict; } #define struct_desc_create_dict(table, values) \ __struct_desc_create_dict(table, ARRAY_SIZE(table), values) static int __struct_desc_from_dict(struct struct_desc *table, int nr_entries, void *to, PyObject *dict) { char buf[2048]; int i; for (i = 0; i < nr_entries; ++i) { struct struct_desc *d = &table[i]; void *val = to + d->offset; PyObject *obj; switch (d->size) { case sizeof(uint32_t): obj = PyDict_GetItemString(dict, d->name); if (obj == NULL) { snprintf(buf, sizeof(buf), "Missing dict entry for field %s", d->name); PyErr_SetString(PyExc_IOError, buf); return -1; } *(uint32_t *)val = PyLong_AsLong(obj); break; default: snprintf(buf, sizeof(buf), "Invalid type size %d for field %s", d->size, d->name); PyErr_SetString(PyExc_IOError, buf); return -1; } } return 0; } #define struct_desc_from_dict(table, to, dict) \ __struct_desc_from_dict(table, ARRAY_SIZE(table), to, dict) static PyObject *get_coalesce(PyObject *self __unused, PyObject *args) { struct ethtool_coalesce coal; if (get_dev_value(ETHTOOL_GCOALESCE, args, &coal) < 0) return NULL; return struct_desc_create_dict(ethtool_coalesce_desc, &coal); } static PyObject *set_coalesce(PyObject *self __unused, PyObject *args) { struct ethtool_coalesce coal; const char *devname; PyObject *dict; if (!PyArg_ParseTuple(args, "sO", &devname, &dict)) return NULL; if (struct_desc_from_dict(ethtool_coalesce_desc, &coal, dict) != 0) return NULL; if (send_command(ETHTOOL_SCOALESCE, devname, &coal)) return NULL; Py_RETURN_NONE; } struct struct_desc ethtool_ringparam_desc[] = { member_desc(struct ethtool_ringparam, rx_max_pending), member_desc(struct ethtool_ringparam, rx_mini_max_pending), member_desc(struct ethtool_ringparam, rx_jumbo_max_pending), member_desc(struct ethtool_ringparam, tx_max_pending), member_desc(struct ethtool_ringparam, rx_pending), member_desc(struct ethtool_ringparam, rx_mini_pending), member_desc(struct ethtool_ringparam, rx_jumbo_pending), member_desc(struct ethtool_ringparam, tx_pending), }; static PyObject *get_ringparam(PyObject *self __unused, PyObject *args) { struct ethtool_ringparam ring; if (get_dev_value(ETHTOOL_GRINGPARAM, args, &ring) < 0) return NULL; return struct_desc_create_dict(ethtool_ringparam_desc, &ring); } static PyObject *set_ringparam(PyObject *self __unused, PyObject *args) { struct ethtool_ringparam ring; const char *devname; PyObject *dict; if (!PyArg_ParseTuple(args, "sO", &devname, &dict)) return NULL; if (struct_desc_from_dict(ethtool_ringparam_desc, &ring, dict) != 0) return NULL; if (send_command(ETHTOOL_SRINGPARAM, devname, &ring)) return NULL; Py_RETURN_NONE; } static struct PyMethodDef PyEthModuleMethods[] = { { .ml_name = "get_module", .ml_meth = (PyCFunction)get_module, .ml_flags = METH_VARARGS, }, { .ml_name = "get_businfo", .ml_meth = (PyCFunction)get_businfo, .ml_flags = METH_VARARGS, }, { .ml_name = "get_hwaddr", .ml_meth = (PyCFunction)get_hwaddress, .ml_flags = METH_VARARGS, }, { .ml_name = "get_ipaddr", .ml_meth = (PyCFunction)get_ipaddress, .ml_flags = METH_VARARGS, }, { .ml_name = "get_interfaces_info", .ml_meth = (PyCFunction)get_interfaces_info, .ml_flags = METH_VARARGS, .ml_doc = "Accepts a string, list or tupples of interface names. " "Returns a list of ethtool.etherinfo objets with device information." }, { .ml_name = "get_netmask", .ml_meth = (PyCFunction)get_netmask, .ml_flags = METH_VARARGS, }, { .ml_name = "get_broadcast", .ml_meth = (PyCFunction)get_broadcast, .ml_flags = METH_VARARGS, }, { .ml_name = "get_coalesce", .ml_meth = (PyCFunction)get_coalesce, .ml_flags = METH_VARARGS, }, { .ml_name = "set_coalesce", .ml_meth = (PyCFunction)set_coalesce, .ml_flags = METH_VARARGS, }, { .ml_name = "get_devices", .ml_meth = (PyCFunction)get_devices, .ml_flags = METH_VARARGS, }, { .ml_name = "get_active_devices", .ml_meth = (PyCFunction)get_active_devices, .ml_flags = METH_VARARGS, }, { .ml_name = "get_ringparam", .ml_meth = (PyCFunction)get_ringparam, .ml_flags = METH_VARARGS, }, { .ml_name = "set_ringparam", .ml_meth = (PyCFunction)set_ringparam, .ml_flags = METH_VARARGS, }, { .ml_name = "get_tso", .ml_meth = (PyCFunction)get_tso, .ml_flags = METH_VARARGS, }, { .ml_name = "set_tso", .ml_meth = (PyCFunction)set_tso, .ml_flags = METH_VARARGS, }, { .ml_name = "get_ufo", .ml_meth = (PyCFunction)get_ufo, .ml_flags = METH_VARARGS, }, { .ml_name = "get_gso", .ml_meth = (PyCFunction)get_gso, .ml_flags = METH_VARARGS, }, { .ml_name = "set_gso", .ml_meth = (PyCFunction)set_gso, .ml_flags = METH_VARARGS, }, { .ml_name = "get_gro", .ml_meth = (PyCFunction)get_gro, .ml_flags = METH_VARARGS, }, { .ml_name = "set_gro", .ml_meth = (PyCFunction)set_gro, .ml_flags = METH_VARARGS, }, { .ml_name = "get_sg", .ml_meth = (PyCFunction)get_sg, .ml_flags = METH_VARARGS, }, { .ml_name = "get_flags", .ml_meth = (PyCFunction)get_flags, .ml_flags = METH_VARARGS, }, { .ml_name = "get_wireless_protocol", .ml_meth = (PyCFunction)get_wireless_protocol, .ml_flags = METH_VARARGS, }, { .ml_name = NULL, }, }; static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, .m_name = "ethtool", .m_doc = "Python ethtool module", .m_size = -1, .m_methods = PyEthModuleMethods, }; MODULE_INIT_FUNC(ethtool) { PyObject *m; m = PyModule_Create(&moduledef); if (m == NULL) return NULL; // Prepare the ethtool.etherinfo class if (PyType_Ready(&PyEtherInfo_Type) < 0) return NULL; // Prepare the ethtool IPv6 and IPv4 address types if (PyType_Ready(ðtool_netlink_ip_address_Type)) return NULL; // Setup constants /* Interface is up: */ PyModule_AddIntConstant(m, "IFF_UP", IFF_UP); /* Broadcast address valid: */ PyModule_AddIntConstant(m, "IFF_BROADCAST", IFF_BROADCAST); /* Turn on debugging: */ PyModule_AddIntConstant(m, "IFF_DEBUG", IFF_DEBUG); /* Is a loopback net: */ PyModule_AddIntConstant(m, "IFF_LOOPBACK", IFF_LOOPBACK); /* Is a point-to-point link: */ PyModule_AddIntConstant(m, "IFF_POINTOPOINT", IFF_POINTOPOINT); /* Avoid use of trailers: */ PyModule_AddIntConstant(m, "IFF_NOTRAILERS", IFF_NOTRAILERS); /* Resources allocated: */ PyModule_AddIntConstant(m, "IFF_RUNNING", IFF_RUNNING); /* No address resolution protocol: */ PyModule_AddIntConstant(m, "IFF_NOARP", IFF_NOARP); /* Receive all packets: */ PyModule_AddIntConstant(m, "IFF_PROMISC", IFF_PROMISC); /* Receive all multicast packets: */ PyModule_AddIntConstant(m, "IFF_ALLMULTI", IFF_ALLMULTI); /* Master of a load balancer: */ PyModule_AddIntConstant(m, "IFF_MASTER", IFF_MASTER); /* Slave of a load balancer: */ PyModule_AddIntConstant(m, "IFF_SLAVE", IFF_SLAVE); /* Supports multicast: */ PyModule_AddIntConstant(m, "IFF_MULTICAST", IFF_MULTICAST); /* Can set media type: */ PyModule_AddIntConstant(m, "IFF_PORTSEL", IFF_PORTSEL); /* Auto media select active: */ PyModule_AddIntConstant(m, "IFF_AUTOMEDIA", IFF_AUTOMEDIA); /* Dialup device with changing addresses: */ PyModule_AddIntConstant(m, "IFF_DYNAMIC", IFF_DYNAMIC); /* IPv4 interface: */ PyModule_AddIntConstant(m, "AF_INET", AF_INET); /* IPv6 interface: */ PyModule_AddIntConstant(m, "AF_INET6", AF_INET6); /* python-ethtool version: */ PyModule_AddStringConstant(m, "version", "python-ethtool v" VERSION); Py_INCREF(&PyEtherInfo_Type); PyModule_AddObject(m, "etherinfo", (PyObject *)&PyEtherInfo_Type); Py_INCREF(ðtool_netlink_ip_address_Type); PyModule_AddObject(m, "NetlinkIPaddress", (PyObject *)ðtool_netlink_ip_address_Type); return m; } python-ethtool-0.14/python-ethtool/include/000077500000000000000000000000001334642534600210655ustar00rootroot00000000000000python-ethtool-0.14/python-ethtool/include/py3c/000077500000000000000000000000001334642534600217435ustar00rootroot00000000000000python-ethtool-0.14/python-ethtool/include/py3c/compat.h000066400000000000000000000116331334642534600234030ustar00rootroot00000000000000/* Licensed under the MIT license The MIT License (MIT) Copyright (c) 2015, Red Hat, Inc. and/or its affiliates Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _PY3C_COMPAT_H_ #define _PY3C_COMPAT_H_ #include #if PY_MAJOR_VERSION >= 3 /***** Python 3 *****/ #define IS_PY3 1 /* Strings */ #define PyStr_Type PyUnicode_Type #define PyStr_Check PyUnicode_Check #define PyStr_CheckExact PyUnicode_CheckExact #define PyStr_FromString PyUnicode_FromString #define PyStr_FromStringAndSize PyUnicode_FromStringAndSize #define PyStr_FromFormat PyUnicode_FromFormat #define PyStr_FromFormatV PyUnicode_FromFormatV #define PyStr_AsString PyUnicode_AsUTF8 #define PyStr_Concat PyUnicode_Concat #define PyStr_Format PyUnicode_Format #define PyStr_InternInPlace PyUnicode_InternInPlace #define PyStr_InternFromString PyUnicode_InternFromString #define PyStr_Decode PyUnicode_Decode #define PyStr_AsUTF8String PyUnicode_AsUTF8String // returns PyBytes #define PyStr_AsUTF8 PyUnicode_AsUTF8 #define PyStr_AsUTF8AndSize PyUnicode_AsUTF8AndSize /* Ints */ #define PyInt_Type PyLong_Type #define PyInt_Check PyLong_Check #define PyInt_CheckExact PyLong_CheckExact #define PyInt_FromString PyLong_FromString #define PyInt_FromLong PyLong_FromLong #define PyInt_FromSsize_t PyLong_FromSsize_t #define PyInt_FromSize_t PyLong_FromSize_t #define PyInt_AsLong PyLong_AsLong #define PyInt_AS_LONG PyLong_AS_LONG #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask #define PyInt_AsSsize_t PyLong_AsSsize_t /* Module init */ #define MODULE_INIT_FUNC(name) \ PyMODINIT_FUNC PyInit_ ## name(void); \ PyMODINIT_FUNC PyInit_ ## name(void) #else /***** Python 2 *****/ #define IS_PY3 0 /* Strings */ #define PyStr_Type PyString_Type #define PyStr_Check PyString_Check #define PyStr_CheckExact PyString_CheckExact #define PyStr_FromString PyString_FromString #define PyStr_FromStringAndSize PyString_FromStringAndSize #define PyStr_FromFormat PyString_FromFormat #define PyStr_FromFormatV PyString_FromFormatV #define PyStr_AsString PyString_AsString #define PyStr_Format PyString_Format #define PyStr_InternInPlace PyString_InternInPlace #define PyStr_InternFromString PyString_InternFromString #define PyStr_Decode PyString_Decode static PyObject *PyStr_Concat(PyObject *left, PyObject *right) { PyObject *str = left; Py_INCREF(left); // reference to old left will be stolen PyString_Concat(&str, right); if (str) { return str; } else { return NULL; } } #define PyStr_AsUTF8String(str) (Py_INCREF(str), (str)) #define PyStr_AsUTF8 PyString_AsString #define PyStr_AsUTF8AndSize(pystr, sizeptr) \ ((*sizeptr=PyString_Size(pystr)), PyString_AsString(pystr)) #define PyBytes_Type PyString_Type #define PyBytes_Check PyString_Check #define PyBytes_CheckExact PyString_CheckExact #define PyBytes_FromString PyString_FromString #define PyBytes_FromStringAndSize PyString_FromStringAndSize #define PyBytes_FromFormat PyString_FromFormat #define PyBytes_FromFormatV PyString_FromFormatV #define PyBytes_Size PyString_Size #define PyBytes_GET_SIZE PyString_GET_SIZE #define PyBytes_AsString PyString_AsString #define PyBytes_AS_STRING PyString_AS_STRING #define PyBytes_AsStringAndSize PyString_AsStringAndSize #define PyBytes_Concat PyString_Concat #define PyBytes_ConcatAndDel PyString_ConcatAndDel #define _PyBytes_Resize _PyString_Resize /* Floats */ #define PyFloat_FromString(str) PyFloat_FromString(str, NULL) /* Module init */ #define PyModuleDef_HEAD_INIT 0 typedef struct PyModuleDef { int m_base; const char* m_name; const char* m_doc; Py_ssize_t m_size; PyMethodDef *m_methods; } PyModuleDef; #define PyModule_Create(def) \ Py_InitModule3((def)->m_name, (def)->m_methods, (def)->m_doc) #define MODULE_INIT_FUNC(name) \ static PyObject *PyInit_ ## name(void); \ PyMODINIT_FUNC init ## name(void); \ PyMODINIT_FUNC init ## name(void) { PyInit_ ## name(); } \ static PyObject *PyInit_ ## name(void) #endif #endif python-ethtool-0.14/python-ethtool/netlink-address.c000066400000000000000000000145231334642534600227020ustar00rootroot00000000000000/* * Copyright (C) 2011 - 2013 Red Hat Inc. * * David Malcolm * * This application is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; version 2. * * This application is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ /* Python object corresponding to a (struct rtnl_addr) */ #include #include "include/py3c/compat.h" #include #include "structmember.h" #include #include #include #include #include "etherinfo_struct.h" #include "etherinfo.h" /* IP Address parsing: */ static PyObject * PyNetlinkIPaddress_from_rtnl_addr(struct rtnl_addr *addr) { PyNetlinkIPaddress *py_obj; char buf[INET6_ADDRSTRLEN+1]; struct nl_addr *peer_addr = NULL, *brdcst = NULL; py_obj = PyObject_New(PyNetlinkIPaddress, ðtool_netlink_ip_address_Type); if (!py_obj) { return NULL; } /* Set IP address family. Only AF_INET and AF_INET6 is supported */ py_obj->family = rtnl_addr_get_family(addr); if (py_obj->family != AF_INET && py_obj->family != AF_INET6) { PyErr_SetString(PyExc_RuntimeError, "Only IPv4 (AF_INET) and IPv6 (AF_INET6) " "address types are supported"); goto error; } /* Set local IP address: */ memset(&buf, 0, sizeof(buf)); if (!inet_ntop(py_obj->family, nl_addr_get_binary_addr(rtnl_addr_get_local(addr)), buf, sizeof(buf))) { PyErr_SetFromErrno(PyExc_RuntimeError); goto error; } py_obj->local = PyStr_FromString(buf); if (!py_obj->local) { goto error; } /* Set peer IP address: */ memset(&buf, 0, sizeof(buf)); if ((peer_addr = rtnl_addr_get_peer(addr))) { nl_addr2str(peer_addr, buf, sizeof(buf)); py_obj->peer = PyStr_FromString(buf); if (!py_obj->local) { goto error; } } else { py_obj->peer = NULL; } /* Set IP address prefix length (netmask): */ py_obj->prefixlen = rtnl_addr_get_prefixlen(addr); /* Set ipv4_broadcast: */ py_obj->ipv4_broadcast = NULL; brdcst = rtnl_addr_get_broadcast(addr); if (py_obj->family == AF_INET && brdcst) { memset(&buf, 0, sizeof(buf)); if (!inet_ntop(AF_INET, nl_addr_get_binary_addr(brdcst), buf, sizeof(buf))) { PyErr_SetFromErrno(PyExc_RuntimeError); goto error; } py_obj->ipv4_broadcast = PyStr_FromString(buf); if (!py_obj->ipv4_broadcast) { goto error; } } /* Set IP address scope: */ memset(&buf, 0, sizeof(buf)); rtnl_scope2str(rtnl_addr_get_scope(addr), buf, sizeof(buf)); py_obj->scope = PyStr_FromString(buf); return (PyObject*)py_obj; error: Py_DECREF(py_obj); return NULL; } static void netlink_ip_address_dealloc(PyNetlinkIPaddress *obj) { Py_DECREF(obj->local); Py_XDECREF(obj->peer); Py_XDECREF(obj->ipv4_broadcast); Py_XDECREF(obj->scope); /* We can call PyObject_Del directly rather than calling through tp_free since the type is not subtypable (Py_TPFLAGS_BASETYPE is not set): */ PyObject_Del(obj); } static PyObject* netlink_ip_address_repr(PyNetlinkIPaddress *obj) { PyObject *result = PyStr_FromString("ethtool.NetlinkIPaddress(family="); char buf[256]; memset(&buf, 0, sizeof(buf)); nl_af2str(obj->family, buf, sizeof(buf)); result = PyStr_Concat(result, PyStr_FromFormat("%s, address='%s", buf, PyStr_AsString(obj->local))); if (obj->family == AF_INET) { result = PyStr_Concat(result, PyStr_FromFormat("', netmask=%d", obj->prefixlen)); } else if (obj->family == AF_INET6) { result = PyStr_Concat(result, PyStr_FromFormat("/%d'", obj->prefixlen)); } if (obj->peer) { result = PyStr_Concat(result, PyStr_FromFormat(", peer_address='%s'", PyStr_AsString(obj->peer))); } if (obj->family == AF_INET && obj->ipv4_broadcast) { result = PyStr_Concat(result, PyStr_FromFormat(", broadcast='%s'", PyStr_AsString( obj->ipv4_broadcast))); } result = PyStr_Concat(result, PyStr_FromFormat(", scope=%s)", PyStr_AsString(obj->scope))); return result; } static PyMemberDef _ethtool_netlink_ip_address_members[] = { { "address", T_OBJECT_EX, offsetof(PyNetlinkIPaddress, local), 0, NULL }, { "peer_address", T_OBJECT_EX, offsetof(PyNetlinkIPaddress, peer), 0, NULL }, { "netmask", T_INT, offsetof(PyNetlinkIPaddress, prefixlen), 0, NULL }, { "broadcast", T_OBJECT, /* can be NULL */ offsetof(PyNetlinkIPaddress, ipv4_broadcast), 0, NULL }, { "scope", T_OBJECT_EX, offsetof(PyNetlinkIPaddress, scope), 0, NULL }, {NULL} /* End of member list */ }; PyTypeObject ethtool_netlink_ip_address_Type = { PyVarObject_HEAD_INIT(0, 0) .tp_name = "ethtool.NetlinkIPaddress", .tp_basicsize = sizeof(PyNetlinkIPaddress), .tp_dealloc = (destructor)netlink_ip_address_dealloc, .tp_repr = (reprfunc)netlink_ip_address_repr, .tp_members = _ethtool_netlink_ip_address_members, }; PyObject * make_python_address_from_rtnl_addr(struct rtnl_addr *addr) { assert(addr); switch( rtnl_addr_get_family(addr)) { case AF_INET: case AF_INET6: return PyNetlinkIPaddress_from_rtnl_addr(addr); default: return PyErr_SetFromErrno(PyExc_RuntimeError); } } python-ethtool-0.14/python-ethtool/netlink.c000066400000000000000000000066551334642534600212660ustar00rootroot00000000000000/* netlink.c - Generic NETLINK API functions * * Copyright (C) 2009-2013 Red Hat Inc. * * David Sommerseth * * This application is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; version 2. * * This application is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ #include #include #include #include #include #include #include "etherinfo_struct.h" pthread_mutex_t nlc_counter_mtx = PTHREAD_MUTEX_INITIALIZER; static struct nl_sock *nlconnection = NULL; /* How many NETLINK users are active? */ static unsigned int nlconnection_users = 0; /** * Connects to the NETLINK interface. This will be called * for each etherinfo object being generated, and it will * keep a separate file descriptor open for each object * * @param ethi PyEtherInfo structure (basically the "self" object) * * @return Returns 1 on success, otherwise 0. */ int open_netlink(PyEtherInfo *ethi) { if (!ethi) { return 0; } /* Reuse already established NETLINK connection, if a connection exists */ if (nlconnection) { /* If this object has not used NETLINK earlier, tag it as a user */ if (!ethi->nlc_active) { pthread_mutex_lock(&nlc_counter_mtx); nlconnection_users++; pthread_mutex_unlock(&nlc_counter_mtx); } ethi->nlc_active = 1; return 1; } /* No earlier connections exists, establish a new one */ nlconnection = nl_socket_alloc(); if (nlconnection != NULL) { if (nl_connect(nlconnection, NETLINK_ROUTE) < 0) { return 0; } /* Force O_CLOEXEC flag on the NETLINK socket */ if (fcntl(nl_socket_get_fd(nlconnection), F_SETFD, FD_CLOEXEC) == -1) { fprintf(stderr, "**WARNING** Failed to set O_CLOEXEC on NETLINK socket: " "%s\n", strerror(errno)); } /* Tag this object as an active user */ pthread_mutex_lock(&nlc_counter_mtx); nlconnection_users++; pthread_mutex_unlock(&nlc_counter_mtx); ethi->nlc_active = 1; return 1; } else { return 0; } } /** * Return a reference to the global netlink connection * * @returns Returns a pointer to a NETLINK connection libnl functions can use */ struct nl_sock * get_nlc() { assert(nlconnection); return nlconnection; } /** * Closes the NETLINK connection. This should be called automatically whenever * the corresponding etherinfo object is deleted. * * @param ethi PyEtherInfo structure (basically the "self" object) */ void close_netlink(PyEtherInfo *ethi) { if (!ethi || !nlconnection) { return; } /* Untag this object as a NETLINK user */ ethi->nlc_active = 0; pthread_mutex_lock(&nlc_counter_mtx); nlconnection_users--; pthread_mutex_unlock(&nlc_counter_mtx); /* Don't close the connection if there are more users */ if (nlconnection_users > 0) { return; } /* Close NETLINK connection */ nl_close(nlconnection); nl_socket_free(nlconnection); nlconnection = NULL; } python-ethtool-0.14/scripts/000077500000000000000000000000001334642534600161345ustar00rootroot00000000000000python-ethtool-0.14/scripts/pethtool000077500000000000000000000260741334642534600177310ustar00rootroot00000000000000#! /usr/bin/python # -*- python -*- # -*- coding: utf-8 -*- # Copyright (C) 2008 Red Hat Inc. # # This application is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; version 2. # # This application is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. from __future__ import unicode_literals, print_function import getopt import ethtool import sys def usage(): print('''Usage: pethtool [OPTIONS] [] -h|--help Give this help list -c|--show-coalesce Show coalesce options -C|--coalesce Set coalesce options [adaptive-rx on|off] [adaptive-tx on|off] [rx-usecs N] [rx-frames N] [rx-usecs-irq N] [rx-frames-irq N] [tx-usecs N] [tx-frames N] [tx-usecs-irq N] [tx-frames-irq N] [stats-block-usecs N] [pkt-rate-low N] [rx-usecs-low N] [rx-frames-low N] [tx-usecs-low N] [tx-frames-low N] [pkt-rate-high N] [rx-usecs-high N] [rx-frames-high N] [tx-usecs-high N] [tx-frames-high N] [sample-interval N] -g|--show-ring Show ring parameters -G|--set-ring Set ring parameters [rx N] [rx-mini N] [rx-jumbo N] [tx N] -i|--driver Show driver information -k|--show-offload Get protocol offload information -K|--offload Set protocol offload [ tso on|off ]''') tab = '' def printtab(msg): print(tab + msg) all_devices = [] ethtool_coalesce_msgs = ( ('stats-block-usecs', 'stats_block_coalesce_usecs'), ('sample-interval', 'rate_sample_interval'), ('pkt-rate-low', 'pkt_rate_low'), ('pkt-rate-high', 'pkt_rate_high'), ('\n'), ('rx-usecs', 'rx_coalesce_usecs'), ('rx-frames', 'rx_max_coalesced_frames'), ('rx-usecs-irq', 'rx_coalesce_usecs_irq'), ('rx-frames-irq', 'rx_max_coalesced_frames_irq'), ('\n'), ('tx-usecs', 'tx_coalesce_usecs'), ('tx-frames', 'tx_max_coalesced_frames'), ('tx-usecs-irq', 'tx_coalesce_usecs_irq'), ('tx-frames-irq', 'tx_max_coalesced_frames_irq'), ('\n'), ('rx-usecs-low', 'rx_coalesce_usecs_low'), ('rx-frame-low', 'rx_max_coalesced_frames_low'), ('tx-usecs-low', 'tx_coalesce_usecs_low'), ('tx-frame-low', 'tx_max_coalesced_frames_low'), ('\n'), ('rx-usecs-high', 'rx_coalesce_usecs_high'), ('rx-frame-high', 'rx_max_coalesced_frames_high'), ('tx-usecs-high', 'tx_coalesce_usecs_high'), ('tx-frame-high', 'tx_max_coalesced_frames_high'), ) def get_coalesce_dict_entry(ethtool_name): if ethtool_name == 'adaptive-rx': return 'use_adaptive_rx_coalesce' if ethtool_name == 'adaptive-tx': return 'use_adaptive_tx_coalesce' for name in ethtool_coalesce_msgs: if name[0] == ethtool_name: return name[1] return None def show_coalesce(interface, args=None): printtab('Coalesce parameters for %s:' % interface) try: coal = ethtool.get_coalesce(interface) except IOError: printtab(' NOT supported!') return printtab('Adaptive RX: %s TX: %s' % (coal['use_adaptive_rx_coalesce'] and 'on' or 'off', coal['use_adaptive_tx_coalesce'] and 'on' or 'off')) printed = ['use_adaptive_rx_coalesce', 'use_adaptive_tx_coalesce'] for tunable in ethtool_coalesce_msgs: if tunable[0] == '\n': print else: printtab('%s: %s' % (tunable[0], coal[tunable[1]])) printed.append(tunable[1]) coalkeys = coal.keys() if len(coalkeys) != len(printed): print for tunable in coalkeys: if tunable not in printed: printtab('%s %s' % (tunable, coal[tunable])) def set_coalesce(interface, args): try: coal = ethtool.get_coalesce(interface) except IOError: printtab('Interrupt coalescing NOT supported on %s!' % interface) return changed = False args = [a.lower() for a in args] for arg, value in [(args[i], args[i + 1]) for i in range(0, len(args), 2)]: real_arg = get_coalesce_dict_entry(arg) if not real_arg: continue if value == 'on': value = 1 elif value == 'off': value = 0 else: try: value = int(value) except: continue if coal[real_arg] != value: coal[real_arg] = value changed = True if not changed: return ethtool.set_coalesce(interface, coal) def show_offload(interface, args=None): try: sg = ethtool.get_sg(interface) and 'on' or 'off' except IOError: sg = 'not supported' try: tso = ethtool.get_tso(interface) and 'on' or 'off' except IOError: tso = 'not supported' try: ufo = ethtool.get_ufo(interface) and 'on' or 'off' except IOError: ufo = 'not supported' try: gso = ethtool.get_gso(interface) and 'on' or 'off' except IOError: gso = 'not supported' try: gro = ethtool.get_gro(interface) and 'on' or 'off' except IOError: gro = 'not supported' printtab('scatter-gather: %s' % sg) printtab('tcp segmentation offload: %s' % tso) printtab('udp fragmentation offload: %s' % ufo) printtab('generic segmentation offload: %s' % gso) printtab('generic receive offload: %s' % gro) def set_offload(interface, args): cmd, value = [a.lower() for a in args] if cmd == 'tso': value = value == 'on' and 1 or 0 try: ethtool.set_tso(interface, value) except: pass elif cmd == 'gso': value = value == 'on' and 1 or 0 try: ethtool.set_gso(interface, value) except: pass elif cmd == 'gro': value = value == 'on' and 1 or 0 try: ethtool.set_gro(interface, value) except: pass ethtool_ringparam_msgs = ( ('Pre-set maximums', ), ('RX:\t\t', 'rx_max_pending'), ('RX Mini:\t', 'rx_mini_max_pending'), ('RX Jumbo:\t', 'rx_jumbo_max_pending'), ('TX:\t\t', 'tx_max_pending'), ('Current hardware settings', ), ('RX:\t\t', 'rx_pending'), ('RX Mini:\t', 'rx_mini_pending'), ('RX Jumbo:\t', 'rx_jumbo_pending'), ('TX:\t\t', 'tx_pending'), ) def show_ring(interface, args=None): printtab('Ring parameters for %s:' % interface) try: ring = ethtool.get_ringparam(interface) except IOError: printtab(' NOT supported!') return printed = [] for tunable in ethtool_ringparam_msgs: if len(tunable) == 1: printtab('%s:' % tunable[0]) else: printtab('%s %s' % (tunable[0], ring[tunable[1]])) printed.append(tunable[1]) ringkeys = ring.keys() if len(ringkeys) != len(printed): print for tunable in ringkeys: if tunable not in printed: printtab('%s %s' % (tunable, ring[tunable])) ethtool_ringparam_map = { 'rx': 'rx_pending', 'rx-mini': 'rx_mini_pending', 'rx-jumbo': 'rx_jumbo_pending', 'tx': 'tx_pending', } def set_ringparam(interface, args): try: ring = ethtool.get_ringparam(interface) except IOError: printtab('ring parameters NOT supported on %s!' % interface) return changed = False args = [a.lower() for a in args] for arg, value in [(args[i], args[i + 1]) for i in range(0, len(args), 2)]: if arg not in ethtool_ringparam_map: continue try: value = int(value) except: continue real_arg = ethtool_ringparam_map[arg] if ring[real_arg] != value: ring[real_arg] = value changed = True if not changed: return ethtool.set_ringparam(interface, ring) def show_driver(interface, args=None): try: driver = ethtool.get_module(interface) except IOError: driver = 'not implemented' try: bus = ethtool.get_businfo(interface) except IOError: bus = 'not available' printtab('driver: %s' % driver) printtab('bus-info: %s' % bus) def run_cmd(cmd, interface, args): global tab, all_devices active_devices = ethtool.get_active_devices() if not interface: tab = ' ' for interface in all_devices: inactive = ' (not active)' if interface in active_devices: inactive = '' print('%s%s:' % (interface, inactive)) cmd(interface, args) else: cmd(interface, args) def run_cmd_noargs(cmd, args): if args: run_cmd(cmd, args[0], None) else: global all_devices all_devices = ethtool.get_devices() run_cmd(cmd, None, None) def main(): global all_devices try: opts, args = getopt.getopt(sys.argv[1:], 'hcCgGikK', ('help', 'show-coalesce', 'coalesce', 'show-ring', 'set-ring', 'driver', 'show-offload', 'offload')) except getopt.GetoptError as err: usage() print(err) sys.exit(2) if not opts: usage() sys.exit(0) for o, a in opts: if o in ('-h', '--help'): usage() return elif o in ('-c', '--show-coalesce'): run_cmd_noargs(show_coalesce, args) break elif o in ('-i', '--driver'): run_cmd_noargs(show_driver, args) break elif o in ('-k', '--show-offload'): run_cmd_noargs(show_offload, args) break elif o in ('-g', '--show-ring'): run_cmd_noargs(show_ring, args) break elif o in ('-K', '--offload', '-C', '--coalesce', '-G', '--set-ring'): all_devices = ethtool.get_devices() if len(args) < 2: usage() sys.exit(1) if args[0] not in all_devices: interface = None else: interface = args[0] args = args[1:] if o in ('-K', '--offload'): cmd = set_offload elif o in ('-C', '--coalesce'): cmd = set_coalesce elif o in ('-G', '--set-ring'): cmd = set_ringparam run_cmd(cmd, interface, args) break if __name__ == '__main__': main() python-ethtool-0.14/scripts/pifconfig000077500000000000000000000060701334642534600200310ustar00rootroot00000000000000#! /usr/bin/python # -*- python -*- # -*- coding: utf-8 -*- # Copyright (C) 2008 Red Hat Inc. # # Arnaldo Carvalho de Melo # # This application is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; version 2. # # This application is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. from __future__ import unicode_literals, print_function import ethtool import sys from optparse import OptionParser def flags2str(flags): string = '' if flags & ethtool.IFF_UP: string += 'UP ' if flags & ethtool.IFF_BROADCAST: string += 'BROADCAST ' if flags & ethtool.IFF_DEBUG: string += 'DEBUG ' if flags & ethtool.IFF_LOOPBACK: string += 'LOOPBACK ' if flags & ethtool.IFF_POINTOPOINT: string += 'POINTOPOINT ' if flags & ethtool.IFF_NOTRAILERS: string += 'NOTRAILERS ' if flags & ethtool.IFF_RUNNING: string += 'RUNNING ' if flags & ethtool.IFF_NOARP: string += 'NOARP ' if flags & ethtool.IFF_PROMISC: string += 'PROMISC ' if flags & ethtool.IFF_ALLMULTI: string += 'ALLMULTI ' if flags & ethtool.IFF_MASTER: string += 'MASTER ' if flags & ethtool.IFF_SLAVE: string += 'SLAVE ' if flags & ethtool.IFF_MULTICAST: string += 'MULTICAST ' if flags & ethtool.IFF_PORTSEL: string += 'PORTSEL ' if flags & ethtool.IFF_AUTOMEDIA: string += 'AUTOMEDIA ' if flags & ethtool.IFF_DYNAMIC: string += 'DYNAMIC ' return string.strip() def show_config(device): ipaddr = ethtool.get_ipaddr(device) netmask = ethtool.get_netmask(device) flags = ethtool.get_flags(device) print('%s' % device) if not (flags & ethtool.IFF_LOOPBACK): print('\tHWaddr %s' % ethtool.get_hwaddr(device)) print('\tinet addr:%s' % ipaddr) if not (flags & (ethtool.IFF_LOOPBACK | ethtool.IFF_POINTOPOINT)): print('\tBcast:%s' % ethtool.get_broadcast(device)) print('\tMask:%s' % netmask) for info in ethtool.get_interfaces_info(device): for addr in info.get_ipv6_addresses(): print('\tinet6 addr: %s/%s Scope: %s' % (addr.address, addr.netmask, addr.scope)) print('\t%s\n' % flags2str(flags)) print def main(): usage = 'usage: %prog [interface [interface [interface] ...]]' parser = OptionParser(usage=usage) (opts, args) = parser.parse_args() if args is None or len(args) == 0: sel_devs = ethtool.get_active_devices() else: sel_devs = args for device in sel_devs: try: show_config(device) except Exception as ex: print('** ERROR ** [Device %s]: %s' % (device, str(ex))) sys.exit(2) if __name__ == '__main__': main() python-ethtool-0.14/setup.py000066400000000000000000000112411334642534600161560ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- from __future__ import print_function from setuptools import setup, Extension import sys from io import open try: import commands except ImportError: import subprocess as commands version = '0.14' class PkgConfigExtension(Extension): '''Extension with lazy properties taken from pkg-config''' def __init__(self, *args, **kwargs): '''Behaves like Extension's __init__ but you should not use include_dirs, library_dirs and libraries arguments. Extra arguments: pkg : string The name of the pkg-config package to use for querying extra_libraris : [string] This will be added to the libraries attribute. Optional. ''' self._pkg = kwargs['pkg'] del kwargs['pkg'] if 'extra_libraries' in kwargs: self._extra_libraries = kwargs['extra_libraries'] del kwargs['extra_libraries'] else: self._extra_libraries = [] Extension.__init__(self, *args, **kwargs) try: # on Python 2 we need to delete those now del self.include_dirs del self.library_dirs del self.libraries except AttributeError: # on Python 3, that's not needed or possible pass @classmethod def _str2list(cls, pkgstr, onlystr): res = [] for l in pkgstr.split(" "): if l.find(onlystr) == 0: res.append(l.replace(onlystr, "", 1)) return res @classmethod def _run(cls, command_string): res, output = commands.getstatusoutput(command_string) if res != 0: print('Failed to query %s' % command_string) sys.exit(1) return output @property def include_dirs(self): includes = self._run('pkg-config --cflags-only-I %s' % self._pkg) return self._str2list(includes, '-I') @property def library_dirs(self): libdirs = self._run('pkg-config --libs-only-L %s' % self._pkg) return self._str2list(libdirs, '-L') @property def libraries(self): libs = self._run('pkg-config --libs-only-l %s' % self._pkg) return self._str2list(libs, '-l') + self._extra_libraries @include_dirs.setter def include_dirs(self, value): pass @library_dirs.setter def library_dirs(self, value): pass @libraries.setter def libraries(self, value): pass with open('README.rst', encoding='utf-8') as f: long_description = f.read() with open('CHANGES.rst', encoding='utf-8') as f: long_description += '\n\n' long_description += f.read() setup(name='ethtool', version=version, description='Python module to interface with ethtool', long_description=long_description, author='Harald Hoyer, Arnaldo Carvalho de Melo, David Sommerseth', author_email='davids@redhat.com', maintainer='Lumír Balhar, Miro Hrončok, Charalampos Stratakis, Sanqui', maintainer_email='python-maint@redhat.com', url='https://github.com/fedora-python/python-ethtool', license='GPL-2.0', keywords='network networking ethernet tool ethtool', classifiers=[ 'Development Status :: 7 - Inactive', 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', 'Operating System :: POSIX :: Linux', 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: Implementation :: CPython', 'Topic :: Software Development :: Libraries', 'Topic :: System :: Networking', ], scripts=[ 'scripts/pethtool', 'scripts/pifconfig' ], ext_modules=[ PkgConfigExtension( 'ethtool', sources=[ 'python-ethtool/ethtool.c', 'python-ethtool/etherinfo.c', 'python-ethtool/etherinfo_obj.c', 'python-ethtool/netlink.c', 'python-ethtool/netlink-address.c'], extra_compile_args=[ '-fno-strict-aliasing', '-Wno-unused-function'], define_macros=[('VERSION', '"%s"' % version)], pkg='libnl-3.0', extra_libraries=['nl-route-3'], ) ] ) python-ethtool-0.14/tests/000077500000000000000000000000001334642534600156075ustar00rootroot00000000000000python-ethtool-0.14/tests/__init__.py000066400000000000000000000000001334642534600177060ustar00rootroot00000000000000python-ethtool-0.14/tests/parse_ifconfig.py000066400000000000000000001073671334642534600211550ustar00rootroot00000000000000# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # Copyright (c) 2012 Red Hat, Inc. All rights reserved. # # This copyrighted material is made available to anyone wishing # to use, modify, copy, or redistribute it subject to the terms # and conditions of the GNU General Public License version 2. # # This program is distributed in the hope that it will be # useful, but WITHOUT ANY WARRANTY; without even the implied # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR # PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public # License along with this program; if not, write to the Free # Software Foundation, Inc., 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. # # Author: Dave Malcolm # # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Screenscraper for the output of "ifconfig" # The relevant sources for ifconfig can be found in e.g.: # net-tools-1.60/lib/interface.c # within ife_print_long() import os import re from subprocess import Popen, PIPE import unittest __all__ = ['IfConfig'] # any whitespace: ws = '\s+' # any non-whitespace, as a delimited group: group_nonws = '(\S+)' # a decimal number, as a delimited group: group_dec = '([0-9]+)' # hexadecimal number of the form "0xf2600000" group_o_hex = '0x([0-9a-f]+)' # hexadecimal number without the "0x" prefix, e.g. "f2600000" group_hex = '([0-9a-f]+)' dot = r'\.' dec = '[0-9]+' group_ip4addr = ('(' + dec + dot + dec + dot + dec + dot + dec + ')') def parse_ip4addr(addr): import socket return (socket.inet_aton(addr)) class IfConfig: """ Wrapper around a single invocation of "ifconfig" """ def __init__(self, stdout=None, debug=False): if stdout is not None: self.stdout = stdout self.stderr = '' else: env = os.environ.copy() env.update(LANG='C.utf8') p = Popen('ifconfig', stdout=PIPE, stderr=PIPE, env=env, universal_newlines=True) self.stdout, self.stderr = p.communicate() if self.stderr != '': raise ValueError( 'stderr from ifconfig was nonempty:\n%s' % self.stderr) if 0: print('self.stdout: %r' % self.stdout) self.devices = [] curdev = None for line in self.stdout.splitlines(): if 0: print('line: %r' % line) if line == '': continue # Start of a device entry, e.g: # 'lo: flags=73 mtu 16436' # old ifconfig format: # 'lo Link encap:Local Loopback' m = re.match(r'(\w+): (.+)', line) mo = re.match(r'(\w+)\s+(.+)', line) if m: self.oldFormat = False devname = m.group(1) curdev = Device(devname, debug) self.devices.append(curdev) curdev._parse_rest_of_first_line(m.group(2)) continue if mo: self.oldFormat = True devname = mo.group(1) curdev = Device(devname, debug) self.devices.append(curdev) curdev._parse_rest_of_first_line_old(mo.group(2)) continue # If we don't have current device yet, doesn't make sense to # read the rest of output lines if curdev is None: continue if self.oldFormat: curdev._parse_line_old(line) else: curdev._parse_line(line) def get_device_by_name(self, devname): for dev in self.devices: if dev.name == devname: return dev raise ValueError('device not found: %r' % devname) class Device: """ Wrapper around a device entry within the output of "ifconfig" """ def __init__(self, name, debug=False): self.name = name self.debug = debug self.flagsint = None self.flagsstr = None self.mtu = None self.metric = None self.outfill = None self.keepalive = None self.inet = None self.netmask = None self.broadcast = None self.destination = None self.inet6 = None self.prefixlen = None self.scopeid = None self.hwname = None self.hwaddr = None self.txqueuelen = None self.hwtitle = None self.rxpackets = None self.rxbytes = None self.rxerrors = None self.rxdropped = None self.rxoverruns = None self.rxframe = None self.rxcompressed = None self.txpackets = None self.txbytes = None self.txerrors = None self.txdropped = None self.txoverruns = None self.txcarrier = None self.txcollisions = None self.txcompressed = None self.interrupt = None self.baseaddr = None self.memstart = None self.memend = None self.dma = None def get_netmask_bits(self): # Convert a dotted netmask string to a bitcount int # e.g. from "255.255.252.0" to 22: if not self.netmask: return 0 packed = parse_ip4addr(self.netmask) # count bits in "packed": result = 0 for ch in packed: ch = ord(ch) if isinstance(ch, str) else ch while ch: if ch & 1: result += 1 ch //= 2 return result def __repr__(self): return ('Device(name=%(name)r, flagsint=%(flagsint)r, ' 'flagsstr=%(flagsstr)r, mtu=%(mtu)r)' % (self.__dict__)) def _debug(self, groups): if self.debug: print('groups: %r' % (groups,)) def _parse_rest_of_first_line(self, text): m = re.match(r'flags=([0-9]+)<(.*)> mtu ([0-9]+)(.*)', text) if not m: raise ValueError('unable to parse: %r' % text) self._debug(m.groups()) self.flagsint = int(m.group(1)) self.flagsstr = m.group(2) self.mtu = int(m.group(3)) # It might have " outfill %d keepalive %d": m = re.match(ws + 'outfill' + ws + group_dec + ws + 'keepalive' + ws + group_dec, m.group(4)) if m: self._debug(m.groups()) self.outfill = int(m.group(1)) self.keepalive = int(m.group(2)) def _parse_rest_of_first_line_old(self, text): m = re.match('Link encap:(\w+ ?\w*)\s*(HWaddr )?(\S*)', text) if not m: raise ValueError('unable to parse: %r' % text) self.hwtitle = m.group(1).strip() if m.group(2): self.hwaddr = m.group(3) def _parse_line(self, line): m = re.match(ws + 'inet ' + group_ip4addr + ws + 'netmask ' + group_ip4addr + '(.*)', line) if m: self._debug(m.groups()) self.inet = m.group(1) self.netmask = m.group(2) # "broadcast" and "destination" are both optional: line = m.group(3) m = re.match(ws + 'broadcast ' + group_ip4addr + '(.*)', line) if m: self.broadcast = m.group(1) line = m.group(2) m = re.match(ws + 'destination ' + group_nonws, line) if m: self.destination = m.group(1) return m = re.match(ws + 'inet6 ' + group_nonws + ws + 'prefixlen' + ws + group_dec + ws + 'scopeid ' + group_nonws, line) if m: self._debug(m.groups()) self.inet6 = m.group(1) self.prefixlen = int(m.group(2)) self.scopeid = m.group(3) return # e.g. (with hwaddr): # ' ether ff:00:11:22:33:42 txqueuelen 1000 (Ethernet)' m = re.match(ws + group_nonws + ws + group_nonws + ws + 'txqueuelen' + ws + group_dec + ws + '\((.*)\)', line) if m: self._debug(m.groups()) self.hwname = m.group(1) self.hwaddr = m.group(2) self.txqueuelen = int(m.group(3)) self.hwtitle = m.group(4) return # e.g. (without hwaddr): # ' loop txqueuelen 0 (Local Loopback)' m = re.match(ws + group_nonws + ws + 'txqueuelen' + ws + group_dec + ws + '\((.*)\)', line) if m: self._debug(m.groups()) self.hwname = m.group(1) self.hwaddr = None self.txqueuelen = int(m.group(2)) self.hwtitle = m.group(3) return # e.g. ' RX packets 5313261 bytes 6062336615 (5.6 GiB)' m = re.match(ws + 'RX packets ' + group_dec + ws + 'bytes ' + group_dec + ws + '\(.*\)', line) if m: self._debug(m.groups()) self.rxpackets = int(m.group(1)) self.rxbytes = int(m.group(2)) return # e.g. ' RX errors 0 dropped 0 overruns 0 frame 0' m = re.match(ws + 'RX errors ' + group_dec + ws + 'dropped ' + group_dec + ws + 'overruns ' + group_dec + ws + 'frame ' + group_dec, line) if m: self._debug(m.groups()) self.rxerrors = int(m.group(1)) self.rxdropped = int(m.group(2)) self.rxoverruns = int(m.group(3)) self.rxframe = int(m.group(4)) return # e.g. ' TX packets 2949524 bytes 344092625 (328.1 MiB)' m = re.match(ws + 'TX packets ' + group_dec + ws + 'bytes ' + group_dec + ws + '\(.*\)', line) if m: self._debug(m.groups()) self.txpackets = int(m.group(1)) self.txbytes = int(m.group(2)) return # e.g. ' TX errors 0 dropped 0 overruns 0 carrier 0 # collisions 0' m = re.match(ws + 'TX errors ' + group_dec + ws + 'dropped ' + group_dec + ws + 'overruns ' + group_dec + ws + 'carrier ' + group_dec + ws + 'collisions ' + group_dec, line) if m: self._debug(m.groups()) self.txerrors = int(m.group(1)) self.txdropped = int(m.group(2)) self.txoverruns = int(m.group(3)) self.txcarrier = int(m.group(4)) self.txcollisions = int(m.group(5)) return # e.g.' device interrupt 20 memory 0xf2600000-f2620000 ' m = re.match(ws + 'device' + ws + '(.*)', line) if m: self._debug(m.groups()) line = m.group(1) m = re.match('interrupt ' + group_dec + ws + '(.*)', line) if m: self.interrupt = int(m.group(1)) line = m.group(2) m = re.match('base ' + group_o_hex + ws + '(.*)', line) if m: self.baseaddr = int(m.group(1), 16) line = m.group(2) m = re.match('memory ' + group_o_hex + '-' + group_hex + ws + '(.*)', line) if m: self.memstart = int(m.group(1), 16) self.memend = int(m.group(2), 16) line = m.group(3) m = re.match('dma ' + group_o_hex, line) if m: self.dma = int(m.group(1), 16) return raise ValueError('parser could not handle line: %r' % line) def _parse_line_old(self, line): m = re.match(ws + 'inet addr:' + group_ip4addr + '(.*)', line) if m: self._debug(m.groups()) self.inet = m.group(1) # "destination (P-t-P)" and "Bcast" are both optional: line = m.group(2) m = re.match(ws + 'P-t-P:' + group_ip4addr + '(.*)', line) if m: self.destination = m.group(1) line = m.group(2) m = re.match(ws + 'Bcast:' + group_ip4addr + '(.*)', line) if m: self.broadcast = m.group(1) line = m.group(2) m = re.match(ws + 'Mask:' + group_ip4addr, line) if m: self.netmask = m.group(1) return m = re.match(ws + 'inet6 addr: ' + group_nonws + '/' + group_dec + ws + 'Scope:' + group_nonws, line) if m: self._debug(m.groups()) self.inet6 = m.group(1) self.prefixlen = int(m.group(2)) self.scopeid = m.group(3) return # UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 m = re.match(ws + '(.*)' + ' MTU:' + group_dec + ws + 'Metric:' + group_dec + '(.*)', line) if m: self._debug(m.groups()) self.flagsstr = m.group(1) self.mtu = int(m.group(2)) self.metric = int(m.group(3)) # It might have " Outfill:%d Keepalive:%d": m = re.match(ws + 'Outfill:' + group_dec + ws + 'Keepalive:' + group_dec, m.group(4)) if m: self._debug(m.groups()) self.outfill = int(m.group(1)) self.keepalive = int(m.group(2)) return # RX packets:4458926 errors:0 dropped:0 overruns:0 frame:0 m = re.match(ws + 'RX packets:' + group_dec + ws + 'errors:' + group_dec + ws + 'dropped:' + group_dec + ws + 'overruns:' + group_dec + ws + 'frame:' + group_dec, line) if m: self._debug(m.groups()) self.rxpackets = int(m.group(1)) self.rxerrors = int(m.group(2)) self.rxdropped = int(m.group(3)) self.rxoverruns = int(m.group(4)) self.rxframe = int(m.group(5)) return # " compressed:%lu\n" m = re.match(ws + 'compressed:' + group_dec, line) if m: self.rxcompressed = int(m.group(1)) return # TX packets:3536982 errors:0 dropped:0 overruns:0 carrier:0 m = re.match(ws + 'TX packets:' + group_dec + ws + 'errors:' + group_dec + ws + 'dropped:' + group_dec + ws + 'overruns:' + group_dec + ws + 'carrier:' + group_dec, line) if m: self._debug(m.groups()) self.txpackets = int(m.group(1)) self.txerrors = int(m.group(2)) self.txdropped = int(m.group(3)) self.txoverruns = int(m.group(4)) self.txcarrier = int(m.group(5)) return # " collisions:%lu compressed:%lu txqueuelen:%d " m = re.match(ws + 'collisions:' + group_dec + ws + '(.*)', line) if m: self._debug(m.groups()) self.txcollisions = int(m.group(1)) line = m.group(2) m = re.match('compressed:' + group_dec + ws + '(.*)', line) if m: self.txcompressed = int(m.group(1)) line = m.group(2) m = re.match('txqueuelen:' + group_dec, line) if m: self.txqueuelen = int(m.group(1)) return # RX bytes:3380060233 (3.1 GiB) TX bytes:713438255 (680.3 MiB) m = re.match(ws + 'RX bytes:' + group_dec + ws + '\(.*\)' + ws + 'TX bytes:' + group_dec + ws + '\(.*\)', line) if m: self._debug(m.groups()) self.rxbytes = int(m.group(1)) self.txbytes = int(m.group(2)) return # Interrupt:17 Memory:da000000-da012800 m = re.match(ws + 'Interrupt:' + group_dec + '\s*(.*)', line) if m: self._debug(m.groups()) self.interrupt = int(m.group(1)) line = m.group(2) m = re.match('Base address:' + group_o_hex + '\s*(.*)', line) if m: self._debug(m.groups()) self.baseaddr = int(m.group(1), 16) line = m.group(2) m = re.match('Memory:' + group_hex + '-' + group_hex + '\s*(.*)', line) if m: self._debug(m.groups()) self.memstart = int(m.group(1), 16) self.memend = int(m.group(2), 16) line = m.group(3) m = re.match('DMA chan:' + group_hex, line) if m: self._debug(m.groups()) self.dma = int(m.group(1), 16) return # ifconfig = IfConfig() # for dev in ifconfig.devices: # print(dev) class ParserTests(unittest.TestCase): def test_full(self): # Parse a complex pre-canned output from ifconfig # This is the output of "ifconfig" on this machine, sanitized # to remove stuff that identifies it full = ''' eth1: flags=4163 mtu 1500 inet 1.12.123.124 netmask 255.255.252.0 broadcast 1.12.123.255 inet6 ffff::ffff:ffff:ffff:ffff prefixlen 64 scopeid 0x20 ether ff:00:11:22:33:42 txqueuelen 1000 (Ethernet) RX packets 5329294 bytes 6074440831 (5.6 GiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 2955574 bytes 344607935 (328.6 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 ''' + ' device interrupt 20 memory 0xf2600000-f2620000 ' + ''' lo: flags=73 mtu 16436 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10 loop txqueuelen 0 (Local Loopback) RX packets 1562620 bytes 524530977 (500.2 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 1562620 bytes 524530977 (500.2 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 virbr0: flags=4163 mtu 1500 inet 1.12.123.124 netmask 255.255.252.0 broadcast 1.12.123.255 ether ff:00:11:22:33:42 txqueuelen 0 (Ethernet) RX packets 88730 bytes 5140566 (4.9 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 177583 bytes 244647206 (233.3 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 vnet0: flags=4163 mtu 1500 inet6 ffff::ffff:ffff:ffff:ffff prefixlen 64 scopeid 0x20 ether ff:00:11:22:33:42 txqueuelen 0 (Ethernet) RX packets 538 bytes 172743 (168.6 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 26593 bytes 1379054 (1.3 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 vnet1: flags=4163 mtu 1500 inet6 ffff::ffff:ffff:ffff:ffff prefixlen 64 scopeid 0x20 ether ff:00:11:22:33:42 txqueuelen 0 (Ethernet) RX packets 71567 bytes 5033151 (4.7 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 216553 bytes 200424748 (191.1 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 ''' ifconfig = IfConfig(stdout=full) self.assertEqual(len(ifconfig.devices), 5) # Verify eth1: eth1 = ifconfig.devices[0] # eth1: flags=4163 mtu 1500 self.assertEqual(eth1.name, 'eth1') self.assertEqual(eth1.flagsint, 4163) self.assertEqual(eth1.flagsstr, 'UP,BROADCAST,RUNNING,MULTICAST') self.assertEqual(eth1.mtu, 1500) # inet 1.12.123.124 netmask 255.255.252.0 broadcast 1.12.123.255 self.assertEqual(eth1.inet, '1.12.123.124') self.assertEqual(eth1.netmask, '255.255.252.0') self.assertEqual(eth1.broadcast, '1.12.123.255') # inet6 ffff::ffff:ffff:ffff:ffff prefixlen 64 scopeid 0x20 self.assertEqual(eth1.inet6, 'ffff::ffff:ffff:ffff:ffff') self.assertEqual(eth1.prefixlen, 64) self.assertEqual(eth1.scopeid, '0x20') # ether ff:00:11:22:33:42 txqueuelen 1000 (Ethernet) self.assertEqual(eth1.hwname, 'ether') self.assertEqual(eth1.hwaddr, 'ff:00:11:22:33:42') self.assertEqual(eth1.txqueuelen, 1000) self.assertEqual(eth1.hwtitle, 'Ethernet') # RX packets 5329294 bytes 6074440831 (5.6 GiB) self.assertEqual(eth1.rxpackets, 5329294) self.assertEqual(eth1.rxbytes, 6074440831) # RX errors 0 dropped 0 overruns 0 frame 0 self.assertEqual(eth1.rxerrors, 0) self.assertEqual(eth1.rxdropped, 0) self.assertEqual(eth1.rxoverruns, 0) self.assertEqual(eth1.rxframe, 0) # TX packets 2955574 bytes 344607935 (328.6 MiB) self.assertEqual(eth1.txpackets, 2955574) self.assertEqual(eth1.txbytes, 344607935) # TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 self.assertEqual(eth1.txerrors, 0) self.assertEqual(eth1.txdropped, 0) self.assertEqual(eth1.txoverruns, 0) self.assertEqual(eth1.txcarrier, 0) self.assertEqual(eth1.txcollisions, 0) # device interrupt 20 memory 0xf2600000-f2620000 self.assertEqual(eth1.interrupt, 20) # Verify lo: lo = ifconfig.devices[1] self.assertEqual(lo.name, 'lo') # lo: flags=73 mtu 16436 self.assertEqual(lo.flagsint, 73) self.assertEqual(lo.flagsstr, 'UP,LOOPBACK,RUNNING') self.assertEqual(lo.mtu, 16436) # inet 127.0.0.1 netmask 255.0.0.0 self.assertEqual(lo.inet, '127.0.0.1') self.assertEqual(lo.netmask, '255.0.0.0') self.assertEqual(lo.broadcast, None) # inet6 ::1 prefixlen 128 scopeid 0x10 self.assertEqual(lo.inet6, '::1') self.assertEqual(lo.prefixlen, 128) self.assertEqual(lo.scopeid, '0x10') # loop txqueuelen 0 (Local Loopback) self.assertEqual(lo.hwname, 'loop') self.assertEqual(lo.txqueuelen, 0) self.assertEqual(lo.hwtitle, 'Local Loopback') # RX packets 1562620 bytes 524530977 (500.2 MiB) # RX errors 0 dropped 0 overruns 0 frame 0 # TX packets 1562620 bytes 524530977 (500.2 MiB) # TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 # Verify virbr0: virbr0 = ifconfig.devices[2] self.assertEqual(virbr0.name, 'virbr0') # virbr0: flags=4163 mtu 1500 # inet 1.12.123.124 netmask 255.255.252.0 broadcast 1.12.123.255 # ether ff:00:11:22:33:42 txqueuelen 0 (Ethernet) # RX packets 88730 bytes 5140566 (4.9 MiB) # RX errors 0 dropped 0 overruns 0 frame 0 # TX packets 177583 bytes 244647206 (233.3 MiB) # TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 # Verify vnet0: vnet0 = ifconfig.devices[3] self.assertEqual(vnet0.name, 'vnet0') # vnet0: flags=4163 mtu 1500 # inet6 ffff::ffff:ffff:ffff:ffff prefixlen 64 scopeid 0x20 # ether ff:00:11:22:33:42 txqueuelen 0 (Ethernet) # RX packets 538 bytes 172743 (168.6 KiB) # RX errors 0 dropped 0 overruns 0 frame 0 # TX packets 26593 bytes 1379054 (1.3 MiB) # TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 # Verify vnet1: vnet1 = ifconfig.devices[4] self.assertEqual(vnet1.name, 'vnet1') # vnet1: flags=4163 mtu 1500 # inet6 ffff::ffff:ffff:ffff:ffff prefixlen 64 scopeid 0x20 # ether ff:00:11:22:33:42 txqueuelen 0 (Ethernet) # RX packets 71567 bytes 5033151 (4.7 MiB) # RX errors 0 dropped 0 overruns 0 frame 0 # TX packets 216553 bytes 200424748 (191.1 MiB) # TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 fullOld = ''' eth0 Link encap:Ethernet HWaddr 00:11:22:33:44:55 inet addr:1.12.123.124 Bcast:1.12.123.255 Mask:255.255.252.0 inet6 addr: dddd::dddd:dddd:dddd:dddd:dddd:dddd/64 Scope:Site inet6 addr: eeee::eeee:eeee:eeee:eeee:eeee:eeee/64 Scope:Global inet6 addr: ffff::ffff:ffff:ffff:ffff/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:4458926 errors:0 dropped:0 overruns:0 frame:0 TX packets:3536982 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:3380060233 (3.1 GiB) TX bytes:713438255 (680.3 MiB) Interrupt:17 Memory:da000000-da012800 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:805234 errors:0 dropped:0 overruns:0 frame:0 TX packets:805234 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:132177529 (126.0 MiB) TX bytes:132177529 (126.0 MiB) ''' ifconfig = IfConfig(stdout=fullOld) self.assertEqual(len(ifconfig.devices), 2) # Verify eth0: eth0 = ifconfig.devices[0] # eth0 Link encap:Ethernet HWaddr 00:11:22:33:44:55 self.assertEqual(eth0.name, 'eth0') self.assertEqual(eth0.hwtitle, 'Ethernet') self.assertEqual(eth0.hwaddr, '00:11:22:33:44:55') # inet addr:1.12.123.124 Bcast:1.12.123.255 Mask:255.255.252.0 self.assertEqual(eth0.inet, '1.12.123.124') self.assertEqual(eth0.netmask, '255.255.252.0') self.assertEqual(eth0.broadcast, '1.12.123.255') # inet6 addr: dddd::dddd:dddd:dddd:dddd:dddd:dddd/64 Scope:Site # self.assertEqual(eth0.inet6, 'dddd::dddd:dddd:dddd:dddd:dddd:dddd') # self.assertEqual(eth0.prefixlen, 64) # self.assertEqual(eth0.scopeid, 'Site') # inet6 addr: eeee::eeee:eeee:eeee:eeee:eeee:eeee/64 Scope:Global # self.assertEqual(eth0.inet6, 'eeee::eeee:eeee:eeee:eeee:eeee:eeee') # self.assertEqual(eth0.prefixlen, 64) # self.assertEqual(eth0.scopeid, 'Global') # inet6 addr: ffff::ffff:ffff:ffff:ffff/64 Scope:Link self.assertEqual(eth0.inet6, 'ffff::ffff:ffff:ffff:ffff') self.assertEqual(eth0.prefixlen, 64) self.assertEqual(eth0.scopeid, 'Link') # UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 self.assertEqual(eth0.flagsstr, 'UP BROADCAST RUNNING MULTICAST') self.assertEqual(eth0.mtu, 1500) self.assertEqual(eth0.metric, 1) # RX packets:4458926 errors:0 dropped:0 overruns:0 frame:0 self.assertEqual(eth0.rxpackets, 4458926) self.assertEqual(eth0.rxerrors, 0) self.assertEqual(eth0.rxdropped, 0) self.assertEqual(eth0.rxoverruns, 0) self.assertEqual(eth0.rxframe, 0) # TX packets:3536982 errors:0 dropped:0 overruns:0 carrier:0 self.assertEqual(eth0.txpackets, 3536982) self.assertEqual(eth0.txerrors, 0) self.assertEqual(eth0.txdropped, 0) self.assertEqual(eth0.txoverruns, 0) self.assertEqual(eth0.txcarrier, 0) # collisions:0 txqueuelen:1000 self.assertEqual(eth0.txcollisions, 0) self.assertEqual(eth0.txqueuelen, 1000) # RX bytes:3380060233 (3.1 GiB) TX bytes:713438255 (680.3 MiB) self.assertEqual(eth0.rxbytes, 3380060233) self.assertEqual(eth0.txbytes, 713438255) # Interrupt:17 Memory:da000000-da012800 self.assertEqual(eth0.interrupt, 17) self.assertEqual(eth0.memstart, 0xda000000) self.assertEqual(eth0.memend, 0xda012800) # Verify lo: lo = ifconfig.devices[1] # lo Link encap:Local Loopback self.assertEqual(lo.name, 'lo') self.assertEqual(lo.hwtitle, 'Local Loopback') self.assertEqual(lo.hwaddr, None) # inet addr:127.0.0.1 Mask:255.0.0.0 self.assertEqual(lo.inet, '127.0.0.1') self.assertEqual(lo.netmask, '255.0.0.0') self.assertEqual(lo.broadcast, None) # inet6 addr: ::1/128 Scope:Host self.assertEqual(lo.inet6, '::1') self.assertEqual(lo.prefixlen, 128) self.assertEqual(lo.scopeid, 'Host') # UP LOOPBACK RUNNING MTU:16436 Metric:1 self.assertEqual(lo.flagsstr, 'UP LOOPBACK RUNNING') self.assertEqual(lo.mtu, 16436) self.assertEqual(lo.metric, 1) # RX packets:805234 errors:0 dropped:0 overruns:0 frame:0 self.assertEqual(lo.rxpackets, 805234) # TX packets:805234 errors:0 dropped:0 overruns:0 carrier:0 self.assertEqual(lo.txpackets, 805234) # collisions:0 txqueuelen:0 # RX bytes:132177529 (126.0 MiB) TX bytes:132177529 (126.0 MiB) self.assertEqual(lo.rxbytes, 132177529) self.assertEqual(lo.txbytes, 132177529) def parse_single_device(self, stdout, debug=False): ifconfig = IfConfig(stdout, debug) self.assertEqual(len(ifconfig.devices), 1) return ifconfig.devices[0] def test_parsing_flags_line(self): dev = self.parse_single_device( 'foo: flags=4163 mtu 1500\n') self.assertEqual(dev.name, 'foo') self.assertEqual(dev.flagsint, 4163) self.assertEqual(dev.flagsstr, 'UP,BROADCAST,RUNNING,MULTICAST') self.assertEqual(dev.mtu, 1500) dev = self.parse_single_device( 'foo: flags=4163 mtu 1500 ' 'outfill 32 keepalive 96\n') self.assertEqual(dev.mtu, 1500) self.assertEqual(dev.outfill, 32) self.assertEqual(dev.keepalive, 96) # old format dev = self.parse_single_device( 'foo Link encap:Ethernet HWaddr F0:F0:F0:F0:F0:F0\n' ' UP BROADCAST RUNNING MULTICAST MTU:500 Metric:2 ' 'Outfill:55 Keepalive:66\n') self.assertEqual(dev.flagsstr, 'UP BROADCAST RUNNING MULTICAST') self.assertEqual(dev.mtu, 500) self.assertEqual(dev.metric, 2) self.assertEqual(dev.outfill, 55) self.assertEqual(dev.keepalive, 66) def test_parsing_ip(self): dev = self.parse_single_device( 'foo: flags=4163 mtu 1500\n' ' inet 1.12.123.124 netmask 255.255.252.0 broadcast ' '1.12.123.255\n') self.assertEqual(dev.inet, '1.12.123.124') self.assertEqual(dev.netmask, '255.255.252.0') self.assertEqual(dev.get_netmask_bits(), 22) self.assertEqual(dev.broadcast, '1.12.123.255') self.assertEqual(dev.destination, None) dev = self.parse_single_device( 'lo: flags=73 mtu 16436\n' ' inet 127.0.0.1 netmask 255.0.0.0\n') self.assertEqual(dev.inet, '127.0.0.1') self.assertEqual(dev.netmask, '255.0.0.0') self.assertEqual(dev.get_netmask_bits(), 8) self.assertEqual(dev.broadcast, None) self.assertEqual(dev.destination, None) dev = self.parse_single_device( 'foo: flags=4163 mtu 1500\n' ' inet 1.1.1.1 netmask 255.255.255.254 destination ' '1.12.123.255\n') self.assertEqual(dev.inet, '1.1.1.1') self.assertEqual(dev.netmask, '255.255.255.254') self.assertEqual(dev.broadcast, None) self.assertEqual(dev.destination, '1.12.123.255') # old format dev = self.parse_single_device( 'foo Link encap:Ethernet HWaddr F0:F0:F0:F0:F0:F0\n' ' inet addr:1.2.3.4 P-t-P:10.20.30.40 ' 'Mask:255.255.254.0\n') self.assertEqual(dev.inet, '1.2.3.4') self.assertEqual(dev.destination, '10.20.30.40') self.assertEqual(dev.broadcast, None) self.assertEqual(dev.get_netmask_bits(), 23) self.assertEqual(dev.netmask, '255.255.254.0') def test_parsing_device_line(self): dev = self.parse_single_device( 'foo: flags=4163 mtu 1500\n' ' device interrupt 20 memory 0xf2600000-f2620000 \n') self.assertEqual(dev.interrupt, 20) self.assertEqual(dev.baseaddr, None) self.assertEqual(dev.memstart, 0xf2600000) self.assertEqual(dev.memend, 0xf2620000) self.assertEqual(dev.dma, None) # but the fields in the "device" field are optional: dev = self.parse_single_device( 'foo: flags=4163 mtu 1500\n' ' device \n') self.assertEqual(dev.interrupt, None) self.assertEqual(dev.baseaddr, None) self.assertEqual(dev.memstart, None) self.assertEqual(dev.memend, None) self.assertEqual(dev.dma, None) dev = self.parse_single_device( 'foo: flags=4163 mtu 1500\n' ' device memory 0xf2600000-f2620000 \n') self.assertEqual(dev.interrupt, None) self.assertEqual(dev.baseaddr, None) self.assertEqual(dev.memstart, 0xf2600000) self.assertEqual(dev.memend, 0xf2620000) self.assertEqual(dev.dma, None) # and there could potentially be "base" and "dma" fields: dev = self.parse_single_device( 'foo: flags=4163 mtu 1500\n' ' device base 0xdeadbeef \n') self.assertEqual(dev.interrupt, None) self.assertEqual(dev.baseaddr, 0xdeadbeef) self.assertEqual(dev.memstart, None) self.assertEqual(dev.memend, None) self.assertEqual(dev.dma, None) dev = self.parse_single_device( 'foo: flags=4163 mtu 1500\n' ' device interrupt 20 dma 0xbad4f00d\n') self.assertEqual(dev.interrupt, 20) self.assertEqual(dev.baseaddr, None) self.assertEqual(dev.memstart, None) self.assertEqual(dev.memend, None) self.assertEqual(dev.dma, 0xbad4f00d) # old format dev = self.parse_single_device( 'foo Link encap:Ethernet HWaddr F0:F0:F0:F0:F0:F0\n' ' Interrupt:20 Base address:0xdeadbeef DMA chan:bad4f00d\n' ' collisions:13 compressed:11 \n') self.assertEqual(dev.interrupt, 20) self.assertEqual(dev.baseaddr, 0xdeadbeef) self.assertEqual(dev.dma, 0xbad4f00d) self.assertEqual(dev.txcollisions, 13) self.assertEqual(dev.txcompressed, 11) def test_parse_ip4addr(self): self.assertEqual(parse_ip4addr('1.1.1.1'), b'\x01\x01\x01\x01') self.assertEqual(parse_ip4addr('127.0.0.1'), b'\x7f\x00\x00\x01') def test_local(self): # Actually invoke ifconfig locally, and parse whatever it emits: IfConfig() if __name__ == '__main__': unittest.main() python-ethtool-0.14/tests/test_ethtool.py000077500000000000000000000235211334642534600207040ustar00rootroot00000000000000# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # Copyright (c) 2011, 2012, 2013 Red Hat, Inc. All rights reserved. # # This copyrighted material is made available to anyone wishing # to use, modify, copy, or redistribute it subject to the terms # and conditions of the GNU General Public License version 2. # # This program is distributed in the hope that it will be # useful, but WITHOUT ANY WARRANTY; without even the implied # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR # PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public # License along with this program; if not, write to the Free # Software Foundation, Inc., 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. # # Author: Dave Malcolm # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ import unittest import ethtool from .parse_ifconfig import IfConfig INVALID_DEVICE_NAME = "I am not a valid device name" # Screenscrape the output from "ifconfig". We will use this below to validate # the results from the "ethtool" module: ifconfig = IfConfig() for dev in ifconfig.devices: print(dev) class EthtoolTests(unittest.TestCase): # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # asserts # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def assertIsString(self, value): self.assertTrue(isinstance(value, str)) def assertIsStringOrNone(self, value): if value is not None: self.assertTrue(isinstance(value, str)) def assertIsInt(self, value): self.assertTrue(isinstance(value, int)) def assertRaisesIOError(self, fn, args, errmsg): """ Verify that an IOError is raised, and that the errno and message are as expected (Python 2.6 and earlier's assertRaises doesn't allow us to check the details of the exception that is raised) """ try: fn(*args) except IOError as e: # Check the details of the exception: enum, emsg = e.args self.assertEqual('[Errno {}] {}'.format(enum, emsg), errmsg) else: self.fail('IOError was not raised calling %s on %s' % (fn, args)) def assertRaisesNoSuchDevice(self, fn, *args): self.assertRaisesIOError(fn, args, '[Errno 19] No such device') def assertIsStringExceptForLoopback(self, fn, devname, errmsg): if devname == 'lo': self.assertRaisesIOError(fn, (devname, ), errmsg) else: self.assertIsString(fn(devname)) def assertEqualIpv4Str(self, ethtooladdr, scrapedaddr): if scrapedaddr is None: self.assertEqual(ethtooladdr, '0.0.0.0') else: self.assertEqual(ethtooladdr, scrapedaddr) def assertEqualHwAddr(self, ethtooladdr, scrapedaddr): if scrapedaddr is None: self.assertEqual(ethtooladdr, '00:00:00:00:00:00') else: self.assertEqual(ethtooladdr, scrapedaddr.lower()) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # helpers # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def _functions_accepting_devnames(self, devname): self.assertIsString(devname) scraped = ifconfig.get_device_by_name(devname) try: broadcast = ethtool.get_broadcast(devname) except (OSError, IOError): # Some devices might end up with # [Errno 99] Cannot assign requested address # That's IOError on 2.7, OSError on 3 assignable = False else: assignable = True self.assertIsString(broadcast) # Broadcast is optional in ifconfig output if scraped.broadcast: self.assertEqualIpv4Str(broadcast, scraped.broadcast) self.assertIsStringExceptForLoopback(ethtool.get_businfo, devname, '[Errno 95] Operation not ' 'supported') self.assertIsInt(ethtool.get_flags(devname)) # flagsint cannot be obtained from old ifconfig format if not ifconfig.oldFormat: self.assertEqual(ethtool.get_flags(devname), scraped.flagsint) self.assertIsInt(ethtool.get_gso(devname)) self.assertIsInt(ethtool.get_gro(devname)) self.assertIsString(ethtool.get_hwaddr(devname)) self.assertEqualHwAddr(ethtool.get_hwaddr(devname), scraped.hwaddr) if assignable: self.assertIsString(ethtool.get_ipaddr(devname)) self.assertEqual(ethtool.get_ipaddr(devname), scraped.inet) self.assertIsStringExceptForLoopback(ethtool.get_module, devname, '[Errno 95] Operation not ' 'supported') if assignable: self.assertIsString(ethtool.get_netmask(devname)) self.assertEqual(ethtool.get_netmask(devname), scraped.netmask) # Operation is not supported only on loopback device if devname == 'lo': self.assertRaisesIOError(ethtool.get_ringparam, (devname, ), '[Errno 95] Operation not supported') self.assertIsInt(ethtool.get_sg(devname)) try: self.assertIsInt(ethtool.get_ufo(devname)) except (OSError, IOError): # This test may fail due to insufficient privileges # That's IOError on 2.7, OSError (PermissionError) on 3 pass self.assertIsInt(ethtool.get_tso(devname)) # TODO: self.assertIsString(ethtool.set_coalesce(devname)) # TODO: self.assertIsString(ethtool.set_ringparam(devname)) # TODO: self.assertIsString(ethtool.set_tso(devname)) # TODO: self.assertIsString(ethtool.set_gso(devname)) # TODO: self.assertIsString(ethtool.set_gro(devname)) def _verify_etherinfo_object(self, ei): self.assertTrue(isinstance(ei, ethtool.etherinfo)) self.assertIsString(ei.device) try: scraped = ifconfig.get_device_by_name(ei.device) except ValueError: scraped = None self.assertIsStringOrNone(ei.ipv4_address) if scraped: self.assertEqual(ei.ipv4_address, scraped.inet) self.assertIsStringOrNone(ei.ipv4_broadcast) if scraped and scraped.broadcast: # Broadcast is optional self.assertEqual(ei.ipv4_broadcast, scraped.broadcast) self.assertIsInt(ei.ipv4_netmask) if scraped: self.assertEqual(ei.ipv4_netmask, scraped.get_netmask_bits()) self.assertIsStringOrNone(ei.mac_address) if scraped and scraped.hwaddr and scraped.hwtitle.lower() != 'unspec': scraped.hwaddr = scraped.hwaddr.lower() self.assertEqualHwAddr(ei.mac_address.lower(), scraped.hwaddr) i6s = ei.get_ipv6_addresses() for i6 in i6s: self.assertTrue(isinstance(i6, ethtool.NetlinkIPaddress)) self.assertIsString(i6.address) self.assertIsInt(i6.netmask) self.assertIsString(i6.scope) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # tests # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def test_invalid_devices(self): # Verify sane handling of non-existant devices get_fns = ('get_broadcast', 'get_businfo', 'get_coalesce', 'get_flags', 'get_gso', 'get_gso', 'get_hwaddr', 'get_ipaddr', 'get_module', 'get_netmask', 'get_ringparam', 'get_sg', 'get_tso', 'get_ufo') for fnname in get_fns: self.assertRaisesNoSuchDevice(getattr(ethtool, fnname), INVALID_DEVICE_NAME) set_fns = ('set_coalesce', 'set_ringparam', 'set_tso', 'set_gso', 'set_gro') for fnname in set_fns: # Currently this fails, with an IOError from # ethtool.c:__struct_desc_from_dict # with message: # 'Missing dict entry for field rx_coalesce_usecs' if False: self.assertRaisesNoSuchDevice(getattr(ethtool, fnname), INVALID_DEVICE_NAME, 42) def test_get_interface_info_invalid(self): eis = ethtool.get_interfaces_info(INVALID_DEVICE_NAME) self.assertEqual(len(eis), 1) ei = eis[0] self.assertEqual(ei.device, INVALID_DEVICE_NAME) self.assertRaisesIOError( getattr, (ei, 'ipv4_address'), '[Errno 19] No such device') self.assertRaisesIOError( getattr, (ei, 'ipv4_netmask'), '[Errno 19] No such device') self.assertRaisesIOError( getattr, (ei, 'ipv4_broadcast'), '[Errno 19] No such device') self.assertRaisesIOError( getattr, (ei, 'mac_address'), '[Errno 19] No such device') def test_get_interface_info_active(self): eis = ethtool.get_interfaces_info(ethtool.get_active_devices()) for ei in eis: self._verify_etherinfo_object(ei) def test_get_interface_info_all(self): eis = ethtool.get_interfaces_info(ethtool.get_devices()) for ei in eis: self._verify_etherinfo_object(ei) def test_get_active_devices(self): for devname in ethtool.get_active_devices(): # Skip these test on tun devices if devname.startswith('tun'): continue self._functions_accepting_devnames(devname) def test_etherinfo_objects(self): devnames = ethtool.get_devices() eis = ethtool.get_interfaces_info(devnames) for ei in eis: self._verify_etherinfo_object(ei) if __name__ == '__main__': unittest.main() python-ethtool-0.14/tests/test_scripts.py000077500000000000000000000137231334642534600207200ustar00rootroot00000000000000import unittest import ethtool import sys import os from io import TextIOWrapper, BytesIO from imp import load_source pifc = load_source('pifc', 'scripts/pifconfig') peth = load_source('peth', 'scripts/pethtool') def find_suitable_device(): active_devices = ethtool.get_active_devices() for device in active_devices: device_flags = ethtool.get_flags(device) str_flags = pifc.flags2str(device_flags) try: wireless_protocol = ethtool.get_wireless_protocol(device) except Exception: wireless_protocol = None if 'UP' in str_flags and 'RUNNING' in str_flags \ and 'BROADCAST' in str_flags and not wireless_protocol: return device return None loopback = 'lo' device = find_suitable_device() class ScriptsTests(unittest.TestCase): def setUp(self): self._old_stdout = sys.stdout self._stdout = sys.stdout = TextIOWrapper(BytesIO(), sys.stdout.encoding) def _output(self): self._stdout.seek(0) return self._stdout.read() def tearDown(self): sys.stdout = self._old_stdout self._stdout.close() def test_flags2str(self): self.assertEqual(pifc.flags2str(0), '') self.assertEqual(pifc.flags2str(73), 'UP LOOPBACK RUNNING') self.assertEqual(pifc.flags2str(4305), 'UP POINTOPOINT RUNNING NOARP MULTICAST') self.assertEqual(pifc.flags2str(4163), 'UP BROADCAST RUNNING MULTICAST') # Tests for loopback def test_driver_lo(self): self.assertIsNone(peth.show_driver(loopback)) self.assertEqual(self._output(), 'driver: not implemented\nbus-info: not available\n' ) def test_show_ring_lo(self): self.assertIsNone(peth.show_ring(loopback)) self.assertEqual(self._output(), 'Ring parameters for {}:\n NOT supported!\n'.format(loopback) ) def test_show_coalesce_lo(self): self.assertIsNone(peth.show_coalesce(loopback)) self.assertEqual(self._output(), 'Coalesce parameters for {}:\n NOT supported!\n'.format(loopback) ) def test_show_offload_lo(self): self.assertIsNone(peth.show_offload(loopback)) # Check if we have rights to obtain ufo and set proper expected output try: ethtool.get_ufo(loopback) expected_ufo = 'on' except (OSError, IOError): expected_ufo = 'not supported' self.assertEqual(self._output(), '''scatter-gather: on tcp segmentation offload: on udp fragmentation offload: {expected_ufo} generic segmentation offload: on generic receive offload: on '''.format(expected_ufo=expected_ufo) ) # Tests for another device if device: def test_driver_eth(self): self.assertIsNone(peth.show_driver(device)) expected_lines_start = ['driver: ', 'bus-info: '] lines = self._output().split('\n') for expected_start, line in zip(expected_lines_start, lines): self.assertTrue(line.startswith(expected_start)) def test_show_ring_eth(self): self.assertIsNone(peth.show_ring(device)) expected_lines_start = ['Ring parameters for ', 'Pre-set maximums:', 'RX:', 'RX Mini:', 'RX Jumbo:', 'TX', 'Current hardware settings:', 'RX:', 'RX Mini:', 'RX Jumbo:', 'TX:'] lines = self._output().split('\n') for expected_start, line in zip(expected_lines_start, lines): self.assertTrue(line.startswith(expected_start)) @unittest.skipIf('TRAVIS' in os.environ and os.environ['TRAVIS'] == 'true', 'Skipping this test on Travis CI because show ' 'coalesce is not supported on ethernet device in VM.') def test_show_coalesce_eth(self): self.assertIsNone(peth.show_coalesce(device)) expected_lines_start = ['Coalesce parameters for', 'Adaptive RX:', 'stats-block-usecs:', 'sample-interval:', 'pkt-rate-low:', 'pkt-rate-high:', 'rx-usecs:', 'rx-frames:', 'rx-usecs-irq:', 'rx-frames-irq:', 'tx-usecs:', 'tx-frames:', 'tx-usecs-irq:', 'tx-frames-irq:', 'rx-usecs-low:', 'rx-frame-low:', 'tx-usecs-low:', 'tx-frame-low:', 'rx-usecs-high:', 'rx-frame-high:', 'tx-usecs-high:', 'tx-frame-high:'] lines = self._output().split('\n') for expected_start, line in zip(expected_lines_start, lines): self.assertTrue(line.startswith(expected_start)) def test_show_offload_eth(self): self.assertIsNone(peth.show_offload(device)) expected_lines_start = ['scatter-gather:', 'tcp segmentation offload:', 'udp fragmentation offload:', 'generic segmentation offload:'] lines = self._output().split('\n') for expected_start, line in zip(expected_lines_start, lines): self.assertTrue(line.startswith(expected_start)) if __name__ == '__main__': unittest.main() python-ethtool-0.14/tox.ini000066400000000000000000000003561334642534600157640ustar00rootroot00000000000000[tox] envlist = py27,py35,py36,py37 [testenv] commands= python tests/parse_ifconfig.py -v python -m unittest discover -v passenv= TRAVIS # Run all the above commands, don't worry it reports failure anyway ignore_errors = True