summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Kozlov <xeb@mail.ru>2013-10-10 22:39:44 +0400
committerDmitry Kozlov <xeb@mail.ru>2013-10-10 22:39:44 +0400
commit272dbf39f83240451d6a0c122ccdbe28eb892ad7 (patch)
treeb9e8e4fb13cb2dcf00535c0f5b7240928ca47ec4
parent21d36db2bad56b6389873b1c10e45f36938ed5fc (diff)
downloadaccel-ppp-xebd-272dbf39f83240451d6a0c122ccdbe28eb892ad7.tar.gz
accel-ppp-xebd-272dbf39f83240451d6a0c122ccdbe28eb892ad7.zip
ipoe: optimize use of raw sockets
Signed-off-by: Dmitry Kozlov <xeb@mail.ru>
-rw-r--r--accel-pppd/ctrl/ipoe/dhcpv4.c79
-rw-r--r--accel-pppd/ctrl/ipoe/dhcpv4.h2
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c4
3 files changed, 55 insertions, 30 deletions
diff --git a/accel-pppd/ctrl/ipoe/dhcpv4.c b/accel-pppd/ctrl/ipoe/dhcpv4.c
index d3f0010..12ba95c 100644
--- a/accel-pppd/ctrl/ipoe/dhcpv4.c
+++ b/accel-pppd/ctrl/ipoe/dhcpv4.c
@@ -43,9 +43,35 @@ static mempool_t opt_pool;
static LIST_HEAD(relay_list);
static pthread_mutex_t relay_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_key_t raw_sock_key;
+static __thread int raw_sock = -1;
+
static int dhcpv4_read(struct triton_md_handler_t *h);
int dhcpv4_packet_add_opt(struct dhcpv4_packet *pack, int type, const void *data, int len);
+static int open_raw_sock(void)
+{
+ if (raw_sock == -1) {
+ raw_sock = socket(AF_PACKET, SOCK_RAW, 0);
+ if (raw_sock < 0) {
+ log_error("dhcpv4: socket(AF_PACKET, SOCK_RAW): %s\n", strerror(errno));
+ return -1;
+ }
+
+ fcntl(raw_sock, F_SETFL, O_NONBLOCK);
+ fcntl(raw_sock, F_SETFD, fcntl(raw_sock, F_GETFD) | FD_CLOEXEC);
+
+ pthread_setspecific(raw_sock_key, (void *)(long)raw_sock);
+ }
+
+ return raw_sock;
+}
+
+static void close_raw_sock(void *arg)
+{
+ close((long)arg);
+}
+
static struct dhcpv4_iprange *parse_range(const char *str)
{
unsigned int f1,f2,f3,f4,m,n, mask, start, end, len;
@@ -96,13 +122,12 @@ parse_err:
struct dhcpv4_serv *dhcpv4_create(struct triton_context_t *ctx, const char *ifname, const char *opt)
{
struct dhcpv4_serv *serv;
- int sock, raw_sock;
+ int sock;
struct sockaddr_in addr;
- struct sockaddr_ll ll_addr;
struct ifreq ifr;
int f = 1;
char *str0, *str, *ptr1, *ptr2;
- int end;
+ int end, ifindex;
memset(&ifr, 0, sizeof(ifr));
@@ -111,23 +136,7 @@ struct dhcpv4_serv *dhcpv4_create(struct triton_context_t *ctx, const char *ifna
log_error("dhcpv4(%s): ioctl(SIOCGIFINDEX): %s\n", ifname, strerror(errno));
return NULL;
}
-
- raw_sock = socket(AF_PACKET, SOCK_RAW, ntohs(ETH_P_IP));
- if (raw_sock < 0) {
- log_error("dhcpv4: packet socket is not supported by kernel\n");
- return NULL;
- }
-
- memset(&ll_addr, 0, sizeof(ll_addr));
- ll_addr.sll_family = AF_PACKET;
- ll_addr.sll_ifindex = ifr.ifr_ifindex;
- ll_addr.sll_protocol = ntohs(ETH_P_IP);
-
- if (bind(raw_sock, (struct sockaddr *)&ll_addr, sizeof(ll_addr))) {
- log_error("dhcpv4(%s): bind: %s\n", ifname, strerror(errno));
- close(raw_sock);
- return NULL;
- }
+ ifindex = ifr.ifr_ifindex;
memset(&addr, 0, sizeof(addr));
@@ -161,9 +170,6 @@ struct dhcpv4_serv *dhcpv4_create(struct triton_context_t *ctx, const char *ifna
goto out_err;
}
- fcntl(raw_sock, F_SETFL, O_NONBLOCK);
- fcntl(raw_sock, F_SETFD, fcntl(raw_sock, F_GETFD) | FD_CLOEXEC);
-
fcntl(sock, F_SETFL, O_NONBLOCK);
fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
@@ -175,7 +181,7 @@ struct dhcpv4_serv *dhcpv4_create(struct triton_context_t *ctx, const char *ifna
serv->ctx = ctx;
serv->hnd.fd = sock;
serv->hnd.read = dhcpv4_read;
- serv->raw_sock = raw_sock;
+ serv->ifindex = ifindex;
str0 = opt ? strchr(opt, ',') : NULL;
if (str0) {
@@ -218,7 +224,6 @@ struct dhcpv4_serv *dhcpv4_create(struct triton_context_t *ctx, const char *ifna
return serv;
out_err:
- close(raw_sock);
close(sock);
return NULL;
}
@@ -575,6 +580,21 @@ static int dhcpv4_send_raw(struct dhcpv4_serv *serv, struct dhcpv4_packet *pack,
int len = pack->ptr - pack->data;
struct iovec iov[2];
static uint8_t bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ struct sockaddr_ll ll_addr;
+ struct msghdr msg;
+ int sock = open_raw_sock();
+
+ memset(&ll_addr, 0, sizeof(ll_addr));
+ ll_addr.sll_family = AF_PACKET;
+ ll_addr.sll_ifindex = serv->ifindex;
+ ll_addr.sll_protocol = ntohs(ETH_P_IP);
+
+ msg.msg_name = &ll_addr;
+ msg.msg_namelen = sizeof(ll_addr);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 2;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
memcpy(eth->ether_dhost, (pack->hdr->flags & DHCP_F_BROADCAST) ? bc_addr : pack->hdr->chaddr, ETH_ALEN);
memcpy(eth->ether_shost, serv->hwaddr, ETH_ALEN);
@@ -603,10 +623,13 @@ static int dhcpv4_send_raw(struct dhcpv4_serv *serv, struct dhcpv4_packet *pack,
iov[1].iov_base = pack->data;
iov[1].iov_len = len;
- len = writev(serv->raw_sock, iov, 2);
+ len = sendmsg(sock, &msg, 0);
- if (len < 0)
+ if (len < 0) {
+ perror("sendmsg");
+ printf("%i %i\n", errno, serv->ifindex);
return -1;
+ }
return 0;
}
@@ -1093,6 +1116,8 @@ static void init()
{
pack_pool = mempool_create(BUF_SIZE + sizeof(struct dhcpv4_packet));
opt_pool = mempool_create(sizeof(struct dhcpv4_option));
+
+ pthread_key_create(&raw_sock_key, close_raw_sock);
load_config();
diff --git a/accel-pppd/ctrl/ipoe/dhcpv4.h b/accel-pppd/ctrl/ipoe/dhcpv4.h
index 57fcf93..7494b73 100644
--- a/accel-pppd/ctrl/ipoe/dhcpv4.h
+++ b/accel-pppd/ctrl/ipoe/dhcpv4.h
@@ -84,8 +84,8 @@ struct dhcpv4_iprange {
struct dhcpv4_serv {
struct triton_context_t *ctx;
struct triton_md_handler_t hnd;
- int raw_sock;
uint8_t hwaddr[6];
+ int ifindex;
void (*recv)(struct dhcpv4_serv *serv, struct dhcpv4_packet *pack);
struct dhcpv4_iprange *range;
};
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index 7059e2a..4914be2 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.c
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -521,7 +521,7 @@ static void ipoe_session_start(struct ipoe_session *ses)
ses->ifindex = ipoe_nl_create(0, 0, ses->serv->opt_mode == MODE_L2 ? ses->serv->ifname : NULL, ses->hwaddr);
if (ses->ifindex == -1) {
log_ppp_error("ipoe: failed to create interface\n");
- ipoe_session_finished(&ses->ses);
+ ap_session_terminate(&ses->ses, TERM_NAS_ERROR, 1);
return;
}
}
@@ -531,7 +531,7 @@ static void ipoe_session_start(struct ipoe_session *ses)
if (ioctl(sock_fd, SIOCGIFNAME, &ifr, sizeof(ifr))) {
log_ppp_error("ipoe: failed to get interface name\n");
ses->ifindex = -1;
- ipoe_session_finished(&ses->ses);
+ ap_session_terminate(&ses->ses, TERM_NAS_ERROR, 1);
return;
}