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