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>
48 #define SMBD_NICMON_ENABLE "nicmon_enable"
49 #define SMBD_NICMON_THROTTLE 100
50 #define SMBD_NICMON_DEBOUNCE 2
54 static boolean_t smbd_nicmon_enabled
= B_TRUE
;
56 /* Use this to stop monitoring */
57 static int eventpipe_write
= -1;
59 /* Use this to refresh service instance */
60 static char *smbd_nicmon_caller_fmri
= NULL
;
62 static void smbd_nicmon_run_check(void);
63 static int smbd_nicmon_setup_rtsock(int);
64 static int smbd_nicmon_needscan(int);
65 static int smbd_nicmon_setup_eventpipe(int *, int *);
66 static void *smbd_nicmon_daemon(void *);
69 * Start the nic monitor thread.
72 smbd_nicmon_start(const char *svc_fmri
)
74 pthread_t smbd_nicmon_tid
;
77 if (smb_nic_init() != SMB_NIC_SUCCESS
)
80 rc
= pthread_create(&smbd_nicmon_tid
, NULL
, smbd_nicmon_daemon
, NULL
);
85 smbd_nicmon_caller_fmri
= (char *)svc_fmri
;
87 smbd_nicmon_run_check();
92 smbd_nicmon_stop(void)
96 if (eventpipe_write
< 0)
99 (void) write(eventpipe_write
, &buf
, sizeof (buf
));
100 smbd_nicmon_caller_fmri
= NULL
;
105 smbd_nicmon_refresh(void)
107 if (smb_nic_init() != SMB_NIC_SUCCESS
)
110 smbd_nicmon_run_check();
115 * The monitor is enabled unless it is explicitly
116 * disabled by setting smbd/nicmon_enable to false.
117 * smbd/nicmon_enable is not defined by default.
120 smbd_nicmon_run_check(void)
126 smbd_nicmon_enabled
= B_TRUE
;
128 if ((hd
= smb_smf_scf_init(SMBD_FMRI_PREFIX
)) == NULL
) {
130 "smbd_nicmon: smb_smf_scf_init failed");
134 rc
= smb_smf_create_service_pgroup(hd
, SMBD_PG_NAME
);
135 if (rc
!= SMBD_SMF_OK
) {
136 smb_smf_scf_fini(hd
);
138 "smbd_nicmon: smb_smf_create_service_pgroup failed");
142 rc
= smb_smf_get_boolean_property(hd
, SMBD_NICMON_ENABLE
, &status
);
143 if (rc
== SMBD_SMF_OK
&& status
== 0)
144 smbd_nicmon_enabled
= B_FALSE
;
146 smb_smf_scf_fini(hd
);
150 * Setup routing socket for getting RTM messages.
153 smbd_nicmon_setup_rtsock(int af
)
158 if ((sd
= socket(PF_ROUTE
, SOCK_RAW
, af
)) == -1) {
160 "smbd_nicmon: routing socket failed: %d", errno
);
164 if ((flags
= fcntl(sd
, F_GETFL
, 0)) < 0) {
166 "smbd_nicmon: fcntl F_GETFL failed: %d", errno
);
171 if ((fcntl(sd
, F_SETFL
, flags
| O_NONBLOCK
)) < 0) {
173 "smbd_nicmon: fcntl F_SETFL failed: %d", errno
);
182 smbd_nicmon_needscan(int sock
)
184 static uint32_t throttle
;
185 struct rt_msghdr
*rtm
;
186 int64_t msg
[2048 / 8];
187 int need_if_scan
= 0;
190 /* Read as many messages as possible and try to empty the sockets */
192 nbytes
= read(sock
, msg
, sizeof (msg
));
196 rtm
= (struct rt_msghdr
*)msg
;
197 if (rtm
->rtm_version
!= RTM_VERSION
)
200 if (nbytes
< rtm
->rtm_msglen
) {
201 if ((throttle
% SMBD_NICMON_THROTTLE
) == 0) {
203 "smbd_nicmon: short read: %d of %d",
204 nbytes
, rtm
->rtm_msglen
);
210 switch (rtm
->rtm_type
) {
221 return (need_if_scan
);
225 * Create pipe for signal delivery and set up signal handlers.
228 smbd_nicmon_setup_eventpipe(int *read_pipe
, int *write_pipe
)
232 if ((pipe(fds
)) < 0) {
234 "smbd_nicmon: event pipe failed: %d", errno
);
239 *write_pipe
= fds
[1];
244 * Create the global routing socket to monitor changes in NIC interfaces.
245 * We are only interested in new inerface addition/deletion and changes
248 * Note: only supports AF_INET routing socket. Need to add AF_INET6 to
253 smbd_nicmon_daemon(void *arg
)
255 static uint32_t throttle
;
256 static int rtsock_v4
;
257 static int eventpipe_read
= -1;
258 struct pollfd pollfds
[2];
263 if ((rtsock_v4
= smbd_nicmon_setup_rtsock(AF_INET
)) == -1)
266 rc
= smbd_nicmon_setup_eventpipe(&eventpipe_read
, &eventpipe_write
);
271 * Listen for activity on any of the sockets.
272 * The delay before checking the rtsock will hopefully
273 * smooth things out when there is a lot of activity.
278 pollfds
[0].fd
= rtsock_v4
;
279 pollfds
[0].events
= POLLIN
;
280 pollfds
[1].fd
= eventpipe_read
;
281 pollfds
[1].events
= POLLIN
;
283 if (poll(pollfds
, pollfd_num
, -1) < 0) {
286 if ((throttle
% SMBD_NICMON_THROTTLE
) == 0)
288 "smbd_nicmon: poll failed: %d", errno
);
293 for (i
= 0; i
< pollfd_num
; i
++) {
294 if ((pollfds
[i
].fd
< 0) ||
295 !(pollfds
[i
].revents
& POLLIN
))
297 if (pollfds
[i
].fd
== rtsock_v4
) {
298 (void) sleep(SMBD_NICMON_DEBOUNCE
);
299 nic_changed
= smbd_nicmon_needscan(rtsock_v4
);
301 if (pollfds
[i
].fd
== eventpipe_read
)
306 * If the monitor is enabled and something has changed,
307 * refresh the registered SMF service.
309 if (smbd_nicmon_enabled
&& nic_changed
&&
310 smbd_nicmon_caller_fmri
) {
311 if (smf_refresh_instance(smbd_nicmon_caller_fmri
) != 0)
313 "smbd_nicmon: %s refresh failed",
314 smbd_nicmon_caller_fmri
);
318 (void) close(rtsock_v4
);
319 (void) close(eventpipe_read
);
320 (void) close(eventpipe_write
);
321 eventpipe_write
= -1;