123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- /* 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->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);
- 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);
- }
- }
|