0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-23 10:11:53 +00:00

Core: Prepare for multicast

This commit is contained in:
Ondřej Hlavatý 2016-05-27 02:40:17 +02:00
parent 925aa14912
commit 76baa8b38a
15 changed files with 478 additions and 68 deletions

View File

@ -64,24 +64,6 @@ static inline int u64_cmp(u64 i1, u64 i2)
#define PACKED __attribute__((packed))
/* Microsecond time */
typedef s64 btime;
#define S_ *1000000
#define MS_ *1000
#define US_ *1
#define TO_S /1000000
#define TO_MS /1000
#define TO_US /1
#ifndef PARSER
#define S S_
#define MS MS_
#define US US_
#endif
/* Rate limiting */
struct tbf {

View File

@ -1,4 +1,5 @@
#ifndef BIRD_HASH_H
#define BIRD_HASH_H
#define HASH(type) struct { type **data; uint count, order; }
#define HASH_TYPE(v) typeof(** (v).data)
@ -212,3 +213,4 @@ mem_hash(void *p, int s)
return mem_hash_value(&h);
}
#endif

View File

@ -11,6 +11,10 @@ const char * const net_label[] = {
[NET_VPN6] = "vpn6",
[NET_ROA4] = "roa4",
[NET_ROA6] = "roa6",
[NET_MREQ4] = "mreq4",
[NET_MREQ6] = "mreq6",
[NET_MGRP4] = "mgrp4",
[NET_MGRP6] = "mgrp6",
};
const u16 net_addr_length[] = {
@ -19,7 +23,11 @@ const u16 net_addr_length[] = {
[NET_VPN4] = sizeof(net_addr_vpn4),
[NET_VPN6] = sizeof(net_addr_vpn6),
[NET_ROA4] = sizeof(net_addr_roa4),
[NET_ROA6] = sizeof(net_addr_roa6)
[NET_ROA6] = sizeof(net_addr_roa6),
[NET_MREQ4] = sizeof(net_addr_mreq4),
[NET_MREQ6] = sizeof(net_addr_mreq6),
[NET_MGRP4] = sizeof(net_addr_mgrp4),
[NET_MGRP6] = sizeof(net_addr_mgrp6),
};
const u8 net_max_prefix_length[] = {
@ -28,7 +36,11 @@ const u8 net_max_prefix_length[] = {
[NET_VPN4] = IP4_MAX_PREFIX_LENGTH,
[NET_VPN6] = IP6_MAX_PREFIX_LENGTH,
[NET_ROA4] = IP4_MAX_PREFIX_LENGTH,
[NET_ROA6] = IP6_MAX_PREFIX_LENGTH
[NET_ROA6] = IP6_MAX_PREFIX_LENGTH,
[NET_MREQ4] = IP4_MAX_PREFIX_LENGTH,
[NET_MREQ6] = IP6_MAX_PREFIX_LENGTH,
[NET_MGRP4] = IP4_MAX_PREFIX_LENGTH,
[NET_MGRP6] = IP6_MAX_PREFIX_LENGTH,
};
const u16 net_max_text_length[] = {
@ -38,6 +50,10 @@ const u16 net_max_text_length[] = {
[NET_VPN6] = 65, /* "4294967296:4294967296 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */
[NET_ROA4] = 34, /* "255.255.255.255/32-32 AS4294967295" */
[NET_ROA6] = 60, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128-128 AS4294967295" */
[NET_MREQ4] = 15, /* "255.255.255.255" */
[NET_MREQ6] = 39, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" */
[NET_MGRP4] = 15, /* "255.255.255.255" */
[NET_MGRP6] = 39, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" */
};
@ -60,6 +76,12 @@ net_format(const net_addr *N, char *buf, int buflen)
return bsnprintf(buf, buflen, "%I4/%u-%u AS%u", n->roa4.prefix, n->roa4.pxlen, n->roa4.max_pxlen, n->roa4.asn);
case NET_ROA6:
return bsnprintf(buf, buflen, "%I6/%u-%u AS%u", n->roa6.prefix, n->roa6.pxlen, n->roa6.max_pxlen, n->roa6.asn);
case NET_MREQ4:
case NET_MGRP4:
return bsnprintf(buf, buflen, "%I4", n->mgrp4.ga);
case NET_MREQ6:
case NET_MGRP6:
return bsnprintf(buf, buflen, "%I6", n->mgrp6.ga);
}
return 0;
@ -73,11 +95,15 @@ net_pxmask(const net_addr *a)
case NET_IP4:
case NET_VPN4:
case NET_ROA4:
case NET_MREQ4:
case NET_MGRP4:
return ipa_from_ip4(ip4_mkmask(net4_pxlen(a)));
case NET_IP6:
case NET_VPN6:
case NET_ROA6:
case NET_MREQ6:
case NET_MGRP6:
return ipa_from_ip6(ip6_mkmask(net6_pxlen(a)));
default:
@ -105,6 +131,12 @@ net_compare(const net_addr *a, const net_addr *b)
return net_compare_roa4((const net_addr_roa4 *) a, (const net_addr_roa4 *) b);
case NET_ROA6:
return net_compare_roa6((const net_addr_roa6 *) a, (const net_addr_roa6 *) b);
case NET_MREQ4:
case NET_MGRP4:
return net_compare_mgrp4((const net_addr_mgrp4 *) a, (const net_addr_mgrp4 *) b);
case NET_MREQ6:
case NET_MGRP6:
return net_compare_mgrp6((const net_addr_mgrp6 *) a, (const net_addr_mgrp6 *) b);
}
return 0;
}
@ -124,6 +156,13 @@ net_validate(const net_addr *N)
case NET_ROA6:
return net_validate_ip6((net_addr_ip6 *) N);
case NET_MREQ4:
case NET_MGRP4:
return ip4_classify(((net_addr_mgrp4 *) N)->ga) & IADDR_MULTICAST;
case NET_MREQ6:
case NET_MGRP6:
return ip6_classify(&((net_addr_mgrp6 *) N)->ga) & IADDR_MULTICAST;
default:
return 0;
}
@ -164,6 +203,13 @@ net_classify(const net_addr *N)
case NET_VPN6:
case NET_ROA6:
return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6.prefix);
case NET_MREQ4:
case NET_MGRP4:
return ip4_classify(n->mgrp4.ga);
case NET_MREQ6:
case NET_MGRP6:
return ip6_classify(&n->mgrp6.ga);
}
return IADDR_INVALID;
@ -188,6 +234,15 @@ ipa_in_netX(const ip_addr a, const net_addr *n)
return ip6_zero(ip6_and(ip6_xor(ipa_to_ip6(a), net6_prefix(n)),
ip6_mkmask(net6_pxlen(n))));
case NET_MREQ4:
case NET_MGRP4:
if (!ipa_is_ip4(a)) return 0;
return ip4_equal(ipa_to_ip4(a), ((net_addr_mgrp4 *) n)->ga);
case NET_MREQ6:
case NET_MGRP6:
if (ipa_is_ip4(a)) return 0;
return ip6_equal(ipa_to_ip6(a), ((net_addr_mgrp6 *) n)->ga);
default:
return 0;
}

181
lib/net.h
View File

@ -19,7 +19,11 @@
#define NET_VPN6 4
#define NET_ROA4 5
#define NET_ROA6 6
#define NET_MAX 7
#define NET_MREQ4 7
#define NET_MREQ6 8
#define NET_MGRP4 9
#define NET_MGRP6 10
#define NET_MAX 11
#define NB_IP4 (1 << NET_IP4)
#define NB_IP6 (1 << NET_IP6)
@ -27,8 +31,16 @@
#define NB_VPN6 (1 << NET_VPN6)
#define NB_ROA4 (1 << NET_ROA4)
#define NB_ROA6 (1 << NET_ROA6)
#define NB_MREQ4 (1 << NET_MREQ4)
#define NB_MREQ6 (1 << NET_MREQ6)
#define NB_MGRP4 (1 << NET_MGRP4)
#define NB_MGRP6 (1 << NET_MGRP6)
#define NB_IP (NB_IP4 | NB_IP6)
#define NB_MREQ (NB_MREQ4 | NB_MREQ6)
#define NB_MGRP (NB_MGRP4 | NB_MGRP6)
#define NB_MCAST (NB_MREQ | NB_MGRP)
#define NB_6 (NB_IP6 | NB_VPN6 | NB_MREQ6 | NB_MGRP6)
#define NB_ANY 0xffffffff
@ -88,6 +100,36 @@ typedef struct net_addr_roa6 {
u32 asn;
} net_addr_roa6;
typedef struct net_addr_mreq4 {
u8 type;
u8 pxlen;
u16 length;
ip4_addr ga;
unsigned ifindex;
} net_addr_mreq4;
typedef struct net_addr_mreq6 {
u8 type;
u8 pxlen;
u16 length;
ip6_addr ga;
unsigned ifindex;
} net_addr_mreq6;
typedef struct net_addr_mgrp4 {
u8 type;
u8 pxlen;
u16 length;
ip4_addr ga;
} net_addr_mgrp4;
typedef struct net_addr_mgrp6 {
u8 type;
u8 pxlen;
u16 length;
ip6_addr ga;
} net_addr_mgrp6;
typedef union net_addr_union {
net_addr n;
net_addr_ip4 ip4;
@ -96,6 +138,10 @@ typedef union net_addr_union {
net_addr_vpn6 vpn6;
net_addr_roa4 roa4;
net_addr_roa6 roa6;
net_addr_mreq4 mreq4;
net_addr_mreq6 mreq6;
net_addr_mgrp4 mgrp4;
net_addr_mgrp6 mgrp6;
} net_addr_union;
@ -125,6 +171,17 @@ extern const u16 net_max_text_length[];
#define NET_ADDR_ROA6(prefix,pxlen,max_pxlen,asn) \
((net_addr_roa6) { NET_ROA6, pxlen, sizeof(net_addr_roa6), prefix, max_pxlen, asn })
#define NET_ADDR_MREQ4(ga, ifindex) \
((net_addr_mreq4) { NET_MREQ4, IP4_MAX_PREFIX_LENGTH, sizeof(net_addr_mreq4), ga, ifindex })
#define NET_ADDR_MREQ6(ga, ifindex) \
((net_addr_mreq6) { NET_MREQ6, IP6_MAX_PREFIX_LENGTH, sizeof(net_addr_mreq6), ga, ifindex })
#define NET_ADDR_MGRP4(ga) \
((net_addr_mgrp4) { NET_MGRP4, IP4_MAX_PREFIX_LENGTH, sizeof(net_addr_mgrp4), ga })
#define NET_ADDR_MGRP6(ga) \
((net_addr_mgrp6) { NET_MGRP6, IP6_MAX_PREFIX_LENGTH, sizeof(net_addr_mgrp6), ga })
static inline void net_fill_ip4(net_addr *a, ip4_addr prefix, uint pxlen)
@ -145,6 +202,18 @@ static inline void net_fill_roa4(net_addr *a, ip4_addr prefix, uint pxlen, uint
static inline void net_fill_roa6(net_addr *a, ip6_addr prefix, uint pxlen, uint max_pxlen, u32 asn)
{ *(net_addr_roa6 *)a = NET_ADDR_ROA6(prefix, pxlen, max_pxlen, asn); }
static inline void net_fill_mreq4(net_addr *a, ip4_addr ga, unsigned ifindex)
{ *(net_addr_mreq4 *)a = NET_ADDR_MREQ4(ga, ifindex); }
static inline void net_fill_mreq6(net_addr *a, ip6_addr ga, unsigned ifindex)
{ *(net_addr_mreq6 *)a = NET_ADDR_MREQ6(ga, ifindex); }
static inline void net_fill_mgrp4(net_addr *a, ip4_addr ga)
{ *(net_addr_mgrp4 *)a = NET_ADDR_MGRP4(ga); }
static inline void net_fill_mgrp6(net_addr *a, ip6_addr ga)
{ *(net_addr_mgrp6 *)a = NET_ADDR_MGRP6(ga); }
static inline void net_fill_ipa(net_addr *a, ip_addr prefix, uint pxlen)
{
if (ipa_is_ip4(prefix))
@ -161,6 +230,21 @@ static inline void net_fill_ip_host(net_addr *a, ip_addr prefix)
net_fill_ip6(a, ipa_to_ip6(prefix), IP6_MAX_PREFIX_LENGTH);
}
static inline void net_fill_mreq(net_addr *a, ip_addr ga, unsigned ifindex)
{
if (ipa_is_ip4(ga))
net_fill_mreq4(a, ipa_to_ip4(ga), ifindex);
else
net_fill_mreq6(a, ipa_to_ip6(ga), ifindex);
}
static inline void net_fill_mgrp(net_addr *a, ip_addr ga)
{
if (ipa_is_ip4(ga))
net_fill_mgrp4(a, ipa_to_ip4(ga));
else
net_fill_mgrp6(a, ipa_to_ip6(ga));
}
static inline int net_val_match(u8 type, u32 mask)
{ return !!((1 << type) & mask); }
@ -185,11 +269,15 @@ static inline ip_addr net_prefix(const net_addr *a)
case NET_IP4:
case NET_VPN4:
case NET_ROA4:
case NET_MREQ4:
case NET_MGRP4:
return ipa_from_ip4(net4_prefix(a));
case NET_IP6:
case NET_VPN6:
case NET_ROA6:
case NET_MREQ6:
case NET_MGRP6:
return ipa_from_ip6(net6_prefix(a));
default:
@ -208,6 +296,39 @@ static inline uint net_pxlen(const net_addr *a)
ip_addr net_pxmask(const net_addr *a);
static inline int net_is_host(const net_addr *a)
{
switch (a->type)
{
case NET_IP4:
case NET_VPN4: return net4_pxlen(a) == IP4_MAX_PREFIX_LENGTH;
case NET_IP6:
case NET_VPN6: return net6_pxlen(a) == IP6_MAX_PREFIX_LENGTH;
case NET_MREQ4:
case NET_MREQ6:
case NET_MGRP4:
case NET_MGRP6: return 1;
default: return 0;
}
}
static inline int net_is_v6(net_addr *a)
{
return net_type_match(a, NB_6);
}
static inline int net_ifindex(net_addr *a)
{
switch (a->type)
{
case NET_MREQ4:
return ((net_addr_mreq4 *) a)->ifindex;
case NET_MREQ6:
return ((net_addr_mreq6 *) a)->ifindex;
default: return 0;
}
}
static inline int net_equal(const net_addr *a, const net_addr *b)
{ return (a->length == b->length) && !memcmp(a, b, a->length); }
@ -236,6 +357,18 @@ static inline int net_equal_prefix_roa4(const net_addr_roa4 *a, const net_addr_r
static inline int net_equal_prefix_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b)
{ return ip6_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); }
static inline int net_equal_mreq4(const net_addr_mreq4 *a, const net_addr_mreq4 *b)
{ return !memcmp(a, b, sizeof(net_addr_mreq4)); }
static inline int net_equal_mreq6(const net_addr_mreq6 *a, const net_addr_mreq6 *b)
{ return !memcmp(a, b, sizeof(net_addr_mreq6)); }
static inline int net_equal_mgrp4(const net_addr_mgrp4 *a, const net_addr_mgrp4 *b)
{ return !memcmp(a, b, sizeof(net_addr_mgrp4)); }
static inline int net_equal_mgrp6(const net_addr_mgrp6 *a, const net_addr_mgrp6 *b)
{ return !memcmp(a, b, sizeof(net_addr_mgrp6)); }
static inline int net_zero_ip4(const net_addr_ip4 *a)
{ return !a->pxlen && ip4_zero(a->prefix); }
@ -255,6 +388,18 @@ static inline int net_zero_roa4(const net_addr_roa4 *a)
static inline int net_zero_roa6(const net_addr_roa6 *a)
{ return !a->pxlen && ip6_zero(a->prefix) && !a->max_pxlen && !a->asn; }
static inline int net_zero_mreq4(const net_addr_mreq4 *a)
{ return ip4_zero(a->ga) && !a->ifindex; }
static inline int net_zero_mreq6(const net_addr_mreq6 *a)
{ return ip6_zero(a->ga) && !a->ifindex; }
static inline int net_zero_mgrp4(const net_addr_mgrp4 *a)
{ return ip4_zero(a->ga); }
static inline int net_zero_mgrp6(const net_addr_mgrp6 *a)
{ return ip6_zero(a->ga); }
static inline int net_compare_ip4(const net_addr_ip4 *a, const net_addr_ip4 *b)
{ return ip4_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen); }
@ -274,6 +419,18 @@ static inline int net_compare_roa4(const net_addr_roa4 *a, const net_addr_roa4 *
static inline int net_compare_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b)
{ return ip6_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen) ?: uint_cmp(a->max_pxlen, b->max_pxlen) ?: uint_cmp(a->asn, b->asn); }
static inline int net_compare_mreq4(const net_addr_mreq4 *a, const net_addr_mreq4 *b)
{ return ip4_compare(a->ga, b->ga) ?: uint_cmp(a->ifindex, b->ifindex); }
static inline int net_compare_mreq6(const net_addr_mreq6 *a, const net_addr_mreq6 *b)
{ return ip6_compare(a->ga, b->ga) ?: uint_cmp(a->ifindex, b->ifindex); }
static inline int net_compare_mgrp4(const net_addr_mgrp4 *a, const net_addr_mgrp4 *b)
{ return ip4_compare(a->ga, b->ga); }
static inline int net_compare_mgrp6(const net_addr_mgrp6 *a, const net_addr_mgrp6 *b)
{ return ip6_compare(a->ga, b->ga); }
int net_compare(const net_addr *a, const net_addr *b);
@ -298,6 +455,17 @@ static inline void net_copy_roa4(net_addr_roa4 *dst, const net_addr_roa4 *src)
static inline void net_copy_roa6(net_addr_roa6 *dst, const net_addr_roa6 *src)
{ memcpy(dst, src, sizeof(net_addr_roa6)); }
static inline void net_copy_mreq4(net_addr_mreq4 *dst, const net_addr_mreq4 *src)
{ memcpy(dst, src, sizeof(net_addr_mreq4)); }
static inline void net_copy_mreq6(net_addr_mreq6 *dst, const net_addr_mreq6 *src)
{ memcpy(dst, src, sizeof(net_addr_mreq6)); }
static inline void net_copy_mgrp4(net_addr_mgrp4 *dst, const net_addr_mgrp4 *src)
{ memcpy(dst, src, sizeof(net_addr_mgrp4)); }
static inline void net_copy_mgrp6(net_addr_mgrp6 *dst, const net_addr_mgrp6 *src)
{ memcpy(dst, src, sizeof(net_addr_mgrp6)); }
static inline u32 net_hash_ip4(const net_addr_ip4 *n)
{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
@ -321,6 +489,17 @@ static inline u32 net_hash_roa4(const net_addr_roa4 *n)
static inline u32 net_hash_roa6(const net_addr_roa6 *n)
{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
static inline u32 net_hash_mreq4(const net_addr_mreq4 *n)
{ return ip4_hash(n->ga) ^ u64_hash(n->ifindex); }
static inline u32 net_hash_mreq6(const net_addr_mreq6 *n)
{ return ip6_hash(n->ga) ^ u64_hash(n->ifindex); }
static inline u32 net_hash_mgrp4(const net_addr_mgrp4 *n)
{ return ip4_hash(n->ga); }
static inline u32 net_hash_mgrp6(const net_addr_mgrp6 *n)
{ return ip6_hash(n->ga); }
static inline int net_validate_ip4(const net_addr_ip4 *n)
{

View File

@ -364,6 +364,9 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
case 'o':
base = 8;
break;
case 'b':
base = 2;
break;
case 'X':
flags |= LARGE;

View File

@ -77,6 +77,7 @@ static inline int sk_send_buffer_empty(sock *sk)
int sk_setup_multicast(sock *s); /* Prepare UDP or IP socket for multicasting */
int sk_join_group(sock *s, ip_addr maddr); /* Join multicast group on sk iface */
int sk_leave_group(sock *s, ip_addr maddr); /* Leave multicast group on sk iface */
int sk_set_router_alert(sock *s, int ra);
int sk_setup_broadcast(sock *s);
int sk_set_ttl(sock *s, int ttl); /* Set transmit TTL for given socket */
int sk_set_min_ttl(sock *s, int ttl); /* Set minimal accepted TTL for given socket */

View File

@ -65,7 +65,7 @@ CF_DECLS
CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6)
CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, MREQ4, MREQ6, MGRP4, MGRP6)
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE) /* ,ROA */
@ -148,6 +148,10 @@ net_type:
| VPN6 { $$ = NET_VPN6; }
| ROA4 { $$ = NET_ROA4; }
| ROA6 { $$ = NET_ROA6; }
| MREQ4 { $$ = NET_MREQ4; }
| MREQ6 { $$ = NET_MREQ6; }
| MGRP4 { $$ = NET_MGRP4; }
| MGRP6 { $$ = NET_MGRP6; }
;

View File

@ -502,6 +502,17 @@ ifa_same(struct ifa *a, struct ifa *b)
return ipa_equal(a->ip, b->ip) && net_equal(&a->prefix, &b->prefix);
}
struct ifa *
ifa_find_match(struct iface *i, u32 mask)
{
struct ifa *a;
WALK_LIST(a, i->addrs)
if (net_type_match(&a->prefix, mask))
return a;
return NULL;
}
/**
* ifa_update - update interface address

View File

@ -88,6 +88,7 @@ void if_show(void);
void if_show_summary(void);
struct iface *if_update(struct iface *);
void if_delete(struct iface *old);
struct ifa *ifa_find_match(struct iface *i, u32 mask);
struct ifa *ifa_update(struct ifa *);
void ifa_delete(struct ifa *);
void if_start_update(void);

View File

@ -200,6 +200,8 @@ struct hostentry {
u32 igp_metric; /* Chosen route IGP metric */
};
#define RTE_MGRP_MAXVIFS 32
typedef struct rte {
struct rte *next;
net *net; /* Network this RTE belongs to */
@ -235,6 +237,9 @@ typedef struct rte {
u64 router_id; /* Babel router id */
} babel;
#endif
struct {
u32 oifs, iifs; /* Bitmaps for iifs and oifs. Use RTE_MGRP_* macros to manipulate. */
} mkrt;
struct { /* Routes generated by krt sync (both temporary and inherited ones) */
s8 src; /* Alleged route source (see krt.h) */
u8 proto; /* Kernel source protocol ID */
@ -269,6 +274,13 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED);
#define RIC_REJECT -1 /* Rejected by protocol */
#define RIC_DROP -2 /* Silently dropped by protocol */
#define RTE_MGRP_SET(iface,m) ((m)|=(1<<if_get_vifi((iface))))
#define RTE_MGRP_CLR(iface,m) ((m)&=~(1<<if_get_vifi((iface))))
#define RTE_MGRP_ISSET(iface,m) ((m)&(1<<if_get_vifi((iface))))
#define RTE_MGRP_CLRALL(m) ((m)=0)
#define RTE_MGRP_COPY(mfrom,mto) ((mto)=(mfrom))
#define RTE_MGRP_SAME(m1,m2) ((m1)==(m2))
struct config;
void rt_init(void);
@ -287,10 +299,13 @@ void rte_update2(struct channel *c, net_addr *n, rte *new, struct rte_src *src);
/* rte_update() moved to protocol.h to avoid dependency conflicts */
void rte_discard(rtable *tab, rte *old);
int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter);
int rt_examine2(net *n, struct proto *p, struct filter *filter, void (*callback)(struct proto *, void *, rte *), void *data);
rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, struct ea_list **tmpa, int silent);
void rt_refresh_begin(rtable *t, struct channel *c);
void rt_refresh_end(rtable *t, struct channel *c);
int rt_route(struct channel *c, net_addr *net, void (*callback)(struct proto *, void *, rte *), void *data);
void rt_schedule_prune(rtable *t);
u32 rt_get_igp_metric(rte *rt);
void rte_dump(rte *);
void rte_free(rte *);
rte *rte_do_cow(rte *);
@ -396,7 +411,9 @@ typedef struct rta {
#define RTD_UNREACHABLE 3 /* Reject as unreachable */
#define RTD_PROHIBIT 4 /* Administratively prohibited */
#define RTD_MULTIPATH 5 /* Multipath route (nexthops != NULL) */
#define RTD_NONE 6 /* Invalid RTD */
#define RTD_MREQUEST 6 /* Multicast pseudoroute */
#define RTD_MULTICAST 7 /* Multicast pseudoroute */
#define RTD_NONE 8 /* Invalid RTD */
/* Flags for net->n.flags, used by kernel syncer */
#define KRF_INSTALLED 0x80 /* This route should be installed in the kernel */

View File

@ -193,6 +193,10 @@ fib_hash(struct fib *f, const net_addr *a)
case NET_VPN6: return FIB_HASH(f, a, vpn6);
case NET_ROA4: return FIB_HASH(f, a, roa4);
case NET_ROA6: return FIB_HASH(f, a, roa6);
case NET_MREQ4: return FIB_HASH(f, a, mreq4);
case NET_MREQ6: return FIB_HASH(f, a, mreq6);
case NET_MGRP4: return FIB_HASH(f, a, mgrp4);
case NET_MGRP6: return FIB_HASH(f, a, mgrp6);
default: bug("invalid type");
}
}
@ -227,6 +231,10 @@ fib_find(struct fib *f, const net_addr *a)
case NET_VPN6: return FIB_FIND(f, a, vpn6);
case NET_ROA4: return FIB_FIND(f, a, roa4);
case NET_ROA6: return FIB_FIND(f, a, roa6);
case NET_MREQ4: return FIB_FIND(f, a, mreq4);
case NET_MREQ6: return FIB_FIND(f, a, mreq6);
case NET_MGRP4: return FIB_FIND(f, a, mgrp4);
case NET_MGRP6: return FIB_FIND(f, a, mgrp6);
default: bug("invalid type");
}
}
@ -244,6 +252,10 @@ fib_insert(struct fib *f, const net_addr *a, struct fib_node *e)
case NET_VPN6: FIB_INSERT(f, a, e, vpn6); return;
case NET_ROA4: FIB_INSERT(f, a, e, roa4); return;
case NET_ROA6: FIB_INSERT(f, a, e, roa6); return;
case NET_MREQ4: FIB_INSERT(f, a, e, mreq4); return;
case NET_MREQ6: FIB_INSERT(f, a, e, mreq6); return;
case NET_MGRP4: FIB_INSERT(f, a, e, mgrp4); return;
case NET_MGRP6: FIB_INSERT(f, a, e, mgrp6); return;
default: bug("invalid type");
}
}

View File

@ -900,7 +900,7 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old,
static inline int
rte_validate(rte *e)
{
int c;
int c, mask;
net *n = e->net;
// (n->n.pxlen > BITS_PER_IP_ADDRESS) || !ip_is_prefix(n->n.prefix,n->n.pxlen))
@ -911,8 +911,10 @@ rte_validate(rte *e)
return 0;
}
mask = net_val_match(n->n.addr->type, NB_MCAST) ? IADDR_MULTICAST : IADDR_HOST;
c = net_classify(n->n.addr);
if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
if ((c < 0) || !(c & mask) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
{
log(L_WARN "Ignoring bogus route %N received via %s",
n->n.addr, e->sender->proto->name);
@ -1406,8 +1408,15 @@ int
rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
{
net *n = net_find(t, a);
rte *rt = n ? n->routes : NULL;
return rt_examine2(n, p, filter, NULL, NULL);
}
/* If rte would be exported to p, call the callback */
int
rt_examine2(net *n, struct proto *p, struct filter *filter, void (*callback)(struct proto *, void *, rte *), void *data)
{
rte *rt = n ? n->routes : NULL;
if (!rte_is_valid(rt))
return 0;
@ -1419,6 +1428,9 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
if (v == RIC_PROCESS)
v = (f_run(filter, &rt, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
if (callback && v > 0)
callback(p, data, rt);
/* Discard temporary rte */
if (rt != n->routes)
rte_free(rt);
@ -1426,6 +1438,32 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
rte_update_unlock();
return v > 0;
}
/* Sometimes protocols need to find one route in table without keeping their own copy.
* rt_route finds the best route after applying filter.
* As the routes may be temporary, successful find is announced by the callback.
* Returns 1 if the callback was called.
*/
int
rt_route(struct channel *c, net_addr *n, void (*callback)(struct proto *, void *, rte *), void *data)
{
net *r;
net_addr *n0 = alloca(n->length);
net_copy(n0, n);
while (1)
{
r = net_find(c->table, n0);
if (r && rte_is_valid(r->routes) && rt_examine2(r, c->proto, c->out_filter, callback, data))
return 1;
if (n0->pxlen == 0)
return 0;
n0->pxlen--;
net_normalize(n0);
}
}
@ -1734,6 +1772,11 @@ rt_preconfig(struct config *c)
rt_new_table(cf_get_symbol("master4"), NET_IP4);
rt_new_table(cf_get_symbol("master6"), NET_IP6);
rt_new_table(cf_get_symbol("mreq4"), NET_MREQ4);
rt_new_table(cf_get_symbol("mreq6"), NET_MREQ6);
rt_new_table(cf_get_symbol("mroute4"), NET_MGRP4);
rt_new_table(cf_get_symbol("mroute6"), NET_MGRP6);
}
@ -2278,7 +2321,7 @@ if_local_addr(ip_addr a, struct iface *i)
return 0;
}
static u32
u32
rt_get_igp_metric(rte *rt)
{
eattr *ea = ea_find(rt->attrs->eattrs, EA_GEN_IGP_METRIC);
@ -2439,6 +2482,8 @@ rt_format_via(rte *e, byte *via)
case RTD_UNREACHABLE: bsprintf(via, "unreachable"); break;
case RTD_PROHIBIT: bsprintf(via, "prohibited"); break;
case RTD_MULTIPATH: bsprintf(via, "multipath"); break;
case RTD_MREQUEST: bsprintf(via, "for %s", a->iface->name); break;
case RTD_MULTICAST: bsprintf(via, "iifs: %b, oifs: %b", e->u.mkrt.iifs, e->u.mkrt.oifs); break;
default: bsprintf(via, "???");
}
}

View File

@ -236,6 +236,25 @@ sk_set_min_ttl6(sock *s, int ttl)
return 0;
}
static inline int
sk_set_router_alert4(sock *s, int ra)
{
if (setsockopt(s->fd, SOL_IP, IP_ROUTER_ALERT, &ra, sizeof(ra)) < 0)
ERR("IP_ROUTER_ALER");
return 0;
}
static inline int
sk_set_router_alert6(sock *s, int ra)
{
if (setsockopt(s->fd, SOL_IPV6, IPV6_ROUTER_ALERT, &ra, sizeof(ra)) < 0)
ERR("IPV6_ROUTER_ALER");
return 0;
}
static inline int
sk_disable_mtu_disc4(sock *s)
{

View File

@ -122,10 +122,11 @@ tracked_fopen(pool *p, char *name, char *mode)
#define NEAR_TIMER_LIMIT 4
static list near_timers, far_timers;
static bird_clock_t first_far_timer = TIME_INFINITY;
static btime first_far_timer = BTIME_INFINITY;
/* now must be different from 0, because 0 is a special value in timer->expires */
bird_clock_t now = 1, now_real, boot_time;
btime now_btime = 1;
static void
update_times_plain(void)
@ -134,10 +135,11 @@ update_times_plain(void)
int delta = new_time - now_real;
if ((delta >= 0) && (delta < 60))
now += delta;
now_btime += delta S;
else if (now_real != 0)
log(L_WARN "Time jump, delta %d s", delta);
now = now_btime TO_S;
now_real = new_time;
}
@ -151,11 +153,14 @@ update_times_gettime(void)
if (rv != 0)
die("clock_gettime: %m");
if (ts.tv_sec != now) {
if (ts.tv_sec < now)
btime bt = (ts.tv_sec S) + (ts.tv_nsec NS);
if (bt != now_btime) {
if (bt < now_btime)
log(L_ERR "Monotonic timer is broken");
now = ts.tv_sec;
now_btime = bt;
now = now_btime TO_S;
now_real = time(NULL);
}
}
@ -234,7 +239,7 @@ tm_insert_near(timer *t)
{
node *n = HEAD(near_timers);
while (n->next && (SKIP_BACK(timer, n, n)->expires < t->expires))
while (n->next && (SKIP_BACK(timer, n, n)->expires_btime < t->expires_btime))
n = n->next;
insert_node(&t->n, n->prev);
}
@ -259,17 +264,25 @@ tm_insert_near(timer *t)
void
tm_start(timer *t, unsigned after)
{
bird_clock_t when;
if (t->randomize)
after += random() % (t->randomize + 1);
when = now + after;
if (t->expires == when)
tm_start_btime(t, after S);
}
void
tm_start_btime(timer *t, btime after)
{
btime when;
when = now_btime + after;
if (t->expires_btime == when)
return;
if (t->expires)
if (t->expires_btime)
rem_node(&t->n);
t->expires = when;
if (after <= NEAR_TIMER_LIMIT)
t->expires_btime = when;
t->expires = when TO_S;
if (after TO_S <= NEAR_TIMER_LIMIT)
tm_insert_near(t);
else
{
@ -289,10 +302,10 @@ tm_start(timer *t, unsigned after)
void
tm_stop(timer *t)
{
if (t->expires)
if (t->expires_btime)
{
rem_node(&t->n);
t->expires = 0;
t->expires = t->expires_btime = 0;
}
}
@ -319,16 +332,16 @@ tm_dump_all(void)
tm_dump_them("Far", &far_timers);
}
static inline time_t
static inline btime
tm_first_shot(void)
{
time_t x = first_far_timer;
btime x = first_far_timer;
if (!EMPTY_LIST(near_timers))
{
timer *t = SKIP_BACK(timer, n, HEAD(near_timers));
if (t->expires < x)
x = t->expires;
if (t->expires_btime < x)
x = t->expires_btime;
}
return x;
}
@ -341,21 +354,21 @@ tm_shot(void)
timer *t;
node *n, *m;
if (first_far_timer <= now)
if (first_far_timer <= now_btime)
{
bird_clock_t limit = now + NEAR_TIMER_LIMIT;
first_far_timer = TIME_INFINITY;
btime limit = now_btime + NEAR_TIMER_LIMIT S;
first_far_timer = BTIME_INFINITY;
n = HEAD(far_timers);
while (m = n->next)
{
t = SKIP_BACK(timer, n, n);
if (t->expires <= limit)
if (t->expires_btime <= limit)
{
rem_node(n);
tm_insert_near(t);
}
else if (t->expires < first_far_timer)
first_far_timer = t->expires;
else if (t->expires_btime < first_far_timer)
first_far_timer = t->expires_btime;
n = m;
}
}
@ -363,17 +376,17 @@ tm_shot(void)
{
int delay;
t = SKIP_BACK(timer, n, n);
if (t->expires > now)
if (t->expires_btime > now_btime)
break;
rem_node(n);
delay = t->expires - now;
t->expires = 0;
delay = t->expires_btime - now_btime;
t->expires = t->expires_btime = 0;
if (t->recurrent)
{
int i = t->recurrent - delay;
int i = t->recurrent S - delay;
if (i < 0)
i = 0;
tm_start(t, i);
tm_start_btime(t, i);
}
io_log_event(t->hook, t->data);
t->hook(t);
@ -812,7 +825,7 @@ sk_skip_ip_header(byte *pkt, int *len)
byte *
sk_rx_buffer(sock *s, int *len)
{
if (sk_is_ipv4(s) && (s->type == SK_IP))
if (sk_is_ipv4(s) && s->type == SK_IP)
return sk_skip_ip_header(s->rbuf, len);
else
return s->rbuf;
@ -948,6 +961,24 @@ sk_set_min_ttl(sock *s, int ttl)
return sk_set_min_ttl6(s, ttl);
}
/**
* sk_set_router_alert - set router alert option
* @s: socket
* @ra: packets with this router alert option value will be passed to the
* socket. Negative integer disables.
*
* Result: 0 for success, -1 for an error.
*/
int
sk_set_router_alert(sock *s, int ra)
{
if (sk_is_ipv4(s))
return sk_set_router_alert4(s, ra);
else
return sk_set_router_alert6(s, ra);
}
#if 0
/**
* sk_set_md5_auth - add / remove MD5 security association for given socket
@ -1087,7 +1118,8 @@ sk_free(resource *r)
current_sock = sk_next(s);
if (s == stored_sock)
stored_sock = sk_next(s);
rem_node(&s->n);
if (NODE_VALID(&s->n))
rem_node(&s->n);
}
}
@ -2093,7 +2125,7 @@ void
io_loop(void)
{
int poll_tout;
time_t tout;
btime tout;
int nfds, events, pout;
sock *s;
node *n;
@ -2107,12 +2139,12 @@ io_loop(void)
timers:
update_times();
tout = tm_first_shot();
if (tout <= now)
if (tout <= now_btime)
{
tm_shot();
goto timers;
}
poll_tout = (events ? 0 : MIN(tout - now, 3)) * 1000; /* Time in milliseconds */
poll_tout = (events ? 0 : MIN(tout - now_btime, 3)) TO_MS; /* Time in milliseconds */
io_close_event();

View File

@ -13,6 +13,27 @@
#include "lib/resource.h"
/* Microsecond time */
typedef s64 btime;
#define S_ *1000000
#define MS_ *1000
#define US_ *1
#define NS_ /1000
#define TO_S /1000000
#define TO_MS /1000
#define TO_US /1
#define TO_NS *1000
#ifndef PARSER
#define S S_
#define MS MS_
#define US US_
#define NS NS_
#endif
typedef time_t bird_clock_t; /* Use instead of time_t */
typedef struct timer {
@ -22,35 +43,59 @@ typedef struct timer {
unsigned randomize; /* Amount of randomization */
unsigned recurrent; /* Timer recurrence */
node n; /* Internal link */
bird_clock_t expires; /* 0=inactive */
btime expires_btime; /* 0=inactive */
bird_clock_t expires; /* == expires_btime TO_S */
} timer;
timer *tm_new(pool *);
void tm_start(timer *, unsigned after);
void tm_start_btime(timer *, btime after);
void tm_stop(timer *);
void tm_dump_all(void);
extern bird_clock_t now; /* Relative, monotonic time in seconds */
extern btime now_btime; /* dtto in microseconds */
extern bird_clock_t now_real; /* Time in seconds since fixed known epoch */
extern bird_clock_t boot_time;
static inline int
tm_active(timer *t)
{
return t->expires != 0;
return t->expires_btime != 0;
}
static inline btime
tm_remains_btime(timer *t)
{
return t->expires_btime ? t->expires_btime - now_btime : 0;
}
static inline bird_clock_t
tm_remains(timer *t)
{
return t->expires ? t->expires - now : 0;
return tm_remains_btime(t) TO_S;
}
static inline void
tm_start_max_btime(timer *t, btime after)
{
btime rem = tm_remains_btime(t);
tm_start(t, (rem > after) ? rem : after);
}
static inline void
tm_start_min_btime(timer *t, btime after)
{
btime rem = tm_remains_btime(t);
if (!rem || after < rem)
tm_start(t, after);
}
static inline void
tm_start_max(timer *t, unsigned after)
{
bird_clock_t rem = tm_remains(t);
tm_start(t, (rem > after) ? rem : after);
tm_start_max_btime(t, after S_);
}
static inline timer *
@ -87,4 +132,6 @@ tm_format_datetime(char *x, struct timeformat *fmt_spec, bird_clock_t t);
#endif
#endif
#define BTIME_INFINITY 0x7fffffffffffffff
#endif