📄 ripngd.c
字号:
ripng_read (struct thread *thread){ int len; int sock; struct sockaddr_in6 from; struct ripng_packet *packet; unsigned int ifindex; struct interface *ifp; int hoplimit = -1; /* Check ripng is active and alive. */ assert (ripng != NULL); assert (ripng->sock >= 0); /* Fetch thread data and set read pointer to empty for event managing. `sock' sould be same as ripng->sock. */ sock = THREAD_FD (thread); ripng->t_read = NULL; /* Add myself to the next event. */ ripng_event (RIPNG_READ, sock); /* Read RIPng packet. */ len = ripng_recv_packet (sock, STREAM_DATA (ripng->ibuf), STREAM_SIZE (ripng->ibuf), &from, &ifindex, &hoplimit); if (len < 0) { zlog_warn ("RIPng recvfrom failed: %s.", strerror (errno)); return len; } /* Check RTE boundary. RTE size (Packet length - RIPng header size (4)) must be multiple size of one RTE size (20). */ if (((len - 4) % 20) != 0) { zlog_warn ("RIPng invalid packet size %d from %s", len, inet6_ntop (&from.sin6_addr)); return 0; } packet = (struct ripng_packet *) STREAM_DATA (ripng->ibuf); ifp = if_lookup_by_index (ifindex); /* RIPng packet received. */ if (IS_RIPNG_DEBUG_EVENT) zlog_info ("RIPng packet received from %s port %d on %s", inet6_ntop (&from.sin6_addr), ntohs (from.sin6_port), ifp ? ifp->name : "unknown"); /* Logging before packet checking. */ if (IS_RIPNG_DEBUG_RECV) ripng_packet_dump (packet, len, "RECV"); /* Packet comes from unknown interface. */ if (ifp == NULL) { zlog_warn ("RIPng packet comes from unknown interface %d", ifindex); return 0; } /* Packet version mismatch checking. */ if (packet->version != ripng->version) { zlog_warn ("RIPng packet version %d doesn't fit to my version %d", packet->version, ripng->version); return 0; } /* Process RIPng packet. */ switch (packet->command) { case RIPNG_REQUEST: ripng_request_process (packet, len, &from, ifp); break; case RIPNG_RESPONSE: ripng_response_process (packet, len, &from, ifp, hoplimit); break; default: zlog_warn ("Invalid RIPng command %d", packet->command); break; } return 0;}/* Walk down the RIPng routing table then clear changed flag. */voidripng_clear_changed_flag (){ struct route_node *rp; struct ripng_info *rinfo; for (rp = route_top (ripng->table); rp; rp = route_next (rp)) if ((rinfo = rp->info) != NULL) if (rinfo->flags & RIPNG_RTF_CHANGED) rinfo->flags &= ~RIPNG_RTF_CHANGED;}/* Regular update of RIPng route. Send all routing formation to RIPng enabled interface. */intripng_update (struct thread *t){ listnode node; struct interface *ifp; struct ripng_interface *ri; /* Clear update timer thread. */ ripng->t_update = NULL; /* Logging update event. */ if (IS_RIPNG_DEBUG_EVENT) zlog_info ("RIPng update timer expired!"); /* Supply routes to each interface. */ for (node = listhead (iflist); node; nextnode (node)) { ifp = getdata (node); ri = ifp->info; if (if_is_loopback (ifp) || ! if_is_up (ifp)) continue; if (! ri->running) continue; /* When passive interface is specified, suppress announce to the interface. */ if (ri->passive) continue;#if RIPNG_ADVANCED if (ri->ri_send == RIPNG_SEND_OFF) { if (IS_RIPNG_DEBUG_EVENT) zlog (NULL, LOG_INFO, "[Event] RIPng send to if %d is suppressed by config", ifp->ifindex); continue; }#endif /* RIPNG_ADVANCED */ ripng_output_process (ifp, NULL, ripng_all_route, ripng_split_horizon); } /* Triggered updates may be suppressed if a regular update is due by the time the triggered update would be sent. */ if (ripng->t_triggered_interval) { thread_cancel (ripng->t_triggered_interval); ripng->t_triggered_interval = NULL; } ripng->trigger = 0; /* Reset flush event. */ ripng_event (RIPNG_UPDATE_EVENT, 0); return 0;}/* Triggered update interval timer. */intripng_triggered_interval (struct thread *t){ ripng->t_triggered_interval = NULL; if (ripng->trigger) { ripng->trigger = 0; ripng_triggered_update (t); } return 0;} /* Execute triggered update. */intripng_triggered_update (struct thread *t){ listnode node; struct interface *ifp; struct ripng_interface *ri; int interval; ripng->t_triggered_update = NULL; /* Cancel interval timer. */ if (ripng->t_triggered_interval) { thread_cancel (ripng->t_triggered_interval); ripng->t_triggered_interval = NULL; } ripng->trigger = 0; /* Logging triggered update. */ if (IS_RIPNG_DEBUG_EVENT) zlog_info ("RIPng triggered update!"); /* Split Horizon processing is done when generating triggered updates as well as normal updates (see section 2.6). */ for (node = listhead (iflist); node; nextnode (node)) { ifp = getdata (node); ri = ifp->info; if (if_is_loopback (ifp) || ! if_is_up (ifp)) continue; if (! ri->running) continue; /* When passive interface is specified, suppress announce to the interface. */ if (ri->passive) continue; ripng_output_process (ifp, NULL, ripng_changed_route, ripng_split_horizon); } /* Once all of the triggered updates have been generated, the route change flags should be cleared. */ ripng_clear_changed_flag (); /* After a triggered update is sent, a timer should be set for a random interval between 1 and 5 seconds. If other changes that would trigger updates occur before the timer expires, a single update is triggered when the timer expires. */ interval = (random () % 5) + 1; ripng->t_triggered_interval = thread_add_timer (master, ripng_triggered_interval, NULL, interval); return 0;}/* Write routing table entry to the stream and return next index of the routing table entry in the stream. */intripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p, u_int16_t tag, u_char metric){ /* RIPng packet header. */ if (num == 0) { stream_putc (s, RIPNG_RESPONSE); stream_putc (s, RIPNG_V1); stream_putw (s, 0); } /* Write routing table entry. */ stream_write (s, (caddr_t) &p->prefix, sizeof (struct in6_addr)); stream_putw (s, tag); stream_putc (s, p->prefixlen); stream_putc (s, metric); return ++num;}/* Send RESPONSE message to specified destination. */voidripng_output_process (struct interface *ifp, struct sockaddr_in6 *to, int route_type, int split_horizon){ int ret; struct stream *s; struct route_node *rp; struct ripng_info *rinfo; struct ripng_interface *ri; struct ripng_aggregate *aggregate; struct prefix_ipv6 *p; int num; int mtu; int rtemax; u_char metric; u_char metric_set; if (IS_RIPNG_DEBUG_EVENT) zlog_info ("RIPng update routes on interface %s", ifp->name); /* Output stream get from ripng structre. XXX this should be interface structure. */ s = ripng->obuf; /* Reset stream and RTE counter. */ stream_reset (s); num = 0; mtu = ifp->mtu; if (mtu < 0) mtu = IFMINMTU; rtemax = (min (mtu, RIPNG_MAX_PACKET_SIZE) - IPV6_HDRLEN - sizeof (struct udphdr) - sizeof (struct ripng_packet) + sizeof (struct rte)) / sizeof (struct rte);#ifdef DEBUG zlog_info ("DEBUG RIPng: ifmtu is %d", ifp->mtu); zlog_info ("DEBUG RIPng: rtemax is %d", rtemax);#endif /* DEBUG */ /* Get RIPng interface. */ ri = ifp->info; for (rp = route_top (ripng->table); rp; rp = route_next (rp)) { if ((rinfo = rp->info) != NULL && rinfo->suppress == 0) { p = (struct prefix_ipv6 *) &rp->p; metric = rinfo->metric; /* Changed route only output. */ if (route_type == ripng_changed_route && (! (rinfo->flags & RIPNG_RTF_CHANGED))) continue; /* Split horizon. */ if (split_horizon == ripng_split_horizon && rinfo->ifindex == ifp->ifindex) continue; /* Apply output filters.*/ if (ri->list[RIPNG_FILTER_OUT]) { if (access_list_apply (ri->list[RIPNG_FILTER_OUT], (struct prefix *) p) == FILTER_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_info ("RIPng %s/%d is filtered by distribute out", inet6_ntop (&p->prefix), p->prefixlen); continue; } } if (ri->prefix[RIPNG_FILTER_OUT]) { if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT], (struct prefix *) p) == PREFIX_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_info ("RIPng %s/%d is filtered by prefix-list out", inet6_ntop (&p->prefix), p->prefixlen); continue; } } /* Preparation for route-map. */ metric_set = 0; /* Route-map */ if (ri->routemap[RIPNG_FILTER_OUT]) { int ret; struct ripng_info newinfo; memset (&newinfo, 0, sizeof (struct ripng_info)); newinfo.metric = metric; ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT], (struct prefix *) p, RMAP_RIPNG, &newinfo); if (ret == RMAP_DENYMATCH) { if (IS_RIPNG_DEBUG_PACKET) zlog_info ("RIPng %s/%d is filtered by route-map out", inet6_ntop (&p->prefix), p->prefixlen); return; } metric = newinfo.metric; metric_set = newinfo.metric_set; } /* When the interface route-map does not set metric */ if (! metric_set) { /* and the redistribute route-map is set. */ if (ripng->route_map[rinfo->type].name) { int ret; struct ripng_info newinfo; memset (&newinfo, 0, sizeof (struct ripng_info)); newinfo.metric = metric; ret = route_map_apply (ripng->route_map[rinfo->type].map, (struct prefix *) p, RMAP_RIPNG, &newinfo); if (ret == RMAP_DENYMATCH) { if (IS_RIPNG_DEBUG_PACKET) zlog_info ("RIPng %s/%d is filtered by route-map", inet6_ntop (&p->prefix), p->prefixlen); continue; } metric = newinfo.metric; metric_set = newinfo.metric_set; } /* When the redistribute route-map does not set metric. */ if (! metric_set) { /* If the redistribute metric is set. */ if (ripng->route_map[rinfo->type].metric_config && rinfo->metric != RIPNG_METRIC_INFINITY) { metric = ripng->route_map[rinfo->type].metric; } else { /* If the route is not connected or localy generated one, use default-metric value */ if (rinfo->type != ZEBRA_ROUTE_RIPNG && rinfo->type != ZEBRA_ROUTE_CONNECT && rinfo->metric != RIPNG_METRIC_INFINITY) metric = ripng->default_metric; } } } /* Write RTE to the stream. */ num = ripng_write_rte (num, s, p, rinfo->tag, metric); if (num == rtemax) { ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifp); if (ret >= 0 && IS_RIPNG_DEBUG_SEND) ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s), stream_get_endp(s), "SEND"); num = 0; stream_reset (s); } } if ((aggregate = rp->aggregate) != NULL && aggregate->count > 0 && aggregate->suppress == 0) { p = (struct prefix_ipv6 *) &rp->p; metric = aggregate->metric; /* Apply output filters.*/ if (ri->list[RIPNG_FILTER_OUT]) { if (access_list_apply (ri->list[RIPNG_FILTER_OUT], (struct prefix *) p) == FILTER_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_info ("RIPng %s/%d is filtered by distribute out", inet6_ntop (&p->prefix), p->prefixlen); continue; } } if (ri->prefix[RIPNG_FILTER_OUT]) { if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT], (struct prefix *) p) == PREFIX_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_info ("RIPng %s/%d is filtered by prefix-list out", inet6_ntop (&p->prefix), p->prefixlen); continue; } } /* Route-map */ if (ri->routemap[RIPNG_FILTER_OUT]) { int ret; struct ripng_info newinfo; memset (&newinfo, 0, sizeof (struct ripng_info)); newinfo.metric = metric; ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT], (struct prefix *) p, RMAP_RIPNG, &newinfo); if (ret == RMAP_DENYMATCH) { if (IS_RIPNG_DEBUG_PACKET) zlog_info ("RIPng %s/%d is filtered by route-map out", inet6_ntop (&p->prefix), p->prefixlen); return; } metric = newinfo.metric; } /* Changed route only output. */ if (route_type == ripng_changed_route) continue; /* Write RTE to the stream. */ num = ripng_write_rte (num, s, p, aggregate->tag, metric); if (num == rtemax) { ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifp); if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -