github.com/castai/kvisor@v1.7.1-0.20240516114728-b3572a2607b5/cmd/agent/daemon/conntrack/conntrack_cilium_linux.go (about)

     1  //go:build linux
     2  
     3  package conntrack
     4  
     5  import (
     6  	"net/netip"
     7  	"path/filepath"
     8  
     9  	"github.com/castai/kvisor/pkg/logging"
    10  	"github.com/castai/kvisor/pkg/proc"
    11  	"github.com/cilium/cilium/pkg/bpf"
    12  	"github.com/cilium/cilium/pkg/defaults"
    13  	"github.com/cilium/cilium/pkg/loadbalancer"
    14  	"github.com/cilium/cilium/pkg/maps/ctmap"
    15  	"github.com/cilium/cilium/pkg/maps/lbmap"
    16  	"github.com/cilium/cilium/pkg/tuple"
    17  	"github.com/cilium/cilium/pkg/u8proto"
    18  )
    19  
    20  var (
    21  	ciliumCt4    *bpf.Map
    22  	ciliumCt6    *bpf.Map
    23  	backends4Map *bpf.Map
    24  	backends6Map *bpf.Map
    25  )
    26  
    27  // TODO(anjmao): Rewrite this with simple cilium/ebpf map lookups to not depend on cilium packages.
    28  func iniCiliumMaps(log *logging.Logger) bool {
    29  	var err error
    30  
    31  	ciliumCt4, err = bpf.OpenMap(proc.HostPath(filepath.Join(defaults.BPFFSRoot, defaults.TCGlobalsPath, ctmap.MapNameTCP4Global)), &ctmap.CtKey4Global{}, &ctmap.CtEntry{})
    32  	if err != nil {
    33  		log.Info(err.Error())
    34  		// We always expect v4 map. If it doesn't exist assume that cilium is not used.
    35  		return false
    36  	} else {
    37  		log.Infof("found cilium ebpf-map %s", ctmap.MapNameTCP4Global)
    38  	}
    39  
    40  	ciliumCt6, err = bpf.OpenMap(proc.HostPath(filepath.Join(defaults.BPFFSRoot, defaults.TCGlobalsPath, ctmap.MapNameTCP6Global)), &ctmap.CtKey6Global{}, &ctmap.CtEntry{})
    41  	if err != nil {
    42  		log.Warn(err.Error())
    43  	} else {
    44  		log.Infof("found cilium ebpf-map %s", ctmap.MapNameTCP6Global)
    45  	}
    46  	backends4Map, err = bpf.OpenMap(proc.HostPath(filepath.Join(defaults.BPFFSRoot, defaults.TCGlobalsPath, lbmap.Backend4MapV3Name)), &lbmap.Backend4KeyV3{}, &lbmap.Backend4ValueV3{})
    47  	if err != nil {
    48  		log.Warn(err.Error())
    49  	} else {
    50  		log.Infof("found cilium ebpf-map %s", lbmap.Backend4MapV3Name)
    51  	}
    52  
    53  	backends6Map, err = bpf.OpenMap(proc.HostPath(filepath.Join(defaults.BPFFSRoot, defaults.TCGlobalsPath, lbmap.Backend6MapV3Name)), &lbmap.Backend6KeyV3{}, &lbmap.Backend6ValueV3{})
    54  	if err != nil {
    55  		log.Warn(err.Error())
    56  	} else {
    57  		log.Infof("found cilium ebpf-map %s", lbmap.Backend6MapV3Name)
    58  	}
    59  
    60  	return true
    61  }
    62  
    63  func closeCilium() {
    64  	if ciliumCt4 != nil {
    65  		_ = ciliumCt4.Close()
    66  	}
    67  	if ciliumCt6 != nil {
    68  		_ = ciliumCt6.Close()
    69  	}
    70  	if backends4Map != nil {
    71  		_ = backends4Map.Close()
    72  	}
    73  	if backends6Map != nil {
    74  		_ = backends6Map.Close()
    75  	}
    76  }
    77  
    78  func lookupCiliumConntrackTable(src, dst netip.AddrPort) *netip.AddrPort {
    79  	if src.Addr().Is4() {
    80  		return lookupCilium4(src, dst)
    81  	}
    82  	if src.Addr().Is6() {
    83  		return lookupCilium6(src, dst)
    84  	}
    85  	return nil
    86  }
    87  
    88  func lookupCilium4(src, dst netip.AddrPort) *netip.AddrPort {
    89  	if ciliumCt4 == nil || backends4Map == nil {
    90  		return nil
    91  	}
    92  	key := &ctmap.CtKey4Global{
    93  		TupleKey4Global: tuple.TupleKey4Global{
    94  			TupleKey4: tuple.TupleKey4{
    95  				SourcePort: dst.Port(),
    96  				SourceAddr: src.Addr().As4(),
    97  				DestPort:   src.Port(),
    98  				DestAddr:   dst.Addr().As4(),
    99  				NextHeader: u8proto.TCP,
   100  				Flags:      ctmap.TUPLE_F_SERVICE,
   101  			},
   102  		},
   103  	}
   104  	v, err := ciliumCt4.Lookup(key.ToNetwork())
   105  	if err != nil || v == nil {
   106  		return nil
   107  	}
   108  	e := v.(*ctmap.CtEntry)
   109  
   110  	// https://github.com/cilium/cilium/blob/v1.13.0/bpf/lib/common.h#L819
   111  	// CtEntity.RxBytes stores `backend_id` if `e.Flags & TUPLE_F_SERVICE`
   112  	backendId := e.RxBytes
   113  	backendKey := lbmap.NewBackend4KeyV3(loadbalancer.BackendID(backendId))
   114  	b, err := backends4Map.Lookup(backendKey)
   115  	if err != nil || b == nil {
   116  		return nil
   117  	}
   118  	var backend lbmap.BackendValue
   119  	switch bv := b.(type) {
   120  	case *lbmap.Backend4Value:
   121  		backend = bv.ToHost()
   122  	case *lbmap.Backend4ValueV3:
   123  		backend = bv.ToHost()
   124  	default:
   125  		return nil
   126  	}
   127  	backendIP, _ := netip.AddrFromSlice(backend.GetAddress())
   128  	res := netip.AddrPortFrom(backendIP, backend.GetPort())
   129  	return &res
   130  }
   131  
   132  func lookupCilium6(src, dst netip.AddrPort) *netip.AddrPort {
   133  	if ciliumCt6 == nil || backends6Map == nil {
   134  		return nil
   135  	}
   136  	key := &ctmap.CtKey6Global{
   137  		TupleKey6Global: tuple.TupleKey6Global{
   138  			TupleKey6: tuple.TupleKey6{
   139  				SourcePort: dst.Port(),
   140  				SourceAddr: src.Addr().As16(),
   141  				DestPort:   src.Port(),
   142  				DestAddr:   dst.Addr().As16(),
   143  				NextHeader: u8proto.TCP,
   144  				Flags:      ctmap.TUPLE_F_SERVICE,
   145  			},
   146  		},
   147  	}
   148  	v, err := ciliumCt6.Lookup(key.ToNetwork())
   149  	if err != nil || v == nil {
   150  		return nil
   151  	}
   152  	e := v.(*ctmap.CtEntry)
   153  	backendId := e.RxBytes
   154  	backendKey := lbmap.NewBackend6KeyV3(loadbalancer.BackendID(backendId))
   155  	b, err := backends6Map.Lookup(backendKey)
   156  	if err != nil || b == nil {
   157  		return nil
   158  	}
   159  	var backend lbmap.BackendValue
   160  	switch bv := b.(type) {
   161  	case *lbmap.Backend6Value:
   162  		backend = bv.ToHost()
   163  	case *lbmap.Backend6ValueV3:
   164  		backend = bv.ToHost()
   165  	default:
   166  		return nil
   167  	}
   168  	backendIP, _ := netip.AddrFromSlice(backend.GetAddress())
   169  	res := netip.AddrPortFrom(backendIP, backend.GetPort())
   170  	return &res
   171  }