github.com/cilium/cilium@v1.16.2/pkg/policy/types/types.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Hubble
     3  
     4  package types
     5  
     6  import (
     7  	"math/bits"
     8  	"strconv"
     9  
    10  	"github.com/cilium/cilium/pkg/policy/trafficdirection"
    11  )
    12  
    13  // MapStatePrefixLen is the length, in bits, of the Key when converted
    14  // to binary minus the sizeof the identity field (which is not indexed).
    15  const MapStatePrefixLen = uint(32)
    16  
    17  // Key is the userspace representation of a policy key in BPF. It is
    18  // intentionally duplicated from pkg/maps/policymap to avoid pulling in the
    19  // BPF dependency to this package.
    20  type Key struct {
    21  	// Identity is the numeric identity to / from which traffic is allowed.
    22  	Identity uint32
    23  	// DestPort is the port at L4 to / from which traffic is allowed, in
    24  	// host-byte order.
    25  	DestPort uint16
    26  	// InvertedPortMask is the mask that should be applied to the DestPort to
    27  	// define a range of ports for the policy-key, encoded as the bitwise inverse
    28  	// of its true/useful value. This is done so that the default value of the
    29  	// Key is a full port mask (that is, "0" represents 0xffff), as that is
    30  	// the most likely value to be used. InvertedPortMask is also, conveniently,
    31  	// the number or ports on top of DestPort that define that range. That is
    32  	// the end port is equal to the DestPort added to the InvertedPortMask.
    33  	//
    34  	// It is **not** the prefix that is applied for the BPF key entries.
    35  	// That value is calculated in the maps/policymap package.
    36  	//
    37  	// For example:
    38  	// range 2-3 would be DestPort:2 and InvertedPortMask:0x1 (i.e 0xfffe)
    39  	// range 32768-49151 would be DestPort:32768 and InvertedPortMask:0x3fff (i.e. 0xc000)
    40  	InvertedPortMask uint16
    41  	// NextHdr is the protocol which is allowed.
    42  	Nexthdr uint8
    43  	// TrafficDirection indicates in which direction Identity is allowed
    44  	// communication (egress or ingress).
    45  	TrafficDirection uint8
    46  }
    47  
    48  // PortMask returns the bitwise mask that should be applied
    49  // to the DestPort.
    50  func (k Key) PortMask() uint16 {
    51  	return ^k.InvertedPortMask
    52  }
    53  
    54  // String returns a string representation of the Key
    55  func (k Key) String() string {
    56  	dPort := strconv.FormatUint(uint64(k.DestPort), 10)
    57  	if k.DestPort != 0 && k.InvertedPortMask != 0 {
    58  		dPort += "-" + strconv.FormatUint(uint64(k.DestPort+k.InvertedPortMask), 10)
    59  	}
    60  	return "Identity=" + strconv.FormatUint(uint64(k.Identity), 10) +
    61  		",DestPort=" + dPort +
    62  		",Nexthdr=" + strconv.FormatUint(uint64(k.Nexthdr), 10) +
    63  		",TrafficDirection=" + strconv.FormatUint(uint64(k.TrafficDirection), 10)
    64  }
    65  
    66  // IsIngress returns true if the key refers to an ingress policy key
    67  func (k Key) IsIngress() bool {
    68  	return k.TrafficDirection == trafficdirection.Ingress.Uint8()
    69  }
    70  
    71  // IsEgress returns true if the key refers to an egress policy key
    72  func (k Key) IsEgress() bool {
    73  	return k.TrafficDirection == trafficdirection.Egress.Uint8()
    74  }
    75  
    76  // EndPort returns the end-port of the Key based on the Mask.
    77  func (k Key) EndPort() uint16 {
    78  	return k.DestPort + k.InvertedPortMask
    79  }
    80  
    81  // PortProtoIsBroader returns true if the receiver Key has broader
    82  // port-protocol than the argument Key. That is a port-protocol
    83  // that covers the argument Key's port-protocol and is larger.
    84  // An equal port-protocol will return false.
    85  func (k Key) PortProtoIsBroader(c Key) bool {
    86  	if k.Nexthdr == 0 && c.Nexthdr != 0 {
    87  		return k.PortIsEqual(c) || k.PortIsBroader(c)
    88  	}
    89  	return k.Nexthdr == c.Nexthdr && k.PortIsBroader(c)
    90  }
    91  
    92  // PortProtoIsEqual returns true if the port-protocols of the
    93  // two keys are exactly equal.
    94  func (k Key) PortProtoIsEqual(c Key) bool {
    95  	return k.DestPort == c.DestPort &&
    96  		k.InvertedPortMask == c.InvertedPortMask &&
    97  		k.Nexthdr == c.Nexthdr
    98  }
    99  
   100  // PortIsBroader returns true if the receiver Key's
   101  // port range covers the argument Key's port range,
   102  // but returns false if they are equal.
   103  func (k Key) PortIsBroader(c Key) bool {
   104  	if k.DestPort == 0 && c.DestPort != 0 {
   105  		return true
   106  	}
   107  	if k.DestPort != 0 && c.DestPort == 0 {
   108  		return false
   109  	}
   110  	kEP := k.EndPort()
   111  	cEP := c.EndPort()
   112  	return k.DestPort <= c.DestPort && kEP >= cEP &&
   113  		// The port ranges cannot be exactly equal.
   114  		(k.DestPort != c.DestPort || kEP != cEP)
   115  }
   116  
   117  // PortIsEqual returns true if the port ranges
   118  // between the two keys are exactly equal.
   119  func (k Key) PortIsEqual(c Key) bool {
   120  	return k.DestPort == c.DestPort &&
   121  		k.InvertedPortMask == c.InvertedPortMask
   122  }
   123  
   124  // PrefixLength returns the prefix lenth of the key
   125  // for indexing it for the userspace cache (not the
   126  // BPF map or datapath).
   127  func (k Key) PrefixLength() uint {
   128  	keyPrefix := MapStatePrefixLen
   129  	portPrefix := uint(16)
   130  	if k.DestPort != 0 {
   131  		// It is not possible for k.InvertedPortMask
   132  		// to be incorrectly set, but even if
   133  		// it was the default value of "0" is
   134  		// what we want.
   135  		portPrefix = uint(bits.TrailingZeros16(k.PortMask()))
   136  	}
   137  	keyPrefix -= portPrefix
   138  	// If the port is fully wildcarded then
   139  	// we can also wildcard the protocol
   140  	// (if it is also wildcarded).
   141  	if portPrefix == 16 && k.Nexthdr == 0 {
   142  		keyPrefix -= 8
   143  	}
   144  	return keyPrefix
   145  }
   146  
   147  // CommonPrefix implements the CommonPrefix method for the
   148  // bitlpm.Key interface. Identity is not indexed and is instead,
   149  // saved as a simple map per TrafficDirection-Protocol-Port index
   150  // key.
   151  func (k Key) CommonPrefix(b Key) uint {
   152  	v := bits.LeadingZeros8(k.TrafficDirection ^ b.TrafficDirection)
   153  	if v != 8 {
   154  		return uint(v)
   155  	}
   156  	v += bits.LeadingZeros8(k.Nexthdr ^ b.Nexthdr)
   157  	if v != 16 {
   158  		return uint(v)
   159  	}
   160  	return uint(v + bits.LeadingZeros16(k.DestPort^b.DestPort))
   161  }
   162  
   163  // BitValueAt implements the BitValueAt method for the
   164  // bitlpm.Key interface.
   165  func (k Key) BitValueAt(i uint) uint8 {
   166  	if i < 8 {
   167  		return min(k.TrafficDirection&(1<<(7-i)), 1)
   168  	}
   169  	if i < 16 {
   170  		return min(k.Nexthdr&(1<<(7-(i-8))), 1)
   171  	}
   172  	return uint8(min(k.DestPort&(1<<(15-(i-16))), 1))
   173  }
   174  
   175  // Value implements the Value method for the
   176  // bitlpm.Key interface.
   177  func (k Key) Value() Key {
   178  	return k
   179  }
   180  
   181  type Keys map[Key]struct{}