nfs-ganesha 1.4

nfs_ip_stats.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=8:tabstop=8:
00003  *
00004  * Copyright CEA/DAM/DIF  (2008)
00005  * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
00006  *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
00007  *
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 3 of the License, or (at your option) any later version.
00013  * 
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  * 
00023  * ---------------------------------------
00024  */
00025 
00050 #ifdef HAVE_CONFIG_H
00051 #include "config.h"
00052 #endif
00053 
00054 #ifdef _SOLARIS
00055 #include "solaris_port.h"
00056 #endif
00057 
00058 #include "HashData.h"
00059 #include "HashTable.h"
00060 #include "log.h"
00061 #include "nfs_core.h"
00062 #include "nfs_exports.h"
00063 #include "config_parsing.h"
00064 #include "nfs_ip_stats.h"
00065 #include <stdlib.h>
00066 #include <string.h>
00067 
00083 uint32_t ip_stats_value_hash_func(hash_parameter_t * p_hparam,
00084                                            hash_buffer_t * buffclef)
00085 {
00086   return hash_sockaddr((sockaddr_t *)buffclef->pdata, IGNORE_PORT) % p_hparam->index_size;
00087 }
00088 
00104 uint64_t ip_stats_rbt_hash_func(hash_parameter_t * p_hparam,
00105                                          hash_buffer_t * buffclef)
00106 {
00107   return hash_sockaddr((sockaddr_t *)buffclef->pdata, IGNORE_PORT);
00108 }
00109 
00123 int compare_ip_stats(hash_buffer_t * buff1, hash_buffer_t * buff2)
00124 {
00125   return (cmp_sockaddr((sockaddr_t *)(buff1->pdata), (sockaddr_t *)(buff2->pdata), IGNORE_PORT) != 0) ? 0 : 1;
00126 }
00127 
00140 int display_ip_stats_key(hash_buffer_t * pbuff, char *str)
00141 {
00142   sockaddr_t *addr = (sockaddr_t *)(pbuff->pdata);
00143 
00144   sprint_sockaddr(addr, str, HASHTABLE_DISPLAY_STRLEN);
00145   return strlen(str);
00146 }
00147 
00160 int display_ip_stats_val(hash_buffer_t * pbuff, char *str)
00161 {
00162   nfs_ip_stats_t *ip_stats = (nfs_ip_stats_t *)(pbuff->pdata);
00163 
00164   return snprintf(str, HASHTABLE_DISPLAY_STRLEN,
00165                   "calls %u nfs2 %u nfs3 %u nfs4 %u mnt1 %u mnt3 %u",
00166                   ip_stats->nb_call,
00167                   ip_stats->nb_req_nfs2,
00168                   ip_stats->nb_req_nfs3,
00169                   ip_stats->nb_req_nfs4,
00170                   ip_stats->nb_req_mnt1,
00171                   ip_stats->nb_req_mnt3);
00172 }
00173 
00189 int nfs_ip_stats_add(hash_table_t * ht_ip_stats,
00190                      sockaddr_t * ipaddr, pool_t *ip_stats_pool)
00191 {
00192   hash_buffer_t buffkey;
00193   hash_buffer_t buffdata;
00194   nfs_ip_stats_t *g = NULL;
00195   sockaddr_t *pipaddr = NULL;
00196 
00197   /* Do nothing if configuration disables IP_Stats */
00198   if(nfs_param.core_param.dump_stats_per_client == 0)
00199     return IP_STATS_SUCCESS;
00200 
00201   /* Entry to be cached */
00202   g = pool_alloc(ip_stats_pool, NULL);
00203 
00204   if(g == NULL)
00205     return IP_STATS_INSERT_MALLOC_ERROR;
00206 
00207   if((pipaddr = gsh_malloc(sizeof(sockaddr_t))) == NULL)
00208     {
00209       pool_free(ip_stats_pool, g);
00210       return IP_STATS_INSERT_MALLOC_ERROR;
00211     }
00212 
00213   /* I have to keep an integer as key, I wil use the pointer
00214    * buffkey->pdata for this, this also means that buffkey->len will
00215    * be 0 */
00216   memcpy(pipaddr, ipaddr, sizeof(sockaddr_t));
00217 
00218   buffkey.pdata = pipaddr;
00219   buffkey.len = sizeof(sockaddr_t);
00220 
00221   /* I build the data with the request pointer that should be in state 'IN USE' */
00222   g->nb_call = 0;
00223   g->nb_req_nfs2 = 0;
00224   g->nb_req_nfs3 = 0;
00225   g->nb_req_nfs4 = 0;
00226   g->nb_req_mnt1 = 0;
00227   g->nb_req_mnt3 = 0;
00228 
00229   memset(g->req_mnt1, 0, MNT_V1_NB_COMMAND * sizeof(int));
00230   memset(g->req_mnt3, 0, MNT_V3_NB_COMMAND * sizeof(int));
00231   memset(g->req_nfs2, 0, NFS_V2_NB_COMMAND * sizeof(int));
00232   memset(g->req_nfs3, 0, NFS_V3_NB_COMMAND * sizeof(int));
00233 
00234   buffdata.pdata = (caddr_t) g;
00235   buffdata.len = sizeof(nfs_ip_stats_t);
00236 
00237   if(HashTable_Set(ht_ip_stats, &buffkey, &buffdata) != HASHTABLE_SUCCESS)
00238     return IP_STATS_INSERT_MALLOC_ERROR;
00239 
00240   return IP_STATS_SUCCESS;
00241 }                               /* nfs_ip_stats_add */
00242 
00254 int nfs_ip_stats_incr(hash_table_t * ht_ip_stats,
00255                       sockaddr_t * ipaddr,
00256                       unsigned int nfs_prog,
00257                       unsigned int mnt_prog, struct svc_req *ptr_req)
00258 {
00259   hash_buffer_t buffkey;
00260   hash_buffer_t buffval;
00261   int status;
00262   nfs_ip_stats_t *g;
00263 
00264   buffkey.pdata = (caddr_t) ipaddr;
00265   buffkey.len = sizeof(sockaddr_t);
00266 
00267   /* Do nothing if configuration disables IP_Stats */
00268   if(nfs_param.core_param.dump_stats_per_client == 0)
00269     return IP_STATS_SUCCESS;
00270 
00271   if(HashTable_Get(ht_ip_stats, &buffkey, &buffval) == HASHTABLE_SUCCESS)
00272     {
00273       g = (nfs_ip_stats_t *) buffval.pdata;
00274       g->nb_call += 1;
00275 
00276       status = IP_STATS_SUCCESS;
00277 
00278       if(ptr_req->rq_prog == nfs_prog)
00279         {
00280           switch (ptr_req->rq_vers)
00281             {
00282             case NFS_V2:
00283               g->nb_req_nfs2 += 1;
00284               g->req_nfs2[ptr_req->rq_proc] += 1;
00285               break;
00286 
00287             case NFS_V3:
00288               g->nb_req_nfs3 += 1;
00289               g->req_nfs3[ptr_req->rq_proc] += 1;
00290               break;
00291 
00292             case NFS_V4:
00293               g->nb_req_nfs4 += 1;
00294               break;
00295             }
00296         }
00297       else if(ptr_req->rq_prog == mnt_prog)
00298         {
00299           switch (ptr_req->rq_vers)
00300             {
00301             case MOUNT_V1:
00302               g->nb_req_mnt1 += 1;
00303               g->req_mnt1[ptr_req->rq_proc] += 1;
00304               break;
00305 
00306             case MOUNT_V3:
00307               g->nb_req_mnt3 += 1;
00308               g->req_mnt3[ptr_req->rq_proc] += 1;
00309               break;
00310             }
00311         }
00312     }
00313   else
00314     {
00315       status = IP_STATS_NOT_FOUND;
00316     }
00317   return status;
00318 }                               /* nfs_ip_stats_incr */
00319 
00320 
00332 int nfs_ip_stats_get(hash_table_t * ht_ip_stats,
00333                      sockaddr_t * ipaddr, nfs_ip_stats_t ** g)
00334 {
00335   hash_buffer_t buffkey;
00336   hash_buffer_t buffval;
00337   int status;
00338 
00339   buffkey.pdata = (caddr_t) ipaddr;
00340   buffkey.len = sizeof(sockaddr_t);
00341 
00342   /* Do nothing if configuration disables IP_Stats */
00343   if(nfs_param.core_param.dump_stats_per_client == 0)
00344     return IP_STATS_SUCCESS;
00345 
00346   if(HashTable_Get(ht_ip_stats, &buffkey, &buffval) == HASHTABLE_SUCCESS)
00347     {
00348       *g = (nfs_ip_stats_t *) buffval.pdata;
00349 
00350       status = IP_STATS_SUCCESS;
00351     }
00352   else
00353     {
00354       status = IP_STATS_NOT_FOUND;
00355     }
00356   return status;
00357 }                               /* nfs_ip_stats_get */
00358 
00371 int nfs_ip_stats_remove(hash_table_t * ht_ip_stats,
00372                         sockaddr_t * ipaddr, pool_t *ip_stats_pool)
00373 {
00374   hash_buffer_t buffkey, old_key, old_value;
00375   int status = IP_STATS_SUCCESS;
00376   nfs_ip_stats_t *g = NULL;
00377 
00378   buffkey.pdata = (caddr_t) ipaddr;
00379   buffkey.len = sizeof(sockaddr_t);
00380 
00381   /* Do nothing if configuration disables IP_Stats */
00382   if(nfs_param.core_param.dump_stats_per_client == 0)
00383     return IP_STATS_SUCCESS;
00384 
00385   if(HashTable_Del(ht_ip_stats, &buffkey, &old_key, &old_value) == HASHTABLE_SUCCESS)
00386     {
00387       gsh_free(old_key.pdata);
00388       g = old_value.pdata;
00389       pool_free(ip_stats_pool, g);
00390     }
00391   else
00392     {
00393       status = IP_STATS_NOT_FOUND;
00394     }
00395 
00396   return status;
00397 }                               /* nfs_ip_stats_remove */
00398 
00410 hash_table_t *nfs_Init_ip_stats(nfs_ip_stats_parameter_t param)
00411 {
00412   hash_table_t *ht_ip_stats;
00413 
00414   if((ht_ip_stats = HashTable_Init(&param.hash_param)) == NULL)
00415     {
00416       LogCrit(COMPONENT_INIT, "NFS IP_STATS: Cannot init IP stats cache");
00417       return NULL;
00418     }
00419 
00420   return ht_ip_stats;
00421 }                               /* nfs_Init_ip_stats */
00422 
00433 void nfs_ip_stats_dump(hash_table_t ** ht_ip_stats,
00434                        unsigned int nb_worker, char *path_stat)
00435 {
00436   struct rbt_node *it;
00437   struct rbt_head *tete_rbt;
00438   hash_data_t *pdata = NULL;
00439   unsigned int i = 0;
00440   unsigned int j = 0;
00441   unsigned int k = 0;
00442   nfs_ip_stats_t *g[NB_MAX_WORKER_THREAD];
00443   nfs_ip_stats_t ip_stats_aggreg;
00444   // enough to hold an IPv4 or IPv6 address as a string
00445   char ipaddrbuf[40];
00446   char ifpathdump[MAXPATHLEN];
00447   sockaddr_t * ipaddr;
00448   time_t current_time;
00449   struct tm current_time_struct;
00450   char strdate[1024];
00451   FILE *flushipstat = NULL;
00452 
00453   /* Do nothing if configuration disables IP_Stats */
00454   if(nfs_param.core_param.dump_stats_per_client == 0)
00455     return;
00456 
00457   /* Compute the current time */
00458   current_time = time(NULL);
00459   memcpy(&current_time_struct, localtime(&current_time), sizeof(current_time_struct));
00460   snprintf(strdate, 1024, "%u, %.2d/%.2d/%.4d %.2d:%.2d:%.2d ",
00461            (unsigned int)current_time,
00462            current_time_struct.tm_mday,
00463            current_time_struct.tm_mon + 1,
00464            1900 + current_time_struct.tm_year,
00465            current_time_struct.tm_hour,
00466            current_time_struct.tm_min, current_time_struct.tm_sec);
00467 
00468   /* All clients are supposed to have call at least one time worker #0
00469    * we loop on every client in the HashTable */
00470   for(i = 0; i < ht_ip_stats[0]->parameter.index_size; i++)
00471     {
00472       tete_rbt = &ht_ip_stats[0]->partitions[i].rbt;
00473       RBT_LOOP(tete_rbt, it)
00474       {
00475         pdata = (hash_data_t *) it->rbt_opaq;
00476 
00477         ipaddr = (sockaddr_t *) pdata->buffkey.pdata;
00478 
00479         sprint_sockaddr(ipaddr, ipaddrbuf, sizeof(ipaddrbuf));
00480 
00481         snprintf(ifpathdump, MAXPATHLEN, "%s/stats_nfs-%s", path_stat, ipaddrbuf);
00482 
00483         if((flushipstat = fopen(ifpathdump, "a")) == NULL)
00484           return;
00485 
00486         /* Collect stats for each worker and aggregate them */
00487         memset(&ip_stats_aggreg, 0, sizeof(ip_stats_aggreg));
00488         for(j = 0; j < nb_worker; j++)
00489           {
00490             if(nfs_ip_stats_get(ht_ip_stats[j],
00491                                 ipaddr, &g[j]) != IP_STATS_SUCCESS)
00492               {
00493                 fclose(flushipstat);
00494                 return;
00495               }
00496             ip_stats_aggreg.nb_call += (g[j])->nb_call;
00497 
00498             ip_stats_aggreg.nb_req_nfs2 += (g[j])->nb_req_nfs2;
00499             ip_stats_aggreg.nb_req_nfs3 += (g[j])->nb_req_nfs3;
00500             ip_stats_aggreg.nb_req_nfs4 += (g[j])->nb_req_nfs4;
00501             ip_stats_aggreg.nb_req_mnt1 += (g[j])->nb_req_mnt1;
00502             ip_stats_aggreg.nb_req_mnt3 += (g[j])->nb_req_mnt3;
00503 
00504             for(k = 0; k < MNT_V1_NB_COMMAND; k++)
00505               ip_stats_aggreg.req_mnt1[k] += (g[j])->req_mnt1[k];
00506 
00507             for(k = 0; k < MNT_V3_NB_COMMAND; k++)
00508               ip_stats_aggreg.req_mnt3[k] += (g[j])->req_mnt3[k];
00509 
00510             for(k = 0; k < NFS_V2_NB_COMMAND; k++)
00511               ip_stats_aggreg.req_nfs2[k] += (g[j])->req_nfs2[k];
00512 
00513             for(k = 0; k < NFS_V3_NB_COMMAND; k++)
00514               ip_stats_aggreg.req_nfs3[k] += (g[j])->req_nfs3[k];
00515           }
00516 
00517         /* Write stats to file */
00518         fprintf(flushipstat, "NFS/MOUNT STATISTICS,%s;%u|%u,%u,%u,%u,%u\n",
00519                 strdate,
00520                 ip_stats_aggreg.nb_call,
00521                 ip_stats_aggreg.nb_req_mnt1,
00522                 ip_stats_aggreg.nb_req_mnt3,
00523                 ip_stats_aggreg.nb_req_nfs2,
00524                 ip_stats_aggreg.nb_req_nfs3, ip_stats_aggreg.nb_req_nfs4);
00525 
00526         fprintf(flushipstat, "MNT V1 REQUEST,%s;%u|", strdate,
00527                 ip_stats_aggreg.nb_req_mnt1);
00528         for(k = 0; k < MNT_V1_NB_COMMAND - 1; k++)
00529           fprintf(flushipstat, "%u,", ip_stats_aggreg.req_mnt1[k]);
00530         fprintf(flushipstat, "%u\n", ip_stats_aggreg.req_mnt1[MNT_V1_NB_COMMAND - 1]);
00531 
00532         fprintf(flushipstat, "MNT V3 REQUEST,%s;%u|", strdate,
00533                 ip_stats_aggreg.nb_req_mnt3);
00534         for(k = 0; k < MNT_V3_NB_COMMAND - 1; k++)
00535           fprintf(flushipstat, "%u,", ip_stats_aggreg.req_mnt3[k]);
00536         fprintf(flushipstat, "%u\n", ip_stats_aggreg.req_mnt3[MNT_V3_NB_COMMAND - 1]);
00537 
00538         fprintf(flushipstat, "NFS V2 REQUEST,%s;%u|", strdate,
00539                 ip_stats_aggreg.nb_req_nfs2);
00540         for(k = 0; k < NFS_V2_NB_COMMAND - 1; k++)
00541           fprintf(flushipstat, "%u,", ip_stats_aggreg.req_nfs2[k]);
00542         fprintf(flushipstat, "%u\n", ip_stats_aggreg.req_nfs2[NFS_V2_NB_COMMAND - 1]);
00543 
00544         fprintf(flushipstat, "NFS V3 REQUEST,%s;%u|", strdate,
00545                 ip_stats_aggreg.nb_req_nfs3);
00546         for(k = 0; k < NFS_V3_NB_COMMAND - 1; k++)
00547           fprintf(flushipstat, "%u,", ip_stats_aggreg.req_nfs3[k]);
00548         fprintf(flushipstat, "%u\n", ip_stats_aggreg.req_nfs3[NFS_V3_NB_COMMAND - 1]);
00549 
00550         fprintf(flushipstat, "END, ----- NO MORE STATS FOR THIS PASS ----\n");
00551 
00552         fflush(flushipstat);
00553 
00554         /* Check next client */
00555         RBT_INCREMENT(it);
00556 
00557         fclose(flushipstat);
00558       }
00559 
00560     }
00561 }                               /* nfs_ip_stats_dump */