]> git.proxmox.com Git - mirror_frr.git/blob - bfdd/bfdd_cli.c
isisd: if IS-IS is configured for v6, prefer v6 bfd sessions
[mirror_frr.git] / bfdd / bfdd_cli.c
1 /*
2 * BFD daemon CLI implementation.
3 *
4 * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
5 * Rafael Zalamena
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301 USA.
21 */
22
23 #include <zebra.h>
24
25 #include "lib/command.h"
26 #include "lib/log.h"
27 #include "lib/northbound_cli.h"
28
29 #ifndef VTYSH_EXTRACT_PL
30 #include "bfdd/bfdd_cli_clippy.c"
31 #endif /* VTYSH_EXTRACT_PL */
32
33 #include "bfd.h"
34 #include "bfdd_nb.h"
35
36 /*
37 * Definitions.
38 */
39 #define PEER_STR "Configure peer\n"
40 #define INTERFACE_NAME_STR "Configure interface name to use\n"
41 #define PEER_IPV4_STR "IPv4 peer address\n"
42 #define PEER_IPV6_STR "IPv6 peer address\n"
43 #define MHOP_STR "Configure multihop\n"
44 #define LOCAL_STR "Configure local address\n"
45 #define LOCAL_IPV4_STR "IPv4 local address\n"
46 #define LOCAL_IPV6_STR "IPv6 local address\n"
47 #define LOCAL_INTF_STR "Configure local interface name to use\n"
48 #define VRF_STR "Configure VRF\n"
49 #define VRF_NAME_STR "Configure VRF name\n"
50
51 /*
52 * Prototypes.
53 */
54
55 /*
56 * Functions.
57 */
58 DEFPY_YANG_NOSH(
59 bfd_enter, bfd_enter_cmd,
60 "bfd",
61 "Configure BFD peers\n")
62 {
63 int ret;
64
65 nb_cli_enqueue_change(vty, "/frr-bfdd:bfdd/bfd", NB_OP_CREATE, NULL);
66 ret = nb_cli_apply_changes(vty, NULL);
67 if (ret == CMD_SUCCESS)
68 VTY_PUSH_XPATH(BFD_NODE, "/frr-bfdd:bfdd/bfd");
69
70 return ret;
71 }
72
73 DEFUN_YANG(
74 bfd_config_reset, bfd_config_reset_cmd,
75 "no bfd",
76 NO_STR
77 "Configure BFD peers\n")
78 {
79 nb_cli_enqueue_change(vty, "/frr-bfdd:bfdd/bfd", NB_OP_DESTROY, NULL);
80 return nb_cli_apply_changes(vty, NULL);
81 }
82
83 void bfd_cli_show_header(struct vty *vty,
84 struct lyd_node *dnode __attribute__((__unused__)),
85 bool show_defaults __attribute__((__unused__)))
86 {
87 vty_out(vty, "!\nbfd\n");
88 }
89
90 void bfd_cli_show_header_end(struct vty *vty,
91 struct lyd_node *dnode __attribute__((__unused__)))
92 {
93 vty_out(vty, "!\n");
94 }
95
96 DEFPY_YANG_NOSH(
97 bfd_peer_enter, bfd_peer_enter_cmd,
98 "peer <A.B.C.D|X:X::X:X> [{multihop$multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME$ifname|vrf NAME}]",
99 PEER_STR
100 PEER_IPV4_STR
101 PEER_IPV6_STR
102 MHOP_STR
103 LOCAL_STR
104 LOCAL_IPV4_STR
105 LOCAL_IPV6_STR
106 INTERFACE_STR
107 LOCAL_INTF_STR
108 VRF_STR
109 VRF_NAME_STR)
110 {
111 int ret, slen;
112 char source_str[INET6_ADDRSTRLEN + 32];
113 char xpath[XPATH_MAXLEN], xpath_srcaddr[XPATH_MAXLEN + 32];
114
115 if (multihop)
116 snprintf(source_str, sizeof(source_str), "[source-addr='%s']",
117 local_address_str);
118 else
119 source_str[0] = 0;
120
121 slen = snprintf(xpath, sizeof(xpath),
122 "/frr-bfdd:bfdd/bfd/sessions/%s%s[dest-addr='%s']",
123 multihop ? "multi-hop" : "single-hop", source_str,
124 peer_str);
125 if (ifname)
126 slen += snprintf(xpath + slen, sizeof(xpath) - slen,
127 "[interface='%s']", ifname);
128 else
129 slen += snprintf(xpath + slen, sizeof(xpath) - slen,
130 "[interface='*']");
131 if (vrf)
132 snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", vrf);
133 else
134 snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']",
135 VRF_DEFAULT_NAME);
136
137 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
138 if (multihop == NULL && local_address_str != NULL) {
139 snprintf(xpath_srcaddr, sizeof(xpath_srcaddr),
140 "%s/source-addr", xpath);
141 nb_cli_enqueue_change(vty, xpath_srcaddr, NB_OP_MODIFY,
142 local_address_str);
143 }
144
145 /* Apply settings immediately. */
146 ret = nb_cli_apply_changes(vty, NULL);
147 if (ret == CMD_SUCCESS)
148 VTY_PUSH_XPATH(BFD_PEER_NODE, xpath);
149
150 return ret;
151 }
152
153 DEFPY_YANG(
154 bfd_no_peer, bfd_no_peer_cmd,
155 "no peer <A.B.C.D|X:X::X:X> [{multihop$multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME$ifname|vrf NAME}]",
156 NO_STR
157 PEER_STR
158 PEER_IPV4_STR
159 PEER_IPV6_STR
160 MHOP_STR
161 LOCAL_STR
162 LOCAL_IPV4_STR
163 LOCAL_IPV6_STR
164 INTERFACE_STR
165 LOCAL_INTF_STR
166 VRF_STR
167 VRF_NAME_STR)
168 {
169 int slen;
170 char xpath[XPATH_MAXLEN];
171 char source_str[INET6_ADDRSTRLEN + 32];
172
173 if (multihop)
174 snprintf(source_str, sizeof(source_str), "[source-addr='%s']",
175 local_address_str);
176 else
177 source_str[0] = 0;
178
179 slen = snprintf(xpath, sizeof(xpath),
180 "/frr-bfdd:bfdd/bfd/sessions/%s%s[dest-addr='%s']",
181 multihop ? "multi-hop" : "single-hop", source_str,
182 peer_str);
183 if (ifname)
184 slen += snprintf(xpath + slen, sizeof(xpath) - slen,
185 "[interface='%s']", ifname);
186 else
187 slen += snprintf(xpath + slen, sizeof(xpath) - slen,
188 "[interface='*']");
189 if (vrf)
190 snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", vrf);
191 else
192 snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']",
193 VRF_DEFAULT_NAME);
194
195 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
196
197 /* Apply settings immediatly. */
198 return nb_cli_apply_changes(vty, NULL);
199 }
200
201 static void _bfd_cli_show_peer(struct vty *vty, struct lyd_node *dnode,
202 bool show_defaults __attribute__((__unused__)),
203 bool mhop)
204 {
205 const char *vrf = yang_dnode_get_string(dnode, "./vrf");
206 const char *ifname = yang_dnode_get_string(dnode, "./interface");
207
208 vty_out(vty, " peer %s",
209 yang_dnode_get_string(dnode, "./dest-addr"));
210
211 if (mhop)
212 vty_out(vty, " multihop");
213
214 if (yang_dnode_exists(dnode, "./source-addr"))
215 vty_out(vty, " local-address %s",
216 yang_dnode_get_string(dnode, "./source-addr"));
217
218 if (strcmp(vrf, VRF_DEFAULT_NAME))
219 vty_out(vty, " vrf %s", vrf);
220
221 if (strcmp(ifname, "*"))
222 vty_out(vty, " interface %s", ifname);
223
224 vty_out(vty, "\n");
225 }
226
227 void bfd_cli_show_single_hop_peer(struct vty *vty,
228 struct lyd_node *dnode,
229 bool show_defaults)
230 {
231 _bfd_cli_show_peer(vty, dnode, show_defaults, false);
232 }
233
234 void bfd_cli_show_multi_hop_peer(struct vty *vty,
235 struct lyd_node *dnode,
236 bool show_defaults)
237 {
238 _bfd_cli_show_peer(vty, dnode, show_defaults, true);
239 }
240
241 void bfd_cli_show_peer_end(struct vty *vty,
242 struct lyd_node *dnode __attribute__((__unused__)))
243 {
244 vty_out(vty, " !\n");
245 }
246
247 DEFPY_YANG(
248 bfd_peer_shutdown, bfd_peer_shutdown_cmd,
249 "[no] shutdown",
250 NO_STR
251 "Disable BFD peer\n")
252 {
253 nb_cli_enqueue_change(vty, "./administrative-down", NB_OP_MODIFY,
254 no ? "false" : "true");
255 return nb_cli_apply_changes(vty, NULL);
256 }
257
258 void bfd_cli_show_shutdown(struct vty *vty, struct lyd_node *dnode,
259 bool show_defaults)
260 {
261 if (show_defaults)
262 vty_out(vty, " shutdown\n");
263 else
264 vty_out(vty, " %sshutdown\n",
265 yang_dnode_get_bool(dnode, NULL) ? "" : "no ");
266 }
267
268 DEFPY_YANG(
269 bfd_peer_passive, bfd_peer_passive_cmd,
270 "[no] passive-mode",
271 NO_STR
272 "Don't attempt to start sessions\n")
273 {
274 nb_cli_enqueue_change(vty, "./passive-mode", NB_OP_MODIFY,
275 no ? "false" : "true");
276 return nb_cli_apply_changes(vty, NULL);
277 }
278
279 void bfd_cli_show_passive(struct vty *vty, struct lyd_node *dnode,
280 bool show_defaults)
281 {
282 if (show_defaults)
283 vty_out(vty, " no passive-mode\n");
284 else
285 vty_out(vty, " %spassive-mode\n",
286 yang_dnode_get_bool(dnode, NULL) ? "" : "no ");
287 }
288
289 DEFPY_YANG(
290 bfd_peer_minimum_ttl, bfd_peer_minimum_ttl_cmd,
291 "[no] minimum-ttl (1-254)$ttl",
292 NO_STR
293 "Expect packets with at least this TTL\n"
294 "Minimum TTL expected\n")
295 {
296 if (no)
297 nb_cli_enqueue_change(vty, "./minimum-ttl", NB_OP_DESTROY,
298 NULL);
299 else
300 nb_cli_enqueue_change(vty, "./minimum-ttl", NB_OP_MODIFY,
301 ttl_str);
302 return nb_cli_apply_changes(vty, NULL);
303 }
304
305 DEFPY_YANG(
306 no_bfd_peer_minimum_ttl, no_bfd_peer_minimum_ttl_cmd,
307 "no minimum-ttl",
308 NO_STR
309 "Expect packets with at least this TTL\n")
310 {
311 nb_cli_enqueue_change(vty, "./minimum-ttl", NB_OP_DESTROY, NULL);
312 return nb_cli_apply_changes(vty, NULL);
313 }
314
315 void bfd_cli_show_minimum_ttl(struct vty *vty, struct lyd_node *dnode,
316 bool show_defaults)
317 {
318 if (show_defaults)
319 vty_out(vty, " minimum-ttl 254\n");
320 else
321 vty_out(vty, " minimum-ttl %s\n",
322 yang_dnode_get_string(dnode, NULL));
323 }
324
325 DEFPY_YANG(
326 bfd_peer_mult, bfd_peer_mult_cmd,
327 "detect-multiplier (2-255)$multiplier",
328 "Configure peer detection multiplier\n"
329 "Configure peer detection multiplier value\n")
330 {
331 nb_cli_enqueue_change(vty, "./detection-multiplier", NB_OP_MODIFY,
332 multiplier_str);
333 return nb_cli_apply_changes(vty, NULL);
334 }
335
336 void bfd_cli_show_mult(struct vty *vty, struct lyd_node *dnode,
337 bool show_defaults)
338 {
339 if (show_defaults)
340 vty_out(vty, " detect-multiplier %d\n",
341 BFD_DEFDETECTMULT);
342 else
343 vty_out(vty, " detect-multiplier %s\n",
344 yang_dnode_get_string(dnode, NULL));
345 }
346
347 DEFPY_YANG(
348 bfd_peer_rx, bfd_peer_rx_cmd,
349 "receive-interval (10-60000)$interval",
350 "Configure peer receive interval\n"
351 "Configure peer receive interval value in milliseconds\n")
352 {
353 char value[32];
354
355 snprintf(value, sizeof(value), "%ld", interval * 1000);
356 nb_cli_enqueue_change(vty, "./required-receive-interval", NB_OP_MODIFY,
357 value);
358
359 return nb_cli_apply_changes(vty, NULL);
360 }
361
362 void bfd_cli_show_rx(struct vty *vty, struct lyd_node *dnode,
363 bool show_defaults)
364 {
365 uint32_t value;
366
367 if (show_defaults)
368 vty_out(vty, " receive-interval %d\n",
369 BFD_DEFREQUIREDMINRX);
370 else {
371 value = yang_dnode_get_uint32(dnode, NULL);
372 vty_out(vty, " receive-interval %u\n", value / 1000);
373 }
374 }
375
376 DEFPY_YANG(
377 bfd_peer_tx, bfd_peer_tx_cmd,
378 "transmit-interval (10-60000)$interval",
379 "Configure peer transmit interval\n"
380 "Configure peer transmit interval value in milliseconds\n")
381 {
382 char value[32];
383
384 snprintf(value, sizeof(value), "%ld", interval * 1000);
385 nb_cli_enqueue_change(vty, "./desired-transmission-interval",
386 NB_OP_MODIFY, value);
387
388 return nb_cli_apply_changes(vty, NULL);
389 }
390
391 void bfd_cli_show_tx(struct vty *vty, struct lyd_node *dnode,
392 bool show_defaults)
393 {
394 uint32_t value;
395
396 if (show_defaults)
397 vty_out(vty, " transmit-interval %d\n",
398 BFD_DEFDESIREDMINTX);
399 else {
400 value = yang_dnode_get_uint32(dnode, NULL);
401 vty_out(vty, " transmit-interval %u\n", value / 1000);
402 }
403 }
404
405 DEFPY_YANG(
406 bfd_peer_echo, bfd_peer_echo_cmd,
407 "[no] echo-mode",
408 NO_STR
409 "Configure echo mode\n")
410 {
411 nb_cli_enqueue_change(vty, "./echo-mode", NB_OP_MODIFY,
412 no ? "false" : "true");
413 return nb_cli_apply_changes(vty, NULL);
414 }
415
416 void bfd_cli_show_echo(struct vty *vty, struct lyd_node *dnode,
417 bool show_defaults)
418 {
419 if (show_defaults)
420 vty_out(vty, " no echo-mode\n");
421 else
422 vty_out(vty, " %secho-mode\n",
423 yang_dnode_get_bool(dnode, NULL) ? "" : "no ");
424 }
425
426 DEFPY_YANG(
427 bfd_peer_echo_interval, bfd_peer_echo_interval_cmd,
428 "echo-interval (10-60000)$interval",
429 "Configure peer echo interval\n"
430 "Configure peer echo interval value in milliseconds\n")
431 {
432 char value[32];
433
434 snprintf(value, sizeof(value), "%ld", interval * 1000);
435 nb_cli_enqueue_change(vty, "./desired-echo-transmission-interval",
436 NB_OP_MODIFY, value);
437
438 return nb_cli_apply_changes(vty, NULL);
439 }
440
441 void bfd_cli_show_echo_interval(struct vty *vty, struct lyd_node *dnode,
442 bool show_defaults)
443 {
444 uint32_t value;
445
446 if (show_defaults)
447 vty_out(vty, " echo-interval %d\n",
448 BFD_DEF_REQ_MIN_ECHO);
449 else {
450 value = yang_dnode_get_uint32(dnode, NULL);
451 vty_out(vty, " echo-interval %u\n", value / 1000);
452 }
453 }
454
455 /*
456 * Profile commands.
457 */
458 DEFPY_YANG_NOSH(bfd_profile, bfd_profile_cmd,
459 "profile WORD$name",
460 BFD_PROFILE_STR
461 BFD_PROFILE_NAME_STR)
462 {
463 char xpath[XPATH_MAXLEN];
464 int rv;
465
466 snprintf(xpath, sizeof(xpath), "/frr-bfdd:bfdd/bfd/profile[name='%s']",
467 name);
468
469 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
470
471 /* Apply settings immediately. */
472 rv = nb_cli_apply_changes(vty, NULL);
473 if (rv == CMD_SUCCESS)
474 VTY_PUSH_XPATH(BFD_PROFILE_NODE, xpath);
475
476 return CMD_SUCCESS;
477 }
478
479 DEFPY_YANG(no_bfd_profile, no_bfd_profile_cmd,
480 "no profile BFDPROF$name",
481 NO_STR
482 BFD_PROFILE_STR
483 BFD_PROFILE_NAME_STR)
484 {
485 char xpath[XPATH_MAXLEN];
486
487 snprintf(xpath, sizeof(xpath), "/frr-bfdd:bfdd/bfd/profile[name='%s']",
488 name);
489
490 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
491
492 /* Apply settings immediately. */
493 return nb_cli_apply_changes(vty, NULL);
494 }
495
496 void bfd_cli_show_profile(struct vty *vty, struct lyd_node *dnode,
497 bool show_defaults)
498 {
499 vty_out(vty, " profile %s\n", yang_dnode_get_string(dnode, "./name"));
500 }
501
502 ALIAS_YANG(bfd_peer_mult, bfd_profile_mult_cmd,
503 "detect-multiplier (2-255)$multiplier",
504 "Configure peer detection multiplier\n"
505 "Configure peer detection multiplier value\n")
506
507 ALIAS_YANG(bfd_peer_tx, bfd_profile_tx_cmd,
508 "transmit-interval (10-60000)$interval",
509 "Configure peer transmit interval\n"
510 "Configure peer transmit interval value in milliseconds\n")
511
512 ALIAS_YANG(bfd_peer_rx, bfd_profile_rx_cmd,
513 "receive-interval (10-60000)$interval",
514 "Configure peer receive interval\n"
515 "Configure peer receive interval value in milliseconds\n")
516
517 ALIAS_YANG(bfd_peer_shutdown, bfd_profile_shutdown_cmd,
518 "[no] shutdown",
519 NO_STR
520 "Disable BFD peer\n")
521
522 ALIAS_YANG(bfd_peer_passive, bfd_profile_passive_cmd,
523 "[no] passive-mode",
524 NO_STR
525 "Don't attempt to start sessions\n")
526
527 ALIAS_YANG(bfd_peer_minimum_ttl, bfd_profile_minimum_ttl_cmd,
528 "[no] minimum-ttl (1-254)$ttl",
529 NO_STR
530 "Expect packets with at least this TTL\n"
531 "Minimum TTL expected\n")
532
533 ALIAS_YANG(no_bfd_peer_minimum_ttl, no_bfd_profile_minimum_ttl_cmd,
534 "no minimum-ttl",
535 NO_STR
536 "Expect packets with at least this TTL\n")
537
538 ALIAS_YANG(bfd_peer_echo, bfd_profile_echo_cmd,
539 "[no] echo-mode",
540 NO_STR
541 "Configure echo mode\n")
542
543 ALIAS_YANG(bfd_peer_echo_interval, bfd_profile_echo_interval_cmd,
544 "echo-interval (10-60000)$interval",
545 "Configure peer echo interval\n"
546 "Configure peer echo interval value in milliseconds\n")
547
548 DEFPY_YANG(bfd_peer_profile, bfd_peer_profile_cmd,
549 "[no] profile BFDPROF$pname",
550 NO_STR
551 "Use BFD profile settings\n"
552 BFD_PROFILE_NAME_STR)
553 {
554 if (no)
555 nb_cli_enqueue_change(vty, "./profile", NB_OP_DESTROY, NULL);
556 else
557 nb_cli_enqueue_change(vty, "./profile", NB_OP_MODIFY, pname);
558
559 return nb_cli_apply_changes(vty, NULL);
560 }
561
562 void bfd_cli_peer_profile_show(struct vty *vty, struct lyd_node *dnode,
563 bool show_defaults)
564 {
565 vty_out(vty, " profile %s\n", yang_dnode_get_string(dnode, NULL));
566 }
567
568 struct cmd_node bfd_profile_node = {
569 .name = "bfd profile",
570 .node = BFD_PROFILE_NODE,
571 .parent_node = BFD_NODE,
572 .prompt = "%s(config-bfd-profile)# ",
573 };
574
575 static void bfd_profile_var(vector comps, struct cmd_token *token)
576 {
577 extern struct bfdproflist bplist;
578 struct bfd_profile *bp;
579
580 TAILQ_FOREACH (bp, &bplist, entry) {
581 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, bp->name));
582 }
583 }
584
585 static const struct cmd_variable_handler bfd_vars[] = {
586 {.tokenname = "BFDPROF", .completions = bfd_profile_var},
587 {.completions = NULL}
588 };
589
590 void
591 bfdd_cli_init(void)
592 {
593 install_element(CONFIG_NODE, &bfd_enter_cmd);
594 install_element(CONFIG_NODE, &bfd_config_reset_cmd);
595
596 install_element(BFD_NODE, &bfd_peer_enter_cmd);
597 install_element(BFD_NODE, &bfd_no_peer_cmd);
598
599 install_element(BFD_PEER_NODE, &bfd_peer_shutdown_cmd);
600 install_element(BFD_PEER_NODE, &bfd_peer_mult_cmd);
601 install_element(BFD_PEER_NODE, &bfd_peer_rx_cmd);
602 install_element(BFD_PEER_NODE, &bfd_peer_tx_cmd);
603 install_element(BFD_PEER_NODE, &bfd_peer_echo_cmd);
604 install_element(BFD_PEER_NODE, &bfd_peer_echo_interval_cmd);
605 install_element(BFD_PEER_NODE, &bfd_peer_profile_cmd);
606 install_element(BFD_PEER_NODE, &bfd_peer_passive_cmd);
607 install_element(BFD_PEER_NODE, &bfd_peer_minimum_ttl_cmd);
608 install_element(BFD_PEER_NODE, &no_bfd_peer_minimum_ttl_cmd);
609
610 /* Profile commands. */
611 cmd_variable_handler_register(bfd_vars);
612
613 install_node(&bfd_profile_node);
614 install_default(BFD_PROFILE_NODE);
615
616 install_element(BFD_NODE, &bfd_profile_cmd);
617 install_element(BFD_NODE, &no_bfd_profile_cmd);
618
619 install_element(BFD_PROFILE_NODE, &bfd_profile_mult_cmd);
620 install_element(BFD_PROFILE_NODE, &bfd_profile_tx_cmd);
621 install_element(BFD_PROFILE_NODE, &bfd_profile_rx_cmd);
622 install_element(BFD_PROFILE_NODE, &bfd_profile_shutdown_cmd);
623 install_element(BFD_PROFILE_NODE, &bfd_profile_echo_cmd);
624 install_element(BFD_PROFILE_NODE, &bfd_profile_echo_interval_cmd);
625 install_element(BFD_PROFILE_NODE, &bfd_profile_passive_cmd);
626 install_element(BFD_PROFILE_NODE, &bfd_profile_minimum_ttl_cmd);
627 install_element(BFD_PROFILE_NODE, &no_bfd_profile_minimum_ttl_cmd);
628 }