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  }