xref: /plan9/sys/src/cmd/ip/measure.c (revision 274d35ba18649000b37dd5ce33abed48883c9b02)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <ip.h>
57dd7cddfSDavid du Colombier 
67dd7cddfSDavid du Colombier /*
77dd7cddfSDavid du Colombier  *  ether packet
87dd7cddfSDavid du Colombier  */
97dd7cddfSDavid du Colombier typedef struct Etherpkt	Etherpkt;
107dd7cddfSDavid du Colombier struct Etherpkt {
117dd7cddfSDavid du Colombier 	uchar d[6];
127dd7cddfSDavid du Colombier 	uchar s[6];
137dd7cddfSDavid du Colombier 	uchar type[2];
147dd7cddfSDavid du Colombier 	char data[1500];
157dd7cddfSDavid du Colombier };
167dd7cddfSDavid du Colombier #define	ETHERMINTU	60	/* minimum transmit size */
177dd7cddfSDavid du Colombier #define	ETHERMAXTU	1514	/* maximum transmit size */
187dd7cddfSDavid du Colombier #define ETHERHDRSIZE	14	/* size of an ethernet header */
197dd7cddfSDavid du Colombier 
207dd7cddfSDavid du Colombier /*
217dd7cddfSDavid du Colombier  *  ip packets
227dd7cddfSDavid du Colombier  */
237dd7cddfSDavid du Colombier typedef struct Ippkt	Ippkt;
247dd7cddfSDavid du Colombier struct Ippkt
257dd7cddfSDavid du Colombier {
267dd7cddfSDavid du Colombier 	uchar	vihl;		/* Version and header length */
277dd7cddfSDavid du Colombier 	uchar	tos;		/* Type of service */
287dd7cddfSDavid du Colombier 	uchar	length[2];	/* packet length */
297dd7cddfSDavid du Colombier 	uchar	id[2];		/* Identification */
307dd7cddfSDavid du Colombier 	uchar	frag[2];	/* Fragment information */
317dd7cddfSDavid du Colombier 	uchar	ttl;		/* Time to live */
327dd7cddfSDavid du Colombier 	uchar	proto;		/* Protocol */
337dd7cddfSDavid du Colombier 	uchar	cksum[2];	/* Header checksum */
347dd7cddfSDavid du Colombier 	uchar	src[4];		/* Ip source */
357dd7cddfSDavid du Colombier 	uchar	dst[4];		/* Ip destination */
367dd7cddfSDavid du Colombier 	char	data[1];
377dd7cddfSDavid du Colombier };
387dd7cddfSDavid du Colombier 
397dd7cddfSDavid du Colombier #define IP_HDRSIZE	20
407dd7cddfSDavid du Colombier #define IP_UDPPROTO	17
417dd7cddfSDavid du Colombier #define IP_MBONEPROTO	4
427dd7cddfSDavid du Colombier #define IP_TCPPROTO	6
437dd7cddfSDavid du Colombier #define	IP_ILPROTO	40
447dd7cddfSDavid du Colombier #define	IP_ICMPPROTO	1
457dd7cddfSDavid du Colombier #define	IP_DF		0x4000
467dd7cddfSDavid du Colombier #define	IP_MF		0x2000
477dd7cddfSDavid du Colombier 
487dd7cddfSDavid du Colombier #define NetS(x) (((x)[0]<<8) | (x)[1])
497dd7cddfSDavid du Colombier #define NetL(x) (((x)[0]<<24) | ((x)[1]<<16) | ((x)[2]<<8) | (x)[3])
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier /*
527dd7cddfSDavid du Colombier  *  run flags
537dd7cddfSDavid du Colombier  */
547dd7cddfSDavid du Colombier int	debug;
557dd7cddfSDavid du Colombier int	mbone;
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier ulong protoin[256];
587dd7cddfSDavid du Colombier ulong protoout[256];
597dd7cddfSDavid du Colombier ulong protopin[256];
607dd7cddfSDavid du Colombier ulong protopout[256];
617dd7cddfSDavid du Colombier 
627dd7cddfSDavid du Colombier void
error(char * s)637dd7cddfSDavid du Colombier error(char *s)
647dd7cddfSDavid du Colombier {
65*274d35baSDavid du Colombier 	char buf[ERRMAX];
667dd7cddfSDavid du Colombier 
67*274d35baSDavid du Colombier 	errstr(buf, sizeof buf);
687dd7cddfSDavid du Colombier 	fprint(2, "snoopy: %s %s\n", buf, s);
697dd7cddfSDavid du Colombier 	exits("death");
707dd7cddfSDavid du Colombier }
717dd7cddfSDavid du Colombier 
727dd7cddfSDavid du Colombier void
warning(char * s)737dd7cddfSDavid du Colombier warning(char *s)
747dd7cddfSDavid du Colombier {
75*274d35baSDavid du Colombier 	char buf[ERRMAX];
767dd7cddfSDavid du Colombier 
77*274d35baSDavid du Colombier 	errstr(buf, sizeof buf);
787dd7cddfSDavid du Colombier 	fprint(2, "snoopy: %s %s\n", buf, s);
797dd7cddfSDavid du Colombier }
807dd7cddfSDavid du Colombier 
817dd7cddfSDavid du Colombier void
printproto(int p)827dd7cddfSDavid du Colombier printproto(int p)
837dd7cddfSDavid du Colombier {
84*274d35baSDavid du Colombier 	print("\t%d(%ld %ld %ld %ld)", p, protoin[p], protopin[p], protoout[p], protopout[p]);
857dd7cddfSDavid du Colombier }
867dd7cddfSDavid du Colombier 
877dd7cddfSDavid du Colombier void
main(int argc,char * argv[])887dd7cddfSDavid du Colombier main(int argc, char *argv[])
897dd7cddfSDavid du Colombier {
907dd7cddfSDavid du Colombier 	Etherpkt e;
917dd7cddfSDavid du Colombier 	Ippkt *ip;
927dd7cddfSDavid du Colombier 	long n;
937dd7cddfSDavid du Colombier 	int fd, cfd;
947dd7cddfSDavid du Colombier 	int ts, len, t;
957dd7cddfSDavid du Colombier 	long start;
967dd7cddfSDavid du Colombier 	int delta;
977dd7cddfSDavid du Colombier 	uchar target[6];
987dd7cddfSDavid du Colombier 	char buf[256];
997dd7cddfSDavid du Colombier 	ulong samples;
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier 	samples = -1;
1027dd7cddfSDavid du Colombier 	ARGBEGIN{
1037dd7cddfSDavid du Colombier 	case 'd':
1047dd7cddfSDavid du Colombier 		debug++;
1057dd7cddfSDavid du Colombier 		break;
1067dd7cddfSDavid du Colombier 	case 's':
1077dd7cddfSDavid du Colombier 		samples = atoi(ARGF());
1087dd7cddfSDavid du Colombier 		break;
1097dd7cddfSDavid du Colombier 	}ARGEND;
1107dd7cddfSDavid du Colombier 
1117dd7cddfSDavid du Colombier 	if(argc < 2){
1127dd7cddfSDavid du Colombier 		fprint(2, "usage: %s device ip-addr [minutes-per-sample]\n", argv0);
1137dd7cddfSDavid du Colombier 		exits("usage");
1147dd7cddfSDavid du Colombier 	}
1157dd7cddfSDavid du Colombier 	if(argc > 2)
1167dd7cddfSDavid du Colombier 		delta = atoi(argv[2])*60*1000;
1177dd7cddfSDavid du Colombier 	else
1187dd7cddfSDavid du Colombier 		delta = 5*60*1000;
1197dd7cddfSDavid du Colombier 	parseether(target, argv[1]);
1207dd7cddfSDavid du Colombier 
121*274d35baSDavid du Colombier 	fmtinstall('E', eipfmt);
122*274d35baSDavid du Colombier 	fmtinstall('I', eipfmt);
1237dd7cddfSDavid du Colombier 
1247dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "%s!-2", argv[0]);
1257dd7cddfSDavid du Colombier 	fd = dial(buf, 0, 0, &cfd);
1267dd7cddfSDavid du Colombier 	if(fd < 0)
1277dd7cddfSDavid du Colombier 		error("opening ether data");
1287dd7cddfSDavid du Colombier 	if(write(cfd, "promiscuous", sizeof("promiscuous")-1) <= 0)
1297dd7cddfSDavid du Colombier 		error("connecting");
1307dd7cddfSDavid du Colombier 
1317dd7cddfSDavid du Colombier 	start = 0;
1327dd7cddfSDavid du Colombier 	fd = -1;
1337dd7cddfSDavid du Colombier 
1347dd7cddfSDavid du Colombier 	for(;;){
1357dd7cddfSDavid du Colombier 		if(fd < 0){
1367dd7cddfSDavid du Colombier 			fd = dial(buf, 0, 0, &cfd);
1377dd7cddfSDavid du Colombier 			if(fd < 0)
1387dd7cddfSDavid du Colombier 				error("opening ether data");
1397dd7cddfSDavid du Colombier 			if(write(cfd, "promiscuous", sizeof("promiscuous")-1) <= 0)
1407dd7cddfSDavid du Colombier 				error("connecting");
1417dd7cddfSDavid du Colombier 			close(cfd);
1427dd7cddfSDavid du Colombier 		}
1437dd7cddfSDavid du Colombier 		n = read(fd, &e, sizeof(e));
1447dd7cddfSDavid du Colombier 		if(n <= 0)
1457dd7cddfSDavid du Colombier 			break;
1467dd7cddfSDavid du Colombier 		ts = NetL(&e.d[60]);
1477dd7cddfSDavid du Colombier 		n = NetS(&e.d[58]) - ETHERHDRSIZE;
1487dd7cddfSDavid du Colombier 		if(n < 0)
1497dd7cddfSDavid du Colombier 			continue;
1507dd7cddfSDavid du Colombier 		if(start == 0)
1517dd7cddfSDavid du Colombier 			start = ts;
1527dd7cddfSDavid du Colombier 		t = NetS(e.type);
1537dd7cddfSDavid du Colombier 		if(t == 0x0800 || (t&0xFF00) == 0x1000){
1547dd7cddfSDavid du Colombier 			ip = (Ippkt*)e.data;
1557dd7cddfSDavid du Colombier 			len = NetS(ip->length);
1567dd7cddfSDavid du Colombier 			if(len > n)
1577dd7cddfSDavid du Colombier 				len = n;
1587dd7cddfSDavid du Colombier 			if(debug)
1597dd7cddfSDavid du Colombier 				fprint(2, "%I -> %I %d\n", ip->src, ip->dst, len);
1607dd7cddfSDavid du Colombier 			if(memcmp(e.s, target, 6) == 0){
1617dd7cddfSDavid du Colombier 				protopin[0]++;
1627dd7cddfSDavid du Colombier 				protoin[0] += len;
1637dd7cddfSDavid du Colombier 				if(ip->proto){
1647dd7cddfSDavid du Colombier 					protopin[ip->proto]++;
1657dd7cddfSDavid du Colombier 					protoin[ip->proto] += len;
1667dd7cddfSDavid du Colombier 				}
1677dd7cddfSDavid du Colombier 			}
1687dd7cddfSDavid du Colombier 			if(memcmp(e.d, target, 6) == 0){
1697dd7cddfSDavid du Colombier 				protopout[0]++;
1707dd7cddfSDavid du Colombier 				protoout[0] += len;
1717dd7cddfSDavid du Colombier 				if(ip->proto){
1727dd7cddfSDavid du Colombier 					protopout[ip->proto]++;
1737dd7cddfSDavid du Colombier 					protoout[ip->proto] += len;
1747dd7cddfSDavid du Colombier 				}
1757dd7cddfSDavid du Colombier 			}
1767dd7cddfSDavid du Colombier 		}
1777dd7cddfSDavid du Colombier 		if(ts - start >= delta){
178*274d35baSDavid du Colombier 			print("%8.8ld %ld", time(0), ts - start);
1797dd7cddfSDavid du Colombier 			printproto(0);
1807dd7cddfSDavid du Colombier 			printproto(IP_MBONEPROTO);
1817dd7cddfSDavid du Colombier 			printproto(IP_UDPPROTO);
1827dd7cddfSDavid du Colombier 			printproto(IP_TCPPROTO);
1837dd7cddfSDavid du Colombier 			print("\n");
1847dd7cddfSDavid du Colombier 			start = 0;
1857dd7cddfSDavid du Colombier 			memset(protoin, 0, sizeof(protoin));
1867dd7cddfSDavid du Colombier 			memset(protoout, 0, sizeof(protoout));
1877dd7cddfSDavid du Colombier 			memset(protopin, 0, sizeof(protopin));
1887dd7cddfSDavid du Colombier 			memset(protopout, 0, sizeof(protopout));
1897dd7cddfSDavid du Colombier 			close(fd);
1907dd7cddfSDavid du Colombier 			fd = -1;
1917dd7cddfSDavid du Colombier 			if(--samples == 0)
1927dd7cddfSDavid du Colombier 				break;
1937dd7cddfSDavid du Colombier 		}
1947dd7cddfSDavid du Colombier 	}
1957dd7cddfSDavid du Colombier 	exits(0);
1967dd7cddfSDavid du Colombier }
197