* Re: [PATCH v3] net: Allow no-cache copy from user on transmit
From: Michał Mirosław @ 2011-03-31 8:52 UTC (permalink / raw)
To: Tom Herbert; +Cc: davem, netdev
In-Reply-To: <alpine.DEB.2.00.1103302156270.17065@pokey.mtv.corp.google.com>
2011/3/31 Tom Herbert <therbert@google.com>:
> This patch uses __copy_from_user_nocache (from skb_copy_to_page)
> on transmit to bypass data cache for a performance improvement.
> This functionality is configurable per device using ethtool.
[...]
> diff --git a/include/net/sock.h b/include/net/sock.h
> index da0534d..74ce586 100644
> --- a/include/net/sock.h
> +++ b/include/net/sock.h
> @@ -1401,6 +1401,11 @@ static inline int skb_copy_to_page(struct sock *sk, char __user *from,
> if (err)
> return err;
> skb->csum = csum_block_add(skb->csum, csum, skb->len);
> + } else if (sk->sk_route_caps & NETIF_F_NOCACHE_COPY) {
> + if (!access_ok(VERIFY_READ, from, copy) ||
> + __copy_from_user_nocache(page_address(page) + off,
> + from, copy))
> + return -EFAULT;
> } else if (copy_from_user(page_address(page) + off, from, copy))
> return -EFAULT;
>
BTW, the checks should take protocol into account. If, for example,
device has NOCACHE_COPY and CSUM_IPV4, but not CSUM_IPV6, then it will
take a hit for every IPv6 packet that needs checksumming in software.
Maybe this can be taken into account when sk_route_caps are set?
[...]
> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> index 1a6e9eb..59b6ce9 100644
> --- a/drivers/net/bonding/bond_main.c
> +++ b/drivers/net/bonding/bond_main.c
> @@ -1407,7 +1407,7 @@ static int bond_compute_features(struct bonding *bond)
> int i;
>
> features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES);
> - features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM;
> + features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_NOCACHE_COPY;
>
> if (!bond->first_slave)
> goto done;
[...]
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 0b88eba..454abfd 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -5444,6 +5444,13 @@ int register_netdevice(struct net_device *dev)
> dev->features &= ~NETIF_F_GSO;
> }
>
> + /* Turn no cache copy off if HW isn't doing checksum */
> + if (!(dev->features & NETIF_F_ALL_CSUM) ||
> + (dev->features & NETIF_F_NO_CSUM)) {
> + dev->wanted_features &= ~NETIF_F_NOCACHE_COPY;
> + dev->features &= ~NETIF_F_NOCACHE_COPY;
> + }
> +
> /* Enable GRO and NETIF_F_HIGHDMA for vlans by default,
> * vlan_dev_init() will do the dev->features check, so these features
> * are enabled only if supported by underlying device.
Why NO_CSUM is disabling NOCACHE_COPY? You combine those features in
bonding code anyway.
You didn't add netdev_fix_features() checks, so NOCACHE_COPY might be
enabled via ethtool after device is registered even if driver doesn't
support checksum offloads.
Best Regards,
Michał Mirosław
^ permalink raw reply
* Re: [PATCH net-next-2.6] fib: add __rcu annotations
From: David Miller @ 2011-03-31 8:51 UTC (permalink / raw)
To: eric.dumazet; +Cc: netdev
In-Reply-To: <1301561072.3169.23.camel@edumazet-laptop>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Thu, 31 Mar 2011 10:44:32 +0200
> Add __rcu annotations and lockdep checks.
>
> Add const qualifiers
>
> node_parent() and node_parent_rcu() can use
> rcu_dereference_index_check()
>
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Applied, thanks Eric.
^ permalink raw reply
* [PATCH net-next-2.6] fib: add __rcu annotations
From: Eric Dumazet @ 2011-03-31 8:44 UTC (permalink / raw)
To: David Miller; +Cc: netdev
Add __rcu annotations and lockdep checks.
Add const qualifiers
node_parent() and node_parent_rcu() can use
rcu_dereference_index_check()
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
net/ipv4/fib_trie.c | 103 +++++++++++++++++++++++-------------------
1 file changed, 58 insertions(+), 45 deletions(-)
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index b92c86f..b9d1f33 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -126,7 +126,7 @@ struct tnode {
struct work_struct work;
struct tnode *tnode_free;
};
- struct rt_trie_node *child[0];
+ struct rt_trie_node __rcu *child[0];
};
#ifdef CONFIG_IP_FIB_TRIE_STATS
@@ -151,7 +151,7 @@ struct trie_stat {
};
struct trie {
- struct rt_trie_node *trie;
+ struct rt_trie_node __rcu *trie;
#ifdef CONFIG_IP_FIB_TRIE_STATS
struct trie_use_stats stats;
#endif
@@ -177,16 +177,29 @@ static const int sync_pages = 128;
static struct kmem_cache *fn_alias_kmem __read_mostly;
static struct kmem_cache *trie_leaf_kmem __read_mostly;
-static inline struct tnode *node_parent(struct rt_trie_node *node)
+/*
+ * caller must hold RTNL
+ */
+static inline struct tnode *node_parent(const struct rt_trie_node *node)
{
- return (struct tnode *)(node->parent & ~NODE_TYPE_MASK);
+ unsigned long parent;
+
+ parent = rcu_dereference_index_check(node->parent, lockdep_rtnl_is_held());
+
+ return (struct tnode *)(parent & ~NODE_TYPE_MASK);
}
-static inline struct tnode *node_parent_rcu(struct rt_trie_node *node)
+/*
+ * caller must hold RCU read lock or RTNL
+ */
+static inline struct tnode *node_parent_rcu(const struct rt_trie_node *node)
{
- struct tnode *ret = node_parent(node);
+ unsigned long parent;
+
+ parent = rcu_dereference_index_check(node->parent, rcu_read_lock_held() ||
+ lockdep_rtnl_is_held());
- return rcu_dereference_rtnl(ret);
+ return (struct tnode *)(parent & ~NODE_TYPE_MASK);
}
/* Same as rcu_assign_pointer
@@ -198,18 +211,24 @@ static inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr)
node->parent = (unsigned long)ptr | NODE_TYPE(node);
}
-static inline struct rt_trie_node *tnode_get_child(struct tnode *tn, unsigned int i)
+/*
+ * caller must hold RTNL
+ */
+static inline struct rt_trie_node *tnode_get_child(const struct tnode *tn, unsigned int i)
{
BUG_ON(i >= 1U << tn->bits);
- return tn->child[i];
+ return rtnl_dereference(tn->child[i]);
}
-static inline struct rt_trie_node *tnode_get_child_rcu(struct tnode *tn, unsigned int i)
+/*
+ * caller must hold RCU read lock or RTNL
+ */
+static inline struct rt_trie_node *tnode_get_child_rcu(const struct tnode *tn, unsigned int i)
{
- struct rt_trie_node *ret = tnode_get_child(tn, i);
+ BUG_ON(i >= 1U << tn->bits);
- return rcu_dereference_rtnl(ret);
+ return rcu_dereference_rtnl(tn->child[i]);
}
static inline int tnode_child_length(const struct tnode *tn)
@@ -487,7 +506,7 @@ static inline void put_child(struct trie *t, struct tnode *tn, int i,
static void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *n,
int wasfull)
{
- struct rt_trie_node *chi = tn->child[i];
+ struct rt_trie_node *chi = rtnl_dereference(tn->child[i]);
int isfull;
BUG_ON(i >= 1<<tn->bits);
@@ -665,7 +684,7 @@ one_child:
for (i = 0; i < tnode_child_length(tn); i++) {
struct rt_trie_node *n;
- n = tn->child[i];
+ n = rtnl_dereference(tn->child[i]);
if (!n)
continue;
@@ -679,6 +698,20 @@ one_child:
return (struct rt_trie_node *) tn;
}
+
+static void tnode_clean_free(struct tnode *tn)
+{
+ int i;
+ struct tnode *tofree;
+
+ for (i = 0; i < tnode_child_length(tn); i++) {
+ tofree = (struct tnode *)rtnl_dereference(tn->child[i]);
+ if (tofree)
+ tnode_free(tofree);
+ }
+ tnode_free(tn);
+}
+
static struct tnode *inflate(struct trie *t, struct tnode *tn)
{
struct tnode *oldtnode = tn;
@@ -755,8 +788,8 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
inode = (struct tnode *) node;
if (inode->bits == 1) {
- put_child(t, tn, 2*i, inode->child[0]);
- put_child(t, tn, 2*i+1, inode->child[1]);
+ put_child(t, tn, 2*i, rtnl_dereference(inode->child[0]));
+ put_child(t, tn, 2*i+1, rtnl_dereference(inode->child[1]));
tnode_free_safe(inode);
continue;
@@ -797,8 +830,8 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
size = tnode_child_length(left);
for (j = 0; j < size; j++) {
- put_child(t, left, j, inode->child[j]);
- put_child(t, right, j, inode->child[j + size]);
+ put_child(t, left, j, rtnl_dereference(inode->child[j]));
+ put_child(t, right, j, rtnl_dereference(inode->child[j + size]));
}
put_child(t, tn, 2*i, resize(t, left));
put_child(t, tn, 2*i+1, resize(t, right));
@@ -808,18 +841,8 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
tnode_free_safe(oldtnode);
return tn;
nomem:
- {
- int size = tnode_child_length(tn);
- int j;
-
- for (j = 0; j < size; j++)
- if (tn->child[j])
- tnode_free((struct tnode *)tn->child[j]);
-
- tnode_free(tn);
-
- return ERR_PTR(-ENOMEM);
- }
+ tnode_clean_free(tn);
+ return ERR_PTR(-ENOMEM);
}
static struct tnode *halve(struct trie *t, struct tnode *tn)
@@ -890,18 +913,8 @@ static struct tnode *halve(struct trie *t, struct tnode *tn)
tnode_free_safe(oldtnode);
return tn;
nomem:
- {
- int size = tnode_child_length(tn);
- int j;
-
- for (j = 0; j < size; j++)
- if (tn->child[j])
- tnode_free((struct tnode *)tn->child[j]);
-
- tnode_free(tn);
-
- return ERR_PTR(-ENOMEM);
- }
+ tnode_clean_free(tn);
+ return ERR_PTR(-ENOMEM);
}
/* readside must use rcu_read_lock currently dump routines
@@ -1033,7 +1046,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
t_key cindex;
pos = 0;
- n = t->trie;
+ n = rtnl_dereference(t->trie);
/* If we point to NULL, stop. Either the tree is empty and we should
* just put a new leaf in if, or we have reached an empty child slot,
@@ -1756,7 +1769,7 @@ static struct leaf *leaf_walk_rcu(struct tnode *p, struct rt_trie_node *c)
continue;
if (IS_LEAF(c)) {
- prefetch(p->child[idx]);
+ prefetch(rcu_dereference_rtnl(p->child[idx]));
return (struct leaf *) c;
}
@@ -2272,7 +2285,7 @@ static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
/* walk rest of this hash chain */
h = tb->tb_id & (FIB_TABLE_HASHSZ - 1);
- while ( (tb_node = rcu_dereference(tb->tb_hlist.next)) ) {
+ while ((tb_node = rcu_dereference(hlist_next_rcu(&tb->tb_hlist)))) {
tb = hlist_entry(tb_node, struct fib_table, tb_hlist);
n = fib_trie_get_first(iter, (struct trie *) tb->tb_data);
if (n)
^ permalink raw reply related
* DSA for the 88e6061 switch
From: Stefan Bigler @ 2011-03-31 7:35 UTC (permalink / raw)
To: netdev
Hello,
we would like to implement DSA for the 88e6061 switch, mainly to manage
the phys of the various switch ports. Unfortunately, this switch seems
only to supports the Marvell Header tagging mode but not the Trailer or
DSA mode. The Header mode has the disadvantage, that the tagging bytes
are inserted in*front* of the MAC header which most Ethernet
controllers do not like because it's used for RX filtering and TX length
padding. This could be worked around by using promiscuous mode and doing
TX length padding in software, but that's not a really good solution.
This rises the following questions:
- Are there other tagging methods which could be used for the 88e6061
switch?
- Is there an interface to manage the phys of the various ports
*without* an associated netdev device, e.g. using ethtool directly
over the mdio bus?
Any help is appreciated.
Thanks,
Stefan
^ permalink raw reply
* [PATCH 2/3] bonding:typo in comment
From: Pan Weiping @ 2011-03-31 6:46 UTC (permalink / raw)
Cc: Pan Weiping, Jay Vosburgh, Andy Gospodarek,
open list:BONDING DRIVER, open list
use accumulates instead of acumulates.
Signed-off-by: Pan Weiping <panweiping3@gmail.com>
---
drivers/net/bonding/bond_alb.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h
index 118c28a..4b3e358 100644
--- a/drivers/net/bonding/bond_alb.h
+++ b/drivers/net/bonding/bond_alb.h
@@ -74,7 +74,7 @@ struct tlb_client_info {
* packets to a Client that the Hash function
* gave this entry index.
*/
- u32 tx_bytes; /* Each Client acumulates the BytesTx that
+ u32 tx_bytes; /* Each Client accumulates the BytesTx that
* were tranmitted to it, and after each
* CallBack the LoadHistory is devided
* by the balance interval
--
1.7.4
^ permalink raw reply related
* Re: [PATCH net-next-2.6 v1] sctp: Add Auto-ASCONF support
From: Wei Yongjun @ 2011-03-31 6:45 UTC (permalink / raw)
To: Michio Honda; +Cc: netdev, lksctp-developers
In-Reply-To: <8484E05B-B474-4D3B-A192-7413FC6B9141@sfc.wide.ad.jp>
Hi Michio Honda
I try to understand what you are doing now, and some comments inline.
And
this patch is too big for review, you'd better to split it to a patchset:
the improve on orig asconf code, the auto-asconf support, the socket
option etc.
> SCTP reconfigure the IP addresses in the association by using ASCONF chunks as mentioned in RFC5061.
> For example, we can start to use the newly configured IP address in the existing association.
> ASCONF operation is invoked in two ways:
> First is done by the application to call sctp_bindx() system call.
> Second is automatic operation in the SCTP stack with address events in the host computer (called auto_asconf) .
> The former is already implemented, but the latter is not yet. This patch enables it with one sysctl parameter and setsockopt() system call.
>
> Signed-off-by: Michio Honda <micchie@sfc.wide.ad.jp>
> ---
>
> diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
> index 11684d9..11c3060 100644
> --- a/include/linux/sysctl.h
> +++ b/include/linux/sysctl.h
> @@ -767,6 +767,7 @@ enum {
> NET_SCTP_SNDBUF_POLICY = 15,
> NET_SCTP_SACK_TIMEOUT = 16,
> NET_SCTP_RCVBUF_POLICY = 17,
> + NET_SCTP_AUTO_ASCONF_ENABLE = 18,
> };
>
> /* /proc/sys/net/bridge */
> diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h
> index c70d8cc..d7a4ee3 100644
> --- a/include/net/sctp/constants.h
> +++ b/include/net/sctp/constants.h
> @@ -441,4 +441,8 @@ enum {
> */
> #define SCTP_AUTH_RANDOM_LENGTH 32
>
> +/* ASCONF PARAMETERS */
> +#define SCTP_ASCONF_V4_PARAM_LEN 16
> +#define SCTP_ASCONF_V6_PARAM_LEN 28
> +
> #endif /* __sctp_constants_h__ */
> diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
> index 505845d..7161932 100644
> --- a/include/net/sctp/sctp.h
> +++ b/include/net/sctp/sctp.h
> @@ -121,6 +121,7 @@ extern int sctp_copy_local_addr_list(struct sctp_bind_addr *,
> int flags);
> extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family);
> extern int sctp_register_pf(struct sctp_pf *, sa_family_t);
> +void sctp_addr_wq_mgmt(union sctp_addr *, int);
>
> /*
> * sctp/socket.c
> @@ -135,6 +136,8 @@ void sctp_sock_rfree(struct sk_buff *skb);
> void sctp_copy_sock(struct sock *newsk, struct sock *sk,
> struct sctp_association *asoc);
> extern struct percpu_counter sctp_sockets_allocated;
> +int sctp_asconf_mgmt(struct sctp_endpoint *, struct sock *sk);
> +void sctp_add_addr_to_laddr(struct sockaddr *, struct sctp_association *);
>
> /*
> * sctp/primitive.c
> diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h
> index 9352d12..498a3cf 100644
> --- a/include/net/sctp/sm.h
> +++ b/include/net/sctp/sm.h
> @@ -259,6 +259,7 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
> struct sctp_chunk *asconf);
> int sctp_process_asconf_ack(struct sctp_association *asoc,
> struct sctp_chunk *asconf_ack);
> +void sctp_path_check_and_react(struct sctp_association *, struct sockaddr *);
> struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
> __u32 new_cum_tsn, size_t nstreams,
> struct sctp_fwdtsn_skip *skiplist);
> diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
> index cc9185c..0c6a6f4 100644
> --- a/include/net/sctp/structs.h
> +++ b/include/net/sctp/structs.h
> @@ -205,6 +205,11 @@ extern struct sctp_globals {
> * It is a list of sctp_sockaddr_entry.
> */
> struct list_head local_addr_list;
> + int auto_asconf_enable;
> + struct list_head addr_waitq;
> + struct timer_list addr_wq_timer;
> + struct list_head auto_asconf_eplist;
> + spinlock_t addr_wq_lock;
>
> /* Lock that protects the local_addr_list writers */
> spinlock_t addr_list_lock;
> @@ -264,6 +269,11 @@ extern struct sctp_globals {
> #define sctp_port_hashtable (sctp_globals.port_hashtable)
> #define sctp_local_addr_list (sctp_globals.local_addr_list)
> #define sctp_local_addr_lock (sctp_globals.addr_list_lock)
> +#define sctp_auto_asconf_eplist (sctp_globals.auto_asconf_eplist)
> +#define sctp_addr_waitq (sctp_globals.addr_waitq)
> +#define sctp_addr_wq_timer (sctp_globals.addr_wq_timer)
> +#define sctp_addr_wq_lock (sctp_globals.addr_wq_lock)
> +#define sctp_auto_asconf_enable (sctp_globals.auto_asconf_enable)
> #define sctp_scope_policy (sctp_globals.ipv4_scope_policy)
> #define sctp_addip_enable (sctp_globals.addip_enable)
> #define sctp_addip_noauth (sctp_globals.addip_noauth_enable)
> @@ -796,6 +806,16 @@ struct sctp_sockaddr_entry {
> __u8 valid;
> };
>
> +#define SCTP_NEWADDR 1
> +#define SCTP_DELADDR 2
> +#define SCTP_ADDRESS_TICK_DELAY 500
> +struct sctp_addr_wait {
> + struct list_head list;
> + struct rcu_head rcu;
rcu is not need?
> + union sctp_addr a;
> + int cmd;
> +};
> +
> typedef struct sctp_chunk *(sctp_packet_phandler_t)(struct sctp_association *);
>
> /* This structure holds lists of chunks as we are assembling for
> @@ -1239,6 +1259,7 @@ sctp_scope_t sctp_scope(const union sctp_addr *);
> int sctp_in_scope(const union sctp_addr *addr, const sctp_scope_t scope);
> int sctp_is_any(struct sock *sk, const union sctp_addr *addr);
> int sctp_addr_is_valid(const union sctp_addr *addr);
> +int sctp_is_ep_boundall(struct sock *sk);
>
>
> /* What type of endpoint? */
> @@ -1267,6 +1288,7 @@ struct sctp_ep_common {
> /* Fields to help us manage our entries in the hash tables. */
> struct hlist_node node;
> int hashent;
> + struct list_head auto_asconf_list;
>
> /* Runtime type information. What kind of endpoint is this? */
> sctp_endpoint_type_t type;
> @@ -1901,6 +1923,17 @@ struct sctp_association {
> * after reaching 4294967295.
> */
> __u32 addip_serial;
> + /* list of valid addresses in association local
> + * This list is needed to ensure base.bind_addr being a valid address
> + * list of the endpoint-wide. When one of associations receives
> + * ASCONF-ACK, that address is added to this list. When all
> + * associations belonging to the same endpoint receive ASCONF-ACKs,
> + * that address is added to base.bind_addr
> + */
> + struct list_head asoc_laddr_list;
> + union sctp_addr *asconf_addr_del_pending;
> + __u32 asconf_del_pending_cid;
> + int src_out_of_asoc_ok;
>
> /* SCTP AUTH: list of the endpoint shared keys. These
> * keys are provided out of band by the user applicaton
> diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h
> index e73ebda..75c96b1 100644
> --- a/include/net/sctp/user.h
> +++ b/include/net/sctp/user.h
> @@ -91,6 +91,7 @@ typedef __s32 sctp_assoc_t;
> #define SCTP_PEER_AUTH_CHUNKS 26 /* Read only */
> #define SCTP_LOCAL_AUTH_CHUNKS 27 /* Read only */
> #define SCTP_GET_ASSOC_NUMBER 28 /* Read only */
> +#define SCTP_AUTO_ASCONF 29
>
> /* Internal Socket Options. Some of the sctp library functions are
> * implemented using these socket options.
> diff --git a/net/sctp/associola.c b/net/sctp/associola.c
> index 6b04287..082f1f0 100644
> --- a/net/sctp/associola.c
> +++ b/net/sctp/associola.c
> @@ -280,6 +280,10 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
> if (sctp_addip_noauth)
> asoc->peer.asconf_capable = 1;
>
> + asoc->asconf_addr_del_pending = NULL;
> + asoc->asconf_del_pending_cid = 0;
> + asoc->src_out_of_asoc_ok = 0;
> + INIT_LIST_HEAD(&asoc->asoc_laddr_list);
> /* Create an input queue. */
> sctp_inq_init(&asoc->base.inqueue);
> sctp_inq_set_th_handler(&asoc->base.inqueue, sctp_assoc_bh_rcv);
> @@ -446,6 +450,18 @@ void sctp_association_free(struct sctp_association *asoc)
> /* Free any cached ASCONF_ACK chunk. */
> sctp_assoc_free_asconf_acks(asoc);
>
> + /* Free pending address space being deleted */
> + if (asoc->asconf_addr_del_pending != NULL)
> + kfree(asoc->asconf_addr_del_pending);
> + if (!list_empty(&asoc->asoc_laddr_list)) {
> + struct sctp_sockaddr_entry *laddr, *tmp;
> + list_for_each_entry_safe(laddr, tmp, &asoc->asoc_laddr_list, \
> + list) {
> + list_del(&laddr->list);
> + kfree(laddr);
> + }
> + }
> +
> /* Free any cached ASCONF chunk. */
> if (asoc->addip_last_asconf)
> sctp_chunk_free(asoc->addip_last_asconf);
> @@ -620,6 +636,7 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
> if (!mod_timer(&active->T3_rtx_timer,
> jiffies + active->rto))
> sctp_transport_hold(active);
> + active->flight_size += peer->flight_size;
> }
>
> asoc->peer.transport_count--;
> @@ -1277,7 +1294,7 @@ void sctp_assoc_update(struct sctp_association *asoc,
> */
> void sctp_assoc_update_retran_path(struct sctp_association *asoc)
> {
> - struct sctp_transport *t, *next;
> + struct sctp_transport *t, *next, *unconfirmed;
> struct list_head *head = &asoc->peer.transport_addr_list;
> struct list_head *pos;
>
> @@ -1287,7 +1304,7 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
> /* Find the next transport in a round-robin fashion. */
> t = asoc->peer.retran_path;
> pos = &t->transports;
> - next = NULL;
> + next = unconfirmed = NULL;
>
> while (1) {
> /* Skip the head. */
> @@ -1318,11 +1335,15 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
> */
> if (t->state != SCTP_UNCONFIRMED && !next)
> next = t;
> + else if (t->state == SCTP_UNCONFIRMED)
> + unconfirmed = t;
> }
> }
>
> if (t)
> asoc->peer.retran_path = t;
> + else if (unconfirmed)
> + asoc->peer.retran_path = t = unconfirmed;
>
> SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_update_retran_path:association"
> " %p addr: ",
> diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
> index faf71d1..426715f 100644
> --- a/net/sctp/bind_addr.c
> +++ b/net/sctp/bind_addr.c
> @@ -536,6 +536,23 @@ int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope)
> return 0;
> }
>
> +int sctp_is_ep_boundall(struct sock *sk)
> +{
> + struct sctp_bind_addr *bp;
> + struct sctp_sockaddr_entry *addr;
> +
> + bp = &sctp_sk(sk)->ep->base.bind_addr;
> + if (sctp_list_single_entry(&bp->address_list)) {
> + addr = list_entry(bp->address_list.next,
> + struct sctp_sockaddr_entry, list);
> + if (sctp_is_any(sk, &addr->a))
> + return 1;
> + else
> + return 0;
> + }
> + return 1;
> +}
> +
> /********************************************************************
> * 3rd Level Abstractions
> ********************************************************************/
> diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
> index 865ce7b..471facd 100644
> --- a/net/sctp/ipv6.c
> +++ b/net/sctp/ipv6.c
> @@ -105,6 +105,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
> addr->valid = 1;
> spin_lock_bh(&sctp_local_addr_lock);
> list_add_tail_rcu(&addr->list, &sctp_local_addr_list);
> + sctp_addr_wq_mgmt(&addr->a, SCTP_NEWADDR);
> spin_unlock_bh(&sctp_local_addr_lock);
> }
> break;
> @@ -115,6 +116,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
> if (addr->a.sa.sa_family == AF_INET6 &&
> ipv6_addr_equal(&addr->a.v6.sin6_addr,
> &ifa->addr)) {
> + sctp_addr_wq_mgmt(&addr->a, SCTP_DELADDR);
> found = 1;
> addr->valid = 0;
> list_del_rcu(&addr->list);
> @@ -332,8 +334,26 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk,
> matchlen = bmatchlen;
> }
> }
> + if (laddr->state == SCTP_ADDR_NEW && asoc->src_out_of_asoc_ok) {
> + bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
> + if (!baddr || (matchlen < bmatchlen)) {
> + baddr = &laddr->a;
> + matchlen = bmatchlen;
> + }
> + }
> + }
> + if (baddr == NULL) {
> + /* We don't have a valid src addr in "endpoint-wide".
> + * Looking up in assoc-locally valid address list.
> + */
> + list_for_each_entry(laddr, &asoc->asoc_laddr_list, list) {
> + bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
> + if (!baddr || (matchlen < bmatchlen)) {
> + baddr = &laddr->a;
> + matchlen = bmatchlen;
> + }
> + }
> }
> -
> if (baddr) {
> memcpy(saddr, baddr, sizeof(union sctp_addr));
> SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr);
> diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
> index 26dc005..033ea20 100644
> --- a/net/sctp/outqueue.c
> +++ b/net/sctp/outqueue.c
> @@ -344,7 +344,14 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
> break;
> }
> } else {
> - list_add_tail(&chunk->list, &q->control_chunk_list);
> + /* We add the ASCONF for the only one newly added address at
> + * the front of the queue
> + */
> + if (q->asoc->src_out_of_asoc_ok && \
> + chunk->chunk_hdr->type == SCTP_CID_ASCONF)
> + list_add(&chunk->list, &q->control_chunk_list);
> + else
> + list_add_tail(&chunk->list, &q->control_chunk_list);
Why we need to add at front of the queue?
> SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
> }
>
> @@ -850,6 +857,24 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
> case SCTP_CID_SHUTDOWN:
> case SCTP_CID_ECN_ECNE:
> case SCTP_CID_ASCONF:
> + /* RFC 5061, 5.3
> + * F1) This means that until such time as the ASCONF
> + * containing the add is acknowledged, the sender MUST
> + * NOT use the new IP address as a source for ANY SCTP
> + * packet except on carrying an ASCONF Chunk.
> + */
> + if (asoc->src_out_of_asoc_ok) {
> + SCTP_DEBUG_PRINTK("outq_flush: out_of_asoc_ok, transmit chunk type %d\n",
> + chunk->chunk_hdr->type);
> + packet = &transport->packet;
> + sctp_packet_config(packet, vtag,
> + asoc->peer.ecn_capable);
> + sctp_packet_append_chunk(packet, chunk);
> + error = sctp_packet_transmit(packet);
> + if (error < 0)
> + return error;
> + goto sctp_flush_out;
> + }
> case SCTP_CID_FWD_TSN:
> status = sctp_packet_transmit_chunk(packet, chunk,
> one_packet);
> diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
> index 152976e..2859c16 100644
> --- a/net/sctp/protocol.c
> +++ b/net/sctp/protocol.c
> @@ -510,12 +510,20 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
> sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port));
> rcu_read_lock();
> list_for_each_entry_rcu(laddr, &bp->address_list, list) {
> - if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC))
> + if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC &&
> + asoc->src_out_of_asoc_ok == 0))
> continue;
> if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a))
> goto out_unlock;
> }
> rcu_read_unlock();
> + /* We don't have a valid src addr in "endpoint-wide".
> + * Looking up in assoc-locally valid address list.
> + */
> + list_for_each_entry(laddr, &asoc->asoc_laddr_list, list) {
> + if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a))
> + goto out_unlock;
> + }
>
> /* None of the bound addresses match the source address of the
> * dst. So release it.
> @@ -636,6 +644,182 @@ static void sctp_v4_ecn_capable(struct sock *sk)
> INET_ECN_xmit(sk);
> }
>
> +void sctp_addr_wq_timeout_handler(unsigned long arg)
> +{
> + struct sctp_addr_wait *addrw = NULL;
> + union sctp_addr *addr = NULL;
> + struct sctp_ep_common *epb = NULL;
> + struct sctp_endpoint *ep = NULL;
> + int cnt = 0;
cnt is useless
> +
> + spin_lock_bh(&sctp_addr_wq_lock);
> +retry_wq:
> + if (list_empty(&sctp_addr_waitq)) {
> + SCTP_DEBUG_PRINTK("sctp_addrwq_timo_handler: nothing in addr waitq\n");
> + spin_unlock_bh(&sctp_addr_wq_lock);
> + return;
> + }
> + addrw = list_first_entry(&sctp_addr_waitq, struct sctp_addr_wait, list);
> + if (addrw->cmd != SCTP_NEWADDR && addrw->cmd != SCTP_DELADDR) {
> + SCTP_DEBUG_PRINTK("sctp_addrwq_timo_handler: cmd is neither NEWADDR nor DELADDR\n");
> + list_del(&addrw->list);
> + kfree(addrw);
> + goto retry_wq;
> + }
> +
> + addr = &addrw->a;
> + SCTP_DEBUG_PRINTK_IPADDR("sctp_addrwq_timo_handler: the first ent in wq %p is ",
> + " for cmd %d at entry %p\n", &sctp_addr_waitq, addr, addrw->cmd,
> + addrw);
> +
> + /* Now we send an ASCONF for each association */
> + /* Note. we currently don't handle link local IPv6 addressees */
> + if (addr->sa.sa_family == AF_INET6) {
> + struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr;
> +
> + if (ipv6_addr_type(&addr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) {
> + SCTP_DEBUG_PRINTK("sctp_timo_handler: link local, hence don't tell eps\n");
> + list_del(&addrw->list);
> + kfree(addrw);
> + goto retry_wq;
> + }
> + if (ipv6_chk_addr(&init_net, in6, NULL, 0) == 0 &&
> + addrw->cmd == SCTP_NEWADDR) {
> + unsigned long timeo_val;
> +
> + SCTP_DEBUG_PRINTK("sctp_timo_handler: this is on DAD, trying %d sec later\n",
> + SCTP_ADDRESS_TICK_DELAY);
> + timeo_val = jiffies;
> + timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY);
> + (void)mod_timer(&sctp_addr_wq_timer, timeo_val);
> + spin_unlock_bh(&sctp_addr_wq_lock);
> + return;
> + }
> + }
> + list_for_each_entry(epb, &sctp_auto_asconf_eplist, auto_asconf_list) {
> + if (epb == NULL) {
> + SCTP_DEBUG_PRINTK("addrwq_timo_handler: no epb\n");
> + continue;
> + }
> + if (!sctp_is_ep_boundall(epb->sk))
> + /* ignore bound-specific endpoints */
> + continue;
> + ep = sctp_ep(epb);
> + sctp_bh_lock_sock(epb->sk);
> + if (sctp_asconf_mgmt(ep, epb->sk) < 0) {
> + SCTP_DEBUG_PRINTK("sctp_addrwq_timo_handler: sctp_asconf_mgmt failed\n");
> + sctp_bh_unlock_sock(epb->sk);
> + continue;
> + }
> + sctp_bh_unlock_sock(epb->sk);
> + ++cnt;
> + }
> +
> + list_del(&addrw->list);
> + kfree(addrw);
> +
> + if (list_empty(&sctp_addr_waitq)) {
> + spin_unlock_bh(&sctp_addr_wq_lock);
> + return;
> + } else
> + goto retry_wq;
> +
> + spin_unlock_bh(&sctp_addr_wq_lock);
> +}
> +
> +void sctp_addr_wq_mgmt(union sctp_addr *reqaddr, int cmd)
> +{
> + struct sctp_addr_wait *addrw = NULL;
> + struct sctp_addr_wait *addrw_new = NULL;
> + unsigned long timeo_val;
> + union sctp_addr *tmpaddr;
> +
> + /* first, we check if an opposite message already exist in the queue.
> + * If we found such message, it is removed.
> + * This operation is a bit stupid, but the DHCP client attaches the
> + * new address after a couple of addition and deletion of that address
> + */
> +
> + if (reqaddr == NULL) {
> + SCTP_DEBUG_PRINTK("sctp_addr_wq_mgmt: no address message?\n");
> + return;
> + }
> +
> + spin_lock_bh(&sctp_addr_wq_lock);
> + /* Offsets existing events in addr_wq */
> + list_for_each_entry(addrw, &sctp_addr_waitq, list) {
> + if (addrw->a.sa.sa_family != reqaddr->sa.sa_family)
> + continue;
> + if (reqaddr->sa.sa_family == AF_INET) {
> + if (reqaddr->v4.sin_addr.s_addr ==
> + addrw->a.v4.sin_addr.s_addr) {
> + if (cmd != addrw->cmd) {
> + tmpaddr = &addrw->a;
> + SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt offsets existing entry for %d ",
> + " in waitq %p\n", addrw->cmd,
> + tmpaddr, &sctp_addr_waitq);
> + list_del(&addrw->list);
> + kfree(addrw);
> + /* nothing to do anymore */
> + spin_unlock_bh(&sctp_addr_wq_lock);
> + return;
> + }
> + }
> + } else if (reqaddr->sa.sa_family == AF_INET6) {
> + if (ipv6_addr_equal(&reqaddr->v6.sin6_addr,
> + &addrw->a.v6.sin6_addr)) {
> + if (cmd != addrw->cmd) {
> + tmpaddr = &addrw->a;
> + SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt: offsets existing entry for %d ",
> + " in waitq %p\n", addrw->cmd,
> + tmpaddr, &sctp_addr_waitq);
> + list_del(&addrw->list);
> + kfree(addrw);
> + spin_unlock_bh(&sctp_addr_wq_lock);
> + return;
> + }
> + }
> + }
> + }
> +
> + /* OK, we have to add the new address to the wait queue */
> + addrw_new = kzalloc(sizeof(struct sctp_addr_wait), GFP_ATOMIC);
> + if (addrw_new == NULL) {
> + SCTP_DEBUG_PRINTK("sctp_addr_weitq_mgmt no memory? return\n");
> + spin_unlock_bh(&sctp_addr_wq_lock);
> + return;
> + }
> + if (reqaddr->sa.sa_family == AF_INET) {
> + addrw_new->a.v4.sin_family = AF_INET;
> + addrw_new->a.v4.sin_addr.s_addr = reqaddr->v4.sin_addr.s_addr;
> + } else if (reqaddr->sa.sa_family == AF_INET6) {
> + addrw_new->a.v6.sin6_family = AF_INET6;
> + ipv6_addr_copy(&addrw_new->a.v6.sin6_addr,
> + &reqaddr->v6.sin6_addr);
> + } else {
> + SCTP_DEBUG_PRINTK("sctp_addr_waitq_mgmt: Unknown family of request addr, return\n");
> + kfree(addrw_new);
> + spin_unlock_bh(&sctp_addr_wq_lock);
> + return;
> + }
> + addrw_new->cmd = cmd;
> + list_add_tail(&addrw_new->list, &sctp_addr_waitq);
> + tmpaddr = &addrw_new->a;
> + SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt add new entry for cmd:%d ",
> + " in waitq %p, start a timer\n",
> + addrw_new->cmd, tmpaddr, &sctp_addr_waitq);
> +
> + if (timer_pending(&sctp_addr_wq_timer)) {
> + SCTP_DEBUG_PRINTK("sctp_addr_wq_mgmt: addr_wq timer is already running\n");
> + spin_unlock_bh(&sctp_addr_wq_lock);
> + return;
> + }
> + timeo_val = jiffies;
> + timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY);
> + (void)mod_timer(&sctp_addr_wq_timer, timeo_val);
> + spin_unlock_bh(&sctp_addr_wq_lock);
> +}
> +
> /* Event handler for inet address addition/deletion events.
> * The sctp_local_addr_list needs to be protocted by a spin lock since
> * multiple notifiers (say IPv4 and IPv6) may be running at the same
> @@ -663,6 +847,7 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
> addr->valid = 1;
> spin_lock_bh(&sctp_local_addr_lock);
> list_add_tail_rcu(&addr->list, &sctp_local_addr_list);
> + sctp_addr_wq_mgmt(&addr->a, SCTP_NEWADDR);
> spin_unlock_bh(&sctp_local_addr_lock);
> }
> break;
> @@ -673,6 +858,7 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
> if (addr->a.sa.sa_family == AF_INET &&
> addr->a.v4.sin_addr.s_addr ==
> ifa->ifa_local) {
> + sctp_addr_wq_mgmt(&addr->a, SCTP_DELADDR);
> found = 1;
> addr->valid = 0;
> list_del_rcu(&addr->list);
> @@ -1277,6 +1463,12 @@ SCTP_STATIC __init int sctp_init(void)
>
> /* Initialize the local address list. */
> INIT_LIST_HEAD(&sctp_local_addr_list);
> + INIT_LIST_HEAD(&sctp_addr_waitq);
> + INIT_LIST_HEAD(&sctp_auto_asconf_eplist);
> + spin_lock_init(&sctp_addr_wq_lock);
> + sctp_addr_wq_timer.expires = 0;
> + setup_timer(&sctp_addr_wq_timer, sctp_addr_wq_timeout_handler,
> + (unsigned long)NULL);
We also need to stop the timer when mod is removed.
> spin_lock_init(&sctp_local_addr_lock);
> sctp_get_local_addr_list();
>
> diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
> index de98665..b5ca24a 100644
> --- a/net/sctp/sm_make_chunk.c
> +++ b/net/sctp/sm_make_chunk.c
> @@ -2651,6 +2651,61 @@ __u32 sctp_generate_tsn(const struct sctp_endpoint *ep)
> return retval;
> }
>
> +void
> +sctp_path_check_and_react(struct sctp_association *asoc, struct sockaddr *sa)
> +{
> + struct sctp_transport *trans;
> + int addrnum, family;
> + struct sctp_sockaddr_entry *saddr;
> + struct sctp_bind_addr *bp;
> + union sctp_addr *tmpaddr;
> +
> + family = sa->sa_family;
> + bp = &asoc->base.bind_addr;
> + addrnum = 0;
> + /* count up the number of local addresses in the same family */
> + list_for_each_entry(saddr, &bp->address_list, list) {
> + if (saddr->a.sa.sa_family == family) {
> + tmpaddr = &saddr->a;
> + if (family == AF_INET6 &&
> + ipv6_addr_type(&tmpaddr->v6.sin6_addr) &
> + IPV6_ADDR_LINKLOCAL) {
> + continue;
> + }
> + addrnum++;
> + }
> + }
> + if (addrnum == 1) {
> + union sctp_addr *tmpaddr;
> + tmpaddr = (union sctp_addr *)sa;
> + SCTP_DEBUG_PRINTK_IPADDR("pcheck_react: only 1 local addr in asoc %p ",
> + " family %d\n", asoc, tmpaddr, family);
> + list_for_each_entry(trans, &asoc->peer.transport_addr_list,
> + transports) {
> + /* reset path information and release refcount to the
> + * dst_entry based on the src change */
> + sctp_transport_hold(trans);
> + trans->cwnd = min(4*asoc->pathmtu,
> + max_t(__u32, 2*asoc->pathmtu, 4380));
> + trans->ssthresh = asoc->peer.i.a_rwnd;
> + trans->rtt = 0;
> + trans->srtt = 0;
> + trans->rttvar = 0;
> + trans->rto = asoc->rto_initial;
> + dst_release(trans->dst);
> + trans->dst = NULL;
> + memset(&trans->saddr, 0, sizeof(union sctp_addr));
> + sctp_transport_route(trans, NULL,
> + sctp_sk(asoc->base.sk));
> + SCTP_DEBUG_PRINTK_IPADDR("we freed dst_entry (asoc: %p dst: ",
> + " trans: %p)\n", asoc, (&trans->ipaddr), trans);
> + trans->rto_pending = 1;
> + sctp_transport_put(trans);
> + }
> + }
> + return;
> +}
> +
> /*
> * ADDIP 3.1.1 Address Configuration Change Chunk (ASCONF)
> * 0 1 2 3
> @@ -2744,11 +2799,29 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
> int addr_param_len = 0;
> int totallen = 0;
> int i;
> + sctp_addip_param_t del_param; /* 8 Bytes (Type 0xC002, Len and CrrID) */
> + sctp_addip_param_t spr_param;
> + struct sctp_af *del_af;
> + struct sctp_af *spr_af;
> + int del_addr_param_len = 0;
> + int spr_addr_param_len = 0;
> + int del_paramlen = sizeof(sctp_addip_param_t);
> + int spr_paramlen = sizeof(sctp_addip_param_t);
> + union sctp_addr_param del_addr_param; /* (v4) 8 Bytes, (v6) 20 Bytes */
> + union sctp_addr_param spr_addr_param;
> + int v4 = 0;
> + int v6 = 0;
>
> /* Get total length of all the address parameters. */
> addr_buf = addrs;
> for (i = 0; i < addrcnt; i++) {
> addr = (union sctp_addr *)addr_buf;
> + if (addr != NULL) {
> + if (addr->sa.sa_family == AF_INET)
> + v4 = 1;
> + else if (addr->sa.sa_family == AF_INET6)
> + v6 = 1;
> + }
> af = sctp_get_af_specific(addr->v4.sin_family);
> addr_param_len = af->to_addr_param(addr, &addr_param);
>
> @@ -2757,6 +2830,40 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
>
> addr_buf += af->sockaddr_len;
> }
> + /* Add the length of a pending address being deleted */
> + if (flags == SCTP_PARAM_ADD_IP && asoc->asconf_addr_del_pending) {
> + if ((asoc->asconf_addr_del_pending->sa.sa_family == AF_INET
> + && v4) ||
> + (asoc->asconf_addr_del_pending->sa.sa_family == AF_INET6
> + && v6)) {
> + del_af = sctp_get_af_specific(
> + asoc->asconf_addr_del_pending->sa.sa_family);
> + del_addr_param_len = del_af->to_addr_param(
> + asoc->asconf_addr_del_pending, &del_addr_param);
> + totallen += del_paramlen;
> + totallen += del_addr_param_len;
> + SCTP_DEBUG_PRINTK("mkasconf_update_ip: now we picked del_pending addr, totallen for all addresses is %d\n",
> + totallen);
> + /* for Set Primary (equal size as del parameters */
> + totallen += del_paramlen;
> + totallen += del_addr_param_len;
> + }
> + if (v4) {
> + if (totallen != SCTP_ASCONF_V4_PARAM_LEN * 2 &&
> + totallen != SCTP_ASCONF_V4_PARAM_LEN * 3) {
> + SCTP_DEBUG_PRINTK("mkasconf_update_ip: incorrect total length of ASCONF parameters, del + add MUST be 32 bytes, but %d bytes\n", totallen);
> + return NULL;
> + }
> + } else if (v6) {
> + if (totallen != SCTP_ASCONF_V6_PARAM_LEN * 2 &&
> + totallen != SCTP_ASCONF_V6_PARAM_LEN * 3) {
> + SCTP_DEBUG_PRINTK("mkasconf_update_ip: incorrect total length of ASCONF parameters, del + add MUST be 56 bytes, but %d bytes\n", totallen);
> + return NULL;
> + }
> + }
> + }
> + SCTP_DEBUG_PRINTK("mkasconf_update_ip: call mkasconf() for %d bytes\n",
> + totallen);
>
> /* Create an asconf chunk with the required length. */
> retval = sctp_make_asconf(asoc, laddr, totallen);
> @@ -2778,6 +2885,32 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
>
> addr_buf += af->sockaddr_len;
> }
> + if (flags == SCTP_PARAM_ADD_IP && asoc->asconf_addr_del_pending) {
> + addr = asoc->asconf_addr_del_pending;
> + del_af = sctp_get_af_specific(addr->v4.sin_family);
> + del_addr_param_len = del_af->to_addr_param(addr,
> + &del_addr_param);
> + del_param.param_hdr.type = SCTP_PARAM_DEL_IP;
> + del_param.param_hdr.length = htons(del_paramlen +
> + del_addr_param_len);
> + del_param.crr_id = i;
> + asoc->asconf_del_pending_cid = i;
> +
> + sctp_addto_chunk(retval, del_paramlen, &del_param);
> + sctp_addto_chunk(retval, del_addr_param_len, &del_addr_param);
> + /* For SET_PRIMARY */
> + addr_buf = addrs;
> + addr = (union sctp_addr *)addr_buf;
> + spr_af = sctp_get_af_specific(addr->v4.sin_family);
> + spr_addr_param_len = spr_af->to_addr_param(addr,
> + &spr_addr_param);
> + spr_param.param_hdr.type = SCTP_PARAM_SET_PRIMARY;
> + spr_param.param_hdr.length = htons(spr_paramlen +
> + spr_addr_param_len);
> + spr_param.crr_id = (i+1);
> + sctp_addto_chunk(retval, spr_paramlen, &spr_param);
> + sctp_addto_chunk(retval, spr_addr_param_len, &spr_addr_param);
> + }
> return retval;
> }
>
> @@ -2990,7 +3123,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
> * an Error Cause TLV set to the new error code 'Request to
> * Delete Source IP Address'
> */
> - if (sctp_cmp_addr_exact(sctp_source(asconf), &addr))
> + if (sctp_cmp_addr_exact(&asconf->source, &addr))
> return SCTP_ERROR_DEL_SRC_IP;
>
> /* Section 4.2.2
> @@ -3171,7 +3304,6 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
> struct sctp_bind_addr *bp = &asoc->base.bind_addr;
> union sctp_addr_param *addr_param;
> struct sctp_transport *transport;
> - struct sctp_sockaddr_entry *saddr;
>
> addr_param = (union sctp_addr_param *)
> ((void *)asconf_param + sizeof(sctp_addip_param_t));
> @@ -3186,9 +3318,16 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
> * held, so the list can not change.
> */
> local_bh_disable();
> - list_for_each_entry(saddr, &bp->address_list, list) {
> - if (sctp_cmp_addr_exact(&saddr->a, &addr))
> - saddr->state = SCTP_ADDR_SRC;
> + /* Until this ASCONF is acked on all associations, we cannot
> + * consider this address as ADDR_SRC
> + */
> + asoc->src_out_of_asoc_ok = 0;
> + sctp_add_addr_to_laddr(&addr.sa, asoc);
> + list_for_each_entry(transport, &asoc->peer.transport_addr_list,
> + transports) {
> + dst_release(transport->dst);
> + sctp_transport_route(transport, NULL,
> + sctp_sk(asoc->base.sk));
> }
> local_bh_enable();
> list_for_each_entry(transport, &asoc->peer.transport_addr_list,
> @@ -3203,6 +3342,25 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
> case SCTP_PARAM_DEL_IP:
> local_bh_disable();
> sctp_del_bind_addr(bp, &addr);
> + if (asoc->asconf_addr_del_pending != NULL) {
> + if ((addr.sa.sa_family == AF_INET) &&
> + (asoc->asconf_addr_del_pending->sa.sa_family ==
> + AF_INET)) {
> + if (asoc->asconf_addr_del_pending->v4.sin_addr.s_addr == addr.v4.sin_addr.s_addr) {
> + kfree(asoc->asconf_addr_del_pending);
> + asoc->asconf_del_pending_cid = 0;
> + asoc->asconf_addr_del_pending = NULL;
> + }
> + } else if ((addr.sa.sa_family == AF_INET6) &&
> + (asoc->asconf_addr_del_pending->sa.sa_family ==
> + AF_INET6)) {
> + if (ipv6_addr_equal(&asoc->asconf_addr_del_pending->v6.sin6_addr, &addr.v6.sin6_addr)) {
> + kfree(asoc->asconf_addr_del_pending);
> + asoc->asconf_del_pending_cid = 0;
> + asoc->asconf_addr_del_pending = NULL;
> + }
> + }
> + }
> local_bh_enable();
> list_for_each_entry(transport, &asoc->peer.transport_addr_list,
> transports) {
> @@ -3293,6 +3451,8 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
> int no_err = 1;
> int retval = 0;
> __be16 err_code = SCTP_ERROR_NO_ERROR;
> + sctp_addip_param_t *first_asconf_param = NULL;
> + int first_asconf_paramlen;
>
> /* Skip the chunkhdr and addiphdr from the last asconf sent and store
> * a pointer to address parameter.
> @@ -3307,6 +3467,8 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
> length = ntohs(addr_param->v4.param_hdr.length);
> asconf_param = (sctp_addip_param_t *)((void *)addr_param + length);
> asconf_len -= length;
> + first_asconf_param = asconf_param;
> + first_asconf_paramlen = ntohs(first_asconf_param->param_hdr.length);
>
> /* ADDIP 4.1
> * A8) If there is no response(s) to specific TLV parameter(s), and no
> @@ -3361,6 +3523,35 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
> asconf_len -= length;
> }
>
> + /* When the source address obviously changes to newly added one, we
> + reset the cwnd to re-probe the path condition
> + */
> + if (no_err && first_asconf_param->param_hdr.type == SCTP_PARAM_ADD_IP) {
> + if (first_asconf_paramlen == SCTP_ASCONF_V4_PARAM_LEN) {
> + struct sockaddr_in sin;
> +
> + memset(&sin, 0, sizeof(struct sockaddr_in));
> + sin.sin_family = AF_INET;
> + memcpy(&sin.sin_addr.s_addr, first_asconf_param + 1,
> + sizeof(struct in_addr));
> + sctp_path_check_and_react(asoc,
> + (struct sockaddr *)&sin);
> +
> + } else if (first_asconf_paramlen == SCTP_ASCONF_V6_PARAM_LEN) {
> + struct sockaddr_in6 sin6;
> +
> + memset(&sin6, 0, sizeof(struct sockaddr_in6));
> + sin6.sin6_family = AF_INET6;
> + memcpy(&sin6.sin6_addr, first_asconf_param + 1,
> + sizeof(struct in6_addr));
> + sctp_path_check_and_react(asoc,
> + (struct sockaddr *)&sin6);
> + } else {
> + SCTP_DEBUG_PRINTK("funny asconf_paramlen? (%d)\n",
> + first_asconf_paramlen);
> + }
> + }
> +
> /* Free the cached last sent asconf chunk. */
> list_del_init(&asconf->transmitted_list);
> sctp_chunk_free(asconf);
> diff --git a/net/sctp/socket.c b/net/sctp/socket.c
> index 3951a10..9bc5e98 100644
> --- a/net/sctp/socket.c
> +++ b/net/sctp/socket.c
> @@ -527,6 +527,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
> struct list_head *p;
> int i;
> int retval = 0;
> + struct sctp_transport *trans = NULL;
>
> if (!sctp_addip_enable)
> return retval;
> @@ -583,13 +584,10 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
> goto out;
> }
>
> - retval = sctp_send_asconf(asoc, chunk);
> - if (retval)
> - goto out;
> -
> /* Add the new addresses to the bind address list with
> * use_as_src set to 0.
> */
> + SCTP_DEBUG_PRINTK("snd_asconf_addip: next, add_bind_addr with ADDR_NEW flag\n");
> addr_buf = addrs;
> for (i = 0; i < addrcnt; i++) {
> addr = (union sctp_addr *)addr_buf;
> @@ -599,6 +597,28 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
> SCTP_ADDR_NEW, GFP_ATOMIC);
> addr_buf += af->sockaddr_len;
> }
> + list_for_each_entry(trans, &asoc->peer.transport_addr_list,
> + transports) {
> + if (asoc->asconf_addr_del_pending != NULL)
> + /* This ADDIP ASCONF piggybacks DELIP for the
> + * last address, so need to select src addr
> + * from the out_of_asoc addrs
> + */
> + asoc->src_out_of_asoc_ok = 1;
> + /* Clear the source and route cache in the path */
> + memset(&trans->saddr, 0, sizeof(union sctp_addr));
> + dst_release(trans->dst);
> + trans->cwnd = min(4*asoc->pathmtu, max_t(__u32,
> + 2*asoc->pathmtu, 4380));
> + trans->ssthresh = asoc->peer.i.a_rwnd;
> + trans->rto = asoc->rto_initial;
> + trans->rtt = 0;
> + trans->srtt = 0;
> + trans->rttvar = 0;
> + sctp_transport_route(trans, NULL,
> + sctp_sk(asoc->base.sk));
> + }
> + retval = sctp_send_asconf(asoc, chunk);
We need to do this really?
> }
>
> out:
> @@ -711,7 +731,9 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
> struct sctp_sockaddr_entry *saddr;
> int i;
> int retval = 0;
> + int stored = 0;
>
> + chunk = NULL;
> if (!sctp_addip_enable)
> return retval;
>
> @@ -762,8 +784,42 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
> bp = &asoc->base.bind_addr;
> laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs,
> addrcnt, sp);
> - if (!laddr)
> - continue;
> + if ((laddr == NULL) && (addrcnt == 1)) {
> + union sctp_addr *sa_addr = NULL;
> +
> + if (asoc->asconf_addr_del_pending == NULL) {
> + asoc->asconf_addr_del_pending =
> + kmalloc(sizeof(union sctp_addr),
> + GFP_ATOMIC);
> + memset(asoc->asconf_addr_del_pending, 0,
> + sizeof(union sctp_addr));
> + if (addrs->sa_family == AF_INET) {
> + struct sockaddr_in *sin;
> +
> + sin = (struct sockaddr_in *)addrs;
> + asoc->asconf_addr_del_pending->v4.sin_family = AF_INET;
> + memcpy(&asoc->asconf_addr_del_pending->v4.sin_addr, &sin->sin_addr, sizeof(struct in_addr));
> + } else if (addrs->sa_family == AF_INET6) {
> + struct sockaddr_in6 *sin6;
> +
> + sin6 = (struct sockaddr_in6 *)addrs;
> + asoc->asconf_addr_del_pending->v6.sin6_family = AF_INET6;
> + memcpy(&asoc->asconf_addr_del_pending->v6.sin6_addr, &sin6->sin6_addr, sizeof(struct in6_addr));
> + }
> + sa_addr = (union sctp_addr *)addrs;
> + SCTP_DEBUG_PRINTK_IPADDR("send_asconf_del_ip: keep the last address asoc: %p ",
> + " at %p\n", asoc, sa_addr,
> + asoc->asconf_addr_del_pending);
> + stored = 1;
> + goto skip_mkasconf;
> + } else {
> + SCTP_DEBUG_PRINTK_IPADDR("send_asconf_del_ip: asoc %p, deleting last address ",
> + " is already stored at %p\n", asoc,
> + asoc->asconf_addr_del_pending,
> + asoc->asconf_addr_del_pending);
> + continue;
> + }
> + }
>
> /* We do not need RCU protection throughout this loop
> * because this is done under a socket lock from the
> @@ -776,6 +832,7 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
> goto out;
> }
>
> +skip_mkasconf:
> /* Reset use_as_src flag for the addresses in the bind address
> * list that are to be deleted.
> */
> @@ -797,16 +854,205 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
> list_for_each_entry(transport, &asoc->peer.transport_addr_list,
> transports) {
> dst_release(transport->dst);
> + /* Clear source address cache */
> + memset(&transport->saddr, 0, sizeof(union sctp_addr));
> sctp_transport_route(transport, NULL,
> sctp_sk(asoc->base.sk));
> }
>
> + if (stored) {
> + /* We don't need to transmit ASCONF */
> + continue;
> + }
> retval = sctp_send_asconf(asoc, chunk);
> }
> out:
> return retval;
> }
>
> +/* Add a new address to the list contains available addresses only in the
> + * association. If the new address is also available on the other associations
> + * on the endpoint, it is marked as SCTP_ADDR_SRC in the bind address list on
> + * the endpoint. This situation is possible when some of associations receive
> + * ASCONF-ACK for ADD_IP at the endpoint
> + */
> +void
> +sctp_add_addr_to_laddr(struct sockaddr *sa, struct sctp_association *asoc)
> +{
> + struct sctp_endpoint *ep = asoc->ep;
> + struct sctp_association *tmp = NULL;
> + struct sctp_bind_addr *bp;
> + struct sctp_sockaddr_entry *addr;
> + struct sockaddr_in *sin = NULL;
> + struct sockaddr_in6 *sin6 = NULL;
> + int local;
> + int found;
> +
> + union sctp_addr *tmpaddr = NULL;
> + tmpaddr = (union sctp_addr *)sa;
> + SCTP_DEBUG_PRINTK_IPADDR("add_addr_to_laddr: asoc: %p ", " ep: %p",
> + asoc, tmpaddr, ep);
> + if (sa->sa_family == AF_INET)
> + sin = (struct sockaddr_in *)sa;
> + else if (sa->sa_family == AF_INET6)
> + sin6 = (struct sockaddr_in6 *)sa;
> +
> + /* Check if this address is locally available in the other asocs */
> + local = 0;
> + list_for_each_entry(tmp, &ep->asocs, asocs) {
> + if (tmp == asoc)
> + continue;
> + found = 0;
> + list_for_each_entry(addr, &tmp->asoc_laddr_list, list) {
> + tmpaddr = &addr->a;
> + if (sa->sa_family != addr->a.sa.sa_family)
> + continue;
> + if (sa->sa_family == AF_INET) {
> + if (sin->sin_addr.s_addr ==
> + addr->a.v4.sin_addr.s_addr)
> + found = 1;
> + } else if (sa->sa_family == AF_INET6) {
> + if (ipv6_addr_equal(&sin6->sin6_addr,
> + &addr->a.v6.sin6_addr))
> + found = 1;
> +
> + }
> + }
> + if (!found) {
> + SCTP_DEBUG_PRINTK("add_addr_to_laddr: not found in asoc %p\n", tmp);
> + local = 1;
> + break;
> + }
> + }
> + addr = NULL;
> +
> + if (local) {
> + /* this address is not available in some of the other
> + * associations. So add as locally-available in this
> + * asocciation
> + */
> + addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
> + if (addr == NULL) {
> + SCTP_DEBUG_PRINTK("add_addr_to_laddr: failed to allocate memory for this address\n");
> + return;
> + }
> + memset(addr, 0, sizeof(struct sctp_sockaddr_entry));
> + if (sa->sa_family == AF_INET) {
> + addr->a.sa.sa_family = AF_INET;
> + addr->a.v4.sin_port = sin->sin_port;
> + addr->a.v4.sin_addr.s_addr = sin->sin_addr.s_addr;
> + } else if (sa->sa_family == AF_INET6) {
> + addr->a.sa.sa_family = AF_INET6;
> + addr->a.v6.sin6_port = sin6->sin6_port;
> + memcpy(&addr->a.v6.sin6_addr, &sin6->sin6_addr,
> + sizeof(struct in6_addr));
> + }
> + list_add_tail(&addr->list, &asoc->asoc_laddr_list);
> + SCTP_DEBUG_PRINTK("add_addr_to_laddr: now we added this address to the local list on asoc %p\n", asoc);
> + } else {
> + /* this address is also available in all other asocs. So set
> + * it as ADDR_SRC in the bind-addr list in the endpoint, then
> + * remove from the asoc_laddr_list on the associations.
> + */
> + SCTP_DEBUG_PRINTK("add_addr_to_laddr: this address is available in all other asocs\n");
> + bp = &asoc->base.bind_addr;
> +
> + /* change state of the new address in the bind list */
> + list_for_each_entry(addr, &bp->address_list, list) {
> + if (addr->state != SCTP_ADDR_NEW)
> + continue;
> + if (addr->a.sa.sa_family != sa->sa_family)
> + continue;
> + if (addr->a.sa.sa_family == AF_INET) {
> + if (sin->sin_port != addr->a.v4.sin_port)
> + continue;
> + if (sin->sin_addr.s_addr !=
> + addr->a.v4.sin_addr.s_addr)
> + continue;
> + } else if (addr->a.sa.sa_family == AF_INET6) {
> + if (sin6->sin6_port != addr->a.v6.sin6_port)
> + continue;
> + if (!ipv6_addr_equal(&sin6->sin6_addr,
> + &addr->a.v6.sin6_addr))
> + continue;
> + }
> + SCTP_DEBUG_PRINTK("add_addr_to_laddr: found the entry for this address with ADDR_NEW flag, set to ADDR_SRC\n");
> + addr->state = SCTP_ADDR_SRC;
> + }
> +
> + /* remove the entry of this address from the asoc-local list */
> + list_for_each_entry(tmp, &ep->asocs, asocs) {
> + if (tmp == asoc)
> + continue;
> + addr = NULL;
> + list_for_each_entry(addr, &tmp->asoc_laddr_list, list) {
> + if (sa->sa_family != addr->a.sa.sa_family)
> + continue;
> + if (sa->sa_family == AF_INET) {
> + if (sin->sin_addr.s_addr !=
> + addr->a.v4.sin_addr.s_addr)
> + continue;
> + } else if (sa->sa_family == AF_INET6) {
> + if (!ipv6_addr_equal(&sin6->sin6_addr,
> + &addr->a.v6.sin6_addr))
> + continue;
> + }
> + break;
> + }
> + if (addr == NULL) {
> + SCTP_DEBUG_PRINTK("add_addr_to_laddr: Huh, asoc %p doesn't have the entry for this address?\n", asoc);
> + continue;
> + }
> + list_del(&addr->list);
> + kfree(addr);
> + }
> + }
> +}
> +
> +/* set addr events to assocs in the endpoint. ep and addr_wq must be locked */
> +int
> +sctp_asconf_mgmt(struct sctp_endpoint *ep, struct sock *sk)
only the ep param is necessary, sk should be fetch from ep.
> +{
> + struct sctp_addr_wait *addrw = NULL;
> + union sctp_addr *addr = NULL;
> + int cmd;
> + int error = 0;
> +
> + if (ep == NULL || sk == NULL)
> + return -EINVAL;
> + if (list_empty(&sctp_addr_waitq)) {
> + SCTP_DEBUG_PRINTK("asconf_mgmt: nothing in the wq\n");
> + return -EINVAL;
> + }
> + addrw = list_first_entry(&sctp_addr_waitq, struct sctp_addr_wait, list);
> + if (addrw->cmd != SCTP_NEWADDR && addrw->cmd != SCTP_DELADDR)
> + return -EINVAL;
> + addr = &addrw->a;
> + cmd = addrw->cmd;
> +
> + if (addr->sa.sa_family == AF_INET)
> + addr->v4.sin_port = htons(ep->base.bind_addr.port);
> + else if (addr->sa.sa_family == AF_INET6)
> + addr->v6.sin6_port = htons(ep->base.bind_addr.port);
use addr->v4.sin_port = htons(ep->base.bind_addr.port) is enough,
no need to check the family.
> +
> + SCTP_DEBUG_PRINTK("sctp_asconf_mgmt sk:%p ep:%p\n", sk, ep);
> + if (cmd == SCTP_NEWADDR) {
> + error = sctp_send_asconf_add_ip(sk, (struct sockaddr *)addr, 1);
> + if (error) {
> + SCTP_DEBUG_PRINTK("asconf_mgmt: send_asconf_add_ip returns %d\n", error);
> + return error;
> + }
> + } else if (cmd == SCTP_DELADDR) {
> + error = sctp_send_asconf_del_ip(sk, (struct sockaddr *)addr, 1);
> + if (error) {
> + SCTP_DEBUG_PRINTK("asconf_mgmt: send_asconf_del_ip returns %d\n", error);
> + return error;
> + }
> + }
> +
> + return 0;
> +}
> +
> /* Helper for tunneling sctp_bindx() requests through sctp_setsockopt()
> *
> * API 8.1
> @@ -3341,6 +3587,44 @@ static int sctp_setsockopt_del_key(struct sock *sk,
>
> }
>
> +/*
> + * 8.1.23 SCTP_AUTO_ASCONF
> + *
> + * This option will enable or disable the use of the automatic generation of
> + * ASCONF chunks to add and delete addresses to an existing association. Note
> + * that this option has two caveats namely: a) it only affects sockets that
> + * are bound to all addresses available to the SCTP stack, and b) the system
> + * administrator may have an overriding control that turns the ASCONF feature
> + * off no matter what setting the socket option may have.
> + * This option expects an integer boolean flag, where a non-zero value turns on
> + * the option, and a zero value turns off the option.
> + * Note. In this implementation, socket operation overrides default parameter
> + * being set by sysctl as well as FreeBSD implementation
> + */
> +static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval,
> + unsigned int optlen)
> +{
> + int val;
> + struct sctp_ep_common *epb;
> +
> + if (optlen < sizeof(int))
> + return -EINVAL;
> + if (get_user(val, (int __user *)optval))
> + return -EFAULT;
> + if (!sctp_is_ep_boundall(sk) && val)
> + return -EINVAL;
> + list_for_each_entry(epb, &sctp_auto_asconf_eplist, auto_asconf_list) {
> + if (epb->sk == sk) {
> + if (val == 0)
> + list_del(&epb->auto_asconf_list);
> + return 0;
> + }
> + }
> + if (val)
> + list_add_tail(&sctp_sk(sk)->ep->base.auto_asconf_list,
> + &sctp_auto_asconf_eplist);
> + return 0;
> +}
The sctp_setsockopt_auto_asconf is not correct, if we enable this option
twice, the list will be broken.
We'd better to introcude a auto_asconf flag to ep, and then, we do not
need to scanf the asconf_list.
If auto_asconf flag is true, it is exists in the list, otherwise, not.
>
> /* API 6.2 setsockopt(), getsockopt()
> *
> @@ -3488,6 +3772,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
> case SCTP_AUTH_DELETE_KEY:
> retval = sctp_setsockopt_del_key(sk, optval, optlen);
> break;
> + case SCTP_AUTO_ASCONF:
> + retval = sctp_setsockopt_auto_asconf(sk, optval, optlen);
> + break;
> default:
> retval = -ENOPROTOOPT;
> break;
> @@ -3770,6 +4057,10 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
> local_bh_disable();
> percpu_counter_inc(&sctp_sockets_allocated);
> sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
> + if (sctp_auto_asconf_enable)
> + list_add_tail(&ep->base.auto_asconf_list,
> + &sctp_auto_asconf_eplist);
> + SCTP_DEBUG_PRINTK("sctp_init_sk sk:%p ep:%p\n", sk, ep);
All of the sctp sockets are added to sctp_auto_asconf_eplist.
I think none of the sockets should exists in this list by default,
only after we enable AUTO_ASCONF, we should add it to this list.
> local_bh_enable();
>
> return 0;
> @@ -3779,11 +4070,18 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
> SCTP_STATIC void sctp_destroy_sock(struct sock *sk)
> {
> struct sctp_endpoint *ep;
> + struct sctp_ep_common *epb;
>
> SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk);
>
> /* Release our hold on the endpoint. */
> ep = sctp_sk(sk)->ep;
> + list_for_each_entry(epb, &sctp_auto_asconf_eplist, auto_asconf_list) {
> + if (epb->sk == sk) {
> + list_del(&epb->auto_asconf_list);
> + break;
> + }
> + }
> sctp_endpoint_free(ep);
> local_bh_disable();
> percpu_counter_dec(&sctp_sockets_allocated);
> @@ -5283,6 +5581,31 @@ static int sctp_getsockopt_assoc_number(struct sock *sk, int len,
> return 0;
> }
>
> +/*
> + * 8.1.23 SCTP_AUTO_ASCONF
> + * See the corresponding setsockopt entry as description
> + */
> +static int sctp_getsockopt_auto_asconf(struct sock *sk, int len,
> + char __user *optval, int __user *optlen)
> +{
> + int val = 0;
> + struct sctp_ep_common *epb;
> +
> + if (len < sizeof(int))
> + return -EINVAL;
> +
> + len = sizeof(int);
> + list_for_each_entry(epb, &sctp_auto_asconf_eplist, auto_asconf_list) {
> + if (epb->sk == sk)
> + val = 1;
> + }
> + if (put_user(len, optlen))
> + return -EFAULT;
> + if (copy_to_user(optval, &val, len))
> + return -EFAULT;
> + return 0;
> +}
> +
> SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
> char __user *optval, int __user *optlen)
> {
> @@ -5415,6 +5738,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
> case SCTP_GET_ASSOC_NUMBER:
> retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen);
> break;
> + case SCTP_AUTO_ASCONF:
> + retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen);
> + break;
> default:
> retval = -ENOPROTOOPT;
> break;
> diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
> index 50cb57f..df39789 100644
> --- a/net/sctp/sysctl.c
> +++ b/net/sctp/sysctl.c
> @@ -183,6 +183,13 @@ static ctl_table sctp_table[] = {
> .proc_handler = proc_dointvec,
> },
> {
> + .procname = "auto_asconf_enable",
> + .data = &sctp_auto_asconf_enable,
> + .maxlen = sizeof(int),
> + .mode = 0644,
> + .proc_handler = proc_dointvec,
> + },
> + {
> .procname = "prsctp_enable",
> .data = &sctp_prsctp_enable,
> .maxlen = sizeof(int),
>
Is the sysctl parameter necessary, since auto_asconf is disabled
by default, and we need to set the option to enabled it.
^ permalink raw reply
* RE: [PATCH] net: ethtool support to configure number of RX rings
From: Amit Salecha @ 2011-03-31 5:55 UTC (permalink / raw)
To: davem@davemloft.net
Cc: netdev@vger.kernel.org, Ameen Rahman, Anirban Chakraborty
In-Reply-To: <1301482774-2173-1-git-send-email-amit.salecha@qlogic.com>
> o Ethtool hook to configure number of RX rings.
> o Implementation is scalable to support configuring TX rings.
> o There exist ETHTOOL_GRXRINGS command for getting number of RX rings,
> but it is tigtly coupled with RX flow hash configuration.
> o Patches for qlcnic and netxen_nic driver supporting this features
> will follow soon.
>
> Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
> ---
> include/linux/ethtool.h | 20 ++++++++++++++++++++
> net/core/ethtool.c | 33 +++++++++++++++++++++++++++++++++
> 2 files changed, 53 insertions(+), 0 deletions(-)
>
> diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
> index aac3e2e..de0decd 100644
> --- a/include/linux/ethtool.h
> +++ b/include/linux/ethtool.h
> @@ -226,6 +226,21 @@ struct ethtool_ringparam {
> __u32 tx_pending;
> };
>
> +/* for configuring number of RX ring */
> +struct ethtool_ring {
> + __u32 cmd; /* ETHTOOL_{G,S}RING */
> +
> + /* Read only attributes. These indicate the maximum number
> + * of RX rings the driver will allow the user to set.
> + */
> + __u32 rx_max;
> +
> + /* Values changeable by the user. The valid values are
> + * in the range 1 to the "*_max" counterpart above.
> + */
> + __u32 rx_pending;
> +};
> +
Current implementation can't scale to support TX rings. Because once structure is defined, that can't be changed.
As tools will have dependency on it.
If configuring tx rings need to be supported, I need to define Tx parameters in struct ethtool_ring now.
Currently qlcnic and netxen_nic driver doesn't have requirement to configure number of tx rings.
Should I define tx parameters in struct ethtool_ring ?
-Amit
This message and any attached documents contain information from QLogic Corporation or its wholly-owned subsidiaries that may be confidential. If you are not the intended recipient, you may not read, copy, distribute, or use this information. If you have received this transmission in error, please notify the sender immediately by reply e-mail and then delete this message.
^ permalink raw reply
* Re: [PATCH 1/2] socket: increase default maximum listen queue length
From: David Miller @ 2011-03-31 5:52 UTC (permalink / raw)
To: hagen; +Cc: netdev, eric.dumazet
In-Reply-To: <1301077899-16482-1-git-send-email-hagen@jauu.net>
From: Hagen Paul Pfeifer <hagen@jauu.net>
Date: Fri, 25 Mar 2011 19:31:38 +0100
> sysctl_max_syn_backlog on the other hand provides similar functionality:
> provides a system wide upper limit of request sockets per listen socket.
> But sysctl_max_syn_backlog provides a more accurate value by considerate
> the actual memory situation of the system. 256 by default, 128 for
> systems with low memory and up to 1024 for larger systems.
sysctl_max_syn_backlog is not "256 by default", the calculation is:
cnt = tcp_hashinfo.ehash_mask + 1;
...
sysctl_max_syn_backlog = max(128, cnt / 256);
And I think we should leave the SOMAXCONN define alone (it's a
historic relic for userspace, and any sane server passes something
like ~0 into listen()).
And calculate the somaxconn sysctl at run time using a similar
formula to that used by sysctl_max_syn_backlog.
^ permalink raw reply
* Re: [PATCH] drivers/net: Remove IRQF_SAMPLE_RANDOM flag from network drivers
From: David Miller @ 2011-03-31 5:28 UTC (permalink / raw)
To: martinez.javier
Cc: bhutchings, ffainelli, eric.dumazet, netdev, kernel-janitors,
linux-kernel
In-Reply-To: <1301365651-9106-1-git-send-email-martinez.javier@gmail.com>
From: Javier Martinez Canillas <martinez.javier@gmail.com>
Date: Tue, 29 Mar 2011 04:27:31 +0200
> The IRQF_SAMPLE_RANDOM flag is marked as deprecated and will be removed.
>
> Every input point to the kernel's entropy pool have to better document the
> type of entropy source it is.
>
> drivers/char/random.c now implements a set of interfaces that can be used for
> devices to collect enviromental noise. IRQF_SAMPLE_RANDOM will be replaced
> with these add_*_randomness exported functions.
>
> Network drivers are not a good source of entropy. They use as a source of
> entropy essentially a remote host. Which means that the source of entropy can
> be potentially controlled by an attacker. Also, with heavy workloads the
> entropy decreases due to less hardware interrupts happening thanks to irq
> mitigation and NAPI.
>
> If a system relies in its network interface as a entropy source it has a false
> sense of security. Systems that don't have devices whose drivers are good
> sources of entropy, should either use a hardware random number generator or
> feed the kernel's entropy pool from userspace using other sources of entropy
> such as EGD, video_entropyd, timer_entropyd and audio-entropyd.
>
> Signed-off-by: Javier Martinez Canillas <martinez.javier@gmail.com>
Appied to net-next-2.6, thanks!
^ permalink raw reply
* [PATCH v3] net: Allow no-cache copy from user on transmit
From: Tom Herbert @ 2011-03-31 5:04 UTC (permalink / raw)
To: davem, netdev
This patch uses __copy_from_user_nocache (from skb_copy_to_page)
on transmit to bypass data cache for a performance improvement.
This functionality is configurable per device using ethtool.
Presumably, this feature would only be useful when the driver does
not touch the data. The feature is turned on by default if a device
indicates that it does some form of checksum offload; it is off by
default for devices that do no checksum offload or indicate no checksum
is necessary. For the former case copy-checksum is probably done
anyway, in the latter case the device is likely loopback in which case
the no cache copy is probably not beneficial.
This patch was tested using 200 instances of netperf TCP_RR with
1400 byte request and one byte reply. Platform is 16 core AMD x86.
No-cache copy disabled:
672703 tps, 97.13% utilization
50/90/99% latency:244.31 484.205 1028.41
No-cache copy enabled:
702113 tps, 96.16% utilization,
50/90/99% latency 238.56 467.56 956.955
Using 14000 byte request and response sizes demonstrate the
effects more dramatically:
No-cache copy disabled:
79571 tps, 34.34 %utlization
50/90/95% latency 1584.46 2319.59 5001.76
No-cache copy enabled:
83856 tps, 34.81% utilization
50/90/95% latency 2508.42 2622.62 2735.88
Note especially the effect on latency tail (95th percentile).
This seems to provide a nice performance improvement and is
consistent in the tests I ran. Presumably, this would provide
the greatest benfits in the presence of an application workload
stressing the cache and a lot of transmit data happening.
Signed-off-by: Tom Herbert <therbert@google.com>
---
drivers/net/bonding/bond_main.c | 2 +-
include/linux/netdevice.h | 6 ++++--
include/net/sock.h | 5 +++++
net/core/dev.c | 11 +++++++++++
net/core/ethtool.c | 2 +-
5 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 1a6e9eb..59b6ce9 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1407,7 +1407,7 @@ static int bond_compute_features(struct bonding *bond)
int i;
features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES);
- features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM;
+ features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_NOCACHE_COPY;
if (!bond->first_slave)
goto done;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 5eeb2cd..06327b5 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1066,6 +1066,7 @@ struct net_device {
#define NETIF_F_NTUPLE (1 << 27) /* N-tuple filters supported */
#define NETIF_F_RXHASH (1 << 28) /* Receive hashing offload */
#define NETIF_F_RXCSUM (1 << 29) /* Receive checksumming offload */
+#define NETIF_F_NOCACHE_COPY (1 << 30) /* Use no-cache copyfromuser */
/* Segmentation offload features */
#define NETIF_F_GSO_SHIFT 16
@@ -1081,7 +1082,7 @@ struct net_device {
/* = all defined minus driver/device-class-related */
#define NETIF_F_NEVER_CHANGE (NETIF_F_HIGHDMA | NETIF_F_VLAN_CHALLENGED | \
NETIF_F_LLTX | NETIF_F_NETNS_LOCAL)
-#define NETIF_F_ETHTOOL_BITS (0x3f3fffff & ~NETIF_F_NEVER_CHANGE)
+#define NETIF_F_ETHTOOL_BITS (0x7f3fffff & ~NETIF_F_NEVER_CHANGE)
/* List of features with software fallbacks. */
#define NETIF_F_GSO_SOFTWARE (NETIF_F_TSO | NETIF_F_TSO_ECN | \
@@ -1108,7 +1109,8 @@ struct net_device {
NETIF_F_FRAGLIST)
/* changeable features with no special hardware requirements */
-#define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO)
+#define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO | \
+ NETIF_F_NOCACHE_COPY)
/* Interface index. Unique device identifier */
int ifindex;
diff --git a/include/net/sock.h b/include/net/sock.h
index da0534d..74ce586 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1401,6 +1401,11 @@ static inline int skb_copy_to_page(struct sock *sk, char __user *from,
if (err)
return err;
skb->csum = csum_block_add(skb->csum, csum, skb->len);
+ } else if (sk->sk_route_caps & NETIF_F_NOCACHE_COPY) {
+ if (!access_ok(VERIFY_READ, from, copy) ||
+ __copy_from_user_nocache(page_address(page) + off,
+ from, copy))
+ return -EFAULT;
} else if (copy_from_user(page_address(page) + off, from, copy))
return -EFAULT;
diff --git a/net/core/dev.c b/net/core/dev.c
index 0b88eba..454abfd 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5444,6 +5444,13 @@ int register_netdevice(struct net_device *dev)
dev->features &= ~NETIF_F_GSO;
}
+ /* Turn no cache copy off if HW isn't doing checksum */
+ if (!(dev->features & NETIF_F_ALL_CSUM) ||
+ (dev->features & NETIF_F_NO_CSUM)) {
+ dev->wanted_features &= ~NETIF_F_NOCACHE_COPY;
+ dev->features &= ~NETIF_F_NOCACHE_COPY;
+ }
+
/* Enable GRO and NETIF_F_HIGHDMA for vlans by default,
* vlan_dev_init() will do the dev->features check, so these features
* are enabled only if supported by underlying device.
@@ -6201,6 +6208,10 @@ u32 netdev_increment_features(u32 all, u32 one, u32 mask)
}
}
+ /* If device can't no cache copy, don't do for all */
+ if (!(one & NETIF_F_NOCACHE_COPY))
+ all &= ~NETIF_F_NOCACHE_COPY;
+
one |= NETIF_F_ALL_CSUM;
one |= all & NETIF_F_ONE_FOR_ALL;
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index c1a71bb..40b6fe0 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -344,7 +344,7 @@ static const char netdev_features_strings[ETHTOOL_DEV_FEATURE_WORDS * 32][ETH_GS
/* NETIF_F_NTUPLE */ "rx-ntuple-filter",
/* NETIF_F_RXHASH */ "rx-hashing",
/* NETIF_F_RXCSUM */ "rx-checksum",
- "",
+ /* NETIF_F_NOCACHE_COPY */ "tx-nocache-copy"
"",
};
--
1.7.3.1
^ permalink raw reply related
* Re: [net-next-2.6 PATCH 0/4] enic: updates to version 2.1.1.13
From: David Miller @ 2011-03-31 4:43 UTC (permalink / raw)
To: roprabhu; +Cc: netdev
In-Reply-To: <20110330063533.7187.80458.stgit@savbu-pc100.cisco.com>
From: Roopa Prabhu <roprabhu@cisco.com>
Date: Tue, 29 Mar 2011 23:35:46 -0700
> This patch series implements the following enic driver updates:
>
> 01/4 - enic: Add support for new fw devcmds for port profile handling
> 02/4 - enic: Add wrapper routines for new fw devcmds for port profile handling
> 03/4 - enic: Cleanups in port profile helper code
> 04/4 - enic: Add support for PORT_REQUEST_PREASSOCIATE_RR
>
> Signed-off-by: Roopa Prabhu <roprabhu@cisco.com>
> Signed-off-by: David Wang <dwang2@cisco.com>
> Signed-off-by: Christian Benvenuti <benve@cisco.com>
All applied.
^ permalink raw reply
* Re: [PATCH] via-rhine: trivial sparse annotation in vlan_tci helper
From: David Miller @ 2011-03-31 4:43 UTC (permalink / raw)
To: harvey.harrison; +Cc: netdev
In-Reply-To: <1301368139-2489-1-git-send-email-harvey.harrison@gmail.com>
From: Harvey Harrison <harvey.harrison@gmail.com>
Date: Mon, 28 Mar 2011 20:08:59 -0700
> Noticed by sparse:
> drivers/net/via-rhine.c:1706:16: warning: cast to restricted __be16
>
> Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com>
Applied.
^ permalink raw reply
* Re: [PATCH] kstrtox: convert drivers/isdn/
From: David Miller @ 2011-03-31 4:43 UTC (permalink / raw)
To: adobriyan; +Cc: t.schmidt, netdev
In-Reply-To: <20110327125835.GA5820@p183.telecom.by>
From: Alexey Dobriyan <adobriyan@gmail.com>
Date: Sun, 27 Mar 2011 15:58:35 +0300
> Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Applied.
^ permalink raw reply
* Re: [PATCH] smsc911x: Use pr_fmt, netdev_<level>, and netif_<level>
From: David Miller @ 2011-03-31 4:43 UTC (permalink / raw)
To: joe; +Cc: steve.glendinning, jtp.park, netdev
In-Reply-To: <1301098883.4132.23.camel@Joe-Laptop>
From: Joe Perches <joe@perches.com>
Date: Fri, 25 Mar 2011 17:21:22 -0700
> Use the more common/verbose logging styles.
>
> Add #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> Remove smsc911x prefixes from format strings.
> Rename SMSC_WARNING to SMSC_WARN.
> Remove DPRINTK macro.
> Use netif_<level> in SMSC_<level> macros.
> Convert NETIF_MSG_<foo> uses to lower case.
> Add no_printk verification in non-debug uses.
> Add pdata to SMSC_<level> uses to avoid hidden variable uses.
> Convert printks to netdev_<level> as appropriate.
>
> Signed-off-by: Joe Perches <joe@perches.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next-2.6 0/5] resending patch series minus one patch
From: David Miller @ 2011-03-31 4:42 UTC (permalink / raw)
To: sathya.perla; +Cc: netdev
In-Reply-To: <cc416d6a-630e-41f2-a74e-22993cc1293d@exht1.ad.emulex.com>
From: Sathya Perla <sathya.perla@emulex.com>
Date: Tue, 22 Mar 2011 12:19:24 +0530
> Hi Dave, I'm re-sending my previous patch series minus the "don't drop vlan
> pkts" patch (I'll address this in a separate patch.)
>
> Pls apply. Thanks.
All applied.
^ permalink raw reply
* Re: [PATCH net-next 3/3] net/r8169: support RTL8168E
From: David Miller @ 2011-03-31 4:42 UTC (permalink / raw)
To: hayeswang; +Cc: romieu, netdev, linux-kernel
In-Reply-To: <1300708230-1934-1-git-send-email-hayeswang@realtek.com>
From: Hayes Wang <hayeswang@realtek.com>
Date: Mon, 21 Mar 2011 19:50:28 +0800
> Support RTL8168E/RTL8111E.
>
> Signed-off-by: Hayes Wang <hayeswang@realtek.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next 2/3] net/r8169: add a new chip for RTL8168DP
From: David Miller @ 2011-03-31 4:42 UTC (permalink / raw)
To: hayeswang; +Cc: romieu, netdev, linux-kernel
In-Reply-To: <1300708230-1934-2-git-send-email-hayeswang@realtek.com>
From: Hayes Wang <hayeswang@realtek.com>
Date: Mon, 21 Mar 2011 19:50:29 +0800
> Add a new chip for RTL8168DP.
>
> Signed-off-by: Hayes Wang <hayeswang@realtek.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next 1/3] net/r8169: add a new chip for RTL8105
From: David Miller @ 2011-03-31 4:42 UTC (permalink / raw)
To: hayeswang; +Cc: romieu, netdev, linux-kernel
In-Reply-To: <1300708230-1934-3-git-send-email-hayeswang@realtek.com>
From: Hayes Wang <hayeswang@realtek.com>
Date: Mon, 21 Mar 2011 19:50:30 +0800
> Add a new chip for RTL8105 whose settings are the same with RTL_GIGA_MAC_VER_30.
>
> Signed-off-by: Hayes Wang <hayeswang@realtek.com>
Applied.
^ permalink raw reply
* Re: [PATCH 1/9 net-next-2.6] qlcnic: make PCI info available in all modes
From: David Miller @ 2011-03-31 4:40 UTC (permalink / raw)
To: anirban.chakraborty; +Cc: netdev, Dept_NX_Linux_NIC_Driver
In-Reply-To: <alpine.OSX.2.00.1103301258180.31005@macintosh-2.local>
From: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
Date: Wed, 30 Mar 2011 13:21:36 -0700
> From: Sony Chacko <sony.chacko@qlogic.com>
>
> Before this fix, PCI info was available only when multiple NIC functions were
> present on a port.
>
> Signed-off-by: Sony Chacko <sony.chacko@qlogic.com>
> Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
Your email client has mangled all of these patches, turning tab characters
into spaces.
Given the number of patches that come in for the qlcnic driver, you guys
have to do better than this.
^ permalink raw reply
* [PATCH] IPVS Bug, Null ptr in ip_vs_ctl.c ip_vs_genl_dump_daemons().
From: Simon Horman @ 2011-03-31 1:32 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter-devel, netfilter
Cc: Hans Schillstrom, Julian Anastasov, Patrick McHardy, Simon Horman,
Hans Schillstrom
In-Reply-To: <1301535135-4288-1-git-send-email-horms@verge.net.au>
From: Hans Schillstrom <hans.schillstrom@ericsson.com>
ipvsadm -ln --daemon will trigger a Null pointer exception because
ip_vs_genl_dump_daemons() uses skb_net() instead of skb_sknet().
To prevent others from NULL ptr a check is made in ip_vs.h skb_net().
Signed-off-by: Hans Schillstrom <hans.schillstrom@ericsson.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
include/net/ip_vs.h | 2 +-
net/netfilter/ipvs/ip_vs_ctl.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 30b49ed..4d1b71a 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -52,7 +52,7 @@ static inline struct net *skb_net(const struct sk_buff *skb)
*/
if (likely(skb->dev && skb->dev->nd_net))
return dev_net(skb->dev);
- if (skb_dst(skb)->dev)
+ if (skb_dst(skb) && skb_dst(skb)->dev)
return dev_net(skb_dst(skb)->dev);
WARN(skb->sk, "Maybe skb_sknet should be used in %s() at line:%d\n",
__func__, __LINE__);
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 33733c8..ae47090 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -3120,7 +3120,7 @@ nla_put_failure:
static int ip_vs_genl_dump_daemons(struct sk_buff *skb,
struct netlink_callback *cb)
{
- struct net *net = skb_net(skb);
+ struct net *net = skb_sknet(skb);
struct netns_ipvs *ipvs = net_ipvs(net);
mutex_lock(&__ip_vs_mutex);
--
1.7.4.1
^ permalink raw reply related
* [GIT PULL nf-2.6] IPVS
From: Simon Horman @ 2011-03-31 1:32 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter-devel, netfilter
Cc: Hans Schillstrom, Julian Anastasov, Patrick McHardy, Simon Horman
Hi Patrick,
please consider pulling
git://git.kernel.org/pub/scm/linux/kernel/git/horms/lvs-test-2.6.git for-patrick
to get the following fix from Hans.
I have based this patch on net-2.6/master as nf-2.6/master seems a little
out of date (i.e. pre 2.6.39-rc1). Please let me know if you would
prefer me to use a different base. Alternatively, feel free to apply
the single patch by hand.
Hans Schillstrom (1):
IPVS Bug, Null ptr in ip_vs_ctl.c ip_vs_genl_dump_daemons().
include/net/ip_vs.h | 2 +-
net/netfilter/ipvs/ip_vs_ctl.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
^ permalink raw reply
* Re: [PATCH] IPVS Bug, Null ptr in ip_vs_ctl.c ip_vs_genl_dump_daemons().
From: Simon Horman @ 2011-03-31 1:24 UTC (permalink / raw)
To: Hans Schillstrom; +Cc: ja, wensong, lvs-devel, netdev, netfilter-devel, hans
In-Reply-To: <1301495797-7546-1-git-send-email-hans.schillstrom@ericsson.com>
On Wed, Mar 30, 2011 at 04:36:37PM +0200, Hans Schillstrom wrote:
> ipvsadm -ln --daemon will trigger a Null pointer exception because
> ip_vs_genl_dump_daemons() uses skb_net() instead of skb_sknet().
>
> To prevent others from NULL ptr a check is made in ip_vs.h skb_net().
>
> This patches is based on net-2.6
Thanks Hans,
I will prepare a pull request for Patrick this afternoon.
^ permalink raw reply
* Re: loading sctp fails an order 10 allocation.
From: David Miller @ 2011-03-31 0:52 UTC (permalink / raw)
To: davej; +Cc: netdev, linux-kernel
In-Reply-To: <20110330234020.GA24517@redhat.com>
From: Dave Jones <davej@redhat.com>
Date: Wed, 30 Mar 2011 19:40:21 -0400
> modprobe sctp on my laptop does this which looks crazy..
...
> it doesn't look like the hashtable allocation code has changed in ages, so I'm
> not sure why I've never triggered this before.
I decided to take a break from watching Charlie Sheen dubstep remixes
in a loop on youtube to look at this bug.
This situation is amusing because SCTP actually tries to allocate an
initially smaller hash table than, for example, the DCCP module does.
But DCCP won't show the behavior you see.
The thing that's different is that SCTP forgets to pass __GFP_NOWARN
to the allocation. The code there is able to handle failures just
fine and simply tries to progressively grab a smaller table when that
happens.
I'll commit the following to net-2.6, thanks.
Now back to Adonis dubsteps...
--------------------
sctp: Pass __GFP_NOWARN to hash table allocation attempts.
Like DCCP and other similar pieces of code, there are mechanisms
here to try allocating smaller hash tables if the allocation
fails. So pass in __GFP_NOWARN like the others do instead of
emitting a scary message.
Reported-by: Dave Jones <davej@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/sctp/protocol.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 152976e..d5bf91d 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -1205,7 +1205,7 @@ SCTP_STATIC __init int sctp_init(void)
if ((sctp_assoc_hashsize > (64 * 1024)) && order > 0)
continue;
sctp_assoc_hashtable = (struct sctp_hashbucket *)
- __get_free_pages(GFP_ATOMIC, order);
+ __get_free_pages(GFP_ATOMIC|__GFP_NOWARN, order);
} while (!sctp_assoc_hashtable && --order > 0);
if (!sctp_assoc_hashtable) {
pr_err("Failed association hash alloc\n");
@@ -1238,7 +1238,7 @@ SCTP_STATIC __init int sctp_init(void)
if ((sctp_port_hashsize > (64 * 1024)) && order > 0)
continue;
sctp_port_hashtable = (struct sctp_bind_hashbucket *)
- __get_free_pages(GFP_ATOMIC, order);
+ __get_free_pages(GFP_ATOMIC|__GFP_NOWARN, order);
} while (!sctp_port_hashtable && --order > 0);
if (!sctp_port_hashtable) {
pr_err("Failed bind hash alloc\n");
--
1.7.4.2
^ permalink raw reply related
* Re: connector: convert to synchronous netlink message processing
From: David Miller @ 2011-03-31 0:15 UTC (permalink / raw)
To: zbr; +Cc: kaber, netdev
In-Reply-To: <20110330133913.GA9425@ioremap.net>
From: Evgeniy Polyakov <zbr@ioremap.net>
Date: Wed, 30 Mar 2011 17:39:13 +0400
> Hi Patrick
>
> On Mon, Mar 28, 2011 at 08:39:36PM +0200, Patrick McHardy (kaber@trash.net) wrote:
>> This patch fixes up connector to work properly with the recent
>> netlink changes that require synchronous netlink message processing.
>>
>> The patch is so far only compile tested since I'm still looking
>> for a good way to test it. If you could point me to some software
>> using the proc events that would be appreciated.
>
> There is test module in Documentation/connector/ and/or samples/ which I
> used for tests. It was quite for a while when it was used last time
> though.
>
> Your patch looks very good and I definitely ack this :)
Applied, if there are some bugs spotted, please just send the fixes
as follow-on patches.
Thanks.
^ permalink raw reply
* Re: [PATCH 1/1] atm/solos-pci: Don't flap VCs when carrier state changes
From: David Miller @ 2011-03-30 23:56 UTC (permalink / raw)
To: philipp_subx; +Cc: netdev
In-Reply-To: <1301527024-28875-1-git-send-email-philipp_subx@redfish-solutions.com>
All 3 patches applied, thanks.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox