diff options
author | Kozlov Dmitry <xeb@mail.ru> | 2012-07-11 18:47:08 +0400 |
---|---|---|
committer | Kozlov Dmitry <xeb@mail.ru> | 2012-07-11 18:47:08 +0400 |
commit | b2e106f8778fd834e0518cc6c0704d7d6b50875e (patch) | |
tree | e6a7dcd7f80b4cb52dd59a2cd087f4c30c357b41 | |
parent | 07c57d04f2c585f4e3ba37bf61c3d14f9d40cd7d (diff) | |
download | accel-ppp-xebd-b2e106f8778fd834e0518cc6c0704d7d6b50875e.tar.gz accel-ppp-xebd-b2e106f8778fd834e0518cc6c0704d7d6b50875e.zip |
radius: fetch interface statistics via netlink
-rw-r--r-- | accel-pppd/libnetlink/iplink.c | 93 | ||||
-rw-r--r-- | accel-pppd/libnetlink/iplink.h | 3 | ||||
-rw-r--r-- | accel-pppd/radius/acct.c | 58 | ||||
-rw-r--r-- | accel-pppd/radius/radius_p.h | 9 |
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; |