Mercurial > illumos > illumos-gate
changeset 3799:271cf3faf99c
6459412 ip_strict_dst_multihoming does not handle multiple i/f with the same ip address
author | ja97890 |
---|---|
date | Mon, 12 Mar 2007 04:15:10 -0700 |
parents | 36499f71540b |
children | 3d29f956e474 |
files | usr/src/uts/common/inet/ip.h usr/src/uts/common/inet/ip/ip.c usr/src/uts/common/inet/ip/ip6.c |
diffstat | 3 files changed, 133 insertions(+), 138 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/inet/ip.h Sat Mar 10 17:17:25 2007 -0800 +++ b/usr/src/uts/common/inet/ip.h Mon Mar 12 04:15:10 2007 -0700 @@ -3191,6 +3191,7 @@ extern void ip_udp_input(queue_t *, mblk_t *, ipha_t *, ire_t *, ill_t *); extern void ip_proto_input(queue_t *, mblk_t *, ipha_t *, ire_t *, ill_t *); extern void ip_rput_other(ipsq_t *, queue_t *, mblk_t *, void *); +extern ire_t *ip_check_multihome(void *, ire_t *, ill_t *); extern void ip_setqinfo(queue_t *, minor_t, boolean_t, ip_stack_t *); extern void ip_trash_ire_reclaim(void *); extern void ip_trash_timer_expire(void *);
--- a/usr/src/uts/common/inet/ip/ip.c Sat Mar 10 17:17:25 2007 -0800 +++ b/usr/src/uts/common/inet/ip/ip.c Mon Mar 12 04:15:10 2007 -0700 @@ -13988,78 +13988,107 @@ return (B_TRUE); } -static boolean_t -ip_rput_notforus(queue_t **qp, mblk_t *mp, ire_t *ire, ill_t *ill) -{ - ill_group_t *ill_group; - ill_group_t *ire_group; - queue_t *q; +ire_t * +ip_check_multihome(void *addr, ire_t *ire, ill_t *ill) +{ + ire_t *new_ire; ill_t *ire_ill; - uint_t ill_ifindex; - ip_stack_t *ipst = ill->ill_ipst; - - q = *qp; - /* - * We need to check to make sure the packet came in - * on the queue associated with the destination IRE. - * Note that for multicast packets and broadcast packets sent to - * a broadcast address which is shared between multiple interfaces - * we should not do this since we just got a random broadcast ire. - */ - if (ire->ire_rfq && ire->ire_type != IRE_BROADCAST) { - boolean_t check_multi = B_TRUE; - - /* - * This packet came in on an interface other than the - * one associated with the destination address. - * "Gateway" it to the appropriate interface here. - * As long as the ills belong to the same group, - * we don't consider them to arriving on the wrong - * interface. Thus, when the switch is doing inbound - * load spreading, we won't drop packets when we - * are doing strict multihoming checks. Note, the - * same holds true for 'usesrc groups' where the - * destination address may belong to another interface - * to allow multipathing to happen - */ - ill_group = ill->ill_group; - ire_ill = (ill_t *)(ire->ire_rfq)->q_ptr; - ill_ifindex = ill->ill_usesrc_ifindex; - ire_group = ire_ill->ill_group; - - /* - * If it's part of the same IPMP group, or if it's a legal - * address on the 'usesrc' interface, then bypass strict - * checks. - */ - if (ill_group != NULL && ill_group == ire_group) { - check_multi = B_FALSE; - } else if (ill_ifindex != 0 && - ill_ifindex == ire_ill->ill_phyint->phyint_ifindex) { - check_multi = B_FALSE; - } - - if (check_multi && - ipst->ips_ip_strict_dst_multihoming && - ((ill->ill_flags & - ire->ire_ipif->ipif_ill->ill_flags & - ILLF_ROUTER) == 0)) { - /* Drop packet */ - BUMP_MIB(ill->ill_ip_mib, ipIfStatsForwProhibits); - freemsg(mp); - return (B_TRUE); - } - - /* - * Change the queue (for non-virtual destination network - * interfaces) and ip_rput_local will be called with the right - * queue - */ - q = ire->ire_rfq; - } - /* Must be broadcast. We'll take it. */ - *qp = q; - return (B_FALSE); + uint_t ifindex; + ip_stack_t *ipst = ill->ill_ipst; + boolean_t strict_check = B_FALSE; + + /* + * This packet came in on an interface other than the one associated + * with the first ire we found for the destination address. We do + * another ire lookup here, using the ingress ill, to see if the + * interface is in an interface group. + * As long as the ills belong to the same group, we don't consider + * them to be arriving on the wrong interface. Thus, if the switch + * is doing inbound load spreading, we won't drop packets when the + * ip*_strict_dst_multihoming switch is on. Note, the same holds true + * for 'usesrc groups' where the destination address may belong to + * another interface to allow multipathing to happen. + * We also need to check for IPIF_UNNUMBERED point2point interfaces + * where the local address may not be unique. In this case we were + * at the mercy of the initial ire cache lookup and the IRE_LOCAL it + * actually returned. The new lookup, which is more specific, should + * only find the IRE_LOCAL associated with the ingress ill if one + * exists. + */ + + if (ire->ire_ipversion == IPV4_VERSION) { + if (ipst->ips_ip_strict_dst_multihoming) + strict_check = B_TRUE; + new_ire = ire_ctable_lookup(*((ipaddr_t *)addr), 0, IRE_LOCAL, + ill->ill_ipif, ALL_ZONES, NULL, + (MATCH_IRE_TYPE|MATCH_IRE_ILL_GROUP), ipst); + } else { + ASSERT(!IN6_IS_ADDR_MULTICAST((in6_addr_t *)addr)); + if (ipst->ips_ipv6_strict_dst_multihoming) + strict_check = B_TRUE; + new_ire = ire_ctable_lookup_v6((in6_addr_t *)addr, NULL, + IRE_LOCAL, ill->ill_ipif, ALL_ZONES, NULL, + (MATCH_IRE_TYPE|MATCH_IRE_ILL_GROUP), ipst); + } + /* + * If the same ire that was returned in ip_input() is found then this + * is an indication that interface groups are in use. The packet + * arrived on a different ill in the group than the one associated with + * the destination address. If a different ire was found then the same + * IP address must be hosted on multiple ills. This is possible with + * unnumbered point2point interfaces. We switch to use this new ire in + * order to have accurate interface statistics. + */ + if (new_ire != NULL) { + if ((new_ire != ire) && (new_ire->ire_rfq != NULL)) { + ire_refrele(ire); + ire = new_ire; + } else { + ire_refrele(new_ire); + } + return (ire); + } else if ((ire->ire_rfq == NULL) && + (ire->ire_ipversion == IPV4_VERSION)) { + /* + * The best match could have been the original ire which + * was created against an IRE_LOCAL on lo0. In the IPv4 case + * the strict multihoming checks are irrelevant as we consider + * local addresses hosted on lo0 to be interface agnostic. We + * only expect a null ire_rfq on IREs which are associated with + * lo0 hence we can return now. + */ + return (ire); + } + + /* + * Chase pointers once and store locally. + */ + ire_ill = (ire->ire_rfq == NULL) ? NULL : + (ill_t *)(ire->ire_rfq->q_ptr); + ifindex = ill->ill_usesrc_ifindex; + + /* + * Check if it's a legal address on the 'usesrc' interface. + */ + if ((ifindex != 0) && (ire_ill != NULL) && + (ifindex == ire_ill->ill_phyint->phyint_ifindex)) { + return (ire); + } + + /* + * If the ip*_strict_dst_multihoming switch is on then we can + * only accept this packet if the interface is marked as routing. + */ + if (!(strict_check)) + return (ire); + + if ((ill->ill_flags & ire->ire_ipif->ipif_ill->ill_flags & + ILLF_ROUTER) != 0) { + return (ire); + } + + ire_refrele(ire); + return (NULL); } ire_t * @@ -15439,10 +15468,25 @@ } local: - /* packet not for us */ - if (ire->ire_rfq != q) { - if (ip_rput_notforus(&q, mp, ire, ill)) + /* + * If the queue in the ire is different to the ingress queue + * then we need to check to see if we can accept the packet. + * Note that for multicast packets and broadcast packets sent + * to a broadcast address which is shared between multiple + * interfaces we should not do this since we just got a random + * broadcast ire. + */ + if ((ire->ire_rfq != q) && (ire->ire_type != IRE_BROADCAST)) { + if ((ire = ip_check_multihome(&ipha->ipha_dst, ire, + ill)) == NULL) { + /* Drop packet */ + BUMP_MIB(ill->ill_ip_mib, + ipIfStatsForwProhibits); + freemsg(mp); continue; + } + if (ire->ire_rfq != NULL) + q = ire->ire_rfq; } switch (ipha->ipha_protocol) {
--- a/usr/src/uts/common/inet/ip/ip6.c Sat Mar 10 17:17:25 2007 -0800 +++ b/usr/src/uts/common/inet/ip/ip6.c Mon Mar 12 04:15:10 2007 -0700 @@ -7245,7 +7245,6 @@ uint_t flags, mblk_t *hada_mp, mblk_t *dl_mp) { ire_t *ire = NULL; - queue_t *rq; ill_t *ill = inill; ill_t *outill; ipif_t *ipif; @@ -7418,7 +7417,6 @@ pr_addr_dbg("ip_rput_data_v6: multicast for us: %s\n", AF_INET6, &ip6h->ip6_dst); } - rq = ill->ill_rq; zoneid = GLOBAL_ZONEID; goto ipv6forus; } @@ -7687,77 +7685,29 @@ IRE_REFRELE(ire); return; } - rq = ire->ire_rfq; /* * Need to put on correct queue for reassembly to find it. * No need to use put() since reassembly has its own locks. * Note: multicast packets and packets destined to addresses * assigned to loopback (ire_rfq is NULL) will be reassembled on - * the arriving ill. - */ - if (rq != q) { - boolean_t check_multi = B_TRUE; - ill_group_t *ill_group = NULL; - ill_group_t *ire_group = NULL; - ill_t *ire_ill = NULL; - uint_t ill_ifindex = ill->ill_usesrc_ifindex; - - /* - * To be quicker, we may wish not to chase pointers - * (ire->ire_ipif->ipif_ill...) and instead store the - * forwarding policy in the ire. An unfortunate side- - * effect of this would be requiring an ire flush whenever - * the ILLF_ROUTER flag changes. For now, chase pointers - * once and store in the boolean no_forward. - */ - no_forward = ((ill->ill_flags & - ire->ire_ipif->ipif_ill->ill_flags & ILLF_ROUTER) == 0); - - ill_group = ill->ill_group; - if (rq != NULL) { - ire_ill = (ill_t *)(rq->q_ptr); - ire_group = ire_ill->ill_group; - } - - /* - * If it's part of the same IPMP group, or if it's a legal - * address on the 'usesrc' interface, then bypass strict - * checks. - */ - if (ill_group != NULL && ill_group == ire_group) { - check_multi = B_FALSE; - } else if (ill_ifindex != 0 && ire_ill != NULL && - ill_ifindex == ire_ill->ill_phyint->phyint_ifindex) { - check_multi = B_FALSE; - } - - ASSERT(!IN6_IS_ADDR_MULTICAST(&ip6h->ip6_dst)); - if (check_multi && ipst->ips_ipv6_strict_dst_multihoming && - no_forward) { - /* - * This packet came in on an interface other than the - * one associated with the destination address - * and we are strict about matches. - * - * As long as the ills belong to the same group, - * we don't consider them to arriving on the wrong - * interface. Thus, when the switch is doing inbound - * load spreading, we won't drop packets when we - * are doing strict multihoming checks. - */ + * the arriving ill. Unlike the IPv4 case, enabling strict + * destination multihoming will prevent accepting packets + * addressed to an IRE_LOCAL on lo0. + */ + if (ire->ire_rfq != q) { + if ((ire = ip_check_multihome(&ip6h->ip6_dst, ire, ill)) + == NULL) { BUMP_MIB(ill->ill_ip_mib, ipIfStatsForwProhibits); freemsg(hada_mp); freemsg(first_mp); - ire_refrele(ire); - return; - } - - if (rq != NULL) - q = rq; - - ill = (ill_t *)q->q_ptr; - ASSERT(ill); + return; + } + if (ire->ire_rfq != NULL) { + q = ire->ire_rfq; + ill = (ill_t *)q->q_ptr; + ASSERT(ill != NULL); + } } zoneid = ire->ire_zoneid;