Repository: moby/moby
File: daemon/libnetwork/drivers/bridge/bridge_linux.go (Go)

Code before:

	if err = d.storeUpdate(ctx, endpoint); err != nil {
		return fmt.Errorf("failed to update bridge endpoint %.7s to store: %v", endpoint.id, err)
	}

	return nil
}

// trimPortBindings compares pbmReq with the current port bindings, and removes
// port bindings that are no longer required.
//
// ep.portMapping is updated when bindings are removed.
func (ep *bridgeEndpoint) trimPortBindings(ctx context.Context, n *bridgeNetwork, pbmReq portBindingMode) (func() []portmapperapi.PortBinding, error) {
	// If the network is IPv4-only, this endpoint is the container's IPv6 gateway,
	// and IPv4 addresses are published to the host - when it's acting as the IPv6
	// gateway, bindings may be set up to proxy from host IPv6 to endpoint IPv4.
	proxy6To4 := ep.addr != nil && ep.addrv6 == nil && !n.gwMode(firewaller.IPv4).routed()

	// Drop IPv4 bindings if this endpoint is not the IPv4 gateway, unless the
	// network is "routed" (routed bindings get dropped unconditionally by Leave).
	drop4 := !pbmReq.ipv4 && !n.gwMode(firewaller.IPv4).routed()

	// Drop IPv6 bindings if this endpoint is not the IPv6 gateway, unless the IPv6
	// network is "routed" (routed bindings get dropped unconditionally by Leave),
	// or there may be mappings proxying between host IPv6 and container IPv4.
	drop6 := !pbmReq.ipv6 && (!n.gwMode(firewaller.IPv6).routed() || proxy6To4)

	if !drop4 && !drop6 {
		return nil, nil
	}

	toDrop := make([]portmapperapi.PortBinding, 0, len(ep.portMapping))
	toKeep := slices.DeleteFunc(ep.portMapping, func(pb portmapperapi.PortBinding) bool {
		is4 := pb.HostIP.To4() != nil
		if (is4 && drop4) || (!is4 && drop6) {
			toDrop = append(toDrop, pb)
			return true
		}
		return false
	})
	if len(toDrop) == 0 {
		return nil, nil
	}

	if err := n.unmapPBs(ctx, toDrop); err != nil {
		log.G(ctx).WithFields(log.Fields{
			"error": err,
			"gw4":   pbmReq.ipv4,
			"gw6":   pbmReq.ipv6,
			"nid":   stringid.TruncateID(n.id),
			"eid":   stringid.TruncateID(ep.id),

Review comment (suggestion):
Based on our Slack discussion, I think you don't need to check `proxy6To4` in `drop6`, because `pbmReq.ipv6` is set to true when the current endpoint is the IPv6 gateway, or when the container has no IPv6 gateway at all and the current endpoint is the IPv4 gateway.

https://github.com/moby/moby/blob/e1281f09fceec4aab518267c319a7bd4c79cf3c5/daemon/libnetwork/drivers/bridge/bridge_linux.go#L1537-L1542

So, you can probably replace `drop6` with:

```
drop6 := !pbmReq.ipv6 && !n.gwMode(firewaller.IPv6).routed()
```

Also, I think it's quite confusing to say `Drop IPv6 bindings if this endpoint is not the IPv6 gateway` while `pbmReq.ipv6` is set true when there's no IPv6 gateway.

Code after:

	if err = d.storeUpdate(ctx, endpoint); err != nil {
		return fmt.Errorf("failed to update bridge endpoint %.7s to store: %v", endpoint.id, err)
	}

	return nil
}

// trimPortBindings compares pbmReq with the current port bindings, and removes
// port bindings that are no longer required.
//
// ep.portMapping is updated when bindings are removed.
func (ep *bridgeEndpoint) trimPortBindings(ctx context.Context, n *bridgeNetwork, pbmReq portBindingMode) (func() []portmapperapi.PortBinding, error) {
	// Drop IPv4 bindings if this endpoint is not the IPv4 gateway, unless the
	// network is "routed" (routed bindings get dropped unconditionally by Leave).
	drop4 := !pbmReq.ipv4 && !n.gwMode(firewaller.IPv4).routed()

	// Drop IPv6 bindings if this endpoint is not the IPv6 gateway, and not proxying
	// from host IPv6 to container IPv6 because there is no IPv6 gateway - unless the
	// IPv6 network is "routed" (routed bindings get dropped unconditionally by Leave).
	drop6 := !pbmReq.ipv6 && !n.gwMode(firewaller.IPv6).routed()

	if !drop4 && !drop6 {
		return nil, nil
	}

	toDrop := make([]portmapperapi.PortBinding, 0, len(ep.portMapping))
	toKeep := slices.DeleteFunc(ep.portMapping, func(pb portmapperapi.PortBinding) bool {
		is4 := pb.HostIP.To4() != nil
		if (is4 && drop4) || (!is4 && drop6) {
			toDrop = append(toDrop, pb)
			return true
		}
		return false
	})
	if len(toDrop) == 0 {
		return nil, nil
	}

	if err := n.unmapPBs(ctx, toDrop); err != nil {
		log.G(ctx).WithFields(log.Fields{
			"error": err,
			"gw4":   pbmReq.ipv4,
			"gw6":   pbmReq.ipv6,
			"nid":   stringid.TruncateID(n.id),
			"eid":   stringid.TruncateID(ep.id),
		}).Error("Failed to release port bindings")
		return nil, err
	}
	ep.portMapping = toKeep