version 1.1, 2017/08/22 12:33:54
|
version 1.1.1.2, 2021/03/17 19:50:23
|
Line 59
|
Line 59
|
/* |
/* |
* Structure nl_parse_state keeps state of received route processing. Ideally, |
* Structure nl_parse_state keeps state of received route processing. Ideally, |
* we could just independently parse received Netlink messages and immediately |
* we could just independently parse received Netlink messages and immediately |
* propagate received routes to the rest of BIRD, but Linux kernel represents | * propagate received routes to the rest of BIRD, but older Linux kernel (before |
* and announces IPv6 ECMP routes not as one route with multiple next hops (like | * version 4.11) represents and announces IPv6 ECMP routes not as one route with |
* RTA_MULTIPATH in IPv4 ECMP), but as a set of routes with the same prefix. | * multiple next hops (like RTA_MULTIPATH in IPv4 ECMP), but as a sequence of |
| * routes with the same prefix. More recent kernels work as with IPv4. |
* |
* |
* Therefore, BIRD keeps currently processed route in nl_parse_state structure |
* Therefore, BIRD keeps currently processed route in nl_parse_state structure |
* and postpones its propagation until we expect it to be final; i.e., when |
* and postpones its propagation until we expect it to be final; i.e., when |
* non-matching route is received or when the scan ends. When another matching |
* non-matching route is received or when the scan ends. When another matching |
* route is received, it is merged with the already processed route to form an |
* route is received, it is merged with the already processed route to form an |
* ECMP route. Note that merging is done only for IPv6 (merge == 1), but the |
* ECMP route. Note that merging is done only for IPv6 (merge == 1), but the |
* postponing is done in both cases (for simplicity). All IPv4 routes are just | * postponing is done in both cases (for simplicity). All IPv4 routes or IPv6 |
* considered non-matching. | * routes with RTA_MULTIPATH set are just considered non-matching. |
* |
* |
* This is ignored for asynchronous notifications (every notification is handled |
* This is ignored for asynchronous notifications (every notification is handled |
* as a separate route). It is not an issue for our routes, as we ignore such |
* as a separate route). It is not an issue for our routes, as we ignore such |
* notifications anyways. But importing alien IPv6 ECMP routes does not work |
* notifications anyways. But importing alien IPv6 ECMP routes does not work |
* properly. | * properly with older kernels. |
| * |
| * Whatever the kernel version is, IPv6 ECMP routes are sent as multiple routes |
| * for the same prefix. |
*/ |
*/ |
|
|
struct nl_parse_state |
struct nl_parse_state |
Line 296 struct nl_want_attrs {
|
Line 300 struct nl_want_attrs {
|
static struct nl_want_attrs ifla_attr_want[BIRD_IFLA_MAX] = { |
static struct nl_want_attrs ifla_attr_want[BIRD_IFLA_MAX] = { |
[IFLA_IFNAME] = { 1, 0, 0 }, |
[IFLA_IFNAME] = { 1, 0, 0 }, |
[IFLA_MTU] = { 1, 1, sizeof(u32) }, |
[IFLA_MTU] = { 1, 1, sizeof(u32) }, |
|
[IFLA_MASTER] = { 1, 1, sizeof(u32) }, |
[IFLA_WIRELESS] = { 1, 0, 0 }, |
[IFLA_WIRELESS] = { 1, 0, 0 }, |
}; |
}; |
|
|
Line 320 static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MA
|
Line 325 static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MA
|
|
|
#define BIRD_RTA_MAX (RTA_TABLE+1) |
#define BIRD_RTA_MAX (RTA_TABLE+1) |
|
|
|
#ifndef IPV6 |
static struct nl_want_attrs mpnh_attr_want4[BIRD_RTA_MAX] = { |
static struct nl_want_attrs mpnh_attr_want4[BIRD_RTA_MAX] = { |
[RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) }, |
[RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) }, |
}; |
}; |
|
#else |
|
static struct nl_want_attrs mpnh_attr_want6[BIRD_RTA_MAX] = { |
|
[RTA_GATEWAY] = { 1, 1, sizeof(ip6_addr) }, |
|
}; |
|
#endif |
|
|
#ifndef IPV6 |
#ifndef IPV6 |
static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = { |
static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = { |
Line 345 static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MA
|
Line 356 static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MA
|
[RTA_PRIORITY] = { 1, 1, sizeof(u32) }, |
[RTA_PRIORITY] = { 1, 1, sizeof(u32) }, |
[RTA_PREFSRC] = { 1, 1, sizeof(ip6_addr) }, |
[RTA_PREFSRC] = { 1, 1, sizeof(ip6_addr) }, |
[RTA_METRICS] = { 1, 0, 0 }, |
[RTA_METRICS] = { 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) }, |
}; |
}; |
Line 477 nl_add_multipath(struct nlmsghdr *h, unsigned bufsize,
|
Line 489 nl_add_multipath(struct nlmsghdr *h, unsigned bufsize,
|
} |
} |
|
|
static struct mpnh * |
static struct mpnh * |
nl_parse_multipath(struct krt_proto *p, struct rtattr *ra) | nl_parse_multipath(struct krt_proto *p, struct rtattr *ra, int af) |
{ |
{ |
/* Temporary buffer for multicast nexthops */ |
/* Temporary buffer for multicast nexthops */ |
static struct mpnh *nh_buffer; |
static struct mpnh *nh_buffer; |
Line 515 nl_parse_multipath(struct krt_proto *p, struct rtattr
|
Line 527 nl_parse_multipath(struct krt_proto *p, struct rtattr
|
|
|
/* Nonexistent RTNH_PAYLOAD ?? */ |
/* Nonexistent RTNH_PAYLOAD ?? */ |
nl_attr_len = nh->rtnh_len - RTNH_LENGTH(0); |
nl_attr_len = nh->rtnh_len - RTNH_LENGTH(0); |
nl_parse_attrs(RTNH_DATA(nh), mpnh_attr_want4, a, sizeof(a)); | switch (af) |
| { |
| #ifndef IPV6 |
| case AF_INET: |
| if (!nl_parse_attrs(RTNH_DATA(nh), mpnh_attr_want4, a, sizeof(a))) |
| return NULL; |
| break; |
| #else |
| case AF_INET6: |
| if (!nl_parse_attrs(RTNH_DATA(nh), mpnh_attr_want6, a, sizeof(a))) |
| return NULL; |
| break; |
| #endif |
| default: |
| return NULL; |
| } |
| |
if (a[RTA_GATEWAY]) |
if (a[RTA_GATEWAY]) |
{ |
{ |
memcpy(&rv->gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ip_addr)); | memcpy(&rv->gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(rv->gw)); |
ipa_ntoh(rv->gw); |
ipa_ntoh(rv->gw); |
|
|
neighbor *ng = neigh_find2(&p->p, &rv->gw, rv->iface, |
neighbor *ng = neigh_find2(&p->p, &rv->gw, rv->iface, |
Line 591 nl_parse_link(struct nlmsghdr *h, int scan)
|
Line 619 nl_parse_link(struct nlmsghdr *h, int scan)
|
struct iface f = {}; |
struct iface f = {}; |
struct iface *ifi; |
struct iface *ifi; |
char *name; |
char *name; |
u32 mtu; | u32 mtu, master = 0; |
uint fl; |
uint fl; |
|
|
if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFLA_RTA(i), ifla_attr_want, a, sizeof(a))) |
if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFLA_RTA(i), ifla_attr_want, a, sizeof(a))) |
Line 614 nl_parse_link(struct nlmsghdr *h, int scan)
|
Line 642 nl_parse_link(struct nlmsghdr *h, int scan)
|
name = RTA_DATA(a[IFLA_IFNAME]); |
name = RTA_DATA(a[IFLA_IFNAME]); |
mtu = rta_get_u32(a[IFLA_MTU]); |
mtu = rta_get_u32(a[IFLA_MTU]); |
|
|
|
if (a[IFLA_MASTER]) |
|
master = rta_get_u32(a[IFLA_MASTER]); |
|
|
ifi = if_find_by_index(i->ifi_index); |
ifi = if_find_by_index(i->ifi_index); |
if (!new) |
if (!new) |
{ |
{ |
Line 633 nl_parse_link(struct nlmsghdr *h, int scan)
|
Line 664 nl_parse_link(struct nlmsghdr *h, int scan)
|
f.index = i->ifi_index; |
f.index = i->ifi_index; |
f.mtu = mtu; |
f.mtu = mtu; |
|
|
|
f.master_index = master; |
|
f.master = if_find_by_index(master); |
|
|
fl = i->ifi_flags; |
fl = i->ifi_flags; |
if (fl & IFF_UP) |
if (fl & IFF_UP) |
f.flags |= IF_ADMIN_UP; |
f.flags |= IF_ADMIN_UP; |
Line 808 kif_do_scan(struct kif_proto *p UNUSED)
|
Line 842 kif_do_scan(struct kif_proto *p UNUSED)
|
else |
else |
log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type); |
log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type); |
|
|
|
/* Re-resolve master interface for slaves */ |
|
struct iface *i; |
|
WALK_LIST(i, iface_list) |
|
if (i->master_index) |
|
{ |
|
struct iface f = { |
|
.flags = i->flags, |
|
.mtu = i->mtu, |
|
.index = i->index, |
|
.master_index = i->master_index, |
|
.master = if_find_by_index(i->master_index) |
|
}; |
|
|
|
if (f.master != i->master) |
|
{ |
|
memcpy(f.name, i->name, sizeof(f.name)); |
|
if_update(&f); |
|
} |
|
} |
|
|
nl_request_dump(BIRD_AF, RTM_GETADDR); |
nl_request_dump(BIRD_AF, RTM_GETADDR); |
while (h = nl_get_scan()) |
while (h = nl_get_scan()) |
if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) |
if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) |
Line 885 nl_send_route(struct krt_proto *p, rte *e, struct ea_l
|
Line 939 nl_send_route(struct krt_proto *p, rte *e, struct ea_l
|
struct { |
struct { |
struct nlmsghdr h; |
struct nlmsghdr h; |
struct rtmsg r; |
struct rtmsg r; |
char buf[128 + KRT_METRICS_MAX*8 + nh_bufsize(a->nexthops)]; | char buf[0]; |
} r; | } *r; |
|
|
|
uint rsize = sizeof(*r) + 128 + KRT_METRICS_MAX*8 + nh_bufsize(a->nexthops); |
|
r = alloca(rsize); |
|
|
DBG("nl_send_route(%I/%d,op=%x)\n", net->n.prefix, net->n.pxlen, op); |
DBG("nl_send_route(%I/%d,op=%x)\n", net->n.prefix, net->n.pxlen, op); |
|
|
bzero(&r.h, sizeof(r.h)); | bzero(&r->h, sizeof(r->h)); |
bzero(&r.r, sizeof(r.r)); | bzero(&r->r, sizeof(r->r)); |
r.h.nlmsg_type = op ? RTM_NEWROUTE : RTM_DELROUTE; | r->h.nlmsg_type = op ? RTM_NEWROUTE : RTM_DELROUTE; |
r.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); | r->h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); |
r.h.nlmsg_flags = op | NLM_F_REQUEST | NLM_F_ACK; | r->h.nlmsg_flags = op | NLM_F_REQUEST | NLM_F_ACK; |
|
|
r.r.rtm_family = BIRD_AF; | r->r.rtm_family = BIRD_AF; |
r.r.rtm_dst_len = net->n.pxlen; | r->r.rtm_dst_len = net->n.pxlen; |
r.r.rtm_protocol = RTPROT_BIRD; | r->r.rtm_protocol = RTPROT_BIRD; |
r.r.rtm_scope = RT_SCOPE_NOWHERE; | r->r.rtm_scope = RT_SCOPE_NOWHERE; |
nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix); | nl_add_attr_ipa(&r->h, rsize, RTA_DST, net->n.prefix); |
|
|
/* |
/* |
* Strange behavior for RTM_DELROUTE: |
* Strange behavior for RTM_DELROUTE: |
Line 910 nl_send_route(struct krt_proto *p, rte *e, struct ea_l
|
Line 967 nl_send_route(struct krt_proto *p, rte *e, struct ea_l
|
*/ |
*/ |
|
|
if (krt_table_id(p) < 256) |
if (krt_table_id(p) < 256) |
r.r.rtm_table = krt_table_id(p); | r->r.rtm_table = krt_table_id(p); |
else |
else |
nl_add_attr_u32(&r.h, sizeof(r), RTA_TABLE, krt_table_id(p)); | nl_add_attr_u32(&r->h, rsize, RTA_TABLE, krt_table_id(p)); |
|
|
if (a->source == RTS_DUMMY) |
if (a->source == RTS_DUMMY) |
priority = e->u.krt.metric; |
priority = e->u.krt.metric; |
Line 922 nl_send_route(struct krt_proto *p, rte *e, struct ea_l
|
Line 979 nl_send_route(struct krt_proto *p, rte *e, struct ea_l
|
priority = ea->u.data; |
priority = ea->u.data; |
|
|
if (priority) |
if (priority) |
nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, priority); | nl_add_attr_u32(&r->h, rsize, RTA_PRIORITY, priority); |
|
|
/* For route delete, we do not specify remaining route attributes */ |
/* For route delete, we do not specify remaining route attributes */ |
if (op == NL_OP_DELETE) |
if (op == NL_OP_DELETE) |
Line 930 nl_send_route(struct krt_proto *p, rte *e, struct ea_l
|
Line 987 nl_send_route(struct krt_proto *p, rte *e, struct ea_l
|
|
|
/* Default scope is LINK for device routes, UNIVERSE otherwise */ |
/* Default scope is LINK for device routes, UNIVERSE otherwise */ |
if (ea = ea_find(eattrs, EA_KRT_SCOPE)) |
if (ea = ea_find(eattrs, EA_KRT_SCOPE)) |
r.r.rtm_scope = ea->u.data; | r->r.rtm_scope = ea->u.data; |
else |
else |
r.r.rtm_scope = (dest == RTD_DEVICE) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; | r->r.rtm_scope = (dest == RTD_DEVICE) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; |
|
|
if (ea = ea_find(eattrs, EA_KRT_PREFSRC)) |
if (ea = ea_find(eattrs, EA_KRT_PREFSRC)) |
nl_add_attr_ipa(&r.h, sizeof(r), RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data); | nl_add_attr_ipa(&r->h, rsize, RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data); |
|
|
if (ea = ea_find(eattrs, EA_KRT_REALM)) |
if (ea = ea_find(eattrs, EA_KRT_REALM)) |
nl_add_attr_u32(&r.h, sizeof(r), RTA_FLOW, ea->u.data); | nl_add_attr_u32(&r->h, rsize, RTA_FLOW, ea->u.data); |
|
|
|
|
u32 metrics[KRT_METRICS_MAX]; |
u32 metrics[KRT_METRICS_MAX]; |
Line 953 nl_send_route(struct krt_proto *p, rte *e, struct ea_l
|
Line 1010 nl_send_route(struct krt_proto *p, rte *e, struct ea_l
|
} |
} |
|
|
if (metrics[0]) |
if (metrics[0]) |
nl_add_metrics(&r.h, sizeof(r), metrics, KRT_METRICS_MAX); | nl_add_metrics(&r->h, rsize, metrics, KRT_METRICS_MAX); |
|
|
|
|
dest: |
dest: |
Line 961 dest:
|
Line 1018 dest:
|
switch (dest) |
switch (dest) |
{ |
{ |
case RTD_ROUTER: |
case RTD_ROUTER: |
r.r.rtm_type = RTN_UNICAST; | r->r.rtm_type = RTN_UNICAST; |
nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, iface->index); | nl_add_attr_u32(&r->h, rsize, RTA_OIF, iface->index); |
nl_add_attr_ipa(&r.h, sizeof(r), RTA_GATEWAY, gw); | nl_add_attr_ipa(&r->h, rsize, RTA_GATEWAY, gw); |
break; |
break; |
case RTD_DEVICE: |
case RTD_DEVICE: |
r.r.rtm_type = RTN_UNICAST; | r->r.rtm_type = RTN_UNICAST; |
nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, iface->index); | nl_add_attr_u32(&r->h, rsize, RTA_OIF, iface->index); |
break; |
break; |
case RTD_BLACKHOLE: |
case RTD_BLACKHOLE: |
r.r.rtm_type = RTN_BLACKHOLE; | r->r.rtm_type = RTN_BLACKHOLE; |
break; |
break; |
case RTD_UNREACHABLE: |
case RTD_UNREACHABLE: |
r.r.rtm_type = RTN_UNREACHABLE; | r->r.rtm_type = RTN_UNREACHABLE; |
break; |
break; |
case RTD_PROHIBIT: |
case RTD_PROHIBIT: |
r.r.rtm_type = RTN_PROHIBIT; | r->r.rtm_type = RTN_PROHIBIT; |
break; |
break; |
case RTD_MULTIPATH: |
case RTD_MULTIPATH: |
r.r.rtm_type = RTN_UNICAST; | r->r.rtm_type = RTN_UNICAST; |
nl_add_multipath(&r.h, sizeof(r), a->nexthops); | nl_add_multipath(&r->h, rsize, a->nexthops); |
break; |
break; |
case RTD_NONE: |
case RTD_NONE: |
break; |
break; |
Line 989 dest:
|
Line 1046 dest:
|
} |
} |
|
|
/* Ignore missing for DELETE */ |
/* Ignore missing for DELETE */ |
return nl_exchange(&r.h, (op == NL_OP_DELETE)); | return nl_exchange(&r->h, (op == NL_OP_DELETE)); |
} |
} |
|
|
static inline int |
static inline int |
Line 1240 nl_parse_route(struct nl_parse_state *s, struct nlmsgh
|
Line 1297 nl_parse_route(struct nl_parse_state *s, struct nlmsgh
|
{ |
{ |
case RTN_UNICAST: |
case RTN_UNICAST: |
|
|
if (a[RTA_MULTIPATH] && (i->rtm_family == AF_INET)) | if (a[RTA_MULTIPATH]) |
{ |
{ |
ra->dest = RTD_MULTIPATH; |
ra->dest = RTD_MULTIPATH; |
ra->nexthops = nl_parse_multipath(p, a[RTA_MULTIPATH]); | ra->nexthops = nl_parse_multipath(p, a[RTA_MULTIPATH], i->rtm_family); |
if (!ra->nexthops) |
if (!ra->nexthops) |
{ |
{ |
log(L_ERR "KRT: Received strange multipath route %I/%d", |
log(L_ERR "KRT: Received strange multipath route %I/%d", |
Line 1385 nl_parse_route(struct nl_parse_state *s, struct nlmsgh
|
Line 1442 nl_parse_route(struct nl_parse_state *s, struct nlmsgh
|
|
|
/* |
/* |
* Ideally, now we would send the received route to the rest of kernel code. |
* Ideally, now we would send the received route to the rest of kernel code. |
* But IPv6 ECMP routes are sent as a sequence of routes, so we postpone it | * But IPv6 ECMP routes before 4.11 are sent as a sequence of routes, so we |
* and merge next hops until the end of the sequence. | * postpone it and merge next hops until the end of the sequence. Note that |
| * proper multipath updates are rejected by nl_mergable_route(), so it is |
| * always the first case for them. |
*/ |
*/ |
|
|
if (!s->net) |
if (!s->net) |
Line 1694 kif_sys_start(struct kif_proto *p UNUSED)
|
Line 1753 kif_sys_start(struct kif_proto *p UNUSED)
|
void |
void |
kif_sys_shutdown(struct kif_proto *p UNUSED) |
kif_sys_shutdown(struct kif_proto *p UNUSED) |
{ |
{ |
} | } |
|
|