github.phpd.cn/cilium/cilium@v1.6.12/pkg/labels/cidr/cidr.go (about) 1 // Copyright 2018 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package cidr 16 17 import ( 18 "fmt" 19 "net" 20 "strings" 21 22 "github.com/cilium/cilium/pkg/labels" 23 ) 24 25 // maskedIPToLabelString is the base method for serializing an IP + prefix into 26 // a string that can be used for creating Labels and EndpointSelector objects. 27 // 28 // For IPv6 addresses, it converts ":" into "-" as EndpointSelectors don't 29 // support colons inside the name section of a label. 30 func maskedIPToLabelString(ip *net.IP, prefix int) string { 31 ipStr := ip.String() 32 ipNoColons := strings.Replace(ipStr, ":", "-", -1) 33 34 // EndpointSelector keys can't start or end with a "-", so insert a 35 // zero at the start or end if it would otherwise have a "-" at that 36 // position. 37 preZero := "" 38 postZero := "" 39 if ipNoColons[0] == '-' { 40 preZero = "0" 41 } 42 if ipNoColons[len(ipNoColons)-1] == '-' { 43 postZero = "0" 44 } 45 return fmt.Sprintf("%s:%s%s%s/%d", labels.LabelSourceCIDR, preZero, 46 ipNoColons, postZero, prefix) 47 } 48 49 // ipNetToLabel turns a CIDR into a Label object which can be used to create 50 // EndpointSelector objects. 51 func ipNetToLabel(cidr *net.IPNet) labels.Label { 52 ones, _ := cidr.Mask.Size() 53 lblStr := maskedIPToLabelString(&cidr.IP, ones) 54 return labels.ParseLabel(lblStr) 55 } 56 57 // IPStringToLabel parses a string and returns it as a CIDR label. 58 // 59 // If "IP" is not a valid IP address or CIDR Prefix, returns an error. 60 func IPStringToLabel(IP string) (labels.Label, error) { 61 _, parsedPrefix, err := net.ParseCIDR(IP) 62 if err != nil { 63 parsedIP := net.ParseIP(IP) 64 if parsedIP == nil { 65 return labels.Label{}, fmt.Errorf("Not an IP address or CIDR: %s", IP) 66 } 67 bits := net.IPv6len * 8 68 if parsedIP.To4() != nil { 69 bits = net.IPv4len * 8 70 } 71 parsedPrefix = &net.IPNet{IP: parsedIP, Mask: net.CIDRMask(bits, bits)} 72 } 73 74 return ipNetToLabel(parsedPrefix), nil 75 } 76 77 // maskedIPNetToLabelString masks the prefix/bits of the specified 'cidr' then 78 // turns the resulting CIDR into a label string for use elsewhere. 79 func maskedIPNetToLabelString(cidr *net.IPNet, prefix, bits int) string { 80 mask := net.CIDRMask(prefix, bits) 81 maskedIP := cidr.IP.Mask(mask) 82 return maskedIPToLabelString(&maskedIP, prefix) 83 } 84 85 // GetCIDRLabels turns a CIDR into a set of labels representing the cidr itself 86 // and all broader CIDRS which include the specified CIDR in them. For example: 87 // CIDR: 10.0.0.0/8 => 88 // "cidr:10.0.0.0/8", "cidr:10.0.0.0/7", "cidr:8.0.0.0/6", 89 // "cidr:8.0.0.0/5", "cidr:0.0.0.0/4, "cidr:0.0.0.0/3", 90 // "cidr:0.0.0.0/2", "cidr:0.0.0.0/1", "cidr:0.0.0.0/0" 91 // 92 // The identity reserved:world is always added as it includes any CIDR. 93 func GetCIDRLabels(cidr *net.IPNet) labels.Labels { 94 ones, bits := cidr.Mask.Size() 95 result := []string{} 96 97 // If ones is zero, then it's the default CIDR prefix /0 which should 98 // just be regarded as reserved:world. In all other cases, we need 99 // to generate the set of prefixes starting from the /0 up to the 100 // specified prefix length. 101 if ones > 0 { 102 for i := 0; i <= ones; i++ { 103 label := maskedIPNetToLabelString(cidr, i, bits) 104 result = append(result, label) 105 } 106 } 107 108 result = append(result, fmt.Sprintf("%s:%s", labels.LabelSourceReserved, labels.IDNameWorld)) 109 110 return labels.NewLabelsFromModel(result) 111 }