mirror of
https://github.com/CumulusNetworks/ifupdown2.git
synced 2024-05-06 15:54:50 +00:00
7c8627f876
Signed-off-by: Julien Fortin <jfortin@nvidia.com>
190 lines
5.0 KiB
Python
190 lines
5.0 KiB
Python
# Copyright (C) 2019, 2020 Cumulus Networks, Inc. all rights reserved
|
|
#
|
|
# 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; 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.
|
|
#
|
|
# https://www.gnu.org/licenses/gpl-2.0-standalone.html
|
|
#
|
|
# Author:
|
|
# Julien Fortin, julien@cumulusnetworks.com
|
|
#
|
|
|
|
import ipaddress
|
|
|
|
|
|
class IPNetwork:
|
|
|
|
__INIT_WITH_PREFIXLEN = 0b01
|
|
|
|
ip_family_handler = {
|
|
0: ipaddress.ip_address,
|
|
4: ipaddress.IPv4Address,
|
|
6: ipaddress.IPv6Address
|
|
}
|
|
|
|
def __init__(self, ip, prefixlen=None, scope=0, family=0):
|
|
|
|
if isinstance(ip, IPNetwork):
|
|
prefixlen = ip.prefixlen
|
|
scope = ip.scope
|
|
family = ip.version
|
|
ip = ip.ip
|
|
|
|
self.__scope = scope
|
|
self.__flags = 0
|
|
|
|
if isinstance(ip, int):
|
|
self._ip = self.ip_family_handler[family](ip)
|
|
else:
|
|
if not prefixlen:
|
|
try:
|
|
ip, prefixlen = ip.split("/")
|
|
except ValueError:
|
|
prefixlen = None
|
|
|
|
self._ip = ipaddress.ip_address(ip)
|
|
|
|
if not prefixlen:
|
|
self.__prefixlen = 32 if self.ip.version == 4 else 128
|
|
else:
|
|
try:
|
|
self.__prefixlen = int(prefixlen)
|
|
except ValueError:
|
|
if isinstance(prefixlen, str) and "." in prefixlen:
|
|
self.__prefixlen = ipaddress.ip_network("{}/{}".format(self.ip, prefixlen), strict=False).prefixlen
|
|
else:
|
|
raise
|
|
|
|
if (self.ip.version == 4 and self.prefixlen != 32) or (self.ip.version == 6 and self.prefixlen != 128):
|
|
self.__flags |= self.__INIT_WITH_PREFIXLEN
|
|
|
|
def __hash__(self):
|
|
return int(self._ip) ^ self.__prefixlen ^ self.version
|
|
|
|
def __eq__(self, other) -> bool:
|
|
return other \
|
|
and self.version == other.version \
|
|
and self._ip == other.ip \
|
|
and self.__prefixlen == other.prefixlen
|
|
|
|
def __repr__(self):
|
|
return "{}/{}".format(self._ip, self.__prefixlen)
|
|
|
|
def __int__(self):
|
|
return int(self._ip)
|
|
|
|
__str__ = __repr__
|
|
|
|
@property
|
|
def ip(self):
|
|
return self._ip
|
|
|
|
@property
|
|
def packed(self):
|
|
return self._ip.packed
|
|
|
|
@property
|
|
def is_multicast(self):
|
|
return self._ip.is_multicast
|
|
|
|
@property
|
|
def prefixlen(self) -> int:
|
|
return self.__prefixlen
|
|
|
|
@property
|
|
def version(self) -> int:
|
|
return self._ip.version
|
|
|
|
@property
|
|
def scope(self) -> int:
|
|
return self.__scope
|
|
|
|
@property
|
|
def initialized_with_prefixlen(self) -> int:
|
|
return self.__flags & self.__INIT_WITH_PREFIXLEN
|
|
|
|
def ignore_prefixlen(self):
|
|
self.__prefixlen = 32 if self.ip.version == 4 else 128
|
|
|
|
|
|
class IPv4Network(IPNetwork):
|
|
def __init__(self, *args, **kwargs):
|
|
super(IPv4Network, self).__init__(family=4, *args, **kwargs)
|
|
|
|
if self.version != 4:
|
|
self._ip = ipaddress.IPv4Address(self._ip)
|
|
|
|
|
|
class IPv6Network(IPNetwork):
|
|
def __init__(self, *args, **kwargs):
|
|
super(IPv6Network, self).__init__(family=6, *args, **kwargs)
|
|
|
|
if self.version != 6:
|
|
self._ip = ipaddress.IPv6Address(self._ip)
|
|
|
|
|
|
class IPAddress(IPNetwork):
|
|
def __init__(self, ip, prefixlen=None, *args, **kwargs):
|
|
|
|
if isinstance(ip, int):
|
|
raise NotImplementedError
|
|
|
|
if prefixlen is not None:
|
|
self.__raise_exception("{}/{}".format(ip, prefixlen))
|
|
elif "/" in ip:
|
|
self.__raise_exception(ip)
|
|
|
|
super(IPAddress, self).__init__(ip, prefixlen, *args, **kwargs)
|
|
self.ignore_prefixlen()
|
|
|
|
def __repr__(self):
|
|
return str(self._ip)
|
|
|
|
def __raise_exception(self, ip):
|
|
raise ValueError(
|
|
"'%s' does not appear to be an IPv4 or IPv6 address"
|
|
% ip
|
|
)
|
|
|
|
|
|
class IPv4Address(IPv4Network):
|
|
def __init__(self, *args, **kwargs):
|
|
super(IPv4Address, self).__init__(*args, **kwargs)
|
|
self.ignore_prefixlen()
|
|
|
|
def __repr__(self):
|
|
return str(self._ip)
|
|
|
|
def __str__(self):
|
|
return str(self._ip)
|
|
|
|
|
|
class IPv6Address(IPv6Network):
|
|
def __init__(self, *args, **kwargs):
|
|
super(IPv6Address, self).__init__(*args, **kwargs)
|
|
self.ignore_prefixlen()
|
|
|
|
def __repr__(self):
|
|
return str(self._ip)
|
|
|
|
def __str__(self):
|
|
return str(self._ip)
|
|
|
|
|
|
def ip_address(ip):
|
|
try:
|
|
return IPv4Address(ip)
|
|
except Exception:
|
|
return IPv6Address(ip)
|