Use device notifier in Linux kernel switch for detecting port status changes.
[sliver-openvswitch.git] / datapath / dp_notify.c
1 /*
2  * Distributed under the terms of the GNU GPL version 2.
3  * Copyright (c) 2007, 2008 The Board of Trustees of The Leland 
4  * Stanford Junior University
5  */
6
7 /* Handle changes to managed devices */
8
9 #include <linux/netdevice.h>
10
11 #include "datapath.h"
12
13
14 static int dp_device_event(struct notifier_block *unused, unsigned long event, 
15                 void *ptr) 
16 {
17         struct net_device *dev = ptr;
18         struct net_bridge_port *p = dev->br_port;
19         unsigned long int flags;
20         uint32_t orig_status;
21
22
23         /* Check if monitored port */
24         if (!p)
25                 return NOTIFY_DONE;
26
27         spin_lock_irqsave(&p->lock, flags);
28         orig_status = p->status;
29
30         switch (event) {
31                 case NETDEV_CHANGE:
32                         if (netif_carrier_ok(p->dev))
33                                 p->status &= ~OFPPFL_LINK_DOWN;
34                         else
35                                 p->status |= OFPPFL_LINK_DOWN;
36                         break;
37
38                 case NETDEV_DOWN:
39                         p->status |= OFPPFL_PORT_DOWN;
40                         break;
41
42                 case NETDEV_UP:
43                         p->status &= ~OFPPFL_PORT_DOWN;
44                         break;
45
46                 case NETDEV_UNREGISTER:
47                         /* xxx Make sure this is correct */
48                         spin_unlock_irqrestore(&p->lock, flags);
49                         dp_del_switch_port(p);
50                         return NOTIFY_DONE;
51                         break;
52         }
53         spin_unlock_irqrestore(&p->lock, flags);
54
55         if (orig_status != p->status) 
56                 dp_send_port_status(p, OFPPR_MOD);
57
58         return NOTIFY_DONE;
59 }
60
61 struct notifier_block dp_device_notifier = {
62         .notifier_call = dp_device_event
63 };