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

net-sysfs: expose number of carrier on/off changes

This allows to monitor carrier on/off transitions and detect link
flapping issues:
- new /sys/class/net/X/carrier_changes
- new rtnetlink IFLA_CARRIER_CHANGES (getlink)

Tested:
- grep . /sys/class/net/*/carrier_changes
+ ip link set dev X down/up
+ plug/unplug cable
- updated iproute2: prints IFLA_CARRIER_CHANGES
- iproute2 20121211-2 (debian): unchanged behavior

Signed-off-by: David Decotigny <decot@googlers.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

david decotigny and committed by
David S. Miller
2d3b479d 9c76a114

+22 -1
+3
include/linux/netdevice.h
··· 1308 1308 atomic_long_t rx_dropped; 1309 1309 atomic_long_t tx_dropped; 1310 1310 1311 + /* Stats to monitor carrier on<->off transitions */ 1312 + atomic_t carrier_changes; 1313 + 1311 1314 #ifdef CONFIG_WIRELESS_EXT 1312 1315 /* List of functions to handle Wireless Extensions (instead of ioctl). 1313 1316 * See <net/iw_handler.h> for details. Jean II */
+1
include/uapi/linux/if_link.h
··· 144 144 IFLA_NUM_RX_QUEUES, 145 145 IFLA_CARRIER, 146 146 IFLA_PHYS_PORT_ID, 147 + IFLA_CARRIER_CHANGES, 147 148 __IFLA_MAX 148 149 }; 149 150
+11
net/core/net-sysfs.c
··· 253 253 } 254 254 static DEVICE_ATTR_RO(operstate); 255 255 256 + static ssize_t carrier_changes_show(struct device *dev, 257 + struct device_attribute *attr, 258 + char *buf) 259 + { 260 + struct net_device *netdev = to_net_dev(dev); 261 + return sprintf(buf, fmt_dec, 262 + atomic_read(&netdev->carrier_changes)); 263 + } 264 + static DEVICE_ATTR_RO(carrier_changes); 265 + 256 266 /* read-write attributes */ 257 267 258 268 static int change_mtu(struct net_device *net, unsigned long new_mtu) ··· 396 386 &dev_attr_duplex.attr, 397 387 &dev_attr_dormant.attr, 398 388 &dev_attr_operstate.attr, 389 + &dev_attr_carrier_changes.attr, 399 390 &dev_attr_ifalias.attr, 400 391 &dev_attr_carrier.attr, 401 392 &dev_attr_mtu.attr,
+5 -1
net/core/rtnetlink.c
··· 822 822 + nla_total_size(4) /* IFLA_NUM_RX_QUEUES */ 823 823 + nla_total_size(1) /* IFLA_OPERSTATE */ 824 824 + nla_total_size(1) /* IFLA_LINKMODE */ 825 + + nla_total_size(4) /* IFLA_CARRIER_CHANGES */ 825 826 + nla_total_size(ext_filter_mask 826 827 & RTEXT_FILTER_VF ? 4 : 0) /* IFLA_NUM_VF */ 827 828 + rtnl_vfinfo_size(dev, ext_filter_mask) /* IFLA_VFINFO_LIST */ ··· 971 970 (dev->qdisc && 972 971 nla_put_string(skb, IFLA_QDISC, dev->qdisc->ops->id)) || 973 972 (dev->ifalias && 974 - nla_put_string(skb, IFLA_IFALIAS, dev->ifalias))) 973 + nla_put_string(skb, IFLA_IFALIAS, dev->ifalias)) || 974 + nla_put_u32(skb, IFLA_CARRIER_CHANGES, 975 + atomic_read(&dev->carrier_changes))) 975 976 goto nla_put_failure; 976 977 977 978 if (1) { ··· 1150 1147 [IFLA_NUM_TX_QUEUES] = { .type = NLA_U32 }, 1151 1148 [IFLA_NUM_RX_QUEUES] = { .type = NLA_U32 }, 1152 1149 [IFLA_PHYS_PORT_ID] = { .type = NLA_BINARY, .len = MAX_PHYS_PORT_ID_LEN }, 1150 + [IFLA_CARRIER_CHANGES] = { .type = NLA_U32 }, /* ignored */ 1153 1151 }; 1154 1152 1155 1153 static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
+2
net/sched/sch_generic.c
··· 310 310 if (test_and_clear_bit(__LINK_STATE_NOCARRIER, &dev->state)) { 311 311 if (dev->reg_state == NETREG_UNINITIALIZED) 312 312 return; 313 + atomic_inc(&dev->carrier_changes); 313 314 linkwatch_fire_event(dev); 314 315 if (netif_running(dev)) 315 316 __netdev_watchdog_up(dev); ··· 329 328 if (!test_and_set_bit(__LINK_STATE_NOCARRIER, &dev->state)) { 330 329 if (dev->reg_state == NETREG_UNINITIALIZED) 331 330 return; 331 + atomic_inc(&dev->carrier_changes); 332 332 linkwatch_fire_event(dev); 333 333 } 334 334 }