summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKozlov Dmitry <xeb@mail.ru>2012-07-11 18:47:08 +0400
committerKozlov Dmitry <xeb@mail.ru>2012-07-11 18:47:08 +0400
commitb2e106f8778fd834e0518cc6c0704d7d6b50875e (patch)
treee6a7dcd7f80b4cb52dd59a2cd087f4c30c357b41
parent07c57d04f2c585f4e3ba37bf61c3d14f9d40cd7d (diff)
downloadaccel-ppp-b2e106f8778fd834e0518cc6c0704d7d6b50875e.tar.gz
accel-ppp-b2e106f8778fd834e0518cc6c0704d7d6b50875e.zip
radius: fetch interface statistics via netlink
-rw-r--r--accel-pppd/libnetlink/iplink.c93
-rw-r--r--accel-pppd/libnetlink/iplink.h3
-rw-r--r--accel-pppd/radius/acct.c58
-rw-r--r--accel-pppd/radius/radius_p.h9
4 files changed, 137 insertions, 26 deletions
diff --git a/accel-pppd/libnetlink/iplink.c b/accel-pppd/libnetlink/iplink.c
index ba3ada0..df00285 100644
--- a/accel-pppd/libnetlink/iplink.c
+++ b/accel-pppd/libnetlink/iplink.c
@@ -3,6 +3,7 @@
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
+#include <pthread.h>
#include <net/if_arp.h>
#include <sys/socket.h>
#include <netinet/in.h>
@@ -11,17 +12,51 @@
#include <time.h>
#include <sys/uio.h>
-#include "libnetlink.h"
-#include "iplink.h"
#include "triton.h"
#include "log.h"
+#include "libnetlink.h"
+#include "iplink.h"
+
+#include "memdebug.h"
+
struct arg
{
iplink_list_func func;
void *arg;
};
+static pthread_key_t rth_key;
+static __thread struct rtnl_handle *rth;
+
+static void open_rth(void)
+{
+ rth = _malloc(sizeof(*rth));
+
+ if (!rth)
+ return;
+
+ memset(rth, 0, sizeof(*rth));
+
+ if (rtnl_open(rth, 0)) {
+ log_ppp_error("radius: cannot open rtnetlink\n");
+ _free(rth);
+ rth = NULL;
+ return;
+ }
+
+ pthread_setspecific(rth_key, rth);
+}
+
+static void free_rth(void *arg)
+{
+ struct rtnl_handle *rth = arg;
+
+ rtnl_close(rth);
+
+ _free(rth);
+}
+
static int store_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
struct ifinfomsg *ifi = NLMSG_DATA(n);
@@ -75,3 +110,57 @@ out_err:
return -1;
}
+int __export iplink_get_stats(int ifindex, struct rtnl_link_stats *stats)
+{
+ struct iplink_req {
+ struct nlmsghdr n;
+ struct ifinfomsg i;
+ char buf[4096];
+ } req;
+ struct ifinfomsg *ifi;
+ int len;
+ struct rtattr *tb[IFLA_MAX + 1];
+
+ if (!rth)
+ open_rth();
+
+ if (!rth)
+ return -1;
+
+ memset(&req, 0, sizeof(req) - 1024);
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ req.n.nlmsg_type = RTM_GETLINK;
+ req.i.ifi_family = AF_PACKET;
+ req.i.ifi_index = ifindex;
+
+ if (rtnl_talk(rth, &req.n, 0, 0, &req.n, NULL, NULL, 0) < 0)
+ return -1;
+
+ if (req.n.nlmsg_type != RTM_NEWLINK)
+ return -1;
+
+ ifi = NLMSG_DATA(&req.n);
+
+ len = req.n.nlmsg_len;
+
+ len -= NLMSG_LENGTH(sizeof(*ifi));
+ if (len < 0)
+ return -1;
+
+ parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
+ if (tb[IFLA_STATS])
+ memcpy(stats, RTA_DATA(tb[IFLA_STATS]), sizeof(*stats));
+ else
+ return -1;
+
+ return 0;
+}
+
+static void init(void)
+{
+ pthread_key_create(&rth_key, free_rth);
+}
+
+DEFINE_INIT(100, init);
diff --git a/accel-pppd/libnetlink/iplink.h b/accel-pppd/libnetlink/iplink.h
index 70c7c60..e67e8ed 100644
--- a/accel-pppd/libnetlink/iplink.h
+++ b/accel-pppd/libnetlink/iplink.h
@@ -1,8 +1,11 @@
#ifndef __IPLINK_H
#define __IPLINK_H
+#include <linux/if_link.h>
+
typedef int (*iplink_list_func)(int index, int flags, const char *name, void *arg);
int iplink_list(iplink_list_func func, void *arg);
+int iplink_get_stats(int ifindex, struct rtnl_link_stats *stats);
#endif
diff --git a/accel-pppd/radius/acct.c b/accel-pppd/radius/acct.c
index b5f7ff7..87ffd83 100644
--- a/accel-pppd/radius/acct.c
+++ b/accel-pppd/radius/acct.c
@@ -12,6 +12,8 @@
#include "log.h"
#include "backup.h"
#include "ap_session_backup.h"
+#include "iplink.h"
+
#include "radius_p.h"
#include "memdebug.h"
@@ -36,7 +38,9 @@ static int req_set_RA(struct rad_req_t *req, const char *secret)
static void req_set_stat(struct rad_req_t *req, struct ap_session *ses)
{
- struct ifpppstatsreq ifreq;
+ struct rtnl_link_stats stats;
+ struct radius_pd_t *rpd = req->rpd;
+
time_t stop_time;
if (ses->stop_time)
@@ -44,31 +48,31 @@ static void req_set_stat(struct rad_req_t *req, struct ap_session *ses)
else
time(&stop_time);
- memset(&ifreq, 0, sizeof(ifreq));
- ifreq.stats_ptr = (void *)&ifreq.stats;
- strcpy(ifreq.ifr__name, ses->ifname);
+ if (iplink_get_stats(ses->ifindex, &stats)) {
+ log_ppp_warn("radius: failed to get interface statistics\n");
+ return;
+ }
- if (ses->ctrl->type != CTRL_TYPE_IPOE) {
- if (ioctl(sock_fd, SIOCGPPPSTATS, &ifreq)) {
- log_ppp_error("radius: failed to get ppp statistics: %s\n", strerror(errno));
- return;
- }
+ stats.rx_packets -= rpd->acct_rx_packets_i;
+ stats.tx_packets -= rpd->acct_tx_packets_i;
+ stats.rx_bytes -= rpd->acct_rx_bytes_i;
+ stats.tx_bytes -= rpd->acct_tx_bytes_i;
- if (ifreq.stats.p.ppp_ibytes < req->rpd->acct_input_octets)
- req->rpd->acct_input_gigawords++;
- req->rpd->acct_input_octets = ifreq.stats.p.ppp_ibytes;
+ if (stats.rx_bytes < rpd->acct_rx_bytes)
+ req->rpd->acct_input_gigawords++;
+ req->rpd->acct_rx_bytes = stats.rx_packets;
- if (ifreq.stats.p.ppp_obytes < req->rpd->acct_output_octets)
- req->rpd->acct_output_gigawords++;
- req->rpd->acct_output_octets = ifreq.stats.p.ppp_obytes;
+ if (stats.tx_bytes < rpd->acct_tx_bytes)
+ req->rpd->acct_output_gigawords++;
+ req->rpd->acct_tx_bytes = stats.tx_bytes;
+
+ rad_packet_change_int(req->pack, NULL, "Acct-Input-Octets", stats.rx_bytes);
+ rad_packet_change_int(req->pack, NULL, "Acct-Output-Octets", stats.tx_bytes);
+ rad_packet_change_int(req->pack, NULL, "Acct-Input-Packets", stats.rx_packets);
+ rad_packet_change_int(req->pack, NULL, "Acct-Output-Packets", stats.tx_packets);
+ rad_packet_change_int(req->pack, NULL, "Acct-Input-Gigawords", rpd->acct_input_gigawords);
+ rad_packet_change_int(req->pack, NULL, "Acct-Output-Gigawords", rpd->acct_output_gigawords);
- rad_packet_change_int(req->pack, NULL, "Acct-Input-Octets", ifreq.stats.p.ppp_ibytes);
- rad_packet_change_int(req->pack, NULL, "Acct-Output-Octets", ifreq.stats.p.ppp_obytes);
- rad_packet_change_int(req->pack, NULL, "Acct-Input-Packets", ifreq.stats.p.ppp_ipackets);
- rad_packet_change_int(req->pack, NULL, "Acct-Output-Packets", ifreq.stats.p.ppp_opackets);
- rad_packet_change_int(req->pack, NULL, "Acct-Input-Gigawords", req->rpd->acct_input_gigawords);
- rad_packet_change_int(req->pack, NULL, "Acct-Output-Gigawords", req->rpd->acct_output_gigawords);
- }
rad_packet_change_int(req->pack, NULL, "Acct-Session-Time", stop_time - ses->start_time);
}
@@ -233,9 +237,19 @@ int rad_acct_start(struct radius_pd_t *rpd)
int i;
time_t ts;
unsigned int dt;
+ struct rtnl_link_stats stats;
if (!conf_accounting)
return 0;
+
+ if (iplink_get_stats(rpd->ses->ifindex, &stats))
+ log_ppp_warn("radius: failed to get interface statistics\n");
+ else {
+ rpd->acct_rx_packets_i = stats.rx_packets;
+ rpd->acct_tx_packets_i = stats.tx_packets;
+ rpd->acct_rx_bytes_i = stats.rx_bytes;
+ rpd->acct_tx_bytes_i = stats.tx_bytes;
+ }
if (!rpd->acct_req)
rpd->acct_req = rad_req_alloc(rpd, CODE_ACCOUNTING_REQUEST, rpd->ses->username);
diff --git a/accel-pppd/radius/radius_p.h b/accel-pppd/radius/radius_p.h
index 0709351..383be7d 100644
--- a/accel-pppd/radius/radius_p.h
+++ b/accel-pppd/radius/radius_p.h
@@ -24,10 +24,15 @@ struct radius_pd_t
struct rad_req_t *auth_req;
struct rad_req_t *acct_req;
struct triton_timer_t acct_interim_timer;
- uint32_t acct_input_octets;
- uint32_t acct_output_octets;
+
+ uint32_t acct_rx_bytes;
+ uint32_t acct_tx_bytes;
uint32_t acct_input_gigawords;
uint32_t acct_output_gigawords;
+ uint32_t acct_rx_packets_i;
+ uint32_t acct_tx_packets_i;
+ uint32_t acct_rx_bytes_i;
+ uint32_t acct_tx_bytes_i;
struct triton_timer_t session_timeout;