struct radix_node * rn_lookup(void *v_arg, void *m_arg, struct radix_node_head *head) { struct radix_node *x; caddr_t netmask = 0; if (m_arg) { if ((x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_off)) == 0) return (0); netmask = x->rn_key; } x = rn_match(v_arg, head); if (x && netmask) { while (x && x->rn_mask != netmask) x = x->rn_dupedkey; } return x; }
struct radix_node * rn_lookup(void *v_arg, void *m_arg, struct radix_node_head *head) { register struct radix_node *x; uint8 *netmask = NULL; if (m_arg) { x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_offset); if (x == 0) return 0; netmask = x->rn_key; } x = rn_match(v_arg, head); if (x && netmask) { while (x && x->rn_mask != netmask) x = x->rn_dupedkey; } return x; }
struct radix_node * rn_lookup(void *v_arg, void *m_arg, struct radix_node_head *head) { struct radix_node *x, *tm; caddr_t netmask = 0; if (m_arg) { tm = rn_addmask(m_arg, 1, head->rnh_treetop->rn_off); if (tm == NULL) return (NULL); netmask = tm->rn_key; } x = rn_match(v_arg, head); if (x && netmask) { while (x && x->rn_mask != netmask) x = x->rn_dupedkey; } return x; }
struct radix_node * rn_lookup(char *key, char *mask, struct radix_node_head *head) { struct radix_node *x; char *netmask = NULL; if (mask != NULL) { x = rn_addmask(mask, TRUE, head->rnh_treetop->rn_offset, head->rnh_maskhead); if (x == NULL) return (NULL); netmask = x->rn_key; } x = rn_match(key, head); if (x != NULL && netmask != NULL) { while (x != NULL && x->rn_mask != netmask) x = x->rn_dupedkey; } return x; }
struct radix_node * rn_lookup( const void *v_arg, const void *m_arg, struct radix_node_head *head) { struct radix_node *x; const char *netmask = NULL; if (m_arg) { if ((x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_off)) == 0) return NULL; netmask = x->rn_key; } x = rn_match(v_arg, head); if (x != NULL && netmask != NULL) { while (x != NULL && x->rn_mask != netmask) x = x->rn_dupedkey; } return x; }
/* * Search for exact match in given @head. * Assume host bits are cleared in @v_arg if @m_arg is not NULL * Note that prefixes with /32 or /128 masks are treated differently * from host routes. */ struct radix_node * rn_lookup(void *v_arg, void *m_arg, struct radix_node_head *head) { struct radix_node *x; caddr_t netmask; if (m_arg != NULL) { /* * Most common case: search exact prefix/mask */ x = rn_addmask(m_arg, head->rnh_masks, 1, head->rnh_treetop->rn_offset); if (x == NULL) return (NULL); netmask = x->rn_key; x = rn_match(v_arg, head); while (x != NULL && x->rn_mask != netmask) x = x->rn_dupedkey; return (x); } /* * Search for host address. */ if ((x = rn_match(v_arg, head)) == NULL) return (NULL); /* Check if found key is the same */ if (LEN(x->rn_key) != LEN(v_arg) || bcmp(x->rn_key, v_arg, LEN(v_arg))) return (NULL); /* Check if this is not host route */ if (x->rn_mask != NULL) return (NULL); return (x); }
ROUTE_ENTRY * routeLookup ( struct sockaddr * pDest, /* IP address reachable with matching route */ ULONG * pMask, /* netmask value, in network byte order */ int protoId /* route source from m2Lib.h, or 0 for any. */ ) { struct radix_node_head * pHead = rt_tables[pDest->sa_family]; struct radix_node * pNode; /* radix tree entry for route */ struct rtentry * pRoute = NULL; /* candidate for matching route */ ROUTE_ENTRY * pMatch = NULL; /* matching route entry */ struct sockaddr_in netmask; /* netmask value, internal format */ char * pNetmask = NULL; /* target netmask value from tree */ struct rtentry * pNextRoute; STATUS result = ERROR; /* OK indicates a successful search */ int s; if (pHead == NULL) { /* No route table exists for the given address family. */ return (NULL); } bzero ( (char *)&netmask, sizeof (struct sockaddr_in)); s = splnet (); /* * If a specific netmask match is required, find the target value * (a pointer to the stored netmask entry) which will determine * whether the match exists. A mask value of zero indicates a * host-specific route, which does not contain a netmask entry. */ if (pMask && *pMask) { /* Setup data structure to search mask's tree for given value. */ netmask.sin_family = AF_INET; netmask.sin_len = sizeof (struct sockaddr_in); netmask.sin_addr.s_addr = *pMask; TOS_SET (&netmask, 0x1f); in_socktrim (&netmask); /* Adjust length field for tree search. */ /* Search for netmask from corresponding tree. */ pNode = rn_addmask (&netmask, 1, pHead->rnh_treetop->rn_off); if (pNode == 0) { /* No route currently uses the specified netmask. */ #ifdef DEBUG logMsg ("routeLookup: requested mask does not exist.\n", 0, 0, 0, 0, 0, 0); #endif splx(s); return (NULL); } pNetmask = pNode->rn_key; } pNode = pHead->rnh_matchaddr ((caddr_t)pDest, pHead); if (pNode && ((pNode->rn_flags & RNF_ROOT) == 0)) { /* Possible match found. Save for later use. */ pRoute = (struct rtentry *)pNode; } else { /* No route matches the given key. */ splx (s); return (NULL); } #ifdef DEBUG logMsg ("routeLookup: candidate for match at %p.\n", pNode, 0, 0, 0, 0, 0); #endif /* * Compare the set of routes available with the initial key * against the desired values. Each entry in the chain of * routes with duplicate keys uses a different netmask value. * * NOTE: The pNode value is not necessarily the start of the * chain. It is the first entry in the chain with a short * enough netmask to produce a match against the destination. */ for ( ; pRoute != NULL; pRoute = pNextRoute) { /* Select the next route candidate in case a test fails. */ pNextRoute = (struct rtentry *) ((struct radix_node *)pRoute)->rn_dupedkey; if (pMask) { /* * Check mask of route against corresponding entry from * the stored netmasks (derived from the given value). */ #ifdef DEBUG logMsg ("routeLookup: checking against specific mask.\n", 0, 0, 0, 0, 0, 0); #endif if (*pMask) { if ( ((struct radix_node *)pRoute)->rn_mask != pNetmask) continue; /* Mask values do not match. */ } else if ( ( (struct sockaddr_in *)pDest)->sin_addr.s_addr) { /* Searching for a host-specific route (no netmask entry). */ if ( ((struct radix_node *)pRoute)->rn_mask != 0) continue; /* Entry is not a host route. */ } } /* * Candidate passed any mask requirements. Search for entries * which match the specified route source. */ #ifdef DEBUG logMsg ("routeLookup: Current mask is OK.\n", 0, 0, 0, 0, 0, 0); #endif if (protoId) { /* Check source of route against specified value. */ #ifdef DEBUG logMsg ("routeLookup: testing protocol ID.\n", 0, 0, 0, 0, 0, 0); #endif for (pMatch = (ROUTE_ENTRY *)pRoute; pMatch != NULL; pMatch = pMatch->diffNode.pFrwd) { if (RT_PROTO_GET(ROUTE_ENTRY_KEY(pMatch)) == protoId) break; } if (pMatch == NULL) /* Route protocol values do not match. */ continue; #ifdef DEBUG logMsg ("routeLookup: Current protocol ID is OK.\n", 0, 0, 0, 0, 0, 0); #endif } else { /* * No route source is specified. Accept the entry * which met any mask criteria. */ pMatch = (ROUTE_ENTRY *)pRoute; } /* The candidate route entry met all criteria. Stop the search. */ result = OK; break; } if (result == OK) { /* Increase the reference count before returning the matching entry. */ pMatch->rtEntry.rt_refcnt++; } else pMatch = NULL; splx (s); return (pMatch); }
static struct radix_node * rn_delete(void *v_arg, void *netmask_arg, struct radix_node_head *head) { struct radix_node *t, *p, *x, *tt; struct radix_mask *m, *saved_m, **mp; struct radix_node *dupedkey, *saved_tt, *top; caddr_t v, netmask; int b, head_off, vlen; v = v_arg; netmask = netmask_arg; x = head->rnh_treetop; tt = rn_search(v, x); head_off = x->rn_off; vlen = *(u_char *)v; saved_tt = tt; top = x; if (tt == 0 || Bcmp(v + head_off, tt->rn_key + head_off, vlen - head_off)) return (0); /* * Delete our route from mask lists. */ if (netmask) { if ((x = rn_addmask(netmask, 1, head_off)) == 0) return (0); netmask = x->rn_key; while (tt->rn_mask != netmask) if ((tt = tt->rn_dupedkey) == 0) return (0); } if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == 0) goto on1; if (tt->rn_flags & RNF_NORMAL) { if (m->rm_leaf != tt || m->rm_refs > 0) { log(LOG_ERR, "rn_delete: inconsistent annotation\n"); return 0; /* dangling ref could cause disaster */ } } else { if (m->rm_mask != tt->rn_mask) { log(LOG_ERR, "rn_delete: inconsistent annotation\n"); goto on1; } if (--m->rm_refs >= 0) goto on1; } b = -1 - tt->rn_b; t = saved_tt->rn_p; if (b > t->rn_b) goto on1; /* Wasn't lifted at all */ do { x = t; t = t->rn_p; } while (b <= t->rn_b && x != top); for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) if (m == saved_m) { *mp = m->rm_mklist; MKFree(m); break; } if (m == 0) { log(LOG_ERR, "rn_delete: couldn't find our annotation\n"); if (tt->rn_flags & RNF_NORMAL) return (0); /* Dangling ref to us */ } on1: /* * Eliminate us from tree */ if (tt->rn_flags & RNF_ROOT) return (0); #ifdef RN_DEBUG /* Get us out of the creation list */ for (t = rn_clist; t && t->rn_ybro != tt; t = t->rn_ybro) {} if (t) t->rn_ybro = tt->rn_ybro; #endif t = tt->rn_p; if ((dupedkey = saved_tt->rn_dupedkey)) { if (tt == saved_tt) { x = dupedkey; x->rn_p = t; if (t->rn_l == tt) t->rn_l = x; else t->rn_r = x; } else { for (x = p = saved_tt; p && p->rn_dupedkey != tt;) p = p->rn_dupedkey; if (p) p->rn_dupedkey = tt->rn_dupedkey; else log(LOG_ERR, "rn_delete: couldn't find us\n"); } t = tt + 1; if (t->rn_flags & RNF_ACTIVE) { #ifndef RN_DEBUG *++x = *t; p = t->rn_p; #else b = t->rn_info; *++x = *t; t->rn_info = b; p = t->rn_p; #endif if (p->rn_l == t) p->rn_l = x; else p->rn_r = x; x->rn_l->rn_p = x; x->rn_r->rn_p = x; } goto out; } if (t->rn_l == tt) x = t->rn_r; else x = t->rn_l; p = t->rn_p; if (p->rn_r == t) p->rn_r = x; else p->rn_l = x; x->rn_p = p; /* * Demote routes attached to us. */ if (t->rn_mklist) { if (x->rn_b >= 0) { for (mp = &x->rn_mklist; (m = *mp);) mp = &m->rm_mklist; *mp = t->rn_mklist; } else { /* If there are any key,mask pairs in a sibling duped-key chain, some subset will appear sorted in the same order attached to our mklist */ for (m = t->rn_mklist; m && x; x = x->rn_dupedkey) if (m == x->rn_mklist) { struct radix_mask *mm = m->rm_mklist; x->rn_mklist = 0; if (--(m->rm_refs) < 0) MKFree(m); m = mm; } if (m) syslog(LOG_ERR, "%s 0x%lx at 0x%lx\n", "rn_delete: Orphaned Mask", (unsigned long)m, (unsigned long)x); } } /* * We may be holding an active internal node in the tree. */ x = tt + 1; if (t != x) { #ifndef RN_DEBUG *t = *x; #else b = t->rn_info; *t = *x; t->rn_info = b; #endif t->rn_l->rn_p = t; t->rn_r->rn_p = t; p = x->rn_p; if (p->rn_l == x) p->rn_l = t; else p->rn_r = t; } out: tt->rn_flags &= ~RNF_ACTIVE; tt[1].rn_flags &= ~RNF_ACTIVE; return (tt); }
static struct radix_node * rn_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, struct radix_node treenodes[2]) { caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg; struct radix_node *t, *x = 0, *tt; struct radix_node *saved_tt, *top = head->rnh_treetop; short b = 0, b_leaf = 0; int keyduplicated; caddr_t mmask; struct radix_mask *m, **mp; /* * In dealing with non-contiguous masks, there may be * many different routes which have the same mask. * We will find it useful to have a unique pointer to * the mask to speed avoiding duplicate references at * nodes and possibly save time in calculating indices. */ if (netmask) { if ((x = rn_addmask(netmask, 0, top->rn_off)) == 0) return (0); b_leaf = x->rn_b; b = -1 - x->rn_b; netmask = x->rn_key; } /* * Deal with duplicated keys: attach node to previous instance */ saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes); if (keyduplicated) { for (t = tt; tt; t = tt, tt = tt->rn_dupedkey) { if (tt->rn_mask == netmask) return (0); if (netmask == 0 || (tt->rn_mask && ((b_leaf < tt->rn_b) || /* index(netmask) > node */ rn_refines(netmask, tt->rn_mask) || rn_lexobetter(netmask, tt->rn_mask)))) break; } /* * If the mask is not duplicated, we wouldn't * find it among possible duplicate key entries * anyway, so the above test doesn't hurt. * * We sort the masks for a duplicated key the same way as * in a masklist -- most specific to least specific. * This may require the unfortunate nuisance of relocating * the head of the list. */ if (tt == saved_tt) { struct radix_node *xx = x; /* link in at head of list */ (tt = treenodes)->rn_dupedkey = t; tt->rn_flags = t->rn_flags; tt->rn_p = x = t->rn_p; if (x->rn_l == t) x->rn_l = tt; else x->rn_r = tt; saved_tt = tt; x = xx; } else { (tt = treenodes)->rn_dupedkey = t->rn_dupedkey; t->rn_dupedkey = tt; } #ifdef RN_DEBUG t=tt+1; tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++; tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt; #endif tt->rn_key = (caddr_t) v; tt->rn_b = -1; tt->rn_flags = RNF_ACTIVE; } /* * Put mask in tree. */ if (netmask) { tt->rn_mask = netmask; tt->rn_b = x->rn_b; tt->rn_flags |= x->rn_flags & RNF_NORMAL; } t = saved_tt->rn_p; if (keyduplicated) goto on2; b_leaf = -1 - t->rn_b; if (t->rn_r == saved_tt) x = t->rn_l; else x = t->rn_r; /* Promote general routes from below */ if (x->rn_b < 0) { for (mp = &t->rn_mklist; x; x = x->rn_dupedkey) if (x->rn_mask && (x->rn_b >= b_leaf) && x->rn_mklist == 0) { if ((*mp = m = rn_new_radix_mask(x, 0))) mp = &m->rm_mklist; } } else if (x->rn_mklist) { /* * Skip over masks whose index is > that of new node */ for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) if (m->rm_b >= b_leaf) break; t->rn_mklist = m; *mp = 0; } on2: /* Add new route to highest possible ancestor's list */ if ((netmask == 0) || (b > t->rn_b )) return tt; /* can't lift at all */ b_leaf = tt->rn_b; do { x = t; t = t->rn_p; } while (b <= t->rn_b && x != top); /* * Search through routes associated with node to * insert new route according to index. * Need same criteria as when sorting dupedkeys to avoid * double loop on deletion. */ for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) { if (m->rm_b < b_leaf) continue; if (m->rm_b > b_leaf) break; if (m->rm_flags & RNF_NORMAL) { mmask = m->rm_leaf->rn_mask; if (tt->rn_flags & RNF_NORMAL) { log(LOG_ERR, "Non-unique normal route, mask not entered"); return tt; } } else mmask = m->rm_mask; if (mmask == netmask) { m->rm_refs++; tt->rn_mklist = m; return tt; } if (rn_refines(netmask, mmask) || rn_lexobetter(netmask, mmask)) break; } *mp = rn_new_radix_mask(tt, *mp); return tt; }