diff --git a/.github/workflows/build-x86-image.yaml b/.github/workflows/build-x86-image.yaml index 9787017d1bf..78d1db3f3e2 100644 --- a/.github/workflows/build-x86-image.yaml +++ b/.github/workflows/build-x86-image.yaml @@ -23,7 +23,7 @@ concurrency: env: GO_VERSION: '' KIND_VERSION: v0.24.0 - GOLANGCI_LINT_VERSION: 'v1.60.1' + GOLANGCI_LINT_VERSION: 'v1.61.0' HELM_VERSION: v3.15.4 SUBMARINER_VERSION: '0.18.0' @@ -2065,9 +2065,13 @@ jobs: echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV" fi - - name: Remove DNS search domain + - name: Configure docker run: | + # enable addition of ip6tables rules + sudo sh -c "echo '{\"experimental\": true, \"ip6tables\": true}' > /etc/docker/daemon.json" + # remove DNS search domain sudo sed -i '/^search/d' /etc/resolv.conf + # restart docker sudo systemctl restart docker - uses: actions/setup-go@v5 diff --git a/.github/workflows/changelog.yaml b/.github/workflows/changelog.yaml index 11b2dbba99f..0c61e800db6 100644 --- a/.github/workflows/changelog.yaml +++ b/.github/workflows/changelog.yaml @@ -18,7 +18,7 @@ jobs: - run: git fetch --prune --prune-tags - run: git tag -l 'v*' - run: ./hack/changelog.sh > CHANGELOG.md - - uses: peter-evans/create-pull-request@v6 + - uses: peter-evans/create-pull-request@v7 with: title: 'docs: updated CHANGELOG.md' commit-message: 'docs: updated CHANGELOG.md' diff --git a/.gitignore b/.gitignore index 44f81bdd468..91a8d3ca4e2 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,4 @@ cacert.pem ovn-req.pem ovn-cert.pem ovn-privkey.pem +anp-test-report.yaml diff --git a/Makefile b/Makefile index 98cec8b0786..09ad8134e8e 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ KUBEVIRT_LAUNCHER_IMAGE = quay.io/kubevirt/virt-launcher:$(KUBEVIRT_VERSION) KUBEVIRT_OPERATOR_YAML = https://github.com/kubevirt/kubevirt/releases/download/$(KUBEVIRT_VERSION)/kubevirt-operator.yaml KUBEVIRT_CR_YAML = https://github.com/kubevirt/kubevirt/releases/download/$(KUBEVIRT_VERSION)/kubevirt-cr.yaml -CILIUM_VERSION = 1.15.8 +CILIUM_VERSION = 1.16.1 CILIUM_IMAGE_REPO = quay.io/cilium CERT_MANAGER_VERSION = v1.15.2 @@ -83,9 +83,24 @@ KWOK_IMAGE = registry.k8s.io/kwok/kwok:$(KWOK_VERSION) VPC_NAT_GW_IMG = $(REGISTRY)/vpc-nat-gateway:$(VERSION) -E2E_NETWORK = bridge -ifneq ($(VLAN_ID),) +ANP_TEST_IMAGE = registry.k8s.io/e2e-test-images/agnhost:2.45 +ANP_CR_YAML = https://raw.githubusercontent.com/kubernetes-sigs/network-policy-api/main/config/crd/standard/policy.networking.k8s.io_adminnetworkpolicies.yaml +BANP_CR_YAML = https://raw.githubusercontent.com/kubernetes-sigs/network-policy-api/main/config/crd/standard/policy.networking.k8s.io_baselineadminnetworkpolicies.yaml + E2E_NETWORK = kube-ovn-vlan + +KIND_NETWORK_UNDERLAY = $(shell echo $${KIND_NETWORK_UNDERLAY:-kind}) +UNDERLAY_VAR_PREFIX = $(shell echo $(KIND_NETWORK_UNDERLAY) | tr '[:lower:]-' '[:upper:]_') +UNDERLAY_IPV4_SUBNET = $(UNDERLAY_VAR_PREFIX)_IPV4_SUBNET +UNDERLAY_IPV6_SUBNET = $(UNDERLAY_VAR_PREFIX)_IPV6_SUBNET +UNDERLAY_IPV4_GATEWAY = $(UNDERLAY_VAR_PREFIX)_IPV4_GATEWAY +UNDERLAY_IPV6_GATEWAY = $(UNDERLAY_VAR_PREFIX)_IPV6_GATEWAY +UNDERLAY_IPV4_EXCLUDE_IPS = $(UNDERLAY_VAR_PREFIX)_IPV4_EXCLUDE_IPS +UNDERLAY_IPV6_EXCLUDE_IPS = $(UNDERLAY_VAR_PREFIX)_IPV6_EXCLUDE_IPS + +VLAN_NIC = $(shell echo $${VLAN_NIC:-eth0}) +ifneq ($(KIND_NETWORK_UNDERLAY),kind) +VLAN_NIC = eth1 endif KIND_AUDITING = $(shell echo $${KIND_AUDITING:-false}) @@ -231,30 +246,20 @@ define docker_ensure_image_exists endef define docker_rm_container - @docker ps -a -f name="$(1)" --format "{{.ID}}" | while read c; do docker rm -f $$c; done + @docker ps -a -f name="^$(1)$$" --format "{{.ID}}" | while read c; do docker rm -f $$c; done endef define docker_network_info - $(eval VAR_PREFIX = $(shell echo $(1) | tr '[:lower:]' '[:upper:]')) + $(eval VAR_PREFIX = $(shell echo $(1) | tr '[:lower:]-' '[:upper:]_')) $(eval $(VAR_PREFIX)_IPV4_SUBNET = $(shell docker network inspect $(1) -f "{{range .IPAM.Config}}{{println .Subnet}}{{end}}" | grep -v :)) $(eval $(VAR_PREFIX)_IPV6_SUBNET = $(shell docker network inspect $(1) -f "{{range .IPAM.Config}}{{println .Subnet}}{{end}}" | grep :)) $(eval $(VAR_PREFIX)_IPV4_GATEWAY = $(shell docker network inspect $(1) -f "{{range .IPAM.Config}}{{println .Gateway}}{{end}}" | grep -v :)) $(eval $(VAR_PREFIX)_IPV6_GATEWAY = $(shell docker network inspect $(1) -f "{{range .IPAM.Config}}{{println .Gateway}}{{end}}" | grep :)) - $(eval $(VAR_PREFIX)_IPV6_GATEWAY := $(shell docker exec kube-ovn-control-plane ip -6 route show default | awk '{print $$3}')) + $(eval $(VAR_PREFIX)_IPV6_GATEWAY := $(if $($(VAR_PREFIX)_IPV6_GATEWAY),$($(VAR_PREFIX)_IPV6_GATEWAY),$(shell docker exec kube-ovn-control-plane ip -6 route show default | awk '{print $$3}'))) $(eval $(VAR_PREFIX)_IPV4_EXCLUDE_IPS = $(shell docker network inspect $(1) -f '{{range .Containers}},{{index (split .IPv4Address "/") 0}}{{end}}' | sed 's/^,//')) $(eval $(VAR_PREFIX)_IPV6_EXCLUDE_IPS = $(shell docker network inspect $(1) -f '{{range .Containers}},{{index (split .IPv6Address "/") 0}}{{end}}' | sed 's/^,//')) endef -define docker_create_vlan_network - $(eval VLAN_NETWORK_ID = $(shell docker network ls -f name=$(E2E_NETWORK) --format '{{.ID}}')) - @if [ ! -z "$(VLAN_ID)" -a -z "$(VLAN_NETWORK_ID)" ]; then \ - docker network create --attachable -d bridge \ - --ipv6 --subnet fc00:adb1:b29b:608d::/64 --gateway fc00:adb1:b29b:608d::1 \ - -o com.docker.network.bridge.enable_ip_masquerade=true \ - -o com.docker.network.driver.mtu=1500 $(E2E_NETWORK); \ - fi -endef - define docker_config_bridge @set -e; \ docker network ls --format "{{.Name}}" | grep '^$(1)$$' >/dev/null || exit 0; \ @@ -290,6 +295,10 @@ define docker_config_bridge fi endef +define add_docker_iptables_rule + @sudo $(1) -t filter -C DOCKER-USER $(2) 2>/dev/null || sudo $(1) -I DOCKER-USER $(2) +endef + define kind_create_cluster kind create cluster --config $(1) --name $(2) @if [ "x$(3)" = "x1" ]; then \ @@ -356,17 +365,43 @@ define subctl_join $(call kubectl_wait_submariner_ready) endef +.PHONY: kind-network-create-underlay +kind-network-create-underlay: + $(eval UNDERLAY_NETWORK_ID = $(shell docker network ls -f name='^kind-underlay$$' --format '{{.ID}}')) + @if [ -z "$(UNDERLAY_NETWORK_ID)" ]; then \ + docker network create --attachable -d bridge \ + --ipv6 --subnet fc00:adb1:b29b:608d::/64 --gateway fc00:adb1:b29b:608d::1 \ + -o com.docker.network.bridge.enable_ip_masquerade=true \ + -o com.docker.network.driver.mtu=1500 kind-underlay; \ + fi + +.PHONY: kind-network-connect-underlay +kind-network-connect-underlay: + @for node in `kind -n kube-ovn get nodes`; do \ + docker network connect kind-underlay $$node; \ + docker exec $$node ip address flush dev eth1; \ + done + +.PHONY: kind-iptables-accepct-underlay +kind-iptables-accepct-underlay: + $(call docker_network_info,kind) + $(call docker_network_info,kind-underlay) + $(call add_docker_iptables_rule,iptables,-s $(KIND_UNDERLAY_IPV4_SUBNET) -d $(KIND_IPV4_SUBNET) -j ACCEPT) + $(call add_docker_iptables_rule,iptables,-d $(KIND_UNDERLAY_IPV4_SUBNET) -s $(KIND_IPV4_SUBNET) -j ACCEPT) + $(call add_docker_iptables_rule,ip6tables,-s $(KIND_UNDERLAY_IPV6_SUBNET) -d $(KIND_IPV6_SUBNET) -j ACCEPT) + $(call add_docker_iptables_rule,ip6tables,-d $(KIND_UNDERLAY_IPV6_SUBNET) -s $(KIND_IPV6_SUBNET) -j ACCEPT) + .PHONY: kind-generate-config kind-generate-config: jinjanate yamls/kind.yaml.j2 -o yamls/kind.yaml .PHONY: kind-disable-hairpin kind-disable-hairpin: - $(call docker_config_bridge,kind,0,) + $(call docker_config_bridge,$(KIND_NETWORK_UNDERLAY),0,) .PHONY: kind-enable-hairpin kind-enable-hairpin: - $(call docker_config_bridge,kind,1,) + $(call docker_config_bridge,$(KIND_NETWORK_UNDERLAY),1,) .PHONY: kind-create kind-create: @@ -393,8 +428,10 @@ kind-init-ovn-ic-%: kind-clean-ovn-ic kind-init-cilium-chaining: kind-init-cilium-chaining-ipv4 .PHONY: kind-init-cilium-chaining-% -kind-init-cilium-chaining-%: +kind-init-cilium-chaining-%: kind-network-create-underlay @kube_proxy_mode=none $(MAKE) kind-init-$* + @$(MAKE) kind-iptables-accepct-underlay + @$(MAKE) kind-network-connect-underlay .PHONY: kind-init-ovn-submariner kind-init-ovn-submariner: kind-clean-ovn-submariner kind-init @@ -476,6 +513,7 @@ kind-install-chart: kind-load-image kind-untaint-control-plane --set networking.ENABLE_SSL=$(shell echo $${ENABLE_SSL:-false}) \ --set func.ENABLE_BIND_LOCAL_IP=$(shell echo $${ENABLE_BIND_LOCAL_IP:-true}) \ --set func.ENABLE_OVN_IPSEC=$(shell echo $${ENABLE_OVN_IPSEC:-false}) \ + --set func.ENABLE_ANP=$(shell echo $${ENABLE_ANP:-false}) \ --set func.ENABLE_IC=$(shell kubectl get node --show-labels | grep -qw "ovn.kubernetes.io/ic-gw" && echo true || echo false) .PHONY: kind-install-chart-ssl @@ -490,6 +528,7 @@ kind-upgrade-chart: kind-load-image --set networking.ENABLE_SSL=$(shell echo $${ENABLE_SSL:-false}) \ --set func.ENABLE_BIND_LOCAL_IP=$(shell echo $${ENABLE_BIND_LOCAL_IP:-true}) \ --set func.ENABLE_OVN_IPSEC=$(shell echo $${ENABLE_OVN_IPSEC:-false}) \ + --set func.ENABLE_ANP=$(shell echo $${ENABLE_ANP:-false}) \ --set func.ENABLE_IC=$(shell kubectl get node --show-labels | grep -qw "ovn.kubernetes.io/ic-gw" && echo true || echo false) kubectl -n kube-system wait pod --for=condition=ready -l app=ovs --timeout=60s @@ -648,71 +687,71 @@ kind-install-underlay-hairpin: kind-install-underlay-hairpin-ipv4 .PHONY: kind-install-underlay-ipv4 kind-install-underlay-ipv4: kind-disable-hairpin kind-load-image kind-untaint-control-plane - $(call docker_network_info,kind) - @sed -e 's@^[[:space:]]*POD_CIDR=.*@POD_CIDR="$(KIND_IPV4_SUBNET)"@' \ - -e 's@^[[:space:]]*POD_GATEWAY=.*@POD_GATEWAY="$(KIND_IPV4_GATEWAY)"@' \ - -e 's@^[[:space:]]*EXCLUDE_IPS=.*@EXCLUDE_IPS="$(KIND_IPV4_EXCLUDE_IPS)"@' \ + $(call docker_network_info,$(KIND_NETWORK_UNDERLAY)) + @sed -e 's@^[[:space:]]*POD_CIDR=.*@POD_CIDR="$($(UNDERLAY_IPV4_SUBNET))"@' \ + -e 's@^[[:space:]]*POD_GATEWAY=.*@POD_GATEWAY="$($(UNDERLAY_IPV4_GATEWAY))"@' \ + -e 's@^[[:space:]]*EXCLUDE_IPS=.*@EXCLUDE_IPS="$($(UNDERLAY_IPV4_EXCLUDE_IPS))"@' \ -e 's@^VLAN_ID=.*@VLAN_ID="0"@' \ -e 's/VERSION=.*/VERSION=$(VERSION)/' \ dist/images/install.sh | \ - ENABLE_VLAN=true VLAN_NIC=eth0 bash + ENABLE_VLAN=true VLAN_NIC=$(VLAN_NIC) bash kubectl describe no .PHONY: kind-install-underlay-hairpin-ipv4 kind-install-underlay-hairpin-ipv4: kind-enable-hairpin kind-load-image kind-untaint-control-plane - $(call docker_network_info,kind) - @sed -e 's@^[[:space:]]*POD_CIDR=.*@POD_CIDR="$(KIND_IPV4_SUBNET)"@' \ - -e 's@^[[:space:]]*POD_GATEWAY=.*@POD_GATEWAY="$(KIND_IPV4_GATEWAY)"@' \ - -e 's@^[[:space:]]*EXCLUDE_IPS=.*@EXCLUDE_IPS="$(KIND_IPV4_EXCLUDE_IPS)"@' \ + $(call docker_network_info,$(KIND_NETWORK_UNDERLAY)) + @sed -e 's@^[[:space:]]*POD_CIDR=.*@POD_CIDR="$($(UNDERLAY_IPV4_SUBNET))"@' \ + -e 's@^[[:space:]]*POD_GATEWAY=.*@POD_GATEWAY="$($(UNDERLAY_IPV4_GATEWAY))"@' \ + -e 's@^[[:space:]]*EXCLUDE_IPS=.*@EXCLUDE_IPS="$($(UNDERLAY_IPV4_EXCLUDE_IPS))"@' \ -e 's@^VLAN_ID=.*@VLAN_ID="0"@' \ -e 's/VERSION=.*/VERSION=$(VERSION)/' \ dist/images/install.sh | \ - ENABLE_VLAN=true VLAN_NIC=eth0 bash + ENABLE_VLAN=true VLAN_NIC=$(VLAN_NIC) bash kubectl describe no .PHONY: kind-install-underlay-ipv6 kind-install-underlay-ipv6: kind-disable-hairpin kind-load-image kind-untaint-control-plane - $(call docker_network_info,kind) - @sed -e 's@^[[:space:]]*POD_CIDR=.*@POD_CIDR="$(KIND_IPV6_SUBNET)"@' \ - -e 's@^[[:space:]]*POD_GATEWAY=.*@POD_GATEWAY="$(KIND_IPV6_GATEWAY)"@' \ - -e 's@^[[:space:]]*EXCLUDE_IPS=.*@EXCLUDE_IPS="$(KIND_IPV6_EXCLUDE_IPS)"@' \ + $(call docker_network_info,$(KIND_NETWORK_UNDERLAY)) + @sed -e 's@^[[:space:]]*POD_CIDR=.*@POD_CIDR="$($(UNDERLAY_IPV6_SUBNET))"@' \ + -e 's@^[[:space:]]*POD_GATEWAY=.*@POD_GATEWAY="$($(UNDERLAY_IPV6_GATEWAY))"@' \ + -e 's@^[[:space:]]*EXCLUDE_IPS=.*@EXCLUDE_IPS="$($(UNDERLAY_IPV6_EXCLUDE_IPS))"@' \ -e 's@^VLAN_ID=.*@VLAN_ID="0"@' \ -e 's/VERSION=.*/VERSION=$(VERSION)/' \ dist/images/install.sh | \ - IPV6=true ENABLE_VLAN=true VLAN_NIC=eth0 bash + IPV6=true ENABLE_VLAN=true VLAN_NIC=$(VLAN_NIC) bash .PHONY: kind-install-underlay-hairpin-ipv6 kind-install-underlay-hairpin-ipv6: kind-enable-hairpin kind-load-image kind-untaint-control-plane - $(call docker_network_info,kind) - @sed -e 's@^[[:space:]]*POD_CIDR=.*@POD_CIDR="$(KIND_IPV6_SUBNET)"@' \ - -e 's@^[[:space:]]*POD_GATEWAY=.*@POD_GATEWAY="$(KIND_IPV6_GATEWAY)"@' \ - -e 's@^[[:space:]]*EXCLUDE_IPS=.*@EXCLUDE_IPS="$(KIND_IPV6_EXCLUDE_IPS)"@' \ + $(call docker_network_info,$(KIND_NETWORK_UNDERLAY)) + @sed -e 's@^[[:space:]]*POD_CIDR=.*@POD_CIDR="$($(UNDERLAY_IPV6_SUBNET))"@' \ + -e 's@^[[:space:]]*POD_GATEWAY=.*@POD_GATEWAY="$($(UNDERLAY_IPV6_GATEWAY))"@' \ + -e 's@^[[:space:]]*EXCLUDE_IPS=.*@EXCLUDE_IPS="$($(UNDERLAY_IPV6_EXCLUDE_IPS))"@' \ -e 's@^VLAN_ID=.*@VLAN_ID="0"@' \ -e 's/VERSION=.*/VERSION=$(VERSION)/' \ dist/images/install.sh | \ - IPV6=true ENABLE_VLAN=true VLAN_NIC=eth0 bash + IPV6=true ENABLE_VLAN=true VLAN_NIC=$(VLAN_NIC) bash .PHONY: kind-install-underlay-dual kind-install-underlay-dual: kind-disable-hairpin kind-load-image kind-untaint-control-plane - $(call docker_network_info,kind) - @sed -e 's@^[[:space:]]*POD_CIDR=.*@POD_CIDR="$(KIND_IPV4_SUBNET),$(KIND_IPV6_SUBNET)"@' \ - -e 's@^[[:space:]]*POD_GATEWAY=.*@POD_GATEWAY="$(KIND_IPV4_GATEWAY),$(KIND_IPV6_GATEWAY)"@' \ - -e 's@^[[:space:]]*EXCLUDE_IPS=.*@EXCLUDE_IPS="$(KIND_IPV4_EXCLUDE_IPS),$(KIND_IPV6_EXCLUDE_IPS)"@' \ + $(call docker_network_info,$(KIND_NETWORK_UNDERLAY)) + @sed -e 's@^[[:space:]]*POD_CIDR=.*@POD_CIDR="$($(UNDERLAY_IPV4_SUBNET)),$($(UNDERLAY_IPV6_SUBNET))"@' \ + -e 's@^[[:space:]]*POD_GATEWAY=.*@POD_GATEWAY="$($(UNDERLAY_IPV4_GATEWAY)),$($(UNDERLAY_IPV6_GATEWAY))"@' \ + -e 's@^[[:space:]]*EXCLUDE_IPS=.*@EXCLUDE_IPS="$($(UNDERLAY_IPV4_EXCLUDE_IPS)),$($(UNDERLAY_IPV6_EXCLUDE_IPS))"@' \ -e 's@^VLAN_ID=.*@VLAN_ID="0"@' \ -e 's/VERSION=.*/VERSION=$(VERSION)/' \ dist/images/install.sh | \ - DUAL_STACK=true ENABLE_VLAN=true VLAN_NIC=eth0 bash + DUAL_STACK=true ENABLE_VLAN=true VLAN_NIC=$(VLAN_NIC) bash .PHONY: kind-install-underlay-hairpin-dual kind-install-underlay-hairpin-dual: kind-enable-hairpin kind-load-image kind-untaint-control-plane - $(call docker_network_info,kind) - @sed -e 's@^[[:space:]]*POD_CIDR=.*@POD_CIDR="$(KIND_IPV4_SUBNET),$(KIND_IPV6_SUBNET)"@' \ - -e 's@^[[:space:]]*POD_GATEWAY=.*@POD_GATEWAY="$(KIND_IPV4_GATEWAY),$(KIND_IPV6_GATEWAY)"@' \ - -e 's@^[[:space:]]*EXCLUDE_IPS=.*@EXCLUDE_IPS="$(KIND_IPV4_EXCLUDE_IPS),$(KIND_IPV6_EXCLUDE_IPS)"@' \ + $(call docker_network_info,$(KIND_NETWORK_UNDERLAY)) + @sed -e 's@^[[:space:]]*POD_CIDR=.*@POD_CIDR="$($(UNDERLAY_IPV4_SUBNET)),$($(UNDERLAY_IPV6_SUBNET))"@' \ + -e 's@^[[:space:]]*POD_GATEWAY=.*@POD_GATEWAY="$($(UNDERLAY_IPV4_GATEWAY)),$($(UNDERLAY_IPV6_GATEWAY))"@' \ + -e 's@^[[:space:]]*EXCLUDE_IPS=.*@EXCLUDE_IPS="$($(UNDERLAY_IPV4_EXCLUDE_IPS)),$($(UNDERLAY_IPV6_EXCLUDE_IPS))"@' \ -e 's@^VLAN_ID=.*@VLAN_ID="0"@' \ -e 's/VERSION=.*/VERSION=$(VERSION)/' \ dist/images/install.sh | \ - DUAL_STACK=true ENABLE_VLAN=true VLAN_NIC=eth0 bash + DUAL_STACK=true ENABLE_VLAN=true VLAN_NIC=$(VLAN_NIC) bash .PHONY: kind-install-underlay-u2o kind-install-underlay-u2o: kind-install-underlay-u2o-ipv4 @@ -723,15 +762,15 @@ kind-install-underlay-u2o-%: .PHONY: kind-install-underlay-logical-gateway-dual kind-install-underlay-logical-gateway-dual: kind-disable-hairpin kind-load-image kind-untaint-control-plane - $(call docker_network_info,kind) - @sed -e 's@^[[:space:]]*POD_CIDR=.*@POD_CIDR="$(KIND_IPV4_SUBNET),$(KIND_IPV6_SUBNET)"@' \ - -e 's@^[[:space:]]*POD_GATEWAY=.*@POD_GATEWAY="$(KIND_IPV4_GATEWAY)9,$(KIND_IPV6_GATEWAY)f"@' \ - -e 's@^[[:space:]]*EXCLUDE_IPS=.*@EXCLUDE_IPS="$(KIND_IPV4_GATEWAY),$(KIND_IPV4_EXCLUDE_IPS),$(KIND_IPV6_GATEWAY),$(KIND_IPV6_EXCLUDE_IPS)"@' \ + $(call docker_network_info,$(KIND_NETWORK_UNDERLAY)) + @sed -e 's@^[[:space:]]*POD_CIDR=.*@POD_CIDR="$($(UNDERLAY_IPV4_SUBNET)),$($(UNDERLAY_IPV6_SUBNET))"@' \ + -e 's@^[[:space:]]*POD_GATEWAY=.*@POD_GATEWAY="$($(UNDERLAY_IPV4_GATEWAY))9,$($(UNDERLAY_IPV6_GATEWAY))f"@' \ + -e 's@^[[:space:]]*EXCLUDE_IPS=.*@EXCLUDE_IPS="$($(UNDERLAY_IPV4_GATEWAY)),$($(UNDERLAY_IPV4_EXCLUDE_IPS)),$($(UNDERLAY_IPV6_GATEWAY)),$($(UNDERLAY_IPV6_EXCLUDE_IPS))"@' \ -e 's@^VLAN_ID=.*@VLAN_ID="0"@' \ -e 's/VERSION=.*/VERSION=$(VERSION)/' \ dist/images/install.sh | \ DUAL_STACK=true ENABLE_VLAN=true \ - VLAN_NIC=eth0 LOGICAL_GATEWAY=true bash + VLAN_NIC=$(VLAN_NIC) LOGICAL_GATEWAY=true bash .PHONY: kind-install-multus kind-install-multus: @@ -740,7 +779,7 @@ kind-install-multus: kubectl -n kube-system rollout status ds kube-multus-ds .PHONY: kind-install-metallb -kind-install-metallb: kind-install +kind-install-metallb: $(call docker_network_info,kind) $(call kind_load_image,kube-ovn,$(METALLB_CONTROLLER_IMAGE),1) $(call kind_load_image,kube-ovn,$(METALLB_SPEAKER_IMAGE),1) @@ -818,13 +857,12 @@ kind-install-cilium-chaining-%: --namespace kube-system \ --set k8sServiceHost=$(KUBERNETES_SERVICE_HOST) \ --set k8sServicePort=6443 \ - --set kubeProxyReplacement=partial \ + --set kubeProxyReplacement=false \ --set operator.replicas=1 \ --set socketLB.enabled=true \ --set nodePort.enabled=true \ --set externalIPs.enabled=true \ --set hostPort.enabled=false \ - --set routingMode=native \ --set sessionAffinity=true \ --set enableIPv4Masquerade=false \ --set enableIPv6Masquerade=false \ @@ -832,6 +870,9 @@ kind-install-cilium-chaining-%: --set sctp.enabled=true \ --set ipv4.enabled=$(shell if echo $* | grep -q ipv6; then echo false; else echo true; fi) \ --set ipv6.enabled=$(shell if echo $* | grep -q ipv4; then echo false; else echo true; fi) \ + --set routingMode=native \ + --set devices="eth+ ovn0" \ + --set forceDeviceDetection=true \ --set ipam.mode=cluster-pool \ --set-json ipam.operator.clusterPoolIPv4PodCIDRList='["100.65.0.0/16"]' \ --set-json ipam.operator.clusterPoolIPv6PodCIDRList='["fd00:100:65::/112"]' \ @@ -842,6 +883,7 @@ kind-install-cilium-chaining-%: kubectl -n kube-system rollout status ds cilium --timeout 120s @$(MAKE) ENABLE_LB=false ENABLE_NP=false \ CNI_CONFIG_PRIORITY=10 WITHOUT_KUBE_PROXY=true \ + KIND_NETWORK_UNDERLAY=kind-underlay \ kind-install-$* kubectl describe no @@ -918,6 +960,13 @@ kind-install-kwok: kind-install-ovn-ipsec: @$(MAKE) ENABLE_OVN_IPSEC=true kind-install +.PHONY: kind-install-anp +kind-install-anp: kind-load-image + $(call kind_load_image,kube-ovn,$(ANP_TEST_IMAGE),1) + kubectl apply -f "$(ANP_CR_YAML)" + kubectl apply -f "$(BANP_CR_YAML)" + @$(MAKE) ENABLE_ANP=true kind-install + .PHONY: kind-reload kind-reload: kind-reload-ovs kubectl delete pod -n kube-system -l app=kube-ovn-controller diff --git a/Makefile.e2e b/Makefile.e2e index fb1568e76d4..03e9f4ef20a 100644 --- a/Makefile.e2e +++ b/Makefile.e2e @@ -229,3 +229,8 @@ kube-ovn-ipsec-e2e: E2E_NETWORK_MODE=$(E2E_NETWORK_MODE) \ ginkgo $(GINKGO_OUTPUT_OPT) $(GINKGO_PARALLEL_OPT) --randomize-all -v \ --focus=CNI:Kube-OVN ./test/e2e/ipsec/ipsec.test -- $(TEST_BIN_ARGS) + +.PHONY: kube-ovn-anp-e2e +kube-ovn-anp-e2e: + KUBECONFIG=$(KUBECONFIG) ./test/anp/conformance.sh + diff --git a/charts/kube-ovn/templates/controller-deploy.yaml b/charts/kube-ovn/templates/controller-deploy.yaml index eaa4c3dc5a0..cd8e1b3b717 100644 --- a/charts/kube-ovn/templates/controller-deploy.yaml +++ b/charts/kube-ovn/templates/controller-deploy.yaml @@ -136,6 +136,7 @@ spec: - --node-local-dns-ip={{- .Values.networking.NODE_LOCAL_DNS_IP }} - --secure-serving={{- .Values.func.SECURE_SERVING }} - --enable-ovn-ipsec={{- .Values.func.ENABLE_OVN_IPSEC }} + - --enable-anp={{- .Values.func.ENABLE_ANP }} securityContext: runAsUser: {{ include "kubeovn.runAsUser" . }} privileged: false diff --git a/charts/kube-ovn/values.yaml b/charts/kube-ovn/values.yaml index 1df4bdb9e59..1a52064db16 100644 --- a/charts/kube-ovn/values.yaml +++ b/charts/kube-ovn/values.yaml @@ -74,6 +74,7 @@ func: ENABLE_IC: false ENABLE_NAT_GW: true ENABLE_OVN_IPSEC: false + ENABLE_ANP: false ipv4: POD_CIDR: "10.16.0.0/16" diff --git a/dist/images/Dockerfile.base b/dist/images/Dockerfile.base index 1d16873551d..9a159faa0a8 100644 --- a/dist/images/Dockerfile.base +++ b/dist/images/Dockerfile.base @@ -137,6 +137,10 @@ RUN curl -sSf -L --retry 3 -o /usr/local/bin/bfdd-control https://github.com/bob chmod +x /usr/local/bin/bfdd-control /usr/local/bin/bfdd-beacon && \ setcap CAP_NET_BIND_SERVICE+eip $(readlink -f $(which bfdd-beacon)) +ARG GOBGP_VERSION="3.29.0" +RUN curl -sSf -L --retry 5 https://github.com/osrg/gobgp/releases/download/v${GOBGP_VERSION}/gobgp_${GOBGP_VERSION}_linux_${ARCH}.tar.gz | tar -xz -C /usr/bin gobgp && \ + chmod +x /usr/bin/gobgp + ARG DEBUG=false RUN --mount=type=bind,target=/packages,from=ovs-builder,source=/packages \ diff --git a/dist/images/install.sh b/dist/images/install.sh index 47922900806..051a5c69f08 100755 --- a/dist/images/install.sh +++ b/dist/images/install.sh @@ -40,6 +40,7 @@ OVS_VSCTL_CONCURRENCY=${OVS_VSCTL_CONCURRENCY:-100} ENABLE_COMPACT=${ENABLE_COMPACT:-false} SECURE_SERVING=${SECURE_SERVING:-false} ENABLE_OVN_IPSEC=${ENABLE_OVN_IPSEC:-false} +ENABLE_ANP=${ENABLE_ANP:-false} # debug DEBUG_WRAPPER=${DEBUG_WRAPPER:-} @@ -2255,6 +2256,10 @@ spec: type: string u2oInterconnectionMAC: type: string + mcastQuerierIP: + type: string + mcastQuerierMAC: + type: string u2oInterconnectionVPC: type: string v4usingIPrange: @@ -4295,6 +4300,7 @@ spec: - --node-local-dns-ip=$NODE_LOCAL_DNS_IP - --enable-ovn-ipsec=$ENABLE_OVN_IPSEC - --secure-serving=${SECURE_SERVING} + - --enable-anp=$ENABLE_ANP securityContext: runAsUser: ${RUN_AS_USER} privileged: false @@ -5152,6 +5158,7 @@ while true; do sleep 1 done kubectl rollout status daemonset/kube-ovn-pinger -n kube-system --timeout 120s +sleep 1 kubectl wait pod --for=condition=Ready -l app=kube-ovn-pinger -n kube-system --timeout 120s echo "-------------------------------" echo "" diff --git a/dist/images/kubectl-ko b/dist/images/kubectl-ko index e7182a5aae2..8e8e5a1e517 100755 --- a/dist/images/kubectl-ko +++ b/dist/images/kubectl-ko @@ -160,23 +160,28 @@ tcpdump(){ exit 1 fi - ovnCni=$(kubectl get pod -n $KUBE_OVN_NS -l app=kube-ovn-cni -o 'jsonpath={.items[?(@.spec.nodeName=="'$nodeName'")].metadata.name}') - if [ -z "$ovnCni" ]; then - echo "kube-ovn-cni not exist on node $nodeName" + ovsPod=$(kubectl get pod -n $KUBE_OVN_NS -l app=ovs -o 'jsonpath={.items[?(@.spec.nodeName=="'$nodeName'")].metadata.name}') + if [ -z "$ovsPod" ]; then + echo "ovs-ovn not exist on node $nodeName" exit 1 fi if [ "$hostNetwork" = "true" ]; then set -x - kubectl exec "$ovnCni" -n $KUBE_OVN_NS -- tcpdump -nn "$@" + kubectl exec "$ovsPod" -n $KUBE_OVN_NS -- tcpdump -nn "$@" else - nicName=$(kubectl exec "$ovnCni" -n $KUBE_OVN_NS -- ovs-vsctl --data=bare --no-heading --columns=name find interface external-ids:iface-id="$podName"."$namespace" | tr -d '\r') + nicName=$(kubectl exec "$ovsPod" -n $KUBE_OVN_NS -- ovs-vsctl --data=bare --no-heading --columns=name find interface external-ids:iface-id="$podName"."$namespace" | tr -d '\r') if [ -z "$nicName" ]; then echo "nic doesn't exist on node $nodeName" exit 1 fi podNicType=$(kubectl get pod "$podName" -n "$namespace" -o jsonpath={.metadata.annotations.ovn\\.kubernetes\\.io/pod_nic_type}) - podNetNs=$(kubectl exec "$ovnCni" -n $KUBE_OVN_NS -- ovs-vsctl --data=bare --no-heading get interface "$nicName" external-ids:pod_netns | tr -d '\r' | sed -e 's/^"//' -e 's/"$//') + podNetNs=$(kubectl exec "$ovsPod" -n $KUBE_OVN_NS -- ovs-vsctl --data=bare --no-heading get interface "$nicName" external-ids:pod_netns | tr -d '\r' | sed -e 's/^"//' -e 's/"$//') + ovnCni=$(kubectl get pod -n $KUBE_OVN_NS -l app=kube-ovn-cni -o 'jsonpath={.items[?(@.spec.nodeName=="'$nodeName'")].metadata.name}') + if [ -z "$ovnCni" ]; then + echo "kube-ovn-cni not exist on node $nodeName" + exit 1 + fi set -x if [ "$podNicType" = "internal-port" ]; then kubectl exec "$ovnCni" -n $KUBE_OVN_NS -- nsenter --net="$podNetNs" tcpdump -nn -i "$nicName" "$@" @@ -277,9 +282,9 @@ trace(){ exit 1 fi - local ovnCni=$(kubectl get pod -n $KUBE_OVN_NS -l app=kube-ovn-cni -o 'jsonpath={.items[?(@.spec.nodeName=="'$node'")].metadata.name}') - if [ -z "$ovnCni" ]; then - echo "Error: no kube-ovn-cni Pod running on node $nodeName" + local ovsPod=$(kubectl get pod -n $KUBE_OVN_NS -l app=ovs -o 'jsonpath={.items[?(@.spec.nodeName=="'$node'")].metadata.name}') + if [ -z "$ovsPod" ]; then + echo "Error: no ovs-ovn Pod running on node $nodeName" exit 1 fi @@ -313,6 +318,12 @@ trace(){ exit 1 fi + ovnCni=$(kubectl get pod -n $KUBE_OVN_NS -l app=kube-ovn-cni -o 'jsonpath={.items[?(@.spec.nodeName=="'$node'")].metadata.name}') + if [ -z "$ovnCni" ]; then + echo "kube-ovn-cni not exist on node $node" + exit 1 + fi + local vlan=$(kubectl get subnet "$ls" -o jsonpath={.spec.vlan}) local logicalGateway=$(kubectl get subnet "$ls" -o jsonpath={.spec.logicalGateway}) local u2oIC=$(kubectl get subnet "$ls" -o jsonpath={.spec.u2oInterconnection}) @@ -326,21 +337,21 @@ trace(){ fi fi - local nicName=$(kubectl exec "$ovnCni" -c cni-server -n $KUBE_OVN_NS -- ovs-vsctl --data=bare --no-heading --columns=name find interface external-ids:iface-id="$lsp" | tr -d '\r') + local nicName=$(kubectl exec "$ovsPod" -c openvswitch -n $KUBE_OVN_NS -- ovs-vsctl --data=bare --no-heading --columns=name find interface external-ids:iface-id="$lsp" | tr -d '\r') if [ -z "$nicName" ]; then echo "Error: failed to find ovs interface for LSP $lsp" exit 1 fi local podNicType=$(kubectl get "$typedName" $optNamespace -o jsonpath={.metadata.annotations.ovn\\.kubernetes\\.io/pod_nic_type}) - local podNetNs=$(kubectl exec "$ovnCni" -c cni-server -n $KUBE_OVN_NS -- ovs-vsctl --data=bare --no-heading get interface "$nicName" external-ids:pod_netns | tr -d '\r' | sed -e 's/^"//' -e 's/"$//') + local podNetNs=$(kubectl exec "$ovsPod" -c openvswitch -n $KUBE_OVN_NS -- ovs-vsctl --data=bare --no-heading get interface "$nicName" external-ids:pod_netns | tr -d '\r' | sed -e 's/^"//' -e 's/"$//') local nicName= nsenterCmd= if [ ! -z $podNetNs ]; then nsenterCmd="nsenter --net='$podNetNs'" fi if [ "$podNicType" != "internal-port" ]; then - local interface=$(kubectl exec "$ovnCni" -c cni-server -n $KUBE_OVN_NS -- ovs-vsctl --format=csv --data=bare --no-heading --columns=name find interface external_id:iface-id="$lsp") - local peer=$(kubectl exec "$ovnCni" -c cni-server -n $KUBE_OVN_NS -- ip link show $interface | grep -oE "^[0-9]+:\\s$interface@if[0-9]+" | awk -F @ '{print $2}') + local interface=$(kubectl exec "$ovsPod" -c openvswitch -n $KUBE_OVN_NS -- ovs-vsctl --format=csv --data=bare --no-heading --columns=name find interface external_id:iface-id="$lsp") + local peer=$(kubectl exec "$ovsPod" -c openvswitch -n $KUBE_OVN_NS -- ip link show $interface | grep -oE "^[0-9]+:\\s$interface@if[0-9]+" | awk -F @ '{print $2}') local peerIndex=${peer//if/} local peer=$(kubectl exec "$ovnCni" -c cni-server -n $KUBE_OVN_NS -- sh -c "$nsenterCmd ip link show type veth" | grep "^$peerIndex:" | awk -F @ '{print $1}') nicName=$(echo $peer | awk '{print $2}') @@ -453,25 +464,25 @@ trace(){ echo "" echo "" - local inPort=$(kubectl exec "$ovnCni" -c cni-server -n $KUBE_OVN_NS -- ovs-vsctl --format=csv --data=bare --no-heading --columns=ofport find interface external_id:iface-id="$lsp") + local inPort=$(kubectl exec "$ovsPod" -c openvswitch -n $KUBE_OVN_NS -- ovs-vsctl --format=csv --data=bare --no-heading --columns=ofport find interface external_id:iface-id="$lsp") case $type in icmp) set -x - kubectl exec "$ovnCni" -c cni-server -n $KUBE_OVN_NS -- ovs-appctl ofproto/trace br-int "in_port=$inPort,icmp$proto,nw_ttl=64,${nw}_src=$srcIP,${nw}_dst=$dst,dl_src=$mac,dl_dst=$dstMac" + kubectl exec "$ovsPod" -c openvswitch -n $KUBE_OVN_NS -- ovs-appctl ofproto/trace br-int "in_port=$inPort,icmp$proto,nw_ttl=64,${nw}_src=$srcIP,${nw}_dst=$dst,dl_src=$mac,dl_dst=$dstMac" ;; tcp|udp) set -x - kubectl exec "$ovnCni" -c cni-server -n $KUBE_OVN_NS -- ovs-appctl ofproto/trace br-int "in_port=$inPort,$type$proto,nw_ttl=64,${nw}_src=$srcIP,${nw}_dst=$dst,dl_src=$mac,dl_dst=$dstMac,${type}_src=1000,${type}_dst=$4" + kubectl exec "$ovsPod" -c openvswitch -n $KUBE_OVN_NS -- ovs-appctl ofproto/trace br-int "in_port=$inPort,$type$proto,nw_ttl=64,${nw}_src=$srcIP,${nw}_dst=$dst,dl_src=$mac,dl_dst=$dstMac,${type}_src=1000,${type}_dst=$4" ;; arp) case "$4" in ""|request) set -x - kubectl exec "$ovnCni" -c cni-server -n $KUBE_OVN_NS -- ovs-appctl ofproto/trace br-int "in_port=$inPort,arp,arp_op=1,dl_src=$mac,dl_dst=$dstMac,arp_spa=$srcIP,arp_tpa=$dst,arp_sha=$mac,arp_tha=00:00:00:00:00:00" + kubectl exec "$ovsPod" -c openvswitch -n $KUBE_OVN_NS -- ovs-appctl ofproto/trace br-int "in_port=$inPort,arp,arp_op=1,dl_src=$mac,dl_dst=$dstMac,arp_spa=$srcIP,arp_tpa=$dst,arp_sha=$mac,arp_tha=00:00:00:00:00:00" ;; reply) set -x - kubectl exec "$ovnCni" -c cni-server -n $KUBE_OVN_NS -- ovs-appctl ofproto/trace br-int "in_port=$inPort,arp,arp_op=2,dl_src=$mac,dl_dst=$dstMac,arp_spa=$srcIP,arp_tpa=$dst,arp_sha=$mac,arp_tha=$dstMac" + kubectl exec "$ovsPod" -c openvswitch -n $KUBE_OVN_NS -- ovs-appctl ofproto/trace br-int "in_port=$inPort,arp,arp_op=2,dl_src=$mac,dl_dst=$dstMac,arp_spa=$srcIP,arp_tpa=$dst,arp_sha=$mac,arp_tha=$dstMac" ;; esac ;; diff --git a/dist/images/vpcnatgateway/lb-svc.sh b/dist/images/vpcnatgateway/lb-svc.sh index dc3abb37080..c19c102d625 100644 --- a/dist/images/vpcnatgateway/lb-svc.sh +++ b/dist/images/vpcnatgateway/lb-svc.sh @@ -38,7 +38,7 @@ function add_eip() { exec_cmd "ip route replace $eip_network/$eip_prefix dev net1 table $ROUTE_TABLE" exec_cmd "ip route replace default via $gateway dev net1 table $ROUTE_TABLE" ip link set dev net1 arp on - exec_cmd "arping -c 3 -s $eip_without_prefix $gateway" + exec_cmd "arping -f -c 3 -s $eip_without_prefix $gateway" done } diff --git a/go.mod b/go.mod index 90c89106413..1ed39849b62 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/kubeovn/kube-ovn -go 1.22.6 +go 1.22.7 require ( github.com/Microsoft/go-winio v0.6.2 @@ -11,7 +11,7 @@ require ( github.com/containerd/containerd v1.7.21 github.com/containernetworking/cni v1.2.3 github.com/containernetworking/plugins v1.5.1 - github.com/docker/docker v27.2.0+incompatible + github.com/docker/docker v27.2.1+incompatible github.com/emicklei/go-restful/v3 v3.12.1 github.com/evanphx/json-patch/v5 v5.9.0 github.com/go-logr/stdr v1.2.2 @@ -25,12 +25,12 @@ require ( github.com/mdlayher/arp v0.0.0-20220512170110-6706a2966875 github.com/moby/sys/mountinfo v0.7.2 github.com/onsi/ginkgo/v2 v2.20.2 - github.com/onsi/gomega v1.34.1 + github.com/onsi/gomega v1.34.2 github.com/osrg/gobgp/v3 v3.29.0 github.com/ovn-org/libovsdb v0.7.0 github.com/parnurzeal/gorequest v0.3.0 github.com/prometheus-community/pro-bing v0.4.1 - github.com/prometheus/client_golang v1.20.2 + github.com/prometheus/client_golang v1.20.3 github.com/puzpuzpuz/xsync/v3 v3.4.0 github.com/scylladb/go-set v1.0.2 github.com/sirupsen/logrus v1.9.3 @@ -38,15 +38,15 @@ require ( github.com/stretchr/testify v1.9.0 github.com/vishvananda/netlink v1.3.0 go.uber.org/mock v0.4.0 - golang.org/x/mod v0.20.0 - golang.org/x/sys v0.24.0 + golang.org/x/mod v0.21.0 + golang.org/x/sys v0.25.0 golang.org/x/time v0.6.0 google.golang.org/grpc v1.66.0 google.golang.org/protobuf v1.34.2 gopkg.in/k8snetworkplumbingwg/multus-cni.v4 v4.1.0 k8s.io/api v0.31.0 k8s.io/apimachinery v0.31.0 - k8s.io/client-go v12.0.0+incompatible + k8s.io/client-go v1.5.2 k8s.io/klog/v2 v2.130.1 k8s.io/kubectl v0.31.0 k8s.io/kubernetes v1.31.0 @@ -129,7 +129,7 @@ require ( github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.16 // indirect @@ -170,7 +170,7 @@ require ( github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect - github.com/opencontainers/runc v1.1.13 // indirect + github.com/opencontainers/runc v1.1.14 // indirect github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/opencontainers/selinux v1.11.0 // indirect github.com/openshift/api v0.0.0-20231207204216-5efc6fca4b2d // indirect @@ -208,32 +208,32 @@ require ( go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect go.etcd.io/etcd/client/v3 v3.5.15 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful v0.53.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/sdk v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful v0.54.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect + go.opentelemetry.io/otel v1.29.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 // indirect + go.opentelemetry.io/otel/metric v1.29.0 // indirect + go.opentelemetry.io/otel/sdk v1.29.0 // indirect + go.opentelemetry.io/otel/trace v1.29.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.starlark.net v0.0.0-20231121155337-90ade8b19d09 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.26.0 // indirect - golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/oauth2 v0.22.0 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/term v0.23.0 // indirect - golang.org/x/text v0.17.0 // indirect + golang.org/x/term v0.24.0 // indirect + golang.org/x/text v0.18.0 // indirect golang.org/x/tools v0.24.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 4a8a7b28e61..7ab24632c6a 100644 --- a/go.sum +++ b/go.sum @@ -106,8 +106,8 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WA github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v27.2.0+incompatible h1:Rk9nIVdfH3+Vz4cyI/uhbINhEZ/oLmc+CBXmH6fbNk4= -github.com/docker/docker v27.2.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.2.1+incompatible h1:fQdiLfW7VLscyoeYEBz7/J8soYFDZV1u6VW6gJEjNMI= +github.com/docker/docker v27.2.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -281,8 +281,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92Bcuy github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0 h1:CWyXh/jylQWp2dtiV33mY4iSSp6yf4lmn+c7/tN+ObI= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0/go.mod h1:nCLIt0w3Ept2NwF8ThLmrppXsfT07oC8k0XNDxd8sVU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -464,14 +464,15 @@ github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3ev github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= -github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= +github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= +github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= -github.com/opencontainers/runc v1.1.13 h1:98S2srgG9vw0zWcDpFMn5TRrh8kLxa/5OFUstuUhmRs= -github.com/opencontainers/runc v1.1.13/go.mod h1:R016aXacfp/gwQBYw2FDGa9m+n6atbLWrYY8hNMT/sA= +github.com/opencontainers/runc v1.1.14 h1:rgSuzbmgz5DUJjeSnw337TxDbRuqjs6iqQck/2weR6w= +github.com/opencontainers/runc v1.1.14/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1LjPNeMTfRGvOA= github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= @@ -509,8 +510,8 @@ github.com/prometheus-community/pro-bing v0.4.1 h1:aMaJwyifHZO0y+h8+icUz0xbToHbi github.com/prometheus-community/pro-bing v0.4.1/go.mod h1:aLsw+zqCaDoa2RLVVSX3+UiCkBBXTMtZC3c7EkfWnAE= github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.76.0 h1:tRwEFYFg+To2TGnibGl8dHBCh8Z/BVNKnXj2O5Za/2M= github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.76.0/go.mod h1:Rd8YnCqz+2FYsiGmE2DMlaLjQRB4v2jFNnzCt9YY4IM= -github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg= -github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4= +github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= @@ -617,28 +618,28 @@ go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful v0.53.0 h1:wwtQnRJbaVShQGjKomYYjvNoAvgXftwMIPxfY0LwWKY= -go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful v0.53.0/go.mod h1:OgGTh4n1VkuEmwUC+4jkHDakfhhDYUgH1RlAROSHx9Q= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= -go.opentelemetry.io/contrib/propagators/b3 v1.28.0 h1:XR6CFQrQ/ttAYmTBX2loUEFGdk1h17pxYI8828dk/1Y= -go.opentelemetry.io/contrib/propagators/b3 v1.28.0/go.mod h1:DWRkzJONLquRz7OJPh2rRbZ7MugQj62rk7g6HRnEqh0= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 h1:j9+03ymgYhPKmeXGk5Zu+cIZOlVzd9Zv7QIiyItjFBU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0/go.mod h1:Y5+XiUG4Emn1hTfciPzGPJaSI+RpDts6BnCIir0SLqk= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful v0.54.0 h1:PwK3qu85W2/OZsZ+7KVSSKj6fAy9Ewf0E2N34UZNUjU= +go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful v0.54.0/go.mod h1:fgH0JNwCMNwGsQOz4nlf6j5OhJwpE/Bv1hpQM6sjYOU= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/contrib/propagators/b3 v1.29.0 h1:hNjyoRsAACnhoOLWupItUjABzeYmX3GTTZLzwJluJlk= +go.opentelemetry.io/contrib/propagators/b3 v1.29.0/go.mod h1:E76MTitU1Niwo5NSN+mVxkyLu4h4h7Dp/yh38F2WuIU= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 h1:JAv0Jwtl01UFiyWZEMiJZBiTlv5A50zNs8lsthXqIio= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0/go.mod h1:QNKLmUEAq2QUbPQUfvw4fmv0bgbK7UlOSFCnXyfvSNc= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= +go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= +go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.starlark.net v0.0.0-20231121155337-90ade8b19d09 h1:hzy3LFnSN8kuQK8h9tHl4ndF6UruMj47OqwqsS+/Ai4= @@ -672,12 +673,13 @@ golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= -golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA= -golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= +golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk= +golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -698,8 +700,9 @@ golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -743,13 +746,14 @@ golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= -golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -818,8 +822,8 @@ golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -843,8 +847,9 @@ golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -861,8 +866,9 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= @@ -912,10 +918,10 @@ google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 h1:CT2Thj5AuPV9phrYMtzX11k+XkzMGfRAet42PmoTATM= google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988/go.mod h1:7uvplUBj4RjHAxIZ//98LzOvrQ04JBkaixRmCMI29hc= -google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988 h1:+/tmTy5zAieooKIXfzDm9KiA3Bv6JBwriRN9LY+yayk= -google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988/go.mod h1:4+X6GvPs+25wZKbQq9qyAXrwIRExv7w0Ea6MgZLZiDM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 h1:V71AcdLZr2p8dC9dbOIMCpqi4EmRl8wUwnJzXXLmbmc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= diff --git a/hack/update-codegen-docker.sh b/hack/update-codegen-docker.sh index 8e97f09e3eb..ea2aafd8b3d 100755 --- a/hack/update-codegen-docker.sh +++ b/hack/update-codegen-docker.sh @@ -7,7 +7,7 @@ GOPROXY=${GOPROXY:-"https://goproxy.cn"} docker run -it --rm \ -v ${PWD}:/app \ -e GOPROXY=${GOPROXY} \ - ghcr.io/zhangzujian/kube-code-generator:v0.2.3 \ + ghcr.io/zhangzujian/kube-code-generator:v0.3.1 \ --boilerplate-path ./hack/boilerplate.go.txt \ --apis-in ./pkg/apis \ --go-gen-out ./pkg/client diff --git a/pkg/apis/kubeovn/v1/types.go b/pkg/apis/kubeovn/v1/types.go index cda348c1b35..e53c4e8c579 100644 --- a/pkg/apis/kubeovn/v1/types.go +++ b/pkg/apis/kubeovn/v1/types.go @@ -245,6 +245,8 @@ type SubnetStatus struct { U2OInterconnectionMAC string `json:"u2oInterconnectionMAC"` U2OInterconnectionVPC string `json:"u2oInterconnectionVPC"` NatOutgoingPolicyRules []NatOutgoingPolicyRuleStatus `json:"natOutgoingPolicyRules"` + McastQuerierIP string `json:"mcastQuerierIP"` + McastQuerierMAC string `json:"mcastQuerierMAC"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/controller/admin_network_policy.go b/pkg/controller/admin_network_policy.go index 1447a0ec10c..b5bcd3282d1 100644 --- a/pkg/controller/admin_network_policy.go +++ b/pkg/controller/admin_network_policy.go @@ -945,7 +945,7 @@ func getAnpAddressSetName(pgName, ruleName string, index int, isIngress bool) (s func convertAction(anpRuleAction v1alpha1.AdminNetworkPolicyRuleAction, banpRuleAction v1alpha1.BaselineAdminNetworkPolicyRuleAction) (aclAction ovnnb.ACLAction) { switch anpRuleAction { case v1alpha1.AdminNetworkPolicyRuleActionAllow: - aclAction = ovnnb.ACLActionAllow + aclAction = ovnnb.ACLActionAllowRelated case v1alpha1.AdminNetworkPolicyRuleActionDeny: aclAction = ovnnb.ACLActionDrop case v1alpha1.AdminNetworkPolicyRuleActionPass: @@ -954,7 +954,7 @@ func convertAction(anpRuleAction v1alpha1.AdminNetworkPolicyRuleAction, banpRule switch banpRuleAction { case v1alpha1.BaselineAdminNetworkPolicyRuleActionAllow: - aclAction = ovnnb.ACLActionAllow + aclAction = ovnnb.ACLActionAllowRelated case v1alpha1.BaselineAdminNetworkPolicyRuleActionDeny: aclAction = ovnnb.ACLActionDrop } diff --git a/pkg/controller/ip.go b/pkg/controller/ip.go index 46638347bf2..75e8894aecd 100644 --- a/pkg/controller/ip.go +++ b/pkg/controller/ip.go @@ -389,6 +389,9 @@ func (c *Controller) createOrUpdateIPCR(ipCRName, podName, ip, mac, subnetName, case strings.HasPrefix(podName, util.U2OInterconnName[0:19]): key = podName // interconn IP name ipName = podName + case strings.HasPrefix(podName, util.McastQuerierName[0:13]): + key = podName // mcast querier IP name + ipName = podName } } diff --git a/pkg/controller/subnet.go b/pkg/controller/subnet.go index 0a8cd2fd4ee..47eefb25dca 100644 --- a/pkg/controller/subnet.go +++ b/pkg/controller/subnet.go @@ -683,14 +683,11 @@ func (c *Controller) handleAddOrUpdateSubnet(key string) error { klog.Errorf("failed to get subnet's vpc '%s', %v", subnet.Spec.Vpc, err) return err } - - if subnet.Spec.Vlan != "" && !subnet.Spec.LogicalGateway { - if err := c.reconcileU2OInterconnectionIP(subnet); err != nil { - klog.Errorf("failed to reconcile underlay subnet %s to overlay interconnection %v", subnet.Name, err) - return err - } + _, isMcastQuerierChanged, err := c.reconcileSubnetSpecialIPs(subnet) + if err != nil { + klog.Errorf("failed to reconcile subnet %s Custom IPs %v", subnet.Name, err) + return err } - if err := c.checkSubnetConflict(subnet); err != nil { klog.Errorf("failed to check subnet %s, %v", subnet.Name, err) return err @@ -721,15 +718,9 @@ func (c *Controller) handleAddOrUpdateSubnet(key string) error { return err } - multicastSnoopFlag := map[string]string{"mcast_snoop": "true", "mcast_querier": "false"} - if subnet.Spec.EnableMulticastSnoop { - if err := c.OVNNbClient.LogicalSwitchUpdateOtherConfig(subnet.Name, ovsdb.MutateOperationInsert, multicastSnoopFlag); err != nil { - klog.Errorf("enable logical switch multicast snoop %s: %v", subnet.Name, err) - return err - } - } else { - if err := c.OVNNbClient.LogicalSwitchUpdateOtherConfig(subnet.Name, ovsdb.MutateOperationDelete, multicastSnoopFlag); err != nil { - klog.Errorf("disable logical switch multicast snoop %s: %v", subnet.Name, err) + if isMcastQuerierChanged { + if err := c.handleMcastQuerierChange(subnet); err != nil { + klog.Errorf("failed to handle mcast querier IP change for subnet %s: %v", subnet.Name, err) return err } } @@ -1815,85 +1806,186 @@ func (c *Controller) reconcileVlan(subnet *kubeovnv1.Subnet) error { return nil } -func (c *Controller) reconcileU2OInterconnectionIP(subnet *kubeovnv1.Subnet) error { - needCalcIP := false - if subnet.Spec.U2OInterconnection { +func (c *Controller) reconcileSubnetSpecialIPs(subnet *kubeovnv1.Subnet) (bool, bool, error) { + isU2OIPChanged := false + isMcastQuerierIPChanged := false + var err error + + // reconcile u2o IP + if subnet.Spec.Vlan != "" && !subnet.Spec.LogicalGateway { u2oInterconnName := fmt.Sprintf(util.U2OInterconnName, subnet.Spec.Vpc, subnet.Name) u2oInterconnLrpName := fmt.Sprintf("%s-%s", subnet.Spec.Vpc, subnet.Name) - var v4ip, v6ip, mac string - var err error - if subnet.Spec.U2OInterconnectionIP == "" && (subnet.Status.U2OInterconnectionIP == "" || subnet.Status.U2OInterconnectionMAC == "") { - v4ip, v6ip, mac, err = c.acquireIPAddress(subnet.Name, u2oInterconnName, u2oInterconnLrpName) + var v4ip, v6ip string + if subnet.Spec.U2OInterconnection { + v4ip, v6ip, _, err = c.acquireU2OIP(subnet, u2oInterconnName, u2oInterconnLrpName) if err != nil { - klog.Errorf("failed to acquire underlay to overlay interconnection ip address for subnet %s, %v", subnet.Name, err) - return err - } - } else if subnet.Spec.U2OInterconnectionIP != "" && subnet.Status.U2OInterconnectionIP != subnet.Spec.U2OInterconnectionIP { - if subnet.Status.U2OInterconnectionIP != "" { - klog.Infof("release underlay to overlay interconnection ip address %s for subnet %s", subnet.Status.U2OInterconnectionIP, subnet.Name) - c.ipam.ReleaseAddressByPod(u2oInterconnName, subnet.Name) + return isU2OIPChanged, isMcastQuerierIPChanged, err } - v4ip, v6ip, mac, err = c.acquireStaticIPAddress(subnet.Name, u2oInterconnName, u2oInterconnLrpName, subnet.Spec.U2OInterconnectionIP) + if v4ip != "" || v6ip != "" { + isU2OIPChanged = true + } + } else if subnet.Status.U2OInterconnectionIP != "" { + err = c.releaseU2OIP(subnet, u2oInterconnName) if err != nil { - klog.Errorf("failed to acquire static underlay to overlay interconnection ip address for subnet %s, %v", subnet.Name, err) - return err + return isU2OIPChanged, isMcastQuerierIPChanged, err } + isU2OIPChanged = true } - if v4ip != "" || v6ip != "" { - switch subnet.Spec.Protocol { - case kubeovnv1.ProtocolIPv4: - subnet.Status.U2OInterconnectionIP = v4ip - case kubeovnv1.ProtocolIPv6: - subnet.Status.U2OInterconnectionIP = v6ip - case kubeovnv1.ProtocolDual: - subnet.Status.U2OInterconnectionIP = fmt.Sprintf("%s,%s", v4ip, v6ip) - } - if err := c.createOrUpdateIPCR("", u2oInterconnName, subnet.Status.U2OInterconnectionIP, mac, subnet.Name, "default", "", ""); err != nil { - klog.Errorf("failed to create or update IPs of %s : %v", u2oInterconnLrpName, err) - return err - } - - subnet.Status.U2OInterconnectionMAC = mac - needCalcIP = true + if isU2OIPChanged { + klog.Infof("reconcile underlay subnet %s to overlay interconnection with U2OInterconnection %v U2OInterconnectionIP %s", + subnet.Name, subnet.Spec.U2OInterconnection, subnet.Status.U2OInterconnectionIP) } - } else if subnet.Status.U2OInterconnectionIP != "" { - u2oInterconnName := fmt.Sprintf(util.U2OInterconnName, subnet.Spec.Vpc, subnet.Name) - klog.Infof("release underlay to overlay interconnection ip address %s for subnet %s", subnet.Status.U2OInterconnectionIP, subnet.Name) - c.ipam.ReleaseAddressByPod(u2oInterconnName, subnet.Name) - subnet.Status.U2OInterconnectionIP = "" - subnet.Status.U2OInterconnectionMAC = "" - subnet.Status.U2OInterconnectionVPC = "" + } - if err := c.config.KubeOvnClient.KubeovnV1().IPs().Delete(context.Background(), u2oInterconnName, metav1.DeleteOptions{}); err != nil { - if !k8serrors.IsNotFound(err) { - klog.Errorf("failed to delete ip %s, %v", u2oInterconnName, err) - return err - } + // reconcile mcast querier IP + if subnet.Spec.EnableMulticastSnoop { + isMcastQuerierIPChanged, err = c.acquireMcastQuerierIP(subnet) + if err != nil { + return isU2OIPChanged, isMcastQuerierIPChanged, err + } + } else { + isMcastQuerierIPChanged, err = c.releaseMcastQuerierIP(subnet) + if err != nil { + return isU2OIPChanged, isMcastQuerierIPChanged, err } - - needCalcIP = true } - if needCalcIP { - klog.Infof("reconcile underlay subnet %s to overlay interconnection with U2OInterconnection %v U2OInterconnectionIP %s", - subnet.Name, subnet.Spec.U2OInterconnection, subnet.Status.U2OInterconnectionIP) + // caculate subnet status + if isU2OIPChanged || isMcastQuerierIPChanged { if subnet.Spec.Protocol == kubeovnv1.ProtocolDual { if _, err := c.calcDualSubnetStatusIP(subnet); err != nil { klog.Error(err) - return err + return isU2OIPChanged, isMcastQuerierIPChanged, err } } else { if _, err := c.calcSubnetStatusIP(subnet); err != nil { klog.Error(err) - return err + return isU2OIPChanged, isMcastQuerierIPChanged, err } } } + + return isU2OIPChanged, isMcastQuerierIPChanged, nil +} + +func (c *Controller) acquireU2OIP(subnet *kubeovnv1.Subnet, u2oInterconnName, u2oInterconnLrpName string) (string, string, string, error) { + var v4ip, v6ip, mac string + var err error + if subnet.Spec.U2OInterconnectionIP == "" && (subnet.Status.U2OInterconnectionIP == "" || subnet.Status.U2OInterconnectionMAC == "") { + v4ip, v6ip, mac, err = c.acquireIPAddress(subnet.Name, u2oInterconnName, u2oInterconnLrpName) + if err != nil { + klog.Errorf("failed to acquire underlay to overlay interconnection ip address for subnet %s, %v", subnet.Name, err) + return "", "", "", err + } + } else if subnet.Spec.U2OInterconnectionIP != "" && subnet.Status.U2OInterconnectionIP != subnet.Spec.U2OInterconnectionIP { + if subnet.Status.U2OInterconnectionIP != "" { + klog.Infof("release underlay to overlay interconnection ip address %s for subnet %s", subnet.Status.U2OInterconnectionIP, subnet.Name) + c.ipam.ReleaseAddressByPod(u2oInterconnName, subnet.Name) + } + v4ip, v6ip, mac, err = c.acquireStaticIPAddress(subnet.Name, u2oInterconnName, u2oInterconnLrpName, subnet.Spec.U2OInterconnectionIP) + if err != nil { + klog.Errorf("failed to acquire static underlay to overlay interconnection ip address for subnet %s, %v", subnet.Name, err) + return "", "", "", err + } + } + if v4ip != "" || v6ip != "" { + switch subnet.Spec.Protocol { + case kubeovnv1.ProtocolIPv4: + subnet.Status.U2OInterconnectionIP = v4ip + case kubeovnv1.ProtocolIPv6: + subnet.Status.U2OInterconnectionIP = v6ip + case kubeovnv1.ProtocolDual: + subnet.Status.U2OInterconnectionIP = fmt.Sprintf("%s,%s", v4ip, v6ip) + } + err = c.createOrUpdateIPCR("", u2oInterconnName, subnet.Status.U2OInterconnectionIP, mac, subnet.Name, "default", "", "") + if err != nil { + klog.Errorf("failed to create or update IPs of %s : %v", u2oInterconnLrpName, err) + return "", "", "", err + } + subnet.Status.U2OInterconnectionMAC = mac + } + return v4ip, v6ip, mac, nil +} + +func (c *Controller) releaseU2OIP(subnet *kubeovnv1.Subnet, u2oInterconnName string) error { + klog.Infof("release underlay to overlay interconnection ip address %s for subnet %s", subnet.Status.U2OInterconnectionIP, subnet.Name) + c.ipam.ReleaseAddressByPod(u2oInterconnName, subnet.Name) + subnet.Status.U2OInterconnectionIP = "" + subnet.Status.U2OInterconnectionMAC = "" + subnet.Status.U2OInterconnectionVPC = "" + + err := c.config.KubeOvnClient.KubeovnV1().IPs().Delete(context.Background(), u2oInterconnName, metav1.DeleteOptions{}) + if err != nil && !k8serrors.IsNotFound(err) { + klog.Errorf("failed to delete ip %s, %v", u2oInterconnName, err) + return err + } + return nil } +func (c *Controller) acquireMcastQuerierIP(subnet *kubeovnv1.Subnet) (bool, error) { + isMcastQuerierChanged := false + mcastQuerierLspName := fmt.Sprintf(util.McastQuerierName, subnet.Name) + var v4ip, v6ip, mac string + var err error + + if subnet.Status.McastQuerierIP == "" || subnet.Status.McastQuerierMAC == "" { + v4ip, v6ip, mac, err = c.acquireIPAddress(subnet.Name, mcastQuerierLspName, mcastQuerierLspName) + if err != nil { + klog.Errorf("failed to acquire mcast querier ip address for subnet %s, %v", subnet.Name, err) + return isMcastQuerierChanged, err + } + } + + if v4ip != "" || v6ip != "" { + switch subnet.Spec.Protocol { + case kubeovnv1.ProtocolIPv4: + subnet.Status.McastQuerierIP = v4ip + case kubeovnv1.ProtocolIPv6: + subnet.Status.McastQuerierIP = v6ip + case kubeovnv1.ProtocolDual: + subnet.Status.McastQuerierIP = fmt.Sprintf("%s,%s", v4ip, v6ip) + } + + err := c.createOrUpdateIPCR("", mcastQuerierLspName, subnet.Status.McastQuerierIP, mac, subnet.Name, "default", "", "") + if err != nil { + klog.Errorf("failed to create or update IPs of %s : %v", mcastQuerierLspName, err) + return isMcastQuerierChanged, err + } + + subnet.Status.McastQuerierMAC = mac + klog.Infof("reconcile subnet %s mcast querier IP %s mac %s", + subnet.Name, subnet.Status.McastQuerierIP, subnet.Status.McastQuerierMAC) + isMcastQuerierChanged = true + } + + return isMcastQuerierChanged, nil +} + +func (c *Controller) releaseMcastQuerierIP(subnet *kubeovnv1.Subnet) (bool, error) { + isMcastQuerierChanged := false + if subnet.Status.McastQuerierIP != "" { + mcastQuerierLspName := fmt.Sprintf(util.McastQuerierName, subnet.Name) + klog.Infof("release mcast querier ip address %s for subnet %s", subnet.Status.McastQuerierIP, subnet.Name) + c.ipam.ReleaseAddressByPod(mcastQuerierLspName, subnet.Name) + subnet.Status.McastQuerierIP = "" + subnet.Status.McastQuerierMAC = "" + + if err := c.config.KubeOvnClient.KubeovnV1().IPs().Delete(context.Background(), mcastQuerierLspName, metav1.DeleteOptions{}); err != nil { + if !k8serrors.IsNotFound(err) { + klog.Errorf("failed to delete ip %s, %v", mcastQuerierLspName, err) + return isMcastQuerierChanged, err + } + } + isMcastQuerierChanged = true + klog.Infof("reconcile subnet %s mcast querier IP %s mac %s", + subnet.Name, subnet.Status.McastQuerierIP, subnet.Status.McastQuerierMAC) + } + return isMcastQuerierChanged, nil +} + func (c *Controller) calcDualSubnetStatusIP(subnet *kubeovnv1.Subnet) (*kubeovnv1.Subnet, error) { if err := util.CheckCidrs(subnet.Spec.CIDRBlock); err != nil { return nil, err @@ -3133,3 +3225,52 @@ func (c *Controller) findSubnetByNetworkAttachmentDefinition(ns, name string, su return subnet, nil } + +func (c *Controller) handleMcastQuerierChange(subnet *kubeovnv1.Subnet) error { + if subnet.Spec.EnableMulticastSnoop { + multicastSnoopFlag := map[string]string{ + "mcast_snoop": "true", + "mcast_querier": "true", + "mcast_ip4_src": subnet.Status.McastQuerierIP, + "mcast_eth_src": subnet.Status.McastQuerierMAC, + } + mcastQuerierLspName := fmt.Sprintf(util.McastQuerierName, subnet.Name) + if err := c.OVNNbClient.CreateLogicalSwitchPort(subnet.Name, mcastQuerierLspName, subnet.Status.McastQuerierIP, subnet.Status.McastQuerierMAC, mcastQuerierLspName, "default", false, "", "", false, nil, ""); err != nil { + err = fmt.Errorf("failed to create mcast querier lsp %s: %w", mcastQuerierLspName, err) + klog.Error(err) + return err + } + + if err := c.OVNNbClient.LogicalSwitchUpdateOtherConfig(subnet.Name, ovsdb.MutateOperationInsert, multicastSnoopFlag); err != nil { + klog.Errorf("enable logical switch multicast snoop %s: %v", subnet.Name, err) + return err + } + } else { + lss, err := c.OVNNbClient.ListLogicalSwitch(false, func(ls *ovnnb.LogicalSwitch) bool { + return ls.Name == subnet.Name + }) + if err != nil || len(lss) == 0 { + klog.Errorf("failed to list logical switch %s: %v", subnet.Name, err) + return err + } + + multicastSnoopFlag := map[string]string{ + "mcast_snoop": lss[0].OtherConfig["mcast_snoop"], + "mcast_querier": lss[0].OtherConfig["mcast_querier"], + "mcast_ip4_src": lss[0].OtherConfig["mcast_ip4_src"], + "mcast_eth_src": lss[0].OtherConfig["mcast_eth_src"], + } + mcastQuerierLspName := fmt.Sprintf(util.McastQuerierName, subnet.Name) + if err := c.OVNNbClient.LogicalSwitchUpdateOtherConfig(subnet.Name, ovsdb.MutateOperationDelete, multicastSnoopFlag); err != nil { + klog.Errorf("disable logical switch multicast snoop %s: %v", subnet.Name, err) + return err + } + + if err := c.OVNNbClient.DeleteLogicalSwitchPort(mcastQuerierLspName); err != nil { + err = fmt.Errorf("failed to delete mcast querier lsp %s: %w", mcastQuerierLspName, err) + klog.Error(err) + return err + } + } + return nil +} diff --git a/pkg/controller/vpc_dns.go b/pkg/controller/vpc_dns.go index b15f6a20fce..541dcb90b2f 100644 --- a/pkg/controller/vpc_dns.go +++ b/pkg/controller/vpc_dns.go @@ -289,7 +289,8 @@ func (c *Controller) createOrUpdateVpcDNSSlr(vpcDNS *kubeovnv1.VpcDns) error { } func (c *Controller) genVpcDNSDeployment(vpcDNS *kubeovnv1.VpcDns, oldDeploy *v1.Deployment) (*v1.Deployment, error) { - tmp, err := template.ParseGlob(corednsTemplateContent) + tmp := template.New("coredns") + tmp, err := tmp.Parse(corednsTemplateContent) if err != nil { klog.Errorf("failed to parse coredns template file, %v", err) return nil, err diff --git a/pkg/daemon/gateway.go b/pkg/daemon/gateway.go index 5c3af620a49..9333a8aeac3 100644 --- a/pkg/daemon/gateway.go +++ b/pkg/daemon/gateway.go @@ -260,7 +260,7 @@ func (c *Controller) getTProxyConditionPod(needSort bool) ([]*v1.Pod, error) { } for _, pod := range pods { - if pod.Spec.NodeName != c.config.NodeName { + if pod.Spec.HostNetwork || pod.Spec.NodeName != c.config.NodeName { continue } @@ -271,7 +271,7 @@ func (c *Controller) getTProxyConditionPod(needSort bool) ([]*v1.Pod, error) { subnet, err := c.subnetsLister.Get(subnetName) if err != nil { - return nil, fmt.Errorf("failed to get subnet '%s', err: %w", subnetName, err) + return nil, fmt.Errorf("failed to get subnet %q: %w", subnetName, err) } if subnet.Spec.Vpc == c.config.ClusterRouter { diff --git a/pkg/daemon/gateway_linux.go b/pkg/daemon/gateway_linux.go index e8ae2adbf21..916cdf43c18 100644 --- a/pkg/daemon/gateway_linux.go +++ b/pkg/daemon/gateway_linux.go @@ -62,6 +62,11 @@ const ( TProxyPreroutingMask = util.TProxyPreroutingMask ) +var ( + tProxyOutputMarkMask = fmt.Sprintf("%#x/%#x", TProxyOutputMark, TProxyOutputMask) + tProxyPreRoutingMarkMask = fmt.Sprintf("%#x/%#x", TProxyPreroutingMark, TProxyPreroutingMask) +) + type policyRouteMeta struct { family int source string @@ -856,7 +861,6 @@ func (c *Controller) reconcileTProxyIPTableRules(protocol string, isDual bool) e ipt := c.iptables[protocol] tproxyPreRoutingRules := make([]util.IPTableRule, 0) tproxyOutputRules := make([]util.IPTableRule, 0) - probePorts := strset.New() pods, err := c.getTProxyConditionPod(true) if err != nil { @@ -877,54 +881,12 @@ func (c *Controller) reconcileTProxyIPTableRules(protocol string, isDual bool) e continue } - for _, container := range pod.Spec.Containers { - if container.ReadinessProbe != nil { - if httpGet := container.ReadinessProbe.HTTPGet; httpGet != nil { - if port := httpGet.Port.String(); port != "" { - probePorts.Add(port) - } - } - - if tcpSocket := container.ReadinessProbe.TCPSocket; tcpSocket != nil { - if port := tcpSocket.Port.String(); port != "" { - if isTCPProbePortReachable, ok := customVPCPodTCPProbeIPPort.Load(getIPPortString(podIP, port)); ok { - if isTCPProbePortReachable.(bool) { - probePorts.Add(port) - } - } - } - } - } - - if container.LivenessProbe != nil { - if httpGet := container.LivenessProbe.HTTPGet; httpGet != nil { - if port := httpGet.Port.String(); port != "" { - probePorts.Add(port) - } - } - - if tcpSocket := container.LivenessProbe.TCPSocket; tcpSocket != nil { - if port := tcpSocket.Port.String(); port != "" { - if isTCPProbePortReachable, ok := customVPCPodTCPProbeIPPort.Load(getIPPortString(podIP, port)); ok { - if isTCPProbePortReachable.(bool) { - probePorts.Add(port) - } - } - } - } - } - } - - if probePorts.IsEmpty() { + ports := getProbePorts(pod) + if ports.Len() == 0 { continue } - probePortList := probePorts.List() - sort.Strings(probePortList) - for _, probePort := range probePortList { - tProxyOutputMarkMask := fmt.Sprintf("%#x/%#x", TProxyOutputMark, TProxyOutputMask) - tProxyPreRoutingMarkMask := fmt.Sprintf("%#x/%#x", TProxyPreroutingMark, TProxyPreroutingMask) - + for _, probePort := range ports.SortedList() { hostIP := pod.Status.HostIP prefixLen := 32 if protocol == kubeovnv1.ProtocolIPv6 { @@ -938,8 +900,8 @@ func (c *Controller) reconcileTProxyIPTableRules(protocol string, isDual bool) e hostIP = "::" } } - tproxyOutputRules = append(tproxyOutputRules, util.IPTableRule{Table: MANGLE, Chain: OvnOutput, Rule: strings.Fields(fmt.Sprintf(`-d %s/%d -p tcp -m tcp --dport %s -j MARK --set-xmark %s`, podIP, prefixLen, probePort, tProxyOutputMarkMask))}) - tproxyPreRoutingRules = append(tproxyPreRoutingRules, util.IPTableRule{Table: MANGLE, Chain: OvnPrerouting, Rule: strings.Fields(fmt.Sprintf(`-d %s/%d -p tcp -m tcp --dport %s -j TPROXY --on-port %d --on-ip %s --tproxy-mark %s`, podIP, prefixLen, probePort, util.TProxyListenPort, hostIP, tProxyPreRoutingMarkMask))}) + tproxyOutputRules = append(tproxyOutputRules, util.IPTableRule{Table: MANGLE, Chain: OvnOutput, Rule: strings.Fields(fmt.Sprintf(`-d %s/%d -p tcp -m tcp --dport %d -j MARK --set-xmark %s`, podIP, prefixLen, probePort, tProxyOutputMarkMask))}) + tproxyPreRoutingRules = append(tproxyPreRoutingRules, util.IPTableRule{Table: MANGLE, Chain: OvnPrerouting, Rule: strings.Fields(fmt.Sprintf(`-d %s/%d -p tcp -m tcp --dport %d -j TPROXY --on-port %d --on-ip %s --tproxy-mark %s`, podIP, prefixLen, probePort, util.TProxyListenPort, hostIP, tProxyPreRoutingMarkMask))}) } } @@ -1422,6 +1384,12 @@ func (c *Controller) setExGateway() error { klog.Errorf("failed to get node, %v", err) return err } + var isUserspaceDP bool + isUserspaceDP, err = ovs.IsUserspaceDataPath() + if err != nil { + klog.Error(err) + return err + } enable := node.Labels[util.ExGatewayLabel] externalBridge := util.ExternalBridgeName(c.config.ExternalGatewaySwitch) if enable == "true" { @@ -1437,15 +1405,19 @@ func (c *Controller) setExGateway() error { klog.Error(err) return err } - link, err := netlink.LinkByName(linkName) - if err != nil { - klog.Errorf("failed to get nic %s, %v", linkName, err) - return err - } - if err := netlink.LinkSetUp(link); err != nil { - klog.Errorf("failed to set gateway nic %s up, %v", linkName, err) - return err + + if !isUserspaceDP { + link, err := netlink.LinkByName(linkName) + if err != nil { + klog.Errorf("failed to get nic %s, %v", linkName, err) + return err + } + if err := netlink.LinkSetUp(link); err != nil { + klog.Errorf("failed to set gateway nic %s up, %v", linkName, err) + return err + } } + externalBrReady := false // if external nic already attached into another bridge if existBr, err := ovs.Exec("port-to-br", linkName); err == nil { @@ -1513,7 +1485,7 @@ func (c *Controller) setExGateway() error { } } - if !keepExternalSubnet { + if !isUserspaceDP && !keepExternalSubnet { klog.Infof("delete external bridge %s", externalBridge) if _, err := ovs.Exec( ovs.IfExists, "del-br", externalBridge); err != nil { diff --git a/pkg/daemon/handler.go b/pkg/daemon/handler.go index 39333b95fd9..6367a4a049e 100644 --- a/pkg/daemon/handler.go +++ b/pkg/daemon/handler.go @@ -426,14 +426,10 @@ func (csh cniServerHandler) handleDel(req *restful.Request, resp *restful.Respon return } + // Try to get the Pod, but if it fails due to not being found, log a warning and continue. pod, err := csh.Controller.podsLister.Pods(podRequest.PodNamespace).Get(podRequest.PodName) - if err != nil { - if k8serrors.IsNotFound(err) { - resp.WriteHeader(http.StatusNoContent) - return - } - - errMsg := fmt.Errorf("parse del request failed %w", err) + if err != nil && !k8serrors.IsNotFound(err) { + errMsg := fmt.Errorf("failed to retrieve Pod %s/%s: %w", podRequest.PodNamespace, podRequest.PodName, err) klog.Error(errMsg) if err := resp.WriteHeaderAndEntity(http.StatusBadRequest, request.CniResponse{Err: errMsg.Error()}); err != nil { klog.Errorf("failed to write response, %v", err) @@ -456,56 +452,73 @@ func (csh cniServerHandler) handleDel(req *restful.Request, resp *restful.Respon return } - if pod.Annotations != nil && (util.IsOvnProvider(podRequest.Provider) || podRequest.CniType == util.CniTypeName) { - subnet := pod.Annotations[fmt.Sprintf(util.LogicalSwitchAnnotationTemplate, podRequest.Provider)] - if subnet != "" { - ip := pod.Annotations[fmt.Sprintf(util.IPAddressAnnotationTemplate, podRequest.Provider)] - if err = csh.Controller.removeEgressConfig(subnet, ip); err != nil { - errMsg := fmt.Errorf("failed to remove egress configuration: %w", err) - klog.Error(errMsg) - if err = resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil { - klog.Errorf("failed to write response, %v", err) + var nicType string + var vmName string + + // If the Pod was found, process its annotations and labels. + if err == nil { + if pod.Annotations != nil && (util.IsOvnProvider(podRequest.Provider) || podRequest.CniType == util.CniTypeName) { + subnet := pod.Annotations[fmt.Sprintf(util.LogicalSwitchAnnotationTemplate, podRequest.Provider)] + if subnet != "" { + ip := pod.Annotations[fmt.Sprintf(util.IPAddressAnnotationTemplate, podRequest.Provider)] + if err = csh.Controller.removeEgressConfig(subnet, ip); err != nil { + errMsg := fmt.Errorf("failed to remove egress configuration: %w", err) + klog.Error(errMsg) + if err = resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil { + klog.Errorf("failed to write response, %v", err) + } + return } - return } - } - // For Support kubevirt hotplug dpdk nic, forbidden set the volume name - if podRequest.VhostUserSocketConsumption == util.ConsumptionKubevirt { - podRequest.VhostUserSocketVolumeName = util.VhostUserSocketVolumeName - } + switch { + case podRequest.DeviceID != "": + nicType = util.OffloadType + case podRequest.VhostUserSocketVolumeName != "": + nicType = util.DpdkType + if err = removeShortSharedDir(pod, podRequest.VhostUserSocketVolumeName, podRequest.VhostUserSocketConsumption); err != nil { + klog.Error(err.Error()) + if err = resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: err.Error()}); err != nil { + klog.Errorf("failed to write response: %v", err) + } + return + } + default: + nicType = pod.Annotations[fmt.Sprintf(util.PodNicAnnotationTemplate, podRequest.Provider)] + } - var nicType string + vmName = pod.Annotations[fmt.Sprintf(util.VMAnnotationTemplate, podRequest.Provider)] + if vmName != "" { + podRequest.PodName = vmName + } + } + } else { + // If the Pod is not found, assign a default value. + klog.Warningf("Pod %s not found, proceeding with NIC deletion using ContainerID and NetNs", podRequest.PodName) switch { case podRequest.DeviceID != "": nicType = util.OffloadType case podRequest.VhostUserSocketVolumeName != "": nicType = util.DpdkType - if err = removeShortSharedDir(pod, podRequest.VhostUserSocketVolumeName, podRequest.VhostUserSocketConsumption); err != nil { - klog.Error(err.Error()) - if err = resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: err.Error()}); err != nil { - klog.Errorf("failed to write response: %v", err) - } - return - } default: - nicType = pod.Annotations[fmt.Sprintf(util.PodNicAnnotationTemplate, podRequest.Provider)] - } - vmName := pod.Annotations[fmt.Sprintf(util.VMAnnotationTemplate, podRequest.Provider)] - if vmName != "" { - podRequest.PodName = vmName + nicType = "veth-pair" } + } - err = csh.deleteNic(podRequest.PodName, podRequest.PodNamespace, podRequest.ContainerID, podRequest.NetNs, podRequest.DeviceID, podRequest.IfName, nicType, podRequest.Provider) - if err != nil { - errMsg := fmt.Errorf("del nic failed %w", err) - klog.Error(errMsg) - if err := resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil { - klog.Errorf("failed to write response, %v", err) - } - return - } + // For Support kubevirt hotplug dpdk nic, forbidden set the volume name + if podRequest.VhostUserSocketConsumption == util.ConsumptionKubevirt { + podRequest.VhostUserSocketVolumeName = util.VhostUserSocketVolumeName } + // Proceed to delete the NIC regardless of whether the Pod was found or not. + err = csh.deleteNic(podRequest.PodName, podRequest.PodNamespace, podRequest.ContainerID, podRequest.NetNs, podRequest.DeviceID, podRequest.IfName, nicType) + if err != nil { + errMsg := fmt.Errorf("del nic failed %w", err) + klog.Error(errMsg) + if err := resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil { + klog.Errorf("failed to write response, %v", err) + } + return + } resp.WriteHeader(http.StatusNoContent) } diff --git a/pkg/daemon/init.go b/pkg/daemon/init.go index 3d7095e2da8..2b3ed3bc3e6 100644 --- a/pkg/daemon/init.go +++ b/pkg/daemon/init.go @@ -159,43 +159,53 @@ func (c *Controller) ovsCleanProviderNetwork(provider string) error { return nil } - // get host nic - if output, err = ovs.Exec("list-ports", brName); err != nil { - return fmt.Errorf("failed to list ports of OVS bridge %s, %w: %q", brName, err, output) + isUserspaceDP, err := ovs.IsUserspaceDataPath() + if err != nil { + klog.Error(err) + return err } - // remove host nic from the external bridge - if output != "" { - for _, port := range strings.Split(output, "\n") { - // patch port created by ovn-controller has an external ID ovn-localnet-port=localnet. - if output, err = ovs.Exec("--data=bare", "--no-heading", "--columns=_uuid", "find", "port", "name="+port, `external-ids:ovn-localnet-port!=""`); err != nil { - return fmt.Errorf("failed to find ovs port %s, %w: %q", port, err, output) - } - if output != "" { - continue - } - klog.V(3).Infof("removing ovs port %s from bridge %s", port, brName) - if err = c.removeProviderNic(port, brName); err != nil { - errMsg := fmt.Errorf("failed to remove port %s from external bridge %s: %w", port, brName, err) - klog.Error(errMsg) - return errMsg - } - klog.V(3).Infof("ovs port %s has been removed from bridge %s", port, brName) + if !isUserspaceDP { + // get host nic + if output, err = ovs.Exec("list-ports", brName); err != nil { + klog.Errorf("failed to list ports of OVS bridge %s, %v: %q", brName, err, output) + return err } - } - // remove OVS bridge - klog.Infof("delete external bridge %s", brName) - if output, err = ovs.Exec(ovs.IfExists, "del-br", brName); err != nil { - return fmt.Errorf("failed to remove OVS bridge %s, %w: %q", brName, err, output) - } - klog.V(3).Infof("ovs bridge %s has been deleted", brName) + // remove host nic from the external bridge + if output != "" { + for _, port := range strings.Split(output, "\n") { + // patch port created by ovn-controller has an external ID ovn-localnet-port=localnet. + if output, err = ovs.Exec("--data=bare", "--no-heading", "--columns=_uuid", "find", "port", "name="+port, `external-ids:ovn-localnet-port!=""`); err != nil { + klog.Errorf("failed to find ovs port %s, %v: %q", port, err, output) + return err + } + if output != "" { + continue + } + klog.Infof("removing ovs port %s from bridge %s", port, brName) + if err = c.removeProviderNic(port, brName); err != nil { + klog.Errorf("failed to remove port %s from external bridge %s: %v", port, brName, err) + return err + } + klog.Infof("ovs port %s has been removed from bridge %s", port, brName) + } + } - if br := util.ExternalBridgeName(provider); br != brName { - if _, err = c.changeProvideNicName(br, brName); err != nil { - klog.Errorf("failed to change provider nic name from %s to %s: %v", br, brName, err) + // remove OVS bridge + klog.Infof("delete external bridge %s", brName) + if output, err = ovs.Exec(ovs.IfExists, "del-br", brName); err != nil { + klog.Errorf("failed to remove OVS bridge %s, %v: %q", brName, err, output) return err } + klog.Infof("ovs bridge %s has been deleted", brName) + + if br := util.ExternalBridgeName(provider); br != brName { + if _, err = c.changeProvideNicName(br, brName); err != nil { + klog.Errorf("failed to change provider nic name from %s to %s: %v", br, brName, err) + return err + } + } } if err := removeOvnMapping("ovn-chassis-mac-mappings", provider); err != nil { diff --git a/pkg/daemon/ovs_linux.go b/pkg/daemon/ovs_linux.go index 3bc89172857..1f64f58507f 100644 --- a/pkg/daemon/ovs_linux.go +++ b/pkg/daemon/ovs_linux.go @@ -151,6 +151,7 @@ func (csh cniServerHandler) configureNic(podName, podNamespace, provider, netns, oriPod := pod.DeepCopy() pod.Annotations[fmt.Sprintf(util.VfRepresentorNameTemplate, provider)] = hostNicName pod.Annotations[fmt.Sprintf(util.VfNameTemplate, provider)] = containerNicName + pod.Annotations[fmt.Sprintf(util.PodNicAnnotationTemplate, provider)] = util.SriovNicType var patch []byte patch, err = util.GenerateMergePatchPayload(oriPod, pod) if err != nil { @@ -215,7 +216,7 @@ func (csh cniServerHandler) configureNic(podName, podNamespace, provider, netns, return finalRoutes, nil } -func (csh cniServerHandler) releaseVf(podName, podNamespace, podNetns, ifName, nicType, provider, deviceID string) error { +func (csh cniServerHandler) releaseVf(podName, podNamespace, podNetns, ifName, nicType, deviceID string) error { // Only for SRIOV case, we'd need to move the VF from container namespace back to the host namespace if !(nicType == util.OffloadType && deviceID != "") { return nil @@ -244,18 +245,14 @@ func (csh cniServerHandler) releaseVf(podName, podNamespace, podNetns, ifName, n return fmt.Errorf("failed to bring down container interface %s %s: %w", ifName, podDesc, err) } // rename VF device back to its original name in the host namespace: - pod, err := csh.Controller.podsLister.Pods(podNamespace).Get(podName) - if err != nil { - klog.Errorf("failed to get pod %s/%s: %v", podName, podNamespace, err) - return err - } - vfName := pod.Annotations[fmt.Sprintf(util.VfNameTemplate, provider)] + vfName := link.Attrs().Alias if err = netlink.LinkSetName(link, vfName); err != nil { return fmt.Errorf("failed to rename container interface %s to %s %s: %w", ifName, vfName, podDesc, err) } // move VF device to host netns - if err = netlink.LinkSetNsFd(link, int(hostNS.Fd())); err != nil { + fd := int(netns.Fd()) // #nosec G115 + if err = netlink.LinkSetNsFd(link, fd); err != nil { return fmt.Errorf("failed to move container interface %s back to host namespace %s: %w", ifName, podDesc, err) } @@ -268,8 +265,8 @@ func (csh cniServerHandler) releaseVf(podName, podNamespace, podNetns, ifName, n return nil } -func (csh cniServerHandler) deleteNic(podName, podNamespace, containerID, netns, deviceID, ifName, nicType, provider string) error { - if err := csh.releaseVf(podName, podNamespace, netns, ifName, nicType, provider, deviceID); err != nil { +func (csh cniServerHandler) deleteNic(podName, podNamespace, containerID, netns, deviceID, ifName, nicType string) error { + if err := csh.releaseVf(podName, podNamespace, netns, ifName, nicType, deviceID); err != nil { return fmt.Errorf("failed to release VF %s assigned to the Pod %s/%s back to the host network namespace: "+ "%w", ifName, podName, podNamespace, err) } @@ -406,7 +403,8 @@ func (csh cniServerHandler) configureContainerNic(podName, podNamespace, nicName return nil, err } - if err = netlink.LinkSetNsFd(containerLink, int(netns.Fd())); err != nil { + fd := int(netns.Fd()) // #nosec G115 + if err = netlink.LinkSetNsFd(containerLink, fd); err != nil { return nil, fmt.Errorf("failed to move link to netns: %w", err) } @@ -790,7 +788,8 @@ func configureNodeGwNic(portName, ip, gw string, macAddr net.HardwareAddr, mtu i } gwLink, err := netlink.LinkByName(util.NodeGwNic) if err == nil { - if err = netlink.LinkSetNsFd(gwLink, int(gwNS.Fd())); err != nil { + fd := int(gwNS.Fd()) // #nosec G115 + if err = netlink.LinkSetNsFd(gwLink, fd); err != nil { klog.Errorf("failed to move link into netns: %v", err) return err } @@ -1341,16 +1340,29 @@ func (c *Controller) transferAddrsAndRoutes(nicName, brName string, delNonExiste // Add host nic to external bridge // Mac address, MTU, IP addresses & routes will be copied/transferred to the external bridge func (c *Controller) configProviderNic(nicName, brName string, trunks []string) (int, error) { - mtu, err := c.transferAddrsAndRoutes(nicName, brName, false) + isUserspaceDP, err := ovs.IsUserspaceDataPath() if err != nil { - return 0, fmt.Errorf("failed to transfer addresses and routes from %s to %s: %w", nicName, brName, err) + klog.Error(err) + return 0, err } - if _, err = ovs.Exec(ovs.MayExist, "add-port", brName, nicName, - "--", "set", "port", nicName, "trunks="+strings.Join(trunks, ","), "external_ids:vendor="+util.CniTypeName); err != nil { - return 0, fmt.Errorf("failed to add %s to OVS bridge %s: %w", nicName, brName, err) + var mtu int + if !isUserspaceDP { + mtu, err = c.transferAddrsAndRoutes(nicName, brName, false) + if err != nil { + klog.Errorf("failed to transfer addresses and routes from %s to %s: %v", nicName, brName, err) + return 0, err + } + + if _, err = ovs.Exec(ovs.MayExist, "add-port", brName, nicName, + "--", "set", "port", nicName, "trunks="+strings.Join(trunks, ","), "external_ids:vendor="+util.CniTypeName); err != nil { + klog.Errorf("failed to add %s to OVS bridge %s: %v", nicName, brName, err) + return 0, err + } + klog.V(3).Infof("ovs port %s has been added to bridge %s", nicName, brName) + } else { + mtu = c.config.MTU } - klog.V(3).Infof("ovs port %s has been added to bridge %s", nicName, brName) return mtu, nil } diff --git a/pkg/daemon/tproxy_linux.go b/pkg/daemon/tproxy_linux.go index d0bd3801945..7c8e66c3d43 100644 --- a/pkg/daemon/tproxy_linux.go +++ b/pkg/daemon/tproxy_linux.go @@ -10,11 +10,13 @@ import ( "syscall" "github.com/containernetworking/plugins/pkg/ns" - "github.com/scylladb/go-set/strset" "github.com/vishvananda/netlink" "golang.org/x/sys/unix" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/klog/v2" "k8s.io/utils/ptr" + "k8s.io/utils/set" kubeovnv1 "github.com/kubeovn/kube-ovn/pkg/apis/kubeovn/v1" "github.com/kubeovn/kube-ovn/pkg/ovs" @@ -56,9 +58,43 @@ func (c *Controller) StartTProxyForwarding() { } } -func (c *Controller) StartTProxyTCPPortProbe() { - probePorts := strset.New() +func getProbePorts(pod *corev1.Pod) set.Set[int32] { + ports := set.New[int32]() + for _, container := range pod.Spec.Containers { + for _, probe := range [...]*corev1.Probe{container.LivenessProbe, container.ReadinessProbe} { + if probe == nil { + continue + } + var port intstr.IntOrString + switch { + case probe.TCPSocket != nil: + port = probe.TCPSocket.Port + case probe.HTTPGet != nil: + port = probe.HTTPGet.Port + case probe.GRPC != nil: + port = intstr.FromInt32(probe.GRPC.Port) + default: + continue + } + if port.Type == intstr.Int { + ports.Insert(port.IntVal) + continue + } + for _, p := range container.Ports { + if p.Name == port.StrVal { + ports.Insert(p.ContainerPort) + break + } + } + } + } + ports.Delete(0) + klog.Infof("probe ports for pod %s/%s: %v", pod.Namespace, pod.Name, ports.SortedList()) + return ports +} + +func (c *Controller) StartTProxyTCPPortProbe() { pods, err := c.getTProxyConditionPod(false) if err != nil { return @@ -67,33 +103,19 @@ func (c *Controller) StartTProxyTCPPortProbe() { for _, pod := range pods { iface := ovs.PodNameToPortName(pod.Name, pod.Namespace, util.OvnProvider) nsName, err := ovs.GetInterfacePodNs(iface) - if err != nil || nsName == "" { - klog.Infof("iface %s's namespace not found", iface) + if err != nil { + klog.Errorf("failed to get netns for pod %s/%s: %v", pod.Namespace, pod.Name, err) + continue + } + if nsName == "" { + klog.Infof("netns for pod %s/%s not found", pod.Namespace, pod.Name) continue } + ports := getProbePorts(pod) for _, podIP := range pod.Status.PodIPs { customVPCPodIPToNs.Store(podIP.IP, nsName) - for _, container := range pod.Spec.Containers { - if container.ReadinessProbe != nil { - if tcpSocket := container.ReadinessProbe.TCPSocket; tcpSocket != nil { - if port := tcpSocket.Port.String(); port != "" { - probePorts.Add(port) - } - } - } - - if container.LivenessProbe != nil { - if tcpSocket := container.LivenessProbe.TCPSocket; tcpSocket != nil { - if port := tcpSocket.Port.String(); port != "" { - probePorts.Add(port) - } - } - } - } - - probePortsList := probePorts.List() - for _, port := range probePortsList { + for _, port := range ports.UnsortedList() { probePortInNs(podIP.IP, port, true, nil) } } @@ -264,7 +286,7 @@ func delRouteIfExist(family, table int, dst *net.IPNet) error { } func handleRedirectFlow(conn net.Conn) { - klog.V(5).Infof("Accepting TCP connection from %v with destination of %v", conn.RemoteAddr().String(), conn.LocalAddr().String()) + klog.V(5).Infof("accepting TCP connection from %s to %s", conn.RemoteAddr(), conn.LocalAddr()) defer func() { if err := conn.Close(); err != nil { klog.Errorf("conn Close err: %v", err) @@ -278,42 +300,44 @@ func handleRedirectFlow(conn net.Conn) { return } - probePortInNs(podIP, probePort, false, conn) + port, err := strconv.ParseInt(probePort, 10, 32) + if err != nil { + klog.Errorf("failed to parse port number %q: %v", probePort, err) + return + } + + probePortInNs(podIP, int32(port), false, conn) // #nosec G115 } -func probePortInNs(podIP, probePort string, isTProxyProbe bool, conn net.Conn) { +func probePortInNs(podIP string, probePort int32, isTProxyProbe bool, conn net.Conn) { podNs, ok := customVPCPodIPToNs.Load(podIP) if !ok { - return - } - - iprobePort, err := strconv.Atoi(probePort) - if err != nil { + klog.V(3).Infof("failed to get netns for pod with ip %s", podIP) return } podNS, err := ns.GetNS(podNs.(string)) if err != nil { customVPCPodIPToNs.Delete(podIP) - klog.Infof("ns %s already deleted", podNs) + klog.V(3).Infof("netns %s not found", podNs) return } _ = ns.WithNetNSPath(podNS.Path(), func(_ ns.NetNS) error { // Packet's src and dst IP are both PodIP in netns localpodTCPAddr := net.TCPAddr{IP: net.ParseIP(podIP)} - remotepodTCPAddr := net.TCPAddr{IP: net.ParseIP(podIP), Port: iprobePort} + remotepodTCPAddr := net.TCPAddr{IP: net.ParseIP(podIP), Port: int(probePort)} remoteConn, err := goTProxy.DialTCP(&localpodTCPAddr, &remotepodTCPAddr, !isTProxyProbe) if err != nil { if isTProxyProbe { - customVPCPodTCPProbeIPPort.Store(getIPPortString(podIP, probePort), false) + customVPCPodTCPProbeIPPort.Store(util.JoinHostPort(podIP, probePort), false) } return nil } if isTProxyProbe { - customVPCPodTCPProbeIPPort.Store(getIPPortString(podIP, probePort), true) + customVPCPodTCPProbeIPPort.Store(util.JoinHostPort(podIP, probePort), true) return nil } @@ -342,10 +366,6 @@ func probePortInNs(podIP, probePort string, isTProxyProbe bool, conn net.Conn) { }) } -func getIPPortString(podIP, port string) string { - return fmt.Sprintf("%s|%s", podIP, port) -} - func getProtocols(protocol string) []string { var protocols []string if protocol == kubeovnv1.ProtocolDual { diff --git a/pkg/ipam/ipam.go b/pkg/ipam/ipam.go index 9edf65a2486..a0cb492dfcf 100644 --- a/pkg/ipam/ipam.go +++ b/pkg/ipam/ipam.go @@ -180,8 +180,14 @@ func (ipam *IPAM) AddOrUpdateSubnet(name, cidrStr, gw string, excludeIps []strin v4cidrStr = cidrs[0].String() v6cidrStr = cidrs[1].String() gws := strings.Split(gw, ",") - v4Gw = gws[0] - v6Gw = gws[1] + if len(gws) == 2 { + v4Gw = gws[0] + v6Gw = gws[1] + } else { + err := fmt.Errorf("dual subnet %s invalid gw %s", name, gw) + klog.Error(err) + return err + } case kubeovnv1.ProtocolIPv4: v4cidrStr = cidrs[0].String() v4Gw = gw diff --git a/pkg/ipam/ipam_test.go b/pkg/ipam/ipam_test.go index 82c64624be7..e49383466d5 100644 --- a/pkg/ipam/ipam_test.go +++ b/pkg/ipam/ipam_test.go @@ -621,4 +621,271 @@ func TestIsIPAssignedToOtherPod(t *testing.T) { notUsingDualV6 := "2001:db88::10" _, ok = ipam.IsIPAssignedToOtherPod(notUsingDualV6, dualSubnetName, dualPod2Name) require.False(t, ok) + // test subnet not exist + notExistSubnet := "notExistSubnet" + _, ok = ipam.IsIPAssignedToOtherPod(v4, notExistSubnet, dualPod2Name) + require.False(t, ok) +} + +func TestIPAMAddOrUpdateSubnet(t *testing.T) { + // test v4 subnet + ipam := NewIPAM() + v4ExcludeIps := []string{ + "10.0.0.2", "10.0.0.4", "10.0.0.100", + "10.0.0.252", "10.0.0.253", "10.0.0.254", + } + v4SubnetName := "v4Subnet" + ipv4CIDR := "10.0.0.0/24" + v4Gw := "10.0.0.1" + err := ipam.AddOrUpdateSubnet(v4SubnetName, ipv4CIDR, v4Gw, v4ExcludeIps) + require.NoError(t, err) + // test valid empty exclude ips + v4ExcludeIps = []string{} + err = ipam.AddOrUpdateSubnet(v4SubnetName, ipv4CIDR, v4Gw, v4ExcludeIps) + require.NoError(t, err) + // test valid empty gw + v4Gw = "" + err = ipam.AddOrUpdateSubnet(v4SubnetName, ipv4CIDR, v4Gw, v4ExcludeIps) + require.NoError(t, err) + // test invalid ipv4 cidr + ipv4CIDR = "10.0.0./24" + err = ipam.AddOrUpdateSubnet(v4SubnetName, ipv4CIDR, v4Gw, v4ExcludeIps) + require.Equal(t, err, ErrInvalidCIDR) + + // test v6 subnet + v6ExcludeIps := []string{ + "2001:db8::2", "2001:db8::4", "2001:db8::100", + "2001:db8::252", "2001:db8::253", "2001:db8::254", + } + v6SubnetName := "v6Subnet" + ipv6CIDR := "2001:db8::/64" + v6Gw := "2001:db8::1" + err = ipam.AddOrUpdateSubnet(v6SubnetName, ipv6CIDR, v6Gw, v6ExcludeIps) + require.NoError(t, err) + + // test valid empty exclude ips + v6ExcludeIps = []string{} + err = ipam.AddOrUpdateSubnet(v6SubnetName, ipv6CIDR, v6Gw, v6ExcludeIps) + require.NoError(t, err) + + // test valid empty gw + v6Gw = "" + err = ipam.AddOrUpdateSubnet(v6SubnetName, ipv6CIDR, v6Gw, v6ExcludeIps) + require.NoError(t, err) + + // test invalid ipv6 cidr + ipv6CIDR = "2001:g6::/64" + err = ipam.AddOrUpdateSubnet(v6SubnetName, ipv6CIDR, v6Gw, v6ExcludeIps) + require.Equal(t, err, ErrInvalidCIDR) + + // test dual stack subnet + dualSubnetName := "dualSubnet" + dualExcludeIps := []string{ + "10.0.0.2", "10.0.0.4", "10.0.0.100", + "10.0.0.252", "10.0.0.253", "10.0.0.254", + "2001:db8::2", "2001:db8::4", "2001:db8::100", + "2001:db8::252", "2001:db8::253", "2001:db8::254", + } + cidr := "10.0.0.0/24,2001:db8::/64" + gw := "10.0.0.1,2001:db8::1" + err = ipam.AddOrUpdateSubnet(dualSubnetName, cidr, gw, dualExcludeIps) + require.NoError(t, err) + + // test valid empty exclude ips + dualExcludeIps = []string{} + err = ipam.AddOrUpdateSubnet(dualSubnetName, cidr, gw, dualExcludeIps) + require.NoError(t, err) + + // test invalid empty gw + gw = "" + err = ipam.AddOrUpdateSubnet(dualSubnetName, cidr, gw, dualExcludeIps) + require.Error(t, err) + + // test invalid empty cidr + cidr = "" + err = ipam.AddOrUpdateSubnet(dualSubnetName, cidr, gw, dualExcludeIps) + require.Error(t, err) + // test invalid v4 cidr + cidr = "10.0.0./24,2001:db8::/64" + err = ipam.AddOrUpdateSubnet(dualSubnetName, cidr, gw, dualExcludeIps) + require.Error(t, err) + // test invalid v6 cidr + cidr = "10.0.0./24,2001:db8::/64" + err = ipam.AddOrUpdateSubnet(dualSubnetName, cidr, gw, dualExcludeIps) + require.Error(t, err) +} + +func TestIPAMAddOrUpdateIPPool(t *testing.T) { + // test v4 subnet + ipam := NewIPAM() + v4ExcludeIps := []string{ + "10.0.0.2", "10.0.0.4", "10.0.0.100", + "10.0.0.252", "10.0.0.253", "10.0.0.254", + } + v4SubnetName := "v4Subnet" + ipv4CIDR := "10.0.0.0/24" + v4Gw := "10.0.0.1" + err := ipam.AddOrUpdateSubnet(v4SubnetName, ipv4CIDR, v4Gw, v4ExcludeIps) + require.NoError(t, err) + // create v4 pool in exist subnet + v4PoolName := "v4Pool" + v4PoolIPs := []string{"10.0.0.21", "10.0.0.41", "10.0.0.101"} + err = ipam.AddOrUpdateIPPool(v4SubnetName, v4PoolName, v4PoolIPs) + require.NoError(t, err) + // create v4 pool in non-exist subnet + nonExistSubnetName := "nonExistSubnet" + v4PoolName = "v4Pool" + err = ipam.AddOrUpdateIPPool(nonExistSubnetName, v4PoolName, v4PoolIPs) + require.Error(t, err) + + // test v6 subnet + v6ExcludeIps := []string{ + "2001:db8::2", "2001:db8::4", "2001:db8::100", + "2001:db8::252", "2001:db8::253", "2001:db8::254", + } + v6SubnetName := "v6Subnet" + ipv6CIDR := "2001:db8::/64" + v6Gw := "2001:db8::1" + err = ipam.AddOrUpdateSubnet(v6SubnetName, ipv6CIDR, v6Gw, v6ExcludeIps) + require.NoError(t, err) + // create v6 pool in exist subnet + v6PoolName := "v6Pool" + v6PoolIPs := []string{"2001:db8::21", "2001:db8::41", "2001:db8::101"} + err = ipam.AddOrUpdateIPPool(v6SubnetName, v6PoolName, v6PoolIPs) + require.NoError(t, err) + // create v6 pool in non-exist subnet + v6PoolName = "v6Pool" + err = ipam.AddOrUpdateIPPool(nonExistSubnetName, v6PoolName, v6PoolIPs) + require.Error(t, err) + + // test dual stack subnet + dualSubnetName := "dualSubnet" + dualExcludeIps := []string{ + "10.0.0.2", "10.0.0.4", "10.0.0.100", + "10.0.0.252", "10.0.0.253", "10.0.0.254", + "2001:db8::2", "2001:db8::4", "2001:db8::100", + "2001:db8::252", "2001:db8::253", "2001:db8::254", + } + cidr := "10.0.0.0/24,2001:db8::/64" + gw := "10.0.0.1,2001:db8::1" + err = ipam.AddOrUpdateSubnet(dualSubnetName, cidr, gw, dualExcludeIps) + require.NoError(t, err) + dualPoolName := "dualPool" + dualPoolIPs := []string{"10.0.0.21", "10.0.0.41", "2001:db8::21", "2001:db8::41"} + err = ipam.AddOrUpdateIPPool(dualSubnetName, dualPoolName, dualPoolIPs) + require.NoError(t, err) + // create dual pool in non-exist subnet + dualPoolName = "dualPool" + err = ipam.AddOrUpdateIPPool(nonExistSubnetName, dualPoolName, dualPoolIPs) + require.Error(t, err) +} + +func TestIPAMRemoveIPPool(t *testing.T) { + // test dual stack subnet + ipam := NewIPAM() + dualSubnetName := "dualSubnet" + dualExcludeIps := []string{ + "10.0.0.2", "10.0.0.4", "10.0.0.100", + "10.0.0.252", "10.0.0.253", "10.0.0.254", + "2001:db8::2", "2001:db8::4", "2001:db8::100", + "2001:db8::252", "2001:db8::253", "2001:db8::254", + } + cidr := "10.0.0.0/24,2001:db8::/64" + gw := "10.0.0.1,2001:db8::1" + err := ipam.AddOrUpdateSubnet(dualSubnetName, cidr, gw, dualExcludeIps) + require.NoError(t, err) + dualPoolName := "dualPool" + dualPoolIPs := []string{"10.0.0.21", "10.0.0.41", "2001:db8::21", "2001:db8::41"} + err = ipam.AddOrUpdateIPPool(dualSubnetName, dualPoolName, dualPoolIPs) + require.NoError(t, err) + // remove exist pool + ipam.RemoveIPPool(dualSubnetName, dualPoolName) + _, ok := ipam.Subnets[dualSubnetName].IPPools[dualPoolName] + require.False(t, ok) + + // remove already exist pool + ipam.RemoveIPPool(dualSubnetName, dualPoolName) + _, ok = ipam.Subnets[dualSubnetName].IPPools[dualPoolName] + require.False(t, ok) + + // remove non-exist pool + nonExistPoolName := "nonExistPool" + ipam.RemoveIPPool(dualSubnetName, nonExistPoolName) +} + +func TestIPAMIPPoolStatistics(t *testing.T) { + // test dual stack subnet + ipam := NewIPAM() + dualSubnetName := "dualSubnet" + dualExcludeIps := []string{ + "10.0.0.2", "10.0.0.4", "10.0.0.100", + "10.0.0.252", "10.0.0.253", "10.0.0.254", + "2001:db8::2", "2001:db8::4", "2001:db8::100", + "2001:db8::252", "2001:db8::253", "2001:db8::254", + } + cidr := "10.0.0.0/24,2001:db8::/64" + gw := "10.0.0.1,2001:db8::1" + err := ipam.AddOrUpdateSubnet(dualSubnetName, cidr, gw, dualExcludeIps) + require.NoError(t, err) + dualPoolName := "dualPool" + dualPoolIPs := []string{"10.0.0.21", "10.0.0.41", "2001:db8::21", "2001:db8::41"} + err = ipam.AddOrUpdateIPPool(dualSubnetName, dualPoolName, dualPoolIPs) + require.NoError(t, err) + // get exist pool statistics + v4Available, v4Using, v6Available, v6Using, v4AvailableRange, v4UsingRange, v6AvailableRange, v6UsingRange := ipam.IPPoolStatistics(dualSubnetName, dualPoolName) + require.Equal(t, "2", v4Available.String()) + require.Empty(t, v4Using) + require.Equal(t, "2", v6Available.String()) + require.Empty(t, v6Using) + require.Equal(t, "10.0.0.21,10.0.0.41", v4AvailableRange) + require.Equal(t, "", v4UsingRange) + require.Equal(t, "2001:db8::21,2001:db8::41", v6AvailableRange) + require.Equal(t, "", v6UsingRange) + // get non-exist pool statistics + nonExistPoolName := "nonExistPool" + v4Available, v4Using, v6Available, v6Using, v4AvailableRange, v4UsingRange, v6AvailableRange, v6UsingRange = ipam.IPPoolStatistics(dualSubnetName, nonExistPoolName) + require.Equal(t, "0", v4Available.String()) + require.Empty(t, v4Using) + require.Equal(t, "0", v6Available.String()) + require.Empty(t, v6Using) + require.Empty(t, v4AvailableRange) + require.Empty(t, v4UsingRange) + require.Empty(t, v6AvailableRange) + require.Empty(t, v6UsingRange) + + // get pool statistics from non-exist subnet + nonExistSubnetName := "nonExistSubnet" + v4Available, v4Using, v6Available, v6Using, v4AvailableRange, v4UsingRange, v6AvailableRange, v6UsingRange = ipam.IPPoolStatistics(nonExistSubnetName, dualPoolName) + require.Equal(t, "0", v4Available.String()) + require.Empty(t, v4Using) + require.Equal(t, "0", v6Available.String()) + require.Empty(t, v6Using) + require.Empty(t, v4AvailableRange) + require.Empty(t, v4UsingRange) + require.Empty(t, v6AvailableRange) + require.Empty(t, v6UsingRange) +} + +func TestGetSubnetV4Mask(t *testing.T) { + ipam := NewIPAM() + // get mask for exist subnet + v4ExcludeIps := []string{ + "10.0.0.2", "10.0.0.4", "10.0.0.100", + "10.0.0.252", "10.0.0.253", "10.0.0.254", + } + v4SubnetName := "v4Subnet" + ipv4CIDR := "10.0.0.0/24" + v4Gw := "10.0.0.1" + v4SubnetMask := "24" + err := ipam.AddOrUpdateSubnet(v4SubnetName, ipv4CIDR, v4Gw, v4ExcludeIps) + require.NoError(t, err) + mask, err := ipam.GetSubnetV4Mask(v4SubnetName) + require.NoError(t, err) + require.Equal(t, mask, v4SubnetMask) + + // get mask for non-exist subnet + nonExistSubnetName := "nonExistSubnet" + mask, err = ipam.GetSubnetV4Mask(nonExistSubnetName) + require.Equal(t, err, ErrNoAvailable) + require.Empty(t, mask) } diff --git a/pkg/ipam/subnet_test.go b/pkg/ipam/subnet_test.go index 8928d2f012b..04dbf052b82 100644 --- a/pkg/ipam/subnet_test.go +++ b/pkg/ipam/subnet_test.go @@ -208,6 +208,38 @@ func TestGetV4StaticAddress(t *testing.T) { require.Equal(t, "pod1.default", usingPod) } +func TestGetV4StaticAddressPTP(t *testing.T) { + excludeIps := []string{ + "10.0.0.0", + } + subnet, err := NewSubnet("v4Subnet", "10.0.0.0/31", excludeIps) + require.NoError(t, err) + require.NotNil(t, subnet) + // 1. pod1 has v4 ip but no mac, should get specified ip and mac + podName := "pod1.default" + nicName := "pod1.default" + var mac *string + v4 := "10.0.0.1" + v4IP, err := NewIP(v4) + require.NoError(t, err) + ip1, macStr1, err := subnet.GetStaticAddress(podName, nicName, v4IP, mac, false, true) + require.NoError(t, err) + require.Equal(t, v4, ip1.String()) + require.NotEmpty(t, macStr1) + v4IP, v6IP, m, protocol := subnet.GetPodAddress(nicName) + require.Equal(t, v4, v4IP.String()) + require.Nil(t, v6IP) + require.Equal(t, macStr1, m) + require.Equal(t, apiv1.ProtocolIPv4, protocol) + + // 2. ip is assigned to pod1, should get error + podName = "pod5.default" + v4 = "10.0.0.1" + usingPod, using := subnet.isIPAssignedToOtherPod(v4, podName) + require.True(t, using) + require.Equal(t, "pod1.default", usingPod) +} + func TestGetV6StaticAddress(t *testing.T) { excludeIps := []string{ "2001:db8::2", "2001:db8::4", "2001:db8::100", @@ -402,6 +434,30 @@ func TestGetGetV4RandomAddress(t *testing.T) { require.NotEqual(t, mac1, mac2) } +func TestGetGetV4RandomAddressPTP(t *testing.T) { + excludeIps := []string{ + "10.0.0.0", + } + subnet, err := NewSubnet("randomAddressV4Subnet1", "10.0.0.0/31", excludeIps) + require.NoError(t, err) + require.NotNil(t, subnet) + // 1. no mac, get v4 address for pod1 + podName := "pod1.default" + nicName := "pod1.default" + v4IP1, v6IP1, mac1, err := subnet.GetRandomAddress("", podName, nicName, nil, nil, false) + require.NoError(t, err) + require.NotEmpty(t, v4IP1.String()) + require.Nil(t, v6IP1) + require.NotEmpty(t, mac1) + + // 2. ip is assigned to pod1, should get error + podName = "pod5.default" + v4 := "10.0.0.1" + usingPod, using := subnet.isIPAssignedToOtherPod(v4, podName) + require.True(t, using) + require.Equal(t, "pod1.default", usingPod) +} + func TestGetGetV6RandomAddress(t *testing.T) { excludeIps := []string{ "2001:db8::2", "2001:db8::4", "2001:db8::100", @@ -573,4 +629,393 @@ func TestReleaseAddrForDualSubnet(t *testing.T) { require.False(t, subnet.ContainAddress(v6)) } -// TODO: ippool +func TestSubnetAddOrUpdateIPPool(t *testing.T) { + excludeIps := []string{ + "10.0.0.2", "10.0.0.4", "10.0.0.100", + "10.0.0.252", "10.0.0.253", "10.0.0.254", + "2001:db8::2", "2001:db8::4", "2001:db8::100", + "2001:db8::252", "2001:db8::253", "2001:db8::254", + } + subnetName := "dualSubnet" + subnet, err := NewSubnet(subnetName, "10.0.0.0/16,2001:db8::/64", excludeIps) + require.NoError(t, err) + // check default pool + defaultPool := subnet.IPPools[""] + require.NotNil(t, defaultPool) + require.NotNil(t, defaultPool.V4IPs) + require.NotNil(t, defaultPool.V6IPs) + require.NotNil(t, defaultPool.V4Free) + require.NotNil(t, defaultPool.V6Free) + require.NotNil(t, defaultPool.V4Available) + require.NotNil(t, defaultPool.V6Available) + require.NotNil(t, defaultPool.V4Reserved) + require.NotNil(t, defaultPool.V6Reserved) + require.NotNil(t, defaultPool.V4IPs) + require.NotNil(t, defaultPool.V4IPs) + require.NotNil(t, defaultPool.V4Released) + require.NotNil(t, defaultPool.V6Released) + require.NotNil(t, defaultPool.V4Using) + require.NotNil(t, defaultPool.V6Using) + require.Equal(t, defaultPool.V4IPs.String(), "10.0.0.1-10.0.255.254") + require.Equal(t, defaultPool.V6IPs.String(), "2001:db8::1-2001:db8::ffff:ffff:ffff:fffe") + require.Equal(t, defaultPool.V4Free.String(), "10.0.0.1,10.0.0.3,10.0.0.5-10.0.0.99,10.0.0.101-10.0.0.251,10.0.0.255-10.0.255.254") + require.Equal(t, defaultPool.V6Free.String(), "2001:db8::1,2001:db8::3,2001:db8::5-2001:db8::ff,2001:db8::101-2001:db8::251,2001:db8::255-2001:db8::ffff:ffff:ffff:fffe") + require.Equal(t, defaultPool.V4Available.String(), "10.0.0.1,10.0.0.3,10.0.0.5-10.0.0.99,10.0.0.101-10.0.0.251,10.0.0.255-10.0.255.254") + require.Equal(t, defaultPool.V6Available.String(), "2001:db8::1,2001:db8::3,2001:db8::5-2001:db8::ff,2001:db8::101-2001:db8::251,2001:db8::255-2001:db8::ffff:ffff:ffff:fffe") + require.Equal(t, defaultPool.V4Reserved.String(), "10.0.0.2,10.0.0.4,10.0.0.100,10.0.0.252-10.0.0.254") + require.Equal(t, defaultPool.V6Reserved.String(), "2001:db8::2,2001:db8::4,2001:db8::100,2001:db8::252-2001:db8::254") + require.Equal(t, defaultPool.V4Released.String(), "") + require.Equal(t, defaultPool.V6Released.String(), "") + require.Equal(t, defaultPool.V4Using.String(), "") + require.Equal(t, defaultPool.V6Using.String(), "") + + // check V4 valid pool + v4ValidPoolName := "v4ValidPool" + validV4IPs := []string{"10.0.0.20", "10.0.0.90", "10.0.0.170", "10.0.0.240", "10.0.0.250"} + err = subnet.AddOrUpdateIPPool(v4ValidPoolName, validV4IPs) + require.NoError(t, err) + require.NotNil(t, subnet.IPPools[v4ValidPoolName]) + v4ValidPool, ok := subnet.IPPools[v4ValidPoolName] + require.True(t, ok) + require.NotNil(t, v4ValidPool) + require.NotNil(t, v4ValidPool.V4IPs) + require.NotNil(t, v4ValidPool.V6IPs) + require.NotNil(t, v4ValidPool.V4Free) + require.NotNil(t, v4ValidPool.V6Free) + require.NotNil(t, v4ValidPool.V4Available) + require.NotNil(t, v4ValidPool.V6Available) + require.NotNil(t, v4ValidPool.V4Reserved) + require.NotNil(t, v4ValidPool.V6Reserved) + require.NotNil(t, v4ValidPool.V4IPs) + require.NotNil(t, v4ValidPool.V6IPs) + require.NotNil(t, v4ValidPool.V4Released) + require.NotNil(t, v4ValidPool.V6Released) + require.NotNil(t, v4ValidPool.V4Using) + require.NotNil(t, v4ValidPool.V6Using) + + require.Equal(t, v4ValidPool.V4IPs.String(), "10.0.0.20,10.0.0.90,10.0.0.170,10.0.0.240,10.0.0.250") + require.Equal(t, v4ValidPool.V6IPs.String(), "") + require.Equal(t, v4ValidPool.V4Free.String(), "10.0.0.20,10.0.0.90,10.0.0.170,10.0.0.240,10.0.0.250") + require.Equal(t, v4ValidPool.V6Free.String(), "") + require.Equal(t, v4ValidPool.V4Available.String(), "10.0.0.20,10.0.0.90,10.0.0.170,10.0.0.240,10.0.0.250") + require.Equal(t, v4ValidPool.V6Available.String(), "") + require.Equal(t, v4ValidPool.V4Reserved.String(), "") + require.Equal(t, v4ValidPool.V6Reserved.String(), "") + require.Equal(t, v4ValidPool.V4Released.String(), "") + require.Equal(t, v4ValidPool.V6Released.String(), "") + require.Equal(t, v4ValidPool.V4Using.String(), "") + require.Equal(t, v4ValidPool.V6Using.String(), "") + + // check V4 invalid pool + v4InvalidPoolName := "v4InvalidPool" + invalidV4IPs := []string{"10.0.0.21", "10.0.0.9", "10.0.0.17", "10.0.0.241", "10.0.0.261"} + err = subnet.AddOrUpdateIPPool(v4InvalidPoolName, invalidV4IPs) + require.Error(t, err) + require.Nil(t, subnet.IPPools[v4InvalidPoolName]) + + // check V4 different pool has the same ip + v4ConflictPoolName := "v4ConflictPool" + conflictV4IPs := []string{"10.0.0.20", "10.0.0.92", "10.0.0.172", "10.0.0.242"} + err = subnet.AddOrUpdateIPPool(v4ConflictPoolName, conflictV4IPs) + require.Error(t, err) + require.Nil(t, subnet.IPPools[v4ConflictPoolName]) + + // check V6 valid pool + v6ValidPoolName := "v6ValidPool" + validV6IPs := []string{"2001:db8::20", "2001:db8::90", "2001:db8::170", "2001:db8::240", "2001:db8::250"} + err = subnet.AddOrUpdateIPPool(v6ValidPoolName, validV6IPs) + require.NoError(t, err) + require.NotNil(t, subnet.IPPools[v6ValidPoolName]) + v6ValidPool, ok := subnet.IPPools[v6ValidPoolName] + require.True(t, ok) + require.NotNil(t, v6ValidPool) + require.NotNil(t, v6ValidPool.V4IPs) + require.NotNil(t, v6ValidPool.V6IPs) + require.NotNil(t, v6ValidPool.V4Free) + require.NotNil(t, v6ValidPool.V6Free) + require.NotNil(t, v6ValidPool.V4Available) + require.NotNil(t, v6ValidPool.V6Available) + require.NotNil(t, v6ValidPool.V4Reserved) + require.NotNil(t, v6ValidPool.V4Reserved) + require.NotNil(t, v6ValidPool.V6Reserved) + require.NotNil(t, v6ValidPool.V4IPs) + require.NotNil(t, v6ValidPool.V4IPs) + require.NotNil(t, v6ValidPool.V4Released) + require.NotNil(t, v6ValidPool.V6Released) + require.NotNil(t, v6ValidPool.V4Using) + require.NotNil(t, v6ValidPool.V6Using) + + require.Equal(t, v6ValidPool.V4IPs.String(), "") + require.Equal(t, v6ValidPool.V6IPs.String(), "2001:db8::20,2001:db8::90,2001:db8::170,2001:db8::240,2001:db8::250") + require.Equal(t, v6ValidPool.V4Free.String(), "") + require.Equal(t, v6ValidPool.V6Free.String(), "2001:db8::20,2001:db8::90,2001:db8::170,2001:db8::240,2001:db8::250") + require.Equal(t, v6ValidPool.V4Available.String(), "") + require.Equal(t, v6ValidPool.V6Available.String(), "2001:db8::20,2001:db8::90,2001:db8::170,2001:db8::240,2001:db8::250") + require.Equal(t, v6ValidPool.V4Reserved.String(), "") + require.Equal(t, v6ValidPool.V6Reserved.String(), "") + require.Equal(t, v6ValidPool.V4Released.String(), "") + require.Equal(t, v6ValidPool.V6Released.String(), "") + require.Equal(t, v6ValidPool.V4Using.String(), "") + require.Equal(t, v6ValidPool.V6Using.String(), "") + + // check V6 invalid pool + v6InvalidPoolName := "v6InvalidPool" + invalidV6IPs := []string{"2001:db8::21", "2001:db8::9", "2001:db8::17", "2001:db8::241", "2001:db8::g61"} + err = subnet.AddOrUpdateIPPool(v6InvalidPoolName, invalidV6IPs) + require.Error(t, err) + require.Nil(t, subnet.IPPools[v6InvalidPoolName]) + + // check V6 different pool has the same ip + v6ConflictPoolName := "v6ConflictPool" + conflictV6IPs := []string{"2001:db8::20", "2001:db8::92", "2001:db8::172", "2001:db8::242"} + err = subnet.AddOrUpdateIPPool(v6ConflictPoolName, conflictV6IPs) + require.Error(t, err) + require.Nil(t, subnet.IPPools[v6ConflictPoolName]) + + // check dualstack valid pool + dualValidPoolName := "dualValidPool" + validDualIPs := []string{"10.0.0.30", "10.0.0.80", "2001:db8::30", "2001:db8::80"} + err = subnet.AddOrUpdateIPPool(dualValidPoolName, validDualIPs) + require.NoError(t, err) + require.NotNil(t, subnet.IPPools[dualValidPoolName]) + dualValidPool, ok := subnet.IPPools[dualValidPoolName] + require.True(t, ok) + require.NotNil(t, dualValidPool) + require.NotNil(t, dualValidPool.V4IPs) + require.NotNil(t, dualValidPool.V6IPs) + require.NotNil(t, dualValidPool.V4Free) + require.NotNil(t, dualValidPool.V6Free) + require.NotNil(t, dualValidPool.V4Available) + require.NotNil(t, dualValidPool.V6Available) + require.NotNil(t, dualValidPool.V4Reserved) + require.NotNil(t, dualValidPool.V6Reserved) + require.NotNil(t, dualValidPool.V4IPs) + require.NotNil(t, dualValidPool.V4IPs) + require.NotNil(t, dualValidPool.V4Released) + require.NotNil(t, dualValidPool.V6Released) + require.NotNil(t, dualValidPool.V4Using) + require.NotNil(t, dualValidPool.V6Using) + + require.Equal(t, dualValidPool.V4IPs.String(), "10.0.0.30,10.0.0.80") + require.Equal(t, dualValidPool.V6IPs.String(), "2001:db8::30,2001:db8::80") + require.Equal(t, dualValidPool.V4Free.String(), "10.0.0.30,10.0.0.80") + require.Equal(t, dualValidPool.V6Free.String(), "2001:db8::30,2001:db8::80") + require.Equal(t, dualValidPool.V4Available.String(), "10.0.0.30,10.0.0.80") + require.Equal(t, dualValidPool.V6Available.String(), "2001:db8::30,2001:db8::80") + require.Equal(t, dualValidPool.V4Reserved.String(), "") + require.Equal(t, dualValidPool.V6Reserved.String(), "") + require.Equal(t, dualValidPool.V4Released.String(), "") + require.Equal(t, dualValidPool.V6Released.String(), "") + require.Equal(t, dualValidPool.V4Using.String(), "") + require.Equal(t, dualValidPool.V6Using.String(), "") + + // check dualstack invalid pool + dualInvalidPoolName := "dualInvalidPool" + invalidDualIPs := []string{"10.0.0.31", "10.0.0.256", "2001:db8::31", "2001:db8::79"} + err = subnet.AddOrUpdateIPPool(dualInvalidPoolName, invalidDualIPs) + require.Error(t, err) + require.Nil(t, subnet.IPPools[dualInvalidPoolName]) + invalidDualIPs = []string{"10.0.0.31", "10.0.0.25", "2001:db8::31", "2001:db8::g9"} + err = subnet.AddOrUpdateIPPool(dualInvalidPoolName, invalidDualIPs) + require.Error(t, err) + require.Nil(t, subnet.IPPools[dualInvalidPoolName]) + + // check dualstack different pool has the same ip + dualConflictPoolName := "dualConflictPool" + conflictDualIPs := []string{"10.0.0.30", "10.0.0.92", "2001:db8::35", "2001:db8::92"} + err = subnet.AddOrUpdateIPPool(dualConflictPoolName, conflictDualIPs) + require.Error(t, err) + require.Nil(t, subnet.IPPools[dualConflictPoolName]) + conflictDualIPs = []string{"10.0.0.30", "10.0.0.93", "2001:db8::30", "2001:db8::92"} + err = subnet.AddOrUpdateIPPool(dualConflictPoolName, conflictDualIPs) + require.Error(t, err) + require.Nil(t, subnet.IPPools[dualConflictPoolName]) + + // re check default pool + defaultPool = subnet.IPPools[""] + require.NotNil(t, defaultPool) + require.NotNil(t, defaultPool.V4IPs) + require.NotNil(t, defaultPool.V6IPs) + require.NotNil(t, defaultPool.V4Free) + require.NotNil(t, defaultPool.V6Free) + require.NotNil(t, defaultPool.V4Available) + require.NotNil(t, defaultPool.V6Available) + require.NotNil(t, defaultPool.V4Reserved) + require.NotNil(t, defaultPool.V6Reserved) + require.NotNil(t, defaultPool.V4IPs) + require.NotNil(t, defaultPool.V4IPs) + require.NotNil(t, defaultPool.V4Released) + require.NotNil(t, defaultPool.V6Released) + require.NotNil(t, defaultPool.V4Using) + require.NotNil(t, defaultPool.V6Using) + + require.Equal(t, defaultPool.V4IPs.String(), "10.0.0.1-10.0.0.19,10.0.0.21-10.0.0.29,10.0.0.31-10.0.0.79,10.0.0.81-10.0.0.89,10.0.0.91-10.0.0.169,10.0.0.171-10.0.0.239,10.0.0.241-10.0.0.249,10.0.0.251-10.0.255.254") + require.Equal(t, defaultPool.V6IPs.String(), "2001:db8::1-2001:db8::1f,2001:db8::21-2001:db8::2f,2001:db8::31-2001:db8::7f,2001:db8::81-2001:db8::8f,2001:db8::91-2001:db8::16f,2001:db8::171-2001:db8::23f,2001:db8::241-2001:db8::24f,2001:db8::251-2001:db8::ffff:ffff:ffff:fffe") + require.Equal(t, defaultPool.V4Free.String(), "10.0.0.1,10.0.0.3,10.0.0.5-10.0.0.19,10.0.0.21-10.0.0.29,10.0.0.31-10.0.0.79,10.0.0.81-10.0.0.89,10.0.0.91-10.0.0.99,10.0.0.101-10.0.0.169,10.0.0.171-10.0.0.239,10.0.0.241-10.0.0.249,10.0.0.251,10.0.0.255-10.0.255.254") + require.Equal(t, defaultPool.V6Free.String(), "2001:db8::1,2001:db8::3,2001:db8::5-2001:db8::1f,2001:db8::21-2001:db8::2f,2001:db8::31-2001:db8::7f,2001:db8::81-2001:db8::8f,2001:db8::91-2001:db8::ff,2001:db8::101-2001:db8::16f,2001:db8::171-2001:db8::23f,2001:db8::241-2001:db8::24f,2001:db8::251,2001:db8::255-2001:db8::ffff:ffff:ffff:fffe") + require.Equal(t, defaultPool.V4Available.String(), "10.0.0.1,10.0.0.3,10.0.0.5-10.0.0.19,10.0.0.21-10.0.0.29,10.0.0.31-10.0.0.79,10.0.0.81-10.0.0.89,10.0.0.91-10.0.0.99,10.0.0.101-10.0.0.169,10.0.0.171-10.0.0.239,10.0.0.241-10.0.0.249,10.0.0.251,10.0.0.255-10.0.255.254") + require.Equal(t, defaultPool.V6Available.String(), "2001:db8::1,2001:db8::3,2001:db8::5-2001:db8::1f,2001:db8::21-2001:db8::2f,2001:db8::31-2001:db8::7f,2001:db8::81-2001:db8::8f,2001:db8::91-2001:db8::ff,2001:db8::101-2001:db8::16f,2001:db8::171-2001:db8::23f,2001:db8::241-2001:db8::24f,2001:db8::251,2001:db8::255-2001:db8::ffff:ffff:ffff:fffe") + require.Equal(t, defaultPool.V4Reserved.String(), "10.0.0.2,10.0.0.4,10.0.0.100,10.0.0.252-10.0.0.254") + require.Equal(t, defaultPool.V6Reserved.String(), "2001:db8::2,2001:db8::4,2001:db8::100,2001:db8::252-2001:db8::254") + require.Equal(t, defaultPool.V4Released.String(), "") + require.Equal(t, defaultPool.V6Released.String(), "") + require.Equal(t, defaultPool.V4Using.String(), "") + require.Equal(t, defaultPool.V6Using.String(), "") +} + +func TestSubnetRemoveIPPool(t *testing.T) { + excludeIps := []string{ + "10.0.0.2", "10.0.0.4", "10.0.0.100", + "10.0.0.252", "10.0.0.253", "10.0.0.254", + "2001:db8::2", "2001:db8::4", "2001:db8::100", + "2001:db8::252", "2001:db8::253", "2001:db8::254", + } + subnetName := "dualSubnet" + subnet, err := NewSubnet(subnetName, "10.0.0.0/16,2001:db8::/64", excludeIps) + require.NoError(t, err) + // check default pool + defaultPool := subnet.IPPools[""] + require.NotNil(t, defaultPool) + require.NotNil(t, defaultPool.V4IPs) + require.NotNil(t, defaultPool.V6IPs) + require.NotNil(t, defaultPool.V4Free) + require.NotNil(t, defaultPool.V6Free) + require.NotNil(t, defaultPool.V4Available) + require.NotNil(t, defaultPool.V6Available) + require.NotNil(t, defaultPool.V4Reserved) + require.NotNil(t, defaultPool.V6Reserved) + require.NotNil(t, defaultPool.V4IPs) + require.NotNil(t, defaultPool.V4IPs) + require.NotNil(t, defaultPool.V4Released) + require.NotNil(t, defaultPool.V6Released) + require.NotNil(t, defaultPool.V4Using) + require.NotNil(t, defaultPool.V6Using) + require.Equal(t, defaultPool.V4IPs.String(), "10.0.0.1-10.0.255.254") + require.Equal(t, defaultPool.V6IPs.String(), "2001:db8::1-2001:db8::ffff:ffff:ffff:fffe") + require.Equal(t, defaultPool.V4Free.String(), "10.0.0.1,10.0.0.3,10.0.0.5-10.0.0.99,10.0.0.101-10.0.0.251,10.0.0.255-10.0.255.254") + require.Equal(t, defaultPool.V6Free.String(), "2001:db8::1,2001:db8::3,2001:db8::5-2001:db8::ff,2001:db8::101-2001:db8::251,2001:db8::255-2001:db8::ffff:ffff:ffff:fffe") + require.Equal(t, defaultPool.V4Available.String(), "10.0.0.1,10.0.0.3,10.0.0.5-10.0.0.99,10.0.0.101-10.0.0.251,10.0.0.255-10.0.255.254") + require.Equal(t, defaultPool.V6Available.String(), "2001:db8::1,2001:db8::3,2001:db8::5-2001:db8::ff,2001:db8::101-2001:db8::251,2001:db8::255-2001:db8::ffff:ffff:ffff:fffe") + require.Equal(t, defaultPool.V4Reserved.String(), "10.0.0.2,10.0.0.4,10.0.0.100,10.0.0.252-10.0.0.254") + require.Equal(t, defaultPool.V6Reserved.String(), "2001:db8::2,2001:db8::4,2001:db8::100,2001:db8::252-2001:db8::254") + require.Equal(t, defaultPool.V4Released.String(), "") + require.Equal(t, defaultPool.V6Released.String(), "") + require.Equal(t, defaultPool.V4Using.String(), "") + require.Equal(t, defaultPool.V6Using.String(), "") + // check dualstack valid pool + dualValidPoolName := "dualValidPool" + validDualIPs := []string{"10.0.0.30", "10.0.0.80", "2001:db8::30", "2001:db8::80"} + err = subnet.AddOrUpdateIPPool(dualValidPoolName, validDualIPs) + require.NoError(t, err) + require.NotNil(t, subnet.IPPools[dualValidPoolName]) + _, ok := subnet.IPPools[dualValidPoolName] + require.True(t, ok) + require.Equal(t, 2, len(subnet.IPPools)) + // remove dualValidPool + subnet.RemoveIPPool(dualValidPoolName) + require.Nil(t, subnet.IPPools[dualValidPoolName]) + require.Equal(t, 1, len(subnet.IPPools)) + // recheck default pool + defaultPool = subnet.IPPools[""] + require.NotNil(t, defaultPool) + require.NotNil(t, defaultPool.V4IPs) + require.NotNil(t, defaultPool.V6IPs) + require.NotNil(t, defaultPool.V4Free) + require.NotNil(t, defaultPool.V6Free) + require.NotNil(t, defaultPool.V4Available) + require.NotNil(t, defaultPool.V6Available) + require.NotNil(t, defaultPool.V4Reserved) + require.NotNil(t, defaultPool.V6Reserved) + require.NotNil(t, defaultPool.V4IPs) + require.NotNil(t, defaultPool.V4IPs) + require.NotNil(t, defaultPool.V4Released) + require.NotNil(t, defaultPool.V6Released) + require.NotNil(t, defaultPool.V4Using) + require.NotNil(t, defaultPool.V6Using) + require.Equal(t, defaultPool.V4IPs.String(), "10.0.0.1-10.0.0.29,10.0.0.31-10.0.0.79,10.0.0.81-10.0.255.254") + require.Equal(t, defaultPool.V6IPs.String(), "2001:db8::1-2001:db8::2f,2001:db8::31-2001:db8::7f,2001:db8::81-2001:db8::ffff:ffff:ffff:fffe") + require.Equal(t, defaultPool.V4Free.String(), "10.0.0.1,10.0.0.3,10.0.0.5-10.0.0.99,10.0.0.101-10.0.0.251,10.0.0.255-10.0.255.254") + require.Equal(t, defaultPool.V6Free.String(), "2001:db8::1,2001:db8::3,2001:db8::5-2001:db8::ff,2001:db8::101-2001:db8::251,2001:db8::255-2001:db8::ffff:ffff:ffff:fffe") + require.Equal(t, defaultPool.V4Available.String(), "10.0.0.1,10.0.0.3,10.0.0.5-10.0.0.99,10.0.0.101-10.0.0.251,10.0.0.255-10.0.255.254") + require.Equal(t, defaultPool.V6Available.String(), "2001:db8::1,2001:db8::3,2001:db8::5-2001:db8::ff,2001:db8::101-2001:db8::251,2001:db8::255-2001:db8::ffff:ffff:ffff:fffe") + require.Equal(t, defaultPool.V4Reserved.String(), "10.0.0.2,10.0.0.4,10.0.0.100,10.0.0.252-10.0.0.254") + require.Equal(t, defaultPool.V6Reserved.String(), "2001:db8::2,2001:db8::4,2001:db8::100,2001:db8::252-2001:db8::254") + require.Equal(t, defaultPool.V4Released.String(), "") + require.Equal(t, defaultPool.V6Released.String(), "") + require.Equal(t, defaultPool.V4Using.String(), "") + require.Equal(t, defaultPool.V6Using.String(), "") + + // remove dualValidPool + subnet.RemoveIPPool(dualValidPoolName) + require.Nil(t, subnet.IPPools[dualValidPoolName]) + require.Equal(t, 1, len(subnet.IPPools)) +} + +func TestSubnetIPPoolStatistics(t *testing.T) { + excludeIps := []string{ + "10.0.0.2", "10.0.0.4", "10.0.0.100", + "10.0.0.252", "10.0.0.253", "10.0.0.254", + "2001:db8::2", "2001:db8::4", "2001:db8::100", + "2001:db8::252", "2001:db8::253", "2001:db8::254", + } + subnetName := "dualSubnet" + subnet, err := NewSubnet(subnetName, "10.0.0.0/16,2001:db8::/64", excludeIps) + require.NoError(t, err) + + // check V4 valid pool + v4ValidPoolName := "v4ValidPool" + validV4IPs := []string{"10.0.0.20", "10.0.0.90", "10.0.0.170", "10.0.0.240", "10.0.0.250"} + err = subnet.AddOrUpdateIPPool(v4ValidPoolName, validV4IPs) + require.NoError(t, err) + v4a, v4u, v6a, v6u, v4as, v4us, v6as, v6us := subnet.IPPoolStatistics(v4ValidPoolName) + require.Equal(t, v4a.String(), "5") + require.Empty(t, v4u) + require.Empty(t, v6a) + require.Empty(t, v6u) + require.Equal(t, v4as, "10.0.0.20,10.0.0.90,10.0.0.170,10.0.0.240,10.0.0.250") + require.Empty(t, v4us) + require.Empty(t, v6as) + require.Empty(t, v6us) + + // check V6 valid pool + v6ValidPoolName := "v6ValidPool" + validV6IPs := []string{"2001:db8::20", "2001:db8::90", "2001:db8::170", "2001:db8::240", "2001:db8::250"} + err = subnet.AddOrUpdateIPPool(v6ValidPoolName, validV6IPs) + require.NoError(t, err) + v4a, v4u, v6a, v6u, v4as, v4us, v6as, v6us = subnet.IPPoolStatistics(v6ValidPoolName) + require.Empty(t, v4a) + require.Empty(t, v4u) + require.Equal(t, v6a.String(), "5") + require.Empty(t, v6u) + require.Empty(t, v4as) + require.Empty(t, v4us) + require.Equal(t, v6as, "2001:db8::20,2001:db8::90,2001:db8::170,2001:db8::240,2001:db8::250") + require.Empty(t, v6us) + + // check dualstack valid pool + dualValidPoolName := "dualValidPool" + validDualIPs := []string{"10.0.0.30", "10.0.0.80", "2001:db8::30", "2001:db8::80"} + err = subnet.AddOrUpdateIPPool(dualValidPoolName, validDualIPs) + require.NoError(t, err) + v4a, v4u, v6a, v6u, v4as, v4us, v6as, v6us = subnet.IPPoolStatistics(dualValidPoolName) + require.Equal(t, v4a.String(), "2") + require.Empty(t, v4u) + require.Equal(t, v6a.String(), "2") + require.Empty(t, v6u) + require.Equal(t, v4as, "10.0.0.30,10.0.0.80") + require.Empty(t, v4us) + require.Equal(t, v6as, "2001:db8::30,2001:db8::80") + require.Empty(t, v6us) + + // check not exist pool + notExistPoolName := "notExistPool" + v4a, v4u, v6a, v6u, v4as, v4us, v6as, v6us = subnet.IPPoolStatistics(notExistPoolName) + require.Empty(t, v4a) + require.Empty(t, v4u) + require.Empty(t, v6a) + require.Empty(t, v6u) + require.Empty(t, v4as) + require.Empty(t, v4us) + require.Empty(t, v6as) + require.Empty(t, v6us) +} diff --git a/pkg/ovn_ic_controller/ovn_ic_controller.go b/pkg/ovn_ic_controller/ovn_ic_controller.go index 9a86e65957b..3757862ef77 100644 --- a/pkg/ovn_ic_controller/ovn_ic_controller.go +++ b/pkg/ovn_ic_controller/ovn_ic_controller.go @@ -356,10 +356,10 @@ func (c *Controller) acquireLrpAddress(ts string) (string, error) { var ips []string v4Cidr, v6Cidr := util.SplitStringIP(cidr) if v4Cidr != "" { - ips = append(ips, util.GenerateRandomV4IP(v4Cidr)) + ips = append(ips, util.GenerateRandomIP(v4Cidr)) } if v6Cidr != "" { - ips = append(ips, util.GenerateRandomV6IP(v6Cidr)) + ips = append(ips, util.GenerateRandomIP(v6Cidr)) } random = strings.Join(ips, ",") // find a free address diff --git a/pkg/ovs/ovn-nb-acl_test.go b/pkg/ovs/ovn-nb-acl_test.go index f1c29a7924b..cdd98ea061c 100644 --- a/pkg/ovs/ovn-nb-acl_test.go +++ b/pkg/ovs/ovn-nb-acl_test.go @@ -360,9 +360,6 @@ func (suite *OvnClientTestSuite) testCreateNodeACL() { t.Parallel() ovnClient := suite.ovnClient - pgName := "test_create_node_acl_pg" - nodeIP := "192.168.20.3" - joinIP := "100.64.0.2,fd00:100:64::2" checkACL := func(pg *ovnnb.PortGroup, direction, priority, match string, options map[string]string) { acl, err := ovnClient.GetACL(pg.Name, direction, priority, match, false) @@ -376,7 +373,7 @@ func (suite *OvnClientTestSuite) testCreateNodeACL() { require.Contains(t, pg.ACLs, acl.UUID) } - expect := func(pg *ovnnb.PortGroup, _ string) { + expect := func(pg *ovnnb.PortGroup, nodeIP, pgName string) { for _, ip := range strings.Split(nodeIP, ",") { protocol := util.CheckProtocol(ip) ipSuffix := "ip4" @@ -396,17 +393,41 @@ func (suite *OvnClientTestSuite) testCreateNodeACL() { } } - err := ovnClient.CreatePortGroup(pgName, nil) - require.NoError(t, err) + t.Run("create node ACL with single stack nodeIP and dual stack joinIP", func(t *testing.T) { + pgName := "test_create_node_acl_pg" + nodeIP := "192.168.20.3" + joinIP := "100.64.0.2,fd00:100:64::2" - err = ovnClient.CreateNodeACL(pgName, nodeIP, joinIP) - require.NoError(t, err) + err := ovnClient.CreatePortGroup(pgName, nil) + require.NoError(t, err) - pg, err := ovnClient.GetPortGroup(pgName, false) - require.NoError(t, err) - require.Len(t, pg.ACLs, 2) + err = ovnClient.CreateNodeACL(pgName, nodeIP, joinIP) + require.NoError(t, err) + + pg, err := ovnClient.GetPortGroup(pgName, false) + require.NoError(t, err) + require.Len(t, pg.ACLs, 2) + + expect(pg, nodeIP, pgName) + }) + + t.Run("create node ACL with dual stack nodeIP and join IP", func(t *testing.T) { + pgName := "test-pg-overlap" + nodeIP := "192.168.20.4,fd00::4" + joinIP := "100.64.0.3,fd00:100:64::3" + + err := ovnClient.CreatePortGroup(pgName, nil) + require.NoError(t, err) - expect(pg, nodeIP) + err = ovnClient.CreateNodeACL(pgName, nodeIP, joinIP) + require.NoError(t, err) + + pg, err := ovnClient.GetPortGroup(pgName, false) + require.NoError(t, err) + require.Len(t, pg.ACLs, 4) + + expect(pg, nodeIP, pgName) + }) } func (suite *OvnClientTestSuite) testCreateSgDenyAllACL() { @@ -2145,3 +2166,89 @@ func (suite *OvnClientTestSuite) testNewAnpACLMatch() { }) } } + +func (suite *OvnClientTestSuite) testCreateBareACL() { + t := suite.T() + t.Parallel() + + ovnClient := suite.ovnClient + + t.Run("create bare ACL successfully", func(t *testing.T) { + err := ovnClient.CreateBareACL("test-parent", "from-lport", "1000", "ip4.src == 10.0.0.1", "allow") + require.NoError(t, err) + }) + + t.Run("create bare ACL with empty match", func(t *testing.T) { + err := ovnClient.CreateBareACL("test-parent", "from-lport", "1000", "", "allow") + require.Error(t, err) + require.Contains(t, err.Error(), "new acl direction from-lport priority 1000 match") + }) +} + +func (suite *OvnClientTestSuite) testUpdateAnpRuleACLOps() { + t := suite.T() + t.Parallel() + + ovnClient := suite.ovnClient + + expect := func(row ovsdb.Row, action, direction, match, priority string) { + intPriority, err := strconv.Atoi(priority) + require.NoError(t, err) + require.Equal(t, action, row["action"]) + require.Equal(t, direction, row["direction"]) + require.Equal(t, match, row["match"]) + require.Equal(t, intPriority, row["priority"]) + } + + t.Run("ingress ACL for ANP", func(t *testing.T) { + pgName := "test-pg-ingress" + asName := "test-as-ingress" + protocol := "tcp" + aclName := "test-acl" + priority := 1000 + aclAction := ovnnb.ACLActionAllow + logACLActions := []ovnnb.ACLAction{ovnnb.ACLActionAllow} + rulePorts := []v1alpha1.AdminNetworkPolicyPort{} + isIngress := true + isBanp := false + + err := ovnClient.CreatePortGroup(pgName, nil) + require.NoError(t, err) + ops, err := ovnClient.UpdateAnpRuleACLOps(pgName, asName, protocol, aclName, priority, aclAction, logACLActions, rulePorts, isIngress, isBanp) + require.NoError(t, err) + require.NotEmpty(t, ops) + expect(ops[0].Row, ovnnb.ACLActionAllow, ovnnb.ACLDirectionToLport, fmt.Sprintf("outport == @%s && ip && ip4.src == $%s", pgName, asName), "1000") + }) + + t.Run("egress ACL for BANP", func(t *testing.T) { + pgName := "test-pg-egress" + asName := "test-as-egress" + protocol := "udp" + aclName := "test-acl" + priority := 2000 + aclAction := ovnnb.ACLActionDrop + logACLActions := []ovnnb.ACLAction{ovnnb.ACLActionDrop} + rulePorts := []v1alpha1.AdminNetworkPolicyPort{} + isIngress := false + isBanp := true + + err := ovnClient.CreatePortGroup(pgName, nil) + require.NoError(t, err) + ops, err := ovnClient.UpdateAnpRuleACLOps(pgName, asName, protocol, aclName, priority, aclAction, logACLActions, rulePorts, isIngress, isBanp) + require.NoError(t, err) + require.NotEmpty(t, ops) + expect(ops[0].Row, ovnnb.ACLActionDrop, ovnnb.ACLDirectionFromLport, fmt.Sprintf("inport == @%s && ip && ip4.dst == $%s", pgName, asName), "2000") + }) +} + +func (suite *OvnClientTestSuite) testUpdateACL() { + t := suite.T() + + ovnClient := suite.ovnClient + + t.Run("update ACL with nil input", func(t *testing.T) { + err := ovnClient.UpdateACL(nil) + require.Error(t, err) + require.Contains(t, err.Error(), "address_set is nil") + }) +} diff --git a/pkg/ovs/ovn-nb-address_set_test.go b/pkg/ovs/ovn-nb-address_set_test.go index eb29d06fc25..5bd6af7b7dd 100644 --- a/pkg/ovs/ovn-nb-address_set_test.go +++ b/pkg/ovs/ovn-nb-address_set_test.go @@ -44,6 +44,27 @@ func (suite *OvnClientTestSuite) testCreateAddressSet() { }) require.Error(t, err) }) + + t.Run("create address set that already exists", func(t *testing.T) { + asName := "existing_address_set" + err := ovnClient.CreateAddressSet(asName, nil) + require.NoError(t, err) + + // Attempt to create the same address set again + err = ovnClient.CreateAddressSet(asName, nil) + require.NoError(t, err) + + // Verify that only one address set exists + ass, err := ovnClient.ListAddressSets(nil) + require.NoError(t, err) + count := 0 + for _, as := range ass { + if as.Name == asName { + count++ + } + } + require.Equal(t, 1, count) + }) } func (suite *OvnClientTestSuite) testAddressSetUpdateAddress() { @@ -86,6 +107,62 @@ func (suite *OvnClientTestSuite) testAddressSetUpdateAddress() { require.NoError(t, err) require.Empty(t, as.Addresses) }) + + t.Run("update with mixed IPv4 and IPv6 addresses", func(t *testing.T) { + addresses := []string{"192.168.1.1", "2001:db8::1", "10.0.0.1", "fe80::1"} + err := ovnClient.AddressSetUpdateAddress(asName, addresses...) + require.NoError(t, err) + + as, err := ovnClient.GetAddressSet(asName, false) + require.NoError(t, err) + require.ElementsMatch(t, addresses, as.Addresses) + }) + + t.Run("update with CIDR notation", func(t *testing.T) { + addresses := []string{"192.168.1.0/24", "2001:db8::/64"} + err := ovnClient.AddressSetUpdateAddress(asName, addresses...) + require.NoError(t, err) + + as, err := ovnClient.GetAddressSet(asName, false) + require.NoError(t, err) + require.ElementsMatch(t, []string{"192.168.1.0/24", "2001:db8::/64"}, as.Addresses) + }) + + t.Run("update with duplicate addresses", func(t *testing.T) { + addresses := []string{"192.168.1.1", "192.168.1.1", "2001:db8::1", "2001:db8::1"} + err := ovnClient.AddressSetUpdateAddress(asName, addresses...) + require.NoError(t, err) + + as, err := ovnClient.GetAddressSet(asName, false) + require.NoError(t, err) + require.ElementsMatch(t, []string{"192.168.1.1", "2001:db8::1"}, as.Addresses) + }) + + t.Run("update with invalid CIDR", func(t *testing.T) { + addresses := []string{"192.168.1.1", "invalid_cidr", "2001:db8::1"} + err := ovnClient.AddressSetUpdateAddress(asName, addresses...) + require.NoError(t, err) + + as, err := ovnClient.GetAddressSet(asName, false) + require.NoError(t, err) + require.ElementsMatch(t, []string{"192.168.1.1", "invalid_cidr", "2001:db8::1"}, as.Addresses) + }) + + t.Run("update with empty address list", func(t *testing.T) { + err := ovnClient.AddressSetUpdateAddress(asName) + require.NoError(t, err) + + as, err := ovnClient.GetAddressSet(asName, false) + require.NoError(t, err) + require.Empty(t, as.Addresses) + }) + + t.Run("update non-existent address set", func(t *testing.T) { + nonExistentAS := "non_existent_as" + err := ovnClient.AddressSetUpdateAddress(nonExistentAS, "192.168.1.1") + require.Error(t, err) + require.Contains(t, err.Error(), "get address set") + }) } func (suite *OvnClientTestSuite) testDeleteAddressSet() { @@ -146,6 +223,10 @@ func (suite *OvnClientTestSuite) testDeleteAddressSets() { ass, err := ovnClient.ListAddressSets(externalIDs) require.NoError(t, err) require.Empty(t, ass) + + // delete address sets with empty externalIDs + err = ovnClient.DeleteAddressSets(map[string]string{}) + require.NoError(t, err) } func (suite *OvnClientTestSuite) testListAddressSets() { @@ -239,3 +320,16 @@ func (suite *OvnClientTestSuite) testAddressSetFilter() { require.False(t, out) }) } + +func (suite *OvnClientTestSuite) testUpdateAddressSet() { + t := suite.T() + t.Parallel() + + ovnClient := suite.ovnClient + + t.Run("update with nil address set", func(t *testing.T) { + err := ovnClient.UpdateAddressSet(nil) + require.Error(t, err) + require.Contains(t, err.Error(), "address_set is nil") + }) +} diff --git a/pkg/ovs/ovn-nb-bfd_test.go b/pkg/ovs/ovn-nb-bfd_test.go index 441af1b101d..fd9df258cc6 100644 --- a/pkg/ovs/ovn-nb-bfd_test.go +++ b/pkg/ovs/ovn-nb-bfd_test.go @@ -3,6 +3,8 @@ package ovs import ( "testing" + "github.com/kubeovn/kube-ovn/pkg/ovsdb/ovnnb" + "github.com/scylladb/go-set/strset" "github.com/stretchr/testify/require" ) @@ -12,13 +14,14 @@ func (suite *OvnClientTestSuite) testCreateBFD() { t.Parallel() ovnClient := suite.ovnClient - lrpName := "test-create-bfd" dstIP := "192.168.124.1" minRx, minTx, detectMult := 101, 102, 19 t.Run("create BFD", func(t *testing.T) { t.Parallel() + lrpName := "test-create-bfd" + bfd, err := ovnClient.CreateBFD(lrpName, dstIP, minRx, minTx, detectMult) require.NoError(t, err) require.NotNil(t, bfd) @@ -31,6 +34,25 @@ func (suite *OvnClientTestSuite) testCreateBFD() { require.Equal(t, minTx, *bfd.MinTx) require.Equal(t, detectMult, *bfd.DetectMult) }) + + t.Run("create BFD with existing entry", func(t *testing.T) { + t.Parallel() + + lrpName := "test-create-existing-bfd" + + bfd1, err := ovnClient.CreateBFD(lrpName, dstIP, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd1) + + bfd2, err := ovnClient.CreateBFD(lrpName, dstIP, minRx+1, minTx+1, detectMult+1) + require.NoError(t, err) + require.NotNil(t, bfd2) + require.Equal(t, bfd1, bfd2) + require.Equal(t, bfd1.UUID, bfd2.UUID) + require.Equal(t, minRx, *bfd2.MinRx) + require.Equal(t, minTx, *bfd2.MinTx) + require.Equal(t, detectMult, *bfd2.DetectMult) + }) } func (suite *OvnClientTestSuite) testListBFD() { @@ -115,4 +137,511 @@ func (suite *OvnClientTestSuite) testDeleteBFD() { require.NoError(t, err) require.Len(t, bfdList, 0) }) + + t.Run("delete non-existent BFD", func(t *testing.T) { + t.Parallel() + + err := ovnClient.DeleteBFD(lrpName, "192.168.124.17") + require.NoError(t, err) + }) +} + +func (suite *OvnClientTestSuite) testListDownBFDs() { + t := suite.T() + t.Parallel() + + ovnClient := suite.ovnClient + lrpName := "test-list-down-bfd" + dstIP1 := "192.168.124.6" + dstIP2 := "192.168.124.7" + dstIP3 := "192.168.124.8" + minRx, minTx, detectMult := 101, 102, 19 + + t.Run("list down BFDs", func(t *testing.T) { + t.Parallel() + + bfd1, err := ovnClient.CreateBFD(lrpName, dstIP1, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd1) + + bfd2, err := ovnClient.CreateBFD(lrpName, dstIP2, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd2) + + bfd3, err := ovnClient.CreateBFD(lrpName, dstIP3, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd3) + + // Set BFD statuses + downStatus := ovnnb.BFDStatusDown + adminDownStatus := ovnnb.BFDStatusAdminDown + upStatus := ovnnb.BFDStatusUp + + bfd1.Status = &downStatus + bfd2.Status = &adminDownStatus + bfd3.Status = &upStatus + + err = ovnClient.UpdateBFD(bfd1) + require.NoError(t, err) + err = ovnClient.UpdateBFD(bfd2) + require.NoError(t, err) + err = ovnClient.UpdateBFD(bfd3) + require.NoError(t, err) + + // Test listing down BFDs for specific IP + downBFDs, err := ovnClient.ListDownBFDs(dstIP1) + require.NoError(t, err) + require.Len(t, downBFDs, 1) + require.Equal(t, bfd1.UUID, downBFDs[0].UUID) + + downBFDs, err = ovnClient.ListDownBFDs(dstIP2) + require.NoError(t, err) + require.Len(t, downBFDs, 1) + + downBFDs, err = ovnClient.ListDownBFDs(dstIP3) + require.NoError(t, err) + require.Len(t, downBFDs, 0) + + // Test listing down BFDs for non-existent IP + nonExistentBFDs, err := ovnClient.ListDownBFDs("192.168.124.9") + require.NoError(t, err) + require.Len(t, nonExistentBFDs, 0) + }) + + t.Run("list down BFDs with no down BFDs", func(t *testing.T) { + t.Parallel() + + // Create a BFD with UP status + bfd, err := ovnClient.CreateBFD(lrpName, "192.168.124.10", minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd) + + upStatus := ovnnb.BFDStatusUp + bfd.Status = &upStatus + err = ovnClient.UpdateBFD(bfd) + require.NoError(t, err) + + // Try to list down BFDs + downBFDs, err := ovnClient.ListDownBFDs("192.168.124.10") + require.NoError(t, err) + require.Len(t, downBFDs, 0) + }) +} + +func (suite *OvnClientTestSuite) testListUpBFDs() { + t := suite.T() + t.Parallel() + + ovnClient := suite.ovnClient + lrpName := "test-list-up-bfd" + dstIP1 := "192.168.124.11" + dstIP2 := "192.168.124.12" + dstIP3 := "192.168.124.13" + minRx, minTx, detectMult := 101, 102, 19 + + t.Run("list up BFDs", func(t *testing.T) { + t.Parallel() + + bfd1, err := ovnClient.CreateBFD(lrpName, dstIP1, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd1) + + bfd2, err := ovnClient.CreateBFD(lrpName, dstIP2, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd2) + + bfd3, err := ovnClient.CreateBFD(lrpName, dstIP3, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd3) + + upStatus := ovnnb.BFDStatusUp + downStatus := ovnnb.BFDStatusDown + adminDownStatus := ovnnb.BFDStatusAdminDown + + bfd1.Status = &upStatus + bfd2.Status = &downStatus + bfd3.Status = &adminDownStatus + + err = ovnClient.UpdateBFD(bfd1) + require.NoError(t, err) + err = ovnClient.UpdateBFD(bfd2) + require.NoError(t, err) + err = ovnClient.UpdateBFD(bfd3) + require.NoError(t, err) + + upBFDs, err := ovnClient.ListUpBFDs(dstIP1) + require.NoError(t, err) + require.Len(t, upBFDs, 1) + require.Equal(t, bfd1.UUID, upBFDs[0].UUID) + + upBFDs, err = ovnClient.ListUpBFDs(dstIP2) + require.NoError(t, err) + require.Len(t, upBFDs, 0) + + upBFDs, err = ovnClient.ListUpBFDs(dstIP3) + require.NoError(t, err) + require.Len(t, upBFDs, 0) + }) + + t.Run("list up BFDs with non-existent IP", func(t *testing.T) { + t.Parallel() + + upBFDs, err := ovnClient.ListUpBFDs("192.168.124.14") + require.NoError(t, err) + require.Len(t, upBFDs, 0) + }) +} + +func (suite *OvnClientTestSuite) testIsLrpBfdUp() { + t := suite.T() + t.Parallel() + + ovnClient := suite.ovnClient + + dstIP := "192.168.124.15" + minRx, minTx, detectMult := 101, 102, 19 + + t.Run("BFD is up", func(t *testing.T) { + t.Parallel() + + lrpName := "test-is-lrp-bfd-up" + bfd, err := ovnClient.CreateBFD(lrpName, dstIP, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd) + + upStatus := ovnnb.BFDStatusUp + bfd.Status = &upStatus + err = ovnClient.UpdateBFD(bfd) + require.NoError(t, err) + + isUp, err := ovnClient.isLrpBfdUp(lrpName, dstIP) + require.NoError(t, err) + require.True(t, isUp) + }) + + t.Run("BFD is down", func(t *testing.T) { + t.Parallel() + + lrpName := "test-is-lrp-bfd-down" + bfd, err := ovnClient.CreateBFD(lrpName, dstIP, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd) + + downStatus := ovnnb.BFDStatusDown + bfd.Status = &downStatus + err = ovnClient.UpdateBFD(bfd) + require.NoError(t, err) + + isUp, err := ovnClient.isLrpBfdUp(lrpName, dstIP) + require.Error(t, err) + require.False(t, isUp) + require.Contains(t, err.Error(), "status is down") + }) + + t.Run("BFD status is nil", func(t *testing.T) { + t.Parallel() + + lrpName := "test-is-lrp-bfd-status-nil" + bfd, err := ovnClient.CreateBFD(lrpName, dstIP, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd) + + bfd.Status = nil + err = ovnClient.UpdateBFD(bfd) + require.NoError(t, err) + + isUp, err := ovnClient.isLrpBfdUp(lrpName, dstIP) + require.Error(t, err) + require.False(t, isUp) + require.Contains(t, err.Error(), "status is nil") + }) + + t.Run("No BFD exists", func(t *testing.T) { + t.Parallel() + + lrpName := "test-is-lrp-bfd-none" + isUp, err := ovnClient.isLrpBfdUp(lrpName, "192.168.124.16") + require.NoError(t, err) + require.True(t, isUp) + }) +} + +func (suite *OvnClientTestSuite) testBfdAddL3HAHandler() { + t := suite.T() + t.Parallel() + + ovnClient := suite.ovnClient + + t.Run("BFD status is nil", func(t *testing.T) { + t.Parallel() + + lrpName := "test-bfd-add-l3ha-handler-nil" + dstIP := "192.168.124.19" + minRx, minTx, detectMult := 101, 102, 19 + + bfd, err := ovnClient.CreateBFD(lrpName, dstIP, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd) + + bfd.Status = nil + err = ovnClient.UpdateBFD(bfd) + require.NoError(t, err) + + ovnClient.bfdAddL3HAHandler(ovnnb.BFDTable, bfd) + + updatedBfd, err := ovnClient.ListBFDs(lrpName, dstIP) + require.NoError(t, err) + require.Nil(t, updatedBfd[0].Status) + }) + + t.Run("BFD status is down", func(t *testing.T) { + t.Parallel() + + lrpName := "test-bfd-add-l3ha-handler-down" + dstIP := "192.168.124.20" + minRx, minTx, detectMult := 101, 102, 19 + + bfd, err := ovnClient.CreateBFD(lrpName, dstIP, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd) + + downStatus := ovnnb.BFDStatusDown + bfd.Status = &downStatus + err = ovnClient.UpdateBFD(bfd) + require.NoError(t, err) + + ovnClient.bfdAddL3HAHandler(ovnnb.BFDTable, bfd) + + updatedBfd, err := ovnClient.ListBFDs(lrpName, dstIP) + require.NoError(t, err) + require.NotNil(t, updatedBfd[0].Status) + require.Equal(t, ovnnb.BFDStatusDown, *updatedBfd[0].Status) + }) + + t.Run("BFD status is already up", func(t *testing.T) { + t.Parallel() + + lrpName := "test-bfd-add-l3ha-handler-up" + dstIP := "192.168.124.21" + minRx, minTx, detectMult := 101, 102, 19 + + bfd, err := ovnClient.CreateBFD(lrpName, dstIP, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd) + + upStatus := ovnnb.BFDStatusUp + bfd.Status = &upStatus + err = ovnClient.UpdateBFD(bfd) + require.NoError(t, err) + + ovnClient.bfdAddL3HAHandler(ovnnb.BFDTable, bfd) + + updatedBfd, err := ovnClient.ListBFDs(lrpName, dstIP) + require.NoError(t, err) + require.NotNil(t, updatedBfd[0].Status) + require.Equal(t, ovnnb.BFDStatusUp, *updatedBfd[0].Status) + }) + + t.Run("Wrong table", func(t *testing.T) { + t.Parallel() + + lrpName := "test-bfd-add-l3ha-handler-up-wrong-table" + dstIP := "192.168.124.22" + minRx, minTx, detectMult := 101, 102, 19 + + bfd, err := ovnClient.CreateBFD(lrpName, dstIP, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd) + + ovnClient.bfdAddL3HAHandler("WrongTable", bfd) + + updatedBfd, err := ovnClient.ListBFDs(lrpName, dstIP) + require.NoError(t, err) + require.Nil(t, updatedBfd[0].Status) + }) +} + +func (suite *OvnClientTestSuite) testBfdUpdateL3HAHandler() { + t := suite.T() + t.Parallel() + + ovnClient := suite.ovnClient + + t.Run("BFD status change with wrong table", func(t *testing.T) { + t.Parallel() + + lrpName := "test-bfd-update-l3ha-handler-wrong-table" + dstIP := "192.168.124.26" + minRx, minTx, detectMult := 101, 102, 19 + + bfd, err := ovnClient.CreateBFD(lrpName, dstIP, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd) + + upStatus := ovnnb.BFDStatusUp + bfd.Status = &upStatus + err = ovnClient.UpdateBFD(bfd) + require.NoError(t, err) + + newBfd := *bfd + downStatus := ovnnb.BFDStatusDown + newBfd.Status = &downStatus + + ovnClient.bfdUpdateL3HAHandler("WrongTable", bfd, &newBfd) + }) + + t.Run("BFD status change with nil status", func(t *testing.T) { + t.Parallel() + + lrpName := "test-bfd-update-l3ha-handler-nil-status" + dstIP := "192.168.124.27" + minRx, minTx, detectMult := 101, 102, 19 + + bfd, err := ovnClient.CreateBFD(lrpName, dstIP, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd) + bfd.Status = nil + err = ovnClient.UpdateBFD(bfd) + require.NoError(t, err) + + newBfd := *bfd + downStatus := ovnnb.BFDStatusDown + newBfd.Status = &downStatus + + ovnClient.bfdUpdateL3HAHandler(ovnnb.BFDTable, bfd, &newBfd) + + updatedBfd, err := ovnClient.ListBFDs(lrpName, dstIP) + require.NoError(t, err) + require.Nil(t, updatedBfd[0].Status) + }) + + t.Run("BFD status not changed", func(t *testing.T) { + t.Parallel() + + lrpName := "test-bfd-update-l3ha-handler-same-status" + dstIP := "192.168.124.28" + minRx, minTx, detectMult := 101, 102, 19 + + bfd, err := ovnClient.CreateBFD(lrpName, dstIP, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd) + upStatus := ovnnb.BFDStatusUp + bfd.Status = &upStatus + err = ovnClient.UpdateBFD(bfd) + require.NoError(t, err) + + newBfd := *bfd + newBfd.Status = &upStatus + + ovnClient.bfdUpdateL3HAHandler(ovnnb.BFDTable, bfd, &newBfd) + }) + + t.Run("BFD status change from AdminDown to Down", func(t *testing.T) { + t.Parallel() + + lrpName := "test-bfd-update-l3ha-handler-admin-down-to-down" + dstIP := "192.168.124.23" + minRx, minTx, detectMult := 101, 102, 19 + + bfd, err := ovnClient.CreateBFD(lrpName, dstIP, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd) + + adminDownStatus := ovnnb.BFDStatusAdminDown + bfd.Status = &adminDownStatus + err = ovnClient.UpdateBFD(bfd) + require.NoError(t, err) + + newBfd := *bfd + downStatus := ovnnb.BFDStatusDown + newBfd.Status = &downStatus + + ovnClient.bfdUpdateL3HAHandler(ovnnb.BFDTable, bfd, &newBfd) + }) + + t.Run("BFD status change from Down to Up", func(t *testing.T) { + t.Parallel() + + lrpName := "test-bfd-update-l3ha-handler-down-to-up" + dstIP := "192.168.124.24" + minRx, minTx, detectMult := 101, 102, 19 + + bfd, err := ovnClient.CreateBFD(lrpName, dstIP, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd) + + downStatus := ovnnb.BFDStatusDown + bfd.Status = &downStatus + err = ovnClient.UpdateBFD(bfd) + require.NoError(t, err) + + newBfd := *bfd + upStatus := ovnnb.BFDStatusUp + newBfd.Status = &upStatus + + ovnClient.bfdUpdateL3HAHandler(ovnnb.BFDTable, bfd, &newBfd) + }) + + t.Run("BFD status change from Up to Down", func(t *testing.T) { + t.Parallel() + + lrpName := "test-bfd-update-l3ha-handler-up-to-down" + dstIP := "192.168.124.25" + minRx, minTx, detectMult := 101, 102, 19 + + bfd, err := ovnClient.CreateBFD(lrpName, dstIP, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd) + + upStatus := ovnnb.BFDStatusUp + bfd.Status = &upStatus + err = ovnClient.UpdateBFD(bfd) + require.NoError(t, err) + + newBfd := *bfd + downStatus := ovnnb.BFDStatusDown + newBfd.Status = &downStatus + + ovnClient.bfdUpdateL3HAHandler(ovnnb.BFDTable, bfd, &newBfd) + }) +} + +func (suite *OvnClientTestSuite) testBfdDelL3HAHandler() { + t := suite.T() + t.Parallel() + + ovnClient := suite.ovnClient + + t.Run("BFD deletion with wrong table", func(t *testing.T) { + t.Parallel() + + lrpName := "test-bfd-del-l3ha-handler-wrong-table" + dstIP := "192.168.124.30" + minRx, minTx, detectMult := 101, 102, 19 + + bfd, err := ovnClient.CreateBFD(lrpName, dstIP, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd) + + ovnClient.bfdDelL3HAHandler("WrongTable", bfd) + + // Verify that the BFD is not deleted + bfdList, err := ovnClient.ListBFDs(lrpName, dstIP) + require.NoError(t, err) + require.Len(t, bfdList, 1) + }) + + t.Run("BFD deletion with correct table", func(t *testing.T) { + t.Parallel() + + lrpName := "test-bfd-del-l3ha-handler-correct-table" + dstIP := "192.168.124.31" + minRx, minTx, detectMult := 101, 102, 19 + + bfd, err := ovnClient.CreateBFD(lrpName, dstIP, minRx, minTx, detectMult) + require.NoError(t, err) + require.NotNil(t, bfd) + + ovnClient.bfdDelL3HAHandler(ovnnb.BFDTable, bfd) + }) } diff --git a/pkg/ovs/ovn-nb-logical_switch_port_test.go b/pkg/ovs/ovn-nb-logical_switch_port_test.go index 3fff4abaa38..9016bbdb677 100644 --- a/pkg/ovs/ovn-nb-logical_switch_port_test.go +++ b/pkg/ovs/ovn-nb-logical_switch_port_test.go @@ -885,7 +885,7 @@ func (suite *OvnClientTestSuite) testEnablePortLayer2forward() { lspName := "test-enable-port-l2-lsp" ns := "test-enable-port-l2-ns" pod := "test-enable-port-l2-pod" - ip := util.GenerateRandomV4IP("192.168.1.0/24") + ip := util.GenerateRandomIP("192.168.1.0/24") mac := util.GenerateMac() err := ovnClient.CreateBareLogicalSwitch(lsName) diff --git a/pkg/ovs/ovn-nb-suite_test.go b/pkg/ovs/ovn-nb-suite_test.go index e8f1442e2b3..f7fc289b717 100644 --- a/pkg/ovs/ovn-nb-suite_test.go +++ b/pkg/ovs/ovn-nb-suite_test.go @@ -288,6 +288,7 @@ func (suite *OvnClientTestSuite) Test_logicalRouterPortFilter() { suite.testlogicalRouterPortFilter() } +/* bfd unit test */ func (suite *OvnClientTestSuite) Test_CreateBFD() { suite.testCreateBFD() } @@ -300,6 +301,30 @@ func (suite *OvnClientTestSuite) Test_DeleteBFD() { suite.testDeleteBFD() } +func (suite *OvnClientTestSuite) Test_ListDownBFDs() { + suite.testListDownBFDs() +} + +func (suite *OvnClientTestSuite) Test_ListUpBFDs() { + suite.testListUpBFDs() +} + +func (suite *OvnClientTestSuite) Test_isLrpBfdUp() { + suite.testIsLrpBfdUp() +} + +func (suite *OvnClientTestSuite) Test_BfdAddL3HAHandler() { + suite.testBfdAddL3HAHandler() +} + +func (suite *OvnClientTestSuite) Test_BfdUpdateL3HAHandler() { + suite.testBfdUpdateL3HAHandler() +} + +func (suite *OvnClientTestSuite) Test_BfdDelL3HAHandler() { + suite.testBfdDelL3HAHandler() +} + /* gateway_chassis unit test */ func (suite *OvnClientTestSuite) Test_CreateGatewayChassises() { suite.testCreateGatewayChassises() @@ -469,6 +494,10 @@ func (suite *OvnClientTestSuite) Test_addressSetFilter() { suite.testAddressSetFilter() } +func (suite *OvnClientTestSuite) Test_UpdateAddressSet() { + suite.testUpdateAddressSet() +} + /* acl unit test */ func (suite *OvnClientTestSuite) Test_testUpdateIngressAclOps() { suite.testUpdateIngressACLOps() @@ -558,6 +587,18 @@ func (suite *OvnClientTestSuite) Test_newAnpACLMatch() { suite.testNewAnpACLMatch() } +func (suite *OvnClientTestSuite) Test_CreateBareACL() { + suite.testCreateBareACL() +} + +func (suite *OvnClientTestSuite) Test_UpdateAnpRuleACLOps() { + suite.testUpdateAnpRuleACLOps() +} + +func (suite *OvnClientTestSuite) Test_UpdateACL() { + suite.testUpdateACL() +} + /* logical_router_policy unit test */ func (suite *OvnClientTestSuite) Test_AddLogicalRouterPolicy() { suite.testAddLogicalRouterPolicy() diff --git a/pkg/speaker/utils.go b/pkg/speaker/utils.go index 22e9e6b7b1b..7778a84d5a5 100644 --- a/pkg/speaker/utils.go +++ b/pkg/speaker/utils.go @@ -86,7 +86,7 @@ func parseRoute(route string) (string, uint32, error) { if err != nil { return "", 0, err } - prefixLen = uint32(intLen) + prefixLen = uint32(intLen) // #nosec G115 } return prefix, prefixLen, nil } diff --git a/pkg/tproxy/tproxy_tcp_linux.go b/pkg/tproxy/tproxy_tcp_linux.go index 90cd54e786f..bab981dab45 100644 --- a/pkg/tproxy/tproxy_tcp_linux.go +++ b/pkg/tproxy/tproxy_tcp_linux.go @@ -81,13 +81,14 @@ func listenTCP(device, network string, laddr *net.TCPAddr) (net.Listener, error) } }() + fd := int(fileDescriptorSource.Fd()) // #nosec G115 if device != "" { - if err = syscall.BindToDevice(int(fileDescriptorSource.Fd()), device); err != nil { + if err = syscall.BindToDevice(fd, device); err != nil { return nil, &net.OpError{Op: "listen", Net: network, Source: nil, Addr: laddr, Err: fmt.Errorf("set socket option: SO_BINDTODEVICE(%s): %w", device, err)} } } - if err = syscall.SetsockoptInt(int(fileDescriptorSource.Fd()), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil { + if err = syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil { return nil, &net.OpError{Op: "listen", Net: network, Source: nil, Addr: laddr, Err: fmt.Errorf("set socket option: IP_TRANSPARENT: %w", err)} } diff --git a/pkg/util/const.go b/pkg/util/const.go index 17f12566259..2d7af73ffad 100644 --- a/pkg/util/const.go +++ b/pkg/util/const.go @@ -170,6 +170,8 @@ const ( SRIOVResourceName = "mellanox.com/cx5_sriov_switchdev" + SriovNicType = "sriov" + InterconnectionConfig = "ovn-ic-config" ExternalGatewayConfig = "ovn-external-gw-config" InterconnectionSwitch = "ts" @@ -264,6 +266,8 @@ const ( U2OInterconnName = "u2o-interconnection.%s.%s" U2OExcludeIPAg = "%s.u2o_exclude_ip.%s" + McastQuerierName = "mcast-querier.%s" + DefaultServiceSessionStickinessTimeout = 10800 OvnSubnetGatewayIptables = "ovn-subnet-gateway" diff --git a/pkg/util/net.go b/pkg/util/net.go index 23bf0e4a8f5..bf59009a5be 100644 --- a/pkg/util/net.go +++ b/pkg/util/net.go @@ -69,51 +69,62 @@ func BigInt2Ip(ipInt *big.Int) string { func SubnetNumber(subnet string) string { _, cidr, _ := net.ParseCIDR(subnet) + maskLength, length := cidr.Mask.Size() + if maskLength+1 == length { + return "" + } return cidr.IP.String() } func SubnetBroadcast(subnet string) string { _, cidr, _ := net.ParseCIDR(subnet) - var length uint - if CheckProtocol(subnet) == kubeovnv1.ProtocolIPv4 { - length = 32 - } else { - length = 128 + ones, bits := cidr.Mask.Size() + if ones+1 == bits { + return "" } - maskLength, _ := cidr.Mask.Size() ipInt := IP2BigInt(cidr.IP.String()) - size := big.NewInt(0).Lsh(big.NewInt(1), length-uint(maskLength)) + zeros := uint(bits - ones) // #nosec G115 + size := big.NewInt(0).Lsh(big.NewInt(1), zeros) size = big.NewInt(0).Sub(size, big.NewInt(1)) return BigInt2Ip(ipInt.Add(ipInt, size)) } +// FirstIP returns first usable ip address in the subnet func FirstIP(subnet string) (string, error) { _, cidr, err := net.ParseCIDR(subnet) if err != nil { return "", fmt.Errorf("%s is not a valid cidr", subnet) } + // Handle ptp network case specially + if ones, bits := cidr.Mask.Size(); ones+1 == bits { + return cidr.IP.String(), nil + } ipInt := IP2BigInt(cidr.IP.String()) return BigInt2Ip(ipInt.Add(ipInt, big.NewInt(1))), nil } +// LastIP returns last usable ip address in the subnet func LastIP(subnet string) (string, error) { _, cidr, err := net.ParseCIDR(subnet) if err != nil { return "", fmt.Errorf("%s is not a valid cidr", subnet) } - var length uint - if CheckProtocol(subnet) == kubeovnv1.ProtocolIPv4 { - length = 32 - } else { - length = 128 - } - maskLength, _ := cidr.Mask.Size() + ipInt := IP2BigInt(cidr.IP.String()) - size := big.NewInt(0).Lsh(big.NewInt(1), length-uint(maskLength)) - size = big.NewInt(0).Sub(size, big.NewInt(2)) + size := getCIDRSize(cidr) return BigInt2Ip(ipInt.Add(ipInt, size)), nil } +func getCIDRSize(cidr *net.IPNet) *big.Int { + ones, bits := cidr.Mask.Size() + zeros := uint(bits - ones) // #nosec G115 + size := big.NewInt(0).Lsh(big.NewInt(1), zeros) + if ones+1 == bits { + return big.NewInt(0).Sub(size, big.NewInt(1)) + } + return big.NewInt(0).Sub(size, big.NewInt(2)) +} + func CIDRContainIP(cidrStr, ipStr string) bool { cidrs := strings.Split(cidrStr, ",") ips := strings.Split(ipStr, ",") @@ -121,7 +132,7 @@ func CIDRContainIP(cidrStr, ipStr string) bool { if len(cidrs) == 1 { for _, ip := range ips { if CheckProtocol(cidrStr) != CheckProtocol(ip) { - klog.Errorf("ip %s and cidr %s should be the same protocol", ip, cidrStr) + klog.Warningf("ip %q and cidr %q should be the same protocol", ip, cidrStr) return false } } @@ -140,12 +151,10 @@ func CIDRContainIP(cidrStr, ipStr string) bool { } ipAddr := net.ParseIP(ip) if ipAddr == nil { - klog.Errorf("invalid ip %s", ip) + klog.Errorf("invalid ip %q", ip) return false } - if !cidrNet.Contains(ipAddr) { - klog.Errorf("ip %s is not in cidr %s", ip, cidr) return false } } @@ -155,6 +164,10 @@ func CIDRContainIP(cidrStr, ipStr string) bool { } func CheckProtocol(address string) string { + if address == "" { + return "" + } + ips := strings.Split(address, ",") if len(ips) == 2 { IP1 := net.ParseIP(strings.Split(ips[0], "/")[0]) @@ -165,7 +178,7 @@ func CheckProtocol(address string) string { if IP2.To4() != nil && IP1.To4() == nil && IP1.To16() != nil { return kubeovnv1.ProtocolDual } - err := fmt.Errorf("invalid address %s", address) + err := fmt.Errorf("invalid address %q", address) klog.Error(err) return "" } @@ -179,44 +192,37 @@ func CheckProtocol(address string) string { } // cidr format error - err := fmt.Errorf("invalid address %s", address) + err := fmt.Errorf("invalid address %q", address) klog.Error(err) return "" } func AddressCount(network *net.IPNet) float64 { prefixLen, bits := network.Mask.Size() - if bits-prefixLen < 2 { - return 0 + // Special case handling for /31 and /32 subnets + if bits-prefixLen == 1 { + return 2 // /31 subnet + } else if bits-prefixLen == 0 { + return 1 // /32 subnet } return math.Pow(2, float64(bits-prefixLen)) - 2 } -func GenerateRandomV4IP(cidr string) string { - return genRandomIP(cidr, false) -} - -func GenerateRandomV6IP(cidr string) string { - return genRandomIP(cidr, true) -} - -func genRandomIP(cidr string, isIPv6 bool) string { - if len(strings.Split(cidr, "/")) != 2 { +func GenerateRandomIP(cidr string) string { + ip, network, err := net.ParseCIDR(cidr) + if err != nil { + klog.Errorf("failed to parse cidr %q: %v", cidr, err) return "" } - ip := strings.Split(cidr, "/")[0] - netMask, _ := strconv.Atoi(strings.Split(cidr, "/")[1]) - hostBits := 32 - netMask - if isIPv6 { - hostBits = 128 - netMask - } - add, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), uint(hostBits)-1)) + ones, bits := network.Mask.Size() + zeros := uint(bits - ones) // #nosec G115 + add, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), zeros-1)) if err != nil { - klog.Errorf("failed to generate random big int with bits %d: %v", hostBits, err) + klog.Errorf("failed to generate random big int with bits %d: %v", zeros, err) return "" } - t := big.NewInt(0).Add(IP2BigInt(ip), add) - return fmt.Sprintf("%s/%d", BigInt2Ip(t), netMask) + t := big.NewInt(0).Add(IP2BigInt(ip.String()), add) + return fmt.Sprintf("%s/%d", BigInt2Ip(t), ones) } func IPToString(ip string) string { diff --git a/pkg/util/net_test.go b/pkg/util/net_test.go index c7580ce4cc2..185cceb1a0c 100644 --- a/pkg/util/net_test.go +++ b/pkg/util/net_test.go @@ -205,6 +205,11 @@ func TestSubnetBroadcast(t *testing.T) { subnet: "192.128.23.1/15", expect: "192.129.255.255", }, + { + name: "v4/31", + subnet: "192.128.23.0/31", + expect: "", + }, { name: "v6", subnet: "ffff:ffff:ffff:ffff:ffff:0:ffff:ffff/96", @@ -238,6 +243,17 @@ func TestFirstIP(t *testing.T) { name: "controversy", subnet: "192.168.0.23/32", expect: "192.168.0.24", + }, + { + name: "base31netmask", + subnet: "192.168.0.23/31", + expect: "192.168.0.22", + err: "", + }, + { + name: "base31netmask", + subnet: "192.168.0.0/31", + expect: "192.168.0.0", err: "", }, { @@ -252,6 +268,12 @@ func TestFirstIP(t *testing.T) { expect: "ffff:ffff:ffff:ffff:ffff::1", err: "", }, + { + name: "v6127netmask", + subnet: "ffff:ffff:ffff:ffff:ffff:0:ffff:0/127", + expect: "ffff:ffff:ffff:ffff:ffff:0:ffff:0", + err: "", + }, } for _, c := range tests { t.Run(c.name, func(t *testing.T) { @@ -271,6 +293,12 @@ func TestLastIP(t *testing.T) { expect string err string }{ + { + name: "base31netmask", + subnet: "192.168.0.2/31", + expect: "192.168.0.3", + err: "", + }, { name: "base", subnet: "192.168.0.23/24", @@ -289,6 +317,12 @@ func TestLastIP(t *testing.T) { expect: "ffff:ffff:ffff:ffff:ffff:0:ffff:fffe", err: "", }, + { + name: "v6127netmask", + subnet: "ffff:ffff:ffff:ffff:ffff:0:ffff:0/127", + expect: "ffff:ffff:ffff:ffff:ffff:0:ffff:1", + err: "", + }, } for _, c := range tests { t.Run(c.name, func(t *testing.T) { @@ -309,6 +343,12 @@ func TestCIDRContainIP(t *testing.T) { ipStr string want bool }{ + { + name: "base", + cidrStr: "192.168.0.23/31", + ipStr: "192.168.0.23,192.168.0.22", + want: true, + }, { name: "base", cidrStr: "192.168.0.23/24", @@ -327,6 +367,12 @@ func TestCIDRContainIP(t *testing.T) { ipStr: "ffff:ffff:ffff:ffff:ffff:0:ffff:fffe", want: true, }, + { + name: "v6", + cidrStr: "ffff:ffff:ffff:ffff:ffff:0:ffff:4/127", + ipStr: "ffff:ffff:ffff:ffff:ffff:0:ffff:4,ffff:ffff:ffff:ffff:ffff:0:ffff:5", + want: true, + }, } for _, c := range tests { t.Run(c.name, func(t *testing.T) { @@ -395,7 +441,7 @@ func TestAddressCount(t *testing.T) { IP: net.ParseIP("192.168.1.0"), Mask: net.IPMask{255, 255, 255, 254}, }, - want: 0, + want: 2, }, } for _, c := range tests { @@ -429,14 +475,14 @@ func TestGenerateRandomV4IP(t *testing.T) { t.Run(c.name, func(t *testing.T) { _, IPNets, err := net.ParseCIDR(c.cidr) if err != nil { - ans := GenerateRandomV4IP(c.cidr) + ans := GenerateRandomIP(c.cidr) if c.want != ans { t.Errorf("%v expected %v, but %v got", c.cidr, c.want, ans) } } else { - ans := GenerateRandomV4IP(c.cidr) - if IPNets.Contains(net.ParseIP(GenerateRandomV4IP(c.cidr))) { + ans := GenerateRandomIP(c.cidr) + if IPNets.Contains(net.ParseIP(GenerateRandomIP(c.cidr))) { t.Errorf("%v expected %v, but %v got", c.cidr, c.want, ans) } @@ -468,7 +514,7 @@ func TestGenerateRandomV6IP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ip := GenerateRandomV6IP(tt.cidr) + ip := GenerateRandomIP(tt.cidr) if tt.wantErr { if ip != "" { t.Errorf("GenerateRandomV6IP(%s) = %s; want empty string", tt.cidr, ip) @@ -671,6 +717,12 @@ func TestGetGwByCidr(t *testing.T) { want: "10.16.0.1", err: "", }, + { + name: "v4", + cidr: "10.16.0.112/31", + want: "10.16.0.112", + err: "", + }, { name: "dual", cidr: "10.16.0.112/24,ffff:ffff:ffff:ffff:ffff:0:ffff:0/96", diff --git a/pkg/util/validator.go b/pkg/util/validator.go index c5af196e2b3..b4d2d25d350 100644 --- a/pkg/util/validator.go +++ b/pkg/util/validator.go @@ -334,6 +334,10 @@ func ValidateNetworkBroadcast(cidr, ip string) error { if CheckProtocol(cidrBlock) != CheckProtocol(ipAddr) { continue } + _, network, _ := net.ParseCIDR(cidrBlock) + if AddressCount(network) == 1 { + return fmt.Errorf("subnet %s is configured with /32 netmask", cidrBlock) + } ipStr := IPToString(ipAddr) if SubnetBroadcast(cidrBlock) == ipStr { diff --git a/pkg/util/validator_test.go b/pkg/util/validator_test.go index 2d3eda1b963..4124d1b36ad 100644 --- a/pkg/util/validator_test.go +++ b/pkg/util/validator_test.go @@ -476,6 +476,50 @@ func TestValidateSubnet(t *testing.T) { }, err: "ip 10.16.1 in excludeIps is not a valid address", }, + { + name: "ValidPTPSubnet", + asubnet: kubeovnv1.Subnet{ + TypeMeta: metav1.TypeMeta{Kind: "Subnet", APIVersion: "kubeovn.io/v1"}, + ObjectMeta: metav1.ObjectMeta{ + Name: "utest-ptpsubnet", + }, + Spec: kubeovnv1.SubnetSpec{ + Default: true, + Vpc: "ovn-cluster", + Protocol: kubeovnv1.ProtocolIPv4, + Namespaces: nil, + CIDRBlock: "10.16.0.0/31", + Gateway: "10.16.0.0", + ExcludeIps: []string{"10.16.0.0"}, + Provider: OvnProvider, + GatewayType: kubeovnv1.GWDistributedType, + }, + Status: kubeovnv1.SubnetStatus{}, + }, + err: "", + }, + { + name: "Invalid/32Subnet", + asubnet: kubeovnv1.Subnet{ + TypeMeta: metav1.TypeMeta{Kind: "Subnet", APIVersion: "kubeovn.io/v1"}, + ObjectMeta: metav1.ObjectMeta{ + Name: "utest-ptpsubnet", + }, + Spec: kubeovnv1.SubnetSpec{ + Default: true, + Vpc: "ovn-cluster", + Protocol: kubeovnv1.ProtocolIPv4, + Namespaces: nil, + CIDRBlock: "10.16.0.0/32", + Gateway: "10.16.0.0", + ExcludeIps: []string{"10.16.0.0"}, + Provider: OvnProvider, + GatewayType: kubeovnv1.GWDistributedType, + }, + Status: kubeovnv1.SubnetStatus{}, + }, + err: "validate gateway 10.16.0.0 for cidr 10.16.0.0/32 failed: subnet 10.16.0.0/32 is configured with /32 netmask", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -653,6 +697,12 @@ func TestValidateNetworkBroadcast(t *testing.T) { ip: "10.16.0.0", err: "10.16.0.0 is the network number ip in cidr 10.16.0.0/16", }, + { + name: "boardV4/31subnet", + cidr: "10.16.0.0/31", + ip: "", + err: "", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/test/anp/anp_test.go b/test/anp/anp_test.go new file mode 100644 index 00000000000..d159d17197e --- /dev/null +++ b/test/anp/anp_test.go @@ -0,0 +1,89 @@ +package anp + +import ( + "fmt" + "os" + "testing" + "time" + + "gopkg.in/yaml.v3" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/config" + netpolv1alpha1 "sigs.k8s.io/network-policy-api/apis/v1alpha1" + "sigs.k8s.io/network-policy-api/conformance/tests" + netpolv1config "sigs.k8s.io/network-policy-api/conformance/utils/config" + "sigs.k8s.io/network-policy-api/conformance/utils/suite" +) + +const ( + NetworkPolicyAPIRepoURL = "https://raw.githubusercontent.com/kubernetes-sigs/network-policy-api/v0.1.5" + reportFileName = "anp-test-report.yaml" +) + +var baseManifests = fmt.Sprintf("%s/conformance/base/manifests.yaml", NetworkPolicyAPIRepoURL) + +func TestAdminNetworkPolicyConformance(t *testing.T) { + t.Log("Configuring environment for adminnetworkpolicies conformance tests") + cfg, err := config.GetConfig() + if err != nil { + t.Fatalf("Error loading Kubernetes config: %v", err) + } + client, err := client.New(cfg, client.Options{}) + if err != nil { + t.Fatalf("Error initializing Kubernetes client: %v", err) + } + kubeConfig, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(clientcmd.NewDefaultClientConfigLoadingRules(), &clientcmd.ConfigOverrides{}).ClientConfig() + if err != nil { + t.Fatalf("error building Kube config for client-go: %v", err) + } + clientset, err := kubernetes.NewForConfig(kubeConfig) + if err != nil { + t.Fatalf("error when creating Kubernetes ClientSet: %v", err) + } + err = netpolv1alpha1.AddToScheme(client.Scheme()) + if err != nil { + t.Fatalf("Error initializing API scheme: %v", err) + } + + t.Log("Starting the admin network policy conformance test suite") + profiles := sets.Set[suite.ConformanceProfileName]{} + profiles.Insert(suite.ConformanceProfileName(suite.SupportAdminNetworkPolicy)) + profiles.Insert(suite.ConformanceProfileName(suite.SupportBaselineAdminNetworkPolicy)) + cSuite, err := suite.NewConformanceProfileTestSuite( + suite.ConformanceProfileOptions{ + Options: suite.Options{ + Client: client, + ClientSet: clientset, + KubeConfig: *cfg, + Debug: true, + CleanupBaseResources: true, + SupportedFeatures: suite.CoreFeatures, + BaseManifests: baseManifests, + TimeoutConfig: netpolv1config.TimeoutConfig{GetTimeout: 300 * time.Second}, + }, + ConformanceProfiles: profiles, + }) + if err != nil { + t.Fatalf("error creating conformance test suite: %v", err) + } + cSuite.Setup(t) + cSuite.Run(t, tests.ConformanceTests) + + report, err := cSuite.Report() + if err != nil { + t.Fatalf("error generating conformance profile report: %v", err) + } + t.Logf("Printing report...%v", report) + + rawReport, err := yaml.Marshal(report) + if err != nil { + t.Fatalf("error marshalling conformance profile report: %v", err) + } + err = os.WriteFile("../../"+reportFileName, rawReport, 0600) + if err != nil { + t.Fatalf("error writing conformance profile report: %v", err) + } +} diff --git a/test/anp/conformance.sh b/test/anp/conformance.sh new file mode 100755 index 00000000000..a6e3400cd3f --- /dev/null +++ b/test/anp/conformance.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -ex + +# setting this env prevents ginkgo e2e from trying to run provider setup +export KUBERNETES_CONFORMANCE_TEST=y + +pushd ./test/anp +go mod download +go test -timeout=0 -v -kubeconfig ${KUBECONFIG} +popd diff --git a/test/anp/go.mod b/test/anp/go.mod new file mode 100644 index 00000000000..f1101cfe7dd --- /dev/null +++ b/test/anp/go.mod @@ -0,0 +1,56 @@ +module github.com/kubeovn/kube-ovn/test/anp + +go 1.22.7 + +require ( + gopkg.in/yaml.v3 v3.0.1 + k8s.io/apimachinery v0.30.3 + k8s.io/client-go v0.30.3 + sigs.k8s.io/controller-runtime v0.18.4 + sigs.k8s.io/network-policy-api v0.1.5 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/emicklei/go-restful/v3 v3.12.1 // indirect + github.com/evanphx/json-patch/v5 v5.9.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.3 // indirect + github.com/imdario/mergo v0.3.6 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/moby/spdystream v0.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/testify v1.9.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/term v0.24.0 // indirect + golang.org/x/text v0.18.0 // indirect + golang.org/x/time v0.6.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + k8s.io/api v0.30.3 // indirect + k8s.io/klog/v2 v2.120.1 // indirect + k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect + k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect +) diff --git a/test/anp/go.sum b/test/anp/go.sum new file mode 100644 index 00000000000..b18bc11f319 --- /dev/null +++ b/test/anp/go.sum @@ -0,0 +1,165 @@ +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= +github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= +github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= +github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= +github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= +github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= +github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= +github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= +golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ= +k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04= +k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws= +k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4= +k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc= +k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= +k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k= +k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw= +sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/network-policy-api v0.1.5 h1:xyS7VAaM9EfyB428oFk7WjWaCK6B129i+ILUF4C8l6E= +sigs.k8s.io/network-policy-api v0.1.5/go.mod h1:D7Nkr43VLNd7iYryemnj8qf0N/WjBzTZDxYA+g4u1/Y= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/test/e2e/kube-ovn/pod/vpc_pod_probe.go b/test/e2e/kube-ovn/pod/vpc_pod_probe.go index 233ced69f40..ff7e7f0247b 100644 --- a/test/e2e/kube-ovn/pod/vpc_pod_probe.go +++ b/test/e2e/kube-ovn/pod/vpc_pod_probe.go @@ -17,6 +17,11 @@ import ( "github.com/kubeovn/kube-ovn/test/e2e/framework/iptables" ) +var ( + tProxyOutputMarkMask = fmt.Sprintf("%#x/%#x", util.TProxyOutputMark, util.TProxyOutputMask) + tProxyPreRoutingMarkMask = fmt.Sprintf("%#x/%#x", util.TProxyPreroutingMark, util.TProxyPreroutingMask) +) + var _ = framework.SerialDescribe("[group:pod]", func() { f := framework.NewDefaultFramework("vpc-pod-probe") @@ -175,7 +180,7 @@ var _ = framework.SerialDescribe("[group:pod]", func() { framework.ExpectTrue(found, "Pod readiness probe is expected to fail") pod = podClient.GetPod(podName) - checkTProxyRules(f, pod, port-1, false) + checkTProxyRules(f, pod, port-1, true) }) }) @@ -183,9 +188,6 @@ func checkTProxyRules(f *framework.Framework, pod *corev1.Pod, probePort int32, ginkgo.GinkgoHelper() nodeName := pod.Spec.NodeName - tProxyOutputMarkMask := fmt.Sprintf("%#x/%#x", util.TProxyOutputMark, util.TProxyOutputMask) - tProxyPreRoutingMarkMask := fmt.Sprintf("%#x/%#x", util.TProxyPreroutingMark, util.TProxyPreroutingMask) - isZeroIP := false if len(pod.Status.PodIPs) == 2 { isZeroIP = true diff --git a/test/e2e/kube-ovn/subnet/subnet.go b/test/e2e/kube-ovn/subnet/subnet.go index 61d75544b92..4c16c98f6a1 100644 --- a/test/e2e/kube-ovn/subnet/subnet.go +++ b/test/e2e/kube-ovn/subnet/subnet.go @@ -1168,6 +1168,33 @@ var _ = framework.Describe("[group:subnet]", func() { } }) + framework.ConformanceIt("Should support subnet multicast snoop", func() { + f.SkipVersionPriorTo(1, 13, "subnet multicast snoop is introduced in v1.13") + ginkgo.By("Creating subnet " + subnetName) + subnet = framework.MakeSubnet(subnetName, "", cidr, "", "", "", nil, nil, nil) + subnet = subnetClient.CreateSync(subnet) + + ginkgo.By("Checking subnet multicast snoop enable " + subnetName) + subnet = subnetClient.Get(subnetName) + modifiedSubnet := subnet.DeepCopy() + modifiedSubnet.Spec.EnableMulticastSnoop = true + subnetClient.PatchSync(subnet, modifiedSubnet) + + subnet = subnetClient.Get(subnetName) + framework.ExpectNotEmpty(subnet.Status.McastQuerierIP) + framework.ExpectNotEmpty(subnet.Status.McastQuerierMAC) + + ginkgo.By("Checking subnet multicast snoop disable " + subnetName) + subnet = subnetClient.Get(subnetName) + modifiedSubnet = subnet.DeepCopy() + modifiedSubnet.Spec.EnableMulticastSnoop = false + subnetClient.PatchSync(subnet, modifiedSubnet) + + subnet = subnetClient.Get(subnetName) + framework.ExpectEmpty(subnet.Status.McastQuerierIP) + framework.ExpectEmpty(subnet.Status.McastQuerierMAC) + }) + framework.ConformanceIt("should support subnet add nat outgoing policy rules", func() { f.SkipVersionPriorTo(1, 12, "Support for subnet add nat outgoing policy rules in v1.12") diff --git a/test/unittest/util/net.go b/test/unittest/util/net.go index ed804e19258..e5d838907f2 100644 --- a/test/unittest/util/net.go +++ b/test/unittest/util/net.go @@ -18,8 +18,8 @@ var _ = ginkgo.Describe("[Net]", func() { {IP: net.ParseIP("10.0.0.0"), Mask: net.CIDRMask(24, 32)}, } wants := []float64{ - 0, - 0, + 1, + 2, 2, 254, } @@ -112,7 +112,7 @@ var _ = ginkgo.Describe("[Net]", func() { {"10.0.1.1", "10.0.1.101..10.0.1.105"}, {"10.0.1.1", "10.0.1.101..10.0.1.105", "10.0.1.111..10.0.1.120"}, {"10.0.1.1"}, - {}, + {"10.0.1.1"}, {}, {}, @@ -130,7 +130,7 @@ var _ = ginkgo.Describe("[Net]", func() { {"fe00::101", "fe00::1a1..fe00::1a5"}, {"fe00::101", "fe00::1a1..fe00::1a5", "fe00::1b1..fe00::1c0"}, {"fe00::101"}, - {}, + {"fe00::101"}, {}, {"10.0.1.1", "10.0.1.101..10.0.1.105"},