summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2022-04-07 19:33:40 +0200
committerOndrej Zajicek (work) <santiago@crfreenet.org>2022-04-07 19:33:40 +0200
commit692055e3df6cc9f0d428d3b0dd8cdd8e825eb6f4 (patch)
treea7eea92e04722f395f9a2978ae12965d6a4021a5
parent4b1aa37f931888febfd768309d5e2ef36f5e7194 (diff)
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.
-rw-r--r--doc/bird.sgml7
-rw-r--r--proto/bfd/bfd.c31
-rw-r--r--proto/bfd/bfd.h3
-rw-r--r--proto/bfd/config.Y4
-rw-r--r--proto/bfd/packets.c36
5 files changed, 70 insertions, 11 deletions
diff --git a/doc/bird.sgml b/doc/bird.sgml
index 1d5ae056..9c4a6f68 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -2153,6 +2153,13 @@ protocol bfd [&lt;name&gt;] {
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.
diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c
index dac184c5..cc941695 100644
--- a/proto/bfd/bfd.c
+++ b/proto/bfd/bfd.c
@@ -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,17 +1047,20 @@ bfd_start(struct proto *P)
birdloop_enter(p->loop);
- if (cf->accept_ipv4 && cf->accept_direct)
- p->rx4_1 = bfd_open_rx_sk(p, 0, SK_IPV4);
+ if (!cf->strict_bind)
+ {
+ if (cf->accept_ipv4 && cf->accept_direct)
+ p->rx4_1 = bfd_open_rx_sk(p, 0, SK_IPV4);
- if (cf->accept_ipv4 && cf->accept_multihop)
- p->rx4_m = bfd_open_rx_sk(p, 1, SK_IPV4);
+ if (cf->accept_ipv4 && cf->accept_multihop)
+ p->rx4_m = bfd_open_rx_sk(p, 1, SK_IPV4);
- if (cf->accept_ipv6 && cf->accept_direct)
- p->rx6_1 = bfd_open_rx_sk(p, 0, SK_IPV6);
+ if (cf->accept_ipv6 && cf->accept_direct)
+ p->rx6_1 = bfd_open_rx_sk(p, 0, SK_IPV6);
- if (cf->accept_ipv6 && cf->accept_multihop)
- p->rx6_m = bfd_open_rx_sk(p, 1, SK_IPV6);
+ 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);
diff --git a/proto/bfd/bfd.h b/proto/bfd/bfd.h
index 91fdaa60..7caf9f66 100644
--- a/proto/bfd/bfd.h
+++ b/proto/bfd/bfd.h
@@ -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);
diff --git a/proto/bfd/config.Y b/proto/bfd/config.Y
index df1cba42..70461872 100644
--- a/proto/bfd/config.Y
+++ b/proto/bfd/config.Y
@@ -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:
diff --git a/proto/bfd/packets.c b/proto/bfd/packets.c
index 7618e20f..5f10734c 100644
--- a/proto/bfd/packets.c
+++ b/proto/bfd/packets.c
@@ -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 */
@@ -439,6 +441,38 @@ bfd_open_rx_sk(struct bfd_proto *p, int multihop, int af)
}
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)
{
sock *sk = sk_new(p->tpool);