SwordArMor

Comment monter un point d’échange, partie technique : un serveur de routes avec bird

Présentation d’un point d’échange

Sur Internet, il y a globalement deux façons de parler aux autres opérateurs : soit en passant par du peering, soit en passant par un transitaire.
Un transitaire est un opérateur branché à beaucoup de monde qui se charge d’acheminer nos paquets vers le reste d’Internet et de relayer nos annonces BGP. Le contrat que l’on passe avec ce type d’opérateur est très généralement payant.
Un peering est un contrat entre deux opérateurs permettant de s’échanger du trafic entre eux (et éventuellement leurs clients), mais seulement. Bien que l’on atteint beaucoup moins de monde avec cette session BGP, l’intérêt est que ce type de contrat est très généralement gratuit pour les deux parties (si on oublie les frais annexes, comme la cross-connection). Pour que cela soit possible, ils faut que les deux opérateurs aient un câble entre eux. Comme il est très compliqué de se brancher avec tout le monde, il est très courant de voir des structure se chargeant de brancher beaucoup de monde entre eux, c’est que l’on appelle un point d’échange internet, souvent abrégé en IX ou IXP pour Internet eXchange Point.

Mais là, nous rencontrons un autre problème, le nombre de sessions BGP pour que tout le monde s’échange des routes. Soit on a un serveur de routes central, qui reçoit les annonces de tout le monde et les redistribue, ce qui permet à chaque participant à l’IX de ne monter une session BGP qu’avec le serveur de routes. Soit, il faudra que chaque participant monte une session avec chaque autre ; dans ce cas le nombre de sessions augmente au carré du nombre de participants, ce n’est pas envisageable sur le long terme.

Notez bien que je ne parle ici que du serveur de routes, quand on en arrive là, c’est que l’on a déjà reçu ses ressources RIPE afin d’adresser votre LAN d’interconnexion et surtout que l’on a du monde à brancher.

Notre serveur de route avec bird

Ici, bird ne va servir qu’à recevoir des routes et à les redistribuer, il est complètement inutile de les installer dans la table de routage du kernel. Un serveur de route n’est pas un routeur.
Toute la configuration de bird se fait dans /etc/bird.conf en IPv4 et dans /etc/bird6.conf. Cette configuration est tirée de ce que j’ai fait pour BreizhIX, l’ASN est 206165, le range IPv4 est 185.1.89.0/24 et le range IPv6 est 2001:7f8:b1::/64.

Configuration globale

Ici, c’est ce que nous retrouvons dans quasi toutes les configurations bird.

# Configure logging
log syslog { warning, error, fatal, bug };

# Turn on global debugging of all protocols
# debug protocols all;


# Override router ID and store ASN
router id 185.1.89.1;
define myasn = 206165;


#####################
# GENERAL PROTOCOLS #
#####################
# This pseudo-protocol watches all interface up/down events.
protocol device {
	# Scan interfaces every 5 seconds
        scan time 5;
}

Fonctions pour les filtres

Ces fonctions seront utilisées plus tard afin de filtrer les préfixes reçus par chaque pair BGP.

function check_import(int peeras; ip nexthop)
  prefix set martians;
  int set reserved_asn;
  prefix set our_prefixes;
{
    martians = [ 10.0.0.0/8+, 100.64.0.0/10+,
        127.0.0.0/8+, 169.254.0.0/16+, 172.16.0.0/12+,
        192.0.0.0/24+, 192.0.2.0/24+, 192.168.0.0/16+,
        198.18.0.0/15+, 198.51.100.0/24+, 203.0.113.0/24+,
        224.0.0.0/4+, 240.0.0.0/4+, 255.255.255.255/32 ];

    reserved_asn = [ 0, 64297..131071, 4200000000..4294967294, 4294967295 ];

    # Avoid too short and too long prefixes
    if (net.len < 8) || (net.len > 24) then return false;

    # Avoid 0.0.0.0/X (default route + 0.0.0.0/8)
    if net.ip = 0.0.0.0 then return false;

    # Avoid reserved networks
    if net ~ martians then return false;

    # Remove our prefixes. Only us can announce them
    # Remove also our interconnection prefixes. We are directly connected.
    if net ~ 185.1.89.0/24 then return false;

    # Check that the next AS is our neighbour's.
    # Same for next-hop
    if bgp_path.first != peeras then return false;
    if bgp_next_hop != nexthop then return false;

    # AS_PATH too long (2 because a member could re-annonce its clients on the
    # IXP)
    if bgp_path.len > 2 then return false;

    # Don't accept if path contains a reserved AS
    # Disabled because it removes legit prefixes
    # if bgp_path ~ reserved_asn then return false;

    return true;
}

# In;  each prefix annonced by peer
# Out: prefixes specified (drop all the rest)
function bgp_filter_customer_in (prefix set customer_prefix) {
	return (net ~ customer_prefix);
}

Gabarit de configuration

Ce bout de configuration nous évitera de le répéter pour chaque pair alors qu’il ne changera jamais.
Ce qui change par rapport à un pair BGP classique est le rs client qui indique à bird de ne pas insérer l’ASN du pair dans l’AS path lors de l’export de la route à un autre pair.

template bgp PEERS {
	local as myasn;
	import keep filtered;
	import all;
	export all;
	import limit 100 action restart;
	rs client;
	source address 185.1.89.1;
}

Définition des pairs

Je ne prends qu’un routeur de grifon en exemple, mais nous retrouvons une configuration de ce type pour chaque pair. L’ASN est 204092, l’IP d’interconnexion est 185.1.89.10 et le réseau annoncé est 89.234.186.0/24.

filter bgp_filter_grifon_nominoe_in {
	if (check_import(204092, 185.1.89.10) &&
	    bgp_filter_customer_in([ 89.234.186.0/24 ])) then {
	    	accept;
	} else {
		reject "Prefix filtered for Grifon";
	}
}

protocol bgp bgp_grifon_nominoe from PEERS {
	description "Grifon nominoe";
	neighbor 185.1.89.10 as 204092;
	import filter bgp_filter_grifon_nominoe_in;
}

Résultat final

De cette façon, nous avons bien un échange de route entre les pairs, sans les installer dans notre noyau.

panoramix ~ # birdc sh pr all
BIRD 1.6.3 ready.
name     proto    table    state  since       info
device1  Device   master   up     2017-03-19  
  Preference:     240
  Input filter:   ACCEPT
  Output filter:  REJECT
  Routes:         0 imported, 0 exported, 0 preferred
  Route change stats:     received   rejected   filtered    ignored   accepted
    Import updates:              0          0          0          0          0
    Import withdraws:            0          0        ---          0          0
    Export updates:              0          0          0        ---          0
    Export withdraws:            0        ---        ---        ---          0

bgp_awedia BGP      master   up     19:32:18    Established   
  Description:    awedia
  Preference:     100
  Input filter:   ACCEPT
  Output filter:  ACCEPT
  Import limit:   100
    Action:       restart
  Routes:         2 imported, 0 filtered, 1 exported, 2 preferred
  Route change stats:     received   rejected   filtered    ignored   accepted
    Import updates:              4          0          0          2          2
    Import withdraws:            0          0        ---          0          0
    Export updates:              3          2          0        ---          1
    Export withdraws:            0        ---        ---        ---          0
  BGP state:          Established
    Neighbor address: 185.1.89.11
    Neighbor AS:      61198
    Neighbor ID:      89.234.151.5
    Neighbor caps:    refresh AS4
    Session:          external route-server AS4
    Source address:   185.1.89.1
    Route limit:      2/100
    Hold timer:       153/180
    Keepalive timer:  50/60

bgp_grifon_nominoe BGP      master   up     2017-03-19  Established   
  Description:    Grifon nominoe
  Preference:     100
  Input filter:   bgp_filter_grifon_nominoe_in
  Output filter:  ACCEPT
  Import limit:   100
    Action:       restart
  Routes:         1 imported, 0 filtered, 3 exported, 0 preferred
  Route change stats:     received   rejected   filtered    ignored   accepted
    Import updates:              3          0          1          0          2
    Import withdraws:      1262772          0        ---    1262772          1
    Export updates:             15          1          0        ---         14
    Export withdraws:            9        ---        ---        ---          9
  BGP state:          Established
    Neighbor address: 185.1.89.10
    Neighbor AS:      204092
    Neighbor ID:      89.234.186.7
    Neighbor caps:    refresh enhanced-refresh restart-aware AS4
    Session:          external route-server AS4
    Source address:   185.1.89.1
    Route limit:      1/100
    Hold timer:       205/240
    Keepalive timer:  44/80

bgp_grifon_budic BGP      master   up     2017-03-19  Established   
  Description:    Grifon budic
  Preference:     100
  Input filter:   bgp_filter_grifon_budic_in
  Output filter:  ACCEPT
  Import limit:   100
    Action:       restart
  Routes:         1 imported, 0 filtered, 2 exported, 1 preferred
  Route change stats:     received   rejected   filtered    ignored   accepted
    Import updates:              3          0          0          0          3
    Import withdraws:      1262752          0        ---    1262752          0
    Export updates:              9          3          0        ---          6
    Export withdraws:            4        ---        ---        ---          4
  BGP state:          Established
    Neighbor address: 185.1.89.13
    Neighbor AS:      204092
    Neighbor ID:      89.234.186.6
    Neighbor caps:    refresh enhanced-refresh restart-aware AS4
    Session:          external route-server AS4
    Source address:   185.1.89.1
    Route limit:      1/100
    Hold timer:       164/240
    Keepalive timer:  30/80

panoramix ~ # birdc sh route all
BIRD 1.6.3 ready.
154.43.33.0/24     via 185.1.89.11 on eth2 [bgp_awedia 19:32:18] * (100) [AS61198i]
	Type: BGP unicast univ
	BGP.origin: IGP
	BGP.as_path: 61198
	BGP.next_hop: 185.1.89.11
	BGP.local_pref: 100
89.234.186.0/24    via 185.1.89.13 on eth2 [bgp_grifon_budic 19:06:23] * (100) [AS204092i]
	Type: BGP unicast univ
	BGP.origin: IGP
	BGP.as_path: 204092
	BGP.next_hop: 185.1.89.13
	BGP.local_pref: 100
                   via 185.1.89.10 on eth2 [bgp_grifon_nominoe 19:04:29] (100) [AS204092i]
	Type: BGP unicast univ
	BGP.origin: IGP
	BGP.as_path: 204092
	BGP.next_hop: 185.1.89.10
	BGP.local_pref: 100
89.234.151.0/24    via 185.1.89.11 on eth2 [bgp_awedia 19:32:18] * (100) [AS61198i]
	Type: BGP unicast univ
	BGP.origin: IGP
	BGP.as_path: 61198
	BGP.next_hop: 185.1.89.11
	BGP.local_pref: 100
panoramix ~ # ip route list 
default via 89.234.186.209 dev eth0  metric 2 
89.234.186.208/28 dev eth0  proto kernel  scope link  src 89.234.186.213 
172.16.0.0/24 dev eth3  proto kernel  scope link  src 172.16.0.2 
185.1.89.0/24 dev eth2  proto kernel  scope link  src 185.1.89.1 

Et vu du côté d’un participant à l’IX, nous allons bien voir l’autre participant directement, sans avoir l’ASN de l’IX dans notre chemin :

alarig@nominoe:~ % birdc show route all protocol bgp_breizhix
BIRD 1.5.0 ready.
154.43.33.0/24     via 185.1.89.11 on em0.22 [bgp_breizhix 19:33:49 from 185.1.89.1] * (100) [AS61198i]
	Type: BGP unicast univ
	BGP.origin: IGP
	BGP.as_path: 61198
	BGP.next_hop: 185.1.89.11
	BGP.local_pref: 100
89.234.151.0/24    via 185.1.89.11 on em0.22 [bgp_breizhix 19:33:49 from 185.1.89.1] * (100) [AS61198i]
	Type: BGP unicast univ
	BGP.origin: IGP
	BGP.as_path: 61198
	BGP.next_hop: 185.1.89.11
	BGP.local_pref: 100