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
|
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):
|
def validate_interfaces(yaml):
|
||||||
result = True
|
result = True
|
||||||
msgs = []
|
msgs = []
|
||||||
@ -410,6 +421,8 @@ def validate_interfaces(yaml):
|
|||||||
if ifname.startswith("BondEthernet") and (None,None) == bondethernet.get_by_name(yaml, ifname):
|
if ifname.startswith("BondEthernet") and (None,None) == bondethernet.get_by_name(yaml, ifname):
|
||||||
msgs.append("interface %s does not exist in bondethernets" % ifname)
|
msgs.append("interface %s does not exist in bondethernets" % ifname)
|
||||||
result = False
|
result = False
|
||||||
|
if not 'state' in iface:
|
||||||
|
iface['state'] = 'up'
|
||||||
|
|
||||||
iface_mtu = get_mtu(yaml, ifname)
|
iface_mtu = get_mtu(yaml, ifname)
|
||||||
iface_lcp = get_lcp(yaml, ifname)
|
iface_lcp = get_lcp(yaml, ifname)
|
||||||
@ -473,6 +486,12 @@ def validate_interfaces(yaml):
|
|||||||
result = False
|
result = False
|
||||||
continue
|
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)
|
sub_mtu = get_mtu(yaml, sub_ifname)
|
||||||
if sub_mtu > iface_mtu:
|
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))
|
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)
|
addresses: list(ip_interface(),min=1,max=6,required=False)
|
||||||
sub-interfaces: map(include('sub-interface'),key=int(min=1,max=4294967295),required=False)
|
sub-interfaces: map(include('sub-interface'),key=int(min=1,max=4294967295),required=False)
|
||||||
l2xc: str(required=False)
|
l2xc: str(required=False)
|
||||||
|
state: enum('up', 'down', required=False)
|
||||||
---
|
---
|
||||||
sub-interface:
|
sub-interface:
|
||||||
description: str(exclude='\'"',len=64,required=False)
|
description: str(exclude='\'"',len=64,required=False)
|
||||||
@ -59,6 +60,7 @@ sub-interface:
|
|||||||
addresses: list(ip_interface(),required=False)
|
addresses: list(ip_interface(),required=False)
|
||||||
encapsulation: include('encapsulation',required=False)
|
encapsulation: include('encapsulation',required=False)
|
||||||
l2xc: str(required=False)
|
l2xc: str(required=False)
|
||||||
|
state: enum('up', 'down', required=False)
|
||||||
---
|
---
|
||||||
encapsulation:
|
encapsulation:
|
||||||
dot1q: int(min=1,max=4095,required=False)
|
dot1q: int(min=1,max=4095,required=False)
|
||||||
|
@ -201,3 +201,10 @@ class TestInterfaceMethods(unittest.TestCase):
|
|||||||
def test_is_phy(self):
|
def test_is_phy(self):
|
||||||
self.assertTrue(interface.is_phy(self.cfg, "GigabitEthernet1/0/0"))
|
self.assertTrue(interface.is_phy(self.cfg, "GigabitEthernet1/0/0"))
|
||||||
self.assertFalse(interface.is_phy(self.cfg, "GigabitEthernet1/0/0.100"))
|
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
|
* ***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
|
this interface cannot have any L3 configuration (IP addresses or LCP), and neither can the
|
||||||
target interface.
|
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
|
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
|
to have any number of sub-interfaces specified by `subid`, an integer between [0,2G), which further
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
interfaces:
|
interfaces:
|
||||||
GigabitEthernet3/0/0:
|
GigabitEthernet3/0/0:
|
||||||
mtu: 1500
|
mtu: 1500
|
||||||
|
state: down
|
||||||
description: Not Used
|
description: Not Used
|
||||||
GigabitEthernet3/0/1:
|
GigabitEthernet3/0/1:
|
||||||
mtu: 1500
|
mtu: 1500
|
||||||
|
state: down
|
||||||
description: Not Used
|
description: Not Used
|
||||||
HundredGigabitEthernet12/0/0:
|
HundredGigabitEthernet12/0/0:
|
||||||
mtu: 1500
|
mtu: 1500
|
||||||
|
state: down
|
||||||
description: Not Used
|
description: Not Used
|
||||||
HundredGigabitEthernet12/0/1:
|
HundredGigabitEthernet12/0/1:
|
||||||
mtu: 1500
|
mtu: 1500
|
||||||
|
state: down
|
||||||
description: Not Used
|
description: Not Used
|
||||||
|
@ -37,6 +37,7 @@ interface:
|
|||||||
addresses: list(ip_interface(),min=1,max=6,required=False)
|
addresses: list(ip_interface(),min=1,max=6,required=False)
|
||||||
sub-interfaces: map(include('sub-interface'),key=int(min=1,max=4294967295),required=False)
|
sub-interfaces: map(include('sub-interface'),key=int(min=1,max=4294967295),required=False)
|
||||||
l2xc: str(required=False)
|
l2xc: str(required=False)
|
||||||
|
state: enum('up', 'down', required=False)
|
||||||
---
|
---
|
||||||
sub-interface:
|
sub-interface:
|
||||||
description: str(exclude='\'"',len=64,required=False)
|
description: str(exclude='\'"',len=64,required=False)
|
||||||
@ -45,6 +46,7 @@ sub-interface:
|
|||||||
addresses: list(ip_interface(),required=False)
|
addresses: list(ip_interface(),required=False)
|
||||||
encapsulation: include('encapsulation',required=False)
|
encapsulation: include('encapsulation',required=False)
|
||||||
l2xc: str(required=False)
|
l2xc: str(required=False)
|
||||||
|
state: enum('up', 'down', required=False)
|
||||||
---
|
---
|
||||||
encapsulation:
|
encapsulation:
|
||||||
dot1q: int(min=1,max=4095,required=False)
|
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"
|
description: "This sub-int is invalid because it has no outer dot1q and dot1ad"
|
||||||
encapsulation:
|
encapsulation:
|
||||||
inner-dot1q: 1000
|
inner-dot1q: 1000
|
||||||
|
|
||||||
102:
|
102:
|
||||||
description: "This sub-int is has the same encap as 103"
|
description: "This sub-int is has the same encap as 103"
|
||||||
|
state: down
|
||||||
103:
|
103:
|
||||||
description: "This sub-int is has the same encap as 102"
|
description: "This sub-int is has the same encap as 102"
|
||||||
encapsulation:
|
encapsulation:
|
||||||
@ -59,6 +59,7 @@ interfaces:
|
|||||||
GigabitEthernet2/0/0:
|
GigabitEthernet2/0/0:
|
||||||
description: "This interface has no sub-ints"
|
description: "This interface has no sub-ints"
|
||||||
lcp: "e2"
|
lcp: "e2"
|
||||||
|
state: down
|
||||||
|
|
||||||
GigabitEthernet3/0/0:
|
GigabitEthernet3/0/0:
|
||||||
l2xc: GigabitEthernet3/0/1
|
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
|
config_admin_state = 1
|
||||||
else:
|
else:
|
||||||
vpp_ifname, config_iface = interface.get_by_name(self.cfg, ifname)
|
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
|
vpp_admin_state = 0
|
||||||
if vpp_ifname in self.vpp.cache['interface_names']:
|
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']:
|
if iface.sw_if_index in self.cache['l2xcs']:
|
||||||
l2xc = self.cache['l2xcs'][iface.sw_if_index]
|
l2xc = self.cache['l2xcs'][iface.sw_if_index]
|
||||||
i['l2xc'] = self.cache['interfaces'][l2xc.tx_sw_if_index].interface_name
|
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]
|
i['mtu'] = iface.mtu[0]
|
||||||
if iface.sub_number_of_tags == 0:
|
if iface.sub_number_of_tags == 0:
|
||||||
config['interfaces'][iface.interface_name] = i
|
config['interfaces'][iface.interface_name] = i
|
||||||
|
Reference in New Issue
Block a user