Jan Kiszka wrote:
Gilles Chanteperdrix wrote:
Gilles Chanteperdrix wrote:
Hi,

here is another patch to RTnet, which replaces the list of UDP sockets
with a hash, so makes the searching for an RTnet registered socket a bit
faster.
Ok. Should have read the patch better before sending it. There are two
more features poured into this patch:
- we add a "receiving" member to the UDP socket structure, which is only
sets either if the program using the socket has called recv, or if the
program has bound the socket to a particular port, this is to prevent a
problem which happens when putting an RTnet box on an heterogenous
network, with an application which only uses a socket to send packets:
if the network sends some packets to the automatically assigned port,
they use rtskbs from the socket pool, until the socket pool becomes
empty, and no more packet can be sent using the socket.
- when a socket is bound to a particular IP address, we use this IP as
the source IP of the packets sent by this socket, even if they end-up
being sent through another interface, this is Linux behaviour, and was
required for one of our applications to work correctly with
off-the-shelf IP phones (they do filtering based on the source IP).

Could you break those two changes out and post them separately? Such
changes are too critical to have them all-in-one.

Ok. Here it comes, extracted from revision control history.
Apply in order:
- rtnet-fix-src-ip.diff
- rtnet-check-receiving.diff
- rtnet-hash-port.diff

--
                                                 Gilles.
Index: stack/ipv4/udp.c
===================================================================
--- stack/ipv4/udp.c    (révision 3250)
+++ stack/ipv4/udp.c    (révision 5093)
@@ -576,14 +576,8 @@ ssize_t rt_udp_sendmsg(struct rtdm_dev_c
     if (err)
         return err;
 
-    /* check if specified source address fits */
-    if ((saddr != INADDR_ANY) && (saddr != rt.rtdev->local_ip)) {
-        rtdev_dereference(rt.rtdev);
-        return -EHOSTUNREACH;
-    }
-
     /* we found a route, remember the routing dest-addr could be the netmask */
-    ufh.saddr     = rt.rtdev->local_ip;
+    ufh.saddr     = saddr ?: rt.rtdev->local_ip;
     ufh.daddr     = daddr;
     ufh.uh.dest   = dport;
     ufh.uh.len    = htons(ulen);
Index: stack/ipv4/udp.c
===================================================================
--- stack/ipv4/udp.c    (révision 5093)
+++ stack/ipv4/udp.c    (révision 5250)
@@ -49,6 +49,7 @@
  */
 struct udp_socket {
     u16             sport;      /* local port */
+    u16             receiving;
     u32             saddr;      /* local ip-addr */
     struct rtsocket *sock;
 };
@@ -116,7 +117,8 @@ static inline struct rtsocket *rt_udp_v4
         bitmap = port_bitmap[bitmap_index];
         while (bitmap != 0) {
             if (test_bit(bit, &bitmap)) {
-                if ((port_registry[index].sport == dport) &&
+               if ((port_registry[index].receiving) &&
+                   (port_registry[index].sport == dport) &&
                     ((port_registry[index].saddr == INADDR_ANY) ||
                      (port_registry[index].saddr == daddr))) {
                     sock = port_registry[index].sock;
@@ -177,6 +179,7 @@ int rt_udp_bind(struct rtsocket *sock, c
 
     port_registry[index].sport = sock->prot.inet.sport;
     port_registry[index].saddr = sock->prot.inet.saddr;
+    port_registry[index].receiving = 1;
 
     rtdm_lock_put_irqrestore(&udp_socket_base_lock, context);
 
@@ -285,6 +288,7 @@ int rt_udp_socket(struct rtdm_dev_contex
     /* register UDP socket */
     port_registry[index].sport = sock->prot.inet.sport;
     port_registry[index].saddr = INADDR_ANY;
+    port_registry[index].receiving = 0;
     port_registry[index].sock  = sock;
 
     rtdm_lock_put_irqrestore(&udp_socket_base_lock, context);
@@ -375,13 +379,23 @@ ssize_t rt_udp_recvmsg(struct rtdm_dev_c
     struct udphdr       *uh;
     struct sockaddr_in  *sin;
     nanosecs_rel_t      timeout = sock->timeout;
-    int                 ret;
+    int                 ret, index;
+    rtdm_lockctx_t  context;
 
 
     /* non-blocking receive? */
     if (testbits(msg_flags, MSG_DONTWAIT))
         timeout = -1;
 
+    rtdm_lock_get_irqsave(&udp_socket_base_lock, context);
+    if ((index = sock->prot.inet.reg_index) < 0) {
+           rtdm_lock_put_irqrestore(&udp_socket_base_lock, context);
+        /* socket is being closed */
+           return -EBADF;
+    }
+    port_registry[index].receiving = 1;
+    rtdm_lock_put_irqrestore(&udp_socket_base_lock, context);
+           
     ret = rtdm_sem_timeddown(&sock->pending_sem, timeout, NULL);
     if (unlikely(ret < 0))
         switch (ret) {
Index: stack/ipv4/udp.c
===================================================================
--- stack/ipv4/udp.c    (révision 5250)
+++ stack/ipv4/udp.c    (révision 6049)
@@ -29,6 +29,7 @@
 #include <linux/udp.h>
 #include <linux/tcp.h>
 #include <net/checksum.h>
+#include <linux/list.h>
 
 #include <rtskb.h>
 #include <rtnet_internal.h>
@@ -52,6 +53,7 @@ struct udp_socket {
     u16             receiving;
     u32             saddr;      /* local ip-addr */
     struct rtsocket *sock;
+    struct hlist_node link;
 };
 
 /***
@@ -81,12 +83,49 @@ static u32                  port_bitmap[
 static struct udp_socket    port_registry[RT_UDP_SOCKETS];
 static rtdm_lock_t          udp_socket_base_lock = RTDM_LOCK_UNLOCKED;
 
+static struct hlist_head port_hash[RT_UDP_SOCKETS * 2];
+#define port_hash_mask (RT_UDP_SOCKETS * 2 - 1)
+
 module_param(auto_port_start, uint, 0444);
 module_param(auto_port_mask, uint, 0444);
 MODULE_PARM_DESC(auto_port_start, "Start of automatically assigned port 
range");
 MODULE_PARM_DESC(auto_port_mask,
                  "Mask that defines port range for automatic assignment");
 
+static inline struct udp_socket *port_hash_search(u32 saddr, u16 sport)
+{
+       unsigned bucket = sport & port_hash_mask;
+       struct udp_socket *sock;
+       struct hlist_node *n;
+
+       hlist_for_each_entry(sock, n, &port_hash[bucket], link)
+               if (sock->sport == sport &&
+                   (saddr == INADDR_ANY
+                    || sock->saddr == saddr
+                    || sock->saddr == INADDR_ANY))
+                       return sock;
+
+       return NULL;
+}
+
+static inline int port_hash_insert(struct udp_socket *sock, u32 saddr, u16 
sport)
+{
+       unsigned bucket;
+
+       if (port_hash_search(saddr, sport))
+               return -EADDRINUSE;
+
+       bucket = sport & port_hash_mask;
+       sock->saddr = saddr;
+       sock->sport = sport;
+       hlist_add_head(&sock->link, &port_hash[bucket]);
+       return 0;
+}
+
+static inline void port_hash_del(struct udp_socket *sock)
+{
+       hlist_del(&sock->link);
+}
 
 /***
  *  rt_udp_v4_lookup
@@ -94,49 +133,20 @@ MODULE_PARM_DESC(auto_port_mask,
 static inline struct rtsocket *rt_udp_v4_lookup(u32 daddr, u16 dport)
 {
     rtdm_lockctx_t  context;
-    int             index;
-    int             bit;
-    int             bitmap_index;
-#if BITS_PER_LONG == 32
-    unsigned long   bitmap;
-#elif BITS_PER_LONG == 64
-    u32             bitmap;
-#else
-#error please include asm/types.h
-#endif
-    struct rtsocket *sock;
-
-
-    for (bitmap_index = 0; bitmap_index < ((RT_UDP_SOCKETS + 31) / 32);
-         bitmap_index++) {
-        bit    = 0;
-        index  = bitmap_index * 32;
+    struct udp_socket *sock;
 
-        rtdm_lock_get_irqsave(&udp_socket_base_lock, context);
+    rtdm_lock_get_irqsave(&udp_socket_base_lock, context);
+    sock = port_hash_search(daddr, dport);
+    if (sock && sock->receiving) {
+           rt_socket_reference(sock->sock);
 
-        bitmap = port_bitmap[bitmap_index];
-        while (bitmap != 0) {
-            if (test_bit(bit, &bitmap)) {
-               if ((port_registry[index].receiving) &&
-                   (port_registry[index].sport == dport) &&
-                    ((port_registry[index].saddr == INADDR_ANY) ||
-                     (port_registry[index].saddr == daddr))) {
-                    sock = port_registry[index].sock;
-                    rt_socket_reference(sock);
-
-                    rtdm_lock_put_irqrestore(&udp_socket_base_lock, context);
-
-                    return sock;
-                }
-                clear_bit(bit, &bitmap);
-            }
-            index++;
-            bit++;
-        }
+           rtdm_lock_put_irqrestore(&udp_socket_base_lock, context);
 
-        rtdm_lock_put_irqrestore(&udp_socket_base_lock, context);
+           return sock->sock;
     }
 
+    rtdm_lock_put_irqrestore(&udp_socket_base_lock, context);
+           
     return NULL;
 }
 
@@ -170,15 +180,23 @@ int rt_udp_bind(struct rtsocket *sock, c
         return -EINVAL;
     }
 
+    port_hash_del(&port_registry[index]);
+    if (port_hash_insert(&port_registry[index],
+                        usin->sin_addr.s_addr,
+                        usin->sin_port ?: index + auto_port_start)) {
+           port_hash_insert(&port_registry[index],
+                            port_registry[index].saddr,
+                            port_registry[index].sport);
+           rtdm_lock_put_irqrestore(&udp_socket_base_lock, context);
+           return -EADDRINUSE;
+    }
+
     /* set the source-addr */
-    sock->prot.inet.saddr = usin->sin_addr.s_addr;
+    sock->prot.inet.saddr = port_registry[index].saddr;
 
     /* set source port, if not set by user */
-    if ((sock->prot.inet.sport = usin->sin_port) == 0)
-        sock->prot.inet.sport = index + auto_port_start;
+    sock->prot.inet.sport = port_registry[index].sport;
 
-    port_registry[index].sport = sock->prot.inet.sport;
-    port_registry[index].saddr = sock->prot.inet.saddr;
     port_registry[index].receiving = 1;
 
     rtdm_lock_put_irqrestore(&udp_socket_base_lock, context);
@@ -286,8 +304,7 @@ int rt_udp_socket(struct rtdm_dev_contex
     sock->prot.inet.sport     = index + auto_port_start;
 
     /* register UDP socket */
-    port_registry[index].sport = sock->prot.inet.sport;
-    port_registry[index].saddr = INADDR_ANY;
+    port_hash_insert(&port_registry[index], INADDR_ANY, sock->prot.inet.sport);
     port_registry[index].receiving = 0;
     port_registry[index].sock  = sock;
 
@@ -317,6 +334,7 @@ int rt_udp_close(struct rtdm_dev_context
     if (sock->prot.inet.reg_index >= 0) {
         port = sock->prot.inet.reg_index;
         clear_bit(port % 32, &port_bitmap[port / 32]);
+       port_hash_del(&port_registry[port]);
 
         free_ports++;
 
@@ -780,19 +798,21 @@ static struct rtinet_protocol udp_protoc
     init_socket:    &rt_udp_socket
 };
 
-
-
 /***
  *  rt_udp_init
  */
 void __init rt_udp_init(void)
 {
+    int i;
     if ((auto_port_start < 0) || (auto_port_start >= 0x10000 - RT_UDP_SOCKETS))
         auto_port_start = 1024;
     auto_port_start = htons(auto_port_start & (auto_port_mask & 0xFFFF));
     auto_port_mask  = htons(auto_port_mask | 0xFFFF0000);
 
     rt_inet_add_protocol(&udp_protocol);
+
+    for (i = 0; i < ARRAY_SIZE(port_hash); i++)
+           INIT_HLIST_HEAD(&port_hash[i]);
 }
 
 
-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php
_______________________________________________
RTnet-developers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/rtnet-developers

Reply via email to