github.com/imran-kn/cilium-fork@v1.6.9/pkg/policy/l3.go (about)

     1  // Copyright 2016-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 policy
    16  
    17  import (
    18  	"fmt"
    19  	"net"
    20  	"sort"
    21  	"strconv"
    22  
    23  	"github.com/cilium/cilium/api/v1/models"
    24  	"github.com/cilium/cilium/pkg/labels"
    25  	"github.com/cilium/cilium/pkg/policy/api"
    26  )
    27  
    28  // CIDRPolicyMapRule holds a L3 (CIDR) prefix and the rule labels that allow it.
    29  type CIDRPolicyMapRule struct {
    30  	Prefix           net.IPNet
    31  	DerivedFromRules labels.LabelArrayList
    32  }
    33  
    34  // CIDRPolicyMap is a list of CIDR filters indexable by address/prefixlen
    35  // key format: "address/prefixlen", e.g., "10.1.1.0/24"
    36  // Each prefix struct also includes the rule labels that allowed it.
    37  //
    38  // CIDRPolicyMap does no locking internally, so the user is responsible for synchronizing
    39  // between multiple threads when applicable.
    40  type CIDRPolicyMap struct {
    41  	Map map[string]*CIDRPolicyMapRule // Allowed L3 (CIDR) prefixes
    42  
    43  	IPv6PrefixCount map[int]int // Count of IPv6 prefixes in 'Map' indexed by prefix length
    44  	IPv4PrefixCount map[int]int // Count of IPv4 prefixes in 'Map' indexed by prefix length
    45  }
    46  
    47  // GetDefaultPrefixLengths returns the set of prefix lengths for handling
    48  // CIDRs that are unconditionally mapped to identities, ie for the reserved
    49  // identities 'host', 'world'.
    50  func GetDefaultPrefixLengths() (s6 []int, s4 []int) {
    51  	// These *must* be in the order of longest prefix to shortest, as the
    52  	// LPM implementation on older kernels depends on this ordering.
    53  	s6 = []int{net.IPv6len * 8, 0}
    54  	s4 = []int{net.IPv4len * 8, 0}
    55  	return
    56  }
    57  
    58  // Insert places 'cidr' and its corresponding rule labels into map 'm'. Returns
    59  // `1` if `cidr` is added to the map, `0` otherwise.
    60  func (m *CIDRPolicyMap) Insert(cidr string, ruleLabels labels.LabelArray) int {
    61  	_, ipnet, err := net.ParseCIDR(cidr)
    62  	if err != nil {
    63  		var mask net.IPMask
    64  		ip := net.ParseIP(cidr)
    65  		// Use default CIDR mask for the address if the bits in the address
    66  		// after the mask are all zeroes.
    67  		ip4 := ip.To4()
    68  		if ip4 == nil {
    69  			mask = net.CIDRMask(128, 128)
    70  		} else { // IPv4
    71  			ip = ip4
    72  			mask = ip.DefaultMask() // IP address class based mask (/8, /16, or /24)
    73  			if !ip.Equal(ip.Mask(mask)) {
    74  				// IPv4 with non-zeroes after the subnetwork, use full mask.
    75  				mask = net.CIDRMask(32, 32)
    76  			}
    77  		}
    78  		ipnet = &net.IPNet{IP: ip, Mask: mask}
    79  	}
    80  
    81  	ones, _ := ipnet.Mask.Size()
    82  
    83  	key := ipnet.IP.String() + "/" + strconv.Itoa(ones)
    84  	if _, found := m.Map[key]; !found {
    85  		m.Map[key] = &CIDRPolicyMapRule{Prefix: *ipnet, DerivedFromRules: labels.LabelArrayList{ruleLabels}}
    86  		if ipnet.IP.To4() == nil {
    87  			m.IPv6PrefixCount[ones]++
    88  		} else {
    89  			m.IPv4PrefixCount[ones]++
    90  		}
    91  		return 1
    92  	} else {
    93  		m.Map[key].DerivedFromRules = append(m.Map[key].DerivedFromRules, ruleLabels)
    94  	}
    95  
    96  	return 0
    97  }
    98  
    99  // CIDRPolicy contains L3 (CIDR) policy maps for ingress.
   100  //
   101  // This is not used for map entry generation; It has two uses:
   102  // * On older kernels, generate the set of CIDR prefix lengths that
   103  //   are necessary to implement an LPM
   104  // * Reflect desired state of the CIDR policy in the API.
   105  type CIDRPolicy struct {
   106  	Ingress CIDRPolicyMap
   107  	Egress  CIDRPolicyMap
   108  }
   109  
   110  // NewCIDRPolicy creates a new CIDRPolicy.
   111  func NewCIDRPolicy() (policy *CIDRPolicy) {
   112  	policy = &CIDRPolicy{
   113  		Ingress: CIDRPolicyMap{
   114  			Map:             make(map[string]*CIDRPolicyMapRule),
   115  			IPv6PrefixCount: make(map[int]int),
   116  			IPv4PrefixCount: make(map[int]int),
   117  		},
   118  		Egress: CIDRPolicyMap{
   119  			Map:             make(map[string]*CIDRPolicyMapRule),
   120  			IPv6PrefixCount: make(map[int]int),
   121  			IPv4PrefixCount: make(map[int]int),
   122  		},
   123  	}
   124  	// Add a default reference to the default {host, cluster, world} prefix
   125  	// to ensure that ToBPFData() always serializes these lengths for LPM.
   126  	s6, s4 := GetDefaultPrefixLengths()
   127  	for _, i := range s6 {
   128  		policy.Egress.IPv6PrefixCount[i] = 0
   129  		policy.Ingress.IPv6PrefixCount[i] = 0
   130  	}
   131  	for _, i := range s4 {
   132  		policy.Egress.IPv4PrefixCount[i] = 0
   133  		policy.Ingress.IPv4PrefixCount[i] = 0
   134  	}
   135  	return
   136  }
   137  
   138  // ToBPFData converts the ingress and egress cidr map into int slices 's6'
   139  // (IPv6) and 's4' (IPv4), formatted for insertion into bpf program as prefix
   140  // lengths.
   141  //
   142  // Note that this will always include the CIDR prefix lengths for host (eg /32
   143  // for host), cluster (typically /8 or /64), and world (/0).
   144  //
   145  // FIXME: Move this function out of policy into a datapath specific package
   146  func (cp *CIDRPolicy) ToBPFData() (s6, s4 []int) {
   147  	s6duplicates, s4duplicates := map[int]bool{}, map[int]bool{}
   148  
   149  	for _, m := range []CIDRPolicyMap{cp.Ingress, cp.Egress} {
   150  		for p := range m.IPv6PrefixCount {
   151  			if _, ok := s6duplicates[p]; !ok {
   152  				s6 = append(s6, p)
   153  				s6duplicates[p] = true
   154  			}
   155  		}
   156  		for p := range m.IPv4PrefixCount {
   157  			if _, ok := s4duplicates[p]; !ok {
   158  				s4 = append(s4, p)
   159  				s4duplicates[p] = true
   160  			}
   161  		}
   162  	}
   163  
   164  	// The datapath expects longest-to-shortest prefixes so that it can
   165  	// clear progressively more bits with a single load of the address.
   166  	sort.Sort(sort.Reverse(sort.IntSlice(s6)))
   167  	sort.Sort(sort.Reverse(sort.IntSlice(s4)))
   168  	return
   169  }
   170  
   171  // GetModel returns the API model representation of the CIDRPolicy.
   172  func (cp *CIDRPolicy) GetModel() *models.CIDRPolicy {
   173  	if cp == nil {
   174  		return nil
   175  	}
   176  
   177  	ingress := []*models.PolicyRule{}
   178  	for _, v := range cp.Ingress.Map {
   179  		ingress = append(ingress, &models.PolicyRule{
   180  			Rule:             v.Prefix.String(),
   181  			DerivedFromRules: v.DerivedFromRules.GetModel(),
   182  		})
   183  	}
   184  
   185  	egress := []*models.PolicyRule{}
   186  	for _, v := range cp.Egress.Map {
   187  		egress = append(egress, &models.PolicyRule{
   188  			Rule:             v.Prefix.String(),
   189  			DerivedFromRules: v.DerivedFromRules.GetModel(),
   190  		})
   191  	}
   192  
   193  	return &models.CIDRPolicy{
   194  		Ingress: ingress,
   195  		Egress:  egress,
   196  	}
   197  }
   198  
   199  // Validate returns error if the CIDR policy might lead to code generation failure
   200  func (cp *CIDRPolicy) Validate() error {
   201  	if cp == nil {
   202  		return nil
   203  	}
   204  	if l := len(cp.Ingress.IPv6PrefixCount); l > api.MaxCIDRPrefixLengths {
   205  		return fmt.Errorf("too many ingress CIDR prefix lengths %d/%d", l, api.MaxCIDRPrefixLengths)
   206  	}
   207  	return nil
   208  }