Cette page décrit en détail l'architecture de collecte FTTH mutualisée au sein de Grenode. Pour l'heure cette infra est uniquement utilisée pour la collecte FTTH Axione.

Prérequis :

  • DHCP
  • RADIUS: Authentication, Authorization and Accounting

Fonctionnement de la collecte

Principe général

La mutualisation de la collectes FTTH se passe sur les machines ?rosette et ?gabier. D'un point de vue réseau, ces deux machines se retrouvent entre les BNG/RADIUS du fournisseur de collecte et les réseaux des membres de Grenode. Elles assurent un rôle de proxy radius avancé, de serveur DHCP et de routeur.

[BNG]: Broadband Network Gateway : équipements situés sur le réseau de l'opérateur de collecte et servant de passerelle aux routeurs des abonnés.

Processus lors de la connexion d'un abonné FTTH

  1. Le routeur abonné émet un DHCP Discover (v4 ou v6)
  2. L'OLT modifie le DHCP Discover pour y insérer le Circuit-ID et l'envoi au BNG
  3. Le BNG bloque le DHCP Discover et émet une requête d'authentification RADIUS Access-Request contenant le Circuit-ID du lien FTTH.
  4. L'Access-Request arrive sur ?rosette ou ?gabier, qui aiguille la requête vers le Radius du FAI membre, en fonction du Circuit-ID.
  5. Le Radius du FAI répond avec un Access-Accept, qui contient également les paramètres IP à fournir en DHCP et le profil de débit à appliquer
  6. ?rosette ou ?gabier reçoivent l'Access-Accept et provisionnent à la volée leurs serveurs DHCP.
  7. L'Access-Accept est routé jusqu'au BNG, qui libère le DHCP Discover inital. Le BNG agit comme relay DHCP et envoie le Discover en unicast vers ?rosette ou ?gabier.
  8. La suite de l'échange DHCP s'effectue de manière classique entre le BNG et ?rosette ou ?gabier
  9. Le routeur abonné reçoit ses adresses IP publiques.

En schéma:

--- ABONNÉ ---   ---      FOURNISSEUR     ---          --- GRENODE ---      --- MEMBRE ---

ROUTEUR                                 PROXY          PROXY     SERVEUR
ABONNÉ           OLT         BNG        RADIUS         RADIUS     DHCP           RADIUS
   ·     (1)      ·           ·           ·              ·         ·               ·
   o------------->·    (2)    |           ·              ·         ·               ·
   ·              o---------->|    (3)    ·              ·         ·               ·
   ·              ·           o---------->|     (3)      ·         ·               ·
   ·              ·           ·           o------------->|            (4)          ·
   ·              ·           ·           ·              o------------------------>|
   ·              ·           ·           ·              ·            (5)          |
   ·              ·           ·           ·              |<------------------------o
   ·              ·           ·           ·              |   (6)   ·
   ·              ·           .           ·     (7)      o-------->|
   ·              ·           ·    (7)    |<-------------o         ·
   ·              ·           |<----------o                        ·
   ·              ·           |                                    ·
   ·              ·           |                 (8)                ·
   ·              ·           o----------------------------------->|
   ·              ·           ·                 (9)                |
   ·              ·           |<-----------------------------------o
   ·              ·           |
   |<-------------------------o

Principe de routage des flux d'un abonné FTTH

Le BNG agit comme proxy ARP/NDP. Il est donc possible de donner au routeur abonné n'importe quelle adresse IP de passerelle. Dans un soucis de simplicité et de standardisation, nous utilisons la première IP du subnet (.1 et :1)

?rosette et ?gabier effectuent du routage par IP source, afin d'envoyer le flux d'un abonné vers le bon FAI.

Le fournisseur de collecte annonce à Grenode les routes spécifiques à chaque abonné. Un /32 en IPv4, et un /128 + un /56 délégué en IPv6.
Ces routes sont ré-annoncées au FAI membre.

Dans le sens inverse, le FAI annonce une route pas défaut à Grenode. Grenode annonce une route par défaut à l'opérateur de collecte.

Proxy Radius

Contrairement à la Collecte xDSL, il n'est pas possible d'aiguiller facilement les requêtes en fonction d'un royaume (realm). Les requêtes sont aiguillées vers le bon FAI membre en fonction de leur Circuit-ID qui est sous la forme suivante:

olt-bsn42-01 pon 1/1/01/01/4/1/1/

Tout ce qui commence par "olt-XXX42" correspond aux connexions du RIP THD42, et est par défaut aiguillé vers le FAI Illyse dans notre cas.

Le proxy radius utilise le logiciel Freeradius. La configuration Freeradius permettant cet aiguillage se présente sous cette forme:

authorize {
[...]

    #if %{ADSL-Agent-Circuit-Id} exist and realm @gnd.ftth.axione
    if (&ADSL-Agent-Circuit-Id) && !(&ADSL-Agent-Circuit-Id =="") && (&User-Name =~ /@gnd\.ftth\.axione$$/  ) {

    if ( `/bin/grep -i %{ADSL-Agent-Circuit-Id} /srv/data/specific-ils-circuitid` ) {
            update request {
                    Calling-Station-Id := "%{User-Name}"
                    User-Name := "%{ADSL-Agent-Circuit-Id}"
                    User-Password := 'secret01'
            }
            update control {
                    Proxy-To-Realm := 'ils-ftth'
            }
    }
    elsif ( `/bin/grep -i %{ADSL-Agent-Circuit-Id} /srv/data/specific-rzn-circuitid` ) {
            update request {
                    Calling-Station-Id := "%{User-Name}"
                    User-Name := "%{ADSL-Agent-Circuit-Id}"
        User-Password := 'secret02'
            }
            update control {
                    Proxy-To-Realm := 'rzn-ftth'
            }
    }

    #THD42 --> ILS si pas de Circuit-ID spécifique trouvé
    #elsif ("%{ADSL-Agent-Circuit-Id}" =~ /olt-...42-.*/) { 
    elsif ("%{ADSL-Agent-Circuit-Id}" =~ /6f6c742d......34322d.*/) {
            update request {
                    Calling-Station-Id := "%{User-Name}"
                    User-Name := "%{ADSL-Agent-Circuit-Id}"
                    User-Password := 'secret01'
            }
            update control {
                    Proxy-To-Realm := 'ils-ftth'
            }
    }

    }

}

Dans les fichiers /srv/data/specific-XXX-circuitid, sont inscrit les Circuit-ID des liens qui ne rentrent pas dans les cas par défaut.

Avant de transmettre la requête radius au FAI membre, son format est légèrement modifié afin mettre l'adresse MAC du routeur abonné dans l'attribut Calling-Station-Id, et le Circuit-ID dans le champ User-Name.

Format d'une requête Access-Request envoyée par l'opérateur de collecte:

(79) Received Access-Request Id 178 from 109.74.90.58:60534 to 91.216.110.144:1812 length 158            
(79)   User-Name = "00:0d:b9:42:aa:60@gnd.ftth.axione"                                                   
(79)   User-Password = "password"                                                                             
(79)   NAS-IP-Address = 10.200.50.241                                                                    
(79)   ADSL-Agent-Circuit-Id = 0x6f6c742d62736e34322d303120706f6e20312f312f30312f30312f342f312f312f      
(79)   Alc-Client-Hardware-Addr = "00:0d:b9:42:aa:60"                                                    
(79)   Calling-Station-Id = "axione#OLT#"                                                                

Format d'une requête Access-Request envoyée par Grenode au FAI:

(79) Sent Access-Request Id 244 from 0.0.0.0:35620 to 89.234.140.4:1812 length 244
(79)   User-Name := "0x6f6c742d62736e34322d303120706f6e20312f312f30312f30312f342f312f312f"
(79)   User-Password := "secret01"
(79)   NAS-IP-Address = 10.200.50.241
(79)   ADSL-Agent-Circuit-Id = 0x6f6c742d62736e34322d303120706f6e20312f312f30312f30312f342f312f312f
(79)   Alc-Client-Hardware-Addr = "00:0d:b9:42:aa:60"
(79)   Calling-Station-Id := "00:0d:b9:42:aa:60@gnd.ftth.axione"
(79)   Event-Timestamp = "Feb  2 2020 12:31:36 CET"
(79)   Message-Authenticator := 0x00
(79)   Proxy-State = 0x313738

Format d'une requête Access-Accept envoyé par le FAI à Grenode:

(79) Received Access-Accept Id 244 from 89.234.140.4:1812 to 91.216.110.144:35620 length 119
(79)   Service-Type = Outbound-User
(79)   Alc-Ipv6-Address = 2a0e:c400:ff:f010:ffff:ffff:ffff:ffff
(79)   Framed-IPv6-Route = "2a0e:c400:0:a00::/56"
(79)   Class = 0x465454482d47502d444c3330306d31306d3530306b2d554c3330306d316d3530306b
(79)   Framed-IP-Address = 5.183.104.10
(79)   Proxy-State = 0x313738

Format d'une requête Access-Accept envoyé par Grenode à l'opérateur de collecte:

(79) Sent Access-Accept Id 178 from 91.216.110.144:1812 to 109.74.90.58:60534 length 0
(79)   Class = 0x465454482d47502d444c3330306d31306d3530306b2d554c3330306d316d3530306b

Afin de comprendre le contenu des attributs Circuit-ID et Class, il faut convertir la valeur affiché en hexadécimale en ascii.

ADSL-Agent-Circuit-Id = 0x6f6c742d62736e34322d303120706f6e20312f312f30312f30312f342f312f312f
                  = olt-bsn42-01 pon 1/1/01/01/4/1/1/
Class = 0x465454482d47502d444c3330306d31306d3530306b2d554c3330306d316d3530306b
      = FTTH-GP-DL300m10m500k-UL300m1m500k

Serveurs DHCP

Nous utilisons KEA comme serveur DHCP (aussi bien pour DHCPv4 que DHCPv6). Pour chaque abonné, une réservation est crée afin d'allouer des adresses stables.

"reservations": [
  {
    "circuit-id": "6f6c742d62736e34322d303120706f6e20312f312f30312f30312f342f312f312f",
    "ip-address": "5.183.104.10"
  }
 ]

Pour l'instant, kea-dhcpv6 ne permet pas de faire des réservations en utilisant le Circuit-id. En attendant, on utilise l'adresse mac (apprise dynamique par les échanges radius). Cette méthode est imparfaite, et fonctionne uniquement si le DUID du client DHCPv6 est construit sur la base de l'adresse MAC de l'interface WAN du routeur. (DUID-LLT ou DUID-LL)

"reservations": [
  {
    "hw-address": "00:0d:b9:42:aa:60",
    "ip-addresses": [ "2a0e:c400:ff:f010:ffff:ffff:ffff:ffff" ],
    "prefixes": [ "2a0e:c400:0:a00::/56" ]
  }
 ]

Ces réservations sont crées dynamiquement sur la base du message Radius Access-Accept renvoyé par le FAI membre. Freeradius exécute pour ce faire un script bash maison qui utilise l'API de KEA pour ajouter les réservations. On crée la réservation dans les serveurs DHCP de rosette et gabier

    post-auth {

    #rosette
    `/srv/script/createDhcpReservation.sh -c %{User-Name} -4 %{&proxy-reply:Framed-IP-Address} -m %{Proxy-request:Calling-Station-Id} -6 %{&proxy-reply:Alc-Ipv6-Address} -p %{&proxy-reply:Framed-IPv6-Route} -k http://91.216.110.144/kea`

    #gabier
    `/srv/script/createDhcpReservation.sh -c %{User-Name} -4 %{&proxy-reply:Framed-IP-Address} -m %{Proxy-request:Calling-Station-Id} -6 %{&proxy-reply:Alc-Ipv6-Address} -p %{&proxy-reply:Framed-IPv6-Route} -k http://91.216.110.145/kea`

    }

Les fonctions disponibles dans l'API de KEA sont très limitées (sans les "Premium Hook"). Le script récupère donc la totalité de la configuration, ajoute ou modifie la réservation, et pousse la nouvelle configuration. Cette opération de rechargement de configuration n'est effectuée qu'a la toute première connexion d'un nouvel abonné FTTH, ou si un paramètre à changé (Adresses IP, Mac-address, etc)

Le script interroge un reverse-proxy nginx, qui lui même interroge isc-kea-ctrl-agent, qui lui même configure kea-dhcp4-server et kea-dhcp6-server.

FreeRadius → createDhcpReservation.sh → nginx → isc-kea-ctrl-agent → kea-dhcp4-server
                                                                   → kea-dhcp6-server

Routage par IP source

Dans le sens remontant (abonné vers Internet), du routage par IP source est en place. En effet, l'ensemble des flux abonné arrivent sur rosette ou gabier sur la même interface réseau.

Afin d'envoyer les flux vers le bon FAI membre, on effectue un routage par ip source, avec une table de routage par FAI.

La méthode est documenté sur ?Mettre en place du source routing

Redondance

A l'heure actuelle, Grenode ne dispose que d'un tronc de collecte FTTH. Il a cependant été choisi d'avoir deux routeurs de collecte: ?rosette et ?gabier Gabier peut, si nécessaire, prendre le relai de rosette (en cas de panne ou de maintenance).

Il n'a pas été possible d'obtenir 2 sessions BGP vers le fournisseur de collecte. La session est donc montée sur une IP virtuelle qui peut basculer d'un routeur à l'autre.

Les configurations Freeradius, DHCP et routage sont entièrement symétriques.

Procédure de bascule vers gabier pour maintenance sur rosette:

rosette:~# systemctl stop freeradius
rosette:~# iptables -t nat -A PREROUTING  -d 91.216.110.144 -p udp --dport 1812 -j DNAT --to 91.216.110.145:1812 
rosette:~# iptables -t nat -A POSTROUTING -d 91.216.110.145 -p udp --dport 1812 -j SNAT --to-source 91.216.110.144
rosette:~# systemctl stop isc-kea-dhcp4-server
rosette:~# systemctl stop isc-kea-dhcp6-server
rosette:~# birdc disable ils_thorondor
rosette:~# birdc6 disable ils_thorondor
rosette:~# systemctl stop keepalived

Si besoin de redémarrer la machine, on désactive les services (systemctl disable XXX) et les sessions BGP de livraison dans les fichiers de configuration de bird, afin d'éviter une réactivation non voulue au reboot.

Les règles de DNAT/SNAT permettent de renvoyer les échanges Radius vers gabier. Elles ne sont pas strictement nécessaires, mais il a été constaté que les équipements du fournisseur ont du mal à basculer sur le radius secondaire. Cela peut entrainer des problèmes au renouvellement des baux DHCP. (routeur abonné sans IP pendant quelques secondes/minutes)