diff --git a/build/charts/antrea/README.md b/build/charts/antrea/README.md index 8463ec55e6e..4d03d1c2072 100644 --- a/build/charts/antrea/README.md +++ b/build/charts/antrea/README.md @@ -68,9 +68,9 @@ Kubernetes: `>= 1.16.0-0` | controller.tolerations | list | `[{"key":"CriticalAddonsOnly","operator":"Exists"},{"effect":"NoSchedule","key":"node-role.kubernetes.io/master"},{"effect":"NoSchedule","key":"node-role.kubernetes.io/control-plane"}]` | Tolerations for the antrea-controller Pod. | | defaultMTU | int | `0` | Default MTU to use for the host gateway interface and the network interface of each Pod. By default, antrea-agent will discover the MTU of the Node's primary interface and adjust it to accommodate for tunnel encapsulation overhead if applicable. | | disableTXChecksumOffload | bool | `false` | Disable TX checksum offloading for container network interfaces. It's supposed to be set to true when the datapath doesn't support TX checksum offloading, which causes packets to be dropped due to bad checksum. It affects Pods running on Linux Nodes only. | -| dnsServerOverride | string | `""` | Address of DNS server, to override the kube-dns service. It's used to resolve hostname in FQDN policy. | +| dnsServerOverride | string | `""` | Address of DNS server, to override the kube-dns Service. It's used to resolve hostnames in a FQDN policy. | | egress.exceptCIDRs | list | `[]` | CIDR ranges to which outbound Pod traffic will not be SNAT'd by Egresses. | -| egress.maxEgressIPsPerNode | int | `255` | The maximum number of Egress IPs that can be assigned to a Node. It's useful when the Node network restricts the number of secondary IPs a Node can have, e.g. EKS. It must not be greater than 255. | +| egress.maxEgressIPsPerNode | int | `255` | The maximum number of Egress IPs that can be assigned to a Node. It is useful when the Node network restricts the number of secondary IPs a Node can have, e.g. EKS. It must not be greater than 255. | | enableBridgingMode | bool | `false` | Enable bridging mode of Pod network on Nodes, in which the Node's transport interface is connected to the OVS bridge. | | featureGates | object | `{}` | To explicitly enable or disable a FeatureGate and bypass the Antrea defaults, add an entry to the dictionary with the FeatureGate's name as the key and a boolean as the value. | | flowExporter.activeFlowExportTimeout | string | `"5s"` | timeout after which a flow record is sent to the collector for active flows. | @@ -107,12 +107,7 @@ Kubernetes: `>= 1.16.0-0` | nodePortLocal.portRange | string | `"61000-62000"` | Port range used by NodePortLocal when creating Pod port mappings. | | ovs.bridgeName | string | `"br-int"` | Name of the OVS bridge antrea-agent will create and use. | | ovs.hwOffload | bool | `false` | Enable hardware offload for the OVS bridge (required additional configuration). | -| secondaryNetwork.ovs.datapathType | string | `"system"` | 'system' is the default value and corresponds to the kernel datapath. Use 'netdev' to run OVS in userspace mode. Userspace mode requires the tun device driver to be available. | -| secondaryNetwork.ovs.enable | bool | `false` | Enable OVS bridge configuration for secondary network. | -| secondaryNetwork.ovs.integrationBridgeName | string | `"br-secnet-int"` | Secondary network OVS integration bridge name. | -| secondaryNetwork.ovs.patchPort | string | `"br-secnet-patch0"` | Name of the OVS patch port which connects the integration and transport bridge. | -| secondaryNetwork.ovs.transportBridgeName | string | `"br-secnet-trans"` | Secondary network OVS transport bridge name. | -| secondaryNetwork.tunnelType | string | `"geneve"` | Tunnel protocol used for encapsulating traffic across Nodes. It must be one of "geneve", "vxlan", "gre", "stt". | +| secondaryNetwork.ovsBridges | list | `[]` | Configuration of OVS bridges for secondary network. At the moment, at most one OVS bridge can be specified. If the specified bridge does not exist on the Node, antrea-agent will create it based on the configuration. The following configuration specifies an OVS bridge with name "br1" and a physical interface "eth1": [{bridgeName: "br1", physicalInterfaces: ["eth1"]}] | | serviceCIDR | string | `""` | IPv4 CIDR range used for Services. Required when AntreaProxy is disabled. | | serviceCIDRv6 | string | `""` | IPv6 CIDR range used for Services. Required when AntreaProxy is disabled. | | testing.coverage | bool | `false` | Enable code coverage measurement (used when testing Antrea only). | diff --git a/build/charts/antrea/conf/antrea-agent.conf b/build/charts/antrea/conf/antrea-agent.conf index 66b80003d79..f4c4ca4c3f2 100644 --- a/build/charts/antrea/conf/antrea-agent.conf +++ b/build/charts/antrea/conf/antrea-agent.conf @@ -254,14 +254,15 @@ nodePortLocal: portRange: {{ .portRange | quote }} {{- end }} -# Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or InClusterConfig. -# It is typically used when kube-proxy is not deployed (replaced by AntreaProxy). +# Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or +# InClusterConfig. It is typically used when kube-proxy is not deployed (replaced by AntreaProxy). # Defaults to "". It must be a host string, a host:port pair, or a URL to the base of the apiserver. kubeAPIServerOverride: {{ .Values.kubeAPIServerOverride | quote }} -# Provide the address of DNS server, to override the kube-dns service. It's used to resolve hostname in FQDN policy. -# Defaults to "". It must be a host string or a host:port pair of the DNS server (e.g. 10.96.0.10, 10.96.0.10:53, -# [fd00:10:96::a]:53). +# Provide the address of DNS server, to override the kube-dns Service. It's used to resolve +# hostnames in a FQDN policy. +# Defaults to "". It must be a host string or a host:port pair of the DNS server (e.g. 10.96.0.10, +# 10.96.0.10:53, [fd00:10:96::a]:53). dnsServerOverride: {{ .Values.dnsServerOverride | quote }} # Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. @@ -402,24 +403,8 @@ multicluster: secondaryNetwork: {{- with .Values.secondaryNetwork }} - # OVS bridge configuration for secondary network. - ovs: - # Enable OVS bridge configuration for secondary network. - enable: {{ .ovs.enable }} - # Secondary network OVS integration bridge name. Ensure it doesn't conflict with your existing OpenVSwitch bridges. - integrationBridgeName: {{ .ovs.integrationBridgeName | quote }} - # Secondary network OVS transport bridge name. Ensure it doesn't conflict with your existing OpenVSwitch bridges. - transportBridgeName: {{ .ovs.transportBridgeName | quote }} - # Datapath type to use for the OpenVSwitch bridge created by Antrea. Supported values are: - # - system - # - netdev - # 'system' is the default value and corresponds to the kernel datapath. Use 'netdev' to run - # OVS in userspace mode. Userspace mode requires the tun device driver to be available. - datapathType: {{ .ovs.datapathType | quote }} - # Name of the OVS patch port which connects the integration and transport bridge. - patchPort: {{ .ovs.patchPort | quote }} - # Tunnel protocol used for encapsulating traffic across Nodes. It must be one - # of "geneve", "vxlan", "gre", "stt". - tunnelType: {{ .tunnelType | quote }} + # Configuration of OVS bridges for secondary network. + ovsBridges: + {{- toYaml .ovsBridges | trim | nindent 6 }} {{- end }} {{- end }} diff --git a/build/charts/antrea/values.yaml b/build/charts/antrea/values.yaml index 10b8bf0bfab..5f6b1d29475 100644 --- a/build/charts/antrea/values.yaml +++ b/build/charts/antrea/values.yaml @@ -74,24 +74,13 @@ ovs: hwOffload: false secondaryNetwork: - ovs: - # -- Enable OVS bridge configuration for secondary network. - enable: false - # -- Secondary network OVS integration bridge name. - integrationBridgeName: "br-secnet-int" - # -- Secondary network OVS transport bridge name. - transportBridgeName: "br-secnet-trans" - # -- Datapath type to use for the OpenVSwitch bridge created by Antrea. Supported values are: - # - system - # - netdev - # -- 'system' is the default value and corresponds to the kernel datapath. Use 'netdev' to run - # OVS in userspace mode. Userspace mode requires the tun device driver to be available. - datapathType: "system" - # -- Name of the OVS patch port which connects the integration and transport bridge. - patchPort: "br-secnet-patch0" - # -- Tunnel protocol used for encapsulating traffic across Nodes. It must be one - # of "geneve", "vxlan", "gre", "stt". - tunnelType: "geneve" + # -- Configuration of OVS bridges for secondary network. At the moment, at + # most one OVS bridge can be specified. If the specified bridge does not exist + # on the Node, antrea-agent will create it based on the configuration. + # The following configuration specifies an OVS bridge with name "br1" and a + # physical interface "eth1": + # [{bridgeName: "br1", physicalInterfaces: ["eth1"]}] + ovsBridges: [] wireGuard: # -- Port for WireGuard to send and receive traffic. @@ -113,8 +102,9 @@ ipsec: egress: # -- CIDR ranges to which outbound Pod traffic will not be SNAT'd by Egresses. exceptCIDRs: [] - # -- The maximum number of Egress IPs that can be assigned to a Node. It's useful when the Node network restricts - # the number of secondary IPs a Node can have, e.g. EKS. It must not be greater than 255. + # -- The maximum number of Egress IPs that can be assigned to a Node. It is + # useful when the Node network restricts the number of secondary IPs a Node + # can have, e.g. EKS. It must not be greater than 255. maxEgressIPsPerNode: 255 nodePortLocal: @@ -141,8 +131,8 @@ antreaProxy: # will only handle Services without the "service.kubernetes.io/service-proxy-name" # label, but ignore Services with the label no matter what is the value. serviceProxyName: "" - # -- Determines how external traffic is processed when it's load balanced across Nodes by default. It must be one of "nat" or - # "dsr". + # -- Determines how external traffic is processed when it's load balanced + # across Nodes by default. It must be one of "nat" or "dsr". defaultLoadBalancerMode: "nat" nodeIPAM: @@ -162,8 +152,8 @@ nodeIPAM: # -- Address of Kubernetes apiserver, to override any value provided in # kubeconfig or InClusterConfig. kubeAPIServerOverride: "" -# -- Address of DNS server, to override the kube-dns service. It's used to -# resolve hostname in FQDN policy. +# -- Address of DNS server, to override the kube-dns Service. It's used to +# resolve hostnames in a FQDN policy. dnsServerOverride: "" # -- IPv4 CIDR range used for Services. Required when AntreaProxy is disabled. serviceCIDR: "" diff --git a/build/yamls/antrea-aks.yml b/build/yamls/antrea-aks.yml index dbbe093060e..d4e6b5b2d7f 100644 --- a/build/yamls/antrea-aks.yml +++ b/build/yamls/antrea-aks.yml @@ -3921,14 +3921,15 @@ data: # directed to that port will be forwarded to the Pod. portRange: "61000-62000" - # Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or InClusterConfig. - # It is typically used when kube-proxy is not deployed (replaced by AntreaProxy). + # Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or + # InClusterConfig. It is typically used when kube-proxy is not deployed (replaced by AntreaProxy). # Defaults to "". It must be a host string, a host:port pair, or a URL to the base of the apiserver. kubeAPIServerOverride: "" - # Provide the address of DNS server, to override the kube-dns service. It's used to resolve hostname in FQDN policy. - # Defaults to "". It must be a host string or a host:port pair of the DNS server (e.g. 10.96.0.10, 10.96.0.10:53, - # [fd00:10:96::a]:53). + # Provide the address of DNS server, to override the kube-dns Service. It's used to resolve + # hostnames in a FQDN policy. + # Defaults to "". It must be a host string or a host:port pair of the DNS server (e.g. 10.96.0.10, + # 10.96.0.10:53, [fd00:10:96::a]:53). dnsServerOverride: "" # Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. @@ -5014,7 +5015,7 @@ spec: kubectl.kubernetes.io/default-container: antrea-agent # Automatically restart Pods with a RollingUpdate if the ConfigMap changes # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments - checksum/config: e3208d24eb3232bd1fa2936e6b7a265c2ff3b462b5091828467c88f9df0e0b42 + checksum/config: dc20c0dfcf5de2f50d35da9f7150b6fbe4b6be5699c2a3e297583f3329b0c7ad labels: app: antrea component: antrea-agent @@ -5255,7 +5256,7 @@ spec: annotations: # Automatically restart Pod if the ConfigMap changes # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments - checksum/config: e3208d24eb3232bd1fa2936e6b7a265c2ff3b462b5091828467c88f9df0e0b42 + checksum/config: dc20c0dfcf5de2f50d35da9f7150b6fbe4b6be5699c2a3e297583f3329b0c7ad labels: app: antrea component: antrea-controller diff --git a/build/yamls/antrea-eks.yml b/build/yamls/antrea-eks.yml index 90df532f592..140531b6ace 100644 --- a/build/yamls/antrea-eks.yml +++ b/build/yamls/antrea-eks.yml @@ -3921,14 +3921,15 @@ data: # directed to that port will be forwarded to the Pod. portRange: "61000-62000" - # Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or InClusterConfig. - # It is typically used when kube-proxy is not deployed (replaced by AntreaProxy). + # Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or + # InClusterConfig. It is typically used when kube-proxy is not deployed (replaced by AntreaProxy). # Defaults to "". It must be a host string, a host:port pair, or a URL to the base of the apiserver. kubeAPIServerOverride: "" - # Provide the address of DNS server, to override the kube-dns service. It's used to resolve hostname in FQDN policy. - # Defaults to "". It must be a host string or a host:port pair of the DNS server (e.g. 10.96.0.10, 10.96.0.10:53, - # [fd00:10:96::a]:53). + # Provide the address of DNS server, to override the kube-dns Service. It's used to resolve + # hostnames in a FQDN policy. + # Defaults to "". It must be a host string or a host:port pair of the DNS server (e.g. 10.96.0.10, + # 10.96.0.10:53, [fd00:10:96::a]:53). dnsServerOverride: "" # Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. @@ -5014,7 +5015,7 @@ spec: kubectl.kubernetes.io/default-container: antrea-agent # Automatically restart Pods with a RollingUpdate if the ConfigMap changes # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments - checksum/config: e3208d24eb3232bd1fa2936e6b7a265c2ff3b462b5091828467c88f9df0e0b42 + checksum/config: dc20c0dfcf5de2f50d35da9f7150b6fbe4b6be5699c2a3e297583f3329b0c7ad labels: app: antrea component: antrea-agent @@ -5256,7 +5257,7 @@ spec: annotations: # Automatically restart Pod if the ConfigMap changes # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments - checksum/config: e3208d24eb3232bd1fa2936e6b7a265c2ff3b462b5091828467c88f9df0e0b42 + checksum/config: dc20c0dfcf5de2f50d35da9f7150b6fbe4b6be5699c2a3e297583f3329b0c7ad labels: app: antrea component: antrea-controller diff --git a/build/yamls/antrea-gke.yml b/build/yamls/antrea-gke.yml index 3b6c0ef5b0b..26430005161 100644 --- a/build/yamls/antrea-gke.yml +++ b/build/yamls/antrea-gke.yml @@ -3921,14 +3921,15 @@ data: # directed to that port will be forwarded to the Pod. portRange: "61000-62000" - # Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or InClusterConfig. - # It is typically used when kube-proxy is not deployed (replaced by AntreaProxy). + # Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or + # InClusterConfig. It is typically used when kube-proxy is not deployed (replaced by AntreaProxy). # Defaults to "". It must be a host string, a host:port pair, or a URL to the base of the apiserver. kubeAPIServerOverride: "" - # Provide the address of DNS server, to override the kube-dns service. It's used to resolve hostname in FQDN policy. - # Defaults to "". It must be a host string or a host:port pair of the DNS server (e.g. 10.96.0.10, 10.96.0.10:53, - # [fd00:10:96::a]:53). + # Provide the address of DNS server, to override the kube-dns Service. It's used to resolve + # hostnames in a FQDN policy. + # Defaults to "". It must be a host string or a host:port pair of the DNS server (e.g. 10.96.0.10, + # 10.96.0.10:53, [fd00:10:96::a]:53). dnsServerOverride: "" # Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. @@ -5014,7 +5015,7 @@ spec: kubectl.kubernetes.io/default-container: antrea-agent # Automatically restart Pods with a RollingUpdate if the ConfigMap changes # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments - checksum/config: cec624c3579d3f07e29b6842e3bcc09a12963c97da2c4e24afa646b6c3875809 + checksum/config: 6b950862e9c2f2068a550c2fc6ec66defbcf306c703def6a57b89d1c87017c74 labels: app: antrea component: antrea-agent @@ -5253,7 +5254,7 @@ spec: annotations: # Automatically restart Pod if the ConfigMap changes # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments - checksum/config: cec624c3579d3f07e29b6842e3bcc09a12963c97da2c4e24afa646b6c3875809 + checksum/config: 6b950862e9c2f2068a550c2fc6ec66defbcf306c703def6a57b89d1c87017c74 labels: app: antrea component: antrea-controller diff --git a/build/yamls/antrea-ipsec.yml b/build/yamls/antrea-ipsec.yml index 26a0d62a085..5976f1b8028 100644 --- a/build/yamls/antrea-ipsec.yml +++ b/build/yamls/antrea-ipsec.yml @@ -3934,14 +3934,15 @@ data: # directed to that port will be forwarded to the Pod. portRange: "61000-62000" - # Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or InClusterConfig. - # It is typically used when kube-proxy is not deployed (replaced by AntreaProxy). + # Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or + # InClusterConfig. It is typically used when kube-proxy is not deployed (replaced by AntreaProxy). # Defaults to "". It must be a host string, a host:port pair, or a URL to the base of the apiserver. kubeAPIServerOverride: "" - # Provide the address of DNS server, to override the kube-dns service. It's used to resolve hostname in FQDN policy. - # Defaults to "". It must be a host string or a host:port pair of the DNS server (e.g. 10.96.0.10, 10.96.0.10:53, - # [fd00:10:96::a]:53). + # Provide the address of DNS server, to override the kube-dns Service. It's used to resolve + # hostnames in a FQDN policy. + # Defaults to "". It must be a host string or a host:port pair of the DNS server (e.g. 10.96.0.10, + # 10.96.0.10:53, [fd00:10:96::a]:53). dnsServerOverride: "" # Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. @@ -5027,7 +5028,7 @@ spec: kubectl.kubernetes.io/default-container: antrea-agent # Automatically restart Pods with a RollingUpdate if the ConfigMap changes # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments - checksum/config: 711e1747ccd17b291d523080c4942e215d7499a6b00f936149c488cdaef6d342 + checksum/config: 2dd0d7f0520d69ffc02992e7154893d54384936121734cf5605864f2c0196552 checksum/ipsec-secret: d0eb9c52d0cd4311b6d252a951126bf9bea27ec05590bed8a394f0f792dcb2a4 labels: app: antrea @@ -5312,7 +5313,7 @@ spec: annotations: # Automatically restart Pod if the ConfigMap changes # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments - checksum/config: 711e1747ccd17b291d523080c4942e215d7499a6b00f936149c488cdaef6d342 + checksum/config: 2dd0d7f0520d69ffc02992e7154893d54384936121734cf5605864f2c0196552 labels: app: antrea component: antrea-controller diff --git a/build/yamls/antrea.yml b/build/yamls/antrea.yml index 5084c8df511..7c6646c7cb9 100644 --- a/build/yamls/antrea.yml +++ b/build/yamls/antrea.yml @@ -3921,14 +3921,15 @@ data: # directed to that port will be forwarded to the Pod. portRange: "61000-62000" - # Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or InClusterConfig. - # It is typically used when kube-proxy is not deployed (replaced by AntreaProxy). + # Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or + # InClusterConfig. It is typically used when kube-proxy is not deployed (replaced by AntreaProxy). # Defaults to "". It must be a host string, a host:port pair, or a URL to the base of the apiserver. kubeAPIServerOverride: "" - # Provide the address of DNS server, to override the kube-dns service. It's used to resolve hostname in FQDN policy. - # Defaults to "". It must be a host string or a host:port pair of the DNS server (e.g. 10.96.0.10, 10.96.0.10:53, - # [fd00:10:96::a]:53). + # Provide the address of DNS server, to override the kube-dns Service. It's used to resolve + # hostnames in a FQDN policy. + # Defaults to "". It must be a host string or a host:port pair of the DNS server (e.g. 10.96.0.10, + # 10.96.0.10:53, [fd00:10:96::a]:53). dnsServerOverride: "" # Comma-separated list of Cipher Suites. If omitted, the default Go Cipher Suites will be used. @@ -5014,7 +5015,7 @@ spec: kubectl.kubernetes.io/default-container: antrea-agent # Automatically restart Pods with a RollingUpdate if the ConfigMap changes # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments - checksum/config: 96448ab5ddc455d898d31956cc9d15fae055b4fb4bdc9acc9dc765ca125c0867 + checksum/config: 9b729e8394d6b478787f0e1e64d8c00326f714e6f5d4a8b1774de1040fc5984b labels: app: antrea component: antrea-agent @@ -5253,7 +5254,7 @@ spec: annotations: # Automatically restart Pod if the ConfigMap changes # See https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments - checksum/config: 96448ab5ddc455d898d31956cc9d15fae055b4fb4bdc9acc9dc765ca125c0867 + checksum/config: 9b729e8394d6b478787f0e1e64d8c00326f714e6f5d4a8b1774de1040fc5984b labels: app: antrea component: antrea-controller diff --git a/cmd/antrea-agent/agent.go b/cmd/antrea-agent/agent.go index 0c6b5c3945e..bdfc6b4591a 100644 --- a/cmd/antrea-agent/agent.go +++ b/cmd/antrea-agent/agent.go @@ -58,8 +58,8 @@ import ( proxytypes "antrea.io/antrea/pkg/agent/proxy/types" "antrea.io/antrea/pkg/agent/querier" "antrea.io/antrea/pkg/agent/route" + "antrea.io/antrea/pkg/agent/secondarynetwork" "antrea.io/antrea/pkg/agent/secondarynetwork/cnipodcache" - "antrea.io/antrea/pkg/agent/secondarynetwork/podwatch" "antrea.io/antrea/pkg/agent/servicecidr" "antrea.io/antrea/pkg/agent/stats" support "antrea.io/antrea/pkg/agent/supportbundlecollection" @@ -679,21 +679,15 @@ func run(o *Options) error { } if features.DefaultFeatureGate.Enabled(features.SecondaryNetwork) { - // Create the NetworkAttachmentDefinition client, which handles access to secondary network object definition from the API Server. - netAttachDefClient, err := k8s.CreateNetworkAttachDefClient(o.config.ClientConnection, o.config.KubeAPIServerOverride) - if err != nil { - return fmt.Errorf("NetworkAttachmentDefinition client creation failed. %v", err) - } - // Create podController to handle secondary network configuration for Pods with k8s.v1.cni.cncf.io/networks Annotation defined. - podWatchController := podwatch.NewPodController( - k8sClient, - netAttachDefClient, - localPodInformer, - nodeConfig.Name, - cniPodInfoStore, + if err := secondarynetwork.Initialize( + o.config.ClientConnection, o.config.KubeAPIServerOverride, + k8sClient, localPodInformer, nodeConfig.Name, cniPodInfoStore, // safe to call given that cniServer.Initialize has been called already. - cniServer.GetPodConfigurator()) - go podWatchController.Run(stopCh) + cniServer.GetPodConfigurator(), + stopCh, + &o.config.SecondaryNetwork, ovsdbConnection); err != nil { + return fmt.Errorf("failed to initialize secondary network: %v", err) + } } if features.DefaultFeatureGate.Enabled(features.TrafficControl) { diff --git a/cmd/antrea-agent/options.go b/cmd/antrea-agent/options.go index 4741bcb7afd..2ccdaa1dec0 100644 --- a/cmd/antrea-agent/options.go +++ b/cmd/antrea-agent/options.go @@ -597,7 +597,7 @@ func (o *Options) validateK8sNodeOptions() error { o.dnsServerOverride = hostPort } - return nil + return o.validateSecondaryNetworkConfig() } // resetVMDefaultFeatures sets the feature's default enablement status as false if it is not supported on a VM or a BM. @@ -684,3 +684,25 @@ func (o *Options) setMulticlusterDefaultOptions() { } } } + +func (o *Options) validateSecondaryNetworkConfig() error { + if !features.DefaultFeatureGate.Enabled(features.SecondaryNetwork) { + return nil + } + + if len(o.config.SecondaryNetwork.OVSBridges) == 0 { + return nil + } + if len(o.config.SecondaryNetwork.OVSBridges) > 1 { + return fmt.Errorf("only one OVS bridge can be specified for secondary network") + } + brConfig := o.config.SecondaryNetwork.OVSBridges[0] + if brConfig.BridgeName == "" { + return fmt.Errorf("bridge name is not provided for the secondary network OVS bridge") + } + if len(brConfig.PhysicalInterfaces) > 1 { + return fmt.Errorf("at most one physical interface can be specified for the secondary network OVS bridge") + } + + return nil +} diff --git a/cmd/antrea-agent/options_test.go b/cmd/antrea-agent/options_test.go index e41bd0acede..421dd1a6fa2 100644 --- a/cmd/antrea-agent/options_test.go +++ b/cmd/antrea-agent/options_test.go @@ -242,3 +242,71 @@ func TestOptionsValidateMulticastConfig(t *testing.T) { }) } } + +func TestOptionsValidateSecondaryNetworkConfig(t *testing.T) { + tests := []struct { + name string + featureGateValue bool + ovsBridges []string + physicalInterfaces []string + expectedErr string + }{ + { + name: "featureGate off", + ovsBridges: []string{"br1"}, + }, + { + name: "no bridge", + featureGateValue: true, + }, + { + name: "one bridge", + featureGateValue: true, + ovsBridges: []string{"br1"}, + }, + { + name: "one interface", + featureGateValue: true, + ovsBridges: []string{"br1"}, + physicalInterfaces: []string{"eth1"}, + }, + { + name: "two bridges", + featureGateValue: true, + ovsBridges: []string{"br1", "br2"}, + expectedErr: "only one OVS bridge can be specified for secondary network", + }, + { + name: "no bridge name", + featureGateValue: true, + ovsBridges: []string{""}, + expectedErr: "bridge name is not provided for the secondary network OVS bridge", + }, + { + name: "two interfaces", + featureGateValue: true, + ovsBridges: []string{"br1"}, + physicalInterfaces: []string{"eth1", "eth2"}, + expectedErr: "at most one physical interface can be specified for the secondary network OVS bridge", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, features.DefaultFeatureGate, features.SecondaryNetwork, tc.featureGateValue)() + + o := &Options{config: &agentconfig.AgentConfig{}} + for _, brName := range tc.ovsBridges { + br := agentconfig.OVSBridgeConfig{BridgeName: brName} + br.PhysicalInterfaces = tc.physicalInterfaces + o.config.SecondaryNetwork.OVSBridges = append(o.config.SecondaryNetwork.OVSBridges, br) + } + + err := o.validateSecondaryNetworkConfig() + if tc.expectedErr == "" { + require.NoError(t, err) + } else { + require.Error(t, err, tc.expectedErr) + } + }) + } +} diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go index 62b51ec7152..9c0932135ef 100644 --- a/pkg/agent/agent.go +++ b/pkg/agent/agent.go @@ -78,8 +78,8 @@ var ( // getIPNetDeviceByV4CIDR is meant to be overridden for testing. getIPNetDeviceByCIDRs = util.GetIPNetDeviceByCIDRs - // getTransportIPNetDeviceByName is meant to be overridden for testing. - getTransportIPNetDeviceByName = GetTransportIPNetDeviceByName + // getTransportIPNetDeviceByNameFn is meant to be overridden for testing. + getTransportIPNetDeviceByNameFn = getTransportIPNetDeviceByName // setLinkUp is meant to be overridden for testing setLinkUp = util.SetLinkUp @@ -951,7 +951,7 @@ func (i *Initializer) initK8sNodeLocalConfig(nodeName string) error { transportInterface = nodeInterface if i.networkConfig.TransportIface != "" { // Find the configured transport interface, and update its IP address in Node's annotation. - transportIPv4Addr, transportIPv6Addr, transportInterface, err = getTransportIPNetDeviceByName(i.networkConfig.TransportIface, i.ovsBridge) + transportIPv4Addr, transportIPv6Addr, transportInterface, err = getTransportIPNetDeviceByNameFn(i.networkConfig.TransportIface, i.ovsBridge) if err != nil { return fmt.Errorf("failed to get local IPNet device with transport interface %s: %v", i.networkConfig.TransportIface, err) } @@ -1344,8 +1344,7 @@ func (i *Initializer) setOVSDatapath() error { if _, exists := otherConfig[ovsconfig.OVSOtherConfigDatapathIDKey]; exists { return nil } - randMAC := util.GenerateRandomMAC() - datapathID := "0000" + strings.Replace(randMAC.String(), ":", "", -1) + datapathID := util.GenerateOVSDatapathID("") if err := i.ovsBridgeClient.SetDatapathID(datapathID); err != nil { klog.ErrorS(err, "Failed to set OVS bridge datapath_id", "datapathID", datapathID) return err diff --git a/pkg/agent/agent_linux.go b/pkg/agent/agent_linux.go index eebc2851f3a..a797c21349f 100644 --- a/pkg/agent/agent_linux.go +++ b/pkg/agent/agent_linux.go @@ -20,7 +20,6 @@ package agent import ( "fmt" "net" - "strings" "time" "github.com/vishvananda/netlink" @@ -75,10 +74,8 @@ func (i *Initializer) prepareOVSBridgeForK8sNode() error { // Set datapathID of OVS bridge. // If no datapathID configured explicitly, the reconfiguration operation will change OVS bridge datapathID // and break the OpenFlow channel. - // The length of datapathID is 64 bits, the lower 48-bits are for a MAC address, while the upper 16-bits are - // implementer-defined. Antrea uses "0x0000" for the upper 16-bits. - datapathID := strings.Replace(uplinkNetConfig.MAC.String(), ":", "", -1) - datapathID = "0000" + datapathID + datapathID := util.GenerateOVSDatapathID(uplinkNetConfig.MAC.String()) + if err = i.ovsBridgeClient.SetDatapathID(datapathID); err != nil { return fmt.Errorf("failed to set datapath_id %s: err=%w", datapathID, err) } @@ -123,14 +120,14 @@ func (i *Initializer) getTunnelPortLocalIP() net.IP { return nil } -func GetTransportIPNetDeviceByName(ifaceName string, ovsBridgeName string) (*net.IPNet, *net.IPNet, *net.Interface, error) { +func getTransportIPNetDeviceByName(ifaceName string, ovsBridgeName string) (*net.IPNet, *net.IPNet, *net.Interface, error) { return util.GetIPNetDeviceByName(ifaceName) } -// saveHostRoutes saves routes which are configured on uplink interface before -// the interface the configured as the uplink of antrea network. -// The routes will be restored on OVS bridge interface after the IP configuration -// is moved to the OVS bridge. +// saveHostRoutes saves the routes which were configured on the uplink interface +// before the interface is configured as the OVS brdige uplink. These routes +// will be moved to the bridge interface together with the interface IP +// configuration. func (i *Initializer) saveHostRoutes() error { routes, err := netlink.RouteList(nil, netlink.FAMILY_V4) if err != nil { @@ -155,8 +152,8 @@ func (i *Initializer) saveHostRoutes() error { // restoreHostRoutes restores the host routes which are lost when moving the IP // configuration of uplink interface to the OVS bridge interface during -// the antrea network initialize stage. -// The backup routes are restored after the IP configuration change. +// the Antrea bridge initialization stage. +// The backup routes are restored after the IP configuration changes. func (i *Initializer) restoreHostRoutes() error { return i.restoreHostRoutesToInterface(i.nodeConfig.UplinkNetConfig.Name) } @@ -188,7 +185,7 @@ func (i *Initializer) ConnectUplinkToOVSBridge() error { uplinkName := uplinkNetConfig.Name bridgedUplinkName := util.GenerateUplinkInterfaceName(uplinkNetConfig.Name) - // If uplink is already exists, return. + // If the uplink port already exists, just return. if uplinkOFPort, err := i.ovsBridgeClient.GetOFPort(bridgedUplinkName, false); err == nil { klog.InfoS("Uplink already exists, skip the configuration", "uplink", bridgedUplinkName, "port", uplinkOFPort) return nil diff --git a/pkg/agent/agent_test.go b/pkg/agent/agent_test.go index 625731553a2..337f807701d 100644 --- a/pkg/agent/agent_test.go +++ b/pkg/agent/agent_test.go @@ -441,11 +441,11 @@ func mockNodeNameEnv(name string) func() { } func mockGetTransportIPNetDeviceByName(ipV4Net, ipV6Net *net.IPNet, ipDevice *net.Interface) func() { - prevGetIPNetDeviceByName := getTransportIPNetDeviceByName - getTransportIPNetDeviceByName = func(ifName, brName string) (*net.IPNet, *net.IPNet, *net.Interface, error) { + prevGetIPNetDeviceByName := getTransportIPNetDeviceByNameFn + getTransportIPNetDeviceByNameFn = func(ifName, brName string) (*net.IPNet, *net.IPNet, *net.Interface, error) { return ipV4Net, ipV6Net, ipDevice, nil } - return func() { getTransportIPNetDeviceByName = prevGetIPNetDeviceByName } + return func() { getTransportIPNetDeviceByNameFn = prevGetIPNetDeviceByName } } func mockGetIPNetDeviceByCIDRs(ipV4Net, ipV6Net *net.IPNet, ipDevice *net.Interface) func() { diff --git a/pkg/agent/agent_windows.go b/pkg/agent/agent_windows.go index beb50c9ef1f..78c04f1b23d 100644 --- a/pkg/agent/agent_windows.go +++ b/pkg/agent/agent_windows.go @@ -215,10 +215,7 @@ func (i *Initializer) prepareOVSBridgeOnHNSNetwork() error { // Set datapathID of OVS bridge. // If no datapathID configured explicitly, the reconfiguration operation will change OVS bridge datapathID // and break the OpenFlow channel. - // The length of datapathID is 64 bits, the lower 48-bits are for a MAC address, while the upper 16-bits are - // implementer-defined. Antrea uses "0x0000" for the upper 16-bits. - datapathID := strings.Replace(hnsNetwork.SourceMac, ":", "", -1) - datapathID = "0000" + datapathID + datapathID := util.GenerateOVSDatapathID(hnsNetwork.SourceMac) if err = i.ovsBridgeClient.SetDatapathID(datapathID); err != nil { klog.ErrorS(err, "Failed to set OVS bridge datapath_id", "datapathID", datapathID) return err @@ -366,10 +363,10 @@ func (i *Initializer) getTunnelPortLocalIP() net.IP { return i.nodeConfig.NodeTransportIPv4Addr.IP } -// saveHostRoutes saves routes which are configured on uplink interface before -// the interface the configured as the uplink of antrea HNS network. -// The routes will be restored on OVS bridge interface after the IP configuration -// is moved to the OVS bridge. +// saveHostRoutes saves routes configured on the uplink interface before the +// interface is configured as the uplink of Antrea HNS network. +// The routes will be restored on the OVS bridge interface after the IP +// configuration is moved to the OVS bridge. func (i *Initializer) saveHostRoutes() error { routes, err := util.GetNetRoutesAll() if err != nil { @@ -397,7 +394,7 @@ func (i *Initializer) saveHostRoutes() error { return nil } -func GetTransportIPNetDeviceByName(ifaceName string, ovsBridgeName string) (*net.IPNet, *net.IPNet, *net.Interface, error) { +func getTransportIPNetDeviceByName(ifaceName string, ovsBridgeName string) (*net.IPNet, *net.IPNet, *net.Interface, error) { // Find transport Interface in the order: ifaceName -> br-int. Return immediately if // an interface using the specified name exists. Using br-int is for restart agent case. for _, name := range []string{ifaceName, ovsBridgeName} { diff --git a/pkg/agent/secondarynetwork/init.go b/pkg/agent/secondarynetwork/init.go new file mode 100644 index 00000000000..1758962fb13 --- /dev/null +++ b/pkg/agent/secondarynetwork/init.go @@ -0,0 +1,125 @@ +// Copyright 2023 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 secondarynetwork + +import ( + "fmt" + "net" + + "github.com/TomCodeLV/OVSDB-golang-lib/pkg/ovsdb" + netdefclient "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/client/clientset/versioned/typed/k8s.cni.cncf.io/v1" + clientset "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/cache" + componentbaseconfig "k8s.io/component-base/config" + "k8s.io/klog/v2" + + "antrea.io/antrea/pkg/agent/interfacestore" + "antrea.io/antrea/pkg/agent/secondarynetwork/cnipodcache" + "antrea.io/antrea/pkg/agent/secondarynetwork/podwatch" + agentconfig "antrea.io/antrea/pkg/config/agent" + "antrea.io/antrea/pkg/ovs/ovsconfig" + "antrea.io/antrea/pkg/util/k8s" +) + +var ( + // Funcs which will be orridden with mock funcs in tests. + interfaceByNameFn = net.InterfaceByName + newOVSBridgeFn = ovsconfig.NewOVSBridge +) + +// Initialize sets up OVS bridges and starts the Pod controller for secondary networks. +func Initialize( + clientConnectionConfig componentbaseconfig.ClientConnectionConfiguration, + kubeAPIServerOverride string, + k8sClient clientset.Interface, + podInformer cache.SharedIndexInformer, + nodeName string, + podCache cnipodcache.CNIPodInfoStore, + interfaceConfigurator podwatch.InterfaceConfigurator, + stopCh <-chan struct{}, + config *agentconfig.SecondaryNetworkConfig, ovsdb *ovsdb.OVSDB) error { + if err := createOVSBridge(config.OVSBridges, ovsdb); err != nil { + return err + } + + // Create the NetworkAttachmentDefinition client, which handles access to secondary network object + // definition from the API Server. + netAttachDefClient, err := createNetworkAttachDefClient(clientConnectionConfig, kubeAPIServerOverride) + if err != nil { + return fmt.Errorf("NetworkAttachmentDefinition client creation failed: %v", err) + } + + // Create podController to handle secondary network configuration for Pods with + // k8s.v1.cni.cncf.io/networks Annotation defined. + podWatchController := podwatch.NewPodController( + k8sClient, + netAttachDefClient, + podInformer, + nodeName, + podCache, + interfaceConfigurator) + go podWatchController.Run(stopCh) + return nil +} + +// TODO: check and update bridge configuration. +func createOVSBridge(bridges []agentconfig.OVSBridgeConfig, ovsdb *ovsdb.OVSDB) error { + if len(bridges) == 0 { + return nil + } + // Only one OVS bridge is supported. + bridgeConfig := bridges[0] + + ovsBridgeClient := newOVSBridgeFn(bridgeConfig.BridgeName, ovsconfig.OVSDatapathSystem, ovsdb) + if err := ovsBridgeClient.Create(); err != nil { + return fmt.Errorf("failed to create OVS bridge %s: %v", bridgeConfig.BridgeName, err) + } + klog.InfoS("OVS bridge created", "bridge", bridgeConfig.BridgeName) + + if len(bridgeConfig.PhysicalInterfaces) == 0 { + return nil + } + phyInterface := bridgeConfig.PhysicalInterfaces[0] + if _, err := interfaceByNameFn(phyInterface); err != nil { + return fmt.Errorf("failed to get interface %s: %v", phyInterface, err) + } + + if _, err := ovsBridgeClient.GetOFPort(phyInterface, false); err == nil { + klog.V(2).InfoS("Physical interface already connected to OVS bridge, skip the configuration", "device", phyInterface, "bridge", bridgeConfig.BridgeName) + return nil + } + + _, err := ovsBridgeClient.CreateUplinkPort(phyInterface, 0, map[string]interface{}{interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaUplink}) + if err != nil { + return fmt.Errorf("failed to create OVS uplink port %s: %v", phyInterface, err) + } + klog.InfoS("Physical interface added to OVS bridge", "device", "phyInterface", "bridge", bridgeConfig.BridgeName) + + return nil +} + +// CreateNetworkAttachDefClient creates net-attach-def client handle from the given config. +func createNetworkAttachDefClient(config componentbaseconfig.ClientConnectionConfiguration, kubeAPIServerOverride string) (netdefclient.K8sCniCncfIoV1Interface, error) { + kubeConfig, err := k8s.CreateRestConfig(config, kubeAPIServerOverride) + if err != nil { + return nil, err + } + + netAttachDefClient, err := netdefclient.NewForConfig(kubeConfig) + if err != nil { + return nil, err + } + return netAttachDefClient, nil +} diff --git a/pkg/agent/secondarynetwork/init_test.go b/pkg/agent/secondarynetwork/init_test.go new file mode 100644 index 00000000000..ed7ef8fe5d3 --- /dev/null +++ b/pkg/agent/secondarynetwork/init_test.go @@ -0,0 +1,162 @@ +// Copyright 2023 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 secondarynetwork + +import ( + "errors" + "net" + "testing" + + "github.com/TomCodeLV/OVSDB-golang-lib/pkg/ovsdb" + mock "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + agentconfig "antrea.io/antrea/pkg/config/agent" + "antrea.io/antrea/pkg/ovs/ovsconfig" + ovsconfigtest "antrea.io/antrea/pkg/ovs/ovsconfig/testing" +) + +const nonExistingInterface = "non-existing" + +func TestCreateOVSBridge(t *testing.T) { + tests := []struct { + name string + ovsBridges []string + physicalInterfaces []string + expectedErr string + expectedCalls func(m *ovsconfigtest.MockOVSBridgeClient) + }{ + { + name: "no bridge", + }, + { + name: "no interface", + ovsBridges: []string{"br1"}, + expectedCalls: func(m *ovsconfigtest.MockOVSBridgeClient) { + m.EXPECT().Create().Return(nil) + }, + }, + { + name: "two bridges", + ovsBridges: []string{"br1", "br2"}, + expectedCalls: func(m *ovsconfigtest.MockOVSBridgeClient) { + m.EXPECT().Create().Return(nil) + }, + }, + { + name: "create br error", + ovsBridges: []string{"br1", "br2"}, + expectedErr: "create error", + expectedCalls: func(m *ovsconfigtest.MockOVSBridgeClient) { + m.EXPECT().Create().Return(ovsconfig.InvalidArgumentsError("create error")) + }, + }, + { + name: "one interface", + ovsBridges: []string{"br1"}, + physicalInterfaces: []string{"eth1"}, + expectedCalls: func(m *ovsconfigtest.MockOVSBridgeClient) { + m.EXPECT().Create().Return(nil) + m.EXPECT().GetOFPort("eth1", false).Return(int32(0), ovsconfig.InvalidArgumentsError("port not found")) + m.EXPECT().CreateUplinkPort("eth1", int32(0), map[string]interface{}{"antrea-type": "uplink"}).Return("", nil) + }, + }, + { + name: "two interfaces", + ovsBridges: []string{"br1", "br2"}, + physicalInterfaces: []string{"eth1", "eth2"}, + expectedCalls: func(m *ovsconfigtest.MockOVSBridgeClient) { + m.EXPECT().Create().Return(nil) + m.EXPECT().GetOFPort("eth1", false).Return(int32(0), ovsconfig.InvalidArgumentsError("port not found")) + m.EXPECT().CreateUplinkPort("eth1", int32(0), map[string]interface{}{"antrea-type": "uplink"}).Return("", nil) + }, + }, + { + name: "interface already attached", + ovsBridges: []string{"br1"}, + physicalInterfaces: []string{"eth1"}, + expectedCalls: func(m *ovsconfigtest.MockOVSBridgeClient) { + m.EXPECT().Create().Return(nil) + m.EXPECT().GetOFPort("eth1", false).Return(int32(0), nil) + }, + }, + { + name: "non-existing interface", + ovsBridges: []string{"br1"}, + physicalInterfaces: []string{nonExistingInterface, "eth2"}, + expectedErr: "failed to get interface", + expectedCalls: func(m *ovsconfigtest.MockOVSBridgeClient) { + m.EXPECT().Create().Return(nil) + }, + }, + { + name: "create port error", + ovsBridges: []string{"br1"}, + physicalInterfaces: []string{"eth1"}, + expectedErr: "create error", + expectedCalls: func(m *ovsconfigtest.MockOVSBridgeClient) { + m.EXPECT().Create().Return(nil) + m.EXPECT().GetOFPort("eth1", false).Return(int32(0), ovsconfig.InvalidArgumentsError("port not found")) + m.EXPECT().CreateUplinkPort("eth1", int32(0), map[string]interface{}{"antrea-type": "uplink"}).Return("", ovsconfig.InvalidArgumentsError("create error")) + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var bridges []agentconfig.OVSBridgeConfig + for _, brName := range tc.ovsBridges { + br := agentconfig.OVSBridgeConfig{BridgeName: brName} + br.PhysicalInterfaces = tc.physicalInterfaces + bridges = append(bridges, br) + } + + controller := mock.NewController(t) + mockOVSBridgeClient := ovsconfigtest.NewMockOVSBridgeClient(controller) + + defer mockNewOVSBridge(mockOVSBridgeClient)() + defer mockInterfaceByName()() + if tc.expectedCalls != nil { + tc.expectedCalls(mockOVSBridgeClient) + } + + err := createOVSBridge(bridges, nil) + if tc.expectedErr != "" { + assert.ErrorContains(t, err, tc.expectedErr) + } else { + require.NoError(t, err) + } + }) + } +} + +func mockInterfaceByName() func() { + prevFunc := interfaceByNameFn + interfaceByNameFn = func(name string) (*net.Interface, error) { + if name == nonExistingInterface { + return nil, errors.New("interface not found") + } + return nil, nil + } + return func() { interfaceByNameFn = prevFunc } +} + +func mockNewOVSBridge(brClient ovsconfig.OVSBridgeClient) func() { + prevFunc := newOVSBridgeFn + newOVSBridgeFn = func(bridgeName string, ovsDatapathType ovsconfig.OVSDatapathType, ovsdb *ovsdb.OVSDB) ovsconfig.OVSBridgeClient { + return brClient + } + return func() { newOVSBridgeFn = prevFunc } +} diff --git a/pkg/agent/util/net.go b/pkg/agent/util/net.go index 1f5b96cedac..7e08780c104 100644 --- a/pkg/agent/util/net.go +++ b/pkg/agent/util/net.go @@ -436,3 +436,13 @@ func GetIPNetsByLink(link *net.Interface) ([]*net.IPNet, error) { } return addrs, nil } + +// GenerateOVSDatapathID generates an OVS datapath ID string. +func GenerateOVSDatapathID(macString string) string { + // The length of datapathID is 64 bits, the lower 48-bits are for a MAC address, while the + // upper 16-bits are implementer-defined. Antrea uses "0x0000" for the upper 16-bits. + if macString == "" { + macString = GenerateRandomMAC().String() + } + return "0000" + strings.Replace(macString, ":", "", -1) +} diff --git a/pkg/agent/util/net_test.go b/pkg/agent/util/net_test.go index c4d51896509..42bc4187e01 100644 --- a/pkg/agent/util/net_test.go +++ b/pkg/agent/util/net_test.go @@ -459,6 +459,34 @@ func TestGetIPNetsByLink(t *testing.T) { } } +func TestGenerateOVSDatapathID(t *testing.T) { + tests := []struct { + name string + mac net.HardwareAddr + expectedID string + }{ + { + name: "valid MAC", + mac: net.HardwareAddr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}, + expectedID: "001122334455", + }, + { + name: "empty MAC", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + id := GenerateOVSDatapathID(tc.mac.String()) + if tc.expectedID != "" { + assert.Equal(t, "0000"+tc.expectedID, id) + } else { + assert.Equal(t, 16, len(id)) + assert.True(t, strings.HasPrefix(id, "0000")) + } + }) + } +} + func generateNetInterfaceAddrs(idx int) []net.Addr { netAddrsIPv4 := []net.Addr{&ipv4PublicIPNet} netAddrsIPv6 := []net.Addr{ diff --git a/pkg/config/agent/config.go b/pkg/config/agent/config.go index 8451695a83f..200deec1c64 100644 --- a/pkg/config/agent/config.go +++ b/pkg/config/agent/config.go @@ -147,13 +147,14 @@ type AgentConfig struct { NodePortLocal NodePortLocalConfig `yaml:"nodePortLocal,omitempty"` // FlowExporter configuration options. FlowExporter FlowExporterConfig `yaml:"flowExporter,omitempty"` - // Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or InClusterConfig. - // It is typically used when kube-proxy is not deployed (replaced by AntreaProxy). + // Provide the address of Kubernetes apiserver, to override any value provided in kubeconfig or + // InClusterConfig. It is typically used when kube-proxy is not deployed (replaced by AntreaProxy). // Defaults to "". It must be a host string, a host:port pair, or a URL to the base of the apiserver. KubeAPIServerOverride string `yaml:"kubeAPIServerOverride,omitempty"` - // Provide the address of DNS server, to override the kube-dns service. It's used to resolve hostname in FQDN policy. - // Defaults to "". It must be a host string or a host:port pair of the DNS server (e.g. 10.96.0.10, 10.96.0.10:53, - // [fd00:10:96::a]:53). + // Provide the address of DNS server, to override the kube-dns Service. It's used to resolve + // hostnames in a FQDN policy. + // Defaults to "". It must be a host string or a host:port pair of the DNS server (e.g. 10.96.0.10, + // 10.96.0.10:53, [fd00:10:96::a]:53). DNSServerOverride string `yaml:"dnsServerOverride,omitempty"` // Cipher suites to use. TLSCipherSuites string `yaml:"tlsCipherSuites,omitempty"` @@ -369,21 +370,14 @@ type PolicyBypassRule struct { } type SecondaryNetworkConfig struct { - // Secondary network specific OVS configuration. - OVS SecondaryNetworkOVSConfig `yaml:"ovs,omitempty"` - // TunnelType to be used for node to node transport, which is part of the same virtual network. - TunnelType string `yaml:"tunnelType,omitempty"` + // Configuration of OVS bridges for secondary networks. At the moment, only a + // single OVS bridge is supported. + OVSBridges []OVSBridgeConfig `yaml:"ovsBridges,omitempty"` } -type SecondaryNetworkOVSConfig struct { - // Enable Antrea's native secondary network OVS configuration. - Enable bool `yaml:"enable,omitempty"` - // OVS integration bridge name. - OVSIntegrationBridgeName string `yaml:"ovsIntegrationBridgeName,omitempty"` - // OVS transport bridge name. - OVSTransportBridgeName string `yaml:"ovsTransportBridgeName,omitempty"` - // OVS Datapath type to use for the OpenVSwitch bridge created by Antrea. - OVSDatapathType string `yaml:"ovsDatapathType,omitempty"` - // OVS patch port which connects the integration and transport bridge. - OVSPatchPort string `yaml:"ovsPatchPort,omitempty"` +type OVSBridgeConfig struct { + BridgeName string `yaml:"bridgeName"` + // Names of physical interfaces to be connected to the bridge. At the moment, + // only a single physical interface is supported. + PhysicalInterfaces []string `yaml:"physicalInterfaces,omitempty"` } diff --git a/pkg/ovs/ovsconfig/ovs_client.go b/pkg/ovs/ovsconfig/ovs_client.go index 72a0760b67e..b243e656011 100644 --- a/pkg/ovs/ovsconfig/ovs_client.go +++ b/pkg/ovs/ovsconfig/ovs_client.go @@ -98,7 +98,7 @@ func NewOVSDBConnectionUDS(address string) (*ovsdb.OVSDB, Error) { } // NewOVSBridge creates and returns a new OVSBridge struct. -func NewOVSBridge(bridgeName string, ovsDatapathType OVSDatapathType, ovsdb *ovsdb.OVSDB) *OVSBridge { +func NewOVSBridge(bridgeName string, ovsDatapathType OVSDatapathType, ovsdb *ovsdb.OVSDB) OVSBridgeClient { return &OVSBridge{ovsdb, bridgeName, ovsDatapathType, "", false, []int32{}} } diff --git a/pkg/util/k8s/client.go b/pkg/util/k8s/client.go index df19393696b..52cda5933f3 100644 --- a/pkg/util/k8s/client.go +++ b/pkg/util/k8s/client.go @@ -20,7 +20,6 @@ import ( "os" "strings" - netdefclient "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/client/clientset/versioned/typed/k8s.cni.cncf.io/v1" discovery "k8s.io/api/discovery/v1" apiextensionclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" "k8s.io/apimachinery/pkg/api/errors" @@ -43,7 +42,7 @@ const ( // CreateClients creates kube clients from the given config. func CreateClients(config componentbaseconfig.ClientConnectionConfiguration, kubeAPIServerOverride string) ( clientset.Interface, aggregatorclientset.Interface, crdclientset.Interface, apiextensionclientset.Interface, mcclientset.Interface, error) { - kubeConfig, err := createRestConfig(config, kubeAPIServerOverride) + kubeConfig, err := CreateRestConfig(config, kubeAPIServerOverride) if err != nil { return nil, nil, nil, nil, nil, err } @@ -76,21 +75,7 @@ func CreateClients(config componentbaseconfig.ClientConnectionConfiguration, kub return client, aggregatorClient, crdClient, apiExtensionClient, mcClient, nil } -// CreateNetworkAttachDefClient creates net-attach-def client handle from the given config. -func CreateNetworkAttachDefClient(config componentbaseconfig.ClientConnectionConfiguration, kubeAPIServerOverride string) (netdefclient.K8sCniCncfIoV1Interface, error) { - kubeConfig, err := createRestConfig(config, kubeAPIServerOverride) - if err != nil { - return nil, err - } - - netAttachDefClient, err := netdefclient.NewForConfig(kubeConfig) - if err != nil { - return nil, err - } - return netAttachDefClient, nil -} - -func createRestConfig(config componentbaseconfig.ClientConnectionConfiguration, kubeAPIServerOverride string) (*rest.Config, error) { +func CreateRestConfig(config componentbaseconfig.ClientConnectionConfiguration, kubeAPIServerOverride string) (*rest.Config, error) { var kubeConfig *rest.Config var err error