diff --git a/doc/ChangeLog.md b/doc/ChangeLog.md index 7f5f37e6..7507412e 100644 --- a/doc/ChangeLog.md +++ b/doc/ChangeLog.md @@ -17,6 +17,7 @@ All notable changes to the project are documented in this file. RPC and add boot order to operational datastore. - SSH Server is now configurable, issue #441 SSH Server and NETCONF Server now uses the same SSH hostkey in factory-config + - Add support for GRE/GRETAP tunnels ### Fixes diff --git a/doc/tunnels.md b/doc/tunnels.md new file mode 100644 index 00000000..fc1ffc4a --- /dev/null +++ b/doc/tunnels.md @@ -0,0 +1,16 @@ +# Tunnel configuration + +Tunnel traffic from point A to point B + + +## Generic Routing Encapsulation (GRE) + +The support for GRE tunnels includes IPv4 and IPv6 tunnels both in GRE +(IP) and GRETAP (MAC) modes. +``` +admin@example:/config/> edit interface gre1 +admin@example:/config/interface/gre1/> set type gretap +admin@example:/config/interface/gre1/> set gre local 192.168.3.1 remote 192.168.3.2 +admin@example:/config/interface/gre1/> leave +admin@example:/> +``` diff --git a/src/confd/src/Makefile.am b/src/confd/src/Makefile.am index 6a4a64a9..101183d0 100644 --- a/src/confd/src/Makefile.am +++ b/src/confd/src/Makefile.am @@ -34,6 +34,7 @@ confd_plugin_la_SOURCES = \ infix-if-bridge-port.c \ infix-if-veth.c \ infix-if-vlan.c \ + infix-if-gre.c \ ietf-keystore.c \ ietf-system.c \ ietf-syslog.c \ diff --git a/src/confd/src/ietf-interfaces.c b/src/confd/src/ietf-interfaces.c index f2928e25..4cd6028f 100644 --- a/src/confd/src/ietf-interfaces.c +++ b/src/confd/src/ietf-interfaces.c @@ -87,6 +87,10 @@ static int ifchange_cand_infer_type(sr_session_ctx_t *session, const char *path) inferred.data.string_val = "infix-if-type:vlan"; else if (!fnmatch("*.+([0-9])", ifname, FNM_EXTMATCH)) inferred.data.string_val = "infix-if-type:vlan"; + else if (!fnmatch("gre+([0-9])", ifname, FNM_EXTMATCH)) + inferred.data.string_val = "infix-if-type:gre"; + else if (!fnmatch("gretap+([0-9])", ifname, FNM_EXTMATCH)) + inferred.data.string_val = "infix-if-type:gretap"; free(ifname); @@ -395,6 +399,8 @@ static int netdag_gen_afspec_add(sr_session_ctx_t *session, struct dagger *net, sr_session_set_error_message(net->session, "Cannot create fixed Ethernet interface %s," " wrong type or name.", ifname); return -ENOENT; + } else if (!strcmp(iftype, "infix-if-type:gre") || !strcmp(iftype, "infix-if-type:gretap")) { + err = gre_gen(net, NULL, cif, ip); } else { sr_session_set_error_message(net->session, "%s: unsupported interface type \"%s\"", ifname, iftype); return -ENOSYS; @@ -420,6 +426,8 @@ static int netdag_gen_afspec_set(sr_session_ctx_t *session, struct dagger *net, return netdag_gen_vlan(net, dif, cif, ip); if (!strcmp(iftype, "infix-if-type:veth")) return 0; + if (!strcmp(iftype, "infix-if-type:gretap")) + return 0; ERROR("%s: unsupported interface type \"%s\"", ifname, iftype); return -ENOSYS; @@ -451,6 +459,9 @@ static bool netdag_must_del(struct lyd_node *dif, struct lyd_node *cif) } else if (!strcmp(iftype, "infix-if-type:veth")) { if (lydx_get_descendant(lyd_child(dif), "veth", NULL)) return true; + } else if (!strcmp(iftype, "infix-if-type:gre") || !strcmp(iftype, "infix-if-type:gretap")) { + if (lydx_get_descendant(lyd_child(dif), "gre", NULL)) + return true; /* } else if (!strcmp(iftype, "infix-if-type:lag")) { if (is_phys_addr_deleted(dif)) diff --git a/src/confd/src/ietf-interfaces.h b/src/confd/src/ietf-interfaces.h index 585a0d9a..7c733950 100644 --- a/src/confd/src/ietf-interfaces.h +++ b/src/confd/src/ietf-interfaces.h @@ -73,6 +73,8 @@ int ifchange_cand_infer_vlan(sr_session_ctx_t *session, const char *path); int netdag_gen_vlan(struct dagger *net, struct lyd_node *dif, struct lyd_node *cif, FILE *ip); +/* infix-if-gre.c */ +int gre_gen(struct dagger *net, struct lyd_node *dif, + struct lyd_node *cif, FILE *ip); + #endif /* CONFD_IETF_INTERFACES_H_ */ - - diff --git a/src/confd/src/infix-if-gre.c b/src/confd/src/infix-if-gre.c new file mode 100644 index 00000000..9b078ba7 --- /dev/null +++ b/src/confd/src/infix-if-gre.c @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +#include + +#include "ietf-interfaces.h" + +int gre_gen(struct dagger *net, struct lyd_node *dif, + struct lyd_node *cif, FILE *ip) +{ + const char *ifname, *iftype, *local, *remote, *mac = NULL; + struct lyd_node *node = NULL; + char gretype[10] = ""; + int ipv6; + + ifname = lydx_get_cattr(cif, "name"); + iftype = lydx_get_cattr(cif, "type"); + + node = lydx_get_descendant(lyd_child(cif), "gre", NULL); + if (!node) + return -EINVAL; + + local = lydx_get_cattr(node, "local"); + remote = lydx_get_cattr(node, "remote"); + ipv6 = !!strstr(local, ":"); + + if (!strcmp(iftype, "infix-if-type:gre")) { + snprintf(gretype, sizeof(gretype), "%sgre", ipv6 ? "ip6" : ""); + + } + else if (!strcmp(iftype, "infix-if-type:gretap")) { + snprintf(gretype, sizeof(gretype), "%sgretap", ipv6 ? "ip6" : ""); + mac = get_phys_addr(cif, NULL); + } + + fprintf(ip, "link add name %s type %s local %s remote %s", ifname, gretype, local, remote); + if (mac) + fprintf(ip, "address %s\n", mac); + else + fprintf(ip, "\n"); + + return 0; +} diff --git a/src/confd/yang/infix-if-bridge.yang b/src/confd/yang/infix-if-bridge.yang index a141aa13..4a594b41 100644 --- a/src/confd/yang/infix-if-bridge.yang +++ b/src/confd/yang/infix-if-bridge.yang @@ -525,7 +525,8 @@ submodule infix-if-bridge { "derived-from-or-self(if:type,'ianaift:ethernetCsmacd') or "+ "derived-from-or-self(if:type,'ianaift:ieee8023adLag') or "+ "derived-from-or-self(if:type,'ianaift:l2vlan') or "+ - "derived-from-or-self(if:type,'ianaift:ilan')" { + "derived-from-or-self(if:type,'ianaift:ilan') or "+ + "derived-from-or-self(if:type,'infix-ift:gretap')" { description "Applies when a Bridge interface exists."; } diff --git a/src/confd/yang/infix-if-gre.yang b/src/confd/yang/infix-if-gre.yang new file mode 100644 index 00000000..f8f9b3ef --- /dev/null +++ b/src/confd/yang/infix-if-gre.yang @@ -0,0 +1,35 @@ +submodule infix-if-gre { + yang-version 1.1; + belongs-to infix-interfaces { + prefix infix-if; + } + + import ietf-interfaces { + prefix if; + } + + import infix-if-type { + prefix infixift; + } + + organization "KernelKit"; + contact "kernelkit@googlegroups.com"; + description "GRE and GRETAP tunnel extension for ietf-interfaces"; + + revision 2024-12-20 { + description "Initial revision."; + reference "internal"; + } + + augment "/if:interfaces/if:interface" { + when "derived-from-or-self(if:type, 'infixift:gre') or"+ + "derived-from-or-self(if:type, 'infixift:gretap')" { + description "Only shown for if:type infixift:gre"; + } + + description "Augments the interface model with GRE tunnels."; + container gre { + uses local-remote; + } + } +} diff --git a/src/confd/yang/infix-if-gre@2024-12-20.yang b/src/confd/yang/infix-if-gre@2024-12-20.yang new file mode 120000 index 00000000..93196ca8 --- /dev/null +++ b/src/confd/yang/infix-if-gre@2024-12-20.yang @@ -0,0 +1 @@ +infix-if-gre.yang \ No newline at end of file diff --git a/src/confd/yang/infix-if-type.yang b/src/confd/yang/infix-if-type.yang index 179358d7..d26ba58f 100644 --- a/src/confd/yang/infix-if-type.yang +++ b/src/confd/yang/infix-if-type.yang @@ -64,6 +64,12 @@ module infix-if-type { description "Interface with properties resembling Ethernet"; reference "RFC 3635"; } + identity gre { + base infix-interface-type; + } + identity gretap { + base infix-interface-type; + } identity lag { base infix-interface-type; base ianaift:ieee8023adLag; diff --git a/src/confd/yang/infix-interfaces.yang b/src/confd/yang/infix-interfaces.yang index a97c2b20..90978e07 100644 --- a/src/confd/yang/infix-interfaces.yang +++ b/src/confd/yang/infix-interfaces.yang @@ -12,12 +12,16 @@ module infix-interfaces { import ietf-yang-types { prefix yang; } + import ietf-inet-types { + prefix inet; + } include infix-if-base; include infix-if-bridge; include infix-if-container; include infix-if-veth; include infix-if-vlan; + include infix-if-gre; organization "KernelKit"; contact "kernelkit@googlegroups.com"; @@ -80,6 +84,23 @@ module infix-interfaces { reference "internal"; } + grouping local-remote { + description "Local address to use as source address"; + leaf local { + type inet:ip-address; + mandatory true; + } + leaf remote { + description "Peer address"; + type inet:ip-address; + must "(contains(../local, ':') and contains(., ':')) + or (not(contains(../local, ':')) and not(contains(., ':')))" { + error-message + "Local and remote must be both IPv4 or both IPv6 addresses."; + } + mandatory true; + } + } /* * Data Nodes */ diff --git a/src/statd/python/cli_pretty/cli_pretty.py b/src/statd/python/cli_pretty/cli_pretty.py index f485fada..acb08c1b 100755 --- a/src/statd/python/cli_pretty/cli_pretty.py +++ b/src/statd/python/cli_pretty/cli_pretty.py @@ -304,6 +304,8 @@ class Iface: else: self.ipv6_addr = [] + if self.data.get('infix-interfaces:gre'): + self.gre = self.data['infix-interfaces:gre'] if self.data.get('infix-interfaces:vlan'): self.lower_if = self.data.get('infix-interfaces:vlan', None).get('lower-layer-if',None) @@ -323,6 +325,9 @@ class Iface: def is_veth(self): return self.data['type'] == "infix-if-type:veth" + def is_gre(self): + return self.data['type'] == "infix-if-type:gre" or self.data['type'] == "infix-if-type:gretap" + def oper(self, detail=False): """Remap in brief overview to fit column widths.""" if not detail and self.oper_status == "lower-layer-down": diff --git a/src/statd/python/yanger/yanger.py b/src/statd/python/yanger/yanger.py index 401d6bdc..62fdc125 100755 --- a/src/statd/python/yanger/yanger.py +++ b/src/statd/python/yanger/yanger.py @@ -38,6 +38,9 @@ def json_get_yang_type(iface_in): if iface_in['link_type'] == "loopback": return "infix-if-type:loopback" + if iface_in['link_type'] in ("gre", "gre6"): + return "infix-if-type:gre" + if iface_in['link_type'] != "ether": return "infix-if-type:other" @@ -53,6 +56,9 @@ def json_get_yang_type(iface_in): if iface_in['linkinfo']['info_kind'] == "veth": return "infix-if-type:veth" + if iface_in['linkinfo']['info_kind'] in ("gretap", "ip6gretap"): + return "infix-if-type:gretap" + if iface_in['linkinfo']['info_kind'] == "vlan": return "infix-if-type:vlan" @@ -715,6 +721,19 @@ def add_bridge_port_lower(ifname, iface_in, iface_out): multicast = get_brport_multicast(ifname) insert(iface_out, "infix-interfaces:bridge-port", "multicast", multicast) + +def add_gre(iface_in, iface_out): + if 'link_type' in iface_in: + val = json_get_yang_type(iface_in) + if val != "infix-if-type:gre" and val != "infix-if-type:gretap": + return; + gre={} + info_data=iface_in.get("linkinfo", {}).get("info_data", {}) + gre["local"] = info_data.get("local") + gre["remote"] = info_data.get("remote") + insert(iface_out, "infix-interfaces:gre", gre) + + def add_ip_link(ifname, iface_in, iface_out): if 'ifname' in iface_in: iface_out['name'] = ifname @@ -725,14 +744,14 @@ def add_ip_link(ifname, iface_in, iface_out): if 'ifalias' in iface_in: iface_out['description'] = iface_in['ifalias'] - if 'address' in iface_in: + if 'address' in iface_in and not "POINTOPOINT" in iface_in["flags"]: iface_out['phys-address'] = iface_in['address'] add_bridge_port_common(ifname, iface_in, iface_out) add_bridge_port_lower(ifname, iface_in, iface_out) if not iface_is_dsa(iface_in): - if 'link' in iface_in: + if iface_in.get('link'): insert(iface_out, "infix-interfaces:vlan", "lower-layer-if", iface_in['link']) elif 'link_index' in iface_in: # 'link_index' is the only reference we have if the link iface is in a namespace @@ -758,6 +777,7 @@ def add_ip_link(ifname, iface_in, iface_out): if 'link_type' in iface_in: val = json_get_yang_type(iface_in) iface_out['type'] = val + add_gre(iface_in, iface_out) val = lookup(iface_in, "stats64", "rx", "bytes") if val is not None: diff --git a/test/case/ietf_interfaces/Readme.adoc b/test/case/ietf_interfaces/Readme.adoc index 712d9573..61b861fa 100644 --- a/test/case/ietf_interfaces/Readme.adoc +++ b/test/case/ietf_interfaces/Readme.adoc @@ -47,3 +47,6 @@ include::veth_delete/Readme.adoc[] include::vlan_iface_termination/Readme.adoc[] +include::gre_basic/Readme.adoc[] + +include::gretap_bridged/Readme.adoc[] diff --git a/test/case/ietf_interfaces/gre_basic/Readme.adoc b/test/case/ietf_interfaces/gre_basic/Readme.adoc new file mode 100644 index 00000000..f197f2f4 --- /dev/null +++ b/test/case/ietf_interfaces/gre_basic/Readme.adoc @@ -0,0 +1,26 @@ +=== Basic IP GRE test +==== Description +Test setting up IP GRE tunnels using IPv4 and IPv6, +and then a connectivity test. + +==== Topology +ifdef::topdoc[] +image::../../test/case/ietf_interfaces/gre_basic/topology.svg[Basic IP GRE test topology] +endif::topdoc[] +ifndef::topdoc[] +ifdef::testgroup[] +image::gre_basic/topology.svg[Basic IP GRE test topology] +endif::testgroup[] +ifndef::testgroup[] +image::topology.svg[Basic IP GRE test topology] +endif::testgroup[] +endif::topdoc[] +==== Test sequence +. Set up topology and attach to target DUTs +. Configure DUTs +. Test connectivity host:data to gre 10.0.0.2 +. Test connectivity host:data to gre on right 2001:db8::c0a8:0a02 + + +<<< + diff --git a/test/case/ietf_interfaces/gre_basic/test.py b/test/case/ietf_interfaces/gre_basic/test.py new file mode 100755 index 00000000..1a1a0ef7 --- /dev/null +++ b/test/case/ietf_interfaces/gre_basic/test.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python3 +""" +Basic IP GRE test + +Test setting up IP GRE tunnels using IPv4 and IPv6, +and then a connectivity test. +""" + +import infamy + +with infamy.Test() as test: + with test.step("Set up topology and attach to target DUTs"): + env = infamy.Env() + left = env.attach("left", "mgmt") + right = env.attach("right", "mgmt") + _, leftlink = env.ltop.xlate("left", "link") + _, leftdata = env.ltop.xlate("left", "data") + _, rightlink = env.ltop.xlate("right", "link") + + + with test.step("Configure DUTs"): + left.put_config_dicts({ "ietf-interfaces": { + "interfaces": { + "interface": [ + { + "name": leftlink, + "ipv4": { + "address": [{ + "ip": "192.168.50.1", + "prefix-length": 24 + }], + "forwarding": True + }, + "ipv6": { + "address": [{ + "ip": "2001:db8:3c4d:50::1", + "prefix-length": 64 + }], + "forwarding": True + } + }, + { + "name": leftdata, + "ipv4": { + "address": [{ + "ip": "192.168.10.1", + "prefix-length": 24 + }], + "forwarding": True + }, + "ipv6": { + "address": [{ + "ip": "2001:db8:3c4d:10::1", + "prefix-length": 64 + }], + "forwarding": True + } + }, + { + "name": "gre0", + "type": "infix-if-type:gre", + "ipv4": { + "address": [{ + "ip": "192.168.30.1", + "prefix-length": 24 + }], + "forwarding": True + }, + "gre": { + "local": "192.168.50.1", + "remote": "192.168.50.2" + } + + }, + { + "name": "gre6", + "type": "infix-if-type:gre", + "ipv6": { + "address": [{ + "ip": "2001:db8:3c4d:30::1", + "prefix-length": 64 + }] + }, + "gre": { + "local": "2001:db8:3c4d:50::1", + "remote": "2001:db8:3c4d:50::2", + } + }] + } + } + }) + + right.put_config_dicts({ + "ietf-interfaces": { + "interfaces": { + "interface": [ + { + "name": rightlink, + "ipv4": { + "address": [{ + "ip": "192.168.50.2", + "prefix-length": 24 + }], + "forwarding": True + }, + "ipv6": { + "address": [{ + "ip": "2001:db8:3c4d:50::2", + "prefix-length": 64 + }] + } + }, + { + "name": "gre1", + "type": "infix-if-type:gre", + "ipv4": { + "address": [{ + "ip": "192.168.30.2", + "prefix-length": 24 + }], + "forwarding": True + }, + "gre": { + "local": "192.168.50.2", + "remote": "192.168.50.1" + } + }, + { + "name": "gre6", + "type": "infix-if-type:gre", + "ipv6": { + "address": [{ + "ip": "2001:db8:3c4d:30::2", + "prefix-length": 64 + }] + }, + "gre": { + "local": "2001:db8:3c4d:50::2", + "remote": "2001:db8:3c4d:50::1", + } + }] + } + }, + "ietf-routing": { + "routing": { + "control-plane-protocols": { + "control-plane-protocol": [{ + "type": "infix-routing:static", + "name": "default", + "static-routes": { + "ipv4": { + "route": [{ + "destination-prefix": "192.168.10.0/24", + "next-hop": { + "next-hop-address": "192.168.30.1" + } + }] + }, + "ipv6": { + "route": [{ + "destination-prefix": "2001:db8:3c4d:10::/64", + "next-hop": { + "next-hop-address": "2001:db8:3c4d:30::1" + } + }] + } + } + }] + } + } + } + }) + _, hport = env.ltop.xlate("host", "data") + with test.step("Test connectivity host:data to gre 10.0.0.2"): + with infamy.IsolatedMacVlan(hport) as ns0: + ns0.addip("192.168.10.2") + ns0.addroute("192.168.30.0/24", "192.168.10.1") + ns0.must_reach("192.168.30.2") + with test.step("Test connectivity host:data to gre on right 2001:db8::c0a8:0a02"): + with infamy.IsolatedMacVlan(hport) as ns0: + ns0.addip("2001:db8:3c4d:10::2", prefix_length=64, proto="ipv6") + ns0.addroute("2001:db8:3c4d:30::/64", "2001:db8:3c4d:10::1", proto="ipv6") + #breakpoint() + ns0.must_reach("2001:db8:3c4d:30::2") + + test.succeed() diff --git a/test/case/ietf_interfaces/gre_basic/topology.dot b/test/case/ietf_interfaces/gre_basic/topology.dot new file mode 100644 index 00000000..ed68c3dd --- /dev/null +++ b/test/case/ietf_interfaces/gre_basic/topology.dot @@ -0,0 +1,35 @@ +graph "gre-basic" { + layout="neato"; + overlap="false"; + esep="+40"; + + node [shape=record, fontname="DejaVu Sans Mono, Book"]; + edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"]; + + host [ + label="host | { mgmt1 } | { data } | { mgmt2 }" + pos="3,0!", + kind="controller", + ]; + + left [ + label="{ left } | { mgmt } | { data } | { link }", + pos="0, -3!", + + kind="infix", + ]; + + right [ + label="{ link } | { mgmt } | { right }", + pos="8,-3!", + + kind="infix", + ]; + + host:mgmt1 -- left:mgmt [kind=mgmt, color="lightgray"] + host:data -- left:data [headlabel=".1", label="192.168.10.0/24" taillabel=".2 ", labeldistance=1, fontcolor="black", color="black"] + host:mgmt2 -- right:mgmt [kind=mgmt, color="lightgray"] + + + left:link -- right:link [headlabel=".1\n\n", label="192.168.50.0/24", taillabel="\n.2", labeldistance=1, fontcolor="black", color="black"] +} \ No newline at end of file diff --git a/test/case/ietf_interfaces/gre_basic/topology.svg b/test/case/ietf_interfaces/gre_basic/topology.svg new file mode 100644 index 00000000..4a86ba43 --- /dev/null +++ b/test/case/ietf_interfaces/gre_basic/topology.svg @@ -0,0 +1,72 @@ + + + + + + +gre-basic + + + +host + +host + +mgmt1 + +data + +mgmt2 + + + +left + +left + +mgmt + +data + +link + + + +host:mgmt1--left:mgmt + + + + +host:data--left:data + +192.168.10.0/24 +.1 +.2  + + + +right + +link + +mgmt + +right + + + +host:mgmt2--right:mgmt + + + + +left:link--right:link + +192.168.50.0/24 +.1 +.2 + + + diff --git a/test/case/ietf_interfaces/gretap_bridged/Readme.adoc b/test/case/ietf_interfaces/gretap_bridged/Readme.adoc new file mode 100644 index 00000000..6060218a --- /dev/null +++ b/test/case/ietf_interfaces/gretap_bridged/Readme.adoc @@ -0,0 +1,24 @@ +=== GRETAP interface bridged with physical +==== Description +Test that GRETAP works as it should and that it possible to bridge it. + +==== Topology +ifdef::topdoc[] +image::../../test/case/ietf_interfaces/gretap_bridged/topology.svg[GRETAP interface bridged with physical topology] +endif::topdoc[] +ifndef::topdoc[] +ifdef::testgroup[] +image::gretap_bridged/topology.svg[GRETAP interface bridged with physical topology] +endif::testgroup[] +ifndef::testgroup[] +image::topology.svg[GRETAP interface bridged with physical topology] +endif::testgroup[] +endif::topdoc[] +==== Test sequence +. Set up topology and attach to target DUTs +. Configure DUTs +. Test connectivity host:data to right:gre0 at 192.168.10.2 + + +<<< + diff --git a/test/case/ietf_interfaces/gretap_bridged/test.py b/test/case/ietf_interfaces/gretap_bridged/test.py new file mode 100755 index 00000000..2ec73c7f --- /dev/null +++ b/test/case/ietf_interfaces/gretap_bridged/test.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +""" +GRETAP interface bridged with physical + +Test that GRETAP works as it should and that it possible to bridge it. + +""" + +import infamy + +with infamy.Test() as test: + with test.step("Set up topology and attach to target DUTs"): + env = infamy.Env() + left = env.attach("left", "mgmt") + right = env.attach("right", "mgmt") + _, leftlink = env.ltop.xlate("left", "link") + _, leftdata = env.ltop.xlate("left", "data") + _, rightlink = env.ltop.xlate("right", "link") + + + with test.step("Configure DUTs"): + left.put_config_dicts({ "ietf-interfaces": { + "interfaces": { + "interface": [ + { + "name": leftlink, + "ipv4": { + "address": [{ + "ip": "192.168.50.1", + "prefix-length": 24 + }], + "forwarding": True + } + }, + { + "name": leftdata, + "bridge-port": { + "bridge": "br0" + } + }, + { + "name": "br0", + "type": "infix-if-type:bridge" + }, + { + "name": "gre0", + "type": "infix-if-type:gretap", + "gre": { + "local": "192.168.50.1", + "remote": "192.168.50.2" + }, + "bridge-port": { + "bridge": "br0" + } + + } + ] + } + } + }) + + right.put_config_dicts({ + "ietf-interfaces": { + "interfaces": { + "interface": [ + { + "name": rightlink, + "ipv4": { + "address": [{ + "ip": "192.168.50.2", + "prefix-length": 24 + }], + "forwarding": True + }, + "ipv6": { + "address": [{ + "ip": "2001:db8:3c4d:50::2", + "prefix-length": 64 + }] + } + }, + { + "name": "gre0", + "type": "infix-if-type:gretap", + "ipv4": { + "address": [{ + "ip": "192.168.10.2", + "prefix-length": 24 + }], + "forwarding": True + }, + "gre": { + "local": "192.168.50.2", + "remote": "192.168.50.1" + } + }] + } + } + }) + _, hport = env.ltop.xlate("host", "data") + with test.step("Test connectivity host:data to right:gre0 at 192.168.10.2"): + with infamy.IsolatedMacVlan(hport) as ns0: + ns0.addip("192.168.10.1") + ns0.must_reach("192.168.10.2") + + test.succeed() diff --git a/test/case/ietf_interfaces/gretap_bridged/topology.dot b/test/case/ietf_interfaces/gretap_bridged/topology.dot new file mode 100644 index 00000000..d3dd36aa --- /dev/null +++ b/test/case/ietf_interfaces/gretap_bridged/topology.dot @@ -0,0 +1,35 @@ +graph "gre-basic" { + layout="neato"; + overlap="false"; + esep="+40"; + + node [shape=record, fontname="DejaVu Sans Mono, Book"]; + edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"]; + + host [ + label="host | { mgmt1 } | { data } | { mgmt2 }" + pos="3,0!", + kind="controller", + ]; + + left [ + label="{ left } | { mgmt } | { data } | { link }", + pos="0, -3!", + + kind="infix", + ]; + + right [ + label="{ link } | { mgmt } | { right }", + pos="8,-3!", + + kind="infix", + ]; + + host:mgmt1 -- left:mgmt [kind=mgmt, color="lightgray"] + host:data -- left:data [taillabel="192.168.10.2/24    ", fontcolor="black", color="black"] + host:mgmt2 -- right:mgmt [kind=mgmt, color="lightgray"] + + + left:link -- right:link [headlabel=".1\n\n", label="192.168.50.0/24", taillabel="\n.2", labeldistance=1, fontcolor="black", color="black"] +} \ No newline at end of file diff --git a/test/case/ietf_interfaces/gretap_bridged/topology.svg b/test/case/ietf_interfaces/gretap_bridged/topology.svg new file mode 100644 index 00000000..f6737ac4 --- /dev/null +++ b/test/case/ietf_interfaces/gretap_bridged/topology.svg @@ -0,0 +1,70 @@ + + + + + + +gre-basic + + + +host + +host + +mgmt1 + +data + +mgmt2 + + + +left + +left + +mgmt + +data + +link + + + +host:mgmt1--left:mgmt + + + + +host:data--left:data + +192.168.10.2/24     + + + +right + +link + +mgmt + +right + + + +host:mgmt2--right:mgmt + + + + +left:link--right:link + +192.168.50.0/24 +.1 +.2 + + + diff --git a/test/case/ietf_interfaces/ietf_interfaces.yaml b/test/case/ietf_interfaces/ietf_interfaces.yaml index b1418d10..532a8de5 100644 --- a/test/case/ietf_interfaces/ietf_interfaces.yaml +++ b/test/case/ietf_interfaces/ietf_interfaces.yaml @@ -64,3 +64,9 @@ - name: vlan_iface_termination case: vlan_iface_termination/test.py + +- name: gre_basic + case: gre_basic/test.py + +- name: gretap_bridged + case: gretap_bridged/test.py