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