summaryrefslogtreecommitdiff
path: root/accel-pppd/ctrl/ipoe/ipoe.c
diff options
context:
space:
mode:
authorDmitry Kozlov <xeb@mail.ru>2016-11-29 22:19:52 +0300
committerDmitry Kozlov <xeb@mail.ru>2016-11-29 22:19:52 +0300
commit8557ca019041374d43712506eecc21479f83b9e6 (patch)
tree92bb6ffd66129da92250e54d7f143aeed1f78cdb /accel-pppd/ctrl/ipoe/ipoe.c
parent01a985316d5240e7a2ba9ba683493cc015282d8a (diff)
downloadaccel-ppp-8557ca019041374d43712506eecc21479f83b9e6.tar.gz
accel-ppp-8557ca019041374d43712506eecc21479f83b9e6.zip
ipoe: apply offer-delay rules to arp initiated sessions
Diffstat (limited to 'accel-pppd/ctrl/ipoe/ipoe.c')
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c121
1 files changed, 108 insertions, 13 deletions
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index 5a150082..a969894c 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.c
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -7,6 +7,7 @@
#include <fcntl.h>
#include <assert.h>
#include <time.h>
+#include <limits.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <net/ethernet.h>
@@ -14,6 +15,7 @@
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>
+#include <linux/if_arp.h>
#include <linux/route.h>
#include <pcre.h>
@@ -76,6 +78,12 @@ struct disc_item {
struct timespec ts;
};
+struct arp_item {
+ struct list_head entry;
+ struct timespec ts;
+ struct _arphdr arph;
+};
+
struct delay {
struct list_head entry;
unsigned int conn_cnt;
@@ -166,6 +174,7 @@ static unsigned int stat_delayed_offer;
static mempool_t ses_pool;
static mempool_t disc_item_pool;
+static mempool_t arp_item_pool;
static mempool_t req_item_pool;
static int connlimit_loaded;
@@ -200,6 +209,7 @@ static int ipoe_rad_send_auth_request(struct rad_plugin_t *rad, struct rad_packe
static int ipoe_rad_send_acct_request(struct rad_plugin_t *rad, struct rad_packet_t *pack);
static void ipoe_session_create_auto(struct ipoe_serv *serv);
static void ipoe_serv_timeout(struct triton_timer_t *t);
+static struct ipoe_session *ipoe_session_create_up(struct ipoe_serv *serv, struct ethhdr *eth, struct iphdr *iph, struct _arphdr *arph);
static void ipoe_ctx_switch(struct triton_context_t *ctx, void *arg)
{
@@ -727,7 +737,7 @@ static void send_arp_reply(struct ipoe_serv *serv, struct _arphdr *arph)
memcpy(arph->ar_sha, serv->hwaddr, ETH_ALEN);
arph->ar_tpa = arph->ar_spa;
arph->ar_spa = tpa;
- arp_send(serv->ifindex, arph);
+ arp_send(serv->ifindex, arph, 1);
}
static void __ipoe_session_start(struct ipoe_session *ses)
@@ -1449,36 +1459,79 @@ static void ipoe_ses_recv_dhcpv4_request(struct dhcpv4_packet *pack)
static void ipoe_serv_disc_timer(struct triton_timer_t *t)
{
struct ipoe_serv *serv = container_of(t, typeof(*serv), disc_timer);
- struct disc_item *d;
struct timespec ts;
- int delay, offer_delay;
+ int delay, delay1 = INT_MAX, delay2 = INT_MAX, offer_delay;
clock_gettime(CLOCK_MONOTONIC, &ts);
while (!list_empty(&serv->disc_list)) {
- d = list_entry(serv->disc_list.next, typeof(*d), entry);
+ struct disc_item *d = list_entry(serv->disc_list.next, typeof(*d), entry);
delay = (ts.tv_sec - d->ts.tv_sec) * 1000 + (ts.tv_nsec - d->ts.tv_nsec) / 1000000;
offer_delay = get_offer_delay();
if (delay < offer_delay - 1) {
- delay = offer_delay - delay;
- t->expire_tv.tv_sec = delay / 1000;
- t->expire_tv.tv_usec = (delay % 1000) * 1000;
- triton_timer_mod(t, 0);
- return;
+ delay1 = delay;
+ break;
}
__ipoe_recv_dhcpv4(serv->dhcpv4, d->pack, 1);
+ dhcpv4_packet_free(d->pack);
list_del(&d->entry);
- dhcpv4_packet_free(d->pack);
mempool_free(d);
__sync_sub_and_fetch(&stat_delayed_offer, 1);
}
- triton_timer_del(t);
+ while (!list_empty(&serv->arp_list)) {
+ struct arp_item *d = list_entry(serv->arp_list.next, typeof(*d), entry);
+
+ delay = (ts.tv_sec - d->ts.tv_sec) * 1000 + (ts.tv_nsec - d->ts.tv_nsec) / 1000000;
+ offer_delay = get_offer_delay();
+
+ if (delay < offer_delay - 1) {
+ delay2 = delay;
+ break;
+ }
+
+ ipoe_session_create_up(serv, NULL, NULL, &d->arph);
+
+ list_del(&d->entry);
+ mempool_free(d);
+
+ __sync_sub_and_fetch(&stat_delayed_offer, 1);
+ }
+
+ if (list_empty(&serv->disc_list) && list_empty(&serv->arp_list))
+ triton_timer_del(t);
+ else {
+ delay = delay1 < delay2 ? delay1 : delay2;
+ delay = offer_delay - delay;
+ t->expire_tv.tv_sec = delay / 1000;
+ t->expire_tv.tv_usec = (delay % 1000) * 1000;
+ triton_timer_mod(t, 0);
+ }
+}
+
+static void ipoe_serv_add_disc_arp(struct ipoe_serv *serv, struct _arphdr *arph, int offer_delay)
+{
+ struct arp_item *d = mempool_alloc(arp_item_pool);
+
+ if (!d)
+ return;
+
+ __sync_add_and_fetch(&stat_delayed_offer, 1);
+
+ memcpy(&d->arph, arph, sizeof(*arph));
+ clock_gettime(CLOCK_MONOTONIC, &d->ts);
+ list_add_tail(&d->entry, &serv->arp_list);
+
+ if (!serv->disc_timer.tpd) {
+ serv->disc_timer.expire_tv.tv_sec = offer_delay / 1000;
+ serv->disc_timer.expire_tv.tv_usec = (offer_delay % 1000) * 1000;
+ triton_timer_add(&serv->ctx, &serv->disc_timer, 0);
+ }
}
static void ipoe_serv_add_disc(struct ipoe_serv *serv, struct dhcpv4_packet *pack, int offer_delay)
@@ -1988,6 +2041,39 @@ void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph, struct _ar
pthread_mutex_unlock(&serv_lock);
}
+void ipoe_serv_recv_arp(struct ipoe_serv *serv, struct _arphdr *arph)
+{
+ struct arp_item *d;
+
+ if (arph->ar_op == htons(ARPOP_REQUEST)) {
+ int offer_delay = get_offer_delay();
+
+ if (offer_delay == -1)
+ return;
+
+ list_for_each_entry(d, &serv->arp_list, entry) {
+ if (d->arph.ar_spa == arph->ar_spa)
+ return;
+ }
+
+ if (offer_delay)
+ ipoe_serv_add_disc_arp(serv, arph, offer_delay);
+ else
+ ipoe_session_create_up(serv, NULL, NULL, arph);
+ } else {
+ list_for_each_entry(d, &serv->arp_list, entry) {
+ if (d->arph.ar_spa == arph->ar_tpa) {
+ list_del(&d->entry);
+ mempool_free(d);
+
+ __sync_sub_and_fetch(&stat_delayed_offer, 1);
+
+ break;
+ }
+ }
+ }
+}
+
#ifdef RADIUS
static void ev_radius_access_accept(struct ev_radius_t *ev)
{
@@ -2173,6 +2259,13 @@ static void ipoe_serv_release(struct ipoe_serv *serv)
__sync_sub_and_fetch(&stat_delayed_offer, 1);
}
+ while (!list_empty(&serv->arp_list)) {
+ struct arp_item *d = list_entry(serv->arp_list.next, typeof(*d), entry);
+ list_del(&d->entry);
+ mempool_free(d);
+ __sync_sub_and_fetch(&stat_delayed_offer, 1);
+ }
+
while (!list_empty(&serv->req_list)) {
struct request_item *r = list_first_entry(&serv->req_list, typeof(*r), entry);
list_del(&r->entry);
@@ -2637,10 +2730,10 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int
if (!serv->dhcpv4_relay && serv->opt_dhcpv4 && opt_relay)
serv->dhcpv4_relay = dhcpv4_relay_create(opt_relay, opt_giaddr, &serv->ctx, (triton_event_func)ipoe_recv_dhcpv4_relay);
- if (serv->arp && !conf_arp) {
+ if (serv->arp && !opt_arp && !opt_up) {
arpd_stop(serv->arp);
serv->arp = NULL;
- } else if (!serv->arp && conf_arp)
+ } else if (!serv->arp && (opt_arp || opt_up))
serv->arp = arpd_start(serv);
serv->opt_up = opt_up;
@@ -2744,6 +2837,7 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int
serv->active = 1;
INIT_LIST_HEAD(&serv->sessions);
INIT_LIST_HEAD(&serv->disc_list);
+ INIT_LIST_HEAD(&serv->arp_list);
INIT_LIST_HEAD(&serv->req_list);
memcpy(serv->hwaddr, hwaddr, ETH_ALEN);
serv->disc_timer.expire = ipoe_serv_disc_timer;
@@ -3563,6 +3657,7 @@ static void ipoe_init(void)
{
ses_pool = mempool_create(sizeof(struct ipoe_session));
disc_item_pool = mempool_create(sizeof(struct disc_item));
+ arp_item_pool = mempool_create(sizeof(struct arp_item));
req_item_pool = mempool_create(sizeof(struct request_item));
uc_pool = mempool_create(sizeof(struct unit_cache));