Browse Source

bgpd: Rollback "always send OPEN" a little, to workaround test suite issues

* "bgpd: Send OPEN immediately on inbound connections" doesn't play well with
  some partial BGP implementations, test and conformance suites e.g., which
  have rigid expectations about ordering and don't implement much of CD.

  roll back, but only a little, by deferring OPEN sending on outbound till
  receive.

* bgpd.h: (struct peer) add PEER_STATUS_OPEN_DEFERRED status flag.
  Kind of a sub-fsm.  Main FSM does not allow transition functions to
  signal next-state - next-state is inflexibly fixed in the table -
  so can't handle it cleanly at that level.
* bgp_fsm.c: (bgp_connect_success) Defer sending open if the peer is
  an accept-peer/inbound and there appears to be an outbound connection
  in progress. Set PEER_STATUS_OPEN_DEFERRED to signal to bgp_open_receive
  that an OPEN still must be sent.
* bgp_packet.c: (bgp_open_receive) Send the OPEN here, when deferred.
Paul Jakma 2 years ago
parent
commit
d023f9ffae
3 changed files with 39 additions and 2 deletions
  1. 24 1
      bgpd/bgp_fsm.c
  2. 14 0
      bgpd/bgp_packet.c
  3. 1 1
      bgpd/bgpd.h

+ 24 - 1
bgpd/bgp_fsm.c

@@ -656,6 +656,8 @@ bgp_stop_with_notify (struct peer *peer, u_char code, u_char sub_code)
 static int
 bgp_connect_success (struct peer *peer)
 {
+  struct peer *realpeer;
+  
   if (peer->fd < 0)
     {
       zlog_err ("bgp_connect_success peer's fd is negative value %d",
@@ -677,7 +679,28 @@ bgp_connect_success (struct peer *peer)
       else
 	zlog_debug ("%s passive open", peer->host);
     }
-
+  
+  /* Generally we want to send OPEN ASAP. Except, some partial BGP
+   * implementations out there (e.g., conformance test tools / BGP
+   * traffic generators) seem to be a bit funny about connection collisions,
+   * and OPENs before they have sent.
+   *
+   * As a hack, delay sending OPEN on an inbound accept-peer session
+   * _IF_ we locally have an outbound connection in progress, i.e. 
+   * we're in middle of a connection collision. If we delay, we delay until
+   * an Open is received - as per old Quagga behaviour.
+   */
+  if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+    {
+      realpeer = peer_lookup (peer->bgp, &peer->su);
+      
+      if (realpeer->status > Idle && realpeer->status <= Established)
+        {
+          SET_FLAG (peer->sflags, PEER_STATUS_OPEN_DEFERRED);
+          return 0;
+        }
+   }
+  
   bgp_open_send (peer);
 
   return 0;

+ 14 - 0
bgpd/bgp_packet.c

@@ -1542,12 +1542,16 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
       realpeer->obuf = peer->obuf;
       peer->obuf = NULL;
       
+      bool open_deferred
+        = CHECK_FLAG (peer->sflags, PEER_STATUS_OPEN_DEFERRED);
+      
       /* Transfer status. */
       realpeer->status = peer->status;
       bgp_stop (peer);
       
       /* peer pointer change */
       peer = realpeer;
+      
       if (peer->fd < 0)
 	{
 	  zlog_err ("bgp_open_receive peer's fd is negative value %d",
@@ -1557,6 +1561,16 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
       BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
       if (stream_fifo_head (peer->obuf))
         BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+      
+      /* hack: we may defer OPEN on accept peers, when there seems to be a
+       * realpeer in progress, when an accept peer connection is opened. This
+       * is to avoid interoperability issues, with test/conformance tools
+       * particularly. See bgp_fsm.c::bgp_connect_success
+       *
+       * If OPEN was deferred there, then we must send it now.
+       */
+      if (open_deferred)
+        bgp_open_send (peer);
     }
 
   /* remote router-id check. */

+ 1 - 1
bgpd/bgpd.h

@@ -442,7 +442,7 @@ struct peer
 #define PEER_STATUS_ACCEPT_PEER	      (1 << 0) /* accept peer */
 #define PEER_STATUS_PREFIX_OVERFLOW   (1 << 1) /* prefix-overflow */
 #define PEER_STATUS_CAPABILITY_OPEN   (1 << 2) /* capability open send */
-#define PEER_STATUS_HAVE_ACCEPT       (1 << 3) /* accept peer's parent */
+#define PEER_STATUS_OPEN_DEFERRED     (1 << 3) /* deferred to open_receive */
 #define PEER_STATUS_GROUP             (1 << 4) /* peer-group conf */
 #define PEER_STATUS_NSF_MODE          (1 << 5) /* NSF aware peer */
 #define PEER_STATUS_NSF_WAIT          (1 << 6) /* wait comeback peer */