X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=datapath%2Fvport-netdev.c;h=c15923b2048515339ea6cac36da56ea4f962d2c2;hb=0ef165ecb57943e17a8ee8270df68ffb8d032e29;hp=4e7342c10bb090901ed07588fd88360366392706;hpb=db0c31340fe260f281aaea07b0fbce41bef07c7d;p=sliver-openvswitch.git diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c index 4e7342c10..c15923b20 100644 --- a/datapath/vport-netdev.c +++ b/datapath/vport-netdev.c @@ -25,32 +25,15 @@ #include #include #include +#include #include -#include "checksum.h" #include "datapath.h" #include "vlan.h" #include "vport-internal_dev.h" #include "vport-netdev.h" -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) && \ - !defined(HAVE_VLAN_BUG_WORKAROUND) -#include - -static int vlan_tso __read_mostly; -module_param(vlan_tso, int, 0644); -MODULE_PARM_DESC(vlan_tso, "Enable TSO for VLAN packets"); -#else -#define vlan_tso true -#endif - -#ifdef HAVE_RHEL_OVS_HOOK -static atomic_t nr_bridges = ATOMIC_INIT(0); - -extern struct sk_buff *(*openvswitch_handle_frame_hook)(struct sk_buff *skb); -#endif - static void netdev_port_receive(struct vport *vport, struct sk_buff *skb); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) @@ -85,7 +68,7 @@ static struct sk_buff *netdev_frame_hook(struct sk_buff *skb) return NULL; } -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) /* * Used as br_handle_frame_hook. (Cannot run bridge at the same time, even on * different set of devices!) @@ -97,51 +80,19 @@ static struct sk_buff *netdev_frame_hook(struct net_bridge_port *p, netdev_port_receive((struct vport *)p, skb); return NULL; } -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) -/* - * Used as br_handle_frame_hook. (Cannot run bridge at the same time, even on - * different set of devices!) - */ -/* Called with rcu_read_lock and bottom-halves disabled. */ -static int netdev_frame_hook(struct net_bridge_port *p, struct sk_buff **pskb) -{ - netdev_port_receive((struct vport *)p, *pskb); - return 1; -} #else #error #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) || \ - defined HAVE_RHEL_OVS_HOOK -static int netdev_init(void) { return 0; } -static void netdev_exit(void) { } -#else -static int port_count; - -static void netdev_init(void) +static struct net_device *get_dpdev(struct datapath *dp) { - port_count++; - if (port_count > 1) - return; - - /* Hook into callback used by the bridge to intercept packets. - * Parasites we are. */ - br_handle_frame_hook = netdev_frame_hook; + struct vport *local; - return; + local = ovs_vport_ovsl(dp, OVSP_LOCAL); + BUG_ON(!local); + return netdev_vport_priv(local)->dev; } -static void netdev_exit(void) -{ - port_count--; - if (port_count > 0) - return; - - br_handle_frame_hook = NULL; -} -#endif - static struct vport *netdev_create(const struct vport_parms *parms) { struct vport *vport; @@ -171,30 +122,25 @@ static struct vport *netdev_create(const struct vport_parms *parms) } rtnl_lock(); -#ifdef HAVE_RHEL_OVS_HOOK - rcu_assign_pointer(netdev_vport->dev->ax25_ptr, vport); - atomic_inc(&nr_bridges); - rcu_assign_pointer(openvswitch_handle_frame_hook, netdev_frame_hook); -#else + err = netdev_master_upper_dev_link(netdev_vport->dev, + get_dpdev(vport->dp)); + if (err) + goto error_unlock; + err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook, vport); if (err) - goto error_unlock; -#endif + goto error_master_upper_dev_unlink; dev_set_promiscuity(netdev_vport->dev, 1); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) - dev_disable_lro(netdev_vport->dev); -#endif netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH; rtnl_unlock(); - netdev_init(); return vport; -#ifndef HAVE_RHEL_OVS_HOOK +error_master_upper_dev_unlink: + netdev_upper_dev_unlink(netdev_vport->dev, get_dpdev(vport->dp)); error_unlock: -#endif rtnl_unlock(); error_put: dev_put(netdev_vport->dev); @@ -209,25 +155,29 @@ static void free_port_rcu(struct rcu_head *rcu) struct netdev_vport *netdev_vport = container_of(rcu, struct netdev_vport, rcu); -#ifdef HAVE_RHEL_OVS_HOOK - rcu_assign_pointer(netdev_vport->dev->ax25_ptr, NULL); - - if (atomic_dec_and_test(&nr_bridges)) - rcu_assign_pointer(openvswitch_handle_frame_hook, NULL); -#endif dev_put(netdev_vport->dev); ovs_vport_free(vport_from_priv(netdev_vport)); } -static void netdev_destroy(struct vport *vport) +void ovs_netdev_detach_dev(struct vport *vport) { struct netdev_vport *netdev_vport = netdev_vport_priv(vport); - netdev_exit(); - rtnl_lock(); + ASSERT_RTNL(); netdev_vport->dev->priv_flags &= ~IFF_OVS_DATAPATH; netdev_rx_handler_unregister(netdev_vport->dev); + netdev_upper_dev_unlink(netdev_vport->dev, + netdev_master_upper_dev_get(netdev_vport->dev)); dev_set_promiscuity(netdev_vport->dev, -1); +} + +static void netdev_destroy(struct vport *vport) +{ + struct netdev_vport *netdev_vport = netdev_vport_priv(vport); + + rtnl_lock(); + if (ovs_netdev_get_vport(netdev_vport->dev)) + ovs_netdev_detach_dev(vport); rtnl_unlock(); call_rcu(&netdev_vport->rcu, free_port_rcu); @@ -257,11 +207,7 @@ static void netdev_port_receive(struct vport *vport, struct sk_buff *skb) return; skb_push(skb, ETH_HLEN); - - if (unlikely(compute_ip_summed(skb, false))) - goto error; - - vlan_copy_skb_tci(skb); + ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN); ovs_vport_receive(vport, skb, NULL); return; @@ -280,19 +226,6 @@ static unsigned int packet_length(const struct sk_buff *skb) return length; } -static bool dev_supports_vlan_tx(struct net_device *dev) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) - /* Software fallback means every device supports vlan_tci on TX. */ - return true; -#elif defined(HAVE_VLAN_BUG_WORKAROUND) - return dev->features & NETIF_F_HW_VLAN_TX; -#else - /* Assume that the driver is buggy. */ - return false; -#endif -} - static int netdev_send(struct vport *vport, struct sk_buff *skb) { struct netdev_vport *netdev_vport = netdev_vport_priv(vport); @@ -307,60 +240,6 @@ static int netdev_send(struct vport *vport, struct sk_buff *skb) } skb->dev = netdev_vport->dev; - forward_ip_summed(skb, true); - - if (vlan_tx_tag_present(skb) && !dev_supports_vlan_tx(skb->dev)) { - int features; - - features = netif_skb_features(skb); - - if (!vlan_tso) - features &= ~(NETIF_F_TSO | NETIF_F_TSO6 | - NETIF_F_UFO | NETIF_F_FSO); - - if (netif_needs_gso(skb, features)) { - struct sk_buff *nskb; - - nskb = skb_gso_segment(skb, features); - if (!nskb) { - if (unlikely(skb_cloned(skb) && - pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) - goto drop; - - skb_shinfo(skb)->gso_type &= ~SKB_GSO_DODGY; - goto tag; - } - - if (IS_ERR(nskb)) - goto drop; - consume_skb(skb); - skb = nskb; - - len = 0; - do { - nskb = skb->next; - skb->next = NULL; - - skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb)); - if (likely(skb)) { - len += skb->len; - vlan_set_tci(skb, 0); - dev_queue_xmit(skb); - } - - skb = nskb; - } while (skb); - - return len; - } - -tag: - skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb)); - if (unlikely(!skb)) - return 0; - vlan_set_tci(skb, 0); - } - len = skb->len; dev_queue_xmit(skb);