From 859f43b9d1efcaf1bafc45944c756d0db224ffd4 Mon Sep 17 00:00:00 2001 From: Xu Liu Date: Wed, 23 Jun 2021 09:45:39 +0800 Subject: [PATCH] Add WireGuard support for tunnel traffic encryption This PR implements #2243. Change tunnel traffic encryption option to enum type. The options contains none (default), ipsec and wireguard. Signed-off-by: Xu Liu --- build/images/scripts/install_cni | 4 + build/images/wireguard-go/Dockerfile | 19 + build/images/wireguard-go/README.md | 20 + build/yamls/antrea-aks.yml | 27 +- build/yamls/antrea-eks.yml | 27 +- build/yamls/antrea-gke.yml | 27 +- build/yamls/antrea-ipsec.yml | 27 +- build/yamls/antrea.yml | 27 +- build/yamls/base/conf/antrea-agent.conf | 19 +- build/yamls/patches/kind/wireguardGo.yml | 39 ++ ci/kind/test-e2e-kind.sh | 10 +- cmd/antrea-agent/agent.go | 20 +- cmd/antrea-agent/config.go | 21 +- cmd/antrea-agent/options.go | 15 +- cmd/antrea-agent/options_windows.go | 6 +- cmd/antrea-agent/options_windows_test.go | 9 +- go.mod | 16 +- go.sum | 60 ++- hack/generate-manifest.sh | 30 +- pkg/agent/agent.go | 46 ++- pkg/agent/agent_test.go | 112 +++--- pkg/agent/config/node_config.go | 46 ++- pkg/agent/config/node_config_test.go | 165 ++++++++ pkg/agent/config/traffic_encap_mode.go | 11 - pkg/agent/config/traffic_encap_mode_test.go | 115 ------ pkg/agent/config/traffic_encryption_mode.go | 60 +++ .../config/traffic_encryption_mode_test.go | 66 +++ .../noderoute/node_route_controller.go | 85 +++- .../noderoute/node_route_controller_test.go | 10 +- pkg/agent/openflow/client.go | 30 +- pkg/agent/openflow/client_test.go | 10 +- pkg/agent/openflow/network_policy_test.go | 3 + pkg/agent/openflow/pipeline.go | 5 +- pkg/agent/openflow/pipeline_windows.go | 4 +- pkg/agent/openflow/testing/mock_openflow.go | 2 +- pkg/agent/route/route_linux.go | 13 +- pkg/agent/route/route_windows.go | 4 +- pkg/agent/types/annotations.go | 3 + pkg/agent/wireguard/client_linux.go | 227 +++++++++++ pkg/agent/wireguard/client_test.go | 379 ++++++++++++++++++ pkg/agent/wireguard/client_windows.go | 28 ++ pkg/agent/wireguard/interface.go | 33 ++ pkg/apis/ports.go | 2 + plugins/octant/go.mod | 6 +- plugins/octant/go.sum | 46 ++- test/e2e/connectivity_test.go | 20 +- test/e2e/fixtures.go | 2 +- test/e2e/framework.go | 60 ++- test/e2e/ipsec_test.go | 8 +- test/e2e/performance_test.go | 2 +- test/e2e/traceflow_test.go | 4 +- test/e2e/wireguard_test.go | 125 ++++++ test/integration/agent/openflow_test.go | 10 +- 53 files changed, 1805 insertions(+), 360 deletions(-) create mode 100644 build/images/wireguard-go/Dockerfile create mode 100644 build/images/wireguard-go/README.md create mode 100644 build/yamls/patches/kind/wireguardGo.yml create mode 100644 pkg/agent/config/node_config_test.go create mode 100644 pkg/agent/config/traffic_encryption_mode.go create mode 100644 pkg/agent/config/traffic_encryption_mode_test.go create mode 100644 pkg/agent/wireguard/client_linux.go create mode 100644 pkg/agent/wireguard/client_test.go create mode 100644 pkg/agent/wireguard/client_windows.go create mode 100644 pkg/agent/wireguard/interface.go create mode 100644 test/e2e/wireguard_test.go diff --git a/build/images/scripts/install_cni b/build/images/scripts/install_cni index 336e53cb031..a464662efdc 100755 --- a/build/images/scripts/install_cni +++ b/build/images/scripts/install_cni @@ -33,5 +33,9 @@ install -m 755 /opt/cni/bin/whereabouts /host/opt/cni/bin/whereabouts # Load the OVS kernel module modprobe openvswitch || (echo "Failed to load the OVS kernel module from the container, try running 'modprobe openvswitch' on your Nodes"; exit 1) +# Load the WireGuard kernel module. This is only required when WireGuard encryption is enabled. +# We could parse the antrea config file in the init-container to dynamically load this kernel module in the future. +modprobe wireguard || (echo "Failed to load the WireGuard kernel module, WireGuard encryption will not be available") + # Change the default permissions of the run directory. chmod 0750 /var/run/antrea diff --git a/build/images/wireguard-go/Dockerfile b/build/images/wireguard-go/Dockerfile new file mode 100644 index 00000000000..71e8aba8857 --- /dev/null +++ b/build/images/wireguard-go/Dockerfile @@ -0,0 +1,19 @@ +ARG GO_VERSION +ARG WIREGUARD_GO_VERSION + +FROM golang:${GO_VERSION} as builder + +RUN git clone https://git.zx2c4.com/wireguard-go && \ + cd wireguard-go && \ + git checkout ${WIREGUARD_GO_VERSION} && \ + make && \ + make install + +RUN git clone https://git.zx2c4.com/wireguard-tools && \ + cd wireguard-tools && \ + cd src && \ + make && \ + make install + +FROM ubuntu:20.04 +COPY --from=builder /usr/bin/wireguard-go /usr/bin/wg /usr/bin/ diff --git a/build/images/wireguard-go/README.md b/build/images/wireguard-go/README.md new file mode 100644 index 00000000000..66abe59644c --- /dev/null +++ b/build/images/wireguard-go/README.md @@ -0,0 +1,20 @@ +# images/wireguard-go + +This Docker image is a very lightweight image based on Ubuntu 20.04 which +includes WireGuard golang implementation and wireguard-tools. It can be used +for Kind clusters for tests when injected as a sidecar to antrea-agent. +The version is available at . + +If you need to build a new version of the image and push it to Dockerhub, you +can run the following: + +```bash +cd build/images/wireguard-go +GO_VERSION=$(head -n 1 ../deps/go-version) +WIREGUARD_GO_VERSION=0.0.20210424 +docker build -t antrea/wireguard-go:$WIREGUARD_GO_VERSION --build-arg GO_VERSION=$GO_VERSION --build-arg WIREGUARD_GO_VERSION=$WIREGUARD_GO_VERSION . +docker push antrea/wireguard-go:$WIREGUARD_GO_VERSION +``` + +The `docker push` command will fail if you do not have permission to push to the +`antrea` Dockerhub repository. diff --git a/build/yamls/antrea-aks.yml b/build/yamls/antrea-aks.yml index 0a6f01ae2b4..3c797ae61cc 100644 --- a/build/yamls/antrea-aks.yml +++ b/build/yamls/antrea-aks.yml @@ -3820,20 +3820,33 @@ data: # performs SNAT and this option will be ignored; for other modes it must be set to false. #noSNAT: false - # Tunnel protocols used for encapsulating traffic across Nodes. Supported values: + # Tunnel protocols used for encapsulating traffic across Nodes. If WireGuard is enabled in trafficEncryptionMode, + # this option will not take effect. Supported values: # - geneve (default) # - vxlan # - gre # - stt #tunnelType: geneve + # Determines how tunnel traffic is encrypted. Currently encryption only works with antrea encap mode. + # It has the following options: + # - none (default): Inter-node Pod traffic will not be encrypted. + # - ipsec: Enable IPSec (ESP) encryption for Pod traffic across Nodes. Antrea uses + # Preshared Key (PSK) for IKE authentication. When IPSec tunnel is enabled, + # the PSK value must be passed to Antrea Agent through an environment + # variable: ANTREA_IPSEC_PSK. + # - wireGuard: Enable WireGuard for tunnel traffic encryption. + #trafficEncryptionMode: none + # Default MTU to use for the host gateway interface and the network interface of each Pod. # If omitted, antrea-agent will discover the MTU of the Node's primary interface and # also adjust MTU to accommodate for tunnel encapsulation overhead (if applicable). #defaultMTU: 0 - # Whether or not to enable IPsec encryption of tunnel traffic. - #enableIPSecTunnel: false + # wireGuard specifies WireGuard related configurations. + wireGuard: + # The port for WireGuard to receive traffic. + # port: 51820 # ClusterIP CIDR range for IPv6 Services. It's required when using kube-proxy to provide IPv6 Service in a Dual-Stack # cluster or an IPv6 only cluster. The value should be the same as the configuration for kube-apiserver specified by @@ -3983,7 +3996,7 @@ metadata: annotations: {} labels: app: antrea - name: antrea-config-66dt98cgtb + name: antrea-config-565d7ttk2b namespace: kube-system --- apiVersion: v1 @@ -4054,7 +4067,7 @@ spec: fieldRef: fieldPath: spec.serviceAccountName - name: ANTREA_CONFIG_MAP_NAME - value: antrea-config-66dt98cgtb + value: antrea-config-565d7ttk2b image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest imagePullPolicy: IfNotPresent livenessProbe: @@ -4105,7 +4118,7 @@ spec: key: node-role.kubernetes.io/master volumes: - configMap: - name: antrea-config-66dt98cgtb + name: antrea-config-565d7ttk2b name: antrea-config - name: antrea-controller-tls secret: @@ -4386,7 +4399,7 @@ spec: operator: Exists volumes: - configMap: - name: antrea-config-66dt98cgtb + name: antrea-config-565d7ttk2b name: antrea-config - hostPath: path: /etc/cni/net.d diff --git a/build/yamls/antrea-eks.yml b/build/yamls/antrea-eks.yml index 518f90f45d7..e0d83733538 100644 --- a/build/yamls/antrea-eks.yml +++ b/build/yamls/antrea-eks.yml @@ -3820,20 +3820,33 @@ data: # performs SNAT and this option will be ignored; for other modes it must be set to false. #noSNAT: false - # Tunnel protocols used for encapsulating traffic across Nodes. Supported values: + # Tunnel protocols used for encapsulating traffic across Nodes. If WireGuard is enabled in trafficEncryptionMode, + # this option will not take effect. Supported values: # - geneve (default) # - vxlan # - gre # - stt #tunnelType: geneve + # Determines how tunnel traffic is encrypted. Currently encryption only works with antrea encap mode. + # It has the following options: + # - none (default): Inter-node Pod traffic will not be encrypted. + # - ipsec: Enable IPSec (ESP) encryption for Pod traffic across Nodes. Antrea uses + # Preshared Key (PSK) for IKE authentication. When IPSec tunnel is enabled, + # the PSK value must be passed to Antrea Agent through an environment + # variable: ANTREA_IPSEC_PSK. + # - wireGuard: Enable WireGuard for tunnel traffic encryption. + #trafficEncryptionMode: none + # Default MTU to use for the host gateway interface and the network interface of each Pod. # If omitted, antrea-agent will discover the MTU of the Node's primary interface and # also adjust MTU to accommodate for tunnel encapsulation overhead (if applicable). #defaultMTU: 0 - # Whether or not to enable IPsec encryption of tunnel traffic. - #enableIPSecTunnel: false + # wireGuard specifies WireGuard related configurations. + wireGuard: + # The port for WireGuard to receive traffic. + # port: 51820 # ClusterIP CIDR range for IPv6 Services. It's required when using kube-proxy to provide IPv6 Service in a Dual-Stack # cluster or an IPv6 only cluster. The value should be the same as the configuration for kube-apiserver specified by @@ -3983,7 +3996,7 @@ metadata: annotations: {} labels: app: antrea - name: antrea-config-66dt98cgtb + name: antrea-config-565d7ttk2b namespace: kube-system --- apiVersion: v1 @@ -4054,7 +4067,7 @@ spec: fieldRef: fieldPath: spec.serviceAccountName - name: ANTREA_CONFIG_MAP_NAME - value: antrea-config-66dt98cgtb + value: antrea-config-565d7ttk2b image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest imagePullPolicy: IfNotPresent livenessProbe: @@ -4105,7 +4118,7 @@ spec: key: node-role.kubernetes.io/master volumes: - configMap: - name: antrea-config-66dt98cgtb + name: antrea-config-565d7ttk2b name: antrea-config - name: antrea-controller-tls secret: @@ -4388,7 +4401,7 @@ spec: operator: Exists volumes: - configMap: - name: antrea-config-66dt98cgtb + name: antrea-config-565d7ttk2b name: antrea-config - hostPath: path: /etc/cni/net.d diff --git a/build/yamls/antrea-gke.yml b/build/yamls/antrea-gke.yml index 0150f013609..f2921986366 100644 --- a/build/yamls/antrea-gke.yml +++ b/build/yamls/antrea-gke.yml @@ -3820,20 +3820,33 @@ data: # performs SNAT and this option will be ignored; for other modes it must be set to false. #noSNAT: false - # Tunnel protocols used for encapsulating traffic across Nodes. Supported values: + # Tunnel protocols used for encapsulating traffic across Nodes. If WireGuard is enabled in trafficEncryptionMode, + # this option will not take effect. Supported values: # - geneve (default) # - vxlan # - gre # - stt #tunnelType: geneve + # Determines how tunnel traffic is encrypted. Currently encryption only works with antrea encap mode. + # It has the following options: + # - none (default): Inter-node Pod traffic will not be encrypted. + # - ipsec: Enable IPSec (ESP) encryption for Pod traffic across Nodes. Antrea uses + # Preshared Key (PSK) for IKE authentication. When IPSec tunnel is enabled, + # the PSK value must be passed to Antrea Agent through an environment + # variable: ANTREA_IPSEC_PSK. + # - wireGuard: Enable WireGuard for tunnel traffic encryption. + #trafficEncryptionMode: none + # Default MTU to use for the host gateway interface and the network interface of each Pod. # If omitted, antrea-agent will discover the MTU of the Node's primary interface and # also adjust MTU to accommodate for tunnel encapsulation overhead (if applicable). #defaultMTU: 0 - # Whether or not to enable IPsec encryption of tunnel traffic. - #enableIPSecTunnel: false + # wireGuard specifies WireGuard related configurations. + wireGuard: + # The port for WireGuard to receive traffic. + # port: 51820 # ClusterIP CIDR range for IPv6 Services. It's required when using kube-proxy to provide IPv6 Service in a Dual-Stack # cluster or an IPv6 only cluster. The value should be the same as the configuration for kube-apiserver specified by @@ -3983,7 +3996,7 @@ metadata: annotations: {} labels: app: antrea - name: antrea-config-d2f597tg62 + name: antrea-config-gb72f9b99b namespace: kube-system --- apiVersion: v1 @@ -4054,7 +4067,7 @@ spec: fieldRef: fieldPath: spec.serviceAccountName - name: ANTREA_CONFIG_MAP_NAME - value: antrea-config-d2f597tg62 + value: antrea-config-gb72f9b99b image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest imagePullPolicy: IfNotPresent livenessProbe: @@ -4105,7 +4118,7 @@ spec: key: node-role.kubernetes.io/master volumes: - configMap: - name: antrea-config-d2f597tg62 + name: antrea-config-gb72f9b99b name: antrea-config - name: antrea-controller-tls secret: @@ -4389,7 +4402,7 @@ spec: path: /home/kubernetes/bin name: host-cni-bin - configMap: - name: antrea-config-d2f597tg62 + name: antrea-config-gb72f9b99b name: antrea-config - hostPath: path: /etc/cni/net.d diff --git a/build/yamls/antrea-ipsec.yml b/build/yamls/antrea-ipsec.yml index 9b71c9a0c02..b9d6742d553 100644 --- a/build/yamls/antrea-ipsec.yml +++ b/build/yamls/antrea-ipsec.yml @@ -3820,20 +3820,33 @@ data: # performs SNAT and this option will be ignored; for other modes it must be set to false. #noSNAT: false - # Tunnel protocols used for encapsulating traffic across Nodes. Supported values: + # Tunnel protocols used for encapsulating traffic across Nodes. If WireGuard is enabled in trafficEncryptionMode, + # this option will not take effect. Supported values: # - geneve (default) # - vxlan # - gre # - stt tunnelType: gre + # Determines how tunnel traffic is encrypted. Currently encryption only works with antrea encap mode. + # It has the following options: + # - none (default): Inter-node Pod traffic will not be encrypted. + # - ipsec: Enable IPSec (ESP) encryption for Pod traffic across Nodes. Antrea uses + # Preshared Key (PSK) for IKE authentication. When IPSec tunnel is enabled, + # the PSK value must be passed to Antrea Agent through an environment + # variable: ANTREA_IPSEC_PSK. + # - wireGuard: Enable WireGuard for tunnel traffic encryption. + trafficEncryptionMode: ipsec + # Default MTU to use for the host gateway interface and the network interface of each Pod. # If omitted, antrea-agent will discover the MTU of the Node's primary interface and # also adjust MTU to accommodate for tunnel encapsulation overhead (if applicable). #defaultMTU: 0 - # Whether or not to enable IPsec encryption of tunnel traffic. - enableIPSecTunnel: true + # wireGuard specifies WireGuard related configurations. + wireGuard: + # The port for WireGuard to receive traffic. + # port: 51820 # ClusterIP CIDR range for Services. It's required when AntreaProxy is not enabled, and should be # set to the same value as the one specified by --service-cluster-ip-range for kube-apiserver. When @@ -3988,7 +4001,7 @@ metadata: annotations: {} labels: app: antrea - name: antrea-config-bgd79km9c8 + name: antrea-config-2652tb62dt namespace: kube-system --- apiVersion: v1 @@ -4068,7 +4081,7 @@ spec: fieldRef: fieldPath: spec.serviceAccountName - name: ANTREA_CONFIG_MAP_NAME - value: antrea-config-bgd79km9c8 + value: antrea-config-2652tb62dt image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest imagePullPolicy: IfNotPresent livenessProbe: @@ -4119,7 +4132,7 @@ spec: key: node-role.kubernetes.io/master volumes: - configMap: - name: antrea-config-bgd79km9c8 + name: antrea-config-2652tb62dt name: antrea-config - name: antrea-controller-tls secret: @@ -4435,7 +4448,7 @@ spec: operator: Exists volumes: - configMap: - name: antrea-config-bgd79km9c8 + name: antrea-config-2652tb62dt name: antrea-config - hostPath: path: /etc/cni/net.d diff --git a/build/yamls/antrea.yml b/build/yamls/antrea.yml index 642c5f2b5e2..1784e8ebaeb 100644 --- a/build/yamls/antrea.yml +++ b/build/yamls/antrea.yml @@ -3820,20 +3820,33 @@ data: # performs SNAT and this option will be ignored; for other modes it must be set to false. #noSNAT: false - # Tunnel protocols used for encapsulating traffic across Nodes. Supported values: + # Tunnel protocols used for encapsulating traffic across Nodes. If WireGuard is enabled in trafficEncryptionMode, + # this option will not take effect. Supported values: # - geneve (default) # - vxlan # - gre # - stt #tunnelType: geneve + # Determines how tunnel traffic is encrypted. Currently encryption only works with antrea encap mode. + # It has the following options: + # - none (default): Inter-node Pod traffic will not be encrypted. + # - ipsec: Enable IPSec (ESP) encryption for Pod traffic across Nodes. Antrea uses + # Preshared Key (PSK) for IKE authentication. When IPSec tunnel is enabled, + # the PSK value must be passed to Antrea Agent through an environment + # variable: ANTREA_IPSEC_PSK. + # - wireGuard: Enable WireGuard for tunnel traffic encryption. + #trafficEncryptionMode: none + # Default MTU to use for the host gateway interface and the network interface of each Pod. # If omitted, antrea-agent will discover the MTU of the Node's primary interface and # also adjust MTU to accommodate for tunnel encapsulation overhead (if applicable). #defaultMTU: 0 - # Whether or not to enable IPsec encryption of tunnel traffic. - #enableIPSecTunnel: false + # wireGuard specifies WireGuard related configurations. + wireGuard: + # The port for WireGuard to receive traffic. + # port: 51820 # ClusterIP CIDR range for Services. It's required when AntreaProxy is not enabled, and should be # set to the same value as the one specified by --service-cluster-ip-range for kube-apiserver. When @@ -3988,7 +4001,7 @@ metadata: annotations: {} labels: app: antrea - name: antrea-config-dd8ffc8tk9 + name: antrea-config-4749gkck7d namespace: kube-system --- apiVersion: v1 @@ -4059,7 +4072,7 @@ spec: fieldRef: fieldPath: spec.serviceAccountName - name: ANTREA_CONFIG_MAP_NAME - value: antrea-config-dd8ffc8tk9 + value: antrea-config-4749gkck7d image: projects.registry.vmware.com/antrea/antrea-ubuntu:latest imagePullPolicy: IfNotPresent livenessProbe: @@ -4110,7 +4123,7 @@ spec: key: node-role.kubernetes.io/master volumes: - configMap: - name: antrea-config-dd8ffc8tk9 + name: antrea-config-4749gkck7d name: antrea-config - name: antrea-controller-tls secret: @@ -4391,7 +4404,7 @@ spec: operator: Exists volumes: - configMap: - name: antrea-config-dd8ffc8tk9 + name: antrea-config-4749gkck7d name: antrea-config - hostPath: path: /etc/cni/net.d diff --git a/build/yamls/base/conf/antrea-agent.conf b/build/yamls/base/conf/antrea-agent.conf index 36193814a3c..4fd379879e0 100644 --- a/build/yamls/base/conf/antrea-agent.conf +++ b/build/yamls/base/conf/antrea-agent.conf @@ -65,20 +65,33 @@ featureGates: # performs SNAT and this option will be ignored; for other modes it must be set to false. #noSNAT: false -# Tunnel protocols used for encapsulating traffic across Nodes. Supported values: +# Tunnel protocols used for encapsulating traffic across Nodes. If WireGuard is enabled in trafficEncryptionMode, +# this option will not take effect. Supported values: # - geneve (default) # - vxlan # - gre # - stt #tunnelType: geneve +# Determines how tunnel traffic is encrypted. Currently encryption only works with antrea encap mode. +# It has the following options: +# - none (default): Inter-node Pod traffic will not be encrypted. +# - ipsec: Enable IPSec (ESP) encryption for Pod traffic across Nodes. Antrea uses +# Preshared Key (PSK) for IKE authentication. When IPSec tunnel is enabled, +# the PSK value must be passed to Antrea Agent through an environment +# variable: ANTREA_IPSEC_PSK. +# - wireGuard: Enable WireGuard for tunnel traffic encryption. +#trafficEncryptionMode: none + # Default MTU to use for the host gateway interface and the network interface of each Pod. # If omitted, antrea-agent will discover the MTU of the Node's primary interface and # also adjust MTU to accommodate for tunnel encapsulation overhead (if applicable). #defaultMTU: 0 -# Whether or not to enable IPsec encryption of tunnel traffic. -#enableIPSecTunnel: false +# wireGuard specifies WireGuard related configurations. +wireGuard: +# The port for WireGuard to receive traffic. +# port: 51820 # ClusterIP CIDR range for Services. It's required when AntreaProxy is not enabled, and should be # set to the same value as the one specified by --service-cluster-ip-range for kube-apiserver. When diff --git a/build/yamls/patches/kind/wireguardGo.yml b/build/yamls/patches/kind/wireguardGo.yml new file mode 100644 index 00000000000..6d42f38c021 --- /dev/null +++ b/build/yamls/patches/kind/wireguardGo.yml @@ -0,0 +1,39 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: antrea-agent +spec: + template: + spec: + containers: + - name: wireguard + command: + - wireguard-go + args: + - -f + - antrea-wg0 + image: projects.registry.vmware.com/antrea/wireguard-go:0.0.20210424 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 100m + securityContext: + capabilities: + add: + - NET_ADMIN + volumeMounts: + - mountPath: /var/run/wireguard + name: host-var-run-antrea + subPath: wireguard + - name: dev-tun + mountPath: /dev/net/tun + - name: antrea-agent + volumeMounts: + - mountPath: /var/run/wireguard + name: host-var-run-antrea + subPath: wireguard + volumes: + - name: dev-tun + hostPath: + path: /dev/net/tun + type: CharDevice diff --git a/ci/kind/test-e2e-kind.sh b/ci/kind/test-e2e-kind.sh index 0e8e9a429b9..d590420c9fa 100755 --- a/ci/kind/test-e2e-kind.sh +++ b/ci/kind/test-e2e-kind.sh @@ -112,7 +112,12 @@ if ! $np; then manifest_args="$manifest_args --no-np" fi -COMMON_IMAGES_LIST=("gcr.io/kubernetes-e2e-test-images/agnhost:2.8" "projects.registry.vmware.com/library/busybox" "projects.registry.vmware.com/antrea/nginx" "projects.registry.vmware.com/antrea/perftool" "projects.registry.vmware.com/antrea/ipfix-collector:v0.5.4") +COMMON_IMAGES_LIST=("gcr.io/kubernetes-e2e-test-images/agnhost:2.8" \ + "projects.registry.vmware.com/library/busybox" \ + "projects.registry.vmware.com/antrea/nginx" \ + "projects.registry.vmware.com/antrea/perftool" \ + "projects.registry.vmware.com/antrea/ipfix-collector:v0.5.4" \ + "projects.registry.vmware.com/antrea/wireguard-go:0.0.20210424") for image in "${COMMON_IMAGES_LIST[@]}"; do for i in `seq 3`; do docker pull $image && break @@ -147,11 +152,14 @@ function run_test { if $coverage; then $YML_CMD --kind --encap-mode $current_mode $manifest_args | docker exec -i kind-control-plane dd of=/root/antrea-coverage.yml + $YML_CMD --kind --encap-mode $current_mode --wireguard-go $manifest_args | docker exec -i kind-control-plane dd of=/root/antrea-wireguard-go-coverage.yml $FLOWAGGREGATOR_YML_CMD --coverage | docker exec -i kind-control-plane dd of=/root/flow-aggregator-coverage.yml else $YML_CMD --kind --encap-mode $current_mode $manifest_args | docker exec -i kind-control-plane dd of=/root/antrea.yml + $YML_CMD --kind --encap-mode $current_mode --wireguard-go $manifest_args | docker exec -i kind-control-plane dd of=/root/antrea-wireguard-go.yml $FLOWAGGREGATOR_YML_CMD | docker exec -i kind-control-plane dd of=/root/flow-aggregator.yml fi + sleep 1 if $coverage; then diff --git a/cmd/antrea-agent/agent.go b/cmd/antrea-agent/agent.go index 4fb42755235..f63c1554219 100644 --- a/cmd/antrea-agent/agent.go +++ b/cmd/antrea-agent/agent.go @@ -114,13 +114,21 @@ func run(o *Options) error { } _, encapMode := config.GetTrafficEncapModeFromStr(o.config.TrafficEncapMode) + _, encryptionMode := config.GetTrafficEncryptionModeFromStr(o.config.TrafficEncryptionMode) + if o.config.EnableIPSecTunnel { + klog.Warning("enableIPSecTunnel is deprecated, use trafficEncryptionMode instead.") + encryptionMode = config.TrafficEncryptionModeIPSec + } networkConfig := &config.NetworkConfig{ - TunnelType: ovsconfig.TunnelType(o.config.TunnelType), - TrafficEncapMode: encapMode, - EnableIPSecTunnel: o.config.EnableIPSecTunnel, - TransportIface: o.config.TransportInterface, + TunnelType: ovsconfig.TunnelType(o.config.TunnelType), + TrafficEncapMode: encapMode, + TrafficEncryptionMode: encryptionMode, + TransportIface: o.config.TransportInterface, } + wireguardConfig := &config.WireGuardConfig{ + Port: o.config.WireGuard.Port, + } routeClient, err := route.NewClient(serviceCIDRNet, networkConfig, o.config.NoSNAT) if err != nil { return fmt.Errorf("error creating route client: %v", err) @@ -149,6 +157,7 @@ func run(o *Options) error { serviceCIDRNet, serviceCIDRNetv6, networkConfig, + wireguardConfig, networkReadyCh, stopCh, features.DefaultFeatureGate.Enabled(features.AntreaProxy)) @@ -166,7 +175,8 @@ func run(o *Options) error { routeClient, ifaceStore, networkConfig, - nodeConfig) + nodeConfig, + agentInitializer.GetWireGuardClient()) var proxier proxy.Proxier if features.DefaultFeatureGate.Enabled(features.AntreaProxy) { diff --git a/cmd/antrea-agent/config.go b/cmd/antrea-agent/config.go index d3c3a0c2582..4ae77758b92 100644 --- a/cmd/antrea-agent/config.go +++ b/cmd/antrea-agent/config.go @@ -89,11 +89,19 @@ type AgentConfig struct { // --service-cluster-ip-range. When AntreaProxy is enabled, this parameter is not needed. // No default value for this field. ServiceCIDRv6 string `yaml:"serviceCIDRv6,omitempty"` - // Whether or not to enable IPSec (ESP) encryption for Pod traffic across Nodes. Antrea uses Preshared Key (PSK) for IKE - // authentication. When IPSec tunnel is enabled, the PSK value must be passed to Antrea Agent - // through an environment variable: ANTREA_IPSEC_PSK. - // Defaults to false. + // Deprecated. Use TrafficEncryptionMode instead. EnableIPSecTunnel bool `yaml:"enableIPSecTunnel,omitempty"` + // Determines how tunnel traffic is encrypted. + // It has the following options: + // - none (default): Inter-node Pod traffic will not be encrypted. + // - ipsec: Enable IPSec (ESP) encryption for Pod traffic across Nodes. Antrea uses + // Preshared Key (PSK) for IKE authentication. When IPSec tunnel is enabled, + // the PSK value must be passed to Antrea Agent through an environment + // variable: ANTREA_IPSEC_PSK. + // - wireguard: Enable WireGuard for tunnel traffic encryption. + TrafficEncryptionMode string `yaml:"trafficEncryptionMode,omitempty"` + // WireGuerd related configurations. + WireGuard WireGuardConfig `yaml:"wireGuard"` // APIPort is the port for the antrea-agent APIServer to serve on. // Defaults to 10350. APIPort int `yaml:"apiPort,omitempty"` @@ -155,3 +163,8 @@ type AgentConfig struct { // The interface configured with Node IP is used if this parameter is not set. TransportInterface string `yaml:"transportInterface,omitempty"` } + +type WireGuardConfig struct { + // The port for the WireGuard to receive traffic. Defaults to 51820. + Port int `yaml:"port,omitempty"` +} diff --git a/cmd/antrea-agent/options.go b/cmd/antrea-agent/options.go index b6a28e02a36..7c4f0973b2b 100644 --- a/cmd/antrea-agent/options.go +++ b/cmd/antrea-agent/options.go @@ -116,6 +116,10 @@ func (o *Options) validate(args []string) error { o.config.TunnelType != ovsconfig.GRETunnel && o.config.TunnelType != ovsconfig.STTTunnel { return fmt.Errorf("tunnel type %s is invalid", o.config.TunnelType) } + ok, encryptionMode := config.GetTrafficEncryptionModeFromStr(o.config.TrafficEncryptionMode) + if !ok { + return fmt.Errorf("TrafficEncryptionMode %s is unknown", o.config.TrafficEncryptionMode) + } if o.config.OVSDatapathType != string(ovsconfig.OVSDatapathSystem) && o.config.OVSDatapathType != string(ovsconfig.OVSDatapathNetdev) { return fmt.Errorf("OVS datapath type %s is not supported", o.config.OVSDatapathType) } @@ -134,8 +138,8 @@ func (o *Options) validate(args []string) error { if !features.DefaultFeatureGate.Enabled(features.AntreaProxy) { return fmt.Errorf("TrafficEncapMode %s requires AntreaProxy to be enabled", o.config.TrafficEncapMode) } - if o.config.EnableIPSecTunnel { - return fmt.Errorf("IPsec tunnel may only be enabled in %s mode", config.TrafficEncapModeEncap) + if encryptionMode != config.TrafficEncryptionModeNone { + return fmt.Errorf("TrafficEncryptionMode %s may only be enabled in %s mode", encryptionMode, config.TrafficEncapModeEncap) } } if o.config.NoSNAT && !(encapMode == config.TrafficEncapModeNoEncap || encapMode == config.TrafficEncapModeNetworkPolicyOnly) { @@ -180,6 +184,9 @@ func (o *Options) setDefaults() { if o.config.TrafficEncapMode == "" { o.config.TrafficEncapMode = config.TrafficEncapModeEncap.String() } + if o.config.TrafficEncryptionMode == "" { + o.config.TrafficEncryptionMode = config.TrafficEncryptionModeNone.String() + } if o.config.TunnelType == "" { o.config.TunnelType = defaultTunnelType } @@ -192,10 +199,12 @@ func (o *Options) setDefaults() { if o.config.APIPort == 0 { o.config.APIPort = apis.AntreaAgentAPIPort } - if o.config.ClusterMembershipPort == 0 { o.config.ClusterMembershipPort = apis.AntreaAgentClusterMembershipPort } + if o.config.WireGuard.Port == 0 { + o.config.WireGuard.Port = apis.WireGuardListenPort + } if features.DefaultFeatureGate.Enabled(features.FlowExporter) { if o.config.FlowCollectorAddr == "" { diff --git a/cmd/antrea-agent/options_windows.go b/cmd/antrea-agent/options_windows.go index e0b8970d65a..90567213471 100644 --- a/cmd/antrea-agent/options_windows.go +++ b/cmd/antrea-agent/options_windows.go @@ -49,10 +49,10 @@ func (o *Options) checkUnsupportedFeatures() error { if o.config.TunnelType == ovsconfig.GRETunnel { unsupported = append(unsupported, "TunnelType: "+o.config.TunnelType) } - if o.config.EnableIPSecTunnel { - unsupported = append(unsupported, "IPsecTunnel") + _, encryptionMode := config.GetTrafficEncryptionModeFromStr(o.config.TrafficEncryptionMode) + if encryptionMode != config.TrafficEncryptionModeNone { + unsupported = append(unsupported, "TrafficEncryptionMode: "+encryptionMode.String()) } - if unsupported != nil { return fmt.Errorf("unsupported features on Windows: {%s}", strings.Join(unsupported, ", ")) } diff --git a/cmd/antrea-agent/options_windows_test.go b/cmd/antrea-agent/options_windows_test.go index 473bd5f6d2e..af1eaeb4f4b 100644 --- a/cmd/antrea-agent/options_windows_test.go +++ b/cmd/antrea-agent/options_windows_test.go @@ -66,8 +66,13 @@ func TestCheckUnsupportedFeatures(t *testing.T) { false, }, { - "IPsec tunnel", - AgentConfig{EnableIPSecTunnel: true}, + "IPsec encryption", + AgentConfig{TrafficEncryptionMode: config.TrafficEncryptionModeIPSec.String()}, + false, + }, + { + "WireGuard encryption", + AgentConfig{TrafficEncryptionMode: config.TrafficEncryptionModeWireGuard.String()}, false, }, { diff --git a/go.mod b/go.mod index 68bb77e4933..cdf6af7685b 100644 --- a/go.mod +++ b/go.mod @@ -42,15 +42,16 @@ require ( github.com/streamrail/concurrent-map v0.0.0-20160823150647-8bf1e9bacbf6 // indirect github.com/stretchr/testify v1.7.0 github.com/ti-mo/conntrack v0.3.0 - github.com/vishvananda/netlink v1.1.0 + github.com/vishvananda/netlink v1.1.1-0.20210510164352-d17758a128bf github.com/vmware/go-ipfix v0.5.7 - golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 + golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 golang.org/x/mod v0.4.2 - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 + golang.org/x/net v0.0.0-20210504132125-bbd867fde50d golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20210510120138-977fb7262007 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba + golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210506160403-92e472f520a5 google.golang.org/grpc v1.27.1 gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v2 v2.4.0 @@ -102,13 +103,15 @@ require ( github.com/hashicorp/golang-lru v0.5.1 // indirect github.com/imdario/mergo v0.3.5 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect github.com/json-iterator/go v1.1.10 // indirect github.com/mailru/easyjson v0.7.0 // indirect github.com/mattn/go-colorable v0.1.2 // indirect github.com/mattn/go-isatty v0.0.10 // indirect github.com/mattn/go-runewidth v0.0.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect - github.com/mdlayher/netlink v1.1.0 // indirect + github.com/mdlayher/genetlink v1.0.0 // indirect + github.com/mdlayher/netlink v1.4.0 // indirect github.com/moby/spdystream v0.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect @@ -123,7 +126,7 @@ require ( github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/ti-mo/netfilter v0.3.1 // indirect - github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect + github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae // indirect go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489 // indirect go.opencensus.io v0.22.3 // indirect go.uber.org/atomic v1.4.0 // indirect @@ -131,8 +134,9 @@ require ( go.uber.org/zap v1.10.0 // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect - golang.org/x/text v0.3.4 // indirect + golang.org/x/text v0.3.6 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b // indirect google.golang.org/appengine v1.6.5 // indirect google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect google.golang.org/protobuf v1.27.1 // indirect diff --git a/go.sum b/go.sum index f00e50bec72..00f7c40b6a4 100644 --- a/go.sum +++ b/go.sum @@ -302,6 +302,7 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -378,9 +379,16 @@ github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6t github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA= +github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= -github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4 h1:nwOc1YaOrYJ37sEBrtWZrdqzK22hiJs3GpDmP3sR2Yw= github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= +github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= +github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= +github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= +github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA= +github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b h1:c3NTyLNozICy8B4mlMXemD3z/gXgQzVXZS/HqT+i3do= +github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= @@ -436,14 +444,26 @@ github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vq github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JAQI/ZLUkCZ7VJS3r74hwFIGXJsgZlY= +github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= +github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0= +github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= -github.com/mdlayher/netlink v1.1.0 h1:mpdLgm+brq10nI9zM1BpX1kpDbh3NLl3RSnVq6ZSkfg= github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= +github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= +github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8= +github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= +github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= +github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys= +github.com/mdlayher/netlink v1.4.0 h1:n3ARR+Fm0dDv37dj5wSWZXDKcy+U0zwcXS3zKMnSiT0= +github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs= github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= +github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -609,11 +629,13 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= -github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netlink v1.1.1-0.20210510164352-d17758a128bf h1:JMdq3oWN6LQKfRpwVfjwuaZcPN4vGdVBzvOU2mzUXd8= +github.com/vishvananda/netlink v1.1.1-0.20210510164352-d17758a128bf/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= -github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae h1:4hwBBUfQCFe3Cym0ZtKyq7L16eZUtYKs+BaHDN6mAns= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vmware/go-ipfix v0.5.7 h1:twv8mrXwlXhlWdixogGmyKwLia/G7hsZM46xd8aO+rc= github.com/vmware/go-ipfix v0.5.7/go.mod h1:yzbG1rv+yJ8GeMrRm+MDhOV3akygNZUHLhC1pDoD2AY= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= @@ -662,8 +684,9 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI= +golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -734,11 +757,17 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210504132125-bbd867fde50d h1:nTDGCTeAu2LhcsHTRzjyIUbZHCJ4QePArsm27Hka0UM= +golang.org/x/net v0.0.0-20210504132125-bbd867fde50d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -794,18 +823,30 @@ golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -817,8 +858,9 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -875,6 +917,10 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b h1:XDLXhn7ryprJVo+Lpkiib6CIuXE2031GDwtfEm7vLjI= +golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210506160403-92e472f520a5 h1:LpEwXnbN4q2EIPkqbG9KHBUrducJYDOOdL+eMcJAlFo= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210506160403-92e472f520a5/go.mod h1:+1XihzyZUBJcSc5WO9SwNA7v26puQwOEDwanaxfNXPQ= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= diff --git a/hack/generate-manifest.sh b/hack/generate-manifest.sh index 1ecdf687406..6a779c635f5 100755 --- a/hack/generate-manifest.sh +++ b/hack/generate-manifest.sh @@ -44,6 +44,8 @@ Generate a YAML manifest for Antrea using Kustomize and print it to stdout. --custom-adm-controller Generates a manifest with custom Antrea admission controller to validate/mutate resources. --hw-offload Generates a manifest with hw-offload enabled in the antrea-ovs container. --sriov Generates a manifest which enables use of Kubelet API for SR-IOV device info. + --wireguard-go Generate a manifest with WireGuard (golang implementation) encryption enabled. + This option will work only for Kind clusters (when using '--kind'). --help, -h Print this message and exit In 'release' mode, environment variables IMG_NAME and IMG_TAG must be set. @@ -84,6 +86,7 @@ SIMULATOR=false CUSTOM_ADM_CONTROLLER=false HW_OFFLOAD=false SRIOV=false +WIREGUARD_GO=false while [[ $# -gt 0 ]] do @@ -170,6 +173,10 @@ case $key in --sriov) SRIOV=true shift + ;; + --wireguard-go) + WIREGUARD_GO=true + shift ;; -h|--help) print_usage @@ -229,6 +236,18 @@ if [[ "$ENCAP_MODE" != "" ]] && [[ "$ENCAP_MODE" != "encap" ]] && ! $PROXY; then exit 1 fi +if "$WIREGUARD_GO" && "$IPSEC"; then + echoerr "Cannot use '--wireguard-go' together with '--ipsec'" + print_help + exit 1 +fi + +if "$WIREGUARD_GO" && ! "$KIND"; then + echoerr "--wireguard-go works only for Kind clusters" + print_help + exit 1 +fi + THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" source $THIS_DIR/verify-kustomize.sh @@ -260,11 +279,15 @@ if $KIND; then fi if $IPSEC; then - sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*enableIPSecTunnel[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/enableIPSecTunnel: true/" antrea-agent.conf + sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*trafficEncryptionMode[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/trafficEncryptionMode: ipsec/" antrea-agent.conf # change the tunnel type to GRE which works better with IPSec encryption than other types. sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*tunnelType[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/tunnelType: gre/" antrea-agent.conf fi +if $WIREGUARD_GO; then + sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*trafficEncryptionMode[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/trafficEncryptionMode: wireguard/" antrea-agent.conf +fi + if $ALLFEATURES; then sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*AntreaPolicy[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/ AntreaPolicy: true/" antrea-agent.conf sed -i.bak -E "s/^[[:space:]]*#[[:space:]]*FlowExporter[[:space:]]*:[[:space:]]*[a-z]+[[:space:]]*$/ FlowExporter: true/" antrea-agent.conf @@ -410,6 +433,11 @@ if $KIND; then # change initContainer script and remove SYS_MODULE capability $KUSTOMIZE edit add patch --path installCni.yml + # inject the wireguard-go container to run WireGuard in userspace + if $WIREGUARD_GO; then + $KUSTOMIZE edit add patch --path wireguardGo.yml + fi + if $ON_DELETE; then $KUSTOMIZE edit add patch --path onDeleteUpdateStrategy.yml fi diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go index 75cba398c23..b766bb45115 100644 --- a/pkg/agent/agent.go +++ b/pkg/agent/agent.go @@ -42,6 +42,7 @@ import ( "antrea.io/antrea/pkg/agent/route" "antrea.io/antrea/pkg/agent/types" "antrea.io/antrea/pkg/agent/util" + "antrea.io/antrea/pkg/agent/wireguard" "antrea.io/antrea/pkg/features" "antrea.io/antrea/pkg/ovs/ovsconfig" "antrea.io/antrea/pkg/ovs/ovsctl" @@ -72,6 +73,7 @@ type Initializer struct { ovsBridgeClient ovsconfig.OVSBridgeClient ofClient openflow.Client routeClient route.Interface + wireGuardClient wireguard.Interface ifaceStore interfacestore.InterfaceStore ovsBridge string hostGateway string // name of gateway port on the OVS bridge @@ -80,6 +82,7 @@ type Initializer struct { serviceCIDRv6 *net.IPNet // K8s Service ClusterIP CIDR in IPv6 networkConfig *config.NetworkConfig nodeConfig *config.NodeConfig + wireGuardConfig *config.WireGuardConfig enableProxy bool // networkReadyCh should be closed once the Node's network is ready. // The CNI server will wait for it before handling any CNI Add requests. @@ -99,6 +102,7 @@ func NewInitializer( serviceCIDR *net.IPNet, serviceCIDRv6 *net.IPNet, networkConfig *config.NetworkConfig, + wireGuardConfig *config.WireGuardConfig, networkReadyCh chan<- struct{}, stopCh <-chan struct{}, enableProxy bool) *Initializer { @@ -114,6 +118,7 @@ func NewInitializer( serviceCIDR: serviceCIDR, serviceCIDRv6: serviceCIDRv6, networkConfig: networkConfig, + wireGuardConfig: wireGuardConfig, networkReadyCh: networkReadyCh, stopCh: stopCh, enableProxy: enableProxy, @@ -125,6 +130,11 @@ func (i *Initializer) GetNodeConfig() *config.NodeConfig { return i.nodeConfig } +// GetNodeConfig returns the NodeConfig. +func (i *Initializer) GetWireGuardClient() wireguard.Interface { + return i.wireGuardClient +} + // setupOVSBridge sets up the OVS bridge and create host gateway interface and tunnel port func (i *Initializer) setupOVSBridge() error { if err := i.ovsBridgeClient.Create(); err != nil { @@ -259,8 +269,15 @@ func (i *Initializer) Initialize() error { return err } - if err := i.initializeIPSec(); err != nil { - return err + switch i.networkConfig.TrafficEncryptionMode { + case config.TrafficEncryptionModeIPSec: + if err := i.initializeIPSec(); err != nil { + return err + } + case config.TrafficEncryptionModeWireGuard: + if err := i.initializeWireGuard(); err != nil { + return err + } } if err := i.prepareHostNetwork(); err != nil { @@ -337,7 +354,7 @@ func (i *Initializer) initOpenFlowPipeline() error { roundInfo := getRoundInfo(i.ovsBridgeClient) // Set up all basic flows. - ofConnCh, err := i.ofClient.Initialize(roundInfo, i.nodeConfig, i.networkConfig.TrafficEncapMode) + ofConnCh, err := i.ofClient.Initialize(roundInfo, i.nodeConfig, i.networkConfig) if err != nil { klog.Errorf("Failed to initialize openflow client: %v", err) return err @@ -737,7 +754,10 @@ func (i *Initializer) initNodeLocalConfig() error { NodeIPv6Addr: nodeIPv6Addr, NodeTransportIPv4Addr: transportIPv4Addr, NodeTransportIPv6Addr: transportIPv6Addr, - UplinkNetConfig: new(config.AdapterNetConfig)} + UplinkNetConfig: new(config.AdapterNetConfig), + NodeLocalInterfaceMTU: localIntf.MTU, + WireGuardConfig: i.wireGuardConfig, + } mtu, err := i.getNodeMTU(localIntf) if err != nil { @@ -797,10 +817,6 @@ func (i *Initializer) initNodeLocalConfig() error { // initializeIPSec checks if preconditions are met for using IPsec and reads the IPsec PSK value. func (i *Initializer) initializeIPSec() error { - if !i.networkConfig.EnableIPSecTunnel { - return nil - } - // At the time the agent is initialized and this code is executed, the // OVS daemons are already running given that we have successfully // connected to OVSDB. Given that the start_ovs script deletes existing @@ -830,6 +846,18 @@ func (i *Initializer) initializeIPSec() error { return nil } +// initializeWireguard checks if preconditions are met for using WireGuard and initializes WireGuard client or cleans up. +func (i *Initializer) initializeWireGuard() error { + i.wireGuardConfig.MTU = i.nodeConfig.NodeLocalInterfaceMTU - config.WireGuardOverhead + wgClient, err := wireguard.New(i.client, i.nodeConfig, i.wireGuardConfig) + if err != nil { + return err + } + + i.wireGuardClient = wgClient + return i.wireGuardClient.Init() +} + // readIPSecPSK reads the IPsec PSK value from environment variable ANTREA_IPSEC_PSK func (i *Initializer) readIPSecPSK() error { i.networkConfig.IPSecPSK = os.Getenv(ipsecPSKEnvKey) @@ -914,7 +942,7 @@ func (i *Initializer) getNodeMTU(localIntf *net.Interface) (int, error) { mtu -= config.IPv6ExtraOverhead } } - if i.networkConfig.EnableIPSecTunnel { + if i.networkConfig.TrafficEncryptionMode == config.TrafficEncryptionModeIPSec { mtu -= config.IPSecESPOverhead } return mtu, nil diff --git a/pkg/agent/agent_test.go b/pkg/agent/agent_test.go index 3b975e736f3..7bb95a2df73 100644 --- a/pkg/agent/agent_test.go +++ b/pkg/agent/agent_test.go @@ -175,84 +175,93 @@ func TestInitNodeLocalConfig(t *testing.T) { ipNet: transportIPNet, } tests := []struct { - name string - trafficEncapMode config.TrafficEncapModeType - transportInterface *testTransInterface - tunnelType ovsconfig.TunnelType - mtu int - expectedMTU int - expectedNodeAnnotation map[string]string + name string + trafficEncapMode config.TrafficEncapModeType + transportInterface *testTransInterface + tunnelType ovsconfig.TunnelType + mtu int + expectedMTU int + expectedNodeLocalIfaceMTU int + expectedNodeAnnotation map[string]string }{ { - name: "noencap mode", - trafficEncapMode: config.TrafficEncapModeNoEncap, - mtu: 0, - expectedMTU: 1500, - expectedNodeAnnotation: map[string]string{types.NodeMACAddressAnnotationKey: macAddr.String()}, + name: "noencap mode", + trafficEncapMode: config.TrafficEncapModeNoEncap, + mtu: 0, + expectedNodeLocalIfaceMTU: 1500, + expectedMTU: 1500, + expectedNodeAnnotation: map[string]string{types.NodeMACAddressAnnotationKey: macAddr.String()}, }, { - name: "hybrid mode", - trafficEncapMode: config.TrafficEncapModeHybrid, - mtu: 0, - expectedMTU: 1500, - expectedNodeAnnotation: map[string]string{types.NodeMACAddressAnnotationKey: macAddr.String()}, + name: "hybrid mode", + trafficEncapMode: config.TrafficEncapModeHybrid, + mtu: 0, + expectedNodeLocalIfaceMTU: 1500, + expectedMTU: 1500, + expectedNodeAnnotation: map[string]string{types.NodeMACAddressAnnotationKey: macAddr.String()}, }, { - name: "encap mode, geneve tunnel", - trafficEncapMode: config.TrafficEncapModeEncap, - tunnelType: ovsconfig.GeneveTunnel, - mtu: 0, - expectedMTU: 1450, - expectedNodeAnnotation: nil, + name: "encap mode, geneve tunnel", + trafficEncapMode: config.TrafficEncapModeEncap, + tunnelType: ovsconfig.GeneveTunnel, + mtu: 0, + expectedNodeLocalIfaceMTU: 1500, + expectedMTU: 1450, + expectedNodeAnnotation: nil, }, { - name: "encap mode, mtu specified", - trafficEncapMode: config.TrafficEncapModeEncap, - tunnelType: ovsconfig.GeneveTunnel, - mtu: 1400, - expectedMTU: 1400, - expectedNodeAnnotation: nil, + name: "encap mode, mtu specified", + trafficEncapMode: config.TrafficEncapModeEncap, + tunnelType: ovsconfig.GeneveTunnel, + mtu: 1400, + expectedNodeLocalIfaceMTU: 1500, + expectedMTU: 1400, + expectedNodeAnnotation: nil, }, { - name: "noencap mode with transportInterface", - trafficEncapMode: config.TrafficEncapModeNoEncap, - transportInterface: testTransportIface, - mtu: 0, - expectedMTU: 1500, + name: "noencap mode with transportInterface", + trafficEncapMode: config.TrafficEncapModeNoEncap, + transportInterface: testTransportIface, + mtu: 0, + expectedNodeLocalIfaceMTU: 1500, + expectedMTU: 1500, expectedNodeAnnotation: map[string]string{ types.NodeMACAddressAnnotationKey: transportIfaceMAC.String(), types.NodeTransportAddressAnnotationKey: transportIP.String(), }, }, { - name: "hybrid mode with transportInterface", - trafficEncapMode: config.TrafficEncapModeHybrid, - transportInterface: testTransportIface, - mtu: 0, - expectedMTU: 1500, + name: "hybrid mode with transportInterface", + trafficEncapMode: config.TrafficEncapModeHybrid, + transportInterface: testTransportIface, + mtu: 0, + expectedNodeLocalIfaceMTU: 1500, + expectedMTU: 1500, expectedNodeAnnotation: map[string]string{ types.NodeMACAddressAnnotationKey: transportIfaceMAC.String(), types.NodeTransportAddressAnnotationKey: transportIP.String(), }, }, { - name: "encap mode with transportInterface, geneve tunnel", - trafficEncapMode: config.TrafficEncapModeEncap, - transportInterface: testTransportIface, - tunnelType: ovsconfig.GeneveTunnel, - mtu: 0, - expectedMTU: 1450, + name: "encap mode with transportInterface, geneve tunnel", + trafficEncapMode: config.TrafficEncapModeEncap, + transportInterface: testTransportIface, + tunnelType: ovsconfig.GeneveTunnel, + mtu: 0, + expectedNodeLocalIfaceMTU: 1500, + expectedMTU: 1450, expectedNodeAnnotation: map[string]string{ types.NodeTransportAddressAnnotationKey: transportIP.String(), }, }, { - name: "encap mode with transportInterface, mtu specified", - trafficEncapMode: config.TrafficEncapModeEncap, - transportInterface: testTransportIface, - tunnelType: ovsconfig.GeneveTunnel, - mtu: 1400, - expectedMTU: 1400, + name: "encap mode with transportInterface, mtu specified", + trafficEncapMode: config.TrafficEncapModeEncap, + transportInterface: testTransportIface, + tunnelType: ovsconfig.GeneveTunnel, + mtu: 1400, + expectedNodeLocalIfaceMTU: 1500, + expectedMTU: 1400, expectedNodeAnnotation: map[string]string{ types.NodeTransportAddressAnnotationKey: transportIP.String(), }, @@ -285,6 +294,7 @@ func TestInitNodeLocalConfig(t *testing.T) { PodIPv4CIDR: podCIDR, NodeIPv4Addr: nodeIPNet, NodeTransportIPv4Addr: nodeIPNet, + NodeLocalInterfaceMTU: tt.expectedNodeLocalIfaceMTU, NodeMTU: tt.expectedMTU, UplinkNetConfig: new(config.AdapterNetConfig), } diff --git a/pkg/agent/config/node_config.go b/pkg/agent/config/node_config.go index 2089d359f9a..1138f1057ad 100644 --- a/pkg/agent/config/node_config.go +++ b/pkg/agent/config/node_config.go @@ -34,9 +34,10 @@ const ( ) const ( - VXLANOverhead = 50 - GeneveOverhead = 50 - GREOverhead = 38 + VXLANOverhead = 50 + GeneveOverhead = 50 + GREOverhead = 38 + WireGuardOverhead = 80 // IPsec ESP can add a maximum of 38 bytes to the packet including the ESP // header and trailer. IPSecESPOverhead = 38 @@ -68,6 +69,17 @@ type AdapterNetConfig struct { Routes []interface{} } +type WireGuardConfig struct { + // Name is the name of WireGurad interface. e.g. antrea-wg0. + Name string + // LinkIndex is the link index of WireGuard interface. + LinkIndex int + // Port is the port for the WireGuard to receive traffic. + Port int + // The MTU of WireGuard interface. + MTU int +} + // Local Node configurations retrieved from K8s API or host networking state. type NodeConfig struct { // The Node's name used in Kubernetes. @@ -91,6 +103,8 @@ type NodeConfig struct { NodeTransportIPv4Addr *net.IPNet // The IPv6 address on the Node's transport interface. It is used for tunneling or routing the Pod traffic across Nodes. NodeTransportIPv6Addr *net.IPNet + // The original MTU of Node's local interface which has the K8s Node IP. + NodeLocalInterfaceMTU int // Set either via defaultMTU config in antrea.yaml or auto discovered. // Auto discovery will use MTU value of the Node's primary interface. // For Encap and Hybrid mode, Node MTU will be adjusted to account for encap header. @@ -99,6 +113,8 @@ type NodeConfig struct { GatewayConfig *GatewayConfig // The config of the OVS bridge uplink interface. Only for Windows Node. UplinkNetConfig *AdapterNetConfig + // The config of the WireGuard interface. + WireGuardConfig *WireGuardConfig } func (n *NodeConfig) String() string { @@ -108,11 +124,11 @@ func (n *NodeConfig) String() string { // User provided network configuration parameters. type NetworkConfig struct { - TrafficEncapMode TrafficEncapModeType - TunnelType ovsconfig.TunnelType - EnableIPSecTunnel bool - IPSecPSK string - TransportIface string + TrafficEncapMode TrafficEncapModeType + TunnelType ovsconfig.TunnelType + TrafficEncryptionMode TrafficEncryptionModeType + IPSecPSK string + TransportIface string } // IsIPv4Enabled returns true if the cluster network supports IPv4. @@ -126,3 +142,17 @@ func IsIPv6Enabled(nodeConfig *NodeConfig, trafficEncapMode TrafficEncapModeType return nodeConfig.PodIPv6CIDR != nil || (trafficEncapMode.IsNetworkPolicyOnly() && nodeConfig.NodeIPv6Addr != nil) } + +// NeedsEncapToPeer returns true if Pod traffic to peer Node needs to be encapsulated. +// If WireGuard is enabled, traffic does not need to be encapsulated from OVS side. +func (nc *NetworkConfig) NeedsEncapToPeer(peerIP net.IP, localIP *net.IPNet) bool { + if nc.TrafficEncryptionMode == TrafficEncryptionModeWireGuard { + return false + } + return nc.TrafficEncapMode == TrafficEncapModeEncap || (nc.TrafficEncapMode == TrafficEncapModeHybrid && !localIP.Contains(peerIP)) +} + +// NeedsDirectRoutingToPeer returns true if Pod traffic to peer Node needs a direct route installed to the routing table. +func (nc *NetworkConfig) NeedsDirectRoutingToPeer(peerIP net.IP, localIP *net.IPNet) bool { + return (nc.TrafficEncapMode == TrafficEncapModeNoEncap || nc.TrafficEncapMode == TrafficEncapModeHybrid) && localIP.Contains(peerIP) +} diff --git a/pkg/agent/config/node_config_test.go b/pkg/agent/config/node_config_test.go new file mode 100644 index 00000000000..8e23eb41411 --- /dev/null +++ b/pkg/agent/config/node_config_test.go @@ -0,0 +1,165 @@ +// Copyright 2021 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package config + +import ( + "net" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNetworkConfig_NeedsEncapToPeer(t *testing.T) { + tests := []struct { + name string + nc *NetworkConfig + peerIP net.IP + localIP *net.IPNet + expBool bool + }{ + { + name: "encap-mode", + nc: &NetworkConfig{ + TrafficEncapMode: TrafficEncapModeEncap, + }, + peerIP: net.ParseIP("192.168.0.5"), + localIP: &net.IPNet{ + IP: net.IPv4(192, 168, 0, 1), + Mask: net.IPv4Mask(255, 255, 255, 0), + }, + expBool: true, + }, + { + name: "no-encap-mode", + nc: &NetworkConfig{ + TrafficEncapMode: TrafficEncapModeNoEncap, + }, + peerIP: net.ParseIP("192.168.0.5"), + localIP: &net.IPNet{ + IP: net.IPv4(192, 168, 0, 1), + Mask: net.IPv4Mask(255, 255, 255, 0), + }, + expBool: false, + }, + { + name: "hybrid-mode-need-encapsulated", + nc: &NetworkConfig{ + TrafficEncapMode: TrafficEncapModeHybrid, + }, + peerIP: net.ParseIP("10.0.0.0"), + localIP: &net.IPNet{ + IP: net.IPv4(192, 168, 0, 1), + Mask: net.IPv4Mask(255, 255, 255, 0), + }, + expBool: true, + }, + { + name: "hybrid-mode-no-need-encapsulated", + nc: &NetworkConfig{ + TrafficEncapMode: TrafficEncapModeHybrid, + }, + peerIP: net.ParseIP("192.168.0.5"), + localIP: &net.IPNet{ + IP: net.IPv4(192, 168, 0, 1), + Mask: net.IPv4Mask(255, 255, 255, 0), + }, + expBool: false, + }, + { + name: "WireGuard enabled", + nc: &NetworkConfig{ + TrafficEncapMode: TrafficEncapModeEncap, + TrafficEncryptionMode: TrafficEncryptionModeWireGuard, + }, + peerIP: net.ParseIP("10.0.0.0"), + localIP: &net.IPNet{ + IP: net.IPv4(192, 168, 0, 1), + Mask: net.IPv4Mask(255, 255, 255, 0), + }, + expBool: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actualBool := tt.nc.NeedsEncapToPeer(tt.peerIP, tt.localIP) + assert.Equal(t, tt.expBool, actualBool, "NeedsEncapToPeer did not return correct result") + }) + } +} + +func TestNetworkConfig_NeedsDirectRoutingToPeer(t *testing.T) { + tests := []struct { + name string + nc *NetworkConfig + peerIP net.IP + localIP *net.IPNet + expBool bool + }{ + { + name: "encap-mode", + nc: &NetworkConfig{ + TrafficEncapMode: TrafficEncapModeEncap, + }, + peerIP: net.ParseIP("192.168.0.5"), + localIP: &net.IPNet{ + IP: net.IPv4(192, 168, 0, 1), + Mask: net.IPv4Mask(255, 255, 255, 0), + }, + expBool: false, + }, + { + name: "no-encap-mode-need-direct-routing", + nc: &NetworkConfig{ + TrafficEncapMode: TrafficEncapModeNoEncap, + }, + peerIP: net.ParseIP("192.168.0.5"), + localIP: &net.IPNet{ + IP: net.IPv4(192, 168, 0, 1), + Mask: net.IPv4Mask(255, 255, 255, 0), + }, + expBool: true, + }, + { + name: "no-encap-mode-no-need-direct-routing", + nc: &NetworkConfig{ + TrafficEncapMode: TrafficEncapModeNoEncap, + }, + peerIP: net.ParseIP("192.168.1.5"), + localIP: &net.IPNet{ + IP: net.IPv4(192, 168, 0, 1), + Mask: net.IPv4Mask(255, 255, 255, 0), + }, + expBool: false, + }, + { + name: "hybrid-mode-need-direct-routing", + nc: &NetworkConfig{ + TrafficEncapMode: TrafficEncapModeHybrid, + }, + peerIP: net.ParseIP("192.168.0.5"), + localIP: &net.IPNet{ + IP: net.IPv4(192, 168, 0, 1), + Mask: net.IPv4Mask(255, 255, 255, 0), + }, + expBool: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actualBool := tt.nc.NeedsDirectRoutingToPeer(tt.peerIP, tt.localIP) + assert.Equal(t, tt.expBool, actualBool, "NeedsDirectRoutingToPeer did not return correct result") + }) + } +} diff --git a/pkg/agent/config/traffic_encap_mode.go b/pkg/agent/config/traffic_encap_mode.go index 878d53c5047..430a621bfcd 100644 --- a/pkg/agent/config/traffic_encap_mode.go +++ b/pkg/agent/config/traffic_encap_mode.go @@ -15,7 +15,6 @@ package config import ( - "net" "strings" ) @@ -77,13 +76,3 @@ func (m TrafficEncapModeType) SupportsNoEncap() bool { func (m TrafficEncapModeType) SupportsEncap() bool { return m == TrafficEncapModeEncap || m == TrafficEncapModeHybrid } - -// NeedsEncapToPeer returns true if Pod traffic to peer Node needs to be encapsulated. -func (m TrafficEncapModeType) NeedsEncapToPeer(peerIP net.IP, localIP *net.IPNet) bool { - return (m == TrafficEncapModeEncap) || (m == TrafficEncapModeHybrid && !localIP.Contains(peerIP)) -} - -// NeedsDirectRoutingToPeer returns true if Pod traffic to peer Node needs a direct route installed to the routing table. -func (m TrafficEncapModeType) NeedsDirectRoutingToPeer(peerIP net.IP, localIP *net.IPNet) bool { - return (m == TrafficEncapModeNoEncap || m == TrafficEncapModeHybrid) && localIP.Contains(peerIP) -} diff --git a/pkg/agent/config/traffic_encap_mode_test.go b/pkg/agent/config/traffic_encap_mode_test.go index 234a5bb8518..23cf15380fc 100644 --- a/pkg/agent/config/traffic_encap_mode_test.go +++ b/pkg/agent/config/traffic_encap_mode_test.go @@ -1,7 +1,6 @@ package config import ( - "net" "testing" "github.com/stretchr/testify/assert" @@ -76,117 +75,3 @@ func TestTrafficEncapModeTypeSupports(t *testing.T) { }) } } - -func TestTrafficEncapModeTypeNeedsEncapToPeer(t *testing.T) { - tests := []struct { - name string - mode TrafficEncapModeType - peerIP net.IP - localIP *net.IPNet - expBool bool - }{ - { - name: "encap-mode", - mode: 0, - peerIP: net.ParseIP("192.168.0.5"), - localIP: &net.IPNet{ - IP: net.IPv4(192, 168, 0, 1), - Mask: net.IPv4Mask(255, 255, 255, 0), - }, - expBool: true, - }, - { - name: "no-encap-mode", - mode: 1, - peerIP: net.ParseIP("192.168.0.5"), - localIP: &net.IPNet{ - IP: net.IPv4(192, 168, 0, 1), - Mask: net.IPv4Mask(255, 255, 255, 0), - }, - expBool: false, - }, - { - name: "hybrid-mode-need-encapsulated", - mode: 2, - peerIP: net.ParseIP("10.0.0.0"), - localIP: &net.IPNet{ - IP: net.IPv4(192, 168, 0, 1), - Mask: net.IPv4Mask(255, 255, 255, 0), - }, - expBool: true, - }, - { - name: "hybrid-mode-no-need-encapsulated", - mode: 2, - peerIP: net.ParseIP("192.168.0.5"), - localIP: &net.IPNet{ - IP: net.IPv4(192, 168, 0, 1), - Mask: net.IPv4Mask(255, 255, 255, 0), - }, - expBool: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - actualBool := tt.mode.NeedsEncapToPeer(tt.peerIP, tt.localIP) - assert.Equal(t, tt.expBool, actualBool, "NeedsEncapToPeer did not return correct result") - }) - } -} - -func TestTrafficEncapModeTypeNeedsDirectRoutingToPeer(t *testing.T) { - tests := []struct { - name string - mode TrafficEncapModeType - peerIP net.IP - localIP *net.IPNet - expBool bool - }{ - { - name: "encap-mode", - mode: 0, - peerIP: net.ParseIP("192.168.0.5"), - localIP: &net.IPNet{ - IP: net.IPv4(192, 168, 0, 1), - Mask: net.IPv4Mask(255, 255, 255, 0), - }, - expBool: false, - }, - { - name: "no-encap-mode-need-direct-routing", - mode: 1, - peerIP: net.ParseIP("192.168.0.5"), - localIP: &net.IPNet{ - IP: net.IPv4(192, 168, 0, 1), - Mask: net.IPv4Mask(255, 255, 255, 0), - }, - expBool: true, - }, - { - name: "no-encap-mode-no-need-direct-routing", - mode: 1, - peerIP: net.ParseIP("192.168.1.5"), - localIP: &net.IPNet{ - IP: net.IPv4(192, 168, 0, 1), - Mask: net.IPv4Mask(255, 255, 255, 0), - }, - expBool: false, - }, - { - name: "hybrid-mode-need-direct-routing", - mode: 2, - peerIP: net.ParseIP("192.168.0.5"), - localIP: &net.IPNet{ - IP: net.IPv4(192, 168, 0, 1), - Mask: net.IPv4Mask(255, 255, 255, 0), - }, - expBool: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - actualBool := tt.mode.NeedsDirectRoutingToPeer(tt.peerIP, tt.localIP) - assert.Equal(t, tt.expBool, actualBool, "NeedsDirectRoutingToPeer did not return correct result") - }) - } -} diff --git a/pkg/agent/config/traffic_encryption_mode.go b/pkg/agent/config/traffic_encryption_mode.go new file mode 100644 index 00000000000..e21d445a1eb --- /dev/null +++ b/pkg/agent/config/traffic_encryption_mode.go @@ -0,0 +1,60 @@ +// Copyright 2021 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package config + +import ( + "strings" +) + +type TrafficEncryptionModeType int + +const ( + TrafficEncryptionModeNone TrafficEncryptionModeType = iota + TrafficEncryptionModeIPSec + TrafficEncryptionModeWireGuard + TrafficEncryptionModeInvalid = -1 +) + +var ( + encryptionModeStrs = [...]string{ + "None", + "IPsec", + "WireGuard", + } +) + +// GetTrafficEncryptionModeFromStr returns true and TrafficEncryptionModeType corresponding to input string. +// Otherwise, false and undefined value is returned +func GetTrafficEncryptionModeFromStr(str string) (bool, TrafficEncryptionModeType) { + for idx, ms := range encryptionModeStrs { + if strings.EqualFold(ms, str) { + return true, TrafficEncryptionModeType(idx) + } + } + return false, TrafficEncryptionModeInvalid +} + +func GetTrafficEncryptionModes() []TrafficEncryptionModeType { + return []TrafficEncryptionModeType{ + TrafficEncryptionModeNone, + TrafficEncryptionModeIPSec, + TrafficEncryptionModeWireGuard, + } +} + +// String returns value in string. +func (m TrafficEncryptionModeType) String() string { + return encryptionModeStrs[m] +} diff --git a/pkg/agent/config/traffic_encryption_mode_test.go b/pkg/agent/config/traffic_encryption_mode_test.go new file mode 100644 index 00000000000..3aebda6cfc5 --- /dev/null +++ b/pkg/agent/config/traffic_encryption_mode_test.go @@ -0,0 +1,66 @@ +// Copyright 2021 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package config + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetTrafficEncryptionModes(t *testing.T) { + modes := GetTrafficEncryptionModes() + expModes := []TrafficEncryptionModeType{0, 1, 2} + assert.Equal(t, expModes, modes, "TestGetTrafficEncryptionModes received unexpected encryption modes") +} + +func TestGetTrafficEncryptionModeFromStr(t *testing.T) { + tests := []struct { + name string + input string + expBool bool + expMode TrafficEncryptionModeType + }{ + {"None by default", "none", true, TrafficEncryptionModeNone}, + {"IPsec", "ipsec", true, TrafficEncryptionModeIPSec}, + {"WireGuard", "wireguard", true, TrafficEncryptionModeWireGuard}, + {"Capital case", "IPsec", true, TrafficEncryptionModeIPSec}, + {"Invalid string", "wire guard", false, TrafficEncryptionModeInvalid}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ok, mode := GetTrafficEncryptionModeFromStr(tt.input) + assert.Equal(t, tt.expBool, ok, "GetTrafficEncryptionModeFromStr did not return correct boolean") + assert.Equal(t, tt.expMode, mode, "GetTrafficEncryptionModeFromStr did not return correct string") + }) + } +} + +func TestTrafficEncryptionModeType_String(t *testing.T) { + tests := []struct { + name string + m TrafficEncryptionModeType + want string + }{ + {"None", TrafficEncryptionModeNone, "None"}, + {"IPsec", TrafficEncryptionModeIPSec, "IPsec"}, + {"WireGuard", TrafficEncryptionModeWireGuard, "WireGuard"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, tt.m.String(), "TrafficEncryptionModeType.String did not return correct string representation") + }) + } +} diff --git a/pkg/agent/controller/noderoute/node_route_controller.go b/pkg/agent/controller/noderoute/node_route_controller.go index 5cd5b09416e..d158602e50d 100644 --- a/pkg/agent/controller/noderoute/node_route_controller.go +++ b/pkg/agent/controller/noderoute/node_route_controller.go @@ -38,6 +38,7 @@ import ( "antrea.io/antrea/pkg/agent/route" "antrea.io/antrea/pkg/agent/types" "antrea.io/antrea/pkg/agent/util" + "antrea.io/antrea/pkg/agent/wireguard" "antrea.io/antrea/pkg/ovs/ovsconfig" utilip "antrea.io/antrea/pkg/util/ip" "antrea.io/antrea/pkg/util/k8s" @@ -74,7 +75,8 @@ type Controller struct { // installedNodes records routes and flows installation states of Nodes. // The key is the host name of the Node, the value is the nodeRouteInfo of the Node. // A node will be in the map after its flows and routes are installed successfully. - installedNodes cache.Indexer + installedNodes cache.Indexer + wireGuardClient wireguard.Interface } // NewNodeRouteController instantiates a new Controller object which will process Node events @@ -87,7 +89,9 @@ func NewNodeRouteController( routeClient route.Interface, interfaceStore interfacestore.InterfaceStore, networkConfig *config.NetworkConfig, - nodeConfig *config.NodeConfig) *Controller { + nodeConfig *config.NodeConfig, + wireguardClient wireguard.Interface, +) *Controller { nodeInformer := informerFactory.Core().V1().Nodes() controller := &Controller{ kubeClient: kubeClient, @@ -102,6 +106,7 @@ func NewNodeRouteController( nodeListerSynced: nodeInformer.Informer().HasSynced, queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(minRetryDelay, maxRetryDelay), "noderoute"), installedNodes: cache.NewIndexer(nodeRouteInfoKeyFunc, cache.Indexers{nodeRouteInfoPodCIDRIndexName: nodeRouteInfoPodCIDRIndexFunc}), + wireGuardClient: wireguardClient, } nodeInformer.Informer().AddEventHandlerWithResyncPeriod( cache.ResourceEventHandlerFuncs{ @@ -134,11 +139,12 @@ func nodeRouteInfoPodCIDRIndexFunc(obj interface{}) ([]string, error) { // nodeRouteInfo is the route related information extracted from corev1.Node. type nodeRouteInfo struct { - nodeName string - podCIDRs []*net.IPNet - nodeIPs *utilip.DualStackIPs - gatewayIPs *utilip.DualStackIPs - nodeMAC net.HardwareAddr + nodeName string + podCIDRs []*net.IPNet + nodeIPs *utilip.DualStackIPs + gatewayIPs *utilip.DualStackIPs + nodeMAC net.HardwareAddr + wireGuardPublicKey string } // enqueueNode adds an object to the controller work queue @@ -208,7 +214,7 @@ func (c *Controller) removeStaleTunnelPorts() error { // knownInterfaces is the list of interfaces currently in the local cache. knownInterfaces := c.interfaceStore.GetInterfaceKeysByType(interfacestore.TunnelInterface) - if c.networkConfig.EnableIPSecTunnel { + if c.networkConfig.TrafficEncryptionMode == config.TrafficEncryptionModeIPSec { for _, node := range nodes { interfaceConfig, found := c.interfaceStore.GetNodeTunnelInterface(node.Name) if !found { @@ -276,9 +282,30 @@ func (c *Controller) reconcile() error { if err := c.removeStaleTunnelPorts(); err != nil { return fmt.Errorf("error when removing stale tunnel ports: %v", err) } + if err := c.removeStaleWireGuardPeers(); err != nil { + return fmt.Errorf("error when removing stale WireGuard peers: %v", err) + } return nil } +// removeStaleWireGuardPeers deletes stale WireGuard peers if necessary. +func (c *Controller) removeStaleWireGuardPeers() error { + if c.networkConfig.TrafficEncryptionMode != config.TrafficEncryptionModeWireGuard { + return nil + } + nodes, err := c.nodeLister.List(labels.Everything()) + if err != nil { + return fmt.Errorf("error when listing Nodes: %v", err) + } + currentPeerPublicKeys := make(map[string]string) + for _, n := range nodes { + if pubkey, ok := n.Annotations[types.NodeWireGuardPublicAnnotationKey]; ok { + currentPeerPublicKeys[n.Name] = pubkey + } + } + return c.wireGuardClient.RemoveStalePeers(currentPeerPublicKeys) +} + // Run will create defaultWorkers workers (go routines) which will process the Node events from the // workqueue. func (c *Controller) Run(stopCh <-chan struct{}) { @@ -300,7 +327,7 @@ func (c *Controller) Run(stopCh <-chan struct{}) { } if err := c.reconcile(); err != nil { - klog.Errorf("Error during %s reconciliation", controllerName) + klog.ErrorS(err, "Error during reconciliation", "controller", controllerName) } for i := 0; i < defaultWorkers; i++ { @@ -399,7 +426,7 @@ func (c *Controller) deleteNodeRoute(nodeName string) error { } c.installedNodes.Delete(obj) - if c.networkConfig.EnableIPSecTunnel { + if c.networkConfig.TrafficEncryptionMode == config.TrafficEncryptionModeIPSec { interfaceConfig, ok := c.interfaceStore.GetNodeTunnelInterface(nodeName) if !ok { // Tunnel port not created for this Node. @@ -412,6 +439,12 @@ func (c *Controller) deleteNodeRoute(nodeName string) error { } c.interfaceStore.DeleteInterface(interfaceConfig) } + + if c.networkConfig.TrafficEncryptionMode == config.TrafficEncryptionModeWireGuard { + if err := c.wireGuardClient.DeletePeer(nodeName); err != nil { + return fmt.Errorf("delete WireGuard peer %s failed: %v", nodeName, err) + } + } return nil } @@ -425,10 +458,14 @@ func (c *Controller) addNodeRoute(nodeName string, node *corev1.Node) error { if err != nil { return err } + peerWireGuardPublicKey := node.Annotations[types.NodeWireGuardPublicAnnotationKey] nrInfo, installed, _ := c.installedNodes.GetByKey(nodeName) - if installed && nrInfo.(*nodeRouteInfo).nodeMAC.String() == peerNodeMAC.String() && peerNodeIPs.Equal(*nrInfo.(*nodeRouteInfo).nodeIPs) { - // Route is already added for this Node and both Node MAC and transport IP are not changed. + // Route is already added for this Node and Node MAC, transport IP + // and WireGuard public key are not changed. + if installed && nrInfo.(*nodeRouteInfo).nodeMAC.String() == peerNodeMAC.String() && + peerNodeIPs.Equal(*nrInfo.(*nodeRouteInfo).nodeIPs) && + nrInfo.(*nodeRouteInfo).wireGuardPublicKey == peerWireGuardPublicKey { return nil } @@ -485,7 +522,7 @@ func (c *Controller) addNodeRoute(nodeName string, node *corev1.Node) error { } var ipsecTunOFPort uint32 - if c.networkConfig.EnableIPSecTunnel { + if c.networkConfig.TrafficEncryptionMode == config.TrafficEncryptionModeIPSec { // Create a separate tunnel port for the Node, as OVS IPSec monitor needs to // read PSK and remote IP from the Node's tunnel interface to create IPSec // security policies. @@ -500,6 +537,16 @@ func (c *Controller) addNodeRoute(nodeName string, node *corev1.Node) error { ipsecTunOFPort = uint32(port) } + if c.networkConfig.TrafficEncryptionMode == config.TrafficEncryptionModeWireGuard && peerWireGuardPublicKey != "" { + peerNodeIP := peerNodeIPs.IPv4 + if peerNodeIP == nil { + peerNodeIP = peerNodeIPs.IPv6 + } + if err := c.wireGuardClient.UpdatePeer(nodeName, peerWireGuardPublicKey, peerNodeIP, peerPodCIDRs); err != nil { + return err + } + } + if err = c.ofClient.InstallNodeFlows( nodeName, peerConfigs, @@ -523,12 +570,14 @@ func (c *Controller) addNodeRoute(nodeName string, node *corev1.Node) error { peerGatewayIPs.IPv4 = peerGatewayIP } } + c.installedNodes.Add(&nodeRouteInfo{ - nodeName: nodeName, - podCIDRs: peerPodCIDRs, - nodeIPs: peerNodeIPs, - gatewayIPs: peerGatewayIPs, - nodeMAC: peerNodeMAC, + nodeName: nodeName, + podCIDRs: peerPodCIDRs, + nodeIPs: peerNodeIPs, + gatewayIPs: peerGatewayIPs, + nodeMAC: peerNodeMAC, + wireGuardPublicKey: peerWireGuardPublicKey, }) return err diff --git a/pkg/agent/controller/noderoute/node_route_controller_test.go b/pkg/agent/controller/noderoute/node_route_controller_test.go index 658116e244d..0aa196a67ab 100644 --- a/pkg/agent/controller/noderoute/node_route_controller_test.go +++ b/pkg/agent/controller/noderoute/node_route_controller_test.go @@ -72,7 +72,7 @@ func newController(t *testing.T, networkConfig *config.NetworkConfig) (*fakeCont c := NewNodeRouteController(clientset, informerFactory, ofClient, ovsClient, routeClient, interfaceStore, networkConfig, &config.NodeConfig{GatewayConfig: &config.GatewayConfig{ IPv4: nil, MAC: gatewayMAC, - }}) + }}, nil) return &fakeController{ Controller: c, clientset: clientset, @@ -231,10 +231,10 @@ func TestIPInPodSubnets(t *testing.T) { func setup(t *testing.T, ifaces []*interfacestore.InterfaceConfig) (*fakeController, func()) { c, closeFn := newController(t, &config.NetworkConfig{ - TrafficEncapMode: 0, - TunnelType: ovsconfig.TunnelType("vxlan"), - EnableIPSecTunnel: true, - IPSecPSK: "changeme", + TrafficEncapMode: 0, + TunnelType: ovsconfig.TunnelType("vxlan"), + TrafficEncryptionMode: config.TrafficEncryptionModeIPSec, + IPSecPSK: "changeme", }) for _, i := range ifaces { c.interfaceStore.AddInterface(i) diff --git a/pkg/agent/openflow/client.go b/pkg/agent/openflow/client.go index c8f660b408f..2b8f4e0aa2c 100644 --- a/pkg/agent/openflow/client.go +++ b/pkg/agent/openflow/client.go @@ -40,7 +40,7 @@ type Client interface { // be called to ensure that the set of OVS flows is correct. All flows programmed in the // switch which match the current round number will be deleted before any new flow is // installed. - Initialize(roundInfo types.RoundInfo, config *config.NodeConfig, encapMode config.TrafficEncapModeType) (<-chan struct{}, error) + Initialize(roundInfo types.RoundInfo, config *config.NodeConfig, networkconfig *config.NetworkConfig) (<-chan struct{}, error) // InstallGatewayFlows sets up flows related to an OVS gateway port, the gateway must exist. InstallGatewayFlows() error @@ -417,13 +417,13 @@ func (c *client) InstallNodeFlows(hostname string, peerConfigs map[*net.IPNet]net.IP, tunnelPeerIPs *utilip.DualStackIPs, ipsecTunOFPort uint32, - remoteGatewayMAC net.HardwareAddr) error { + remoteGatewayMAC net.HardwareAddr, +) error { c.replayMutex.RLock() defer c.replayMutex.RUnlock() var flows []binding.Flow localGatewayMAC := c.nodeConfig.GatewayConfig.MAC - for peerPodCIDR, peerGatewayIP := range peerConfigs { isIPv6 := peerGatewayIP.To4() == nil tunnelPeerIP := tunnelPeerIPs.IPv4 @@ -434,10 +434,10 @@ func (c *client) InstallNodeFlows(hostname string, // only work for IPv4 addresses. flows = append(flows, c.arpResponderFlow(peerGatewayIP, cookie.Node)) } - if (!isIPv6 && c.encapMode.NeedsEncapToPeer(tunnelPeerIPs.IPv4, c.nodeConfig.NodeTransportIPv4Addr)) || - (isIPv6 && c.encapMode.NeedsEncapToPeer(tunnelPeerIPs.IPv6, c.nodeConfig.NodeTransportIPv6Addr)) { - // tunnelPeerIP is the Node Internal Address. In a dual-stack setup, one Node has 2 Node Internal - // Addresses (IPv4 and IPv6) . + // tunnelPeerIP is the Node Internal Address. In a dual-stack setup, one Node has 2 Node Internal + // Addresses (IPv4 and IPv6) . + if (!isIPv6 && c.networkConfig.NeedsEncapToPeer(tunnelPeerIPs.IPv4, c.nodeConfig.NodeTransportIPv4Addr)) || + (isIPv6 && c.networkConfig.NeedsEncapToPeer(tunnelPeerIPs.IPv6, c.nodeConfig.NodeTransportIPv6Addr)) { flows = append(flows, c.l3FwdFlowToRemote(localGatewayMAC, *peerPodCIDR, tunnelPeerIP, cookie.Node)) } else { flows = append(flows, c.l3FwdFlowToRemoteViaRouting(localGatewayMAC, remoteGatewayMAC, cookie.Node, tunnelPeerIP, peerPodCIDR)...) @@ -481,7 +481,7 @@ func (c *client) InstallPodFlows(interfaceName string, podInterfaceIPs []net.IP, // Add L3 Routing flows to rewrite Pod's dst MAC for all validate IPs. flows = append(flows, c.l3FwdFlowToPod(localGatewayMAC, podInterfaceIPs, podInterfaceMAC, cookie.Pod)...) - if c.encapMode.IsNetworkPolicyOnly() { + if c.networkConfig.TrafficEncapMode.IsNetworkPolicyOnly() { // In policy-only mode, traffic to local Pod is routed based on destination IP. flows = append(flows, c.l3FwdFlowRouteToPod(podInterfaceIPs, podInterfaceMAC, cookie.Pod)..., @@ -713,7 +713,7 @@ func (c *client) initialize() error { if err := c.ofEntryOperations.AddAll(c.rejectBypassNetworkpolicyFlows(cookie.Default)); err != nil { return fmt.Errorf("failed to install flows to skip generated reject responses: %v", err) } - if c.encapMode.IsNetworkPolicyOnly() { + if c.networkConfig.TrafficEncapMode.IsNetworkPolicyOnly() { if err := c.setupPolicyOnlyFlows(); err != nil { return fmt.Errorf("failed to setup policy only flows: %w", err) } @@ -729,14 +729,14 @@ func (c *client) initialize() error { return nil } -func (c *client) Initialize(roundInfo types.RoundInfo, nodeConfig *config.NodeConfig, encapMode config.TrafficEncapModeType) (<-chan struct{}, error) { +func (c *client) Initialize(roundInfo types.RoundInfo, nodeConfig *config.NodeConfig, networkConfig *config.NetworkConfig) (<-chan struct{}, error) { c.nodeConfig = nodeConfig - c.encapMode = encapMode + c.networkConfig = networkConfig - if config.IsIPv4Enabled(nodeConfig, encapMode) { + if config.IsIPv4Enabled(nodeConfig, c.networkConfig.TrafficEncapMode) { c.ipProtocols = append(c.ipProtocols, binding.ProtocolIP) } - if config.IsIPv6Enabled(nodeConfig, encapMode) { + if config.IsIPv6Enabled(nodeConfig, c.networkConfig.TrafficEncapMode) { c.ipProtocols = append(c.ipProtocols, binding.ProtocolIPv6) } @@ -993,11 +993,11 @@ func (c *client) InitialTLVMap() error { } func (c *client) IsIPv4Enabled() bool { - return config.IsIPv4Enabled(c.nodeConfig, c.encapMode) + return config.IsIPv4Enabled(c.nodeConfig, c.networkConfig.TrafficEncapMode) } func (c *client) IsIPv6Enabled() bool { - return config.IsIPv6Enabled(c.nodeConfig, c.encapMode) + return config.IsIPv6Enabled(c.nodeConfig, c.networkConfig.TrafficEncapMode) } // setBasePacketOutBuilder sets base IP properties of a packetOutBuilder which can have more packet data added. diff --git a/pkg/agent/openflow/client_test.go b/pkg/agent/openflow/client_test.go index 387ab70a059..f0d35e1c3df 100644 --- a/pkg/agent/openflow/client_test.go +++ b/pkg/agent/openflow/client_test.go @@ -49,7 +49,11 @@ var ( IPv6: gwIPv6, MAC: gwMAC, } - nodeConfig = &config.NodeConfig{GatewayConfig: gatewayConfig} + nodeConfig = &config.NodeConfig{ + GatewayConfig: gatewayConfig, + WireGuardConfig: &config.WireGuardConfig{}, + } + networkConfig = &config.NetworkConfig{} ) func installNodeFlows(ofClient Client, cacheKey string) (int, error) { @@ -104,6 +108,7 @@ func TestIdempotentFlowInstallation(t *testing.T) { client.cookieAllocator = cookie.NewAllocator(0) client.ofEntryOperations = m client.nodeConfig = nodeConfig + client.networkConfig = networkConfig m.EXPECT().AddAll(gomock.Any()).Return(nil).Times(1) // Installing the flows should succeed, and all the flows should be added into the cache. @@ -132,6 +137,7 @@ func TestIdempotentFlowInstallation(t *testing.T) { client.cookieAllocator = cookie.NewAllocator(0) client.ofEntryOperations = m client.nodeConfig = nodeConfig + client.networkConfig = networkConfig errorCall := m.EXPECT().AddAll(gomock.Any()).Return(errors.New("Bundle error")).Times(1) m.EXPECT().AddAll(gomock.Any()).Return(nil).After(errorCall) @@ -173,6 +179,7 @@ func TestFlowInstallationFailed(t *testing.T) { client.cookieAllocator = cookie.NewAllocator(0) client.ofEntryOperations = m client.nodeConfig = nodeConfig + client.networkConfig = networkConfig // We generate an error for AddAll call. m.EXPECT().AddAll(gomock.Any()).Return(errors.New("Bundle error")) @@ -207,6 +214,7 @@ func TestConcurrentFlowInstallation(t *testing.T) { client.cookieAllocator = cookie.NewAllocator(0) client.ofEntryOperations = m client.nodeConfig = nodeConfig + client.networkConfig = networkConfig var concurrentCalls atomic.Value // set to true if we observe concurrent calls timeoutCh := make(chan struct{}) diff --git a/pkg/agent/openflow/network_policy_test.go b/pkg/agent/openflow/network_policy_test.go index 86bbb6916c8..efdffd06602 100644 --- a/pkg/agent/openflow/network_policy_test.go +++ b/pkg/agent/openflow/network_policy_test.go @@ -156,6 +156,7 @@ func TestInstallPolicyRuleFlows(t *testing.T) { c = prepareClient(ctrl) c.nodeConfig = &config.NodeConfig{PodIPv4CIDR: podIPv4CIDR, PodIPv6CIDR: nil} + c.networkConfig = &config.NetworkConfig{} c.ipProtocols = []binding.Protocol{binding.ProtocolIP} defaultAction := crdv1alpha1.RuleActionAllow ruleID1 := uint32(101) @@ -511,6 +512,7 @@ func TestBatchInstallPolicyRuleFlows(t *testing.T) { c.cookieAllocator = cookie.NewAllocator(0) c.ofEntryOperations = mockOperations c.nodeConfig = &config.NodeConfig{PodIPv4CIDR: podIPv4CIDR, PodIPv6CIDR: nil} + c.networkConfig = &config.NetworkConfig{} c.ipProtocols = []binding.Protocol{binding.ProtocolIP} c.deterministic = true @@ -636,6 +638,7 @@ func TestInstallPolicyRuleFlowsInDualStackCluster(t *testing.T) { c = prepareClient(ctrl) c.nodeConfig = &config.NodeConfig{PodIPv4CIDR: podIPv4CIDR, PodIPv6CIDR: podIPv6CIDR} + c.networkConfig = &config.NetworkConfig{} c.ipProtocols = []binding.Protocol{binding.ProtocolIP, binding.ProtocolIPv6} defaultAction := crdv1alpha1.RuleActionAllow ruleID1 := uint32(101) diff --git a/pkg/agent/openflow/pipeline.go b/pkg/agent/openflow/pipeline.go index 187e30f9bf9..7adf2cc0a77 100644 --- a/pkg/agent/openflow/pipeline.go +++ b/pkg/agent/openflow/pipeline.go @@ -295,6 +295,7 @@ type client struct { enableAntreaPolicy bool enableDenyTracking bool enableEgress bool + enableWireGuard bool roundInfo types.RoundInfo cookieAllocator cookie.Allocator bridge binding.Bridge @@ -320,7 +321,7 @@ type client struct { // replayMutex provides exclusive access to the OFSwitch to the ReplayFlows method. replayMutex sync.RWMutex nodeConfig *config.NodeConfig - encapMode config.TrafficEncapModeType + networkConfig *config.NetworkConfig gatewayOFPort uint32 // ovsDatapathType is the type of the datapath used by the bridge. ovsDatapathType ovsconfig.OVSDatapathType @@ -876,7 +877,7 @@ func (c *client) traceflowL2ForwardOutputFlows(dataplaneTag uint8, liveTraffic, flows := []binding.Flow{} l2FwdOutTable := c.pipeline[L2ForwardingOutTable] for _, ipProtocol := range c.ipProtocols { - if c.encapMode.SupportsEncap() { + if c.networkConfig.TrafficEncapMode.SupportsEncap() { // SendToController and Output if output port is tunnel port. fb1 := l2FwdOutTable.BuildFlow(priorityNormal+3). MatchRegFieldWithValue(TargetOFPortField, config.DefaultTunOFPort). diff --git a/pkg/agent/openflow/pipeline_windows.go b/pkg/agent/openflow/pipeline_windows.go index 26604f074df..5411fa8186e 100644 --- a/pkg/agent/openflow/pipeline_windows.go +++ b/pkg/agent/openflow/pipeline_windows.go @@ -94,7 +94,7 @@ func (c *client) hostBridgeUplinkFlows(localSubnet net.IPNet, category cookie.Ca Cookie(c.cookieAllocator.Request(category).Raw()). Done(), } - if c.encapMode.SupportsNoEncap() { + if c.networkConfig.TrafficEncapMode.SupportsNoEncap() { // If NoEncap is enabled, the reply packets from remote Pod can be forwarded to local Pod directly. // by explicitly resubmitting them to serviceHairpinTable and marking "macRewriteMark" at same time. flows = append(flows, c.pipeline[ClassifierTable].BuildFlow(priorityHigh).MatchProtocol(binding.ProtocolIP). @@ -111,7 +111,7 @@ func (c *client) hostBridgeUplinkFlows(localSubnet net.IPNet, category cookie.Ca func (c *client) l3FwdFlowToRemoteViaRouting(localGatewayMAC net.HardwareAddr, remoteGatewayMAC net.HardwareAddr, category cookie.Category, peerIP net.IP, peerPodCIDR *net.IPNet) []binding.Flow { - if c.encapMode.NeedsDirectRoutingToPeer(peerIP, c.nodeConfig.NodeTransportIPv4Addr) && remoteGatewayMAC != nil { + if c.networkConfig.NeedsDirectRoutingToPeer(peerIP, c.nodeConfig.NodeTransportIPv4Addr) && remoteGatewayMAC != nil { ipProto := getIPProtocol(peerIP) l3FwdTable := c.pipeline[l3ForwardingTable] // It enhances Windows Noencap mode performance by bypassing host network. diff --git a/pkg/agent/openflow/testing/mock_openflow.go b/pkg/agent/openflow/testing/mock_openflow.go index 203770d8310..abf0bfe9f2e 100644 --- a/pkg/agent/openflow/testing/mock_openflow.go +++ b/pkg/agent/openflow/testing/mock_openflow.go @@ -251,7 +251,7 @@ func (mr *MockClientMockRecorder) InitialTLVMap() *gomock.Call { } // Initialize mocks base method -func (m *MockClient) Initialize(arg0 types.RoundInfo, arg1 *config.NodeConfig, arg2 config.TrafficEncapModeType) (<-chan struct{}, error) { +func (m *MockClient) Initialize(arg0 types.RoundInfo, arg1 *config.NodeConfig, arg2 *config.NetworkConfig) (<-chan struct{}, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Initialize", arg0, arg1, arg2) ret0, _ := ret[0].(<-chan struct{}) diff --git a/pkg/agent/route/route_linux.go b/pkg/agent/route/route_linux.go index b1c49e7c699..9ae2b3bc07d 100644 --- a/pkg/agent/route/route_linux.go +++ b/pkg/agent/route/route_linux.go @@ -605,7 +605,16 @@ func (c *Client) AddRoutes(podCIDR *net.IPNet, nodeName string, nodeIP, nodeGwIP Dst: podCIDR, } var routes []*netlink.Route - if c.networkConfig.TrafficEncapMode.NeedsEncapToPeer(nodeIP, nodeTransportIPAddr) { + // If WireGuard is enabled, create a route via WireGuard device regardless of the traffic encapsulation modes. + if c.networkConfig.TrafficEncryptionMode == config.TrafficEncryptionModeWireGuard { + route.LinkIndex = c.nodeConfig.WireGuardConfig.LinkIndex + route.Scope = netlink.SCOPE_LINK + if podCIDR.IP.To4() != nil { + route.Src = c.nodeConfig.GatewayConfig.IPv4 + } else { + route.Src = c.nodeConfig.GatewayConfig.IPv6 + } + } else if c.networkConfig.NeedsEncapToPeer(nodeIP, nodeTransportIPAddr) { if podCIDR.IP.To4() == nil { // "on-link" is not identified in IPv6 route entries, so split the configuration into 2 entries. routes = []*netlink.Route{ @@ -619,7 +628,7 @@ func (c *Client) AddRoutes(podCIDR *net.IPNet, nodeName string, nodeIP, nodeGwIP } route.LinkIndex = c.nodeConfig.GatewayConfig.LinkIndex route.Gw = nodeGwIP - } else if c.networkConfig.TrafficEncapMode.NeedsDirectRoutingToPeer(nodeIP, nodeTransportIPAddr) { + } else if c.networkConfig.NeedsDirectRoutingToPeer(nodeIP, nodeTransportIPAddr) { // NoEncap traffic to Node on the same subnet. // Set the peerNodeIP as next hop. route.Gw = nodeIP diff --git a/pkg/agent/route/route_windows.go b/pkg/agent/route/route_windows.go index 8e5b694e33f..337241af07d 100644 --- a/pkg/agent/route/route_windows.go +++ b/pkg/agent/route/route_windows.go @@ -118,10 +118,10 @@ func (c *Client) AddRoutes(podCIDR *net.IPNet, nodeName string, peerNodeIP, peer DestinationSubnet: podCIDR, RouteMetric: util.DefaultMetric, } - if c.networkConfig.TrafficEncapMode.NeedsEncapToPeer(peerNodeIP, c.nodeConfig.NodeTransportIPv4Addr) { + if c.networkConfig.NeedsEncapToPeer(peerNodeIP, c.nodeConfig.NodeTransportIPv4Addr) { route.LinkIndex = c.nodeConfig.GatewayConfig.LinkIndex route.GatewayAddress = peerGwIP - } else if c.networkConfig.TrafficEncapMode.NeedsDirectRoutingToPeer(peerNodeIP, c.nodeConfig.NodeTransportIPv4Addr) { + } else if c.networkConfig.NeedsDirectRoutingToPeer(peerNodeIP, c.nodeConfig.NodeTransportIPv4Addr) { // NoEncap traffic to Node on the same subnet. // Set the peerNodeIP as next hop. route.LinkIndex = c.bridgeInfIndex diff --git a/pkg/agent/types/annotations.go b/pkg/agent/types/annotations.go index 586a1b51b26..fa7c941bea0 100644 --- a/pkg/agent/types/annotations.go +++ b/pkg/agent/types/annotations.go @@ -20,4 +20,7 @@ const ( // NodeTransportAddressAnnotationKey represents the key of the interface's IP addresses on which the Node transfers Pod traffic in the Annotations of the Node. NodeTransportAddressAnnotationKey string = "node.antrea.io/transport-addresses" + + // NodeWireGuardPublicAnnotationKey represents the key of the Node's WireGuard public key in the Annotations of the Node. + NodeWireGuardPublicAnnotationKey string = "node.antrea.io/wireguard-public-key" ) diff --git a/pkg/agent/wireguard/client_linux.go b/pkg/agent/wireguard/client_linux.go new file mode 100644 index 00000000000..1aea2d869b3 --- /dev/null +++ b/pkg/agent/wireguard/client_linux.go @@ -0,0 +1,227 @@ +//go:build linux + +// Copyright 2021 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package wireguard + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net" + "strconv" + "sync" + + "github.com/vishvananda/netlink" + "golang.org/x/sys/unix" + "golang.zx2c4.com/wireguard/wgctrl" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apitypes "k8s.io/apimachinery/pkg/types" + clientset "k8s.io/client-go/kubernetes" + "k8s.io/client-go/util/retry" + "k8s.io/klog/v2" + + "antrea.io/antrea/pkg/agent/config" + "antrea.io/antrea/pkg/agent/types" +) + +const defaultWireGuardInterfaceName = "antrea-wg0" + +var zeroKey = wgtypes.Key{} + +// wgctrlClient is an interface to mock wgctrl.Client +type wgctrlClient interface { + io.Closer + Devices() ([]*wgtypes.Device, error) + Device(name string) (*wgtypes.Device, error) + ConfigureDevice(name string, config wgtypes.Config) error +} + +var _ Interface = (*client)(nil) + +type client struct { + wgClient wgctrlClient + nodeName string + k8sClient clientset.Interface + privateKey wgtypes.Key + peerPublicKeyByNodeName *sync.Map + wireGuardConfig *config.WireGuardConfig +} + +func New(clientSet clientset.Interface, nodeConfig *config.NodeConfig, wireGuardConfig *config.WireGuardConfig) (Interface, error) { + wgClient, err := wgctrl.New() + if err != nil { + return nil, err + } + if wireGuardConfig.Name == "" { + wireGuardConfig.Name = defaultWireGuardInterfaceName + } + c := &client{ + wgClient: wgClient, + nodeName: nodeConfig.Name, + k8sClient: clientSet, + wireGuardConfig: wireGuardConfig, + peerPublicKeyByNodeName: &sync.Map{}, + } + return c, nil +} + +func (client *client) Init() error { + link := &netlink.Wireguard{LinkAttrs: netlink.LinkAttrs{Name: client.wireGuardConfig.Name, MTU: client.wireGuardConfig.MTU}} + err := netlink.LinkAdd(link) + // ignore existing link as it may have already been created or managed by userspace process. + if err != nil && !errors.Is(err, unix.EEXIST) { + if errors.Is(err, unix.EOPNOTSUPP) { + return fmt.Errorf("WireGuard not supported by the Linux kernel (netlink: %w), make sure the WireGuard kernel module is loaded", err) + } + return err + } + if err := netlink.LinkSetUp(link); err != nil { + return err + } + client.wireGuardConfig.LinkIndex = link.Attrs().Index + wgDev, err := client.wgClient.Device(client.wireGuardConfig.Name) + if err != nil { + return err + } + client.privateKey = wgDev.PrivateKey + // WireGuard private key will be persistent across agent restarts. So we only need to + // generate a new private key if it is empty (all zero). + if client.privateKey == zeroKey { + newPkey, err := wgtypes.GeneratePrivateKey() + if err != nil { + return err + } + client.privateKey = newPkey + } + cfg := wgtypes.Config{ + PrivateKey: &client.privateKey, + ListenPort: &client.wireGuardConfig.Port, + ReplacePeers: false, + } + patch, _ := json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "annotations": map[string]string{ + types.NodeWireGuardPublicAnnotationKey: client.privateKey.PublicKey().String(), + }, + }, + }) + if err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + _, err := client.k8sClient.CoreV1().Nodes().Patch(context.TODO(), client.nodeName, apitypes.MergePatchType, patch, metav1.PatchOptions{}) + return err + }); err != nil { + return fmt.Errorf("error when patching the Node with the '%s' annotation: %w", types.NodeWireGuardPublicAnnotationKey, err) + } + + return client.wgClient.ConfigureDevice(client.wireGuardConfig.Name, cfg) +} + +func (client *client) RemoveStalePeers(currentPeerPublickeys map[string]string) error { + wgdev, err := client.wgClient.Device(client.wireGuardConfig.Name) + if err != nil { + return err + } + restoredPeerPublicKeys := make(map[wgtypes.Key]struct{}) + for _, peer := range wgdev.Peers { + restoredPeerPublicKeys[peer.PublicKey] = struct{}{} + } + + for nodeName, pubKey := range currentPeerPublickeys { + pubKey, err := wgtypes.ParseKey(pubKey) + if err != nil { + klog.ErrorS(err, "Parse WireGuard public key error", "nodeName", nodeName, "publicKey", pubKey) + continue + } + if _, exist := restoredPeerPublicKeys[pubKey]; exist { + // Save known Node name and public key mappings for tracking of public key changes when calling UpdatePeer. + client.peerPublicKeyByNodeName.Store(nodeName, pubKey) + delete(restoredPeerPublicKeys, pubKey) + } + } + for k := range restoredPeerPublicKeys { + if err := client.deletePeerByPublicKey(k); err != nil { + klog.ErrorS(err, "Delete WireGuard peer error") + return err + } + } + return nil +} + +func (client *client) UpdatePeer(nodeName, publicKeyString string, peerNodeIP net.IP, podCIDRs []*net.IPNet) error { + pubKey, err := wgtypes.ParseKey(publicKeyString) + if err != nil { + return err + } + var allowedIPs []net.IPNet + + if peerNodeIP.To16() == nil { + return fmt.Errorf("peer Node IP is not valid: %s", peerNodeIP.String()) + } + + for _, cidr := range podCIDRs { + allowedIPs = append(allowedIPs, *cidr) + } + + if key, exist := client.peerPublicKeyByNodeName.Load(nodeName); exist { + cachedPeerPubKey := key.(wgtypes.Key) + if cachedPeerPubKey != pubKey { + klog.InfoS("WireGuard peer public key updated", "nodeName", nodeName, "publicKey", publicKeyString) + // delete old peer by public key. + if err := client.deletePeerByPublicKey(cachedPeerPubKey); err != nil { + return err + } + } + } + endpoint := net.JoinHostPort(peerNodeIP.String(), strconv.Itoa(client.wireGuardConfig.Port)) + endpointUDP, err := net.ResolveUDPAddr("udp", endpoint) + if err != nil { + return err + } + client.peerPublicKeyByNodeName.Store(nodeName, pubKey) + peerConfig := wgtypes.PeerConfig{ + PublicKey: pubKey, + Endpoint: endpointUDP, + AllowedIPs: allowedIPs, + ReplaceAllowedIPs: true, + } + cfg := wgtypes.Config{ + ReplacePeers: false, + Peers: []wgtypes.PeerConfig{peerConfig}, + } + return client.wgClient.ConfigureDevice(client.wireGuardConfig.Name, cfg) +} + +func (client *client) deletePeerByPublicKey(pubKey wgtypes.Key) error { + cfg := wgtypes.Config{Peers: []wgtypes.PeerConfig{ + {PublicKey: pubKey, Remove: true}, + }} + return client.wgClient.ConfigureDevice(client.wireGuardConfig.Name, cfg) +} + +func (client *client) DeletePeer(nodeName string) error { + key, exist := client.peerPublicKeyByNodeName.Load(nodeName) + if !exist { + return nil + } + peerPublicKey := key.(wgtypes.Key) + if err := client.deletePeerByPublicKey(peerPublicKey); err != nil { + return err + } + client.peerPublicKeyByNodeName.Delete(nodeName) + return nil +} diff --git a/pkg/agent/wireguard/client_test.go b/pkg/agent/wireguard/client_test.go new file mode 100644 index 00000000000..e490318f07a --- /dev/null +++ b/pkg/agent/wireguard/client_test.go @@ -0,0 +1,379 @@ +//go:build linux + +// Copyright 2021 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package wireguard + +import ( + "net" + "sync" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + + "antrea.io/antrea/pkg/agent/config" +) + +type fakeWireGuardClient struct { + peers map[wgtypes.Key]wgtypes.Peer +} + +func (f *fakeWireGuardClient) Close() error { + return nil +} + +func (f *fakeWireGuardClient) Devices() ([]*wgtypes.Device, error) { + return nil, nil +} + +func (f *fakeWireGuardClient) Device(name string) (*wgtypes.Device, error) { + var res []wgtypes.Peer + for _, p := range f.peers { + res = append(res, p) + } + return &wgtypes.Device{ + Peers: res, + }, nil +} + +func (f *fakeWireGuardClient) ConfigureDevice(name string, cfg wgtypes.Config) error { + for _, c := range cfg.Peers { + if c.Remove { + delete(f.peers, c.PublicKey) + } else { + f.peers[c.PublicKey] = wgtypes.Peer{ + PublicKey: c.PublicKey, + Endpoint: c.Endpoint, + AllowedIPs: c.AllowedIPs, + } + } + } + return nil +} + +func getFakeClient() *client { + return &client{ + wgClient: &fakeWireGuardClient{}, + nodeName: "fake-node-1", + wireGuardConfig: &config.WireGuardConfig{ + MTU: 1420, + Port: 12345, + }, + peerPublicKeyByNodeName: &sync.Map{}, + } +} + +func Test_RemoveStalePeers(t *testing.T) { + pk1, _ := wgtypes.GeneratePrivateKey() + pk2, _ := wgtypes.GeneratePrivateKey() + pk3, _ := wgtypes.GeneratePrivateKey() + tests := []struct { + name string + existingPeers map[wgtypes.Key]wgtypes.Peer + inputPublicKeys map[string]string + expectedPeers map[wgtypes.Key]wgtypes.Peer + expectdPeerPublicKeyByNodeName map[string]wgtypes.Key + }{ + { + "pass empty/nil slice should remove all existing peers", + map[wgtypes.Key]wgtypes.Peer{ + pk1.PublicKey(): {PublicKey: pk1.PublicKey()}, + pk2.PublicKey(): {PublicKey: pk2.PublicKey()}, + }, + nil, + map[wgtypes.Key]wgtypes.Peer{}, + map[string]wgtypes.Key{}, + }, + { + "args has no intersection with existing peers", + map[wgtypes.Key]wgtypes.Peer{ + pk1.PublicKey(): {PublicKey: pk1.PublicKey()}, + pk2.PublicKey(): {PublicKey: pk2.PublicKey()}, + }, + map[string]string{ + "node3": pk3.PublicKey().String(), + }, + map[wgtypes.Key]wgtypes.Peer{}, + map[string]wgtypes.Key{}, + }, + { + "should only keep peers passed by args", + map[wgtypes.Key]wgtypes.Peer{ + pk1.PublicKey(): {PublicKey: pk1.PublicKey()}, + pk2.PublicKey(): {PublicKey: pk2.PublicKey()}, + pk3.PublicKey(): {PublicKey: pk3.PublicKey()}, + }, + map[string]string{ + "node3": pk3.PublicKey().String(), + }, + map[wgtypes.Key]wgtypes.Peer{ + pk3.PublicKey(): {PublicKey: pk3.PublicKey()}, + }, + map[string]wgtypes.Key{ + "node3": pk3.PublicKey(), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + client := getFakeClient() + fc := &fakeWireGuardClient{peers: tt.existingPeers} + client.wgClient = fc + err := client.RemoveStalePeers(tt.inputPublicKeys) + require.NoError(t, err) + assert.Equal(t, tt.expectedPeers, fc.peers) + for k, v := range tt.expectdPeerPublicKeyByNodeName { + pk, ok := client.peerPublicKeyByNodeName.Load(k) + assert.True(t, ok) + pubKey, ok := pk.(wgtypes.Key) + assert.True(t, ok) + assert.Equal(t, v, pubKey) + } + }) + } +} + +func Test_UpdatePeer(t *testing.T) { + pk1, _ := wgtypes.GeneratePrivateKey() + pk2, _ := wgtypes.GeneratePrivateKey() + ip1, _, _ := net.ParseCIDR("10.20.30.42/32") + ip2, _, _ := net.ParseCIDR("10.20.30.43/32") + _, podCIDR1, _ := net.ParseCIDR("172.16.1.0/24") + _, podCIDR2, _ := net.ParseCIDR("172.16.2.0/24") + listenPort := getFakeClient().wireGuardConfig.Port + tests := []struct { + name string + existingPeers map[string]wgtypes.Peer + inputPeerNodeName string + inputPeerNodePublicKey string + inputPeerNodeIP net.IP + inputPodCIDRs []*net.IPNet + expectedError bool + expectedPeers map[wgtypes.Key]wgtypes.Peer + }{ + { + "call update peer to add new peers", + map[string]wgtypes.Peer{}, + "fake-node-2", + pk1.PublicKey().String(), + ip1, + []*net.IPNet{podCIDR1}, + false, + map[wgtypes.Key]wgtypes.Peer{ + pk1.PublicKey(): { + PublicKey: pk1.PublicKey(), + Endpoint: &net.UDPAddr{ + IP: ip1, + Port: listenPort, + }, + AllowedIPs: []net.IPNet{*podCIDR1}, + }, + }, + }, + { + "call update peer to update the public key of an existing peer", + map[string]wgtypes.Peer{ + "fake-node-2": { + PublicKey: pk2.PublicKey(), + Endpoint: &net.UDPAddr{ + IP: ip1, + Port: listenPort, + }, + AllowedIPs: []net.IPNet{*podCIDR1}, + }, + }, + "fake-node-2", + pk2.PublicKey().String(), + ip1, + []*net.IPNet{podCIDR1}, + false, + map[wgtypes.Key]wgtypes.Peer{ + pk2.PublicKey(): { + PublicKey: pk2.PublicKey(), + Endpoint: &net.UDPAddr{ + IP: ip1, + Port: listenPort, + }, + AllowedIPs: []net.IPNet{*podCIDR1}, + }, + }, + }, + { + "call update peer to update Node IP of an existing peer", + map[string]wgtypes.Peer{ + "fake-node-2": { + PublicKey: pk2.PublicKey(), + Endpoint: &net.UDPAddr{ + IP: ip1, + Port: listenPort, + }, + AllowedIPs: []net.IPNet{*podCIDR1}, + }, + }, + "fake-node-2", + pk2.PublicKey().String(), + ip2, + []*net.IPNet{podCIDR1}, + false, + map[wgtypes.Key]wgtypes.Peer{ + pk2.PublicKey(): { + PublicKey: pk2.PublicKey(), + Endpoint: &net.UDPAddr{ + IP: ip2, + Port: listenPort, + }, + AllowedIPs: []net.IPNet{*podCIDR1}, + }, + }, + }, + { + "call update peer to update Pod CIDR of an existing peer", + map[string]wgtypes.Peer{ + "fake-node-2": { + PublicKey: pk2.PublicKey(), + Endpoint: &net.UDPAddr{ + IP: ip1, + Port: listenPort, + }, + AllowedIPs: []net.IPNet{*podCIDR1}, + }, + }, + "fake-node-2", + pk2.PublicKey().String(), + ip1, + []*net.IPNet{podCIDR2}, + false, + map[wgtypes.Key]wgtypes.Peer{ + pk2.PublicKey(): { + PublicKey: pk2.PublicKey(), + Endpoint: &net.UDPAddr{ + IP: ip1, + Port: listenPort, + }, + AllowedIPs: []net.IPNet{*podCIDR2}, + }, + }, + }, + { + "call update peer with invalid public key", + map[string]wgtypes.Peer{ + "fake-node-2": { + PublicKey: pk2.PublicKey(), + Endpoint: &net.UDPAddr{ + IP: ip1, + Port: listenPort, + }, + AllowedIPs: []net.IPNet{*podCIDR1}, + }, + }, + "fake-node-2", + "invalid key", + ip1, + []*net.IPNet{podCIDR1}, + true, + map[wgtypes.Key]wgtypes.Peer{ + pk2.PublicKey(): { + PublicKey: pk2.PublicKey(), + Endpoint: &net.UDPAddr{ + IP: ip1, + Port: listenPort, + }, + AllowedIPs: []net.IPNet{*podCIDR1}, + }, + }, + }, + { + "call update peer with nil IP", + map[string]wgtypes.Peer{ + "fake-node-2": { + PublicKey: pk2.PublicKey(), + Endpoint: &net.UDPAddr{ + IP: ip1, + Port: listenPort, + }, + AllowedIPs: []net.IPNet{*podCIDR1}, + }, + }, + "fake-node-2", + pk2.PublicKey().String(), + nil, + []*net.IPNet{podCIDR1}, + true, + map[wgtypes.Key]wgtypes.Peer{ + pk2.PublicKey(): { + PublicKey: pk2.PublicKey(), + Endpoint: &net.UDPAddr{ + IP: ip1, + Port: listenPort, + }, + AllowedIPs: []net.IPNet{*podCIDR1}, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + client := getFakeClient() + fc := &fakeWireGuardClient{ + peers: map[wgtypes.Key]wgtypes.Peer{}, + } + for _, ec := range tt.existingPeers { + fc.peers[ec.PublicKey] = ec + } + client.wgClient = fc + err := client.UpdatePeer(tt.inputPeerNodeName, tt.inputPeerNodePublicKey, tt.inputPeerNodeIP, tt.inputPodCIDRs) + if tt.expectedError { + require.Error(t, err) + } else { + require.NoError(t, err) + } + assert.Equal(t, tt.expectedPeers, fc.peers) + }) + } +} + +func Test_DeletePeer(t *testing.T) { + client := getFakeClient() + fc := &fakeWireGuardClient{ + peers: map[wgtypes.Key]wgtypes.Peer{}, + } + client.wgClient = fc + pk1, _ := wgtypes.GeneratePrivateKey() + ip1, _, _ := net.ParseCIDR("10.20.30.42/32") + t.Run("delete non-existing peer", func(tt *testing.T) { + err := client.UpdatePeer("fake-node-1", pk1.String(), ip1, nil) + require.NoError(tt, err) + assert.Len(tt, fc.peers, 1) + _, ok := client.peerPublicKeyByNodeName.Load("fake-node-1") + assert.True(t, ok) + err = client.DeletePeer("fake-node-2") + require.NoError(tt, err) + assert.Len(tt, fc.peers, 1) + _, ok = client.peerPublicKeyByNodeName.Load("fake-node-1") + assert.True(t, ok) + }) + + t.Run("delete existing peer", func(tt *testing.T) { + err := client.DeletePeer("fake-node-1") + require.NoError(tt, err) + assert.Len(tt, fc.peers, 0) + _, ok := client.peerPublicKeyByNodeName.Load("fake-node-1") + assert.False(t, ok) + }) + +} diff --git a/pkg/agent/wireguard/client_windows.go b/pkg/agent/wireguard/client_windows.go new file mode 100644 index 00000000000..43c3c49a36a --- /dev/null +++ b/pkg/agent/wireguard/client_windows.go @@ -0,0 +1,28 @@ +// +build windows + +// Copyright 2021 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package wireguard + +import ( + "fmt" + + clientset "k8s.io/client-go/kubernetes" + + "antrea.io/antrea/pkg/agent/config" +) + +func New(clientSet clientset.Interface, nodeConfig *config.NodeConfig, wireGuardConfig *config.WireGuardConfig) (Interface, error) { + return nil, fmt.Errorf("WireGuard is not implemented for windows") +} diff --git a/pkg/agent/wireguard/interface.go b/pkg/agent/wireguard/interface.go new file mode 100644 index 00000000000..4b11b33709c --- /dev/null +++ b/pkg/agent/wireguard/interface.go @@ -0,0 +1,33 @@ +// Copyright 2021 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package wireguard + +import ( + "net" +) + +type Interface interface { + // Init initializes the WireGuard client and sets up the WireGuard device. + // It will generate a new private key if necessary and update the public key to the Node's annotation. + Init() error + // UpdatePeer updates WireGuard peer by provided public key and Node IPs. + // It will create a new WireGuard peer if the specified Node is not present in WireGuard device. + UpdatePeer(nodeName, publicKeyString string, peerNodeIP net.IP, podCIDRs []*net.IPNet) error + // RemoveStalePeers reads existing WireGuard peers from the WireGuard device and deletes those which are not in currentPeerPublickeys. + // currentPeerPublickeys is a map of Node names to public keys. It is useful to clean up stale WireGuard peers upon antrea starting. + RemoveStalePeers(currentPeerPublickeys map[string]string) error + // DeletePeer deletes the WireGuard peer by Node name. + DeletePeer(nodeName string) error +} diff --git a/pkg/apis/ports.go b/pkg/apis/ports.go index c22a0bd5a43..3138209ad00 100644 --- a/pkg/apis/ports.go +++ b/pkg/apis/ports.go @@ -22,4 +22,6 @@ const ( // AntreaAgentClusterMembershipPort is the default port for the antrea-agent cluster. // A gossip-based cluster will be created in the background when the egress feature is turned on. AntreaAgentClusterMembershipPort = 10351 + // WireGuardListenPort is the default port for WireGuard encrypted traffic. + WireGuardListenPort = 51820 ) diff --git a/plugins/octant/go.mod b/plugins/octant/go.mod index abe1095dbda..aa327884efd 100644 --- a/plugins/octant/go.mod +++ b/plugins/octant/go.mod @@ -68,13 +68,13 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.16.0 // indirect - golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect + golang.org/x/net v0.0.0-20210504132125-bbd867fde50d // indirect golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect - golang.org/x/text v0.3.4 // indirect + golang.org/x/text v0.3.6 // indirect golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect golang.org/x/tools v0.1.1 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/plugins/octant/go.sum b/plugins/octant/go.sum index c028ed816cb..9f1fdd2d2fe 100644 --- a/plugins/octant/go.sum +++ b/plugins/octant/go.sum @@ -336,6 +336,7 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -426,8 +427,14 @@ github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6t github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= +github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= +github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= +github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= +github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA= +github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= @@ -483,12 +490,21 @@ github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= +github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= +github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= +github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8= +github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= +github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= +github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys= +github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -659,8 +675,10 @@ github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netlink v1.1.1-0.20210510164352-d17758a128bf/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vmware-tanzu/octant v0.17.0 h1:2H2AiQU5C1RiHxxYrrOosDHHI9eV51nP+e9PjRP+c48= github.com/vmware-tanzu/octant v0.17.0/go.mod h1:lA32xKa6icUclg+DjAX/E/Id1cTqwCXZUem3RGEp/2A= github.com/vmware/go-ipfix v0.5.7/go.mod h1:yzbG1rv+yJ8GeMrRm+MDhOV3akygNZUHLhC1pDoD2AY= @@ -719,8 +737,9 @@ golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI= +golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -797,12 +816,18 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201024042810-be3efd7ff127/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210504132125-bbd867fde50d h1:nTDGCTeAu2LhcsHTRzjyIUbZHCJ4QePArsm27Hka0UM= +golang.org/x/net v0.0.0-20210504132125-bbd867fde50d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -863,6 +888,7 @@ golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -873,15 +899,26 @@ golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201024232916-9f70ab9862d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -893,8 +930,9 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -967,6 +1005,8 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210506160403-92e472f520a5/go.mod h1:+1XihzyZUBJcSc5WO9SwNA7v26puQwOEDwanaxfNXPQ= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= diff --git a/test/e2e/connectivity_test.go b/test/e2e/connectivity_test.go index d393c406666..3eecd06347f 100644 --- a/test/e2e/connectivity_test.go +++ b/test/e2e/connectivity_test.go @@ -197,7 +197,7 @@ func createPodsOnDifferentNodes(t *testing.T, data *TestData, tag string) (podIn for _, p := range pods.Items { os := clusterInfo.nodesOS[p.Spec.NodeName] - piMap[os] = append(piMap[os], podInfo{p.Name, os}) + piMap[os] = append(piMap[os], podInfo{p.Name, os, p.Spec.NodeName}) } var linIdx, winIdx int for linIdx != len(piMap["linux"]) && winIdx != len(piMap["windows"]) { @@ -242,29 +242,19 @@ func testPodConnectivityDifferentNodes(t *testing.T, data *TestData) { data.testPodConnectivityDifferentNodes(t) } -func (data *TestData) redeployAntrea(t *testing.T, enableIPSec bool) { +func (data *TestData) redeployAntrea(t *testing.T, option deployAntreaOptions) { var err error // export logs before deleting Antrea - if enableIPSec { - exportLogs(t, data, "beforeRedeployWithIPsec", false) - } else { - exportLogs(t, data, "beforeRedploy", false) - } + exportLogs(t, data, fmt.Sprintf("beforeRedeploy%s", option), false) t.Logf("Deleting Antrea Agent DaemonSet") if err = data.deleteAntrea(defaultTimeout); err != nil { t.Fatalf("Error when deleting Antrea DaemonSet: %v", err) } - t.Logf("Applying Antrea YAML") - if enableIPSec { - err = data.deployAntreaIPSec() - } else { - err = data.deployAntrea() - } + err = data.deployAntrea(option) if err != nil { t.Fatalf("Error when applying Antrea YAML: %v", err) } - // After redeploying Antrea with / without IPsec, we wait for watchForRestartsDuration and // count the number of container restarts. watchForRestartsDuration should be large enough // to detect issues, e.g. if there is an issue with the antrea-ipsec container. @@ -302,7 +292,7 @@ func testPodConnectivityAfterAntreaRestart(t *testing.T, data *TestData) { data.runPingMesh(t, podInfos[:numPods], agnhostContainerName) - data.redeployAntrea(t, false) + data.redeployAntrea(t, deployAntreaDefault) data.runPingMesh(t, podInfos[:numPods], agnhostContainerName) } diff --git a/test/e2e/fixtures.go b/test/e2e/fixtures.go index cc183ba9ec5..0dbb1373010 100644 --- a/test/e2e/fixtures.go +++ b/test/e2e/fixtures.go @@ -136,7 +136,7 @@ func skipIfFeatureDisabled(tb testing.TB, feature featuregate.Feature, checkAgen func ensureAntreaRunning(data *TestData) error { log.Println("Applying Antrea YAML") - if err := data.deployAntrea(); err != nil { + if err := data.deployAntrea(deployAntreaDefault); err != nil { return err } log.Println("Waiting for all Antrea DaemonSet Pods") diff --git a/test/e2e/framework.go b/test/e2e/framework.go index 1e118e7acd5..ca017e849ad 100644 --- a/test/e2e/framework.go +++ b/test/e2e/framework.go @@ -80,6 +80,8 @@ const ( agentContainerName string = "antrea-agent" antreaYML string = "antrea.yml" antreaIPSecYML string = "antrea-ipsec.yml" + antreaWireGuardGoYML string = "antrea-wireguard-go.yml" + antreaWireGuardGoCovYML string = "antrea-wireguard-go-coverage.yml" antreaCovYML string = "antrea-coverage.yml" antreaIPSecCovYML string = "antrea-ipsec-coverage.yml" flowAggregatorYML string = "flow-aggregator.yml" @@ -161,8 +163,9 @@ var provider providers.ProviderInterface // podInfo combines OS info with a Pod name. It is useful when choosing commands and options on Pods of different OS (Windows, Linux). type podInfo struct { - name string - os string + name string + os string + nodeName string } // TestData stores the state required for each test case. @@ -189,6 +192,43 @@ type PodIPs struct { ipStrings []string } +type deployAntreaOptions int + +const ( + deployAntreaDefault deployAntreaOptions = iota + deployAntreaIPsec + deployAntreaWireGuardGo + deployAntreaCoverageOffset +) + +func (o deployAntreaOptions) WithCoverage() deployAntreaOptions { + return o + deployAntreaCoverageOffset +} + +func (o deployAntreaOptions) DeployYML() string { + return deployAntreaOptionsYML[o] +} + +func (o deployAntreaOptions) String() string { + return deployAntreaOptionsString[o] +} + +var ( + deployAntreaOptionsString = [...]string{ + "AntreaDefault", + "AntreaWithIPSec", + "AntreaWithWireGuardGo", + } + deployAntreaOptionsYML = [...]string{ + antreaYML, + antreaIPSecYML, + antreaWireGuardGoYML, + antreaCovYML, + antreaIPSecCovYML, + antreaWireGuardGoCovYML, + } +) + func (p PodIPs) String() string { res := "" if p.ipv4 != nil { @@ -562,20 +602,12 @@ func (data *TestData) deployAntreaCommon(yamlFile string, extraOptions string, w return nil } -// deployAntrea deploys Antrea with the standard manifest. -func (data *TestData) deployAntrea() error { - if testOptions.enableCoverage { - return data.deployAntreaCommon(antreaCovYML, "", true) - } - return data.deployAntreaCommon(antreaYML, "", true) -} - -// deployAntreaIPSec deploys Antrea with IPSec tunnel enabled. -func (data *TestData) deployAntreaIPSec() error { +// deployAntrea deploys Antrea with deploy options. +func (data *TestData) deployAntrea(option deployAntreaOptions) error { if testOptions.enableCoverage { - return data.deployAntreaCommon(antreaIPSecCovYML, "", true) + option = option.WithCoverage() } - return data.deployAntreaCommon(antreaIPSecYML, "", true) + return data.deployAntreaCommon(option.DeployYML(), "", true) } // deployAntreaFlowExporter deploys Antrea with flow exporter config params enabled. diff --git a/test/e2e/ipsec_test.go b/test/e2e/ipsec_test.go index cb2c1b3d429..9083f810bb3 100644 --- a/test/e2e/ipsec_test.go +++ b/test/e2e/ipsec_test.go @@ -76,7 +76,7 @@ func (data *TestData) readSecurityAssociationsStatus(nodeName string) (up int, c // them ping each other. func testIPSecTunnelConnectivity(t *testing.T, data *TestData) { t.Logf("Redeploy Antrea with IPSec tunnel enabled") - data.redeployAntrea(t, true) + data.redeployAntrea(t, deployAntreaIPsec) data.testPodConnectivityDifferentNodes(t) @@ -92,7 +92,7 @@ func testIPSecTunnelConnectivity(t *testing.T, data *TestData) { } // Restore normal Antrea deployment with IPSec disabled. - data.redeployAntrea(t, false) + data.redeployAntrea(t, deployAntreaDefault) } // testIPSecDeleteStaleTunnelPorts checks that when switching from IPsec mode to @@ -100,7 +100,7 @@ func testIPSecTunnelConnectivity(t *testing.T, data *TestData) { // correctly. func testIPSecDeleteStaleTunnelPorts(t *testing.T, data *TestData) { t.Logf("Redeploy Antrea with IPSec tunnel enabled") - data.redeployAntrea(t, true) + data.redeployAntrea(t, deployAntreaIPsec) nodeName0 := nodeName(0) nodeName1 := nodeName(1) @@ -132,7 +132,7 @@ func testIPSecDeleteStaleTunnelPorts(t *testing.T, data *TestData) { } t.Logf("Redeploy Antrea with IPSec tunnel disabled") - data.redeployAntrea(t, false) + data.redeployAntrea(t, deployAntreaDefault) t.Logf("Checking that tunnel port has been deleted") if err := wait.PollImmediate(defaultInterval, defaultTimeout, func() (found bool, err error) { diff --git a/test/e2e/performance_test.go b/test/e2e/performance_test.go index 9182a383a9e..f2f1033cc0c 100644 --- a/test/e2e/performance_test.go +++ b/test/e2e/performance_test.go @@ -320,7 +320,7 @@ func withPerfTestSetup(fn func(data *TestData), b *testing.B) { b.Fatalf("Error when deleting Antrea DaemonSet: %v", err) } b.Logf("Applying Antrea YAML") - if err := data.deployAntrea(); err != nil { + if err := data.deployAntrea(deployAntreaDefault); err != nil { b.Fatalf("Error when restarting Antrea: %v", err) } b.Logf("Waiting for all Antrea DaemonSet Pods") diff --git a/test/e2e/traceflow_test.go b/test/e2e/traceflow_test.go index da0f4032c52..a4f3b8653bb 100644 --- a/test/e2e/traceflow_test.go +++ b/test/e2e/traceflow_test.go @@ -2111,13 +2111,13 @@ func runTestTraceflow(t *testing.T, data *TestData, tc testcase) { } } else { dstPod := tc.tf.Spec.Destination.Pod - podIPs := waitForPodIPs(t, data, []podInfo{{dstPod, "linux"}}) + podIPs := waitForPodIPs(t, data, []podInfo{{dstPod, "linux", ""}}) dstPodIPs = podIPs[dstPod] } // Give a little time for Nodes to install OVS flows. time.Sleep(time.Second * 2) // Send an ICMP echo packet from the source Pod to the destination. - if err := data.runPingCommandFromTestPod(podInfo{srcPod, "linux"}, testNamespace, dstPodIPs, busyboxContainerName, 2, 0); err != nil { + if err := data.runPingCommandFromTestPod(podInfo{srcPod, "linux", ""}, testNamespace, dstPodIPs, busyboxContainerName, 2, 0); err != nil { t.Logf("Ping '%s' -> '%v' failed: ERROR (%v)", srcPod, *dstPodIPs, err) } } diff --git a/test/e2e/wireguard_test.go b/test/e2e/wireguard_test.go new file mode 100644 index 00000000000..205ba4586bc --- /dev/null +++ b/test/e2e/wireguard_test.go @@ -0,0 +1,125 @@ +// Copyright 2021 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package e2e + +import ( + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "antrea.io/antrea/pkg/agent/config" + "antrea.io/antrea/pkg/apis" +) + +// TestWireGuard checks that Pod traffic across two Nodes over the WireGuard tunnel by creating +// multiple Pods across distinct Nodes and having them ping each other. It will also verify that +// the handshake was established when the wg command line is available. +func TestWireGuard(t *testing.T) { + skipIfNumNodesLessThan(t, 2) + skipIfHasWindowsNodes(t) + providerIsKind := testOptions.providerName == "kind" + if !providerIsKind { + for _, node := range clusterInfo.nodes { + skipIfMissingKernelModule(t, node.name, []string{"wireguard"}) + } + } + data, err := setupTest(t) + skipIfEncapModeIsNot(t, data, config.TrafficEncapModeEncap) + + if err != nil { + t.Fatalf("Error when setting up test: %v", err) + } + defer teardownTest(t, data) + + if !providerIsKind { + ac := []configChange{ + {"trafficEncryptionMode", "wireguard", false}, + } + if err := data.mutateAntreaConfigMap(nil, ac, false, true); err != nil { + t.Fatalf("Failed to enable WireGuard tunnel: %v", err) + } + defer func() { + ac = []configChange{ + {"trafficEncryptionMode", "none", false}, + } + if err := data.mutateAntreaConfigMap(nil, ac, false, true); err != nil { + t.Fatalf("Failed to disable WireGuard tunnel: %v", err) + } + }() + } else { + data.redeployAntrea(t, deployAntreaWireGuardGo) + defer data.redeployAntrea(t, deployAntreaDefault) + } + + t.Run("testWireGuardTunnelConnectivity", func(t *testing.T) { testWireGuardTunnelConnectivity(t, data) }) +} + +func (data *TestData) getWireGuardPeerEndpointsWithHandshake(nodeName string) ([]string, error) { + var peerEndpoints []string + antreaPodName, err := data.getAntreaPodOnNode(nodeName) + if err != nil { + return peerEndpoints, err + } + cmd := []string{"wg"} + stdout, stderr, err := data.runCommandFromPod(antreaNamespace, antreaPodName, "wireguard", cmd) + if err != nil { + return peerEndpoints, fmt.Errorf("error when running 'wg' on '%s': %v - stdout: %s - stderr: %s", nodeName, err, stdout, stderr) + } + peerConfigs := strings.Split(stdout, "\n\n") + if len(peerConfigs) < 1 { + return peerEndpoints, fmt.Errorf("invalid 'wg' output on '%s': %v - stdout: %s - stderr: %s", nodeName, err, stdout, stderr) + } + + for _, p := range peerConfigs[1:] { + lines := strings.Split(p, "\n") + if len(lines) < 2 { + return peerEndpoints, fmt.Errorf("invalid WireGuard peer config output - %s", p) + } + peerEndpoint := strings.TrimPrefix(strings.TrimSpace(lines[1]), "endpoint: ") + for _, l := range lines { + if strings.Contains(l, "latest handshake") { + peerEndpoints = append(peerEndpoints, peerEndpoint) + break + } + } + } + return peerEndpoints, nil +} + +func testWireGuardTunnelConnectivity(t *testing.T, data *TestData) { + podInfos, deletePods := createPodsOnDifferentNodes(t, data, "differentnodes") + defer deletePods() + numPods := 2 + data.runPingMesh(t, podInfos[:numPods], agnhostContainerName) + // wg command is only available in WireGuard sidecar container. + if testOptions.providerName == "kind" { + nodeName0 := podInfos[0].nodeName + nodeName1 := podInfos[1].nodeName + endpoints, err := data.getWireGuardPeerEndpointsWithHandshake(nodeName0) + require.NoError(t, err) + t.Logf("Found peer endpoints %v with handshake established for Node '%s'", endpoints, nodeName0) + var nodeIP string + for _, n := range clusterInfo.nodes { + if n.name == nodeName1 { + nodeIP = n.ip + break + } + } + assert.Contains(t, endpoints, fmt.Sprintf("%s:%d", nodeIP, apis.WireGuardListenPort)) + } +} diff --git a/test/integration/agent/openflow_test.go b/test/integration/agent/openflow_test.go index 80c0e5b728a..dac34e96bc6 100644 --- a/test/integration/agent/openflow_test.go +++ b/test/integration/agent/openflow_test.go @@ -193,7 +193,7 @@ func TestReplayFlowsNetworkPolicyFlows(t *testing.T) { err := ofTestUtils.PrepareOVSBridge(br) require.Nil(t, err, fmt.Sprintf("Failed to prepare OVS bridge: %v", err)) - _, err = c.Initialize(roundInfo, &config1.NodeConfig{}, config1.TrafficEncapModeEncap) + _, err = c.Initialize(roundInfo, &config1.NodeConfig{}, &config1.NetworkConfig{TrafficEncapMode: config1.TrafficEncapModeEncap}) require.Nil(t, err, "Failed to initialize OFClient") defer func() { @@ -280,7 +280,7 @@ func testReplayFlows(t *testing.T) { } func testInitialize(t *testing.T, config *testConfig) { - if _, err := c.Initialize(roundInfo, config.nodeConfig, config1.TrafficEncapModeEncap); err != nil { + if _, err := c.Initialize(roundInfo, config.nodeConfig, &config1.NetworkConfig{TrafficEncapMode: config1.TrafficEncapModeEncap}); err != nil { t.Errorf("Failed to initialize openflow client: %v", err) } for _, tableFlow := range prepareDefaultFlows(config) { @@ -378,7 +378,7 @@ func TestNetworkPolicyFlows(t *testing.T) { err := ofTestUtils.PrepareOVSBridge(br) require.Nil(t, err, fmt.Sprintf("Failed to prepare OVS bridge %s", br)) - _, err = c.Initialize(roundInfo, &config1.NodeConfig{PodIPv4CIDR: podIPv4CIDR, PodIPv6CIDR: podIPv6CIDR}, config1.TrafficEncapModeEncap) + _, err = c.Initialize(roundInfo, &config1.NodeConfig{PodIPv4CIDR: podIPv4CIDR, PodIPv6CIDR: podIPv6CIDR}, &config1.NetworkConfig{TrafficEncapMode: config1.TrafficEncapModeEncap}) require.Nil(t, err, "Failed to initialize OFClient") defer func() { @@ -530,7 +530,7 @@ func TestProxyServiceFlows(t *testing.T) { err := ofTestUtils.PrepareOVSBridge(br) require.Nil(t, err, fmt.Sprintf("Failed to prepare OVS bridge %s", br)) - _, err = c.Initialize(roundInfo, &config1.NodeConfig{}, config1.TrafficEncapModeEncap) + _, err = c.Initialize(roundInfo, &config1.NodeConfig{}, &config1.NetworkConfig{TrafficEncapMode: config1.TrafficEncapModeEncap}) require.Nil(t, err, "Failed to initialize OFClient") defer func() { @@ -1404,7 +1404,7 @@ func TestSNATFlows(t *testing.T) { require.Nil(t, err, fmt.Sprintf("Failed to prepare OVS bridge %s", br)) config := prepareConfiguration() - _, err = c.Initialize(roundInfo, config.nodeConfig, config1.TrafficEncapModeEncap) + _, err = c.Initialize(roundInfo, config.nodeConfig, &config1.NetworkConfig{TrafficEncapMode: config1.TrafficEncapModeEncap}) require.Nil(t, err, "Failed to initialize OFClient") defer func() {