./python-ethtool-0.12/0000755000175000017500000000000012754311023013224 5ustar galtgalt./python-ethtool-0.12/setup.py0000644000175000017500000000461612754311023014745 0ustar galtgalt#!/usr/bin/python2 from __future__ import print_function from distutils.core import setup, Extension try: import commands except ImportError: import subprocess as commands import sys version = '0.10' def pkgconfig(pkg): def _str2list(pkgstr, onlystr): res = [] for l in pkgstr.split(" "): if l.find(onlystr) == 0: res.append(l.replace(onlystr, "", 1)) return res (res, cflags) = commands.getstatusoutput('pkg-config --cflags-only-other %s' % pkg) if res != 0: print('Failed to query pkg-config --cflags-only-other %s' % pkg) sys.exit(1) (res, includes) = commands.getstatusoutput('pkg-config --cflags-only-I %s' % pkg) if res != 0: print('Failed to query pkg-config --cflags-only-I %s' % pkg) sys.exit(1) (res, libs) = commands.getstatusoutput('pkg-config --libs-only-l %s' % pkg) if res != 0: print('Failed to query pkg-config --libs-only-l %s' % pkg) sys.exit(1) (res, libdirs) = commands.getstatusoutput('pkg-config --libs-only-L %s' % pkg) if res != 0: print('Failed to query pkg-config --libs-only-L %s' % pkg) sys.exit(1) # Clean up the results and return what we've extracted from pkg-config return {'cflags': cflags, 'include': _str2list(includes, '-I'), 'libs': _str2list(libs, '-l'), 'libdirs': _str2list(libdirs, '-L') } libnl = pkgconfig('libnl-3.0') libnl['libs'].append('nl-route-3') # don't reformat this line, Makefile parses it setup(name='ethtool', version=version, description='Python module to interface with ethtool', author='Harald Hoyer, Arnaldo Carvalho de Melo, David Sommerseth', author_email='davids@redhat.com', url='http://fedoraproject.org/wiki/python-ethtool', ext_modules=[ Extension( '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'], include_dirs = libnl['include'], library_dirs = libnl['libdirs'], libraries = libnl['libs'], define_macros = [('VERSION', '"%s"' % version)] ) ] ) ./python-ethtool-0.12/pethtool.py0000755000175000017500000002170412754311023015443 0ustar galtgalt#! /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. import getopt, ethtool, 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] -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" printtab("scatter-gather: %s" % sg) printtab("tcp segmentation offload: %s" % tso) printtab("udp fragmentation offload: %s" % ufo) printtab("generic segmentation offload: %s" % gso) 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 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 not ethtool_ringparam_map.has_key(arg): 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, err: usage() print str(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.12/MANIFEST0000644000175000017500000000062212754311023014355 0ustar galtgaltCOPYING pethtool.py pifconfig.py python-ethtool/ethtool.c python-ethtool/ethtool-copy.h python-ethtool/etherinfo.c python-ethtool/etherinfo_obj.c python-ethtool/etherinfo_struct.h python-ethtool/etherinfo.h python-ethtool/etherinfo_obj.h python-ethtool/netlink.c python-ethtool/netlink-address.c man/pethtool.8.asciidoc man/pifconfig.8.asciidoc setup.py rpm/SPECS/python-ethtool.spec MANIFEST Makefile ./python-ethtool-0.12/COPYING0000644000175000017500000004310312754311023014260 0ustar galtgalt 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.12/python-ethtool/0000755000175000017500000000000012754311023016221 5ustar galtgalt./python-ethtool-0.12/python-ethtool/etherinfo.c0000644000175000017500000001755712754311023020367 0ustar galtgalt/* 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 #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 = PyBytes_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, PyBytes_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", PyBytes_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", PyBytes_AsString(self->device)); return NULL; } if( _set_device_index(self) != 1) { 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.12/python-ethtool/etherinfo_obj.h0000644000175000017500000000230612754311023021210 0ustar galtgalt/* * 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.12/python-ethtool/netlink-address.c0000644000175000017500000001322712754311023021461 0ustar galtgalt/* * 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 "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 = PyBytes_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 = PyBytes_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 = PyBytes_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 = PyBytes_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 = PyBytes_FromString("ethtool.NetlinkIPaddress(family="); char buf[256]; memset(&buf, 0, sizeof(buf)); nl_af2str(obj->family, buf, sizeof(buf)); PyBytes_ConcatAndDel(&result, PyBytes_FromFormat("%s, address='", buf)); PyBytes_Concat(&result, obj->local); if (obj->family == AF_INET) { PyBytes_ConcatAndDel(&result, PyBytes_FromFormat("', netmask=%d", obj->prefixlen)); } else if (obj->family == AF_INET6) { PyBytes_ConcatAndDel(&result, PyBytes_FromFormat("/%d'", obj->prefixlen)); } if (obj->peer) { PyBytes_ConcatAndDel(&result, PyBytes_FromString(", peer_address='")); PyBytes_Concat(&result, obj->peer); PyBytes_ConcatAndDel(&result, PyBytes_FromString("'")); } if (obj->family == AF_INET && obj->ipv4_broadcast) { PyBytes_ConcatAndDel(&result, PyBytes_FromString(", broadcast='")); PyBytes_Concat(&result, obj->ipv4_broadcast); PyBytes_ConcatAndDel(&result, PyBytes_FromString("'")); } PyBytes_ConcatAndDel(&result, PyBytes_FromString(", scope=")); PyBytes_Concat(&result, obj->scope); PyBytes_ConcatAndDel(&result, PyBytes_FromString(")")); #if PY_MAJOR_VERSION >= 3 { PyObject *bytestr = result; result = PyUnicode_FromString(PyBytes_AsString(result)); Py_DECREF(bytestr); } #endif 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); } } /* Local variables: c-basic-offset: 8 indent-tabs-mode: y End: */ ./python-ethtool-0.12/python-ethtool/ethtool.c0000644000175000017500000006021612754311023020050 0ustar galtgalt/* * 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 #include #include #include #include #include #include #include #include #include #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 = PyBytes_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 ) { 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 = PyBytes_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 PyBytes_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 PyBytes_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( PyBytes_Check(inargs) ) { /* Input argument is just a string */ fetch_devs_len = 1; fetch_devs = calloc(1, sizeof(char *)); fetch_devs[0] = PyBytes_AsString(inargs); #if PY_MAJOR_VERSION >= 3 } else if( PyUnicode_Check(inargs) ) { /* Input argument is just a ustring */ fetch_devs_len = 1; fetch_devs = calloc(1, sizeof(char *)); fetch_devs[0] = PyUnicode_AsUTF8(inargs); #endif } 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 && PyBytes_Check(elmt) ) { fetch_devs[j++] = PyBytes_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 && PyBytes_Check(elmt) ) { fetch_devs[j++] = PyBytes_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 = PyBytes_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 PyBytes_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 PyBytes_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 PyBytes_FromString(driver); } } close(fd); return PyBytes_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 PyBytes_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), err; 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, "s*i", &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_INCREF(Py_None); return Py_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 *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); } 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) goto out; 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) goto free_dict; if (PyDict_SetItemString(dict, d->name, objval) != 0) { Py_DECREF(objval); goto free_dict; } Py_DECREF(objval); } out: return dict; free_dict: goto out; dict = NULL; } #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, "s*O", &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_INCREF(Py_None); return Py_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, "s*O", &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_INCREF(Py_None); return Py_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 = "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 = NULL, }, }; #if PY_MAJOR_VERSION >= 3 #define MOD_ERROR_VAL NULL #define MOD_SUCCESS_VAL(val) val #define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void) #define MOD_DEF(ob, name, doc, methods) \ static struct PyModuleDef moduledef = { \ PyModuleDef_HEAD_INIT, name, doc, -1, methods, }; \ ob = PyModule_Create(&moduledef); #else #define MOD_ERROR_VAL #define MOD_SUCCESS_VAL(val) #define MOD_INIT(name) void init##name(void) #define MOD_DEF(ob, name, doc, methods) \ ob = Py_InitModule3(name, methods, doc); #endif MOD_INIT(ethtool) { PyObject *m; MOD_DEF(m, "ethtool", "Python ethtool module", PyEthModuleMethods); // Prepare the ethtool.etherinfo class if (PyType_Ready(&PyEtherInfo_Type) < 0) return MOD_ERROR_VAL; // Prepare the ethtool IPv6 and IPv4 address types if (PyType_Ready(ðtool_netlink_ip_address_Type)) return MOD_ERROR_VAL; // Setup constants PyModule_AddIntConstant(m, "IFF_UP", IFF_UP); /* Interface is up. */ PyModule_AddIntConstant(m, "IFF_BROADCAST", IFF_BROADCAST); /* Broadcast address valid. */ PyModule_AddIntConstant(m, "IFF_DEBUG", IFF_DEBUG); /* Turn on debugging. */ PyModule_AddIntConstant(m, "IFF_LOOPBACK", IFF_LOOPBACK); /* Is a loopback net */ PyModule_AddIntConstant(m, "IFF_POINTOPOINT", IFF_POINTOPOINT); /* Is a point-to-point link */ PyModule_AddIntConstant(m, "IFF_NOTRAILERS", IFF_NOTRAILERS); /* Avoid use of trailers */ PyModule_AddIntConstant(m, "IFF_RUNNING", IFF_RUNNING); /* Resources allocated */ PyModule_AddIntConstant(m, "IFF_NOARP", IFF_NOARP); /* No address resolution protocol. */ PyModule_AddIntConstant(m, "IFF_PROMISC", IFF_PROMISC); /* Receive all packets. */ PyModule_AddIntConstant(m, "IFF_ALLMULTI", IFF_ALLMULTI); /* Receive all multicast packets. */ PyModule_AddIntConstant(m, "IFF_MASTER", IFF_MASTER); /* Master of a load balancer. */ PyModule_AddIntConstant(m, "IFF_SLAVE", IFF_SLAVE); /* Slave of a load balancer. */ PyModule_AddIntConstant(m, "IFF_MULTICAST", IFF_MULTICAST); /* Supports multicast. */ PyModule_AddIntConstant(m, "IFF_PORTSEL", IFF_PORTSEL); /* Can set media type. */ PyModule_AddIntConstant(m, "IFF_AUTOMEDIA", IFF_AUTOMEDIA); /* Auto media select active. */ PyModule_AddIntConstant(m, "IFF_DYNAMIC", IFF_DYNAMIC); /* Dialup device with changing addresses. */ PyModule_AddIntConstant(m, "AF_INET", AF_INET); /* IPv4 interface */ PyModule_AddIntConstant(m, "AF_INET6", AF_INET6); /* IPv6 interface */ PyModule_AddStringConstant(m, "version", "python-ethtool v" VERSION); return MOD_SUCCESS_VAL(m); } /* Local variables: c-basic-offset: 8 indent-tabs-mode: y End: */ ./python-ethtool-0.12/python-ethtool/etherinfo_struct.h0000644000175000017500000000366612754311023021774 0ustar galtgalt/* * 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 address */ 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.12/python-ethtool/ethtool-copy.h0000644000175000017500000003006512754311023021024 0ustar galtgalt/* * 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 (ethtool_value) */ #define ETHTOOL_SRXCSUM 0x00000015 /* Set RX hw csum enable (ethtool_value) */ #define ETHTOOL_GTXCSUM 0x00000016 /* Get TX hw csum enable (ethtool_value) */ #define ETHTOOL_STXCSUM 0x00000017 /* Set TX hw csum enable (ethtool_value) */ #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 (ethtool_value) */ #define ETHTOOL_STSO 0x0000001f /* Set TSO enable (ethtool_value) */ #define ETHTOOL_GUFO 0x00000021 /* Get UFO enable (ethtool_value) */ #define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (ethtool_value) */ #define ETHTOOL_GGSO 0x00000023 /* Get GSO enable (ethtool_value) */ #define ETHTOOL_SGSO 0x00000024 /* Set GSO enable (ethtool_value) */ /* 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.12/python-ethtool/etherinfo_obj.c0000644000175000017500000002063012754311023021203 0ustar galtgalt/* * 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 "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 = PyBytes_FromFormat("Device "); PyBytes_Concat(&ret, self->device); PyBytes_ConcatAndDel(&ret, PyBytes_FromString(":\n")); if( self->hwaddress ) { PyBytes_ConcatAndDel(&ret, PyBytes_FromString("\tMAC address: ")); PyBytes_Concat(&ret, self->hwaddress); PyBytes_ConcatAndDel(&ret, PyBytes_FromString("\n")); } 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 = PyBytes_FromFormat("\tIPv4 address: "); PyBytes_Concat(&tmp, py_addr->local); PyBytes_ConcatAndDel(&tmp, PyBytes_FromFormat("/%d", py_addr->prefixlen)); if (py_addr->ipv4_broadcast ) { PyBytes_ConcatAndDel(&tmp, PyBytes_FromString(" Broadcast: ")); PyBytes_Concat(&tmp, py_addr->ipv4_broadcast); } PyBytes_ConcatAndDel(&tmp, PyBytes_FromString("\n")); PyBytes_ConcatAndDel(&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 = PyBytes_FromFormat("\tIPv6 address: ["); PyBytes_Concat(&tmp, py_addr->scope); PyBytes_ConcatAndDel(&tmp, PyBytes_FromString("] ")); PyBytes_Concat(&tmp, py_addr->local); PyBytes_ConcatAndDel(&tmp, PyBytes_FromFormat("/%d", py_addr->prefixlen)); PyBytes_ConcatAndDel(&tmp, PyBytes_FromString("\n")); PyBytes_ConcatAndDel(&ret, tmp); } } #if PY_MAJOR_VERSION >= 3 { PyObject *bytestr = ret; ret = PyUnicode_FromString(PyBytes_AsString(bytestr)); Py_DECREF(bytestr); } #endif 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; } } 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 PyLong_FromLong(py_addr->prefixlen); } return PyLong_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; } } Py_RETURN_NONE; } 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.12/python-ethtool/netlink.c0000644000175000017500000000631512754311023020036 0ustar galtgalt/* 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; static unsigned int nlconnection_users = 0; /* How many NETLINK users are active? */ /** * 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; } /* Local variables: c-basic-offset: 8 indent-tabs-mode: y End: */ ./python-ethtool-0.12/python-ethtool/etherinfo.h0000644000175000017500000000170312754311023020356 0ustar galtgalt/* 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 typedef enum {NLQRY_ADDR4, NLQRY_ADDR6} nlQuery; /**< Supported query types in the etherinfo code */ 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.12/tests/0000755000175000017500000000000012754311023014366 5ustar galtgalt./python-ethtool-0.12/tests/__init__.py0000644000175000017500000000000012754311023016465 0ustar galtgalt./python-ethtool-0.12/tests/parse_ifconfig.py0000644000175000017500000010666212754311023017731 0ustar galtgalt# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # 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 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: p = Popen('ifconfig', stdout=PIPE, stderr=PIPE) 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 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: packed = parse_ip4addr(self.netmask) # count bits in "packed": result = 0 for ch in packed: ch = ord(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 raise ValueError('parser could not handle line: %r' % line) #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'), '\x01\x01\x01\x01') self.assertEqual(parse_ip4addr('127.0.0.1'), '\x7f\x00\x00\x01') def test_local(self): # Actually invoke ifconfig locally, and parse whatever it emits: ifconfig = IfConfig() if __name__ == '__main__': unittest.main() ./python-ethtool-0.12/tests/test_ethtool.py0000755000175000017500000002251512754311023017465 0ustar galtgalt# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # 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 sys import unittest from test.test_support import run_unittest # requires python-test subpackage on Fedora/RHEL 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.assert_(isinstance(value, str)) def assertIsStringOrNone(self, value): if value is not None: self.assert_(isinstance(value, str)) def assertIsInt(self, value): self.assert_(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, e: # Check the details of the exception: self.assertEquals(e.args, (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) self.assertIsString(ethtool.get_broadcast(devname)) self.assertEqualIpv4Str(ethtool.get_broadcast(devname), scraped.broadcast) self.assertIsStringExceptForLoopback(ethtool.get_businfo, devname, '[Errno 95] Operation not supported') # ethtool.get_coalesce(devname) # this gives me: # IOError: [Errno 95] Operation not supported # on my test box 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.assertIsString(ethtool.get_hwaddr(devname)) self.assertEqualHwAddr(ethtool.get_hwaddr(devname), scraped.hwaddr) 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') self.assertIsString(ethtool.get_netmask(devname)) self.assertEqual(ethtool.get_netmask(devname), scraped.netmask) #self.assertRaisesIOError(ethtool.get_ringparam, (devname, ), # '[Errno 95] Operation not supported') # Disabling until BZ#703089 is investigated #self.assertIsInt(ethtool.get_sg(devname)) #self.assertIsInt(ethtool.get_ufo(devname)) 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)) def _verify_etherinfo_object(self, ei): self.assert_(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: 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: if scraped.hwaddr: scraped.hwaddr = scraped.hwaddr.lower() self.assertEqualHwAddr(ei.mac_address.lower(), scraped.hwaddr) i6s = ei.get_ipv6_addresses() for i6 in i6s: self.assert_(isinstance(i6, ethtool.etherinfo_ipv6addr)) self.assertIsString(i6.address) self.assertIsInt(i6.netmask) self.assertIsString(i6.scope) self.assertEquals(str(i6), '[%s] %s/%i' % (i6.scope, i6.address, i6.netmask)) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # 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_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') 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.assertEquals(len(eis), 1) ei = eis[0] self.assertEquals(ei.device, INVALID_DEVICE_NAME) self.assertEquals(ei.ipv4_address, None) self.assertEquals(ei.ipv4_broadcast, None) self.assertEquals(ei.ipv4_netmask, 0) self.assertEquals(ei.mac_address, None) 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(): 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__': try: # if count provided do a soak test, to detect leaking resources count = int(sys.argv[1]) for i in range(count): run_unittest(EthtoolTests) if i % (count / 10) == 0: sys.stderr.write("%s %%\n" % (i * 100 / count)) except: run_unittest(EthtoolTests) ./python-ethtool-0.12/man/0000755000175000017500000000000012754311023013777 5ustar galtgalt./python-ethtool-0.12/man/pethtool.8.asciidoc0000644000175000017500000000272412754311023017510 0ustar galtgaltpethtool(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.12/man/pifconfig.8.asciidoc0000644000175000017500000000122312754311023017607 0ustar galtgaltpifconfig(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.12/pifconfig.py0000755000175000017500000000556412754311023015557 0ustar galtgalt#! /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. import getopt, ethtool, 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 '%-9.9s' % device, if not (flags & ethtool.IFF_LOOPBACK): print "HWaddr %s" % ethtool.get_hwaddr(device), print ''' inet addr:%s''' % ipaddr, if not (flags & (ethtool.IFF_LOOPBACK | ethtool.IFF_POINTOPOINT)): print "Bcast:%s" % ethtool.get_broadcast(device), print ' Mask:%s' % netmask for info in ethtool.get_interfaces_info(device): for addr in info.get_ipv6_addresses(): print (" inet6 addr: %s/%s Scope: %s" % (addr.address, addr.netmask, addr.scope)) print ' %s' % flags2str(flags) print def main(): global all_devices 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, ex: print "** ERROR ** [Device %s]: %s" % (device, str(ex)) sys.exit(2) if __name__ == '__main__': main() ./python-ethtool-0.12/rpm/0000755000175000017500000000000012754311023014022 5ustar galtgalt./python-ethtool-0.12/rpm/SPECS/0000755000175000017500000000000012754311023014677 5ustar galtgalt./python-ethtool-0.12/rpm/SPECS/python-ethtool.spec0000644000175000017500000000720412754311023020553 0ustar galtgalt%{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")} %{!?python_ver: %define python_ver %(%{__python} -c "import sys ; print sys.version[:3]")} Summary: Ethernet settings python bindings Name: python-ethtool Version: 0.10 Release: 1%{?dist} URL: https://fedorahosted.org/python-ethtool/ Source: https://fedorahosted.org/releases/p/y/python-ethtool/python-ethtool-%{version}.tar.bz2 License: GPLv2 Group: System Environment/Libraries BuildRequires: python-devel libnl3-devel asciidoc BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) %description Python bindings for the ethtool kernel interface, that allows querying and changing of Ethernet card settings, such as speed, port, auto-negotiation, and PCI locations. %prep %setup -q %build %{__python} setup.py build a2x -d manpage -f manpage man/pethtool.8.asciidoc a2x -d manpage -f manpage man/pifconfig.8.asciidoc %install rm -rf %{buildroot} %{__python} setup.py install --skip-build --root %{buildroot} mkdir -p %{buildroot}%{_sbindir} %{buildroot}%{_mandir}/man8 cp -p pethtool.py %{buildroot}%{_sbindir}/pethtool cp -p pifconfig.py %{buildroot}%{_sbindir}/pifconfig %{__gzip} -c man/pethtool.8 > %{buildroot}%{_mandir}/man8/pethtool.8.gz %{__gzip} -c man/pifconfig.8 > %{buildroot}%{_mandir}/man8/pifconfig.8.gz %clean rm -rf %{buildroot} %files %defattr(-,root,root) %doc COPYING %{_sbindir}/pethtool %{_sbindir}/pifconfig %doc %{_mandir}/man8/* %{python_sitearch}/ethtool.so %if "%{python_ver}" >= "2.5" %{python_sitearch}/*.egg-info %endif %changelog * Mon Apr 11 2011 David Sommerseth - 0.7-1 - 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) * Wed Jan 19 2011 David Sommerseth - 0.6-1 - 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) * Mon Aug 9 2010 David Sommerseth - 0.5-1 - Fixed double free issue (commit c52ed2cbdc5b851ebc7b) * Wed Apr 28 2010 David Sommerseth - 0.4-1 - 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() * Fri Sep 5 2008 Arnaldo Carvalho de Melo - 0.3-2 - Rewrote build and install sections as part of the fedora review process BZ #459549 * Tue Aug 26 2008 Arnaldo Carvalho de Melo - 0.3-1 - Add get_flags method from the first python-ethtool contributor, yay - Add pifconfig command, that mimics the ifconfig tool using the bindings available * Wed Aug 20 2008 Arnaldo Carvalho de Melo - 0.2-1 - Expand description and summary fields, as part of the fedora review process. * Tue Jun 10 2008 Arnaldo Carvalho de Melo - 0.1-3 - add dist to the release tag * Tue Dec 18 2007 Arnaldo Carvalho de Melo - 0.1-2 - First build into MRG repo * Tue Dec 18 2007 Arnaldo Carvalho de Melo - 0.1-1 - Get ethtool code from rhpl 0.212 ./python-ethtool-0.12/Makefile0000644000175000017500000000424512754311023014671 0ustar galtgaltPACKAGE := python-ethtool VERSION := $(shell rpm -q --qf '%{VERSION} ' --specfile rpm/SPECS/$(PACKAGE).spec | cut -d' ' -f1) rpmdirs: @[ -d rpm/BUILD ] || mkdir rpm/BUILD @[ -d rpm/RPMS ] || mkdir rpm/RPMS @[ -d rpm/SRPMS ] || mkdir rpm/SRPMS @[ -d rpm/SOURCES ] || mkdir rpm/SOURCES bz2: rpmdirs git archive --format=tar --prefix=$(PACKAGE)-$(VERSION)/ HEAD | \ bzip2 -9 > rpm/SOURCES/$(PACKAGE)-$(VERSION).tar.bz2 install: python setup.py install --root=$(DESTDIR) rpm: bz2 rpmdirs rpmbuild -ba --define "_topdir $(PWD)/rpm" rpm/SPECS/$(PACKAGE).spec bz2dev: rpmdirs @mkdir -p /tmp/$(PACKAGE)-$(VERSION) @tar cf - `cat MANIFEST` | (cd /tmp/$(PACKAGE)-$(VERSION) ; tar xf -) @(cd /tmp; tar cf - $(PACKAGE)-$(VERSION)) | bzip2 -9 > rpm/SOURCES/$(PACKAGE)-$(VERSION).tar.bz2 rpmdev: bz2dev rpmdirs rpmbuild -ba --define "_topdir $(PWD)/rpm" rpm/SPECS/$(PACKAGE).spec build: python setup.py build # Need to set PYTHONPATH appropriately when invoking this test: python tests/parse_ifconfig.py -v python -m unittest discover -v valgrind --leak-check=full python tests/test_ethtool.py # As of 5f6339c432dc227e456b70c459cf6f57c6cfe7c2 I (dmalcolm) hope to have # fixed the memory leaks within python-ethtool itself, but I expect # to see a few blocks lost within libnl which appear to be caches, # and thus (presumably) false positives: # ==9163== 4,600 (80 direct, 4,520 indirect) bytes in 2 blocks are definitely lost in loss record 2,559 of 2,612 # ==9163== at 0x4C26F18: calloc (vg_replace_malloc.c:566) # ==9163== by 0x1152C307: nl_cache_alloc (in /usr/lib64/libnl.so.1.1) # ==9163== by 0x115309FC: rtnl_link_alloc_cache (in /usr/lib64/libnl.so.1.1) # ==9163== by 0x1130C843: get_etherinfo (etherinfo.c:315) # ==9163== by 0x1130CFD0: _ethtool_etherinfo_getter (etherinfo_obj.c:152) # ==9163== by 0x4F07E90: PyEval_EvalFrameEx (ceval.c:2330) # ...etc... # ==9163== LEAK SUMMARY: # ==9163== definitely lost: 160 bytes in 4 blocks # ==9163== indirectly lost: 9,040 bytes in 60 blocks # ==9163== possibly lost: 489,676 bytes in 3,299 blocks # ==9163== still reachable: 1,277,848 bytes in 11,100 blocks # ==9163== suppressed: 0 bytes in 0 blocks