annet 0.16.25__py3-none-any.whl → 0.16.27__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/adapters/file/provider.py +28 -10
- annet/adapters/netbox/v37/storage.py +1 -1
- annet/annlib/netdev/devdb/data/devdb.json +3 -2
- annet/annlib/patching.py +50 -14
- annet/bgp_models.py +28 -0
- annet/mesh/__init__.py +4 -0
- annet/mesh/basemodel.py +5 -0
- annet/mesh/device_models.py +2 -0
- annet/mesh/executor.py +90 -66
- annet/mesh/peer_models.py +3 -3
- annet/mesh/port_processor.py +18 -0
- annet/mesh/registry.py +12 -4
- annet/rpl/match_builder.py +30 -9
- annet/rpl/routemap.py +5 -3
- annet/rpl/statement_builder.py +31 -7
- annet/rpl_generators/__init__.py +24 -0
- annet/rpl_generators/aspath.py +57 -0
- annet/rpl_generators/community.py +242 -0
- annet/rpl_generators/cumulus_frr.py +458 -0
- annet/rpl_generators/entities.py +70 -0
- annet/rpl_generators/execute.py +12 -0
- annet/rpl_generators/policy.py +676 -0
- annet/rpl_generators/prefix_lists.py +158 -0
- annet/rpl_generators/rd.py +40 -0
- {annet-0.16.25.dist-info → annet-0.16.27.dist-info}/METADATA +2 -2
- {annet-0.16.25.dist-info → annet-0.16.27.dist-info}/RECORD +36 -25
- annet_generators/rpl_example/__init__.py +3 -5
- annet_generators/rpl_example/generator.py +127 -0
- annet_generators/rpl_example/items.py +21 -31
- annet_generators/rpl_example/mesh.py +9 -0
- annet_generators/rpl_example/route_policy.py +43 -9
- annet_generators/rpl_example/policy_generator.py +0 -233
- {annet-0.16.25.dist-info → annet-0.16.27.dist-info}/AUTHORS +0 -0
- {annet-0.16.25.dist-info → annet-0.16.27.dist-info}/LICENSE +0 -0
- {annet-0.16.25.dist-info → annet-0.16.27.dist-info}/WHEEL +0 -0
- {annet-0.16.25.dist-info → annet-0.16.27.dist-info}/entry_points.txt +0 -0
- {annet-0.16.25.dist-info → annet-0.16.27.dist-info}/top_level.txt +0 -0
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
from collections.abc import Iterator, Sequence
|
|
2
|
-
from typing import Any, cast
|
|
3
|
-
|
|
4
|
-
from annet.generators import PartialGenerator, BaseGenerator
|
|
5
|
-
from annet.rpl import (
|
|
6
|
-
CommunityActionValue,
|
|
7
|
-
ResultType, RoutingPolicyStatement, RoutingPolicy, ConditionOperator, SingleCondition, SingleAction, ActionType,
|
|
8
|
-
)
|
|
9
|
-
from annet.rpl.statement_builder import AsPathActionValue, NextHopActionValue
|
|
10
|
-
from annet.storage import Storage
|
|
11
|
-
from .items import AS_PATH_FILTERS, COMMUNITIES, EXT_COMMUNITIES
|
|
12
|
-
from .route_policy import routemap
|
|
13
|
-
|
|
14
|
-
HUAWEI_MATCH_COMMAND_MAP = {
|
|
15
|
-
"as_path_filter": "as-path-filter {option_value}",
|
|
16
|
-
"metric": "cost {option_value}",
|
|
17
|
-
"protocol": "protocol {option_value}",
|
|
18
|
-
"interface": "interface {option_value}",
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
HUAWEI_THEN_COMMAND_MAP = {
|
|
22
|
-
"metric": "cost {option_value}",
|
|
23
|
-
"local_pref": "local-preference {option_value}",
|
|
24
|
-
"metric_type": "cost-type {option_value}",
|
|
25
|
-
"mpls_label": "mpls-label",
|
|
26
|
-
"origin": "origin {option_value}",
|
|
27
|
-
"tag": "tag {option_value}",
|
|
28
|
-
# unsupported: resolution
|
|
29
|
-
# unsupported: rpki_valid_state
|
|
30
|
-
}
|
|
31
|
-
HUAWEI_RESULT_MAP = {
|
|
32
|
-
ResultType.ALLOW: "permit",
|
|
33
|
-
ResultType.DENY: "deny",
|
|
34
|
-
ResultType.NEXT: ""
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class RoutingPolicyGenerator(PartialGenerator):
|
|
39
|
-
TAGS = ["policy", "rpl", "routing"]
|
|
40
|
-
|
|
41
|
-
def acl_huawei(self, _):
|
|
42
|
-
return r"""
|
|
43
|
-
ip as-path-filter
|
|
44
|
-
route-policy *
|
|
45
|
-
~ %global=1
|
|
46
|
-
"""
|
|
47
|
-
|
|
48
|
-
def _huawei_match(self, device, condition: SingleCondition[Any]) -> Iterator[Sequence[str]]:
|
|
49
|
-
if condition.field == "community":
|
|
50
|
-
if condition.operator is ConditionOperator.HAS:
|
|
51
|
-
if len(condition.value) > 1:
|
|
52
|
-
raise NotImplementedError("Multiple HAS for communities is not supported for huawei")
|
|
53
|
-
elif condition.operator is not ConditionOperator.HAS_ANY:
|
|
54
|
-
raise NotImplementedError("Community operator %r not supported for huawei" % condition.operator)
|
|
55
|
-
for comm_name in condition.value:
|
|
56
|
-
yield "if-match community-filter", comm_name
|
|
57
|
-
return
|
|
58
|
-
if condition.field == "extcommunity":
|
|
59
|
-
if condition.operator is ConditionOperator.HAS:
|
|
60
|
-
if len(condition.value) > 1:
|
|
61
|
-
raise NotImplementedError("Multiple HAS for extcommunities is not supported for huawei")
|
|
62
|
-
elif condition.operator is not ConditionOperator.HAS_ANY:
|
|
63
|
-
raise NotImplementedError("Extcommunity operator %r not supported for huawei" % condition.operator)
|
|
64
|
-
for comm_name in condition.value:
|
|
65
|
-
yield "if-match extcommunity-filter", comm_name
|
|
66
|
-
return
|
|
67
|
-
if condition.field == "ip_prefix":
|
|
68
|
-
for name in condition.value.names:
|
|
69
|
-
yield "if-match", "ip-prefix-filter", name
|
|
70
|
-
return
|
|
71
|
-
if condition.field == "ipv6_prefix":
|
|
72
|
-
for name in condition.value.names:
|
|
73
|
-
yield "if-match", "ipv6 address prefix-list", name
|
|
74
|
-
return
|
|
75
|
-
if condition.field == "as_path_length":
|
|
76
|
-
if condition.operator is ConditionOperator.EQ:
|
|
77
|
-
yield "if-match", "as-path length", condition.value
|
|
78
|
-
elif condition.operator is ConditionOperator.LE:
|
|
79
|
-
yield "if-match", "as-path length less-equal", condition.value
|
|
80
|
-
elif condition.operator is ConditionOperator.GE:
|
|
81
|
-
yield "if-match", "as-path length greater-equal", condition.value
|
|
82
|
-
elif condition.operator is ConditionOperator.BETWEEN_INCLUDED:
|
|
83
|
-
yield "if-match", "as-path length greater-equal", condition.value[0], "less-equal", condition.value[1]
|
|
84
|
-
else:
|
|
85
|
-
raise NotImplementedError(
|
|
86
|
-
f"as_path_length operator {condition.operator} not supported for huawei",
|
|
87
|
-
)
|
|
88
|
-
return
|
|
89
|
-
if condition.operator is not ConditionOperator.EQ:
|
|
90
|
-
raise NotImplementedError(
|
|
91
|
-
f"`{condition.field}` with operator {condition.operator} is not supported for huawei",
|
|
92
|
-
)
|
|
93
|
-
if condition.field not in HUAWEI_MATCH_COMMAND_MAP:
|
|
94
|
-
raise NotImplementedError(f"Match using `{condition.field}` is not supported for huawei")
|
|
95
|
-
cmd = HUAWEI_MATCH_COMMAND_MAP[condition.field]
|
|
96
|
-
yield "if-match", cmd.format(option_value=condition.value)
|
|
97
|
-
|
|
98
|
-
def _huawei_then_community(self, action: SingleAction[CommunityActionValue]) -> Iterator[Sequence[str]]:
|
|
99
|
-
if action.value.replaced is not None:
|
|
100
|
-
if not action.value.replaced:
|
|
101
|
-
yield "apply", "community", "none"
|
|
102
|
-
first = True
|
|
103
|
-
for community_name in action.value.replaced:
|
|
104
|
-
community = COMMUNITIES[community_name]
|
|
105
|
-
for comm_value in community.values:
|
|
106
|
-
if first:
|
|
107
|
-
yield "apply", "community", comm_value
|
|
108
|
-
first = False
|
|
109
|
-
else:
|
|
110
|
-
yield "apply", "community", comm_value, "additive"
|
|
111
|
-
for community_name in action.value.added:
|
|
112
|
-
community = COMMUNITIES[community_name]
|
|
113
|
-
for comm_value in community.values:
|
|
114
|
-
yield "apply", "community", comm_value, "additive"
|
|
115
|
-
for community_name in action.value.removed:
|
|
116
|
-
yield "apply comm-filter", community_name, "delete"
|
|
117
|
-
|
|
118
|
-
def _huawei_then_extcommunity(self, action: SingleAction[CommunityActionValue]) -> Iterator[Sequence[str]]:
|
|
119
|
-
if action.value.replaced is not None:
|
|
120
|
-
if not action.value.replaced:
|
|
121
|
-
yield "apply", "extcommunity", "none"
|
|
122
|
-
first = True
|
|
123
|
-
for community_name in action.value.replaced:
|
|
124
|
-
community = EXT_COMMUNITIES[community_name]
|
|
125
|
-
for comm_value in community.values:
|
|
126
|
-
if first:
|
|
127
|
-
yield "apply", "extcommunity", comm_value
|
|
128
|
-
first = False
|
|
129
|
-
else:
|
|
130
|
-
yield "apply", "extcommunity", comm_value, "additive"
|
|
131
|
-
for community_name in action.value.added:
|
|
132
|
-
community = EXT_COMMUNITIES[community_name]
|
|
133
|
-
for comm_value in community.values:
|
|
134
|
-
yield "apply", "extcommunity", comm_value, "additive"
|
|
135
|
-
for community_name in action.value.removed:
|
|
136
|
-
yield "apply extcommunity-filter", community_name, "delete"
|
|
137
|
-
|
|
138
|
-
def _huawei_then(self, device, action: SingleAction[Any]) -> Iterator[Sequence[str]]:
|
|
139
|
-
if action.field == "community":
|
|
140
|
-
yield from self._huawei_then_community(cast(SingleAction[CommunityActionValue], action))
|
|
141
|
-
return
|
|
142
|
-
if action.field == "extcommunity":
|
|
143
|
-
yield from self._huawei_then_extcommunity(cast(SingleAction[CommunityActionValue], action))
|
|
144
|
-
return
|
|
145
|
-
if action.field == "metric":
|
|
146
|
-
if action.type is ActionType.ADD:
|
|
147
|
-
yield "apply", f"cost + {action.value}"
|
|
148
|
-
elif action.type is ActionType.SET:
|
|
149
|
-
yield "apply", f"cost {action.value}"
|
|
150
|
-
else:
|
|
151
|
-
raise NotImplementedError(f"Action type {action.type} for metric is not supported for huawei")
|
|
152
|
-
return
|
|
153
|
-
if action.field == "as_path":
|
|
154
|
-
as_path_action_value = cast(AsPathActionValue, action.value)
|
|
155
|
-
if as_path_action_value.set is not None:
|
|
156
|
-
if not as_path_action_value.set:
|
|
157
|
-
yield "apply", "as_path", "none overwrite"
|
|
158
|
-
first = True
|
|
159
|
-
for path_item in as_path_action_value.set:
|
|
160
|
-
if first:
|
|
161
|
-
yield "apply as-path", path_item, "overwrite"
|
|
162
|
-
first = False
|
|
163
|
-
else:
|
|
164
|
-
yield "apply as-path", path_item, "additive"
|
|
165
|
-
if as_path_action_value.prepend:
|
|
166
|
-
for path_item in as_path_action_value.prepend:
|
|
167
|
-
yield "apply as-path", path_item, "additive"
|
|
168
|
-
if as_path_action_value.expand: # same as prepend?
|
|
169
|
-
for path_item in as_path_action_value.expand:
|
|
170
|
-
yield "apply as-path", path_item, "additive"
|
|
171
|
-
if as_path_action_value.delete:
|
|
172
|
-
for path_item in as_path_action_value.delete:
|
|
173
|
-
yield "apply as-path", path_item, "delete"
|
|
174
|
-
if as_path_action_value.expand_last_as:
|
|
175
|
-
raise RuntimeError("asp_path.expand_last_as is not supported for huawei")
|
|
176
|
-
return
|
|
177
|
-
if action.field == "next_hop":
|
|
178
|
-
next_hop_action_value = cast(NextHopActionValue, action.value)
|
|
179
|
-
if next_hop_action_value.target == "self":
|
|
180
|
-
yield "apply", "cost 1"
|
|
181
|
-
elif next_hop_action_value.target == "discard":
|
|
182
|
-
pass
|
|
183
|
-
elif next_hop_action_value.target == "peer":
|
|
184
|
-
pass
|
|
185
|
-
elif next_hop_action_value.target == "ipv4_addr":
|
|
186
|
-
yield "apply", f"ip-address next-hop {next_hop_action_value.addr}"
|
|
187
|
-
elif next_hop_action_value.target == "ipv6_addr":
|
|
188
|
-
yield "apply", f"ipv6 next-hop {next_hop_action_value.addr}"
|
|
189
|
-
elif next_hop_action_value.target == "mapped_ipv4":
|
|
190
|
-
yield "apply", f"ipv6 next-hop ::FFFF:{next_hop_action_value.addr}"
|
|
191
|
-
else:
|
|
192
|
-
raise RuntimeError(f"Next_hop target {next_hop_action_value.target} is not supported for huawei")
|
|
193
|
-
|
|
194
|
-
if action.type is not ActionType.SET:
|
|
195
|
-
raise NotImplementedError(f"Action type {action.type} for `{action.field}` is not supported for huawei")
|
|
196
|
-
if action.field not in HUAWEI_THEN_COMMAND_MAP:
|
|
197
|
-
raise NotImplementedError(f"Then action using `{action.field}` is not supported for huawei")
|
|
198
|
-
cmd = HUAWEI_THEN_COMMAND_MAP[action.field]
|
|
199
|
-
yield "apply", cmd.format(option_value=action.value)
|
|
200
|
-
|
|
201
|
-
def _huawei_statement(
|
|
202
|
-
self, device, policy: RoutingPolicy, statement: RoutingPolicyStatement,
|
|
203
|
-
) -> Iterator[Sequence[str]]:
|
|
204
|
-
if "as_path_filter" in statement.match:
|
|
205
|
-
as_path_condition = statement.match["as_path_filter"]
|
|
206
|
-
as_filter_value = AS_PATH_FILTERS[as_path_condition.value]
|
|
207
|
-
yield "ip as-path-filter", \
|
|
208
|
-
as_path_condition.value, \
|
|
209
|
-
"index 10 permit", \
|
|
210
|
-
"_{}_".format("_".join(("%s" % x for x in as_filter_value if x != ".*")))
|
|
211
|
-
|
|
212
|
-
with self.block(
|
|
213
|
-
"route-policy", policy.name,
|
|
214
|
-
HUAWEI_RESULT_MAP[statement.result],
|
|
215
|
-
"node", statement.number
|
|
216
|
-
):
|
|
217
|
-
for condition in statement.match:
|
|
218
|
-
yield from self._huawei_match(device, condition)
|
|
219
|
-
for action in statement.then:
|
|
220
|
-
yield from self._huawei_then(device, action)
|
|
221
|
-
if statement.result is ResultType.NEXT:
|
|
222
|
-
yield "goto next-node"
|
|
223
|
-
|
|
224
|
-
def run_huawei(self, device):
|
|
225
|
-
for policy in routemap.apply(device):
|
|
226
|
-
for statement in policy.statements:
|
|
227
|
-
yield from self._huawei_statement(device, policy, statement)
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
def get_generators(store: Storage) -> list[BaseGenerator]:
|
|
231
|
-
return [
|
|
232
|
-
RoutingPolicyGenerator(store),
|
|
233
|
-
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|