mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-28 16:50:16 +01:00
cli: add command for displaying LLDP neighbors
The list of LLDP neighbors is available through the D-Bus interface and libnm already provides functions to retrieve it; make the list available through nmcli as well. Sample output: $ nmcli device lldp NEIGHBOR[0].DEVICE: eth0 NEIGHBOR[0].CHASSIS-ID: 00:13:21:58:CA:42 NEIGHBOR[0].PORT-ID: 1 NEIGHBOR[0].PORT-DESCRIPTION: 1 NEIGHBOR[0].SYSTEM-NAME: ProCurve Switch 2600-8-PWR NEIGHBOR[0].SYSTEM-DESCRIPTION: ProCurve J8762A Switch 2600-8-PWR, revision H.08.89 NEIGHBOR[0].SYSTEM-CAPABILITIES: 20 (mac-bridge,router) NEIGHBOR[1].DEVICE: eth2 NEIGHBOR[1].CHASSIS-ID: 00:01:30:F8:AD:A2 NEIGHBOR[1].PORT-ID: 1/1 NEIGHBOR[1].PORT-DESCRIPTION: Summit300-48-Port 1001 NEIGHBOR[1].SYSTEM-NAME: Summit300-48 NEIGHBOR[1].SYSTEM-DESCRIPTION: Summit300-48 - Version 7.4e.1 (Build 5) NEIGHBOR[1].SYSTEM-CAPABILITIES: 20 (mac-bridge,router) https://bugzilla.gnome.org/show_bug.cgi?id=757307
This commit is contained in:
parent
2b4b78eba1
commit
5b3137984d
5 changed files with 297 additions and 4 deletions
|
|
@ -1200,3 +1200,46 @@ nmc_rl_set_deftext (void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* nmc_parse_lldp_capabilities:
|
||||
* @value: the capabilities value
|
||||
*
|
||||
* Parses LLDP capabilities flags
|
||||
*
|
||||
* Returns: a newly allocated string containing capabilities names separated by commas.
|
||||
*/
|
||||
char *
|
||||
nmc_parse_lldp_capabilities (guint value)
|
||||
{
|
||||
/* IEEE Std 802.1AB-2009 - Table 8.4 */
|
||||
const char *names[] = { "other", "repeater", "mac-bridge", "wlan-access-point",
|
||||
"router", "telephone", "docsis-cable-device", "station-only",
|
||||
"c-vlan-component", "s-vlan-component", "tpmr" };
|
||||
gboolean first = TRUE;
|
||||
GString *str;
|
||||
int i;
|
||||
|
||||
if (!value)
|
||||
return g_strdup ("none");
|
||||
|
||||
str = g_string_new ("");
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (names); i++) {
|
||||
if (value & (1 << i)) {
|
||||
if (!first)
|
||||
g_string_append_c (str, ',');
|
||||
|
||||
first = FALSE;
|
||||
value &= ~(1 << i);
|
||||
g_string_append (str, names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (value) {
|
||||
if (!first)
|
||||
g_string_append_c (str, ',');
|
||||
g_string_append (str, "reserved");
|
||||
}
|
||||
|
||||
return g_string_free (str, FALSE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,4 +70,6 @@ void nmc_set_in_readline (gboolean in_readline);
|
|||
extern char *nmc_rl_pre_input_deftext;
|
||||
int nmc_rl_set_deftext (void);
|
||||
|
||||
char *nmc_parse_lldp_capabilities (guint value);
|
||||
|
||||
#endif /* NMC_COMMON_H */
|
||||
|
|
|
|||
|
|
@ -247,6 +247,31 @@ static NmcOutputField nmc_fields_dev_show_sections[] = {
|
|||
#define NMC_FIELDS_DEV_SHOW_SECTIONS_COMMON "GENERAL.DEVICE,GENERAL.TYPE,GENERAL.HWADDR,GENERAL.MTU,GENERAL.STATE,"\
|
||||
"GENERAL.CONNECTION,GENERAL.CON-PATH,WIRED-PROPERTIES,IP4,IP6"
|
||||
|
||||
/* Available fields for 'device lldp' */
|
||||
static NmcOutputField nmc_fields_dev_lldp_list[] = {
|
||||
{"NAME", N_("NAME")}, /* 0 */
|
||||
{"DEVICE", N_("DEVICE")}, /* 1 */
|
||||
{"CHASSIS-ID", N_("CHASSIS-ID")}, /* 2 */
|
||||
{"PORT-ID", N_("PORT-ID")}, /* 3 */
|
||||
{"PORT-DESCRIPTION", N_("PORT-DESCRIPTION")}, /* 4 */
|
||||
{"SYSTEM-NAME", N_("SYSTEM-NAME")}, /* 5 */
|
||||
{"SYSTEM-DESCRIPTION", N_("SYSTEM-DESCRIPTION")}, /* 6 */
|
||||
{"SYSTEM-CAPABILITIES", N_("SYSTEM-CAPABILITIES")}, /* 7 */
|
||||
{"IEEE-802-1-PVID", N_("IEEE-802-1-PVID")}, /* 8 */
|
||||
{"IEEE-802-1-PPVID", N_("IEEE-802-1-PPVID")}, /* 9 */
|
||||
{"IEEE-802-1-PPVID-FLAGS", N_("IEEE-802-1-PPVID-FLAGS")}, /* 10 */
|
||||
{"IEEE-802-1-VID", N_("IEEE-802-1-VID")}, /* 11 */
|
||||
{"IEEE-802-1-VLAN-NAME", N_("IEEE-802-1-VLAN-NAME")}, /* 12 */
|
||||
{"DESTINATION", N_("DESTINATION")}, /* 13 */
|
||||
{"CHASSIS-ID-TYPE", N_("CHASSIS-ID-TYPE")}, /* 14 */
|
||||
{"PORT-ID-TYPE", N_("PORT-ID-TYPE")}, /* 15 */
|
||||
{NULL, NULL}
|
||||
};
|
||||
#define NMC_FIELDS_DEV_LLDP_LIST_ALL "DEVICE,CHASSIS-ID,PORT-ID,PORT-DESCRIPTION,SYSTEM-NAME,SYSTEM-DESCRIPTION," \
|
||||
"SYSTEM-CAPABILITIES,IEEE-802-1-PVID,IEEE-802-1-PPVID,IEEE-802-1-PPVID-FLAGS," \
|
||||
"IEEE-802-1-VID,IEEE-802-1-VLAN-NAME,DESTINATION,CHASSIS-ID-TYPE,PORT-ID-TYPE"
|
||||
#define NMC_FIELDS_DEV_LLDP_LIST_COMMON "DEVICE,CHASSIS-ID,PORT-ID,PORT-DESCRIPTION,SYSTEM-NAME,SYSTEM-DESCRIPTION," \
|
||||
"SYSTEM-CAPABILITIES"
|
||||
|
||||
/* glib main loop variable - defined in nmcli.c */
|
||||
extern GMainLoop *loop;
|
||||
|
|
@ -257,7 +282,7 @@ static void
|
|||
usage (void)
|
||||
{
|
||||
g_printerr (_("Usage: nmcli device { COMMAND | help }\n\n"
|
||||
"COMMAND := { status | show | connect | disconnect | delete | wifi }\n\n"
|
||||
"COMMAND := { status | show | connect | disconnect | delete | wifi | lldp }\n\n"
|
||||
" status\n\n"
|
||||
" show [<ifname>]\n\n"
|
||||
" set [ifname] <ifname> [autoconnect yes|no] [managed yes|no]\n\n"
|
||||
|
|
@ -270,6 +295,7 @@ usage (void)
|
|||
" wifi hotspot [ifname <ifname>] [con-name <name>] [ssid <SSID>] [band a|bg] [channel <channel>]\n\n"
|
||||
" [password <password>] [--show-password]\n\n"
|
||||
" wifi rescan [ifname <ifname>] [[ssid <SSID to scan>] ...]\n\n"
|
||||
" lldp [list [ifname <ifname>]]\n\n"
|
||||
));
|
||||
}
|
||||
|
||||
|
|
@ -398,6 +424,17 @@ usage_device_wifi (void)
|
|||
"use 'nmcli device wifi list' for that.\n\n"));
|
||||
}
|
||||
|
||||
static void
|
||||
usage_device_lldp (void)
|
||||
{
|
||||
g_printerr (_("Usage: nmcli device lldp { ARGUMENTS | help }\n"
|
||||
"\n"
|
||||
"ARGUMENTS := [list [ifname <ifname>]]\n"
|
||||
"\n"
|
||||
"List neighboring devices discovered through LLDP. The 'ifname' option can be\n"
|
||||
"used to list neighbors for a particular interface.\n\n"));
|
||||
}
|
||||
|
||||
/* quit main loop */
|
||||
static void
|
||||
quit (void)
|
||||
|
|
@ -3171,6 +3208,187 @@ do_device_wifi (NmCli *nmc, int argc, char **argv)
|
|||
return nmc->return_value;
|
||||
}
|
||||
|
||||
static int
|
||||
show_device_lldp_list (NMDevice *device, NmCli *nmc, char *fields_str, int *counter)
|
||||
{
|
||||
NmcOutputField *tmpl, *arr;
|
||||
GPtrArray *neighbors;
|
||||
size_t tmpl_len;
|
||||
const char *str;
|
||||
int i;
|
||||
|
||||
neighbors = nm_device_get_lldp_neighbors (device);
|
||||
|
||||
if (!neighbors || !neighbors->len)
|
||||
return 0;
|
||||
|
||||
tmpl = nmc_fields_dev_lldp_list;
|
||||
tmpl_len = sizeof (nmc_fields_dev_lldp_list);
|
||||
|
||||
/* Main header name */
|
||||
nmc->print_fields.header_name = (char *) construct_header_name (_("Device LLDP neighbors"),
|
||||
nm_device_get_iface (device));
|
||||
nmc->print_fields.indices = parse_output_fields (fields_str, nmc_fields_dev_lldp_list, FALSE, NULL, NULL);
|
||||
arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES);
|
||||
g_ptr_array_add (nmc->output_data, arr);
|
||||
|
||||
for (i = 0; i < neighbors->len; i++) {
|
||||
NMLldpNeighbor *neighbor = neighbors->pdata[i];
|
||||
guint value;
|
||||
|
||||
arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
|
||||
set_val_str (arr, 0, g_strdup_printf ("NEIGHBOR[%d]", (*counter)++));
|
||||
|
||||
set_val_strc (arr, 1, nm_device_get_iface (device));
|
||||
|
||||
if (nm_lldp_neighbor_get_attr_string_value (neighbor, NM_LLDP_ATTR_CHASSIS_ID, &str))
|
||||
set_val_strc (arr, 2, str);
|
||||
|
||||
if (nm_lldp_neighbor_get_attr_string_value (neighbor, NM_LLDP_ATTR_PORT_ID, &str))
|
||||
set_val_strc (arr, 3, str);
|
||||
|
||||
if (nm_lldp_neighbor_get_attr_string_value (neighbor, NM_LLDP_ATTR_PORT_DESCRIPTION, &str))
|
||||
set_val_strc (arr, 4, str);
|
||||
|
||||
if (nm_lldp_neighbor_get_attr_string_value (neighbor, NM_LLDP_ATTR_SYSTEM_NAME, &str))
|
||||
set_val_strc (arr, 5, str);
|
||||
|
||||
if (nm_lldp_neighbor_get_attr_string_value (neighbor, NM_LLDP_ATTR_SYSTEM_DESCRIPTION, &str))
|
||||
set_val_strc (arr, 6, str);
|
||||
|
||||
if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_SYSTEM_CAPABILITIES, &value))
|
||||
set_val_str (arr, 7, g_strdup_printf ("%u (%s)", value, nmc_parse_lldp_capabilities (value)));
|
||||
|
||||
if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_IEEE_802_1_PVID, &value))
|
||||
set_val_str (arr, 8, g_strdup_printf ("%u", value));
|
||||
|
||||
if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_IEEE_802_1_PPVID, &value))
|
||||
set_val_str (arr, 9, g_strdup_printf ("%u", value));
|
||||
|
||||
if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_IEEE_802_1_PPVID_FLAGS, &value))
|
||||
set_val_str (arr, 10, g_strdup_printf ("%u", value));
|
||||
|
||||
if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_IEEE_802_1_VID, &value))
|
||||
set_val_str (arr, 11, g_strdup_printf ("%u", value));
|
||||
|
||||
if (nm_lldp_neighbor_get_attr_string_value (neighbor, NM_LLDP_ATTR_IEEE_802_1_VLAN_NAME, &str))
|
||||
set_val_strc (arr, 12, str);
|
||||
|
||||
if (nm_lldp_neighbor_get_attr_string_value (neighbor, NM_LLDP_ATTR_DESTINATION, &str))
|
||||
set_val_strc (arr, 13, str);
|
||||
|
||||
if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_CHASSIS_ID_TYPE, &value))
|
||||
set_val_strc (arr, 14, g_strdup_printf ("%u", value));
|
||||
|
||||
if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_PORT_ID_TYPE, &value))
|
||||
set_val_strc (arr, 15, g_strdup_printf ("%u", value));
|
||||
|
||||
g_ptr_array_add (nmc->output_data, arr);
|
||||
}
|
||||
|
||||
print_data (nmc);
|
||||
nmc_empty_output_fields (nmc);
|
||||
|
||||
return neighbors->len;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
do_device_lldp_list (NmCli *nmc, int argc, char **argv)
|
||||
{
|
||||
NMDevice *device = NULL, **devices = NULL;
|
||||
GError *error = NULL;
|
||||
const char *ifname = NULL;
|
||||
char *fields_str;
|
||||
int i, counter = 0;
|
||||
|
||||
while (argc > 0) {
|
||||
if (strcmp (*argv, "ifname") == 0) {
|
||||
if (next_arg (&argc, &argv) != 0) {
|
||||
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
goto error;
|
||||
}
|
||||
ifname = *argv;
|
||||
} else {
|
||||
g_string_printf (nmc->return_text, _("Error: unknown parameter: %s"), *argv);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (argc > 0) {
|
||||
g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
|
||||
fields_str = NMC_FIELDS_DEV_LLDP_LIST_COMMON;
|
||||
else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
|
||||
fields_str = NMC_FIELDS_DEV_LLDP_LIST_ALL;
|
||||
else
|
||||
fields_str = nmc->required_fields;
|
||||
|
||||
nmc->print_fields.indices = parse_output_fields (fields_str, nmc_fields_dev_lldp_list, FALSE, NULL, &error);
|
||||
|
||||
if (error) {
|
||||
g_string_printf (nmc->return_text, _("Error: 'device lldp list': %s"), error->message);
|
||||
g_error_free (error);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return nmc->return_value;
|
||||
}
|
||||
|
||||
devices = get_devices_sorted (nmc->client);
|
||||
|
||||
if (ifname) {
|
||||
for (i = 0; devices[i]; i++) {
|
||||
NMDevice *candidate = devices[i];
|
||||
const char *dev_iface = nm_device_get_iface (candidate);
|
||||
|
||||
if (!g_strcmp0 (dev_iface, ifname)) {
|
||||
device = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!device) {
|
||||
g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname);
|
||||
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
|
||||
goto error;
|
||||
}
|
||||
|
||||
nmc_empty_output_fields (nmc);
|
||||
show_device_lldp_list (device, nmc, fields_str, &counter);
|
||||
} else {
|
||||
for (i = 0; devices[i]; i++) {
|
||||
nmc_empty_output_fields (nmc);
|
||||
show_device_lldp_list (devices[i], nmc, fields_str, &counter);
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
g_free (devices);
|
||||
return nmc->return_value;
|
||||
}
|
||||
|
||||
static NMCResultCode
|
||||
do_device_lldp (NmCli *nmc, int argc, char **argv)
|
||||
{
|
||||
if (argc == 0)
|
||||
nmc->return_value = do_device_lldp_list (nmc, argc, argv);
|
||||
else if (matches (*argv, "list") == 0)
|
||||
nmc->return_value = do_device_lldp_list (nmc, argc-1, argv+1);
|
||||
else {
|
||||
g_string_printf (nmc->return_text, _("Error: 'device lldp' command '%s' is not valid."), *argv);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
}
|
||||
|
||||
return nmc->return_value;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_single_word (const char* line)
|
||||
{
|
||||
|
|
@ -3332,6 +3550,17 @@ do_devices (NmCli *nmc, int argc, char **argv)
|
|||
goto opt_error;
|
||||
nmc->return_value = do_device_wifi (nmc, argc-1, argv+1);
|
||||
}
|
||||
else if (matches (*argv, "lldp") == 0) {
|
||||
if (nmc_arg_is_help (*(argv+1))) {
|
||||
usage_device_lldp ();
|
||||
goto usage_exit;
|
||||
}
|
||||
if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
|
||||
goto opt_error;
|
||||
if (!nmc->mode_specified)
|
||||
nmc->multiline_output = TRUE; /* multiline mode is default for 'device lldp' */
|
||||
nmc->return_value = do_device_lldp (nmc, argc-1, argv+1);
|
||||
}
|
||||
else {
|
||||
usage ();
|
||||
g_string_printf (nmc->return_text, _("Error: 'dev' command '%s' is not valid."), *argv);
|
||||
|
|
|
|||
|
|
@ -1291,7 +1291,7 @@ _nmcli()
|
|||
;;
|
||||
d|de|dev|devi|devic|device)
|
||||
if [[ ${#words[@]} -eq 2 ]]; then
|
||||
_nmcli_compl_COMMAND "$command" status show connect disconnect delete wifi set
|
||||
_nmcli_compl_COMMAND "$command" status show connect disconnect delete wifi set lldp
|
||||
elif [[ ${#words[@]} -gt 2 ]]; then
|
||||
case "$command" in
|
||||
s|st|sta|stat|statu|status)
|
||||
|
|
@ -1359,7 +1359,19 @@ _nmcli()
|
|||
esac
|
||||
fi
|
||||
;;
|
||||
|
||||
l|ll|lld|lldp)
|
||||
if [[ ${#words[@]} -eq 3 ]]; then
|
||||
_nmcli_compl_COMMAND "${words[2]}" list
|
||||
else
|
||||
case "${words[2]}" in
|
||||
l|li|lis|list)
|
||||
_nmcli_array_delete_at words 0 2
|
||||
OPTIONS=(ifname)
|
||||
_nmcli_compl_ARGS
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
;;
|
||||
|
|
|
|||
|
|
@ -769,7 +769,7 @@ of its latest state.
|
|||
.B device - show and manage network interfaces
|
||||
.br
|
||||
.TP
|
||||
.SS \fICOMMAND\fP := { status | show | set | connect | disconnect | delete | wifi }
|
||||
.SS \fICOMMAND\fP := { status | show | set | connect | disconnect | delete | wifi | lldp }
|
||||
.sp
|
||||
.RS
|
||||
.TP
|
||||
|
|
@ -893,6 +893,13 @@ with hidden SSIDs. You can provide multiple \fIssid\fP parameters in order to
|
|||
scan more SSIDs.
|
||||
.br
|
||||
This command does not show the APs, use 'nmcli device wifi list' for that.
|
||||
.TP
|
||||
.B lldp [list [ifname <ifname>]]
|
||||
.br
|
||||
Display information about neighboring devices learned through the Link
|
||||
Layer Discovery Protocol (LLDP). The \fIifname\fP option can be used to
|
||||
list neighbors only for a given interface. The protocol must be
|
||||
enabled in the connection settings.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue