Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Eric W. Biederman and committed by
David S. Miller
2cf48a10 cac477e8

+11 -40
+11 -40
drivers/net/veth.c
··· 239 239 return 0; 240 240 } 241 241 242 + static 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 + 242 252 static int veth_dev_init(struct net_device *dev) 243 253 { 244 254 struct veth_net_stats *stats; ··· 275 265 static const struct net_device_ops veth_netdev_ops = { 276 266 .ndo_init = veth_dev_init, 277 267 .ndo_open = veth_open, 268 + .ndo_stop = veth_close, 278 269 .ndo_start_xmit = veth_xmit, 279 270 .ndo_get_stats = veth_get_stats, 280 271 .ndo_set_mac_address = eth_mac_addr, ··· 290 279 dev->features |= NETIF_F_LLTX; 291 280 dev->destructor = veth_dev_free; 292 281 } 293 - 294 - static void veth_change_state(struct net_device *dev) 295 - { 296 - struct net_device *peer; 297 - struct veth_priv *priv; 298 - 299 - priv = netdev_priv(dev); 300 - peer = priv->peer; 301 - 302 - if (netif_carrier_ok(peer)) { 303 - if (!netif_carrier_ok(dev)) 304 - netif_carrier_on(dev); 305 - } else { 306 - if (netif_carrier_ok(dev)) 307 - netif_carrier_off(dev); 308 - } 309 - } 310 - 311 - static int veth_device_event(struct notifier_block *unused, 312 - unsigned long event, void *ptr) 313 - { 314 - struct net_device *dev = ptr; 315 - 316 - if (dev->netdev_ops->ndo_open != veth_open) 317 - goto out; 318 - 319 - switch (event) { 320 - case NETDEV_CHANGE: 321 - veth_change_state(dev); 322 - break; 323 - } 324 - out: 325 - return NOTIFY_DONE; 326 - } 327 - 328 - static struct notifier_block veth_notifier_block __read_mostly = { 329 - .notifier_call = veth_device_event, 330 - }; 331 282 332 283 /* 333 284 * netlink interface ··· 441 468 442 469 static __init int veth_init(void) 443 470 { 444 - register_netdevice_notifier(&veth_notifier_block); 445 471 return rtnl_link_register(&veth_link_ops); 446 472 } 447 473 448 474 static __exit void veth_exit(void) 449 475 { 450 476 rtnl_link_unregister(&veth_link_ops); 451 - unregister_netdevice_notifier(&veth_notifier_block); 452 477 } 453 478 454 479 module_init(veth_init);