On Sun, 13 Jan 2008, Cristian Ionescu-Idbohrn wrote:
The problem is described here too:
http://archives.devshed.com/forums/networking-100/dhclient-raw-socket-2147170.html
We noticed that too (corner cases). udhcpc eats up to 30% cpu.
That happens after DISCOVER while waiting for OFFER. udhcpc is looking
through every udp package.
I also learned (from one of my collegues) that a LPF/BPF filter will
most likely help.
[snip]
I intend to try that during the comming weeks, if noone else beats me to
it ;)
And this is what I could come up with (attached). Besides the actual
LPF-filter in networking/udhcp/clientsocket.c, I thought it was wise to
move SERVER_PORT and CLIENT_PORT from networking/udhcp/options.h to
networking/udhcp/common.h and adjust some other file(s) accordingly. The
rest is just whitespace damage fixes.
This patch reduces udhcpc CPU-consumption (when the dhcp-server(s) is/are
unresponsive) on our board from 10-30% down to 0% (as shown by bb-top).
Besides messages like bogous packet and oversized packet (don't
remember the exact wording and I'm too lazy to look them up again, but
can be reproduced with DEBUG enebled and running udhcpc in the foreground)
do no longer show up in the console.
The comment in networking/udhcp/clientsocket.c gives credit to Stefan
Rompf [EMAIL PROTECTED], I've shamelessly stolen the LPF/BPF-filter from.
I hereby aknowledge his involuntary contribution to this project :) I
don't think there should be any copyright and/or licensing problems here.
Stefan (if reachable) will probably comment.
In my big comment inside networking/udhcp/clientsocket.c I'm also trying
to pinpoint some ideas that I'm very fond of and Stefan puts words on. I
think those ideas (if implemented in busybox) would be a big lift for this
project, namely: netlink events and server reconfiguration without
restarts, SIGHUPs, complicates scripts, resource drains especially for
embedded systems, and so on.
Cheers,
--
Cristian--- networking/udhcp/clientsocket.c.~1~ 2006-12-20 08:30:32.0 +0100
+++ networking/udhcp/clientsocket.c 2008-01-16 14:52:21.0 +0100
@@ -30,23 +30,73 @@
#include linux/if_packet.h
#include linux/if_ether.h
#endif
+#include linux/filter.h
#include common.h
-
int raw_socket(int ifindex)
{
int fd;
- struct sockaddr_ll sock;
+ struct sockaddr_ll sock = {
+ .sll_family = AF_PACKET,
+ .sll_protocol = htons(ETH_P_IP),
+ .sll_ifindex = ifindex,
+ };
+
+ /*
+ * Comment:
+ *
+ * I've selected not to see LL header, so BPF doesn't see it, too.
+ * The filter may also pass non-IP and non-ARP packets, but we do
+ * a more complete check when receiving the message in userspace.
+ *
+ * and filter shamelessly stolen from:
+ *
+ * http://www.flamewarmaster.de/software/dhcpclient/
+ *
+ * There are a few other interesting ideas on that page (look under
+ * Motivation). Use of netlink events is most interesting. Think
+ * of various network servers listening for events and reconfiguring.
+ * That would obsolete sending HUP signals and/or make use of restarts.
+ *
+ * Copyright: 2006, 2007 Stefan Rompf [EMAIL PROTECTED].
+ * License: GPL v2.
+ */
+ struct sock_filter filter_instr[] = {
+ /* check for udp */
+ BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
+ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 2, 0), /* L5, L1, is UDP? */
+ /* ugly check for arp on ethernet-like and IPv4 */
+ BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2), /* L1: */
+ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x08000604, 3, 4), /* L3, L4 */
+ /* skip IP header */
+ BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), /* L5: */
+ /* check udp source port */
+ BPF_STMT(BPF_LD|BPF_H|BPF_IND, 0),
+ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SERVER_PORT, 0, 1), /* L3, L4 */
+ /* returns */
+ BPF_STMT(BPF_RET|BPF_K, ~0UL), /* L3: pass */
+ BPF_STMT(BPF_RET|BPF_K, 0), /* L4: reject */
+ };
+
+ struct sock_fprog filter_prog = {
+ .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
+ .filter = filter_instr,
+ };
+
+ DEBUG(opening raw socket on ifindex %d, ifindex);
- DEBUG(Opening raw socket on ifindex %d, ifindex);
fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
+ DEBUG(got raw socket fd %d, fd);
+
+ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, filter_prog,
+sizeof(filter_prog)) 0)
+ bb_perror_msg_and_die(setsockopt);
+ DEBUG(attached filter to raw socket fdr %d, fd);
- sock.sll_family = AF_PACKET;
- sock.sll_protocol = htons(ETH_P_IP);
- sock.sll_ifindex = ifindex;
xbind(fd, (struct sockaddr *) sock, sizeof(sock));
+ DEBUG(bound to raw socket fd %d, fd);
return fd;
}
--- networking/udhcp/common.h.~1~ 2007-12-21 08:30:26.0 +0100
+++ networking/udhcp/common.h 2008-01-16 14:36:29.0 +0100
@@ -14,6 +14,9 @@
#define DEFAULT_SCRIPT /usr/share/udhcpc/default.script
+#define SERVER_PORT 67
+#define CLIENT_PORT 68
+
extern const uint8_t MAC_BCAST_ADDR[6]; /* six all-ones */
/*** packet.h ***/
@@ -93,8 +96,8 @@
int arpping(uint32_t