Let's take a look at the implementation and summarize it. please correct me if you have any mistakes.
I see the source is kernel 2.6.27, ifplugd-0.28.
Question 1: Why can only rtm_newlink be obtained when Netlink is used to detect network cable plugging?
Question 2: How can I detect Nic plugging information.
Netlink is implemented under net/Netlink/af_netlink.c, but rtnetlink. C is implemented under net/core. There is also a Netlink. h under include/net.
If you use multicast as the keyword, you can find a function named nlmsg_multicast. Its role is multicast A Netlink message. OK, follow this to go up.
Function call relationship:
Nlmsg_multicast
^
|
Nlmsg_policy
^
|
Rtnl_notify
^
|
Rtmsg_ifinfo
^
|
Rtnetlink_event
^
|
Rtnetlink_dev_notifier
At this point, go up to register_netdevice_notifier (& rtnetlink_dev_notifier). When you register the notification chain, you don't have to go up and initialize it again.
The rtnetlink_event function provides the following processing functions:
Switch (event ){
Case netdev_unregister:
Rtmsg_ifinfo (rtm_dellink, Dev ,~ 0u );
Break;
Case netdev_register:
Rtmsg_ifinfo (rtm_newlink, Dev ,~ 0u );
Break;
Case netdev_up:
Case netdev_down:
Rtmsg_ifinfo (rtm_newlink, Dev, iff_up | iff_running );
Break;
Case netdev_change:
Case netdev_going_down:
Break;
Default:
Rtmsg_ifinfo (rtm_newlink, Dev, 0 );
Break;
It can be found that both netdev_up and netdev_down are processed in the same way.
Rtm_newlink. Only netdev_unregister uploads rtm_dellink. Currently, netdev_unregister is triggered when only the rmmod NIC Driver is used in this experiment.
Problem 1 should end here.
By the way, the dev_change_flags function is also called for rtmsg_ifinfo. This function is used when IOCTL siocsifflags is processed.
Problem 2 is mainly the four methods of ifplugd (without considering wireless), the Work Function in ifplugd. C:
Switch (api_mode ){
Case api_ethtool: detect_beat_func = interface_detect_beat_ethtool;
Break;
Case api_mii: detect_beat_func = interface_detect_beat_mii; break;
Case api_private: detect_beat_func = interface_detect_beat_priv;
Break;
Case api_wlan: detect_beat_func = interface_detect_beat_wlan; break;
Case api_iff: detect_beat_func = interface_detect_beat_iff; break;
Default:
Detect_beat_func = detect_beat_auto;
Ifplugd uses detect_beat_auto in the default configuration. In fact, this function is to try the above functions one by one. interface_detect_beat_ethtool and interface_detect_beat_mii. The status of the network card can be obtained through these four methods, but the implementation is different.
The following describes their implementation:
Method 1: interface_detect_beat_ethtool
Tune
The siocethtool Implementation of ioctl, and dev_ethtool function processing in net/CORE/dev. C. The ethtool mechanism in the kernel, the most
It was 98 years ago by David S.
Miller made it first. This is a cool man. It is mainly implemented in net/CORE/ethtool. C. Ifplugd uses the ethtool_glink command to obtain
Obtain the NIC status. The processing of this command is the ethtool_get_value function:
Case ethtool_glink:
Rc = ethtool_get_value (Dev, useraddr, ethcmd, Dev-> ethtool_ops-> get_link );
Ethtool_get_value
Call back Dev-> ethtool_ops-> get_link to get the NIC status. This method must be implemented by each NIC Driver.
For example, the e100_get_link function is implemented in drivers/NET/e100.c. Call e100_get_link
Mii_link_ OK (deivers/NET/MII. c), mii_link_ OK processing:
MII-> mdio_read (MII-> Dev, MII-> phy_id, mii_bmsr );
If (MII-> mdio_read (MII-> Dev, MII-> phy_id, mii_bmsr) & bmsr_lstatus)
Return 1;
Return 0;
Mdio_read is a callback implemented by each of the MII drivers. The specific implementation is back to the specific NIC driver, and the mdio_read function of E100 in e100.c. The ioread32 function is used to read the NIC register.
Method 2: interface_detect_beat_mii
Call the siocgmiiphy and siocgmiireg Implementation of ioctl, and process the following in the dev_ifsioc function (net/CORE/dev. C:
If (Dev-> do_ioctl ){
If (netif_device_present (Dev ))
Err = Dev-> do_ioctl (Dev, IFR, CMD );
Else
Err =-enodev;
}
Dev-> do_ioctl
It is implemented by each NIC Driver.
For example, the E100 function is called in the e100_do_ioctl function of drivers/NET/e100.c and e100_do_ioctl.
Generic_mii_ioctl (deivers/NET/MII. C ). The process is as follows:
Switch (CMD ){
Case siocgmiiphy:
Mii_data-> phy_id = mii_if-> phy_id;
/* Fall through */
Case siocgmiireg:
Mii_data-> val_out =
Mii_if-> mdio_read (mii_if-> Dev, mii_data-> phy_id,
Mii_data-> reg_num );
Break;
Many Nic Drivers call generic_mii_ioctl to process IOCTL. MII Definition
[Url = Response
. It seems that the NIC Driver monitors and controls the phy. For more information about mdio_read, see the stuff written in method 1 above.
Method 3: interface_detect_beat_priv
Base
In the same way as method 2, call the siocdevprivate of ioctl, and implement the dev_ifsioc function (net/Core
/Dev. c) Processing in same method 2, one difference is that siocdevprivate to siocdevprivate +
15 is a command defined by each Nic. Some Enis are implemented and some are not. For example, E100 does not implement this IOCTL. The rtl8150 usb nic Driver is implemented.
Method 4: interface_detect_beat_iff
Call the siocgifflags Implementation of ioctl, which is handled in the dev_ifsioc_locked function (net/CORE/dev. C:
Case siocgifflags:/* Get interface flags */
IFR-> ifr_flags = dev_get_flags (Dev );
Return 0;
The processing of the dev_get_flags function:
Flags = (Dev-> flags &~ (Iff_promisc |
Iff_allmulti |
Iff_running |
Iff_lower_up |
Iff_dormant) |
(Dev-> gflags & (iff_promisc |
Iff_allmulti ));
If (netif_running (Dev )){
If (netif_oper_up (Dev ))
Flags | = iff_running;
If (netif_carrier_ OK (Dev ))
Flags | = iff_lower_up;
If (netif_dormant (Dev ))
Flags | = iff_dormant;
The hardware is not checked by the NIC driver, but by the existing status flag.
To sum up, methods 1 and 2 should be the most safe. You can directly check the hardware registers. Method 3 may not support the driver, and method 4 is not very reliable.