From 490f6384f6a54e388587329c0309a6602d5544e8 Mon Sep 17 00:00:00 2001 From: Kozlov Dmitry Date: Wed, 5 Sep 2012 23:24:51 +0400 Subject: generalize interface statistics gathering --- accel-pppd/CMakeLists.txt | 2 +- accel-pppd/ctrl/ipoe/ipoe.c | 2 +- accel-pppd/extra/CMakeLists.txt | 3 +- accel-pppd/extra/pppd_compat.c | 33 ++-- accel-pppd/extra/sigchld.c | 3 +- accel-pppd/include/ap_session.h | 13 ++ accel-pppd/include/iplink.h | 1 - accel-pppd/include/iputils.h | 1 + accel-pppd/libnetlink/iplink.c | 376 ---------------------------------------- accel-pppd/libnetlink/iplink.h | 19 -- accel-pppd/libnetlink/iputils.c | 376 ++++++++++++++++++++++++++++++++++++++++ accel-pppd/libnetlink/iputils.h | 19 ++ accel-pppd/ppp/ppp_lcp.c | 10 +- accel-pppd/radius/acct.c | 45 +---- accel-pppd/radius/radius.c | 11 +- accel-pppd/radius/radius_p.h | 11 -- accel-pppd/session.c | 46 +++++ 17 files changed, 484 insertions(+), 487 deletions(-) delete mode 120000 accel-pppd/include/iplink.h create mode 120000 accel-pppd/include/iputils.h delete mode 100644 accel-pppd/libnetlink/iplink.c delete mode 100644 accel-pppd/libnetlink/iplink.h create mode 100644 accel-pppd/libnetlink/iputils.c create mode 100644 accel-pppd/libnetlink/iputils.h diff --git a/accel-pppd/CMakeLists.txt b/accel-pppd/CMakeLists.txt index 92d7cfb..7b33e68 100644 --- a/accel-pppd/CMakeLists.txt +++ b/accel-pppd/CMakeLists.txt @@ -76,7 +76,7 @@ ADD_EXECUTABLE(accel-pppd cli/cli.c libnetlink/libnetlink.c - libnetlink/iplink.c + libnetlink/iputils.c libnetlink/genl.c pwdb.c diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index 1ddec37..a871f0f 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -28,7 +28,7 @@ #include "pwdb.h" #include "ipdb.h" -#include "iplink.h" +#include "iputils.h" #include "connlimit.h" #ifdef RADIUS #include "radius.h" diff --git a/accel-pppd/extra/CMakeLists.txt b/accel-pppd/extra/CMakeLists.txt index da1ac54..ea640b1 100644 --- a/accel-pppd/extra/CMakeLists.txt +++ b/accel-pppd/extra/CMakeLists.txt @@ -1,7 +1,8 @@ +ADD_LIBRARY(sigchld SHARED sigchld.c) ADD_LIBRARY(pppd_compat SHARED pppd_compat.c) +TARGET_LINK_LIBRARIES(pppd_compat sigchld) ADD_LIBRARY(ippool SHARED ippool.c) ADD_LIBRARY(ipv6pool SHARED ipv6pool.c) -ADD_LIBRARY(sigchld SHARED sigchld.c) ADD_LIBRARY(chap-secrets SHARED chap-secrets.c) ADD_LIBRARY(logwtmp SHARED logwtmp.c) TARGET_LINK_LIBRARIES(logwtmp util) diff --git a/accel-pppd/extra/pppd_compat.c b/accel-pppd/extra/pppd_compat.c index 71934ab..59d052c 100644 --- a/accel-pppd/extra/pppd_compat.c +++ b/accel-pppd/extra/pppd_compat.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include "linux_ppp.h" @@ -18,7 +19,7 @@ #include "log.h" #include "utils.h" #include "sigchld.h" -#include "iplink.h" +#include "iputils.h" #ifdef RADIUS #include "radius.h" @@ -48,8 +49,6 @@ struct pppd_compat_pd_t #endif int started:1; int res; - int bytes_sent; - int bytes_rcvd; in_addr_t ipv4_addr; in_addr_t ipv4_peer_addr; }; @@ -226,23 +225,6 @@ static void ev_ses_started(struct ap_session *ses) pd->started = 1; } -static void ev_ses_finishing(struct ap_session *ses) -{ - struct rtnl_link_stats stats; - struct pppd_compat_pd_t *pd = find_pd(ses); - - if (!pd) - return; - - if (iplink_get_stats(ses->ifindex, &stats)) { - log_ppp_error("pppd_compat: failed to get interface statistics\n"); - return; - } - - pd->bytes_sent = stats.tx_bytes; - pd->bytes_rcvd = stats.rx_bytes; -} - static void ev_ses_finished(struct ap_session *ses) { pid_t pid; @@ -498,12 +480,18 @@ static void fill_argv(char **argv, struct pppd_compat_pd_t *pd, char *path) static void fill_env(char **env, struct pppd_compat_pd_t *pd) { + struct ap_session *ses = pd->ses; + uint64_t tx_bytes, rx_bytes; + + tx_bytes = (uint64_t)ses->acct_tx_bytes + ses->acct_output_gigawords*4294967296llu; + rx_bytes = (uint64_t)ses->acct_rx_bytes + ses->acct_input_gigawords*4294967296llu; + snprintf(env[0], 64, "PEERNAME=%s", pd->ses->username); if (pd->ses->stop_time && env[1]) { snprintf(env[1], 24, "CONNECT_TIME=%lu", pd->ses->stop_time - pd->ses->start_time); - snprintf(env[2], 24, "BYTES_SENT=%u", pd->bytes_sent); - snprintf(env[3], 24, "BYTES_RCVD=%u", pd->bytes_rcvd); + snprintf(env[2], 24, "BYTES_SENT=%" PRIu64, tx_bytes); + snprintf(env[3], 24, "BYTES_RCVD=%" PRIu64, rx_bytes); } } @@ -538,7 +526,6 @@ static void init(void) triton_event_register_handler(EV_SES_STARTING, (triton_event_func)ev_ses_starting); triton_event_register_handler(EV_SES_PRE_UP, (triton_event_func)ev_ses_pre_up); triton_event_register_handler(EV_SES_STARTED, (triton_event_func)ev_ses_started); - triton_event_register_handler(EV_SES_FINISHING, (triton_event_func)ev_ses_finishing); triton_event_register_handler(EV_SES_PRE_FINISHED, (triton_event_func)ev_ses_finished); #ifdef RADIUS if (triton_module_loaded("radius")) { diff --git a/accel-pppd/extra/sigchld.c b/accel-pppd/extra/sigchld.c index 8f1a979..d6b0df5 100644 --- a/accel-pppd/extra/sigchld.c +++ b/accel-pppd/extra/sigchld.c @@ -109,10 +109,9 @@ void __export sigchld_unlock() pthread_mutex_unlock(&handlers_lock); } -static void init(void) +static void __init init(void) { if (pthread_create(&sigchld_thr, NULL, sigchld_thread, NULL)) log_emerg("sigchld: pthread_create: %s\n", strerror(errno)); } -DEFINE_INIT(100, init); \ No newline at end of file diff --git a/accel-pppd/include/ap_session.h b/accel-pppd/include/ap_session.h index 95f0ea2..82654f8 100644 --- a/accel-pppd/include/ap_session.h +++ b/accel-pppd/include/ap_session.h @@ -35,6 +35,7 @@ struct ap_session; struct backup_data; +struct rtnl_link_stats; struct ap_ctrl { @@ -70,6 +71,7 @@ struct ap_session char sessionid[AP_SESSIONID_LEN+1]; time_t start_time; time_t stop_time; + time_t idle_time; char *username; struct ipv4db_item_t *ipv4; struct ipv6db_item_t *ipv6; @@ -87,6 +89,15 @@ struct ap_session int terminate_cause; struct list_head pd_list; + + 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 ap_session_stat @@ -114,6 +125,8 @@ void ap_session_activate(struct ap_session *ses); void ap_session_ifup(struct ap_session *ses); void ap_session_ifdown(struct ap_session *ses); +int ap_session_read_stats(struct ap_session *ses, struct rtnl_link_stats *stats); + void ap_shutdown_soft(void (*cb)(void)); #endif diff --git a/accel-pppd/include/iplink.h b/accel-pppd/include/iplink.h deleted file mode 120000 index 7f0f09d..0000000 --- a/accel-pppd/include/iplink.h +++ /dev/null @@ -1 +0,0 @@ -../libnetlink/iplink.h \ No newline at end of file diff --git a/accel-pppd/include/iputils.h b/accel-pppd/include/iputils.h new file mode 120000 index 0000000..c91d11c --- /dev/null +++ b/accel-pppd/include/iputils.h @@ -0,0 +1 @@ +../libnetlink/iputils.h \ No newline at end of file diff --git a/accel-pppd/libnetlink/iplink.c b/accel-pppd/libnetlink/iplink.c deleted file mode 100644 index 4b85afe..0000000 --- a/accel-pppd/libnetlink/iplink.c +++ /dev/null @@ -1,376 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include -//#include -//#include -#include - -#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); - struct rtattr *tb[IFLA_MAX + 1]; - struct arg *a = arg; - - if (n->nlmsg_type != RTM_NEWLINK) - return 0; - - if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*ifi))) - return -1; - - memset(tb, 0, sizeof(tb)); - parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); - - if (tb[IFLA_IFNAME] == NULL) - return 0; - - //printf("%i %s\n", ifi->ifi_index, RTA_DATA(tb[IFLA_IFNAME])); - - return a->func(ifi->ifi_index, ifi->ifi_flags, RTA_DATA(tb[IFLA_IFNAME]), a->arg); -} - -int __export iplink_list(iplink_list_func func, void *arg) -{ - struct rtnl_handle rth; - struct arg a = { .func = func, .arg = arg }; - - if (rtnl_open(&rth, 0)) { - log_emerg("iplink: cannot open rtnetlink\n"); - return -1; - } - - if (rtnl_wilddump_request(&rth, AF_PACKET, RTM_GETLINK) < 0) { - log_emerg("iplink: cannot send dump request\n"); - goto out_err; - } - - if (rtnl_dump_filter(&rth, store_nlmsg, &a, NULL, NULL) < 0) { - log_emerg("iplink: dump terminated\n"); - goto out_err; - } - - rtnl_close(&rth); - - return 0; - -out_err: - rtnl_close(&rth); - - 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; -} - -int __export ipaddr_add(int ifindex, in_addr_t addr, int mask) -{ - struct ipaddr_req { - struct nlmsghdr n; - struct ifaddrmsg i; - char buf[1024]; - } req; - - if (!rth) - open_rth(); - - if (!rth) - return -1; - - memset(&req, 0, sizeof(req) - 1024); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; - req.n.nlmsg_type = RTM_NEWADDR; - req.i.ifa_family = AF_INET; - req.i.ifa_index = ifindex; - req.i.ifa_prefixlen = mask; - - addattr32(&req.n, sizeof(req), IFA_LOCAL, addr); - - if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) - return -1; - - return 0; -} - -int __export ipaddr_del(int ifindex, in_addr_t addr) -{ - struct ipaddr_req { - struct nlmsghdr n; - struct ifaddrmsg i; - char buf[1024]; - } req; - - if (!rth) - open_rth(); - - if (!rth) - return -1; - - memset(&req, 0, sizeof(req) - 1024); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_DELADDR; - req.i.ifa_family = AF_INET; - req.i.ifa_index = ifindex; - req.i.ifa_prefixlen = 32; - - addattr32(&req.n, sizeof(req), IFA_LOCAL, addr); - - if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) - return -1; - - return 0; -} - -int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst) -{ - struct ipaddr_req { - struct nlmsghdr n; - struct rtmsg i; - char buf[1024]; - } req; - - if (!rth) - open_rth(); - - if (!rth) - return -1; - - memset(&req, 0, sizeof(req) - 1024); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; - req.n.nlmsg_type = RTM_NEWROUTE; - req.i.rtm_family = AF_INET; - req.i.rtm_table = RT_TABLE_MAIN; - req.i.rtm_scope = RT_SCOPE_LINK; - req.i.rtm_protocol = RTPROT_BOOT; - req.i.rtm_type = RTN_UNICAST; - req.i.rtm_dst_len = 32; - - addattr32(&req.n, sizeof(req), RTA_PREFSRC, src); - addattr32(&req.n, sizeof(req), RTA_DST, dst); - addattr32(&req.n, sizeof(req), RTA_OIF, ifindex); - - if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) - return -1; - - return 0; -} - -int __export iproute_del(int ifindex, in_addr_t dst) -{ - struct ipaddr_req { - struct nlmsghdr n; - struct rtmsg i; - char buf[1024]; - } req; - - if (!rth) - open_rth(); - - if (!rth) - return -1; - - memset(&req, 0, sizeof(req) - 1024); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - req.n.nlmsg_type = RTM_DELROUTE; - req.i.rtm_family = AF_INET; - req.i.rtm_table = RT_TABLE_MAIN; - req.i.rtm_scope = RT_SCOPE_LINK; - req.i.rtm_protocol = RTPROT_BOOT; - req.i.rtm_type = RTN_UNICAST; - req.i.rtm_dst_len = 32; - - addattr32(&req.n, sizeof(req), RTA_DST, dst); - addattr32(&req.n, sizeof(req), RTA_OIF, ifindex); - - if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) - return -1; - - return 0; -} - -int __export iprule_add(uint32_t addr, int table) -{ - struct ipaddr_req { - struct nlmsghdr n; - struct rtmsg i; - char buf[1024]; - } req; - - if (!rth) - open_rth(); - - if (!rth) - return -1; - - memset(&req, 0, sizeof(req) - 1024); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_NEWRULE; - req.i.rtm_family = AF_INET; - req.i.rtm_table = table < 256 ? table : RT_TABLE_UNSPEC; - req.i.rtm_scope = RT_SCOPE_UNIVERSE; - req.i.rtm_protocol = RTPROT_BOOT; - req.i.rtm_type = RTN_UNICAST; - req.i.rtm_src_len = 32; - - addattr32(&req.n, sizeof(req), FRA_SRC, addr); - if (table >= 256) - addattr32(&req.n, sizeof(req), FRA_TABLE, table); - - if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) - return -1; - - return 0; -} - -int __export iprule_del(uint32_t addr, int table) -{ - struct ipaddr_req { - struct nlmsghdr n; - struct rtmsg i; - char buf[1024]; - } req; - - if (!rth) - open_rth(); - - if (!rth) - return -1; - - memset(&req, 0, sizeof(req) - 1024); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_DELRULE; - req.i.rtm_family = AF_INET; - req.i.rtm_table = table < 256 ? table : RT_TABLE_UNSPEC; - req.i.rtm_scope = RT_SCOPE_UNIVERSE; - req.i.rtm_protocol = RTPROT_BOOT; - req.i.rtm_type = RTN_UNICAST; - req.i.rtm_src_len = 32; - - addattr32(&req.n, sizeof(req), FRA_SRC, addr); - if (table >= 256) - addattr32(&req.n, sizeof(req), FRA_TABLE, table); - - if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) - 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 deleted file mode 100644 index f912434..0000000 --- a/accel-pppd/libnetlink/iplink.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __IPLINK_H -#define __IPLINK_H - -#include - -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); - -int ipaddr_add(int ifindex, in_addr_t addr, int mask); -int ipaddr_del(int ifindex, in_addr_t addr); - -int iproute_add(int ifindex, in_addr_t src, in_addr_t dst); -int iproute_del(int ifindex, in_addr_t dst); - -int iprule_add(uint32_t addr, int table); -int iprule_del(uint32_t addr, int table); -#endif diff --git a/accel-pppd/libnetlink/iputils.c b/accel-pppd/libnetlink/iputils.c new file mode 100644 index 0000000..0ae4b04 --- /dev/null +++ b/accel-pppd/libnetlink/iputils.c @@ -0,0 +1,376 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +//#include +//#include +#include + +#include "triton.h" +#include "log.h" + +#include "libnetlink.h" +#include "iputils.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); + struct rtattr *tb[IFLA_MAX + 1]; + struct arg *a = arg; + + if (n->nlmsg_type != RTM_NEWLINK) + return 0; + + if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*ifi))) + return -1; + + memset(tb, 0, sizeof(tb)); + parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); + + if (tb[IFLA_IFNAME] == NULL) + return 0; + + //printf("%i %s\n", ifi->ifi_index, RTA_DATA(tb[IFLA_IFNAME])); + + return a->func(ifi->ifi_index, ifi->ifi_flags, RTA_DATA(tb[IFLA_IFNAME]), a->arg); +} + +int __export iplink_list(iplink_list_func func, void *arg) +{ + struct rtnl_handle rth; + struct arg a = { .func = func, .arg = arg }; + + if (rtnl_open(&rth, 0)) { + log_emerg("iplink: cannot open rtnetlink\n"); + return -1; + } + + if (rtnl_wilddump_request(&rth, AF_PACKET, RTM_GETLINK) < 0) { + log_emerg("iplink: cannot send dump request\n"); + goto out_err; + } + + if (rtnl_dump_filter(&rth, store_nlmsg, &a, NULL, NULL) < 0) { + log_emerg("iplink: dump terminated\n"); + goto out_err; + } + + rtnl_close(&rth); + + return 0; + +out_err: + rtnl_close(&rth); + + 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; +} + +int __export ipaddr_add(int ifindex, in_addr_t addr, int mask) +{ + struct ipaddr_req { + struct nlmsghdr n; + struct ifaddrmsg i; + char buf[1024]; + } req; + + if (!rth) + open_rth(); + + if (!rth) + return -1; + + memset(&req, 0, sizeof(req) - 1024); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; + req.n.nlmsg_type = RTM_NEWADDR; + req.i.ifa_family = AF_INET; + req.i.ifa_index = ifindex; + req.i.ifa_prefixlen = mask; + + addattr32(&req.n, sizeof(req), IFA_LOCAL, addr); + + if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) + return -1; + + return 0; +} + +int __export ipaddr_del(int ifindex, in_addr_t addr) +{ + struct ipaddr_req { + struct nlmsghdr n; + struct ifaddrmsg i; + char buf[1024]; + } req; + + if (!rth) + open_rth(); + + if (!rth) + return -1; + + memset(&req, 0, sizeof(req) - 1024); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_DELADDR; + req.i.ifa_family = AF_INET; + req.i.ifa_index = ifindex; + req.i.ifa_prefixlen = 32; + + addattr32(&req.n, sizeof(req), IFA_LOCAL, addr); + + if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) + return -1; + + return 0; +} + +int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst) +{ + struct ipaddr_req { + struct nlmsghdr n; + struct rtmsg i; + char buf[1024]; + } req; + + if (!rth) + open_rth(); + + if (!rth) + return -1; + + memset(&req, 0, sizeof(req) - 1024); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; + req.n.nlmsg_type = RTM_NEWROUTE; + req.i.rtm_family = AF_INET; + req.i.rtm_table = RT_TABLE_MAIN; + req.i.rtm_scope = RT_SCOPE_LINK; + req.i.rtm_protocol = RTPROT_BOOT; + req.i.rtm_type = RTN_UNICAST; + req.i.rtm_dst_len = 32; + + addattr32(&req.n, sizeof(req), RTA_PREFSRC, src); + addattr32(&req.n, sizeof(req), RTA_DST, dst); + addattr32(&req.n, sizeof(req), RTA_OIF, ifindex); + + if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) + return -1; + + return 0; +} + +int __export iproute_del(int ifindex, in_addr_t dst) +{ + struct ipaddr_req { + struct nlmsghdr n; + struct rtmsg i; + char buf[1024]; + } req; + + if (!rth) + open_rth(); + + if (!rth) + return -1; + + memset(&req, 0, sizeof(req) - 1024); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + req.n.nlmsg_type = RTM_DELROUTE; + req.i.rtm_family = AF_INET; + req.i.rtm_table = RT_TABLE_MAIN; + req.i.rtm_scope = RT_SCOPE_LINK; + req.i.rtm_protocol = RTPROT_BOOT; + req.i.rtm_type = RTN_UNICAST; + req.i.rtm_dst_len = 32; + + addattr32(&req.n, sizeof(req), RTA_DST, dst); + addattr32(&req.n, sizeof(req), RTA_OIF, ifindex); + + if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) + return -1; + + return 0; +} + +int __export iprule_add(uint32_t addr, int table) +{ + struct ipaddr_req { + struct nlmsghdr n; + struct rtmsg i; + char buf[1024]; + } req; + + if (!rth) + open_rth(); + + if (!rth) + return -1; + + memset(&req, 0, sizeof(req) - 1024); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_NEWRULE; + req.i.rtm_family = AF_INET; + req.i.rtm_table = table < 256 ? table : RT_TABLE_UNSPEC; + req.i.rtm_scope = RT_SCOPE_UNIVERSE; + req.i.rtm_protocol = RTPROT_BOOT; + req.i.rtm_type = RTN_UNICAST; + req.i.rtm_src_len = 32; + + addattr32(&req.n, sizeof(req), FRA_SRC, addr); + if (table >= 256) + addattr32(&req.n, sizeof(req), FRA_TABLE, table); + + if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) + return -1; + + return 0; +} + +int __export iprule_del(uint32_t addr, int table) +{ + struct ipaddr_req { + struct nlmsghdr n; + struct rtmsg i; + char buf[1024]; + } req; + + if (!rth) + open_rth(); + + if (!rth) + return -1; + + memset(&req, 0, sizeof(req) - 1024); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_DELRULE; + req.i.rtm_family = AF_INET; + req.i.rtm_table = table < 256 ? table : RT_TABLE_UNSPEC; + req.i.rtm_scope = RT_SCOPE_UNIVERSE; + req.i.rtm_protocol = RTPROT_BOOT; + req.i.rtm_type = RTN_UNICAST; + req.i.rtm_src_len = 32; + + addattr32(&req.n, sizeof(req), FRA_SRC, addr); + if (table >= 256) + addattr32(&req.n, sizeof(req), FRA_TABLE, table); + + if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) + 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/iputils.h b/accel-pppd/libnetlink/iputils.h new file mode 100644 index 0000000..f912434 --- /dev/null +++ b/accel-pppd/libnetlink/iputils.h @@ -0,0 +1,19 @@ +#ifndef __IPLINK_H +#define __IPLINK_H + +#include + +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); + +int ipaddr_add(int ifindex, in_addr_t addr, int mask); +int ipaddr_del(int ifindex, in_addr_t addr); + +int iproute_add(int ifindex, in_addr_t src, in_addr_t dst); +int iproute_del(int ifindex, in_addr_t dst); + +int iprule_add(uint32_t addr, int table); +int iprule_del(uint32_t addr, int table); +#endif diff --git a/accel-pppd/ppp/ppp_lcp.c b/accel-pppd/ppp/ppp_lcp.c index 1b47cad..2d1e195 100644 --- a/accel-pppd/ppp/ppp_lcp.c +++ b/accel-pppd/ppp/ppp_lcp.c @@ -12,7 +12,7 @@ #include "ppp.h" #include "ppp_lcp.h" #include "events.h" -#include "iplink.h" +#include "iputils.h" #include "memdebug.h" @@ -656,15 +656,15 @@ static void send_echo_request(struct triton_timer_t *t) ++lcp->echo_sent; + ap_session_read_stats(&lcp->ppp->ses, &stats); + if (conf_echo_timeout) { if (lcp->echo_sent == 2) { - if (iplink_get_stats(lcp->ppp->ses.ifindex, &stats) == 0) - lcp->last_ipackets = stats.rx_packets; - + lcp->last_ipackets = stats.rx_packets; time(&lcp->last_echo_ts); } else if (lcp->echo_sent > 2) { time(&ts); - if (iplink_get_stats(lcp->ppp->ses.ifindex, &stats) == 0 && lcp->last_ipackets != stats.rx_packets) { + if (lcp->last_ipackets != stats.rx_packets) { lcp->echo_sent = 1; lcp_update_echo_timer(lcp); } else if (ts - lcp->last_echo_ts > conf_echo_timeout) { diff --git a/accel-pppd/radius/acct.c b/accel-pppd/radius/acct.c index ab71c45..81145cd 100644 --- a/accel-pppd/radius/acct.c +++ b/accel-pppd/radius/acct.c @@ -12,7 +12,7 @@ #include "log.h" #include "backup.h" #include "ap_session_backup.h" -#include "iplink.h" +#include "iputils.h" #include "radius_p.h" @@ -21,33 +21,6 @@ #define STAT_UPDATE_INTERVAL (10 * 60 * 1000) #define INTERIM_SAFE_TIME 10 -int rad_read_stats(struct radius_pd_t *rpd, struct rtnl_link_stats *stats) -{ - int r; - - if (iplink_get_stats(rpd->ses->ifindex, stats)) { - log_ppp_warn("radius: failed to get interface statistics\n"); - return -1; - } - - 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; - - r = stats->rx_bytes != rpd->acct_rx_bytes || stats->tx_bytes < rpd->acct_tx_bytes; - - if (stats->rx_bytes < rpd->acct_rx_bytes) - rpd->acct_input_gigawords++; - rpd->acct_rx_bytes = stats->rx_packets; - - if (stats->tx_bytes < rpd->acct_tx_bytes) - rpd->acct_output_gigawords++; - rpd->acct_tx_bytes = stats->tx_bytes; - - return r; -} - static int req_set_RA(struct rad_req_t *req, const char *secret) { MD5_CTX ctx; @@ -75,13 +48,13 @@ static void req_set_stat(struct rad_req_t *req, struct ap_session *ses) else time(&stop_time); - if (rad_read_stats(rpd, &stats) > 0) { + if (ap_session_read_stats(ses, &stats) == 0) { 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-Gigawords", rpd->ses->acct_input_gigawords); + rad_packet_change_int(req->pack, NULL, "Acct-Output-Gigawords", rpd->ses->acct_output_gigawords); } rad_packet_change_int(req->pack, NULL, "Acct-Session-Time", stop_time - ses->start_time); @@ -248,20 +221,10 @@ 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.c b/accel-pppd/radius/radius.c index 5f5d0ba..67c18e6 100644 --- a/accel-pppd/radius/radius.c +++ b/accel-pppd/radius/radius.c @@ -235,19 +235,18 @@ static void session_timeout(struct triton_timer_t *t) static void idle_timeout(struct triton_timer_t *t) { struct radius_pd_t *rpd = container_of(t, typeof(*rpd), idle_timeout); - struct rtnl_link_stats stats; + time_t tt; if (rpd->ses->stop_time) return; - rad_read_stats(rpd, &stats); + time(&tt); - if (stats.rx_packets == rpd->acct_rx_packets && stats.tx_packets == rpd->acct_tx_packets) { + ap_session_read_stats(rpd->ses, NULL); + + if (tt - rpd->ses->idle_time > t->period / 1000) { log_ppp_msg("radius: idle timed out\n"); ap_session_terminate(rpd->ses, TERM_IDLE_TIMEOUT, 0); - } else { - rpd->acct_rx_packets = stats.rx_packets; - rpd->acct_tx_packets = stats.tx_packets; } } diff --git a/accel-pppd/radius/radius_p.h b/accel-pppd/radius/radius_p.h index 8a4d27a..4a17202 100644 --- a/accel-pppd/radius/radius_p.h +++ b/accel-pppd/radius/radius_p.h @@ -25,17 +25,6 @@ struct radius_pd_t struct rad_req_t *acct_req; struct triton_timer_t acct_interim_timer; - uint32_t acct_rx_bytes; - uint32_t acct_tx_bytes; - uint32_t acct_rx_packets; - uint32_t acct_tx_packets; - 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; struct triton_timer_t idle_timeout; diff --git a/accel-pppd/session.c b/accel-pppd/session.c index 0ca115c..41c5d69 100644 --- a/accel-pppd/session.c +++ b/accel-pppd/session.c @@ -18,6 +18,7 @@ #include "events.h" #include "ap_session.h" #include "backup.h" +#include "iputils.h" #include "spinlock.h" #include "mempool.h" #include "memdebug.h" @@ -53,6 +54,7 @@ void __export ap_session_init(struct ap_session *ses) int __export ap_session_starting(struct ap_session *ses) { struct ifreq ifr; + struct rtnl_link_stats stats; if (ses->ifindex == -1) { memset(&ifr, 0, sizeof(ifr)); @@ -64,9 +66,19 @@ int __export ap_session_starting(struct ap_session *ses) } ses->ifindex = ifr.ifr_ifindex; } + + if (iplink_get_stats(ses->ifindex, &stats)) + log_ppp_warn("failed to get interface statistics\n"); + else { + ses->acct_rx_packets_i = stats.rx_packets; + ses->acct_tx_packets_i = stats.tx_packets; + ses->acct_rx_bytes_i = stats.rx_bytes; + ses->acct_tx_bytes_i = stats.tx_bytes; + } if (ses->state != AP_STATE_RESTORE) { ses->start_time = time(NULL); + ses->idle_time = ses->start_time; generate_sessionid(ses); ses->state = AP_STATE_STARTING; @@ -215,6 +227,40 @@ static void generate_sessionid(struct ap_session *ses) sprintf(ses->sessionid, "%016llx", sid); } +int __export ap_session_read_stats(struct ap_session *ses, struct rtnl_link_stats *stats) +{ + struct rtnl_link_stats lstats; + time_t t; + + if (!stats) + stats = &lstats; + + time(&t); + + if (iplink_get_stats(ses->ifindex, stats)) { + log_ppp_warn("failed to get interface statistics\n"); + return -1; + } + + stats->rx_packets -= ses->acct_rx_packets_i; + stats->tx_packets -= ses->acct_tx_packets_i; + stats->rx_bytes -= ses->acct_rx_bytes_i; + stats->tx_bytes -= ses->acct_tx_bytes_i; + + if (stats->rx_bytes != ses->acct_rx_bytes || stats->tx_bytes != ses->acct_tx_bytes) + time(&ses->idle_time); + + if (stats->rx_bytes < ses->acct_rx_bytes) + ses->acct_input_gigawords++; + ses->acct_rx_bytes = stats->rx_bytes; + + if (stats->tx_bytes < ses->acct_tx_bytes) + ses->acct_output_gigawords++; + ses->acct_tx_bytes = stats->tx_bytes; + + return 0; +} + static void save_seq(void) { FILE *f; -- cgit v1.2.3