int main(int argc, char const* argv[]) { Input default_gateway_input; Input address; const Entry* entry; RouterTrie rt; // default_gateway_input = rt_create_default_gateway_input( // rt_convert_string_to_address("2001::1"), 0); rt_setup(&rt); // rt_default_gateway(&rt, &default_gateway_input); address.prefix_length = 64; address.interface = 1; address.next_hop = rt_convert_string_to_address("::1"); address.address = rt_convert_string_to_address("2a00:1450:4001:817::0"); rt_insert(&rt, &address); address.prefix_length = 64; address.interface = 2; address.next_hop = rt_convert_string_to_address("::2"); address.address = rt_convert_string_to_address("2aff:1450:4001:817::0"); rt_insert(&rt, &address); address.address = rt_convert_string_to_address("2aff:1450:4001:817::0"); entry = rt_match(&rt, &address.address); printf("%d\n", entry ? entry->interface : 0); rt_destroy(&rt); return 0; }
/** * Handles incoming routing-request packets. */ static void krip_dispatch_in() { fd_set fds; struct timeval timeout; int rc; int i; list_position pos; rip_info *ri; FD_ZERO(&fds); FD_SET(_sock, &fds); timeout.tv_sec = 0; timeout.tv_usec = 0; /* The main loop of the RIP daemon. */ while ((rc = select(_sock + 1, &fds, NULL, NULL, &timeout)) > 0) { rip_buf buf; uint32_t now = krip_get_mtime(); size_t len = RIP_PACKET_MAXSIZ; struct sockaddr_in from; size_t fromlen = sizeof(from); len = recvfrom(_sock, buf.buf, len, 0, (struct sockaddr *)&from, &fromlen); /* Find the sender by matching IP addresses and ports. */ neighbor_info *ni = NULL; pos = list_get_head_position(_neighbor_info_list); for (; pos; pos = list_get_next_position(pos)) { ni = list_get_at(pos); if (from.sin_addr.s_addr == ni->krip_addr.sin_addr.s_addr && from.sin_port == ni->krip_addr.sin_port) break; /* Should be reset to perform below check routines correctly. (ref http://noah.kaist.ac.kr/view.jsp?board=1353&serial=517685) */ ni = NULL; } /* If the sender is not recoginized, skip the RIP message. */ if (!ni) { L_ROUTE("krip_dispatch_in(): unknown neighbor %s:%d", inet_ntoa(from.sin_addr), ntohs(from.sin_port)); continue; } /* If the interface received is disabled, also skip it. */ if (!ni->ifp->if_enabled) { L_ROUTE("krip_dispatch_in(): ignored response from %s {%08x}", inet_ntoa(ni->virtual_addr), ni->ifp); continue; } /* Process RIP packets. */ switch (buf.rip_packet.command) { case RIP_REQUEST: /* Response to the request. */ L_ROUTE("krip_dispatch_in(): RIP_REQUEST from %s {%08x}", inet_ntoa(ni->virtual_addr), ni->ifp); krip_send_response(ni, 0); break; case RIP_RESPONSE: /* RIP 응답 패킷을 받으면 그것을 바탕으로 자신의 routing table 정보를 업데이트한다. */ i = 0; L_ROUTE("krip_dispatch_in(): RIP_RESPONSE from %s {%08x} with %d entries.", inet_ntoa(ni->virtual_addr), ni->ifp, (len - RIP_HEADER_SIZE) / RIP_RTE_SIZE); /* Look up the received routing table entries. */ while (1) { bool found = false; rte *rte = buf.rip_packet.rte + i; /* Convert endians. */ rte->family = ntohs(rte->family); rte->tag = ntohs(rte->tag); rte->metric = ntohl(rte->metric); /* Stop if the index reaches the number of available routing entries in the packet. */ if (i == (len - RIP_HEADER_SIZE) / RIP_RTE_SIZE) break; L_ROUTE("krip_dispatch_in(): processing entry %d (prefix=%s, mask=%s, metric=%d)", i + 1, inet_ntoa(rte->prefix), inet_ntoa(rte->mask), rte->metric); /* 여기에서 distance vector 알고리즘이 구현된다. */ /* Choose minimum of received metric + 1 and inifinity. */ uint32_t new_metric = MIN(rte->metric + 1, RIP_METRIC_INFINITY); for (pos = list_get_head_position(_rip_info_list); pos; pos = list_get_next_position(pos)) { ri = list_get_at(pos); /* 여기에서 match된다는 뜻은 어디로 해당 IP 대역을 담당하는 routing entry를 찾았다는 뜻이다. */ /* If a routing_info matches an entry, update related information. */ if (ri->assoc_rte->dst.s_addr == rte->prefix.s_addr) { L_ROUTE("krip_dispatch_in(): ri->assoc_rte->dst = %s {%08x} has to be updated.", inet_ntoa(ri->assoc_rte->dst), ri->from); found = true; /* If ri is from the neighbor which sent the RIP message, refresh timeout. */ if (ri->from == ni->ifp) { ri->timeout = now + _timeout; } /* 현재 보고 있는 rip_info가 RIP message를 받은 interface로부터 온 것이고 metric 값이 바뀌거나, 새 metric 값이 더 낮을 경우(더 좋은 route임을 뜻함) rip_info를 새로 업데이트한다. (ref http://noah.kaist.ac.kr/view.jsp?board=1248&serial=509303) */ if ((ri->from == ni->ifp && new_metric != ri->metric) || (ri->metric > new_metric)) { /* If previous ri was advertised by the sender, or the new route has lower metric, update ri. */ L_ROUTE("krip_dispatch_in(): updating existing routing info... (gw = %s {%08x}, metric = %d)", inet_ntoa(ni->virtual_addr), ni->ifp, new_metric); ri->assoc_rte->gw.s_addr = ni->virtual_addr.s_addr; ri->assoc_rte->rt_ifp = ni->ifp; ri->metric = new_metric; ri->change_flag = 1; /* Mark it as modified. */ ri->from = ni->ifp; ip_invalidate_forward_rt_cache(); _trigger = true; } } } if (!found) { /* If matching routing info is not found, create a new routing entry and routing info. */ L_ROUTE("krip_dispatch_in(): creating a new routing entry..."); rtentry *new_rte = (rtentry *)malloc(sizeof(rtentry)); new_rte->dst = rte->prefix; new_rte->mask = rte->mask; new_rte->gw = ni->virtual_addr; new_rte->rt_ifp = ni->ifp; if (rt_insert(new_rte)) { L_ROUTE("krip_dispatch_in(): failed to insert new route"); free(new_rte); break; } ri = (rip_info *)malloc(sizeof(rip_info)); ri->assoc_rte = new_rte; ri->metric = new_metric; ri->change_flag = 1; /* Mark it as modified. */ ri->timeout = now + _timeout; /* Initialize timeout. */ ri->from = ni->ifp; list_add_tail(_rip_info_list, ri); ip_invalidate_forward_rt_cache(); _trigger = true; } i++; } break; default: L_ROUTE("krip_dispatch_in(): unrecognized RIP command type (%d) from %s.", buf.rip_packet.command, inet_ntoa(ni->virtual_addr)); break; } } if (rc < 0) perror("krip"); }
int rde_check_route(struct rip_route *e) { struct timeval tv, now; struct rt_node *rn; struct iface *iface; u_int8_t metric; if ((e->nexthop.s_addr & htonl(IN_CLASSA_NET)) == htonl(INADDR_LOOPBACK & IN_CLASSA_NET) || e->nexthop.s_addr == INADDR_ANY) return (-1); if ((iface = if_find_index(e->ifindex)) == NULL) return (-1); metric = MIN(INFINITY, e->metric + iface->cost); if ((rn = rt_find(e->address.s_addr, e->mask.s_addr)) == NULL) { if (metric >= INFINITY) return (0); rn = rt_new_rr(e, metric); rt_insert(rn); rde_send_change_kroute(rn); route_start_timeout(rn); triggered_update(rn); } else { /* * XXX don't we have to track all incoming routes? * what happens if the kernel route is removed later. */ if (rn->flags & F_KERNEL) return (0); if (metric < rn->metric) { rn->metric = metric; rn->nexthop.s_addr = e->nexthop.s_addr; rn->ifindex = e->ifindex; rde_send_change_kroute(rn); triggered_update(rn); } else if (e->nexthop.s_addr == rn->nexthop.s_addr && metric > rn->metric) { rn->metric = metric; rde_send_change_kroute(rn); triggered_update(rn); if (rn->metric == INFINITY) route_start_garbage(rn); } else if (e->nexthop.s_addr != rn->nexthop.s_addr && metric == rn->metric) { /* If the new metric is the same as the old one, * examine the timeout for the existing route. If it * is at least halfway to the expiration point, switch * to the new route. */ timerclear(&tv); gettimeofday(&now, NULL); evtimer_pending(&rn->timeout_timer, &tv); if (tv.tv_sec - now.tv_sec < ROUTE_TIMEOUT / 2) { rn->nexthop.s_addr = e->nexthop.s_addr; rn->ifindex = e->ifindex; rde_send_change_kroute(rn); } } if (e->nexthop.s_addr == rn->nexthop.s_addr && rn->metric < INFINITY) route_reset_timers(rn); } return (0); }
/* ARGSUSED */ void rde_dispatch_parent(int fd, short event, void *bula) { struct imsg imsg; struct rt_node *rt; struct kroute kr; struct imsgev *iev = bula; struct imsgbuf *ibuf = &iev->ibuf; ssize_t n; int shut = 0; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1) fatal("imsg_read error"); if (n == 0) /* connection closed */ shut = 1; } if (event & EV_WRITE) { if (msgbuf_write(&ibuf->w) == -1 && errno != EAGAIN) fatal("msgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("rde_dispatch_parent: imsg_read error"); if (n == 0) break; switch (imsg.hdr.type) { case IMSG_NETWORK_ADD: if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(kr)) { log_warnx("rde_dispatch: wrong imsg len"); break; } memcpy(&kr, imsg.data, sizeof(kr)); rt = rt_new_kr(&kr); rt_insert(rt); break; case IMSG_NETWORK_DEL: if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(kr)) { log_warnx("rde_dispatch: wrong imsg len"); break; } memcpy(&kr, imsg.data, sizeof(kr)); if ((rt = rt_find(kr.prefix.s_addr, kr.netmask.s_addr)) != NULL) rt_remove(rt); break; default: log_debug("rde_dispatch_parent: unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* this pipe is dead, so remove the event handler */ event_del(&iev->ev); event_loopexit(NULL); } }