Skip to content
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

bridge: Add support for IPv6 to bridge plugin #10

Merged
merged 1 commit into from
Jun 28, 2017

Conversation

leblancd
Copy link

@leblancd leblancd commented May 25, 2017

This change adds support for IPv6 container/pod addresses to the CNI
bridge plugin, both for dual-stack (IPv4 + IPv6) and for IPv6-only
network configurations.

The proposed changes support multiple IPv6 addresses on a container
interface. If isGW is configured, the bridge will also be configured with
gateway addresses for each IPv6 subnet.

Please note that both the dual-stack functionality and support for multiple
IPv6 container/gateway addresses depends upon containernetworking/cni
PR #451 "ipam/host-local: support multiple IP ranges".
The bridge plugin changes being proposed here could potentially be committed
independently from this host-local plugin change; however the dual-stack and
multiple IPv6 address functionality that is enabled by this change can't be
exercised/tested until the host-local plugin change is committed.

There are some dual-stack/multiple-IPv6 unit test cases that are
currently commented out in the proposed changes because these
test cases will fail without the prior commits of the multiple IP
range host-local change.

This pull request includes a temporary workaround for Kubernetes
Issue #32291 (Container IPv6 address is marked as duplicate (dadfailed).
The problem is that kubelet enables hairpin mode on bridge veth
interfaces. Hairpin mode causes the container/pod to see echos of its
IPv6 neighbor solicitation packets, so that it declares duplicate address
detection (DAD) failure. The long-term fix is to use enhanced-DAD
when that feature is readily available in kernels. The short-term fix is
to disable IPv6 DAD in the container. Unfortunately, this has to be done
unconditionally (i.e. without a check for whether hairpin mode is enabled)
because hairpin mode is turned on by kubelet after the CNI bridge plugin
has completed cmdAdd processing. Disabling DAD should be okay if
IPv6 addresses are guaranteed to be unique (which is the case for
host-local IPAM plugin).

@@ -392,7 +454,7 @@ func cmdDel(args *skel.CmdArgs) error {
var ipn *net.IPNet
err = ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error {
var err error
ipn, err = ip.DelLinkByNameAddr(args.IfName, netlink.FAMILY_V4)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow :-)

// Add a default route for this family using the current
// gateway address if necessary.
if n.IsDefaultGW && !gws.defaultRouteFound {
defaultNet.Mask = net.IPMask(defaultNet.IP)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason you wouldn't do this above, where defaultNet.IP gets set?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm... I think I was looking at execution efficiency and only executing the line when necessary, but I see your point that it's much clearer to just set the defaultNet fields in one place... so I'll move it.

// Multiple IPv6 addresses are allowed. For IPv4, if
// forceAddress is set to true then reconfigure IP address,
// otherwise throw error.
if family == netlink.FAMILY_V4 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason we wouldn't want to force the IPv6 address too? Obvoiusly the bridge could have an LL and a non-LL address, but I would expect ForceAddress to work for the IPv6 non-LL address as well.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good point. It is a little complicated since we're allowing multiple V6 addresses on the bridge. Let's say we're adding addresses for two V6 subnets: subnet A and subnet B. When this function wants to set a V6 address on the bridge, and the new address happens to be within subnet A... then we'd only want to clear (force) the existing address that corresponds to subnet A (or declare error if ForceAddress is false).

&types.Route{Dst: *defaultNet, GW: ipc.Gateway},
)
}
// Temporary workaround for Kubernetes Issue #32291. Disable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this is fine for now, soon kubelet won't do anything hairpin related (see kubernetes/kubernetes#45790 (comment)) and that'll get punted to this plugin. So we'll know in the plugin if hairpin is enabled, and if so, whether we need to disable DAD or not. Can be a follow-on PR.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good.

if err := ip.SetHWAddrByIP(args.IfName, result.IPs[0].Address.IP, nil /* TODO IPv6 */); err != nil {
return err
if result.IPs[0].Address.IP.To4() != nil {
if err := ip.SetHWAddrByIP(args.IfName, result.IPs[0].Address.IP, nil /* TODO IPv6 */); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also probably fine by now, but containernetworking/cni#448 removes this whole set-HW-addr-by-IP thing. But we can make @squeed rebase that onto this :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or I can rebase onto his change. Either way works for me. :)

@leblancd
Copy link
Author

leblancd commented Jun 1, 2017

@dcbw I've made changes according to your suggestions:

  • Move setting of defaultNet.Mask back to (near) the point where defaultNet.IP is set.
  • For setting IPv6 addresses on the bridge, check the forceAddress flag
    similar to what's done for IPv4, but only if the subnet for the requested
    V6 address overlaps with the subnet of an existing address. For
    non-overlapping V6 subnets, addresses are additive.

@leblancd
Copy link
Author

leblancd commented Jun 1, 2017

Test failures appear to be due to Travis test config issue fixed with PR #13.

@squeed
Copy link
Member

squeed commented Jun 2, 2017

FWIW, once this is merged, I will have a PR that stops changing the mac address.

@leblancd
Copy link
Author

leblancd commented Jun 5, 2017

@squeed, thanks, I saw your PR for retaining MAC address (using arp) in the containernetworking/cni repo. Looks good. I did some testing with your MAC address changes patched in with the changes here to make sure that it'll work when your arp changes merge. By the way, what is the best way to trigger a new round of travis tests?

@leblancd leblancd force-pushed the v6_bridge_plugin branch 2 times, most recently from 4804d31 to 37f8c0a Compare June 5, 2017 23:58
@squeed
Copy link
Member

squeed commented Jun 6, 2017

Hmm, I'm curious why you are adding the "local" route via the gateway - isn't one of the points of using a bridge that the packets don't need to be routed twice?

@leblancd
Copy link
Author

leblancd commented Jun 6, 2017

@squeed : Can you clarify where the local route is being added? I am adding a default route (dest = ::0/0, not a /128) in the container via one of the addresses on the bridge. (I could have set the container's default route via the bridge's link local address, but I figured it was easier to just grab an address that I had on hand). I could be missing something.

@squeed
Copy link
Member

squeed commented Jun 7, 2017

Ah, you're right - I misread the calcGateways function.

The IsDefaultGateway flag in the bridge configuration strikes me as kind of useless (it should have been part of ipam), but oh well - now I understand why you need all that code.

LGTM.

@squeed
Copy link
Member

squeed commented Jun 21, 2017

@dcbw want to give this the second seal of approval?

Copy link
Author

@leblancd leblancd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@squeed @dcbw : I enabled the UT test cases that were dependent on PR #12 getting merged. I also modified the comment for disabling IPv6 DAD to delete the Kubernetes issue (no longer applies) and add short/long term TODOs.

This change adds support for IPv6 container/pod addresses to the CNI
bridge plugin, both for dual-stack (IPv4 + IPv6) and for IPv6-only
network configurations.

The proposed changes support multiple IPv6 addresses on a container
interface. If isGW is configured, the bridge will also be configured with
gateway addresses for each IPv6 subnet.

Please note that both the dual-stack functionality and support for multiple
IPv6 container/gateway addresses depends upon containernetworking/cni
PR 451 "ipam/host-local: support multiple IP ranges".
This change could potentially be committed independently from this host-local
plugin change, however the dual-stack and multiple IPv6 address
functionality that is enabled by this change can't be exercised/tested
until the host-local plugin change is committed.

There are some IPv6 unit test cases that are currently commented out
in the proposed changes because these test cases will fail without the
prior commits of the multiple IP range host-local change.

This pull request includes a temporary workaround for Kubernetes
Issue #32291 (Container IPv6 address is marked as duplicate, or dadfailed).
The problem is that kubelet enables hairpin mode on bridge veth
interfaces. Hairpin mode causes the container/pod to see echos of its
IPv6 neighbor solicitation packets, so that it declares duplicate address
detection (DAD) failure. The long-term fix is to use enhanced-DAD
when that feature is readily available in kernels. The short-term fix is
to disable IPv6 DAD in the container. Unfortunately, this has to be done
unconditionally (i.e. without a check for whether hairpin mode is enabled)
because hairpin mode is turned on by kubelet after the CNI bridge plugin
has completed cmdAdd processing. Disabling DAD should be okay if
IPv6 addresses are guaranteed to be unique (which is the case for
host-local IPAM plugin).
@dcbw
Copy link
Member

dcbw commented Jun 28, 2017

LGTM

@dcbw dcbw merged commit f01230d into containernetworking:master Jun 28, 2017
lsm5 pushed a commit to lsm5/containernetworking-plugins that referenced this pull request Oct 24, 2019
…evert

Reverts change to build_linux.sh to build.sh
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants