1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/net/routing/aodvv2/aodv.c
Lotte Steenbrink 0c67c02047 Add the AODVv2 Routing Protocol
This PR depends on #1766.

It contains a minimal implementation of the AODVv2 routing protocol.
*Not* implemented are:

	- AckReqs
	- alternate metrics
	- multiple interfaces
	- clients and Client Networks
	- buffering
	- all addresses, TLVs, and features that are marked as optional

An example application can be found at https://github.com/Lotterleben/RIOT-AODVv2/tree/master/aodvv2_demo.

The implementation relies heavily on a functioning Neighbor Discovery Protocol.
It might be necessary to fill the neighbor cache manually with the current state
of RIOTs NDP implementation.

The value of AODVV2_MAX_UNREACHABLE_NODES has been chosen arbitrarily and will be subject to
future improvement.

Please note that based on my experience, with the default transceiver
buffer size (3) of the native port, about 2/3 of the route discoveries
will fail. This has been addressed in issue #1747. It is advised to increase
the transceiver buffer size when using AODVv2 as a routing protocol.
2014-11-27 03:50:20 -08:00

479 lines
16 KiB
C

/*
* Copyright (C) 2014 Freie Universität Berlin
* Copyright (C) 2014 Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup aodvv2
* @{
*
* @file aodv.c
* @brief aodvv2 routing protocol
*
* @author Lotte Steenbrink <lotte.steenbrink@fu-berlin.de>
*/
#include "debug.h"
#include "aodv.h"
#include "aodvv2/aodvv2.h"
#include "aodv_debug.h"
#define ENABLE_DEBUG (0)
#define UDP_BUFFER_SIZE (128) /** with respect to IEEE 802.15.4's MTU */
#define RCV_MSG_Q_SIZE (32) /* TODO: check if smaller values work, too */
static void _init_addresses(void);
static void _init_sock_snd(void);
static void *_aodv_receiver_thread(void *arg);
static void *_aodv_sender_thread(void *arg);
static void _deep_free_msg_container(struct msg_container *msg_container);
static void _write_packet(struct rfc5444_writer *wr __attribute__ ((unused)),
struct rfc5444_writer_target *iface __attribute__((unused)),
void *buffer, size_t length);
#ifdef DEBUG_ENABLED
char addr_str[IPV6_MAX_ADDR_STR_LEN];
static struct netaddr_str nbuf;
#endif
static char aodv_rcv_stack_buf[KERNEL_CONF_STACKSIZE_MAIN];
static char aodv_snd_stack_buf[KERNEL_CONF_STACKSIZE_MAIN];
static aodvv2_metric_t _metric_type;
static int sender_thread;
static int _sock_snd;
static struct autobuf _hexbuf;
static sockaddr6_t sa_wp;
static ipv6_addr_t _v6_addr_local, _v6_addr_mcast, _v6_addr_loopback;
static struct netaddr na_local; /* the same as _v6_addr_local, but to save us
* constant calls to ipv6_addr_t_to_netaddr()... */
static struct writer_target *wt;
struct netaddr na_mcast = (struct netaddr){};
void aodv_init(void)
{
AODV_DEBUG("%s()\n", __func__);
/* TODO: set if_id properly */
int if_id = 0;
net_if_set_src_address_mode(if_id, NET_IF_TRANS_ADDR_M_SHORT);
aodv_set_metric_type(AODVV2_DEFAULT_METRIC_TYPE);
_init_addresses();
_init_sock_snd();
/* init ALL the things! \o, */
seqnum_init();
routingtable_init();
clienttable_init();
/* every node is its own client. */
clienttable_add_client(&na_local);
rreqtable_init();
/* init reader and writer */
aodv_packet_reader_init();
aodv_packet_writer_init(_write_packet);
/* start listening & enable sending */
thread_create(aodv_rcv_stack_buf, sizeof(aodv_rcv_stack_buf), PRIORITY_MAIN,
CREATE_STACKTEST, _aodv_receiver_thread, NULL, "_aodv_receiver_thread");
AODV_DEBUG("listening on port %d\n", HTONS(MANET_PORT));
sender_thread = thread_create(aodv_snd_stack_buf, sizeof(aodv_snd_stack_buf),
PRIORITY_MAIN, CREATE_STACKTEST, _aodv_sender_thread,
NULL, "_aodv_sender_thread");
/* register aodv for routing */
ipv6_iface_set_routing_provider(aodv_get_next_hop);
}
void aodv_set_metric_type(aodvv2_metric_t metric_type)
{
if (metric_type != AODVV2_DEFAULT_METRIC_TYPE) {
return;
}
_metric_type = metric_type;
}
void aodv_send_rreq(struct aodvv2_packet_data *packet_data)
{
AODV_DEBUG("%s()\n", __func__);
struct aodvv2_packet_data *pd = malloc(sizeof(struct aodvv2_packet_data));
memcpy(pd, packet_data, sizeof(struct aodvv2_packet_data));
struct rreq_rrep_data *rd = malloc(sizeof(struct rreq_rrep_data));
*rd = (struct rreq_rrep_data) {
.next_hop = &na_mcast,
.packet_data = pd,
};
struct msg_container *mc = malloc(sizeof(struct msg_container));
*mc = (struct msg_container) {
.type = RFC5444_MSGTYPE_RREQ,
.data = rd
};
msg_t msg;
msg.content.ptr = (char *) mc;
msg_try_send(&msg, sender_thread);
}
void aodv_send_rrep(struct aodvv2_packet_data *packet_data, struct netaddr *next_hop)
{
AODV_DEBUG("%s()\n", __func__);
struct aodvv2_packet_data *pd = malloc(sizeof(struct aodvv2_packet_data));
memcpy(pd, packet_data, sizeof(struct aodvv2_packet_data));
struct netaddr *nh = malloc(sizeof(struct netaddr));
memcpy(nh, next_hop, sizeof(struct netaddr));
struct rreq_rrep_data *rd = malloc(sizeof(struct rreq_rrep_data));
*rd = (struct rreq_rrep_data) {
.next_hop = nh,
.packet_data = pd,
};
struct msg_container *mc = malloc(sizeof(struct msg_container));
*mc = (struct msg_container) {
.type = RFC5444_MSGTYPE_RREP,
.data = rd
};
msg_t msg;
msg.content.ptr = (char *) mc;
msg_try_send(&msg, sender_thread);
}
void aodv_send_rerr(struct unreachable_node unreachable_nodes[], size_t len, struct netaddr *next_hop)
{
AODV_DEBUG("%s()\n", __func__);
struct rerr_data *rerrd = malloc(sizeof(struct rerr_data));
*rerrd = (struct rerr_data) {
.unreachable_nodes = unreachable_nodes,
.len = len,
.hoplimit = AODVV2_MAX_HOPCOUNT,
.next_hop = next_hop
};
struct msg_container *mc2 = malloc(sizeof(struct msg_container));
*mc2 = (struct msg_container) {
.type = RFC5444_MSGTYPE_RERR,
.data = rerrd
};
msg_t msg2;
msg2.content.ptr = (char *) mc2;
msg_try_send(&msg2, sender_thread);
}
/*
* init the multicast address all RREQ and RERRS are sent to
* and the local address (source address) of this node
*/
static void _init_addresses(void)
{
/* init multicast address: set to to a link-local all nodes multicast address */
ipv6_addr_set_all_nodes_addr(&_v6_addr_mcast);
AODV_DEBUG("my multicast address is: %s\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &_v6_addr_mcast));
/* get best IP for sending */
ipv6_net_if_get_best_src_addr(&_v6_addr_local, &_v6_addr_mcast);
AODV_DEBUG("my src address is: %s\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &_v6_addr_local));
/* store src & multicast address as netaddr as well for easy interaction
* with oonf based stuff */
ipv6_addr_t_to_netaddr(&_v6_addr_local, &na_local);
ipv6_addr_t_to_netaddr(&_v6_addr_mcast, &na_mcast);
ipv6_addr_set_loopback_addr(&_v6_addr_loopback);
/* init sockaddr that write_packet will use to send data */
sa_wp.sin6_family = AF_INET6;
sa_wp.sin6_port = HTONS(MANET_PORT);
}
/* init socket communication for sender */
static void _init_sock_snd(void)
{
_sock_snd = socket_base_socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (-1 == _sock_snd) {
AODV_DEBUG("Error Creating Socket!\n");
}
}
/* Build RREQs, RREPs and RERRs from the information contained in the thread's
* message queue and send them */
static void *_aodv_sender_thread(void *arg)
{
(void) arg;
msg_t msgq[RCV_MSG_Q_SIZE];
msg_init_queue(msgq, sizeof msgq);
AODV_DEBUG("_aodv_sender_thread initialized.\n");
while (true) {
AODV_DEBUG("%s()\n", __func__);
msg_t msg;
msg_receive(&msg);
struct msg_container *mc = (struct msg_container *) msg.content.ptr;
if (mc->type == RFC5444_MSGTYPE_RREQ) {
struct rreq_rrep_data *rreq_data = (struct rreq_rrep_data *) mc->data;
aodv_packet_writer_send_rreq(rreq_data->packet_data, rreq_data->next_hop);
}
else if (mc->type == RFC5444_MSGTYPE_RREP) {
struct rreq_rrep_data *rrep_data = (struct rreq_rrep_data *) mc->data;
aodv_packet_writer_send_rrep(rrep_data->packet_data, rrep_data->next_hop);
}
else if (mc->type == RFC5444_MSGTYPE_RERR) {
struct rerr_data *rerr_data = (struct rerr_data *) mc->data;
aodv_packet_writer_send_rerr(rerr_data->unreachable_nodes, rerr_data->len,
rerr_data->hoplimit, rerr_data->next_hop);
}
else {
DEBUG("ERROR: Couldn't identify Message\n");
}
_deep_free_msg_container(mc);
}
return NULL;
}
/* receive RREQs, RREPs and RERRs and handle them */
static void *_aodv_receiver_thread(void *arg)
{
(void) arg;
AODV_DEBUG("%s()\n", __func__);
uint32_t fromlen;
char buf_rcv[UDP_BUFFER_SIZE];
msg_t msg_q[RCV_MSG_Q_SIZE];
msg_init_queue(msg_q, RCV_MSG_Q_SIZE);
sockaddr6_t sa_rcv = { .sin6_family = AF_INET6,
.sin6_port = HTONS(MANET_PORT)
};
int sock_rcv = socket_base_socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (-1 == socket_base_bind(sock_rcv, &sa_rcv, sizeof(sa_rcv))) {
DEBUG("Error: bind to receive socket failed!\n");
socket_base_close(sock_rcv);
}
AODV_DEBUG("ready to receive data\n");
while (true) {
int32_t rcv_size = socket_base_recvfrom(sock_rcv, (void *)buf_rcv, UDP_BUFFER_SIZE, 0,
&sa_rcv, &fromlen);
if (rcv_size < 0) {
AODV_DEBUG("ERROR receiving data!\n");
}
AODV_DEBUG("_aodv_receiver_thread() %s:",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &_v6_addr_local));
DEBUG(" UDP packet received from %s\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &sa_rcv.sin6_addr));
struct netaddr _sender;
ipv6_addr_t_to_netaddr(&sa_rcv.sin6_addr, &_sender);
/* For some reason we sometimes get passed our own packets. drop them. */
if (netaddr_cmp(&_sender, &na_local) == 0) {
AODV_DEBUG("received our own packet, dropping it.\n");
aodv_packet_reader_handle_packet((void *) buf_rcv, rcv_size, &_sender);
}
}
socket_base_close(sock_rcv);
return NULL;
}
ipv6_addr_t *aodv_get_next_hop(ipv6_addr_t *dest)
{
AODV_DEBUG("aodv_get_next_hop() %s:",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &_v6_addr_local));
DEBUG(" getting next hop for %s\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, dest));
struct netaddr _tmp_dest;
ipv6_addr_t_to_netaddr(dest, &_tmp_dest);
timex_t now;
struct unreachable_node unreachable_nodes[AODVV2_MAX_UNREACHABLE_NODES];
size_t len;
/* The network stack sometimes asks us for the next hop towards our own IP */
if (memcmp(dest, &_v6_addr_local, sizeof(ipv6_addr_t)) == 0) {
AODV_DEBUG("That's me, returning loopback\n");
return &_v6_addr_loopback;
}
/*
* TODO use ndp_neighbor_get_ll_address() as soon as it's available.
* note: delete check for active/stale/delayed entries, get_ll_address
* does that for us then
*/
ndp_neighbor_cache_t *ndp_nc_entry = ndp_neighbor_cache_search(dest);
struct aodvv2_routing_entry_t *rt_entry = routingtable_get_entry(&_tmp_dest, _metric_type);
if (ndp_nc_entry != NULL) {
/* Case 2: Broken Link (detected by lower layer) */
int link_broken = (ndp_nc_entry->state == NDP_NCE_STATUS_INCOMPLETE ||
ndp_nc_entry->state == NDP_NCE_STATUS_PROBE) &&
(rt_entry != NULL && rt_entry->state != ROUTE_STATE_BROKEN);
if (link_broken) {
DEBUG("\tNeighbor Cache entry found, but invalid (state: %i). Sending RERR.\n",
ndp_nc_entry->state);
/* mark all routes (active, idle, expired) that use next_hop as broken
* and add all *Active* routes to the list of unreachable nodes */
routingtable_break_and_get_all_hopping_over(&_tmp_dest, unreachable_nodes, &len);
aodv_send_rerr(unreachable_nodes, len, &na_mcast);
return NULL;
}
DEBUG("[aodvv2][ndp] found NC entry. Returning dest addr.\n");
return dest;
}
DEBUG("\t[ndp] no entry for addr %s found\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, dest));
if (rt_entry) {
/* Case 1: Undeliverable Packet */
int packet_indeliverable = rt_entry->state == ROUTE_STATE_BROKEN ||
rt_entry->state == ROUTE_STATE_EXPIRED;
if (packet_indeliverable) {
DEBUG("\tRouting table entry found, but invalid (state %i). Sending RERR.\n",
rt_entry->state);
unreachable_nodes[0].addr = _tmp_dest;
unreachable_nodes[0].seqnum = rt_entry->seqnum;
aodv_send_rerr(unreachable_nodes, 1, &na_mcast);
return NULL;
}
DEBUG("\tfound dest %s in routing table\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, dest));
vtimer_now(&now);
rt_entry->lastUsed = now;
if (rt_entry->state == ROUTE_STATE_IDLE) {
rt_entry->state = ROUTE_STATE_ACTIVE;
}
/* Currently, there is no way to do this, so I'm doing it the worst
* possible, but safe way: I can't make sure that the current call to
* aodv_get_next_hop() is overridden by another call to aodv_get_next_hop()
* by a thread with higher priority, thus messing up return values if I just
* use a static ipv6_addr_t.
* The following malloc will never be free()'d. TODO: FIX THIS ASAP.
*/
ipv6_addr_t *next_hop = (ipv6_addr_t *) malloc(sizeof(ipv6_addr_t));
netaddr_to_ipv6_addr_t(&rt_entry->nextHopAddr, next_hop);
return next_hop;
}
aodvv2_seqnum_t seqnum = seqnum_get();
seqnum_inc();
struct aodvv2_packet_data rreq_data = (struct aodvv2_packet_data) {
.hoplimit = AODVV2_MAX_HOPCOUNT,
.metricType = _metric_type,
.origNode = (struct node_data) {
.addr = na_local,
.metric = 0,
.seqnum = seqnum,
},
.targNode = (struct node_data) {
.addr = _tmp_dest,
},
.timestamp = (timex_t) {0,0} /* this timestamp is never used, it exists
* merely to make the compiler shut up */
};
DEBUG("\tNo route found towards %s, starting route discovery... \n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, dest));
aodv_send_rreq(&rreq_data);
return NULL;
}
/**
* Handle the output of the RFC5444 packet creation process. This callback is
* called by every writer_send_* function.
*/
static void _write_packet(struct rfc5444_writer *wr __attribute__ ((unused)),
struct rfc5444_writer_target *iface __attribute__((unused)),
void *buffer, size_t length)
{
AODV_DEBUG("%s()\n", __func__);
/* generate hexdump and human readable representation of packet
* and print to console */
abuf_hexdump(&_hexbuf, "\t", buffer, length);
rfc5444_print_direct(&_hexbuf, buffer, length);
DEBUG("%s", abuf_getptr(&_hexbuf));
abuf_clear(&_hexbuf);
/* fetch the address the packet is supposed to be sent to (i.e. to a
* specific node or the multicast address) from the writer_target struct
* iface* is stored in. This is a bit hacky, but it does the trick. */
wt = container_of(iface, struct writer_target, interface);
netaddr_to_ipv6_addr_t(&wt->target_addr, &sa_wp.sin6_addr);
/* When originating a RREQ, add it to our RREQ table/update its predecessor */
if (wt->type == RFC5444_MSGTYPE_RREQ
&& netaddr_cmp(&wt->packet_data.origNode.addr, &na_local) == 0) {
AODV_DEBUG("originating RREQ with SeqNum %d towards %s via %s; updating RREQ table...\n",
wt->packet_data.origNode.seqnum,
netaddr_to_string(&nbuf, &wt->packet_data.targNode.addr),
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &sa_wp.sin6_addr));
rreqtable_is_redundant(&wt->packet_data);
}
int bytes_sent = socket_base_sendto(_sock_snd, buffer, length,
0, &sa_wp, sizeof sa_wp);
(void) bytes_sent;
AODV_DEBUG("%d bytes sent.\n", bytes_sent);
}
/* free the matryoshka doll of cobbled-together structs that the sender_thread receives */
static void _deep_free_msg_container(struct msg_container *mc)
{
int type = mc->type;
if ((type == RFC5444_MSGTYPE_RREQ) || (type == RFC5444_MSGTYPE_RREP)) {
struct rreq_rrep_data *rreq_rrep_data = (struct rreq_rrep_data *) mc->data;
free(rreq_rrep_data->packet_data);
if (netaddr_cmp(rreq_rrep_data->next_hop, &na_mcast) != 0) {
free(rreq_rrep_data->next_hop);
}
}
else if (type == RFC5444_MSGTYPE_RERR) {
struct rerr_data *rerr_data = (struct rerr_data *) mc->data;
if (netaddr_cmp(rerr_data->next_hop, &na_mcast) != 0) {
free(rerr_data->next_hop);
}
}
free(mc->data);
free(mc);
}