]>
Commit | Line | Data |
---|---|---|
41675b4c RW |
1 | /* Zebra MPLS VTY functions |
2 | * Copyright (C) 2002 Kunihiro Ishiguro | |
3 | * | |
4 | * This file is part of GNU Zebra. | |
5 | * | |
6 | * GNU Zebra is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2, or (at your option) any | |
9 | * later version. | |
10 | * | |
11 | * GNU Zebra is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License for more details. | |
15 | * | |
896014f4 DL |
16 | * You should have received a copy of the GNU General Public License along |
17 | * with this program; see the file COPYING; if not, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
41675b4c RW |
19 | */ |
20 | ||
21 | #include <zebra.h> | |
22 | ||
41675b4c RW |
23 | #include "memory.h" |
24 | #include "if.h" | |
25 | #include "prefix.h" | |
26 | #include "command.h" | |
27 | #include "table.h" | |
28 | #include "rib.h" | |
29 | #include "nexthop.h" | |
30 | #include "vrf.h" | |
31 | #include "mpls.h" | |
32 | #include "lib/json.h" | |
33 | ||
34 | #include "zebra/zserv.h" | |
35 | #include "zebra/zebra_vrf.h" | |
36 | #include "zebra/zebra_mpls.h" | |
37 | #include "zebra/zebra_rnh.h" | |
38 | #include "zebra/redistribute.h" | |
39 | #include "zebra/zebra_routemap.h" | |
41675b4c | 40 | |
d62a17ae | 41 | static int zebra_mpls_transit_lsp(struct vty *vty, int add_cmd, |
42 | const char *inlabel_str, const char *gate_str, | |
43 | const char *outlabel_str, | |
44 | const char *flag_str) | |
41675b4c | 45 | { |
d62a17ae | 46 | struct zebra_vrf *zvrf; |
47 | int ret; | |
48 | enum nexthop_types_t gtype; | |
49 | union g_addr gate; | |
50 | mpls_label_t label; | |
51 | mpls_label_t in_label, out_label; | |
52 | ||
53 | if (!mpls_enabled) { | |
54 | vty_out(vty, | |
55 | "%% MPLS not turned on in kernel, ignoring command\n"); | |
56 | return CMD_WARNING_CONFIG_FAILED; | |
57 | } | |
58 | ||
59 | zvrf = vrf_info_lookup(VRF_DEFAULT); | |
60 | if (!zvrf) { | |
61 | vty_out(vty, "%% Default VRF does not exist\n"); | |
62 | return CMD_WARNING_CONFIG_FAILED; | |
63 | } | |
64 | ||
65 | if (!inlabel_str) { | |
66 | vty_out(vty, "%% No Label Information\n"); | |
67 | return CMD_WARNING_CONFIG_FAILED; | |
68 | } | |
69 | ||
70e98a7f | 70 | out_label = MPLS_LABEL_IMPLICIT_NULL; /* as initialization */ |
d62a17ae | 71 | label = atoi(inlabel_str); |
72 | if (!IS_MPLS_UNRESERVED_LABEL(label)) { | |
73 | vty_out(vty, "%% Invalid label\n"); | |
74 | return CMD_WARNING_CONFIG_FAILED; | |
75 | } | |
76 | ||
77 | if (add_cmd) { | |
78 | if (!gate_str) { | |
79 | vty_out(vty, "%% No Nexthop Information\n"); | |
80 | return CMD_WARNING_CONFIG_FAILED; | |
81 | } | |
82 | if (!outlabel_str) { | |
83 | vty_out(vty, "%% No Outgoing label Information\n"); | |
84 | return CMD_WARNING_CONFIG_FAILED; | |
85 | } | |
86 | } | |
87 | ||
88 | in_label = label; | |
89 | gtype = NEXTHOP_TYPE_BLACKHOLE; /* as initialization */ | |
90 | ||
91 | if (gate_str) { | |
92 | /* Gateway is a IPv4 or IPv6 nexthop. */ | |
93 | ret = inet_pton(AF_INET6, gate_str, &gate.ipv6); | |
94 | if (ret) | |
95 | gtype = NEXTHOP_TYPE_IPV6; | |
96 | else { | |
97 | ret = inet_pton(AF_INET, gate_str, &gate.ipv4); | |
98 | if (ret) | |
99 | gtype = NEXTHOP_TYPE_IPV4; | |
100 | else { | |
101 | vty_out(vty, "%% Invalid nexthop\n"); | |
102 | return CMD_WARNING_CONFIG_FAILED; | |
103 | } | |
104 | } | |
105 | } | |
106 | ||
107 | if (outlabel_str) { | |
108 | if (outlabel_str[0] == 'i') | |
70e98a7f | 109 | out_label = MPLS_LABEL_IMPLICIT_NULL; |
d62a17ae | 110 | else if (outlabel_str[0] == 'e' && gtype == NEXTHOP_TYPE_IPV4) |
70e98a7f | 111 | out_label = MPLS_LABEL_IPV4_EXPLICIT_NULL; |
d62a17ae | 112 | else if (outlabel_str[0] == 'e' && gtype == NEXTHOP_TYPE_IPV6) |
70e98a7f | 113 | out_label = MPLS_LABEL_IPV6_EXPLICIT_NULL; |
d62a17ae | 114 | else |
115 | out_label = atoi(outlabel_str); | |
116 | } | |
117 | ||
118 | if (add_cmd) { | |
41675b4c | 119 | #if defined(HAVE_CUMULUS) |
d62a17ae | 120 | /* Check that label value is consistent. */ |
121 | if (!zebra_mpls_lsp_label_consistent(zvrf, in_label, out_label, | |
122 | gtype, &gate, 0)) { | |
123 | vty_out(vty, "%% Label value not consistent\n"); | |
124 | return CMD_WARNING_CONFIG_FAILED; | |
125 | } | |
41675b4c RW |
126 | #endif /* HAVE_CUMULUS */ |
127 | ||
d62a17ae | 128 | ret = zebra_mpls_static_lsp_add(zvrf, in_label, out_label, |
129 | gtype, &gate, 0); | |
130 | } else | |
131 | ret = zebra_mpls_static_lsp_del(zvrf, in_label, gtype, &gate, | |
132 | 0); | |
41675b4c | 133 | |
d62a17ae | 134 | if (ret) { |
135 | vty_out(vty, "%% LSP cannot be %s\n", | |
136 | add_cmd ? "added" : "deleted"); | |
137 | return CMD_WARNING_CONFIG_FAILED; | |
138 | } | |
41675b4c | 139 | |
d62a17ae | 140 | return CMD_SUCCESS; |
41675b4c RW |
141 | } |
142 | ||
143 | DEFUN (mpls_transit_lsp, | |
144 | mpls_transit_lsp_cmd, | |
e52702f2 | 145 | "mpls lsp (16-1048575) <A.B.C.D|X:X::X:X> <(16-1048575)|explicit-null|implicit-null>", |
41675b4c RW |
146 | MPLS_STR |
147 | "Establish label switched path\n" | |
148 | "Incoming MPLS label\n" | |
149 | "IPv4 gateway address\n" | |
150 | "IPv6 gateway address\n" | |
151 | "Outgoing MPLS label\n" | |
e64f3c32 | 152 | "Use Explicit-Null label\n" |
41675b4c RW |
153 | "Use Implicit-Null label\n") |
154 | { | |
d62a17ae | 155 | return zebra_mpls_transit_lsp(vty, 1, argv[2]->arg, argv[3]->arg, |
156 | argv[4]->arg, NULL); | |
41675b4c RW |
157 | } |
158 | ||
159 | DEFUN (no_mpls_transit_lsp, | |
160 | no_mpls_transit_lsp_cmd, | |
e52702f2 | 161 | "no mpls lsp (16-1048575) <A.B.C.D|X:X::X:X>", |
41675b4c RW |
162 | NO_STR |
163 | MPLS_STR | |
164 | "Establish label switched path\n" | |
165 | "Incoming MPLS label\n" | |
166 | "IPv4 gateway address\n" | |
167 | "IPv6 gateway address\n") | |
168 | { | |
d62a17ae | 169 | return zebra_mpls_transit_lsp(vty, 0, argv[3]->arg, argv[4]->arg, NULL, |
170 | NULL); | |
41675b4c RW |
171 | } |
172 | ||
d62a17ae | 173 | ALIAS(no_mpls_transit_lsp, no_mpls_transit_lsp_out_label_cmd, |
174 | "no mpls lsp (16-1048575) <A.B.C.D|X:X::X:X> <(16-1048575)|explicit-null|implicit-null>", | |
175 | NO_STR MPLS_STR | |
176 | "Establish label switched path\n" | |
177 | "Incoming MPLS label\n" | |
178 | "IPv4 gateway address\n" | |
179 | "IPv6 gateway address\n" | |
180 | "Outgoing MPLS label\n" | |
181 | "Use Explicit-Null label\n" | |
182 | "Use Implicit-Null label\n") | |
183 | ||
41675b4c RW |
184 | DEFUN (no_mpls_transit_lsp_all, |
185 | no_mpls_transit_lsp_all_cmd, | |
e52702f2 | 186 | "no mpls lsp (16-1048575)", |
41675b4c RW |
187 | NO_STR |
188 | MPLS_STR | |
189 | "Establish label switched path\n" | |
190 | "Incoming MPLS label\n") | |
191 | { | |
d62a17ae | 192 | return zebra_mpls_transit_lsp(vty, 0, argv[3]->arg, NULL, NULL, NULL); |
41675b4c RW |
193 | } |
194 | ||
d62a17ae | 195 | static int zebra_mpls_bind(struct vty *vty, int add_cmd, const char *prefix, |
196 | const char *label_str) | |
f31e084c | 197 | { |
d62a17ae | 198 | struct zebra_vrf *zvrf; |
199 | struct prefix p; | |
d7c0a89a | 200 | uint32_t label; |
d62a17ae | 201 | int ret; |
202 | ||
203 | zvrf = vrf_info_lookup(VRF_DEFAULT); | |
204 | if (!zvrf) { | |
205 | vty_out(vty, "%% Default VRF does not exist\n"); | |
206 | return CMD_WARNING_CONFIG_FAILED; | |
207 | } | |
208 | ||
209 | memset(&p, 0, sizeof(struct prefix)); | |
210 | ret = str2prefix(prefix, &p); | |
211 | if (ret <= 0) { | |
212 | vty_out(vty, "%% Malformed address\n"); | |
213 | return CMD_WARNING_CONFIG_FAILED; | |
214 | } | |
215 | ||
216 | if (add_cmd) { | |
217 | if (!label_str) { | |
218 | vty_out(vty, "%% No label binding specified\n"); | |
219 | return CMD_WARNING_CONFIG_FAILED; | |
220 | } | |
221 | ||
222 | if (!strcmp(label_str, "implicit-null")) | |
70e98a7f | 223 | label = MPLS_LABEL_IMPLICIT_NULL; |
d62a17ae | 224 | else if (!strcmp(label_str, "explicit-null")) { |
225 | if (p.family == AF_INET) | |
70e98a7f | 226 | label = MPLS_LABEL_IPV4_EXPLICIT_NULL; |
d62a17ae | 227 | else |
70e98a7f | 228 | label = MPLS_LABEL_IPV6_EXPLICIT_NULL; |
d62a17ae | 229 | } else { |
230 | label = atoi(label_str); | |
231 | if (!IS_MPLS_UNRESERVED_LABEL(label)) { | |
232 | vty_out(vty, "%% Invalid label\n"); | |
233 | return CMD_WARNING_CONFIG_FAILED; | |
234 | } | |
235 | if (zebra_mpls_label_already_bound(zvrf, label)) { | |
236 | vty_out(vty, | |
237 | "%% Label already bound to a FEC\n"); | |
238 | return CMD_WARNING_CONFIG_FAILED; | |
239 | } | |
240 | } | |
241 | ||
242 | ret = zebra_mpls_static_fec_add(zvrf, &p, label); | |
243 | } else | |
244 | ret = zebra_mpls_static_fec_del(zvrf, &p); | |
245 | ||
246 | if (ret) { | |
247 | vty_out(vty, "%% FEC to label binding cannot be %s\n", | |
248 | add_cmd ? "added" : "deleted"); | |
249 | return CMD_WARNING_CONFIG_FAILED; | |
250 | } | |
251 | ||
252 | return CMD_SUCCESS; | |
f31e084c DS |
253 | } |
254 | ||
255 | DEFUN (mpls_label_bind, | |
256 | mpls_label_bind_cmd, | |
bf995813 | 257 | "mpls label bind <A.B.C.D/M|X:X::X:X/M> <(16-1048575)|implicit-null|explicit-null>", |
f31e084c DS |
258 | MPLS_STR |
259 | "Label configuration\n" | |
260 | "Establish FEC to label binding\n" | |
261 | "IPv4 prefix\n" | |
262 | "IPv6 prefix\n" | |
263 | "MPLS Label to bind\n" | |
bf995813 DS |
264 | "Use Implicit-Null Label\n" |
265 | "Use Explicit-Null Label\n") | |
f31e084c | 266 | { |
d62a17ae | 267 | return zebra_mpls_bind(vty, 1, argv[3]->arg, argv[4]->arg); |
f31e084c DS |
268 | } |
269 | ||
270 | DEFUN (no_mpls_label_bind, | |
271 | no_mpls_label_bind_cmd, | |
272 | "no mpls label bind <A.B.C.D/M|X:X::X:X/M> [<(16-1048575)|implicit-null>]", | |
273 | NO_STR | |
274 | MPLS_STR | |
275 | "Label configuration\n" | |
276 | "Establish FEC to label binding\n" | |
277 | "IPv4 prefix\n" | |
278 | "IPv6 prefix\n" | |
279 | "MPLS Label to bind\n" | |
280 | "Use Implicit-Null Label\n") | |
f31e084c | 281 | { |
d62a17ae | 282 | return zebra_mpls_bind(vty, 0, argv[4]->arg, NULL); |
f31e084c DS |
283 | } |
284 | ||
41675b4c | 285 | /* MPLS LSP configuration write function. */ |
d62a17ae | 286 | static int zebra_mpls_config(struct vty *vty) |
41675b4c | 287 | { |
d62a17ae | 288 | int write = 0; |
289 | struct zebra_vrf *zvrf; | |
41675b4c | 290 | |
d62a17ae | 291 | zvrf = vrf_info_lookup(VRF_DEFAULT); |
292 | if (!zvrf) | |
293 | return 0; | |
41675b4c | 294 | |
d62a17ae | 295 | write += zebra_mpls_write_lsp_config(vty, zvrf); |
296 | write += zebra_mpls_write_fec_config(vty, zvrf); | |
297 | write += zebra_mpls_write_label_block_config(vty, zvrf); | |
298 | return write; | |
41675b4c RW |
299 | } |
300 | ||
f31e084c DS |
301 | DEFUN (show_mpls_fec, |
302 | show_mpls_fec_cmd, | |
303 | "show mpls fec [<A.B.C.D/M|X:X::X:X/M>]", | |
304 | SHOW_STR | |
305 | MPLS_STR | |
306 | "MPLS FEC table\n" | |
307 | "FEC to display information about\n" | |
308 | "FEC to display information about\n") | |
309 | { | |
d62a17ae | 310 | struct zebra_vrf *zvrf; |
311 | struct prefix p; | |
312 | int ret; | |
313 | ||
314 | zvrf = vrf_info_lookup(VRF_DEFAULT); | |
315 | if (!zvrf) | |
316 | return 0; | |
317 | ||
318 | if (argc == 3) | |
319 | zebra_mpls_print_fec_table(vty, zvrf); | |
320 | else { | |
321 | memset(&p, 0, sizeof(struct prefix)); | |
322 | ret = str2prefix(argv[3]->arg, &p); | |
323 | if (ret <= 0) { | |
324 | vty_out(vty, "%% Malformed address\n"); | |
325 | return CMD_WARNING; | |
326 | } | |
327 | zebra_mpls_print_fec(vty, zvrf, &p); | |
328 | } | |
329 | ||
330 | return CMD_SUCCESS; | |
f31e084c DS |
331 | } |
332 | ||
41675b4c RW |
333 | DEFUN (show_mpls_table, |
334 | show_mpls_table_cmd, | |
e52702f2 | 335 | "show mpls table [json]", |
41675b4c RW |
336 | SHOW_STR |
337 | MPLS_STR | |
338 | "MPLS table\n" | |
9973d184 | 339 | JSON_STR) |
41675b4c | 340 | { |
d62a17ae | 341 | struct zebra_vrf *zvrf; |
088f1098 | 342 | bool uj = use_json(argc, argv); |
41675b4c | 343 | |
d62a17ae | 344 | zvrf = vrf_info_lookup(VRF_DEFAULT); |
345 | zebra_mpls_print_lsp_table(vty, zvrf, uj); | |
346 | return CMD_SUCCESS; | |
41675b4c RW |
347 | } |
348 | ||
349 | DEFUN (show_mpls_table_lsp, | |
350 | show_mpls_table_lsp_cmd, | |
e52702f2 | 351 | "show mpls table (16-1048575) [json]", |
41675b4c RW |
352 | SHOW_STR |
353 | MPLS_STR | |
354 | "MPLS table\n" | |
355 | "LSP to display information about\n" | |
9973d184 | 356 | JSON_STR) |
41675b4c | 357 | { |
d7c0a89a | 358 | uint32_t label; |
d62a17ae | 359 | struct zebra_vrf *zvrf; |
088f1098 | 360 | bool uj = use_json(argc, argv); |
d62a17ae | 361 | |
362 | zvrf = vrf_info_lookup(VRF_DEFAULT); | |
363 | label = atoi(argv[3]->arg); | |
364 | zebra_mpls_print_lsp(vty, zvrf, label, uj); | |
365 | return CMD_SUCCESS; | |
41675b4c RW |
366 | } |
367 | ||
fe6c7157 RW |
368 | DEFUN (show_mpls_status, |
369 | show_mpls_status_cmd, | |
370 | "show mpls status", | |
371 | SHOW_STR | |
372 | "MPLS information\n" | |
373 | "MPLS status\n") | |
374 | { | |
d62a17ae | 375 | vty_out(vty, "MPLS support enabled: %s\n", |
376 | (mpls_enabled) ? "yes" | |
377 | : "no (mpls kernel extensions not detected)"); | |
378 | return CMD_SUCCESS; | |
fe6c7157 RW |
379 | } |
380 | ||
d62a17ae | 381 | static int zebra_mpls_global_block(struct vty *vty, int add_cmd, |
382 | const char *start_label_str, | |
383 | const char *end_label_str) | |
1b6d5c7e | 384 | { |
d62a17ae | 385 | int ret; |
d7c0a89a QY |
386 | uint32_t start_label; |
387 | uint32_t end_label; | |
d62a17ae | 388 | struct zebra_vrf *zvrf; |
389 | ||
390 | zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); | |
391 | if (!zvrf) { | |
392 | vty_out(vty, "%% Default VRF does not exist\n"); | |
393 | return CMD_WARNING_CONFIG_FAILED; | |
394 | } | |
395 | ||
396 | if (add_cmd) { | |
397 | if (!start_label_str || !end_label_str) { | |
398 | vty_out(vty, "%% Labels not specified\n"); | |
399 | return CMD_WARNING_CONFIG_FAILED; | |
400 | } | |
401 | ||
402 | start_label = atoi(start_label_str); | |
403 | end_label = atoi(end_label_str); | |
404 | if (!IS_MPLS_UNRESERVED_LABEL(start_label) | |
405 | || !IS_MPLS_UNRESERVED_LABEL(end_label)) { | |
406 | vty_out(vty, "%% Invalid label\n"); | |
407 | return CMD_WARNING_CONFIG_FAILED; | |
408 | } | |
409 | if (end_label < start_label) { | |
410 | vty_out(vty, "%% End label is less than Start label\n"); | |
411 | return CMD_WARNING_CONFIG_FAILED; | |
412 | } | |
413 | ||
414 | ret = zebra_mpls_label_block_add(zvrf, start_label, end_label); | |
415 | } else | |
416 | ret = zebra_mpls_label_block_del(zvrf); | |
417 | ||
418 | if (ret) { | |
419 | vty_out(vty, "%% Global label block could not be %s\n", | |
420 | add_cmd ? "added" : "deleted"); | |
421 | return CMD_WARNING_CONFIG_FAILED; | |
422 | } | |
423 | ||
424 | return CMD_SUCCESS; | |
1b6d5c7e VV |
425 | } |
426 | ||
427 | DEFUN (mpls_label_global_block, | |
428 | mpls_label_global_block_cmd, | |
429 | "mpls label global-block (16-1048575) (16-1048575)", | |
430 | MPLS_STR | |
431 | "Label configuration\n" | |
432 | "Configure global label block\n" | |
433 | "Start label\n" | |
434 | "End label\n") | |
435 | { | |
d62a17ae | 436 | return zebra_mpls_global_block(vty, 1, argv[3]->arg, argv[4]->arg); |
1b6d5c7e VV |
437 | } |
438 | ||
439 | DEFUN (no_mpls_label_global_block, | |
440 | no_mpls_label_global_block_cmd, | |
441 | "no mpls label global-block [(16-1048575) (16-1048575)]", | |
442 | NO_STR | |
443 | MPLS_STR | |
444 | "Label configuration\n" | |
445 | "Configure global label block\n" | |
446 | "Start label\n" | |
447 | "End label\n") | |
448 | { | |
d62a17ae | 449 | return zebra_mpls_global_block(vty, 0, NULL, NULL); |
1b6d5c7e VV |
450 | } |
451 | ||
41675b4c | 452 | /* MPLS node for MPLS LSP. */ |
d62a17ae | 453 | static struct cmd_node mpls_node = {MPLS_NODE, "", 1}; |
41675b4c RW |
454 | |
455 | /* MPLS VTY. */ | |
d62a17ae | 456 | void zebra_mpls_vty_init(void) |
41675b4c | 457 | { |
d62a17ae | 458 | install_element(VIEW_NODE, &show_mpls_status_cmd); |
459 | ||
460 | install_node(&mpls_node, zebra_mpls_config); | |
461 | ||
d62a17ae | 462 | install_element(CONFIG_NODE, &mpls_transit_lsp_cmd); |
463 | install_element(CONFIG_NODE, &no_mpls_transit_lsp_cmd); | |
464 | install_element(CONFIG_NODE, &no_mpls_transit_lsp_out_label_cmd); | |
465 | install_element(CONFIG_NODE, &no_mpls_transit_lsp_all_cmd); | |
d97c792e | 466 | |
d62a17ae | 467 | install_element(CONFIG_NODE, &mpls_label_bind_cmd); |
468 | install_element(CONFIG_NODE, &no_mpls_label_bind_cmd); | |
469 | ||
470 | install_element(CONFIG_NODE, &mpls_label_global_block_cmd); | |
471 | install_element(CONFIG_NODE, &no_mpls_label_global_block_cmd); | |
472 | ||
473 | install_element(VIEW_NODE, &show_mpls_table_cmd); | |
474 | install_element(VIEW_NODE, &show_mpls_table_lsp_cmd); | |
475 | install_element(VIEW_NODE, &show_mpls_fec_cmd); | |
41675b4c | 476 | } |