-
Notifications
You must be signed in to change notification settings - Fork 881
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support NDP proxying on bridge networks #1316
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -58,6 +58,7 @@ type networkConfiguration struct { | |
BridgeName string | ||
EnableIPv6 bool | ||
EnableIPMasquerade bool | ||
NDPProxyInterface string | ||
EnableICC bool | ||
Mtu int | ||
DefaultBindingIP net.IP | ||
|
@@ -215,6 +216,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()) | ||
|
@@ -680,6 +683,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 { | ||
|
@@ -699,6 +703,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}, | ||
|
||
|
@@ -1019,6 +1026,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 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) | ||
} | ||
|
@@ -1077,6 +1105,24 @@ 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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with the best effort approach. But it would be useful to log a warning in case the link is not found (specifying this happened during neigh proxy entry removal) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 Does this makes sense ?
|
||
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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here too, can you please log a warning message. Thanks |
||
} | ||
} | ||
|
||
// 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 { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,9 @@ 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" | ||
ndpProxyConfAll = "/proc/sys/net/ipv6/conf/all/proxy_ndp" | ||
) | ||
|
||
func init() { | ||
|
@@ -117,3 +120,31 @@ func setupIPv6Forwarding(config *networkConfiguration, i *bridgeInterface) error | |
|
||
return nil | ||
} | ||
|
||
func setupNDPProxying(config *networkConfiguration, i *bridgeInterface) error { | ||
// Get current NDP default proxying setup | ||
ndpProxyDataDefault, err := ioutil.ReadFile(ndpProxyConfDefault) | ||
if err != nil { | ||
return fmt.Errorf("Cannot read NDP default proxying setup: %v", err) | ||
} | ||
// Enable NDP default proxying only if it is not already enabled | ||
if ndpProxyDataDefault[0] != '1' { | ||
if err := ioutil.WriteFile(ndpProxyConfDefault, []byte{'1', '\n'}, ndpProxyConfPerm); err != nil { | ||
logrus.Warnf("Unable to enable NDP default proxying: %v", err) | ||
} | ||
} | ||
|
||
// Get current NDP all proxying setup | ||
ndpProxyDataAll, err := ioutil.ReadFile(ndpProxyConfAll) | ||
if err != nil { | ||
return fmt.Errorf("Cannot read NDP all proxying setup: %v", err) | ||
} | ||
// Enable NDP all proxying only if it is not already enabled | ||
if ndpProxyDataAll[0] != '1' { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it needed to enbale the proxying on all interfaces ? Would it work if we only enable it on the interface specified by the network driver option There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I understood correctly, neighbours are announced/answered on the configured interface. Request made on other interfaces won't work. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks @mostolog for taking over this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [We posted at the same time] I think the host interface passed via driver options is the one that will advertise outside of the host that it provides reachability to the IPv6 segment assigned to the docker bridge network. Therefore I'd expect external IPv6 requests to the containers coming into the host via that same interface. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIUC, it's looping through networks in https://github.com/mostolog/libnetwork/blob/patch-1/drivers/bridge/bridge.go#L594 and setting ndp in https://github.com/mostolog/libnetwork/blob/patch-1/drivers/bridge/bridge.go#L686, right? Would an if (network == com.docker.network.bridge.ndp_proxy_interface) to set enableNDPProxying work? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, the first loop you pointed out is only to detect if the to-be-created network's configuration conflicts with any existing network. And it ends at https://github.com/mostolog/libnetwork/blob/patch-1/drivers/bridge/bridge.go#L615 Then, the second line you linked
it's where the driver detects whether it does or does not need to program the ndp proxying for this network. This is just fine and does not need any changes. The only one I was asking for is to see if it is enough for The setup function has access to the ndp interface name because it is passed the network configuration: So I was asking that instead of etting
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Committed on my patch-1 branch, however I'm not sure if it's ok. Please review and let me know if ready for PR |
||
if err := ioutil.WriteFile(ndpProxyConfAll, []byte{'1', '\n'}, ndpProxyConfPerm); err != nil { | ||
logrus.Warnf("Unable to enable NDP all proxying: %v", err) | ||
} | ||
} | ||
|
||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please format and return a more expressive error, otherwise caller will receive a simple
link not found
, which does not help much.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not familiar with go;
Is this what you need:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simply
return fmt.Errorf("could not find link for ndp proxy interface %q: %v", config.NDPProxyInterface, err)