Print this page
7388 Support DHCP Client FQDN. Allow IAID/DUID for all v4.
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
+++ new/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright 2016 Argo Technologie SA.
25 + * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
25 26 */
26 27
27 28 /*
28 29 * Contains DB walker functions, which are of type `db_wfunc_t';
29 30 *
30 31 * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
31 32 * size_t bufsize, int *errp);
32 33 *
33 34 * ipadm_rw_db() walks through the data store, one line at a time and calls
34 35 * these call back functions with:
35 36 * `cbarg' - callback argument
36 37 * `db_nvl' - representing a line from DB in nvlist_t form
37 38 * `buf' - character buffer to hold modified line
38 39 * `bufsize'- size of the buffer
39 40 * `errp' - captures any error inside the walker function.
40 41 *
41 42 * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
42 43 * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
43 44 * To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
44 45 * the modified `buf' is written back into DB.
45 46 *
46 47 * All the 'read' callback functions, retrieve the information from the DB, by
47 48 * reading `db_nvl' and then populate the `cbarg'.
48 49 */
49 50
50 51 #include <stdlib.h>
51 52 #include <strings.h>
52 53 #include <errno.h>
53 54 #include <assert.h>
54 55 #include <sys/types.h>
55 56 #include <sys/socket.h>
56 57 #include <netinet/in.h>
57 58 #include <arpa/inet.h>
58 59 #include <unistd.h>
59 60 #include "ipmgmt_impl.h"
60 61
61 62 /* SCF related property group names and property names */
62 63 #define IPMGMTD_APP_PG "ipmgmtd"
63 64 #define IPMGMTD_PROP_FBD "first_boot_done"
64 65 #define IPMGMTD_PROP_DBVER "datastore_version"
65 66 #define IPMGMTD_TRUESTR "true"
66 67
67 68 #define ATYPE "_atype" /* name of the address type nvpair */
68 69 #define FLAGS "_flags" /* name of the flags nvpair */
69 70
70 71 /*
71 72 * flag used by ipmgmt_persist_aobjmap() to indicate address type is
72 73 * IPADM_ADDR_IPV6_ADDRCONF.
73 74 */
74 75 #define IPMGMT_ATYPE_V6ACONF 0x1
75 76
76 77 extern pthread_rwlock_t ipmgmt_dbconf_lock;
77 78
78 79 /* signifies whether volatile copy of data store is in use */
79 80 static boolean_t ipmgmt_rdonly_root = B_FALSE;
80 81
81 82 /*
82 83 * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
83 84 * in private nvpairs `proto', `ifname' & `aobjname'.
84 85 */
85 86 static boolean_t
86 87 ipmgmt_nvlist_match(nvlist_t *db_nvl, const char *proto, const char *ifname,
87 88 const char *aobjname)
88 89 {
89 90 char *db_proto = NULL, *db_ifname = NULL;
90 91 char *db_aobjname = NULL;
91 92 nvpair_t *nvp;
92 93 char *name;
93 94
94 95 /* walk through db_nvl and retrieve all its private nvpairs */
95 96 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
96 97 nvp = nvlist_next_nvpair(db_nvl, nvp)) {
97 98 name = nvpair_name(nvp);
98 99 if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
99 100 (void) nvpair_value_string(nvp, &db_proto);
100 101 else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
101 102 (void) nvpair_value_string(nvp, &db_ifname);
102 103 else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
103 104 (void) nvpair_value_string(nvp, &db_aobjname);
104 105 }
105 106
106 107 if (proto != NULL && proto[0] == '\0')
107 108 proto = NULL;
108 109 if (ifname != NULL && ifname[0] == '\0')
109 110 ifname = NULL;
110 111 if (aobjname != NULL && aobjname[0] == '\0')
111 112 aobjname = NULL;
112 113
113 114 if ((proto == NULL && db_proto != NULL) ||
114 115 (proto != NULL && db_proto == NULL) ||
115 116 (proto != NULL && db_proto != NULL &&
116 117 strcmp(proto, db_proto) != 0)) {
117 118 /* no intersection - different protocols. */
118 119 return (B_FALSE);
119 120 }
120 121 if ((ifname == NULL && db_ifname != NULL) ||
121 122 (ifname != NULL && db_ifname == NULL) ||
122 123 (ifname != NULL && db_ifname != NULL &&
123 124 strcmp(ifname, db_ifname) != 0)) {
124 125 /* no intersection - different interfaces. */
125 126 return (B_FALSE);
126 127 }
127 128 if ((aobjname == NULL && db_aobjname != NULL) ||
128 129 (aobjname != NULL && db_aobjname == NULL) ||
129 130 (aobjname != NULL && db_aobjname != NULL &&
130 131 strcmp(aobjname, db_aobjname) != 0)) {
131 132 /* no intersection - different address objects */
132 133 return (B_FALSE);
133 134 }
134 135
135 136 return (B_TRUE);
136 137 }
137 138
138 139 /*
139 140 * Checks if the database nvl, `db_nvl' and the input nvl, `in_nvl' intersects.
140 141 */
141 142 static boolean_t
142 143 ipmgmt_nvlist_intersects(nvlist_t *db_nvl, nvlist_t *in_nvl)
143 144 {
144 145 nvpair_t *nvp;
145 146 char *name;
146 147 char *proto = NULL, *ifname = NULL, *aobjname = NULL;
147 148
148 149 /* walk through in_nvl and retrieve all its private nvpairs */
149 150 for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
150 151 nvp = nvlist_next_nvpair(in_nvl, nvp)) {
151 152 name = nvpair_name(nvp);
152 153 if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
153 154 (void) nvpair_value_string(nvp, &proto);
154 155 else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
155 156 (void) nvpair_value_string(nvp, &ifname);
156 157 else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
157 158 (void) nvpair_value_string(nvp, &aobjname);
158 159 }
159 160
160 161 return (ipmgmt_nvlist_match(db_nvl, proto, ifname, aobjname));
161 162 }
162 163
163 164 /*
164 165 * Checks if the database nvl, `db_nvl', contains and matches ANY of the passed
165 166 * in private nvpairs `proto', `ifname' & `aobjname'.
166 167 */
167 168 static boolean_t
168 169 ipmgmt_nvlist_contains(nvlist_t *db_nvl, const char *proto,
169 170 const char *ifname, char *aobjname)
170 171 {
171 172 char *db_ifname = NULL, *db_proto = NULL;
172 173 char *db_aobjname = NULL;
173 174 nvpair_t *nvp;
174 175 char *name;
175 176
176 177 /* walk through db_nvl and retrieve all private nvpairs */
177 178 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
178 179 nvp = nvlist_next_nvpair(db_nvl, nvp)) {
179 180 name = nvpair_name(nvp);
180 181 if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
181 182 (void) nvpair_value_string(nvp, &db_proto);
182 183 else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
183 184 (void) nvpair_value_string(nvp, &db_ifname);
184 185 else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
185 186 (void) nvpair_value_string(nvp, &db_aobjname);
186 187 }
187 188
188 189 if (proto != NULL && proto[0] != '\0') {
189 190 if ((db_proto == NULL || strcmp(proto, db_proto) != 0))
190 191 return (B_FALSE);
191 192 }
192 193 if (ifname != NULL && ifname[0] != '\0') {
193 194 if ((db_ifname == NULL || strcmp(ifname, db_ifname) != 0))
194 195 return (B_FALSE);
195 196 }
196 197 if (aobjname != NULL && aobjname[0] != '\0') {
197 198 if ((db_aobjname == NULL || strcmp(aobjname, db_aobjname) != 0))
198 199 return (B_FALSE);
199 200 }
200 201
201 202 return (B_TRUE);
202 203 }
203 204
204 205 /*
205 206 * Retrieves the property value from the DB. The property whose value is to be
206 207 * retrieved is in `pargp->ia_pname'.
207 208 */
208 209 /* ARGSUSED */
209 210 boolean_t
210 211 ipmgmt_db_getprop(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
211 212 int *errp)
212 213 {
213 214 ipmgmt_prop_arg_t *pargp = arg;
214 215 boolean_t cont = B_TRUE;
215 216 char *pval;
216 217 int err = 0;
217 218
218 219 *errp = 0;
219 220
220 221 if (!ipmgmt_nvlist_match(db_nvl, pargp->ia_module,
221 222 pargp->ia_ifname, pargp->ia_aobjname))
222 223 return (B_TRUE);
223 224
224 225 if ((err = nvlist_lookup_string(db_nvl, pargp->ia_pname,
225 226 &pval)) == 0) {
226 227 (void) strlcpy(pargp->ia_pval, pval, sizeof (pargp->ia_pval));
227 228 /*
228 229 * We have retrieved what we are looking for.
229 230 * Stop the walker.
230 231 */
231 232 cont = B_FALSE;
232 233 } else {
233 234 if (err == ENOENT)
234 235 err = 0;
235 236 *errp = err;
236 237 }
237 238
238 239 return (cont);
239 240 }
240 241
241 242 /*
242 243 * Removes the property value from the DB. The property whose value is to be
243 244 * removed is in `pargp->ia_pname'.
244 245 */
245 246 /* ARGSUSED */
246 247 boolean_t
247 248 ipmgmt_db_resetprop(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
248 249 int *errp)
249 250 {
250 251 ipmgmt_prop_arg_t *pargp = arg;
251 252
252 253 *errp = 0;
253 254 if (!ipmgmt_nvlist_match(db_nvl, pargp->ia_module,
254 255 pargp->ia_ifname, pargp->ia_aobjname))
255 256 return (B_TRUE);
256 257
257 258 if (!nvlist_exists(db_nvl, pargp->ia_pname))
258 259 return (B_TRUE);
259 260
260 261 /*
261 262 * We found the property in the DB. If IPMGMT_REMOVE is not set then
262 263 * delete the entry from the db. If it is set, then the property is a
263 264 * multi-valued property so just remove the specified values from DB.
264 265 */
265 266 if (pargp->ia_flags & IPMGMT_REMOVE) {
266 267 char *dbpval = NULL;
267 268 char *inpval = pargp->ia_pval;
268 269 char pval[MAXPROPVALLEN];
269 270 char *val, *lasts;
270 271
271 272 *errp = nvlist_lookup_string(db_nvl, pargp->ia_pname, &dbpval);
272 273 if (*errp != 0)
273 274 return (B_FALSE);
274 275
275 276 /*
276 277 * multi-valued properties are represented as comma separated
277 278 * values. Use string tokenizer functions to split them and
278 279 * search for the value to be removed.
279 280 */
280 281 bzero(pval, sizeof (pval));
281 282 if ((val = strtok_r(dbpval, ",", &lasts)) != NULL) {
282 283 if (strcmp(val, inpval) != 0)
283 284 (void) strlcat(pval, val, MAXPROPVALLEN);
284 285 while ((val = strtok_r(NULL, ",", &lasts)) != NULL) {
285 286 if (strcmp(val, inpval) != 0) {
286 287 if (pval[0] != '\0')
287 288 (void) strlcat(pval, ",",
288 289 MAXPROPVALLEN);
289 290 (void) strlcat(pval, val,
290 291 MAXPROPVALLEN);
291 292 }
292 293 }
293 294 } else {
294 295 if (strcmp(dbpval, inpval) != 0)
295 296 *errp = ENOENT;
296 297 else
297 298 buf[0] = '\0';
298 299 return (B_FALSE);
299 300 }
300 301 *errp = nvlist_add_string(db_nvl, pargp->ia_pname, pval);
301 302 if (*errp != 0)
302 303 return (B_FALSE);
303 304
304 305 (void) memset(buf, 0, buflen);
305 306 if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
306 307 /* buffer overflow */
307 308 *errp = ENOBUFS;
308 309 }
309 310 } else {
310 311 buf[0] = '\0';
311 312 }
312 313
313 314 /* stop the search */
314 315 return (B_FALSE);
315 316 }
316 317
317 318 /*
318 319 * Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
319 320 * found, when one of the following occurs first.
320 321 * - the input aobjname matches the db aobjname. Return the db address.
321 322 * - the input interface matches the db interface. Return all the
322 323 * matching db lines with addresses.
323 324 */
324 325 /* ARGSUSED */
325 326 boolean_t
326 327 ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
327 328 int *errp)
328 329 {
329 330 ipmgmt_getaddr_cbarg_t *cbarg = arg;
330 331 char *db_aobjname = NULL;
331 332 char *db_ifname = NULL;
332 333 nvlist_t *db_addr = NULL;
333 334 char name[IPMGMT_STRSIZE];
334 335 nvpair_t *nvp;
335 336 boolean_t add_nvl = B_FALSE;
336 337
337 338 /* Parse db nvlist */
338 339 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
339 340 nvp = nvlist_next_nvpair(db_nvl, nvp)) {
340 341 if (nvpair_type(nvp) == DATA_TYPE_NVLIST)
341 342 (void) nvpair_value_nvlist(nvp, &db_addr);
342 343 else if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0)
343 344 (void) nvpair_value_string(nvp, &db_ifname);
344 345 else if (strcmp(nvpair_name(nvp), IPADM_NVP_AOBJNAME) == 0)
345 346 (void) nvpair_value_string(nvp, &db_aobjname);
346 347 }
347 348
348 349 if (db_aobjname == NULL) /* Not an address */
349 350 return (B_TRUE);
350 351
351 352 /* Check for a match between the aobjnames or the interface name */
352 353 if (cbarg->cb_aobjname[0] != '\0') {
353 354 if (strcmp(cbarg->cb_aobjname, db_aobjname) == 0)
354 355 add_nvl = B_TRUE;
355 356 } else if (cbarg->cb_ifname[0] != '\0') {
356 357 if (strcmp(cbarg->cb_ifname, db_ifname) == 0)
357 358 add_nvl = B_TRUE;
358 359 } else {
359 360 add_nvl = B_TRUE;
360 361 }
361 362
362 363 if (add_nvl) {
363 364 (void) snprintf(name, sizeof (name), "%s_%d", db_ifname,
364 365 cbarg->cb_ocnt);
365 366 *errp = nvlist_add_nvlist(cbarg->cb_onvl, name, db_nvl);
366 367 if (*errp == 0)
367 368 cbarg->cb_ocnt++;
368 369 }
369 370 return (B_TRUE);
370 371 }
371 372
372 373 /*
373 374 * This function only gets called if a volatile filesystem version
374 375 * of the configuration file has been created. This only happens in the
375 376 * extremely rare case that a request has been made to update the configuration
376 377 * file at boottime while the root filesystem was read-only. This is
377 378 * really a rare occurrence now that we don't support UFS root filesystems
378 379 * any longer. This function will periodically attempt to write the
379 380 * configuration back to its location on the root filesystem. Success
380 381 * will indicate that the filesystem is no longer read-only.
381 382 */
382 383 /* ARGSUSED */
383 384 static void *
384 385 ipmgmt_db_restore_thread(void *arg)
385 386 {
386 387 int err;
387 388
388 389 for (;;) {
389 390 (void) sleep(5);
390 391 (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
391 392 if (!ipmgmt_rdonly_root)
392 393 break;
393 394 err = ipmgmt_cpfile(IPADM_VOL_DB_FILE, IPADM_DB_FILE, B_FALSE);
394 395 if (err == 0) {
395 396 ipmgmt_rdonly_root = B_FALSE;
396 397 break;
397 398 }
398 399 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
399 400 }
400 401 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
401 402 return (NULL);
402 403 }
403 404
404 405 /*
405 406 * This function takes the appropriate lock, read or write, based on the
406 407 * `db_op' and then calls DB walker ipadm_rw_db(). The code is complicated
407 408 * by the fact that we are not always guaranteed to have a writable root
408 409 * filesystem since it is possible that we are reading or writing during
409 410 * bootime while the root filesystem is still read-only. This is, by far,
410 411 * the exception case. Normally, this function will be called when the
411 412 * root filesystem is writable. In the unusual case where this is not
412 413 * true, the configuration file is copied to the volatile file system
413 414 * and is updated there until the root filesystem becomes writable. At
414 415 * that time the file will be moved back to its proper location by
415 416 * ipmgmt_db_restore_thread().
416 417 */
417 418 extern int
418 419 ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op)
419 420 {
420 421 int err;
421 422 boolean_t writeop;
422 423 mode_t mode;
423 424 pthread_t tid;
424 425 pthread_attr_t attr;
425 426
426 427 writeop = (db_op != IPADM_DB_READ);
427 428 if (writeop) {
428 429 (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
429 430 mode = IPADM_FILE_MODE;
430 431 } else {
431 432 (void) pthread_rwlock_rdlock(&ipmgmt_dbconf_lock);
432 433 mode = 0;
433 434 }
434 435
435 436 /*
436 437 * Did a previous write attempt fail? If so, don't even try to
437 438 * read/write to IPADM_DB_FILE.
438 439 */
439 440 if (!ipmgmt_rdonly_root) {
440 441 err = ipadm_rw_db(db_walk_func, db_warg, IPADM_DB_FILE,
441 442 mode, db_op);
442 443 if (err != EROFS)
443 444 goto done;
444 445 }
445 446
446 447 /*
447 448 * If we haven't already copied the file to the volatile
448 449 * file system, do so. This should only happen on a failed
449 450 * writeop(i.e., we have acquired the write lock above).
450 451 */
451 452 if (access(IPADM_VOL_DB_FILE, F_OK) != 0) {
452 453 assert(writeop);
453 454 err = ipmgmt_cpfile(IPADM_DB_FILE, IPADM_VOL_DB_FILE, B_TRUE);
454 455 if (err != 0)
455 456 goto done;
456 457 (void) pthread_attr_init(&attr);
457 458 (void) pthread_attr_setdetachstate(&attr,
458 459 PTHREAD_CREATE_DETACHED);
459 460 err = pthread_create(&tid, &attr, ipmgmt_db_restore_thread,
460 461 NULL);
461 462 (void) pthread_attr_destroy(&attr);
462 463 if (err != 0) {
463 464 (void) unlink(IPADM_VOL_DB_FILE);
464 465 goto done;
465 466 }
466 467 ipmgmt_rdonly_root = B_TRUE;
467 468 }
468 469
469 470 /*
470 471 * Read/write from the volatile copy.
471 472 */
472 473 err = ipadm_rw_db(db_walk_func, db_warg, IPADM_VOL_DB_FILE,
473 474 mode, db_op);
474 475 done:
475 476 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
476 477 return (err);
477 478 }
478 479
479 480 /*
480 481 * Used to add an entry towards the end of DB. It just returns B_TRUE for
481 482 * every line of the DB. When we reach the end, ipadm_rw_db() adds the
482 483 * line at the end.
483 484 */
484 485 /* ARGSUSED */
485 486 boolean_t
486 487 ipmgmt_db_add(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen, int *errp)
487 488 {
488 489 return (B_TRUE);
489 490 }
490 491
491 492 /*
492 493 * This function is used to update or create an entry in DB. The nvlist_t,
493 494 * `in_nvl', represents the line we are looking for. Once we ensure the right
494 495 * line from DB, we update that entry.
495 496 */
496 497 boolean_t
497 498 ipmgmt_db_update(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
498 499 int *errp)
499 500 {
500 501 ipadm_dbwrite_cbarg_t *cb = arg;
501 502 uint_t flags = cb->dbw_flags;
502 503 nvlist_t *in_nvl = cb->dbw_nvl;
503 504 nvpair_t *nvp;
504 505 char *name, *instrval = NULL, *dbstrval = NULL;
505 506 char pval[MAXPROPVALLEN];
506 507
507 508 *errp = 0;
508 509 if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
509 510 return (B_TRUE);
510 511
511 512 for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
512 513 nvp = nvlist_next_nvpair(in_nvl, nvp)) {
513 514 name = nvpair_name(nvp);
514 515 if (!IPADM_PRIV_NVP(name) && nvlist_exists(db_nvl, name))
515 516 break;
516 517 }
517 518
518 519 if (nvp == NULL)
519 520 return (B_TRUE);
520 521
521 522 assert(nvpair_type(nvp) == DATA_TYPE_STRING);
522 523
523 524 if ((*errp = nvpair_value_string(nvp, &instrval)) != 0)
524 525 return (B_FALSE);
525 526
526 527 /*
527 528 * If IPMGMT_APPEND is set then we are dealing with multi-valued
528 529 * properties. We append to the entry from the db, with the new value.
529 530 */
530 531 if (flags & IPMGMT_APPEND) {
531 532 if ((*errp = nvlist_lookup_string(db_nvl, name,
532 533 &dbstrval)) != 0)
533 534 return (B_FALSE);
534 535 (void) snprintf(pval, MAXPROPVALLEN, "%s,%s", dbstrval,
535 536 instrval);
536 537 if ((*errp = nvlist_add_string(db_nvl, name, pval)) != 0)
537 538 return (B_FALSE);
538 539 } else {
539 540 /* case of in-line update of a db entry */
540 541 if ((*errp = nvlist_add_string(db_nvl, name, instrval)) != 0)
541 542 return (B_FALSE);
542 543 }
543 544
544 545 (void) memset(buf, 0, buflen);
545 546 if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
546 547 /* buffer overflow */
547 548 *errp = ENOBUFS;
548 549 }
549 550
550 551 /* we updated the DB entry, so do not continue */
551 552 return (B_FALSE);
552 553 }
553 554
554 555 /*
555 556 * For the given `cbarg->cb_ifname' interface, retrieves any persistent
556 557 * interface information (used in 'ipadm show-if')
557 558 */
558 559 /* ARGSUSED */
559 560 boolean_t
560 561 ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
561 562 int *errp)
562 563 {
563 564 ipmgmt_getif_cbarg_t *cbarg = arg;
564 565 char *ifname = cbarg->cb_ifname;
565 566 char *intf = NULL;
566 567 ipadm_if_info_t *ifp = NULL;
567 568 sa_family_t af;
568 569 char *afstr;
569 570
570 571 *errp = 0;
571 572 if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) != 0 ||
572 573 nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &intf) != 0 ||
573 574 (ifname[0] != '\0' && strcmp(ifname, intf) != 0)) {
574 575 return (B_TRUE);
575 576 }
576 577 af = atoi(afstr);
577 578 for (ifp = cbarg->cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next) {
578 579 if (strcmp(ifp->ifi_name, intf) == 0)
579 580 break;
580 581 }
581 582 if (ifp == NULL) {
582 583 ipadm_if_info_t *new;
583 584
584 585 if ((new = calloc(1, sizeof (*new))) == NULL) {
585 586 *errp = ENOMEM;
586 587 return (B_FALSE); /* don't continue the walk */
587 588 }
588 589 new->ifi_next = cbarg->cb_ifinfo;
589 590 cbarg->cb_ifinfo = new;
590 591 ifp = new;
591 592 (void) strlcpy(ifp->ifi_name, intf, sizeof (ifp->ifi_name));
592 593 }
593 594
594 595 if (af == AF_INET) {
595 596 ifp->ifi_pflags |= IFIF_IPV4;
596 597 } else {
597 598 assert(af == AF_INET6);
598 599 ifp->ifi_pflags |= IFIF_IPV6;
599 600 }
600 601
601 602 /* Terminate the walk if we found both v4 and v6 interfaces. */
602 603 if (ifname[0] != '\0' && (ifp->ifi_pflags & IFIF_IPV4) &&
603 604 (ifp->ifi_pflags & IFIF_IPV6))
604 605 return (B_FALSE);
605 606
606 607 return (B_TRUE);
607 608 }
608 609
609 610 /*
610 611 * Deletes those entries from the database for which interface name
611 612 * matches with the given `cbarg->cb_ifname'
612 613 */
613 614 /* ARGSUSED */
614 615 boolean_t
615 616 ipmgmt_db_resetif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
616 617 int *errp)
617 618 {
618 619 ipmgmt_if_cbarg_t *cbarg = arg;
619 620 boolean_t isv6 = (cbarg->cb_family == AF_INET6);
620 621 char *ifname = cbarg->cb_ifname;
621 622 char *modstr = NULL;
622 623 char *afstr;
623 624 char *aobjname;
624 625 uint_t proto;
625 626 ipmgmt_aobjmap_t *head;
626 627 boolean_t aobjfound = B_FALSE;
627 628
628 629 *errp = 0;
629 630
630 631 if (!ipmgmt_nvlist_contains(db_nvl, NULL, ifname, NULL))
631 632 return (B_TRUE);
632 633
633 634 if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) == 0) {
634 635 if (atoi(afstr) == cbarg->cb_family)
635 636 goto delete;
636 637 return (B_TRUE);
637 638 }
638 639
639 640 /* Reset all the interface configurations for 'ifname' */
640 641 if (isv6 && (nvlist_exists(db_nvl, IPADM_NVP_IPV6ADDR) ||
641 642 nvlist_exists(db_nvl, IPADM_NVP_INTFID))) {
642 643 goto delete;
643 644 }
644 645 if (!isv6 &&
645 646 (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
646 647 nvlist_exists(db_nvl, IPADM_NVP_DHCP))) {
647 648 goto delete;
648 649 }
649 650
650 651 if (nvlist_lookup_string(db_nvl, IPADM_NVP_AOBJNAME, &aobjname) == 0) {
651 652 /*
652 653 * This must be an address property. Delete this
653 654 * line if there is a match in the address family.
654 655 */
655 656 head = aobjmap.aobjmap_head;
656 657 while (head != NULL) {
657 658 if (strcmp(head->am_aobjname, aobjname) == 0) {
658 659 aobjfound = B_TRUE;
659 660 if (head->am_family == cbarg->cb_family)
660 661 goto delete;
661 662 }
662 663 head = head->am_next;
663 664 }
664 665 /*
665 666 * If aobjfound = B_FALSE, then this address is not
666 667 * available in active configuration. We should go ahead
667 668 * and delete it.
668 669 */
669 670 if (!aobjfound)
670 671 goto delete;
671 672 }
672 673
673 674 /*
674 675 * If we are removing both v4 and v6 interface, then we get rid of
675 676 * all the properties for that interface. On the other hand, if we
676 677 * are deleting only v4 instance of an interface, then we delete v4
677 678 * properties only.
678 679 */
679 680 if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME, &modstr) == 0) {
680 681 proto = ipadm_str2proto(modstr);
681 682 switch (proto) {
682 683 case MOD_PROTO_IPV6:
683 684 if (isv6)
684 685 goto delete;
685 686 break;
686 687 case MOD_PROTO_IPV4:
687 688 if (!isv6)
688 689 goto delete;
689 690 break;
690 691 case MOD_PROTO_IP:
691 692 /* this should never be the case, today */
692 693 assert(0);
693 694 break;
694 695 }
695 696 }
696 697 /* Not found a match yet. Continue processing the db */
697 698 return (B_TRUE);
698 699 delete:
699 700 /* delete the line from the db */
700 701 buf[0] = '\0';
701 702 return (B_TRUE);
702 703 }
703 704
704 705 /*
705 706 * Deletes those entries from the database for which address object name
706 707 * matches with the given `cbarg->cb_aobjname'
707 708 */
708 709 /* ARGSUSED */
709 710 boolean_t
710 711 ipmgmt_db_resetaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
711 712 int *errp)
712 713 {
713 714 ipmgmt_resetaddr_cbarg_t *cbarg = arg;
714 715 char *aobjname = cbarg->cb_aobjname;
715 716
716 717 *errp = 0;
717 718 if (!ipmgmt_nvlist_contains(db_nvl, NULL, NULL, aobjname))
718 719 return (B_TRUE);
719 720
720 721 /* delete the line from the db */
721 722 buf[0] = '\0';
722 723 return (B_TRUE);
723 724 }
724 725
725 726 /*
726 727 * Retrieves all interface props, including addresses, for given interface(s).
727 728 * `invl' contains the list of interfaces, for which information need to be
728 729 * retrieved.
729 730 */
730 731 /* ARGSUSED */
731 732 boolean_t
732 733 ipmgmt_db_initif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
733 734 int *errp)
734 735 {
735 736 ipmgmt_initif_cbarg_t *cbarg = arg;
736 737 nvlist_t *onvl = cbarg->cb_onvl;
737 738 nvlist_t *invl = cbarg->cb_invl;
738 739 sa_family_t in_af = cbarg->cb_family;
739 740 char *db_ifname;
740 741
741 742 *errp = 0;
742 743 if (nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &db_ifname) == 0 &&
743 744 nvlist_exists(invl, db_ifname)) {
744 745 char name[IPMGMT_STRSIZE];
745 746 sa_family_t db_af = in_af;
746 747 uint_t proto;
747 748 char *pstr;
748 749
749 750 if (in_af != AF_UNSPEC) {
750 751 if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME,
751 752 &pstr) == 0) {
752 753 proto = ipadm_str2proto(pstr);
753 754 if (proto == MOD_PROTO_IPV4)
754 755 db_af = AF_INET;
755 756 else if (proto == MOD_PROTO_IPV6)
756 757 db_af = AF_INET6;
757 758 else
758 759 db_af = in_af;
759 760 } else {
760 761 if (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
761 762 nvlist_exists(db_nvl, IPADM_NVP_DHCP))
762 763 db_af = AF_INET;
763 764 else
764 765 db_af = AF_INET6;
765 766 }
766 767 }
767 768 if (in_af == db_af) {
768 769 (void) snprintf(name, sizeof (name), "%s_%d", db_ifname,
769 770 cbarg->cb_ocnt);
770 771 *errp = nvlist_add_nvlist(onvl, name, db_nvl);
771 772 if (*errp == 0)
772 773 cbarg->cb_ocnt++;
773 774 }
774 775 }
775 776 return (B_TRUE);
776 777 }
777 778
778 779 /*
779 780 * helper function for ipmgmt_aobjmap_op(). Adds the node pointed by `nodep'
780 781 * into `aobjmap' structure.
781 782 */
782 783 static int
783 784 i_ipmgmt_add_amnode(ipmgmt_aobjmap_t *nodep)
784 785 {
785 786 ipmgmt_aobjmap_t *new, *head;
786 787
787 788 head = aobjmap.aobjmap_head;
788 789 if ((new = malloc(sizeof (ipmgmt_aobjmap_t))) == NULL)
789 790 return (ENOMEM);
790 791 *new = *nodep;
791 792 new->am_next = NULL;
792 793
793 794 /* Add the node at the beginning of the list */
794 795 if (head == NULL) {
795 796 aobjmap.aobjmap_head = new;
796 797 } else {
797 798 new->am_next = aobjmap.aobjmap_head;
798 799 aobjmap.aobjmap_head = new;
799 800 }
800 801 return (0);
801 802 }
802 803
803 804 /*
804 805 * A recursive function to generate alphabetized number given a decimal number.
805 806 * Decimal 0 to 25 maps to 'a' to 'z' and then the counting continues with 'aa',
806 807 * 'ab', 'ac', et al.
807 808 */
808 809 static void
809 810 i_ipmgmt_num2priv_aobjname(uint32_t num, char **cp, char *endp)
810 811 {
811 812 if (num >= 26)
812 813 i_ipmgmt_num2priv_aobjname(num / 26 - 1, cp, endp);
813 814 if (*cp != endp) {
814 815 *cp[0] = 'a' + (num % 26);
815 816 (*cp)++;
816 817 }
817 818 }
818 819
819 820 /*
820 821 * This function generates an `aobjname', when required, and then does
821 822 * lookup-add. If `nodep->am_aobjname' is not an empty string, then it walks
822 823 * through the `aobjmap' to check if an address object with the same
823 824 * `nodep->am_aobjname' exists. If it exists, EEXIST is returned as duplicate
824 825 * `aobjname's are not allowed.
825 826 *
826 827 * If `nodep->am_aobjname' is an empty string then the daemon generates an
827 828 * `aobjname' using the `am_nextnum', which contains the next number to be
828 829 * used to generate `aobjname'. `am_nextnum' is converted to base26 using
829 830 * `a-z' alphabets in i_ipmgmt_num2priv_aobjname().
830 831 *
831 832 * `am_nextnum' will be 0 to begin with. Every time an address object that
832 833 * needs `aobjname' is added it's incremented by 1. So for the first address
833 834 * object on net0 the `am_aobjname' will be net0/_a and `am_nextnum' will be 1.
834 835 * For the second address object on that interface `am_aobjname' will be net0/_b
835 836 * and `am_nextnum' will incremented to 2.
836 837 */
837 838 static int
838 839 i_ipmgmt_lookupadd_amnode(ipmgmt_aobjmap_t *nodep)
839 840 {
840 841 ipmgmt_aobjmap_t *head;
841 842 uint32_t nextnum;
842 843
843 844 for (head = aobjmap.aobjmap_head; head != NULL; head = head->am_next)
844 845 if (strcmp(head->am_ifname, nodep->am_ifname) == 0)
845 846 break;
846 847 nextnum = (head == NULL ? 0 : head->am_nextnum);
847 848
848 849 /*
849 850 * if `aobjname' is empty, then the daemon has to generate the
850 851 * next `aobjname' for the given interface and family.
851 852 */
852 853 if (nodep->am_aobjname[0] == '\0') {
853 854 char tmpstr[IPADM_AOBJ_USTRSIZ - 1]; /* 1 for leading '_' */
854 855 char *cp = tmpstr;
855 856 char *endp = tmpstr + sizeof (tmpstr);
856 857
857 858 i_ipmgmt_num2priv_aobjname(nextnum, &cp, endp);
858 859
859 860 if (cp == endp)
860 861 return (EINVAL);
861 862 cp[0] = '\0';
862 863
863 864 if (snprintf(nodep->am_aobjname, IPADM_AOBJSIZ, "%s/_%s",
864 865 nodep->am_ifname, tmpstr) >= IPADM_AOBJSIZ) {
865 866 return (EINVAL);
866 867 }
867 868 nodep->am_nextnum = ++nextnum;
868 869 } else {
869 870 for (head = aobjmap.aobjmap_head; head != NULL;
870 871 head = head->am_next) {
871 872 if (strcmp(head->am_aobjname, nodep->am_aobjname) == 0)
872 873 return (EEXIST);
873 874 }
874 875 nodep->am_nextnum = nextnum;
875 876 }
876 877 return (i_ipmgmt_add_amnode(nodep));
877 878 }
878 879
879 880 /*
880 881 * Performs following operations on the global `aobjmap' linked list.
881 882 * (a) ADDROBJ_ADD: add or update address object in `aobjmap'
882 883 * (b) ADDROBJ_DELETE: delete address object from `aobjmap'
883 884 * (c) ADDROBJ_LOOKUPADD: place a stub address object in `aobjmap'
884 885 * (d) ADDROBJ_SETLIFNUM: Sets the lifnum for an address object in `aobjmap'
885 886 */
886 887 int
887 888 ipmgmt_aobjmap_op(ipmgmt_aobjmap_t *nodep, uint32_t op)
888 889 {
889 890 ipmgmt_aobjmap_t *head, *prev, *matched = NULL;
890 891 boolean_t update = B_TRUE;
891 892 int err = 0;
892 893 ipadm_db_op_t db_op;
893 894
894 895 (void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
895 896
896 897 head = aobjmap.aobjmap_head;
897 898 switch (op) {
898 899 case ADDROBJ_ADD:
899 900 /*
900 901 * check for stub nodes (added by ADDROBJ_LOOKUPADD) and
|
↓ open down ↓ |
866 lines elided |
↑ open up ↑ |
901 902 * update, else add the new node.
902 903 */
903 904 for (; head != NULL; head = head->am_next) {
904 905 /*
905 906 * For IPv6, we need to distinguish between the
906 907 * linklocal and non-linklocal nodes
907 908 */
908 909 if (strcmp(head->am_aobjname,
909 910 nodep->am_aobjname) == 0 &&
910 911 (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
911 - head->am_linklocal == nodep->am_linklocal))
912 + head->ipmgmt_am_linklocal ==
913 + nodep->ipmgmt_am_linklocal))
912 914 break;
913 915 }
914 916
915 917 if (head != NULL) {
916 918 /* update the node */
917 919 (void) strlcpy(head->am_ifname, nodep->am_ifname,
918 920 sizeof (head->am_ifname));
919 921 head->am_lnum = nodep->am_lnum;
920 922 head->am_family = nodep->am_family;
921 923 head->am_flags = nodep->am_flags;
922 924 head->am_atype = nodep->am_atype;
923 - if (head->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
924 - head->am_ifid = nodep->am_ifid;
925 - head->am_linklocal = nodep->am_linklocal;
926 - }
925 + (void) memcpy(&head->am_atype_cache, &nodep->am_atype_cache,
926 + sizeof (head->am_atype_cache));
927 927 } else {
928 928 for (head = aobjmap.aobjmap_head; head != NULL;
929 929 head = head->am_next) {
930 930 if (strcmp(head->am_ifname,
931 931 nodep->am_ifname) == 0)
932 932 break;
933 933 }
934 934 nodep->am_nextnum = (head == NULL ? 0 :
935 935 head->am_nextnum);
936 936 err = i_ipmgmt_add_amnode(nodep);
937 937 }
938 938 db_op = IPADM_DB_WRITE;
939 939 break;
940 940 case ADDROBJ_DELETE:
941 941 prev = head;
942 942 while (head != NULL) {
943 943 if (strcmp(head->am_aobjname,
944 944 nodep->am_aobjname) == 0) {
945 945 nodep->am_atype = head->am_atype;
946 946 /*
947 947 * There could be multiple IPV6_ADDRCONF nodes,
948 948 * with same address object name, so check for
949 949 * logical number also.
950 950 */
951 951 if (head->am_atype !=
952 952 IPADM_ADDR_IPV6_ADDRCONF ||
953 953 nodep->am_lnum == head->am_lnum)
954 954 break;
955 955 }
956 956 prev = head;
957 957 head = head->am_next;
958 958 }
959 959 if (head != NULL) {
960 960 /*
961 961 * If the address object is in both active and
962 962 * persistent configuration and the user is deleting it
963 963 * only from active configuration then mark this node
964 964 * for deletion by reseting IPMGMT_ACTIVE bit.
965 965 * With this the same address object name cannot
966 966 * be reused until it is permanently removed.
967 967 */
968 968 if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
969 969 nodep->am_flags == IPMGMT_ACTIVE) {
970 970 /* Update flags in the in-memory map. */
971 971 head->am_flags &= ~IPMGMT_ACTIVE;
972 972 head->am_lnum = -1;
973 973
974 974 /* Update info in file. */
975 975 db_op = IPADM_DB_WRITE;
976 976 *nodep = *head;
977 977 } else {
978 978 (void) strlcpy(nodep->am_ifname,
979 979 head->am_ifname,
980 980 sizeof (nodep->am_ifname));
981 981 /* otherwise delete the node */
982 982 if (head == aobjmap.aobjmap_head)
983 983 aobjmap.aobjmap_head = head->am_next;
984 984 else
985 985 prev->am_next = head->am_next;
986 986 free(head);
987 987 db_op = IPADM_DB_DELETE;
988 988 }
989 989 } else {
990 990 err = ENOENT;
991 991 }
992 992 break;
993 993 case ADDROBJ_LOOKUPADD:
994 994 err = i_ipmgmt_lookupadd_amnode(nodep);
995 995 update = B_FALSE;
996 996 break;
997 997 case ADDROBJ_SETLIFNUM:
998 998 update = B_FALSE;
999 999 for (; head != NULL; head = head->am_next) {
1000 1000 if (strcmp(head->am_ifname,
1001 1001 nodep->am_ifname) == 0 &&
1002 1002 head->am_family == nodep->am_family &&
1003 1003 head->am_lnum == nodep->am_lnum) {
1004 1004 err = EEXIST;
1005 1005 break;
1006 1006 }
1007 1007 if (strcmp(head->am_aobjname,
1008 1008 nodep->am_aobjname) == 0) {
1009 1009 matched = head;
1010 1010 }
1011 1011 }
1012 1012 if (err == EEXIST)
1013 1013 break;
1014 1014 if (matched != NULL) {
1015 1015 /* update the lifnum */
1016 1016 matched->am_lnum = nodep->am_lnum;
1017 1017 } else {
1018 1018 err = ENOENT;
1019 1019 }
1020 1020 break;
1021 1021 default:
1022 1022 assert(0);
1023 1023 }
1024 1024
1025 1025 if (err == 0 && update)
1026 1026 err = ipmgmt_persist_aobjmap(nodep, db_op);
1027 1027
1028 1028 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
1029 1029
1030 1030 return (err);
1031 1031 }
1032 1032
1033 1033 /*
1034 1034 * Given a node in `aobjmap', this function converts it into nvlist_t structure.
1035 1035 * The content to be written to DB must be represented as nvlist_t.
1036 1036 */
1037 1037 static int
1038 1038 i_ipmgmt_node2nvl(nvlist_t **nvl, ipmgmt_aobjmap_t *np)
1039 1039 {
1040 1040 int err;
1041 1041 char strval[IPMGMT_STRSIZE];
1042 1042
1043 1043 *nvl = NULL;
1044 1044 if ((err = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0)) != 0)
1045 1045 goto fail;
1046 1046
1047 1047 if ((err = nvlist_add_string(*nvl, IPADM_NVP_AOBJNAME,
1048 1048 np->am_aobjname)) != 0)
1049 1049 goto fail;
1050 1050
1051 1051 if ((err = nvlist_add_string(*nvl, IPADM_NVP_IFNAME,
1052 1052 np->am_ifname)) != 0)
1053 1053 goto fail;
1054 1054
1055 1055 (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_lnum);
1056 1056 if ((err = nvlist_add_string(*nvl, IPADM_NVP_LIFNUM, strval)) != 0)
1057 1057 goto fail;
1058 1058
1059 1059 (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_family);
1060 1060 if ((err = nvlist_add_string(*nvl, IPADM_NVP_FAMILY, strval)) != 0)
|
↓ open down ↓ |
124 lines elided |
↑ open up ↑ |
1061 1061 goto fail;
1062 1062
1063 1063 (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_flags);
1064 1064 if ((err = nvlist_add_string(*nvl, FLAGS, strval)) != 0)
1065 1065 goto fail;
1066 1066
1067 1067 (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_atype);
1068 1068 if ((err = nvlist_add_string(*nvl, ATYPE, strval)) != 0)
1069 1069 goto fail;
1070 1070
1071 - if (np->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
1072 - struct sockaddr_in6 *in6;
1071 + switch (np->am_atype) {
1072 + case IPADM_ADDR_IPV6_ADDRCONF: {
1073 + struct sockaddr_in6 *in6;
1073 1074
1074 - in6 = (struct sockaddr_in6 *)&np->am_ifid;
1075 - if (np->am_linklocal &&
1076 - IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) {
1077 - if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
1078 - "default")) != 0)
1079 - goto fail;
1080 - } else {
1081 - if (inet_ntop(AF_INET6, &in6->sin6_addr, strval,
1082 - IPMGMT_STRSIZE) == NULL) {
1083 - err = errno;
1084 - goto fail;
1075 + in6 = &np->ipmgmt_am_ifid;
1076 + if (np->ipmgmt_am_linklocal &&
1077 + IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) {
1078 + if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
1079 + "default")) != 0)
1080 + goto fail;
1081 + } else {
1082 + if (inet_ntop(AF_INET6, &in6->sin6_addr, strval,
1083 + IPMGMT_STRSIZE) == NULL) {
1084 + err = errno;
1085 + goto fail;
1086 + }
1087 + if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
1088 + strval)) != 0)
1089 + goto fail;
1085 1090 }
1086 - if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
1087 - strval)) != 0)
1091 + }
1092 + break;
1093 + case IPADM_ADDR_DHCP: {
1094 + if (np->ipmgmt_am_reqhost &&
1095 + *np->ipmgmt_am_reqhost != '\0' &&
1096 + (err = nvlist_add_string(*nvl, IPADM_NVP_REQHOST,
1097 + np->ipmgmt_am_reqhost)) != 0)
1088 1098 goto fail;
1089 1099 }
1090 - } else {
1091 - if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
1092 - "")) != 0)
1093 - goto fail;
1100 + /* FALLTHRU */
1101 + default:
1102 + if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
1103 + "")) != 0)
1104 + goto fail;
1105 + break;
1094 1106 }
1095 1107 return (err);
1096 1108 fail:
1097 1109 nvlist_free(*nvl);
1098 1110 return (err);
1099 1111 }
1100 1112
1101 1113 /*
1102 1114 * Read the aobjmap data store and build the in-memory representation
1103 1115 * of the aobjmap. We don't need to hold any locks while building this as
1104 1116 * we do this in very early stage of daemon coming up, even before the door
1105 1117 * is opened.
1106 1118 */
1107 1119 /* ARGSUSED */
1108 1120 extern boolean_t
1109 1121 ipmgmt_aobjmap_init(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
1110 1122 int *errp)
1111 1123 {
1112 1124 nvpair_t *nvp = NULL;
1113 1125 char *name, *strval = NULL;
1114 1126 ipmgmt_aobjmap_t node;
1115 1127 struct sockaddr_in6 *in6;
1116 1128
1117 1129 *errp = 0;
1118 1130 node.am_next = NULL;
1119 1131 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1120 1132 nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1121 1133 name = nvpair_name(nvp);
1122 1134
1123 1135 if ((*errp = nvpair_value_string(nvp, &strval)) != 0)
1124 1136 return (B_TRUE);
1125 1137 if (strcmp(IPADM_NVP_AOBJNAME, name) == 0) {
1126 1138 (void) strlcpy(node.am_aobjname, strval,
1127 1139 sizeof (node.am_aobjname));
1128 1140 } else if (strcmp(IPADM_NVP_IFNAME, name) == 0) {
1129 1141 (void) strlcpy(node.am_ifname, strval,
1130 1142 sizeof (node.am_ifname));
|
↓ open down ↓ |
27 lines elided |
↑ open up ↑ |
1131 1143 } else if (strcmp(IPADM_NVP_LIFNUM, name) == 0) {
1132 1144 node.am_lnum = atoi(strval);
1133 1145 } else if (strcmp(IPADM_NVP_FAMILY, name) == 0) {
1134 1146 node.am_family = (sa_family_t)atoi(strval);
1135 1147 } else if (strcmp(FLAGS, name) == 0) {
1136 1148 node.am_flags = atoi(strval);
1137 1149 } else if (strcmp(ATYPE, name) == 0) {
1138 1150 node.am_atype = (ipadm_addr_type_t)atoi(strval);
1139 1151 } else if (strcmp(IPADM_NVP_IPNUMADDR, name) == 0) {
1140 1152 if (node.am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
1141 - in6 = (struct sockaddr_in6 *)&node.am_ifid;
1153 + in6 = &node.ipmgmt_am_ifid;
1142 1154 if (strcmp(strval, "default") == 0) {
1143 - bzero(in6, sizeof (node.am_ifid));
1144 - node.am_linklocal = B_TRUE;
1155 + bzero(in6, sizeof (node.ipmgmt_am_ifid));
1156 + node.ipmgmt_am_linklocal = B_TRUE;
1145 1157 } else {
1146 1158 (void) inet_pton(AF_INET6, strval,
1147 1159 &in6->sin6_addr);
1148 1160 if (IN6_IS_ADDR_UNSPECIFIED(
1149 1161 &in6->sin6_addr))
1150 - node.am_linklocal = B_TRUE;
1162 + node.ipmgmt_am_linklocal = B_TRUE;
1151 1163 }
1152 1164 }
1153 1165 }
1154 1166 }
1155 1167
1156 1168 /* we have all the information we need, add the node */
1157 1169 *errp = i_ipmgmt_add_amnode(&node);
1158 1170
1159 1171 return (B_TRUE);
1160 1172 }
1161 1173
1162 1174 /*
1163 1175 * Updates an entry from the temporary cache file, which matches the given
1164 1176 * address object name.
1165 1177 */
1166 1178 /* ARGSUSED */
1167 1179 static boolean_t
1168 1180 ipmgmt_update_aobjmap(void *arg, nvlist_t *db_nvl, char *buf,
1169 1181 size_t buflen, int *errp)
1170 1182 {
1171 1183 ipadm_dbwrite_cbarg_t *cb = arg;
1172 1184 nvlist_t *in_nvl = cb->dbw_nvl;
1173 1185 uint32_t flags = cb->dbw_flags;
1174 1186 char *db_lifnumstr = NULL, *in_lifnumstr = NULL;
1175 1187
1176 1188 *errp = 0;
1177 1189 if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
1178 1190 return (B_TRUE);
1179 1191
1180 1192 if (flags & IPMGMT_ATYPE_V6ACONF) {
1181 1193 if (nvlist_lookup_string(db_nvl, IPADM_NVP_LIFNUM,
1182 1194 &db_lifnumstr) != 0 ||
1183 1195 nvlist_lookup_string(in_nvl, IPADM_NVP_LIFNUM,
1184 1196 &in_lifnumstr) != 0 ||
1185 1197 (atoi(db_lifnumstr) != -1 && atoi(in_lifnumstr) != -1 &&
1186 1198 strcmp(db_lifnumstr, in_lifnumstr) != 0))
1187 1199 return (B_TRUE);
1188 1200 }
1189 1201
1190 1202 /* we found the match */
1191 1203 (void) memset(buf, 0, buflen);
1192 1204 if (ipadm_nvlist2str(in_nvl, buf, buflen) == 0) {
1193 1205 /* buffer overflow */
1194 1206 *errp = ENOBUFS;
1195 1207 }
1196 1208
1197 1209 /* stop the walker */
1198 1210 return (B_FALSE);
1199 1211 }
1200 1212
1201 1213 /*
1202 1214 * Deletes an entry from the temporary cache file, which matches the given
1203 1215 * address object name.
1204 1216 */
1205 1217 /* ARGSUSED */
1206 1218 static boolean_t
1207 1219 ipmgmt_delete_aobjmap(void *arg, nvlist_t *db_nvl, char *buf,
1208 1220 size_t buflen, int *errp)
1209 1221 {
1210 1222 ipmgmt_aobjmap_t *nodep = arg;
1211 1223 char *db_lifnumstr = NULL;
1212 1224
1213 1225 *errp = 0;
1214 1226 if (!ipmgmt_nvlist_match(db_nvl, NULL, nodep->am_ifname,
1215 1227 nodep->am_aobjname))
1216 1228 return (B_TRUE);
1217 1229
1218 1230 if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
1219 1231 if (nvlist_lookup_string(db_nvl, IPADM_NVP_LIFNUM,
1220 1232 &db_lifnumstr) != 0 || atoi(db_lifnumstr) != nodep->am_lnum)
1221 1233 return (B_TRUE);
1222 1234 }
1223 1235
1224 1236 /* we found the match, delete the line from the db */
1225 1237 buf[0] = '\0';
1226 1238
1227 1239 /* stop the walker */
1228 1240 return (B_FALSE);
1229 1241 }
1230 1242
1231 1243 /*
1232 1244 * Adds or deletes aobjmap node information into a temporary cache file.
1233 1245 */
1234 1246 extern int
1235 1247 ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t *nodep, ipadm_db_op_t op)
1236 1248 {
1237 1249 int err;
1238 1250 ipadm_dbwrite_cbarg_t cb;
1239 1251 nvlist_t *nvl = NULL;
1240 1252
1241 1253 if (op == IPADM_DB_WRITE) {
1242 1254 if ((err = i_ipmgmt_node2nvl(&nvl, nodep)) != 0)
1243 1255 return (err);
1244 1256 cb.dbw_nvl = nvl;
1245 1257 if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF)
1246 1258 cb.dbw_flags = IPMGMT_ATYPE_V6ACONF;
1247 1259 else
1248 1260 cb.dbw_flags = 0;
1249 1261
1250 1262 err = ipadm_rw_db(ipmgmt_update_aobjmap, &cb,
1251 1263 ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_WRITE);
1252 1264 nvlist_free(nvl);
1253 1265 } else {
1254 1266 assert(op == IPADM_DB_DELETE);
1255 1267
1256 1268 err = ipadm_rw_db(ipmgmt_delete_aobjmap, nodep,
1257 1269 ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_DELETE);
1258 1270 }
1259 1271 return (err);
1260 1272 }
1261 1273
1262 1274 /*
1263 1275 * upgrades the ipadm data-store. It renames all the old private protocol
1264 1276 * property names which start with leading protocol names to begin with
1265 1277 * IPADM_PRIV_PROP_PREFIX.
1266 1278 */
1267 1279 /* ARGSUSED */
1268 1280 boolean_t
1269 1281 ipmgmt_db_upgrade(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
1270 1282 int *errp)
1271 1283 {
1272 1284 nvpair_t *nvp;
1273 1285 char *name, *pname = NULL, *protostr = NULL, *pval = NULL;
1274 1286 uint_t proto, nproto;
1275 1287 char nname[IPMGMT_STRSIZE], tmpstr[IPMGMT_STRSIZE];
1276 1288
1277 1289 *errp = 0;
1278 1290 /*
1279 1291 * We are interested in lines which contain protocol properties. We
1280 1292 * walk through other lines in the DB.
1281 1293 */
1282 1294 if (nvlist_exists(db_nvl, IPADM_NVP_IFNAME) ||
1283 1295 nvlist_exists(db_nvl, IPADM_NVP_AOBJNAME)) {
1284 1296 return (B_TRUE);
1285 1297 }
1286 1298 assert(nvlist_exists(db_nvl, IPADM_NVP_PROTONAME));
1287 1299
1288 1300 /*
1289 1301 * extract the propname from the `db_nvl' and also extract the
1290 1302 * protocol from the `db_nvl'.
1291 1303 */
1292 1304 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1293 1305 nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1294 1306 name = nvpair_name(nvp);
1295 1307 if (strcmp(name, IPADM_NVP_PROTONAME) == 0) {
1296 1308 if (nvpair_value_string(nvp, &protostr) != 0)
1297 1309 return (B_TRUE);
1298 1310 } else {
1299 1311 assert(!IPADM_PRIV_NVP(name));
1300 1312 pname = name;
1301 1313 if (nvpair_value_string(nvp, &pval) != 0)
1302 1314 return (B_TRUE);
1303 1315 }
1304 1316 }
1305 1317
1306 1318 /* if the private property is in the right format return */
1307 1319 if (strncmp(pname, IPADM_PERSIST_PRIVPROP_PREFIX,
1308 1320 strlen(IPADM_PERSIST_PRIVPROP_PREFIX)) == 0) {
1309 1321 return (B_TRUE);
1310 1322 }
1311 1323 /* if it's a public property move onto the next property */
1312 1324 nproto = proto = ipadm_str2proto(protostr);
1313 1325 if (ipadm_legacy2new_propname(pname, nname, sizeof (nname),
1314 1326 &nproto) != 0) {
1315 1327 return (B_TRUE);
1316 1328 }
1317 1329
1318 1330 /* replace the old protocol with new protocol, if required */
1319 1331 if (nproto != proto) {
1320 1332 protostr = ipadm_proto2str(nproto);
1321 1333 if (nvlist_add_string(db_nvl, IPADM_NVP_PROTONAME,
1322 1334 protostr) != 0) {
1323 1335 return (B_TRUE);
1324 1336 }
1325 1337 }
1326 1338
1327 1339 /* replace the old property name with new property name, if required */
1328 1340 /* add the prefix to property name */
1329 1341 (void) snprintf(tmpstr, sizeof (tmpstr), "_%s", nname);
1330 1342 if (nvlist_add_string(db_nvl, tmpstr, pval) != 0 ||
1331 1343 nvlist_remove(db_nvl, pname, DATA_TYPE_STRING) != 0) {
1332 1344 return (B_TRUE);
1333 1345 }
1334 1346 (void) memset(buf, 0, buflen);
1335 1347 if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
1336 1348 /* buffer overflow */
1337 1349 *errp = ENOBUFS;
1338 1350 }
1339 1351 return (B_TRUE);
1340 1352 }
1341 1353
1342 1354 /*
1343 1355 * Called during boot.
1344 1356 *
1345 1357 * Walk through the DB and apply all the global module properties. We plow
1346 1358 * through the DB even if we fail to apply property.
1347 1359 */
1348 1360 /* ARGSUSED */
1349 1361 static boolean_t
1350 1362 ipmgmt_db_init(void *cbarg, nvlist_t *db_nvl, char *buf, size_t buflen,
1351 1363 int *errp)
1352 1364 {
1353 1365 ipadm_handle_t iph = cbarg;
1354 1366 nvpair_t *nvp, *pnvp;
1355 1367 char *strval = NULL, *name, *mod = NULL, *pname;
1356 1368 char tmpstr[IPMGMT_STRSIZE];
1357 1369 uint_t proto;
1358 1370
1359 1371 /*
1360 1372 * We could have used nvl_exists() directly, however we need several
1361 1373 * calls to it and each call traverses the list. Since this codepath
1362 1374 * is exercised during boot, let's traverse the list ourselves and do
1363 1375 * the necessary checks.
1364 1376 */
1365 1377 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1366 1378 nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1367 1379 name = nvpair_name(nvp);
1368 1380 if (IPADM_PRIV_NVP(name)) {
1369 1381 if (strcmp(name, IPADM_NVP_IFNAME) == 0 ||
1370 1382 strcmp(name, IPADM_NVP_AOBJNAME) == 0)
1371 1383 return (B_TRUE);
1372 1384 else if (strcmp(name, IPADM_NVP_PROTONAME) == 0 &&
1373 1385 nvpair_value_string(nvp, &mod) != 0)
1374 1386 return (B_TRUE);
1375 1387 } else {
1376 1388 /* possible a property */
1377 1389 pnvp = nvp;
1378 1390 }
1379 1391 }
1380 1392
1381 1393 /* if we are here than we found a global property */
1382 1394 assert(mod != NULL);
1383 1395 assert(nvpair_type(pnvp) == DATA_TYPE_STRING);
1384 1396
1385 1397 proto = ipadm_str2proto(mod);
1386 1398 name = nvpair_name(pnvp);
1387 1399 if (nvpair_value_string(pnvp, &strval) == 0) {
1388 1400 if (strncmp(name, IPADM_PERSIST_PRIVPROP_PREFIX,
1389 1401 strlen(IPADM_PERSIST_PRIVPROP_PREFIX)) == 0) {
1390 1402 /* private protocol property */
1391 1403 pname = &name[1];
1392 1404 } else if (ipadm_legacy2new_propname(name, tmpstr,
1393 1405 sizeof (tmpstr), &proto) == 0) {
1394 1406 pname = tmpstr;
1395 1407 } else {
1396 1408 pname = name;
1397 1409 }
1398 1410 if (ipadm_set_prop(iph, pname, strval, proto,
1399 1411 IPADM_OPT_ACTIVE) != IPADM_SUCCESS) {
1400 1412 ipmgmt_log(LOG_WARNING, "Failed to reapply property %s",
1401 1413 pname);
1402 1414 }
1403 1415 }
1404 1416
1405 1417 return (B_TRUE);
1406 1418 }
1407 1419
1408 1420 /* initialize global module properties */
1409 1421 void
1410 1422 ipmgmt_init_prop()
1411 1423 {
1412 1424 ipadm_handle_t iph = NULL;
1413 1425
1414 1426 if (ipadm_open(&iph, IPH_INIT) != IPADM_SUCCESS) {
1415 1427 ipmgmt_log(LOG_WARNING, "Could not reapply any of the "
1416 1428 "persisted protocol properties");
1417 1429 return;
1418 1430 }
1419 1431 /* ipmgmt_db_init() logs warnings if there are any issues */
1420 1432 (void) ipmgmt_db_walk(ipmgmt_db_init, iph, IPADM_DB_READ);
1421 1433 ipadm_close(iph);
1422 1434 }
1423 1435
1424 1436 void
1425 1437 ipmgmt_release_scf_resources(scf_resources_t *res)
1426 1438 {
1427 1439 scf_entry_destroy(res->sr_ent);
1428 1440 scf_transaction_destroy(res->sr_tx);
1429 1441 scf_value_destroy(res->sr_val);
1430 1442 scf_property_destroy(res->sr_prop);
1431 1443 scf_pg_destroy(res->sr_pg);
1432 1444 scf_instance_destroy(res->sr_inst);
1433 1445 (void) scf_handle_unbind(res->sr_handle);
1434 1446 scf_handle_destroy(res->sr_handle);
1435 1447 }
1436 1448
1437 1449 /*
1438 1450 * It creates the necessary SCF handles and binds the given `fmri' to an
1439 1451 * instance. These resources are required for retrieving property value,
1440 1452 * creating property groups and modifying property values.
1441 1453 */
1442 1454 int
1443 1455 ipmgmt_create_scf_resources(const char *fmri, scf_resources_t *res)
1444 1456 {
1445 1457 res->sr_tx = NULL;
1446 1458 res->sr_ent = NULL;
1447 1459 res->sr_inst = NULL;
1448 1460 res->sr_pg = NULL;
1449 1461 res->sr_prop = NULL;
1450 1462 res->sr_val = NULL;
1451 1463
1452 1464 if ((res->sr_handle = scf_handle_create(SCF_VERSION)) == NULL)
1453 1465 return (-1);
1454 1466
1455 1467 if (scf_handle_bind(res->sr_handle) != 0) {
1456 1468 scf_handle_destroy(res->sr_handle);
1457 1469 return (-1);
1458 1470 }
1459 1471 if ((res->sr_inst = scf_instance_create(res->sr_handle)) == NULL)
1460 1472 goto failure;
1461 1473 if (scf_handle_decode_fmri(res->sr_handle, fmri, NULL, NULL,
1462 1474 res->sr_inst, NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
1463 1475 goto failure;
1464 1476 }
1465 1477 /* we will create the rest of the resources on demand */
1466 1478 return (0);
1467 1479
1468 1480 failure:
1469 1481 ipmgmt_log(LOG_WARNING, "failed to create scf resources: %s",
1470 1482 scf_strerror(scf_error()));
1471 1483 ipmgmt_release_scf_resources(res);
1472 1484 return (-1);
1473 1485 }
1474 1486
1475 1487 /*
1476 1488 * persists the `pval' for a given property `pname' in SCF. The only supported
1477 1489 * SCF property types are INTEGER and ASTRING.
1478 1490 */
1479 1491 static int
1480 1492 ipmgmt_set_scfprop_value(scf_resources_t *res, const char *pname, void *pval,
1481 1493 scf_type_t ptype)
1482 1494 {
1483 1495 int result = -1;
1484 1496 boolean_t new;
1485 1497
1486 1498 if ((res->sr_val = scf_value_create(res->sr_handle)) == NULL)
1487 1499 goto failure;
1488 1500 switch (ptype) {
1489 1501 case SCF_TYPE_INTEGER:
1490 1502 scf_value_set_integer(res->sr_val, *(int64_t *)pval);
1491 1503 break;
1492 1504 case SCF_TYPE_ASTRING:
1493 1505 if (scf_value_set_astring(res->sr_val, (char *)pval) != 0) {
1494 1506 ipmgmt_log(LOG_WARNING, "Error setting string value %s "
1495 1507 "for property %s: %s", pval, pname,
1496 1508 scf_strerror(scf_error()));
1497 1509 goto failure;
1498 1510 }
1499 1511 break;
1500 1512 default:
1501 1513 goto failure;
1502 1514 }
1503 1515
1504 1516 if ((res->sr_tx = scf_transaction_create(res->sr_handle)) == NULL)
1505 1517 goto failure;
1506 1518 if ((res->sr_ent = scf_entry_create(res->sr_handle)) == NULL)
1507 1519 goto failure;
1508 1520 if ((res->sr_prop = scf_property_create(res->sr_handle)) == NULL)
1509 1521 goto failure;
1510 1522
1511 1523 retry:
1512 1524 new = (scf_pg_get_property(res->sr_pg, pname, res->sr_prop) != 0);
1513 1525 if (scf_transaction_start(res->sr_tx, res->sr_pg) == -1)
1514 1526 goto failure;
1515 1527 if (new) {
1516 1528 if (scf_transaction_property_new(res->sr_tx, res->sr_ent,
1517 1529 pname, ptype) == -1) {
1518 1530 goto failure;
1519 1531 }
1520 1532 } else {
1521 1533 if (scf_transaction_property_change(res->sr_tx, res->sr_ent,
1522 1534 pname, ptype) == -1) {
1523 1535 goto failure;
1524 1536 }
1525 1537 }
1526 1538
1527 1539 if (scf_entry_add_value(res->sr_ent, res->sr_val) != 0)
1528 1540 goto failure;
1529 1541
1530 1542 result = scf_transaction_commit(res->sr_tx);
1531 1543 if (result == 0) {
1532 1544 scf_transaction_reset(res->sr_tx);
1533 1545 if (scf_pg_update(res->sr_pg) == -1) {
1534 1546 goto failure;
1535 1547 }
1536 1548 goto retry;
1537 1549 }
1538 1550 if (result == -1)
1539 1551 goto failure;
1540 1552 return (0);
1541 1553
1542 1554 failure:
1543 1555 ipmgmt_log(LOG_WARNING, "failed to save the data in SCF: %s",
1544 1556 scf_strerror(scf_error()));
1545 1557 return (-1);
1546 1558 }
1547 1559
1548 1560 /*
1549 1561 * Given a `pgname'/`pname', it retrieves the value based on `ptype' and
1550 1562 * places it in `pval'.
1551 1563 */
1552 1564 static int
1553 1565 ipmgmt_get_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
1554 1566 void *pval, scf_type_t ptype)
1555 1567 {
1556 1568 ssize_t numvals;
1557 1569 scf_simple_prop_t *prop;
1558 1570
1559 1571 prop = scf_simple_prop_get(res->sr_handle, IPMGMTD_FMRI, pgname, pname);
1560 1572 numvals = scf_simple_prop_numvalues(prop);
1561 1573 if (numvals <= 0)
1562 1574 goto ret;
1563 1575 switch (ptype) {
1564 1576 case SCF_TYPE_INTEGER:
1565 1577 *(int64_t **)pval = scf_simple_prop_next_integer(prop);
1566 1578 break;
1567 1579 case SCF_TYPE_ASTRING:
1568 1580 *(char **)pval = scf_simple_prop_next_astring(prop);
1569 1581 break;
1570 1582 }
1571 1583 ret:
1572 1584 scf_simple_prop_free(prop);
1573 1585 return (numvals);
1574 1586 }
1575 1587
1576 1588 /*
1577 1589 * It stores the `pval' for given `pgname'/`pname' property group in SCF.
1578 1590 */
1579 1591 static int
1580 1592 ipmgmt_set_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
1581 1593 void *pval, scf_type_t ptype)
1582 1594 {
1583 1595 scf_error_t err;
1584 1596
1585 1597 if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) {
1586 1598 ipmgmt_log(LOG_WARNING, "failed to create property group: %s",
1587 1599 scf_strerror(scf_error()));
1588 1600 return (-1);
1589 1601 }
1590 1602
1591 1603 if (scf_instance_add_pg(res->sr_inst, pgname, SCF_GROUP_APPLICATION,
1592 1604 0, res->sr_pg) != 0) {
1593 1605 if ((err = scf_error()) != SCF_ERROR_EXISTS) {
1594 1606 ipmgmt_log(LOG_WARNING,
1595 1607 "Error adding property group '%s/%s': %s",
1596 1608 pgname, pname, scf_strerror(err));
1597 1609 return (-1);
1598 1610 }
1599 1611 /*
1600 1612 * if the property group already exists, then we get the
1601 1613 * composed view of the property group for the given instance.
1602 1614 */
1603 1615 if (scf_instance_get_pg_composed(res->sr_inst, NULL, pgname,
1604 1616 res->sr_pg) != 0) {
1605 1617 ipmgmt_log(LOG_WARNING, "Error getting composed view "
1606 1618 "of the property group '%s/%s': %s", pgname, pname,
1607 1619 scf_strerror(scf_error()));
1608 1620 return (-1);
1609 1621 }
1610 1622 }
1611 1623
1612 1624 return (ipmgmt_set_scfprop_value(res, pname, pval, ptype));
1613 1625 }
1614 1626
1615 1627 /*
1616 1628 * Returns B_TRUE, if the non-global zone is being booted for the first time
1617 1629 * after being installed. This is required to setup the ipadm data-store for
1618 1630 * the first boot of the non-global zone. Please see, PSARC 2010/166,
1619 1631 * for more info.
1620 1632 *
1621 1633 * Note that, this API cannot be used to determine first boot post image-update.
1622 1634 * 'pkg image-update' clones the current BE and the existing value of
1623 1635 * ipmgmtd/first_boot_done will be carried forward and obviously it will be set
1624 1636 * to B_TRUE.
1625 1637 */
1626 1638 boolean_t
1627 1639 ipmgmt_ngz_firstboot_postinstall()
1628 1640 {
1629 1641 scf_resources_t res;
1630 1642 boolean_t bval = B_TRUE;
1631 1643 char *strval;
1632 1644
1633 1645 /* we always err on the side of caution */
1634 1646 if (ipmgmt_create_scf_resources(IPMGMTD_FMRI, &res) != 0)
1635 1647 return (bval);
1636 1648
1637 1649 if (ipmgmt_get_scfprop(&res, IPMGMTD_APP_PG, IPMGMTD_PROP_FBD, &strval,
1638 1650 SCF_TYPE_ASTRING) > 0) {
1639 1651 bval = (strcmp(strval, IPMGMTD_TRUESTR) == 0 ?
1640 1652 B_FALSE : B_TRUE);
1641 1653 } else {
1642 1654 /*
1643 1655 * IPMGMTD_PROP_FBD does not exist in the SCF. Lets create it.
1644 1656 * Since we err on the side of caution, we ignore the return
1645 1657 * error and return B_TRUE.
1646 1658 */
1647 1659 (void) ipmgmt_set_scfprop(&res, IPMGMTD_APP_PG,
1648 1660 IPMGMTD_PROP_FBD, IPMGMTD_TRUESTR, SCF_TYPE_ASTRING);
1649 1661 }
1650 1662 ipmgmt_release_scf_resources(&res);
1651 1663 return (bval);
1652 1664 }
1653 1665
1654 1666 /*
1655 1667 * Returns B_TRUE, if the data-store needs upgrade otherwise returns B_FALSE.
1656 1668 * Today we have to take care of, one case of, upgrading from version 0 to
1657 1669 * version 1, so we will use boolean_t as means to decide if upgrade is needed
1658 1670 * or not. Further, the upcoming projects might completely move the flatfile
1659 1671 * data-store into SCF and hence we shall keep this interface simple.
1660 1672 */
1661 1673 boolean_t
1662 1674 ipmgmt_needs_upgrade(scf_resources_t *res)
1663 1675 {
1664 1676 boolean_t bval = B_TRUE;
1665 1677 int64_t *verp;
1666 1678
1667 1679 if (ipmgmt_get_scfprop(res, IPMGMTD_APP_PG, IPMGMTD_PROP_DBVER,
1668 1680 &verp, SCF_TYPE_INTEGER) > 0) {
1669 1681 if (*verp == IPADM_DB_VERSION)
1670 1682 bval = B_FALSE;
1671 1683 }
1672 1684 /*
1673 1685 * 'datastore_version' doesn't exist. Which means that we need to
1674 1686 * upgrade the datastore. We will create 'datastore_version' and set
1675 1687 * the version value to IPADM_DB_VERSION, after we upgrade the file.
1676 1688 */
1677 1689 return (bval);
1678 1690 }
1679 1691
1680 1692 /*
1681 1693 * This is called after the successful upgrade of the local data-store. With
1682 1694 * the data-store upgraded to recent version we don't have to do anything on
1683 1695 * subsequent reboots.
1684 1696 */
1685 1697 void
1686 1698 ipmgmt_update_dbver(scf_resources_t *res)
1687 1699 {
1688 1700 int64_t version = IPADM_DB_VERSION;
1689 1701
1690 1702 (void) ipmgmt_set_scfprop(res, IPMGMTD_APP_PG,
1691 1703 IPMGMTD_PROP_DBVER, &version, SCF_TYPE_INTEGER);
1692 1704 }
|
↓ open down ↓ |
532 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX