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:
parent
4b1aa37f93
commit
692055e3df
5 changed files with 70 additions and 11 deletions
|
@ -2153,6 +2153,13 @@ protocol bfd [<name>] {
|
|||
to configure separate BFD protocol instances for IPv4 and for IPv6
|
||||
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>
|
||||
Interface definitions allow to specify options for sessions associated
|
||||
with such interfaces and also may contain interface specific options.
|
||||
|
|
|
@ -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->uc = 1;
|
||||
|
||||
if (cf->strict_bind)
|
||||
ifa->rx = bfd_open_rx_sk_bound(p, local, iface);
|
||||
|
||||
add_tail(&p->iface_list, &ifa->n);
|
||||
|
||||
return ifa;
|
||||
|
@ -599,6 +602,12 @@ bfd_free_iface(struct bfd_iface *ifa)
|
|||
rfree(ifa->sk);
|
||||
}
|
||||
|
||||
if (ifa->rx)
|
||||
{
|
||||
sk_stop(ifa->rx);
|
||||
rfree(ifa->rx);
|
||||
}
|
||||
|
||||
rem_node(&ifa->n);
|
||||
mb_free(ifa);
|
||||
}
|
||||
|
@ -1038,6 +1047,8 @@ bfd_start(struct proto *P)
|
|||
|
||||
birdloop_enter(p->loop);
|
||||
|
||||
if (!cf->strict_bind)
|
||||
{
|
||||
if (cf->accept_ipv4 && cf->accept_direct)
|
||||
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)
|
||||
p->rx6_m = bfd_open_rx_sk(p, 1, SK_IPV6);
|
||||
}
|
||||
|
||||
birdloop_leave(p->loop);
|
||||
|
||||
|
@ -1102,7 +1114,8 @@ bfd_reconfigure(struct proto *P, struct proto_config *c)
|
|||
if ((new->accept_ipv4 != old->accept_ipv4) ||
|
||||
(new->accept_ipv6 != old->accept_ipv6) ||
|
||||
(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;
|
||||
|
||||
birdloop_mask_wakeups(p->loop);
|
||||
|
|
|
@ -47,6 +47,7 @@ struct bfd_config
|
|||
u8 accept_ipv6;
|
||||
u8 accept_direct;
|
||||
u8 accept_multihop;
|
||||
u8 strict_bind;
|
||||
};
|
||||
|
||||
struct bfd_iface_config
|
||||
|
@ -116,6 +117,7 @@ struct bfd_iface
|
|||
struct bfd_proto *bfd;
|
||||
|
||||
sock *sk;
|
||||
sock *rx;
|
||||
u32 uc;
|
||||
u8 changed;
|
||||
};
|
||||
|
@ -221,6 +223,7 @@ void bfd_show_sessions(struct proto *P);
|
|||
/* packets.c */
|
||||
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_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);
|
||||
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ CF_DECLS
|
|||
|
||||
CF_KEYWORDS(BFD, MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE,
|
||||
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 <a> bfd_neigh_local
|
||||
|
@ -48,6 +49,7 @@ bfd_proto_item:
|
|||
| INTERFACE bfd_iface
|
||||
| MULTIHOP bfd_multihop
|
||||
| NEIGHBOR bfd_neighbor
|
||||
| STRICT BIND bool { BFD_CFG->strict_bind = $3; }
|
||||
;
|
||||
|
||||
bfd_proto_opts:
|
||||
|
|
|
@ -366,7 +366,9 @@ bfd_rx_hook(sock *sk, uint len)
|
|||
if (ps > BFD_STATE_DOWN)
|
||||
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);
|
||||
|
||||
/* FIXME: better session matching and message */
|
||||
|
@ -438,6 +440,38 @@ bfd_open_rx_sk(struct bfd_proto *p, int multihop, int af)
|
|||
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 *
|
||||
bfd_open_tx_sk(struct bfd_proto *p, ip_addr local, struct iface *ifa)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue