-
Notifications
You must be signed in to change notification settings - Fork 55
OCPBUGS-87249: on AWS, select associated IPv6 CIDR block for egress IP subnet #228
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
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 |
|---|---|---|
|
|
@@ -276,23 +276,32 @@ func (a *AWS) getSubnet(networkInterface *ec2.InstanceNetworkInterface) (*net.IP | |
| var v4Subnet, v6Subnet *net.IPNet | ||
| subnet := describeOutput.Subnets[0] | ||
| if subnet.CidrBlock != nil && *subnet.CidrBlock != "" { | ||
| _, subnet, err := net.ParseCIDR(*subnet.CidrBlock) | ||
| _, v4Net, err := net.ParseCIDR(*subnet.CidrBlock) | ||
|
Contributor
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. Why do you have to change the variable name here?
Contributor
Author
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. this subnet variable is used for v4 and v6 below, it's like one variable used for two different ipstack types, it is easy to get confused , that is why I changed the variable name. But I can revert if you prefer minimal change |
||
| if err != nil { | ||
| return nil, nil, fmt.Errorf("error: unable to parse IPv4 subnet, err: %v", err) | ||
| } | ||
| v4Subnet = subnet | ||
| v4Subnet = v4Net | ||
| } | ||
|
|
||
| // I don't know what it means to have several IPv6 CIDR blocks defined for | ||
| // one subnet, specially given that you can only have one IPv4 CIDR block | ||
| // defined...¯\_(ツ)_/¯ | ||
| // Let's just pick the first. | ||
| if len(subnet.Ipv6CidrBlockAssociationSet) > 0 && subnet.Ipv6CidrBlockAssociationSet[0].Ipv6CidrBlock != nil && *subnet.Ipv6CidrBlockAssociationSet[0].Ipv6CidrBlock != "" { | ||
| _, subnet, err := net.ParseCIDR(*subnet.Ipv6CidrBlockAssociationSet[0].Ipv6CidrBlock) | ||
| // A subnet can have multiple IPv6 CIDR block associations (e.g., a previous | ||
| // "disassociated" one and a current "associated" one). On dualstack AWS clusters | ||
| // after subnet CIDR changes, picking the wrong (stale) CIDR causes egress IP | ||
| // assignment to fail because OVN-Kubernetes selects IPs from the wrong range. | ||
| // Always select the first association in "associated" state. | ||
| for _, assoc := range subnet.Ipv6CidrBlockAssociationSet { | ||
| if assoc.Ipv6CidrBlock == nil || *assoc.Ipv6CidrBlock == "" { | ||
| continue | ||
| } | ||
| if assoc.Ipv6CidrBlockState == nil || assoc.Ipv6CidrBlockState.State == nil || | ||
| *assoc.Ipv6CidrBlockState.State != ec2.SubnetCidrBlockStateCodeAssociated { | ||
|
Member
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 there a possibility of more than one associated subnet ? hope you have checked it.
Contributor
Author
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. Yes, technically AWS allows multiple IPv6 CIDR blocks in associated state simultaneously (e.g., when additional IPv6 prefixes are added to a subnet). The current code takes the first associated entry, silently ignoring any others. This means EgressIPs can only be assigned from the first CIDR. This is consistent with how we handle the node's subnet today. If multiple associated entries exist, should I add a klog.Warningf when a second associated entry is found to make this situation visible in logs? Is that what you expect?
Member
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 first associated CIDR entry for node subnet? wanted to confirm that, otherwise we may end up EIP not getting assigned to the node.
Contributor
Author
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. yes, it is from node’s subnet, the sequence is
Contributor
Author
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. BTW, regarding whether there would be multiple v6 CIDR blocks, I got more accurate answer from @sadasu: within a VPC in which the cluster is installed. there could be 3 Availability zones (AZs). Within each AZ, there needs to be 1 public and 1 private subnet. So, with this calculation, we should have 6 IPv6 CIDRs within an install.
Contributor
Author
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 — Ipv6CidrBlockAssociationSet is per-subnet, not a mix of public and private subnets. If the worker is in the private subnet (for most normal OpenShift clusters), CNCC describes that subnet via the node ENI’s SubnetId, and the annotation gets that private subnet’s IPv6 /64. We pick the first associated IPv6 CIDR on that subnet, skipping any disassociated (stale) entries. If the worker were placed in a public subnet, the same logic applies and the annotation would get that public subnet’s IPv6 /64 instead. Ipv6CidrBlockAssociationSet on a given subnet only contains IPv6 CIDR blocks for that subnet — it does not mix public and private subnet CIDRs. 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. @jechen0648 +1 . Above approach makes sense. 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.
1 NIC associated with the primary subnet on the worker node is associated with OVNK. I think we are just interested in the subnet associated with this NIC and finding its IPv6 subnet that is still associated.
Contributor
Author
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.
yes
Member
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 @jechen0648 and @sadasu ! |
||
| continue | ||
| } | ||
| _, v6Net, err := net.ParseCIDR(*assoc.Ipv6CidrBlock) | ||
| if err != nil { | ||
| return nil, nil, fmt.Errorf("error: unable to parse IPv6 subnet, err: %v", err) | ||
| } | ||
| v6Subnet = subnet | ||
| v6Subnet = v6Net | ||
| break | ||
|
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 this method is called only for dualstack installations, we should warn when we don't find any IPv6 subnet that is associated. For DualStack IPv6 primary, that would be an error and IPv4Primary that would be a warning. Is that captured anywhere?
Contributor
Author
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. getSubnet() will be called for any IP stack type AWS, if Ipv6CidrBlockAssociationSet is not empty, it just processes and finds the first associated IPv6 CidrBlock You're right that on dual-stack clusters, a missing associated IPv6 subnet may warrant a warning or error depending on Infrastructure.status.platformStatus.aws.ipFamily (DualStackIPv6Primary vs DualStackIPv4Primary). That logic is not implemented today — CNCC does not read cluster IP family config. I think that's out of scope for this PR, which only fixes selecting the correct associated IPv6 CIDR when multiple associations exist. How about to open a follow-up for IP-stack-aware validation? 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. Understood. Thanks! |
||
| } | ||
|
|
||
| return v4Subnet, v6Subnet, 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.
so previously does it took 'disassociated' subnet entry at [0] which is different from host subnet, what was that subnet value ? just curious.
Uh oh!
There was an error while loading. Please reload this page.
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 created a draft PR trying to print out of the first IPv6 CIDR, I ran egressIP test on dualstack AWS a few times, I have not been able to reproduce the first entry as disassociated one. OCPBUGS-87249 is not always reproducible.