1# -*- coding: utf-8 -*- 2# Copyright 2021 Red Hat 3# GNU General Public License v3.0+ 4# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 5 6from __future__ import absolute_import, division, print_function 7 8__metaclass__ = type 9 10""" 11The Route_maps parser templates file. This contains 12a list of parser definitions and associated functions that 13facilitates both facts gathering and native command generation for 14the given network resource. 15""" 16 17import re 18from ansible.module_utils.six import iteritems 19from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network_template import ( 20 NetworkTemplate, 21) 22 23 24def _tmplt_route_map_match(config_data): 25 if ( 26 config_data.get("match") 27 and not config_data["match"].get("ip") 28 and not config_data["match"].get("ipv6") 29 ): 30 command = [] 31 match = config_data["match"] 32 if match and match.get("additional_paths"): 33 cmd = "match additional-paths advertise-set" 34 if config_data["match"]["additional_paths"].get("all"): 35 cmd += " all" 36 if config_data["match"]["additional_paths"].get("best"): 37 cmd += " best {best}".format( 38 **config_data["match"]["additional_paths"] 39 ) 40 if config_data["match"]["additional_paths"].get("best_range"): 41 cmd += " best-range" 42 if config_data["match"]["additional_paths"]["best_range"].get( 43 "lower_limit" 44 ): 45 cmd += " lower-limit {lower_limit}".format( 46 **config_data["match"]["additional_paths"][ 47 "best_range" 48 ] 49 ) 50 if config_data["match"]["additional_paths"]["best_range"].get( 51 "upper_limit" 52 ): 53 cmd += " upper-limit {upper_limit}".format( 54 **config_data["match"]["additional_paths"][ 55 "best_range" 56 ] 57 ) 58 if config_data["match"]["additional_paths"].get("group_best"): 59 cmd += " group-best" 60 command.append(cmd) 61 if match.get("as_path"): 62 cmd = "match as-path " 63 if match["as_path"].get("acls"): 64 temp = [] 65 for k, v in iteritems(match["as_path"]["acls"]): 66 temp.append(str(v)) 67 cmd += " ".join(sorted(temp)) 68 command.append(cmd) 69 if match.get("clns"): 70 cmd = "match clns" 71 if match["clns"].get("address"): 72 cmd += " address {address}".format(**match["clns"]) 73 elif match["clns"].get("next_hop"): 74 cmd = " next-hop {next_hop}".format(**match["clns"]) 75 elif match["clns"].get("route_source"): 76 cmd = " route-source {route_source}".format(**match["clns"]) 77 command.append(cmd) 78 if match.get("community"): 79 cmd = "match community " 80 temp = [] 81 for k, v in iteritems(match["community"]["name"]): 82 temp.append(v) 83 cmd += " ".join(sorted(temp)) 84 if match["community"].get("exact_match"): 85 cmd += " exact-match" 86 command.append(cmd) 87 if match.get("extcommunity"): 88 cmd = "match extcommunity " 89 temp = [] 90 for k, v in iteritems(match["extcommunity"]): 91 temp.append(v) 92 cmd += " ".join(sorted(temp)) 93 command.append(cmd) 94 if match.get("interfaces"): 95 cmd = "match interface " 96 temp = [] 97 for k, v in iteritems(match["interfaces"]): 98 temp.append(v) 99 cmd += " ".join(sorted(temp)) 100 command.append(cmd) 101 if match.get("length"): 102 command.append( 103 "match length {minimum} {maximum}".format(**match["length"]) 104 ) 105 if match.get("local_preference"): 106 cmd = "match local-preference " 107 if match["local_preference"].get("value"): 108 temp = [] 109 for k, v in iteritems(match["local_preference"]["value"]): 110 temp.append(v) 111 cmd += " ".join(sorted(temp)) 112 command.append(cmd) 113 if match.get("mdt_group"): 114 cmd = "match mdt-group " 115 if match["mdt_group"].get("acls"): 116 temp = [] 117 for k, v in iteritems(match["mdt_group"]["acls"]): 118 temp.append(v) 119 cmd += " ".join(sorted(temp)) 120 command.append(cmd) 121 if match.get("metric"): 122 cmd = "match metric" 123 if match["metric"].get("external"): 124 cmd += " external" 125 if match["metric"].get("value"): 126 cmd += " {value}".format(**match["metric"]) 127 if match["metric"].get("deviation"): 128 cmd += " +-" 129 if match["metric"].get("deviation_value"): 130 cmd += " {deviation_value}".format(**match["metric"]) 131 command.append(cmd) 132 if match.get("mpls_label"): 133 command.append("match mpls-label") 134 if match.get("policy_lists"): 135 cmd = "match policy-list " 136 temp = [] 137 for k, v in iteritems(match["policy_lists"]): 138 temp.append(v) 139 cmd += " ".join(sorted(temp)) 140 command.append(cmd) 141 if match.get("route_type"): 142 cmd = "match route-type" 143 if match["route_type"].get("external"): 144 cmd += " external" 145 if match["route_type"]["external"].get("type_1"): 146 cmd += " type-1" 147 elif match["route_type"]["external"].get("type_2"): 148 cmd += " type-2" 149 elif match["route_type"].get("internal"): 150 cmd += " internal" 151 elif match["route_type"].get("level_1"): 152 cmd += " level-1" 153 elif match["route_type"].get("level_2"): 154 cmd += " level-2" 155 elif match["route_type"].get("local"): 156 cmd += " local" 157 elif match["route_type"].get("nssa_external"): 158 cmd += " nssa-external" 159 if match["route_type"]["nssa_external"].get("type_1"): 160 cmd += " type-1" 161 elif match["route_type"]["nssa_external"].get("type_2"): 162 cmd += " type-2" 163 command.append(cmd) 164 if match.get("rpki"): 165 cmd = "match rpki" 166 if match["rpki"].get("invalid"): 167 cmd += " invalid" 168 if match["rpki"].get("not_found"): 169 cmd += " not-found" 170 if match["rpki"].get("valid"): 171 cmd += " valid" 172 command.append(cmd) 173 if match.get("security_group"): 174 cmd = "match security-group" 175 if match["security_group"].get("source"): 176 cmd += " source tag " 177 temp = [] 178 for k, v in iteritems(match["security_group"]["source"]): 179 temp.append(str(v)) 180 cmd += " ".join(sorted(temp)) 181 elif match["security_group"].get("destination"): 182 cmd += " destination tag" 183 for each in match["destination"]: 184 cmd += " {0}".format(each) 185 command.append(cmd) 186 if match.get("source_protocol"): 187 cmd = "match source-protocol" 188 if match["source_protocol"].get("bgp"): 189 cmd += " bgp {bgp}".format(**match["source_protocol"]) 190 if match["source_protocol"].get("connected"): 191 cmd += " connected" 192 if match["source_protocol"].get("eigrp"): 193 cmd += " eigrp {eigrp}".format(**match["source_protocol"]) 194 if match["source_protocol"].get("isis"): 195 cmd += " isis" 196 if match["source_protocol"].get("lisp"): 197 cmd += " lisp" 198 if match["source_protocol"].get("mobile"): 199 cmd += " mobile" 200 if match["source_protocol"].get("ospf"): 201 cmd += " ospf {ospf}".format(**match["source_protocol"]) 202 if match["source_protocol"].get("ospfv3"): 203 cmd += " ospfv3 {ospfv3}".format(**match["source_protocol"]) 204 if match["source_protocol"].get("rip"): 205 cmd += " rip" 206 if match["source_protocol"].get("static"): 207 cmd += " static" 208 command.append(cmd) 209 if match.get("tag"): 210 cmd = "match tag" 211 if match["tag"].get("tag_list"): 212 cmd += " list" 213 for each in match["tag"]["tag_list"]: 214 cmd += " {0}".format(each) 215 elif match["tag"].get("value"): 216 for each in match["tag"]["value"]: 217 cmd += " {0}".format(each) 218 command.append(cmd) 219 if match.get("track"): 220 command.append("match track {track}".format(**match)) 221 return command 222 223 224def _tmplt_route_map_match_ip(config_data): 225 if config_data.get("match") and config_data["match"].get("ip"): 226 227 def construct_cmd_from_list(cmd, config): 228 temp = [] 229 for k, v in iteritems(config): 230 temp.append(v) 231 cmd += " " + " ".join(sorted(temp)) 232 return cmd 233 234 cmd = "match ip" 235 if config_data["match"]["ip"].get("address"): 236 cmd += " address" 237 if config_data["match"]["ip"]["address"].get("prefix_lists"): 238 cmd += " prefix-list" 239 cmd = construct_cmd_from_list( 240 cmd, config_data["match"]["ip"]["address"]["prefix_lists"] 241 ) 242 elif config_data["match"]["ip"]["address"].get("acls"): 243 cmd = construct_cmd_from_list( 244 cmd, config_data["match"]["ip"]["address"]["acls"] 245 ) 246 if config_data["match"]["ip"].get("flowspec"): 247 cmd += " flowspec" 248 if config_data["match"]["ip"]["flowspec"].get("dest_pfx"): 249 cmd += " dest-pfx" 250 elif config_data["match"]["ip"]["flowspec"].get("src_pfx"): 251 cmd += " src-pfx" 252 if config_data["match"]["ip"]["flowspec"].get("prefix_lists"): 253 cmd += " prefix-list" 254 cmd = construct_cmd_from_list( 255 cmd, config_data["match"]["ip"]["flowspec"]["prefix_lists"] 256 ) 257 elif config_data["match"]["ip"]["flowspec"].get("acls"): 258 cmd = construct_cmd_from_list( 259 cmd, config_data["match"]["ip"]["flowspec"]["acls"] 260 ) 261 if config_data["match"]["ip"].get("next_hop"): 262 cmd += " next-hop" 263 if config_data["match"]["ip"]["next_hop"].get("prefix_lists"): 264 cmd += " prefix-list" 265 cmd = construct_cmd_from_list( 266 cmd, config_data["match"]["ip"]["next_hop"]["prefix_lists"] 267 ) 268 elif config_data["match"]["ip"]["next_hop"].get("acls"): 269 cmd = construct_cmd_from_list( 270 cmd, config_data["match"]["ip"]["next_hop"]["acls"] 271 ) 272 if config_data["match"]["ip"].get("redistribution_source"): 273 cmd += " redistribution-source" 274 if config_data["match"]["ip"]["redistribution_source"].get( 275 "prefix_lists" 276 ): 277 cmd += " prefix-list" 278 cmd = construct_cmd_from_list( 279 cmd, 280 config_data["match"]["ip"]["redistribution_source"][ 281 "prefix_lists" 282 ], 283 ) 284 elif config_data["match"]["ip"]["redistribution_source"].get( 285 "acls" 286 ): 287 cmd = construct_cmd_from_list( 288 cmd, 289 config_data["match"]["ip"]["redistribution_source"][ 290 "acls" 291 ], 292 ) 293 if config_data["match"]["ip"].get("route_source"): 294 cmd += " route-source" 295 if config_data["match"]["ip"]["route_source"].get( 296 "redistribution_source" 297 ): 298 cmd += " redistribution-source" 299 if config_data["match"]["ip"]["route_source"].get("prefix_lists"): 300 cmd += " prefix-list" 301 cmd = construct_cmd_from_list( 302 cmd, 303 config_data["match"]["ip"]["route_source"]["prefix_lists"], 304 ) 305 elif config_data["match"]["ip"]["route_source"].get("acls"): 306 cmd = construct_cmd_from_list( 307 cmd, config_data["match"]["ip"]["route_source"]["acls"] 308 ) 309 return cmd 310 311 312def _tmplt_route_map_match_ipv6(config_data): 313 if config_data.get("match") and config_data["match"].get("ipv6"): 314 cmd = "match ipv6" 315 if config_data["match"]["ipv6"].get("address"): 316 cmd += " address" 317 if config_data["match"]["ipv6"]["address"].get("prefix_list"): 318 cmd += " prefix-list {prefix_list}".format( 319 **config_data["match"]["ipv6"]["address"] 320 ) 321 elif config_data["match"]["ipv6"]["address"].get("acl"): 322 cmd += " {acl}".format( 323 **config_data["match"]["ipv6"]["address"] 324 ) 325 if config_data["match"]["ipv6"].get("flowspec"): 326 cmd += " flowspec" 327 if config_data["match"]["ipv6"]["flowspec"].get("dest_pfx"): 328 cmd += " dest-pfx" 329 elif config_data["match"]["ipv6"]["flowspec"].get("src_pfx"): 330 cmd += " src-pfx" 331 if config_data["match"]["ipv6"]["flowspec"].get("prefix_list"): 332 cmd += " prefix-list {prefix_list}".format( 333 **config_data["match"]["ipv6"]["flowspec"] 334 ) 335 elif config_data["match"]["ipv6"]["flowspec"].get("acl"): 336 cmd += " {acl}".format( 337 **config_data["match"]["ipv6"]["flowspec"] 338 ) 339 if config_data["match"]["ipv6"].get("next_hop"): 340 cmd += " next-hop" 341 if config_data["match"]["ipv6"]["next_hop"].get("prefix_list"): 342 cmd += " prefix-list {prefix_list}".format( 343 **config_data["match"]["ipv6"]["next_hop"] 344 ) 345 elif config_data["match"]["ipv6"]["next_hop"].get("acl"): 346 cmd += " {acl}".format( 347 **config_data["match"]["ipv6"]["next_hop"] 348 ) 349 if config_data["match"]["ipv6"].get("route_source"): 350 cmd += " route-source" 351 if config_data["match"]["ipv6"]["route_source"].get("prefix_list"): 352 cmd += " prefix-list {prefix_list}".format( 353 **config_data["match"]["ipv6"]["route_source"] 354 ) 355 elif config_data["match"]["ipv6"]["route_source"].get("acl"): 356 cmd += " {acl}".format( 357 **config_data["match"]["ipv6"]["route_source"] 358 ) 359 return cmd 360 361 362def _tmplt_route_map_set(config_data): 363 if config_data.get("set"): 364 command = [] 365 set = config_data["set"] 366 if set.get("aigp_metric"): 367 cmd = "set aigp-metric" 368 if set["aigp_metric"].get("value"): 369 cmd += " {value}".format(**set["aigp_metric"]) 370 elif set["aigp_metric"].get("igp_metric"): 371 cmd += " igp-metric" 372 command.append(cmd) 373 if set.get("as_path"): 374 cmd = "set as-path" 375 if set["as_path"].get("prepend"): 376 cmd += " prepend" 377 if set["as_path"]["prepend"].get("as_number"): 378 cmd += " {as_number}".format(**set["as_path"]["prepend"]) 379 elif set["as_path"]["prepend"].get("last_as"): 380 cmd += " last-as {last_as}".format( 381 **set["as_path"]["prepend"] 382 ) 383 if set["as_path"].get("tag"): 384 cmd += " tag" 385 command.append(cmd) 386 if set.get("automatic_tag"): 387 command.append("set automatic-tag") 388 if set.get("clns"): 389 command.append("set clns next-hop {clns}".format(**set)) 390 if set.get("comm_list"): 391 command.append("set comm-list {comm_list} delete".format(**set)) 392 if set.get("community"): 393 cmd = "set community" 394 if set["community"].get("number"): 395 cmd += " {number}".format(**set["community"]) 396 if set["community"].get("additive"): 397 cmd += " additive" 398 if set["community"].get("gshut"): 399 cmd += " gshut" 400 if set["community"].get("internet"): 401 cmd += " internet" 402 if set["community"].get("local_as"): 403 cmd += " local-as" 404 if set["community"].get("no_advertise"): 405 cmd += " no-advertise" 406 if set["community"].get("no_export"): 407 cmd += " no-export" 408 if set["community"].get("none"): 409 cmd += " none" 410 command.append(cmd) 411 if set.get("dampening"): 412 command.append( 413 "set dampening {penalty_half_time} {reuse_route_val} {suppress_route_val} {max_suppress}".format( 414 **set["dampening"] 415 ) 416 ) 417 if set.get("default"): 418 command.append( 419 "set default interface {default}".format(**set["default"]) 420 ) 421 if set.get("extcomm_list"): 422 command.append( 423 "set extcomm-list {extcomm_list} delete".format(**set) 424 ) 425 if set.get("extcommunity"): 426 if set["extcommunity"].get("cost"): 427 cmd = "set extcommunity cost" 428 if set["extcommunity"]["cost"].get("igp"): 429 cmd += " igp" 430 elif set["extcommunity"]["cost"].get("pre_bestpath"): 431 cmd += " pre-bestpath" 432 if set["extcommunity"]["cost"].get("id"): 433 cmd += " {id}".format(**set["extcommunity"]["cost"]) 434 if set["extcommunity"]["cost"].get("cost_value"): 435 cmd += " {cost_value}".format( 436 **set["extcommunity"]["cost"] 437 ) 438 command.append(cmd) 439 if set["extcommunity"].get("rt"): 440 cmd = "set extcommunity rt" 441 if set["extcommunity"]["rt"].get("range"): 442 cmd += " range {lower_limit} {upper_limit}".format( 443 **set["extcommunity"]["rt"]["range"] 444 ) 445 elif set["extcommunity"]["rt"].get("address"): 446 cmd += " {address}".format(**set["extcommunity"]["rt"]) 447 if set["extcommunity"]["rt"].get("additive"): 448 cmd += " additive" 449 command.append(cmd) 450 if set["extcommunity"].get("soo"): 451 command.append( 452 "set extcommunity soo {soo}".format(**set["extcommunity"]) 453 ) 454 if set["extcommunity"].get("vpn_distinguisher"): 455 cmd = "set extcommunity vpn-distinguisher" 456 if set["extcommunity"]["vpn_distinguisher"].get("range"): 457 cmd += " range {lower_limit} {upper_limit}".format( 458 **set["extcommunity"]["vpn_distinguisher"]["range"] 459 ) 460 elif set["extcommunity"]["vpn_distinguisher"].get("address"): 461 cmd += " {address}".format( 462 **set["extcommunity"]["vpn_distinguisher"] 463 ) 464 if set["extcommunity"]["vpn_distinguisher"].get("additive"): 465 cmd += " additive" 466 command.append(cmd) 467 if set.get("global"): 468 command.append("set global") 469 if set.get("interfaces"): 470 cmd = "set interface " 471 temp = [] 472 for k, v in iteritems(set["interfaces"]): 473 temp.append(v) 474 cmd += " ".join(sorted(temp)) 475 command.append(cmd) 476 if set.get("level"): 477 cmd = "set level" 478 if set["level"].get("level_1"): 479 cmd += " level-1" 480 elif set["level"].get("level_1_2"): 481 cmd += " level-1-2" 482 elif set["level"].get("level_2"): 483 cmd += " level-2" 484 elif set["level"].get("nssa_only"): 485 cmd += " nssa-only" 486 if set.get("lisp"): 487 command.append("set lisp locator-set {lisp}".format(**set)) 488 if set.get("local_preference"): 489 command.append( 490 "set local-preference {local_preference}".format(**set) 491 ) 492 if set.get("metric"): 493 cmd = "set metric" 494 if set["metric"].get("metric_value"): 495 cmd += " {metric_value}".format(**set["metric"]) 496 if set["metric"].get("deviation"): 497 if set["metric"]["deviation"] == "plus": 498 cmd += " +{eigrp_delay} {metric_reliability} {metric_bandwidth} {mtu}".format( 499 **set["metric"] 500 ) 501 elif set["metric"]["deviation"] == "minus": 502 cmd += " -{eigrp_delay} {metric_reliability} {metric_bandwidth} {mtu}".format( 503 **set["metric"] 504 ) 505 if set["metric"].get("deviation") and not set["metric"].get( 506 "eigrp_delay" 507 ): 508 if set["metric"]["deviation"] == "plus": 509 cmd = "set metric +{metric_value}".format(**set["metric"]) 510 elif set["metric"]["deviation"] == "minus": 511 cmd = "set metric -{metric_value}".format(**set["metric"]) 512 command.append(cmd) 513 if set.get("metric_type"): 514 cmd = "set metric-type" 515 if set["metric_type"].get("external"): 516 cmd += " external" 517 elif set["metric_type"].get("internal"): 518 cmd += " internal" 519 elif set["metric_type"].get("type_1"): 520 cmd += " type-1" 521 elif set["metric_type"].get("type_2"): 522 cmd += " type-2" 523 command.append(cmd) 524 if set.get("mpls_label"): 525 command.append("set mpls-label") 526 if set.get("origin"): 527 cmd = "set origin" 528 if set["origin"].get("igp"): 529 cmd += " igp" 530 elif set["origin"].get("incomplete"): 531 cmd += " incomplete" 532 if set.get("tag"): 533 command.append("set tag {tag}".format(**set)) 534 if set.get("traffic_index"): 535 command.append("set traffic-index {traffic_index}".format(**set)) 536 if set.get("vrf"): 537 command.append("set vrf {vrf}".format(**set)) 538 if set.get("weight"): 539 command.append("set weight {weight}".format(**set)) 540 return command 541 542 543def _tmplt_route_map_set_ip(config_data): 544 if config_data.get("set") and config_data["set"].get("ip"): 545 command = [] 546 set_ip = config_data["set"]["ip"] 547 cmd = "set ip" 548 if set_ip.get("address"): 549 command.append( 550 "{0} address prefix-list {address}".format(cmd, **set_ip) 551 ) 552 if set_ip.get("df"): 553 command.append("{0} df {df}".format(cmd, **set_ip)) 554 if set_ip.get("global_route"): 555 cmd += " global next-hop" 556 if set_ip["global_route"].get("verify_availability"): 557 cmd += " verify-availability {address} {sequence} track {track}".format( 558 **set_ip["global_route"]["verify_availability"] 559 ) 560 elif set_ip["global_route"].get("address"): 561 cmd += " {address}".format(**set_ip["global_route"]) 562 command.append(cmd) 563 if set_ip.get("next_hop"): 564 cmd += " next-hop" 565 if set_ip["next_hop"].get("address"): 566 command.append( 567 "{0} {address}".format(cmd, **set_ip["next_hop"]) 568 ) 569 if set_ip["next_hop"].get("dynamic"): 570 command.append("{0} dynamic dhcp".format(cmd)) 571 if set_ip["next_hop"].get("encapsulate"): 572 command.append( 573 "{0} encapsulate l3vpn {encapsulate}".format( 574 cmd, **set_ip["next_hop"] 575 ) 576 ) 577 if set_ip["next_hop"].get("peer_address"): 578 command.append("{0} peer-address".format(cmd)) 579 if set_ip["next_hop"].get("recursive"): 580 child_cmd = "{0} recursive".format(cmd) 581 if set_ip["next_hop"]["recursive"].get("global_route"): 582 child_cmd += " global" 583 elif set_ip["next_hop"]["recursive"].get("vrf"): 584 child_cmd += " vrf {vrf}".format( 585 **set_ip["next_hop"]["recursive"] 586 ) 587 if set_ip["next_hop"]["recursive"].get("address"): 588 child_cmd += " {address}".format( 589 **set_ip["next_hop"]["recursive"] 590 ) 591 command.append(child_cmd) 592 if set_ip["next_hop"].get("self"): 593 command.append("{0} self".format(cmd)) 594 if set_ip["next_hop"].get("verify_availability"): 595 command.append( 596 "{0} verify-availability {address} {sequence} track {track}".format( 597 cmd, **set_ip["next_hop"]["verify_availability"] 598 ) 599 ) 600 if set_ip.get("precedence"): 601 cmd += " precedence" 602 if set_ip["precedence"].get("critical"): 603 cmd += " critical" 604 elif set_ip["precedence"].get("flash"): 605 cmd += " flash" 606 elif set_ip["precedence"].get("flash_override"): 607 cmd += " flash-override" 608 elif set_ip["precedence"].get("immediate"): 609 cmd += " immediate" 610 elif set_ip["precedence"].get("internet"): 611 cmd += " internet" 612 elif set_ip["precedence"].get("network"): 613 cmd += " network" 614 elif set_ip["precedence"].get("priority"): 615 cmd += " priority" 616 elif set_ip["precedence"].get("routine"): 617 cmd += " routine" 618 command.append(cmd) 619 if set_ip.get("qos_group"): 620 command.append("{0} qos-group {qos_group}".format(cmd, **set_ip)) 621 if set_ip.get("tos"): 622 cmd += " tos" 623 if set_ip["tos"].get("max_reliability"): 624 cmd += " max-reliability" 625 elif set_ip["tos"].get("max_throughput"): 626 cmd += " max-throughput" 627 elif set_ip["tos"].get("min_delay"): 628 cmd += " min-delay" 629 elif set_ip["tos"].get("min_monetary_cost"): 630 cmd += " min-monetary-cost" 631 elif set_ip["tos"].get("normal"): 632 cmd += " normal" 633 command.append(cmd) 634 if set_ip.get("vrf"): 635 cmd += " vrf {vrf} next-hop".format(**set_ip) 636 if set_ip["vrf"].get("verify_availability").get("address"): 637 cmd += " verify-availability {address} {sequence} track {track}".format( 638 **set_ip["vrf"]["verify_availability"] 639 ) 640 elif set_ip["vrf"].get("address"): 641 cmd += " {address}".format(**set_ip["vrf"]) 642 command.append(cmd) 643 return command 644 645 646def _tmplt_route_map_set_ipv6(config_data): 647 if config_data.get("set") and config_data["set"].get("ipv6"): 648 set_ipv6 = config_data["set"]["ipv6"] 649 cmd = "set ipv6" 650 if set_ipv6.get("address"): 651 cmd += " address prefix-list {address}".format(**set_ipv6) 652 if set_ipv6.get("default"): 653 cmd += " default" 654 if set_ipv6.get("global_route"): 655 cmd += " global next-hop" 656 if set_ipv6["global_route"].get("verify_availability"): 657 cmd += " verify-availability {address} {sequence} track {track}".format( 658 **set_ipv6["global_route"]["verify_availability"] 659 ) 660 elif set_ipv6["global_route"].get("address"): 661 cmd += " {address}".format(**set_ipv6["global_route"]) 662 if set_ipv6.get("next_hop"): 663 cmd += " next-hop" 664 if set_ipv6["next_hop"].get("address"): 665 cmd += " {address}".format(**set_ipv6["next_hop"]) 666 if set_ipv6["next_hop"].get("encapsulate"): 667 cmd += " encapsulate l3vpn {encapsulate}".format( 668 **set_ipv6["next_hop"] 669 ) 670 if set_ipv6["next_hop"].get("peer_address"): 671 cmd += " peer-address" 672 if set_ipv6.get("precedence"): 673 cmd += " precedence {precedence}".format(**set_ipv6) 674 if set_ipv6.get("vrf"): 675 cmd += " vrf {vrf} next-hop verify-availability {address} {sequence} track {track}".format( 676 **set_ipv6["vrf"]["verify_availability"] 677 ) 678 return cmd 679 680 681class Route_mapsTemplate(NetworkTemplate): 682 def __init__(self, lines=None): 683 super(Route_mapsTemplate, self).__init__(lines=lines, tmplt=self) 684 685 PARSERS = [ 686 { 687 "name": "route_map", 688 "getval": re.compile( 689 r""" 690 ^route-map* 691 \s*(?P<route_map>\S+)* 692 \s*(?P<action>deny|permit)* 693 \s*(?P<sequence>\d+)* 694 $""", 695 re.VERBOSE, 696 ), 697 "setval": "", 698 "result": { 699 "{{ route_map }}": { 700 "route_map": "{{ route_map }}", 701 "{{ action|d() + '_' + sequence|d() }}": { 702 "entries": { 703 "action": "{{ action }}", 704 "sequence": "{{ sequence }}", 705 } 706 }, 707 } 708 }, 709 "shared": True, 710 }, 711 { 712 "name": "continue_entry", 713 "getval": re.compile( 714 r""" 715 \s+continue* 716 \s*(?P<entry_sequence>\d+)* 717 $""", 718 re.VERBOSE, 719 ), 720 "setval": "continue {{ continue_entry.entry_sequence }}", 721 "result": { 722 "{{ route_map }}": { 723 "{{ action|d() + '_' + sequence|d() }}": { 724 "entries": { 725 "continue_entry": { 726 "set": "{{ True if entry_sequence is not defined }}", 727 "entry_sequence": "{{ entry_sequence }}", 728 } 729 } 730 } 731 } 732 }, 733 }, 734 { 735 "name": "description", 736 "getval": re.compile( 737 r""" 738 \s+description* 739 \s*(?P<description>\S.*)* 740 $""", 741 re.VERBOSE, 742 ), 743 "setval": "description {{ description }}", 744 "result": { 745 "{{ route_map }}": { 746 "{{ action|d() + '_' + sequence|d() }}": { 747 "entries": {"description": "{{ description }}"} 748 } 749 } 750 }, 751 }, 752 { 753 "name": "match", 754 "getval": re.compile( 755 r""" 756 \s+match* 757 \s*(?P<additional_paths>additional-paths\sadvertise-set\s\S.*)* 758 \s*(?P<as_path>as-path.*|as-path)* 759 \s*(?P<clns>clns\s(address\s\S+|next-hop\s\S+|route-source\s\S+))* 760 \s*(?P<community>community\s\S.*)* 761 \s*(?P<extcommunity>extcommunity\s\S.*)* 762 \s*(?P<interfaces>interface\s\S.*)* 763 \s*(?P<length>length\s\d+\s\d+)* 764 \s*(?P<local_preference>local-preference\s\d.*|local-preference)* 765 \s*(?P<mdt_group>mdt-group\s\S.*|mdt-group)* 766 \s*(?P<metric>metric\sexternal\s\S.*|metric\s\d+\S.*)* 767 \s*(?P<mpls_label>mpls-label)* 768 \s*(?P<policy_list>policy-list\s\S.*)* 769 \s*(?P<route_type>route-type\s(external\s(type-1|type-2)|internal|level-1|level-2|local|nssa-external\s(type-1|type-2)))* 770 \s*(?P<rpki>rpki\s(invalid|not-found|valid))* 771 \s*(?P<security_group>security-group\s(destination\stag\s\d.*|source\stag\s\d.*))* 772 \s*(?P<source_protocol>source-protocol\s\S.*)* 773 \s*(?P<tag>tag\slist\s\S.*|tag\s\S.*)* 774 \s*(?P<track>track\s*\d+)* 775 $""", 776 re.VERBOSE, 777 ), 778 "setval": _tmplt_route_map_match, 779 "result": { 780 "{{ route_map }}": { 781 "{{ action|d() + '_' + sequence|d() }}": { 782 "entries": { 783 "match": { 784 "additional_paths": { 785 "all": "{{ True if additional_paths is defined and 'all' in additional_paths }}", 786 "best": "{{ additional_paths.split('best ')[1].split(' ')[0]|int if additional_paths is defined and\ 787 'best' in additional_paths and 'best-range' not in additional_paths }}", 788 "best_range": { 789 "lower_limit": "{{ additional_paths.split('best-range ')[1].split(' ')[0]|int if additional_paths is defined and\ 790 'best-range' in additional_paths }}", 791 "upper_limit": "{{ additional_paths.split('best-range ')[1].split(' ')[1]|int if additional_paths is defined and\ 792 'best-range' in additional_paths }}", 793 }, 794 "group_best": "{{ True if additional_paths is defined and 'group-best' in additional_paths }}", 795 }, 796 "as_path": { 797 "set": "{{ True if as_path is defined and as_path.split(' ')|length == 1 }}", 798 "acls": "{{ as_path.split('as-path ')[1].split(' ') if as_path is defined and as_path.split(' ')|length > 1 }}", 799 }, 800 "clns": { 801 "address": "{{ clns.split('clns address ')[1] if clns is defined }}", 802 "next_hop": "{{ clns.split('clns next-hop ')[1] if clns is defined }}", 803 "route_source": "{{ clns.split('clns route-source ')[1] if clns is defined }}", 804 }, 805 "community": { 806 "name": "{{ community.split('community ')[1].split(' exact-match')[0].split(' ') if community is defined }}", 807 "exact_match": "{{ True if community is defined and 'exact-match' in community }}", 808 }, 809 "extcommunity": "{{ extcommunity.split('extcommunity ')[1].split(' ') if extcommunity is defined }}", 810 "interfaces": "{{ interfaces.split('interface ')[1].split(' ') if interfaces is defined }}", 811 "length": { 812 "minimum": "{{ length.split(' ')[1] if length is defined }}", 813 "maximum": "{{ length.split(' ')[2] if length is defined }}", 814 }, 815 "local_preference": { 816 "set": "{{ True if local_preference is defined and local_preference.split(' ')|length == 1 }}", 817 "value": "{{ local_preference.split('local-preference ')[1].split(' ') if local_preference is defined }}", 818 }, 819 "mdt_group": { 820 "set": "{{ True if mdt_group is defined and mdt_group.split(' ')|length == 1 }}", 821 "acls": "{{ mdt_group.split('mdt-group ')[1].split(' ') if mdt_group is defined }}", 822 }, 823 "metric": { 824 "external": "{{ True if metric is defined and 'external' in metric.split(' ') }}", 825 "value": "{% if metric is defined and 'external' not in metric.split(' ') %}{{ metric.split(' ')[1] }}\ 826 {% elif metric is defined and 'external' in metric.split(' ') %}{{ metric.split(' ')[2] }}\ 827 {% endif %}", 828 "deviation": "{{ True if metric is defined and '+-' in metric }}", 829 "deviation_value": "{% if metric is defined and 'external' in metric and '+-' in metric %}{{ metric.split(' ')[4] }}\ 830 {% elif metric is defined and 'external' not in metric and '+-' in metric %}{{ metric.split(' ')[3] }}{% endif %}", 831 }, 832 "mpls_label": "{{ True if mpls_label is defined }}", 833 "policy_lists": "{{ policy_list.split('policy-list ')[1].split(' ') if policy_list is defined }}", 834 "route_type": { 835 "external": { 836 "set": "{{ True if route_type is defined and 'type-1' not in route_type and 'type-2' not in route_type}}", 837 "type_1": "{{ True if route_type is defined and 'type-1' in route_type }}", 838 "type_2": "{{ True if route_type is defined and 'type-2' in route_type }}", 839 }, 840 "internal": "{{ True if route_type is defined and 'internal' in route_type }}", 841 "level_1": "{{ True if route_type is defined and 'level-1' in route_type }}", 842 "level_2": "{{ True if route_type is defined and 'level-2' in route_type }}", 843 "local": "{{ True if route_type is defined and 'local' in route_type }}", 844 "nssa_external": { 845 "set": "{{ True if route_type is defined and 'type-1' not in route_type and 'type-2' not in route_type}}", 846 "type_1": "{{ True if route_type is defined and 'type-1' in route_type }}", 847 "type_2": "{{ True if route_type is defined and 'type-2' in route_type }}", 848 }, 849 }, 850 "rpki": { 851 "invalid": "{{ True if rpki is defined and 'invalid' in rpki and 'valid' not in rpki.split(' ') }}", 852 "not_found": "{{ True if rpki is defined and 'not-found' in rpki }}", 853 "valid": "{{ True if rpki is defined and 'valid' in rpki and 'invalid' not in rpki.split(' ') }}", 854 }, 855 "security_group": { 856 "destination": "{{ security_group.split('destination tag ')[1].split(' ') if security_group is defined and\ 857 'destination' in security_group }}", 858 "source": "{{ security_group.split('source tag ')[1].split(' ') if security_group is defined and\ 859 'source' in security_group }}", 860 }, 861 "source_protocol": { 862 "bgp": "{{ source_protocol.split('bgp ')[1].split(' ')[0] if source_protocol is defined and 'bgp' in source_protocol }}", 863 "connected": "{{ True if source_protocol is defined and 'connected' in source_protocol }}", 864 "eigrp": "{{ source_protocol.split('eigrp ')[1].split(' ')[0] if source_protocol is defined and\ 865 'eigrp' in source_protocol }}", 866 "isis": "{{ True if source_protocol is defined and 'isis' in source_protocol }}", 867 "lisp": "{{ True if source_protocol is defined and 'lisp' in source_protocol }}", 868 "mobile": "{{ True if source_protocol is defined and 'mobile' in source_protocol }}", 869 "ospf": "{{ source_protocol.split('ospf ')[1].split(' ')[0] if source_protocol is defined and\ 870 'ospf' in source_protocol }}", 871 "ospfv3": "{{ source_protocol.split('ospfv3 ')[1].split(' ')[0] if source_protocol is defined and\ 872 'ospfv3' in source_protocol }}", 873 "rip": "{{ True if source_protocol is defined and 'rip' in source_protocol }}", 874 "static": "{{ True if source_protocol is defined and 'static' in source_protocol }}", 875 }, 876 "tag": { 877 "value": "{{ tag.split('tag ')[1].split(' ') if tag is defined and 'list' not in tag }}", 878 "tag_list": "{{ tag.split('tag list ')[1].split(' ') if tag is defined and 'list' in tag }}", 879 }, 880 "track": "{{ track.split('track ')[1] if track is defined }}", 881 } 882 } 883 } 884 } 885 }, 886 }, 887 { 888 "name": "match.ip", 889 "getval": re.compile( 890 r""" 891 \s+match* 892 \s*(?P<ip>ip)* 893 \s*(?P<address>address\sprefix-list\s\S.*|address\s\S.*)* 894 \s*(?P<flowspec>flowspec\sdest-pfx\s(prefix-list\s\S.*|\S.*)|flowspec\ssrc-pfx\s(prefix-list\s\S.*|\S.*))* 895 \s*(?P<next_hop>next-hop\sprefix-list\s\S.*|next-hop\s\S.*|next-hop)* 896 \s*(?P<redistribution_source>redistribution-source\sprefix-list\s\S.*|redistribution-source\s\S.*|redistribution-source)* 897 \s*(?P<route_source>route-source\sredistribution-source\sprefix-list\s\S.*|route-source\sredistribution-source\s\S.*|route-source\sprefix-list\s\S.*|route-source\s\S.*|route-source\sredistribution-source|route-source)* 898 $""", 899 re.VERBOSE, 900 ), 901 "setval": _tmplt_route_map_match_ip, 902 "compval": "match", 903 "result": { 904 "{{ route_map }}": { 905 "{{ action|d() + '_' + sequence|d() }}": { 906 "entries": { 907 "match": { 908 "ip": { 909 "address": { 910 "acls": "{{ address.split('address ')[1].split(' ') if address is defined and\ 911 'prefix-list' not in address else none }}", 912 "prefix_lists": "{{ address.split('address prefix-list ')[1].split(' ') if address is defined and\ 913 'prefix-list' in address else None }}", 914 }, 915 "flowspec": { 916 "dest_pfx": "{{ True if flowspec is defined and 'dest-pfx' in flowspec }}", 917 "src_pfx": "{{ True if flowspec is defined and 'src-pfx' in flowspec }}", 918 "acls": "{{ flowspec.split('flowspec ')[1].split(' ')|d() if flowspec is defined and\ 919 'prefix-list' not in flowspec else '' }}", 920 "prefix_lists": "{{ flowspec.split('flowspec prefix-list ')[1].split(' ')|d() if flowspec is defined and\ 921 'prefix-list' in flowspec else ''}}", 922 }, 923 "next_hop": { 924 "set": "{{ True if next_hop is defined and next_hop.split(' ')|length == 1 }}", 925 "acls": "{{ next_hop.split('next-hop ')[1].split(' ') if next_hop is defined and\ 926 'prefix-list' not in next_hop else '' }}", 927 "prefix_lists": "{{ next_hop.split('next-hop prefix-list ')[1].split(' ') if next_hop is defined and\ 928 'prefix-list' in next_hop and next_hop.split('next-hop prefix-list ')[1] is not none else '' }}", 929 }, 930 "redistribution_source": { 931 "set": "{{ True if redistribution_source is defined and redistribution_source.split(' ')|length == 1 }}", 932 "acls": "{{ redistribution_source.split('redistribution-source ')[1].split(' ')|d()\ 933 if redistribution_source is defined and 'prefix-list' not in redistribution_source else '' }}", 934 "prefix_lists": "{{ redistribution_source.split('redistribution-source prefix-list ')[1].split(' ')|d()\ 935 if redistribution_source is defined and 'prefix-list' in redistribution_source else '' }}", 936 }, 937 "route_source": { 938 "set": "{{ True if route_source is defined and route_source.split(' ')|length == 1 }}", 939 "redistribution_source": "{{ True if route_source is defined and 'redistribution-source' in route_source }}", 940 "acls": "{{ route_source.split('route-source ')[1].split(' ') if route_source is defined and\ 941 'prefix-list' not in route_source else '' }}", 942 "prefix_lists": "{{ route_source.split('route-source prefix-list ')[1].split(' ') if route_source is defined and\ 943 'prefix-list' in route_source else '' }}", 944 }, 945 } 946 } 947 } 948 } 949 } 950 }, 951 }, 952 { 953 "name": "match.ipv6", 954 "getval": re.compile( 955 r""" 956 \s+match* 957 \s*(?P<ipv6>ipv6)* 958 \s*(?P<address>address\sprefix-list\s\S.*|address\s\S.*)* 959 \s*(?P<flowspec>flowspec\sdest-pfx\s(prefix-list\s\S.*|\S.*)|flowspec\ssrc-pfx\s(prefix-list\s\S.*|\S.*))* 960 \s*(?P<next_hop>next-hop\sprefix-list\s\S.*|next-hop\s\S.*)* 961 \s*(?P<route_source>route-source\sprefix-list\s\S.*|route-source\s\S.*)* 962 $""", 963 re.VERBOSE, 964 ), 965 "setval": _tmplt_route_map_match_ipv6, 966 "compval": "match", 967 "result": { 968 "{{ route_map }}": { 969 "{{ action|d() + '_' + sequence|d() }}": { 970 "entries": { 971 "match": { 972 "ipv6": { 973 "address": { 974 "acl": "{{ address.split('address ')[1] if address is defined and 'prefix-list' not in address }}", 975 "prefix_list": "{{ address.split('address prefix-list ')[1] if address is defined and 'prefix-list' in address }}", 976 }, 977 "flowspec": { 978 "dest_pfx": "{{ True if flowspec is defined and 'dest-pfx' in flowspec }}", 979 "src_pfx": "{{ True if flowspec is defined and 'src-pfx' in flowspec }}", 980 "acl": "{{ flowspec.split('flowspec ')[1] if flowspec is defined and 'prefix-list' not in flowspec }}", 981 "prefix_list": "{{ flowspec.split('flowspec prefix-list ')[1] if flowspec is defined and 'prefix-list' in flowspec }}", 982 }, 983 "next_hop": { 984 "acl": "{{ next_hop.split('next-hop ')[1] if next_hop is defined and 'prefix-list' not in next_hop }}", 985 "prefix_list": "{{ next_hop.split('next-hop prefix-list ')[1] if next_hop is defined and 'prefix-list' in next_hop }}", 986 }, 987 "route_source": { 988 "acl": "{{ route_source.split('route-source ')[1] if route_source is defined and 'prefix-list' not in route_source }}", 989 "prefix_list": "{{ route_source.split('route-source prefix-list ')[1] if route_source is defined and\ 990 'prefix-list' in route_source }}", 991 }, 992 } 993 } 994 } 995 } 996 } 997 }, 998 }, 999 { 1000 "name": "set", 1001 "getval": re.compile( 1002 r""" 1003 \s+set* 1004 \s*(?P<aigp_metric>aigp-metric\sigp-metric|aigp-metric\s\d+)* 1005 \s*(?P<as_path>as-path\s(prepend\s(last-as\s\d+|\S+)|tag))* 1006 \s*(?P<automatic_tag>automatic-tag)* 1007 \s*(?P<clns>clns\snext-hop\s\S.*)* 1008 \s*(?P<comm_list>comm-list\s\S+\sdelete)* 1009 \s*(?P<community>community\s\S.*)* 1010 \s*(?P<dampening>dampening\s\d+\s\d+\s\d+\s\d+)* 1011 \s*(?P<default>default\sinterface\s\S.*)* 1012 \s*(?P<extcomm_list>extcomm-list\s\S+\sdelete)* 1013 \s*(?P<extcommunity>extcommunity\s\S.*)* 1014 \s*(?P<global>global)* 1015 \s*(?P<interfaces>interface\s\S.*)* 1016 \s*(?P<level>level\s(level-1-2|level-1|level-2|nssa-only))* 1017 \s*(?P<lisp>lisp\slocator-set\s\S+)* 1018 \s*(?P<local_preference>local-preference\s\d+)* 1019 \s*(?P<metric>metric\s\S.*)* 1020 \s*(?P<metric_type>metric-type\s(external|internal|type-1|type-2))* 1021 \s*(?P<mpls_label>mpls-label)* 1022 \s*(?P<origin>origin\s(igp|incomplete))* 1023 \s*(?P<tag>tag\s(([0-9]{1,3}\.?){4}|\d+))* 1024 \s*(?P<traffic_index>traffic-index\s\d+)* 1025 \s*(?P<vrf>vrf\s\S+)* 1026 \s*(?P<weight>weight\s\d+)* 1027 $""", 1028 re.VERBOSE, 1029 ), 1030 "setval": _tmplt_route_map_set, 1031 "result": { 1032 "{{ route_map }}": { 1033 "{{ action|d() + '_' + sequence|d() }}": { 1034 "entries": { 1035 "set": { 1036 "aigp_metric": { 1037 "value": "{{ aigp_metric.split('aigp-metric ')[1] if aigp_metric is defined and\ 1038 'igp-metric' not in aigp_metric.split(' ') }}", 1039 "igp_metric": "{{ True if aigp_metric is defined and 'igp-metric' in aigp_metric.split(' ') }}", 1040 }, 1041 "as_path": { 1042 "prepend": { 1043 "as_number": "{{ as_path.split('as-path prepend ')[1].split(' ')\ 1044 if as_path is defined and 'prepend' in as_path and 'last-as' not in as_path }}", 1045 "last_as": "{{ as_path.split('as-path prepend last-as ')[1] if as_path is defined and 'prepend' in as_path and\ 1046 'last-as' in as_path }}", 1047 }, 1048 "tag": "{{ True if as_path is defined and 'tag' in as_path }}", 1049 }, 1050 "automatic_tag": "{{ True if automatic_tag is defined }}", 1051 "clns": "{{ clns.split('clns next-hop ')[1] if clns is defined }}", 1052 "comm_list": "{{ comm_list.split(' ')[1] if comm_list is defined }}", 1053 "community": { 1054 "number": "{{ community.split(' ')[1] if community is defined and 'additive' not in community.split(' ')\ 1055 and 'gshut' not in community.split(' ') and 'internet' not in community.split(' ')\ 1056 and 'internet' not in community.split(' ') and 'local_as' not in community.split(' ')\ 1057 and 'no_advertise' not in community.split(' ') and 'no_export' not in community.split(' ') }}", 1058 "additive": "{{ True if community is defined and 'additive' in community }}", 1059 "gshut": "{{ True if community is defined and 'gshut' in community }}", 1060 "internet": "{{ True if community is defined and 'internet' in community }}", 1061 "local_as": "{{ True if community is defined and 'local_as' in community }}", 1062 "no_advertise": "{{ True if community is defined and 'no_advertise' in community }}", 1063 "no_export": "{{ True if community is defined and 'no_export' in community }}", 1064 "none": "{{ True if community is defined and 'none' in community }}", 1065 }, 1066 "dampening": { 1067 "penalty_half_time": "{{ dampening.split(' ')[1] if dampening is defined }}", 1068 "reuse_route_val": "{{ dampening.split(' ')[2] if dampening is defined }}", 1069 "suppress_route_val": "{{ dampening.split(' ')[3] if dampening is defined }}", 1070 "max_suppress": "{{ dampening.split(' ')[4] if dampening is defined }}", 1071 }, 1072 "default": "{{ default.split('default interface ')[1] if default is defined }}", 1073 "extcomm_list": "{{ extcomm_list.split(' ')[1] if extcomm_list is defined }}", 1074 "extcommunity": { 1075 "cost": { 1076 "id": "{%- if extcommunity is defined and 'cost' in extcommunity and\ 1077 'igp' not in extcommunity and 'pre-bestpath' not in extcommunity -%} {{ extcommunity.split(' ')[2] }}\ 1078 {%- elif extcommunity is defined and 'cost' in extcommunity and ('igp' in extcommunity or\ 1079 'pre-bestpath' in extcommunity) -%} {{ extcommunity.split(' ')[3] }} {%- endif -%}", 1080 "cost_value": "{% if extcommunity is defined and 'cost' in extcommunity and 'igp' not in extcommunity and\ 1081 'pre-bestpath' not in extcommunity %} {{ extcommunity.split(' ')[3] }}\ 1082 {% elif extcommunity is defined and 'cost' in extcommunity and ('igp' in extcommunity or\ 1083 'pre-bestpath' in extcommunity) %} {{ extcommunity.split(' ')[4] }} {% endif %}", 1084 "igp": "{{ True if extcommunity is defined and 'cost' in extcommunity and 'igp' in extcommunity }}", 1085 "pre_bestpath": "{{ True if extcommunity is defined and 'cost' in extcommunity and 'pre-bestpath' in extcommunity }}", 1086 }, 1087 "rt": { 1088 "address": "{{ extcommunity.split(' ')[2] if extcommunity is defined and 'rt' in extcommunity and\ 1089 'range' not in extcommunity }}", 1090 "range": { 1091 "lower_limit": "{{ extcommunity.split('range ')[1].split(' ')[0] if extcommunity is defined and\ 1092 'rt' in extcommunity and 'range' in extcommunity }}", 1093 "upper_limit": "{{ extcommunity.split('range ')[1].split(' ')[1] if extcommunity is defined and\ 1094 'rt' in extcommunity and 'range' in extcommunity }}", 1095 }, 1096 "additive": "{{ True if extcommunity is defined and 'rt' in extcommunity and 'additive' in extcommunity }}", 1097 }, 1098 "soo": "{{ extcommunity.split(' ')[2] if extcommunity is defined and 'soo' in extcommunity }}", 1099 "vpn_distinguisher": { 1100 "address": "{{ extcommunity.split(' ')[2] if extcommunity is defined and\ 1101 'vpn-distinguisher' in extcommunity and 'range' not in extcommunity }}", 1102 "range": { 1103 "lower_limit": "{{ extcommunity.split('range ')[1].split(' ')[0] if extcommunity is defined and\ 1104 'vpn-distinguisher' in extcommunity and 'range' in extcommunity }}", 1105 "upper_limit": "{{ extcommunity.split('range ')[1].split(' ')[1] if extcommunity is defined and\ 1106 'vpn-distinguisher' in extcommunity and 'range' in extcommunity }}", 1107 }, 1108 "additive": "{{ True if extcommunity is defined and 'vpn-distinguisher' in extcommunity and\ 1109 'additive' in extcommunity }}", 1110 }, 1111 }, 1112 "global_route": "{{ True if global is defined }}", 1113 "interfaces": "{{ interfaces.split('interface ')[1].split(' ') if interfaces is defined }}", 1114 "level": { 1115 "level_1": "{{ True if level is defined and 'level-1' in level and 'level-1-2' not in level }}", 1116 "level_1_2": "{{ True if level is defined and 'level-1-2' in level }}", 1117 "level_2": "{{ True if level is defined and 'level-2' in level }}", 1118 "nssa_only": "{{ True if level is defined and 'nssa-only' in level }}", 1119 }, 1120 "lisp": "{{ lisp.split('lisp locator-set ')[1] if lisp is defined }}", 1121 "local_preference": "{{ local_preference.split('local-preference ')[1] if local_preference is defined }}", 1122 "metric": { 1123 "deviation": "{%- if metric is defined and '+' in metric -%}{{ 'plus' }}\ 1124 {%- elif metric is defined and '-' in metric -%}{{ 'minus' }}{%- endif -%}", 1125 "metric_value": "{{ metric.split(' ')[1] if metric is defined and\ 1126 (metric.split(' ')[1] != '+' or metric.split(' ')[1] != '-') }}", 1127 "eigrp_delay": "{% if metric is defined and metric.split(' ')|length > 2 and '+' in metric %}\ 1128 {{ metric.split('+')[1].split(' ')[0] }}\ 1129 {% elif metric is defined and metric.split(' ')|length > 2 and '+' in metric %}\ 1130 {{ metric.split('-')[1].split(' ')[0] }}\ 1131 {% endif %}", 1132 "metric_reliability": "{% if metric is defined and metric.split(' ')|length > 2 and '+' in metric %}\ 1133 {{ metric.split('+')[1].split(' ')[1] }}\ 1134 {% elif metric is defined and metric.split(' ')|length > 2 and '+' in metric %}\ 1135 {{ metric.split('-')[1].split(' ')[1] }}\ 1136 {% endif %}", 1137 "metric_bandwidth": "{% if metric is defined and metric.split(' ')|length > 2 and '+' in metric %}\ 1138 {{ metric.split('+')[1].split(' ')[2] }}\ 1139 {% elif metric is defined and metric.split(' ')|length > 2 and '+' in metric %}\ 1140 {{ metric.split('-')[1].split(' ')[2] }}\ 1141 {% endif %}", 1142 "mtu": "{% if metric is defined and metric.split(' ')|length > 2 and '+' in metric %}\ 1143 {{ metric.split('+')[1].split(' ')[3] }}\ 1144 {% elif metric is defined and metric.split(' ')|length > 2 and '+' in metric %}\ 1145 {{ metric.split('-')[1].split(' ')[3] }}\ 1146 {% endif %}", 1147 }, 1148 "metric_type": { 1149 "external": "{{ True if metric_type is defined and 'external' in metric_type }}", 1150 "internal": "{{ True if metric_type is defined and 'internal' in metric_type }}", 1151 "type_1": "{{ True if metric_type is defined and 'type-1' in metric_type }}", 1152 "type_2": "{{ True if metric_type is defined and 'type-2' in metric_type }}", 1153 }, 1154 "mpls_label": "{{ True if mpls_label is defined }}", 1155 "origin": { 1156 "igp": "{{ True if origin is defined and 'igp' in origin }}", 1157 "incomplete": "{{ True if origin is defined and 'incomplete' in origin }}", 1158 }, 1159 "tag": "{{ tag.split('tag ')[1] if tag is defined }}", 1160 "traffic_index": "{{ traffic_index.split('traffic-index ')[1] if traffic_index is defined }}", 1161 "vrf": "{{ vrf.split('vrf ')[1] if vrf is defined }}", 1162 "weight": "{{ weight.split('weight ')[1] if weight is defined }}", 1163 } 1164 } 1165 } 1166 } 1167 }, 1168 }, 1169 { 1170 "name": "set.ip", 1171 "getval": re.compile( 1172 r""" 1173 \s+set* 1174 \s*(?P<ip>ip)* 1175 \s*(?P<address>address\sprefix-list\s\S+)* 1176 \s*(?P<default>default)* 1177 \s*(?P<df>df\s\d)* 1178 \s*(?P<global>global\snext-hop\s(verify-availability\s([0-9]{1,3}\.?){4}\s\d+\strack\s\d+|(([0-9]{1,3}\.?){4}).*))* 1179 \s*(?P<precedence>precedence\s(critical|flash|flash-override|immediate|internet|network|priority|routine)|precedence)* 1180 \s*(?P<qos_group>qos_group\s\d+)* 1181 \s*(?P<tos>tos\s(max-reliability|max-throughput|min-delay|min-monetary-cost|normal)|tos)* 1182 \s*(?P<vrf>vrf\s\S+\snext-hop\s\S.*)* 1183 \s*(?P<next_hop>next-hop\s\S.*)* 1184 $""", 1185 re.VERBOSE, 1186 ), 1187 "setval": _tmplt_route_map_set_ip, 1188 "compval": "set", 1189 "result": { 1190 "{{ route_map }}": { 1191 "{{ action|d() + '_' + sequence|d() }}": { 1192 "entries": { 1193 "set": { 1194 "ip": { 1195 "address": "{{ address.split('address prefix-list ')[1] if address is defined }}", 1196 "default": "{{ True if default is defined }}", 1197 "df": "{{ df.split('df ')[1] if df is defined }}", 1198 "global_route": { 1199 "address": "{% if global is defined and 'verify-availability' not in global %}{{ global.split('global next-hop ')[1] }}\ 1200 {% elif global is defined and 'verify-availability' in global %}{{ global.split(' ')[3] }}{% endif %}", 1201 "verify_availability": { 1202 "address": "{{ global.split(' ')[3] if global is defined and 'verify-availability' in global }}", 1203 "sequence": "{{ global.split(' ')[4] if global is defined and 'verify-availability' in global }}", 1204 "track": "{{ global.split('track ')[1] if global is defined and 'verify-availability' in global }}", 1205 }, 1206 }, 1207 "next_hop": { 1208 "address": "{{ next_hop.split('next-hop ')[1] if next_hop is defined and 'peer-address' not in next_hop and\ 1209 'self' not in next_hop and next_hop.split(' ')|length == 2 }}", 1210 "dynamic": "{{ True if next_hop is defined and 'dynamic dhcp' in next_hop }}", 1211 "encapsulate": "{{ next_hop.split('next-hop encapsulate l3vpn ')[1] if next_hop is defined and\ 1212 'encapsulate' in next_hop }}", 1213 "peer_address": "{{ True if next_hop is defined and 'peer-address' in next_hop }}", 1214 "recursive": { 1215 "global_route": "{{ True if next_hop is defined and 'global' in next_hop.split(' ') }}", 1216 "vrf": "{{ next_hop.split(' ')[3] if next_hop is defined and 'vrf' in next_hop }}", 1217 "address": "{%- if next_hop is defined and 'global' in next_hop.split(' ') -%}\ 1218 {{ next_hop.split('next-hop recursive global ')[1] }}\ 1219 {%- elif next_hop is defined and 'vrf' in next_hop.split(' ') -%}{{ next_hop.split(' ')[4] }}\ 1220 {%- elif next_hop is defined and 'vrf' not in next_hop.split(' ') and 'global' not in next_hop.split(' ') -%}\ 1221 {{ next_hop.split(' ')[2] }} {%- endif -%}", 1222 }, 1223 "self": "{{ True if next_hop is defined and 'self' in next_hop }}", 1224 "verify_availability": { 1225 "set": "{{ True if next_hop is defined and 'verify-availability' in next_hop and 'track' not in next_hop }}", 1226 "address": "{{ next_hop.split(' ')[2] if next_hop is defined and 'verify-availability' in next_hop and\ 1227 'track' in next_hop }}", 1228 "sequence": "{{ next_hop.split(' ')[3] if next_hop is defined and 'verify-availability' in next_hop and\ 1229 'track' in next_hop }}", 1230 "track": "{{ next_hop.split('track ')[1] if next_hop is defined and 'verify-availability' in next_hop and\ 1231 'track' in next_hop }}", 1232 }, 1233 }, 1234 "precedence": { 1235 "set": "{{ True if precedence is defined and precedence.split(' ')|length == 1 }}", 1236 "critical": "{{ True if precedence is defined and 'critical' in precedence }}", 1237 "flash": "{{ True if precedence is defined and 'flash' in precedence }}", 1238 "flash_override": "{{ True if precedence is defined and 'flash-override' in precedence }}", 1239 "immediate": "{{ True if precedence is defined and 'immediate' in precedence }}", 1240 "internet": "{{ True if precedence is defined and 'internet' in precedence }}", 1241 "network": "{{ True if precedence is defined and 'network' in precedence }}", 1242 "priority": "{{ True if precedence is defined and 'priority' in precedence }}", 1243 "routine": "{{ True if precedence is defined and 'routine' in precedence }}", 1244 }, 1245 "qos_group": "{{ qos_group.split('qos-group ')[1] if qos_group is defined }}", 1246 "tos": { 1247 "set": "{{ True if tos is defined and tos.split(' ')|length == 1 }}", 1248 "max_reliability": "{{ True if tos is defined and 'max-reliability' in tos }}", 1249 "max_throughput": "{{ True if tos is defined and 'max-throughput' in tos }}", 1250 "min_delay": "{{ True if tos is defined and 'min-delay' in tos }}", 1251 "min_monetary_cost": "{{ True if tos is defined and 'min-monetary-cost' in tos }}", 1252 "normal": "{{ True if tos is defined and 'normal' in tos }}", 1253 }, 1254 "vrf": { 1255 "name": "{{ vrf.split(' ')[1] if vrf is defined }}", 1256 "address": "{{ vrf.split('next-hop ')[1] if vrf is defined and 'verify-availability' not in vrf }}", 1257 "verify_availability": { 1258 "set": "{{ True if vrf is defined and 'track' not in vrf }}", 1259 "address": "{{ vrf.split(' ')[4] if vrf is defined and 'track' in vrf }}", 1260 "sequence": "{{ vrf.split(' ')[5] if vrf is defined and 'track' in vrf }}", 1261 "track": "{{ vrf.split('track ')[1] if vrf is defined and 'track' in vrf }}", 1262 }, 1263 }, 1264 } 1265 } 1266 } 1267 } 1268 } 1269 }, 1270 }, 1271 { 1272 "name": "set.ipv6", 1273 "getval": re.compile( 1274 r""" 1275 \s+set* 1276 \s*(?P<ipv6>ipv6)* 1277 \s*(?P<address>address\sprefix-list\s\S+)* 1278 \s*(?P<default>default\snext-hop\s(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\S+)* 1279 \s*(?P<global>global\snext-hop\sverify-availability\s(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\S+\s\d+\strack\s\d+)* 1280 \s*(?P<precedence>precedence\s\d+)* 1281 \s*(?P<vrf>vrf\s\S+\snext-hop\sverify-availability\s(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\S+\s\d+\strack\s\d+)* 1282 \s*(?P<next_hop>next-hop\s\S.*)* 1283 $""", 1284 re.VERBOSE, 1285 ), 1286 "setval": _tmplt_route_map_set_ipv6, 1287 "compval": "set", 1288 "result": { 1289 "{{ route_map }}": { 1290 "{{ action|d() + '_' + sequence|d() }}": { 1291 "entries": { 1292 "set": { 1293 "ipv6": { 1294 "address": "{{ address.split('address prefix-list ')[1] if address is defined }}", 1295 "default": "{{ default.split('default next-hop ')[1] if default is defined }}", 1296 "global_route": { 1297 "verify_availability": { 1298 "address": "{{ global.split(' ')[3] if global is defined and 'verify-availability' in global }}", 1299 "sequence": "{{ global.split(' ')[4] if global is defined and 'verify-availability' in global }}", 1300 "track": "{{ global.split('track ')[1] if global is defined and 'verify-availability' in global }}", 1301 }, 1302 "address": "{{ global.split(' ')[2] if global is defined and 'verify-availability' not in global }}", 1303 }, 1304 "next_hop": { 1305 "address": "{{ next_hop.split('next-hop ')[1] if next_hop is defined and\ 1306 next_hop.split(' ')|length == 2 and 'peer-address' not in next_hop }}", 1307 "encapsulate": "{{ next_hop.split('next-hop encapsulate l3vpn ')[1] if next_hop is defined and\ 1308 'encapsulate' in next_hop}}", 1309 "peer_address": "{{ True if next_hop is defined and next_hop.split(' ')|length == 2 and 'peer-address' in next_hop }}", 1310 "recursive": "{{ next_hop.split('next-hop recursive ')[1] if next_hop is defined }}", 1311 }, 1312 "precedence": "{{ precedence.split(' ')[1] if precedence is defined }}", 1313 "vrf": { 1314 "name": "{{ vrf.split(' ')[1] if vrf is defined }}", 1315 "verify_availability": { 1316 "address": "{{ vrf.split(' ')[4] if vrf is defined and 'verify-availability' in vrf }}", 1317 "sequence": "{{ vrf.split(' ')[5] if vrf is defined and 'verify-availability' in vrf }}", 1318 "track": "{{ vrf.split('track ')[1] if vrf is defined and 'verify-availability' in vrf }}", 1319 }, 1320 }, 1321 } 1322 } 1323 } 1324 } 1325 } 1326 }, 1327 }, 1328 ] 1329