summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Kozlov <xeb@mail.ru>2016-07-11 09:47:04 +0300
committerDmitry Kozlov <xeb@mail.ru>2016-07-11 09:47:04 +0300
commite0cca4344f70b9c9e23e3c6a7e17c8e93c765184 (patch)
tree1068654b025b2e24c983d99776696ad889a0c138
parent6fb04941ca41312909208938bfac4f753d3c277c (diff)
downloadaccel-ppp-e0cca4344f70b9c9e23e3c6a7e17c8e93c765184.tar.gz
accel-ppp-e0cca4344f70b9c9e23e3c6a7e17c8e93c765184.zip
implemented support for network namespace
This is done using radius attribute NAS-Port-Id. The new format of this attribute is NAS-Port-Id=[ns/][name]. Namespaces must be created malually by "ip netns add ..." command
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c4
-rw-r--r--accel-pppd/ctrl/l2tp/l2tp.c3
-rw-r--r--accel-pppd/ctrl/pppoe/pppoe.c9
-rw-r--r--accel-pppd/ctrl/pppoe/pppoe.h2
-rw-r--r--accel-pppd/ctrl/pptp/pptp.c6
-rw-r--r--accel-pppd/ifcfg.c82
-rw-r--r--accel-pppd/include/ap_net.h22
-rw-r--r--accel-pppd/include/ap_session.h8
-rw-r--r--accel-pppd/ipv6/dhcpv6.c22
-rw-r--r--accel-pppd/ipv6/nd.c21
-rw-r--r--accel-pppd/libnetlink/iputils.c220
-rw-r--r--accel-pppd/libnetlink/libnetlink.h2
-rw-r--r--accel-pppd/net.c308
-rw-r--r--accel-pppd/session.c4
-rw-r--r--accel-pppd/shaper/limiter.c37
15 files changed, 509 insertions, 241 deletions
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index c7db14aa..84f8ad7c 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.c
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -203,7 +203,7 @@ static void ipoe_serv_timeout(struct triton_timer_t *t);
static void ipoe_ctx_switch(struct triton_context_t *ctx, void *arg)
{
- net = &def_net;
+ net = def_net;
log_switch(ctx, arg);
}
@@ -3263,7 +3263,7 @@ static void load_config(void)
if (!s)
return;
- net = &def_net;
+ net = def_net;
opt = conf_get_opt("ipoe", "username");
if (opt) {
diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c
index 76c679c7..5d9041fa 100644
--- a/accel-pppd/ctrl/l2tp/l2tp.c
+++ b/accel-pppd/ctrl/l2tp/l2tp.c
@@ -255,7 +255,8 @@ static inline int nsnr_cmp(uint16_t ns, uint16_t nr)
static void l2tp_ctx_switch(struct triton_context_t *ctx, void *arg)
{
- net = &def_net;
+ struct ap_session *s = arg;
+ net = s->net;
log_switch(ctx, arg);
}
diff --git a/accel-pppd/ctrl/pppoe/pppoe.c b/accel-pppd/ctrl/pppoe/pppoe.c
index 242f7e07..4536040d 100644
--- a/accel-pppd/ctrl/pppoe/pppoe.c
+++ b/accel-pppd/ctrl/pppoe/pppoe.c
@@ -264,7 +264,7 @@ static int pppoe_rad_send_accounting_request(struct rad_plugin_t *rad, struct ra
static void pppoe_conn_ctx_switch(struct triton_context_t *ctx, void *arg)
{
struct pppoe_conn_t *conn = arg;
- net = conn->serv->net;
+ net = conn->ppp.ses.net;
log_switch(ctx, &conn->ppp.ses);
}
@@ -400,6 +400,7 @@ static struct pppoe_conn_t *allocate_channel(struct pppoe_serv_t *serv, const ui
ppp_init(&conn->ppp);
+ conn->ppp.ses.net = serv->net;
conn->ppp.ses.ctrl = &conn->ctrl;
conn->ppp.ses.chan_name = conn->ctrl.calling_station_id;
@@ -1266,7 +1267,7 @@ static void pppoe_serv_timeout(struct triton_timer_t *t)
pppoe_server_free(serv);
}
-static int parse_server(const char *opt, int *padi_limit, const struct ap_net **net)
+static int parse_server(const char *opt, int *padi_limit, struct ap_net **net)
{
char *ptr, *endptr;
char name[64];
@@ -1374,7 +1375,7 @@ static void __pppoe_server_start(const char *ifname, const char *opt, void *cli,
struct pppoe_serv_t *serv;
struct ifreq ifr;
int padi_limit = conf_padi_limit;
- const struct ap_net *net = &def_net;
+ struct ap_net *net = def_net;
if (parse_server(opt, &padi_limit, &net)) {
if (cli)
@@ -1462,7 +1463,7 @@ static void __pppoe_server_start(const char *ifname, const char *opt, void *cli,
goto out_err;
}
- if (parent_ifindex == -1 && net == &def_net)
+ if (parent_ifindex == -1 && net == def_net)
vid = iplink_vlan_get_vid(ifr.ifr_ifindex, &parent_ifindex);
serv->ctx.close = pppoe_serv_close;
diff --git a/accel-pppd/ctrl/pppoe/pppoe.h b/accel-pppd/ctrl/pppoe/pppoe.h
index aac169ed..75e0eed9 100644
--- a/accel-pppd/ctrl/pppoe/pppoe.h
+++ b/accel-pppd/ctrl/pppoe/pppoe.h
@@ -70,7 +70,7 @@ struct pppoe_serv_t
struct triton_context_t ctx;
struct rb_node node;
- const struct ap_net *net;
+ struct ap_net *net;
int disc_sock;
uint8_t hwaddr[ETH_ALEN];
diff --git a/accel-pppd/ctrl/pptp/pptp.c b/accel-pppd/ctrl/pptp/pptp.c
index ec20586f..4aba5767 100644
--- a/accel-pppd/ctrl/pptp/pptp.c
+++ b/accel-pppd/ctrl/pptp/pptp.c
@@ -75,7 +75,11 @@ static void ppp_finished(struct ap_session *);
static void pptp_ctx_switch(struct triton_context_t *ctx, void *arg)
{
- net = &def_net;
+ if (arg) {
+ struct ap_session *s = arg;
+ net = s->net;
+ } else
+ net = def_net;
log_switch(ctx, arg);
}
diff --git a/accel-pppd/ifcfg.c b/accel-pppd/ifcfg.c
index 246aa643..5e7c790a 100644
--- a/accel-pppd/ifcfg.c
+++ b/accel-pppd/ifcfg.c
@@ -149,9 +149,11 @@ void __export ap_session_accounting_started(struct ap_session *ses)
}
if (ses->ipv6) {
+ net->enter_ns();
devconf(ses, "accept_ra", "0");
devconf(ses, "autoconf", "0");
devconf(ses, "forwarding", "1");
+ net->exit_ns();
memset(&ifr6, 0, sizeof(ifr6));
@@ -161,7 +163,7 @@ void __export ap_session_accounting_started(struct ap_session *ses)
ifr6.ifr6_prefixlen = 64;
ifr6.ifr6_ifindex = ses->ifindex;
- if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6))
+ if (net->sock6_ioctl(SIOCSIFADDR, &ifr6))
log_ppp_error("faild to set LL IPv6 address: %s\n", strerror(errno));
}
@@ -246,7 +248,7 @@ void __export ap_session_ifdown(struct ap_session *ses)
ifr6.ifr6_addr.s6_addr32[0] = htonl(0xfe800000);
*(uint64_t *)(ifr6.ifr6_addr.s6_addr + 8) = ses->ipv6->intf_id;
ifr6.ifr6_prefixlen = 64;
- ioctl(sock6_fd, SIOCDIFADDR, &ifr6);
+ net->sock6_ioctl(SIOCDIFADDR, &ifr6);
}
list_for_each_entry(a, &ses->ipv6->addr_list, entry) {
@@ -267,42 +269,72 @@ void __export ap_session_ifdown(struct ap_session *ses)
int __export ap_session_rename(struct ap_session *ses, const char *ifname, int len)
{
struct ifreq ifr;
- int r, up = 0;
+ int i, r, up = 0;
+ struct ap_net *ns = NULL;
+ char ns_name[256];
if (len == -1)
len = strlen(ifname);
+ for (i = 0; i < len; i++) {
+ if (ifname[i] == '/') {
+ memcpy(ns_name, ifname, i);
+ ns_name[i] = 0;
+
+ ns = ap_net_open_ns(ns_name);
+ if (!ns)
+ return -1;
+
+ ifname += i + 1;
+ len -= i + 1;
+ break;
+ }
+ }
+
if (len >= IFNAMSIZ) {
- log_ppp_warn("cannot rename interface (name is too long)\n");
+ log_ppp_error("cannot rename interface (name is too long)\n");
return -1;
}
- strcpy(ifr.ifr_name, ses->ifname);
- memcpy(ifr.ifr_newname, ifname, len);
- ifr.ifr_newname[len] = 0;
-
- r = net->sock_ioctl(SIOCSIFNAME, &ifr);
- if (r && errno == EBUSY) {
- net->sock_ioctl(SIOCGIFFLAGS, &ifr);
- ifr.ifr_flags &= ~IFF_UP;
- net->sock_ioctl(SIOCSIFFLAGS, &ifr);
-
+ if (len) {
+ strcpy(ifr.ifr_name, ses->ifname);
memcpy(ifr.ifr_newname, ifname, len);
ifr.ifr_newname[len] = 0;
+
r = net->sock_ioctl(SIOCSIFNAME, &ifr);
+ if (r && errno == EBUSY) {
+ net->sock_ioctl(SIOCGIFFLAGS, &ifr);
+ ifr.ifr_flags &= ~IFF_UP;
+ net->sock_ioctl(SIOCSIFFLAGS, &ifr);
+
+ memcpy(ifr.ifr_newname, ifname, len);
+ ifr.ifr_newname[len] = 0;
+ r = net->sock_ioctl(SIOCSIFNAME, &ifr);
+
+ up = 1;
+ }
- up = 1;
+ if (r) {
+ if (!ses->ifname_rename)
+ ses->ifname_rename = _strdup(ifr.ifr_newname);
+ else
+ log_ppp_warn("interface rename to %s failed: %s\n", ifr.ifr_newname, strerror(errno));
+ } else {
+ log_ppp_info2("rename interface to '%s'\n", ifr.ifr_newname);
+ memcpy(ses->ifname, ifname, len);
+ ses->ifname[len] = 0;
+ }
}
- if (r) {
- if (!ses->ifname_rename)
- ses->ifname_rename = _strdup(ifr.ifr_newname);
- else
- log_ppp_warn("interface rename to %s failed: %s\n", ifr.ifr_newname, strerror(errno));
- } else {
- log_ppp_info2("rename interface to '%s'\n", ifr.ifr_newname);
- memcpy(ses->ifname, ifname, len);
- ses->ifname[len] = 0;
+ if (ns) {
+ if (net->move_link(ns, ses->ifindex)) {
+ log_ppp_error("failed to attach namespace\n");
+ ns->release(ns);
+ return -1;
+ }
+ ses->net = ns;
+ net = ns;
+ log_ppp_info2("move to namespace %s\n", ns->name);
}
if (up) {
@@ -311,6 +343,6 @@ int __export ap_session_rename(struct ap_session *ses, const char *ifname, int l
net->sock_ioctl(SIOCSIFFLAGS, &ifr);
}
- return r;
+ return 0;
}
diff --git a/accel-pppd/include/ap_net.h b/accel-pppd/include/ap_net.h
index 40544d58..25121d94 100644
--- a/accel-pppd/include/ap_net.h
+++ b/accel-pppd/include/ap_net.h
@@ -1,8 +1,12 @@
#ifndef __AP_NET_H
#define __AP_NET_H
+struct rtnl_handle;
+
struct ap_net {
- const char *name;
+ struct list_head entry;
+ int refs;
+ char *name;
int (*socket)(int domain, int type, int proto);
int (*connect)(int sock, const struct sockaddr *, socklen_t len);
int (*bind)(int sock, const struct sockaddr *, socklen_t len);
@@ -14,11 +18,23 @@ struct ap_net {
int (*set_nonblocking)(int sock, int f);
int (*setsockopt)(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
int (*sock_ioctl)(unsigned long request, void *arg);
+ int (*sock6_ioctl)(unsigned long request, void *arg);
int (*ppp_open)();
int (*ppp_ioctl)(int fd, unsigned long request, void *arg);
+ void (*enter_ns)();
+ void (*exit_ns)();
+ struct rtnl_handle *(*rtnl_get)();
+ void (*rtnl_put)(struct rtnl_handle *);
+ int (*rtnl_open)(struct rtnl_handle *h, int proto);
+ int (*move_link)(struct ap_net *net, int ifindex);
+ void (*release)(struct ap_net *net);
};
-int ap_net_register(const struct ap_net *net);
-const struct ap_net *ap_net_find(const char *name);
+extern __thread struct ap_net *net;
+extern struct ap_net *def_net;
+
+int ap_net_register(struct ap_net *net);
+struct ap_net *ap_net_find(const char *name);
+struct ap_net *ap_net_open_ns(const char *name);
#endif
diff --git a/accel-pppd/include/ap_session.h b/accel-pppd/include/ap_session.h
index 0baaab2c..82e7e8c6 100644
--- a/accel-pppd/include/ap_session.h
+++ b/accel-pppd/include/ap_session.h
@@ -81,6 +81,7 @@ struct ap_session
struct ipv6db_prefix_t *ipv6_dp;
char *ipv4_pool_name;
char *ipv6_pool_name;
+ struct ap_net *net;
const struct ap_ctrl *ctrl;
@@ -125,14 +126,11 @@ struct ap_session_stat
extern pthread_rwlock_t ses_lock;
extern struct list_head ses_list;
extern int ap_shutdown;
-extern int sock_fd; // internet socket for ioctls
-extern int sock6_fd; // internet socket for ioctls
+extern int sock_fd;
+extern int sock6_fd;
extern int urandom_fd;
extern struct ap_session_stat ap_session_stat;
-extern __thread const struct ap_net *net;
-extern const struct ap_net def_net;
-
void ap_session_init(struct ap_session *ses);
void ap_session_set_ifindex(struct ap_session *ses);
int ap_session_starting(struct ap_session *ses);
diff --git a/accel-pppd/ipv6/dhcpv6.c b/accel-pppd/ipv6/dhcpv6.c
index e170ae21..f147a8cd 100644
--- a/accel-pppd/ipv6/dhcpv6.c
+++ b/accel-pppd/ipv6/dhcpv6.c
@@ -66,15 +66,15 @@ static void ev_ses_started(struct ap_session *ses)
if (!ses->ipv6)
return;
- sock = socket(AF_INET6, SOCK_DGRAM, 0);
+ sock = net->socket(AF_INET6, SOCK_DGRAM, 0);
if (!sock) {
log_ppp_error("dhcpv6: socket: %s\n", strerror(errno));
return;
}
- setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &f, sizeof(f));
+ net->setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &f, sizeof(f));
- if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ses->ifname, strlen(ses->ifname))) {
+ if (net->setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ses->ifname, strlen(ses->ifname))) {
log_ppp_error("ipv6_nd: setsockopt(SO_BINDTODEVICE): %s\n", strerror(errno));
close(sock);
return;
@@ -84,7 +84,7 @@ static void ev_ses_started(struct ap_session *ses)
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(DHCPV6_SERV_PORT);
- if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) {
+ if (net->bind(sock, (struct sockaddr *)&addr, sizeof(addr))) {
log_ppp_error("dhcpv6: bind: %s\n", strerror(errno));
close(sock);
return;
@@ -95,14 +95,14 @@ static void ev_ses_started(struct ap_session *ses)
mreq.ipv6mr_multiaddr.s6_addr32[0] = htonl(0xff020000);
mreq.ipv6mr_multiaddr.s6_addr32[3] = htonl(0x010002);
- if (setsockopt(sock, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) {
+ if (net->setsockopt(sock, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) {
log_ppp_error("dhcpv6: failed to join to All_DHCP_Relay_Agents_and_Servers\n");
close(sock);
return;
}
- fcntl(sock, F_SETFL, O_NONBLOCK);
fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
+ net->set_nonblocking(sock, 1);
pd = _malloc(sizeof(*pd));
memset(pd, 0, sizeof(*pd));
@@ -189,7 +189,7 @@ static void insert_dp_routes(struct ap_session *ses, struct dhcpv6_pd *pd)
rt6.rtmsg_flags |= RTF_GATEWAY;
list_for_each_entry(a, &ses->ipv6->addr_list, entry) {
build_addr(a, ses->ipv6->peer_intf_id, &rt6.rtmsg_gateway);
- if (ioctl(sock6_fd, SIOCADDRT, &rt6)) {
+ if (net->sock6_ioctl(SIOCADDRT, &rt6)) {
err = errno;
inet_ntop(AF_INET6, &p->addr, str1, sizeof(str1));
inet_ntop(AF_INET6, &rt6.rtmsg_gateway, str2, sizeof(str2));
@@ -202,7 +202,7 @@ static void insert_dp_routes(struct ap_session *ses, struct dhcpv6_pd *pd)
rt6.rtmsg_metric++;
}
} else {
- if (ioctl(sock6_fd, SIOCADDRT, &rt6)) {
+ if (net->sock6_ioctl(SIOCADDRT, &rt6)) {
err = errno;
inet_ntop(AF_INET6, &p->addr, str1, sizeof(str1));
log_ppp_error("dhcpv6: route add %s/%i: %s\n",
@@ -457,7 +457,7 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i
dhcpv6_packet_print(reply, log_ppp_info2);
}
- sendto(pd->hnd.fd, reply->hdr, reply->endptr - (void *)reply->hdr, 0, (struct sockaddr *)&req->addr, sizeof(req->addr));
+ net->sendto(pd->hnd.fd, reply->hdr, reply->endptr - (void *)reply->hdr, 0, (struct sockaddr *)&req->addr, sizeof(req->addr));
dhcpv6_packet_free(reply);
}
@@ -609,7 +609,7 @@ static void dhcpv6_send_reply2(struct dhcpv6_packet *req, struct dhcpv6_pd *pd,
dhcpv6_packet_print(reply, log_ppp_info2);
}
- sendto(pd->hnd.fd, reply->hdr, reply->endptr - (void *)reply->hdr, 0, (struct sockaddr *)&req->addr, sizeof(req->addr));
+ net->sendto(pd->hnd.fd, reply->hdr, reply->endptr - (void *)reply->hdr, 0, (struct sockaddr *)&req->addr, sizeof(req->addr));
out:
dhcpv6_packet_free(reply);
@@ -799,7 +799,7 @@ static int dhcpv6_read(struct triton_md_handler_t *h)
uint8_t *buf = _malloc(BUF_SIZE);
while (1) {
- n = recvfrom(h->fd, buf, BUF_SIZE, 0, &addr, &len);
+ n = net->recvfrom(h->fd, buf, BUF_SIZE, 0, (struct sockaddr *)&addr, &len);
if (n == -1) {
if (errno == EAGAIN)
break;
diff --git a/accel-pppd/ipv6/nd.c b/accel-pppd/ipv6/nd.c
index 19a3d7d3..1d70ae95 100644
--- a/accel-pppd/ipv6/nd.c
+++ b/accel-pppd/ipv6/nd.c
@@ -185,7 +185,7 @@ static void ipv6_nd_send_ra(struct ipv6_nd_handler_t *h, struct sockaddr_in6 *ad
} else
endptr = rdnss_addr;
- sendto(h->hnd.fd, buf, endptr - buf, 0, (struct sockaddr *)addr, sizeof(*addr));
+ net->sendto(h->hnd.fd, buf, endptr - buf, 0, (struct sockaddr *)addr, sizeof(*addr));
mempool_free(buf);
}
@@ -225,7 +225,7 @@ static int ipv6_nd_read(struct triton_md_handler_t *_h)
}
while (1) {
- n = recvfrom(h->hnd.fd, icmph, BUF_SIZE, 0, &addr, &addr_len);
+ n = net->recvfrom(h->hnd.fd, icmph, BUF_SIZE, 0, (struct sockaddr *)&addr, &addr_len);
if (n == -1) {
if (errno == EAGAIN)
break;
@@ -269,31 +269,31 @@ static int ipv6_nd_start(struct ap_session *ses)
int val;
struct ipv6_nd_handler_t *h;
- sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+ sock = net->socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
if (sock < 0) {
log_ppp_error("socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6): %s\n", strerror(errno));
return -1;
}
- if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ses->ifname, strlen(ses->ifname))) {
+ if (net->setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ses->ifname, strlen(ses->ifname))) {
log_ppp_error("ipv6_nd: setsockopt(SO_BINDTODEVICE): %s\n", strerror(errno));
goto out_err;
}
val = 2;
- if (setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val))) {
+ if (net->setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val))) {
log_ppp_error("ipv6_nd: setsockopt(IPV6_CHECKSUM): %s\n", strerror(errno));
goto out_err;
}
val = 255;
- if (setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val))) {
+ if (net->setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val))) {
log_ppp_error("ipv6_nd: setsockopt(IPV6_UNICAST_HOPS): %s\n", strerror(errno));
goto out_err;
}
- if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val))) {
+ if (net->setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val))) {
log_ppp_error("ipv6_nd: setsockopt(IPV6_MULTICAST_HOPS): %s\n", strerror(errno));
goto out_err;
}
@@ -307,7 +307,7 @@ static int ipv6_nd_start(struct ap_session *ses)
ICMP6_FILTER_SETBLOCKALL(&filter);
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
- if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter))) {
+ if (net->setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter))) {
log_ppp_error("ipv6_nd: setsockopt(ICMP6_FILTER): %s\n", strerror(errno));
goto out_err;
}
@@ -317,13 +317,14 @@ static int ipv6_nd_start(struct ap_session *ses)
mreq.ipv6mr_multiaddr.s6_addr32[0] = htonl(0xff020000);
mreq.ipv6mr_multiaddr.s6_addr32[3] = htonl(0x2);
- if (setsockopt(sock, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) {
+ if (net->setsockopt(sock, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) {
log_ppp_error("ipv6_nd: failed to join ipv6 allrouters\n");
goto out_err;
}
fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
- fcntl(sock, F_SETFL, O_NONBLOCK);
+
+ net->set_nonblocking(sock, 1);
h = _malloc(sizeof(*h));
memset(h, 0, sizeof(*h));
diff --git a/accel-pppd/libnetlink/iputils.c b/accel-pppd/libnetlink/iputils.c
index 30a06d1f..7a29d08f 100644
--- a/accel-pppd/libnetlink/iputils.c
+++ b/accel-pppd/libnetlink/iputils.c
@@ -20,6 +20,7 @@
#include "libnetlink.h"
#include "iputils.h"
+#include "ap_net.h"
#ifdef ACCEL_DP
#define _malloc(x) malloc(x)
@@ -37,37 +38,6 @@ struct arg
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);
@@ -143,9 +113,8 @@ int __export iplink_get_stats(int ifindex, struct rtnl_link_stats *stats)
struct ifinfomsg *ifi;
int len;
struct rtattr *tb[IFLA_MAX + 1];
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = -1;
if (!rth)
return -1;
@@ -159,10 +128,10 @@ int __export iplink_get_stats(int ifindex, struct rtnl_link_stats *stats)
req.i.ifi_index = ifindex;
if (rtnl_talk(rth, &req.n, 0, 0, &req.n, NULL, NULL, 0) < 0)
- return -1;
+ goto out;
if (req.n.nlmsg_type != RTM_NEWLINK)
- return -1;
+ goto out;
ifi = NLMSG_DATA(&req.n);
@@ -170,15 +139,18 @@ int __export iplink_get_stats(int ifindex, struct rtnl_link_stats *stats)
len -= NLMSG_LENGTH(sizeof(*ifi));
if (len < 0)
- return -1;
+ goto out;
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
- if (tb[IFLA_STATS])
+ if (tb[IFLA_STATS]) {
memcpy(stats, RTA_DATA(tb[IFLA_STATS]), sizeof(*stats));
- else
- return -1;
+ r = 0;
+ }
- return 0;
+out:
+ net->rtnl_put(rth);
+
+ return r;
}
int __export iplink_vlan_add(const char *ifname, int ifindex, int vid)
@@ -189,9 +161,8 @@ int __export iplink_vlan_add(const char *ifname, int ifindex, int vid)
char buf[4096];
} req;
struct rtattr *linkinfo, *data;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -218,9 +189,11 @@ int __export iplink_vlan_add(const char *ifname, int ifindex, int vid)
linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export iplink_vlan_del(int ifindex)
@@ -231,9 +204,8 @@ int __export iplink_vlan_del(int ifindex)
char buf[4096];
} req;
struct rtattr *linkinfo;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -257,9 +229,11 @@ int __export iplink_vlan_del(int ifindex)
linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export iplink_vlan_get_vid(int ifindex, int *iflink)
@@ -272,9 +246,8 @@ int __export iplink_vlan_get_vid(int ifindex, int *iflink)
struct ifinfomsg *ifi;
int len;
struct rtattr *tb[IFLA_MAX + 1];
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -288,10 +261,10 @@ int __export iplink_vlan_get_vid(int ifindex, int *iflink)
req.i.ifi_index = ifindex;
if (rtnl_talk(rth, &req.n, 0, 0, &req.n, NULL, NULL, 0) < 0)
- return -1;
+ goto out;
if (req.n.nlmsg_type != RTM_NEWLINK)
- return -1;
+ goto out;
ifi = NLMSG_DATA(&req.n);
@@ -299,12 +272,12 @@ int __export iplink_vlan_get_vid(int ifindex, int *iflink)
len -= NLMSG_LENGTH(sizeof(*ifi));
if (len < 0)
- return -1;
+ goto out;
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
if (!tb[IFLA_LINKINFO])
- return 0;
+ goto out;
if (iflink && tb[IFLA_LINK])
*iflink = *(int *)RTA_DATA(tb[IFLA_LINK]);
@@ -312,10 +285,15 @@ int __export iplink_vlan_get_vid(int ifindex, int *iflink)
parse_rtattr_nested(tb, IFLA_MAX, tb[IFLA_LINKINFO]);
if (strcmp(RTA_DATA(tb[IFLA_INFO_KIND]), "vlan"))
- return 0;
+ goto out;
parse_rtattr_nested(tb, IFLA_MAX, tb[IFLA_INFO_DATA]);
- return *(uint16_t *)RTA_DATA(tb[IFLA_VLAN_ID]);
+ r = *(uint16_t *)RTA_DATA(tb[IFLA_VLAN_ID]);
+
+out:
+ net->rtnl_put(rth);
+
+ return r;
}
@@ -326,9 +304,8 @@ int __export ipaddr_add(int ifindex, in_addr_t addr, int mask)
struct ifaddrmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -345,9 +322,11 @@ int __export ipaddr_add(int ifindex, in_addr_t addr, int mask)
addattr32(&req.n, sizeof(req), IFA_LOCAL, addr);
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export ipaddr_del(int ifindex, in_addr_t addr, int mask)
@@ -357,9 +336,8 @@ int __export ipaddr_del(int ifindex, in_addr_t addr, int mask)
struct ifaddrmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -376,9 +354,11 @@ int __export ipaddr_del(int ifindex, in_addr_t addr, int mask)
addattr32(&req.n, sizeof(req), IFA_LOCAL, addr);
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask)
@@ -388,9 +368,8 @@ int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw
struct rtmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -416,9 +395,11 @@ int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw
addattr32(&req.n, sizeof(req), RTA_DST, dst);
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export iproute_del(int ifindex, in_addr_t dst, int proto, int mask)
@@ -428,9 +409,8 @@ int __export iproute_del(int ifindex, in_addr_t dst, int proto, int mask)
struct rtmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -453,9 +433,11 @@ int __export iproute_del(int ifindex, in_addr_t dst, int proto, int mask)
addattr32(&req.n, sizeof(req), RTA_OIF, ifindex);
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export ip6route_add(int ifindex, struct in6_addr *dst, int pref_len, int proto)
@@ -465,9 +447,8 @@ int __export ip6route_add(int ifindex, struct in6_addr *dst, int pref_len, int p
struct rtmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -488,9 +469,11 @@ int __export ip6route_add(int ifindex, struct in6_addr *dst, int pref_len, int p
addattr32(&req.n, sizeof(req), RTA_OIF, ifindex);
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export ip6route_del(int ifindex, struct in6_addr *dst, int pref_len)
@@ -500,9 +483,8 @@ int __export ip6route_del(int ifindex, struct in6_addr *dst, int pref_len)
struct rtmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -521,9 +503,11 @@ int __export ip6route_del(int ifindex, struct in6_addr *dst, int pref_len)
addattr_l(&req.n, sizeof(req), RTA_DST, dst, sizeof(*dst));
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export ip6addr_add(int ifindex, struct in6_addr *addr, int prefix_len)
@@ -533,9 +517,8 @@ int __export ip6addr_add(int ifindex, struct in6_addr *addr, int prefix_len)
struct ifaddrmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -553,9 +536,11 @@ int __export ip6addr_add(int ifindex, struct in6_addr *addr, int prefix_len)
addattr_l(&req.n, sizeof(req), IFA_ADDRESS, addr, 16);
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export ip6addr_del(int ifindex, struct in6_addr *addr, int prefix_len)
@@ -565,9 +550,8 @@ int __export ip6addr_del(int ifindex, struct in6_addr *addr, int prefix_len)
struct ifaddrmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -584,9 +568,11 @@ int __export ip6addr_del(int ifindex, struct in6_addr *addr, int prefix_len)
addattr_l(&req.n, sizeof(req), IFA_ADDRESS, addr, 16);
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
in_addr_t __export iproute_get(in_addr_t dst, in_addr_t *gw)
@@ -600,14 +586,12 @@ in_addr_t __export iproute_get(in_addr_t dst, in_addr_t *gw)
struct rtattr *tb[RTA_MAX+1];
int len;
in_addr_t res = 0;
+ struct rtnl_handle *rth = net->rtnl_get();
if (gw)
*gw = 0;
if (!rth)
- open_rth();
-
- if (!rth)
return -1;
memset(&req, 0, sizeof(req) - 4096);
@@ -654,6 +638,8 @@ in_addr_t __export iproute_get(in_addr_t dst, in_addr_t *gw)
*gw = *(uint32_t *)RTA_DATA(tb[RTA_GATEWAY]);
out:
+ net->rtnl_put(rth);
+
return res;
}
@@ -664,9 +650,8 @@ int __export iprule_add(uint32_t addr, int table)
struct rtmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -688,9 +673,11 @@ int __export iprule_add(uint32_t addr, int table)
addattr32(&req.n, sizeof(req), FRA_TABLE, table);
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export iprule_del(uint32_t addr, int table)
@@ -700,9 +687,8 @@ int __export iprule_del(uint32_t addr, int table)
struct rtmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -724,15 +710,9 @@ int __export iprule_del(uint32_t addr, int table)
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;
-}
+ r = -1;
+ net->rtnl_put(rth);
-static void init(void)
-{
- pthread_key_create(&rth_key, free_rth);
+ return r;
}
-
-DEFINE_INIT(100, init);
diff --git a/accel-pppd/libnetlink/libnetlink.h b/accel-pppd/libnetlink/libnetlink.h
index f68bf8a1..5089c46f 100644
--- a/accel-pppd/libnetlink/libnetlink.h
+++ b/accel-pppd/libnetlink/libnetlink.h
@@ -76,8 +76,6 @@ extern int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rta
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)))
diff --git a/accel-pppd/net.c b/accel-pppd/net.c
index d2bd4e03..0fc6e354 100644
--- a/accel-pppd/net.c
+++ b/accel-pppd/net.c
@@ -1,21 +1,37 @@
+#include <stdlib.h>
+#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
+#include <pthread.h>
+#include <sched.h>
+#include <limits.h>
+#include <errno.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include "triton.h"
-
+#include "log.h"
+#include "libnetlink.h"
#include "ap_net.h"
+#include "memdebug.h"
-#define MAX_NET 2
+struct kern_net {
+ struct ap_net net;
+ struct rtnl_handle *rth;
+ int ns_fd;
+ int sock;
+ int sock6;
+};
-static const struct ap_net *nets[MAX_NET];
-static int net_cnt;
+static const char *conf_netns_run_dir;
-extern int sock_fd;
+static LIST_HEAD(nets);
+static pthread_mutex_t nets_lock = PTHREAD_MUTEX_INITIALIZER;
-__export __thread const struct ap_net *net;
+__export __thread struct ap_net *net;
+__export struct ap_net *def_net;
+static int def_ns_fd;
static int def_socket(int domain, int type, int proto)
{
@@ -79,57 +95,269 @@ static int def_ppp_ioctl(int fd, unsigned long request, void *arg)
static int def_sock_ioctl(unsigned long request, void *arg)
{
- return ioctl(sock_fd, request, arg);
-}
-
-__export const struct ap_net def_net = {
- .name = "kernel",
- .socket = def_socket,
- .connect = def_connect,
- .bind = def_bind,
- .listen = def_listen,
- .read = def_read,
- .recvfrom = def_recvfrom,
- .write = def_write,
- .sendto = def_sendto,
- .set_nonblocking = def_set_nonblocking,
- .setsockopt = def_setsockopt,
- .ppp_open = def_ppp_open,
- .ppp_ioctl = def_ppp_ioctl,
- .sock_ioctl = def_sock_ioctl,
-};
+ struct kern_net *n = container_of(net, typeof(*n), net);
-static void __init init()
+ return ioctl(n->sock, request, arg);
+}
+
+static int def_sock6_ioctl(unsigned long request, void *arg)
{
- nets[0] = &def_net;
- net_cnt = 1;
+ struct kern_net *n = container_of(net, typeof(*n), net);
+
+ return ioctl(n->sock6, request, arg);
+}
+
+static void enter_ns()
+{
+ if (net != def_net) {
+ struct kern_net *n = container_of(net, typeof(*n), net);
+ setns(n->ns_fd, CLONE_NEWNET);
+ }
+}
+
+static void exit_ns()
+{
+ if (net != def_net)
+ setns(def_ns_fd, CLONE_NEWNET);
+}
+
+static struct rtnl_handle *def_rtnl_get()
+{
+ struct kern_net *n = container_of(net, typeof(*n), net);
+ struct rtnl_handle *rth = __sync_lock_test_and_set(&n->rth, NULL);
+ int r;
+
+ if (!rth) {
+ rth = _malloc(sizeof(*rth));
+ enter_ns();
+ r = rtnl_open(rth, 0);
+ exit_ns();
+
+ if (r) {
+ _free(rth);
+ return NULL;
+ }
+ }
+
+ return rth;
}
-int __export ap_net_register(const struct ap_net *net)
+static void def_rtnl_put(struct rtnl_handle *rth)
{
- int i;
+ struct kern_net *n = container_of(net, typeof(*n), net);
- if (net_cnt == MAX_NET)
+ if (!__sync_bool_compare_and_swap(&n->rth, NULL, rth)) {
+ rtnl_close(rth);
+ _free(rth);
+ }
+}
+
+static int def_rtnl_open(struct rtnl_handle *rth, int proto)
+{
+ struct kern_net *n = container_of(net, typeof(*n), net);
+ int r;
+
+ enter_ns();
+ r = rtnl_open_byproto(rth, 0, proto);
+ exit_ns();
+
+ return r;
+}
+
+static int def_move_link(struct ap_net *new_net, int ifindex)
+{
+ struct iplink_req {
+ struct nlmsghdr n;
+ struct ifinfomsg i;
+ char buf[1024];
+ } req;
+ struct rtnl_handle *rth = new_net->rtnl_get();
+ struct kern_net *n = container_of(new_net, typeof(*n), net);
+ int r = 0;
+
+ if (!rth)
return -1;
- for (i = 0; i < net_cnt; i++) {
- if (!strcmp(net->name, nets[i]->name))
- 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_SETLINK;
+ req.i.ifi_family = AF_UNSPEC;
+ req.i.ifi_index = ifindex;
+
+ addattr_l(&req.n, 4096, IFLA_NET_NS_FD, &n->ns_fd, sizeof(n->ns_fd));
+
+ //if (setns(n->ns_fd, CLONE_NEWNET))
+ //perror("setns");
+
+ if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
+ r = -1;
+
+ //setns(def_ns_fd, CLONE_NEWNET);
+
+ new_net->rtnl_put(rth);
+
+ return r;
+}
+
+static void def_release(struct ap_net *d)
+{
+ struct kern_net *n = container_of(d, typeof(*n), net);
+
+ if (d == def_net)
+ return;
+
+ pthread_mutex_lock(&nets_lock);
+ if (--d->refs) {
+ pthread_mutex_unlock(&nets_lock);
+ return;
}
- nets[net_cnt++] = net;
+ list_del(&d->entry);
+ pthread_mutex_unlock(&nets_lock);
+
+ net = def_net;
+
+ log_debug("close ns %s\n", n->net.name);
+
+ close(n->sock);
+ close(n->sock6);
+ close(n->ns_fd);
+
+ if (n->rth) {
+ rtnl_close(n->rth);
+ _free(n->rth);
+ }
+
+ _free(n);
+}
+
+static struct ap_net *alloc_net(const char *name)
+{
+ struct kern_net *n;
+ struct ap_net *net;
+ int ns_fd;
+
+ if (name) {
+ char fname[PATH_MAX];
+ sprintf(fname, "%s/%s", conf_netns_run_dir, name);
+ ns_fd = open(fname, O_RDONLY);
+ if (ns_fd == -1) {
+ log_ppp_error("open %s: %s\n", fname, strerror(errno));
+ return NULL;
+ }
+
+ if (setns(ns_fd, CLONE_NEWNET)) {
+ log_ppp_error("setns %s: %s\n", fname, strerror(errno));
+ close(ns_fd);
+ return NULL;
+ }
+ } else
+ def_ns_fd = ns_fd = open("/proc/self/ns/net", O_RDONLY);
+
+ log_debug("open ns %s\n", name);
+
+ n = _malloc(sizeof(*n));
+ net = &n->net;
+
+ net->refs = 1;
+ net->name = name ? _strdup(name) : "def";
+ net->socket = def_socket;
+ net->connect = def_connect;
+ net->bind = def_bind;
+ net->listen = def_listen;
+ net->read = def_read;
+ net->recvfrom = def_recvfrom;
+ net->write = def_write;
+ net->sendto = def_sendto;
+ net->set_nonblocking = def_set_nonblocking;
+ net->setsockopt = def_setsockopt;
+ net->ppp_open = def_ppp_open;
+ net->ppp_ioctl = def_ppp_ioctl;
+ net->sock_ioctl = def_sock_ioctl;
+ net->sock6_ioctl = def_sock6_ioctl;
+ net->enter_ns = enter_ns;
+ net->exit_ns = exit_ns;
+ net->rtnl_get = def_rtnl_get;
+ net->rtnl_put = def_rtnl_put;
+ net->rtnl_open = def_rtnl_open;
+ net->move_link = def_move_link;
+ net->release = def_release;
+
+ n->ns_fd = ns_fd;
+
+ n->sock = socket(AF_INET, SOCK_DGRAM, 0);
+ n->sock6 = socket(AF_INET6, SOCK_DGRAM, 0);
+ n->rth = _malloc(sizeof(*n->rth));
+ rtnl_open(n->rth, 0);
+
+ if (ns_fd != def_ns_fd)
+ setns(def_ns_fd, CLONE_NEWNET);
+
+ list_add_tail(&net->entry, &nets);
+
+ return net;
+};
+
+int __export ap_net_register(struct ap_net *net)
+{
+ pthread_mutex_lock(&nets_lock);
+ list_add_tail(&net->entry, &nets);
+ pthread_mutex_unlock(&nets_lock);
return 0;
}
-__export const struct ap_net *ap_net_find(const char *name)
+static struct ap_net *find_net(const char *name)
{
- int i;
+ struct ap_net *n;
- for (i = 0; i < net_cnt; i++) {
- if (!strcmp(name, nets[i]->name))
- return nets[i];
+ list_for_each_entry(n, &nets, entry) {
+ if (!strcmp(name, n->name)) {
+ n->refs++;
+ return n;
+ }
}
return NULL;
}
+
+__export struct ap_net *ap_net_find(const char *name)
+{
+ struct ap_net *n;
+
+ pthread_mutex_lock(&nets_lock);
+ n = find_net(name);
+ pthread_mutex_unlock(&nets_lock);
+
+ return n;
+}
+
+__export struct ap_net *ap_net_open_ns(const char *name)
+{
+ struct ap_net *n;
+
+ pthread_mutex_lock(&nets_lock);
+ n = find_net(name);
+ if (!n)
+ n = alloc_net(name);
+ pthread_mutex_unlock(&nets_lock);
+
+ return n;
+}
+
+static void __init init()
+{
+ const char *opt;
+
+ opt = conf_get_opt("common", "netns-run-dir");
+ if (opt)
+ conf_netns_run_dir = opt;
+ else
+ conf_netns_run_dir = "/var/run/netns";
+
+ def_net = net = alloc_net(NULL);
+}
+
+DEFINE_INIT(1, init);
diff --git a/accel-pppd/session.c b/accel-pppd/session.c
index ad164f3f..730a57aa 100644
--- a/accel-pppd/session.c
+++ b/accel-pppd/session.c
@@ -62,6 +62,7 @@ void __export ap_session_init(struct ap_session *ses)
INIT_LIST_HEAD(&ses->pd_list);
ses->ifindex = -1;
ses->unit_idx = -1;
+ ses->net = net;
}
void __export ap_session_set_ifindex(struct ap_session *ses)
@@ -235,6 +236,9 @@ void __export ap_session_finished(struct ap_session *ses)
ses->ifname_rename = NULL;
}
+ if (ses->net)
+ ses->net->release(ses->net);
+
if (ses->timer.tpd)
triton_timer_del(&ses->timer);
diff --git a/accel-pppd/shaper/limiter.c b/accel-pppd/shaper/limiter.c
index 738f747e..0945e982 100644
--- a/accel-pppd/shaper/limiter.c
+++ b/accel-pppd/shaper/limiter.c
@@ -455,10 +455,10 @@ static int remove_htb_ifb(struct rtnl_handle *rth, int ifindex, int priority)
int install_limiter(struct ap_session *ses, int down_speed, int down_burst, int up_speed, int up_burst, int idx)
{
- struct rtnl_handle rth;
+ struct rtnl_handle *rth = net->rtnl_get();
int r;
- if (rtnl_open(&rth, 0)) {
+ if (!rth) {
log_ppp_error("shaper: cannot open rtnetlink\n");
return -1;
}
@@ -469,45 +469,45 @@ int install_limiter(struct ap_session *ses, int down_speed, int down_burst, int
up_burst = up_burst ? up_burst : conf_up_burst_factor * up_speed;
if (conf_down_limiter == LIM_TBF)
- r = install_tbf(&rth, ses->ifindex, down_speed, down_burst);
+ r = install_tbf(rth, ses->ifindex, down_speed, down_burst);
else {
- r = install_htb(&rth, ses->ifindex, down_speed, down_burst);
+ r = install_htb(rth, ses->ifindex, down_speed, down_burst);
if (r == 0)
- r = install_leaf_qdisc(&rth, ses->ifindex, 0x00010001, 0x00020000);
+ r = install_leaf_qdisc(rth, ses->ifindex, 0x00010001, 0x00020000);
}
if (conf_up_limiter == LIM_POLICE)
- r = install_police(&rth, ses->ifindex, up_speed, up_burst);
+ r = install_police(rth, ses->ifindex, up_speed, up_burst);
else {
- r = install_htb_ifb(&rth, ses->ifindex, idx, up_speed, up_burst);
+ r = install_htb_ifb(rth, ses->ifindex, idx, up_speed, up_burst);
if (r == 0)
- r = install_leaf_qdisc(&rth, conf_ifb_ifindex, 0x00010000 + idx, idx << 16);
+ r = install_leaf_qdisc(rth, conf_ifb_ifindex, 0x00010000 + idx, idx << 16);
}
if (conf_fwmark)
- install_fwmark(&rth, ses->ifindex, 0x00010000);
+ install_fwmark(rth, ses->ifindex, 0x00010000);
- rtnl_close(&rth);
+ net->rtnl_put(rth);
return r;
}
int remove_limiter(struct ap_session *ses, int idx)
{
- struct rtnl_handle rth;
+ struct rtnl_handle *rth = net->rtnl_get();
- if (rtnl_open(&rth, 0)) {
+ if (!rth) {
log_ppp_error("shaper: cannot open rtnetlink\n");
return -1;
}
- remove_root(&rth, ses->ifindex);
- remove_ingress(&rth, ses->ifindex);
+ remove_root(rth, ses->ifindex);
+ remove_ingress(rth, ses->ifindex);
if (conf_up_limiter == LIM_HTB)
- remove_htb_ifb(&rth, ses->ifindex, idx);
+ remove_htb_ifb(rth, ses->ifindex, idx);
- rtnl_close(&rth);
+ net->rtnl_put(rth);
return 0;
}
@@ -518,6 +518,7 @@ int init_ifb(const char *name)
struct rtattr *tail;
struct ifreq ifr;
int r;
+ int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
struct {
struct nlmsghdr n;
@@ -541,6 +542,7 @@ int init_ifb(const char *name)
if (ioctl(sock_fd, SIOCGIFINDEX, &ifr)) {
log_emerg("shaper: ioctl(SIOCGIFINDEX): %s\n", strerror(errno));
+ close(sock_fd);
return -1;
}
@@ -550,11 +552,13 @@ int init_ifb(const char *name)
if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr)) {
log_emerg("shaper: ioctl(SIOCSIFINDEX): %s\n", strerror(errno));
+ close(sock_fd);
return -1;
}
if (rtnl_open(&rth, 0)) {
log_emerg("shaper: cannot open rtnetlink\n");
+ close(sock_fd);
return -1;
}
@@ -587,6 +591,7 @@ int init_ifb(const char *name)
out:
rtnl_close(&rth);
+ close(sock_fd);
return r;
}