3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24 /* Copyright (c) 1990 Mentat Inc. */
25
26 #include <inet/ip.h>
27 #include <inet/ip6.h>
28 #include <inet/ip_if.h>
29 #include <inet/ip_ire.h>
30 #include <inet/ipclassifier.h>
31 #include <inet/ip_impl.h>
32 #include <inet/tunables.h>
33 #include <sys/sunddi.h>
34 #include <sys/policy.h>
35
36 /* How long, in seconds, we allow frags to hang around. */
37 #define IP_REASM_TIMEOUT 15
38 #define IPV6_REASM_TIMEOUT 60
39
40 /*
41 * Set ip{,6}_forwarding values. If the value is being set on an ill,
42 * find the ill and set the value on it. On the other hand if we are modifying
43 * global property, modify the global value and set the value on all the ills.
44 */
45 /* ARGSUSED */
46 static int
47 ip_set_forwarding(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
48 const char *ifname, const void* pval, uint_t flags)
49 {
50 char *end;
51 unsigned long new_value;
52 boolean_t per_ill, isv6;
53 ill_walk_context_t ctx;
54 ill_t *ill;
55 ip_stack_t *ipst = (ip_stack_t *)cbarg;
56
57 if (flags & MOD_PROP_DEFAULT) {
58 new_value = pinfo->prop_def_bval;
59 } else {
60 if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
61 *end != '\0')
62 return (EINVAL);
63 if (new_value != B_TRUE && new_value != B_FALSE)
64 return (EINVAL);
65 }
66
67 per_ill = (ifname != NULL && ifname[0] != '\0');
68 /*
69 * if it's not per ill then set the global property and bring all the
70 * ills up to date with the new global value.
71 */
72 if (!per_ill)
73 pinfo->prop_cur_bval = (new_value == 1 ? B_TRUE : B_FALSE);
74
75 isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6 ? B_TRUE : B_FALSE);
77 if (isv6)
78 ill = ILL_START_WALK_V6(&ctx, ipst);
79 else
80 ill = ILL_START_WALK_V4(&ctx, ipst);
81
82 for (; ill != NULL; ill = ill_next(&ctx, ill)) {
83 /*
84 * if the property needs to be set on a particular
85 * interface, look for that interface.
86 */
87 if (per_ill && strcmp(ifname, ill->ill_name) != 0)
88 continue;
89 (void) ill_forward_set(ill, new_value != 0);
90 }
91 rw_exit(&ipst->ips_ill_g_lock);
92
93 return (0);
94 }
95
96 static int
97 ip_get_forwarding(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
98 void *pval, uint_t pr_size, uint_t flags)
99 {
100 boolean_t value;
101 ill_walk_context_t ctx;
102 ill_t *ill;
103 ip_stack_t *ipst = (ip_stack_t *)cbarg;
104 boolean_t get_def = (flags & MOD_PROP_DEFAULT);
105 boolean_t get_perm = (flags & MOD_PROP_PERM);
106 boolean_t isv6;
107 size_t nbytes = 0;
108
109 if (get_perm) {
110 nbytes = snprintf(pval, pr_size, "%d", MOD_PROP_PERM_RW);
111 goto ret;
112 } else if (get_def) {
113 nbytes = snprintf(pval, pr_size, "%d", pinfo->prop_def_bval);
114 goto ret;
115 }
116
117 /*
118 * if per interface value is not asked for return the current
119 * global value
120 */
121 if (ifname == NULL || ifname[0] == '\0') {
122 nbytes = snprintf(pval, pr_size, "%d", pinfo->prop_cur_bval);
123 goto ret;
139 }
140 if (ill == NULL) {
141 rw_exit(&ipst->ips_ill_g_lock);
142 return (ENXIO);
143 }
144 value = ((ill->ill_flags & ILLF_ROUTER) ? B_TRUE : B_FALSE);
145 rw_exit(&ipst->ips_ill_g_lock);
146 nbytes = snprintf(pval, pr_size, "%d", value);
147 ret:
148 if (nbytes >= pr_size)
149 return (ENOBUFS);
150 return (0);
151 }
152
153 /*
154 * `ip_debug' is a global variable. So, we will be modifying the global
155 * variable here.
156 */
157 /* ARGSUSED */
158 int
159 ip_set_debug(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
160 const char *ifname, const void* pval, uint_t flags)
161 {
162 unsigned long new_value;
163 int err;
164
165 if (cr != NULL && secpolicy_net_config(cr, B_FALSE) != 0)
166 return (EPERM);
167
168 if ((err = mod_uint32_value(pval, pinfo, flags, &new_value)) != 0)
169 return (err);
170 ip_debug = (uint32_t)new_value;
171 return (0);
172 }
173
174 /*
175 * ip_debug is a global property. For default, permission and value range
176 * we retrieve the value from `pinfo'. However for the current value we
177 * retrieve the value from the global variable `ip_debug'
178 */
179 /* ARGSUSED */
180 int
181 ip_get_debug(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
182 void *pval, uint_t psize, uint_t flags)
183 {
184 boolean_t get_def = (flags & MOD_PROP_DEFAULT);
185 boolean_t get_perm = (flags & MOD_PROP_PERM);
186 boolean_t get_range = (flags & MOD_PROP_POSSIBLE);
187 size_t nbytes;
188
189 bzero(pval, psize);
190 if (get_perm)
191 nbytes = snprintf(pval, psize, "%u", MOD_PROP_PERM_RW);
192 else if (get_range)
193 nbytes = snprintf(pval, psize, "%u-%u",
194 pinfo->prop_min_uval, pinfo->prop_max_uval);
195 else if (get_def)
196 nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_uval);
197 else
198 nbytes = snprintf(pval, psize, "%u", ip_debug);
199 if (nbytes >= psize)
200 return (ENOBUFS);
201 return (0);
202 }
203
204 /*
205 * Set the CGTP (multirouting) filtering status. If the status is changed
206 * from active to transparent or from transparent to active, forward the
207 * new status to the filtering module (if loaded).
208 */
209 /* ARGSUSED */
210 static int
211 ip_set_cgtp_filter(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
212 const char *ifname, const void* pval, uint_t flags)
213 {
214 unsigned long new_value;
215 ip_stack_t *ipst = (ip_stack_t *)cbarg;
216 char *end;
217
218 if (flags & MOD_PROP_DEFAULT) {
219 new_value = pinfo->prop_def_bval;
220 } else {
221 if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
222 *end != '\0' || new_value > 1) {
223 return (EINVAL);
224 }
225 }
226 if (!pinfo->prop_cur_bval && new_value) {
227 cmn_err(CE_NOTE, "IP: enabling CGTP filtering%s",
228 ipst->ips_ip_cgtp_filter_ops == NULL ?
229 " (module not loaded)" : "");
230 }
231 if (pinfo->prop_cur_bval && !new_value) {
232 cmn_err(CE_NOTE, "IP: disabling CGTP filtering%s",
233 ipst->ips_ip_cgtp_filter_ops == NULL ?
234 " (module not loaded)" : "");
235 }
248 }
249
250 /*
251 * Retrieve the default MTU or min-max MTU range for a given interface.
252 *
253 * -- ill_max_frag value tells us the maximum MTU that can be handled by the
254 * datalink. This value is advertised by the driver via DLPI messages
255 * (DL_NOTE_SDU_SIZE/DL_INFO_ACK).
256 *
257 * -- ill_current_frag for the most link-types will be same as ill_max_frag
258 * to begin with. However it is dynamically computed for some link-types
259 * like tunnels, based on the tunnel PMTU.
260 *
261 * -- ill_mtu is the user set MTU using SIOCSLIFMTU and must lie between
262 * (IPV6_MIN_MTU/IP_MIN_MTU) and ill_max_frag.
263 *
264 * -- ill_user_mtu is set by in.ndpd using SIOCSLIFLNKINFO and must lie between
265 * (IPV6_MIN_MTU/IP_MIN_MTU) and ill_max_frag.
266 */
267 int
268 ip_get_mtu(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
269 void *pval, uint_t psize, uint_t flags)
270 {
271 ill_walk_context_t ctx;
272 ill_t *ill;
273 ip_stack_t *ipst = (ip_stack_t *)cbarg;
274 boolean_t isv6;
275 uint32_t max_mtu, def_mtu;
276 size_t nbytes = 0;
277
278 if (!(flags & (MOD_PROP_DEFAULT|MOD_PROP_POSSIBLE)))
279 return (ENOTSUP);
280
281 if (ifname == NULL || ifname[0] == '\0')
282 return (ENOTSUP);
283
284 isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6 ? B_TRUE : B_FALSE);
285 rw_enter(&ipst->ips_ill_g_lock, RW_READER);
286 if (isv6)
287 ill = ILL_START_WALK_V6(&ctx, ipst);
288 else
289 ill = ILL_START_WALK_V4(&ctx, ipst);
290 for (; ill != NULL; ill = ill_next(&ctx, ill)) {
291 if (strcmp(ifname, ill->ill_name) == 0)
292 break;
293 }
335 } else if (new_value == 0) {
336 ire_walk_v4(ip_ire_unbind_walker, NULL,
337 ALL_ZONES, ipst);
338 }
339 ipcl_walk(conn_ire_revalidate, (void *)B_FALSE, ipst);
340 } else {
341 if (old_value == 0) {
342 ire_walk_v6(ip_ire_rebind_walker, NULL,
343 ALL_ZONES, ipst);
344 } else if (new_value == 0) {
345 ire_walk_v6(ip_ire_unbind_walker, NULL,
346 ALL_ZONES, ipst);
347 }
348 ipcl_walk(conn_ire_revalidate, (void *)B_TRUE, ipst);
349 }
350 }
351 }
352
353 /* ARGSUSED */
354 static int
355 ip_set_src_multihoming(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
356 const char *ifname, const void* pval, uint_t flags)
357 {
358 unsigned long new_value, old_value;
359 boolean_t isv6;
360 ip_stack_t *ipst = (ip_stack_t *)cbarg;
361 int err;
362
363 old_value = pinfo->prop_cur_uval;
364
365 if ((err = mod_uint32_value(pval, pinfo, flags, &new_value)) != 0)
366 return (err);
367 pinfo->prop_cur_uval = new_value;
368 isv6 = (strcmp(pinfo->mpi_name, "ip6_strict_src_multihoming") == 0);
369 ip_set_src_multihoming_common(new_value, old_value, isv6, ipst);
370 return (0);
371 }
372
373
374 /* ARGSUSED */
375 static int
376 ip_set_hostmodel(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
377 const char *ifname, const void* pval, uint_t flags)
378 {
379 ip_hostmodel_t new_value, old_value;
380 ip_stack_t *ipst = (ip_stack_t *)cbarg;
381 uint32_t old_src_multihoming;
382 int err;
383 ulong_t tmp;
384 boolean_t isv6;
385
386 old_value = pinfo->prop_cur_uval;
387
388 if ((err = mod_uint32_value(pval, pinfo, flags, &tmp)) != 0)
389 return (err);
390 new_value = tmp;
391 pinfo->prop_cur_uval = new_value;
392
393 switch (old_value) {
394 case IP_WEAK_ES:
395 old_src_multihoming = 0;
396 break;
397 case IP_SRC_PRI_ES:
398 old_src_multihoming = 1;
399 break;
400 case IP_STRONG_ES:
429 else
430 ipst->ips_ip_strict_dst_multihoming = 0;
431 break;
432 case IP_STRONG_ES:
433 ip_set_src_multihoming_common(2, old_src_multihoming,
434 isv6, ipst);
435 if (isv6)
436 ipst->ips_ipv6_strict_dst_multihoming = 1;
437 else
438 ipst->ips_ip_strict_dst_multihoming = 1;
439 break;
440 default:
441 return (EINVAL);
442 }
443 }
444 return (0);
445 }
446
447 /* ARGSUSED */
448 int
449 ip_get_hostmodel(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
450 void *pval, uint_t psize, uint_t flags)
451 {
452 boolean_t isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6);
453 ip_stack_t *ipst = cbarg;
454 ip_hostmodel_t hostmodel;
455
456 if (psize < sizeof (hostmodel))
457 return (ENOBUFS);
458 bzero(pval, psize);
459 if (!isv6) {
460 if (ipst->ips_ip_strict_src_multihoming == 0 &&
461 ipst->ips_ip_strict_dst_multihoming == 0)
462 hostmodel = IP_WEAK_ES;
463 else if (ipst->ips_ip_strict_src_multihoming == 1 &&
464 ipst->ips_ip_strict_dst_multihoming == 0)
465 hostmodel = IP_SRC_PRI_ES;
466 else if (ipst->ips_ip_strict_src_multihoming == 2 &&
467 ipst->ips_ip_strict_dst_multihoming == 1)
468 hostmodel = IP_STRONG_ES;
469 else
470 hostmodel = IP_MAXVAL_ES;
471 } else {
472 if (ipst->ips_ipv6_strict_src_multihoming == 0 &&
473 ipst->ips_ipv6_strict_dst_multihoming == 0)
|
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2013 by Delphix. All rights reserved.
24 */
25 /* Copyright (c) 1990 Mentat Inc. */
26
27 #include <inet/ip.h>
28 #include <inet/ip6.h>
29 #include <inet/ip_if.h>
30 #include <inet/ip_ire.h>
31 #include <inet/ipclassifier.h>
32 #include <inet/ip_impl.h>
33 #include <inet/tunables.h>
34 #include <sys/sunddi.h>
35 #include <sys/policy.h>
36
37 /* How long, in seconds, we allow frags to hang around. */
38 #define IP_REASM_TIMEOUT 15
39 #define IPV6_REASM_TIMEOUT 60
40
41 /*
42 * Set ip{,6}_forwarding values. If the value is being set on an ill,
43 * find the ill and set the value on it. On the other hand if we are modifying
44 * global property, modify the global value and set the value on all the ills.
45 */
46 /* ARGSUSED */
47 static int
48 ip_set_forwarding(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
49 const char *ifname, const void* pval, uint_t flags)
50 {
51 char *end;
52 unsigned long new_value;
53 boolean_t per_ill, isv6;
54 ill_walk_context_t ctx;
55 ill_t *ill;
56 ip_stack_t *ipst = stack->netstack_ip;
57
58 if (flags & MOD_PROP_DEFAULT) {
59 new_value = pinfo->prop_def_bval;
60 } else {
61 if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
62 *end != '\0')
63 return (EINVAL);
64 if (new_value != B_TRUE && new_value != B_FALSE)
65 return (EINVAL);
66 }
67
68 per_ill = (ifname != NULL && ifname[0] != '\0');
69 /*
70 * if it's not per ill then set the global property and bring all the
71 * ills up to date with the new global value.
72 */
73 if (!per_ill)
74 pinfo->prop_cur_bval = (new_value == 1 ? B_TRUE : B_FALSE);
75
76 isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6 ? B_TRUE : B_FALSE);
78 if (isv6)
79 ill = ILL_START_WALK_V6(&ctx, ipst);
80 else
81 ill = ILL_START_WALK_V4(&ctx, ipst);
82
83 for (; ill != NULL; ill = ill_next(&ctx, ill)) {
84 /*
85 * if the property needs to be set on a particular
86 * interface, look for that interface.
87 */
88 if (per_ill && strcmp(ifname, ill->ill_name) != 0)
89 continue;
90 (void) ill_forward_set(ill, new_value != 0);
91 }
92 rw_exit(&ipst->ips_ill_g_lock);
93
94 return (0);
95 }
96
97 static int
98 ip_get_forwarding(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
99 void *pval, uint_t pr_size, uint_t flags)
100 {
101 boolean_t value;
102 ill_walk_context_t ctx;
103 ill_t *ill;
104 ip_stack_t *ipst = stack->netstack_ip;
105 boolean_t get_def = (flags & MOD_PROP_DEFAULT);
106 boolean_t get_perm = (flags & MOD_PROP_PERM);
107 boolean_t isv6;
108 size_t nbytes = 0;
109
110 if (get_perm) {
111 nbytes = snprintf(pval, pr_size, "%d", MOD_PROP_PERM_RW);
112 goto ret;
113 } else if (get_def) {
114 nbytes = snprintf(pval, pr_size, "%d", pinfo->prop_def_bval);
115 goto ret;
116 }
117
118 /*
119 * if per interface value is not asked for return the current
120 * global value
121 */
122 if (ifname == NULL || ifname[0] == '\0') {
123 nbytes = snprintf(pval, pr_size, "%d", pinfo->prop_cur_bval);
124 goto ret;
140 }
141 if (ill == NULL) {
142 rw_exit(&ipst->ips_ill_g_lock);
143 return (ENXIO);
144 }
145 value = ((ill->ill_flags & ILLF_ROUTER) ? B_TRUE : B_FALSE);
146 rw_exit(&ipst->ips_ill_g_lock);
147 nbytes = snprintf(pval, pr_size, "%d", value);
148 ret:
149 if (nbytes >= pr_size)
150 return (ENOBUFS);
151 return (0);
152 }
153
154 /*
155 * `ip_debug' is a global variable. So, we will be modifying the global
156 * variable here.
157 */
158 /* ARGSUSED */
159 int
160 ip_set_debug(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
161 const char *ifname, const void* pval, uint_t flags)
162 {
163 unsigned long new_value;
164 int err;
165
166 if (cr != NULL && secpolicy_net_config(cr, B_FALSE) != 0)
167 return (EPERM);
168
169 if ((err = mod_uint32_value(pval, pinfo, flags, &new_value)) != 0)
170 return (err);
171 ip_debug = (uint32_t)new_value;
172 return (0);
173 }
174
175 /*
176 * ip_debug is a global property. For default, permission and value range
177 * we retrieve the value from `pinfo'. However for the current value we
178 * retrieve the value from the global variable `ip_debug'
179 */
180 /* ARGSUSED */
181 int
182 ip_get_debug(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
183 void *pval, uint_t psize, uint_t flags)
184 {
185 boolean_t get_def = (flags & MOD_PROP_DEFAULT);
186 boolean_t get_perm = (flags & MOD_PROP_PERM);
187 boolean_t get_range = (flags & MOD_PROP_POSSIBLE);
188 size_t nbytes;
189
190 bzero(pval, psize);
191 if (get_perm)
192 nbytes = snprintf(pval, psize, "%u", MOD_PROP_PERM_RW);
193 else if (get_range)
194 nbytes = snprintf(pval, psize, "%u-%u",
195 pinfo->prop_min_uval, pinfo->prop_max_uval);
196 else if (get_def)
197 nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_uval);
198 else
199 nbytes = snprintf(pval, psize, "%u", ip_debug);
200 if (nbytes >= psize)
201 return (ENOBUFS);
202 return (0);
203 }
204
205 /*
206 * Set the CGTP (multirouting) filtering status. If the status is changed
207 * from active to transparent or from transparent to active, forward the
208 * new status to the filtering module (if loaded).
209 */
210 /* ARGSUSED */
211 static int
212 ip_set_cgtp_filter(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
213 const char *ifname, const void* pval, uint_t flags)
214 {
215 unsigned long new_value;
216 ip_stack_t *ipst = stack->netstack_ip;
217 char *end;
218
219 if (flags & MOD_PROP_DEFAULT) {
220 new_value = pinfo->prop_def_bval;
221 } else {
222 if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
223 *end != '\0' || new_value > 1) {
224 return (EINVAL);
225 }
226 }
227 if (!pinfo->prop_cur_bval && new_value) {
228 cmn_err(CE_NOTE, "IP: enabling CGTP filtering%s",
229 ipst->ips_ip_cgtp_filter_ops == NULL ?
230 " (module not loaded)" : "");
231 }
232 if (pinfo->prop_cur_bval && !new_value) {
233 cmn_err(CE_NOTE, "IP: disabling CGTP filtering%s",
234 ipst->ips_ip_cgtp_filter_ops == NULL ?
235 " (module not loaded)" : "");
236 }
249 }
250
251 /*
252 * Retrieve the default MTU or min-max MTU range for a given interface.
253 *
254 * -- ill_max_frag value tells us the maximum MTU that can be handled by the
255 * datalink. This value is advertised by the driver via DLPI messages
256 * (DL_NOTE_SDU_SIZE/DL_INFO_ACK).
257 *
258 * -- ill_current_frag for the most link-types will be same as ill_max_frag
259 * to begin with. However it is dynamically computed for some link-types
260 * like tunnels, based on the tunnel PMTU.
261 *
262 * -- ill_mtu is the user set MTU using SIOCSLIFMTU and must lie between
263 * (IPV6_MIN_MTU/IP_MIN_MTU) and ill_max_frag.
264 *
265 * -- ill_user_mtu is set by in.ndpd using SIOCSLIFLNKINFO and must lie between
266 * (IPV6_MIN_MTU/IP_MIN_MTU) and ill_max_frag.
267 */
268 int
269 ip_get_mtu(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
270 void *pval, uint_t psize, uint_t flags)
271 {
272 ill_walk_context_t ctx;
273 ill_t *ill;
274 ip_stack_t *ipst = stack->netstack_ip;
275 boolean_t isv6;
276 uint32_t max_mtu, def_mtu;
277 size_t nbytes = 0;
278
279 if (!(flags & (MOD_PROP_DEFAULT|MOD_PROP_POSSIBLE)))
280 return (ENOTSUP);
281
282 if (ifname == NULL || ifname[0] == '\0')
283 return (ENOTSUP);
284
285 isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6 ? B_TRUE : B_FALSE);
286 rw_enter(&ipst->ips_ill_g_lock, RW_READER);
287 if (isv6)
288 ill = ILL_START_WALK_V6(&ctx, ipst);
289 else
290 ill = ILL_START_WALK_V4(&ctx, ipst);
291 for (; ill != NULL; ill = ill_next(&ctx, ill)) {
292 if (strcmp(ifname, ill->ill_name) == 0)
293 break;
294 }
336 } else if (new_value == 0) {
337 ire_walk_v4(ip_ire_unbind_walker, NULL,
338 ALL_ZONES, ipst);
339 }
340 ipcl_walk(conn_ire_revalidate, (void *)B_FALSE, ipst);
341 } else {
342 if (old_value == 0) {
343 ire_walk_v6(ip_ire_rebind_walker, NULL,
344 ALL_ZONES, ipst);
345 } else if (new_value == 0) {
346 ire_walk_v6(ip_ire_unbind_walker, NULL,
347 ALL_ZONES, ipst);
348 }
349 ipcl_walk(conn_ire_revalidate, (void *)B_TRUE, ipst);
350 }
351 }
352 }
353
354 /* ARGSUSED */
355 static int
356 ip_set_src_multihoming(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
357 const char *ifname, const void* pval, uint_t flags)
358 {
359 unsigned long new_value, old_value;
360 boolean_t isv6;
361 ip_stack_t *ipst = stack->netstack_ip;
362 int err;
363
364 old_value = pinfo->prop_cur_uval;
365
366 if ((err = mod_uint32_value(pval, pinfo, flags, &new_value)) != 0)
367 return (err);
368 pinfo->prop_cur_uval = new_value;
369 isv6 = (strcmp(pinfo->mpi_name, "ip6_strict_src_multihoming") == 0);
370 ip_set_src_multihoming_common(new_value, old_value, isv6, ipst);
371 return (0);
372 }
373
374
375 /* ARGSUSED */
376 static int
377 ip_set_hostmodel(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
378 const char *ifname, const void* pval, uint_t flags)
379 {
380 ip_hostmodel_t new_value, old_value;
381 ip_stack_t *ipst = stack->netstack_ip;
382 uint32_t old_src_multihoming;
383 int err;
384 ulong_t tmp;
385 boolean_t isv6;
386
387 old_value = pinfo->prop_cur_uval;
388
389 if ((err = mod_uint32_value(pval, pinfo, flags, &tmp)) != 0)
390 return (err);
391 new_value = tmp;
392 pinfo->prop_cur_uval = new_value;
393
394 switch (old_value) {
395 case IP_WEAK_ES:
396 old_src_multihoming = 0;
397 break;
398 case IP_SRC_PRI_ES:
399 old_src_multihoming = 1;
400 break;
401 case IP_STRONG_ES:
430 else
431 ipst->ips_ip_strict_dst_multihoming = 0;
432 break;
433 case IP_STRONG_ES:
434 ip_set_src_multihoming_common(2, old_src_multihoming,
435 isv6, ipst);
436 if (isv6)
437 ipst->ips_ipv6_strict_dst_multihoming = 1;
438 else
439 ipst->ips_ip_strict_dst_multihoming = 1;
440 break;
441 default:
442 return (EINVAL);
443 }
444 }
445 return (0);
446 }
447
448 /* ARGSUSED */
449 int
450 ip_get_hostmodel(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
451 void *pval, uint_t psize, uint_t flags)
452 {
453 boolean_t isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6);
454 ip_stack_t *ipst = stack->netstack_ip;
455 ip_hostmodel_t hostmodel;
456
457 if (psize < sizeof (hostmodel))
458 return (ENOBUFS);
459 bzero(pval, psize);
460 if (!isv6) {
461 if (ipst->ips_ip_strict_src_multihoming == 0 &&
462 ipst->ips_ip_strict_dst_multihoming == 0)
463 hostmodel = IP_WEAK_ES;
464 else if (ipst->ips_ip_strict_src_multihoming == 1 &&
465 ipst->ips_ip_strict_dst_multihoming == 0)
466 hostmodel = IP_SRC_PRI_ES;
467 else if (ipst->ips_ip_strict_src_multihoming == 2 &&
468 ipst->ips_ip_strict_dst_multihoming == 1)
469 hostmodel = IP_STRONG_ES;
470 else
471 hostmodel = IP_MAXVAL_ES;
472 } else {
473 if (ipst->ips_ipv6_strict_src_multihoming == 0 &&
474 ipst->ips_ipv6_strict_dst_multihoming == 0)
|