#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 {
-
+#ifndef BIRD_HASH_H
+#define BIRD_HASH_H
#define HASH(type) struct { type **data; uint count, order; }
#define HASH_TYPE(v) typeof(** (v).data)
return mem_hash_value(&h);
}
+#endif
[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[] = {
[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[] = {
[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[] = {
[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" */
};
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;
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:
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;
}
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;
}
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;
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;
}
#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)
#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
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;
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;
#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)
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))
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); }
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:
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); }
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); }
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); }
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);
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); }
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)
{
case 'o':
base = 8;
break;
+ case 'b':
+ base = 2;
+ break;
case 'X':
flags |= LARGE;
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 */
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 */
| VPN6 { $$ = NET_VPN6; }
| ROA4 { $$ = NET_ROA4; }
| ROA6 { $$ = NET_ROA6; }
+ | MREQ4 { $$ = NET_MREQ4; }
+ | MREQ6 { $$ = NET_MREQ6; }
+ | MGRP4 { $$ = NET_MGRP4; }
+ | MGRP6 { $$ = NET_MGRP6; }
;
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
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);
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 */
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 */
#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);
/* 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 *);
#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 */
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");
}
}
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");
}
}
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");
}
}
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))
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);
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;
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);
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);
+ }
}
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);
}
return 0;
}
-static u32
+u32
rt_get_igp_metric(rte *rt)
{
eattr *ea = ea_find(rt->attrs->eattrs, EA_GEN_IGP_METRIC);
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, "???");
}
}
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)
{
#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)
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;
}
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);
}
}
{
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);
}
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
{
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;
}
}
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;
}
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;
}
}
{
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);
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;
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
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);
}
}
io_loop(void)
{
int poll_tout;
- time_t tout;
+ btime tout;
int nfds, events, pout;
sock *s;
node *n;
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();
#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 {
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(timer *t, unsigned after)
+tm_start_max_btime(timer *t, btime after)
{
- bird_clock_t rem = tm_remains(t);
+ 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)
+{
+ tm_start_max_btime(t, after S_);
+}
+
static inline timer *
tm_new_set(pool *p, void (*hook)(struct timer *), void *data, unsigned rand, unsigned rec)
{
#endif
#endif
+#define BTIME_INFINITY 0x7fffffffffffffff
+
#endif