From 28c47fa1ccf6a6550f335046349b1716745a2189 Mon Sep 17 00:00:00 2001 From: Kozlov Dmitry Date: Wed, 5 Sep 2012 21:56:53 +0400 Subject: gather interface statistics via netlink --- accel-pppd/CMakeLists.txt | 4 + accel-pppd/extra/CMakeLists.txt | 1 + accel-pppd/extra/pppd_compat.c | 34 +- accel-pppd/extra/sigchld.c | 3 +- accel-pppd/ppp/ppp.c | 42 +++ accel-pppd/ppp/ppp.h | 12 + accel-pppd/ppp/ppp_lcp.c | 19 +- accel-pppd/radius/acct.c | 31 +- accel-pppd/radius/radius_p.h | 5 - accel-pppd/shaper/CMakeLists.txt | 2 +- accel-pppd/shaper/libnetlink.c | 692 --------------------------------------- accel-pppd/shaper/libnetlink.h | 118 ------- 12 files changed, 83 insertions(+), 880 deletions(-) delete mode 100644 accel-pppd/shaper/libnetlink.c delete mode 100644 accel-pppd/shaper/libnetlink.h (limited to 'accel-pppd') diff --git a/accel-pppd/CMakeLists.txt b/accel-pppd/CMakeLists.txt index 1db4137..fb44b50 100644 --- a/accel-pppd/CMakeLists.txt +++ b/accel-pppd/CMakeLists.txt @@ -65,6 +65,10 @@ ADD_EXECUTABLE(accel-pppd cli/tcp.c cli/cli.c + libnetlink/libnetlink.c + libnetlink/iputils.c + libnetlink/genl.c + pwdb.c ipdb.c diff --git a/accel-pppd/extra/CMakeLists.txt b/accel-pppd/extra/CMakeLists.txt index 365f542..e7b9f07 100644 --- a/accel-pppd/extra/CMakeLists.txt +++ b/accel-pppd/extra/CMakeLists.txt @@ -1,4 +1,5 @@ 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) diff --git a/accel-pppd/extra/pppd_compat.c b/accel-pppd/extra/pppd_compat.c index d89a6a6..d4de18f 100644 --- a/accel-pppd/extra/pppd_compat.c +++ b/accel-pppd/extra/pppd_compat.c @@ -47,8 +47,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; }; @@ -224,27 +222,6 @@ static void ev_ppp_started(struct ppp_t *ppp) pd->started = 1; } -static void ev_ppp_finishing(struct ppp_t *ppp) -{ - struct ifpppstatsreq ifreq; - struct pppd_compat_pd_t *pd = find_pd(ppp); - - if (!pd) - return; - - memset(&ifreq, 0, sizeof(ifreq)); - ifreq.stats_ptr = (void *)&ifreq.stats; - strcpy(ifreq.ifr__name, ppp->ifname); - - if (ioctl(sock_fd, SIOCGPPPSTATS, &ifreq)) { - log_ppp_error("pppd_compat: failed to get ppp statistics: %s\n", strerror(errno)); - return; - } - - pd->bytes_sent = ifreq.stats.p.ppp_obytes; - pd->bytes_rcvd = ifreq.stats.p.ppp_ibytes; -} - static void ev_ppp_finished(struct ppp_t *ppp) { pid_t pid; @@ -497,12 +474,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 ppp_t *ppp = pd->ppp; + uint64_t tx_bytes, rx_bytes; + + tx_bytes = (uint64_t)ppp->acct_tx_bytes + ppp->acct_output_gigawords*4294967296llu; + rx_bytes = (uint64_t)ppp->acct_rx_bytes + ppp->acct_input_gigawords*4294967296llu; + snprintf(env[0], 64, "PEERNAME=%s", pd->ppp->username); if (pd->ppp->stop_time && env[1]) { snprintf(env[1], 24, "CONNECT_TIME=%lu", pd->ppp->stop_time - pd->ppp->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=%llu", (long long unsigned)tx_bytes); + snprintf(env[3], 24, "BYTES_RCVD=%llu", (long long unsigned)rx_bytes); } } @@ -537,7 +520,6 @@ static void init(void) triton_event_register_handler(EV_PPP_STARTING, (triton_event_func)ev_ppp_starting); triton_event_register_handler(EV_PPP_PRE_UP, (triton_event_func)ev_ppp_pre_up); triton_event_register_handler(EV_PPP_STARTED, (triton_event_func)ev_ppp_started); - triton_event_register_handler(EV_PPP_FINISHING, (triton_event_func)ev_ppp_finishing); triton_event_register_handler(EV_PPP_PRE_FINISHED, (triton_event_func)ev_ppp_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/ppp/ppp.c b/accel-pppd/ppp/ppp.c index b8feaa1..3e1386b 100644 --- a/accel-pppd/ppp/ppp.c +++ b/accel-pppd/ppp/ppp.c @@ -108,6 +108,7 @@ static void generate_sessionid(struct ppp_t *ppp) int __export establish_ppp(struct ppp_t *ppp) { + struct rtnl_link_stats stats; struct ifreq ifr; struct pppunit_cache *uc = NULL; @@ -188,6 +189,17 @@ int __export establish_ppp(struct ppp_t *ppp) } ppp->ifindex = ifr.ifr_ifindex; + if (uc) { + if (iplink_get_stats(ppp->ifindex, &stats)) + log_ppp_warn("ppp: failed to get interface statistics\n"); + else { + ppp->acct_rx_packets_i = stats.rx_packets; + ppp->acct_tx_packets_i = stats.tx_packets; + ppp->acct_rx_bytes_i = stats.rx_bytes; + ppp->acct_tx_bytes_i = stats.tx_bytes; + } + } + log_ppp_info1("connect: %s <--> %s(%s)\n", ppp->ifname, ppp->ctrl->name, ppp->chan_name); init_layers(ppp); @@ -239,6 +251,8 @@ static void destablish_ppp(struct ppp_t *ppp) { struct pppunit_cache *uc; + ppp_read_stats(ppp, NULL); + triton_event_fire(EV_PPP_PRE_FINISHED, ppp); pthread_rwlock_wrlock(&ppp_lock); @@ -732,6 +746,34 @@ static void save_seq(void) } } +int __export ppp_read_stats(struct ppp_t *ppp, struct rtnl_link_stats *stats) +{ + struct rtnl_link_stats lstats; + + if (!stats) + stats = &lstats; + + if (iplink_get_stats(ppp->ifindex, stats)) { + log_ppp_warn("ppp: failed to get interface statistics\n"); + return -1; + } + + stats->rx_packets -= ppp->acct_rx_packets_i; + stats->tx_packets -= ppp->acct_tx_packets_i; + stats->rx_bytes -= ppp->acct_rx_bytes_i; + stats->tx_bytes -= ppp->acct_tx_bytes_i; + + if (stats->rx_bytes < ppp->acct_rx_bytes) + ppp->acct_input_gigawords++; + ppp->acct_rx_bytes = stats->rx_bytes; + + if (stats->tx_bytes < ppp->acct_tx_bytes) + ppp->acct_output_gigawords++; + ppp->acct_tx_bytes = stats->tx_bytes; + + return 0; +} + static void load_config(void) { char *opt; diff --git a/accel-pppd/ppp/ppp.h b/accel-pppd/ppp/ppp.h index ca97d5a..5e47607 100644 --- a/accel-pppd/ppp/ppp.h +++ b/accel-pppd/ppp/ppp.h @@ -8,6 +8,7 @@ #include "triton.h" #include "list.h" +#include "iputils.h" /* * Packet header = Code, id, length. @@ -134,6 +135,15 @@ struct ppp_t struct ppp_lcp_t *lcp; 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 ppp_layer_t; @@ -200,6 +210,8 @@ int ppp_register_layer(const char *name, struct ppp_layer_t *); void ppp_unregister_layer(struct ppp_layer_t *); struct ppp_layer_data_t *ppp_find_layer_data(struct ppp_t *, struct ppp_layer_t *); +int ppp_read_stats(struct ppp_t *ppp, struct rtnl_link_stats *stats); + extern int ppp_shutdown; void ppp_shutdown_soft(void); diff --git a/accel-pppd/ppp/ppp_lcp.c b/accel-pppd/ppp/ppp_lcp.c index e61738c..9b56ed1 100644 --- a/accel-pppd/ppp/ppp_lcp.c +++ b/accel-pppd/ppp/ppp_lcp.c @@ -638,9 +638,9 @@ static void send_echo_reply(struct ppp_lcp_t *lcp) static void send_echo_request(struct triton_timer_t *t) { struct ppp_lcp_t *lcp = container_of(t, typeof(*lcp), echo_timer); - struct ifpppstatsreq ifreq; - int f = 0; + int f = 0, r; time_t ts; + struct rtnl_link_stats stats; struct lcp_echo_req_t { struct lcp_hdr_t hdr; @@ -655,22 +655,15 @@ static void send_echo_request(struct triton_timer_t *t) ++lcp->echo_sent; + r = ppp_read_stats(lcp->ppp, &stats); + if (conf_echo_timeout) { if (lcp->echo_sent == 2) { - memset(&ifreq, 0, sizeof(ifreq)); - ifreq.stats_ptr = (void *)&ifreq.stats; - strcpy(ifreq.ifr__name, lcp->ppp->ifname); - - if (ioctl(sock_fd, SIOCGPPPSTATS, &ifreq) == 0) - lcp->last_ipackets = ifreq.stats.p.ppp_ipackets; - + lcp->last_ipackets = stats.rx_packets; time(&lcp->last_echo_ts); } else if (lcp->echo_sent > 2) { time(&ts); - memset(&ifreq, 0, sizeof(ifreq)); - ifreq.stats_ptr = (void *)&ifreq.stats; - strcpy(ifreq.ifr__name, lcp->ppp->ifname); - if (ioctl(sock_fd, SIOCGPPPSTATS, &ifreq) == 0 && lcp->last_ipackets != ifreq.stats.p.ppp_ipackets) { + if (r == 0 && 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 76ad329..9a832a9 100644 --- a/accel-pppd/radius/acct.c +++ b/accel-pppd/radius/acct.c @@ -34,7 +34,7 @@ static int req_set_RA(struct rad_req_t *req, const char *secret) static void req_set_stat(struct rad_req_t *req, struct ppp_t *ppp) { - struct ifpppstatsreq ifreq; + struct rtnl_link_stats stats; time_t stop_time; if (ppp->stop_time) @@ -42,29 +42,14 @@ static void req_set_stat(struct rad_req_t *req, struct ppp_t *ppp) else time(&stop_time); - memset(&ifreq, 0, sizeof(ifreq)); - ifreq.stats_ptr = (void *)&ifreq.stats; - strcpy(ifreq.ifr__name, ppp->ifname); - - if (ioctl(sock_fd, SIOCGPPPSTATS, &ifreq)) { - log_ppp_error("radius: failed to get ppp statistics: %s\n", strerror(errno)); - return; + if (ppp_read_stats(ppp, &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", ppp->acct_input_gigawords); + rad_packet_change_int(req->pack, NULL, "Acct-Output-Gigawords", ppp->acct_output_gigawords); } - - 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 (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; - - 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 - ppp->start_time); } diff --git a/accel-pppd/radius/radius_p.h b/accel-pppd/radius/radius_p.h index 7422bbf..65d9b6a 100644 --- a/accel-pppd/radius/radius_p.h +++ b/accel-pppd/radius/radius_p.h @@ -23,11 +23,6 @@ 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_input_gigawords; - uint32_t acct_output_gigawords; - struct triton_timer_t session_timeout; struct rad_packet_t *dm_coa_req; diff --git a/accel-pppd/shaper/CMakeLists.txt b/accel-pppd/shaper/CMakeLists.txt index 515fd83..3c1ac95 100644 --- a/accel-pppd/shaper/CMakeLists.txt +++ b/accel-pppd/shaper/CMakeLists.txt @@ -1,4 +1,4 @@ -ADD_LIBRARY(shaper SHARED shaper.c limiter.c leaf_qdisc.c tc_core.c libnetlink.c) +ADD_LIBRARY(shaper SHARED shaper.c limiter.c leaf_qdisc.c tc_core.c) INSTALL(TARGETS shaper LIBRARY DESTINATION lib/accel-ppp diff --git a/accel-pppd/shaper/libnetlink.c b/accel-pppd/shaper/libnetlink.c deleted file mode 100644 index 74cd5cb..0000000 --- a/accel-pppd/shaper/libnetlink.c +++ /dev/null @@ -1,692 +0,0 @@ -/* - * libnetlink.c RTnetlink service routines. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libnetlink.h" -#include "log.h" - -int rcvbuf = 1024 * 1024; - -void rtnl_close(struct rtnl_handle *rth) -{ - if (rth->fd >= 0) { - close(rth->fd); - rth->fd = -1; - } -} - -int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, - int protocol) -{ - socklen_t addr_len; - int sndbuf = 32768; - - memset(rth, 0, sizeof(*rth)); - - rth->fd = socket(AF_NETLINK, SOCK_RAW, protocol); - if (rth->fd < 0) { - log_error("libnetlink: ""Cannot open netlink socket: %s\n", strerror(errno)); - return -1; - } - - if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) { - log_error("libnetlink: ""SO_SNDBUF: %s\n", strerror(errno)); - return -1; - } - - if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) { - log_error("libnetlink: ""SO_RCVBUF: %s\n", strerror(errno)); - return -1; - } - - memset(&rth->local, 0, sizeof(rth->local)); - rth->local.nl_family = AF_NETLINK; - rth->local.nl_groups = subscriptions; - - if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { - log_error("libnetlink: ""Cannot bind netlink socket: %s\n", strerror(errno)); - return -1; - } - addr_len = sizeof(rth->local); - if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { - log_error("libnetlink: ""Cannot getsockname: %s\n", strerror(errno)); - return -1; - } - if (addr_len != sizeof(rth->local)) { - log_error("libnetlink: ""Wrong address length %d\n", addr_len); - return -1; - } - if (rth->local.nl_family != AF_NETLINK) { - log_error("libnetlink: ""Wrong address family %d\n", rth->local.nl_family); - return -1; - } - rth->seq = time(NULL); - return 0; -} - -int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions) -{ - return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE); -} - -int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) -{ - struct { - struct nlmsghdr nlh; - struct rtgenmsg g; - } req; - - memset(&req, 0, sizeof(req)); - req.nlh.nlmsg_len = sizeof(req); - req.nlh.nlmsg_type = type; - req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; - req.nlh.nlmsg_pid = 0; - req.nlh.nlmsg_seq = rth->dump = ++rth->seq; - req.g.rtgen_family = family; - - return send(rth->fd, (void*)&req, sizeof(req), 0); -} - -int rtnl_send(struct rtnl_handle *rth, const char *buf, int len) -{ - return send(rth->fd, buf, len, 0); -} - -int rtnl_send_check(struct rtnl_handle *rth, const char *buf, int len) -{ - struct nlmsghdr *h; - int status; - char resp[1024]; - - status = send(rth->fd, buf, len, 0); - if (status < 0) - return status; - - /* Check for immediate errors */ - status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK); - if (status < 0) { - if (errno == EAGAIN) - return 0; - return -1; - } - - for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status); - h = NLMSG_NEXT(h, status)) { - if (h->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); - if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) - log_error("libnetlink: ""ERROR truncated\n"); - else - errno = -err->error; - return -1; - } - } - - return 0; -} - -int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) -{ - struct nlmsghdr nlh; - struct sockaddr_nl nladdr; - struct iovec iov[2] = { - { .iov_base = &nlh, .iov_len = sizeof(nlh) }, - { .iov_base = req, .iov_len = len } - }; - struct msghdr msg = { - .msg_name = &nladdr, - .msg_namelen = sizeof(nladdr), - .msg_iov = iov, - .msg_iovlen = 2, - }; - - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; - - nlh.nlmsg_len = NLMSG_LENGTH(len); - nlh.nlmsg_type = type; - nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; - nlh.nlmsg_pid = 0; - nlh.nlmsg_seq = rth->dump = ++rth->seq; - - return sendmsg(rth->fd, &msg, 0); -} - -int rtnl_dump_filter_l(struct rtnl_handle *rth, - const struct rtnl_dump_filter_arg *arg) -{ - struct sockaddr_nl nladdr; - struct iovec iov; - struct msghdr msg = { - .msg_name = &nladdr, - .msg_namelen = sizeof(nladdr), - .msg_iov = &iov, - .msg_iovlen = 1, - }; - char buf[16384]; - - iov.iov_base = buf; - while (1) { - int status; - const struct rtnl_dump_filter_arg *a; - int found_done = 0; - int msglen = 0; - - iov.iov_len = sizeof(buf); - status = recvmsg(rth->fd, &msg, 0); - - if (status < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - log_error("libnetlink: ""netlink receive error %s (%d)\n", - strerror(errno), errno); - return -1; - } - - if (status == 0) { - log_error("libnetlink: ""EOF on netlink\n"); - return -1; - } - - for (a = arg; a->filter; a++) { - struct nlmsghdr *h = (struct nlmsghdr*)buf; - msglen = status; - - while (NLMSG_OK(h, msglen)) { - int err; - - if (nladdr.nl_pid != 0 || - h->nlmsg_pid != rth->local.nl_pid || - h->nlmsg_seq != rth->dump) { - if (a->junk) { - err = a->junk(&nladdr, h, - a->arg2); - if (err < 0) - return err; - } - goto skip_it; - } - - if (h->nlmsg_type == NLMSG_DONE) { - found_done = 1; - break; /* process next filter */ - } - if (h->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); - if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { - fprintf(stderr, - "ERROR truncated\n"); - } else { - errno = -err->error; - log_error("libnetlink: ""RTNETLINK answers: %s\n", strerror(errno)); - } - return -1; - } - err = a->filter(&nladdr, h, a->arg1); - if (err < 0) - return err; - -skip_it: - h = NLMSG_NEXT(h, msglen); - } - } - - if (found_done) - return 0; - - if (msg.msg_flags & MSG_TRUNC) { - log_error("libnetlink: ""Message truncated\n"); - continue; - } - if (msglen) { - log_error("libnetlink: ""!!!Remnant of size %d\n", msglen); - exit(1); - } - } -} - -int rtnl_dump_filter(struct rtnl_handle *rth, - rtnl_filter_t filter, - void *arg1, - rtnl_filter_t junk, - void *arg2) -{ - const struct rtnl_dump_filter_arg a[2] = { - { .filter = filter, .arg1 = arg1, .junk = junk, .arg2 = arg2 }, - { .filter = NULL, .arg1 = NULL, .junk = NULL, .arg2 = NULL } - }; - - return rtnl_dump_filter_l(rth, a); -} - -int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, - unsigned groups, struct nlmsghdr *answer, - rtnl_filter_t junk, - void *jarg, int ignore_einval) -{ - int status; - unsigned seq; - struct nlmsghdr *h; - struct sockaddr_nl nladdr; - struct iovec iov = { - .iov_base = (void*) n, - .iov_len = n->nlmsg_len - }; - struct msghdr msg = { - .msg_name = &nladdr, - .msg_namelen = sizeof(nladdr), - .msg_iov = &iov, - .msg_iovlen = 1, - }; - char buf[16384]; - - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; - nladdr.nl_pid = peer; - nladdr.nl_groups = groups; - - n->nlmsg_seq = seq = ++rtnl->seq; - - if (answer == NULL) - n->nlmsg_flags |= NLM_F_ACK; - - status = sendmsg(rtnl->fd, &msg, 0); - - if (status < 0) { - log_error("libnetlink: ""Cannot talk to rtnetlink: %s\n", strerror(errno)); - return -1; - } - - memset(buf,0,sizeof(buf)); - - iov.iov_base = buf; - - while (1) { - iov.iov_len = sizeof(buf); - status = recvmsg(rtnl->fd, &msg, 0); - - if (status < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - log_error("libnetlink: ""netlink receive error %s (%d)\n", - strerror(errno), errno); - return -1; - } - if (status == 0) { - log_error("libnetlink: ""EOF on netlink\n"); - return -1; - } - if (msg.msg_namelen != sizeof(nladdr)) { - log_error("libnetlink: ""sender address length == %d\n", msg.msg_namelen); - exit(1); - } - for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { - int err; - int len = h->nlmsg_len; - int l = len - sizeof(*h); - - if (l<0 || len>status) { - if (msg.msg_flags & MSG_TRUNC) { - log_error("libnetlink: ""Truncated message\n"); - return -1; - } - log_error("libnetlink: ""!!!malformed message: len=%d\n", len); - exit(1); - } - - if (nladdr.nl_pid != peer || - h->nlmsg_pid != rtnl->local.nl_pid || - h->nlmsg_seq != seq) { - if (junk) { - err = junk(&nladdr, h, jarg); - if (err < 0) - return err; - } - /* Don't forget to skip that message. */ - status -= NLMSG_ALIGN(len); - h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); - continue; - } - - if (h->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); - if (l < sizeof(struct nlmsgerr)) { - log_error("libnetlink: ""ERROR truncated\n"); - } else { - errno = -err->error; - if (errno == 0 || (errno == EINVAL && ignore_einval)) { - if (answer) - memcpy(answer, h, h->nlmsg_len); - return 0; - } - log_error("libnetlink: ""RTNETLINK answers: %s\n", strerror(errno)); - } - return -1; - } - if (answer) { - memcpy(answer, h, h->nlmsg_len); - return 0; - } - - log_error("libnetlink: ""Unexpected reply!!!\n"); - - status -= NLMSG_ALIGN(len); - h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); - } - if (msg.msg_flags & MSG_TRUNC) { - log_error("libnetlink: ""Message truncated\n"); - continue; - } - if (status) { - log_error("libnetlink: ""!!!Remnant of size %d\n", status); - exit(1); - } - } -} - -int rtnl_listen(struct rtnl_handle *rtnl, - rtnl_filter_t handler, - void *jarg) -{ - int status; - struct nlmsghdr *h; - struct sockaddr_nl nladdr; - struct iovec iov; - struct msghdr msg = { - .msg_name = &nladdr, - .msg_namelen = sizeof(nladdr), - .msg_iov = &iov, - .msg_iovlen = 1, - }; - char buf[8192]; - - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; - nladdr.nl_pid = 0; - nladdr.nl_groups = 0; - - iov.iov_base = buf; - while (1) { - iov.iov_len = sizeof(buf); - status = recvmsg(rtnl->fd, &msg, 0); - - if (status < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - log_error("libnetlink: ""netlink receive error %s (%d)\n", - strerror(errno), errno); - if (errno == ENOBUFS) - continue; - return -1; - } - if (status == 0) { - log_error("libnetlink: ""EOF on netlink\n"); - return -1; - } - if (msg.msg_namelen != sizeof(nladdr)) { - log_error("libnetlink: ""Sender address length == %d\n", msg.msg_namelen); - exit(1); - } - for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { - int err; - int len = h->nlmsg_len; - int l = len - sizeof(*h); - - if (l<0 || len>status) { - if (msg.msg_flags & MSG_TRUNC) { - log_error("libnetlink: ""Truncated message\n"); - return -1; - } - log_error("libnetlink: ""!!!malformed message: len=%d\n", len); - exit(1); - } - - err = handler(&nladdr, h, jarg); - if (err < 0) - return err; - - status -= NLMSG_ALIGN(len); - h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); - } - if (msg.msg_flags & MSG_TRUNC) { - log_error("libnetlink: ""Message truncated\n"); - continue; - } - if (status) { - log_error("libnetlink: ""!!!Remnant of size %d\n", status); - exit(1); - } - } -} - -int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler, - void *jarg) -{ - int status; - struct sockaddr_nl nladdr; - char buf[8192]; - struct nlmsghdr *h = (void*)buf; - - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; - nladdr.nl_pid = 0; - nladdr.nl_groups = 0; - - while (1) { - int err, len, type; - int l; - - status = fread(&buf, 1, sizeof(*h), rtnl); - - if (status < 0) { - if (errno == EINTR) - continue; - log_error("libnetlink: ""rtnl_from_file: fread"); - return -1; - } - if (status == 0) - return 0; - - len = h->nlmsg_len; - type= h->nlmsg_type; - l = len - sizeof(*h); - - if (l<0 || len>sizeof(buf)) { - log_error("libnetlink: ""!!!malformed message: len=%d @%lu\n", - len, ftell(rtnl)); - return -1; - } - - status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl); - - if (status < 0) { - log_error("libnetlink: ""rtnl_from_file: fread"); - return -1; - } - if (status < l) { - log_error("libnetlink: ""rtnl-from_file: truncated message\n"); - return -1; - } - - err = handler(&nladdr, h, jarg); - if (err < 0) - return err; - } -} - -int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data) -{ - int len = RTA_LENGTH(4); - struct rtattr *rta; - if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) { - fprintf(stderr,"addattr32: Error! max allowed bound %d exceeded\n",maxlen); - return -1; - } - rta = NLMSG_TAIL(n); - rta->rta_type = type; - rta->rta_len = len; - memcpy(RTA_DATA(rta), &data, 4); - n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; - return 0; -} - -int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, - int alen) -{ - int len = RTA_LENGTH(alen); - struct rtattr *rta; - - if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { - log_error("libnetlink: ""addattr_l ERROR: message exceeded bound of %d\n",maxlen); - return -1; - } - rta = NLMSG_TAIL(n); - rta->rta_type = type; - rta->rta_len = len; - memcpy(RTA_DATA(rta), data, alen); - n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); - return 0; -} - -int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len) -{ - if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) { - log_error("libnetlink: ""addraw_l ERROR: message exceeded bound of %d\n",maxlen); - return -1; - } - - memcpy(NLMSG_TAIL(n), data, len); - memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len); - n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len); - return 0; -} - -struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type) -{ - struct rtattr *nest = NLMSG_TAIL(n); - - addattr_l(n, maxlen, type, NULL, 0); - return nest; -} - -int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest) -{ - nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest; - return n->nlmsg_len; -} - -struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type, - const void *data, int len) -{ - struct rtattr *start = NLMSG_TAIL(n); - - addattr_l(n, maxlen, type, data, len); - addattr_nest(n, maxlen, type); - return start; -} - -int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start) -{ - struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len); - - start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start; - addattr_nest_end(n, nest); - return n->nlmsg_len; -} - -int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data) -{ - int len = RTA_LENGTH(4); - struct rtattr *subrta; - - if (RTA_ALIGN(rta->rta_len) + len > maxlen) { - fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen); - return -1; - } - subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); - subrta->rta_type = type; - subrta->rta_len = len; - memcpy(RTA_DATA(subrta), &data, 4); - rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; - return 0; -} - -int rta_addattr_l(struct rtattr *rta, int maxlen, int type, - const void *data, int alen) -{ - struct rtattr *subrta; - int len = RTA_LENGTH(alen); - - if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) { - fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen); - return -1; - } - subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); - subrta->rta_type = type; - subrta->rta_len = len; - memcpy(RTA_DATA(subrta), data, alen); - rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len); - return 0; -} - -int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) -{ - memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); - while (RTA_OK(rta, len)) { - if ((rta->rta_type <= max) && (!tb[rta->rta_type])) - tb[rta->rta_type] = rta; - rta = RTA_NEXT(rta,len); - } - if (len) - log_error("libnetlink: ""!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); - return 0; -} - -int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len) -{ - int i = 0; - - memset(tb, 0, sizeof(struct rtattr *) * max); - while (RTA_OK(rta, len)) { - if (rta->rta_type <= max && i < max) - tb[i++] = rta; - rta = RTA_NEXT(rta,len); - } - if (len) - log_error("libnetlink: ""!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); - return i; -} - -int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, - int len) -{ - if (RTA_PAYLOAD(rta) < len) - return -1; - if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) { - rta = RTA_DATA(rta) + RTA_ALIGN(len); - return parse_rtattr_nested(tb, max, rta); - } - memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); - return 0; -} diff --git a/accel-pppd/shaper/libnetlink.h b/accel-pppd/shaper/libnetlink.h deleted file mode 100644 index f68bf8a..0000000 --- a/accel-pppd/shaper/libnetlink.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef __LIBNETLINK_H__ -#define __LIBNETLINK_H__ 1 - -#include -#include -#include -#include -#include -#include - -#define TCA_BUF_MAX 64*1024 -#define MAX_MSG 16384 - -struct rtnl_handle -{ - int fd; - struct sockaddr_nl local; - struct sockaddr_nl peer; - __u32 seq; - __u32 dump; -}; - -extern int rcvbuf; - -extern int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions); -extern int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, int protocol); -extern void rtnl_close(struct rtnl_handle *rth); -extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type); -extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len); - -typedef int (*rtnl_filter_t)(const struct sockaddr_nl *, - struct nlmsghdr *n, void *); - -struct rtnl_dump_filter_arg -{ - rtnl_filter_t filter; - void *arg1; - rtnl_filter_t junk; - void *arg2; -}; - -extern int rtnl_dump_filter_l(struct rtnl_handle *rth, - const struct rtnl_dump_filter_arg *arg); -extern int rtnl_dump_filter(struct rtnl_handle *rth, rtnl_filter_t filter, - void *arg1, - rtnl_filter_t junk, - void *arg2); - -extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, - unsigned groups, struct nlmsghdr *answer, - rtnl_filter_t junk, - void *jarg, int ignore_einval); -extern int rtnl_send(struct rtnl_handle *rth, const char *buf, int); -extern int rtnl_send_check(struct rtnl_handle *rth, const char *buf, int); - -extern int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data); -extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, int alen); -extern int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len); -extern struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type); -extern int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest); -extern struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type, const void *data, int len); -extern int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *nest); -extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data); -extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, const void *data, int alen); - -extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len); -extern int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len); -extern int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, int len); - -#define parse_rtattr_nested(tb, max, rta) \ - (parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta))) - -#define parse_rtattr_nested_compat(tb, max, rta, data, len) \ -({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \ - __parse_rtattr_nested_compat(tb, max, rta, len); }) - -extern int rtnl_listen(struct rtnl_handle *, rtnl_filter_t handler, - void *jarg); -extern int rtnl_from_file(FILE *, rtnl_filter_t handler, - void *jarg); - -#define NLMSG_TAIL(nmsg) \ - ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) - -#ifndef IFA_RTA -#define IFA_RTA(r) \ - ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) -#endif -#ifndef IFA_PAYLOAD -#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg)) -#endif - -#ifndef IFLA_RTA -#define IFLA_RTA(r) \ - ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) -#endif -#ifndef IFLA_PAYLOAD -#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) -#endif - -#ifndef NDA_RTA -#define NDA_RTA(r) \ - ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) -#endif -#ifndef NDA_PAYLOAD -#define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg)) -#endif - -#ifndef NDTA_RTA -#define NDTA_RTA(r) \ - ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndtmsg)))) -#endif -#ifndef NDTA_PAYLOAD -#define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg)) -#endif - -#endif /* __LIBNETLINK_H__ */ - -- cgit v1.2.3