loadlwipv6 inlined
[vde.git] / vde-2 / src / lib / libvdesnmp.c
blob5cee51b53c5f0df849a52fe403b8bc59e4e52c73
1 /*
2 * Copyright (C) 2007 - Filippo Giunchedi
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version 2
6 * of the License, or (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <sys/socket.h>
21 #include <sys/un.h>
22 #include <assert.h>
23 #include <errno.h>
24 #include <sys/time.h>
25 #include <time.h>
27 #include <config.h>
28 #include <vde.h>
29 #include <vdecommon.h>
31 #include <libvdesnmp.h>
32 #include <libvdemgmt.h>
33 #include <vdeplugin.h>
35 #ifdef STANDALONE
36 #define EXIT(i) exit(i)
37 #else
38 #define EXIT(i) return(i)
39 #endif
41 vde_stats_t *_stats = NULL;
43 struct vdemgmt *mgmt_conn;
44 struct vdemgmt_out *mgmt_outbuf;
46 struct timeval *init_tv;
47 struct timeval *cur_tv;
49 int (*events[EVENTS_NUM])(int);
51 int stats_init(){
52 assert( _stats == NULL );
54 // init struttura
55 _stats = malloc(sizeof(vde_stats_t));
56 if( _stats == NULL )
57 return 0;
59 // init campi
60 _stats->numports = 0;
62 return 1;
65 #define PORTPRINT(pl) debug(" port: %d", pl->index); \
66 debug(" desc: %s", pl->desc); \
67 debug(" mtu: %d", pl->mtu); \
68 debug(" speed: %d", pl->speed); \
69 debug(" phyaddr: %s", pl->phyaddress); \
70 debug(" adminstatus: %d", pl->adminstatus); \
71 debug(" operstatus: %d", pl->operstatus); \
72 debug(" lastchange: %ld", pl->time_lastchange); \
73 debug(" in->ucastpkts: %ld", pl->in->ucastpkts); \
74 debug(" in->octects: %ld", pl->in->octects); \
75 debug(" out->ucastpkts: %ld", pl->out->ucastpkts); \
76 debug(" out->octects: %ld", pl->out->octects);
78 /* ths of second between a and b (both struct timeval*) assuming a > b */
79 #define CSECDIFF(a, b) ( (((a)->tv_sec - (b)->tv_sec) * 100) + (( (a)->tv_usec > (b)->tv_usec ? (a)->tv_usec - (b)->tv_usec : 1000000 - (b)->tv_usec + (a)->tv_usec ) / 10000 ) )
81 /* return ths of a second from init_tv */
82 #define CSECINIT() ( CSECDIFF(cur_tv, init_tv) )
84 #define PORTUP(num) if( _stats->ports[num].operstatus != OPERSTATUS_UP ) { \
85 _stats->ports[num].time_lastchange = CSECINIT(); } \
86 debug("portup: %d", num); \
87 _stats->ports[num].adminstatus = ADMINSTATUS_UP; \
88 _stats->ports[num].operstatus = OPERSTATUS_UP; \
89 _stats->ports[num].active = 1;
91 #define PORTDOWN(num) if( _stats->ports[num].operstatus != OPERSTATUS_DOWN ) { \
92 _stats->ports[num].time_lastchange = CSECINIT(); } \
93 debug("portdown: %d", num); \
94 _stats->ports[num].adminstatus = ADMINSTATUS_DOWN; \
95 _stats->ports[num].operstatus = OPERSTATUS_DOWN; \
96 _stats->ports[num].active = 0;
100 #define SENDCMD(cmd) memset(mgmt_outbuf, 0, sizeof(struct vdemgmt_out)); if(!mgmt_conn) { errno = ECONNREFUSED; return 0; } vdemgmt_sendcmd(mgmt_conn, cmd, mgmt_outbuf);
102 int mgmt_init(char *sockpath){
103 char *p,*q;
104 short countersok=0, numportsok=0;
106 mgmt_conn = vdemgmt_open(sockpath);
108 if(!mgmt_conn){
109 errno = ECONNREFUSED;
110 return 0;
113 mgmt_outbuf=(struct vdemgmt_out *)malloc(sizeof(struct vdemgmt_out));
114 if(!mgmt_outbuf){
115 errno = ENOMEM;
116 return 0;
119 SENDCMD("port/showinfo");
121 // FIXME this could be factored into a macro
122 q=p=mgmt_outbuf->buf;
123 while(p < mgmt_outbuf->buf+mgmt_outbuf->sz){
124 if(*p == '\0'){
125 if( strcmp(q, "counters=true\n") == 0 )
126 countersok=1;
128 if( sscanf(q, "Numports=%d\n", &(_stats->numports)) == 1 )
129 numportsok=1;
131 q=p+1;
133 p++;
136 if( countersok && numportsok )
137 return 1;
139 printf("couldn't parse counters or numports\n");
140 return 0;
143 int ports_init(void){
144 int i;
145 struct vde_port_stats *ps;
147 cur_tv = malloc(sizeof(struct timeval));
148 init_tv = malloc(sizeof(struct timeval));
150 assert(_stats != NULL);
151 assert(_stats->numports > 0);
153 _stats->ports = (struct vde_port_stats *) malloc(sizeof(struct vde_port_stats) * _stats->numports);
155 assert(_stats->ports != NULL);
157 // ASSUMPTION: this is the same as sysUpTime time
158 gettimeofday(init_tv, NULL);
160 for(i=0; i<_stats->numports; i++){
161 ps = &(_stats->ports[i]);
162 ps->out = malloc(sizeof(traffic_t));
163 ps->in = malloc(sizeof(traffic_t));
164 assert( ps->in != NULL && ps->out != NULL );
166 ps->index = 0;
167 ps->active = 0;
168 // FIXME what sensible values might be for mtu/speed?
169 ps->mtu = 0;
170 ps->speed = 0;
172 ps->adminstatus = ADMINSTATUS_DOWN;
173 ps->operstatus = OPERSTATUS_NOTPRESENT;
174 // TimeTicks == hundredths of a second
175 ps->time_lastchange = init_tv->tv_usec;
177 ps->desc[0] = '\0';
178 ps->phyaddress[0] = '\0';
180 ps->in->octects = 0;
181 ps->in->ucastpkts = 0;
182 ps->in->discards = 0;
183 ps->in->errors = 0;
184 ps->in->unknownprotos = 0;
186 ps->out->octects = 0;
187 ps->out->ucastpkts = 0;
188 ps->out->discards = 0;
189 ps->out->errors = 0;
190 ps->out->unknownprotos = 0;
192 return 1;
195 // FIXME mac address info from hash/print is missing
196 // Hash: 0105 Addr: ae:4a:3c:e1:6e:c9 VLAN 0000 to port: 001 age 3 secs
197 int counters_parse(void){
198 char *p,*q;
200 char portstatus[10];
201 int i, curport=0;
202 char portdesc[DESC_MAXLEN];
204 short inport=0, outok=0, inok=0;
206 struct vde_port_stats *pl;
208 // FIXME are these types large enough?
209 long inbytes, inpkts;
210 long outbytes, outpkts;
212 memset(portdesc, '\0', DESC_MAXLEN);
214 if(!mgmt_conn){
215 printf("error initializing connection, is vde running?\n");
216 return 0;
219 assert(_stats->ports != NULL);
221 for(i=0; i < _stats->numports; i++){
222 _stats->ports[i].active = 0;
225 SENDCMD("port/allprint");
227 q=p=mgmt_outbuf->buf;
228 while(p < mgmt_outbuf->buf+mgmt_outbuf->sz){
229 if(*p == '\0'){
231 /* Port 0001 untagged_vlan=0000 INACTIVE - Unnamed Allocatable */
232 if( sscanf(q, "Port %4d %*s %s - %*s\n", &curport, portstatus) == 2 )
233 inport=1;
235 if( inport ){
236 if( sscanf(q, " IN: pkts %ld bytes %ld\n", &inpkts, &inbytes) == 2 )
237 inok = 1;
239 if( sscanf(q, " OUT: pkts %ld bytes %ld\n", &outpkts, &outbytes) == 2 )
240 outok = 1;
242 /* -- endpoint ID 0005 module unix prog : vde_plug: user=godog PID=22006 SOCK=/tmp/vde.ctl.22006-00000 */
243 /* format from port.c:print_port() however there's room for DESC_MAXLEN bytes in portdesc */
244 if( (sscanf(q, " -- endpoint ID %*04d module %*12c: %255c\n", portdesc) == 1) ||
245 ( (strncmp(portstatus, "INACTIVE", 8) == 0) && inok && outok ) ){
247 gettimeofday(cur_tv, NULL);
249 pl = &(_stats->ports[curport-1]);
251 pl->active = 1;
252 pl->index = curport;
253 pl->in->octects = inbytes;
254 pl->in->ucastpkts = inpkts;
255 pl->out->octects = outbytes;
256 pl->out->ucastpkts = outpkts;
258 // FIXME we do not (yet) know the admin status since it is the
259 // "preferred status", i.e. the one wanted by user
260 if( strncmp(portstatus, "INACTIVE", 8) == 0 ){
261 PORTDOWN(curport-1);
262 } else if( strncmp(portstatus, "ACTIVE", 6) == 0 ){
263 PORTUP(curport-1);
264 strncpy(pl->desc, portdesc, strlen(portdesc)-1);
267 inpkts = inbytes = outpkts = outbytes = 0;
268 inok = outok = 0;
269 inport=0;
271 PORTPRINT(pl);
273 } /* if( inport ) */
275 q=p+1;
276 } /* if(*p == '\0') */
277 p++;
278 } /* while(p < mgmt_outbuf->buf+mgmt_outbuf->sz){ */
280 return 0;
283 void port_debug_handler(const char *event, const int tag, const char *data){
284 int portnum=0;
285 char *i, *j;
286 char tmpstr[DESC_MAXLEN];
288 memset(tmpstr, '\0', DESC_MAXLEN);
290 gettimeofday(cur_tv, NULL);
292 //printf("received: %s -- %d -- %s\n", event, tag, data);
294 switch(tag){
295 case D_PORT|D_DESCR:
296 if( sscanf(data, "/descr Port %02d", &portnum) == 1 ){
297 debug("parsed port %d\n", portnum);
300 i = index(data, '"');
301 j = rindex(data, '"');
302 if( i && j && j > i && portnum ){
303 strncpy(tmpstr, i+1, j - i );
304 strncpy(_stats->ports[portnum-1].desc, tmpstr, DESC_MAXLEN);
306 debug("parsed descr[%p %p]: %s", i, j, tmpstr);
307 break;
309 case D_EP|D_MINUS:
310 debug("ENDPOINT MINUS\n");
311 if( sscanf(data, "ep/- Port %02d", &portnum) == 1 ){
312 PORTDOWN(portnum-1);
313 if(events[EVENT_PORT_DOWN])
314 events[EVENT_PORT_DOWN](portnum-1);
316 break;
318 case D_EP|D_PLUS:
319 debug("ENDPOINT PLUS\n");
320 if( sscanf(data, "ep/+ Port %02d", &portnum) == 1 ){
321 PORTUP(portnum-1);
322 if(events[EVENT_PORT_UP])
323 events[EVENT_PORT_UP](portnum-1);
325 break;
327 case D_PORT|D_MINUS:
328 debug("PORT MINUS\n");
329 if( sscanf(data, "/- %02d", &portnum) == 1 ){
330 PORTDOWN(portnum-1);
332 break;
334 case D_PORT|D_PLUS:
335 debug("PORT PLUS\n");
336 if( sscanf(data, "/+ %02d", &portnum) == 1 ){
337 PORTUP(portnum-1);
339 break;
343 int vde_snmp_reset_lastchange(){
344 return gettimeofday(init_tv, NULL);
347 int vde_snmp_update(){
348 return counters_parse();
351 int vde_snmp_init(char *sockpath){
353 if( !stats_init() ){
354 debug("couldn't stats_init\n");
355 return -1;
358 if( !mgmt_init(sockpath) ){
359 debug("couldn't mgmt_init\n");
360 return -1;
363 if( vdemgmt_asyncreg(mgmt_conn, "port", port_debug_handler) != 0 ){
364 return -1;
367 events[EVENT_PORT_UP] = NULL;
368 events[EVENT_PORT_DOWN] = NULL;
370 if( !ports_init() ){
371 debug("couldn't ports_init\n");
372 return -1;
375 // vde_snmp_dumpstats(_stats);
377 #ifdef STANDALONE
378 counters_parse();
379 #else
380 return counters_parse();
381 #endif
383 /*vdemgmt_rstout(mgmt_outbuf);*/
384 /*vdemgmt_sendcmd(mgmt_conn, "debug/list", mgmt_outbuf);*/
385 /*write(1, mgmt_outbuf->buf, mgmt_outbuf->sz);*/
387 /* standalone mode, only print port events */
388 while(1){
389 struct pollfd pfd={vdemgmt_getfd(mgmt_conn), POLLIN, 0};
390 poll(&pfd,1,-1);
391 vdemgmt_asyncrecv(mgmt_conn);
392 PORTPRINT((&(_stats->ports[0])));
396 // FIXME vde_snmp_close() is missing
398 vde_stats_t* vde_snmp_get_stats(){
399 return _stats;
402 void vde_snmp_dumpstats(vde_stats_t *stats){
403 int i;
404 struct vde_port_stats *pl;
406 assert( stats != NULL );
408 debug("numports: %d", stats->numports);
410 assert( stats->ports != NULL);
412 for(i=0; i < stats->numports; i++){
413 pl = &(stats->ports[i]);
414 PORTPRINT(pl);
418 int vde_snmp_getfd(){
419 assert(mgmt_conn != NULL );
420 return vdemgmt_getfd(mgmt_conn);
423 void vde_snmp_event(){
424 assert(mgmt_conn != NULL );
425 vdemgmt_asyncrecv(mgmt_conn);
428 // TODO support more than one callback per event type
429 int vde_snmp_register_callback(int event, int (*callback)(int portindex)){
430 if( event < 0 || event >= EVENTS_NUM ){
431 errno = ENOENT;
432 return -1;
435 events[event] = callback;
437 return 0;