diff mbox series

[net-next,v2] net: core: Expose number of link up/down transitions

Message ID 20180118175921.17645-1-f.fainelli@gmail.com
State Accepted, archived
Delegated to: David Miller
Headers show
Series [net-next,v2] net: core: Expose number of link up/down transitions | expand

Commit Message

Florian Fainelli Jan. 18, 2018, 5:59 p.m. UTC
From: David Decotigny <decot@googlers.com>

Expose the number of times the link has been going UP or DOWN, and
update the "carrier_changes" counter to be the sum of these two events.
While at it, also update the sysfs-class-net documentation to cover:
carrier_changes (3.15), carrier_up_count (4.16) and carrier_down_count
(4.16)

Signed-off-by: David Decotigny <decot@googlers.com>
[Florian:
* rebase
* add documentation
* merge carrier_changes with up/down counters]
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v2:
- fixed sysfs attributes to use <iface>
- renamed count_link_{up,down} to carrier_{up,down}_count to match
  existing carrier_changes semantics

 Documentation/ABI/testing/sysfs-class-net | 24 ++++++++++++++++++++++++
 include/linux/netdevice.h                 |  6 ++++--
 include/uapi/linux/if_link.h              |  2 ++
 net/core/net-sysfs.c                      | 25 ++++++++++++++++++++++++-
 net/core/rtnetlink.c                      | 13 +++++++++++--
 net/sched/sch_generic.c                   |  4 ++--
 6 files changed, 67 insertions(+), 7 deletions(-)

Comments

David Miller Jan. 22, 2018, 8:43 p.m. UTC | #1
From: Florian Fainelli <f.fainelli@gmail.com>
Date: Thu, 18 Jan 2018 09:59:13 -0800

> From: David Decotigny <decot@googlers.com>
> 
> Expose the number of times the link has been going UP or DOWN, and
> update the "carrier_changes" counter to be the sum of these two events.
> While at it, also update the sysfs-class-net documentation to cover:
> carrier_changes (3.15), carrier_up_count (4.16) and carrier_down_count
> (4.16)
> 
> Signed-off-by: David Decotigny <decot@googlers.com>
> [Florian:
> * rebase
> * add documentation
> * merge carrier_changes with up/down counters]
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
> ---
> Changes in v2:
> - fixed sysfs attributes to use <iface>
> - renamed count_link_{up,down} to carrier_{up,down}_count to match
>   existing carrier_changes semantics

Like David Ahern I am strongly against the proliferation of sysfs files
attached to network devices and the per-netdevice costs associated with
that.

However, dealing with that is a longer term issue that nobody has a clear
plan for.  Therefore I cannot reject this change on that basis alone.

The information is useful, so applied, thanks.
Florian Fainelli Jan. 22, 2018, 8:46 p.m. UTC | #2
On 01/22/2018 12:43 PM, David Miller wrote:
> From: Florian Fainelli <f.fainelli@gmail.com>
> Date: Thu, 18 Jan 2018 09:59:13 -0800
> 
>> From: David Decotigny <decot@googlers.com>
>>
>> Expose the number of times the link has been going UP or DOWN, and
>> update the "carrier_changes" counter to be the sum of these two events.
>> While at it, also update the sysfs-class-net documentation to cover:
>> carrier_changes (3.15), carrier_up_count (4.16) and carrier_down_count
>> (4.16)
>>
>> Signed-off-by: David Decotigny <decot@googlers.com>
>> [Florian:
>> * rebase
>> * add documentation
>> * merge carrier_changes with up/down counters]
>> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
>> ---
>> Changes in v2:
>> - fixed sysfs attributes to use <iface>
>> - renamed count_link_{up,down} to carrier_{up,down}_count to match
>>   existing carrier_changes semantics
> 
> Like David Ahern I am strongly against the proliferation of sysfs files
> attached to network devices and the per-netdevice costs associated with
> that.
> 
> However, dealing with that is a longer term issue that nobody has a clear
> plan for.  Therefore I cannot reject this change on that basis alone.
> 
> The information is useful, so applied, thanks.

Thanks! David A, do you have any plans to revive your LWD/LWT devices
patches, AFAIR you were allowing a knob disabling the creation of sysfs
attributes.
David Ahern Jan. 22, 2018, 10:16 p.m. UTC | #3
On 1/22/18 1:46 PM, Florian Fainelli wrote:
>>
>> Like David Ahern I am strongly against the proliferation of sysfs files
>> attached to network devices and the per-netdevice costs associated with
>> that.
>>
>> However, dealing with that is a longer term issue that nobody has a clear
>> plan for.  Therefore I cannot reject this change on that basis alone.
>>
>> The information is useful, so applied, thanks.
> 
> Thanks! David A, do you have any plans to revive your LWD/LWT devices
> patches, AFAIR you were allowing a knob disabling the creation of sysfs
> attributes.
> 

At the moment (and for the next few months) I am focusing on route
scalability:
	http://vger.kernel.org/netconf2017_files/nexthop-objects.pdf

I do think about the lightweight netdevice need from time to time. If
anyone has the time and wants to pick it up, the patches are on github:

    https://github.com/dsahern/linux net/lwt-dev
    https://github.com/dsahern/iproute2 lwt-dev

As a refresher on the concept, the intention is that users can *opt in*
to skipping the overhead of standard netdevs by adding a flag during the
link create.

Virtual devices such as vlan, macvlan, ipvlan, vrf, dummy are great
candidates for this flag, and potentially bonds and bridges if the
deployment use case is ok with what the lightweight moniker means which is:

1. no sysfs files for the device

2. no separate sysctl tree for the device (default settings are used)

3. delayed network protocol (IPv4, IPv6, MPLS) initializations

The last one dove tails with the need for L2 only devices and suggests a
the need for a separate control flag. If you dig further into the
protocol initializations one could easily justify flags for a finer
granularity on what is skipped (e.g., do protocol init, but skip netconf
(use default values) and skip snmp stats).

Slide 9 in
https://www.netdevconf.org/1.1/proceedings/slides/ahern-aleksandrov-prabhu-scaling-network-cumulus.pdf
shows the memory allocations. 40+kB / netdev is a killer. Using the lwt
tag, that can be shrunk from ~44k to ~4k - a big gain. e.g., 4k VRFs
(yes, I have been asked about that) would go from ~160MB to just ~16MB.

As I recall the kernel patch is not complete, only shows the intent and
what the flag offers (pain is worth the gain). During the last
discussion on this the idea of a net_dev_common was suggested. After
looking into it I believe it is the wrong direction -- an unnecessary
churn on the code base when the only intention is to omit / bypass
existing code paths. The common would come in handy in trying to reduce
the size of 'struct net_device' which is driven by 'struct device' and
similar h/w entries.
diff mbox series

Patch

diff --git a/Documentation/ABI/testing/sysfs-class-net b/Documentation/ABI/testing/sysfs-class-net
index 6856da99b6f7..2f1788111cd9 100644
--- a/Documentation/ABI/testing/sysfs-class-net
+++ b/Documentation/ABI/testing/sysfs-class-net
@@ -259,3 +259,27 @@  Contact:	netdev@vger.kernel.org
 Description:
 		Symbolic link to the PHY device this network device is attached
 		to.
+
+What:		/sys/class/net/<iface>/carrier_changes
+Date:		Mar 2014
+KernelVersion:	3.15
+Contact:	netdev@vger.kernel.org
+Description:
+		32-bit unsigned integer counting the number of times the link has
+		seen a change from UP to DOWN and vice versa
+
+What:		/sys/class/net/<iface>/carrier_up_count
+Date:		Jan 2018
+KernelVersion:	4.16
+Contact:	netdev@vger.kernel.org
+Description:
+		32-bit unsigned integer counting the number of times the link has
+		been up
+
+What:		/sys/class/net/<iface>/carrier_down_count
+Date:		Jan 2018
+KernelVersion:	4.16
+Contact:	netdev@vger.kernel.org
+Description:
+		32-bit unsigned integer counting the number of times the link has
+		been down
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index ed0799a12bf2..837e9cb7e358 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1680,8 +1680,6 @@  struct net_device {
 	unsigned long		base_addr;
 	int			irq;
 
-	atomic_t		carrier_changes;
-
 	/*
 	 *	Some hardware also needs these fields (state,dev_list,
 	 *	napi_list,unreg_list,close_list) but they are not
@@ -1719,6 +1717,10 @@  struct net_device {
 	atomic_long_t		tx_dropped;
 	atomic_long_t		rx_nohandler;
 
+	/* Stats to monitor link on/off, flapping */
+	atomic_t		carrier_up_count;
+	atomic_t		carrier_down_count;
+
 #ifdef CONFIG_WIRELESS_EXT
 	const struct iw_handler_def *wireless_handlers;
 	struct iw_public_data	*wireless_data;
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index f8f04fed6186..8616131e2c61 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -161,6 +161,8 @@  enum {
 	IFLA_EVENT,
 	IFLA_NEW_NETNSID,
 	IFLA_IF_NETNSID,
+	IFLA_CARRIER_UP_COUNT,
+	IFLA_CARRIER_DOWN_COUNT,
 	__IFLA_MAX
 };
 
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 7bf8b85ade16..c4a28f4667b6 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -295,10 +295,31 @@  static ssize_t carrier_changes_show(struct device *dev,
 	struct net_device *netdev = to_net_dev(dev);
 
 	return sprintf(buf, fmt_dec,
-		       atomic_read(&netdev->carrier_changes));
+		       atomic_read(&netdev->carrier_up_count) +
+		       atomic_read(&netdev->carrier_down_count));
 }
 static DEVICE_ATTR_RO(carrier_changes);
 
+static ssize_t carrier_up_count_show(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct net_device *netdev = to_net_dev(dev);
+
+	return sprintf(buf, fmt_dec, atomic_read(&netdev->carrier_up_count));
+}
+static DEVICE_ATTR_RO(carrier_up_count);
+
+static ssize_t carrier_down_count_show(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	struct net_device *netdev = to_net_dev(dev);
+
+	return sprintf(buf, fmt_dec, atomic_read(&netdev->carrier_down_count));
+}
+static DEVICE_ATTR_RO(carrier_down_count);
+
 /* read-write attributes */
 
 static int change_mtu(struct net_device *dev, unsigned long new_mtu)
@@ -547,6 +568,8 @@  static struct attribute *net_class_attrs[] __ro_after_init = {
 	&dev_attr_phys_port_name.attr,
 	&dev_attr_phys_switch_id.attr,
 	&dev_attr_proto_down.attr,
+	&dev_attr_carrier_up_count.attr,
+	&dev_attr_carrier_down_count.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(net_class);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 16d644a4f974..97874daa1336 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -990,6 +990,8 @@  static noinline size_t if_nlmsg_size(const struct net_device *dev,
 	       + nla_total_size(4)  /* IFLA_NEW_NETNSID */
 	       + nla_total_size(1)  /* IFLA_PROTO_DOWN */
 	       + nla_total_size(4)  /* IFLA_IF_NETNSID */
+	       + nla_total_size(4)  /* IFLA_CARRIER_UP_COUNT */
+	       + nla_total_size(4)  /* IFLA_CARRIER_DOWN_COUNT */
 	       + 0;
 }
 
@@ -1551,8 +1553,13 @@  static int rtnl_fill_ifinfo(struct sk_buff *skb,
 	     nla_put_string(skb, IFLA_QDISC, dev->qdisc->ops->id)) ||
 	    nla_put_ifalias(skb, dev) ||
 	    nla_put_u32(skb, IFLA_CARRIER_CHANGES,
-			atomic_read(&dev->carrier_changes)) ||
-	    nla_put_u8(skb, IFLA_PROTO_DOWN, dev->proto_down))
+			atomic_read(&dev->carrier_up_count) +
+			atomic_read(&dev->carrier_down_count)) ||
+	    nla_put_u8(skb, IFLA_PROTO_DOWN, dev->proto_down) ||
+	    nla_put_u32(skb, IFLA_CARRIER_UP_COUNT,
+			atomic_read(&dev->carrier_up_count)) ||
+	    nla_put_u32(skb, IFLA_CARRIER_DOWN_COUNT,
+			atomic_read(&dev->carrier_down_count)))
 		goto nla_put_failure;
 
 	if (event != IFLA_EVENT_NONE) {
@@ -1656,6 +1663,8 @@  static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
 	[IFLA_EVENT]		= { .type = NLA_U32 },
 	[IFLA_GROUP]		= { .type = NLA_U32 },
 	[IFLA_IF_NETNSID]	= { .type = NLA_S32 },
+	[IFLA_CARRIER_UP_COUNT]	= { .type = NLA_U32 },
+	[IFLA_CARRIER_DOWN_COUNT] = { .type = NLA_U32 },
 };
 
 static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index ef8b4ecde2ac..1816bde47256 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -510,7 +510,7 @@  void netif_carrier_on(struct net_device *dev)
 	if (test_and_clear_bit(__LINK_STATE_NOCARRIER, &dev->state)) {
 		if (dev->reg_state == NETREG_UNINITIALIZED)
 			return;
-		atomic_inc(&dev->carrier_changes);
+		atomic_inc(&dev->carrier_up_count);
 		linkwatch_fire_event(dev);
 		if (netif_running(dev))
 			__netdev_watchdog_up(dev);
@@ -529,7 +529,7 @@  void netif_carrier_off(struct net_device *dev)
 	if (!test_and_set_bit(__LINK_STATE_NOCARRIER, &dev->state)) {
 		if (dev->reg_state == NETREG_UNINITIALIZED)
 			return;
-		atomic_inc(&dev->carrier_changes);
+		atomic_inc(&dev->carrier_down_count);
 		linkwatch_fire_event(dev);
 	}
 }