mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
Merge branch 'int-new' of ssh://gitlab.labs.nic.cz/labs/bird into int-new
This commit is contained in:
commit
4406281260
1
.gitignore
vendored
1
.gitignore
vendored
@ -12,3 +12,4 @@
|
||||
/configure
|
||||
/sysdep/autoconf.h.in
|
||||
/sysdep/autoconf.h.in~
|
||||
/cscope.*
|
||||
|
@ -58,7 +58,7 @@ endif
|
||||
docgoals := docs userdocs progdocs
|
||||
testgoals := check test tests tests_run
|
||||
cleangoals := clean distclean testsclean
|
||||
.PHONY: all daemon cli $(docgoals) $(testgoals) $(cleangoals) tags
|
||||
.PHONY: all daemon cli $(docgoals) $(testgoals) $(cleangoals) tags cscope
|
||||
all: daemon cli
|
||||
|
||||
daemon: $(daemon)
|
||||
@ -162,6 +162,9 @@ endif
|
||||
tags:
|
||||
cd $(srcdir) ; etags -lc `find $(dirs) -name *.[chY]`
|
||||
|
||||
cscope:
|
||||
cd $(srcdir) ; find $(dirs) -name *.[chY] > cscope.files ; cscope -b
|
||||
|
||||
# Install
|
||||
|
||||
install: all
|
||||
|
@ -22,13 +22,14 @@ protocol direct {
|
||||
|
||||
# Feed routes to kernel FIB
|
||||
protocol kernel {
|
||||
ipv4 { export all; };
|
||||
# learn; # Learn all routes from the kernel
|
||||
ipv4 { export all; import all; };
|
||||
learn; # Learn all routes from the kernel
|
||||
# scan time 10; # Scan kernel tables every 10 seconds
|
||||
}
|
||||
|
||||
protocol kernel {
|
||||
ipv6;
|
||||
ipv6 { import all; };
|
||||
learn;
|
||||
}
|
||||
|
||||
# Static route feed
|
||||
|
@ -83,7 +83,7 @@ CF_DECLS
|
||||
%type <time> expr_us time
|
||||
%type <a> ipa
|
||||
%type <net> net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa
|
||||
%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_mpls_
|
||||
%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_mpls_
|
||||
%type <mls> label_stack_start label_stack
|
||||
|
||||
%type <t> text opttext
|
||||
@ -96,7 +96,7 @@ CF_DECLS
|
||||
%left '!'
|
||||
%nonassoc '.'
|
||||
|
||||
CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS)
|
||||
CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS, FROM)
|
||||
|
||||
CF_GRAMMAR
|
||||
|
||||
@ -206,6 +206,25 @@ net_ip6_: IP6 '/' NUM
|
||||
n->prefix, n->pxlen, ip6_and(n->prefix, ip6_mkmask(n->pxlen)), n->pxlen);
|
||||
};
|
||||
|
||||
net_ip6_sadr_: IP6 '/' NUM FROM IP6 '/' NUM
|
||||
{
|
||||
if ($3 > IP6_MAX_PREFIX_LENGTH)
|
||||
cf_error("Invalid prefix length %u", $3);
|
||||
|
||||
if ($7 > IP6_MAX_PREFIX_LENGTH)
|
||||
cf_error("Invalid prefix length %u", $7);
|
||||
|
||||
$$ = cfg_alloc(sizeof(net_addr_ip6_sadr));
|
||||
net_fill_ip6_sadr($$, $1, $3, $5, $7);
|
||||
|
||||
net_addr_ip6_sadr *n = (void *) $$;
|
||||
if (!net_validate_ip6_sadr(n))
|
||||
cf_error("Invalid SADR IPv6 prefix %I6/%d from %I6/%d, maybe you wanted %I6/%d from %I6/%d",
|
||||
n->dst_prefix, n->dst_pxlen, n->src_prefix, n->src_pxlen,
|
||||
ip6_and(n->dst_prefix, ip6_mkmask(n->dst_pxlen)), n->dst_pxlen,
|
||||
ip6_and(n->src_prefix, ip6_mkmask(n->src_pxlen)), n->src_pxlen);
|
||||
};
|
||||
|
||||
net_vpn4_: VPN_RD net_ip4_
|
||||
{
|
||||
$$ = cfg_alloc(sizeof(net_addr_vpn4));
|
||||
@ -249,6 +268,7 @@ net_:
|
||||
| net_vpn_
|
||||
| net_roa_
|
||||
| net_flow_
|
||||
| net_ip6_sadr_
|
||||
| net_mpls_
|
||||
;
|
||||
|
||||
|
@ -28,20 +28,15 @@ flow6 table flowtab6;
|
||||
|
||||
|
||||
protocol device {
|
||||
scan time 10;
|
||||
}
|
||||
|
||||
protocol kernel kernel4 {
|
||||
scan time 20;
|
||||
|
||||
ipv4 {
|
||||
export all;
|
||||
};
|
||||
}
|
||||
|
||||
protocol kernel kernel6 {
|
||||
scan time 20;
|
||||
|
||||
ipv6 {
|
||||
export all;
|
||||
};
|
||||
@ -169,8 +164,6 @@ protocol pipe {
|
||||
}
|
||||
|
||||
protocol ospf v2 ospf4 {
|
||||
# ecmp;
|
||||
|
||||
ipv4 {
|
||||
import all;
|
||||
# export where source = RTS_STATIC;
|
||||
@ -186,8 +179,6 @@ protocol ospf v2 ospf4 {
|
||||
|
||||
|
||||
protocol ospf v3 ospf6 {
|
||||
# ecmp;
|
||||
|
||||
ipv6 {
|
||||
import all;
|
||||
# export where source = RTS_STATIC;
|
||||
@ -251,7 +242,7 @@ protocol bgp {
|
||||
};
|
||||
|
||||
# IPv6 with MPLS labels (2/4)
|
||||
ipv6 multicast {
|
||||
ipv6 mpls {
|
||||
# explicit IPv6 table
|
||||
table mtab6;
|
||||
import all;
|
||||
|
@ -24,11 +24,11 @@ f_new_inst(void)
|
||||
}
|
||||
|
||||
struct f_inst *
|
||||
f_new_dynamic_attr(int type, int f_type UNUSED, int code)
|
||||
f_new_dynamic_attr(int type, int f_type, int code)
|
||||
{
|
||||
/* FIXME: Remove the f_type parameter? */
|
||||
struct f_inst *f = f_new_inst();
|
||||
f->aux = type;
|
||||
f->aux = (f_type << 8) | type;
|
||||
f->a2.i = code;
|
||||
return f;
|
||||
}
|
||||
|
@ -587,6 +587,7 @@ val_format_str(struct f_val v) {
|
||||
static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
|
||||
|
||||
#define runtime(fmt, ...) do { \
|
||||
if (!(f_flags & FF_SILENT)) \
|
||||
log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \
|
||||
res.type = T_RETURN; \
|
||||
res.val.i = F_ERROR; \
|
||||
@ -903,7 +904,8 @@ interpret(struct f_inst *what)
|
||||
break;
|
||||
case P('p',','):
|
||||
ONEARG;
|
||||
if (what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p))
|
||||
if ((what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) &&
|
||||
!(f_flags & FF_SILENT))
|
||||
log_commit(*L_INFO, &f_buf);
|
||||
|
||||
switch (what->a2.i) {
|
||||
@ -1003,6 +1005,7 @@ interpret(struct f_inst *what)
|
||||
{
|
||||
eattr *e = NULL;
|
||||
u16 code = what->a2.i;
|
||||
int f_type = what->aux >> 8;
|
||||
|
||||
if (!(f_flags & FF_FORCE_TMPATTR))
|
||||
e = ea_find((*f_rte)->attrs->eattrs, code);
|
||||
@ -1047,7 +1050,7 @@ interpret(struct f_inst *what)
|
||||
|
||||
switch (what->aux & EAF_TYPE_MASK) {
|
||||
case EAF_TYPE_INT:
|
||||
res.type = T_INT;
|
||||
res.type = f_type;
|
||||
res.val.i = e->u.data;
|
||||
break;
|
||||
case EAF_TYPE_ROUTER_ID:
|
||||
@ -1097,18 +1100,18 @@ interpret(struct f_inst *what)
|
||||
{
|
||||
struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
|
||||
u16 code = what->a2.i;
|
||||
int f_type = what->aux >> 8;
|
||||
|
||||
l->next = NULL;
|
||||
l->flags = EALF_SORTED;
|
||||
l->count = 1;
|
||||
l->attrs[0].id = code;
|
||||
l->attrs[0].flags = 0;
|
||||
l->attrs[0].type = what->aux | EAF_ORIGINATED | EAF_FRESH;
|
||||
l->attrs[0].type = (what->aux & 0xff) | EAF_ORIGINATED | EAF_FRESH;
|
||||
|
||||
switch (what->aux & EAF_TYPE_MASK) {
|
||||
case EAF_TYPE_INT:
|
||||
// Enums are also ints, so allow them in.
|
||||
if (v1.type != T_INT && (v1.type < T_ENUM_LO || v1.type > T_ENUM_HI))
|
||||
if (v1.type != f_type)
|
||||
runtime( "Setting int attribute to non-int value" );
|
||||
l->attrs[0].u.data = v1.val.i;
|
||||
break;
|
||||
@ -1793,6 +1796,7 @@ f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struc
|
||||
|
||||
|
||||
if (res.type != T_RETURN) {
|
||||
if (!(f_flags & FF_SILENT))
|
||||
log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name);
|
||||
return F_ERROR;
|
||||
}
|
||||
|
@ -208,6 +208,7 @@ struct f_trie
|
||||
#define NEW_F_VAL struct f_val * val; val = cfg_alloc(sizeof(struct f_val));
|
||||
|
||||
#define FF_FORCE_TMPATTR 1 /* Force all attributes to be temporary */
|
||||
#define FF_SILENT 2 /* Silent filter execution */
|
||||
|
||||
/* Bird Tests */
|
||||
struct f_bt_test_suite {
|
||||
|
23
lib/net.c
23
lib/net.c
@ -14,6 +14,7 @@ const char * const net_label[] = {
|
||||
[NET_ROA6] = "roa6",
|
||||
[NET_FLOW4] = "flow4",
|
||||
[NET_FLOW6] = "flow6",
|
||||
[NET_IP6_SADR]= "ipv6-sadr",
|
||||
[NET_MPLS] = "mpls",
|
||||
};
|
||||
|
||||
@ -26,6 +27,7 @@ const u16 net_addr_length[] = {
|
||||
[NET_ROA6] = sizeof(net_addr_roa6),
|
||||
[NET_FLOW4] = 0,
|
||||
[NET_FLOW6] = 0,
|
||||
[NET_IP6_SADR]= sizeof(net_addr_ip6_sadr),
|
||||
[NET_MPLS] = sizeof(net_addr_mpls),
|
||||
};
|
||||
|
||||
@ -38,6 +40,7 @@ const u8 net_max_prefix_length[] = {
|
||||
[NET_ROA6] = IP6_MAX_PREFIX_LENGTH,
|
||||
[NET_FLOW4] = IP4_MAX_PREFIX_LENGTH,
|
||||
[NET_FLOW6] = IP6_MAX_PREFIX_LENGTH,
|
||||
[NET_IP6_SADR]= IP6_MAX_PREFIX_LENGTH,
|
||||
[NET_MPLS] = 0,
|
||||
};
|
||||
|
||||
@ -50,6 +53,7 @@ const u16 net_max_text_length[] = {
|
||||
[NET_ROA6] = 60, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128-128 AS4294967295" */
|
||||
[NET_FLOW4] = 0, /* "flow4 { ... }" */
|
||||
[NET_FLOW6] = 0, /* "flow6 { ... }" */
|
||||
[NET_IP6_SADR]= 92, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128 from ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */
|
||||
[NET_MPLS] = 7, /* "1048575" */
|
||||
};
|
||||
|
||||
@ -102,6 +106,8 @@ net_format(const net_addr *N, char *buf, int buflen)
|
||||
return flow4_net_format(buf, buflen, &n->flow4);
|
||||
case NET_FLOW6:
|
||||
return flow6_net_format(buf, buflen, &n->flow6);
|
||||
case NET_IP6_SADR:
|
||||
return bsnprintf(buf, buflen, "%I6/%d from %I6/%d", n->ip6_sadr.dst_prefix, n->ip6_sadr.dst_pxlen, n->ip6_sadr.src_prefix, n->ip6_sadr.src_pxlen);
|
||||
case NET_MPLS:
|
||||
return bsnprintf(buf, buflen, "%u", n->mpls.label);
|
||||
}
|
||||
@ -124,6 +130,7 @@ net_pxmask(const net_addr *a)
|
||||
case NET_VPN6:
|
||||
case NET_ROA6:
|
||||
case NET_FLOW6:
|
||||
case NET_IP6_SADR:
|
||||
return ipa_from_ip6(ip6_mkmask(net6_pxlen(a)));
|
||||
|
||||
case NET_MPLS:
|
||||
@ -156,6 +163,8 @@ net_compare(const net_addr *a, const net_addr *b)
|
||||
return net_compare_flow4((const net_addr_flow4 *) a, (const net_addr_flow4 *) b);
|
||||
case NET_FLOW6:
|
||||
return net_compare_flow6((const net_addr_flow6 *) a, (const net_addr_flow6 *) b);
|
||||
case NET_IP6_SADR:
|
||||
return net_compare_ip6_sadr((const net_addr_ip6_sadr *) a, (const net_addr_ip6_sadr *) b);
|
||||
case NET_MPLS:
|
||||
return net_compare_mpls((const net_addr_mpls *) a, (const net_addr_mpls *) b);
|
||||
}
|
||||
@ -177,6 +186,7 @@ net_hash(const net_addr *n)
|
||||
case NET_ROA6: return NET_HASH(n, roa6);
|
||||
case NET_FLOW4: return NET_HASH(n, flow4);
|
||||
case NET_FLOW6: return NET_HASH(n, flow6);
|
||||
case NET_IP6_SADR: return NET_HASH(n, ip6_sadr);
|
||||
case NET_MPLS: return NET_HASH(n, mpls);
|
||||
default: bug("invalid type");
|
||||
}
|
||||
@ -198,6 +208,7 @@ net_validate(const net_addr *n)
|
||||
case NET_ROA6: return NET_VALIDATE(n, roa6);
|
||||
case NET_FLOW4: return NET_VALIDATE(n, flow4);
|
||||
case NET_FLOW6: return NET_VALIDATE(n, flow6);
|
||||
case NET_IP6_SADR: return NET_VALIDATE(n, ip6_sadr);
|
||||
case NET_MPLS: return NET_VALIDATE(n, mpls);
|
||||
default: return 0;
|
||||
}
|
||||
@ -222,6 +233,9 @@ net_normalize(net_addr *N)
|
||||
case NET_FLOW6:
|
||||
return net_normalize_ip6(&n->ip6);
|
||||
|
||||
case NET_IP6_SADR:
|
||||
return net_normalize_ip6_sadr(&n->ip6_sadr);
|
||||
|
||||
case NET_MPLS:
|
||||
return;
|
||||
}
|
||||
@ -246,6 +260,9 @@ net_classify(const net_addr *N)
|
||||
case NET_FLOW6:
|
||||
return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6.prefix);
|
||||
|
||||
case NET_IP6_SADR:
|
||||
return ip6_zero(n->ip6_sadr.dst_prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6_sadr.dst_prefix);
|
||||
|
||||
case NET_MPLS:
|
||||
return IADDR_HOST | SCOPE_UNIVERSE;
|
||||
}
|
||||
@ -274,6 +291,11 @@ 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_IP6_SADR:
|
||||
if (ipa_is_ip4(a)) return 0;
|
||||
return ip6_zero(ip6_and(ip6_xor(ipa_to_ip6(a), net6_prefix(n)),
|
||||
ip6_mkmask(net6_pxlen(n))));
|
||||
|
||||
case NET_MPLS:
|
||||
default:
|
||||
return 0;
|
||||
@ -304,5 +326,6 @@ net_init(void)
|
||||
CHECK_NET(net_addr_roa6, 28);
|
||||
CHECK_NET(net_addr_flow4, 8);
|
||||
CHECK_NET(net_addr_flow6, 20);
|
||||
CHECK_NET(net_addr_ip6_sadr, 40);
|
||||
CHECK_NET(net_addr_mpls, 8);
|
||||
}
|
||||
|
90
lib/net.h
90
lib/net.h
@ -21,8 +21,9 @@
|
||||
#define NET_ROA6 6
|
||||
#define NET_FLOW4 7
|
||||
#define NET_FLOW6 8
|
||||
#define NET_MPLS 9
|
||||
#define NET_MAX 10
|
||||
#define NET_IP6_SADR 9
|
||||
#define NET_MPLS 10
|
||||
#define NET_MAX 11
|
||||
|
||||
#define NB_IP4 (1 << NET_IP4)
|
||||
#define NB_IP6 (1 << NET_IP6)
|
||||
@ -32,12 +33,13 @@
|
||||
#define NB_ROA6 (1 << NET_ROA6)
|
||||
#define NB_FLOW4 (1 << NET_FLOW4)
|
||||
#define NB_FLOW6 (1 << NET_FLOW6)
|
||||
#define NB_IP6_SADR (1 << NET_IP6_SADR)
|
||||
#define NB_MPLS (1 << NET_MPLS)
|
||||
|
||||
#define NB_IP (NB_IP4 | NB_IP6)
|
||||
#define NB_VPN (NB_VPN4 | NB_VPN6)
|
||||
#define NB_FLOW (NB_FLOW4 | NB_FLOW6)
|
||||
#define NB_DEST (NB_IP | NB_VPN | NB_MPLS)
|
||||
#define NB_DEST (NB_IP | NB_IP6_SADR | NB_VPN | NB_MPLS)
|
||||
#define NB_ANY 0xffffffff
|
||||
|
||||
|
||||
@ -121,6 +123,15 @@ typedef struct net_addr_mpls {
|
||||
u32 label;
|
||||
} net_addr_mpls;
|
||||
|
||||
typedef struct net_addr_ip6_sadr {
|
||||
u8 type;
|
||||
u8 dst_pxlen;
|
||||
u16 length;
|
||||
ip6_addr dst_prefix;
|
||||
s32 src_pxlen; /* s32 to avoid padding */
|
||||
ip6_addr src_prefix;
|
||||
} net_addr_ip6_sadr;
|
||||
|
||||
typedef union net_addr_union {
|
||||
net_addr n;
|
||||
net_addr_ip4 ip4;
|
||||
@ -131,6 +142,7 @@ typedef union net_addr_union {
|
||||
net_addr_roa6 roa6;
|
||||
net_addr_flow4 flow4;
|
||||
net_addr_flow6 flow6;
|
||||
net_addr_ip6_sadr ip6_sadr;
|
||||
net_addr_mpls mpls;
|
||||
} net_addr_union;
|
||||
|
||||
@ -167,6 +179,9 @@ extern const u16 net_max_text_length[];
|
||||
#define NET_ADDR_FLOW6(prefix,pxlen,dlen) \
|
||||
((net_addr_flow6) { NET_FLOW6, pxlen, sizeof(net_addr_ip6) + dlen, prefix })
|
||||
|
||||
#define NET_ADDR_IP6_SADR(dst_prefix,dst_pxlen,src_prefix,src_pxlen) \
|
||||
((net_addr_ip6_sadr) { NET_IP6_SADR, dst_pxlen, sizeof(net_addr_ip6_sadr), dst_prefix, src_pxlen, src_prefix })
|
||||
|
||||
#define NET_ADDR_MPLS(label) \
|
||||
((net_addr_mpls) { NET_MPLS, 20, sizeof(net_addr_mpls), label })
|
||||
|
||||
@ -189,6 +204,9 @@ 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_ip6_sadr(net_addr *a, ip6_addr dst_prefix, uint dst_pxlen, ip6_addr src_prefix, uint src_pxlen)
|
||||
{ *(net_addr_ip6_sadr *)a = NET_ADDR_IP6_SADR(dst_prefix, dst_pxlen, src_prefix, src_pxlen); }
|
||||
|
||||
static inline void net_fill_mpls(net_addr *a, u32 label)
|
||||
{ *(net_addr_mpls *)a = NET_ADDR_MPLS(label); }
|
||||
|
||||
@ -222,6 +240,16 @@ static inline void net_fill_flow6(net_addr *a, ip6_addr prefix, uint pxlen, byte
|
||||
memcpy(f->data, data, dlen);
|
||||
}
|
||||
|
||||
/* Make NET_IP6_SADR from NET_IP6, assuming there is enough space */
|
||||
static inline void net_make_ip6_sadr(net_addr *a)
|
||||
{
|
||||
net_addr_ip6_sadr *n = (void *) a;
|
||||
n->type = NET_IP6_SADR;
|
||||
n->length = sizeof(net_addr_ip6_sadr);
|
||||
n->src_pxlen = 0;
|
||||
n->src_prefix = IP6_NONE;
|
||||
}
|
||||
|
||||
static inline int net_val_match(u8 type, u32 mask)
|
||||
{ return !!((1 << type) & mask); }
|
||||
|
||||
@ -261,6 +289,7 @@ static inline ip_addr net_prefix(const net_addr *a)
|
||||
case NET_VPN6:
|
||||
case NET_ROA6:
|
||||
case NET_FLOW6:
|
||||
case NET_IP6_SADR:
|
||||
return ipa_from_ip6(net6_prefix(a));
|
||||
|
||||
case NET_MPLS:
|
||||
@ -328,6 +357,9 @@ static inline int net_equal_flow4(const net_addr_flow4 *a, const net_addr_flow4
|
||||
static inline int net_equal_flow6(const net_addr_flow6 *a, const net_addr_flow6 *b)
|
||||
{ return net_equal((const net_addr *) a, (const net_addr *) b); }
|
||||
|
||||
static inline int net_equal_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b)
|
||||
{ return !memcmp(a, b, sizeof(net_addr_ip6_sadr)); }
|
||||
|
||||
static inline int net_equal_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
|
||||
{ return !memcmp(a, b, sizeof(net_addr_mpls)); }
|
||||
|
||||
@ -338,6 +370,12 @@ 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_dst_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b)
|
||||
{ return ip6_equal(a->dst_prefix, b->dst_prefix) && (a->dst_pxlen == b->dst_pxlen); }
|
||||
|
||||
static inline int net_equal_src_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b)
|
||||
{ return ip6_equal(a->src_prefix, b->src_prefix) && (a->src_pxlen == b->src_pxlen); }
|
||||
|
||||
|
||||
static inline int net_zero_ip4(const net_addr_ip4 *a)
|
||||
{ return !a->pxlen && ip4_zero(a->prefix); }
|
||||
@ -391,6 +429,13 @@ static inline int net_compare_flow4(const net_addr_flow4 *a, const net_addr_flow
|
||||
static inline int net_compare_flow6(const net_addr_flow6 *a, const net_addr_flow6 *b)
|
||||
{ return ip6_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen) ?: uint_cmp(a->length, b->length) ?: memcmp(a->data, b->data, a->length - sizeof(net_addr_flow6)); }
|
||||
|
||||
static inline int net_compare_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b)
|
||||
{
|
||||
return
|
||||
ip6_compare(a->dst_prefix, b->dst_prefix) ?: uint_cmp(a->dst_pxlen, b->dst_pxlen) ?:
|
||||
ip6_compare(a->src_prefix, b->src_prefix) ?: uint_cmp(a->src_pxlen, b->src_pxlen);
|
||||
}
|
||||
|
||||
static inline int net_compare_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
|
||||
{ return uint_cmp(a->label, b->label); }
|
||||
|
||||
@ -424,6 +469,9 @@ static inline void net_copy_flow4(net_addr_flow4 *dst, const net_addr_flow4 *src
|
||||
static inline void net_copy_flow6(net_addr_flow6 *dst, const net_addr_flow6 *src)
|
||||
{ memcpy(dst, src, src->length); }
|
||||
|
||||
static inline void net_copy_ip6_sadr(net_addr_ip6_sadr *dst, const net_addr_ip6_sadr *src)
|
||||
{ memcpy(dst, src, sizeof(net_addr_ip6_sadr)); }
|
||||
|
||||
static inline void net_copy_mpls(net_addr_mpls *dst, const net_addr_mpls *src)
|
||||
{ memcpy(dst, src, sizeof(net_addr_mpls)); }
|
||||
|
||||
@ -456,6 +504,9 @@ static inline u32 net_hash_flow4(const net_addr_flow4 *n)
|
||||
static inline u32 net_hash_flow6(const net_addr_flow6 *n)
|
||||
{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
|
||||
|
||||
static inline u32 net_hash_ip6_sadr(const net_addr_ip6_sadr *n)
|
||||
{ return net_hash_ip6((net_addr_ip6 *) n); }
|
||||
|
||||
static inline u32 net_hash_mpls(const net_addr_mpls *n)
|
||||
{ return n->label; }
|
||||
|
||||
@ -508,6 +559,9 @@ static inline int net_validate_flow6(const net_addr_flow6 *n)
|
||||
static inline int net_validate_mpls(const net_addr_mpls *n)
|
||||
{ return n->label < (1 << 20); }
|
||||
|
||||
static inline int net_validate_ip6_sadr(const net_addr_ip6_sadr *n)
|
||||
{ return net_validate_px6(n->dst_prefix, n->dst_pxlen) && net_validate_px6(n->src_prefix, n->src_pxlen); }
|
||||
|
||||
int net_validate(const net_addr *N);
|
||||
|
||||
|
||||
@ -523,6 +577,12 @@ static inline void net_normalize_vpn4(net_addr_vpn4 *n)
|
||||
static inline void net_normalize_vpn6(net_addr_vpn6 *n)
|
||||
{ net_normalize_ip6((net_addr_ip6 *) n); }
|
||||
|
||||
static inline void net_normalize_ip6_sadr(net_addr_ip6_sadr *n)
|
||||
{
|
||||
n->dst_prefix = ip6_and(n->dst_prefix, ip6_mkmask(n->dst_pxlen));
|
||||
n->src_prefix = ip6_and(n->src_prefix, ip6_mkmask(n->src_pxlen));
|
||||
}
|
||||
|
||||
void net_normalize(net_addr *N);
|
||||
|
||||
|
||||
@ -530,17 +590,29 @@ int net_classify(const net_addr *N);
|
||||
int net_format(const net_addr *N, char *buf, int buflen);
|
||||
int rd_format(const u64 rd, char *buf, int buflen);
|
||||
|
||||
static inline int ipa_in_net_ip4(ip4_addr a, const net_addr_ip4 *n)
|
||||
{ return ip4_zero(ip4_and(ip4_xor(a, n->prefix), ip4_mkmask(n->pxlen))); }
|
||||
static inline int ipa_in_px4(ip4_addr a, ip4_addr prefix, uint pxlen)
|
||||
{ return ip4_zero(ip4_and(ip4_xor(a, prefix), ip4_mkmask(pxlen))); }
|
||||
|
||||
static inline int net_in_net_ip4(const net_addr_ip4 *a, const net_addr_ip4 *b)
|
||||
{ return (a->pxlen >= b->pxlen) && ipa_in_net_ip4(a->prefix, b); }
|
||||
static inline int ipa_in_px6(ip6_addr a, ip6_addr prefix, uint pxlen)
|
||||
{ return ip6_zero(ip6_and(ip6_xor(a, prefix), ip6_mkmask(pxlen))); }
|
||||
|
||||
static inline int ipa_in_net_ip4(ip4_addr a, const net_addr_ip4 *n)
|
||||
{ return ipa_in_px4(a, n->prefix, n->pxlen); }
|
||||
|
||||
static inline int ipa_in_net_ip6(ip6_addr a, const net_addr_ip6 *n)
|
||||
{ return ip6_zero(ip6_and(ip6_xor(a, n->prefix), ip6_mkmask(n->pxlen))); }
|
||||
{ return ipa_in_px6(a, n->prefix, n->pxlen); }
|
||||
|
||||
static inline int net_in_net_ip4(const net_addr_ip4 *a, const net_addr_ip4 *b)
|
||||
{ return (a->pxlen >= b->pxlen) && ipa_in_px4(a->prefix, b->prefix, b->pxlen); }
|
||||
|
||||
static inline int net_in_net_ip6(const net_addr_ip6 *a, const net_addr_ip6 *b)
|
||||
{ return (a->pxlen >= b->pxlen) && ipa_in_net_ip6(a->prefix, b); }
|
||||
{ return (a->pxlen >= b->pxlen) && ipa_in_px6(a->prefix, b->prefix, b->pxlen); }
|
||||
|
||||
static inline int net_in_net_dst_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b)
|
||||
{ return (a->dst_pxlen >= b->dst_pxlen) && ipa_in_px6(a->dst_prefix, b->dst_prefix, b->dst_pxlen); }
|
||||
|
||||
static inline int net_in_net_src_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b)
|
||||
{ return (a->src_pxlen >= b->src_pxlen) && ipa_in_px6(a->src_prefix, b->src_prefix, b->src_pxlen); }
|
||||
|
||||
int ipa_in_netX(const ip_addr A, const net_addr *N);
|
||||
int net_in_netX(const net_addr *A, const net_addr *N);
|
||||
|
@ -66,7 +66,7 @@ CF_DECLS
|
||||
|
||||
CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
|
||||
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, TABLE, STATES, ROUTES, FILTERS)
|
||||
CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6)
|
||||
CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, MPLS)
|
||||
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
|
||||
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
|
||||
CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512)
|
||||
@ -77,7 +77,7 @@ CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US)
|
||||
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
|
||||
|
||||
/* For r_args_channel */
|
||||
CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC)
|
||||
CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC)
|
||||
|
||||
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
|
||||
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL)
|
||||
@ -134,6 +134,7 @@ gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ;
|
||||
net_type:
|
||||
IPV4 { $$ = NET_IP4; }
|
||||
| IPV6 { $$ = NET_IP6; }
|
||||
| IPV6 SADR { $$ = NET_IP6_SADR; }
|
||||
| VPN4 { $$ = NET_VPN4; }
|
||||
| VPN6 { $$ = NET_VPN6; }
|
||||
| ROA4 { $$ = NET_ROA4; }
|
||||
@ -143,7 +144,7 @@ net_type:
|
||||
| MPLS { $$ = NET_MPLS; }
|
||||
;
|
||||
|
||||
CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6)
|
||||
CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, IP6_SADR)
|
||||
|
||||
|
||||
/* Creation of routing tables */
|
||||
@ -625,6 +626,7 @@ r_args_for:
|
||||
}
|
||||
| net_vpn4_
|
||||
| net_vpn6_
|
||||
| net_ip6_sadr_
|
||||
| VPN_RD IP4 {
|
||||
$$ = cfg_alloc(sizeof(net_addr_vpn4));
|
||||
net_fill_vpn4($$, $2, IP4_MAX_PREFIX_LENGTH, $1);
|
||||
@ -633,6 +635,10 @@ r_args_for:
|
||||
$$ = cfg_alloc(sizeof(net_addr_vpn6));
|
||||
net_fill_vpn6($$, $2, IP6_MAX_PREFIX_LENGTH, $1);
|
||||
}
|
||||
| IP6 FROM IP6 {
|
||||
$$ = cfg_alloc(sizeof(net_addr_ip6_sadr));
|
||||
net_fill_ip6_sadr($$, $1, IP6_MAX_PREFIX_LENGTH, $3, IP6_MAX_PREFIX_LENGTH);
|
||||
}
|
||||
| SYM {
|
||||
if ($1->class == (SYM_CONSTANT | T_IP))
|
||||
{
|
||||
@ -666,6 +672,7 @@ r_args_channel:
|
||||
| IPV6 { $$ = "ipv6"; }
|
||||
| IPV6_MC { $$ = "ipv6-mc"; }
|
||||
| IPV6_MPLS { $$ = "ipv6-mpls"; }
|
||||
| IPV6_SADR { $$ = "ipv6-sadr"; }
|
||||
| VPN4 { $$ = "vpn4"; }
|
||||
| VPN4_MC { $$ = "vpn4-mc"; }
|
||||
| VPN4_MPLS { $$ = "vpn4-mpls"; }
|
||||
|
@ -28,4 +28,3 @@
|
||||
void mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -282,7 +282,7 @@ void rt_preconfig(struct config *);
|
||||
void rt_commit(struct config *new, struct config *old);
|
||||
void rt_lock_table(rtable *);
|
||||
void rt_unlock_table(rtable *);
|
||||
void rt_setup(pool *, rtable *, char *, struct rtable_config *);
|
||||
void rt_setup(pool *, rtable *, struct rtable_config *);
|
||||
static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); }
|
||||
static inline net *net_find_valid(rtable *tab, const net_addr *addr)
|
||||
{ net *n = net_find(tab, addr); return (n && rte_is_valid(n->routes)) ? n : NULL; }
|
||||
|
@ -92,8 +92,7 @@ fib_ht_free(struct fib_node **h)
|
||||
}
|
||||
|
||||
|
||||
static u32
|
||||
fib_hash(struct fib *f, const net_addr *a);
|
||||
static inline u32 fib_hash(struct fib *f, const net_addr *a);
|
||||
|
||||
/**
|
||||
* fib_init - initialize a new FIB
|
||||
@ -198,24 +197,11 @@ fib_rehash(struct fib *f, int step)
|
||||
})
|
||||
|
||||
|
||||
static u32
|
||||
static inline u32
|
||||
fib_hash(struct fib *f, const net_addr *a)
|
||||
{
|
||||
ASSERT(f->addr_type == a->type);
|
||||
|
||||
switch (f->addr_type)
|
||||
{
|
||||
case NET_IP4: return FIB_HASH(f, a, ip4);
|
||||
case NET_IP6: return FIB_HASH(f, a, ip6);
|
||||
case NET_VPN4: return FIB_HASH(f, a, vpn4);
|
||||
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_FLOW4: return FIB_HASH(f, a, flow4);
|
||||
case NET_FLOW6: return FIB_HASH(f, a, flow6);
|
||||
case NET_MPLS: return FIB_HASH(f, a, mpls);
|
||||
default: bug("invalid type");
|
||||
}
|
||||
/* Same as FIB_HASH() */
|
||||
return net_hash(a) >> f->hash_shift;
|
||||
}
|
||||
|
||||
void *
|
||||
@ -250,6 +236,7 @@ fib_find(struct fib *f, const net_addr *a)
|
||||
case NET_ROA6: return FIB_FIND(f, a, roa6);
|
||||
case NET_FLOW4: return FIB_FIND(f, a, flow4);
|
||||
case NET_FLOW6: return FIB_FIND(f, a, flow6);
|
||||
case NET_IP6_SADR: return FIB_FIND(f, a, ip6_sadr);
|
||||
case NET_MPLS: return FIB_FIND(f, a, mpls);
|
||||
default: bug("invalid type");
|
||||
}
|
||||
@ -270,6 +257,7 @@ fib_insert(struct fib *f, const net_addr *a, struct fib_node *e)
|
||||
case NET_ROA6: FIB_INSERT(f, a, e, roa6); return;
|
||||
case NET_FLOW4: FIB_INSERT(f, a, e, flow4); return;
|
||||
case NET_FLOW6: FIB_INSERT(f, a, e, flow6); return;
|
||||
case NET_IP6_SADR: FIB_INSERT(f, a, e, ip6_sadr); return;
|
||||
case NET_MPLS: FIB_INSERT(f, a, e, mpls); return;
|
||||
default: bug("invalid type");
|
||||
}
|
||||
|
@ -156,7 +156,8 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
|
||||
* command may change the export filter and do not update routes.
|
||||
*/
|
||||
int do_export = (ic > 0) ||
|
||||
(f_run(ec->out_filter, &e, &tmpa, c->show_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
|
||||
(f_run(ec->out_filter, &e, &tmpa, c->show_pool,
|
||||
FF_FORCE_TMPATTR | FF_SILENT) <= F_ACCEPT);
|
||||
|
||||
if (do_export != (d->export_mode == RSEM_EXPORT))
|
||||
goto skip;
|
||||
@ -418,4 +419,3 @@ rt_show(struct rt_show_data *d)
|
||||
cli_msg(8001, "Network not found");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,6 +85,45 @@ net_route_ip6(rtable *t, net_addr_ip6 *n)
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
net_route_ip6_sadr(rtable *t, net_addr_ip6_sadr *n)
|
||||
{
|
||||
struct fib_node *fn;
|
||||
|
||||
while (1)
|
||||
{
|
||||
net *best = NULL;
|
||||
int best_pxlen = 0;
|
||||
|
||||
/* We need to do dst first matching. Since sadr addresses are hashed on dst
|
||||
prefix only, find the hash table chain and go through it to find the
|
||||
match with the smallest matching src prefix. */
|
||||
for (fn = fib_get_chain(&t->fib, (net_addr *) n); fn; fn = fn->next)
|
||||
{
|
||||
net_addr_ip6_sadr *a = (void *) fn->addr;
|
||||
|
||||
if (net_equal_dst_ip6_sadr(n, a) &&
|
||||
net_in_net_src_ip6_sadr(n, a) &&
|
||||
(a->src_pxlen >= best_pxlen))
|
||||
{
|
||||
best = fib_node_to_user(&t->fib, fn);
|
||||
best_pxlen = a->src_pxlen;
|
||||
}
|
||||
}
|
||||
|
||||
if (best)
|
||||
return best;
|
||||
|
||||
if (!n->dst_pxlen)
|
||||
break;
|
||||
|
||||
n->dst_pxlen--;
|
||||
ip6_clrbit(&n->dst_prefix, n->dst_pxlen);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *
|
||||
net_route(rtable *tab, const net_addr *n)
|
||||
{
|
||||
@ -105,6 +144,9 @@ net_route(rtable *tab, const net_addr *n)
|
||||
case NET_ROA6:
|
||||
return net_route_ip6(tab, (net_addr_ip6 *) n0);
|
||||
|
||||
case NET_IP6_SADR:
|
||||
return net_route_ip6_sadr(tab, (net_addr_ip6_sadr *) n0);
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@ -387,7 +429,8 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, ea_list **tmpa, linpo
|
||||
}
|
||||
|
||||
v = filter && ((filter == FILTER_REJECT) ||
|
||||
(f_run(filter, &rt, tmpa, pool, FF_FORCE_TMPATTR) > F_ACCEPT));
|
||||
(f_run(filter, &rt, tmpa, pool,
|
||||
FF_FORCE_TMPATTR | (silent ? FF_SILENT : 0)) > F_ACCEPT));
|
||||
if (v)
|
||||
{
|
||||
if (silent)
|
||||
@ -1419,7 +1462,8 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
|
||||
ea_list *tmpa = rte_make_tmp_attrs(rt, rte_update_pool);
|
||||
int v = p->import_control ? p->import_control(p, &rt, &tmpa, rte_update_pool) : 0;
|
||||
if (v == RIC_PROCESS)
|
||||
v = (f_run(filter, &rt, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
|
||||
v = (f_run(filter, &rt, &tmpa, rte_update_pool,
|
||||
FF_FORCE_TMPATTR | FF_SILENT) <= F_ACCEPT);
|
||||
|
||||
/* Discard temporary rte */
|
||||
if (rt != n->routes)
|
||||
@ -1597,23 +1641,20 @@ rt_event(void *ptr)
|
||||
}
|
||||
|
||||
void
|
||||
rt_setup(pool *p, rtable *t, char *name, struct rtable_config *cf)
|
||||
rt_setup(pool *p, rtable *t, struct rtable_config *cf)
|
||||
{
|
||||
bzero(t, sizeof(*t));
|
||||
t->name = name;
|
||||
t->name = cf->name;
|
||||
t->config = cf;
|
||||
t->addr_type = cf ? cf->addr_type : NET_IP4;
|
||||
t->addr_type = cf->addr_type;
|
||||
fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL);
|
||||
init_list(&t->channels);
|
||||
|
||||
if (cf)
|
||||
{
|
||||
t->rt_event = ev_new(p);
|
||||
t->rt_event->hook = rt_event;
|
||||
t->rt_event->data = t;
|
||||
t->gc_time = current_time();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* rt_init - initialize routing tables
|
||||
@ -2088,7 +2129,7 @@ rt_commit(struct config *new, struct config *old)
|
||||
{
|
||||
rtable *t = mb_alloc(rt_table_pool, sizeof(struct rtable));
|
||||
DBG("\t%s: created\n", r->name);
|
||||
rt_setup(rt_table_pool, t, r->name, r);
|
||||
rt_setup(rt_table_pool, t, r);
|
||||
add_tail(&routing_tables, &t->n);
|
||||
r->table = t;
|
||||
}
|
||||
@ -2390,12 +2431,13 @@ static int
|
||||
rt_update_hostentry(rtable *tab, struct hostentry *he)
|
||||
{
|
||||
rta *old_src = he->src;
|
||||
int direct = 0;
|
||||
int pxlen = 0;
|
||||
|
||||
/* Reset the hostentry */
|
||||
he->src = NULL;
|
||||
he->nexthop_linkable = 0;
|
||||
he->dest = RTD_UNREACHABLE;
|
||||
he->nexthop_linkable = 0;
|
||||
he->igp_metric = 0;
|
||||
|
||||
net_addr he_addr;
|
||||
@ -2415,9 +2457,7 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
|
||||
goto done;
|
||||
}
|
||||
|
||||
he->dest = a->dest;
|
||||
he->nexthop_linkable = 1;
|
||||
if (he->dest == RTD_UNICAST)
|
||||
if (a->dest == RTD_UNICAST)
|
||||
{
|
||||
for (struct nexthop *nh = &(a->nh); nh; nh = nh->next)
|
||||
if (ipa_zero(nh->gw))
|
||||
@ -2430,12 +2470,13 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
|
||||
goto done;
|
||||
}
|
||||
|
||||
he->nexthop_linkable = 0;
|
||||
break;
|
||||
direct++;
|
||||
}
|
||||
}
|
||||
|
||||
he->src = rta_clone(a);
|
||||
he->dest = a->dest;
|
||||
he->nexthop_linkable = !direct;
|
||||
he->igp_metric = rt_get_igp_metric(e);
|
||||
}
|
||||
|
||||
|
@ -1935,8 +1935,10 @@ babel_show_neighbors(struct proto *P, char *iff)
|
||||
}
|
||||
|
||||
static void
|
||||
babel_show_entries_(struct babel_proto *p UNUSED, struct fib *rtable)
|
||||
babel_show_entries_(struct babel_proto *p, struct fib *rtable)
|
||||
{
|
||||
int width = babel_sadr_enabled(p) ? -54 : -24;
|
||||
|
||||
FIB_WALK(rtable, struct babel_entry, e)
|
||||
{
|
||||
struct babel_route *r = NULL;
|
||||
@ -1950,13 +1952,13 @@ babel_show_entries_(struct babel_proto *p UNUSED, struct fib *rtable)
|
||||
srcs++;
|
||||
|
||||
if (e->valid)
|
||||
cli_msg(-1025, "%-24N %-23lR %6u %5u %7u %7u",
|
||||
cli_msg(-1025, "%-*N %-23lR %6u %5u %7u %7u", width,
|
||||
e->n.addr, e->router_id, e->metric, e->seqno, rts, srcs);
|
||||
else if (r = e->selected)
|
||||
cli_msg(-1025, "%-24N %-23lR %6u %5u %7u %7u",
|
||||
cli_msg(-1025, "%-*N %-23lR %6u %5u %7u %7u", width,
|
||||
e->n.addr, r->router_id, r->metric, r->seqno, rts, srcs);
|
||||
else
|
||||
cli_msg(-1025, "%-24N %-23s %6s %5s %7u %7u",
|
||||
cli_msg(-1025, "%-*N %-23s %6s %5s %7u %7u", width,
|
||||
e->n.addr, "<none>", "-", "-", rts, srcs);
|
||||
}
|
||||
FIB_WALK_END;
|
||||
@ -1966,6 +1968,7 @@ void
|
||||
babel_show_entries(struct proto *P)
|
||||
{
|
||||
struct babel_proto *p = (void *) P;
|
||||
int width = babel_sadr_enabled(p) ? -54 : -24;
|
||||
|
||||
if (p->p.proto_state != PS_UP)
|
||||
{
|
||||
@ -1975,7 +1978,7 @@ babel_show_entries(struct proto *P)
|
||||
}
|
||||
|
||||
cli_msg(-1025, "%s:", p->p.name);
|
||||
cli_msg(-1025, "%-24s %-23s %6s %5s %7s %7s",
|
||||
cli_msg(-1025, "%-*s %-23s %6s %5s %7s %7s", width,
|
||||
"Prefix", "Router ID", "Metric", "Seqno", "Routes", "Sources");
|
||||
|
||||
babel_show_entries_(p, &p->ip4_rtable);
|
||||
@ -1985,8 +1988,10 @@ babel_show_entries(struct proto *P)
|
||||
}
|
||||
|
||||
static void
|
||||
babel_show_routes_(struct babel_proto *p UNUSED, struct fib *rtable)
|
||||
babel_show_routes_(struct babel_proto *p, struct fib *rtable)
|
||||
{
|
||||
int width = babel_sadr_enabled(p) ? -54 : -24;
|
||||
|
||||
FIB_WALK(rtable, struct babel_entry, e)
|
||||
{
|
||||
struct babel_route *r;
|
||||
@ -1994,7 +1999,7 @@ babel_show_routes_(struct babel_proto *p UNUSED, struct fib *rtable)
|
||||
{
|
||||
char c = (r == e->selected) ? '*' : (r->feasible ? '+' : ' ');
|
||||
btime time = r->expires ? r->expires - current_time() : 0;
|
||||
cli_msg(-1025, "%-24N %-25I %-10s %5u %c %5u %7t",
|
||||
cli_msg(-1025, "%-*N %-25I %-10s %5u %c %5u %7t", width,
|
||||
e->n.addr, r->next_hop, r->neigh->ifa->ifname,
|
||||
r->metric, c, r->seqno, MAX(time, 0));
|
||||
}
|
||||
@ -2006,6 +2011,7 @@ void
|
||||
babel_show_routes(struct proto *P)
|
||||
{
|
||||
struct babel_proto *p = (void *) P;
|
||||
int width = babel_sadr_enabled(p) ? -54 : -24;
|
||||
|
||||
if (p->p.proto_state != PS_UP)
|
||||
{
|
||||
@ -2015,7 +2021,7 @@ babel_show_routes(struct proto *P)
|
||||
}
|
||||
|
||||
cli_msg(-1025, "%s:", p->p.name);
|
||||
cli_msg(-1025, "%-24s %-25s %-9s %6s F %5s %7s",
|
||||
cli_msg(-1025, "%-*s %-25s %-9s %6s F %5s %7s", width,
|
||||
"Prefix", "Nexthop", "Interface", "Metric", "Seqno", "Expires");
|
||||
|
||||
babel_show_routes_(p, &p->ip4_rtable);
|
||||
@ -2139,7 +2145,7 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net,
|
||||
e = babel_get_entry(p, net->n.addr);
|
||||
|
||||
/* Activate triggered updates */
|
||||
if ((e->valid |= BABEL_ENTRY_VALID) ||
|
||||
if ((e->valid != BABEL_ENTRY_VALID) ||
|
||||
(e->router_id != rt_router_id))
|
||||
{
|
||||
babel_trigger_update(p);
|
||||
@ -2182,14 +2188,32 @@ babel_rte_same(struct rte *new, struct rte *old)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
babel_postconfig(struct proto_config *CF)
|
||||
{
|
||||
struct babel_config *cf = (void *) CF;
|
||||
struct channel_config *ip4, *ip6, *ip6_sadr;
|
||||
|
||||
ip4 = proto_cf_find_channel(CF, NET_IP4);
|
||||
ip6 = proto_cf_find_channel(CF, NET_IP6);
|
||||
ip6_sadr = proto_cf_find_channel(CF, NET_IP6_SADR);
|
||||
|
||||
if (ip6 && ip6_sadr)
|
||||
cf_error("Both ipv6 and ipv6-sadr channels");
|
||||
|
||||
cf->ip4_channel = ip4;
|
||||
cf->ip6_channel = ip6 ?: ip6_sadr;
|
||||
}
|
||||
|
||||
static struct proto *
|
||||
babel_init(struct proto_config *CF)
|
||||
{
|
||||
struct proto *P = proto_new(CF);
|
||||
struct babel_proto *p = (void *) P;
|
||||
struct babel_config *cf = (void *) CF;
|
||||
|
||||
proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4));
|
||||
proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6));
|
||||
proto_configure_channel(P, &p->ip4_channel, cf->ip4_channel);
|
||||
proto_configure_channel(P, &p->ip6_channel, cf->ip6_channel);
|
||||
|
||||
P->if_notify = babel_if_notify;
|
||||
P->rt_notify = babel_rt_notify;
|
||||
@ -2207,10 +2231,11 @@ babel_start(struct proto *P)
|
||||
{
|
||||
struct babel_proto *p = (void *) P;
|
||||
struct babel_config *cf = (void *) P->cf;
|
||||
u8 ip6_type = cf->ip6_channel ? cf->ip6_channel->net_type : NET_IP6;
|
||||
|
||||
fib_init(&p->ip4_rtable, P->pool, NET_IP4, sizeof(struct babel_entry),
|
||||
OFFSETOF(struct babel_entry, n), 0, babel_init_entry);
|
||||
fib_init(&p->ip6_rtable, P->pool, NET_IP6, sizeof(struct babel_entry),
|
||||
fib_init(&p->ip6_rtable, P->pool, ip6_type, sizeof(struct babel_entry),
|
||||
OFFSETOF(struct babel_entry, n), 0, babel_init_entry);
|
||||
|
||||
init_list(&p->interfaces);
|
||||
@ -2258,11 +2283,15 @@ babel_reconfigure(struct proto *P, struct proto_config *CF)
|
||||
{
|
||||
struct babel_proto *p = (void *) P;
|
||||
struct babel_config *new = (void *) CF;
|
||||
u8 ip6_type = new->ip6_channel ? new->ip6_channel->net_type : NET_IP6;
|
||||
|
||||
TRACE(D_EVENTS, "Reconfiguring");
|
||||
|
||||
if (!proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4)) ||
|
||||
!proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6)))
|
||||
if (p->ip6_rtable.addr_type != ip6_type)
|
||||
return 0;
|
||||
|
||||
if (!proto_configure_channel(P, &p->ip4_channel, new->ip4_channel) ||
|
||||
!proto_configure_channel(P, &p->ip6_channel, new->ip6_channel))
|
||||
return 0;
|
||||
|
||||
p->p.cf = CF;
|
||||
@ -2280,9 +2309,10 @@ struct protocol proto_babel = {
|
||||
.template = "babel%d",
|
||||
.attr_class = EAP_BABEL,
|
||||
.preference = DEF_PREF_BABEL,
|
||||
.channel_mask = NB_IP,
|
||||
.channel_mask = NB_IP | NB_IP6_SADR,
|
||||
.proto_size = sizeof(struct babel_proto),
|
||||
.config_size = sizeof(struct babel_config),
|
||||
.postconfig = babel_postconfig,
|
||||
.init = babel_init,
|
||||
.dump = babel_dump,
|
||||
.start = babel_start,
|
||||
|
@ -85,7 +85,10 @@ enum babel_tlv_type {
|
||||
|
||||
enum babel_subtlv_type {
|
||||
BABEL_SUBTLV_PAD1 = 0,
|
||||
BABEL_SUBTLV_PADN = 1
|
||||
BABEL_SUBTLV_PADN = 1,
|
||||
|
||||
/* Mandatory subtlvs */
|
||||
BABEL_SUBTLV_SOURCE_PREFIX = 128,
|
||||
};
|
||||
|
||||
enum babel_iface_type {
|
||||
@ -109,6 +112,9 @@ struct babel_config {
|
||||
struct proto_config c;
|
||||
list iface_list; /* List of iface configs (struct babel_iface_config) */
|
||||
uint hold_time; /* Time to hold stale entries and unreachable routes */
|
||||
|
||||
struct channel_config *ip4_channel;
|
||||
struct channel_config *ip6_channel;
|
||||
};
|
||||
|
||||
struct babel_iface_config {
|
||||
@ -303,7 +309,10 @@ struct babel_msg_update {
|
||||
u16 seqno;
|
||||
u16 metric;
|
||||
u64 router_id;
|
||||
union {
|
||||
net_addr net;
|
||||
net_addr_ip6_sadr net_sadr;
|
||||
};
|
||||
ip_addr next_hop;
|
||||
ip_addr sender;
|
||||
};
|
||||
@ -311,7 +320,10 @@ struct babel_msg_update {
|
||||
struct babel_msg_route_request {
|
||||
u8 type;
|
||||
u8 full;
|
||||
union {
|
||||
net_addr net;
|
||||
net_addr_ip6_sadr net_sadr;
|
||||
};
|
||||
};
|
||||
|
||||
struct babel_msg_seqno_request {
|
||||
@ -319,7 +331,10 @@ struct babel_msg_seqno_request {
|
||||
u8 hop_count;
|
||||
u16 seqno;
|
||||
u64 router_id;
|
||||
union {
|
||||
net_addr net;
|
||||
net_addr_ip6_sadr net_sadr;
|
||||
};
|
||||
ip_addr sender;
|
||||
};
|
||||
|
||||
@ -339,6 +354,8 @@ struct babel_msg_node {
|
||||
union babel_msg msg;
|
||||
};
|
||||
|
||||
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);
|
||||
|
@ -105,6 +105,13 @@ struct babel_tlv_seqno_request {
|
||||
u8 addr[0];
|
||||
} PACKED;
|
||||
|
||||
struct babel_subtlv_source_prefix {
|
||||
u8 type;
|
||||
u8 length;
|
||||
u8 plen;
|
||||
u8 addr[0];
|
||||
} PACKED;
|
||||
|
||||
|
||||
/* Hello flags */
|
||||
#define BABEL_HF_UNICAST 0x8000
|
||||
@ -127,6 +134,7 @@ struct babel_parse_state {
|
||||
u8 def_ip6_prefix_seen; /* def_ip6_prefix is valid */
|
||||
u8 def_ip4_prefix_seen; /* def_ip4_prefix is valid */
|
||||
u8 current_tlv_endpos; /* End of self-terminating TLVs (offset from start) */
|
||||
u8 sadr_enabled;
|
||||
};
|
||||
|
||||
enum parse_result {
|
||||
@ -237,6 +245,7 @@ static int babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *msg, stru
|
||||
static int babel_read_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
|
||||
static int babel_read_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
|
||||
static int babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
|
||||
static int babel_read_source_prefix(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
|
||||
|
||||
static uint babel_write_ack(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
|
||||
static uint babel_write_hello(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
|
||||
@ -244,6 +253,7 @@ static uint babel_write_ihu(struct babel_tlv *hdr, union babel_msg *msg, struct
|
||||
static uint babel_write_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
|
||||
static uint babel_write_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
|
||||
static uint babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
|
||||
static int babel_write_source_prefix(struct babel_tlv *hdr, net_addr *net, uint max_len);
|
||||
|
||||
struct babel_tlv_data {
|
||||
u8 min_length;
|
||||
@ -640,6 +650,9 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
|
||||
ip6_addr prefix6 = get_ip6(buf);
|
||||
net_fill_ip6(&msg->net, prefix6, tlv->plen);
|
||||
|
||||
if (state->sadr_enabled)
|
||||
net_make_ip6_sadr(&msg->net);
|
||||
|
||||
if (tlv->flags & BABEL_UF_DEF_PREFIX)
|
||||
{
|
||||
put_ip6(state->def_ip6_prefix, prefix6);
|
||||
@ -770,12 +783,21 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
|
||||
put_u16(&tlv->seqno, msg->seqno);
|
||||
put_u16(&tlv->metric, msg->metric);
|
||||
|
||||
if (msg->net.type == NET_IP6_SADR)
|
||||
{
|
||||
int l = babel_write_source_prefix(hdr, &msg->net, max_len - (len0 + len));
|
||||
if (l < 0)
|
||||
return 0;
|
||||
|
||||
len += l;
|
||||
}
|
||||
|
||||
return len0 + len;
|
||||
}
|
||||
|
||||
static int
|
||||
babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
|
||||
struct babel_parse_state *state UNUSED)
|
||||
struct babel_parse_state *state)
|
||||
{
|
||||
struct babel_tlv_route_request *tlv = (void *) hdr;
|
||||
struct babel_msg_route_request *msg = &m->route_request;
|
||||
@ -812,6 +834,10 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
|
||||
|
||||
read_ip6_px(&msg->net, tlv->addr, tlv->plen);
|
||||
state->current_tlv_endpos += BYTES(tlv->plen);
|
||||
|
||||
if (state->sadr_enabled)
|
||||
net_make_ip6_sadr(&msg->net);
|
||||
|
||||
return PARSE_SUCCESS;
|
||||
|
||||
case BABEL_AE_IP6_LL:
|
||||
@ -856,6 +882,15 @@ babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m,
|
||||
put_ip6_px(tlv->addr, &msg->net);
|
||||
}
|
||||
|
||||
if (msg->net.type == NET_IP6_SADR)
|
||||
{
|
||||
int l = babel_write_source_prefix(hdr, &msg->net, max_len - len);
|
||||
if (l < 0)
|
||||
return 0;
|
||||
|
||||
len += l;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -900,6 +935,10 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
|
||||
|
||||
read_ip6_px(&msg->net, tlv->addr, tlv->plen);
|
||||
state->current_tlv_endpos += BYTES(tlv->plen);
|
||||
|
||||
if (state->sadr_enabled)
|
||||
net_make_ip6_sadr(&msg->net);
|
||||
|
||||
return PARSE_SUCCESS;
|
||||
|
||||
case BABEL_AE_IP6_LL:
|
||||
@ -943,38 +982,147 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
|
||||
tlv->hop_count = msg->hop_count;
|
||||
put_u64(&tlv->router_id, msg->router_id);
|
||||
|
||||
if (msg->net.type == NET_IP6_SADR)
|
||||
{
|
||||
int l = babel_write_source_prefix(hdr, &msg->net, max_len - len);
|
||||
if (l < 0)
|
||||
return 0;
|
||||
|
||||
len += l;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
babel_read_source_prefix(struct babel_tlv *hdr, union babel_msg *msg,
|
||||
struct babel_parse_state *state UNUSED)
|
||||
{
|
||||
struct babel_subtlv_source_prefix *tlv = (void *) hdr;
|
||||
net_addr_ip6_sadr *net;
|
||||
|
||||
/*
|
||||
* We would like to skip the sub-TLV if SADR is not enabled, but we do not
|
||||
* know AF of the enclosing TLV yet. We will do that later.
|
||||
*/
|
||||
|
||||
/* Check internal consistency */
|
||||
if ((tlv->length < 1) ||
|
||||
(tlv->plen > IP6_MAX_PREFIX_LENGTH) ||
|
||||
(tlv->length < (1 + BYTES(tlv->plen))))
|
||||
return PARSE_ERROR;
|
||||
|
||||
/* Plen MUST NOT be 0 */
|
||||
if (tlv->plen == 0)
|
||||
return PARSE_ERROR;
|
||||
|
||||
switch(msg->type)
|
||||
{
|
||||
case BABEL_TLV_UPDATE:
|
||||
/* Wildcard updates with source prefix MUST be silently ignored */
|
||||
if (msg->update.wildcard)
|
||||
return PARSE_IGNORE;
|
||||
|
||||
net = (void *) &msg->update.net;
|
||||
break;
|
||||
|
||||
case BABEL_TLV_ROUTE_REQUEST:
|
||||
/* Wildcard requests with source addresses MUST be silently ignored */
|
||||
if (msg->route_request.full)
|
||||
return PARSE_IGNORE;
|
||||
|
||||
net = (void *) &msg->route_request.net;
|
||||
break;
|
||||
|
||||
case BABEL_TLV_SEQNO_REQUEST:
|
||||
net = (void *) &msg->seqno_request.net;
|
||||
break;
|
||||
|
||||
default:
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
|
||||
/* If SADR is active, the net has appropriate type */
|
||||
if (net->type != NET_IP6_SADR)
|
||||
return PARSE_IGNORE;
|
||||
|
||||
/* Duplicate Source Prefix sub-TLV; SHOULD ignore whole TLV */
|
||||
if (net->src_pxlen > 0)
|
||||
return PARSE_IGNORE;
|
||||
|
||||
net_addr_ip6 src;
|
||||
read_ip6_px((void *) &src, tlv->addr, tlv->plen);
|
||||
net->src_prefix = src.prefix;
|
||||
net->src_pxlen = src.pxlen;
|
||||
|
||||
return PARSE_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
babel_write_source_prefix(struct babel_tlv *hdr, net_addr *n, uint max_len)
|
||||
{
|
||||
struct babel_subtlv_source_prefix *tlv = (void *) NEXT_TLV(hdr);
|
||||
net_addr_ip6_sadr *net = (void *) n;
|
||||
|
||||
/* Do not use this sub-TLV for default prefix */
|
||||
if (net->src_pxlen == 0)
|
||||
return 0;
|
||||
|
||||
uint len = sizeof(*tlv) + BYTES(net->src_pxlen);
|
||||
|
||||
if (len > max_len)
|
||||
return -1;
|
||||
|
||||
TLV_HDR(tlv, BABEL_SUBTLV_SOURCE_PREFIX, len);
|
||||
hdr->length += len;
|
||||
|
||||
net_addr_ip6 src = NET_ADDR_IP6(net->src_prefix, net->src_pxlen);
|
||||
tlv->plen = src.pxlen;
|
||||
put_ip6_px(tlv->addr, (void *) &src);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static inline int
|
||||
babel_read_subtlvs(struct babel_tlv *hdr,
|
||||
union babel_msg *msg UNUSED,
|
||||
union babel_msg *msg,
|
||||
struct babel_parse_state *state)
|
||||
{
|
||||
struct babel_tlv *tlv;
|
||||
byte *pos, *end = (byte *) hdr + TLV_LENGTH(hdr);
|
||||
int res;
|
||||
|
||||
for (tlv = (void *) hdr + state->current_tlv_endpos;
|
||||
(void *) tlv < (void *) hdr + TLV_LENGTH(hdr);
|
||||
(byte *) tlv < end;
|
||||
tlv = NEXT_TLV(tlv))
|
||||
{
|
||||
/* Ugly special case */
|
||||
if (tlv->type == BABEL_TLV_PAD1)
|
||||
continue;
|
||||
|
||||
/* The end of the common TLV header */
|
||||
pos = (byte *)tlv + sizeof(struct babel_tlv);
|
||||
if ((pos > end) || (pos + tlv->length > end))
|
||||
return PARSE_ERROR;
|
||||
|
||||
/*
|
||||
* The subtlv type space is non-contiguous (due to the mandatory bit), so
|
||||
* use a switch for dispatch instead of the mapping array we use for TLVs
|
||||
*/
|
||||
switch (tlv->type)
|
||||
{
|
||||
case BABEL_SUBTLV_PAD1:
|
||||
case BABEL_SUBTLV_PADN:
|
||||
/* FIXME: Framing errors in PADN are silently ignored, see babel_process_packet() */
|
||||
case BABEL_SUBTLV_SOURCE_PREFIX:
|
||||
res = babel_read_source_prefix(tlv, msg, state);
|
||||
if (res != PARSE_SUCCESS)
|
||||
return res;
|
||||
break;
|
||||
|
||||
case BABEL_SUBTLV_PADN:
|
||||
default:
|
||||
/* Unknown mandatory subtlv; PARSE_IGNORE ignores the whole TLV */
|
||||
if (tlv->type > 128)
|
||||
{
|
||||
DBG("Babel: Mandatory subtlv %d found; skipping TLV\n", tlv->type);
|
||||
if (tlv->type >= 128)
|
||||
return PARSE_IGNORE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1197,6 +1345,7 @@ babel_process_packet(struct babel_pkt_header *pkt, int len,
|
||||
.ifa = ifa,
|
||||
.saddr = saddr,
|
||||
.next_hop_ip6 = saddr,
|
||||
.sadr_enabled = babel_sadr_enabled(p),
|
||||
};
|
||||
|
||||
if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION))
|
||||
|
@ -118,6 +118,7 @@ struct bgp_config {
|
||||
unsigned error_delay_time_min; /* Time to wait after an error is detected */
|
||||
unsigned error_delay_time_max;
|
||||
unsigned disable_after_error; /* Disable the protocol when error is detected */
|
||||
u32 disable_after_cease; /* Disable it when cease is received, bitfield */
|
||||
|
||||
char *password; /* Password used for MD5 authentication */
|
||||
int check_link; /* Use iface link state for liveness detection */
|
||||
|
@ -32,6 +32,12 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
|
||||
|
||||
%type <i32> bgp_afi
|
||||
|
||||
CF_KEYWORDS(CEASE, PREFIX, LIMIT, HIT, ADMINISTRATIVE, SHUTDOWN, RESET, PEER,
|
||||
CONFIGURATION, CHANGE, DECONFIGURED, CONNECTION, REJECTED, COLLISION,
|
||||
OUT, OF, RESOURCES)
|
||||
|
||||
%type<i> bgp_cease_mask bgp_cease_list bgp_cease_flag
|
||||
|
||||
CF_GRAMMAR
|
||||
|
||||
CF_ADDTO(proto, bgp_proto '}' )
|
||||
@ -74,6 +80,29 @@ bgp_nbr_opts:
|
||||
| bgp_nbr_opts AS expr { BGP_CFG->remote_as = $3; }
|
||||
;
|
||||
|
||||
bgp_cease_mask:
|
||||
/* true -> all except connection collision */
|
||||
bool { $$ = $1 ? ~(1 << 7) : 0; }
|
||||
| '{' bgp_cease_list '}' { $$ = $2; }
|
||||
;
|
||||
|
||||
bgp_cease_list:
|
||||
bgp_cease_flag
|
||||
| bgp_cease_list ',' bgp_cease_flag { $$ = $1 | $3; }
|
||||
;
|
||||
|
||||
bgp_cease_flag:
|
||||
CEASE { $$ = 1 << 0; }
|
||||
| PREFIX LIMIT HIT { $$ = 1 << 1; }
|
||||
| ADMINISTRATIVE SHUTDOWN { $$ = 1 << 2; }
|
||||
| PEER DECONFIGURED { $$ = 1 << 3; }
|
||||
| ADMINISTRATIVE RESET { $$ = 1 << 4; }
|
||||
| CONNECTION REJECTED { $$ = 1 << 5; }
|
||||
| CONFIGURATION CHANGE { $$ = 1 << 6; }
|
||||
| CONNECTION COLLISION { $$ = 1 << 7; }
|
||||
| OUT OF RESOURCES { $$ = 1 << 8; }
|
||||
;
|
||||
|
||||
bgp_proto:
|
||||
bgp_proto_start proto_name '{'
|
||||
| bgp_proto proto_item ';'
|
||||
@ -117,6 +146,7 @@ bgp_proto:
|
||||
| bgp_proto ERROR FORGET TIME expr ';' { BGP_CFG->error_amnesia_time = $5; }
|
||||
| bgp_proto ERROR WAIT TIME expr ',' expr ';' { BGP_CFG->error_delay_time_min = $5; BGP_CFG->error_delay_time_max = $7; }
|
||||
| bgp_proto DISABLE AFTER ERROR bool ';' { BGP_CFG->disable_after_error = $5; }
|
||||
| bgp_proto DISABLE AFTER CEASE bgp_cease_mask ';' { BGP_CFG->disable_after_cease = $5; }
|
||||
| bgp_proto ENABLE ROUTE REFRESH bool ';' { BGP_CFG->enable_refresh = $5; }
|
||||
| bgp_proto ENABLE AS4 bool ';' { BGP_CFG->enable_as4 = $4; }
|
||||
| bgp_proto ENABLE EXTENDED MESSAGES bool ';' { BGP_CFG->enable_extended_messages = $5; }
|
||||
|
@ -2772,6 +2772,16 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, uint len)
|
||||
bgp_update_startup_delay(p);
|
||||
bgp_stop(p, 0, NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint subcode_bit = 1 << ((subcode <= 8) ? subcode : 0);
|
||||
if (p->cf->disable_after_cease & subcode_bit)
|
||||
{
|
||||
log(L_INFO "%s: Disabled after Cease notification", p->p.name);
|
||||
p->startup_delay = 0;
|
||||
p->p.disabled = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -25,13 +25,19 @@ CF_ADDTO(proto, pipe_proto '}' { this_channel = NULL; } )
|
||||
pipe_proto_start: proto_start PIPE
|
||||
{
|
||||
this_proto = proto_config_new(&proto_pipe, $1);
|
||||
}
|
||||
proto_name
|
||||
{
|
||||
this_channel = proto_cf_main_channel(this_proto);
|
||||
if (!this_channel) {
|
||||
this_channel = channel_config_new(NULL, NULL, 0, this_proto);
|
||||
this_channel->in_filter = FILTER_ACCEPT;
|
||||
this_channel->out_filter = FILTER_ACCEPT;
|
||||
}
|
||||
};
|
||||
|
||||
pipe_proto:
|
||||
pipe_proto_start proto_name '{'
|
||||
pipe_proto_start '{'
|
||||
| pipe_proto proto_item ';'
|
||||
| pipe_proto channel_item ';'
|
||||
| pipe_proto PEER TABLE rtable ';' { PIPE_CFG->peer = $4; }
|
||||
|
@ -249,6 +249,8 @@ pipe_show_stats(struct pipe_proto *p)
|
||||
s2->imp_withdraws_ignored, s2->imp_withdraws_accepted);
|
||||
}
|
||||
|
||||
static const char *pipe_feed_state[] = { [ES_DOWN] = "down", [ES_FEEDING] = "feed", [ES_READY] = "up" };
|
||||
|
||||
static void
|
||||
pipe_show_proto_info(struct proto *P)
|
||||
{
|
||||
@ -257,6 +259,8 @@ pipe_show_proto_info(struct proto *P)
|
||||
cli_msg(-1006, " Channel %s", "main");
|
||||
cli_msg(-1006, " Table: %s", p->pri->table->name);
|
||||
cli_msg(-1006, " Peer table: %s", p->sec->table->name);
|
||||
cli_msg(-1006, " Import state: %s", pipe_feed_state[p->sec->export_state]);
|
||||
cli_msg(-1006, " Export state: %s", pipe_feed_state[p->pri->export_state]);
|
||||
cli_msg(-1006, " Import filter: %s", filter_name(p->sec->out_filter));
|
||||
cli_msg(-1006, " Export filter: %s", filter_name(p->pri->out_filter));
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#define CONFIG_SELF_CONSCIOUS
|
||||
#define CONFIG_MULTIPLE_TABLES
|
||||
#define CONFIG_ALL_TABLES_AT_ONCE
|
||||
#define CONFIG_IP6_SADR_KERNEL
|
||||
|
||||
#define CONFIG_MC_PROPER_SRC
|
||||
#define CONFIG_UNIX_DONTROUTE
|
||||
|
@ -374,6 +374,7 @@ static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = {
|
||||
|
||||
static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MAX] = {
|
||||
[RTA_DST] = { 1, 1, sizeof(ip6_addr) },
|
||||
[RTA_SRC] = { 1, 1, sizeof(ip6_addr) },
|
||||
[RTA_IIF] = { 1, 1, sizeof(u32) },
|
||||
[RTA_OIF] = { 1, 1, sizeof(u32) },
|
||||
[RTA_GATEWAY] = { 1, 1, sizeof(ip6_addr) },
|
||||
@ -1221,8 +1222,18 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
nl_add_attr_ipa(&r->h, rsize, RTA_DST, net_prefix(net->n.addr));
|
||||
|
||||
/* Add source address for IPv6 SADR routes */
|
||||
if (net->n.addr->type == NET_IP6_SADR)
|
||||
{
|
||||
net_addr_ip6_sadr *a = (void *) &net->n.addr;
|
||||
nl_add_attr_ip6(&r->h, rsize, RTA_SRC, a->src_prefix);
|
||||
r->r.rtm_src_len = a->src_pxlen;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Strange behavior for RTM_DELROUTE:
|
||||
* 1) rtm_family is ignored in IPv6, works for IPv4
|
||||
@ -1447,12 +1458,12 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||
struct rtattr *a[BIRD_RTA_MAX];
|
||||
int new = h->nlmsg_type == RTM_NEWROUTE;
|
||||
|
||||
net_addr dst;
|
||||
net_addr dst, src = {};
|
||||
u32 oif = ~0;
|
||||
u32 table_id;
|
||||
u32 priority = 0;
|
||||
u32 def_scope = RT_SCOPE_UNIVERSE;
|
||||
int src;
|
||||
int krt_src;
|
||||
|
||||
if (!(i = nl_checkin(h, sizeof(*i))))
|
||||
return;
|
||||
@ -1477,6 +1488,11 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||
net_fill_ip6(&dst, rta_get_ip6(a[RTA_DST]), i->rtm_dst_len);
|
||||
else
|
||||
net_fill_ip6(&dst, IP6_NONE, 0);
|
||||
|
||||
if (a[RTA_SRC])
|
||||
net_fill_ip6(&src, rta_get_ip6(a[RTA_SRC]), i->rtm_src_len);
|
||||
else
|
||||
net_fill_ip6(&src, IP6_NONE, 0);
|
||||
break;
|
||||
|
||||
#ifdef HAVE_MPLS_KERNEL
|
||||
@ -1511,6 +1527,9 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||
if (!p)
|
||||
SKIP("unknown table %d\n", table);
|
||||
|
||||
if (a[RTA_SRC] && (p->p.net_type != NET_IP6_SADR))
|
||||
SKIP("src prefix for non-SADR channel\n");
|
||||
|
||||
if (a[RTA_IIF])
|
||||
SKIP("IIF set\n");
|
||||
|
||||
@ -1533,25 +1552,33 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||
SKIP("proto unspec\n");
|
||||
|
||||
case RTPROT_REDIRECT:
|
||||
src = KRT_SRC_REDIRECT;
|
||||
krt_src = KRT_SRC_REDIRECT;
|
||||
break;
|
||||
|
||||
case RTPROT_KERNEL:
|
||||
src = KRT_SRC_KERNEL;
|
||||
krt_src = KRT_SRC_KERNEL;
|
||||
return;
|
||||
|
||||
case RTPROT_BIRD:
|
||||
if (!s->scan)
|
||||
SKIP("echo\n");
|
||||
src = KRT_SRC_BIRD;
|
||||
krt_src = KRT_SRC_BIRD;
|
||||
break;
|
||||
|
||||
case RTPROT_BOOT:
|
||||
default:
|
||||
src = KRT_SRC_ALIEN;
|
||||
krt_src = KRT_SRC_ALIEN;
|
||||
}
|
||||
|
||||
net *net = net_get(p->p.main_channel->table, &dst);
|
||||
net_addr *n = &dst;
|
||||
if (p->p.net_type == NET_IP6_SADR)
|
||||
{
|
||||
n = alloca(sizeof(net_addr_ip6_sadr));
|
||||
net_fill_ip6_sadr(n, net6_prefix(&dst), net6_pxlen(&dst),
|
||||
net6_prefix(&src), net6_pxlen(&src));
|
||||
}
|
||||
|
||||
net *net = net_get(p->p.main_channel->table, n);
|
||||
|
||||
if (s->net && !nl_mergable_route(s, net, p, priority, i->rtm_type))
|
||||
nl_announce_route(s);
|
||||
@ -1755,7 +1782,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||
s->attrs = ra;
|
||||
s->proto = p;
|
||||
s->new = new;
|
||||
s->krt_src = src;
|
||||
s->krt_src = krt_src;
|
||||
s->krt_type = i->rtm_type;
|
||||
s->krt_proto = i->rtm_protocol;
|
||||
s->krt_metric = priority;
|
||||
|
@ -958,10 +958,6 @@ sk_setup(sock *s)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (s->priority >= 0)
|
||||
if (sk_set_priority(s, s->priority) < 0)
|
||||
return -1;
|
||||
|
||||
if (sk_is_ipv4(s))
|
||||
{
|
||||
if (s->flags & SKF_LADDR_RX)
|
||||
@ -1012,6 +1008,11 @@ sk_setup(sock *s)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Must be after sk_set_tos4() as setting ToS on Linux also mangles priority */
|
||||
if (s->priority >= 0)
|
||||
if (sk_set_priority(s, s->priority) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -16,16 +16,6 @@ CF_DEFINES
|
||||
#define THIS_KIF ((struct kif_config *) this_proto)
|
||||
#define KIF_IFACE ((struct kif_iface_config *) this_ipatt)
|
||||
|
||||
static void
|
||||
krt_set_merge_paths(struct channel_config *cc, uint merge, uint limit)
|
||||
{
|
||||
if ((limit <= 0) || (limit > 255))
|
||||
cf_error("Merge paths limit must be in range 1-255");
|
||||
|
||||
cc->ra_mode = merge ? RA_MERGED : RA_OPTIMAL;
|
||||
cc->merge_limit = limit;
|
||||
}
|
||||
|
||||
static void
|
||||
kif_set_preferred(ip_addr ip)
|
||||
{
|
||||
@ -78,10 +68,9 @@ kern_item:
|
||||
cf_error("Learning of kernel routes not supported on this platform");
|
||||
#endif
|
||||
}
|
||||
| DEVICE ROUTES bool { THIS_KRT->devroutes = $3; }
|
||||
| GRACEFUL RESTART bool { THIS_KRT->graceful_restart = $3; }
|
||||
| MERGE PATHS bool kern_mp_limit {
|
||||
krt_set_merge_paths(this_channel, $3, $4);
|
||||
THIS_KRT->merge_paths = $3 ? $4 : 0;
|
||||
#ifndef KRT_ALLOW_MERGE_PATHS
|
||||
if ($3)
|
||||
cf_error("Path merging not supported on this platform");
|
||||
|
@ -506,7 +506,13 @@ static void
|
||||
krt_learn_init(struct krt_proto *p)
|
||||
{
|
||||
if (KRT_CF->learn)
|
||||
rt_setup(p->p.pool, &p->krt_table, "Inherited", NULL);
|
||||
{
|
||||
struct rtable_config *cf = mb_allocz(p->p.pool, sizeof(struct rtable_config));
|
||||
cf->name = "Inherited";
|
||||
cf->addr_type = p->p.net_type;
|
||||
|
||||
rt_setup(p->p.pool, &p->krt_table, cf);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -578,7 +584,7 @@ krt_export_net(struct krt_proto *p, net *net, rte **rt_free, ea_list **tmpa)
|
||||
if (filter == FILTER_ACCEPT)
|
||||
goto accept;
|
||||
|
||||
if (f_run(filter, &rt, tmpa, krt_filter_lp, FF_FORCE_TMPATTR) > F_ACCEPT)
|
||||
if (f_run(filter, &rt, tmpa, krt_filter_lp, FF_FORCE_TMPATTR | FF_SILENT) > F_ACCEPT)
|
||||
goto reject;
|
||||
|
||||
|
||||
@ -1059,11 +1065,18 @@ krt_postconfig(struct proto_config *CF)
|
||||
cf_error("All kernel syncers must use the same table scan interval");
|
||||
#endif
|
||||
|
||||
struct rtable_config *tab = proto_cf_main_channel(CF)->table;
|
||||
struct channel_config *cc = proto_cf_main_channel(CF);
|
||||
struct rtable_config *tab = cc->table;
|
||||
if (tab->krt_attached)
|
||||
cf_error("Kernel syncer (%s) already attached to table %s", tab->krt_attached->name, tab->name);
|
||||
tab->krt_attached = CF;
|
||||
|
||||
if (cf->merge_paths)
|
||||
{
|
||||
cc->ra_mode = RA_MERGED;
|
||||
cc->merge_limit = cf->merge_paths;
|
||||
}
|
||||
|
||||
krt_sys_postconfig(cf);
|
||||
}
|
||||
|
||||
@ -1097,6 +1110,7 @@ krt_start(struct proto *P)
|
||||
{
|
||||
case NET_IP4: p->af = AF_INET; break;
|
||||
case NET_IP6: p->af = AF_INET6; break;
|
||||
case NET_IP6_SADR: p->af = AF_INET6; break;
|
||||
#ifdef AF_MPLS
|
||||
case NET_MPLS: p->af = AF_MPLS; break;
|
||||
#endif
|
||||
@ -1159,7 +1173,7 @@ krt_reconfigure(struct proto *p, struct proto_config *CF)
|
||||
return 0;
|
||||
|
||||
/* persist, graceful restart need not be the same */
|
||||
return o->scan_time == n->scan_time && o->learn == n->learn && o->devroutes == n->devroutes;
|
||||
return o->scan_time == n->scan_time && o->learn == n->learn;
|
||||
}
|
||||
|
||||
struct proto_config *
|
||||
@ -1206,16 +1220,24 @@ krt_get_attr(eattr *a, byte *buf, int buflen)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IP6_SADR_KERNEL
|
||||
#define MAYBE_IP6_SADR NB_IP6_SADR
|
||||
#else
|
||||
#define MAYBE_IP6_SADR 0
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MPLS_KERNEL
|
||||
#define MAYBE_MPLS NB_MPLS
|
||||
#else
|
||||
#define MAYBE_MPLS 0
|
||||
#endif
|
||||
|
||||
struct protocol proto_unix_kernel = {
|
||||
.name = "Kernel",
|
||||
.template = "kernel%d",
|
||||
.attr_class = EAP_KRT,
|
||||
.preference = DEF_PREF_INHERITED,
|
||||
#ifdef HAVE_MPLS_KERNEL
|
||||
.channel_mask = NB_IP | NB_MPLS,
|
||||
#else
|
||||
.channel_mask = NB_IP,
|
||||
#endif
|
||||
.channel_mask = NB_IP | MAYBE_IP6_SADR | MAYBE_MPLS,
|
||||
.proto_size = sizeof(struct krt_proto),
|
||||
.config_size = sizeof(struct krt_config),
|
||||
.preconfig = krt_preconfig,
|
||||
|
@ -49,8 +49,8 @@ struct krt_config {
|
||||
btime scan_time; /* How often we re-scan routes */
|
||||
int persist; /* Keep routes when we exit */
|
||||
int learn; /* Learn routes from other sources */
|
||||
int devroutes; /* XXX: remove */
|
||||
int graceful_restart; /* Regard graceful restart recovery */
|
||||
int merge_paths; /* Exported routes are merged for ECMP */
|
||||
};
|
||||
|
||||
struct krt_proto {
|
||||
|
Loading…
Reference in New Issue
Block a user