Update from Peter.

This commit is contained in:
Brett Cannon 2009-08-20 19:56:05 +00:00
parent 4b8dac5847
commit fbc70cfb64
1 changed files with 164 additions and 38 deletions

View File

@ -66,44 +66,6 @@ Rationale:
property addresses in an IP network obviously don't have the same property addresses in an IP network obviously don't have the same
properties, they're simply 32 or 128 bit numbers. properties, they're simply 32 or 128 bit numbers.
- Lazy evaluation combined with aggressive caching of network elements.
(the following example is for IPv6Network objects but the exact same
properties apply to IPv6Network objects).
As mentioned, an IP network object is defined by a number of properties.
The object
>>> IPv4Network('1.1.1.0/24')
has a number of IPv4Address properties
>>> o = ipaddr.IPv4Network('1.1.1.0/24')
>>> o.network
IPv4Address('1.1.1.0')
>>> o.broadcast
IPv4Address('1.1.1.255')
>>> o.network
IPv4Address('1.1.1.0')
>>> o.hostmask
IPv4Address('0.0.0.255')
If we were to compute them all at object creation time, we would incur a
non-negligible performance hit. Since these properties are required to
define the object completely but their values aren't always of interest to
the programmer, their computation should be done only when requested.
However, in order to avoid the performance hit in the case where one
attribute for a particular object is requested repeatedly (and continuously
recomputed), the results of the first computation should be cached and only
re-generated should the object properties change. The network properties
would change if, for instance, the prefix length was changed, resulting in
either a larger (decreasing prefix length) or a smaller (increasing prefix
length) network.
- Treat network elements as lists (in so far as it's possible). - Treat network elements as lists (in so far as it's possible).
Treating IP networks as lists is a natural extension from viewing the Treating IP networks as lists is a natural extension from viewing the
@ -127,6 +89,168 @@ Rationale:
needs. needs.
Specification:
A slightly more detailed look at the library follows.
- Multiple ways of displaying an IP Address.
Not everyone will want to display the same information in the same format;
IP addresses in cisco syntax are represented by network/hostmask, junipers
are (network/IP)/prefixlength and IPTables are (network/IP)/(prefixlength/
netmask). The ipaddr library provides mulitple ways to display an address.
In [1]: ipaddr.IP('1.1.1.1').with_prefixlen
Out[1]: '1.1.1.1/32'
In [1]: ipaddr.IP('1.1.1.1').with_netmask
Out[1]: '1.1.1.1/255.255.255.255'
In [1]: ipaddr.IP('1.1.1.1').with_hostmask
Out[1]: '1.1.1.1/0.0.0.0'
the same applies to IPv6
- Lazy evaluation combined with aggressive caching of network elements.
(the following example is for IPv6Network objects but the exact same
properties apply to IPv6Network objects).
As mentioned, an IP network object is defined by a number of properties.
The object
In [1]: IPv4Network('1.1.1.0/24')
has a number of IPv4Address properties
In [1]: o = ipaddr.IPv4Network('1.1.1.0/24')
In [2]: o.network
Out[2]: IPv4Address('1.1.1.0')
In [3]: o.broadcast
Out[3]: IPv4Address('1.1.1.255')
In [4]: o.hostmask
Out[4]: IPv4Address('0.0.0.255')
If we were to compute them all at object creation time, we would incur a
non-negligible performance hit. Since these properties are required to
define the object completely but their values aren't always of interest to
the programmer, their computation should be done only when requested.
However, in order to avoid the performance hit in the case where one
attribute for a particular object is requested repeatedly (and continuously
recomputed), the results of the computation should be cached.
- Address list summarization.
ipaddr supports easy summarization of lists of possibly contigious
addresses, as this is something network administrators constantly find
themselves doing. This currently works in a number of ways.
1. collapse_address_list([list]):
Given a list of networks, ipaddr will collapse the list into the smallest
possible list of networks that wholey contain the addresses supplied.
In [1]: ipaddr.collapse_address_list([ipaddr.IP('1.1.0.0/24'),
...: ipaddr.IP('1.1.1.0/24')])
Out[1]: [IPv4Network('1.1.0.0/23')]
more elaborately:
In [1]: ipaddr.collapse_address_list([ipaddr.IP(x) \
...: for x in ipaddr.IP('1.1.0.0/23')])
Out[1]: [IPv4Network('1.1.0.0/23')]
2. summarize_address_range(first, last). (in a pending change list [2])
Given a start and end address, ipaddr will provide the smallest number of
networks to cover the given range.
In [1]: ipaddr.summarize_address_range(ipaddr.IPv4Address('1.1.1.0'),
...: ipaddr.IPv4Address('2.2.2.0'))
Out[1]:
[IPv4Network('1.1.1.0/24'),
IPv4Network('1.1.2.0/23'),
IPv4Network('1.1.4.0/22'),
IPv4Network('1.1.8.0/21'),
IPv4Network('1.1.16.0/20'),
IPv4Network('1.1.32.0/19'),
IPv4Network('1.1.64.0/18'),
IPv4Network('1.1.128.0/17'),
IPv4Network('1.2.0.0/15'),
IPv4Network('1.4.0.0/14'),
IPv4Network('1.8.0.0/13'),
IPv4Network('1.16.0.0/12'),
IPv4Network('1.32.0.0/11'),
IPv4Network('1.64.0.0/10'),
IPv4Network('1.128.0.0/9'),
IPv4Network('2.0.0.0/15'),
IPv4Network('2.2.0.0/23'),
IPv4Network('2.2.2.0/32')]
- Address Exclusion.
Used somewhat less often, but all the more annoying, is the case where an
programmer would want "all of the addresses in a newtork *except* these".
ipaddr performs this exclusion equally well for IPv4 and IPv6 networks
and collapses the resulting address list.
In [1]: ipaddr.IP('1.1.0.0/15').address_exclude(ipaddr.IP('1.1.1.0/24'))
Out[1]:
[IPv4Network('1.0.0.0/16'),
IPv4Network('1.1.0.0/24'),
IPv4Network('1.1.2.0/23'),
IPv4Network('1.1.4.0/22'),
IPv4Network('1.1.8.0/21'),
IPv4Network('1.1.16.0/20'),
IPv4Network('1.1.32.0/19'),
IPv4Network('1.1.64.0/18'),
IPv4Network('1.1.128.0/17')]
In [1]: ipaddr.IP('::1/96').address_exclude(ipaddr.IP('::1/112'))
Out[1]:
[IPv6Network('::1:0/112'),
IPv6Network('::2:0/111'),
IPv6Network('::4:0/110'),
IPv6Network('::8:0/109'),
IPv6Network('::10:0/108'),
IPv6Network('::20:0/107'),
IPv6Network('::40:0/106'),
IPv6Network('::80:0/105'),
IPv6Network('::100:0/104'),
IPv6Network('::200:0/103'),
IPv6Network('::400:0/102'),
IPv6Network('::800:0/101'),
IPv6Network('::1000:0/100'),
IPv6Network('::2000:0/99'),
IPv6Network('::4000:0/98'),
IPv6Network('::8000:0/97')]
- IPv6 address compression. (in a pending changelist [3])
By default, IPv6 addresses are compressed internally (see the method
BaseV6._compress_hextets), but ipaddr makes both the compressed and the
exploded representations available.
In [1]: ipaddr.IP('::1').compressed
Out[1]: '::1/128'
In [2]: ipaddr.IP('::1').exploded
Out[2]: '0000:0000:0000:0000:0000:0000:0000:1/128'
In [3]: ipaddr.IPv6Address('::1').exploded
Out[3]: '0000:0000:0000:0000:0000:0000:0000:0001'
In [4]: ipaddr.IPv6Address('::1').compressed
Out[4]: '::1'
(the same methods exist for IPv4 networks and addresses, but they're
just stubs for returning the normal __str__ representation).
Reference Implementation: Reference Implementation:
A reference implementation is available at: A reference implementation is available at:
@ -136,6 +260,8 @@ Reference Implementation:
References: References:
[1] http://bugs.python.org/issue3959 [1] http://bugs.python.org/issue3959
[2] http://codereview.appspot.com/67107
[3] http://codereview.appspot.com/110044
Copyright: Copyright: