bird/proto/babel/babel.h
2022-12-07 14:34:45 +08:00

481 lines
12 KiB
C

/*
* BIRD -- The Babel protocol
*
* Copyright (c) 2015--2016 Toke Hoiland-Jorgensen
* (c) 2016--2017 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2016--2017 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
* This file contains the data structures used by Babel.
*/
#ifndef _BIRD_BABEL_H_
#define _BIRD_BABEL_H_
#include "nest/bird.h"
#include "nest/cli.h"
#include "nest/iface.h"
#include "nest/route.h"
#include "nest/protocol.h"
#include "nest/locks.h"
#include "nest/password.h"
#include "lib/resource.h"
#include "lib/lists.h"
#include "lib/socket.h"
#include "lib/string.h"
#include "lib/timer.h"
#define EA_BABEL_METRIC EA_CODE(PROTOCOL_BABEL, 0)
#define EA_BABEL_ROUTER_ID EA_CODE(PROTOCOL_BABEL, 1)
#define BABEL_MAGIC 42
#define BABEL_VERSION 2
#define BABEL_PORT 6696
#define BABEL_INFINITY 0xFFFF
#define BABEL_HELLO_INTERVAL_WIRED (4 S_) /* Default hello intervals in seconds */
#define BABEL_HELLO_INTERVAL_WIRELESS (4 S_)
#define BABEL_HELLO_LIMIT 12
#define BABEL_UPDATE_INTERVAL_FACTOR 4
#define BABEL_IHU_INTERVAL_FACTOR 3
#define BABEL_HOLD_TIME_FACTOR 4 /* How long we keep unreachable route relative to update interval */
#define BABEL_IHU_EXPIRY_FACTOR(X) ((btime)(X)*7/2) /* 3.5 */
#define BABEL_HELLO_EXPIRY_FACTOR(X) ((btime)(X)*3/2) /* 1.5 */
#define BABEL_ROUTE_EXPIRY_FACTOR(X) ((btime)(X)*7/2) /* 3.5 */
#define BABEL_ROUTE_REFRESH_FACTOR(X) ((btime)(X)*5/2) /* 2.5 */
#define BABEL_SEQNO_REQUEST_RETRY 4
#define BABEL_SEQNO_REQUEST_EXPIRY (2 S_)
#define BABEL_GARBAGE_INTERVAL (300 S_)
#define BABEL_RXCOST_WIRED 96
#define BABEL_RXCOST_WIRELESS 256
#define BABEL_RXCOST_RTT 96
#define BABEL_INITIAL_HOP_COUNT 255
#define BABEL_MAX_SEND_INTERVAL 5 /* Unused ? */
#define BABEL_INITIAL_NEIGHBOR_TIMEOUT (60 S_)
#define BABEL_RTT_MAX_VALUE (600 S_)
#define BABEL_RTT_MIN (10 MS_)
#define BABEL_RTT_MAX (120 MS_)
#define BABEL_RTT_WINLEN 100
/*
* Constants for calculating metric smoothing. Chosen so that:
* log(2) = BABEL_SMOOTHING_CONSTANT / BABEL_SMOOTHING_UNIT, which means that
* log(2)/x can be calculated as BABEL_SMOOTHING_UNIT + BABEL_SMOOTHING_CONSTANT / x
*/
#define BABEL_SMOOTHING_UNIT 0x10000000
#define BABEL_SMOOTHING_CONSTANT 186065279
#define BABEL_SMOOTHING_STEP (1 S_) /* smoothing calculated in this step size */
#define BABEL_SMOOTHING_MIN_DIFF 4 /* metric diff beneath this is converged */
#define BABEL_SMOOTHING_DECAY (4 S_)
#define BABEL_SMOOTHING_DECAY_MAX (180 S_)
/* Max interval that will not overflow when carried as 16-bit centiseconds */
#define BABEL_TIME_UNITS 10000 /* On-wire times are counted in centiseconds */
#define BABEL_MIN_INTERVAL (0x0001 * BABEL_TIME_UNITS)
#define BABEL_MAX_INTERVAL (0xFFFF * BABEL_TIME_UNITS)
#define BABEL_OVERHEAD (IP6_HEADER_LENGTH+UDP_HEADER_LENGTH)
#define BABEL_MIN_MTU (512 + BABEL_OVERHEAD)
#define BABEL_AUTH_NONE 0
#define BABEL_AUTH_MAC 1
#define BABEL_AUTH_NONCE_LEN 10 /* we send 80 bit nonces */
#define BABEL_AUTH_MAX_NONCE_LEN 192 /* max allowed by spec */
#define BABEL_AUTH_INDEX_LEN 32 /* max size in spec */
#define BABEL_AUTH_CHALLENGE_TIMEOUT (30 S_)
#define BABEL_AUTH_CHALLENGE_INTERVAL (300 MS_) /* used for both challenges and replies */
enum babel_tlv_type {
BABEL_TLV_PAD1 = 0,
BABEL_TLV_PADN = 1,
BABEL_TLV_ACK_REQ = 2,
BABEL_TLV_ACK = 3,
BABEL_TLV_HELLO = 4,
BABEL_TLV_IHU = 5,
BABEL_TLV_ROUTER_ID = 6,
BABEL_TLV_NEXT_HOP = 7,
BABEL_TLV_UPDATE = 8,
BABEL_TLV_ROUTE_REQUEST = 9,
BABEL_TLV_SEQNO_REQUEST = 10,
BABEL_TLV_MAC = 16,
BABEL_TLV_PC = 17,
BABEL_TLV_CHALLENGE_REQUEST = 18,
BABEL_TLV_CHALLENGE_REPLY = 19,
BABEL_TLV_MAX
};
enum babel_subtlv_type {
BABEL_SUBTLV_PAD1 = 0,
BABEL_SUBTLV_PADN = 1,
BABEL_SUBTLV_DIVERSITY = 2, /* we don't support this */
BABEL_SUBTLV_TIMESTAMP = 3,
/* Mandatory subtlvs */
BABEL_SUBTLV_SOURCE_PREFIX = 128,
};
enum babel_iface_type {
/* In practice, UNDEF and WIRED give equivalent behaviour */
BABEL_IFACE_TYPE_UNDEF = 0,
BABEL_IFACE_TYPE_WIRED = 1,
BABEL_IFACE_TYPE_WIRELESS = 2,
BABEL_IFACE_TYPE_TUNNEL = 3,
BABEL_IFACE_TYPE_MAX
};
enum babel_ae_type {
BABEL_AE_WILDCARD = 0,
BABEL_AE_IP4 = 1,
BABEL_AE_IP6 = 2,
BABEL_AE_IP6_LL = 3,
BABEL_AE_MAX
};
struct babel_config {
struct proto_config c;
list iface_list; /* List of iface configs (struct babel_iface_config) */
btime metric_decay;
uint smooth_recp; /* Reciprocal for exponential metric smoothing */
uint hold_time; /* Time to hold stale entries and unreachable routes */
u8 randomize_router_id;
struct channel_config *ip4_channel;
struct channel_config *ip6_channel;
};
struct babel_iface_config {
struct iface_patt i;
u16 rxcost;
u8 type;
u8 limit; /* Minimum number of Hellos to keep link up */
u8 check_link;
uint port;
uint hello_interval; /* Hello interval, in us */
uint ihu_interval; /* IHU interval, in us */
uint update_interval; /* Update interval, in us */
btime rtt_min; /* rtt above which to start penalising metric */
btime rtt_max; /* max rtt metric penalty applied above this */
u16 rtt_cost; /* metric penalty to apply at rtt_max */
u16 rtt_win_len; /* smoothing windows length */
u8 rtt_send; /* whether to send timestamps on this interface */
u16 rx_buffer; /* RX buffer size, 0 for MTU */
u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */
int tx_tos;
int tx_priority;
ip_addr next_hop_ip4;
ip_addr next_hop_ip6;
u8 auth_type; /* Authentication type (BABEL_AUTH_*) */
u8 auth_permissive; /* Don't drop packets failing auth check */
uint mac_num_keys; /* Number of configured HMAC keys */
uint mac_total_len; /* Total digest length for all configured keys */
list *passwords; /* Passwords for authentication */
};
struct babel_proto {
struct proto p;
timer *timer;
struct fib ip4_rtable;
struct fib ip6_rtable;
struct channel *ip4_channel;
struct channel *ip6_channel;
list interfaces; /* Interfaces we really know about (struct babel_iface) */
u64 router_id;
u16 update_seqno; /* To be increased on request */
u8 update_seqno_inc; /* Request for update_seqno increase */
u8 triggered; /* For triggering global updates */
slab *route_slab;
slab *source_slab;
slab *msg_slab;
slab *seqno_slab;
struct tbf log_pkt_tbf; /* TBF for packet messages */
};
struct babel_iface {
node n;
struct babel_proto *proto;
struct iface *iface;
struct babel_iface_config *cf;
u8 up;
pool *pool;
char *ifname;
sock *sk;
ip_addr addr;
ip_addr next_hop_ip4;
ip_addr next_hop_ip6;
int tx_length;
list neigh_list; /* List of neighbors seen on this iface (struct babel_neighbor) */
list msg_queue;
u16 hello_seqno; /* To be increased on each hello */
u32 auth_pc;
int auth_tx_overhead;
u8 auth_index[BABEL_AUTH_INDEX_LEN];
btime next_hello;
btime next_regular;
btime next_triggered;
btime want_triggered;
timer *timer;
event *send_event;
};
struct babel_neighbor {
node n;
struct babel_iface *ifa;
ip_addr addr;
u16 rxcost; /* Sent in last IHU */
u16 txcost; /* Received in last IHU */
u16 cost; /* Computed neighbor cost */
s8 ihu_cnt; /* IHU countdown, 0 to send it */
u8 hello_cnt;
u16 hello_map;
u16 next_hello_seqno;
uint last_hello_int;
u32 last_tstamp;
btime last_tstamp_rcvd;
btime srtt;
btime *srtt_pool; // an array of btime
btime *srtt_pool_sorted;
u16 srtt_pool_len; // initial length
u16 srtt_poll_idx; // head
u32 auth_pc;
u8 auth_passed;
u8 auth_index_len;
u8 auth_index[BABEL_AUTH_INDEX_LEN];
u8 auth_nonce[BABEL_AUTH_NONCE_LEN];
btime auth_nonce_expiry;
btime auth_next_challenge;
btime auth_next_challenge_reply;
/* expiry timers */
btime hello_expiry;
btime ihu_expiry;
btime init_expiry;
list routes; /* Routes this neighbour has sent us (struct babel_route) */
list requests; /* Seqno requests bound to this neighbor */
};
struct babel_source {
node n;
u64 router_id;
u16 seqno;
u16 metric;
btime expires;
};
struct babel_route {
node n;
node neigh_route;
struct babel_entry *e;
struct babel_neighbor *neigh;
u8 feasible;
u16 seqno;
u16 metric;
u16 advert_metric;
u16 smoothed_metric;
u64 router_id;
ip_addr next_hop;
btime refresh_time;
btime smoothed_time;
btime expires;
};
struct babel_seqno_request {
node n;
node nbr_node;
u64 router_id;
u16 seqno;
u8 hop_count;
u8 count;
btime expires;
struct babel_neighbor *nbr;
};
struct babel_entry {
struct babel_route *selected;
list routes; /* Routes for this prefix (struct babel_route) */
list sources; /* Source entries for this prefix (struct babel_source). */
list requests;
u8 valid; /* Entry validity state (BABEL_ENTRY_*) */
u8 unreachable; /* Unreachable route is announced */
u16 seqno; /* Outgoing seqno */
u16 metric; /* Outgoing metric */
u64 router_id; /* Outgoing router ID */
btime updated; /* Last change of outgoing rte, for triggered updates */
struct fib_node n;
};
#define BABEL_ENTRY_DUMMY 0 /* No outgoing route */
#define BABEL_ENTRY_VALID 1 /* Valid outgoing route */
#define BABEL_ENTRY_STALE 2 /* Stale outgoing route, waiting for GC */
/*
* Internal TLV messages
*/
struct babel_msg_ack_req {
u8 type;
u16 nonce;
uint interval;
ip_addr sender;
};
struct babel_msg_ack {
u8 type;
u16 nonce;
};
struct babel_msg_hello {
u8 type;
u16 seqno;
uint interval;
ip_addr sender;
u32 tstamp;
btime pkt_received;
};
struct babel_msg_ihu {
u8 type;
u8 ae;
u16 rxcost;
uint interval;
ip_addr addr;
ip_addr sender;
u32 tstamp;
u32 tstamp_rcvd;
btime pkt_received;
};
struct babel_msg_update {
u8 type;
u8 wildcard;
uint interval;
u16 seqno;
u16 metric;
u64 router_id;
union {
net_addr net;
net_addr_ip6_sadr net_sadr;
};
ip_addr next_hop;
ip_addr sender;
};
struct babel_msg_route_request {
u8 type;
u8 full;
union {
net_addr net;
net_addr_ip6_sadr net_sadr;
};
};
struct babel_msg_seqno_request {
u8 type;
u8 hop_count;
u16 seqno;
u64 router_id;
union {
net_addr net;
net_addr_ip6_sadr net_sadr;
};
ip_addr sender;
};
struct babel_msg_challenge {
u8 type;
u8 nonce_len;
u8 *nonce;
};
union babel_msg {
u8 type;
struct babel_msg_ack_req ack_req;
struct babel_msg_ack ack;
struct babel_msg_hello hello;
struct babel_msg_ihu ihu;
struct babel_msg_update update;
struct babel_msg_route_request route_request;
struct babel_msg_seqno_request seqno_request;
struct babel_msg_challenge challenge;
};
struct babel_msg_node {
node n;
union babel_msg msg;
};
/* only used for auth checking, so not a part of union above */
struct babel_msg_auth {
ip_addr sender;
u32 pc;
u8 pc_seen;
u8 index_len;
u8 *index;
u8 challenge_reply_seen;
u8 challenge_reply[BABEL_AUTH_NONCE_LEN];
u8 challenge_seen;
u8 challenge_len;
u8 challenge[BABEL_AUTH_MAX_NONCE_LEN];
};
static inline int babel_sadr_enabled(struct babel_proto *p)
{ return p->ip6_rtable.addr_type == NET_IP6_SADR; }
/* babel.c */
void babel_handle_ack_req(union babel_msg *msg, struct babel_iface *ifa);
void babel_handle_ack(union babel_msg *msg, struct babel_iface *ifa);
void babel_handle_hello(union babel_msg *msg, struct babel_iface *ifa);
void babel_handle_ihu(union babel_msg *msg, struct babel_iface *ifa);
void babel_handle_router_id(union babel_msg *msg, struct babel_iface *ifa);
void babel_handle_update(union babel_msg *msg, struct babel_iface *ifa);
void babel_handle_route_request(union babel_msg *msg, struct babel_iface *ifa);
void babel_handle_seqno_request(union babel_msg *msg, struct babel_iface *ifa);
void babel_show_interfaces(struct proto *P, const char *iff);
void babel_show_neighbors(struct proto *P, const char *iff);
void babel_show_entries(struct proto *P);
void babel_show_routes(struct proto *P);
void babel_auth_reset_index(struct babel_iface *ifa);
int babel_auth_check_pc(struct babel_iface *ifa, struct babel_msg_auth *msg);
/* packets.c */
void babel_enqueue(union babel_msg *msg, struct babel_iface *ifa);
void babel_send_unicast(union babel_msg *msg, struct babel_iface *ifa, ip_addr dest);
int babel_open_socket(struct babel_iface *ifa);
void babel_send_queue(void *arg);
void babel_auth_set_tx_overhead(struct babel_iface *ifa);
#endif