194 lines
6.3 KiB
C
194 lines
6.3 KiB
C
/*
|
|
Copyright (c) 2013, Matthias Schiffer <mschiffer@universe-factory.net>
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation
|
|
and/or other materials provided with the distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
|
|
#ifndef _GMRF_PROTO_BABEL_BABEL_H_
|
|
#define _GMRF_PROTO_BABEL_BABEL_H_
|
|
|
|
#include "types.h"
|
|
|
|
|
|
#define GP_BABEL_INFINITY 0xffff
|
|
|
|
#define GP_BABEL_PACKET_MAX 1000
|
|
|
|
#define GP_BABEL_HELLO_INTERVAL 400
|
|
#define GP_BABEL_IHU_INTERVAL (3*GP_BABEL_HELLO_INTERVAL)
|
|
|
|
#define GP_BABEL_UPDATE_INTERVAL 3000
|
|
|
|
#define GP_BABEL_HELLO_TIMEOUT(interval) (16*(interval))
|
|
#define GP_BABEL_IHU_TIMEOUT(interval) ((interval)*7/2)
|
|
#define GP_BABEL_UPDATE_TIMEOUT(interval) ((interval)*7/2) /* 3.5 intervals */
|
|
#define GP_BABEL_UPDATE_REQUEST_TIMEOUT(interval) ((interval)*13/4) /* 3.25 intervals */
|
|
|
|
#define GP_BABEL_MAINTENANCE_INTERVAL GP_BABEL_HELLO_INTERVAL
|
|
|
|
|
|
#define GP_BABEL_SEQNO_REQ_HOP_LIMIT 127
|
|
|
|
|
|
#define GP_BABEL_UPDATE_FLAG_HAS_PAYLOAD 0x01
|
|
#define GP_BABEL_ANNOUCE_REQ_FLAG_WITH_PAYLOAD 0x01
|
|
|
|
|
|
struct gmrf_context {
|
|
gmrf_t *gmrf;
|
|
|
|
gp_babel_node_id_t self;
|
|
|
|
gmrf_iface_state_t *interfaces;
|
|
gp_babel_neigh_t *neighbours;
|
|
|
|
gp_babel_announce_t *announces;
|
|
};
|
|
|
|
struct gmrf_iface_state {
|
|
gmrf_iface_state_t *next;
|
|
|
|
gmrf_iface_t *gmrf_iface;
|
|
|
|
uint16_t seqno;
|
|
|
|
gp_babel_neigh_t *neighbours;
|
|
};
|
|
|
|
struct gp_babel_neigh {
|
|
gp_babel_neigh_t *next;
|
|
|
|
unsigned ref;
|
|
|
|
gmrf_iface_state_t *iface;
|
|
gmrf_addr_t addr;
|
|
|
|
uint16_t hello_log;
|
|
uint16_t hello_interval;
|
|
uint16_t last_seqno;
|
|
gmrf_time_t last_hello;
|
|
|
|
uint16_t ihu_interval;
|
|
gmrf_time_t last_ihu;
|
|
|
|
uint16_t txcost;
|
|
};
|
|
|
|
struct gp_babel_announce {
|
|
gp_babel_announce_t *next;
|
|
|
|
gp_babel_node_id_t node;
|
|
uint16_t type;
|
|
uint16_t key;
|
|
|
|
gp_babel_metric_seqno_t metric;
|
|
uint16_t last_metric;
|
|
gp_babel_metric_seqno_t feasibility_distance;
|
|
|
|
gp_babel_nexthop_t *selected;
|
|
gp_babel_nexthop_t *nexthops;
|
|
|
|
/* an incomplete announcement is specified by a len value of 0xff with NULL payload */
|
|
uint8_t len;
|
|
uint8_t *payload;
|
|
};
|
|
|
|
struct gp_babel_nexthop {
|
|
gp_babel_nexthop_t *next;
|
|
|
|
gp_babel_neigh_t *neigh;
|
|
gp_babel_metric_seqno_t metric_seqno;
|
|
|
|
gmrf_time_t last_update;
|
|
uint16_t interval;
|
|
bool requested_update;
|
|
};
|
|
|
|
|
|
void gp_babel_handle_packet(gmrf_context_t *ctx, gmrf_iface_state_t *iface, const gmrf_addr_t *source, const gp_babel_packet_t *packet);
|
|
|
|
void gp_babel_send_ack(gmrf_context_t *ctx, gp_babel_neigh_t *neigh, uint16_t nonce);
|
|
void gp_babel_send_hellos(gmrf_context_t *ctx);
|
|
|
|
void gp_babel_send_update(gmrf_context_t *ctx, gmrf_iface_state_t *iface, gp_babel_neigh_t *neigh, gp_babel_announce_t *announce, bool with_payload);
|
|
|
|
void gp_babel_send_announce_request(gmrf_context_t *ctx, gmrf_iface_state_t *iface, gp_babel_neigh_t *neigh, const gp_babel_node_id_t *node, uint16_t type, uint16_t key, bool with_payload);
|
|
void gp_babel_send_seqno_request(gmrf_context_t *ctx, gp_babel_neigh_t *neigh, gp_babel_announce_t *announce, uint16_t seqno, uint8_t hop_count);
|
|
|
|
gp_babel_announce_t* gp_babel_announce_new(gmrf_context_t *ctx);
|
|
gp_babel_announce_t* gp_babel_announce_find(gmrf_context_t *ctx, const gp_babel_node_id_t *node, uint16_t type, uint16_t key);
|
|
gp_babel_announce_t* gp_babel_announce_get(gmrf_context_t *ctx, const gp_babel_node_id_t *node, uint16_t type, uint16_t key);
|
|
void gp_babel_announce_update(gmrf_context_t *ctx, gp_babel_announce_t *announce);
|
|
void gp_babel_announce_free(gmrf_context_t *ctx, gp_babel_announce_t *announce);
|
|
|
|
gp_babel_nexthop_t* gp_babel_announce_nexthop_new(gp_babel_announce_t *announce, gp_babel_neigh_t *neigh);
|
|
gp_babel_nexthop_t* gp_babel_announce_nexthop_find(const gp_babel_announce_t *announce, gp_babel_neigh_t *neigh);
|
|
void gp_babel_announce_update_nexthop(gmrf_context_t *ctx, gp_babel_announce_t *announce, gp_babel_nexthop_t *nexthop, gp_babel_metric_seqno_t ms, uint16_t interval);
|
|
|
|
|
|
static inline bool gp_babel_node_id_equal(const gp_babel_node_id_t *id1, const gp_babel_node_id_t *id2) {
|
|
return (memcmp(id1->id, id2->id, GP_BABEL_NODE_ID_LENGTH) == 0);
|
|
}
|
|
|
|
static inline bool gp_babel_node_id_is_unspec(const gp_babel_node_id_t *id) {
|
|
return gp_babel_node_id_equal(id, &gp_babel_node_id_unspec);
|
|
};
|
|
|
|
static inline bool gp_babel_less(uint16_t a, uint16_t b) {
|
|
int16_t diff = a - b;
|
|
|
|
return (diff < 0);
|
|
}
|
|
|
|
static inline bool gp_babel_is_metric_better(gp_babel_metric_seqno_t ms1, gp_babel_metric_seqno_t ms2) {
|
|
if (ms1.metric == GP_BABEL_INFINITY)
|
|
return false;
|
|
|
|
if (ms2.metric == GP_BABEL_INFINITY)
|
|
return true;
|
|
|
|
int16_t seqno_diff = ms2.seqno - ms1.seqno;
|
|
|
|
if (seqno_diff < 0)
|
|
return true;
|
|
if (seqno_diff == 0 && ms1.metric < ms2.metric)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
static inline bool gp_babel_is_feasible(const gp_babel_announce_t *announce, gp_babel_metric_seqno_t ms) {
|
|
if (ms.metric == GP_BABEL_INFINITY)
|
|
return true;
|
|
|
|
return gp_babel_is_metric_better(ms, announce->feasibility_distance);
|
|
}
|
|
|
|
static inline void gp_babel_send_seqno_request_for(gmrf_context_t *ctx, gp_babel_neigh_t *neigh, gp_babel_announce_t *announce) {
|
|
if (announce->feasibility_distance.metric == GP_BABEL_INFINITY)
|
|
return;
|
|
|
|
gp_babel_send_seqno_request(ctx, neigh, announce, announce->feasibility_distance.seqno+1, GP_BABEL_SEQNO_REQ_HOP_LIMIT);
|
|
}
|
|
|
|
#endif /* _GMRF_PROTO_BABEL_BABEL_H_ */
|