Change:
<!-- Thanks for filing an issue! Before hitting the button, please answer these questions.--Is this a request for help? (If yes, you should use our troubleshooting guide and community support channels, see ): No What keywords did you search in Kubernetes issues before filing this one? (If you have found any duplicates, you should instead reply there.): hexCIDR and CIDR Is this a BUG REPORT or FEATURE REQUEST? (choose one): BUG REPORT <!-- If this is a BUG REPORT, please: Fill in as much of the template below as you can. If you leave out information, we can't help you as well. If this is a FEATURE REQUEST, please: Describe in detail the feature/behavior/change you'd like to see. In both cases, be ready for followup questions, and please respond in a timely manner. If we can't reproduce a bug or think a feature already exists, we might close your issue. If we're wrong, PLEASE feel free to reopen it and explain why. --Kubernetes version (use ): latest on master Environment: Cloud provider or hardware configuration: Bare-metal, 3 node config using KubeAdm OS (e.g. from /etc/os-release): CentOS 7 Kernel (e.g. ): Linux devstack-77 3.10.0-514.10.2.el7.x8664 SMP Fri Mar 3 00:04:05 UTC 2017 x8664 x8664 x8664 GNU/Linux Install tools: KubeAdm Others: What happened: Investigating the code, hexCIDR() expects the CIDR passed to be for an IPv4 address and doesn't support an IPv6 CIDR. What you expected to happen: Support either IPv4 or IPv6 CIDRs. How to reproduce it (as minimally and precisely as possible): Anything else we need to know: Will be working on a solution for this. Note: In some of the call paths, a PodIP string is used and passed in as a CIDR with a "/32" appended. At some point, this would need to be updated as well, to use "/128" if an IPv6 PodIP was used.
I see there is an asciiCIDR() method too that needs addressing, but only in the UTs. Appears that it is expecting to reverse hex back to string, but test is not showing case of mask being properly applied. For example, "2001::5/64" when converted to hex and then back to string will be "2001::/64". Will update test to be more accurate.
/area networking
These labels do not exist in this repository: . <detailsIn response to : /area networking Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. I understand the commands that are listed . </details
/sig network
One question I have... Can the callers (bandwidth?) of the function work with an IPv6 based hex CIDR? In the future, if we support pod IPs that are IPv6 addresses, and we modify the code to add /128 vs /32, as is done currently, this would create an IPv6 based hex CIDR.
The only caller is currently the ingress/egress shaping function in kubelet. That code also needs to be updated for IPv6. For example, assumes IPv4 when adding CIDRs to the shaper list.
Agree.I wanted to separate this out, partly to make the change smaller, but also, when I looked at the callers (this shaping functionality) I wasn't sure if it would support IPv6. I looked a bit at the "tc" command and saw some notes that indicate that it doesn't support IPv6 yet. Is that still accurate? Would it be ok to tackle that separately?

Discussion:
return "", err } ip = ip.Mask(ipnet.Mask) <del> hexIP := hex.EncodeToString([]byte(ip.To4())) </del> <ins> hexIP := hex.EncodeToString([]byte(ip)) </ins> hexMask := ipnet.Mask.String() return hexIP + "/" + hexMask, nil }

ip := net.IP(ipData) maskData, err := hex.DecodeString(parts[1]) <ins> if err != nil { return "", err } </ins> mask := net.IPMask(maskData) size, _ := mask.Size()

func TestHexCIDR(t *testing.T) { tests := []struct { <ins> name      string </ins> input     string output    string expectErr bool }{ { <del> input:  "1.2.0.0/16", </del> <ins> name:   "IPv4 masked", input:  "1.2.3.4/16", </ins> output: "01020000/ffff0000", }, { <ins> name:   "IPv4 host", </ins> input:  "172.17.0.2/32", output: "ac110002/ffffffff", }, { <ins> name:   "IPv6 masked", input:  "2001:dead:beef::cafe/64", output: "2001deadbeef00000000000000000000/ffffffffffffffff0000000000000000", }, { name:   "IPv6 host", input:  "2001::5/128", output: "20010000000000000000000000000005/ffffffffffffffffffffffffffffffff", }, { name:      "invalid CIDR", </ins> input:     "foo", expectErr: true, },

output, err := hexCIDR(test.input) if test.expectErr { if err == nil { <del> t.Error("unexpected non-error") </del> <ins> t.Errorf("case %s: unexpected non-error", test.name) </ins> } } else { if err != nil { <del> t.Errorf("unexpected error: %v", err) </del> <ins> t.Errorf("case %s: unexpected error: %v", test.name, err) </ins> } if output != test.output { <del> t.Errorf("expected: %s, saw: %s", test.output, output) </del> <ins> t.Errorf("case %s: expected: %s, saw: %s", test.name, test.output, output) </ins> } <del> input, err := asciiCIDR(output) </del> <ins> } } } func TestAsciiCIDR(t *testing.T) { tests := []struct { name      string input     string output    string expectErr bool }{ { name:   "IPv4", input:  "01020000/ffff0000", output: "1.2.0.0/16", }, { name:   "IPv4 host", input:  "ac110002/ffffffff", output: "172.17.0.2/32", }, { name:   "IPv6", input:  "2001deadbeef00000000000000000000/ffffffffffffffff0000000000000000", output: "2001:dead:beef::/64", }, { name:   "IPv6 host", input:  "20010000000000000000000000000005/ffffffffffffffffffffffffffffffff", output: "2001::5/128", }, { name:      "invalid CIDR", input:     "malformed", expectErr: true, }, { name:      "non-hex IP", input:     "nonhex/32", expectErr: true, }, { name:      "non-hex mask", input:     "01020000/badmask", expectErr: true, }, } for _, test := range tests { output, err := asciiCIDR(test.input) if test.expectErr { if err == nil { t.Errorf("case %s: unexpected non-error", test.name) } } else { </ins> if err != nil { <del> t.Errorf("unexpected error: %v", err) </del> <ins> t.Errorf("case %s: unexpected error: %v", test.name, err) </ins> } <del> if input != test.input { t.Errorf("expected: %s, saw: %s", test.input, input) </del> <ins> if output != test.output { t.Errorf("case %s: expected: %s, saw: %s", test.name, test.output, output) </ins> } } }