From: Paul Mackerras Date: Thu, 28 Oct 2004 00:32:32 +0000 (+0000) Subject: Patch from Robert Vogelgesang: X-Git-Tag: ppp-2.4.7~224 X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=commitdiff_plain;h=b46005d557c870f1125f2fc4dd139adc0bdc54c5 Patch from Robert Vogelgesang: 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. --- diff --git a/pppd/ipcp.c b/pppd/ipcp.c index 128c204..4957ac5 100644 --- a/pppd/ipcp.c +++ b/pppd/ipcp.c @@ -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). diff --git a/pppd/main.c b/pppd/main.c index d53f641..0bb9492 100644 --- a/pppd/main.c +++ b/pppd/main.c @@ -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 #include @@ -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); diff --git a/pppd/pppd.h b/pppd/pppd.h index 14e0dc3..dbb3e87 100644 --- a/pppd/pppd.h +++ b/pppd/pppd.h @@ -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 */