github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/pkg/maps/ctmap/types.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 ctmap
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"unsafe"
    21  
    22  	"github.com/cilium/cilium/pkg/bpf"
    23  	"github.com/cilium/cilium/pkg/byteorder"
    24  	"github.com/cilium/cilium/pkg/tuple"
    25  )
    26  
    27  const (
    28  	// MapTypeIPv4TCPLocal and friends are MapTypes which correspond to a
    29  	// combination of the following attributes:
    30  	// * IPv4 or IPv6;
    31  	// * TCP or non-TCP (shortened to Any)
    32  	// * Local (endpoint-specific) or global (endpoint-oblivious).
    33  	MapTypeIPv4TCPLocal = iota
    34  	MapTypeIPv6TCPLocal
    35  	MapTypeIPv4TCPGlobal
    36  	MapTypeIPv6TCPGlobal
    37  	MapTypeIPv4AnyLocal
    38  	MapTypeIPv6AnyLocal
    39  	MapTypeIPv4AnyGlobal
    40  	MapTypeIPv6AnyGlobal
    41  	MapTypeMax
    42  )
    43  
    44  // MapType is a type of connection tracking map.
    45  type MapType int
    46  
    47  // String renders the map type into a user-readable string.
    48  func (m MapType) String() string {
    49  	switch m {
    50  	case MapTypeIPv4TCPLocal:
    51  		return "Local IPv4 TCP CT map"
    52  	case MapTypeIPv6TCPLocal:
    53  		return "Local IPv6 TCP CT map"
    54  	case MapTypeIPv4TCPGlobal:
    55  		return "Global IPv4 TCP CT map"
    56  	case MapTypeIPv6TCPGlobal:
    57  		return "Global IPv6 TCP CT map"
    58  	case MapTypeIPv4AnyLocal:
    59  		return "Local IPv4 non-TCP CT map"
    60  	case MapTypeIPv6AnyLocal:
    61  		return "Local IPv6 non-TCP CT map"
    62  	case MapTypeIPv4AnyGlobal:
    63  		return "Global IPv4 non-TCP CT map"
    64  	case MapTypeIPv6AnyGlobal:
    65  		return "Global IPv6 non-TCP CT map"
    66  	}
    67  	return fmt.Sprintf("Unknown (%d)", int(m))
    68  }
    69  
    70  func (m MapType) isIPv4() bool {
    71  	switch m {
    72  	case MapTypeIPv4TCPLocal, MapTypeIPv4TCPGlobal, MapTypeIPv4AnyLocal, MapTypeIPv4AnyGlobal:
    73  		return true
    74  	}
    75  	return false
    76  }
    77  
    78  func (m MapType) isIPv6() bool {
    79  	switch m {
    80  	case MapTypeIPv6TCPLocal, MapTypeIPv6TCPGlobal, MapTypeIPv6AnyLocal, MapTypeIPv6AnyGlobal:
    81  		return true
    82  	}
    83  	return false
    84  }
    85  
    86  func (m MapType) isLocal() bool {
    87  	switch m {
    88  	case MapTypeIPv4TCPLocal, MapTypeIPv6TCPLocal, MapTypeIPv4AnyLocal, MapTypeIPv6AnyLocal:
    89  		return true
    90  	}
    91  	return false
    92  }
    93  
    94  func (m MapType) isGlobal() bool {
    95  	switch m {
    96  	case MapTypeIPv4TCPGlobal, MapTypeIPv6TCPGlobal, MapTypeIPv4AnyGlobal, MapTypeIPv6AnyGlobal:
    97  		return true
    98  	}
    99  	return false
   100  }
   101  
   102  func (m MapType) isTCP() bool {
   103  	switch m {
   104  	case MapTypeIPv4TCPLocal, MapTypeIPv6TCPLocal, MapTypeIPv4TCPGlobal, MapTypeIPv6TCPGlobal:
   105  		return true
   106  	}
   107  	return false
   108  }
   109  
   110  type CtKey interface {
   111  	bpf.MapKey
   112  
   113  	// ToNetwork converts fields to network byte order.
   114  	ToNetwork() CtKey
   115  
   116  	// ToHost converts fields to host byte order.
   117  	ToHost() CtKey
   118  
   119  	// Dump contents of key to buffer. Returns true if successful.
   120  	Dump(buffer *bytes.Buffer, reverse bool) bool
   121  
   122  	// GetFlags flags containing the direction of the CtKey.
   123  	GetFlags() uint8
   124  
   125  	GetTupleKey() tuple.TupleKey
   126  }
   127  
   128  // CtKey4 is needed to provide CtEntry type to Lookup values
   129  // +k8s:deepcopy-gen=true
   130  // +k8s:deepcopy-gen:interfaces=github.com/cilium/cilium/pkg/bpf.MapKey
   131  type CtKey4 struct {
   132  	tuple.TupleKey4
   133  }
   134  
   135  // NewValue creates a new bpf.MapValue.
   136  func (k *CtKey4) NewValue() bpf.MapValue { return &CtEntry{} }
   137  
   138  // ToNetwork converts CtKey4 ports to network byte order.
   139  func (k *CtKey4) ToNetwork() CtKey {
   140  	n := *k
   141  	n.SourcePort = byteorder.HostToNetwork(n.SourcePort).(uint16)
   142  	n.DestPort = byteorder.HostToNetwork(n.DestPort).(uint16)
   143  	return &n
   144  }
   145  
   146  // ToHost converts CtKey ports to host byte order.
   147  func (k *CtKey4) ToHost() CtKey {
   148  	n := *k
   149  	n.SourcePort = byteorder.NetworkToHost(n.SourcePort).(uint16)
   150  	n.DestPort = byteorder.NetworkToHost(n.DestPort).(uint16)
   151  	return &n
   152  }
   153  
   154  // GetFlags returns the tuple's flags.
   155  func (k *CtKey4) GetFlags() uint8 {
   156  	return k.Flags
   157  }
   158  
   159  func (k *CtKey4) String() string {
   160  	return fmt.Sprintf("%s:%d, %d, %d, %d", k.DestAddr, k.SourcePort, k.DestPort, k.NextHeader, k.Flags)
   161  }
   162  
   163  // GetKeyPtr returns the unsafe.Pointer for k.
   164  func (k *CtKey4) GetKeyPtr() unsafe.Pointer { return unsafe.Pointer(k) }
   165  
   166  // Dump writes the contents of key to buffer and returns true if the value for
   167  // next header in the key is nonzero.
   168  func (k *CtKey4) Dump(buffer *bytes.Buffer, reverse bool) bool {
   169  	var addrDest string
   170  
   171  	if k.NextHeader == 0 {
   172  		return false
   173  	}
   174  
   175  	// Addresses swapped, see issue #5848
   176  	if reverse {
   177  		addrDest = k.SourceAddr.IP().String()
   178  	} else {
   179  		addrDest = k.DestAddr.IP().String()
   180  	}
   181  
   182  	if k.Flags&TUPLE_F_IN != 0 {
   183  		buffer.WriteString(fmt.Sprintf("%s IN %s %d:%d ",
   184  			k.NextHeader.String(), addrDest, k.SourcePort,
   185  			k.DestPort),
   186  		)
   187  	} else {
   188  		buffer.WriteString(fmt.Sprintf("%s OUT %s %d:%d ",
   189  			k.NextHeader.String(), addrDest, k.DestPort,
   190  			k.SourcePort),
   191  		)
   192  	}
   193  
   194  	if k.Flags&TUPLE_F_RELATED != 0 {
   195  		buffer.WriteString("related ")
   196  	}
   197  
   198  	if k.Flags&TUPLE_F_SERVICE != 0 {
   199  		buffer.WriteString("service ")
   200  	}
   201  
   202  	return true
   203  }
   204  
   205  func (k *CtKey4) GetTupleKey() tuple.TupleKey {
   206  	return &k.TupleKey4
   207  }
   208  
   209  // CtKey4Global is needed to provide CtEntry type to Lookup values
   210  // +k8s:deepcopy-gen=true
   211  // +k8s:deepcopy-gen:interfaces=github.com/cilium/cilium/pkg/bpf.MapKey
   212  type CtKey4Global struct {
   213  	tuple.TupleKey4Global
   214  }
   215  
   216  // NewValue creates a new bpf.MapValue.
   217  func (k *CtKey4Global) NewValue() bpf.MapValue { return &CtEntry{} }
   218  
   219  // ToNetwork converts ports to network byte order.
   220  //
   221  // This is necessary to prevent callers from implicitly converting
   222  // the CtKey4Global type here into a local key type in the nested
   223  // TupleKey4Global field.
   224  func (k *CtKey4Global) ToNetwork() CtKey {
   225  	return &CtKey4Global{
   226  		TupleKey4Global: *k.TupleKey4Global.ToNetwork().(*tuple.TupleKey4Global),
   227  	}
   228  }
   229  
   230  // ToHost converts ports to host byte order.
   231  //
   232  // This is necessary to prevent callers from implicitly converting
   233  // the CtKey4Global type here into a local key type in the nested
   234  // TupleKey4Global field.
   235  func (k *CtKey4Global) ToHost() CtKey {
   236  	return &CtKey4Global{
   237  		TupleKey4Global: *k.TupleKey4Global.ToHost().(*tuple.TupleKey4Global),
   238  	}
   239  }
   240  
   241  // GetFlags returns the tuple's flags.
   242  func (k *CtKey4Global) GetFlags() uint8 {
   243  	return k.Flags
   244  }
   245  
   246  func (k *CtKey4Global) String() string {
   247  	return fmt.Sprintf("%s:%d --> %s:%d, %d, %d", k.SourceAddr, k.SourcePort, k.DestAddr, k.DestPort, k.NextHeader, k.Flags)
   248  }
   249  
   250  // GetKeyPtr returns the unsafe.Pointer for k.
   251  func (k *CtKey4Global) GetKeyPtr() unsafe.Pointer { return unsafe.Pointer(k) }
   252  
   253  // Dump writes the contents of key to buffer and returns true if the
   254  // value for next header in the key is nonzero.
   255  func (k *CtKey4Global) Dump(buffer *bytes.Buffer, reverse bool) bool {
   256  	var addrSource, addrDest string
   257  
   258  	if k.NextHeader == 0 {
   259  		return false
   260  	}
   261  
   262  	// Addresses swapped, see issue #5848
   263  	if reverse {
   264  		addrSource = k.DestAddr.IP().String()
   265  		addrDest = k.SourceAddr.IP().String()
   266  	} else {
   267  		addrSource = k.SourceAddr.IP().String()
   268  		addrDest = k.DestAddr.IP().String()
   269  	}
   270  
   271  	if k.Flags&TUPLE_F_IN != 0 {
   272  		buffer.WriteString(fmt.Sprintf("%s IN %s:%d -> %s:%d ",
   273  			k.NextHeader.String(), addrSource, k.SourcePort,
   274  			addrDest, k.DestPort),
   275  		)
   276  	} else {
   277  		buffer.WriteString(fmt.Sprintf("%s OUT %s:%d -> %s:%d ",
   278  			k.NextHeader.String(), addrSource, k.SourcePort,
   279  			addrDest, k.DestPort),
   280  		)
   281  	}
   282  
   283  	if k.Flags&TUPLE_F_RELATED != 0 {
   284  		buffer.WriteString("related ")
   285  	}
   286  
   287  	if k.Flags&TUPLE_F_SERVICE != 0 {
   288  		buffer.WriteString("service ")
   289  	}
   290  
   291  	return true
   292  }
   293  
   294  func (k *CtKey4Global) GetTupleKey() tuple.TupleKey {
   295  	return &k.TupleKey4Global
   296  }
   297  
   298  // CtKey6 is needed to provide CtEntry type to Lookup values
   299  // +k8s:deepcopy-gen=true
   300  // +k8s:deepcopy-gen:interfaces=github.com/cilium/cilium/pkg/bpf.MapKey
   301  type CtKey6 struct {
   302  	tuple.TupleKey6
   303  }
   304  
   305  // NewValue creates a new bpf.MapValue.
   306  func (k *CtKey6) NewValue() bpf.MapValue { return &CtEntry{} }
   307  
   308  // ToNetwork converts CtKey6 ports to network byte order.
   309  func (k *CtKey6) ToNetwork() CtKey {
   310  	return &CtKey6{
   311  		TupleKey6: *k.TupleKey6.ToNetwork().(*tuple.TupleKey6),
   312  	}
   313  }
   314  
   315  // ToHost converts CtKey ports to host byte order.
   316  func (k *CtKey6) ToHost() CtKey {
   317  	return &CtKey6{
   318  		TupleKey6: *k.TupleKey6.ToHost().(*tuple.TupleKey6),
   319  	}
   320  }
   321  
   322  // GetFlags returns the tuple's flags.
   323  func (k *CtKey6) GetFlags() uint8 {
   324  	return k.Flags
   325  }
   326  
   327  func (k *CtKey6) String() string {
   328  	return fmt.Sprintf("[%s]:%d, %d, %d, %d", k.DestAddr, k.SourcePort, k.DestPort, k.NextHeader, k.Flags)
   329  }
   330  
   331  // GetKeyPtr returns the unsafe.Pointer for k.
   332  func (k *CtKey6) GetKeyPtr() unsafe.Pointer { return unsafe.Pointer(k) }
   333  
   334  // Dump writes the contents of key to buffer and returns true if the value for
   335  // next header in the key is nonzero.
   336  func (k *CtKey6) Dump(buffer *bytes.Buffer, reverse bool) bool {
   337  	var addrDest string
   338  
   339  	if k.NextHeader == 0 {
   340  		return false
   341  	}
   342  
   343  	// Addresses swapped, see issue #5848
   344  	if reverse {
   345  		addrDest = k.SourceAddr.IP().String()
   346  	} else {
   347  		addrDest = k.DestAddr.IP().String()
   348  	}
   349  
   350  	if k.Flags&TUPLE_F_IN != 0 {
   351  		buffer.WriteString(fmt.Sprintf("%s IN %s %d:%d ",
   352  			k.NextHeader.String(), addrDest, k.SourcePort,
   353  			k.DestPort),
   354  		)
   355  	} else {
   356  		buffer.WriteString(fmt.Sprintf("%s OUT %s %d:%d ",
   357  			k.NextHeader.String(), addrDest, k.DestPort,
   358  			k.SourcePort),
   359  		)
   360  	}
   361  
   362  	if k.Flags&TUPLE_F_RELATED != 0 {
   363  		buffer.WriteString("related ")
   364  	}
   365  
   366  	if k.Flags&TUPLE_F_SERVICE != 0 {
   367  		buffer.WriteString("service ")
   368  	}
   369  
   370  	return true
   371  }
   372  
   373  func (k *CtKey6) GetTupleKey() tuple.TupleKey {
   374  	return &k.TupleKey6
   375  }
   376  
   377  // CtKey6Global is needed to provide CtEntry type to Lookup values
   378  // +k8s:deepcopy-gen=true
   379  // +k8s:deepcopy-gen:interfaces=github.com/cilium/cilium/pkg/bpf.MapKey
   380  type CtKey6Global struct {
   381  	tuple.TupleKey6Global
   382  }
   383  
   384  // NewValue creates a new bpf.MapValue.
   385  func (k *CtKey6Global) NewValue() bpf.MapValue { return &CtEntry{} }
   386  
   387  // ToNetwork converts ports to network byte order.
   388  //
   389  // This is necessary to prevent callers from implicitly converting
   390  // the CtKey6Global type here into a local key type in the nested
   391  // TupleKey6Global field.
   392  func (k *CtKey6Global) ToNetwork() CtKey {
   393  	return &CtKey6Global{
   394  		TupleKey6Global: *k.TupleKey6Global.ToNetwork().(*tuple.TupleKey6Global),
   395  	}
   396  }
   397  
   398  // ToHost converts ports to host byte order.
   399  //
   400  // This is necessary to prevent callers from implicitly converting
   401  // the CtKey6Global type here into a local key type in the nested
   402  // TupleKey6Global field.
   403  func (k *CtKey6Global) ToHost() CtKey {
   404  	return &CtKey6Global{
   405  		TupleKey6Global: *k.TupleKey6Global.ToHost().(*tuple.TupleKey6Global),
   406  	}
   407  }
   408  
   409  // GetFlags returns the tuple's flags.
   410  func (k *CtKey6Global) GetFlags() uint8 {
   411  	return k.Flags
   412  }
   413  
   414  func (k *CtKey6Global) String() string {
   415  	return fmt.Sprintf("[%s]:%d --> [%s]:%d, %d, %d", k.SourceAddr, k.SourcePort, k.DestAddr, k.DestPort, k.NextHeader, k.Flags)
   416  }
   417  
   418  // GetKeyPtr returns the unsafe.Pointer for k.
   419  func (k *CtKey6Global) GetKeyPtr() unsafe.Pointer { return unsafe.Pointer(k) }
   420  
   421  // Dump writes the contents of key to buffer and returns true if the
   422  // value for next header in the key is nonzero.
   423  func (k *CtKey6Global) Dump(buffer *bytes.Buffer, reverse bool) bool {
   424  	var addrSource, addrDest string
   425  
   426  	if k.NextHeader == 0 {
   427  		return false
   428  	}
   429  
   430  	// Addresses swapped, see issue #5848
   431  	if reverse {
   432  		addrSource = k.DestAddr.IP().String()
   433  		addrDest = k.SourceAddr.IP().String()
   434  	} else {
   435  		addrSource = k.SourceAddr.IP().String()
   436  		addrDest = k.DestAddr.IP().String()
   437  	}
   438  
   439  	if k.Flags&TUPLE_F_IN != 0 {
   440  		buffer.WriteString(fmt.Sprintf("%s IN %s:%d -> %s:%d ",
   441  			k.NextHeader.String(), addrSource, k.SourcePort,
   442  			addrDest, k.DestPort),
   443  		)
   444  	} else {
   445  		buffer.WriteString(fmt.Sprintf("%s OUT %s:%d -> %s:%d ",
   446  			k.NextHeader.String(), addrSource, k.SourcePort,
   447  			addrDest, k.DestPort),
   448  		)
   449  	}
   450  
   451  	if k.Flags&TUPLE_F_RELATED != 0 {
   452  		buffer.WriteString("related ")
   453  	}
   454  
   455  	if k.Flags&TUPLE_F_SERVICE != 0 {
   456  		buffer.WriteString("service ")
   457  	}
   458  
   459  	return true
   460  }
   461  
   462  func (k *CtKey6Global) GetTupleKey() tuple.TupleKey {
   463  	return &k.TupleKey6Global
   464  }
   465  
   466  // CtEntry represents an entry in the connection tracking table.
   467  // +k8s:deepcopy-gen=true
   468  // +k8s:deepcopy-gen:interfaces=github.com/cilium/cilium/pkg/bpf.MapValue
   469  type CtEntry struct {
   470  	RxPackets uint64 `align:"rx_packets"`
   471  	RxBytes   uint64 `align:"rx_bytes"`
   472  	TxPackets uint64 `align:"tx_packets"`
   473  	TxBytes   uint64 `align:"tx_bytes"`
   474  	Lifetime  uint32 `align:"lifetime"`
   475  	Flags     uint16 `align:"rx_closing"`
   476  	// RevNAT is in network byte order
   477  	RevNAT           uint16 `align:"rev_nat_index"`
   478  	_                uint16 `align:"backend_id"`
   479  	TxFlagsSeen      uint8  `align:"tx_flags_seen"`
   480  	RxFlagsSeen      uint8  `align:"rx_flags_seen"`
   481  	SourceSecurityID uint32 `align:"src_sec_id"`
   482  	LastTxReport     uint32 `align:"last_tx_report"`
   483  	LastRxReport     uint32 `align:"last_rx_report"`
   484  }
   485  
   486  // GetValuePtr returns the unsafe.Pointer for s.
   487  func (c *CtEntry) GetValuePtr() unsafe.Pointer { return unsafe.Pointer(c) }
   488  
   489  const (
   490  	RxClosing  = 1 << 0
   491  	TxClosing  = 1 << 1
   492  	Nat64      = 1 << 2
   493  	LBLoopback = 1 << 3
   494  	SeenNonSyn = 1 << 4
   495  	NodePort   = 1 << 5
   496  )
   497  
   498  func (c *CtEntry) flagsString() string {
   499  	var buffer bytes.Buffer
   500  
   501  	buffer.WriteString(fmt.Sprintf("Flags=%#04x [ ", c.Flags))
   502  	if (c.Flags & RxClosing) != 0 {
   503  		buffer.WriteString("RxClosing ")
   504  	}
   505  	if (c.Flags & TxClosing) != 0 {
   506  		buffer.WriteString("TxClosing ")
   507  	}
   508  	if (c.Flags & Nat64) != 0 {
   509  		buffer.WriteString("Nat64 ")
   510  	}
   511  	if (c.Flags & LBLoopback) != 0 {
   512  		buffer.WriteString("LBLoopback ")
   513  	}
   514  	if (c.Flags & SeenNonSyn) != 0 {
   515  		buffer.WriteString("SeenNonSyn ")
   516  	}
   517  	if (c.Flags & NodePort) != 0 {
   518  		buffer.WriteString("NodePort ")
   519  	}
   520  	buffer.WriteString("]")
   521  	return buffer.String()
   522  }
   523  
   524  // String returns the readable format
   525  func (c *CtEntry) String() string {
   526  	return fmt.Sprintf("expires=%d RxPackets=%d RxBytes=%d RxFlagsSeen=%#02x LastRxReport=%d TxPackets=%d TxBytes=%d TxFlagsSeen=%#02x LastTxReport=%d %s RevNAT=%d SourceSecurityID=%d \n",
   527  		c.Lifetime,
   528  		c.RxPackets,
   529  		c.RxBytes,
   530  		c.RxFlagsSeen,
   531  		c.LastRxReport,
   532  		c.TxPackets,
   533  		c.TxBytes,
   534  		c.TxFlagsSeen,
   535  		c.LastTxReport,
   536  		c.flagsString(),
   537  		byteorder.NetworkToHost(c.RevNAT),
   538  		c.SourceSecurityID)
   539  }