Skip to content

Commit

Permalink
#663: ptp addresses linux implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
giampaolo committed Aug 5, 2015
1 parent 1196991 commit 725dfb4
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 25 deletions.
1 change: 1 addition & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Bug tracker at https://github.com/giampaolo/psutil/issues
**Enhancements**

- #648: CI test integration for OSX. (patch by Jeff Tang)
- #663: net_if_addrs() now returns point-to-point addresses (for VPNs).

**Bug fixes**

Expand Down
12 changes: 6 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,12 @@ Network
...]
>>>
>>> psutil.net_if_addrs()
{'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1'),
snic(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None),
snic(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00')],
'wlan0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255'),
snic(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None),
snic(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff')]}
{'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None),
snic(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None),
snic(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)],
'wlan0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
snic(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None),
snic(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}
>>>
>>> psutil.net_if_stats()
{'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500),
Expand Down
23 changes: 15 additions & 8 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -410,28 +410,33 @@ Network
Return the addresses associated to each NIC (network interface card)
installed on the system as a dictionary whose keys are the NIC names and
value is a list of namedtuples for each address assigned to the NIC.
Each namedtuple includes 4 fields:
Each namedtuple includes 5 fields:

- **family**
- **address**
- **netmask**
- **broadcast**
- **ptp**

*family* can be either
`AF_INET <http://docs.python.org//library/socket.html#socket.AF_INET>`__,
`AF_INET6 <http://docs.python.org//library/socket.html#socket.AF_INET6>`__
or :const:`psutil.AF_LINK`, which refers to a MAC address.
*address* is the primary address, *netmask* and *broadcast* may be ``None``.
*address* is the primary address and it is always set.
*netmask*, *broadcast* and *ptp* may be ``None``.
*ptp* stands for "point to point" and references the destination address on a
point to point interface (tipically a VPN).
*broadcast* and *ptp* are mutually exclusive.
Example::

>>> import psutil
>>> psutil.net_if_addrs()
{'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1'),
snic(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None),
snic(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00')],
'wlan0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255'),
snic(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None),
snic(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff')]}
{'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None),
snic(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None),
snic(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)],
'wlan0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
snic(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None),
snic(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}
>>>

See also `examples/ifconfig.py <https://github.com/giampaolo/psutil/blob/master/examples/ifconfig.py>`__
Expand All @@ -446,6 +451,8 @@ Network

*New in 3.0.0*

*Changed in 3.1.2:* *ptp* field was added.

.. function:: net_if_stats()

Return information about each NIC (network interface card) installed on the
Expand Down
2 changes: 2 additions & 0 deletions examples/ifconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ def main():
print(" broadcast : %s" % addr.broadcast)
if addr.netmask:
print(" netmask : %s" % addr.netmask)
if addr.ptp:
print(" p2p : %s" % addr.ptp)
print("")


Expand Down
15 changes: 10 additions & 5 deletions psutil/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1749,17 +1749,22 @@ def net_if_addrs():
"""Return the addresses associated to each NIC (network interface
card) installed on the system as a dictionary whose keys are the
NIC names and value is a list of namedtuples for each address
assigned to the NIC. Each namedtuple includes 4 fields:
assigned to the NIC. Each namedtuple includes 5 fields:
- family
- address
- netmask
- broadcast
- ptp
'family' can be either socket.AF_INET, socket.AF_INET6 or
psutil.AF_LINK, which refers to a MAC address.
'address' is the primary address, 'netmask' and 'broadcast'
may be None.
'address' is the primary address and it is always set.
'netmask' and 'broadcast' and 'ptp' may be None.
'ptp' stands for "point to point" and references the destination
address on a point to point interface (tipically a VPN).
'broadcast' and 'ptp' are mutually exclusive.
Note: you can have more than one address of the same family
associated with each interface.
"""
Expand All @@ -1769,7 +1774,7 @@ def net_if_addrs():
rawlist = _psplatform.net_if_addrs()
rawlist.sort(key=lambda x: x[1]) # sort by family
ret = collections.defaultdict(list)
for name, fam, addr, mask, broadcast in rawlist:
for name, fam, addr, mask, broadcast, ptp in rawlist:
if has_enums:
try:
fam = socket.AddressFamily(fam)
Expand All @@ -1782,7 +1787,7 @@ def net_if_addrs():
# We re-set the family here so that repr(family)
# will show AF_LINK rather than AF_PACKET
fam = _psplatform.AF_LINK
ret[name].append(_common.snic(fam, addr, mask, broadcast))
ret[name].append(_common.snic(fam, addr, mask, broadcast, ptp))
return dict(ret)


Expand Down
2 changes: 1 addition & 1 deletion psutil/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ def socktype_to_enum(num):
sconn = namedtuple('sconn', ['fd', 'family', 'type', 'laddr', 'raddr',
'status', 'pid'])
# psutil.net_if_addrs()
snic = namedtuple('snic', ['family', 'address', 'netmask', 'broadcast'])
snic = namedtuple('snic', ['family', 'address', 'netmask', 'broadcast', 'ptp'])
# psutil.net_if_stats()
snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu'])

Expand Down
33 changes: 29 additions & 4 deletions psutil/_psutil_posix.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#ifdef __linux
#include <netdb.h>
#include <linux/if_packet.h>
#include <linux/if.h>
#endif // end linux

#if defined(__FreeBSD__) || defined(__APPLE__)
Expand Down Expand Up @@ -163,6 +164,7 @@ psutil_net_if_addrs(PyObject* self, PyObject* args)
PyObject *py_address = NULL;
PyObject *py_netmask = NULL;
PyObject *py_broadcast = NULL;
PyObject *py_ptp = NULL;

if (py_retlist == NULL)
return NULL;
Expand All @@ -185,20 +187,41 @@ psutil_net_if_addrs(PyObject* self, PyObject* args)
py_netmask = psutil_convert_ipaddr(ifa->ifa_netmask, family);
if (py_netmask == NULL)
goto error;

#ifdef __linux
py_broadcast = psutil_convert_ipaddr(ifa->ifa_ifu.ifu_broadaddr, family);
if (ifa->ifa_flags & IFF_BROADCAST) {
py_broadcast = psutil_convert_ipaddr(ifa->ifa_broadaddr, family);
Py_INCREF(Py_None);
py_ptp = Py_None;
}
else if (ifa->ifa_flags & IFF_POINTOPOINT) {
py_ptp = psutil_convert_ipaddr(ifa->ifa_dstaddr, family);
Py_INCREF(Py_None);
py_broadcast = Py_None;
}
else {
Py_INCREF(Py_None);
Py_INCREF(Py_None);
py_broadcast = Py_None;
py_ptp = Py_None;
}
#else
// TODO
py_broadcast = psutil_convert_ipaddr(ifa->ifa_broadaddr, family);
Py_INCREF(Py_None);
py_ptp = Py_None;
#endif
if (py_broadcast == NULL)

if ((py_broadcast == NULL) || (py_ptp == NULL))
goto error;
py_tuple = Py_BuildValue(
"(siOOO)",
"(siOOOO)",
ifa->ifa_name,
family,
py_address,
py_netmask,
py_broadcast
py_broadcast,
py_ptp
);

if (! py_tuple)
Expand All @@ -209,6 +232,7 @@ psutil_net_if_addrs(PyObject* self, PyObject* args)
Py_DECREF(py_address);
Py_DECREF(py_netmask);
Py_DECREF(py_broadcast);
Py_DECREF(py_ptp);
}

freeifaddrs(ifaddr);
Expand All @@ -222,6 +246,7 @@ psutil_net_if_addrs(PyObject* self, PyObject* args)
Py_XDECREF(py_address);
Py_XDECREF(py_netmask);
Py_XDECREF(py_broadcast);
Py_XDECREF(py_ptp);
return NULL;
}

Expand Down
8 changes: 7 additions & 1 deletion test/test_psutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -1069,13 +1069,19 @@ def test_net_if_addrs(self):
s = socket.socket(af, socktype, proto)
with contextlib.closing(s):
s.bind(sa)
for ip in (addr.address, addr.netmask, addr.broadcast):
for ip in (addr.address, addr.netmask, addr.broadcast,
addr.ptp):
if ip is not None:
# TODO: skip AF_INET6 for now because I get:
# AddressValueError: Only hex digits permitted in
# u'c6f3%lxcbr0' in u'fe80::c8e0:fff:fe54:c6f3%lxcbr0'
if addr.family != AF_INET6:
check_ip_address(ip, addr.family)
# broadcast and ptp addresses are mutually exclusive
if addr.broadcast:
self.assertIsNone(addr.ptp)
elif addr.ptp:
self.assertIsNone(addr.broadcast)

if BSD or OSX or SUNOS:
if hasattr(socket, "AF_LINK"):
Expand Down

0 comments on commit 725dfb4

Please sign in to comment.