Configurar rede SR-IOV

Neste documento, descrevemos como configurar uma rede de virtualização de entrada/saída (SR-IOV, na sigla em inglês) de raiz única para clusters do Anthos em bare metal. O SR-IOV fornece virtualização de E/S para disponibilizar uma placa de interface de rede (NIC, na sigla em inglês) como dispositivos de rede no kernel do Linux. Isso permite que você gerencie e atribua conexões de rede aos pods. O desempenho é aprimorado conforme os pacotes se movem diretamente entre a NIC e o pod.

Use esse recurso se você precisar de uma rede rápida para as cargas de trabalho do pod. O SR-IOV para clusters do Anthos em bare metal permite que você configure as funções virtuais (VF, na sigla em inglês) nos dispositivos compatíveis dos nós do cluster. Também é possível especificar o módulo específico do kernel para vincular às VFs.

Esse recurso está disponível para clusters que executam cargas de trabalho, como clusters híbridos, independentes e de usuário.

O processo de configuração consiste nas seguintes etapas de alto nível:

  1. Configurar o cluster para ativar a rede SR-IOV;
  2. Configurar o operador SR-IOV, um recurso personalizado SriovOperatorConfig;
  3. Definir políticas de SR-IOV e configurar as VFs;
  4. Criar um recurso personalizado NetworkAttachmentDefinition que faz referência às VFs.

Requisitos

O recurso de rede SR-IOV exige que os drivers oficiais para os adaptadores de rede estejam presentes nos nós do cluster. Instale os drivers antes de usar o operador SR-IOV. Além disso, para usar o módulo vfio-pci nas VFs, verifique se o módulo está disponível nos nós em que será usado.

Ativar a rede SR-IOV para um cluster

Para ativar a rede SR-IOV, adicione a anotação baremetal.cluster.gke.io/enable-sriov-networking ao recurso personalizado do cluster. Além disso, defina o campo multipleNetworkInterfaces na seção clusterNetwork do recurso personalizado do cluster como true.

apiVersion: baremetal.cluster.gke.io/v1
kind: Cluster
metadata:
  name: cluster1
  annotations:
    baremetal.cluster.gke.io/enable-sriov-networking: "true"
spec:
  clusterNetwork:
    multipleNetworkInterfaces: true
    pods:
      cidrBlocks:
      - 192.168.0.0/16
    services:
      cidrBlocks:
      - 10.96.0.0/12

Configurar o operador SR-IOV

O recurso personalizado SriovOperatorConfig fornece configuração global para o recurso de rede SR-IOV. Esse recurso personalizado empacotado tem o nome default e está no namespace gke-operators. O recurso personalizado SriovOperatorConfig segue apenas esse nome e namespace.

É possível editar este objeto com o seguinte comando:

kubectl -n gke-operators edit sriovoperatorconfigs.sriovnetwork.k8s.cni.cncf.io default

Veja um exemplo de uma configuração de recurso personalizado SriovOperatorConfig:

apiVersion: sriovnetwork.k8s.cni.cncf.io/v1
kind: SriovOperatorConfig
metadata:
  name: default
  namespace: gke-operators
spec:
  configDaemonNodeSelector:
    nodePool: "withSriov"
  disableDrain: false
  logLevel: 2

A seção configDaemonNodeSelector permite limitar os nós que o operador SR-IOV pode processar. No exemplo anterior, o operador é limitado apenas aos nós que têm um rótulo nodePool: withSriov. Se o campo configDaemonNodeSelector não for especificado, os seguintes rótulos padrão serão aplicados:

beta.kubernetes.io/os: linux
node-role.kubernetes.io/worker: ""

O campo disableDrain especifica se é necessário executar uma operação de drenagem do nó do Kubernetes antes da reinicialização do nó ou antes da alteração de uma configuração específica da VF.

Criar políticas SR-IOV

Para configurar VFs específicas no cluster, você precisa criar um recurso personalizado SriovNetworkNodePolicy no namespace gke-operators.

Veja um exemplo de manifesto para um recurso personalizado SriovNetworkNodePolicy:

apiVersion: sriovnetwork.k8s.cni.cncf.io/v1
kind: SriovNetworkNodePolicy
metadata:
  name: policy-1
  namespace: gke-operators
spec:
  deviceType: "netdevice"
  mtu: 1600
  nodeSelector:
    baremetal.cluster.gke.io/node-pool: node-pool-1
  nicSelector:
    pfNames:
    - enp65s0f0
    deviceID: "1015"
    rootDevices:
    - 0000:01:00.0
    vendor: "15b3"
  numVfs: 4
  priority: 80
  resourceName: "mlnx"

A seção nodeSelector permite limitar ainda mais os nós em que as VFs precisam ser criadas. Essa limitação está acima dos seletores do SriovOperatorConfig descrito na seção anterior.

O campo deviceType especifica o módulo do kernel a ser usado para as VFs. As opções disponíveis para deviceType são:

  • netdevice para o módulo padrão de kernel padrão de VF;
  • vfio-pci para o driver VFIO-PCI.

O resourceName define o nome das VFs representadas no nó do Kubernetes.

Após a conclusão do processo de configuração, os nós de cluster selecionados conterão o recurso definido, conforme apresentado no exemplo a seguir (observe o gke.io/mlnx):

apiVersion: v1
kind: Node
metadata:
  name: worker-01
spec:
…
status:
  allocatable:
    cpu: 47410m
    ephemeral-storage: "210725550141"
    gke.io/mlnx: "4"
    hugepages-1Gi: "0"
    hugepages-2Mi: "0"
    memory: 59884492Ki
    pods: "250"
  capacity:
    cpu: "48"
    ephemeral-storage: 228651856Ki
    gke.io/mlnx: "4"
    hugepages-1Gi: "0"
    hugepages-2Mi: "0"
    memory: 65516492Ki
    pods: "250"

O operador sempre adicionará o prefixo gke.io/ a todos os recursos que você definir com SriovNetworkNodePolicy.

Especifique um seletor de NIC

Para que a SriovNetworkNodePolicy funcione corretamente, especifique pelo menos um seletor na seção nicSelector. Esse campo contém várias opções sobre como identificar funções físicas específicas (PFs, na sigla em inglês) nos nós do cluster. A maioria das informações exigidas por esse campo é descoberta para você e salva no recurso personalizado SriovNetworkNodeState. Haverá um objeto por cada nó que esse operador pode manipular.

Use o seguinte comando para ver todos os nós disponíveis:

kubectl -n gke-operators get sriovnetworknodestates.sriovnetwork.k8s.cni.cncf.io -o yaml

Aqui está um exemplo de um nó.

apiVersion: sriovnetwork.k8s.cni.cncf.io/v1
kind: SriovNetworkNodeState
metadata:
  name: worker-01
  namespace: gke-operators
spec:
  dpConfigVersion: "6368949"
status:
  interfaces:
  - deviceID: "1015"
    driver: mlx5_core
    eSwitchMode: legacy
    linkSpeed: 10000 Mb/s
    linkType: ETH
    mac: 1c:34:da:5c:2b:9c
    mtu: 1500
    name: enp1s0f0
    pciAddress: "0000:01:00.0"
    totalvfs: 4
    vendor: 15b3
  - deviceID: "1015"
    driver: mlx5_core
    linkSpeed: 10000 Mb/s
    linkType: ETH
    mac: 1c:34:da:5c:2b:9d
    mtu: 1500
    name: enp1s0f1
    pciAddress: "0000:01:00.1"
    totalvfs: 2
    vendor: 15b3
  syncStatus: Succeeded

Definir o particionamento da função física

Preste atenção especial ao campo pfNames da seção nicSelector. Além de especificar exatamente qual PF a ser usada, ele permite especificar as VFs exatas a serem usadas na PF especificada e no recurso definido na política.

Veja um exemplo:

apiVersion: sriovnetwork.k8s.cni.cncf.io/v1
kind: SriovNetworkNodePolicy
metadata:
  name: policy-1
  namespace: gke-operators
spec:
  deviceType: "netdevice"
  mtu: 1600
  nodeSelector:
    baremetal.cluster.gke.io/node-pool: node-pool-1
  nicSelector:
    pfNames:
    - enp65s0f0#3-6
    deviceID: "1015"
    rootDevices:
    - 0000:01:00.0
    vendor: "15b3"
  numVfs: 7
  priority: 80
  resourceName: "mlnx"

No exemplo anterior, o recurso gke.io/mlnx usa apenas VFs numeradas de 3 a 6 e mostra apenas quatro VFs disponíveis. Como as VFs são sempre criadas a partir do índice zero, o número solicitado de VFs, numVfs, precisa ser pelo menos tão alto quanto o valor de fechamento do intervalo (contando a partir de zero). Essa lógica de numeração é o motivo de numVfs ser definido como 7 no exemplo anterior. Se você definir um intervalo de 3 a 4 (enp65s0f0#3-4), numVfs precisará ser pelo menos 5.

Quando o particionamento não é especificado, o numVfs define o intervalo de VFs que está sendo usado, que sempre começa em zero. Por exemplo, se você definir numVfs=3 sem especificar o particionamento, a VFs 0-2 será usada.

Entender a prioridade da política

É possível especificar vários objetos SriovNetworkNodePolicy para lidar com vários fornecedores ou diferentes configurações de VF. O gerenciamento de vários objetos e fornecedores pode se tornar complicado quando várias políticas fazem referência a mesma PF. Para lidar com essas situações, o campo priority resolve os conflitos por nó.

Veja a lógica de priorização para as políticas de PF sobrepostas:

  1. Uma política de prioridade mais alta sempre substitui uma com prioridade mais baixa.

  2. As mesmas políticas de prioridade são mescladas:

    1. As políticas são classificadas por nome e processadas nessa ordem.
    2. As políticas com intervalo de VFs sobrepostas são substituídas.
    3. As políticas com particionamento de PF sem sobreposição são mescladas e todas estão presentes.

Uma política de alta prioridade é aquela com valor numérico mais baixo no campo priority. Por exemplo, a prioridade é maior para uma política com priority: 10 do que para uma política com priority: 20.

Nas seções a seguir, fornecemos exemplos de políticas para diferentes configurações de particionamento.

PF particionada

A implantação dos dois manifestos SriovNetworkNodePolicy a seguir resulta em dois recursos disponíveis: gke.io/dev-kernel e gke.io/dev-vfio. Cada recurso tem duas VFs que não são sobrepostas.

kind: SriovNetworkNodePolicy
metadata:
  name: policy-1
spec:
  deviceType: "netdevice"
  nodeSelector:
    baremetal.cluster.gke.io/node-pool: node-pool-1
  nicSelector:
    pfNames:
    - enp65s0f0#0-1
  numVfs: 2
  priority: 70
  resourceName: "dev-kernel"
kind: SriovNetworkNodePolicy
metadata:
  name: policy-2
spec:
  deviceType: "vfio-pci"
  nodeSelector:
    baremetal.cluster.gke.io/node-pool: node-pool-1
  nicSelector:
    pfNames:
    - enp65s0f0#2-3
  numVfs: 4
  priority: 70
  resourceName: "dev-vfio"

Intervalos de VF sobrepostas

A implantação dos dois manifestos SriovNetworkNodePolicy a seguir resulta na disponibilização apenas do recurso gke.io/dev-vfio. O intervalo de VF policy-1 é 0-2, que se sobrepõe a policy-2. Devido à nomeação, policy-2 foi processado por último. Portanto, apenas o recurso especificado em policy-2, gke.io/dev-vfio está disponível.

kind: SriovNetworkNodePolicy
metadata:
  name: policy-1
spec:
  deviceType: "netdevice"
  nodeSelector:
    baremetal.cluster.gke.io/node-pool: node-pool-1
  nicSelector:
    pfNames:
    - enp65s0f0
  numVfs: 3
  priority: 70
  resourceName: "dev-kernel"
kind: SriovNetworkNodePolicy
metadata:
  name: policy-2
spec:
  deviceType: "vfio-pci"
  nodeSelector:
    baremetal.cluster.gke.io/node-pool: node-pool-1
  nicSelector:
    pfNames:
    - enp65s0f0#2-3
  numVfs: 4
  priority: 70
  resourceName: "dev-vfio"

Verificar o status da configuração da política de SR-IOV

Ao aplicar as políticas de SR-IOV, é possível rastrear e visualizar a configuração final dos nós no recurso personalizado SriovNetworkNodeState para o nó específico. Na seção status, o campo syncStatus representa o estágio atual do daemon de configuração. O estado Succeeded indica que a configuração foi concluída. A seção spec do recurso personalizado SriovNetworkNodeState define o estado final da configuração das VFs para esse nó, com base no número de políticas e nas prioridades delas. Todas as VFs criadas serão listadas na seção status para as PFs especificadas.

Veja um exemplo de recurso personalizado SriovNetworkNodeState:

apiVersion: sriovnetwork.k8s.cni.cncf.io/v1
kind: SriovNetworkNodeState
metadata:
  name: worker-02
  namespace: gke-operators
spec:
  dpConfigVersion: "9022068"
  interfaces:
  - linkType: eth
    name: enp1s0f0
    numVfs: 2
    pciAddress: "0000:01:00.0"
    vfGroups:
    - deviceType: netdevice
      policyName: policy-1
      resourceName: mlnx
      vfRange: 0-1
status:
  interfaces:
  - Vfs:
    - deviceID: "1016"
      driver: mlx5_core
      mac: 96:8b:39:d8:89:d2
      mtu: 1500
      name: enp1s0f0np0v0
      pciAddress: "0000:01:00.2"
      vendor: 15b3
      vfID: 0
    - deviceID: "1016"
      driver: mlx5_core
      mac: 82:8e:65:fe:9b:cb
      mtu: 1500
      name: enp1s0f0np0v1
      pciAddress: "0000:01:00.3"
      vendor: 15b3
      vfID: 1
    deviceID: "1015"
    driver: mlx5_core
    eSwitchMode: legacy
    linkSpeed: 10000 Mb/s
    linkType: ETH
    mac: 1c:34:da:5c:2b:9c
    mtu: 1500
    name: enp1s0f0
    numVfs: 2
    pciAddress: "0000:01:00.0"
    totalvfs: 2
    vendor: 15b3
  - deviceID: "1015"
    driver: mlx5_core
    linkSpeed: 10000 Mb/s
    linkType: ETH
    mac: 1c:34:da:5c:2b:9d
    mtu: 1500
    name: enp1s0f1
    pciAddress: "0000:01:00.1"
    totalvfs: 2
    vendor: 15b3
  syncStatus: Succeeded

Criar um recurso personalizado NetworkAttachmentDefinition

Depois de configurar as VFs no cluster e elas ficarem visíveis no nó do Kubernetes como um recurso, você precisará criar um NetworkAttachmentDefinition que faça referência ao recurso. Faça a referência com uma anotação k8s.v1.cni.cncf.io/resourceName.

Veja um exemplo de manifesto NetworkAttachmentDefinition que faz referência ao recurso gke.io/mlnx:

apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: gke-sriov-1
  annotations:
    k8s.v1.cni.cncf.io/resourceName: gke.io/mlnx
spec:
  config: '{
      "cniVersion": "0.3.0",
      "name": "mynetwork",
      "type": "sriov",
      "ipam": {
        "type": "whereabouts",
        "range": "21.0.108.0/21",
        "range_start": "21.0.111.16",
        "range_end": "21.0.111.18"
      }
    }'

A NetworkAttachmentDefinition precisa ter a sriov como o tipo de CNI. Faça referência a todos os recursos personalizados NetworkAttachmentDefinition implantados nos pods com uma anotação k8s.v1.cni.cncf.io/networks.

Veja um exemplo de como referenciar o recurso personalizado NetworkAttachmentDefinition anterior em um pod:

apiVersion: v1
kind: Pod
metadata:
  name: samplepod
  annotations:
    k8s.v1.cni.cncf.io/networks: gke-sriov-1
spec:
  containers:
  ...

Ao fazer referência a um recurso personalizado NetworkAttachmentDefinition em cargas de trabalho, você não precisa se preocupar com as definições de recursos dos pods ou com a colocação em nós específicos, o que é feito automaticamente.

O exemplo a seguir mostra um recurso personalizado NetworkAttachmentDefinition com uma configuração de VLAN. Neste exemplo, cada VF pertence à VLAN 100:

apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: gke-sriov-vlan-100
  annotations:
    k8s.v1.cni.cncf.io/resourceName: gke.io/mlnx
spec:
  config: '{
      "cniVersion": "0.3.0",
      "name": "mynetwork",
      "type": "sriov",
      "vlan": 100,
      "ipam": {
        "type": "whereabouts",
        "range": "21.0.100.0/21"
      }
    }'

Mais informações

As seções a seguir contêm informações para ajudar a configurar a rede SR-IOV.

Reinicializações de nó

Quando o operador SR-IOV configura os nós, pode ser necessário reiniciá-los. É possível reinicializar os nós durante a configuração da VF ou do kernel. A configuração do kernel envolve ativar a compatibilidade com a funcionalidade de SR-IOV no sistema operacional.

Adaptadores de rede suportados

A tabela a seguir lista os adaptadores de rede compatíveis com clusters da versão 1.10.x:

Nome ID do fornecedor ID do dispositivo ID do dispositivo da VF
Intel i40e XXV710 8086 158a 154c
Intel i40e 25G SFP28 8086 158b 154c
Intel i40e 10G X710 SFP 8086 1572 154c
Intel i40e XXV710 N3000 8086 0d58 154c
Intel i40e 40G XL710 QSFP 8086 1583 154c
Intel ice Columbiaville E810-CQDA2 2CQDA2 8086 1.592 1889
Intel ice Columbiaville E810-XXVDA4 8086 1593 1889
Intel ice Columbiaville E810-XXVDA2 8086 159b 1889
Nvidia mlx5 ConnectX-4 15b3 1013 1014
Nvidia mlx5 ConnectX-4LX 15b3 1015 1016
Nvidia mlx5 ConnectX-5 15b3 1017 1018
Nvidia mlx5 ConnectX-5 Ex 15b3 1019 101a
Nvidia mlx5 ConnectX-6 15b3 101b 101c
Nvidia mlx5 ConnectX-6_Dx 15b3 101d 101e
Nvidia mlx5 MT42822 BlueField-2 integrado ao ConnectX-6 Dx 15b3 a2d6 101e