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