-
Notifications
You must be signed in to change notification settings - Fork 40k
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
Updates RangeSize error message and tests for IPv6. #47621
Conversation
@@ -254,7 +254,7 @@ func calculateIPOffset(base *big.Int, ip net.IP) int { | |||
func RangeSize(subnet *net.IPNet) int64 { | |||
ones, bits := subnet.Mask.Size() | |||
if (bits - ones) >= 31 { | |||
panic("masks greater than 31 bits are not supported") | |||
panic("masks smaller than /2 for IPv4 or /98 for IPv6 are not supported.") |
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.
Just curious, does everyone say /1 is "smaller" than /2? Will it be ambiguous?
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.
That's a good point. Maybe shorter and longer is more appropriate for describing the "length" of the subnet mask. Let me know if you find these descriptions acceptable.
}, { | ||
cidr: "192.168.1.0/28", | ||
addrs: 999, | ||
expect: false, |
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.
Why can't we use the correct addrs
and test addrs==RangeSize(cidr)?
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.
OK. I'll update.
/assign @MrHohn |
Reassigning ipv6 PR. /unassign /assign @bowei |
lgtm, but will let someone from the networking team take a look. |
@@ -254,7 +254,7 @@ func calculateIPOffset(base *big.Int, ip net.IP) int { | |||
func RangeSize(subnet *net.IPNet) int64 { | |||
ones, bits := subnet.Mask.Size() | |||
if (bits - ones) >= 31 { | |||
panic("masks greater than 31 bits are not supported") | |||
panic("masks shorter than /2 for IPv4 or /98 for IPv6 are not supported.") |
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.
If I understand this, the function is returning the number of hosts that can be expressed by the IPNet. That said, should the message reflect that, instead of in terms of the mask size? Maybe something like "Cannot support more than 2^30 hosts for IPNet 2001::4/64", for example.
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.
In my experience, subnet masks are expressed using "length". I prefer using shorter or longer with a / notation to describe a subnet mask.
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.
Sure. I'm just pointing out (the subtle point) that the method is returning the number of hosts available for the subnet, and wondering if the error message that would get returned, should focus on that, rather than on mask size. For example:
err: = fmt.Sprintf("too many hosts allowed for subnet (%v). Must be /%d or longer", subnet, bits-30)
However, see my last comment on L254, where maybe this should be redesigned to check for valid subnet lengths, rather than returning the number of hosts and having the caller doing some of the checking, with the rest done here. Then, the error messages could be in terms of mask size (from tests for it being too short or too long).
}, { | ||
cidr: "2001:db8::/127", | ||
addrs: 2, | ||
}, |
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.
Only concern is that only passing cases are covered.
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.
Agreed. I had fail cases in my original commit but I then removed them. As you mention in your other comment, I think the func needs to be updated to return an error.
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.
Some suggestions on the RangeSize function.
@@ -254,7 +254,7 @@ func calculateIPOffset(base *big.Int, ip net.IP) int { | |||
func RangeSize(subnet *net.IPNet) int64 { |
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.
Should the function signature be changed to return an error indication? This way, you could unit test for failure cases (I don't know how you can UT panics).
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.
Alternatively, should the function just return the # networks, 0+, and then the caller can check for validity of the number of the range? Right now, it determines the range of hosts AND checks for exceeding a maximum, but not a minimum. Looks like some callers are doing checking.
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 open to making the changes. Maybe it's best to implement the changes and the failure case UT's in a follow-on PR? Lets see what @MrHohn has to say.
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.
My vote would be to address it now, since the submit queue is blocked. BTW the current assignment has @bowei, instead of MrHohn.
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.
If possible I would change this function to return an error, we should try to avoid panic() in long running server code.
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.
Looking at the usage of this, the function panics (should be returning error, IMHO), if the subnet is too large, and if not, returns the number of hosts available, and the caller then checks if the subnet is too small. Maybe this should be changed to CheckSubnetSize() and return error if too large or too small, and caller can just check return (error) for non-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.
Looks like it is not too much work to propagate an error instead of panic here. Would be great to fix.
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.
@bowei when you have time, do you mind taking a look at this PR? |
taking a look |
@@ -156,13 +156,16 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi | |||
return LegacyRESTStorage{}, genericapiserver.APIGroupInfo{}, err | |||
} | |||
|
|||
ServiceClusterIPAllocator := ipallocator.NewAllocatorCIDRRange(&serviceClusterIPRange, func(max int, rangeSpec string) allocator.Interface { | |||
ServiceClusterIPAllocator, err := ipallocator.NewAllocatorCIDRRange(&serviceClusterIPRange, func(max int, rangeSpec string) allocator.Interface { |
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.
is there a reason why this ServiceClusterIPAllocator is Capitalized?
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.
It should not be capitalized. I updated to lowercase.
@@ -83,11 +87,11 @@ func NewAllocatorCIDRRange(cidr *net.IPNet, allocatorFactory allocator.Allocator | |||
max: maximum(0, int(max-2)), // don't use the network broadcast, | |||
} | |||
r.alloc = allocatorFactory(r.max, rangeSpec) | |||
return &r | |||
return &r, err |
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.
shouldn't this be return &r, 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.
Thanks for catching this. I have updated the return.
ones, bits := subnet.Mask.Size() | ||
if (bits - ones) >= 31 { | ||
panic("masks greater than 31 bits are not supported") | ||
return 0, fmt.Errorf("Subnet mask for %q is shorter than /2 for IPv4 or /98 for IPv6.", subnet) |
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.
"subnet mask must be >= /2 for IPv4 or /98 for IPv6"
(change message to be about valid values)
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 have updated the error message.
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.
Updated based on @bowei comments.
@@ -156,13 +156,16 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi | |||
return LegacyRESTStorage{}, genericapiserver.APIGroupInfo{}, err | |||
} | |||
|
|||
ServiceClusterIPAllocator := ipallocator.NewAllocatorCIDRRange(&serviceClusterIPRange, func(max int, rangeSpec string) allocator.Interface { | |||
ServiceClusterIPAllocator, err := ipallocator.NewAllocatorCIDRRange(&serviceClusterIPRange, func(max int, rangeSpec string) allocator.Interface { |
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.
It should not be capitalized. I updated to lowercase.
@@ -83,11 +87,11 @@ func NewAllocatorCIDRRange(cidr *net.IPNet, allocatorFactory allocator.Allocator | |||
max: maximum(0, int(max-2)), // don't use the network broadcast, | |||
} | |||
r.alloc = allocatorFactory(r.max, rangeSpec) | |||
return &r | |||
return &r, err |
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.
Thanks for catching this. I have updated the return.
ones, bits := subnet.Mask.Size() | ||
if (bits - ones) >= 31 { | ||
panic("masks greater than 31 bits are not supported") | ||
return 0, fmt.Errorf("Subnet mask for %q is shorter than /2 for IPv4 or /98 for IPv6.", subnet) |
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 have updated the error message.
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.
otherwise looks ok to me
ones, bits := subnet.Mask.Size() | ||
if (bits - ones) >= 31 { | ||
panic("masks greater than 31 bits are not supported") | ||
return 0, fmt.Errorf("subnet mask must be longer than /1 for IPv4 or /97 for IPv6") |
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.
Put exported error at the top:
ErrMaskTooSmall = error.New("subnet mask must be longer than /1 for IPv4 or /97 for IPv6")
then
return 0, ErrMaskTooSmall
numAddresses := ipallocator.RangeSize(svcSubnet) | ||
numAddresses, err := ipallocator.RangeSize(svcSubnet) | ||
if err != nil { | ||
allErrs = append(allErrs, field.Invalid(fldPath, subnet, "subnet mask is too short")) |
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.
A bit more future proof:
if err != nil {
if err == ipallocator.ErrMaskTooSmall {
allErrs = append(allErrs, field.Invalid(fldPath, subnet, "subnet mask is too short"))
} else {
allErrs = append(allErrs, field.Invalid(fldPath, subnet, "invalid service subnet"))
}
}
@bowei sorry it took me so long to address your feedback. I have updated the PR based on your feedback and tests pass. Let me know if you need anything for a lgtm. Thanks for your help. |
/lgtm thanks for carrying this over the finish line! |
/approve |
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
/retest |
@bowei @mikedanese do you mind reviewing this PR when you have a moment? |
@caesarxuchao do you mind reviewing this PR when you have a moment? This needed for adding IPv6 support in the 1.9 release. /assign @thockin |
name string | ||
cidr string | ||
addrs int64 | ||
expect bool |
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 name expect
isn't clear to me. What does it expect?
A nit. I don't see other problems, but I'm not experienced in the network world. @bowei @dnardo could you take a look? /unassign @caesarxuchao |
@@ -42,6 +42,7 @@ var ( | |||
ErrFull = errors.New("range is full") | |||
ErrAllocated = errors.New("provided IP is already allocated") | |||
ErrMismatchedNetwork = errors.New("the provided network does not match the current range") | |||
ErrMaskTooSmall = errors.New("subnet mask must be longer than /1 for IPv4 or longer than /65 for IPv6") |
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 sure what /1 means here - do you mean /31 ? 10.0.0.0/1
is nonsense?
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 mean the mask must be /2 or longer (/8, /16, etc.). I did not change any of the existing IPv4 logic in this PR. I updated the error message because it was incorrect.
Old Error:masks greater than 31 bits are not supported
As you can see in the RangeSize function, (bits - ones) >= 31
. For IPv4, bits = 32 and ones is the number of masked bits in the 32-bit address. For a /1, the math would trigger the error ``(32 - 1) >= 31`. I am happy to submit a PR to implement a fix if this is not the expected behavior, unless you prefer the fix to be implemented in this PR.
I just mean that `/2` seems like the wrong notation - the "mask" is usually
the ones portion, right, so we're saying that masks subnets smaller than
/30 are not allowed. And frankly, even /30 is kind of silly, but might be
useful for testing. I am arguing with the words/messages, not the logic.
…On Mon, Oct 9, 2017 at 8:58 AM, Daneyon Hansen ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In pkg/registry/core/service/ipallocator/allocator.go
<#47621 (comment)>
:
> @@ -42,6 +42,7 @@ var (
ErrFull = errors.New("range is full")
ErrAllocated = errors.New("provided IP is already allocated")
ErrMismatchedNetwork = errors.New("the provided network does not match the current range")
+ ErrMaskTooSmall = errors.New("subnet mask must be longer than /1 for IPv4 or longer than /65 for IPv6")
I mean the mask must be /2 or longer (/8, /16, etc.). I did not change any
of the existing IPv4 logic in this PR. I updated the error message because
it was incorrect.
*Old Error:*masks greater than 31 bits are not supported
As you can see in the RangeSize function, (bits - ones) >= 31. For IPv4,
bits = 32 and ones is the number of masked bits in the 32-bit address. For
a /1, the math would trigger the error ``(32 - 1) >= 31`. I am happy to
submit a PR to implement a fix if this is not the expected behavior, unless
you prefer the fix to be implemented in this PR.
—
You are receiving this because you were assigned.
Reply to this email directly, view it on GitHub
<#47621 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AFVgVIUZwyOaEWnjKA6dN3N3Ra6O0ly_ks5sqkKIgaJpZM4N72s4>
.
|
I can change the notation in the error message from a
I used the Here is a Go Playground example: https://play.golang.org/p/6r4JwMs1TL I apologize if I'm not following you. |
I think there are a couple things being conflated. The
Basically, could teh whole PR be reduced to removing that panic and just allowing it to return 0 ? |
@thockin I like the idea of simply returning 0 and removing the error return. I can check |
@thockin the PR has been greatly simplified and is passing tests. |
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
@@ -263,8 +263,8 @@ func calculateIPOffset(base *big.Int, ip net.IP) int { | |||
// RangeSize returns the size of a range in valid addresses. | |||
func RangeSize(subnet *net.IPNet) int64 { | |||
ones, bits := subnet.Mask.Size() | |||
if (bits - ones) >= 31 { | |||
panic("masks greater than 31 bits are not supported") | |||
if bits == 32 && (bits-ones) >= 31 || bits == 128 && (bits-ones) >= 63 { |
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.
As a future clean-up, we should look at making this easier to understand (or supplement it with a comment to indicate that if the network bits are less than 2 for IPv4 or less than 65 for IPv6 it fails. OK for now.
/lgtm |
/approve no-issue |
@thockin this PR needs one more approver. Do you mind taking a look when you have a few minutes to spare? |
@wojtek-t for approval |
/approve no-issue |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: bowei, danehans, leblancd, pmichali, wojtek-t Associated issue: 1443 The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these OWNERS Files:
You can indicate your approval by writing |
/test all [submit-queue is verifying that this PR is safe to merge] |
Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions here. |
What this PR does / why we need it:
Updates the RangeSize function's error message and tests for IPv6. Converts RangeSize unit test to a table test and tests for success and failure cases. This is needed to support IPv6. Previously, it was unclear whether RangeSize supported IPv6 CIDRs. These updates make IPv6 support explicit.
Which issue this PR fixes
Partially fixes Issue #1443
Special notes for your reviewer:
/area ipv6
Release note: