chiark / gitweb /
sd-dhcp-client: improve BPF
authorTom Gundersen <teg@jklm.no>
Sun, 6 Apr 2014 17:23:33 +0000 (19:23 +0200)
committerTom Gundersen <teg@jklm.no>
Sun, 6 Apr 2014 17:42:11 +0000 (19:42 +0200)
Try a bit harder to make the kernel drop packets not for us. This should reduce
the number of wakeups from n^2 to n in the number of dhcp clients, which admittedly
only makes a differenc in very extreme cases.

src/libsystemd-network/dhcp-internal.h
src/libsystemd-network/dhcp-network.c
src/libsystemd-network/sd-dhcp-client.c
src/libsystemd-network/test-dhcp-client.c

index 064b13b59ff5dca2bb78cc142d7a93b4df43e3a4..324c2a8d7af8fbe0b69b04c1b87d032494fa37a3 100644 (file)
@@ -29,7 +29,7 @@
 
 #include "dhcp-protocol.h"
 
-int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link);
+int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, uint32_t xid);
 int dhcp_network_bind_udp_socket(int index, be32_t address, uint16_t port);
 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
                                  const void *packet, size_t len);
index a9a15b4d5adc156b6ef5c17671d7df5eca2f54ee..902c9d9be2c6bc48a11b6d6c2c4fc8f0003b9058 100644 (file)
@@ -23,6 +23,7 @@
 #include <string.h>
 #include <linux/if_packet.h>
 #include <net/ethernet.h>
+#include <net/if_arp.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <linux/filter.h>
 
 #include "dhcp-internal.h"
 
-int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link)
-{
+int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, uint32_t xid) {
         struct sock_filter filter[] = {
             BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0),                                 /* A <- packet length */
             BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(DHCPPacket), 1, 0),         /* packet >= DHCPPacket ? */
             BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
+            /* TODO: match ip.version */
             BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, ip.protocol)), /* A <- IP protocol */
             BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0),                /* IP protocol == UDP ? */
             BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
             BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, udp.dest)),    /* A <- UDP destination port */
             BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_PORT_CLIENT, 1, 0),           /* UDP destination port == DHCP client port ? */
             BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
+            BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.op)),     /* A <- DHCP op */
+            BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTREPLY, 1, 0),                  /* op == BOOTREPLY ? */
+            BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
+            BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.htype)),  /* A <- DHCP header type */
+            BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0),               /* header type == ARPHRD_ETHER ? */
+            BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
+            BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)),   /* A <- mac address length */
+            BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHER_ADDR_LEN, 1, 0),             /* address length == ETHER_ADDR_LEN ? */
+            BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
+            BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)),    /* A <- client identifier */
+            BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0),                        /* client identifier == xid ? */
+            BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
+            /* TODO: match chaddr */
+            BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)),  /* A <- DHCP magic cookie */
+            BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0),          /* cookie == DHCP magic cookie ? */
+            BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
             BPF_STMT(BPF_RET + BPF_K, 65535),                                      /* return all */
         };
         struct sock_fprog fprog = {
index 722f862832e7fa477dc194005296b113dd2e6b27..da41c478eaeb477ba286001e5517abc6014ccca9 100644 (file)
@@ -593,7 +593,7 @@ static int client_start(sd_dhcp_client *client) {
 
         client->xid = random_u32();
 
-        r = dhcp_network_bind_raw_socket(client->index, &client->link);
+        r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
 
         if (r < 0) {
                 client_stop(client, r);
@@ -636,7 +636,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
         client->state = DHCP_STATE_REBINDING;
         client->attempt = 1;
 
-        r = dhcp_network_bind_raw_socket(client->index, &client->link);
+        r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
         if (r < 0) {
                 client_stop(client, r);
                 return 0;
index 2d4d59096a3d8d538814f76f2ab5b6b7c4ba1569..4420436f8a1d2048c9520d0159882b7d4b9c1abb 100644 (file)
@@ -190,7 +190,7 @@ int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
         return 575;
 }
 
-int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link)
+int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, uint32_t id)
 {
         if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
                 return -errno;