BFD: Add 'strict bind' option

Add BFD protocol option 'strict bind' to use separate listening socket
for each BFD interface bound to its address instead of using shared
listening sockets.
This commit is contained in:
Ondrej Zajicek (work) 2022-04-07 19:33:40 +02:00
parent 4b1aa37f93
commit 692055e3df
5 changed files with 70 additions and 11 deletions

View file

@ -2153,6 +2153,13 @@ protocol bfd [<name>] {
to configure separate BFD protocol instances for IPv4 and for IPv6 to configure separate BFD protocol instances for IPv4 and for IPv6
sessions. sessions.
<tag><label id="bfd-strict-bind">strict bind <m/switch/</tag>
Specify whether each BFD interface should use a separate listening
socket bound to its local address, or just use a shared listening socket
accepting all addresses. Binding to a specific address could be useful
in cases like running multiple BIRD instances on a machine, each
handling a different set of interfaces. Default: disabled.
<tag><label id="bfd-iface">interface <m/pattern/ [, <m/.../] { <m/options/ }</tag> <tag><label id="bfd-iface">interface <m/pattern/ [, <m/.../] { <m/options/ }</tag>
Interface definitions allow to specify options for sessions associated Interface definitions allow to specify options for sessions associated
with such interfaces and also may contain interface specific options. with such interfaces and also may contain interface specific options.

View file

@ -582,6 +582,9 @@ bfd_get_iface(struct bfd_proto *p, ip_addr local, struct iface *iface)
ifa->sk = bfd_open_tx_sk(p, local, iface); ifa->sk = bfd_open_tx_sk(p, local, iface);
ifa->uc = 1; ifa->uc = 1;
if (cf->strict_bind)
ifa->rx = bfd_open_rx_sk_bound(p, local, iface);
add_tail(&p->iface_list, &ifa->n); add_tail(&p->iface_list, &ifa->n);
return ifa; return ifa;
@ -599,6 +602,12 @@ bfd_free_iface(struct bfd_iface *ifa)
rfree(ifa->sk); rfree(ifa->sk);
} }
if (ifa->rx)
{
sk_stop(ifa->rx);
rfree(ifa->rx);
}
rem_node(&ifa->n); rem_node(&ifa->n);
mb_free(ifa); mb_free(ifa);
} }
@ -1038,6 +1047,8 @@ bfd_start(struct proto *P)
birdloop_enter(p->loop); birdloop_enter(p->loop);
if (!cf->strict_bind)
{
if (cf->accept_ipv4 && cf->accept_direct) if (cf->accept_ipv4 && cf->accept_direct)
p->rx4_1 = bfd_open_rx_sk(p, 0, SK_IPV4); p->rx4_1 = bfd_open_rx_sk(p, 0, SK_IPV4);
@ -1049,6 +1060,7 @@ bfd_start(struct proto *P)
if (cf->accept_ipv6 && cf->accept_multihop) if (cf->accept_ipv6 && cf->accept_multihop)
p->rx6_m = bfd_open_rx_sk(p, 1, SK_IPV6); p->rx6_m = bfd_open_rx_sk(p, 1, SK_IPV6);
}
birdloop_leave(p->loop); birdloop_leave(p->loop);
@ -1102,7 +1114,8 @@ bfd_reconfigure(struct proto *P, struct proto_config *c)
if ((new->accept_ipv4 != old->accept_ipv4) || if ((new->accept_ipv4 != old->accept_ipv4) ||
(new->accept_ipv6 != old->accept_ipv6) || (new->accept_ipv6 != old->accept_ipv6) ||
(new->accept_direct != old->accept_direct) || (new->accept_direct != old->accept_direct) ||
(new->accept_multihop != old->accept_multihop)) (new->accept_multihop != old->accept_multihop) ||
(new->strict_bind != old->strict_bind))
return 0; return 0;
birdloop_mask_wakeups(p->loop); birdloop_mask_wakeups(p->loop);

View file

@ -47,6 +47,7 @@ struct bfd_config
u8 accept_ipv6; u8 accept_ipv6;
u8 accept_direct; u8 accept_direct;
u8 accept_multihop; u8 accept_multihop;
u8 strict_bind;
}; };
struct bfd_iface_config struct bfd_iface_config
@ -116,6 +117,7 @@ struct bfd_iface
struct bfd_proto *bfd; struct bfd_proto *bfd;
sock *sk; sock *sk;
sock *rx;
u32 uc; u32 uc;
u8 changed; u8 changed;
}; };
@ -221,6 +223,7 @@ void bfd_show_sessions(struct proto *P);
/* packets.c */ /* packets.c */
void bfd_send_ctl(struct bfd_proto *p, struct bfd_session *s, int final); void bfd_send_ctl(struct bfd_proto *p, struct bfd_session *s, int final);
sock * bfd_open_rx_sk(struct bfd_proto *p, int multihop, int inet_version); sock * bfd_open_rx_sk(struct bfd_proto *p, int multihop, int inet_version);
sock * bfd_open_rx_sk_bound(struct bfd_proto *p, ip_addr local, struct iface *ifa);
sock * bfd_open_tx_sk(struct bfd_proto *p, ip_addr local, struct iface *ifa); sock * bfd_open_tx_sk(struct bfd_proto *p, ip_addr local, struct iface *ifa);

View file

@ -23,7 +23,8 @@ CF_DECLS
CF_KEYWORDS(BFD, MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE, CF_KEYWORDS(BFD, MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE,
INTERFACE, MULTIHOP, NEIGHBOR, DEV, LOCAL, AUTHENTICATION, INTERFACE, MULTIHOP, NEIGHBOR, DEV, LOCAL, AUTHENTICATION,
NONE, SIMPLE, METICULOUS, KEYED, MD5, SHA1, IPV4, IPV6, DIRECT) NONE, SIMPLE, METICULOUS, KEYED, MD5, SHA1, IPV4, IPV6, DIRECT,
STRICT, BIND)
%type <iface> bfd_neigh_iface %type <iface> bfd_neigh_iface
%type <a> bfd_neigh_local %type <a> bfd_neigh_local
@ -48,6 +49,7 @@ bfd_proto_item:
| INTERFACE bfd_iface | INTERFACE bfd_iface
| MULTIHOP bfd_multihop | MULTIHOP bfd_multihop
| NEIGHBOR bfd_neighbor | NEIGHBOR bfd_neighbor
| STRICT BIND bool { BFD_CFG->strict_bind = $3; }
; ;
bfd_proto_opts: bfd_proto_opts:

View file

@ -366,7 +366,9 @@ bfd_rx_hook(sock *sk, uint len)
if (ps > BFD_STATE_DOWN) if (ps > BFD_STATE_DOWN)
DROP("invalid init state", ps); DROP("invalid init state", ps);
uint ifindex = (sk->sport == BFD_CONTROL_PORT) ? sk->lifindex : 0; uint ifindex = (sk->sport == BFD_CONTROL_PORT) ?
(sk->iface ? sk->iface->index : sk->lifindex) :
0;
s = bfd_find_session_by_addr(p, sk->faddr, ifindex); s = bfd_find_session_by_addr(p, sk->faddr, ifindex);
/* FIXME: better session matching and message */ /* FIXME: better session matching and message */
@ -438,6 +440,38 @@ bfd_open_rx_sk(struct bfd_proto *p, int multihop, int af)
return NULL; return NULL;
} }
sock *
bfd_open_rx_sk_bound(struct bfd_proto *p, ip_addr local, struct iface *ifa)
{
sock *sk = sk_new(p->tpool);
sk->type = SK_UDP;
sk->saddr = local;
sk->sport = ifa ? BFD_CONTROL_PORT : BFD_MULTI_CTL_PORT;
sk->iface = ifa;
sk->vrf = p->p.vrf;
sk->data = p;
sk->rbsize = BFD_MAX_LEN;
sk->rx_hook = bfd_rx_hook;
sk->err_hook = bfd_err_hook;
/* TODO: configurable ToS and priority */
sk->tos = IP_PREC_INTERNET_CONTROL;
sk->priority = sk_priority_control;
sk->flags = SKF_THREAD | SKF_BIND | (ifa ? SKF_TTL_RX : 0);
if (sk_open(sk) < 0)
goto err;
sk_start(sk);
return sk;
err:
sk_log_error(sk, p->p.name);
rfree(sk);
return NULL;
}
sock * sock *
bfd_open_tx_sk(struct bfd_proto *p, ip_addr local, struct iface *ifa) bfd_open_tx_sk(struct bfd_proto *p, ip_addr local, struct iface *ifa)
{ {