2 * Copyright (c) 2014 Intel Corporation. All Rights Reserved
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36 #endif /* HAVE_CONFIG_H */
39 #include <sys/types.h>
56 struct udev_monitor *mon;
58 #include "ibdiag_common.h"
60 #define SYS_HOSTNAME "/proc/sys/kernel/hostname"
61 #define DEF_SYS_DIR "/sys"
62 char *sys_dir = DEF_SYS_DIR;
63 #define SYS_INFINIBAND "class/infiniband"
64 #define DEFAULT_RETRY_RATE 60
65 #define DEFAULT_RETRY_COUNT 0
66 #define DEFAULT_ND_FORMAT "%h %d"
68 int failure_retry_rate = DEFAULT_RETRY_RATE;
69 int set_retry_cnt = DEFAULT_RETRY_COUNT;
73 static void newline_to_null(char *str)
75 char *term = index(str, '\n');
80 static void strip_domain(char *str)
82 char *term = index(str, '.');
87 static void build_node_desc(char *dest, size_t len,
88 const char *device, const char *hostname)
90 char *end = dest + len-1;
92 char *src = ibd_nd_format;
94 while (*src && (dest < end)) {
102 while (*field && (*field != '.') && (dest < end))
107 while (*field && (dest < end))
117 static int update_node_desc(const char *device, const char *hostname, int force)
122 char nd_file[PATH_MAX];
125 snprintf(nd_file, sizeof(nd_file), "%s/%s/%s/node_desc",
126 sys_dir, SYS_INFINIBAND, device);
127 nd_file[sizeof(nd_file)-1] = '\0';
129 f = fopen(nd_file, "r+");
131 syslog(LOG_ERR, "Failed to open %s\n", nd_file);
135 if (!fgets(nd, sizeof(nd), f)) {
136 syslog(LOG_ERR, "Failed to read %s\n", nd_file);
142 build_node_desc(new_nd, sizeof(new_nd), device, hostname);
144 if (!force && strncmp(new_nd, nd, sizeof(new_nd)) == 0) {
145 syslog(LOG_INFO, "%s: no change (%s)\n", device, new_nd);
147 syslog(LOG_INFO, "%s: change (%s) -> (%s)\n",
159 static int set_rdma_node_desc(const char *hostname, int force)
163 char dev_dir[PATH_MAX];
165 snprintf(dev_dir, sizeof(dev_dir), "%s/%s", sys_dir, SYS_INFINIBAND);
166 dev_dir[sizeof(dev_dir)-1] = '\0';
168 class_dir = opendir(dev_dir);
170 syslog(LOG_INFO, "Failed to open %s", dev_dir);
174 while ((dent = readdir(class_dir))) {
175 int retry = set_retry_cnt;
176 if (dent->d_name[0] == '.')
179 while (update_node_desc(dent->d_name, hostname, force) && retry > 0) {
180 syslog(LOG_ERR, "retrying set Node Description on %s\n",
190 static int read_hostname(int fd, char *name, size_t len)
193 memset(name, 0, len);
194 if (read(fd, name, len-1) >= 0) {
195 newline_to_null(name);
199 syslog(LOG_ERR, "Read %s Failed\n", SYS_HOSTNAME);
205 static int process_opts(void *context, int ch, char *optarg)
216 tmp = strtoul(optarg, NULL, 0);
217 if (tmp >= INT_MAX) {
219 "Invalid retry rate specified: %lu s\n",
222 failure_retry_rate = (int)tmp;
226 tmp = strtoul(optarg, NULL, 0);
227 if (tmp >= INT_MAX) {
229 "Invalid retry count specified: %lu\n",
232 set_retry_cnt = (int)tmp;
242 static void udev_log_fn(struct udev *ud, int priority, const char *file, int line,
243 const char *fn, const char *format, va_list args)
247 off = snprintf(msg, MSG_MAX, "libudev: %s:%d %s",
250 vsnprintf(msg+off, MSG_MAX-off, format, args);
251 syslog(LOG_ERR, msg);
254 static void setup_udev(void)
258 syslog(LOG_ERR, "udev_new failed\n");
262 udev_set_log_fn(udev, udev_log_fn);
263 udev_set_log_priority(udev, LOG_INFO);
264 #if HAVE_UDEV_GET_SYS_PATH
265 sys_dir = (char *)udev_get_sys_path(udev);
269 static int get_udev_fd(void)
271 mon = udev_monitor_new_from_netlink(udev, "udev");
273 syslog(LOG_ERR, "udev monitoring failed\n");
277 udev_monitor_filter_add_match_subsystem_devtype(mon, "infiniband", NULL);
278 udev_monitor_enable_receiving(mon);
279 return udev_monitor_get_fd(mon);
282 static void process_udev_event(int ud_fd, const char *hostname)
284 struct udev_device *dev;
286 dev = udev_monitor_receive_device(mon);
288 const char *device = udev_device_get_sysname(dev);
289 const char *action = udev_device_get_action(dev);
291 syslog(LOG_INFO, "Device event: %s, %s, %s\n",
292 udev_device_get_subsystem(dev),
296 && strncmp(action, "add", sizeof("add")) == 0)
297 update_node_desc(device, hostname, 1);
299 udev_device_unref(dev);
303 static void monitor(void)
308 struct pollfd fds[2];
312 ud_fd = get_udev_fd();
317 hn_fd = open(SYS_HOSTNAME, O_RDONLY);
320 "Open %s Failed: retry in %d seconds\n",
321 SYS_HOSTNAME, failure_retry_rate);
322 sleep(failure_retry_rate);
331 fds[1].events = POLLIN;
334 rc = poll(fds, numfds, -1);
337 if (read_hostname(hn_fd, hostname, sizeof(hostname)) != 0)
340 if (fds[0].revents != 0)
341 syslog(LOG_ERR, "Hostname change: %s\n", hostname);
343 if (fds[1].revents != 0)
344 process_udev_event(ud_fd, hostname);
346 rc = set_rdma_node_desc((const char *)hostname, 0);
348 syslog(LOG_ERR, "Poll %s Failed\n", SYS_HOSTNAME);
355 sleep(failure_retry_rate);
359 static void remove_pidfile(void)
365 static void write_pidfile(void)
370 f = fopen(pidfile, "w");
372 fprintf(f, "%d\n", getpid());
375 syslog(LOG_ERR, "Failed to write pidfile : %s\n",
382 int main(int argc, char *argv[])
387 openlog("rdma-ndd", LOG_PID | LOG_PERROR, LOG_DAEMON);
389 const struct ibdiag_opt opts[] = {
390 {"retry_timer", 't', 1, "<retry_timer>",
391 "Length of time to sleep when system errors occur "
392 "when attempting to poll and or read the hostname "
393 "from the system.\n"},
394 {"retry_count", 'r', 1, "<retry_count>",
395 "Number of times to attempt to retry setting "
396 "of the node description on failure\n"},
397 {"foreground", 'f', 0, NULL, "run in the foreground instead of as a daemon\n"},
398 {"pidfile", 0, 1, "<pidfile>", "specify a pid file (daemon mode only)\n"},
402 ibdiag_process_opts(argc, argv, NULL, "CPDLGtsKyevd", opts,
403 process_opts, "", NULL);
406 ibd_nd_format = DEFAULT_ND_FORMAT;
410 openlog("rdma-ndd", LOG_PID, LOG_DAEMON);
411 if (daemon(0, 0) != 0) {
412 syslog(LOG_ERR, "Failed to daemonize\n");
420 syslog(LOG_INFO, "Node Descriptor format (%s)\n", ibd_nd_format);
422 fd = open(SYS_HOSTNAME, O_RDONLY);
423 if (read_hostname(fd, hostname, sizeof(hostname)) != 0)
425 set_rdma_node_desc((const char *)hostname, 1);