implement MTU calculation and adjustments
authorChristian Grothoff <christian@grothoff.org>
Wed, 30 Jan 2019 06:26:53 +0000 (07:26 +0100)
committerChristian Grothoff <christian@grothoff.org>
Wed, 30 Jan 2019 06:26:53 +0000 (07:26 +0100)
src/include/gnunet_tun_lib.h
src/transport/gnunet-communicator-tcp.c
src/transport/gnunet-communicator-udp.c

index 8fb6f32f0cd1f5db5aee07ea5f9aeb673b39d644..11c43e8b74b80b6ad21461d4f5c94b31c18e2e7a 100644 (file)
@@ -58,6 +58,7 @@
  * 8 bytes for IPv4, 4 bytes for port, 1 byte for "4", 2 bytes for "-",
  * one byte for 0-termination.
  */
+
 #define GNUNET_TUN_IPV4_REGEXLEN 16
 
 
index d86fa03b69f893e3ff6a177f7a359c587870e67b..1d10b82e507ca1a3bb84f9e40d3e9b42f5029894 100644 (file)
@@ -590,6 +590,11 @@ queue_destroy (struct Queue *queue)
     queue->mq = NULL;
     GNUNET_MQ_destroy (mq);
   }
+  if (NULL != queue->qh)
+  {
+    GNUNET_TRANSPORT_communicator_mq_del (queue->qh);
+    queue->qh = NULL;
+  }
   GNUNET_assert (GNUNET_YES ==
                  GNUNET_CONTAINER_multipeermap_remove (queue_map,
                                                       &queue->target,
index 12c409b3d376fbd125b206dabb12513866162163..c88f7f6f5a2f9aecd60de7a978dfec5c14396f94 100644 (file)
  * @author Christian Grothoff
  *
  * TODO:
- * - figure out what to do with MTU: 1280 for IPv6 is obvious;
- *   what for IPv4? 1500? Also, consider differences in 
- *   headers for with/without box: need to give MIN of both
- *   to TNG (as TNG expects a fixed MTU!), or maybe
- *   we create a FRESH MQ while we have available BOXes SQNs?
- *   (otherwise padding will REALLY hurt)
  * - add and use util/ check for IPv6 availability (#V6)
  * - consider imposing transmission limits in the absence
  *   of ACKs; or: maybe this should be done at TNG service level?
- * - handle addresses discovered from broadcasts (#)
+ *   (at least the receiver might want to enforce limits on
+ *    KX/DH operations per sender in here)
+ * - overall, we should look more into flow control support
+ *   (either in backchannel, or general solution in TNG service)
+ * - handle addresses discovered from broadcasts (#BC)
  *   (think: what was the story again on address validation?
  *    where is the API for that!?!)
  * - support DNS names in BINDTO option (#5528)
@@ -534,6 +532,12 @@ struct ReceiverAddress
    */
   struct SharedSecret *ss_tail;
 
+  /**
+   * Address of the receiver in the human-readable format
+   * with the #COMMUNICATOR_ADDRESS_PREFIX.
+   */ 
+  char *foreign_addr;
+
   /**
    * Address of the other peer.
    */
@@ -794,6 +798,11 @@ receiver_destroy (struct ReceiverAddress *receiver)
     receiver->mq = NULL;
     GNUNET_MQ_destroy (mq);
   }
+  if (NULL != receiver->qh)
+  {
+    GNUNET_TRANSPORT_communicator_mq_del (receiver->qh);
+    receiver->qh = NULL;
+  }
   GNUNET_assert (GNUNET_YES ==
                  GNUNET_CONTAINER_multipeermap_remove (receivers,
                                                       &receiver->target,
@@ -805,6 +814,7 @@ receiver_destroy (struct ReceiverAddress *receiver)
                         GNUNET_CONTAINER_multipeermap_size (receivers),
                         GNUNET_NO);
   GNUNET_free (receiver->address);
+  GNUNET_free (receiver->foreign_addr);
   GNUNET_free (receiver);
 }
 
@@ -1259,6 +1269,17 @@ setup_shared_secret_enc (const struct GNUNET_CRYPTO_EcdhePrivateKey *ephemeral,
 }
 
 
+/**
+ * Setup the MQ for the @a receiver.  If a queue exists,
+ * the existing one is destroyed.  Then the MTU is
+ * recalculated and a fresh queue is initialized.
+ *
+ * @param receiver receiver to setup MQ for
+ */ 
+static void
+setup_receiver_mq (struct ReceiverAddress *receiver);
+
+
 /**
  * We received an ACK for @a pid. Check if it is for
  * the receiver in @a value and if so, handle it and
@@ -1292,11 +1313,13 @@ handle_ack (void *cls,
                            
       if (allowed > ss->sequence_allowed)
       {
-       if (0 == receiver->acks_available)
+       receiver->acks_available += (allowed - ss->sequence_allowed);
+       if ((allowed - ss->sequence_allowed)
+           == receiver->acks_available)
        {
-         /* FIXME: update MTU / MQ of 'receiver'! */
+         /* we just incremented from zero => MTU change! */
+         setup_receiver_mq (receiver);
        }
-       receiver->acks_available += (allowed - ss->sequence_allowed);
        ss->sequence_allowed = allowed;
        /* move ss to head to avoid discarding it anytime soon! */
        GNUNET_CONTAINER_DLL_remove (receiver->ss_head,
@@ -1649,7 +1672,7 @@ sock_read (void *cls)
                                "# broadcasts received",
                                1,
                                GNUNET_NO);
-      // FIXME: we effectively just got a HELLO!
+      // FIXME #BC: we effectively just got a HELLO!
       // trigger verification NOW!
       return;
     }
@@ -2012,7 +2035,6 @@ mq_send (struct GNUNET_MQ_Handle *mq,
     return;
   } /* End of KX encryption method */
 
-  // FIXME: add support for BOX encryption method!
   /* begin "BOX" encryption method, scan for ACKs from tail! */
   for (struct SharedSecret *ss = receiver->ss_tail;
        NULL != ss;
@@ -2062,7 +2084,8 @@ mq_send (struct GNUNET_MQ_Handle *mq,
       receiver->acks_available--;
       if (0 == receiver->acks_available)
       {
-       /* FIXME: update MTU / MQ of 'receiver'! */
+       /* We have no more ACKs => MTU change! */
+       setup_receiver_mq (receiver);
       }
       return;
     }
@@ -2131,6 +2154,77 @@ mq_error (void *cls,
 }
 
 
+/**
+ * Setup the MQ for the @a receiver.  If a queue exists,
+ * the existing one is destroyed.  Then the MTU is
+ * recalculated and a fresh queue is initialized.
+ *
+ * @param receiver receiver to setup MQ for
+ */ 
+static void
+setup_receiver_mq (struct ReceiverAddress *receiver)
+{
+  size_t base_mtu;
+  
+  if (NULL != receiver->qh)
+  {
+    GNUNET_TRANSPORT_communicator_mq_del (receiver->qh);
+    receiver->qh = NULL;
+  }
+  GNUNET_assert (NULL == receiver->mq);
+  switch (receiver->address->sa_family)
+  {
+  case AF_INET:
+    base_mtu
+      = 1480 /* Ethernet MTU, 1500 - Ethernet header - VLAN tag */
+      - sizeof (struct GNUNET_TUN_IPv4Header) /* 20 */
+      - sizeof (struct GNUNET_TUN_UdpHeader) /* 8 */;
+    break;
+  case AF_INET6:
+    base_mtu
+      = 1280 /* Minimum MTU required by IPv6 */
+      - sizeof (struct GNUNET_TUN_IPv6Header) /* 40 */
+      - sizeof (struct GNUNET_TUN_UdpHeader) /* 8 */;
+    break;
+  default:
+    GNUNET_assert (0);
+    break;
+  }
+  if (0 == receiver->acks_available)
+  {
+    /* MTU based on full KX messages */
+    receiver->mtu
+      = base_mtu
+      - sizeof (struct InitialKX) /* 48 */
+      - sizeof (struct UDPConfirmation); /* 104 */
+  }
+  else
+  {
+    /* MTU based on BOXed messages */
+    receiver->mtu
+      = base_mtu - sizeof (struct UDPBox);
+  }
+  /* => Effective MTU for CORE will range from 1080 (IPv6 + KX) to
+     1404 (IPv4 + Box) bytes, depending on circumstances... */
+  receiver->mq
+    = GNUNET_MQ_queue_for_callbacks (&mq_send,
+                                    &mq_destroy,
+                                    &mq_cancel,
+                                    receiver,
+                                    NULL,
+                                    &mq_error,
+                                    receiver);
+  receiver->qh
+    = GNUNET_TRANSPORT_communicator_mq_add (ch,
+                                           &receiver->target,
+                                           receiver->foreign_addr,
+                                           receiver->mtu,
+                                           receiver->nt,
+                                           GNUNET_TRANSPORT_CS_OUTBOUND,
+                                           receiver->mq);
+}
+
+
 /**
  * Setup a receiver for transmission.  Setup the MQ processing and
  * inform transport that the queue is ready. 
@@ -2161,54 +2255,35 @@ receiver_setup (const struct GNUNET_PeerIdentity *target,
   receiver->hn = GNUNET_CONTAINER_heap_insert (receivers_heap,
                                               receiver,
                                               receiver->timeout.abs_value_us);
-  receiver->mq
-    = GNUNET_MQ_queue_for_callbacks (&mq_send,
-                                    &mq_destroy,
-                                    &mq_cancel,
-                                    receiver,
-                                    NULL,
-                                    &mq_error,
-                                    receiver);
-  receiver->mtu = 1200 /* FIXME: MTU OK? */;
-  if (NULL == timeout_task)
-    timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts,
-                                            NULL);
   GNUNET_STATISTICS_set (stats,
                         "# receivers active",
                         GNUNET_CONTAINER_multipeermap_size (receivers),
                         GNUNET_NO);
+  switch (address->sa_family)
   {
-    char *foreign_addr;
-
-    switch (address->sa_family)
-    {
-    case AF_INET:
-      GNUNET_asprintf (&foreign_addr,
-                      "%s-%s",
-                      COMMUNICATOR_ADDRESS_PREFIX,
-                      GNUNET_a2s (receiver->address,
-                                  receiver->address_len));
-      break;
-    case AF_INET6:
-      GNUNET_asprintf (&foreign_addr,
-                      "%s-%s",
-                      COMMUNICATOR_ADDRESS_PREFIX,
-                      GNUNET_a2s (receiver->address,
-                                  receiver->address_len));
-      break;
-    default:
-      GNUNET_assert (0);
-    }
-    receiver->qh
-      = GNUNET_TRANSPORT_communicator_mq_add (ch,
-                                             &receiver->target,
-                                             foreign_addr,
-                                             receiver->mtu,
-                                             receiver->nt,
-                                             GNUNET_TRANSPORT_CS_OUTBOUND,
-                                             receiver->mq);
-    GNUNET_free (foreign_addr);
+  case AF_INET:
+    GNUNET_asprintf (&receiver->foreign_addr,
+                    "%s-%s",
+                    COMMUNICATOR_ADDRESS_PREFIX,
+                    GNUNET_a2s (receiver->address,
+                                receiver->address_len));
+    break;
+  case AF_INET6:
+    GNUNET_asprintf (&receiver->foreign_addr,
+                    "%s-%s",
+                    COMMUNICATOR_ADDRESS_PREFIX,
+                    GNUNET_a2s (receiver->address,
+                                receiver->address_len));
+    break;
+  default:
+    GNUNET_assert (0);
   }
+
+  setup_receiver_mq (receiver);
+
+  if (NULL == timeout_task)
+    timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts,
+                                            NULL);
   return receiver;
 }