Allow to program Endpoint link-local addresses
Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
parent
f741ccf444
commit
da61c5d37f
7 changed files with 87 additions and 2 deletions
|
@ -832,11 +832,25 @@ func EndpointOptionGeneric(generic map[string]interface{}) EndpointOption {
|
|||
}
|
||||
}
|
||||
|
||||
var (
|
||||
linkLocalMask = net.CIDRMask(16, 32)
|
||||
linkLocalMaskIPv6 = net.CIDRMask(64, 128)
|
||||
)
|
||||
|
||||
// CreateOptionIpam function returns an option setter for the ipam configuration for this endpoint
|
||||
func CreateOptionIpam(ipV4, ipV6 net.IP, ipamOptions map[string]string) EndpointOption {
|
||||
func CreateOptionIpam(ipV4, ipV6 net.IP, llIPs []net.IP, ipamOptions map[string]string) EndpointOption {
|
||||
return func(ep *endpoint) {
|
||||
ep.prefAddress = ipV4
|
||||
ep.prefAddressV6 = ipV6
|
||||
if len(llIPs) != 0 {
|
||||
for _, ip := range llIPs {
|
||||
nw := &net.IPNet{IP: ip, Mask: linkLocalMask}
|
||||
if ip.To4() == nil {
|
||||
nw.Mask = linkLocalMaskIPv6
|
||||
}
|
||||
ep.iface.llAddrs = append(ep.iface.llAddrs, nw)
|
||||
}
|
||||
}
|
||||
ep.ipamOptions = ipamOptions
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,12 +43,16 @@ type InterfaceInfo interface {
|
|||
|
||||
// AddressIPv6 returns the IPv6 address assigned to the endpoint.
|
||||
AddressIPv6() *net.IPNet
|
||||
|
||||
// LinkLocalAddresses returns the list of link-local (IPv4/IPv6) addresses assigned to the endpoint.
|
||||
LinkLocalAddresses() []*net.IPNet
|
||||
}
|
||||
|
||||
type endpointInterface struct {
|
||||
mac net.HardwareAddr
|
||||
addr *net.IPNet
|
||||
addrv6 *net.IPNet
|
||||
llAddrs []*net.IPNet
|
||||
srcName string
|
||||
dstPrefix string
|
||||
routes []*net.IPNet
|
||||
|
@ -67,6 +71,13 @@ func (epi *endpointInterface) MarshalJSON() ([]byte, error) {
|
|||
if epi.addrv6 != nil {
|
||||
epMap["addrv6"] = epi.addrv6.String()
|
||||
}
|
||||
if len(epi.llAddrs) != 0 {
|
||||
list := make([]string, 0, len(epi.llAddrs))
|
||||
for _, ll := range epi.llAddrs {
|
||||
list = append(list, ll.String())
|
||||
}
|
||||
epMap["llAddrs"] = list
|
||||
}
|
||||
epMap["srcName"] = epi.srcName
|
||||
epMap["dstPrefix"] = epi.dstPrefix
|
||||
var routes []string
|
||||
|
@ -102,7 +113,17 @@ func (epi *endpointInterface) UnmarshalJSON(b []byte) error {
|
|||
return types.InternalErrorf("failed to decode endpoint interface ipv6 address after json unmarshal: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := epMap["llAddrs"]; ok {
|
||||
list := v.([]string)
|
||||
epi.llAddrs = make([]*net.IPNet, 0, len(list))
|
||||
for _, llS := range list {
|
||||
ll, err := types.ParseCIDR(llS)
|
||||
if err != nil {
|
||||
return types.InternalErrorf("failed to decode endpoint interface link-local address (%s) after json unmarshal: %v", llS, err)
|
||||
}
|
||||
epi.llAddrs = append(epi.llAddrs, ll)
|
||||
}
|
||||
}
|
||||
epi.srcName = epMap["srcName"].(string)
|
||||
epi.dstPrefix = epMap["dstPrefix"].(string)
|
||||
|
||||
|
@ -131,6 +152,12 @@ func (epi *endpointInterface) CopyTo(dstEpi *endpointInterface) error {
|
|||
dstEpi.dstPrefix = epi.dstPrefix
|
||||
dstEpi.v4PoolID = epi.v4PoolID
|
||||
dstEpi.v6PoolID = epi.v6PoolID
|
||||
if len(epi.llAddrs) != 0 {
|
||||
dstEpi.llAddrs = make([]*net.IPNet, 0, len(epi.llAddrs))
|
||||
for _, ll := range epi.llAddrs {
|
||||
dstEpi.llAddrs = append(dstEpi.llAddrs, ll)
|
||||
}
|
||||
}
|
||||
|
||||
for _, route := range epi.routes {
|
||||
dstEpi.routes = append(dstEpi.routes, types.GetIPNetCopy(route))
|
||||
|
@ -266,6 +293,10 @@ func (epi *endpointInterface) AddressIPv6() *net.IPNet {
|
|||
return types.GetIPNetCopy(epi.addrv6)
|
||||
}
|
||||
|
||||
func (epi *endpointInterface) LinkLocalAddresses() []*net.IPNet {
|
||||
return epi.llAddrs
|
||||
}
|
||||
|
||||
func (epi *endpointInterface) SetNames(srcName string, dstPrefix string) error {
|
||||
epi.srcName = srcName
|
||||
epi.dstPrefix = dstPrefix
|
||||
|
|
|
@ -801,6 +801,12 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
|
|||
|
||||
ep.processOptions(options...)
|
||||
|
||||
for _, llIPNet := range ep.Iface().LinkLocalAddresses() {
|
||||
if !llIPNet.IP.IsLinkLocalUnicast() {
|
||||
return nil, types.BadRequestErrorf("invalid link local IP address: %v", llIPNet.IP)
|
||||
}
|
||||
}
|
||||
|
||||
if opt, ok := ep.generic[netlabel.MacAddress]; ok {
|
||||
if mac, ok := opt.(net.HardwareAddr); ok {
|
||||
ep.iface.mac = mac
|
||||
|
|
|
@ -24,6 +24,7 @@ type nwIface struct {
|
|||
mac net.HardwareAddr
|
||||
address *net.IPNet
|
||||
addressIPv6 *net.IPNet
|
||||
llAddrs []*net.IPNet
|
||||
routes []*net.IPNet
|
||||
bridge bool
|
||||
ns *networkNamespace
|
||||
|
@ -86,6 +87,13 @@ func (i *nwIface) AddressIPv6() *net.IPNet {
|
|||
return types.GetIPNetCopy(i.addressIPv6)
|
||||
}
|
||||
|
||||
func (i *nwIface) LinkLocalAddresses() []*net.IPNet {
|
||||
i.Lock()
|
||||
defer i.Unlock()
|
||||
|
||||
return i.llAddrs
|
||||
}
|
||||
|
||||
func (i *nwIface) Routes() []*net.IPNet {
|
||||
i.Lock()
|
||||
defer i.Unlock()
|
||||
|
@ -316,6 +324,7 @@ func configureInterface(iface netlink.Link, i *nwIface) error {
|
|||
{setInterfaceIP, fmt.Sprintf("error setting interface %q IP to %v", ifaceName, i.Address())},
|
||||
{setInterfaceIPv6, fmt.Sprintf("error setting interface %q IPv6 to %v", ifaceName, i.AddressIPv6())},
|
||||
{setInterfaceMaster, fmt.Sprintf("error setting interface %q master to %q", ifaceName, i.DstMaster())},
|
||||
{setInterfaceLinkLocalIPs, fmt.Sprintf("error setting interface %q link local IPs to %v", ifaceName, i.LinkLocalAddresses())},
|
||||
}
|
||||
|
||||
for _, config := range ifaceConfigurators {
|
||||
|
@ -359,6 +368,16 @@ func setInterfaceIPv6(iface netlink.Link, i *nwIface) error {
|
|||
return netlink.AddrAdd(iface, ipAddr)
|
||||
}
|
||||
|
||||
func setInterfaceLinkLocalIPs(iface netlink.Link, i *nwIface) error {
|
||||
for _, llIP := range i.LinkLocalAddresses() {
|
||||
ipAddr := &netlink.Addr{IPNet: llIP}
|
||||
if err := netlink.AddrAdd(iface, ipAddr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setInterfaceName(iface netlink.Link, i *nwIface) error {
|
||||
return netlink.LinkSetName(iface, i.DstName())
|
||||
}
|
||||
|
|
|
@ -60,6 +60,12 @@ func (n *networkNamespace) AddressIPv6(addr *net.IPNet) IfaceOption {
|
|||
}
|
||||
}
|
||||
|
||||
func (n *networkNamespace) LinkLocalAddresses(list []*net.IPNet) IfaceOption {
|
||||
return func(i *nwIface) {
|
||||
i.llAddrs = list
|
||||
}
|
||||
}
|
||||
|
||||
func (n *networkNamespace) Routes(routes []*net.IPNet) IfaceOption {
|
||||
return func(i *nwIface) {
|
||||
i.routes = routes
|
||||
|
|
|
@ -85,6 +85,9 @@ type IfaceOptionSetter interface {
|
|||
// Address returns an option setter to set IPv6 address.
|
||||
AddressIPv6(*net.IPNet) IfaceOption
|
||||
|
||||
// LinkLocalAddresses returns an option setter to set the link-local IP addresses.
|
||||
LinkLocalAddresses([]*net.IPNet) IfaceOption
|
||||
|
||||
// Master returns an option setter to set the master interface if any for this
|
||||
// interface. The master interface name should refer to the srcname of a
|
||||
// previously added interface of type bridge.
|
||||
|
@ -138,6 +141,9 @@ type Interface interface {
|
|||
// IPv6 address for the interface.
|
||||
AddressIPv6() *net.IPNet
|
||||
|
||||
// LinkLocalAddresses returns the link-local IP addresses assigned to the interface.
|
||||
LinkLocalAddresses() []*net.IPNet
|
||||
|
||||
// IP routes for the interface.
|
||||
Routes() []*net.IPNet
|
||||
|
||||
|
|
|
@ -721,6 +721,9 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
|
|||
if i.addrv6 != nil && i.addrv6.IP.To16() != nil {
|
||||
ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().AddressIPv6(i.addrv6))
|
||||
}
|
||||
if len(i.llAddrs) != 0 {
|
||||
ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().LinkLocalAddresses(i.llAddrs))
|
||||
}
|
||||
if i.mac != nil {
|
||||
ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().MacAddress(i.mac))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue