0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/module.h>
0010 #include <linux/netdevice.h>
0011 #include <linux/if.h>
0012 #include <net/sock.h>
0013 #include <net/pkt_sched.h>
0014 #include <linux/rtnetlink.h>
0015 #include <linux/jiffies.h>
0016 #include <linux/spinlock.h>
0017 #include <linux/workqueue.h>
0018 #include <linux/bitops.h>
0019 #include <linux/types.h>
0020
0021 #include "dev.h"
0022
0023 enum lw_bits {
0024 LW_URGENT = 0,
0025 };
0026
0027 static unsigned long linkwatch_flags;
0028 static unsigned long linkwatch_nextevent;
0029
0030 static void linkwatch_event(struct work_struct *dummy);
0031 static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event);
0032
0033 static LIST_HEAD(lweventlist);
0034 static DEFINE_SPINLOCK(lweventlist_lock);
0035
0036 static unsigned char default_operstate(const struct net_device *dev)
0037 {
0038 if (netif_testing(dev))
0039 return IF_OPER_TESTING;
0040
0041 if (!netif_carrier_ok(dev))
0042 return (dev->ifindex != dev_get_iflink(dev) ?
0043 IF_OPER_LOWERLAYERDOWN : IF_OPER_DOWN);
0044
0045 if (netif_dormant(dev))
0046 return IF_OPER_DORMANT;
0047
0048 return IF_OPER_UP;
0049 }
0050
0051
0052 static void rfc2863_policy(struct net_device *dev)
0053 {
0054 unsigned char operstate = default_operstate(dev);
0055
0056 if (operstate == dev->operstate)
0057 return;
0058
0059 write_lock(&dev_base_lock);
0060
0061 switch(dev->link_mode) {
0062 case IF_LINK_MODE_TESTING:
0063 if (operstate == IF_OPER_UP)
0064 operstate = IF_OPER_TESTING;
0065 break;
0066
0067 case IF_LINK_MODE_DORMANT:
0068 if (operstate == IF_OPER_UP)
0069 operstate = IF_OPER_DORMANT;
0070 break;
0071 case IF_LINK_MODE_DEFAULT:
0072 default:
0073 break;
0074 }
0075
0076 dev->operstate = operstate;
0077
0078 write_unlock(&dev_base_lock);
0079 }
0080
0081
0082 void linkwatch_init_dev(struct net_device *dev)
0083 {
0084
0085 if (!netif_carrier_ok(dev) || netif_dormant(dev) ||
0086 netif_testing(dev))
0087 rfc2863_policy(dev);
0088 }
0089
0090
0091 static bool linkwatch_urgent_event(struct net_device *dev)
0092 {
0093 if (!netif_running(dev))
0094 return false;
0095
0096 if (dev->ifindex != dev_get_iflink(dev))
0097 return true;
0098
0099 if (netif_is_lag_port(dev) || netif_is_lag_master(dev))
0100 return true;
0101
0102 return netif_carrier_ok(dev) && qdisc_tx_changing(dev);
0103 }
0104
0105
0106 static void linkwatch_add_event(struct net_device *dev)
0107 {
0108 unsigned long flags;
0109
0110 spin_lock_irqsave(&lweventlist_lock, flags);
0111 if (list_empty(&dev->link_watch_list)) {
0112 list_add_tail(&dev->link_watch_list, &lweventlist);
0113 netdev_hold(dev, &dev->linkwatch_dev_tracker, GFP_ATOMIC);
0114 }
0115 spin_unlock_irqrestore(&lweventlist_lock, flags);
0116 }
0117
0118
0119 static void linkwatch_schedule_work(int urgent)
0120 {
0121 unsigned long delay = linkwatch_nextevent - jiffies;
0122
0123 if (test_bit(LW_URGENT, &linkwatch_flags))
0124 return;
0125
0126
0127 if (urgent) {
0128 if (test_and_set_bit(LW_URGENT, &linkwatch_flags))
0129 return;
0130 delay = 0;
0131 }
0132
0133
0134 if (delay > HZ)
0135 delay = 0;
0136
0137
0138
0139
0140
0141 if (test_bit(LW_URGENT, &linkwatch_flags))
0142 mod_delayed_work(system_wq, &linkwatch_work, 0);
0143 else
0144 schedule_delayed_work(&linkwatch_work, delay);
0145 }
0146
0147
0148 static void linkwatch_do_dev(struct net_device *dev)
0149 {
0150
0151
0152
0153
0154 smp_mb__before_atomic();
0155
0156
0157
0158
0159 clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state);
0160
0161 rfc2863_policy(dev);
0162 if (dev->flags & IFF_UP) {
0163 if (netif_carrier_ok(dev))
0164 dev_activate(dev);
0165 else
0166 dev_deactivate(dev);
0167
0168 netdev_state_change(dev);
0169 }
0170
0171
0172
0173 __dev_put(dev);
0174 }
0175
0176 static void __linkwatch_run_queue(int urgent_only)
0177 {
0178 #define MAX_DO_DEV_PER_LOOP 100
0179
0180 int do_dev = MAX_DO_DEV_PER_LOOP;
0181 struct net_device *dev;
0182 LIST_HEAD(wrk);
0183
0184
0185 if (urgent_only)
0186 do_dev += MAX_DO_DEV_PER_LOOP;
0187
0188
0189
0190
0191
0192
0193
0194
0195 if (!urgent_only)
0196 linkwatch_nextevent = jiffies + HZ;
0197
0198 else if (time_after(linkwatch_nextevent, jiffies + HZ))
0199 linkwatch_nextevent = jiffies;
0200
0201 clear_bit(LW_URGENT, &linkwatch_flags);
0202
0203 spin_lock_irq(&lweventlist_lock);
0204 list_splice_init(&lweventlist, &wrk);
0205
0206 while (!list_empty(&wrk) && do_dev > 0) {
0207
0208 dev = list_first_entry(&wrk, struct net_device, link_watch_list);
0209 list_del_init(&dev->link_watch_list);
0210
0211 if (!netif_device_present(dev) ||
0212 (urgent_only && !linkwatch_urgent_event(dev))) {
0213 list_add_tail(&dev->link_watch_list, &lweventlist);
0214 continue;
0215 }
0216
0217
0218
0219 netdev_tracker_free(dev, &dev->linkwatch_dev_tracker);
0220 spin_unlock_irq(&lweventlist_lock);
0221 linkwatch_do_dev(dev);
0222 do_dev--;
0223 spin_lock_irq(&lweventlist_lock);
0224 }
0225
0226
0227 list_splice_init(&wrk, &lweventlist);
0228
0229 if (!list_empty(&lweventlist))
0230 linkwatch_schedule_work(0);
0231 spin_unlock_irq(&lweventlist_lock);
0232 }
0233
0234 void linkwatch_forget_dev(struct net_device *dev)
0235 {
0236 unsigned long flags;
0237 int clean = 0;
0238
0239 spin_lock_irqsave(&lweventlist_lock, flags);
0240 if (!list_empty(&dev->link_watch_list)) {
0241 list_del_init(&dev->link_watch_list);
0242 clean = 1;
0243
0244
0245
0246 netdev_tracker_free(dev, &dev->linkwatch_dev_tracker);
0247 }
0248 spin_unlock_irqrestore(&lweventlist_lock, flags);
0249 if (clean)
0250 linkwatch_do_dev(dev);
0251 }
0252
0253
0254
0255 void linkwatch_run_queue(void)
0256 {
0257 __linkwatch_run_queue(0);
0258 }
0259
0260
0261 static void linkwatch_event(struct work_struct *dummy)
0262 {
0263 rtnl_lock();
0264 __linkwatch_run_queue(time_after(linkwatch_nextevent, jiffies));
0265 rtnl_unlock();
0266 }
0267
0268
0269 void linkwatch_fire_event(struct net_device *dev)
0270 {
0271 bool urgent = linkwatch_urgent_event(dev);
0272
0273 if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) {
0274 linkwatch_add_event(dev);
0275 } else if (!urgent)
0276 return;
0277
0278 linkwatch_schedule_work(urgent);
0279 }
0280 EXPORT_SYMBOL(linkwatch_fire_event);