| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include <zebra.h> |
| |
| |
| #include <netinet/udp.h> |
| |
| #include "linklist.h" |
| #include "stream.h" |
| #include "log.h" |
| #include "memory.h" |
| #include "vty.h" |
| #include "if.h" |
| #include "prefix.h" |
| |
| #include "ripngd/ripngd.h" |
| #include "ripngd/ripng_debug.h" |
| #include "ripngd/ripng_nexthop.h" |
| |
| DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_RTE_DATA, "RIPng rte data") |
| |
| #define DEBUG 1 |
| |
| #define min(a, b) ((a) < (b) ? (a) : (b)) |
| |
| struct ripng_rte_data { |
| struct prefix_ipv6 *p; |
| struct ripng_info *rinfo; |
| struct ripng_aggregate *aggregate; |
| }; |
| |
| void _ripng_rte_del(struct ripng_rte_data *A); |
| int _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B); |
| |
| #define METRIC_OUT(a) \ |
| ((a)->rinfo ? (a)->rinfo->metric_out : (a)->aggregate->metric_out) |
| #define NEXTHOP_OUT_PTR(a) \ |
| ((a)->rinfo ? &((a)->rinfo->nexthop_out) \ |
| : &((a)->aggregate->nexthop_out)) |
| #define TAG_OUT(a) ((a)->rinfo ? (a)->rinfo->tag_out : (a)->aggregate->tag_out) |
| |
| struct list *ripng_rte_new(void) |
| { |
| struct list *rte; |
| |
| rte = list_new(); |
| rte->cmp = (int (*)(void *, void *))_ripng_rte_cmp; |
| rte->del = (void (*)(void *))_ripng_rte_del; |
| |
| return rte; |
| } |
| |
| void ripng_rte_free(struct list *ripng_rte_list) |
| { |
| list_delete(&ripng_rte_list); |
| } |
| |
| |
| void _ripng_rte_del(struct ripng_rte_data *A) |
| { |
| XFREE(MTYPE_RIPNG_RTE_DATA, A); |
| } |
| |
| |
| |
| |
| |
| |
| int _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B) |
| { |
| return addr6_cmp(NEXTHOP_OUT_PTR(A), NEXTHOP_OUT_PTR(B)); |
| } |
| |
| |
| void ripng_rte_add(struct list *ripng_rte_list, struct prefix_ipv6 *p, |
| struct ripng_info *rinfo, struct ripng_aggregate *aggregate) |
| { |
| |
| struct ripng_rte_data *data; |
| |
| |
| assert(!rinfo || !aggregate); |
| |
| data = XMALLOC(MTYPE_RIPNG_RTE_DATA, sizeof(*data)); |
| data->p = p; |
| data->rinfo = rinfo; |
| data->aggregate = aggregate; |
| |
| listnode_add_sort(ripng_rte_list, data); |
| } |
| |
| |
| |
| void ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp, |
| struct sockaddr_in6 *to) |
| { |
| struct ripng_interface *ri = ifp->info; |
| struct ripng *ripng = ri->ripng; |
| struct ripng_rte_data *data; |
| struct listnode *node, *nnode; |
| |
| struct in6_addr last_nexthop; |
| struct in6_addr myself_nexthop; |
| |
| struct stream *s; |
| int num; |
| int mtu; |
| int rtemax; |
| int ret; |
| |
| |
| memset(&last_nexthop, 0, sizeof(last_nexthop)); |
| |
| |
| |
| |
| |
| memset(&myself_nexthop, 0, sizeof(myself_nexthop)); |
| |
| |
| |
| s = ripng->obuf; |
| |
| |
| stream_reset(s); |
| num = 0; |
| |
| mtu = ifp->mtu6; |
| 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); |
| |
| for (ALL_LIST_ELEMENTS(ripng_rte_list, node, nnode, data)) { |
| |
| if (!IPV6_ADDR_SAME(&last_nexthop, NEXTHOP_OUT_PTR(data))) { |
| |
| |
| |
| if (num == (rtemax - 1)) { |
| ret = ripng_send_packet((caddr_t)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 (!IN6_IS_ADDR_LINKLOCAL(NEXTHOP_OUT_PTR(data))) |
| last_nexthop = myself_nexthop; |
| else |
| last_nexthop = *NEXTHOP_OUT_PTR(data); |
| |
| num = ripng_write_rte(num, s, NULL, &last_nexthop, 0, |
| RIPNG_METRIC_NEXTHOP); |
| } else { |
| |
| if ((num == 0) |
| && !IPV6_ADDR_SAME(&last_nexthop, &myself_nexthop)) |
| num = ripng_write_rte(num, s, NULL, |
| &last_nexthop, 0, |
| RIPNG_METRIC_NEXTHOP); |
| } |
| num = ripng_write_rte(num, s, data->p, NULL, TAG_OUT(data), |
| METRIC_OUT(data)); |
| |
| if (num == rtemax) { |
| ret = ripng_send_packet((caddr_t)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 (num != 0) { |
| ret = ripng_send_packet((caddr_t)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"); |
| stream_reset(s); |
| } |
| } |