nfs-ganesha 1.4

nfs_ip_name.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 
00036 #ifdef HAVE_CONFIG_H
00037 #include "config.h"
00038 #endif
00039 
00040 #ifdef _SOLARIS
00041 #include "solaris_port.h"
00042 #endif
00043 
00044 #include "HashData.h"
00045 #include "HashTable.h"
00046 #include "log.h"
00047 #include "nfs_core.h"
00048 #include "nfs_exports.h"
00049 #include "config_parsing.h"
00050 #include <stdlib.h>
00051 #include <string.h>
00052 #include <sys/socket.h>
00053 #include <netinet/in.h>
00054 #include <arpa/inet.h>
00055 
00056 /* Hashtable used to cache the hostname, accessed by their IP addess */
00057 hash_table_t *ht_ip_name;
00058 unsigned int expiration_time;
00059 
00075 uint32_t ip_name_value_hash_func(hash_parameter_t * p_hparam,
00076                                           hash_buffer_t * buffclef)
00077 {
00078   return hash_sockaddr((sockaddr_t *)buffclef->pdata, IGNORE_PORT) % p_hparam->index_size;
00079 }
00080 
00096 uint64_t ip_name_rbt_hash_func(hash_parameter_t * p_hparam,
00097                                         hash_buffer_t * buffclef)
00098 {
00099   return hash_sockaddr((sockaddr_t *)buffclef->pdata, IGNORE_PORT);
00100 }
00101 
00115 int compare_ip_name(hash_buffer_t * buff1, hash_buffer_t * buff2)
00116 {
00117   return (cmp_sockaddr((sockaddr_t *)(buff1->pdata), (sockaddr_t *)(buff2->pdata), IGNORE_PORT) != 0) ? 0 : 1;
00118 }
00119 
00132 int display_ip_name_key(hash_buffer_t * pbuff, char *str)
00133 {
00134   sockaddr_t *addr = (sockaddr_t *)(pbuff->pdata);
00135 
00136   sprint_sockaddr(addr, str, HASHTABLE_DISPLAY_STRLEN);
00137   return strlen(str);
00138 }
00139 
00152 int display_ip_name_val(hash_buffer_t * pbuff, char *str)
00153 {
00154   nfs_ip_name_t *nfs_ip_name = (pbuff->pdata);
00155 
00156   return snprintf(str, HASHTABLE_DISPLAY_STRLEN, "%s", nfs_ip_name->hostname);
00157 }
00158 
00174 int nfs_ip_name_add(sockaddr_t *ipaddr, char *hostname)
00175 {
00176   hash_buffer_t buffkey;
00177   hash_buffer_t buffdata;
00178   nfs_ip_name_t *nfs_ip_name = NULL;
00179   sockaddr_t *pipaddr = NULL;
00180   struct timeval tv0, tv1, dur;
00181   int rc;
00182   char ipstring[SOCK_NAME_MAX];
00183 
00184   nfs_ip_name = gsh_malloc(sizeof(nfs_ip_name_t));
00185 
00186   if(nfs_ip_name == NULL)
00187     return IP_NAME_INSERT_MALLOC_ERROR;
00188 
00189   pipaddr = gsh_malloc(sizeof(sockaddr_t));
00190   if(pipaddr == NULL)
00191     {
00192       gsh_free(nfs_ip_name);
00193       return IP_NAME_INSERT_MALLOC_ERROR;
00194     }
00195 
00196   /* I have to keep an integer as key, I wil use the pointer buffkey->pdata for this, 
00197    * this also means that buffkey->len will be 0 */
00198   memcpy(pipaddr, ipaddr, sizeof(sockaddr_t));
00199 
00200   buffkey.pdata = (caddr_t) pipaddr;
00201   buffkey.len = sizeof(sockaddr_t);
00202 
00203   gettimeofday(&tv0, NULL) ;
00204   rc = getnameinfo((struct sockaddr *)pipaddr, sizeof(sockaddr_t),
00205                    nfs_ip_name->hostname, sizeof(nfs_ip_name->hostname),
00206                    NULL, 0, 0);
00207   gettimeofday(&tv1, NULL) ;
00208   timersub(&tv1, &tv0, &dur) ;
00209 
00210 
00211   sprint_sockaddr(pipaddr, ipstring, sizeof(ipstring));
00212 
00213   /* display warning if DNS resolution took more that 1.0s */
00214   if (dur.tv_sec >= 1)
00215   {
00216        LogEvent(COMPONENT_DISPATCH,
00217                 "Warning: long DNS query for %s: %u.%06u sec", ipstring,
00218                 (unsigned int)dur.tv_sec, (unsigned int)dur.tv_usec );
00219   }
00220 
00221 
00222   /* Ask for the name to be cached */
00223   if(rc != 0)
00224     {
00225        LogEvent(COMPONENT_DISPATCH,
00226                 "Cannot resolve address %s, error %s",
00227                 ipstring, gai_strerror(rc));
00228 
00229        gsh_free(nfs_ip_name);
00230        gsh_free(pipaddr);
00231        return IP_NAME_NETDB_ERROR;
00232     }
00233 
00234   LogDebug(COMPONENT_DISPATCH,
00235            "Inserting %s->%s to addr cache",
00236            ipstring, nfs_ip_name->hostname);
00237 
00238   /* I build the data with the request pointer that should be in state 'IN USE' */
00239   nfs_ip_name->timestamp = time(NULL);
00240 
00241   buffdata.pdata = (caddr_t) nfs_ip_name;
00242   buffdata.len = sizeof(nfs_ip_name_t);
00243 
00244   if(HashTable_Set(ht_ip_name, &buffkey, &buffdata) != HASHTABLE_SUCCESS)
00245     return IP_NAME_INSERT_MALLOC_ERROR;
00246 
00247   /* Copy the value for the caller */
00248   strncpy(hostname, nfs_ip_name->hostname, MAXHOSTNAMELEN);
00249 
00250   return IP_NAME_SUCCESS;
00251 }                               /* nfs_ip_name_add */
00252 
00265 int nfs_ip_name_get(sockaddr_t *ipaddr, char *hostname)
00266 {
00267   hash_buffer_t buffkey;
00268   hash_buffer_t buffval;
00269   nfs_ip_name_t *nfs_ip_name;
00270   char ipstring[SOCK_NAME_MAX];
00271 
00272   sprint_sockaddr(ipaddr, ipstring, sizeof(ipstring));
00273 
00274   buffkey.pdata = (caddr_t) ipaddr;
00275   buffkey.len = sizeof(sockaddr_t);
00276 
00277   if(HashTable_Get(ht_ip_name, &buffkey, &buffval) == HASHTABLE_SUCCESS)
00278     {
00279       nfs_ip_name = (nfs_ip_name_t *) buffval.pdata;
00280       strncpy(hostname, nfs_ip_name->hostname, MAXHOSTNAMELEN);
00281 
00282       LogFullDebug(COMPONENT_DISPATCH,
00283                    "Cache get hit for %s->%s",
00284                    ipstring, nfs_ip_name->hostname);
00285 
00286       return IP_NAME_SUCCESS;
00287     }
00288 
00289   LogFullDebug(COMPONENT_DISPATCH,
00290                "Cache get miss for %s",
00291                ipstring);
00292 
00293   return IP_NAME_NOT_FOUND;
00294 }                               /* nfs_ip_name_get */
00295 
00307 int nfs_ip_name_remove(sockaddr_t *ipaddr)
00308 {
00309   hash_buffer_t buffkey, old_value;
00310   nfs_ip_name_t *nfs_ip_name = NULL;
00311   char ipstring[SOCK_NAME_MAX];
00312 
00313   sprint_sockaddr(ipaddr, ipstring, sizeof(ipstring));
00314 
00315   buffkey.pdata = (caddr_t) ipaddr;
00316   buffkey.len = sizeof(sockaddr_t);
00317 
00318   if(HashTable_Del(ht_ip_name, &buffkey, NULL, &old_value) == HASHTABLE_SUCCESS)
00319     {
00320       nfs_ip_name = (nfs_ip_name_t *) old_value.pdata;
00321 
00322       LogFullDebug(COMPONENT_DISPATCH,
00323                    "Cache remove hit for %s->%s",
00324                    ipstring, nfs_ip_name->hostname);
00325 
00326       gsh_free(nfs_ip_name);
00327       return IP_NAME_SUCCESS;
00328     }
00329 
00330   LogFullDebug(COMPONENT_DISPATCH,
00331                "Cache remove miss for %s",
00332                ipstring);
00333 
00334   return IP_NAME_NOT_FOUND;
00335 }                               /* nfs_ip_name_remove */
00336 
00348 int nfs_Init_ip_name(nfs_ip_name_parameter_t param)
00349 {
00350   if((ht_ip_name = HashTable_Init(&param.hash_param)) == NULL)
00351     {
00352       LogCrit(COMPONENT_INIT, "NFS IP_NAME: Cannot init IP/name cache");
00353       return -1;
00354     }
00355 
00356   /* Set the expiration time */
00357   expiration_time = param.expiration_time;
00358 
00359   return IP_NAME_SUCCESS;
00360 }                               /* nfs_Init_ip_name */
00361 
00362 int nfs_ip_name_populate(char *path)
00363 {
00364   config_file_t config_file;
00365   config_item_t block;
00366   int var_max;
00367   int var_index;
00368   int err;
00369   char *key_name;
00370   char *key_value;
00371   char label[MAXNAMLEN];
00372   sockaddr_t ipaddr;
00373   nfs_ip_name_t *nfs_ip_name;
00374   sockaddr_t *pipaddr;
00375   hash_buffer_t buffkey;
00376   hash_buffer_t buffdata;
00377 
00378   config_file = config_ParseFile(path);
00379 
00380   if(!config_file)
00381     {
00382       LogCrit(COMPONENT_CONFIG, "Can't open file %s", path);
00383 
00384       return IP_NAME_NOT_FOUND;
00385     }
00386 
00387   /* Get the config BLOCK */
00388   if((block = config_FindItemByName(config_file, CONF_LABEL_IP_NAME_HOSTS)) == NULL)
00389     {
00390       LogCrit(COMPONENT_CONFIG,
00391               "Can't get label %s in file %s",
00392               CONF_LABEL_IP_NAME_HOSTS, path);
00393       return IP_NAME_NOT_FOUND;
00394     }
00395   else if(config_ItemType(block) != CONFIG_ITEM_BLOCK)
00396     {
00397       /* Expected to be a block */
00398       return IP_NAME_NOT_FOUND;
00399     }
00400 
00401   var_max = config_GetNbItems(block);
00402 
00403   for(var_index = 0; var_index < var_max; var_index++)
00404     {
00405       config_item_t item;
00406 
00407       item = config_GetItemByIndex(block, var_index);
00408 
00409       /* Get key's name */
00410       if((err = config_GetKeyValue(item, &key_name, &key_value)) != 0)
00411         {
00412           LogCrit(COMPONENT_CONFIG,
00413                   "Error reading key[%d] from section \"%s\" of configuration file.",
00414                   var_index, label);
00415           return IP_NAME_NOT_FOUND;
00416         }
00417 
00418       err = ipstring_to_sockaddr(key_value, &ipaddr);
00419       if(err != 0)
00420         {
00421           LogCrit(COMPONENT_CONFIG,
00422                   "Error converting %s to an ipaddress %s",
00423                   key_value, gai_strerror(err));
00424           return IP_NAME_NOT_FOUND;
00425         }
00426 
00427       /* Entry to be cached */
00428       nfs_ip_name = gsh_malloc(sizeof(nfs_ip_name_t));
00429       if(nfs_ip_name == NULL)
00430         return IP_NAME_INSERT_MALLOC_ERROR;
00431 
00432       pipaddr = gsh_malloc(sizeof(sockaddr_t));
00433       if(pipaddr == NULL)
00434         {
00435           gsh_free(nfs_ip_name);
00436           return IP_NAME_INSERT_MALLOC_ERROR;
00437         }
00438 
00439       strncpy(nfs_ip_name->hostname, key_name, MAXHOSTNAMELEN);
00440       nfs_ip_name->timestamp = time(NULL);
00441       memcpy(pipaddr, &ipaddr, sizeof(sockaddr_t));
00442 
00443       buffdata.pdata = (caddr_t) nfs_ip_name;
00444       buffdata.len = sizeof(nfs_ip_name_t);
00445 
00446       buffkey.pdata = (caddr_t) pipaddr;
00447       buffkey.len = sizeof(sockaddr_t);
00448 
00449       if(HashTable_Set(ht_ip_name, &buffkey, &buffdata) != HASHTABLE_SUCCESS)
00450         {
00451           gsh_free(nfs_ip_name);
00452           gsh_free(pipaddr);
00453           return IP_NAME_INSERT_MALLOC_ERROR;
00454         }
00455     }
00456 
00457   if(isFullDebug(COMPONENT_CONFIG))
00458     HashTable_Log(COMPONENT_CONFIG, ht_ip_name);
00459 
00460   return IP_NAME_SUCCESS;
00461 }                               /* nfs_ip_name_populate */
00462 
00476 void nfs_ip_name_get_stats(hash_stat_t * phstat)
00477 {
00478   HashTable_GetStats(ht_ip_name, phstat);
00479 }                               /* nfs_ip_name_get_stats */