diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-09 13:16:35 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-09 13:16:35 +0000 |
commit | e2bbf175a2184bd76f6c54ccf8456babeb1a46fc (patch) | |
tree | f0b76550d6e6f500ada964a3a4ee933a45e5a6f1 /ripngd/ripng_nexthop.c | |
parent | Initial commit. (diff) | |
download | frr-e2bbf175a2184bd76f6c54ccf8456babeb1a46fc.tar.xz frr-e2bbf175a2184bd76f6c54ccf8456babeb1a46fc.zip |
Adding upstream version 9.1.upstream/9.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ripngd/ripng_nexthop.c')
-rw-r--r-- | ripngd/ripng_nexthop.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/ripngd/ripng_nexthop.c b/ripngd/ripng_nexthop.c new file mode 100644 index 0000000..38e7ce2 --- /dev/null +++ b/ripngd/ripng_nexthop.c @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* RIPngd Zebra + * Copyright (C) 2002 6WIND <vincent.jardin@6wind.com> + */ + +/* 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_MTYPE_STATIC(RIPNGD, RIPNG_RTE_DATA, "RIPng rte data"); + +#define DEBUG 1 + +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); +} + +/* 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_PTR(A), NEXTHOP_OUT_PTR(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_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; + + /* 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); + + for (ALL_LIST_ELEMENTS(ripng_rte_list, node, nnode, data)) { + /* (2.1) Next hop support */ + if (!IPV6_ADDR_SAME(&last_nexthop, NEXTHOP_OUT_PTR(data))) { + + /* A nexthop entry should be at least followed by 1 RTE + */ + 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); + } + + /* 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_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 { + /* 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((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 unwritten RTE exist, flush it. */ + 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); + } +} |