Netlink: MPLS routes in kernel
Anyway, Bird is now capable to insert both MPLS routes and MPLS encap routes into kernel. It was (among others) needed to define platform-specific AF_MPLS to 28 as this constant has been assigned in the linux kernel. No support for BSD now, it may be added in the future.
This commit is contained in:
parent
f2010f9c65
commit
d14f8c3c45
10 changed files with 274 additions and 30 deletions
|
@ -270,7 +270,7 @@ net_or_ipa:
|
||||||
|
|
||||||
label_stack_start: NUM
|
label_stack_start: NUM
|
||||||
{
|
{
|
||||||
$$ = cfg_allocz(sizeof(u32) * (NEXTHOP_MAX_LABEL_STACK+1));
|
$$ = cfg_allocz(sizeof(u32) * (MPLS_MAX_LABEL_STACK+1));
|
||||||
$$[0] = 1;
|
$$[0] = 1;
|
||||||
$$[1] = $1;
|
$$[1] = $1;
|
||||||
};
|
};
|
||||||
|
@ -278,7 +278,7 @@ label_stack_start: NUM
|
||||||
label_stack:
|
label_stack:
|
||||||
label_stack_start
|
label_stack_start
|
||||||
| label_stack '/' NUM {
|
| label_stack '/' NUM {
|
||||||
if ($1[0] >= NEXTHOP_MAX_LABEL_STACK)
|
if ($1[0] >= MPLS_MAX_LABEL_STACK)
|
||||||
cf_error("Too many labels in stack.");
|
cf_error("Too many labels in stack.");
|
||||||
$1[++$1[0]] = $3;
|
$1[++$1[0]] = $3;
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
|
|
22
lib/ip.h
22
lib/ip.h
|
@ -325,6 +325,28 @@ static inline ip6_addr ip6_hton(ip6_addr a)
|
||||||
static inline ip6_addr ip6_ntoh(ip6_addr a)
|
static inline ip6_addr ip6_ntoh(ip6_addr a)
|
||||||
{ return _MI6(ntohl(_I0(a)), ntohl(_I1(a)), ntohl(_I2(a)), ntohl(_I3(a))); }
|
{ return _MI6(ntohl(_I0(a)), ntohl(_I1(a)), ntohl(_I2(a)), ntohl(_I3(a))); }
|
||||||
|
|
||||||
|
#define MPLS_MAX_LABEL_STACK 8
|
||||||
|
static inline int
|
||||||
|
mpls_get(const char *buf, int buflen, u32 *stack)
|
||||||
|
{
|
||||||
|
for (int i=0; (i<MPLS_MAX_LABEL_STACK) && (i*4+3 < buflen); i++)
|
||||||
|
{
|
||||||
|
u32 s = get_u32(buf + i*4);
|
||||||
|
stack[i] = s >> 12;
|
||||||
|
if (s & 0x100)
|
||||||
|
return i+1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
mpls_put(char *buf, int len, u32 *stack)
|
||||||
|
{
|
||||||
|
for (int i=0; i<len; i++)
|
||||||
|
put_u32(buf + i*4, stack[i] << 12 | (i+1 == len ? 0x100 : 0));
|
||||||
|
|
||||||
|
return len*4;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unaligned data access (in network order)
|
* Unaligned data access (in network order)
|
||||||
|
|
|
@ -225,7 +225,8 @@ net_classify(const net_addr *N)
|
||||||
case NET_FLOW6:
|
case NET_FLOW6:
|
||||||
return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6.prefix);
|
return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6.prefix);
|
||||||
|
|
||||||
/* classify probably not needed for NET_MPLS */
|
case NET_MPLS:
|
||||||
|
return IADDR_HOST | SCOPE_UNIVERSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return IADDR_INVALID;
|
return IADDR_INVALID;
|
||||||
|
|
|
@ -259,6 +259,14 @@ static inline ip_addr net_prefix(const net_addr *a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline u32 net_mpls(const net_addr *a)
|
||||||
|
{
|
||||||
|
if (a->type == NET_MPLS)
|
||||||
|
return ((net_addr_mpls *) a)->label;
|
||||||
|
|
||||||
|
bug("Can't call net_mpls on non-mpls net_addr");
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint net4_pxlen(const net_addr *a)
|
static inline uint net4_pxlen(const net_addr *a)
|
||||||
{ return a->pxlen; }
|
{ return a->pxlen; }
|
||||||
|
|
||||||
|
|
|
@ -512,8 +512,7 @@ uint ea_hash(ea_list *e); /* Calculate 16-bit hash value */
|
||||||
ea_list *ea_append(ea_list *to, ea_list *what);
|
ea_list *ea_append(ea_list *to, ea_list *what);
|
||||||
void ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max);
|
void ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max);
|
||||||
|
|
||||||
#define NEXTHOP_MAX_LABEL_STACK 8
|
#define NEXTHOP_MAX_SIZE (sizeof(struct nexthop) + sizeof(u32)*MPLS_MAX_LABEL_STACK)
|
||||||
#define NEXTHOP_MAX_SIZE (sizeof(struct nexthop) + sizeof(u32)*NEXTHOP_MAX_LABEL_STACK)
|
|
||||||
|
|
||||||
static inline size_t nexthop_size(const struct nexthop *nh)
|
static inline size_t nexthop_size(const struct nexthop *nh)
|
||||||
{ return sizeof(struct nexthop) + sizeof(u32)*nh->labels; }
|
{ return sizeof(struct nexthop) + sizeof(u32)*nh->labels; }
|
||||||
|
@ -528,7 +527,7 @@ int nexthop_is_sorted(struct nexthop *x);
|
||||||
|
|
||||||
void rta_init(void);
|
void rta_init(void);
|
||||||
static inline size_t rta_size(const rta *a) { return sizeof(rta) + sizeof(u32)*a->nh.labels; }
|
static inline size_t rta_size(const rta *a) { return sizeof(rta) + sizeof(u32)*a->nh.labels; }
|
||||||
#define RTA_MAX_SIZE (sizeof(rta) + sizeof(u32)*NEXTHOP_MAX_LABEL_STACK)
|
#define RTA_MAX_SIZE (sizeof(rta) + sizeof(u32)*MPLS_MAX_LABEL_STACK)
|
||||||
rta *rta_lookup(rta *); /* Get rta equivalent to this one, uc++ */
|
rta *rta_lookup(rta *); /* Get rta equivalent to this one, uc++ */
|
||||||
static inline int rta_is_cached(rta *r) { return r->aflags & RTAF_CACHED; }
|
static inline int rta_is_cached(rta *r) { return r->aflags & RTAF_CACHED; }
|
||||||
static inline rta *rta_clone(rta *r) { r->uc++; return r; }
|
static inline rta *rta_clone(rta *r) { r->uc++; return r; }
|
||||||
|
|
|
@ -1279,12 +1279,12 @@ rta_init(void)
|
||||||
rta_slab_[0] = sl_new(rta_pool, sizeof(rta));
|
rta_slab_[0] = sl_new(rta_pool, sizeof(rta));
|
||||||
rta_slab_[1] = sl_new(rta_pool, sizeof(rta) + sizeof(u32));
|
rta_slab_[1] = sl_new(rta_pool, sizeof(rta) + sizeof(u32));
|
||||||
rta_slab_[2] = sl_new(rta_pool, sizeof(rta) + sizeof(u32)*2);
|
rta_slab_[2] = sl_new(rta_pool, sizeof(rta) + sizeof(u32)*2);
|
||||||
rta_slab_[3] = sl_new(rta_pool, sizeof(rta) + sizeof(u32)*NEXTHOP_MAX_LABEL_STACK);
|
rta_slab_[3] = sl_new(rta_pool, sizeof(rta) + sizeof(u32)*MPLS_MAX_LABEL_STACK);
|
||||||
|
|
||||||
nexthop_slab_[0] = sl_new(rta_pool, sizeof(struct nexthop));
|
nexthop_slab_[0] = sl_new(rta_pool, sizeof(struct nexthop));
|
||||||
nexthop_slab_[1] = sl_new(rta_pool, sizeof(struct nexthop) + sizeof(u32));
|
nexthop_slab_[1] = sl_new(rta_pool, sizeof(struct nexthop) + sizeof(u32));
|
||||||
nexthop_slab_[2] = sl_new(rta_pool, sizeof(struct nexthop) + sizeof(u32)*2);
|
nexthop_slab_[2] = sl_new(rta_pool, sizeof(struct nexthop) + sizeof(u32)*2);
|
||||||
nexthop_slab_[3] = sl_new(rta_pool, sizeof(struct nexthop) + sizeof(u32)*NEXTHOP_MAX_LABEL_STACK);
|
nexthop_slab_[3] = sl_new(rta_pool, sizeof(struct nexthop) + sizeof(u32)*MPLS_MAX_LABEL_STACK);
|
||||||
|
|
||||||
rta_alloc_hash();
|
rta_alloc_hash();
|
||||||
rte_src_init();
|
rte_src_init();
|
||||||
|
|
|
@ -2487,7 +2487,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
|
||||||
tm, from, primary ? (sync_error ? " !" : " *") : "", info);
|
tm, from, primary ? (sync_error ? " !" : " *") : "", info);
|
||||||
for (nh = &(a->nh); nh; nh = nh->next)
|
for (nh = &(a->nh); nh; nh = nh->next)
|
||||||
{
|
{
|
||||||
char ls[NEXTHOP_MAX_LABEL_STACK*8 + 5]; char *lsp = ls;
|
char ls[MPLS_MAX_LABEL_STACK*8 + 5]; char *lsp = ls;
|
||||||
if (nh->labels)
|
if (nh->labels)
|
||||||
{
|
{
|
||||||
lsp += bsprintf(lsp, " mpls %d", nh->label[0]);
|
lsp += bsprintf(lsp, " mpls %d", nh->label[0]);
|
||||||
|
|
|
@ -21,6 +21,10 @@
|
||||||
#define CONFIG_INCLUDE_SYSPRIV_H "sysdep/linux/syspriv.h"
|
#define CONFIG_INCLUDE_SYSPRIV_H "sysdep/linux/syspriv.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef AF_MPLS
|
||||||
|
#define AF_MPLS 28
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Link: sysdep/linux
|
Link: sysdep/linux
|
||||||
Link: sysdep/unix
|
Link: sysdep/unix
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include <asm/types.h>
|
#include <asm/types.h>
|
||||||
#include <linux/if.h>
|
#include <linux/if.h>
|
||||||
|
#include <linux/lwtunnel.h>
|
||||||
#include <linux/netlink.h>
|
#include <linux/netlink.h>
|
||||||
#include <linux/rtnetlink.h>
|
#include <linux/rtnetlink.h>
|
||||||
|
|
||||||
|
@ -51,6 +52,21 @@
|
||||||
#define RTA_TABLE 15
|
#define RTA_TABLE 15
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef RTA_VIA
|
||||||
|
#define RTA_VIA 18
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RTA_NEWDST
|
||||||
|
#define RTA_NEWDST 19
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RTA_ENCAP_TYPE
|
||||||
|
#define RTA_ENCAP_TYPE 21
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RTA_ENCAP
|
||||||
|
#define RTA_ENCAP 22
|
||||||
|
#endif
|
||||||
|
|
||||||
#define krt_ecmp6(p) ((p)->af == AF_INET6)
|
#define krt_ecmp6(p) ((p)->af == AF_INET6)
|
||||||
|
|
||||||
|
@ -313,10 +329,16 @@ static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MAX] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define BIRD_RTA_MAX (RTA_TABLE+1)
|
#define BIRD_RTA_MAX (RTA_ENCAP+1)
|
||||||
|
|
||||||
static struct nl_want_attrs nexthop_attr_want4[BIRD_RTA_MAX] = {
|
static struct nl_want_attrs nexthop_attr_want4[BIRD_RTA_MAX] = {
|
||||||
[RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) },
|
[RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) },
|
||||||
|
[RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
|
||||||
|
[RTA_ENCAP] = { 1, 0, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct nl_want_attrs encap_mpls_want[BIRD_RTA_MAX] = {
|
||||||
|
[RTA_DST] = { 1, 0, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = {
|
static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = {
|
||||||
|
@ -329,6 +351,8 @@ static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = {
|
||||||
[RTA_MULTIPATH] = { 1, 0, 0 },
|
[RTA_MULTIPATH] = { 1, 0, 0 },
|
||||||
[RTA_FLOW] = { 1, 1, sizeof(u32) },
|
[RTA_FLOW] = { 1, 1, sizeof(u32) },
|
||||||
[RTA_TABLE] = { 1, 1, sizeof(u32) },
|
[RTA_TABLE] = { 1, 1, sizeof(u32) },
|
||||||
|
[RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
|
||||||
|
[RTA_ENCAP] = { 1, 0, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MAX] = {
|
static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MAX] = {
|
||||||
|
@ -341,6 +365,20 @@ static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MAX] = {
|
||||||
[RTA_METRICS] = { 1, 0, 0 },
|
[RTA_METRICS] = { 1, 0, 0 },
|
||||||
[RTA_FLOW] = { 1, 1, sizeof(u32) },
|
[RTA_FLOW] = { 1, 1, sizeof(u32) },
|
||||||
[RTA_TABLE] = { 1, 1, sizeof(u32) },
|
[RTA_TABLE] = { 1, 1, sizeof(u32) },
|
||||||
|
[RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
|
||||||
|
[RTA_ENCAP] = { 1, 0, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct nl_want_attrs rtm_attr_want_mpls[BIRD_RTA_MAX] = {
|
||||||
|
[RTA_DST] = { 1, 1, sizeof(u32) },
|
||||||
|
[RTA_IIF] = { 1, 1, sizeof(u32) },
|
||||||
|
[RTA_OIF] = { 1, 1, sizeof(u32) },
|
||||||
|
[RTA_PRIORITY] = { 1, 1, sizeof(u32) },
|
||||||
|
[RTA_METRICS] = { 1, 0, 0 },
|
||||||
|
[RTA_FLOW] = { 1, 1, sizeof(u32) },
|
||||||
|
[RTA_TABLE] = { 1, 1, sizeof(u32) },
|
||||||
|
[RTA_VIA] = { 1, 0, 0 },
|
||||||
|
[RTA_NEWDST] = { 1, 0, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -373,6 +411,9 @@ nl_parse_attrs(struct rtattr *a, struct nl_want_attrs *want, struct rtattr **k,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline u16 rta_get_u16(struct rtattr *a)
|
||||||
|
{ return *(u16 *) RTA_DATA(a); }
|
||||||
|
|
||||||
static inline u32 rta_get_u32(struct rtattr *a)
|
static inline u32 rta_get_u32(struct rtattr *a)
|
||||||
{ return *(u32 *) RTA_DATA(a); }
|
{ return *(u32 *) RTA_DATA(a); }
|
||||||
|
|
||||||
|
@ -390,6 +431,25 @@ static inline ip_addr rta_get_ipa(struct rtattr *a)
|
||||||
return ipa_from_ip6(rta_get_ip6(a));
|
return ipa_from_ip6(rta_get_ip6(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline ip_addr rta_get_via(struct rtattr *a)
|
||||||
|
{
|
||||||
|
struct rtvia *v = RTA_DATA(a);
|
||||||
|
switch(v->rtvia_family) {
|
||||||
|
case AF_INET: return ipa_from_ip4(ip4_ntoh(*(ip4_addr *) v->rtvia_addr));
|
||||||
|
case AF_INET6: return ipa_from_ip6(ip6_ntoh(*(ip6_addr *) v->rtvia_addr));
|
||||||
|
}
|
||||||
|
return IPA_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 rta_mpls_stack[MPLS_MAX_LABEL_STACK];
|
||||||
|
static inline int rta_get_mpls(struct rtattr *a, u32 *stack)
|
||||||
|
{
|
||||||
|
if (RTA_PAYLOAD(a) % 4)
|
||||||
|
log(L_WARN "KRT: Strange length of received MPLS stack: %u", RTA_PAYLOAD(a));
|
||||||
|
|
||||||
|
return mpls_get(RTA_DATA(a), RTA_PAYLOAD(a) & ~0x3, stack);
|
||||||
|
}
|
||||||
|
|
||||||
struct rtattr *
|
struct rtattr *
|
||||||
nl_add_attr(struct nlmsghdr *h, uint bufsize, uint code, const void *data, uint dlen)
|
nl_add_attr(struct nlmsghdr *h, uint bufsize, uint code, const void *data, uint dlen)
|
||||||
{
|
{
|
||||||
|
@ -410,6 +470,24 @@ nl_add_attr(struct nlmsghdr *h, uint bufsize, uint code, const void *data, uint
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline struct rtattr *
|
||||||
|
nl_open_attr(struct nlmsghdr *h, uint bufsize, uint code)
|
||||||
|
{
|
||||||
|
return nl_add_attr(h, bufsize, code, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
nl_close_attr(struct nlmsghdr *h, struct rtattr *a)
|
||||||
|
{
|
||||||
|
a->rta_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)a;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
nl_add_attr_u16(struct nlmsghdr *h, uint bufsize, int code, u16 data)
|
||||||
|
{
|
||||||
|
nl_add_attr(h, bufsize, code, &data, 2);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
nl_add_attr_u32(struct nlmsghdr *h, uint bufsize, int code, u32 data)
|
nl_add_attr_u32(struct nlmsghdr *h, uint bufsize, int code, u32 data)
|
||||||
{
|
{
|
||||||
|
@ -439,16 +517,47 @@ nl_add_attr_ipa(struct nlmsghdr *h, uint bufsize, int code, ip_addr ipa)
|
||||||
nl_add_attr_ip6(h, bufsize, code, ipa_to_ip6(ipa));
|
nl_add_attr_ip6(h, bufsize, code, ipa_to_ip6(ipa));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct rtattr *
|
static inline void
|
||||||
nl_open_attr(struct nlmsghdr *h, uint bufsize, uint code)
|
nl_add_attr_mpls(struct nlmsghdr *h, uint bufsize, int code, int len, u32 *stack)
|
||||||
{
|
{
|
||||||
return nl_add_attr(h, bufsize, code, NULL, 0);
|
char buf[len*4];
|
||||||
|
mpls_put(buf, len, stack);
|
||||||
|
nl_add_attr(h, bufsize, code, buf, len*4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
nl_close_attr(struct nlmsghdr *h, struct rtattr *a)
|
nl_add_attr_mpls_encap(struct nlmsghdr *h, uint bufsize, int len, u32 *stack)
|
||||||
{
|
{
|
||||||
a->rta_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)a;
|
nl_add_attr_u16(h, bufsize, RTA_ENCAP_TYPE, LWTUNNEL_ENCAP_MPLS);
|
||||||
|
|
||||||
|
struct rtattr *nest = nl_open_attr(h, bufsize, RTA_ENCAP);
|
||||||
|
nl_add_attr_mpls(h, bufsize, RTA_DST, len, stack);
|
||||||
|
nl_close_attr(h, nest);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
nl_add_attr_via(struct nlmsghdr *h, uint bufsize, ip_addr ipa)
|
||||||
|
{
|
||||||
|
struct rtattr *nest = nl_open_attr(h, bufsize, RTA_VIA);
|
||||||
|
struct rtvia *via = RTA_DATA(nest);
|
||||||
|
|
||||||
|
h->nlmsg_len += sizeof(*via);
|
||||||
|
|
||||||
|
if (ipa_is_ip4(ipa)) {
|
||||||
|
ip4_addr ip4 = ipa_to_ip4(ipa);
|
||||||
|
ip4 = ip4_hton(ip4);
|
||||||
|
via->rtvia_family = AF_INET;
|
||||||
|
memcpy(via->rtvia_addr, &ip4, sizeof(ip4));
|
||||||
|
h->nlmsg_len += sizeof(ip4);
|
||||||
|
} else {
|
||||||
|
ip6_addr ip6 = ipa_to_ip6(ipa);
|
||||||
|
ip6 = ip6_hton(ip6);
|
||||||
|
via->rtvia_family = AF_INET6;
|
||||||
|
memcpy(via->rtvia_addr, &ip6, sizeof(ip6));
|
||||||
|
h->nlmsg_len += sizeof(ip6);
|
||||||
|
}
|
||||||
|
|
||||||
|
nl_close_attr(h, nest);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct rtnexthop *
|
static inline struct rtnexthop *
|
||||||
|
@ -471,8 +580,24 @@ nl_close_nexthop(struct nlmsghdr *h, struct rtnexthop *nh)
|
||||||
nh->rtnh_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)nh;
|
nh->rtnh_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)nh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
nl_add_nexthop(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af)
|
||||||
|
{
|
||||||
|
if (nh->labels > 0)
|
||||||
|
if (af == AF_MPLS)
|
||||||
|
nl_add_attr_mpls(h, bufsize, RTA_NEWDST, nh->labels, nh->label);
|
||||||
|
else
|
||||||
|
nl_add_attr_mpls_encap(h, bufsize, nh->labels, nh->label);
|
||||||
|
|
||||||
|
if (ipa_nonzero(nh->gw))
|
||||||
|
if (af == AF_MPLS)
|
||||||
|
nl_add_attr_via(h, bufsize, nh->gw);
|
||||||
|
else
|
||||||
|
nl_add_attr_ipa(h, bufsize, RTA_GATEWAY, nh->gw);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh)
|
nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af)
|
||||||
{
|
{
|
||||||
struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH);
|
struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH);
|
||||||
|
|
||||||
|
@ -484,7 +609,7 @@ nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh)
|
||||||
rtnh->rtnh_hops = nh->weight;
|
rtnh->rtnh_hops = nh->weight;
|
||||||
rtnh->rtnh_ifindex = nh->iface->index;
|
rtnh->rtnh_ifindex = nh->iface->index;
|
||||||
|
|
||||||
nl_add_attr_ipa(h, bufsize, RTA_GATEWAY, nh->gw);
|
nl_add_nexthop(h, bufsize, nh, af);
|
||||||
|
|
||||||
nl_close_nexthop(h, rtnh);
|
nl_close_nexthop(h, rtnh);
|
||||||
}
|
}
|
||||||
|
@ -518,7 +643,7 @@ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
|
||||||
if (nh_buf_used == nh_buf_size)
|
if (nh_buf_used == nh_buf_size)
|
||||||
{
|
{
|
||||||
nh_buf_size = nh_buf_size ? (nh_buf_size * 2) : 4;
|
nh_buf_size = nh_buf_size ? (nh_buf_size * 2) : 4;
|
||||||
nh_buffer = xrealloc(nh_buffer, nh_buf_size * sizeof(struct nexthop));
|
nh_buffer = xrealloc(nh_buffer, nh_buf_size * NEXTHOP_MAX_SIZE);
|
||||||
}
|
}
|
||||||
*last = rv = nh_buffer + nh_buf_used++;
|
*last = rv = nh_buffer + nh_buf_used++;
|
||||||
rv->next = NULL;
|
rv->next = NULL;
|
||||||
|
@ -543,7 +668,21 @@ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
rv->gw = IPA_NONE;
|
||||||
|
if (a[RTA_ENCAP_TYPE])
|
||||||
|
{
|
||||||
|
if (rta_get_u16(a[RTA_ENCAP_TYPE]) != LWTUNNEL_ENCAP_MPLS) {
|
||||||
|
log(L_WARN "KRT: Unknown encapsulation method %d in multipath", rta_get_u16(a[RTA_ENCAP_TYPE]));
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rtattr *enca[BIRD_RTA_MAX];
|
||||||
|
nl_attr_len = RTA_PAYLOAD(a[RTA_ENCAP]);
|
||||||
|
nl_parse_attrs(RTA_DATA(a[RTA_ENCAP]), encap_mpls_want, enca, sizeof(enca));
|
||||||
|
rv->labels = rta_get_mpls(enca[RTA_DST], rv->label);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
len -= NLMSG_ALIGN(nh->rtnh_len);
|
len -= NLMSG_ALIGN(nh->rtnh_len);
|
||||||
nh = RTNH_NEXT(nh);
|
nh = RTNH_NEXT(nh);
|
||||||
|
@ -1008,6 +1147,12 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d
|
||||||
r->r.rtm_dst_len = net_pxlen(net->n.addr);
|
r->r.rtm_dst_len = net_pxlen(net->n.addr);
|
||||||
r->r.rtm_protocol = RTPROT_BIRD;
|
r->r.rtm_protocol = RTPROT_BIRD;
|
||||||
r->r.rtm_scope = RT_SCOPE_UNIVERSE;
|
r->r.rtm_scope = RT_SCOPE_UNIVERSE;
|
||||||
|
if (p->af == AF_MPLS)
|
||||||
|
{
|
||||||
|
u32 label = net_mpls(net->n.addr);
|
||||||
|
nl_add_attr_mpls(&r->h, rsize, RTA_DST, 1, &label);
|
||||||
|
}
|
||||||
|
else
|
||||||
nl_add_attr_ipa(&r->h, rsize, RTA_DST, net_prefix(net->n.addr));
|
nl_add_attr_ipa(&r->h, rsize, RTA_DST, net_prefix(net->n.addr));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1071,13 +1216,11 @@ dest:
|
||||||
case RTD_UNICAST:
|
case RTD_UNICAST:
|
||||||
r->r.rtm_type = RTN_UNICAST;
|
r->r.rtm_type = RTN_UNICAST;
|
||||||
if (nh->next && !krt_ecmp6(p))
|
if (nh->next && !krt_ecmp6(p))
|
||||||
nl_add_multipath(&r->h, rsize, nh);
|
nl_add_multipath(&r->h, rsize, nh, p->af);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nl_add_attr_u32(&r->h, rsize, RTA_OIF, nh->iface->index);
|
nl_add_attr_u32(&r->h, rsize, RTA_OIF, nh->iface->index);
|
||||||
|
nl_add_nexthop(&r->h, rsize, nh, p->af);
|
||||||
if (ipa_nonzero(nh->gw))
|
|
||||||
nl_add_attr_ipa(&r->h, rsize, RTA_GATEWAY, nh->gw);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RTD_BLACKHOLE:
|
case RTD_BLACKHOLE:
|
||||||
|
@ -1276,6 +1419,19 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||||
net_fill_ip6(&dst, IP6_NONE, 0);
|
net_fill_ip6(&dst, IP6_NONE, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case AF_MPLS:
|
||||||
|
if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want_mpls, a, sizeof(a)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (a[RTA_DST])
|
||||||
|
if (rta_get_mpls(a[RTA_DST], rta_mpls_stack) == 1)
|
||||||
|
net_fill_mpls(&dst, rta_mpls_stack[0]);
|
||||||
|
else
|
||||||
|
log(L_WARN "KRT: Got multi-label MPLS RTA_DST");
|
||||||
|
else
|
||||||
|
return; /* No support for MPLS routes without RTA_DST */
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1338,7 +1494,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||||
if (s->net && !nl_mergable_route(s, net, p, priority, i->rtm_type))
|
if (s->net && !nl_mergable_route(s, net, p, priority, i->rtm_type))
|
||||||
nl_announce_route(s);
|
nl_announce_route(s);
|
||||||
|
|
||||||
rta *ra = lp_allocz(s->pool, sizeof(rta)); // TODO: fix alloc
|
rta *ra = lp_allocz(s->pool, RTA_MAX_SIZE);
|
||||||
ra->src = p->p.main_source;
|
ra->src = p->p.main_source;
|
||||||
ra->source = RTS_INHERIT;
|
ra->source = RTS_INHERIT;
|
||||||
ra->scope = SCOPE_UNIVERSE;
|
ra->scope = SCOPE_UNIVERSE;
|
||||||
|
@ -1367,8 +1523,11 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a[RTA_GATEWAY])
|
if ((i->rtm_family != AF_MPLS) && a[RTA_GATEWAY] || (i->rtm_family == AF_MPLS) && a[RTA_VIA])
|
||||||
{
|
{
|
||||||
|
if (i->rtm_family == AF_MPLS)
|
||||||
|
ra->nh.gw = rta_get_via(a[RTA_VIA]);
|
||||||
|
else
|
||||||
ra->nh.gw = rta_get_ipa(a[RTA_GATEWAY]);
|
ra->nh.gw = rta_get_ipa(a[RTA_GATEWAY]);
|
||||||
|
|
||||||
/* Silently skip strange 6to4 routes */
|
/* Silently skip strange 6to4 routes */
|
||||||
|
@ -1377,7 +1536,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
neighbor *nbr;
|
neighbor *nbr;
|
||||||
nbr = neigh_find2(&p->p, &ra->nh.gw, ra->nh.iface,
|
nbr = neigh_find2(&p->p, &(ra->nh.gw), ra->nh.iface,
|
||||||
(i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
|
(i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
|
||||||
if (!nbr || (nbr->scope == SCOPE_HOST))
|
if (!nbr || (nbr->scope == SCOPE_HOST))
|
||||||
{
|
{
|
||||||
|
@ -1403,6 +1562,44 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int labels = 0;
|
||||||
|
if ((i->rtm_family == AF_MPLS) && a[RTA_NEWDST] && !ra->nh.next)
|
||||||
|
labels = rta_get_mpls(a[RTA_NEWDST], ra->nh.label);
|
||||||
|
|
||||||
|
if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE] && !ra->nh.next)
|
||||||
|
{
|
||||||
|
switch (rta_get_u16(a[RTA_ENCAP_TYPE]))
|
||||||
|
{
|
||||||
|
case LWTUNNEL_ENCAP_MPLS:
|
||||||
|
{
|
||||||
|
struct rtattr *enca[BIRD_RTA_MAX];
|
||||||
|
nl_attr_len = RTA_PAYLOAD(a[RTA_ENCAP]);
|
||||||
|
nl_parse_attrs(RTA_DATA(a[RTA_ENCAP]), encap_mpls_want, enca, sizeof(enca));
|
||||||
|
labels = rta_get_mpls(enca[RTA_DST], ra->nh.label);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
SKIP("unknown encapsulation method %d\n", rta_get_u16(a[RTA_ENCAP_TYPE]));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (labels < 0)
|
||||||
|
{
|
||||||
|
log(L_WARN "KRT: Too long MPLS stack received, ignoring.");
|
||||||
|
ra->nh.labels = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ra->nh.labels = labels;
|
||||||
|
|
||||||
|
rte *e = rte_get_temp(ra);
|
||||||
|
e->net = net;
|
||||||
|
e->u.krt.src = src;
|
||||||
|
e->u.krt.proto = i->rtm_protocol;
|
||||||
|
e->u.krt.seen = 0;
|
||||||
|
e->u.krt.best = 0;
|
||||||
|
e->u.krt.metric = 0;
|
||||||
|
|
||||||
if (i->rtm_scope != def_scope)
|
if (i->rtm_scope != def_scope)
|
||||||
{
|
{
|
||||||
ea_list *ea = lp_alloc(s->pool, sizeof(ea_list) + sizeof(eattr));
|
ea_list *ea = lp_alloc(s->pool, sizeof(ea_list) + sizeof(eattr));
|
||||||
|
@ -1416,6 +1613,9 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||||
ea->attrs[0].u.data = i->rtm_scope;
|
ea->attrs[0].u.data = i->rtm_scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (a[RTA_PRIORITY])
|
||||||
|
e->u.krt.metric = rta_get_u32(a[RTA_PRIORITY]);
|
||||||
|
|
||||||
if (a[RTA_PREFSRC])
|
if (a[RTA_PREFSRC])
|
||||||
{
|
{
|
||||||
ip_addr ps = rta_get_ipa(a[RTA_PREFSRC]);
|
ip_addr ps = rta_get_ipa(a[RTA_PREFSRC]);
|
||||||
|
@ -1527,6 +1727,15 @@ krt_do_scan(struct krt_proto *p UNUSED) /* CONFIG_ALL_TABLES_AT_ONCE => p is NUL
|
||||||
else
|
else
|
||||||
log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", h->nlmsg_type);
|
log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", h->nlmsg_type);
|
||||||
nl_parse_end(&s);
|
nl_parse_end(&s);
|
||||||
|
|
||||||
|
nl_parse_begin(&s, 1, 1);
|
||||||
|
nl_request_dump(AF_MPLS, RTM_GETROUTE);
|
||||||
|
while (h = nl_get_scan())
|
||||||
|
if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)
|
||||||
|
nl_parse_route(&s, h);
|
||||||
|
else
|
||||||
|
log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", h->nlmsg_type);
|
||||||
|
nl_parse_end(&s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1153,7 +1153,8 @@ krt_start(struct proto *P)
|
||||||
{
|
{
|
||||||
case NET_IP4: p->af = AF_INET; break;
|
case NET_IP4: p->af = AF_INET; break;
|
||||||
case NET_IP6: p->af = AF_INET6; break;
|
case NET_IP6: p->af = AF_INET6; break;
|
||||||
default: ASSERT(0);
|
case NET_MPLS: p->af = AF_MPLS; break;
|
||||||
|
default: log(L_ERR "KRT: Tried to start with strange net type: %d", p->p.net_type); return PS_START; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
add_tail(&krt_proto_list, &p->krt_node);
|
add_tail(&krt_proto_list, &p->krt_node);
|
||||||
|
@ -1264,7 +1265,7 @@ struct protocol proto_unix_kernel = {
|
||||||
.template = "kernel%d",
|
.template = "kernel%d",
|
||||||
.attr_class = EAP_KRT,
|
.attr_class = EAP_KRT,
|
||||||
.preference = DEF_PREF_INHERITED,
|
.preference = DEF_PREF_INHERITED,
|
||||||
.channel_mask = NB_IP,
|
.channel_mask = NB_IP | NB_MPLS,
|
||||||
.proto_size = sizeof(struct krt_proto),
|
.proto_size = sizeof(struct krt_proto),
|
||||||
.config_size = sizeof(struct krt_config),
|
.config_size = sizeof(struct krt_config),
|
||||||
.preconfig = krt_preconfig,
|
.preconfig = krt_preconfig,
|
||||||
|
|
Loading…
Reference in a new issue