Make connect_to parameter for DLEP router useful again
authorHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Fri, 16 Mar 2018 12:57:04 +0000 (13:57 +0100)
committerHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Fri, 16 Mar 2018 12:57:04 +0000 (13:57 +0100)
12 files changed:
src-plugins/generic/dlep/dlep_interface.c
src-plugins/generic/dlep/dlep_interface.h
src-plugins/generic/dlep/dlep_session.c
src-plugins/generic/dlep/dlep_session.h
src-plugins/generic/dlep/radio/dlep_radio.c
src-plugins/generic/dlep/radio/dlep_radio_interface.c
src-plugins/generic/dlep/radio/dlep_radio_session.c
src-plugins/generic/dlep/router/dlep_router.c
src-plugins/generic/dlep/router/dlep_router_interface.c
src-plugins/generic/dlep/router/dlep_router_interface.h
src-plugins/generic/dlep/router/dlep_router_session.c
src-plugins/generic/dlep/router/dlep_router_session.h

index 65e37a7..19f97c8 100644 (file)
@@ -73,13 +73,15 @@ dlep_if_get_tree(bool radio) {
  * @param ifname name of interface
  * @param l2_origin layer2 originator that shall be used
  * @param l2_default_origin layer2 originator that shall be used for setting defaults
+ * @param if_changed interface listener bound to UDP session, can be NULL
  * @param log_src logging source that shall be used
  * @param radio true if it is a radio interface, false for router
  * @return -1 if an error happened, 0 otherwise
  */
 int
 dlep_if_add(struct dlep_if *interf, const char *ifname, const struct oonf_layer2_origin *l2_origin,
-  const struct oonf_layer2_origin *l2_default_origin, enum oonf_log_source log_src, bool radio) {
+  const struct oonf_layer2_origin *l2_default_origin,
+  int (*if_changed)(struct os_interface_listener *), enum oonf_log_source log_src, bool radio) {
   struct dlep_extension *ext;
 
   /* initialize key */
@@ -93,8 +95,8 @@ dlep_if_add(struct dlep_if *interf, const char *ifname, const struct oonf_layer2
   /* add dlep prefix to buffer */
   abuf_memcpy(&interf->udp_out, _DLEP_PREFIX, sizeof(_DLEP_PREFIX) - 1);
 
-  if (dlep_session_add(
-        &interf->session, interf->l2_ifname, l2_origin, l2_default_origin, &interf->udp_out, radio, log_src)) {
+  if (dlep_session_add(&interf->session, interf->l2_ifname,
+    l2_origin, l2_default_origin, &interf->udp_out, radio, if_changed, log_src)) {
     abuf_free(&interf->udp_out);
     return -1;
   }
@@ -188,9 +190,16 @@ _cb_receive_udp(struct oonf_packet_socket *pkt, union netaddr_socket *from, void
   interf = pkt->config.user;
   buffer = ptr;
 
-  if (interf->session_tree.count > 0 && interf->single_session) {
-    /* ignore UDP traffic as long as we have a connection */
-    return;
+  switch (interf->udp_mode) {
+    case DLEP_IF_UDP_NONE:
+      return;
+    case DLEP_IF_UDP_SINGLE_SESSION:
+      if(interf->session_tree.count > 0) {
+        return;
+      }
+      break;
+    default:
+      break;
   }
 
   if (length < sizeof(_DLEP_PREFIX) - 1) {
@@ -263,9 +272,16 @@ _cb_send_multicast(struct dlep_session *session, int af_family) {
   /* get pointer to radio interface */
   interf = container_of(session, struct dlep_if, session);
 
-  if (interf->session_tree.count > 0 && interf->single_session) {
-    /* do not produce UDP traffic as long as we are connected */
-    return;
+  switch (interf->udp_mode) {
+    case DLEP_IF_UDP_NONE:
+      return;
+    case DLEP_IF_UDP_SINGLE_SESSION:
+      if(interf->session_tree.count > 0) {
+        return;
+      }
+      break;
+    default:
+      break;
   }
 
   OONF_DEBUG(
index 6b116d4..f8a9b57 100644 (file)
 #include "core/oonf_logging.h"
 #include "subsystems/oonf_packet_socket.h"
 
+#define DLEP_IF_UDP_NONE_STR           "none"
+#define DLEP_IF_UDP_SINGLE_SESSION_STR "single_session"
+#define DLEP_IF_UDP_ALWAYS_STR         "always"
+
+enum dlep_if_udp_mode{
+  /* never handle UDP */
+  DLEP_IF_UDP_NONE,
+
+  /* just use UDP if no session is active */
+  DLEP_IF_UDP_SINGLE_SESSION,
+
+  /* always handle UDP */
+  DLEP_IF_UDP_ALWAYS,
+};
+
 /**
  * Interface that is used for one or multiple dlep sessions
  */
@@ -70,8 +85,8 @@ struct dlep_if {
   /*! dynamic buffer for UDP output */
   struct autobuf udp_out;
 
-  /*! true if radio should only accept a single session */
-  bool single_session;
+  /*! decides when/if UDP should be sent/processed */
+  enum dlep_if_udp_mode udp_mode;
 
   /*! true if this interface is used for DLEP radio */
   bool radio;
@@ -85,7 +100,8 @@ struct dlep_if {
 
 struct avl_tree *dlep_if_get_tree(bool radio);
 int dlep_if_add(struct dlep_if *interf, const char *ifname, const struct oonf_layer2_origin *l2_origin,
-  const struct oonf_layer2_origin *l2_default_origin, enum oonf_log_source log_src, bool radio);
+  const struct oonf_layer2_origin *l2_default_origin,
+  int (*if_changed)(struct os_interface_listener *), enum oonf_log_source log_src, bool radio);
 void dlep_if_remove(struct dlep_if *interface);
 
 #endif /* DLEP_INTERFACE_H_ */
index 8d3a2c4..16d7fad 100644 (file)
@@ -114,13 +114,14 @@ dlep_session_init(void) {
  * @param out output buffer for session
  * @param radio true if this is a radio session,
  *   false for a router session
+ * @param if_changed interface listener for session, can be NULL
  * @param log_source logging source for session
  * @return -1 if an error happened, 0 otherwise
  */
 int
 dlep_session_add(struct dlep_session *session, const char *l2_ifname, const struct oonf_layer2_origin *l2_origin,
   const struct oonf_layer2_origin *l2_default_origin, struct autobuf *out, bool radio,
-  enum oonf_log_source log_source) {
+  int (*if_changed)(struct os_interface_listener *), enum oonf_log_source log_source) {
   struct dlep_session_parser *parser;
   struct dlep_extension *ext;
   int32_t i;
@@ -135,9 +136,11 @@ dlep_session_add(struct dlep_session *session, const char *l2_ifname, const stru
   session->l2_default_origin = l2_default_origin;
   session->radio = radio;
   session->writer.out = out;
+  session->_peer_state = DLEP_PEER_WAIT_FOR_INIT;
 
   /* remember interface name */
   session->l2_listener.name = l2_ifname;
+  session->l2_listener.if_changed = if_changed;
 
   /* get interface listener to lock interface */
   if (!os_interface_add(&session->l2_listener)) {
@@ -214,6 +217,8 @@ dlep_session_remove(struct dlep_session *session) {
 
   free(parser->values);
   parser->values = NULL;
+
+  session->_peer_state = DLEP_PEER_NOT_CONNECTED;
 }
 
 /**
index b837b26..6f6d50f 100644 (file)
@@ -258,6 +258,7 @@ struct dlep_session_config {
  */
 enum dlep_peer_state
 {
+  DLEP_PEER_NOT_CONNECTED,
   DLEP_PEER_WAIT_FOR_INIT,
   DLEP_PEER_WAIT_FOR_UPDATE_ACK,
   DLEP_PEER_SEND_UPDATE,
@@ -336,7 +337,8 @@ struct dlep_session {
 void dlep_session_init(void);
 
 int dlep_session_add(struct dlep_session *session, const char *l2_ifname, const struct oonf_layer2_origin *l2_origin,
-  const struct oonf_layer2_origin *l2_default_origin, struct autobuf *out, bool radio, enum oonf_log_source);
+  const struct oonf_layer2_origin *l2_default_origin, struct autobuf *out, bool radio,
+  int (*if_changed)(struct os_interface_listener *), enum oonf_log_source);
 void dlep_session_remove(struct dlep_session *session);
 void dlep_session_terminate(struct dlep_session *session);
 
index 0f213a8..ebad508 100644 (file)
@@ -74,6 +74,12 @@ static void _initiate_shutdown(void);
 static void _cb_config_changed(void);
 
 /* configuration */
+static const char *_UDP_MODE[] = {
+  [DLEP_IF_UDP_NONE] = DLEP_IF_UDP_NONE_STR,
+  [DLEP_IF_UDP_SINGLE_SESSION] = DLEP_IF_UDP_SINGLE_SESSION_STR,
+  [DLEP_IF_UDP_ALWAYS] = DLEP_IF_UDP_ALWAYS_STR,
+};
+
 static struct cfg_schema_entry _radio_entries[] = {
   CFG_MAP_STRING_ARRAY(dlep_radio_if, interf.udp_config.interface, "datapath_if", "",
     "Name of interface to talk to dlep router (default is section name)", IF_NAMESIZE),
@@ -97,7 +103,10 @@ static struct cfg_schema_entry _radio_entries[] = {
   CFG_MAP_CLOCK_MINMAX(dlep_radio_if, interf.session.cfg.heartbeat_interval, "heartbeat_interval", "1.000",
     "Interval in seconds between two heartbeat signals", 1000, 65535 * 1000),
 
-  CFG_MAP_BOOL(dlep_radio_if, interf.single_session, "single_session", "true", "Connect only to a single router"),
+  CFG_MAP_CHOICE(dlep_radio_if, interf.udp_mode, "udp_mode", DLEP_IF_UDP_SINGLE_SESSION_STR,
+    "Determines the UDP behavior of the radio. 'none' never sends/processes UDP, 'single_session' only does"
+    " if no DLEP session is active and 'always' always sends/processes UDP and allows multiple sessions",
+    _UDP_MODE),
 
   CFG_MAP_BOOL(dlep_radio_if, interf.session.cfg.send_proxied, "proxied", "true",
     "Report 802.11s proxied mac address for neighbors"),
index b19d0ac..0886274 100644 (file)
@@ -180,7 +180,7 @@ dlep_radio_add_interface(const char *ifname) {
     return NULL;
   }
 
-  if (dlep_if_add(&interface->interf, ifname, &_l2_origin, &_l2_default_origin, LOG_DLEP_RADIO, true)) {
+  if (dlep_if_add(&interface->interf, ifname, &_l2_origin, &_l2_default_origin, NULL, LOG_DLEP_RADIO, true)) {
     oonf_class_free(&_interface_class, interface);
     return NULL;
   }
index 1bde0a0..9fd551a 100644 (file)
@@ -128,7 +128,7 @@ _cb_incoming_tcp(struct oonf_stream_session *tcp_session) {
 
   /* activate session */
   if (dlep_session_add(&radio_session->session, interface->interf.l2_ifname, interface->interf.session.l2_origin,
-        interface->interf.session.l2_default_origin, &tcp_session->out, true, LOG_DLEP_RADIO)) {
+        interface->interf.session.l2_default_origin, &tcp_session->out, true, NULL, LOG_DLEP_RADIO)) {
     return -1;
   }
   radio_session->session.restrict_signal = DLEP_SESSION_INITIALIZATION;
index 6a1f51d..fa864cf 100644 (file)
@@ -73,6 +73,12 @@ static void _cleanup(void);
 static void _cb_config_changed(void);
 
 /* configuration */
+static const char *_UDP_MODE[] = {
+  [DLEP_IF_UDP_NONE] = DLEP_IF_UDP_NONE_STR,
+  [DLEP_IF_UDP_SINGLE_SESSION] = DLEP_IF_UDP_SINGLE_SESSION_STR,
+  [DLEP_IF_UDP_ALWAYS] = DLEP_IF_UDP_ALWAYS_STR,
+};
+
 static struct cfg_schema_entry _router_entries[] = {
   CFG_MAP_STRING(dlep_router_if, interf.session.cfg.peer_type, "peer_type", "OONF DLEP Router",
     "Identification string of DLEP router endpoint"),
@@ -92,8 +98,10 @@ static struct cfg_schema_entry _router_entries[] = {
   CFG_MAP_CLOCK_MINMAX(dlep_router_if, interf.session.cfg.heartbeat_interval, "heartbeat_interval", "1.000",
     "Interval in seconds between two heartbeat signals", 1000, 65535000),
 
-  CFG_MAP_BOOL(dlep_router_if, interf.single_session, "single_session", "true",
-    "Restrict DLEP router to single session per interface"),
+  CFG_MAP_CHOICE(dlep_router_if, interf.udp_mode, "udp_mode", DLEP_IF_UDP_SINGLE_SESSION_STR,
+    "Determines the UDP behavior of the router. 'none' never sends/processes UDP, 'single_session' only does"
+    " if no DLEP session is active and 'always' always sends/processes UDP and allows multiple sessions",
+    _UDP_MODE),
 
   CFG_MAP_STRING_ARRAY(dlep_router_if, interf.udp_config.interface, "datapath_if", "",
     "Overwrite datapath interface for incoming dlep traffic, used for"
index 9f3d9bb..236cb81 100644 (file)
@@ -55,6 +55,7 @@
 #include "subsystems/oonf_layer2.h"
 #include "subsystems/oonf_packet_socket.h"
 #include "subsystems/oonf_timer.h"
+#include "subsystems/os_interface.h"
 
 #include "dlep/dlep_extension.h"
 #include "dlep/dlep_iana.h"
 #include "dlep/router/dlep_router_internal.h"
 #include "dlep/router/dlep_router_session.h"
 
+static void _connect_to_setup(struct dlep_router_if *router_if);
+static void _check_connect_to(struct dlep_router_if *router_if);
 static void _cleanup_interface(struct dlep_router_if *interface);
+static int _connect_to_if_changed(struct os_interface_listener *);
+static void _cb_check_connect_to_status(struct oonf_timer_instance *);
 
 static struct oonf_class _router_if_class = {
   .name = "DLEP router interface",
@@ -95,6 +100,11 @@ static struct oonf_layer2_origin _l2_default_origin = {
   .priority = OONF_LAYER2_ORIGIN_UNRELIABLE,
 };
 
+static struct oonf_timer_class _connect_to_watchdog_class = {
+  .name = "connect_to watchdog",
+  .callback = _cb_check_connect_to_status,
+};
+
 /**
  * Initialize dlep router interface framework. This will also
  * initialize the dlep router session framework.
@@ -116,6 +126,7 @@ dlep_router_interface_init(void) {
   _shutting_down = false;
 
   oonf_layer2_origin_add(&_l2_origin);
+  oonf_timer_add(&_connect_to_watchdog_class);
 }
 
 /**
@@ -136,6 +147,7 @@ dlep_router_interface_cleanup(void) {
   dlep_router_session_cleanup();
   dlep_extension_cleanup();
   oonf_layer2_origin_remove(&_l2_origin);
+  oonf_timer_remove(&_connect_to_watchdog_class);
 }
 
 /**
@@ -187,11 +199,14 @@ dlep_router_add_interface(const char *ifname) {
     return NULL;
   }
 
-  if (dlep_if_add(&interface->interf, ifname, &_l2_origin, &_l2_default_origin, LOG_DLEP_ROUTER, false)) {
+  if (dlep_if_add(&interface->interf, ifname, &_l2_origin, &_l2_default_origin, _connect_to_if_changed, LOG_DLEP_ROUTER, false)) {
     oonf_class_free(&_router_if_class, interface);
     return NULL;
   }
 
+  /* prepare timer */
+  interface->_connect_to_watchdog.class = &_connect_to_watchdog_class;
+
   OONF_DEBUG(LOG_DLEP_ROUTER, "Add session %s", ifname);
   return interface;
 }
@@ -221,31 +236,16 @@ dlep_router_remove_interface(struct dlep_router_if *interface) {
 void
 dlep_router_apply_interface_settings(struct dlep_router_if *interf) {
   struct dlep_extension *ext;
-  struct os_interface *os_if;
-  const struct os_interface_ip *result;
-  union netaddr_socket local, remote;
-#ifdef OONF_LOG_DEBUG_INFO
-  struct netaddr_str nbuf;
-#endif
 
   oonf_packet_apply_managed(&interf->interf.udp, &interf->interf.udp_config);
 
   _cleanup_interface(interf);
 
   if (!netaddr_is_unspec(&interf->connect_to_addr)) {
-    os_if = interf->interf.session.l2_listener.data;
-
-    OONF_DEBUG(LOG_DLEP_ROUTER, "Connect directly to [%s]:%d", netaddr_to_string(&nbuf, &interf->connect_to_addr),
-      interf->connect_to_port);
-
-    result = os_interface_get_prefix_from_dst(&interf->connect_to_addr, os_if);
-    if (result) {
-      /* initialize local and remote socket */
-      netaddr_socket_init(&local, &result->address, 0, os_if->index);
-      netaddr_socket_init(&remote, &interf->connect_to_addr, interf->connect_to_port, os_if->index);
-
-      dlep_router_add_session(interf, &local, &remote);
-    }
+    _connect_to_setup(interf);
+  }
+  else {
+    oonf_timer_stop(&interf->_connect_to_watchdog);
   }
 
   avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
@@ -273,6 +273,37 @@ dlep_router_terminate_all_sessions(void) {
 }
 
 /**
+* open a direct TCP connection for this interface
+* @param router_if router interface
+*/
+static void
+_connect_to_setup(struct dlep_router_if *router_if) {
+  struct os_interface *os_if;
+  const struct os_interface_ip *result;
+  union netaddr_socket local;
+#ifdef OONF_LOG_DEBUG_INFO
+  struct netaddr_str nbuf;
+#endif
+
+  os_if = router_if->interf.session.l2_listener.data;
+
+  OONF_DEBUG(LOG_DLEP_ROUTER, "Connect directly to [%s]:%d", netaddr_to_string(&nbuf, &router_if->connect_to_addr),
+      router_if->connect_to_port);
+
+  /* start watchdog */
+  oonf_timer_set(&router_if->_connect_to_watchdog, 1000);
+
+  result = os_interface_get_prefix_from_dst(&router_if->connect_to_addr, os_if);
+  if (result) {
+    /* initialize local and remote socket */
+    netaddr_socket_init(&local, &result->address, 0, os_if->index);
+    netaddr_socket_init(&router_if->connect_to, &router_if->connect_to_addr, router_if->connect_to_port, os_if->index);
+
+    dlep_router_add_session(router_if, &local, &router_if->connect_to);
+  }
+}
+
+/**
  * Close all existing dlep sessions of a dlep interface
  * @param interface dlep router interface
  */
@@ -285,3 +316,56 @@ _cleanup_interface(struct dlep_router_if *interface) {
     dlep_router_remove_session(stream);
   }
 }
+
+/**
+ * check if connect_to session is up and running. If not, restart it.
+ * @param router_if router interface
+ */
+static void
+_check_connect_to(struct dlep_router_if *router_if) {
+  struct dlep_router_session *connect_to_session;
+
+  if (netaddr_is_unspec(&router_if->connect_to_addr)) {
+    /* do not connect */
+    return;
+  }
+
+  connect_to_session = dlep_router_get_session(router_if, &router_if->connect_to);
+  if (connect_to_session->session._peer_state == DLEP_PEER_NOT_CONNECTED
+    || connect_to_session->session._peer_state == DLEP_PEER_TERMINATED) {
+    /* cleanup not working session */
+    dlep_router_remove_session(connect_to_session);
+    connect_to_session = NULL;
+  }
+
+  if (!connect_to_session) {
+    _connect_to_setup(router_if);
+  }
+  return;
+}
+
+/**
+* Interface listener to (re-)establish connect_to session if it failed.
+* @param interf interface listener that triggered
+* @return always 0
+*/
+static int
+_connect_to_if_changed(struct os_interface_listener *interf) {
+  struct dlep_router_if *router_if;
+
+  router_if = container_of(interf, struct dlep_router_if, interf.session.l2_listener);
+  _check_connect_to(router_if);
+  return 0;
+}
+
+/**
+ * Timer callback to watch connect_to session status
+ * @param instance watchdog timer instance
+ */
+static void
+_cb_check_connect_to_status(struct oonf_timer_instance *instance) {
+  struct dlep_router_if *router_if;
+
+  router_if = container_of(instance, struct dlep_router_if, _connect_to_watchdog);
+  _check_connect_to(router_if);
+}
index c654110..fd479c6 100644 (file)
@@ -48,6 +48,7 @@
 
 #include "common/common_types.h"
 #include "common/netaddr.h"
+#include "subsystems/oonf_timer.h"
 
 #include "dlep/dlep_interface.h"
 #include "dlep/dlep_session.h"
@@ -59,11 +60,17 @@ struct dlep_router_if {
   /*! generic DLEP interface */
   struct dlep_if interf;
 
+  /* combined address/port we are directly connected to */
+  union netaddr_socket connect_to;
+
   /*! IP address to directly connect router to */
   struct netaddr connect_to_addr;
 
   /*! TCP port to directly connect router to */
   int32_t connect_to_port;
+
+  /* timer to make sure we stay connected */
+  struct oonf_timer_instance _connect_to_watchdog;
 };
 
 void dlep_router_interface_init(void);
index ff68a66..b6d4f01 100644 (file)
@@ -165,7 +165,7 @@ dlep_router_add_session(struct dlep_router_if *interf, union netaddr_socket *loc
   }
 
   if (dlep_session_add(&router_session->session, interf->interf.l2_ifname, interf->interf.session.l2_origin,
-        interf->interf.session.l2_default_origin, &router_session->stream->out, false, LOG_DLEP_ROUTER)) {
+        interf->interf.session.l2_default_origin, &router_session->stream->out, false, NULL, LOG_DLEP_ROUTER)) {
     dlep_router_remove_session(router_session);
     return NULL;
   }
index 9d2c7a8..3344f07 100644 (file)
@@ -51,6 +51,7 @@
 #include "common/netaddr.h"
 #include "subsystems/oonf_stream_socket.h"
 #include "subsystems/oonf_timer.h"
+#include "subsystems/os_interface.h"
 
 #include "dlep/router/dlep_router_interface.h"
 
@@ -93,8 +94,8 @@ void dlep_router_session_init(void);
 void dlep_router_session_cleanup(void);
 
 struct dlep_router_session *dlep_router_get_session(struct dlep_router_if *interf, union netaddr_socket *remote);
-struct dlep_router_session *dlep_router_add_session(
-  struct dlep_router_if *interf, union netaddr_socket *local, union netaddr_socket *remote);
+struct dlep_router_session *dlep_router_add_session(struct dlep_router_if *interf,
+    union netaddr_socket *local, union netaddr_socket *remote);
 void dlep_router_remove_session(struct dlep_router_session *);
 
 #endif /* DLEP_ROUTER_SESSION_H_ */