From ee26df28d0645eec382517d5bf21ebc1365b616d Mon Sep 17 00:00:00 2001 From: Eddie Kohler Date: Thu, 28 Jan 2010 12:51:38 -0800 Subject: [PATCH] Modern eth_type_trans adds some functionality for DSA tagging. Mark that we would like to use that functionality. --- config-linuxmodule.h.in | 6 +++ configure | 68 ++++++++++++++++++++++++++++++++ configure.in | 14 +++++++ elements/linuxmodule/tohost.cc | 72 ++++++++++++++++++++++------------ 4 files changed, 134 insertions(+), 26 deletions(-) diff --git a/config-linuxmodule.h.in b/config-linuxmodule.h.in index 7c619d6b78..c03673c72c 100644 --- a/config-linuxmodule.h.in +++ b/config-linuxmodule.h.in @@ -94,6 +94,12 @@ /* Define if you have the netdev_get_tx_queue function. */ #undef HAVE_NETDEV_GET_TX_QUEUE +/* Define if you have the netdev_uses_dsa_tags function. */ +#undef HAVE_NETDEV_USES_DSA_TAGS + +/* Define if you have the netdev_uses_trailer_tags function. */ +#undef HAVE_NETDEV_USES_TRAILER_TAGS + /* Define if netif_receive_skb takes 3 arguments. */ #undef HAVE_NETIF_RECEIVE_SKB_EXTENDED diff --git a/configure b/configure index b3a4f05706..32436ae172 100755 --- a/configure +++ b/configure @@ -10625,6 +10625,74 @@ $as_echo "#define HAVE_NETDEV_GET_TX_QUEUE 1" >>confdefs.h fi + ac_fn_c_check_decl "$LINENO" "netdev_uses_dsa_tags" "ac_cv_have_decl_netdev_uses_dsa_tags" "#if HAVE_LINUXMODULE_2_6 +# define KBUILD_STR(s) #s +# define KBUILD_BASENAME KBUILD_STR(click) +# define KBUILD_MODNAME KBUILD_STR(click) +#endif +#define new linux_new +#define this linux_this +#define delete linux_delete +#define class linux_class +#define virtual linux_virtual +#define typename linux_typename +#define private linux_private +#define protected linux_protected +#define public linux_public +#define namespace linux_namespace +#define false linux_false +#define true linux_true +#include +#include +#include +#include +" +if test "x$ac_cv_have_decl_netdev_uses_dsa_tags" = x""yes; then : + ac_cv_netdev_uses_dsa_tags=yes +else + ac_cv_netdev_uses_dsa_tags=no +fi + + if test $ac_cv_netdev_uses_dsa_tags = yes; then + +$as_echo "#define HAVE_NETDEV_USES_DSA_TAGS 1" >>confdefs.h + + fi + + ac_fn_c_check_decl "$LINENO" "netdev_uses_trailer_tags" "ac_cv_have_decl_netdev_uses_trailer_tags" "#if HAVE_LINUXMODULE_2_6 +# define KBUILD_STR(s) #s +# define KBUILD_BASENAME KBUILD_STR(click) +# define KBUILD_MODNAME KBUILD_STR(click) +#endif +#define new linux_new +#define this linux_this +#define delete linux_delete +#define class linux_class +#define virtual linux_virtual +#define typename linux_typename +#define private linux_private +#define protected linux_protected +#define public linux_public +#define namespace linux_namespace +#define false linux_false +#define true linux_true +#include +#include +#include +#include +" +if test "x$ac_cv_have_decl_netdev_uses_trailer_tags" = x""yes; then : + ac_cv_netdev_uses_trailer_tags=yes +else + ac_cv_netdev_uses_trailer_tags=no +fi + + if test $ac_cv_netdev_uses_trailer_tags = yes; then + +$as_echo "#define HAVE_NETDEV_USES_TRAILER_TAGS 1" >>confdefs.h + + fi + CC="$save_cc" CXX="$save_cxx" diff --git a/configure.in b/configure.in index 9932ea2e15..331088ae6f 100644 --- a/configure.in +++ b/configure.in @@ -1297,6 +1297,20 @@ void f1(int64_t) { // will fail if long long and int64_t are the same type AC_DEFINE([HAVE_NETDEV_GET_TX_QUEUE], [1], [Define if you have the netdev_get_tx_queue function.]) fi + AC_CHECK_DECL(netdev_uses_dsa_tags, [ac_cv_netdev_uses_dsa_tags=yes], [ac_cv_netdev_uses_dsa_tags=no], [CLICK_LINUXMODULE_PROLOGUE()[ +#include +#include ]]) + if test $ac_cv_netdev_uses_dsa_tags = yes; then + AC_DEFINE([HAVE_NETDEV_USES_DSA_TAGS], [1], [Define if you have the netdev_uses_dsa_tags function.]) + fi + + AC_CHECK_DECL(netdev_uses_trailer_tags, [ac_cv_netdev_uses_trailer_tags=yes], [ac_cv_netdev_uses_trailer_tags=no], [CLICK_LINUXMODULE_PROLOGUE()[ +#include +#include ]]) + if test $ac_cv_netdev_uses_trailer_tags = yes; then + AC_DEFINE([HAVE_NETDEV_USES_TRAILER_TAGS], [1], [Define if you have the netdev_uses_trailer_tags function.]) + fi + CC="$save_cc" CXX="$save_cxx" diff --git a/elements/linuxmodule/tohost.cc b/elements/linuxmodule/tohost.cc index e856d78be8..e24346e6aa 100644 --- a/elements/linuxmodule/tohost.cc +++ b/elements/linuxmodule/tohost.cc @@ -133,6 +133,38 @@ device_notifier_hook(struct notifier_block *nb, unsigned long flags, void *v) } } +static inline uint16_t +tohost_eth_type_trans(struct sk_buff *skb, struct net_device *dev) +{ +#if 0 + /* XXX Newer versions of eth_type_trans have this code, but we can't use + * it in a module since dsa_uses_dsa_tags is not exported. */ +# if HAVE_NETDEV_USES_DSA_TAGS + if (netdev_uses_dsa_tags(skb->dev)) + return __constant_htons(ETH_P_DSA); +# endif +# if HAVE_NETDEV_USES_TRAILER_TAGS + if (netdev_uses_trailer_tags(skb->dev)) + return __constant_htons(ETH_P_TRAILER); +# endif +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + const ethhdr *eth = eth_hdr(skb); +#else + const ethhdr *eth = skb->mac.ethernet; +#endif + if (ntohs(eth->h_proto) >= 1536) + return eth->h_proto; + + const unsigned char *rawp = skb->data; + /* "This is a magic hack to spot IPX packets." + * See net/ethernet/eth.c:eth_type_trans */ + if (*(const unsigned short *)rawp == 0xFFFF) + return __constant_htons(ETH_P_802_3); + return __constant_htons(ETH_P_802_2); +} + void ToHost::push(int port, Packet *p) { @@ -157,9 +189,20 @@ ToHost::push(int port, Packet *p) skb->pkt_type &= PACKET_TYPE_MASK; #endif + // skb->dst may be set if the packet came from Linux originally. In this + // case, we must clear skb->dst so Linux finds the correct dst. +#if HAVE_SKB_DST_DROP + skb_dst_drop(skb); +#else + if (skb->dst) { + dst_release(skb->dst); + skb->dst = 0; + } +#endif + // MAC header is the data pointer #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) - skb_set_mac_header(skb, 0); + skb_reset_mac_header(skb); #else skb->mac.raw = skb->data; #endif @@ -169,33 +212,10 @@ ToHost::push(int port, Packet *p) skb->protocol = __constant_htons(ETH_P_IP); else { // do not call eth_type_trans; it changes pkt_type! Instead, do its - // work directly. + // relevant work directly. skb_pull(skb, 14); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) - const ethhdr *eth = eth_hdr(skb); -#else - const ethhdr *eth = skb->mac.ethernet; -#endif - if (ntohs(eth->h_proto) >= 1536) - skb->protocol = eth->h_proto; - else { - const unsigned short *crap = (const unsigned short *)skb->data; - // "magic hack to spot IPX packets" - skb->protocol = (*crap == 0xFFFF ? htons(ETH_P_802_3) : htons(ETH_P_802_2)); - } - } - - // skb->dst may be set if the packet came from Linux originally. In this - // case, we must clear skb->dst so Linux finds the correct dst. -#if HAVE_SKB_DST_DROP - skb_dst_drop(skb); -#else - if (skb->dst) { - dst_release(skb->dst); - skb->dst = 0; + skb->protocol = tohost_eth_type_trans(skb, skb->dev); } -#endif // get protocol to pass to Linux int protocol = (_sniffers ? 0xFFFF : skb->protocol);