Introduction
Ce document montre l'utilisation de la programmation Python pour provisionner un MPLS L3VPN sur un routeur de périphérie du fournisseur de services (PE) à l'aide de l'API REST. Cet exemple utilise les routeurs Cisco CSR1000v (IOS-XE) comme routeurs PE.
Contribution de : Anuradha Perera
Modifié par : Kumar Sridhar
Conditions préalables
- Accès de gestion de l'API REST aux routeurs CSR1000v (reportez-vous aux références à la fin de ce document).
- Python (Version 2.x ou 3.x) et « Requests » Python library installés sur l'ordinateur utilisé pour configurer les routeurs.
- Quelques connaissances de base en programmation Python.
Configuration
Diagramme du réseau

Dans cet exemple, nous nous concentrons sur la configuration des paramètres de service MPLS L3VPN requis sur le routeur PE-1, qui sont mis en surbrillance en couleur rose.
Procédure de configuration
La tâche Configuration est divisée en plusieurs sous-tâches et chaque sous-tâche est implémentée sous une fonction définie par l'utilisateur. De cette façon, les fonctions peuvent être réutilisées si nécessaire.
Toutes les fonctions utilisent la bibliothèque « Requests » pour accéder aux API REST sur le routeur et le format des données est JSON. Dans les requêtes HTTP “ le paramètre ” de vérification a la valeur “ False ” ignorer la validation du certificat SSL.
1. Récupérer l'ID de jeton
Avant de procéder à une configuration sur un routeur, vous devez obtenir un ID de jeton valide auprès du routeur. Cette fonction initie une requête HTTP pour authentifier et obtenir un ID de jeton afin qu'il puisse appeler d'autres API à l'aide de ce jeton. La réponse de cette demande inclut un ID de jeton.
#-----------------------------------
def getToken (ip, port, nom d'utilisateur, mot de passe) :
demandes d'importation
importer la base64
url = "https://" + ip + « : »+ port + "/api/v1/auth/token-services »
en-têtes = {
'content-type' : « application/json »,
'autorisation' : « Basic " + base64.b64encode((username + « : » + password).encode('UTF-8')).decode('ascii'),
'contrôle-cache' : « no-cache »
}
réponse = request.request(« POST », url, headers=headers, verify=False )
if response.status_code == 200 :
return response.json()['id-jeton']
sinon :
retour « échec »
#-----------------------------------
2. Créer VRF
Cette fonction crée le VRF sur le routeur PE avec le séparateur de route (RD) requis et les cibles de route d'importation/exportation (RT) requises.
#-----------------------------------
def createVRF (ip, port, tokenID, vrfName, RD, importRT, exportRT) :
demandes d'importation
url = "https://" + ip + « : »+ port + "/api/v1/vrf »
en-têtes = {
'content-type': « application/json »,
'Jeton d'authentification X' : tokenID,
'contrôle-cache' : « no-cache »
}
données = {
'nom': vrfName,
'rd' : RD,
'route-target' : [
{
'action' : « importation »,
'communauté' : importRT
},
{
'action' : « exportation »,
'communauté' : exportRT
}
]
}
réponse = request.request(« POST », url, headers=headers, json=data, verify=False )
if response.status_code == 201 :
retour « réussi »
sinon :
retour « échec »
#-----------------------------------
3. Déplacer une interface dans un VRF
Cette fonction déplace une interface donnée dans un VRF.
#-----------------------------------
def addInterfacetoVRF (ip, port, tokenID, vrfName, interfaceName, RD, importRT, exportRT) :
demandes d'importation
url = "https://" + ip + « : »+ port + "/api/v1/vrf/" + vrfName »
en-têtes = {
'content-type': « application/json »,
'Jeton d'authentification X' : tokenID,
'contrôle-cache' : « no-cache »
}
données = {
'rd' : RD,
'transfert': [ nom_interface ],
'route-target' : [
{
'action' : « importation »,
'communauté' : importRT
},
{
'action' : « exportation »,
'communauté' : exportRT
}
]
}
réponse = request.request(« PUT », url, headers=headers, json=data, verify=False )
if response.status_code == 204 :
retour « réussi »
sinon :
retour « échec »
#-----------------------------------
4. Attribuer une adresse IP à l’interface
Cette fonction attribue une adresse IP à l'interface.
#-----------------------------------
def assignationInterfaceIP (ip, port, tokenID, interfaceName, interfaceIP, interfaceSubnet) :
demandes d'importation
url = "https://" + ip + « : »+ port + "/api/v1/interfaces/" + interfaceName »
en-têtes = {
'content-type': « application/json »,
'Jeton d'authentification X' : tokenID,
'contrôle-cache' : « no-cache »
}
données = {
'type': « Ethernet »,
'if-name' : NomInterface,
'adresse IP' : interfaceIP,
'masque de sous-réseau' : interfaceSous-réseau
}
réponse = request.request(« PUT », url, headers=headers, json=data, verify=False )
if response.status_code == 204 :
retour « réussi »
sinon :
retour « échec »
#-----------------------------------
5. Créer bgp compatible VRF
Ceci active la famille d'adresses VRF ipv4.
#-----------------------------------
def createVrfBGP (ip, port, tokenID, vrfName, ASN) :
demandes d'importation
url = "https://" + ip + « : »+ port + "/api/v1/vrf/" + vrfName + "/routing-svc/bgp »
en-têtes = {
'content-type': « application/json »,
'Jeton d'authentification X' : tokenID,
'contrôle-cache' : « no-cache »
}
données = {
'id-protocole-routage': ASN
}
réponse = request.request(« POST », url, headers=headers, json=data, verify=False )
if response.status_code == 201 :
retour « réussi »
sinon :
retour « échec »
#-----------------------------------
6. Définir le voisin BGP sous la famille d'adresses VRF
Cette fonction définit le voisin BGP sous la famille d'adresses VRF IPV4.
#-----------------------------------
def defineVrfBGPNneighbor (ip, port, tokenID, vrfName, ASN, neighbbourIP, remoteAS) :
demandes d'importation
url = "https://" + ip + « : »+ port + "/api/v1/vrf/" + vrfName + "/routing-svc/bgp/" + ASN +"/neighbors »
en-têtes = {
'content-type': « application/json »,
'Jeton d'authentification X' : tokenID,
'contrôle-cache' : « no-cache »
}
données = {
'id-protocole-routage': ASN,
'adresse' : adresse IP voisine,
'remote-as' : remoteAS
}
réponse = request.request(« POST », url, headers=headers, json=data, verify=False )
if response.status_code == 201 :
retour « réussi »
sinon :
retour « échec »
#-----------------------------------
Description et valeurs des paramètres d'entrée
ip = "10.0.0.1" # adresse ip du routeur
port = "55443" # Port API REST sur le routeur
nom d'utilisateur = « cisco » # nom d'utilisateur à connecter.Ce paramètre doit être configuré avec le niveau de privilège 15.
mot de passe = « cisco » # mot de passe associé au nom d'utilisateur
tokenID = <valeur renvoyée> # ID de jeton obtenu à partir du routeur à l'aide de la fonction getToken
vrfName = « VRF-A » # nom du VRF
RD = « 3:3 » # Distingueur de route pour VRF
importRT = « 34:34 » # Importer la cible de route
exportRT = « 34:34 » # export Route Target
interfaceName = « GigabitEthernet3 » # nom de l'interface de périphérie client (CE) orientée
interfaceIP = « 192.168.13.3 » # adresse IP de l'interface CE orientée
interfaceSubnet = « 255.255.255.0 » # sous-réseau de l'interface CE orientée
ASN = « 34 » # BGP AS numéro de routeur PE
neighbbourIP = « 192.168.13.1 » # IP d'appairage BGP du routeur CE
remoteAS = « 11 » # Numéro AS du routeur CE
Dans toutes les fonctions ci-dessus, des API dédiées ont été demandées pour chaque étape de configuration. L'exemple ci-dessous montre comment passer l'interface de ligne de commande IOS-XE, en général, dans le corps de l'appel de l'API REST. Ceci peut être utilisé comme solution de contournement pour automatiser si une API particulière n'est pas disponible. Dans les fonctions ci-dessus, 'content-type' est défini sur 'application/json', mais dans l'exemple ci-dessous, 'content-type' est défini sur 'text/plain' car il analyse l'entrée CLI standard.
Cet exemple définit la description de l'interface GigabitEthernet3. La configuration peut être personnalisée en modifiant le paramètre cliInput.
#-----------------------------------
def passCLIInput (ip, port, tokenID) :
demandes d'importation
url = "https://" + ip + « : »+ port + "/api/v1/global/running-config »
en-têtes = {
'content-type': « texte/brut »,
'Jeton d'authentification X' : tokenID,
'contrôle-cache' : « no-cache »
}
line1 = « Interface GigabitEthernet 3 »
ligne 2 = « description Interface client »
cliInput = ligne1 + "\r\n" + ligne2
réponse = request.request(« PUT », url, headers=headers, data=cliInput, verify=False )
print(response.text)
if response.status_code == 204 :
retour « réussi »
sinon :
retour « échec »
#-----------------------------------
Références
- Guide de configuration du logiciel du routeur de services cloud de la gamme Cisco CSR 1000v
https://www.cisco.com/c/en/us/td/docs/routers/csr1000/software/configuration/b_CSR1000v_Configuration_Guide /b_CSR1000v_Configuration_Guide_chapter_01101.html
- Guide de référence de la gestion de l'API REST de Cisco IOS XE
https://www.cisco.com/c/en/us/td/docs/routers/csr1000/software/restapi/restapi.html
Acronymes utilisés :
MPLS - Commutation multiprotocole par étiquette
L3 - Couche 3
VPN - Réseau privé virtuel
VRF - Transfert de route virtuelle
BGP - Border Gateway Protocol
REST - Transfert d'État de représentation
API - Interface de programme d'application
JSON - Notation d'objet Java Script
HTTP - Hyper Text Transfer Protocol