1 /* Copyright (C) 2007 Henry Zhang
2    This file is part of LibGTop 2.20.
3 
4    Contributed by Henry Zhang <hua.zhang@sun.com>, October 2007.
5 
6    LibGTop is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License,
9    or (at your option) any later version.
10 
11    LibGTop is distributed in the hope that it will be useful, but WITHOUT
12    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14    for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with LibGTop; see the file COPYING. If not, write to the
18    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19    Boston, MA 02110-1301, USA.
20 */
21 
22 #include <config.h>
23 #include <glibtop.h>
24 #include <glibtop/error.h>
25 #include <glibtop/netload.h>
26 
27 #include "glibtop_private.h"
28 
29 #include <errno.h>
30 #include <string.h>
31 #include <kstat.h>
32 
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/ioctl.h>
36 #include <sys/sockio.h>
37 
38 #include <net/if.h>
39 
40 
41 static const unsigned long _glibtop_sysdeps_netload =
42 (1L << GLIBTOP_NETLOAD_ERRORS_IN) +
43 (1L << GLIBTOP_NETLOAD_ERRORS_OUT) +
44 (1L << GLIBTOP_NETLOAD_COLLISIONS);
45 
46 static const unsigned long _glibtop_sysdeps_netload_data =
47 (1L << GLIBTOP_NETLOAD_ADDRESS) +
48 (1L << GLIBTOP_NETLOAD_SUBNET) +
49 (1L << GLIBTOP_NETLOAD_MTU);
50 
51 static const unsigned long _glibtop_sysdeps_netload_bytes =
52 (1L << GLIBTOP_NETLOAD_BYTES_IN) +
53 (1L << GLIBTOP_NETLOAD_BYTES_OUT) +
54 (1L << GLIBTOP_NETLOAD_BYTES_TOTAL);
55 
56 static const unsigned long _glibtop_sysdeps_netload_packets =
57 (1L << GLIBTOP_NETLOAD_PACKETS_IN) +
58 (1L << GLIBTOP_NETLOAD_PACKETS_OUT) +
59 (1L << GLIBTOP_NETLOAD_PACKETS_TOTAL);
60 
61 static const unsigned long _glibtop_sysdeps_netload_total =
62 (1L << GLIBTOP_NETLOAD_PACKETS_TOTAL) +
63 (1L << GLIBTOP_NETLOAD_BYTES_TOTAL);
64 
65 static const unsigned long _glibtop_sysdeps_netload_in =
66 (1L << GLIBTOP_NETLOAD_PACKETS_TOTAL) +
67 (1L << GLIBTOP_NETLOAD_BYTES_TOTAL) +
68 (1L << GLIBTOP_NETLOAD_PACKETS_IN) +
69 (1L << GLIBTOP_NETLOAD_BYTES_IN);
70 
71 static const unsigned long _glibtop_sysdeps_netload_out =
72 (1L << GLIBTOP_NETLOAD_PACKETS_TOTAL) +
73 (1L << GLIBTOP_NETLOAD_BYTES_TOTAL) +
74 (1L << GLIBTOP_NETLOAD_PACKETS_OUT) +
75 (1L << GLIBTOP_NETLOAD_BYTES_OUT);
76 
77 static const unsigned long _glibtop_sysdeps_netload_6 =
78 (1L << GLIBTOP_NETLOAD_ADDRESS6) +
79 (1L << GLIBTOP_NETLOAD_PREFIX6) +
80 (1L << GLIBTOP_NETLOAD_SCOPE6);
81 
82 /* Init function. */
83 
84 void
_glibtop_init_netload_s(glibtop * server)85 _glibtop_init_netload_s (glibtop *server)
86 {
87         server->sysdeps.netload = _glibtop_sysdeps_netload |
88 	_glibtop_sysdeps_netload_bytes |
89 	_glibtop_sysdeps_netload_packets;
90 }
91 
92 static int
solaris_stats(glibtop * server,glibtop_netload * buf,const char * interface)93 solaris_stats(glibtop *server,
94 		glibtop_netload *buf,
95 		const char *interface)
96 {
97 	char	*name = interface;
98 	char	*module;
99 	char	*ptr;
100     	kstat_ctl_t * const kctl = server->machine->kc;
101 	kstat_t			*ksp;
102 	kstat_named_t		*kdata;
103 	int have_bytes = 1;
104 
105 	/*
106 	 *  chop off the trailing interface
107 	 */
108 	module = strdup( name );
109 	ptr = module + strlen( module ) - 1;
110 	while( (ptr > module) && isdigit( (int) *ptr ) ) {
111 		*ptr = '\0';
112 		ptr--;
113 	}
114 
115 	/*
116 	 *  get a kstat handle and update the user's kstat chain
117 	 */
118 	if( kctl == NULL ){
119 		glibtop_warn_io_r (server, "kstat_open ()");
120 		free( module );
121 		return( 0 );
122 	}
123 	while( kstat_chain_update( kctl ) != 0 )
124 		;
125 
126 	/*
127 	 *  traverse the kstat chain
128 	 *  to find the appropriate statistics
129 	 */
130 	if( (ksp = kstat_lookup( kctl,
131 			module, 0, name )) == NULL ) {
132 		free( module );
133 		return( 0 );
134 	}
135 	if( kstat_read( kctl, ksp, NULL ) == -1 ) {
136 		free( module );
137 		return( 0 );
138 	}
139 	free( module );
140 
141 	/*
142 	 *  lookup & store the data
143 	 */
144 	kdata = (kstat_named_t *) kstat_data_lookup( ksp, "ipackets" );
145 	if( kdata != NULL ) {
146 		buf->packets_in= kdata->value.ul;
147 	}
148 	kdata = (kstat_named_t *) kstat_data_lookup( ksp, "opackets" );
149 	if( kdata != NULL ) {
150 		buf->packets_out = kdata->value.ul;
151 	}
152 	kdata = (kstat_named_t *) kstat_data_lookup( ksp, "rbytes" );
153 	if( kdata != NULL ) {
154 		buf->bytes_in =kdata->value.ul;
155 	}
156 	kdata = (kstat_named_t *) kstat_data_lookup( ksp, "obytes" );
157 	if( kdata != NULL ) {
158 		buf->bytes_out =kdata->value.ul;
159 	}
160 	kdata = (kstat_named_t *) kstat_data_lookup( ksp, "ierrors" );
161 	if( kdata != NULL ) {
162 		buf->errors_in = kdata->value.ul;
163 	}
164 	kdata = (kstat_named_t *) kstat_data_lookup( ksp, "oerrors" );
165 	if( kdata != NULL ) {
166 		buf->errors_out = kdata->value.ul;
167 	}
168 	kdata = (kstat_named_t *) kstat_data_lookup( ksp, "collisions" );
169 	if( kdata != NULL ) {
170 		buf->collisions = kdata->value.ul;
171 	}
172 
173 	/* Compute total valules. */
174 
175 	buf->bytes_total = buf->bytes_in + buf->bytes_out;
176 	buf->packets_total = buf->packets_in + buf->packets_out;
177 	buf->errors_total = buf->errors_in + buf->errors_out;
178 	/* And now the flags. */
179 	buf->flags |= _glibtop_sysdeps_netload;
180 	buf->flags |= _glibtop_sysdeps_netload_bytes;
181 	buf->flags |= _glibtop_sysdeps_netload_packets;
182 
183 	/* finished */
184 }
185 
186 /* Provides network statistics. */
187 
188 void
glibtop_get_netload_s(glibtop * server,glibtop_netload * buf,const char * interface)189 glibtop_get_netload_s (glibtop *server, glibtop_netload *buf,
190 		       const char *interface)
191 {
192    int skfd;
193     memset (buf, 0, sizeof (glibtop_netload));
194 
195     /* set flag */
196     skfd = socket (PF_INET, SOCK_DGRAM, 0);
197     if (skfd) {
198 	struct ifreq ifr;
199 
200 	g_strlcpy (ifr.ifr_name, interface, sizeof ifr.ifr_name);
201 	if (ioctl (skfd, SIOCGIFFLAGS, &ifr) >= 0) {
202 	    const unsigned long long flags = ifr.ifr_flags;
203 
204 	    buf->flags |= (1L << GLIBTOP_NETLOAD_IF_FLAGS);
205 
206 	    if (flags & IFF_UP)
207 		buf->if_flags |= (1L << GLIBTOP_IF_FLAGS_UP);
208 
209 	    if (flags & IFF_BROADCAST)
210 		buf->if_flags |= (1L << GLIBTOP_IF_FLAGS_BROADCAST);
211 
212 	    if (flags & IFF_DEBUG)
213 		buf->if_flags |= (1L << GLIBTOP_IF_FLAGS_DEBUG);
214 
215 	    if (flags & IFF_LOOPBACK)
216 		buf->if_flags |= (1L << GLIBTOP_IF_FLAGS_LOOPBACK);
217 
218 	    if (flags & IFF_POINTOPOINT)
219 		buf->if_flags |= (1L << GLIBTOP_IF_FLAGS_POINTOPOINT);
220 
221 	    if (flags & IFF_RUNNING)
222 		buf->if_flags |= (1L << GLIBTOP_IF_FLAGS_RUNNING);
223 
224 	    if (flags & IFF_NOARP)
225 		buf->if_flags |= (1L << GLIBTOP_IF_FLAGS_NOARP);
226 
227 	    if (flags & IFF_PROMISC)
228 		buf->if_flags |= (1L << GLIBTOP_IF_FLAGS_PROMISC);
229 
230 	    if (flags & IFF_ALLMULTI)
231 		buf->if_flags |= (1L << GLIBTOP_IF_FLAGS_ALLMULTI);
232 
233 	    if (flags & IFF_MULTICAST)
234 		buf->if_flags |= (1L << GLIBTOP_IF_FLAGS_MULTICAST);
235 	    }
236 
237 	g_strlcpy (ifr.ifr_name, interface, sizeof ifr.ifr_name);
238 	if (!ioctl (skfd, SIOCGIFADDR, &ifr)) {
239 	    buf->address = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr;
240 	    buf->flags |= (1L << GLIBTOP_NETLOAD_ADDRESS);
241 	}
242 
243 	g_strlcpy (ifr.ifr_name, interface, sizeof ifr.ifr_name);
244 	if (!ioctl (skfd, SIOCGIFNETMASK, &ifr)) {
245 	    buf->subnet = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr;
246 	    buf->flags |= (1L << GLIBTOP_NETLOAD_SUBNET);
247 	}
248 	close (skfd);
249     }
250 
251     /*
252      * Statistics
253      */
254 
255     solaris_stats(server, buf, interface);
256 
257 }
258