summaryrefslogtreecommitdiff
path: root/python/vyos/ifconfig/interface.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/vyos/ifconfig/interface.py')
-rw-r--r--python/vyos/ifconfig/interface.py161
1 files changed, 109 insertions, 52 deletions
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index 62c30dbf7..61f2c6482 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -1,4 +1,4 @@
-# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2020 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -42,6 +42,7 @@ from vyos.ifconfig.control import Control
from vyos.ifconfig.dhcp import DHCP
from vyos.ifconfig.vrrp import VRRP
from vyos.ifconfig.operational import Operational
+from vyos.ifconfig import Section
class Interface(Control):
@@ -133,8 +134,12 @@ class Interface(Control):
'validate': assert_boolean,
'location': '/proc/sys/net/ipv4/conf/{ifname}/arp_ignore',
},
+ 'ipv6_accept_ra': {
+ 'validate': lambda ara: assert_range(ara,0,3),
+ 'location': '/proc/sys/net/ipv6/conf/{ifname}/accept_ra',
+ },
'ipv6_autoconf': {
- 'validate': lambda fwd: assert_range(fwd,0,2),
+ 'validate': lambda aco: assert_range(aco,0,2),
'location': '/proc/sys/net/ipv6/conf/{ifname}/autoconf',
},
'ipv6_forwarding': {
@@ -219,7 +224,7 @@ class Interface(Control):
else:
raise Exception('interface "{}" not found'.format(self.config['ifname']))
- # list of assigned IP addresses
+ # temporary list of assigned IP addresses
self._addr = []
self.operational = self.OperationalClass(ifname)
@@ -240,15 +245,11 @@ class Interface(Control):
>>> i = Interface('eth0')
>>> i.remove()
"""
- # stop DHCP(v6) if running
- self.dhcp.v4.delete()
- self.dhcp.v6.delete()
# remove all assigned IP addresses from interface - this is a bit redundant
# as the kernel will remove all addresses on interface deletion, but we
# can not delete ALL interfaces, see below
- for addr in self.get_addr():
- self.del_addr(addr)
+ self.flush_addrs()
# ---------------------------------------------------------------------
# Any class can define an eternal regex in its definition
@@ -412,6 +413,21 @@ class Interface(Control):
"""
return self.set_interface('arp_ignore', arp_ignore)
+ def set_ipv6_accept_ra(self, accept_ra):
+ """
+ Accept Router Advertisements; autoconfigure using them.
+
+ It also determines whether or not to transmit Router Solicitations.
+ If and only if the functional setting is to accept Router
+ Advertisements, Router Solicitations will be transmitted.
+
+ 0 - Do not accept Router Advertisements.
+ 1 - (default) Accept Router Advertisements if forwarding is disabled.
+ 2 - Overrule forwarding behaviour. Accept Router Advertisements even if
+ forwarding is enabled.
+ """
+ return self.set_interface('ipv6_accept_ra', accept_ra)
+
def set_ipv6_autoconf(self, autoconf):
"""
Autoconfigure addresses using Prefix Information in Router
@@ -419,39 +435,28 @@ class Interface(Control):
"""
return self.set_interface('ipv6_autoconf', autoconf)
- def set_ipv6_eui64_address(self, prefix):
+ def add_ipv6_eui64_address(self, prefix):
"""
Extended Unique Identifier (EUI), as per RFC2373, allows a host to
- assign iteslf a unique IPv6 address based on a given IPv6 prefix.
+ assign itself a unique IPv6 address based on a given IPv6 prefix.
- If prefix is passed address is assigned, if prefix is '' address is
- removed from interface.
+ Calculate the EUI64 from the interface's MAC, then assign it
+ with the given prefix to the interface.
"""
- # if prefix is an empty string convert it to None so mac2eui64 works
- # as expected
- if not prefix:
- prefix = None
eui64 = mac2eui64(self.get_mac(), prefix)
+ prefixlen = prefix.split('/')[1]
+ self.add_addr(f'{eui64}/{prefixlen}')
- if not prefix:
- # if prefix is empty - thus removed - we need to walk through all
- # interface IPv6 addresses and find the one with the calculated
- # EUI-64 identifier. The address is then removed
- for addr in self.get_addr():
- addr_wo_prefix = addr.split('/')[0]
- if is_ipv6(addr_wo_prefix):
- if eui64 in IPv6Address(addr_wo_prefix).exploded:
- self.del_addr(addr)
-
- return None
+ def del_ipv6_eui64_address(self, prefix):
+ """
+ Delete the address based on the interface's MAC-based EUI64
+ combined with the prefix address.
+ """
+ eui64 = mac2eui64(self.get_mac(), prefix)
+ prefixlen = prefix.split('/')[1]
+ self.del_addr(f'{eui64}/{prefixlen}')
- # calculate and add EUI-64 IPv6 address
- if IPv6Network(prefix):
- # we also need to take the subnet length into account
- prefix = prefix.split('/')[1]
- eui64 = f'{eui64}/{prefix}'
- self.add_addr(eui64 )
def set_ipv6_forwarding(self, forwarding):
"""
@@ -632,7 +637,8 @@ class Interface(Control):
def add_addr(self, addr):
"""
Add IP(v6) address to interface. Address is only added if it is not
- already assigned to that interface.
+ already assigned to that interface. Address format must be validated
+ and compressed/normalized before calling this function.
addr: can be an IPv4 address, IPv6 address, dhcp or dhcpv6!
IPv4: add IPv4 address to interface
@@ -640,6 +646,7 @@ class Interface(Control):
dhcp: start dhclient (IPv4) on interface
dhcpv6: start dhclient (IPv6) on interface
+ Returns False if address is already assigned and wasn't re-added.
Example:
>>> from vyos.ifconfig import Interface
>>> j = Interface('eth0')
@@ -648,32 +655,41 @@ class Interface(Control):
>>> j.get_addr()
['192.0.2.1/24', '2001:db8::ffff/64']
"""
+ # XXX: normalize/compress with ipaddress if calling functions don't?
+ # is subnet mask always passed, and in the same way?
- # cache new IP address which is assigned to interface
- self._addr.append(addr)
+ # do not add same address twice
+ if addr in self._addr:
+ return False
- # we can not have both DHCP and static IPv4 addresses assigned to an interface
- if 'dhcp' in self._addr:
- for addr in self._addr:
- # do not change below 'if' ordering esle you will get an exception as:
- # ValueError: 'dhcp' does not appear to be an IPv4 or IPv6 address
- if addr != 'dhcp' and is_ipv4(addr):
- raise ConfigError(
- "Can't configure both static IPv4 and DHCP address on the same interface")
+ # we can't have both DHCP and static IPv4 addresses assigned
+ for a in self._addr:
+ if ( ( addr == 'dhcp' and a != 'dhcpv6' and is_ipv4(a) ) or
+ ( a == 'dhcp' and addr != 'dhcpv6' and is_ipv4(addr) ) ):
+ raise ConfigError((
+ "Can't configure both static IPv4 and DHCP address "
+ "on the same interface"))
+ # add to interface
if addr == 'dhcp':
self.dhcp.v4.set()
elif addr == 'dhcpv6':
self.dhcp.v6.set()
+ elif not is_intf_addr_assigned(self.ifname, addr):
+ self._cmd(f'ip addr add "{addr}" dev "{self.ifname}"')
else:
- if not is_intf_addr_assigned(self.config['ifname'], addr):
- cmd = 'ip addr add "{}" dev "{}"'.format(addr, self.config['ifname'])
- return self._cmd(cmd)
+ return False
+
+ # add to cache
+ self._addr.append(addr)
+
+ return True
def del_addr(self, addr):
"""
- Delete IP(v6) address to interface. Address is only added if it is
- assigned to that interface.
+ Delete IP(v6) address from interface. Address is only deleted if it is
+ assigned to that interface. Address format must be exactly the same as
+ was used when adding the address.
addr: can be an IPv4 address, IPv6 address, dhcp or dhcpv6!
IPv4: delete IPv4 address from interface
@@ -681,6 +697,7 @@ class Interface(Control):
dhcp: stop dhclient (IPv4) on interface
dhcpv6: stop dhclient (IPv6) on interface
+ Returns False if address isn't already assigned and wasn't deleted.
Example:
>>> from vyos.ifconfig import Interface
>>> j = Interface('eth0')
@@ -692,11 +709,51 @@ class Interface(Control):
>>> j.get_addr()
['2001:db8::ffff/64']
"""
+
+ # remove from interface
if addr == 'dhcp':
self.dhcp.v4.delete()
elif addr == 'dhcpv6':
self.dhcp.v6.delete()
+ elif is_intf_addr_assigned(self.ifname, addr):
+ self._cmd(f'ip addr del "{addr}" dev "{self.ifname}"')
else:
- if is_intf_addr_assigned(self.config['ifname'], addr):
- cmd = 'ip addr del "{}" dev "{}"'.format(addr, self.config['ifname'])
- return self._cmd(cmd)
+ return False
+
+ # remove from cache
+ if addr in self._addr:
+ self._addr.remove(addr)
+
+ return True
+
+ def flush_addrs(self):
+ """
+ Flush all addresses from an interface, including DHCP.
+
+ Will raise an exception on error.
+ """
+ # stop DHCP(v6) if running
+ self.dhcp.v4.delete()
+ self.dhcp.v6.delete()
+
+ # flush all addresses
+ self._cmd(f'ip addr flush dev "{self.ifname}"')
+
+ def add_to_bridge(self, br):
+ """
+ Adds the interface to the bridge with the passed port config.
+
+ Returns False if bridge doesn't exist.
+ """
+
+ # check if the bridge exists (on boot it doesn't)
+ if br not in Section.interfaces('bridge'):
+ return False
+
+ self.flush_addrs()
+ # add interface to bridge - use Section.klass to get BridgeIf class
+ Section.klass(br)(br, create=False).add_port(self.ifname)
+
+ # TODO: port config (STP)
+
+ return True