diff options
author | hasso <hasso> | 2003-05-25 17:10:12 +0000 |
---|---|---|
committer | hasso <hasso> | 2003-05-25 17:10:12 +0000 |
commit | a94434b69197e074569d7579126074e9cb7212a5 (patch) | |
tree | b63c34ee20e8e6b57796ee591d4569407140047d /ripngd/ripng_nexthop.c | |
parent | dd55f9eb73347cb2bb7f8dc0f8108b21a733c9b4 (diff) |
Ripngd part of 6Wind patch.
Diffstat (limited to 'ripngd/ripng_nexthop.c')
-rw-r--r-- | ripngd/ripng_nexthop.c | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/ripngd/ripng_nexthop.c b/ripngd/ripng_nexthop.c new file mode 100644 index 00000000..2c5d45cd --- /dev/null +++ b/ripngd/ripng_nexthop.c @@ -0,0 +1,216 @@ +/* RIPngd Zebra + * Copyright (C) 2002 6WIND <vincent.jardin@6wind.com> + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* This file is required in order to support properly the RIPng nexthop + * feature. + */ + +#include <zebra.h> + +/* For struct udphdr. */ +#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 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(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); +} + +/* Delete RTE */ +void +_ripng_rte_del(struct ripng_rte_data *A) { + XFREE(MTYPE_RIPNG_RTE_DATA, A); +} + +/* Compare RTE: + * return + if A > B + * 0 if A = B + * - if A < B + */ +int +_ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B) { + return addr6_cmp(&NEXTHOP_OUT(A), &NEXTHOP_OUT(B)); +} + +/* Add routing table entry */ +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; + + /* At least one should not be null */ + 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); +} + +/* Send the RTE with the nexthop support + */ +void +ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp, + struct sockaddr_in6 *to) { + + struct ripng_rte_data *data; + struct listnode * nn; + + struct in6_addr last_nexthop; + struct in6_addr myself_nexthop; + + struct stream *s; + int num; + int mtu; + int rtemax; + int ret; + + /* Most of the time, there is no nexthop */ + memset(&last_nexthop, 0, sizeof(last_nexthop)); + + /* Use myself_nexthop if the nexthop is not a link-local address, because + * we remain a right path without beeing the optimal one. + */ + memset(&myself_nexthop, 0, sizeof(myself_nexthop)); + + /* 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); + + LIST_LOOP(ripng_rte_list, data, nn) { + + /* (2.1) Next hop support */ + if (!IPV6_ADDR_SAME(&last_nexthop, &NEXTHOP_OUT(data))) { + + /* A nexthop entry should be at least followed by 1 RTE */ + if (num == (rtemax-1)) { + 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); + } + + /* Add the nexthop (2.1) */ + + /* If the received next hop address is not a link-local address, + * it should be treated as 0:0:0:0:0:0:0:0. + */ + if (!IN6_IS_ADDR_LINKLOCAL(&NEXTHOP_OUT(data))) + last_nexthop = myself_nexthop; + else + last_nexthop = NEXTHOP_OUT(data); + + num = ripng_write_rte(num, s, NULL, &last_nexthop, 0, RIPNG_METRIC_NEXTHOP); + } else { + /* Rewrite the nexthop for each new packet */ + 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 (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 unwritten RTE exist, flush it. */ + if (num != 0) { + 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); + } +} |