annet 1.1.1__py3-none-any.whl → 2.0.0__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.
- annet/annet.py +2 -1
- annet/annlib/lib.py +0 -14
- annet/annlib/rbparser/platform.py +2 -2
- annet/annlib/tabparser.py +46 -21
- annet/api/__init__.py +35 -29
- annet/diff.py +71 -2
- annet/gen.py +0 -46
- annet/generators/entire.py +0 -4
- annet/lib.py +6 -2
- annet/output.py +9 -2
- annet/rpl/__init__.py +2 -1
- annet/rpl/match_builder.py +10 -6
- annet/rpl_generators/__init__.py +3 -1
- annet/rpl_generators/cumulus_frr.py +24 -51
- annet/rpl_generators/entities.py +70 -27
- annet/rpl_generators/policy.py +61 -55
- annet/rpl_generators/prefix_lists.py +36 -81
- annet/rulebook/juniper/__init__.py +1 -1
- {annet-1.1.1.dist-info → annet-2.0.0.dist-info}/METADATA +1 -2
- {annet-1.1.1.dist-info → annet-2.0.0.dist-info}/RECORD +26 -26
- annet_generators/rpl_example/items.py +3 -3
- {annet-1.1.1.dist-info → annet-2.0.0.dist-info}/AUTHORS +0 -0
- {annet-1.1.1.dist-info → annet-2.0.0.dist-info}/LICENSE +0 -0
- {annet-1.1.1.dist-info → annet-2.0.0.dist-info}/WHEEL +0 -0
- {annet-1.1.1.dist-info → annet-2.0.0.dist-info}/entry_points.txt +0 -0
- {annet-1.1.1.dist-info → annet-2.0.0.dist-info}/top_level.txt +0 -0
|
@@ -14,7 +14,7 @@ from .entities import (
|
|
|
14
14
|
AsPathFilter, IpPrefixList, CommunityList, CommunityLogic, CommunityType,
|
|
15
15
|
mangle_united_community_list_name, PrefixListNameGenerator,
|
|
16
16
|
)
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
|
|
19
19
|
FRR_RESULT_MAP = {
|
|
20
20
|
ResultType.ALLOW: "permit",
|
|
@@ -51,12 +51,6 @@ class CumulusPolicyGenerator(ABC):
|
|
|
51
51
|
def get_prefix_lists(self, device: Any) -> Sequence[IpPrefixList]:
|
|
52
52
|
raise NotImplementedError()
|
|
53
53
|
|
|
54
|
-
def get_used_prefix_lists(self, device: Any, name_generator: PrefixListNameGenerator) -> Sequence[IpPrefixList]:
|
|
55
|
-
return get_used_prefix_lists(
|
|
56
|
-
prefix_lists=self.get_prefix_lists(device),
|
|
57
|
-
name_generator=name_generator,
|
|
58
|
-
)
|
|
59
|
-
|
|
60
54
|
@abstractmethod
|
|
61
55
|
def get_community_lists(self, device: Any) -> list[CommunityList]:
|
|
62
56
|
raise NotImplementedError()
|
|
@@ -66,8 +60,9 @@ class CumulusPolicyGenerator(ABC):
|
|
|
66
60
|
raise NotImplementedError
|
|
67
61
|
|
|
68
62
|
def generate_cumulus_rpl(self, device: Any) -> Iterator[Sequence[str]]:
|
|
63
|
+
prefix_lists = self.get_prefix_lists(device)
|
|
69
64
|
policies = self.get_policies(device)
|
|
70
|
-
prefix_list_name_generator =
|
|
65
|
+
prefix_list_name_generator = PrefixListNameGenerator(prefix_lists, policies)
|
|
71
66
|
|
|
72
67
|
communities = {c.name: c for c in self.get_community_lists(device)}
|
|
73
68
|
yield from self._cumulus_as_path_filters(device, policies)
|
|
@@ -89,60 +84,46 @@ class CumulusPolicyGenerator(ABC):
|
|
|
89
84
|
|
|
90
85
|
def _cumulus_prefix_list(
|
|
91
86
|
self,
|
|
92
|
-
name: str,
|
|
93
87
|
ip_type: Literal["ipv6", "ip"],
|
|
94
|
-
match: PrefixMatchValue,
|
|
95
88
|
plist: IpPrefixList,
|
|
96
89
|
) -> Iterable[Sequence[str]]:
|
|
97
|
-
for i,
|
|
98
|
-
|
|
90
|
+
for i, m in enumerate(plist.members):
|
|
91
|
+
ge, le = m.or_longer
|
|
99
92
|
yield (
|
|
100
93
|
ip_type,
|
|
101
94
|
"prefix-list",
|
|
102
|
-
name,
|
|
95
|
+
plist.name,
|
|
103
96
|
f"seq {i * 5 + 5}",
|
|
104
|
-
"permit",
|
|
97
|
+
"permit", str(m.prefix),
|
|
105
98
|
) + (
|
|
106
|
-
("ge", str(
|
|
99
|
+
("ge", str(ge)) if ge is not None else ()
|
|
107
100
|
) + (
|
|
108
|
-
("le", str(
|
|
101
|
+
("le", str(le)) if le is not None else ()
|
|
109
102
|
)
|
|
110
103
|
|
|
111
104
|
def _cumulus_prefix_lists(
|
|
112
105
|
self, device: Any,
|
|
113
106
|
policies: list[RoutingPolicy],
|
|
114
|
-
|
|
107
|
+
name_generator: PrefixListNameGenerator,
|
|
115
108
|
) -> Iterable[Sequence[str]]:
|
|
116
|
-
|
|
117
|
-
if not plists.values():
|
|
118
|
-
return
|
|
119
|
-
|
|
120
|
-
precessed_names = set()
|
|
109
|
+
processed_names = set()
|
|
121
110
|
for policy in policies:
|
|
122
111
|
for statement in policy.statements:
|
|
123
112
|
cond: SingleCondition[PrefixMatchValue]
|
|
124
113
|
for cond in statement.match.find_all(MatchField.ip_prefix):
|
|
125
114
|
for name in cond.value.names:
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
greater_equal=cond.value.greater_equal,
|
|
129
|
-
less_equal=cond.value.less_equal,
|
|
130
|
-
)
|
|
131
|
-
if mangled_name in precessed_names:
|
|
115
|
+
plist = name_generator.get_prefix(name, cond.value)
|
|
116
|
+
if plist.name in processed_names:
|
|
132
117
|
continue
|
|
133
|
-
yield from self._cumulus_prefix_list(
|
|
134
|
-
|
|
118
|
+
yield from self._cumulus_prefix_list("ip", plist)
|
|
119
|
+
processed_names.add(plist.name)
|
|
135
120
|
for cond in statement.match.find_all(MatchField.ipv6_prefix):
|
|
136
121
|
for name in cond.value.names:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
greater_equal=cond.value.greater_equal,
|
|
140
|
-
less_equal=cond.value.less_equal,
|
|
141
|
-
)
|
|
142
|
-
if mangled_name in precessed_names:
|
|
122
|
+
plist = name_generator.get_prefix(name, cond.value)
|
|
123
|
+
if plist.name in processed_names:
|
|
143
124
|
continue
|
|
144
|
-
yield from self._cumulus_prefix_list(
|
|
145
|
-
|
|
125
|
+
yield from self._cumulus_prefix_list("ipv6", plist)
|
|
126
|
+
processed_names.add(plist.name)
|
|
146
127
|
yield "!"
|
|
147
128
|
|
|
148
129
|
def get_used_united_community_lists(
|
|
@@ -231,7 +212,7 @@ class CumulusPolicyGenerator(ABC):
|
|
|
231
212
|
self,
|
|
232
213
|
device: Any,
|
|
233
214
|
condition: SingleCondition[Any],
|
|
234
|
-
|
|
215
|
+
name_generator: PrefixListNameGenerator,
|
|
235
216
|
) -> Iterator[Sequence[str]]:
|
|
236
217
|
if condition.field == MatchField.community:
|
|
237
218
|
for comm_name in self._get_match_community_names(condition):
|
|
@@ -251,21 +232,13 @@ class CumulusPolicyGenerator(ABC):
|
|
|
251
232
|
return
|
|
252
233
|
if condition.field == MatchField.ip_prefix:
|
|
253
234
|
for name in condition.value.names:
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
greater_equal=condition.value.greater_equal,
|
|
257
|
-
less_equal=condition.value.less_equal,
|
|
258
|
-
)
|
|
259
|
-
yield "match", "ip address prefix-list", mangled_name
|
|
235
|
+
plist = name_generator.get_prefix(name, condition.value)
|
|
236
|
+
yield "match", "ip address prefix-list", plist.name
|
|
260
237
|
return
|
|
261
238
|
if condition.field == MatchField.ipv6_prefix:
|
|
262
239
|
for name in condition.value.names:
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
greater_equal=condition.value.greater_equal,
|
|
266
|
-
less_equal=condition.value.less_equal,
|
|
267
|
-
)
|
|
268
|
-
yield "match", "ipv6 address prefix-list", mangled_name
|
|
240
|
+
plist = name_generator.get_prefix(name, condition.value)
|
|
241
|
+
yield "match", "ipv6 address prefix-list", plist.name
|
|
269
242
|
return
|
|
270
243
|
if condition.operator is not ConditionOperator.EQ:
|
|
271
244
|
raise NotImplementedError(
|
annet/rpl_generators/entities.py
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
from
|
|
1
|
+
from ipaddress import IPv4Network, IPv6Network, ip_network
|
|
2
2
|
from collections.abc import Sequence
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from enum import Enum
|
|
5
|
-
from typing import Optional
|
|
5
|
+
from typing import Optional, List
|
|
6
|
+
|
|
7
|
+
from annet.rpl import RoutingPolicy, PrefixMatchValue, OrLonger
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
class CommunityLogic(Enum):
|
|
@@ -40,10 +42,48 @@ class AsPathFilter:
|
|
|
40
42
|
filters: Sequence[str]
|
|
41
43
|
|
|
42
44
|
|
|
43
|
-
@dataclass
|
|
45
|
+
@dataclass
|
|
46
|
+
class IpPrefixListMember:
|
|
47
|
+
prefix: IPv4Network | IPv6Network
|
|
48
|
+
or_longer: OrLonger = (None, None)
|
|
49
|
+
|
|
50
|
+
def __post_init__(self):
|
|
51
|
+
self.prefix = ip_network(self.prefix)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass
|
|
44
55
|
class IpPrefixList:
|
|
45
56
|
name: str
|
|
46
|
-
members:
|
|
57
|
+
members: list[IpPrefixListMember]
|
|
58
|
+
|
|
59
|
+
def __post_init__(self):
|
|
60
|
+
for (i, m) in enumerate(self.members):
|
|
61
|
+
if isinstance(m, str):
|
|
62
|
+
self.members[i] = IpPrefixListMember(m)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def ip_prefix_list(
|
|
66
|
+
name: str,
|
|
67
|
+
members_or_str: Sequence[IpPrefixListMember | str],
|
|
68
|
+
or_longer: OrLonger = (None, None),
|
|
69
|
+
) -> IpPrefixList:
|
|
70
|
+
members: List[IpPrefixListMember] = []
|
|
71
|
+
for m in members_or_str:
|
|
72
|
+
if isinstance(m, str):
|
|
73
|
+
m = IpPrefixListMember(
|
|
74
|
+
prefix=ip_network(m),
|
|
75
|
+
or_longer=or_longer,
|
|
76
|
+
)
|
|
77
|
+
elif m.or_longer == (None, None):
|
|
78
|
+
m = IpPrefixListMember(
|
|
79
|
+
prefix=m.prefix,
|
|
80
|
+
or_longer=or_longer,
|
|
81
|
+
)
|
|
82
|
+
members.append(m)
|
|
83
|
+
return IpPrefixList(
|
|
84
|
+
name=name,
|
|
85
|
+
members=members,
|
|
86
|
+
)
|
|
47
87
|
|
|
48
88
|
|
|
49
89
|
def arista_well_known_community(community: str) -> str:
|
|
@@ -58,26 +98,29 @@ def mangle_united_community_list_name(values: Sequence[str]) -> str:
|
|
|
58
98
|
|
|
59
99
|
|
|
60
100
|
class PrefixListNameGenerator:
|
|
61
|
-
def __init__(self):
|
|
62
|
-
self._prefix_lists =
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
101
|
+
def __init__(self, prefix_lists: Sequence[IpPrefixList], policies: Sequence[RoutingPolicy]):
|
|
102
|
+
self._prefix_lists = {x.name: x for x in prefix_lists}
|
|
103
|
+
self._policies = {x.name: x for x in policies} # this is here for a later use ~azryve@
|
|
104
|
+
|
|
105
|
+
def get_prefix(self, name: str, match: PrefixMatchValue) -> IpPrefixList:
|
|
106
|
+
orig_prefix = self._prefix_lists[name]
|
|
107
|
+
override_name: Optional[str] = None
|
|
108
|
+
override_orlonger: Optional[OrLonger] = None
|
|
109
|
+
|
|
110
|
+
if any(match.or_longer):
|
|
111
|
+
ge, le = match.or_longer
|
|
112
|
+
ge_str = "unset" if ge is None else str(ge)
|
|
113
|
+
le_str = "unset" if le is None else str(le)
|
|
114
|
+
override_name = f"{orig_prefix.name}_{ge_str}_{le_str}"
|
|
115
|
+
override_orlonger = match.or_longer
|
|
116
|
+
|
|
117
|
+
return IpPrefixList(
|
|
118
|
+
name=override_name or name,
|
|
119
|
+
members=[
|
|
120
|
+
IpPrefixListMember(
|
|
121
|
+
x.prefix,
|
|
122
|
+
or_longer=override_orlonger or x.or_longer,
|
|
123
|
+
)
|
|
124
|
+
for x in orig_prefix.members
|
|
125
|
+
],
|
|
126
|
+
)
|
annet/rpl_generators/policy.py
CHANGED
|
@@ -12,8 +12,9 @@ from annet.rpl.statement_builder import AsPathActionValue, NextHopActionValue, T
|
|
|
12
12
|
from annet.rpl_generators.entities import (
|
|
13
13
|
arista_well_known_community,
|
|
14
14
|
CommunityList, RDFilter, PrefixListNameGenerator, CommunityLogic, mangle_united_community_list_name,
|
|
15
|
+
IpPrefixList,
|
|
15
16
|
)
|
|
16
|
-
|
|
17
|
+
|
|
17
18
|
|
|
18
19
|
HUAWEI_MATCH_COMMAND_MAP: dict[str, str] = {
|
|
19
20
|
MatchField.as_path_filter: "as-path-filter {option_value}",
|
|
@@ -62,6 +63,10 @@ ARISTA_THEN_COMMAND_MAP: dict[str, str] = {
|
|
|
62
63
|
class RoutingPolicyGenerator(PartialGenerator, ABC):
|
|
63
64
|
TAGS = ["policy", "rpl", "routing"]
|
|
64
65
|
|
|
66
|
+
@abstractmethod
|
|
67
|
+
def get_prefix_lists(self, device: Any) -> list[IpPrefixList]:
|
|
68
|
+
raise NotImplementedError()
|
|
69
|
+
|
|
65
70
|
@abstractmethod
|
|
66
71
|
def get_policies(self, device: Any) -> list[RoutingPolicy]:
|
|
67
72
|
raise NotImplementedError()
|
|
@@ -87,7 +92,7 @@ class RoutingPolicyGenerator(PartialGenerator, ABC):
|
|
|
87
92
|
condition: SingleCondition[Any],
|
|
88
93
|
communities: dict[str, CommunityList],
|
|
89
94
|
rd_filters: dict[str, RDFilter],
|
|
90
|
-
|
|
95
|
+
name_generator: PrefixListNameGenerator,
|
|
91
96
|
) -> Iterator[Sequence[str]]:
|
|
92
97
|
if condition.field == MatchField.community:
|
|
93
98
|
if condition.operator is ConditionOperator.HAS:
|
|
@@ -136,21 +141,13 @@ class RoutingPolicyGenerator(PartialGenerator, ABC):
|
|
|
136
141
|
return
|
|
137
142
|
if condition.field == MatchField.ip_prefix:
|
|
138
143
|
for name in condition.value.names:
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
greater_equal=condition.value.greater_equal,
|
|
142
|
-
less_equal=condition.value.less_equal,
|
|
143
|
-
)
|
|
144
|
-
yield "if-match", "ip-prefix", mangled_name
|
|
144
|
+
plist = name_generator.get_prefix(name, condition.value)
|
|
145
|
+
yield "if-match", "ip-prefix", plist.name
|
|
145
146
|
return
|
|
146
147
|
if condition.field == MatchField.ipv6_prefix:
|
|
147
148
|
for name in condition.value.names:
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
greater_equal=condition.value.greater_equal,
|
|
151
|
-
less_equal=condition.value.less_equal,
|
|
152
|
-
)
|
|
153
|
-
yield "if-match", "ipv6 address prefix-list", mangled_name
|
|
149
|
+
plist = name_generator.get_prefix(name, condition.value)
|
|
150
|
+
yield "if-match", "ipv6 address prefix-list", plist.name
|
|
154
151
|
return
|
|
155
152
|
if condition.field == MatchField.as_path_length:
|
|
156
153
|
if condition.operator is ConditionOperator.EQ:
|
|
@@ -353,10 +350,11 @@ class RoutingPolicyGenerator(PartialGenerator, ABC):
|
|
|
353
350
|
yield "goto next-node"
|
|
354
351
|
|
|
355
352
|
def run_huawei(self, device):
|
|
353
|
+
prefix_lists = self.get_prefix_lists(device)
|
|
356
354
|
policies = self.get_policies(device)
|
|
357
355
|
communities = {c.name: c for c in self.get_community_lists(device)}
|
|
358
356
|
rd_filters = {f.name: f for f in self.get_rd_filters(device)}
|
|
359
|
-
prefix_name_generator =
|
|
357
|
+
prefix_name_generator = PrefixListNameGenerator(prefix_lists, policies)
|
|
360
358
|
|
|
361
359
|
for policy in self.get_policies(device):
|
|
362
360
|
for statement in policy.statements:
|
|
@@ -383,7 +381,7 @@ class RoutingPolicyGenerator(PartialGenerator, ABC):
|
|
|
383
381
|
condition: SingleCondition[Any],
|
|
384
382
|
communities: dict[str, CommunityList],
|
|
385
383
|
rd_filters: dict[str, RDFilter],
|
|
386
|
-
|
|
384
|
+
name_generator: PrefixListNameGenerator,
|
|
387
385
|
) -> Iterator[Sequence[str]]:
|
|
388
386
|
if condition.field == MatchField.community:
|
|
389
387
|
if condition.operator is ConditionOperator.HAS_ANY:
|
|
@@ -436,21 +434,13 @@ class RoutingPolicyGenerator(PartialGenerator, ABC):
|
|
|
436
434
|
return
|
|
437
435
|
if condition.field == MatchField.ip_prefix:
|
|
438
436
|
for name in condition.value.names:
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
greater_equal=condition.value.greater_equal,
|
|
442
|
-
less_equal=condition.value.less_equal,
|
|
443
|
-
)
|
|
444
|
-
yield "match", "ip address prefix-list", mangled_name
|
|
437
|
+
plist = name_generator.get_prefix(name, condition.value)
|
|
438
|
+
yield "match", "ip address prefix-list", plist.name
|
|
445
439
|
return
|
|
446
440
|
if condition.field == MatchField.ipv6_prefix:
|
|
447
441
|
for name in condition.value.names:
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
greater_equal=condition.value.greater_equal,
|
|
451
|
-
less_equal=condition.value.less_equal,
|
|
452
|
-
)
|
|
453
|
-
yield "match", "ipv6 address prefix-list", mangled_name
|
|
442
|
+
plist = name_generator.get_prefix(name, condition.value)
|
|
443
|
+
yield "match", "ipv6 address prefix-list", plist.name
|
|
454
444
|
return
|
|
455
445
|
if condition.field == MatchField.as_path_length:
|
|
456
446
|
if condition.operator is ConditionOperator.EQ:
|
|
@@ -492,12 +482,15 @@ class RoutingPolicyGenerator(PartialGenerator, ABC):
|
|
|
492
482
|
yield "set", "community community-list", *action.value.replaced
|
|
493
483
|
else:
|
|
494
484
|
yield "set", "community", "none"
|
|
495
|
-
|
|
496
|
-
yield "set", "community community-list",
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
485
|
+
if action.value.added:
|
|
486
|
+
yield "set", "community community-list", *action.value.added, "additive"
|
|
487
|
+
if action.value.removed:
|
|
488
|
+
members = [
|
|
489
|
+
arista_well_known_community(member)
|
|
490
|
+
for community_name in action.value.removed
|
|
491
|
+
for member in communities[community_name].members
|
|
492
|
+
]
|
|
493
|
+
yield "set community", *members, "delete"
|
|
501
494
|
|
|
502
495
|
def _arista_then_large_community(
|
|
503
496
|
self,
|
|
@@ -520,10 +513,10 @@ class RoutingPolicyGenerator(PartialGenerator, ABC):
|
|
|
520
513
|
first = False
|
|
521
514
|
else:
|
|
522
515
|
yield "set", "large-community large-community-list", community_name, "additive"
|
|
523
|
-
|
|
524
|
-
yield "set", "large-community large-community-list",
|
|
525
|
-
|
|
526
|
-
yield "set large-community large-community-list",
|
|
516
|
+
if action.value.added:
|
|
517
|
+
yield "set", "large-community large-community-list", *action.value.added, "additive"
|
|
518
|
+
if action.value.removed:
|
|
519
|
+
yield "set large-community large-community-list", *action.value.removed, "delete"
|
|
527
520
|
|
|
528
521
|
def _arista_then_extcommunity_rt(
|
|
529
522
|
self,
|
|
@@ -533,14 +526,20 @@ class RoutingPolicyGenerator(PartialGenerator, ABC):
|
|
|
533
526
|
) -> Iterator[Sequence[str]]:
|
|
534
527
|
if action.value.replaced is not None:
|
|
535
528
|
raise NotImplementedError("Extcommunity_rt replace is not supported for arista")
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
529
|
+
if action.value.added:
|
|
530
|
+
members = [
|
|
531
|
+
f"rt {member}"
|
|
532
|
+
for community_name in action.value.removed
|
|
533
|
+
for member in communities[community_name].members
|
|
534
|
+
]
|
|
535
|
+
yield "set", "extcommunity", *members, "additive"
|
|
536
|
+
if action.value.removed:
|
|
537
|
+
members = [
|
|
538
|
+
f"rt {member}"
|
|
539
|
+
for community_name in action.value.removed
|
|
540
|
+
for member in communities[community_name].members
|
|
541
|
+
]
|
|
542
|
+
yield "set extcommunity", *members, "delete"
|
|
544
543
|
|
|
545
544
|
def _arista_then_extcommunity_soo(
|
|
546
545
|
self,
|
|
@@ -550,14 +549,20 @@ class RoutingPolicyGenerator(PartialGenerator, ABC):
|
|
|
550
549
|
) -> Iterator[Sequence[str]]:
|
|
551
550
|
if action.value.replaced is not None:
|
|
552
551
|
raise NotImplementedError("Extcommunity_soo replace is not supported for arista")
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
552
|
+
if action.value.added:
|
|
553
|
+
members = [
|
|
554
|
+
f"soo {member}"
|
|
555
|
+
for community_name in action.value.removed
|
|
556
|
+
for member in communities[community_name].members
|
|
557
|
+
]
|
|
558
|
+
yield "set", "extcommunity", *members, "additive"
|
|
559
|
+
if action.value.removed:
|
|
560
|
+
members = [
|
|
561
|
+
f"soo {member}"
|
|
562
|
+
for community_name in action.value.removed
|
|
563
|
+
for member in communities[community_name].members
|
|
564
|
+
]
|
|
565
|
+
yield "set", "extcommunity", *members, "delete"
|
|
561
566
|
|
|
562
567
|
def _arista_then_as_path(
|
|
563
568
|
self,
|
|
@@ -675,8 +680,9 @@ class RoutingPolicyGenerator(PartialGenerator, ABC):
|
|
|
675
680
|
yield "continue"
|
|
676
681
|
|
|
677
682
|
def run_arista(self, device):
|
|
683
|
+
prefix_lists = self.get_prefix_lists(device)
|
|
678
684
|
policies = self.get_policies(device)
|
|
679
|
-
prefix_name_generator =
|
|
685
|
+
prefix_name_generator = PrefixListNameGenerator(prefix_lists, policies)
|
|
680
686
|
communities = {c.name: c for c in self.get_community_lists(device)}
|
|
681
687
|
rd_filters = {f.name: f for f in self.get_rd_filters(device)}
|
|
682
688
|
|
|
@@ -8,26 +8,6 @@ from annet.rpl import PrefixMatchValue, MatchField, SingleCondition, RoutingPoli
|
|
|
8
8
|
from .entities import IpPrefixList, PrefixListNameGenerator
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def get_used_prefix_lists(
|
|
12
|
-
prefix_lists: Sequence[IpPrefixList], name_generator: PrefixListNameGenerator,
|
|
13
|
-
) -> list[IpPrefixList]:
|
|
14
|
-
return [c for c in prefix_lists if name_generator.is_used(c.name)]
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def new_prefix_list_name_generator(policies: list[RoutingPolicy]) -> PrefixListNameGenerator:
|
|
18
|
-
name_gen = PrefixListNameGenerator()
|
|
19
|
-
for policy in policies:
|
|
20
|
-
for statement in policy.statements:
|
|
21
|
-
condition: SingleCondition[PrefixMatchValue]
|
|
22
|
-
for condition in statement.match.find_all(MatchField.ipv6_prefix):
|
|
23
|
-
for name in condition.value.names:
|
|
24
|
-
name_gen.add_prefix(name, condition.value.greater_equal, condition.value.less_equal)
|
|
25
|
-
for condition in statement.match.find_all(MatchField.ip_prefix):
|
|
26
|
-
for name in condition.value.names:
|
|
27
|
-
name_gen.add_prefix(name, condition.value.greater_equal, condition.value.less_equal)
|
|
28
|
-
return name_gen
|
|
29
|
-
|
|
30
|
-
|
|
31
11
|
class PrefixListFilterGenerator(PartialGenerator, ABC):
|
|
32
12
|
TAGS = ["policy", "rpl", "routing"]
|
|
33
13
|
|
|
@@ -39,12 +19,6 @@ class PrefixListFilterGenerator(PartialGenerator, ABC):
|
|
|
39
19
|
def get_prefix_lists(self, device: Any) -> Sequence[IpPrefixList]:
|
|
40
20
|
raise NotImplementedError()
|
|
41
21
|
|
|
42
|
-
def get_used_prefix_lists(self, device: Any, name_generator: PrefixListNameGenerator) -> Sequence[IpPrefixList]:
|
|
43
|
-
return get_used_prefix_lists(
|
|
44
|
-
prefix_lists=self.get_prefix_lists(device),
|
|
45
|
-
name_generator=name_generator,
|
|
46
|
-
)
|
|
47
|
-
|
|
48
22
|
# huawei
|
|
49
23
|
def acl_huawei(self, _):
|
|
50
24
|
return r"""
|
|
@@ -54,57 +28,48 @@ class PrefixListFilterGenerator(PartialGenerator, ABC):
|
|
|
54
28
|
|
|
55
29
|
def _huawei_prefix_list(
|
|
56
30
|
self,
|
|
57
|
-
name: str,
|
|
58
31
|
prefix_type: Literal["ipv6-prefix", "ip-prefix"],
|
|
59
|
-
match: PrefixMatchValue,
|
|
60
32
|
plist: IpPrefixList,
|
|
61
33
|
) -> Iterable[Sequence[str]]:
|
|
62
|
-
for i,
|
|
63
|
-
|
|
34
|
+
for i, m in enumerate(plist.members):
|
|
35
|
+
ge, le = m.or_longer
|
|
64
36
|
yield (
|
|
65
37
|
"ip",
|
|
66
38
|
prefix_type,
|
|
67
|
-
name,
|
|
39
|
+
plist.name,
|
|
68
40
|
f"index {i * 5 + 5}",
|
|
69
41
|
"permit",
|
|
70
|
-
str(
|
|
71
|
-
str(
|
|
42
|
+
str(m.prefix.network_address).upper(),
|
|
43
|
+
str(m.prefix.prefixlen),
|
|
72
44
|
) + (
|
|
73
|
-
("greater-equal", str(
|
|
45
|
+
("greater-equal", str(ge)) if ge is not None else ()
|
|
74
46
|
) + (
|
|
75
|
-
("less-equal", str(
|
|
47
|
+
("less-equal", str(le)) if le is not None else ()
|
|
76
48
|
)
|
|
77
49
|
|
|
78
50
|
def run_huawei(self, device: Any):
|
|
51
|
+
prefix_lists = self.get_prefix_lists(device)
|
|
79
52
|
policies = self.get_policies(device)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
53
|
+
|
|
54
|
+
name_generator = PrefixListNameGenerator(prefix_lists, policies)
|
|
55
|
+
processed_names = set()
|
|
83
56
|
for policy in policies:
|
|
84
57
|
for statement in policy.statements:
|
|
85
58
|
cond: SingleCondition[PrefixMatchValue]
|
|
86
59
|
for cond in statement.match.find_all(MatchField.ip_prefix):
|
|
87
60
|
for name in cond.value.names:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
greater_equal=cond.value.greater_equal,
|
|
91
|
-
less_equal=cond.value.less_equal,
|
|
92
|
-
)
|
|
93
|
-
if mangled_name in precessed_names:
|
|
61
|
+
plist = name_generator.get_prefix(name, cond.value)
|
|
62
|
+
if plist.name in processed_names:
|
|
94
63
|
continue
|
|
95
|
-
yield from self._huawei_prefix_list(
|
|
96
|
-
|
|
64
|
+
yield from self._huawei_prefix_list("ip-prefix", plist)
|
|
65
|
+
processed_names.add(plist.name)
|
|
97
66
|
for cond in statement.match.find_all(MatchField.ipv6_prefix):
|
|
98
67
|
for name in cond.value.names:
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
greater_equal=cond.value.greater_equal,
|
|
102
|
-
less_equal=cond.value.less_equal,
|
|
103
|
-
)
|
|
104
|
-
if mangled_name in precessed_names:
|
|
68
|
+
plist = name_generator.get_prefix(name, cond.value)
|
|
69
|
+
if plist.name in processed_names:
|
|
105
70
|
continue
|
|
106
|
-
yield from self._huawei_prefix_list(
|
|
107
|
-
|
|
71
|
+
yield from self._huawei_prefix_list("ipv6-prefix", plist)
|
|
72
|
+
processed_names.add(plist.name)
|
|
108
73
|
|
|
109
74
|
# arista
|
|
110
75
|
def acl_arista(self, _):
|
|
@@ -117,51 +82,41 @@ class PrefixListFilterGenerator(PartialGenerator, ABC):
|
|
|
117
82
|
|
|
118
83
|
def _arista_prefix_list(
|
|
119
84
|
self,
|
|
120
|
-
name: str,
|
|
121
85
|
prefix_type: Literal["ipv6", "ip"],
|
|
122
|
-
match: PrefixMatchValue,
|
|
123
86
|
plist: IpPrefixList,
|
|
124
87
|
) -> Iterable[Sequence[str]]:
|
|
125
|
-
with self.block(prefix_type, "prefix-list", name):
|
|
126
|
-
for i,
|
|
127
|
-
|
|
88
|
+
with self.block(prefix_type, "prefix-list", plist.name):
|
|
89
|
+
for i, m in enumerate(plist.members):
|
|
90
|
+
ge, le = m.or_longer
|
|
128
91
|
yield (
|
|
129
92
|
f"seq {i * 10 + 10}",
|
|
130
93
|
"permit",
|
|
131
|
-
|
|
94
|
+
str(m.prefix),
|
|
132
95
|
) + (
|
|
133
|
-
("ge", str(
|
|
96
|
+
("ge", str(ge)) if ge is not None else ()
|
|
134
97
|
) + (
|
|
135
|
-
("le", str(
|
|
98
|
+
("le", str(le)) if le is not None else ()
|
|
136
99
|
)
|
|
137
100
|
|
|
138
101
|
def run_arista(self, device: Any):
|
|
102
|
+
prefix_lists = self.get_prefix_lists(device)
|
|
139
103
|
policies = self.get_policies(device)
|
|
140
|
-
name_generator =
|
|
141
|
-
|
|
142
|
-
precessed_names = set()
|
|
104
|
+
name_generator = PrefixListNameGenerator(prefix_lists, policies)
|
|
105
|
+
processed_names = set()
|
|
143
106
|
for policy in policies:
|
|
144
107
|
for statement in policy.statements:
|
|
145
108
|
cond: SingleCondition[PrefixMatchValue]
|
|
146
109
|
for cond in statement.match.find_all(MatchField.ip_prefix):
|
|
147
110
|
for name in cond.value.names:
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
greater_equal=cond.value.greater_equal,
|
|
151
|
-
less_equal=cond.value.less_equal,
|
|
152
|
-
)
|
|
153
|
-
if mangled_name in precessed_names:
|
|
111
|
+
plist = name_generator.get_prefix(name, cond.value)
|
|
112
|
+
if plist.name in processed_names:
|
|
154
113
|
continue
|
|
155
|
-
yield from self._arista_prefix_list(
|
|
156
|
-
|
|
114
|
+
yield from self._arista_prefix_list("ip", plist)
|
|
115
|
+
processed_names.add(plist.name)
|
|
157
116
|
for cond in statement.match.find_all(MatchField.ipv6_prefix):
|
|
158
117
|
for name in cond.value.names:
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
greater_equal=cond.value.greater_equal,
|
|
162
|
-
less_equal=cond.value.less_equal,
|
|
163
|
-
)
|
|
164
|
-
if mangled_name in precessed_names:
|
|
118
|
+
plist = name_generator.get_prefix(name, cond.value)
|
|
119
|
+
if plist.name in processed_names:
|
|
165
120
|
continue
|
|
166
|
-
yield from self._arista_prefix_list(
|
|
167
|
-
|
|
121
|
+
yield from self._arista_prefix_list("ipv6", plist)
|
|
122
|
+
processed_names.add(plist.name)
|