1 /*
2  * SHARP - vty code
3  * Copyright (C) Cumulus Networks, Inc.
4  *               Donald Sharp
5  *
6  * This file is part of FRR.
7  *
8  * FRR is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the
10  * Free Software Foundation; either version 2, or (at your option) any
11  * later version.
12  *
13  * FRR is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; see the file COPYING; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 #include <zebra.h>
23 
24 #include "vty.h"
25 #include "command.h"
26 #include "prefix.h"
27 #include "nexthop.h"
28 #include "log.h"
29 #include "vrf.h"
30 #include "zclient.h"
31 #include "nexthop_group.h"
32 
33 #include "sharpd/sharp_globals.h"
34 #include "sharpd/sharp_zebra.h"
35 #include "sharpd/sharp_nht.h"
36 #include "sharpd/sharp_vty.h"
37 #ifndef VTYSH_EXTRACT_PL
38 #include "sharpd/sharp_vty_clippy.c"
39 #endif
40 
41 DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd,
42       "sharp watch [vrf NAME$vrf_name] <nexthop$n X:X::X:X$nhop|import$import X:X::X:X/M$inhop>  [connected$connected]",
43       "Sharp routing Protocol\n"
44       "Watch for changes\n"
45       "The vrf we would like to watch if non-default\n"
46       "The NAME of the vrf\n"
47       "Watch for nexthop changes\n"
48       "The v6 nexthop to signal for watching\n"
49       "Watch for import check changes\n"
50       "The v6 prefix to signal for watching\n"
51       "Should the route be connected\n")
52 {
53 	struct vrf *vrf;
54 	struct prefix p;
55 	bool type_import;
56 
57 	if (!vrf_name)
58 		vrf_name = VRF_DEFAULT_NAME;
59 	vrf = vrf_lookup_by_name(vrf_name);
60 	if (!vrf) {
61 		vty_out(vty, "The vrf NAME specified: %s does not exist\n",
62 			vrf_name);
63 		return CMD_WARNING;
64 	}
65 
66 	memset(&p, 0, sizeof(p));
67 
68 	if (n) {
69 		type_import = false;
70 		p.prefixlen = 128;
71 		memcpy(&p.u.prefix6, &nhop, 16);
72 		p.family = AF_INET6;
73 	} else {
74 		type_import = true;
75 		p = *(const struct prefix *)inhop;
76 	}
77 
78 	sharp_nh_tracker_get(&p);
79 	sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import,
80 				  true, !!connected);
81 
82 	return CMD_SUCCESS;
83 }
84 
85 DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd,
86       "sharp watch [vrf NAME$vrf_name] <nexthop$n A.B.C.D$nhop|import$import A.B.C.D/M$inhop> [connected$connected]",
87       "Sharp routing Protocol\n"
88       "Watch for changes\n"
89       "The vrf we would like to watch if non-default\n"
90       "The NAME of the vrf\n"
91       "Watch for nexthop changes\n"
92       "The v4 address to signal for watching\n"
93       "Watch for import check changes\n"
94       "The v4 prefix for import check to watch\n"
95       "Should the route be connected\n")
96 {
97 	struct vrf *vrf;
98 	struct prefix p;
99 	bool type_import;
100 
101 	if (!vrf_name)
102 		vrf_name = VRF_DEFAULT_NAME;
103 	vrf = vrf_lookup_by_name(vrf_name);
104 	if (!vrf) {
105 		vty_out(vty, "The vrf NAME specified: %s does not exist\n",
106 			vrf_name);
107 		return CMD_WARNING;
108 	}
109 
110 	memset(&p, 0, sizeof(p));
111 
112 	if (n) {
113 		type_import = false;
114 		p.prefixlen = 32;
115 		p.u.prefix4 = nhop;
116 		p.family = AF_INET;
117 	}
118 	else {
119 		type_import = true;
120 		p = *(const struct prefix *)inhop;
121 	}
122 
123 	sharp_nh_tracker_get(&p);
124 	sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import,
125 				  true, !!connected);
126 
127 	return CMD_SUCCESS;
128 }
129 
130 DEFPY(sharp_nht_data_dump,
131       sharp_nht_data_dump_cmd,
132       "sharp data nexthop",
133       "Sharp routing Protocol\n"
134       "Data about what is going on\n"
135       "Nexthop information\n")
136 {
137 	sharp_nh_tracker_dump(vty);
138 
139 	return CMD_SUCCESS;
140 }
141 
142 DEFPY (install_routes_data_dump,
143        install_routes_data_dump_cmd,
144        "sharp data route",
145        "Sharp routing Protocol\n"
146        "Data about what is going on\n"
147        "Route Install/Removal Information\n")
148 {
149 	char buf[PREFIX_STRLEN];
150 	struct timeval r;
151 
152 	timersub(&sg.r.t_end, &sg.r.t_start, &r);
153 	vty_out(vty, "Prefix: %s Total: %u %u %u Time: %jd.%ld\n",
154 		prefix2str(&sg.r.orig_prefix, buf, sizeof(buf)),
155 		sg.r.total_routes,
156 		sg.r.installed_routes,
157 		sg.r.removed_routes,
158 		(intmax_t)r.tv_sec, (long)r.tv_usec);
159 
160 	return CMD_SUCCESS;
161 }
162 
163 DEFPY (install_routes,
164        install_routes_cmd,
165        "sharp install routes [vrf NAME$vrf_name]\
166 	  <A.B.C.D$start4|X:X::X:X$start6>\
167 	  <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|\
168 	   nexthop-group NHGNAME$nexthop_group>\
169 	  [backup$backup <A.B.C.D$backup_nexthop4|X:X::X:X$backup_nexthop6>] \
170 	  (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]",
171        "Sharp routing Protocol\n"
172        "install some routes\n"
173        "Routes to install\n"
174        "The vrf we would like to install into if non-default\n"
175        "The NAME of the vrf\n"
176        "v4 Address to start /32 generation at\n"
177        "v6 Address to start /32 generation at\n"
178        "Nexthop to use(Can be an IPv4 or IPv6 address)\n"
179        "V4 Nexthop address to use\n"
180        "V6 Nexthop address to use\n"
181        "Nexthop-Group to use\n"
182        "The Name of the nexthop-group\n"
183        "Backup nexthop to use(Can be an IPv4 or IPv6 address)\n"
184        "Backup V4 Nexthop address to use\n"
185        "Backup V6 Nexthop address to use\n"
186        "How many to create\n"
187        "Instance to use\n"
188        "Instance\n"
189        "Should we repeat this command\n"
190        "How many times to repeat this command\n")
191 {
192 	struct vrf *vrf;
193 	struct prefix prefix;
194 	uint32_t rts;
195 
196 	sg.r.total_routes = routes;
197 	sg.r.installed_routes = 0;
198 
199 	if (rpt >= 2)
200 		sg.r.repeat = rpt * 2;
201 	else
202 		sg.r.repeat = 0;
203 
204 	memset(&prefix, 0, sizeof(prefix));
205 	memset(&sg.r.orig_prefix, 0, sizeof(sg.r.orig_prefix));
206 	memset(&sg.r.nhop, 0, sizeof(sg.r.nhop));
207 	memset(&sg.r.nhop_group, 0, sizeof(sg.r.nhop_group));
208 	memset(&sg.r.backup_nhop, 0, sizeof(sg.r.nhop));
209 	memset(&sg.r.backup_nhop_group, 0, sizeof(sg.r.nhop_group));
210 
211 	if (start4.s_addr != 0) {
212 		prefix.family = AF_INET;
213 		prefix.prefixlen = 32;
214 		prefix.u.prefix4 = start4;
215 	} else {
216 		prefix.family = AF_INET6;
217 		prefix.prefixlen = 128;
218 		prefix.u.prefix6 = start6;
219 	}
220 	sg.r.orig_prefix = prefix;
221 
222 	if (!vrf_name)
223 		vrf_name = VRF_DEFAULT_NAME;
224 
225 	vrf = vrf_lookup_by_name(vrf_name);
226 	if (!vrf) {
227 		vty_out(vty, "The vrf NAME specified: %s does not exist\n",
228 			vrf_name);
229 		return CMD_WARNING;
230 	}
231 
232 	/* Explicit backup not available with named nexthop-group */
233 	if (backup && nexthop_group) {
234 		vty_out(vty, "%% Invalid: cannot specify both nexthop-group and backup\n");
235 		return CMD_WARNING;
236 	}
237 
238 	if (nexthop_group) {
239 		struct nexthop_group_cmd *nhgc = nhgc_find(nexthop_group);
240 		if (!nhgc) {
241 			vty_out(vty,
242 				"Specified Nexthop Group: %s does not exist\n",
243 				nexthop_group);
244 			return CMD_WARNING;
245 		}
246 
247 		sg.r.nhop_group.nexthop = nhgc->nhg.nexthop;
248 
249 		/* Use group's backup nexthop info if present */
250 		if (nhgc->backup_list_name[0]) {
251 			struct nexthop_group_cmd *bnhgc =
252 				nhgc_find(nhgc->backup_list_name);
253 
254 			if (!bnhgc) {
255 				vty_out(vty, "%% Backup group %s not found for group %s\n",
256 					nhgc->backup_list_name,
257 					nhgc->name);
258 				return CMD_WARNING;
259 			}
260 
261 			sg.r.backup_nhop.vrf_id = vrf->vrf_id;
262 			sg.r.backup_nhop_group.nexthop = bnhgc->nhg.nexthop;
263 		}
264 	} else {
265 		if (nexthop4.s_addr != INADDR_ANY) {
266 			sg.r.nhop.gate.ipv4 = nexthop4;
267 			sg.r.nhop.type = NEXTHOP_TYPE_IPV4;
268 		} else {
269 			sg.r.nhop.gate.ipv6 = nexthop6;
270 			sg.r.nhop.type = NEXTHOP_TYPE_IPV6;
271 		}
272 
273 		sg.r.nhop.vrf_id = vrf->vrf_id;
274 		sg.r.nhop_group.nexthop = &sg.r.nhop;
275 	}
276 
277 	/* Use single backup nexthop if specified */
278 	if (backup) {
279 		/* Set flag and index in primary nexthop */
280 		SET_FLAG(sg.r.nhop.flags, NEXTHOP_FLAG_HAS_BACKUP);
281 		sg.r.nhop.backup_num = 1;
282 		sg.r.nhop.backup_idx[0] = 0;
283 
284 		if (backup_nexthop4.s_addr != INADDR_ANY) {
285 			sg.r.backup_nhop.gate.ipv4 = backup_nexthop4;
286 			sg.r.backup_nhop.type = NEXTHOP_TYPE_IPV4;
287 		} else {
288 			sg.r.backup_nhop.gate.ipv6 = backup_nexthop6;
289 			sg.r.backup_nhop.type = NEXTHOP_TYPE_IPV6;
290 		}
291 
292 		sg.r.backup_nhop.vrf_id = vrf->vrf_id;
293 		sg.r.backup_nhop_group.nexthop = &sg.r.backup_nhop;
294 	}
295 
296 	sg.r.inst = instance;
297 	sg.r.vrf_id = vrf->vrf_id;
298 	rts = routes;
299 	sharp_install_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst,
300 				    &sg.r.nhop_group, &sg.r.backup_nhop_group,
301 				    rts);
302 
303 	return CMD_SUCCESS;
304 }
305 
306 DEFPY(vrf_label, vrf_label_cmd,
307       "sharp label <ip$ipv4|ipv6$ipv6> vrf NAME$vrf_name label (0-100000)$label",
308       "Sharp Routing Protocol\n"
309       "Give a vrf a label\n"
310       "Pop and forward for IPv4\n"
311       "Pop and forward for IPv6\n"
312       VRF_CMD_HELP_STR
313       "The label to use, 0 specifies remove the label installed from previous\n"
314       "Specified range to use\n")
315 {
316 	struct vrf *vrf;
317 	afi_t afi = (ipv4) ? AFI_IP : AFI_IP6;
318 
319 	if (strcmp(vrf_name, "default") == 0)
320 		vrf = vrf_lookup_by_id(VRF_DEFAULT);
321 	else
322 		vrf = vrf_lookup_by_name(vrf_name);
323 
324 	if (!vrf) {
325 		vty_out(vty, "Unable to find vrf you silly head");
326 		return CMD_WARNING_CONFIG_FAILED;
327 	}
328 
329 	if (label == 0)
330 		label = MPLS_LABEL_NONE;
331 
332 	vrf_label_add(vrf->vrf_id, afi, label);
333 	return CMD_SUCCESS;
334 }
335 
336 DEFPY (remove_routes,
337        remove_routes_cmd,
338        "sharp remove routes [vrf NAME$vrf_name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]",
339        "Sharp Routing Protocol\n"
340        "Remove some routes\n"
341        "Routes to remove\n"
342        "The vrf we would like to remove from if non-default\n"
343        "The NAME of the vrf\n"
344        "v4 Starting spot\n"
345        "v6 Starting spot\n"
346        "Routes to uninstall\n"
347        "instance to use\n"
348        "Value of instance\n")
349 {
350 	struct vrf *vrf;
351 	struct prefix prefix;
352 
353 	sg.r.total_routes = routes;
354 	sg.r.removed_routes = 0;
355 	uint32_t rts;
356 
357 	memset(&prefix, 0, sizeof(prefix));
358 
359 	if (start4.s_addr != 0) {
360 		prefix.family = AF_INET;
361 		prefix.prefixlen = 32;
362 		prefix.u.prefix4 = start4;
363 	} else {
364 		prefix.family = AF_INET6;
365 		prefix.prefixlen = 128;
366 		prefix.u.prefix6 = start6;
367 	}
368 
369 	vrf = vrf_lookup_by_name(vrf_name ? vrf_name : VRF_DEFAULT_NAME);
370 	if (!vrf) {
371 		vty_out(vty, "The vrf NAME specified: %s does not exist\n",
372 			vrf_name ? vrf_name : VRF_DEFAULT_NAME);
373 		return CMD_WARNING;
374 	}
375 
376 	sg.r.inst = instance;
377 	sg.r.vrf_id = vrf->vrf_id;
378 	rts = routes;
379 	sharp_remove_routes_helper(&prefix, sg.r.vrf_id,
380 				   sg.r.inst, rts);
381 
382 	return CMD_SUCCESS;
383 }
384 
385 DEFUN_NOSH (show_debugging_sharpd,
386 	    show_debugging_sharpd_cmd,
387 	    "show debugging [sharp]",
388 	    SHOW_STR
389 	    DEBUG_STR
390 	    "Sharp Information\n")
391 {
392 	vty_out(vty, "Sharp debugging status:\n");
393 
394 	return CMD_SUCCESS;
395 }
396 
397 DEFPY (sharp_lsp_prefix_v4, sharp_lsp_prefix_v4_cmd,
398        "sharp lsp [update]$update (0-100000)$inlabel\
399         nexthop-group NHGNAME$nhgname\
400         [prefix A.B.C.D/M$pfx\
401        " FRR_IP_REDIST_STR_ZEBRA "$type_str [instance (0-255)$instance]]",
402        "Sharp Routing Protocol\n"
403        "Add an LSP\n"
404        "Update an LSP\n"
405        "The ingress label to use\n"
406        "Use nexthops from a nexthop-group\n"
407        "The nexthop-group name\n"
408        "Label a prefix\n"
409        "The v4 prefix to label\n"
410        FRR_IP_REDIST_HELP_STR_ZEBRA
411        "Instance to use\n"
412        "Instance\n")
413 {
414 	struct nexthop_group_cmd *nhgc = NULL;
415 	struct nexthop_group_cmd *backup_nhgc = NULL;
416 	struct nexthop_group *backup_nhg = NULL;
417 	struct prefix p = {};
418 	int type = 0;
419 	bool update_p;
420 
421 	update_p = (update != NULL);
422 
423 	/* We're offered a v4 prefix */
424 	if (pfx->family > 0 && type_str) {
425 		p.family = pfx->family;
426 		p.prefixlen = pfx->prefixlen;
427 		p.u.prefix4 = pfx->prefix;
428 
429 		type = proto_redistnum(AFI_IP, type_str);
430 		if (type < 0) {
431 			vty_out(vty, "%%  Unknown route type '%s'\n", type_str);
432 			return CMD_WARNING;
433 		}
434 	} else if (pfx->family > 0 || type_str) {
435 		vty_out(vty, "%%  Must supply both prefix and type\n");
436 		return CMD_WARNING;
437 	}
438 
439 	nhgc = nhgc_find(nhgname);
440 	if (!nhgc) {
441 		vty_out(vty, "%%  Nexthop-group '%s' does not exist\n",
442 			nhgname);
443 		return CMD_WARNING;
444 	}
445 
446 	if (nhgc->nhg.nexthop == NULL) {
447 		vty_out(vty, "%%  Nexthop-group '%s' is empty\n", nhgname);
448 		return CMD_WARNING;
449 	}
450 
451 	/* Use group's backup nexthop info if present */
452 	if (nhgc->backup_list_name[0]) {
453 		backup_nhgc = nhgc_find(nhgc->backup_list_name);
454 
455 		if (!backup_nhgc) {
456 			vty_out(vty,
457 				"%% Backup group %s not found for group %s\n",
458 				nhgc->backup_list_name,
459 				nhgname);
460 			return CMD_WARNING;
461 		}
462 		backup_nhg = &(backup_nhgc->nhg);
463 	}
464 
465 	if (sharp_install_lsps_helper(true /*install*/, update_p,
466 				      pfx->family > 0 ? &p : NULL,
467 				      type, instance, inlabel,
468 				      &(nhgc->nhg), backup_nhg) == 0)
469 		return CMD_SUCCESS;
470 	else {
471 		vty_out(vty, "%% LSP install failed!\n");
472 		return CMD_WARNING;
473 	}
474 }
475 
476 DEFPY(sharp_remove_lsp_prefix_v4, sharp_remove_lsp_prefix_v4_cmd,
477       "sharp remove lsp \
478         (0-100000)$inlabel\
479         [nexthop-group NHGNAME$nhgname] \
480         [prefix A.B.C.D/M$pfx\
481        " FRR_IP_REDIST_STR_SHARPD "$type_str [instance (0-255)$instance]]",
482       "Sharp Routing Protocol\n"
483       "Remove data\n"
484       "Remove an LSP\n"
485       "The ingress label\n"
486       "Use nexthops from a nexthop-group\n"
487       "The nexthop-group name\n"
488       "Specify a v4 prefix\n"
489       "The v4 prefix to label\n"
490       FRR_IP_REDIST_HELP_STR_SHARPD
491       "Routing instance\n"
492       "Instance to use\n")
493 {
494 	struct nexthop_group_cmd *nhgc = NULL;
495 	struct prefix p = {};
496 	int type = 0;
497 	struct nexthop_group *nhg = NULL;
498 
499 	/* We're offered a v4 prefix */
500 	if (pfx->family > 0 && type_str) {
501 		p.family = pfx->family;
502 		p.prefixlen = pfx->prefixlen;
503 		p.u.prefix4 = pfx->prefix;
504 
505 		type = proto_redistnum(AFI_IP, type_str);
506 		if (type < 0) {
507 			vty_out(vty, "%%  Unknown route type '%s'\n", type_str);
508 			return CMD_WARNING;
509 		}
510 	} else if (pfx->family > 0 || type_str) {
511 		vty_out(vty, "%%  Must supply both prefix and type\n");
512 		return CMD_WARNING;
513 	}
514 
515 	if (nhgname) {
516 		nhgc = nhgc_find(nhgname);
517 		if (!nhgc) {
518 			vty_out(vty, "%%  Nexthop-group '%s' does not exist\n",
519 				nhgname);
520 			return CMD_WARNING;
521 		}
522 
523 		if (nhgc->nhg.nexthop == NULL) {
524 			vty_out(vty, "%%  Nexthop-group '%s' is empty\n",
525 				nhgname);
526 			return CMD_WARNING;
527 		}
528 		nhg = &(nhgc->nhg);
529 	}
530 
531 	if (sharp_install_lsps_helper(false /*!install*/, false,
532 				      pfx->family > 0 ? &p : NULL,
533 				      type, instance, inlabel, nhg, NULL) == 0)
534 		return CMD_SUCCESS;
535 	else {
536 		vty_out(vty, "%% LSP remove failed!\n");
537 		return CMD_WARNING;
538 	}
539 }
540 
541 DEFPY (logpump,
542        logpump_cmd,
543        "sharp logpump duration (1-60) frequency (1-1000000) burst (1-1000)",
544        "Sharp Routing Protocol\n"
545        "Generate bulk log messages for testing\n"
546        "Duration of run (s)\n"
547        "Duration of run (s)\n"
548        "Frequency of bursts (s^-1)\n"
549        "Frequency of bursts (s^-1)\n"
550        "Number of log messages per each burst\n"
551        "Number of log messages per each burst\n")
552 {
553 	sharp_logpump_run(vty, duration, frequency, burst);
554 	return CMD_SUCCESS;
555 }
556 
557 DEFPY (create_session,
558        create_session_cmd,
559        "sharp create session (1-1024)",
560        "Sharp Routing Protocol\n"
561        "Create data\n"
562        "Create a test session\n"
563        "Session ID\n")
564 {
565 	if (sharp_zclient_create(session) != 0) {
566 		vty_out(vty, "%% Client session error\n");
567 		return CMD_WARNING;
568 	}
569 
570 	return CMD_SUCCESS;
571 }
572 
573 DEFPY (remove_session,
574        remove_session_cmd,
575        "sharp remove session (1-1024)",
576        "Sharp Routing Protocol\n"
577        "Remove data\n"
578        "Remove a test session\n"
579        "Session ID\n")
580 {
581 	sharp_zclient_delete(session);
582 	return CMD_SUCCESS;
583 }
584 
585 DEFPY (send_opaque,
586        send_opaque_cmd,
587        "sharp send opaque type (1-255) (1-1000)$count",
588        SHARP_STR
589        "Send messages for testing\n"
590        "Send opaque messages\n"
591        "Type code to send\n"
592        "Type code to send\n"
593        "Number of messages to send\n")
594 {
595 	sharp_opaque_send(type, 0, 0, 0, count);
596 	return CMD_SUCCESS;
597 }
598 
599 DEFPY (send_opaque_unicast,
600        send_opaque_unicast_cmd,
601        "sharp send opaque unicast type (1-255) \
602        " FRR_IP_REDIST_STR_ZEBRA "$proto_str \
603         [{instance (0-1000) | session (1-1000)}] (1-1000)$count",
604        SHARP_STR
605        "Send messages for testing\n"
606        "Send opaque messages\n"
607        "Send unicast messages\n"
608        "Type code to send\n"
609        "Type code to send\n"
610        FRR_IP_REDIST_HELP_STR_ZEBRA
611        "Daemon instance\n"
612        "Daemon instance\n"
613        "Session ID\n"
614        "Session ID\n"
615        "Number of messages to send\n")
616 {
617 	uint32_t proto;
618 
619 	proto = proto_redistnum(AFI_IP, proto_str);
620 
621 	sharp_opaque_send(type, proto, instance, session, count);
622 
623 	return CMD_SUCCESS;
624 }
625 
626 DEFPY (send_opaque_reg,
627        send_opaque_reg_cmd,
628        "sharp send opaque <reg$reg | unreg> \
629        " FRR_IP_REDIST_STR_ZEBRA "$proto_str \
630         [{instance (0-1000) | session (1-1000)}] type (1-1000)",
631        SHARP_STR
632        "Send messages for testing\n"
633        "Send opaque messages\n"
634        "Send opaque registration\n"
635        "Send opaque unregistration\n"
636        FRR_IP_REDIST_HELP_STR_ZEBRA
637        "Daemon instance\n"
638        "Daemon instance\n"
639        "Session ID\n"
640        "Session ID\n"
641        "Opaque sub-type code\n"
642        "Opaque sub-type code\n")
643 {
644 	int proto;
645 
646 	proto = proto_redistnum(AFI_IP, proto_str);
647 
648 	sharp_opaque_reg_send((reg != NULL), proto, instance, session, type);
649 	return CMD_SUCCESS;
650 }
651 
652 DEFPY (neigh_discover,
653        neigh_discover_cmd,
654        "sharp neigh discover [vrf NAME$vrf_name] <A.B.C.D$dst4|X:X::X:X$dst6> IFNAME$ifname",
655        SHARP_STR
656        "Discover neighbours\n"
657        "Send an ARP/NDP request\n"
658        VRF_CMD_HELP_STR
659        "v4 Destination address\n"
660        "v6 Destination address\n"
661        "Interface name\n")
662 {
663 	struct vrf *vrf;
664 	struct interface *ifp;
665 	struct prefix prefix;
666 
667 	memset(&prefix, 0, sizeof(prefix));
668 
669 	if (dst4.s_addr != 0) {
670 		prefix.family = AF_INET;
671 		prefix.prefixlen = 32;
672 		prefix.u.prefix4 = dst4;
673 	} else {
674 		prefix.family = AF_INET6;
675 		prefix.prefixlen = 128;
676 		prefix.u.prefix6 = dst6;
677 	}
678 
679 	vrf = vrf_lookup_by_name(vrf_name ? vrf_name : VRF_DEFAULT_NAME);
680 	if (!vrf) {
681 		vty_out(vty, "The vrf NAME specified: %s does not exist\n",
682 			vrf_name ? vrf_name : VRF_DEFAULT_NAME);
683 		return CMD_WARNING;
684 	}
685 
686 	ifp = if_lookup_by_name_vrf(ifname, vrf);
687 	if (ifp == NULL) {
688 		vty_out(vty, "%% Can't find interface %s\n", ifname);
689 		return CMD_WARNING;
690 	}
691 
692 	sharp_zebra_send_arp(ifp, &prefix);
693 
694 	return CMD_SUCCESS;
695 }
696 
sharp_vty_init(void)697 void sharp_vty_init(void)
698 {
699 	install_element(ENABLE_NODE, &install_routes_data_dump_cmd);
700 	install_element(ENABLE_NODE, &install_routes_cmd);
701 	install_element(ENABLE_NODE, &remove_routes_cmd);
702 	install_element(ENABLE_NODE, &vrf_label_cmd);
703 	install_element(ENABLE_NODE, &sharp_nht_data_dump_cmd);
704 	install_element(ENABLE_NODE, &watch_nexthop_v6_cmd);
705 	install_element(ENABLE_NODE, &watch_nexthop_v4_cmd);
706 	install_element(ENABLE_NODE, &sharp_lsp_prefix_v4_cmd);
707 	install_element(ENABLE_NODE, &sharp_remove_lsp_prefix_v4_cmd);
708 	install_element(ENABLE_NODE, &logpump_cmd);
709 	install_element(ENABLE_NODE, &create_session_cmd);
710 	install_element(ENABLE_NODE, &remove_session_cmd);
711 	install_element(ENABLE_NODE, &send_opaque_cmd);
712 	install_element(ENABLE_NODE, &send_opaque_unicast_cmd);
713 	install_element(ENABLE_NODE, &send_opaque_reg_cmd);
714 	install_element(ENABLE_NODE, &neigh_discover_cmd);
715 
716 	install_element(ENABLE_NODE, &show_debugging_sharpd_cmd);
717 
718 	return;
719 }
720