* [PATCH 3/4] ibmveth: Add ethtool TSO handlers
From: Brian King @ 2007-07-19 15:48 UTC (permalink / raw)
To: santil; +Cc: rcjenn, netdev, linuxppc-dev, brking
In-Reply-To: <1184860086366-patch-mail.ibm.com>
Add handlers for get_tso and get_ufo to prevent errors being printed
by ethtool.
Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
---
linux-2.6-bjking1/drivers/net/ibmveth.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff -puN drivers/net/ibmveth.c~ibmveth_ethtool_get_tso drivers/net/ibmveth.c
--- linux-2.6/drivers/net/ibmveth.c~ibmveth_ethtool_get_tso 2007-07-19 08:39:31.000000000 -0500
+++ linux-2.6-bjking1/drivers/net/ibmveth.c 2007-07-19 08:39:31.000000000 -0500
@@ -761,7 +761,9 @@ static const struct ethtool_ops netdev_e
.get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ibmveth_set_tx_csum,
.get_rx_csum = ibmveth_get_rx_csum,
- .set_rx_csum = ibmveth_set_rx_csum
+ .set_rx_csum = ibmveth_set_rx_csum,
+ .get_tso = ethtool_op_get_tso,
+ .get_ufo = ethtool_op_get_ufo
};
static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
_
^ permalink raw reply
* [PATCH 4/4] ibmveth: Add ethtool driver stats hooks
From: Brian King @ 2007-07-19 15:48 UTC (permalink / raw)
To: santil; +Cc: rcjenn, netdev, linuxppc-dev, brking
In-Reply-To: <1184860086366-patch-mail.ibm.com>
Add ethtool hooks to ibmveth to retrieve driver statistics.
Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
---
linux-2.6-bjking1/drivers/net/ibmveth.c | 53 +++++++++++++++++++++++++++++++-
1 file changed, 52 insertions(+), 1 deletion(-)
diff -puN drivers/net/ibmveth.c~ibmveth_ethtool_driver_stats drivers/net/ibmveth.c
--- linux-2.6/drivers/net/ibmveth.c~ibmveth_ethtool_driver_stats 2007-07-19 08:39:35.000000000 -0500
+++ linux-2.6-bjking1/drivers/net/ibmveth.c 2007-07-19 08:39:35.000000000 -0500
@@ -112,6 +112,28 @@ MODULE_DESCRIPTION("IBM i/pSeries Virtua
MODULE_LICENSE("GPL");
MODULE_VERSION(ibmveth_driver_version);
+struct ibmveth_stat {
+ char name[ETH_GSTRING_LEN];
+ int offset;
+};
+
+#define IBMVETH_STAT_OFF(stat) offsetof(struct ibmveth_adapter, stat)
+#define IBMVETH_GET_STAT(a, off) *((u64 *)(((unsigned long)(a)) + off))
+
+struct ibmveth_stat ibmveth_stats[] = {
+ { "replenish_task_cycles", IBMVETH_STAT_OFF(replenish_task_cycles) },
+ { "replenish_no_mem", IBMVETH_STAT_OFF(replenish_no_mem) },
+ { "replenish_add_buff_failure", IBMVETH_STAT_OFF(replenish_add_buff_failure) },
+ { "replenish_add_buff_success", IBMVETH_STAT_OFF(replenish_add_buff_success) },
+ { "rx_invalid_buffer", IBMVETH_STAT_OFF(rx_invalid_buffer) },
+ { "rx_no_buffer", IBMVETH_STAT_OFF(rx_no_buffer) },
+ { "tx_multidesc_send", IBMVETH_STAT_OFF(tx_multidesc_send) },
+ { "tx_linearized", IBMVETH_STAT_OFF(tx_linearized) },
+ { "tx_linearize_failed", IBMVETH_STAT_OFF(tx_linearize_failed) },
+ { "tx_map_failed", IBMVETH_STAT_OFF(tx_map_failed) },
+ { "tx_send_failed", IBMVETH_STAT_OFF(tx_send_failed) }
+};
+
/* simple methods of getting data from the current rxq entry */
static inline int ibmveth_rxq_pending_buffer(struct ibmveth_adapter *adapter)
{
@@ -753,6 +775,32 @@ static u32 ibmveth_get_rx_csum(struct ne
return adapter->rx_csum;
}
+static void ibmveth_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ int i;
+
+ if (stringset != ETH_SS_STATS)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(ibmveth_stats); i++, data += ETH_GSTRING_LEN)
+ memcpy(data, ibmveth_stats[i].name, ETH_GSTRING_LEN);
+}
+
+static int ibmveth_get_stats_count(struct net_device *dev)
+{
+ return ARRAY_SIZE(ibmveth_stats);
+}
+
+static void ibmveth_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ int i;
+ struct ibmveth_adapter *adapter = dev->priv;
+
+ for (i = 0; i < ARRAY_SIZE(ibmveth_stats); i++)
+ data[i] = IBMVETH_GET_STAT(adapter, ibmveth_stats[i].offset);
+}
+
static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_settings = netdev_get_settings,
@@ -763,7 +811,10 @@ static const struct ethtool_ops netdev_e
.get_rx_csum = ibmveth_get_rx_csum,
.set_rx_csum = ibmveth_set_rx_csum,
.get_tso = ethtool_op_get_tso,
- .get_ufo = ethtool_op_get_ufo
+ .get_ufo = ethtool_op_get_ufo,
+ .get_strings = ibmveth_get_strings,
+ .get_stats_count = ibmveth_get_stats_count,
+ .get_ethtool_stats = ibmveth_get_ethtool_stats
};
static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
diff -puN drivers/net/ibmveth.h~ibmveth_ethtool_driver_stats drivers/net/ibmveth.h
_
^ permalink raw reply
* [PATCH 2/4] ibmveth: Implement ethtool hooks to enable/disable checksum offload
From: Brian King @ 2007-07-19 15:48 UTC (permalink / raw)
To: santil; +Cc: rcjenn, netdev, linuxppc-dev, brking
In-Reply-To: <1184860086366-patch-mail.ibm.com>
This patch adds the appropriate ethtool hooks to allow for enabling/disabling
of hypervisor assisted checksum offload for TCP.
Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
---
linux-2.6-bjking1/drivers/net/ibmveth.c | 120 +++++++++++++++++++++++++++++++-
linux-2.6-bjking1/drivers/net/ibmveth.h | 1
2 files changed, 119 insertions(+), 2 deletions(-)
diff -puN drivers/net/ibmveth.c~ibmveth_csum_offload_ethtool drivers/net/ibmveth.c
--- linux-2.6/drivers/net/ibmveth.c~ibmveth_csum_offload_ethtool 2007-07-19 08:38:27.000000000 -0500
+++ linux-2.6-bjking1/drivers/net/ibmveth.c 2007-07-19 08:39:08.000000000 -0500
@@ -641,12 +641,127 @@ static u32 netdev_get_link(struct net_de
return 1;
}
+static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data)
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+
+ if (data)
+ adapter->rx_csum = 1;
+ else {
+ adapter->rx_csum = 0;
+ dev->features &= ~NETIF_F_IP_CSUM;
+ }
+}
+
+static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data)
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+
+ if (data) {
+ dev->features |= NETIF_F_IP_CSUM;
+ adapter->rx_csum = 1;
+ } else
+ dev->features &= ~NETIF_F_IP_CSUM;
+}
+
+static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
+ void (*done) (struct net_device *, u32))
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+ union ibmveth_illan_attributes set_attr, clr_attr, ret_attr;
+ long ret;
+ int rc1 = 0, rc2 = 0;
+ int restart = 0;
+
+ if (netif_running(dev)) {
+ restart = 1;
+ adapter->pool_config = 1;
+ ibmveth_close(dev);
+ adapter->pool_config = 0;
+ }
+
+ set_attr.desc = 0;
+ clr_attr.desc = 0;
+
+ if (data)
+ set_attr.fields.tcp_csum_offload_ipv4 = 1;
+ else
+ clr_attr.fields.tcp_csum_offload_ipv4 = 1;
+
+ ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr.desc);
+
+ if (ret == H_SUCCESS && !ret_attr.fields.active_trunk &&
+ !ret_attr.fields.trunk_priority &&
+ ret_attr.fields.csum_offload_padded_pkt_support) {
+ ret = h_illan_attributes(adapter->vdev->unit_address, clr_attr.desc,
+ set_attr.desc, &ret_attr.desc);
+
+ if (ret != H_SUCCESS) {
+ rc1 = -EIO;
+ ibmveth_error_printk("unable to change checksum offload settings."
+ " %d rc=%ld\n", data, ret);
+
+ ret = h_illan_attributes(adapter->vdev->unit_address,
+ set_attr.desc, clr_attr.desc, &ret_attr.desc);
+ } else
+ done(dev, data);
+ } else {
+ rc1 = -EIO;
+ ibmveth_error_printk("unable to change checksum offload settings."
+ " %d rc=%ld ret_attr=%lx\n", data, ret, ret_attr.desc);
+ }
+
+ if (restart)
+ rc2 = ibmveth_open(dev);
+
+ return rc1 ? rc1 : rc2;
+}
+
+static int ibmveth_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+
+ if (data && adapter->rx_csum)
+ return 0;
+ if (!data && !adapter->rx_csum)
+ return 0;
+
+ return ibmveth_set_csum_offload(dev, data, ibmveth_set_rx_csum_flags);
+}
+
+static int ibmveth_set_tx_csum(struct net_device *dev, u32 data)
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+ int rc = 0;
+
+ if (data && (dev->features & NETIF_F_IP_CSUM))
+ return 0;
+ if (!data && !(dev->features & NETIF_F_IP_CSUM))
+ return 0;
+
+ if (data && !adapter->rx_csum)
+ rc = ibmveth_set_csum_offload(dev, data, ibmveth_set_tx_csum_flags);
+ else
+ ibmveth_set_tx_csum_flags(dev, data);
+
+ return rc;
+}
+
+static u32 ibmveth_get_rx_csum(struct net_device *dev)
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+ return adapter->rx_csum;
+}
+
static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_settings = netdev_get_settings,
.get_link = netdev_get_link,
.get_sg = ethtool_op_get_sg,
.get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ibmveth_set_tx_csum,
+ .get_rx_csum = ibmveth_get_rx_csum,
+ .set_rx_csum = ibmveth_set_rx_csum
};
static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -1104,9 +1219,10 @@ static int __devinit ibmveth_probe(struc
ret = h_illan_attributes(dev->unit_address, 0, set_attr.desc,
&ret_attr.desc);
- if (ret == H_SUCCESS)
+ if (ret == H_SUCCESS) {
+ adapter->rx_csum = 1;
netdev->features |= NETIF_F_IP_CSUM;
- else
+ } else
ret = h_illan_attributes(dev->unit_address, set_attr.desc,
0, &ret_attr.desc);
}
diff -puN drivers/net/ibmveth.h~ibmveth_csum_offload_ethtool drivers/net/ibmveth.h
--- linux-2.6/drivers/net/ibmveth.h~ibmveth_csum_offload_ethtool 2007-07-19 08:38:27.000000000 -0500
+++ linux-2.6-bjking1/drivers/net/ibmveth.h 2007-07-19 08:38:27.000000000 -0500
@@ -140,6 +140,7 @@ struct ibmveth_adapter {
struct ibmveth_buff_pool rx_buff_pool[IbmVethNumBufferPools];
struct ibmveth_rx_q rx_queue;
int pool_config;
+ int rx_csum;
/* adapter specific stats */
u64 replenish_task_cycles;
_
^ permalink raw reply
* [PATCH 1/4] ibmveth: Enable TCP checksum offload
From: Brian King @ 2007-07-19 15:48 UTC (permalink / raw)
To: santil; +Cc: rcjenn, netdev, linuxppc-dev, brking
This patchset enables TCP checksum offload support for IPV4
on ibmveth. This completely eliminates the generation and checking of
the checksum for packets that are completely virtual and never
touch a physical network. A simple TCP_STREAM netperf run on
a virtual network with maximum mtu set yielded a ~30% increase
in throughput. This feature is enabled by default on systems that
support it, but can be disabled with a module option.
Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
---
linux-2.6-bjking1/drivers/net/ibmveth.c | 53 ++++++++++++++++++++++++++++++++
linux-2.6-bjking1/drivers/net/ibmveth.h | 41 +++++++++++++++++++++++-
2 files changed, 92 insertions(+), 2 deletions(-)
diff -puN drivers/net/ibmveth.c~ibmveth_csum_offload drivers/net/ibmveth.c
--- linux-2.6/drivers/net/ibmveth.c~ibmveth_csum_offload 2007-07-18 16:55:06.000000000 -0500
+++ linux-2.6-bjking1/drivers/net/ibmveth.c 2007-07-19 08:36:05.000000000 -0500
@@ -47,6 +47,8 @@
#include <linux/mm.h>
#include <linux/ethtool.h>
#include <linux/proc_fs.h>
+#include <linux/in.h>
+#include <linux/ip.h>
#include <asm/semaphore.h>
#include <asm/hvcall.h>
#include <asm/atomic.h>
@@ -131,6 +133,11 @@ static inline int ibmveth_rxq_frame_leng
return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].length);
}
+static inline int ibmveth_rxq_csum_good(struct ibmveth_adapter *adapter)
+{
+ return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].csum_good);
+}
+
/* setup the initial settings for a buffer pool */
static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size, u32 pool_active)
{
@@ -684,6 +691,24 @@ static int ibmveth_start_xmit(struct sk_
desc[0].fields.length, DMA_TO_DEVICE);
desc[0].fields.valid = 1;
+ if (skb->ip_summed == CHECKSUM_PARTIAL &&
+ ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) {
+ ibmveth_error_printk("tx: failed to checksum packet\n");
+ tx_dropped++;
+ goto out;
+ }
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ unsigned char *buf = skb_transport_header(skb) + skb->csum_offset;
+
+ desc[0].fields.no_csum = 1;
+ desc[0].fields.csum_good = 1;
+
+ /* Need to zero out the checksum */
+ buf[0] = 0;
+ buf[1] = 0;
+ }
+
if(dma_mapping_error(desc[0].fields.address)) {
ibmveth_error_printk("tx: unable to map initial fragment\n");
tx_map_failed++;
@@ -702,6 +727,10 @@ static int ibmveth_start_xmit(struct sk_
frag->size, DMA_TO_DEVICE);
desc[curfrag+1].fields.length = frag->size;
desc[curfrag+1].fields.valid = 1;
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ desc[curfrag+1].fields.no_csum = 1;
+ desc[curfrag+1].fields.csum_good = 1;
+ }
if(dma_mapping_error(desc[curfrag+1].fields.address)) {
ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag);
@@ -792,7 +821,11 @@ static int ibmveth_poll(struct net_devic
} else {
int length = ibmveth_rxq_frame_length(adapter);
int offset = ibmveth_rxq_frame_offset(adapter);
+ int csum_good = ibmveth_rxq_csum_good(adapter);
+
skb = ibmveth_rxq_get_buffer(adapter);
+ if (csum_good)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
ibmveth_rxq_harvest_buffer(adapter);
@@ -962,8 +995,10 @@ static void ibmveth_poll_controller(stru
static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
{
int rc, i;
+ long ret;
struct net_device *netdev;
struct ibmveth_adapter *adapter = NULL;
+ union ibmveth_illan_attributes set_attr, ret_attr;
unsigned char *mac_addr_p;
unsigned int *mcastFilterSize_p;
@@ -1058,6 +1093,24 @@ static int __devinit ibmveth_probe(struc
ibmveth_debug_printk("registering netdev...\n");
+ ret = h_illan_attributes(dev->unit_address, 0, 0, &ret_attr.desc);
+
+ if (ret == H_SUCCESS && !ret_attr.fields.active_trunk &&
+ !ret_attr.fields.trunk_priority &&
+ ret_attr.fields.csum_offload_padded_pkt_support) {
+ set_attr.desc = 0;
+ set_attr.fields.tcp_csum_offload_ipv4 = 1;
+
+ ret = h_illan_attributes(dev->unit_address, 0, set_attr.desc,
+ &ret_attr.desc);
+
+ if (ret == H_SUCCESS)
+ netdev->features |= NETIF_F_IP_CSUM;
+ else
+ ret = h_illan_attributes(dev->unit_address, set_attr.desc,
+ 0, &ret_attr.desc);
+ }
+
rc = register_netdev(netdev);
if(rc) {
diff -puN drivers/net/ibmveth.h~ibmveth_csum_offload drivers/net/ibmveth.h
--- linux-2.6/drivers/net/ibmveth.h~ibmveth_csum_offload 2007-07-18 16:55:06.000000000 -0500
+++ linux-2.6-bjking1/drivers/net/ibmveth.h 2007-07-19 08:35:25.000000000 -0500
@@ -67,6 +67,21 @@ static inline long h_send_logical_lan(un
return rc;
}
+static inline long h_illan_attributes(unsigned long unit_address,
+ unsigned long reset_mask, unsigned long set_mask,
+ unsigned long *ret_attributes)
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(H_ILLAN_ATTRIBUTES, retbuf, unit_address,
+ reset_mask, set_mask);
+
+ *ret_attributes = retbuf[0];
+
+ return rc;
+}
+
#define h_multicast_ctrl(ua, cmd, mac) \
plpar_hcall_norets(H_MULTICAST_CTRL, ua, cmd, mac)
@@ -144,7 +159,9 @@ struct ibmveth_adapter {
struct ibmveth_buf_desc_fields {
u32 valid : 1;
u32 toggle : 1;
- u32 reserved : 6;
+ u32 reserved : 4;
+ u32 no_csum : 1;
+ u32 csum_good : 1;
u32 length : 24;
u32 address;
};
@@ -154,10 +171,30 @@ union ibmveth_buf_desc {
struct ibmveth_buf_desc_fields fields;
};
+struct ibmveth_illan_attributes_fields {
+ u32 reserved;
+ u32 reserved2 : 18;
+ u32 csum_offload_padded_pkt_support : 1;
+ u32 reserved3 : 1;
+ u32 trunk_priority : 4;
+ u32 reserved4 : 5;
+ u32 tcp_csum_offload_ipv6 : 1;
+ u32 tcp_csum_offload_ipv4 : 1;
+ u32 active_trunk : 1;
+};
+
+union ibmveth_illan_attributes {
+ u64 desc;
+ struct ibmveth_illan_attributes_fields fields;
+};
+
struct ibmveth_rx_q_entry {
u16 toggle : 1;
u16 valid : 1;
- u16 reserved : 14;
+ u16 reserved : 4;
+ u16 no_csum : 1;
+ u16 csum_good : 1;
+ u16 reserved2 : 8;
u16 offset;
u32 length;
u64 correlator;
_
^ permalink raw reply
* [PATCH 1/4] ibmveth: Enable TCP checksum offload
From: Brian King @ 2007-07-19 15:48 UTC (permalink / raw)
To: santil; +Cc: linuxppc-dev, rcjenn, brking, netdev
This patchset enables TCP checksum offload support for IPV4
on ibmveth. This completely eliminates the generation and checking of
the checksum for packets that are completely virtual and never
touch a physical network. A simple TCP_STREAM netperf run on
a virtual network with maximum mtu set yielded a ~30% increase
in throughput. This feature is enabled by default on systems that
support it, but can be disabled with a module option.
Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
---
linux-2.6-bjking1/drivers/net/ibmveth.c | 53 ++++++++++++++++++++++++++++++++
linux-2.6-bjking1/drivers/net/ibmveth.h | 41 +++++++++++++++++++++++-
2 files changed, 92 insertions(+), 2 deletions(-)
diff -puN drivers/net/ibmveth.c~ibmveth_csum_offload drivers/net/ibmveth.c
--- linux-2.6/drivers/net/ibmveth.c~ibmveth_csum_offload 2007-07-18 16:55:06.000000000 -0500
+++ linux-2.6-bjking1/drivers/net/ibmveth.c 2007-07-19 08:36:05.000000000 -0500
@@ -47,6 +47,8 @@
#include <linux/mm.h>
#include <linux/ethtool.h>
#include <linux/proc_fs.h>
+#include <linux/in.h>
+#include <linux/ip.h>
#include <asm/semaphore.h>
#include <asm/hvcall.h>
#include <asm/atomic.h>
@@ -131,6 +133,11 @@ static inline int ibmveth_rxq_frame_leng
return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].length);
}
+static inline int ibmveth_rxq_csum_good(struct ibmveth_adapter *adapter)
+{
+ return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].csum_good);
+}
+
/* setup the initial settings for a buffer pool */
static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size, u32 pool_active)
{
@@ -684,6 +691,24 @@ static int ibmveth_start_xmit(struct sk_
desc[0].fields.length, DMA_TO_DEVICE);
desc[0].fields.valid = 1;
+ if (skb->ip_summed == CHECKSUM_PARTIAL &&
+ ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) {
+ ibmveth_error_printk("tx: failed to checksum packet\n");
+ tx_dropped++;
+ goto out;
+ }
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ unsigned char *buf = skb_transport_header(skb) + skb->csum_offset;
+
+ desc[0].fields.no_csum = 1;
+ desc[0].fields.csum_good = 1;
+
+ /* Need to zero out the checksum */
+ buf[0] = 0;
+ buf[1] = 0;
+ }
+
if(dma_mapping_error(desc[0].fields.address)) {
ibmveth_error_printk("tx: unable to map initial fragment\n");
tx_map_failed++;
@@ -702,6 +727,10 @@ static int ibmveth_start_xmit(struct sk_
frag->size, DMA_TO_DEVICE);
desc[curfrag+1].fields.length = frag->size;
desc[curfrag+1].fields.valid = 1;
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ desc[curfrag+1].fields.no_csum = 1;
+ desc[curfrag+1].fields.csum_good = 1;
+ }
if(dma_mapping_error(desc[curfrag+1].fields.address)) {
ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag);
@@ -792,7 +821,11 @@ static int ibmveth_poll(struct net_devic
} else {
int length = ibmveth_rxq_frame_length(adapter);
int offset = ibmveth_rxq_frame_offset(adapter);
+ int csum_good = ibmveth_rxq_csum_good(adapter);
+
skb = ibmveth_rxq_get_buffer(adapter);
+ if (csum_good)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
ibmveth_rxq_harvest_buffer(adapter);
@@ -962,8 +995,10 @@ static void ibmveth_poll_controller(stru
static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
{
int rc, i;
+ long ret;
struct net_device *netdev;
struct ibmveth_adapter *adapter = NULL;
+ union ibmveth_illan_attributes set_attr, ret_attr;
unsigned char *mac_addr_p;
unsigned int *mcastFilterSize_p;
@@ -1058,6 +1093,24 @@ static int __devinit ibmveth_probe(struc
ibmveth_debug_printk("registering netdev...\n");
+ ret = h_illan_attributes(dev->unit_address, 0, 0, &ret_attr.desc);
+
+ if (ret == H_SUCCESS && !ret_attr.fields.active_trunk &&
+ !ret_attr.fields.trunk_priority &&
+ ret_attr.fields.csum_offload_padded_pkt_support) {
+ set_attr.desc = 0;
+ set_attr.fields.tcp_csum_offload_ipv4 = 1;
+
+ ret = h_illan_attributes(dev->unit_address, 0, set_attr.desc,
+ &ret_attr.desc);
+
+ if (ret == H_SUCCESS)
+ netdev->features |= NETIF_F_IP_CSUM;
+ else
+ ret = h_illan_attributes(dev->unit_address, set_attr.desc,
+ 0, &ret_attr.desc);
+ }
+
rc = register_netdev(netdev);
if(rc) {
diff -puN drivers/net/ibmveth.h~ibmveth_csum_offload drivers/net/ibmveth.h
--- linux-2.6/drivers/net/ibmveth.h~ibmveth_csum_offload 2007-07-18 16:55:06.000000000 -0500
+++ linux-2.6-bjking1/drivers/net/ibmveth.h 2007-07-19 08:35:25.000000000 -0500
@@ -67,6 +67,21 @@ static inline long h_send_logical_lan(un
return rc;
}
+static inline long h_illan_attributes(unsigned long unit_address,
+ unsigned long reset_mask, unsigned long set_mask,
+ unsigned long *ret_attributes)
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(H_ILLAN_ATTRIBUTES, retbuf, unit_address,
+ reset_mask, set_mask);
+
+ *ret_attributes = retbuf[0];
+
+ return rc;
+}
+
#define h_multicast_ctrl(ua, cmd, mac) \
plpar_hcall_norets(H_MULTICAST_CTRL, ua, cmd, mac)
@@ -144,7 +159,9 @@ struct ibmveth_adapter {
struct ibmveth_buf_desc_fields {
u32 valid : 1;
u32 toggle : 1;
- u32 reserved : 6;
+ u32 reserved : 4;
+ u32 no_csum : 1;
+ u32 csum_good : 1;
u32 length : 24;
u32 address;
};
@@ -154,10 +171,30 @@ union ibmveth_buf_desc {
struct ibmveth_buf_desc_fields fields;
};
+struct ibmveth_illan_attributes_fields {
+ u32 reserved;
+ u32 reserved2 : 18;
+ u32 csum_offload_padded_pkt_support : 1;
+ u32 reserved3 : 1;
+ u32 trunk_priority : 4;
+ u32 reserved4 : 5;
+ u32 tcp_csum_offload_ipv6 : 1;
+ u32 tcp_csum_offload_ipv4 : 1;
+ u32 active_trunk : 1;
+};
+
+union ibmveth_illan_attributes {
+ u64 desc;
+ struct ibmveth_illan_attributes_fields fields;
+};
+
struct ibmveth_rx_q_entry {
u16 toggle : 1;
u16 valid : 1;
- u16 reserved : 14;
+ u16 reserved : 4;
+ u16 no_csum : 1;
+ u16 csum_good : 1;
+ u16 reserved2 : 8;
u16 offset;
u32 length;
u64 correlator;
_
^ permalink raw reply
* Re: Linux, tcpdump and vlan
From: andrei radulescu-banu @ 2007-07-19 15:47 UTC (permalink / raw)
To: Patrick McHardy, Stephen Hemminger
Cc: Krzysztof Halasa, linux-kernel, Linux Netdev List
The consensus seems to be that skb's need to carry vlan accelerated tags in their cb's, on rx as well as tx. VLAN_TX_SKB_CB() is perfect for that.
> [Patrick] On the TX path, it could simply use the CB, but this is actually
also wrong (for both macvlan and real devices) since qdiscs have
ownership of the skb in between, and at least netem *does* modify
the CB, breaking VLAN.
Thanks for pointing that out... It appears to me that qdisc/netem already breaks the vlan implementation, in the path
vlan_dev_hwaccel_hard_start_xmit(): sets accelerated vlan tag in skb->cb, calls
dev_queue_xmit(): may pass skb to qdisc/netem, which may mangle skb->cb before calling
dev->hard_start_xmit(), resulting in a tx frame without its vlan tag.
So netem needs to look for hw accelerated vlan metadata and insert it in the skb... Don't see any other way around this.
> [Patrick] Your suggestion of disabling VLAN acceleration in promiscuous
mode sounds like a reasonable solution until then ..
I was rather thinking of keeping hw vlan acceleration in promiscuous mode. Upon becoming promisc, the driver will be changed to disable vlan filters - it will reenable them when leaving promisc mode.
My 2 cents on vlan hw acceleration: it does not save much in computing cycles, if software is written carefully. It is vlan filtering that saves computing time.
> [Ben] I think a better method would be to allow disabling VLAN HW accel for a NIC with ethtool.
This requires changes to ethtool and e1000 driver, +other drivers. It is a handy thing to have. I don't view it as a solution to tcpdump - or to the vlan bridging problem. One concern: if we're switching hw accel mode on the fly, we need to carefully protect tx frames that are just about going out and have already been set up for the opposite mode.
Any comments on what is the expected behavior of 'tcpdump -i eth0.2' vs. 'tcpdump -i eth0'?
Andrei Radulescu-Banu
Brix Networks
____________________________________________________________________________________
Need a vacation? Get great deals
to amazing places on Yahoo! Travel.
http://travel.yahoo.com/
^ permalink raw reply
* Re: Linux, tcpdump and vlan
From: Krzysztof Halasa @ 2007-07-19 15:45 UTC (permalink / raw)
To: Stephen Hemminger
Cc: Patrick McHardy, andrei radulescu-banu, linux-kernel,
Linux Netdev List
In-Reply-To: <20070719160033.628f39e1@oldman.hamilton.local>
Stephen Hemminger <shemminger@linux-foundation.org> writes:
> Not at runtime, acceleration is always on if you compile kernel with vlan
> support. That is a design mistake as far as I can tell.
I think so.
>> However seeing unknown tags on master device (with tcpdump etc)
>> would certainly be useful.
>
> Only in promiscuous mode. In some sense tag is part of the mac address.
Well, in "some sense" maybe, though the MAC address is rather
strictly defined to be a 6-octet value. I can live with
promiscous anyway, it's really minor issue.
--
Krzysztof Halasa
^ permalink raw reply
* Re: [PATCH] net/, drivers/net/ , missing EXPERIMENTAL in menus
From: Randy Dunlap @ 2007-07-19 15:31 UTC (permalink / raw)
To: Robert P. J. Day
Cc: Stefan Richter, Adrian Bunk, Jeff Garzik, Gabriel C,
Linux Kernel Mailing List, netdev
In-Reply-To: <Pine.LNX.4.64.0707190523001.19216@localhost.localdomain>
On Thu, 19 Jul 2007 05:25:30 -0400 (EDT) Robert P. J. Day wrote:
> On Thu, 19 Jul 2007, Stefan Richter wrote:
>
> > Robert P. J. Day wrote:
> > > On Thu, 19 Jul 2007, Adrian Bunk wrote:
> > >
> > > ...
> > >> I would consider it more ugly to special case this and that in the
> > >> kconfig code when plain dependencies already offer exactly the same
> > >> functionality...
> > >
> > > well, this is the *third* time i've proposed adding this kind of
> > > feature so, at this point, i've really given up caring about it. if
> > > someone wants to do this, have at it. i have better things to do than
> > > to keep suggesting it and getting nowhere with it.
> >
> > For better or worse, it can often be observed that feature requests
> > don't set anything in motion until a first patch is sent. Even a
> > patch that is far from perfect can get things going really quickly.
> > (If the requested feature makes sense to other people.)
>
> i *did* submit a preliminary patch once upon a time, and it
> (predictably) went nowhere. so, if someone else wants to pick this up
> and do something with it, you have my blessing. life's too short to
> keep wasting time on this.
I think that Stefan means a patch to the kconfig source code,
not the the Kconfig files. Good luck. I'd still like to see it.
---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
^ permalink raw reply
* Re: kmap_atomic() oopses in current mainline
From: Dan Williams @ 2007-07-19 15:23 UTC (permalink / raw)
To: Evgeniy Polyakov; +Cc: Andrew Morton, netdev, linux-kernel-announce
In-Reply-To: <20070719100132.GC15839@2ka.mipt.ru>
On 7/19/07, Evgeniy Polyakov <johnpol@2ka.mipt.ru> wrote:
> On Thu, Jul 19, 2007 at 02:38:31AM -0700, Andrew Morton (akpm@linux-foundation.org) wrote:
> > > > is very wrong if both ASYNC_TX_KMAP_DST and ASYNC_TX_KMAP_SRC can ever be
> > > > set. We'll end up using the same kmap slot for both src add dest and we
> > > > get either corrupted data or a BUG.
> > >
> > > So far it can not since the only user is raid code, which only allows to
> > > perform either reading from bio or writing into one, which requires only
> > > one mapping.
> >
> > hm, so we got lucky?
>
> I would say it was intentionally, current code can perform only one
> operation in a time. Of course changing KM_USER from 0 to 1 in second
> kmap_atomic will not force oceans to run out of coasts.
>
> Kind of:
>
> diff --git a/crypto/async_tx/async_memcpy.c b/crypto/async_tx/async_memcpy.c
> index a973f4e..a48c7f3 100644
> --- a/crypto/async_tx/async_memcpy.c
> +++ b/crypto/async_tx/async_memcpy.c
> @@ -94,7 +94,7 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
> dest_buf = page_address(dest) + dest_offset;
>
> if (flags & ASYNC_TX_KMAP_SRC)
> - src_buf = kmap_atomic(src, KM_USER0) + src_offset;
> + src_buf = kmap_atomic(src, KM_USER1) + src_offset;
> else
> src_buf = page_address(src) + src_offset;
>
> @@ -104,7 +104,7 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
> kunmap_atomic(dest_buf, KM_USER0);
>
> if (flags & ASYNC_TX_KMAP_SRC)
> - kunmap_atomic(src_buf, KM_USER0);
> + kunmap_atomic(src_buf, KM_USER1);
>
> async_tx_sync_epilog(flags, depend_tx, cb_fn, cb_param);
> }
>
> > > Btw, shouldn't it always be kmap_atomic() even if flag is not set.
> > > That pages are usual one returned by alloc_page().
> >
> > The code would work OK if the kmap_atomic()s were unconditional, but it
> > would be a bit more expensive if the page is in highmem and we don't
> > actually intend to access it with the CPU.
> >
> > kmap_atomic() against a non-highmem page is basically free: just an
> > additional test_bit().
>
Always kmap'ing the page is the way to go, since in this path the page
is always accessed with the CPU. This also allows these ASYNC_TX_
flags to be killed off as they are not necessary. I'll cook up a
patch, and be more careful about my kmap usage going forward.
> As far as I recall there was an intention to do async memory copy to
> userspace, so likely kmapping is a good idea.
>
> --
> Evgeniy Polyakov
Thanks,
Dan
^ permalink raw reply
* Re: Linux, tcpdump and vlan
From: Stephen Hemminger @ 2007-07-19 15:20 UTC (permalink / raw)
To: Krzysztof Halasa
Cc: Patrick McHardy, andrei radulescu-banu, linux-kernel,
Linux Netdev List
In-Reply-To: <m3k5swbhfv.fsf@maximus.localdomain>
On Thu, 19 Jul 2007 16:23:48 +0200
Krzysztof Halasa <khc@pm.waw.pl> wrote:
> Stephen Hemminger <shemminger@linux-foundation.org> writes:
>
> > 1) non-accelerated device
> > * all frames show in promiscious mode
> > * tag is part of the frame that shows up
> > in tcpdump, and then gets stripped by the 8021q module.
>
> Sure. It's IMHO good and working, modulo the tag being removed
> on the master device (optional cloning or something, IIRC).
>
> > 2) rx tag stripping device
> > * all frames show in promiscious mode
> > * tag is in skb but NOT passed to tcpdump
> > 3) rx vlan acceleration
> > * only frames that for vlan's that are registered show up
> > in promisicous mode
> > * tag is in skb but NOT passed to tcpdump
>
> I wasn't aware of devices doing 3. Aren't we able to tell them
> to receive all packets anyway (even unknown VLANs#)?
See NETIF_F_HW_VLAN_FILTER (e1000, etc).
> > Unfortunately, the tag is lost as part of the VLAN acceleration process
> > so it is not a simple matter of changing code in AF_PACKET receive
> > to restore the tag.
>
> I'm not sure if we really want it. If needed we can disable
> acceleration, can't we? While accelerated we can see the packets
> (without tags) on logical devices.
Not at runtime, acceleration is always on if you compile kernel with vlan
support. That is a design mistake as far as I can tell.
> However seeing unknown tags on master device (with tcpdump etc)
> would certainly be useful.
Only in promiscuous mode. In some sense tag is part of the mac address.
^ permalink raw reply
* Re: Races in net_rx_action vs netpoll?
From: Olaf Kirch @ 2007-07-19 15:19 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20070711.193320.102574858.davem@davemloft.net>
On Thursday 12 July 2007 04:33, David Miller wrote:
> I'll add merge your patch with a target of 2.6.23
>
> If you really want, after this patch has sat in 2.6.23 for a while
> and got some good testing, we can consider a submission for -stable.
Okay, those of you who followed the discussion on lkml will have
read why this patch breaks on e1000.
Short summary: some NIC drivers expect that there is a one-to-one
relation between calls to net_rx_schedule (where we put the device
on the poll list) and netif_rx_complete (where it's supposed to be
taken off the list). The e1000 is such a beast. Not sure if other
drivers make the same assumption re NAPI.
So: should a driver be allowed to rely on this behavior? Or should
I go and look for another fix to the poll_napi issue?
I keep coming back to the question Jarek asked - why does netpoll
want to call dev->poll() anyway? I dug around a little and it
seems the original idea was to do this only if netpoll_poll was
running on the CPU the netdevice was scheduled to.
So one way to fix the problem is to add a dev->poll_cpu field
that tells us on which CPU's poll list it has been added - and
check for this in poll_napi.
Comments?
David, should I submit an updated patch for 2.6.23, or do you
prefer to yank the patch now and try again for 2.6.24?
Olaf
--
Olaf Kirch | --- o --- Nous sommes du soleil we love when we play
okir@lst.de | / | \ sol.dhoop.naytheet.ah kin.ir.samse.qurax
^ permalink raw reply
* Re: [PATCH 1/2] nbd: use list_for_each_entry_safe to make it more consolidated and readable
From: Paul Clements @ 2007-07-19 15:12 UTC (permalink / raw)
To: Denis Cheng
Cc: netdev, linux-kernel, Pavel Machek, Steven Whitehouse,
Andrew Morton
In-Reply-To: <11848376711601-git-send-email-crquan@gmail.com>
Denis Cheng wrote:
> Thus the traverse of the loop may delete nodes, use the safe version.
>
> Signed-off-by: Denis Cheng <crquan@gmail.com>
> ---
> drivers/block/nbd.c | 6 ++----
> 1 files changed, 2 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
> index c129510..86639c0 100644
> --- a/drivers/block/nbd.c
> +++ b/drivers/block/nbd.c
> @@ -237,8 +237,7 @@ error_out:
>
> static struct request *nbd_find_request(struct nbd_device *lo, char *handle)
> {
> - struct request *req;
> - struct list_head *tmp;
> + struct request *req, *n;
> struct request *xreq;
> int err;
>
> @@ -249,8 +248,7 @@ static struct request *nbd_find_request(struct nbd_device *lo, char *handle)
> goto out;
>
> spin_lock(&lo->queue_lock);
> - list_for_each(tmp, &lo->queue_head) {
> - req = list_entry(tmp, struct request, queuelist);
> + list_for_each_entry_safe(req, n, &lo->queue_head, queuelist) {
> if (req != xreq)
> continue;
> list_del_init(&req->queuelist);
Could you name "n" as "tmp" (as in the previous code) so that it's clear
that's only a temporary variable. Other than that, this looks good.
Thanks,
Paul
^ permalink raw reply
* Re: Linux, tcpdump and vlan
From: Stephen Hemminger @ 2007-07-19 15:00 UTC (permalink / raw)
To: Krzysztof Halasa
Cc: Patrick McHardy, andrei radulescu-banu, linux-kernel,
Linux Netdev List
In-Reply-To: <m3k5swbhfv.fsf@maximus.localdomain>
On Thu, 19 Jul 2007 16:23:48 +0200
Krzysztof Halasa <khc@pm.waw.pl> wrote:
> Stephen Hemminger <shemminger@linux-foundation.org> writes:
>
> > 1) non-accelerated device
> > * all frames show in promiscious mode
> > * tag is part of the frame that shows up
> > in tcpdump, and then gets stripped by the 8021q module.
>
> Sure. It's IMHO good and working, modulo the tag being removed
> on the master device (optional cloning or something, IIRC).
>
> > 2) rx tag stripping device
> > * all frames show in promiscious mode
> > * tag is in skb but NOT passed to tcpdump
> > 3) rx vlan acceleration
> > * only frames that for vlan's that are registered show up
> > in promisicous mode
> > * tag is in skb but NOT passed to tcpdump
>
> I wasn't aware of devices doing 3. Aren't we able to tell them
> to receive all packets anyway (even unknown VLANs#)?
See NETIF_F_HW_VLAN_FILTER (e1000, etc).
> > Unfortunately, the tag is lost as part of the VLAN acceleration process
> > so it is not a simple matter of changing code in AF_PACKET receive
> > to restore the tag.
>
> I'm not sure if we really want it. If needed we can disable
> acceleration, can't we? While accelerated we can see the packets
> (without tags) on logical devices.
Not at runtime, acceleration is always on if you compile kernel with vlan
support. That is a design mistake as far as I can tell.
> However seeing unknown tags on master device (with tcpdump etc)
> would certainly be useful.
Only in promiscuous mode. In some sense tag is part of the mac address.
^ permalink raw reply
* Re: [PATCH net-2.6.22-rc7] xfrm beet interfamily support
From: Patrick McHardy @ 2007-07-19 14:46 UTC (permalink / raw)
To: Joakim Koskela; +Cc: netdev, David Miller
In-Reply-To: <200707191708.58863.joakim.koskela@hiit.fi>
Joakim Koskela wrote:
> static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb)
> {
[... ipv4 handling, looks fine ...]
> +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
> + int delta = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
> + u8 protocol;
> +
> + /* Inner = 6, Outer = 4 : changing the external IP hdr
> + * to the outer addresses
> + */
> + hdrlen = x->props.header_len - IPV4_BEET_PHMAXLEN;
This still looks wrong. You removed the IPV4_BEET_PHMAXLEN addition
in esp6_init_state, which was correct since you don't do option
encapsulation for IPv6, but you still substract it here. What
also seems to be missing is accounting for the size difference
between IPv4 and IPv6 headers. In the inner IPv6, outer IPv4 case
its not too important, the other way around we need 20 bytes of
additional space plus room for option encapsulation. By not including
it in the header_len you're breaking MTU calculation and potentially
causing unnecessary reallocations.
> + skb_push(skb, hdrlen);
> + iphv6 = ipv6_hdr(skb);
> +
> + skb_reset_network_header(skb);
> + top_iphv6 = ipv6_hdr(skb);
> +
> + protocol = iphv6->nexthdr;
> + skb_pull(skb, delta);
> + skb_reset_network_header(skb);
> + top_iphv4 = ip_hdr(skb);
> + skb_set_transport_header(skb, hdrlen);
> + top_iphv4->ihl = (sizeof(struct iphdr) >> 2);
> + top_iphv4->version = 4;
> + top_iphv4->id = 0;
> + top_iphv4->frag_off = htons(IP_DF);
> + top_iphv4->ttl = dst_metric(dst->child, RTAX_HOPLIMIT);
> + top_iphv4->saddr = x->props.saddr.a4;
> + top_iphv4->daddr = x->id.daddr.a4;
> + skb->transport_header += top_iphv4->ihl*4;
> + top_iphv4->protocol = protocol;
> +
> + skb->protocol = htons(ETH_P_IP);
> +#endif
The output function in the IPv6/IPv4 case is called from
xfrm6_output_one, which loops until after a tunnel mode
encapsulation is done and then returns to the outer loop
in xfrm6_output_finish2, which passes the packet through
the netfilter hooks and continues with the next transform.
There are multiple problems resulting from the inter-family
encapsulation. First of all, the inner loop continues after
beet mode encapsulation, skipping the netfilter hooks in
case there are more transforms. It should (as with decaps = 1
on input) at least call netfilter hooks after an inter-family
transform. If the beet transform is the last one, the IPv4
skb will be passed through the IPv6 netfilter hooks, which is
clearly wrong. To fix these problems some restructuring in
xfrm[46]_output.c seems to be necessary.
> static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb)
> {
> [...]
> +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
> + } else if (x->sel.family == AF_INET6) {
> + /* Here, the inner family is 6, therefore I have to
> + * substitute the IPhdr by enlarging it.
> + */
> + if (skb_tailroom(skb) < delta) {
> + if (pskb_expand_head(skb, 0, delta, GFP_ATOMIC))
You want skb_headroom I suppose.
> diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
> index 4ff8ed3..ff3d638 100644
> --- a/net/ipv4/xfrm4_policy.c
> +++ b/net/ipv4/xfrm4_policy.c
> @@ -15,6 +15,7 @@
>
> static struct dst_ops xfrm4_dst_ops;
> static struct xfrm_policy_afinfo xfrm4_policy_afinfo;
> +static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu);
>
> static int xfrm4_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
> {
> @@ -81,10 +82,17 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
> }
> }
> };
> + union {
> +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
> + struct in6_addr *in6;
> +#endif
> + struct in_addr *in;
> + } remote, local;
> int i;
> int err;
> int header_len = 0;
> int trailer_len = 0;
> + unsigned short encap_family = 0;
>
> dst = dst_prev = NULL;
> dst_hold(&rt->u.dst);
> @@ -113,12 +121,26 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
>
> dst1->next = dst_prev;
> dst_prev = dst1;
> -
> + if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
> + encap_family = xfrm[i]->props.family;
> + if (encap_family == AF_INET) {
> + remote.in = (struct in_addr *)
> + &xfrm[i]->id.daddr.a4;
> + local.in = (struct in_addr *)
> + &xfrm[i]->props.saddr.a4;
> +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
> + } else if (encap_family == AF_INET6) {
> + remote.in6 = (struct in6_addr *)
> + xfrm[i]->id.daddr.a6;
> + local.in6 = (struct in6_addr *)
> + xfrm[i]->props.saddr.a6;
> +#endif
You set the addresses above ..
> + }
> + }
> header_len += xfrm[i]->props.header_len;
> trailer_len += xfrm[i]->props.trailer_len;
>
> - if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL) {
> - unsigned short encap_family = xfrm[i]->props.family;
> + if (encap_family) {
> switch (encap_family) {
> case AF_INET:
> fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4;
and don't seem to use them for anything.
> @@ -198,6 +220,14 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
> }
>
> xfrm_init_pmtu(dst);
> +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
> + if (encap_family == AF_INET6) {
> + /* The worst case */
> + int delta = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
> + u32 mtu = dst_mtu(dst);
> + xfrm4_update_pmtu(dst, mtu - delta);
Any call to *_update_pmtu indicates that you didn't initialize the
states properly and therefore the MTU calculation gave a wrong result.
Please do proper initialization instead.
> diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
> index 7107bb7..7ddd858 100644
> --- a/net/ipv6/esp6.c
> +++ b/net/ipv6/esp6.c
> @@ -246,7 +246,8 @@ static u32 esp6_get_mtu(struct xfrm_state *x, int mtu)
> rem = mtu & (align - 1);
> mtu &= ~(align - 1);
>
> - if (x->props.mode != XFRM_MODE_TUNNEL) {
> + if (x->props.mode != XFRM_MODE_TUNNEL ||
> + x->props.mode != XFRM_MODE_BEET) {
> u32 padsize = ((blksize - 1) & 7) + 1;
> mtu -= blksize - padsize;
> mtu += min_t(u32, blksize - padsize, rem);
I'm possibly confused, but if you encapsulate IPv4 packets in IPv6
you need to account for option encapsulation overhead here.
> diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c
> index 2e61d6d..c5c2f4f 100644
> --- a/net/ipv6/xfrm6_mode_beet.c
> +++ b/net/ipv6/xfrm6_mode_beet.c
> @@ -6,6 +6,7 @@
> * Herbert Xu <herbert@gondor.apana.org.au>
> * Abhinav Pathak <abhinav.pathak@hiit.fi>
> * Jeff Ahrenholz <ahrenholz@gmail.com>
> + * Joakim Koskela <jookos@gmail.com>
> */
>
> #include <linux/init.h>
> @@ -17,6 +18,7 @@
> #include <net/dst.h>
> #include <net/inet_ecn.h>
> #include <net/ipv6.h>
> +#include <net/ip.h>
> #include <net/xfrm.h>
>
> /* Add encapsulation header.
> @@ -33,57 +35,218 @@
> */
> static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb)
> {
Same problems wrt. netfilter hooks as in IPv4.
> diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
Same comments as for xfrm4_policy.c
> diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
> index baa461b..5c14227 100644
> --- a/net/ipv6/xfrm6_state.c
> +++ b/net/ipv6/xfrm6_state.c
> @@ -98,6 +98,17 @@ __xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n)
> src[i] = NULL;
> }
> }
> + if (j == n)
> + goto end;
> +
> + /* Rule 5: select IPsec BEET */
> + for (i = 0; i < n; i++) {
> + if (src[i] &&
> + src[i]->props.mode == XFRM_MODE_BEET) {
> + dst[j++] = src[i];
> + src[i] = NULL;
> + }
> + }
Just out of interest, is there any particular logic behind the
ordering of the "rules"?
> if (likely(j == n))
> goto end;
>
> diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
> index 157bfbd..75fdb7d 100644
> --- a/net/xfrm/xfrm_policy.c
> +++ b/net/xfrm/xfrm_policy.c
> @@ -1299,7 +1299,8 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl,
> xfrm_address_t *local = saddr;
> struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i];
>
> - if (tmpl->mode == XFRM_MODE_TUNNEL) {
> + if (tmpl->mode == XFRM_MODE_TUNNEL ||
> + tmpl->mode == XFRM_MODE_BEET) {
Is this a bugfix?
> remote = &tmpl->id.daddr;
> local = &tmpl->saddr;
> family = tmpl->encap_family;
> diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
> index dfacb9c..0a2ff8e 100644
> --- a/net/xfrm/xfrm_state.c
> +++ b/net/xfrm/xfrm_state.c
> @@ -611,7 +611,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
> selector.
> */
> if (x->km.state == XFRM_STATE_VALID) {
> - if (!xfrm_selector_match(&x->sel, fl, family) ||
> + if (!xfrm_selector_match(&x->sel, fl, x->sel.family) ||
> !security_xfrm_state_pol_flow_match(x, pol, fl))
> continue;
> if (!best ||
> @@ -623,7 +623,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
> acquire_in_progress = 1;
> } else if (x->km.state == XFRM_STATE_ERROR ||
> x->km.state == XFRM_STATE_EXPIRED) {
> - if (xfrm_selector_match(&x->sel, fl, family) &&
> + if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
> security_xfrm_state_pol_flow_match(x, pol, fl))
> error = -ESRCH;
> }
And these two? Also look like bugfixes ..
^ permalink raw reply
* Re: [PATCH] Merge GT/MV642xx Support into MV643xx Driver [8/8]
From: Dale Farnsworth @ 2007-07-19 14:45 UTC (permalink / raw)
To: Steven J. Hill; +Cc: netdev
In-Reply-To: <469EF04C.1020505@realitydiluted.com>
On Thu, Jul 19, 2007 at 05:02:04AM +0000, Steven J. Hill wrote:
> Fix long standing panic with regards to descriptors and locking.
>
> Signed-off-by: Steven J. Hill <sjhill1@rockwellcollins.com>
> ---
>
> diff -ur linux-2.6.22.1/drivers/net/mv643xx_eth.c linux-2.6.22.1-rci/drivers/net/mv643xx_eth.c
> --- linux-2.6.22.1/drivers/net/mv643xx_eth.c 2007-07-18 22:55:11.000000000 -0500
> +++ linux-2.6.22.1-rci/drivers/net/mv643xx_eth.c 2007-07-18 22:39:37.000000000 -0500
> @@ -350,13 +350,6 @@
>
> while (mp->tx_desc_count > 0) {
> spin_lock_irqsave(&mp->lock, flags);
> -
> - /* tx_desc_count might have changed before acquiring the lock */
> - if (mp->tx_desc_count <= 0) {
> - spin_unlock_irqrestore(&mp->lock, flags);
> - return released;
> - }
> -
The code you remove above is needed to protect against a nasty bug.
It was added in January and needs to stay in.
> @@ -367,7 +360,7 @@
>
> if (!force && (cmd_sts & ETH_BUFFER_OWNED_BY_DMA)) {
> spin_unlock_irqrestore(&mp->lock, flags);
> - return released;
> + continue;
> }
No. Continuing at that point results in the driver spinning, wasting
cpu while polling for the hardware to release the DMA descriptor.
> @@ -1488,7 +1481,19 @@
> BUG_ON(netif_queue_stopped(dev));
> BUG_ON(skb == NULL);
>
> - if (mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB) {
> + if (mp->tx_ring_size - mp->tx_desc_count <= MAX_DESCS_PER_SKB) {
> + /*
> + * We are completely out of TX descriptors, however,
> + * if 'tx_used_desc_q' is zero, most likely the port
> + * has been configured and is up, but there is no link.
> + * We attempt to free a single descriptor to keep the
> + * 'sendto' call and rest of the stack happy. If this
> + * check is taken out, expect an error and kernel panic
> + * from 'kernel/softirq.c:141' inside 'local_bh_enable'.
> + */
> + if (mp->tx_used_desc_q == 0)
> + mv643xx_eth_free_all_tx_descs(dev);
I don't understand the bug, but regardless, we need a better fix.
Freeing all the descriptors when the HW xmit queue is full is not
a solution.
-Dale
^ permalink raw reply
* Re: Linux, tcpdump and vlan
From: Krzysztof Halasa @ 2007-07-19 14:23 UTC (permalink / raw)
To: Stephen Hemminger
Cc: Patrick McHardy, andrei radulescu-banu, linux-kernel,
Linux Netdev List
In-Reply-To: <20070719144131.0c230c8f@oldman.hamilton.local>
Stephen Hemminger <shemminger@linux-foundation.org> writes:
> 1) non-accelerated device
> * all frames show in promiscious mode
> * tag is part of the frame that shows up
> in tcpdump, and then gets stripped by the 8021q module.
Sure. It's IMHO good and working, modulo the tag being removed
on the master device (optional cloning or something, IIRC).
> 2) rx tag stripping device
> * all frames show in promiscious mode
> * tag is in skb but NOT passed to tcpdump
> 3) rx vlan acceleration
> * only frames that for vlan's that are registered show up
> in promisicous mode
> * tag is in skb but NOT passed to tcpdump
I wasn't aware of devices doing 3. Aren't we able to tell them
to receive all packets anyway (even unknown VLANs#)?
> Unfortunately, the tag is lost as part of the VLAN acceleration process
> so it is not a simple matter of changing code in AF_PACKET receive
> to restore the tag.
I'm not sure if we really want it. If needed we can disable
acceleration, can't we? While accelerated we can see the packets
(without tags) on logical devices.
However seeing unknown tags on master device (with tcpdump etc)
would certainly be useful.
--
Krzysztof Halasa
^ permalink raw reply
* Re: [PATCH] Merge GT/MV642xx Support into MV643xx Driver [7/8]
From: Dale Farnsworth @ 2007-07-19 14:21 UTC (permalink / raw)
To: Steven J. Hill; +Cc: netdev
In-Reply-To: <469EEF13.2000607@realitydiluted.com>
On Thu, Jul 19, 2007 at 04:56:51AM +0000, Steven J. Hill wrote:
> Get rid of global PHY spinlock.
You have replaced the use of the global PHY spinlock with a per-port spinlock.
However, the SMI register is shared by all ports. The global lock is
needed to prevent simultaneous updates of the register by drivers for
multiple ports.
NAK
-Dale
^ permalink raw reply
* Re: [PATCH] Merge GT/MV642xx Support into MV643xx Driver [6/8]
From: Dale Farnsworth @ 2007-07-19 14:15 UTC (permalink / raw)
To: Steven J. Hill; +Cc: netdev
In-Reply-To: <469EEEC8.5040805@realitydiluted.com>
On Thu, Jul 19, 2007 at 04:55:36AM +0000, Steven J. Hill wrote:
> Fix the TX bytes statistics counter to, um, actually count.
>
> Signed-off-by: Steven J. Hill <sjhill1@rockwellcollins.com>
> ---
> --- linux-2.6.22.1/drivers/net/mv643xx_eth.c 2007-07-18 21:51:49.000000000 -0500
> +++ linux-2.6.22.1-rci/drivers/net/mv643xx_eth.c 2007-07-18 21:44:07.000000000 -0500
> @@ -1506,7 +1511,7 @@
> spin_lock_irqsave(&mp->lock, flags);
>
> eth_tx_submit_descs_for_skb(mp, skb);
> - stats->tx_bytes = skb->len;
> + stats->tx_bytes += skb->len;
> stats->tx_packets++;
> dev->trans_start = jiffies;
>
Good fix, thanks. Please resubmit per the guidelines in
Documentation/SubmittingPatches.
-Dale
^ permalink raw reply
* Re: [PATCH] Merge GT/MV642xx Support into MV643xx Driver [4/8]
From: Dale Farnsworth @ 2007-07-19 14:07 UTC (permalink / raw)
To: Steven J. Hill; +Cc: netdev
In-Reply-To: <469EEE4B.2090008@realitydiluted.com>
On Thu, Jul 19, 2007 at 04:53:31AM +0000, Steven J. Hill wrote:
> Add main 642xx support to 'drivers/net/mv643xx_eth.c' file.
As Christoph said, this quantity of ifdefs really hurt the
maintainability. Refactoring is needed. Also, since in arch/powerpc
we want to have a single kernel support both MV64[34]60 and GT64260
(determined at runtime) and their register sets are so different, I
think the best approach is to have a separate module for the GT64260.
Also, please follow Documentation/SubmittingPatches. Good subjects,
diffstats and "diff -p" would have been helpful in reviewing this series.
-Dale
^ permalink raw reply
* Re: [PATCH] Merge GT/MV642xx Support into MV643xx Driver [5/8]
From: Dale Farnsworth @ 2007-07-19 14:13 UTC (permalink / raw)
To: Steven J. Hill; +Cc: netdev
In-Reply-To: <469EEE95.8050500@realitydiluted.com>
On Thu, Jul 19, 2007 at 04:54:45AM +0000, Steven J. Hill wrote:
> Fix 'mv643xx_eth_tx_timeout_task' function prototype.
>
> Signed-off-by: Steven J. Hill <sjhill1@rockwellcollins.com>
> ---
>
> --- linux-2.6.22.1/drivers/net/mv643xx_eth.c 2007-07-18 21:45:13.000000000 -0500
> +++ linux-2.6.22.1-rci/drivers/net/mv643xx_eth.c 2007-07-18 21:44:07.000000000 -0500
> @@ -317,11 +315,9 @@
> *
> * Actual routine to reset the adapter when a timeout on Tx has occurred
> */
> -static void mv643xx_eth_tx_timeout_task(struct work_struct *ugly)
> +static void mv643xx_eth_tx_timeout_task(struct net_device *dev)
> {
> - struct mv643xx_private *mp = container_of(ugly, struct mv643xx_private,
> - tx_timeout_task);
> - struct net_device *dev = mp->mii.dev; /* yuck */
> + struct mv643xx_private *mp = netdev_priv(dev);
>
> if (!netif_running(dev))
> return;
Applying this patch results yields a new compiler warning:
drivers/net/mv643xx_eth.c: In function `mv643xx_eth_probe':
drivers/net/mv643xx_eth.c:1375: warning: assignment from incompatible pointer type
I think we're stuck with the "struct work_struct" argument.
-Dale
^ permalink raw reply
* [BUG] Lockup on boot when trying to bring up r8169 NIC
From: Thomas Müller @ 2007-07-19 14:11 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev
Hi,
I already sent this two days ago, but I have the feeling it was
overlooked or filtered because of a large attachment.
If I try to boot 2.6.21.6, 2.6.22.1 or 2.6.22-git8 the system completely
hangs when init tries to bring up my r8169-based NIC. Not even the
keyboard lights are working anymore.
If I unplug the network cable, boot continues just fine and everything
works as it should.
If I boot with the cable unplugged, the system also hangs and continues
after I plug in the cable.
Everything works fine with 2.6.20.15.
Configuration:
http://www.mathtm.de/config_2.6.20.15_fc6based
http://www.mathtm.de/config_2.6.21.6_f7based
Using a Fedora kernel (based on 2.6.21.5) I get the following kernel
message:
r8169: eth0: link down
BUG: soft lockup detected on CPU#0!
[<c0451ea2>] softlockup_tick+0xa5/0xb4
[<c042e930>] update_process_times+0x3b/0x5e
[<c043d298>] tick_sched_timer+0x57/0x9a
[<c0439df5>] hrtimer_interrupt+0x12b/0x1b6
[<c043d241>] tick_sched_timer+0x0/0x9a
[<c0408534>] timer_interrupt+0x2c/0x32
[<c045210e>] handle_IRQ_event+0x1a/0x3f
[<c045354e>] handle_level_irq+0x81/0xc7
[<c04072c7>] do_IRQ+0xb8/0xd1
[<c04058ff>] common_interrupt+0x23/0x28
[<c0452105>] handle_IRQ_event+0x11/0x3f
[<c045354e>] handle_level_irq+0x81/0xc7
[<c04534cd>] handle_level_irq+0x0/0xc7
[<c04072bb>] do_IRQ+0xac/0xd1
[<c04058ff>] common_interrupt+0x23/0x28
[<c042b2dc>] __do_softirq+0x54/0xba
[<c04071b7>] do_softirq+0x59/0xb1
[<c04534cd>] handle_level_irq+0x0/0xc7
[<c042b194>] irq_exit+0x38/0x6b
[<c04072cc>] do_IRQ+0xbd/0xd1
[<c04058ff>] common_interrupt+0x23/0x28
[<c04200d8>] find_busiest_group+0x264/0x4c5
[<c0601895>] _spin_unlock_irqrestore+0x8/0x9
[<c042e863>] __mod_timer+0xa1/0xab
[<f8a4e1ec>] rtl8169_open+0x12e/0x194 [r8169]
[<c05a3054>] dev_open+0x2b/0x62
[<c05a1aa1>] dev_change_flags+0x47/0xe4
[<c05de45c>] devinet_ioctl+0x250/0x56a
[<c04e72c0>] copy_to_user+0x3c/0x50
[<c0598b47>] sock_ioctl+0x19f/0x1be
[<c05989a8>] sock_ioctl+0x0/0x1be
[<c047f713>] do_ioctl+0x1f/0x62
[<c047f99a>] vfs_ioctl+0x244/0x256
[<c047f9f8>] sys_ioctl+0x4c/0x64
[<c0404f70>] syscall_call+0x7/0xb
=======================
r8169: eth0: link up
There already is a bugzilla entry at
http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=242572
I know, not everyone is a fan of bugzilla, but maybe someone wants to
take a look at what was discussed there.
Please CC me as I'm not subscribed to the list and don't hesitate to
tell me that I forgot to include some crucial information ;)
Regards,
Thomas
^ permalink raw reply
* [PATCH net-2.6.22-rc7] xfrm beet interfamily support
From: Joakim Koskela @ 2007-07-19 14:08 UTC (permalink / raw)
To: netdev; +Cc: Patrick McHardy, David Miller
In-Reply-To: <469CE793.7020903@trash.net>
Hi all,
Here's once again a corrected version of the patch adding support for
ipv4/ipv6 interfamily addressing for the ipsec BEET (Bound End-to-End
Tunnel) mode, as specified by the ietf draft found at:
http://www.ietf.org/internet-drafts/draft-nikander-esp-beet-mode-07.txt
The previous implementation required that both address pairs in the SA
were of the same family. This patch enables mixing ipv4 and ipv6
addresses. All combinations (4-4, 4-6, 6-4, 6-6) have been tested
using manual key setups.
Signed-off-by: Joakim Koskela <jookos@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Diego Beltrami <diego.beltrami@gmail.com>
Signed-off-by: Miika Komu <miika@iki.fi>
---
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index fa1902d..43c0d80 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -108,7 +108,9 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
if (x->mode->input(x, skb))
goto drop;
- if (x->props.mode == XFRM_MODE_TUNNEL) {
+ if (x->props.mode == XFRM_MODE_TUNNEL ||
+ (x->props.mode == XFRM_MODE_BEET &&
+ x->sel.family != AF_INET)) {
decaps = 1;
break;
}
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c
index a73e710..20e0610 100644
--- a/net/ipv4/xfrm4_mode_beet.c
+++ b/net/ipv4/xfrm4_mode_beet.c
@@ -6,6 +6,7 @@
* Herbert Xu <herbert@gondor.apana.org.au>
* Abhinav Pathak <abhinav.pathak@hiit.fi>
* Jeff Ahrenholz <ahrenholz@gmail.com>
+ * Joakim Koskela <jookos@gmail.com>
*/
#include <linux/init.h>
@@ -24,92 +25,179 @@
* tot_len
* check
*
- * On exit, skb->h will be set to the start of the payload to be processed
- * by x->type->output and skb->nh will be set to the top IP header.
+ * On exit, skb->transport_header will be set to the start of the
+ * payload to be processed by x->type->output and skb->network_header
+ * will be set to the top IP header.
*/
static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb)
{
- struct iphdr *iph, *top_iph;
- int hdrlen, optlen;
-
- iph = ip_hdr(skb);
- skb->transport_header = skb->network_header;
-
- hdrlen = 0;
- optlen = iph->ihl * 4 - sizeof(*iph);
- if (unlikely(optlen))
- hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4);
-
- skb_push(skb, x->props.header_len - IPV4_BEET_PHMAXLEN + hdrlen);
- skb_reset_network_header(skb);
- top_iph = ip_hdr(skb);
- skb->transport_header += sizeof(*iph) - hdrlen;
-
- memmove(top_iph, iph, sizeof(*iph));
- if (unlikely(optlen)) {
- struct ip_beet_phdr *ph;
-
- BUG_ON(optlen < 0);
-
- ph = (struct ip_beet_phdr *)skb_transport_header(skb);
- ph->padlen = 4 - (optlen & 4);
- ph->hdrlen = optlen / 8;
- ph->nexthdr = top_iph->protocol;
- if (ph->padlen)
- memset(ph + 1, IPOPT_NOP, ph->padlen);
-
- top_iph->protocol = IPPROTO_BEETPH;
- top_iph->ihl = sizeof(struct iphdr) / 4;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ struct ipv6hdr *iphv6, *top_iphv6;
+#endif
+ struct dst_entry *dst = skb->dst;
+ struct iphdr *iphv4, *top_iphv4;
+ int hdrlen;
+
+ if (ip_hdr(skb)->version == 4) {
+ int optlen;
+
+ /* 4-4 */
+ iphv4 = ip_hdr(skb);
+ skb->transport_header = skb->network_header;
+
+ hdrlen = 0;
+ optlen = iphv4->ihl * 4 - sizeof(*iphv4);
+ if (unlikely(optlen))
+ hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4);
+
+ skb_push(skb, x->props.header_len - IPV4_BEET_PHMAXLEN + hdrlen);
+ skb_reset_network_header(skb);
+ top_iphv4 = ip_hdr(skb);
+ skb->transport_header += sizeof(*iphv4) - hdrlen;
+
+ memmove(top_iphv4, iphv4, sizeof(*iphv4));
+ if (unlikely(optlen)) {
+ struct ip_beet_phdr *ph;
+
+ BUG_ON(optlen < 0);
+
+ ph = (struct ip_beet_phdr *)skb_transport_header(skb);
+ ph->padlen = 4 - (optlen & 4);
+ ph->hdrlen = optlen / 8;
+ ph->nexthdr = iphv4->protocol;
+ if (ph->padlen)
+ memset(ph + 1, IPOPT_NOP, ph->padlen);
+ top_iphv4->protocol = IPPROTO_BEETPH;
+ top_iphv4->ihl = sizeof(struct iphdr) / 4;
+ }
+
+ top_iphv4->saddr = x->props.saddr.a4;
+ top_iphv4->daddr = x->id.daddr.a4;
+
+ skb->protocol = htons(ETH_P_IP);
+ } else if (ip_hdr(skb)->version == 6) {
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ int delta = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+ u8 protocol;
+
+ /* Inner = 6, Outer = 4 : changing the external IP hdr
+ * to the outer addresses
+ */
+ hdrlen = x->props.header_len - IPV4_BEET_PHMAXLEN;
+ skb_push(skb, hdrlen);
+ iphv6 = ipv6_hdr(skb);
+
+ skb_reset_network_header(skb);
+ top_iphv6 = ipv6_hdr(skb);
+
+ protocol = iphv6->nexthdr;
+ skb_pull(skb, delta);
+ skb_reset_network_header(skb);
+ top_iphv4 = ip_hdr(skb);
+ skb_set_transport_header(skb, hdrlen);
+ top_iphv4->ihl = (sizeof(struct iphdr) >> 2);
+ top_iphv4->version = 4;
+ top_iphv4->id = 0;
+ top_iphv4->frag_off = htons(IP_DF);
+ top_iphv4->ttl = dst_metric(dst->child, RTAX_HOPLIMIT);
+ top_iphv4->saddr = x->props.saddr.a4;
+ top_iphv4->daddr = x->id.daddr.a4;
+ skb->transport_header += top_iphv4->ihl*4;
+ top_iphv4->protocol = protocol;
+
+ skb->protocol = htons(ETH_P_IP);
+#endif
}
- top_iph->saddr = x->props.saddr.a4;
- top_iph->daddr = x->id.daddr.a4;
-
return 0;
}
static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb)
{
struct iphdr *iph = ip_hdr(skb);
+ int hops = iph->ttl;
int phlen = 0;
int optlen = 0;
- u8 ph_nexthdr = 0;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ int size = ((x->sel.family == AF_INET) ?
+ sizeof(struct iphdr) :
+ sizeof(struct ipv6hdr));
+ int delta = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+ struct ipv6hdr *ip6h;
+#endif
+ __u8 ph_nexthdr = 0, protocol = 0;
int err = -EINVAL;
- if (unlikely(iph->protocol == IPPROTO_BEETPH)) {
- struct ip_beet_phdr *ph;
-
- if (!pskb_may_pull(skb, sizeof(*ph)))
- goto out;
- ph = (struct ip_beet_phdr *)(ipip_hdr(skb) + 1);
-
- phlen = sizeof(*ph) + ph->padlen;
- optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen);
- if (optlen < 0 || optlen & 3 || optlen > 250)
- goto out;
-
- if (!pskb_may_pull(skb, phlen + optlen))
- goto out;
- skb->len -= phlen + optlen;
-
- ph_nexthdr = ph->nexthdr;
+ protocol = iph->protocol;
+ if (x->sel.family == AF_INET) {
+
+ if (unlikely(iph->protocol == IPPROTO_BEETPH)) {
+ struct ip_beet_phdr *ph;
+
+ if (!pskb_may_pull(skb, sizeof(*ph)))
+ goto out;
+ ph = (struct ip_beet_phdr *)(ipip_hdr(skb) + 1);
+
+ phlen = sizeof(*ph) + ph->padlen;
+ optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen);
+ if (optlen < 0 || optlen & 3 || optlen > 250)
+ goto out;
+
+ if (!pskb_may_pull(skb, phlen + optlen))
+ goto out;
+ skb->len -= phlen + optlen;
+
+ ph_nexthdr = ph->nexthdr;
+ }
+
+ skb_set_network_header(skb, phlen - sizeof(*iph));
+ memmove(skb_network_header(skb), iph, sizeof(*iph));
+ skb_set_transport_header(skb, phlen + optlen);
+ skb->data = skb_transport_header(skb);
+
+ iph = ip_hdr(skb);
+ iph->ihl = (sizeof(*iph) + optlen) / 4;
+ iph->tot_len = htons(skb->len + iph->ihl * 4);
+ iph->daddr = x->sel.daddr.a4;
+ iph->saddr = x->sel.saddr.a4;
+ if (ph_nexthdr)
+ iph->protocol = ph_nexthdr;
+ iph->check = 0;
+ iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl);
+ err = 0;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ } else if (x->sel.family == AF_INET6) {
+ /* Here, the inner family is 6, therefore I have to
+ * substitute the IPhdr by enlarging it.
+ */
+ if (skb_tailroom(skb) < delta) {
+ if (pskb_expand_head(skb, 0, delta, GFP_ATOMIC))
+ goto out;
+ }
+
+ skb->network_header -= delta;
+
+ size += (optlen - phlen);
+ skb_push(skb, size);
+ memmove(skb->data, skb_network_header(skb), sizeof(*iph));
+ skb_reset_network_header(skb);
+
+ ip6h = ipv6_hdr(skb);
+ memset(ip6h->flow_lbl, 0, sizeof(ip6h->flow_lbl));
+ ip6h->version = 6;
+ ip6h->priority = 0;
+ ip6h->nexthdr = protocol;
+ ip6h->hop_limit = hops;
+ ip6h->payload_len = htons(skb->len - size);
+ ipv6_addr_copy(&ip6h->daddr,
+ (struct in6_addr *)&x->sel.daddr.a6);
+ ipv6_addr_copy(&ip6h->saddr,
+ (struct in6_addr *)&x->sel.saddr.a6);
+ skb->protocol = htons(ETH_P_IPV6);
+
+ err = 0;
+#endif
}
-
- skb_set_network_header(skb, phlen - sizeof(*iph));
- memmove(skb_network_header(skb), iph, sizeof(*iph));
- skb_set_transport_header(skb, phlen + optlen);
- skb->data = skb_transport_header(skb);
-
- iph = ip_hdr(skb);
- iph->ihl = (sizeof(*iph) + optlen) / 4;
- iph->tot_len = htons(skb->len + iph->ihl * 4);
- iph->daddr = x->sel.daddr.a4;
- iph->saddr = x->sel.saddr.a4;
- if (ph_nexthdr)
- iph->protocol = ph_nexthdr;
- iph->check = 0;
- iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl);
- err = 0;
out:
return err;
}
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 4ff8ed3..ff3d638 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -15,6 +15,7 @@
static struct dst_ops xfrm4_dst_ops;
static struct xfrm_policy_afinfo xfrm4_policy_afinfo;
+static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu);
static int xfrm4_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
{
@@ -81,10 +82,17 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
}
}
};
+ union {
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ struct in6_addr *in6;
+#endif
+ struct in_addr *in;
+ } remote, local;
int i;
int err;
int header_len = 0;
int trailer_len = 0;
+ unsigned short encap_family = 0;
dst = dst_prev = NULL;
dst_hold(&rt->u.dst);
@@ -113,12 +121,26 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst1->next = dst_prev;
dst_prev = dst1;
-
+ if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
+ encap_family = xfrm[i]->props.family;
+ if (encap_family == AF_INET) {
+ remote.in = (struct in_addr *)
+ &xfrm[i]->id.daddr.a4;
+ local.in = (struct in_addr *)
+ &xfrm[i]->props.saddr.a4;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ } else if (encap_family == AF_INET6) {
+ remote.in6 = (struct in6_addr *)
+ xfrm[i]->id.daddr.a6;
+ local.in6 = (struct in6_addr *)
+ xfrm[i]->props.saddr.a6;
+#endif
+ }
+ }
header_len += xfrm[i]->props.header_len;
trailer_len += xfrm[i]->props.trailer_len;
- if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL) {
- unsigned short encap_family = xfrm[i]->props.family;
+ if (encap_family) {
switch (encap_family) {
case AF_INET:
fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4;
@@ -198,6 +220,14 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
}
xfrm_init_pmtu(dst);
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ if (encap_family == AF_INET6) {
+ /* The worst case */
+ int delta = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+ u32 mtu = dst_mtu(dst);
+ xfrm4_update_pmtu(dst, mtu - delta);
+ }
+#endif
return 0;
error:
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 7107bb7..7ddd858 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -246,7 +246,8 @@ static u32 esp6_get_mtu(struct xfrm_state *x, int mtu)
rem = mtu & (align - 1);
mtu &= ~(align - 1);
- if (x->props.mode != XFRM_MODE_TUNNEL) {
+ if (x->props.mode != XFRM_MODE_TUNNEL ||
+ x->props.mode != XFRM_MODE_BEET) {
u32 padsize = ((blksize - 1) & 7) + 1;
mtu -= blksize - padsize;
mtu += min_t(u32, blksize - padsize, rem);
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index c858537..1728f69 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -73,7 +73,9 @@ int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi)
if (x->mode->input(x, skb))
goto drop;
- if (x->props.mode == XFRM_MODE_TUNNEL) { /* XXX */
+ if (x->props.mode == XFRM_MODE_TUNNEL ||
+ (x->props.mode == XFRM_MODE_BEET &&
+ x->sel.family != AF_INET6)) {
decaps = 1;
break;
}
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c
index 2e61d6d..c5c2f4f 100644
--- a/net/ipv6/xfrm6_mode_beet.c
+++ b/net/ipv6/xfrm6_mode_beet.c
@@ -6,6 +6,7 @@
* Herbert Xu <herbert@gondor.apana.org.au>
* Abhinav Pathak <abhinav.pathak@hiit.fi>
* Jeff Ahrenholz <ahrenholz@gmail.com>
+ * Joakim Koskela <jookos@gmail.com>
*/
#include <linux/init.h>
@@ -17,6 +18,7 @@
#include <net/dst.h>
#include <net/inet_ecn.h>
#include <net/ipv6.h>
+#include <net/ip.h>
#include <net/xfrm.h>
/* Add encapsulation header.
@@ -33,57 +35,218 @@
*/
static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb)
{
- struct ipv6hdr *iph, *top_iph;
- u8 *prevhdr;
+ struct dst_entry *dst = skb->dst;
+ struct iphdr *iphv4, *top_iphv4;
+ struct ipv6hdr *iphv6, *top_iphv6;
int hdr_len;
- skb_push(skb, x->props.header_len);
- iph = ipv6_hdr(skb);
+ if (ip_hdr(skb)->version == 6) {
+ u8 *prevhdr;
- hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
- skb_set_network_header(skb,
- (prevhdr - x->props.header_len) - skb->data);
- skb_set_transport_header(skb, hdr_len);
- memmove(skb->data, iph, hdr_len);
+ skb_push(skb, x->props.header_len);
+ iphv6 = ipv6_hdr(skb);
- skb_reset_network_header(skb);
- top_iph = ipv6_hdr(skb);
- skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
- skb->network_header += offsetof(struct ipv6hdr, nexthdr);
+ hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
- ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
- ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
+ skb_set_network_header(skb,
+ (prevhdr - x->props.header_len) - skb->data);
+ skb_set_transport_header(skb, hdr_len);
+ memmove(skb->data, iphv6, hdr_len);
+
+ skb_reset_network_header(skb);
+ top_iphv6 = ipv6_hdr(skb);
+ skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
+ skb->network_header += offsetof(struct ipv6hdr, nexthdr);
+
+ ipv6_addr_copy(&top_iphv6->saddr, (struct in6_addr *)&x->props.saddr);
+ ipv6_addr_copy(&top_iphv6->daddr, (struct in6_addr *)&x->id.daddr);
+
+ } else if (ip_hdr(skb)->version == 4) {
+ int delta = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+ int flags, optlen, dsfield;
+ u8 protocol;
+
+ iphv4 = ip_hdr(skb);
+ skb->transport_header = skb->network_header;
+
+ hdr_len = 0;
+ optlen = iphv4->ihl * 4 - sizeof(*iphv4);
+ if (unlikely(optlen))
+ hdr_len += IPV4_BEET_PHMAXLEN - (optlen & 4);
+
+ skb_push(skb, x->props.header_len + hdr_len);
+ skb_reset_network_header(skb);
+ top_iphv4 = ip_hdr(skb);
+ skb->transport_header += sizeof(*iphv4) - hdr_len;
+
+ if (unlikely(optlen)) {
+ struct ip_beet_phdr *ph;
+
+ BUG_ON(optlen < 0);
+
+ ph = (struct ip_beet_phdr *)skb_transport_header(skb);
+ ph->padlen = 4 - (optlen & 4);
+ ph->hdrlen = optlen / 8;
+ ph->nexthdr = iphv4->protocol;
+ if (ph->padlen)
+ memset(ph + 1, IPOPT_NOP, ph->padlen);
+ top_iphv4->protocol = IPPROTO_BEETPH;
+ top_iphv4->ihl = sizeof(struct iphdr) / 4;
+ }
+
+ if (unlikely(optlen))
+ protocol = top_iphv4->protocol;
+ else
+ protocol = iphv4->protocol;
+
+ if (skb_headroom(skb) <= 2*delta) {
+ if (pskb_expand_head(skb, delta,0, GFP_ATOMIC))
+ return -ENOMEM;
+ }
+
+ skb_push(skb, delta);
+ skb_reset_network_header(skb);
+
+ top_iphv6 = ipv6_hdr(skb);
+ skb_set_transport_header(skb, sizeof(struct ipv6hdr));
+
+ /* DS disclosed */
+ top_iphv6->version = 6;
+ top_iphv6->priority = 0;
+ top_iphv6->flow_lbl[0] = 0;
+ top_iphv6->flow_lbl[1] = 0;
+ top_iphv6->flow_lbl[2] = 0;
+ dsfield = ipv6_get_dsfield(top_iphv6);
+ dsfield = INET_ECN_encapsulate(dsfield, dsfield);
+ flags = x->props.flags;
+ if (flags & XFRM_STATE_NOECN)
+ dsfield &= ~INET_ECN_MASK;
+ ipv6_change_dsfield(top_iphv6, 0, dsfield);
+
+ top_iphv6->nexthdr = protocol;
+ top_iphv6->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT);
+ top_iphv6->payload_len = htons(skb->len -
+ sizeof(struct ipv6hdr));
+ ipv6_addr_copy(&top_iphv6->saddr,
+ (struct in6_addr *) &x->props.saddr);
+ ipv6_addr_copy(&top_iphv6->daddr,
+ (struct in6_addr *) &x->id.daddr);
+
+ skb->network_header += offsetof(struct ipv6hdr, nexthdr);
+
+ skb->protocol = htons(ETH_P_IPV6);
+ }
return 0;
}
static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb)
{
+
struct ipv6hdr *ip6h;
const unsigned char *old_mac;
- int size = sizeof(struct ipv6hdr);
+ int size = ((x->sel.family == AF_INET) ?
+ sizeof(struct iphdr) :
+ sizeof(struct ipv6hdr));
int err = -EINVAL;
- if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
- goto out;
+ if (x->sel.family == AF_INET6) {
+
+ if (skb_cloned(skb) &&
+ pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ goto out;
+
+ skb_push(skb, size);
+ memmove(skb->data, skb_network_header(skb), size);
+ skb_reset_network_header(skb);
+
+ old_mac = skb_mac_header(skb);
+ skb_set_mac_header(skb, -skb->mac_len);
+ memmove(skb_mac_header(skb), old_mac, skb->mac_len);
+
+ skb_set_transport_header(skb, size);
+ skb->data = skb_transport_header(skb);
+ skb->len -= size;
+
+ ip6h = ipv6_hdr(skb);
+ ip6h->payload_len = htons(skb->len);
+ ipv6_addr_copy(&ip6h->daddr, (struct in6_addr *) &x->sel.daddr.a6);
+ ipv6_addr_copy(&ip6h->saddr, (struct in6_addr *) &x->sel.saddr.a6);
+ skb->protocol = htons(ETH_P_IPV6);
+
+ err = 0;
+ } else {
+ struct ip_beet_phdr *ph = (struct ip_beet_phdr *)
+ skb_transport_header(skb);
+ int delta = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+ __u8 proto = ipv6_hdr(skb)->nexthdr;
+ __u8 hops = ipv6_hdr(skb)->hop_limit;
+ int phlen = 0;
+ int optlen = 0;
+ struct iphdr *iph;
+
+ /* Inner = IPv4, therefore the IPhdr must be shrunk */
+ /* Inner = 4, Outer = 6 */
+ if (unlikely(proto == IPPROTO_BEETPH)) {
+ if (!pskb_may_pull(skb, sizeof(*ph)))
+ goto out;
- skb_push(skb, size);
- memmove(skb->data, skb_network_header(skb), size);
- skb_reset_network_header(skb);
+ phlen = sizeof(*ph) + ph->padlen;
+ optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen);
+ if (optlen < 0 || optlen & 3 || optlen > 250)
+ goto out;
- old_mac = skb_mac_header(skb);
- skb_set_mac_header(skb, -skb->mac_len);
- memmove(skb_mac_header(skb), old_mac, skb->mac_len);
+ if (!pskb_may_pull(skb, phlen + optlen))
+ goto out;
+ skb->len -= phlen + optlen;
+ proto = ph->nexthdr;
+ }
+ skb->network_header += delta;
- ip6h = ipv6_hdr(skb);
- ip6h->payload_len = htons(skb->len - size);
- ipv6_addr_copy(&ip6h->daddr, (struct in6_addr *) &x->sel.daddr.a6);
- ipv6_addr_copy(&ip6h->saddr, (struct in6_addr *) &x->sel.saddr.a6);
- err = 0;
-out:
+ if (skb_cloned(skb) &&
+ pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ goto out;
+
+ skb_push(skb, size);
+ memmove(skb->data, skb_network_header(skb), size);
+ skb_reset_network_header(skb);
+
+ old_mac = skb_mac_header(skb);
+ skb_set_mac_header(skb, -skb->mac_len);
+ memmove(skb_mac_header(skb), old_mac, skb->mac_len);
+
+ if (unlikely(phlen)) {
+ skb_pull(skb, phlen - optlen);
+ skb_reset_network_header(skb);
+ }
+
+ iph = ip_hdr(skb);
+ iph->ihl = (sizeof(*iph) + optlen) / 4;
+ iph->version = 4;
+ iph->tos = 0;
+ iph->id = 0;
+ iph->frag_off = 0;
+ iph->ttl = hops;
+ iph->protocol = proto;
+ iph->daddr = x->sel.daddr.a4;
+ iph->saddr = x->sel.saddr.a4;
+ iph->tot_len = htons(skb->len);
+ ip_send_check(iph);
+ skb->protocol = htons(ETH_P_IP);
+ if (unlikely(!optlen))
+ skb->transport_header = skb->network_header;
+
+ dst_release(skb->dst);
+ skb->dst = NULL;
+
+ err = 0;
+ }
+ out:
return err;
}
+
+
static struct xfrm_mode xfrm6_beet_mode = {
.input = xfrm6_beet_input,
.output = xfrm6_beet_output,
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 1faa2ea..7c6b69a 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -24,6 +24,7 @@
static struct dst_ops xfrm6_dst_ops;
static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
+static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu);
static int xfrm6_dst_lookup(struct xfrm_dst **xdst, struct flowi *fl)
{
@@ -131,6 +132,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
struct dst_entry *dst, *dst_prev;
struct rt6_info *rt0 = (struct rt6_info*)(*dst_p);
struct rt6_info *rt = rt0;
+ unsigned short encap_family = 0, beet = 0;
struct flowi fl_tunnel = {
.nl_u = {
.ip6_u = {
@@ -179,16 +181,21 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
trailer_len += xfrm[i]->props.trailer_len;
if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL ||
+ xfrm[i]->props.mode == XFRM_MODE_BEET ||
xfrm[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION) {
- unsigned short encap_family = xfrm[i]->props.family;
+
+ beet = xfrm[i]->props.mode == XFRM_MODE_BEET;
+ encap_family = xfrm[i]->props.family;
+
switch(encap_family) {
case AF_INET:
fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4;
fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4;
+ fl_tunnel.fl4_tos = 0;
+ fl_tunnel.fl4_scope = 0;
break;
case AF_INET6:
ipv6_addr_copy(&fl_tunnel.fl6_dst, __xfrm6_bundle_addr_remote(xfrm[i], &fl->fl6_dst));
-
ipv6_addr_copy(&fl_tunnel.fl6_src, __xfrm6_bundle_addr_local(xfrm[i], &fl->fl6_src));
break;
default:
@@ -259,7 +266,14 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
trailer_len -= x->u.dst.xfrm->props.trailer_len;
}
+
xfrm_init_pmtu(dst);
+ if (beet && encap_family == AF_INET) {
+ int delta = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+ u32 mtu = dst_mtu(dst);
+ xfrm6_update_pmtu(dst, mtu + delta);
+ }
+
return 0;
error:
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index baa461b..5c14227 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -98,6 +98,17 @@ __xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n)
src[i] = NULL;
}
}
+ if (j == n)
+ goto end;
+
+ /* Rule 5: select IPsec BEET */
+ for (i = 0; i < n; i++) {
+ if (src[i] &&
+ src[i]->props.mode == XFRM_MODE_BEET) {
+ dst[j++] = src[i];
+ src[i] = NULL;
+ }
+ }
if (likely(j == n))
goto end;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 157bfbd..75fdb7d 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1299,7 +1299,8 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl,
xfrm_address_t *local = saddr;
struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i];
- if (tmpl->mode == XFRM_MODE_TUNNEL) {
+ if (tmpl->mode == XFRM_MODE_TUNNEL ||
+ tmpl->mode == XFRM_MODE_BEET) {
remote = &tmpl->id.daddr;
local = &tmpl->saddr;
family = tmpl->encap_family;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index dfacb9c..0a2ff8e 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -611,7 +611,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
selector.
*/
if (x->km.state == XFRM_STATE_VALID) {
- if (!xfrm_selector_match(&x->sel, fl, family) ||
+ if (!xfrm_selector_match(&x->sel, fl, x->sel.family) ||
!security_xfrm_state_pol_flow_match(x, pol, fl))
continue;
if (!best ||
@@ -623,7 +623,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
acquire_in_progress = 1;
} else if (x->km.state == XFRM_STATE_ERROR ||
x->km.state == XFRM_STATE_EXPIRED) {
- if (xfrm_selector_match(&x->sel, fl, family) &&
+ if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
security_xfrm_state_pol_flow_match(x, pol, fl))
error = -ESRCH;
}
^ permalink raw reply related
* Re: Linux, tcpdump and vlan
From: Patrick McHardy @ 2007-07-19 14:00 UTC (permalink / raw)
To: Stephen Hemminger
Cc: Krzysztof Halasa, andrei radulescu-banu, linux-kernel,
Linux Netdev List
In-Reply-To: <20070719144131.0c230c8f@oldman.hamilton.local>
Stephen Hemminger wrote:
> On Thu, 19 Jul 2007 15:28:46 +0200
> Krzysztof Halasa <khc@pm.waw.pl> wrote:
>
>>>Your suggestion of disabling VLAN acceleration in promiscous
>>>mode sounds like a reasonable solution until then ..
>>
>>From a user perspective:
>>
>>I'm not sure promiscous mode is related to the problem.
>>Tcpdump without promiscous mode makes perfect sense.
Good point.
>>I don't know very well VLAN code internals, but I think
>>the VLAN # is used for looking up the interface, so
>>presenting the "original" packet on the trunk device
>>would IMHO involve some skb cloning, and perhaps some
>>ethtool option could probably control that.
>>
>>Not sure about untagged frames vs. tagged frames with
>>the default VLAN id - can the hardware at all differentiate
>>between them?
>>
>>
>>Or, perhaps it should be left (almost) as is - with "software"
>>VLANs the traffic always goes through the master interface,
>>but with "accelerated" mode it only goes through logical
>>interfaces and doesn't show up on master? Probably with
>>exception of invalid VLANs, which could be injected back to
>>master (because no logical device exists)?
The last case is the problematic one, the tag might be gone.
> I don't claim to be a VLAN expert but there are really three cases
> for handling tagged frames
>
> 1) non-accelerated device
> * all frames show in promiscious mode
> * tag is part of the frame that shows up
> in tcpdump, and then gets stripped by the 8021q module.
> 2) rx tag stripping device
> * all frames show in promiscious mode
> * tag is in skb but NOT passed to tcpdump
> 3) rx vlan acceleration
> * only frames that for vlan's that are registered show up
> in promisicous mode
> * tag is in skb but NOT passed to tcpdump
>
> Unfortunately, the tag is lost as part of the VLAN acceleration process
> so it is not a simple matter of changing code in AF_PACKET receive
> to restore the tag.
I think case 2) is not correct, the tag is stripped and is not in the
skb. Check out sky2 for example :)
if (sky2->vlgrp && (status & GMR_FS_VLAN)) {
vlan_hwaccel_receive_skb(skb,
sky2->vlgrp,
be16_to_cpu(sky2->rx_tag));
The tag it uses for the lookup comes from the descriptor. I don't
know any examples for case 3), but I would expect that the header
is also removed.
Anyway, I think what we should do is store the VLAN tag in the skb
meta data. That would not only allow tcpdump to reconstruct it, it
would also fix the invalid use of skb->cb on the TX path. It would
also fix the bridge eating VLAN headers case (bridge on eth0 + eth1,
additionally eth0.1 on eth0 using vlan RX accerlation with header
stripping) and would allow to simply forward the vlan tag to the
outgoing device in case it supports hardware accererated vlan tagging.
^ permalink raw reply
* Re: [PATCH] net/, drivers/net/ , missing EXPERIMENTAL in menus
From: Stefan Richter @ 2007-07-19 13:53 UTC (permalink / raw)
To: Robert P. J. Day
Cc: Adrian Bunk, Jeff Garzik, Randy Dunlap, Gabriel C,
Linux Kernel Mailing List, netdev
In-Reply-To: <Pine.LNX.4.64.0707190523001.19216@localhost.localdomain>
Robert P. J. Day wrote:
> i *did* submit a preliminary patch once upon a time, and it
> (predictably) went nowhere.
A patch which pulls the word "experimental" into prompts or adds a
dedicated directive for tagging of options? Can't find it in archives.
--
Stefan Richter
-=====-=-=== -=== =--==
http://arcgraph.de/sr/
^ permalink raw reply
* Re: Linux, tcpdump and vlan
From: Stephen Hemminger @ 2007-07-19 13:41 UTC (permalink / raw)
To: Krzysztof Halasa
Cc: Patrick McHardy, andrei radulescu-banu, linux-kernel,
Linux Netdev List
In-Reply-To: <m3zm1sbjzl.fsf@maximus.localdomain>
On Thu, 19 Jul 2007 15:28:46 +0200
Krzysztof Halasa <khc@pm.waw.pl> wrote:
> Patrick McHardy <kaber@trash.net> writes:
>
> > Your suggestion of disabling VLAN acceleration in promiscous
> > mode sounds like a reasonable solution until then ..
>
> From a user perspective:
>
> I'm not sure promiscous mode is related to the problem.
> Tcpdump without promiscous mode makes perfect sense.
>
> I don't know very well VLAN code internals, but I think
> the VLAN # is used for looking up the interface, so
> presenting the "original" packet on the trunk device
> would IMHO involve some skb cloning, and perhaps some
> ethtool option could probably control that.
>
> Not sure about untagged frames vs. tagged frames with
> the default VLAN id - can the hardware at all differentiate
> between them?
>
>
> Or, perhaps it should be left (almost) as is - with "software"
> VLANs the traffic always goes through the master interface,
> but with "accelerated" mode it only goes through logical
> interfaces and doesn't show up on master? Probably with
> exception of invalid VLANs, which could be injected back to
> master (because no logical device exists)?
I don't claim to be a VLAN expert but there are really three cases
for handling tagged frames
1) non-accelerated device
* all frames show in promiscious mode
* tag is part of the frame that shows up
in tcpdump, and then gets stripped by the 8021q module.
2) rx tag stripping device
* all frames show in promiscious mode
* tag is in skb but NOT passed to tcpdump
3) rx vlan acceleration
* only frames that for vlan's that are registered show up
in promisicous mode
* tag is in skb but NOT passed to tcpdump
Unfortunately, the tag is lost as part of the VLAN acceleration process
so it is not a simple matter of changing code in AF_PACKET receive
to restore the tag.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox