/** * trie_match * @t: trie * @px: prefix address * @plen: prefix length * * Tries to find a matching prefix pattern in the trie such that * prefix @px/@plen matches that prefix pattern. Returns 1 if there * is such prefix pattern in the trie. */ int trie_match_prefix(struct f_trie *t, ip_addr px, int plen) { ip_addr pmask = ipa_mkmask(plen); ip_addr paddr = ipa_and(px, pmask); if (plen == 0) return t->zero; int plentest = plen - 1; struct f_trie_node *n = &t->root; while(n) { ip_addr cmask = ipa_and(n->mask, pmask); /* We are out of path */ if (ipa_compare(ipa_and(paddr, cmask), ipa_and(n->addr, cmask))) return 0; /* Check accept mask */ if (ipa_getbit(n->accept, plentest)) return 1; /* We finished trie walk and still no match */ if (plen <= n->plen) return 0; /* Choose children */ n = n->c[(ipa_getbit(paddr, n->plen)) ? 1 : 0]; } return 0; }
static void scan_ifs(struct ifreq *r, int cnt) { struct iface i, *pi; struct ifa a; char *err, *colon; unsigned fl; ip_addr netmask; int l, scope; sockaddr *sa; if_start_update(); for (cnt /= sizeof(struct ifreq); cnt; cnt--, r++) { int sec = 0; bzero(&i, sizeof(i)); bzero(&a, sizeof(a)); if (colon = strchr(r->ifr_name, ':')) { /* It's an alias -- let's interpret it as a secondary interface address */ sec = 1; *colon = 0; } strncpy(i.name, r->ifr_name, sizeof(i.name) - 1); if(ioctl(if_scan_sock, SIOCGIFADDR,r)<0) continue; get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.ip, NULL, 1); if (ipa_nonzero(a.ip)) { l = ipa_classify(a.ip); if (l < 0 || !(l & IADDR_HOST)) { log(L_ERR "%s: Invalid interface address", i.name); a.ip = IPA_NONE; } else { a.scope = l & IADDR_SCOPE_MASK; if (a.scope == SCOPE_HOST) i.flags |= IF_LOOPBACK | IF_IGNORE; } } if (ioctl(if_scan_sock, SIOCGIFFLAGS, r) < 0) { err = "SIOCGIFFLAGS"; faulty: log(L_ERR "%s(%s): %m", err, i.name); bad: i.flags = (i.flags & ~IF_LINK_UP) | IF_ADMIN_DOWN; continue; } fl = r->ifr_flags; if (fl & IFF_UP) i.flags |= IF_LINK_UP; if (ioctl(if_scan_sock, SIOCGIFNETMASK, r) < 0) { err = "SIOCGIFNETMASK"; goto faulty; } get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &netmask, NULL, 0); l = ipa_mklen(netmask); if (l < 0 || l == 31) { log(L_ERR "%s: Invalid netmask (%x)", i.name, netmask); goto bad; } a.pxlen = l; if (fl & IFF_POINTOPOINT) { a.flags |= IA_UNNUMBERED; if (ioctl(if_scan_sock, SIOCGIFDSTADDR, r) < 0) { err = "SIOCGIFDSTADDR"; goto faulty; } get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.opposite, NULL, 1); a.prefix = a.opposite; a.pxlen = BITS_PER_IP_ADDRESS; } else a.prefix = ipa_and(a.ip, ipa_mkmask(a.pxlen)); if (fl & IFF_LOOPBACK) i.flags |= IF_LOOPBACK | IF_IGNORE; if (1 #ifndef CONFIG_ALL_MULTICAST && (fl & IFF_MULTICAST) #endif #ifndef CONFIG_UNNUM_MULTICAST && !(a.flags & IA_UNNUMBERED) #endif ) i.flags |= IF_MULTICAST; scope = ipa_classify(a.ip); if (scope < 0) { log(L_ERR "%s: Invalid address", i.name); goto bad; } a.scope = scope & IADDR_SCOPE_MASK; if (a.pxlen < 32) { a.brd = ipa_or(a.prefix, ipa_not(ipa_mkmask(a.pxlen))); if (ipa_equal(a.ip, a.prefix) || ipa_equal(a.ip, a.brd)) { log(L_ERR "%s: Using network or broadcast address for interface", i.name); goto bad; } if (fl & IFF_BROADCAST) i.flags |= IF_BROADCAST; if (a.pxlen < 30) i.flags |= IF_MULTIACCESS; else a.opposite = ipa_opposite(a.ip, a.pxlen); } else a.brd = a.opposite; a.scope = SCOPE_UNIVERSE; if (ioctl(if_scan_sock, SIOCGIFMTU, r) < 0) { err = "SIOCGIFMTU"; goto faulty; } i.mtu = r->ifr_mtu; #ifdef SIOCGIFINDEX if (ioctl(if_scan_sock, SIOCGIFINDEX, r) >= 0) i.index = r->ifr_ifindex; else if (errno != EINVAL) DBG("SIOCGIFINDEX failed: %m\n"); else /* defined, but not supported by the kernel */ #endif /* * The kernel doesn't give us real ifindices, but we still need them * at least for OSPF unnumbered links. So let's make them up ourselves. */ if (pi = if_find_by_name(i.name)) i.index = pi->index; else { static int if_index_counter = 1; i.index = if_index_counter++; } pi = NULL; if (sec) { a.flags |= IA_SECONDARY; pi = if_find_by_index(i.index); } if (!pi) pi = if_update(&i); a.iface = pi; ifa_update(&a); } if_end_update(); }
void trie_add_prefix(struct f_trie *t, ip_addr px, int plen, int l, int h) { if (l == 0) t->zero = 1; else l--; if (h < plen) plen = h; ip_addr amask = ipa_xor(ipa_mkmask(l), ipa_mkmask(h)); ip_addr pmask = ipa_mkmask(plen); ip_addr paddr = ipa_and(px, pmask); struct f_trie_node *o = NULL; struct f_trie_node *n = &t->root; while(n) { ip_addr cmask = ipa_and(n->mask, pmask); if (ipa_compare(ipa_and(paddr, cmask), ipa_and(n->addr, cmask))) { /* We are out of path - we have to add branching node 'b' between node 'o' and node 'n', and attach new node 'a' as the other child of 'b'. */ int blen = ipa_pxlen(paddr, n->addr); ip_addr bmask = ipa_mkmask(blen); ip_addr baddr = ipa_and(px, bmask); /* Merge accept masks from children to get accept mask for node 'b' */ ip_addr baccm = ipa_and(ipa_or(amask, n->accept), bmask); struct f_trie_node *a = new_node(t, plen, paddr, pmask, amask); struct f_trie_node *b = new_node(t, blen, baddr, bmask, baccm); attach_node(o, b); attach_node(b, n); attach_node(b, a); return; } if (plen < n->plen) { /* We add new node 'a' between node 'o' and node 'n' */ amask = ipa_or(amask, ipa_and(n->accept, pmask)); struct f_trie_node *a = new_node(t, plen, paddr, pmask, amask); attach_node(o, a); attach_node(a, n); return; } if (plen == n->plen) { /* We already found added node in trie. Just update accept mask */ n->accept = ipa_or(n->accept, amask); return; } /* Update accept mask part M2 and go deeper */ n->accept = ipa_or(n->accept, ipa_and(amask, n->mask)); /* n->plen < plen and plen <= 32 (128) */ o = n; n = n->c[ipa_getbit(paddr, n->plen) ? 1 : 0]; } /* We add new tail node 'a' after node 'o' */ struct f_trie_node *a = new_node(t, plen, paddr, pmask, amask); attach_node(o, a); }