diff options
author | Kozlov Dmitry <xeb@mail.ru> | 2012-06-05 14:24:31 +0400 |
---|---|---|
committer | Kozlov Dmitry <xeb@mail.ru> | 2012-06-05 14:27:57 +0400 |
commit | fa315a7a7584f6f4954888c010e3cc84c2b33330 (patch) | |
tree | 778396449f9e19c52d8b83e7fabdb1c37706e16f /accel-pppd | |
parent | 6f01783f2b67cd0b82805240f2aeea9a39606d65 (diff) | |
download | accel-ppp-fa315a7a7584f6f4954888c010e3cc84c2b33330.tar.gz accel-ppp-fa315a7a7584f6f4954888c010e3cc84c2b33330.zip |
ppp: implemented unit cache
If enabled accel-pppd will not destroy interface immediately after corresponding session is terminated, instead interface will be brought down and placed to cache for later use for new sessions.
It should reduce kernel interface creation/deletion rate lack and increase responsibility of daemon
Diffstat (limited to 'accel-pppd')
-rw-r--r-- | accel-pppd/CMakeLists.txt | 1 | ||||
-rw-r--r-- | accel-pppd/accel-ppp.conf | 6 | ||||
-rw-r--r-- | accel-pppd/accel-ppp.conf.5 | 4 | ||||
-rw-r--r-- | accel-pppd/ppp/ipcp_opt_ipaddr.c | 29 | ||||
-rw-r--r-- | accel-pppd/ppp/ipv6cp_opt_intfid.c | 81 | ||||
-rw-r--r-- | accel-pppd/ppp/ppp.c | 144 | ||||
-rw-r--r-- | accel-pppd/ppp/ppp.h | 3 | ||||
-rw-r--r-- | accel-pppd/ppp/ppp_auth.c | 12 | ||||
-rw-r--r-- | accel-pppd/ppp/ppp_ifcfg.c | 182 | ||||
-rw-r--r-- | accel-pppd/ppp/ppp_ipcp.c | 6 | ||||
-rw-r--r-- | accel-pppd/ppp/ppp_ipv6cp.c | 6 |
11 files changed, 295 insertions, 179 deletions
diff --git a/accel-pppd/CMakeLists.txt b/accel-pppd/CMakeLists.txt index 0702e5e..bfec9e2 100644 --- a/accel-pppd/CMakeLists.txt +++ b/accel-pppd/CMakeLists.txt @@ -43,6 +43,7 @@ ADD_SUBDIRECTORY(shaper) ADD_EXECUTABLE(accel-pppd ppp/ppp.c + ppp/ppp_ifcfg.c ppp/ppp_fsm.c ppp/ppp_lcp.c ppp/lcp_opt_mru.c diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf index 527c2fb..0fd118e 100644 --- a/accel-pppd/accel-ppp.conf +++ b/accel-pppd/accel-ppp.conf @@ -49,8 +49,10 @@ ipv6=deny ipv6-intf-id=0:0:0:1 ipv6-peer-intf-id=0:0:0:2 ipv6-accept-peer-intf-id=1 -lcp-echo-interval=30 -lcp-echo-failure=3 +lcp-echo-interval=20 +#lcp-echo-failure=3 +lcp-echo-timeout=120 +#unit-cache=1000 [auth] #any-login=0 diff --git a/accel-pppd/accel-ppp.conf.5 b/accel-pppd/accel-ppp.conf.5 index 21e5923..046c48e 100644 --- a/accel-pppd/accel-ppp.conf.5 +++ b/accel-pppd/accel-ppp.conf.5 @@ -177,6 +177,10 @@ Specifies maximum number of echo-requests may be sent without valid echo-reply, .BI "lcp-echo-timeout=" sec Specifies timeout in seconds to wait for any peer activity. If this option specified it turns on adaptive lcp echo functionality and "lcp-echo-failure" is not used. .TP +.BI "unit-cache=" n +Specifies number of interfaces to keep in cache. It means that don't destory interface after corresponding session is destoyed, instead place it to cache and use it later for new sessions repeatedly. +This should reduce kernel-level interface creation/deletion rate lack. +.TP .SH [dns] .TP .BI "dns1=" x.x.x.x diff --git a/accel-pppd/ppp/ipcp_opt_ipaddr.c b/accel-pppd/ppp/ipcp_opt_ipaddr.c index 1455744..e965f5c 100644 --- a/accel-pppd/ppp/ipcp_opt_ipaddr.c +++ b/accel-pppd/ppp/ipcp_opt_ipaddr.c @@ -58,8 +58,10 @@ static void ipaddr_free(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt) { struct ipaddr_option_t *ipaddr_opt = container_of(opt, typeof(*ipaddr_opt), opt); - if (ipcp->ppp->ipv4) + if (ipcp->ppp->ipv4) { ipdb_put_ipv4(ipcp->ppp, ipcp->ppp->ipv4); + ipcp->ppp->ipv4 = NULL; + } _free(ipaddr_opt); } @@ -137,8 +139,6 @@ static int ipaddr_recv_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *o { struct ipaddr_option_t *ipaddr_opt = container_of(opt, typeof(*ipaddr_opt), opt); struct ipcp_opt32_t *opt32 = (struct ipcp_opt32_t *)ptr; - struct ifreq ifr; - struct sockaddr_in addr; int r; if (!ipcp->ppp->ipv4) { @@ -152,31 +152,10 @@ static int ipaddr_recv_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *o if (ipcp->ppp->ipv4->peer_addr == opt32->val) { ipcp->delay_ack = ccp_ipcp_started(ipcp->ppp); - goto ack; + return IPCP_OPT_ACK; } return IPCP_OPT_NAK; - -ack: - memset(&ifr, 0, sizeof(ifr)); - memset(&addr, 0, sizeof(addr)); - - strcpy(ifr.ifr_name, ipcp->ppp->ifname); - - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = ipcp->ppp->ipv4->addr; - memcpy(&ifr.ifr_addr,&addr,sizeof(addr)); - - if (ioctl(sock_fd, SIOCSIFADDR, &ifr)) - log_ppp_error("ipcp: failed to set PA address: %s\n", strerror(errno)); - - addr.sin_addr.s_addr = ipcp->ppp->ipv4->peer_addr; - memcpy(&ifr.ifr_dstaddr,&addr,sizeof(addr)); - - if (ioctl(sock_fd, SIOCSIFDSTADDR, &ifr)) - log_ppp_error("ipcp: failed to set remote PA address: %s\n", strerror(errno)); - - return IPCP_OPT_ACK; } static void ipaddr_print(void (*print)(const char *fmt,...),struct ipcp_option_t *opt, uint8_t *ptr) diff --git a/accel-pppd/ppp/ipv6cp_opt_intfid.c b/accel-pppd/ppp/ipv6cp_opt_intfid.c index 0d3d751..9a2ddee 100644 --- a/accel-pppd/ppp/ipv6cp_opt_intfid.c +++ b/accel-pppd/ppp/ipv6cp_opt_intfid.c @@ -30,13 +30,6 @@ static int conf_peer_intf_id = INTF_ID_FIXED; static uint64_t conf_peer_intf_id_val = 2; static int conf_accept_peer_intf_id; -// from /usr/include/linux/ipv6.h -struct in6_ifreq { - struct in6_addr ifr6_addr; - __u32 ifr6_prefixlen; - int ifr6_ifindex; -}; - static struct ipv6cp_option_t *ipaddr_init(struct ppp_ipv6cp_t *ipv6cp); static void ipaddr_free(struct ppp_ipv6cp_t *ipv6cp, struct ipv6cp_option_t *opt); static int ipaddr_send_conf_req(struct ppp_ipv6cp_t *ipv6cp, struct ipv6cp_option_t *opt, uint8_t *ptr); @@ -79,8 +72,10 @@ static void ipaddr_free(struct ppp_ipv6cp_t *ipv6cp, struct ipv6cp_option_t *opt { struct ipaddr_option_t *ipaddr_opt=container_of(opt,typeof(*ipaddr_opt),opt); - if (ipv6cp->ppp->ipv6) + if (ipv6cp->ppp->ipv6) { ipdb_put_ipv6(ipv6cp->ppp, ipv6cp->ppp->ipv6); + ipv6cp->ppp->ipv6 = NULL; + } _free(ipaddr_opt); } @@ -211,39 +206,10 @@ static int ipaddr_send_conf_nak(struct ppp_ipv6cp_t *ipv6cp, struct ipv6cp_optio return 10; } -static void devconf(struct ppp_t *ppp, const char *attr, const char *val) -{ - int fd; - char fname[PATH_MAX]; - - sprintf(fname, "/proc/sys/net/ipv6/conf/%s/%s", ppp->ifname, attr); - fd = open(fname, O_WRONLY); - if (!fd) { - log_ppp_error("ppp:ipv6cp: failed to open '%s': %s\n", fname, strerror(errno)); - return; - } - - write(fd, val, strlen(val)); - - close(fd); -} - -static void build_addr(struct ipv6db_addr_t *a, uint64_t intf_id, struct in6_addr *addr) -{ - memcpy(addr, &a->addr, sizeof(*addr)); - - if (a->prefix_len <= 64) - *(uint64_t *)(addr->s6_addr + 8) = intf_id; - else - *(uint64_t *)(addr->s6_addr + 8) |= intf_id & ((1 << (128 - a->prefix_len)) - 1); -} - static int ipaddr_recv_conf_req(struct ppp_ipv6cp_t *ipv6cp, struct ipv6cp_option_t *opt, uint8_t *ptr) { struct ipaddr_option_t *ipaddr_opt = container_of(opt, typeof(*ipaddr_opt), opt); struct ipv6cp_opt64_t *opt64 = (struct ipv6cp_opt64_t* )ptr; - struct in6_ifreq ifr6; - struct ipv6db_addr_t *a; int r; if (opt64->hdr.len != 10) @@ -265,48 +231,11 @@ static int ipaddr_recv_conf_req(struct ppp_ipv6cp_t *ipv6cp, struct ipv6cp_optio if (opt64->val && ipv6cp->ppp->ipv6->peer_intf_id == opt64->val && opt64->val != ipv6cp->ppp->ipv6->intf_id) { ipv6cp->delay_ack = ccp_ipcp_started(ipv6cp->ppp); - goto ack; + ipaddr_opt->started = 1; + return IPV6CP_OPT_ACK; } return IPV6CP_OPT_NAK; - -ack: - if (ipaddr_opt->started) - return IPV6CP_OPT_ACK; - - ipaddr_opt->started = 1; - - devconf(ipv6cp->ppp, "accept_ra", "0"); - devconf(ipv6cp->ppp, "autoconf", "0"); - devconf(ipv6cp->ppp, "forwarding", "1"); - - memset(&ifr6, 0, sizeof(ifr6)); - ifr6.ifr6_addr.s6_addr32[0] = htons(0xfe80); - *(uint64_t *)(ifr6.ifr6_addr.s6_addr + 8) = ipv6cp->ppp->ipv6->intf_id; - ifr6.ifr6_prefixlen = 64; - ifr6.ifr6_ifindex = ipv6cp->ppp->ifindex; - - if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6)) { - log_ppp_error("ppp:ipv6cp: ioctl(SIOCSIFADDR): %s\n", strerror(errno)); - return IPV6CP_OPT_REJ; - } - - list_for_each_entry(a, &ipv6cp->ppp->ipv6->addr_list, entry) { - if (a->prefix_len == 128) - continue; - - build_addr(a, ipv6cp->ppp->ipv6->intf_id, &ifr6.ifr6_addr); - ifr6.ifr6_prefixlen = a->prefix_len; - - if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6)) { - log_ppp_error("ppp:ipv6cp: ioctl(SIOCSIFADDR): %s\n", strerror(errno)); - return IPV6CP_OPT_REJ; - } - - - } - - return IPV6CP_OPT_ACK; } static void ipaddr_print(void (*print)(const char *fmt,...), struct ipv6cp_option_t *opt, uint8_t *ptr) diff --git a/accel-pppd/ppp/ppp.c b/accel-pppd/ppp/ppp.c index 4f3beb9..814240c 100644 --- a/accel-pppd/ppp/ppp.c +++ b/accel-pppd/ppp/ppp.c @@ -5,10 +5,11 @@ #include <stdint.h> #include <string.h> #include <errno.h> -#include <sys/ioctl.h> #include <arpa/inet.h> #include <features.h> #include <signal.h> +#include <sys/socket.h> +#include <sys/ioctl.h> #include "linux_ppp.h" #include "crypto.h" @@ -18,6 +19,7 @@ #include "events.h" #include "ppp.h" #include "ppp_fsm.h" +#include "ipdb.h" #include "log.h" #include "spinlock.h" #include "mempool.h" @@ -27,6 +29,7 @@ int __export conf_ppp_verbose; int conf_sid_ucase; int conf_single_session = -1; +int conf_unit_cache = 0; pthread_rwlock_t __export ppp_lock = PTHREAD_RWLOCK_INITIALIZER; __export LIST_HEAD(ppp_list); @@ -55,6 +58,18 @@ struct layer_node_t struct list_head items; }; +struct pppunit_cache +{ + struct list_head entry; + int fd; + int unit_idx; +}; + +static pthread_mutex_t uc_lock = PTHREAD_MUTEX_INITIALIZER; +static LIST_HEAD(uc_list); +static int uc_size; +static mempool_t uc_pool; + static int ppp_chan_read(struct triton_md_handler_t*); static int ppp_unit_read(struct triton_md_handler_t*); static void init_layers(struct ppp_t *); @@ -68,6 +83,9 @@ void __export ppp_init(struct ppp_t *ppp) INIT_LIST_HEAD(&ppp->chan_handlers); INIT_LIST_HEAD(&ppp->unit_handlers); INIT_LIST_HEAD(&ppp->pd_list); + ppp->fd = -1; + ppp->chan_fd = -1; + ppp->unit_fd = -1; } static void generate_sessionid(struct ppp_t *ppp) @@ -91,6 +109,7 @@ static void generate_sessionid(struct ppp_t *ppp) int __export establish_ppp(struct ppp_t *ppp) { struct ifreq ifr; + struct pppunit_cache *uc = NULL; /* Open an instance of /dev/ppp and connect the channel to it */ if (ioctl(ppp->fd, PPPIOCGCHAN, &ppp->chan_idx) == -1) { @@ -111,18 +130,39 @@ int __export establish_ppp(struct ppp_t *ppp) goto exit_close_chan; } - ppp->unit_fd = open("/dev/ppp", O_RDWR); - if (ppp->unit_fd < 0) { - log_ppp_error("open(unit) /dev/ppp: %s\n", strerror(errno)); - goto exit_close_chan; + if (uc_size) { + pthread_mutex_lock(&uc_lock); + if (!list_empty(&uc_list)) { + uc = list_entry(uc_list.next, typeof(*uc), entry); + list_del(&uc->entry); + --uc_size; + } + pthread_mutex_unlock(&uc_lock); } - - fcntl(ppp->unit_fd, F_SETFD, fcntl(ppp->unit_fd, F_GETFD) | FD_CLOEXEC); - ppp->unit_idx = -1; - if (ioctl(ppp->unit_fd, PPPIOCNEWUNIT, &ppp->unit_idx) < 0) { - log_ppp_error("ioctl(PPPIOCNEWUNIT): %s\n", strerror(errno)); - goto exit_close_unit; + if (uc) { + ppp->unit_fd = uc->fd; + ppp->unit_idx = uc->unit_idx; + mempool_free(uc); + } else { + ppp->unit_fd = open("/dev/ppp", O_RDWR); + if (ppp->unit_fd < 0) { + log_ppp_error("open(unit) /dev/ppp: %s\n", strerror(errno)); + goto exit_close_chan; + } + + fcntl(ppp->unit_fd, F_SETFD, fcntl(ppp->unit_fd, F_GETFD) | FD_CLOEXEC); + + ppp->unit_idx = -1; + if (ioctl(ppp->unit_fd, PPPIOCNEWUNIT, &ppp->unit_idx) < 0) { + log_ppp_error("ioctl(PPPIOCNEWUNIT): %s\n", strerror(errno)); + goto exit_close_unit; + } + + if (fcntl(ppp->unit_fd, F_SETFL, O_NONBLOCK)) { + log_ppp_error("ppp: cann't to set nonblocking mode: %s\n", strerror(errno)); + goto exit_close_unit; + } } if (ioctl(ppp->chan_fd, PPPIOCCONNECT, &ppp->unit_idx) < 0) { @@ -135,11 +175,6 @@ int __export establish_ppp(struct ppp_t *ppp) goto exit_close_unit; } - if (fcntl(ppp->unit_fd, F_SETFL, O_NONBLOCK)) { - log_ppp_error("ppp: cann't to set nonblocking mode: %s\n", strerror(errno)); - goto exit_close_unit; - } - ppp->start_time = time(NULL); generate_sessionid(ppp); sprintf(ppp->ifname, "ppp%i", ppp->unit_idx); @@ -202,6 +237,8 @@ exit_close_chan: static void destablish_ppp(struct ppp_t *ppp) { + struct pppunit_cache *uc; + triton_event_fire(EV_PPP_PRE_FINISHED, ppp); pthread_rwlock_wrlock(&ppp_lock); @@ -223,7 +260,18 @@ static void destablish_ppp(struct ppp_t *ppp) triton_md_unregister_handler(&ppp->chan_hnd); triton_md_unregister_handler(&ppp->unit_hnd); - close(ppp->unit_fd); + if (uc_size < conf_unit_cache) { + uc = mempool_alloc(uc_pool); + uc->fd = ppp->unit_fd; + uc->unit_idx = ppp->unit_idx; + + pthread_mutex_lock(&uc_lock); + list_add_tail(&uc->entry, &uc_list); + ++uc_size; + pthread_mutex_unlock(&uc_lock); + } else + close(ppp->unit_fd); + close(ppp->chan_fd); close(ppp->fd); @@ -356,13 +404,15 @@ cont: return 0; } - //printf("ppp_unit_read: "); + //printf("ppp_unit_read: %i\n", ppp->buf_size); + if (ppp->buf_size == 0) + return 0; //print_buf(ppp->buf,ppp->buf_size); - if (ppp->buf_size == 0) { + /*if (ppp->buf_size == 0) { ppp_terminate(ppp, TERM_NAS_ERROR, 1); return 1; - } + }*/ if (ppp->buf_size < 2) { log_ppp_error("ppp_unit_read: short read %i\n", ppp->buf_size); @@ -406,51 +456,6 @@ void ppp_recv_proto_rej(struct ppp_t *ppp, uint16_t proto) } } -static void ppp_ifup(struct ppp_t *ppp) -{ - struct ifreq ifr; - struct npioctl np; - - triton_event_fire(EV_PPP_ACCT_START, ppp); - if (ppp->stop_time) - return; - - triton_event_fire(EV_PPP_PRE_UP, ppp); - if (ppp->stop_time) - return; - - memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, ppp->ifname); - - if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr)) - log_ppp_error("ppp: failed to get interface flags: %s\n", strerror(errno)); - - ifr.ifr_flags |= IFF_UP | IFF_POINTOPOINT; - - if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr)) - log_ppp_error("ppp: failed to set interface flags: %s\n", strerror(errno)); - - if (ppp->ipv4) { - np.protocol = PPP_IP; - np.mode = NPMODE_PASS; - - if (ioctl(ppp->unit_fd, PPPIOCSNPMODE, &np)) - log_ppp_error("ppp: failed to set NP (IPv4) mode: %s\n", strerror(errno)); - } - - if (ppp->ipv6) { - np.protocol = PPP_IPV6; - np.mode = NPMODE_PASS; - - if (ioctl(ppp->unit_fd, PPPIOCSNPMODE, &np)) - log_ppp_error("ppp: failed to set NP (IPv6) mode: %s\n", strerror(errno)); - } - - ppp->ctrl->started(ppp); - - triton_event_fire(EV_PPP_STARTED, ppp); -} - static void __ppp_layer_started(struct ppp_t *ppp, struct ppp_layer_data_t *d) { struct layer_node_t *n = d->node; @@ -553,6 +558,8 @@ void __export ppp_terminate(struct ppp_t *ppp, int cause, int hard) log_ppp_debug("ppp_terminate\n"); + ppp_ifdown(ppp); + triton_event_fire(EV_PPP_FINISHING, ppp); if (hard) { @@ -749,6 +756,12 @@ static void load_config(void) conf_single_session = 1; } else conf_single_session = -1; + + opt = conf_get_opt("ppp", "unit-cache"); + if (opt && atoi(opt) > 0) + conf_unit_cache = atoi(opt); + else + conf_unit_cache = 0; } static void init(void) @@ -757,6 +770,7 @@ static void init(void) FILE *f; buf_pool = mempool_create(PPP_MRU); + uc_pool = mempool_create(sizeof(struct pppunit_cache)); sock_fd = socket(AF_INET, SOCK_DGRAM, 0); if (sock_fd < 0) { diff --git a/accel-pppd/ppp/ppp.h b/accel-pppd/ppp/ppp.h index f831242..e37c75d 100644 --- a/accel-pppd/ppp/ppp.h +++ b/accel-pppd/ppp/ppp.h @@ -181,6 +181,9 @@ int ppp_unit_send(struct ppp_t *ppp, void *data, int size); void lcp_send_proto_rej(struct ppp_t *ppp, uint16_t proto); void ppp_recv_proto_rej(struct ppp_t *ppp, uint16_t proto); +void ppp_ifup(struct ppp_t *ppp); +void ppp_ifdown(struct ppp_t *ppp); + struct ppp_fsm_t* ppp_lcp_init(struct ppp_t *ppp); void ppp_layer_started(struct ppp_t *ppp,struct ppp_layer_data_t*); void ppp_layer_finished(struct ppp_t *ppp,struct ppp_layer_data_t*); diff --git a/accel-pppd/ppp/ppp_auth.c b/accel-pppd/ppp/ppp_auth.c index f78b652..7603d8c 100644 --- a/accel-pppd/ppp/ppp_auth.c +++ b/accel-pppd/ppp/ppp_auth.c @@ -337,16 +337,6 @@ static void __ppp_auth_started(struct ppp_t *ppp) triton_event_fire(EV_PPP_AUTHORIZED, ppp); } -static void ifdown(struct ppp_t *ppp) -{ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, ppp->ifname); - - ioctl(sock_fd, SIOCSIFFLAGS, &ifr); -} - int __export ppp_auth_successed(struct ppp_t *ppp, char *username) { struct ppp_t *p; @@ -362,7 +352,7 @@ int __export ppp_auth_successed(struct ppp_t *ppp, char *username) return -1; } else { if (conf_single_session == 1) { - ifdown(p); + ppp_ifdown(p); triton_context_call(p->ctrl->ctx, (triton_event_func)ppp_terminate_sec, p); } } diff --git a/accel-pppd/ppp/ppp_ifcfg.c b/accel-pppd/ppp/ppp_ifcfg.c new file mode 100644 index 0000000..f916251 --- /dev/null +++ b/accel-pppd/ppp/ppp_ifcfg.c @@ -0,0 +1,182 @@ +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <limits.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include "linux_ppp.h" + +#include "triton.h" +#include "events.h" +#include "ppp.h" +#include "ipdb.h" +#include "log.h" + +// from /usr/include/linux/ipv6.h +struct in6_ifreq { + struct in6_addr ifr6_addr; + __u32 ifr6_prefixlen; + int ifr6_ifindex; +}; + +static void devconf(struct ppp_t *ppp, const char *attr, const char *val) +{ + int fd; + char fname[PATH_MAX]; + + sprintf(fname, "/proc/sys/net/ipv6/conf/%s/%s", ppp->ifname, attr); + fd = open(fname, O_WRONLY); + if (!fd) { + log_ppp_error("ppp: failed to open '%s': %s\n", fname, strerror(errno)); + return; + } + + write(fd, val, strlen(val)); + + close(fd); +} + +static void build_addr(struct ipv6db_addr_t *a, uint64_t intf_id, struct in6_addr *addr) +{ + memcpy(addr, &a->addr, sizeof(*addr)); + + if (a->prefix_len <= 64) + *(uint64_t *)(addr->s6_addr + 8) = intf_id; + else + *(uint64_t *)(addr->s6_addr + 8) |= intf_id & ((1 << (128 - a->prefix_len)) - 1); +} + +void ppp_ifup(struct ppp_t *ppp) +{ + struct ipv6db_addr_t *a; + struct ifreq ifr; + struct in6_ifreq ifr6; + struct npioctl np; + struct sockaddr_in addr; + + triton_event_fire(EV_PPP_ACCT_START, ppp); + if (ppp->stop_time) + return; + + triton_event_fire(EV_PPP_PRE_UP, ppp); + if (ppp->stop_time) + return; + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, ppp->ifname); + + if (ppp->ipv4) { + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = ppp->ipv4->addr; + memcpy(&ifr.ifr_addr,&addr,sizeof(addr)); + + if (ioctl(sock_fd, SIOCSIFADDR, &ifr)) + log_ppp_error("ppp: failed to set IPv4 address: %s\n", strerror(errno)); + + addr.sin_addr.s_addr = ppp->ipv4->peer_addr; + memcpy(&ifr.ifr_dstaddr,&addr,sizeof(addr)); + + if (ioctl(sock_fd, SIOCSIFDSTADDR, &ifr)) + log_ppp_error("ppp: failed to set peer IPv4 address: %s\n", strerror(errno)); + } + + if (ppp->ipv6) { + devconf(ppp, "accept_ra", "0"); + devconf(ppp, "autoconf", "0"); + devconf(ppp, "forwarding", "1"); + + memset(&ifr6, 0, sizeof(ifr6)); + ifr6.ifr6_addr.s6_addr32[0] = htons(0xfe80); + *(uint64_t *)(ifr6.ifr6_addr.s6_addr + 8) = ppp->ipv6->intf_id; + ifr6.ifr6_prefixlen = 64; + ifr6.ifr6_ifindex = ppp->ifindex; + + if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6)) + log_ppp_error("ppp: faild to set LL IPv6 address: %s\n", strerror(errno)); + + list_for_each_entry(a, &ppp->ipv6->addr_list, entry) { + if (a->prefix_len == 128) + continue; + + build_addr(a, ppp->ipv6->intf_id, &ifr6.ifr6_addr); + ifr6.ifr6_prefixlen = a->prefix_len; + + if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6)) + log_ppp_error("ppp: failed to add IPv6 address: %s\n", strerror(errno)); + } + } + + if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr)) + log_ppp_error("ppp: failed to get interface flags: %s\n", strerror(errno)); + + ifr.ifr_flags |= IFF_UP | IFF_POINTOPOINT; + + if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr)) + log_ppp_error("ppp: failed to set interface flags: %s\n", strerror(errno)); + + if (ppp->ipv4) { + np.protocol = PPP_IP; + np.mode = NPMODE_PASS; + + if (ioctl(ppp->unit_fd, PPPIOCSNPMODE, &np)) + log_ppp_error("ppp: failed to set NP (IPv4) mode: %s\n", strerror(errno)); + } + + if (ppp->ipv6) { + np.protocol = PPP_IPV6; + np.mode = NPMODE_PASS; + + if (ioctl(ppp->unit_fd, PPPIOCSNPMODE, &np)) + log_ppp_error("ppp: failed to set NP (IPv6) mode: %s\n", strerror(errno)); + } + + ppp->ctrl->started(ppp); + + triton_event_fire(EV_PPP_STARTED, ppp); +} + +void __export ppp_ifdown(struct ppp_t *ppp) +{ + struct ifreq ifr; + struct sockaddr_in addr; + struct in6_ifreq ifr6; + struct ipv6db_addr_t *a; + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, ppp->ifname); + ioctl(sock_fd, SIOCSIFFLAGS, &ifr); + + if (ppp->ipv4) { + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + memcpy(&ifr.ifr_addr,&addr,sizeof(addr)); + ioctl(sock_fd, SIOCSIFADDR, &ifr); + } + + if (ppp->ipv6) { + memset(&ifr6, 0, sizeof(ifr6)); + ifr6.ifr6_addr.s6_addr32[0] = htons(0xfe80); + *(uint64_t *)(ifr6.ifr6_addr.s6_addr + 8) = ppp->ipv6->intf_id; + ifr6.ifr6_prefixlen = 64; + ifr6.ifr6_ifindex = ppp->ifindex; + + ioctl(sock6_fd, SIOCDIFADDR, &ifr6); + + list_for_each_entry(a, &ppp->ipv6->addr_list, entry) { + if (a->prefix_len == 128) + continue; + + build_addr(a, ppp->ipv6->intf_id, &ifr6.ifr6_addr); + ifr6.ifr6_prefixlen = a->prefix_len; + + ioctl(sock6_fd, SIOCDIFADDR, &ifr6); + } + } +} + diff --git a/accel-pppd/ppp/ppp_ipcp.c b/accel-pppd/ppp/ppp_ipcp.c index 625358a..9ec92d4 100644 --- a/accel-pppd/ppp/ppp_ipcp.c +++ b/accel-pppd/ppp/ppp_ipcp.c @@ -11,6 +11,7 @@ #include "ppp.h" #include "ppp_ipcp.h" +#include "ipdb.h" #include "memdebug.h" @@ -208,6 +209,11 @@ static void ipcp_layer_finished(struct ppp_fsm_t *fsm) ppp_terminate(ipcp->ppp, TERM_USER_ERROR, 0); fsm->fsm_state = FSM_Closed; + + if (ipcp->ppp->ipv4) { + ipdb_put_ipv4(ipcp->ppp, ipcp->ppp->ipv4); + ipcp->ppp->ipv4 = NULL; + } } static void ipcp_layer_down(struct ppp_fsm_t *fsm) diff --git a/accel-pppd/ppp/ppp_ipv6cp.c b/accel-pppd/ppp/ppp_ipv6cp.c index ffffa1e..9e7bf78 100644 --- a/accel-pppd/ppp/ppp_ipv6cp.c +++ b/accel-pppd/ppp/ppp_ipv6cp.c @@ -11,6 +11,7 @@ #include "ppp.h" #include "ppp_ipv6cp.h" +#include "ipdb.h" #include "memdebug.h" @@ -208,6 +209,11 @@ static void ipv6cp_layer_finished(struct ppp_fsm_t *fsm) ppp_terminate(ipv6cp->ppp, TERM_USER_ERROR, 0); fsm->fsm_state = FSM_Closed; + + if (ipv6cp->ppp->ipv6) { + ipdb_put_ipv6(ipv6cp->ppp, ipv6cp->ppp->ipv6); + ipv6cp->ppp->ipv6 = NULL; + } } static void ipv6cp_layer_down(struct ppp_fsm_t *fsm) |