Allow to program Endpoint link-local addresses

Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
Alessandro Boch 2016-05-24 20:04:49 -07:00
parent f741ccf444
commit da61c5d37f
7 changed files with 87 additions and 2 deletions

View file

@ -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
}
}

View file

@ -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

View file

@ -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

View file

@ -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())
}

View file

@ -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

View file

@ -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

View file

@ -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))
}