Fix the handling of neighbor IPs in dlep radio.
authorHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Wed, 16 May 2018 12:26:29 +0000 (14:26 +0200)
committerHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Wed, 16 May 2018 12:26:29 +0000 (14:26 +0200)
src/generic/dlep/dlep_session.c
src/generic/dlep/ext_base_ip/ip.c
src/generic/dlep/ext_base_proto/proto_radio.c
src/generic/layer2_import/layer2_import.c
src/libcommon/netaddr.c

index 87f898b..044dfa5 100644 (file)
@@ -128,7 +128,7 @@ dlep_session_add(struct dlep_session *session, const char *l2_ifname, const stru
   parser = &session->parser;
 
   avl_init(&parser->allowed_tlvs, avl_comp_uint16, false);
-  avl_init(&session->local_neighbor_tree, avl_comp_netaddr, false);
+  avl_init(&session->local_neighbor_tree, oonf_layer2_avlcmp_neigh_key, false);
 
   session->log_source = log_source;
   session->l2_origin = l2_origin;
@@ -578,9 +578,9 @@ _generate_signal(struct dlep_session *session, int32_t signal, const struct oonf
   struct netaddr_str nbuf2;
 #endif
 
-  OONF_DEBUG(session->log_source, "Generate signal %u for %s on %s (%s)", signal,
+  OONF_DEBUG(session->log_source, "Generate signal %u for %s on %s (0x%zx %s)", signal,
              oonf_layer2_neigh_key_to_string(&nkbuf, neighbor, true),
-             session->l2_listener.name, netaddr_socket_to_string(&nbuf2, &session->remote_socket));
+             session->l2_listener.name, (size_t)session, netaddr_socket_to_string(&nbuf2, &session->remote_socket));
 
   len = abuf_getlen(session->writer.out);
 
index 330a854..1d2c0ae 100644 (file)
@@ -62,8 +62,6 @@
 struct _prefix_storage {
   struct netaddr prefix;
 
-  bool add;
-
   struct avl_node _node;
 };
 
@@ -76,12 +74,7 @@ static int _radio_write_destination_update(
 static enum dlep_parser_error _router_process_session_update(struct dlep_extension *ext, struct dlep_session *session);
 static enum dlep_parser_error _router_process_destination_update(
   struct dlep_extension *ext, struct dlep_session *session);
-static void _add_prefix(struct avl_tree *tree, struct netaddr *addr, bool add);
-
-static void _cb_add_if_ip(void *ptr);
-static void _cb_remove_if_ip(void *ptr);
-static void _cb_add_neigh_ip(void *ptr);
-static void _cb_remove_neigh_ip(void *ptr);
+static void _add_prefix(struct avl_tree *tree, struct netaddr *addr);
 
 /* peer initialization ack/peer update/destination update */
 static const uint16_t _ip_tlvs[] = {
@@ -169,22 +162,6 @@ static struct oonf_class _prefix_class = {
   .size = sizeof(struct _prefix_storage),
 };
 
-static struct oonf_class_extension _l2_interface_ip_listener = {
-  .ext_name = "dlep l2 if-ip",
-  .class_name = LAYER2_CLASS_NETWORK_ADDRESS,
-
-  .cb_add = _cb_add_if_ip,
-  .cb_remove = _cb_remove_if_ip,
-};
-
-static struct oonf_class_extension _l2_neighbor_ip_listener = {
-  .ext_name = "dlep l2 neigh-ip",
-  .class_name = LAYER2_CLASS_NEIGHBOR_ADDRESS,
-
-  .cb_add = _cb_add_neigh_ip,
-  .cb_remove = _cb_remove_neigh_ip,
-};
-
 /**
  * Initialize the base metric DLEP extension
  * @return this extension
@@ -193,44 +170,17 @@ struct dlep_extension *
 dlep_base_ip_init(void) {
   dlep_extension_add(&_base_ip);
   oonf_class_add(&_prefix_class);
-  oonf_class_extension_add(&_l2_interface_ip_listener);
-  oonf_class_extension_add(&_l2_neighbor_ip_listener);
 
   return &_base_ip;
 }
 
 void
 dlep_base_ip_cleanup(void) {
-  oonf_class_extension_remove(&_l2_neighbor_ip_listener);
-  oonf_class_extension_remove(&_l2_interface_ip_listener);
   oonf_class_remove(&_prefix_class);
 }
 
 static void
-_cb_session_init(struct dlep_session *session) {
-  struct oonf_layer2_neighbor_address *l2neigh_ip;
-  struct oonf_layer2_neigh *l2neigh;
-  struct oonf_layer2_peer_address *l2net_ip;
-  struct oonf_layer2_net *l2net;
-  struct dlep_local_neighbor *dlep_neighbor;
-
-  l2net = oonf_layer2_net_get(session->l2_listener.name);
-  if (!l2net) {
-    return;
-  }
-
-  avl_for_each_element(&l2net->local_peer_ips, l2net_ip, _net_node) {
-    _add_prefix(&session->_ext_ip.prefix_modification, &l2net_ip->ip, true);
-  }
-
-  avl_for_each_element(&l2net->neighbors, l2neigh, _node) {
-    dlep_neighbor = dlep_session_add_local_neighbor(session, &l2neigh->key);
-    if (dlep_neighbor) {
-      avl_for_each_element(&l2neigh->remote_neighbor_ips, l2neigh_ip, _neigh_node) {
-        _add_prefix(&dlep_neighbor->_ip_prefix_modification, &l2neigh_ip->ip, true);
-      }
-    }
-  }
+_cb_session_init(struct dlep_session *session __attribute__((unused))) {
 }
 
 static void
@@ -278,18 +228,53 @@ _radio_write_session_update(struct dlep_extension *ext __attribute__((unused)),
   const struct oonf_layer2_neigh_key *neigh __attribute__((unused))) {
   struct _prefix_storage *storage, *storage_it;
   struct dlep_radio_session *radio_session;
+  struct oonf_layer2_peer_address *peer_ip;
+  struct oonf_layer2_net *l2net;
   struct os_interface *os_if;
   struct netaddr_str nbuf;
 
-  /* transmit modified IP network prefixes */
-  avl_for_each_element(&session->_ext_ip.prefix_modification, storage, _node) {
-    OONF_INFO(session->log_source, "Add '%s' (%s) to session update", netaddr_to_string(&nbuf, &storage->prefix),
-      storage->add ? "add" : "remove");
-    if (dlep_writer_add_ip_tlv(&session->writer, &storage->prefix, storage->add)) {
-      OONF_WARN(session->log_source, "Cannot add '%s' (%s) to session update",
-        netaddr_to_string(&nbuf, &storage->prefix), storage->add ? "add" : "remove");
+  /* first make sure defaults are set correctly */
+  l2net = oonf_layer2_net_get(session->l2_listener.name);
+
+  /* announce newly added interface prefixes */
+  if (l2net) {
+    avl_for_each_element(&l2net->local_peer_ips, peer_ip, _net_node) {
+      if (avl_find(&session->_ext_ip.prefix_modification, &peer_ip->ip)) {
+        /* prefix already known to session */
+        continue;
+      }
+
+      OONF_INFO(session->log_source, "New prefix '%s' for session update",
+                netaddr_to_string(&nbuf, &peer_ip->ip));
+
+      if (dlep_writer_add_ip_tlv(&session->writer, &peer_ip->ip, true)) {
+        OONF_WARN(session->log_source, "Cannot add TLV for '%s' to session update",
+          netaddr_to_string(&nbuf, &peer_ip->ip));
+        return -1;
+      }
+
+      _add_prefix(&session->_ext_ip.prefix_modification, &peer_ip->ip);
+    }
+  }
+
+  /* remove missing interface prefixes */
+  avl_for_each_element_safe(&session->_ext_ip.prefix_modification, storage, _node, storage_it) {
+    if (l2net && avl_find(&l2net->local_peer_ips, &storage->prefix)) {
+      /* prefix is still on interface */
+      continue;
+    }
+
+    OONF_INFO(session->log_source, "Removed prefix '%s' for session update",
+              netaddr_to_string(&nbuf, &storage->prefix));
+
+    if (dlep_writer_add_ip_tlv(&session->writer, &storage->prefix, false)) {
+      OONF_WARN(session->log_source, "Cannot add TLV for '%s' to session update",
+        netaddr_to_string(&nbuf, &storage->prefix));
       return -1;
     }
+
+    avl_remove(&session->_ext_ip.prefix_modification, &storage->_node);
+    oonf_class_free(&_prefix_class, storage);
   }
 
   /* also transmit IP interface addresses */
@@ -299,12 +284,6 @@ _radio_write_session_update(struct dlep_extension *ext __attribute__((unused)),
     _handle_if_ip(session, &session->_ext_ip.if_ip_v4, os_if->if_linklocal_v4, os_if->if_v4);
     _handle_if_ip(session, &session->_ext_ip.if_ip_v6, os_if->if_linklocal_v6, os_if->if_v6);
   }
-
-  /* no error, now remove elements from temporary storage */
-  avl_for_each_element_safe(&session->_ext_ip.prefix_modification, storage, _node, storage_it) {
-    avl_remove(&session->_ext_ip.prefix_modification, &storage->_node);
-    oonf_class_free(&_prefix_class, storage);
-  }
   return 0;
 }
 
@@ -312,6 +291,9 @@ static int
 _radio_write_destination_update(struct dlep_extension *ext __attribute__((unused)), struct dlep_session *session,
     const struct oonf_layer2_neigh_key *neigh) {
   struct dlep_local_neighbor *dlep_neigh;
+  struct oonf_layer2_neigh *l2neigh;
+  struct oonf_layer2_neighbor_address *l2neigh_ip;
+
   struct _prefix_storage *storage, *storage_it;
 
   union oonf_layer2_neigh_key_str nkbuf;
@@ -325,21 +307,51 @@ _radio_write_destination_update(struct dlep_extension *ext __attribute__((unused
     return -1;
   }
 
+  l2neigh = dlep_session_get_l2_from_neighbor(dlep_neigh);
+
   /* send every attached IP towards the router */
-  avl_for_each_element(&dlep_neigh->_ip_prefix_modification, storage, _node) {
-    OONF_INFO(session->log_source, "add '%s' (%s) to destination update %s",
-      netaddr_to_string(&nbuf1, &storage->prefix), storage->add ? "add" : "remove",
-      oonf_layer2_neigh_key_to_string(&nkbuf, neigh, true));
-    if (dlep_writer_add_ip_tlv(&session->writer, &storage->prefix, storage->add)) {
-      OONF_WARN(session->log_source, "Cannot add '%s' (%s) to destination update %s",
-        netaddr_to_string(&nbuf1, &storage->prefix), storage->add ? "add" : "remove",
-        oonf_layer2_neigh_key_to_string(&nkbuf, neigh, true));
-      return -1;
+//  avl_for_each_element(&dlep_neigh->_ip_prefix_modification, storage, _node) {
+  /* announce newly added interface prefixes */
+  if (l2neigh) {
+    avl_for_each_element(&l2neigh->remote_neighbor_ips, l2neigh_ip, _neigh_node) {
+      if (avl_find(&dlep_neigh->_ip_prefix_modification, &l2neigh_ip->ip)) {
+        /* prefix already known to neighbor */
+        continue;
+      }
+
+      OONF_INFO(session->log_source, "New prefix '%s' for neighbor %s update",
+                netaddr_to_string(&nbuf1, &l2neigh_ip->ip),
+                oonf_layer2_neigh_key_to_string(&nkbuf, neigh, true)
+               );
+
+      if (dlep_writer_add_ip_tlv(&session->writer, &l2neigh_ip->ip, true)) {
+        OONF_WARN(session->log_source, "Cannot add TLV for '%s' to neighbor update",
+          netaddr_to_string(&nbuf1, &l2neigh_ip->ip));
+        return -1;
+      }
+
+      _add_prefix(&dlep_neigh->_ip_prefix_modification, &l2neigh_ip->ip);
     }
   }
 
-  /* no error, now remove elements from temporary storage */
+  /* remove missing interface prefixes */
   avl_for_each_element_safe(&dlep_neigh->_ip_prefix_modification, storage, _node, storage_it) {
+    if (l2neigh && avl_find(&l2neigh->remote_neighbor_ips, &storage->prefix)) {
+      /* prefix is still on neighbor */
+      continue;
+    }
+
+    OONF_INFO(session->log_source, "Removed prefix '%s' for neighbor %s update",
+              netaddr_to_string(&nbuf1, &storage->prefix),
+              oonf_layer2_neigh_key_to_string(&nkbuf, neigh, true)
+             );
+
+    if (dlep_writer_add_ip_tlv(&session->writer, &storage->prefix, false)) {
+      OONF_WARN(session->log_source, "Cannot add TLV for '%s' to neighbor update",
+        netaddr_to_string(&nbuf1, &storage->prefix));
+      return -1;
+    }
+
     avl_remove(&dlep_neigh->_ip_prefix_modification, &storage->_node);
     oonf_class_free(&_prefix_class, storage);
   }
@@ -493,12 +505,11 @@ _router_process_destination_update(struct dlep_extension *ext __attribute((unuse
 }
 
 static void
-_add_prefix(struct avl_tree *tree, struct netaddr *addr, bool add) {
+_add_prefix(struct avl_tree *tree, struct netaddr *addr) {
   struct _prefix_storage *storage;
 
   storage = avl_find_element(tree, addr, storage, _node);
   if (storage) {
-    storage->add = add;
     return;
   }
 
@@ -511,62 +522,4 @@ _add_prefix(struct avl_tree *tree, struct netaddr *addr, bool add) {
   memcpy(&storage->prefix, addr, sizeof(*addr));
   storage->_node.key = &storage->prefix;
   avl_insert(tree, &storage->_node);
-
-  storage->add = add;
-}
-
-static void
-_modify_if_ip(const char *if_name, struct netaddr *prefix, bool add) {
-  struct dlep_radio_if *interf;
-  struct dlep_radio_session *radio_session;
-
-  avl_for_each_element(dlep_if_get_tree(true), interf, interf._node) {
-    if (strcmp(interf->interf.l2_ifname, if_name) == 0) {
-      avl_for_each_element(&interf->interf.session_tree, radio_session, _node) {
-        _add_prefix(&radio_session->session._ext_ip.prefix_modification, prefix, add);
-      }
-    }
-  }
-}
-
-static void
-_cb_add_if_ip(void *ptr) {
-  struct oonf_layer2_peer_address *peer_ip = ptr;
-  _modify_if_ip(peer_ip->l2net->name, &peer_ip->ip, true);
-}
-
-static void
-_cb_remove_if_ip(void *ptr) {
-  struct oonf_layer2_peer_address *peer_ip = ptr;
-  _modify_if_ip(peer_ip->l2net->name, &peer_ip->ip, false);
-}
-
-static void
-_modify_neigh_ip(const char *if_name, struct oonf_layer2_neigh_key *neighbor, struct netaddr *prefix, bool add) {
-  struct dlep_radio_if *radio_interf;
-  struct dlep_local_neighbor *dlep_neighbor;
-  struct dlep_radio_session *radio_session;
-
-  avl_for_each_element(dlep_if_get_tree(true), radio_interf, interf._node) {
-    if (strcmp(radio_interf->interf.l2_ifname, if_name) == 0) {
-      avl_for_each_element(&radio_interf->interf.session_tree, radio_session, _node) {
-        dlep_neighbor = dlep_session_add_local_neighbor(&radio_session->session, neighbor);
-        if (dlep_neighbor) {
-          _add_prefix(&dlep_neighbor->_ip_prefix_modification, prefix, add);
-        }
-      }
-    }
-  }
-}
-
-static void
-_cb_add_neigh_ip(void *ptr) {
-  struct oonf_layer2_neighbor_address *neigh_ip = ptr;
-  _modify_neigh_ip(neigh_ip->l2neigh->network->name, &neigh_ip->l2neigh->key, &neigh_ip->ip, true);
-}
-
-static void
-_cb_remove_neigh_ip(void *ptr) {
-  struct oonf_layer2_neighbor_address *neigh_ip = ptr;
-  _modify_neigh_ip(neigh_ip->l2neigh->network->name, &neigh_ip->l2neigh->key, &neigh_ip->ip, false);
 }
index 6a83a1d..e9d8644 100644 (file)
@@ -542,7 +542,7 @@ _l2_neigh_added(struct oonf_layer2_neigh *l2neigh, struct oonf_layer2_destinatio
     if (!l2dest && !radio_session->session.cfg.send_neighbors) {
       continue;
     }
-    _l2_neigh_added_to_session(&radio_if->interf.session, l2neigh, mac);
+    _l2_neigh_added_to_session(&radio_session->session, l2neigh, mac);
   }
 }
 
@@ -550,7 +550,7 @@ _l2_neigh_added(struct oonf_layer2_neigh *l2neigh, struct oonf_layer2_destinatio
  * Helper function triggered when a layer2 neighbor changed
  * @param l2neigh layer2 neighbor
  * @param l2dest layer2 destination (might be NULL)
- * @param mac MAC address of other endpoint
+ * @param mac MAC address of other endpoint (can be the key from neighbor or destination)
  */
 static void
 _l2_neigh_changed(
@@ -575,7 +575,7 @@ _l2_neigh_changed(
     local = dlep_session_add_local_neighbor(&radio_session->session, mac);
 
     if (local) {
-      memcpy(&local->neigh_key, &l2neigh->key, sizeof(local->neigh_key));
+      memcpy(&local->neigh_key, mac, sizeof(*mac));
 
       switch (local->state) {
         case DLEP_NEIGHBOR_UP_SENT:
@@ -630,13 +630,14 @@ _l2_neigh_removed(
     if (!local) {
       continue;
     }
-
+/*
     if ((l2dest && memcmp(&l2neigh->key, &local->neigh_key, sizeof(l2neigh->key)) == 0) ||
         (!l2dest && netaddr_is_unspec(&local->neigh_key.addr))) {
+*/
       dlep_session_generate_signal(&radio_session->session, DLEP_DESTINATION_DOWN, mac);
       local->state = DLEP_NEIGHBOR_DOWN_SENT;
       oonf_timer_set(&local->_ack_timeout, radio_session->session.cfg.heartbeat_interval * 2);
-    }
+//    }
   }
 }
 
index 48d4053..f369ac0 100644 (file)
@@ -307,6 +307,30 @@ _cb_query(struct os_route *filter __attribute__((unused)), struct os_route *rout
 static void
 _cb_query_finished(struct os_route *route __attribute__((unused)), int error __attribute__((unused))) {}
 
+static struct oonf_layer2_neighbor_address *
+_remove_old_entries(struct oonf_layer2_net *l2net, struct _import_entry *import,
+                    const struct netaddr *route_gw, const struct netaddr *route_dst) {
+  struct oonf_layer2_neighbor_address *match, *l2n_it1, *l2n_start, *l2n_it2;
+  const struct netaddr *gw;
+  struct netaddr_str nbuf;
+
+  match = NULL;
+  OONF_DEBUG(LOG_L2_IMPORT, "route-DST: %s", netaddr_to_string(&nbuf, route_dst));
+  avl_for_each_elements_with_key_safe(&l2net->remote_neighbor_ips, l2n_it1, _net_node, l2n_start, l2n_it2, route_dst) {
+    OONF_DEBUG(LOG_L2_IMPORT, "l2n-remote: %s", netaddr_to_string(&nbuf, &l2n_it1->ip));
+    if (l2n_it1->origin == &import->l2origin) {
+      gw = oonf_layer2_neigh_get_nexthop(l2n_it1->l2neigh, netaddr_get_address_family(route_dst));
+      if (netaddr_cmp(gw, route_gw) == 0) {
+        match = l2n_it1;
+      }
+      else {
+        oonf_layer2_neigh_remove_ip(l2n_it1, &import->l2origin);
+      }
+    }
+  }
+  return match;
+}
+
 /**
  * Callback for route listener
  * @param route routing data
@@ -443,42 +467,35 @@ _cb_rt_event(const struct os_route *route, bool set) {
     dst = &route->p.key.dst;
     gw = &route->p.gw;
 
-    /* generate l2 key including LID */
-    if (oonf_layer2_neigh_generate_lid(&nb_key, &import->l2origin, mac)) {
-      OONF_DEBUG(LOG_L2_IMPORT, "Could not generate LID for MAC %s",
-          netaddr_to_string(&nbuf, mac));
-      continue;
-    }
-
+    l2neigh_ip = _remove_old_entries(l2net, import, gw, dst);
+    l2neigh = NULL;
     /* get layer2 neighbor */
-    if (set) {
+    if (set && !l2neigh_ip) {
+      /* generate l2 key including LID */
+      if (oonf_layer2_neigh_generate_lid(&nb_key, &import->l2origin, mac)) {
+        OONF_DEBUG(LOG_L2_IMPORT, "Could not generate LID for MAC %s",
+            netaddr_to_string(&nbuf, mac));
+        continue;
+      }
+
       l2neigh = oonf_layer2_neigh_add_lid(l2net, &nb_key);
-    }
-    else {
-      l2neigh = oonf_layer2_neigh_get_lid(l2net, &nb_key);
-    }
-    if (!l2neigh) {
-      OONF_DEBUG(LOG_L2_IMPORT, "No l2 neighbor found");
-      return;
-    }
+      if (!l2neigh) {
+        OONF_DEBUG(LOG_L2_IMPORT, "No l2 neighbor found");
+        return;
+      }
 
-    if (set) {
-      OONF_DEBUG(LOG_L2_IMPORT, "Add lan...");
+      OONF_DEBUG(LOG_L2_IMPORT, "Import layer2 neighbor...");
 
+      /* make sure next hop is initialized */
+      oonf_layer2_neigh_set_nexthop(l2neigh, gw);
       if (!oonf_layer2_neigh_get_remote_ip(l2neigh, dst)) {
         oonf_layer2_neigh_add_ip(l2neigh, &import->l2origin, dst);
       }
+      oonf_layer2_neigh_commit(l2neigh);
     }
-    else {
-      OONF_DEBUG(LOG_L2_IMPORT, "Remove lan...");
-
-      l2neigh_ip = oonf_layer2_neigh_get_remote_ip(l2neigh, dst);
-      if (l2neigh_ip) {
-        oonf_layer2_neigh_remove_ip(l2neigh_ip, &import->l2origin);
-      }
-    }
-    /* make sure next hop is initialized */
-    if (!oonf_layer2_neigh_set_nexthop(l2neigh, gw)) {
+    else if (!set && l2neigh_ip) {
+      l2neigh = l2neigh_ip->l2neigh;
+      oonf_layer2_neigh_remove_ip(l2neigh_ip, &import->l2origin);
       oonf_layer2_neigh_commit(l2neigh);
     }
   }
index b5fc72b..47fc936 100644 (file)
@@ -722,6 +722,7 @@ netaddr_from_string(struct netaddr *dst, const char *src) {
 const char *
 netaddr_socket_to_string(struct netaddr_str *dst, const union netaddr_socket *src) {
   struct netaddr_str buf;
+  static const char NONE[] = "-";
 
   if (src->std.sa_family == AF_INET) {
     snprintf(dst->buf, sizeof(*dst), "%s:%d", inet_ntop(AF_INET, &src->v4.sin_addr, buf.buf, sizeof(buf)),
@@ -739,6 +740,9 @@ netaddr_socket_to_string(struct netaddr_str *dst, const union netaddr_socket *sr
         ntohs(src->v6.sin6_port));
     }
   }
+  else if (src->std.sa_family == 0) {
+    strscpy(dst->buf, NONE, sizeof(*dst));
+  }
   else {
     snprintf(dst->buf, sizeof(*dst), "\"Unknown socket type: %d\"", src->std.sa_family);
   }