Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions drivers/bridge/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ type networkConfiguration struct {
DefaultBindingIP net.IP
DefaultBridge bool
ContainerIfacePrefix string
NDPProxyInterface string
// Internal fields set after ipam data parsing
AddressIPv4 *net.IPNet
AddressIPv6 *net.IPNet
Expand Down Expand Up @@ -228,6 +229,8 @@ func (c *networkConfiguration) fromLabels(labels map[string]string) error {
if c.EnableIPMasquerade, err = strconv.ParseBool(value); err != nil {
return parseErr(label, value, err.Error())
}
case NDPProxyInterface:
c.NDPProxyInterface = value
case EnableICC:
if c.EnableICC, err = strconv.ParseBool(value); err != nil {
return parseErr(label, value, err.Error())
Expand Down Expand Up @@ -714,6 +717,7 @@ func (d *driver) createNetwork(config *networkConfiguration) error {
bridgeSetup.queueStep(setupBridgeIPv4)

enableIPv6Forwarding := d.config.EnableIPForwarding && config.AddressIPv6 != nil
enableNDPProxying := config.NDPProxyInterface != "" && config.AddressIPv6 != nil

// Conditionally queue setup steps depending on configuration values.
for _, step := range []struct {
Expand All @@ -733,6 +737,9 @@ func (d *driver) createNetwork(config *networkConfiguration) error {
// Enable IPv6 Forwarding
{enableIPv6Forwarding, setupIPv6Forwarding},

// Enable NDP Proxying
{enableNDPProxying, setupNDPProxying},

// Setup Loopback Adresses Routing
{!d.config.EnableUserlandProxy, setupLoopbackAdressesRouting},

Expand Down Expand Up @@ -1073,6 +1080,27 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
}
}

// Add a neighbor proxy if using NDP proxying
if config.NDPProxyInterface != "" && config.EnableIPv6 {
link, err := d.nlh.LinkByName(config.NDPProxyInterface)
if err != nil {
return fmt.Errorf("could not find link for ndp proxy interface %q: %v", config.NDPProxyInterface, err)
}
neighbor := netlink.Neigh{
LinkIndex: link.Attrs().Index,
Family: netlink.FAMILY_V6,
State: netlink.NUD_PERMANENT,
Type: netlink.NDA_UNSPEC,
Flags: netlink.NTF_PROXY,
IP: endpoint.addrv6.IP,
HardwareAddr: endpoint.macAddress,
}
if err := d.nlh.NeighAdd(&neighbor); err != nil {
logrus.Warnf("could not add the neighbor proxy: %v", err)
return err
}
}

if err = d.storeUpdate(endpoint); err != nil {
return fmt.Errorf("failed to save bridge endpoint %s to store: %v", endpoint.id[0:7], err)
}
Expand Down Expand Up @@ -1131,6 +1159,27 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
}
}()

// Try removal of neighbor proxy. Discard error: it is a best effort.
// Also make sure defer does not see this error either.
if n.config.NDPProxyInterface != "" && n.config.EnableIPv6 {
link, err := d.nlh.LinkByName(n.config.NDPProxyInterface)
if err != nil {
logrus.Warnf("could not remove ndp neighbour, because could not find link for ndp proxy interface %q: %v",
n.config.NDPProxyInterface, err)
} else {
neighbor := netlink.Neigh{
LinkIndex: link.Attrs().Index,
Family: netlink.FAMILY_V6,
State: netlink.NUD_PERMANENT,
Type: netlink.NDA_UNSPEC,
Flags: netlink.NTF_PROXY,
IP: ep.addrv6.IP,
HardwareAddr: ep.macAddress,
}
d.nlh.NeighDel(&neighbor)
}
}

// Try removal of link. Discard error: it is a best effort.
// Also make sure defer does not see this error either.
if link, err := d.nlh.LinkByName(ep.srcName); err == nil {
Expand Down
4 changes: 4 additions & 0 deletions drivers/bridge/bridge_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ func (ncfg *networkConfiguration) MarshalJSON() ([]byte, error) {
nMap["BridgeName"] = ncfg.BridgeName
nMap["EnableIPv6"] = ncfg.EnableIPv6
nMap["EnableIPMasquerade"] = ncfg.EnableIPMasquerade
nMap["NDPProxyInterface"] = ncfg.NDPProxyInterface
nMap["EnableICC"] = ncfg.EnableICC
nMap["Mtu"] = ncfg.Mtu
nMap["Internal"] = ncfg.Internal
Expand Down Expand Up @@ -191,6 +192,9 @@ func (ncfg *networkConfiguration) UnmarshalJSON(b []byte) error {
ncfg.BridgeName = nMap["BridgeName"].(string)
ncfg.EnableIPv6 = nMap["EnableIPv6"].(bool)
ncfg.EnableIPMasquerade = nMap["EnableIPMasquerade"].(bool)
if v, ok := nMap["NDPProxyInterface"]; ok {
ncfg.NDPProxyInterface = v.(string)
}
ncfg.EnableICC = nMap["EnableICC"].(bool)
ncfg.Mtu = int(nMap["Mtu"].(float64))
if v, ok := nMap["Internal"]; ok {
Expand Down
22 changes: 22 additions & 0 deletions drivers/bridge/bridge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,13 +270,15 @@ func TestCreateFullOptionsLabels(t *testing.T) {
gwV6s := "2001:db8:2600:2700:2800::25/80"
nwV6, _ := types.ParseCIDR(nwV6s)
gwV6, _ := types.ParseCIDR(gwV6s)
ndpPxyIface := "lo"

labels := map[string]string{
BridgeName: DefaultBridgeName,
DefaultBridge: "true",
EnableICC: "true",
EnableIPMasquerade: "true",
DefaultBindingIP: bndIPs,
NDPProxyInterface: ndpPxyIface,
}

netOption := make(map[string]interface{})
Expand Down Expand Up @@ -319,6 +321,10 @@ func TestCreateFullOptionsLabels(t *testing.T) {
t.Fatal("incongruent EnableIPMasquerade in bridge network")
}

if nw.config.NDPProxyInterface != ndpPxyIface {
t.Fatalf("incongruend NDPProxyInterface in bridge network")
}

bndIP := net.ParseIP(bndIPs)
if !bndIP.Equal(nw.config.DefaultBindingIP) {
t.Fatalf("Unexpected: %v", nw.config.DefaultBindingIP)
Expand Down Expand Up @@ -348,6 +354,22 @@ func TestCreateFullOptionsLabels(t *testing.T) {
if te.Interface().AddressIPv6().IP.String() != "2001:db8:2600:2700:2800:aabb:ccdd:eeff" {
t.Fatalf("Unexpected endpoint IPv6 address: %v", te.Interface().AddressIPv6().IP)
}

// Check that the neighbor proxy was created by trying to delete it,
// because netlink.NeighList currently can't list proxies.
link, _ := d.nlh.LinkByName(ndpPxyIface)
err = d.nlh.NeighDel(&netlink.Neigh{
LinkIndex: link.Attrs().Index,
Family: netlink.FAMILY_V6,
State: netlink.NUD_PERMANENT,
Type: netlink.NDA_UNSPEC,
Flags: netlink.NTF_PROXY,
IP: te.Interface().AddressIPv6().IP,
HardwareAddr: te.Interface().MacAddress(),
})
if err != nil {
t.Fatalf("Cannot delete neighbor proxy, suggesting it wasn't created: %v", err)
}
}

func TestCreate(t *testing.T) {
Expand Down
3 changes: 3 additions & 0 deletions drivers/bridge/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ const (
// EnableIPMasquerade label for bridge driver
EnableIPMasquerade = "com.docker.network.bridge.enable_ip_masquerade"

// NDPProxyInterface label for bridge driver
NDPProxyInterface = "com.docker.network.bridge.ndp_proxy_interface"

// EnableICC label
EnableICC = "com.docker.network.bridge.enable_icc"

Expand Down
17 changes: 17 additions & 0 deletions drivers/bridge/setup_ipv6.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const (
ipv6ForwardConfPerm = 0644
ipv6ForwardConfDefault = "/proc/sys/net/ipv6/conf/default/forwarding"
ipv6ForwardConfAll = "/proc/sys/net/ipv6/conf/all/forwarding"
ndpProxyConfPerm = 0644
ndpProxyConfDefault = "/proc/sys/net/ipv6/conf/default/proxy_ndp"
)

func init() {
Expand Down Expand Up @@ -117,3 +119,18 @@ func setupIPv6Forwarding(config *networkConfiguration, i *bridgeInterface) error

return nil
}

func setupNDPProxying(config *networkConfiguration, i *bridgeInterface) error {
ndpProxyConfPath := fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/proxy_ndp", config.NDPProxyInterface)
ndpProxyDataIface, err := ioutil.ReadFile(ndpProxyConfPath)
if err != nil {
return fmt.Errorf("Cannot read NDP proxying for interface %s: %v", config.NDPProxyInterface, err)
}
// Enable NDP proxying only if it is not already enabled
if ndpProxyDataIface[0] != '1' {
if err := ioutil.WriteFile(ndpProxyConfPath, []byte{'1', '\n'}, ndpProxyConfPerm); err != nil {
logrus.Warnf("Unable to enable NDP proxying for interface %s: %v", config.NDPProxyInterface, err)
}
}
return nil
}