Ensure that LCP names are globally unique (between interface/sub-interface/loopback/bridgedomain)
This commit is contained in:
@ -55,4 +55,4 @@ bridgedomains:
|
||||
description: "Bridge Domain 12, LCP but no address"
|
||||
mtu: 9000
|
||||
interfaces: [ GigabitEthernet4/0/0, GigabitEthernet4/0/1 ]
|
||||
lcp: "bvi11"
|
||||
lcp: "bvi12"
|
||||
|
18
unittest/error-lcp-unique1.yaml
Normal file
18
unittest/error-lcp-unique1.yaml
Normal file
@ -0,0 +1,18 @@
|
||||
test:
|
||||
description: "Two interfaces or subinterfaces can't have the same LCP"
|
||||
errors:
|
||||
expected:
|
||||
- "interface .* does not have a unique LCP name"
|
||||
- "sub-interface .* does not have a unique LCP name"
|
||||
count: 3
|
||||
---
|
||||
interfaces:
|
||||
GigabitEthernet1/0/0:
|
||||
lcp: "e1"
|
||||
sub-interfaces:
|
||||
100:
|
||||
lcp: "e1"
|
||||
|
||||
GigabitEthernet1/0/1:
|
||||
lcp: "e1"
|
||||
|
26
unittest/error-lcp-unique2.yaml
Normal file
26
unittest/error-lcp-unique2.yaml
Normal file
@ -0,0 +1,26 @@
|
||||
test:
|
||||
description: "Loopback and BridgeDomain and Interfaces can't have the same LCP"
|
||||
errors:
|
||||
expected:
|
||||
- "interface .* does not have a unique LCP name"
|
||||
- "loopback .* does not have a unique LCP name"
|
||||
- "bridgedomain .* does not have a unique LCP name"
|
||||
count: 3
|
||||
---
|
||||
interfaces:
|
||||
GigabitEthernet1/0/0:
|
||||
lcp: "e1"
|
||||
|
||||
GigabitEthernet2/0/0:
|
||||
mtu: 1500
|
||||
GigabitEthernet2/0/1:
|
||||
mtu: 1500
|
||||
|
||||
loopbacks:
|
||||
loop0:
|
||||
lcp: "e1"
|
||||
|
||||
bridgedomains:
|
||||
bd0:
|
||||
lcp: "e1"
|
||||
interfaces: [ GigabitEthernet2/0/0, GigabitEthernet2/0/1 ]
|
@ -1,5 +1,6 @@
|
||||
import logging
|
||||
import validator.interface as interface
|
||||
import validator.lcp as lcp
|
||||
|
||||
class NullHandler(logging.Handler):
|
||||
def emit(self, record):
|
||||
@ -35,6 +36,9 @@ def validate_bridgedomains(yaml):
|
||||
if 'addresses' in iface and not 'lcp' in iface:
|
||||
msgs.append("bridgedomain %s has an address but no LCP" % ifname)
|
||||
result = False
|
||||
if 'lcp' in iface and not lcp.is_unique(yaml, iface['lcp']):
|
||||
msgs.append("bridgedomain %s does not have a unique LCP name %s" % (ifname, iface['lcp']))
|
||||
result = False
|
||||
|
||||
if 'interfaces' in iface:
|
||||
for member in iface['interfaces']:
|
||||
|
@ -1,5 +1,6 @@
|
||||
import logging
|
||||
import validator.bondethernet as bondethernet
|
||||
import validator.lcp as lcp
|
||||
|
||||
class NullHandler(logging.Handler):
|
||||
def emit(self, record):
|
||||
@ -18,6 +19,7 @@ def get_parent_by_name(yaml, ifname):
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
def get_by_name(yaml, ifname):
|
||||
""" Returns the interface or sub-interface by a given name, or None if it does not exist """
|
||||
if '.' in ifname:
|
||||
@ -84,25 +86,6 @@ def is_bond_member(yaml, ifname):
|
||||
return True
|
||||
return False
|
||||
|
||||
def unique_lcp(yaml, ifname):
|
||||
""" Returns true if this interface has a unique LCP name """
|
||||
if not 'interfaces' in yaml:
|
||||
return True
|
||||
iface = get_by_name(yaml, ifname)
|
||||
lcp = get_lcp(yaml, ifname)
|
||||
if not lcp:
|
||||
return True
|
||||
|
||||
ncount = 0
|
||||
for sibling_ifname, sibling_iface in yaml['interfaces'].items():
|
||||
sibling_lcp = get_lcp(yaml, sibling_ifname)
|
||||
if sibling_lcp == lcp and sibling_ifname != ifname:
|
||||
## print("%s overlaps with %s: %s" % (ifname, sibling_ifname, lcp))
|
||||
ncount = ncount + 1
|
||||
if ncount == 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
def has_lcp(yaml, ifname):
|
||||
""" Returns True if this interface or sub-interface has an LCP"""
|
||||
if not 'interfaces' in yaml:
|
||||
@ -282,9 +265,9 @@ def validate_interfaces(yaml):
|
||||
if iface_address and not iface_lcp:
|
||||
msgs.append("interface %s has an address but no LCP" % ifname)
|
||||
result = False
|
||||
if iface_lcp and not unique_lcp(yaml, ifname):
|
||||
lcp = get_lcp(yaml, ifname)
|
||||
msgs.append("interface %s does not have a unique LCP name %s" % (ifname, lcp))
|
||||
iface_lcp = get_lcp(yaml, ifname)
|
||||
if iface_lcp and not lcp.is_unique(yaml, iface_lcp):
|
||||
msgs.append("interface %s does not have a unique LCP name %s" % (ifname, iface_lcp))
|
||||
result = False
|
||||
|
||||
if has_sub(yaml, ifname):
|
||||
@ -300,6 +283,9 @@ def validate_interfaces(yaml):
|
||||
if sub_lcp and len(sub_lcp)>15:
|
||||
msgs.append("sub-interface %s has LCP with too long name '%s'" % (sub_ifname, sub_lcp))
|
||||
result = False
|
||||
if iface_lcp and not lcp.is_unique(yaml, iface_lcp):
|
||||
msgs.append("sub-interface %s does not have a unique LCP name %s" % (sub_ifname, sub_lcp))
|
||||
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 MTU %d" % (sub_ifname, sub_iface['mtu'], iface_mtu))
|
||||
|
24
validator/lcp.py
Normal file
24
validator/lcp.py
Normal file
@ -0,0 +1,24 @@
|
||||
import logging
|
||||
|
||||
def is_unique(yaml, lcpname):
|
||||
""" Returns True if there is at most one occurence of the LCP name in the entire config."""
|
||||
ncount=0
|
||||
if 'interfaces' in yaml:
|
||||
for ifname, iface in yaml['interfaces'].items():
|
||||
if 'lcp' in iface and iface['lcp'] == lcpname:
|
||||
ncount = ncount + 1
|
||||
if 'sub-interfaces' in iface:
|
||||
for sub_ifname, sub_iface in iface['sub-interfaces'].items():
|
||||
if 'lcp' in sub_iface and sub_iface['lcp'] == lcpname:
|
||||
ncount = ncount + 1
|
||||
if 'loopbacks' in yaml:
|
||||
for ifname, iface in yaml['loopbacks'].items():
|
||||
if 'lcp' in iface and iface['lcp'] == lcpname:
|
||||
ncount = ncount + 1
|
||||
if 'bridgedomains' in yaml:
|
||||
for ifname, iface in yaml['bridgedomains'].items():
|
||||
if 'lcp' in iface and iface['lcp'] == lcpname:
|
||||
ncount = ncount + 1
|
||||
if ncount > 1:
|
||||
return False
|
||||
return True
|
@ -1,4 +1,5 @@
|
||||
import logging
|
||||
import validator.lcp as lcp
|
||||
|
||||
class NullHandler(logging.Handler):
|
||||
def emit(self, record):
|
||||
@ -29,5 +30,8 @@ def validate_loopbacks(yaml):
|
||||
if 'addresses' in iface and not 'lcp' in iface:
|
||||
msgs.append("loopback %s has an address but no LCP" % ifname)
|
||||
result = False
|
||||
if 'lcp' in iface and not lcp.is_unique(yaml, iface['lcp']):
|
||||
msgs.append("loopback %s does not have a unique LCP name %s" % (ifname, iface['lcp']))
|
||||
result = False
|
||||
|
||||
return result, msgs
|
||||
|
Reference in New Issue
Block a user