github.com/cilium/cilium@v1.16.2/pkg/labels/cidr_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package labels 5 6 import ( 7 "net/netip" 8 "testing" 9 10 "github.com/stretchr/testify/assert" 11 12 "github.com/cilium/cilium/pkg/option" 13 ) 14 15 func TestGetCIDRLabels(t *testing.T) { 16 // save global config and restore it at the end of the test 17 enableIPv4, enableIPv6 := option.Config.EnableIPv4, option.Config.EnableIPv6 18 t.Cleanup(func() { 19 option.Config.EnableIPv4, option.Config.EnableIPv6 = enableIPv4, enableIPv6 20 }) 21 22 for _, tc := range []struct { 23 name string 24 enableIPv4 bool 25 enableIPv6 bool 26 prefix netip.Prefix 27 expected LabelArray 28 }{ 29 { 30 name: "IPv4 /32 prefix", 31 enableIPv4: true, 32 enableIPv6: false, 33 prefix: netip.MustParsePrefix("192.0.2.3/32"), 34 expected: ParseLabelArray( 35 "cidr:192.0.2.3/32", 36 "reserved:world", 37 ), 38 }, 39 { 40 name: "IPv4 /24 prefix", 41 enableIPv4: true, 42 enableIPv6: false, 43 prefix: netip.MustParsePrefix("192.0.2.0/24"), 44 expected: ParseLabelArray( 45 "cidr:192.0.2.0/24", 46 "reserved:world", 47 ), 48 }, 49 { 50 name: "IPv4 /16 prefix", 51 enableIPv4: true, 52 enableIPv6: false, 53 prefix: netip.MustParsePrefix("10.0.0.0/16"), 54 expected: ParseLabelArray( 55 "cidr:10.0.0.0/16", 56 "reserved:world", 57 ), 58 }, 59 { 60 name: "IPv4 zero length prefix", 61 enableIPv4: true, 62 enableIPv6: false, 63 prefix: netip.MustParsePrefix("0.0.0.0/0"), 64 expected: ParseLabelArray( 65 "reserved:world", 66 ), 67 }, 68 { 69 name: "IPv6 /112 prefix", 70 enableIPv4: false, 71 enableIPv6: true, 72 prefix: netip.MustParsePrefix("2001:db8:cafe::cab:4:b0b:0/112"), 73 expected: ParseLabelArray( 74 // Note that we convert the colons in IPv6 addresses into dashes when 75 // translating into labels, because endpointSelectors don't support 76 // colons. 77 "cidr:2001-db8-cafe-0-cab-4-b0b-0/112", 78 "reserved:world", 79 ), 80 }, 81 { 82 name: "IPv6 /128 prefix", 83 enableIPv4: false, 84 enableIPv6: true, 85 prefix: netip.MustParsePrefix("2001:DB8::1/128"), 86 expected: ParseLabelArray( 87 "cidr:2001-db8--1/128", 88 "reserved:world", 89 ), 90 }, 91 { 92 name: "IPv4 /32 prefix in dual stack mode", 93 enableIPv4: true, 94 enableIPv6: true, 95 prefix: netip.MustParsePrefix("192.0.2.3/32"), 96 expected: ParseLabelArray( 97 "cidr:192.0.2.3/32", 98 "reserved:world-ipv4", 99 ), 100 }, 101 { 102 name: "IPv4 /24 prefix in dual stack mode", 103 enableIPv4: true, 104 enableIPv6: true, 105 prefix: netip.MustParsePrefix("192.0.2.0/24"), 106 expected: ParseLabelArray( 107 "cidr:192.0.2.0/24", 108 "reserved:world-ipv4", 109 ), 110 }, 111 { 112 name: "IPv4 /16 prefix in dual stack mode", 113 enableIPv4: true, 114 enableIPv6: true, 115 prefix: netip.MustParsePrefix("10.0.0.0/16"), 116 expected: ParseLabelArray( 117 "cidr:10.0.0.0/16", 118 "reserved:world-ipv4", 119 ), 120 }, 121 { 122 name: "IPv4 zero length prefix in dual stack mode", 123 enableIPv4: true, 124 enableIPv6: true, 125 prefix: netip.MustParsePrefix("0.0.0.0/0"), 126 expected: ParseLabelArray( 127 "reserved:world-ipv4", 128 ), 129 }, 130 { 131 name: "IPv6 /112 prefix in dual stack mode", 132 enableIPv4: true, 133 enableIPv6: true, 134 prefix: netip.MustParsePrefix("2001:db8:cafe::cab:4:b0b:0/112"), 135 expected: ParseLabelArray( 136 "cidr:2001-db8-cafe-0-cab-4-b0b-0/112", 137 "reserved:world-ipv6", 138 ), 139 }, 140 { 141 name: "IPv6 /128 prefix in dual stack mode", 142 enableIPv4: true, 143 enableIPv6: true, 144 prefix: netip.MustParsePrefix("2001:DB8::1/128"), 145 expected: ParseLabelArray( 146 "cidr:2001-db8--1/128", 147 "reserved:world-ipv6", 148 ), 149 }, 150 } { 151 t.Run(tc.name, func(t *testing.T) { 152 option.Config.EnableIPv4 = tc.enableIPv4 153 option.Config.EnableIPv6 = tc.enableIPv6 154 155 lbls := GetCIDRLabels(tc.prefix) 156 lblArray := lbls.LabelArray() 157 assert.ElementsMatch(t, lblArray, tc.expected) 158 }) 159 } 160 } 161 162 func TestIPStringToLabel(t *testing.T) { 163 for _, tc := range []struct { 164 ip string 165 label string 166 wantErr bool 167 }{ 168 { 169 ip: "0.0.0.0/0", 170 label: "cidr:0.0.0.0/0", 171 }, 172 { 173 ip: "192.0.2.3", 174 label: "cidr:192.0.2.3/32", 175 }, 176 { 177 ip: "192.0.2.3/32", 178 label: "cidr:192.0.2.3/32", 179 }, 180 { 181 ip: "192.0.2.3/24", 182 label: "cidr:192.0.2.0/24", 183 }, 184 { 185 ip: "192.0.2.0/24", 186 label: "cidr:192.0.2.0/24", 187 }, 188 { 189 ip: "::/0", 190 label: "cidr:0--0/0", 191 }, 192 { 193 ip: "fdff::ff", 194 label: "cidr:fdff--ff/128", 195 }, 196 { 197 ip: "f00d:42::ff/128", 198 label: "cidr:f00d-42--ff/128", 199 }, 200 { 201 ip: "f00d:42::ff/96", 202 label: "cidr:f00d-42--0/96", 203 }, 204 { 205 ip: "", 206 wantErr: true, 207 }, 208 { 209 ip: "foobar", 210 wantErr: true, 211 }, 212 } { 213 lbl, err := IPStringToLabel(tc.ip) 214 if !tc.wantErr { 215 assert.NoError(t, err) 216 assert.Equal(t, lbl.String(), tc.label) 217 } else { 218 assert.Error(t, err) 219 } 220 } 221 } 222 223 func BenchmarkIPStringToLabel(b *testing.B) { 224 for _, ip := range []string{ 225 "0.0.0.0/0", 226 "192.0.2.3", 227 "192.0.2.3/32", 228 "192.0.2.3/24", 229 "192.0.2.0/24", 230 "::/0", 231 "fdff::ff", 232 "f00d:42::ff/128", 233 "f00d:42::ff/96", 234 } { 235 b.Run(ip, func(b *testing.B) { 236 b.ReportAllocs() 237 for i := 0; i < b.N; i++ { 238 _, err := IPStringToLabel(ip) 239 if err != nil { 240 b.Fatal(err) 241 } 242 } 243 }) 244 } 245 } 246 247 func TestGetPrintableModel(t *testing.T) { 248 assert.Equal(t, 249 []string{"k8s:foo=bar"}, 250 NewLabelsFromModel([]string{ 251 "k8s:foo=bar", 252 }).GetPrintableModel(), 253 ) 254 255 assert.Equal(t, 256 []string{ 257 "k8s:foo=bar", 258 "reserved:remote-node", 259 }, 260 NewLabelsFromModel([]string{ 261 "k8s:foo=bar", 262 "reserved:remote-node", 263 }).GetPrintableModel(), 264 ) 265 266 assert.Equal(t, 267 []string{ 268 "k8s:foo=bar", 269 "reserved:remote-node", 270 }, 271 NewLabelsFromModel([]string{ 272 "k8s:foo=bar", 273 "reserved:remote-node", 274 }).GetPrintableModel(), 275 ) 276 277 // Test multiple CIDRs, as well as other labels 278 cl := NewLabelsFromModel([]string{ 279 "k8s:foo=bar", 280 "reserved:remote-node", 281 }) 282 cl.MergeLabels(GetCIDRLabels(netip.MustParsePrefix("10.0.0.6/32"))) 283 cl.MergeLabels(GetCIDRLabels(netip.MustParsePrefix("10.0.1.0/24"))) 284 cl.MergeLabels(GetCIDRLabels(netip.MustParsePrefix("192.168.0.0/24"))) 285 cl.MergeLabels(GetCIDRLabels(netip.MustParsePrefix("fc00:c111::5/128"))) 286 cl.MergeLabels(GetCIDRLabels(netip.MustParsePrefix("fc00:c112::0/64"))) 287 assert.Equal(t, 288 []string{ 289 "cidr:10.0.0.6/32", 290 "cidr:10.0.1.0/24", 291 "cidr:192.168.0.0/24", 292 "cidr:fc00:c111::5/128", 293 "cidr:fc00:c112::/64", 294 "k8s:foo=bar", 295 "reserved:remote-node", 296 "reserved:world-ipv4", 297 "reserved:world-ipv6", 298 }, 299 cl.GetPrintableModel(), 300 ) 301 } 302 303 func TestLabelToPrefix(t *testing.T) { 304 for _, pfx := range []string{ 305 "1.1.1.1/32", 306 "1.1.1.0/24", 307 "2001::4/128", 308 "2001::fffc/126", 309 "::/0", 310 "2001::/64", 311 "0.0.0.0/0", 312 } { 313 want, err := netip.ParsePrefix(pfx) 314 if err != nil { 315 t.Fatalf("failed to parse prefix %s: %v", pfx, err) 316 } 317 want = want.Masked() 318 319 label := maskedIPToLabel(want.Addr().String(), want.Bits()) 320 have, err := LabelToPrefix(label.Key) 321 if err != nil { 322 t.Fatalf("unexpected err: %v", err) 323 } 324 if have != want { 325 t.Fatalf("prefixes did not match: want %s, have %s, label %s", want, have, label.Key) 326 } 327 } 328 }