diff --git a/vppcfg/config/loopback.py b/vppcfg/config/loopback.py index 4bf6294..4e28b45 100644 --- a/vppcfg/config/loopback.py +++ b/vppcfg/config/loopback.py @@ -16,6 +16,7 @@ import logging from . import lcp from . import address from . import mac +from . import interface def get_loopbacks(yaml): @@ -53,6 +54,32 @@ def is_loopback(yaml, ifname): return iface is not None +def get_unnumbered_loopbacks(yaml): + """Returns a list of all loopbacks that are unnumbered""" + ret = [] + if not "loopbacks" in yaml: + return ret + for ifname, iface in yaml["loopbacks"].items(): + if "unnumbered" in iface: + ret.append(ifname) + + return ret + + +def is_unnumbered(yaml, ifname): + """Returns True if the loopback exists and is unnumbered""" + return ifname in get_unnumbered_loopbacks(yaml) + + +def has_address(yaml, ifname): + """Returns True if this loopback has one or more addresses""" + + ifname, iface = get_by_name(yaml, ifname) + if not iface: + return False + return "addresses" in iface + + def validate_loopbacks(yaml): """Validate the semantics of all YAML 'loopbacks' entries""" result = True @@ -76,6 +103,31 @@ def validate_loopbacks(yaml): f"loopback {ifname} does not have a unique LCP name {iface['lcp']}" ) result = False + if "unnumbered" in iface: + target = iface["unnumbered"] + _, target_iface = get_by_name(yaml, target) + if not target_iface: + _, target_iface = interface.get_by_name(yaml, target) + if not target_iface: + msgs.append( + f"loopback {ifname} unnumbered target {target} does not exist" + ) + result = False + if is_unnumbered(yaml, target): + msgs.append( + f"loopback {ifname} unnumbered target {target} cannot also be unnumbered" + ) + result = False + if ifname == target: + msgs.append( + f"loopback {ifname} unnumbered target cannot point to itself" + ) + result = False + if has_address(yaml, ifname): + msgs.append( + f"loopback {ifname} cannot also have addresses when it is unnumbered" + ) + result = False if "addresses" in iface: for addr in iface["addresses"]: if not address.is_allowed(yaml, ifname, iface["addresses"], addr): diff --git a/vppcfg/schema.yaml b/vppcfg/schema.yaml index 8787d6d..7e60b2f 100644 --- a/vppcfg/schema.yaml +++ b/vppcfg/schema.yaml @@ -35,6 +35,7 @@ loopback: lcp: str(max=15,matches='[a-z]+[a-z0-9-]*',required=False) mtu: int(min=128,max=9216,required=False) addresses: list(ip_interface(),min=1,max=6,required=False) + unnumbered: str(required=False) mpls: bool(required=False) --- bondethernet: diff --git a/vppcfg/unittest/yaml/correct-unnumbered.yaml b/vppcfg/unittest/yaml/correct-unnumbered.yaml index 1433232..693ba45 100644 --- a/vppcfg/unittest/yaml/correct-unnumbered.yaml +++ b/vppcfg/unittest/yaml/correct-unnumbered.yaml @@ -7,6 +7,18 @@ loopbacks: loop0: mtu: 9216 addresses: [ 192.0.2.1/32, 2001:db8:1::1/128 ] + loop1: + mtu: 1500 + addresses: [ 192.0.2.17/32, 2001:db8:10::1/128 ] + loop2: + mtu: 1500 + unnumbered: loop1 + loop3: + mtu: 1500 + unnumbered: GigabitEthernet1/0/0 + loop4: + mtu: 1500 + unnumbered: GigabitEthernet3/0/0.100 interfaces: GigabitEthernet1/0/0: diff --git a/vppcfg/unittest/yaml/error-unnumbered1.yaml b/vppcfg/unittest/yaml/error-unnumbered1.yaml index fc9966e..e529b7d 100644 --- a/vppcfg/unittest/yaml/error-unnumbered1.yaml +++ b/vppcfg/unittest/yaml/error-unnumbered1.yaml @@ -2,21 +2,27 @@ test: description: "Nonexistent unnumbered target" errors: expected: - - "^sub-interface .* unnumbered target .* does not exist" - - "^interface .* unnumbered target .* does not exist" - count: 4 + - "(sub-)?interface .* unnumbered target .* does not exist" + - "loopback .* unnumbered target .* does not exist" + count: 6 --- loopbacks: loop0: mtu: 9216 addresses: [ 192.0.2.1/32, 2001:db8:1::1/128 ] + loop1: + mtu: 9216 + unnumbered: loop2 + loop3: + mtu: 9216 + unnumbered: GigabitEthernet0/0/0 interfaces: GigabitEthernet1/0/0: sub-interfaces: 101: description: "Error: non existent loopback device" - unnumbered: loop1 + unnumbered: loop2 GigabitEthernet2/0/0: addresses: [ 192.0.2.5/30, 2001:db8:2::1/64 ] diff --git a/vppcfg/unittest/yaml/error-unnumbered2.yaml b/vppcfg/unittest/yaml/error-unnumbered2.yaml index 3009921..d17e20c 100644 --- a/vppcfg/unittest/yaml/error-unnumbered2.yaml +++ b/vppcfg/unittest/yaml/error-unnumbered2.yaml @@ -4,8 +4,18 @@ test: expected: - "(sub-)?interface .* unnumbered target cannot point to itself" - "(sub-)?interface .* unnumbered target .* cannot also be unnumbered" - count: 8 + - "loopback .* unnumbered target cannot point to itself" + - "loopback .* unnumbered target .* cannot also be unnumbered" + count: 12 --- +loopbacks: + loop0: + unnumbered: loop1 + loop1: + unnumbered: loop0 + loop2: + unnumbered: loop2 + interfaces: GigabitEthernet1/0/0: description: "Cannot point to the same interface" diff --git a/vppcfg/unittest/yaml/error-unnumbered3.yaml b/vppcfg/unittest/yaml/error-unnumbered3.yaml index cbbe8b1..a22d639 100644 --- a/vppcfg/unittest/yaml/error-unnumbered3.yaml +++ b/vppcfg/unittest/yaml/error-unnumbered3.yaml @@ -3,12 +3,17 @@ test: errors: expected: - "(sub-)?interface .* cannot also have addresses when it is unnumbered" - count: 3 + - "loopback .* cannot also have addresses when it is unnumbered" + count: 4 --- loopbacks: loop0: mtu: 9216 addresses: [ 192.0.2.1/32, 2001:db8:1::1/128 ] + loop1: + mtu: 9216 + unnumbered: loop0 + addresses: [ 192.0.2.13/32, 2001:db8:4::1/128 ] interfaces: GigabitEthernet1/0/0: