aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2009-02-25 14:47:29 -0500
committerDavid S. Miller <davem@davemloft.net>2009-03-01 23:44:21 -0500
commit2cf48a10aa1f45c7b1f1117a829f2f8a1a1309e2 (patch)
tree4b467e81ebb7aa6c6789791115426ab5837b701f /drivers/net
parentcac477e8f1038c41b6f29d3161ce351462ef3df7 (diff)
veth: Fix carrier detect
The current implementation of carrier detect in veth is broken. It reports the link is down until both sides of the veth pair are administatively up and then forever after it reports link up. So fix veth so that it only reports link up when both interfaces of the pair are administratively up. Signed-off-by: Eric Biederman <ebiederm@aristanetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/veth.c51
1 files changed, 11 insertions, 40 deletions
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 108bbbeacfb6..124fe75b8a8a 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -239,6 +239,16 @@ static int veth_open(struct net_device *dev)
239 return 0; 239 return 0;
240} 240}
241 241
242static int veth_close(struct net_device *dev)
243{
244 struct veth_priv *priv = netdev_priv(dev);
245
246 netif_carrier_off(dev);
247 netif_carrier_off(priv->peer);
248
249 return 0;
250}
251
242static int veth_dev_init(struct net_device *dev) 252static int veth_dev_init(struct net_device *dev)
243{ 253{
244 struct veth_net_stats *stats; 254 struct veth_net_stats *stats;
@@ -265,6 +275,7 @@ static void veth_dev_free(struct net_device *dev)
265static const struct net_device_ops veth_netdev_ops = { 275static const struct net_device_ops veth_netdev_ops = {
266 .ndo_init = veth_dev_init, 276 .ndo_init = veth_dev_init,
267 .ndo_open = veth_open, 277 .ndo_open = veth_open,
278 .ndo_stop = veth_close,
268 .ndo_start_xmit = veth_xmit, 279 .ndo_start_xmit = veth_xmit,
269 .ndo_get_stats = veth_get_stats, 280 .ndo_get_stats = veth_get_stats,
270 .ndo_set_mac_address = eth_mac_addr, 281 .ndo_set_mac_address = eth_mac_addr,
@@ -280,44 +291,6 @@ static void veth_setup(struct net_device *dev)
280 dev->destructor = veth_dev_free; 291 dev->destructor = veth_dev_free;
281} 292}
282 293
283static void veth_change_state(struct net_device *dev)
284{
285 struct net_device *peer;
286 struct veth_priv *priv;
287
288 priv = netdev_priv(dev);
289 peer = priv->peer;
290
291 if (netif_carrier_ok(peer)) {
292 if (!netif_carrier_ok(dev))
293 netif_carrier_on(dev);
294 } else {
295 if (netif_carrier_ok(dev))
296 netif_carrier_off(dev);
297 }
298}
299
300static int veth_device_event(struct notifier_block *unused,
301 unsigned long event, void *ptr)
302{
303 struct net_device *dev = ptr;
304
305 if (dev->netdev_ops->ndo_open != veth_open)
306 goto out;
307
308 switch (event) {
309 case NETDEV_CHANGE:
310 veth_change_state(dev);
311 break;
312 }
313out:
314 return NOTIFY_DONE;
315}
316
317static struct notifier_block veth_notifier_block __read_mostly = {
318 .notifier_call = veth_device_event,
319};
320
321/* 294/*
322 * netlink interface 295 * netlink interface
323 */ 296 */
@@ -468,14 +441,12 @@ static struct rtnl_link_ops veth_link_ops = {
468 441
469static __init int veth_init(void) 442static __init int veth_init(void)
470{ 443{
471 register_netdevice_notifier(&veth_notifier_block);
472 return rtnl_link_register(&veth_link_ops); 444 return rtnl_link_register(&veth_link_ops);
473} 445}
474 446
475static __exit void veth_exit(void) 447static __exit void veth_exit(void)
476{ 448{
477 rtnl_link_unregister(&veth_link_ops); 449 rtnl_link_unregister(&veth_link_ops);
478 unregister_netdevice_notifier(&veth_notifier_block);
479} 450}
480 451
481module_init(veth_init); 452module_init(veth_init);