From 4f511651b830aabc251eee01cb90ace822578053 Mon Sep 17 00:00:00 2001 From: Dmitry Kozlov Date: Mon, 23 Nov 2015 00:53:04 +0300 Subject: pppoe: implemented per net discovery socket --- accel-pppd/ctrl/pppoe/disc.c | 161 ++++++++++++++++++++++++++---------------- accel-pppd/ctrl/pppoe/pppoe.c | 21 ++++-- accel-pppd/ctrl/pppoe/pppoe.h | 6 +- 3 files changed, 117 insertions(+), 71 deletions(-) (limited to 'accel-pppd/ctrl/pppoe') diff --git a/accel-pppd/ctrl/pppoe/disc.c b/accel-pppd/ctrl/pppoe/disc.c index 151ef10c..5a8fc83a 100644 --- a/accel-pppd/ctrl/pppoe/disc.c +++ b/accel-pppd/ctrl/pppoe/disc.c @@ -15,6 +15,7 @@ #include "log.h" #include "mempool.h" +#include "ap_net.h" #include "pppoe.h" #include "memdebug.h" @@ -25,24 +26,101 @@ struct tree { }; #define HASH_BITS 0xff -static struct tree *tree; -static uint8_t bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +struct disc_net { + struct triton_context_t ctx; + struct list_head entry; + struct triton_md_handler_t hnd; + const struct ap_net *net; + struct tree tree[0]; +}; -static struct triton_md_handler_t disc_hnd; +static uint8_t bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static mempool_t pkt_pool; -int disc_sock; +static LIST_HEAD(nets); + +static void disc_close(struct triton_context_t *ctx); +static int disc_read(struct triton_md_handler_t *h); + +static struct disc_net *init_net(const struct ap_net *net) +{ + struct sockaddr_ll addr; + int i, f = 1; + struct disc_net *n; + struct tree *tree; + int sock; + + sock = net->socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PPP_DISC)); + if (sock < 0) + return NULL; + + memset(&addr, 0, sizeof(addr)); + addr.sll_family = AF_PACKET; + addr.sll_protocol = htons(ETH_P_PPP_DISC); + + net->setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &f, sizeof(f)); + + if (net->bind(sock, (struct sockaddr *)&addr, sizeof(addr))) { + log_error("pppoe: disc: bind: %s\n", strerror(errno)); + close(sock); + return NULL; + } + + fcntl(sock, F_SETFD, FD_CLOEXEC); + net->set_nonblocking(sock, 1); + + n = malloc(sizeof(*net) + (HASH_BITS + 1) * sizeof(struct tree)); + tree = n->tree; + + for (i = 0; i <= HASH_BITS; i++) { + pthread_mutex_init(&tree[i].lock, NULL); + tree[i].root = RB_ROOT; + } + + n->ctx.close = disc_close; + n->hnd.fd = sock; + n->hnd.read = disc_read; + n->net = net; + + triton_context_register(&n->ctx, NULL); + triton_md_register_handler(&n->ctx, &n->hnd); + triton_md_enable_handler(&n->hnd, MD_MODE_READ); + triton_context_wakeup(&n->ctx); + + list_add_tail(&n->entry, &nets); + + return n; +} + +static struct disc_net *find_net(const struct ap_net *net) +{ + struct disc_net *n; + + list_for_each_entry(n, &nets, entry) { + if (n->net == net) + return n; + } + + return NULL; +} -void pppoe_disc_start(struct pppoe_serv_t *serv) +int pppoe_disc_start(struct pppoe_serv_t *serv) { + struct disc_net *net = find_net(serv->net); struct rb_node **p, *parent = NULL; struct tree *t; int ifindex = serv->ifindex, i; struct pppoe_serv_t *n; - t = &tree[ifindex & HASH_BITS]; + if (!net) { + net = init_net(serv->net); + if (!net) + return -1; + } + + t = &net->tree[ifindex & HASH_BITS]; pthread_mutex_lock(&t->lock); @@ -60,7 +138,7 @@ void pppoe_disc_start(struct pppoe_serv_t *serv) else { pthread_mutex_unlock(&t->lock); log_error("pppoe: disc: attempt to add duplicate ifindex\n"); - return; + return -1; } } @@ -68,21 +146,24 @@ void pppoe_disc_start(struct pppoe_serv_t *serv) rb_insert_color(&serv->node, &t->root); pthread_mutex_unlock(&t->lock); + + return net->hnd.fd; } void pppoe_disc_stop(struct pppoe_serv_t *serv) { - struct tree *t = &tree[serv->ifindex & HASH_BITS]; + struct disc_net *n = find_net(serv->net); + struct tree *t = &n->tree[serv->ifindex & HASH_BITS]; pthread_mutex_lock(&t->lock); rb_erase(&serv->node, &t->root); pthread_mutex_unlock(&t->lock); } -static int forward(int ifindex, void *pkt, int len) +static int forward(struct disc_net *net, int ifindex, void *pkt, int len) { struct pppoe_serv_t *n; - struct tree *t = &tree[ifindex & HASH_BITS]; + struct tree *t = &net->tree[ifindex & HASH_BITS]; struct rb_node **p = &t->root.rb_node, *parent = NULL; int r = 0; struct ethhdr *ethhdr = (struct ethhdr *)(pkt + 4); @@ -112,10 +193,10 @@ static int forward(int ifindex, void *pkt, int len) return r; } -static void notify_down(int ifindex) +static void notify_down(struct disc_net *net, int ifindex) { struct pppoe_serv_t *n; - struct tree *t = &tree[ifindex & HASH_BITS]; + struct tree *t = &net->tree[ifindex & HASH_BITS]; struct rb_node **p = &t->root.rb_node, *parent = NULL; pthread_mutex_lock(&t->lock); @@ -139,6 +220,7 @@ static void notify_down(int ifindex) static int disc_read(struct triton_md_handler_t *h) { + struct disc_net *net = container_of(h, typeof(*net), hnd); uint8_t *pack = NULL; struct ethhdr *ethhdr; struct pppoe_hdr *hdr; @@ -150,14 +232,14 @@ static int disc_read(struct triton_md_handler_t *h) if (!pack) pack = mempool_alloc(pkt_pool); - n = recvfrom(disc_sock, pack + 4, ETHER_MAX_LEN, MSG_DONTWAIT, (struct sockaddr *)&src, &slen); + n = net->net->recvfrom(h->fd, pack + 4, ETHER_MAX_LEN, MSG_DONTWAIT, (struct sockaddr *)&src, &slen); if (n < 0) { if (errno == EAGAIN) break; if (errno == ENETDOWN) { - notify_down(src.sll_ifindex); + notify_down(net, src.sll_ifindex); continue; } @@ -211,7 +293,7 @@ static int disc_read(struct triton_md_handler_t *h) log_warn("pppoe: discarding packet (unsupported type %i)\n", hdr->type); } - if (forward(src.sll_ifindex, pack, n)) + if (forward(net, src.sll_ifindex, pack, n)) pack = NULL; } @@ -220,60 +302,17 @@ static int disc_read(struct triton_md_handler_t *h) return 0; } -static void disc_close(struct triton_context_t *ctx); - -static struct triton_context_t disc_ctx = { - .close = disc_close, -}; - -static struct triton_md_handler_t disc_hnd = { - .read = disc_read, -}; - static void disc_close(struct triton_context_t *ctx) { - triton_md_unregister_handler(&disc_hnd, 1); + struct disc_net *n = container_of(ctx, typeof(*n), ctx); + + triton_md_unregister_handler(&n->hnd, 1); triton_context_unregister(ctx); } static void init() { - struct sockaddr_ll addr; - int i, f = 1; - pkt_pool = mempool_create(ETHER_MAX_LEN + 4); - - tree = malloc((HASH_BITS + 1) * sizeof(struct tree)); - for (i = 0; i <= HASH_BITS; i++) { - pthread_mutex_init(&tree[i].lock, NULL); - tree[i].root = RB_ROOT; - } - - disc_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PPP_DISC)); - if (disc_sock < 0) - return; - - memset(&addr, 0, sizeof(addr)); - addr.sll_family = AF_PACKET; - addr.sll_protocol = htons(ETH_P_PPP_DISC); - - setsockopt(disc_sock, SOL_SOCKET, SO_BROADCAST, &f, sizeof(f)); - - if (bind(disc_sock, (struct sockaddr *)&addr, sizeof(addr))) { - log_error("pppoe: disc: bind: %s\n", strerror(errno)); - close(disc_sock); - return; - } - - fcntl(disc_sock, F_SETFL, O_NONBLOCK); - fcntl(disc_sock, F_SETFD, FD_CLOEXEC); - - disc_hnd.fd = disc_sock; - - triton_context_register(&disc_ctx, NULL); - triton_md_register_handler(&disc_ctx, &disc_hnd); - triton_md_enable_handler(&disc_hnd, MD_MODE_READ); - triton_context_wakeup(&disc_ctx); } DEFINE_INIT(1, init); diff --git a/accel-pppd/ctrl/pppoe/pppoe.c b/accel-pppd/ctrl/pppoe/pppoe.c index 44851c25..f2191526 100644 --- a/accel-pppd/ctrl/pppoe/pppoe.c +++ b/accel-pppd/ctrl/pppoe/pppoe.c @@ -712,17 +712,17 @@ static void add_tag2(uint8_t *pack, const struct pppoe_tag *t) hdr->length = htons(ntohs(hdr->length) + sizeof(*tag) + ntohs(t->tag_len)); } -static void pppoe_send(int ifindex, const uint8_t *pack) +static void pppoe_send(struct pppoe_serv_t *serv, const uint8_t *pack) { struct sockaddr_ll addr = { .sll_family = AF_PACKET, .sll_protocol = htons(ETH_P_PPP_DISC), - .sll_ifindex = ifindex, + .sll_ifindex = serv->ifindex, }; struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); int len = ETH_HLEN + sizeof(*hdr) + ntohs(hdr->length); - sendto(disc_sock, pack, len, MSG_DONTWAIT, (struct sockaddr *)&addr, sizeof(addr)); + sendto(serv->disc_sock, pack, len, MSG_DONTWAIT, (struct sockaddr *)&addr, sizeof(addr)); } static void pppoe_send_PADO(struct pppoe_serv_t *serv, const uint8_t *addr, const struct pppoe_tag *host_uniq, const struct pppoe_tag *relay_sid, const struct pppoe_tag *service_name) @@ -755,7 +755,7 @@ static void pppoe_send_PADO(struct pppoe_serv_t *serv, const uint8_t *addr, cons } __sync_add_and_fetch(&stat_PADO_sent, 1); - pppoe_send(serv->ifindex, pack); + pppoe_send(serv, pack); } static void pppoe_send_err(struct pppoe_serv_t *serv, const uint8_t *addr, const struct pppoe_tag *host_uniq, const struct pppoe_tag *relay_sid, int code, int tag_type) @@ -778,7 +778,7 @@ static void pppoe_send_err(struct pppoe_serv_t *serv, const uint8_t *addr, const print_packet(pack); } - pppoe_send(serv->ifindex, pack); + pppoe_send(serv, pack); } static void pppoe_send_PADS(struct pppoe_conn_t *conn) @@ -803,7 +803,7 @@ static void pppoe_send_PADS(struct pppoe_conn_t *conn) } __sync_add_and_fetch(&stat_PADS_sent, 1); - pppoe_send(conn->serv->ifindex, pack); + pppoe_send(conn->serv, pack); } static void pppoe_send_PADT(struct pppoe_conn_t *conn) @@ -824,7 +824,7 @@ static void pppoe_send_PADT(struct pppoe_conn_t *conn) print_packet(pack); } - pppoe_send(conn->serv->ifindex, pack); + pppoe_send(conn->serv, pack); } static void free_delayed_pado(struct delayed_pado_t *pado) @@ -1408,6 +1408,13 @@ static void __pppoe_server_start(const char *ifname, const char *opt, void *cli, triton_context_register(&serv->ctx, serv); + serv->disc_sock = pppoe_disc_start(serv); + if (serv->disc_sock < 0) { + log_error("pppoe: %s: failed to create discovery socket\n", ifname); + triton_context_unregister(&serv->ctx); + goto out_err; + } + if (vid) { serv->parent_ifindex = parent_ifindex; serv->vid = vid; diff --git a/accel-pppd/ctrl/pppoe/pppoe.h b/accel-pppd/ctrl/pppoe/pppoe.h index b526c3e7..44a31258 100644 --- a/accel-pppd/ctrl/pppoe/pppoe.h +++ b/accel-pppd/ctrl/pppoe/pppoe.h @@ -70,6 +70,7 @@ struct pppoe_serv_t struct rb_node node; const struct ap_net *net; + int disc_sock; uint8_t hwaddr[ETH_ALEN]; char *ifname; @@ -115,14 +116,13 @@ extern unsigned long stat_filtered; extern pthread_rwlock_t serv_lock; extern struct list_head serv_list; -extern int disc_sock; - int mac_filter_check(const uint8_t *addr); void pppoe_server_start(const char *intf, void *client); void pppoe_server_stop(const char *intf); void pppoe_serv_read(uint8_t *data); void _server_stop(struct pppoe_serv_t *s); -void pppoe_disc_start(struct pppoe_serv_t *serv); + +int pppoe_disc_start(struct pppoe_serv_t *serv); void pppoe_disc_stop(struct pppoe_serv_t *serv); extern int pado_delay; -- cgit v1.2.3