Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b0226d5

Browse filesBrowse files
authored
Merge pull request #48971 from robmry/ipv6_disabled_on_interface
Release IPv6 address if IPv6 is disabled on an interface
2 parents da5ca1b + 2bb0443 commit b0226d5
Copy full SHA for b0226d5

15 files changed

+388-119Lines changed: 388 additions & 119 deletions
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎daemon/container_operations.go‎

Copy file name to clipboardExpand all lines: daemon/container_operations.go
+21-3Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -739,11 +739,22 @@ func (daemon *Daemon) connectToNetwork(ctx context.Context, cfg *config.Config,
739739
delete(ctr.NetworkSettings.Networks, nwName)
740740
}
741741
}()
742-
if err := daemon.updateEndpointNetworkSettings(cfg, ctr, n, ep); err != nil {
743-
return err
744-
}
745742

746743
if nwName == network.DefaultNetwork {
744+
// Legacy links must be prepared before the Endpoint.Join, because the network
745+
// driver needs info about them - and, the daemon's network settings need to be
746+
// filled-in for daemon.addLegacyLinks(). So, set up both here.
747+
//
748+
// However, this means if the Endpoint.Join drops the endpoint's IPv6 address
749+
// (because there's a sysctl setting or some equivalent disabling IPv6 on the
750+
// interface), host entries set up by addLegacyLinks() for IPv6 addresses of the
751+
// linked container will be left behind in the container's /etc/hosts file. It
752+
// won't be able to use those addresses, because it won't have IPv6 on that
753+
// interface. So, even if the address is recycled by another container on the
754+
// network, the old hosts entry can't access the wrong container.
755+
if err := daemon.updateEndpointNetworkSettings(cfg, ctr, n, ep); err != nil {
756+
return err
757+
}
747758
if err := daemon.addLegacyLinks(ctx, cfg, ctr, endpointConfig, sb); err != nil {
748759
return err
749760
}
@@ -754,10 +765,17 @@ func (daemon *Daemon) connectToNetwork(ctx context.Context, cfg *config.Config,
754765
return err
755766
}
756767

768+
// Connect the container to the network. Note that this will release the IPv6
769+
// address assigned to the Endpoint, if IPv6 is disabled on the interface
770+
// (probably by an endpoint specific sysctl setting).
757771
if err := ep.Join(ctx, sb, joinOptions...); err != nil {
758772
return err
759773
}
760774

775+
if err := daemon.updateEndpointNetworkSettings(cfg, ctr, n, ep); err != nil {
776+
return err
777+
}
778+
761779
if !ctr.Managed {
762780
// add container name/alias to DNS
763781
if err := daemon.ActivateContainerServiceBinding(ctr.Name); err != nil {
Collapse file

‎daemon/libnetwork/driverapi/driverapi.go‎

Copy file name to clipboardExpand all lines: daemon/libnetwork/driverapi/driverapi.go
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,15 @@ type ExtConner interface {
107107
ProgramExternalConnectivity(ctx context.Context, nid, eid string, gw4Id, gw6Id string) error
108108
}
109109

110+
// IPv6Releaser is an optional interface for a network driver.
111+
type IPv6Releaser interface {
112+
// ReleaseIPv6 tells the driver that an endpoint has no IPv6 address, even
113+
// if the options passed to Driver.CreateEndpoint specified an address. This
114+
// happens when, for example, sysctls applied after configuring the interface
115+
// disable IPv6.
116+
ReleaseIPv6(ctx context.Context, nid, eid string) error
117+
}
118+
110119
// GwAllocChecker is an optional interface for a network driver.
111120
type GwAllocChecker interface {
112121
// GetSkipGwAlloc returns true if the opts describe a network
Collapse file

‎daemon/libnetwork/drivers/bridge/bridge_linux.go‎

Copy file name to clipboardExpand all lines: daemon/libnetwork/drivers/bridge/bridge_linux.go
+26-1Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ type containerConfiguration struct {
127127
type connectivityConfiguration struct {
128128
PortBindings []portmapperapi.PortBindingReq
129129
ExposedPorts []types.TransportPort
130-
NoProxy6To4 bool
131130
}
132131

133132
type bridgeEndpoint struct {
@@ -167,6 +166,9 @@ type driver struct {
167166
mu sync.Mutex
168167
}
169168

169+
// Assert that the driver is a driverapi.IPv6Releaser.
170+
var _ driverapi.IPv6Releaser = (*driver)(nil)
171+
170172
type gwMode string
171173

172174
const (
@@ -1437,6 +1439,29 @@ func (d *driver) Join(ctx context.Context, nid, eid string, sboxKey string, jinf
14371439
return nil
14381440
}
14391441

1442+
func (d *driver) ReleaseIPv6(ctx context.Context, nid, eid string) error {
1443+
network, err := d.getNetwork(nid)
1444+
if err != nil {
1445+
return err
1446+
}
1447+
1448+
endpoint, err := network.getEndpoint(eid)
1449+
if err != nil {
1450+
return err
1451+
}
1452+
1453+
if endpoint == nil {
1454+
return endpointNotFoundError(eid)
1455+
}
1456+
1457+
_, netip6 := endpoint.netipAddrs()
1458+
if err := network.firewallerNetwork.DelEndpoint(ctx, netip.Addr{}, netip6); err != nil {
1459+
return fmt.Errorf("removing firewall rules while releasing IPv6 address: %v", err)
1460+
}
1461+
endpoint.addrv6 = nil
1462+
return nil
1463+
}
1464+
14401465
// Leave method is invoked when a Sandbox detaches from an endpoint.
14411466
func (d *driver) Leave(nid, eid string) error {
14421467
network, err := d.getNetwork(nid)
Collapse file

‎daemon/libnetwork/endpoint.go‎

Copy file name to clipboardExpand all lines: daemon/libnetwork/endpoint.go
+74-58Lines changed: 74 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"github.com/moby/moby/v2/daemon/libnetwork/netlabel"
2323
"github.com/moby/moby/v2/daemon/libnetwork/scope"
2424
"github.com/moby/moby/v2/daemon/libnetwork/types"
25-
"github.com/moby/moby/v2/errdefs"
2625
"go.opentelemetry.io/otel"
2726
)
2827

@@ -532,6 +531,8 @@ func (ep *Endpoint) sbJoin(ctx context.Context, sb *Sandbox, options ...Endpoint
532531
return fmt.Errorf("failed to get driver during join: %v", err)
533532
}
534533

534+
// Tell the driver about the new endpoint. The driver populates ep.joinInfo using
535+
// the Endpoint's JoinInfo interface.
535536
if err := d.Join(ctx, nid, epid, sb.Key(), ep, ep.generic, sb.Labels()); err != nil {
536537
return err
537538
}
@@ -549,61 +550,39 @@ func (ep *Endpoint) sbJoin(ctx context.Context, sb *Sandbox, options ...Endpoint
549550
ep.joinInfo.gw6 = nil
550551
}
551552

552-
if !n.getController().isAgent() {
553-
if !n.getController().isSwarmNode() || n.Scope() != scope.Swarm || !n.driverIsMultihost() {
554-
n.updateSvcRecord(context.WithoutCancel(ctx), ep, true)
555-
}
556-
}
557-
558-
sb.addHostsEntries(ctx, ep.getEtcHostsAddrs())
559-
if err := sb.updateDNS(n.enableIPv6); err != nil {
560-
return err
561-
}
562-
563-
// Current endpoint(s) providing external connectivity for the sandbox
553+
// Current endpoint(s) providing external connectivity for the Sandbox.
554+
// If ep is selected as a gateway endpoint once it's been added to the Sandbox,
555+
// these are the endpoints that need to be un-gateway'd.
564556
gwepBefore4, gwepBefore6 := sb.getGatewayEndpoint()
565557

566558
sb.addEndpoint(ep)
567559

568-
if err := sb.populateNetworkResources(ctx, ep); err != nil {
569-
return err
570-
}
571-
572-
if err := addEpToResolver(ctx, n.Name(), ep.Name(), &sb.config, ep.iface, n.Resolvers()); err != nil {
573-
return errdefs.System(err)
560+
// For Linux, at this point, in most cases, the container task has been created
561+
// and the container's network namespace (sb.osSbox) is ready to be configured
562+
// with addresses, routes and so on. The exception is when the SetKey re-exec is
563+
// used by a build container. In that case, the osSbox doesn't exist yet. So,
564+
// stop here and SetKey will finish off the configuration when it's ready.
565+
// For Windows, canPopulateNetworkResources() is always true.
566+
if sb.canPopulateNetworkResources() {
567+
if err := sb.populateNetworkResources(ctx, ep); err != nil {
568+
return err
569+
}
570+
if err := ep.updateExternalConnectivity(ctx, sb, gwepBefore4, gwepBefore6); err != nil {
571+
return err
572+
}
574573
}
575574

576575
if err := n.getController().storeEndpoint(ctx, ep); err != nil {
577576
return err
578577
}
578+
return nil
579+
}
579580

580-
if err := ep.addDriverInfoToCluster(); err != nil {
581-
return err
582-
}
583-
584-
defer func() {
585-
if retErr != nil {
586-
if e := ep.deleteDriverInfoFromCluster(); e != nil {
587-
log.G(ctx).WithError(e).Error("Could not delete endpoint state from cluster on join failure")
588-
}
589-
}
590-
}()
591-
592-
// Load balancing endpoints should never have a default gateway nor
593-
// should they alter the status of a network's default gateway
594-
if ep.loadBalancer && !sb.ingress {
595-
return nil
596-
}
597-
598-
if sb.needDefaultGW() && sb.getEndpointInGWNetwork() == nil {
599-
return sb.setupDefaultGW()
600-
}
601-
602-
// Enable upstream forwarding if the sandbox gained external connectivity.
603-
if sb.resolver != nil {
604-
sb.resolver.SetForwardingPolicy(sb.hasExternalAccess())
605-
}
606-
581+
// updateExternalConnectivity configures an Endpoint when it becomes the gateway
582+
// endpoint for a network, revoking external connectivity from the previous gateway
583+
// endpoints, if necessary. (It does not update the Sandbox's default gateway, the
584+
// Sandbox takes care of that. This is just about network driver config.)
585+
func (ep *Endpoint) updateExternalConnectivity(ctx context.Context, sb *Sandbox, gwepBefore4, gwepBefore6 *Endpoint) (retErr error) {
607586
gwepAfter4, gwepAfter6 := sb.getGatewayEndpoint()
608587

609588
log.G(ctx).Infof("sbJoin: gwep4 '%s'->'%s', gwep6 '%s'->'%s'",
@@ -649,16 +628,6 @@ func (ep *Endpoint) sbJoin(ctx context.Context, sb *Sandbox, options ...Endpoint
649628
return err
650629
}
651630

652-
if !sb.needDefaultGW() {
653-
if e := sb.clearDefaultGW(); e != nil {
654-
log.G(ctx).WithFields(log.Fields{
655-
"error": e,
656-
"sid": sb.ID(),
657-
"cid": sb.ContainerID(),
658-
}).Warn("Failure while disconnecting sandbox from gateway network")
659-
}
660-
}
661-
662631
return nil
663632
}
664633

@@ -971,7 +940,7 @@ func (ep *Endpoint) Delete(ctx context.Context, force bool) error {
971940
return err
972941
}
973942

974-
ep.releaseAddress()
943+
ep.releaseIPAddresses()
975944

976945
return nil
977946
}
@@ -1261,7 +1230,7 @@ func (ep *Endpoint) assignAddressVersion(ipVer int, ipam ipamapi.Ipam) error {
12611230
return fmt.Errorf("no available IPv%d addresses on this network's address pools: %s (%s)", ipVer, n.Name(), n.ID())
12621231
}
12631232

1264-
func (ep *Endpoint) releaseAddress() {
1233+
func (ep *Endpoint) releaseIPAddresses() {
12651234
n := ep.getNetwork()
12661235
if n.hasSpecialDriver() {
12671236
return
@@ -1288,6 +1257,53 @@ func (ep *Endpoint) releaseAddress() {
12881257
}
12891258
}
12901259

1260+
func (ep *Endpoint) releaseIPv6Address(ctx context.Context) error {
1261+
n := ep.network
1262+
ctx = log.WithLogger(ctx, log.G(ctx).WithFields(log.Fields{
1263+
"net": n.Name(),
1264+
"ep": ep.name,
1265+
"ip": ep.iface.addrv6,
1266+
}))
1267+
1268+
if ep.iface.addrv6 == nil || n.hasSpecialDriver() {
1269+
return nil
1270+
}
1271+
1272+
log.G(ctx).Debug("Releasing IPv6 address for endpoint")
1273+
1274+
ipam, _, err := n.getController().getIPAMDriver(n.ipamType)
1275+
if err != nil {
1276+
log.G(ctx).WithError(err).Warn("Failed to retrieve ipam driver to release IPv6 address")
1277+
return err
1278+
}
1279+
1280+
if err := ipam.ReleaseAddress(ep.iface.v6PoolID, ep.iface.addrv6.IP); err != nil {
1281+
log.G(ctx).WithError(err).Warn("Failed to release IPv6 address")
1282+
return err
1283+
}
1284+
1285+
ep.iface.addrv6 = nil
1286+
if ep.joinInfo != nil {
1287+
ep.joinInfo.gw6 = nil
1288+
}
1289+
1290+
d, err := n.driver(true)
1291+
if err != nil {
1292+
return fmt.Errorf("fetching driver to release IPv6 address: %v", err)
1293+
}
1294+
if dr, ok := d.(driverapi.IPv6Releaser); ok {
1295+
if err := dr.ReleaseIPv6(ctx, n.id, ep.id); err != nil {
1296+
return fmt.Errorf("releasing IPv6 address: %v", err)
1297+
}
1298+
}
1299+
1300+
if err := ep.network.getController().updateToStore(ctx, ep); err != nil {
1301+
return err
1302+
}
1303+
1304+
return nil
1305+
}
1306+
12911307
func (c *Controller) cleanupLocalEndpoints() error {
12921308
// Get used endpoints
12931309
eps := make(map[string]any)
Collapse file

‎daemon/libnetwork/network.go‎

Copy file name to clipboardExpand all lines: daemon/libnetwork/network.go
+1-10Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,7 +1240,7 @@ func (n *Network) createEndpoint(ctx context.Context, name string, options ...En
12401240
}
12411241
defer func() {
12421242
if err != nil {
1243-
ep.releaseAddress()
1243+
ep.releaseIPAddresses()
12441244
}
12451245
}()
12461246

@@ -1268,15 +1268,6 @@ func (n *Network) createEndpoint(ctx context.Context, name string, options ...En
12681268
}
12691269
}()
12701270

1271-
if !n.getController().isSwarmNode() || n.Scope() != scope.Swarm || !n.driverIsMultihost() {
1272-
n.updateSvcRecord(context.WithoutCancel(ctx), ep, true)
1273-
defer func() {
1274-
if err != nil {
1275-
n.updateSvcRecord(context.WithoutCancel(ctx), ep, false)
1276-
}
1277-
}()
1278-
}
1279-
12801271
return ep, nil
12811272
}
12821273

Collapse file

‎daemon/libnetwork/network_unix.go‎

Copy file name to clipboardExpand all lines: daemon/libnetwork/network_unix.go
-11Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
package libnetwork
44

55
import (
6-
"context"
76
"fmt"
87
"strconv"
98
"time"
@@ -21,16 +20,6 @@ type platformNetwork struct{} //nolint:nolintlint,unused // only populated on wi
2120
func (n *Network) startResolver() {
2221
}
2322

24-
func addEpToResolver(
25-
ctx context.Context,
26-
netName, epName string,
27-
config *containerConfig,
28-
epIface *EndpointInterface,
29-
resolvers []*Resolver,
30-
) error {
31-
return nil
32-
}
33-
3423
func deleteEpFromResolver(epName string, epIface *EndpointInterface, resolvers []*Resolver) error {
3524
return nil
3625
}
Collapse file

‎daemon/libnetwork/osl/interface_linux.go‎

Copy file name to clipboardExpand all lines: daemon/libnetwork/osl/interface_linux.go
+20Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,9 @@ func moveLink(ctx context.Context, nlhHost nlwrap.Handle, iface netlink.Link, i
228228
// an auto-generated dest name that combines the provided dstPrefix and a
229229
// numeric suffix.
230230
//
231+
// If an IPv6 address is configured, but unused because of sysctl settings applied
232+
// after address assignment, it will be removed from the Interface.
233+
//
231234
// It's safe to call concurrently.
232235
func (n *Namespace) AddInterface(ctx context.Context, srcName, dstPrefix, dstName string, options ...IfaceOption) error {
233236
ctx, span := otel.Tracer("").Start(ctx, "libnetwork.osl.AddInterface", trace.WithAttributes(
@@ -874,6 +877,23 @@ func (n *Namespace) configureInterface(ctx context.Context, nlh nlwrap.Handle, i
874877
return err
875878
}
876879

880+
// If an IPv6 address was configured, and now it's gone away, it's because of a sysctl
881+
// setting. Remove the address from the Interface so that there's no attempt to send
882+
// Neighbour Advertisements for it, and the caller knows to release the address.
883+
if i.addressIPv6 != nil {
884+
v6addrs, err := nlh.AddrList(iface, netlink.FAMILY_V6)
885+
if err != nil {
886+
return fmt.Errorf("failed to check IPv6 addresses: %v", err)
887+
}
888+
if len(v6addrs) == 0 {
889+
log.G(ctx).WithFields(log.Fields{
890+
"ip": i.addressIPv6.String(),
891+
"ifname": i.dstName,
892+
}).Debug("IPv6 address not present after applying sysctls")
893+
i.addressIPv6 = nil
894+
}
895+
}
896+
877897
return nil
878898
}
879899

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.