annet 3.4.0__py3-none-any.whl → 3.4.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of annet might be problematic. Click here for more details.

Files changed (50) hide show
  1. annet/__init__.py +1 -1
  2. annet/adapters/netbox/common/models.py +13 -5
  3. annet/annlib/filter_acl.py +2 -1
  4. annet/annlib/patching.py +1 -1
  5. annet/annlib/rbparser/syntax.py +2 -1
  6. annet/api/__init__.py +2 -3
  7. annet/bgp_models.py +9 -1
  8. annet/diff.py +2 -2
  9. annet/gen.py +2 -1
  10. annet/generators/__init__.py +11 -7
  11. annet/generators/base.py +2 -1
  12. annet/mesh/device_models.py +6 -0
  13. annet/mesh/executor.py +8 -16
  14. annet/mesh/models_converter.py +1 -1
  15. annet/mesh/peer_models.py +1 -5
  16. annet/parallel.py +0 -6
  17. annet/rpl/match_builder.py +1 -1
  18. annet/rpl_generators/aspath.py +16 -0
  19. annet/rpl_generators/community.py +37 -3
  20. annet/rpl_generators/policy.py +340 -5
  21. annet/rpl_generators/prefix_lists.py +51 -1
  22. annet/rpl_generators/rd.py +16 -0
  23. annet/rulebook/juniper/__init__.py +1 -1
  24. annet/rulebook/texts/cisco.order +2 -0
  25. annet/rulebook/texts/iosxr.order +21 -4
  26. annet/vendors/base.py +1 -1
  27. annet/vendors/library/arista.py +1 -1
  28. annet/vendors/library/aruba.py +1 -1
  29. annet/vendors/library/b4com.py +1 -1
  30. annet/vendors/library/cisco.py +1 -1
  31. annet/vendors/library/h3c.py +1 -1
  32. annet/vendors/library/huawei.py +1 -1
  33. annet/vendors/library/iosxr.py +1 -1
  34. annet/vendors/library/juniper.py +1 -1
  35. annet/vendors/library/nexus.py +1 -1
  36. annet/vendors/library/nokia.py +1 -1
  37. annet/vendors/library/optixtrans.py +1 -1
  38. annet/vendors/library/pc.py +1 -1
  39. annet/vendors/library/ribbon.py +1 -1
  40. annet/vendors/library/routeros.py +1 -1
  41. annet/vendors/registry.py +1 -1
  42. annet/{annlib → vendors}/tabparser.py +3 -3
  43. {annet-3.4.0.dist-info → annet-3.4.2.dist-info}/METADATA +1 -1
  44. {annet-3.4.0.dist-info → annet-3.4.2.dist-info}/RECORD +50 -50
  45. {annet-3.4.0.dist-info → annet-3.4.2.dist-info}/WHEEL +1 -1
  46. annet_generators/rpl_example/items.py +13 -5
  47. {annet-3.4.0.dist-info → annet-3.4.2.dist-info}/entry_points.txt +0 -0
  48. {annet-3.4.0.dist-info → annet-3.4.2.dist-info}/licenses/AUTHORS +0 -0
  49. {annet-3.4.0.dist-info → annet-3.4.2.dist-info}/licenses/LICENSE +0 -0
  50. {annet-3.4.0.dist-info → annet-3.4.2.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,12 @@
1
1
  from abc import ABC, abstractmethod
2
- from collections.abc import Iterator, Sequence
2
+ from collections.abc import Iterator, Sequence, Iterable
3
3
  from typing import Any, cast, Literal
4
4
 
5
5
  from annet.generators import PartialGenerator
6
6
  from annet.rpl import (
7
7
  CommunityActionValue,
8
8
  ResultType, RoutingPolicyStatement, RoutingPolicy, ConditionOperator, SingleCondition, SingleAction, ActionType,
9
- MatchField,
9
+ MatchField, PrefixMatchValue,
10
10
  )
11
11
  from annet.rpl.statement_builder import AsPathActionValue, NextHopActionValue, ThenField
12
12
  from annet.rpl_generators.entities import (
@@ -15,7 +15,6 @@ from annet.rpl_generators.entities import (
15
15
  IpPrefixList, group_community_members, CommunityType,
16
16
  )
17
17
 
18
-
19
18
  HUAWEI_MATCH_COMMAND_MAP: dict[str, str] = {
20
19
  MatchField.as_path_filter: "as-path-filter {option_value}",
21
20
  MatchField.metric: "cost {option_value}",
@@ -58,6 +57,28 @@ ARISTA_THEN_COMMAND_MAP: dict[str, str] = {
58
57
  # unsupported: resolution
59
58
  # unsupported: rpki_valid_state
60
59
  }
60
+ IOSXR_MATCH_COMMAND_MAP: dict[str, str] = {
61
+ MatchField.as_path_filter: "as-path in {option_value}",
62
+ MatchField.protocol: "protocol is {option_value}",
63
+ # unsupported: interface
64
+ # unsupported: metric
65
+ # unsupported: large-community
66
+ }
67
+ IOSXR_THEN_COMMAND_MAP: dict[str, str] = {
68
+ ThenField.local_pref: "local-preference {option_value}",
69
+ ThenField.origin: "origin {option_value}",
70
+ ThenField.tag: "tag {option_value}",
71
+ ThenField.metric_type: "metric-type {option_value}",
72
+ # unsupported: mpls_label # label?
73
+ # unsupported: resolution
74
+ # unsupported: rpki_valid_state
75
+ # unsupported: large_community
76
+ }
77
+ IOSXR_RESULT_MAP = {
78
+ ResultType.ALLOW: "done",
79
+ ResultType.DENY: "drop",
80
+ ResultType.NEXT: "pass"
81
+ }
61
82
 
62
83
 
63
84
  class RoutingPolicyGenerator(PartialGenerator, ABC):
@@ -408,7 +429,8 @@ class RoutingPolicyGenerator(PartialGenerator, ABC):
408
429
 
409
430
  for policy in self.get_policies(device):
410
431
  for statement in policy.statements:
411
- yield from self._huawei_statement(communities, rd_filters, device, policy, statement, prefix_name_generator)
432
+ yield from self._huawei_statement(communities, rd_filters, device, policy, statement,
433
+ prefix_name_generator)
412
434
 
413
435
  # arista
414
436
  def acl_arista(self, device):
@@ -564,7 +586,7 @@ class RoutingPolicyGenerator(PartialGenerator, ABC):
564
586
  else:
565
587
  yield "set", "large-community large-community-list", community_name, "additive"
566
588
  if action.value.added:
567
- yield "set", "large-community large-community-list", *action.value.added, "additive"
589
+ yield "set", "large-community large-community-list", *action.value.added, "additive"
568
590
  if action.value.removed:
569
591
  yield "set large-community large-community-list", *action.value.removed, "delete"
570
592
 
@@ -764,6 +786,8 @@ class RoutingPolicyGenerator(PartialGenerator, ABC):
764
786
  statement: RoutingPolicyStatement,
765
787
  prefix_name_generator: PrefixListNameGenerator,
766
788
  ) -> Iterator[Sequence[str]]:
789
+ if statement.number is None:
790
+ raise RuntimeError(f"Statement number should not be empty on Arista (found for policy: {policy.name})")
767
791
  with self.block(
768
792
  "route-map",
769
793
  policy.name,
@@ -789,3 +813,314 @@ class RoutingPolicyGenerator(PartialGenerator, ABC):
789
813
  yield from self._arista_statement(
790
814
  communities, rd_filters, device, policy, statement, prefix_name_generator,
791
815
  )
816
+
817
+ # Cisco IOS XR
818
+ def acl_iosxr(self, device):
819
+ return r"""
820
+ route-policy *
821
+ ~ %global=1
822
+ """
823
+
824
+ def _iosxr_match_community(
825
+ self,
826
+ community_type: Literal["community", "extcommunity rt", "extcommunity soo"],
827
+ community: CommunityList,
828
+ ) -> Iterator[Sequence[str]]:
829
+ if community.logic is CommunityLogic.AND:
830
+ yield community_type, "matches-every", community.name
831
+ elif community.logic is CommunityLogic.OR:
832
+ yield community_type, "matches-any", community.name
833
+ else:
834
+ raise ValueError(f"Unknown community logic {community.logic}")
835
+
836
+ def _iosxr_match_communities(
837
+ self,
838
+ operator: ConditionOperator,
839
+ community_type: Literal["community", "extcommunity rt", "extcommunity soo"],
840
+ community_names: list[str],
841
+ communities: dict[str, CommunityList],
842
+ ) -> Iterator[Sequence[str]]:
843
+ if operator == ConditionOperator.HAS_ANY:
844
+ yield self._iosxr_or_matches(
845
+ self._iosxr_match_community(community_type, communities[name])
846
+ for name in community_names
847
+ ),
848
+ elif operator == ConditionOperator.HAS:
849
+ for name in community_names:
850
+ yield from self._iosxr_match_community(community_type, communities[name])
851
+ else:
852
+ raise NotImplementedError(f"Operator {operator} is not supported for {community_type} on Cisco IOS XR")
853
+
854
+ def _iosxr_match_rd(
855
+ self,
856
+ condition: SingleCondition[Sequence[str]],
857
+ rd_filters: dict[str, RDFilter],
858
+ ) -> Iterator[Sequence[str]]:
859
+ if condition.operator == ConditionOperator.HAS_ANY:
860
+ if len(condition.value) == 1:
861
+ yield "rd", "in", condition.value[0]
862
+ return
863
+ conds = " or ".join(f"rd in {name}" for name in condition.value)
864
+ yield f"({conds})",
865
+ return
866
+ elif condition.operator == ConditionOperator.HAS:
867
+ for name in condition.value:
868
+ yield "rd", "in", name
869
+ else:
870
+ raise NotImplementedError(f"Operator {condition.operator} is not supported for {condition.field} on Cisco IOS XR")
871
+
872
+ def _iosxr_match_prefix_lists(
873
+ self,
874
+ condition: SingleCondition[PrefixMatchValue],
875
+ name_generator: PrefixListNameGenerator
876
+ ) -> Iterator[Sequence[str]]:
877
+ matches = []
878
+ for name in condition.value.names:
879
+ plist = name_generator.get_prefix(name, condition.value)
880
+ matches.append(("destination in", plist.name))
881
+ if len(matches) == 1:
882
+ yield matches[0]
883
+ else:
884
+ yield self._iosxr_or_matches([matches]),
885
+
886
+ def _iosxr_match_local_pref(self, condition: SingleCondition) -> Iterator[Sequence[str]]:
887
+ if condition.operator is ConditionOperator.EQ:
888
+ yield "local-preference", "eq", str(condition.value)
889
+ elif condition.operator is ConditionOperator.LE:
890
+ yield "local-preference", "le", str(condition.value)
891
+ elif condition.operator is ConditionOperator.GE:
892
+ yield "local-preference", "ge", str(condition.value)
893
+ elif condition.operator is ConditionOperator.BETWEEN_INCLUDED:
894
+ yield "local-preference", "ge", str(condition.value[0])
895
+ yield "local-preference", "le", str(condition.value[1])
896
+ else:
897
+ raise NotImplementedError(
898
+ f"Operator {condition.operator} is not supported for {condition.field} on Cisco IOS XR",
899
+ )
900
+
901
+ def _iosxr_match_as_path_length(self, condition: SingleCondition) -> Iterator[Sequence[str]]:
902
+ if condition.operator is ConditionOperator.EQ:
903
+ yield "as-path length", "eq", str(condition.value)
904
+ elif condition.operator is ConditionOperator.LE:
905
+ yield "as-path length", "le", str(condition.value)
906
+ elif condition.operator is ConditionOperator.GE:
907
+ yield "as-path length", "ge", str(condition.value)
908
+ elif condition.operator is ConditionOperator.BETWEEN_INCLUDED:
909
+ yield "as-path length", "ge", str(condition.value[0])
910
+ yield "as-path length", "le", str(condition.value[1])
911
+ else:
912
+ raise NotImplementedError(
913
+ f"Operator {condition.operator} is not supported for {condition.field} on Cisco IOS XR",
914
+ )
915
+
916
+ def _iosxr_and_matches(self, conditions: Iterable[Iterable[Sequence[str]]]) -> str:
917
+ return " and ".join(" ".join(c) for seq in conditions for c in seq)
918
+
919
+ def _iosxr_or_matches(self, conditions: Iterable[Iterable[Sequence[str]]]) -> str:
920
+ return "(" + " or ".join(" ".join(c) for seq in conditions for c in seq) + ")"
921
+
922
+ def _iosxr_match(
923
+ self,
924
+ device: Any,
925
+ condition: SingleCondition[Any],
926
+ communities: dict[str, CommunityList],
927
+ rd_filters: dict[str, RDFilter],
928
+ name_generator: PrefixListNameGenerator,
929
+ ) -> Iterator[Sequence[str]]:
930
+ if condition.field == MatchField.community:
931
+ yield from self._iosxr_match_communities(condition.operator, "community", condition.value, communities)
932
+ return
933
+ elif condition.field == MatchField.extcommunity_rt:
934
+ yield from self._iosxr_match_communities(condition.operator, "extcommunity rt", condition.value, communities)
935
+ return
936
+ elif condition.field == MatchField.extcommunity_soo:
937
+ yield from self._iosxr_match_communities(condition.operator, "extcommunity soo", condition.value, communities)
938
+ return
939
+ elif condition.field == MatchField.local_pref:
940
+ yield from self._iosxr_match_local_pref(condition)
941
+ return
942
+ elif condition.field == MatchField.as_path_length:
943
+ yield from self._iosxr_match_as_path_length(condition)
944
+ return
945
+ elif condition.field == MatchField.rd:
946
+ yield from self._iosxr_match_rd(condition, rd_filters)
947
+ return
948
+ elif condition.field == MatchField.ip_prefix:
949
+ yield from self._iosxr_match_prefix_lists(condition, name_generator)
950
+ return
951
+ elif condition.field == MatchField.ipv6_prefix:
952
+ yield from self._iosxr_match_prefix_lists(condition, name_generator)
953
+ return
954
+
955
+ if condition.operator is not ConditionOperator.EQ:
956
+ raise NotImplementedError(
957
+ f"`{condition.field}` with operator {condition.operator} is not supported for Cisco IOS XR",
958
+ )
959
+ if condition.field not in IOSXR_MATCH_COMMAND_MAP:
960
+ raise NotImplementedError(f"Match using `{condition.field}` is not supported for Cisco IOS XR")
961
+ yield IOSXR_MATCH_COMMAND_MAP[condition.field].format(option_value=condition.value),
962
+
963
+ def _iosxr_then_as_path(
964
+ self,
965
+ device: Any,
966
+ action: SingleAction[AsPathActionValue],
967
+ ) -> Iterator[Sequence[str]]:
968
+ if action.value.set is not None:
969
+ raise RuntimeError("as_path.set is not supported for Cisco IOS XR")
970
+ if action.value.prepend:
971
+ for asn in action.value.prepend:
972
+ yield "prepend as-path", asn
973
+ if action.value.expand:
974
+ raise RuntimeError("as_path.expand is not supported for Cisco IOS XR")
975
+ if action.value.delete:
976
+ raise RuntimeError("as_path.delete is not supported for Cisco IOS XR")
977
+ if action.value.expand_last_as:
978
+ raise RuntimeError("as_path.expand_last_as is not supported for Cisco IOS XR")
979
+
980
+ def _iosxr_then_next_hop(
981
+ self,
982
+ device: Any,
983
+ action: SingleAction[NextHopActionValue],
984
+ ) -> Iterator[Sequence[str]]:
985
+ if action.value.target == "self":
986
+ yield "set", "next-hop", "self"
987
+ elif action.value.target == "discard":
988
+ yield "set", "next-hop", "discard"
989
+ elif action.value.target == "peer":
990
+ pass
991
+ elif action.value.target == "ipv4_addr":
992
+ yield "set", "next-hop", action.value.addr
993
+ elif action.value.target == "ipv6_addr":
994
+ yield "set", "next-hop", action.value.addr.lower()
995
+ elif action.value.target == "mapped_ipv4":
996
+ yield "set", "next-hop", f"::ffff:{action.value.addr}"
997
+ else:
998
+ raise RuntimeError(f"Next_hop target {action.value.target} is not supported for Cisco IOS XR")
999
+
1000
+ def _iosxr_then_metric(
1001
+ self,
1002
+ device: Any,
1003
+ action: SingleAction[NextHopActionValue],
1004
+ ) -> Iterator[Sequence[str]]:
1005
+ if action.type is ActionType.ADD:
1006
+ yield "set", f"med +{action.value}"
1007
+ elif action.type is ActionType.REMOVE:
1008
+ yield "set", f"med -{action.value}"
1009
+ elif action.type is ActionType.SET:
1010
+ yield "set", f"med {action.value}"
1011
+ else:
1012
+ raise NotImplementedError(f"Action type {action.type} for metric is not supported for Cisco IOS XR")
1013
+
1014
+ def _iosxr_then_community(
1015
+ self,
1016
+ communities: dict[str, CommunityList],
1017
+ device: Any,
1018
+ action: SingleAction[CommunityActionValue],
1019
+ ) -> Iterator[Sequence[str]]:
1020
+ added = []
1021
+ if action.value.replaced is not None:
1022
+ yield "delete", "community", "all"
1023
+ added.extend(action.value.replaced)
1024
+ added.extend(action.value.added)
1025
+ for name in added:
1026
+ yield "set", "community", name, "additive"
1027
+ for community_name in action.value.removed:
1028
+ yield "delete", "community", "in", community_name
1029
+
1030
+ def _iosxr_community_type_str(self, comm_type: CommunityType) -> str:
1031
+ if comm_type is CommunityType.RT:
1032
+ return "rt"
1033
+ elif comm_type is CommunityType.LARGE:
1034
+ raise ValueError("Large community is not subtype of extcommunity")
1035
+ elif comm_type is CommunityType.BASIC:
1036
+ raise ValueError("Basic community is not subtype of extcommunity")
1037
+ else:
1038
+ raise NotImplementedError(f"Community type {comm_type} is not supported on Cisco IOS XR")
1039
+
1040
+ def _iosxr_then_extcommunity(
1041
+ self,
1042
+ communities: dict[str, CommunityList],
1043
+ device: Any,
1044
+ action: SingleAction[CommunityActionValue],
1045
+ ) -> Iterator[Sequence[str]]:
1046
+ added = []
1047
+ if action.value.replaced is not None:
1048
+ yield "delete", "extcommunity", "rt", "all"
1049
+ added.extend(action.value.replaced)
1050
+
1051
+ added.extend(action.value.replaced)
1052
+ for member_name in added:
1053
+ typename = self._iosxr_community_type_str(communities[member_name].type)
1054
+ yield "set", "extcommunity", typename, member_name, "additive"
1055
+ for member_name in action.value.removed:
1056
+ typename = self._iosxr_community_type_str(communities[member_name].type)
1057
+ yield "delete", "extcommunity", typename, "in", member_name
1058
+
1059
+ def _iosxr_then(
1060
+ self,
1061
+ communities: dict[str, CommunityList],
1062
+ device: Any,
1063
+ action: SingleAction[Any],
1064
+ ) -> Iterator[Sequence[str]]:
1065
+ if action.field == ThenField.community:
1066
+ yield from self._iosxr_then_community(communities, device, action)
1067
+ return
1068
+ if action.field == ThenField.extcommunity:
1069
+ yield from self._iosxr_then_extcommunity(communities, device, action)
1070
+ return
1071
+ if action.field == ThenField.metric:
1072
+ yield from self._iosxr_then_metric(device, action)
1073
+ return
1074
+ if action.field == ThenField.as_path:
1075
+ yield from self._iosxr_then_as_path(device, cast(SingleAction[AsPathActionValue], action))
1076
+ return
1077
+ if action.field == ThenField.next_hop:
1078
+ yield from self._iosxr_then_next_hop(device, cast(SingleAction[NextHopActionValue], action))
1079
+ return
1080
+ if action.type is not ActionType.SET:
1081
+ raise NotImplementedError(f"Action type {action.type} for `{action.field}` is not supported for Cisco IOS XR")
1082
+ if action.field not in IOSXR_THEN_COMMAND_MAP:
1083
+ raise NotImplementedError(f"Then action using `{action.field}` is not supported for Cisco IOS XR")
1084
+ cmd = IOSXR_THEN_COMMAND_MAP[action.field]
1085
+ yield "set", cmd.format(option_value=action.value)
1086
+
1087
+ def _iosxr_statement(
1088
+ self,
1089
+ communities: dict[str, CommunityList],
1090
+ rd_filters: dict[str, RDFilter],
1091
+ device: Any,
1092
+ policy: RoutingPolicy,
1093
+ statement: RoutingPolicyStatement,
1094
+ prefix_name_generator: PrefixListNameGenerator,
1095
+ ) -> Iterator[Sequence[str]]:
1096
+ if statement.match:
1097
+ condition_expr = self._iosxr_and_matches(
1098
+ self._iosxr_match(device, condition, communities, rd_filters, prefix_name_generator)
1099
+ for condition in statement.match
1100
+ )
1101
+ with self.block(
1102
+ "if", condition_expr, "then",
1103
+ ):
1104
+ for action in statement.then:
1105
+ yield from self._iosxr_then(communities, device, action)
1106
+ yield IOSXR_RESULT_MAP[statement.result],
1107
+ else:
1108
+ for action in statement.then:
1109
+ yield from self._iosxr_then(communities, device, action)
1110
+ yield IOSXR_RESULT_MAP[statement.result],
1111
+
1112
+ def run_iosxr(self, device):
1113
+ prefix_lists = self.get_prefix_lists(device)
1114
+ policies = self.get_policies(device)
1115
+ prefix_name_generator = PrefixListNameGenerator(prefix_lists, policies)
1116
+ communities = {c.name: c for c in self.get_community_lists(device)}
1117
+ rd_filters = {f.name: f for f in self.get_rd_filters(device)}
1118
+
1119
+ for policy in policies:
1120
+ with self.block(
1121
+ "route-policy", policy.name,
1122
+ ):
1123
+ for statement in policy.statements:
1124
+ yield from self._iosxr_statement(
1125
+ communities, rd_filters, device, policy, statement, prefix_name_generator,
1126
+ )
@@ -1,6 +1,5 @@
1
1
  from abc import ABC, abstractmethod
2
2
  from collections.abc import Sequence, Iterable
3
- from ipaddress import ip_interface
4
3
  from typing import Any, Literal
5
4
 
6
5
  from annet.generators import PartialGenerator
@@ -120,3 +119,54 @@ class PrefixListFilterGenerator(PartialGenerator, ABC):
120
119
  continue
121
120
  yield from self._arista_prefix_list("ipv6", plist)
122
121
  processed_names.add(plist.name)
122
+
123
+ # Cisco IOS XR
124
+ def acl_iosxr(self, device: Any):
125
+ return r"""
126
+ prefix-set
127
+ ~ %global=1
128
+ """
129
+
130
+ def _iosxr_prefixlist(self, prefixlist: IpPrefixList):
131
+ with self.block("prefix-set", prefixlist.name):
132
+ for n, member in enumerate(prefixlist.members):
133
+ if n + 1 < len(prefixlist.members):
134
+ comma = ","
135
+ else:
136
+ comma = ""
137
+
138
+ ge, le = member.or_longer
139
+ if ge is le is None:
140
+ yield f"{member.prefix}{comma}",
141
+ elif ge is None:
142
+ yield f"{member.prefix} le {le}{comma}",
143
+ elif le is None:
144
+ yield f"{member.prefix} ge {ge}{comma}",
145
+ elif ge == le:
146
+ yield f"{member.prefix} eq {ge}{comma}",
147
+ else:
148
+ yield f"{member.prefix} ge {ge} le {le}{comma}",
149
+
150
+ def run_iosxr(self, device: Any):
151
+ prefix_lists = self.get_prefix_lists(device)
152
+ policies = self.get_policies(device)
153
+
154
+ name_generator = PrefixListNameGenerator(prefix_lists, policies)
155
+ processed_names = set()
156
+ for policy in policies:
157
+ for statement in policy.statements:
158
+ cond: SingleCondition[PrefixMatchValue]
159
+ for cond in statement.match.find_all(MatchField.ip_prefix):
160
+ for name in cond.value.names:
161
+ plist = name_generator.get_prefix(name, cond.value)
162
+ if plist.name in processed_names:
163
+ continue
164
+ yield from self._iosxr_prefixlist(plist)
165
+ processed_names.add(plist.name)
166
+ for cond in statement.match.find_all(MatchField.ipv6_prefix):
167
+ for name in cond.value.names:
168
+ plist = name_generator.get_prefix(name, cond.value)
169
+ if plist.name in processed_names:
170
+ continue
171
+ yield from self._iosxr_prefixlist(plist)
172
+ processed_names.add(plist.name)
@@ -38,3 +38,19 @@ class RDFilterFilterGenerator(PartialGenerator, ABC):
38
38
  for i, route_distinguisher in enumerate(rd_filter.members):
39
39
  rd_id = (i + 1) * 10 + 5
40
40
  yield "ip rd-filter", rd_filter.number, f"index {rd_id}", "permit", route_distinguisher
41
+
42
+ def acl_iosxr(self, _):
43
+ return r"""
44
+ rd-set *
45
+ ~ %global=1
46
+ """
47
+
48
+ def run_iosxr(self, device: Any):
49
+ for rd_filter in self.get_used_rd_filters(device):
50
+ with self.block("rd-set", rd_filter.name):
51
+ for i, route_distinguisher in enumerate(rd_filter.members):
52
+ if i + 1 < len(rd_filter.members):
53
+ comma = ","
54
+ else:
55
+ comma = ""
56
+ yield f"{route_distinguisher}{comma}",
@@ -3,7 +3,7 @@ import re
3
3
  from collections import OrderedDict as odict
4
4
 
5
5
  from annet.annlib.lib import jun_activate, jun_is_inactive, merge_dicts
6
- from annet.annlib.tabparser import JuniperFormatter
6
+ from annet.vendors.tabparser import JuniperFormatter
7
7
  from annet.annlib.types import Op
8
8
  from annet.rulebook import common
9
9
 
@@ -62,6 +62,8 @@ interface */Vlan\d+/
62
62
  interface *
63
63
  no switchport
64
64
  encapsulation
65
+ ip vrf forwarding
66
+ vrf forwarding
65
67
  vrf member
66
68
  ip
67
69
  ipv6
@@ -72,14 +72,31 @@ interface *
72
72
 
73
73
  interface */\S+\.\d+/
74
74
 
75
- route-map
75
+
76
+ # all referenced in policy
77
+ as-path-set *
78
+ ~
79
+ prefix-set *
80
+ ~
81
+ community-set *
82
+ ~
83
+ extcommunity-set *
84
+ ~
85
+
86
+ route-policy *
87
+ ~
76
88
 
77
89
  # удалять eth-trunk можно только после того, как вычистим member interfaces
78
90
  undo interface */port-channel\d+/ %order_reverse
79
91
 
80
- # remote as of neighbors should be assigned before peer-group, the rule is applied to neighbors, not peer-groups
92
+
81
93
  router bgp
82
- neighbor */[\da-f\.\:]+/ remote-as
83
- neighbor */[\da-f\.\:]+/ peer-group
94
+ bgp ~
95
+ neighbor-group *
96
+ ~
97
+ vrf *
98
+ ~
99
+ neighbor *
100
+ ~
84
101
 
85
102
  line
annet/vendors/base.py CHANGED
@@ -3,7 +3,7 @@ from typing import ClassVar
3
3
 
4
4
  from annet.annlib.command import CommandList
5
5
  from annet.annlib.netdev.views.hardware import HardwareView
6
- from annet.annlib.tabparser import CommonFormatter
6
+ from annet.vendors.tabparser import CommonFormatter
7
7
 
8
8
 
9
9
  class AbstractVendor(abc.ABC):
@@ -1,6 +1,6 @@
1
1
  from annet.annlib.command import Command, CommandList
2
2
  from annet.annlib.netdev.views.hardware import HardwareView
3
- from annet.annlib.tabparser import AristaFormatter
3
+ from annet.vendors.tabparser import AristaFormatter
4
4
  from annet.vendors.base import AbstractVendor
5
5
  from annet.vendors.registry import registry
6
6
 
@@ -1,6 +1,6 @@
1
1
  from annet.annlib.command import Command, CommandList
2
2
  from annet.annlib.netdev.views.hardware import HardwareView
3
- from annet.annlib.tabparser import ArubaFormatter
3
+ from annet.vendors.tabparser import ArubaFormatter
4
4
  from annet.vendors.base import AbstractVendor
5
5
  from annet.vendors.registry import registry
6
6
 
@@ -1,6 +1,6 @@
1
1
  from annet.annlib.command import Command, CommandList
2
2
  from annet.annlib.netdev.views.hardware import HardwareView
3
- from annet.annlib.tabparser import B4comFormatter
3
+ from annet.vendors.tabparser import B4comFormatter
4
4
  from annet.vendors.base import AbstractVendor
5
5
  from annet.vendors.registry import registry
6
6
 
@@ -1,6 +1,6 @@
1
1
  from annet.annlib.command import Command, CommandList
2
2
  from annet.annlib.netdev.views.hardware import HardwareView
3
- from annet.annlib.tabparser import CiscoFormatter
3
+ from annet.vendors.tabparser import CiscoFormatter
4
4
  from annet.vendors.base import AbstractVendor
5
5
  from annet.vendors.registry import registry
6
6
 
@@ -1,6 +1,6 @@
1
1
  from annet.annlib.command import Command, CommandList
2
2
  from annet.annlib.netdev.views.hardware import HardwareView
3
- from annet.annlib.tabparser import HuaweiFormatter
3
+ from annet.vendors.tabparser import HuaweiFormatter
4
4
  from annet.vendors.base import AbstractVendor
5
5
  from annet.vendors.registry import registry
6
6
 
@@ -1,6 +1,6 @@
1
1
  from annet.annlib.command import Command, CommandList
2
2
  from annet.annlib.netdev.views.hardware import HardwareView
3
- from annet.annlib.tabparser import HuaweiFormatter
3
+ from annet.vendors.tabparser import HuaweiFormatter
4
4
  from annet.vendors.base import AbstractVendor
5
5
  from annet.vendors.registry import registry
6
6
 
@@ -1,6 +1,6 @@
1
1
  from annet.annlib.command import Command, CommandList
2
2
  from annet.annlib.netdev.views.hardware import HardwareView
3
- from annet.annlib.tabparser import AsrFormatter
3
+ from annet.vendors.tabparser import AsrFormatter
4
4
  from annet.vendors.base import AbstractVendor
5
5
  from annet.vendors.registry import registry
6
6
 
@@ -1,6 +1,6 @@
1
1
  from annet.annlib.command import Command, CommandList
2
2
  from annet.annlib.netdev.views.hardware import HardwareView
3
- from annet.annlib.tabparser import JuniperFormatter
3
+ from annet.vendors.tabparser import JuniperFormatter
4
4
  from annet.vendors.base import AbstractVendor
5
5
  from annet.vendors.registry import registry
6
6
 
@@ -1,6 +1,6 @@
1
1
  from annet.annlib.command import Command, CommandList
2
2
  from annet.annlib.netdev.views.hardware import HardwareView
3
- from annet.annlib.tabparser import NexusFormatter
3
+ from annet.vendors.tabparser import NexusFormatter
4
4
  from annet.vendors.base import AbstractVendor
5
5
  from annet.vendors.registry import registry
6
6
 
@@ -1,6 +1,6 @@
1
1
  from annet.annlib.command import Command, CommandList
2
2
  from annet.annlib.netdev.views.hardware import HardwareView
3
- from annet.annlib.tabparser import NokiaFormatter
3
+ from annet.vendors.tabparser import NokiaFormatter
4
4
  from annet.vendors.base import AbstractVendor
5
5
  from annet.vendors.registry import registry
6
6
 
@@ -1,5 +1,5 @@
1
1
  from annet.annlib.netdev.views.hardware import HardwareView
2
- from annet.annlib.tabparser import OptixtransFormatter
2
+ from annet.vendors.tabparser import OptixtransFormatter
3
3
  from annet.vendors.registry import registry
4
4
 
5
5
  from .huawei import HuaweiVendor
@@ -2,7 +2,7 @@ import os
2
2
 
3
3
  from annet.annlib.command import Command, CommandList
4
4
  from annet.annlib.netdev.views.hardware import HardwareView
5
- from annet.annlib.tabparser import CommonFormatter
5
+ from annet.vendors.tabparser import CommonFormatter
6
6
  from annet.vendors.base import AbstractVendor
7
7
  from annet.vendors.registry import registry
8
8
 
@@ -1,6 +1,6 @@
1
1
  from annet.annlib.command import Command, CommandList
2
2
  from annet.annlib.netdev.views.hardware import HardwareView
3
- from annet.annlib.tabparser import RibbonFormatter
3
+ from annet.vendors.tabparser import RibbonFormatter
4
4
  from annet.vendors.base import AbstractVendor
5
5
  from annet.vendors.registry import registry
6
6
 
@@ -1,6 +1,6 @@
1
1
  from annet.annlib.command import Command, CommandList
2
2
  from annet.annlib.netdev.views.hardware import HardwareView
3
- from annet.annlib.tabparser import RosFormatter
3
+ from annet.vendors.tabparser import RosFormatter
4
4
  from annet.vendors.base import AbstractVendor
5
5
  from annet.vendors.registry import registry
6
6