Avec le changement des PE, on se doit de pouvoir proposer les mêmes offres DATA qu'avec les Cisco :
- Internet : Publique + NAT
- MPLS
- SDWAN (Hors cadre LNS)
Les accès Internet ont été vu dans l'ancien épisode. Il nous reste plus qu'à voir comment proposer du MPLS à nos clients avec les Mikrotiks 😄
Configuration
On va créer la VRF Customer1.
Tout d'abord, il nous faut une loopback :
#LNS1
/interface bridge
add name=Lo_Customer1
/ip address
add address=100.101.0.1 interface=Lo_Customer1
On crée une liste d'interface et on place la loopback du client dedans :
#LNS1
/interface list
add name=VRF-Customer1
/interface list member
add interface=Lo_Customer1 list=VRF-Customer1
Ensuite, on peut créer la VRF :
#LNS1
/ip vrf
add interfaces=VRF-Customer1 name=Customer1
A l'heure actuelle, on a créer une liste d'interface qu'on a placé dans la VRF cliente. Cette liste est dynamique ! Les clients PPP vont pouvoir monter dedans.
Et maintenant le PPP :
#LNS1
/ppp profile
add change-tcp-mss=yes interface-list=VRF-Customer1 local-address=100.101.0.1 name=Profile-Customer1 use-compression=no use-encryption=no use-mpls=no
Cette ligne va permettre de créer un profile PPP nommé Customer1. On va l'utiliser dans la configuration de l'user dans le freeradius.
Et on déclare le L3VPN MPLS dans le BGP :
#LNS1
/routing bgp vpn
add disabled=no export.redistribute=connected,static,bgp .route-targets=64555:64560 import.route-targets=64555:64560 instance=BGP_BACKBONE \
label-allocation-policy=per-vrf name=Customer1 route-distinguisher=64555:64560 vrf=Customer1
Bon c'est plutôt mal ! Regardons ce que ca donne avec un utilisateur configuré comme ca dans le radius :
#RADIUS
test1@naruto.ninja Cleartext-Password := "nathan"
Service-Type := Framed-User,
Framed-Protocol := PPP,
Framed-IP-Address := 100.64.0.1,
Framed-IP-Netmask := 255.255.255.255,
Framed-Route := "10.0.0.0/24 100.64.0.1",
Mikrotik-Group := "Profile-Customer1"
Le PPP monte bien :
#LNS1
[admin@PE-LNS1] /ppp/active> pr
Flags: R - RADIUS
Columns: NAME, SERVICE, CALLER-ID, ADDRESS, UPTIME
# NAME SERVICE CALLER-ID ADDRESS UPTIME
0 R test1@naruto.ninja pppoe 50:00:00:47:00:00 100.64.0.1 10s
La table de routage de la VRF Customer1 :
#LNS1
[admin@PE-LNS1] > /ip route/print where routing-table=Customer1
Flags: D - DYNAMIC; A - ACTIVE; c - CONNECT, b - BGP
Columns: DST-ADDRESS, GATEWAY, ROUTING-TABLE, DISTANCE
DST-ADDRESS GATEWAY ROUTING-TABLE DISTANCE
DAc 100.64.0.1/32 @Customer1 Customer1 0
DAc 100.101.0.1/32 Lo_Customer1@Customer1 Customer1 0
La framed route ? Wesh ? Elle est où ?
#LNS1
[admin@PE-LNS1] > /ip route/print where dst-address=10.0.0.0/24
Flags: D - DYNAMIC; I - INACTIVE; v - VPN
Columns: DST-ADDRESS, GATEWAY, ROUTING-TABLE, DISTANCE
DST-ADDRESS GATEWAY ROUTING-TABLE DISTANCE
DIv 10.0.0.0/24 100.64.0.1 main 1
Elle monte dans la VRF main .....
Et oui ! Mikrotik ne prend pas en charge les framed-routes dans des VRF 😦
Comment faire ? On ne va pas pouvoir proposer de MPLS aux clients ?
La solution à tous nos problèmes : BGP
On va monter des session eBGP entre les CPE et les PE !
Pensons industrialisation et automatisation :
- Un BGP listen range par VRF
- Redistribute connected,static sur les CPE
- Principe de nominal/backup
Tout d'abord, on commence par créer une template BGP sur les PE qui va servir pour tous les clients L3VPN MPLS :
#LNS1
/routing bgp template
add hold-time=1m keepalive-time=30s name=L3VPN-Customer output.default-originate=always
Ensuite, on peut configurer le BGP listen range :
#LNS1
/routing bgp connection
add instance=BGP_BACKBONE local.address=100.101.0.1 .role=ebgp name=Customer1 remote.address=100.64.0.0/16 templates=L3VPN-Customer vrf=Customer1
On autorise toute la plage 100.64.0.0/16 (Subnet de management des CPE) à pouvoir monter un peering avec l'IP 100.101.0.1 (Loopback de la VRF) dans la VRF Customer1.
Et .... c'est tout comme configuration ! Sah quel plaisir de réfléchir deux minutes en amont 😄
Du côté des CPE, on crée la route map qui va permettre de faire varier l'AS PATH dans les annonces. Plus un AS PATH est grand, moins la route est prioritaire.
#NOMINAL
/routing filter rule
add chain=RM_PRINCIPAL rule="if (dst in 10.0.0.0/8 || dst in 172.16.0.0/12 || dst in 192.168.0.0/16) { set bgp-path-prepend 1; accept }"
#BACKUP
/routing filter rule
add chain=RM_BACKUP rule="if (dst in 10.0.0.0/8 || dst in 172.16.0.0/12 || dst in 192.168.0.0/16) {set bgp-path-prepend 5; accept}"
#NOMINAL
/routing bgp connection
add as=64560 local.role=ebgp name=LNS1 output.filter-chain=RM_PRINCIPAL .redistribute=connected,static remote.address=100.101.0.1
#BACKUP
/routing bgp connection
add as=64560 local.role=ebgp name=LNS1 output.filter-chain=RM_BACKUP .redistribute=connected,static remote.address=100.101.0.1
Les peerings montent bien dans la VRF sur les LNS :
#LNS1
[admin@PE-LNS1] /routing/bgp/session> pr
Flags: E - established
0 E name="Customer1-1" instance=BGP_BACKBONE
remote.address=100.64.0.1@Customer1 .as=64560 .id=192.168.4.1 .capabilities=mp,rr,gr,as4 .afi=ip .messages=30 .bytes=603 .eor=""
local.address=100.101.0.1@Customer1 .as=64555 .id=100.124.0.1 .cluster-id=100.124.0.1 .capabilities=mp,rr,gr,as4 .afi=ip .messages=23 .bytes=549
.eor=""
output.procid=20 .default-originate=always
input.procid=20 ebgp
routing-table=Customer1 hold-time=1m keepalive-time=30s uptime=9m31s820ms last-started=2025-06-24 19:19:29 prefix-count=2
1 E name="Customer1-2" instance=BGP_BACKBONE
remote.address=100.64.0.2@Customer1 .as=64560 .id=192.168.2.1 .capabilities=mp,rr,gr,as4 .afi=ip .messages=8 .bytes=201 .eor=""
local.address=100.101.0.1@Customer1 .as=64555 .id=100.124.0.1 .cluster-id=100.124.0.1 .capabilities=mp,rr,gr,as4 .afi=ip .messages=8 .bytes=264
.eor=""
output.procid=21 .default-originate=always
input.procid=21 ebgp
routing-table=Customer1 hold-time=1m keepalive-time=30s uptime=2m18s160ms last-started=2025-06-24 19:26:43 prefix-count=2
Admettons que le subnet 192.168.1.0/24 doit être backup :
#LNS1
[admin@PE-LNS1] /ip/route> print where routing-table=Customer1 dst-address=192.168.1.0/24
Flags: D - DYNAMIC; A - ACTIVE; b - BGP
Columns: DST-ADDRESS, GATEWAY, ROUTING-TABLE, DISTANCE
DST-ADDRESS GATEWAY ROUTING-TABLE DISTANCE
DAb 192.168.1.0/24 100.64.0.1@Customer1 Customer1 20
D b 192.168.1.0/24 100.64.0.2@Customer1 Customer1 20
La route est bien annoncée par les deux CPE mais seul la route du principal monte dans la table de routage.
#LNS1
[admin@PE-LNS1] > /routing/route/print detail where routing-table=Customer1 dst-address=192.168.1.0/24
Flags: X - disabled, F - filtered, U - unreachable, A - active;
c - connect, s - static, r - rip, b - bgp, o - ospf, i - isis, d - dhcp, v - vpn, m - modem, a - ldp-address, l - ldp-mapping, g - slaac, y - bgp-mpls>
H - hw-offloaded; + - ecmp, B - blackhole
Ab afi=ip contribution=active dst-address=192.168.1.0/24 routing-table=Customer1 gateway=100.64.0.1@Customer1
immediate-gw=100.64.0.1% distance=20 scope=40 target-scope=10 belongs-to="bgp-IP-100.64.0.1@*1"
bgp.session=Customer1-1 .as-path="64560" .origin=igp
debug.fwp-ptr=0x20302A80
b afi=ip contribution=candidate dst-address=192.168.1.0/24 routing-table=Customer1 gateway=100.64.0.2@Customer1
immediate-gw=100.64.0.2% distance=20 scope=40 target-scope=10 belongs-to="bgp-IP-100.64.0.2@*1"
bgp.session=Customer1-2 .as-path="64560,64560,64560,64560,64560" .origin=igp
debug.fwp-ptr=0x20302C00
Comme vous pouvez le voir, la route est bien apprise deux fois mais avec un AS PATH différent. Ainsi, le PE va privilégier la route avec .as-path="64560" plutôt que .as-path="64560,64560,64560,64560,64560".
Et du côté de LNS2 ? Ca dit quoi ?
#LNS2
[admin@PE-LNS2] > /ip route/print where routing-table=Customer1
Flags: D - DYNAMIC; A - ACTIVE; c - CONNECT, y - BGP-MPLS-VPN
Columns: DST-ADDRESS, GATEWAY, ROUTING-TABLE, DISTANCE
DST-ADDRESS GATEWAY ROUTING-TABLE DISTANCE
DAy 192.168.1.0/24 100.124.0.1 Customer1 200
DAy 100.64.0.1/32 100.124.0.1 Customer1 200
DAy 100.64.0.2/32 100.124.0.1 Customer1 200
D y 100.101.0.1/32 100.124.0.1 Customer1 200
DAc 100.101.0.1/32 Lo_Customer1@Customer1 Customer1 0
Les routes sont bien inscrites dans la table de routage de la VRF 😄!
Allez un peu d'automatisation
Pour récapituler, il nous comme informations :
- Le nom de la VRF
- Le RD
- L'AS des CPE
- IP de la Loopback de la VRF
J'utilise Netbox pour mon IPAM. C'est ma source de vérité. Toutes les informations de mon réseau sont dedans. Que ce soit le subnet d'interco de deux routeurs backbone comme la position précise d'un device dans une baie dans un datacenter.
Il existe une API qui permet d'interroger Netbox et faire du first available. C'est ce qu'il nous faut ! On va prendre le premier RD dispo, l'AS et une IP pour la looback. Le nom de la VRF sera donné par l'utilisateur qui souhaite réserver la configuration. Une fois la réservation faite, je souhaite que le même utilisateur puisse pousser la configuration de façon automatique sur les LNS.
Pour répondre à ces besoin, je vais utiliser du go et de l'ansible. Le go me servira à interroger l'API netbox et lancer le playbook ansible (qui servira à pousser la configuration sur les LNS). Le tout avec une API en gin.
Avec une simple requête HTTP, on va pouvoir réserver et pousser la configuration 😄
Le code est ici :
J'utilise les custom fields de netbox. Pour une machine virtuelle (une VRF donc un client), je peux utiliser un json :

(Ne faites pas attention au custom field Fortigate, c'est pour automatiser la production de VDOM sur le même principe de go et ansible 😄)
Le code a donc réservé l'AS 4210000000 pour les CPE et 100.101.0.1 comme IP pour la loopback. Le RD sera toujours AS_BGP:AS_CPE. Donc 64555:4210000000.
Pour réserver les ressources (AS et IPLooback), j'utilise cette commande :
curl -X POST http://192.168.1.59:8081/conflns -H "Content-Type: application/json" -d '{"Vdom":"VRF_CLIENTE"}'
Pour pousser la configuration, j'utilise cette commande :
curl -X POST http://192.168.1.59:8081/postlns -H "Content-Type: application/json" -d '{"Vdom":"VRF_CLIENTE"}'
Ensuite, j'ai un playbook ansible qui vient s'exécuter sur les LNS.
Et le pire la dedans, c'est que ça fonctionne ;)
Conclusion
La configuration d'un L3VPN MPLS diffère un peu entre Mikrotik et Cisco surtout que j'ai dû changer la manière d'annoncer les subnets dans les MPLS clients avec la non prise en charge des framed-routes côté Mikrotik mais je suis plutôt content du résultat.
Un tech/admin réseau ne sera plus obligé de créer x framed route sur les logins. Un gain de temps non négligeable ! De plus, cette méthode permet d'avoir TOUT LE TEMPS la même template de configuration sur les CPE. Et pour les PE, c'est automatiser via le script go + ansible.
Prochain épisode : Soit je regarde comment recollecter les 4G/Starlink sur les LNS soit je commence à monter mon infra de virtualisation (cluster proxmox en EVPN/VXLAN sur mes Spines et du ZFS pour mon stockage).
Je termine sur un mot de fin : Si la production est industrialisée et automatisée, TOUT coulera de source après. Que ce soit le support, l'exploitation ou un ajout de sites pour un client.
Une production propre est nécessaire pour tout opérateur !