Commit Diff


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