]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
BFD: Dispatch sessions also by interface index
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Sun, 10 Jan 2021 14:29:02 +0000 (15:29 +0100)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Sun, 10 Jan 2021 14:29:02 +0000 (15:29 +0100)
Direct BFD sessions needs to be dispatched not only by IP addresses, but
also by interfaces, in order to avoid collisions between neighbors with
the same IPv6 link-local addresses.

Extend BFD session hash_ip key by interface index to handle that. Use 0
for multihop sessions.

Thanks to Sebastian Hahn for the original patch.

proto/bfd/bfd.c
proto/bfd/bfd.h
proto/bfd/packets.c

index 8dfca7903af9a4f1ca4773f9349745a50d29f4b1..dac184c50ba84bb51c1f9a6834bd282c5d32f4d5 100644 (file)
  * related to the session and two timers (TX timer for periodic packets and hold
  * timer for session timeout). These sessions are allocated from @session_slab
  * and are accessible by two hash tables, @session_hash_id (by session ID) and
- * @session_hash_ip (by IP addresses of neighbors). Slab and both hashes are in
- * the main protocol structure &bfd_proto. The protocol logic related to BFD
- * sessions is implemented in internal functions bfd_session_*(), which are
- * expected to be called from the context of BFD thread, and external functions
- * bfd_add_session(), bfd_remove_session() and bfd_reconfigure_session(), which
- * form an interface to the BFD core for the rest and are expected to be called
- * from the context of main thread.
+ * @session_hash_ip (by IP addresses of neighbors and associated interfaces).
+ * Slab and both hashes are in the main protocol structure &bfd_proto. The
+ * protocol logic related to BFD sessions is implemented in internal functions
+ * bfd_session_*(), which are expected to be called from the context of BFD
+ * thread, and external functions bfd_add_session(), bfd_remove_session() and
+ * bfd_reconfigure_session(), which form an interface to the BFD core for the
+ * rest and are expected to be called from the context of main thread.
  *
  * Each BFD session has an associated BFD interface, represented by structure
  * &bfd_iface. A BFD interface contains a socket used for TX (the one for RX is
 #define HASH_ID_EQ(a,b)                a == b
 #define HASH_ID_FN(k)          k
 
-#define HASH_IP_KEY(n)         n->addr
+#define HASH_IP_KEY(n)         n->addr, n->ifindex
 #define HASH_IP_NEXT(n)                n->next_ip
-#define HASH_IP_EQ(a,b)                ipa_equal(a,b)
-#define HASH_IP_FN(k)          ipa_hash(k)
+#define HASH_IP_EQ(a1,n1,a2,n2)        ipa_equal(a1, a2) && n1 == n2
+#define HASH_IP_FN(a,n)                ipa_hash(a) ^ u32_hash(n)
 
 static list bfd_proto_list;
 static list bfd_wait_list;
@@ -385,9 +385,9 @@ bfd_find_session_by_id(struct bfd_proto *p, u32 id)
 }
 
 struct bfd_session *
-bfd_find_session_by_addr(struct bfd_proto *p, ip_addr addr)
+bfd_find_session_by_addr(struct bfd_proto *p, ip_addr addr, uint ifindex)
 {
-  return HASH_FIND(p->session_hash_ip, HASH_IP, addr);
+  return HASH_FIND(p->session_hash_ip, HASH_IP, addr, ifindex);
 }
 
 static void
@@ -426,6 +426,7 @@ bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface *
   struct bfd_session *s = sl_allocz(p->session_slab);
   s->addr = addr;
   s->ifa = ifa;
+  s->ifindex = iface ? iface->index : 0;
   s->loc_id = bfd_get_free_id(p);
 
   HASH_INSERT(p->session_hash_id, HASH_ID, s);
@@ -658,7 +659,8 @@ bfd_add_request(struct bfd_proto *p, struct bfd_request *req)
   if (req->iface ? !cf->accept_direct : !cf->accept_multihop)
     return 0;
 
-  struct bfd_session *s = bfd_find_session_by_addr(p, req->addr);
+  uint ifindex = req->iface ? req->iface->index : 0;
+  struct bfd_session *s = bfd_find_session_by_addr(p, req->addr, ifindex);
   u8 state, diag;
 
   if (!s)
index 83e2a9910ba4b0934d182206474ef8929f1e9a54..91fdaa600f64f38b77d02d31613f627fee79d2cb 100644 (file)
@@ -153,6 +153,7 @@ struct bfd_session
   u8 detect_mult;                      /* Announced detect_mult, local option */
   u8 rem_detect_mult;                  /* Last received detect_mult */
 
+  uint ifindex;                                /* Iface index, for hashing in bfd.session_hash_ip */
   btime last_tx;                       /* Time of last sent periodic control packet */
   btime last_rx;                       /* Time of last received valid control packet */
 
@@ -213,7 +214,7 @@ static inline void bfd_unlock_sessions(struct bfd_proto *p) { pthread_spin_unloc
 
 /* bfd.c */
 struct bfd_session * bfd_find_session_by_id(struct bfd_proto *p, u32 id);
-struct bfd_session * bfd_find_session_by_addr(struct bfd_proto *p, ip_addr addr);
+struct bfd_session * bfd_find_session_by_addr(struct bfd_proto *p, ip_addr addr, uint ifindex);
 void bfd_session_process_ctl(struct bfd_session *s, u8 flags, u32 old_tx_int, u32 old_rx_int);
 void bfd_show_sessions(struct proto *P);
 
index 703c6e28a7fdfbc5c801ba2f6d876ee0131681ca..7618e20ff7cea12536b531517023b5d856bc3a51 100644 (file)
@@ -366,7 +366,8 @@ bfd_rx_hook(sock *sk, uint len)
     if (ps > BFD_STATE_DOWN)
       DROP("invalid init state", ps);
 
-    s = bfd_find_session_by_addr(p, sk->faddr);
+    uint ifindex = (sk->sport == BFD_CONTROL_PORT) ? sk->lifindex : 0;
+    s = bfd_find_session_by_addr(p, sk->faddr, ifindex);
 
     /* FIXME: better session matching and message */
     if (!s)