xds: fix uint32 overflow scaling rds route runtime_fraction - #9308
xds: fix uint32 overflow scaling rds route runtime_fraction#9308nvxbug wants to merge 2 commits into
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #9308 +/- ##
==========================================
- Coverage 83.07% 83.05% -0.02%
==========================================
Files 423 424 +1
Lines 35230 35223 -7
==========================================
- Hits 29266 29255 -11
+ Misses 4448 4446 -2
- Partials 1516 1522 +6
🚀 New features to boost your workflow:
|
|
I see that there are a bunch of places where fractional percent is handled/parsed/used. I'd like to centralize this into a type in the package xdsresource
// FractionalPercent is the internal representation of the xDS FractionalPercent proto.
type FractionalPercent struct {
Numerator uint32
Denominator uint32
PPM uint32 // Pre-computed and capped at 1,000,000
}
func NewFractionalPercent(fp *v3typepb.FractionalPercent) (FractionalPercent, error) {
if fp == nil {
return FractionalPercent{Numerator: 0, Denominator: 100, PPM: 0}, nil
}
var den uint32
switch fp.GetDenominator() {
case v3typepb.FractionalPercent_HUNDRED:
den = 100
case v3typepb.FractionalPercent_TEN_THOUSAND:
den = 10000
case v3typepb.FractionalPercent_MILLION:
den = 1000000
default:
return FractionalPercent{}, fmt.Errorf("unsupported denominator: %v", fp.GetDenominator())
}
num := fp.GetNumerator()
// Perform multiplication in uint64 to prevent overflow
ppm := uint64(num) * 1000000 / uint64(den)
if ppm > 1000000 {
ppm = 1000000 // Cap at 100%
}
return FractionalPercent{
Numerator: num,
Denominator: den,
PPM: uint32(ppm),
}, nil
}Then we can fix usages in the following places:
Please let me know if you are interested in making these changes. Thanks. |
c53a790 to
1fb7ac3
Compare
|
Done. Added FractionalPercent/NewFractionalPercent to xdsresource pretty much as you sketched it, and moved the four call sites onto it: rds runtime_fraction now stores the precomputed PPM, the eds drop policy carries a FractionalPercent in OverloadDropConfig, clusterimpl uses the PPM directly (dropRequestsPerMillion is gone), and fault's splitPct delegates to it. One behavior change worth flagging: an rds runtime_fraction with an unrecognized denominator now NACKs the route config instead of treating the numerator as parts-per-million, which matches what the eds path already did. I left ext_authz's parseFilterEnabled alone since it wasn't on your list, but can fold it in too if you'd rather. Also rebased onto master while I was at it. |
Thank you for fixing this.
That would be great if you can handle it too. |
| wantErr bool | ||
| }{ | ||
| { | ||
| name: "nil is zero out of hundred", |
There was a problem hiding this comment.
Nit: Could you please make the subtest names look more like identifiers (using underscores or dashes instead of spaces would work). See: https://google.github.io/styleguide/go/decisions#subtest-names
Thanks.
| func splitPct(fp *tpb.FractionalPercent) (num int, den int) { | ||
| if fp == nil { | ||
| return 0, 100 | ||
| f, err := xdsresource.NewFractionalPercent(fp) |
There was a problem hiding this comment.
Do you mind adding a TODO here to say that this validation should happen at parsing time instead and the filter configuration must be NACKed if an unrecognized denominator is seen.
I don't want to ask you to do this change as part of this PR since it would involve a bunch of refactoring in the fault filter to actually convert the proto into an internal representation at config parsing time (and perform all validation checks) and then only use the internal representation during runtime.
|
@eshitachandwani Moving it to you for second set of eyes |
|
Looks good to me but I will wait till the comments from Easwar are resolved before approving and merging. |
routesProtoToSlice scales a route's runtime_fraction to parts-per-million by multiplying the numerator by 10000 (HUNDRED) or 100 (TEN_THOUSAND) in uint32. The numerator comes from the control plane, so a value like 429497 with a HUNDRED denominator computes 429497*10000 and wraps around to 2704. A route meant to match every request then matches roughly 0.27% of them, and the rest silently fall through to a different route action.
Per review feedback, fractional percent handling is now centralized in a new xdsresource.FractionalPercent type. NewFractionalPercent converts the proto, computes the parts-per-million value in uint64, caps it at 1000000 (100%), and rejects unsupported denominators. The four places that parsed the proto themselves now use it:
RELEASE NOTES: