From dfdde7a55fa31b9b82d6767319e4943e47d70999 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 27 May 2008 17:42:16 -0700 Subject: [PATCH] Don't ever send frames on OpenFlow devices to the host stack. On Linux 2.6 only, we would send frames received on OpenFlow devices to the host TCP/IP stack if the dest Ethernet address matched the device's Ethernet address (or under some other conditions). This caused confusion when the host stack was configured for forwarding, because received IP packets would be forwarded to other interfaces with IP addresses even if the device on which they were received was configured with no IP address. (This was discovered by Murphy. Thanks Murphy!) This change drops this "feature". A more or less equivalent feature that may be less prone to confusion and which works on any kernel version will be added in a future commit via the of%d device. This also allowed factoring out common code from the bridge hooks. --- datapath/datapath.c | 55 ++++++++++++++------------------------------- 1 file changed, 17 insertions(+), 38 deletions(-) diff --git a/datapath/datapath.c b/datapath/datapath.c index 5665de47..ef8094e2 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -438,66 +438,45 @@ static int dp_maint_func(void *data) return 0; } -/* - * Used as br_handle_frame_hook. (Cannot run bridge at the same time, even on - * different set of devices!) Returns 0 if *pskb should be processed further, - * 1 if *pskb is handled. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) -/* Called with rcu_read_lock. */ -static struct sk_buff *dp_frame_hook(struct net_bridge_port *p, - struct sk_buff *skb) +static void +do_port_input(struct net_bridge_port *p, struct sk_buff *skb) { - struct ethhdr *eh = eth_hdr(skb); - struct sk_buff *skb_local = NULL; - - - if (compare_ether_addr(eh->h_dest, skb->dev->dev_addr) == 0) - return skb; - - if (is_broadcast_ether_addr(eh->h_dest) - || is_multicast_ether_addr(eh->h_dest) - || is_local_ether_addr(eh->h_dest)) - skb_local = skb_clone(skb, GFP_ATOMIC); - /* Push the Ethernet header back on. */ if (skb->protocol == htons(ETH_P_8021Q)) skb_push(skb, VLAN_ETH_HLEN); else skb_push(skb, ETH_HLEN); - fwd_port_input(p->dp->chain, skb, p->port_no); +} - return skb_local; +/* + * Used as br_handle_frame_hook. (Cannot run bridge at the same time, even on + * different set of devices!) + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +/* Called with rcu_read_lock. */ +static struct sk_buff *dp_frame_hook(struct net_bridge_port *p, + struct sk_buff *skb) +{ + do_port_input(p, skb); + return NULL; } #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) static int dp_frame_hook(struct net_bridge_port *p, struct sk_buff **pskb) { - /* Push the Ethernet header back on. */ - if ((*pskb)->protocol == htons(ETH_P_8021Q)) - skb_push(*pskb, VLAN_ETH_HLEN); - else - skb_push(*pskb, ETH_HLEN); - - fwd_port_input(p->dp->chain, *pskb, p->port_no); + do_port_input(p, *pskb); return 1; } -#else +#else /* NB: This has only been tested on 2.4.35 */ /* Called without any locks (?) */ static void dp_frame_hook(struct sk_buff *skb) { struct net_bridge_port *p = skb->dev->br_port; - - /* Push the Ethernet header back on. */ - if (skb->protocol == htons(ETH_P_8021Q)) - skb_push(skb, VLAN_ETH_HLEN); - else - skb_push(skb, ETH_HLEN); - if (p) { rcu_read_lock(); - fwd_port_input(p->dp->chain, skb, p->port_no); + do_port_input(p, skb); rcu_read_unlock(); } else kfree_skb(skb); -- 2.30.2