mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-12-24 11:51:13 +08:00
refactor: optimize get pod/service netowrk cidr logic (#585)
This commit is contained in:
@@ -216,12 +216,7 @@ func (m *Manager) Get(ctx context.Context, key string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if cm != nil && cm.Data != nil {
|
||||
if v, ok := cm.Data[key]; ok {
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("can not get data")
|
||||
return cm.Data[key], nil
|
||||
}
|
||||
|
||||
func (m *Manager) ForEach(ctx context.Context, fnv4 func(net.IP), fnv6 func(net.IP)) error {
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"slices"
|
||||
"sort"
|
||||
@@ -411,17 +410,19 @@ func (c *ConnectOptions) startLocalTunServer(ctx context.Context, forwardAddress
|
||||
}
|
||||
// add extra-cidr
|
||||
for _, s := range c.ExtraRouteInfo.ExtraCIDR {
|
||||
var ipnet *net.IPNet
|
||||
_, ipnet, err = net.ParseCIDR(s)
|
||||
var ipNet *net.IPNet
|
||||
_, ipNet, err = net.ParseCIDR(s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid extra-cidr %s, err: %v", s, err)
|
||||
}
|
||||
cidrList = append(cidrList, ipnet)
|
||||
cidrList = append(cidrList, ipNet)
|
||||
}
|
||||
|
||||
var routes []types.Route
|
||||
for _, ipNet := range util.RemoveLargerOverlappingCIDRs(cidrList) {
|
||||
routes = append(routes, types.Route{Dst: *ipNet})
|
||||
if ipNet != nil {
|
||||
routes = append(routes, types.Route{Dst: *ipNet})
|
||||
}
|
||||
}
|
||||
|
||||
tunConfig := tun.Config{
|
||||
@@ -761,78 +762,45 @@ func (c *ConnectOptions) GetRunningPodList(ctx context.Context) ([]v1.Pod, error
|
||||
// https://stackoverflow.com/questions/45903123/kubernetes-set-service-cidr-and-pod-cidr-the-same
|
||||
// https://stackoverflow.com/questions/44190607/how-do-you-find-the-cluster-service-cidr-of-a-kubernetes-cluster/54183373#54183373
|
||||
// https://stackoverflow.com/questions/44190607/how-do-you-find-the-cluster-service-cidr-of-a-kubernetes-cluster
|
||||
func (c *ConnectOptions) getCIDR(ctx context.Context, m *dhcp.Manager) (err error) {
|
||||
defer func() {
|
||||
if err == nil {
|
||||
u, err2 := url.Parse(c.config.Host)
|
||||
if err2 != nil {
|
||||
return
|
||||
}
|
||||
host, _, err3 := net.SplitHostPort(u.Host)
|
||||
if err3 != nil {
|
||||
return
|
||||
}
|
||||
var ipList []net.IP
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
ipList = append(ipList, ip)
|
||||
}
|
||||
ips, _ := net.LookupIP(host)
|
||||
if ips != nil {
|
||||
ipList = append(ipList, ips...)
|
||||
}
|
||||
c.apiServerIPs = ipList
|
||||
c.removeCIDRsContainingIPs(ipList)
|
||||
}
|
||||
}()
|
||||
func (c *ConnectOptions) getCIDR(ctx context.Context, m *dhcp.Manager) error {
|
||||
var err error
|
||||
c.apiServerIPs, err = util.GetAPIServerIP(c.config.Host)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// (1) get CIDR from cache
|
||||
var value string
|
||||
value, err = m.Get(ctx, config.KeyClusterIPv4POOLS)
|
||||
if err == nil {
|
||||
for _, s := range strings.Split(value, " ") {
|
||||
var ipPoolStr string
|
||||
ipPoolStr, err = m.Get(ctx, config.KeyClusterIPv4POOLS)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ipPoolStr != "" {
|
||||
for _, s := range strings.Split(ipPoolStr, " ") {
|
||||
_, cidr, _ := net.ParseCIDR(s)
|
||||
if cidr != nil {
|
||||
c.cidrs = util.RemoveLargerOverlappingCIDRs(append(c.cidrs, cidr))
|
||||
c.cidrs = util.RemoveCIDRsContainingIPs(util.RemoveLargerOverlappingCIDRs(append(c.cidrs, cidr)), c.apiServerIPs)
|
||||
}
|
||||
}
|
||||
if len(c.cidrs) != 0 {
|
||||
plog.G(ctx).Infoln("Get network CIDR from cache")
|
||||
return nil
|
||||
}
|
||||
plog.G(ctx).Infoln("Get network CIDR from cache")
|
||||
return nil
|
||||
}
|
||||
|
||||
// (2) get CIDR from cni
|
||||
c.cidrs, err = util.GetCIDRElegant(ctx, c.clientset, c.config, c.Namespace)
|
||||
c.cidrs, err = util.GetCIDR(ctx, c.clientset, c.config, c.Namespace)
|
||||
c.cidrs = util.RemoveCIDRsContainingIPs(util.RemoveLargerOverlappingCIDRs(c.cidrs), c.apiServerIPs)
|
||||
if err == nil {
|
||||
s := sets.New[string]()
|
||||
for _, cidr := range c.cidrs {
|
||||
s.Insert(cidr.String())
|
||||
}
|
||||
cidrs := util.GetCIDRFromResourceUgly(ctx, c.clientset, c.Namespace)
|
||||
for _, cidr := range cidrs {
|
||||
s.Insert(cidr.String())
|
||||
}
|
||||
c.cidrs = util.RemoveLargerOverlappingCIDRs(append(c.cidrs, cidrs...))
|
||||
_ = m.Set(ctx, config.KeyClusterIPv4POOLS, strings.Join(s.UnsortedList(), " "))
|
||||
return nil
|
||||
return m.Set(ctx, config.KeyClusterIPv4POOLS, strings.Join(s.UnsortedList(), " "))
|
||||
}
|
||||
|
||||
// (3) fallback to get cidr from node/pod/service
|
||||
c.cidrs = util.GetCIDRFromResourceUgly(ctx, c.clientset, c.Namespace)
|
||||
// ignore error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ConnectOptions) removeCIDRsContainingIPs(ipList []net.IP) {
|
||||
for i := len(c.cidrs) - 1; i >= 0; i-- {
|
||||
for _, ip := range ipList {
|
||||
if c.cidrs[i].Contains(ip) {
|
||||
c.cidrs = append(c.cidrs[:i], c.cidrs[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConnectOptions) addExtraRoute(ctx context.Context, name string) error {
|
||||
if len(c.ExtraRouteInfo.ExtraDomain) == 0 {
|
||||
return nil
|
||||
|
||||
@@ -27,134 +27,6 @@ func TestRoute(t *testing.T) {
|
||||
t.Logf("iface: %s, gateway: %s, src: %s", iface.Name, gateway, src)
|
||||
}
|
||||
|
||||
func TestRemoveCIDRsContainingIPs(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
cidrStrings []string
|
||||
ipStrings []string
|
||||
expectedCIDRs []string
|
||||
expectPanic bool
|
||||
}{
|
||||
{
|
||||
name: "Normal case - some overlaps",
|
||||
cidrStrings: []string{
|
||||
"10.140.45.0/24", "10.140.44.0/24", "10.31.0.0/24", "10.31.1.0/24", "10.31.2.0/24", "10.31.3.0/24", "10.140.47.0/24", "10.140.46.0/24",
|
||||
},
|
||||
ipStrings: []string{
|
||||
"10.140.45.1", "10.140.46.220", "10.140.45.180", "10.140.45.152",
|
||||
"10.140.46.183", "10.140.45.52", "10.140.47.148", "10.140.46.214",
|
||||
},
|
||||
expectedCIDRs: []string{
|
||||
"10.140.44.0/24", "10.31.0.0/24", "10.31.1.0/24", "10.31.2.0/24", "10.31.3.0/24",
|
||||
},
|
||||
expectPanic: false,
|
||||
},
|
||||
{
|
||||
name: "Empty CIDR list",
|
||||
cidrStrings: []string{},
|
||||
ipStrings: []string{
|
||||
"10.140.45.1",
|
||||
},
|
||||
expectedCIDRs: []string{},
|
||||
expectPanic: false,
|
||||
},
|
||||
{
|
||||
name: "Empty IP list",
|
||||
cidrStrings: []string{
|
||||
"10.140.45.0/24", "10.140.44.0/24",
|
||||
},
|
||||
ipStrings: []string{},
|
||||
expectedCIDRs: []string{
|
||||
"10.140.45.0/24", "10.140.44.0/24",
|
||||
},
|
||||
expectPanic: false,
|
||||
},
|
||||
{
|
||||
name: "All CIDRs removed",
|
||||
cidrStrings: []string{
|
||||
"10.140.45.0/24", "10.140.46.0/24",
|
||||
},
|
||||
ipStrings: []string{
|
||||
"10.140.45.1", "10.140.46.220",
|
||||
},
|
||||
expectedCIDRs: []string{},
|
||||
expectPanic: false,
|
||||
},
|
||||
{
|
||||
name: "Overlapping CIDRs",
|
||||
cidrStrings: []string{
|
||||
"10.140.45.0/24", "10.140.45.0/25", "10.140.45.128/25",
|
||||
},
|
||||
ipStrings: []string{
|
||||
"10.140.45.1", "10.140.45.129",
|
||||
},
|
||||
expectedCIDRs: []string{},
|
||||
expectPanic: false,
|
||||
},
|
||||
{
|
||||
name: "Invalid CIDR format",
|
||||
cidrStrings: []string{
|
||||
"10.140.45.0/24", "invalid-cidr",
|
||||
},
|
||||
ipStrings: []string{
|
||||
"10.140.45.1",
|
||||
},
|
||||
expectedCIDRs: nil, // Panic expected
|
||||
expectPanic: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if !test.expectPanic {
|
||||
t.Errorf("unexpected panic: %v", r)
|
||||
}
|
||||
} else if test.expectPanic {
|
||||
t.Errorf("expected panic but got none")
|
||||
}
|
||||
}()
|
||||
|
||||
var cidrs []*net.IPNet
|
||||
for _, cidr := range test.cidrStrings {
|
||||
_, ipNet, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
if test.expectPanic {
|
||||
panic(err)
|
||||
}
|
||||
t.Fatalf("failed to parse CIDR %s: %v", cidr, err)
|
||||
}
|
||||
cidrs = append(cidrs, ipNet)
|
||||
}
|
||||
|
||||
var ipList []net.IP
|
||||
for _, ip := range test.ipStrings {
|
||||
parsedIP := net.ParseIP(ip)
|
||||
if parsedIP == nil {
|
||||
t.Fatalf("failed to parse IP %s", ip)
|
||||
}
|
||||
ipList = append(ipList, parsedIP)
|
||||
}
|
||||
|
||||
c := &ConnectOptions{
|
||||
cidrs: cidrs,
|
||||
}
|
||||
c.removeCIDRsContainingIPs(ipList)
|
||||
if !test.expectPanic {
|
||||
if len(c.cidrs) != len(test.expectedCIDRs) {
|
||||
t.Fatalf("unexpected number of remaining CIDRs: got %d, want %d", len(c.cidrs), len(test.expectedCIDRs))
|
||||
}
|
||||
for i, cidr := range c.cidrs {
|
||||
if cidr.String() != test.expectedCIDRs[i] {
|
||||
t.Errorf("unexpected CIDR at index %d: got %s, want %s", i, cidr.String(), test.expectedCIDRs[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSort(t *testing.T) {
|
||||
list := v1.PodList{
|
||||
Items: []v1.Pod{
|
||||
|
||||
@@ -101,7 +101,7 @@ func addTunRoutes(ifName string, routes ...types.Route) error {
|
||||
|
||||
var prefixList []netip.Prefix
|
||||
for _, r := range routes {
|
||||
if r.Dst.String() == "" {
|
||||
if net.ParseIP(r.Dst.IP.String()) == nil {
|
||||
continue
|
||||
}
|
||||
var prefix netip.Prefix
|
||||
@@ -116,7 +116,7 @@ func addTunRoutes(ifName string, routes ...types.Route) error {
|
||||
}
|
||||
err = addRoute(gw, prefixList...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add route: %v", err)
|
||||
return fmt.Errorf("failed to add dst %v via %s to route table: %v", prefixList, ifName, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -107,13 +107,13 @@ func createTun(cfg Config) (conn net.Conn, itf *net.Interface, err error) {
|
||||
|
||||
func addTunRoutes(ifName string, routes ...types.Route) error {
|
||||
for _, route := range routes {
|
||||
if route.Dst.String() == "" {
|
||||
if net.ParseIP(route.Dst.IP.String()) == nil {
|
||||
continue
|
||||
}
|
||||
// ip route add 192.168.1.123/32 dev utun0
|
||||
err := netlink.AddRoute(route.Dst.String(), "", "", ifName)
|
||||
if err != nil && !errors.Is(err, syscall.EEXIST) {
|
||||
return fmt.Errorf("failed to add route: %v", err)
|
||||
return fmt.Errorf("failed to add dst %v via %s to route table: %v", route.Dst.String(), ifName, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -135,7 +135,7 @@ func addTunRoutes(tunName string, routes ...types.Route) error {
|
||||
return err
|
||||
}
|
||||
for _, route := range routes {
|
||||
if route.Dst.String() == "" {
|
||||
if net.ParseIP(route.Dst.IP.String()) == nil {
|
||||
continue
|
||||
}
|
||||
if route.GW == nil {
|
||||
|
||||
239
pkg/util/cidr.go
239
pkg/util/cidr.go
@@ -5,6 +5,8 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -26,12 +28,12 @@ import (
|
||||
plog "github.com/wencaiwulue/kubevpn/v2/pkg/log"
|
||||
)
|
||||
|
||||
// GetCIDRElegant
|
||||
// GetCIDR
|
||||
// 1) dump cluster info
|
||||
// 2) grep cmdline
|
||||
// 3) create svc + cat *.conflist
|
||||
// 4) create svc + get pod ip with svc mask
|
||||
func GetCIDRElegant(ctx context.Context, clientset *kubernetes.Clientset, restconfig *rest.Config, namespace string) ([]*net.IPNet, error) {
|
||||
func GetCIDR(ctx context.Context, clientset *kubernetes.Clientset, restconfig *rest.Config, namespace string) ([]*net.IPNet, error) {
|
||||
defer func() {
|
||||
_ = clientset.CoreV1().Pods(namespace).Delete(context.Background(), config.CniNetName, v1.DeleteOptions{GracePeriodSeconds: pointer.Int64(0)})
|
||||
}()
|
||||
@@ -51,107 +53,26 @@ func GetCIDRElegant(ctx context.Context, clientset *kubernetes.Clientset, restco
|
||||
result = append(result, cni...)
|
||||
}
|
||||
|
||||
pod, err := GetPodCIDRFromCNI(ctx, clientset, restconfig, namespace)
|
||||
podCIDR, err := GetPodCIDRFromCNI(ctx, clientset, restconfig, namespace)
|
||||
if err == nil {
|
||||
result = append(result, pod...)
|
||||
}
|
||||
|
||||
svc, err := GetServiceCIDRByCreateService(ctx, clientset.CoreV1().Services(namespace))
|
||||
if err == nil {
|
||||
result = append(result, svc)
|
||||
result = append(result, podCIDR...)
|
||||
}
|
||||
|
||||
plog.G(ctx).Infoln("Getting network CIDR from services...")
|
||||
pod, err = GetPodCIDRFromPod(ctx, clientset, namespace, svc)
|
||||
if err == nil {
|
||||
svcCIDR, _ := GetServiceCIDRByCreateService(ctx, clientset.CoreV1().Services(namespace))
|
||||
if svcCIDR != nil {
|
||||
plog.G(ctx).Debugf("Getting network CIDR from services successfully")
|
||||
result = append(result, pod...)
|
||||
result = append(result, svcCIDR)
|
||||
|
||||
podCIDR, err = GetPodCIDRFromPod(ctx, clientset, namespace, svcCIDR)
|
||||
if err == nil {
|
||||
result = append(result, podCIDR...)
|
||||
}
|
||||
}
|
||||
|
||||
result = RemoveLargerOverlappingCIDRs(result)
|
||||
if len(result) == 0 {
|
||||
err = fmt.Errorf("failed to get any network CIDR, please verify that you have the necessary permissions")
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetCIDRFromResourceUgly
|
||||
// use podIP/24 and serviceIP/24 as cidr
|
||||
func GetCIDRFromResourceUgly(ctx context.Context, clientset *kubernetes.Clientset, namespace string) []*net.IPNet {
|
||||
var cidrs []*net.IPNet
|
||||
// (2) get pod CIDR from pod ip, why doing this: notice that node's pod cidr is not correct in minikube
|
||||
// ➜ ~ kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}'
|
||||
//10.244.0.0/24%
|
||||
// ➜ ~ kubectl get pods -o=custom-columns=podIP:.status.podIP
|
||||
//podIP
|
||||
//172.17.0.5
|
||||
//172.17.0.4
|
||||
//172.17.0.4
|
||||
//172.17.0.3
|
||||
//172.17.0.3
|
||||
//172.17.0.6
|
||||
//172.17.0.8
|
||||
//172.17.0.3
|
||||
//172.17.0.7
|
||||
//172.17.0.2
|
||||
for _, n := range []string{v1.NamespaceAll, namespace} {
|
||||
podList, err := clientset.CoreV1().Pods(n).List(ctx, v1.ListOptions{})
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, pod := range podList.Items {
|
||||
if pod.Spec.HostNetwork {
|
||||
continue
|
||||
}
|
||||
s := sets.Set[string]{}.Insert(pod.Status.PodIP)
|
||||
for _, p := range pod.Status.PodIPs {
|
||||
s.Insert(p.IP)
|
||||
}
|
||||
for _, t := range s.UnsortedList() {
|
||||
if ip := net.ParseIP(t); ip != nil {
|
||||
var mask net.IPMask
|
||||
if ip.To4() != nil {
|
||||
mask = net.CIDRMask(24, 32)
|
||||
} else {
|
||||
mask = net.CIDRMask(64, 128)
|
||||
}
|
||||
cidrs = append(cidrs, &net.IPNet{IP: ip.Mask(mask), Mask: mask})
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// (2) get service CIDR
|
||||
for _, n := range []string{v1.NamespaceAll, namespace} {
|
||||
serviceList, err := clientset.CoreV1().Services(n).List(ctx, v1.ListOptions{})
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, service := range serviceList.Items {
|
||||
s := sets.Set[string]{}.Insert(service.Spec.ClusterIP)
|
||||
for _, p := range service.Spec.ClusterIPs {
|
||||
s.Insert(p)
|
||||
}
|
||||
for _, t := range s.UnsortedList() {
|
||||
if ip := net.ParseIP(t); ip != nil {
|
||||
var mask net.IPMask
|
||||
if ip.To4() != nil {
|
||||
mask = net.CIDRMask(24, 32)
|
||||
} else {
|
||||
mask = net.CIDRMask(64, 128)
|
||||
}
|
||||
cidrs = append(cidrs, &net.IPNet{IP: ip.Mask(mask), Mask: mask})
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return cidrs
|
||||
}
|
||||
|
||||
// ParseCIDRFromString
|
||||
/*
|
||||
*
|
||||
@@ -170,8 +91,8 @@ func ParseCIDRFromString(content string) (result []*net.IPNet) {
|
||||
if len(split) == 2 {
|
||||
cidrList := split[1]
|
||||
for _, cidr := range strings.Split(cidrList, ",") {
|
||||
_, c, err := net.ParseCIDR(cidr)
|
||||
if err == nil {
|
||||
_, c, _ := net.ParseCIDR(cidr)
|
||||
if c != nil {
|
||||
result = append(result, c)
|
||||
}
|
||||
}
|
||||
@@ -185,7 +106,7 @@ func ParseCIDRFromString(content string) (result []*net.IPNet) {
|
||||
// ref: https://kubernetes.io/docs/concepts/services-networking/dual-stack/#configure-ipv4-ipv6-dual-stack
|
||||
// get cidr by dump cluster info
|
||||
func GetCIDRByDumpClusterInfo(ctx context.Context, clientset *kubernetes.Clientset) ([]*net.IPNet, error) {
|
||||
podList, err := clientset.CoreV1().Pods(v1.NamespaceSystem).List(ctx, v1.ListOptions{})
|
||||
podList, err := clientset.CoreV1().Pods(v1.NamespaceSystem).List(ctx, v1.ListOptions{Limit: 100})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -201,7 +122,7 @@ func GetCIDRByDumpClusterInfo(ctx context.Context, clientset *kubernetes.Clients
|
||||
for _, s := range list {
|
||||
result = append(result, ParseCIDRFromString(s)...)
|
||||
}
|
||||
return RemoveLargerOverlappingCIDRs(result), nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetCIDRFromCNI kube-controller-manager--allocate-node-cidrs=true--authentication-kubeconfig=/etc/kubernetes/controller-manager.conf--authorization-kubeconfig=/etc/kubernetes/controller-manager.conf--bind-address=0.0.0.0--client-ca-file=/etc/kubernetes/ssl/ca.crt--cluster-cidr=10.233.64.0/18--cluster-name=cluster.local--cluster-signing-cert-file=/etc/kubernetes/ssl/ca.crt--cluster-signing-key-file=/etc/kubernetes/ssl/ca.key--configure-cloud-routes=false--controllers=*,bootstrapsigner,tokencleaner--kubeconfig=/etc/kubernetes/controller-manager.conf--leader-elect=true--leader-elect-lease-duration=15s--leader-elect-renew-deadline=10s--node-cidr-mask-size=24--node-monitor-grace-period=40s--node-monitor-period=5s--port=0--profiling=False--requestheader-client-ca-file=/etc/kubernetes/ssl/front-proxy-ca.crt--root-ca-file=/etc/kubernetes/ssl/ca.crt--service-account-private-key-file=/etc/kubernetes/ssl/sa.key--service-cluster-ip-range=10.233.0.0/18--terminated-pod-gc-threshold=12500--use-service-account-credentials=true
|
||||
@@ -221,7 +142,7 @@ func GetCIDRFromCNI(ctx context.Context, clientset *kubernetes.Clientset, restco
|
||||
|
||||
var result []*net.IPNet
|
||||
for _, s := range strings.Split(content, "\n") {
|
||||
result = RemoveLargerOverlappingCIDRs(append(result, ParseCIDRFromString(s)...))
|
||||
result = append(result, ParseCIDRFromString(s)...)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
@@ -237,15 +158,12 @@ func GetServiceCIDRByCreateService(ctx context.Context, serviceInterface v12.Ser
|
||||
if err != nil {
|
||||
idx := strings.LastIndex(err.Error(), defaultCIDRIndex)
|
||||
if idx != -1 {
|
||||
_, cidr, err := net.ParseCIDR(strings.TrimSpace(err.Error()[idx+len(defaultCIDRIndex):]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cidr, nil
|
||||
_, cidr, err1 := net.ParseCIDR(strings.TrimSpace(err.Error()[idx+len(defaultCIDRIndex):]))
|
||||
return cidr, err1
|
||||
}
|
||||
return nil, fmt.Errorf("can not found any keyword of service network CIDR info, err: %s", err.Error())
|
||||
return nil, fmt.Errorf("can not found any keyword of service network CIDR info: %s", err.Error())
|
||||
}
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("can not found any keyword of service network CIDR info")
|
||||
}
|
||||
|
||||
// GetPodCIDRFromCNI
|
||||
@@ -295,7 +213,7 @@ func GetPodCIDRFromCNI(ctx context.Context, clientset *kubernetes.Clientset, res
|
||||
return nil, err
|
||||
}
|
||||
plog.G(ctx).Infoln("Get CNI config", configList.Name)
|
||||
var cidr []*net.IPNet
|
||||
var cidrList []*net.IPNet
|
||||
for _, plugin := range configList.Plugins {
|
||||
switch plugin.Network.Type {
|
||||
case "calico":
|
||||
@@ -305,13 +223,13 @@ func GetPodCIDRFromCNI(ctx context.Context, clientset *kubernetes.Clientset, res
|
||||
slice6, _, _ := unstructured.NestedStringSlice(m, "ipam", "ipv6_pools")
|
||||
for _, s := range sets.New[string]().Insert(slice...).Insert(slice6...).UnsortedList() {
|
||||
if _, ipNet, _ := net.ParseCIDR(s); ipNet != nil {
|
||||
cidr = append(cidr, ipNet)
|
||||
cidrList = append(cidrList, ipNet)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cidr, nil
|
||||
return cidrList, nil
|
||||
}
|
||||
|
||||
func CreateCIDRPod(ctx context.Context, clientset *kubernetes.Clientset, namespace string) (*v13.Pod, error) {
|
||||
@@ -439,37 +357,110 @@ func CreateCIDRPod(ctx context.Context, clientset *kubernetes.Clientset, namespa
|
||||
}
|
||||
|
||||
func GetPodCIDRFromPod(ctx context.Context, clientset *kubernetes.Clientset, namespace string, svc *net.IPNet) ([]*net.IPNet, error) {
|
||||
podList, err := clientset.CoreV1().Pods(namespace).List(ctx, v1.ListOptions{})
|
||||
podList, err := clientset.CoreV1().Pods(namespace).List(ctx, v1.ListOptions{Limit: 100})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < len(podList.Items); i++ {
|
||||
if podList.Items[i].Spec.HostNetwork {
|
||||
podList.Items = append(podList.Items[:i], podList.Items[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
|
||||
var result []*net.IPNet
|
||||
for _, item := range podList.Items {
|
||||
if item.Spec.HostNetwork {
|
||||
continue
|
||||
}
|
||||
|
||||
s := sets.New[string]().Insert(item.Status.PodIP)
|
||||
for _, p := range item.Status.PodIPs {
|
||||
s.Insert(p.IP)
|
||||
}
|
||||
for _, t := range s.UnsortedList() {
|
||||
if ip := net.ParseIP(t); ip != nil {
|
||||
var mask net.IPMask
|
||||
if ip.To4() != nil {
|
||||
mask = net.CIDRMask(24, 32)
|
||||
} else {
|
||||
mask = net.CIDRMask(64, 128)
|
||||
_, ipNet, _ := net.ParseCIDR((&net.IPNet{IP: ip, Mask: svc.Mask}).String())
|
||||
if ipNet != nil {
|
||||
result = append(result, ipNet)
|
||||
}
|
||||
result = append(result, &net.IPNet{IP: ip, Mask: /*svc.Mask*/ mask})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(result) == 0 {
|
||||
return nil, fmt.Errorf("can not found pod network CIDR from pod list")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func RemoveCIDRsContainingIPs(cidrs []*net.IPNet, ipList []net.IP) []*net.IPNet {
|
||||
for i := len(cidrs) - 1; i >= 0; i-- {
|
||||
for _, ip := range ipList {
|
||||
if cidrs[i].Contains(ip) {
|
||||
cidrs = append(cidrs[:i], cidrs[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return cidrs
|
||||
}
|
||||
|
||||
func GetAPIServerIP(apiServerHost string) ([]net.IP, error) {
|
||||
u, err := url.Parse(apiServerHost)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var host string
|
||||
if strings.IndexByte(u.Host, ':') < 0 {
|
||||
host = u.Host
|
||||
} else {
|
||||
host, _, err = net.SplitHostPort(u.Host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var ipList []net.IP
|
||||
var set = sets.New[string]()
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
if !set.Has(ip.String()) {
|
||||
ipList = append(ipList, ip)
|
||||
set.Insert(ip.String())
|
||||
}
|
||||
}
|
||||
|
||||
addrs, _ := net.LookupHost(host)
|
||||
for _, addr := range addrs {
|
||||
ip := net.ParseIP(addr)
|
||||
if ip == nil {
|
||||
continue
|
||||
}
|
||||
if !set.Has(ip.String()) {
|
||||
ipList = append(ipList, ip)
|
||||
set.Insert(ip.String())
|
||||
}
|
||||
}
|
||||
return ipList, nil
|
||||
}
|
||||
|
||||
func RemoveLargerOverlappingCIDRs(cidrNets []*net.IPNet) []*net.IPNet {
|
||||
sort.Slice(cidrNets, func(i, j int) bool {
|
||||
onesI, _ := cidrNets[i].Mask.Size()
|
||||
onesJ, _ := cidrNets[j].Mask.Size()
|
||||
// mask number is smaller, means the mask is larger
|
||||
return onesI < onesJ
|
||||
})
|
||||
|
||||
var cidrsOverlap = func(cidr1, cidr2 *net.IPNet) bool {
|
||||
return cidr1.Contains(cidr2.IP) || cidr2.Contains(cidr1.IP)
|
||||
}
|
||||
|
||||
var result []*net.IPNet
|
||||
skipped := make(map[int]bool)
|
||||
|
||||
for i := range cidrNets {
|
||||
if skipped[i] {
|
||||
continue
|
||||
}
|
||||
for j := i + 1; j < len(cidrNets); j++ {
|
||||
if cidrsOverlap(cidrNets[i], cidrNets[j]) {
|
||||
skipped[j] = true
|
||||
}
|
||||
}
|
||||
result = append(result, cidrNets[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -69,7 +71,7 @@ func TestByCreateSvc(t *testing.T) {
|
||||
|
||||
func TestElegant(t *testing.T) {
|
||||
before()
|
||||
elegant, err := GetCIDRElegant(context.Background(), clientset, restconfig, namespace)
|
||||
elegant, err := GetCIDR(context.Background(), clientset, restconfig, namespace)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -127,3 +129,181 @@ func TestPatch(t *testing.T) {
|
||||
}
|
||||
fmt.Println(string(bytes))
|
||||
}
|
||||
|
||||
func TestRemoveCIDRsContainingIPs(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
cidrStrings []string
|
||||
ipStrings []string
|
||||
expectedCIDRs []string
|
||||
expectPanic bool
|
||||
}{
|
||||
{
|
||||
name: "Normal case - some overlaps",
|
||||
cidrStrings: []string{
|
||||
"10.140.45.0/24", "10.140.44.0/24", "10.31.0.0/24", "10.31.1.0/24", "10.31.2.0/24", "10.31.3.0/24", "10.140.47.0/24", "10.140.46.0/24",
|
||||
},
|
||||
ipStrings: []string{
|
||||
"10.140.45.1", "10.140.46.220", "10.140.45.180", "10.140.45.152",
|
||||
"10.140.46.183", "10.140.45.52", "10.140.47.148", "10.140.46.214",
|
||||
},
|
||||
expectedCIDRs: []string{
|
||||
"10.140.44.0/24", "10.31.0.0/24", "10.31.1.0/24", "10.31.2.0/24", "10.31.3.0/24",
|
||||
},
|
||||
expectPanic: false,
|
||||
},
|
||||
{
|
||||
name: "Empty CIDR list",
|
||||
cidrStrings: []string{},
|
||||
ipStrings: []string{
|
||||
"10.140.45.1",
|
||||
},
|
||||
expectedCIDRs: []string{},
|
||||
expectPanic: false,
|
||||
},
|
||||
{
|
||||
name: "Empty IP list",
|
||||
cidrStrings: []string{
|
||||
"10.140.45.0/24", "10.140.44.0/24",
|
||||
},
|
||||
ipStrings: []string{},
|
||||
expectedCIDRs: []string{
|
||||
"10.140.45.0/24", "10.140.44.0/24",
|
||||
},
|
||||
expectPanic: false,
|
||||
},
|
||||
{
|
||||
name: "All CIDRs removed",
|
||||
cidrStrings: []string{
|
||||
"10.140.45.0/24", "10.140.46.0/24",
|
||||
},
|
||||
ipStrings: []string{
|
||||
"10.140.45.1", "10.140.46.220",
|
||||
},
|
||||
expectedCIDRs: []string{},
|
||||
expectPanic: false,
|
||||
},
|
||||
{
|
||||
name: "Overlapping CIDRs",
|
||||
cidrStrings: []string{
|
||||
"10.140.45.0/24", "10.140.45.0/25", "10.140.45.128/25",
|
||||
},
|
||||
ipStrings: []string{
|
||||
"10.140.45.1", "10.140.45.129",
|
||||
},
|
||||
expectedCIDRs: []string{},
|
||||
expectPanic: false,
|
||||
},
|
||||
{
|
||||
name: "Invalid CIDR format",
|
||||
cidrStrings: []string{
|
||||
"10.140.45.0/24", "invalid-cidr",
|
||||
},
|
||||
ipStrings: []string{
|
||||
"10.140.45.1",
|
||||
},
|
||||
expectedCIDRs: nil, // Panic expected
|
||||
expectPanic: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if !test.expectPanic {
|
||||
t.Errorf("unexpected panic: %v", r)
|
||||
}
|
||||
} else if test.expectPanic {
|
||||
t.Errorf("expected panic but got none")
|
||||
}
|
||||
}()
|
||||
|
||||
var cidrs []*net.IPNet
|
||||
for _, cidr := range test.cidrStrings {
|
||||
_, ipNet, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
if test.expectPanic {
|
||||
panic(err)
|
||||
}
|
||||
t.Fatalf("failed to parse CIDR %s: %v", cidr, err)
|
||||
}
|
||||
cidrs = append(cidrs, ipNet)
|
||||
}
|
||||
|
||||
var ipList []net.IP
|
||||
for _, ip := range test.ipStrings {
|
||||
parsedIP := net.ParseIP(ip)
|
||||
if parsedIP == nil {
|
||||
t.Fatalf("failed to parse IP %s", ip)
|
||||
}
|
||||
ipList = append(ipList, parsedIP)
|
||||
}
|
||||
|
||||
cidrs = RemoveCIDRsContainingIPs(cidrs, ipList)
|
||||
if !test.expectPanic {
|
||||
if len(cidrs) != len(test.expectedCIDRs) {
|
||||
t.Fatalf("unexpected number of remaining CIDRs: got %d, want %d", len(cidrs), len(test.expectedCIDRs))
|
||||
}
|
||||
for i, cidr := range cidrs {
|
||||
if cidr.String() != test.expectedCIDRs[i] {
|
||||
t.Errorf("unexpected CIDR at index %d: got %s, want %s", i, cidr.String(), test.expectedCIDRs[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveLargerOverlappingCIDRs(t *testing.T) {
|
||||
type args struct {
|
||||
cidrNets []*net.IPNet
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []*net.IPNet
|
||||
}{
|
||||
{
|
||||
name: "equal",
|
||||
args: args{
|
||||
cidrNets: []*net.IPNet{
|
||||
{IP: net.ParseIP("192.168.1.0"), Mask: net.CIDRMask(24, 32)},
|
||||
{IP: net.ParseIP("192.168.2.0"), Mask: net.CIDRMask(24, 32)},
|
||||
}},
|
||||
want: []*net.IPNet{
|
||||
{IP: net.ParseIP("192.168.1.0"), Mask: net.CIDRMask(24, 32)},
|
||||
{IP: net.ParseIP("192.168.2.0"), Mask: net.CIDRMask(24, 32)},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "larger",
|
||||
args: args{
|
||||
cidrNets: []*net.IPNet{
|
||||
{IP: net.ParseIP("192.168.1.0"), Mask: net.CIDRMask(24, 32)},
|
||||
{IP: net.ParseIP("192.168.2.0"), Mask: net.CIDRMask(16, 32)},
|
||||
}},
|
||||
want: []*net.IPNet{
|
||||
{IP: net.ParseIP("192.168.2.0"), Mask: net.CIDRMask(16, 32)},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "deduplicated",
|
||||
args: args{
|
||||
cidrNets: []*net.IPNet{
|
||||
{IP: net.ParseIP("192.168.1.0"), Mask: net.CIDRMask(24, 32)},
|
||||
{IP: net.ParseIP("192.168.1.0"), Mask: net.CIDRMask(24, 32)},
|
||||
}},
|
||||
want: []*net.IPNet{
|
||||
{IP: net.ParseIP("192.168.1.0"), Mask: net.CIDRMask(24, 32)},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := RemoveLargerOverlappingCIDRs(tt.args.cidrNets); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("RemoveLargerOverlappingCIDRs() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ var (
|
||||
)
|
||||
|
||||
const (
|
||||
addr = "https://github.com/wencaiwulue/kubevpn/releases/latest"
|
||||
downloadAddr = "https://github.com/wencaiwulue/kubevpn/releases/latest"
|
||||
)
|
||||
|
||||
func GetManifest(httpCli *http.Client, os string, arch string) (version string, url string, err error) {
|
||||
@@ -70,7 +70,7 @@ func GetManifest(httpCli *http.Client, os string, arch string) (version string,
|
||||
}
|
||||
}
|
||||
|
||||
err = fmt.Errorf("%s: try download it from: %s", If(m.Message != "", m.Message, string(content)), addr)
|
||||
err = fmt.Errorf("%s: try download it from: %s", If(m.Message != "", m.Message, string(content)), downloadAddr)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -7,13 +7,11 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
osexec "os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
@@ -234,34 +232,6 @@ func CanI(clientset *kubernetes.Clientset, sa, ns string, resource *rbacv1.Polic
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func RemoveLargerOverlappingCIDRs(cidrNets []*net.IPNet) []*net.IPNet {
|
||||
sort.Slice(cidrNets, func(i, j int) bool {
|
||||
onesI, _ := cidrNets[i].Mask.Size()
|
||||
onesJ, _ := cidrNets[j].Mask.Size()
|
||||
return onesI > onesJ
|
||||
})
|
||||
|
||||
var cidrsOverlap = func(cidr1, cidr2 *net.IPNet) bool {
|
||||
return cidr1.Contains(cidr2.IP) || cidr2.Contains(cidr1.IP)
|
||||
}
|
||||
|
||||
var result []*net.IPNet
|
||||
skipped := make(map[int]bool)
|
||||
|
||||
for i := range cidrNets {
|
||||
if skipped[i] {
|
||||
continue
|
||||
}
|
||||
for j := i + 1; j < len(cidrNets); j++ {
|
||||
if cidrsOverlap(cidrNets[i], cidrNets[j]) {
|
||||
skipped[j] = true
|
||||
}
|
||||
}
|
||||
result = append(result, cidrNets[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func CleanExtensionLib() {
|
||||
if !IsWindows() {
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user