diff --git a/unittest/correct-bridgedomain.yaml b/unittest/correct-bridgedomain.yaml index c9eda94..ae55910 100644 --- a/unittest/correct-bridgedomain.yaml +++ b/unittest/correct-bridgedomain.yaml @@ -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" diff --git a/unittest/error-lcp-unique1.yaml b/unittest/error-lcp-unique1.yaml new file mode 100644 index 0000000..5f00583 --- /dev/null +++ b/unittest/error-lcp-unique1.yaml @@ -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" + diff --git a/unittest/error-lcp-unique2.yaml b/unittest/error-lcp-unique2.yaml new file mode 100644 index 0000000..a75fc54 --- /dev/null +++ b/unittest/error-lcp-unique2.yaml @@ -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 ] diff --git a/validator/bridgedomain.py b/validator/bridgedomain.py index c2f5b1e..86f2baa 100644 --- a/validator/bridgedomain.py +++ b/validator/bridgedomain.py @@ -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']: diff --git a/validator/interface.py b/validator/interface.py index 7f037f1..b400ece 100644 --- a/validator/interface.py +++ b/validator/interface.py @@ -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)) diff --git a/validator/lcp.py b/validator/lcp.py new file mode 100644 index 0000000..1e87571 --- /dev/null +++ b/validator/lcp.py @@ -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 diff --git a/validator/loopback.py b/validator/loopback.py index 0acbee3..2dc9c55 100644 --- a/validator/loopback.py +++ b/validator/loopback.py @@ -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