nfs-ganesha 1.4
|
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(¶m.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 */