From 9f3c9ce503a1f983ee8fffeb6f1eaf571b976ca0 Mon Sep 17 00:00:00 2001
From: Jacek Kowalski <Jacek@jacekk.info>
Date: Fri, 13 Mar 2026 09:19:04 +0000
Subject: [PATCH] Move gw4/gw6 options to network level (with optional overrides)
---
test_integration.sh | 58 +++++++++++++++++++++++++++++
lib/NetworkDriver.py | 4 +-
README.md | 24 +++++++----
3 files changed, 75 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index dce319d..aa1a02a 100644
--- a/README.md
+++ b/README.md
@@ -57,6 +57,20 @@
Disable assignment of IPv6 gateway IP.
+`gw4=IP`
+
+`gw6=IP`
+
+Forces assignment of a specified gateway (only if one is not provided by the IPAM module)
+when creating the interface. Useful for [pyipam](https://github.com/jacekkow/docker-plugin-pyipam)
+with `ptp=1` option and `nogw=1`/`nogw4=1`/`nogw6=1` here.
+
+Using these would add routes like:
+```
+default via IP dev eth0
+IP dev eth0 scope link
+```
+
## Container creation options
To use these options add `--network name=network_name,driver-opt=option=value,driver-opt=option=value`
@@ -72,15 +86,7 @@
`gw6=IP`
-Forces assignment of a specified gateway (if one is not provided by the IPAM)
-when creating the interface. Useful for [pyipam](https://github.com/jacekkow/docker-plugin-pyipam)
-with "ptp=1,nogw=1" options.
-
-Using these would add routes:
-```
-default via IP dev eth0
-IP dev eth0 scope link
-```
+Overrides network-level gw4/gw6 options.
## Manual packaging
diff --git a/lib/NetworkDriver.py b/lib/NetworkDriver.py
index e48071a..478414b 100644
--- a/lib/NetworkDriver.py
+++ b/lib/NetworkDriver.py
@@ -163,14 +163,14 @@
result['Gateway'] = gw4.ip.compressed
if gw6 is not None:
result['GatewayIPv6'] = gw6.ip.compressed
- gw4 = endpoint.Options.get("gw4", None)
+ gw4 = endpoint.Options.get("gw4", network.Options.get("gw4", None))
if gw4 is not None:
result['StaticRoutes'].append({
'Destination': gw4 + '/32',
'RouteType': 1,
})
result['Gateway'] = gw4
- gw6 = endpoint.Options.get("gw6", None)
+ gw6 = endpoint.Options.get("gw6", network.Options.get("gw6", None))
if gw6 is not None:
result['StaticRoutes'].append({
'Destination': gw6 + '/128',
diff --git a/test_integration.sh b/test_integration.sh
index 9f1744c..e695f08 100755
--- a/test_integration.sh
+++ b/test_integration.sh
@@ -193,3 +193,61 @@
fi
docker network rm test2
+
+
+###############
+# Test gw4/gw6
+
+docker network create \
+ --internal \
+ --driver "${PLUGIN}" \
+ --opt nogw=1 \
+ --opt gw4=192.168.254.1 \
+ --ipam-driver jacekkow/pyipam:latest \
+ --ipam-opt ptp=1 \
+ --ipv6 \
+ --subnet 192.168.255.0/24 \
+ --subnet 2001:db8::/32 \
+ test2
+
+ADDRESSES=$(docker run --rm --network test2 \
+ alpine \
+ /sbin/ip addr show
+)
+if ! echo "${ADDRESSES}" | grep 192.168.255.0/32; then
+ echo "ERROR: invalid PtP address assigned"
+ exit 1
+fi
+if ! echo "${ADDRESSES}" | grep 2001:db8::/128; then
+ echo "ERROR: invalid PtP address assigned"
+ exit 1
+fi
+
+ROUTES=$(docker run --rm --network test2 \
+ alpine \
+ /sbin/ip route show
+)
+if ! echo "${ROUTES}" | grep "via 192.168.254.1"; then
+ echo "ERROR: IPv4 route not assigned with gw4=..."
+ exit 1
+fi
+
+ROUTES=$(docker run --rm --network test2 \
+ alpine \
+ /sbin/ip -6 route show
+)
+if echo "${ROUTES}" | grep default; then
+ echo "ERROR: IPv6 route assigned with nogw=1"
+ exit 1
+fi
+
+ROUTES=$(docker run --rm --network name=test2,driver-opt=gw6=fe80::1 \
+ alpine \
+ /sbin/ip -6 route show
+)
+if ! echo "${ROUTES}" | grep "via fe80::1"; then
+ echo "ERROR: IPv6 route not assigned with per-container gw6=..."
+ exit 1
+fi
+
+docker network rm test2
--
Gitblit v1.10.0