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

Code before:
		}
	}

	// Up the host interface after finishing all netlink configuration
	if err = d.linkUp(ctx, host); err != nil {
		return fmt.Errorf("could not set link up for host interface %s: %v", hostIfName, err)
	}

	// Generate a MAC-address-based IPv6 address, which may be used by the default
	// bridge network instead of an IPAM allocated address.
	if endpoint.addrv6 == nil && config.EnableIPv6 {
		var ip6 net.IP
		network := n.bridge.bridgeIPv6
		if config.AddressIPv6 != nil {
			network = config.AddressIPv6
		}
		// If there are fewer than 48 host-bits in the network, it's not possible to
		// generate an IPv6 address from the MAC address. The network size has already
		// been checked, so we can safely assume this endpoint must not need a MAC-based
		// IPv6 address.
		ones, _ := network.Mask.Size()
		if ones <= 80 {
			ip6 = make(net.IP, len(network.IP))
			copy(ip6, network.IP)
			for i, h := range endpoint.macAddress {
				ip6[i+10] = h
			}

			endpoint.addrv6 = &net.IPNet{IP: ip6, Mask: network.Mask}
			if err = ifInfo.SetIPAddress(endpoint.addrv6); err != nil {
				return err
			}
		}
	}

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

	return nil
}

// createVeth creates a veth device with one end in the container's network namespace,
// if it can get hold of the netns path and open the handles. In that case, it returns
// a netlink handle in the container's namespace that must be closed by the caller.
//
// If the netns path isn't available, possibly because the netns hasn't been created
// yet, or it's not possible to get a netns or netlink handle in the container's
// namespace - both ends of the veth device are created in nlh's netns, and no netlink
// handle is returned.
//

Review comment (refactor):
Also for a follow-up; wondering if extracting this to a separate function could make the logic easier (being  able to do an early return from  that function)

Code after:
	}

	return nil
}

// createVeth creates a veth device with one end in the container's network namespace,
// if it can get hold of the netns path and open the handles. In that case, it returns
// a netlink handle in the container's namespace that must be closed by the caller.
//
// If the netns path isn't available, possibly because the netns hasn't been created
// yet, or it's not possible to get a netns or netlink handle in the container's
// namespace - both ends of the veth device are created in nlh's netns, and no netlink
// handle is returned.
//
// (Only the error from creating the interface is returned. Failure to create the
// interface in the container's netns is not an error.)
func createVeth(ctx context.Context, hostIfName, containerIfName string, ifInfo driverapi.InterfaceInfo, nlh nlwrap.Handle) (nlhCtr *nlwrap.Handle, retErr error) {
	veth := &netlink.Veth{
		LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0},
		PeerName:  containerIfName,
	}

	if nspath := ifInfo.NetnsPath(); nspath == "" {
		log.G(ctx).WithField("ifname", containerIfName).Debug("No container netns path, creating interface in host netns")
	} else if netnsh, err := netns.GetFromPath(nspath); err != nil {
		log.G(ctx).WithFields(log.Fields{
			"error":  err,
			"netns":  nspath,
			"ifname": containerIfName,
		}).Warn("No container netns, creating interface in host netns")
	} else {
		defer netnsh.Close()

		if nh, err := nlwrap.NewHandleAt(netnsh, syscall.NETLINK_ROUTE); err != nil {
			log.G(ctx).WithFields(log.Fields{
				"error": err,
				"netns": nspath,
			}).Warn("No netlink handle for container, creating interface in host netns")
		} else {
			defer func() {
				if retErr != nil {
					nh.Close()
				}
			}()

			veth.PeerNamespace = netlink.NsFd(netnsh)
			nlhCtr = &nh
			ifInfo.SetCreatedInContainer(true)
		}
	}