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
Delete IPv6 route and neigh to peer gateway if necessary #3490
Conversation
047d9df
to
48cf995
Compare
/test-ipv6-only-e2e |
Codecov Report
@@ Coverage Diff @@
## main #3490 +/- ##
===========================================
- Coverage 65.47% 55.28% -10.20%
===========================================
Files 268 384 +116
Lines 26909 52707 +25798
===========================================
+ Hits 17620 29137 +11517
- Misses 7366 21096 +13730
- Partials 1923 2474 +551
Flags with carried forward coverage won't be shown. Click here to find out more.
|
pkg/agent/route/route_linux.go
Outdated
@@ -726,7 +726,9 @@ func (c *Client) Reconcile(podCIDRs []string, svcIPs map[string]bool) error { | |||
} | |||
// IPv6 doesn't support "on-link" route, routes to the peer IPv6 gateways need to | |||
// be added separately. So don't delete such routes. | |||
if desiredIPv6GWs.Has(route.Dst.IP.String()) { | |||
// If WireGuard is enabled, the route to peer IPv6 gateway should be deleted since |
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.
When it starts, if there is an IPv6 "onlink" route, it means it was normal mode and the remote Node still exists. I think it's more proper to "replace" the routes together when we call InstallNodeRoute
for this Node, instead of removing "onlink" route here and the other route in InstallNodeRoute
.
The issue is essentially we thought route.Replace
can achieve route removal and creation, but it didn't work for wireguard case as the latter has only 1 route.
I think we could probably first check if the normal case really needs two routes. If yes, we should fix how "replace" is implemented. If no, we should just remove the "onlink" route.
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.
After some digging, I found that kernel > 4.16 supports adding IPv6 routes with the onlink
flag as IPv4 does. Do you think we can remove the routes for the peer gateway and add routes to peer CIDRs with the onlink
flag directly?
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.
The current kernel version requirement is >4.6. I think it's not worth to bump up the requirement to 4.16 just for this, given that it's easy to resolve with existing solution. Besides, Ubuntu 18.04 (<18.04.2) ships with 4.15, which might still be used.
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.
Thank you, @tnqn. I think we can remove routes for peer gateway if WireGuard is enabled in AddRoutes
or create a gateway route for WireGuard to replace the one in normal mode. I am not sure which one is better. I initially thought that AddRoutes
is responsible for adding or replacing routes. But we did need to delete the route for WireGuard.
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.
Not only WireGuard, there is also an issue when changing from encap to noEncap mode (in same subnet case).
I think we shouldn't add an unneeded route for this bug, and it doesn't fix encap -> noEncap (in different subnet case) anyway.
I feel the proper fix is to clean up possible stable routes installed by other modes when it installs routes for one mode. For example:
routeToNodeGwIPReplaced := false
routeToPodCIDRReplaced := false
for _, route := range routes {
if err := netlink.RouteReplace(route); err != nil {
return fmt.Errorf("failed to install route to peer %s (%s) with netlink. Route config: %s. Error: %v", nodeName, nodeIP, route.String(), err)
}
if route.Dst == podCIDR {
routeToPodCIDRReplaced = true
} else if route.Dst == ... {
routeToNodeGwIPReplaced = true
}
}
if !routeToNodeGwIPReplaced {
if err := netlink.RouteDel(...); err != nil {
...
}
}
if !routeToPodCIDRReplaced {
if err := netlink.RouteDel(...); err != 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.
I've updated the code per discussion. But I did not remove the route to peer Pod CIDR when the route to peer Pod CIDR was not replaced. I am not confident about removing the route by just setting the Pod CIDR as the only parameter. Will it delete the route added manually in noEncap mode plus different subnet cases?
48cf995
to
dd00ccd
Compare
pkg/agent/route/route_linux.go
Outdated
} | ||
|
||
if podCIDR.IP.To4() == nil { | ||
if !routeToNodeGwIPv6Replaced && utilnet.IsIPv6(nodeGwIP) { |
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.
Not only routeToNodeGwIPNetv6, we also need to remove routeToPodCIDRReplaced when it's NoEncap mode in different subnet. And second thought about how to identify stale routes:
staleRouteDsts := sets.NewString(podCIDR.String())
if utilnet.IsIPv6(nodeGwIP) {
staleRouteDsts.Insert(&net.IPNet{IP: nodeGwIP, Mask: net.CIDRMask(128, 128).String())
}
if c.networkConfig.TrafficEncryptionMode == config.TrafficEncryptionModeWireGuard {
route.LinkIndex = c.nodeConfig.WireGuardConfig.LinkIndex
route.Scope = netlink.SCOPE_LINK
if podCIDR.IP.To4() != nil {
route.Src = c.nodeConfig.GatewayConfig.IPv4
} else {
route.Src = c.nodeConfig.GatewayConfig.IPv6
}
staleRouteDsts.Delete(podCIDR.String())
} else if ... {
...
}
...
for dst := range staleRouteDsts {
if err := netlink.RouteDel(&netlink.Route{Dst: dst}); err != 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.
I am unsure about the CIDR route for Pods in NoEncap mode & different subnets. Do you think we may delete the route added by users or other CNIs mistakenly if we only use the Pod CIDR as dst IP to identify a route?
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.
Good point, I think you are right. antrea can work with kube-router, which may install route for PodCIDR for noEncap case.
pkg/agent/route/route_linux.go
Outdated
routeToNodeGwIPNetv6 := &netlink.Route{ | ||
Dst: nodeGwIPNetv6, | ||
} | ||
if err := netlink.RouteDel(routeToNodeGwIPNetv6); err != nil && err == 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.
err != nil && err == nil ?
dd00ccd
to
0d124bf
Compare
pkg/agent/route/route_linux.go
Outdated
} | ||
|
||
if podCIDR.IP.To4() == nil { | ||
if !routeToNodeGwIPv6Replaced && utilnet.IsIPv6(nodeGwIP) { |
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.
Good point, I think you are right. antrea can work with kube-router, which may install route for PodCIDR for noEncap case.
pkg/agent/route/route_linux.go
Outdated
nodeGwIPNetv6, nodeName, nodeIP, err) | ||
} | ||
} | ||
if routeToPodCIDRReplaced && podCIDR.IP.To4() == 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.
I suspect the original code is wrong, because it seems the neighbor entry is only needed in encap case.
If you could verify and fix it in the PR it would be great. Or we could keep its current behavior for now, but the code could be simpler (sorry for the second thought):
requireNodeGwIPv6RouteAndNeigh := false
if c.networkConfig.TrafficEncryptionMode == config.TrafficEncryptionModeWireGuard {
...
} else if c.networkConfig.NeedsTunnelToPeer(nodeIP, nodeTransportIPAddr) {
if podCIDR.IP.To4() == nil {
requireNodeGwIPv6RouteAndNeigh = true
// "on-link" is not identified in IPv6 route entries, so split the configuration into 2 entries.
routes = []*netlink.Route{
{
Dst: &net.IPNet{IP: nodeGwIP, Mask: net.IPMask{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
LinkIndex: c.nodeConfig.GatewayConfig.LinkIndex,
},
}
} else {
...
}
}
if !requireNodeGwIPv6RouteAndNeigh && utilnet.IsIPv6(nodeGwIP) {
err := netlink.RouteDel(...)
...
}
if requireNodeGwIPv6RouteAndNeigh && utilnet.IsIPv6(nodeGwIP) {
// Add IPv6 neighbor if the given podCIDR is using IPv6 address.
neigh := &netlink.Neigh{...}
...
/test-ipv6-only-e2e |
/test-ipv6-only-e2e |
0d124bf
to
14ffad8
Compare
14ffad8
to
dbfe802
Compare
/test-ipv6-only-e2e |
dbfe802
to
11ab140
Compare
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.
LGTM, let's see if test passes
pkg/agent/route/route_linux.go
Outdated
Dst: &net.IPNet{IP: nodeGwIP, Mask: net.CIDRMask(128, 128)}, | ||
} | ||
if err := netlink.RouteDel(routeToNodeGwIPNetv6); err == nil { | ||
klog.InfoS("Deleted route to peer gateway", "node", nodeName, "ip", nodeIP) |
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.
klog.InfoS("Deleted route to peer gateway", "node", nodeName, "ip", nodeIP) | |
klog.InfoS("Deleted route to peer gateway", "node", nodeName, "nodeIP", nodeIP, "nodeGatewayIP", nodeGwIP) |
as this route is mainly related to nodeGatewayIP.
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.
done.
pkg/agent/route/route_linux.go
Outdated
IP: nodeGwIP, | ||
} | ||
if err := netlink.NeighDel(neigh); err == nil { | ||
klog.InfoS("Deleted neigh to peer gateway", "node", nodeName, "ip", nodeIP) |
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.
ditto
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.
done. thanks!
Check whether the route and neigh to peer gateway are still needed and delete the route and neigh if necessary. This can happen when the traffic encryption mode or traffic encapsulation mode changes. Fixes antrea-io#3437 Signed-off-by: Xu Liu <xliu2@vmware.com>
11ab140
to
5973624
Compare
/test-e2e |
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.
LGTM
/test-integration |
Check whether the route and neigh to peer gateway are still needed
and delete the route and neigh if necessary. This can happen when
the traffic encryption mode or traffic encapsulation mode changes.
Fixes #3437
Signed-off-by: Xu Liu xliu2@vmware.com