diff --git a/bpf/include/map_config.h b/bpf/include/map_config.h index 2a293e8cd..aab499ce7 100644 --- a/bpf/include/map_config.h +++ b/bpf/include/map_config.h @@ -10,5 +10,6 @@ #define tmp_buf km_tmpbuf #define kmesh_config_map km_configmap #define kmesh_log_events km_log_event +#define map_of_nodeinfo km_nodeinfo #endif // _MAP_CONFIG_H_ \ No newline at end of file diff --git a/bpf/kmesh/bpf2go/bpf2go.go b/bpf/kmesh/bpf2go/bpf2go.go index 5163f6284..2fb660590 100644 --- a/bpf/kmesh/bpf2go/bpf2go.go +++ b/bpf/kmesh/bpf2go/bpf2go.go @@ -25,6 +25,8 @@ package bpf2go //go:generate go run github.com/cilium/ebpf/cmd/bpf2go --output-dir dualengine --go-package dualengine -cc clang --cflags $EXTRA_CFLAGS --cflags $EXTRA_CDEFINE KmeshSockopsWorkload ../workload/sockops.c -- -I../workload/include -I../../include -I../probes -DKERNEL_VERSION_HIGHER_5_13_0=1 //go:generate go run github.com/cilium/ebpf/cmd/bpf2go --output-dir dualengine --go-package dualengine -cc clang --cflags $EXTRA_CFLAGS --cflags $EXTRA_CDEFINE KmeshXDPAuth ../workload/xdp.c -- -I../workload/include -I../../include -I../../../api/v2-c -DKERNEL_VERSION_HIGHER_5_13_0=1 //go:generate go run github.com/cilium/ebpf/cmd/bpf2go --output-dir dualengine --go-package dualengine -cc clang --cflags $EXTRA_CFLAGS --cflags $EXTRA_CDEFINE KmeshSendmsg ../workload/sendmsg.c -- -I../workload/include -I../../include -DKERNEL_VERSION_HIGHER_5_13_0=1 +//go:generate go run github.com/cilium/ebpf/cmd/bpf2go --output-dir general --go-package general -cc clang --cflags $EXTRA_CFLAGS --cflags $EXTRA_CDEFINE KmeshTcMarkEncrypt ../general/tc_mark_encrypt.c -- -I../general/include -I../../include -DKERNEL_VERSION_HIGHER_5_13_0=1 +//go:generate go run github.com/cilium/ebpf/cmd/bpf2go --output-dir general --go-package general -cc clang --cflags $EXTRA_CFLAGS --cflags $EXTRA_CDEFINE KmeshTcMarkDecrypt ../general/tc_mark_decrypt.c -- -I../general/include -I../../include -DKERNEL_VERSION_HIGHER_5_13_0=1 //go:generate go run github.com/cilium/ebpf/cmd/bpf2go --output-dir kernelnative/normal --go-package normal -cc clang --cflags $EXTRA_CFLAGS --cflags $EXTRA_CDEFINE KmeshCgroupSockCompat ../ads/cgroup_sock.c -- -I../ads/include -I../../include -I../../../api/v2-c -DCGROUP_SOCK_MANAGE -DKERNEL_VERSION_HIGHER_5_13_0=0 //go:generate go run github.com/cilium/ebpf/cmd/bpf2go --output-dir dualengine --go-package dualengine -cc clang --cflags $EXTRA_CFLAGS --cflags $EXTRA_CDEFINE KmeshCgroupSockWorkloadCompat ../workload/cgroup_sock.c -- -I../workload/include -I../../include -I../probes -DKERNEL_VERSION_HIGHER_5_13_0=0 @@ -33,3 +35,5 @@ package bpf2go //go:generate go run github.com/cilium/ebpf/cmd/bpf2go --output-dir dualengine --go-package dualengine -cc clang --cflags $EXTRA_CFLAGS --cflags $EXTRA_CDEFINE KmeshSockopsWorkloadCompat ../workload/sockops.c -- -I../workload/include -I../../include -I../probes -DKERNEL_VERSION_HIGHER_5_13_0=0 //go:generate go run github.com/cilium/ebpf/cmd/bpf2go --output-dir dualengine --go-package dualengine -cc clang --cflags $EXTRA_CFLAGS --cflags $EXTRA_CDEFINE KmeshXDPAuthCompat ../workload/xdp.c -- -I../workload/include -I../../include -I../../../api/v2-c -DKERNEL_VERSION_HIGHER_5_13_0=0 //go:generate go run github.com/cilium/ebpf/cmd/bpf2go --output-dir dualengine --go-package dualengine -cc clang --cflags $EXTRA_CFLAGS --cflags $EXTRA_CDEFINE KmeshSendmsgCompat ../workload/sendmsg.c -- -I../workload/include -I../../include -DKERNEL_VERSION_HIGHER_5_13_0=0 +//go:generate go run github.com/cilium/ebpf/cmd/bpf2go --output-dir general --go-package general -cc clang --cflags $EXTRA_CFLAGS --cflags $EXTRA_CDEFINE KmeshTcMarkEncryptCompat ../general/tc_mark_encrypt.c -- -I../general/include -I../../include -DKERNEL_VERSION_HIGHER_5_13_0=0 +//go:generate go run github.com/cilium/ebpf/cmd/bpf2go --output-dir general --go-package general -cc clang --cflags $EXTRA_CFLAGS --cflags $EXTRA_CDEFINE KmeshTcMarkDecryptCompat ../general/tc_mark_decrypt.c -- -I../general/include -I../../include -DKERNEL_VERSION_HIGHER_5_13_0=0 diff --git a/bpf/kmesh/bpf2go/general/kmeshtcmarkdecrypt_bpfeb.go b/bpf/kmesh/bpf2go/general/kmeshtcmarkdecrypt_bpfeb.go new file mode 100644 index 000000000..3318f3411 --- /dev/null +++ b/bpf/kmesh/bpf2go/general/kmeshtcmarkdecrypt_bpfeb.go @@ -0,0 +1,149 @@ +// Code generated by bpf2go; DO NOT EDIT. +//go:build mips || mips64 || ppc64 || s390x + +package general + +import ( + "bytes" + _ "embed" + "fmt" + "io" + + "github.com/cilium/ebpf" +) + +type KmeshTcMarkDecryptBuf struct{ Data [40]int8 } + +type KmeshTcMarkDecryptKmeshConfig struct { + BpfLogLevel uint32 + NodeIp [4]uint32 + PodGateway [4]uint32 + AuthzOffload uint32 + EnableMonitoring uint32 +} + +type KmeshTcMarkDecryptLpmKey struct { + TrieKey struct { + Prefixlen uint32 + Data [0]uint8 + } + Ip struct { + Ip4 uint32 + _ [12]byte + } +} + +// LoadKmeshTcMarkDecrypt returns the embedded CollectionSpec for KmeshTcMarkDecrypt. +func LoadKmeshTcMarkDecrypt() (*ebpf.CollectionSpec, error) { + reader := bytes.NewReader(_KmeshTcMarkDecryptBytes) + spec, err := ebpf.LoadCollectionSpecFromReader(reader) + if err != nil { + return nil, fmt.Errorf("can't load KmeshTcMarkDecrypt: %w", err) + } + + return spec, err +} + +// LoadKmeshTcMarkDecryptObjects loads KmeshTcMarkDecrypt and converts it into a struct. +// +// The following types are suitable as obj argument: +// +// *KmeshTcMarkDecryptObjects +// *KmeshTcMarkDecryptPrograms +// *KmeshTcMarkDecryptMaps +// +// See ebpf.CollectionSpec.LoadAndAssign documentation for details. +func LoadKmeshTcMarkDecryptObjects(obj interface{}, opts *ebpf.CollectionOptions) error { + spec, err := LoadKmeshTcMarkDecrypt() + if err != nil { + return err + } + + return spec.LoadAndAssign(obj, opts) +} + +// KmeshTcMarkDecryptSpecs contains maps and programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkDecryptSpecs struct { + KmeshTcMarkDecryptProgramSpecs + KmeshTcMarkDecryptMapSpecs +} + +// KmeshTcMarkDecryptSpecs contains programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkDecryptProgramSpecs struct { + TcMarkDecrypt *ebpf.ProgramSpec `ebpf:"tc_mark_decrypt"` +} + +// KmeshTcMarkDecryptMapSpecs contains maps before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkDecryptMapSpecs struct { + KmConfigmap *ebpf.MapSpec `ebpf:"km_configmap"` + KmLogEvent *ebpf.MapSpec `ebpf:"km_log_event"` + KmNodeinfo *ebpf.MapSpec `ebpf:"km_nodeinfo"` + KmTmpbuf *ebpf.MapSpec `ebpf:"km_tmpbuf"` +} + +// KmeshTcMarkDecryptObjects contains all objects after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkDecryptObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkDecryptObjects struct { + KmeshTcMarkDecryptPrograms + KmeshTcMarkDecryptMaps +} + +func (o *KmeshTcMarkDecryptObjects) Close() error { + return _KmeshTcMarkDecryptClose( + &o.KmeshTcMarkDecryptPrograms, + &o.KmeshTcMarkDecryptMaps, + ) +} + +// KmeshTcMarkDecryptMaps contains all maps after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkDecryptObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkDecryptMaps struct { + KmConfigmap *ebpf.Map `ebpf:"km_configmap"` + KmLogEvent *ebpf.Map `ebpf:"km_log_event"` + KmNodeinfo *ebpf.Map `ebpf:"km_nodeinfo"` + KmTmpbuf *ebpf.Map `ebpf:"km_tmpbuf"` +} + +func (m *KmeshTcMarkDecryptMaps) Close() error { + return _KmeshTcMarkDecryptClose( + m.KmConfigmap, + m.KmLogEvent, + m.KmNodeinfo, + m.KmTmpbuf, + ) +} + +// KmeshTcMarkDecryptPrograms contains all programs after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkDecryptObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkDecryptPrograms struct { + TcMarkDecrypt *ebpf.Program `ebpf:"tc_mark_decrypt"` +} + +func (p *KmeshTcMarkDecryptPrograms) Close() error { + return _KmeshTcMarkDecryptClose( + p.TcMarkDecrypt, + ) +} + +func _KmeshTcMarkDecryptClose(closers ...io.Closer) error { + for _, closer := range closers { + if err := closer.Close(); err != nil { + return err + } + } + return nil +} + +// Do not access this directly. +// +//go:embed kmeshtcmarkdecrypt_bpfeb.o +var _KmeshTcMarkDecryptBytes []byte diff --git a/bpf/kmesh/bpf2go/general/kmeshtcmarkdecrypt_bpfel.go b/bpf/kmesh/bpf2go/general/kmeshtcmarkdecrypt_bpfel.go new file mode 100644 index 000000000..fe9096843 --- /dev/null +++ b/bpf/kmesh/bpf2go/general/kmeshtcmarkdecrypt_bpfel.go @@ -0,0 +1,149 @@ +// Code generated by bpf2go; DO NOT EDIT. +//go:build 386 || amd64 || arm || arm64 || loong64 || mips64le || mipsle || ppc64le || riscv64 + +package general + +import ( + "bytes" + _ "embed" + "fmt" + "io" + + "github.com/cilium/ebpf" +) + +type KmeshTcMarkDecryptBuf struct{ Data [40]int8 } + +type KmeshTcMarkDecryptKmeshConfig struct { + BpfLogLevel uint32 + NodeIp [4]uint32 + PodGateway [4]uint32 + AuthzOffload uint32 + EnableMonitoring uint32 +} + +type KmeshTcMarkDecryptLpmKey struct { + TrieKey struct { + Prefixlen uint32 + Data [0]uint8 + } + Ip struct { + Ip4 uint32 + _ [12]byte + } +} + +// LoadKmeshTcMarkDecrypt returns the embedded CollectionSpec for KmeshTcMarkDecrypt. +func LoadKmeshTcMarkDecrypt() (*ebpf.CollectionSpec, error) { + reader := bytes.NewReader(_KmeshTcMarkDecryptBytes) + spec, err := ebpf.LoadCollectionSpecFromReader(reader) + if err != nil { + return nil, fmt.Errorf("can't load KmeshTcMarkDecrypt: %w", err) + } + + return spec, err +} + +// LoadKmeshTcMarkDecryptObjects loads KmeshTcMarkDecrypt and converts it into a struct. +// +// The following types are suitable as obj argument: +// +// *KmeshTcMarkDecryptObjects +// *KmeshTcMarkDecryptPrograms +// *KmeshTcMarkDecryptMaps +// +// See ebpf.CollectionSpec.LoadAndAssign documentation for details. +func LoadKmeshTcMarkDecryptObjects(obj interface{}, opts *ebpf.CollectionOptions) error { + spec, err := LoadKmeshTcMarkDecrypt() + if err != nil { + return err + } + + return spec.LoadAndAssign(obj, opts) +} + +// KmeshTcMarkDecryptSpecs contains maps and programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkDecryptSpecs struct { + KmeshTcMarkDecryptProgramSpecs + KmeshTcMarkDecryptMapSpecs +} + +// KmeshTcMarkDecryptSpecs contains programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkDecryptProgramSpecs struct { + TcMarkDecrypt *ebpf.ProgramSpec `ebpf:"tc_mark_decrypt"` +} + +// KmeshTcMarkDecryptMapSpecs contains maps before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkDecryptMapSpecs struct { + KmConfigmap *ebpf.MapSpec `ebpf:"km_configmap"` + KmLogEvent *ebpf.MapSpec `ebpf:"km_log_event"` + KmNodeinfo *ebpf.MapSpec `ebpf:"km_nodeinfo"` + KmTmpbuf *ebpf.MapSpec `ebpf:"km_tmpbuf"` +} + +// KmeshTcMarkDecryptObjects contains all objects after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkDecryptObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkDecryptObjects struct { + KmeshTcMarkDecryptPrograms + KmeshTcMarkDecryptMaps +} + +func (o *KmeshTcMarkDecryptObjects) Close() error { + return _KmeshTcMarkDecryptClose( + &o.KmeshTcMarkDecryptPrograms, + &o.KmeshTcMarkDecryptMaps, + ) +} + +// KmeshTcMarkDecryptMaps contains all maps after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkDecryptObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkDecryptMaps struct { + KmConfigmap *ebpf.Map `ebpf:"km_configmap"` + KmLogEvent *ebpf.Map `ebpf:"km_log_event"` + KmNodeinfo *ebpf.Map `ebpf:"km_nodeinfo"` + KmTmpbuf *ebpf.Map `ebpf:"km_tmpbuf"` +} + +func (m *KmeshTcMarkDecryptMaps) Close() error { + return _KmeshTcMarkDecryptClose( + m.KmConfigmap, + m.KmLogEvent, + m.KmNodeinfo, + m.KmTmpbuf, + ) +} + +// KmeshTcMarkDecryptPrograms contains all programs after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkDecryptObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkDecryptPrograms struct { + TcMarkDecrypt *ebpf.Program `ebpf:"tc_mark_decrypt"` +} + +func (p *KmeshTcMarkDecryptPrograms) Close() error { + return _KmeshTcMarkDecryptClose( + p.TcMarkDecrypt, + ) +} + +func _KmeshTcMarkDecryptClose(closers ...io.Closer) error { + for _, closer := range closers { + if err := closer.Close(); err != nil { + return err + } + } + return nil +} + +// Do not access this directly. +// +//go:embed kmeshtcmarkdecrypt_bpfel.o +var _KmeshTcMarkDecryptBytes []byte diff --git a/bpf/kmesh/bpf2go/general/kmeshtcmarkdecryptcompat_bpfeb.go b/bpf/kmesh/bpf2go/general/kmeshtcmarkdecryptcompat_bpfeb.go new file mode 100644 index 000000000..301b640ec --- /dev/null +++ b/bpf/kmesh/bpf2go/general/kmeshtcmarkdecryptcompat_bpfeb.go @@ -0,0 +1,149 @@ +// Code generated by bpf2go; DO NOT EDIT. +//go:build mips || mips64 || ppc64 || s390x + +package general + +import ( + "bytes" + _ "embed" + "fmt" + "io" + + "github.com/cilium/ebpf" +) + +type KmeshTcMarkDecryptCompatBuf struct{ Data [40]int8 } + +type KmeshTcMarkDecryptCompatKmeshConfig struct { + BpfLogLevel uint32 + NodeIp [4]uint32 + PodGateway [4]uint32 + AuthzOffload uint32 + EnableMonitoring uint32 +} + +type KmeshTcMarkDecryptCompatLpmKey struct { + TrieKey struct { + Prefixlen uint32 + Data [0]uint8 + } + Ip struct { + Ip4 uint32 + _ [12]byte + } +} + +// LoadKmeshTcMarkDecryptCompat returns the embedded CollectionSpec for KmeshTcMarkDecryptCompat. +func LoadKmeshTcMarkDecryptCompat() (*ebpf.CollectionSpec, error) { + reader := bytes.NewReader(_KmeshTcMarkDecryptCompatBytes) + spec, err := ebpf.LoadCollectionSpecFromReader(reader) + if err != nil { + return nil, fmt.Errorf("can't load KmeshTcMarkDecryptCompat: %w", err) + } + + return spec, err +} + +// LoadKmeshTcMarkDecryptCompatObjects loads KmeshTcMarkDecryptCompat and converts it into a struct. +// +// The following types are suitable as obj argument: +// +// *KmeshTcMarkDecryptCompatObjects +// *KmeshTcMarkDecryptCompatPrograms +// *KmeshTcMarkDecryptCompatMaps +// +// See ebpf.CollectionSpec.LoadAndAssign documentation for details. +func LoadKmeshTcMarkDecryptCompatObjects(obj interface{}, opts *ebpf.CollectionOptions) error { + spec, err := LoadKmeshTcMarkDecryptCompat() + if err != nil { + return err + } + + return spec.LoadAndAssign(obj, opts) +} + +// KmeshTcMarkDecryptCompatSpecs contains maps and programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkDecryptCompatSpecs struct { + KmeshTcMarkDecryptCompatProgramSpecs + KmeshTcMarkDecryptCompatMapSpecs +} + +// KmeshTcMarkDecryptCompatSpecs contains programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkDecryptCompatProgramSpecs struct { + TcMarkDecrypt *ebpf.ProgramSpec `ebpf:"tc_mark_decrypt"` +} + +// KmeshTcMarkDecryptCompatMapSpecs contains maps before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkDecryptCompatMapSpecs struct { + KmConfigmap *ebpf.MapSpec `ebpf:"km_configmap"` + KmLogEvent *ebpf.MapSpec `ebpf:"km_log_event"` + KmNodeinfo *ebpf.MapSpec `ebpf:"km_nodeinfo"` + KmTmpbuf *ebpf.MapSpec `ebpf:"km_tmpbuf"` +} + +// KmeshTcMarkDecryptCompatObjects contains all objects after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkDecryptCompatObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkDecryptCompatObjects struct { + KmeshTcMarkDecryptCompatPrograms + KmeshTcMarkDecryptCompatMaps +} + +func (o *KmeshTcMarkDecryptCompatObjects) Close() error { + return _KmeshTcMarkDecryptCompatClose( + &o.KmeshTcMarkDecryptCompatPrograms, + &o.KmeshTcMarkDecryptCompatMaps, + ) +} + +// KmeshTcMarkDecryptCompatMaps contains all maps after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkDecryptCompatObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkDecryptCompatMaps struct { + KmConfigmap *ebpf.Map `ebpf:"km_configmap"` + KmLogEvent *ebpf.Map `ebpf:"km_log_event"` + KmNodeinfo *ebpf.Map `ebpf:"km_nodeinfo"` + KmTmpbuf *ebpf.Map `ebpf:"km_tmpbuf"` +} + +func (m *KmeshTcMarkDecryptCompatMaps) Close() error { + return _KmeshTcMarkDecryptCompatClose( + m.KmConfigmap, + m.KmLogEvent, + m.KmNodeinfo, + m.KmTmpbuf, + ) +} + +// KmeshTcMarkDecryptCompatPrograms contains all programs after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkDecryptCompatObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkDecryptCompatPrograms struct { + TcMarkDecrypt *ebpf.Program `ebpf:"tc_mark_decrypt"` +} + +func (p *KmeshTcMarkDecryptCompatPrograms) Close() error { + return _KmeshTcMarkDecryptCompatClose( + p.TcMarkDecrypt, + ) +} + +func _KmeshTcMarkDecryptCompatClose(closers ...io.Closer) error { + for _, closer := range closers { + if err := closer.Close(); err != nil { + return err + } + } + return nil +} + +// Do not access this directly. +// +//go:embed kmeshtcmarkdecryptcompat_bpfeb.o +var _KmeshTcMarkDecryptCompatBytes []byte diff --git a/bpf/kmesh/bpf2go/general/kmeshtcmarkdecryptcompat_bpfel.go b/bpf/kmesh/bpf2go/general/kmeshtcmarkdecryptcompat_bpfel.go new file mode 100644 index 000000000..a0fcde11f --- /dev/null +++ b/bpf/kmesh/bpf2go/general/kmeshtcmarkdecryptcompat_bpfel.go @@ -0,0 +1,149 @@ +// Code generated by bpf2go; DO NOT EDIT. +//go:build 386 || amd64 || arm || arm64 || loong64 || mips64le || mipsle || ppc64le || riscv64 + +package general + +import ( + "bytes" + _ "embed" + "fmt" + "io" + + "github.com/cilium/ebpf" +) + +type KmeshTcMarkDecryptCompatBuf struct{ Data [40]int8 } + +type KmeshTcMarkDecryptCompatKmeshConfig struct { + BpfLogLevel uint32 + NodeIp [4]uint32 + PodGateway [4]uint32 + AuthzOffload uint32 + EnableMonitoring uint32 +} + +type KmeshTcMarkDecryptCompatLpmKey struct { + TrieKey struct { + Prefixlen uint32 + Data [0]uint8 + } + Ip struct { + Ip4 uint32 + _ [12]byte + } +} + +// LoadKmeshTcMarkDecryptCompat returns the embedded CollectionSpec for KmeshTcMarkDecryptCompat. +func LoadKmeshTcMarkDecryptCompat() (*ebpf.CollectionSpec, error) { + reader := bytes.NewReader(_KmeshTcMarkDecryptCompatBytes) + spec, err := ebpf.LoadCollectionSpecFromReader(reader) + if err != nil { + return nil, fmt.Errorf("can't load KmeshTcMarkDecryptCompat: %w", err) + } + + return spec, err +} + +// LoadKmeshTcMarkDecryptCompatObjects loads KmeshTcMarkDecryptCompat and converts it into a struct. +// +// The following types are suitable as obj argument: +// +// *KmeshTcMarkDecryptCompatObjects +// *KmeshTcMarkDecryptCompatPrograms +// *KmeshTcMarkDecryptCompatMaps +// +// See ebpf.CollectionSpec.LoadAndAssign documentation for details. +func LoadKmeshTcMarkDecryptCompatObjects(obj interface{}, opts *ebpf.CollectionOptions) error { + spec, err := LoadKmeshTcMarkDecryptCompat() + if err != nil { + return err + } + + return spec.LoadAndAssign(obj, opts) +} + +// KmeshTcMarkDecryptCompatSpecs contains maps and programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkDecryptCompatSpecs struct { + KmeshTcMarkDecryptCompatProgramSpecs + KmeshTcMarkDecryptCompatMapSpecs +} + +// KmeshTcMarkDecryptCompatSpecs contains programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkDecryptCompatProgramSpecs struct { + TcMarkDecrypt *ebpf.ProgramSpec `ebpf:"tc_mark_decrypt"` +} + +// KmeshTcMarkDecryptCompatMapSpecs contains maps before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkDecryptCompatMapSpecs struct { + KmConfigmap *ebpf.MapSpec `ebpf:"km_configmap"` + KmLogEvent *ebpf.MapSpec `ebpf:"km_log_event"` + KmNodeinfo *ebpf.MapSpec `ebpf:"km_nodeinfo"` + KmTmpbuf *ebpf.MapSpec `ebpf:"km_tmpbuf"` +} + +// KmeshTcMarkDecryptCompatObjects contains all objects after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkDecryptCompatObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkDecryptCompatObjects struct { + KmeshTcMarkDecryptCompatPrograms + KmeshTcMarkDecryptCompatMaps +} + +func (o *KmeshTcMarkDecryptCompatObjects) Close() error { + return _KmeshTcMarkDecryptCompatClose( + &o.KmeshTcMarkDecryptCompatPrograms, + &o.KmeshTcMarkDecryptCompatMaps, + ) +} + +// KmeshTcMarkDecryptCompatMaps contains all maps after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkDecryptCompatObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkDecryptCompatMaps struct { + KmConfigmap *ebpf.Map `ebpf:"km_configmap"` + KmLogEvent *ebpf.Map `ebpf:"km_log_event"` + KmNodeinfo *ebpf.Map `ebpf:"km_nodeinfo"` + KmTmpbuf *ebpf.Map `ebpf:"km_tmpbuf"` +} + +func (m *KmeshTcMarkDecryptCompatMaps) Close() error { + return _KmeshTcMarkDecryptCompatClose( + m.KmConfigmap, + m.KmLogEvent, + m.KmNodeinfo, + m.KmTmpbuf, + ) +} + +// KmeshTcMarkDecryptCompatPrograms contains all programs after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkDecryptCompatObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkDecryptCompatPrograms struct { + TcMarkDecrypt *ebpf.Program `ebpf:"tc_mark_decrypt"` +} + +func (p *KmeshTcMarkDecryptCompatPrograms) Close() error { + return _KmeshTcMarkDecryptCompatClose( + p.TcMarkDecrypt, + ) +} + +func _KmeshTcMarkDecryptCompatClose(closers ...io.Closer) error { + for _, closer := range closers { + if err := closer.Close(); err != nil { + return err + } + } + return nil +} + +// Do not access this directly. +// +//go:embed kmeshtcmarkdecryptcompat_bpfel.o +var _KmeshTcMarkDecryptCompatBytes []byte diff --git a/bpf/kmesh/bpf2go/general/kmeshtcmarkencrypt_bpfeb.go b/bpf/kmesh/bpf2go/general/kmeshtcmarkencrypt_bpfeb.go new file mode 100644 index 000000000..9720f2de6 --- /dev/null +++ b/bpf/kmesh/bpf2go/general/kmeshtcmarkencrypt_bpfeb.go @@ -0,0 +1,149 @@ +// Code generated by bpf2go; DO NOT EDIT. +//go:build mips || mips64 || ppc64 || s390x + +package general + +import ( + "bytes" + _ "embed" + "fmt" + "io" + + "github.com/cilium/ebpf" +) + +type KmeshTcMarkEncryptBuf struct{ Data [40]int8 } + +type KmeshTcMarkEncryptKmeshConfig struct { + BpfLogLevel uint32 + NodeIp [4]uint32 + PodGateway [4]uint32 + AuthzOffload uint32 + EnableMonitoring uint32 +} + +type KmeshTcMarkEncryptLpmKey struct { + TrieKey struct { + Prefixlen uint32 + Data [0]uint8 + } + Ip struct { + Ip4 uint32 + _ [12]byte + } +} + +// LoadKmeshTcMarkEncrypt returns the embedded CollectionSpec for KmeshTcMarkEncrypt. +func LoadKmeshTcMarkEncrypt() (*ebpf.CollectionSpec, error) { + reader := bytes.NewReader(_KmeshTcMarkEncryptBytes) + spec, err := ebpf.LoadCollectionSpecFromReader(reader) + if err != nil { + return nil, fmt.Errorf("can't load KmeshTcMarkEncrypt: %w", err) + } + + return spec, err +} + +// LoadKmeshTcMarkEncryptObjects loads KmeshTcMarkEncrypt and converts it into a struct. +// +// The following types are suitable as obj argument: +// +// *KmeshTcMarkEncryptObjects +// *KmeshTcMarkEncryptPrograms +// *KmeshTcMarkEncryptMaps +// +// See ebpf.CollectionSpec.LoadAndAssign documentation for details. +func LoadKmeshTcMarkEncryptObjects(obj interface{}, opts *ebpf.CollectionOptions) error { + spec, err := LoadKmeshTcMarkEncrypt() + if err != nil { + return err + } + + return spec.LoadAndAssign(obj, opts) +} + +// KmeshTcMarkEncryptSpecs contains maps and programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkEncryptSpecs struct { + KmeshTcMarkEncryptProgramSpecs + KmeshTcMarkEncryptMapSpecs +} + +// KmeshTcMarkEncryptSpecs contains programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkEncryptProgramSpecs struct { + TcMarkEncrypt *ebpf.ProgramSpec `ebpf:"tc_mark_encrypt"` +} + +// KmeshTcMarkEncryptMapSpecs contains maps before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkEncryptMapSpecs struct { + KmConfigmap *ebpf.MapSpec `ebpf:"km_configmap"` + KmLogEvent *ebpf.MapSpec `ebpf:"km_log_event"` + KmNodeinfo *ebpf.MapSpec `ebpf:"km_nodeinfo"` + KmTmpbuf *ebpf.MapSpec `ebpf:"km_tmpbuf"` +} + +// KmeshTcMarkEncryptObjects contains all objects after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkEncryptObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkEncryptObjects struct { + KmeshTcMarkEncryptPrograms + KmeshTcMarkEncryptMaps +} + +func (o *KmeshTcMarkEncryptObjects) Close() error { + return _KmeshTcMarkEncryptClose( + &o.KmeshTcMarkEncryptPrograms, + &o.KmeshTcMarkEncryptMaps, + ) +} + +// KmeshTcMarkEncryptMaps contains all maps after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkEncryptObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkEncryptMaps struct { + KmConfigmap *ebpf.Map `ebpf:"km_configmap"` + KmLogEvent *ebpf.Map `ebpf:"km_log_event"` + KmNodeinfo *ebpf.Map `ebpf:"km_nodeinfo"` + KmTmpbuf *ebpf.Map `ebpf:"km_tmpbuf"` +} + +func (m *KmeshTcMarkEncryptMaps) Close() error { + return _KmeshTcMarkEncryptClose( + m.KmConfigmap, + m.KmLogEvent, + m.KmNodeinfo, + m.KmTmpbuf, + ) +} + +// KmeshTcMarkEncryptPrograms contains all programs after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkEncryptObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkEncryptPrograms struct { + TcMarkEncrypt *ebpf.Program `ebpf:"tc_mark_encrypt"` +} + +func (p *KmeshTcMarkEncryptPrograms) Close() error { + return _KmeshTcMarkEncryptClose( + p.TcMarkEncrypt, + ) +} + +func _KmeshTcMarkEncryptClose(closers ...io.Closer) error { + for _, closer := range closers { + if err := closer.Close(); err != nil { + return err + } + } + return nil +} + +// Do not access this directly. +// +//go:embed kmeshtcmarkencrypt_bpfeb.o +var _KmeshTcMarkEncryptBytes []byte diff --git a/bpf/kmesh/bpf2go/general/kmeshtcmarkencrypt_bpfel.go b/bpf/kmesh/bpf2go/general/kmeshtcmarkencrypt_bpfel.go new file mode 100644 index 000000000..52dbce9d6 --- /dev/null +++ b/bpf/kmesh/bpf2go/general/kmeshtcmarkencrypt_bpfel.go @@ -0,0 +1,149 @@ +// Code generated by bpf2go; DO NOT EDIT. +//go:build 386 || amd64 || arm || arm64 || loong64 || mips64le || mipsle || ppc64le || riscv64 + +package general + +import ( + "bytes" + _ "embed" + "fmt" + "io" + + "github.com/cilium/ebpf" +) + +type KmeshTcMarkEncryptBuf struct{ Data [40]int8 } + +type KmeshTcMarkEncryptKmeshConfig struct { + BpfLogLevel uint32 + NodeIp [4]uint32 + PodGateway [4]uint32 + AuthzOffload uint32 + EnableMonitoring uint32 +} + +type KmeshTcMarkEncryptLpmKey struct { + TrieKey struct { + Prefixlen uint32 + Data [0]uint8 + } + Ip struct { + Ip4 uint32 + _ [12]byte + } +} + +// LoadKmeshTcMarkEncrypt returns the embedded CollectionSpec for KmeshTcMarkEncrypt. +func LoadKmeshTcMarkEncrypt() (*ebpf.CollectionSpec, error) { + reader := bytes.NewReader(_KmeshTcMarkEncryptBytes) + spec, err := ebpf.LoadCollectionSpecFromReader(reader) + if err != nil { + return nil, fmt.Errorf("can't load KmeshTcMarkEncrypt: %w", err) + } + + return spec, err +} + +// LoadKmeshTcMarkEncryptObjects loads KmeshTcMarkEncrypt and converts it into a struct. +// +// The following types are suitable as obj argument: +// +// *KmeshTcMarkEncryptObjects +// *KmeshTcMarkEncryptPrograms +// *KmeshTcMarkEncryptMaps +// +// See ebpf.CollectionSpec.LoadAndAssign documentation for details. +func LoadKmeshTcMarkEncryptObjects(obj interface{}, opts *ebpf.CollectionOptions) error { + spec, err := LoadKmeshTcMarkEncrypt() + if err != nil { + return err + } + + return spec.LoadAndAssign(obj, opts) +} + +// KmeshTcMarkEncryptSpecs contains maps and programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkEncryptSpecs struct { + KmeshTcMarkEncryptProgramSpecs + KmeshTcMarkEncryptMapSpecs +} + +// KmeshTcMarkEncryptSpecs contains programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkEncryptProgramSpecs struct { + TcMarkEncrypt *ebpf.ProgramSpec `ebpf:"tc_mark_encrypt"` +} + +// KmeshTcMarkEncryptMapSpecs contains maps before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkEncryptMapSpecs struct { + KmConfigmap *ebpf.MapSpec `ebpf:"km_configmap"` + KmLogEvent *ebpf.MapSpec `ebpf:"km_log_event"` + KmNodeinfo *ebpf.MapSpec `ebpf:"km_nodeinfo"` + KmTmpbuf *ebpf.MapSpec `ebpf:"km_tmpbuf"` +} + +// KmeshTcMarkEncryptObjects contains all objects after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkEncryptObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkEncryptObjects struct { + KmeshTcMarkEncryptPrograms + KmeshTcMarkEncryptMaps +} + +func (o *KmeshTcMarkEncryptObjects) Close() error { + return _KmeshTcMarkEncryptClose( + &o.KmeshTcMarkEncryptPrograms, + &o.KmeshTcMarkEncryptMaps, + ) +} + +// KmeshTcMarkEncryptMaps contains all maps after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkEncryptObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkEncryptMaps struct { + KmConfigmap *ebpf.Map `ebpf:"km_configmap"` + KmLogEvent *ebpf.Map `ebpf:"km_log_event"` + KmNodeinfo *ebpf.Map `ebpf:"km_nodeinfo"` + KmTmpbuf *ebpf.Map `ebpf:"km_tmpbuf"` +} + +func (m *KmeshTcMarkEncryptMaps) Close() error { + return _KmeshTcMarkEncryptClose( + m.KmConfigmap, + m.KmLogEvent, + m.KmNodeinfo, + m.KmTmpbuf, + ) +} + +// KmeshTcMarkEncryptPrograms contains all programs after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkEncryptObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkEncryptPrograms struct { + TcMarkEncrypt *ebpf.Program `ebpf:"tc_mark_encrypt"` +} + +func (p *KmeshTcMarkEncryptPrograms) Close() error { + return _KmeshTcMarkEncryptClose( + p.TcMarkEncrypt, + ) +} + +func _KmeshTcMarkEncryptClose(closers ...io.Closer) error { + for _, closer := range closers { + if err := closer.Close(); err != nil { + return err + } + } + return nil +} + +// Do not access this directly. +// +//go:embed kmeshtcmarkencrypt_bpfel.o +var _KmeshTcMarkEncryptBytes []byte diff --git a/bpf/kmesh/bpf2go/general/kmeshtcmarkencryptcompat_bpfeb.go b/bpf/kmesh/bpf2go/general/kmeshtcmarkencryptcompat_bpfeb.go new file mode 100644 index 000000000..22e20fe7a --- /dev/null +++ b/bpf/kmesh/bpf2go/general/kmeshtcmarkencryptcompat_bpfeb.go @@ -0,0 +1,149 @@ +// Code generated by bpf2go; DO NOT EDIT. +//go:build mips || mips64 || ppc64 || s390x + +package general + +import ( + "bytes" + _ "embed" + "fmt" + "io" + + "github.com/cilium/ebpf" +) + +type KmeshTcMarkEncryptCompatBuf struct{ Data [40]int8 } + +type KmeshTcMarkEncryptCompatKmeshConfig struct { + BpfLogLevel uint32 + NodeIp [4]uint32 + PodGateway [4]uint32 + AuthzOffload uint32 + EnableMonitoring uint32 +} + +type KmeshTcMarkEncryptCompatLpmKey struct { + TrieKey struct { + Prefixlen uint32 + Data [0]uint8 + } + Ip struct { + Ip4 uint32 + _ [12]byte + } +} + +// LoadKmeshTcMarkEncryptCompat returns the embedded CollectionSpec for KmeshTcMarkEncryptCompat. +func LoadKmeshTcMarkEncryptCompat() (*ebpf.CollectionSpec, error) { + reader := bytes.NewReader(_KmeshTcMarkEncryptCompatBytes) + spec, err := ebpf.LoadCollectionSpecFromReader(reader) + if err != nil { + return nil, fmt.Errorf("can't load KmeshTcMarkEncryptCompat: %w", err) + } + + return spec, err +} + +// LoadKmeshTcMarkEncryptCompatObjects loads KmeshTcMarkEncryptCompat and converts it into a struct. +// +// The following types are suitable as obj argument: +// +// *KmeshTcMarkEncryptCompatObjects +// *KmeshTcMarkEncryptCompatPrograms +// *KmeshTcMarkEncryptCompatMaps +// +// See ebpf.CollectionSpec.LoadAndAssign documentation for details. +func LoadKmeshTcMarkEncryptCompatObjects(obj interface{}, opts *ebpf.CollectionOptions) error { + spec, err := LoadKmeshTcMarkEncryptCompat() + if err != nil { + return err + } + + return spec.LoadAndAssign(obj, opts) +} + +// KmeshTcMarkEncryptCompatSpecs contains maps and programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkEncryptCompatSpecs struct { + KmeshTcMarkEncryptCompatProgramSpecs + KmeshTcMarkEncryptCompatMapSpecs +} + +// KmeshTcMarkEncryptCompatSpecs contains programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkEncryptCompatProgramSpecs struct { + TcMarkEncrypt *ebpf.ProgramSpec `ebpf:"tc_mark_encrypt"` +} + +// KmeshTcMarkEncryptCompatMapSpecs contains maps before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkEncryptCompatMapSpecs struct { + KmConfigmap *ebpf.MapSpec `ebpf:"km_configmap"` + KmLogEvent *ebpf.MapSpec `ebpf:"km_log_event"` + KmNodeinfo *ebpf.MapSpec `ebpf:"km_nodeinfo"` + KmTmpbuf *ebpf.MapSpec `ebpf:"km_tmpbuf"` +} + +// KmeshTcMarkEncryptCompatObjects contains all objects after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkEncryptCompatObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkEncryptCompatObjects struct { + KmeshTcMarkEncryptCompatPrograms + KmeshTcMarkEncryptCompatMaps +} + +func (o *KmeshTcMarkEncryptCompatObjects) Close() error { + return _KmeshTcMarkEncryptCompatClose( + &o.KmeshTcMarkEncryptCompatPrograms, + &o.KmeshTcMarkEncryptCompatMaps, + ) +} + +// KmeshTcMarkEncryptCompatMaps contains all maps after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkEncryptCompatObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkEncryptCompatMaps struct { + KmConfigmap *ebpf.Map `ebpf:"km_configmap"` + KmLogEvent *ebpf.Map `ebpf:"km_log_event"` + KmNodeinfo *ebpf.Map `ebpf:"km_nodeinfo"` + KmTmpbuf *ebpf.Map `ebpf:"km_tmpbuf"` +} + +func (m *KmeshTcMarkEncryptCompatMaps) Close() error { + return _KmeshTcMarkEncryptCompatClose( + m.KmConfigmap, + m.KmLogEvent, + m.KmNodeinfo, + m.KmTmpbuf, + ) +} + +// KmeshTcMarkEncryptCompatPrograms contains all programs after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkEncryptCompatObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkEncryptCompatPrograms struct { + TcMarkEncrypt *ebpf.Program `ebpf:"tc_mark_encrypt"` +} + +func (p *KmeshTcMarkEncryptCompatPrograms) Close() error { + return _KmeshTcMarkEncryptCompatClose( + p.TcMarkEncrypt, + ) +} + +func _KmeshTcMarkEncryptCompatClose(closers ...io.Closer) error { + for _, closer := range closers { + if err := closer.Close(); err != nil { + return err + } + } + return nil +} + +// Do not access this directly. +// +//go:embed kmeshtcmarkencryptcompat_bpfeb.o +var _KmeshTcMarkEncryptCompatBytes []byte diff --git a/bpf/kmesh/bpf2go/general/kmeshtcmarkencryptcompat_bpfel.go b/bpf/kmesh/bpf2go/general/kmeshtcmarkencryptcompat_bpfel.go new file mode 100644 index 000000000..549a42f38 --- /dev/null +++ b/bpf/kmesh/bpf2go/general/kmeshtcmarkencryptcompat_bpfel.go @@ -0,0 +1,149 @@ +// Code generated by bpf2go; DO NOT EDIT. +//go:build 386 || amd64 || arm || arm64 || loong64 || mips64le || mipsle || ppc64le || riscv64 + +package general + +import ( + "bytes" + _ "embed" + "fmt" + "io" + + "github.com/cilium/ebpf" +) + +type KmeshTcMarkEncryptCompatBuf struct{ Data [40]int8 } + +type KmeshTcMarkEncryptCompatKmeshConfig struct { + BpfLogLevel uint32 + NodeIp [4]uint32 + PodGateway [4]uint32 + AuthzOffload uint32 + EnableMonitoring uint32 +} + +type KmeshTcMarkEncryptCompatLpmKey struct { + TrieKey struct { + Prefixlen uint32 + Data [0]uint8 + } + Ip struct { + Ip4 uint32 + _ [12]byte + } +} + +// LoadKmeshTcMarkEncryptCompat returns the embedded CollectionSpec for KmeshTcMarkEncryptCompat. +func LoadKmeshTcMarkEncryptCompat() (*ebpf.CollectionSpec, error) { + reader := bytes.NewReader(_KmeshTcMarkEncryptCompatBytes) + spec, err := ebpf.LoadCollectionSpecFromReader(reader) + if err != nil { + return nil, fmt.Errorf("can't load KmeshTcMarkEncryptCompat: %w", err) + } + + return spec, err +} + +// LoadKmeshTcMarkEncryptCompatObjects loads KmeshTcMarkEncryptCompat and converts it into a struct. +// +// The following types are suitable as obj argument: +// +// *KmeshTcMarkEncryptCompatObjects +// *KmeshTcMarkEncryptCompatPrograms +// *KmeshTcMarkEncryptCompatMaps +// +// See ebpf.CollectionSpec.LoadAndAssign documentation for details. +func LoadKmeshTcMarkEncryptCompatObjects(obj interface{}, opts *ebpf.CollectionOptions) error { + spec, err := LoadKmeshTcMarkEncryptCompat() + if err != nil { + return err + } + + return spec.LoadAndAssign(obj, opts) +} + +// KmeshTcMarkEncryptCompatSpecs contains maps and programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkEncryptCompatSpecs struct { + KmeshTcMarkEncryptCompatProgramSpecs + KmeshTcMarkEncryptCompatMapSpecs +} + +// KmeshTcMarkEncryptCompatSpecs contains programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkEncryptCompatProgramSpecs struct { + TcMarkEncrypt *ebpf.ProgramSpec `ebpf:"tc_mark_encrypt"` +} + +// KmeshTcMarkEncryptCompatMapSpecs contains maps before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type KmeshTcMarkEncryptCompatMapSpecs struct { + KmConfigmap *ebpf.MapSpec `ebpf:"km_configmap"` + KmLogEvent *ebpf.MapSpec `ebpf:"km_log_event"` + KmNodeinfo *ebpf.MapSpec `ebpf:"km_nodeinfo"` + KmTmpbuf *ebpf.MapSpec `ebpf:"km_tmpbuf"` +} + +// KmeshTcMarkEncryptCompatObjects contains all objects after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkEncryptCompatObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkEncryptCompatObjects struct { + KmeshTcMarkEncryptCompatPrograms + KmeshTcMarkEncryptCompatMaps +} + +func (o *KmeshTcMarkEncryptCompatObjects) Close() error { + return _KmeshTcMarkEncryptCompatClose( + &o.KmeshTcMarkEncryptCompatPrograms, + &o.KmeshTcMarkEncryptCompatMaps, + ) +} + +// KmeshTcMarkEncryptCompatMaps contains all maps after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkEncryptCompatObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkEncryptCompatMaps struct { + KmConfigmap *ebpf.Map `ebpf:"km_configmap"` + KmLogEvent *ebpf.Map `ebpf:"km_log_event"` + KmNodeinfo *ebpf.Map `ebpf:"km_nodeinfo"` + KmTmpbuf *ebpf.Map `ebpf:"km_tmpbuf"` +} + +func (m *KmeshTcMarkEncryptCompatMaps) Close() error { + return _KmeshTcMarkEncryptCompatClose( + m.KmConfigmap, + m.KmLogEvent, + m.KmNodeinfo, + m.KmTmpbuf, + ) +} + +// KmeshTcMarkEncryptCompatPrograms contains all programs after they have been loaded into the kernel. +// +// It can be passed to LoadKmeshTcMarkEncryptCompatObjects or ebpf.CollectionSpec.LoadAndAssign. +type KmeshTcMarkEncryptCompatPrograms struct { + TcMarkEncrypt *ebpf.Program `ebpf:"tc_mark_encrypt"` +} + +func (p *KmeshTcMarkEncryptCompatPrograms) Close() error { + return _KmeshTcMarkEncryptCompatClose( + p.TcMarkEncrypt, + ) +} + +func _KmeshTcMarkEncryptCompatClose(closers ...io.Closer) error { + for _, closer := range closers { + if err := closer.Close(); err != nil { + return err + } + } + return nil +} + +// Do not access this directly. +// +//go:embed kmeshtcmarkencryptcompat_bpfel.o +var _KmeshTcMarkEncryptCompatBytes []byte diff --git a/bpf/kmesh/general/include/ipsec_map.h b/bpf/kmesh/general/include/ipsec_map.h new file mode 100644 index 000000000..22bb69109 --- /dev/null +++ b/bpf/kmesh/general/include/ipsec_map.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright Authors of Kmesh */ + +#ifndef __KMESH_IPSEC_H__ +#define __KMESH_IPSEC_H__ +#include +#include "common.h" +#include "map_config.h" + +#define MAP_SIZE_OF_NODEINFO 8192 + +struct lpm_key { + struct bpf_lpm_trie_key trie_key; + struct ip_addr ip; +}; + +struct { + __uint(type, BPF_MAP_TYPE_LPM_TRIE); + __type(key, struct lpm_key); + __type(value, __u32); + __uint(map_flags, BPF_F_NO_PREALLOC); + __uint(max_entries, MAP_SIZE_OF_NODEINFO); +} map_of_nodeinfo SEC(".maps"); + +#endif /* __KMESH_IPSEC_H__ */ \ No newline at end of file diff --git a/bpf/kmesh/general/include/tc.h b/bpf/kmesh/general/include/tc.h new file mode 100644 index 000000000..18b178e38 --- /dev/null +++ b/bpf/kmesh/general/include/tc.h @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright Authors of Kmesh */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bpf_log.h" +#include "common.h" +#include "ipsec_map.h" + +struct tc_info { + struct ethhdr *ethh; + union { + struct iphdr *iph; + struct ipv6hdr *ip6h; + }; +}; + +#define PARSER_FAILED 1 +#define PARSER_SUCC 0 + +static inline bool is_ipv4(struct tc_info *info) +{ + return info->ethh->h_proto == bpf_htons(ETH_P_IP); +} + +static inline bool is_ipv6(struct tc_info *info) +{ + return info->ethh->h_proto == bpf_htons(ETH_P_IPV6); +} + +static inline int parser_tc_info(struct __sk_buff *ctx, struct tc_info *info) +{ + void *begin = (void *)(long)(ctx->data); + void *end = (void *)(long)(ctx->data_end); + + // eth header + info->ethh = (struct ethhdr *)begin; + if ((void *)(info->ethh + 1) > end) + return PARSER_FAILED; + + // ip4|ip6 header + begin = info->ethh + 1; + if ((begin + 1) > end) + return PARSER_FAILED; + if (is_ipv4(info)) { + info->iph = (struct iphdr *)begin; + if ((void *)(info->iph + 1) > end) + return PARSER_FAILED; + } else if (is_ipv6(info)) { + info->ip6h = (struct ipv6hdr *)begin; + if ((void *)(info->ip6h + 1) > end) + return PARSER_FAILED; + } else + return PARSER_FAILED; + + return PARSER_SUCC; +} + +struct nodeinfo *check_remote_manage_by_kmesh(struct __sk_buff *ctx, struct tc_info *info, __u32 ip4, __u32 *ip6) +{ + struct lpm_key key = {0}; + struct bpf_sock_tuple tuple_key = {0}; + void *end = (void *)(long)(ctx->data_end); + if (is_ipv4(info)) { + key.trie_key.prefixlen = 32; + key.ip.ip4 = ip4; + } else if (is_ipv6(info)) { + // original data boundary access will be lost. + // The boundary needs to be determined again. + if ((void *)(info->ip6h + 1) > end) { + return NULL; + } + key.trie_key.prefixlen = 128; + IP6_COPY(key.ip.ip6, ip6); + } else { + return NULL; + } + return bpf_map_lookup_elem(&map_of_nodeinfo, &key); +} \ No newline at end of file diff --git a/bpf/kmesh/general/tc_mark_decrypt.c b/bpf/kmesh/general/tc_mark_decrypt.c new file mode 100644 index 000000000..04e4d3a6e --- /dev/null +++ b/bpf/kmesh/general/tc_mark_decrypt.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright Authors of Kmesh */ + +#include "tc.h" +#include "bpf_log.h" +#include "common.h" +#include "ipsec_map.h" + +// run at node nic and mark traffic need to decryption +SEC("tc_ingress") +int tc_mark_decrypt(struct __sk_buff *ctx) +{ + struct nodeinfo *nodeinfo; + struct tc_info info = {0}; + + if (parser_tc_info(ctx, &info)) { + return TC_ACT_OK; + } + nodeinfo = check_remote_manage_by_kmesh(ctx, &info, info.iph->saddr, info.ip6h->saddr.s6_addr32); + if (!nodeinfo) { + return TC_ACT_OK; + } + // 0x00d0 mean need decryption in ipsec + ctx->mark = 0x00d0; + return TC_ACT_OK; +} + +char _license[] SEC("license") = "Dual BSD/GPL"; +int _version SEC("version") = 1; \ No newline at end of file diff --git a/bpf/kmesh/general/tc_mark_encrypt.c b/bpf/kmesh/general/tc_mark_encrypt.c new file mode 100644 index 000000000..862484c4e --- /dev/null +++ b/bpf/kmesh/general/tc_mark_encrypt.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright Authors of Kmesh */ + +#include "tc.h" +#include "bpf_log.h" +#include "ipsec_map.h" + +// run at pod nic and mark traffic need to encryption. +// It runs on the host side of the eth NIC, as packets +// enter the NIC(i.e., into the host ns network) +SEC("tc_ingress") +int tc_mark_encrypt(struct __sk_buff *ctx) +{ + struct nodeinfo *nodeinfo; + struct tc_info info = {0}; + + if (parser_tc_info(ctx, &info)) { + return TC_ACT_OK; + } + + nodeinfo = check_remote_manage_by_kmesh(ctx, &info, info.iph->daddr, info.ip6h->daddr.s6_addr32); + if (!nodeinfo) { + return TC_ACT_OK; + } + // 0x00d0 mean need encryption in ipsec + ctx->mark = 0x00e0; + return TC_ACT_OK; +} + +char _license[] SEC("license") = "Dual BSD/GPL"; +int _version SEC("version") = 1; \ No newline at end of file diff --git a/ctl/common/common.go b/ctl/common/common.go index 22c10e879..b804bafc1 100644 --- a/ctl/common/common.go +++ b/ctl/common/common.go @@ -23,6 +23,7 @@ import ( "kmesh.net/kmesh/ctl/dump" logcmd "kmesh.net/kmesh/ctl/log" "kmesh.net/kmesh/ctl/monitoring" + "kmesh.net/kmesh/ctl/secret" "kmesh.net/kmesh/ctl/version" "kmesh.net/kmesh/ctl/waypoint" ) @@ -43,6 +44,7 @@ func GetRootCommand() *cobra.Command { rootCmd.AddCommand(version.NewCmd()) rootCmd.AddCommand(monitoring.NewCmd()) rootCmd.AddCommand(authz.NewCmd()) + rootCmd.AddCommand(secret.NewCmd()) return rootCmd } diff --git a/ctl/secret/secret.go b/ctl/secret/secret.go new file mode 100644 index 000000000..734a33313 --- /dev/null +++ b/ctl/secret/secret.go @@ -0,0 +1,143 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secret + +import ( + "context" + "encoding/hex" + "encoding/json" + "os" + "strings" + + "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "kmesh.net/kmesh/ctl/utils" + "kmesh.net/kmesh/pkg/controller/encryption/ipsec" + "kmesh.net/kmesh/pkg/logger" +) + +var log = logger.NewLoggerScope("kmeshctl/secret") + +const ( + SecretName = "kmesh-ipsec" + AeadAlgoName = "rfc4106(gcm(aes))" + AeadAlgoICVLength = 128 // IPsec support ICV length can use 64/96/128 bit when use gcm-aes, we use 128 bit + AeadKeyLength = 36 // aead algo use rfc4106(gcm(aes)). use 32 char(256 bit) as the key and 4 char (32bit) as the salt value +) + +func NewCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "secret", + Short: "Use secrets to generate secret configuration data for IPsec", + Example: `# Use secrets to generate secret configuration data for IPsec: + kmeshctl secret --key or -k, only support use aead algo: rfc4106(gcm(aes)) + key need 36 characters(use 32 characters as key, 4 characters as salt). + Hexadecimal dump is required when the key is entered. + e.g.:kmeshctl secret --key=$(dd if=/dev/urandom count=36 bs=1 2>/dev/null | xxd -p -c 64) + e.g.:kmeshctl secret -k=$(echo -n "{36-character user-defined key here}" | xxd -p -c 64)`, + Args: cobra.MaximumNArgs(0), + Run: func(cmd *cobra.Command, args []string) { + GeneralSecret(cmd, args) + }, + } + cmd.Flags().StringP("key", "k", "", "key of the encryption") + return cmd +} + +func GeneralSecret(cmd *cobra.Command, args []string) { + var ipSecKey, ipSecKeyOld ipsec.IpSecKey + var err error + + clientset, err := utils.CreateKubeClient() + if err != nil { + log.Errorf("failed to connect k8s client, %v", err) + os.Exit(1) + } + + ipSecKey.AeadKeyName = AeadAlgoName + + aeadKeyArg, _ := cmd.Flags().GetString("key") + + if strings.Compare(aeadKeyArg, "") == 0 { + log.Errorf("no param --key or -k, we need a encryption key") + os.Exit(1) + } + + aeadKey, err := hex.DecodeString(aeadKeyArg) + if err != nil { + log.Errorf("invalid input argument, %v, input: %v", err, aeadKeyArg) + os.Exit(1) + } + + if len(aeadKey) != 36 { + log.Errorf("The key length is not enough!. It requires 36 characters(256-bit key + 32-bit salt)") + os.Exit(1) + } + + ipSecKey.AeadKey = aeadKey + + ipSecKey.Length = AeadAlgoICVLength + + secretOld, err := clientset.Kube().CoreV1().Secrets(utils.KmeshNamespace).Get(context.TODO(), SecretName, metav1.GetOptions{}) + if err != nil { + if !apierrors.IsNotFound(err) { + log.Errorf("failed to get secret: %v, %v", SecretName, err) + os.Exit(1) + } + ipSecKey.Spi = 1 + } else { + err = json.Unmarshal(secretOld.Data["ipSec"], &ipSecKeyOld) + if err != nil { + log.Errorf("failed to unmarshal secret: %v, %v", secretOld, err) + os.Exit(1) + } + ipSecKey.Spi = ipSecKeyOld.Spi + 1 + } + + secretData, err := json.Marshal(ipSecKey) + if err != nil { + log.Errorf("failed to convert ipsec key to secret data, %v", err) + os.Exit(1) + } + + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: SecretName, + }, + Type: corev1.SecretTypeOpaque, + Data: map[string][]byte{ + "ipSec": []byte(secretData), + }, + } + + if ipSecKey.Spi == 1 { + _, err = clientset.Kube().CoreV1().Secrets(utils.KmeshNamespace).Create(context.TODO(), secret, metav1.CreateOptions{}) + if err != nil { + log.Errorf("failed to create %v secret, %v", SecretName, err) + os.Exit(1) + } + } else { + _, err = clientset.Kube().CoreV1().Secrets(utils.KmeshNamespace).Update(context.TODO(), secret, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("failed to update %v secret, %v", SecretName, err) + os.Exit(1) + } + } +} diff --git a/daemon/manager/manager.go b/daemon/manager/manager.go index 59046c4fe..18d9e757c 100644 --- a/daemon/manager/manager.go +++ b/daemon/manager/manager.go @@ -106,7 +106,7 @@ func Execute(configs *options.BootstrapConfigs) error { _ = statusServer.StopServer() }() - cniInstaller := cni.NewInstaller(configs.BpfConfig.Mode, + cniInstaller := cni.NewInstaller(configs.BpfConfig.Mode, configs.BpfConfig.EnableIPsec, configs.CniConfig.CniMountNetEtcDIR, configs.CniConfig.CniConfigName, configs.CniConfig.CniConfigChained, configs.CniConfig.ServiceAccountPath) if err := cniInstaller.Start(); err != nil { return err diff --git a/daemon/manager/uninstall/uninstall.go b/daemon/manager/uninstall/uninstall.go index 276c03de2..6c730e91b 100644 --- a/daemon/manager/uninstall/uninstall.go +++ b/daemon/manager/uninstall/uninstall.go @@ -37,7 +37,7 @@ func NewCmd() *cobra.Command { if err := configs.ParseConfigs(); err != nil { return err } - cniInstaller := cni.NewInstaller(configs.BpfConfig.Mode, + cniInstaller := cni.NewInstaller(configs.BpfConfig.Mode, configs.BpfConfig.EnableIPsec, configs.CniConfig.CniMountNetEtcDIR, configs.CniConfig.CniConfigName, configs.CniConfig.CniConfigChained, configs.CniConfig.ServiceAccountPath) cniInstaller.Stop() return nil diff --git a/daemon/options/bpf.go b/daemon/options/bpf.go index f2925af33..32aaf0d6c 100644 --- a/daemon/options/bpf.go +++ b/daemon/options/bpf.go @@ -32,6 +32,7 @@ type BpfConfig struct { EnableMda bool EnableMonitoring bool EnableProfiling bool + EnableIPsec bool } func (c *BpfConfig) AttachFlags(cmd *cobra.Command) { @@ -41,6 +42,7 @@ func (c *BpfConfig) AttachFlags(cmd *cobra.Command) { cmd.PersistentFlags().BoolVar(&c.EnableMda, "enable-mda", false, "enable mda") cmd.PersistentFlags().BoolVar(&c.EnableMonitoring, "monitoring", true, "enable kmesh traffic monitoring in daemon process") cmd.PersistentFlags().BoolVar(&c.EnableProfiling, "profiling", false, "whether to enable profiling or not, default to false") + cmd.PersistentFlags().BoolVar(&c.EnableIPsec, "enable-ipsec", false, "enable ipsec encryption and authentication between nodes") } func (c *BpfConfig) ParseConfig() error { diff --git a/deploy/yaml/clusterrole.yaml b/deploy/yaml/clusterrole.yaml index 474fce33a..8308971a4 100644 --- a/deploy/yaml/clusterrole.yaml +++ b/deploy/yaml/clusterrole.yaml @@ -11,3 +11,6 @@ rules: - apiGroups: ["apps"] resources: ["daemonsets"] verbs: ["get"] +- apiGroups: ["kmesh.net"] + resources: ["kmeshnodeinfos"] + verbs: ["get", "create", "update", "delete", "list", "watch"] \ No newline at end of file diff --git a/deploy/yaml/crd/kmesh.net_kmeshnodeinfos.yaml b/deploy/yaml/crd/kmesh.net_kmeshnodeinfos.yaml new file mode 100644 index 000000000..94cbd2e06 --- /dev/null +++ b/deploy/yaml/crd/kmesh.net_kmeshnodeinfos.yaml @@ -0,0 +1,78 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: kmeshnodeinfos.kmesh.net +spec: + group: kmesh.net + names: + kind: KmeshNodeInfo + listKind: KmeshNodeInfoList + plural: kmeshnodeinfos + singular: kmeshnodeinfo + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: KmeshNode is the Schema for the kmeshnodes API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + addresses: + description: |- + Addresses is used to store the internal ip address informatioon on the + host. The IP address information is used to generate the IPsec state + informatioon. IPsec uses this information to determine which network + adapter is used to encrypt and send data. + items: + type: string + type: array + bootID: + description: |- + bootid is used to generate the ipsec key. After the node is restarted, + the key needs to be updated. + type: string + podCIDRS: + description: |- + PodCIDRs used in IPsec checks the destination of the data to + determine which IPsec state is used for encryption. + items: + type: string + type: array + spi: + description: |- + The SPI is used to identify the version number of the current key. + The communication can be normal only when both communication parties + have spis and the spi keys are the same. + type: integer + required: + - addresses + - bootID + - podCIDRS + - spi + type: object + status: + type: object + type: object + served: true + storage: true diff --git a/deploy/yaml/kmesh.yaml b/deploy/yaml/kmesh.yaml index f80ef2f54..927b9ec44 100644 --- a/deploy/yaml/kmesh.yaml +++ b/deploy/yaml/kmesh.yaml @@ -39,6 +39,10 @@ spec: - name: sys-fs-bpf hostPath: path: /sys/fs/bpf + - name: kmesh-ipsec + secret: + secretName: kmesh-ipsec + optional: true # required for compiling and building ko - name: lib-modules hostPath: @@ -128,6 +132,8 @@ spec: mountPath: /var/run/secrets/istio - name: istio-token mountPath: /var/run/secrets/tokens + - name: kmesh-ipsec + mountPath: /kmesh/kmesh-ipsec resources: limits: # image online-compile needs 800Mi, or only 200Mi diff --git a/docs/ctl/kmeshctl.md b/docs/ctl/kmeshctl.md index 656807bcc..2a736088d 100644 --- a/docs/ctl/kmeshctl.md +++ b/docs/ctl/kmeshctl.md @@ -14,6 +14,7 @@ Kmesh command line tools to operate and debug Kmesh * [kmeshctl dump](kmeshctl_dump.md) - Dump config of kernel-native or dual-engine mode * [kmeshctl log](kmeshctl_log.md) - Get or set kmesh-daemon's logger level * [kmeshctl monitoring](kmeshctl_monitoring.md) - Control Kmesh's monitoring to be turned on as needed +* [kmeshctl secret](kmeshctl_secret.md) - Use secrets to generate secret configuration data for IPsec * [kmeshctl version](kmeshctl_version.md) - Prints out build version info * [kmeshctl waypoint](kmeshctl_waypoint.md) - Manage waypoint configuration diff --git a/docs/ctl/kmeshctl_secret.md b/docs/ctl/kmeshctl_secret.md new file mode 100644 index 000000000..7d5b62057 --- /dev/null +++ b/docs/ctl/kmeshctl_secret.md @@ -0,0 +1,30 @@ +## kmeshctl secret + +Use secrets to generate secret configuration data for IPsec + +``` +kmeshctl secret [flags] +``` + +### Examples + +``` +# Use secrets to generate secret configuration data for IPsec: + kmeshctl secret --key or -k, only support use aead algo: rfc4106(gcm(aes)) + key need 36 characters(use 32 characters as key, 4 characters as salt). + Hexadecimal dump is required when the key is entered. + e.g.:kmeshctl secret --key=$(dd if=/dev/urandom count=36 bs=1 2>/dev/null | xxd -p -c 64) + e.g.:kmeshctl secret -k=$(echo -n "{36-character user-defined key here}" | xxd -p -c 64) +``` + +### Options + +``` + -h, --help help for secret + -k, --key string key of the encryption +``` + +### SEE ALSO + +* [kmeshctl](kmeshctl.md) - Kmesh command line tools to operate and debug Kmesh + diff --git a/docs/proposal/kmesh_support_encrypt.md b/docs/proposal/kmesh_support_encrypt.md new file mode 100644 index 000000000..416633071 --- /dev/null +++ b/docs/proposal/kmesh_support_encrypt.md @@ -0,0 +1,233 @@ +--- +title: Kmesh支持节点之间进行数据加密 +authors: +- "@bitcoffeeiux" +reviews: +- +approves: +- + +create-date: 2024-10-10 + +--- + +## 1.背景 + +随着网络安全威胁的增加,未经加密的数据在传输过程中容易被黑客或第三方监听、截取甚至篡改,导致敏感信息泄露。为了解决上述安全风险,Kmesh计划引入节点数据加密模式,为节点之间的通信流量进行加密,消除通讯过程中的安全风险。 + +## 2.使用场景 + +由Kmesh进行代理的节点,在数据从应用发出时,路由到指定的网络接口设备进行加密处理后再经过网络发送给对端。对端由特定的网络接口设备接收到数据后进行解密,上送给对应的服务应用。 + +![alt text](./pics/p2p_encryption.png) + +## 3.IPsec简介 + +IPsec是一个保护IP层通信的安全保密架构,是一个协议簇,通过对IP协议的分组进行加密和认证来保护IP协议的网络传输协议簇。运行在OSI模型的第三层(Internet Protocol,IP层),在VPN(virtual private networks)应用很广泛。 +有关IPsec的更多描述请参阅[什么是IPsec](https://info.support.huawei.com/info-finder/encyclopedia/zh/IPsec.html) + +## 4.Kmesh集成IPSec作为节点之间的加密工具 + +Kmesh仅使用IPSec的加密功能,IPSec的预共享密钥由用户设置在K8s后,传递至Kmesh进行管理并设置到IPSec中,保证IPSec的正常通信。整体架构图如下: + +![alt text](./pics/Kmesh_ipsec_workload.png) + +### 4.1 用户设置IPSec密钥 + +用户通过kmeshctl向K8s中设置名称为Kmesh-ipsec-keys的secret类型资源,格式如下: + + kmeshctl secret --key= + +当前仅支持rfc4106 gcm aes (aead)算法,该资源中包含有ipsec使用的aead key,以及ipsec的icv长度 + +### 4.2 CRD设计 + +Kmesh使能ipsec时,需要精细化控制ipsec数据加密行为,这其中要求Kmesh具有节点之间的信息同步机制。当前主要场景基于云原生业务场景,信息同步机制基于K8s集群api-server构建,依赖Kmesh自定义结构体来完成数据存储。 + +CRD数据结构定义如下: + + apiVersion: apiextensions.k8s.io/v1 + kind: CustomResourceDefinition + metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: kmeshnodeinfos.kmesh.net + spec: + group: kmesh.net + names: + kind: KmeshNodeInfo + listKind: KmeshNodeInfoList + plural: kmeshnodeinfos + singular: kmeshnodeinfo + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: KmeshNode is the Schema for the kmeshnodes API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + addresses: + description: |- + Addresses is used to store the internal ip address informatioon on the + host. The IP address information is used to generate the IPsec state + informatioon. IPsec uses this information to determine which network + adapter is used to encrypt and send data. + items: + type: string + type: array + bootID: + description: |- + bootid is used to generate the ipsec key. After the node is restarted, + the key needs to be updated. + type: string + podCIDRS: + description: |- + PodCIDRs used in IPsec checks the destination of the data to + determine which IPsec state is used for encryption. + items: + type: string + type: array + spi: + description: |- + The SPI is used to identify the version number of the current key. + The communication can be normal only when both communication parties + have spis and the spi keys are the same. + type: integer + required: + - addresses + - bootID + - podCIDRS + - spi + type: object + status: + type: object + type: object + served: true + storage: true + + +### 4.3 Kmesh IPsec通信路径 + +![alt text](./pics/ipsec_traffic_path.png) + +流量数据路径上需要新增一张map以及两个tc程序 + +- 加密路径新增map: + | 类型 | lpm前缀树map(4.11版本引入内核) | + |:-------:|:-------| + | 作用 | 在流量编排时,判断发送的对端pod所在的节点是否被Kmesh接管了,只有当两边的pod都被Kmesh接管,才会被ipsec加密 | + | key | bpf_lpm_trie_key {u32 prefixlen; u8 data[0]}; | + | value | uint32 | +- 新增2个tc: +在每个pod的容器出口网卡上新增一个tc程序,该tc程序用于将从pod中发出的流量打上mark,标记为走ipsec加密发出 + +在node网卡上新增tc程序,ipsec将数据包解密完成后进入tc程序,tc将数据包打上mark,转给对应的ipsec策略分发处理。如果没有这个tc程序,不在收包时打上mark,会导致非ipsec的数据包接收时出现丢包问题 + + +### 4.4 Kmesh IPSec操作 + +**规格限制** + +- 由于ipsec规则匹配时使用了mark标记,所以请保证当前环境中mark不会出现冲突 + + - 加密时使用的mark如下:0x000000e0,mask :0xffffffff + - 解密时使用的mark如下:0x000000d0,mask :0xffffffff + - 请勿与该mark使用相同的bit,导致数据包识别错误 + +- 数据从客户端发送时不能在iptables中为需要加密的流量开启地址伪装(masq)选项。地址伪装会使用snat技术,在服务端收到的ipsec数据包中,将流量src_ip伪装成nodeid,导致服务端ipsec无法正确匹配,数据包被丢弃 + + +**Kmesh-daemon启动时,完成以下动作:** + +- 从Kmesh-daemon读取secret信息并解析存储以下关键信息: + | 名称 | 作用 | + |:-------:|:-------| + | spi | 加密密钥的序列号,由kmeshctl secret自动生成spi | + | aead-algo | 密钥算法,当前仅支持rfc4106(gcm(aes)) | + | aead-key | 预共享密钥,所有的节点间的ipsec密钥从此密钥通过特定算法进行派生 | + | icv-len | 密钥长度 | + +- 获取本端的如下信息: + | 名称 | 作用 | + |:-------:|:-------| + | 本端的PodCIDR | 用于生成ipsec规则 | + | 本端的集群内部ip地址 | 用于生成nodeid,ipsec规则 | + | bootid | 启动id | + +- 从api-server中读取出所有kmeshNodeInfo节点信息,节点信息包含各node当前name,使用的spi版本号、ipsec设备的ip地址、bootID信息并开始生成ipsec规则,每个对端node需要生成2条state(一进一出),3条policy(out、in、fwd)。密钥从预共享密钥中进行派生,规则如下: + +出口密钥: 预共享密钥+本机IP+对端IP+本机bootid+对端bootID,hash后截取aead密钥长度 + +入口密钥: 预共享密钥+对端IP+本机IP+对端bootid+本机bootID,hash后截取aead密钥长度 + + ipsec示例:本机ip地址为7.6.122.84,获取到对端的node ip 地址信息为7.6.122.220,设置ipsec配置预览如下 + # state配置 + ip xfrm state add src 7.6.122.84 dst 7.6.122.220 proto esp spi 0x1 mode tunnel reqid 1 {\$aead-algo} {\$aead-出口密钥} {\$icv-len} + ip xfrm state add src 7.6.122.220 dst 7.6.122.84 proto esp spi 0x1 mode tunnel reqid 1 {\$aead-algo} {\$aead-入口密钥} {\$icv-len} + # policy配置 + + ip xfrm policy add src 0.0.0.0/0 dst {\$对端CIDR} dir out tmpl src 7.6.122.84 dst 7.6.122.220 proto esp spi 0x1 reqid 1 mode tunnel mark 0x000000e0 mask 0xffff + ip xfrm policy add src 0.0.0.0/0 dst {\$本端CIDR} dir in tmpl src 7.6.122.220 dst 7.6.122.84 proto esp reqid 1 mode tunnel mark 0x000000d0 mask 0xfffffff + ip xfrm policy add src 0.0.0.0/0 dst {\$本端CIDR} dir fwd tmpl src 7.6.122.220 dst 7.6.122.84 proto esp reqid 1 mode tunnel mark 0x000000d0 mask 0xfffffff + +- 更新lpm前缀树map,key为对端CIDR地址,value当前全部设置为1,tc根据目标pod ip在前缀树找到记录,确定对端pod为Kmesh纳管,为流量打上对应的加密、解密标签 +- Kmesh-daemon将本端的spi、IPsec设备ip、podCIDRs更新到api-server中,触发其他节点更新机器上的IPsec配置 + +**Kmesh-daemon检测到node节点新增时:** + +新增节点:可参考上一章节[Kmesh-daemon启动时,完成以下动作:] + +其他节点: + +- 新增节点将自己的kmeshNodeInfo信息上传api-server后,说明新增节点上IPsec规则已准备好 +- 本端需要创建ipsec in/fwd/out方向的state、policy规则 +- 本端更新map表,将对应的CIDR更新到lpm map中 + +**Kmesh-daemon退出时,完成以下动作:** + +退出节点: +- 清理api-server中的本node的kmeshNodeInfo信息 +- 清理当前node上ipsec的state、policy信息 +- 卸载tc程序 +- 清理lpm数据 + +其他节点: +- 本端删除退出节点的IPsec state、policy信息 +- 本端清理退出节点的lpm CIDR数据 + +**secret更新时,完成以下动作:** + +更新节点: +- Kmesh检测到当前secret更新后,需要对IPsec规则进行全量扫描更新 +- 遍历kmeshNodeInfo信息,执行以下动作: + - 如果对端的secret spi版本在本端记录的当前、历史spi中没有查询到,则什么也不做(无spi则缺失预共享密钥,无法生成密钥),可能是对端的spi比本端高,则等待下次secret更新时再触发更新 + - 使用新的spi创建所有到对端的in、fwd方向state,in/fwd方向policy支持多版本密钥解析,无需更新。 + - 如果对端的secret spi版本小于等于本端的secret spi,则创建out方向新的state,更新out方向的policy中spi到最新的spi版本 + - 如果对端的secret spi版本大于本端的secret spi,说明本端spi版本落后,等待secret版本更新时再生成out方向的state以及policy +- 更新自己的kmeshNodeInfo到api-server中 + +其他节点: +- 本端从api-server中读取到kmeshNodeInfo更新后,执行以下动作: + - 如果对端的secret spi版本在本端记录的当前、历史spi中没有查询到,则什么也不做(无spi则缺失预共享密钥,无法生成密钥),可能是对端的spi比本端高,则等待下次secret更新时再触发更新。也可能是对端的版本过低,低于本端Kmesh启动时的spi版本号,等待对端spi版本更新后再出发本端更新 + - 使用新的spi创建所有到对端的in、fwd方向state,in/fwd方向policy支持多版本密钥解析,无需更新 + - 如果对端的secret spi版本小于等于本端的secret spi,则创建out方向新的state,更新out方向的policy中spi到最新的spi版本 + - 如果对端的secret spi版本大于本端的secret spi,说明本端spi版本落后,等待secret版本更新时再生成out方向的state以及policy diff --git a/docs/proposal/pics/Kmesh_ipsec_workload.png b/docs/proposal/pics/Kmesh_ipsec_workload.png new file mode 100644 index 000000000..559fa2d6a Binary files /dev/null and b/docs/proposal/pics/Kmesh_ipsec_workload.png differ diff --git a/docs/proposal/pics/ipsec_traffic_path.png b/docs/proposal/pics/ipsec_traffic_path.png new file mode 100644 index 000000000..07391b748 Binary files /dev/null and b/docs/proposal/pics/ipsec_traffic_path.png differ diff --git a/docs/proposal/pics/p2p_encryption.png b/docs/proposal/pics/p2p_encryption.png new file mode 100644 index 000000000..3f24e240c Binary files /dev/null and b/docs/proposal/pics/p2p_encryption.png differ diff --git a/go.mod b/go.mod index 95b293222..dbadce720 100644 --- a/go.mod +++ b/go.mod @@ -18,11 +18,13 @@ require ( github.com/miekg/dns v1.1.62 github.com/prometheus/client_golang v1.20.5 github.com/prometheus/common v0.61.0 + github.com/safchain/ethtool v0.5.9 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.10.0 github.com/vishvananda/netlink v1.3.0 + golang.org/x/sys v0.28.0 google.golang.org/grpc v1.69.0 google.golang.org/protobuf v1.36.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1 @@ -206,7 +208,6 @@ require ( golang.org/x/net v0.32.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect golang.org/x/term v0.27.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.8.0 // indirect diff --git a/go.sum b/go.sum index c6459f0d7..96e5dd0df 100644 --- a/go.sum +++ b/go.sum @@ -378,6 +378,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/safchain/ethtool v0.5.9 h1://6RvaOKFf3nQ0rl5+8zBbE4/72455VC9Jq61pfq67E= +github.com/safchain/ethtool v0.5.9/go.mod h1:w8oSsZeowyRaM7xJJBAbubzzrOkwO8TBgPSEqPP/5mg= github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= @@ -561,6 +563,7 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/pkg/bpf/ads/loader.go b/pkg/bpf/ads/loader.go index d03b521df..8db2b9119 100644 --- a/pkg/bpf/ads/loader.go +++ b/pkg/bpf/ads/loader.go @@ -29,6 +29,7 @@ import ( "github.com/cilium/ebpf" "kmesh.net/kmesh/daemon/options" + "kmesh.net/kmesh/pkg/bpf/general" "kmesh.net/kmesh/pkg/bpf/utils" "kmesh.net/kmesh/pkg/consistenthash/maglev" "kmesh.net/kmesh/pkg/logger" @@ -38,6 +39,7 @@ var log = logger.NewLoggerScope("bpf_ads") type BpfAds struct { SockConn BpfSockConn + Tc *general.BpfTCGeneral } func NewBpfAds(cfg *options.BpfConfig) (*BpfAds, error) { @@ -45,6 +47,13 @@ func NewBpfAds(cfg *options.BpfConfig) (*BpfAds, error) { if err := sc.SockConn.NewBpf(cfg); err != nil { return nil, err } + if cfg.EnableIPsec { + var err error + sc.Tc, err = general.NewBpf(cfg) + if err != nil { + return nil, err + } + } return sc, nil } @@ -92,6 +101,10 @@ func (sc *BpfAds) Load() error { return err } + if err := sc.Tc.LoadTC(); err != nil { + return err + } + return nil } @@ -136,6 +149,9 @@ func (sc *BpfAds) Detach() error { if err := sc.SockConn.Detach(); err != nil { return err } + if err := sc.Tc.Close(); err != nil { + return err + } return nil } diff --git a/pkg/bpf/ads/loader_enhanced.go b/pkg/bpf/ads/loader_enhanced.go index 1f9332ff0..0be22da24 100644 --- a/pkg/bpf/ads/loader_enhanced.go +++ b/pkg/bpf/ads/loader_enhanced.go @@ -39,6 +39,7 @@ type BpfAds struct { TracePoint BpfTracePoint SockConn BpfSockConn SockOps BpfSockOps + Tc *general.BpfTCGeneral } func NewBpfAds(cfg *options.BpfConfig) (*BpfAds, error) { @@ -54,6 +55,15 @@ func NewBpfAds(cfg *options.BpfConfig) (*BpfAds, error) { if err := sc.SockConn.NewBpf(cfg); err != nil { return nil, err } + + if cfg.EnableIPsec { + var err error + sc.Tc, err = general.NewBpf(cfg) + if err != nil { + return nil, err + } + } + return sc, nil } @@ -108,6 +118,10 @@ func (sc *BpfAds) Load() error { return err } + if err := sc.Tc.LoadTC(); err != nil { + return err + } + return nil } @@ -171,6 +185,11 @@ func (sc *BpfAds) Detach() error { if err := sc.SockConn.Detach(); err != nil { return err } + + if err := sc.Tc.Close(); err != nil { + return err + } + return nil } diff --git a/pkg/bpf/ads/sock_connection.go b/pkg/bpf/ads/sock_connection.go index fff2a608a..f574a9368 100644 --- a/pkg/bpf/ads/sock_connection.go +++ b/pkg/bpf/ads/sock_connection.go @@ -34,6 +34,7 @@ import ( bpf2go "kmesh.net/kmesh/bpf/kmesh/bpf2go/kernelnative/normal" "kmesh.net/kmesh/daemon/options" + "kmesh.net/kmesh/pkg/bpf/general" "kmesh.net/kmesh/pkg/bpf/utils" helper "kmesh.net/kmesh/pkg/utils" ) @@ -45,17 +46,8 @@ var KMESH_TAIL_CALL_ROUTER = uint32(C.KMESH_TAIL_CALL_ROUTER) var KMESH_TAIL_CALL_CLUSTER = uint32(C.KMESH_TAIL_CALL_CLUSTER) var KMESH_TAIL_CALL_ROUTER_CONFIG = uint32(C.KMESH_TAIL_CALL_ROUTER_CONFIG) -type BpfInfo struct { - MapPath string - BpfFsPath string - Cgroup2Path string - - Type ebpf.ProgramType - AttachType ebpf.AttachType -} - type BpfSockConn struct { - Info BpfInfo + Info general.BpfInfo Link link.Link bpf2go.KmeshCgroupSockObjects } diff --git a/pkg/bpf/ads/sock_ops.go b/pkg/bpf/ads/sock_ops.go index 6f6391110..5117d429e 100644 --- a/pkg/bpf/ads/sock_ops.go +++ b/pkg/bpf/ads/sock_ops.go @@ -30,6 +30,7 @@ import ( bpf2go "kmesh.net/kmesh/bpf/kmesh/bpf2go/kernelnative/enhanced" "kmesh.net/kmesh/daemon/options" + "kmesh.net/kmesh/pkg/bpf/general" "kmesh.net/kmesh/pkg/bpf/restart" "kmesh.net/kmesh/pkg/bpf/utils" "kmesh.net/kmesh/pkg/constants" @@ -37,7 +38,7 @@ import ( ) type BpfSockOps struct { - Info BpfInfo + Info general.BpfInfo Link link.Link bpf2go.KmeshSockopsObjects } diff --git a/pkg/bpf/ads/trace_point.go b/pkg/bpf/ads/trace_point.go index 5f0258935..1cafd4f7b 100644 --- a/pkg/bpf/ads/trace_point.go +++ b/pkg/bpf/ads/trace_point.go @@ -29,13 +29,14 @@ import ( bpf2go "kmesh.net/kmesh/bpf/kmesh/bpf2go/kernelnative/enhanced" "kmesh.net/kmesh/daemon/options" + "kmesh.net/kmesh/pkg/bpf/general" "kmesh.net/kmesh/pkg/bpf/restart" "kmesh.net/kmesh/pkg/constants" helper "kmesh.net/kmesh/pkg/utils" ) type BpfTracePoint struct { - Info BpfInfo + Info general.BpfInfo Link link.Link bpf2go.KmeshTracePointObjects } diff --git a/pkg/bpf/general/bpfinfo.go b/pkg/bpf/general/bpfinfo.go new file mode 100644 index 000000000..d017d7ef3 --- /dev/null +++ b/pkg/bpf/general/bpfinfo.go @@ -0,0 +1,28 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package general + +import "github.com/cilium/ebpf" + +type BpfInfo struct { + MapPath string + BpfFsPath string + Cgroup2Path string + + Type ebpf.ProgramType + AttachType ebpf.AttachType +} diff --git a/pkg/bpf/general/tc.go b/pkg/bpf/general/tc.go new file mode 100644 index 000000000..a2d4f720e --- /dev/null +++ b/pkg/bpf/general/tc.go @@ -0,0 +1,169 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package general + +import ( + "os" + "reflect" + "syscall" + + "github.com/cilium/ebpf" + + "kmesh.net/kmesh/bpf/kmesh/bpf2go/general" + bpf2go_general "kmesh.net/kmesh/bpf/kmesh/bpf2go/general" + "kmesh.net/kmesh/daemon/options" + "kmesh.net/kmesh/pkg/bpf/utils" + "kmesh.net/kmesh/pkg/constants" + helper "kmesh.net/kmesh/pkg/utils" +) + +type BpfTCGeneral struct { + InfoTcMarkEncrypt BpfInfo + InfoTcMarkDecrypt BpfInfo + bpf2go_general.KmeshTcMarkEncryptObjects + bpf2go_general.KmeshTcMarkDecryptObjects +} + +func NewBpf(cfg *options.BpfConfig) (*BpfTCGeneral, error) { + tc := &BpfTCGeneral{} + + if err := tc.newBpf(&tc.InfoTcMarkEncrypt, &tc.InfoTcMarkDecrypt, cfg); err != nil { + return nil, err + } + + return tc, nil +} + +func (tc *BpfTCGeneral) newBpf(encryptInfo *BpfInfo, decryptInfo *BpfInfo, cfg *options.BpfConfig) error { + generalMapPath := cfg.BpfFsPath + "/bpf_kmesh_workload/map/" + generalFsPath := cfg.BpfFsPath + "/bpf_kmesh_workload/tc/" + + encryptInfo.MapPath = generalMapPath + encryptInfo.BpfFsPath = generalFsPath + encryptInfo.Cgroup2Path = cfg.Cgroup2Path + + decryptInfo.MapPath = generalMapPath + decryptInfo.BpfFsPath = generalFsPath + decryptInfo.Cgroup2Path = cfg.Cgroup2Path + + if err := os.MkdirAll(generalMapPath, + syscall.S_IRUSR|syscall.S_IWUSR|syscall.S_IXUSR| + syscall.S_IRGRP|syscall.S_IXGRP); err != nil && !os.IsExist(err) { + return err + } + + if err := os.MkdirAll(generalFsPath, + syscall.S_IRUSR|syscall.S_IWUSR|syscall.S_IXUSR| + syscall.S_IRGRP|syscall.S_IXGRP); err != nil && !os.IsExist(err) { + return err + } + + return nil +} + +func (tc *BpfTCGeneral) loadKmeshTCObjects() (*ebpf.CollectionSpec, *ebpf.CollectionSpec, error) { + var ( + errTcMarkEncrypt error + errTcMarkDecrypt error + specTcMarkEncrypt *ebpf.CollectionSpec + optsTcMarkEncrypt ebpf.CollectionOptions + specTcMarkDecrypt *ebpf.CollectionSpec + optsTcMarkDecrypt ebpf.CollectionOptions + ) + + optsTcMarkEncrypt.Maps.PinPath = tc.InfoTcMarkEncrypt.MapPath + optsTcMarkDecrypt.Maps.PinPath = tc.InfoTcMarkDecrypt.MapPath + if helper.KernelVersionLowerThan5_13() { + specTcMarkEncrypt, errTcMarkEncrypt = general.LoadKmeshTcMarkEncryptCompat() + specTcMarkDecrypt, errTcMarkDecrypt = general.LoadKmeshTcMarkDecryptCompat() + } else { + specTcMarkEncrypt, errTcMarkEncrypt = general.LoadKmeshTcMarkEncrypt() + specTcMarkDecrypt, errTcMarkDecrypt = general.LoadKmeshTcMarkDecrypt() + } + + if errTcMarkEncrypt != nil { + return nil, nil, errTcMarkEncrypt + } + + if errTcMarkDecrypt != nil { + return nil, nil, errTcMarkDecrypt + } + + utils.SetMapPinType(specTcMarkEncrypt, ebpf.PinByName) + utils.SetMapPinType(specTcMarkDecrypt, ebpf.PinByName) + if err := specTcMarkEncrypt.LoadAndAssign(&tc.KmeshTcMarkEncryptObjects, &optsTcMarkEncrypt); err != nil { + return nil, nil, err + } + if err := specTcMarkDecrypt.LoadAndAssign(&tc.KmeshTcMarkDecryptObjects, &optsTcMarkDecrypt); err != nil { + return nil, nil, err + } + + return specTcMarkEncrypt, specTcMarkDecrypt, nil +} + +func (tc *BpfTCGeneral) LoadTC() error { + if tc == nil { + return nil + } + specMarkEncrypt, specMarkDecrypt, err := tc.loadKmeshTCObjects() + if err != nil { + return err + } + + prog := specMarkEncrypt.Programs[constants.TC_MARK_ENCRYPT] + tc.InfoTcMarkEncrypt.Type = prog.Type + tc.InfoTcMarkEncrypt.AttachType = prog.AttachType + + prog = specMarkDecrypt.Programs[constants.TC_MARK_DECRYPT] + tc.InfoTcMarkDecrypt.Type = prog.Type + tc.InfoTcMarkDecrypt.AttachType = prog.AttachType + + return nil +} + +func (tc *BpfTCGeneral) Close() error { + if tc == nil { + return nil + } + + if err := tc.KmeshTcMarkEncryptObjects.Close(); err != nil { + return err + } + if err := tc.KmeshTcMarkDecryptObjects.Close(); err != nil { + return err + } + + progVal := reflect.ValueOf(tc.KmeshTcMarkEncryptObjects.KmeshTcMarkEncryptPrograms) + if err := utils.UnpinPrograms(&progVal); err != nil { + return err + } + progVal = reflect.ValueOf(tc.KmeshTcMarkDecryptObjects.KmeshTcMarkDecryptPrograms) + if err := utils.UnpinPrograms(&progVal); err != nil { + return err + } + + mapVal := reflect.ValueOf(tc.KmeshTcMarkEncryptObjects.KmeshTcMarkEncryptMaps) + if err := utils.UnpinMaps(&mapVal); err != nil { + return err + } + mapVal = reflect.ValueOf(tc.KmeshTcMarkDecryptObjects.KmeshTcMarkDecryptMaps) + if err := utils.UnpinMaps(&mapVal); err != nil { + return err + } + + return nil +} diff --git a/pkg/bpf/workload/loader.go b/pkg/bpf/workload/loader.go index 4e8083dbb..d7c9cf879 100644 --- a/pkg/bpf/workload/loader.go +++ b/pkg/bpf/workload/loader.go @@ -26,6 +26,7 @@ import ( "github.com/cilium/ebpf" "kmesh.net/kmesh/daemon/options" + "kmesh.net/kmesh/pkg/bpf/general" "kmesh.net/kmesh/pkg/bpf/utils" "kmesh.net/kmesh/pkg/logger" ) @@ -37,15 +38,7 @@ type BpfWorkload struct { SockOps BpfSockOpsWorkload XdpAuth BpfXdpAuthWorkload SendMsg BpfSendMsgWorkload -} - -type BpfInfo struct { - MapPath string - BpfFsPath string - Cgroup2Path string - - Type ebpf.ProgramType - AttachType ebpf.AttachType + Tc *general.BpfTCGeneral } func NewBpfWorkload(cfg *options.BpfConfig) (*BpfWorkload, error) { @@ -68,6 +61,13 @@ func NewBpfWorkload(cfg *options.BpfConfig) (*BpfWorkload, error) { return nil, err } + if cfg.EnableIPsec { + var err error + workloadObj.Tc, err = general.NewBpf(cfg) + if err != nil { + return nil, err + } + } return workloadObj, nil } @@ -121,6 +121,10 @@ func (w *BpfWorkload) Load() error { if err := w.SendMsg.LoadSendMsg(); err != nil { return err } + + if err := w.Tc.LoadTC(); err != nil { + return err + } return nil } @@ -157,6 +161,10 @@ func (w *BpfWorkload) Detach() error { return err } + if err := w.Tc.Close(); err != nil { + return err + } + return nil } diff --git a/pkg/bpf/workload/sendmsg.go b/pkg/bpf/workload/sendmsg.go index 84a6db9c7..722b24154 100644 --- a/pkg/bpf/workload/sendmsg.go +++ b/pkg/bpf/workload/sendmsg.go @@ -27,13 +27,14 @@ import ( bpf2go "kmesh.net/kmesh/bpf/kmesh/bpf2go/dualengine" "kmesh.net/kmesh/daemon/options" + "kmesh.net/kmesh/pkg/bpf/general" "kmesh.net/kmesh/pkg/bpf/restart" "kmesh.net/kmesh/pkg/bpf/utils" helper "kmesh.net/kmesh/pkg/utils" ) type BpfSendMsgWorkload struct { - Info BpfInfo + Info general.BpfInfo AttachFD int bpf2go.KmeshSendmsgObjects diff --git a/pkg/bpf/workload/sock_connection.go b/pkg/bpf/workload/sock_connection.go index 995f7f6d5..b30d0d80e 100644 --- a/pkg/bpf/workload/sock_connection.go +++ b/pkg/bpf/workload/sock_connection.go @@ -27,6 +27,7 @@ import ( bpf2go "kmesh.net/kmesh/bpf/kmesh/bpf2go/dualengine" "kmesh.net/kmesh/daemon/options" + "kmesh.net/kmesh/pkg/bpf/general" "kmesh.net/kmesh/pkg/bpf/restart" "kmesh.net/kmesh/pkg/bpf/utils" "kmesh.net/kmesh/pkg/constants" @@ -34,9 +35,9 @@ import ( ) type SockConnWorkload struct { - Info BpfInfo + Info general.BpfInfo Link link.Link - Info6 BpfInfo + Info6 general.BpfInfo Link6 link.Link bpf2go.KmeshCgroupSockWorkloadObjects } diff --git a/pkg/bpf/workload/sock_ops.go b/pkg/bpf/workload/sock_ops.go index da8a33cff..b6211b722 100644 --- a/pkg/bpf/workload/sock_ops.go +++ b/pkg/bpf/workload/sock_ops.go @@ -28,13 +28,14 @@ import ( bpf2go "kmesh.net/kmesh/bpf/kmesh/bpf2go/dualengine" "kmesh.net/kmesh/daemon/options" + "kmesh.net/kmesh/pkg/bpf/general" "kmesh.net/kmesh/pkg/bpf/restart" "kmesh.net/kmesh/pkg/bpf/utils" helper "kmesh.net/kmesh/pkg/utils" ) type BpfSockOpsWorkload struct { - Info BpfInfo + Info general.BpfInfo Link link.Link bpf2go.KmeshSockopsWorkloadObjects } diff --git a/pkg/bpf/workload/xdp.go b/pkg/bpf/workload/xdp.go index 2205b3e03..a0106166d 100644 --- a/pkg/bpf/workload/xdp.go +++ b/pkg/bpf/workload/xdp.go @@ -26,13 +26,14 @@ import ( bpf2go "kmesh.net/kmesh/bpf/kmesh/bpf2go/dualengine" "kmesh.net/kmesh/daemon/options" + "kmesh.net/kmesh/pkg/bpf/general" "kmesh.net/kmesh/pkg/bpf/utils" "kmesh.net/kmesh/pkg/constants" helper "kmesh.net/kmesh/pkg/utils" ) type BpfXdpAuthWorkload struct { - Info BpfInfo + Info general.BpfInfo bpf2go.KmeshXDPAuthObjects } diff --git a/pkg/cni/chained.go b/pkg/cni/chained.go index 3f00cbe6f..0ed09a91c 100644 --- a/pkg/cni/chained.go +++ b/pkg/cni/chained.go @@ -117,12 +117,13 @@ func (i *Installer) insertCNIConfig(oldconfig []byte, mode string) ([]byte, erro } } - kmeshConfig := map[string]string{} + kmeshConfig := map[string]any{} kubeconfigFilepath := filepath.Join(i.CniMountNetEtcDIR, kmeshCniKubeConfig) // add kmesh-cni configuration kmeshConfig["type"] = kmeshCniPluginName kmeshConfig["kubeConfig"] = kubeconfigFilepath kmeshConfig["mode"] = mode // provide mode here, so that kmesh-cni can decide how to run + kmeshConfig["enableIpSec"] = i.EnableIpSec if kmeshIndex >= 0 { plugins[kmeshIndex] = kmeshConfig cniConfigMap["plugins"] = plugins diff --git a/pkg/cni/chained_test.go b/pkg/cni/chained_test.go index 1273de6e9..a259c4de5 100644 --- a/pkg/cni/chained_test.go +++ b/pkg/cni/chained_test.go @@ -204,7 +204,7 @@ func TestGetCniConfigPath(t *testing.T) { t.Run(tt.name, func(t *testing.T) { config := tt.utconfig tt.beforeFunc() - i := NewInstaller(constants.KernelNativeMode, config.CniMountNetEtcDIR, config.CniConfigName, config.CniConfigChained, "") + i := NewInstaller(constants.KernelNativeMode, false, config.CniMountNetEtcDIR, config.CniConfigName, config.CniConfigChained, "") _, err := i.getCniConfigPath() if (err != nil) != tt.wantErr { t.Errorf("getCniConfigPath() error = %v, wantErr %v", err, tt.wantErr) @@ -307,7 +307,7 @@ func TestInsertCNIConfig(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.beforeFunc() - i := NewInstaller(constants.KernelNativeMode, "", "", true, "") + i := NewInstaller(constants.KernelNativeMode, false, "", "", true, "") _, err := i.insertCNIConfig(tt.utconfig, "workload") if (err != nil) != tt.wantErr { t.Errorf("insertCNIConfig() error = %v, wantErr %v", err, tt.wantErr) diff --git a/pkg/cni/install.go b/pkg/cni/install.go index f234889fd..0054c1e5f 100644 --- a/pkg/cni/install.go +++ b/pkg/cni/install.go @@ -55,6 +55,7 @@ func (i *Installer) removeCniConfig() error { type Installer struct { Mode string + EnableIpSec bool CniMountNetEtcDIR string CniConfigName string CniConfigChained bool @@ -64,12 +65,14 @@ type Installer struct { } func NewInstaller(mode string, + enableIpSec bool, cniMountNetEtcDIR string, cniConfigName string, cniConfigChained bool, serviceAccountPath string) *Installer { return &Installer{ Mode: mode, + EnableIpSec: enableIpSec, CniMountNetEtcDIR: cniMountNetEtcDIR, CniConfigName: cniConfigName, CniConfigChained: cniConfigChained, diff --git a/pkg/cni/install_test.go b/pkg/cni/install_test.go index 43031c098..f9e1c522e 100644 --- a/pkg/cni/install_test.go +++ b/pkg/cni/install_test.go @@ -43,7 +43,7 @@ func TestWatchTokenFile(t *testing.T) { cniDir := t.TempDir() - i := NewInstaller(constants.DualEngineMode, cniDir, "conflist-name", true, serviceAccountPath) + i := NewInstaller(constants.DualEngineMode, false, cniDir, "conflist-name", true, serviceAccountPath) defer i.Watcher.Close() kubeconfigPath := filepath.Join(i.CniMountNetEtcDIR, kmeshCniKubeConfig) diff --git a/pkg/cni/plugin/plugin.go b/pkg/cni/plugin/plugin.go index fb0e823ce..af779a3a7 100644 --- a/pkg/cni/plugin/plugin.go +++ b/pkg/cni/plugin/plugin.go @@ -47,8 +47,9 @@ type cniConf struct { types.NetConf // Add plugin-specific flags here - KubeConfig string `json:"kubeconfig,omitempty"` - Mode string `json:"mode,omitempty"` + KubeConfig string `json:"kubeconfig,omitempty"` + Mode string `json:"mode,omitempty"` + EnableIpSec bool `json:"enableIpSec,omitempty"` } // K8sArgs parameter is used to transfer the k8s information transferred @@ -129,6 +130,45 @@ func enableXdpAuth(ifname string) error { return nil } +func enableTcMarkEncrypt(args *skel.CmdArgs) error { + var ( + err error + link netlink.Link + tc *ebpf.Program + ifIndex uint64 + ) + + ifIndex = 0 + + if tc, err = utils.GetProgramByName(constants.TC_MARK_ENCRYPT); err != nil { + return fmt.Errorf("failed to get tc program: %v", err) + } + + getVethPeerIndexFunc := func(netns.NetNS) error { + ifIndex, err = utils.GetVethPeerIndexFromName(args.IfName) + return err + } + + if err := netns.WithNetNSPath(args.Netns, getVethPeerIndexFunc); err != nil { + log.Errorf("failed to get veth peer link number, %v", err) + return err + } + + if ifIndex == 0 { + return fmt.Errorf("failed to find valid peer interface index, ifname: %v", args.IfName) + } + + if link, err = netlink.LinkByIndex(int(ifIndex)); err != nil { + return fmt.Errorf("failed to link valid interface, %v", err) + } + + if err = utils.ManageTCProgram(link, tc, constants.TC_ATTACH); err != nil { + return fmt.Errorf("failed to attach tc program, %v", err) + } + + return nil +} + // if cmdadd failed, then we cannot return failed, do nothing and print pre result func CmdAdd(args *skel.CmdArgs) error { var err error @@ -190,12 +230,19 @@ func CmdAdd(args *skel.CmdArgs) error { return nil } - if err := netns.WithNetNSPath(string(args.Netns), enableXDPFunc); err != nil { + if err := netns.WithNetNSPath(args.Netns, enableXDPFunc); err != nil { log.Error(err) return err } } + if cniConf.EnableIpSec { + if err := enableTcMarkEncrypt(args); err != nil { + err = fmt.Errorf("failed to link tc program(set encryption marker) to dev %v, err is %v", args.IfName, err) + return err + } + } + return types.PrintResult(preResult, cniConf.CNIVersion) } diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index dc741271d..146f29636 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -31,6 +31,12 @@ const ( ENABLED = uint32(1) DISABLED = uint32(0) + TC_MARK_DECRYPT = "tc_mark_decrypt" + TC_MARK_ENCRYPT = "tc_mark_encrypt" + + TC_ATTACH = 0 + TC_DETACH = 1 + RootCertPath = "/var/run/secrets/istio/root-cert.pem" TrustDomain = "cluster.local" @@ -69,4 +75,6 @@ const ( TailCallMap = "tail_call_map" Prog_link = "prog_link" + + ALL_CIDR = "0.0.0.0/0" ) diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index aa1ba7387..15689729f 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -20,12 +20,15 @@ import ( "context" "fmt" + "github.com/cilium/ebpf" + "kmesh.net/kmesh/daemon/options" "kmesh.net/kmesh/pkg/bpf" bpfads "kmesh.net/kmesh/pkg/bpf/ads" bpfwl "kmesh.net/kmesh/pkg/bpf/workload" "kmesh.net/kmesh/pkg/constants" "kmesh.net/kmesh/pkg/controller/bypass" + "kmesh.net/kmesh/pkg/controller/encryption/ipsec" manage "kmesh.net/kmesh/pkg/controller/manage" "kmesh.net/kmesh/pkg/controller/security" "kmesh.net/kmesh/pkg/dns" @@ -44,6 +47,7 @@ type Controller struct { bpfAdsObj *bpfads.BpfAds bpfWorkloadObj *bpfwl.BpfWorkload client *XdsClient + ipsecController *ipsec.IPSecController enableByPass bool enableSecretManager bool bpfConfig *options.BpfConfig @@ -63,12 +67,35 @@ func NewController(opts *options.BootstrapConfigs, bpfAdsObj *bpfads.BpfAds, bpf func (c *Controller) Start(stopCh <-chan struct{}) error { var err error var kmeshManageController *manage.KmeshManageController + var tcFd int clientset, err := kube.CreateKubeClient("") if err != nil { return err } + if c.bpfConfig.EnableIPsec { + var kniMap *ebpf.Map + var decryptProg *ebpf.Program + if c.mode == constants.KernelNativeMode { + kniMap = c.bpfAdsObj.Tc.KmeshTcMarkEncryptObjects.KmNodeinfo + tcFd = c.bpfAdsObj.Tc.TcMarkEncrypt.FD() + decryptProg = c.bpfAdsObj.Tc.KmeshTcMarkDecryptObjects.TcMarkDecrypt + } else { + kniMap = c.bpfWorkloadObj.Tc.KmeshTcMarkEncryptObjects.KmNodeinfo + tcFd = c.bpfWorkloadObj.Tc.TcMarkEncrypt.FD() + decryptProg = c.bpfWorkloadObj.Tc.KmeshTcMarkDecryptObjects.TcMarkDecrypt + } + c.ipsecController, err = ipsec.NewIPsecController(clientset, kniMap, decryptProg) + if err != nil { + return fmt.Errorf("failed to new IPsec controller, %v", err) + } + go c.ipsecController.Run(stopCh) + log.Info("start IPsec controller successfully") + } else { + tcFd = -1 + } + if c.mode == constants.DualEngineMode { var secertManager *security.SecretManager if c.enableSecretManager { @@ -78,9 +105,9 @@ func (c *Controller) Start(stopCh <-chan struct{}) error { } go secertManager.Run(stopCh) } - kmeshManageController, err = manage.NewKmeshManageController(clientset, secertManager, c.bpfWorkloadObj.XdpAuth.XdpAuthz.FD(), c.mode) + kmeshManageController, err = manage.NewKmeshManageController(clientset, secertManager, c.bpfWorkloadObj.XdpAuth.XdpAuthz.FD(), tcFd, c.mode) } else { - kmeshManageController, err = manage.NewKmeshManageController(clientset, nil, -1, c.mode) + kmeshManageController, err = manage.NewKmeshManageController(clientset, nil, -1, tcFd, c.mode) } if err != nil { return fmt.Errorf("failed to start kmesh manage controller: %v", err) @@ -119,6 +146,7 @@ func (c *Controller) Start(stopCh <-chan struct{}) error { return fmt.Errorf("Failed to update config in order to start metric: %v", err) } } + c.client = NewXdsClient(c.mode, c.bpfAdsObj, c.bpfWorkloadObj, c.bpfConfig.EnableMonitoring, c.bpfConfig.EnableProfiling) if c.client.WorkloadController != nil { @@ -142,6 +170,9 @@ func (c *Controller) Stop() { return } cancel() + if c.bpfConfig.EnableIPsec { + c.ipsecController.Stop() + } if c.client != nil { c.client.Close() } diff --git a/pkg/controller/encryption/ipsec/ipsec_controller.go b/pkg/controller/encryption/ipsec/ipsec_controller.go new file mode 100644 index 000000000..c9640da93 --- /dev/null +++ b/pkg/controller/encryption/ipsec/ipsec_controller.go @@ -0,0 +1,493 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ipsec + +import ( + "context" + "encoding/binary" + "fmt" + "net" + "net/netip" + "os" + "reflect" + "strings" + + "github.com/cilium/ebpf" + netns "github.com/containernetworking/plugins/pkg/ns" + "github.com/vishvananda/netlink" + v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/util/workqueue" + + "kmesh.net/kmesh/pkg/bpf/restart" + "kmesh.net/kmesh/pkg/constants" + kmesh_netns "kmesh.net/kmesh/pkg/controller/netns" + "kmesh.net/kmesh/pkg/kube" + v1alpha1 "kmesh.net/kmesh/pkg/kube/apis/kmeshnodeinfo/v1alpha1" + v1alpha1_clientset "kmesh.net/kmesh/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1" + informer "kmesh.net/kmesh/pkg/kube/nodeinfo/informers/externalversions" + kmeshnodeinfov1alpha1 "kmesh.net/kmesh/pkg/kube/nodeinfo/listers/kmeshnodeinfo/v1alpha1" + "kmesh.net/kmesh/pkg/logger" + "kmesh.net/kmesh/pkg/utils" +) + +const ( + MaxRetries = 5 +) + +var log = logger.NewLoggerScope("ipsec_controller") + +type lpmKey struct { + prefix uint32 + ip [4]uint32 +} + +type IPSecController struct { + informer cache.SharedIndexInformer + lister kmeshnodeinfov1alpha1.KmeshNodeInfoLister + queue workqueue.TypedRateLimitingInterface[any] + knclient v1alpha1_clientset.KmeshNodeInfoInterface + kmeshNodeInfo v1alpha1.KmeshNodeInfo + ipsecHandler *IpSecHandler + kniMap *ebpf.Map + tcDecryptProg *ebpf.Program +} + +func NewIPsecController(k8sClientSet kubernetes.Interface, kniMap *ebpf.Map, decryptProg *ebpf.Program) (*IPSecController, error) { + clientSet, err := kube.GetKmeshNodeInfoClient() + if err != nil { + return nil, fmt.Errorf("failed to get kmesh node info client: %v", err) + } + factroy := informer.NewSharedInformerFactory(clientSet, 0) + nodeinfoLister := factroy.Kmesh().V1alpha1().KmeshNodeInfos().Lister() + nodeinfoInformer := factroy.Kmesh().V1alpha1().KmeshNodeInfos().Informer() + + ipsecController := &IPSecController{ + informer: nodeinfoInformer, + lister: nodeinfoLister, + queue: workqueue.NewTypedRateLimitingQueue(workqueue.DefaultTypedControllerRateLimiter[any]()), + knclient: clientSet.KmeshV1alpha1().KmeshNodeInfos(kube.KmeshNamespace), + ipsecHandler: NewIpSecHandler(), + kniMap: kniMap, + tcDecryptProg: decryptProg, + } + + // load ipsec info + err = ipsecController.ipsecHandler.LoadIPSecKeyFromFile(IpSecKeyFile) + if err != nil { + return nil, fmt.Errorf("failed to load ipsec key from file %s: %v", IpSecKeyFile, err) + } + + localNodeName := os.Getenv("NODE_NAME") + + localNode, err := k8sClientSet.CoreV1().Nodes().Get(context.TODO(), localNodeName, metav1.GetOptions{}) + if err != nil { + return nil, fmt.Errorf("failed to get kmesh node info from k8s: %v", err) + } + + ipsecController.kmeshNodeInfo = v1alpha1.KmeshNodeInfo{ + ObjectMeta: metav1.ObjectMeta{ + Name: localNodeName, + }, + Spec: v1alpha1.KmeshNodeInfoSpec{ + SPI: ipsecController.ipsecHandler.Spi, + Addresses: []string{}, + BootID: localNode.Status.NodeInfo.BootID, + PodCIDRs: localNode.Spec.PodCIDRs, + }, + } + for _, addr := range localNode.Status.Addresses { + if strings.Compare(string(addr.Type), string(v1.NodeInternalIP)) == 0 { + ipsecController.kmeshNodeInfo.Spec.Addresses = append(ipsecController.kmeshNodeInfo.Spec.Addresses, addr.Address) + } + } + + if _, err := nodeinfoInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + ipsecController.handleKNIAdd(obj) + }, + UpdateFunc: func(oldObj, newObj interface{}) { + ipsecController.handleKNIUpdate(oldObj, newObj) + }, + DeleteFunc: func(obj interface{}) { + ipsecController.handleKNIDelete(obj) + }, + }); err != nil { + return nil, fmt.Errorf("failed to add event handler to kmeshnodeinfoInformer: %v", err) + } + + return ipsecController, nil +} + +func (c *IPSecController) Run(stop <-chan struct{}) { + defer c.queue.ShutDown() + go c.informer.Run(stop) + if !cache.WaitForCacheSync(stop, c.informer.HasSynced) { + log.Error("timed out waiting for caches to sync") + return + } + + if err := c.attachTcDecrypt(); err != nil { + log.Errorf("%v", err) + return + } + + // create xfrm in rule, current host not update my kmeshnodeinfo + // the peer end does not use the key of the current host to send encrypted data. + if err := c.syncAllNodeInfo(); err != nil { + log.Errorf("failed to sync all node info: %v", err) + return + } + + // update my kmesh node info, notify other machines that the key can be updated. + if err := c.updateLocalKmeshNodeInfo(); err != nil { + log.Errorf("failed to update local node info: %v", err) + return + } + + if err := c.ipsecHandler.StartWatch(c.handleIpsecUpdate); err != nil { + log.Errorf("failed to start watch file: %v", err) + return + } + + go wait.Until(func() { + for c.processNextItem() { + } + }, 0, stop) + + <-stop +} + +func (c *IPSecController) Stop() { + c.ipsecHandler.StopWatch() + if restart.GetStartType() == restart.Normal { + _ = c.knclient.Delete(context.TODO(), c.kmeshNodeInfo.Name, metav1.DeleteOptions{}) + _ = c.detachTcDecrypt() + c.CleanAllIPsec() + } +} + +func (c *IPSecController) handleTc(mode int) error { + ifaces, err := net.Interfaces() + if err != nil { + return fmt.Errorf("failed to get interfaces: %v", err) + } + + for _, iface := range ifaces { + if iface.Flags&net.FlagLoopback != 0 { + continue + } + + find, err := utils.IfaceContainIPs(iface, c.kmeshNodeInfo.Spec.Addresses) + if err != nil { + log.Warnf("%v", err) + continue + } + + if find { + link, err := netlink.LinkByName(iface.Name) + if err != nil { + log.Warnf("failed to link interface %v, %v", iface, err) + continue + } + err = utils.ManageTCProgram(link, c.tcDecryptProg, mode) + if err != nil { + log.Warnf("failed to attach tc ebpf on interface %v, %v", iface, err) + continue + } + } + } + return nil +} + +func (c *IPSecController) attachTcDecrypt() error { + nodeNsPath := kmesh_netns.GetNodeNSpath() + attachFunc := func(netns.NetNS) error { + return c.handleTc(constants.TC_ATTACH) + } + + if err := netns.WithNetNSPath(nodeNsPath, attachFunc); err != nil { + return fmt.Errorf("failed to exec tc program attach, %v", err) + } + return nil +} + +func (c *IPSecController) detachTcDecrypt() error { + nodeNsPath := kmesh_netns.GetNodeNSpath() + detachFunc := func(netns.NetNS) error { + return c.handleTc(constants.TC_DETACH) + } + + if err := netns.WithNetNSPath(nodeNsPath, detachFunc); err != nil { + log.Errorf("failed to exec tc program detach, %v", err) + } + return nil +} + +func (c *IPSecController) handleKNIAdd(obj interface{}) { + kni, ok := obj.(*v1alpha1.KmeshNodeInfo) + if !ok { + log.Errorf("expected *v1alpha1_core.KmeshNodeInfo but got %T in handle add func", obj) + return + } + + if kni.Name == c.kmeshNodeInfo.Name { + return + } + c.queue.AddRateLimited(kni.Name) +} + +func (c *IPSecController) handleKNIUpdate(oldObj, newObj interface{}) { + newKni, okNew := newObj.(*v1alpha1.KmeshNodeInfo) + if !okNew { + log.Errorf("expected *v1alpha1_core.KmeshNodeInfo but got %T in handle update new obj func", newObj) + return + } + + oldKni, okold := oldObj.(*v1alpha1.KmeshNodeInfo) + if !okold { + log.Errorf("expected *v1alpha1_core.KmeshNodeInfo but got %T in handle update old obj func", oldObj) + return + } + + if newKni.Name == c.kmeshNodeInfo.Name { + return + } + + if reflect.DeepEqual(oldKni.Spec, newKni.Spec) { + return + } + + c.queue.AddRateLimited(newKni.Name) +} + +func (c *IPSecController) handleKNIDelete(obj interface{}) { + node, ok := obj.(*v1alpha1.KmeshNodeInfo) + if !ok { + log.Errorf("expected *v1alpha1_core.KmeshNodeInfo but got %T in handle delete func", obj) + return + } + nodeNsPath := kmesh_netns.GetNodeNSpath() + deleteFunc := func(netns.NetNS) error { + for _, targetIP := range node.Spec.Addresses { + c.ipsecHandler.mutex.Lock() + _ = c.ipsecHandler.Clean(targetIP) + c.ipsecHandler.mutex.Unlock() + } + return nil + } + _ = netns.WithNetNSPath(nodeNsPath, deleteFunc) + for _, podCIDR := range node.Spec.PodCIDRs { + c.deleteKNIMapCIDR(podCIDR, c.kniMap) + } +} + +func (c *IPSecController) handleOneNodeInfo(node *v1alpha1.KmeshNodeInfo) error { + // can't change ipsec information when process + c.ipsecHandler.mutex.Lock() + defer c.ipsecHandler.mutex.Unlock() + + nodeNsPath := kmesh_netns.GetNodeNSpath() + + handleFunc := func(netns.NetNS) error { + return c.ipsecHandler.CreateXfrmRule(&c.kmeshNodeInfo, node) + } + if err := netns.WithNetNSPath(nodeNsPath, handleFunc); err != nil { + return err + } + + for _, podCIDR := range node.Spec.PodCIDRs { + if err := c.updateKNIMapCIDR(podCIDR, c.kniMap); err != nil { + return fmt.Errorf("update kni map podCIDR failed, %v", err) + } + } + + return nil +} + +func (c *IPSecController) generalKNIMapKey(remoteCIDR string) (*lpmKey, error) { + prefix, err := netip.ParsePrefix(remoteCIDR) + if err != nil { + err = fmt.Errorf("update kni map podCIDR failed, podCIDR is %v, %v", remoteCIDR, err) + return nil, err + } + kniKey := &lpmKey{ + prefix: uint32(prefix.Bits()), + } + + bytes := prefix.Masked().Addr().AsSlice() + if len(bytes) == 4 { + kniKey.ip[0] = binary.LittleEndian.Uint32(bytes) + } else if len(bytes) == 16 { + kniKey.ip[0] = binary.LittleEndian.Uint32(bytes[:4]) + kniKey.ip[1] = binary.LittleEndian.Uint32(bytes[4:8]) + kniKey.ip[2] = binary.LittleEndian.Uint32(bytes[8:12]) + kniKey.ip[3] = binary.LittleEndian.Uint32(bytes[12:]) + } + return kniKey, nil +} + +func (c *IPSecController) updateKNIMapCIDR(remoteCIDR string, mapfd *ebpf.Map) error { + kniKey, err := c.generalKNIMapKey(remoteCIDR) + if err != nil { + return err + } + + kniValue := uint32(1) + + return mapfd.Update(kniKey, &kniValue, ebpf.UpdateAny) +} + +func (c *IPSecController) deleteKNIMapCIDR(remoteCIDR string, mapfd *ebpf.Map) { + kniKey, err := c.generalKNIMapKey(remoteCIDR) + if err != nil { + return + } + _ = mapfd.Delete(kniKey) +} + +func (c *IPSecController) syncAllNodeInfo() error { + nodeList, err := c.lister.KmeshNodeInfos(kube.KmeshNamespace).List(labels.Everything()) + if err != nil { + return fmt.Errorf("failed to get kmesh node info list: %v", err) + } + for _, node := range nodeList { + if node.Name == c.kmeshNodeInfo.Name { + continue + } + if err = c.handleOneNodeInfo(node); err != nil { + log.Errorf("failed to create xfrm rule for node %v: err: %v", node.Name, err) + } + } + return nil +} + +func (c *IPSecController) updateLocalKmeshNodeInfo() error { + node, _ := c.lister.KmeshNodeInfos(kube.KmeshNamespace).Get(c.kmeshNodeInfo.Name) + if node == nil { + _, err := c.knclient.Create(context.TODO(), &c.kmeshNodeInfo, metav1.CreateOptions{}) + if err != nil { + return fmt.Errorf("failed to create kmesh node info: %v", err) + } + return nil + } + + if reflect.DeepEqual(node.Spec, c.kmeshNodeInfo.Spec) { + return nil + } + node = node.DeepCopy() + node.Spec = c.kmeshNodeInfo.Spec + _, err := c.knclient.Update(context.TODO(), node, metav1.UpdateOptions{}) + if err != nil { + return fmt.Errorf("failed to update kmeshinfo, %v", err) + } + return nil +} + +func (c *IPSecController) CleanAllIPsec() { + nodeNsPath := kmesh_netns.GetNodeNSpath() + cleanFunc := func(netns.NetNS) error { + c.ipsecHandler.Flush() + return nil + } + + _ = netns.WithNetNSPath(nodeNsPath, cleanFunc) +} + +func (c *IPSecController) processNextItem() bool { + key, quit := c.queue.Get() + if quit { + return false + } + defer c.queue.Done(key) + + name, ok := key.(string) + if !ok { + log.Errorf("expected QueueItem but got %T", key) + return true + } + + node, err := c.lister.KmeshNodeInfos(kube.KmeshNamespace).Get(name) + if err != nil { + if !apierrors.IsNotFound(err) { + log.Errorf("failed to get kmesh node info %s: %v", name, err) + } + return true + } + if err := c.handleOneNodeInfo(node); err != nil { + if c.queue.NumRequeues(key) < MaxRetries { + log.Errorf("failed to handle other node %s err: %v, will retry", name, err) + c.queue.AddRateLimited(key) + } else { + log.Errorf("failed to handle other node %s err: %v, giving up", name, err) + c.queue.Forget(key) + } + } + + c.queue.Forget(key) + return true +} + +// this function need ipsechanler mutex lock before use +func (c *IPSecController) handleIpsecUpdate() { + c.kmeshNodeInfo.Spec.SPI = c.ipsecHandler.Spi + nodeNsPath := kmesh_netns.GetNodeNSpath() + + allNodeInfo, err := c.lister.KmeshNodeInfos(kube.KmeshNamespace).List(labels.Everything()) + if err != nil { + log.Errorf("failed to get all kmesh node info, %v", err) + return + } + + updateFunc := func(netns.NetNS) error { + for _, node := range allNodeInfo { + if node.Name == c.kmeshNodeInfo.Name { + continue + } + if err = c.ipsecHandler.CreateXfrmRule(&c.kmeshNodeInfo, node); err != nil { + log.Errorf("%v", err) + } + } + return nil + } + if err := netns.WithNetNSPath(nodeNsPath, updateFunc); err != nil { + return + } + + node, err := c.lister.KmeshNodeInfos(kube.KmeshNamespace).Get(c.kmeshNodeInfo.Name) + if err != nil { + log.Errorf("failed to get kmesh node info: %v", err) + return + } + + if node.Spec.SPI == c.ipsecHandler.Spi { + return + } + + update := node.DeepCopy() + update.Spec.SPI = c.kmeshNodeInfo.Spec.SPI + _, err = c.knclient.Update(context.TODO(), update, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("failed to update kmeshinfo, %v", err) + return + } +} diff --git a/pkg/controller/encryption/ipsec/ipsec_handler.go b/pkg/controller/encryption/ipsec/ipsec_handler.go new file mode 100644 index 000000000..e7e058e52 --- /dev/null +++ b/pkg/controller/encryption/ipsec/ipsec_handler.go @@ -0,0 +1,398 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ipsec + +import ( + "bufio" + "crypto/sha512" + "encoding/json" + "fmt" + "net" + "os" + "strings" + "sync" + "time" + + "github.com/fsnotify/fsnotify" + "github.com/vishvananda/netlink" + "istio.io/istio/pkg/filewatcher" + + "kmesh.net/kmesh/pkg/constants" + "kmesh.net/kmesh/pkg/kube/apis/kmeshnodeinfo/v1alpha1" +) + +const ( + IpSecKeyFile = "./kmesh-ipsec/ipSec" +) + +type IpSecKey struct { + Spi int `json:"spi"` + AeadKeyName string `json:"aeadKeyName"` + AeadKey []byte `json:"aeadKey"` + Length int `json:"length"` +} + +type IpSecHandler struct { + Spi int + mutex sync.RWMutex + watcher filewatcher.FileWatcher + historyIpSecKey map[int]IpSecKey +} + +func NewIpSecHandler() *IpSecHandler { + return &IpSecHandler{ + historyIpSecKey: make(map[int]IpSecKey), + } +} + +func (is *IpSecHandler) LoadIPSecKeyFromFile(filePath string) error { + file, err := os.Open(filePath) + if err != nil { + return fmt.Errorf("load ipsec keys failed: %v", err) + } + defer file.Close() + + err = is.loadIPSecKeyFromIO(file) + if err != nil { + return err + } + return nil +} + +func (is *IpSecHandler) loadIPSecKeyFromIO(file *os.File) error { + reader := bufio.NewReader(file) + decoder := json.NewDecoder(reader) + var key IpSecKey + if err := decoder.Decode(&key); err != nil { + return fmt.Errorf("ipsec config file decoder error, %v, please use Kmesh tool generate ipsec secret key", err) + } + if !strings.HasPrefix(key.AeadKeyName, "rfc") { + return fmt.Errorf("ipsec config file error, invalid algo name, aead need begin with \"rfc\"") + } + is.Spi = key.Spi + is.historyIpSecKey[is.Spi] = key + return nil +} + +func (h *IpSecHandler) StartWatch(f func()) error { + h.watcher = filewatcher.NewWatcher() + if err := h.watcher.Add(IpSecKeyFile); err != nil { + return fmt.Errorf("failed to add %s to file watcher: %v", IpSecKeyFile, err) + } + go func() { + log.Infof("start watching file %s", IpSecKeyFile) + + var timerC <-chan time.Time + for { + select { + case <-timerC: + timerC = nil + h.mutex.Lock() + if err := h.LoadIPSecKeyFromFile(IpSecKeyFile); err != nil { + log.Errorf("failed to load ipsec key, %v", err) + h.mutex.Unlock() + continue + } + f() + h.mutex.Unlock() + + case event := <-h.watcher.Events(IpSecKeyFile): + log.Debugf("got event %s", event.String()) + if event.Has(fsnotify.Write) || event.Has(fsnotify.Create) || + event.Has(fsnotify.Rename) || event.Has(fsnotify.Chmod) { + if timerC == nil { + timerC = time.After(100 * time.Millisecond) + } + } + case err := <-h.watcher.Errors(IpSecKeyFile): + if err != nil { + log.Errorf("err from errors channel of file watcher: %v", err) + return + } + } + } + }() + return nil +} + +func (is *IpSecHandler) StopWatch() { + if is.watcher == nil { + return + } + if err := is.watcher.Close(); err != nil { + log.Errorf("failed to close fsnotify watcher: %v", err) + } +} + +func (is *IpSecHandler) generateIPSecKey(srcIP, dstIP, srcBootID, dstBootID string, key []byte) []byte { + inputLen := len(key) + len(srcIP) + len(dstIP) + len(srcBootID) + len(dstBootID) + input := make([]byte, 0, inputLen) + input = append(input, key...) + input = append(input, []byte(srcIP)...) + input = append(input, []byte(dstIP)...) + input = append(input, []byte(srcBootID)[:36]...) + input = append(input, []byte(dstBootID)[:36]...) + + hash := sha512.Sum512(input) + return hash[:len(key)] +} + +func (is *IpSecHandler) CreateXfrmRule(localNode, remoteNode *v1alpha1.KmeshNodeInfo) error { + ipsecKey, ok := is.historyIpSecKey[remoteNode.Spec.SPI] + if !ok { + // not found spi! May be i haven't record, skip + log.Warnf("can not found the spi key, maybe spi has expire before kmesh start") + return nil + } + for _, remoteNicIP := range remoteNode.Spec.Addresses { + for _, localNicIP := range localNode.Spec.Addresses { + if err := is.createXfrmRuleIngress(remoteNicIP, localNicIP, remoteNode.Spec.BootID, localNode.Spec.BootID, + localNode.Spec.SPI, localNode.Spec.PodCIDRs); err != nil { + return err + } + // remoteIPInfo may no exist + if remoteNode.Spec.SPI > localNode.Spec.SPI { + // my ipsec not update, do nothing, I will do egress again when ipsec watch file update + // only add ingress + continue + } + + if err := is.createXfrmRuleEgress(localNicIP, remoteNicIP, localNode.Spec.BootID, remoteNode.Spec.BootID, + ipsecKey, remoteNode.Spec.PodCIDRs); err != nil { + return fmt.Errorf("create xfrm out rule failed, %v", err) + } + } + } + return nil +} + +/* + * src is remote host, dst is local host + * create xfrm rule like: + * ip xfrm state add src {rawRemoteIP} dst {rawLocalNicIP} proto esp {rawLocalSpi} mode tunnel reqid 1 {aead-algo} {aead-key} {aead-key-length} + * ip xfrm policy add src 0.0.0.0/0 dst {rawLocalCIDR} dir in tmpl src {rawRemoteIP} dst {rawLocalNicIP} proto esp reqid 1 mode tunnel mark 0x{remoteNodeID}00d0 mask 0xffffffff + * ip xfrm policy add src 0.0.0.0/0 dst {rawLocalCIDR} dir fwd tmpl src {rawRemoteIP} dst {rawLocalNicIP} proto esp reqid 1 mode tunnel mark 0x{remoteNodeID}00d0 mask 0xffffffff + * remoteid = sum(rawRemoteIP) + */ +func (is *IpSecHandler) createXfrmRuleIngress(rawRemoteIP, rawLocalNicIP, remoteBootID, localBootID string, spi int, podCIDRs []string) error { + src := net.ParseIP(rawRemoteIP) + if src == nil { + return fmt.Errorf("failed to parser ip in inserting xfrm rule, input: %v", rawRemoteIP) + } + dst := net.ParseIP(rawLocalNicIP) + if dst == nil { + return fmt.Errorf("failed to parser ip in inserting xfrm rule, input: %v", rawLocalNicIP) + } + + // localNicIPInfo must exist, spi is local node info spi + newKey := is.generateIPSecKey(rawRemoteIP, rawLocalNicIP, remoteBootID, localBootID, is.historyIpSecKey[spi].AeadKey) + + err := is.createStateRule(src, dst, newKey, is.historyIpSecKey[spi]) + if err != nil { + return err + } + + _, remoteCIDR, err := net.ParseCIDR(constants.ALL_CIDR) + if err != nil { + return fmt.Errorf("failed to parser podCIDR in inserting xfrm rule, %v", err) + } + + for _, pocCIDR := range podCIDRs { + _, localCIDR, err := net.ParseCIDR(pocCIDR) + if err != nil { + return fmt.Errorf("failed to parser podCIDR in inserting xfrm rule, %v", err) + } + if err = is.createPolicyRule(remoteCIDR, localCIDR, src, dst, 0, true); err != nil { + return fmt.Errorf("failed to create policy rule, %v", err) + } + } + + return nil +} + +/* + * src is local host, dst is remote host + * create xfrm rule like: + * ip xfrm state add src {localNicIP} dst {remoteNicIP} proto esp spi {remoteSpi} mode tunnel reqid 1 {aead-algo} {aead-key} {aead-key-length} + * ip xfrm policy add src 0.0.0.0/0 dst {remoteCIDR} dir out tmpl src {localNicIP} dst {remoteNicIP} proto esp spi {remoteSpi} reqid 1 mode tunnel mark 0x{remoteNodeID}00e0 + */ +func (is *IpSecHandler) createXfrmRuleEgress(rawLocalNicIP, rawRemoteIP, localBootID, remoteBootID string, ipsecKey IpSecKey, podCIDRs []string) error { + src := net.ParseIP(rawLocalNicIP) + if src == nil { + return fmt.Errorf("failed to parser ip in inserting xfrm rule, input: %v", rawLocalNicIP) + } + + dst := net.ParseIP(rawRemoteIP) + if dst == nil { + return fmt.Errorf("failed to parser ip in inserting xfrm rule, input: %v", rawRemoteIP) + } + + newKey := is.generateIPSecKey(rawLocalNicIP, rawRemoteIP, localBootID, remoteBootID, ipsecKey.AeadKey) + + err := is.createStateRule(src, dst, newKey, ipsecKey) + if err != nil { + return err + } + + _, localCIDR, err := net.ParseCIDR(constants.ALL_CIDR) + if err != nil { + return fmt.Errorf("failed to parser podCIDR in inserting xfrm rule, %v", err) + } + + for _, podCIDR := range podCIDRs { + _, remoteCIDR, err := net.ParseCIDR(podCIDR) + if err != nil { + return fmt.Errorf("failed to parser podCIDR in inserting xfrm rule, %v", err) + } + if err = is.createPolicyRule(localCIDR, remoteCIDR, src, dst, ipsecKey.Spi, false); err != nil { + return fmt.Errorf("failed to create policy rule, %v", err) + } + } + + return nil +} + +func (is *IpSecHandler) createStateRule(src net.IP, dst net.IP, key []byte, ipsecKey IpSecKey) error { + state := &netlink.XfrmState{ + Src: src, + Dst: dst, + Proto: netlink.XFRM_PROTO_ESP, + Mode: netlink.XFRM_MODE_TUNNEL, + Spi: ipsecKey.Spi, + Reqid: 1, + Aead: &netlink.XfrmStateAlgo{ + Name: ipsecKey.AeadKeyName, + Key: key, + ICVLen: ipsecKey.Length, + }, + } + err := netlink.XfrmStateAdd(state) + if err != nil && !os.IsExist(err) { + return fmt.Errorf("failed to add xfrm state to host in inserting xfrm out rule, %v", err) + } + return nil +} + +func (is *IpSecHandler) createPolicyRule(srcCIDR, dstCIDR *net.IPNet, src, dst net.IP, spi int, out bool) error { + policy := &netlink.XfrmPolicy{ + Src: srcCIDR, + Dst: dstCIDR, + Tmpls: []netlink.XfrmPolicyTmpl{ + { + Src: src, + Dst: dst, + Proto: netlink.XFRM_PROTO_ESP, + Reqid: 1, + Mode: netlink.XFRM_MODE_TUNNEL, + }, + }, + Mark: &netlink.XfrmMark{ + Mask: 0xffffffff, + }, + } + if out { + // ingress + mark := uint32(0xd0) + policy.Mark.Value = mark + + policy.Dir = netlink.XFRM_DIR_IN + if err := is.xfrmPolicyCreateOrUpdate(policy); err != nil { + return err + } + + policy.Dir = netlink.XFRM_DIR_FWD + if err := is.xfrmPolicyCreateOrUpdate(policy); err != nil { + return err + } + } else { + // egress, update SPI + mark := uint32(0xe0) + + policy.Mark.Value = uint32(mark) + policy.Tmpls[0].Spi = int(spi) + policy.Dir = netlink.XFRM_DIR_OUT + + if err := is.xfrmPolicyCreateOrUpdate(policy); err != nil { + return err + } + } + return nil +} + +func (*IpSecHandler) xfrmPolicyCreateOrUpdate(policy *netlink.XfrmPolicy) error { + err := netlink.XfrmPolicyAdd(policy) + if err != nil && os.IsExist(err) { + err = netlink.XfrmPolicyUpdate(policy) + } + if err != nil { + return fmt.Errorf("failed to add xfrm policy to host in inserting xfrm fwd rule, %v", err) + } + return nil +} + +func (is *IpSecHandler) Clean(ip string) error { + targetIP := net.ParseIP(ip) + oldPolicyList, err := netlink.XfrmPolicyList(netlink.FAMILY_ALL) + if err != nil { + return err + } + for _, policy := range oldPolicyList { + for _, tmpl := range policy.Tmpls { + if tmpl.Src.Equal(targetIP) { + err = netlink.XfrmPolicyDel(&policy) + if err != nil { + return err + } + continue + } + if tmpl.Dst.Equal(targetIP) { + err = netlink.XfrmPolicyDel(&policy) + if err != nil { + return err + } + continue + } + } + } + oldStateList, err := netlink.XfrmStateList(netlink.FAMILY_ALL) + if err != nil { + return err + } + for _, state := range oldStateList { + if state.Src.Equal(targetIP) { + err = netlink.XfrmStateDel(&state) + if err != nil { + return err + } + continue + } + if state.Dst.Equal(targetIP) { + err = netlink.XfrmStateDel(&state) + if err != nil { + return err + } + continue + } + } + return nil +} + +func (is *IpSecHandler) Flush() error { + netlink.XfrmPolicyFlush() + netlink.XfrmStateFlush(netlink.XFRM_PROTO_ESP) + return nil +} diff --git a/pkg/controller/manage/manage_controller.go b/pkg/controller/manage/manage_controller.go index 72b251609..d9d781122 100644 --- a/pkg/controller/manage/manage_controller.go +++ b/pkg/controller/manage/manage_controller.go @@ -35,6 +35,7 @@ import ( "k8s.io/client-go/util/workqueue" "kmesh.net/kmesh/pkg/constants" + kmesh_netns "kmesh.net/kmesh/pkg/controller/netns" ns "kmesh.net/kmesh/pkg/controller/netns" kmeshsecurity "kmesh.net/kmesh/pkg/controller/security" "kmesh.net/kmesh/pkg/kube" @@ -66,6 +67,7 @@ type KmeshManageController struct { client kubernetes.Interface sm *kmeshsecurity.SecretManager xdpProgFd int + tcProgFd int mode string } @@ -78,7 +80,7 @@ func isPodReady(pod *corev1.Pod) bool { return false } -func NewKmeshManageController(client kubernetes.Interface, sm *kmeshsecurity.SecretManager, xdpProgFd int, mode string) (*KmeshManageController, error) { +func NewKmeshManageController(client kubernetes.Interface, sm *kmeshsecurity.SecretManager, xdpProgFd, tcProgFd int, mode string) (*KmeshManageController, error) { informerFactory := kube.NewInformerFactory(client) podInformer := informerFactory.Core().V1().Pods().Informer() podLister := informerFactory.Core().V1().Pods().Lister() @@ -98,6 +100,7 @@ func NewKmeshManageController(client kubernetes.Interface, sm *kmeshsecurity.Sec client: client, sm: sm, xdpProgFd: xdpProgFd, + tcProgFd: tcProgFd, mode: mode, } @@ -233,6 +236,7 @@ func (c *KmeshManageController) enableKmeshManage(pod *corev1.Pod) { } c.queue.AddRateLimited(QueueItem{podName: pod.Name, podNs: pod.Namespace, action: ActionAddAnnotation}) _ = linkXdp(nspath, c.xdpProgFd, c.mode) + _ = linkTc(nspath, c.tcProgFd) } func (c *KmeshManageController) disableKmeshManage(pod *corev1.Pod) { @@ -249,6 +253,7 @@ func (c *KmeshManageController) disableKmeshManage(pod *corev1.Pod) { } c.queue.AddRateLimited(QueueItem{podName: pod.Name, podNs: pod.Namespace, action: ActionDeleteAnnotation}) _ = unlinkXdp(nspath, c.mode) + _ = unlinkTc(nspath, c.tcProgFd) } func (c *KmeshManageController) enableKmeshForPodsInNamespace(namespace *corev1.Namespace) { @@ -435,3 +440,95 @@ func unlinkXdp(netNsPath string, mode string) error { return nil } + +func getVethPeerIndex() (ifIndex uint64, err error) { + ifIndex = 0 + // Get all NIC iface in a pod + ifaces, err := net.Interfaces() + if err != nil { + return ifIndex, err + } + // Link XDP prog on every iface, except loopback or not up + for _, iface := range ifaces { + ifIndex, err = utils.GetVethPeerIndexFromInterface(iface) + if ifIndex == 0 { + log.Infof("%v", err) + continue + } + } + if ifIndex == 0 { + err = fmt.Errorf("failed to find a valid veth interface") + } + return ifIndex, err +} + +func managleVethTc(ifIndex uint64, tcProgFd int, mode int) error { + var ( + err error + link netlink.Link + ) + if link, err = netlink.LinkByIndex(int(ifIndex)); err != nil { + return fmt.Errorf("failed to link valid interface, %v", err) + } + + return utils.ManageTCProgramByFd(link, tcProgFd, mode) +} + +func linkTc(netNsPath string, tcProgFd int) error { + var ( + err error + ifIndex uint64 + ) + + if tcProgFd == -1 { + return nil + } + + warpGetVethPeerNum := func(_ netns.NetNS) error { + ifIndex, err = getVethPeerIndex() + return err + } + + if err = netns.WithNetNSPath(netNsPath, warpGetVethPeerNum); err != nil { + err = fmt.Errorf("Run get veth peer num in netNsPath %v failed, err: %v", netNsPath, err) + return err + } + // set tc on node namespace veth peer + if err = netns.WithNetNSPath(kmesh_netns.GetNodeNSpath(), func(_ netns.NetNS) error { + return managleVethTc(ifIndex, tcProgFd, constants.TC_ATTACH) + }); err != nil { + err = fmt.Errorf("Run link tc in netNsPath %v failed, err: %v", netNsPath, err) + return err + } + + return nil +} + +func unlinkTc(netNsPath string, tcProgFd int) error { + var ( + err error + ifIndex uint64 + ) + + if tcProgFd == -1 { + return nil + } + + warpGetVethPeerNum := func(_ netns.NetNS) error { + ifIndex, err = getVethPeerIndex() + return err + } + + if err = netns.WithNetNSPath(netNsPath, warpGetVethPeerNum); err != nil { + err = fmt.Errorf("Run get veth peer num in netNsPath %v failed, err: %v", netNsPath, err) + return err + } + // set tc on node namespace veth peer + if err := netns.WithNetNSPath(kmesh_netns.GetNodeNSpath(), func(_ netns.NetNS) error { + return managleVethTc(ifIndex, tcProgFd, constants.TC_DETACH) + }); err != nil { + err = fmt.Errorf("Run link tc in netNsPath %v failed, err: %v", netNsPath, err) + return err + } + return nil +} diff --git a/pkg/controller/manage/manage_controller_test.go b/pkg/controller/manage/manage_controller_test.go index 1c2aec304..433bc7599 100644 --- a/pkg/controller/manage/manage_controller_test.go +++ b/pkg/controller/manage/manage_controller_test.go @@ -29,6 +29,7 @@ import ( "github.com/cilium/ebpf" "github.com/cilium/ebpf/asm" "github.com/containernetworking/plugins/pkg/ns" + netns "github.com/containernetworking/plugins/pkg/ns" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/vishvananda/netlink" @@ -194,7 +195,7 @@ func TestHandleKmeshManage(t *testing.T) { t.Cleanup(func() { os.Unsetenv("NODE_NAME") }) - controller, err := NewKmeshManageController(client, nil, 0, "") + controller, err := NewKmeshManageController(client, nil, 0, -1, "") if err != nil { t.Fatalf("error creating KmeshManageController: %v", err) } @@ -435,7 +436,7 @@ func TestNsInformerHandleKmeshManage(t *testing.T) { t.Cleanup(func() { os.Unsetenv("NODE_NAME") }) - controller, err := NewKmeshManageController(client, nil, 0, "") + controller, err := NewKmeshManageController(client, nil, 0, -1, "") if err != nil { t.Fatalf("error creating KmeshManageController: %v", err) } @@ -757,3 +758,178 @@ func Test_unlinkXdp(t *testing.T) { }) } } + +// Create a test netns, link an old TC program on veth0 created inside the netns +func newTestNetNsWithVethPeerIndex(t *testing.T) (uint64, ns.NetNS, ns.NetNS) { + var targetIndex uint64 = 0 + testNs1, err := ns.TempNetNS() + if err != nil { + t.Fatal(err) + } + testNs2, err := ns.TempNetNS() + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + if testNs1 != nil { + testNs1.Close() + } + if testNs2 != nil { + testNs1.Close() + } + }) + + testNs1.Do(func(_ ns.NetNS) error { + veth := &netlink.Veth{ + LinkAttrs: netlink.LinkAttrs{Name: "veth0"}, + PeerName: "veth1", + } + if err := netlink.LinkAdd(veth); err != nil { + t.Fatal(err) + } + if err := netlink.LinkSetUp(veth); err != nil { + t.Fatal(err) + } + peer, err := netlink.LinkByName("veth1") + if err != nil { + t.Fatal(err) + } + if err = netlink.LinkSetNsFd(peer, int(testNs2.Fd())); err != nil { + t.Fatal(err) + } + if err = netlink.LinkSetUp(veth); err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + netlink.LinkDel(veth) + }) + return nil + }) + + testNs2.Do(func(_ ns.NetNS) error { + peer, err := netlink.LinkByName("veth1") + if err != nil { + t.Fatal(err) + } + if err = netlink.LinkSetUp(peer); err != nil { + t.Fatal(err) + } + + targetIndex = uint64(peer.Attrs().Index) + + t.Cleanup(func() { + netlink.LinkDel(peer) + }) + return nil + }) + + return targetIndex, testNs1, testNs2 +} + +func Test_getVethPeerNum(t *testing.T) { + patches := gomonkey.NewPatches() + defer patches.Reset() + targetIndex, testNetNs, _ := newTestNetNsWithVethPeerIndex(t) + patches.ApplyFunc(ns.GetNS, func(_ string) (ns.NetNS, error) { + return testNetNs, nil + }) + + tests := []struct { + name string + netNsPath string + wantErr bool + }{ + { + name: "get veth peer index, no error", + netNsPath: "test_ns_path", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var ifIndex uint64 + var err error + warpGetVethPeerIndex := func(_ netns.NetNS) error { + ifIndex, err = getVethPeerIndex() + return err + } + + if err = netns.WithNetNSPath(tt.netNsPath, warpGetVethPeerIndex); err != nil || ifIndex != targetIndex { + t.Errorf("getVethPeerIndex() error = %v, ifIndex = %v, wantIndex = %v, wantErr %v", err, ifIndex, targetIndex, tt.wantErr) + } + }) + } +} + +func newTextTcProg(t *testing.T, name string) *ebpf.Program { + prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{ + Type: ebpf.SocketFilter, + Name: name, + Instructions: asm.Instructions{ + asm.Mov.Imm(asm.R0, 0), + asm.Return(), + }, + License: "GPL", + }) + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + prog.Close() + }) + return prog +} + +func Test_TC(t *testing.T) { + patches := gomonkey.NewPatches() + defer patches.Reset() + _, testNetNs1, testNetNs2 := newTestNetNsWithVethPeerIndex(t) + patches.ApplyFunc(ns.WithNetNSPath, func(nspath string, toRun func(ns.NetNS) error) error { + if nspath == "test_netns1" { + return testNetNs1.Do(toRun) + } + if nspath == "test_netns2" { + return testNetNs2.Do(toRun) + } + return nil + }) + patches.ApplyFunc(utils.ManageTCProgramByFd, func(link netlink.Link, tcFd int, mode int) error { + return nil + }) + type args struct { + netNsPath1 string + netNsPath2 string + tcProgFd int + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + "Link a new tc program, no error", + args{ + "test_netns1", + "test_netns2", + newTextTcProg(t, "new_tc").FD(), + }, + false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + warpFunc := func(netns.NetNS) error { + if err := linkTc(tt.args.netNsPath1, tt.args.tcProgFd); (err != nil) != tt.wantErr { + t.Errorf("linkTc() error = %v, wantErr %v", err, tt.wantErr) + } + if err := unlinkTc(tt.args.netNsPath1, tt.args.tcProgFd); (err != nil) != tt.wantErr { + t.Errorf("unlinkTc() error = %v, wantErr %v", err, tt.wantErr) + } + return nil + } + if err := netns.WithNetNSPath(tt.args.netNsPath2, warpFunc); err != nil { + t.Errorf("failed") + } + }) + } +} diff --git a/pkg/controller/netns/netns.go b/pkg/controller/netns/netns.go index 6cdcee62e..2338d4354 100644 --- a/pkg/controller/netns/netns.go +++ b/pkg/controller/netns/netns.go @@ -37,6 +37,11 @@ var ( FS embed.FS ) +func GetNodeNSpath() string { + res := path.Join("/host/proc", "1", "ns", "net") + return res +} + func GetPodNSpath(pod *corev1.Pod) (string, error) { res, err := FindNetnsForPod(pod) if err != nil { diff --git a/pkg/kube/apis/kmeshnodeinfo/register.go b/pkg/kube/apis/kmeshnodeinfo/register.go new file mode 100644 index 000000000..6fcf6e7be --- /dev/null +++ b/pkg/kube/apis/kmeshnodeinfo/register.go @@ -0,0 +1,21 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kmeshnodeinfo + +const ( + GroupName = "kmesh.net" +) diff --git a/pkg/kube/apis/kmeshnodeinfo/v1alpha1/doc.go b/pkg/kube/apis/kmeshnodeinfo/v1alpha1/doc.go new file mode 100644 index 000000000..fadea3548 --- /dev/null +++ b/pkg/kube/apis/kmeshnodeinfo/v1alpha1/doc.go @@ -0,0 +1,20 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +k8s:deepcopy-gen=package +// +groupName=kmesh.net + +package v1alpha1 // import "kmesh.net/kmesh/pkg/apis/kmeshnodeinfo/v1alpha1" diff --git a/pkg/kube/apis/kmeshnodeinfo/v1alpha1/register.go b/pkg/kube/apis/kmeshnodeinfo/v1alpha1/register.go new file mode 100644 index 000000000..5b6a90f24 --- /dev/null +++ b/pkg/kube/apis/kmeshnodeinfo/v1alpha1/register.go @@ -0,0 +1,45 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// register customer sources +var SchemeGroupVersion = schema.GroupVersion{Group: "kmesh.net", Version: "v1alpha1"} + +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, &KmeshNodeInfo{}, &KmeshNodeInfoList{}) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/kube/apis/kmeshnodeinfo/v1alpha1/types.go b/pkg/kube/apis/kmeshnodeinfo/v1alpha1/types.go new file mode 100644 index 000000000..c92b7c1c2 --- /dev/null +++ b/pkg/kube/apis/kmeshnodeinfo/v1alpha1/types.go @@ -0,0 +1,63 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// KmeshNode is the Schema for the kmeshnodes API +type KmeshNodeInfo struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec KmeshNodeInfoSpec `json:"spec,omitempty"` + Status KmeshNodeInfoStatus `json:"status,omitempty"` +} + +type KmeshNodeInfoSpec struct { + // The SPI is used to identify the version number of the current key. + // The communication can be normal only when both communication parties + // have spis and the spi keys are the same. + SPI int `json:"spi"` + // Addresses is used to store the internal ip address informatioon on the + // host. The IP address information is used to generate the IPsec state + // informatioon. IPsec uses this information to determine which network + // adapter is used to encrypt and send data. + Addresses []string `json:"addresses"` + // bootid is used to generate the ipsec key. After the node is restarted, + // the key needs to be updated. + BootID string `json:"bootID"` + // PodCIDRs used in IPsec checks the destination of the data to + // determine which IPsec state is used for encryption. + PodCIDRs []string `json:"podCIDRS"` +} + +type KmeshNodeInfoStatus struct { +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// KmeshNodeLists contains a list of KmeshNode +type KmeshNodeInfoList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []KmeshNodeInfo `json:"items"` +} diff --git a/pkg/kube/apis/kmeshnodeinfo/v1alpha1/zz_generated.deepcopy.go b/pkg/kube/apis/kmeshnodeinfo/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 000000000..1a24d73fa --- /dev/null +++ b/pkg/kube/apis/kmeshnodeinfo/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,128 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KmeshNodeInfo) DeepCopyInto(out *KmeshNodeInfo) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KmeshNodeInfo. +func (in *KmeshNodeInfo) DeepCopy() *KmeshNodeInfo { + if in == nil { + return nil + } + out := new(KmeshNodeInfo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KmeshNodeInfo) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KmeshNodeInfoList) DeepCopyInto(out *KmeshNodeInfoList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]KmeshNodeInfo, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KmeshNodeInfoList. +func (in *KmeshNodeInfoList) DeepCopy() *KmeshNodeInfoList { + if in == nil { + return nil + } + out := new(KmeshNodeInfoList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KmeshNodeInfoList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KmeshNodeInfoSpec) DeepCopyInto(out *KmeshNodeInfoSpec) { + *out = *in + if in.Addresses != nil { + in, out := &in.Addresses, &out.Addresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.PodCIDRs != nil { + in, out := &in.PodCIDRs, &out.PodCIDRs + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KmeshNodeInfoSpec. +func (in *KmeshNodeInfoSpec) DeepCopy() *KmeshNodeInfoSpec { + if in == nil { + return nil + } + out := new(KmeshNodeInfoSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KmeshNodeInfoStatus) DeepCopyInto(out *KmeshNodeInfoStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KmeshNodeInfoStatus. +func (in *KmeshNodeInfoStatus) DeepCopy() *KmeshNodeInfoStatus { + if in == nil { + return nil + } + out := new(KmeshNodeInfoStatus) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/kube/boilerplate.go.txt b/pkg/kube/boilerplate.go.txt new file mode 100644 index 000000000..6e9499eb0 --- /dev/null +++ b/pkg/kube/boilerplate.go.txt @@ -0,0 +1,15 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ \ No newline at end of file diff --git a/pkg/kube/clean.sh b/pkg/kube/clean.sh new file mode 100644 index 000000000..c7ca03f98 --- /dev/null +++ b/pkg/kube/clean.sh @@ -0,0 +1,6 @@ +#!/bin/bash +rm -rf ../../deploy/yaml/crd/kmesh.net_kmeshnodeinfoes.yaml +rm -rf apis/kmeshnodeinfo/v1alpha1/zz_generated.deepcopy.go +rm -rf nodeinfo/clientset +rm -rf nodeinfo/informers +rm -rf nodeinfo/listers \ No newline at end of file diff --git a/pkg/kube/generate.sh b/pkg/kube/generate.sh new file mode 100644 index 000000000..06e68cc26 --- /dev/null +++ b/pkg/kube/generate.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +controller-gen crd paths=./... output:crd:dir=../../deploy/yaml/crd + +set -o errexit +set -o nounset +set -o pipefail + +SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/../../ +CODEGEN_PKG=${CODEGEN_PKG:-$(cd "${SCRIPT_ROOT}"; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../../../code-generator)} +KUBE_VERBOSE=9 + +source "${CODEGEN_PKG}/kube_codegen.sh" + +THIS_PKG="kmesh.net/kmesh" + +kube::codegen::gen_helpers \ + --boilerplate "${SCRIPT_ROOT}/pkg/kube/boilerplate.go.txt" \ + "${SCRIPT_ROOT}/pkg/kube/apis" + +kube::codegen::gen_client \ + --with-watch \ + --output-dir "${SCRIPT_ROOT}/pkg/kube/nodeinfo" \ + --output-pkg "${THIS_PKG}/pkg/kube/nodeinfo" \ + --boilerplate "${SCRIPT_ROOT}/pkg/kube/boilerplate.go.txt" \ + "${SCRIPT_ROOT}/pkg/kube/apis" \ No newline at end of file diff --git a/pkg/kube/kubeclient.go b/pkg/kube/kubeclient.go index 0314cae1b..93950a051 100644 --- a/pkg/kube/kubeclient.go +++ b/pkg/kube/kubeclient.go @@ -20,6 +20,8 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + + nodeinfo "kmesh.net/kmesh/pkg/kube/nodeinfo/clientset/versioned" ) // CreateKubeClient creates a kube client with the given kubeconfig file, if no kubeconfig specified, in cluster kubeconfig will be used. @@ -43,3 +45,17 @@ func CreateKubeClient(kubeConfig string, applyFuncs ...func(c *rest.Config)) (ku return kubernetes.NewForConfig(restConfig) } + +func GetKmeshNodeInfoClient() (nodeinfo.Interface, error) { + config, err := rest.InClusterConfig() + if err != nil { + return nil, err + } + + // Create kmesh node info clientset + clientset, err := nodeinfo.NewForConfig(config) + if err != nil { + return nil, err + } + return clientset, nil +} diff --git a/pkg/kube/nodeinfo/clientset/versioned/clientset.go b/pkg/kube/nodeinfo/clientset/versioned/clientset.go new file mode 100644 index 000000000..bafebb1a3 --- /dev/null +++ b/pkg/kube/nodeinfo/clientset/versioned/clientset.go @@ -0,0 +1,119 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by client-gen. DO NOT EDIT. + +package versioned + +import ( + fmt "fmt" + http "net/http" + + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" + kmeshv1alpha1 "kmesh.net/kmesh/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + KmeshV1alpha1() kmeshv1alpha1.KmeshV1alpha1Interface +} + +// Clientset contains the clients for groups. +type Clientset struct { + *discovery.DiscoveryClient + kmeshV1alpha1 *kmeshv1alpha1.KmeshV1alpha1Client +} + +// KmeshV1alpha1 retrieves the KmeshV1alpha1Client +func (c *Clientset) KmeshV1alpha1() kmeshv1alpha1.KmeshV1alpha1Interface { + return c.kmeshV1alpha1 +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfig will generate a rate-limiter in configShallowCopy. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + + if configShallowCopy.UserAgent == "" { + configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent() + } + + // share the transport between all clients + httpClient, err := rest.HTTPClientFor(&configShallowCopy) + if err != nil { + return nil, err + } + + return NewForConfigAndClient(&configShallowCopy, httpClient) +} + +// NewForConfigAndClient creates a new Clientset for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfigAndClient will generate a rate-limiter in configShallowCopy. +func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + if configShallowCopy.Burst <= 0 { + return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") + } + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + + var cs Clientset + var err error + cs.kmeshV1alpha1, err = kmeshv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + cs, err := NewForConfig(c) + if err != nil { + panic(err) + } + return cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.kmeshV1alpha1 = kmeshv1alpha1.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/pkg/kube/nodeinfo/clientset/versioned/fake/clientset_generated.go b/pkg/kube/nodeinfo/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 000000000..91b54b18f --- /dev/null +++ b/pkg/kube/nodeinfo/clientset/versioned/fake/clientset_generated.go @@ -0,0 +1,88 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" + clientset "kmesh.net/kmesh/pkg/kube/nodeinfo/clientset/versioned" + kmeshv1alpha1 "kmesh.net/kmesh/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1" + fakekmeshv1alpha1 "kmesh.net/kmesh/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/fake" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any field management, validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +// +// DEPRECATED: NewClientset replaces this with support for field management, which significantly improves +// server side apply testing. NewClientset is only available when apply configurations are generated (e.g. +// via --with-applyconfig). +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery + tracker testing.ObjectTracker +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +func (c *Clientset) Tracker() testing.ObjectTracker { + return c.tracker +} + +var ( + _ clientset.Interface = &Clientset{} + _ testing.FakeClient = &Clientset{} +) + +// KmeshV1alpha1 retrieves the KmeshV1alpha1Client +func (c *Clientset) KmeshV1alpha1() kmeshv1alpha1.KmeshV1alpha1Interface { + return &fakekmeshv1alpha1.FakeKmeshV1alpha1{Fake: &c.Fake} +} diff --git a/pkg/kube/nodeinfo/clientset/versioned/fake/doc.go b/pkg/kube/nodeinfo/clientset/versioned/fake/doc.go new file mode 100644 index 000000000..7e3f76baf --- /dev/null +++ b/pkg/kube/nodeinfo/clientset/versioned/fake/doc.go @@ -0,0 +1,19 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/pkg/kube/nodeinfo/clientset/versioned/fake/register.go b/pkg/kube/nodeinfo/clientset/versioned/fake/register.go new file mode 100644 index 000000000..5fea28fdd --- /dev/null +++ b/pkg/kube/nodeinfo/clientset/versioned/fake/register.go @@ -0,0 +1,55 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + kmeshv1alpha1 "kmesh.net/kmesh/pkg/kube/apis/kmeshnodeinfo/v1alpha1" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) + +var localSchemeBuilder = runtime.SchemeBuilder{ + kmeshv1alpha1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) +} diff --git a/pkg/kube/nodeinfo/clientset/versioned/scheme/doc.go b/pkg/kube/nodeinfo/clientset/versioned/scheme/doc.go new file mode 100644 index 000000000..4fd1be092 --- /dev/null +++ b/pkg/kube/nodeinfo/clientset/versioned/scheme/doc.go @@ -0,0 +1,19 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/pkg/kube/nodeinfo/clientset/versioned/scheme/register.go b/pkg/kube/nodeinfo/clientset/versioned/scheme/register.go new file mode 100644 index 000000000..63187f62d --- /dev/null +++ b/pkg/kube/nodeinfo/clientset/versioned/scheme/register.go @@ -0,0 +1,55 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + kmeshv1alpha1 "kmesh.net/kmesh/pkg/kube/apis/kmeshnodeinfo/v1alpha1" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + kmeshv1alpha1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(Scheme)) +} diff --git a/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/doc.go b/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/doc.go new file mode 100644 index 000000000..88af3faf1 --- /dev/null +++ b/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/doc.go @@ -0,0 +1,19 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1alpha1 diff --git a/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/fake/doc.go b/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/fake/doc.go new file mode 100644 index 000000000..ed472f17d --- /dev/null +++ b/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/fake/doc.go @@ -0,0 +1,19 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/fake/fake_kmeshnodeinfo.go b/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/fake/fake_kmeshnodeinfo.go new file mode 100644 index 000000000..510a6add0 --- /dev/null +++ b/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/fake/fake_kmeshnodeinfo.go @@ -0,0 +1,146 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha1 "kmesh.net/kmesh/pkg/kube/apis/kmeshnodeinfo/v1alpha1" +) + +// FakeKmeshNodeInfos implements KmeshNodeInfoInterface +type FakeKmeshNodeInfos struct { + Fake *FakeKmeshV1alpha1 + ns string +} + +var kmeshnodeinfosResource = v1alpha1.SchemeGroupVersion.WithResource("kmeshnodeinfos") + +var kmeshnodeinfosKind = v1alpha1.SchemeGroupVersion.WithKind("KmeshNodeInfo") + +// Get takes name of the kmeshNodeInfo, and returns the corresponding kmeshNodeInfo object, and an error if there is any. +func (c *FakeKmeshNodeInfos) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.KmeshNodeInfo, err error) { + emptyResult := &v1alpha1.KmeshNodeInfo{} + obj, err := c.Fake. + Invokes(testing.NewGetActionWithOptions(kmeshnodeinfosResource, c.ns, name, options), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1alpha1.KmeshNodeInfo), err +} + +// List takes label and field selectors, and returns the list of KmeshNodeInfos that match those selectors. +func (c *FakeKmeshNodeInfos) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.KmeshNodeInfoList, err error) { + emptyResult := &v1alpha1.KmeshNodeInfoList{} + obj, err := c.Fake. + Invokes(testing.NewListActionWithOptions(kmeshnodeinfosResource, kmeshnodeinfosKind, c.ns, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.KmeshNodeInfoList{ListMeta: obj.(*v1alpha1.KmeshNodeInfoList).ListMeta} + for _, item := range obj.(*v1alpha1.KmeshNodeInfoList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested kmeshNodeInfos. +func (c *FakeKmeshNodeInfos) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchActionWithOptions(kmeshnodeinfosResource, c.ns, opts)) + +} + +// Create takes the representation of a kmeshNodeInfo and creates it. Returns the server's representation of the kmeshNodeInfo, and an error, if there is any. +func (c *FakeKmeshNodeInfos) Create(ctx context.Context, kmeshNodeInfo *v1alpha1.KmeshNodeInfo, opts v1.CreateOptions) (result *v1alpha1.KmeshNodeInfo, err error) { + emptyResult := &v1alpha1.KmeshNodeInfo{} + obj, err := c.Fake. + Invokes(testing.NewCreateActionWithOptions(kmeshnodeinfosResource, c.ns, kmeshNodeInfo, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1alpha1.KmeshNodeInfo), err +} + +// Update takes the representation of a kmeshNodeInfo and updates it. Returns the server's representation of the kmeshNodeInfo, and an error, if there is any. +func (c *FakeKmeshNodeInfos) Update(ctx context.Context, kmeshNodeInfo *v1alpha1.KmeshNodeInfo, opts v1.UpdateOptions) (result *v1alpha1.KmeshNodeInfo, err error) { + emptyResult := &v1alpha1.KmeshNodeInfo{} + obj, err := c.Fake. + Invokes(testing.NewUpdateActionWithOptions(kmeshnodeinfosResource, c.ns, kmeshNodeInfo, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1alpha1.KmeshNodeInfo), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeKmeshNodeInfos) UpdateStatus(ctx context.Context, kmeshNodeInfo *v1alpha1.KmeshNodeInfo, opts v1.UpdateOptions) (result *v1alpha1.KmeshNodeInfo, err error) { + emptyResult := &v1alpha1.KmeshNodeInfo{} + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceActionWithOptions(kmeshnodeinfosResource, "status", c.ns, kmeshNodeInfo, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1alpha1.KmeshNodeInfo), err +} + +// Delete takes name of the kmeshNodeInfo and deletes it. Returns an error if one occurs. +func (c *FakeKmeshNodeInfos) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(kmeshnodeinfosResource, c.ns, name, opts), &v1alpha1.KmeshNodeInfo{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeKmeshNodeInfos) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionActionWithOptions(kmeshnodeinfosResource, c.ns, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.KmeshNodeInfoList{}) + return err +} + +// Patch applies the patch and returns the patched kmeshNodeInfo. +func (c *FakeKmeshNodeInfos) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.KmeshNodeInfo, err error) { + emptyResult := &v1alpha1.KmeshNodeInfo{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(kmeshnodeinfosResource, c.ns, name, pt, data, opts, subresources...), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1alpha1.KmeshNodeInfo), err +} diff --git a/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/fake/fake_kmeshnodeinfo_client.go b/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/fake/fake_kmeshnodeinfo_client.go new file mode 100644 index 000000000..25a62e9e5 --- /dev/null +++ b/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/fake/fake_kmeshnodeinfo_client.go @@ -0,0 +1,39 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1alpha1 "kmesh.net/kmesh/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1" +) + +type FakeKmeshV1alpha1 struct { + *testing.Fake +} + +func (c *FakeKmeshV1alpha1) KmeshNodeInfos(namespace string) v1alpha1.KmeshNodeInfoInterface { + return &FakeKmeshNodeInfos{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeKmeshV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/generated_expansion.go b/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/generated_expansion.go new file mode 100644 index 000000000..2d8fd2f8f --- /dev/null +++ b/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/generated_expansion.go @@ -0,0 +1,20 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +type KmeshNodeInfoExpansion interface{} diff --git a/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/kmeshnodeinfo.go b/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/kmeshnodeinfo.go new file mode 100644 index 000000000..9fc2bdb3f --- /dev/null +++ b/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/kmeshnodeinfo.go @@ -0,0 +1,69 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + kmeshnodeinfov1alpha1 "kmesh.net/kmesh/pkg/kube/apis/kmeshnodeinfo/v1alpha1" + scheme "kmesh.net/kmesh/pkg/kube/nodeinfo/clientset/versioned/scheme" +) + +// KmeshNodeInfosGetter has a method to return a KmeshNodeInfoInterface. +// A group's client should implement this interface. +type KmeshNodeInfosGetter interface { + KmeshNodeInfos(namespace string) KmeshNodeInfoInterface +} + +// KmeshNodeInfoInterface has methods to work with KmeshNodeInfo resources. +type KmeshNodeInfoInterface interface { + Create(ctx context.Context, kmeshNodeInfo *kmeshnodeinfov1alpha1.KmeshNodeInfo, opts v1.CreateOptions) (*kmeshnodeinfov1alpha1.KmeshNodeInfo, error) + Update(ctx context.Context, kmeshNodeInfo *kmeshnodeinfov1alpha1.KmeshNodeInfo, opts v1.UpdateOptions) (*kmeshnodeinfov1alpha1.KmeshNodeInfo, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, kmeshNodeInfo *kmeshnodeinfov1alpha1.KmeshNodeInfo, opts v1.UpdateOptions) (*kmeshnodeinfov1alpha1.KmeshNodeInfo, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*kmeshnodeinfov1alpha1.KmeshNodeInfo, error) + List(ctx context.Context, opts v1.ListOptions) (*kmeshnodeinfov1alpha1.KmeshNodeInfoList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *kmeshnodeinfov1alpha1.KmeshNodeInfo, err error) + KmeshNodeInfoExpansion +} + +// kmeshNodeInfos implements KmeshNodeInfoInterface +type kmeshNodeInfos struct { + *gentype.ClientWithList[*kmeshnodeinfov1alpha1.KmeshNodeInfo, *kmeshnodeinfov1alpha1.KmeshNodeInfoList] +} + +// newKmeshNodeInfos returns a KmeshNodeInfos +func newKmeshNodeInfos(c *KmeshV1alpha1Client, namespace string) *kmeshNodeInfos { + return &kmeshNodeInfos{ + gentype.NewClientWithList[*kmeshnodeinfov1alpha1.KmeshNodeInfo, *kmeshnodeinfov1alpha1.KmeshNodeInfoList]( + "kmeshnodeinfos", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *kmeshnodeinfov1alpha1.KmeshNodeInfo { return &kmeshnodeinfov1alpha1.KmeshNodeInfo{} }, + func() *kmeshnodeinfov1alpha1.KmeshNodeInfoList { return &kmeshnodeinfov1alpha1.KmeshNodeInfoList{} }, + ), + } +} diff --git a/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/kmeshnodeinfo_client.go b/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/kmeshnodeinfo_client.go new file mode 100644 index 000000000..b3a5ae36d --- /dev/null +++ b/pkg/kube/nodeinfo/clientset/versioned/typed/kmeshnodeinfo/v1alpha1/kmeshnodeinfo_client.go @@ -0,0 +1,106 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + http "net/http" + + rest "k8s.io/client-go/rest" + kmeshnodeinfov1alpha1 "kmesh.net/kmesh/pkg/kube/apis/kmeshnodeinfo/v1alpha1" + scheme "kmesh.net/kmesh/pkg/kube/nodeinfo/clientset/versioned/scheme" +) + +type KmeshV1alpha1Interface interface { + RESTClient() rest.Interface + KmeshNodeInfosGetter +} + +// KmeshV1alpha1Client is used to interact with features provided by the kmesh.net group. +type KmeshV1alpha1Client struct { + restClient rest.Interface +} + +func (c *KmeshV1alpha1Client) KmeshNodeInfos(namespace string) KmeshNodeInfoInterface { + return newKmeshNodeInfos(c, namespace) +} + +// NewForConfig creates a new KmeshV1alpha1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*KmeshV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new KmeshV1alpha1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*KmeshV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &KmeshV1alpha1Client{client}, nil +} + +// NewForConfigOrDie creates a new KmeshV1alpha1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *KmeshV1alpha1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new KmeshV1alpha1Client for the given RESTClient. +func New(c rest.Interface) *KmeshV1alpha1Client { + return &KmeshV1alpha1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := kmeshnodeinfov1alpha1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *KmeshV1alpha1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/kube/nodeinfo/informers/externalversions/factory.go b/pkg/kube/nodeinfo/informers/externalversions/factory.go new file mode 100644 index 000000000..d942826e6 --- /dev/null +++ b/pkg/kube/nodeinfo/informers/externalversions/factory.go @@ -0,0 +1,261 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + versioned "kmesh.net/kmesh/pkg/kube/nodeinfo/clientset/versioned" + internalinterfaces "kmesh.net/kmesh/pkg/kube/nodeinfo/informers/externalversions/internalinterfaces" + kmeshnodeinfo "kmesh.net/kmesh/pkg/kube/nodeinfo/informers/externalversions/kmeshnodeinfo" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + transform cache.TransformFunc + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool + // wg tracks how many goroutines were started. + wg sync.WaitGroup + // shuttingDown is true when Shutdown has been called. It may still be running + // because it needs to wait for goroutines. + shuttingDown bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// WithTransform sets a transform on all informers. +func WithTransform(transform cache.TransformFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.transform = transform + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + if f.shuttingDown { + return + } + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + f.wg.Add(1) + // We need a new variable in each loop iteration, + // otherwise the goroutine would use the loop variable + // and that keeps changing. + informer := informer + go func() { + defer f.wg.Done() + informer.Run(stopCh) + }() + f.startedInformers[informerType] = true + } + } +} + +func (f *sharedInformerFactory) Shutdown() { + f.lock.Lock() + f.shuttingDown = true + f.lock.Unlock() + + // Will return immediately if there is nothing to wait for. + f.wg.Wait() +} + +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + informer.SetTransform(f.transform) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +// +// It is typically used like this: +// +// ctx, cancel := context.Background() +// defer cancel() +// factory := NewSharedInformerFactory(client, resyncPeriod) +// defer factory.WaitForStop() // Returns immediately if nothing was started. +// genericInformer := factory.ForResource(resource) +// typedInformer := factory.SomeAPIGroup().V1().SomeType() +// factory.Start(ctx.Done()) // Start processing these informers. +// synced := factory.WaitForCacheSync(ctx.Done()) +// for v, ok := range synced { +// if !ok { +// fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v) +// return +// } +// } +// +// // Creating informers can also be created after Start, but then +// // Start must be called again: +// anotherGenericInformer := factory.ForResource(resource) +// factory.Start(ctx.Done()) +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + + // Start initializes all requested informers. They are handled in goroutines + // which run until the stop channel gets closed. + // Warning: Start does not block. When run in a go-routine, it will race with a later WaitForCacheSync. + Start(stopCh <-chan struct{}) + + // Shutdown marks a factory as shutting down. At that point no new + // informers can be started anymore and Start will return without + // doing anything. + // + // In addition, Shutdown blocks until all goroutines have terminated. For that + // to happen, the close channel(s) that they were started with must be closed, + // either before Shutdown gets called or while it is waiting. + // + // Shutdown may be called multiple times, even concurrently. All such calls will + // block until all goroutines have terminated. + Shutdown() + + // WaitForCacheSync blocks until all started informers' caches were synced + // or the stop channel gets closed. + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + // ForResource gives generic access to a shared informer of the matching type. + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + + // InformerFor returns the SharedIndexInformer for obj using an internal + // client. + InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer + + Kmesh() kmeshnodeinfo.Interface +} + +func (f *sharedInformerFactory) Kmesh() kmeshnodeinfo.Interface { + return kmeshnodeinfo.New(f, f.namespace, f.tweakListOptions) +} diff --git a/pkg/kube/nodeinfo/informers/externalversions/generic.go b/pkg/kube/nodeinfo/informers/externalversions/generic.go new file mode 100644 index 000000000..eeb0374d2 --- /dev/null +++ b/pkg/kube/nodeinfo/informers/externalversions/generic.go @@ -0,0 +1,61 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + fmt "fmt" + + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + v1alpha1 "kmesh.net/kmesh/pkg/kube/apis/kmeshnodeinfo/v1alpha1" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=kmesh.net, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("kmeshnodeinfos"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Kmesh().V1alpha1().KmeshNodeInfos().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/pkg/kube/nodeinfo/informers/externalversions/internalinterfaces/factory_interfaces.go b/pkg/kube/nodeinfo/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 000000000..2bf0a5b51 --- /dev/null +++ b/pkg/kube/nodeinfo/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,39 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" + versioned "kmesh.net/kmesh/pkg/kube/nodeinfo/clientset/versioned" +) + +// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +// TweakListOptionsFunc is a function that transforms a v1.ListOptions. +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/pkg/kube/nodeinfo/informers/externalversions/kmeshnodeinfo/interface.go b/pkg/kube/nodeinfo/informers/externalversions/kmeshnodeinfo/interface.go new file mode 100644 index 000000000..59bd1b376 --- /dev/null +++ b/pkg/kube/nodeinfo/informers/externalversions/kmeshnodeinfo/interface.go @@ -0,0 +1,45 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by informer-gen. DO NOT EDIT. + +package kmeshnodeinfo + +import ( + internalinterfaces "kmesh.net/kmesh/pkg/kube/nodeinfo/informers/externalversions/internalinterfaces" + v1alpha1 "kmesh.net/kmesh/pkg/kube/nodeinfo/informers/externalversions/kmeshnodeinfo/v1alpha1" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1alpha1 provides access to shared informers for resources in V1alpha1. + V1alpha1() v1alpha1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1alpha1 returns a new v1alpha1.Interface. +func (g *group) V1alpha1() v1alpha1.Interface { + return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/kube/nodeinfo/informers/externalversions/kmeshnodeinfo/v1alpha1/interface.go b/pkg/kube/nodeinfo/informers/externalversions/kmeshnodeinfo/v1alpha1/interface.go new file mode 100644 index 000000000..f520c53cc --- /dev/null +++ b/pkg/kube/nodeinfo/informers/externalversions/kmeshnodeinfo/v1alpha1/interface.go @@ -0,0 +1,44 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + internalinterfaces "kmesh.net/kmesh/pkg/kube/nodeinfo/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // KmeshNodeInfos returns a KmeshNodeInfoInformer. + KmeshNodeInfos() KmeshNodeInfoInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// KmeshNodeInfos returns a KmeshNodeInfoInformer. +func (v *version) KmeshNodeInfos() KmeshNodeInfoInformer { + return &kmeshNodeInfoInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/kube/nodeinfo/informers/externalversions/kmeshnodeinfo/v1alpha1/kmeshnodeinfo.go b/pkg/kube/nodeinfo/informers/externalversions/kmeshnodeinfo/v1alpha1/kmeshnodeinfo.go new file mode 100644 index 000000000..2ac63b4fe --- /dev/null +++ b/pkg/kube/nodeinfo/informers/externalversions/kmeshnodeinfo/v1alpha1/kmeshnodeinfo.go @@ -0,0 +1,89 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + apiskmeshnodeinfov1alpha1 "kmesh.net/kmesh/pkg/kube/apis/kmeshnodeinfo/v1alpha1" + versioned "kmesh.net/kmesh/pkg/kube/nodeinfo/clientset/versioned" + internalinterfaces "kmesh.net/kmesh/pkg/kube/nodeinfo/informers/externalversions/internalinterfaces" + kmeshnodeinfov1alpha1 "kmesh.net/kmesh/pkg/kube/nodeinfo/listers/kmeshnodeinfo/v1alpha1" +) + +// KmeshNodeInfoInformer provides access to a shared informer and lister for +// KmeshNodeInfos. +type KmeshNodeInfoInformer interface { + Informer() cache.SharedIndexInformer + Lister() kmeshnodeinfov1alpha1.KmeshNodeInfoLister +} + +type kmeshNodeInfoInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewKmeshNodeInfoInformer constructs a new informer for KmeshNodeInfo type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewKmeshNodeInfoInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredKmeshNodeInfoInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredKmeshNodeInfoInformer constructs a new informer for KmeshNodeInfo type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredKmeshNodeInfoInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.KmeshV1alpha1().KmeshNodeInfos(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.KmeshV1alpha1().KmeshNodeInfos(namespace).Watch(context.TODO(), options) + }, + }, + &apiskmeshnodeinfov1alpha1.KmeshNodeInfo{}, + resyncPeriod, + indexers, + ) +} + +func (f *kmeshNodeInfoInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredKmeshNodeInfoInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *kmeshNodeInfoInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apiskmeshnodeinfov1alpha1.KmeshNodeInfo{}, f.defaultInformer) +} + +func (f *kmeshNodeInfoInformer) Lister() kmeshnodeinfov1alpha1.KmeshNodeInfoLister { + return kmeshnodeinfov1alpha1.NewKmeshNodeInfoLister(f.Informer().GetIndexer()) +} diff --git a/pkg/kube/nodeinfo/listers/kmeshnodeinfo/v1alpha1/expansion_generated.go b/pkg/kube/nodeinfo/listers/kmeshnodeinfo/v1alpha1/expansion_generated.go new file mode 100644 index 000000000..506d079f6 --- /dev/null +++ b/pkg/kube/nodeinfo/listers/kmeshnodeinfo/v1alpha1/expansion_generated.go @@ -0,0 +1,26 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +// KmeshNodeInfoListerExpansion allows custom methods to be added to +// KmeshNodeInfoLister. +type KmeshNodeInfoListerExpansion interface{} + +// KmeshNodeInfoNamespaceListerExpansion allows custom methods to be added to +// KmeshNodeInfoNamespaceLister. +type KmeshNodeInfoNamespaceListerExpansion interface{} diff --git a/pkg/kube/nodeinfo/listers/kmeshnodeinfo/v1alpha1/kmeshnodeinfo.go b/pkg/kube/nodeinfo/listers/kmeshnodeinfo/v1alpha1/kmeshnodeinfo.go new file mode 100644 index 000000000..bcc68710f --- /dev/null +++ b/pkg/kube/nodeinfo/listers/kmeshnodeinfo/v1alpha1/kmeshnodeinfo.go @@ -0,0 +1,69 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" + kmeshnodeinfov1alpha1 "kmesh.net/kmesh/pkg/kube/apis/kmeshnodeinfo/v1alpha1" +) + +// KmeshNodeInfoLister helps list KmeshNodeInfos. +// All objects returned here must be treated as read-only. +type KmeshNodeInfoLister interface { + // List lists all KmeshNodeInfos in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*kmeshnodeinfov1alpha1.KmeshNodeInfo, err error) + // KmeshNodeInfos returns an object that can list and get KmeshNodeInfos. + KmeshNodeInfos(namespace string) KmeshNodeInfoNamespaceLister + KmeshNodeInfoListerExpansion +} + +// kmeshNodeInfoLister implements the KmeshNodeInfoLister interface. +type kmeshNodeInfoLister struct { + listers.ResourceIndexer[*kmeshnodeinfov1alpha1.KmeshNodeInfo] +} + +// NewKmeshNodeInfoLister returns a new KmeshNodeInfoLister. +func NewKmeshNodeInfoLister(indexer cache.Indexer) KmeshNodeInfoLister { + return &kmeshNodeInfoLister{listers.New[*kmeshnodeinfov1alpha1.KmeshNodeInfo](indexer, kmeshnodeinfov1alpha1.Resource("kmeshnodeinfo"))} +} + +// KmeshNodeInfos returns an object that can list and get KmeshNodeInfos. +func (s *kmeshNodeInfoLister) KmeshNodeInfos(namespace string) KmeshNodeInfoNamespaceLister { + return kmeshNodeInfoNamespaceLister{listers.NewNamespaced[*kmeshnodeinfov1alpha1.KmeshNodeInfo](s.ResourceIndexer, namespace)} +} + +// KmeshNodeInfoNamespaceLister helps list and get KmeshNodeInfos. +// All objects returned here must be treated as read-only. +type KmeshNodeInfoNamespaceLister interface { + // List lists all KmeshNodeInfos in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*kmeshnodeinfov1alpha1.KmeshNodeInfo, err error) + // Get retrieves the KmeshNodeInfo from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*kmeshnodeinfov1alpha1.KmeshNodeInfo, error) + KmeshNodeInfoNamespaceListerExpansion +} + +// kmeshNodeInfoNamespaceLister implements the KmeshNodeInfoNamespaceLister +// interface. +type kmeshNodeInfoNamespaceLister struct { + listers.ResourceIndexer[*kmeshnodeinfov1alpha1.KmeshNodeInfo] +} diff --git a/pkg/utils/tc.go b/pkg/utils/tc.go new file mode 100644 index 000000000..9dd068269 --- /dev/null +++ b/pkg/utils/tc.go @@ -0,0 +1,140 @@ +/* + * Copyright The Kmesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package utils + +import ( + "fmt" + "net" + "strings" + + "github.com/cilium/ebpf" + "github.com/safchain/ethtool" + "github.com/vishvananda/netlink" + "golang.org/x/sys/unix" + + "kmesh.net/kmesh/pkg/constants" +) + +func ManageTCProgramByFd(link netlink.Link, tcFd int, mode int) error { + if mode == constants.TC_ATTACH { + if err := replaceQdisc(link); err != nil { + return fmt.Errorf("failed to replace qdisc for interface %v: %v", link.Attrs().Name, err) + } + } + + var parent uint32 = netlink.HANDLE_MIN_INGRESS + var tcName string = "tc_ingress" + filter := &netlink.BpfFilter{ + FilterAttrs: netlink.FilterAttrs{ + LinkIndex: link.Attrs().Index, + Parent: parent, + Handle: 1, + Protocol: unix.ETH_P_ALL, + Priority: 1, + }, + Fd: tcFd, + Name: fmt.Sprintf("%s-%s", tcName, link.Attrs().Name), + DirectAction: true, + } + + if mode == constants.TC_ATTACH { + if err := netlink.FilterReplace(filter); err != nil { + return fmt.Errorf("failed to replace filter for interface %v: %v", link.Attrs().Name, err) + } + } else if mode == constants.TC_DETACH { + if err := netlink.FilterDel(filter); err != nil { + return fmt.Errorf("failed to delete filter for interface %v: %v", link.Attrs().Name, err) + } + } else { + return fmt.Errorf("invalid mode in ManageTCProgramByFd") + } + return nil +} + +func ManageTCProgram(link netlink.Link, tc *ebpf.Program, mode int) error { + return ManageTCProgramByFd(link, tc.FD(), mode) +} + +func replaceQdisc(link netlink.Link) error { + attrs := netlink.QdiscAttrs{ + LinkIndex: link.Attrs().Index, + Handle: netlink.MakeHandle(0xffff, 0), + Parent: netlink.HANDLE_CLSACT, + } + + qdisc := &netlink.GenericQdisc{ + QdiscAttrs: attrs, + QdiscType: "clsact", + } + + return netlink.QdiscReplace(qdisc) +} + +func GetVethPeerIndexFromName(ifaceName string) (uint64, error) { + var ifIndex uint64 + ethHandle, err := ethtool.NewEthtool() + if err != nil { + return 0, err + } + defer ethHandle.Close() + if driver, err := ethHandle.DriverName(ifaceName); err != nil { + return 0, fmt.Errorf("failed to get %v driver name, %v", ifaceName, err) + } else if strings.Compare(driver, "veth") != 0 { + return 0, fmt.Errorf("interface: %v is %v, not a veth", ifaceName, driver) + } + + if stats, err := ethHandle.Stats(ifaceName); err != nil { + return 0, fmt.Errorf("failed to get %v stats, %v", ifaceName, err) + } else { + ifIndex = stats["peer_ifindex"] + } + return ifIndex, nil +} + +func GetVethPeerIndexFromInterface(iface net.Interface) (uint64, error) { + if iface.Flags&net.FlagLoopback != 0 { + return 0, fmt.Errorf("interface: %v is a local interface", iface) + } + + if iface.Flags&net.FlagUp == 0 { + return 0, fmt.Errorf("interface: %v not up", iface) + } + + return GetVethPeerIndexFromName(iface.Name) +} + +func IfaceContainIPs(iface net.Interface, IPs []string) (bool, error) { + addresses, err := iface.Addrs() + if err != nil { + return false, fmt.Errorf("failed to get interface %v address: %v", iface.Name, err) + } + + for _, rawAddr := range addresses { + addr, ok := rawAddr.(*net.IPNet) + if !ok { + log.Warnf("failed to convert ifaddr %v, %v", rawAddr, err) + continue + } + for _, rawLocalAddr := range IPs { + localAddr := net.ParseIP(rawLocalAddr) + if addr.IP.Equal(localAddr) { + return true, nil + } + } + } + return false, nil +}