Site icon Karneliuk

SP. Part 4. Using IETF L3VPN SVC YANG to provision IP VPN for Arista, Cisco, Nokia with Ansible

Hello my friend,

Looking on the title of the article, you might ask “Hasn’t he already provided configuration of IP VPN for these vendors? (link)” That’s true, this is already described. But this time we are focusing not on a particular configuration of the network functions, but rather on proper modelling of IP VPN service relying on IETF L3VPN SVC YANG model and Ansible for automation.


1
2
3
4
5
No part of this blogpost could be reproduced, stored in a
retrieval system, or transmitted in any form or by any
means, electronic, mechanical or photocopying, recording,
or otherwise, for commercial purposes without the
prior permission of the author.

Brief description

Modelling of any kind of end to end services in multivendor environment is quite challenging though interesting task. It’s important not only to create model, which can be implemented across different network functions, but the model, which also describes CPEs and other customer related data. The additional complexity is also dictated by the fact that it is necessary to find the proper balance between the detailed parameters needed for configuration of network elements, and high level view of the service needed for end to end service.

In 2018 the IETF has released RFC 8299 called “YANG Data Model for L3VPN Service Delivery”, which goal is to define the YANG model, which is good enough to be used for creation of IP VPN services in multi-vendor environment. Below you will find detailed example of usage if this data model for provisioning of IP VPN service for IPv4 and IPv6 address families.

What are we going to test?

We are going to discuss in details the following topics:

  1. Provisioning of IP VPN suing IETF L3VPN SVC YANG model in multivendor environment
  2. Necessary adaptation to make this model usable
  3. Creation of proper per-vendor drivers (Arista EOS, Nokia SR OS, Cisco IOS XR)
  4. Automated provisioning of CE running Cumulus Linux

Software version

The following software components are used in this lab:

More details about Service Provider Fabric you may find in the previous articles.

Topology

To control all the virtual network functions (VNF) we run in our test lab, we are using the management host running CentOS Linux with the following topology:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
+---------------------------------------------------------------------------+
|                                                                           |
|    +-------------+          +-----------------+                           |
|    | Internet GW |          | management host |                           |
|    +------+------+          +--------+--------+                           |
|           | eth1                     | ens33                              |
|           | .2                       | .131       OOB: 192.168.141.0/24   |
|           |                          |                                    |
|       +---+-----------+--------------+--------------+-------------+       |
|       |               |              |              |             |       |
|       | BOF (Eth)     | MgmtEth0     | Management1  | Management1 | eth0  |
|       | .101          | .51          | .71          | .72         | .84   |
|   +---+---+       +---+---+      +---+---+      +---+---+     +---+---+   |
|   |  SR1  |       |  XR1  |      |  EOS1 |      |  EOS2 |     |  VX4  |   |
|   +-------+       +-------+      +-------+      +-------+     +-------+   |
|                                                                           |
+---------------------------------------------------------------------------+

You can use any hypervisor of your choice (KVM, VMWare Player/ESXI, etc). For KVM you can use corresponding cheat sheet for VM creation.

The logical topology looks like the one below provided in ASCII format:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
+-------------------------------------------------------------------------------------------------------------+
|                                                                                                             |
|     L0:                                                                                                     |
|     10.0.0.22/32                                                                                            |
|     fc00::10:0:0:22/128        10.1.22.0/24                                                                 |
|        (Metric: 10)            fc00::10:1:22:0/112                                                          |
|    +---------------+              (Metric: 10)                                                              |
|    | EOS1 (SID:22) |(Eth2)+----------------------+                                                          |
|    +---------------+ .22/:22                     |                                                          |
|          (Eth1)                                  |                                                          |
|            + .22/:22                             + .1/:1       10.1.44.0/24                                 |
|            |                                   (Eth1)          fc00::10:1:44:0/112                          |
|            |  10.22.33.0/24               +--------------+        (Metric: 10)        +----------------+    |
|            |  fc00::10:22:33:0/112        | EOS2 (SID:1) |(Eth3)+--------------+(Eth3)|  SR1 (SID: 44) |    |
|            |     (Metric: 100)            +--------------+ .1:/1              .44/:44 +----------------+    |
|            |                                   (Eth2)                                                       |
|            + .33/:33                             + .1/:1  L0:                         system:               |
|        (G0/0/0/0)                                |        10.0.0.1/32                 10.0.0.44/32          |
|    +---------------+                             |        fc00::10:0:0:1/128          fc00::10:0:0:44/128   |
|    |  XR1 (SID:33) |(G0/0/0/1)+------------------+           (Metric: 10)                (Metric: 10)       |
|    +---------------+ .33/:33      (Metric: 10)                                                              |
|                                10.1.33.0/24                                                                 |
|     L0:                        fc00::10:1:33:0/112                                                          |
|     10.0.0.33/32                                                                                            |
|     fc00::10:0:0:33/128                                                                                     |
|        (Metric: 10)              ISIS 0 (CORE) / level 2 / Segment Routing                                  |
|                                                                                                             |
|                                                ASN: 65000                                                   |
|                                                                                                             |                                              
|                               Full iBGP mesh for VPNV4 UNICAST, VPNV6 UNICAST                               |
|                                 and L2VPN EVPN between loopbacks of all PEs                                 |
|                                                                                                             |
+-------------------------------------------------------------------------------------------------------------+

As said this topology was in details explained and configured in the previous article. It’s called Service Provider Fabric. We are running ISIS enabled with Segment Routing in underlay, multiprotocol BGP for VPNv4/VPNv6 and EVPN address families for overlay signaling.

The initial configuration as well as the topologies and all the automations you can find on my GitHub page.

IETF L3VPN SVC YANG model for provisioning of IP VPN services

IETF did a great effort to create a YANG data model for IP VPN service. To understand it thoroughly, I’ve read that RFC and here you see description of this model from RFC itself:

This model is intended to be instantiated at the management system to deliver the overall service.  It is not a configuration model to be used directly on network elements.  This model provides an abstracted view of the Layer 3 IP VPN service configuration components.

RFC 8299

What does it mean? The following image is also coming from that RFC 8299:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
                   l3vpn-svc |
                     Model   |
                             |
                      +------------------+         +-----+
                      |   Orchestration  | < --- > | OSS |
                      +------------------+         +-----+
                         |            |
                 +----------------+   |
                 | Config manager |   |
                 +----------------+   |
                         |            |
                         | NETCONF/CLI ...
                         |            |
           +------------------------------------------------+
                                Network

                              +++++++
                              + AAA +
                              +++++++

      ++++++++   Bearer    ++++++++           ++++++++      ++++++++
      + CE A + ----------- + PE A +           + PE B + ---- + CE B +
      ++++++++  Connection ++++++++           ++++++++      ++++++++

                 Site A                               Site B

As you can see this model is supposed be to be applied to Orchestrator, which then translates this service YANG model into particular vendor-native or OpenConfig YANG models for network function configuration. Let’s take a look more precisely, what is included in the model by default:

  1. Client information (VPN ID, customer name, address, etc)
  2. Information if any addition service (QoS, encryption, Extranet VPN) is needed
  3. VPN topology (any-to-any, hub-and-spoke, etc)
  4. Client’s “sites” information (location addresses, CE type, CE management, PE-CE routing protocols, QoS config (if defined), access circuit type)
  5. Within client’s site information there is a dedicated session called “site network accesses”, which contains parameters of the customer circuit type (like Ethernet, supported address families, IP addresses), any deviations about QoS/PE-CE routing from parents “site” context and mapping of the circuit to particular VPN.

What is not included in the model (and it’s explicitly said in RFC):

  1. Information about Route Distinguisher
  2. Information about Route Targets
  3. Dedicated mapping of CE to PE

In a nutshell, alone the IETF L3VPN SVC YANG model won’t work. There must be several additional functions in Orchestrator (like PE to CE mapping, mechanism to track and allocate RD/RT and so on) to make use of this model. But all this issues are solved, when you have a hierarchical model in terms of service portal, orchestrator and SDN controller, where each components consumes its piece of high level data and provides more details down to next level.

Use case of provisioning of IP VPN within Service Provider Fabric

The following topology is used for customer connection:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
+----------+                                                     /\/\/\/\/\
|          |                fc00::192:168:22:0/112              /         /
|     +----+---------+         192.168.22.0/24            +---------+     \
|     | VRF: CUST22  |(VLAN22/swp1)--------------(Eth3.22)|  EOS1   |     /
|     +----+---------+ .22                             .1 +---------+  M  \
|          |           :22                             :1      \       P  /
|          |                fc00::192:168:33:0/112             /       L  \
|  V  +----+---------+         192.168.33.0/24            +---------+  S  /
|  X  | VRF: CUST33  |(VLAN33/swp2)----------(G0/0/0/2.33)|  XR1    |     \
|  4  +----+---------+ .33                             .1 +---------+  C  /
|          |           :33                             :1      \       O  \
|          |                fc00::192:168:44:0/112             /       R  /
|     +----+---------+         192.168.44.0/24            +---------+  E  \
|     | VRF: CUST44  |(VLAN44/swp3)-------(sap1/1/c2/1:44)|  SR1    |     /
|     +----+---------+ .44                             .1 +---------+     \
|          |           :44                             :1      \          /
+----------+                                                    \/\/\/\/\/

               Networks advertised via BGP from customers
                 (Local routed VLANs within VRF CUSTXXX)

    CUST22 / VLAN1001 / 192.168.122.1/25, fc00::192:168:122:1/113
    CUST22 / VLAN1002 / 192.168.122.129/25, fc00::192:168:122:8001/113

    CUST33 / VLAN1003 / 192.168.133.1/25, fc00::192:168:133:1/113
    CUST33 / VLAN1004 / 192.168.133.129/25, fc00::192:168:133:8001/113

    CUST44 / VLAN1005 / 192.168.144.1/25, fc00::192:168:144:1/113
    CUST44 / VLAN1006 / 192.168.144.129/25, fc00::192:168:144:8001/113

Basically, each VRF emulates dedicated customer site, which is described then in IETF L3VPN SVC in section “sites”. The PE-CE connections are running eBGP:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
   +-----------------------------------------------------------------------------------------------------------+
   |      fc00::192:168:22:0/112                                                   fc00::192:168:44:0/112      |
   |         192.168. 22.0/24    +-----------------+          +-----------------+     192.168.44.0/24          |
+--+------+                      |VRF: IP-VPN      |          |VPRN: IP-VPN     |                        +-----+---+
| CUST122 |(Vlan22)------(Vlan22)|RD: 65000:10000  |          |RD: 65000:10000  |(1/1/c2/1:44)---(Vlan44)| CUST144 |
+--+------+ .22<-eBGP(IPv4)-> .1 |RT: 65000:10000  |          |RT: 65000:10000  | .1 <--eBGP(IPv4)-> .44 +-----+---+
   |  ASN   :22<-eBGP(IPv6)-> :1 +------+----------+          +----------+------+ :1 <--eBGP(IPv6)-> :44  ASN  |
   | 65234                              |   EOS1   +----------+   SR1    |                               65234 |
   |                                    +----+-----+          +----+-----+                                     |
   |                                         |     ASN 65000       |                                           |
   |                                         |    MPLS (SR-ISIS)   |                                           |
   |                                         |     +----------+    |                                           |
   |                                         +-----+   XR1    +----+                                           |
   |                                           +-----------------+                                             |
   |                                           |VRF: IP-VPN      |                                             |
   |                                           |RD: 65000:10000  |                                             |
   |                                           |RT: 65000:10000  |                                             |
   |                                           +-----------------+                                             |
   |                                  :1      .1  (G0/0/0/2.33)                                                |
   |                                   ^       ^        |                                                      |
   |                                   |eBGP   |eBGP    | fc00:192:168:33:0/112                                |
   |                                   |(IPv6) |(IPv4)  | 192.168.33.0/24                                      |
   |                                   |       |        |                                                      |
   |                                   v       v        |                                                      |
   |                                  :33     .33    (Vlan33)                                                  |
   |                                               +---------+ ASN 65234                                       |
   +-----------------------------------------------+ CUST133 +-------------------------------------------------+
                                                   +---------+

You see some RD/RT values on the service topology, but in reality they will be allocated dynamically from range 65000:10000 – 65000:99999.

Actually, the Ansible works as orchestrator in this case, as it receives the high level request in IETF L3VPN SVC YANG model and translates its depending on capabilities of the network elements into OpenConfig/YANG, vendor-native/YANG or CLI commands.

#1. Structure of IP VPN automation with Ansible within Service Provider Fabric – input data

Refer to Service Provider Fabric description to get details about how it works.

In the table below you can find incremental update to Service Provider Fabric focused on IP VPN provisioning using IETF L3VPN SVC model:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
+--service_provider_fabric
   +--ansible
      +--customer_equipment.yml
      +--group_vars
      |  +--all
      |     +--main.yml
      +--roles
      |  +--cpe_ip_vpn --> further_details_available
      |  +--spf_ip_vpn --> further_details_available
      +--service_provider_fabric.yml
      +--vars
         +--cpe_to_location.json
         +--l3vpn_index.yml
         +--pe_to_location.json
         +--provisioned_services.yml
         +--service_ip_vpn_IMBA_CUST.json
         +--VX4_ip_vpn.yml

The content of roles related to IP VPN is described later in greater details.

The key component for this article is the IETF L3VPN SVC model. The example of customer IP VPN in this model is stored in “service_ip_vpn_IMBA_CUST.json”:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
$ cat vars/service_ip_vpn_IMBA_CUST.json
{
    "l3vpn_svc": {
        "vpn_profiles": {
            "valid_provider_identifiers": {
                "encryption_profile_identifier": [
                    {
                        "id": "NO_ENCR"
                    }
                ],
                "cloud_identifier": [
                    {
                        "id": "NO_CLOUD"
                    }
                ],
                "bfd_profile_identifier": [
                    {
                        "id": "NO_BFD"
                    }
                ],
                "qos_profile_identifier": [
                    {
                        "id": "DEFAULT_QOS"
                    }
                ]
            }
        },
        "vpn_services": {
            "vpn_service": [
                {
                    "vpn_id": "223344",
                    "customer_name": "Imba_Cust",
                    "vpn_service_topology": "any-to-any",
                    "multicast": {
                        "enabled": false
                    }
                }
            ]
        },
        "sites": {
            "site": [
                {
                    "site_id": "CUST1",
                    "requested_site_start": "string",
                    "requested_site_stop": "string",
                    "locations": {
                        "location": [
                            {
                                "location_id": "DE-FRA-EQUINIX-FR2",
                                "country_code": "DE",
                                "city": "Frankfurt",
                                "state": "Hessen",
                                "address": "Somestreet 22",
                                "postal_code": "60500"
                            }
                        ]
                    },
                    "devices": {
                        "device": [
                            {
                                "device_id": "VX4",
                                "management": {
                                    "address_family": "ipv4",
                                    "address": "192.168.141.84"
                                },
                                "location": "CUST22"
                            }
                        ]
                    },
                    "management": {
                        "type": "customer_managed",
                    },
                    "site_vpn_flavor": "site_vpn_flavor_single",
                    "maximum_routes": {
                        "address_family": [
                            {
                                "maximum_routes": "100",
                                "af": "ipv4"
                            },
                            {
                                "maximum_routes": "100",  
                                "af": "ipv6"
                            }
                        ]
                    },
                    "traffic_protection": {
                        "enabled": false
                    },
                    "routing_protocols": {
                        "routing_protocol": [
                            {
                                "type": "bgp",
                                "bgp": {
                                    "autonomous_system": "65234",
                                    "address_family": ["ipv4", "ipv6"]
                                }
                            }
                        ]
                    },
                    "site_network_accesses": {
                        "site_network_access": [
                            {
                                "site_network_access_id": "223344_22_1",
                                "site_network_access_type": "point-to-point",
                                "location_reference": "DE-FRA-EQUINIX-FR2",
                                "access_diversity": {
                                    "constraints": {
                                    "groups": {
                                        "group": [
                                            {
                                                "group_id": "234"
                                            }
                                        ]
                                    },
                                        "constraint": [
                                            {
                                                "constraint_type": "pe-diverse",
                                                "target": {
                                                    "group": [
                                                        {
                                                            "group_id": "234"
                                                        }
                                                    ]
                                                }
                                            }
                                        ]
                                    }
                                },
                                "bearer": {
                                    "always_on": true,
                                    "requested_type": {
                                        "strict": true,
                                        "requested_type": "Ethernet-dot1q",
                                        "dot1q_vlan": 22
                                    }
                                },
                                "ip_connection": {
                                    "oam": {
                                        "bfd": {
                                            "enabled": false
                                        }
                                    },
                                    "ipv4": {
                                        "address_allocation_type": "static-address",
                                        "addresses": {
                                            "provider_address": "192.168.22.1",
                                            "prefix_length": "24",
                                            "customer_address": "192.168.22.22"
                                        }
                                    },
                                    "ipv6": {
                                        "address_allocation_type": "static-address",
                                        "addresses": {
                                            "provider_address": "fc00::192:168:22:1",
                                            "prefix_length": "112",
                                            "customer_address": "fc00::192:168:22:22"
                                        }
                                    }
                                },
                                "service": {
                                    "svc_input_bandwidth": 100000000,
                                    "svc_output_bandwidth": 100000000,
                                    "svc_mtu": 1514
                                },  
                                "vpn_attachment": {
                                    "vpn_id": "223344",
                                    "site_role": "any-to-any-role"
                                }
                            }
                        ]
                    }
                },
                {
                    "site_id": "CUST2",
! The output is truncated for brevity
                },
                {
                    "site_id": "CUST3",
! The output is truncated for brevity
                }
            ]
        }
    }
}

The content of the site 2 and 3 are omitted, as site 1 already explains the structure.

The first part “vpn profiles” should contain any profiles out of standard service provider portfolioAs we don’t speak about any kind of extranet VPN or cloud access (BTW, in the RFC standard access to internet is also treated as cloud access), QoS or encryption, all these fields are empty.

The second part is “vpn_services”, where the high level information about particular customer VPN is stored. Among others, there is also information about VPN topology, “any-to-any” in our case. Point out, that “vpn_services” is a list, meaning there might be simultaneously about different VPNs, which are not necessary connected to each other.

The third part is “sites”, where information about customer’s sites is located. The container “location” provides details about customer site. This will be necessary later on to map certain connection to PE of the Service Provider Fabric. The container called “devices” lists the CE. Theoretically, it can be mapped to a particular location from “location” container, though it isn’t stated in RFC. In this case I’ve added the name of customers VRF. The container “management” is very important, because depending on it’s “type” value we speak either about PE-CE connectivity (our case) or LAN after CE to further customer infrastructure, if “type” is “provider-management”. Further we have “routing_protocols” container, where the protocol for PE-CE (or CE-LAN) is defined alongside with some parameters. In our case we use eBGP for IPv4 and IPv6 address families.

The last major block is “site_network_accesses” within “sites”, as it models particular attached circuit. There is again huge amount of information stored. From this example prospective, we use “bearer” to define L1 and L2 parameters of the customer connection, “ip_connection” for IPv4/IPv6 addressing, “service” to define MTU and “vpn_attachment” to associate link with customers VRF.

Frankly speaking, I’m just using 10-20% of all possibilities provided in the IETF L3VPN SVC model.

As you might have seen, there is no mapping of the links to any PE. To do it, we have a dedicated file with vars:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ cat vars/pe_to_location.json
{
   "pe_to_location": [
       {
           "location_id": "DE-FRA-EQUINIX-FR2",
           "pe_id": "EOS1",
           "uni_port": "Ethernet3"
       },
       {
           "location_id": "UK-LON-INTERXION-LON1",
           "pe_id": "XR1",
           "uni_port": "GigabitEthernet0/0/0/2"
       },
       {
           "location_id": "BY-MIN-BELTELECOM-IX1",
           "pe_id": "SR1",
           "uni_port": "1/1/c2/1"
       }
   ]
}

This file is kind of internal resource mapping of Service Provider Fabric, where each “location_id” is associated with the certain PE and the customer port on this PE. This mapping is used later on by Ansible playbook to define, which PE must be configured and how.

The similar mapping exists for CEs as well:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
$ cat vars/cpe_to_location.json
{
   "cpe_to_location": [
       {
           "location_id": "DE-FRA-EQUINIX-FR2",
           "cpe_id": "VX4",
           "uni_port": "swp1",
           "advertised_subnets": [
               {
                  "afi": "ipv4",
                  "address": "192.168.22.0",
                  "prefix_length": 24
               },
               {
                  "afi": "ipv4",
                  "address": "192.168.122.0",
                  "prefix_length": 25
               },
               {
                  "afi": "ipv4",
                  "address": "192.168.122.128",
                  "prefix_length": 25
               },
               {
                  "afi": "ipv6",
                  "address": "fc00::192:168:22:0",
                  "prefix_length": 112
               },
               {
                  "afi": "ipv6",
                  "address": "fc00::192:168:122:0",
                  "prefix_length": 113
               },
               {
                  "afi": "ipv6",
                  "address": "fc00::192:168:122:8000",
                  "prefix_length": 113
               }
           ]
       },
       {
           "location_id": "UK-LON-INTERXION-LON1",
! The output is truncated for brevity
       },
       {
           "location_id": "BY-MIN-BELTELECOM-IX1",
! The output is truncated for brevity
       }
   ]
}

Here we have mapping of customer’s CE to certain locations as well as ports and announces subnets per each site.

To configure the CE subnets (emulation in this case), there is dedicated file with variables:


1
2
3
4
5
6
7
8
9
10
11
12
13
$ cat vars/VX4_ip_vpn.yml
---
starting_vlan: 1000
customer_emulation:
    - vrf: CUST22
      afi: ipv4
      address: 192.168.122.1
      prefix: 25
    - vrf: CUST22
      afi: ipv4
      address: 192.168.122.129
      prefix: 25
! The output is truncated for brevity

It looks very similar to previous one, but the idea was to split the particular host configuration in terms of interfaces and so on, and really PE-CE configuration, which can be used later on in the production scenarios.

Coming back to the Service Provider Fabric, to create proper RT/RD, we are using two additional sources of the information:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ cat group_vars/all/main.yml
---
# Default for Ansible operation
temp_folder: /tmp/SP_SR_TEMP
# Defaults for IETF L3VPN SVC provisioning
l3vpn_defaults:
    route_distinguisher:
        format: 2_byte_asn
        start: 10000
        end: 99999
    route_target:
        start: 10000
        end: 99999
...


$ cat vars/l3vpn_index.yml
---
l3vpn_index_next_free: 3
...

The first one defines what are the range of RD/RT should be used, whereas the second stores information about which is the next available index, how RD/RT should be incremented in order not to overlap with configured services.

In case the service is successfully provisioned, the information about is documented:


1
2
3
4
5
6
7
8
9
$ cat vars/provisioned_services.yml
l3vpns:
    l3vpn:
# BEGIN ANSIBLE MANAGED BLOCK
        - vpn_id: 223344
          customer_name: Imba_Cust
          route_distinguisher: 65000:10002
          route_target: 65000:10002
# END ANSIBLE MANAGED BLOCK

#2. Structure of IP VPN automation with Ansible within Service Provider Fabric – provisioning

The provisioning of the configuration on Service Provider Fabric is done using the same master playbook, we’ve already used:


1
2
3
4
5
6
7
8
9
10
$ cat service_provider_fabric.yml
---
- hosts: fabric
  gather_facts: yes
  connection: netconf
  roles:
      - spf_underlay_mpls
      - spf_underlay_bgp
      - spf_ip_vpn
...

As you can easily guess, the role “spf_ip_vpn” is used:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
+--spf_ip_vpn
   +--tasks
   |  +--cli_configuration_loop.yml
   |  +--cli_main.yml
   |  +--main.yml
   |  +--native_main.yml
   |  +--openconfig_configuration_loop.yml
   |  +--openconfig_main.yml
   |  +--openconfig_netconf_xml_modification.yml
   |  +--sros_configuration_loop.yml
   +--templates
      +--eos-interfaces.j2
      +--eos-network-instance.j2
      +--iosxr-temp-yang.j2
      +--openconfig-interfaces.j2
      +--openconfig-network-instance.j2
      +--provision_new_ip_vpn.j2
      +--sros-interfaces.j2
      +--sros-network-instance.j2

When we call this role during execution of the main Ansible playbook, “main.yml” is launched:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
$ cat roles/spf_ip_vpn/tasks/main.yml
---
- name: IMPORTING HOST VARIABLES
  include_vars:
      file: "{{ inventory_hostname }}_underlay.yml"
  tags:
      - ip_vpn

- name: IMPORTING SERVICE REQUEST
  include_vars:
      file: service_ip_vpn_IMBA_CUST.json
  tags:
      - ip_vpn

- name: IMPORTING DEVICE MAPPING
  include_vars:
      file: pe_to_location.json
  tags:
      - ip_vpn

- name: CREATING TEMPORARY OUTPUT FOLDER
  file:
      dest: "{{ temp_folder }}"
      state: directory
  tags:
      - ip_vpn

- name: OPENCONFIG YANG
  include_tasks: openconfig_main.yml
  when: ansible_network_os == 'iosxr'
  tags:
      - ip_vpn

- name: NATIVE YANG
  include_tasks: native_main.yml
  when: ansible_network_os == 'sros'
  tags:
      - ip_vpn

- name: CLI AUTOMATION
  include_tasks: cli_main.yml
  when: ansible_network_os == 'nexus'
  tags:
      - ip_vpn

- name: UPDATING LIST OF PROVISIONED SERVICES
  blockinfile:
      path: vars/provisioned_services.yml
      block: "{{ lookup('template', 'provision_new_ip_vpn.j2') }}"
  tags:
      - ip_vpn

- name: UPDATING NEXT FREE RD/RT INDEX
  lineinfile:
      path: vars/l3vpn_index.yml
      regexp: 'l3vpn_index_next_free'
      line: 'l3vpn_index_next_free: {{ l3vpn_index_next_free + 1 }}'
  tags:
      - ip_vpn

- name: DELETING TEMPORARY FILES
  file:
      dest: "{{ temp_folder }}"
      state: absent
  tags:
      - ip_vpn
...

As you can see, all the described earlier files with variables are imported and then, depending on the vendor defined by “ansible_network_os” value proper subtasks are launched. After all the subtasks are executed, the variable with RD/RT index is incremented by one and the documentation of VPN service is done.

Inside sub tasks for each vendor (or more precisely the way how the network function by vendor is configured) we have more or less similar structure:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ cat roles/spf_ip_vpn/tasks/openconfig_main.yml
---
- name: OPENCONFIG YANG // IMPORTING NEXT FREE RD/RT INDEX
  include_vars:
      file: l3vpn_index.yml
  tags:
      - ip_vpn

- name: OPENCONFIG YANG // STARTING NOKIA CONFIGURATION LOOP
  include_tasks: "openconfig_configuration_loop.yml"
  loop:
      - openconfig-interfaces
      - openconfig-network-instance
  loop_control:
      loop_var: conf_loop_item
  tags:
      - ip_vpn

- name: OPENCONFIG YANG // FIXING RT FOR CISCO USING NATIVE YANG
  netconf_config:
      xml: "{{ lookup ('template', '{{ ansible_network_os }}-temp-yang.j2') }}"
  ignore_errors: yes
  when: ansible_network_os == 'iosxr'
  tags:
      - ip_vpn
...

For each type of the configuration the current index for RD/RT is imported. Afterwards, the configuration loop is started for each specific submodule. For OpenConfig the configuration is splitted per OpenConfig YANG module. For the rest of the configurations, the split is following the same flavour: interfaces and routing context. Though it isn’t necessary, I’ve implemented similar approach to show that the abstraction happening on controller/orchestrator level is relevant for all vendors, all type of configuration, regardless of the particular implementation of YANG models (or CLI commands) within the vendor.

More details about configuration loops you can find in the previous article.

The last part is the provisioning of the customer routers, which is done by using another master Ansible playbook “customer_equipment.yml”, which calls then role “cpe_ip_vpn”:


1
2
3
4
5
6
7
+--cpe_ip_vpn
   +--tasks
   |  +--cli_configuration_loop.yml
   |  +--main.yml
   +--templates
      +--cumulus-interfaces.j2
      +--cumulus-network-instance.j2

As you might have spot, the structure of the playbooks is exactly the same as for “service_provider_fabric.yml”.

Usage of automation for IP VPN for Arista EOS, Cisco IOS XR and Nokia SR OS

To provision the configuration of IP VPN for customer on Service Provider Fabric launch the master playbook in the following way:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[aaa@sand7 ansible]$ ansible-playbook service_provider_fabric.yml -i hosts --tags=ip_vpn

PLAY [fabric] ****************************************************

TASK [Gathering Facts] *******************************************
ok: [SR1]
ok: [EOS2]
ok: [EOS1]
ok: [XR1]
! OUTPUT IS OMMITED
PLAY RECAP *******************************************************
EOS1                       : ok=16   changed=6    unreachable=0    failed=0  
EOS2                       : ok=16   changed=7    unreachable=0    failed=0  
SR1                        : ok=16   changed=4    unreachable=0    failed=0  
XR1                        : ok=36   changed=17   unreachable=0    failed=0

And afterwards you can connect the customer:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ ansible-playbook customer_equipment.yml -i hosts --tags=ip_vpn

PLAY [cpe] *******************************************************

TASK [Gathering Facts] *******************************************
ok: [VX4]

TASK [cpe_ip_vpn : IMPORTING SERVICE REQUEST] ********************
ok: [VX4]

! OUTPUT IS OMITTED

TASK [cpe_ip_vpn : CONFIGURATION LOOP // PUSHING CLI CONFIG] *****
changed: [VX4]

PLAY RECAP *******************************************************
VX4                        : ok=11   changed=5    unreachable=0    failed=0

After the convergence of the BGP is done, the customer traffic can flow between the different sites:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
cumulus@VX4:mgmt-vrf:~$ ping -I CUST22 192.168.22.1 -c 1
ping: Warning: source address might be selected on device other than CUST22.
PING 192.168.22.1 (192.168.22.1) from 192.168.22.22 CUST22: 56(84) bytes of data.
64 bytes from 192.168.22.1: icmp_seq=1 ttl=64 time=8.27 ms

--- 192.168.22.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 8.276/8.276/8.276/0.000 ms


cumulus@VX4:mgmt-vrf:~$ ping -I CUST22 192.168.33.1 -c 1
ping: Warning: source address might be selected on device other than CUST22.
PING 192.168.33.1 (192.168.33.1) from 192.168.22.22 CUST22: 56(84) bytes of data.
64 bytes from 192.168.33.1: icmp_seq=1 ttl=253 time=63.9 ms

--- 192.168.33.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 63.911/63.911/63.911/0.000 ms


cumulus@VX4:mgmt-vrf:~$ ping -I CUST22 192.168.44.1 -c 1
ping: Warning: source address might be selected on device other than CUST22.
PING 192.168.44.1 (192.168.44.1) from 192.168.22.22 CUST22: 56(84) bytes of data.
64 bytes from 192.168.44.1: icmp_seq=1 ttl=253 time=48.1 ms

--- 192.168.44.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 48.187/48.187/48.187/0.000 ms

We are done. Provisioning of IP VPN is automated using Ansible and IETF L3VPN SVC YANG module.

The final configurations as well as topology files you can find on my GitHub

Lessons learned

When the new things are just being released, like IETF L3VPN SVC YANG model, the best way to learn how it is working is to read RFC, as there is too less information available besides RFC. On the other side, the RFC is written in a fairly easy language, that’s why it isn’t scary and it was a pleasure reading it.

Conclusion

The IETF YANG model to create IP VPN is very good step up into direction of open networks, as the standard is always better than proprietary implementations. On the other hand, we need always understand, where the standards are applied so that we can understand where the additional workarounds are needed. I can imagine that all the traditional vendors, like Cisco, Nokia or Juniper will adapt their SDN controller to work with this IETF YANG model, but all of them will have some internal mechanisms to mitigate the gaps (or just free areas) in the standard. Nevertheless, implementation of IP VPN in multivendor network running Arista EOS, Cisco IOS XR and Nokia (Alcatel-Lucent) SR OS using IETF L3VPN SVC YANG model is possible.

Take care and good bye!

Support us





P.S.

If you have further questions or you need help with your networks, I’m happy to assist you, just send me message (https://karneliuk.com/contact/). Also don’t forget to share the article on your social media, if you like it.

BR,

Anton Karneliuk

Exit mobile version