[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1287757138.2316.18.camel@achroite.uk.solarflarecom.com>
Date: Fri, 22 Oct 2010 15:18:58 +0100
From: Ben Hutchings <bhutchings@...arflare.com>
To: David Miller <davem@...emloft.net>
Cc: Jesse Gross <jesse@...ira.com>, netdev@...r.kernel.org
Subject: Re: [PATCH net-next-2.6] net: Fix some corner cases in
dev_can_checksum()
Of the following tests, the current implementation fails
'test_no_2vlan_ob_ip' and 'test_vlan_ib_unknown'.
Ben.
#include <assert.h>
#include <stdbool.h>
#include <string.h>
/* Dummy definitions */
typedef unsigned short __be16, __u16, u16;
static inline __be16 htons(u16 value)
{
return value >> 8 | value << 8;
}
struct net_device {
unsigned long features;
#define NETIF_F_SG 1 /* Scatter/gather IO. */
#define NETIF_F_IP_CSUM 2 /* Can checksum TCP/UDP over IPv4. */
#define NETIF_F_NO_CSUM 4 /* Does not require checksum. F.e. loopack. */
#define NETIF_F_HW_CSUM 8 /* Can checksum all the packets. */
#define NETIF_F_IPV6_CSUM 16 /* Can checksum TCP/UDP over IPV6 */
#define NETIF_F_FCOE_CRC (1 << 24) /* FCoE CRC32 */
#define NETIF_F_GEN_CSUM (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
#define NETIF_F_V4_CSUM (NETIF_F_GEN_CSUM | NETIF_F_IP_CSUM)
#define NETIF_F_V6_CSUM (NETIF_F_GEN_CSUM | NETIF_F_IPV6_CSUM)
#define NETIF_F_ALL_CSUM (NETIF_F_V4_CSUM | NETIF_F_V6_CSUM)
unsigned long vlan_features;
};
struct sk_buff {
__be16 protocol;
__u16 vlan_tci;
void *data;
};
#define ETH_ALEN 6
struct ethhdr {
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
unsigned char h_source[ETH_ALEN]; /* source ether addr */
__be16 h_proto; /* packet type ID field */
};
struct vlan_ethhdr {
unsigned char h_dest[ETH_ALEN];
unsigned char h_source[ETH_ALEN];
__be16 h_vlan_proto;
__be16 h_vlan_TCI;
__be16 h_vlan_encapsulated_proto;
};
#define ETH_P_IP 0x0800 /* Internet Protocol packet */
#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */
#define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */
#define VLAN_CFI_MASK 0x1000 /* Canonical Format Indicator */
#define VLAN_TAG_PRESENT VLAN_CFI_MASK
#define vlan_tx_tag_present(__skb) ((__skb)->vlan_tci & VLAN_TAG_PRESENT)
#define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT)
/* Functions to test */
static bool can_checksum_protocol(unsigned long features, __be16 protocol)
{
return ((features & NETIF_F_GEN_CSUM) ||
((features & NETIF_F_IP_CSUM) &&
protocol == htons(ETH_P_IP)) ||
((features & NETIF_F_IPV6_CSUM) &&
protocol == htons(ETH_P_IPV6)) ||
((features & NETIF_F_FCOE_CRC) &&
protocol == htons(ETH_P_FCOE)));
}
static bool dev_can_checksum(struct net_device *dev, struct sk_buff *skb)
{
__be16 protocol = skb->protocol;
int features = dev->features;
if (vlan_tx_tag_present(skb)) {
features &= dev->vlan_features;
} else if (protocol == htons(ETH_P_8021Q)) {
struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
protocol = veh->h_vlan_encapsulated_proto;
features &= dev->vlan_features;
}
return can_checksum_protocol(features, protocol);
}
/* Test suite */
struct test_data {
union {
struct ethhdr eh;
struct vlan_ethhdr veh;
};
struct sk_buff skb;
struct net_device dev;
};
typedef void test_fn(struct test_data *);
static void test_unknown(struct test_data *data)
{
data->dev.features = NETIF_F_IP_CSUM;
assert(!dev_can_checksum(&data->dev, &data->skb));
}
static void test_no_ip(struct test_data *data)
{
data->skb.protocol = htons(ETH_P_IP);
assert(!dev_can_checksum(&data->dev, &data->skb));
}
static void test_ip(struct test_data *data)
{
data->skb.protocol = htons(ETH_P_IP);
data->dev.features = NETIF_F_IP_CSUM;
assert(dev_can_checksum(&data->dev, &data->skb));
}
static void test_vlan_ob_unknown(struct test_data *data)
{
data->skb.vlan_tci = VLAN_CFI_MASK | 1;
data->dev.features = NETIF_F_GEN_CSUM;
assert(!dev_can_checksum(&data->dev, &data->skb));
}
static void test_no_vlan_ob_ip(struct test_data *data)
{
data->skb.protocol = htons(ETH_P_IP);
data->skb.vlan_tci = VLAN_CFI_MASK | 1;
data->dev.features = NETIF_F_IP_CSUM;
data->dev.vlan_features = 0;
assert(!dev_can_checksum(&data->dev, &data->skb));
}
static void test_vlan_ob_ip(struct test_data *data)
{
data->skb.protocol = htons(ETH_P_IP);
data->skb.vlan_tci = VLAN_CFI_MASK | 1;
data->dev.features = NETIF_F_IP_CSUM;
data->dev.vlan_features = NETIF_F_IP_CSUM;
assert(dev_can_checksum(&data->dev, &data->skb));
}
static void test_vlan_ib_unknown(struct test_data *data)
{
data->skb.protocol = htons(ETH_P_8021Q);
data->dev.features = NETIF_F_GEN_CSUM;
assert(!dev_can_checksum(&data->dev, &data->skb));
}
static void test_no_vlan_ib_ip(struct test_data *data)
{
data->skb.protocol = htons(ETH_P_8021Q);
data->veh.h_vlan_encapsulated_proto = htons(ETH_P_IP);
data->dev.features = NETIF_F_IP_CSUM;
data->dev.vlan_features = 0;
assert(!dev_can_checksum(&data->dev, &data->skb));
}
static void test_vlan_ib_ip(struct test_data *data)
{
data->skb.protocol = htons(ETH_P_8021Q);
data->veh.h_vlan_encapsulated_proto = htons(ETH_P_IP);
data->dev.features = NETIF_F_IP_CSUM;
data->dev.vlan_features = NETIF_F_IP_CSUM;
assert(dev_can_checksum(&data->dev, &data->skb));
}
static void test_no_2vlan_ob_ip(struct test_data *data)
{
data->skb.protocol = htons(ETH_P_8021Q);
data->skb.vlan_tci = VLAN_CFI_MASK | 1;
data->veh.h_vlan_encapsulated_proto = htons(ETH_P_IP);
data->dev.features = NETIF_F_IP_CSUM;
data->dev.vlan_features = NETIF_F_IP_CSUM;
assert(!dev_can_checksum(&data->dev, &data->skb));
}
static test_fn *tests[] = {
test_unknown, test_no_ip, test_ip,
test_vlan_ob_unknown, test_no_vlan_ob_ip, test_vlan_ob_ip,
test_vlan_ib_unknown, test_no_vlan_ib_ip, test_vlan_ib_ip,
test_no_2vlan_ob_ip,
};
int main(void)
{
struct test_data data;
test_fn **test;
for (test = tests;
test != tests + sizeof(tests) / sizeof(tests[0]);
++test) {
memset(&data, 0, sizeof(data));
data.skb.data = &data.eh;
(**test)(&data);
}
return 0;
}
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists