4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
29 #include <sys/types.h>
37 #include <net/route.h>
38 #include <sys/sockio.h>
39 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
45 #include <smbsrv/libsmb.h>
49 #define SMBD_NICMON_ENABLE "nicmon_enable"
50 #define SMBD_NICMON_THROTTLE 100
51 #define SMBD_NICMON_DEBOUNCE 2
55 static boolean_t smbd_nicmon_enabled
= B_TRUE
;
57 /* Use this to stop monitoring */
58 static int eventpipe_write
= -1;
60 /* Use this to refresh service instance */
61 static char *smbd_nicmon_caller_fmri
= NULL
;
63 static void smbd_nicmon_run_check(void);
64 static int smbd_nicmon_setup_rtsock(int);
65 static int smbd_nicmon_needscan(int);
66 static int smbd_nicmon_setup_eventpipe(int *, int *);
67 static void *smbd_nicmon_daemon(void *);
70 * Start the nic monitor thread.
73 smbd_nicmon_start(const char *svc_fmri
)
75 pthread_t smbd_nicmon_tid
;
78 if (smb_nic_init() != SMB_NIC_SUCCESS
)
81 rc
= pthread_create(&smbd_nicmon_tid
, NULL
, smbd_nicmon_daemon
, NULL
);
86 smbd_nicmon_caller_fmri
= (char *)svc_fmri
;
88 smbd_nicmon_run_check();
93 smbd_nicmon_stop(void)
97 if (eventpipe_write
< 0)
100 (void) write(eventpipe_write
, &buf
, sizeof (buf
));
101 smbd_nicmon_caller_fmri
= NULL
;
106 smbd_nicmon_refresh(void)
108 if (smb_nic_init() != SMB_NIC_SUCCESS
)
111 smbd_nicmon_run_check();
116 * The monitor is enabled unless it is explicitly
117 * disabled by setting smbd/nicmon_enable to false.
118 * smbd/nicmon_enable is not defined by default.
121 smbd_nicmon_run_check(void)
127 smbd_nicmon_enabled
= B_TRUE
;
129 if ((hd
= smb_smf_scf_init(SMBD_FMRI_PREFIX
)) == NULL
) {
131 "smbd_nicmon: smb_smf_scf_init failed");
135 rc
= smb_smf_create_service_pgroup(hd
, SMBD_PG_NAME
);
136 if (rc
!= SMBD_SMF_OK
) {
137 smb_smf_scf_fini(hd
);
139 "smbd_nicmon: smb_smf_create_service_pgroup failed");
143 rc
= smb_smf_get_boolean_property(hd
, SMBD_NICMON_ENABLE
, &status
);
144 if (rc
== SMBD_SMF_OK
&& status
== 0)
145 smbd_nicmon_enabled
= B_FALSE
;
147 smb_smf_scf_fini(hd
);
151 * Setup routing socket for getting RTM messages.
154 smbd_nicmon_setup_rtsock(int af
)
159 if ((sd
= socket(PF_ROUTE
, SOCK_RAW
, af
)) == -1) {
161 "smbd_nicmon: routing socket failed: %d", errno
);
165 if ((flags
= fcntl(sd
, F_GETFL
, 0)) < 0) {
167 "smbd_nicmon: fcntl F_GETFL failed: %d", errno
);
172 if ((fcntl(sd
, F_SETFL
, flags
| O_NONBLOCK
)) < 0) {
174 "smbd_nicmon: fcntl F_SETFL failed: %d", errno
);
183 smbd_nicmon_needscan(int sock
)
185 static uint32_t throttle
;
186 struct rt_msghdr
*rtm
;
187 int64_t msg
[2048 / 8];
188 int need_if_scan
= 0;
191 /* Read as many messages as possible and try to empty the sockets */
193 nbytes
= read(sock
, msg
, sizeof (msg
));
197 rtm
= (struct rt_msghdr
*)msg
;
198 if (rtm
->rtm_version
!= RTM_VERSION
)
201 if (nbytes
< rtm
->rtm_msglen
) {
202 if ((throttle
% SMBD_NICMON_THROTTLE
) == 0) {
204 "smbd_nicmon: short read: %d of %d",
205 nbytes
, rtm
->rtm_msglen
);
211 switch (rtm
->rtm_type
) {
222 return (need_if_scan
);
226 * Create pipe for signal delivery and set up signal handlers.
229 smbd_nicmon_setup_eventpipe(int *read_pipe
, int *write_pipe
)
233 if ((pipe(fds
)) < 0) {
235 "smbd_nicmon: event pipe failed: %d", errno
);
240 *write_pipe
= fds
[1];
245 * Create the global routing socket to monitor changes in NIC interfaces.
246 * We are only interested in new inerface addition/deletion and changes
249 * Note: only supports AF_INET routing socket. Need to add AF_INET6 to
254 smbd_nicmon_daemon(void *arg
)
256 static uint32_t throttle
;
257 static int rtsock_v4
;
258 static int eventpipe_read
= -1;
259 struct pollfd pollfds
[2];
264 if ((rtsock_v4
= smbd_nicmon_setup_rtsock(AF_INET
)) == -1)
267 rc
= smbd_nicmon_setup_eventpipe(&eventpipe_read
, &eventpipe_write
);
272 * Listen for activity on any of the sockets.
273 * The delay before checking the rtsock will hopefully
274 * smooth things out when there is a lot of activity.
279 pollfds
[0].fd
= rtsock_v4
;
280 pollfds
[0].events
= POLLIN
;
281 pollfds
[1].fd
= eventpipe_read
;
282 pollfds
[1].events
= POLLIN
;
284 if (poll(pollfds
, pollfd_num
, -1) < 0) {
287 if ((throttle
% SMBD_NICMON_THROTTLE
) == 0)
289 "smbd_nicmon: poll failed: %d", errno
);
294 for (i
= 0; i
< pollfd_num
; i
++) {
295 if ((pollfds
[i
].fd
< 0) ||
296 !(pollfds
[i
].revents
& POLLIN
))
298 if (pollfds
[i
].fd
== rtsock_v4
) {
299 (void) sleep(SMBD_NICMON_DEBOUNCE
);
300 nic_changed
= smbd_nicmon_needscan(rtsock_v4
);
302 if (pollfds
[i
].fd
== eventpipe_read
)
307 * If the monitor is enabled and something has changed,
308 * refresh the registered SMF service.
310 if (smbd_nicmon_enabled
&& nic_changed
&&
311 smbd_nicmon_caller_fmri
) {
312 if (smf_refresh_instance(smbd_nicmon_caller_fmri
) != 0)
314 "smbd_nicmon: %s refresh failed",
315 smbd_nicmon_caller_fmri
);
319 (void) close(rtsock_v4
);
320 (void) close(eventpipe_read
);
321 (void) close(eventpipe_write
);
322 eventpipe_write
= -1;