summaryrefslogtreecommitdiff
path: root/src/pmdas/cisco/telnet.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pmdas/cisco/telnet.c')
-rw-r--r--src/pmdas/cisco/telnet.c755
1 files changed, 755 insertions, 0 deletions
diff --git a/src/pmdas/cisco/telnet.c b/src/pmdas/cisco/telnet.c
new file mode 100644
index 0000000..bcee1db
--- /dev/null
+++ b/src/pmdas/cisco/telnet.c
@@ -0,0 +1,755 @@
+/*
+ * Copyright (c) 2012 Red Hat.
+ * Copyright (c) 1995-2004 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <syslog.h>
+#include "./cisco.h"
+
+extern int port;
+
+int
+conn_cisco(cisco_t * cp)
+{
+ __pmFdSet wfds;
+ __pmSockAddr *myaddr;
+ void *enumIx;
+ int flags = 0;
+ int fd;
+ int ret;
+
+ fd = -1;
+ enumIx = NULL;
+ for (myaddr = __pmHostEntGetSockAddr(cp->hostinfo, &enumIx);
+ myaddr != NULL;
+ myaddr = __pmHostEntGetSockAddr(cp->hostinfo, &enumIx)) {
+ /* Create a socket */
+ if (__pmSockAddrIsInet(myaddr))
+ fd = __pmCreateSocket();
+ else if (__pmSockAddrIsIPv6(myaddr))
+ fd = __pmCreateIPv6Socket();
+ else
+ continue;
+ if (fd < 0) {
+ __pmSockAddrFree(myaddr);
+ continue; /* Try the next address */
+ }
+
+ /* Attempt to connect */
+ flags = __pmConnectTo(fd, myaddr, cp->port);
+ __pmSockAddrFree(myaddr);
+
+ if (flags < 0) {
+ /*
+ * Mark failure in case we fall out the end of the loop
+ * and try next address. fd has been closed in __pmConnectTo().
+ */
+ setoserror(ECONNREFUSED);
+ fd = -1;
+ continue;
+ }
+
+ /* FNDELAY and we're in progress - wait on select */
+ __pmFD_ZERO(&wfds);
+ __pmFD_SET(fd, &wfds);
+ ret = __pmSelectWrite(fd+1, &wfds, NULL);
+
+ /* Was the connection successful? */
+ if (ret == 0)
+ setoserror(ETIMEDOUT);
+ else if (ret > 0) {
+ ret = __pmConnectCheckError(fd);
+ if (ret == 0)
+ break;
+ setoserror(ret);
+ }
+
+ /* Unsuccessful connection. */
+ __pmCloseSocket(fd);
+ fd = -1;
+ } /* loop over addresses */
+
+ if (fd == -1) {
+ fprintf(stderr, "conn_cisco(%s): connect: %s\n",
+ cp->host, netstrerror());
+ return -1;
+ }
+
+ fd = __pmConnectRestoreFlags(fd, flags);
+ if (fd < 0) {
+ fprintf(stderr, "conn_cisco(%s): setsockopt: %s\n",
+ cp->host, netstrerror());
+ return -1;
+ }
+
+ return fd;
+}
+
+static void
+skip2eol(FILE *f)
+{
+ int c;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ fprintf(stderr, "skip2eol:");
+#endif
+
+ while ((c = fgetc(f)) != EOF) {
+ if (c == '\n')
+ break;
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ fprintf(stderr, "%c", c);
+#endif
+ }
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ fputc('\n', stderr);
+#endif
+}
+
+char *
+mygetwd(FILE *f, char *prompt)
+{
+ char *p;
+ int c;
+ static char buf[1024];
+ int len_prompt = strlen(prompt);
+ int found_prompt = 0;
+
+ p = buf;
+
+ while ((c = fgetc(f)) != EOF) {
+ if (c == '\r' || c == '\n' || c == ' ' || c == '\t') {
+ if (p == buf)
+ continue;
+ break;
+ }
+ *p++ = c;
+ if (p-buf >= len_prompt && strncmp(&p[-len_prompt], prompt, len_prompt) == 0) {
+ found_prompt = 1;
+ break;
+ }
+ }
+ *p = '\0';
+
+ if (feof(f)) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ fprintf(stderr, "mygetwd: EOF fd=%d\n", fileno(f));
+#endif
+ return NULL;
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ fprintf(stderr, "mygetwd: fd=%d wd=\"%s\"%s\n", fileno(f), buf, found_prompt ? " [prompt]" : "");
+#endif
+
+ return buf;
+}
+
+/*
+ * The CISCO "show interface" command output is parsed.
+ *
+ * See the file Samples for examples.
+ *
+ * The parser is a Finite State Automaton (FSA) that follows these
+ * rules:
+ *
+ * SHOW_INT style ... uses "show int <interface>" command
+ * state token next state
+ * NOISE <interface name> IN_REPORT
+ * IN_REPORT Description: skip rest of line, IN_REPORT
+ * IN_REPORT <prompt> DONE
+ * IN_REPORT minute RATE
+ * IN_REPORT second RATE
+ * IN_REPORT input, BYTES_IN
+ * IN_REPORT output, BYTES_OUT
+ * IN_REPORT BW BW
+ * RATE input skip next token, RATE_IN
+ * RATE output skip next token, RATE_OUT
+ * RATE_IN <number> (rate_in) IN_REPORT
+ * RATE_OUT <number> (rate_out) IN_REPORT
+ * BYTES_IN <number> (bytes_in) IN_REPORT
+ * BYTES_OUT <number> (bytes_out) IN_REPORT
+ * BW <number> (bandwidth) IN_REPORT
+ *
+ * SHOW_FRAME style ... uses "show frame pvc int <interface>" command
+ * state token next state
+ * NOISE <interface name> IN_REPORT
+ * IN_REPORT Description: skip rest of line, IN_REPORT
+ * IN_REPORT <prompt> DONE
+ * IN_REPORT 1st bytes BYTES_IN
+ * IN_REPORT 2nd bytes BYTES_OUT
+ * IN_REPORT 3rd bytes BYTES_OUT_BCAST
+ * BYTES_IN <number> (bytes_in) IN_REPORT
+ * BYTES_OUT <number> (bytes_out) IN_REPORT
+ * BYTES_OUT_BCAST <number> (bytes_out_bcast) IN_REPORT
+ *
+ * Note lines are terminated with \r
+ */
+
+#define DONE -1
+#define NOISE 0
+#define IN_REPORT 1
+#define RATE 2
+#define RATE_IN 3
+#define RATE_OUT 4
+#define BYTES_IN 5
+#define BYTES_OUT 6
+#define BW 7
+#define BYTES_OUT_BCAST 8
+
+#ifdef PCP_DEBUG
+static char *statestr[] = {
+ "done", "noise", "in_report",
+ "rate", "rate_in", "rate_out", "bytes_in", "bytes_out", "bw",
+ "bytes_out_bcast"
+};
+#endif
+
+int
+dousername(cisco_t *cp, char **pw_prompt)
+{
+ char *w;
+ int len, done = 0;
+ int len_prompt = strlen(cp->prompt);
+
+ for ( ; ; ) {
+ w = mygetwd(cp->fin, cp->prompt);
+ if (w == NULL)
+ break;
+ if (strlen(w) >= len_prompt && strncmp(&w[strlen(w)-len_prompt], cp->prompt, len_prompt) == 0)
+ break;
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ fprintf(stderr, "Username:? got - %s\n", w);
+#endif
+ if (strcmp(w, USERPROMPT) == 0) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1) {
+ fprintf(stderr, "Send username: %s\n", cp->username);
+ }
+#endif
+ fprintf(cp->fout, "%s\n", cp->username);
+ fflush(cp->fout);
+ for ( ; ; ) {
+ w = mygetwd(cp->fin, cp->prompt);
+ if (w == NULL || strcmp(w, USERPROMPT) == 0)
+ /* closed connection or Username re-prompt */
+ break;
+ len = strlen(w);
+ if ((len >= len_prompt && strncmp(&w[len-len_prompt], cp->prompt, len_prompt) == 0) ||
+ w[len-1] == ':') {
+ /* command prompt or passwd */
+ if (w[len-1] == ':')
+ *pw_prompt = w;
+ done = 1;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ if (done == 0) {
+ fprintf(stderr, "Error: Cisco username negotiation failed for \"%s\"\n",
+ cp->host);
+ fprintf(stderr,
+"To check that a username is required, enter the following command:\n"
+" $ telnet %s\n"
+"If the prompt \"%s\" does not appear, no username is required.\n"
+"Otherwise, enter the username \"%s\" to check that this\n"
+"is correct.\n",
+cp->host, USERPROMPT, cp->username);
+ }
+
+ return done;
+}
+
+int
+dopasswd(cisco_t *cp, char *pw_prompt)
+{
+ char *w;
+ int done = 0;
+ int len_prompt = strlen(cp->prompt);
+
+ for ( ; ; ) {
+ if (pw_prompt) /* dousername may have read passwd prompt */
+ w = pw_prompt;
+ else
+ w = mygetwd(cp->fin, cp->prompt);
+ pw_prompt = NULL;
+ if (w == NULL)
+ break;
+ if (strlen(w) >= len_prompt && strncmp(&w[strlen(w)-len_prompt], cp->prompt, len_prompt) == 0)
+ break;
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ fprintf(stderr, "Password:? got - %s\n", w);
+#endif
+ if (strcmp(w, PWPROMPT) == 0) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1) {
+ fprintf(stderr, "Send passwd: %s\n", cp->passwd);
+ }
+#endif
+ fprintf(cp->fout, "%s\n", cp->passwd);
+ fflush(cp->fout);
+ for ( ; ; ) {
+ w = mygetwd(cp->fin, cp->prompt);
+ if (w == NULL || strcmp(w, PWPROMPT) == 0)
+ /* closed connection or user-level password re-prompt */
+ break;
+ if (strlen(w) >= len_prompt && strncmp(&w[strlen(w)-len_prompt], cp->prompt, len_prompt) == 0) {
+ /* command prompt */
+ done = 1;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ if (done == 0) {
+ fprintf(stderr, "Error: Cisco user-level password negotiation failed for \"%s\"\n",
+ cp->host);
+ fprintf(stderr,
+"To check that a user-level password is required, enter the following command:\n"
+" $ telnet %s\n"
+"If the prompt \"%s\" does not appear, no user-level password is required.\n"
+"Otherwise, enter the user-level password \"%s\" to check that this\n"
+"is correct.\n",
+cp->host, PWPROMPT, cp->passwd);
+ }
+
+ return done;
+}
+
+static int timeout;
+
+void
+onalarm(int dummy)
+{
+ timeout = 1;
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ fprintf(stderr, "Alarm timeout!\n");
+ }
+#endif
+
+}
+
+static int
+get_fr_bw(cisco_t *cp, char *interface)
+{
+ int state = NOISE;
+ int bandwidth = -1;
+ char *w;
+ int len_prompt = strlen(cp->prompt);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1) {
+ fprintf(stderr, "Send: s%s\n", interface);
+ }
+#endif
+ fprintf(cp->fout, "show int s%s\n", interface);
+ fflush(cp->fout);
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ fprintf(stderr, "BW Parse:");
+#endif
+ while (state != DONE) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ fprintf(stderr, "[%s] ", statestr[state+1]);
+#endif
+ w = mygetwd(cp->fin, cp->prompt);
+ if (w == NULL || timeout) {
+ /*
+ * End of File (telenet timeout?)
+ */
+ alarm(0);
+ return -1;
+ }
+ switch (state) {
+
+ case NOISE:
+ if (strncmp(w, "Serial", 6) == 0 && strcmp(&w[6], interface) == 0)
+ state = IN_REPORT;
+ break;
+
+ case IN_REPORT:
+ if (strcmp(w, "Description:") == 0)
+ skip2eol(cp->fin);
+ else if (strlen(w) >= len_prompt && strncmp(&w[strlen(w)-len_prompt], cp->prompt, len_prompt) == 0)
+ state = DONE;
+ else if (strcmp(w, "BW") == 0)
+ state = BW;
+ break;
+
+ case BW:
+ sscanf(w, "%d", &bandwidth);
+ bandwidth *= 1000; /* Kbit -> bytes/sec */
+ bandwidth /= 8;
+ state = IN_REPORT;
+ break;
+
+ }
+ }
+ alarm(0);
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ fprintf(stderr, "Extracted bandwidth: %d bytes/sec\n", bandwidth);
+ }
+#endif
+ return bandwidth;
+}
+
+#define SHOW_INT 1
+#define SHOW_FRAME 2
+
+int
+grab_cisco(intf_t *ip)
+{
+ int style;
+ int next_state;
+ int state = NOISE;
+ int skip = 0;
+ int i;
+ int namelen;
+ char *pw_prompt = NULL;
+ char *w;
+ int fd;
+ int fd2;
+ int nval = 0;
+ cisco_t *cp = ip->cp;
+ intf_t tmp;
+ int len_prompt = strlen(cp->prompt);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ fprintf(stderr, "grab_cisco(%s:%s):\n", cp->host, ip->interface);
+ }
+#endif
+
+ tmp.bandwidth = tmp.rate_in = tmp.rate_out = -1;
+ tmp.bytes_in = tmp.bytes_out = tmp.bytes_out_bcast = -1;
+
+ if (cp->fin == NULL) {
+ fd = conn_cisco(cp);
+ if (fd < 0) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ fprintf(stderr, "grab_cisco(%s:%s): connect failed: %s\n",
+ cp->host, ip->interface, netstrerror());
+#endif
+ return -1;
+ }
+ else {
+ cp->fin = fdopen (fd, "r");
+ if ((fd2 = dup(fd)) < 0) {
+ perror("dup");
+ exit(1);
+ }
+ cp->fout = fdopen (fd2, "w");
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ fprintf(stderr, "grab_cisco(%s:%s): connected fin=%d fout=%d",
+ cp->host, ip->interface, fileno(cp->fin), fileno(cp->fout));
+ if (cp->username != NULL)
+ fprintf(stderr, " username=%s", cp->username);
+ else
+ fprintf(stderr, " NO username");
+ if (cp->passwd != NULL)
+ fprintf(stderr, " passwd=%s", cp->passwd);
+ else
+ fprintf(stderr, " NO passwd");
+ fputc('\n', stderr);
+ }
+#endif
+
+ if (cp->username != NULL) {
+ /*
+ * Username stuff ...
+ */
+ if (dousername(cp, &pw_prompt) == 0) {
+ fclose(cp->fin);
+ fclose(cp->fout);
+ cp->fin = cp->fout = NULL;
+ return -1;
+ }
+ }
+ if (cp->passwd != NULL) {
+ /*
+ * User-level password stuff ...
+ */
+ if (dopasswd(cp, pw_prompt) == 0) {
+ fclose(cp->fin);
+ fclose(cp->fout);
+ cp->fin = cp->fout = NULL;
+ return -1;
+ }
+ }
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1) {
+ fprintf(stderr, "Send: \n");
+ }
+#endif
+ fprintf(cp->fout, "\n");
+ fflush(cp->fout);
+ }
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1) {
+ fprintf(stderr, "Send: terminal length 0\n");
+ }
+#endif
+ fprintf(cp->fout, "terminal length 0\n");
+ fflush(cp->fout);
+ }
+
+ timeout = 0;
+ signal(SIGALRM, onalarm);
+ /*
+ * Choice of timeout here is somewhat arbitrary ... for a long
+ * time this was 5 (seconds), but then testing with an entry
+ * level Model 800 ADSL router revealed that up to 20 seconds
+ * was required to generate the expected output.
+ */
+ alarm(20);
+
+ style = SHOW_INT; /* default Cisco command */
+ if (ip->interface[0] == 's' && strchr(ip->interface, '.') != NULL) {
+ /*
+ * Frame-relay PVC on subinterface for s2/3.7 style interface name
+ */
+ style = SHOW_FRAME;
+ if (ip->bandwidth == -2) {
+ /*
+ * one-trip initialzation ... need show int s2/3.7 to
+ * get bandwidth
+ */
+ ip->bandwidth = get_fr_bw(cp, &ip->interface[1]);
+ }
+ tmp.bandwidth = ip->bandwidth;
+ if (tmp.bandwidth != -1)
+ nval++;
+ }
+ if (style == SHOW_FRAME) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1) {
+ fprintf(stderr, "Send: show frame pvc int s%s\n", &ip->interface[1]);
+ }
+#endif
+ fprintf(cp->fout, "show frame pvc int s%s\n", &ip->interface[1]);
+ next_state = BYTES_IN;
+ }
+ else {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1) {
+ fprintf(stderr, "Send: show int %s\n", ip->interface);
+ }
+#endif
+ fprintf(cp->fout, "show int %s\n", ip->interface);
+ }
+ fflush(cp->fout);
+ state = NOISE;
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2) {
+ fprintf(stderr, "Parse:");
+ fflush(stderr);
+ }
+#endif
+ while (state != DONE) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2) {
+ fprintf(stderr, "[%s] ", statestr[state+1]);
+ fflush(stderr);
+ }
+#endif
+ w = mygetwd(cp->fin, cp->prompt);
+ if (w == NULL || timeout) {
+ /*
+ * End of File (telenet timeout?)
+ * ... mark as closed, and try again at next request
+ */
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ fprintf(stderr, "grab_cisco(%s:%s): forced disconnect fin=%d\n",
+ cp->host, ip->interface, fileno(cp->fin));
+#endif
+ fclose(cp->fin);
+ fclose(cp->fout);
+ cp->fin = cp->fout = NULL;
+ alarm(0);
+ return -1;
+ }
+ switch (state) {
+
+ case NOISE:
+ for (i = 0; i < num_intf_tab; i++) {
+ namelen = strlen(intf_tab[i].name);
+ if (strncmp(w, intf_tab[i].name, namelen) == 0) {
+ state = IN_REPORT;
+ break;
+ }
+ }
+ break;
+
+ case IN_REPORT:
+ if (strcmp(w, "Description:") == 0)
+ skip2eol(cp->fin);
+ if (strlen(w) >= len_prompt && strncmp(&w[strlen(w)-len_prompt], cp->prompt, len_prompt) == 0)
+ state = DONE;
+ else if (style == SHOW_INT) {
+ if (strcmp(w, "minute") == 0 || strcmp(w, "second") == 0)
+ state = RATE;
+ else if (strcmp(w, "input,") == 0)
+ state = BYTES_IN;
+ else if (strcmp(w, "output,") == 0)
+ state = BYTES_OUT;
+ else if (strcmp(w, "BW") == 0)
+ state = BW;
+ }
+ else if (style == SHOW_FRAME) {
+ if (strcmp(w, "bytes") == 0) {
+ if (next_state == BYTES_IN) {
+ state = BYTES_IN;
+ next_state = BYTES_OUT;
+ }
+ else if (next_state == BYTES_OUT) {
+ state = BYTES_OUT;
+ next_state = BYTES_OUT_BCAST;
+ }
+ else if (next_state == BYTES_OUT_BCAST) {
+ state = BYTES_OUT_BCAST;
+ next_state = IN_REPORT;
+ }
+ else
+ state = next_state;
+ }
+ }
+ break;
+
+ case RATE:
+ if (strcmp(w, "input") == 0) {
+ skip = 1;
+ state = RATE_IN;
+ }
+ else if (strcmp(w, "output") == 0) {
+ skip = 1;
+ state = RATE_OUT;
+ }
+ break;
+
+ case RATE_IN:
+ if (skip-- == 0) {
+ tmp.rate_in = atol(w) / 8;
+ nval++;
+ state = IN_REPORT;
+ }
+ break;
+
+ case RATE_OUT:
+ if (skip-- == 0) {
+ tmp.rate_out = atol(w) / 8;
+ nval++;
+ state = IN_REPORT;
+ }
+ break;
+
+ case BYTES_IN:
+ tmp.bytes_in = strtoull(w, NULL, 10);
+ nval++;
+ state = IN_REPORT;
+ break;
+
+ case BYTES_OUT:
+ tmp.bytes_out = strtoull(w, NULL, 10);
+ nval++;
+ state = IN_REPORT;
+ break;
+
+ case BYTES_OUT_BCAST:
+ tmp.bytes_out_bcast = strtoull(w, NULL, 10);
+ nval++;
+ state = IN_REPORT;
+ break;
+
+ case BW:
+ sscanf(w, "%d", &tmp.bandwidth);
+ tmp.bandwidth *= 1000; /* Kbit -> bytes/sec */
+ tmp.bandwidth /= 8;
+ nval++;
+ state = IN_REPORT;
+ break;
+
+ }
+ }
+ alarm(0);
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ fprintf(stderr, "Extracted %d values ...\n", nval);
+ if (tmp.bandwidth != 0xffffffff)
+ fprintf(stderr, "bandwidth: %d bytes/sec\n", tmp.bandwidth);
+ else
+ fprintf(stderr, "bandwidth: ? bytes/sec\n");
+ fprintf(stderr, "recent rate (bytes/sec):");
+ if (tmp.rate_in != 0xffffffff)
+ fprintf(stderr, " %d in", tmp.rate_in);
+ else
+ fprintf(stderr, " ? in");
+ if (tmp.rate_out != 0xffffffff)
+ fprintf(stderr, " %d out", tmp.rate_out);
+ else
+ fprintf(stderr, " ? out");
+ fprintf(stderr, "\ntotal bytes:");
+ if (tmp.bytes_in != 0xffffffffffffffffLL)
+ fprintf(stderr, " %llu in", (unsigned long long)tmp.bytes_in);
+ else
+ fprintf(stderr, " ? in");
+ if (tmp.bytes_out != 0xffffffffffffffffLL)
+ fprintf(stderr, " %llu out", (unsigned long long)tmp.bytes_out);
+ else
+ fprintf(stderr, " ? out");
+ if (tmp.bytes_out_bcast != 0xffffffffffffffffLL)
+ fprintf(stderr, " %llu out_bcast", (unsigned long long)tmp.bytes_out_bcast);
+ else
+ fprintf(stderr, " ? out_bcast");
+ fprintf(stderr, "\n\n");
+ }
+#endif
+
+ /* pretend this is atomic */
+ ip->bandwidth = tmp.bandwidth;
+ ip->rate_in = tmp.rate_in;
+ ip->rate_out = tmp.rate_out;
+ ip->bytes_in = tmp.bytes_in;
+ ip->bytes_out = tmp.bytes_out;
+ ip->bytes_out_bcast = tmp.bytes_out_bcast;
+
+ return nval;
+}