]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
BFD: Add 'strict bind' option
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Thu, 7 Apr 2022 17:33:40 +0000 (19:33 +0200)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Thu, 7 Apr 2022 17:33:40 +0000 (19:33 +0200)
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.

doc/bird.sgml
proto/bfd/bfd.c
proto/bfd/bfd.h
proto/bfd/config.Y
proto/bfd/packets.c

index 1d5ae056a099b15c544e319c89a23fdc64562f3e..9c4a6f68a447a4e79b159c7502e60eda78c4ae86 100644 (file)
@@ -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.
index dac184c50ba84bb51c1f9a6834bd282c5d32f4d5..cc9416958803576185f168d1ca52749b33a9b5e2 100644 (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->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);
index 91fdaa600f64f38b77d02d31613f627fee79d2cb..7caf9f666dc81caada4681399e25b52e4c695996 100644 (file)
@@ -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);
 
 
index df1cba42cfa7d2129389a80756849573b5b9b443..70461872c06d6b337c99760653b42f2b6fad18dd 100644 (file)
@@ -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:
index 7618e20ff7cea12536b531517023b5d856bc3a51..5f10734ce3b08aa4bf7b445c35e9b9ffc1212026 100644 (file)
@@ -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)
 {