Bird-users
Threads by month
- ----- 2026 -----
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2000 -----
- December
- November
- October
- September
- August
- July
- June
February 2018
- 29 participants
- 35 discussions
This adds support for source-specific IPv6 routes to Bird core. This is
based on Dean Luga's original patch, with the review comments addressed.
Sadr support is added to network address parsing in confbase.Y and to
the kernel protocol on Linux.
A couple of issues remain with this patch:
- Had to change the default addr_type in rt_setup() to NET_SADR_IP6 to
get the kernel 'learn' mechanism to work.
- Not sure if the logic in net_route_sadr_ip6() is right.
- The config parser barfs on sadr route literals in the static protocol
with an "Integer expression expected" error message.
- There's no way to mix source-specific and non-source-specific routes
(i.e., sadr tables cannot be connected to non-sadr tables).
Signed-off-by: Toke Høiland-Jørgensen <toke(a)toke.dk>
---
conf/confbase.Y | 22 ++++++++++++++++---
lib/net.c | 34 ++++++++++++++++++++++++++++++
lib/net.h | 57 ++++++++++++++++++++++++++++++++++++++++++++++----
nest/config.Y | 5 +++--
nest/rt-fib.c | 2 ++
nest/rt-table.c | 49 ++++++++++++++++++++++++++++++++++++++-----
sysdep/linux/netlink.c | 31 +++++++++++++++++++++++++--
sysdep/unix/krt.c | 8 ++++---
8 files changed, 189 insertions(+), 19 deletions(-)
diff --git a/conf/confbase.Y b/conf/confbase.Y
index 7e0537c5..246d6c3b 100644
--- a/conf/confbase.Y
+++ b/conf/confbase.Y
@@ -82,7 +82,7 @@ CF_DECLS
%type <i> expr bool pxlen4
%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> net_ip4_ net_ip6_ net_sadr_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 <mls> label_stack_start label_stack
@@ -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,22 @@ net_ip6_: IP6 '/' NUM
n->prefix, n->pxlen, ip6_and(n->prefix, ip6_mkmask(n->pxlen)), n->pxlen);
};
+net_sadr_ip6_: 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);
+
+ net_fill_sadr_ip6(&($$), $1, $3, $5, $7);
+
+ net_addr_sadr_ip6 *n = (void *) &($$);
+ if (!net_validate_sadr_ip6(n))
+ cf_error("Invalid SADR IPv6 prefix %I6/%d from %I6/%d",
+ n->dst_prefix, n->dst_pxlen, n->src_prefix, n->src_pxlen);
+};
+
net_vpn4_: VPN_RD net_ip4_
{
$$ = cfg_alloc(sizeof(net_addr_vpn4));
@@ -240,7 +256,7 @@ net_mpls_: MPLS NUM
net_fill_mpls($$, $2);
}
-net_ip_: net_ip4_ | net_ip6_ ;
+net_ip_: net_ip4_ | net_ip6_ | net_sadr_ip6_;
net_vpn_: net_vpn4_ | net_vpn6_ ;
net_roa_: net_roa4_ | net_roa6_ ;
diff --git a/lib/net.c b/lib/net.c
index 9335b78f..a2dad51d 100644
--- a/lib/net.c
+++ b/lib/net.c
@@ -14,6 +14,7 @@ const char * const net_label[] = {
[NET_ROA6] = "roa6",
[NET_FLOW4] = "flow4",
[NET_FLOW6] = "flow6",
+ [NET_SADR_IP6] = "sadr6",
[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_SADR_IP6]= sizeof(net_addr_sadr_ip6),
[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_SADR_IP6]= 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_SADR_IP6]= 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_SADR_IP6:
+ return bsnprintf(buf, buflen, "%I6/%d from %I6/%d", n->sadr_ip6.dst_prefix, n->sadr_ip6.dst_pxlen, n->sadr_ip6.src_prefix, n->sadr_ip6.src_pxlen);
case NET_MPLS:
return bsnprintf(buf, buflen, "%u", n->mpls.label);
}
@@ -126,12 +132,25 @@ net_pxmask(const net_addr *a)
case NET_FLOW6:
return ipa_from_ip6(ip6_mkmask(net6_pxlen(a)));
+ case NET_SADR_IP6:
+ return ipa_from_ip6(ip6_mkmask(net6_pxlen(a)));
+
case NET_MPLS:
default:
return IPA_NONE;
}
}
+int
+net_compare_sadr_ip6(const net_addr_sadr_ip6 *a, const net_addr_sadr_ip6 *b)
+{
+ int dst_cmp = ip6_compare(a->dst_prefix, b->dst_prefix) ?: uint_cmp(a->dst_pxlen, b->dst_pxlen);
+ if (dst_cmp)
+ return dst_cmp;
+ else
+ return ip6_compare(a->src_prefix, b->src_prefix) ?: uint_cmp(a->src_pxlen, b->src_pxlen);
+}
+
int
net_compare(const net_addr *a, const net_addr *b)
{
@@ -158,6 +177,8 @@ net_compare(const net_addr *a, const net_addr *b)
return net_compare_flow6((const net_addr_flow6 *) a, (const net_addr_flow6 *) b);
case NET_MPLS:
return net_compare_mpls((const net_addr_mpls *) a, (const net_addr_mpls *) b);
+ case NET_SADR_IP6:
+ return net_compare_sadr_ip6((const net_addr_sadr_ip6 *) a, (const net_addr_sadr_ip6 *) b);
}
return 0;
}
@@ -177,6 +198,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_SADR_IP6: return NET_HASH(n, sadr_ip6);
case NET_MPLS: return NET_HASH(n, mpls);
default: bug("invalid type");
}
@@ -199,6 +221,7 @@ net_validate(const net_addr *n)
case NET_FLOW4: return NET_VALIDATE(n, flow4);
case NET_FLOW6: return NET_VALIDATE(n, flow6);
case NET_MPLS: return NET_VALIDATE(n, mpls);
+ case NET_SADR_IP6: return NET_VALIDATE(n, sadr_ip6);
default: return 0;
}
}
@@ -224,6 +247,9 @@ net_normalize(net_addr *N)
case NET_MPLS:
return;
+
+ case NET_SADR_IP6:
+ return net_normalize_sadr_ip6(&n->sadr_ip6);
}
}
@@ -248,6 +274,9 @@ net_classify(const net_addr *N)
case NET_MPLS:
return IADDR_HOST | SCOPE_UNIVERSE;
+
+ case NET_SADR_IP6:
+ return ip6_zero(n->sadr_ip6.dst_prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->sadr_ip6.dst_prefix);
}
return IADDR_INVALID;
@@ -274,6 +303,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_SADR_IP6:
+ 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;
diff --git a/lib/net.h b/lib/net.h
index 69f00641..5204e6b5 100644
--- a/lib/net.h
+++ b/lib/net.h
@@ -12,7 +12,6 @@
#include "lib/ip.h"
-
#define NET_IP4 1
#define NET_IP6 2
#define NET_VPN4 3
@@ -21,8 +20,9 @@
#define NET_ROA6 6
#define NET_FLOW4 7
#define NET_FLOW6 8
-#define NET_MPLS 9
-#define NET_MAX 10
+#define NET_SADR_IP6 9
+#define NET_MPLS 10
+#define NET_MAX 11
#define NB_IP4 (1 << NET_IP4)
#define NB_IP6 (1 << NET_IP6)
@@ -32,12 +32,13 @@
#define NB_ROA6 (1 << NET_ROA6)
#define NB_FLOW4 (1 << NET_FLOW4)
#define NB_FLOW6 (1 << NET_FLOW6)
+#define NB_SADR_IP6 (1 << NET_SADR_IP6)
#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_SADR_IP6 | NB_VPN | NB_MPLS)
#define NB_ANY 0xffffffff
@@ -121,6 +122,15 @@ typedef struct net_addr_mpls {
u32 label;
} net_addr_mpls;
+typedef struct net_addr_sadr_ip6 {
+ u8 type;
+ u8 dst_pxlen;
+ u16 length;
+ ip6_addr dst_prefix;
+ u32 src_pxlen; // if u8, NET_ADDR_SADR_IP6 would leave non-zero padding
+ ip6_addr src_prefix;
+} net_addr_sadr_ip6;
+
typedef union net_addr_union {
net_addr n;
net_addr_ip4 ip4;
@@ -132,6 +142,7 @@ typedef union net_addr_union {
net_addr_flow4 flow4;
net_addr_flow6 flow6;
net_addr_mpls mpls;
+ net_addr_sadr_ip6 sadr_ip6;
} net_addr_union;
@@ -170,6 +181,9 @@ extern const u16 net_max_text_length[];
#define NET_ADDR_MPLS(label) \
((net_addr_mpls) { NET_MPLS, 20, sizeof(net_addr_mpls), label })
+#define NET_ADDR_SADR_IP6(dst_prefix,dst_pxlen,src_prefix,src_pxlen) \
+ ((net_addr_sadr_ip6) { NET_SADR_IP6, dst_pxlen, sizeof(net_addr_sadr_ip6), dst_prefix, src_pxlen, src_prefix })
+
static inline void net_fill_ip4(net_addr *a, ip4_addr prefix, uint pxlen)
{ *(net_addr_ip4 *)a = NET_ADDR_IP4(prefix, pxlen); }
@@ -192,6 +206,9 @@ static inline void net_fill_roa6(net_addr *a, ip6_addr prefix, uint pxlen, uint
static inline void net_fill_mpls(net_addr *a, u32 label)
{ *(net_addr_mpls *)a = NET_ADDR_MPLS(label); }
+static inline void net_fill_sadr_ip6(net_addr *a, ip6_addr dst_prefix, uint dst_pxlen, ip6_addr src_prefix, uint src_pxlen)
+{ *(net_addr_sadr_ip6 *)a = NET_ADDR_SADR_IP6(dst_prefix, dst_pxlen, src_prefix, src_pxlen); }
+
static inline void net_fill_ipa(net_addr *a, ip_addr prefix, uint pxlen)
{
if (ipa_is_ip4(prefix))
@@ -240,6 +257,15 @@ static inline int net_is_roa(const net_addr *a)
static inline int net_is_flow(const net_addr *a)
{ return (a->type == NET_FLOW4) || (a->type == NET_FLOW6); }
+static inline int net_is_sadr(const net_addr *a)
+{ return (a->type == NET_SADR_IP6); }
+
+static inline int net_is_sadr_set(const net_addr *a)
+{
+ net_addr_sadr_ip6 *sa = (void *) a;
+ return (a->type == NET_SADR_IP6 && sa->src_pxlen > 0);
+}
+
static inline ip4_addr net4_prefix(const net_addr *a)
{ return ((net_addr_ip4 *) a)->prefix; }
@@ -261,6 +287,7 @@ static inline ip_addr net_prefix(const net_addr *a)
case NET_VPN6:
case NET_ROA6:
case NET_FLOW6:
+ case NET_SADR_IP6:
return ipa_from_ip6(net6_prefix(a));
case NET_MPLS:
@@ -331,6 +358,13 @@ static inline int net_equal_flow6(const net_addr_flow6 *a, const net_addr_flow6
static inline int net_equal_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
{ return !memcmp(a, b, sizeof(net_addr_mpls)); }
+typedef net_addr_ip6 net_addr_sadr_dst;
+static inline int net_equal_sadr_dst(const net_addr_ip6 *a, const net_addr_ip6 *b)
+{ return net_equal_ip6(a, b); }
+
+static inline int net_equal_sadr_ip6(const net_addr_sadr_ip6 *a, const net_addr_sadr_ip6 *b)
+{ return !memcmp(a, b, sizeof(net_addr_sadr_ip6)); }
+
static inline int net_equal_prefix_roa4(const net_addr_roa4 *a, const net_addr_roa4 *b)
{ return ip4_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); }
@@ -394,6 +428,8 @@ static inline int net_compare_flow6(const net_addr_flow6 *a, const net_addr_flow
static inline int net_compare_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
{ return uint_cmp(a->label, b->label); }
+int net_compare_sadr_ip6(const net_addr_sadr_ip6 *a, const net_addr_sadr_ip6 *b);
+
int net_compare(const net_addr *a, const net_addr *b);
@@ -427,6 +463,9 @@ static inline void net_copy_flow6(net_addr_flow6 *dst, const net_addr_flow6 *src
static inline void net_copy_mpls(net_addr_mpls *dst, const net_addr_mpls *src)
{ memcpy(dst, src, sizeof(net_addr_mpls)); }
+static inline void net_copy_sadr_ip6(net_addr_sadr_ip6 *dst, const net_addr_sadr_ip6 *src)
+{ memcpy(dst, src, sizeof(net_addr_sadr_ip6)); }
+
/* XXXX */
static inline u32 u64_hash(u64 a)
@@ -438,6 +477,9 @@ static inline u32 net_hash_ip4(const net_addr_ip4 *n)
static inline u32 net_hash_ip6(const net_addr_ip6 *n)
{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
+static inline u32 net_hash_sadr_ip6(const net_addr_sadr_ip6 *n)
+{ return net_hash_ip6((net_addr_ip6 *)n); }
+
static inline u32 net_hash_vpn4(const net_addr_vpn4 *n)
{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26) ^ u64_hash(n->rd); }
@@ -508,6 +550,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_sadr_ip6(const net_addr_sadr_ip6 *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 +568,10 @@ 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_sadr_ip6(net_addr_sadr_ip6 *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);
diff --git a/nest/config.Y b/nest/config.Y
index 044aba2b..e8cb26e4 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -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, 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_SADR_IP6; }
| 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, SADR_IP6)
/* Creation of routing tables */
diff --git a/nest/rt-fib.c b/nest/rt-fib.c
index c09f2759..1046350d 100644
--- a/nest/rt-fib.c
+++ b/nest/rt-fib.c
@@ -236,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_SADR_IP6: return FIB_FIND(f, a, sadr_ip6);
case NET_MPLS: return FIB_FIND(f, a, mpls);
default: bug("invalid type");
}
@@ -256,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_SADR_IP6: FIB_INSERT(f, a, e, sadr_ip6); return;
case NET_MPLS: FIB_INSERT(f, a, e, mpls); return;
default: bug("invalid type");
}
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 4640d6a9..c88dffef 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -85,6 +85,42 @@ net_route_ip6(rtable *t, net_addr_ip6 *n)
return r;
}
+static inline void *
+net_route_sadr_ip6(rtable *t, net_addr_sadr_ip6 *n)
+{
+ net *r;
+
+ net_addr_ip6 dst = NET_ADDR_IP6(n->dst_prefix, n->dst_pxlen);
+ dst.type = NET_SADR_IP6;
+
+ // search for matching dst
+ while (r = net_route_ip6(t, &dst))
+ {
+ /* FIXME: Is this right? */
+ net_addr_ip6 *n6 = (net_addr_ip6 *) r->n.addr;
+ dst.pxlen = n6->pxlen;
+
+ // found a matching dst, start search for entries that match both prefixes
+ net_addr_sadr_ip6 full_addr =
+ NET_ADDR_SADR_IP6(dst.prefix, dst.pxlen, n->src_prefix, n->src_pxlen);
+
+ while (r = net_find_valid(t, (net_addr *) &full_addr), (!r) && (full_addr.src_pxlen > 0))
+ {
+ full_addr.src_pxlen--;
+ ip6_clrbit(&full_addr.src_prefix, full_addr.src_pxlen);
+ }
+
+ if (r)
+ return r;
+
+ if (!dst.pxlen)
+ break;
+ dst.pxlen--;
+ }
+
+ return NULL;
+}
+
void *
net_route(rtable *tab, const net_addr *n)
{
@@ -105,6 +141,9 @@ net_route(rtable *tab, const net_addr *n)
case NET_ROA6:
return net_route_ip6(tab, (net_addr_ip6 *) n0);
+ case NET_SADR_IP6:
+ return net_route_sadr_ip6(tab, (net_addr_sadr_ip6 *) n0);
+
default:
return NULL;
}
@@ -614,9 +653,9 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang
old_meet = 1;
}
- /*
+ /*
* Second, handle the feed case. That means we do not care for
- * old_best. It is NULL for feed, and the new_best for refeed.
+ * old_best. It is NULL for feed, and the new_best for refeed.
* For refeed, there is a hack similar to one in rt_notify_basic()
* to ensure withdraws in case of changed filters
*/
@@ -1387,7 +1426,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
/* Independent call to rte_announce(), used from next hop
recalculation, outside of rte_update(). new must be non-NULL */
-static inline void
+static inline void
rte_announce_i(rtable *tab, unsigned type, net *net, rte *new, rte *old,
rte *new_best, rte *old_best)
{
@@ -1604,7 +1643,7 @@ rt_setup(pool *p, rtable *t, char *name, struct rtable_config *cf)
bzero(t, sizeof(*t));
t->name = name;
t->config = cf;
- t->addr_type = cf ? cf->addr_type : NET_IP4;
+ t->addr_type = cf ? cf->addr_type : NET_SADR_IP6; /* FIXME */
fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL);
init_list(&t->channels);
@@ -2360,7 +2399,7 @@ if_local_addr(ip_addr a, struct iface *i)
return 0;
}
-static u32
+static u32
rt_get_igp_metric(rte *rt)
{
eattr *ea = ea_find(rt->attrs->eattrs, EA_GEN_IGP_METRIC);
diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c
index 4cb51519..e59b4910 100644
--- a/sysdep/linux/netlink.c
+++ b/sysdep/linux/netlink.c
@@ -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,7 +1222,16 @@ 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 SADR routes
+ if (net->n.addr->type == NET_SADR_IP6)
+ {
+ net_addr_sadr_ip6 *sadr_addr = (void *) &net->n.addr;
+ r->r.rtm_src_len = sadr_addr->src_pxlen;
+ nl_add_attr_ipa(&r->h, rsize, RTA_SRC, sadr_addr->src_prefix);
+ }
+ }
/*
* Strange behavior for RTM_DELROUTE:
@@ -1447,7 +1457,8 @@ 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, sadr_src;
+ net_fill_ip6(&sadr_src, IP6_NONE, 0);
u32 oif = ~0;
u32 table_id;
u32 priority = 0;
@@ -1473,6 +1484,9 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want6, a, sizeof(a)))
return;
+ if (a[RTA_SRC])
+ net_fill_ip6(&sadr_src, rta_get_ip6(a[RTA_SRC]), i->rtm_src_len);
+
if (a[RTA_DST])
net_fill_ip6(&dst, rta_get_ip6(a[RTA_DST]), i->rtm_dst_len);
else
@@ -1551,7 +1565,20 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
src = KRT_SRC_ALIEN;
}
- net *net = net_get(p->p.main_channel->table, &dst);
+ net *net;
+ if (p->p.main_channel->table->addr_type == NET_SADR_IP6)
+ {
+ net_addr_sadr_ip6 sadr_addr =
+ NET_ADDR_SADR_IP6(net_prefix(&dst), net_pxlen(&dst),
+ net_prefix(&sadr_src), net_pxlen(&sadr_src));
+ net = net_get(p->p.main_channel->table, (net_addr *)&sadr_addr);
+ }
+ else
+ {
+ if (a[RTA_SRC])
+ SKIP("sadr prefix for non-sadr channel\n");
+ net = net_get(p->p.main_channel->table, &dst);
+ }
if (s->net && !nl_mergable_route(s, net, p, priority, i->rtm_type))
nl_announce_route(s);
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index e7bd79e3..7166bbec 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -1103,7 +1103,9 @@ krt_start(struct proto *P)
switch (p->p.net_type)
{
case NET_IP4: p->af = AF_INET; break;
- case NET_IP6: p->af = AF_INET6; break;
+ case NET_IP6:
+ case NET_SADR_IP6:
+ p->af = AF_INET6; break;
#ifdef AF_MPLS
case NET_MPLS: p->af = AF_MPLS; break;
#endif
@@ -1219,9 +1221,9 @@ struct protocol proto_unix_kernel = {
.attr_class = EAP_KRT,
.preference = DEF_PREF_INHERITED,
#ifdef HAVE_MPLS_KERNEL
- .channel_mask = NB_IP | NB_MPLS,
+ .channel_mask = NB_IP | NB_SADR_IP6 | NB_MPLS,
#else
- .channel_mask = NB_IP,
+ .channel_mask = NB_IP | NB_SADR_IP6,
#endif
.proto_size = sizeof(struct krt_proto),
.config_size = sizeof(struct krt_config),
--
2.16.1
2
16
While trying to setup bird on a new multi-host setup on Arch Linux.
We have two routers with two (diverse) directs paths using a /31 (so
please ignore the missing broadcast warnings)..
At this point we try to get both IPV4 and IPV6 to talk together using
both OSPF and BGP.
It seems that it is alive for 15 seconds from assert till death...
In our handful tries, it is always R1 (and not R2) that dies...
(systemd) Journal entries:
jan 28 14:59:14 R1 systemd[1]: Started BIRD routing daemon.
jan 28 14:59:14 R1 bird[6648]: Missing broadcast address for interface
bond0.3670 <<==== due to /31
jan 28 14:59:14 R1 bird[6648]: Missing broadcast address for interface
bond0.3671 <<==== due to /31
jan 28 14:59:14 R1 bird[6648]: Started
jan 28 14:59:14 R1 bird[6648]: Assertion 'f->addr_type ==
a->type' failed at nest/rt-fib.c:241
jan 28 14:59:14 R1 bird[6648]: Assertion 'f->addr_type ==
a->type' failed at nest/rt-fib.c:261
jan 28 14:59:14 R1 bird[6648]: Assertion 'f->addr_type ==
a->type' failed at nest/rt-fib.c:241
jan 28 14:59:14 R1 bird[6648]: Assertion 'f->addr_type ==
a->type' failed at nest/rt-fib.c:204
jan 28 14:59:29 R1 bird[6648]: Next hop address 185.38.27.64 is a local
address of iface bond0.3670
jan 28 14:59:29 R1 systemd[1]: bird.service: Main process exited,
code=dumped, status=11/SEGV
jan 28 14:59:29 R1 systemd[1]: bird.service: Failed with result 'core-dump'.
GDB from coredump:
(gdb) bt
#0 nexthop_size (nh=0x48) at ./nest/route.h:601
#1 rta_apply_hostentry (a=0x7ffd3846b5d0, he=0x556b706028c8, mls=0x0)
at nest/rt-table.c:1787
#2 0x0000556b6e835f6e in bgp_apply_next_hop (s=0x7ffd3846b6f0,
a=0x7ffd3846b5d0, gw=..., ll=...)
at proto/bgp/packets.c:767
#3 0x0000556b6e836713 in bgp_decode_nlri (s=s@entry=0x7ffd3846b6f0,
afi=afi@entry=65537,
nlri=0x556b70603aec
"\030\300\250\002\035\n\023:\bP\037\271&\033B\037\271&\033@", '\377'
<repeats 16 times>,
len=9, ea=ea@entry=0x556b705ff290, nh=<optimized out>, nh_len=4) at
proto/bgp/packets.c:2206
#4 0x0000556b6e838dde in bgp_rx_update (conn=conn@entry=0x556b705b6c90,
pkt=pkt@entry=0x556b70603ac0 '\377' <repeats 16 times>, len=53) at
proto/bgp/packets.c:2306
#5 0x0000556b6e83a51d in bgp_rx_packet (len=<optimized out>,
pkt=0x556b70603ac0 '\377' <repeats 16 times>,
conn=0x556b705b6c90) at proto/bgp/packets.c:2815
#6 bgp_rx (sk=0x556b70603970, size=<optimized out>) at
proto/bgp/packets.c:2860
#7 0x0000556b6e85c44a in call_rx_hook (s=0x556b70603970,
size=<optimized out>) at sysdep/unix/io.c:1770
#8 0x0000556b6e85eb57 in sk_read (s=s@entry=0x556b70603970, revents=1)
at sysdep/unix/io.c:1858
#9 0x0000556b6e85f5d5 in io_loop () at sysdep/unix/io.c:2318
#10 0x0000556b6e7f493e in main (argc=<optimized out>, argv=<optimized
out>) at sysdep/unix/main.c:892
I have the config and both the core file and a binary with debug
symbols, that I can send.
Svenne
2
5
05 Feb '18
This adds support for source-specific routing to the babel protocol. It
changes the protocol to always use a NET_SADR_IP6 channel for IPv6
addresses, and just treats non-source-specific routes as source-specific
routes with sadr prefix 0. This means that almost all changes in this
patch is to the packet parsing and serialising code.
Signed-off-by: Toke Høiland-Jørgensen <toke(a)toke.dk>
---
proto/babel/babel.c | 20 +++----
proto/babel/babel.h | 14 ++++-
proto/babel/packets.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 175 insertions(+), 20 deletions(-)
diff --git a/proto/babel/babel.c b/proto/babel/babel.c
index aa7e8b68..5f02c3a2 100644
--- a/proto/babel/babel.c
+++ b/proto/babel/babel.c
@@ -1950,13 +1950,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, "%-50N %-23lR %6u %5u %7u %7u",
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, "%-50N %-23lR %6u %5u %7u %7u",
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, "%-50N %-23s %6s %5s %7u %7u",
e->n.addr, "<none>", "-", "-", rts, srcs);
}
FIB_WALK_END;
@@ -1975,7 +1975,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, "%-50s %-23s %6s %5s %7s %7s",
"Prefix", "Router ID", "Metric", "Seqno", "Routes", "Sources");
babel_show_entries_(p, &p->ip4_rtable);
@@ -1994,7 +1994,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, "%-50N %-25I %-10s %5u %c %5u %7t",
e->n.addr, r->next_hop, r->neigh->ifa->ifname,
r->metric, c, r->seqno, MAX(time, 0));
}
@@ -2015,7 +2015,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, "%-50s %-25s %-9s %6s F %5s %7s",
"Prefix", "Nexthop", "Interface", "Metric", "Seqno", "Expires");
babel_show_routes_(p, &p->ip4_rtable);
@@ -2189,7 +2189,7 @@ babel_init(struct proto_config *CF)
struct babel_proto *p = (void *) P;
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->ip6_channel, proto_cf_find_channel(CF, NET_IP6_SADR));
P->if_notify = babel_if_notify;
P->rt_notify = babel_rt_notify;
@@ -2210,7 +2210,7 @@ babel_start(struct proto *P)
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, NET_IP6_SADR, sizeof(struct babel_entry),
OFFSETOF(struct babel_entry, n), 0, babel_init_entry);
init_list(&p->interfaces);
@@ -2262,7 +2262,7 @@ babel_reconfigure(struct proto *P, struct proto_config *CF)
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)))
+ !proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6_SADR)))
return 0;
p->p.cf = CF;
@@ -2280,7 +2280,7 @@ struct protocol proto_babel = {
.template = "babel%d",
.attr_class = EAP_BABEL,
.preference = DEF_PREF_BABEL,
- .channel_mask = NB_IP,
+ .channel_mask = (NB_IP4 | NB_IP6_SADR),
.proto_size = sizeof(struct babel_proto),
.config_size = sizeof(struct babel_config),
.init = babel_init,
diff --git a/proto/babel/babel.h b/proto/babel/babel.h
index 1128d261..0902241a 100644
--- a/proto/babel/babel.h
+++ b/proto/babel/babel.h
@@ -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 {
@@ -303,7 +306,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 +317,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 +328,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;
};
diff --git a/proto/babel/packets.c b/proto/babel/packets.c
index dd86222a..2d78d4cb 100644
--- a/proto/babel/packets.c
+++ b/proto/babel/packets.c
@@ -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
@@ -201,7 +208,7 @@ read_ip6_px(net_addr *n, const void *p, uint plen)
{
ip6_addr addr = IPA_NONE;
memcpy(&addr, p, BYTES(plen));
- net_fill_ip6(n, ip6_ntoh(addr), plen);
+ net_fill_ip6_sadr(n, ip6_ntoh(addr), plen, IPA_NONE6, 0);
}
static inline void
@@ -237,6 +244,8 @@ 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;
@@ -638,7 +648,7 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
memcpy(buf + tlv->omitted, tlv->addr, len);
ip6_addr prefix6 = get_ip6(buf);
- net_fill_ip6(&msg->net, prefix6, tlv->plen);
+ net_fill_ip6_sadr(&msg->net, prefix6, tlv->plen, IPA_NONE6, 0);
if (tlv->flags & BABEL_UF_DEF_PREFIX)
{
@@ -739,11 +749,13 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
}
else
{
+ u8 buf[16], omit;
+ int l;
+
tlv->ae = BABEL_AE_IP6;
tlv->plen = net6_pxlen(&msg->net);
/* Address compression - omit initial matching bytes */
- u8 buf[16], omit;
put_ip6(buf, net6_prefix(&msg->net));
omit = bytes_equal(buf, state->def_ip6_prefix,
MIN(tlv->plen, state->def_ip6_pxlen) / 8);
@@ -764,6 +776,12 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
put_ip6(state->def_ip6_prefix, net6_prefix(&msg->net));
state->def_ip6_pxlen = tlv->plen;
}
+
+ l = babel_write_source_prefix(hdr, &msg->net, max_len - len - len0);
+ if (l < 0)
+ return 0;
+
+ len += l;
}
put_time16(&tlv->interval, msg->interval);
@@ -851,9 +869,17 @@ babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m,
}
else
{
+ int l;
+
tlv->ae = BABEL_AE_IP6;
tlv->plen = net6_pxlen(&msg->net);
put_ip6_px(tlv->addr, &msg->net);
+
+ l = babel_write_source_prefix(hdr, &msg->net, max_len - len);
+ if (l < 0)
+ return 0;
+
+ len += l;
}
return len;
@@ -920,6 +946,7 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
struct babel_msg_seqno_request *msg = &m->seqno_request;
uint len = sizeof(struct babel_tlv_seqno_request) + NET_SIZE(&msg->net);
+ int l;
if (len > max_len)
return 0;
@@ -943,34 +970,150 @@ 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);
+ l = babel_write_source_prefix(hdr, &msg->net, max_len - len);
+ if (l < 0)
+ return 0;
+
+ return len + l;
+}
+
+/* Add a subtlv to the tlv pointed to by header, with the specified subtlv type
+ and len. The length of the surrounding TLV is expanded.
+
+ Caller must ensure the buffer has enough space. */
+static struct babel_tlv *
+babel_add_subtlv(struct babel_tlv *hdr,
+ u8 type,
+ u8 len)
+{
+ struct babel_tlv *subtlv = (struct babel_tlv *) ((byte *) hdr + TLV_LENGTH(hdr));
+ hdr->length += len;
+ TLV_HDR(subtlv, type, len);
+ return subtlv;
+}
+
+static int
+babel_write_source_prefix(struct babel_tlv *hdr,
+ net_addr *net,
+ uint max_len)
+{
+ struct babel_subtlv_source_prefix *tlv;
+ struct net_addr_ip6_sadr *adr = (void *) net;
+ uint len;
+
+ if (!net_is_sadr_set(net))
+ return 0;
+
+ len = sizeof(*tlv) + BYTES(adr->src_pxlen);
+
+ if (len > max_len)
+ return -1;
+
+ tlv = (void *) babel_add_subtlv(hdr, BABEL_SUBTLV_SOURCE_PREFIX, len);
+ net_addr_ip6 sadr = NET_ADDR_IP6(adr->src_prefix, adr->src_pxlen);
+ tlv->plen = adr->src_pxlen;
+ put_ip6_px(tlv->addr, (void *) &sadr);
+
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;
+ struct net_addr_ip6_sadr *adr;
+ struct net_addr_ip6_sadr sadr;
+
+ if (tlv->length < BYTES(tlv->plen) + 1 ||
+ tlv->plen > IP6_MAX_PREFIX_LENGTH)
+ return PARSE_ERROR;
+
+ /* plen MUST NOT be 0 */
+ if (tlv->plen == 0)
+ return PARSE_IGNORE;
+
+ switch(msg->type) {
+ case BABEL_TLV_UPDATE:
+ /* wildcard updates with source prefix MUST be silently ignored */
+ if (msg->update.wildcard)
+ return PARSE_IGNORE;
+
+ adr = (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;
+
+ adr = (void *) &msg->route_request.net;
+ break;
+
+ case BABEL_TLV_SEQNO_REQUEST:
+ adr = (void *) &msg->seqno_request.net;
+ break;
+
+ default:
+ return PARSE_ERROR;
+ }
+
+ if (!net_is_sadr((net_addr *) adr))
+ return PARSE_ERROR;
+
+ /* Duplicate source prefix subtlv; SHOULD ignore TLV */
+ if (adr->src_pxlen > 0)
+ return PARSE_IGNORE;
+
+ /* read_ip6_px() reads a prefix into a net_addr_ip6_sadr struct, which in this
+ case is the sadr */
+ read_ip6_px((void *) &sadr, tlv->addr, tlv->plen);
+ adr->src_prefix = sadr.dst_prefix;
+ adr->src_pxlen = sadr.dst_pxlen;
+
+ return PARSE_SUCCESS;
+}
+
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))
{
+ if (tlv->type == BABEL_TLV_PAD1)
+ continue;
+
+ pos = (byte *)tlv + sizeof(struct babel_tlv);
+ if ((pos > end) || (pos + tlv->length > end))
+ {
+ DBG("Babel: subtlv framing error.\n");
+ 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)
+ if (tlv->type >= 128)
{
DBG("Babel: Mandatory subtlv %d found; skipping TLV\n", tlv->type);
return PARSE_IGNORE;
--
2.16.1
1
0
03 Feb '18
This adds support for source-specific routing to the babel protocol. It
changes the protocol to always use a NET_SADR_IP6 channel for IPv6
addresses, and just treats non-source-specific routes as source-specific
routes with sadr prefix 0. This means that almost all changes in this
patch is to the packet parsing and serialising code.
Signed-off-by: Toke Høiland-Jørgensen <toke(a)toke.dk>
---
proto/babel/babel.c | 20 +++----
proto/babel/babel.h | 20 +++++--
proto/babel/packets.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 178 insertions(+), 23 deletions(-)
diff --git a/proto/babel/babel.c b/proto/babel/babel.c
index aa7e8b68..71e8d2fc 100644
--- a/proto/babel/babel.c
+++ b/proto/babel/babel.c
@@ -1950,13 +1950,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, "%-50N %-23lR %6u %5u %7u %7u",
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, "%-50N %-23lR %6u %5u %7u %7u",
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, "%-50N %-23s %6s %5s %7u %7u",
e->n.addr, "<none>", "-", "-", rts, srcs);
}
FIB_WALK_END;
@@ -1975,7 +1975,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, "%-50s %-23s %6s %5s %7s %7s",
"Prefix", "Router ID", "Metric", "Seqno", "Routes", "Sources");
babel_show_entries_(p, &p->ip4_rtable);
@@ -1994,7 +1994,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, "%-50N %-25I %-10s %5u %c %5u %7t",
e->n.addr, r->next_hop, r->neigh->ifa->ifname,
r->metric, c, r->seqno, MAX(time, 0));
}
@@ -2015,7 +2015,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, "%-50s %-25s %-9s %6s F %5s %7s",
"Prefix", "Nexthop", "Interface", "Metric", "Seqno", "Expires");
babel_show_routes_(p, &p->ip4_rtable);
@@ -2189,7 +2189,7 @@ babel_init(struct proto_config *CF)
struct babel_proto *p = (void *) P;
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->ip6_channel, proto_cf_find_channel(CF, NET_SADR_IP6));
P->if_notify = babel_if_notify;
P->rt_notify = babel_rt_notify;
@@ -2210,7 +2210,7 @@ babel_start(struct proto *P)
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, NET_SADR_IP6, sizeof(struct babel_entry),
OFFSETOF(struct babel_entry, n), 0, babel_init_entry);
init_list(&p->interfaces);
@@ -2262,7 +2262,7 @@ babel_reconfigure(struct proto *P, struct proto_config *CF)
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)))
+ !proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_SADR_IP6)))
return 0;
p->p.cf = CF;
@@ -2280,7 +2280,7 @@ struct protocol proto_babel = {
.template = "babel%d",
.attr_class = EAP_BABEL,
.preference = DEF_PREF_BABEL,
- .channel_mask = NB_IP,
+ .channel_mask = (NB_IP4 | NB_SADR_IP6),
.proto_size = sizeof(struct babel_proto),
.config_size = sizeof(struct babel_config),
.init = babel_init,
diff --git a/proto/babel/babel.h b/proto/babel/babel.h
index 1128d261..85e1750f 100644
--- a/proto/babel/babel.h
+++ b/proto/babel/babel.h
@@ -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 {
@@ -303,7 +306,10 @@ struct babel_msg_update {
u16 seqno;
u16 metric;
u64 router_id;
- net_addr net;
+ union {
+ net_addr net;
+ net_addr_sadr_ip6 net_sadr;
+ };
ip_addr next_hop;
ip_addr sender;
};
@@ -311,7 +317,10 @@ struct babel_msg_update {
struct babel_msg_route_request {
u8 type;
u8 full;
- net_addr net;
+ union {
+ net_addr net;
+ net_addr_sadr_ip6 net_sadr;
+ };
};
struct babel_msg_seqno_request {
@@ -319,7 +328,10 @@ struct babel_msg_seqno_request {
u8 hop_count;
u16 seqno;
u64 router_id;
- net_addr net;
+ union {
+ net_addr net;
+ net_addr_sadr_ip6 net_sadr;
+ };
ip_addr sender;
};
diff --git a/proto/babel/packets.c b/proto/babel/packets.c
index dd86222a..239a83ef 100644
--- a/proto/babel/packets.c
+++ b/proto/babel/packets.c
@@ -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
@@ -201,7 +208,7 @@ read_ip6_px(net_addr *n, const void *p, uint plen)
{
ip6_addr addr = IPA_NONE;
memcpy(&addr, p, BYTES(plen));
- net_fill_ip6(n, ip6_ntoh(addr), plen);
+ net_fill_sadr_ip6(n, ip6_ntoh(addr), plen, IPA_NONE6, 0);
}
static inline void
@@ -237,6 +244,8 @@ 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;
@@ -638,7 +648,7 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
memcpy(buf + tlv->omitted, tlv->addr, len);
ip6_addr prefix6 = get_ip6(buf);
- net_fill_ip6(&msg->net, prefix6, tlv->plen);
+ net_fill_sadr_ip6(&msg->net, prefix6, tlv->plen, IPA_NONE6, 0);
if (tlv->flags & BABEL_UF_DEF_PREFIX)
{
@@ -739,11 +749,13 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
}
else
{
+ u8 buf[16], omit;
+ int l;
+
tlv->ae = BABEL_AE_IP6;
tlv->plen = net6_pxlen(&msg->net);
/* Address compression - omit initial matching bytes */
- u8 buf[16], omit;
put_ip6(buf, net6_prefix(&msg->net));
omit = bytes_equal(buf, state->def_ip6_prefix,
MIN(tlv->plen, state->def_ip6_pxlen) / 8);
@@ -764,6 +776,12 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
put_ip6(state->def_ip6_prefix, net6_prefix(&msg->net));
state->def_ip6_pxlen = tlv->plen;
}
+
+ l = babel_write_source_prefix(hdr, &msg->net, max_len - len - len0);
+ if (l < 0)
+ return 0;
+
+ len += l;
}
put_time16(&tlv->interval, msg->interval);
@@ -851,9 +869,17 @@ babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m,
}
else
{
+ int l;
+
tlv->ae = BABEL_AE_IP6;
tlv->plen = net6_pxlen(&msg->net);
put_ip6_px(tlv->addr, &msg->net);
+
+ l = babel_write_source_prefix(hdr, &msg->net, max_len - len);
+ if (l < 0)
+ return 0;
+
+ len += l;
}
return len;
@@ -920,6 +946,7 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
struct babel_msg_seqno_request *msg = &m->seqno_request;
uint len = sizeof(struct babel_tlv_seqno_request) + NET_SIZE(&msg->net);
+ int l;
if (len > max_len)
return 0;
@@ -943,34 +970,150 @@ 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);
+ l = babel_write_source_prefix(hdr, &msg->net, max_len - len);
+ if (l < 0)
+ return 0;
+
+ return len + l;
+}
+
+/* Add a subtlv to the tlv pointed to by header, with the specified subtlv type
+ and len. The length of the surrounding TLV is expanded.
+
+ Caller must ensure the buffer has enough space. */
+static struct babel_tlv *
+babel_add_subtlv(struct babel_tlv *hdr,
+ u8 type,
+ u8 len)
+{
+ struct babel_tlv *subtlv = (struct babel_tlv *) ((byte *) hdr + TLV_LENGTH(hdr));
+ hdr->length += len;
+ TLV_HDR(subtlv, type, len);
+ return subtlv;
+}
+
+static int
+babel_write_source_prefix(struct babel_tlv *hdr,
+ net_addr *net,
+ uint max_len)
+{
+ struct babel_subtlv_source_prefix *tlv;
+ struct net_addr_sadr_ip6 *adr = (void *) net;
+ uint len;
+
+ if (!net_is_sadr_set(net))
+ return 0;
+
+ len = sizeof(*tlv) + BYTES(adr->src_pxlen);
+
+ if (len > max_len)
+ return -1;
+
+ tlv = (void *) babel_add_subtlv(hdr, BABEL_SUBTLV_SOURCE_PREFIX, len);
+ net_addr_ip6 sadr = NET_ADDR_IP6(adr->src_prefix, adr->src_pxlen);
+ tlv->plen = adr->src_pxlen;
+ put_ip6_px(tlv->addr, (void *) &sadr);
+
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;
+ struct net_addr_sadr_ip6 *adr;
+ struct net_addr_sadr_ip6 sadr;
+
+ if (tlv->length < BYTES(tlv->plen) + 1 ||
+ tlv->plen > IP6_MAX_PREFIX_LENGTH)
+ return PARSE_ERROR;
+
+ /* plen MUST NOT be 0 */
+ if (tlv->plen == 0)
+ return PARSE_IGNORE;
+
+ switch(msg->type) {
+ case BABEL_TLV_UPDATE:
+ /* wildcard updates with source prefix MUST be silently ignored */
+ if (msg->update.wildcard)
+ return PARSE_IGNORE;
+
+ adr = (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;
+
+ adr = (void *) &msg->route_request.net;
+ break;
+
+ case BABEL_TLV_SEQNO_REQUEST:
+ adr = (void *) &msg->seqno_request.net;
+ break;
+
+ default:
+ return PARSE_ERROR;
+ }
+
+ if (!net_is_sadr((net_addr *) adr))
+ return PARSE_ERROR;
+
+ /* Duplicate source prefix subtlv; SHOULD ignore TLV */
+ if (adr->src_pxlen > 0)
+ return PARSE_IGNORE;
+
+ /* read_ip6_px() reads a prefix into a net_addr_sadr_ip6 struct, which in this
+ case is the sadr */
+ read_ip6_px((void *) &sadr, tlv->addr, tlv->plen);
+ adr->src_prefix = sadr.dst_prefix;
+ adr->src_pxlen = sadr.dst_pxlen;
+
+ return PARSE_SUCCESS;
+}
+
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))
{
+ if (tlv->type == BABEL_TLV_PAD1)
+ continue;
+
+ pos = (byte *)tlv + sizeof(struct babel_tlv);
+ if ((pos > end) || (pos + tlv->length > end))
+ {
+ DBG("Babel: subtlv framing error.\n");
+ 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)
+ if (tlv->type >= 128)
{
DBG("Babel: Mandatory subtlv %d found; skipping TLV\n", tlv->type);
return PARSE_IGNORE;
--
2.16.1
1
0
Hello,
I am testing Bird 2.0.1 as a RR in order to replace very old Cisco Hardware RR.
Everything was fine until I tried VPNv6 RR. Bird seems to ignore all vpnv6 routes:
----------------------------------------------------------------------------------------------------------------
Channel vpn4-mpls
State: UP
Table: vpntab4
Preference: 100
Input filter: ACCEPT
Output filter: ACCEPT
Routes: 5237 imported, 17 exported
Route change stats: received rejected filtered ignored accepted
Import updates: 5362 0 0 0 5362
Import withdraws: 125 0 --- 0 125
Export updates: 5401 5362 0 --- 39
Export withdraws: 147 --- --- --- 22
BGP Next hop: A.A.A.A
IGP IPv4 table: master4
Channel vpn6-mpls
State: UP
Table: vpntab6
Preference: 100
Input filter: ACCEPT
Output filter: ACCEPT
Routes: 0 imported, 0 exported
Route change stats: received rejected filtered ignored accepted
Import updates: 0 0 0 0 0
Import withdraws: 4889 0 --- 4889 0
Export updates: 0 0 0 --- 0
Export withdraws: 0 --- --- --- 0
BGP Next hop: ::
IGP IPv6 table: master6
----------------------------------------------------------------------------------------------------------------
Unlike VPNv4 output, BGP Next hop is empty here...not sure if it's the cause of my issue.
When I check on one of the client, it was sending ipv6 routes normally.
VPNv6 are configred through ipv4 bgp sessions (which works fine with our actual RR), here is the bird.conf configuration:
----------------------------------------------------------------------------------------------------------------
log "/home/bird/log/bird.log" all;
debug commands 0;
debug protocols {states,events};
router id A.A.A.A;
ipv4 table master4;
ipv6 table master6;
vpn4 table vpntab4;
vpn6 table vpntab6;
protocol kernel kernel4 {
#persist; # Don't remove routes on BIRD shutdown
debug off;
scan time 20; # Scan kernel routing table every 20 seconds
ipv4{
export all; # Default is export none
};
}
protocol kernel kernel6 {
scan time 20;
debug off;
ipv6 {
export all;
};
}
protocol device {
scan time 10; # Scan interfaces every 10 seconds
debug off;
}
protocol static static4 {
ipv4;
route B.B.0.0/16 via C.C.C.C;
}
template bgp rr_client {
local A.A.A.A as 65000;
passive on;
multihop;
rr client;
rr cluster id 500;
ipv4 {
# connects to master4 table by default
import all;
#export where source ~ [ RTS_STATIC, RTS_BGP ];
};
vpn4 mpls {
# connects to vpntab4 table by default
import all;
export all;
};
vpn6 mpls {
# connects to vpntab6 table by default
import all;
export all;
};
}
protocol bgp rrcli1 from rr_client {
neighbor D.D.D.D as 65000;
}
protocol bgp rrcli2 from rr_client {
neighbor E.E.E.E as 65000;
}
protocol bgp rrcli3 from rr_client {
neighbor F.F.F.F as 65000;
}
----------------------------------------------------------------------------------------------------------------
Did I missed something ?
Thanks
Gilles Friang
2
2