Add 'state' field to interfaces and sub-interfaces
Assert that children cannot be 'up' of their parent is 'down'. Add tests. Update user-guide.
This commit is contained in:
@ -396,6 +396,17 @@ def get_mtu(yaml, ifname):
|
||||
return 1500
|
||||
|
||||
|
||||
def get_admin_state(yaml, ifname):
|
||||
""" Return True if the interface admin state should be 'up'. Return False
|
||||
if it does not exist, or if it's set to 'down'. """
|
||||
ifname, iface = get_by_name(yaml, ifname)
|
||||
if not iface:
|
||||
return False
|
||||
if not 'state' in iface:
|
||||
return True
|
||||
return iface['state'] == 'up'
|
||||
|
||||
|
||||
def validate_interfaces(yaml):
|
||||
result = True
|
||||
msgs = []
|
||||
@ -410,6 +421,8 @@ def validate_interfaces(yaml):
|
||||
if ifname.startswith("BondEthernet") and (None,None) == bondethernet.get_by_name(yaml, ifname):
|
||||
msgs.append("interface %s does not exist in bondethernets" % ifname)
|
||||
result = False
|
||||
if not 'state' in iface:
|
||||
iface['state'] = 'up'
|
||||
|
||||
iface_mtu = get_mtu(yaml, ifname)
|
||||
iface_lcp = get_lcp(yaml, ifname)
|
||||
@ -473,6 +486,12 @@ def validate_interfaces(yaml):
|
||||
result = False
|
||||
continue
|
||||
|
||||
if not 'state' in sub_iface:
|
||||
sub_iface['state'] = 'up'
|
||||
if sub_iface['state'] == 'up' and iface['state'] == 'down':
|
||||
msgs.append("sub-interface %s cannot be up if parent %s is down" % (sub_ifname, ifname))
|
||||
result = False
|
||||
|
||||
sub_mtu = get_mtu(yaml, sub_ifname)
|
||||
if sub_mtu > iface_mtu:
|
||||
msgs.append("sub-interface %s has MTU %d higher than parent %s MTU %d" % (sub_ifname, sub_iface['mtu'], ifname, iface_mtu))
|
||||
|
@ -51,6 +51,7 @@ interface:
|
||||
addresses: list(ip_interface(),min=1,max=6,required=False)
|
||||
sub-interfaces: map(include('sub-interface'),key=int(min=1,max=4294967295),required=False)
|
||||
l2xc: str(required=False)
|
||||
state: enum('up', 'down', required=False)
|
||||
---
|
||||
sub-interface:
|
||||
description: str(exclude='\'"',len=64,required=False)
|
||||
@ -59,6 +60,7 @@ sub-interface:
|
||||
addresses: list(ip_interface(),required=False)
|
||||
encapsulation: include('encapsulation',required=False)
|
||||
l2xc: str(required=False)
|
||||
state: enum('up', 'down', required=False)
|
||||
---
|
||||
encapsulation:
|
||||
dot1q: int(min=1,max=4095,required=False)
|
||||
|
@ -201,3 +201,10 @@ class TestInterfaceMethods(unittest.TestCase):
|
||||
def test_is_phy(self):
|
||||
self.assertTrue(interface.is_phy(self.cfg, "GigabitEthernet1/0/0"))
|
||||
self.assertFalse(interface.is_phy(self.cfg, "GigabitEthernet1/0/0.100"))
|
||||
|
||||
def test_get_admin_state(self):
|
||||
self.assertFalse(interface.get_admin_state(self.cfg, "notexist"))
|
||||
self.assertFalse(interface.get_admin_state(self.cfg, "GigabitEthernet2/0/0"))
|
||||
self.assertTrue(interface.get_admin_state(self.cfg, "GigabitEthernet1/0/0"))
|
||||
self.assertTrue(interface.get_admin_state(self.cfg, "GigabitEthernet1/0/0.101"))
|
||||
self.assertFalse(interface.get_admin_state(self.cfg, "GigabitEthernet1/0/0.102"))
|
||||
|
@ -212,6 +212,8 @@ exist as a PHY in VPP (ie. `HundredGigabitEthernet12/0/0`) or as a specified `Bo
|
||||
* ***l2xc***: A Layer2 Cross Connect interface name. An `l2xc` will be configured, after which
|
||||
this interface cannot have any L3 configuration (IP addresses or LCP), and neither can the
|
||||
target interface.
|
||||
* ***state***: An optional string that configures the link admin state, either `up` or `down`.
|
||||
If it is not specified, the link is considered admin 'up'.
|
||||
|
||||
Further, top-level interfaces, that is to say those that do not have an encapsulation, are permitted
|
||||
to have any number of sub-interfaces specified by `subid`, an integer between [0,2G), which further
|
||||
|
@ -1,13 +1,17 @@
|
||||
interfaces:
|
||||
GigabitEthernet3/0/0:
|
||||
mtu: 1500
|
||||
state: down
|
||||
description: Not Used
|
||||
GigabitEthernet3/0/1:
|
||||
mtu: 1500
|
||||
state: down
|
||||
description: Not Used
|
||||
HundredGigabitEthernet12/0/0:
|
||||
mtu: 1500
|
||||
state: down
|
||||
description: Not Used
|
||||
HundredGigabitEthernet12/0/1:
|
||||
mtu: 1500
|
||||
state: down
|
||||
description: Not Used
|
||||
|
@ -37,6 +37,7 @@ interface:
|
||||
addresses: list(ip_interface(),min=1,max=6,required=False)
|
||||
sub-interfaces: map(include('sub-interface'),key=int(min=1,max=4294967295),required=False)
|
||||
l2xc: str(required=False)
|
||||
state: enum('up', 'down', required=False)
|
||||
---
|
||||
sub-interface:
|
||||
description: str(exclude='\'"',len=64,required=False)
|
||||
@ -45,6 +46,7 @@ sub-interface:
|
||||
addresses: list(ip_interface(),required=False)
|
||||
encapsulation: include('encapsulation',required=False)
|
||||
l2xc: str(required=False)
|
||||
state: enum('up', 'down', required=False)
|
||||
---
|
||||
encapsulation:
|
||||
dot1q: int(min=1,max=4095,required=False)
|
||||
|
@ -10,9 +10,9 @@ interfaces:
|
||||
description: "This sub-int is invalid because it has no outer dot1q and dot1ad"
|
||||
encapsulation:
|
||||
inner-dot1q: 1000
|
||||
|
||||
102:
|
||||
description: "This sub-int is has the same encap as 103"
|
||||
state: down
|
||||
103:
|
||||
description: "This sub-int is has the same encap as 102"
|
||||
encapsulation:
|
||||
@ -59,6 +59,7 @@ interfaces:
|
||||
GigabitEthernet2/0/0:
|
||||
description: "This interface has no sub-ints"
|
||||
lcp: "e2"
|
||||
state: down
|
||||
|
||||
GigabitEthernet3/0/0:
|
||||
l2xc: GigabitEthernet3/0/1
|
||||
|
17
unittest/yaml/error-subinterface9.yaml
Normal file
17
unittest/yaml/error-subinterface9.yaml
Normal file
@ -0,0 +1,17 @@
|
||||
test:
|
||||
description: "A sub-interface cannot be up if its parent is down."
|
||||
errors:
|
||||
expected:
|
||||
- "sub-interface .* cannot be up if parent .* is down"
|
||||
count: 1
|
||||
---
|
||||
interfaces:
|
||||
GigabitEthernet1/0/0:
|
||||
state: down
|
||||
lcp: "e1"
|
||||
sub-interfaces:
|
||||
100:
|
||||
state: up
|
||||
encapsulation:
|
||||
dot1q: 100
|
||||
exact-match: false
|
@ -920,7 +920,7 @@ class Reconciler():
|
||||
config_admin_state = 1
|
||||
else:
|
||||
vpp_ifname, config_iface = interface.get_by_name(self.cfg, ifname)
|
||||
config_admin_state = 1
|
||||
config_admin_state = interface.get_admin_state(self.cfg, ifname)
|
||||
|
||||
vpp_admin_state = 0
|
||||
if vpp_ifname in self.vpp.cache['interface_names']:
|
||||
|
@ -316,6 +316,9 @@ class VPPApiDumper(VPPApi):
|
||||
if iface.sw_if_index in self.cache['l2xcs']:
|
||||
l2xc = self.cache['l2xcs'][iface.sw_if_index]
|
||||
i['l2xc'] = self.cache['interfaces'][l2xc.tx_sw_if_index].interface_name
|
||||
if not self.cache['interfaces'][idx].flags & 1: # IF_STATUS_API_FLAG_ADMIN_UP
|
||||
i['state'] = 'down'
|
||||
|
||||
i['mtu'] = iface.mtu[0]
|
||||
if iface.sub_number_of_tags == 0:
|
||||
config['interfaces'][iface.interface_name] = i
|
||||
|
Reference in New Issue
Block a user