Author: glebius
Date: Sun Aug 31 06:46:21 2014
New Revision: 270870
URL: http://svnweb.freebsd.org/changeset/base/270870

Log:
  o Remove struct if_data from struct ifnet. Now it is merely API structure
    for route(4) socket and ifmib(4) sysctl.
  o Move fields from if_data to ifnet, but keep all statistic counters
    separate, since they should disappear later.
  o Provide function if_data_copy() to fill if_data, utilize it in routing
    socket and ifmib handler.
  o Provide overridable ifnet(9) method to fetch counters. If no provided,
    if_get_counters_compat() would be used, that returns old counters.
  
  Sponsored by: Netflix
  Sponsored by: Nginx, Inc.

Modified:
  head/sys/net/if.c
  head/sys/net/if_mib.c
  head/sys/net/if_var.h
  head/sys/net/rtsock.c

Modified: head/sys/net/if.c
==============================================================================
--- head/sys/net/if.c   Sun Aug 31 06:30:50 2014        (r270869)
+++ head/sys/net/if.c   Sun Aug 31 06:46:21 2014        (r270870)
@@ -605,8 +605,7 @@ if_attach_internal(struct ifnet *ifp, in
        if_addgroup(ifp, IFG_ALL);
 
        getmicrotime(&ifp->if_lastchange);
-       ifp->if_data.ifi_epoch = time_uptime;
-       ifp->if_data.ifi_datalen = sizeof(struct if_data);
+       ifp->if_epoch = time_uptime;
 
        KASSERT((ifp->if_transmit == NULL && ifp->if_qflush == NULL) ||
            (ifp->if_transmit != NULL && ifp->if_qflush != NULL),
@@ -615,7 +614,10 @@ if_attach_internal(struct ifnet *ifp, in
                ifp->if_transmit = if_transmit;
                ifp->if_qflush = if_qflush;
        }
-       
+
+       if (ifp->if_get_counter == NULL)
+               ifp->if_get_counter = if_get_counter_compat;
+
        if (!vmove) {
 #ifdef MAC
                mac_ifnet_create(ifp);
@@ -1384,6 +1386,77 @@ if_rtdel(struct radix_node *rn, void *ar
 }
 
 /*
+ * Return counter values from old racy non-pcpu counters.
+ */
+uint64_t
+if_get_counter_compat(struct ifnet *ifp, ifnet_counter cnt)
+{
+
+       switch (cnt) {
+               case IFCOUNTER_IPACKETS:
+                       return (ifp->if_ipackets);
+               case IFCOUNTER_IERRORS:
+                       return (ifp->if_ierrors);
+               case IFCOUNTER_OPACKETS:
+                       return (ifp->if_opackets);
+               case IFCOUNTER_OERRORS:
+                       return (ifp->if_oerrors);
+               case IFCOUNTER_COLLISIONS:
+                       return (ifp->if_collisions);
+               case IFCOUNTER_IBYTES:
+                       return (ifp->if_ibytes);
+               case IFCOUNTER_OBYTES:
+                       return (ifp->if_obytes);
+               case IFCOUNTER_IMCASTS:
+                       return (ifp->if_imcasts);
+               case IFCOUNTER_OMCASTS:
+                       return (ifp->if_omcasts);
+               case IFCOUNTER_IQDROPS:
+                       return (ifp->if_iqdrops);
+               case IFCOUNTER_OQDROPS:
+                       return (ifp->if_oqdrops);
+               case IFCOUNTER_NOPROTO:
+                       return (ifp->if_noproto);
+       }
+       panic("%s: unknown counter %d", __func__, cnt);
+}
+
+/*
+ * Copy data from ifnet to userland API structure if_data.
+ */
+void
+if_data_copy(struct ifnet *ifp, struct if_data *ifd)
+{
+
+       ifd->ifi_type = ifp->if_type;
+       ifd->ifi_physical = 0;
+       ifd->ifi_addrlen = ifp->if_addrlen;
+       ifd->ifi_hdrlen = ifp->if_hdrlen;
+       ifd->ifi_link_state = ifp->if_link_state;
+       ifd->ifi_vhid = 0;
+       ifd->ifi_datalen = sizeof(struct if_data);
+       ifd->ifi_mtu = ifp->if_mtu;
+       ifd->ifi_metric = ifp->if_metric;
+       ifd->ifi_baudrate = ifp->if_baudrate;
+       ifd->ifi_hwassist = ifp->if_hwassist;
+       ifd->ifi_epoch = ifp->if_epoch;
+       ifd->ifi_lastchange = ifp->if_lastchange;
+
+       ifd->ifi_ipackets = ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS);
+       ifd->ifi_ierrors = ifp->if_get_counter(ifp, IFCOUNTER_IERRORS);
+       ifd->ifi_opackets = ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS);
+       ifd->ifi_oerrors = ifp->if_get_counter(ifp, IFCOUNTER_OERRORS);
+       ifd->ifi_collisions = ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS);
+       ifd->ifi_ibytes = ifp->if_get_counter(ifp, IFCOUNTER_IBYTES);
+       ifd->ifi_obytes = ifp->if_get_counter(ifp, IFCOUNTER_OBYTES);
+       ifd->ifi_imcasts = ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS);
+       ifd->ifi_omcasts = ifp->if_get_counter(ifp, IFCOUNTER_OMCASTS);
+       ifd->ifi_iqdrops = ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS);
+       ifd->ifi_oqdrops = ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS);
+       ifd->ifi_noproto = ifp->if_get_counter(ifp, IFCOUNTER_NOPROTO);
+}
+
+/*
  * Wrapper functions for struct ifnet address list locking macros.  These are
  * used by kernel modules to avoid encoding programming interface or binary
  * interface assumptions that may be violated when kernel-internal locking
@@ -2167,7 +2240,8 @@ ifhwioctl(u_long cmd, struct ifnet *ifp,
                break;
 
        case SIOCGIFPHYS:
-               ifr->ifr_phys = ifp->if_physical;
+               /* XXXGL: did this ever worked? */
+               ifr->ifr_phys = 0;
                break;
 
        case SIOCGIFDESCR:
@@ -3915,7 +3989,7 @@ if_sendq_prepend(if_t ifp, struct mbuf *
 int
 if_setifheaderlen(if_t ifp, int len)
 {
-       ((struct ifnet *)ifp)->if_data.ifi_hdrlen = len;
+       ((struct ifnet *)ifp)->if_hdrlen = len;
        return (0);
 }
 

Modified: head/sys/net/if_mib.c
==============================================================================
--- head/sys/net/if_mib.c       Sun Aug 31 06:30:50 2014        (r270869)
+++ head/sys/net/if_mib.c       Sun Aug 31 06:46:21 2014        (r270870)
@@ -99,10 +99,9 @@ sysctl_ifdata(SYSCTL_HANDLER_ARGS) /* XX
                bzero(&ifmd, sizeof(ifmd));
                strlcpy(ifmd.ifmd_name, ifp->if_xname, sizeof(ifmd.ifmd_name));
 
-#define COPY(fld) ifmd.ifmd_##fld = ifp->if_##fld
-               COPY(pcount);
-               COPY(data);
-#undef COPY
+               ifmd.ifmd_pcount = ifp->if_pcount;
+               if_data_copy(ifp, &ifmd.ifmd_data);
+
                ifmd.ifmd_flags = ifp->if_flags | ifp->if_drv_flags;
                ifmd.ifmd_snd_len = ifp->if_snd.ifq_len;
                ifmd.ifmd_snd_maxlen = ifp->if_snd.ifq_maxlen;

Modified: head/sys/net/if_var.h
==============================================================================
--- head/sys/net/if_var.h       Sun Aug 31 06:30:50 2014        (r270869)
+++ head/sys/net/if_var.h       Sun Aug 31 06:46:21 2014        (r270870)
@@ -94,11 +94,27 @@ VNET_DECLARE(struct pfil_head, link_pfil
 #define        V_link_pfil_hook        VNET(link_pfil_hook)
 #endif /* _KERNEL */
 
+typedef enum {
+       IFCOUNTER_IPACKETS = 1,
+       IFCOUNTER_IERRORS,
+       IFCOUNTER_OPACKETS,
+       IFCOUNTER_OERRORS,
+       IFCOUNTER_COLLISIONS,
+       IFCOUNTER_IBYTES,
+       IFCOUNTER_OBYTES,
+       IFCOUNTER_IMCASTS,
+       IFCOUNTER_OMCASTS,
+       IFCOUNTER_IQDROPS,
+       IFCOUNTER_OQDROPS,
+       IFCOUNTER_NOPROTO,
+} ifnet_counter;
+
 typedef        void (*if_start_fn_t)(struct ifnet *);
 typedef        int (*if_ioctl_fn_t)(struct ifnet *, u_long, caddr_t);
 typedef        void (*if_init_fn_t)(void *);
 typedef void (*if_qflush_fn_t)(struct ifnet *);
 typedef int (*if_transmit_fn_t)(struct ifnet *, struct mbuf *);
+typedef        uint64_t (*if_get_counter_t)(struct ifnet *, ifnet_counter);
 
 /* Opaque object pointing to interface structure (ifnet) */
 typedef void *if_t;
@@ -136,8 +152,21 @@ struct ifnet {
        size_t  if_linkmiblen;          /* length of above data */
        int     if_drv_flags;           /* driver-managed status flags */
        u_int   if_refcount;            /* reference count */
+
+       /* These fields are shared with struct if_data. */
+       uint8_t         if_type;        /* ethernet, tokenring, etc */
+       uint8_t         if_addrlen;     /* media address length */
+       uint8_t         if_hdrlen;      /* media header length */
+       uint8_t         if_link_state;  /* current link state */
+       uint32_t        if_spare32;
+       uint32_t        if_mtu;         /* maximum transmission unit */
+       uint32_t        if_metric;      /* routing metric (external only) */
+       uint64_t        if_baudrate;    /* linespeed */
+       uint64_t        if_hwassist;    /* HW offload capabilities, see IFCAP */
+       time_t          if_epoch;       /* uptime at attach or stat reset */
+       struct timeval  if_lastchange;  /* time of last administrative change */
+
        struct  ifaltq if_snd;          /* output queue (includes altq) */
-       struct  if_data if_data;        /* type information and statistics */
        struct  task if_linktask;       /* task for link change events */
 
        /* Addresses of different protocol families assigned to this if. */
@@ -190,6 +219,7 @@ struct ifnet {
 
        void    (*if_reassign)          /* reassign to vnet routine */
                (struct ifnet *, struct vnet *, char *);
+       if_get_counter_t if_get_counter; /* get counter values */
 
        /* Stuff that's only temporary and doesn't belong here. */
        u_int   if_hw_tsomax;           /* tso burst length limit, the minimum
@@ -197,45 +227,31 @@ struct ifnet {
                                         * XXXAO: Have to find a better place
                                         * for it eventually. */
        /*
-        * Spare fields are added so that we can modify sensitive data
-        * structures without changing the kernel binary interface, and must
-        * be used with care where binary compatibility is required.
+        * Old, racy and expensive statistics, should not be used in
+        * new drivers.
+        */
+       uint64_t        if_ipackets;    /* packets received on interface */
+       uint64_t        if_ierrors;     /* input errors on interface */
+       uint64_t        if_opackets;    /* packets sent on interface */
+       uint64_t        if_oerrors;     /* output errors on interface */
+       uint64_t        if_collisions;  /* collisions on csma interfaces */
+       uint64_t        if_ibytes;      /* total number of octets received */
+       uint64_t        if_obytes;      /* total number of octets sent */
+       uint64_t        if_imcasts;     /* packets received via multicast */
+       uint64_t        if_omcasts;     /* packets sent via multicast */
+       uint64_t        if_iqdrops;     /* dropped on input */
+       uint64_t        if_oqdrops;     /* dropped on output */
+       uint64_t        if_noproto;     /* destined for unsupported protocol */
+
+       /*
+        * Spare fields to be added before branching a stable branch, so
+        * that structure can be enhanced without changing the kernel
+        * binary interface.
         */
-       char    if_cspare[3];
-       int     if_ispare[4];
-       void    *if_unused[2];
-       void    *if_pspare[8];          /* 1 netmap, 7 TDB */
 };
 
 #include <net/ifq.h>   /* XXXAO: temporary unconditional include */
 
-/*
- * XXX These aliases are terribly dangerous because they could apply
- * to anything.
- */
-#define        if_mtu          if_data.ifi_mtu
-#define        if_type         if_data.ifi_type
-#define if_physical    if_data.ifi_physical
-#define        if_addrlen      if_data.ifi_addrlen
-#define        if_hdrlen       if_data.ifi_hdrlen
-#define        if_metric       if_data.ifi_metric
-#define        if_link_state   if_data.ifi_link_state
-#define        if_baudrate     if_data.ifi_baudrate
-#define        if_hwassist     if_data.ifi_hwassist
-#define        if_ipackets     if_data.ifi_ipackets
-#define        if_ierrors      if_data.ifi_ierrors
-#define        if_opackets     if_data.ifi_opackets
-#define        if_oerrors      if_data.ifi_oerrors
-#define        if_collisions   if_data.ifi_collisions
-#define        if_ibytes       if_data.ifi_ibytes
-#define        if_obytes       if_data.ifi_obytes
-#define        if_imcasts      if_data.ifi_imcasts
-#define        if_omcasts      if_data.ifi_omcasts
-#define        if_iqdrops      if_data.ifi_iqdrops
-#define        if_oqdrops      if_data.ifi_oqdrops
-#define        if_noproto      if_data.ifi_noproto
-#define        if_lastchange   if_data.ifi_lastchange
-
 /* for compatibility with other BSDs */
 #define        if_addrlist     if_addrhead
 #define        if_list         if_link
@@ -513,6 +529,8 @@ typedef     void *if_com_alloc_t(u_char type
 typedef        void if_com_free_t(void *com, u_char type);
 void   if_register_com_alloc(u_char type, if_com_alloc_t *a, if_com_free_t *f);
 void   if_deregister_com_alloc(u_char type);
+void   if_data_copy(struct ifnet *, struct if_data *);
+uint64_t if_get_counter_compat(struct ifnet *, ifnet_counter);
 
 #define IF_LLADDR(ifp)                                                 \
     LLADDR((struct sockaddr_dl *)((ifp)->if_addr->ifa_addr))

Modified: head/sys/net/rtsock.c
==============================================================================
--- head/sys/net/rtsock.c       Sun Aug 31 06:30:50 2014        (r270869)
+++ head/sys/net/rtsock.c       Sun Aug 31 06:46:21 2014        (r270870)
@@ -1252,7 +1252,7 @@ rt_ifmsg(struct ifnet *ifp)
        ifm = mtod(m, struct if_msghdr *);
        ifm->ifm_index = ifp->if_index;
        ifm->ifm_flags = ifp->if_flags | ifp->if_drv_flags;
-       ifm->ifm_data = ifp->if_data;
+       if_data_copy(ifp, &ifm->ifm_data);
        ifm->ifm_addrs = 0;
        rt_dispatch(m, AF_UNSPEC);
 }
@@ -1574,7 +1574,7 @@ sysctl_iflist_ifml(struct ifnet *ifp, st
                ifd = &ifm->ifm_data;
        }
 
-       *ifd = ifp->if_data;
+       if_data_copy(ifp, ifd);
 
        /* Some drivers still use ifqueue(9), add its stats. */
        ifd->ifi_oqdrops += ifp->if_snd.ifq_drops;
@@ -1609,7 +1609,7 @@ sysctl_iflist_ifm(struct ifnet *ifp, str
                ifd = &ifm->ifm_data;
        }
 
-       *ifd = ifp->if_data;
+       if_data_copy(ifp, ifd);
 
        /* Some drivers still use ifqueue(9), add its stats. */
        ifd->ifi_oqdrops += ifp->if_snd.ifq_drops;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to