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  *
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
19  */
20 
21 #include <zebra.h>
22 
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"
40 
zebra_mpls_transit_lsp(struct vty * vty,int add_cmd,const char * inlabel_str,const char * gate_str,const char * outlabel_str,const char * flag_str)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)
45 {
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 
70 	out_label = MPLS_LABEL_IMPLICIT_NULL; /* as initialization */
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')
109 			out_label = MPLS_LABEL_IMPLICIT_NULL;
110 		else if (outlabel_str[0] == 'e' && gtype == NEXTHOP_TYPE_IPV4)
111 			out_label = MPLS_LABEL_IPV4_EXPLICIT_NULL;
112 		else if (outlabel_str[0] == 'e' && gtype == NEXTHOP_TYPE_IPV6)
113 			out_label = MPLS_LABEL_IPV6_EXPLICIT_NULL;
114 		else
115 			out_label = atoi(outlabel_str);
116 	}
117 
118 	if (add_cmd) {
119 #if defined(HAVE_CUMULUS)
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 		}
126 #endif /* HAVE_CUMULUS */
127 
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);
133 
134 	if (ret) {
135 		vty_out(vty, "%% LSP cannot be %s\n",
136 			add_cmd ? "added" : "deleted");
137 		return CMD_WARNING_CONFIG_FAILED;
138 	}
139 
140 	return CMD_SUCCESS;
141 }
142 
143 DEFUN (mpls_transit_lsp,
144        mpls_transit_lsp_cmd,
145        "mpls lsp (16-1048575) <A.B.C.D|X:X::X:X> <(16-1048575)|explicit-null|implicit-null>",
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"
152        "Use Explicit-Null label\n"
153        "Use Implicit-Null label\n")
154 {
155 	return zebra_mpls_transit_lsp(vty, 1, argv[2]->arg, argv[3]->arg,
156 				      argv[4]->arg, NULL);
157 }
158 
159 DEFUN (no_mpls_transit_lsp,
160        no_mpls_transit_lsp_cmd,
161        "no mpls lsp (16-1048575) <A.B.C.D|X:X::X:X>",
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 {
169 	return zebra_mpls_transit_lsp(vty, 0, argv[3]->arg, argv[4]->arg, NULL,
170 				      NULL);
171 }
172 
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 
184 DEFUN (no_mpls_transit_lsp_all,
185        no_mpls_transit_lsp_all_cmd,
186        "no mpls lsp (16-1048575)",
187        NO_STR
188        MPLS_STR
189        "Establish label switched path\n"
190        "Incoming MPLS label\n")
191 {
192 	return zebra_mpls_transit_lsp(vty, 0, argv[3]->arg, NULL, NULL, NULL);
193 }
194 
zebra_mpls_bind(struct vty * vty,int add_cmd,const char * prefix,const char * label_str)195 static int zebra_mpls_bind(struct vty *vty, int add_cmd, const char *prefix,
196 			   const char *label_str)
197 {
198 	struct zebra_vrf *zvrf;
199 	struct prefix p;
200 	uint32_t label;
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"))
223 			label = MPLS_LABEL_IMPLICIT_NULL;
224 		else if (!strcmp(label_str, "explicit-null")) {
225 			if (p.family == AF_INET)
226 				label = MPLS_LABEL_IPV4_EXPLICIT_NULL;
227 			else
228 				label = MPLS_LABEL_IPV6_EXPLICIT_NULL;
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;
253 }
254 
255 DEFUN (mpls_label_bind,
256        mpls_label_bind_cmd,
257        "mpls label bind <A.B.C.D/M|X:X::X:X/M> <(16-1048575)|implicit-null|explicit-null>",
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"
264        "Use Implicit-Null Label\n"
265        "Use Explicit-Null Label\n")
266 {
267 	return zebra_mpls_bind(vty, 1, argv[3]->arg, argv[4]->arg);
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")
281 {
282 	return zebra_mpls_bind(vty, 0, argv[4]->arg, NULL);
283 }
284 
285 /* MPLS LSP configuration write function. */
zebra_mpls_config(struct vty * vty)286 static int zebra_mpls_config(struct vty *vty)
287 {
288 	int write = 0;
289 	struct zebra_vrf *zvrf;
290 
291 	zvrf = vrf_info_lookup(VRF_DEFAULT);
292 	if (!zvrf)
293 		return 0;
294 
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;
299 }
300 
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 {
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;
331 }
332 
333 DEFUN (show_mpls_table,
334        show_mpls_table_cmd,
335        "show mpls table [json]",
336        SHOW_STR
337        MPLS_STR
338        "MPLS table\n"
339        JSON_STR)
340 {
341 	struct zebra_vrf *zvrf;
342 	bool uj = use_json(argc, argv);
343 
344 	zvrf = vrf_info_lookup(VRF_DEFAULT);
345 	zebra_mpls_print_lsp_table(vty, zvrf, uj);
346 	return CMD_SUCCESS;
347 }
348 
349 DEFUN (show_mpls_table_lsp,
350        show_mpls_table_lsp_cmd,
351        "show mpls table (16-1048575) [json]",
352        SHOW_STR
353        MPLS_STR
354        "MPLS table\n"
355        "LSP to display information about\n"
356        JSON_STR)
357 {
358 	uint32_t label;
359 	struct zebra_vrf *zvrf;
360 	bool uj = use_json(argc, argv);
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;
366 }
367 
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 {
375 	vty_out(vty, "MPLS support enabled: %s\n",
376 		(mpls_enabled) ? "yes"
377 			       : "no (mpls kernel extensions not detected)");
378 	return CMD_SUCCESS;
379 }
380 
zebra_mpls_global_block(struct vty * vty,int add_cmd,const char * start_label_str,const char * end_label_str)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)
384 {
385 	int ret;
386 	uint32_t start_label;
387 	uint32_t end_label;
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;
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 {
436 	return zebra_mpls_global_block(vty, 1, argv[3]->arg, argv[4]->arg);
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 {
449 	return zebra_mpls_global_block(vty, 0, NULL, NULL);
450 }
451 
452 static int zebra_mpls_config(struct vty *vty);
453 /* MPLS node for MPLS LSP. */
454 static struct cmd_node mpls_node = {
455 	.name = "mpls",
456 	.node = MPLS_NODE,
457 	.prompt = "",
458 	.config_write = zebra_mpls_config,
459 };
460 
461 /* MPLS VTY.  */
zebra_mpls_vty_init(void)462 void zebra_mpls_vty_init(void)
463 {
464 	install_element(VIEW_NODE, &show_mpls_status_cmd);
465 
466 	install_node(&mpls_node);
467 
468 	install_element(CONFIG_NODE, &mpls_transit_lsp_cmd);
469 	install_element(CONFIG_NODE, &no_mpls_transit_lsp_cmd);
470 	install_element(CONFIG_NODE, &no_mpls_transit_lsp_out_label_cmd);
471 	install_element(CONFIG_NODE, &no_mpls_transit_lsp_all_cmd);
472 
473 	install_element(CONFIG_NODE, &mpls_label_bind_cmd);
474 	install_element(CONFIG_NODE, &no_mpls_label_bind_cmd);
475 
476 	install_element(CONFIG_NODE, &mpls_label_global_block_cmd);
477 	install_element(CONFIG_NODE, &no_mpls_label_global_block_cmd);
478 
479 	install_element(VIEW_NODE, &show_mpls_table_cmd);
480 	install_element(VIEW_NODE, &show_mpls_table_lsp_cmd);
481 	install_element(VIEW_NODE, &show_mpls_fec_cmd);
482 }
483