Linux: utilisation ethtool (test du lien ethernet, vitesse, options wol)

Description

N'ayant pas trouvé l'équivalent, je vous propose un léger exemple d'utilisation d'ethtool.

Ici je me concentre sur 3 des nombreuses possibilités d'ethtool, et ce, en lecture uniquement :
Récupération de l'état du lien ethernet vue par le host (lien physique inclus).
Récupération de la vitesse de la carte.
Récupération des option Wake On Lan.

L'utilisation d'ethtool nécessite les caps CAP_NET_ADMIN.

Source / Exemple :


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
/* headers pour if_ ifreq et les ios ethtool */
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/in.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>

/* forward */
int net_hwd_get_phy_link(int fd, const char* iface);
int net_hwd_get_link_speed(int fd, const char* iface);
int net_hwd_get_wol_supported_opts(int fd, const char* iface);

int main(int argc, char** argv) {
  int fd, n, i;
  char* iface;

  /* Liste toutes les cartes réseaux du PC */
  struct if_nameindex *nameindex = if_nameindex();
  if(nameindex == NULL){
    fprintf(stderr, "if_nameindex: (%d) %s.\n", errno, strerror(errno));
    return EXIT_FAILURE;
  }

  /* boucle sur les interfaces */
  i = 0; /* init */
  while(1){
    if(nameindex[i].if_name == NULL) break;
    /* Récupération du nom qui sera utilise plus bas. */
    iface = nameindex[i++].if_name;
    
    /* Création d'un socket qui sera utilise pour l'ioctl */
    fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
    if (fd < 0) {
      if_freenameindex(nameindex);
      fprintf(stderr, "socket failed: (%d) %s.\n", errno, strerror(errno));
      return EXIT_FAILURE;
    }

    /* Affiche le nom de la carte */
    printf("IFace name: %s\n", iface);

    /* Récupération de l&#8217;état du lien */
    n = net_hwd_get_phy_link(fd, iface);
    printf("\tLink: %s.\n", n == 1 ? "Detected" : "Not detected");

    /* Récupération de la vitesse du lien */
    n = net_hwd_get_link_speed(fd, iface);
    if(n > 0) {
      printf("\tSpeed: ");
      switch (n) {
	case SPEED_10:    printf("10Mbps.\n");  break;
	case SPEED_100:   printf("100Mbps.\n"); break;
	case SPEED_1000:  printf("1Gbps.\n");   break;
	case SPEED_2500:  printf("2.5Gbps.\n"); break;
	case SPEED_10000: printf("10Gbps.\n");  break;
	default:          printf("%d.\n", n);   break;
      }
    } else 
      printf("\tSpeed not supported.\n");

    /* Récupération des options WOL */
    n = net_hwd_get_wol_supported_opts(fd, iface);
    if(n < 0)
    printf("\tWOL not supported.\n");
    else {
      printf("\tWOL options: ");
      if(n&WAKE_PHY)   printf("WAKE_PHY ");
      if(n&WAKE_UCAST) printf("WAKE_UCAST ");
      if(n&WAKE_MCAST) printf("WAKE_MCAST ");
      if(n&WAKE_BCAST) printf("WAKE_BCAST ");
      if(n&WAKE_ARP)   printf("WAKE_ARP ");
      printf("\n");
    }

    /* fermeture du socket */
    close(fd);
  }
  /* Libération des ressources */
  if_freenameindex(nameindex);

  return EXIT_SUCCESS;
}

inline struct ifreq net_hwd_prepare_ifreq(const char* iface) {
  struct ifreq ifr;
  /* Cleanup de la structure ifr. */
  memset(&ifr, 0, sizeof(ifr));
  /* Set du nom de l'interface qui sera utilisée pour récupérer les infos. */
  strncpy(ifr.ifr_name, iface, IFNAMSIZ);
  return ifr;
}

/**

  • \brief Récupération de l&#8217;état de la carte pour le host ainsi que l&#8217;état du lien physique.
  • \param fd Descripteur du socket.
  • \param iface Nom de l'interface.
  • \return -1 si une erreur se produit, sinon 1 si le lien est OK ou 0 si le lien est KO.
  • /
int net_hwd_get_phy_link(int fd, const char* iface) { int err; struct ethtool_value v; struct ifreq ifr = net_hwd_prepare_ifreq(iface); memset(&v, 0, sizeof(v)); /* Commande de type GET LINK */ v.cmd = ETHTOOL_GLINK; /* Set de la structure */ ifr.ifr_data = (void*)&v; /* Demande de l&#8217;état du lien */ err = ioctl(fd, SIOCETHTOOL, &ifr); if (err < 0) { if(errno != EOPNOTSUPP) /* pas besoin de printer si non supporté */ /* Si la commande n'est pas supportée (device non trouve, Droits non suffisants, etc...) */ fprintf(stderr, "get link status failed: (%d) %s.\n", errno, strerror(errno)); return -1; } return !!v.data; } /**
  • \brief Récupération de la vitesse de l'interface.
  • \param fd Descripteur du socket.
  • \param iface Nom de l'interface.
  • \return \a -1 si une erreur se produit, sinon la vitesse (SPEED_10, SPEED_100, SPEED_2500, SPEED_10000, autre).
  • /
int net_hwd_get_link_speed(int fd, const char* iface) { int err; struct ethtool_cmd v; struct ifreq ifr = net_hwd_prepare_ifreq(iface); memset(&v, 0, sizeof(v)); /* Commande de type GET SETTINGS */ v.cmd = ETHTOOL_GSET; /* Set de la structure */ ifr.ifr_data = (void*)&v; /* Demande de la vitesse du lien */ err = ioctl(fd, SIOCETHTOOL, &ifr); if (err < 0) { if(errno != EOPNOTSUPP) /* pas besoin de printer si non supporté */ /* Si la commande n'est pas supportée (device non trouve, Droits non suffisants, etc...) */ fprintf(stderr, "get speed failed: (%d) %s.\n", errno, strerror(errno)); return -1; } return ethtool_cmd_speed(&v); } /**
  • \brief Récupération des options supportées.
  • \param fd Descripteur du socket.
  • \param iface Nom de l'interface.
  • \return \a -1 si une erreur se produit, sinon les options.
  • /
int net_hwd_get_wol_supported_opts(int fd, const char* iface) { int err; struct ethtool_wolinfo v; struct ifreq ifr = net_hwd_prepare_ifreq(iface); memset(&v, 0, sizeof(v)); /* Commande de type GET WOL */ v.cmd = ETHTOOL_GWOL; /* Set de la structure */ ifr.ifr_data = (void*)&v; /* Demande de la vitesse du lien */ err = ioctl(fd, SIOCETHTOOL, &ifr); if (err < 0) { if(errno != EOPNOTSUPP) /* pas besoin de printer si non support& */ /* Si la commande n'est pas supportée (device non trouve, Droits non suffisants, etc...) */ fprintf(stderr, "get wol failed: (%d) %s.\n", errno, strerror(errno)); return -1; } return v.supported; }

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.