commit 1edb14c1c67f348a1056574a5a133747677b9f50 from: Stefan Sperling date: Wed Mar 08 12:38:04 2023 UTC add a "show vlan" command This command provides a high-level overview of VLANs configured on the system, similar to the cisco-style "show vlan" command. commit - 3e900a0e4ce20da82f78e6b5b2ab520729e3e62c commit + 1edb14c1c67f348a1056574a5a133747677b9f50 blob - b1d9c274def09e29eae01f867cb11514985521cc blob + 466ff2ef225f9867bc2af333a122be8e53db54c0 --- bridge.c +++ bridge.c @@ -901,7 +901,50 @@ bridge_list(int s, char *brdg, char *delim, char *br_s return (identified); } +/* + * Find a bridge, if any, which the given interface is a member of. + * Return the interface index of the bridge, or 0 if not found. + * A given interface can only be a member of one bridge at a time. + */ int +bridge_member_search(int ifs, char *ifname) +{ + struct if_nameindex *ifn_list, *ifnp; + int idx = 0; + char buf[1024]; + char *p, *s; + + if (!is_valid_ifname(ifname) || is_bridge(ifs, ifname)) { + printf("%% bridge_member_search: bad interface %s\n", ifname); + return 0; + } + + if ((ifn_list = if_nameindex()) == NULL) { + printf("%% bridge_member_search: if_nameindex failed\n"); + return 0; + } + + /* Search all bridges. */ + for (ifnp = ifn_list; ifnp->if_name != NULL; ifnp++) { + if (!is_bridge(ifs, ifnp->if_name)) + continue; + if (bridge_list(ifs, ifnp->if_name, NULL, buf, sizeof(buf), + MEMBER) == 0) + continue; + p = buf; + while ((s = strsep(&p, " ")) != NULL) { + if (strcmp(s, ifname) == 0) { + idx = ifnp->if_index; + goto found; + } + } + } +found: + if_freenameindex(ifn_list); + return idx; +} + +int bridge_add(int s, char *brdg, char *ifn) { struct ifbreq req; blob - 9de8d9a66405e5604734ee27af9681d8f639a925 blob + f1bf08371228e7adba03257740a3c587c0f3d35b --- commands.c +++ commands.c @@ -167,6 +167,7 @@ Menu showlist[] = { { "sadb", "Security Association Database", CMPL0 0, 0, 0, 0, pr_sadb }, { "arp", "ARP table", CMPL0 0, 0, 0, 1, pr_arp }, { "ndp", "NDP table", CMPL0 0, 0, 0, 1, pr_ndp }, + { "vlan", "802.1Q/802.1ad VLANs", CMPL0 0, 0, 0, 1, show_vlans }, { "kernel", "Kernel statistics", CMPL(ta) (char **)stts, sizeof(struct stt), 0, 1, pr_kernel }, { "bgp", "BGP information", CMPL(ta) (char **)bgcs, sizeof(struct prot1), 0, 4, pr_prot1 }, { "ospf", "OSPF information", CMPL(ta) (char **)oscs, sizeof(struct prot1), 0, 3, pr_prot1 }, blob - 0bf82578b4be5faafabd5a26c5369e900453f07d blob + ee19c6a2191be0ed569d12fdb514e512a8fbda74 --- externs.h +++ externs.h @@ -385,6 +385,7 @@ int parse_ipv6(char *, struct in6_addr *); void imr_init(char *); int is_valid_ifname(char *); int show_int(int, char **); +int show_vlans(int, char **); int show_autoconf(int, char **); int get_rdomain(int, char *); int get_ifdata(char *, int); @@ -438,6 +439,7 @@ long bridge_cfg(int, char *, int); int bridge_confaddrs(int, char *, char *, FILE *); int bridge_rules(int, char *, char *, char *, FILE *); int bridge_list(int, char *, char *, char *, int, int); +int bridge_member_search(int, char *); int bridge_addrs(int, char *, char *, char *); int set_ifflag(int, char *, short); int clr_ifflag(int, char *, short); blob - ff37c8bb238a7c157908dcaf8a18acf7bd72bfc7 blob + 033de835920959e576e9e82209adc8f2086beb02 --- if.c +++ if.c @@ -60,6 +60,7 @@ void ipv6ll_db_store(struct sockaddr_in6 *, struct soc void printifhwfeatures(int, char *); void show_vnet_parent(int, char *); void pwe3usage(void); +int show_vlan(int); static struct ifmpwreq imrsave; static char imrif[IFNAMSIZ]; @@ -2551,4 +2552,137 @@ intvnetflowid(char *ifname, int ifs, int argc, char ** printf("%% intvnetflowid: SIOCSVNETFLOWID: %s\n", strerror(errno)); return(0); +} + +int +show_vlan(int wanted_vnetid) +{ + struct if_nameindex *ifn_list, *ifnp; + struct ifreq ifr; + struct if_parent ifp; + int ifs, vnetid, flags, bridx; + const char *parent, *description, *bridgename; + char ifdescr[IFDESCRSIZE]; + char vnetid_str[5]; + int found_vnetid = 0, header_shown = 0; + char ifix_buf[IFNAMSIZ]; + + if ((ifs = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + printf("%% show_vlan: %s\n", strerror(errno)); + return 0; + } + + if ((ifn_list = if_nameindex()) == NULL) { + printf("%% show_vlan: if_nameindex failed\n"); + close(ifs); + return 0; + } + + for (ifnp = ifn_list; ifnp->if_name != NULL; ifnp++) { + if (!isprefix("vlan", ifnp->if_name) && + !isprefix("svlan", ifnp->if_name)) + continue; + + memset(&ifr, 0, sizeof(ifr)); + if (strlcpy(ifr.ifr_name, ifnp->if_name, + sizeof(ifr.ifr_name)) >= sizeof(ifr.ifr_name)) { + printf("%% %s: interface name is too long\n", + ifnp->if_name); + continue; + } + + vnetid = -1; + if (ioctl(ifs, SIOCGVNETID, &ifr) == -1) { + if (errno != EADDRNOTAVAIL) { + printf("%% %s: SIOCGVNETID: %s\n", + ifnp->if_name, strerror(errno)); + continue; + } + } else if (ifr.ifr_vnetid >= 0) + vnetid = ifr.ifr_vnetid; + + if (wanted_vnetid != -1) { + if (vnetid != wanted_vnetid) + continue; + found_vnetid = 1; + } + + if (!header_shown) { + puts("% Interface Tag Status Type " + "Parent Bridge Description"); + header_shown = 1; + } + + memset(&ifp, 0, sizeof(ifp)); + if (strlcpy(ifp.ifp_name, ifnp->if_name, + sizeof(ifp.ifp_name)) >= sizeof(ifp.ifp_name)) { + printf("%% %s: interface name is too long\n", + ifnp->if_name); + continue; + } + parent = "-"; + if (ioctl(ifs, SIOCGIFPARENT, &ifp) == -1) { + if (errno != EADDRNOTAVAIL) { + printf("%% %s: SIOCGIFPARENT: %s\n", + ifnp->if_name, strerror(errno)); + continue; + } + } else + parent = ifp.ifp_parent; + + flags = get_ifflags(ifnp->if_name, ifs); + + memset(ifdescr, 0, sizeof(ifdescr)); + ifr.ifr_data = (caddr_t)&ifdescr; + if (ioctl(ifs, SIOCGIFDESCR, &ifr) == 0) + description = ifr.ifr_data; + else + description = ""; + + if (vnetid == -1) + strlcpy(vnetid_str, "-", sizeof(vnetid_str)); + else + snprintf(vnetid_str, sizeof(vnetid_str), "%d", vnetid); + + bridx = bridge_member_search(ifs, ifnp->if_name); + if (bridx) + bridgename = if_indextoname(bridx, ifix_buf); + else + bridgename = "-"; + + printf(" %-10s %-5s %-7s %-8s %-7s %-8s %s\n", ifnp->if_name, + vnetid_str, (flags & IFF_UP) ? "up" : "down", + isprefix("vlan", ifnp->if_name) ? "802.1Q" : "802.1ad", + parent, bridgename, description); + } + + if (wanted_vnetid != -1 && !found_vnetid) + printf("%% no VLAN with tag %d configured\n", wanted_vnetid); + + if_freenameindex(ifn_list); + close(ifs); + return 0; } + +int +show_vlans(int argc, char **argv) +{ + long long vnetid = -1; + const char *errstr; + + switch (argc) { + case 2: + show_vlan(-1); + break; + case 3: + vnetid = strtonum(argv[2], EVL_VLID_NULL, + EVL_VLID_MAX, &errstr); + if (errstr) { + printf("%% VLAN tag %s is %s\n", argv[2], errstr); + break; + } + show_vlan(vnetid); + break; + } + return 0; +} blob - 5f9794d6b92a5e5ef101c1b2fc72a8e8fdb75b2d blob + dfdab5d2d531b2a4f4f76dde6b9e16bcb1d70484 --- nsh.8 +++ nsh.8 @@ -1471,7 +1471,7 @@ nsh/no verbose .El .Tg show .Ic show -.Op hostname | interface | route | route6 | sadb | arp | ndp | kernel | bgp | ospf\ +.Op hostname | interface | route | route6 | sadb | arp | ndp | vlan | kernel | bgp | ospf\ | ospf6 |eigrp | rip | ldp | ike | ipsec | dvmrp | relay | dhcp | smtp\ | ldap | monitor | version | users | running-config | startup-config |\&? | help .Pp @@ -1492,6 +1492,7 @@ nsh(p)/show sadb Security Association Database arp ARP table ndp NDP table + vlan 802.1Q/802.1ad VLANs kernel Kernel statistics bgp BGP information ospf OSPF information