Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
operstate [2018/08/26 15:55] – [Philosophy] rpjdayoperstate [2018/08/27 11:07] (current) – [Testing under sysfs] rpjday
Line 66: Line 66:
  
 ==== include/uapi/linux/if.h ==== ==== include/uapi/linux/if.h ====
 +
 +Possible values for ''netdev%%->%%operstate'':
  
 <code> <code>
Line 116: Line 118:
 ===== Testing under sysfs ===== ===== Testing under sysfs =====
  
-Unplugging and plugging:+Unplugging and plugging (administratively, the interface remains UP the whole time):
  
 <code> <code>
Line 150: Line 152:
 </code> </code>
  
-This should be set by ''dev_open()'', so it should be up regardless.+This should be set by ''dev_open()'', so it should be up regardless. See usage [[https://elixir.bootlin.com/linux/latest/ident/__LINK_STATE_START|here]].
 ==== netif_oper_up() ==== ==== netif_oper_up() ====
  
-This is the important one related to plugging and unplugging:+This is the important one related to plugging and unplugging (ignore the possibility of ''IF_OPER_UNKNOWN'' for now):
  
 <code> <code>
Line 169: Line 171:
 </code> </code>
 ==== netif_carrier_ok() ==== ==== netif_carrier_ok() ====
 +
 +This routine becomes important shortly:
  
 <code> <code>
Line 188: Line 192:
  
 Clearly(?) based on presence or absence of carrier (see tests above). Clearly(?) based on presence or absence of carrier (see tests above).
 +
 +==== net/core/net-sysfs.c ====
 +
 +Consults ''netif_carrier_ok()'':
 +
 +<code>
 +static ssize_t carrier_show(struct device *dev,
 +                            struct device_attribute *attr, char *buf)
 +{
 +        struct net_device *netdev = to_net_dev(dev);
 +
 +        if (netif_running(netdev))  // if __LINK_STATE_START, which should be true
 +                return sprintf(buf, fmt_dec, !!netif_carrier_ok(netdev));
 +
 +        return -EINVAL;
 +}
 +static DEVICE_ATTR_RW(carrier);
 +</code>
 +
 +defined as:
 +
 +<code>
 +static inline bool netif_carrier_ok(const struct net_device *dev)
 +{
 + return !test_bit(__LINK_STATE_NOCARRIER, &dev->state);
 +}
 +</code>
 +
 +==== Where is IF_OPER_DOWN set? ====
 +
 +From ''net/core/link_watch.c'', it all comes back to ''netif_carrier_ok()'':
 +
 +<code>
 +static unsigned char default_operstate(const struct net_device *dev)
 +{
 + if (!netif_carrier_ok(dev))
 + return (dev->ifindex != dev_get_iflink(dev) ?
 + IF_OPER_LOWERLAYERDOWN : IF_OPER_DOWN);
 +
 + if (netif_dormant(dev))
 + return IF_OPER_DORMANT;
 +
 + return IF_OPER_UP;
 +}
 +</code>
 +
 +which brings us back to who sets ''%%__%%LINK_STATE_NOCARRIER''.
 +
 +==== Setting/detecting carrier ====
 +
 +From ''net/sched/sch_generic.c'':
 +
 +<code>
 +/**
 + * netif_carrier_on - set carrier
 + * @dev: network device
 + *
 + * Device has detected that carrier.
 + */
 +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_up_count);
 + linkwatch_fire_event(dev);
 + if (netif_running(dev))
 + __netdev_watchdog_up(dev);
 + }
 +}
 +EXPORT_SYMBOL(netif_carrier_on);
 +
 +/**
 + * netif_carrier_off - clear carrier
 + * @dev: network device
 + *
 + * Device has detected loss of carrier.
 + */
 +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_down_count);
 + linkwatch_fire_event(dev);
 + }
 +}
 +EXPORT_SYMBOL(netif_carrier_off);
 +</code>
 +
 +So who calls ''netif_carrier_off()''? Apparently, lots of people.
  • operstate.1535298923.txt.gz
  • Last modified: 2018/08/26 15:55
  • by rpjday