Home | History | Annotate | Download | only in network
      1 # Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import logging
      6 
      7 from autotest_lib.client.common_lib import error
      8 
      9 def from_addr(addr, prefix_len=None):
     10     """Build a Netblock object.
     11 
     12     @param addr: string IP address with optional prefix length
     13             (e.g. '192.168.1.1' or '192.168.1.1/24'). If |addr| has no
     14             prefix length, then use the |prefix_len| parameter.
     15     @param prefix_len: int number of bits forming the IP subnet prefix for
     16             |addr|. This value will be preferred to the parsed value if
     17             |addr| has a prefix length as well. If |addr|
     18             has no prefix length and |prefix_len| is None, then an error
     19             will be thrown.
     20 
     21     """
     22     if addr is None:
     23         raise error.TestError('netblock.from_addr() expects non-None addr '
     24                               'parameter.')
     25 
     26     prefix_sep_count = addr.count('/')
     27     if prefix_sep_count > 1:
     28         raise error.TestError('Invalid IP address found: "%s".' % addr)
     29 
     30     if prefix_sep_count == 1:
     31         addr_str, prefix_len_str = addr.split('/')
     32     else:
     33         # No prefix separator.  Assume addr looks like '192.168.1.1'
     34         addr_str = addr
     35         # Rely on passed in |prefix_len|
     36         prefix_len_str = None
     37 
     38     if prefix_len is not None and prefix_len_str is not None:
     39         logging.warning('Ignoring parsed prefix length of %s in favor of '
     40                         'passed in value %d', prefix_len_str, prefix_len)
     41     elif prefix_len is not None and prefix_len_str is None:
     42         pass
     43     elif prefix_len is None and prefix_len_str is not None:
     44         prefix_len = int(prefix_len_str)
     45     else:
     46         raise error.TestError('Cannot construct netblock without knowing '
     47                               'prefix length for addr: "%s".' % addr)
     48 
     49     return Netblock(addr_str, prefix_len)
     50 
     51 
     52 class Netblock(object):
     53     """Utility class for transforming netblock address to related strings."""
     54 
     55     @staticmethod
     56     def _octets_to_addr(octets):
     57         """Transform a list of bytes into a string IP address.
     58 
     59         @param octets list of ints (e.g. [192.168.0.1]).
     60         @return string IP address (e.g. '192.168.0.1.').
     61 
     62         """
     63         return '.'.join(map(str, octets))
     64 
     65 
     66     @staticmethod
     67     def _int_to_octets(num):
     68         """Tranform a 32 bit number into a list of 4 octets.
     69 
     70         @param num: number to convert to octets.
     71         @return list of int values <= 8 bits long.
     72 
     73         """
     74         return [(num >> s) & 0xff for s in (24, 16, 8, 0)]
     75 
     76 
     77     @property
     78     def netblock(self):
     79         """@return the IPv4 address/prefix, e.g., '192.168.0.1/24'."""
     80         return '/'.join([self._octets_to_addr(self._octets),
     81                          str(self.prefix_len)])
     82 
     83 
     84     @property
     85     def netmask(self):
     86         """@return the IPv4 netmask, e.g., '255.255.255.0'."""
     87         return self._octets_to_addr(self._mask_octets)
     88 
     89 
     90     @property
     91     def prefix_len(self):
     92         """@return the IPv4 prefix len, e.g., 24."""
     93         return self._prefix_len
     94 
     95 
     96     @property
     97     def subnet(self):
     98         """@return the IPv4 subnet, e.g., '192.168.0.0'."""
     99         octets = [a & m for a, m in zip(self._octets, self._mask_octets)]
    100         return self._octets_to_addr(octets)
    101 
    102 
    103     @property
    104     def broadcast(self):
    105         """@return the IPv4 broadcast address, e.g., '192.168.0.255'."""
    106         octets = [a | (m ^ 0xff)
    107                   for a, m in zip(self._octets, self._mask_octets)]
    108         return self._octets_to_addr(octets)
    109 
    110 
    111     @property
    112     def addr(self):
    113         """@return the IPv4 address, e.g., '192.168.0.1'."""
    114         return self._octets_to_addr(self._octets)
    115 
    116 
    117     def __init__(self, addr_str, prefix_len):
    118         """Construct a Netblock.
    119 
    120         @param addr_str: string IP address (e.g. '192.168.1.1').
    121         @param prefix_len: int length of subnet prefix (e.g. 24).
    122 
    123         """
    124         self._octets = map(int, addr_str.split('.'))
    125         mask_bits = (-1 << (32 - prefix_len)) & 0xffffffff
    126         self._mask_octets = self._int_to_octets(mask_bits)
    127         self._prefix_len = prefix_len
    128 
    129 
    130     def get_addr_in_block(self, offset):
    131         """Get an address in a subnet.
    132 
    133         For instance if this netblock represents 192.168.0.1/24,
    134         then get_addr_in_block(5) would return 192.168.0.5.
    135 
    136         @param offset int offset in block, (e.g. 5).
    137         @return string address (e.g. '192.168.0.5').
    138 
    139         """
    140         offset = self._int_to_octets(offset)
    141         octets = [(a & m) + o
    142                   for a, m, o in zip(self._octets, self._mask_octets, offset)]
    143         return self._octets_to_addr(octets)
    144