Print this page
7388 Support DHCP Client FQDN. Allow IAID/DUID for all v4.
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c
+++ new/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.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 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
24 + * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
24 25 */
25 26 #include <arpa/inet.h>
26 27 #include <errno.h>
27 28 #include <getopt.h>
28 29 #include <inet/ip.h>
29 30 #include <inet/iptun.h>
30 31 #include <inet/tunables.h>
31 32 #include <libdladm.h>
32 33 #include <libdliptun.h>
33 34 #include <libdllink.h>
34 35 #include <libinetutil.h>
35 36 #include <libipadm.h>
36 37 #include <locale.h>
37 38 #include <netdb.h>
38 39 #include <netinet/in.h>
39 40 #include <ofmt.h>
40 41 #include <stdarg.h>
41 42 #include <stddef.h>
42 43 #include <stdio.h>
43 44 #include <stdlib.h>
44 45 #include <string.h>
45 46 #include <strings.h>
46 47 #include <sys/stat.h>
47 48 #include <sys/types.h>
48 49 #include <zone.h>
49 50
50 51 #define STR_UNKNOWN_VAL "?"
51 52 #define LIFC_DEFAULT (LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES |\
52 53 LIFC_UNDER_IPMP)
53 54
54 55 typedef void cmdfunc_t(int, char **, const char *);
55 56 static cmdfunc_t do_create_if, do_delete_if, do_enable_if, do_disable_if;
56 57 static cmdfunc_t do_show_if;
57 58 static cmdfunc_t do_set_prop, do_show_prop, do_set_ifprop;
58 59 static cmdfunc_t do_show_ifprop, do_reset_ifprop, do_reset_prop;
59 60 static cmdfunc_t do_show_addrprop, do_set_addrprop, do_reset_addrprop;
60 61 static cmdfunc_t do_create_addr, do_delete_addr, do_show_addr;
61 62 static cmdfunc_t do_enable_addr, do_disable_addr;
62 63 static cmdfunc_t do_up_addr, do_down_addr, do_refresh_addr;
63 64
64 65 typedef struct cmd {
65 66 char *c_name;
66 67 cmdfunc_t *c_fn;
67 68 const char *c_usage;
68 69 } cmd_t;
69 70
70 71 static cmd_t cmds[] = {
71 72 /* interface management related sub-commands */
72 73 { "create-if", do_create_if, "\tcreate-if\t[-t] <interface>" },
73 74 { "disable-if", do_disable_if, "\tdisable-if\t-t <interface>" },
74 75 { "enable-if", do_enable_if, "\tenable-if\t-t <interface>" },
75 76 { "delete-if", do_delete_if, "\tdelete-if\t<interface>" },
76 77 { "show-if", do_show_if,
77 78 "\tshow-if\t\t[[-p] -o <field>,...] [<interface>]\n" },
78 79 { "set-ifprop", do_set_ifprop,
79 80 "\tset-ifprop\t[-t] -p <prop>=<value[,...]> -m <protocol> "
80 81 "<interface>" },
|
↓ open down ↓ |
47 lines elided |
↑ open up ↑ |
81 82 { "reset-ifprop", do_reset_ifprop,
82 83 "\treset-ifprop\t[-t] -p <prop> -m <protocol> <interface>" },
83 84 { "show-ifprop", do_show_ifprop,
84 85 "\tshow-ifprop\t[[-c] -o <field>,...] [-p <prop>,...]\n"
85 86 "\t\t\t[-m <protocol>] [interface]\n" },
86 87
87 88 /* address management related sub-commands */
88 89 { "create-addr", do_create_addr,
89 90 "\tcreate-addr\t[-t] -T static [-d] "
90 91 "-a{local|remote}=addr[/prefixlen]\n\t\t\t<addrobj>\n"
91 - "\tcreate-addr\t[-t] -T dhcp [-w <seconds> | forever] <addrobj>\n"
92 + "\tcreate-addr\t[-t] -T dhcp [-w <seconds> | forever]\n"
93 + "\t\t\t[-1] [-h <hostname>] <addrobj>\n"
92 94 "\tcreate-addr\t[-t] -T addrconf [-i interface-id]\n"
93 95 "\t\t\t[-p {stateful|stateless}={yes|no}] <addrobj>" },
94 96 { "down-addr", do_down_addr, "\tdown-addr\t[-t] <addrobj>" },
95 97 { "up-addr", do_up_addr, "\tup-addr\t\t[-t] <addrobj>" },
96 98 { "disable-addr", do_disable_addr, "\tdisable-addr\t-t <addrobj>" },
97 99 { "enable-addr", do_enable_addr, "\tenable-addr\t-t <addrobj>" },
98 100 { "refresh-addr", do_refresh_addr, "\trefresh-addr\t[-i] <addrobj>" },
99 101 { "delete-addr", do_delete_addr, "\tdelete-addr\t[-r] <addrobj>" },
100 102 { "show-addr", do_show_addr,
101 103 "\tshow-addr\t[[-p] -o <field>,...] [<addrobj>]\n" },
102 104 { "set-addrprop", do_set_addrprop,
103 105 "\tset-addrprop\t[-t] -p <prop>=<value[,...]> <addrobj>" },
104 106 { "reset-addrprop", do_reset_addrprop,
105 107 "\treset-addrprop\t[-t] -p <prop> <addrobj>" },
106 108 { "show-addrprop", do_show_addrprop,
107 109 "\tshow-addrprop\t[[-c] -o <field>,...] [-p <prop>,...] "
108 110 "<addrobj>\n" },
109 111
110 112 /* protocol properties related sub-commands */
111 113 { "set-prop", do_set_prop,
112 114 "\tset-prop\t[-t] -p <prop>[+|-]=<value[,...]> <protocol>" },
113 115 { "reset-prop", do_reset_prop,
114 116 "\treset-prop\t[-t] -p <prop> <protocol>" },
115 117 { "show-prop", do_show_prop,
116 118 "\tshow-prop\t[[-c] -o <field>,...] [-p <prop>,...]"
117 119 " [protocol]" }
118 120 };
119 121
120 122 static const struct option if_longopts[] = {
121 123 {"temporary", no_argument, 0, 't' },
122 124 { 0, 0, 0, 0 }
123 125 };
124 126
125 127 static const struct option show_prop_longopts[] = {
126 128 {"parsable", no_argument, 0, 'c' },
127 129 {"prop", required_argument, 0, 'p' },
128 130 {"output", required_argument, 0, 'o' },
129 131 { 0, 0, 0, 0 }
130 132 };
131 133
132 134 static const struct option show_ifprop_longopts[] = {
133 135 {"module", required_argument, 0, 'm' },
134 136 {"parsable", no_argument, 0, 'c' },
135 137 {"prop", required_argument, 0, 'p' },
136 138 {"output", required_argument, 0, 'o' },
137 139 { 0, 0, 0, 0 }
138 140 };
139 141
140 142 static const struct option set_prop_longopts[] = {
141 143 {"prop", required_argument, 0, 'p' },
142 144 {"temporary", no_argument, 0, 't' },
143 145 { 0, 0, 0, 0 }
144 146 };
145 147
146 148 static const struct option set_ifprop_longopts[] = {
147 149 {"module", required_argument, 0, 'm' },
148 150 {"prop", required_argument, 0, 'p' },
149 151 {"temporary", no_argument, 0, 't' },
150 152 { 0, 0, 0, 0 }
151 153 };
152 154
153 155 static const struct option addr_misc_longopts[] = {
|
↓ open down ↓ |
52 lines elided |
↑ open up ↑ |
154 156 {"inform", no_argument, 0, 'i' },
155 157 {"release", no_argument, 0, 'r' },
156 158 {"temporary", no_argument, 0, 't' },
157 159 { 0, 0, 0, 0 }
158 160 };
159 161
160 162 static const struct option addr_longopts[] = {
161 163 {"address", required_argument, 0, 'a' },
162 164 {"down", no_argument, 0, 'd' },
163 165 {"interface-id", required_argument, 0, 'i' },
166 + {"primary", no_argument, 0, '1' },
164 167 {"prop", required_argument, 0, 'p' },
168 + {"reqhost", required_argument, 0, 'h' },
165 169 {"temporary", no_argument, 0, 't' },
166 170 {"type", required_argument, 0, 'T' },
167 171 {"wait", required_argument, 0, 'w' },
168 172 { 0, 0, 0, 0 }
169 173 };
170 174
171 175 static const struct option show_addr_longopts[] = {
172 176 {"parsable", no_argument, 0, 'p' },
173 177 {"output", required_argument, 0, 'o' },
174 178 { 0, 0, 0, 0 }
175 179 };
176 180
177 181 static const struct option show_if_longopts[] = {
178 182 {"parsable", no_argument, 0, 'p' },
179 183 {"output", required_argument, 0, 'o' },
180 184 { 0, 0, 0, 0 }
181 185 };
182 186
183 187 /* callback functions to print show-* subcommands output */
184 188 static ofmt_cb_t print_prop_cb;
185 189 static ofmt_cb_t print_sa_cb;
186 190 static ofmt_cb_t print_si_cb;
187 191
188 192 /* structures for 'ipadm show-*' subcommands */
189 193 typedef enum {
190 194 IPADM_PROPFIELD_IFNAME,
191 195 IPADM_PROPFIELD_PROTO,
192 196 IPADM_PROPFIELD_ADDROBJ,
193 197 IPADM_PROPFIELD_PROPERTY,
194 198 IPADM_PROPFIELD_PERM,
195 199 IPADM_PROPFIELD_CURRENT,
196 200 IPADM_PROPFIELD_PERSISTENT,
197 201 IPADM_PROPFIELD_DEFAULT,
198 202 IPADM_PROPFIELD_POSSIBLE
199 203 } ipadm_propfield_index_t;
200 204
201 205 static ofmt_field_t intfprop_fields[] = {
202 206 /* name, field width, index, callback */
203 207 { "IFNAME", 12, IPADM_PROPFIELD_IFNAME, print_prop_cb},
204 208 { "PROPERTY", 16, IPADM_PROPFIELD_PROPERTY, print_prop_cb},
205 209 { "PROTO", 6, IPADM_PROPFIELD_PROTO, print_prop_cb},
206 210 { "PERM", 5, IPADM_PROPFIELD_PERM, print_prop_cb},
207 211 { "CURRENT", 11, IPADM_PROPFIELD_CURRENT, print_prop_cb},
208 212 { "PERSISTENT", 11, IPADM_PROPFIELD_PERSISTENT, print_prop_cb},
209 213 { "DEFAULT", 11, IPADM_PROPFIELD_DEFAULT, print_prop_cb},
210 214 { "POSSIBLE", 16, IPADM_PROPFIELD_POSSIBLE, print_prop_cb},
211 215 { NULL, 0, 0, NULL}
212 216 };
213 217
214 218
215 219 static ofmt_field_t modprop_fields[] = {
216 220 /* name, field width, index, callback */
217 221 { "PROTO", 6, IPADM_PROPFIELD_PROTO, print_prop_cb},
218 222 { "PROPERTY", 22, IPADM_PROPFIELD_PROPERTY, print_prop_cb},
219 223 { "PERM", 5, IPADM_PROPFIELD_PERM, print_prop_cb},
220 224 { "CURRENT", 13, IPADM_PROPFIELD_CURRENT, print_prop_cb},
221 225 { "PERSISTENT", 13, IPADM_PROPFIELD_PERSISTENT, print_prop_cb},
222 226 { "DEFAULT", 13, IPADM_PROPFIELD_DEFAULT, print_prop_cb},
223 227 { "POSSIBLE", 15, IPADM_PROPFIELD_POSSIBLE, print_prop_cb},
224 228 { NULL, 0, 0, NULL}
225 229 };
226 230
227 231 static ofmt_field_t addrprop_fields[] = {
228 232 /* name, field width, index, callback */
229 233 { "ADDROBJ", 18, IPADM_PROPFIELD_ADDROBJ, print_prop_cb},
230 234 { "PROPERTY", 11, IPADM_PROPFIELD_PROPERTY, print_prop_cb},
231 235 { "PERM", 5, IPADM_PROPFIELD_PERM, print_prop_cb},
232 236 { "CURRENT", 16, IPADM_PROPFIELD_CURRENT, print_prop_cb},
233 237 { "PERSISTENT", 16, IPADM_PROPFIELD_PERSISTENT, print_prop_cb},
234 238 { "DEFAULT", 16, IPADM_PROPFIELD_DEFAULT, print_prop_cb},
235 239 { "POSSIBLE", 15, IPADM_PROPFIELD_POSSIBLE, print_prop_cb},
236 240 { NULL, 0, 0, NULL}
237 241 };
238 242
239 243 typedef struct show_prop_state {
240 244 char sps_ifname[LIFNAMSIZ];
241 245 char sps_aobjname[IPADM_AOBJSIZ];
242 246 const char *sps_pname;
243 247 uint_t sps_proto;
244 248 char *sps_propval;
245 249 nvlist_t *sps_proplist;
246 250 boolean_t sps_parsable;
247 251 boolean_t sps_addrprop;
248 252 boolean_t sps_ifprop;
249 253 boolean_t sps_modprop;
250 254 ipadm_status_t sps_status;
251 255 ipadm_status_t sps_retstatus;
252 256 ofmt_handle_t sps_ofmt;
253 257 } show_prop_state_t;
254 258
255 259 typedef struct show_addr_state {
256 260 boolean_t sa_parsable;
257 261 boolean_t sa_persist;
258 262 ofmt_handle_t sa_ofmt;
259 263 } show_addr_state_t;
260 264
261 265 typedef struct show_if_state {
262 266 boolean_t si_parsable;
263 267 ofmt_handle_t si_ofmt;
264 268 } show_if_state_t;
265 269
266 270 typedef struct show_addr_args_s {
267 271 show_addr_state_t *sa_state;
268 272 ipadm_addr_info_t *sa_info;
269 273 } show_addr_args_t;
270 274
271 275 typedef struct show_if_args_s {
272 276 show_if_state_t *si_state;
273 277 ipadm_if_info_t *si_info;
274 278 } show_if_args_t;
275 279
276 280 typedef enum {
277 281 SA_ADDROBJ,
278 282 SA_TYPE,
279 283 SA_STATE,
280 284 SA_CURRENT,
281 285 SA_PERSISTENT,
282 286 SA_ADDR
283 287 } sa_field_index_t;
284 288
285 289 typedef enum {
286 290 SI_IFNAME,
287 291 SI_STATE,
288 292 SI_CURRENT,
289 293 SI_PERSISTENT
290 294 } si_field_index_t;
291 295
292 296 static ofmt_field_t show_addr_fields[] = {
293 297 /* name, field width, id, callback */
294 298 { "ADDROBJ", 18, SA_ADDROBJ, print_sa_cb},
295 299 { "TYPE", 9, SA_TYPE, print_sa_cb},
296 300 { "STATE", 13, SA_STATE, print_sa_cb},
297 301 { "CURRENT", 8, SA_CURRENT, print_sa_cb},
298 302 { "PERSISTENT", 11, SA_PERSISTENT, print_sa_cb},
299 303 { "ADDR", 46, SA_ADDR, print_sa_cb},
300 304 { NULL, 0, 0, NULL}
301 305 };
302 306
303 307 static ofmt_field_t show_if_fields[] = {
304 308 /* name, field width, id, callback */
305 309 { "IFNAME", 11, SI_IFNAME, print_si_cb},
306 310 { "STATE", 9, SI_STATE, print_si_cb},
307 311 { "CURRENT", 13, SI_CURRENT, print_si_cb},
308 312 { "PERSISTENT", 11, SI_PERSISTENT, print_si_cb},
309 313 { NULL, 0, 0, NULL}
310 314 };
311 315
312 316 #define IPADM_ALL_BITS ((uint_t)-1)
313 317 typedef struct intf_mask {
314 318 char *name;
315 319 uint64_t bits;
316 320 uint64_t mask;
317 321 } fmask_t;
318 322
319 323 /*
320 324 * Handle to libipadm. Opened in main() before the sub-command specific
321 325 * function is called and is closed before the program exits.
322 326 */
323 327 ipadm_handle_t iph = NULL;
324 328
325 329 /*
326 330 * Opaque ipadm address object. Used by all the address management subcommands.
327 331 */
328 332 ipadm_addrobj_t ipaddr = NULL;
329 333
330 334 static char *progname;
331 335
332 336 static void die(const char *, ...);
333 337 static void die_opterr(int, int, const char *);
334 338 static void warn_ipadmerr(ipadm_status_t, const char *, ...);
335 339 static void ipadm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t);
336 340 static void ipadm_check_propstr(const char *, boolean_t, const char *);
337 341 static void process_misc_addrargs(int, char **, const char *, int *,
338 342 uint32_t *);
339 343
340 344 static void
341 345 usage(void)
342 346 {
343 347 int i;
344 348 cmd_t *cmdp;
345 349
346 350 (void) fprintf(stderr,
347 351 gettext("usage: ipadm <subcommand> <args> ...\n"));
348 352 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
349 353 cmdp = &cmds[i];
350 354 if (cmdp->c_usage != NULL)
351 355 (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage));
352 356 }
353 357
354 358 ipadm_destroy_addrobj(ipaddr);
355 359 ipadm_close(iph);
356 360 exit(1);
357 361 }
358 362
359 363 int
360 364 main(int argc, char *argv[])
361 365 {
362 366 int i;
363 367 cmd_t *cmdp;
364 368 ipadm_status_t status;
365 369
366 370 (void) setlocale(LC_ALL, "");
367 371 (void) textdomain(TEXT_DOMAIN);
368 372
369 373 if ((progname = strrchr(argv[0], '/')) == NULL)
370 374 progname = argv[0];
371 375 else
372 376 progname++;
373 377
374 378 if (argc < 2)
375 379 usage();
376 380
377 381 status = ipadm_open(&iph, 0);
378 382 if (status != IPADM_SUCCESS) {
379 383 die("Could not open handle to library - %s",
380 384 ipadm_status2str(status));
381 385 }
382 386
383 387 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
384 388 cmdp = &cmds[i];
385 389 if (strcmp(argv[1], cmdp->c_name) == 0) {
386 390 cmdp->c_fn(argc - 1, &argv[1], gettext(cmdp->c_usage));
387 391 ipadm_destroy_addrobj(ipaddr);
388 392 ipadm_close(iph);
389 393 exit(0);
390 394 }
391 395 }
392 396
393 397 (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
394 398 progname, argv[1]);
395 399 usage();
396 400
397 401 return (0);
398 402 }
399 403
400 404 /*
401 405 * Create an IP interface for which no saved configuration exists in the
402 406 * persistent store.
403 407 */
404 408 static void
405 409 do_create_if(int argc, char *argv[], const char *use)
406 410 {
407 411 ipadm_status_t status;
408 412 int option;
409 413 uint32_t flags = IPADM_OPT_PERSIST|IPADM_OPT_ACTIVE;
410 414
411 415 opterr = 0;
412 416 while ((option = getopt_long(argc, argv, ":t", if_longopts,
413 417 NULL)) != -1) {
414 418 switch (option) {
415 419 case 't':
416 420 /*
417 421 * "ifconfig" mode - plumb interface, but do not
418 422 * restore settings that may exist in db.
419 423 */
420 424 flags &= ~IPADM_OPT_PERSIST;
421 425 break;
422 426 default:
423 427 die_opterr(optopt, option, use);
424 428 }
425 429 }
426 430 if (optind != (argc - 1))
427 431 die("Usage: %s", use);
428 432 status = ipadm_create_if(iph, argv[optind], AF_UNSPEC, flags);
429 433 if (status != IPADM_SUCCESS) {
430 434 die("Could not create %s : %s",
431 435 argv[optind], ipadm_status2str(status));
432 436 }
433 437 }
434 438
435 439 /*
436 440 * Enable an IP interface based on the persistent configuration for
437 441 * that interface.
438 442 */
439 443 static void
440 444 do_enable_if(int argc, char *argv[], const char *use)
441 445 {
442 446 ipadm_status_t status;
443 447 int index;
444 448 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
445 449
446 450 process_misc_addrargs(argc, argv, use, &index, &flags);
447 451 if (flags & IPADM_OPT_PERSIST)
448 452 die("persistent operation not supported for enable-if");
449 453 status = ipadm_enable_if(iph, argv[index], flags);
450 454 if (status == IPADM_ALL_ADDRS_NOT_ENABLED) {
451 455 warn_ipadmerr(status, "");
452 456 } else if (status != IPADM_SUCCESS) {
453 457 die("Could not enable %s : %s",
454 458 argv[optind], ipadm_status2str(status));
455 459 }
456 460 }
457 461
458 462 /*
459 463 * Remove an IP interface from both active and persistent configuration.
460 464 */
461 465 static void
462 466 do_delete_if(int argc, char *argv[], const char *use)
463 467 {
464 468 ipadm_status_t status;
465 469 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
466 470
467 471 if (argc != 2)
468 472 die("Usage: %s", use);
469 473
470 474 status = ipadm_delete_if(iph, argv[1], AF_UNSPEC, flags);
471 475 if (status != IPADM_SUCCESS) {
472 476 die("Could not delete %s: %s",
473 477 argv[optind], ipadm_status2str(status));
474 478 }
475 479 }
476 480
477 481 /*
478 482 * Disable an IP interface by removing it from active configuration.
479 483 */
480 484 static void
481 485 do_disable_if(int argc, char *argv[], const char *use)
482 486 {
483 487 ipadm_status_t status;
484 488 int index;
485 489 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
486 490
487 491 process_misc_addrargs(argc, argv, use, &index, &flags);
488 492 if (flags & IPADM_OPT_PERSIST)
489 493 die("persistent operation not supported for disable-if");
490 494 status = ipadm_disable_if(iph, argv[index], flags);
491 495 if (status != IPADM_SUCCESS) {
492 496 die("Could not disable %s: %s",
493 497 argv[optind], ipadm_status2str(status));
494 498 }
495 499 }
496 500
497 501 /*
498 502 * called in from print_prop_cb() and does the job of printing each
499 503 * individual column in the 'ipadm show-*prop' output.
500 504 */
501 505 static void
502 506 print_prop(show_prop_state_t *statep, uint_t flags, char *buf, size_t bufsize)
503 507 {
504 508 const char *prop_name = statep->sps_pname;
505 509 char *ifname = statep->sps_ifname;
506 510 char *propval = statep->sps_propval;
507 511 uint_t proto = statep->sps_proto;
508 512 size_t propsize = MAXPROPVALLEN;
509 513 char *object;
510 514 ipadm_status_t status;
511 515
512 516 if (statep->sps_ifprop) {
513 517 status = ipadm_get_ifprop(iph, ifname, prop_name, propval,
514 518 &propsize, proto, flags);
515 519 object = ifname;
516 520 } else if (statep->sps_modprop) {
517 521 status = ipadm_get_prop(iph, prop_name, propval, &propsize,
518 522 proto, flags);
519 523 object = ipadm_proto2str(proto);
520 524 } else {
521 525 status = ipadm_get_addrprop(iph, prop_name, propval, &propsize,
522 526 statep->sps_aobjname, flags);
523 527 object = statep->sps_aobjname;
524 528 }
525 529
526 530 if (status != IPADM_SUCCESS) {
527 531 if (status == IPADM_PROP_UNKNOWN ||
528 532 status == IPADM_INVALID_ARG) {
529 533 warn_ipadmerr(status, "cannot get property '%s' for "
530 534 "'%s'", prop_name, object);
531 535 } else if (status == IPADM_NOTSUP) {
532 536 warn_ipadmerr(status, "'%s'", object);
533 537 } else if (status == IPADM_NOTFOUND) {
534 538 if (flags & IPADM_OPT_PERSIST) {
535 539 propval[0] = '\0';
536 540 goto cont;
537 541 } else {
538 542 warn_ipadmerr(status, "no such object '%s'",
539 543 object);
540 544 }
541 545 } else if (status == IPADM_ENXIO) {
542 546 /* the interface is probably disabled */
543 547 propval[0] = '\0';
544 548 goto cont;
545 549 }
546 550 statep->sps_status = status;
547 551 statep->sps_retstatus = status;
548 552 return;
549 553 }
550 554 cont:
551 555 statep->sps_status = IPADM_SUCCESS;
552 556 (void) snprintf(buf, bufsize, "%s", propval);
553 557 }
554 558
555 559 /*
556 560 * callback function which displays output for set-prop, set-ifprop and
557 561 * set-addrprop subcommands.
558 562 */
559 563 static boolean_t
560 564 print_prop_cb(ofmt_arg_t *ofarg, char *buf, size_t bufsize)
561 565 {
562 566 show_prop_state_t *statep = ofarg->ofmt_cbarg;
563 567 const char *propname = statep->sps_pname;
564 568 uint_t proto = statep->sps_proto;
565 569 boolean_t cont = _B_TRUE;
566 570
567 571 /*
568 572 * Fail retrieving remaining fields, if you fail
569 573 * to retrieve a field.
570 574 */
571 575 if (statep->sps_status != IPADM_SUCCESS)
572 576 return (_B_FALSE);
573 577
574 578 switch (ofarg->ofmt_id) {
575 579 case IPADM_PROPFIELD_IFNAME:
576 580 (void) snprintf(buf, bufsize, "%s", statep->sps_ifname);
577 581 break;
578 582 case IPADM_PROPFIELD_PROTO:
579 583 (void) snprintf(buf, bufsize, "%s", ipadm_proto2str(proto));
580 584 break;
581 585 case IPADM_PROPFIELD_ADDROBJ:
582 586 (void) snprintf(buf, bufsize, "%s", statep->sps_aobjname);
583 587 break;
584 588 case IPADM_PROPFIELD_PROPERTY:
585 589 (void) snprintf(buf, bufsize, "%s", propname);
586 590 break;
587 591 case IPADM_PROPFIELD_PERM:
588 592 print_prop(statep, IPADM_OPT_PERM, buf, bufsize);
589 593 break;
590 594 case IPADM_PROPFIELD_CURRENT:
591 595 print_prop(statep, IPADM_OPT_ACTIVE, buf, bufsize);
592 596 break;
593 597 case IPADM_PROPFIELD_PERSISTENT:
594 598 print_prop(statep, IPADM_OPT_PERSIST, buf, bufsize);
595 599 break;
596 600 case IPADM_PROPFIELD_DEFAULT:
597 601 print_prop(statep, IPADM_OPT_DEFAULT, buf, bufsize);
598 602 break;
599 603 case IPADM_PROPFIELD_POSSIBLE:
600 604 print_prop(statep, IPADM_OPT_POSSIBLE, buf, bufsize);
601 605 break;
602 606 }
603 607 if (statep->sps_status != IPADM_SUCCESS)
604 608 cont = _B_FALSE;
605 609 return (cont);
606 610 }
607 611
608 612 /*
609 613 * Callback function called by the property walker (ipadm_walk_prop() or
610 614 * ipadm_walk_proptbl()), for every matched property. This function in turn
611 615 * calls ofmt_print() to print property information.
612 616 */
613 617 boolean_t
614 618 show_property(void *arg, const char *pname, uint_t proto)
615 619 {
616 620 show_prop_state_t *statep = arg;
617 621
618 622 statep->sps_pname = pname;
619 623 statep->sps_proto = proto;
620 624 statep->sps_status = IPADM_SUCCESS;
621 625 ofmt_print(statep->sps_ofmt, arg);
622 626
623 627 /*
624 628 * if an object is not found or operation is not supported then
|
↓ open down ↓ |
450 lines elided |
↑ open up ↑ |
625 629 * stop the walker.
626 630 */
627 631 if (statep->sps_status == IPADM_NOTFOUND ||
628 632 statep->sps_status == IPADM_NOTSUP)
629 633 return (_B_FALSE);
630 634 return (_B_TRUE);
631 635 }
632 636
633 637 /*
634 638 * Properties to be displayed is in `statep->sps_proplist'. If it is NULL,
635 - * for all the properties for the specified object, relavant information, will
636 - * be displayed. Otherwise, for the selected property set, display relevant
639 + * for all the properties for the specified object, display relevant
640 + * information. Otherwise, for the selected property set, display relevant
637 641 * information
638 642 */
639 643 static void
640 644 show_properties(void *arg, int prop_class)
641 645 {
642 646 show_prop_state_t *statep = arg;
643 647 nvlist_t *nvl = statep->sps_proplist;
644 648 uint_t proto = statep->sps_proto;
645 649 nvpair_t *curr_nvp;
646 650 char *buf, *name;
647 651 ipadm_status_t status;
648 652
649 653 /* allocate sufficient buffer to hold a property value */
650 654 if ((buf = malloc(MAXPROPVALLEN)) == NULL)
651 655 die("insufficient memory");
652 656 statep->sps_propval = buf;
653 657
654 658 /* if no properties were specified, display all the properties */
655 659 if (nvl == NULL) {
656 660 (void) ipadm_walk_proptbl(proto, prop_class, show_property,
657 661 statep);
658 662 } else {
659 663 for (curr_nvp = nvlist_next_nvpair(nvl, NULL); curr_nvp;
660 664 curr_nvp = nvlist_next_nvpair(nvl, curr_nvp)) {
661 665 name = nvpair_name(curr_nvp);
662 666 status = ipadm_walk_prop(name, proto, prop_class,
663 667 show_property, statep);
664 668 if (status == IPADM_PROP_UNKNOWN)
665 669 (void) show_property(statep, name, proto);
666 670 }
667 671 }
668 672
669 673 free(buf);
670 674 }
671 675
672 676 /*
673 677 * Display information for all or specific interface properties, either for a
674 678 * given interface or for all the interfaces in the system.
675 679 */
676 680 static void
677 681 do_show_ifprop(int argc, char **argv, const char *use)
678 682 {
679 683 int option;
680 684 nvlist_t *proplist = NULL;
681 685 char *fields_str = NULL;
682 686 char *ifname;
683 687 ofmt_handle_t ofmt;
684 688 ofmt_status_t oferr;
685 689 uint_t ofmtflags = 0;
686 690 uint_t proto;
687 691 boolean_t m_arg = _B_FALSE;
688 692 char *protostr;
689 693 ipadm_if_info_t *ifinfo, *ifp;
690 694 ipadm_status_t status;
691 695 show_prop_state_t state;
692 696
693 697 opterr = 0;
694 698 bzero(&state, sizeof (state));
695 699 state.sps_propval = NULL;
696 700 state.sps_parsable = _B_FALSE;
697 701 state.sps_ifprop = _B_TRUE;
698 702 state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
699 703 while ((option = getopt_long(argc, argv, ":p:m:co:",
700 704 show_ifprop_longopts, NULL)) != -1) {
701 705 switch (option) {
702 706 case 'p':
703 707 if (ipadm_str2nvlist(optarg, &proplist,
704 708 IPADM_NORVAL) != 0)
705 709 die("invalid interface properties specified");
706 710 break;
707 711 case 'c':
708 712 state.sps_parsable = _B_TRUE;
709 713 break;
710 714 case 'o':
711 715 fields_str = optarg;
712 716 break;
713 717 case 'm':
714 718 if (m_arg)
715 719 die("cannot specify more than one -m");
716 720 m_arg = _B_TRUE;
717 721 protostr = optarg;
718 722 break;
719 723 default:
720 724 die_opterr(optopt, option, use);
721 725 break;
722 726 }
723 727 }
724 728
725 729 if (optind == argc - 1)
726 730 ifname = argv[optind];
727 731 else if (optind != argc)
728 732 die("Usage: %s", use);
729 733 else
730 734 ifname = NULL;
731 735
732 736 if (!m_arg)
733 737 protostr = "ip";
734 738 if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
735 739 die("invalid protocol '%s' specified", protostr);
736 740
737 741 state.sps_proto = proto;
738 742 state.sps_proplist = proplist;
739 743
740 744 if (state.sps_parsable)
741 745 ofmtflags |= OFMT_PARSABLE;
742 746 oferr = ofmt_open(fields_str, intfprop_fields, ofmtflags, 0, &ofmt);
743 747 ipadm_ofmt_check(oferr, state.sps_parsable, ofmt);
744 748 state.sps_ofmt = ofmt;
745 749
746 750 /* retrieve interface(s) and print the properties */
747 751 status = ipadm_if_info(iph, ifname, &ifinfo, 0, LIFC_DEFAULT);
748 752 if (ifname != NULL && status == IPADM_ENXIO)
749 753 die("no such object '%s': %s", ifname,
750 754 ipadm_status2str(status));
751 755 if (status != IPADM_SUCCESS)
752 756 die("Error retrieving interface(s): %s",
753 757 ipadm_status2str(status));
754 758 for (ifp = ifinfo; ifp; ifp = ifp->ifi_next) {
755 759 (void) strlcpy(state.sps_ifname, ifp->ifi_name, LIFNAMSIZ);
756 760 state.sps_proto = proto;
757 761 show_properties(&state, IPADMPROP_CLASS_IF);
758 762 }
759 763 if (ifinfo)
760 764 ipadm_free_if_info(ifinfo);
761 765
762 766 nvlist_free(proplist);
763 767 ofmt_close(ofmt);
764 768
765 769 if (state.sps_retstatus != IPADM_SUCCESS) {
766 770 ipadm_close(iph);
767 771 exit(EXIT_FAILURE);
768 772 }
769 773 }
770 774
771 775 /*
772 776 * set/reset the interface property for a given interface.
773 777 */
774 778 static void
775 779 set_ifprop(int argc, char **argv, boolean_t reset, const char *use)
776 780 {
777 781 int option;
778 782 ipadm_status_t status = IPADM_SUCCESS;
779 783 boolean_t p_arg = _B_FALSE;
780 784 boolean_t m_arg = _B_FALSE;
781 785 char *ifname, *nv, *protostr;
782 786 char *prop_name, *prop_val;
783 787 uint_t flags = IPADM_OPT_PERSIST;
784 788 uint_t proto;
785 789
786 790 opterr = 0;
787 791 while ((option = getopt_long(argc, argv, ":m:p:t",
788 792 set_ifprop_longopts, NULL)) != -1) {
789 793 switch (option) {
790 794 case 'p':
791 795 if (p_arg)
792 796 die("-p must be specified once only");
793 797 p_arg = _B_TRUE;
794 798
795 799 ipadm_check_propstr(optarg, reset, use);
796 800 nv = optarg;
797 801 break;
798 802 case 'm':
799 803 if (m_arg)
800 804 die("-m must be specified once only");
801 805 m_arg = _B_TRUE;
802 806 protostr = optarg;
803 807 break;
804 808 case 't':
805 809 flags &= ~IPADM_OPT_PERSIST;
806 810 break;
807 811 default:
808 812 die_opterr(optopt, option, use);
809 813 }
810 814 }
811 815
812 816 if (!m_arg || !p_arg || optind != argc - 1)
813 817 die("Usage: %s", use);
814 818
815 819 ifname = argv[optind];
816 820
817 821 prop_name = nv;
818 822 prop_val = strchr(nv, '=');
819 823 if (prop_val != NULL)
820 824 *prop_val++ = '\0';
821 825
822 826 if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
823 827 die("invalid protocol '%s' specified", protostr);
824 828
825 829 if (reset)
826 830 flags |= IPADM_OPT_DEFAULT;
827 831 else
828 832 flags |= IPADM_OPT_ACTIVE;
829 833 status = ipadm_set_ifprop(iph, ifname, prop_name, prop_val, proto,
830 834 flags);
831 835
832 836 done:
833 837 if (status != IPADM_SUCCESS) {
834 838 if (reset)
835 839 die("reset-ifprop: %s: %s",
836 840 prop_name, ipadm_status2str(status));
837 841 else
838 842 die("set-ifprop: %s: %s",
839 843 prop_name, ipadm_status2str(status));
840 844 }
841 845 }
842 846
843 847 static void
844 848 do_set_ifprop(int argc, char **argv, const char *use)
845 849 {
846 850 set_ifprop(argc, argv, _B_FALSE, use);
847 851 }
848 852
849 853 static void
850 854 do_reset_ifprop(int argc, char **argv, const char *use)
851 855 {
852 856 set_ifprop(argc, argv, _B_TRUE, use);
853 857 }
854 858
855 859 /*
856 860 * Display information for all or specific protocol properties, either for a
857 861 * given protocol or for supported protocols (IP/IPv4/IPv6/TCP/UDP/SCTP)
858 862 */
859 863 static void
860 864 do_show_prop(int argc, char **argv, const char *use)
861 865 {
862 866 char option;
863 867 nvlist_t *proplist = NULL;
864 868 char *fields_str = NULL;
865 869 char *protostr;
866 870 show_prop_state_t state;
867 871 ofmt_handle_t ofmt;
868 872 ofmt_status_t oferr;
869 873 uint_t ofmtflags = 0;
870 874 uint_t proto;
871 875 boolean_t p_arg = _B_FALSE;
872 876
873 877 opterr = 0;
874 878 bzero(&state, sizeof (state));
875 879 state.sps_propval = NULL;
876 880 state.sps_parsable = _B_FALSE;
877 881 state.sps_modprop = _B_TRUE;
878 882 state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
879 883 while ((option = getopt_long(argc, argv, ":p:co:", show_prop_longopts,
880 884 NULL)) != -1) {
881 885 switch (option) {
882 886 case 'p':
883 887 if (p_arg)
884 888 die("-p must be specified once only");
885 889 p_arg = _B_TRUE;
886 890 if (ipadm_str2nvlist(optarg, &proplist,
887 891 IPADM_NORVAL) != 0)
888 892 die("invalid protocol properties specified");
889 893 break;
890 894 case 'c':
891 895 state.sps_parsable = _B_TRUE;
892 896 break;
893 897 case 'o':
894 898 fields_str = optarg;
895 899 break;
896 900 default:
897 901 die_opterr(optopt, option, use);
898 902 break;
899 903 }
900 904 }
901 905 if (optind == argc - 1) {
902 906 protostr = argv[optind];
903 907 if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
904 908 die("invalid protocol '%s' specified", protostr);
905 909 state.sps_proto = proto;
906 910 } else if (optind != argc) {
907 911 die("Usage: %s", use);
908 912 } else {
909 913 if (p_arg)
910 914 die("protocol must be specified when "
911 915 "property name is used");
912 916 state.sps_proto = MOD_PROTO_NONE;
913 917 }
914 918
915 919 state.sps_proplist = proplist;
916 920
917 921 if (state.sps_parsable)
918 922 ofmtflags |= OFMT_PARSABLE;
919 923 else
920 924 ofmtflags |= OFMT_WRAP;
921 925 oferr = ofmt_open(fields_str, modprop_fields, ofmtflags, 0, &ofmt);
922 926 ipadm_ofmt_check(oferr, state.sps_parsable, ofmt);
923 927 state.sps_ofmt = ofmt;
924 928
925 929 /* handles all the errors */
926 930 show_properties(&state, IPADMPROP_CLASS_MODULE);
927 931
928 932 nvlist_free(proplist);
929 933 ofmt_close(ofmt);
930 934
931 935 if (state.sps_retstatus != IPADM_SUCCESS) {
932 936 ipadm_close(iph);
933 937 exit(EXIT_FAILURE);
934 938 }
935 939 }
936 940
937 941 /*
938 942 * Checks to see if there are any modifiers, + or -. If there are modifiers
939 943 * then sets IPADM_OPT_APPEND or IPADM_OPT_REMOVE, accordingly.
940 944 */
941 945 static void
942 946 parse_modifiers(const char *pstr, uint_t *flags, const char *use)
943 947 {
944 948 char *p;
945 949
946 950 if ((p = strchr(pstr, '=')) == NULL)
947 951 return;
948 952
949 953 if (p == pstr)
950 954 die("Invalid prop=val specified\n%s", use);
951 955
952 956 --p;
953 957 if (*p == '+')
954 958 *flags |= IPADM_OPT_APPEND;
955 959 else if (*p == '-')
956 960 *flags |= IPADM_OPT_REMOVE;
957 961 }
958 962
959 963 /*
960 964 * set/reset the protocol property for a given protocol.
961 965 */
962 966 static void
963 967 set_prop(int argc, char **argv, boolean_t reset, const char *use)
964 968 {
965 969 int option;
966 970 ipadm_status_t status = IPADM_SUCCESS;
967 971 char *protostr, *nv, *prop_name, *prop_val;
968 972 boolean_t p_arg = _B_FALSE;
969 973 uint_t proto;
970 974 uint_t flags = IPADM_OPT_PERSIST;
971 975
972 976 opterr = 0;
973 977 while ((option = getopt_long(argc, argv, ":p:t", set_prop_longopts,
974 978 NULL)) != -1) {
975 979 switch (option) {
976 980 case 'p':
977 981 if (p_arg)
978 982 die("-p must be specified once only");
979 983 p_arg = _B_TRUE;
980 984
981 985 ipadm_check_propstr(optarg, reset, use);
982 986 nv = optarg;
983 987 break;
984 988 case 't':
985 989 flags &= ~IPADM_OPT_PERSIST;
986 990 break;
987 991 default:
988 992 die_opterr(optopt, option, use);
989 993 }
990 994 }
991 995
992 996 if (!p_arg || optind != argc - 1)
993 997 die("Usage: %s", use);
994 998
995 999 parse_modifiers(nv, &flags, use);
996 1000 prop_name = nv;
997 1001 prop_val = strchr(nv, '=');
998 1002 if (prop_val != NULL) {
999 1003 if (flags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))
1000 1004 *(prop_val - 1) = '\0';
1001 1005 *prop_val++ = '\0';
1002 1006 }
1003 1007 protostr = argv[optind];
1004 1008 if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
1005 1009 die("invalid protocol '%s' specified", protostr);
1006 1010
1007 1011 if (reset)
1008 1012 flags |= IPADM_OPT_DEFAULT;
1009 1013 else
1010 1014 flags |= IPADM_OPT_ACTIVE;
1011 1015 status = ipadm_set_prop(iph, prop_name, prop_val, proto, flags);
1012 1016 done:
1013 1017 if (status != IPADM_SUCCESS) {
1014 1018 if (reset)
1015 1019 die("reset-prop: %s: %s",
1016 1020 prop_name, ipadm_status2str(status));
1017 1021 else
1018 1022 die("set-prop: %s: %s",
1019 1023 prop_name, ipadm_status2str(status));
1020 1024 }
1021 1025 }
1022 1026
1023 1027 static void
1024 1028 do_set_prop(int argc, char **argv, const char *use)
1025 1029 {
1026 1030 set_prop(argc, argv, _B_FALSE, use);
1027 1031 }
1028 1032
1029 1033 static void
1030 1034 do_reset_prop(int argc, char **argv, const char *use)
1031 1035 {
1032 1036 set_prop(argc, argv, _B_TRUE, use);
1033 1037 }
1034 1038
1035 1039 /* PRINTFLIKE1 */
1036 1040 static void
1037 1041 warn(const char *format, ...)
1038 1042 {
1039 1043 va_list alist;
1040 1044
1041 1045 format = gettext(format);
1042 1046 (void) fprintf(stderr, gettext("%s: warning: "), progname);
1043 1047
1044 1048 va_start(alist, format);
1045 1049 (void) vfprintf(stderr, format, alist);
1046 1050 va_end(alist);
1047 1051
1048 1052 (void) fprintf(stderr, "\n");
1049 1053 }
1050 1054
1051 1055 /* PRINTFLIKE1 */
1052 1056 static void
1053 1057 die(const char *format, ...)
1054 1058 {
1055 1059 va_list alist;
1056 1060
1057 1061 format = gettext(format);
1058 1062 (void) fprintf(stderr, "%s: ", progname);
1059 1063
1060 1064 va_start(alist, format);
1061 1065 (void) vfprintf(stderr, format, alist);
1062 1066 va_end(alist);
1063 1067
1064 1068 (void) putchar('\n');
1065 1069
1066 1070 ipadm_destroy_addrobj(ipaddr);
1067 1071 ipadm_close(iph);
1068 1072 exit(EXIT_FAILURE);
1069 1073 }
1070 1074
1071 1075 static void
1072 1076 die_opterr(int opt, int opterr, const char *usage)
1073 1077 {
1074 1078 switch (opterr) {
1075 1079 case ':':
1076 1080 die("option '-%c' requires a value\nusage: %s", opt,
1077 1081 gettext(usage));
1078 1082 break;
1079 1083 case '?':
1080 1084 default:
1081 1085 die("unrecognized option '-%c'\nusage: %s", opt,
1082 1086 gettext(usage));
1083 1087 break;
1084 1088 }
1085 1089 }
1086 1090
1087 1091 /* PRINTFLIKE2 */
1088 1092 static void
1089 1093 warn_ipadmerr(ipadm_status_t err, const char *format, ...)
1090 1094 {
1091 1095 va_list alist;
1092 1096
1093 1097 format = gettext(format);
1094 1098 (void) fprintf(stderr, gettext("%s: warning: "), progname);
1095 1099
1096 1100 va_start(alist, format);
1097 1101 (void) vfprintf(stderr, format, alist);
1098 1102 va_end(alist);
1099 1103
1100 1104 (void) fprintf(stderr, "%s\n", ipadm_status2str(err));
1101 1105 }
1102 1106
1103 1107 static void
1104 1108 process_static_addrargs(const char *use, char *addrarg, const char *aobjname)
1105 1109 {
1106 1110 int option;
1107 1111 char *val;
1108 1112 char *laddr = NULL;
1109 1113 char *raddr = NULL;
1110 1114 char *save_input_arg = addrarg;
1111 1115 boolean_t found_mismatch = _B_FALSE;
1112 1116 ipadm_status_t status;
1113 1117 enum { A_LOCAL, A_REMOTE };
1114 1118 static char *addr_optstr[] = {
1115 1119 "local",
1116 1120 "remote",
1117 1121 NULL,
1118 1122 };
1119 1123
1120 1124 while (*addrarg != '\0') {
1121 1125 option = getsubopt(&addrarg, addr_optstr, &val);
1122 1126 switch (option) {
1123 1127 case A_LOCAL:
1124 1128 if (laddr != NULL)
1125 1129 die("Multiple local addresses provided");
1126 1130 laddr = val;
1127 1131 break;
1128 1132 case A_REMOTE:
1129 1133 if (raddr != NULL)
1130 1134 die("Multiple remote addresses provided");
1131 1135 raddr = val;
1132 1136 break;
1133 1137 default:
1134 1138 if (found_mismatch)
1135 1139 die("Invalid address provided\nusage: %s", use);
1136 1140 found_mismatch = _B_TRUE;
1137 1141 break;
1138 1142 }
1139 1143 }
1140 1144 if (raddr != NULL && laddr == NULL)
1141 1145 die("Missing local address\nusage: %s", use);
1142 1146
1143 1147 /* If only one address is provided, it is assumed a local address. */
1144 1148 if (laddr == NULL) {
1145 1149 if (found_mismatch)
1146 1150 laddr = save_input_arg;
1147 1151 else
1148 1152 die("Missing local address\nusage: %s", use);
1149 1153 }
1150 1154
1151 1155 /* Initialize the addrobj for static addresses. */
1152 1156 status = ipadm_create_addrobj(IPADM_ADDR_STATIC, aobjname, &ipaddr);
1153 1157 if (status != IPADM_SUCCESS) {
1154 1158 die("Error in creating address object: %s",
1155 1159 ipadm_status2str(status));
1156 1160 }
1157 1161
1158 1162 /* Set the local and remote addresses */
1159 1163 status = ipadm_set_addr(ipaddr, laddr, AF_UNSPEC);
1160 1164 if (status != IPADM_SUCCESS) {
1161 1165 die("Error in setting local address: %s",
1162 1166 ipadm_status2str(status));
1163 1167 }
1164 1168 if (raddr != NULL) {
1165 1169 status = ipadm_set_dst_addr(ipaddr, raddr, AF_UNSPEC);
1166 1170 if (status != IPADM_SUCCESS) {
1167 1171 die("Error in setting remote address: %s",
1168 1172 ipadm_status2str(status));
1169 1173 }
1170 1174 }
1171 1175 }
1172 1176
1173 1177 static void
1174 1178 process_addrconf_addrargs(const char *use, char *addrarg)
1175 1179 {
1176 1180 int option;
1177 1181 char *val;
1178 1182 enum { P_STATELESS, P_STATEFUL };
1179 1183 static char *addr_optstr[] = {
1180 1184 "stateless",
1181 1185 "stateful",
1182 1186 NULL,
1183 1187 };
1184 1188 boolean_t stateless;
1185 1189 boolean_t stateless_arg = _B_FALSE;
1186 1190 boolean_t stateful;
1187 1191 boolean_t stateful_arg = _B_FALSE;
1188 1192 ipadm_status_t status;
1189 1193
1190 1194 while (*addrarg != '\0') {
1191 1195 option = getsubopt(&addrarg, addr_optstr, &val);
1192 1196 switch (option) {
1193 1197 case P_STATELESS:
1194 1198 if (stateless_arg)
1195 1199 die("Duplicate option");
1196 1200 if (val == NULL)
1197 1201 die("Invalid argument");
1198 1202 if (strcmp(val, "yes") == 0)
1199 1203 stateless = _B_TRUE;
1200 1204 else if (strcmp(val, "no") == 0)
1201 1205 stateless = _B_FALSE;
1202 1206 else
1203 1207 die("Invalid argument");
1204 1208 stateless_arg = _B_TRUE;
1205 1209 break;
1206 1210 case P_STATEFUL:
1207 1211 if (stateful_arg)
1208 1212 die("Duplicate option");
1209 1213 if (val == NULL)
1210 1214 die("Invalid argument");
1211 1215 if (strcmp(val, "yes") == 0)
1212 1216 stateful = _B_TRUE;
1213 1217 else if (strcmp(val, "no") == 0)
1214 1218 stateful = _B_FALSE;
1215 1219 else
1216 1220 die("Invalid argument");
1217 1221 stateful_arg = _B_TRUE;
1218 1222 break;
1219 1223 default:
1220 1224 die_opterr(optopt, option, use);
1221 1225 }
1222 1226 }
1223 1227
1224 1228 if (!stateless_arg && !stateful_arg)
1225 1229 die("Invalid arguments for option -p");
1226 1230
1227 1231 /* Set the addrobj fields for addrconf */
1228 1232 if (stateless_arg) {
1229 1233 status = ipadm_set_stateless(ipaddr, stateless);
1230 1234 if (status != IPADM_SUCCESS) {
1231 1235 die("Error in setting stateless option: %s",
1232 1236 ipadm_status2str(status));
1233 1237 }
1234 1238 }
1235 1239 if (stateful_arg) {
1236 1240 status = ipadm_set_stateful(ipaddr, stateful);
1237 1241 if (status != IPADM_SUCCESS) {
1238 1242 die("Error in setting stateful option: %s",
1239 1243 ipadm_status2str(status));
1240 1244 }
1241 1245 }
1242 1246 }
1243 1247
1244 1248 /*
1245 1249 * Creates static, dhcp or addrconf addresses and associates the created
1246 1250 * addresses with the specified address object name.
1247 1251 */
1248 1252 static void
1249 1253 do_create_addr(int argc, char *argv[], const char *use)
1250 1254 {
|
↓ open down ↓ |
604 lines elided |
↑ open up ↑ |
1251 1255 ipadm_status_t status;
1252 1256 int option;
1253 1257 uint32_t flags =
1254 1258 IPADM_OPT_PERSIST|IPADM_OPT_ACTIVE|IPADM_OPT_UP|IPADM_OPT_V46;
1255 1259 char *cp;
1256 1260 char *atype = NULL;
1257 1261 char *static_arg = NULL;
1258 1262 char *addrconf_arg = NULL;
1259 1263 char *interface_id = NULL;
1260 1264 char *wait = NULL;
1265 + char *reqhost = NULL;
1261 1266 boolean_t s_opt = _B_FALSE; /* static addr options */
1262 1267 boolean_t auto_opt = _B_FALSE; /* Addrconf options */
1263 1268 boolean_t dhcp_opt = _B_FALSE; /* dhcp options */
1269 + boolean_t primary_opt = _B_FALSE; /* dhcp primary option */
1264 1270
1265 1271 opterr = 0;
1266 - while ((option = getopt_long(argc, argv, ":T:a:di:p:w:t",
1272 + while ((option = getopt_long(argc, argv, ":1T:a:dh:i:p:w:t",
1267 1273 addr_longopts, NULL)) != -1) {
1268 1274 switch (option) {
1275 + case '1':
1276 + primary_opt = _B_TRUE;
1277 + break;
1269 1278 case 'T':
1270 1279 atype = optarg;
1271 1280 break;
1272 1281 case 'a':
1273 1282 static_arg = optarg;
1274 1283 s_opt = _B_TRUE;
1275 1284 break;
1276 1285 case 'd':
1277 1286 flags &= ~IPADM_OPT_UP;
1278 1287 s_opt = _B_TRUE;
1279 1288 break;
1289 + case 'h':
1290 + reqhost = optarg;
1291 + break;
1280 1292 case 'i':
1281 1293 interface_id = optarg;
1282 1294 auto_opt = _B_TRUE;
1283 1295 break;
1284 1296 case 'p':
1285 1297 addrconf_arg = optarg;
1286 1298 auto_opt = _B_TRUE;
1287 1299 break;
1288 1300 case 'w':
1289 1301 wait = optarg;
1290 1302 dhcp_opt = _B_TRUE;
1291 1303 break;
1292 1304 case 't':
1293 1305 flags &= ~IPADM_OPT_PERSIST;
1294 1306 break;
1295 1307 default:
1296 1308 die_opterr(optopt, option, use);
1297 1309 }
1298 1310 }
1299 1311 if (atype == NULL || optind != (argc - 1)) {
1300 1312 die("Invalid arguments\nusage: %s", use);
|
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
1301 1313 } else if ((cp = strchr(argv[optind], '/')) == NULL ||
1302 1314 strlen(++cp) == 0) {
1303 1315 die("invalid address object name: %s\nusage: %s",
1304 1316 argv[optind], use);
1305 1317 }
1306 1318
1307 1319 /*
1308 1320 * Allocate and initialize the addrobj based on the address type.
1309 1321 */
1310 1322 if (strcmp(atype, "static") == 0) {
1311 - if (static_arg == NULL || auto_opt || dhcp_opt) {
1323 + if (static_arg == NULL || auto_opt || dhcp_opt
1324 + || reqhost != NULL || primary_opt) {
1312 1325 die("Invalid arguments for type %s\nusage: %s",
1313 1326 atype, use);
1314 1327 }
1315 1328 process_static_addrargs(use, static_arg, argv[optind]);
1316 1329 } else if (strcmp(atype, "dhcp") == 0) {
1317 1330 if (auto_opt || s_opt) {
1318 1331 die("Invalid arguments for type %s\nusage: %s",
1319 1332 atype, use);
1320 1333 }
1321 1334
1322 1335 /* Initialize the addrobj for dhcp addresses. */
1323 1336 status = ipadm_create_addrobj(IPADM_ADDR_DHCP, argv[optind],
1324 1337 &ipaddr);
1325 1338 if (status != IPADM_SUCCESS) {
1326 1339 die("Error in creating address object: %s",
1327 1340 ipadm_status2str(status));
1328 1341 }
1329 1342 if (wait != NULL) {
1330 1343 int32_t ipadm_wait;
1331 1344
1332 1345 if (strcmp(wait, "forever") == 0) {
1333 1346 ipadm_wait = IPADM_DHCP_WAIT_FOREVER;
1334 1347 } else {
1335 1348 char *end;
1336 1349 long timeout = strtol(wait, &end, 10);
1337 1350
|
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
1338 1351 if (*end != '\0' || timeout < 0)
1339 1352 die("Invalid argument");
1340 1353 ipadm_wait = (int32_t)timeout;
1341 1354 }
1342 1355 status = ipadm_set_wait_time(ipaddr, ipadm_wait);
1343 1356 if (status != IPADM_SUCCESS) {
1344 1357 die("Error in setting wait time: %s",
1345 1358 ipadm_status2str(status));
1346 1359 }
1347 1360 }
1361 + if (primary_opt) {
1362 + status = ipadm_set_primary(ipaddr, _B_TRUE);
1363 + if (status != IPADM_SUCCESS) {
1364 + die("Error in setting primary flag: %s",
1365 + ipadm_status2str(status));
1366 + }
1367 + }
1368 + if (reqhost != NULL) {
1369 + status = ipadm_set_reqhost(ipaddr, reqhost);
1370 + if (status != IPADM_SUCCESS) {
1371 + die("Error in setting reqhost: %s",
1372 + ipadm_status2str(status));
1373 + }
1374 + }
1348 1375 } else if (strcmp(atype, "addrconf") == 0) {
1349 - if (dhcp_opt || s_opt) {
1376 + if (dhcp_opt || s_opt || reqhost != NULL || primary_opt) {
1350 1377 die("Invalid arguments for type %s\nusage: %s",
1351 1378 atype, use);
1352 1379 }
1353 1380
1354 - /* Initialize the addrobj for dhcp addresses. */
1381 + /* Initialize the addrobj for ipv6-addrconf addresses. */
1355 1382 status = ipadm_create_addrobj(IPADM_ADDR_IPV6_ADDRCONF,
1356 1383 argv[optind], &ipaddr);
1357 1384 if (status != IPADM_SUCCESS) {
1358 1385 die("Error in creating address object: %s",
1359 1386 ipadm_status2str(status));
1360 1387 }
1361 1388 if (interface_id != NULL) {
1362 1389 status = ipadm_set_interface_id(ipaddr, interface_id);
1363 1390 if (status != IPADM_SUCCESS) {
1364 1391 die("Error in setting interface ID: %s",
1365 1392 ipadm_status2str(status));
1366 1393 }
1367 1394 }
1368 1395 if (addrconf_arg)
1369 1396 process_addrconf_addrargs(use, addrconf_arg);
1370 1397 } else {
1371 1398 die("Invalid address type %s", atype);
1372 1399 }
1373 1400
1374 1401 status = ipadm_create_addr(iph, ipaddr, flags);
1375 1402 if (status == IPADM_DHCP_IPC_TIMEOUT)
1376 1403 warn_ipadmerr(status, "");
1377 1404 else if (status != IPADM_SUCCESS)
1378 1405 die("Could not create address: %s", ipadm_status2str(status));
1379 1406 }
1380 1407
1381 1408 /*
1382 1409 * Used by some address management functions to parse the command line
1383 1410 * arguments and create `ipaddr' address object.
1384 1411 */
1385 1412 static void
1386 1413 process_misc_addrargs(int argc, char *argv[], const char *use, int *index,
1387 1414 uint32_t *flags)
1388 1415 {
1389 1416 int option;
1390 1417
1391 1418 opterr = 0;
1392 1419 while ((option = getopt_long(argc, argv, ":t", addr_misc_longopts,
1393 1420 NULL)) != -1) {
1394 1421 switch (option) {
1395 1422 case 't':
1396 1423 *flags &= ~IPADM_OPT_PERSIST;
1397 1424 break;
1398 1425 default:
1399 1426 die_opterr(optopt, option, use);
1400 1427 }
1401 1428 }
1402 1429 if (optind != (argc - 1))
1403 1430 die("Usage: %s", use);
1404 1431
1405 1432 *index = optind;
1406 1433 }
1407 1434
1408 1435 /*
1409 1436 * Remove an addrobj from both active and persistent configuration.
1410 1437 */
1411 1438 static void
1412 1439 do_delete_addr(int argc, char *argv[], const char *use)
1413 1440 {
1414 1441 ipadm_status_t status;
1415 1442 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1416 1443 int option;
1417 1444
1418 1445 opterr = 0;
1419 1446 while ((option = getopt_long(argc, argv, ":r", addr_misc_longopts,
1420 1447 NULL)) != -1) {
1421 1448 switch (option) {
1422 1449 case 'r':
1423 1450 flags |= IPADM_OPT_RELEASE;
1424 1451 break;
1425 1452 default:
1426 1453 die_opterr(optopt, option, use);
1427 1454 }
1428 1455 }
1429 1456 if (optind != (argc - 1))
1430 1457 die("Usage: %s", use);
1431 1458
1432 1459 status = ipadm_delete_addr(iph, argv[optind], flags);
1433 1460 if (status != IPADM_SUCCESS) {
1434 1461 die("could not delete address: %s",
1435 1462 ipadm_status2str(status));
1436 1463 }
1437 1464 }
1438 1465
1439 1466 /*
1440 1467 * Enable an IP address based on the persistent configuration for that
1441 1468 * IP address
1442 1469 */
1443 1470 static void
1444 1471 do_enable_addr(int argc, char *argv[], const char *use)
1445 1472 {
1446 1473 ipadm_status_t status;
1447 1474 int index;
1448 1475 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1449 1476
1450 1477 process_misc_addrargs(argc, argv, use, &index, &flags);
1451 1478 if (flags & IPADM_OPT_PERSIST)
1452 1479 die("persistent operation not supported for enable-addr");
1453 1480
1454 1481 status = ipadm_enable_addr(iph, argv[index], flags);
1455 1482 if (status != IPADM_SUCCESS)
1456 1483 die("could not enable address: %s", ipadm_status2str(status));
1457 1484 }
1458 1485
1459 1486 /*
1460 1487 * Mark the address identified by addrobj 'up'
1461 1488 */
1462 1489 static void
1463 1490 do_up_addr(int argc, char *argv[], const char *use)
1464 1491 {
1465 1492 ipadm_status_t status;
1466 1493 int index;
1467 1494 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1468 1495
1469 1496 process_misc_addrargs(argc, argv, use, &index, &flags);
1470 1497 status = ipadm_up_addr(iph, argv[index], flags);
1471 1498 if (status != IPADM_SUCCESS) {
1472 1499 die("Could not mark the address up: %s",
1473 1500 ipadm_status2str(status));
1474 1501 }
1475 1502 }
1476 1503
1477 1504 /*
1478 1505 * Disable the specified addrobj by removing it from active cofiguration
1479 1506 */
1480 1507 static void
1481 1508 do_disable_addr(int argc, char *argv[], const char *use)
1482 1509 {
1483 1510 ipadm_status_t status;
1484 1511 int index;
1485 1512 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1486 1513
1487 1514 process_misc_addrargs(argc, argv, use, &index, &flags);
1488 1515 if (flags & IPADM_OPT_PERSIST)
1489 1516 die("persistent operation not supported for disable-addr");
1490 1517
1491 1518 status = ipadm_disable_addr(iph, argv[index], flags);
1492 1519 if (status != IPADM_SUCCESS) {
1493 1520 die("could not disable address: %s",
1494 1521 ipadm_status2str(status));
1495 1522 }
1496 1523 }
1497 1524
1498 1525 /*
1499 1526 * Mark the address identified by addrobj 'down'
1500 1527 */
1501 1528 static void
1502 1529 do_down_addr(int argc, char *argv[], const char *use)
1503 1530 {
1504 1531 ipadm_status_t status;
1505 1532 int index;
1506 1533 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1507 1534
1508 1535 process_misc_addrargs(argc, argv, use, &index, &flags);
1509 1536 status = ipadm_down_addr(iph, argv[index], flags);
1510 1537 if (status != IPADM_SUCCESS)
1511 1538 die("Could not mark the address down: %s",
1512 1539 ipadm_status2str(status));
1513 1540 }
1514 1541
1515 1542 /*
1516 1543 * Restart DAD for static address. Extend lease duration for DHCP addresses
1517 1544 */
1518 1545 static void
1519 1546 do_refresh_addr(int argc, char *argv[], const char *use)
1520 1547 {
1521 1548 ipadm_status_t status;
1522 1549 int option;
1523 1550 uint32_t flags = 0;
1524 1551
1525 1552 opterr = 0;
1526 1553 while ((option = getopt_long(argc, argv, ":i", addr_misc_longopts,
1527 1554 NULL)) != -1) {
1528 1555 switch (option) {
1529 1556 case 'i':
1530 1557 flags |= IPADM_OPT_INFORM;
1531 1558 break;
1532 1559 default:
1533 1560 die_opterr(optopt, option, use);
1534 1561 }
1535 1562 }
1536 1563 if (optind != (argc - 1))
1537 1564 die("Usage: %s", use);
1538 1565
1539 1566 status = ipadm_refresh_addr(iph, argv[optind], flags);
1540 1567 if (status == IPADM_DHCP_IPC_TIMEOUT)
1541 1568 warn_ipadmerr(status, "");
1542 1569 else if (status != IPADM_SUCCESS)
1543 1570 die("could not refresh address %s", ipadm_status2str(status));
1544 1571 }
1545 1572
1546 1573 static void
1547 1574 sockaddr2str(const struct sockaddr_storage *ssp, char *buf, uint_t bufsize)
1548 1575 {
1549 1576 socklen_t socklen;
1550 1577 struct sockaddr *sp = (struct sockaddr *)ssp;
1551 1578
1552 1579 switch (ssp->ss_family) {
1553 1580 case AF_INET:
1554 1581 socklen = sizeof (struct sockaddr_in);
1555 1582 break;
1556 1583 case AF_INET6:
1557 1584 socklen = sizeof (struct sockaddr_in6);
1558 1585 break;
1559 1586 default:
1560 1587 (void) strlcpy(buf, STR_UNKNOWN_VAL, bufsize);
1561 1588 return;
1562 1589 }
1563 1590
1564 1591 (void) getnameinfo(sp, socklen, buf, bufsize, NULL, 0,
1565 1592 (NI_NOFQDN | NI_NUMERICHOST));
1566 1593 }
1567 1594
1568 1595 static void
1569 1596 flags2str(uint64_t flags, fmask_t *tbl, boolean_t is_bits,
1570 1597 char *buf, uint_t bufsize)
1571 1598 {
1572 1599 int i;
1573 1600 boolean_t first = _B_TRUE;
1574 1601
1575 1602 if (is_bits) {
1576 1603 for (i = 0; tbl[i].name; i++) {
1577 1604 if ((flags & tbl[i].mask) == tbl[i].bits)
1578 1605 (void) strlcat(buf, tbl[i].name, bufsize);
1579 1606 else
1580 1607 (void) strlcat(buf, "-", bufsize);
1581 1608 }
1582 1609 } else {
1583 1610 for (i = 0; tbl[i].name; i++) {
1584 1611 if ((flags & tbl[i].mask) == tbl[i].bits) {
1585 1612 if (!first)
1586 1613 (void) strlcat(buf, ",", bufsize);
1587 1614 (void) strlcat(buf, tbl[i].name, bufsize);
1588 1615 first = _B_FALSE;
1589 1616 }
1590 1617 }
1591 1618 }
1592 1619 }
1593 1620
1594 1621 /*
1595 1622 * return true if the address for lifname comes to us from the global zone
1596 1623 * with 'allowed-ips' constraints.
1597 1624 */
1598 1625 static boolean_t
1599 1626 is_from_gz(const char *lifname)
1600 1627 {
1601 1628 ipadm_if_info_t *if_info;
1602 1629 char phyname[LIFNAMSIZ], *cp;
1603 1630 boolean_t ret = _B_FALSE;
1604 1631 ipadm_status_t status;
1605 1632 zoneid_t zoneid;
1606 1633 ushort_t zflags;
1607 1634
1608 1635 if ((zoneid = getzoneid()) == GLOBAL_ZONEID)
1609 1636 return (_B_FALSE); /* from-gz only makes sense in a NGZ */
1610 1637
1611 1638 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &zflags, sizeof (zflags)) < 0)
1612 1639 return (_B_FALSE);
1613 1640
1614 1641 if (!(zflags & ZF_NET_EXCL))
1615 1642 return (_B_TRUE); /* everything is from the GZ for shared-ip */
1616 1643
1617 1644 (void) strncpy(phyname, lifname, sizeof (phyname));
1618 1645 if ((cp = strchr(phyname, ':')) != NULL)
1619 1646 *cp = '\0';
1620 1647 status = ipadm_if_info(iph, phyname, &if_info, 0, LIFC_DEFAULT);
1621 1648 if (status != IPADM_SUCCESS)
1622 1649 return (ret);
1623 1650
1624 1651 if (if_info->ifi_cflags & IFIF_L3PROTECT)
1625 1652 ret = _B_TRUE;
1626 1653 if (if_info)
1627 1654 ipadm_free_if_info(if_info);
1628 1655 return (ret);
1629 1656 }
1630 1657
1631 1658 static boolean_t
1632 1659 print_sa_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
1633 1660 {
1634 1661 show_addr_args_t *arg = ofarg->ofmt_cbarg;
1635 1662 ipadm_addr_info_t *ainfo = arg->sa_info;
1636 1663 char interface[LIFNAMSIZ];
1637 1664 char addrbuf[MAXPROPVALLEN];
1638 1665 char dstbuf[MAXPROPVALLEN];
1639 1666 char prefixlenstr[MAXPROPVALLEN];
1640 1667 int prefixlen;
1641 1668 struct sockaddr_in *sin;
1642 1669 struct sockaddr_in6 *sin6;
1643 1670 sa_family_t af;
1644 1671 char *phyname = NULL;
1645 1672 struct ifaddrs *ifa = &ainfo->ia_ifa;
1646 1673 fmask_t cflags_mask[] = {
1647 1674 { "U", IA_UP, IA_UP },
1648 1675 { "u", IA_UNNUMBERED, IA_UNNUMBERED },
1649 1676 { "p", IA_PRIVATE, IA_PRIVATE },
1650 1677 { "t", IA_TEMPORARY, IA_TEMPORARY },
1651 1678 { "d", IA_DEPRECATED, IA_DEPRECATED },
1652 1679 { NULL, 0, 0 }
1653 1680 };
1654 1681 fmask_t pflags_mask[] = {
1655 1682 { "U", IA_UP, IA_UP },
1656 1683 { "p", IA_PRIVATE, IA_PRIVATE },
1657 1684 { "d", IA_DEPRECATED, IA_DEPRECATED },
1658 1685 { NULL, 0, 0 }
1659 1686 };
1660 1687 fmask_t type[] = {
1661 1688 { "static", IPADM_ADDR_STATIC, IPADM_ALL_BITS},
1662 1689 { "addrconf", IPADM_ADDR_IPV6_ADDRCONF, IPADM_ALL_BITS},
1663 1690 { "dhcp", IPADM_ADDR_DHCP, IPADM_ALL_BITS},
1664 1691 { NULL, 0, 0 }
1665 1692 };
1666 1693 fmask_t addr_state[] = {
1667 1694 { "disabled", IFA_DISABLED, IPADM_ALL_BITS},
1668 1695 { "duplicate", IFA_DUPLICATE, IPADM_ALL_BITS},
1669 1696 { "down", IFA_DOWN, IPADM_ALL_BITS},
1670 1697 { "tentative", IFA_TENTATIVE, IPADM_ALL_BITS},
1671 1698 { "ok", IFA_OK, IPADM_ALL_BITS},
1672 1699 { "inaccessible", IFA_INACCESSIBLE, IPADM_ALL_BITS},
1673 1700 { NULL, 0, 0 }
1674 1701 };
1675 1702
1676 1703 buf[0] = '\0';
1677 1704 switch (ofarg->ofmt_id) {
1678 1705 case SA_ADDROBJ:
1679 1706 if (ainfo->ia_aobjname[0] == '\0') {
1680 1707 (void) strncpy(interface, ifa->ifa_name, LIFNAMSIZ);
1681 1708 phyname = strrchr(interface, ':');
1682 1709 if (phyname)
1683 1710 *phyname = '\0';
1684 1711 (void) snprintf(buf, bufsize, "%s/%s", interface,
1685 1712 STR_UNKNOWN_VAL);
1686 1713 } else {
1687 1714 (void) snprintf(buf, bufsize, "%s", ainfo->ia_aobjname);
1688 1715 }
1689 1716 break;
1690 1717 case SA_STATE:
1691 1718 flags2str(ainfo->ia_state, addr_state, _B_FALSE,
1692 1719 buf, bufsize);
1693 1720 break;
1694 1721 case SA_TYPE:
1695 1722 if (is_from_gz(ifa->ifa_name))
1696 1723 (void) snprintf(buf, bufsize, "from-gz");
1697 1724 else
1698 1725 flags2str(ainfo->ia_atype, type, _B_FALSE, buf,
1699 1726 bufsize);
1700 1727 break;
1701 1728 case SA_CURRENT:
1702 1729 flags2str(ainfo->ia_cflags, cflags_mask, _B_TRUE, buf, bufsize);
1703 1730 break;
1704 1731 case SA_PERSISTENT:
1705 1732 flags2str(ainfo->ia_pflags, pflags_mask, _B_TRUE, buf, bufsize);
1706 1733 break;
1707 1734 case SA_ADDR:
1708 1735 af = ifa->ifa_addr->sa_family;
1709 1736 /*
1710 1737 * If the address is 0.0.0.0 or :: and the origin is DHCP,
1711 1738 * print STR_UNKNOWN_VAL.
1712 1739 */
1713 1740 if (ainfo->ia_atype == IPADM_ADDR_DHCP) {
1714 1741 sin = (struct sockaddr_in *)ifa->ifa_addr;
1715 1742 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
1716 1743 if ((af == AF_INET &&
1717 1744 sin->sin_addr.s_addr == INADDR_ANY) ||
1718 1745 (af == AF_INET6 &&
1719 1746 IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))) {
1720 1747 (void) snprintf(buf, bufsize, STR_UNKNOWN_VAL);
1721 1748 break;
1722 1749 }
1723 1750 }
1724 1751 if (ifa->ifa_netmask == NULL)
1725 1752 prefixlen = 0;
1726 1753 else
1727 1754 prefixlen = mask2plen(ifa->ifa_netmask);
1728 1755 bzero(prefixlenstr, sizeof (prefixlenstr));
1729 1756 if (prefixlen > 0) {
1730 1757 (void) snprintf(prefixlenstr, sizeof (prefixlenstr),
1731 1758 "/%d", prefixlen);
1732 1759 }
1733 1760 bzero(addrbuf, sizeof (addrbuf));
1734 1761 bzero(dstbuf, sizeof (dstbuf));
1735 1762 if (ainfo->ia_atype == IPADM_ADDR_STATIC) {
1736 1763 /*
1737 1764 * Print the hostname fields if the address is not
1738 1765 * in active configuration.
1739 1766 */
1740 1767 if (ainfo->ia_state == IFA_DISABLED) {
1741 1768 (void) snprintf(buf, bufsize, "%s",
1742 1769 ainfo->ia_sname);
1743 1770 if (ainfo->ia_dname[0] != '\0') {
1744 1771 (void) snprintf(dstbuf, sizeof (dstbuf),
1745 1772 "->%s", ainfo->ia_dname);
1746 1773 (void) strlcat(buf, dstbuf, bufsize);
1747 1774 } else {
1748 1775 (void) strlcat(buf, prefixlenstr,
1749 1776 bufsize);
1750 1777 }
1751 1778 break;
1752 1779 }
1753 1780 }
1754 1781 /*
1755 1782 * For the non-persistent case, we need to show the
1756 1783 * currently configured addresses for source and
1757 1784 * destination.
1758 1785 */
1759 1786 sockaddr2str((struct sockaddr_storage *)ifa->ifa_addr,
1760 1787 addrbuf, sizeof (addrbuf));
1761 1788 if (ifa->ifa_flags & IFF_POINTOPOINT) {
1762 1789 sockaddr2str(
1763 1790 (struct sockaddr_storage *)ifa->ifa_dstaddr,
1764 1791 dstbuf, sizeof (dstbuf));
1765 1792 (void) snprintf(buf, bufsize, "%s->%s", addrbuf,
1766 1793 dstbuf);
1767 1794 } else {
1768 1795 (void) snprintf(buf, bufsize, "%s%s", addrbuf,
1769 1796 prefixlenstr);
1770 1797 }
1771 1798 break;
1772 1799 default:
1773 1800 die("invalid input");
1774 1801 break;
1775 1802 }
1776 1803
1777 1804 return (_B_TRUE);
1778 1805 }
1779 1806
1780 1807 /*
1781 1808 * Display address information, either for the given address or
1782 1809 * for all the addresses managed by ipadm.
1783 1810 */
1784 1811 static void
1785 1812 do_show_addr(int argc, char *argv[], const char *use)
1786 1813 {
1787 1814 ipadm_status_t status;
1788 1815 show_addr_state_t state;
1789 1816 char *def_fields_str = "addrobj,type,state,addr";
1790 1817 char *fields_str = NULL;
1791 1818 ipadm_addr_info_t *ainfo;
1792 1819 ipadm_addr_info_t *ptr;
1793 1820 show_addr_args_t sargs;
1794 1821 int option;
1795 1822 ofmt_handle_t ofmt;
1796 1823 ofmt_status_t oferr;
1797 1824 uint_t ofmtflags = 0;
1798 1825 char *aname;
1799 1826 char *ifname = NULL;
1800 1827 char *cp;
1801 1828 boolean_t found = _B_FALSE;
1802 1829
1803 1830 opterr = 0;
1804 1831 state.sa_parsable = _B_FALSE;
1805 1832 state.sa_persist = _B_FALSE;
1806 1833 while ((option = getopt_long(argc, argv, "po:", show_addr_longopts,
1807 1834 NULL)) != -1) {
1808 1835 switch (option) {
1809 1836 case 'p':
1810 1837 state.sa_parsable = _B_TRUE;
1811 1838 break;
1812 1839 case 'o':
1813 1840 fields_str = optarg;
1814 1841 break;
1815 1842 default:
1816 1843 die_opterr(optopt, option, use);
1817 1844 break;
1818 1845 }
1819 1846 }
1820 1847 if (state.sa_parsable && fields_str == NULL)
1821 1848 die("-p requires -o");
1822 1849
1823 1850 if (optind == argc - 1) {
1824 1851 aname = argv[optind];
1825 1852 if ((cp = strchr(aname, '/')) == NULL)
1826 1853 die("Invalid address object name provided");
1827 1854 if (*(cp + 1) == '\0') {
1828 1855 ifname = aname;
1829 1856 *cp = '\0';
1830 1857 aname = NULL;
1831 1858 }
1832 1859 } else if (optind == argc) {
1833 1860 aname = NULL;
1834 1861 } else {
1835 1862 die("Usage: %s", use);
1836 1863 }
1837 1864
1838 1865 if (state.sa_parsable)
1839 1866 ofmtflags |= OFMT_PARSABLE;
1840 1867 if (fields_str == NULL)
1841 1868 fields_str = def_fields_str;
1842 1869 oferr = ofmt_open(fields_str, show_addr_fields, ofmtflags, 0, &ofmt);
1843 1870
1844 1871 ipadm_ofmt_check(oferr, state.sa_parsable, ofmt);
1845 1872 state.sa_ofmt = ofmt;
1846 1873
1847 1874 status = ipadm_addr_info(iph, ifname, &ainfo, 0, LIFC_DEFAULT);
1848 1875 /*
1849 1876 * Return without printing any error, if no addresses were found,
1850 1877 * for the case where all addresses are requested.
1851 1878 */
1852 1879 if (status != IPADM_SUCCESS)
1853 1880 die("Could not get address: %s", ipadm_status2str(status));
1854 1881 if (ainfo == NULL) {
1855 1882 ofmt_close(ofmt);
1856 1883 return;
1857 1884 }
1858 1885
1859 1886 bzero(&sargs, sizeof (sargs));
1860 1887 sargs.sa_state = &state;
1861 1888 for (ptr = ainfo; ptr != NULL; ptr = IA_NEXT(ptr)) {
1862 1889 sargs.sa_info = ptr;
1863 1890 if (aname != NULL) {
1864 1891 if (strcmp(sargs.sa_info->ia_aobjname, aname) != 0)
1865 1892 continue;
1866 1893 found = _B_TRUE;
1867 1894 }
1868 1895 ofmt_print(state.sa_ofmt, &sargs);
1869 1896 }
1870 1897 if (ainfo)
1871 1898 ipadm_free_addr_info(ainfo);
1872 1899 if (aname != NULL && !found)
1873 1900 die("Address object not found");
1874 1901 }
1875 1902
1876 1903 static boolean_t
1877 1904 print_si_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
1878 1905 {
1879 1906 show_if_args_t *arg = ofarg->ofmt_cbarg;
1880 1907 ipadm_if_info_t *ifinfo = arg->si_info;
1881 1908 char *ifname = ifinfo->ifi_name;
1882 1909 fmask_t intf_state[] = {
1883 1910 { "ok", IFIS_OK, IPADM_ALL_BITS},
1884 1911 { "down", IFIS_DOWN, IPADM_ALL_BITS},
1885 1912 { "disabled", IFIS_DISABLED, IPADM_ALL_BITS},
1886 1913 { "failed", IFIS_FAILED, IPADM_ALL_BITS},
1887 1914 { "offline", IFIS_OFFLINE, IPADM_ALL_BITS},
1888 1915 { NULL, 0, 0 }
1889 1916 };
1890 1917 fmask_t intf_pflags[] = {
1891 1918 { "s", IFIF_STANDBY, IFIF_STANDBY },
1892 1919 { "4", IFIF_IPV4, IFIF_IPV4 },
1893 1920 { "6", IFIF_IPV6, IFIF_IPV6 },
1894 1921 { NULL, 0, 0 }
1895 1922 };
1896 1923 fmask_t intf_cflags[] = {
1897 1924 { "b", IFIF_BROADCAST, IFIF_BROADCAST },
1898 1925 { "m", IFIF_MULTICAST, IFIF_MULTICAST },
1899 1926 { "p", IFIF_POINTOPOINT, IFIF_POINTOPOINT},
1900 1927 { "v", IFIF_VIRTUAL, IFIF_VIRTUAL },
1901 1928 { "I", IFIF_IPMP, IFIF_IPMP },
1902 1929 { "s", IFIF_STANDBY, IFIF_STANDBY },
1903 1930 { "i", IFIF_INACTIVE, IFIF_INACTIVE },
1904 1931 { "V", IFIF_VRRP, IFIF_VRRP },
1905 1932 { "a", IFIF_NOACCEPT, IFIF_NOACCEPT },
1906 1933 { "Z", IFIF_L3PROTECT, IFIF_L3PROTECT },
1907 1934 { "4", IFIF_IPV4, IFIF_IPV4 },
1908 1935 { "6", IFIF_IPV6, IFIF_IPV6 },
1909 1936 { NULL, 0, 0 }
1910 1937 };
1911 1938
1912 1939 buf[0] = '\0';
1913 1940 switch (ofarg->ofmt_id) {
1914 1941 case SI_IFNAME:
1915 1942 (void) snprintf(buf, bufsize, "%s", ifname);
1916 1943 break;
1917 1944 case SI_STATE:
1918 1945 flags2str(ifinfo->ifi_state, intf_state, _B_FALSE,
1919 1946 buf, bufsize);
1920 1947 break;
1921 1948 case SI_CURRENT:
1922 1949 flags2str(ifinfo->ifi_cflags, intf_cflags, _B_TRUE,
1923 1950 buf, bufsize);
1924 1951 break;
1925 1952 case SI_PERSISTENT:
1926 1953 flags2str(ifinfo->ifi_pflags, intf_pflags, _B_TRUE,
1927 1954 buf, bufsize);
1928 1955 break;
1929 1956 default:
1930 1957 die("invalid input");
1931 1958 break;
1932 1959 }
1933 1960
1934 1961 return (_B_TRUE);
1935 1962 }
1936 1963
1937 1964 /*
1938 1965 * Display interface information, either for the given interface or
1939 1966 * for all the interfaces in the system.
1940 1967 */
1941 1968 static void
1942 1969 do_show_if(int argc, char *argv[], const char *use)
1943 1970 {
1944 1971 ipadm_status_t status;
1945 1972 show_if_state_t state;
1946 1973 char *fields_str = NULL;
1947 1974 ipadm_if_info_t *if_info, *ptr;
1948 1975 show_if_args_t sargs;
1949 1976 int option;
1950 1977 ofmt_handle_t ofmt;
1951 1978 ofmt_status_t oferr;
1952 1979 uint_t ofmtflags = 0;
1953 1980 char *ifname = NULL;
1954 1981
1955 1982 opterr = 0;
1956 1983 state.si_parsable = _B_FALSE;
1957 1984
1958 1985 while ((option = getopt_long(argc, argv, "po:", show_if_longopts,
1959 1986 NULL)) != -1) {
1960 1987 switch (option) {
1961 1988 case 'p':
1962 1989 state.si_parsable = _B_TRUE;
1963 1990 break;
1964 1991 case 'o':
1965 1992 fields_str = optarg;
1966 1993 break;
1967 1994 default:
1968 1995 die_opterr(optopt, option, use);
1969 1996 break;
1970 1997 }
1971 1998 }
1972 1999 if (optind == argc - 1)
1973 2000 ifname = argv[optind];
1974 2001 else if (optind != argc)
1975 2002 die("Usage: %s", use);
1976 2003 if (state.si_parsable)
1977 2004 ofmtflags |= OFMT_PARSABLE;
1978 2005 oferr = ofmt_open(fields_str, show_if_fields, ofmtflags, 0, &ofmt);
1979 2006 ipadm_ofmt_check(oferr, state.si_parsable, ofmt);
1980 2007 state.si_ofmt = ofmt;
1981 2008 bzero(&sargs, sizeof (sargs));
1982 2009 sargs.si_state = &state;
1983 2010 status = ipadm_if_info(iph, ifname, &if_info, 0, LIFC_DEFAULT);
1984 2011 /*
1985 2012 * Return without printing any error, if no addresses were found.
1986 2013 */
1987 2014 if (status != IPADM_SUCCESS) {
1988 2015 die("Could not get interface(s): %s",
1989 2016 ipadm_status2str(status));
1990 2017 }
1991 2018
1992 2019 for (ptr = if_info; ptr; ptr = ptr->ifi_next) {
1993 2020 sargs.si_info = ptr;
1994 2021 ofmt_print(state.si_ofmt, &sargs);
1995 2022 }
1996 2023 if (if_info)
1997 2024 ipadm_free_if_info(if_info);
1998 2025 }
1999 2026
2000 2027 /*
2001 2028 * set/reset the address property for a given address
2002 2029 */
2003 2030 static void
2004 2031 set_addrprop(int argc, char **argv, boolean_t reset, const char *use)
2005 2032 {
2006 2033 int option;
2007 2034 ipadm_status_t status = IPADM_SUCCESS;
2008 2035 boolean_t p_arg = _B_FALSE;
2009 2036 char *nv, *aobjname;
2010 2037 char *prop_name, *prop_val;
2011 2038 uint_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
2012 2039
2013 2040 opterr = 0;
2014 2041 while ((option = getopt_long(argc, argv, ":i:p:t", set_ifprop_longopts,
2015 2042 NULL)) != -1) {
2016 2043 switch (option) {
2017 2044 case 'p':
2018 2045 if (p_arg)
2019 2046 die("-p must be specified once only");
2020 2047 p_arg = _B_TRUE;
2021 2048
2022 2049 ipadm_check_propstr(optarg, reset, use);
2023 2050 nv = optarg;
2024 2051 break;
2025 2052 case 't':
2026 2053 flags &= ~IPADM_OPT_PERSIST;
2027 2054 break;
2028 2055 default:
2029 2056 die_opterr(optopt, option, use);
2030 2057 }
2031 2058 }
2032 2059
2033 2060 if (!p_arg || optind != (argc - 1))
2034 2061 die("Usage: %s", use);
2035 2062
2036 2063 prop_name = nv;
2037 2064 prop_val = strchr(nv, '=');
2038 2065 if (prop_val != NULL)
2039 2066 *prop_val++ = '\0';
2040 2067 aobjname = argv[optind];
2041 2068 if (reset)
2042 2069 flags |= IPADM_OPT_DEFAULT;
2043 2070 status = ipadm_set_addrprop(iph, prop_name, prop_val, aobjname, flags);
2044 2071 if (status != IPADM_SUCCESS) {
2045 2072 if (reset)
2046 2073 die("reset-addrprop: %s: %s", prop_name,
2047 2074 ipadm_status2str(status));
2048 2075 else
2049 2076 die("set-addrprop: %s: %s", prop_name,
2050 2077 ipadm_status2str(status));
2051 2078 }
2052 2079 }
2053 2080
2054 2081 /*
2055 2082 * Sets a property on an address object.
2056 2083 */
2057 2084 static void
2058 2085 do_set_addrprop(int argc, char **argv, const char *use)
2059 2086 {
2060 2087 set_addrprop(argc, argv, _B_FALSE, use);
2061 2088 }
2062 2089
2063 2090 /*
2064 2091 * Resets a property to its default value on an address object.
2065 2092 */
2066 2093 static void
2067 2094 do_reset_addrprop(int argc, char **argv, const char *use)
2068 2095 {
2069 2096 set_addrprop(argc, argv, _B_TRUE, use);
2070 2097 }
2071 2098
2072 2099 /*
2073 2100 * Display information for all or specific address properties, either for a
2074 2101 * given address or for all the addresses in the system.
2075 2102 */
2076 2103 static void
2077 2104 do_show_addrprop(int argc, char *argv[], const char *use)
2078 2105 {
2079 2106 int option;
2080 2107 nvlist_t *proplist = NULL;
2081 2108 char *fields_str = NULL;
2082 2109 show_prop_state_t state;
2083 2110 ofmt_handle_t ofmt;
2084 2111 ofmt_status_t oferr;
2085 2112 uint_t ofmtflags = 0;
2086 2113 char *aobjname;
2087 2114 char *ifname = NULL;
2088 2115 char *cp;
2089 2116
2090 2117 opterr = 0;
2091 2118 bzero(&state, sizeof (state));
2092 2119 state.sps_propval = NULL;
2093 2120 state.sps_parsable = _B_FALSE;
2094 2121 state.sps_addrprop = _B_TRUE;
2095 2122 state.sps_proto = MOD_PROTO_NONE;
2096 2123 state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
2097 2124 while ((option = getopt_long(argc, argv, ":p:i:cPo:",
2098 2125 show_prop_longopts, NULL)) != -1) {
2099 2126 switch (option) {
2100 2127 case 'p':
2101 2128 if (ipadm_str2nvlist(optarg, &proplist,
2102 2129 IPADM_NORVAL) != 0)
2103 2130 die("invalid interface properties specified");
2104 2131 break;
2105 2132 case 'c':
2106 2133 state.sps_parsable = _B_TRUE;
2107 2134 break;
2108 2135 case 'o':
2109 2136 fields_str = optarg;
2110 2137 break;
2111 2138 default:
2112 2139 die_opterr(optopt, option, use);
2113 2140 break;
2114 2141 }
2115 2142 }
2116 2143 if (optind == argc - 1) {
2117 2144 aobjname = argv[optind];
2118 2145 cp = strchr(aobjname, '/');
2119 2146 if (cp == NULL)
2120 2147 die("Invalid address object name provided");
2121 2148 if (*(cp + 1) == '\0') {
2122 2149 ifname = aobjname;
2123 2150 *cp = '\0';
2124 2151 aobjname = NULL;
2125 2152 }
2126 2153 } else if (optind == argc) {
2127 2154 aobjname = NULL;
2128 2155 } else {
2129 2156 die("Usage: %s", use);
2130 2157 }
2131 2158 state.sps_proplist = proplist;
2132 2159 if (state.sps_parsable)
2133 2160 ofmtflags |= OFMT_PARSABLE;
2134 2161 oferr = ofmt_open(fields_str, addrprop_fields, ofmtflags, 0, &ofmt);
2135 2162 ipadm_ofmt_check(oferr, state.sps_parsable, ofmt);
2136 2163 state.sps_ofmt = ofmt;
2137 2164
2138 2165 if (aobjname != NULL) {
2139 2166 (void) strlcpy(state.sps_aobjname, aobjname,
2140 2167 sizeof (state.sps_aobjname));
2141 2168 show_properties(&state, IPADMPROP_CLASS_ADDR);
2142 2169 } else {
2143 2170 ipadm_addr_info_t *ainfop = NULL;
2144 2171 ipadm_addr_info_t *ptr;
2145 2172 ipadm_status_t status;
2146 2173
2147 2174 status = ipadm_addr_info(iph, ifname, &ainfop, 0, LIFC_DEFAULT);
2148 2175 /*
2149 2176 * Return without printing any error, if no addresses were
2150 2177 * found.
2151 2178 */
2152 2179 if (status == IPADM_NOTFOUND)
2153 2180 return;
2154 2181 if (status != IPADM_SUCCESS) {
2155 2182 die("Error retrieving address: %s",
2156 2183 ipadm_status2str(status));
2157 2184 }
2158 2185 for (ptr = ainfop; ptr; ptr = IA_NEXT(ptr)) {
2159 2186 aobjname = ptr->ia_aobjname;
2160 2187 if (aobjname[0] == '\0' ||
2161 2188 ptr->ia_atype == IPADM_ADDR_IPV6_ADDRCONF) {
2162 2189 continue;
2163 2190 }
2164 2191 (void) strlcpy(state.sps_aobjname, aobjname,
2165 2192 sizeof (state.sps_aobjname));
2166 2193 show_properties(&state, IPADMPROP_CLASS_ADDR);
2167 2194 }
2168 2195 ipadm_free_addr_info(ainfop);
2169 2196 }
2170 2197 nvlist_free(proplist);
2171 2198 ofmt_close(ofmt);
2172 2199 if (state.sps_retstatus != IPADM_SUCCESS) {
2173 2200 ipadm_close(iph);
2174 2201 exit(EXIT_FAILURE);
2175 2202 }
2176 2203 }
2177 2204
2178 2205 static void
2179 2206 ipadm_ofmt_check(ofmt_status_t oferr, boolean_t parsable,
2180 2207 ofmt_handle_t ofmt)
2181 2208 {
2182 2209 char buf[OFMT_BUFSIZE];
2183 2210
2184 2211 if (oferr == OFMT_SUCCESS)
2185 2212 return;
2186 2213 (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
2187 2214 /*
2188 2215 * All errors are considered fatal in parsable mode.
2189 2216 * NOMEM errors are always fatal, regardless of mode.
2190 2217 * For other errors, we print diagnostics in human-readable
2191 2218 * mode and processs what we can.
2192 2219 */
2193 2220 if (parsable || oferr == OFMT_ENOFIELDS) {
2194 2221 ofmt_close(ofmt);
2195 2222 die(buf);
2196 2223 } else {
2197 2224 warn(buf);
2198 2225 }
2199 2226 }
2200 2227
2201 2228 /*
2202 2229 * check if the `pstr' adheres to following syntax
2203 2230 * - prop=<value[,...]> (for set)
2204 2231 * - prop (for reset)
2205 2232 */
2206 2233 static void
2207 2234 ipadm_check_propstr(const char *pstr, boolean_t reset, const char *use)
2208 2235 {
2209 2236 char *nv;
2210 2237
2211 2238 nv = strchr(pstr, '=');
2212 2239 if (reset) {
2213 2240 if (nv != NULL)
2214 2241 die("incorrect syntax used for -p.\n%s", use);
2215 2242 } else {
2216 2243 if (nv == NULL || *++nv == '\0')
2217 2244 die("please specify the value to be set.\n%s", use);
2218 2245 nv = strchr(nv, '=');
2219 2246 /* cannot have multiple 'prop=val' for single -p */
2220 2247 if (nv != NULL)
2221 2248 die("cannot specify more than one prop=val at "
2222 2249 "a time.\n%s", use);
2223 2250 }
2224 2251 }
|
↓ open down ↓ |
860 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX