Patch from Robert Vogelgesang:
authorPaul Mackerras <paulus@samba.org>
Thu, 28 Oct 2004 00:32:32 +0000 (00:32 +0000)
committerPaul Mackerras <paulus@samba.org>
Thu, 28 Oct 2004 00:32:32 +0000 (00:32 +0000)
This patch fixes the link statistics for connections that
go through multiple IPCP up-down cycles.  Such connections
happen typically in a setup where pppd is used as a back-end
by a L2TP daemon, in case the PPP session at the other side
of the L2TP tunnel reconnects, but the L2TP daemon at that
side just reuses the old L2TP tunnel instead of creating a
new one.

The patch is most important when RADIUS accounting is in use:
Each IPCP-down initiates a RADIUS-Accounting-Stop packet, which
indicates the end of a session.  Without this patch, the
accounting information in each subsequent RADIUS-Accounting-Stop
packet of the very same connection would contain cumulative
data since the connection start, but not the data of the last
"sub-session"; in other words, the accounting data sent to
the RADIUS server would indicate that the client had used much
more session time and transfered much more data.
NOTE: The problem fixed by this patch exists even when the
radius plugin is not in use; when extracting accounting data
from the syslog, you can work around the bug, because you
can see there that the same instance of pppd had multiple
sessions; you cannot see this in the RADIUS accounting data.

Furthermore, this patch suppresses duplicate printing/syslogging
of identical data.

pppd/ipcp.c
pppd/main.c
pppd/pppd.h

index 128c204d64e0c96b2b8379dabb53b4a23718fdc9..4957ac59c2f106a35f746af249afa2b84d399be4 100644 (file)
@@ -40,7 +40,7 @@
  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define RCSID  "$Id: ipcp.c,v 1.65 2004/01/13 03:59:06 paulus Exp $"
+#define RCSID  "$Id: ipcp.c,v 1.66 2004/10/28 00:32:32 paulus Exp $"
 
 /*
  * TODO:
@@ -1805,6 +1805,8 @@ ipcp_up(f)
            notice("secondary DNS address %I", go->dnsaddr[1]);
     }
 
+    reset_link_stats(f->unit);
+
     np_up(f->unit, PPP_IP);
     ipcp_is_up = 1;
 
@@ -1836,6 +1838,8 @@ ipcp_down(f)
     IPCPDEBUG(("ipcp: down"));
     /* XXX a bit IPv4-centric here, we only need to get the stats
      * before the interface is marked down. */
+    /* XXX more correct: we must get the stats before running the notifiers,
+     * at least for the radius plugin */
     update_link_stats(f->unit);
     notify(ip_down_notifier, 0);
     if (ip_down_hook)
@@ -1846,6 +1850,10 @@ ipcp_down(f)
     }
     sifvjcomp(f->unit, 0, 0, 0);
 
+    print_link_stats(); /* _after_ running the notifiers and ip_down_hook(),
+                        * because print_link_stats() sets link_stats_valid
+                        * to 0 (zero) */
+
     /*
      * If we are doing dial-on-demand, set the interface
      * to queue up outgoing packets (for now).
index d53f6412746f081e1796bc1dc17c345435aa1418..0bb94922e78d545545d134912412acb8ad22c49a 100644 (file)
@@ -40,7 +40,7 @@
  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define RCSID  "$Id: main.c,v 1.137 2004/10/24 23:13:16 paulus Exp $"
+#define RCSID  "$Id: main.c,v 1.138 2004/10/28 00:32:32 paulus Exp $"
 
 #include <stdio.h>
 #include <ctype.h>
@@ -172,6 +172,7 @@ int ngroups;                        /* How many groups valid in groups */
 
 static struct timeval start_time;      /* Time when link was started. */
 
+static struct pppd_stats old_link_stats;
 struct pppd_stats link_stats;
 unsigned link_connect_time;
 int link_stats_valid;
@@ -219,7 +220,7 @@ static void cleanup_db __P((void));
 #endif
 
 static void handle_events __P((void));
-static void print_link_stats __P((void));
+void print_link_stats __P((void));
 
 extern char    *ttyname __P((int));
 extern char    *getlogin __P((void));
@@ -1126,7 +1127,7 @@ void
 die(status)
     int status;
 {
-       print_link_stats();
+    print_link_stats();
     cleanup();
     notify(exitnotify, status);
     syslog(LOG_INFO, "Exit.");
@@ -1176,6 +1177,18 @@ print_link_stats()
     }
 }
 
+/*
+ * reset_link_stats - "reset" stats when link goes up.
+ */
+void
+reset_link_stats(u)
+    int u;
+{
+    if (!get_ppp_stats(u, &old_link_stats))
+       return;
+    gettimeofday(&start_time, NULL);
+}
+
 /*
  * update_link_stats - get stats at link termination.
  */
@@ -1192,6 +1205,11 @@ update_link_stats(u)
     link_connect_time = now.tv_sec - start_time.tv_sec;
     link_stats_valid = 1;
 
+    link_stats.bytes_in  -= old_link_stats.bytes_in;
+    link_stats.bytes_out -= old_link_stats.bytes_out;
+    link_stats.pkts_in   -= old_link_stats.pkts_in;
+    link_stats.pkts_out  -= old_link_stats.pkts_out;
+
     slprintf(numbuf, sizeof(numbuf), "%u", link_connect_time);
     script_setenv("CONNECT_TIME", numbuf, 0);
     slprintf(numbuf, sizeof(numbuf), "%u", link_stats.bytes_out);
index 14e0dc39cb19cf995e15d672058afb60e2e616cd..dbb3e871634387e46588f41aa7716129526bcf29 100644 (file)
@@ -39,7 +39,7 @@
  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * $Id: pppd.h,v 1.82 2003/04/07 00:01:46 paulus Exp $
+ * $Id: pppd.h,v 1.83 2004/10/28 00:32:32 paulus Exp $
  */
 
 /*
@@ -473,6 +473,8 @@ pid_t run_program __P((char *prog, char **args, int must_exist,
                       void (*done)(void *), void *arg));
                                /* Run program prog with args in child */
 void reopen_log __P((void));   /* (re)open the connection to syslog */
+void print_link_stats __P((void)); /* Print stats, if available */
+void reset_link_stats __P((int)); /* Reset (init) stats when link goes up */
 void update_link_stats __P((int)); /* Get stats at link termination */
 void script_setenv __P((char *, char *, int)); /* set script env var */
 void script_unsetenv __P((char *));            /* unset script env var */