radix.c revision c793af95640863cd29868fc7c419c5d2496b207b
c793af95640863cd29868fc7c419c5d2496b207bsangeeta/*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Use is subject to license terms.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Copyright (c) 1988, 1989, 1993
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * The Regents of the University of California. All rights reserved.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Redistribution and use in source and binary forms, with or without
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * modification, are permitted provided that the following conditions
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * are met:
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * 1. Redistributions of source code must retain the above copyright
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * notice, this list of conditions and the following disclaimer.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * 2. Redistributions in binary form must reproduce the above copyright
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * notice, this list of conditions and the following disclaimer in the
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * documentation and/or other materials provided with the distribution.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * 4. Neither the name of the University nor the names of its contributors
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * may be used to endorse or promote products derived from this software
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * without specific prior written permission.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * SUCH DAMAGE.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * @(#)radix.c 8.5 (Berkeley) 5/19/95
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * $FreeBSD: /repoman/r/ncvs/src/sys/net/radix.c,v 1.36.2.1 2005/01/31 23:26:23
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * imp Exp $
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#pragma ident "%Z%%M% %I% %E% SMI"
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta/*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Routines to build and maintain radix trees for routing lookups.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#include <sys/types.h>
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#ifndef _RADIX_H_
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#include <sys/param.h>
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#ifdef _KERNEL
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#include <sys/lock.h>
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#include <sys/mutex.h>
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#include <sys/systm.h>
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#include <sys/cmn_err.h>
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#include <assert.h>
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#define ASSERT assert
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#include <stdio.h>
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#include <stdlib.h>
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#include <syslog.h>
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#include <strings.h>
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#endif /* _KERNEL */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#include <net/radix.h>
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#include <inet/ip_ftable.h>
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#endif
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#ifndef _KERNEL
c793af95640863cd29868fc7c419c5d2496b207bsangeetavoid
c793af95640863cd29868fc7c419c5d2496b207bsangeetapanic(const char *str)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta fprintf(stderr, "Panic - %s\n", str);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta abort();
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#endif /* _KERNEL */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic int rn_walktree(struct radix_node_head *, walktree_f_t *, void *);
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic struct radix_node
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *rn_insert(void *, struct radix_node_head *, int *,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node [2]),
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *rn_newpair(void *, int, struct radix_node[2]),
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *rn_search(void *, struct radix_node *),
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *rn_search_m(void *, struct radix_node *, void *),
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *rn_lookup(void *, void *, struct radix_node_head *),
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *rn_match(void *, struct radix_node_head *),
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *rn_match_args(void *, struct radix_node_head *, match_leaf_t *,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void *),
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *rn_addmask(void *, int, int),
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *rn_addroute(void *, void *, struct radix_node_head *,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node [2]),
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *rn_delete(void *, void *, struct radix_node_head *);
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic boolean_t rn_refines(void *, void *);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#define MAX_KEYLEN 16
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic int max_keylen = MAX_KEYLEN;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#ifdef _KERNEL
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic struct kmem_cache *radix_mask_cache; /* for rn_mkfreelist */
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic struct kmem_cache *radix_node_cache;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#else
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic char *radix_mask_cache, *radix_node_cache; /* dummy vars. never inited */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#endif /* _KERNEL */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic struct radix_mask *rn_mkfreelist;
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic struct radix_node_head *mask_rnhead;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta/*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Work area -- the following point to 2 buffers of size max_keylen,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * allocated in this order in a block of memory malloc'ed by rn_init.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * A third buffer of size MAX_KEYLEN is allocated from the stack.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic char *rn_zeros, *rn_ones;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#define MKGet(m) R_Malloc(m, radix_mask_cache, sizeof (struct radix_mask))
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#define MKFree(m) Free(m, radix_mask_cache)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#define rn_masktop (mask_rnhead->rnh_treetop)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic boolean_t rn_lexobetter(void *m_arg, void *n_arg);
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic struct radix_mask *
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rn_new_radix_mask(struct radix_node *tt,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_mask *next);
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic boolean_t
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rn_satisfies_leaf(char *trial, struct radix_node *leaf,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int skip, match_leaf_t *rn_leaf_fn, void *rn_leaf_arg);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#define RN_MATCHF(rn, f, arg) (f == NULL || (*f)((rn), arg))
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta/*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * The data structure for the keys is a radix tree with one way
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * branching removed. The index rn_bit at an internal node n represents a bit
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * position to be tested. The tree is arranged so that all descendants
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * of a node n have keys whose bits all agree up to position rn_bit - 1.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * (We say the index of n is rn_bit.)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * There is at least one descendant which has a one bit at position rn_bit,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * and at least one with a zero there.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * A route is determined by a pair of key and mask. We require that the
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * bit-wise logical and of the key and mask to be the key.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * We define the index of a route associated with the mask to be
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * the first bit number in the mask where 0 occurs (with bit number 0
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * representing the highest order bit).
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * We say a mask is normal if every bit is 0, past the index of the mask.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * If a node n has a descendant (k, m) with index(m) == index(n) == rn_bit,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * and m is a normal mask, then the route applies to every descendant of n.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * If the index(m) < rn_bit, this implies the trailing last few bits of k
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * before bit b are all 0, (and hence consequently true of every descendant
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * of n), so the route applies to all descendants of the node as well.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Similar logic shows that a non-normal mask m such that
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * index(m) <= index(n) could potentially apply to many children of n.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Thus, for each non-host route, we attach its mask to a list at an internal
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * node as high in the tree as we can go.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * The present version of the code makes use of normal routes in short-
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * circuiting an explict mask and compare operation when testing whether
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * a key satisfies a normal route, and also in remembering the unique leaf
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * that governs a subtree.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta/*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Most of the functions in this code assume that the key/mask arguments
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * are sockaddr-like structures, where the first byte is an uchar_t
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * indicating the size of the entire structure.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * To make the assumption more explicit, we use the LEN() macro to access
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * this field. It is safe to pass an expression with side effects
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * to LEN() as the argument is evaluated only once.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#define LEN(x) (*(const uchar_t *)(x))
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta/*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Search a node in the tree matching the key.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic struct radix_node *
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_search(v_arg, head)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void *v_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *head;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t v;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (x = head, v = v_arg; x->rn_bit >= 0; ) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (x->rn_bmask & v[x->rn_offset])
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = x->rn_right;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = x->rn_left;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (x);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta/*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Same as above, but with an additional mask.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic struct radix_node *
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_search_m(v_arg, head, m_arg)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *head;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void *v_arg, *m_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t v = v_arg, m = m_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (x = head; x->rn_bit >= 0; ) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if ((x->rn_bmask & m[x->rn_offset]) &&
c793af95640863cd29868fc7c419c5d2496b207bsangeeta (x->rn_bmask & v[x->rn_offset]))
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = x->rn_right;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = x->rn_left;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (x);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta/*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Returns true if there are no bits set in n_arg that are zero in
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * m_arg and the masks aren't equal. In other words, it returns true
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * when m_arg is a finer-granularity netmask -- it represents a subset
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * of the destinations implied by n_arg.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic boolean_t
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_refines(m_arg, n_arg)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void *m_arg, *n_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t m = m_arg, n = n_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t lim = n + LEN(n), lim2 = lim;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int longer = LEN(n++) - (int)LEN(m++);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta boolean_t masks_are_equal = B_TRUE;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (longer > 0)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta lim -= longer;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta while (n < lim) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (*n & ~(*m))
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (0);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (*n++ != *m++)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta masks_are_equal = B_FALSE;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta while (n < lim2)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (*n++)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (B_FALSE);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (masks_are_equal && (longer < 0))
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (lim2 = m - longer; m < lim2; )
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (*m++)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (B_TRUE);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (!masks_are_equal);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic struct radix_node *
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_lookup(v_arg, m_arg, head)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void *v_arg, *m_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node_head *head;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t netmask = NULL;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (m_arg) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_offset);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (x == NULL)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (NULL);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta netmask = x->rn_key;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = rn_match(v_arg, head);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (x && netmask) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta while (x && x->rn_mask != netmask)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = x->rn_dupedkey;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (x);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta/*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Returns true if address 'trial' has no bits differing from the
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * leaf's key when compared under the leaf's mask. In other words,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * returns true when 'trial' matches leaf.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * In addition, if a rn_leaf_fn is passed in, that is used to find
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * a match on conditions defined by the caller of rn_match. This is
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * used by the kernel ftable to match on IRE_MATCH_* conditions.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic boolean_t
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_satisfies_leaf(trial, leaf, skip, rn_leaf_fn, rn_leaf_arg)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t trial;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *leaf;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int skip;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta match_leaf_t *rn_leaf_fn;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void *rn_leaf_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta char *cplim;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int length = min(LEN(cp), LEN(cp2));
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (cp3 == 0)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cp3 = rn_ones;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta length = min(length, LEN(cp3));
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cplim = cp + length;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cp3 += skip;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cp2 += skip;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (cp += skip; cp < cplim; cp++, cp2++, cp3++)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if ((*cp ^ *cp2) & *cp3)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (B_FALSE);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (RN_MATCHF(leaf, rn_leaf_fn, rn_leaf_arg));
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic struct radix_node *
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_match(v_arg, head)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void *v_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node_head *head;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (rn_match_args(v_arg, head, NULL, NULL));
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic struct radix_node *
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_match_args(v_arg, head, rn_leaf_fn, rn_leaf_arg)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void *v_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node_head *head;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta match_leaf_t *rn_leaf_fn;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void *rn_leaf_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t v = v_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *t = head->rnh_treetop, *x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t cp = v, cp2;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t cplim;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *saved_t, *top = t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int off = t->rn_offset, vlen = LEN(cp), matched_off;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int test, b, rn_bit;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Open code rn_search(v, top) to avoid overhead of extra
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * subroutine call.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (; t->rn_bit >= 0; ) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (t->rn_bmask & cp[t->rn_offset])
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t = t->rn_right;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t = t->rn_left;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * See if we match exactly as a host destination
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * or at least learn how many bits match, for normal mask finesse.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * It doesn't hurt us to limit how many bytes to check
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * to the length of the mask, since if it matches we had a genuine
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * match and the leaf we have is the most specific one anyway;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * if it didn't match with a shorter length it would fail
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * with a long one. This wins big for class B&C netmasks which
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * are probably the most common case...
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (t->rn_mask)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta vlen = LEN(t->rn_mask);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cp += off; cp2 = t->rn_key + off; cplim = v + vlen;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (; cp < cplim; cp++, cp2++)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (*cp != *cp2)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta goto keydiff;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * This extra grot is in case we are explicitly asked
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * to look up the default. Ugh!
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Never return the root node itself, it seems to cause a
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * lot of confusion.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (t->rn_flags & RNF_ROOT)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t = t->rn_dupedkey;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (t == NULL || RN_MATCHF(t, rn_leaf_fn, rn_leaf_arg)) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (t);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta } else {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Although we found an exact match on the key, rn_leaf_fn
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * is looking for some other criteria as well. Continue
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * looking as if the exact match failed.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (t->rn_parent->rn_flags & RNF_ROOT) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /* hit the top. have to give up */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (NULL);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta b = 0;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta goto keeplooking;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeetakeydiff:
c793af95640863cd29868fc7c419c5d2496b207bsangeeta test = (*cp ^ *cp2) & 0xff; /* find first bit that differs */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (b = 7; (test >>= 1) > 0; )
c793af95640863cd29868fc7c419c5d2496b207bsangeeta b--;
c793af95640863cd29868fc7c419c5d2496b207bsangeetakeeplooking:
c793af95640863cd29868fc7c419c5d2496b207bsangeeta matched_off = cp - v;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta b += matched_off << 3;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rn_bit = -1 - b;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * If there is a host route in a duped-key chain, it will be first.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if ((saved_t = t)->rn_mask == 0)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t = t->rn_dupedkey;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (; t != NULL; t = t->rn_dupedkey) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Even if we don't match exactly as a host,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * we may match if the leaf we wound up at is
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * a route to a net.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (t->rn_flags & RNF_NORMAL) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if ((rn_bit <= t->rn_bit) &&
c793af95640863cd29868fc7c419c5d2496b207bsangeeta RN_MATCHF(t, rn_leaf_fn, rn_leaf_arg)) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (t);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta } else if (rn_satisfies_leaf(v, t, matched_off, rn_leaf_fn,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rn_leaf_arg)) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (t);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t = saved_t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /* start searching up the tree */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta do {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_mask *m;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t = t->rn_parent;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta m = t->rn_mklist;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * If non-contiguous masks ever become important
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * we can restore the masking and open coding of
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * the search and satisfaction test and put the
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * calculation of "off" back before the "do".
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta while (m) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (m->rm_flags & RNF_NORMAL) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if ((rn_bit <= m->rm_bit) &&
c793af95640863cd29868fc7c419c5d2496b207bsangeeta RN_MATCHF(m->rm_leaf, rn_leaf_fn,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rn_leaf_arg)) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (m->rm_leaf);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta } else {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta off = min(t->rn_offset, matched_off);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = rn_search_m(v, t, m->rm_mask);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta while (x != NULL && x->rn_mask != m->rm_mask)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = x->rn_dupedkey;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (x && rn_satisfies_leaf(v, x, off,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rn_leaf_fn, rn_leaf_arg)) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (x);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta m = m->rm_mklist;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta } while (t != top);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (0);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta/*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Whenever we add a new leaf to the tree, we also add a parent node,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * so we allocate them as an array of two elements: the first one must be
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * the leaf (see RNTORT() in route.c), the second one is the parent.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * This routine initializes the relevant fields of the nodes, so that
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * the leaf is the left child of the parent node, and both nodes have
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * (almost) all all fields filled as appropriate.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * The function returns a pointer to the parent node.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic struct radix_node *
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_newpair(v, b, nodes)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void *v;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int b;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node nodes[2];
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *tt = nodes, *t = tt + 1;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t->rn_bit = b;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t->rn_bmask = 0x80 >> (b & 7);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t->rn_left = tt;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t->rn_offset = b >> 3;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * t->rn_parent, r->rn_right, tt->rn_mask, tt->rn_dupedkey
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * and tt->rn_bmask must have been zeroed by caller.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_bit = -1;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_key = v;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_parent = t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_flags = t->rn_flags = RNF_ACTIVE;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_mklist = t->rn_mklist = 0;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (t);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic struct radix_node *
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_insert(v_arg, head, dupentry, nodes)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void *v_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node_head *head;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int *dupentry;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node nodes[2];
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t v = v_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *top = head->rnh_treetop;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int head_off = top->rn_offset, vlen = (int)LEN(v);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *t = rn_search(v_arg, top);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t cp = v + head_off;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int b;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *tt;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Find first bit at which v and t->rn_key differ
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t cp2 = t->rn_key + head_off;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int cmp_res;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t cplim = v + vlen;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta while (cp < cplim)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (*cp2++ != *cp++)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta goto on1;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *dupentry = 1;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (t);
c793af95640863cd29868fc7c419c5d2496b207bsangeetaon1:
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *dupentry = 0;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cmp_res = (cp[-1] ^ cp2[-1]) & 0xff;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (b = (cp - v) << 3; cmp_res; b--)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cmp_res >>= 1;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *p, *x = top;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cp = v;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta do {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta p = x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (cp[x->rn_offset] & x->rn_bmask)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = x->rn_right;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = x->rn_left;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta } while (b > (unsigned)x->rn_bit);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /* x->rn_bit < b && x->rn_bit >= 0 */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t = rn_newpair(v_arg, b, nodes);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt = t->rn_left;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if ((cp[p->rn_offset] & p->rn_bmask) == 0)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta p->rn_left = t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta p->rn_right = t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x->rn_parent = t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t->rn_parent = p;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if ((cp[t->rn_offset] & t->rn_bmask) == 0) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t->rn_right = x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta } else {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t->rn_right = tt;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t->rn_left = x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (tt);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic struct radix_node *
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_addmask(n_arg, search, skip)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int search, skip;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void *n_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t netmask = (caddr_t)n_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t cp, cplim;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int b = 0, mlen, j;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int maskduplicated, m0, isnormal;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *saved_x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int last_zeroed = 0;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta char addmask_key[MAX_KEYLEN];
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if ((mlen = LEN(netmask)) > max_keylen)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta mlen = max_keylen;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (skip == 0)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta skip = 1;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (mlen <= skip)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (mask_rnhead->rnh_nodes);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (skip > 1)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta bcopy(rn_ones + 1, addmask_key + 1, skip - 1);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if ((m0 = mlen) > skip)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta bcopy(netmask + skip, addmask_key + skip, mlen - skip);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Trim trailing zeroes.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (cp = addmask_key + mlen; (cp > addmask_key) && cp[-1] == 0; )
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cp--;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta mlen = cp - addmask_key;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (mlen <= skip) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (m0 >= last_zeroed)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta last_zeroed = mlen;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (mask_rnhead->rnh_nodes);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (m0 < last_zeroed)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta bzero(addmask_key + m0, last_zeroed - m0);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *addmask_key = last_zeroed = mlen;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = rn_search(addmask_key, rn_masktop);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (bcmp(addmask_key, x->rn_key, mlen) != 0)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = 0;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (x || search)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (x);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta R_Zalloc(x, radix_node_cache, max_keylen + 2 * sizeof (*x));
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if ((saved_x = x) == 0)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (0);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta netmask = cp = (caddr_t)(x + 2);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta bcopy(addmask_key, cp, mlen);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = rn_insert(cp, mask_rnhead, &maskduplicated, x);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (maskduplicated) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#ifdef _KERNEL
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cmn_err(CE_WARN, "rn_addmask: mask impossibly already in tree");
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta syslog(LOG_ERR, "rn_addmask: mask impossibly already in tree");
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#endif /* _KERNEL */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta Free(saved_x, radix_node_cache);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (x);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Calculate index of mask, and check for normalcy.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * First find the first byte with a 0 bit, then if there are
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * more bits left (remember we already trimmed the trailing 0's),
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * the pattern must be one of those in normal_chars[], or we have
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * a non-contiguous mask.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cplim = netmask + mlen;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta isnormal = 1;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (cp = netmask + skip; (cp < cplim) && *(uchar_t *)cp == 0xff; )
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cp++;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (cp != cplim) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta static uint8_t normal_chars[] = {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (j = 0x80; (j & *cp) != 0; j >>= 1)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta b++;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (*cp != normal_chars[b] || cp != (cplim - 1))
c793af95640863cd29868fc7c419c5d2496b207bsangeeta isnormal = 0;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta b += (cp - netmask) << 3;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x->rn_bit = -1 - b;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (isnormal)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x->rn_flags |= RNF_NORMAL;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (x);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta/* arbitrary ordering for non-contiguous masks */
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic boolean_t
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_lexobetter(m_arg, n_arg)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void *m_arg, *n_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta uchar_t *mp = m_arg, *np = n_arg, *lim;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (LEN(mp) > LEN(np))
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /* not really, but need to check longer one first */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (B_TRUE);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (LEN(mp) == LEN(np))
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (lim = mp + LEN(mp); mp < lim; )
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (*mp++ > *np++)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (B_TRUE);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (B_FALSE);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic struct radix_mask *
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_new_radix_mask(tt, next)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *tt;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_mask *next;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_mask *m;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta MKGet(m);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (m == 0) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#ifndef _KERNEL
c793af95640863cd29868fc7c419c5d2496b207bsangeeta syslog(LOG_ERR, "Mask for route not entered\n");
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#endif /* _KERNEL */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (0);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta bzero(m, sizeof (*m));
c793af95640863cd29868fc7c419c5d2496b207bsangeeta m->rm_bit = tt->rn_bit;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta m->rm_flags = tt->rn_flags;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (tt->rn_flags & RNF_NORMAL)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta m->rm_leaf = tt;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta m->rm_mask = tt->rn_mask;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta m->rm_mklist = next;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_mklist = m;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (m);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic struct radix_node *
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_addroute(v_arg, n_arg, head, treenodes)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void *v_arg, *n_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node_head *head;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node treenodes[2];
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *t, *x = 0, *tt;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *saved_tt, *top = head->rnh_treetop;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta short b = 0, b_leaf = 0;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int keyduplicated;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t mmask;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_mask *m, **mp;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * In dealing with non-contiguous masks, there may be
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * many different routes which have the same mask.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * We will find it useful to have a unique pointer to
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * the mask to speed avoiding duplicate references at
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * nodes and possibly save time in calculating indices.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (netmask) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if ((x = rn_addmask(netmask, 0, top->rn_offset)) == 0)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (0);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta b_leaf = x->rn_bit;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta b = -1 - x->rn_bit;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta netmask = x->rn_key;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Deal with duplicated keys: attach node to previous instance
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (keyduplicated) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (t = tt; tt; t = tt, tt = tt->rn_dupedkey) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (tt->rn_mask == netmask)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (0);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (netmask == 0 ||
c793af95640863cd29868fc7c419c5d2496b207bsangeeta (tt->rn_mask &&
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /* index (netmask) > node */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta ((b_leaf < tt->rn_bit) ||
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rn_refines(netmask, tt->rn_mask) ||
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rn_lexobetter(netmask, tt->rn_mask))))
c793af95640863cd29868fc7c419c5d2496b207bsangeeta break;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * If the mask is not duplicated, we wouldn't
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * find it among possible duplicate key entries
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * anyway, so the above test doesn't hurt.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * We sort the masks for a duplicated key the same way as
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * in a masklist -- most specific to least specific.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * This may require the unfortunate nuisance of relocating
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * the head of the list.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * We also reverse, or doubly link the list through the
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * parent pointer.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (tt == saved_tt) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *xx = x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /* link in at head of list */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta (tt = treenodes)->rn_dupedkey = t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_flags = t->rn_flags;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_parent = x = t->rn_parent;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t->rn_parent = tt; /* parent */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (x->rn_left == t)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x->rn_left = tt;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x->rn_right = tt;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta saved_tt = tt; x = xx;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta } else {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta (tt = treenodes)->rn_dupedkey = t->rn_dupedkey;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t->rn_dupedkey = tt;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /* Set rn_parent value for tt and tt->rn_dupedkey */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_parent = t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (tt->rn_dupedkey)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_dupedkey->rn_parent = tt;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_key = v;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_bit = -1;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_flags = RNF_ACTIVE;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Put mask in tree.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (netmask) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_mask = netmask;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_bit = x->rn_bit;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_flags |= x->rn_flags & RNF_NORMAL;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t = saved_tt->rn_parent;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (keyduplicated)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta goto key_exists;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta b_leaf = -1 - t->rn_bit;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (t->rn_right == saved_tt)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = t->rn_left;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = t->rn_right;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /* Promote general routes from below */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (x->rn_bit < 0) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (mp = &t->rn_mklist; x; x = x->rn_dupedkey)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (x->rn_mask && (x->rn_bit >= b_leaf) && x->rn_mklist == 0) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *mp = m = rn_new_radix_mask(x, 0);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (m)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta mp = &m->rm_mklist;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta } else if (x->rn_mklist) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Skip over masks whose index is > that of new node
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (mp = &x->rn_mklist; (m = *mp) != NULL; mp = &m->rm_mklist)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (m->rm_bit >= b_leaf)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta break;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t->rn_mklist = m; *mp = 0;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeetakey_exists:
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /* Add new route to highest possible ancestor's list */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if ((netmask == 0) || (b > t->rn_bit))
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (tt); /* can't lift at all */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta b_leaf = tt->rn_bit;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta do {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t = t->rn_parent;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta } while (b <= t->rn_bit && x != top);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Search through routes associated with node to
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * insert new route according to index.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Need same criteria as when sorting dupedkeys to avoid
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * double loop on deletion.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (mp = &x->rn_mklist; (m = *mp) != NULL; mp = &m->rm_mklist) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (m->rm_bit < b_leaf)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta continue;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (m->rm_bit > b_leaf)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta break;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (m->rm_flags & RNF_NORMAL) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta mmask = m->rm_leaf->rn_mask;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (tt->rn_flags & RNF_NORMAL) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#ifdef _KERNEL
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cmn_err(CE_WARN, "Non-unique normal route, "
c793af95640863cd29868fc7c419c5d2496b207bsangeeta "mask not entered\n");
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta syslog(LOG_ERR, "Non-unique normal route, "
c793af95640863cd29868fc7c419c5d2496b207bsangeeta "mask not entered\n");
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#endif /* _KERNEL */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (tt);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta } else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta mmask = m->rm_mask;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (mmask == netmask) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta m->rm_refs++;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_mklist = m;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (tt);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (rn_refines(netmask, mmask) ||
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rn_lexobetter(netmask, mmask))
c793af95640863cd29868fc7c419c5d2496b207bsangeeta break;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *mp = rn_new_radix_mask(tt, *mp);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (tt);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic struct radix_node *
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_delete(v_arg, netmask_arg, head)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void *v_arg, *netmask_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node_head *head;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *t, *p, *x, *tt;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_mask *m, *saved_m, **mp;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *dupedkey, *saved_tt, *top;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta caddr_t v, netmask;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int b, head_off, vlen;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta v = v_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta netmask = netmask_arg;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = head->rnh_treetop;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt = rn_search(v, x);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta head_off = x->rn_offset;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta vlen = LEN(v);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta saved_tt = tt;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta top = x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (tt == 0 ||
c793af95640863cd29868fc7c419c5d2496b207bsangeeta bcmp(v + head_off, tt->rn_key + head_off, vlen - head_off))
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (0);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Delete our route from mask lists.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (netmask) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if ((x = rn_addmask(netmask, 1, head_off)) == 0)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (0);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta netmask = x->rn_key;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta while (tt->rn_mask != netmask)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if ((tt = tt->rn_dupedkey) == 0)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (0);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == 0)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta goto on1;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (tt->rn_flags & RNF_NORMAL) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (m->rm_leaf != tt || m->rm_refs > 0) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#ifdef _KERNEL
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cmn_err(CE_WARN,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta "rn_delete: inconsistent annotation\n");
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta syslog(LOG_ERR, "rn_delete: inconsistent annotation\n");
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#endif /* _KERNEL */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (0); /* dangling ref could cause disaster */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta } else {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (m->rm_mask != tt->rn_mask) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#ifdef _KERNEL
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cmn_err(CE_WARN,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta "rn_delete: inconsistent annotation 2\n");
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta syslog(LOG_ERR,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta "rn_delete: inconsistent annotation 2\n");
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#endif /* _KERNEL */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta goto on1;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (--m->rm_refs >= 0)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta goto on1;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta b = -1 - tt->rn_bit;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t = saved_tt->rn_parent;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (b > t->rn_bit)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta goto on1; /* Wasn't lifted at all */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta do {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t = t->rn_parent;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta } while (b <= t->rn_bit && x != top);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (mp = &x->rn_mklist; (m = *mp) != NULL; mp = &m->rm_mklist)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (m == saved_m) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *mp = m->rm_mklist;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta MKFree(m);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta break;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (m == 0) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#ifdef _KERNEL
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cmn_err(CE_WARN, "rn_delete: couldn't find our annotation\n");
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta syslog(LOG_ERR, "rn_delete: couldn't find our annotation\n");
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#endif /* _KERNEL */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (tt->rn_flags & RNF_NORMAL)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (0); /* Dangling ref to us */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeetaon1:
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Eliminate us from tree
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (tt->rn_flags & RNF_ROOT)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (0);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t = tt->rn_parent;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta dupedkey = saved_tt->rn_dupedkey;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (dupedkey) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Here, tt is the deletion target and
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * saved_tt is the head of the dupekey chain.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (tt == saved_tt) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /* remove from head of chain */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = dupedkey; x->rn_parent = t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (t->rn_left == tt)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t->rn_left = x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t->rn_right = x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta } else {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /* find node in front of tt on the chain */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (x = p = saved_tt; p && p->rn_dupedkey != tt; )
c793af95640863cd29868fc7c419c5d2496b207bsangeeta p = p->rn_dupedkey;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (p) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta p->rn_dupedkey = tt->rn_dupedkey;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (tt->rn_dupedkey) /* parent */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_dupedkey->rn_parent = p;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /* parent */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta } else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#ifdef _KERNEL
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cmn_err(CE_WARN,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta "rn_delete: couldn't find us\n");
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta syslog(LOG_ERR,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta "rn_delete: couldn't find us\n");
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#endif /* _KERNEL */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t = tt + 1;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (t->rn_flags & RNF_ACTIVE) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *++x = *t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta p = t->rn_parent;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (p->rn_left == t)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta p->rn_left = x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta p->rn_right = x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x->rn_left->rn_parent = x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x->rn_right->rn_parent = x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta goto out;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (t->rn_left == tt)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = t->rn_right;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = t->rn_left;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta p = t->rn_parent;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (p->rn_right == t)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta p->rn_right = x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta p->rn_left = x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x->rn_parent = p;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Demote routes attached to us.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (t->rn_mklist) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (x->rn_bit >= 0) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (mp = &x->rn_mklist; (m = *mp) != NULL; )
c793af95640863cd29868fc7c419c5d2496b207bsangeeta mp = &m->rm_mklist;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *mp = t->rn_mklist;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta } else {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * If there are any key,mask pairs in a sibling
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * duped-key chain, some subset will appear sorted
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * in the same order attached to our mklist
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (m = t->rn_mklist; m && x; x = x->rn_dupedkey)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (m == x->rn_mklist) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_mask *mm = m->rm_mklist;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x->rn_mklist = 0;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (--(m->rm_refs) < 0)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta MKFree(m);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta m = mm;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (m)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#ifdef _KERNEL
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cmn_err(CE_WARN,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta "rn_delete: Orphaned Mask %p at %p\n",
c793af95640863cd29868fc7c419c5d2496b207bsangeeta (void *)m, (void *)x);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta syslog(LOG_ERR,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta "rn_delete: Orphaned Mask %p at %p\n",
c793af95640863cd29868fc7c419c5d2496b207bsangeeta (void *)m, (void *)x);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#endif /* _KERNEL */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * We may be holding an active internal node in the tree.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta x = tt + 1;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (t != x) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *t = *x;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t->rn_left->rn_parent = t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t->rn_right->rn_parent = t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta p = x->rn_parent;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (p->rn_left == x)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta p->rn_left = t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta p->rn_right = t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeetaout:
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_flags &= ~RNF_ACTIVE;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt[1].rn_flags &= ~RNF_ACTIVE;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (tt);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta/*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Walk the radix tree; For the kernel routing table, we hold additional
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * refs on the ire_bucket to ensure that the walk function f() does not
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * run into trashed memory. The kernel routing table is identified by
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * a rnh_treetop that has RNF_SUNW_FT set in the rn_flags.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Note that all refs takein in rn_walktree are released before it returns,
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * so that f() will need to take any additional references on memory
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * to be passed back to the caller of rn_walktree.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeetastatic int
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_walktree(h, f, w)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node_head *h;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta walktree_f_t *f;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void *w;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int error;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *base, *next;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *rn = h->rnh_treetop;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta boolean_t is_ftable = B_FALSE;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (h->rnh_treetop->rn_flags & RNF_SUNW_FT) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * this is a kernel ip ftable with rt_t leaf structures.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta is_ftable = B_TRUE;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * This gets complicated because we may delete the node
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * while applying the function f to it, so we need to calculate
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * the successor node in advance.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta RADIX_NODE_HEAD_RLOCK(h);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /* First time through node, go left */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta while (rn->rn_bit >= 0) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rn = rn->rn_left;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (is_ftable)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta IRB_REFHOLD_RN(rn);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (;;) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta base = rn;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /* If at right child go back up, otherwise, go right */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta while (rn->rn_parent->rn_right == rn &&
c793af95640863cd29868fc7c419c5d2496b207bsangeeta (rn->rn_flags & RNF_ROOT) == 0) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rn = rn->rn_parent;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /* Find the next *leaf* since next node might vanish, too */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0; ) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rn = rn->rn_left;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta next = rn;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (is_ftable && next != NULL)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta IRB_REFHOLD_RN(next);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /* Process leaves */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta while ((rn = base) != NULL) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta base = rn->rn_dupedkey;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (is_ftable && base != NULL)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta IRB_REFHOLD_RN(base);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta RADIX_NODE_HEAD_UNLOCK(h);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (!(rn->rn_flags & RNF_ROOT) &&
c793af95640863cd29868fc7c419c5d2496b207bsangeeta (error = (*f)(rn, w))) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (is_ftable) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (rn != NULL)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta IRB_REFRELE_RN(rn);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (base != NULL)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta IRB_REFRELE_RN(base);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (next != NULL)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta IRB_REFRELE_RN(next);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (error);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (is_ftable && rn != NULL)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta IRB_REFRELE_RN(rn);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta RADIX_NODE_HEAD_RLOCK(h);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rn = next;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (rn->rn_flags & RNF_ROOT) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta RADIX_NODE_HEAD_UNLOCK(h);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (0);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta /* NOTREACHED */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta/*
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Allocate and initialize an empty tree. This has 3 nodes, which are
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * part of the radix_node_head (in the order <left,root,right>) and are
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * marked RNF_ROOT so they cannot be freed.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * The leaves have all-zero and all-one keys, with significant
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * bits starting at 'off'.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta * Return 1 on success, 0 on error.
c793af95640863cd29868fc7c419c5d2496b207bsangeeta */
c793af95640863cd29868fc7c419c5d2496b207bsangeetaint
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_inithead(head, off)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void **head;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta int off;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node_head *rnh;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *t, *tt, *ttt;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (*head)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (1);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta R_ZallocSleep(rnh, struct radix_node_head *, sizeof (*rnh));
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (rnh == 0)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (0);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#ifdef _KERNEL
c793af95640863cd29868fc7c419c5d2496b207bsangeeta RADIX_NODE_HEAD_LOCK_INIT(rnh);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#endif
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *head = rnh;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t = rn_newpair(rn_zeros, off, rnh->rnh_nodes);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta ttt = rnh->rnh_nodes + 2;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t->rn_right = ttt;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta t->rn_parent = t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt = t->rn_left; /* ... which in turn is rnh->rnh_nodes */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta tt->rn_bit = -1 - off;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *ttt = *tt;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta ttt->rn_key = rn_ones;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rnh->rnh_addaddr = rn_addroute;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rnh->rnh_deladdr = rn_delete;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rnh->rnh_matchaddr = rn_match;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rnh->rnh_matchaddr_args = rn_match_args;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rnh->rnh_lookup = rn_lookup;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rnh->rnh_walktree = rn_walktree;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rnh->rnh_walktree_from = NULL; /* not implemented */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rnh->rnh_treetop = t;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (1);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeetavoid
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_init()
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta char *cp, *cplim;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#ifdef _KERNEL
c793af95640863cd29868fc7c419c5d2496b207bsangeeta radix_mask_cache = kmem_cache_create("radix_mask",
c793af95640863cd29868fc7c419c5d2496b207bsangeeta sizeof (struct radix_mask), 0, NULL, NULL, NULL, NULL, NULL, 0);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta radix_node_cache = kmem_cache_create("radix_node",
c793af95640863cd29868fc7c419c5d2496b207bsangeeta max_keylen + 2 * sizeof (struct radix_node),
c793af95640863cd29868fc7c419c5d2496b207bsangeeta 0, NULL, NULL, NULL, NULL, NULL, 0);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#endif /* _KERNEL */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta R_ZallocSleep(rn_zeros, char *, 2 * max_keylen);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta ASSERT(rn_zeros != NULL);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta bzero(rn_zeros, 2 * max_keylen);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rn_ones = cp = rn_zeros + max_keylen;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta cplim = rn_ones + max_keylen;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta while (cp < cplim)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta *cp++ = -1;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (rn_inithead((void **)(void *)&mask_rnhead, 0) == 0)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta panic("rn_init: could not init mask_rnhead ");
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeetaint
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_freenode(n, p)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *n;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta void *p;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node_head *rnh = p;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node *d;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta d = rnh->rnh_deladdr(n->rn_key, NULL, rnh);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (d != NULL) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta Free(d, radix_node_cache);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta return (0);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeetavoid
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_freehead(rnh)
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_node_head *rnh;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta (void) rn_walktree(rnh, rn_freenode, rnh);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rnh->rnh_addaddr = NULL;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rnh->rnh_deladdr = NULL;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rnh->rnh_matchaddr = NULL;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rnh->rnh_lookup = NULL;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rnh->rnh_walktree = NULL;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#ifdef _KERNEL
c793af95640863cd29868fc7c419c5d2496b207bsangeeta FreeHead(rnh, sizeof (*rnh));
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta Free(rnh, NULL);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#endif /* _KERNEL */
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeetavoid
c793af95640863cd29868fc7c419c5d2496b207bsangeetarn_fini()
c793af95640863cd29868fc7c419c5d2496b207bsangeeta{
c793af95640863cd29868fc7c419c5d2496b207bsangeeta struct radix_mask *m;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (rn_zeros != NULL) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#ifdef _KERNEL
c793af95640863cd29868fc7c419c5d2496b207bsangeeta FreeHead(rn_zeros, 2 * max_keylen);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#else
c793af95640863cd29868fc7c419c5d2496b207bsangeeta Free(rn_zeros, NULL);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta#endif
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rn_zeros = NULL;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta if (mask_rnhead != NULL) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rn_freehead(mask_rnhead);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta mask_rnhead = NULL;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta
c793af95640863cd29868fc7c419c5d2496b207bsangeeta while ((m = rn_mkfreelist) != NULL) {
c793af95640863cd29868fc7c419c5d2496b207bsangeeta rn_mkfreelist = m->rm_mklist;
c793af95640863cd29868fc7c419c5d2496b207bsangeeta Free(m, NULL);
c793af95640863cd29868fc7c419c5d2496b207bsangeeta }
c793af95640863cd29868fc7c419c5d2496b207bsangeeta}