admin@example:/> configure
admin@example:/config/> edit firewall zone dmz
-admin@example:/config/firewall/zone/dmz/> set description "Semi-trusted public services"
-admin@example:/config/firewall/zone/dmz/> set action drop
-admin@example:/config/firewall/zone/dmz/> set interface eth1
-admin@example:/config/firewall/zone/dmz/> set service ssh
-admin@example:/config/firewall/zone/dmz/> end
+admin@example:/config/firewall/…/dmz/> set description "Semi-trusted public services"
+admin@example:/config/firewall/…/dmz/> set action drop
+admin@example:/config/firewall/…/dmz/> set interface eth1
+admin@example:/config/firewall/…/dmz/> set service ssh
+admin@example:/config/firewall/…/dmz/> end
admin@example:/config/firewall/> edit policy loc-to-wan
-admin@example:/config/firewall/policy/loc-to-wan/> set description "Allow local networks (LAN+DMZ) to WAN with SNAT"
-admin@example:/config/firewall/policy/loc-to-wan/> set ingress dmz
-admin@example:/config/firewall/policy/loc-to-wan/> set egress wan
-admin@example:/config/firewall/policy/loc-to-wan/> set action accept
-admin@example:/config/firewall/policy/loc-to-wan/> set masquerade
-admin@example:/config/firewall/policy/loc-to-wan/> end
+admin@example:/config/firewall/…/loc-to-wan/> set description "Allow local networks (LAN+DMZ) to WAN with SNAT"
+admin@example:/config/firewall/…/loc-to-wan/> set ingress dmz
+admin@example:/config/firewall/…/loc-to-wan/> set egress wan
+admin@example:/config/firewall/…/loc-to-wan/> set action accept
+admin@example:/config/firewall/…/loc-to-wan/> set masquerade
+admin@example:/config/firewall/…/loc-to-wan/> end
admin@example:/config/firewall/> edit policy lan-to-dmz
-admin@example:/config/firewall/policy/lan-to-dmz/> set description "Allow LAN to manage DMZ services"
-admin@example:/config/firewall/policy/lan-to-dmz/> set ingress lan
-admin@example:/config/firewall/policy/lan-to-dmz/> set egress dmz
-admin@example:/config/firewall/policy/lan-to-dmz/> set action accept
-admin@example:/config/firewall/policy/lan-to-dmz/> end
+admin@example:/config/firewall/…/lan-to-dmz/> set description "Allow LAN to manage DMZ services"
+admin@example:/config/firewall/…/lan-to-dmz/> set ingress lan
+admin@example:/config/firewall/…/lan-to-dmz/> set egress dmz
+admin@example:/config/firewall/…/lan-to-dmz/> set action accept
+admin@example:/config/firewall/…/lan-to-dmz/> end
admin@example:/config/firewall/> edit zone wan port-forward 8080 tcp
-admin@example:/config/firewall/zone/wan/port-forward/8080/tcp/> set to addr 192.168.2.10
-admin@example:/config/firewall/zone/wan/port-forward/8080/tcp/> set to port 80
-admin@example:/config/firewall/zone/wan/port-forward/8080/tcp/> leave
+admin@example:/config/firewall/…/tcp/> set to addr 192.168.2.10
+admin@example:/config/firewall/…/tcp/> set to port 80
+admin@example:/config/firewall/…/tcp/> leave
This adds a DMZ zone for public services, updates the internet access policy
diff --git a/doc/networking.md b/doc/networking.md
index 64e0d7d5..bc738812 100644
--- a/doc/networking.md
+++ b/doc/networking.md
@@ -1264,18 +1264,18 @@ control plane protocol. For our examples we use the instance name
For a route with destination 192.168.200.0/24 via 192.168.1.1:
admin@example:/> configure
- admin@example:/config/> edit routing control-plane-protocol static name default
- admin@example:/config/routing/control-plane-protocol/static/name/default/> set ipv4 route 192.168.200.0/24 next-hop next-hop-address 192.168.1.1
- admin@example:/config/routing/control-plane-protocol/static/name/default/> leave
+ admin@example:/config/> edit routing control-plane-protocol static name default ipv4
+ admin@example:/config/routing/…/ipv4/> set route 192.168.200.0/24 next-hop next-hop-address 192.168.1.1
+ admin@example:/config/routing/…/ipv4/> leave
admin@example:/>
For a "floating" static route with destination 10.0.0.0/16 via a backup
router 192.168.1.1, using the highest possible distance:
admin@example:/> configure
- admin@example:/config/> edit routing control-plane-protocol static name default
- admin@example:/config/routing/control-plane-protocol/static/name/default/> set ipv4 route 10.0.0.0/16 next-hop next-hop-address 192.168.1.1 route-preference 254
- admin@example:/config/routing/control-plane-protocol/static/name/default/> leave
+ admin@example:/config/> edit routing control-plane-protocol static name default ipv4
+ admin@example:/config/routing/…/ipv4/> set route 10.0.0.0/16 next-hop next-hop-address 192.168.1.1 route-preference 254
+ admin@example:/config/routing/…/ipv4/> leave
admin@example:/>
> [!TIP]
@@ -1286,9 +1286,9 @@ router 192.168.1.1, using the highest possible distance:
### IPv6 Static routes
admin@example:/> configure
- admin@example:/config/> edit routing control-plane-protocol static name default
- admin@example:/config/routing/control-plane-protocol/static/name/default/> set ipv6 route 2001:db8:3c4d:200::/64 next-hop next-hop-address 2001:db8:3c4d:1::1
- admin@example:/config/routing/control-plane-protocol/static/name/default/> leave
+ admin@example:/config/> edit routing control-plane-protocol static name default ipv6
+ admin@example:/config/routing/…/ipv6/> set route 2001:db8:3c4d:200::/64 next-hop next-hop-address 2001:db8:3c4d:1::1
+ admin@example:/config/routing/…/ipv6/> leave
admin@example:/>
@@ -1297,9 +1297,9 @@ router 192.168.1.1, using the highest possible distance:
The system supports OSPF dynamic routing for IPv4, i.e., OSPFv2. To
enable OSPF and set one active interface in area 0:
- admin@example:/config/> edit routing control-plane-protocol ospfv2 name default
- admin@example:/config/routing/control-plane-protocol/ospfv2/name/default/> set ospf area 0.0.0.0 interface e0 enabled
- admin@example:/config/routing/control-plane-protocol/ospfv2/name/default/> leave
+ admin@example:/config/> edit routing control-plane-protocol ospfv2 name default ospf
+ admin@example:/config/routing/…/ospf/> set area 0.0.0.0 interface e0 enabled
+ admin@example:/config/routing/…/ospf/> leave
admin@example:/>
> [!TIP]
@@ -1312,10 +1312,10 @@ enable OSPF and set one active interface in area 0:
In addition to *regular* OSPF areas, area types *NSSA* and *Stub* are
also supported. To configure an NSSA area with summary routes:
- admin@example:/config/> edit routing control-plane-protocol ospfv2 name default
- admin@example:/config/routing/control-plane-protocol/ospfv2/name/default/> set ospf area 0.0.0.1 area-type nssa-area
- admin@example:/config/routing/control-plane-protocol/ospfv2/name/default/> set ospf area 0.0.0.1 summary true
- admin@example:/config/routing/control-plane-protocol/ospfv2/name/default/> leave
+ admin@example:/config/> edit routing control-plane-protocol ospfv2 name default ospf
+ admin@example:/config/routing/…/ospf/> set area 0.0.0.1 area-type nssa-area
+ admin@example:/config/routing/…/ospf/> set area 0.0.0.1 summary true
+ admin@example:/config/routing/…/ospf/> leave
admin@example:/>
@@ -1324,9 +1324,9 @@ also supported. To configure an NSSA area with summary routes:
It is possible to enable BFD per OSPF interface to speed up detection of
link loss.
- admin@example:/config/> edit routing control-plane-protocol ospfv2 name default
- admin@example:/config/routing/control-plane-protocol/ospfv2/name/default/ospf/> set area 0.0.0.0 interface e0 bfd enabled true
- admin@example:/config/routing/control-plane-protocol/ospfv2/name/default/> leave
+ admin@example:/config/> edit routing control-plane-protocol ospfv2 name default ospf
+ admin@example:/config/routing/…/ospf/> set area 0.0.0.0 interface e0 bfd enabled true
+ admin@example:/config/routing/…/ospf/> leave
admin@example:/>
@@ -1337,9 +1337,9 @@ and BFD for OSPF per interface (*bfd enabled true*). These and other
OSPF interface settings are done in context of an OSFP area, e.g., *area
0.0.0.0*. Available commands can be listed using the `?` mark.
- admin@example:/config/routing/control-plane-protocol/ospfv2/name/default/> edit ospf area 0.0.0.0
- admin@example:/config/routing/control-plane-protocol/ospfv2/name/default/ospf/area/0.0.0.0/> edit interface e0
- admin@example:/config/routing/control-plane-protocol/ospfv2/name/default/ospf/area/0.0.0.0/interface/e0/> set ?
+ admin@example:/config/routing/…/> edit ospf area 0.0.0.0
+ admin@example:/config/routing/…/ospf/area/0.0.0.0/> edit interface e0
+ admin@example:/config/routing/…/ospf/area/0.0.0.0/interface/e0/> set ?
bfd BFD interface configuration.
cost Interface's cost.
dead-interval Interval after which a neighbor is declared down
@@ -1349,13 +1349,13 @@ OSPF interface settings are done in context of an OSFP area, e.g., *area
passive Enables/disables a passive interface. A passive
retransmit-interval Interval between retransmitting unacknowledged Link
transmit-delay Estimated time needed to transmit Link State Update
- admin@example:/config/routing/control-plane-protocol/ospfv2/name/default/ospf/area/0.0.0.0/interface/e0/> set
+ admin@example:/config/routing/…/ospf/area/0.0.0.0/interface/e0/> set
For example, setting the OSPF *interface type* to *point-to-point* for
an Ethernet interface can be done as follows.
- admin@example:/config/routing/control-plane-protocol/ospfv2/name/default/ospf/area/0.0.0.0/interface/e0/> set interface-type point-to-point
- admin@example:/config/routing/control-plane-protocol/ospfv2/name/default/ospf/area/0.0.0.0/interface/e0/>
+ admin@example:/config/routing/…/ospf/area/0.0.0.0/interface/e0/> set interface-type point-to-point
+ admin@example:/config/routing/…/ospf/area/0.0.0.0/interface/e0/>
#### OSPF global settings
@@ -1364,12 +1364,12 @@ global settings for route redistribution and OSPF router identifier.
```
admin@example:/config/> edit routing control-plane-protocol ospfv2 name default ospf
-admin@example:/config/routing/control-plane-protocol/ospfv2/name/default/ospf/> set ?
+admin@example:/config/routing/…/ospf/> set ?
area List of OSPF areas.
default-route-advertise Distribute default route to network
explicit-router-id Defined in RFC 2328. A 32-bit number
redistribute Redistribute protocols into OSPF
-admin@example:/config/routing/control-plane-protocol/ospfv2/name/default/ospf/> set
+admin@example:/config/routing/…/ospf/> set
```
- Explicit router ID: By default the router will pick an IP address
diff --git a/doc/syslog.md b/doc/syslog.md
index 3244351d..33cf0375 100644
--- a/doc/syslog.md
+++ b/doc/syslog.md
@@ -23,17 +23,16 @@ For a list of available log facilities, see the table in a later section.
```
admin@example:/> configure
-admin@example:/config/> edit syslog
-admin@example:/config/syslog/> edit actions log-file file:/media/log/mylog
-admin@example:/config/syslog/actions/log-file/file:/media/log/mylog/> set facility-list
+admin@example:/config/> edit syslog actions log-file file:/media/log/mylog
+admin@example:/config/syslog/…/file:/media/log/mylog/> set facility-list
all audit auth authpriv console cron cron2 daemon ftp kern
local0 local1 local2 local3 local4 local5 local6 local7 lpr mail
news ntp syslog user uucp
-admin@example:/config/syslog/actions/log-file/file:/media/log/mylog/> set facility-list all severity
+admin@example:/config/syslog/…/file:/media/log/mylog/> set facility-list all severity
alert all critical debug emergency error info none notice warning
-admin@example:/config/syslog/actions/log-file/file:/media/log/mylog/> set facility-list all severity critical
-admin@example:/config/syslog/actions/log-file/file:/media/log/mylog/> set facility-list mail severity warning
-admin@example:/config/syslog/actions/log-file/file:/media/log/mylog/> leave
+admin@example:/config/syslog/…/file:/media/log/mylog/> set facility-list all severity critical
+admin@example:/config/syslog/…/file:/media/log/mylog/> set facility-list mail severity warning
+admin@example:/config/syslog/…/file:/media/log/mylog/> leave
admin@example:/>
```
@@ -137,11 +136,11 @@ perform time stamping at the time of arrival.
Configuring the log format is the same for log files and remotes:
```
-admin@example:/config/> edit syslog actions log-file file:foobar
-admin@example:/config/syslog/actions/log-file/file:foobar/> set log-format
+admin@example:/config/> edit syslog actions log-file file:foobar
+admin@example:/config/syslog/…/file:foobar/> set log-format
bsd rfc3164 rfc5424
-admin@example:/config/syslog/actions/log-file/file:foobar/> set log-format rfc5424
-admin@example:/config/syslog/actions/log-file/file:foobar/> leave
+admin@example:/config/syslog/…/file:foobar/> set log-format rfc5424
+admin@example:/config/syslog/…/file:foobar/> leave
admin@example:/>
```
@@ -163,13 +162,13 @@ up, as well as local policy.
admin@example:/config/> edit syslog
actions file-rotation server
admin@example:/config/> edit syslog actions destination moon
-admin@example:/config/syslog/actions/destination/moon/> set
+admin@example:/config/syslog/…/moon/> set
facility-list log-format udp
-admin@example:/config/syslog/actions/destination/moon/> set udp
+admin@example:/config/syslog/…/moon/> set udp
address port
-admin@example:/config/syslog/actions/destination/moon/> set udp address 192.168.0.12
-admin@example:/config/syslog/actions/destination/moon/> set facility-list container severity all
-admin@example:/config/syslog/actions/destination/moon/> leave
+admin@example:/config/syslog/…/moon/> set udp address 192.168.0.12
+admin@example:/config/syslog/…/moon/> set facility-list container severity all
+admin@example:/config/syslog/…/moon/> leave
admin@example:/>
```
diff --git a/doc/tunnels.md b/doc/tunnels.md
index 70064519..7906f2f1 100644
--- a/doc/tunnels.md
+++ b/doc/tunnels.md
@@ -1,28 +1,212 @@
-# Tunnel configuration
+# Tunnel Configuration
-Tunnel traffic from point A to point B
+Infix supports multiple tunnel encapsulation protocols for connecting
+remote networks or devices across an IP backbone. Tunnels encapsulate
+packets within IP datagrams, allowing traffic to traverse intermediate
+networks transparently.
+> [!IMPORTANT]
+> When issuing `leave` to activate your changes, remember to also save
+> your settings, `copy running-config startup-config`. See the [CLI
+> Introduction](cli/introduction.md) for a background.
## Generic Routing Encapsulation (GRE)
-The support for GRE tunnels includes IPv4 and IPv6 tunnels both in GRE
-(IP) and GRETAP (MAC) modes.
+GRE tunnels provide a simple and efficient method to encapsulate various
+network layer protocols over IP networks. Infix supports both IPv4 and
+IPv6 tunnels in two modes:
+
+- **GRE (Layer 3):** Point-to-point IP tunnel for routing protocols and
+ routed traffic
+- **GRETAP (Layer 2):** Ethernet tunnel for bridging Layer 2 networks
+
+> [!TIP]
+> If you name your tunnel interface `greN` or `gretapN`, where `N` is a
+> number, the CLI infers the interface type automatically.
+
+### Basic GRE Configuration
+
+A basic GRE tunnel for routing between two sites:
+
```
-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:/> configure
+admin@example:/config/> edit interface gre0
+admin@example:/config/interface/gre0/> set gre local 192.168.3.1 remote 192.168.3.2
+admin@example:/config/interface/gre0/> set ipv4 address 10.255.0.1 prefix-length 30
+admin@example:/config/interface/gre0/> leave
admin@example:/>
```
-## Virtual eXtensible Local Area Network (VXLAN)
+This creates a Layer 3 tunnel between 192.168.3.1 and 192.168.3.2 using
+the outer IP addresses, with the tunnel itself using 10.255.0.0/30 for
+the inner IP addressing.
-The support for VXLAN tunnels includes IPv4 and IPv6.
+### GRETAP Configuration
+
+GRETAP tunnels operate at Layer 2, allowing bridging across the tunnel:
```
+admin@example:/> configure
+admin@example:/config/> edit interface gretap0
+admin@example:/config/interface/gretap0/> set type gretap
+admin@example:/config/interface/gretap0/> set gre local 192.168.3.1 remote 192.168.3.2
+admin@example:/config/interface/gretap0/> leave
+admin@example:/>
+```
+
+GRETAP interfaces can be added to a bridge, bridging local and remote Ethernet
+segments. See the [Bridge Configuration](networking.md#bridge-configuration)
+for more on bridges.
+
+### OSPF over GRE
+
+GRE tunnels are commonly used to carry dynamic routing protocols like
+OSPF across networks that don't support multicast or where you want to
+create a virtual topology different from the physical network.
+
+Example topology: Two sites connected via a GRE tunnel, running OSPF to
+exchange routes.
+
+**Site A configuration:**
+
+```
+admin@siteA:/> configure
+admin@siteA:/config/> edit interface gre0
+admin@siteA:/config/interface/gre0/> set gre local 203.0.113.1 remote 203.0.113.2
+admin@siteA:/config/interface/gre0/> set ipv4 address 10.255.0.1 prefix-length 30
+admin@siteA:/config/interface/gre0/> set ipv4 forwarding
+admin@siteA:/config/interface/gre0/> end
+admin@siteA:/config/> edit routing control-plane-protocol ospfv2 name default ospf
+admin@siteA:/config/routing/…/ospf/> set area 0.0.0.0 interface gre0
+admin@siteA:/config/routing/…/ospf/> leave
+admin@siteA:/>
+```
+
+**Site B configuration:**
+
+```
+admin@siteB:/> configure
+admin@siteB:/config/> edit interface gre0
+admin@siteB:/config/interface/gre0/> set gre local 203.0.113.2 remote 203.0.113.1
+admin@siteB:/config/interface/gre0/> set ipv4 address 10.255.0.2 prefix-length 30
+admin@siteB:/config/interface/gre0/> set ipv4 forwarding
+admin@siteB:/config/interface/gre0/> end
+admin@siteB:/config/> edit routing control-plane-protocol ospfv2 name default ospf
+admin@siteB:/config/routing/…/ospf/> set area 0.0.0.0 interface gre0
+admin@siteB:/config/routing/…/ospf/> leave
+admin@siteB:/>
+```
+
+Once configured, OSPF will establish a neighbor relationship through the
+tunnel and exchange routes between the sites. For more on OSPF
+configuration, see [Routing Configuration](routing.md).
+
+> [!NOTE]
+> Consider adjusting MTU on the tunnel interface to account for GRE
+> overhead (typically 24 bytes for IPv4, 44 bytes for IPv6) to avoid
+> fragmentation issues.
+
+
+### Advanced Tunnel Settings
+
+All tunnel types support common parameters for controlling tunnel behavior
+and performance.
+
+#### Time To Live (TTL)
+
+The TTL setting controls the Time To Live value for the outer tunnel packets.
+By default, tunnels use a fixed TTL of 64, which allows packets to traverse
+multiple hops between tunnel endpoints.
+
+```
+admin@example:/config/> edit interface gre0
+admin@example:/config/interface/gre0/> set gre ttl 255
+admin@example:/config/interface/gre0/> leave
+```
+
+Valid values are 1-255, or the special value `inherit` which copies the TTL
+from the encapsulated packet.
+
+> [!IMPORTANT]
+> The `inherit` mode can cause problems with routing protocols like OSPF
+> that use TTL=1 for their packets. For tunnels carrying routing protocols,
+> always use a fixed TTL value (typically 64 or 255).
+
+#### Type of Service (ToS)
+
+The ToS setting controls QoS marking for tunnel traffic:
+
+```
+admin@example:/config/> edit interface gre0
+admin@example:/config/interface/gre0/> set gre tos 0x10
+admin@example:/config/interface/gre0/> leave
+```
+
+Valid values are 0-255 for fixed ToS/DSCP marking, or `inherit` (default)
+to copy the ToS value from the encapsulated packet.
+
+#### Path MTU Discovery (GRE only)
+
+The `pmtu-discovery` setting can be used to control the Path MTU Discovery on
+GRE tunnels. When enabled (default), the tunnel respects the Don't Fragment
+(DF) bit and performs PMTU discovery:
+
+```
+admin@example:/config/> edit interface gre0
+admin@example:/config/interface/gre0/> set gre pmtudisc false
+admin@example:/config/interface/gre0/> leave
+```
+
+Disabling PMTU discovery may be necessary in networks with broken ICMP
+filtering but can lead to suboptimal performance and fragmentation.
+
+## Virtual eXtensible Local Area Network (VXLAN)
+
+VXLAN is a network virtualization technology that encapsulates Layer 2
+Ethernet frames within Layer 4 UDP datagrams. It uses a 24-bit segment
+ID, termed VXLAN Network Identifier (VNI), allowing up to 16 million
+isolated networks.
+
+Infix supports both IPv4 and IPv6 for VXLAN tunnel endpoints.
+
+### Basic VXLAN Configuration
+
+> [!TIP]
+> If you name your VXLAN interface `vxlanN`, where `N` is a number, the
+> CLI infers the interface type automatically.
+
+```
+admin@example:/> configure
admin@example:/config/> edit interface vxlan100
admin@example:/config/interface/vxlan100/> set vxlan local 192.168.3.1
admin@example:/config/interface/vxlan100/> set vxlan remote 192.168.3.2
admin@example:/config/interface/vxlan100/> set vxlan vni 100
admin@example:/config/interface/vxlan100/> leave
+admin@example:/>
```
+
+The VNI uniquely identifies the VXLAN segment and must match on both
+tunnel endpoints.
+
+### VXLAN with Custom UDP Port
+
+The default VXLAN UDP destination port is 4789 (IANA assigned). In some
+cases you may need to use a different port:
+
+```
+admin@example:/> configure
+admin@example:/config/> edit interface vxlan100
+admin@example:/config/interface/vxlan100/> set vxlan local 192.168.3.1
+admin@example:/config/interface/vxlan100/> set vxlan remote 192.168.3.2
+admin@example:/config/interface/vxlan100/> set vxlan vni 100
+admin@example:/config/interface/vxlan100/> set vxlan remote-port 8472
+admin@example:/config/interface/vxlan100/> leave
+admin@example:/>
+```
+
+The remote-port setting allows interoperability with systems using
+non-standard VXLAN ports.
+
+> [!NOTE]
+> VXLAN tunnels also support the `ttl` and `tos` settings described in
+> the [Advanced Tunnel Settings](#advanced-tunnel-settings) section above.
diff --git a/doc/wifi.md b/doc/wifi.md
index be5574b3..60dfbe65 100644
--- a/doc/wifi.md
+++ b/doc/wifi.md
@@ -83,9 +83,9 @@ and 63 characters
```
admin@example:/> configure
admin@example:/config/> edit keystore symmetric-key example
-admin@example:/config/keystore/symmetric-key/example/> set key-format wifi-preshared-key-format
-admin@example:/config/keystore/symmetric-key/example/> set cleartext-key mysecret
-admin@example:/config/keystore/symmetric-key/example/> leave
+admin@example:/config/keystore/…/example/> set key-format wifi-preshared-key-format
+admin@example:/config/keystore/…/example/> set cleartext-key mysecret
+admin@example:/config/keystore/…/example/> leave
admin@example:/>
```
diff --git a/src/confd/src/infix-if-gre.c b/src/confd/src/infix-if-gre.c
index 5f17e6f3..dbb96224 100644
--- a/src/confd/src/infix-if-gre.c
+++ b/src/confd/src/infix-if-gre.c
@@ -5,7 +5,8 @@
int gre_gen(struct lyd_node *dif, struct lyd_node *cif, FILE *ip)
{
- const char *local, *remote;
+ const char *local, *remote, *ttl, *tos, *pmtudisc;
+ const char *ifname = lydx_get_cattr(cif, "name");
struct lyd_node *gre;
int ipv6;
@@ -15,8 +16,7 @@ int gre_gen(struct lyd_node *dif, struct lyd_node *cif, FILE *ip)
ipv6 = !!strstr(local, ":");
- fprintf(ip, "link add name %s",
- lydx_get_cattr(cif, "name"));
+ fprintf(ip, "link add name %s", ifname);
switch (iftype_from_iface(cif)) {
case IFT_GRE:
@@ -30,6 +30,24 @@ int gre_gen(struct lyd_node *dif, struct lyd_node *cif, FILE *ip)
return -EINVAL;
}
- fprintf(ip, " local %s remote %s\n", local, remote);
+ fprintf(ip, " local %s remote %s", local, remote);
+
+ ttl = lydx_get_cattr(gre, "ttl");
+ if (ttl)
+ fprintf(ip, " ttl %s", ttl);
+
+ tos = lydx_get_cattr(gre, "tos");
+ if (tos)
+ fprintf(ip, " tos %s", tos);
+
+ pmtudisc = lydx_get_cattr(gre, "pmtu-discovery");
+ if (pmtudisc && !strcmp(pmtudisc, "false"))
+ fprintf(ip, " nopmtudisc");
+
+ fputc('\n', ip);
+
+ /* GRE interfaces don't have IFF_MULTICAST by default */
+ fprintf(ip, "link set dev %s multicast on\n", ifname);
+
return 0;
}
diff --git a/src/confd/src/infix-if-vxlan.c b/src/confd/src/infix-if-vxlan.c
index e270c8c4..f4e6ae98 100644
--- a/src/confd/src/infix-if-vxlan.c
+++ b/src/confd/src/infix-if-vxlan.c
@@ -6,6 +6,7 @@
int vxlan_gen(struct lyd_node *dif, struct lyd_node *cif, FILE *ip)
{
struct lyd_node *vxlan = NULL;
+ const char *ttl, *tos;
vxlan = lydx_get_descendant(lyd_child(cif), "vxlan", NULL);
if (!vxlan)
@@ -18,6 +19,14 @@ int vxlan_gen(struct lyd_node *dif, struct lyd_node *cif, FILE *ip)
lydx_get_cattr(vxlan, "remote"),
lydx_get_cattr(vxlan, "remote-port"));
+ ttl = lydx_get_cattr(vxlan, "ttl");
+ if (ttl)
+ fprintf(ip, " ttl %s", ttl);
+
+ tos = lydx_get_cattr(vxlan, "tos");
+ if (tos)
+ fprintf(ip, " tos %s", tos);
+
link_gen_address(cif, ip);
fputc('\n', ip);
diff --git a/src/confd/yang/confd.inc b/src/confd/yang/confd.inc
index cb005656..bc747889 100644
--- a/src/confd/yang/confd.inc
+++ b/src/confd/yang/confd.inc
@@ -37,7 +37,7 @@ MODULES=(
"ieee802-ethernet-interface@2019-06-21.yang"
"infix-ethernet-interface@2024-02-27.yang"
"infix-factory-default@2023-06-28.yang"
- "infix-interfaces@2025-06-17.yang -e vlan-filtering"
+ "infix-interfaces@2025-11-06.yang -e vlan-filtering"
"ietf-crypto-types -e cleartext-symmetric-keys"
"infix-crypto-types@2025-06-17.yang"
"ietf-keystore -e symmetric-keys"
diff --git a/src/confd/yang/confd/infix-if-gre.yang b/src/confd/yang/confd/infix-if-gre.yang
index f8f9b3ef..6cd48ce9 100644
--- a/src/confd/yang/confd/infix-if-gre.yang
+++ b/src/confd/yang/confd/infix-if-gre.yang
@@ -16,6 +16,12 @@ submodule infix-if-gre {
contact "kernelkit@googlegroups.com";
description "GRE and GRETAP tunnel extension for ietf-interfaces";
+ revision 2025-11-06 {
+ description "Use tunnel-common grouping for local, remote, TTL, and TOS/DSCP.
+ Add GRE-specific pmtu-discovery setting.";
+ reference "internal";
+ }
+
revision 2024-12-20 {
description "Initial revision.";
reference "internal";
@@ -29,7 +35,21 @@ submodule infix-if-gre {
description "Augments the interface model with GRE tunnels.";
container gre {
- uses local-remote;
+ uses tunnel-common;
+
+ leaf pmtu-discovery {
+ type boolean;
+ default true;
+ description
+ "Enable or disable Path MTU Discovery on the tunnel.
+
+ When enabled (default), the tunnel respects the Don't Fragment (DF)
+ bit and performs PMTU discovery. When disabled, the tunnel will
+ fragment packets as needed.
+
+ Disabling PMTU discovery may be necessary in networks with broken
+ ICMP filtering but can lead to suboptimal performance.";
+ }
}
}
}
diff --git a/src/confd/yang/confd/infix-if-gre@2024-12-20.yang b/src/confd/yang/confd/infix-if-gre@2025-11-06.yang
similarity index 100%
rename from src/confd/yang/confd/infix-if-gre@2024-12-20.yang
rename to src/confd/yang/confd/infix-if-gre@2025-11-06.yang
diff --git a/src/confd/yang/confd/infix-if-vxlan.yang b/src/confd/yang/confd/infix-if-vxlan.yang
index 8523433c..a58cca11 100644
--- a/src/confd/yang/confd/infix-if-vxlan.yang
+++ b/src/confd/yang/confd/infix-if-vxlan.yang
@@ -20,6 +20,11 @@ submodule infix-if-vxlan {
contact "kernelkit@googlegroups.com";
description "VXLAN tunnel extension for ietf-interfaces";
+ revision 2025-11-06 {
+ description "Use new tunnel-common grouping for local, remote, ttl, and tos.";
+ reference "internal";
+ }
+
revision 2025-01-13 {
description "Initial revision.";
reference "internal";
@@ -36,18 +41,19 @@ submodule infix-if-vxlan {
}
description "Augments the interface model with VXLAN tunnels.";
container vxlan {
- uses local-remote;
+ uses tunnel-common;
+
leaf remote-port {
type inet-types:port-number;
default 4789;
description
- "VXLAN destination UDP port. Valid range: 0..65535. Default is 4789 (IANA-assigned VXLAN UDP port).";
+ "VXLAN destination UDP port, valid range: 0..65535.";
}
leaf vni {
type vni;
mandatory true;
description
- "VXLAN Network Identifier (VNI), valid values are 0 to 16777215.";
+ "VXLAN Network Identifier (VNI), valid range: 0..16777215.";
}
}
}
diff --git a/src/confd/yang/confd/infix-if-vxlan@2025-01-13.yang b/src/confd/yang/confd/infix-if-vxlan@2025-11-06.yang
similarity index 100%
rename from src/confd/yang/confd/infix-if-vxlan@2025-01-13.yang
rename to src/confd/yang/confd/infix-if-vxlan@2025-11-06.yang
diff --git a/src/confd/yang/confd/infix-interfaces.yang b/src/confd/yang/confd/infix-interfaces.yang
index 592d2318..9fea0434 100644
--- a/src/confd/yang/confd/infix-interfaces.yang
+++ b/src/confd/yang/confd/infix-interfaces.yang
@@ -33,6 +33,11 @@ module infix-interfaces {
contact "kernelkit@googlegroups.com";
description "Linux bridge and lag extensions for ietf-interfaces.";
+ revision 2025-11-06 {
+ description "Use new tunnel-common grouping for local, remote, ttl, and tos.";
+ reference "internal";
+ }
+
revision 2025-06-17 {
description "Add support for Wi-Fi client.";
reference "internal";
@@ -106,14 +111,16 @@ module infix-interfaces {
reference "internal";
}
- grouping local-remote {
- description "Local address to use as source address";
+ grouping tunnel-common {
+ description "Common tunnel parameters applicable to all tunnel types.";
+
leaf local {
type inet:ip-address;
mandatory true;
+ description "Local address to use as source address for the tunnel.";
}
+
leaf remote {
- description "Peer address";
type inet:ip-address;
must "(contains(../local, ':') and contains(., ':'))
or (not(contains(../local, ':')) and not(contains(., ':')))" {
@@ -121,6 +128,48 @@ module infix-interfaces {
"Local and remote must be both IPv4 or both IPv6 addresses.";
}
mandatory true;
+ description "Remote peer address for the tunnel.";
+ }
+
+ leaf ttl {
+ type union {
+ type uint8 {
+ range "1..255";
+ }
+ type enumeration {
+ enum inherit {
+ description
+ "Copy TTL from inner packet (default kernel behavior).
+ WARNING: This can cause issues with protocols like OSPF
+ that use TTL=1 for their packets.";
+ }
+ }
+ }
+ default 64;
+ description
+ "Time To Live (TTL) for IPv4 or Hop Limit for IPv6 tunnel packets.
+ A fixed value (1-255) sets the outer packet TTL regardless of inner
+ packet TTL. The 'inherit' mode copies TTL from the encapsulated packet.
+
+ For OSPF and other routing protocols over tunnels, a fixed value
+ (typically 64 or 255) should be used to ensure packets can traverse
+ multiple hops between tunnel endpoints.";
+ }
+
+ leaf tos {
+ type union {
+ type uint8;
+ type enumeration {
+ enum inherit {
+ description "Copy ToS/DSCP from inner packet.";
+ }
+ }
+ }
+ default "inherit";
+ description
+ "Type of Service (IPv4) or Traffic Class (IPv6) for tunnel packets.
+ Can be a fixed value (0-255) for QoS marking, or 'inherit' to copy
+ from the encapsulated packet.";
}
}
diff --git a/src/confd/yang/confd/infix-interfaces@2025-06-17.yang b/src/confd/yang/confd/infix-interfaces@2025-11-06.yang
similarity index 100%
rename from src/confd/yang/confd/infix-interfaces@2025-06-17.yang
rename to src/confd/yang/confd/infix-interfaces@2025-11-06.yang
diff --git a/test/case/ietf_interfaces/tunnel_ttl/Readme.adoc b/test/case/ietf_interfaces/tunnel_ttl/Readme.adoc
new file mode 100644
index 00000000..062cb018
--- /dev/null
+++ b/test/case/ietf_interfaces/tunnel_ttl/Readme.adoc
@@ -0,0 +1,6 @@
+include::gre.adoc[]
+
+<<<
+
+include::vxlan.adoc[]
+
diff --git a/test/case/ietf_interfaces/tunnel_ttl/gre.adoc b/test/case/ietf_interfaces/tunnel_ttl/gre.adoc
new file mode 100644
index 00000000..6b42cc0a
--- /dev/null
+++ b/test/case/ietf_interfaces/tunnel_ttl/gre.adoc
@@ -0,0 +1,32 @@
+=== GRE Tunnel TTL verification
+
+ifdef::topdoc[:imagesdir: {topdoc}../../test/case/ietf_interfaces/tunnel_ttl]
+
+==== Description
+
+Verify that GRE and VXLAN tunnels use a fixed TTL (default 64) for
+encapsulated frames instead of inheriting the TTL from inner packets.
+Critical for protocols like OSPF that use TTL=1 for their packets.
+
+The test setup creates a tunnel between R1 and R3 so that injecting
+a frame with TTL=3 from PC:west, routing it through the tunnel, it
+would still reach PC:east. (Had it been routed via R2 it would be too
+many hops and the TTL would reach zero before the last routing step.)
+
+ PC:west -- R1 -- R2 -- R3 -- PC:east
+ `== Tunnel =='
+
+==== Topology
+
+image::topology.svg[GRE Tunnel TTL verification topology, align=center, scaledwidth=75%]
+
+==== Sequence
+
+. Set up topology and attach to target DUTs
+. Configure R1 with gre tunnel to R3
+. Configure R2 as intermediate router (underlay forwarding)
+. Configure R3 with gre tunnel to R1
+. Send ping from PC:west to PC:east with low TTL
+. Verify packets arrived at PC:east
+
+
diff --git a/test/case/ietf_interfaces/tunnel_ttl/gre.py b/test/case/ietf_interfaces/tunnel_ttl/gre.py
new file mode 120000
index 00000000..94656643
--- /dev/null
+++ b/test/case/ietf_interfaces/tunnel_ttl/gre.py
@@ -0,0 +1 @@
+test.py
\ No newline at end of file
diff --git a/test/case/ietf_interfaces/tunnel_ttl/test.py b/test/case/ietf_interfaces/tunnel_ttl/test.py
new file mode 100755
index 00000000..72c4f9a4
--- /dev/null
+++ b/test/case/ietf_interfaces/tunnel_ttl/test.py
@@ -0,0 +1,269 @@
+#!/usr/bin/env python3
+"""Tunnel TTL Verification
+
+Verify that GRE and VXLAN tunnels use a fixed TTL (default 64) for
+encapsulated frames instead of inheriting the TTL from inner packets.
+Critical for protocols like OSPF that use TTL=1 for their packets.
+
+The test setup creates a tunnel between R1 and R3 so that injecting
+a frame with TTL=3 from PC:west, routing it through the tunnel, it
+would still reach PC:east. (Had it been routed via R2 it would be too
+many hops and the TTL would reach zero before the last routing step.)
+
+ PC:west -- R1 -- R2 -- R3 -- PC:east
+ `== Tunnel =='
+
+"""
+
+import infamy
+
+
+class ArgumentParser(infamy.ArgumentParser):
+ def __init__(self):
+ super().__init__()
+ self.add_argument("--tunnel")
+
+# IP address plan
+# PC:west subnet
+PC_WEST_R1 = "192.168.10.1"
+PC_WEST_HOST = "192.168.10.2"
+PC_WEST_NET = "192.168.10.0/24"
+
+# R1-R2 underlay subnet
+R1_R2_R1 = "192.168.50.1"
+R1_R2_R2 = "192.168.50.2"
+R1_R2_NET = "192.168.50.0/24"
+
+# R2-R3 underlay subnet
+R2_R3_R2 = "192.168.60.1"
+R2_R3_R3 = "192.168.60.2"
+R2_R3_NET = "192.168.60.0/24"
+
+# PC:east subnet
+PC_EAST_R3 = "192.168.70.1"
+PC_EAST_HOST = "192.168.70.2"
+PC_EAST_NET = "192.168.70.0/24"
+
+# Tunnel subnet
+TUNNEL_R1 = "10.255.0.1"
+TUNNEL_R3 = "10.255.0.2"
+TUNNEL_NET = "10.255.0.0/30"
+
+# Prefix lengths
+PREFIX_24 = 24
+PREFIX_30 = 30
+
+# Test TTL value
+TEST_TTL = 3
+
+# VXLAN VNI
+VNI = 10
+
+
+with infamy.Test() as test:
+ with test.step("Set up topology and attach to target DUTs"):
+ arg = ArgumentParser()
+ env = infamy.Env(args=arg)
+ tunnel = env.args.tunnel
+ r1 = env.attach("R1", "mgmt")
+ r2 = env.attach("R2", "mgmt")
+ r3 = env.attach("R3", "mgmt")
+
+ with test.step(f"Configure R1 with {tunnel} tunnel to R3"):
+ # R1: Entry point, west facing PC, east facing R2, tunnel to R3
+
+ # Build tunnel container configs
+ container_r1 = {
+ "local": R1_R2_R1,
+ "remote": R2_R3_R3
+ }
+ container_r3 = {
+ "local": R2_R3_R3,
+ "remote": R1_R2_R1
+ }
+
+ CONTAINER_TYPE = tunnel
+ if tunnel == "vxlan":
+ container_r1["vni"] = VNI
+ container_r3["vni"] = VNI
+
+ r1.put_config_dicts({"ietf-interfaces": {
+ "interfaces": {
+ "interface": [{
+ "name": r1["west"],
+ "ipv4": {
+ "address": [{
+ "ip": PC_WEST_R1,
+ "prefix-length": PREFIX_24
+ }],
+ "forwarding": True
+ }
+ }, {
+ "name": r1["east"],
+ "ipv4": {
+ "address": [{
+ "ip": R1_R2_R1,
+ "prefix-length": PREFIX_24
+ }],
+ "forwarding": True
+ }
+ }, {
+ "name": f"{tunnel}0",
+ "type": f"infix-if-type:{tunnel}",
+ "ipv4": {
+ "address": [{
+ "ip": TUNNEL_R1,
+ "prefix-length": PREFIX_30
+ }],
+ "forwarding": True
+ },
+ CONTAINER_TYPE: container_r1
+ }]
+ }
+ }, "ietf-routing": {
+ "routing": {
+ "control-plane-protocols": {
+ "control-plane-protocol": [{
+ "type": "infix-routing:static",
+ "name": "default",
+ "static-routes": {
+ "ipv4": {
+ "route": [{
+ "destination-prefix": R2_R3_NET,
+ "next-hop": {
+ "next-hop-address": R1_R2_R2
+ }
+ }, {
+ "destination-prefix": PC_EAST_NET,
+ "next-hop": {
+ "next-hop-address": TUNNEL_R3
+ }
+ }]
+ }
+ }
+ }]
+ }
+ }
+ }})
+
+ with test.step("Configure R2 as intermediate router (underlay forwarding)"):
+ # R2: Intermediate router, just forwards packets between west and east
+ r2.put_config_dicts({"ietf-interfaces": {
+ "interfaces": {
+ "interface": [{
+ "name": r2["west"],
+ "ipv4": {
+ "address": [{
+ "ip": R1_R2_R2,
+ "prefix-length": PREFIX_24
+ }],
+ "forwarding": True
+ }
+ }, {
+ "name": r2["east"],
+ "ipv4": {
+ "address": [{
+ "ip": R2_R3_R2,
+ "prefix-length": PREFIX_24
+ }],
+ "forwarding": True
+ }
+ }]
+ }
+ }})
+
+ with test.step(f"Configure R3 with {tunnel} tunnel to R1"):
+ # R3: Exit point, west facing R2, east facing PC, tunnel to R1
+ r3.put_config_dicts({"ietf-interfaces": {
+ "interfaces": {
+ "interface": [{
+ "name": r3["west"],
+ "ipv4": {
+ "address": [{
+ "ip": R2_R3_R3,
+ "prefix-length": PREFIX_24
+ }],
+ "forwarding": True
+ }
+ }, {
+ "name": r3["east"],
+ "ipv4": {
+ "address": [{
+ "ip": PC_EAST_R3,
+ "prefix-length": PREFIX_24
+ }],
+ "forwarding": True
+ }
+ }, {
+ "name": f"{tunnel}0",
+ "type": f"infix-if-type:{tunnel}",
+ "ipv4": {
+ "address": [{
+ "ip": TUNNEL_R3,
+ "prefix-length": PREFIX_30
+ }],
+ "forwarding": True
+ },
+ CONTAINER_TYPE: container_r3
+ }]
+ }
+ }, "ietf-routing": {
+ "routing": {
+ "control-plane-protocols": {
+ "control-plane-protocol": [{
+ "type": "infix-routing:static",
+ "name": "default",
+ "static-routes": {
+ "ipv4": {
+ "route": [{
+ "destination-prefix": R1_R2_NET,
+ "next-hop": {
+ "next-hop-address": R2_R3_R2
+ }
+ }, {
+ "destination-prefix": PC_WEST_NET,
+ "next-hop": {
+ "next-hop-address": TUNNEL_R1
+ }
+ }]
+ }
+ }
+ }]
+ }
+ }
+ }})
+
+ with test.step("Send ping from PC:west to PC:east with low TTL"):
+ _, pc_east = env.ltop.xlate("PC", "east")
+
+ with infamy.IsolatedMacVlan(pc_east) as east_ns:
+ east_ns.addip(PC_EAST_HOST)
+ east_ns.addroute("default", PC_EAST_R3)
+
+ pcap = east_ns.pcap("icmp")
+ with pcap:
+ _, pc_west = env.ltop.xlate("PC", "west")
+ with infamy.IsolatedMacVlan(pc_west) as west_ns:
+ west_ns.addip(PC_WEST_HOST)
+ west_ns.addroute("default", PC_WEST_R1)
+
+ # Send 3 pings with TTL=3, TTL is decremented before each
+ # router hop. So at PC:west (TTL=3) -> R1 routed to GRE
+ # tunnel (TTL=2) -> frame egresses tunnel -> R3 where it
+ # is routed to PC:east (TTL=1).
+ #
+ # If outer TTL was inherited (TTL=2), packet would be
+ # dropped at R3.
+ west_ns.runsh(f"ping -c 3 -t {TEST_TTL} {PC_EAST_HOST}")
+
+ with test.step("Verify packets arrived at PC:east"):
+ packets = pcap.tcpdump()
+ print("Captured packets on PC:east:")
+ print(packets)
+
+ pings = [line for line in packets.splitlines()
+ if f"{PC_WEST_HOST} > {PC_EAST_HOST}: ICMP echo request" in line]
+
+ assert len(pings) >= 1, f"Expected at least 1 ping, got {len(pings)}."
+
+ test.succeed()
diff --git a/test/case/ietf_interfaces/tunnel_ttl/test.yaml b/test/case/ietf_interfaces/tunnel_ttl/test.yaml
new file mode 100644
index 00000000..4b38e5d8
--- /dev/null
+++ b/test/case/ietf_interfaces/tunnel_ttl/test.yaml
@@ -0,0 +1,11 @@
+---
+- settings:
+ test-spec: