datapath: Add support for lwtunnel
[cascardo/ovs.git] / datapath / linux / compat / dev-openvswitch.c
1 #include <linux/if_bridge.h>
2 #include <linux/netdevice.h>
3 #include <linux/version.h>
4 #include <net/rtnetlink.h>
5
6 #ifndef HAVE_DEV_DISABLE_LRO
7
8 #ifdef NETIF_F_LRO
9 #include <linux/ethtool.h>
10
11 /**
12  *      dev_disable_lro - disable Large Receive Offload on a device
13  *      @dev: device
14  *
15  *      Disable Large Receive Offload (LRO) on a net device.  Must be
16  *      called under RTNL.  This is needed if received packets may be
17  *      forwarded to another interface.
18  */
19 void dev_disable_lro(struct net_device *dev)
20 {
21         if (dev->ethtool_ops && dev->ethtool_ops->get_flags &&
22             dev->ethtool_ops->set_flags) {
23                 u32 flags = dev->ethtool_ops->get_flags(dev);
24                 if (flags & ETH_FLAG_LRO) {
25                         flags &= ~ETH_FLAG_LRO;
26                         dev->ethtool_ops->set_flags(dev, flags);
27                 }
28         }
29         WARN_ON(dev->features & NETIF_F_LRO);
30 }
31 #else
32 void dev_disable_lro(struct net_device *dev) { }
33 #endif /* NETIF_F_LRO */
34
35 #endif /* HAVE_DEV_DISABLE_LRO */
36
37 #if !defined HAVE_NETDEV_RX_HANDLER_REGISTER || \
38     defined HAVE_RHEL_OVS_HOOK
39
40 static int nr_bridges;
41
42 #ifdef HAVE_RHEL_OVS_HOOK
43 int rpl_netdev_rx_handler_register(struct net_device *dev,
44                                    openvswitch_handle_frame_hook_t *hook,
45                                    void *rx_handler_data)
46 {
47         nr_bridges++;
48         rcu_assign_pointer(dev->ax25_ptr, rx_handler_data);
49
50         if (nr_bridges == 1)
51                 rcu_assign_pointer(openvswitch_handle_frame_hook, hook);
52         return 0;
53 }
54 EXPORT_SYMBOL_GPL(rpl_netdev_rx_handler_register);
55 #else
56
57 int rpl_netdev_rx_handler_register(struct net_device *dev,
58                                    struct sk_buff *(*hook)(struct net_bridge_port *p,
59                                                            struct sk_buff *skb),
60                                    void *rx_handler_data)
61 {
62         nr_bridges++;
63         if (dev->br_port)
64                 return -EBUSY;
65
66         rcu_assign_pointer(dev->br_port, rx_handler_data);
67
68         if (nr_bridges == 1)
69                 br_handle_frame_hook = hook;
70         return 0;
71 }
72 EXPORT_SYMBOL_GPL(rpl_netdev_rx_handler_register);
73 #endif
74
75 void rpl_netdev_rx_handler_unregister(struct net_device *dev)
76 {
77         nr_bridges--;
78 #ifdef HAVE_RHEL_OVS_HOOK
79         rcu_assign_pointer(dev->ax25_ptr, NULL);
80
81         if (nr_bridges)
82                 return;
83
84         rcu_assign_pointer(openvswitch_handle_frame_hook, NULL);
85 #else
86         rcu_assign_pointer(dev->br_port, NULL);
87
88         if (nr_bridges)
89                 return;
90
91         br_handle_frame_hook = NULL;
92 #endif
93 }
94 EXPORT_SYMBOL_GPL(rpl_netdev_rx_handler_unregister);
95
96 #endif
97
98 int rpl_rtnl_delete_link(struct net_device *dev)
99 {
100         const struct rtnl_link_ops *ops;
101
102         ops = dev->rtnl_link_ops;
103         if (!ops || !ops->dellink)
104                 return -EOPNOTSUPP;
105
106 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)
107         ops->dellink(dev);
108 #else
109         {
110                 LIST_HEAD(list_kill);
111
112                 ops->dellink(dev, &list_kill);
113                 unregister_netdevice_many(&list_kill);
114         }
115 #endif
116         return 0;
117 }