I was searching for a way to easily determine what the network
interface capabilities were for each plumb'd network interface
today and came up with nothing...

So I've put together a small program that I hope others will also
find interesting/useful/helpful.

To compile (same for sparc/x86):

32bit:
gcc ifcapability.c -o ifcapability -lkvm -lelf

64bit:
gcc -m64 ifcapability.c -o ifcapability -lkvm -lelf

It should compile and work on both Solaris 10 and OpenSolaris,
with or without IP instances but the binary is tied to whatever
kernel you build it with.

Sample output:
# /tmp/ifcapability
lo0 inet
eri0 inet +HCKSUM(version=1 +partial +ipv4hdr)
e1000g0 inet +HCKSUM(version=1 +partial +ipv4hdr) +ZEROCOPY(version=1 flags=0x1) +POLL

# /tmp/ifcapability
lo0 inet
nge0 inet +HCKSUM(version=1 +full +ipv4hdr) +ZEROCOPY(version=1 flags=0x1) +POLL
nge0 inet6 +HCKSUM(version=1 +full +ipv4hdr) +ZEROCOPY(version=1 flags=0x1)

At some point in the future, I hope that similar functionality
(or more :-) :-) will find its way into dladm or similar but while
we are all waiting, this might help...

Oh, it won't work inside zones and will list interfaces assigned
exclusively to zones other than the global zone.

Cheers,
Darren

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */
#include <sys/types.h>
#include <sys/pattr.h>

#include <sys/proc.h>
#include <sys/procset.h>
#include <sys/zone.h>
#ifdef ZCF_NET_EXCL
# include <sys/netstack.h>
#endif
#include <stdlib.h>

#define _KERNEL
#include <inet/common.h>
#include <inet/led.h>
#include <inet/ip.h>
#undef _KERNEL
#ifdef ZCF_NET_EXCL
# include <inet/ip_stack.h>
#endif

#include <kvm.h>
#include <nlist.h>
#include <stdio.h>
#include <fcntl.h>


void printill(kvm_t *k, void *);
void printillheads(kvm_t *k, ill_g_head_t *head);
void printillcapability(kvm_t *k, ill_t *ill);
void printmdtcapab(kvm_t *k, ill_t *ill);
void printhcksumcapab(kvm_t *k, ill_t *ill);
void printlsocapab(kvm_t *k, ill_t *ill);
void printdlscapab(kvm_t *k, ill_t *ill);
void printzerocopycapab(kvm_t *k, ill_t *ill);

int
main(int argc, char *argv[])
{
	struct nlist names[] = {
		{ "ill_g_heads" },
		{ "netstack_head" },
		{ NULL }
	};
	kvm_t *k;

	k = kvm_open(NULL, NULL, NULL, O_RDONLY, argv[0]);
	if (k == NULL)
		exit(1);

	if (kvm_nlist(k, names) != 0) {
		fprintf(stderr, "kvm_nlist failed\n");
		exit(1);
	}

#ifndef ZCF_NET_EXCL
	if (names[0].n_value != 0) {
		printillheads(k, (ill_g_head_t *)names[0].n_value);
	}
#else
	if (names[1].n_value != 0) {
		netstack_t ns, *nsp;
		ip_stack_t ips, *ipsp;

		if (kvm_read(k, (uintptr_t)names[1].n_value, &nsp,
		    sizeof(nsp)) != sizeof(nsp)) {
			fprintf(stderr, "read error for netstack_head\n");
			exit(1);
		}

		while (nsp != NULL) {
			if (kvm_read(k, (uintptr_t)nsp, &ns, sizeof(ns)) !=
			    sizeof(ns)) {
				fprintf(stderr, "read error for netstack\n");
				break;
			}

			nsp = ns.netstack_next;
			ipsp = ns.netstack_ip;
			if (kvm_read(k, (uintptr_t)ipsp, &ips, sizeof(ips)) !=
			    sizeof(ips)) {
				fprintf(stderr, "read error for ipstack %p\n",
				    ipsp);
				break;
			}
			printillheads(k, ips.ips_ill_g_heads);
		}
	}
#endif

	kvm_close(k);

	return (0);
}


void
printillheads(kvm_t *k, ill_g_head_t *headp)
{
	ill_g_head_t head[MAX_G_HEADS];
	ill_if_t *iftp, ift;

	if (kvm_read(k, (uintptr_t)headp, &head, sizeof(head)) !=
	    sizeof(head)) {
		fprintf(stderr, "read error for ill_g_heads %p\n", headp);
		exit(1);
	}

	for (iftp = head[0].ill_g_list_head; iftp != (void *)headp; ) {
		if (kvm_read(k, (uintptr_t)iftp, &ift, sizeof(ift)) !=
		    sizeof(ift)) {
			fprintf(stderr, "read error for ill_if_t\n");
			continue;
		}

		printill(k, AVL_NODE2DATA(ift.illif_avl_by_ppa.avl_root,
		    ift.illif_avl_by_ppa.avl_offset));

		iftp = ift.illif_next;
	}

	for (iftp = head[1].ill_g_list_head; iftp != (void *)(headp + 1); ) {
		if (kvm_read(k, (uintptr_t)iftp, &ift, sizeof(ift)) !=
		    sizeof(ift)) {
			fprintf(stderr, "read error for ill_if_t\n");
			continue;
		}

		printill(k, AVL_NODE2DATA(ift.illif_avl_by_ppa.avl_root,
		    ift.illif_avl_by_ppa.avl_offset));

		iftp = ift.illif_next;
	}
}


void
printill(kvm_t *k, void *illp)
{
	char name[LIFNAMSIZ+1];
	ill_t ill;

	if (kvm_read(k, (uintptr_t)illp, &ill, sizeof(ill)) != sizeof(ill)) {
		fprintf(stderr, "read error for ill %p\n", illp);
		return;
	}

	if (ill.ill_name_length > LIFNAMSIZ)
		ill.ill_name_length = LIFNAMSIZ;

	if (kvm_read(k, (uintptr_t)ill.ill_name, name, ill.ill_name_length) !=
	    ill.ill_name_length) {
		fprintf(stderr, "read error for ill_name\n");
		return;
	}

	printf("%s inet", name);
	if (ill.ill_isv6)
		putchar('6');

	printillcapability(k, &ill);

	printf("\n");
}

void
printillcapability(kvm_t *k, ill_t *ill)
{
	if (ill->ill_capabilities & ILL_CAPAB_AH)
		printf(" +AH");

	if (ill->ill_capabilities & ILL_CAPAB_ESP)
		printf(" +ESP");

	if (ill->ill_capabilities & ILL_CAPAB_MDT) {
		printf(" +MDT");
		printmdtcapab(k, ill);
	}

	if (ill->ill_capabilities & ILL_CAPAB_HCKSUM) {
		printf(" +HCKSUM");
		printhcksumcapab(k, ill);
	}

	if (ill->ill_capabilities & ILL_CAPAB_ZEROCOPY) {
		printf(" +ZEROCOPY");
		printzerocopycapab(k, ill);
	}

	if (ill->ill_capabilities & ILL_CAPAB_POLL)
		printf(" +POLL");

	if (ill->ill_capabilities & ILL_CAPAB_SOFT_RING) {
		printf(" +SOFT_RING");
		printdlscapab(k, ill);
	}

#ifdef ILL_CAPAB_LSO
	if (ill->ill_capabilities & ILL_CAPAB_LSO) {
		printf(" +LSO");
		printlsocapab(k, ill);
	}
#endif
}


void
printmdtcapab(kvm_t *k, ill_t *ill)
{
	ill_mdt_capab_t mdt, *mdtp = ill->ill_mdt_capab;

	if (mdtp == NULL)
		return;

	if (kvm_read(k, (uintptr_t)mdtp, &mdt, sizeof(mdt)) != sizeof(mdt)) {
		fprintf(stderr, "read error for mdt\n");
		return;
	}

	printf("(version=%d %s maxpayload=%d maxspan=%d)",
	    mdt.ill_mdt_version, mdt.ill_mdt_on ? "on" : "off",
	    mdt.ill_mdt_max_pld, mdt.ill_mdt_span_limit);
}


void
printhcksumcapab(kvm_t *k, ill_t *ill)
{
	ill_hcksum_capab_t hck, *hckp = ill->ill_hcksum_capab;

	if (hckp == NULL)
		return;

	if (kvm_read(k, (uintptr_t)hckp, &hck, sizeof(hck)) != sizeof(hck)) {
		fprintf(stderr, "read error for hcksum\n");
		return;
	}

	printf("(version=%d", hck.ill_hcksum_version);
	if (hck.ill_hcksum_txflags != 0) {
		if (hck.ill_hcksum_txflags & HCK_FULLCKSUM)
			printf(" +full");
		if (hck.ill_hcksum_txflags & HCK_PARTIALCKSUM)
			printf(" +partial");
		if (hck.ill_hcksum_txflags & HCK_IPV4_HDRCKSUM)
			printf(" +ipv4hdr");
	}
	printf(")");
}


#ifdef ILL_CAPAB_LSO
void
printlsocapab(kvm_t *k, ill_t *ill)
{
	ill_lso_capab_t lso, *lsop = ill->ill_lso_capab;

	if (lsop == NULL)
		return;

	if (kvm_read(k, (uintptr_t)lsop, &lso, sizeof(lso)) != sizeof(lso)) {
		fprintf(stderr, "read error for lso\n");
		return;
	}

	printf("(version=%d %s maxpayload=%d",
	    lso.ill_lso_version, lso.ill_lso_on ? "on" : "off",
	    lso.ill_lso_max);
	if (lso.ill_lso_flags) {
		printf(" %#x", lso.ill_lso_flags);
	}
	printf(")");
}
#endif


void
printdlscapab(kvm_t *k, ill_t *ill)
{
	ill_dls_capab_t dls, *dlsp = ill->ill_dls_capab;

	if (dlsp == NULL)
		return;

	if (kvm_read(k, (uintptr_t)dlsp, &dls, sizeof(dls)) != sizeof(dls)) {
		fprintf(stderr, "read error for dls\n");
		return;
	}

	printf("(rings=%d status=%#x)",
	    dls.ill_dls_soft_ring_cnt, dls.ill_dls_change_status);
}


void
printzerocopycapab(kvm_t *k, ill_t *ill)
{
	ill_zerocopy_capab_t zero, *zerop = ill->ill_zerocopy_capab;

	if (zerop == NULL)
		return;

	if (kvm_read(k, (uintptr_t)zerop, &zero, sizeof(zero)) !=
	    sizeof(zero)) {
		fprintf(stderr, "read error for zerocopy\n");
		return;
	}

	printf("(version=%d flags=%#x)",
	    zero.ill_zerocopy_version, zero.ill_zerocopy_flags);
}
_______________________________________________
networking-discuss mailing list
[email protected]

Reply via email to