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