]>
Commit | Line | Data |
---|---|---|
4d7b695d SM |
1 | /* |
2 | * Copyright (C) 2020 NetDEF, Inc. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms of the GNU General Public License as published by the Free | |
6 | * Software Foundation; either version 2 of the License, or (at your option) | |
7 | * any later version. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
12 | * more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License along | |
15 | * with this program; see the file COPYING; if not, write to the Free Software | |
16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
17 | */ | |
18 | ||
1f8031f7 DL |
19 | #include <zebra.h> |
20 | ||
4d7b695d SM |
21 | #include <float.h> |
22 | #include <math.h> | |
23 | #include <zebra.h> | |
24 | ||
c7479286 | 25 | #include "memory.h" |
4d7b695d SM |
26 | #include "log.h" |
27 | #include "command.h" | |
28 | #include "mpls.h" | |
29 | #include "northbound_cli.h" | |
30 | #include "termtable.h" | |
31 | ||
32 | #include "pathd/pathd.h" | |
33 | #include "pathd/path_nb.h" | |
4d7b695d | 34 | #include "pathd/path_cli_clippy.c" |
f2b9485d | 35 | #include "pathd/path_ted.h" |
4d7b695d SM |
36 | |
37 | #define XPATH_MAXATTRSIZE 64 | |
38 | #define XPATH_MAXKEYSIZE 42 | |
39 | #define XPATH_POLICY_BASELEN 100 | |
40 | #define XPATH_POLICY_MAXLEN (XPATH_POLICY_BASELEN + XPATH_MAXATTRSIZE) | |
41 | #define XPATH_CANDIDATE_BASELEN (XPATH_POLICY_BASELEN + XPATH_MAXKEYSIZE) | |
42 | #define XPATH_CANDIDATE_MAXLEN (XPATH_CANDIDATE_BASELEN + XPATH_MAXATTRSIZE) | |
43 | ||
44 | ||
45 | static int config_write_segment_routing(struct vty *vty); | |
f2b9485d JG |
46 | static int segment_list_has_src_dst( |
47 | struct vty *vty, char *xpath, long index, const char *index_str, | |
48 | struct in_addr adj_src_ipv4, struct in_addr adj_dst_ipv4, | |
49 | struct in6_addr adj_src_ipv6, struct in6_addr adj_dst_ipv6, | |
50 | const char *adj_src_ipv4_str, const char *adj_dst_ipv4_str, | |
51 | const char *adj_src_ipv6_str, const char *adj_dst_ipv6_str); | |
52 | static int segment_list_has_prefix( | |
53 | struct vty *vty, char *xpath, long index, const char *index_str, | |
54 | const struct prefix_ipv4 *prefix_ipv4, const char *prefix_ipv4_str, | |
55 | const struct prefix_ipv6 *prefix_ipv6, const char *prefix_ipv6_str, | |
56 | const char *has_algo, long algo, const char *algo_str, | |
57 | const char *has_iface_id, long iface_id, const char *iface_id_str); | |
4d7b695d | 58 | |
bf8d3d6a | 59 | DEFINE_MTYPE_STATIC(PATHD, PATH_CLI, "Client"); |
4d7b695d | 60 | |
ac9103aa IR |
61 | DEFINE_HOOK(pathd_srte_config_write, (struct vty *vty), (vty)); |
62 | ||
4d7b695d SM |
63 | /* Vty node structures. */ |
64 | static struct cmd_node segment_routing_node = { | |
65 | .name = "segment-routing", | |
66 | .node = SEGMENT_ROUTING_NODE, | |
67 | .parent_node = CONFIG_NODE, | |
68 | .prompt = "%s(config-sr)# ", | |
69 | .config_write = config_write_segment_routing, | |
70 | }; | |
71 | ||
72 | static struct cmd_node sr_traffic_eng_node = { | |
73 | .name = "sr traffic-eng", | |
74 | .node = SR_TRAFFIC_ENG_NODE, | |
75 | .parent_node = SEGMENT_ROUTING_NODE, | |
76 | .prompt = "%s(config-sr-te)# ", | |
4d7b695d SM |
77 | }; |
78 | ||
79 | static struct cmd_node srte_segment_list_node = { | |
80 | .name = "srte segment-list", | |
81 | .node = SR_SEGMENT_LIST_NODE, | |
82 | .parent_node = SR_TRAFFIC_ENG_NODE, | |
83 | .prompt = "%s(config-sr-te-segment-list)# ", | |
4d7b695d SM |
84 | }; |
85 | ||
86 | static struct cmd_node srte_policy_node = { | |
87 | .name = "srte policy", | |
88 | .node = SR_POLICY_NODE, | |
89 | .parent_node = SR_TRAFFIC_ENG_NODE, | |
90 | .prompt = "%s(config-sr-te-policy)# ", | |
4d7b695d SM |
91 | }; |
92 | ||
93 | static struct cmd_node srte_candidate_dyn_node = { | |
94 | .name = "srte candidate-dyn", | |
95 | .node = SR_CANDIDATE_DYN_NODE, | |
96 | .parent_node = SR_POLICY_NODE, | |
97 | .prompt = "%s(config-sr-te-candidate)# ", | |
98 | }; | |
99 | ||
100 | ||
101 | /* | |
102 | * Show SR-TE info | |
103 | */ | |
104 | DEFPY(show_srte_policy, | |
105 | show_srte_policy_cmd, | |
106 | "show sr-te policy", | |
107 | SHOW_STR | |
108 | "SR-TE info\n" | |
109 | "SR-TE Policy\n") | |
110 | { | |
111 | struct ttable *tt; | |
112 | struct srte_policy *policy; | |
113 | char *table; | |
114 | ||
115 | if (RB_EMPTY(srte_policy_head, &srte_policies)) { | |
116 | vty_out(vty, "No SR Policies to display.\n\n"); | |
117 | return CMD_SUCCESS; | |
118 | } | |
119 | ||
120 | /* Prepare table. */ | |
121 | tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); | |
122 | ttable_add_row(tt, "Endpoint|Color|Name|BSID|Status"); | |
123 | tt->style.cell.rpad = 2; | |
124 | tt->style.corner = '+'; | |
125 | ttable_restyle(tt); | |
126 | ttable_rowseps(tt, 0, BOTTOM, true, '-'); | |
127 | ||
128 | RB_FOREACH (policy, srte_policy_head, &srte_policies) { | |
c1657d26 | 129 | char endpoint[ENDPOINT_STR_LENGTH]; |
4d7b695d SM |
130 | char binding_sid[16] = "-"; |
131 | ||
132 | ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint)); | |
133 | if (policy->binding_sid != MPLS_LABEL_NONE) | |
134 | snprintf(binding_sid, sizeof(binding_sid), "%u", | |
135 | policy->binding_sid); | |
136 | ||
137 | ttable_add_row(tt, "%s|%u|%s|%s|%s", endpoint, policy->color, | |
138 | policy->name, binding_sid, | |
139 | policy->status == SRTE_POLICY_STATUS_UP | |
140 | ? "Active" | |
141 | : "Inactive"); | |
142 | } | |
143 | ||
144 | /* Dump the generated table. */ | |
145 | table = ttable_dump(tt, "\n"); | |
146 | vty_out(vty, "%s\n", table); | |
147 | XFREE(MTYPE_TMP, table); | |
148 | ||
149 | ttable_del(tt); | |
150 | ||
151 | return CMD_SUCCESS; | |
152 | } | |
153 | ||
f2b9485d | 154 | |
4d7b695d SM |
155 | /* |
156 | * Show detailed SR-TE info | |
157 | */ | |
158 | DEFPY(show_srte_policy_detail, | |
159 | show_srte_policy_detail_cmd, | |
160 | "show sr-te policy detail", | |
161 | SHOW_STR | |
162 | "SR-TE info\n" | |
163 | "SR-TE Policy\n" | |
164 | "Show a detailed summary\n") | |
165 | { | |
166 | struct srte_policy *policy; | |
167 | ||
168 | if (RB_EMPTY(srte_policy_head, &srte_policies)) { | |
169 | vty_out(vty, "No SR Policies to display.\n\n"); | |
170 | return CMD_SUCCESS; | |
171 | } | |
172 | ||
173 | vty_out(vty, "\n"); | |
174 | RB_FOREACH (policy, srte_policy_head, &srte_policies) { | |
175 | struct srte_candidate *candidate; | |
c1657d26 | 176 | char endpoint[ENDPOINT_STR_LENGTH]; |
4d7b695d SM |
177 | char binding_sid[16] = "-"; |
178 | char *segment_list_info; | |
179 | static char undefined_info[] = "(undefined)"; | |
180 | static char created_by_pce_info[] = "(created by PCE)"; | |
181 | ||
182 | ||
183 | ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint)); | |
184 | if (policy->binding_sid != MPLS_LABEL_NONE) | |
185 | snprintf(binding_sid, sizeof(binding_sid), "%u", | |
186 | policy->binding_sid); | |
187 | vty_out(vty, | |
188 | "Endpoint: %s Color: %u Name: %s BSID: %s Status: %s\n", | |
189 | endpoint, policy->color, policy->name, binding_sid, | |
190 | policy->status == SRTE_POLICY_STATUS_UP ? "Active" | |
191 | : "Inactive"); | |
192 | ||
193 | RB_FOREACH (candidate, srte_candidate_head, | |
194 | &policy->candidate_paths) { | |
195 | struct srte_segment_list *segment_list; | |
196 | ||
197 | segment_list = candidate->lsp->segment_list; | |
198 | if (segment_list == NULL) | |
199 | segment_list_info = undefined_info; | |
200 | else if (segment_list->protocol_origin | |
201 | == SRTE_ORIGIN_PCEP) | |
202 | segment_list_info = created_by_pce_info; | |
203 | else | |
204 | segment_list_info = | |
205 | candidate->lsp->segment_list->name; | |
206 | ||
207 | vty_out(vty, | |
208 | " %s Preference: %d Name: %s Type: %s Segment-List: %s Protocol-Origin: %s\n", | |
209 | CHECK_FLAG(candidate->flags, F_CANDIDATE_BEST) | |
210 | ? "*" | |
211 | : " ", | |
212 | candidate->preference, candidate->name, | |
213 | candidate->type == SRTE_CANDIDATE_TYPE_EXPLICIT | |
214 | ? "explicit" | |
215 | : "dynamic", | |
216 | segment_list_info, | |
217 | srte_origin2str( | |
218 | candidate->lsp->protocol_origin)); | |
219 | } | |
220 | ||
221 | vty_out(vty, "\n"); | |
222 | } | |
223 | ||
224 | return CMD_SUCCESS; | |
225 | } | |
226 | ||
227 | DEFPY_NOSH( | |
228 | segment_routing_list, | |
229 | segment_routing_cmd, | |
230 | "segment-routing", | |
231 | "Configure segment routing\n") | |
232 | { | |
233 | VTY_PUSH_CONTEXT_NULL(SEGMENT_ROUTING_NODE); | |
234 | return CMD_SUCCESS; | |
235 | } | |
236 | ||
237 | DEFPY_NOSH( | |
238 | sr_traffic_eng_list, | |
239 | sr_traffic_eng_cmd, | |
240 | "traffic-eng", | |
241 | "Configure SR traffic engineering\n") | |
242 | { | |
243 | VTY_PUSH_CONTEXT_NULL(SR_TRAFFIC_ENG_NODE); | |
244 | return CMD_SUCCESS; | |
245 | } | |
246 | ||
247 | /* | |
248 | * XPath: /frr-pathd:pathd/srte/segment-list | |
249 | */ | |
250 | DEFPY_NOSH( | |
251 | srte_segment_list, | |
252 | srte_segment_list_cmd, | |
253 | "segment-list WORD$name", | |
254 | "Segment List\n" | |
255 | "Segment List Name\n") | |
256 | { | |
257 | char xpath[XPATH_MAXLEN]; | |
258 | int ret; | |
259 | ||
260 | snprintf(xpath, sizeof(xpath), | |
261 | "/frr-pathd:pathd/srte/segment-list[name='%s']", name); | |
262 | nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); | |
263 | ||
264 | snprintf(xpath, sizeof(xpath), | |
265 | "/frr-pathd:pathd/srte/segment-list[name='%s']/protocol-origin", | |
266 | name); | |
267 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "local"); | |
268 | ||
269 | snprintf(xpath, sizeof(xpath), | |
270 | "/frr-pathd:pathd/srte/segment-list[name='%s']/originator", name); | |
271 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "config"); | |
272 | ||
273 | ret = nb_cli_apply_changes(vty, NULL); | |
274 | if (ret == CMD_SUCCESS) { | |
275 | snprintf(xpath, sizeof(xpath), | |
276 | "/frr-pathd:pathd/srte/segment-list[name='%s']", name); | |
277 | VTY_PUSH_XPATH(SR_SEGMENT_LIST_NODE, xpath); | |
278 | } | |
279 | ||
280 | return ret; | |
281 | } | |
282 | ||
283 | DEFPY(srte_no_segment_list, | |
284 | srte_no_segment_list_cmd, | |
285 | "no segment-list WORD$name", | |
286 | NO_STR | |
287 | "Segment List\n" | |
288 | "Segment List Name\n") | |
289 | { | |
290 | char xpath[XPATH_MAXLEN]; | |
291 | ||
292 | snprintf(xpath, sizeof(xpath), | |
293 | "/frr-pathd:pathd/srte/segment-list[name='%s']", name); | |
294 | nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); | |
295 | ||
296 | return nb_cli_apply_changes(vty, NULL); | |
297 | } | |
298 | ||
25605051 | 299 | void cli_show_srte_segment_list(struct vty *vty, const struct lyd_node *dnode, |
4d7b695d SM |
300 | bool show_defaults) |
301 | { | |
302 | vty_out(vty, " segment-list %s\n", | |
303 | yang_dnode_get_string(dnode, "./name")); | |
304 | } | |
305 | ||
25605051 IR |
306 | void cli_show_srte_segment_list_end(struct vty *vty, |
307 | const struct lyd_node *dnode) | |
07679ad9 IR |
308 | { |
309 | vty_out(vty, " exit\n"); | |
310 | } | |
311 | ||
f2b9485d JG |
312 | static int segment_list_has_src_dst( |
313 | struct vty *vty, char *xpath, long index, const char *index_str, | |
314 | struct in_addr adj_src_ipv4, struct in_addr adj_dst_ipv4, | |
315 | struct in6_addr adj_src_ipv6, struct in6_addr adj_dst_ipv6, | |
316 | const char *adj_src_ipv4_str, const char *adj_dst_ipv4_str, | |
317 | const char *adj_src_ipv6_str, const char *adj_dst_ipv6_str) | |
318 | { | |
319 | const char *node_src_id; | |
320 | uint32_t ted_sid = MPLS_LABEL_NONE; | |
321 | ||
322 | struct ipaddr ip_src = {}; | |
323 | struct ipaddr ip_dst = {}; | |
324 | if (adj_src_ipv4_str != NULL) { | |
325 | ip_src.ipa_type = IPADDR_V4; | |
326 | ip_src.ip._v4_addr = adj_src_ipv4; | |
327 | ip_dst.ipa_type = IPADDR_V4; | |
328 | ip_dst.ip._v4_addr = adj_dst_ipv4; | |
329 | } else if (adj_src_ipv6_str != NULL) { | |
330 | ip_src.ipa_type = IPADDR_V6; | |
331 | ip_src.ip._v6_addr = adj_src_ipv6; | |
332 | ip_dst.ipa_type = IPADDR_V6; | |
333 | ip_dst.ip._v6_addr = adj_dst_ipv6; | |
334 | } else { | |
335 | return CMD_ERR_NO_MATCH; | |
336 | } | |
337 | ted_sid = path_ted_query_type_f(&ip_src, &ip_dst); | |
338 | if (ted_sid == MPLS_LABEL_NONE) { | |
339 | zlog_warn( | |
340 | "%s: [rcv ted] CLI NOT FOUND Continue query_type_f SRC (%pIA) DST (%pIA)!", | |
341 | __func__, &ip_src, &ip_dst); | |
342 | } | |
343 | /* type */ | |
344 | snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/type", | |
345 | index_str); | |
346 | if (adj_src_ipv4_str != NULL) { | |
347 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, | |
348 | "ipv4_adjacency"); | |
349 | node_src_id = adj_src_ipv4_str; | |
350 | } else if (adj_src_ipv6_str != NULL) { | |
351 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, | |
352 | "ipv6_adjacency"); | |
353 | node_src_id = adj_src_ipv6_str; | |
e81a74a6 DS |
354 | } else { |
355 | /* | |
356 | * This is just to make the compiler happy about | |
357 | * node_src_id not being initialized. This | |
358 | * should never happen unless we change the cli | |
359 | * function. | |
360 | */ | |
361 | assert(!"We must have a adj_src_ipv4_str or a adj_src_ipv6_str"); | |
f2b9485d | 362 | } |
e81a74a6 | 363 | |
f2b9485d JG |
364 | /* addresses */ |
365 | snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/local-address", | |
366 | index_str); | |
367 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, node_src_id); | |
368 | snprintf(xpath, XPATH_MAXLEN, | |
369 | "./segment[index='%s']/nai/remote-address", index_str); | |
370 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, | |
371 | adj_dst_ipv4_str ? adj_dst_ipv4_str | |
372 | : adj_dst_ipv6_str); | |
373 | return CMD_SUCCESS; | |
374 | } | |
375 | int segment_list_has_prefix( | |
376 | struct vty *vty, char *xpath, long index, const char *index_str, | |
377 | const struct prefix_ipv4 *prefix_ipv4, const char *prefix_ipv4_str, | |
378 | const struct prefix_ipv6 *prefix_ipv6, const char *prefix_ipv6_str, | |
379 | const char *has_algo, long algo, const char *algo_str, | |
380 | const char *has_iface_id, long iface_id, const char *iface_id_str) | |
381 | { | |
382 | char buf_prefix[INET6_ADDRSTRLEN]; | |
383 | ||
384 | uint32_t ted_sid = MPLS_LABEL_NONE; | |
385 | struct prefix prefix_cli = {}; | |
386 | struct ipaddr pre_ipaddr = {}; | |
387 | /* prefix with algorithm or local interface id */ | |
388 | /* Type */ | |
389 | snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/type", | |
390 | index_str); | |
391 | if (has_iface_id != NULL) { | |
392 | if (prefix_ipv4_str != NULL) { | |
393 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, | |
394 | "ipv4_local_iface"); | |
395 | } else if (prefix_ipv6_str != NULL) { | |
396 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, | |
397 | "ipv6_local_iface"); | |
398 | } else { | |
399 | return CMD_ERR_NO_MATCH; | |
400 | } | |
401 | } else { | |
402 | if (prefix_ipv4_str != NULL) { | |
403 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, | |
404 | "ipv4_algo"); | |
405 | } else if (prefix_ipv6_str != NULL) { | |
406 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, | |
407 | "ipv6_algo"); | |
408 | } else { | |
409 | return CMD_ERR_NO_MATCH; | |
410 | } | |
411 | } | |
412 | /* Prefix */ | |
413 | if (prefix_ipv4_str != NULL) { | |
414 | if (!str2prefix(prefix_ipv4_str, &prefix_cli)) { | |
415 | vty_out(vty, "%% Malformed prefix\n"); | |
416 | return CMD_WARNING_CONFIG_FAILED; | |
417 | } | |
418 | inet_ntop(AF_INET, &prefix_cli.u.prefix4, buf_prefix, | |
419 | sizeof(buf_prefix)); | |
420 | pre_ipaddr.ipa_type = IPADDR_V4; | |
421 | pre_ipaddr.ip._v4_addr = prefix_cli.u.prefix4; | |
422 | } else if (prefix_ipv6_str != NULL) { | |
423 | if (!str2prefix(prefix_ipv6_str, &prefix_cli)) { | |
424 | vty_out(vty, "%% Malformed prefix\n"); | |
425 | return CMD_WARNING_CONFIG_FAILED; | |
426 | } | |
427 | inet_ntop(AF_INET6, &prefix_cli.u.prefix6, buf_prefix, | |
428 | sizeof(buf_prefix)); | |
429 | pre_ipaddr.ipa_type = IPADDR_V6; | |
430 | pre_ipaddr.ip._v6_addr = prefix_cli.u.prefix6; | |
f2b9485d JG |
431 | } |
432 | snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/local-address", | |
433 | index_str); | |
434 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, buf_prefix); | |
435 | snprintf(xpath, XPATH_MAXLEN, | |
436 | "./segment[index='%s']/nai/local-prefix-len", index_str); | |
437 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, | |
438 | prefix_ipv4_str | |
439 | ? strchr(prefix_ipv4_str, '/') + 1 | |
440 | : strchr(prefix_ipv6_str, '/') + 1); | |
441 | /* Alg / Iface */ | |
442 | if (has_algo != NULL) { | |
443 | snprintf(xpath, XPATH_MAXLEN, | |
444 | "./segment[index='%s']/nai/algorithm", index_str); | |
445 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, algo_str); | |
446 | } else { | |
447 | if (has_iface_id != NULL) { | |
448 | snprintf(xpath, XPATH_MAXLEN, | |
449 | "./segment[index='%s']/nai/local-interface", | |
450 | index_str); | |
451 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, | |
452 | iface_id_str); | |
453 | } | |
454 | } | |
455 | if (has_algo != NULL) { | |
456 | ted_sid = path_ted_query_type_c(&prefix_cli, algo); | |
457 | if (ted_sid == MPLS_LABEL_NONE) { | |
458 | zlog_err( | |
459 | "%s: [rcv ted] CLI NOT FOUND Continue query_type_c PREFIX (%pIA/%d) ALGO (%ld) sid:(%d)!", | |
460 | __func__, &pre_ipaddr, prefix_cli.prefixlen, | |
461 | algo, ted_sid); | |
462 | } | |
463 | } | |
464 | if (has_iface_id != NULL) { | |
465 | ted_sid = path_ted_query_type_e(&prefix_cli, iface_id); | |
466 | if (ted_sid == MPLS_LABEL_NONE) { | |
467 | zlog_err( | |
468 | "%s: [rcv ted] CLI NOT FOUND Continue query_type_e PREFIX (%pIA/%d) IFACE (%ld) sid:(%d)!", | |
469 | __func__, &pre_ipaddr, prefix_cli.prefixlen, | |
470 | iface_id, ted_sid); | |
471 | } | |
472 | } | |
473 | return CMD_SUCCESS; | |
474 | } | |
4d7b695d SM |
475 | /* |
476 | * XPath: /frr-pathd:pathd/srte/segment-list/segment | |
477 | */ | |
f2b9485d JG |
478 | /* clang-format off */ |
479 | DEFPY(srte_segment_list_segment, srte_segment_list_segment_cmd, | |
480 | "index (0-4294967295)$index <[mpls$has_mpls_label label (16-1048575)$label] " | |
481 | "|" | |
4d7b695d | 482 | "[nai$has_nai <" |
f2b9485d JG |
483 | "prefix <A.B.C.D/M$prefix_ipv4|X:X::X:X/M$prefix_ipv6>" |
484 | "<algorithm$has_algo (0-1)$algo| iface$has_iface_id (0-4294967295)$iface_id>" | |
485 | "| adjacency$has_adj " | |
486 | "<A.B.C.D$adj_src_ipv4 A.B.C.D$adj_dst_ipv4|X:X::X:X$adj_src_ipv6 X:X::X:X$adj_dst_ipv6>" | |
487 | ">]" | |
488 | ">", | |
4d7b695d SM |
489 | "Index\n" |
490 | "Index Value\n" | |
491 | "MPLS or IP Label\n" | |
492 | "Label\n" | |
493 | "Label Value\n" | |
494 | "Segment NAI\n" | |
f2b9485d JG |
495 | "NAI prefix identifier\n" |
496 | "NAI IPv4 prefix identifier\n" | |
497 | "NAI IPv6 prefix identifier\n" | |
498 | "IGP Algorithm\n" | |
499 | "Algorithm Value SPF or Strict-SPF\n" | |
500 | "Interface Id\n" | |
501 | "Interface Value\n" | |
502 | "ADJ identifier\n" | |
503 | "ADJ IPv4 src identifier\n" | |
504 | "ADJ IPv4 dst identifier\n" | |
505 | "ADJ IPv6 src identifier\n" | |
506 | "ADJ IPv6 dst identifier\n") | |
507 | /* clang-format on */ | |
4d7b695d SM |
508 | { |
509 | char xpath[XPATH_MAXLEN]; | |
f2b9485d JG |
510 | int status = CMD_SUCCESS; |
511 | ||
4d7b695d SM |
512 | |
513 | snprintf(xpath, sizeof(xpath), "./segment[index='%s']", index_str); | |
514 | nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); | |
515 | ||
f2b9485d | 516 | if (has_mpls_label != NULL) { |
4d7b695d | 517 | snprintf(xpath, sizeof(xpath), |
f2b9485d JG |
518 | "./segment[index='%s']/sid-value", index_str); |
519 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, label_str); | |
520 | return nb_cli_apply_changes(vty, NULL); | |
521 | } | |
522 | ||
523 | if (has_adj != NULL) { | |
524 | status = segment_list_has_src_dst(vty, xpath, index, index_str, | |
525 | adj_src_ipv4, adj_dst_ipv4, | |
526 | adj_src_ipv6, adj_dst_ipv6, | |
527 | adj_src_ipv4_str, adj_dst_ipv4_str, | |
a38d5b7a | 528 | adj_src_ipv6_str, adj_dst_ipv6_str); |
f2b9485d JG |
529 | if (status != CMD_SUCCESS) |
530 | return status; | |
4d7b695d | 531 | } else { |
ac57e2c9 | 532 | status = segment_list_has_prefix( |
f2b9485d JG |
533 | vty, xpath, index, index_str, prefix_ipv4, |
534 | prefix_ipv4_str, prefix_ipv6, prefix_ipv6_str, has_algo, | |
535 | algo, algo_str, has_iface_id, iface_id, iface_id_str); | |
536 | if (status != CMD_SUCCESS) | |
537 | return status; | |
4d7b695d SM |
538 | } |
539 | ||
540 | return nb_cli_apply_changes(vty, NULL); | |
541 | } | |
542 | ||
543 | DEFPY(srte_segment_list_no_segment, | |
544 | srte_segment_list_no_segment_cmd, | |
545 | "no index (0-4294967295)$index", | |
546 | NO_STR | |
547 | "Index\n" | |
548 | "Index Value\n") | |
549 | { | |
550 | char xpath[XPATH_MAXLEN]; | |
551 | ||
552 | snprintf(xpath, sizeof(xpath), "./segment[index='%s']", index_str); | |
553 | nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); | |
554 | ||
555 | return nb_cli_apply_changes(vty, NULL); | |
556 | } | |
557 | ||
558 | void cli_show_srte_segment_list_segment(struct vty *vty, | |
25605051 | 559 | const struct lyd_node *dnode, |
4d7b695d SM |
560 | bool show_defaults) |
561 | { | |
882bae36 | 562 | vty_out(vty, " index %s", yang_dnode_get_string(dnode, "./index")); |
f2b9485d JG |
563 | if (yang_dnode_exists(dnode, "./sid-value")) { |
564 | vty_out(vty, " mpls label %s", | |
565 | yang_dnode_get_string(dnode, "./sid-value")); | |
566 | } | |
4d7b695d SM |
567 | if (yang_dnode_exists(dnode, "./nai")) { |
568 | struct ipaddr addr; | |
f2b9485d JG |
569 | struct ipaddr addr_rmt; |
570 | ||
4d7b695d SM |
571 | switch (yang_dnode_get_enum(dnode, "./nai/type")) { |
572 | case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE: | |
f2b9485d JG |
573 | case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE: |
574 | case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM: | |
4d7b695d | 575 | yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); |
f2b9485d | 576 | vty_out(vty, " nai prefix %pI4", &addr.ipaddr_v4); |
4d7b695d SM |
577 | break; |
578 | case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE: | |
f2b9485d JG |
579 | case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE: |
580 | case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM: | |
4d7b695d | 581 | yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); |
f2b9485d JG |
582 | vty_out(vty, " nai prefix %pI6", &addr.ipaddr_v6); |
583 | break; | |
584 | case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY: | |
585 | yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); | |
586 | yang_dnode_get_ip(&addr_rmt, dnode, | |
587 | "./nai/remote-address"); | |
588 | vty_out(vty, " nai adjacency %pI4", &addr.ipaddr_v4); | |
589 | vty_out(vty, " %pI4", &addr_rmt.ipaddr_v4); | |
590 | break; | |
591 | case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY: | |
592 | yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); | |
593 | yang_dnode_get_ip(&addr_rmt, dnode, | |
594 | "./nai/remote-address"); | |
595 | vty_out(vty, " nai adjacency %pI6", &addr.ipaddr_v6); | |
596 | vty_out(vty, " %pI6", &addr_rmt.ipaddr_v6); | |
4d7b695d SM |
597 | break; |
598 | default: | |
599 | break; | |
600 | } | |
f2b9485d JG |
601 | if (yang_dnode_exists(dnode, "./nai/local-prefix-len")) { |
602 | vty_out(vty, "/%s", | |
603 | yang_dnode_get_string( | |
604 | dnode, "./nai/local-prefix-len")); | |
605 | } | |
606 | if (yang_dnode_exists(dnode, "./nai/local-interface")) { | |
607 | vty_out(vty, " iface %s", | |
608 | yang_dnode_get_string(dnode, | |
609 | "./nai/local-interface")); | |
610 | } | |
611 | if (yang_dnode_exists(dnode, "./nai/algorithm")) { | |
612 | vty_out(vty, " algorithm %s", | |
613 | yang_dnode_get_string(dnode, | |
614 | "./nai/algorithm")); | |
615 | } | |
4d7b695d SM |
616 | } |
617 | vty_out(vty, "\n"); | |
618 | } | |
619 | ||
620 | /* | |
621 | * XPath: /frr-pathd:pathd/policy | |
622 | */ | |
623 | DEFPY_NOSH( | |
624 | srte_policy, | |
625 | srte_policy_cmd, | |
626 | "policy color (0-4294967295)$num endpoint <A.B.C.D|X:X::X:X>$endpoint", | |
627 | "Segment Routing Policy\n" | |
628 | "SR Policy color\n" | |
629 | "SR Policy color value\n" | |
630 | "SR Policy endpoint\n" | |
631 | "SR Policy endpoint IPv4 address\n" | |
632 | "SR Policy endpoint IPv6 address\n") | |
633 | { | |
634 | char xpath[XPATH_POLICY_BASELEN]; | |
635 | int ret; | |
636 | ||
637 | snprintf(xpath, sizeof(xpath), | |
638 | "/frr-pathd:pathd/srte/policy[color='%s'][endpoint='%s']", | |
639 | num_str, endpoint_str); | |
640 | nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); | |
641 | ||
642 | ret = nb_cli_apply_changes(vty, NULL); | |
643 | if (ret == CMD_SUCCESS) | |
644 | VTY_PUSH_XPATH(SR_POLICY_NODE, xpath); | |
645 | ||
646 | return ret; | |
647 | } | |
648 | ||
649 | DEFPY(srte_no_policy, | |
650 | srte_no_policy_cmd, | |
651 | "no policy color (0-4294967295)$num endpoint <A.B.C.D|X:X::X:X>$endpoint", | |
652 | NO_STR | |
653 | "Segment Routing Policy\n" | |
654 | "SR Policy color\n" | |
655 | "SR Policy color value\n" | |
656 | "SR Policy endpoint\n" | |
657 | "SR Policy endpoint IPv4 address\n" | |
658 | "SR Policy endpoint IPv6 address\n") | |
659 | { | |
660 | char xpath[XPATH_POLICY_BASELEN]; | |
661 | ||
662 | snprintf(xpath, sizeof(xpath), | |
663 | "/frr-pathd:pathd/srte/policy[color='%s'][endpoint='%s']", | |
664 | num_str, endpoint_str); | |
665 | nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); | |
666 | ||
667 | return nb_cli_apply_changes(vty, NULL); | |
668 | } | |
669 | ||
25605051 | 670 | void cli_show_srte_policy(struct vty *vty, const struct lyd_node *dnode, |
4d7b695d SM |
671 | bool show_defaults) |
672 | { | |
673 | vty_out(vty, " policy color %s endpoint %s\n", | |
674 | yang_dnode_get_string(dnode, "./color"), | |
675 | yang_dnode_get_string(dnode, "./endpoint")); | |
676 | } | |
677 | ||
25605051 | 678 | void cli_show_srte_policy_end(struct vty *vty, const struct lyd_node *dnode) |
07679ad9 IR |
679 | { |
680 | vty_out(vty, " exit\n"); | |
681 | } | |
682 | ||
4d7b695d SM |
683 | /* |
684 | * XPath: /frr-pathd:pathd/srte/policy/name | |
685 | */ | |
686 | DEFPY(srte_policy_name, | |
687 | srte_policy_name_cmd, | |
688 | "name WORD$name", | |
689 | "Segment Routing Policy name\n" | |
690 | "SR Policy name value\n") | |
691 | { | |
692 | nb_cli_enqueue_change(vty, "./name", NB_OP_CREATE, name); | |
693 | ||
694 | return nb_cli_apply_changes(vty, NULL); | |
695 | } | |
696 | ||
697 | DEFPY(srte_policy_no_name, | |
698 | srte_policy_no_name_cmd, | |
699 | "no name [WORD]", | |
700 | NO_STR | |
701 | "Segment Routing Policy name\n" | |
702 | "SR Policy name value\n") | |
703 | { | |
704 | nb_cli_enqueue_change(vty, "./name", NB_OP_DESTROY, NULL); | |
705 | ||
706 | return nb_cli_apply_changes(vty, NULL); | |
707 | } | |
708 | ||
709 | ||
25605051 IR |
710 | void cli_show_srte_policy_name(struct vty *vty, const struct lyd_node *dnode, |
711 | bool show_defaults) | |
4d7b695d SM |
712 | { |
713 | vty_out(vty, " name %s\n", yang_dnode_get_string(dnode, NULL)); | |
714 | } | |
715 | ||
716 | /* | |
717 | * XPath: /frr-pathd:pathd/srte/policy/binding-sid | |
718 | */ | |
719 | DEFPY(srte_policy_binding_sid, | |
720 | srte_policy_binding_sid_cmd, | |
721 | "binding-sid (16-1048575)$label", | |
722 | "Segment Routing Policy Binding-SID\n" | |
723 | "SR Policy Binding-SID label\n") | |
724 | { | |
725 | nb_cli_enqueue_change(vty, "./binding-sid", NB_OP_CREATE, label_str); | |
726 | ||
727 | return nb_cli_apply_changes(vty, NULL); | |
728 | } | |
729 | ||
730 | DEFPY(srte_policy_no_binding_sid, | |
731 | srte_policy_no_binding_sid_cmd, | |
732 | "no binding-sid [(16-1048575)]", | |
733 | NO_STR | |
734 | "Segment Routing Policy Binding-SID\n" | |
735 | "SR Policy Binding-SID label\n") | |
736 | { | |
737 | nb_cli_enqueue_change(vty, "./binding-sid", NB_OP_DESTROY, NULL); | |
738 | ||
739 | return nb_cli_apply_changes(vty, NULL); | |
740 | } | |
741 | ||
742 | void cli_show_srte_policy_binding_sid(struct vty *vty, | |
25605051 | 743 | const struct lyd_node *dnode, |
4d7b695d SM |
744 | bool show_defaults) |
745 | { | |
746 | vty_out(vty, " binding-sid %s\n", yang_dnode_get_string(dnode, NULL)); | |
747 | } | |
748 | ||
749 | /* | |
750 | * XPath: /frr-pathd:pathd/srte/policy/candidate-path | |
751 | */ | |
752 | DEFPY(srte_policy_candidate_exp, | |
753 | srte_policy_candidate_exp_cmd, | |
754 | "candidate-path preference (0-4294967295)$preference name WORD$name \ | |
755 | explicit segment-list WORD$list_name", | |
756 | "Segment Routing Policy Candidate Path\n" | |
757 | "Segment Routing Policy Candidate Path Preference\n" | |
758 | "Administrative Preference\n" | |
759 | "Segment Routing Policy Candidate Path Name\n" | |
760 | "Symbolic Name\n" | |
761 | "Explicit Path\n" | |
762 | "List of SIDs\n" | |
763 | "Name of the Segment List\n") | |
764 | { | |
765 | nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, preference_str); | |
766 | nb_cli_enqueue_change(vty, "./name", NB_OP_MODIFY, name); | |
767 | nb_cli_enqueue_change(vty, "./protocol-origin", NB_OP_MODIFY, "local"); | |
768 | nb_cli_enqueue_change(vty, "./originator", NB_OP_MODIFY, "config"); | |
769 | nb_cli_enqueue_change(vty, "./type", NB_OP_MODIFY, "explicit"); | |
770 | nb_cli_enqueue_change(vty, "./segment-list-name", NB_OP_MODIFY, | |
771 | list_name); | |
772 | return nb_cli_apply_changes(vty, "./candidate-path[preference='%s']", | |
773 | preference_str); | |
774 | } | |
775 | ||
776 | DEFPY_NOSH( | |
777 | srte_policy_candidate_dyn, | |
778 | srte_policy_candidate_dyn_cmd, | |
779 | "candidate-path preference (0-4294967295)$preference name WORD$name dynamic", | |
780 | "Segment Routing Policy Candidate Path\n" | |
781 | "Segment Routing Policy Candidate Path Preference\n" | |
782 | "Administrative Preference\n" | |
783 | "Segment Routing Policy Candidate Path Name\n" | |
784 | "Symbolic Name\n" | |
785 | "Dynamic Path\n") | |
786 | { | |
938b2b79 | 787 | char xpath[XPATH_MAXLEN + XPATH_CANDIDATE_BASELEN]; |
4d7b695d SM |
788 | int ret; |
789 | ||
790 | snprintf(xpath, sizeof(xpath), "%s/candidate-path[preference='%s']", | |
791 | VTY_CURR_XPATH, preference_str); | |
792 | ||
793 | nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, preference_str); | |
794 | nb_cli_enqueue_change(vty, "./name", NB_OP_MODIFY, name); | |
795 | nb_cli_enqueue_change(vty, "./protocol-origin", NB_OP_MODIFY, "local"); | |
796 | nb_cli_enqueue_change(vty, "./originator", NB_OP_MODIFY, "config"); | |
797 | nb_cli_enqueue_change(vty, "./type", NB_OP_MODIFY, "dynamic"); | |
798 | ret = nb_cli_apply_changes(vty, "./candidate-path[preference='%s']", | |
799 | preference_str); | |
800 | ||
801 | if (ret == CMD_SUCCESS) | |
802 | VTY_PUSH_XPATH(SR_CANDIDATE_DYN_NODE, xpath); | |
803 | ||
804 | return ret; | |
805 | } | |
806 | ||
807 | DEFPY(srte_candidate_bandwidth, | |
808 | srte_candidate_bandwidth_cmd, | |
809 | "bandwidth BANDWIDTH$value [required$required]", | |
810 | "Define a bandwidth constraint\n" | |
811 | "Bandwidth value\n" | |
812 | "Required constraint\n") | |
813 | { | |
814 | nb_cli_enqueue_change(vty, "./constraints/bandwidth/required", | |
815 | NB_OP_MODIFY, required ? "true" : "false"); | |
816 | nb_cli_enqueue_change(vty, "./constraints/bandwidth/value", | |
817 | NB_OP_MODIFY, value); | |
818 | return nb_cli_apply_changes(vty, NULL); | |
819 | } | |
820 | ||
821 | DEFPY(srte_candidate_no_bandwidth, | |
822 | srte_candidate_no_bandwidth_cmd, | |
823 | "no bandwidth [BANDWIDTH$value] [required$required]", | |
824 | NO_STR | |
825 | "Remove a bandwidth constraint\n" | |
826 | "Bandwidth value\n" | |
827 | "Required constraint\n") | |
828 | { | |
829 | nb_cli_enqueue_change(vty, "./constraints/bandwidth", NB_OP_DESTROY, | |
830 | NULL); | |
831 | return nb_cli_apply_changes(vty, NULL); | |
832 | } | |
833 | ||
839e6ce5 JG |
834 | DEFPY(srte_candidate_affinity_filter, srte_candidate_affinity_filter_cmd, |
835 | "affinity <exclude-any|include-any|include-all>$type BITPATTERN$value", | |
4d7b695d SM |
836 | "Affinity constraint\n" |
837 | "Exclude any matching link\n" | |
838 | "Include any matching link\n" | |
839 | "Include all matching links\n" | |
840 | "Attribute filter bit pattern as an hexadecimal value from 0x00000000 to 0xFFFFFFFF\n") | |
841 | { | |
842 | uint32_t filter; | |
843 | char xpath[XPATH_CANDIDATE_MAXLEN]; | |
844 | char decimal_value[11]; | |
845 | ||
846 | if (sscanf(value, "0x%x", &filter) != 1) { | |
847 | vty_out(vty, "affinity type: fscanf: %s\n", | |
848 | safe_strerror(errno)); | |
849 | return CMD_WARNING_CONFIG_FAILED; | |
850 | } | |
851 | snprintf(decimal_value, sizeof(decimal_value), "%u", filter); | |
852 | snprintf(xpath, sizeof(xpath), "./constraints/affinity/%s", type); | |
853 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, decimal_value); | |
854 | ||
855 | return nb_cli_apply_changes(vty, NULL); | |
856 | } | |
857 | ||
839e6ce5 JG |
858 | DEFPY(srte_candidate_no_affinity_filter, srte_candidate_no_affinity_filter_cmd, |
859 | "no affinity <exclude-any|include-any|include-all>$type [BITPATTERN$value]", | |
4d7b695d SM |
860 | NO_STR |
861 | "Affinity constraint\n" | |
862 | "Exclude any matching link\n" | |
863 | "Include any matching link\n" | |
864 | "Include all matching links\n" | |
865 | "Attribute filter bit pattern as an hexadecimal value from 0x00000000 to 0xFFFFFFFF\n") | |
866 | { | |
867 | char xpath[XPATH_CANDIDATE_MAXLEN]; | |
868 | ||
869 | snprintf(xpath, sizeof(xpath), "./constraints/affinity/%s", type); | |
870 | nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); | |
871 | return nb_cli_apply_changes(vty, NULL); | |
872 | } | |
873 | ||
874 | DEFPY(srte_candidate_metric, | |
875 | srte_candidate_metric_cmd, | |
876 | "metric [bound$bound] <igp|te|hc|abc|lmll|cigp|cte|pigp|pte|phc|msd|pd|pdv|pl|ppd|ppdv|ppl|nap|nlp|dc|bnc>$type METRIC$value [required$required]", | |
877 | "Define a metric constraint\n" | |
878 | "If the metric is bounded\n" | |
879 | "IGP metric\n" | |
880 | "TE metric\n" | |
881 | "Hop Counts\n" | |
882 | "Aggregate bandwidth consumption\n" | |
883 | "Load of the most loaded link\n" | |
884 | "Cumulative IGP cost\n" | |
885 | "Cumulative TE cost\n" | |
886 | "P2MP IGP metric\n" | |
887 | "P2MP TE metric\n" | |
888 | "P2MP hop count metric\n" | |
889 | "Segment-ID (SID) Depth.\n" | |
890 | "Path Delay metric\n" | |
891 | "Path Delay Variation metric\n" | |
892 | "Path Loss metric\n" | |
893 | "P2MP Path Delay metric\n" | |
894 | "P2MP Path Delay variation metric\n" | |
895 | "P2MP Path Loss metric\n" | |
896 | "Number of adaptations on a path\n" | |
897 | "Number of layers on a path\n" | |
898 | "Domain Count metric\n" | |
899 | "Border Node Count metric\n" | |
900 | "Metric value\n" | |
901 | "Required constraint\n") | |
902 | { | |
903 | char xpath[XPATH_CANDIDATE_MAXLEN]; | |
904 | snprintf(xpath, sizeof(xpath), "./constraints/metrics[type='%s']/value", | |
905 | type); | |
906 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, value); | |
907 | snprintf(xpath, sizeof(xpath), | |
908 | "./constraints/metrics[type='%s']/is-bound", type); | |
909 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, | |
910 | (bound != NULL) ? "true" : "false"); | |
911 | snprintf(xpath, sizeof(xpath), | |
912 | "./constraints/metrics[type='%s']/required", type); | |
913 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, | |
914 | required ? "true" : "false"); | |
915 | return nb_cli_apply_changes(vty, NULL); | |
916 | } | |
917 | ||
918 | DEFPY(srte_candidate_no_metric, | |
919 | srte_candidate_no_metric_cmd, | |
920 | "no metric [bound] <igp|te|hc|abc|lmll|cigp|cte|pigp|pte|phc|msd|pd|pdv|pl|ppd|ppdv|ppl|nap|nlp|dc|bnc>$type [METRIC$value] [required$required]", | |
921 | NO_STR | |
922 | "Remove a metric constraint\n" | |
923 | "If the metric is bounded\n" | |
924 | "IGP metric\n" | |
925 | "TE metric\n" | |
926 | "Hop Counts\n" | |
927 | "Aggregate bandwidth consumption\n" | |
928 | "Load of the most loaded link\n" | |
929 | "Cumulative IGP cost\n" | |
930 | "Cumulative TE cost\n" | |
931 | "P2MP IGP metric\n" | |
932 | "P2MP TE metric\n" | |
933 | "P2MP hop count metric\n" | |
934 | "Segment-ID (SID) Depth.\n" | |
935 | "Path Delay metric\n" | |
936 | "Path Delay Variation metric\n" | |
937 | "Path Loss metric\n" | |
938 | "P2MP Path Delay metric\n" | |
939 | "P2MP Path Delay variation metric\n" | |
940 | "P2MP Path Loss metric\n" | |
941 | "Number of adaptations on a path\n" | |
942 | "Number of layers on a path\n" | |
943 | "Domain Count metric\n" | |
944 | "Border Node Count metric\n" | |
945 | "Metric value\n" | |
946 | "Required constraint\n") | |
947 | { | |
948 | char xpath[XPATH_CANDIDATE_MAXLEN]; | |
949 | snprintf(xpath, sizeof(xpath), "./constraints/metrics[type='%s']", | |
950 | type); | |
951 | nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); | |
952 | return nb_cli_apply_changes(vty, NULL); | |
953 | } | |
954 | ||
955 | DEFPY(srte_policy_no_candidate, | |
956 | srte_policy_no_candidate_cmd, | |
957 | "no candidate-path\ | |
958 | preference (0-4294967295)$preference\ | |
959 | [name WORD\ | |
960 | <\ | |
961 | explicit segment-list WORD\ | |
962 | |dynamic\ | |
963 | >]", | |
964 | NO_STR | |
965 | "Segment Routing Policy Candidate Path\n" | |
966 | "Segment Routing Policy Candidate Path Preference\n" | |
967 | "Administrative Preference\n" | |
968 | "Segment Routing Policy Candidate Path Name\n" | |
969 | "Symbolic Name\n" | |
970 | "Explicit Path\n" | |
971 | "List of SIDs\n" | |
972 | "Name of the Segment List\n" | |
973 | "Dynamic Path\n") | |
974 | { | |
975 | nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); | |
976 | ||
977 | return nb_cli_apply_changes(vty, "./candidate-path[preference='%s']", | |
978 | preference_str); | |
979 | } | |
980 | ||
981 | DEFPY(srte_candidate_objfun, | |
982 | srte_candidate_objfun_cmd, | |
983 | "objective-function <mcp|mlp|mbp|mbc|mll|mcc|spt|mct|mplp|mup|mrup|mtd|mbn|mctd|msl|mss|msn>$type [required$required]", | |
984 | "Define an objective function constraint\n" | |
985 | "Minimum Cost Path\n" | |
986 | "Minimum Load Path\n" | |
987 | "Maximum residual Bandwidth Path\n" | |
988 | "Minimize aggregate Bandwidth Consumption\n" | |
989 | "Minimize the Load of the most loaded Link\n" | |
990 | "Minimize the Cumulative Cost of a set of paths\n" | |
991 | "Shortest Path Tree\n" | |
992 | "Minimum Cost Tree\n" | |
993 | "Minimum Packet Loss Path\n" | |
994 | "Maximum Under-Utilized Path\n" | |
995 | "Maximum Reserved Under-Utilized Path\n" | |
996 | "Minimize the number of Transit Domains\n" | |
997 | "Minimize the number of Border Nodes\n" | |
998 | "Minimize the number of Common Transit Domains\n" | |
999 | "Minimize the number of Shared Links\n" | |
1000 | "Minimize the number of Shared SRLGs\n" | |
1001 | "Minimize the number of Shared Nodes\n" | |
1002 | "Required constraint\n") | |
1003 | { | |
1004 | char xpath[XPATH_CANDIDATE_MAXLEN]; | |
1005 | nb_cli_enqueue_change(vty, "./constraints/objective-function", | |
1006 | NB_OP_DESTROY, NULL); | |
1007 | snprintf(xpath, sizeof(xpath), | |
1008 | "./constraints/objective-function/required"); | |
1009 | nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, | |
1010 | required ? "true" : "false"); | |
1011 | nb_cli_enqueue_change(vty, "./constraints/objective-function/type", | |
1012 | NB_OP_MODIFY, type); | |
1013 | return nb_cli_apply_changes(vty, NULL); | |
1014 | } | |
1015 | ||
1016 | DEFPY(srte_candidate_no_objfun, | |
1017 | srte_candidate_no_objfun_cmd, | |
1018 | "no objective-function [<mcp|mlp|mbp|mbc|mll|mcc|spt|mct|mplp|mup|mrup|mtd|mbn|mctd|msl|mss|msn>] [required$required]", | |
1019 | NO_STR | |
1020 | "Remove an objective function constraint\n" | |
1021 | "Minimum Cost Path\n" | |
1022 | "Minimum Load Path\n" | |
1023 | "Maximum residual Bandwidth Path\n" | |
1024 | "Minimize aggregate Bandwidth Consumption\n" | |
1025 | "Minimize the Load of the most loaded Link\n" | |
1026 | "Minimize the Cumulative Cost of a set of paths\n" | |
1027 | "Shortest Path Tree\n" | |
1028 | "Minimum Cost Tree\n" | |
1029 | "Minimum Packet Loss Path\n" | |
1030 | "Maximum Under-Utilized Path\n" | |
1031 | "Maximum Reserved Under-Utilized Path\n" | |
1032 | "Minimize the number of Transit Domains\n" | |
1033 | "Minimize the number of Border Nodes\n" | |
1034 | "Minimize the number of Common Transit Domains\n" | |
1035 | "Minimize the number of Shared Links\n" | |
1036 | "Minimize the number of Shared SRLGs\n" | |
1037 | "Minimize the number of Shared Nodes\n" | |
1038 | "Required constraint\n") | |
1039 | { | |
1040 | nb_cli_enqueue_change(vty, "./constraints/objective-function", | |
1041 | NB_OP_DESTROY, NULL); | |
1042 | return nb_cli_apply_changes(vty, NULL); | |
1043 | } | |
1044 | ||
1045 | static const char *objfun_type_name(enum objfun_type type) | |
1046 | { | |
1047 | switch (type) { | |
1048 | case OBJFUN_MCP: | |
1049 | return "mcp"; | |
1050 | case OBJFUN_MLP: | |
1051 | return "mlp"; | |
1052 | case OBJFUN_MBP: | |
1053 | return "mbp"; | |
1054 | case OBJFUN_MBC: | |
1055 | return "mbc"; | |
1056 | case OBJFUN_MLL: | |
1057 | return "mll"; | |
1058 | case OBJFUN_MCC: | |
1059 | return "mcc"; | |
1060 | case OBJFUN_SPT: | |
1061 | return "spt"; | |
1062 | case OBJFUN_MCT: | |
1063 | return "mct"; | |
1064 | case OBJFUN_MPLP: | |
1065 | return "mplp"; | |
1066 | case OBJFUN_MUP: | |
1067 | return "mup"; | |
1068 | case OBJFUN_MRUP: | |
1069 | return "mrup"; | |
1070 | case OBJFUN_MTD: | |
1071 | return "mtd"; | |
1072 | case OBJFUN_MBN: | |
1073 | return "mbn"; | |
1074 | case OBJFUN_MCTD: | |
1075 | return "mctd"; | |
1076 | case OBJFUN_MSL: | |
1077 | return "msl"; | |
1078 | case OBJFUN_MSS: | |
1079 | return "mss"; | |
1080 | case OBJFUN_MSN: | |
1081 | return "msn"; | |
1082 | default: | |
1083 | return NULL; | |
1084 | } | |
1085 | } | |
1086 | ||
1087 | DEFPY_NOSH(show_debugging_pathd, show_debugging_pathd_cmd, | |
1088 | "show debugging [pathd]", | |
1089 | SHOW_STR | |
1090 | "State of each debugging option\n" | |
1091 | "pathd module debugging\n") | |
1092 | { | |
cf00164b | 1093 | |
96cb277e PG |
1094 | vty_out(vty, "Path debugging status:\n"); |
1095 | ||
cf00164b | 1096 | cmd_show_lib_debugs(vty); |
4d7b695d | 1097 | /* nothing to do here */ |
96cb277e | 1098 | path_ted_show_debugging(vty); |
116f9b45 PG |
1099 | path_policy_show_debugging(vty); |
1100 | return CMD_SUCCESS; | |
1101 | } | |
1102 | ||
1103 | DEFPY(debug_path_policy, debug_path_policy_cmd, "[no] debug pathd policy", | |
1104 | NO_STR DEBUG_STR | |
1105 | "path debugging\n" | |
1106 | "policy debugging\n") | |
1107 | { | |
1108 | uint32_t mode = DEBUG_NODE2MODE(vty->node); | |
1109 | bool no_debug = no; | |
1110 | ||
1111 | DEBUG_MODE_SET(&path_policy_debug, mode, !no); | |
1112 | DEBUG_FLAGS_SET(&path_policy_debug, PATH_POLICY_DEBUG_BASIC, !no_debug); | |
4d7b695d SM |
1113 | return CMD_SUCCESS; |
1114 | } | |
1115 | ||
1116 | static const char *metric_type_name(enum srte_candidate_metric_type type) | |
1117 | { | |
1118 | switch (type) { | |
1119 | case SRTE_CANDIDATE_METRIC_TYPE_IGP: | |
1120 | return "igp"; | |
1121 | case SRTE_CANDIDATE_METRIC_TYPE_TE: | |
1122 | return "te"; | |
1123 | case SRTE_CANDIDATE_METRIC_TYPE_HC: | |
1124 | return "hc"; | |
1125 | case SRTE_CANDIDATE_METRIC_TYPE_ABC: | |
1126 | return "abc"; | |
1127 | case SRTE_CANDIDATE_METRIC_TYPE_LMLL: | |
1128 | return "lmll"; | |
1129 | case SRTE_CANDIDATE_METRIC_TYPE_CIGP: | |
1130 | return "cigp"; | |
1131 | case SRTE_CANDIDATE_METRIC_TYPE_CTE: | |
1132 | return "cte"; | |
1133 | case SRTE_CANDIDATE_METRIC_TYPE_PIGP: | |
1134 | return "pigp"; | |
1135 | case SRTE_CANDIDATE_METRIC_TYPE_PTE: | |
1136 | return "pte"; | |
1137 | case SRTE_CANDIDATE_METRIC_TYPE_PHC: | |
1138 | return "phc"; | |
1139 | case SRTE_CANDIDATE_METRIC_TYPE_MSD: | |
1140 | return "msd"; | |
1141 | case SRTE_CANDIDATE_METRIC_TYPE_PD: | |
1142 | return "pd"; | |
1143 | case SRTE_CANDIDATE_METRIC_TYPE_PDV: | |
1144 | return "pdv"; | |
1145 | case SRTE_CANDIDATE_METRIC_TYPE_PL: | |
1146 | return "pl"; | |
1147 | case SRTE_CANDIDATE_METRIC_TYPE_PPD: | |
1148 | return "ppd"; | |
1149 | case SRTE_CANDIDATE_METRIC_TYPE_PPDV: | |
1150 | return "ppdv"; | |
1151 | case SRTE_CANDIDATE_METRIC_TYPE_PPL: | |
1152 | return "ppl"; | |
1153 | case SRTE_CANDIDATE_METRIC_TYPE_NAP: | |
1154 | return "nap"; | |
1155 | case SRTE_CANDIDATE_METRIC_TYPE_NLP: | |
1156 | return "nlp"; | |
1157 | case SRTE_CANDIDATE_METRIC_TYPE_DC: | |
1158 | return "dc"; | |
1159 | case SRTE_CANDIDATE_METRIC_TYPE_BNC: | |
1160 | return "bnc"; | |
1161 | default: | |
1162 | return NULL; | |
1163 | } | |
1164 | } | |
1165 | ||
1166 | static void config_write_float(struct vty *vty, float value) | |
1167 | { | |
1168 | if (fabs(truncf(value) - value) < FLT_EPSILON) { | |
1169 | vty_out(vty, " %d", (int)value); | |
1170 | return; | |
1171 | } else { | |
1172 | vty_out(vty, " %f", value); | |
1173 | } | |
1174 | } | |
1175 | ||
1176 | static void config_write_metric(struct vty *vty, | |
1177 | enum srte_candidate_metric_type type, | |
1178 | float value, bool required, bool is_bound) | |
1179 | { | |
1180 | const char *name = metric_type_name(type); | |
1181 | if (name == NULL) | |
1182 | return; | |
1183 | vty_out(vty, " metric %s%s", is_bound ? "bound " : "", | |
1184 | metric_type_name(type)); | |
1185 | config_write_float(vty, value); | |
1186 | vty_out(vty, required ? " required" : ""); | |
1187 | vty_out(vty, "\n"); | |
1188 | } | |
1189 | ||
1190 | static int config_write_metric_cb(const struct lyd_node *dnode, void *arg) | |
1191 | { | |
1192 | struct vty *vty = arg; | |
1193 | enum srte_candidate_metric_type type; | |
1194 | bool required, is_bound = false; | |
1195 | float value; | |
1196 | ||
1197 | type = yang_dnode_get_enum(dnode, "./type"); | |
1198 | value = (float)yang_dnode_get_dec64(dnode, "./value"); | |
1199 | required = yang_dnode_get_bool(dnode, "./required"); | |
1200 | if (yang_dnode_exists(dnode, "./is-bound")) | |
1201 | is_bound = yang_dnode_get_bool(dnode, "./is-bound"); | |
1202 | ||
1203 | config_write_metric(vty, type, value, required, is_bound); | |
1204 | return YANG_ITER_CONTINUE; | |
1205 | } | |
1206 | ||
1207 | void cli_show_srte_policy_candidate_path(struct vty *vty, | |
25605051 | 1208 | const struct lyd_node *dnode, |
4d7b695d SM |
1209 | bool show_defaults) |
1210 | { | |
1211 | float bandwidth; | |
1212 | uint32_t affinity; | |
1213 | bool required; | |
1214 | enum objfun_type objfun_type; | |
1215 | const char *type = yang_dnode_get_string(dnode, "./type"); | |
1216 | ||
1217 | vty_out(vty, " candidate-path preference %s name %s %s", | |
1218 | yang_dnode_get_string(dnode, "./preference"), | |
1219 | yang_dnode_get_string(dnode, "./name"), type); | |
1220 | if (strmatch(type, "explicit")) | |
1221 | vty_out(vty, " segment-list %s", | |
1222 | yang_dnode_get_string(dnode, "./segment-list-name")); | |
1223 | vty_out(vty, "\n"); | |
1224 | ||
1225 | if (strmatch(type, "dynamic")) { | |
1226 | if (yang_dnode_exists(dnode, "./constraints/bandwidth")) { | |
1227 | bandwidth = (float)yang_dnode_get_dec64( | |
1228 | dnode, "./constraints/bandwidth/value"); | |
1229 | required = yang_dnode_get_bool( | |
1230 | dnode, "./constraints/bandwidth/required"); | |
ec957bbc | 1231 | vty_out(vty, " bandwidth"); |
4d7b695d | 1232 | config_write_float(vty, bandwidth); |
ec957bbc EDP |
1233 | if (required) |
1234 | vty_out(vty, " required"); | |
4d7b695d SM |
1235 | vty_out(vty, "\n"); |
1236 | } | |
1237 | if (yang_dnode_exists(dnode, | |
1238 | "./constraints/affinity/exclude-any")) { | |
1239 | affinity = yang_dnode_get_uint32( | |
1240 | dnode, "./constraints/affinity/exclude-any"); | |
1241 | vty_out(vty, " affinity exclude-any 0x%08x\n", | |
1242 | affinity); | |
1243 | } | |
1244 | if (yang_dnode_exists(dnode, | |
1245 | "./constraints/affinity/include-any")) { | |
1246 | affinity = yang_dnode_get_uint32( | |
1247 | dnode, "./constraints/affinity/include-any"); | |
1248 | vty_out(vty, " affinity include-any 0x%08x\n", | |
1249 | affinity); | |
1250 | } | |
1251 | if (yang_dnode_exists(dnode, | |
1252 | "./constraints/affinity/include-all")) { | |
1253 | affinity = yang_dnode_get_uint32( | |
1254 | dnode, "./constraints/affinity/include-all"); | |
1255 | vty_out(vty, " affinity include-all 0x%08x\n", | |
1256 | affinity); | |
1257 | } | |
1258 | yang_dnode_iterate(config_write_metric_cb, vty, dnode, | |
1259 | "./constraints/metrics"); | |
1260 | if (yang_dnode_exists(dnode, | |
1261 | "./constraints/objective-function")) { | |
1262 | objfun_type = yang_dnode_get_enum(dnode, | |
1263 | "./constraints/objective-function/type"); | |
1264 | required = yang_dnode_get_bool(dnode, | |
1265 | "./constraints/objective-function/required"); | |
1266 | vty_out(vty, " objective-function %s%s\n", | |
1267 | objfun_type_name(objfun_type), | |
1268 | required ? " required" : ""); | |
1269 | } | |
1270 | } | |
1271 | } | |
1272 | ||
07679ad9 | 1273 | void cli_show_srte_policy_candidate_path_end(struct vty *vty, |
25605051 | 1274 | const struct lyd_node *dnode) |
07679ad9 IR |
1275 | { |
1276 | const char *type = yang_dnode_get_string(dnode, "./type"); | |
1277 | ||
1278 | if (strmatch(type, "dynamic")) | |
1279 | vty_out(vty, " exit\n"); | |
1280 | } | |
1281 | ||
4d7b695d SM |
1282 | static int config_write_dnode(const struct lyd_node *dnode, void *arg) |
1283 | { | |
1284 | struct vty *vty = arg; | |
1285 | ||
25605051 | 1286 | nb_cli_show_dnode_cmds(vty, dnode, false); |
4d7b695d SM |
1287 | |
1288 | return YANG_ITER_CONTINUE; | |
1289 | } | |
1290 | ||
1291 | int config_write_segment_routing(struct vty *vty) | |
1292 | { | |
1293 | vty_out(vty, "segment-routing\n"); | |
4d7b695d | 1294 | vty_out(vty, " traffic-eng\n"); |
ac9103aa | 1295 | |
f2b9485d | 1296 | path_ted_config_write(vty); |
4d7b695d | 1297 | |
4d7b695d SM |
1298 | yang_dnode_iterate(config_write_dnode, vty, running_config->dnode, |
1299 | "/frr-pathd:pathd/srte/segment-list"); | |
4d7b695d SM |
1300 | yang_dnode_iterate(config_write_dnode, vty, running_config->dnode, |
1301 | "/frr-pathd:pathd/srte/policy"); | |
1302 | ||
ac9103aa IR |
1303 | hook_call(pathd_srte_config_write, vty); |
1304 | ||
07679ad9 IR |
1305 | vty_out(vty, " exit\n"); |
1306 | vty_out(vty, "exit\n"); | |
1307 | ||
4d7b695d SM |
1308 | return 1; |
1309 | } | |
1310 | ||
116f9b45 PG |
1311 | static int path_policy_cli_debug_config_write(struct vty *vty) |
1312 | { | |
1313 | if (DEBUG_MODE_CHECK(&path_policy_debug, DEBUG_MODE_CONF)) { | |
1314 | if (DEBUG_FLAGS_CHECK(&path_policy_debug, | |
1315 | PATH_POLICY_DEBUG_BASIC)) | |
1316 | vty_out(vty, "debug pathd policy\n"); | |
1317 | return 1; | |
1318 | } | |
1319 | return 0; | |
1320 | } | |
1321 | ||
1322 | static int path_policy_cli_debug_set_all(uint32_t flags, bool set) | |
1323 | { | |
1324 | DEBUG_FLAGS_SET(&path_policy_debug, flags, set); | |
1325 | ||
1326 | /* If all modes have been turned off, don't preserve options. */ | |
1327 | if (!DEBUG_MODE_CHECK(&path_policy_debug, DEBUG_MODE_ALL)) | |
1328 | DEBUG_CLEAR(&path_policy_debug); | |
1329 | ||
1330 | return 0; | |
1331 | } | |
1332 | ||
4d7b695d SM |
1333 | void path_cli_init(void) |
1334 | { | |
116f9b45 PG |
1335 | hook_register(nb_client_debug_config_write, |
1336 | path_policy_cli_debug_config_write); | |
1337 | hook_register(nb_client_debug_set_all, path_policy_cli_debug_set_all); | |
1338 | ||
4d7b695d SM |
1339 | install_node(&segment_routing_node); |
1340 | install_node(&sr_traffic_eng_node); | |
1341 | install_node(&srte_segment_list_node); | |
1342 | install_node(&srte_policy_node); | |
1343 | install_node(&srte_candidate_dyn_node); | |
1344 | install_default(SEGMENT_ROUTING_NODE); | |
1345 | install_default(SR_TRAFFIC_ENG_NODE); | |
1346 | install_default(SR_SEGMENT_LIST_NODE); | |
1347 | install_default(SR_POLICY_NODE); | |
1348 | install_default(SR_CANDIDATE_DYN_NODE); | |
1349 | ||
1350 | install_element(ENABLE_NODE, &show_debugging_pathd_cmd); | |
1351 | install_element(ENABLE_NODE, &show_srte_policy_cmd); | |
1352 | install_element(ENABLE_NODE, &show_srte_policy_detail_cmd); | |
1353 | ||
116f9b45 PG |
1354 | install_element(ENABLE_NODE, &debug_path_policy_cmd); |
1355 | install_element(CONFIG_NODE, &debug_path_policy_cmd); | |
1356 | ||
4d7b695d SM |
1357 | install_element(CONFIG_NODE, &segment_routing_cmd); |
1358 | install_element(SEGMENT_ROUTING_NODE, &sr_traffic_eng_cmd); | |
1359 | install_element(SR_TRAFFIC_ENG_NODE, &srte_segment_list_cmd); | |
1360 | install_element(SR_TRAFFIC_ENG_NODE, &srte_no_segment_list_cmd); | |
1361 | install_element(SR_SEGMENT_LIST_NODE, | |
1362 | &srte_segment_list_segment_cmd); | |
1363 | install_element(SR_SEGMENT_LIST_NODE, | |
1364 | &srte_segment_list_no_segment_cmd); | |
1365 | install_element(SR_TRAFFIC_ENG_NODE, &srte_policy_cmd); | |
1366 | install_element(SR_TRAFFIC_ENG_NODE, &srte_no_policy_cmd); | |
1367 | install_element(SR_POLICY_NODE, &srte_policy_name_cmd); | |
1368 | install_element(SR_POLICY_NODE, &srte_policy_no_name_cmd); | |
1369 | install_element(SR_POLICY_NODE, &srte_policy_binding_sid_cmd); | |
1370 | install_element(SR_POLICY_NODE, &srte_policy_no_binding_sid_cmd); | |
1371 | install_element(SR_POLICY_NODE, &srte_policy_candidate_exp_cmd); | |
1372 | install_element(SR_POLICY_NODE, &srte_policy_candidate_dyn_cmd); | |
1373 | install_element(SR_POLICY_NODE, &srte_policy_no_candidate_cmd); | |
1374 | install_element(SR_CANDIDATE_DYN_NODE, | |
1375 | &srte_candidate_bandwidth_cmd); | |
1376 | install_element(SR_CANDIDATE_DYN_NODE, | |
1377 | &srte_candidate_no_bandwidth_cmd); | |
1378 | install_element(SR_CANDIDATE_DYN_NODE, | |
1379 | &srte_candidate_affinity_filter_cmd); | |
1380 | install_element(SR_CANDIDATE_DYN_NODE, | |
1381 | &srte_candidate_no_affinity_filter_cmd); | |
1382 | install_element(SR_CANDIDATE_DYN_NODE, | |
1383 | &srte_candidate_metric_cmd); | |
1384 | install_element(SR_CANDIDATE_DYN_NODE, | |
1385 | &srte_candidate_no_metric_cmd); | |
1386 | install_element(SR_CANDIDATE_DYN_NODE, | |
1387 | &srte_candidate_objfun_cmd); | |
1388 | install_element(SR_CANDIDATE_DYN_NODE, | |
1389 | &srte_candidate_no_objfun_cmd); | |
1390 | } |