Je suis Charlie

Autres trucs

Accueil

Seulement les RFC

Seulement les fiches de lecture

Mon livre « Cyberstructure »

Ève

RFC 8522: Looking Glass Command Set

Date de publication du RFC : Février 2019
Auteur(s) du RFC : M. Stubbig
Pour information
Première rédaction de cet article le 6 février 2019


Avec plusieurs systèmes de routage, et notamment avec le protocole standard de l'Internet, BGP, un routeur donné n'a qu'une vue partielle du réseau. Ce que voit votre routeur n'est pas forcément ce que verront les autres routeurs. Pour déboguer les problèmes de routage, il est donc souvent utile de disposer d'une vue sur les routeurs des autres acteurs. C'est fait par le biais de looking glasses qui sont des mécanismes permettant de voir l'état d'un routeur distant, même géré par un autre acteur. Il n'y a aucun standard pour ces mécanismes, il faut donc tout réapprendre pour chaque looking glass, et il est difficile d'automatiser la collecte d'informations. Ce RFC propose une solution (surtout théorique aujourd'hui) : une norme des commandes à exécuter par un looking glass, utilisant les concepts REST.

Voyons d'abord deux exemples de looking glass. Le premier, au France-IX, utilise une interface Web : lg-franceix.png

Le second, chez Route Views, utilise telnet :

% telnet route-views3.routeviews.org
...
route-views3.routeviews.org> show bgp 2001:678:c::1
BGP routing table entry for 2001:678:c::/48
Paths: (8 available, best #4, table Default-IP-Routing-Table)
  Not advertised to any peer
  39351 2484
    2a03:1b20:1:ff01::5 from 2a03:1b20:1:ff01::5 (193.138.216.164)
      Origin IGP, localpref 100, valid, external
      AddPath ID: RX 0, TX 179257267
      Last update: Mon Jan 28 15:22:29 2019
                                           
  46450 6939 2484
    2606:3580:fc00:102::1 from 2606:3580:fc00:102::1 (158.106.197.135)
      Origin IGP, localpref 100, valid, external
      AddPath ID: RX 0, TX 173243076
      Last update: Sat Jan 26 08:26:39 2019
...
    

Notez que le premier looking glass n'affichait que les routes locales au point d'échange alors que le second voit toute la DFZ. Les looking glasses jouent un rôle essentiel dans l'Internet, en permettant d'analyser les problèmes réseau chez un autre opérateur. (On peut avoir une liste, très partielle et pas à jour, des looking glasses existants en http://traceroute.org/#Looking%20Glass.)

La section 2 de notre RFC décrit le fonctionnement de ce looking glass normalisé. Il y a trois acteurs, le client, le serveur et le routeur. Le client est le logiciel utilisé par l'administrateur réseaux qui veut des informations (par exemple curl), le serveur est le looking glass, le routeur est la machine qui possède les informations de routage. (Le RFC l'appelle « routeur » mais ce n'est pas forcément un routeur, cela peut être une machine spécialisée qui récolte les informations en parlant BGP avec les routeurs.) Entre le client et le serveur, on parle HTTP ou, plus exactement, HTTPS. Le client ne parle pas directement au routeur. La communication entre le serveur et le routeur se fait avec le protocole de leur choix, il n'est pas normalisé (cela peut être SSH, NETCONF, etc).

La requête se fera toujours avec la méthode HTTP GET, puisqu'on ne modifie rien sur le serveur. Si le serveur est lg.op.example, la requête sera vers l'URL https://lg.op.example/.well-known/looking-glass/v1 (le préfixe bien connu est décrit dans le RFC 8615, et ce looking-glass figure désormais dans le registre IANA). L'URL est complété avec le nom de la commande effectuée sur le routeur. Évidemment, on ne peut pas exécuter de commande arbitraire sur le routeur, on est limité au jeu défini dans ce RFC, où on trouve les grands classiques comme ping ou bien l'affichage de la table de routage. La commande peut être suivie de détails, comme l'adresse IP visée, et de paramètres. Parmi ces paramètres :

  • protocol qui indique notamment si on va utiliser IPv4 ou IPv6,
  • router qui va indiquer l'identité du routeur qui exécutera la commande, pour le cas, fréquent, où un même serveur looking glass donne accès à plusieurs routeurs.
  • vrf (Virtual Routing and Forwarding), une table de routage spécifique, pour le cas où le routeur en ait plusieurs,
  • format, qui indique le format de sortie souhaité sous forme d'un type MIME ; par défaut, c'est text/plain. Attention, c'est le format des données envoyées par le routeur, pas le format de l'ensemble de la réponse, qui est forcément en JSON.

Le code de retour est un code HTTP classique (RFC 7231, section 6), la réponse est de type application/json, suivant le profil JSend, rappelé dans l'annexe A. Ce profil impose la présence d'un champ success, ainsi que d'un champ data en cas de succès. Voici un exemple où tout s'est bien passé :

HTTP/1.1 200 OK
Content-Type: application/json
{
     "status" : "success",
     "data" : {
       "router" : "route-server.lg.op.example"
       "performed_at" : "2019-01-29T17:13:11Z",
       "runtime" : 2.63,
       "output" : [
         "Neighbor              V         AS MsgRcvd MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd
          2001:67c:16c8:18d1::1 4     206479   80966   79935        0    0    0 01w2d14h            2
          2401:da80::2          4      63927 12113237   79918        0    0    0 07w6d13h        62878
          2405:3200:0:23::      4      17639       0       0        0    0    0    never      Connect"
       ],
       "format" : "text/plain"
     }
}
    

JSend impose un champ status qui, ici, indique le succès. Le champ data contient la réponse. output est la sortie littérale du routeur, non structurée (le type est text/plain). router est le nom du routeur utilisé (rappelez-vous qu'un serveur looking glass peut donner accès à plusieurs routeurs).

Ici, par contre, on a eu une erreur (une erreur sur le routeur, le serveur, lui, a bien fonctionné, d'où le code de retour 200, cf. section 4 sur les conséquences de ce choix) :

HTTP/2.0 200 OK
Content-Type: application/json
{
     "status" : "fail",
     "data" : {
       "performed_at" : "2019-01-29T17:14:51Z",
       "runtime" : 10.37,
       "output" : [
         "Sending 5, 100-byte ICMP Echos to 2001:db8:fa3::fb56:18e",
         ".....",
         "Success rate is 0 percent (0/5)"
       ],
       "format" : "text/plain",
       "router" : "route-server.lg.op.example"
     }
}      
    

Le fail indique que la commande exécutée sur le routeur a donné un résultat négatif, mais, autrement, tout allait bien. Si le serveur looking glass ne peut même pas faire exécuter la commande par le routeur, il faut utiliser error et mettre un code de retour HTTP approprié :

HTTP/1.1 400 Bad Request
{
     "status" : "error",
     "message" : "Unrecognized host or address."
}      
    

La section 3 du RFC donne la liste des commandes possibles (un looking glass peut toujours en ajouter d'autres). La syntaxe suivie pour les présenter est celle des gabarits d'URL du RFC 6570. La première est évidemment ce brave ping, avec le gabarit https://lg.op.example/.well-known/looking-glass/v1/ping/{host} :

GET /.well-known/looking-glass/v1/ping/2001:db8::35?protocol=2
Host: lg.op.example

HTTP/1.1 200 OK
{
     "status" : "success",
     "data" : {
       "min" : 40,
       "avg" : 41,
       "max" : 44,
       "rate" : 100,
       "output" : [
         "Sending 5, 100-byte ICMP Echos to 2001:db8::35",
         "!!!!!",
         "Success rate is 100 percent (5/5)"
       ],
       "format" : "text/plain",
       "performed_at" : "2019-01-29T17:28:02Z",
       "runtime" : 0.77,
       "router" : "c2951.lab.lg.op.example"
     }
 }
    

Notez que le RFC ne décrit pas les champs possibles (comme min ou avg), ni les unités utilisées (probablement la milliseconde).

Autre commande traditionnelle, traceroute :

GET /.well-known/looking-glass/v1/traceroute/192.0.2.8
Host: lg.op.example

HTTP/1.1 200 OK
{
     "status": "success",
     "data": {
       "output": [
         "Tracing the route to 192.0.2.8",
         "",
         "  1 198.51.100.77 28 msec 28 msec 20 msec",
         "  2 203.0.113.130 52 msec 40 msec 40 msec",
         "  3 192.0.2.8 72 msec 76 msec 68 msec"
       ],
       "format": "text/plain",
       "performed_at": "2018-06-10T12:09:31Z",
       "runtime": 4.21,
       "router": "c7206.lab.lg.op.example"
     }
}     
    

Notez une des conséquences du format non structuré de output : ce sera au client de l'analyser. Le RFC permet d'utiliser des formats structurés (par exemple, pour traceroute, on peut penser à celui du RFC 5388) mais ce n'est pas obligatoire car on ne peut pas forcément exiger du serveur qu'il sache traiter les formats de sortie de tous les routeurs qu'il permet d'utiliser. L'analyse automatique des résultats reste donc difficile.

D'autres commandes permettent d'explorer la table de routage. Ainsi, show route affiche le route vers un préfixe donné (ici, le routeur est un Cisco et affiche donc les données au format Cisco) :

GET /.well-known/looking-glass/v1/show/route/2001:db8::/48?protocol=2,1
Host: lg.op.example

HTTP/1.1 200 OK
{
     "status": "success",
     "data": {
       "output": [
         "S   2001:DB8::/48 [1/0]",
         "     via FE80::C007:CFF:FED9:17, FastEthernet0/0"
       ],
       "format": "text/plain",
       "performed_at": "2018-06-11T17:13:39Z",
       "runtime": 1.39,
       "router": "c2951.lab.lg.op.example"
     }
   }
    

Une autre commande, show bgp, affiche les informations BGP :

GET /.well-known/looking-glass/v1/show/bgp/192.0.2.0/24
Host: lg.op.example

HTTP/1.1 200 OK
{
     "status": "success",
     "data": {
       "output": [
         "BGP routing table entry for 192.0.2.0/24, version 2",
         "Paths: (2 available, best #2, table default)",
         "  Advertised to update-groups:",
         "     1",
         "  Refresh Epoch 1",
         "  Local",
         "    192.0.2.226 from 192.0.2.226 (192.0.2.226)",
         "      Origin IGP, metric 0, localpref 100, valid, internal",
         "[...]"
       ],
       "format": "text/plain",
       "performed_at": "2018-06-11T21:47:17Z",
       "runtime": 2.03,
       "router": "c2951.lab.lg.op.example"
     }
}
    

Les deux précédentes commandes avaient un argument, le préfixe IP sur lequel on cherche des informations (avec la syntaxe des gabarits, cela s'écrit https://lg.op.example/.well-known/looking-glass/v1/show/bgp/{addr}). Mais certaines commandes n'ont pas d'argument. Par exemple, show bgp summary affiche la liste des pairs BGP  :

      
GET /.well-known/looking-glass/v1/show/bgp/summary?protocol=2&routerindex=3
Host: lg.op.example

HTTP/1.1 200 OK
{
     "status": "success",
     "data": {
       "output": [
         "BGP router identifier 192.0.2.18, local AS number 64501",
         "BGP table version is 85298, main routing table version 85298",
         "50440 network entries using 867568 bytes of memory",
         "[...]",
         "Neighbor        V       AS MsgRcvd MsgSent   TblVer  Up/Down",
         "2001:DB8:91::24 4    64500  481098  919095   85298   41w5d"
       ],
       "format": "text/plain",
       "performed_at": "2018-06-11T21:59:21Z",
       "runtime": 1.91,
       "router": "c2951.lab.lg.op.example"
     }
}

    

D'autres commandes (« organisationnelles ») sont destinées à aider le client à formuler sa question. C'est le cas de show router list, qui affiche la liste des routeurs auquel ce serveur looking glass donne accés :

GET /.well-known/looking-glass/v1/routers
...
{
     "status" : "success",
     "data" : {
       "routers" : [
         "route-server.lg.op.example",
         "customer-edge.lg.op.example",
         "provider-edge.lg.op.example"
       ],
       "performed_at" : "2018-10-19T12:07:23Z",
       "runtime" : 0.73
     }
   }
    

Autre exemple de commande organisationnelle, cmd, qui permet d'obtenir la liste des commandes acceptées par ce serveur (curieusement, ici, la syntaxe des gabarits du RFC 6570 n'est plus utilisée intégralement) :

GET /.well-known/looking-glass/v1/cmd
...
{
     "status" : "success",
     "data" : {
       "commands" : [
         {
           "href" : "https://lg.op.example/.well-known/looking-glass/v1/show/route",
           "arguments" : "{addr}",
           "description" : "Print records from IP routing table",
           "command" : "show route"
         },
         {
           "href" : "https://lg.op.example/.well-known/looking-glass/v1/traceroute",
           "arguments" : "{addr}",
           "description" : "Trace route to destination host",
           "command" : "traceroute"
         }
       ]
     }
   }
    

La liste des commandes données dans ce RFC n'est pas exhaustive, un looking glass peut toujours en ajouter (par exemple pour donner de l'information sur les routes OSPF en plus des BGP).

La section 6 du RFC décrit les problèmes de sécurité envisageables. Par exemple, un client malveillant ou maladroit peut abuser de ce service et il est donc prudent de prévoir une limitation de trafic. D'autre part, les informations distribuées par un looking glass peuvent être trop détaillées, révéler trop de détail sur le réseau et ce qu'en connaissent les routeurs, et le RFC note qu'un serveur peut donc limiter les informations données.

Et question mises en œuvre de ce RFC ? Il existe Beagle mais qui, à l'heure où ce RFC est publié, ne semble pas à jour et concerne encore une version antérieure de l'API. Peut-être RANCID va t-il fournir une API compatible pour son looking glass. Periscope, lui, est un projet différent, avec une autre API.


Téléchargez le RFC 8522

Version PDF de cette page (mais vous pouvez aussi imprimer depuis votre navigateur, il y a une feuille de style prévue pour cela)

Source XML de cette page (cette page est distribuée sous les termes de la licence GFDL)