aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/8021q/vlan_core.c39
-rw-r--r--net/Kconfig2
-rw-r--r--net/appletalk/dev.c10
-rw-r--r--net/atm/br2684.c58
-rw-r--r--net/atm/clip.c30
-rw-r--r--net/atm/lec.c64
-rw-r--r--net/atm/lec.h1
-rw-r--r--net/core/dev.c212
-rw-r--r--net/core/skbuff.c27
-rw-r--r--net/dccp/dccp.h21
-rw-r--r--net/dccp/feat.c232
-rw-r--r--net/dccp/feat.h21
-rw-r--r--net/dccp/minisocks.c11
-rw-r--r--net/dccp/options.c8
-rw-r--r--net/dccp/proto.c2
-rw-r--r--net/dccp/sysctl.c43
-rw-r--r--net/ipv4/af_inet.c10
-rw-r--r--net/ipv4/inet_connection_sock.c41
-rw-r--r--net/ipv4/inet_hashtables.c11
-rw-r--r--net/ipv4/ip_gre.c131
-rw-r--r--net/ipv4/ipmr.c461
-rw-r--r--net/ipv4/route.c11
-rw-r--r--net/ipv4/tcp.c16
-rw-r--r--net/ipv4/tcp_ipv4.c2
-rw-r--r--net/ipv6/af_inet6.c30
-rw-r--r--net/ipv6/tcp_ipv6.c2
-rw-r--r--net/netrom/af_netrom.c2
-rw-r--r--net/netrom/nr_dev.c26
-rw-r--r--net/phonet/af_phonet.c29
-rw-r--r--net/phonet/pn_dev.c119
-rw-r--r--net/phonet/pn_netlink.c24
-rw-r--r--net/rose/af_rose.c3
-rw-r--r--net/rose/rose_dev.c22
-rw-r--r--net/sctp/ipv6.c3
34 files changed, 1046 insertions, 678 deletions
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index e9db889d622..378fa69d625 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -98,22 +98,9 @@ drop:
int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp,
unsigned int vlan_tci, struct sk_buff *skb)
{
- int err = NET_RX_SUCCESS;
+ skb_gro_reset_offset(skb);
- switch (vlan_gro_common(napi, grp, vlan_tci, skb)) {
- case -1:
- return netif_receive_skb(skb);
-
- case 2:
- err = NET_RX_DROP;
- /* fall through */
-
- case 1:
- kfree_skb(skb);
- break;
- }
-
- return err;
+ return napi_skb_finish(vlan_gro_common(napi, grp, vlan_tci, skb), skb);
}
EXPORT_SYMBOL(vlan_gro_receive);
@@ -121,27 +108,11 @@ int vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp,
unsigned int vlan_tci, struct napi_gro_fraginfo *info)
{
struct sk_buff *skb = napi_fraginfo_skb(napi, info);
- int err = NET_RX_DROP;
if (!skb)
- goto out;
-
- err = NET_RX_SUCCESS;
-
- switch (vlan_gro_common(napi, grp, vlan_tci, skb)) {
- case -1:
- return netif_receive_skb(skb);
-
- case 2:
- err = NET_RX_DROP;
- /* fall through */
-
- case 1:
- napi_reuse_skb(napi, skb);
- break;
- }
+ return NET_RX_DROP;
-out:
- return err;
+ return napi_frags_finish(napi, skb,
+ vlan_gro_common(napi, grp, vlan_tci, skb));
}
EXPORT_SYMBOL(vlan_gro_frags);
diff --git a/net/Kconfig b/net/Kconfig
index cdb8fdef6c4..a12bae0e3fe 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -185,6 +185,7 @@ source "net/x25/Kconfig"
source "net/lapb/Kconfig"
source "net/econet/Kconfig"
source "net/wanrouter/Kconfig"
+source "net/phonet/Kconfig"
source "net/sched/Kconfig"
source "net/dcb/Kconfig"
@@ -229,7 +230,6 @@ source "net/can/Kconfig"
source "net/irda/Kconfig"
source "net/bluetooth/Kconfig"
source "net/rxrpc/Kconfig"
-source "net/phonet/Kconfig"
config FIB_RULES
bool
diff --git a/net/appletalk/dev.c b/net/appletalk/dev.c
index d856a62ab50..72277d70c98 100644
--- a/net/appletalk/dev.c
+++ b/net/appletalk/dev.c
@@ -9,22 +9,20 @@
#include <linux/if_arp.h>
#include <linux/if_ltalk.h>
+#ifdef CONFIG_COMPAT_NET_DEV_OPS
static int ltalk_change_mtu(struct net_device *dev, int mtu)
{
return -EINVAL;
}
-
-static int ltalk_mac_addr(struct net_device *dev, void *addr)
-{
- return -EINVAL;
-}
+#endif
static void ltalk_setup(struct net_device *dev)
{
/* Fill in the fields of the device structure with localtalk-generic values. */
+#ifdef CONFIG_COMPAT_NET_DEV_OPS
dev->change_mtu = ltalk_change_mtu;
- dev->set_mac_address = ltalk_mac_addr;
+#endif
dev->type = ARPHRD_LOCALTLK;
dev->hard_header_len = LTALK_HLEN;
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index ea9438fc685..334fcd4a4ea 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -83,7 +83,6 @@ struct br2684_dev {
struct list_head br2684_devs;
int number;
struct list_head brvccs; /* one device <=> one vcc (before xmas) */
- struct net_device_stats stats;
int mac_was_set;
enum br2684_payload payload;
};
@@ -148,9 +147,10 @@ static struct net_device *br2684_find_dev(const struct br2684_if_spec *s)
* the way for multiple vcc's per itf. Returns true if we can send,
* otherwise false
*/
-static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev,
+static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev,
struct br2684_vcc *brvcc)
{
+ struct br2684_dev *brdev = BRPRIV(dev);
struct atm_vcc *atmvcc;
int minheadroom = (brvcc->encaps == e_llc) ? 10 : 2;
@@ -211,8 +211,8 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev,
}
atomic_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc);
ATM_SKB(skb)->atm_options = atmvcc->atm_options;
- brdev->stats.tx_packets++;
- brdev->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
atmvcc->send(atmvcc, skb);
return 1;
}
@@ -233,14 +233,14 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev)
brvcc = pick_outgoing_vcc(skb, brdev);
if (brvcc == NULL) {
pr_debug("no vcc attached to dev %s\n", dev->name);
- brdev->stats.tx_errors++;
- brdev->stats.tx_carrier_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_carrier_errors++;
/* netif_stop_queue(dev); */
dev_kfree_skb(skb);
read_unlock(&devs_lock);
return 0;
}
- if (!br2684_xmit_vcc(skb, brdev, brvcc)) {
+ if (!br2684_xmit_vcc(skb, dev, brvcc)) {
/*
* We should probably use netif_*_queue() here, but that
* involves added complication. We need to walk before
@@ -248,27 +248,20 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev)
*
* Don't free here! this pointer might be no longer valid!
*/
- brdev->stats.tx_errors++;
- brdev->stats.tx_fifo_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_fifo_errors++;
}
read_unlock(&devs_lock);
return 0;
}
-static struct net_device_stats *br2684_get_stats(struct net_device *dev)
-{
- pr_debug("br2684_get_stats\n");
- return &BRPRIV(dev)->stats;
-}
-
/*
* We remember when the MAC gets set, so we don't override it later with
* the ESI of the ATM card of the first VC
*/
-static int (*my_eth_mac_addr) (struct net_device *, void *);
static int br2684_mac_addr(struct net_device *dev, void *p)
{
- int err = my_eth_mac_addr(dev, p);
+ int err = eth_mac_addr(dev, p);
if (!err)
BRPRIV(dev)->mac_was_set = 1;
return err;
@@ -430,17 +423,17 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
/* sigh, interface is down? */
if (unlikely(!(net_dev->flags & IFF_UP)))
goto dropped;
- brdev->stats.rx_packets++;
- brdev->stats.rx_bytes += skb->len;
+ net_dev->stats.rx_packets++;
+ net_dev->stats.rx_bytes += skb->len;
memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
netif_rx(skb);
return;
dropped:
- brdev->stats.rx_dropped++;
+ net_dev->stats.rx_dropped++;
goto free_skb;
error:
- brdev->stats.rx_errors++;
+ net_dev->stats.rx_errors++;
free_skb:
dev_kfree_skb(skb);
return;
@@ -531,8 +524,8 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
skb->next = skb->prev = NULL;
br2684_push(atmvcc, skb);
- BRPRIV(skb->dev)->stats.rx_bytes -= skb->len;
- BRPRIV(skb->dev)->stats.rx_packets--;
+ skb->dev->stats.rx_bytes -= skb->len;
+ skb->dev->stats.rx_packets--;
skb = next;
}
@@ -544,17 +537,20 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
return err;
}
+static const struct net_device_ops br2684_netdev_ops = {
+ .ndo_start_xmit = br2684_start_xmit,
+ .ndo_set_mac_address = br2684_mac_addr,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
static void br2684_setup(struct net_device *netdev)
{
struct br2684_dev *brdev = BRPRIV(netdev);
ether_setup(netdev);
- brdev->net_dev = netdev;
- my_eth_mac_addr = netdev->set_mac_address;
- netdev->set_mac_address = br2684_mac_addr;
- netdev->hard_start_xmit = br2684_start_xmit;
- netdev->get_stats = br2684_get_stats;
+ netdev->netdev_ops = &br2684_netdev_ops;
INIT_LIST_HEAD(&brdev->brvccs);
}
@@ -565,10 +561,8 @@ static void br2684_setup_routed(struct net_device *netdev)
brdev->net_dev = netdev;
netdev->hard_header_len = 0;
- my_eth_mac_addr = netdev->set_mac_address;
- netdev->set_mac_address = br2684_mac_addr;
- netdev->hard_start_xmit = br2684_start_xmit;
- netdev->get_stats = br2684_get_stats;
+
+ netdev->netdev_ops = &br2684_netdev_ops;
netdev->addr_len = 0;
netdev->mtu = 1500;
netdev->type = ARPHRD_PPP;
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 2d33a83be79..da42fd06b61 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -214,15 +214,15 @@ static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb)
skb->protocol = ((__be16 *) skb->data)[3];
skb_pull(skb, RFC1483LLC_LEN);
if (skb->protocol == htons(ETH_P_ARP)) {
- PRIV(skb->dev)->stats.rx_packets++;
- PRIV(skb->dev)->stats.rx_bytes += skb->len;
+ skb->dev->stats.rx_packets++;
+ skb->dev->stats.rx_bytes += skb->len;
clip_arp_rcv(skb);
return;
}
}
clip_vcc->last_use = jiffies;
- PRIV(skb->dev)->stats.rx_packets++;
- PRIV(skb->dev)->stats.rx_bytes += skb->len;
+ skb->dev->stats.rx_packets++;
+ skb->dev->stats.rx_bytes += skb->len;
memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
netif_rx(skb);
}
@@ -372,7 +372,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (!skb->dst) {
printk(KERN_ERR "clip_start_xmit: skb->dst == NULL\n");
dev_kfree_skb(skb);
- clip_priv->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
return 0;
}
if (!skb->dst->neighbour) {
@@ -380,13 +380,13 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb->dst->neighbour = clip_find_neighbour(skb->dst, 1);
if (!skb->dst->neighbour) {
dev_kfree_skb(skb); /* lost that one */
- clip_priv->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
return 0;
}
#endif
printk(KERN_ERR "clip_start_xmit: NO NEIGHBOUR !\n");
dev_kfree_skb(skb);
- clip_priv->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
return 0;
}
entry = NEIGH2ENTRY(skb->dst->neighbour);
@@ -400,7 +400,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb_queue_tail(&entry->neigh->arp_queue, skb);
else {
dev_kfree_skb(skb);
- clip_priv->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
}
return 0;
}
@@ -423,8 +423,8 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_WARNING "clip_start_xmit: XOFF->XOFF transition\n");
return 0;
}
- clip_priv->stats.tx_packets++;
- clip_priv->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
vcc->send(vcc, skb);
if (atm_may_send(vcc, 0)) {
entry->vccs->xoff = 0;
@@ -443,11 +443,6 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-static struct net_device_stats *clip_get_stats(struct net_device *dev)
-{
- return &PRIV(dev)->stats;
-}
-
static int clip_mkip(struct atm_vcc *vcc, int timeout)
{
struct clip_vcc *clip_vcc;
@@ -501,8 +496,8 @@ static int clip_mkip(struct atm_vcc *vcc, int timeout)
skb_get(skb);
clip_push(vcc, skb);
- PRIV(skb->dev)->stats.rx_packets--;
- PRIV(skb->dev)->stats.rx_bytes -= len;
+ skb->dev->stats.rx_packets--;
+ skb->dev->stats.rx_bytes -= len;
kfree_skb(skb);
}
@@ -561,7 +556,6 @@ static void clip_setup(struct net_device *dev)
{
dev->hard_start_xmit = clip_start_xmit;
/* sg_xmit ... */
- dev->get_stats = clip_get_stats;
dev->type = ARPHRD_ATM;
dev->hard_header_len = RFC1483LLC_LEN;
dev->mtu = RFC1626_MTU;
diff --git a/net/atm/lec.c b/net/atm/lec.c
index e5e301550e8..c0cba9a037e 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -62,7 +62,6 @@ static unsigned char bridge_ula_lec[] = { 0x01, 0x80, 0xc2, 0x00, 0x00 };
static int lec_open(struct net_device *dev);
static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int lec_close(struct net_device *dev);
-static struct net_device_stats *lec_get_stats(struct net_device *dev);
static void lec_init(struct net_device *dev);
static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
const unsigned char *mac_addr);
@@ -218,28 +217,28 @@ static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
static int lec_open(struct net_device *dev)
{
- struct lec_priv *priv = netdev_priv(dev);
-
netif_start_queue(dev);
- memset(&priv->stats, 0, sizeof(struct net_device_stats));
+ memset(&dev->stats, 0, sizeof(struct net_device_stats));
return 0;
}
-static __inline__ void
-lec_send(struct atm_vcc *vcc, struct sk_buff *skb, struct lec_priv *priv)
+static void
+lec_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
+ struct net_device *dev = skb->dev;
+
ATM_SKB(skb)->vcc = vcc;
ATM_SKB(skb)->atm_options = vcc->atm_options;
atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
if (vcc->send(vcc, skb) < 0) {
- priv->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
return;
}
- priv->stats.tx_packets++;
- priv->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
}
static void lec_tx_timeout(struct net_device *dev)
@@ -270,7 +269,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
pr_debug("lec_start_xmit called\n");
if (!priv->lecd) {
printk("%s:No lecd attached\n", dev->name);
- priv->stats.tx_errors++;
+ dev->stats.tx_errors++;
netif_stop_queue(dev);
return -EUNATCH;
}
@@ -345,7 +344,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
GFP_ATOMIC);
dev_kfree_skb(skb);
if (skb2 == NULL) {
- priv->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
return 0;
}
skb = skb2;
@@ -380,7 +379,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ",
dev->name);
pr_debug("MAC address %pM\n", lec_h->h_dest);
- priv->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
dev_kfree_skb(skb);
}
goto out;
@@ -392,10 +391,10 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
pr_debug("lec.c: emptying tx queue, ");
pr_debug("MAC address %pM\n", lec_h->h_dest);
- lec_send(vcc, skb2, priv);
+ lec_send(vcc, skb2);
}
- lec_send(vcc, skb, priv);
+ lec_send(vcc, skb);
if (!atm_may_send(vcc, 0)) {
struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
@@ -427,15 +426,6 @@ static int lec_close(struct net_device *dev)
return 0;
}
-/*
- * Get the current statistics.
- * This may be called with the card open or closed.
- */
-static struct net_device_stats *lec_get_stats(struct net_device *dev)
-{
- return &((struct lec_priv *)netdev_priv(dev))->stats;
-}
-
static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
unsigned long flags;
@@ -677,17 +667,19 @@ static void lec_set_multicast_list(struct net_device *dev)
return;
}
+static const struct net_device_ops lec_netdev_ops = {
+ .ndo_open = lec_open,
+ .ndo_stop = lec_close,
+ .ndo_start_xmit = lec_start_xmit,
+ .ndo_change_mtu = lec_change_mtu,
+ .ndo_tx_timeout = lec_tx_timeout,
+ .ndo_set_multicast_list = lec_set_multicast_list,
+};
+
+
static void lec_init(struct net_device *dev)
{
- dev->change_mtu = lec_change_mtu;
- dev->open = lec_open;
- dev->stop = lec_close;
- dev->hard_start_xmit = lec_start_xmit;
- dev->tx_timeout = lec_tx_timeout;
-
- dev->get_stats = lec_get_stats;
- dev->set_multicast_list = lec_set_multicast_list;
- dev->do_ioctl = NULL;
+ dev->netdev_ops = &lec_netdev_ops;
printk("%s: Initialized!\n", dev->name);
}
@@ -810,8 +802,8 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
else
#endif
skb->protocol = eth_type_trans(skb, dev);
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
netif_rx(skb);
}
@@ -1887,7 +1879,7 @@ restart:
lec_arp_hold(entry);
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
- lec_send(vcc, skb, entry->priv);
+ lec_send(vcc, skb);
entry->last_used = jiffies;
entry->status = ESI_FORWARD_DIRECT;
lec_arp_put(entry);
@@ -2305,7 +2297,7 @@ restart:
lec_arp_hold(entry);
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
- lec_send(vcc, skb, entry->priv);
+ lec_send(vcc, skb);
entry->last_used = jiffies;
entry->status = ESI_FORWARD_DIRECT;
lec_arp_put(entry);
diff --git a/net/atm/lec.h b/net/atm/lec.h
index 0d376682c1a..9d14d196cc1 100644
--- a/net/atm/lec.h
+++ b/net/atm/lec.h
@@ -69,7 +69,6 @@ struct lane2_ops {
#define LEC_ARP_TABLE_SIZE 16
struct lec_priv {
- struct net_device_stats stats;
unsigned short lecid; /* Lecid of this client */
struct hlist_head lec_arp_empty_ones;
/* Used for storing VCC's that don't have a MAC address attached yet */
diff --git a/net/core/dev.c b/net/core/dev.c
index 5379b0c1190..ec5be1c7f2f 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -135,6 +135,14 @@
/* This should be increased if a protocol with a bigger head is added. */
#define GRO_MAX_HEAD (MAX_HEADER + 128)
+enum {
+ GRO_MERGED,
+ GRO_MERGED_FREE,
+ GRO_HELD,
+ GRO_NORMAL,
+ GRO_DROP,
+};
+
/*
* The list of packet types we will receive (as opposed to discard)
* and the routines to invoke.
@@ -207,6 +215,13 @@ static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex)
return &net->dev_index_head[ifindex & ((1 << NETDEV_HASHBITS) - 1)];
}
+static inline void *skb_gro_mac_header(struct sk_buff *skb)
+{
+ return skb_headlen(skb) ? skb_mac_header(skb) :
+ page_address(skb_shinfo(skb)->frags[0].page) +
+ skb_shinfo(skb)->frags[0].page_offset;
+}
+
/* Device list insertion */
static int list_netdevice(struct net_device *dev)
{
@@ -1708,56 +1723,26 @@ out_kfree_skb:
return 0;
}
-static u32 simple_tx_hashrnd;
-static int simple_tx_hashrnd_initialized = 0;
+static u32 skb_tx_hashrnd;
+static int skb_tx_hashrnd_initialized = 0;
-static u16 simple_tx_hash(struct net_device *dev, struct sk_buff *skb)
+static u16 skb_tx_hash(struct net_device *dev, struct sk_buff *skb)
{
- u32 addr1, addr2, ports;
- u32 hash, ihl;
- u8 ip_proto = 0;
-
- if (unlikely(!simple_tx_hashrnd_initialized)) {
- get_random_bytes(&simple_tx_hashrnd, 4);
- simple_tx_hashrnd_initialized = 1;
- }
+ u32 hash;
- switch (skb->protocol) {
- case htons(ETH_P_IP):
- if (!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)))
- ip_proto = ip_hdr(skb)->protocol;
- addr1 = ip_hdr(skb)->saddr;
- addr2 = ip_hdr(skb)->daddr;
- ihl = ip_hdr(skb)->ihl;
- break;
- case htons(ETH_P_IPV6):
- ip_proto = ipv6_hdr(skb)->nexthdr;
- addr1 = ipv6_hdr(skb)->saddr.s6_addr32[3];
- addr2 = ipv6_hdr(skb)->daddr.s6_addr32[3];
- ihl = (40 >> 2);
- break;
- default:
- return 0;
+ if (unlikely(!skb_tx_hashrnd_initialized)) {
+ get_random_bytes(&skb_tx_hashrnd, 4);
+ skb_tx_hashrnd_initialized = 1;
}
+ if (skb_rx_queue_recorded(skb)) {
+ hash = skb_get_rx_queue(skb);
+ } else if (skb->sk && skb->sk->sk_hash) {
+ hash = skb->sk->sk_hash;
+ } else
+ hash = skb->protocol;
- switch (ip_proto) {
- case IPPROTO_TCP:
- case IPPROTO_UDP:
- case IPPROTO_DCCP:
- case IPPROTO_ESP:
- case IPPROTO_AH:
- case IPPROTO_SCTP:
- case IPPROTO_UDPLITE:
- ports = *((u32 *) (skb_network_header(skb) + (ihl * 4)));
- break;
-
- default:
- ports = 0;
- break;
- }
-
- hash = jhash_3words(addr1, addr2, ports, simple_tx_hashrnd);
+ hash = jhash_1word(hash, skb_tx_hashrnd);
return (u16) (((u64) hash * dev->real_num_tx_queues) >> 32);
}
@@ -1771,7 +1756,7 @@ static struct netdev_queue *dev_pick_tx(struct net_device *dev,
if (ops->ndo_select_queue)
queue_index = ops->ndo_select_queue(dev, skb);
else if (dev->real_num_tx_queues > 1)
- queue_index = simple_tx_hash(dev, skb);
+ queue_index = skb_tx_hash(dev, skb);
skb_set_queue_mapping(skb, queue_index);
return netdev_get_tx_queue(dev, queue_index);
@@ -2372,7 +2357,6 @@ static int napi_gro_complete(struct sk_buff *skb)
out:
skb_shinfo(skb)->gso_size = 0;
- __skb_push(skb, -skb_network_offset(skb));
return netif_receive_skb(skb);
}
@@ -2390,6 +2374,25 @@ void napi_gro_flush(struct napi_struct *napi)
}
EXPORT_SYMBOL(napi_gro_flush);
+void *skb_gro_header(struct sk_buff *skb, unsigned int hlen)
+{
+ unsigned int offset = skb_gro_offset(skb);
+
+ hlen += offset;
+ if (hlen <= skb_headlen(skb))
+ return skb->data + offset;
+
+ if (unlikely(!skb_shinfo(skb)->nr_frags ||
+ skb_shinfo(skb)->frags[0].size <=
+ hlen - skb_headlen(skb) ||
+ PageHighMem(skb_shinfo(skb)->frags[0].page)))
+ return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL;
+
+ return page_address(skb_shinfo(skb)->frags[0].page) +
+ skb_shinfo(skb)->frags[0].page_offset + offset;
+}
+EXPORT_SYMBOL(skb_gro_header);
+
int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
{
struct sk_buff **pp = NULL;
@@ -2399,7 +2402,7 @@ int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
int count = 0;
int same_flow;
int mac_len;
- int free;
+ int ret;
if (!(skb->dev->features & NETIF_F_GRO))
goto normal;
@@ -2410,11 +2413,13 @@ int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
rcu_read_lock();
list_for_each_entry_rcu(ptype, head, list) {
struct sk_buff *p;
+ void *mac;
if (ptype->type != type || ptype->dev || !ptype->gro_receive)
continue;
- skb_reset_network_header(skb);
+ skb_set_network_header(skb, skb_gro_offset(skb));
+ mac = skb_gro_mac_header(skb);
mac_len = skb->network_header - skb->mac_header;
skb->mac_len = mac_len;
NAPI_GRO_CB(skb)->same_flow = 0;
@@ -2428,8 +2433,7 @@ int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
continue;
if (p->mac_len != mac_len ||
- memcmp(skb_mac_header(p), skb_mac_header(skb),
- mac_len))
+ memcmp(skb_mac_header(p), mac, mac_len))
NAPI_GRO_CB(p)->same_flow = 0;
}
@@ -2442,7 +2446,7 @@ int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
goto normal;
same_flow = NAPI_GRO_CB(skb)->same_flow;
- free = NAPI_GRO_CB(skb)->free;
+ ret = NAPI_GRO_CB(skb)->free ? GRO_MERGED_FREE : GRO_MERGED;
if (pp) {
struct sk_buff *nskb = *pp;
@@ -2456,21 +2460,20 @@ int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
if (same_flow)
goto ok;
- if (NAPI_GRO_CB(skb)->flush || count >= MAX_GRO_SKBS) {
- __skb_push(skb, -skb_network_offset(skb));
+ if (NAPI_GRO_CB(skb)->flush || count >= MAX_GRO_SKBS)
goto normal;
- }
NAPI_GRO_CB(skb)->count = 1;
- skb_shinfo(skb)->gso_size = skb->len;
+ skb_shinfo(skb)->gso_size = skb_gro_len(skb);
skb->next = napi->gro_list;
napi->gro_list = skb;
+ ret = GRO_HELD;
ok:
- return free;
+ return ret;
normal:
- return -1;
+ return GRO_NORMAL;
}
EXPORT_SYMBOL(dev_gro_receive);
@@ -2486,18 +2489,32 @@ static int __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
return dev_gro_receive(napi, skb);
}
-int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
+int napi_skb_finish(int ret, struct sk_buff *skb)
{
- switch (__napi_gro_receive(napi, skb)) {
- case -1:
+ int err = NET_RX_SUCCESS;
+
+ switch (ret) {
+ case GRO_NORMAL:
return netif_receive_skb(skb);
- case 1:
+ case GRO_DROP:
+ err = NET_RX_DROP;
+ /* fall through */
+
+ case GRO_MERGED_FREE:
kfree_skb(skb);
break;
}
- return NET_RX_SUCCESS;
+ return err;
+}
+EXPORT_SYMBOL(napi_skb_finish);
+
+int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
+{
+ skb_gro_reset_offset(skb);
+
+ return napi_skb_finish(__napi_gro_receive(napi, skb), skb);
}
EXPORT_SYMBOL(napi_gro_receive);
@@ -2515,6 +2532,9 @@ struct sk_buff *napi_fraginfo_skb(struct napi_struct *napi,
{
struct net_device *dev = napi->dev;
struct sk_buff *skb = napi->skb;
+ struct ethhdr *eth;
+ skb_frag_t *frag;
+ int i;
napi->skb = NULL;
@@ -2527,20 +2547,36 @@ struct sk_buff *napi_fraginfo_skb(struct napi_struct *napi,
}
BUG_ON(info->nr_frags > MAX_SKB_FRAGS);
+ frag = &info->frags[info->nr_frags - 1];
+
+ for (i = skb_shinfo(skb)->nr_frags; i < info->nr_frags; i++) {
+ skb_fill_page_desc(skb, i, frag->page, frag->page_offset,
+ frag->size);
+ frag++;
+ }
skb_shinfo(skb)->nr_frags = info->nr_frags;
- memcpy(skb_shinfo(skb)->frags, info->frags, sizeof(info->frags));
skb->data_len = info->len;
skb->len += info->len;
skb->truesize += info->len;
- if (!pskb_may_pull(skb, ETH_HLEN)) {
+ skb_reset_mac_header(skb);
+ skb_gro_reset_offset(skb);
+
+ eth = skb_gro_header(skb, sizeof(*eth));
+ if (!eth) {
napi_reuse_skb(napi, skb);
skb = NULL;
goto out;
}
- skb->protocol = eth_type_trans(skb, dev);
+ skb_gro_pull(skb, sizeof(*eth));
+
+ /*
+ * This works because the only protocols we care about don't require
+ * special handling. We'll fix it up properly at the end.
+ */
+ skb->protocol = eth->h_proto;
skb->ip_summed = info->ip_summed;
skb->csum = info->csum;
@@ -2550,29 +2586,47 @@ out:
}
EXPORT_SYMBOL(napi_fraginfo_skb);
-int napi_gro_frags(struct napi_struct *napi, struct napi_gro_fraginfo *info)
+int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret)
{
- struct sk_buff *skb = napi_fraginfo_skb(napi, info);
- int err = NET_RX_DROP;
+ int err = NET_RX_SUCCESS;
+ int may;
- if (!skb)
- goto out;
+ switch (ret) {
+ case GRO_NORMAL:
+ case GRO_HELD:
+ may = pskb_may_pull(skb, skb_gro_offset(skb));
+ BUG_ON(!may);
- err = NET_RX_SUCCESS;
+ skb->protocol = eth_type_trans(skb, napi->dev);
- switch (__napi_gro_receive(napi, skb)) {
- case -1:
- return netif_receive_skb(skb);
+ if (ret == GRO_NORMAL)
+ return netif_receive_skb(skb);
- case 0:
- goto out;
- }
+ skb_gro_pull(skb, -ETH_HLEN);
+ break;
- napi_reuse_skb(napi, skb);
+ case GRO_DROP:
+ err = NET_RX_DROP;
+ /* fall through */
+
+ case GRO_MERGED_FREE:
+ napi_reuse_skb(napi, skb);
+ break;
+ }
-out:
return err;
}
+EXPORT_SYMBOL(napi_frags_finish);
+
+int napi_gro_frags(struct napi_struct *napi, struct napi_gro_fraginfo *info)
+{
+ struct sk_buff *skb = napi_fraginfo_skb(napi, info);
+
+ if (!skb)
+ return NET_RX_DROP;
+
+ return napi_frags_finish(napi, skb, __napi_gro_receive(napi, skb));
+}
EXPORT_SYMBOL(napi_gro_frags);
static int process_backlog(struct napi_struct *napi, int quota)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index da74b844f4e..f20e758fe46 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2585,17 +2585,23 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
struct sk_buff *p = *head;
struct sk_buff *nskb;
unsigned int headroom;
- unsigned int hlen = p->data - skb_mac_header(p);
- unsigned int len = skb->len;
+ unsigned int len = skb_gro_len(skb);
- if (hlen + p->len + len >= 65536)
+ if (p->len + len >= 65536)
return -E2BIG;
if (skb_shinfo(p)->frag_list)
goto merge;
- else if (!skb_headlen(p) && !skb_headlen(skb) &&
- skb_shinfo(p)->nr_frags + skb_shinfo(skb)->nr_frags <
- MAX_SKB_FRAGS) {
+ else if (skb_headlen(skb) <= skb_gro_offset(skb)) {
+ if (skb_shinfo(p)->nr_frags + skb_shinfo(skb)->nr_frags >
+ MAX_SKB_FRAGS)
+ return -E2BIG;
+
+ skb_shinfo(skb)->frags[0].page_offset +=
+ skb_gro_offset(skb) - skb_headlen(skb);
+ skb_shinfo(skb)->frags[0].size -=
+ skb_gro_offset(skb) - skb_headlen(skb);
+
memcpy(skb_shinfo(p)->frags + skb_shinfo(p)->nr_frags,
skb_shinfo(skb)->frags,
skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t));
@@ -2612,7 +2618,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
}
headroom = skb_headroom(p);
- nskb = netdev_alloc_skb(p->dev, headroom);
+ nskb = netdev_alloc_skb(p->dev, headroom + skb_gro_offset(p));
if (unlikely(!nskb))
return -ENOMEM;
@@ -2620,12 +2626,15 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
nskb->mac_len = p->mac_len;
skb_reserve(nskb, headroom);
+ __skb_put(nskb, skb_gro_offset(p));
- skb_set_mac_header(nskb, -hlen);
+ skb_set_mac_header(nskb, skb_mac_header(p) - p->data);
skb_set_network_header(nskb, skb_network_offset(p));
skb_set_transport_header(nskb, skb_transport_offset(p));
- memcpy(skb_mac_header(nskb), skb_mac_header(p), hlen);
+ __skb_pull(p, skb_gro_offset(p));
+ memcpy(skb_mac_header(nskb), skb_mac_header(p),
+ p->data - skb_mac_header(p));
*NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p);
skb_shinfo(nskb)->frag_list = p;
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index f2230fc168e..08a569ff02d 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -42,9 +42,11 @@
extern int dccp_debug;
#define dccp_pr_debug(format, a...) DCCP_PR_DEBUG(dccp_debug, format, ##a)
#define dccp_pr_debug_cat(format, a...) DCCP_PRINTK(dccp_debug, format, ##a)
+#define dccp_debug(fmt, a...) dccp_pr_debug_cat(KERN_DEBUG fmt, ##a)
#else
#define dccp_pr_debug(format, a...)
#define dccp_pr_debug_cat(format, a...)
+#define dccp_debug(format, a...)
#endif
extern struct inet_hashinfo dccp_hashinfo;
@@ -95,9 +97,6 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
extern int sysctl_dccp_request_retries;
extern int sysctl_dccp_retries1;
extern int sysctl_dccp_retries2;
-extern int sysctl_dccp_feat_sequence_window;
-extern int sysctl_dccp_feat_rx_ccid;
-extern int sysctl_dccp_feat_tx_ccid;
extern int sysctl_dccp_tx_qlen;
extern int sysctl_dccp_sync_ratelimit;
@@ -409,23 +408,21 @@ static inline void dccp_hdr_set_ack(struct dccp_hdr_ack_bits *dhack,
static inline void dccp_update_gsr(struct sock *sk, u64 seq)
{
struct dccp_sock *dp = dccp_sk(sk);
- const struct dccp_minisock *dmsk = dccp_msk(sk);
dp->dccps_gsr = seq;
- dccp_set_seqno(&dp->dccps_swl,
- dp->dccps_gsr + 1 - (dmsk->dccpms_sequence_window / 4));
- dccp_set_seqno(&dp->dccps_swh,
- dp->dccps_gsr + (3 * dmsk->dccpms_sequence_window) / 4);
+ /* Sequence validity window depends on remote Sequence Window (7.5.1) */
+ dp->dccps_swl = SUB48(ADD48(dp->dccps_gsr, 1), dp->dccps_r_seq_win / 4);
+ dp->dccps_swh = ADD48(dp->dccps_gsr, (3 * dp->dccps_r_seq_win) / 4);
}
static inline void dccp_update_gss(struct sock *sk, u64 seq)
{
struct dccp_sock *dp = dccp_sk(sk);
- dp->dccps_awh = dp->dccps_gss = seq;
- dccp_set_seqno(&dp->dccps_awl,
- (dp->dccps_gss -
- dccp_msk(sk)->dccpms_sequence_window + 1));
+ dp->dccps_gss = seq;
+ /* Ack validity window depends on local Sequence Window value (7.5.1) */
+ dp->dccps_awl = SUB48(ADD48(dp->dccps_gss, 1), dp->dccps_l_seq_win);
+ dp->dccps_awh = dp->dccps_gss;
}
static inline int dccp_ack_pending(const struct sock *sk)
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index 4152308958a..b04160a2eea 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -25,6 +25,11 @@
#include "ccid.h"
#include "feat.h"
+/* feature-specific sysctls - initialised to the defaults from RFC 4340, 6.4 */
+unsigned long sysctl_dccp_sequence_window __read_mostly = 100;
+int sysctl_dccp_rx_ccid __read_mostly = 2,
+ sysctl_dccp_tx_ccid __read_mostly = 2;
+
/*
* Feature activation handlers.
*
@@ -51,8 +56,17 @@ static int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx)
static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx)
{
- if (!rx)
- dccp_msk(sk)->dccpms_sequence_window = seq_win;
+ struct dccp_sock *dp = dccp_sk(sk);
+
+ if (rx) {
+ dp->dccps_r_seq_win = seq_win;
+ /* propagate changes to update SWL/SWH */
+ dccp_update_gsr(sk, dp->dccps_gsr);
+ } else {
+ dp->dccps_l_seq_win = seq_win;
+ /* propagate changes to update AWL */
+ dccp_update_gss(sk, dp->dccps_gss);
+ }
return 0;
}
@@ -194,6 +208,100 @@ static int dccp_feat_default_value(u8 feat_num)
return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
}
+/*
+ * Debugging and verbose-printing section
+ */
+static const char *dccp_feat_fname(const u8 feat)
+{
+ static const char *feature_names[] = {
+ [DCCPF_RESERVED] = "Reserved",
+ [DCCPF_CCID] = "CCID",
+ [DCCPF_SHORT_SEQNOS] = "Allow Short Seqnos",
+ [DCCPF_SEQUENCE_WINDOW] = "Sequence Window",
+ [DCCPF_ECN_INCAPABLE] = "ECN Incapable",
+ [DCCPF_ACK_RATIO] = "Ack Ratio",
+ [DCCPF_SEND_ACK_VECTOR] = "Send ACK Vector",
+ [DCCPF_SEND_NDP_COUNT] = "Send NDP Count",
+ [DCCPF_MIN_CSUM_COVER] = "Min. Csum Coverage",
+ [DCCPF_DATA_CHECKSUM] = "Send Data Checksum",
+ };
+ if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
+ return feature_names[DCCPF_RESERVED];
+
+ if (feat == DCCPF_SEND_LEV_RATE)
+ return "Send Loss Event Rate";
+ if (feat >= DCCPF_MIN_CCID_SPECIFIC)
+ return "CCID-specific";
+
+ return feature_names[feat];
+}
+
+static const char *dccp_feat_sname[] = { "DEFAULT", "INITIALISING", "CHANGING",
+ "UNSTABLE", "STABLE" };
+
+#ifdef CONFIG_IP_DCCP_DEBUG
+static const char *dccp_feat_oname(const u8 opt)
+{
+ switch (opt) {
+ case DCCPO_CHANGE_L: return "Change_L";
+ case DCCPO_CONFIRM_L: return "Confirm_L";
+ case DCCPO_CHANGE_R: return "Change_R";
+ case DCCPO_CONFIRM_R: return "Confirm_R";
+ }
+ return NULL;
+}
+
+static void dccp_feat_printval(u8 feat_num, dccp_feat_val const *val)
+{
+ u8 i, type = dccp_feat_type(feat_num);
+
+ if (val == NULL || (type == FEAT_SP && val->sp.vec == NULL))
+ dccp_pr_debug_cat("(NULL)");
+ else if (type == FEAT_SP)
+ for (i = 0; i < val->sp.len; i++)
+ dccp_pr_debug_cat("%s%u", i ? " " : "", val->sp.vec[i]);
+ else if (type == FEAT_NN)
+ dccp_pr_debug_cat("%llu", (unsigned long long)val->nn);
+ else
+ dccp_pr_debug_cat("unknown type %u", type);
+}
+
+static void dccp_feat_printvals(u8 feat_num, u8 *list, u8 len)
+{
+ u8 type = dccp_feat_type(feat_num);
+ dccp_feat_val fval = { .sp.vec = list, .sp.len = len };
+
+ if (type == FEAT_NN)
+ fval.nn = dccp_decode_value_var(list, len);
+ dccp_feat_printval(feat_num, &fval);
+}
+
+static void dccp_feat_print_entry(struct dccp_feat_entry const *entry)
+{
+ dccp_debug(" * %s %s = ", entry->is_local ? "local" : "remote",
+ dccp_feat_fname(entry->feat_num));
+ dccp_feat_printval(entry->feat_num, &entry->val);
+ dccp_pr_debug_cat(", state=%s %s\n", dccp_feat_sname[entry->state],
+ entry->needs_confirm ? "(Confirm pending)" : "");
+}
+
+#define dccp_feat_print_opt(opt, feat, val, len, mandatory) do { \
+ dccp_pr_debug("%s(%s, ", dccp_feat_oname(opt), dccp_feat_fname(feat));\
+ dccp_feat_printvals(feat, val, len); \
+ dccp_pr_debug_cat(") %s\n", mandatory ? "!" : ""); } while (0)
+
+#define dccp_feat_print_fnlist(fn_list) { \
+ const struct dccp_feat_entry *___entry; \
+ \
+ dccp_pr_debug("List Dump:\n"); \
+ list_for_each_entry(___entry, fn_list, node) \
+ dccp_feat_print_entry(___entry); \
+}
+#else /* ! CONFIG_IP_DCCP_DEBUG */
+#define dccp_feat_print_opt(opt, feat, val, len, mandatory)
+#define dccp_feat_print_fnlist(fn_list)
+#endif
+
static int __dccp_feat_activate(struct sock *sk, const int idx,
const bool is_local, dccp_feat_val const *fval)
{
@@ -226,6 +334,10 @@ static int __dccp_feat_activate(struct sock *sk, const int idx,
/* Location is RX if this is a local-RX or remote-TX feature */
rx = (is_local == (dccp_feat_table[idx].rxtx == FEAT_AT_RX));
+ dccp_debug(" -> activating %s %s, %sval=%llu\n", rx ? "RX" : "TX",
+ dccp_feat_fname(dccp_feat_table[idx].feat_num),
+ fval ? "" : "default ", (unsigned long long)val);
+
return dccp_feat_table[idx].activation_hdlr(sk, val, rx);
}
@@ -530,6 +642,7 @@ int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq,
return -1;
}
}
+ dccp_feat_print_opt(opt, pos->feat_num, ptr, len, 0);
if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt))
return -1;
@@ -783,6 +896,7 @@ int dccp_feat_finalise_settings(struct dccp_sock *dp)
while (i--)
if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
return -1;
+ dccp_feat_print_fnlist(fn);
return 0;
}
@@ -901,6 +1015,8 @@ static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
if (len == 0 || type == FEAT_UNKNOWN) /* 6.1 and 6.6.8 */
goto unknown_feature_or_value;
+ dccp_feat_print_opt(opt, feat, val, len, is_mandatory);
+
/*
* Negotiation of NN features: Change R is invalid, so there is no
* simultaneous negotiation; hence we do not look up in the list.
@@ -1006,6 +1122,8 @@ static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
const bool local = (opt == DCCPO_CONFIRM_R);
struct dccp_feat_entry *entry = dccp_feat_list_lookup(fn, feat, local);
+ dccp_feat_print_opt(opt, feat, val, len, is_mandatory);
+
if (entry == NULL) { /* nothing queued: ignore or handle error */
if (is_mandatory && type == FEAT_UNKNOWN)
return DCCP_RESET_CODE_MANDATORY_ERROR;
@@ -1115,23 +1233,70 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
return 0; /* ignore FN options in all other states */
}
+/**
+ * dccp_feat_init - Seed feature negotiation with host-specific defaults
+ * This initialises global defaults, depending on the value of the sysctls.
+ * These can later be overridden by registering changes via setsockopt calls.
+ * The last link in the chain is finalise_settings, to make sure that between
+ * here and the start of actual feature negotiation no inconsistencies enter.
+ *
+ * All features not appearing below use either defaults or are otherwise
+ * later adjusted through dccp_feat_finalise_settings().
+ */
int dccp_feat_init(struct sock *sk)
{
- struct dccp_sock *dp = dccp_sk(sk);
- struct dccp_minisock *dmsk = dccp_msk(sk);
+ struct list_head *fn = &dccp_sk(sk)->dccps_featneg;
+ u8 on = 1, off = 0;
int rc;
+ struct {
+ u8 *val;
+ u8 len;
+ } tx, rx;
+
+ /* Non-negotiable (NN) features */
+ rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0,
+ sysctl_dccp_sequence_window);
+ if (rc)
+ return rc;
+
+ /* Server-priority (SP) features */
+
+ /* Advertise that short seqnos are not supported (7.6.1) */
+ rc = __feat_register_sp(fn, DCCPF_SHORT_SEQNOS, true, true, &off, 1);
+ if (rc)
+ return rc;
- INIT_LIST_HEAD(&dmsk->dccpms_pending); /* XXX no longer used */
- INIT_LIST_HEAD(&dmsk->dccpms_conf); /* XXX no longer used */
+ /* RFC 4340 12.1: "If a DCCP is not ECN capable, ..." */
+ rc = __feat_register_sp(fn, DCCPF_ECN_INCAPABLE, true, true, &on, 1);
+ if (rc)
+ return rc;
+
+ /*
+ * We advertise the available list of CCIDs and reorder according to
+ * preferences, to avoid failure resulting from negotiating different
+ * singleton values (which always leads to failure).
+ * These settings can still (later) be overridden via sockopts.
+ */
+ if (ccid_get_builtin_ccids(&tx.val, &tx.len) ||
+ ccid_get_builtin_ccids(&rx.val, &rx.len))
+ return -ENOBUFS;
+
+ if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) ||
+ !dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len))
+ goto free_ccid_lists;
+
+ rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len);
+ if (rc)
+ goto free_ccid_lists;
+
+ rc = __feat_register_sp(fn, DCCPF_CCID, false, false, rx.val, rx.len);
- /* Ack ratio */
- rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
- dp->dccps_l_ack_ratio);
+free_ccid_lists:
+ kfree(tx.val);
+ kfree(rx.val);
return rc;
}
-EXPORT_SYMBOL_GPL(dccp_feat_init);
-
int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
{
struct dccp_sock *dp = dccp_sk(sk);
@@ -1156,9 +1321,10 @@ int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
goto activation_failed;
}
if (cur->state != FEAT_STABLE) {
- DCCP_CRIT("Negotiation of %s %u failed in state %u",
+ DCCP_CRIT("Negotiation of %s %s failed in state %s",
cur->is_local ? "local" : "remote",
- cur->feat_num, cur->state);
+ dccp_feat_fname(cur->feat_num),
+ dccp_feat_sname[cur->state]);
goto activation_failed;
}
fvals[idx][cur->is_local] = &cur->val;
@@ -1199,43 +1365,3 @@ activation_failed:
dp->dccps_hc_rx_ackvec = NULL;
return -1;
}
-
-#ifdef CONFIG_IP_DCCP_DEBUG
-const char *dccp_feat_typename(const u8 type)
-{
- switch(type) {
- case DCCPO_CHANGE_L: return("ChangeL");
- case DCCPO_CONFIRM_L: return("ConfirmL");
- case DCCPO_CHANGE_R: return("ChangeR");
- case DCCPO_CONFIRM_R: return("ConfirmR");
- /* the following case must not appear in feature negotation */
- default: dccp_pr_debug("unknown type %d [BUG!]\n", type);
- }
- return NULL;
-}
-
-const char *dccp_feat_name(const u8 feat)
-{
- static const char *feature_names[] = {
- [DCCPF_RESERVED] = "Reserved",
- [DCCPF_CCID] = "CCID",
- [DCCPF_SHORT_SEQNOS] = "Allow Short Seqnos",
- [DCCPF_SEQUENCE_WINDOW] = "Sequence Window",
- [DCCPF_ECN_INCAPABLE] = "ECN Incapable",
- [DCCPF_ACK_RATIO] = "Ack Ratio",
- [DCCPF_SEND_ACK_VECTOR] = "Send ACK Vector",
- [DCCPF_SEND_NDP_COUNT] = "Send NDP Count",
- [DCCPF_MIN_CSUM_COVER] = "Min. Csum Coverage",
- [DCCPF_DATA_CHECKSUM] = "Send Data Checksum",
- };
- if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
- return feature_names[DCCPF_RESERVED];
-
- if (feat == DCCPF_SEND_LEV_RATE)
- return "Send Loss Event Rate";
- if (feat >= DCCPF_MIN_CCID_SPECIFIC)
- return "CCID-specific";
-
- return feature_names[feat];
-}
-#endif /* CONFIG_IP_DCCP_DEBUG */
diff --git a/net/dccp/feat.h b/net/dccp/feat.h
index 9b46e2a7866..f96721619de 100644
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -100,26 +100,21 @@ struct ccid_dependency {
u8 val;
};
-#ifdef CONFIG_IP_DCCP_DEBUG
-extern const char *dccp_feat_typename(const u8 type);
-extern const char *dccp_feat_name(const u8 feat);
-
-static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
-{
- dccp_pr_debug("%s(%s (%d), %d)\n", dccp_feat_typename(type),
- dccp_feat_name(feat), feat, val);
-}
-#else
-#define dccp_feat_debug(type, feat, val)
-#endif /* CONFIG_IP_DCCP_DEBUG */
+/*
+ * Sysctls to seed defaults for feature negotiation
+ */
+extern unsigned long sysctl_dccp_sequence_window;
+extern int sysctl_dccp_rx_ccid;
+extern int sysctl_dccp_tx_ccid;
+extern int dccp_feat_init(struct sock *sk);
+extern void dccp_feat_initialise_sysctls(void);
extern int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
u8 const *list, u8 len);
extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
extern int dccp_feat_clone_list(struct list_head const *, struct list_head *);
-extern int dccp_feat_init(struct sock *sk);
/*
* Encoding variable-length options and their maximum length.
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c
index 6821ae33dd3..5ca49cec95f 100644
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -42,11 +42,6 @@ struct inet_timewait_death_row dccp_death_row = {
EXPORT_SYMBOL_GPL(dccp_death_row);
-void dccp_minisock_init(struct dccp_minisock *dmsk)
-{
- dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
-}
-
void dccp_time_wait(struct sock *sk, int state, int timeo)
{
struct inet_timewait_sock *tw = NULL;
@@ -110,7 +105,6 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
struct dccp_request_sock *dreq = dccp_rsk(req);
struct inet_connection_sock *newicsk = inet_csk(newsk);
struct dccp_sock *newdp = dccp_sk(newsk);
- struct dccp_minisock *newdmsk = dccp_msk(newsk);
newdp->dccps_role = DCCP_ROLE_SERVER;
newdp->dccps_hc_rx_ackvec = NULL;
@@ -128,10 +122,6 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
* Initialize S.GAR := S.ISS
* Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
*/
-
- /* See dccp_v4_conn_request */
- newdmsk->dccpms_sequence_window = req->rcv_wnd;
-
newdp->dccps_gar = newdp->dccps_iss = dreq->dreq_iss;
dccp_update_gss(newsk, dreq->dreq_iss);
@@ -290,7 +280,6 @@ int dccp_reqsk_init(struct request_sock *req,
inet_rsk(req)->rmt_port = dccp_hdr(skb)->dccph_sport;
inet_rsk(req)->loc_port = dccp_hdr(skb)->dccph_dport;
inet_rsk(req)->acked = 0;
- req->rcv_wnd = sysctl_dccp_feat_sequence_window;
dreq->dreq_timestamp_echo = 0;
/* inherit feature negotiation options from listening socket */
diff --git a/net/dccp/options.c b/net/dccp/options.c
index 7b1165c21f5..1b08cae9c65 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -23,10 +23,6 @@
#include "dccp.h"
#include "feat.h"
-int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
-int sysctl_dccp_feat_rx_ccid = DCCPF_INITIAL_CCID;
-int sysctl_dccp_feat_tx_ccid = DCCPF_INITIAL_CCID;
-
u64 dccp_decode_value_var(const u8 *bf, const u8 len)
{
u64 value = 0;
@@ -502,10 +498,6 @@ int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
*to++ = *val;
if (len)
memcpy(to, val, len);
-
- dccp_pr_debug("%s(%s (%d), ...), length %d\n",
- dccp_feat_typename(type),
- dccp_feat_name(feat), feat, len);
return 0;
}
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 945b4d5d23b..314a1b5c033 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -174,8 +174,6 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
struct dccp_sock *dp = dccp_sk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
- dccp_minisock_init(&dp->dccps_minisock);
-
icsk->icsk_rto = DCCP_TIMEOUT_INIT;
icsk->icsk_syn_retries = sysctl_dccp_request_retries;
sk->sk_state = DCCP_CLOSED;
diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c
index 018e210875e..a5a1856234e 100644
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -18,55 +18,72 @@
#error This file should not be compiled without CONFIG_SYSCTL defined
#endif
+/* Boundary values */
+static int zero = 0,
+ u8_max = 0xFF;
+static unsigned long seqw_min = 32;
+
static struct ctl_table dccp_default_table[] = {
{
.procname = "seq_window",
- .data = &sysctl_dccp_feat_sequence_window,
- .maxlen = sizeof(sysctl_dccp_feat_sequence_window),
+ .data = &sysctl_dccp_sequence_window,
+ .maxlen = sizeof(sysctl_dccp_sequence_window),
.mode = 0644,
- .proc_handler = proc_dointvec,
+ .proc_handler = proc_doulongvec_minmax,
+ .extra1 = &seqw_min, /* RFC 4340, 7.5.2 */
},
{
.procname = "rx_ccid",
- .data = &sysctl_dccp_feat_rx_ccid,
- .maxlen = sizeof(sysctl_dccp_feat_rx_ccid),
+ .data = &sysctl_dccp_rx_ccid,
+ .maxlen = sizeof(sysctl_dccp_rx_ccid),
.mode = 0644,
- .proc_handler = proc_dointvec,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &u8_max, /* RFC 4340, 10. */
},
{
.procname = "tx_ccid",
- .data = &sysctl_dccp_feat_tx_ccid,
- .maxlen = sizeof(sysctl_dccp_feat_tx_ccid),
+ .data = &sysctl_dccp_tx_ccid,
+ .maxlen = sizeof(sysctl_dccp_tx_ccid),
.mode = 0644,
- .proc_handler = proc_dointvec,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &u8_max, /* RFC 4340, 10. */
},
{
.procname = "request_retries",
.data = &sysctl_dccp_request_retries,
.maxlen = sizeof(sysctl_dccp_request_retries),
.mode = 0644,
- .proc_handler = proc_dointvec,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &u8_max,
},
{
.procname = "retries1",
.data = &sysctl_dccp_retries1,
.maxlen = sizeof(sysctl_dccp_retries1),
.mode = 0644,
- .proc_handler = proc_dointvec,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &u8_max,
},
{
.procname = "retries2",
.data = &sysctl_dccp_retries2,
.maxlen = sizeof(sysctl_dccp_retries2),
.mode = 0644,
- .proc_handler = proc_dointvec,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &u8_max,
},
{
.procname = "tx_qlen",
.data = &sysctl_dccp_tx_qlen,
.maxlen = sizeof(sysctl_dccp_tx_qlen),
.mode = 0644,
- .proc_handler = proc_dointvec,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
},
{
.procname = "sync_ratelimit",
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 743f5542d65..d6770f295d5 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1253,10 +1253,10 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
int proto;
int id;
- if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
+ iph = skb_gro_header(skb, sizeof(*iph));
+ if (unlikely(!iph))
goto out;
- iph = ip_hdr(skb);
proto = iph->protocol & (MAX_INET_PROTOS - 1);
rcu_read_lock();
@@ -1270,7 +1270,7 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
goto out_unlock;
- flush = ntohs(iph->tot_len) != skb->len ||
+ flush = ntohs(iph->tot_len) != skb_gro_len(skb) ||
iph->frag_off != htons(IP_DF);
id = ntohs(iph->id);
@@ -1298,8 +1298,8 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
}
NAPI_GRO_CB(skb)->flush |= flush;
- __skb_pull(skb, sizeof(*iph));
- skb_reset_transport_header(skb);
+ skb_gro_pull(skb, sizeof(*iph));
+ skb_set_transport_header(skb, skb_gro_offset(skb));
pp = ops->gro_receive(head, skb);
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index f26ab38680d..df8e72f0747 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -93,24 +93,40 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
struct inet_bind_hashbucket *head;
struct hlist_node *node;
struct inet_bind_bucket *tb;
- int ret;
+ int ret, attempts = 5;
struct net *net = sock_net(sk);
+ int smallest_size = -1, smallest_rover;
local_bh_disable();
if (!snum) {
int remaining, rover, low, high;
+again:
inet_get_local_port_range(&low, &high);
remaining = (high - low) + 1;
- rover = net_random() % remaining + low;
+ smallest_rover = rover = net_random() % remaining + low;
+ smallest_size = -1;
do {
head = &hashinfo->bhash[inet_bhashfn(net, rover,
hashinfo->bhash_size)];
spin_lock(&head->lock);
inet_bind_bucket_for_each(tb, node, &head->chain)
- if (ib_net(tb) == net && tb->port == rover)
+ if (ib_net(tb) == net && tb->port == rover) {
+ if (tb->fastreuse > 0 &&
+ sk->sk_reuse &&
+ sk->sk_state != TCP_LISTEN &&
+ (tb->num_owners < smallest_size || smallest_size == -1)) {
+ smallest_size = tb->num_owners;
+ smallest_rover = rover;
+ if (hashinfo->bsockets > (high - low) + 1) {
+ spin_unlock(&head->lock);
+ snum = smallest_rover;
+ goto have_snum;
+ }
+ }
goto next;
+ }
break;
next:
spin_unlock(&head->lock);
@@ -125,14 +141,19 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
* the top level, not from the 'break;' statement.
*/
ret = 1;
- if (remaining <= 0)
+ if (remaining <= 0) {
+ if (smallest_size != -1) {
+ snum = smallest_rover;
+ goto have_snum;
+ }
goto fail;
-
+ }
/* OK, here is the one we will use. HEAD is
* non-NULL and we hold it's mutex.
*/
snum = rover;
} else {
+have_snum:
head = &hashinfo->bhash[inet_bhashfn(net, snum,
hashinfo->bhash_size)];
spin_lock(&head->lock);
@@ -145,12 +166,18 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
tb_found:
if (!hlist_empty(&tb->owners)) {
if (tb->fastreuse > 0 &&
- sk->sk_reuse && sk->sk_state != TCP_LISTEN) {
+ sk->sk_reuse && sk->sk_state != TCP_LISTEN &&
+ smallest_size == -1) {
goto success;
} else {
ret = 1;
- if (inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb))
+ if (inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb)) {
+ if (sk->sk_reuse && sk->sk_state != TCP_LISTEN && --attempts >= 0) {
+ spin_unlock(&head->lock);
+ goto again;
+ }
goto fail_unlock;
+ }
}
}
tb_not_found:
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 6a1045da48d..d7b6178bf48 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -38,6 +38,7 @@ struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep,
write_pnet(&tb->ib_net, hold_net(net));
tb->port = snum;
tb->fastreuse = 0;
+ tb->num_owners = 0;
INIT_HLIST_HEAD(&tb->owners);
hlist_add_head(&tb->node, &head->chain);
}
@@ -59,8 +60,13 @@ void inet_bind_bucket_destroy(struct kmem_cache *cachep, struct inet_bind_bucket
void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb,
const unsigned short snum)
{
+ struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
+
+ hashinfo->bsockets++;
+
inet_sk(sk)->num = snum;
sk_add_bind_node(sk, &tb->owners);
+ tb->num_owners++;
inet_csk(sk)->icsk_bind_hash = tb;
}
@@ -75,9 +81,12 @@ static void __inet_put_port(struct sock *sk)
struct inet_bind_hashbucket *head = &hashinfo->bhash[bhash];
struct inet_bind_bucket *tb;
+ hashinfo->bsockets--;
+
spin_lock(&head->lock);
tb = inet_csk(sk)->icsk_bind_hash;
__sk_del_bind_node(sk);
+ tb->num_owners--;
inet_csk(sk)->icsk_bind_hash = NULL;
inet_sk(sk)->num = 0;
inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
@@ -444,9 +453,9 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
*/
inet_bind_bucket_for_each(tb, node, &head->chain) {
if (ib_net(tb) == net && tb->port == port) {
- WARN_ON(hlist_empty(&tb->owners));
if (tb->fastreuse >= 0)
goto next_port;
+ WARN_ON(hlist_empty(&tb->owners));
if (!check_established(death_row, sk,
port, &tw))
goto ok;
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 0101521f366..07a188afb3a 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -164,67 +164,124 @@ static DEFINE_RWLOCK(ipgre_lock);
/* Given src, dst and key, find appropriate for input tunnel. */
-static struct ip_tunnel * ipgre_tunnel_lookup(struct net *net,
+static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
__be32 remote, __be32 local,
__be32 key, __be16 gre_proto)
{
+ struct net *net = dev_net(dev);
+ int link = dev->ifindex;
unsigned h0 = HASH(remote);
unsigned h1 = HASH(key);
- struct ip_tunnel *t;
- struct ip_tunnel *t2 = NULL;
+ struct ip_tunnel *t, *cand = NULL;
struct ipgre_net *ign = net_generic(net, ipgre_net_id);
int dev_type = (gre_proto == htons(ETH_P_TEB)) ?
ARPHRD_ETHER : ARPHRD_IPGRE;
+ int score, cand_score = 4;
for (t = ign->tunnels_r_l[h0^h1]; t; t = t->next) {
- if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) {
- if (t->parms.i_key == key && t->dev->flags & IFF_UP) {
- if (t->dev->type == dev_type)
- return t;
- if (t->dev->type == ARPHRD_IPGRE && !t2)
- t2 = t;
- }
+ if (local != t->parms.iph.saddr ||
+ remote != t->parms.iph.daddr ||
+ key != t->parms.i_key ||
+ !(t->dev->flags & IFF_UP))
+ continue;
+
+ if (t->dev->type != ARPHRD_IPGRE &&
+ t->dev->type != dev_type)
+ continue;
+
+ score = 0;
+ if (t->parms.link != link)
+ score |= 1;
+ if (t->dev->type != dev_type)
+ score |= 2;
+ if (score == 0)
+ return t;
+
+ if (score < cand_score) {
+ cand = t;
+ cand_score = score;
}
}
for (t = ign->tunnels_r[h0^h1]; t; t = t->next) {
- if (remote == t->parms.iph.daddr) {
- if (t->parms.i_key == key && t->dev->flags & IFF_UP) {
- if (t->dev->type == dev_type)
- return t;
- if (t->dev->type == ARPHRD_IPGRE && !t2)
- t2 = t;
- }
+ if (remote != t->parms.iph.daddr ||
+ key != t->parms.i_key ||
+ !(t->dev->flags & IFF_UP))
+ continue;
+
+ if (t->dev->type != ARPHRD_IPGRE &&
+ t->dev->type != dev_type)
+ continue;
+
+ score = 0;
+ if (t->parms.link != link)
+ score |= 1;
+ if (t->dev->type != dev_type)
+ score |= 2;
+ if (score == 0)
+ return t;
+
+ if (score < cand_score) {
+ cand = t;
+ cand_score = score;
}
}
for (t = ign->tunnels_l[h1]; t; t = t->next) {
- if (local == t->parms.iph.saddr ||
- (local == t->parms.iph.daddr &&
- ipv4_is_multicast(local))) {
- if (t->parms.i_key == key && t->dev->flags & IFF_UP) {
- if (t->dev->type == dev_type)
- return t;
- if (t->dev->type == ARPHRD_IPGRE && !t2)
- t2 = t;
- }
+ if ((local != t->parms.iph.saddr &&
+ (local != t->parms.iph.daddr ||
+ !ipv4_is_multicast(local))) ||
+ key != t->parms.i_key ||
+ !(t->dev->flags & IFF_UP))
+ continue;
+
+ if (t->dev->type != ARPHRD_IPGRE &&
+ t->dev->type != dev_type)
+ continue;
+
+ score = 0;
+ if (t->parms.link != link)
+ score |= 1;
+ if (t->dev->type != dev_type)
+ score |= 2;
+ if (score == 0)
+ return t;
+
+ if (score < cand_score) {
+ cand = t;
+ cand_score = score;
}
}
for (t = ign->tunnels_wc[h1]; t; t = t->next) {
- if (t->parms.i_key == key && t->dev->flags & IFF_UP) {
- if (t->dev->type == dev_type)
- return t;
- if (t->dev->type == ARPHRD_IPGRE && !t2)
- t2 = t;
+ if (t->parms.i_key != key ||
+ !(t->dev->flags & IFF_UP))
+ continue;
+
+ if (t->dev->type != ARPHRD_IPGRE &&
+ t->dev->type != dev_type)
+ continue;
+
+ score = 0;
+ if (t->parms.link != link)
+ score |= 1;
+ if (t->dev->type != dev_type)
+ score |= 2;
+ if (score == 0)
+ return t;
+
+ if (score < cand_score) {
+ cand = t;
+ cand_score = score;
}
}
- if (t2)
- return t2;
+ if (cand != NULL)
+ return cand;
- if (ign->fb_tunnel_dev->flags&IFF_UP)
+ if (ign->fb_tunnel_dev->flags & IFF_UP)
return netdev_priv(ign->fb_tunnel_dev);
+
return NULL;
}
@@ -284,6 +341,7 @@ static struct ip_tunnel *ipgre_tunnel_find(struct net *net,
__be32 remote = parms->iph.daddr;
__be32 local = parms->iph.saddr;
__be32 key = parms->i_key;
+ int link = parms->link;
struct ip_tunnel *t, **tp;
struct ipgre_net *ign = net_generic(net, ipgre_net_id);
@@ -291,6 +349,7 @@ static struct ip_tunnel *ipgre_tunnel_find(struct net *net,
if (local == t->parms.iph.saddr &&
remote == t->parms.iph.daddr &&
key == t->parms.i_key &&
+ link == t->parms.link &&
type == t->dev->type)
break;
@@ -421,7 +480,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
}
read_lock(&ipgre_lock);
- t = ipgre_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr,
+ t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr,
flags & GRE_KEY ?
*(((__be32 *)p) + (grehlen / 4) - 1) : 0,
p[1]);
@@ -518,7 +577,7 @@ static int ipgre_rcv(struct sk_buff *skb)
gre_proto = *(__be16 *)(h + 2);
read_lock(&ipgre_lock);
- if ((tunnel = ipgre_tunnel_lookup(dev_net(skb->dev),
+ if ((tunnel = ipgre_tunnel_lookup(skb->dev,
iph->saddr, iph->daddr, key,
gre_proto))) {
struct net_device_stats *stats = &tunnel->dev->stats;
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 14666449dc1..21a6dc710f2 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -67,9 +67,6 @@
#define CONFIG_IP_PIMSM 1
#endif
-static struct sock *mroute_socket;
-
-
/* Big lock, protecting vif table, mrt cache and mroute socket state.
Note that the changes are semaphored via rtnl_lock.
*/
@@ -80,18 +77,9 @@ static DEFINE_RWLOCK(mrt_lock);
* Multicast router control variables
*/
-static struct vif_device vif_table[MAXVIFS]; /* Devices */
-static int maxvif;
-
-#define VIF_EXISTS(idx) (vif_table[idx].dev != NULL)
-
-static int mroute_do_assert; /* Set in PIM assert */
-static int mroute_do_pim;
-
-static struct mfc_cache *mfc_cache_array[MFC_LINES]; /* Forwarding cache */
+#define VIF_EXISTS(_net, _idx) ((_net)->ipv4.vif_table[_idx].dev != NULL)
static struct mfc_cache *mfc_unres_queue; /* Queue of unresolved entries */
-static atomic_t cache_resolve_queue_len; /* Size of unresolved */
/* Special spinlock for queue of unresolved entries */
static DEFINE_SPINLOCK(mfc_unres_lock);
@@ -107,7 +95,8 @@ static DEFINE_SPINLOCK(mfc_unres_lock);
static struct kmem_cache *mrt_cachep __read_mostly;
static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local);
-static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert);
+static int ipmr_cache_report(struct net *net,
+ struct sk_buff *pkt, vifi_t vifi, int assert);
static int ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm);
#ifdef CONFIG_IP_PIMSM_V2
@@ -120,9 +109,11 @@ static struct timer_list ipmr_expire_timer;
static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
{
+ struct net *net = dev_net(dev);
+
dev_close(dev);
- dev = __dev_get_by_name(&init_net, "tunl0");
+ dev = __dev_get_by_name(net, "tunl0");
if (dev) {
const struct net_device_ops *ops = dev->netdev_ops;
struct ifreq ifr;
@@ -148,11 +139,11 @@ static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
}
static
-struct net_device *ipmr_new_tunnel(struct vifctl *v)
+struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
{
struct net_device *dev;
- dev = __dev_get_by_name(&init_net, "tunl0");
+ dev = __dev_get_by_name(net, "tunl0");
if (dev) {
const struct net_device_ops *ops = dev->netdev_ops;
@@ -181,7 +172,8 @@ struct net_device *ipmr_new_tunnel(struct vifctl *v)
dev = NULL;
- if (err == 0 && (dev = __dev_get_by_name(&init_net, p.name)) != NULL) {
+ if (err == 0 &&
+ (dev = __dev_get_by_name(net, p.name)) != NULL) {
dev->flags |= IFF_MULTICAST;
in_dev = __in_dev_get_rtnl(dev);
@@ -209,14 +201,15 @@ failure:
#ifdef CONFIG_IP_PIMSM
-static int reg_vif_num = -1;
-
static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
{
+ struct net *net = dev_net(dev);
+
read_lock(&mrt_lock);
dev->stats.tx_bytes += skb->len;
dev->stats.tx_packets++;
- ipmr_cache_report(skb, reg_vif_num, IGMPMSG_WHOLEPKT);
+ ipmr_cache_report(net, skb, net->ipv4.mroute_reg_vif_num,
+ IGMPMSG_WHOLEPKT);
read_unlock(&mrt_lock);
kfree_skb(skb);
return 0;
@@ -283,16 +276,16 @@ failure:
* @notify: Set to 1, if the caller is a notifier_call
*/
-static int vif_delete(int vifi, int notify)
+static int vif_delete(struct net *net, int vifi, int notify)
{
struct vif_device *v;
struct net_device *dev;
struct in_device *in_dev;
- if (vifi < 0 || vifi >= maxvif)
+ if (vifi < 0 || vifi >= net->ipv4.maxvif)
return -EADDRNOTAVAIL;
- v = &vif_table[vifi];
+ v = &net->ipv4.vif_table[vifi];
write_lock_bh(&mrt_lock);
dev = v->dev;
@@ -304,17 +297,17 @@ static int vif_delete(int vifi, int notify)
}
#ifdef CONFIG_IP_PIMSM
- if (vifi == reg_vif_num)
- reg_vif_num = -1;
+ if (vifi == net->ipv4.mroute_reg_vif_num)
+ net->ipv4.mroute_reg_vif_num = -1;
#endif
- if (vifi+1 == maxvif) {
+ if (vifi+1 == net->ipv4.maxvif) {
int tmp;
for (tmp=vifi-1; tmp>=0; tmp--) {
- if (VIF_EXISTS(tmp))
+ if (VIF_EXISTS(net, tmp))
break;
}
- maxvif = tmp+1;
+ net->ipv4.maxvif = tmp+1;
}
write_unlock_bh(&mrt_lock);
@@ -333,6 +326,12 @@ static int vif_delete(int vifi, int notify)
return 0;
}
+static inline void ipmr_cache_free(struct mfc_cache *c)
+{
+ release_net(mfc_net(c));
+ kmem_cache_free(mrt_cachep, c);
+}
+
/* Destroy an unresolved cache entry, killing queued skbs
and reporting error to netlink readers.
*/
@@ -341,8 +340,9 @@ static void ipmr_destroy_unres(struct mfc_cache *c)
{
struct sk_buff *skb;
struct nlmsgerr *e;
+ struct net *net = mfc_net(c);
- atomic_dec(&cache_resolve_queue_len);
+ atomic_dec(&net->ipv4.cache_resolve_queue_len);
while ((skb = skb_dequeue(&c->mfc_un.unres.unresolved))) {
if (ip_hdr(skb)->version == 0) {
@@ -354,12 +354,12 @@ static void ipmr_destroy_unres(struct mfc_cache *c)
e->error = -ETIMEDOUT;
memset(&e->msg, 0, sizeof(e->msg));
- rtnl_unicast(skb, &init_net, NETLINK_CB(skb).pid);
+ rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
} else
kfree_skb(skb);
}
- kmem_cache_free(mrt_cachep, c);
+ ipmr_cache_free(c);
}
@@ -376,7 +376,7 @@ static void ipmr_expire_process(unsigned long dummy)
return;
}
- if (atomic_read(&cache_resolve_queue_len) == 0)
+ if (mfc_unres_queue == NULL)
goto out;
now = jiffies;
@@ -397,7 +397,7 @@ static void ipmr_expire_process(unsigned long dummy)
ipmr_destroy_unres(c);
}
- if (atomic_read(&cache_resolve_queue_len))
+ if (mfc_unres_queue != NULL)
mod_timer(&ipmr_expire_timer, jiffies + expires);
out:
@@ -409,13 +409,15 @@ out:
static void ipmr_update_thresholds(struct mfc_cache *cache, unsigned char *ttls)
{
int vifi;
+ struct net *net = mfc_net(cache);
cache->mfc_un.res.minvif = MAXVIFS;
cache->mfc_un.res.maxvif = 0;
memset(cache->mfc_un.res.ttls, 255, MAXVIFS);
- for (vifi=0; vifi<maxvif; vifi++) {
- if (VIF_EXISTS(vifi) && ttls[vifi] && ttls[vifi] < 255) {
+ for (vifi = 0; vifi < net->ipv4.maxvif; vifi++) {
+ if (VIF_EXISTS(net, vifi) &&
+ ttls[vifi] && ttls[vifi] < 255) {
cache->mfc_un.res.ttls[vifi] = ttls[vifi];
if (cache->mfc_un.res.minvif > vifi)
cache->mfc_un.res.minvif = vifi;
@@ -425,16 +427,16 @@ static void ipmr_update_thresholds(struct mfc_cache *cache, unsigned char *ttls)
}
}
-static int vif_add(struct vifctl *vifc, int mrtsock)
+static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock)
{
int vifi = vifc->vifc_vifi;
- struct vif_device *v = &vif_table[vifi];
+ struct vif_device *v = &net->ipv4.vif_table[vifi];
struct net_device *dev;
struct in_device *in_dev;
int err;
/* Is vif busy ? */
- if (VIF_EXISTS(vifi))
+ if (VIF_EXISTS(net, vifi))
return -EADDRINUSE;
switch (vifc->vifc_flags) {
@@ -444,7 +446,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
* Special Purpose VIF in PIM
* All the packets will be sent to the daemon
*/
- if (reg_vif_num >= 0)
+ if (net->ipv4.mroute_reg_vif_num >= 0)
return -EADDRINUSE;
dev = ipmr_reg_vif();
if (!dev)
@@ -458,7 +460,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
break;
#endif
case VIFF_TUNNEL:
- dev = ipmr_new_tunnel(vifc);
+ dev = ipmr_new_tunnel(net, vifc);
if (!dev)
return -ENOBUFS;
err = dev_set_allmulti(dev, 1);
@@ -469,7 +471,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
}
break;
case 0:
- dev = ip_dev_find(&init_net, vifc->vifc_lcl_addr.s_addr);
+ dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr);
if (!dev)
return -EADDRNOTAVAIL;
err = dev_set_allmulti(dev, 1);
@@ -510,20 +512,22 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
v->dev = dev;
#ifdef CONFIG_IP_PIMSM
if (v->flags&VIFF_REGISTER)
- reg_vif_num = vifi;
+ net->ipv4.mroute_reg_vif_num = vifi;
#endif
- if (vifi+1 > maxvif)
- maxvif = vifi+1;
+ if (vifi+1 > net->ipv4.maxvif)
+ net->ipv4.maxvif = vifi+1;
write_unlock_bh(&mrt_lock);
return 0;
}
-static struct mfc_cache *ipmr_cache_find(__be32 origin, __be32 mcastgrp)
+static struct mfc_cache *ipmr_cache_find(struct net *net,
+ __be32 origin,
+ __be32 mcastgrp)
{
int line = MFC_HASH(mcastgrp, origin);
struct mfc_cache *c;
- for (c=mfc_cache_array[line]; c; c = c->next) {
+ for (c = net->ipv4.mfc_cache_array[line]; c; c = c->next) {
if (c->mfc_origin==origin && c->mfc_mcastgrp==mcastgrp)
break;
}
@@ -533,22 +537,24 @@ static struct mfc_cache *ipmr_cache_find(__be32 origin, __be32 mcastgrp)
/*
* Allocate a multicast cache entry
*/
-static struct mfc_cache *ipmr_cache_alloc(void)
+static struct mfc_cache *ipmr_cache_alloc(struct net *net)
{
struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
if (c == NULL)
return NULL;
c->mfc_un.res.minvif = MAXVIFS;
+ mfc_net_set(c, net);
return c;
}
-static struct mfc_cache *ipmr_cache_alloc_unres(void)
+static struct mfc_cache *ipmr_cache_alloc_unres(struct net *net)
{
struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
if (c == NULL)
return NULL;
skb_queue_head_init(&c->mfc_un.unres.unresolved);
c->mfc_un.unres.expires = jiffies + 10*HZ;
+ mfc_net_set(c, net);
return c;
}
@@ -581,7 +587,7 @@ static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c)
memset(&e->msg, 0, sizeof(e->msg));
}
- rtnl_unicast(skb, &init_net, NETLINK_CB(skb).pid);
+ rtnl_unicast(skb, mfc_net(c), NETLINK_CB(skb).pid);
} else
ip_mr_forward(skb, c, 0);
}
@@ -594,7 +600,8 @@ static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c)
* Called under mrt_lock.
*/
-static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert)
+static int ipmr_cache_report(struct net *net,
+ struct sk_buff *pkt, vifi_t vifi, int assert)
{
struct sk_buff *skb;
const int ihl = ip_hdrlen(pkt);
@@ -626,7 +633,7 @@ static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert)
memcpy(msg, skb_network_header(pkt), sizeof(struct iphdr));
msg->im_msgtype = IGMPMSG_WHOLEPKT;
msg->im_mbz = 0;
- msg->im_vif = reg_vif_num;
+ msg->im_vif = net->ipv4.mroute_reg_vif_num;
ip_hdr(skb)->ihl = sizeof(struct iphdr) >> 2;
ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(pkt)->tot_len) +
sizeof(struct iphdr));
@@ -658,7 +665,7 @@ static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert)
skb->transport_header = skb->network_header;
}
- if (mroute_socket == NULL) {
+ if (net->ipv4.mroute_sk == NULL) {
kfree_skb(skb);
return -EINVAL;
}
@@ -666,7 +673,8 @@ static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert)
/*
* Deliver to mrouted
*/
- if ((ret = sock_queue_rcv_skb(mroute_socket, skb))<0) {
+ ret = sock_queue_rcv_skb(net->ipv4.mroute_sk, skb);
+ if (ret < 0) {
if (net_ratelimit())
printk(KERN_WARNING "mroute: pending queue full, dropping entries.\n");
kfree_skb(skb);
@@ -680,7 +688,7 @@ static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert)
*/
static int
-ipmr_cache_unresolved(vifi_t vifi, struct sk_buff *skb)
+ipmr_cache_unresolved(struct net *net, vifi_t vifi, struct sk_buff *skb)
{
int err;
struct mfc_cache *c;
@@ -688,7 +696,8 @@ ipmr_cache_unresolved(vifi_t vifi, struct sk_buff *skb)
spin_lock_bh(&mfc_unres_lock);
for (c=mfc_unres_queue; c; c=c->next) {
- if (c->mfc_mcastgrp == iph->daddr &&
+ if (net_eq(mfc_net(c), net) &&
+ c->mfc_mcastgrp == iph->daddr &&
c->mfc_origin == iph->saddr)
break;
}
@@ -698,8 +707,8 @@ ipmr_cache_unresolved(vifi_t vifi, struct sk_buff *skb)
* Create a new entry if allowable
*/
- if (atomic_read(&cache_resolve_queue_len) >= 10 ||
- (c=ipmr_cache_alloc_unres())==NULL) {
+ if (atomic_read(&net->ipv4.cache_resolve_queue_len) >= 10 ||
+ (c = ipmr_cache_alloc_unres(net)) == NULL) {
spin_unlock_bh(&mfc_unres_lock);
kfree_skb(skb);
@@ -716,18 +725,19 @@ ipmr_cache_unresolved(vifi_t vifi, struct sk_buff *skb)
/*
* Reflect first query at mrouted.
*/
- if ((err = ipmr_cache_report(skb, vifi, IGMPMSG_NOCACHE))<0) {
+ err = ipmr_cache_report(net, skb, vifi, IGMPMSG_NOCACHE);
+ if (err < 0) {
/* If the report failed throw the cache entry
out - Brad Parker
*/
spin_unlock_bh(&mfc_unres_lock);
- kmem_cache_free(mrt_cachep, c);
+ ipmr_cache_free(c);
kfree_skb(skb);
return err;
}
- atomic_inc(&cache_resolve_queue_len);
+ atomic_inc(&net->ipv4.cache_resolve_queue_len);
c->next = mfc_unres_queue;
mfc_unres_queue = c;
@@ -753,35 +763,37 @@ ipmr_cache_unresolved(vifi_t vifi, struct sk_buff *skb)
* MFC cache manipulation by user space mroute daemon
*/
-static int ipmr_mfc_delete(struct mfcctl *mfc)
+static int ipmr_mfc_delete(struct net *net, struct mfcctl *mfc)
{
int line;
struct mfc_cache *c, **cp;
line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
- for (cp=&mfc_cache_array[line]; (c=*cp) != NULL; cp = &c->next) {
+ for (cp = &net->ipv4.mfc_cache_array[line];
+ (c = *cp) != NULL; cp = &c->next) {
if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
write_lock_bh(&mrt_lock);
*cp = c->next;
write_unlock_bh(&mrt_lock);
- kmem_cache_free(mrt_cachep, c);
+ ipmr_cache_free(c);
return 0;
}
}
return -ENOENT;
}
-static int ipmr_mfc_add(struct mfcctl *mfc, int mrtsock)
+static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock)
{
int line;
struct mfc_cache *uc, *c, **cp;
line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
- for (cp=&mfc_cache_array[line]; (c=*cp) != NULL; cp = &c->next) {
+ for (cp = &net->ipv4.mfc_cache_array[line];
+ (c = *cp) != NULL; cp = &c->next) {
if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr)
break;
@@ -800,7 +812,7 @@ static int ipmr_mfc_add(struct mfcctl *mfc, int mrtsock)
if (!ipv4_is_multicast(mfc->mfcc_mcastgrp.s_addr))
return -EINVAL;
- c = ipmr_cache_alloc();
+ c = ipmr_cache_alloc(net);
if (c == NULL)
return -ENOMEM;
@@ -812,8 +824,8 @@ static int ipmr_mfc_add(struct mfcctl *mfc, int mrtsock)
c->mfc_flags |= MFC_STATIC;
write_lock_bh(&mrt_lock);
- c->next = mfc_cache_array[line];
- mfc_cache_array[line] = c;
+ c->next = net->ipv4.mfc_cache_array[line];
+ net->ipv4.mfc_cache_array[line] = c;
write_unlock_bh(&mrt_lock);
/*
@@ -823,19 +835,21 @@ static int ipmr_mfc_add(struct mfcctl *mfc, int mrtsock)
spin_lock_bh(&mfc_unres_lock);
for (cp = &mfc_unres_queue; (uc=*cp) != NULL;
cp = &uc->next) {
- if (uc->mfc_origin == c->mfc_origin &&
+ if (net_eq(mfc_net(uc), net) &&
+ uc->mfc_origin == c->mfc_origin &&
uc->mfc_mcastgrp == c->mfc_mcastgrp) {
*cp = uc->next;
- if (atomic_dec_and_test(&cache_resolve_queue_len))
- del_timer(&ipmr_expire_timer);
+ atomic_dec(&net->ipv4.cache_resolve_queue_len);
break;
}
}
+ if (mfc_unres_queue == NULL)
+ del_timer(&ipmr_expire_timer);
spin_unlock_bh(&mfc_unres_lock);
if (uc) {
ipmr_cache_resolve(uc, c);
- kmem_cache_free(mrt_cachep, uc);
+ ipmr_cache_free(uc);
}
return 0;
}
@@ -844,16 +858,16 @@ static int ipmr_mfc_add(struct mfcctl *mfc, int mrtsock)
* Close the multicast socket, and clear the vif tables etc
*/
-static void mroute_clean_tables(struct sock *sk)
+static void mroute_clean_tables(struct net *net)
{
int i;
/*
* Shut down all active vif entries
*/
- for (i=0; i<maxvif; i++) {
- if (!(vif_table[i].flags&VIFF_STATIC))
- vif_delete(i, 0);
+ for (i = 0; i < net->ipv4.maxvif; i++) {
+ if (!(net->ipv4.vif_table[i].flags&VIFF_STATIC))
+ vif_delete(net, i, 0);
}
/*
@@ -862,7 +876,7 @@ static void mroute_clean_tables(struct sock *sk)
for (i=0; i<MFC_LINES; i++) {
struct mfc_cache *c, **cp;
- cp = &mfc_cache_array[i];
+ cp = &net->ipv4.mfc_cache_array[i];
while ((c = *cp) != NULL) {
if (c->mfc_flags&MFC_STATIC) {
cp = &c->next;
@@ -872,22 +886,23 @@ static void mroute_clean_tables(struct sock *sk)
*cp = c->next;
write_unlock_bh(&mrt_lock);
- kmem_cache_free(mrt_cachep, c);
+ ipmr_cache_free(c);
}
}
- if (atomic_read(&cache_resolve_queue_len) != 0) {
- struct mfc_cache *c;
+ if (atomic_read(&net->ipv4.cache_resolve_queue_len) != 0) {
+ struct mfc_cache *c, **cp;
spin_lock_bh(&mfc_unres_lock);
- while (mfc_unres_queue != NULL) {
- c = mfc_unres_queue;
- mfc_unres_queue = c->next;
- spin_unlock_bh(&mfc_unres_lock);
+ cp = &mfc_unres_queue;
+ while ((c = *cp) != NULL) {
+ if (!net_eq(mfc_net(c), net)) {
+ cp = &c->next;
+ continue;
+ }
+ *cp = c->next;
ipmr_destroy_unres(c);
-
- spin_lock_bh(&mfc_unres_lock);
}
spin_unlock_bh(&mfc_unres_lock);
}
@@ -895,15 +910,17 @@ static void mroute_clean_tables(struct sock *sk)
static void mrtsock_destruct(struct sock *sk)
{
+ struct net *net = sock_net(sk);
+
rtnl_lock();
- if (sk == mroute_socket) {
- IPV4_DEVCONF_ALL(sock_net(sk), MC_FORWARDING)--;
+ if (sk == net->ipv4.mroute_sk) {
+ IPV4_DEVCONF_ALL(net, MC_FORWARDING)--;
write_lock_bh(&mrt_lock);
- mroute_socket = NULL;
+ net->ipv4.mroute_sk = NULL;
write_unlock_bh(&mrt_lock);
- mroute_clean_tables(sk);
+ mroute_clean_tables(net);
}
rtnl_unlock();
}
@@ -920,9 +937,10 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
int ret;
struct vifctl vif;
struct mfcctl mfc;
+ struct net *net = sock_net(sk);
if (optname != MRT_INIT) {
- if (sk != mroute_socket && !capable(CAP_NET_ADMIN))
+ if (sk != net->ipv4.mroute_sk && !capable(CAP_NET_ADMIN))
return -EACCES;
}
@@ -935,7 +953,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
return -ENOPROTOOPT;
rtnl_lock();
- if (mroute_socket) {
+ if (net->ipv4.mroute_sk) {
rtnl_unlock();
return -EADDRINUSE;
}
@@ -943,15 +961,15 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
ret = ip_ra_control(sk, 1, mrtsock_destruct);
if (ret == 0) {
write_lock_bh(&mrt_lock);
- mroute_socket = sk;
+ net->ipv4.mroute_sk = sk;
write_unlock_bh(&mrt_lock);
- IPV4_DEVCONF_ALL(sock_net(sk), MC_FORWARDING)++;
+ IPV4_DEVCONF_ALL(net, MC_FORWARDING)++;
}
rtnl_unlock();
return ret;
case MRT_DONE:
- if (sk != mroute_socket)
+ if (sk != net->ipv4.mroute_sk)
return -EACCES;
return ip_ra_control(sk, 0, NULL);
case MRT_ADD_VIF:
@@ -964,9 +982,9 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
return -ENFILE;
rtnl_lock();
if (optname == MRT_ADD_VIF) {
- ret = vif_add(&vif, sk==mroute_socket);
+ ret = vif_add(net, &vif, sk == net->ipv4.mroute_sk);
} else {
- ret = vif_delete(vif.vifc_vifi, 0);
+ ret = vif_delete(net, vif.vifc_vifi, 0);
}
rtnl_unlock();
return ret;
@@ -983,9 +1001,9 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
return -EFAULT;
rtnl_lock();
if (optname == MRT_DEL_MFC)
- ret = ipmr_mfc_delete(&mfc);
+ ret = ipmr_mfc_delete(net, &mfc);
else
- ret = ipmr_mfc_add(&mfc, sk==mroute_socket);
+ ret = ipmr_mfc_add(net, &mfc, sk == net->ipv4.mroute_sk);
rtnl_unlock();
return ret;
/*
@@ -996,7 +1014,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
int v;
if (get_user(v,(int __user *)optval))
return -EFAULT;
- mroute_do_assert=(v)?1:0;
+ net->ipv4.mroute_do_assert = (v) ? 1 : 0;
return 0;
}
#ifdef CONFIG_IP_PIMSM
@@ -1010,11 +1028,11 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
rtnl_lock();
ret = 0;
- if (v != mroute_do_pim) {
- mroute_do_pim = v;
- mroute_do_assert = v;
+ if (v != net->ipv4.mroute_do_pim) {
+ net->ipv4.mroute_do_pim = v;
+ net->ipv4.mroute_do_assert = v;
#ifdef CONFIG_IP_PIMSM_V2
- if (mroute_do_pim)
+ if (net->ipv4.mroute_do_pim)
ret = inet_add_protocol(&pim_protocol,
IPPROTO_PIM);
else
@@ -1045,6 +1063,7 @@ int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int
{
int olr;
int val;
+ struct net *net = sock_net(sk);
if (optname != MRT_VERSION &&
#ifdef CONFIG_IP_PIMSM
@@ -1066,10 +1085,10 @@ int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int
val = 0x0305;
#ifdef CONFIG_IP_PIMSM
else if (optname == MRT_PIM)
- val = mroute_do_pim;
+ val = net->ipv4.mroute_do_pim;
#endif
else
- val = mroute_do_assert;
+ val = net->ipv4.mroute_do_assert;
if (copy_to_user(optval, &val, olr))
return -EFAULT;
return 0;
@@ -1085,16 +1104,17 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
struct sioc_vif_req vr;
struct vif_device *vif;
struct mfc_cache *c;
+ struct net *net = sock_net(sk);
switch (cmd) {
case SIOCGETVIFCNT:
if (copy_from_user(&vr, arg, sizeof(vr)))
return -EFAULT;
- if (vr.vifi >= maxvif)
+ if (vr.vifi >= net->ipv4.maxvif)
return -EINVAL;
read_lock(&mrt_lock);
- vif=&vif_table[vr.vifi];
- if (VIF_EXISTS(vr.vifi)) {
+ vif = &net->ipv4.vif_table[vr.vifi];
+ if (VIF_EXISTS(net, vr.vifi)) {
vr.icount = vif->pkt_in;
vr.ocount = vif->pkt_out;
vr.ibytes = vif->bytes_in;
@@ -1112,7 +1132,7 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
return -EFAULT;
read_lock(&mrt_lock);
- c = ipmr_cache_find(sr.src.s_addr, sr.grp.s_addr);
+ c = ipmr_cache_find(net, sr.src.s_addr, sr.grp.s_addr);
if (c) {
sr.pktcnt = c->mfc_un.res.pkt;
sr.bytecnt = c->mfc_un.res.bytes;
@@ -1134,18 +1154,19 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
+ struct net *net = dev_net(dev);
struct vif_device *v;
int ct;
- if (!net_eq(dev_net(dev), &init_net))
+ if (!net_eq(dev_net(dev), net))
return NOTIFY_DONE;
if (event != NETDEV_UNREGISTER)
return NOTIFY_DONE;
- v=&vif_table[0];
- for (ct=0; ct<maxvif; ct++,v++) {
+ v = &net->ipv4.vif_table[0];
+ for (ct = 0; ct < net->ipv4.maxvif; ct++, v++) {
if (v->dev == dev)
- vif_delete(ct, 1);
+ vif_delete(net, ct, 1);
}
return NOTIFY_DONE;
}
@@ -1205,8 +1226,9 @@ static inline int ipmr_forward_finish(struct sk_buff *skb)
static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
{
+ struct net *net = mfc_net(c);
const struct iphdr *iph = ip_hdr(skb);
- struct vif_device *vif = &vif_table[vifi];
+ struct vif_device *vif = &net->ipv4.vif_table[vifi];
struct net_device *dev;
struct rtable *rt;
int encap = 0;
@@ -1220,7 +1242,7 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
vif->bytes_out += skb->len;
vif->dev->stats.tx_bytes += skb->len;
vif->dev->stats.tx_packets++;
- ipmr_cache_report(skb, vifi, IGMPMSG_WHOLEPKT);
+ ipmr_cache_report(net, skb, vifi, IGMPMSG_WHOLEPKT);
kfree_skb(skb);
return;
}
@@ -1233,7 +1255,7 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
.saddr = vif->local,
.tos = RT_TOS(iph->tos) } },
.proto = IPPROTO_IPIP };
- if (ip_route_output_key(&init_net, &rt, &fl))
+ if (ip_route_output_key(net, &rt, &fl))
goto out_free;
encap = sizeof(struct iphdr);
} else {
@@ -1242,7 +1264,7 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
{ .daddr = iph->daddr,
.tos = RT_TOS(iph->tos) } },
.proto = IPPROTO_IPIP };
- if (ip_route_output_key(&init_net, &rt, &fl))
+ if (ip_route_output_key(net, &rt, &fl))
goto out_free;
}
@@ -1306,9 +1328,10 @@ out_free:
static int ipmr_find_vif(struct net_device *dev)
{
+ struct net *net = dev_net(dev);
int ct;
- for (ct=maxvif-1; ct>=0; ct--) {
- if (vif_table[ct].dev == dev)
+ for (ct = net->ipv4.maxvif-1; ct >= 0; ct--) {
+ if (net->ipv4.vif_table[ct].dev == dev)
break;
}
return ct;
@@ -1320,6 +1343,7 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local
{
int psend = -1;
int vif, ct;
+ struct net *net = mfc_net(cache);
vif = cache->mfc_parent;
cache->mfc_un.res.pkt++;
@@ -1328,7 +1352,7 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local
/*
* Wrong interface: drop packet and (maybe) send PIM assert.
*/
- if (vif_table[vif].dev != skb->dev) {
+ if (net->ipv4.vif_table[vif].dev != skb->dev) {
int true_vifi;
if (skb->rtable->fl.iif == 0) {
@@ -1349,23 +1373,24 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local
cache->mfc_un.res.wrong_if++;
true_vifi = ipmr_find_vif(skb->dev);
- if (true_vifi >= 0 && mroute_do_assert &&
+ if (true_vifi >= 0 && net->ipv4.mroute_do_assert &&
/* pimsm uses asserts, when switching from RPT to SPT,
so that we cannot check that packet arrived on an oif.
It is bad, but otherwise we would need to move pretty
large chunk of pimd to kernel. Ough... --ANK
*/
- (mroute_do_pim || cache->mfc_un.res.ttls[true_vifi] < 255) &&
+ (net->ipv4.mroute_do_pim ||
+ cache->mfc_un.res.ttls[true_vifi] < 255) &&
time_after(jiffies,
cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
cache->mfc_un.res.last_assert = jiffies;
- ipmr_cache_report(skb, true_vifi, IGMPMSG_WRONGVIF);
+ ipmr_cache_report(net, skb, true_vifi, IGMPMSG_WRONGVIF);
}
goto dont_forward;
}
- vif_table[vif].pkt_in++;
- vif_table[vif].bytes_in += skb->len;
+ net->ipv4.vif_table[vif].pkt_in++;
+ net->ipv4.vif_table[vif].bytes_in += skb->len;
/*
* Forward the frame
@@ -1405,6 +1430,7 @@ dont_forward:
int ip_mr_input(struct sk_buff *skb)
{
struct mfc_cache *cache;
+ struct net *net = dev_net(skb->dev);
int local = skb->rtable->rt_flags&RTCF_LOCAL;
/* Packet is looped back after forward, it should not be
@@ -1425,9 +1451,9 @@ int ip_mr_input(struct sk_buff *skb)
that we can forward NO IGMP messages.
*/
read_lock(&mrt_lock);
- if (mroute_socket) {
+ if (net->ipv4.mroute_sk) {
nf_reset(skb);
- raw_rcv(mroute_socket, skb);
+ raw_rcv(net->ipv4.mroute_sk, skb);
read_unlock(&mrt_lock);
return 0;
}
@@ -1436,7 +1462,7 @@ int ip_mr_input(struct sk_buff *skb)
}
read_lock(&mrt_lock);
- cache = ipmr_cache_find(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
+ cache = ipmr_cache_find(net, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
/*
* No usable cache entry
@@ -1456,7 +1482,7 @@ int ip_mr_input(struct sk_buff *skb)
vif = ipmr_find_vif(skb->dev);
if (vif >= 0) {
- int err = ipmr_cache_unresolved(vif, skb);
+ int err = ipmr_cache_unresolved(net, vif, skb);
read_unlock(&mrt_lock);
return err;
@@ -1487,6 +1513,7 @@ static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen)
{
struct net_device *reg_dev = NULL;
struct iphdr *encap;
+ struct net *net = dev_net(skb->dev);
encap = (struct iphdr *)(skb_transport_header(skb) + pimlen);
/*
@@ -1501,8 +1528,8 @@ static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen)
return 1;
read_lock(&mrt_lock);
- if (reg_vif_num >= 0)
- reg_dev = vif_table[reg_vif_num].dev;
+ if (net->ipv4.mroute_reg_vif_num >= 0)
+ reg_dev = net->ipv4.vif_table[net->ipv4.mroute_reg_vif_num].dev;
if (reg_dev)
dev_hold(reg_dev);
read_unlock(&mrt_lock);
@@ -1537,13 +1564,14 @@ static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen)
int pim_rcv_v1(struct sk_buff * skb)
{
struct igmphdr *pim;
+ struct net *net = dev_net(skb->dev);
if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
goto drop;
pim = igmp_hdr(skb);
- if (!mroute_do_pim ||
+ if (!net->ipv4.mroute_do_pim ||
pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER)
goto drop;
@@ -1583,7 +1611,8 @@ ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm)
{
int ct;
struct rtnexthop *nhp;
- struct net_device *dev = vif_table[c->mfc_parent].dev;
+ struct net *net = mfc_net(c);
+ struct net_device *dev = net->ipv4.vif_table[c->mfc_parent].dev;
u8 *b = skb_tail_pointer(skb);
struct rtattr *mp_head;
@@ -1599,7 +1628,7 @@ ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm)
nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
nhp->rtnh_flags = 0;
nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
- nhp->rtnh_ifindex = vif_table[ct].dev->ifindex;
+ nhp->rtnh_ifindex = net->ipv4.vif_table[ct].dev->ifindex;
nhp->rtnh_len = sizeof(*nhp);
}
}
@@ -1613,14 +1642,15 @@ rtattr_failure:
return -EMSGSIZE;
}
-int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait)
+int ipmr_get_route(struct net *net,
+ struct sk_buff *skb, struct rtmsg *rtm, int nowait)
{
int err;
struct mfc_cache *cache;
struct rtable *rt = skb->rtable;
read_lock(&mrt_lock);
- cache = ipmr_cache_find(rt->rt_src, rt->rt_dst);
+ cache = ipmr_cache_find(net, rt->rt_src, rt->rt_dst);
if (cache == NULL) {
struct sk_buff *skb2;
@@ -1651,7 +1681,7 @@ int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait)
iph->saddr = rt->rt_src;
iph->daddr = rt->rt_dst;
iph->version = 0;
- err = ipmr_cache_unresolved(vif, skb2);
+ err = ipmr_cache_unresolved(net, vif, skb2);
read_unlock(&mrt_lock);
return err;
}
@@ -1668,17 +1698,19 @@ int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait)
* The /proc interfaces to multicast routing /proc/ip_mr_cache /proc/ip_mr_vif
*/
struct ipmr_vif_iter {
+ struct seq_net_private p;
int ct;
};
-static struct vif_device *ipmr_vif_seq_idx(struct ipmr_vif_iter *iter,
+static struct vif_device *ipmr_vif_seq_idx(struct net *net,
+ struct ipmr_vif_iter *iter,
loff_t pos)
{
- for (iter->ct = 0; iter->ct < maxvif; ++iter->ct) {
- if (!VIF_EXISTS(iter->ct))
+ for (iter->ct = 0; iter->ct < net->ipv4.maxvif; ++iter->ct) {
+ if (!VIF_EXISTS(net, iter->ct))
continue;
if (pos-- == 0)
- return &vif_table[iter->ct];
+ return &net->ipv4.vif_table[iter->ct];
}
return NULL;
}
@@ -1686,23 +1718,26 @@ static struct vif_device *ipmr_vif_seq_idx(struct ipmr_vif_iter *iter,
static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos)
__acquires(mrt_lock)
{
+ struct net *net = seq_file_net(seq);
+
read_lock(&mrt_lock);
- return *pos ? ipmr_vif_seq_idx(seq->private, *pos - 1)
+ return *pos ? ipmr_vif_seq_idx(net, seq->private, *pos - 1)
: SEQ_START_TOKEN;
}
static void *ipmr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct ipmr_vif_iter *iter = seq->private;
+ struct net *net = seq_file_net(seq);
++*pos;
if (v == SEQ_START_TOKEN)
- return ipmr_vif_seq_idx(iter, 0);
+ return ipmr_vif_seq_idx(net, iter, 0);
- while (++iter->ct < maxvif) {
- if (!VIF_EXISTS(iter->ct))
+ while (++iter->ct < net->ipv4.maxvif) {
+ if (!VIF_EXISTS(net, iter->ct))
continue;
- return &vif_table[iter->ct];
+ return &net->ipv4.vif_table[iter->ct];
}
return NULL;
}
@@ -1715,6 +1750,8 @@ static void ipmr_vif_seq_stop(struct seq_file *seq, void *v)
static int ipmr_vif_seq_show(struct seq_file *seq, void *v)
{
+ struct net *net = seq_file_net(seq);
+
if (v == SEQ_START_TOKEN) {
seq_puts(seq,
"Interface BytesIn PktsIn BytesOut PktsOut Flags Local Remote\n");
@@ -1724,7 +1761,7 @@ static int ipmr_vif_seq_show(struct seq_file *seq, void *v)
seq_printf(seq,
"%2Zd %-10s %8ld %7ld %8ld %7ld %05X %08X %08X\n",
- vif - vif_table,
+ vif - net->ipv4.vif_table,
name, vif->bytes_in, vif->pkt_in,
vif->bytes_out, vif->pkt_out,
vif->flags, vif->local, vif->remote);
@@ -1741,8 +1778,8 @@ static const struct seq_operations ipmr_vif_seq_ops = {
static int ipmr_vif_open(struct inode *inode, struct file *file)
{
- return seq_open_private(file, &ipmr_vif_seq_ops,
- sizeof(struct ipmr_vif_iter));
+ return seq_open_net(inode, file, &ipmr_vif_seq_ops,
+ sizeof(struct ipmr_vif_iter));
}
static const struct file_operations ipmr_vif_fops = {
@@ -1750,23 +1787,26 @@ static const struct file_operations ipmr_vif_fops = {
.open = ipmr_vif_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release_net,
};
struct ipmr_mfc_iter {
+ struct seq_net_private p;
struct mfc_cache **cache;
int ct;
};
-static struct mfc_cache *ipmr_mfc_seq_idx(struct ipmr_mfc_iter *it, loff_t pos)
+static struct mfc_cache *ipmr_mfc_seq_idx(struct net *net,
+ struct ipmr_mfc_iter *it, loff_t pos)
{
struct mfc_cache *mfc;
- it->cache = mfc_cache_array;
+ it->cache = net->ipv4.mfc_cache_array;
read_lock(&mrt_lock);
for (it->ct = 0; it->ct < MFC_LINES; it->ct++)
- for (mfc = mfc_cache_array[it->ct]; mfc; mfc = mfc->next)
+ for (mfc = net->ipv4.mfc_cache_array[it->ct];
+ mfc; mfc = mfc->next)
if (pos-- == 0)
return mfc;
read_unlock(&mrt_lock);
@@ -1774,7 +1814,8 @@ static struct mfc_cache *ipmr_mfc_seq_idx(struct ipmr_mfc_iter *it, loff_t pos)
it->cache = &mfc_unres_queue;
spin_lock_bh(&mfc_unres_lock);
for (mfc = mfc_unres_queue; mfc; mfc = mfc->next)
- if (pos-- == 0)
+ if (net_eq(mfc_net(mfc), net) &&
+ pos-- == 0)
return mfc;
spin_unlock_bh(&mfc_unres_lock);
@@ -1786,9 +1827,11 @@ static struct mfc_cache *ipmr_mfc_seq_idx(struct ipmr_mfc_iter *it, loff_t pos)
static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
{
struct ipmr_mfc_iter *it = seq->private;
+ struct net *net = seq_file_net(seq);
+
it->cache = NULL;
it->ct = 0;
- return *pos ? ipmr_mfc_seq_idx(seq->private, *pos - 1)
+ return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
: SEQ_START_TOKEN;
}
@@ -1796,11 +1839,12 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct mfc_cache *mfc = v;
struct ipmr_mfc_iter *it = seq->private;
+ struct net *net = seq_file_net(seq);
++*pos;
if (v == SEQ_START_TOKEN)
- return ipmr_mfc_seq_idx(seq->private, 0);
+ return ipmr_mfc_seq_idx(net, seq->private, 0);
if (mfc->next)
return mfc->next;
@@ -1808,10 +1852,10 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
if (it->cache == &mfc_unres_queue)
goto end_of_list;
- BUG_ON(it->cache != mfc_cache_array);
+ BUG_ON(it->cache != net->ipv4.mfc_cache_array);
while (++it->ct < MFC_LINES) {
- mfc = mfc_cache_array[it->ct];
+ mfc = net->ipv4.mfc_cache_array[it->ct];
if (mfc)
return mfc;
}
@@ -1823,6 +1867,8 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
spin_lock_bh(&mfc_unres_lock);
mfc = mfc_unres_queue;
+ while (mfc && !net_eq(mfc_net(mfc), net))
+ mfc = mfc->next;
if (mfc)
return mfc;
@@ -1836,16 +1882,18 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
{
struct ipmr_mfc_iter *it = seq->private;
+ struct net *net = seq_file_net(seq);
if (it->cache == &mfc_unres_queue)
spin_unlock_bh(&mfc_unres_lock);
- else if (it->cache == mfc_cache_array)
+ else if (it->cache == net->ipv4.mfc_cache_array)
read_unlock(&mrt_lock);
}
static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
{
int n;
+ struct net *net = seq_file_net(seq);
if (v == SEQ_START_TOKEN) {
seq_puts(seq,
@@ -1866,9 +1914,9 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
mfc->mfc_un.res.wrong_if);
for (n = mfc->mfc_un.res.minvif;
n < mfc->mfc_un.res.maxvif; n++ ) {
- if (VIF_EXISTS(n)
- && mfc->mfc_un.res.ttls[n] < 255)
- seq_printf(seq,
+ if (VIF_EXISTS(net, n) &&
+ mfc->mfc_un.res.ttls[n] < 255)
+ seq_printf(seq,
" %2d:%-3d",
n, mfc->mfc_un.res.ttls[n]);
}
@@ -1892,8 +1940,8 @@ static const struct seq_operations ipmr_mfc_seq_ops = {
static int ipmr_mfc_open(struct inode *inode, struct file *file)
{
- return seq_open_private(file, &ipmr_mfc_seq_ops,
- sizeof(struct ipmr_mfc_iter));
+ return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
+ sizeof(struct ipmr_mfc_iter));
}
static const struct file_operations ipmr_mfc_fops = {
@@ -1901,7 +1949,7 @@ static const struct file_operations ipmr_mfc_fops = {
.open = ipmr_mfc_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release_net,
};
#endif
@@ -1915,6 +1963,65 @@ static struct net_protocol pim_protocol = {
/*
* Setup for IP multicast routing
*/
+static int __net_init ipmr_net_init(struct net *net)
+{
+ int err = 0;
+
+ net->ipv4.vif_table = kcalloc(MAXVIFS, sizeof(struct vif_device),
+ GFP_KERNEL);
+ if (!net->ipv4.vif_table) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ /* Forwarding cache */
+ net->ipv4.mfc_cache_array = kcalloc(MFC_LINES,
+ sizeof(struct mfc_cache *),
+ GFP_KERNEL);
+ if (!net->ipv4.mfc_cache_array) {
+ err = -ENOMEM;
+ goto fail_mfc_cache;
+ }
+
+#ifdef CONFIG_IP_PIMSM
+ net->ipv4.mroute_reg_vif_num = -1;
+#endif
+
+#ifdef CONFIG_PROC_FS
+ err = -ENOMEM;
+ if (!proc_net_fops_create(net, "ip_mr_vif", 0, &ipmr_vif_fops))
+ goto proc_vif_fail;
+ if (!proc_net_fops_create(net, "ip_mr_cache", 0, &ipmr_mfc_fops))
+ goto proc_cache_fail;
+#endif
+ return 0;
+
+#ifdef CONFIG_PROC_FS
+proc_cache_fail:
+ proc_net_remove(net, "ip_mr_vif");
+proc_vif_fail:
+ kfree(net->ipv4.mfc_cache_array);
+#endif
+fail_mfc_cache:
+ kfree(net->ipv4.vif_table);
+fail:
+ return err;
+}
+
+static void __net_exit ipmr_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ proc_net_remove(net, "ip_mr_cache");
+ proc_net_remove(net, "ip_mr_vif");
+#endif
+ kfree(net->ipv4.mfc_cache_array);
+ kfree(net->ipv4.vif_table);
+}
+
+static struct pernet_operations ipmr_net_ops = {
+ .init = ipmr_net_init,
+ .exit = ipmr_net_exit,
+};
int __init ip_mr_init(void)
{
@@ -1927,26 +2034,20 @@ int __init ip_mr_init(void)
if (!mrt_cachep)
return -ENOMEM;
+ err = register_pernet_subsys(&ipmr_net_ops);
+ if (err)
+ goto reg_pernet_fail;
+
setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0);
err = register_netdevice_notifier(&ip_mr_notifier);
if (err)
goto reg_notif_fail;
-#ifdef CONFIG_PROC_FS
- err = -ENOMEM;
- if (!proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops))
- goto proc_vif_fail;
- if (!proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops))
- goto proc_cache_fail;
-#endif
return 0;
-#ifdef CONFIG_PROC_FS
-proc_cache_fail:
- proc_net_remove(&init_net, "ip_mr_vif");
-proc_vif_fail:
- unregister_netdevice_notifier(&ip_mr_notifier);
-#endif
+
reg_notif_fail:
del_timer(&ipmr_expire_timer);
+ unregister_pernet_subsys(&ipmr_net_ops);
+reg_pernet_fail:
kmem_cache_destroy(mrt_cachep);
return err;
}
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 97f71153584..6a9e204c802 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2779,7 +2779,8 @@ int ip_route_output_key(struct net *net, struct rtable **rp, struct flowi *flp)
return ip_route_output_flow(net, rp, flp, NULL, 0);
}
-static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
+static int rt_fill_info(struct net *net,
+ struct sk_buff *skb, u32 pid, u32 seq, int event,
int nowait, unsigned int flags)
{
struct rtable *rt = skb->rtable;
@@ -2844,8 +2845,8 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
__be32 dst = rt->rt_dst;
if (ipv4_is_multicast(dst) && !ipv4_is_local_multicast(dst) &&
- IPV4_DEVCONF_ALL(&init_net, MC_FORWARDING)) {
- int err = ipmr_get_route(skb, r, nowait);
+ IPV4_DEVCONF_ALL(net, MC_FORWARDING)) {
+ int err = ipmr_get_route(net, skb, r, nowait);
if (err <= 0) {
if (!nowait) {
if (err == 0)
@@ -2950,7 +2951,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
if (rtm->rtm_flags & RTM_F_NOTIFY)
rt->rt_flags |= RTCF_NOTIFY;
- err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
+ err = rt_fill_info(net, skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
RTM_NEWROUTE, 0, 0);
if (err <= 0)
goto errout_free;
@@ -2988,7 +2989,7 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb)
if (rt_is_expired(rt))
continue;
skb->dst = dst_clone(&rt->u.dst);
- if (rt_fill_info(skb, NETLINK_CB(cb->skb).pid,
+ if (rt_fill_info(net, skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, RTM_NEWROUTE,
1, NLM_F_MULTI) <= 0) {
dst_release(xchg(&skb->dst, NULL));
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 76b148bcb0d..73266b79c19 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2482,19 +2482,19 @@ struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb)
unsigned int mss = 1;
int flush = 1;
- if (!pskb_may_pull(skb, sizeof(*th)))
+ th = skb_gro_header(skb, sizeof(*th));
+ if (unlikely(!th))
goto out;
- th = tcp_hdr(skb);
thlen = th->doff * 4;
if (thlen < sizeof(*th))
goto out;
- if (!pskb_may_pull(skb, thlen))
+ th = skb_gro_header(skb, thlen);
+ if (unlikely(!th))
goto out;
- th = tcp_hdr(skb);
- __skb_pull(skb, thlen);
+ skb_gro_pull(skb, thlen);
flags = tcp_flag_word(th);
@@ -2522,10 +2522,10 @@ found:
flush |= th->ack_seq != th2->ack_seq || th->window != th2->window;
flush |= memcmp(th + 1, th2 + 1, thlen - sizeof(*th));
- total = p->len;
+ total = skb_gro_len(p);
mss = skb_shinfo(p)->gso_size;
- flush |= skb->len > mss || skb->len <= 0;
+ flush |= skb_gro_len(skb) > mss || !skb_gro_len(skb);
flush |= ntohl(th2->seq) + total != ntohl(th->seq);
if (flush || skb_gro_receive(head, skb)) {
@@ -2538,7 +2538,7 @@ found:
tcp_flag_word(th2) |= flags & (TCP_FLAG_FIN | TCP_FLAG_PSH);
out_check_final:
- flush = skb->len < mss;
+ flush = skb_gro_len(skb) < mss;
flush |= flags & (TCP_FLAG_URG | TCP_FLAG_PSH | TCP_FLAG_RST |
TCP_FLAG_SYN | TCP_FLAG_FIN);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 19d7b429a26..f6b962f56ab 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2355,7 +2355,7 @@ struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb)
switch (skb->ip_summed) {
case CHECKSUM_COMPLETE:
- if (!tcp_v4_check(skb->len, iph->saddr, iph->daddr,
+ if (!tcp_v4_check(skb_gro_len(skb), iph->saddr, iph->daddr,
skb->csum)) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
break;
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index c802bc1658a..bd91eadcbe3 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -799,24 +799,34 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
int proto;
__wsum csum;
- if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
+ iph = skb_gro_header(skb, sizeof(*iph));
+ if (unlikely(!iph))
goto out;
- iph = ipv6_hdr(skb);
- __skb_pull(skb, sizeof(*iph));
+ skb_gro_pull(skb, sizeof(*iph));
+ skb_set_transport_header(skb, skb_gro_offset(skb));
- flush += ntohs(iph->payload_len) != skb->len;
+ flush += ntohs(iph->payload_len) != skb_gro_len(skb);
rcu_read_lock();
- proto = ipv6_gso_pull_exthdrs(skb, iph->nexthdr);
- iph = ipv6_hdr(skb);
- IPV6_GRO_CB(skb)->proto = proto;
+ proto = iph->nexthdr;
ops = rcu_dereference(inet6_protos[proto]);
- if (!ops || !ops->gro_receive)
- goto out_unlock;
+ if (!ops || !ops->gro_receive) {
+ __pskb_pull(skb, skb_gro_offset(skb));
+ proto = ipv6_gso_pull_exthdrs(skb, proto);
+ skb_gro_pull(skb, -skb_transport_offset(skb));
+ skb_reset_transport_header(skb);
+ __skb_push(skb, skb_gro_offset(skb));
+
+ if (!ops || !ops->gro_receive)
+ goto out_unlock;
+
+ iph = ipv6_hdr(skb);
+ }
+
+ IPV6_GRO_CB(skb)->proto = proto;
flush--;
- skb_reset_transport_header(skb);
nlen = skb_network_header_len(skb);
for (p = *head; p; p = p->next) {
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index e5b85d45bee..00f1269e11e 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -948,7 +948,7 @@ struct sk_buff **tcp6_gro_receive(struct sk_buff **head, struct sk_buff *skb)
switch (skb->ip_summed) {
case CHECKSUM_COMPLETE:
- if (!tcp_v6_check(skb->len, &iph->saddr, &iph->daddr,
+ if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
skb->csum)) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
break;
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index e9c05b8f4f4..cba7849de98 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -1432,7 +1432,7 @@ static int __init nr_proto_init(void)
struct net_device *dev;
sprintf(name, "nr%d", i);
- dev = alloc_netdev(sizeof(struct nr_private), name, nr_setup);
+ dev = alloc_netdev(0, name, nr_setup);
if (!dev) {
printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device structure\n");
goto fail;
diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c
index 6caf459665f..351372463fe 100644
--- a/net/netrom/nr_dev.c
+++ b/net/netrom/nr_dev.c
@@ -42,7 +42,7 @@
int nr_rx_ip(struct sk_buff *skb, struct net_device *dev)
{
- struct net_device_stats *stats = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
if (!netif_running(dev)) {
stats->rx_dropped++;
@@ -171,8 +171,7 @@ static int nr_close(struct net_device *dev)
static int nr_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct nr_private *nr = netdev_priv(dev);
- struct net_device_stats *stats = &nr->stats;
+ struct net_device_stats *stats = &dev->stats;
unsigned int len = skb->len;
if (!nr_route_frame(skb, NULL)) {
@@ -187,34 +186,27 @@ static int nr_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-static struct net_device_stats *nr_get_stats(struct net_device *dev)
-{
- struct nr_private *nr = netdev_priv(dev);
-
- return &nr->stats;
-}
-
static const struct header_ops nr_header_ops = {
.create = nr_header,
.rebuild= nr_rebuild_header,
};
+static const struct net_device_ops nr_netdev_ops = {
+ .ndo_open = nr_open,
+ .ndo_stop = nr_close,
+ .ndo_start_xmit = nr_xmit,
+ .ndo_set_mac_address = nr_set_mac_address,
+};
void nr_setup(struct net_device *dev)
{
dev->mtu = NR_MAX_PACKET_SIZE;
- dev->hard_start_xmit = nr_xmit;
- dev->open = nr_open;
- dev->stop = nr_close;
-
+ dev->netdev_ops = &nr_netdev_ops;
dev->header_ops = &nr_header_ops;
dev->hard_header_len = NR_NETWORK_LEN + NR_TRANSPORT_LEN;
dev->addr_len = AX25_ADDR_LEN;
dev->type = ARPHRD_NETROM;
- dev->set_mac_address = nr_set_mac_address;
/* New-style flags. */
dev->flags = IFF_NOARP;
-
- dev->get_stats = nr_get_stats;
}
diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c
index 13cb323f8c3..95bc49ddb8b 100644
--- a/net/phonet/af_phonet.c
+++ b/net/phonet/af_phonet.c
@@ -275,8 +275,6 @@ static inline int can_respond(struct sk_buff *skb)
return 0;
ph = pn_hdr(skb);
- if (phonet_address_get(skb->dev, ph->pn_rdev) != ph->pn_rdev)
- return 0; /* we are not the destination */
if (ph->pn_res == PN_PREFIX && !pskb_may_pull(skb, 5))
return 0;
if (ph->pn_res == PN_COMMGR) /* indications */
@@ -344,8 +342,8 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pkttype,
struct net_device *orig_dev)
{
+ struct net *net = dev_net(dev);
struct phonethdr *ph;
- struct sock *sk;
struct sockaddr_pn sa;
u16 len;
@@ -364,21 +362,21 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
skb_reset_transport_header(skb);
pn_skb_get_dst_sockaddr(skb, &sa);
- if (pn_sockaddr_get_addr(&sa) == 0)
- goto out; /* currently, we cannot be device 0 */
- sk = pn_find_sock_by_sa(dev_net(dev), &sa);
- if (sk == NULL) {
+ /* check if we are the destination */
+ if (phonet_address_lookup(net, pn_sockaddr_get_addr(&sa)) == 0) {
+ /* Phonet packet input */
+ struct sock *sk = pn_find_sock_by_sa(net, &sa);
+
+ if (sk)
+ return sk_receive_skb(sk, skb, 0);
+
if (can_respond(skb)) {
send_obj_unreachable(skb);
send_reset_indications(skb);
}
- goto out;
}
- /* Push data to the socket (or other sockets connected to it). */
- return sk_receive_skb(sk, skb, 0);
-
out:
kfree_skb(skb);
return NET_RX_DROP;
@@ -428,16 +426,18 @@ static int __init phonet_init(void)
{
int err;
+ err = phonet_device_init();
+ if (err)
+ return err;
+
err = sock_register(&phonet_proto_family);
if (err) {
printk(KERN_ALERT
"phonet protocol family initialization failed\n");
- return err;
+ goto err_sock;
}
- phonet_device_init();
dev_add_pack(&phonet_packet_type);
- phonet_netlink_register();
phonet_sysctl_init();
err = isi_register();
@@ -449,6 +449,7 @@ err:
phonet_sysctl_exit();
sock_unregister(PF_PHONET);
dev_remove_pack(&phonet_packet_type);
+err_sock:
phonet_device_exit();
return err;
}
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index 5491bf5e354..80a322d7790 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -28,32 +28,41 @@
#include <linux/netdevice.h>
#include <linux/phonet.h>
#include <net/sock.h>
+#include <net/netns/generic.h>
#include <net/phonet/pn_dev.h>
-/* when accessing, remember to lock with spin_lock(&pndevs.lock); */
-struct phonet_device_list pndevs = {
- .list = LIST_HEAD_INIT(pndevs.list),
- .lock = __SPIN_LOCK_UNLOCKED(pndevs.lock),
+struct phonet_net {
+ struct phonet_device_list pndevs;
};
+int phonet_net_id;
+
+struct phonet_device_list *phonet_device_list(struct net *net)
+{
+ struct phonet_net *pnn = net_generic(net, phonet_net_id);
+ return &pnn->pndevs;
+}
+
/* Allocate new Phonet device. */
static struct phonet_device *__phonet_device_alloc(struct net_device *dev)
{
+ struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
struct phonet_device *pnd = kmalloc(sizeof(*pnd), GFP_ATOMIC);
if (pnd == NULL)
return NULL;
pnd->netdev = dev;
bitmap_zero(pnd->addrs, 64);
- list_add(&pnd->list, &pndevs.list);
+ list_add(&pnd->list, &pndevs->list);
return pnd;
}
static struct phonet_device *__phonet_get(struct net_device *dev)
{
+ struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
struct phonet_device *pnd;
- list_for_each_entry(pnd, &pndevs.list, list) {
+ list_for_each_entry(pnd, &pndevs->list, list) {
if (pnd->netdev == dev)
return pnd;
}
@@ -68,32 +77,33 @@ static void __phonet_device_free(struct phonet_device *pnd)
struct net_device *phonet_device_get(struct net *net)
{
+ struct phonet_device_list *pndevs = phonet_device_list(net);
struct phonet_device *pnd;
struct net_device *dev;
- spin_lock_bh(&pndevs.lock);
- list_for_each_entry(pnd, &pndevs.list, list) {
+ spin_lock_bh(&pndevs->lock);
+ list_for_each_entry(pnd, &pndevs->list, list) {
dev = pnd->netdev;
BUG_ON(!dev);
- if (net_eq(dev_net(dev), net) &&
- (dev->reg_state == NETREG_REGISTERED) &&
+ if ((dev->reg_state == NETREG_REGISTERED) &&
((pnd->netdev->flags & IFF_UP)) == IFF_UP)
break;
dev = NULL;
}
if (dev)
dev_hold(dev);
- spin_unlock_bh(&pndevs.lock);
+ spin_unlock_bh(&pndevs->lock);
return dev;
}
int phonet_address_add(struct net_device *dev, u8 addr)
{
+ struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
struct phonet_device *pnd;
int err = 0;
- spin_lock_bh(&pndevs.lock);
+ spin_lock_bh(&pndevs->lock);
/* Find or create Phonet-specific device data */
pnd = __phonet_get(dev);
if (pnd == NULL)
@@ -102,31 +112,33 @@ int phonet_address_add(struct net_device *dev, u8 addr)
err = -ENOMEM;
else if (test_and_set_bit(addr >> 2, pnd->addrs))
err = -EEXIST;
- spin_unlock_bh(&pndevs.lock);
+ spin_unlock_bh(&pndevs->lock);
return err;
}
int phonet_address_del(struct net_device *dev, u8 addr)
{
+ struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
struct phonet_device *pnd;
int err = 0;
- spin_lock_bh(&pndevs.lock);
+ spin_lock_bh(&pndevs->lock);
pnd = __phonet_get(dev);
if (!pnd || !test_and_clear_bit(addr >> 2, pnd->addrs))
err = -EADDRNOTAVAIL;
else if (bitmap_empty(pnd->addrs, 64))
__phonet_device_free(pnd);
- spin_unlock_bh(&pndevs.lock);
+ spin_unlock_bh(&pndevs->lock);
return err;
}
/* Gets a source address toward a destination, through a interface. */
u8 phonet_address_get(struct net_device *dev, u8 addr)
{
+ struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
struct phonet_device *pnd;
- spin_lock_bh(&pndevs.lock);
+ spin_lock_bh(&pndevs->lock);
pnd = __phonet_get(dev);
if (pnd) {
BUG_ON(bitmap_empty(pnd->addrs, 64));
@@ -136,30 +148,31 @@ u8 phonet_address_get(struct net_device *dev, u8 addr)
addr = find_first_bit(pnd->addrs, 64) << 2;
} else
addr = PN_NO_ADDR;
- spin_unlock_bh(&pndevs.lock);
+ spin_unlock_bh(&pndevs->lock);
return addr;
}
int phonet_address_lookup(struct net *net, u8 addr)
{
+ struct phonet_device_list *pndevs = phonet_device_list(net);
struct phonet_device *pnd;
+ int err = -EADDRNOTAVAIL;
- spin_lock_bh(&pndevs.lock);
- list_for_each_entry(pnd, &pndevs.list, list) {
- if (!net_eq(dev_net(pnd->netdev), net))
- continue;
+ spin_lock_bh(&pndevs->lock);
+ list_for_each_entry(pnd, &pndevs->list, list) {
/* Don't allow unregistering devices! */
if ((pnd->netdev->reg_state != NETREG_REGISTERED) ||
((pnd->netdev->flags & IFF_UP)) != IFF_UP)
continue;
if (test_bit(addr >> 2, pnd->addrs)) {
- spin_unlock_bh(&pndevs.lock);
- return 0;
+ err = 0;
+ goto found;
}
}
- spin_unlock_bh(&pndevs.lock);
- return -EADDRNOTAVAIL;
+found:
+ spin_unlock_bh(&pndevs->lock);
+ return err;
}
/* notify Phonet of device events */
@@ -169,14 +182,16 @@ static int phonet_device_notify(struct notifier_block *me, unsigned long what,
struct net_device *dev = arg;
if (what == NETDEV_UNREGISTER) {
+ struct phonet_device_list *pndevs;
struct phonet_device *pnd;
/* Destroy phonet-specific device data */
- spin_lock_bh(&pndevs.lock);
+ pndevs = phonet_device_list(dev_net(dev));
+ spin_lock_bh(&pndevs->lock);
pnd = __phonet_get(dev);
if (pnd)
__phonet_device_free(pnd);
- spin_unlock_bh(&pndevs.lock);
+ spin_unlock_bh(&pndevs->lock);
}
return 0;
@@ -187,24 +202,52 @@ static struct notifier_block phonet_device_notifier = {
.priority = 0,
};
-/* Initialize Phonet devices list */
-void phonet_device_init(void)
+/* Per-namespace Phonet devices handling */
+static int phonet_init_net(struct net *net)
{
- register_netdevice_notifier(&phonet_device_notifier);
+ struct phonet_net *pnn = kmalloc(sizeof(*pnn), GFP_KERNEL);
+ if (!pnn)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&pnn->pndevs.list);
+ spin_lock_init(&pnn->pndevs.lock);
+ net_assign_generic(net, phonet_net_id, pnn);
+ return 0;
}
-void phonet_device_exit(void)
+static void phonet_exit_net(struct net *net)
{
+ struct phonet_net *pnn = net_generic(net, phonet_net_id);
struct phonet_device *pnd, *n;
- rtnl_unregister_all(PF_PHONET);
- rtnl_lock();
- spin_lock_bh(&pndevs.lock);
-
- list_for_each_entry_safe(pnd, n, &pndevs.list, list)
+ list_for_each_entry_safe(pnd, n, &pnn->pndevs.list, list)
__phonet_device_free(pnd);
- spin_unlock_bh(&pndevs.lock);
- rtnl_unlock();
+ kfree(pnn);
+}
+
+static struct pernet_operations phonet_net_ops = {
+ .init = phonet_init_net,
+ .exit = phonet_exit_net,
+};
+
+/* Initialize Phonet devices list */
+int __init phonet_device_init(void)
+{
+ int err = register_pernet_gen_device(&phonet_net_id, &phonet_net_ops);
+ if (err)
+ return err;
+
+ register_netdevice_notifier(&phonet_device_notifier);
+ err = phonet_netlink_register();
+ if (err)
+ phonet_device_exit();
+ return err;
+}
+
+void phonet_device_exit(void)
+{
+ rtnl_unregister_all(PF_PHONET);
unregister_netdevice_notifier(&phonet_device_notifier);
+ unregister_pernet_gen_device(phonet_net_id, &phonet_net_ops);
}
diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c
index 242fe8f8c32..1ceea1f9241 100644
--- a/net/phonet/pn_netlink.c
+++ b/net/phonet/pn_netlink.c
@@ -123,17 +123,16 @@ nla_put_failure:
static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
{
- struct net *net = sock_net(skb->sk);
+ struct phonet_device_list *pndevs;
struct phonet_device *pnd;
int dev_idx = 0, dev_start_idx = cb->args[0];
int addr_idx = 0, addr_start_idx = cb->args[1];
- spin_lock_bh(&pndevs.lock);
- list_for_each_entry(pnd, &pndevs.list, list) {
+ pndevs = phonet_device_list(sock_net(skb->sk));
+ spin_lock_bh(&pndevs->lock);
+ list_for_each_entry(pnd, &pndevs->list, list) {
u8 addr;
- if (!net_eq(dev_net(pnd->netdev), net))
- continue;
if (dev_idx > dev_start_idx)
addr_start_idx = 0;
if (dev_idx++ < dev_start_idx)
@@ -153,16 +152,21 @@ static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
}
out:
- spin_unlock_bh(&pndevs.lock);
+ spin_unlock_bh(&pndevs->lock);
cb->args[0] = dev_idx;
cb->args[1] = addr_idx;
return skb->len;
}
-void __init phonet_netlink_register(void)
+int __init phonet_netlink_register(void)
{
- rtnl_register(PF_PHONET, RTM_NEWADDR, addr_doit, NULL);
- rtnl_register(PF_PHONET, RTM_DELADDR, addr_doit, NULL);
- rtnl_register(PF_PHONET, RTM_GETADDR, NULL, getaddr_dumpit);
+ int err = __rtnl_register(PF_PHONET, RTM_NEWADDR, addr_doit, NULL);
+ if (err)
+ return err;
+
+ /* Further __rtnl_register() cannot fail */
+ __rtnl_register(PF_PHONET, RTM_DELADDR, addr_doit, NULL);
+ __rtnl_register(PF_PHONET, RTM_GETADDR, NULL, getaddr_dumpit);
+ return 0;
}
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 01392649b46..65013962658 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -1587,8 +1587,7 @@ static int __init rose_proto_init(void)
char name[IFNAMSIZ];
sprintf(name, "rose%d", i);
- dev = alloc_netdev(sizeof(struct net_device_stats),
- name, rose_setup);
+ dev = alloc_netdev(0, name, rose_setup);
if (!dev) {
printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate memory\n");
rc = -ENOMEM;
diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c
index 12cfcf09556..7dcf2569613 100644
--- a/net/rose/rose_dev.c
+++ b/net/rose/rose_dev.c
@@ -57,7 +57,7 @@ static int rose_rebuild_header(struct sk_buff *skb)
{
#ifdef CONFIG_INET
struct net_device *dev = skb->dev;
- struct net_device_stats *stats = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
unsigned char *bp = (unsigned char *)skb->data;
struct sk_buff *skbn;
unsigned int len;
@@ -133,7 +133,7 @@ static int rose_close(struct net_device *dev)
static int rose_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct net_device_stats *stats = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
if (!netif_running(dev)) {
printk(KERN_ERR "ROSE: rose_xmit - called when iface is down\n");
@@ -144,30 +144,28 @@ static int rose_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-static struct net_device_stats *rose_get_stats(struct net_device *dev)
-{
- return netdev_priv(dev);
-}
-
static const struct header_ops rose_header_ops = {
.create = rose_header,
.rebuild= rose_rebuild_header,
};
+static const struct net_device_ops rose_netdev_ops = {
+ .ndo_open = rose_open,
+ .ndo_stop = rose_close,
+ .ndo_start_xmit = rose_xmit,
+ .ndo_set_mac_address = rose_set_mac_address,
+};
+
void rose_setup(struct net_device *dev)
{
dev->mtu = ROSE_MAX_PACKET_SIZE - 2;
- dev->hard_start_xmit = rose_xmit;
- dev->open = rose_open;
- dev->stop = rose_close;
+ dev->netdev_ops = &rose_netdev_ops;
dev->header_ops = &rose_header_ops;
dev->hard_header_len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN;
dev->addr_len = ROSE_ADDR_LEN;
dev->type = ARPHRD_ROSE;
- dev->set_mac_address = rose_set_mac_address;
/* New-style flags. */
dev->flags = IFF_NOARP;
- dev->get_stats = rose_get_stats;
}
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index ceaa4aa066e..78622756669 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -97,8 +97,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
if (addr) {
addr->a.v6.sin6_family = AF_INET6;
addr->a.v6.sin6_port = 0;
- memcpy(&addr->a.v6.sin6_addr, &ifa->addr,
- sizeof(struct in6_addr));
+ ipv6_addr_copy(&addr->a.v6.sin6_addr, &ifa->addr);
addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex;
addr->valid = 1;
spin_lock_bh(&sctp_local_addr_lock);