summaryrefslogtreecommitdiff
path: root/data/templates/frr/bgpd.frr.tmpl
blob: e49aaf12c832c36116ea1e9ea0d611fbced18b46 (plain)
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
{### MACRO definition for recurring peer patter, this can be either fed by a ###}
{### peer-group or an individual BGP neighbor ###}
{% macro bgp_neighbor(neighbor, config, peer_group=false) %}
{%   if peer_group == true %}
 neighbor {{ neighbor }} peer-group
{%   elif config.peer_group is defined and config.peer_group is not none %}
 neighbor {{ neighbor }} peer-group {{ config.peer_group }}
{%   endif %}
{%   if config.remote_as is defined and config.remote_as is not none %}
 neighbor {{ neighbor }} remote-as {{ config.remote_as }}
{%   endif %}
{%   if config.interface is defined and config.interface.remote_as is defined and config.interface.remote_as is not none %}
 neighbor {{ neighbor }} interface remote-as {{ config.interface.remote_as }}
{%   endif %}
{%   if config.advertisement_interval is defined and config.advertisement_interval is not none %}
 neighbor {{ neighbor }} advertisement-interval {{ config.advertisement_interval }}
{%   endif %}
{%   if config.bfd is defined %}
 neighbor {{ neighbor }} bfd
{%     if config.bfd.check_control_plane_failure is defined %}
 neighbor {{ neighbor }} bfd check-control-plane-failure
{%     endif %}
{%     if config.bfd.profile is defined and config.bfd.profile is not none %}
 neighbor {{ neighbor }} bfd profile {{ config.bfd.profile }}
{%     endif %}
{%   endif %}
{%   if config.capability is defined and config.capability is not none %}
{%     if config.capability.dynamic is defined %}
 neighbor {{ neighbor }} capability dynamic
{%     endif %}
{%     if config.capability.extended_nexthop is defined %}
 neighbor {{ neighbor }} capability extended-nexthop
{%     endif %}
{%   endif %}
{%   if config.description is defined and config.description is not none %}
 neighbor {{ neighbor }} description {{ config.description }}
{%   endif %}
{%   if config.disable_capability_negotiation is defined %}
 neighbor {{ neighbor }} dont-capability-negotiate
{%   endif %}
{%   if config.ebgp_multihop is defined and config.ebgp_multihop is not none %}
 neighbor {{ neighbor }} ebgp-multihop {{ config.ebgp_multihop }}
{%   endif %}
{%   if config.graceful_restart is defined and config.graceful_restart is not none %}
{%     if config.graceful_restart == 'enable' %}
{%       set graceful_restart = 'graceful-restart' %}
{%     elif config.graceful_restart == 'disable' %}
{%       set graceful_restart = 'graceful-restart-disable' %}
{%     elif config.graceful_restart == 'restart-helper' %}
{%       set graceful_restart = 'graceful-restart-helper' %}
{%     endif %}
 neighbor {{ neighbor }} {{ graceful_restart }}
{%   endif %}
{%   if config.local_as is defined and config.local_as is not none %}
{%     for local_as, local_as_config in config.local_as.items() %}
{#       There can be only one local-as value, this is checked in the Python code #}
 neighbor {{ neighbor }} local-as {{ local_as }} {{ 'no-prepend' if local_as_config.no_prepend is defined }} {{ 'replace-as' if local_as_config.no_prepend is defined and local_as_config.no_prepend.replace_as is defined }}
{%     endfor %}
{%   endif %}
{%   if config.override_capability is defined %}
 neighbor {{ neighbor }} override-capability
{%   endif %}
{%   if config.passive is defined %}
 neighbor {{ neighbor }} passive
{%   endif %}
{%   if config.password is defined and config.password is not none %}
 neighbor {{ neighbor }} password {{ config.password }}
{%   endif %}
{%   if config.port is defined and config.port is not none %}
 neighbor {{ neighbor }} port {{ config.port }}
{%   endif %}
{%   if config.shutdown is defined %}
 neighbor {{ neighbor }} shutdown
{%   endif %}
{%   if config.solo is defined %}
 neighbor {{ neighbor }} solo
{%   endif %}
{%   if config.strict_capability_match is defined %}
 neighbor {{ neighbor }} strict-capability-match
{%   endif %}
{%   if config.ttl_security is defined and config.ttl_security.hops is defined and config.ttl_security.hops is not none %}
 neighbor {{ neighbor }} ttl-security hops {{ config.ttl_security.hops }}
{%   endif %}
{%   if config.timers is defined %}
{%     if config.timers.connect is defined and config.timers.connect is not none %}
 neighbor {{ neighbor }} timers connect {{ config.timers.connect }}
{%     endif %}
{%     if config.timers.holdtime is defined and config.timers.keepalive is defined and config.timers.holdtime is not none and config.timers.keepalive is not none %}
 neighbor {{ neighbor }} timers {{ config.timers.keepalive }} {{ config.timers.holdtime }}
{%     endif %}
{%   endif %}
{%   if config.update_source is defined and config.update_source is not none %}
 neighbor {{ neighbor }} update-source {{ config.update_source }}
{%   endif %}
{%   if config.interface is defined and config.interface is not none %}
{%     if config.interface.peer_group is defined and config.interface.peer_group is not none %}
 neighbor {{ neighbor }} interface peer-group {{ config.interface.peer_group }}
{%     endif %}
{%     if config.interface.source_interface is defined and config.interface.source_interface is not none %}
 neighbor {{ neighbor }} interface {{ config.interface.source_interface }}
{%     endif %}
{%     if config.interface.v6only is defined and config.interface.v6only is not none %}
{%       if config.interface.v6only.peer_group is defined and config.interface.v6only.peer_group is not none %}
 neighbor {{ neighbor }} interface v6only peer-group {{ config.interface.v6only.peer_group }}
{%       endif %}
{%       if config.interface.v6only.remote_as is defined and config.interface.v6only.remote_as is not none %}
 neighbor {{ neighbor }} interface v6only remote-as {{ config.interface.v6only.remote_as }}
{%       endif %}
{%     endif %}
{%   endif %}
 !
{%   if config.address_family is defined and config.address_family is not none %}
{%     for afi, afi_config in config.address_family.items() %}
{%       if afi == 'ipv4_unicast' %}
 address-family ipv4 unicast
{%       elif afi == 'ipv4_multicast' %}
 address-family ipv4 multicast
{%       elif afi == 'ipv4_labeled_unicast' %}
 address-family ipv4 labeled-unicast
{%       elif afi == 'ipv4_vpn' %}
 address-family ipv4 vpn
{%       elif afi == 'ipv4_flowspec' %}
 address-family ipv4 flowspec
{%       elif afi == 'ipv6_unicast' %}
 address-family ipv6 unicast
{%       elif afi == 'ipv6_multicast' %}
 address-family ipv6 multicast
{%       elif afi == 'ipv6_labeled_unicast' %}
 address-family ipv6 labeled-unicast
{%       elif afi == 'ipv6_vpn' %}
 address-family ipv6 vpn
{%       elif afi == 'ipv6_flowspec' %}
 address-family ipv6 flowspec
{%       elif afi == 'l2vpn_evpn' %}
 address-family l2vpn evpn
{%       endif %}
{%       if afi_config.addpath_tx_all is defined %}
  neighbor {{ neighbor }} addpath-tx-all-paths
{%       endif %}
{%       if afi_config.addpath_tx_per_as is defined %}
  neighbor {{ neighbor }} addpath-tx-bestpath-per-AS
{%       endif %}
{%       if afi_config.allowas_in is defined and afi_config.allowas_in is not none %}
  neighbor {{ neighbor }} allowas-in {{ afi_config.allowas_in.number if afi_config.allowas_in.number is defined }}
{%       endif %}
{%       if afi_config.as_override is defined %}
  neighbor {{ neighbor }} as-override
{%       endif %}
{%       if afi_config.remove_private_as is defined %}
  neighbor {{ neighbor }} remove-private-AS
{%       endif %}
{%       if afi_config.route_reflector_client is defined %}
  neighbor {{ neighbor }} route-reflector-client
{%       endif %}
{%       if afi_config.weight is defined and afi_config.weight is not none %}
  neighbor {{ neighbor }} weight {{ afi_config.weight }}
{%       endif %}
{%       if afi_config.attribute_unchanged is defined and afi_config.attribute_unchanged is not none %}
  neighbor {{ neighbor }} attribute-unchanged {{ 'as-path ' if afi_config.attribute_unchanged.as_path is defined }}{{ 'med ' if afi_config.attribute_unchanged.med is defined }}{{ 'next-hop ' if afi_config.attribute_unchanged.next_hop is defined }}
{%       endif %}
{%       if afi_config.capability is defined and afi_config.capability.orf is defined and afi_config.capability.orf.prefix_list is defined and afi_config.capability.orf.prefix_list.send is defined %}
  neighbor {{ neighbor }} capability orf prefix-list send
{%       endif %}
{%       if afi_config.capability is defined and afi_config.capability.orf is defined and afi_config.capability.orf.prefix_list is defined and afi_config.capability.orf.prefix_list.receive is defined %}
  neighbor {{ neighbor }} capability orf prefix-list receive
{%       endif %}
{%       if afi_config.default_originate is defined %}
  neighbor {{ neighbor }} default-originate {{ 'route-map ' ~ afi_config.default_originate.route_map if afi_config.default_originate.route_map is defined }}
{%       endif %}
{%       if afi_config.distribute_list is defined and afi_config.distribute_list is not none %}
{%         if afi_config.distribute_list.export is defined and afi_config.distribute_list.export is not none %}
  neighbor {{ neighbor }} distribute-list {{ afi_config.distribute_list.export }} out
{%         endif %}
{%         if afi_config.distribute_list.import is defined and afi_config.distribute_list.import is not none %}
  neighbor {{ neighbor }} distribute-list {{ afi_config.distribute_list.import }} in
{%         endif %}
{%       endif %}
{%       if afi_config.filter_list is defined and afi_config.filter_list is not none %}
{%         if afi_config.filter_list.export is defined and afi_config.filter_list.export is not none %}
  neighbor {{ neighbor }} filter-list {{ afi_config.filter_list.export }} out
{%         endif %}
{%         if afi_config.filter_list.import is defined and afi_config.filter_list.import is not none %}
  neighbor {{ neighbor }} filter-list {{ afi_config.filter_list.import }} in
{%         endif %}
{%       endif %}
{%       if afi_config.maximum_prefix is defined and afi_config.maximum_prefix is not none %}
  neighbor {{ neighbor }} maximum-prefix {{ afi_config.maximum_prefix }}
{%       endif %}
{%       if afi_config.maximum_prefix_out is defined and afi_config.maximum_prefix_out is not none %}
  neighbor {{ neighbor }} maximum-prefix-out {{ afi_config.maximum_prefix_out }}
{%       endif %}
{%       if afi_config.nexthop_self is defined %}
  neighbor {{ neighbor }} next-hop-self {{ 'force' if afi_config.nexthop_self.force is defined }}
{%       endif %}
{%       if afi_config.route_server_client is defined %}
  neighbor {{ neighbor }} route-server-client
{%       endif %}
{%       if afi_config.route_map is defined and afi_config.route_map is not none %}
{%         if afi_config.route_map.export is defined and afi_config.route_map.export is not none %}
  neighbor {{ neighbor }} route-map {{ afi_config.route_map.export }} out
{%         endif %}
{%         if afi_config.route_map.import is defined and afi_config.route_map.import is not none %}
  neighbor {{ neighbor }} route-map {{ afi_config.route_map.import }} in
{%         endif %}
{%       endif %}
{%       if afi_config.prefix_list is defined and afi_config.prefix_list is not none %}
{%         if afi_config.prefix_list.export is defined and afi_config.prefix_list.export is not none %}
  neighbor {{ neighbor }} prefix-list  {{ afi_config.prefix_list.export }} out
{%         endif %}
{%         if afi_config.prefix_list.import is defined and afi_config.prefix_list.import is not none %}
  neighbor {{ neighbor }} prefix-list  {{ afi_config.prefix_list.import }} in
{%         endif %}
{%       endif %}
{%       if afi_config.soft_reconfiguration is defined and afi_config.soft_reconfiguration.inbound is defined %}
  neighbor {{ neighbor }} soft-reconfiguration inbound
{%       endif %}
{%       if afi_config.unsuppress_map is defined and afi_config.unsuppress_map is not none %}
  neighbor {{ neighbor }} unsuppress-map {{ afi_config.unsuppress_map }}
{%       endif %}
{%       if afi_config.disable_send_community is defined and afi_config.disable_send_community.extended is defined %}
 no neighbor {{ neighbor }} send-community extended
{%       endif %}
{%       if afi_config.disable_send_community is defined and afi_config.disable_send_community.standard is defined %}
 no neighbor {{ neighbor }} send-community standard
{%       endif %}
  neighbor {{ neighbor }} activate
 exit-address-family
 !
{%     endfor %}
{%   endif %}
{% endmacro %}
!
router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none }}
{% if parameters is defined and parameters.ebgp_requires_policy is defined %}
 bgp ebgp-requires-policy
{% else %}
 no bgp ebgp-requires-policy
{% endif %}
{#   Option must be set before any neighbor - see https://phabricator.vyos.net/T3463 #}
 no bgp default ipv4-unicast
{# Workaround for T2100 until we have decided about a migration script #}
 no bgp network import-check
{% if address_family is defined and address_family is not none %}
{%   for afi, afi_config in address_family.items() %}
 !
{%     if afi == 'ipv4_unicast' %}
 address-family ipv4 unicast
{%     elif afi == 'ipv4_multicast' %}
 address-family ipv4 multicast
{%     elif afi == 'ipv4_labeled_unicast' %}
 address-family ipv4 labeled-unicast
{%     elif afi == 'ipv4_vpn' %}
 address-family ipv4 vpn
{%     elif afi == 'ipv4_flowspec' %}
 address-family ipv4 flowspec
{%     elif afi == 'ipv6_unicast' %}
 address-family ipv6 unicast
{%     elif afi == 'ipv6_multicast' %}
 address-family ipv6 multicast
{%     elif afi == 'ipv6_labeled_unicast' %}
 address-family ipv6 labeled-unicast
{%     elif afi == 'ipv6_vpn' %}
 address-family ipv6 vpn
{%     elif afi == 'ipv6_flowspec' %}
 address-family ipv6 flowspec
{%     elif afi == 'l2vpn_evpn' %}
 address-family l2vpn evpn
{%     if afi_config.rd is defined and afi_config.rd is not none %}
  rd {{ afi_config.rd }}
{%     endif %}
{%     endif %}
{%     if afi_config.aggregate_address is defined and afi_config.aggregate_address is not none %}
{%       for aggregate, aggregate_config in afi_config.aggregate_address.items() %}
  aggregate-address {{ aggregate }}{{ ' as-set' if aggregate_config.as_set is defined }}{{ ' summary-only' if aggregate_config.summary_only is defined }}
{%         if aggregate_config.route_map is defined and aggregate_config.route_map is not none %}
  aggregate-address {{ aggregate }} route-map {{ aggregate_config.route_map }}
{%         endif %}
{%       endfor %}
{%     endif %}
{%     if afi_config.maximum_paths is defined and afi_config.maximum_paths.ebgp is defined and afi_config.maximum_paths.ebgp is not none %}
  maximum-paths {{ afi_config.maximum_paths.ebgp }}
{%     endif %}
{%     if afi_config.maximum_paths is defined and afi_config.maximum_paths.ibgp is defined and afi_config.maximum_paths.ibgp is not none %}
  maximum-paths ibgp {{ afi_config.maximum_paths.ibgp }}
{%     endif %}
{%     if afi_config.redistribute is defined and afi_config.redistribute is not none %}
{%       for protocol in afi_config.redistribute %}
{%         if protocol == 'table' %}
  redistribute table {{ afi_config.redistribute[protocol].table }}
{%         else %}
{%           set redistribution_protocol = protocol %}
{%             if protocol == 'ospfv3' %}
{%               set redistribution_protocol = 'ospf6' %}
{%             endif %}
  redistribute {{ redistribution_protocol }}{% if afi_config.redistribute[protocol].metric is defined %} metric {{ afi_config.redistribute[protocol].metric }}{% endif %}{% if afi_config.redistribute[protocol].route_map is defined %} route-map {{ afi_config.redistribute[protocol].route_map }}{% endif %}
{#######   we need this blank line!! #######}

{%         endif %}
{%       endfor %}
{%     endif %}
{%     if afi_config.network is defined and afi_config.network is not none %}
{%       for network in afi_config.network %}
  network {{ network }}{% if afi_config.network[network].route_map is defined %} route-map {{ afi_config.network[network].route_map }}{% endif %}{% if afi_config.network[network].backdoor is defined %} backdoor{% endif %}{% if afi_config.network[network].rd is defined and afi_config.network[network].label is defined%} rd {{ afi_config.network[network].rd }} label {{ afi_config.network[network].label }}{% endif %}
{#######   we need this blank line!! #######}

{%       endfor %}
{%     endif %}
{%     if afi_config.advertise is defined and afi_config.advertise is not none %}
{%       for adv_afi, adv_afi_config in afi_config.advertise.items() %}
{%         if adv_afi_config.unicast is defined and adv_afi_config.unicast is not none %}
  advertise {{ adv_afi }} unicast {{ 'route-map ' ~ adv_afi_config.unicast.route_map if adv_afi_config.unicast.route_map is defined }}
{%         endif %}
{%       endfor %}
{%     endif %}
{%     if afi_config.distance is defined and afi_config.distance is not none %}
{%       if afi_config.distance is defined and afi_config.distance.external is defined and afi_config.distance.internal is defined and afi_config.distance.local is defined %}
  distance bgp {{ afi_config.distance.external }} {{ afi_config.distance.internal }} {{ afi_config.distance.local }}
{%       endif %}
{%       if afi_config.distance.prefix is defined and afi_config.distance.prefix is not none %}
{%         for prefix in afi_config.distance.prefix %}
  distance {{ afi_config.distance.prefix[prefix].distance }} {{ prefix }}
{%         endfor %}
{%       endif %}
{%     endif %}
{%     if afi_config.export is defined and afi_config.export.vpn is defined %}
  export vpn
{%     endif %}
{%     if afi_config.import is defined and afi_config.import is not none %}
{%       if afi_config.import.vpn is defined %}
  import vpn
{%       endif %}
{%       if afi_config.import.vrf is defined and afi_config.import.vrf is not none %}
{%         for vrf in afi_config.import.vrf %}
  import vrf {{ vrf }}
{%         endfor %}
{%       endif %}
{%     endif %}
{%     if afi_config.label is defined and afi_config.label.vpn is defined and afi_config.label.vpn.export is defined and afi_config.label.vpn.export is not none %}
  label vpn export {{ afi_config.label.vpn.export }}
{%     endif %}
{%     if afi_config.local_install is defined and afi_config.local_install is not none %}
{%       for interface in afi_config.local_install.interface %}
  local-install {{ interface }}
{%       endfor %}
{%     endif %}
{%     if afi_config.advertise_all_vni is defined %}
  advertise-all-vni
{%     endif %}
{%     if afi_config.advertise_default_gw is defined %}
  advertise-default-gw
{%     endif %}
{%     if afi_config.advertise_pip is defined and afi_config.advertise_pip is not none %}
  advertise-pip ip {{ afi_config.advertise_pip }}
{%     endif %}
{%     if afi_config.advertise_svi_ip is defined %}
  advertise-svi-ip
{%     endif %}
{%     if afi_config.rt_auto_derive is defined %}
  autort rfc8365-compatible
{%     endif %}
{%     if afi_config.flooding is defined and afi_config.flooding.disable is defined %}
  flooding disable
{%     endif %}
{%     if afi_config.flooding is defined and afi_config.flooding.head_end_replication is defined %}
  flooding head-end-replication
{%     endif %}
{%     if afi_config.rd is defined and afi_config.rd.vpn is defined and afi_config.rd.vpn.export is defined %}
  rd vpn export {{ afi_config.rd.vpn.export }}
{%     endif %}
{%     if afi_config.route_target is defined and afi_config.route_target is not none %}
{%       if afi_config.route_target.vpn is defined and afi_config.route_target.vpn is not none %}
{%         if afi_config.route_target.vpn.both is defined and afi_config.route_target.vpn.both is not none %}
  route-target vpn both {{ afi_config.route_target.vpn.both }}
{%         else %}
{%           if afi_config.route_target.vpn.export is defined and afi_config.route_target.vpn.export is not none %}
  route-target vpn export {{ afi_config.route_target.vpn.export }}
{%           endif %}
{%           if afi_config.route_target.vpn.import is defined and afi_config.route_target.vpn.import is not none %}
  route-target vpn import {{ afi_config.route_target.vpn.import }}
{%           endif %}
{%         endif %}
{%       endif %}
{%       if afi_config.route_target.both is defined and afi_config.route_target.both is not none %}
  route-target both {{ afi_config.route_target.both }}
{%       else %}
{%         if afi_config.route_target.export is defined and afi_config.route_target.export is not none %}
  route-target export {{ afi_config.route_target.export }}
{%         endif %}
{%         if afi_config.route_target.import is defined and afi_config.route_target.import is not none %}
  route-target import {{ afi_config.route_target.import }}
{%         endif %}
{%       endif %}
{%     endif %}
{%     if afi_config.route_map is defined and afi_config.route_map.vpn is defined and afi_config.route_map.vpn is not none %}
{%       if afi_config.route_map.vpn.export is defined and afi_config.route_map.vpn.export is not none %}
  route-map vpn export {{ afi_config.route_map.vpn.export }}
{%       endif %}
{%       if afi_config.route_map.vpn.import is defined and afi_config.route_map.vpn.import is not none %}
  route-map vpn import {{ afi_config.route_map.vpn.import }}
{%       endif %}
{%     endif %}
{%     if afi_config.vni is defined and afi_config.vni is not none %}
{%       for vni, vni_config in afi_config.vni.items() %}
  vni {{ vni }}
{%         if vni_config.advertise_default_gw is defined %}
   advertise-default-gw
{%         endif %}
{%     if vni_config.advertise_svi_ip is defined %}
   advertise-svi-ip
{%     endif %}
{%     if vni_config.rd is defined and vni_config.rd is not none %}
   rd {{ vni_config.rd }}
{%     endif %}
{%     if vni_config.route_target is defined and vni_config.route_target is not none %}
{%       if vni_config.route_target.both is defined and vni_config.route_target.both is not none %}
   route-target both {{ vni_config.route_target.both }}
{%       endif %}
{%       if vni_config.route_target.export is defined and vni_config.route_target.export is not none %}
   route-target export {{ vni_config.route_target.export }}
{%       endif %}
{%       if vni_config.route_target.import is defined and vni_config.route_target.import is not none %}
   route-target import {{ vni_config.route_target.import }}
{%       endif %}
{%     endif %}
  exit-vni
{%       endfor %}
{%     endif %}
 exit-address-family
{%   endfor %}
{% endif %}
 !
{% if peer_group is defined and peer_group is not none %}
{%   for peer, config in peer_group.items() %}
{{ bgp_neighbor(peer, config, true) }}
{%   endfor %}
{% endif %}
 !
{% if neighbor is defined and neighbor is not none %}
{%   for peer, config in neighbor.items() %}
{{ bgp_neighbor(peer, config) }}
{%   endfor %}
{% endif %}
 !
{% if listen is defined %}
{%   if listen.limit is defined and listen.limit is not none %}
 bgp listen limit {{ listen.limit }}
{%   endif %}
{%   for prefix, options in listen.range.items() %}
{%     if options.peer_group is defined and options.peer_group is not none %}
 bgp listen range {{ prefix }} peer-group {{ options.peer_group }}
{%     endif %}
{%   endfor %}
{% endif %}
{% if parameters is defined %}
{%   if parameters.always_compare_med is defined %}
 bgp always-compare-med
{%   endif %}
{%   if parameters.bestpath is defined and parameters.bestpath is not none %}
{%     if parameters.bestpath.as_path is defined and parameters.bestpath.as_path is not none %}
{%       for option in parameters.bestpath.as_path %}
{# replace is required for multipath-relax option #}
 bgp bestpath as-path {{ option|replace('_', '-') }}
{%       endfor %}
{%     endif %}
{%     if parameters.bestpath.bandwidth is defined and parameters.bestpath.bandwidth is not none %}
 bgp bestpath bandwidth {{ parameters.bestpath.bandwidth }}
{%     endif %}
{%     if parameters.bestpath.compare_routerid is defined %}
 bgp bestpath compare-routerid
{%     endif %}
{%     if parameters.bestpath.med is defined and parameters.bestpath.med is not none %}
 bgp bestpath med {{ 'confed' if parameters.bestpath.med.confed is defined }} {{ 'missing-as-worst' if parameters.bestpath.med.missing_as_worst is defined }}
{%     endif %}
{%   endif %}
{%   if parameters.cluster_id is defined and parameters.cluster_id is not none %}
 bgp cluster-id {{ parameters.cluster_id }}
{%   endif %}
{%   if parameters.conditional_advertisement is defined and parameters.conditional_advertisement is not none %}
{%     if parameters.conditional_advertisement.timer is defined and parameters.conditional_advertisement.timer is not none %}
 bgp conditional-advertisement timer {{ parameters.conditional_advertisement.timer }}
{%     endif %}
{%   endif %}
{%   if parameters.confederation is defined and parameters.confederation is not none %}
{%     if parameters.confederation.identifier is defined and parameters.confederation.identifier is not none %}
 bgp confederation identifier {{ parameters.confederation.identifier }}
{%     endif %}
{%     if parameters.confederation.peers is defined and parameters.confederation.peers is not none %}
 bgp confederation peers {{ parameters.confederation.peers | join(' ') }}
{%     endif %}
{%   endif %}
{%   if parameters.dampening is defined and parameters.dampening is defined and parameters.dampening.half_life is defined and parameters.dampening.half_life is not none %}
{# Doesn't work in current FRR configuration; vtysh (bgp dampening 16 751 2001 61) #}
 bgp dampening {{ parameters.dampening.half_life }} {{ parameters.dampening.re_use if parameters.dampening.re_use is defined }} {{ parameters.dampening.start_suppress_time if parameters.dampening.start_suppress_time is defined }} {{ parameters.dampening.max_suppress_time if parameters.dampening.max_suppress_time is defined }}
{%   endif %}
{%   if parameters.default is defined and parameters.default is not none %}
{%     if parameters.default.local_pref is defined and parameters.default.local_pref is not none %}
 bgp default local-preference {{ parameters.default.local_pref }}
{%     endif %}
{%   endif %}
{%   if parameters.deterministic_med is defined %}
 bgp deterministic-med
{%   endif %}
{%   if parameters.distance is defined and parameters.distance is not none %}
{%     if parameters.distance.global is defined and parameters.distance.global.external is defined and parameters.distance.global.internal is defined and parameters.distance.global.local is defined %}
  distance bgp {{ parameters.distance.global.external }} {{ parameters.distance.global.internal }} {{ parameters.distance.global.local }}
{%     endif %}
{%     if parameters.distance.prefix is defined and parameters.distance.prefix is not none %}
{%       for prefix in parameters.distance.prefix %}
  distance {{ parameters.distance.prefix[prefix].distance }} {{ prefix }}
{%       endfor %}
{%     endif %}
{%   endif %}
{%   if parameters.fast_convergence is defined %}
  bgp fast-convergence
{%   endif %}
{%   if parameters.graceful_restart is defined %}
 bgp graceful-restart {{ 'stalepath-time ' ~ parameters.graceful_restart.stalepath_time if parameters.graceful_restart.stalepath_time is defined }}
{%   endif %}
{%   if parameters.graceful_shutdown is defined %}
 bgp graceful-shutdown
{%   endif %}
{%   if parameters.log_neighbor_changes is defined %}
 bgp log-neighbor-changes
{%   endif %}
{%   if parameters.minimum_holdtime is defined and parameters.minimum_holdtime is not none %}
 bgp minimum-holdtime {{ parameters.minimum_holdtime }}
{%   endif %}
{%   if parameters.network_import_check is defined %}
 bgp network import-check
{%   endif %}
{%   if parameters.no_client_to_client_reflection is defined %}
 no bgp client-to-client reflection
{%   endif %}
{%   if parameters.no_fast_external_failover is defined %}
 no bgp fast-external-failover
{%   endif %}
{%   if parameters.reject_as_sets is defined %}
 bgp reject-as-sets
{%   endif %}
{%   if parameters.router_id is defined and parameters.router_id is not none %}
 bgp router-id {{ parameters.router_id }}
{%   endif %}
{% endif %}
{% if timers is defined and timers.keepalive is defined and timers.holdtime is defined %}
 timers bgp {{ timers.keepalive }} {{ timers.holdtime }}
{% endif %}
exit