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

     1  // Copyright 2016-2019 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  	"github.com/cilium/cilium/pkg/identity"
    19  	"github.com/cilium/cilium/pkg/lock"
    20  	"github.com/cilium/cilium/pkg/logging/logfields"
    21  	"github.com/cilium/cilium/pkg/option"
    22  	"github.com/cilium/cilium/pkg/policy/trafficdirection"
    23  
    24  	"github.com/sirupsen/logrus"
    25  )
    26  
    27  var (
    28  	// localHostKey represents an ingress L3 allow from the local host.
    29  	localHostKey = Key{
    30  		Identity:         identity.ReservedIdentityHost.Uint32(),
    31  		TrafficDirection: trafficdirection.Ingress.Uint8(),
    32  	}
    33  )
    34  
    35  // MapState is a state of a policy map.
    36  type MapState map[Key]MapStateEntry
    37  
    38  // Key is the userspace representation of a policy key in BPF. It is
    39  // intentionally duplicated from pkg/maps/policymap to avoid pulling in the
    40  // BPF dependency to this package.
    41  type Key struct {
    42  	// Identity is the numeric identity to / from which traffic is allowed.
    43  	Identity uint32
    44  	// DestPort is the port at L4 to / from which traffic is allowed, in
    45  	// host-byte order.
    46  	DestPort uint16
    47  	// NextHdr is the protocol which is allowed.
    48  	Nexthdr uint8
    49  	// TrafficDirection indicates in which direction Identity is allowed
    50  	// communication (egress or ingress).
    51  	TrafficDirection uint8
    52  }
    53  
    54  // IsIngress returns true if the key refers to an ingress policy key
    55  func (k Key) IsIngress() bool {
    56  	return k.TrafficDirection == trafficdirection.Ingress.Uint8()
    57  }
    58  
    59  // IsEgress returns true if the key refers to an egress policy key
    60  func (k Key) IsEgress() bool {
    61  	return k.TrafficDirection == trafficdirection.Egress.Uint8()
    62  }
    63  
    64  // MapStateEntry is the configuration associated with a Key in a
    65  // MapState. This is a minimized version of policymap.PolicyEntry.
    66  type MapStateEntry struct {
    67  	// The proxy port, in host byte order.
    68  	// If 0 (default), there is no proxy redirection for the corresponding
    69  	// Key.
    70  	ProxyPort uint16
    71  }
    72  
    73  // DetermineAllowLocalhostIngress determines whether communication should be allowed
    74  // from the localhost. It inserts the Key corresponding to the localhost in
    75  // the desiredPolicyKeys if the localhost is allowed to communicate with the
    76  // endpoint.
    77  func (keys MapState) DetermineAllowLocalhostIngress(l4Policy *L4Policy) {
    78  
    79  	if option.Config.AlwaysAllowLocalhost() || (l4Policy != nil && l4Policy.HasRedirect()) {
    80  		keys[localHostKey] = MapStateEntry{}
    81  	}
    82  }
    83  
    84  // AllowAllIdentities translates all identities in selectorCache to their
    85  // corresponding Keys in the specified direction (ingress, egress) which allows
    86  // all at L3.
    87  func (keys MapState) AllowAllIdentities(ingress, egress bool) {
    88  	if ingress {
    89  		keyToAdd := Key{
    90  			Identity:         0,
    91  			DestPort:         0,
    92  			Nexthdr:          0,
    93  			TrafficDirection: trafficdirection.Ingress.Uint8(),
    94  		}
    95  		keys[keyToAdd] = MapStateEntry{}
    96  	}
    97  	if egress {
    98  		keyToAdd := Key{
    99  			Identity:         0,
   100  			DestPort:         0,
   101  			Nexthdr:          0,
   102  			TrafficDirection: trafficdirection.Egress.Uint8(),
   103  		}
   104  		keys[keyToAdd] = MapStateEntry{}
   105  	}
   106  }
   107  
   108  // MapChanges collects updates to the endpoint policy on the
   109  // granularity of individual mapstate key-value pairs for both adds
   110  // and deletes. 'mutex' must be held for any access.
   111  type MapChanges struct {
   112  	mutex   lock.Mutex
   113  	adds    MapState
   114  	deletes MapState
   115  }
   116  
   117  // AccumulateMapChanges accumulates the given changes to the
   118  // MapChanges, updating both maps for each add and delete, as
   119  // applicable.
   120  //
   121  // The caller is responsible for making sure the same identity is not
   122  // present in both 'adds' and 'deletes'.  Accross multiple calls we
   123  // maintain the adds and deletes within the MapChanges are disjoint in
   124  // cases where an identity is first added and then deleted, or first
   125  // deleted and then added.
   126  func (mc *MapChanges) AccumulateMapChanges(adds, deletes []identity.NumericIdentity,
   127  	port uint16, proto uint8, direction trafficdirection.TrafficDirection) {
   128  	key := Key{
   129  		// The actual identity is set in the loops below
   130  		Identity: 0,
   131  		// NOTE: Port is in host byte-order!
   132  		DestPort:         port,
   133  		Nexthdr:          proto,
   134  		TrafficDirection: direction.Uint8(),
   135  	}
   136  	value := MapStateEntry{
   137  		ProxyPort: 0, // Will be updated by the caller when applicable
   138  	}
   139  
   140  	if option.Config.Debug {
   141  		log.WithFields(logrus.Fields{
   142  			logfields.AddedPolicyID:    adds,
   143  			logfields.DeletedPolicyID:  deletes,
   144  			logfields.Port:             port,
   145  			logfields.Protocol:         proto,
   146  			logfields.TrafficDirection: direction,
   147  		}).Debug("AccumulateMapChanges")
   148  	}
   149  
   150  	mc.mutex.Lock()
   151  	if len(adds) > 0 {
   152  		if mc.adds == nil {
   153  			mc.adds = make(MapState)
   154  		}
   155  		for _, id := range adds {
   156  			key.Identity = id.Uint32()
   157  			mc.adds[key] = value
   158  			// Remove a potential previously deleted key
   159  			if mc.deletes != nil {
   160  				delete(mc.deletes, key)
   161  			}
   162  		}
   163  	}
   164  	if len(deletes) > 0 {
   165  		if mc.deletes == nil {
   166  			mc.deletes = make(MapState)
   167  		}
   168  		for _, id := range deletes {
   169  			key.Identity = id.Uint32()
   170  			mc.deletes[key] = value
   171  			// Remove a potential previously added key
   172  			if mc.adds != nil {
   173  				delete(mc.adds, key)
   174  			}
   175  		}
   176  	}
   177  	mc.mutex.Unlock()
   178  }
   179  
   180  // ConsumeMapChanges transfers the changes from MapChanges to the caller.
   181  // May return nil maps.
   182  func (mc *MapChanges) ConsumeMapChanges() (adds, deletes MapState) {
   183  	mc.mutex.Lock()
   184  	adds = mc.adds
   185  	mc.adds = nil
   186  	deletes = mc.deletes
   187  	mc.deletes = nil
   188  	mc.mutex.Unlock()
   189  	return adds, deletes
   190  }