---
categories: openbsd network
title: Howto CARP sous OpenBSD
---

* Documentation : <https://www.openbsd.org/faq/pf/carp.html>

[CARP (Common Address Redundancy Protocol)](https://man.openbsd.org/man4/carp.4) est une alternative libre et sécurisée aux protocoles [VRRP](https://www.ietf.org/rfc/rfc3768.txt) et [HSRP](https://www.ietf.org/rfc/rfc2281.txt). Il permet à plusieurs équipements, sur un même segment réseau, de partager une même adresse IP. L'objectif principal du protocole est de permettre une bascule réseau sur un équipement secondaire en cas d'incident.

**Principe :** Une interface réseau d'un des équipements est configurée pour être dans un état MASTER ou BACKUP. L'interface MASTER émet régulièrement des paquets à destination de l'interface BACKUP pour prouver son bon fonctionnement. Le choix MASTER/BACKUP est effectué grâce à des priorités configurables. Si le BACKUP ne reçoit pas un paquet dans les temps (ou si il reçoit un paquet inférieur à sa priorité), il passera en MASTER.


## Configuration 

`advskew` est un des paramètres pour jouer sur le choix de qui est master. Entre deux hôtes avec des valeurs de `advskew` différentes, c'est celui avec la valeur la plus petite qui sera `MASTER`.

### manuelle

Sur le MASTER :

~~~
# ifconfig carp0 create
# ifconfig carp0 vhid 1 pass PASSWORD carpdev bnx0 advskew 1 192.0.2.30 netmask 255.255.255.224
~~~

Sur le BACKUP :

~~~
# ifconfig carp0 create
# ifconfig carp0 vhid 1 pass PASSWORD carpdev bnx0 advskew 128 192.0.2.30 netmask 255.255.255.224
~~~

### persistante

Sur le MASTER :

~~~
# cat /etc/hostname.carp0
192.0.2.30/27 carpdev bnx0 pass PASSWORD vhid 1 advskew 1
# sh /etc/netstart carp0
~~~

Sur le BACKUP :

~~~
# cat /etc/hostname.carp0
192.0.2.30/27 carpdev bnx0 pass PASSWORD vhid 1 advskew 128
# sh /etc/netstart carp0
~~~

### Création d'une interface CARP dans un VLAN

On peut attacher une interface CARP à une interface VLAN. L'interface carp0 sera alors isolée dans le VLAN auquel elle est attachée.

Pour la création d'un VLAN, voir [VLAN](VLAN)

~~~
# cat /etc/hostname.bnx0
up

# cat /etc/hostname.vlan42
vlandev bnx0 description "VLAN42"

# cat /etc/hostname.carp0
192.0.2.30/27 carpdev vlan42 pass PASSWORD vhid 1 advskew 128
~~~

## Le droit de préemption

Sur des équipements réseau de type firewall pour lesquels l'ensemble des interfaces doivent se trouver dans le même état (toutes MASTER ou BACKUP), on activera le paramètre kernel preempt :

~~~
# sysctl net.inet.carp.preempt=1
# echo 'net.inet.carp.preempt=1' >> /etc/sysctl.conf
~~~

L'activation de ce paramètre permet notamment la bascule de l'ensemble des interfaces d'un groupe CARP dans le cas d'un changement d'état d'une interface. En cas de bascule d'une interface, le compteur _carpdemote_ sera incrémenté de 1 sur le groupe entraînant une bascule de l'ensemble des membres du groupe CARP.

## Informations utiles

### Bascule CARP

Pour des raisons de maintenance, on peut vouloir forcer une bascule CARP. ATTENTION, cela bascule **toutes** les interfaces du groupe carp, c'est à dire, toutes les interfaces carp.
Nous conseillons de faire sur le MASTER :

~~~
# ifconfig -g carp carpdemote 50
~~~

Le MASTER va générer un paquet CARP avec la priorité 255 et le BACKUP va ainsi immédiatemment passer MASTER. Ce paquet peut être observé avec `tcpdump proto carp`

~~~
20:58:59.490207 CARPv2-advertise 36: vhid=1 advbase=1 advskew=12 demote=0 (DF) [tos 0x10]                                                                                                     
20:58:59.809967 CARPv2-advertise 36: vhid=1 advbase=1 advskew=12 demote=50 (DF) [tos 0x10]                                                                                                    

~~~

Pour avoir l'état actuel du compteur :

~~~
# ifconfig -g carp
carp: carp demote count 50
~~~

**Important** : Si le compteur carpdemote n'a pas la même valeur sur tous les membres CARP, alors le membre ayant la valeur carpdemote la plus faible (re)passera automatiquement master, même en forçant l'état.

Pour revenir à l'état initial

~~~
# ifconfig -g carp -carpdemote 50
~~~

À noter que l'on peut également faire `ifconfig carp0 down` ou `ifconfig carp0 advskew XXX` (avec XXX supérieur à l'actuel backup) mais c'est moins optimum (bascule non immédiate, perte de trafic pendant quelques secondes…)


### Remonter une interface CARP

Si on a coupé une interface carp en faisant `ifconfig carpX down`, pour la remettre en place, on vérifie que le `advskew` est bien supérieur à celui où le master est actuellement pour ne pas basculer directement en tant que MASTER. Si ce n'est pas le cas, on peut corriger avec `ifconfig carpX advskew xxx`. Lorsque c'est OK, il reste juste à faire `ifconfig carpX up`.

Attention, si le droit de préemption est activé, il faut penser à le désactiver avec `sysctl net.inet.carp.preempt=0` avant de réactiver l'interface CARP pour éviter que toutes les CARP changent de statut en cas de problème. Le réactiver une fois l'interface CARP correctement remise en place avec `sysctl net.inet.carp.preempt=1`.

### Cas pratique de bascule

Dans cet exemple, nous avons deux pare-feux configurés avec CARP.

Sur fw00 :

~~~
$ ifconfig carp
carp0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        lladdr 00:00:42:00:00:01
        index 12 priority 15 llprio 3
        carp: MASTER carpdev em0 vhid 1 advbase 1 advskew 1
        groups: carp
        status: master
        inet 192.0.2.30 netmask 0xffffffe0 broadcast 192.0.2.31
carp1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        lladdr 00:00:42:00:00:02
        index 13 priority 15 llprio 3
        carp: MASTER carpdev em1 vhid 2 advbase 1 advskew 1
        groups: carp
        status: master
        inet 192.0.2.60 netmask 0xffffffe0 broadcast 192.0.2.61
~~~

Sur fw01 :

~~~
$ ifconfig carp
carp0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        lladdr 00:00:42:00:00:03
        description: CARP DMZ
        index 16 priority 15 llprio 3
        carp: BACKUP carpdev em0 vhid 1 advbase 1 advskew 42
        groups: carp
        status: backup
        inet 192.0.2.30 netmask 0xffffffe0 broadcast 192.0.2.31
carp1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        lladdr 00:00:42:00:00:04
        description: CARP LAN
        index 17 priority 15 llprio 3
        carp: BACKUP carpdev em1 vhid 2 advbase 1 advskew 42
        groups: carp
        status: backup
        inet 192.0.2.60 netmask 0xffffffe0 broadcast 192.0.2.61
~~~

Nous souhaiterons mettre à jour fw00 et donc passer fw01 en master.

Sur fw00 :

~~~
# ifconfig -g carp carpdemote 50
# mv /etc/hostname.carp* /root/
~~~

Le master va alors immédiatement passer en backup. Le déplacement des fichiers de configuration CARP évite que les interfaces ne remontent en cas de redémarrage. On peut désormais lancer la mise à jour et effectuer notre redémarrage.

Une fois fw00 prêt à être réintégré en production, voici un moyen de garantir une re-bascule sans coupure en recréant nos interfaces CARP avec ifconfig sur fw00. Sur ce dernier nous créons les interfaces à la main en se basant sur le contenu des fichiers hostname.carpX (et en veillant à modifier la valeur du advskew pour une valeur plus élevée que celle actuellement configurée sur fw01).

Sur fw00 :

~~~
# ifconfig carp0 vhid 1 pass puffy carpdev em0 advskew 142 advbase 1 192.0.2.30 netmask 255.255.255.224 state backup
# ifconfig carp1 vhid 2 pass puffy carpdev em1 advskew 142 advbase 1 192.0.2.60 netmask 255.255.255.224 state backup
~~~

Nous avons désormais nos interfaces CARP en BACKUP sur fw00. Le failover est donc d'ores et déjà fonctionnel.

Il s'agit maintenant de remettre en place nos fichiers de configuration CARP.

Sur fw00 :

~~~
# mv /root/hostname.carp* /etc/
~~~

On bascule ensuite les interfaces CARP depuis fw01 pour les repasser en BACKUP sur ce dernier et en MASTER sur fw00.

Sur fw01 :

~~~
# ifconfig -g carp carpdemote 50
~~~

Le pare-feu fw00 doit être repassé en MASTER maintenant.

On remet les valeurs de advskew à zero sur notre MASTER.

Sur fw00 :

~~~
# ifconfig carp0 advskew 1
# ifconfig carp1 advskew 1
~~~

Enfin nous reconfigurons le carpdemote à 0 sur fw01.

Sur fw01 :

~~~
# ifconfig -g carp -carpdemote 50
~~~

Et c'est terminé !

### Optimisation CARP au (re)boot d'un BACKUP

Lorsque que l'on a un firewall en BACKUP, il est important de pouvoir le redémarrer sans que cela n'impacte le MASTER. Pour cela, il faut bien comprendre le comportement de CARP au démarrage : pendant un certain temps, il va toujours rester en BACKUP pour voir si il ne reçoit pas d'annonce d'un MASTER. Ce comportement est aussi présent lors de la (re)configuration même si le CARP était MASTER initialement. S'il n'a rien reçu, il passe en MASTER. Ce temps est d'attente correspond à la valeur du paramètre _advbase_ (par défaut à 1 seconde).

Conséquences de cela :

* Si on reconfigure une interface CARP MASTER, elle va passer en BACKUP pendant _advbase_ secondes ! Il est donc judicieux avant d'intervenir sur une machine qui est CARP MASTER, de vérifier et si besoin ajuster le paramètre _advbase_ à une valeur très faible.

* Si on redémarre une machine avec des CARP BACKUP, il est probable que son réseau ne soit pas opérationnel immédiatement (synchronisation _Spanning Tree_ qui prend 50 secondes par défaut sur un switch CISCO par exemple). L'interface va donc se déclarer en MASTER après son temps d'attente, et lorsque le réseau sera activera il y aura donc un conflit entre les deux MASTER. Il faut donc bien ajuster _advbase_ pour qu'il soit bien supérieur au temps d'arrivée du réseau. Une manière de faire est d'avoir une configuration en dur avec _advbase_ à 60 secondes par exemple, ce qui permet d'avoir des reboots transparents, puis on reconfigure manuellement _advbase_ à 10 secondes par exemple quand tout est redémarré.

> *Note :* Lors d'un reboot planifié on peut également décider de commenter l'ensemble des lignes présentes dans le(s) fichier(s) `/etc/hostname.carpX` : une fois la machine de nouveau disponible, il suffira de décommenter la configuration et recréer les interfaces via `sh /etc/netstart carp0 carp1`

### Services et CARP

Sous OpenBSD, plusieurs services sont capables de s'activer en fonction du statut d'une interface CARP : si l'interface est en BACKUP, une partie du service ne s'active pas, mais il s'active automatiquement si l'interface passe en MASTER. On peut notamment citer [OpenBGPD](OpenBGPD), [relayd](http://man.openbsd.org/relayd.8), [OSPFD](http://man.openbsd.org/ospfd) ou encore [sasyncd](sasyncd)


## Statistiques

On peut avoir des statistiques en utilisant [netstat](http://man.openbsd.org/netstat.1)

~~~
$ netstat -sp carp
carp:
        1816636 packets received (IPv4)
        684123 packets received (IPv6)
                0 packets discarded for bad interface
                0 packets discarded for wrong TTL
                0 packets shorter than header
                0 discarded for bad checksums
                0 discarded packets with a bad version
                1293450 discarded because packet too short
                2 discarded for bad authentication
                482883 discarded for unknown vhid
                0 discarded because of a bad address list
        9667 packets sent (IPv4)
        5792 packets sent (IPv6)
                0 send failed due to mbuf memory error
        35 transitions to master
~~~

## Logs

Les changements d'états des interfaces sont notés dans `/var/log/messages`. On peut augmenter la valeur du paramètre kernel `net.inet.carp.log` (par défaut à 2) afin d'avoir des traces plus parlantes.

~~~
# sysctl net.inet.carp.log=X (valeur X comprise entre 0 et 7)
~~~
