Guides

VRF & routage

Tables de routage multi-tenant (VRF) et routes statiques.

Un VRF dans siha est une table FIB VPP nommée. Chaque paquet transféré par l’appliance est recherché dans une table ; si vous ne faites rien, tout le trafic utilise la table 0 (le défaut implicite). Les VRF vous permettent de faire tourner plusieurs domaines de routage isolés sur une seule appliance — un par tenant, un par zone de sécurité, ou ce qui convient à votre topologie.

Ressource VRF

type: VRFs.routing.siha
metadata:
  namespace: routing
  id: tenant-a          # your friendly name; also what other resources reference
spec:
  table: 100            # VPP FIB table id, 1–4294967295 (0 is reserved for default)
  family: DUAL          # IPv4 | IPv6 | DUAL (default when omitted)
  description: "Tenant A production segment"

table est l’identifiant de table au niveau VPP — choisissez n’importe quel entier non nul unique parmi vos VRF. id est l’identifiant COSI lisible par l’humain que les ressources d’interface et de route référencent via leur champ vrf.

family contrôle quelles FIB de famille d’adresses sont créées dans VPP :

ValeurEffet
DUAL (défaut)tables FIB IPv4 et IPv6 créées toutes deux
IPv4seule la FIB IPv4 est créée
IPv6seule la FIB IPv6 est créée

Lier des interfaces à un VRF

Les interfaces portent un champ vrf qui prend l’id COSI d’une ressource VRFs.routing.siha. L’omettre (ou le laisser vide) lie l’interface à la table 0 par défaut.

Pour les interfaces routées (PMD, host-interface, loopback, tap, sous-interfaces VLAN/QinQ) :

type: Interfaces.link.siha
metadata: { namespace: link, id: ext-tenant-a }
spec:
  kind: pmd
  pciAddr: "0000:05:00.0"
  adminUp: true
  addresses: ["10.100.0.1/24"]
  vrf: tenant-a          # binds this interface to the tenant-a FIB table

Pour les interfaces de domaine de pont (bridge), le VRF se place sur le BVI (la passerelle L3 du pont), pas sur le pont lui-même :

type: Interfaces.link.siha
metadata: { namespace: link, id: lan }
spec:
  kind: bridge
  adminUp: true
  members: [lan-nic]
  bvi:
    addresses: ["10.20.0.1/24"]
    vrf: tenant-a          # BVI bound to tenant-a; top-level vrf must be omitted

Lorsqu’une interface est liée à un VRF et que pilotd lui assigne une adresse, VPP installe automatiquement une route connectée pour le préfixe de l’interface dans cette table. Vous n’avez pas besoin d’une ressource Route pour cela.

Routes statiques

Utilisez une ressource Route pour les destinations qui ne sont pas directement connectées — une route par défaut, un préfixe agrégé, ou un sous-réseau distant joignable via une passerelle amont.

type: Routes.routing.siha
metadata:
  namespace: routing
  id: default-tenant-a        # any unique id
spec:
  destination: "0.0.0.0/0"   # prefix to match (CIDR notation)
  gateway: "10.100.0.254"     # next-hop address (must be reachable in the VRF)
  vrf: tenant-a               # COSI id of the target VRF (omit for default table 0)

Le champ vrf se résout en l’identifiant numérique de table du VRF au moment de la réconciliation. Si le VRF référencé n’existe pas encore, le contrôleur remonte une erreur dans RouteStatus.lastError et réessaie — il n’y a pas d’exigence d’ordre strict dans le manifeste, mais le VRF doit exister avant que la route ne soit installée dans VPP.

Une route dans la table par défaut (sans VRF) omet entièrement le champ vrf :

type: Routes.routing.siha
metadata: { namespace: routing, id: default }
spec:
  destination: "0.0.0.0/0"
  gateway: "192.168.1.1"

Exemple complet : deux tenants isolés

# --- Tenant A VRF ---
type: VRFs.routing.siha
metadata: { namespace: routing, id: tenant-a }
spec:
  table: 100
  description: "Tenant A"
---
# --- Tenant B VRF ---
type: VRFs.routing.siha
metadata: { namespace: routing, id: tenant-b }
spec:
  table: 200
  description: "Tenant B"
---
# Tenant A uplink (connected /24 auto-installed, no Route needed)
type: Interfaces.link.siha
metadata: { namespace: link, id: uplink-a }
spec:
  kind: pmd
  pciAddr: "0000:05:00.0"
  adminUp: true
  addresses: ["10.100.0.1/24"]
  vrf: tenant-a
---
# Tenant A default route via its upstream gateway
type: Routes.routing.siha
metadata: { namespace: routing, id: default-a }
spec:
  destination: "0.0.0.0/0"
  gateway: "10.100.0.254"
  vrf: tenant-a
---
# Tenant B uplink
type: Interfaces.link.siha
metadata: { namespace: link, id: uplink-b }
spec:
  kind: pmd
  pciAddr: "0000:06:00.0"
  adminUp: true
  addresses: ["10.200.0.1/24"]
  vrf: tenant-b
---
# Tenant B default route
type: Routes.routing.siha
metadata: { namespace: routing, id: default-b }
spec:
  destination: "0.0.0.0/0"
  gateway: "10.200.0.254"
  vrf: tenant-b

Le trafic entre tenant-a et tenant-b ne peut pas passer d’un côté à l’autre à moins que vous n’ajoutiez explicitement des routes qui pontent les deux tables. VPP impose l’isolation FIB.

Exploitation

S="sihactl --sihaconfig ~/.siha/config --addr <node-ip>:6443"

# List all VRFs with their table id, family, and any error
$S get vrf

# Full spec + status for a single VRF
$S get vrf tenant-a -o yaml

# List all static routes with destination, gateway, resolved table, and errors
$S get route

# Full detail for one route
$S get route default-a -o yaml

# Watch routes as changes are applied
$S watch route

VRFStatus montre l’identifiant de table VPP et la famille d’adresses tels que matérialisés. RouteStatus montre le vrfTable résolu (la table FIB numérique dans laquelle la route a été installée), ce qui est utile pour confirmer qu’une référence de VRF s’est résolue correctement.

Points d’attention

La table 0 est réservée. Le VRF par défaut implicite utilise toujours la table 0 ; siha rejette toute ressource VRFs.routing.siha dont le champ table vaut 0. Utilisez n’importe quel entier non nul (1–4294967295) pour les VRF définis par l’opérateur.

Les routes connectées sont automatiques. Lorsque pilotd assigne une adresse à une interface liée à un VRF, VPP installe automatiquement le préfixe connecté. N’ajoutez pas de Route pour le sous-réseau propre de l’interface — une route statique dupliquée est inoffensive mais inutile.

Le VRF doit exister avant que ses routes ne soient installées. Le contrôleur de routes réessaie sur une référence de VRF manquante, mais il y a une brève fenêtre pendant laquelle RouteStatus.lastError affiche une erreur de résolution. Appliquez d’abord la ressource VRF (ou dans le même bundle) pour éviter le cycle de réessai.

Les routes apprises par BGP cohabitent avec les routes statiques dans la même FIB. Le contrôleur BGP programme ses meilleurs chemins dans les tables FIB VPP en utilisant les mêmes identifiants de table. Si vous combinez des pairs BGP avec des routes statiques dans le même VRF, assurez-vous que leurs préfixes n’entrent pas en conflit — le préfixe le plus spécifique l’emporte dans la correspondance par plus long préfixe de VPP, comme sur n’importe quel routeur.