* [net-next PATCH v3 01/10] llc: use dev_hard_header
2009-12-26 21:50 [net-next PATCH v3 0/10] llc enhancements Octavian Purdila
@ 2009-12-26 21:50 ` Octavian Purdila
2009-12-26 21:51 ` [net-next PATCH v3 02/10] llc: add support for LLC_OPT_PKTINFO Octavian Purdila
` (9 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Octavian Purdila @ 2009-12-26 21:50 UTC (permalink / raw)
To: netdev; +Cc: Arnaldo Carvalho de Melo, Eric Dumazet, Octavian Purdila
Using dev_hard_header allows us to use LLC with VLANs and potentially
other Ethernet/TokernRing specific encapsulations. It also removes code
duplication between LLC and Ethernet/TokenRing core code.
Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
---
drivers/net/myri_sbus.c | 6 +++---
net/8021q/vlan_dev.c | 7 +++----
net/ethernet/eth.c | 6 +++---
net/llc/llc_output.c | 45 ++++++++-------------------------------------
4 files changed, 17 insertions(+), 47 deletions(-)
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index b3513ad..8b43130 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -716,10 +716,10 @@ static int myri_header(struct sk_buff *skb, struct net_device *dev,
pad[0] = MYRI_PAD_LEN;
pad[1] = 0xab;
- /* Set the protocol type. For a packet of type ETH_P_802_3 we put the length
- * in here instead. It is up to the 802.2 layer to carry protocol information.
+ /* Set the protocol type. For a packet of type ETH_P_802_3/2 we put the
+ * length in here instead.
*/
- if (type != ETH_P_802_3)
+ if (type != ETH_P_802_3 && type != ETH_P_802_2)
eth->h_proto = htons(type);
else
eth->h_proto = htons(len);
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index b788978..77a49ff 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -263,11 +263,10 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
vhdr->h_vlan_TCI = htons(vlan_tci);
/*
- * Set the protocol type. For a packet of type ETH_P_802_3 we
- * put the length in here instead. It is up to the 802.2
- * layer to carry protocol information.
+ * Set the protocol type. For a packet of type ETH_P_802_3/2 we
+ * put the length in here instead.
*/
- if (type != ETH_P_802_3)
+ if (type != ETH_P_802_3 && type != ETH_P_802_2)
vhdr->h_vlan_encapsulated_proto = htons(type);
else
vhdr->h_vlan_encapsulated_proto = htons(len);
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index dd3db88..205a1c1 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -73,8 +73,8 @@ __setup("ether=", netdev_boot_setup);
* @len: packet length (<= skb->len)
*
*
- * Set the protocol type. For a packet of type ETH_P_802_3 we put the length
- * in here instead. It is up to the 802.2 layer to carry protocol information.
+ * Set the protocol type. For a packet of type ETH_P_802_3/2 we put the length
+ * in here instead.
*/
int eth_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type,
@@ -82,7 +82,7 @@ int eth_header(struct sk_buff *skb, struct net_device *dev,
{
struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN);
- if (type != ETH_P_802_3)
+ if (type != ETH_P_802_3 && type != ETH_P_802_2)
eth->h_proto = htons(type);
else
eth->h_proto = htons(len);
diff --git a/net/llc/llc_output.c b/net/llc/llc_output.c
index 754f4fe..b38a107 100644
--- a/net/llc/llc_output.c
+++ b/net/llc/llc_output.c
@@ -33,48 +33,19 @@
int llc_mac_hdr_init(struct sk_buff *skb,
const unsigned char *sa, const unsigned char *da)
{
- int rc = 0;
+ int rc = -EINVAL;
switch (skb->dev->type) {
-#ifdef CONFIG_TR
- case ARPHRD_IEEE802_TR: {
- struct net_device *dev = skb->dev;
- struct trh_hdr *trh;
-
- skb_push(skb, sizeof(*trh));
- skb_reset_mac_header(skb);
- trh = tr_hdr(skb);
- trh->ac = AC;
- trh->fc = LLC_FRAME;
- if (sa)
- memcpy(trh->saddr, sa, dev->addr_len);
- else
- memset(trh->saddr, 0, dev->addr_len);
- if (da) {
- memcpy(trh->daddr, da, dev->addr_len);
- tr_source_route(skb, trh, dev);
- skb_reset_mac_header(skb);
- }
- break;
- }
-#endif
+ case ARPHRD_IEEE802_TR:
case ARPHRD_ETHER:
- case ARPHRD_LOOPBACK: {
- unsigned short len = skb->len;
- struct ethhdr *eth;
-
- skb_push(skb, sizeof(*eth));
- skb_reset_mac_header(skb);
- eth = eth_hdr(skb);
- eth->h_proto = htons(len);
- memcpy(eth->h_dest, da, ETH_ALEN);
- memcpy(eth->h_source, sa, ETH_ALEN);
+ case ARPHRD_LOOPBACK:
+ rc = dev_hard_header(skb, skb->dev, ETH_P_802_2, da, sa,
+ skb->len);
+ if (rc > 0)
+ rc = 0;
break;
- }
default:
- printk(KERN_WARNING "device type not supported: %d\n",
- skb->dev->type);
- rc = -EINVAL;
+ WARN(1, "device type not supported: %d\n", skb->dev->type);
}
return rc;
}
--
1.5.6.5
^ permalink raw reply related [flat|nested] 15+ messages in thread* [net-next PATCH v3 02/10] llc: add support for LLC_OPT_PKTINFO
2009-12-26 21:50 [net-next PATCH v3 0/10] llc enhancements Octavian Purdila
2009-12-26 21:50 ` [net-next PATCH v3 01/10] llc: use dev_hard_header Octavian Purdila
@ 2009-12-26 21:51 ` Octavian Purdila
2009-12-26 21:51 ` [net-next PATCH v3 03/10] llc: add support for SO_BINDTODEVICE Octavian Purdila
` (8 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Octavian Purdila @ 2009-12-26 21:51 UTC (permalink / raw)
To: netdev; +Cc: Arnaldo Carvalho de Melo, Eric Dumazet, Octavian Purdila
Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
---
include/linux/llc.h | 7 +++++++
include/net/llc_conn.h | 1 +
net/llc/af_llc.c | 29 +++++++++++++++++++++++++++++
3 files changed, 37 insertions(+), 0 deletions(-)
diff --git a/include/linux/llc.h b/include/linux/llc.h
index 7733585..ad7074b 100644
--- a/include/linux/llc.h
+++ b/include/linux/llc.h
@@ -36,6 +36,7 @@ enum llc_sockopts {
LLC_OPT_BUSY_TMR_EXP, /* busy state expire time (secs). */
LLC_OPT_TX_WIN, /* tx window size. */
LLC_OPT_RX_WIN, /* rx window size. */
+ LLC_OPT_PKTINFO, /* ancillary packet information. */
LLC_OPT_MAX
};
@@ -70,6 +71,12 @@ enum llc_sockopts {
#define LLC_SAP_RM 0xD4 /* Resource Management */
#define LLC_SAP_GLOBAL 0xFF /* Global SAP. */
+struct llc_pktinfo {
+ int lpi_ifindex;
+ unsigned char lpi_sap;
+ unsigned char lpi_mac[IFHWADDRLEN];
+};
+
#ifdef __KERNEL__
#define LLC_SAP_DYN_START 0xC0
#define LLC_SAP_DYN_STOP 0xDE
diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h
index e2374e3..fe982fd 100644
--- a/include/net/llc_conn.h
+++ b/include/net/llc_conn.h
@@ -76,6 +76,7 @@ struct llc_sock {
u32 rx_pdu_hdr; /* used for saving header of last pdu
received and caused sending FRMR.
Used for resending FRMR */
+ u32 cmsg_flags;
};
static inline struct llc_sock *llc_sk(const struct sock *sk)
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index 3a66546..ac691fe 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -47,6 +47,10 @@ static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout);
#define dprintk(args...)
#endif
+/* Maybe we'll add some more in the future. */
+#define LLC_CMSG_PKTINFO 1
+
+
/**
* llc_ui_next_link_no - return the next unused link number for a sap
* @sap: Address of sap to get link number from.
@@ -591,6 +595,20 @@ static int llc_wait_data(struct sock *sk, long timeo)
return rc;
}
+static void llc_cmsg_rcv(struct msghdr *msg, struct sk_buff *skb)
+{
+ struct llc_sock *llc = llc_sk(skb->sk);
+
+ if (llc->cmsg_flags & LLC_CMSG_PKTINFO) {
+ struct llc_pktinfo info;
+
+ info.lpi_ifindex = llc_sk(skb->sk)->dev->ifindex;
+ llc_pdu_decode_dsap(skb, &info.lpi_sap);
+ llc_pdu_decode_da(skb, info.lpi_mac);
+ put_cmsg(msg, SOL_LLC, LLC_OPT_PKTINFO, sizeof(info), &info);
+ }
+}
+
/**
* llc_ui_accept - accept a new incoming connection.
* @sock: Socket which connections arrive on.
@@ -812,6 +830,8 @@ copy_uaddr:
memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr));
msg->msg_namelen = sizeof(*uaddr);
}
+ if (llc_sk(sk)->cmsg_flags)
+ llc_cmsg_rcv(msg, skb);
goto out;
}
@@ -1030,6 +1050,12 @@ static int llc_ui_setsockopt(struct socket *sock, int level, int optname,
goto out;
llc->rw = opt;
break;
+ case LLC_OPT_PKTINFO:
+ if (opt)
+ llc->cmsg_flags |= LLC_CMSG_PKTINFO;
+ else
+ llc->cmsg_flags &= ~LLC_CMSG_PKTINFO;
+ break;
default:
rc = -ENOPROTOOPT;
goto out;
@@ -1083,6 +1109,9 @@ static int llc_ui_getsockopt(struct socket *sock, int level, int optname,
val = llc->k; break;
case LLC_OPT_RX_WIN:
val = llc->rw; break;
+ case LLC_OPT_PKTINFO:
+ val = (llc->cmsg_flags & LLC_CMSG_PKTINFO) != 0;
+ break;
default:
rc = -ENOPROTOOPT;
goto out;
--
1.5.6.5
^ permalink raw reply related [flat|nested] 15+ messages in thread* [net-next PATCH v3 03/10] llc: add support for SO_BINDTODEVICE
2009-12-26 21:50 [net-next PATCH v3 0/10] llc enhancements Octavian Purdila
2009-12-26 21:50 ` [net-next PATCH v3 01/10] llc: use dev_hard_header Octavian Purdila
2009-12-26 21:51 ` [net-next PATCH v3 02/10] llc: add support for LLC_OPT_PKTINFO Octavian Purdila
@ 2009-12-26 21:51 ` Octavian Purdila
2009-12-26 21:51 ` [net-next PATCH v3 04/10] llc: convert the socket list to RCU locking Octavian Purdila
` (7 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Octavian Purdila @ 2009-12-26 21:51 UTC (permalink / raw)
To: netdev; +Cc: Arnaldo Carvalho de Melo, Eric Dumazet, Octavian Purdila
Using bind(MAC address) with LLC sockets has O(n) complexity, where n
is the number of interfaces. To overcome this, we add support for
SO_BINDTODEVICE which drops the complexity to O(1).
Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
---
net/llc/af_llc.c | 29 +++++++++++++++++++++++++++--
1 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index ac691fe..c4d1a1d 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -259,7 +259,14 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
if (!sock_flag(sk, SOCK_ZAPPED))
goto out;
rc = -ENODEV;
- llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd);
+ if (sk->sk_bound_dev_if) {
+ llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if);
+ if (llc->dev && addr->sllc_arphrd != llc->dev->type) {
+ dev_put(llc->dev);
+ llc->dev = NULL;
+ }
+ } else
+ llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd);
if (!llc->dev)
goto out;
rc = -EUSERS;
@@ -310,7 +317,25 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
goto out;
rc = -ENODEV;
rtnl_lock();
- llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd, addr->sllc_mac);
+ if (sk->sk_bound_dev_if) {
+ llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if);
+ if (llc->dev) {
+ if (!addr->sllc_arphrd)
+ addr->sllc_arphrd = llc->dev->type;
+ if (llc_mac_null(addr->sllc_mac))
+ memcpy(addr->sllc_mac, llc->dev->dev_addr,
+ IFHWADDRLEN);
+ if (addr->sllc_arphrd != llc->dev->type ||
+ !llc_mac_match(addr->sllc_mac,
+ llc->dev->dev_addr)) {
+ rc = -EINVAL;
+ dev_put(llc->dev);
+ llc->dev = NULL;
+ }
+ }
+ } else
+ llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd,
+ addr->sllc_mac);
rtnl_unlock();
if (!llc->dev)
goto out;
--
1.5.6.5
^ permalink raw reply related [flat|nested] 15+ messages in thread* [net-next PATCH v3 04/10] llc: convert the socket list to RCU locking
2009-12-26 21:50 [net-next PATCH v3 0/10] llc enhancements Octavian Purdila
` (2 preceding siblings ...)
2009-12-26 21:51 ` [net-next PATCH v3 03/10] llc: add support for SO_BINDTODEVICE Octavian Purdila
@ 2009-12-26 21:51 ` Octavian Purdila
2009-12-26 21:51 ` [net-next PATCH v3 05/10] llc: optimize multicast delivery Octavian Purdila
` (6 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Octavian Purdila @ 2009-12-26 21:51 UTC (permalink / raw)
To: netdev; +Cc: Arnaldo Carvalho de Melo, Eric Dumazet, Octavian Purdila
For the reclamation phase we use the SLAB_DESTROY_BY_RCU mechanism,
which require some extra checks in the lookup code:
a) If the current socket was released, reallocated & inserted in
another list it will short circuit the iteration for the current list,
thus we need to restart the lookup.
b) If the current socket was released, reallocated & inserted in the
same list we just need to recheck it matches the look-up criteria and
if not we can skip to the next element.
In this case there is no need to restart the lookup, since sockets are
inserted at the start of the list and the worst that will happen is
that we will iterate throught some of the list elements more then
once.
Note that the /proc and multicast delivery was not yet converted to
RCU, it still uses spinlocks for protection.
Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
---
include/net/llc.h | 7 ++--
net/llc/af_llc.c | 1 +
net/llc/llc_conn.c | 93 ++++++++++++++++++++++++++++++++++-----------------
net/llc/llc_core.c | 5 ++-
net/llc/llc_proc.c | 22 ++++++------
net/llc/llc_sap.c | 66 ++++++++++++++++++++++++-------------
6 files changed, 123 insertions(+), 71 deletions(-)
diff --git a/include/net/llc.h b/include/net/llc.h
index 7940da1..1559cf1 100644
--- a/include/net/llc.h
+++ b/include/net/llc.h
@@ -16,6 +16,7 @@
#include <linux/if_ether.h>
#include <linux/list.h>
#include <linux/spinlock.h>
+#include <linux/rculist_nulls.h>
#include <asm/atomic.h>
@@ -53,10 +54,8 @@ struct llc_sap {
struct net_device *orig_dev);
struct llc_addr laddr;
struct list_head node;
- struct {
- rwlock_t lock;
- struct hlist_head list;
- } sk_list;
+ spinlock_t sk_lock;
+ struct hlist_nulls_head sk_list;
};
#define LLC_DEST_INVALID 0 /* Invalid LLC PDU type */
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index c4d1a1d..f49f3dd 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -140,6 +140,7 @@ static struct proto llc_proto = {
.name = "LLC",
.owner = THIS_MODULE,
.obj_size = sizeof(struct llc_sock),
+ .slab_flags = SLAB_DESTROY_BY_RCU,
};
/**
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index c6bab39..77bb381 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -468,6 +468,19 @@ static int llc_exec_conn_trans_actions(struct sock *sk,
return rc;
}
+static inline bool llc_estab_match(const struct llc_sap *sap,
+ const struct llc_addr *daddr,
+ const struct llc_addr *laddr,
+ const struct sock *sk)
+{
+ struct llc_sock *llc = llc_sk(sk);
+
+ return llc->laddr.lsap == laddr->lsap &&
+ llc->daddr.lsap == daddr->lsap &&
+ llc_mac_match(llc->laddr.mac, laddr->mac) &&
+ llc_mac_match(llc->daddr.mac, daddr->mac);
+}
+
/**
* __llc_lookup_established - Finds connection for the remote/local sap/mac
* @sap: SAP
@@ -484,23 +497,26 @@ static struct sock *__llc_lookup_established(struct llc_sap *sap,
struct llc_addr *laddr)
{
struct sock *rc;
- struct hlist_node *node;
-
- read_lock(&sap->sk_list.lock);
- sk_for_each(rc, node, &sap->sk_list.list) {
- struct llc_sock *llc = llc_sk(rc);
-
- if (llc->laddr.lsap == laddr->lsap &&
- llc->daddr.lsap == daddr->lsap &&
- llc_mac_match(llc->laddr.mac, laddr->mac) &&
- llc_mac_match(llc->daddr.mac, daddr->mac)) {
- sock_hold(rc);
+ struct hlist_nulls_node *node;
+
+ rcu_read_lock();
+again:
+ sk_nulls_for_each_rcu(rc, node, &sap->sk_list) {
+ if (llc_estab_match(sap, daddr, laddr, rc)) {
+ /* Extra checks required by SLAB_DESTROY_BY_RCU */
+ if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
+ goto again;
+ if (unlikely(llc_sk(rc)->sap != sap ||
+ !llc_estab_match(sap, daddr, laddr, rc))) {
+ sock_put(rc);
+ continue;
+ }
goto found;
}
}
rc = NULL;
found:
- read_unlock(&sap->sk_list.lock);
+ rcu_read_unlock();
return rc;
}
@@ -516,6 +532,18 @@ struct sock *llc_lookup_established(struct llc_sap *sap,
return sk;
}
+static inline bool llc_listener_match(const struct llc_sap *sap,
+ const struct llc_addr *laddr,
+ const struct sock *sk)
+{
+ struct llc_sock *llc = llc_sk(sk);
+
+ return sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN &&
+ llc->laddr.lsap == laddr->lsap &&
+ (llc_mac_match(llc->laddr.mac, laddr->mac) ||
+ llc_mac_null(llc->laddr.mac));
+}
+
/**
* llc_lookup_listener - Finds listener for local MAC + SAP
* @sap: SAP
@@ -530,23 +558,26 @@ static struct sock *llc_lookup_listener(struct llc_sap *sap,
struct llc_addr *laddr)
{
struct sock *rc;
- struct hlist_node *node;
-
- read_lock(&sap->sk_list.lock);
- sk_for_each(rc, node, &sap->sk_list.list) {
- struct llc_sock *llc = llc_sk(rc);
-
- if (rc->sk_type == SOCK_STREAM && rc->sk_state == TCP_LISTEN &&
- llc->laddr.lsap == laddr->lsap &&
- (llc_mac_match(llc->laddr.mac, laddr->mac) ||
- llc_mac_null(llc->laddr.mac))) {
- sock_hold(rc);
+ struct hlist_nulls_node *node;
+
+ rcu_read_lock();
+again:
+ sk_nulls_for_each_rcu(rc, node, &sap->sk_list) {
+ if (llc_listener_match(sap, laddr, rc)) {
+ /* Extra checks required by SLAB_DESTROY_BY_RCU */
+ if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
+ goto again;
+ if (unlikely(llc_sk(rc)->sap != sap ||
+ !llc_listener_match(sap, laddr, rc))) {
+ sock_put(rc);
+ continue;
+ }
goto found;
}
}
rc = NULL;
found:
- read_unlock(&sap->sk_list.lock);
+ rcu_read_unlock();
return rc;
}
@@ -652,10 +683,10 @@ static int llc_find_offset(int state, int ev_type)
void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
{
llc_sap_hold(sap);
- write_lock_bh(&sap->sk_list.lock);
+ spin_lock_bh(&sap->sk_lock);
llc_sk(sk)->sap = sap;
- sk_add_node(sk, &sap->sk_list.list);
- write_unlock_bh(&sap->sk_list.lock);
+ sk_nulls_add_node_rcu(sk, &sap->sk_list);
+ spin_unlock_bh(&sap->sk_lock);
}
/**
@@ -663,14 +694,14 @@ void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
* @sap: SAP
* @sk: socket
*
- * This function removes a connection from sk_list.list of a SAP if
+ * This function removes a connection from sk_list of a SAP if
* the connection was in this list.
*/
void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk)
{
- write_lock_bh(&sap->sk_list.lock);
- sk_del_node_init(sk);
- write_unlock_bh(&sap->sk_list.lock);
+ spin_lock_bh(&sap->sk_lock);
+ sk_nulls_del_node_init_rcu(sk);
+ spin_unlock_bh(&sap->sk_lock);
llc_sap_put(sap);
}
diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c
index ff4c0ab..5276b97 100644
--- a/net/llc/llc_core.c
+++ b/net/llc/llc_core.c
@@ -37,7 +37,8 @@ static struct llc_sap *llc_sap_alloc(void)
if (sap) {
/* sap->laddr.mac - leave as a null, it's filled by bind */
sap->state = LLC_SAP_STATE_ACTIVE;
- rwlock_init(&sap->sk_list.lock);
+ spin_lock_init(&sap->sk_lock);
+ INIT_HLIST_NULLS_HEAD(&sap->sk_list, 0);
atomic_set(&sap->refcnt, 1);
}
return sap;
@@ -142,7 +143,7 @@ out:
*/
void llc_sap_close(struct llc_sap *sap)
{
- WARN_ON(!hlist_empty(&sap->sk_list.list));
+ WARN_ON(!hlist_nulls_empty(&sap->sk_list));
llc_del_sap(sap);
kfree(sap);
}
diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c
index be47ac4..6b3d033 100644
--- a/net/llc/llc_proc.c
+++ b/net/llc/llc_proc.c
@@ -34,19 +34,19 @@ static struct sock *llc_get_sk_idx(loff_t pos)
{
struct list_head *sap_entry;
struct llc_sap *sap;
- struct hlist_node *node;
+ struct hlist_nulls_node *node;
struct sock *sk = NULL;
list_for_each(sap_entry, &llc_sap_list) {
sap = list_entry(sap_entry, struct llc_sap, node);
- read_lock_bh(&sap->sk_list.lock);
- sk_for_each(sk, node, &sap->sk_list.list) {
+ spin_lock_bh(&sap->sk_lock);
+ sk_nulls_for_each(sk, node, &sap->sk_list) {
if (!pos)
goto found;
--pos;
}
- read_unlock_bh(&sap->sk_list.lock);
+ spin_unlock_bh(&sap->sk_lock);
}
sk = NULL;
found:
@@ -73,25 +73,25 @@ static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
goto out;
}
sk = v;
- next = sk_next(sk);
+ next = sk_nulls_next(sk);
if (next) {
sk = next;
goto out;
}
llc = llc_sk(sk);
sap = llc->sap;
- read_unlock_bh(&sap->sk_list.lock);
+ spin_unlock_bh(&sap->sk_lock);
sk = NULL;
for (;;) {
if (sap->node.next == &llc_sap_list)
break;
sap = list_entry(sap->node.next, struct llc_sap, node);
- read_lock_bh(&sap->sk_list.lock);
- if (!hlist_empty(&sap->sk_list.list)) {
- sk = sk_head(&sap->sk_list.list);
+ spin_lock_bh(&sap->sk_lock);
+ if (!hlist_nulls_empty(&sap->sk_list)) {
+ sk = sk_nulls_head(&sap->sk_list);
break;
}
- read_unlock_bh(&sap->sk_list.lock);
+ spin_unlock_bh(&sap->sk_lock);
}
out:
return sk;
@@ -104,7 +104,7 @@ static void llc_seq_stop(struct seq_file *seq, void *v)
struct llc_sock *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap;
- read_unlock_bh(&sap->sk_list.lock);
+ spin_unlock_bh(&sap->sk_lock);
}
read_unlock_bh(&llc_sap_list_lock);
}
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c
index 008de1f..39760d0 100644
--- a/net/llc/llc_sap.c
+++ b/net/llc/llc_sap.c
@@ -297,6 +297,17 @@ static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb,
llc_sap_state_process(sap, skb);
}
+static inline bool llc_dgram_match(const struct llc_sap *sap,
+ const struct llc_addr *laddr,
+ const struct sock *sk)
+{
+ struct llc_sock *llc = llc_sk(sk);
+
+ return sk->sk_type == SOCK_DGRAM &&
+ llc->laddr.lsap == laddr->lsap &&
+ llc_mac_match(llc->laddr.mac, laddr->mac);
+}
+
/**
* llc_lookup_dgram - Finds dgram socket for the local sap/mac
* @sap: SAP
@@ -309,25 +320,41 @@ static struct sock *llc_lookup_dgram(struct llc_sap *sap,
const struct llc_addr *laddr)
{
struct sock *rc;
- struct hlist_node *node;
-
- read_lock_bh(&sap->sk_list.lock);
- sk_for_each(rc, node, &sap->sk_list.list) {
- struct llc_sock *llc = llc_sk(rc);
-
- if (rc->sk_type == SOCK_DGRAM &&
- llc->laddr.lsap == laddr->lsap &&
- llc_mac_match(llc->laddr.mac, laddr->mac)) {
- sock_hold(rc);
+ struct hlist_nulls_node *node;
+
+ rcu_read_lock_bh();
+again:
+ sk_nulls_for_each_rcu(rc, node, &sap->sk_list) {
+ if (llc_dgram_match(sap, laddr, rc)) {
+ /* Extra checks required by SLAB_DESTROY_BY_RCU */
+ if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
+ goto again;
+ if (unlikely(llc_sk(rc)->sap != sap ||
+ !llc_dgram_match(sap, laddr, rc))) {
+ sock_put(rc);
+ continue;
+ }
goto found;
}
}
rc = NULL;
found:
- read_unlock_bh(&sap->sk_list.lock);
+ rcu_read_unlock_bh();
return rc;
}
+static inline bool llc_mcast_match(const struct llc_sap *sap,
+ const struct llc_addr *laddr,
+ const struct sk_buff *skb,
+ const struct sock *sk)
+{
+ struct llc_sock *llc = llc_sk(sk);
+
+ return sk->sk_type == SOCK_DGRAM &&
+ llc->laddr.lsap == laddr->lsap &&
+ llc->dev == skb->dev;
+}
+
/**
* llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets.
* @sap: SAP
@@ -341,20 +368,13 @@ static void llc_sap_mcast(struct llc_sap *sap,
struct sk_buff *skb)
{
struct sock *sk;
- struct hlist_node *node;
+ struct hlist_nulls_node *node;
- read_lock_bh(&sap->sk_list.lock);
- sk_for_each(sk, node, &sap->sk_list.list) {
- struct llc_sock *llc = llc_sk(sk);
+ spin_lock_bh(&sap->sk_lock);
+ sk_nulls_for_each_rcu(sk, node, &sap->sk_list) {
struct sk_buff *skb1;
- if (sk->sk_type != SOCK_DGRAM)
- continue;
-
- if (llc->laddr.lsap != laddr->lsap)
- continue;
-
- if (llc->dev != skb->dev)
+ if (!llc_mcast_match(sap, laddr, skb, sk))
continue;
skb1 = skb_clone(skb, GFP_ATOMIC);
@@ -365,7 +385,7 @@ static void llc_sap_mcast(struct llc_sap *sap,
llc_sap_rcv(sap, skb1, sk);
sock_put(sk);
}
- read_unlock_bh(&sap->sk_list.lock);
+ spin_unlock_bh(&sap->sk_lock);
}
--
1.5.6.5
^ permalink raw reply related [flat|nested] 15+ messages in thread* [net-next PATCH v3 05/10] llc: optimize multicast delivery
2009-12-26 21:50 [net-next PATCH v3 0/10] llc enhancements Octavian Purdila
` (3 preceding siblings ...)
2009-12-26 21:51 ` [net-next PATCH v3 04/10] llc: convert the socket list to RCU locking Octavian Purdila
@ 2009-12-26 21:51 ` Octavian Purdila
2009-12-26 21:51 ` [net-next PATCH v3 06/10] llc: use a device based hash table to speed up " Octavian Purdila
` (5 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Octavian Purdila @ 2009-12-26 21:51 UTC (permalink / raw)
To: netdev; +Cc: Arnaldo Carvalho de Melo, Eric Dumazet, Octavian Purdila
Optimize multicast delivery by doing the actual delivery without
holding the lock. Based on the same approach used in UDP code.
Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
---
net/llc/llc_sap.c | 36 ++++++++++++++++++++++++++++--------
1 files changed, 28 insertions(+), 8 deletions(-)
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c
index 39760d0..94790e6 100644
--- a/net/llc/llc_sap.c
+++ b/net/llc/llc_sap.c
@@ -355,6 +355,24 @@ static inline bool llc_mcast_match(const struct llc_sap *sap,
llc->dev == skb->dev;
}
+static void llc_do_mcast(struct llc_sap *sap, struct sk_buff *skb,
+ struct sock **stack, int count)
+{
+ struct sk_buff *skb1;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ skb1 = skb_clone(skb, GFP_ATOMIC);
+ if (!skb1) {
+ sock_put(stack[i]);
+ continue;
+ }
+
+ llc_sap_rcv(sap, skb1, stack[i]);
+ sock_put(stack[i]);
+ }
+}
+
/**
* llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets.
* @sap: SAP
@@ -367,25 +385,27 @@ static void llc_sap_mcast(struct llc_sap *sap,
const struct llc_addr *laddr,
struct sk_buff *skb)
{
- struct sock *sk;
+ int i = 0, count = 256 / sizeof(struct sock *);
+ struct sock *sk, *stack[count];
struct hlist_nulls_node *node;
spin_lock_bh(&sap->sk_lock);
sk_nulls_for_each_rcu(sk, node, &sap->sk_list) {
- struct sk_buff *skb1;
if (!llc_mcast_match(sap, laddr, skb, sk))
continue;
- skb1 = skb_clone(skb, GFP_ATOMIC);
- if (!skb1)
- break;
-
sock_hold(sk);
- llc_sap_rcv(sap, skb1, sk);
- sock_put(sk);
+ if (i < count)
+ stack[i++] = sk;
+ else {
+ llc_do_mcast(sap, skb, stack, i);
+ i = 0;
+ }
}
spin_unlock_bh(&sap->sk_lock);
+
+ llc_do_mcast(sap, skb, stack, i);
}
--
1.5.6.5
^ permalink raw reply related [flat|nested] 15+ messages in thread* [net-next PATCH v3 06/10] llc: use a device based hash table to speed up multicast delivery
2009-12-26 21:50 [net-next PATCH v3 0/10] llc enhancements Octavian Purdila
` (4 preceding siblings ...)
2009-12-26 21:51 ` [net-next PATCH v3 05/10] llc: optimize multicast delivery Octavian Purdila
@ 2009-12-26 21:51 ` Octavian Purdila
2009-12-26 21:51 ` [net-next PATCH v3 07/10] llc: replace the socket list with a local address based hash Octavian Purdila
` (4 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Octavian Purdila @ 2009-12-26 21:51 UTC (permalink / raw)
To: netdev; +Cc: Arnaldo Carvalho de Melo, Eric Dumazet, Octavian Purdila
This patch adds a per SAP device based hash table to solve the
multicast delivery scalability issue when we have large number of
interfaces and a large number of sockets bound to the same SAP.
Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
---
include/net/llc.h | 11 +++++++++++
include/net/llc_conn.h | 1 +
net/llc/llc_conn.c | 10 +++++++++-
net/llc/llc_sap.c | 8 ++++++--
4 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/include/net/llc.h b/include/net/llc.h
index 1559cf1..dbef591 100644
--- a/include/net/llc.h
+++ b/include/net/llc.h
@@ -32,6 +32,9 @@ struct llc_addr {
#define LLC_SAP_STATE_INACTIVE 1
#define LLC_SAP_STATE_ACTIVE 2
+#define LLC_SK_DEV_HASH_BITS 6
+#define LLC_SK_DEV_HASH_ENTRIES (1<<LLC_SK_DEV_HASH_BITS)
+
/**
* struct llc_sap - Defines the SAP component
*
@@ -56,8 +59,16 @@ struct llc_sap {
struct list_head node;
spinlock_t sk_lock;
struct hlist_nulls_head sk_list;
+ struct hlist_head sk_dev_hash[LLC_SK_DEV_HASH_ENTRIES];
};
+static inline
+struct hlist_head *llc_sk_dev_hash(struct llc_sap *sap, int ifindex)
+{
+ return &sap->sk_dev_hash[ifindex % LLC_SK_DEV_HASH_ENTRIES];
+}
+
+
#define LLC_DEST_INVALID 0 /* Invalid LLC PDU type */
#define LLC_DEST_SAP 1 /* Type 1 goes here */
#define LLC_DEST_CONN 2 /* Type 2 goes here */
diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h
index fe982fd..2f97d8d 100644
--- a/include/net/llc_conn.h
+++ b/include/net/llc_conn.h
@@ -77,6 +77,7 @@ struct llc_sock {
received and caused sending FRMR.
Used for resending FRMR */
u32 cmsg_flags;
+ struct hlist_node dev_hash_node;
};
static inline struct llc_sock *llc_sk(const struct sock *sk)
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index 77bb381..10cdfe2 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -682,10 +682,15 @@ static int llc_find_offset(int state, int ev_type)
*/
void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
{
+ struct llc_sock *llc = llc_sk(sk);
+ struct hlist_head *dev_hb = llc_sk_dev_hash(sap, llc->dev->ifindex);
+
llc_sap_hold(sap);
- spin_lock_bh(&sap->sk_lock);
llc_sk(sk)->sap = sap;
+
+ spin_lock_bh(&sap->sk_lock);
sk_nulls_add_node_rcu(sk, &sap->sk_list);
+ hlist_add_head(&llc->dev_hash_node, dev_hb);
spin_unlock_bh(&sap->sk_lock);
}
@@ -699,8 +704,11 @@ void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
*/
void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk)
{
+ struct llc_sock *llc = llc_sk(sk);
+
spin_lock_bh(&sap->sk_lock);
sk_nulls_del_node_init_rcu(sk);
+ hlist_del(&llc->dev_hash_node);
spin_unlock_bh(&sap->sk_lock);
llc_sap_put(sap);
}
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c
index 94790e6..94cb706 100644
--- a/net/llc/llc_sap.c
+++ b/net/llc/llc_sap.c
@@ -387,10 +387,14 @@ static void llc_sap_mcast(struct llc_sap *sap,
{
int i = 0, count = 256 / sizeof(struct sock *);
struct sock *sk, *stack[count];
- struct hlist_nulls_node *node;
+ struct hlist_node *node;
+ struct llc_sock *llc;
+ struct hlist_head *dev_hb = llc_sk_dev_hash(sap, skb->dev->ifindex);
spin_lock_bh(&sap->sk_lock);
- sk_nulls_for_each_rcu(sk, node, &sap->sk_list) {
+ hlist_for_each_entry(llc, node, dev_hb, dev_hash_node) {
+
+ sk = &llc->sk;
if (!llc_mcast_match(sap, laddr, skb, sk))
continue;
--
1.5.6.5
^ permalink raw reply related [flat|nested] 15+ messages in thread* [net-next PATCH v3 07/10] llc: replace the socket list with a local address based hash
2009-12-26 21:50 [net-next PATCH v3 0/10] llc enhancements Octavian Purdila
` (5 preceding siblings ...)
2009-12-26 21:51 ` [net-next PATCH v3 06/10] llc: use a device based hash table to speed up " Octavian Purdila
@ 2009-12-26 21:51 ` Octavian Purdila
2009-12-26 21:51 ` [net-next PATCH v3 08/10] llc: convert llc_sap_list to RCU Octavian Purdila
` (3 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Octavian Purdila @ 2009-12-26 21:51 UTC (permalink / raw)
To: netdev; +Cc: Arnaldo Carvalho de Melo, Eric Dumazet, Octavian Purdila
For the cases where a lot of interfaces are used in conjunction with a
lot of LLC sockets bound to the same SAP, the iteration of the socket
list becomes prohibitively expensive.
Replacing the list with a a local address based hash significantly
improves the bind and listener lookup operations as well as the
datagram delivery.
Connected sockets delivery is also improved, but this patch does not
address the case where we have lots of sockets with the same local
address connected to different remote addresses.
In order to keep the socket sanity checks alive and fast a socket
counter was added to the SAP structure.
Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
---
include/net/llc.h | 21 +++++++++++++++-
net/llc/llc_conn.c | 70 +++++++++++++++++++++++++++++++++++++--------------
net/llc/llc_core.c | 6 +++-
net/llc/llc_proc.c | 44 ++++++++++++++++++++++----------
net/llc/llc_sap.c | 11 +++++++-
5 files changed, 115 insertions(+), 37 deletions(-)
diff --git a/include/net/llc.h b/include/net/llc.h
index dbef591..709a9b3 100644
--- a/include/net/llc.h
+++ b/include/net/llc.h
@@ -17,6 +17,8 @@
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/rculist_nulls.h>
+#include <linux/hash.h>
+#include <linux/jhash.h>
#include <asm/atomic.h>
@@ -35,6 +37,9 @@ struct llc_addr {
#define LLC_SK_DEV_HASH_BITS 6
#define LLC_SK_DEV_HASH_ENTRIES (1<<LLC_SK_DEV_HASH_BITS)
+#define LLC_SK_LADDR_HASH_BITS 6
+#define LLC_SK_LADDR_HASH_ENTRIES (1<<LLC_SK_LADDR_HASH_BITS)
+
/**
* struct llc_sap - Defines the SAP component
*
@@ -58,7 +63,8 @@ struct llc_sap {
struct llc_addr laddr;
struct list_head node;
spinlock_t sk_lock;
- struct hlist_nulls_head sk_list;
+ int sk_count;
+ struct hlist_nulls_head sk_laddr_hash[LLC_SK_LADDR_HASH_ENTRIES];
struct hlist_head sk_dev_hash[LLC_SK_DEV_HASH_ENTRIES];
};
@@ -68,6 +74,19 @@ struct hlist_head *llc_sk_dev_hash(struct llc_sap *sap, int ifindex)
return &sap->sk_dev_hash[ifindex % LLC_SK_DEV_HASH_ENTRIES];
}
+static inline
+u32 llc_sk_laddr_hashfn(struct llc_sap *sap, const struct llc_addr *laddr)
+{
+ return hash_32(jhash(laddr->mac, sizeof(laddr->mac), 0),
+ LLC_SK_LADDR_HASH_BITS);
+}
+
+static inline
+struct hlist_nulls_head *llc_sk_laddr_hash(struct llc_sap *sap,
+ const struct llc_addr *laddr)
+{
+ return &sap->sk_laddr_hash[llc_sk_laddr_hashfn(sap, laddr)];
+}
#define LLC_DEST_INVALID 0 /* Invalid LLC PDU type */
#define LLC_DEST_SAP 1 /* Type 1 goes here */
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index 10cdfe2..a8dde9b 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -498,10 +498,12 @@ static struct sock *__llc_lookup_established(struct llc_sap *sap,
{
struct sock *rc;
struct hlist_nulls_node *node;
+ int slot = llc_sk_laddr_hashfn(sap, laddr);
+ struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot];
rcu_read_lock();
again:
- sk_nulls_for_each_rcu(rc, node, &sap->sk_list) {
+ sk_nulls_for_each_rcu(rc, node, laddr_hb) {
if (llc_estab_match(sap, daddr, laddr, rc)) {
/* Extra checks required by SLAB_DESTROY_BY_RCU */
if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
@@ -515,6 +517,13 @@ again:
}
}
rc = NULL;
+ /*
+ * if the nulls value we got at the end of this lookup is
+ * not the expected one, we must restart lookup.
+ * We probably met an item that was moved to another chain.
+ */
+ if (unlikely(get_nulls_value(node) != slot))
+ goto again;
found:
rcu_read_unlock();
return rc;
@@ -540,29 +549,20 @@ static inline bool llc_listener_match(const struct llc_sap *sap,
return sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN &&
llc->laddr.lsap == laddr->lsap &&
- (llc_mac_match(llc->laddr.mac, laddr->mac) ||
- llc_mac_null(llc->laddr.mac));
+ llc_mac_match(llc->laddr.mac, laddr->mac);
}
-/**
- * llc_lookup_listener - Finds listener for local MAC + SAP
- * @sap: SAP
- * @laddr: address of local LLC (MAC + SAP)
- *
- * Search connection list of the SAP and finds connection listening on
- * local mac, and local sap. Returns pointer for parent socket found,
- * %NULL otherwise.
- * Caller has to make sure local_bh is disabled.
- */
-static struct sock *llc_lookup_listener(struct llc_sap *sap,
- struct llc_addr *laddr)
+static struct sock *__llc_lookup_listener(struct llc_sap *sap,
+ struct llc_addr *laddr)
{
struct sock *rc;
struct hlist_nulls_node *node;
+ int slot = llc_sk_laddr_hashfn(sap, laddr);
+ struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot];
rcu_read_lock();
again:
- sk_nulls_for_each_rcu(rc, node, &sap->sk_list) {
+ sk_nulls_for_each_rcu(rc, node, laddr_hb) {
if (llc_listener_match(sap, laddr, rc)) {
/* Extra checks required by SLAB_DESTROY_BY_RCU */
if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
@@ -576,11 +576,40 @@ again:
}
}
rc = NULL;
+ /*
+ * if the nulls value we got at the end of this lookup is
+ * not the expected one, we must restart lookup.
+ * We probably met an item that was moved to another chain.
+ */
+ if (unlikely(get_nulls_value(node) != slot))
+ goto again;
found:
rcu_read_unlock();
return rc;
}
+/**
+ * llc_lookup_listener - Finds listener for local MAC + SAP
+ * @sap: SAP
+ * @laddr: address of local LLC (MAC + SAP)
+ *
+ * Search connection list of the SAP and finds connection listening on
+ * local mac, and local sap. Returns pointer for parent socket found,
+ * %NULL otherwise.
+ * Caller has to make sure local_bh is disabled.
+ */
+static struct sock *llc_lookup_listener(struct llc_sap *sap,
+ struct llc_addr *laddr)
+{
+ static struct llc_addr null_addr;
+ struct sock *rc = __llc_lookup_listener(sap, laddr);
+
+ if (!rc)
+ rc = __llc_lookup_listener(sap, &null_addr);
+
+ return rc;
+}
+
static struct sock *__llc_lookup(struct llc_sap *sap,
struct llc_addr *daddr,
struct llc_addr *laddr)
@@ -678,18 +707,20 @@ static int llc_find_offset(int state, int ev_type)
* @sap: SAP
* @sk: socket
*
- * This function adds a socket to sk_list of a SAP.
+ * This function adds a socket to the hash tables of a SAP.
*/
void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
{
struct llc_sock *llc = llc_sk(sk);
struct hlist_head *dev_hb = llc_sk_dev_hash(sap, llc->dev->ifindex);
+ struct hlist_nulls_head *laddr_hb = llc_sk_laddr_hash(sap, &llc->laddr);
llc_sap_hold(sap);
llc_sk(sk)->sap = sap;
spin_lock_bh(&sap->sk_lock);
- sk_nulls_add_node_rcu(sk, &sap->sk_list);
+ sap->sk_count++;
+ sk_nulls_add_node_rcu(sk, laddr_hb);
hlist_add_head(&llc->dev_hash_node, dev_hb);
spin_unlock_bh(&sap->sk_lock);
}
@@ -699,7 +730,7 @@ void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
* @sap: SAP
* @sk: socket
*
- * This function removes a connection from sk_list of a SAP if
+ * This function removes a connection from the hash tables of a SAP if
* the connection was in this list.
*/
void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk)
@@ -709,6 +740,7 @@ void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk)
spin_lock_bh(&sap->sk_lock);
sk_nulls_del_node_init_rcu(sk);
hlist_del(&llc->dev_hash_node);
+ sap->sk_count--;
spin_unlock_bh(&sap->sk_lock);
llc_sap_put(sap);
}
diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c
index 5276b97..0c9ef8b 100644
--- a/net/llc/llc_core.c
+++ b/net/llc/llc_core.c
@@ -33,12 +33,14 @@ DEFINE_RWLOCK(llc_sap_list_lock);
static struct llc_sap *llc_sap_alloc(void)
{
struct llc_sap *sap = kzalloc(sizeof(*sap), GFP_ATOMIC);
+ int i;
if (sap) {
/* sap->laddr.mac - leave as a null, it's filled by bind */
sap->state = LLC_SAP_STATE_ACTIVE;
spin_lock_init(&sap->sk_lock);
- INIT_HLIST_NULLS_HEAD(&sap->sk_list, 0);
+ for (i = 0; i < LLC_SK_LADDR_HASH_ENTRIES; i++)
+ INIT_HLIST_NULLS_HEAD(&sap->sk_laddr_hash[i], i);
atomic_set(&sap->refcnt, 1);
}
return sap;
@@ -143,7 +145,7 @@ out:
*/
void llc_sap_close(struct llc_sap *sap)
{
- WARN_ON(!hlist_nulls_empty(&sap->sk_list));
+ WARN_ON(sap->sk_count);
llc_del_sap(sap);
kfree(sap);
}
diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c
index 6b3d033..09dec63 100644
--- a/net/llc/llc_proc.c
+++ b/net/llc/llc_proc.c
@@ -34,17 +34,22 @@ static struct sock *llc_get_sk_idx(loff_t pos)
{
struct list_head *sap_entry;
struct llc_sap *sap;
- struct hlist_nulls_node *node;
struct sock *sk = NULL;
+ int i;
list_for_each(sap_entry, &llc_sap_list) {
sap = list_entry(sap_entry, struct llc_sap, node);
spin_lock_bh(&sap->sk_lock);
- sk_nulls_for_each(sk, node, &sap->sk_list) {
- if (!pos)
- goto found;
- --pos;
+ for (i = 0; i < LLC_SK_LADDR_HASH_ENTRIES; i++) {
+ struct hlist_nulls_head *head = &sap->sk_laddr_hash[i];
+ struct hlist_nulls_node *node;
+
+ sk_nulls_for_each(sk, node, head) {
+ if (!pos)
+ goto found; /* keep the lock */
+ --pos;
+ }
}
spin_unlock_bh(&sap->sk_lock);
}
@@ -61,6 +66,19 @@ static void *llc_seq_start(struct seq_file *seq, loff_t *pos)
return l ? llc_get_sk_idx(--l) : SEQ_START_TOKEN;
}
+static struct sock *laddr_hash_next(struct llc_sap *sap, int bucket)
+{
+ struct hlist_nulls_node *node;
+ struct sock *sk = NULL;
+
+ while (++bucket < LLC_SK_LADDR_HASH_ENTRIES)
+ sk_nulls_for_each(sk, node, &sap->sk_laddr_hash[bucket])
+ goto out;
+
+out:
+ return sk;
+}
+
static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct sock* sk, *next;
@@ -80,17 +98,15 @@ static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
}
llc = llc_sk(sk);
sap = llc->sap;
+ sk = laddr_hash_next(sap, llc_sk_laddr_hashfn(sap, &llc->laddr));
+ if (sk)
+ goto out;
spin_unlock_bh(&sap->sk_lock);
- sk = NULL;
- for (;;) {
- if (sap->node.next == &llc_sap_list)
- break;
- sap = list_entry(sap->node.next, struct llc_sap, node);
+ list_for_each_entry_continue(sap, &llc_sap_list, node) {
spin_lock_bh(&sap->sk_lock);
- if (!hlist_nulls_empty(&sap->sk_list)) {
- sk = sk_nulls_head(&sap->sk_list);
- break;
- }
+ sk = laddr_hash_next(sap, -1);
+ if (sk)
+ break; /* keep the lock */
spin_unlock_bh(&sap->sk_lock);
}
out:
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c
index 94cb706..ad6e6e1 100644
--- a/net/llc/llc_sap.c
+++ b/net/llc/llc_sap.c
@@ -321,10 +321,12 @@ static struct sock *llc_lookup_dgram(struct llc_sap *sap,
{
struct sock *rc;
struct hlist_nulls_node *node;
+ int slot = llc_sk_laddr_hashfn(sap, laddr);
+ struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot];
rcu_read_lock_bh();
again:
- sk_nulls_for_each_rcu(rc, node, &sap->sk_list) {
+ sk_nulls_for_each_rcu(rc, node, laddr_hb) {
if (llc_dgram_match(sap, laddr, rc)) {
/* Extra checks required by SLAB_DESTROY_BY_RCU */
if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
@@ -338,6 +340,13 @@ again:
}
}
rc = NULL;
+ /*
+ * if the nulls value we got at the end of this lookup is
+ * not the expected one, we must restart lookup.
+ * We probably met an item that was moved to another chain.
+ */
+ if (unlikely(get_nulls_value(node) != slot))
+ goto again;
found:
rcu_read_unlock_bh();
return rc;
--
1.5.6.5
^ permalink raw reply related [flat|nested] 15+ messages in thread* [net-next PATCH v3 08/10] llc: convert llc_sap_list to RCU
2009-12-26 21:50 [net-next PATCH v3 0/10] llc enhancements Octavian Purdila
` (6 preceding siblings ...)
2009-12-26 21:51 ` [net-next PATCH v3 07/10] llc: replace the socket list with a local address based hash Octavian Purdila
@ 2009-12-26 21:51 ` Octavian Purdila
2009-12-26 21:51 ` [net-next PATCH v3 09/10] llc: remove unused APIs (which should be private anyway) Octavian Purdila
` (2 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Octavian Purdila @ 2009-12-26 21:51 UTC (permalink / raw)
To: netdev; +Cc: Arnaldo Carvalho de Melo, Eric Dumazet, Octavian Purdila
Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
---
include/net/llc.h | 2 +-
net/llc/llc_core.c | 46 ++++++++++++++--------------------------------
net/llc/llc_proc.c | 11 ++++-------
3 files changed, 19 insertions(+), 40 deletions(-)
diff --git a/include/net/llc.h b/include/net/llc.h
index 709a9b3..5503b74 100644
--- a/include/net/llc.h
+++ b/include/net/llc.h
@@ -93,7 +93,7 @@ struct hlist_nulls_head *llc_sk_laddr_hash(struct llc_sap *sap,
#define LLC_DEST_CONN 2 /* Type 2 goes here */
extern struct list_head llc_sap_list;
-extern rwlock_t llc_sap_list_lock;
+extern spinlock_t llc_sap_list_lock;
extern int llc_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev);
diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c
index 0c9ef8b..78167e8 100644
--- a/net/llc/llc_core.c
+++ b/net/llc/llc_core.c
@@ -23,7 +23,7 @@
#include <net/llc.h>
LIST_HEAD(llc_sap_list);
-DEFINE_RWLOCK(llc_sap_list_lock);
+DEFINE_SPINLOCK(llc_sap_list_lock);
/**
* llc_sap_alloc - allocates and initializes sap.
@@ -46,30 +46,6 @@ static struct llc_sap *llc_sap_alloc(void)
return sap;
}
-/**
- * llc_add_sap - add sap to station list
- * @sap: Address of the sap
- *
- * Adds a sap to the LLC's station sap list.
- */
-static void llc_add_sap(struct llc_sap *sap)
-{
- list_add_tail(&sap->node, &llc_sap_list);
-}
-
-/**
- * llc_del_sap - del sap from station list
- * @sap: Address of the sap
- *
- * Removes a sap to the LLC's station sap list.
- */
-static void llc_del_sap(struct llc_sap *sap)
-{
- write_lock_bh(&llc_sap_list_lock);
- list_del(&sap->node);
- write_unlock_bh(&llc_sap_list_lock);
-}
-
static struct llc_sap *__llc_sap_find(unsigned char sap_value)
{
struct llc_sap* sap;
@@ -93,13 +69,13 @@ out:
*/
struct llc_sap *llc_sap_find(unsigned char sap_value)
{
- struct llc_sap* sap;
+ struct llc_sap *sap;
- read_lock_bh(&llc_sap_list_lock);
+ rcu_read_lock_bh();
sap = __llc_sap_find(sap_value);
if (sap)
llc_sap_hold(sap);
- read_unlock_bh(&llc_sap_list_lock);
+ rcu_read_unlock_bh();
return sap;
}
@@ -120,7 +96,7 @@ struct llc_sap *llc_sap_open(unsigned char lsap,
{
struct llc_sap *sap = NULL;
- write_lock_bh(&llc_sap_list_lock);
+ spin_lock_bh(&llc_sap_list_lock);
if (__llc_sap_find(lsap)) /* SAP already exists */
goto out;
sap = llc_sap_alloc();
@@ -128,9 +104,9 @@ struct llc_sap *llc_sap_open(unsigned char lsap,
goto out;
sap->laddr.lsap = lsap;
sap->rcv_func = func;
- llc_add_sap(sap);
+ list_add_tail_rcu(&sap->node, &llc_sap_list);
out:
- write_unlock_bh(&llc_sap_list_lock);
+ spin_unlock_bh(&llc_sap_list_lock);
return sap;
}
@@ -146,7 +122,13 @@ out:
void llc_sap_close(struct llc_sap *sap)
{
WARN_ON(sap->sk_count);
- llc_del_sap(sap);
+
+ spin_lock_bh(&llc_sap_list_lock);
+ list_del_rcu(&sap->node);
+ spin_unlock_bh(&llc_sap_list_lock);
+
+ synchronize_rcu();
+
kfree(sap);
}
diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c
index 09dec63..7af1ff2 100644
--- a/net/llc/llc_proc.c
+++ b/net/llc/llc_proc.c
@@ -32,14 +32,11 @@ static void llc_ui_format_mac(struct seq_file *seq, u8 *addr)
static struct sock *llc_get_sk_idx(loff_t pos)
{
- struct list_head *sap_entry;
struct llc_sap *sap;
struct sock *sk = NULL;
int i;
- list_for_each(sap_entry, &llc_sap_list) {
- sap = list_entry(sap_entry, struct llc_sap, node);
-
+ list_for_each_entry_rcu(sap, &llc_sap_list, node) {
spin_lock_bh(&sap->sk_lock);
for (i = 0; i < LLC_SK_LADDR_HASH_ENTRIES; i++) {
struct hlist_nulls_head *head = &sap->sk_laddr_hash[i];
@@ -62,7 +59,7 @@ static void *llc_seq_start(struct seq_file *seq, loff_t *pos)
{
loff_t l = *pos;
- read_lock_bh(&llc_sap_list_lock);
+ rcu_read_lock_bh();
return l ? llc_get_sk_idx(--l) : SEQ_START_TOKEN;
}
@@ -102,7 +99,7 @@ static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
if (sk)
goto out;
spin_unlock_bh(&sap->sk_lock);
- list_for_each_entry_continue(sap, &llc_sap_list, node) {
+ list_for_each_entry_continue_rcu(sap, &llc_sap_list, node) {
spin_lock_bh(&sap->sk_lock);
sk = laddr_hash_next(sap, -1);
if (sk)
@@ -122,7 +119,7 @@ static void llc_seq_stop(struct seq_file *seq, void *v)
spin_unlock_bh(&sap->sk_lock);
}
- read_unlock_bh(&llc_sap_list_lock);
+ rcu_read_unlock_bh();
}
static int llc_seq_socket_show(struct seq_file *seq, void *v)
--
1.5.6.5
^ permalink raw reply related [flat|nested] 15+ messages in thread* [net-next PATCH v3 09/10] llc: remove unused APIs (which should be private anyway)
2009-12-26 21:50 [net-next PATCH v3 0/10] llc enhancements Octavian Purdila
` (7 preceding siblings ...)
2009-12-26 21:51 ` [net-next PATCH v3 08/10] llc: convert llc_sap_list to RCU Octavian Purdila
@ 2009-12-26 21:51 ` Octavian Purdila
2009-12-26 21:51 ` [net-next PATCH v3 10/10] llc: fix SAP reference counting w.r.t. socket handling Octavian Purdila
2009-12-27 4:32 ` [net-next PATCH v3 0/10] llc enhancements David Miller
10 siblings, 0 replies; 15+ messages in thread
From: Octavian Purdila @ 2009-12-26 21:51 UTC (permalink / raw)
To: netdev; +Cc: Arnaldo Carvalho de Melo, Eric Dumazet, Octavian Purdila
Remove the list & lock from the exported API - it is not used anywhere
in the tree and most operations should be covered by llc_sap_open(),
llc_sap_close() and llc_sap_find().
Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
---
include/net/llc.h | 1 -
net/llc/llc_core.c | 4 +---
2 files changed, 1 insertions(+), 4 deletions(-)
diff --git a/include/net/llc.h b/include/net/llc.h
index 5503b74..915d168 100644
--- a/include/net/llc.h
+++ b/include/net/llc.h
@@ -93,7 +93,6 @@ struct hlist_nulls_head *llc_sk_laddr_hash(struct llc_sap *sap,
#define LLC_DEST_CONN 2 /* Type 2 goes here */
extern struct list_head llc_sap_list;
-extern spinlock_t llc_sap_list_lock;
extern int llc_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev);
diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c
index 78167e8..8363637 100644
--- a/net/llc/llc_core.c
+++ b/net/llc/llc_core.c
@@ -23,7 +23,7 @@
#include <net/llc.h>
LIST_HEAD(llc_sap_list);
-DEFINE_SPINLOCK(llc_sap_list_lock);
+static DEFINE_SPINLOCK(llc_sap_list_lock);
/**
* llc_sap_alloc - allocates and initializes sap.
@@ -164,8 +164,6 @@ static void __exit llc_exit(void)
module_init(llc_init);
module_exit(llc_exit);
-EXPORT_SYMBOL(llc_sap_list);
-EXPORT_SYMBOL(llc_sap_list_lock);
EXPORT_SYMBOL(llc_sap_find);
EXPORT_SYMBOL(llc_sap_open);
EXPORT_SYMBOL(llc_sap_close);
--
1.5.6.5
^ permalink raw reply related [flat|nested] 15+ messages in thread* [net-next PATCH v3 10/10] llc: fix SAP reference counting w.r.t. socket handling
2009-12-26 21:50 [net-next PATCH v3 0/10] llc enhancements Octavian Purdila
` (8 preceding siblings ...)
2009-12-26 21:51 ` [net-next PATCH v3 09/10] llc: remove unused APIs (which should be private anyway) Octavian Purdila
@ 2009-12-26 21:51 ` Octavian Purdila
2009-12-27 4:32 ` [net-next PATCH v3 0/10] llc enhancements David Miller
10 siblings, 0 replies; 15+ messages in thread
From: Octavian Purdila @ 2009-12-26 21:51 UTC (permalink / raw)
To: netdev; +Cc: Arnaldo Carvalho de Melo, Eric Dumazet, Octavian Purdila
The SAP ref counter gets decremented twice when deleting a socket,
although for all but the first socket of a SAP the SAP ref counter was
incremented only once.
Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
---
net/llc/af_llc.c | 5 +----
1 files changed, 1 insertions(+), 4 deletions(-)
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index f49f3dd..e35d907 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -197,10 +197,8 @@ static int llc_ui_release(struct socket *sock)
llc->laddr.lsap, llc->daddr.lsap);
if (!llc_send_disc(sk))
llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo);
- if (!sock_flag(sk, SOCK_ZAPPED)) {
- llc_sap_put(llc->sap);
+ if (!sock_flag(sk, SOCK_ZAPPED))
llc_sap_remove_socket(llc->sap, sk);
- }
release_sock(sk);
if (llc->dev)
dev_put(llc->dev);
@@ -352,7 +350,6 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
rc = -EBUSY; /* some other network layer is using the sap */
if (!sap)
goto out;
- llc_sap_hold(sap);
} else {
struct llc_addr laddr, daddr;
struct sock *ask;
--
1.5.6.5
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [net-next PATCH v3 0/10] llc enhancements
2009-12-26 21:50 [net-next PATCH v3 0/10] llc enhancements Octavian Purdila
` (9 preceding siblings ...)
2009-12-26 21:51 ` [net-next PATCH v3 10/10] llc: fix SAP reference counting w.r.t. socket handling Octavian Purdila
@ 2009-12-27 4:32 ` David Miller
2009-12-27 4:37 ` David Miller
10 siblings, 1 reply; 15+ messages in thread
From: David Miller @ 2009-12-27 4:32 UTC (permalink / raw)
To: opurdila; +Cc: netdev, acme, eric.dumazet
From: Octavian Purdila <opurdila@ixiacom.com>
Date: Sat, 26 Dec 2009 23:50:58 +0200
>
> This patch set modifies the LLC code to scale the socket lookup code
> for a large number of interfaces and large number of sockets bound to
> the same SAP. We use it for STP traffic generation from a large number
> of virtual STP ports, via virtual network interfaces.
>
> In the process we converted the socket lookup code and sap list to use
> RCU. It also contains some general cleanups (use dev_hard_header
> instead of handcrafting the headers) and enhancements (LLC_OPT_PKTINFO).
Looks good, applied to net-next-2.6, thanks!
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [net-next PATCH v3 0/10] llc enhancements
2009-12-27 4:32 ` [net-next PATCH v3 0/10] llc enhancements David Miller
@ 2009-12-27 4:37 ` David Miller
2009-12-27 4:47 ` David Miller
0 siblings, 1 reply; 15+ messages in thread
From: David Miller @ 2009-12-27 4:37 UTC (permalink / raw)
To: opurdila; +Cc: netdev, acme, eric.dumazet
From: David Miller <davem@davemloft.net>
Date: Sat, 26 Dec 2009 20:32:52 -0800 (PST)
> Looks good, applied to net-next-2.6, thanks!
Ugh, it doesn't even build when LLC and LLC2 are both modular:
ERROR: "llc_sap_list" [net/llc/llc2.ko] undefined!
make[1]: *** [__modpost] Error 1
make: *** [modules] Error 2
make: *** Waiting for unfinished jobs....
I'll fix this up, but next time please do some more build
testing.
Thanks.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [net-next PATCH v3 0/10] llc enhancements
2009-12-27 4:37 ` David Miller
@ 2009-12-27 4:47 ` David Miller
2009-12-27 12:02 ` Octavian Purdila
0 siblings, 1 reply; 15+ messages in thread
From: David Miller @ 2009-12-27 4:47 UTC (permalink / raw)
To: opurdila; +Cc: netdev, acme, eric.dumazet
From: David Miller <davem@davemloft.net>
Date: Sat, 26 Dec 2009 20:37:27 -0800 (PST)
> ERROR: "llc_sap_list" [net/llc/llc2.ko] undefined!
> make[1]: *** [__modpost] Error 1
> make: *** [modules] Error 2
> make: *** Waiting for unfinished jobs....
>
> I'll fix this up, but next time please do some more build
> testing.
So I'm going to fix this by tossing patch #9 entirely.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [net-next PATCH v3 0/10] llc enhancements
2009-12-27 4:47 ` David Miller
@ 2009-12-27 12:02 ` Octavian Purdila
0 siblings, 0 replies; 15+ messages in thread
From: Octavian Purdila @ 2009-12-27 12:02 UTC (permalink / raw)
To: David Miller; +Cc: netdev, acme, eric.dumazet
On Sunday 27 December 2009 06:47:54 you wrote:
> From: David Miller <davem@davemloft.net>
> Date: Sat, 26 Dec 2009 20:37:27 -0800 (PST)
>
> > ERROR: "llc_sap_list" [net/llc/llc2.ko] undefined!
> > make[1]: *** [__modpost] Error 1
> > make: *** [modules] Error 2
> > make: *** Waiting for unfinished jobs....
> >
> > I'll fix this up, but next time please do some more build
> > testing.
>
> So I'm going to fix this by tossing patch #9 entirely.
>
Sorry about that, patch #9 is completely wrong indeed. Next time I won't skip
the full allmodconfig build.
Thanks !
^ permalink raw reply [flat|nested] 15+ messages in thread