Free ofX network device when we're done with it.
[sliver-openvswitch.git] / datapath / dp_dev.c
1 #include <linux/kernel.h>
2 #include <linux/netdevice.h>
3 #include <linux/etherdevice.h>
4 #include <linux/rcupdate.h>
5
6 #include "datapath.h"
7 #include "forward.h"
8
9 struct dp_dev {
10         struct net_device_stats stats;
11         struct datapath *dp;
12 };
13
14 static struct dp_dev *dp_dev_priv(struct net_device *netdev) 
15 {
16         return netdev_priv(netdev);
17 }
18
19 static struct net_device_stats *dp_dev_get_stats(struct net_device *netdev)
20 {
21         struct dp_dev *dp_dev = dp_dev_priv(netdev);
22         return &dp_dev->stats;
23 }
24
25 int dp_dev_recv(struct net_device *netdev, struct sk_buff *skb) 
26 {
27         int len = skb->len;
28         struct dp_dev *dp_dev = dp_dev_priv(netdev);
29         skb->pkt_type = PACKET_HOST;
30         skb->protocol = eth_type_trans(skb, netdev);
31         netif_rx(skb);
32         netdev->last_rx = jiffies;
33         dp_dev->stats.rx_packets++;
34         dp_dev->stats.rx_bytes += len;
35         return len;
36 }
37
38 static int dp_dev_mac_addr(struct net_device *dev, void *p)
39 {
40         struct sockaddr *addr = p;
41
42         if (netif_running(dev))
43                 return -EBUSY;
44         if (!is_valid_ether_addr(addr->sa_data))
45                 return -EADDRNOTAVAIL;
46         memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
47         return 0;
48 }
49
50 static int dp_dev_xmit(struct sk_buff *skb, struct net_device *netdev)
51 {
52         struct dp_dev *dp_dev = dp_dev_priv(netdev);
53         struct datapath *dp;
54         rcu_read_lock();
55         dp = dp_dev->dp;
56         if (likely(dp != NULL)) {
57                 dp_dev->stats.tx_packets++;
58                 dp_dev->stats.tx_bytes += skb->len;
59                 skb_reset_mac_header(skb);
60                 fwd_port_input(dp->chain, skb, OFPP_LOCAL);
61         } else {
62                 dp_dev->stats.tx_dropped++;
63                 kfree_skb(skb);
64         }
65         rcu_read_unlock();
66         return 0;
67 }
68
69 static int dp_dev_open(struct net_device *netdev)
70 {
71         netif_start_queue(netdev);
72         return 0;
73 }
74
75 static int dp_dev_stop(struct net_device *netdev)
76 {
77         netif_stop_queue(netdev);
78         return 0;
79 }
80
81 static void
82 do_setup(struct net_device *netdev)
83 {
84         ether_setup(netdev);
85
86         netdev->get_stats = dp_dev_get_stats;
87         netdev->hard_start_xmit = dp_dev_xmit;
88         netdev->open = dp_dev_open;
89         netdev->stop = dp_dev_stop;
90         netdev->tx_queue_len = 0;
91         netdev->set_mac_address = dp_dev_mac_addr;
92
93         netdev->flags = IFF_BROADCAST | IFF_MULTICAST;
94
95         random_ether_addr(netdev->dev_addr);
96 }
97
98
99 int dp_dev_setup(struct datapath *dp)
100 {
101         struct dp_dev *dp_dev;
102         struct net_device *netdev;
103         char of_name[8];
104         int err;
105
106         snprintf(of_name, sizeof of_name, "of%d", dp->dp_idx);
107         netdev = alloc_netdev(sizeof(struct dp_dev), of_name, do_setup);
108         if (!netdev)
109                 return -ENOMEM;
110
111         err = register_netdev(netdev);
112         if (err) {
113                 free_netdev(netdev);
114                 return err;
115         }
116
117         dp_dev = dp_dev_priv(netdev);
118         dp_dev->dp = dp;
119         dp->netdev = netdev;
120         return 0;
121 }
122
123 void dp_dev_destroy(struct datapath *dp)
124 {
125         struct dp_dev *dp_dev = dp_dev_priv(dp->netdev);
126         dp_dev->dp = NULL;
127         synchronize_net();
128         unregister_netdev(dp->netdev);
129         free_netdev(dp->netdev);
130 }
131
132 int is_dp_dev(struct net_device *netdev) 
133 {
134         return netdev->open == dp_dev_open;
135 }