1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * This RCM module adds support to the RCM framework for Bridge links
28 */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <synch.h>
36 #include <assert.h>
37 #include <strings.h>
38 #include "rcm_module.h"
39 #include <libintl.h>
40 #include <libdllink.h>
41 #include <libdlbridge.h>
42 #include <libdlpi.h>
43
44 /*
45 * Definitions
46 */
47 #ifndef lint
48 #define _(x) gettext(x)
49 #else
50 #define _(x) x
51 #endif
52
53 /* Some generic well-knowns and defaults used in this module */
54 #define RCM_LINK_PREFIX "SUNW_datalink" /* RCM datalink name prefix */
55 #define RCM_LINK_RESOURCE_MAX (13 + LINKID_STR_WIDTH)
56
57 /* Bridge Cache state flags */
58 typedef enum {
59 CACHE_NODE_STALE = 0x1, /* stale cached data */
60 CACHE_NODE_NEW = 0x2, /* new cached nodes */
61 CACHE_NODE_OFFLINED = 0x4 /* nodes offlined */
62 } cache_node_state_t;
63
64 /* Network Cache lookup options */
65 #define CACHE_NO_REFRESH 0x1 /* cache refresh not needed */
66 #define CACHE_REFRESH 0x2 /* refresh cache */
67
68 /* Cache element */
69 typedef struct link_cache {
70 struct link_cache *vc_next; /* next cached resource */
71 struct link_cache *vc_prev; /* prev cached resource */
72 char *vc_resource; /* resource name */
73 datalink_id_t vc_linkid; /* linkid */
74 cache_node_state_t vc_state; /* cache state flags */
75 char vc_bridge[MAXLINKNAMELEN];
76 } link_cache_t;
77
78 /*
79 * Global cache for network Bridges
80 */
81 static link_cache_t cache_head;
82 static link_cache_t cache_tail;
83 static mutex_t cache_lock;
84 static boolean_t events_registered = B_FALSE;
85
86 static dladm_handle_t dld_handle = NULL;
87
88 /*
89 * RCM module interface prototypes
90 */
91 static int bridge_register(rcm_handle_t *);
92 static int bridge_unregister(rcm_handle_t *);
93 static int bridge_get_info(rcm_handle_t *, char *, id_t, uint_t,
94 char **, char **, nvlist_t *, rcm_info_t **);
95 static int bridge_suspend(rcm_handle_t *, char *, id_t,
96 timespec_t *, uint_t, char **, rcm_info_t **);
97 static int bridge_resume(rcm_handle_t *, char *, id_t, uint_t,
98 char **, rcm_info_t **);
99 static int bridge_offline(rcm_handle_t *, char *, id_t, uint_t,
100 char **, rcm_info_t **);
101 static int bridge_undo_offline(rcm_handle_t *, char *, id_t,
102 uint_t, char **, rcm_info_t **);
103 static int bridge_remove(rcm_handle_t *, char *, id_t, uint_t,
104 char **, rcm_info_t **);
105 static int bridge_notify_event(rcm_handle_t *, char *, id_t,
106 uint_t, char **, nvlist_t *, rcm_info_t **);
107 static int bridge_configure(rcm_handle_t *, datalink_id_t);
108
109 /* Module private routines */
110 static void cache_free(void);
111 static int cache_update(rcm_handle_t *);
112 static void cache_remove(link_cache_t *);
113 static void node_free(link_cache_t *);
114 static void cache_insert(link_cache_t *);
115 static link_cache_t *cache_lookup(rcm_handle_t *, char *, uint_t);
116 static char *bridge_usage(link_cache_t *);
117 static void bridge_log_err(datalink_id_t, char **, char *);
118
119 /* Module-Private data */
120 static struct rcm_mod_ops bridge_ops =
121 {
122 RCM_MOD_OPS_VERSION,
123 bridge_register,
124 bridge_unregister,
125 bridge_get_info,
126 bridge_suspend,
127 bridge_resume,
128 bridge_offline,
129 bridge_undo_offline,
130 bridge_remove,
131 NULL,
132 NULL,
133 bridge_notify_event
134 };
135
136 /*
137 * rcm_mod_init() - Update registrations, and return the ops structure.
138 */
139 struct rcm_mod_ops *
rcm_mod_init(void)140 rcm_mod_init(void)
141 {
142 dladm_status_t status;
143 char errmsg[DLADM_STRSIZE];
144
145 rcm_log_message(RCM_TRACE1, "Bridge: mod_init\n");
146
147 cache_head.vc_next = &cache_tail;
148 cache_head.vc_prev = NULL;
149 cache_tail.vc_prev = &cache_head;
150 cache_tail.vc_next = NULL;
151 (void) mutex_init(&cache_lock, 0, NULL);
152
153 if ((status = dladm_open(&dld_handle)) != DLADM_STATUS_OK) {
154 rcm_log_message(RCM_WARNING,
155 "Bridge: cannot open datalink handle: %s\n",
156 dladm_status2str(status, errmsg));
157 return (NULL);
158 }
159
160 /* Return the ops vectors */
161 return (&bridge_ops);
162 }
163
164 /*
165 * rcm_mod_info() - Return a string describing this module.
166 */
167 const char *
rcm_mod_info(void)168 rcm_mod_info(void)
169 {
170 rcm_log_message(RCM_TRACE1, "Bridge: mod_info\n");
171
172 return ("Bridge module version 1.0");
173 }
174
175 /*
176 * rcm_mod_fini() - Destroy the network Bridge cache.
177 */
178 int
rcm_mod_fini(void)179 rcm_mod_fini(void)
180 {
181 rcm_log_message(RCM_TRACE1, "Bridge: mod_fini\n");
182
183 /*
184 * Note that bridge_unregister() does not seem to be called anywhere,
185 * therefore we free the cache nodes here. In theory we should call
186 * rcm_register_interest() for each node before we free it, but the
187 * framework does not provide the rcm_handle to allow us to do so.
188 */
189 cache_free();
190 (void) mutex_destroy(&cache_lock);
191
192 dladm_close(dld_handle);
193 return (RCM_SUCCESS);
194 }
195
196 /*
197 * bridge_register() - Make sure the cache is properly sync'ed, and its
198 * registrations are in order.
199 */
200 static int
bridge_register(rcm_handle_t * hd)201 bridge_register(rcm_handle_t *hd)
202 {
203 int retv;
204
205 rcm_log_message(RCM_TRACE1, "Bridge: register\n");
206
207 if ((retv = cache_update(hd)) != RCM_SUCCESS)
208 return (retv);
209
210 /*
211 * Need to register interest in all new resources
212 * getting attached, so we get attach event notifications
213 */
214 if (!events_registered) {
215 retv = rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL);
216 if (retv != RCM_SUCCESS) {
217 rcm_log_message(RCM_ERROR,
218 _("Bridge: failed to register %s\n"),
219 RCM_RESOURCE_LINK_NEW);
220 } else {
221 rcm_log_message(RCM_DEBUG, "Bridge: registered %s\n",
222 RCM_RESOURCE_LINK_NEW);
223 events_registered = B_TRUE;
224 }
225 }
226
227 return (retv);
228 }
229
230 /*
231 * bridge_unregister() - Walk the cache, unregistering all the links.
232 */
233 static int
bridge_unregister(rcm_handle_t * hd)234 bridge_unregister(rcm_handle_t *hd)
235 {
236 link_cache_t *node;
237 int retv = RCM_SUCCESS;
238
239 rcm_log_message(RCM_TRACE1, "Bridge: unregister\n");
240
241 /* Walk the cache, unregistering everything */
242 (void) mutex_lock(&cache_lock);
243 node = cache_head.vc_next;
244 while (node != &cache_tail) {
245 retv = rcm_unregister_interest(hd, node->vc_resource, 0);
246 if (retv != RCM_SUCCESS)
247 break;
248 cache_remove(node);
249 node_free(node);
250 node = cache_head.vc_next;
251 }
252 (void) mutex_unlock(&cache_lock);
253 if (retv != RCM_SUCCESS) {
254 rcm_log_message(RCM_ERROR,
255 _("Bridge: failed to unregister %s\n"), node->vc_resource);
256 return (retv);
257 }
258
259 /*
260 * Unregister interest in all new resources
261 */
262 if (events_registered) {
263 retv = rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0);
264 if (retv != RCM_SUCCESS) {
265 rcm_log_message(RCM_ERROR,
266 _("Bridge: failed to unregister %s\n"),
267 RCM_RESOURCE_LINK_NEW);
268 } else {
269 rcm_log_message(RCM_DEBUG, "Bridge: unregistered %s\n",
270 RCM_RESOURCE_LINK_NEW);
271 events_registered = B_FALSE;
272 }
273 }
274
275 return (retv);
276 }
277
278 /*
279 * bridge_offline() - Offline the bridge on a specific link.
280 */
281 static int
bridge_offline(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,rcm_info_t ** info)282 bridge_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
283 char **errorp, rcm_info_t **info)
284 {
285 link_cache_t *node;
286 dladm_status_t status;
287
288 rcm_log_message(RCM_TRACE1, "Bridge: offline(%s)\n", rsrc);
289
290 /* Lock the cache and lookup the resource */
291 (void) mutex_lock(&cache_lock);
292 node = cache_lookup(hd, rsrc, CACHE_REFRESH);
293 if (node == NULL) {
294 /* should not happen because the resource is registered. */
295 bridge_log_err(DATALINK_INVALID_LINKID, errorp,
296 "unrecognized resource");
297 (void) mutex_unlock(&cache_lock);
298 return (RCM_SUCCESS);
299 }
300
301 /* Check if it's a query */
302 if (flags & RCM_QUERY) {
303 rcm_log_message(RCM_TRACE1,
304 "Bridge: offline query succeeded(%s)\n", rsrc);
305 (void) mutex_unlock(&cache_lock);
306 return (RCM_SUCCESS);
307 }
308
309 status = dladm_bridge_setlink(dld_handle, node->vc_linkid, "");
310 if (status != DLADM_STATUS_OK) {
311 bridge_log_err(node->vc_linkid, errorp, "offline failed");
312 (void) mutex_unlock(&cache_lock);
313 return (RCM_FAILURE);
314 }
315
316 node->vc_state |= CACHE_NODE_OFFLINED;
317
318 rcm_log_message(RCM_TRACE1, "Bridge: Offline succeeded(%s %s)\n", rsrc,
319 node->vc_bridge);
320 (void) mutex_unlock(&cache_lock);
321 return (RCM_SUCCESS);
322 }
323
324 /*
325 * bridge_undo_offline() - Undo offline of a previously offlined node.
326 */
327 /*ARGSUSED*/
328 static int
bridge_undo_offline(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,rcm_info_t ** info)329 bridge_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
330 char **errorp, rcm_info_t **info)
331 {
332 link_cache_t *node;
333 dladm_status_t status;
334 char errmsg[DLADM_STRSIZE];
335
336 rcm_log_message(RCM_TRACE1, "Bridge: online(%s)\n", rsrc);
337
338 (void) mutex_lock(&cache_lock);
339 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
340 if (node == NULL) {
341 bridge_log_err(DATALINK_INVALID_LINKID, errorp, "no such link");
342 (void) mutex_unlock(&cache_lock);
343 errno = ENOENT;
344 return (RCM_FAILURE);
345 }
346
347 /* Check if no attempt should be made to online the link here */
348 if (!(node->vc_state & CACHE_NODE_OFFLINED)) {
349 bridge_log_err(node->vc_linkid, errorp, "link not offlined");
350 (void) mutex_unlock(&cache_lock);
351 errno = ENOTSUP;
352 return (RCM_SUCCESS);
353 }
354
355 /*
356 * Try to bring on an offlined bridge link.
357 */
358 status = dladm_bridge_setlink(dld_handle, node->vc_linkid,
359 node->vc_bridge);
360 if (status != DLADM_STATUS_OK) {
361 /*
362 * Print a warning message.
363 */
364 rcm_log_message(RCM_WARNING,
365 _("Bridge: Bridge online failed %u %s: %s\n"),
366 node->vc_linkid, node->vc_bridge,
367 dladm_status2str(status, errmsg));
368 }
369
370 node->vc_state &= ~CACHE_NODE_OFFLINED;
371 rcm_log_message(RCM_TRACE1, "Bridge: online succeeded(%s)\n", rsrc);
372 (void) mutex_unlock(&cache_lock);
373 return (RCM_SUCCESS);
374 }
375
376 /*
377 * bridge_get_info() - Gather usage information for this resource.
378 */
379 /*ARGSUSED*/
380 int
bridge_get_info(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** usagep,char ** errorp,nvlist_t * props,rcm_info_t ** info)381 bridge_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
382 char **usagep, char **errorp, nvlist_t *props, rcm_info_t **info)
383 {
384 link_cache_t *node;
385
386 rcm_log_message(RCM_TRACE1, "Bridge: get_info(%s)\n", rsrc);
387
388 (void) mutex_lock(&cache_lock);
389 node = cache_lookup(hd, rsrc, CACHE_REFRESH);
390 if (node == NULL) {
391 rcm_log_message(RCM_INFO,
392 _("Bridge: get_info(%s) unrecognized resource\n"), rsrc);
393 (void) mutex_unlock(&cache_lock);
394 errno = ENOENT;
395 return (RCM_FAILURE);
396 }
397
398 *usagep = bridge_usage(node);
399 (void) mutex_unlock(&cache_lock);
400 if (*usagep == NULL) {
401 /* most likely malloc failure */
402 rcm_log_message(RCM_ERROR,
403 _("Bridge: get_info(%s) malloc failure\n"), rsrc);
404 (void) mutex_unlock(&cache_lock);
405 errno = ENOMEM;
406 return (RCM_FAILURE);
407 }
408
409 /* Set client/role properties */
410 (void) nvlist_add_string(props, RCM_CLIENT_NAME, "Bridge");
411
412 rcm_log_message(RCM_TRACE1, "Bridge: get_info(%s) info = %s\n",
413 rsrc, *usagep);
414 return (RCM_SUCCESS);
415 }
416
417 /*
418 * bridge_suspend() - Nothing to do, always okay
419 */
420 /*ARGSUSED*/
421 static int
bridge_suspend(rcm_handle_t * hd,char * rsrc,id_t id,timespec_t * interval,uint_t flags,char ** errorp,rcm_info_t ** info)422 bridge_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
423 uint_t flags, char **errorp, rcm_info_t **info)
424 {
425 rcm_log_message(RCM_TRACE1, "Bridge: suspend(%s)\n", rsrc);
426 return (RCM_SUCCESS);
427 }
428
429 /*
430 * bridge_resume() - Nothing to do, always okay
431 */
432 /*ARGSUSED*/
433 static int
bridge_resume(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,rcm_info_t ** info)434 bridge_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
435 char **errorp, rcm_info_t **info)
436 {
437 rcm_log_message(RCM_TRACE1, "Bridge: resume(%s)\n", rsrc);
438 return (RCM_SUCCESS);
439 }
440
441 /*
442 * bridge_remove() - remove a resource from cache
443 */
444 /*ARGSUSED*/
445 static int
bridge_remove(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,rcm_info_t ** info)446 bridge_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
447 char **errorp, rcm_info_t **info)
448 {
449 link_cache_t *node;
450
451 rcm_log_message(RCM_TRACE1, "Bridge: remove(%s)\n", rsrc);
452
453 (void) mutex_lock(&cache_lock);
454 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
455 if (node == NULL) {
456 rcm_log_message(RCM_INFO,
457 _("Bridge: remove(%s) unrecognized resource\n"), rsrc);
458 (void) mutex_unlock(&cache_lock);
459 errno = ENOENT;
460 return (RCM_FAILURE);
461 }
462
463 /* remove the cached entry for the resource */
464 rcm_log_message(RCM_TRACE2,
465 "Bridge: remove succeeded(%s, %s)\n", rsrc, node->vc_bridge);
466 cache_remove(node);
467 (void) mutex_unlock(&cache_lock);
468
469 node_free(node);
470 return (RCM_SUCCESS);
471 }
472
473 /*
474 * bridge_notify_event - Project private implementation to receive new resource
475 * events. It intercepts all new resource events. If the
476 * new resource is a network resource, pass up a notify
477 * for it too. The new resource need not be cached, since
478 * it is done at register again.
479 */
480 /*ARGSUSED*/
481 static int
bridge_notify_event(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,nvlist_t * nvl,rcm_info_t ** info)482 bridge_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
483 char **errorp, nvlist_t *nvl, rcm_info_t **info)
484 {
485 nvpair_t *nvp = NULL;
486 datalink_id_t linkid;
487 uint64_t id64;
488 int rv, lastrv;
489
490 rcm_log_message(RCM_TRACE1, "Bridge: notify_event(%s)\n", rsrc);
491
492 if (strcmp(rsrc, RCM_RESOURCE_LINK_NEW) != 0) {
493 bridge_log_err(DATALINK_INVALID_LINKID, errorp,
494 "unrecognized event");
495 errno = EINVAL;
496 return (RCM_FAILURE);
497 }
498
499 /* Update cache to reflect latest Bridges */
500 if ((lastrv = cache_update(hd)) != RCM_SUCCESS) {
501 bridge_log_err(DATALINK_INVALID_LINKID, errorp,
502 "private Cache update failed");
503 return (lastrv);
504 }
505
506 /*
507 * Try best to recover all configuration.
508 */
509 rcm_log_message(RCM_DEBUG, "Bridge: process_nvlist\n");
510 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
511 if (strcmp(nvpair_name(nvp), RCM_NV_LINKID) != 0)
512 continue;
513
514 if (nvpair_value_uint64(nvp, &id64) != 0) {
515 bridge_log_err(DATALINK_INVALID_LINKID, errorp,
516 "cannot get linkid");
517 lastrv = RCM_FAILURE;
518 continue;
519 }
520
521 linkid = (datalink_id_t)id64;
522 if ((rv = bridge_configure(hd, linkid)) != RCM_SUCCESS) {
523 bridge_log_err(linkid, errorp, "configuring failed");
524 lastrv = rv;
525 }
526 }
527
528 rcm_log_message(RCM_TRACE1,
529 "Bridge: notify_event: link configuration complete\n");
530 return (lastrv);
531 }
532
533 /*
534 * bridge_usage - Determine the usage of a link.
535 * The returned buffer is owned by caller, and the caller
536 * must free it up when done.
537 */
538 static char *
bridge_usage(link_cache_t * node)539 bridge_usage(link_cache_t *node)
540 {
541 char *buf;
542 const char *fmt;
543 char errmsg[DLADM_STRSIZE];
544 char name[MAXLINKNAMELEN];
545 char bridge[MAXLINKNAMELEN];
546 dladm_status_t status;
547
548 rcm_log_message(RCM_TRACE2, "Bridge: usage(%s)\n", node->vc_resource);
549
550 assert(MUTEX_HELD(&cache_lock));
551
552 status = dladm_datalink_id2info(dld_handle, node->vc_linkid, NULL,
553 NULL, NULL, name, sizeof (name));
554
555 if (status != DLADM_STATUS_OK) {
556 rcm_log_message(RCM_ERROR,
557 _("Bridge: usage(%s) get link name failure(%s)\n"),
558 node->vc_resource, dladm_status2str(status, errmsg));
559 return (NULL);
560 }
561
562 (void) dladm_bridge_getlink(dld_handle, node->vc_linkid, bridge,
563 sizeof (bridge));
564
565 if (node->vc_state & CACHE_NODE_OFFLINED)
566 fmt = _("%1$s offlined");
567 else if (bridge[0] == '\0')
568 fmt = _("%1$s not bridged");
569 else
570 fmt = _("%1$s bridge: %2$s");
571
572 (void) asprintf(&buf, fmt, name, bridge);
573
574 rcm_log_message(RCM_TRACE2, "Bridge: usage (%s) info = %s\n",
575 node->vc_resource, buf);
576
577 return (buf);
578 }
579
580 /*
581 * Cache management routines, all cache management functions should be
582 * be called with cache_lock held.
583 */
584
585 /*
586 * cache_lookup() - Get a cache node for a resource.
587 * Call with cache lock held.
588 *
589 * This ensures that the cache is consistent with the system state and
590 * returns a pointer to the cache element corresponding to the resource.
591 */
592 static link_cache_t *
cache_lookup(rcm_handle_t * hd,char * rsrc,uint_t options)593 cache_lookup(rcm_handle_t *hd, char *rsrc, uint_t options)
594 {
595 link_cache_t *node;
596
597 rcm_log_message(RCM_TRACE2, "Bridge: cache lookup(%s)\n", rsrc);
598
599 assert(MUTEX_HELD(&cache_lock));
600 if (options & CACHE_REFRESH) {
601 /* drop lock since update locks cache again */
602 (void) mutex_unlock(&cache_lock);
603 (void) cache_update(hd);
604 (void) mutex_lock(&cache_lock);
605 }
606
607 node = cache_head.vc_next;
608 for (; node != &cache_tail; node = node->vc_next) {
609 if (strcmp(rsrc, node->vc_resource) == 0) {
610 rcm_log_message(RCM_TRACE2,
611 "Bridge: cache lookup succeeded(%s, %s)\n", rsrc,
612 node->vc_bridge);
613 return (node);
614 }
615 }
616 return (NULL);
617 }
618
619 /*
620 * node_free - Free a node from the cache
621 */
622 static void
node_free(link_cache_t * node)623 node_free(link_cache_t *node)
624 {
625 if (node != NULL) {
626 free(node->vc_resource);
627 free(node);
628 }
629 }
630
631 /*
632 * cache_insert - Insert a resource node in cache
633 */
634 static void
cache_insert(link_cache_t * node)635 cache_insert(link_cache_t *node)
636 {
637 assert(MUTEX_HELD(&cache_lock));
638
639 /* insert at the head for best performance */
640 node->vc_next = cache_head.vc_next;
641 node->vc_prev = &cache_head;
642
643 node->vc_next->vc_prev = node;
644 node->vc_prev->vc_next = node;
645 }
646
647 /*
648 * cache_remove() - Remove a resource node from cache.
649 */
650 static void
cache_remove(link_cache_t * node)651 cache_remove(link_cache_t *node)
652 {
653 assert(MUTEX_HELD(&cache_lock));
654 node->vc_next->vc_prev = node->vc_prev;
655 node->vc_prev->vc_next = node->vc_next;
656 node->vc_next = NULL;
657 node->vc_prev = NULL;
658 }
659
660 typedef struct bridge_update_arg_s {
661 rcm_handle_t *hd;
662 int retval;
663 } bridge_update_arg_t;
664
665 /*
666 * bridge_update() - Update physical interface properties
667 */
668 static int
bridge_update(dladm_handle_t handle,datalink_id_t linkid,void * arg)669 bridge_update(dladm_handle_t handle, datalink_id_t linkid, void *arg)
670 {
671 bridge_update_arg_t *bua = arg;
672 rcm_handle_t *hd = bua->hd;
673 link_cache_t *node;
674 char *rsrc;
675 dladm_status_t status;
676 char errmsg[DLADM_STRSIZE];
677 char bridge[MAXLINKNAMELEN];
678 int ret = RCM_FAILURE;
679
680 rcm_log_message(RCM_TRACE2, "Bridge: bridge_update(%u)\n", linkid);
681
682 assert(MUTEX_HELD(&cache_lock));
683 status = dladm_bridge_getlink(dld_handle, linkid, bridge,
684 sizeof (bridge));
685 if (status != DLADM_STATUS_OK) {
686 rcm_log_message(RCM_TRACE1,
687 "Bridge: no bridge information for %u (%s)\n",
688 linkid, dladm_status2str(status, errmsg));
689 return (DLADM_WALK_CONTINUE);
690 }
691
692 (void) asprintf(&rsrc, "%s/%u", RCM_LINK_PREFIX, linkid);
693 if (rsrc == NULL) {
694 rcm_log_message(RCM_ERROR,
695 _("Bridge: allocation failure: %s %u: %s\n"),
696 bridge, linkid, strerror(errno));
697 goto done;
698 }
699
700 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
701 if (node != NULL) {
702 rcm_log_message(RCM_DEBUG, "Bridge: %s already registered\n",
703 rsrc);
704 free(rsrc);
705 node->vc_state &= ~CACHE_NODE_STALE;
706 } else {
707 rcm_log_message(RCM_DEBUG,
708 "Bridge: %s is a new resource (bridge %s)\n",
709 rsrc, bridge);
710 if ((node = calloc(1, sizeof (link_cache_t))) == NULL) {
711 free(rsrc);
712 rcm_log_message(RCM_ERROR, _("Bridge: calloc: %s\n"),
713 strerror(errno));
714 goto done;
715 }
716
717 node->vc_resource = rsrc;
718 node->vc_linkid = linkid;
719 (void) strlcpy(node->vc_bridge, bridge,
720 sizeof (node->vc_bridge));
721 node->vc_state |= CACHE_NODE_NEW;
722 cache_insert(node);
723 }
724
725 rcm_log_message(RCM_TRACE3, "Bridge: bridge_update: succeeded(%u %s)\n",
726 linkid, node->vc_bridge);
727 ret = RCM_SUCCESS;
728 done:
729 bua->retval = ret;
730 return (ret == RCM_SUCCESS ? DLADM_WALK_CONTINUE :
731 DLADM_WALK_TERMINATE);
732 }
733
734 /*
735 * cache_update() - Update cache with latest interface info
736 */
737 static int
cache_update(rcm_handle_t * hd)738 cache_update(rcm_handle_t *hd)
739 {
740 link_cache_t *node, *nnode;
741 int rv, lastrv;
742 bridge_update_arg_t bua;
743
744 rcm_log_message(RCM_TRACE2, "Bridge: cache_update\n");
745
746 (void) mutex_lock(&cache_lock);
747
748 /* first we walk the entire cache, marking each entry stale */
749 node = cache_head.vc_next;
750 for (; node != &cache_tail; node = node->vc_next)
751 node->vc_state |= CACHE_NODE_STALE;
752
753 /* now walk the links and update all of the entries */
754 bua.hd = hd;
755 bua.retval = RCM_SUCCESS;
756 (void) dladm_walk_datalink_id(bridge_update, dld_handle, &bua,
757 DATALINK_CLASS_AGGR | DATALINK_CLASS_PHYS |
758 DATALINK_CLASS_ETHERSTUB, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
759 lastrv = bua.retval;
760
761 /*
762 * Continue to delete all stale nodes from the cache even if the walk
763 * above failed. Unregister links that are not offlined and still in
764 * the cache.
765 */
766 for (node = cache_head.vc_next; node != &cache_tail; node = nnode) {
767 nnode = node->vc_next;
768
769 if (node->vc_state & CACHE_NODE_STALE) {
770 (void) rcm_unregister_interest(hd, node->vc_resource,
771 0);
772 rcm_log_message(RCM_DEBUG,
773 "Bridge: unregistered %s %s\n",
774 node->vc_resource, node->vc_bridge);
775 cache_remove(node);
776 node_free(node);
777 continue;
778 }
779
780 if (!(node->vc_state & CACHE_NODE_NEW))
781 continue;
782
783 rv = rcm_register_interest(hd, node->vc_resource, 0, NULL);
784 if (rv != RCM_SUCCESS) {
785 rcm_log_message(RCM_ERROR,
786 _("Bridge: failed to register %s\n"),
787 node->vc_resource);
788 lastrv = rv;
789 } else {
790 rcm_log_message(RCM_DEBUG, "Bridge: registered %s\n",
791 node->vc_resource);
792 node->vc_state &= ~CACHE_NODE_NEW;
793 }
794 }
795
796 (void) mutex_unlock(&cache_lock);
797 return (lastrv);
798 }
799
800 /*
801 * cache_free() - Empty the cache
802 */
803 static void
cache_free(void)804 cache_free(void)
805 {
806 link_cache_t *node;
807
808 rcm_log_message(RCM_TRACE2, "Bridge: cache_free\n");
809
810 (void) mutex_lock(&cache_lock);
811 node = cache_head.vc_next;
812 while (node != &cache_tail) {
813 cache_remove(node);
814 node_free(node);
815 node = cache_head.vc_next;
816 }
817 (void) mutex_unlock(&cache_lock);
818 }
819
820 /*
821 * bridge_log_err() - RCM error log wrapper
822 */
823 static void
bridge_log_err(datalink_id_t linkid,char ** errorp,char * errmsg)824 bridge_log_err(datalink_id_t linkid, char **errorp, char *errmsg)
825 {
826 char link[MAXLINKNAMELEN];
827 char errstr[DLADM_STRSIZE];
828 dladm_status_t status;
829 char *error;
830
831 link[0] = '\0';
832 if (linkid != DATALINK_INVALID_LINKID) {
833 char rsrc[RCM_LINK_RESOURCE_MAX];
834
835 (void) snprintf(rsrc, sizeof (rsrc), "%s/%u",
836 RCM_LINK_PREFIX, linkid);
837
838 rcm_log_message(RCM_ERROR, _("Bridge: %s(%s)\n"), errmsg, rsrc);
839 if ((status = dladm_datalink_id2info(dld_handle, linkid, NULL,
840 NULL, NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
841 rcm_log_message(RCM_WARNING,
842 _("Bridge: cannot get link name for (%s) %s\n"),
843 rsrc, dladm_status2str(status, errstr));
844 }
845 } else {
846 rcm_log_message(RCM_ERROR, _("Bridge: %s\n"), errmsg);
847 }
848
849 if (link[0] != '\0')
850 (void) asprintf(&error, _("Bridge: %s(%s)"), errmsg, link);
851 else
852 (void) asprintf(&error, _("Bridge: %s"), errmsg);
853
854 if (errorp != NULL)
855 *errorp = error;
856 }
857
858 /*
859 * bridge_configure() - Configure bridge on a physical link after it attaches
860 */
861 static int
bridge_configure(rcm_handle_t * hd,datalink_id_t linkid)862 bridge_configure(rcm_handle_t *hd, datalink_id_t linkid)
863 {
864 char rsrc[RCM_LINK_RESOURCE_MAX];
865 link_cache_t *node;
866 char bridge[MAXLINKNAMELEN];
867
868 /* Check for the bridge links in the cache */
869 (void) snprintf(rsrc, sizeof (rsrc), "%s/%u", RCM_LINK_PREFIX, linkid);
870
871 rcm_log_message(RCM_TRACE2, "Bridge: bridge_configure(%s)\n", rsrc);
872
873 /* Check if the link is new or was previously offlined */
874 (void) mutex_lock(&cache_lock);
875 if (((node = cache_lookup(hd, rsrc, CACHE_REFRESH)) != NULL) &&
876 (!(node->vc_state & CACHE_NODE_OFFLINED))) {
877 rcm_log_message(RCM_TRACE2,
878 "Bridge: Skipping configured interface(%s)\n", rsrc);
879 (void) mutex_unlock(&cache_lock);
880 return (RCM_SUCCESS);
881 }
882 (void) mutex_unlock(&cache_lock);
883
884 /* clear out previous bridge, if any */
885 if (dladm_bridge_getlink(dld_handle, linkid, bridge, sizeof (bridge)) ==
886 DLADM_STATUS_OK) {
887 if (bridge[0] != '\0')
888 (void) dladm_bridge_setlink(dld_handle, linkid, "");
889 }
890
891 /* now set up the new one */
892 if (node != NULL && node->vc_bridge[0] != '\0' &&
893 dladm_bridge_setlink(dld_handle, linkid, node->vc_bridge) !=
894 DLADM_STATUS_OK)
895 return (RCM_FAILURE);
896 else
897 return (RCM_SUCCESS);
898 }
899