151 lines
4.8 KiB
Python
151 lines
4.8 KiB
Python
# Lint as: python2, python3
|
|
# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import print_function
|
|
|
|
import logging
|
|
from six.moves import map
|
|
from six.moves import zip
|
|
|
|
from autotest_lib.client.common_lib import error
|
|
|
|
def from_addr(addr, prefix_len=None):
|
|
"""Build a Netblock object.
|
|
|
|
@param addr: string IP address with optional prefix length
|
|
(e.g. '192.168.1.1' or '192.168.1.1/24'). If |addr| has no
|
|
prefix length, then use the |prefix_len| parameter.
|
|
@param prefix_len: int number of bits forming the IP subnet prefix for
|
|
|addr|. This value will be preferred to the parsed value if
|
|
|addr| has a prefix length as well. If |addr|
|
|
has no prefix length and |prefix_len| is None, then an error
|
|
will be thrown.
|
|
|
|
"""
|
|
if addr is None:
|
|
raise error.TestError('netblock.from_addr() expects non-None addr '
|
|
'parameter.')
|
|
|
|
prefix_sep_count = addr.count('/')
|
|
if prefix_sep_count > 1:
|
|
raise error.TestError('Invalid IP address found: "%s".' % addr)
|
|
|
|
if prefix_sep_count == 1:
|
|
addr_str, prefix_len_str = addr.split('/')
|
|
else:
|
|
# No prefix separator. Assume addr looks like '192.168.1.1'
|
|
addr_str = addr
|
|
# Rely on passed in |prefix_len|
|
|
prefix_len_str = None
|
|
|
|
if prefix_len is not None and prefix_len_str is not None:
|
|
logging.warning('Ignoring parsed prefix length of %s in favor of '
|
|
'passed in value %d', prefix_len_str, prefix_len)
|
|
elif prefix_len is not None and prefix_len_str is None:
|
|
pass
|
|
elif prefix_len is None and prefix_len_str is not None:
|
|
prefix_len = int(prefix_len_str)
|
|
else:
|
|
raise error.TestError('Cannot construct netblock without knowing '
|
|
'prefix length for addr: "%s".' % addr)
|
|
|
|
return Netblock(addr_str, prefix_len)
|
|
|
|
|
|
class Netblock(object):
|
|
"""Utility class for transforming netblock address to related strings."""
|
|
|
|
@staticmethod
|
|
def _octets_to_addr(octets):
|
|
"""Transform a list of bytes into a string IP address.
|
|
|
|
@param octets list of ints (e.g. [192.168.0.1]).
|
|
@return string IP address (e.g. '192.168.0.1.').
|
|
|
|
"""
|
|
return '.'.join(map(str, octets))
|
|
|
|
|
|
@staticmethod
|
|
def _int_to_octets(num):
|
|
"""Tranform a 32 bit number into a list of 4 octets.
|
|
|
|
@param num: number to convert to octets.
|
|
@return list of int values <= 8 bits long.
|
|
|
|
"""
|
|
return [(num >> s) & 0xff for s in (24, 16, 8, 0)]
|
|
|
|
|
|
@property
|
|
def netblock(self):
|
|
"""@return the IPv4 address/prefix, e.g., '192.168.0.1/24'."""
|
|
return '/'.join([self._octets_to_addr(self._octets),
|
|
str(self.prefix_len)])
|
|
|
|
|
|
@property
|
|
def netmask(self):
|
|
"""@return the IPv4 netmask, e.g., '255.255.255.0'."""
|
|
return self._octets_to_addr(self._mask_octets)
|
|
|
|
|
|
@property
|
|
def prefix_len(self):
|
|
"""@return the IPv4 prefix len, e.g., 24."""
|
|
return self._prefix_len
|
|
|
|
|
|
@property
|
|
def subnet(self):
|
|
"""@return the IPv4 subnet, e.g., '192.168.0.0'."""
|
|
octets = [a & m for a, m in zip(self._octets, self._mask_octets)]
|
|
return self._octets_to_addr(octets)
|
|
|
|
|
|
@property
|
|
def broadcast(self):
|
|
"""@return the IPv4 broadcast address, e.g., '192.168.0.255'."""
|
|
octets = [a | (m ^ 0xff)
|
|
for a, m in zip(self._octets, self._mask_octets)]
|
|
return self._octets_to_addr(octets)
|
|
|
|
|
|
@property
|
|
def addr(self):
|
|
"""@return the IPv4 address, e.g., '192.168.0.1'."""
|
|
return self._octets_to_addr(self._octets)
|
|
|
|
|
|
def __init__(self, addr_str, prefix_len):
|
|
"""Construct a Netblock.
|
|
|
|
@param addr_str: string IP address (e.g. '192.168.1.1').
|
|
@param prefix_len: int length of subnet prefix (e.g. 24).
|
|
|
|
"""
|
|
self._octets = list(map(int, addr_str.split('.')))
|
|
mask_bits = (-1 << (32 - prefix_len)) & 0xffffffff
|
|
self._mask_octets = self._int_to_octets(mask_bits)
|
|
self._prefix_len = prefix_len
|
|
|
|
|
|
def get_addr_in_block(self, offset):
|
|
"""Get an address in a subnet.
|
|
|
|
For instance if this netblock represents 192.168.0.1/24,
|
|
then get_addr_in_block(5) would return 192.168.0.5.
|
|
|
|
@param offset int offset in block, (e.g. 5).
|
|
@return string address (e.g. '192.168.0.5').
|
|
|
|
"""
|
|
offset = self._int_to_octets(offset)
|
|
octets = [(a & m) + o
|
|
for a, m, o in zip(self._octets, self._mask_octets, offset)]
|
|
return self._octets_to_addr(octets)
|