Restructure import of FIB entries to go through the layer2 db
authorHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Fri, 4 May 2018 11:39:11 +0000 (13:39 +0200)
committerHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Fri, 4 May 2018 11:39:11 +0000 (13:39 +0200)
allow export of layer2 IP entries to FIB
allow transmission of layer2 IP entries over DLEP

34 files changed:
src-api/common/netaddr.c
src-api/common/netaddr.h
src-plugins/generic/CMakeLists.txt
src-plugins/generic/dlep/dlep_session.c
src-plugins/generic/dlep/dlep_session.h
src-plugins/generic/dlep/dlep_writer.c
src-plugins/generic/dlep/ext_base_ip/ip.c
src-plugins/generic/dlep/ext_lid/lid.c
src-plugins/generic/dlep/radio/dlep_radio.c
src-plugins/generic/dlep/radio/dlep_radio_session.h
src-plugins/generic/dlep/router/dlep_router.c
src-plugins/generic/layer2_export/CMakeLists.txt [moved from src-plugins/olsrv2/lan_import/CMakeLists.txt with 81% similarity]
src-plugins/generic/layer2_export/layer2_export.c [new file with mode: 0644]
src-plugins/generic/layer2_export/layer2_export.h [new file with mode: 0644]
src-plugins/generic/layer2_export/olsrv2_l2import.c [new file with mode: 0644]
src-plugins/generic/layer2_generator/layer2_generator.c
src-plugins/generic/layer2_import/CMakeLists.txt [new file with mode: 0644]
src-plugins/generic/layer2_import/lan_import.c [new file with mode: 0644]
src-plugins/generic/layer2_import/layer2_import.c [moved from src-plugins/olsrv2/lan_import/lan_import.c with 55% similarity]
src-plugins/generic/layer2_import/layer2_import.h [moved from src-plugins/olsrv2/lan_import/lan_import.h with 86% similarity]
src-plugins/generic/layer2info/layer2info.c
src-plugins/generic/nl80211_listener/nl80211_get_station_dump.c
src-plugins/nhdp/nhdp/nhdp_domain.c
src-plugins/nhdp/nhdp/nhdp_domain.h
src-plugins/olsrv2/CMakeLists.txt
src-plugins/olsrv2/olsrv2_l2import/CMakeLists.txt [new file with mode: 0644]
src-plugins/olsrv2/olsrv2_l2import/olsrv2_l2import.c [new file with mode: 0644]
src-plugins/olsrv2/olsrv2_l2import/olsrv2_l2import.h [new file with mode: 0644]
src-plugins/subsystems/oonf_layer2.c
src-plugins/subsystems/oonf_layer2.h
src/dlep-radio/CMakeLists.txt
src/dlep-router/CMakeLists.txt
src/olsrd2-dlep/CMakeLists.txt
src/olsrd2/CMakeLists.txt

index 0bef887..12f7693 100644 (file)
@@ -513,7 +513,7 @@ netaddr_socket_get_port(const union netaddr_socket *sock) {
 /**
  * Converts a netaddr into a string
  * @param dst target string buffer
- * @param src netaddr source
+ * @param src netaddr source (can be NULL)
  * @param forceprefix true if a prefix should be appended even with maximum
  *   prefix length, false if only shorter prefixes should be appended
  * @return pointer to target buffer
index cf0d05f..633a712 100644 (file)
@@ -232,12 +232,12 @@ netaddr_socket_invalidate(union netaddr_socket *sock) {
 }
 
 /**
- * @param addr netaddr object
+ * @param addr netaddr object (might be NULL)
  * @return true if address is AF_UNSPEC, false otherwise
  */
 static INLINE bool
 netaddr_is_unspec(const struct netaddr *addr) {
-  return addr->_type == AF_UNSPEC;
+  return addr == NULL || addr->_type == AF_UNSPEC;
 }
 
 /**
index ea7e963..e82e8fc 100644 (file)
@@ -3,7 +3,9 @@ add_subdirectory(cfg_compact)
 add_subdirectory(dlep)
 add_subdirectory(example)
 add_subdirectory(layer2info)
+add_subdirectory(layer2_import)
 add_subdirectory(layer2_config)
+add_subdirectory(layer2_export)
 add_subdirectory(layer2_generator)
 add_subdirectory(link_config)
 add_subdirectory(plugin_controller)
index 1d751bc..2f8b835 100644 (file)
@@ -168,7 +168,7 @@ dlep_session_add(struct dlep_session *session, const char *l2_ifname, const stru
     return -1;
   }
 
-  avl_init(&session->_ip_prefix_modification, avl_comp_netaddr, false);
+  avl_init(&session->_ext_ip.prefix_modification, avl_comp_netaddr, false);
 
   OONF_INFO(session->log_source, "Add session on %s", session->l2_listener.name);
   return 0;
index 8a3dcfd..67c7fc7 100644 (file)
@@ -270,6 +270,17 @@ enum dlep_peer_state
   DLEP_PEER_TERMINATED,
 };
 
+struct dlep_session_ext_ip {
+  /*! tree of modifications which should be put into the next peer update */
+  struct avl_tree prefix_modification;
+
+  /*! last transmitted IPv4 DLEP interface IP */
+  struct netaddr if_ip_v4;
+
+  /*! last transmitted IPv6 DLEP interface IP */
+  struct netaddr if_ip_v6;
+};
+
 /**
  * Generic DLEP session, might be radio or router
  */
@@ -334,8 +345,8 @@ struct dlep_session {
   /*! true if we cannot send a peer update at the moment */
   enum dlep_peer_state _peer_state;
 
-  /*! tree of modifications which should be put into the next peer update */
-  struct avl_tree _ip_prefix_modification;
+  /*! session data for IP extension */
+  struct dlep_session_ext_ip _ext_ip;
 };
 
 void dlep_session_init(void);
index bd6fb3a..72fb690 100644 (file)
@@ -194,14 +194,16 @@ dlep_writer_add_mac_tlv(struct dlep_writer *writer, const struct oonf_layer2_nei
 }
 
 /**
- * Write a DLEP Link-ID TLV
+ * Write a DLEP Link-ID TLV if length is greater than zero
  * @param writer dlep writer
  * @param mac_lid mac address/LID
  * @return -1 if address was wrong type, 0 otherwise
  */
 int
 dlep_writer_add_lid_tlv(struct dlep_writer *writer, const struct oonf_layer2_neigh_key *mac_lid) {
-  dlep_writer_add_tlv(writer, DLEP_LID_TLV, mac_lid->link_id, mac_lid->link_id_length);
+  if (mac_lid->link_id_length > 0) {
+    dlep_writer_add_tlv(writer, DLEP_LID_TLV, mac_lid->link_id, mac_lid->link_id_length);
+  }
   return 0;
 }
 
index 4b54269..50942b1 100644 (file)
@@ -205,7 +205,7 @@ _cb_session_init(struct dlep_session *session) {
   }
 
   avl_for_each_element(&l2net->local_peer_ips, l2net_ip, _net_node) {
-    _add_prefix(&session->_ip_prefix_modification, &l2net_ip->ip, true);
+    _add_prefix(&session->_ext_ip.prefix_modification, &l2net_ip->ip, true);
   }
 
   avl_for_each_element(&l2net->neighbors, l2neigh, _node) {
@@ -232,20 +232,42 @@ _cb_session_cleanup(struct dlep_session *session) {
   }
 
   /* remove all stored changes for the local peer */
-  avl_for_each_element_safe(&session->_ip_prefix_modification, storage, _node, storage_it) {
-    avl_remove(&session->_ip_prefix_modification, &storage->_node);
+  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);
   }
 }
 
+static void
+_handle_if_ip(struct dlep_session *session, struct netaddr *last_session_if_ip,
+    const struct netaddr *first_if_ip, const struct netaddr *second_if_ip) {
+  const struct netaddr *if_ip;
+
+  if_ip = netaddr_is_unspec(first_if_ip) ? second_if_ip : first_if_ip;
+
+  if (netaddr_cmp(last_session_if_ip, if_ip) == 0) {
+    return;
+  }
+
+  if (!netaddr_is_unspec(last_session_if_ip)) {
+    dlep_writer_add_ip_tlv(&session->writer, last_session_if_ip, false);
+  }
+  if (!netaddr_is_unspec(if_ip)) {
+    dlep_writer_add_ip_tlv(&session->writer, if_ip, true);
+  }
+  memcpy(last_session_if_ip, if_ip, sizeof(*if_ip));
+}
+
 static int
 _radio_write_session_update(struct dlep_extension *ext __attribute__((unused)), struct dlep_session *session,
   const struct oonf_layer2_neigh_key *neigh __attribute__((unused))) {
   struct _prefix_storage *storage, *storage_it;
-
+  struct dlep_radio_session *radio_session;
+  struct os_interface *os_if;
   struct netaddr_str nbuf;
 
-  avl_for_each_element(&session->_ip_prefix_modification, storage, _node) {
+  /* 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)) {
@@ -255,9 +277,17 @@ _radio_write_session_update(struct dlep_extension *ext __attribute__((unused)),
     }
   }
 
+  /* also transmit IP interface addresses */
+  radio_session = dlep_radio_get_session(session);
+  if (radio_session) {
+    os_if = radio_session->interface->interf.udp._if_listener.data;
+    _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->_ip_prefix_modification, storage, _node, storage_it) {
-    avl_remove(&session->_ip_prefix_modification, &storage->_node);
+  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;
@@ -372,8 +402,20 @@ static void
 _process_destination_ip_tlv(
   const struct oonf_layer2_origin *origin, struct oonf_layer2_neigh *l2neigh, struct netaddr *ip, bool add) {
   struct oonf_layer2_neighbor_address *l2addr;
+  struct oonf_layer2_peer_address *peer_ip;
+  int af;
 
+  af = netaddr_get_address_family(ip);
   if (add) {
+    if (!oonf_layer2_neigh_has_nexthop(l2neigh, af)) {
+      avl_for_each_element(&l2neigh->network->local_peer_ips, peer_ip, _net_node) {
+        if (netaddr_get_address_family(&peer_ip->ip) == af
+            && netaddr_get_prefix_length(&peer_ip->ip) == netaddr_get_af_maxprefix(af)) {
+          oonf_layer2_neigh_set_nexthop(l2neigh, &peer_ip->ip);
+          break;
+        }
+      }
+    }
     oonf_layer2_neigh_add_ip(l2neigh, origin, ip);
   }
   else if ((l2addr = oonf_layer2_neigh_get_remote_ip(l2neigh, ip))) {
@@ -466,7 +508,7 @@ _modify_if_ip(const char *if_name, struct netaddr *prefix, bool add) {
   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._ip_prefix_modification, prefix, add);
+        _add_prefix(&radio_session->session._ext_ip.prefix_modification, prefix, add);
       }
     }
   }
index 6817d2d..66925ec 100644 (file)
@@ -69,57 +69,36 @@ static const uint16_t _session_initack_tlvs[] = {
 static const uint16_t _dst_up_tlvs[] = {
   DLEP_LID_TLV,
 };
-static const uint16_t _dst_up_mandatory[] = {
-  DLEP_LID_TLV,
-};
 
 /* destination up ack */
 static const uint16_t _dst_up_ack_tlvs[] = {
   DLEP_LID_TLV,
 };
-static const uint16_t _dst_up_ack_mandatory[] = {
-  DLEP_LID_TLV,
-};
 
 /* destination down */
 static const uint16_t _dst_down_tlvs[] = {
   DLEP_LID_TLV,
 };
-static const uint16_t _dst_down_mandatory[] = {
-  DLEP_LID_TLV,
-};
 
 /* destination down ack */
 static const uint16_t _dst_down_ack_tlvs[] = {
   DLEP_LID_TLV,
 };
-static const uint16_t _dst_down_ack_mandatory[] = {
-  DLEP_LID_TLV,
-};
 
 /* destination update */
 static const uint16_t _dst_update_tlvs[] = {
   DLEP_LID_TLV,
 };
-static const uint16_t _dst_update_mandatory[] = {
-  DLEP_MAC_ADDRESS_TLV,
-};
 
 /* link characteristics request */
 static const uint16_t _linkchar_req_tlvs[] = {
   DLEP_LID_TLV,
 };
-static const uint16_t _linkchar_req_mandatory[] = {
-  DLEP_LID_TLV,
-};
 
 /* link characteristics ack */
 static const uint16_t _linkchar_ack_tlvs[] = {
   DLEP_LID_TLV,
 };
-static const uint16_t _linkchar_ack_mandatory[] = {
-  DLEP_LID_TLV,
-};
 
 /* supported signals of this extension, parsing the LID TLV is done by dlep_extension */
 static struct dlep_extension_signal _signals[] = {
@@ -134,56 +113,42 @@ static struct dlep_extension_signal _signals[] = {
     .id = DLEP_DESTINATION_UP,
     .supported_tlvs = _dst_up_tlvs,
     .supported_tlv_count = ARRAYSIZE(_dst_up_tlvs),
-    .mandatory_tlvs = _dst_up_mandatory,
-    .mandatory_tlv_count = ARRAYSIZE(_dst_up_mandatory),
     .add_radio_tlvs = _write_lid_only,
   },
   {
     .id = DLEP_DESTINATION_UP_ACK,
     .supported_tlvs = _dst_up_ack_tlvs,
     .supported_tlv_count = ARRAYSIZE(_dst_up_ack_tlvs),
-    .mandatory_tlvs = _dst_up_ack_mandatory,
-    .mandatory_tlv_count = ARRAYSIZE(_dst_up_ack_mandatory),
     .add_router_tlvs = _write_lid_only,
   },
   {
     .id = DLEP_DESTINATION_DOWN,
     .supported_tlvs = _dst_down_tlvs,
     .supported_tlv_count = ARRAYSIZE(_dst_down_tlvs),
-    .mandatory_tlvs = _dst_down_mandatory,
-    .mandatory_tlv_count = ARRAYSIZE(_dst_down_mandatory),
     .add_radio_tlvs = _write_lid_only,
   },
   {
     .id = DLEP_DESTINATION_DOWN_ACK,
     .supported_tlvs = _dst_down_ack_tlvs,
     .supported_tlv_count = ARRAYSIZE(_dst_down_ack_tlvs),
-    .mandatory_tlvs = _dst_down_ack_mandatory,
-    .mandatory_tlv_count = ARRAYSIZE(_dst_down_ack_mandatory),
     .add_router_tlvs = _write_lid_only,
   },
   {
     .id = DLEP_DESTINATION_UPDATE,
     .supported_tlvs = _dst_update_tlvs,
     .supported_tlv_count = ARRAYSIZE(_dst_update_tlvs),
-    .mandatory_tlvs = _dst_update_mandatory,
-    .mandatory_tlv_count = ARRAYSIZE(_dst_update_mandatory),
     .add_radio_tlvs = _write_lid_only,
   },
   {
     .id = DLEP_LINK_CHARACTERISTICS_REQUEST,
     .supported_tlvs = _linkchar_req_tlvs,
     .supported_tlv_count = ARRAYSIZE(_linkchar_req_tlvs),
-    .mandatory_tlvs = _linkchar_req_mandatory,
-    .mandatory_tlv_count = ARRAYSIZE(_linkchar_req_mandatory),
     .add_router_tlvs = _write_lid_only,
   },
   {
     .id = DLEP_LINK_CHARACTERISTICS_ACK,
     .supported_tlvs = _linkchar_ack_tlvs,
     .supported_tlv_count = ARRAYSIZE(_linkchar_ack_tlvs),
-    .mandatory_tlvs = _linkchar_ack_mandatory,
-    .mandatory_tlv_count = ARRAYSIZE(_linkchar_ack_mandatory),
     .add_radio_tlvs = _write_lid_only,
   },
 };
index 3c5cb42..3142a6a 100644 (file)
@@ -93,7 +93,7 @@ static struct cfg_schema_entry _radio_entries[] = {
     DLEP_WELL_KNOWN_MULTICAST_ADDRESS_6, "IPv6 address to send discovery UDP packet to", false, false),
   CFG_MAP_INT32_MINMAX(dlep_radio_if, interf.udp_config.port, "discovery_port", DLEP_WELL_KNOWN_MULTICAST_PORT_TXT,
     "UDP port for discovery packets", 0, 1, 65535),
-  CFG_MAP_ACL_V46(dlep_radio_if, interf.udp_config.bindto, "discovery_bindto", "fe80::/10",
+  CFG_MAP_ACL_V46(dlep_radio_if, interf.udp_config.bindto, "discovery_bindto", "fe80::/64",
     "Filter to determine the binding of the UDP discovery socket"),
 
   CFG_MAP_INT32_MINMAX(dlep_radio_if, tcp_config.port, "session_port", DLEP_WELL_KNOWN_SESSION_PORT_TXT,
index cfc36cf..cfd693c 100644 (file)
@@ -79,4 +79,12 @@ void dlep_radio_session_cleanup(void);
 void dlep_radio_remove_session(struct dlep_radio_session *router_session);
 void dlep_radio_session_initialize_tcp_callbacks(struct oonf_stream_config *config);
 
+static INLINE struct dlep_radio_session *
+dlep_radio_get_session(struct dlep_session *session) {
+  if (!session->radio) {
+    return NULL;
+  }
+  return container_of(session, struct dlep_radio_session, session);
+}
+
 #endif /* DLEP_RADIO_SESSION_H_ */
index aa24c22..f81c9d6 100644 (file)
@@ -90,7 +90,7 @@ static struct cfg_schema_entry _router_entries[] = {
   CFG_MAP_INT32_MINMAX(dlep_router_if, interf.udp_config.multicast_port, "discovery_port",
     DLEP_WELL_KNOWN_MULTICAST_PORT_TXT, "UDP port for discovery packets", 0, 1, 65535),
 
-  CFG_MAP_ACL_V46(dlep_router_if, interf.udp_config.bindto, "discovery_bindto", "224.0.0.1\0fe80::/10",
+  CFG_MAP_ACL_V46(dlep_router_if, interf.udp_config.bindto, "discovery_bindto", "fe80::/64",
     "Filter to determine the binding of the UDP discovery socket"),
 
   CFG_MAP_CLOCK_MIN(dlep_router_if, interf.session.cfg.discovery_interval, "discovery_interval", "1.000",
@@ -1,5 +1,5 @@
 # set library parameters
-SET (name lan_import)
+SET (name layer2_export)
 
 # use generic plugin maker
 oonf_create_plugin("${name}" "${name}.c" "${name}.h" "")
diff --git a/src-plugins/generic/layer2_export/layer2_export.c b/src-plugins/generic/layer2_export/layer2_export.c
new file mode 100644 (file)
index 0000000..f3b8ff0
--- /dev/null
@@ -0,0 +1,510 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
+ * Copyright (c) 2004-2015, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <errno.h>
+
+#include "common/avl.h"
+#include "common/avl_comp.h"
+#include "common/common_types.h"
+#include "common/netaddr.h"
+#include "config/cfg_schema.h"
+#include "core/oonf_logging.h"
+#include "core/oonf_subsystem.h"
+#include "subsystems/oonf_class.h"
+#include "subsystems/oonf_layer2.h"
+#include "subsystems/os_routing.h"
+
+#include "layer2_export/layer2_export.h"
+
+/*! logging for plugin */
+#define LOG_L2EXPORT _l2export_subsystem.logging
+
+/**
+ * Additional parameters of an imported layer2 network
+ */
+struct _l2export_data {
+  /*! originator to import, defined as the section name */
+  char originator[16];
+
+  /*! fib distance */
+  int32_t fib_distance;
+
+  /*! fib routing table */
+  int32_t fib_table;
+
+  /*! fib protocol */
+  int32_t fib_protocol;
+
+  /*! tree of routes imported by this section */
+  struct avl_tree route_tree;
+
+  /*! node to hold all l2imports together */
+  struct avl_node _node;
+};
+
+/*! Life cycle of a route exported by this plugin */
+enum route_status {
+  /*! nothing has been done */
+  ROUTE_NOTHING,
+
+  /*! route is currently being added to the FIB */
+  ROUTE_ADDING,
+
+  /*! route has been added to the FIB */
+  ROUTE_ADDED,
+
+  /*! route is currently being removed from the FIB */
+  ROUTE_REMOVING,
+
+  /*! route has been removed from the FIB */
+  ROUTE_REMOVED,
+};
+
+/*! route object for export to FIB */
+struct _l2export_route {
+  /*! os route settings */
+  struct os_route os;
+
+  /*! lifecycle status of this object */
+  enum route_status status;
+
+  /*! back pointer to export data object */
+  struct _l2export_data *export_data;
+
+  /*! node for export data route tree */
+  struct avl_node _node;
+};
+
+/* prototypes */
+static int _init(void);
+static void _cleanup(void);
+static void _initiate_shutdown(void);
+
+static struct _l2export_data *_get_l2export(const char *name);
+static void _destroy_l2export(struct _l2export_data *);
+static bool _is_matching_origin(struct oonf_layer2_neighbor_address *, const char *pattern);
+
+static struct _l2export_route *_get_route(struct _l2export_data *data, struct os_route_key *key);
+static void _destroy_route(struct _l2export_route *route);
+static void _cb_route_finished(struct os_route *route, int error);
+
+static void _cb_l2neigh_ip_added(void *);
+static void _cb_l2neigh_ip_removed(void *);
+
+static void _cb_cfg_changed(void);
+
+static struct cfg_schema_entry _l2export_entries[] = {
+  CFG_MAP_INT32_MINMAX(_l2export_data, fib_distance, "fib_distance", "2",
+      "fib distance for exported layer2 entries", 0, 1, 255),
+  CFG_MAP_INT32_MINMAX(_l2export_data, fib_table, "fib_table", "254",
+      "fib table for exported layer2 entries", 0, 1, 65535),
+  CFG_MAP_INT32_MINMAX(_l2export_data, fib_protocol, "fib_protocol", "100",
+      "fib protocol for exported layer2 entries", 0, 1, 255),
+};
+
+static struct cfg_schema_section _l2export_section = {
+  .type = OONF_LAYER2_EXPORT_SUBSYSTEM,
+  .mode = CFG_SSMODE_NAMED,
+
+  .cb_delta_handler = _cb_cfg_changed,
+  .entries = _l2export_entries,
+  .entry_count = ARRAYSIZE(_l2export_entries),
+};
+
+static const char *_dependencies[] = {
+  OONF_CLASS_SUBSYSTEM,
+  OONF_LAYER2_SUBSYSTEM,
+  OONF_OS_ROUTING_SUBSYSTEM,
+};
+static struct oonf_subsystem _l2export_subsystem = {
+  .name = OONF_LAYER2_EXPORT_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
+  .init = _init,
+  .cleanup = _cleanup,
+  .initiate_shutdown = _initiate_shutdown,
+
+  .cfg_section = &_l2export_section,
+};
+DECLARE_OONF_PLUGIN(_l2export_subsystem);
+
+/*! tree to remember all imported layer2 originators */
+static struct avl_tree _l2export_tree;
+
+/* class definition for filters */
+static struct oonf_class _l2export_class = {
+  .name = "layer2 export",
+  .size = sizeof(struct _l2export_data),
+};
+
+static struct oonf_class _route_class = {
+  .name = "layer2 route",
+  .size = sizeof(struct _l2export_route),
+};
+
+static struct oonf_class_extension _l2neighip_ext = {
+  .ext_name = "l2export listener",
+  .class_name = LAYER2_CLASS_NEIGHBOR_ADDRESS,
+
+  .cb_add = _cb_l2neigh_ip_added,
+  .cb_remove = _cb_l2neigh_ip_removed,
+};
+
+/* tree of routing exporters */
+static struct avl_tree _l2export_tree;
+
+/* tree of removing routes */
+static struct avl_tree _removal_tree;
+
+/**
+ * Initialize plugin
+ * @return always returns 0 (cannot fail)
+ */
+static int
+_init(void) {
+  if (oonf_class_extension_add(&_l2neighip_ext)) {
+    return -1;
+  }
+  avl_init(&_l2export_tree, avl_comp_strcasecmp, false);
+  avl_init(&_removal_tree, os_routing_avl_cmp_route_key, false);
+  oonf_class_add(&_l2export_class);
+  oonf_class_add(&_route_class);
+  return 0;
+}
+
+/**
+ * Cleanup plugin
+ */
+static void
+_cleanup(void) {
+  oonf_class_remove(&_l2export_class);
+  oonf_class_extension_remove(&_l2neighip_ext);
+}
+
+static void
+_initiate_shutdown(void) {
+  struct _l2export_data *mod, *mod_it;
+
+  avl_for_each_element_safe(&_l2export_tree, mod, _node, mod_it) {
+    _destroy_l2export(mod);
+  }
+}
+
+/**
+ * Lookups a layer2 export or create a new one
+ * @param name name of layer2 export
+ * @return pointer to export data or NULL if out of memory
+ */
+static struct _l2export_data *
+_get_l2export(const char *name) {
+  struct _l2export_data *mod;
+
+  mod = avl_find_element(&_l2export_tree, name, mod, _node);
+  if (mod) {
+    return mod;
+  }
+
+  mod = oonf_class_malloc(&_l2export_class);
+  if (mod == NULL) {
+    return NULL;
+  }
+
+  /* copy key and add to tree */
+  strscpy(mod->originator, name, sizeof(mod->originator));
+  mod->_node.key = mod->originator;
+  avl_insert(&_l2export_tree, &mod->_node);
+
+  /* initialize */
+  avl_init(&mod->route_tree, os_routing_avl_cmp_route_key, false);
+
+  return mod;
+}
+
+/**
+ * Free all resources associated with a layer2 import
+ * @param l2export layer2 import
+ */
+static void
+_destroy_l2export(struct _l2export_data *l2export) {
+  struct _l2export_route *l2route, *l2route_it;
+
+  avl_for_each_element_safe(&l2export->route_tree, l2route, _node, l2route_it) {
+    _destroy_route(l2route);
+  }
+
+  /* first remove the import settings from the tree */
+  avl_remove(&_l2export_tree, &l2export->_node);
+
+  oonf_class_free(&_l2export_class, l2export);
+}
+
+/**
+* Checks if the originator name of a l2 neighbor address matches a pattern
+* @param addr l2 neighbor address
+* @param pattern pattern (can end with an asterix wildcard)
+* @return true if matching, false otherwise
+*/
+static bool
+_is_matching_origin(struct oonf_layer2_neighbor_address *addr, const char *pattern) {
+  int len;
+
+  if (strcmp(addr->origin->name, pattern) == 0) {
+    return true;
+  }
+
+  len = strlen(pattern);
+  if (len == 0 || pattern[len-1] != '*') {
+    return false;
+  }
+
+  return strncmp(addr->origin->name, pattern, len-1) == 0;
+}
+
+/**
+* Returns an existing route object or creates a new one
+* @param data layer export data this route belongs to
+* @param key routing key (source/destination) IP
+* @return route, NULL if out of memory
+*/
+static struct _l2export_route *
+_get_route(struct _l2export_data *data, struct os_route_key *key) {
+  struct _l2export_route *l2route;
+
+  l2route = avl_find_element(&data->route_tree, key, l2route, _node);
+  if (l2route) {
+    return l2route;
+  }
+
+  l2route = oonf_class_malloc(&_route_class);
+  if (!l2route) {
+    return NULL;
+  }
+
+  /* hook into tree */
+  memcpy(&l2route->os.p.key, key, sizeof(*key));
+  l2route->_node.key = &l2route->os.p.key;
+  avl_insert(&data->route_tree, &l2route->_node);
+
+  /* initialize */
+  l2route->os.cb_finished = _cb_route_finished;
+  l2route->export_data = data;
+  return l2route;
+}
+
+/**
+* triggers the removal of a route or removes the object from memory
+* @param l2route route object
+*/
+static void
+_destroy_route(struct _l2export_route *l2route) {
+  struct os_route_str rbuf;
+
+  switch (l2route->status) {
+    case ROUTE_NOTHING:
+      avl_remove(&l2route->export_data->route_tree, &l2route->_node);
+      oonf_class_free(&_route_class, l2route);
+      break;
+    case ROUTE_ADDING:
+      os_routing_interrupt(&l2route->os);
+      break;
+      /* fallthrough */
+    case ROUTE_ADDED:
+      /* remove from export database */
+      avl_remove(&l2route->export_data->route_tree, &l2route->_node);
+      l2route->export_data = NULL;
+
+      /* remove route */
+      OONF_DEBUG(LOG_L2EXPORT, "remove route %s from fib", os_routing_to_string(&rbuf, &l2route->os.p));
+      os_routing_set(&l2route->os, false, false);
+      avl_insert(&_removal_tree, &l2route->_node);
+      l2route->status = ROUTE_REMOVING;
+      break;
+    case ROUTE_REMOVING:
+      /* wait for finisher */
+      break;
+    case ROUTE_REMOVED:
+      avl_remove(&_removal_tree, &l2route->_node);
+      oonf_class_free(&_route_class, l2route);
+      break;
+    default:
+      break;
+  }
+}
+
+/**
+* Callback for os routing system when route handling is finished
+* @param os_route route that has been finished
+* @param error error code, 0 if everything is okay
+*/
+static void
+_cb_route_finished(struct os_route *os_route, int error) {
+  struct _l2export_route *l2route;
+  struct os_route_str rbuf;
+
+  l2route = container_of(os_route, struct _l2export_route, os);
+
+  OONF_DEBUG(LOG_L2EXPORT, "route finished (error=%d, status=%d): %s",
+      error, l2route->status, os_routing_to_string(&rbuf, &os_route->p));
+  switch (l2route->status) {
+    case ROUTE_ADDING:
+      l2route->status = ROUTE_ADDED;
+      if (error) {
+        _destroy_route(l2route);
+      }
+      break;
+    case ROUTE_REMOVING:
+      l2route->status = ROUTE_REMOVED;
+      _destroy_route(l2route);
+      break;
+    default:
+      OONF_WARN(LOG_L2EXPORT, "Got route feedback for state %d", l2route->status);
+      _destroy_route(l2route);
+      break;
+  }
+}
+
+/**
+* Callback triggered when a l2 neighbor address is addrd
+* @param ptr address being added
+*/
+static void
+_cb_l2neigh_ip_added(void *ptr) {
+  struct oonf_layer2_neighbor_address *nip = ptr;
+  struct _l2export_data *l2export;
+  struct _l2export_route *l2route;
+  struct os_route_key rt_key;
+  int8_t af;
+  struct os_route_str rbuf;
+  struct netaddr_str nbuf;
+
+  os_routing_init_sourcespec_prefix(&rt_key, &nip->ip);
+
+  avl_for_each_element(&_l2export_tree, l2export, _node) {
+    OONF_DEBUG(LOG_L2EXPORT, "Check export %s against originator %s",
+                   l2export->originator, nip->origin->name);
+    if (_is_matching_origin(nip, l2export->originator)) {
+      OONF_DEBUG(LOG_L2EXPORT, "match");
+      l2route = _get_route(l2export, &rt_key);
+      if (!l2route) {
+        continue;
+      }
+
+      OONF_DEBUG(LOG_L2EXPORT, "got entry");
+
+      // TODO: what if this route is not in state "nothing" ?
+      af = netaddr_get_address_family(&nip->ip);
+
+      /* set route parameters */
+      l2route->os.p.family = af;
+      memcpy(&l2route->os.p.gw, oonf_layer2_neigh_get_nexthop(nip->l2neigh, af), sizeof(struct netaddr));
+      l2route->os.p.type = OS_ROUTE_UNICAST;
+      l2route->os.p.metric   = l2export->fib_distance;
+      l2route->os.p.if_index = nip->l2neigh->network->if_listener.data->index;
+      l2route->os.p.protocol = l2export->fib_protocol;
+      l2route->os.p.table    = l2export->fib_table;
+
+      OONF_DEBUG(LOG_L2EXPORT, "Add route %s to fib (gw was %s)",
+          os_routing_to_string(&rbuf, &l2route->os.p),
+          netaddr_to_string(&nbuf, oonf_layer2_neigh_get_nexthop(nip->l2neigh, af)));
+      if (!os_routing_set(&l2route->os, true, false)) {
+        l2route->status = ROUTE_ADDING;
+      }
+    }
+  }
+}
+
+/**
+* Callback triggered when a l2 neighbor address is removed
+* @param ptr address being removed
+*/
+static void
+_cb_l2neigh_ip_removed(void *ptr) {
+  struct oonf_layer2_neighbor_address *nip = ptr;
+  struct _l2export_data *l2export;
+  struct _l2export_route *l2route;
+  struct os_route_key rt_key;
+
+  os_routing_init_sourcespec_prefix(&rt_key, &nip->ip);
+
+  avl_for_each_element(&_l2export_tree, l2export, _node) {
+    OONF_DEBUG(LOG_L2EXPORT, "Check export %s against originator %s",
+               l2export->originator, nip->origin->name);
+    if (_is_matching_origin(nip, l2export->originator)) {
+      OONF_DEBUG(LOG_L2EXPORT, "match");
+      l2route = avl_find_element(&l2export->route_tree, &rt_key, l2route, _node);
+      if (l2route) {
+        OONF_DEBUG(LOG_L2EXPORT, "found entry");
+        _destroy_route(l2route);
+      }
+    }
+  }
+}
+
+/**
+ * Configuration changed
+ */
+static void
+_cb_cfg_changed(void) {
+  struct _l2export_data *l2export;
+
+  /* get existing import */
+    l2export = _get_l2export(_l2export_section.section_name);
+  if (!l2export) {
+    /* out of memory */
+    return;
+  }
+
+  if (!_l2export_section.post) {
+    /* section was removed */
+        _destroy_l2export(l2export);
+    return;
+  }
+
+  if (cfg_schema_tobin(l2export, _l2export_section.post, _l2export_entries, ARRAYSIZE(_l2export_entries))) {
+    OONF_WARN(LOG_L2EXPORT,
+        "Could not convert configuration data of section '%s'", _l2export_section.section_name);
+
+    if (!_l2export_section.pre) {
+            _destroy_l2export(l2export);
+    }
+    return;
+  }
+}
diff --git a/src-plugins/generic/layer2_export/layer2_export.h b/src-plugins/generic/layer2_export/layer2_export.h
new file mode 100644 (file)
index 0000000..fd3061d
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * layer2_export.h
+ *
+ *  Created on: 18.10.2017
+ *      Author: rogge
+ */
+
+#ifndef _LAYER2_EXPORT_H_
+#define _LAYER2_EXPORT_H_
+
+#define OONF_LAYER2_EXPORT_SUBSYSTEM "layer2_export"
+
+#endif /* _LAYER2_EXPORT_H_ */
diff --git a/src-plugins/generic/layer2_export/olsrv2_l2import.c b/src-plugins/generic/layer2_export/olsrv2_l2import.c
new file mode 100644 (file)
index 0000000..e69de29
index 57c1753..e4b5102 100644 (file)
@@ -245,7 +245,7 @@ _cb_l2gen_event(struct oonf_timer_instance *ptr __attribute((unused))) {
   memcpy(&neigh->key.addr, &_l2gen_config.neighbor, sizeof(neigh->key.addr));
   neigh->key.link_id[0] = event_counter & 0xff;
   neigh->key.link_id_length = 1;
-  neigh->last_seen = oonf_clock_getNow();
+  oonf_layer2_neigh_set_lastseen(neigh, oonf_clock_getNow());
 
   for (neigh_idx = 0; neigh_idx < OONF_LAYER2_NEIGH_COUNT; neigh_idx++) {
     _set_data(&neigh->data[neigh_idx], oonf_layer2_neigh_metadata_get(neigh_idx)->type, event_counter);
diff --git a/src-plugins/generic/layer2_import/CMakeLists.txt b/src-plugins/generic/layer2_import/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9701f39
--- /dev/null
@@ -0,0 +1,5 @@
+# set library parameters
+SET (name layer2_import)
+
+# use generic plugin maker
+oonf_create_plugin("${name}" "${name}.c" "${name}.h" "")
diff --git a/src-plugins/generic/layer2_import/lan_import.c b/src-plugins/generic/layer2_import/lan_import.c
new file mode 100644 (file)
index 0000000..e69de29
 #include "core/oonf_subsystem.h"
 #include "subsystems/oonf_class.h"
 #include "subsystems/oonf_clock.h"
+#include "subsystems/oonf_layer2.h"
 #include "subsystems/oonf_timer.h"
+#include "subsystems/os_interface.h"
+#include "subsystems/os_routing.h"
 
-#include "olsrv2/olsrv2.h"
-#include "olsrv2/olsrv2_lan.h"
-#include "olsrv2/olsrv2_routing.h"
-
-#include "lan_import/lan_import.h"
+#include "layer2_import/layer2_import.h"
 
 /* definitions */
-#define LOG_LAN_IMPORT _import_subsystem.logging
+#define LOG_L2_IMPORT _import_subsystem.logging
 
 /**
  * configuration of one LAN import instance
  */
 struct _import_entry {
   /*! name of the lan import */
-  char name[16];
+  char name[20];
+
+  struct oonf_layer2_origin l2origin;
 
   /*! domain of the lan import */
   int32_t domain;
@@ -94,56 +95,36 @@ struct _import_entry {
   /*! filter by routing metric, 0 to ignore */
   int32_t distance;
 
-  /*! set the routing metric to a specific value */
-  int32_t routing_metric;
+  /*! set MAC address of imported entries to this interface */
+  char fixed_mac_if[IF_NAMESIZE];
 
-  /*! double the metric every time interval, 0 to disable */
-  uint64_t metric_aging;
-
-  /*! list of lan entries imported by this filter */
-  struct avl_tree imported_lan_tree;
+  /*! helper to keep track of MAC of 'fixed' interface */
+  struct os_interface_listener fixed_if_listener;
 
   /*! tree of all configured lan import */
   struct avl_node _node;
 };
 
-struct _imported_lan {
-  struct os_route_key key;
-
-  struct _import_entry *import;
-
-  /*! timer to age metric value */
-  struct oonf_timer_instance _aging_timer;
-
-  /*! node for list of imported lan entries */
-  struct avl_node _node;
-};
-
 /* prototypes */
 static int _init(void);
 static void _initiate_shutdown(void);
 static void _cleanup(void);
 
 static struct _import_entry *_get_import(const char *name);
-static void _destroy_import(struct _import_entry *);
-
-static struct _imported_lan *_add_lan(
-  struct _import_entry *, struct os_route_key *key, uint32_t metric, uint8_t distance);
-static void _destroy_lan(struct _imported_lan *);
+static void _remove_import(struct _import_entry *);
 
 static void _cb_query(struct os_route *filter, struct os_route *route);
 static void _cb_query_finished(struct os_route *, int error);
 
-static bool _is_allowed_to_import(const struct os_route *route);
 static void _cb_rt_event(const struct os_route *, bool);
+static void _cb_reload_routes(struct oonf_timer_instance *);
 
-static void _cb_metric_aging(struct oonf_timer_instance *entry);
-
-static void _cb_cfg_interface_changed(void);
-static void _cb_cfg_changed(void);
+static void _cb_lan_cfg_changed(void);
+static void _cb_l2_cfg_changed(void);
+static void _cb_cfg_changed(struct cfg_schema_section *section, char *section_name);
 
 /* plugin declaration */
-static struct cfg_schema_entry _import_entries[] = {
+static struct cfg_schema_entry _l2_entries[] = {
   CFG_MAP_INT32_MINMAX(
     _import_entry, domain, "domain", "-1", "Routing domain extension for filter, -1 for all domains", 0, -1, 255),
   CFG_MAP_ACL(_import_entry, filter, "matches", ACL_DEFAULT_ACCEPT,
@@ -159,20 +140,47 @@ static struct cfg_schema_entry _import_entries[] = {
     _import_entry, protocol, "protocol", "-1", "Routing protocol of matching routes, 0 for all protocols", 0, -1, 255),
   CFG_MAP_INT32_MINMAX(
     _import_entry, distance, "metric", "-1", "Metric of matching routes, 0 for all metrics", 0, -1, INT32_MAX),
-  CFG_MAP_INT32_MINMAX(_import_entry, routing_metric, "routing_metric", "1",
-    "Set the routing metric of an imported route to a specific value", false, RFC7181_METRIC_MIN, RFC7181_METRIC_MAX),
-  CFG_MAP_CLOCK(_import_entry, metric_aging, "metric_aging", "0",
-    "Double the routing metric value every time interval, 0 to disable"),
+  CFG_MAP_STRING_ARRAY(_import_entry, fixed_mac_if, "fixed_mac_if", "",
+    "Name of interface that will be used to fill in layer2 entry MAC addresses", IF_NAMESIZE),
 };
 
-static struct cfg_schema_section _interface_section = {
-  CFG_OSIF_SCHEMA_INTERFACE_SECTION_INIT,
+static struct cfg_schema_entry _lan_entries[] = {
+  CFG_MAP_INT32_MINMAX(
+    _import_entry, domain, "domain", "-1", "Routing domain extension for filter, -1 for all domains", 0, -1, 255),
+  CFG_MAP_ACL(_import_entry, filter, "matches", ACL_DEFAULT_ACCEPT,
+    "Ip addresses the filter should be applied to"
+    " (the plugin will never import loopback, linklocal or multicast IPs)"),
+  CFG_MAP_INT32_MINMAX(_import_entry, prefix_length, "prefix_length", "-1",
+    "Prefix length the filter should be applied to, -1 for any prefix length", 0, -1, 128),
+  CFG_MAP_STRING_ARRAY(
+    _import_entry, ifname, "interface", "", "Interface name of matching routes, empty if all interfaces", IF_NAMESIZE),
+  CFG_MAP_INT32_MINMAX(
+    _import_entry, table, "table", "-1", "Routing table of matching routes, 0 for matching all tables", 0, -1, 255),
+  CFG_MAP_INT32_MINMAX(
+    _import_entry, protocol, "protocol", "-1", "Routing protocol of matching routes, 0 for all protocols", 0, -1, 255),
+  CFG_MAP_INT32_MINMAX(
+    _import_entry, distance, "metric", "-1", "Metric of matching routes, 0 for all metrics", 0, -1, INT32_MAX),
+  CFG_MAP_STRING_ARRAY(_import_entry, fixed_mac_if, "fixed_mac_if", "",
+    "Name of interface that will be used to fill in layer2 entry MAC addresses", IF_NAMESIZE),
+};
+
+static struct cfg_schema_section _lan_import_section = {
+  .type = OONF_LAN_IMPORT_SECTION,
+
+  /*
+   * this MUST NOT be CFG_SSMODE_NAMED_WITH_DEFAULT, otherwise it will
+   * activate without user interaction
+   */
+  .mode = CFG_SSMODE_NAMED,
+
+  .cb_delta_handler = _cb_lan_cfg_changed,
 
-  .cb_delta_handler = _cb_cfg_interface_changed,
+  .entries = _lan_entries,
+  .entry_count = ARRAYSIZE(_lan_entries),
 };
 
-static struct cfg_schema_section _import_section = {
-  .type = OONF_LAN_IMPORT_SUBSYSTEM,
+static struct cfg_schema_section _l2_import_section = {
+  .type = OONF_LAYER2_IMPORT_SUBSYSTEM,
 
   /*
    * this MUST NOT be CFG_SSMODE_NAMED_WITH_DEFAULT, otherwise it will
@@ -180,29 +188,29 @@ static struct cfg_schema_section _import_section = {
    */
   .mode = CFG_SSMODE_NAMED,
 
-  .cb_delta_handler = _cb_cfg_changed,
+  .cb_delta_handler = _cb_l2_cfg_changed,
 
-  .entries = _import_entries,
-  .entry_count = ARRAYSIZE(_import_entries),
+  .entries = _l2_entries,
+  .entry_count = ARRAYSIZE(_l2_entries),
 
-  .next_section = &_interface_section,
+  .next_section = &_lan_import_section,
 };
 
 static const char *_dependencies[] = {
   OONF_CLASS_SUBSYSTEM,
   OONF_CLOCK_SUBSYSTEM,
   OONF_TIMER_SUBSYSTEM,
-  OONF_OLSRV2_SUBSYSTEM,
+  OONF_OS_INTERFACE_SUBSYSTEM,
   OONF_OS_ROUTING_SUBSYSTEM,
 };
 static struct oonf_subsystem _import_subsystem = {
-  .name = OONF_LAN_IMPORT_SUBSYSTEM,
+  .name = OONF_LAYER2_IMPORT_SUBSYSTEM,
   .dependencies = _dependencies,
   .dependencies_count = ARRAYSIZE(_dependencies),
   .descr = "OLSRv2 lan-import plugin",
   .author = "Henning Rogge",
 
-  .cfg_section = &_import_section,
+  .cfg_section = &_l2_import_section,
 
   .init = _init,
   .cleanup = _cleanup,
@@ -212,14 +220,17 @@ DECLARE_OONF_PLUGIN(_import_subsystem);
 
 /* class definition for filters */
 static struct oonf_class _import_class = {
-  .name = "lan import filter",
+  .name = "l2 import filter",
   .size = sizeof(struct _import_entry),
 };
 
-/* class definition for imported lans */
-static struct oonf_class _lan_import_class = {
-  .name = "lan import entry",
-  .size = sizeof(struct _imported_lan),
+/* timer for triggering 'lazy' reload of routes */
+static struct oonf_timer_class _route_reload = {
+  .name = "l2 import route reload",
+  .callback = _cb_reload_routes,
+};
+static struct oonf_timer_instance _route_reload_instance = {
+  .class = &_route_reload,
 };
 
 /* callback filter for dijkstra */
@@ -230,12 +241,6 @@ static struct os_route_listener _routing_listener = {
 /* tree of lan importers */
 static struct avl_tree _import_tree;
 
-static struct oonf_timer_class _aging_timer_class = {
-  .name = "lan import metric aging",
-  .callback = _cb_metric_aging,
-  .periodic = true,
-};
-
 /* wildcard route for first query */
 static struct os_route _unicast_query;
 
@@ -246,10 +251,10 @@ static struct os_route _unicast_query;
 static int
 _init(void) {
   avl_init(&_import_tree, avl_comp_strcasecmp, false);
+
   oonf_class_add(&_import_class);
-  oonf_class_add(&_lan_import_class);
+  oonf_timer_add(&_route_reload);
   os_routing_listener_add(&_routing_listener);
-  oonf_timer_add(&_aging_timer_class);
 
   /* initialize wildcard query */
   os_routing_init_wildcard_route(&_unicast_query);
@@ -273,11 +278,10 @@ _cleanup(void) {
   struct _import_entry *import, *import_it;
 
   avl_for_each_element_safe(&_import_tree, import, _node, import_it) {
-    _destroy_import(import);
+    _remove_import(import);
   }
 
-  oonf_timer_remove(&_aging_timer_class);
-  oonf_class_remove(&_lan_import_class);
+  oonf_timer_remove(&_route_reload);
   oonf_class_remove(&_import_class);
 }
 
@@ -300,33 +304,6 @@ static void
 _cb_query_finished(struct os_route *route __attribute__((unused)), int error __attribute__((unused))) {}
 
 /**
- * Checks if importing the route is prevented because of safety issues
- * @param route route data
- * @return true if is okay to import, false otherwise
- */
-static bool
-_is_allowed_to_import(const struct os_route *route) {
-  struct nhdp_domain *domain;
-  const struct olsrv2_routing_domain *rtparam;
-  struct os_interface *interf;
-
-  list_for_each_element(nhdp_domain_get_list(), domain, _node) {
-    rtparam = olsrv2_routing_get_parameters(domain);
-    if (rtparam->protocol == route->p.protocol && rtparam->table == route->p.table) {
-      /* do never set a LAN for a route tagged with an olsrv2 protocol */
-      OONF_DEBUG(LOG_LAN_IMPORT, "Matches olsrv2 protocol, do not import!");
-      return false;
-    }
-  }
-
-  interf = os_interface_get_data_by_ifindex(route->p.if_index);
-  if (interf != NULL && interf->flags.mesh) {
-    return false;
-  }
-  return true;
-}
-
-/**
  * Callback for route listener
  * @param route routing data
  * @param set true if route was set, false otherwise
@@ -334,13 +311,16 @@ _is_allowed_to_import(const struct os_route *route) {
 static void
 _cb_rt_event(const struct os_route *route, bool set) {
   struct _import_entry *import;
-  struct _imported_lan *lan;
   char ifname[IF_NAMESIZE];
-  struct os_route_key ssprefix;
-  int metric;
+  struct oonf_layer2_net *l2net;
+  struct oonf_layer2_neigh *l2neigh;
+  struct oonf_layer2_neighbor_address *l2neigh_ip;
+  struct oonf_layer2_neigh_key nb_key;
+  const struct netaddr *gw, *dst, *mac;
 
 #ifdef OONF_LOG_DEBUG_INFO
   struct os_route_str rbuf;
+  struct netaddr_str nbuf;
 #endif
 
   if (netaddr_is_in_subnet(&NETADDR_IPV4_MULTICAST, &route->p.key.dst) ||
@@ -358,85 +338,131 @@ _cb_rt_event(const struct os_route *route, bool set) {
   }
 
   OONF_DEBUG(
-    LOG_LAN_IMPORT, "Received route event (%s): %s", set ? "set" : "remove", os_routing_to_string(&rbuf, &route->p));
+    LOG_L2_IMPORT, "Received route event (%s): %s", set ? "set" : "remove", os_routing_to_string(&rbuf, &route->p));
 
-  if (!_is_allowed_to_import(route)) {
+  /* get interface name for route */
+  if (!route->p.if_index) {
+    /* should not happen for unicast routes */
     return;
   }
 
-  /* get interface name for route */
-  if (route->p.if_index) {
-    if_indextoname(route->p.if_index, ifname);
-  }
+  if_indextoname(route->p.if_index, ifname);
 
   avl_for_each_element(&_import_tree, import, _node) {
-    OONF_DEBUG(LOG_LAN_IMPORT, "Check for import: %s", import->name);
+    OONF_DEBUG(LOG_L2_IMPORT, "Check for import: %s", import->name);
 
     /* check prefix length */
     if (import->prefix_length != -1 && import->prefix_length != netaddr_get_prefix_length(&route->p.key.dst)) {
-      OONF_DEBUG(LOG_LAN_IMPORT, "Bad prefix length");
+      OONF_DEBUG(LOG_L2_IMPORT, "Bad prefix length %u (filter was %d)",
+                 netaddr_get_prefix_length(&route->p.key.dst), import->prefix_length);
       continue;
     }
 
     /* check if destination matches */
     if (!netaddr_acl_check_accept(&import->filter, &route->p.key.dst)) {
-      OONF_DEBUG(LOG_LAN_IMPORT, "Bad prefix");
+      OONF_DEBUG(LOG_L2_IMPORT, "Bad prefix %s", netaddr_to_string(&nbuf, &route->p.key.dst));
       continue;
     }
 
     /* check routing table */
     if (import->table != -1 && import->table != route->p.table) {
-      OONF_DEBUG(LOG_LAN_IMPORT, "Bad routing table");
+      OONF_DEBUG(LOG_L2_IMPORT, "Bad routing table %u (filter was %d)", route->p.table, import->table);
       continue;
     }
 
     /* check protocol */
     if (import->protocol != -1 && import->protocol != route->p.protocol) {
-      OONF_DEBUG(LOG_LAN_IMPORT, "Bad protocol");
+      OONF_DEBUG(LOG_L2_IMPORT, "Bad protocol %u (filter was %d)", route->p.protocol, import->protocol);
       continue;
     }
 
     /* check metric */
     if (import->distance != -1 && import->distance != route->p.metric) {
-      OONF_DEBUG(LOG_LAN_IMPORT, "Bad distance");
+      OONF_DEBUG(LOG_L2_IMPORT, "Bad distance %u (filter was %d)", route->p.metric, import->distance);
       continue;
     }
 
     /* check interface name */
     if (import->ifname[0]) {
       if (route->p.if_index == 0) {
-        OONF_DEBUG(LOG_LAN_IMPORT, "Route has no interface");
+        OONF_DEBUG(LOG_L2_IMPORT, "Route has no interface");
         continue;
       }
       if (strcmp(import->ifname, ifname) != 0) {
-        OONF_DEBUG(LOG_LAN_IMPORT, "Bad interface");
+        OONF_DEBUG(LOG_L2_IMPORT, "Bad interface '%s' (filter was '%s')", ifname, import->ifname);
         continue;
       }
     }
 
-    memcpy(&ssprefix.dst, &route->p.key.dst, sizeof(struct netaddr));
-    memcpy(&ssprefix.src, &route->p.key.src, sizeof(struct netaddr));
-
+    /* get layer2 network */
     if (set) {
-      metric = route->p.metric;
-      if (metric < 1) {
-        metric = 1;
+      l2net = oonf_layer2_net_add(ifname);
+    }
+    else {
+      l2net = oonf_layer2_net_get(ifname);
+    }
+    if (!l2net) {
+      OONF_DEBUG(LOG_L2_IMPORT, "No l2 network found");
+      return;
+    }
+
+    mac = NULL;
+    if (import->fixed_mac_if[0]) {
+      if (import->fixed_if_listener.data) {
+        mac = &import->fixed_if_listener.data->mac;
       }
-      if (metric > 255) {
-        metric = 255;
+    }
+    else {
+      mac = &l2net->if_listener.data->mac;
+    }
+    if (netaddr_is_unspec(mac)) {
+      OONF_DEBUG(LOG_L2_IMPORT, "Wait for interface data to be initialized");
+      if (!oonf_timer_is_active(&_route_reload_instance)) {
+        oonf_timer_set(&_route_reload_instance, 1000);
       }
+      return;
+    }
+
+    dst = &route->p.key.dst;
+    gw = &route->p.gw;
 
-      OONF_DEBUG(LOG_LAN_IMPORT, "Add lan...");
-      lan = _add_lan(import, &ssprefix, import->routing_metric, metric);
-      if (lan && import->metric_aging) {
-        oonf_timer_set(&lan->_aging_timer, import->metric_aging);
+    /* 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;
+    }
+
+    /* get layer2 neighbor */
+    if (set) {
+      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;
+    }
+
+    /* make sure next hop is initialized */
+    if (!oonf_layer2_neigh_set_nexthop(l2neigh, gw)) {
+      oonf_layer2_neigh_commit(l2neigh);
+    }
+
+    if (set) {
+      OONF_DEBUG(LOG_L2_IMPORT, "Add lan...");
+
+      if (!oonf_layer2_neigh_get_remote_ip(l2neigh, dst)) {
+        oonf_layer2_neigh_add_ip(l2neigh, &import->l2origin, dst);
       }
     }
     else {
-      OONF_DEBUG(LOG_LAN_IMPORT, "Remove lan...");
-      lan = avl_find_element(&import->imported_lan_tree, &ssprefix, lan, _node);
-      if (lan) {
-        _destroy_lan(lan);
+      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);
       }
     }
   }
@@ -462,11 +488,20 @@ _get_import(const char *name) {
   }
 
   /* copy key and add to tree */
-  strscpy(import->name, name, sizeof(import->name));
+  snprintf(import->name, sizeof(import->name), LAN_ORIGIN_PREFIX "%s", name);
   import->_node.key = import->name;
   avl_insert(&_import_tree, &import->_node);
 
-  avl_init(&import->imported_lan_tree, os_routing_avl_cmp_route_key, false);
+  /* request layer2 origin */
+  import->l2origin.name = import->name;
+  import->l2origin.priority = OONF_LAYER2_ORIGIN_RELIABLE;
+  import->l2origin.proactive = true;
+  import->l2origin.lid = true;
+
+  oonf_layer2_origin_add(&import->l2origin);
+
+  /* initialize l2 fixed interface listener */
+  import->fixed_if_listener.name = import->fixed_mac_if;
 
   return import;
 }
@@ -476,142 +511,83 @@ _get_import(const char *name) {
  * @param import import entry
  */
 static void
-_destroy_import(struct _import_entry *import) {
+_remove_import(struct _import_entry *import) {
+  oonf_layer2_origin_remove(&import->l2origin);
   avl_remove(&_import_tree, &import->_node);
   netaddr_acl_remove(&import->filter);
   oonf_class_free(&_import_class, import);
 }
 
-static struct _imported_lan *
-_add_lan(struct _import_entry *import, struct os_route_key *key, uint32_t metric, uint8_t distance) {
-  struct nhdp_domain *domain;
-  struct _imported_lan *lan;
-
-  lan = avl_find_element(&import->imported_lan_tree, key, lan, _node);
-  if (lan) {
-    return lan;
-  }
-
-  lan = oonf_class_malloc(&_lan_import_class);
-  if (!lan) {
-    return NULL;
-  }
-
-  memcpy(&lan->key, key, sizeof(*key));
-  lan->_node.key = &lan->key;
-  avl_insert(&import->imported_lan_tree, &lan->_node);
-
-  lan->import = import;
-  lan->_aging_timer.class = &_aging_timer_class;
-
-  list_for_each_element(nhdp_domain_get_list(), domain, _node) {
-    if (import->domain == -1 || import->domain == domain->ext) {
-      olsrv2_lan_add(domain, key, metric, distance);
-    }
-  }
-
-  return lan;
-}
-
 static void
-_destroy_lan(struct _imported_lan *lan) {
-  struct nhdp_domain *domain;
-
-  list_for_each_element(nhdp_domain_get_list(), domain, _node) {
-    if (lan->import->domain == -1 || lan->import->domain == domain->ext) {
-      olsrv2_lan_remove(domain, &lan->key);
-    }
-  }
-
-  avl_remove(&lan->import->imported_lan_tree, &lan->_node);
-  oonf_class_free(&_lan_import_class, lan);
-}
-
-static void
-_cb_metric_aging(struct oonf_timer_instance *entry) {
-  struct olsrv2_lan_entry *lan_entry;
-  struct nhdp_domain *domain;
-  struct olsrv2_lan_domaindata *landata;
-  struct _imported_lan *lan;
-
-  lan = container_of(entry, struct _imported_lan, _aging_timer);
-  lan_entry = olsrv2_lan_get(&lan->key);
-  if (lan_entry) {
-    list_for_each_element(nhdp_domain_get_list(), domain, _node) {
-      if (lan->import->domain == -1 || lan->import->domain == domain->ext) {
-        landata = olsrv2_lan_get_domaindata(domain, lan_entry);
-        if (landata->outgoing_metric >= RFC7181_METRIC_MAX / 2) {
-          landata->outgoing_metric = RFC7181_METRIC_MAX;
-          oonf_timer_stop(entry);
-        }
-        else {
-          landata->outgoing_metric *= 2;
-        }
-      }
-    }
+_cb_reload_routes(struct oonf_timer_instance *timer __attribute__((unused))) {
+  /* trigger wildcard query */
+  if (!os_routing_is_in_progress(&_unicast_query)) {
+    os_routing_query(&_unicast_query);
   }
 }
 
 /**
- * interface section changed
+ * Configuration changed
  */
 static void
-_cb_cfg_interface_changed(void) {
-  struct _import_entry *import;
+_cb_lan_cfg_changed(void) {
+  char name[20];
 
-  if (_interface_section.pre || !_interface_section.post) {
-    /* only check for new sections */
-    return;
-  }
+  snprintf(name, sizeof(name), LAN_ORIGIN_PREFIX "%s", _lan_import_section.section_name);
+  _cb_cfg_changed(&_lan_import_section, name);
+}
 
-  avl_for_each_element(&_import_tree, import, _node) {
-    if (import->ifname[0] && strcmp(import->ifname, _interface_section.section_name) == 0) {
-      OONF_WARN(LOG_LAN_IMPORT, "Mesh interface %s cannot be used for LAN IMPORT",
-                _interface_section.section_name);
-    }
-  }
+static void
+_cb_l2_cfg_changed(void) {
+  char name[20];
+
+  snprintf(name, sizeof(name), L2IMPORT_ORIGIN_PREFIX "%s", _l2_import_section.section_name);
+  _cb_cfg_changed(&_l2_import_section, name);
 }
 
 /**
  * Configuration changed
  */
 static void
-_cb_cfg_changed(void) {
+_cb_cfg_changed(struct cfg_schema_section *section, char *section_name) {
   struct _import_entry *import;
 
-  if (_import_section.post && !_import_section.pre) {
-    if (nhdp_interface_get(_import_section.section_name)) {
-      OONF_WARN(LOG_LAN_IMPORT, "Mesh interface %s cannot be used for LAN IMPORT",
-                _import_section.section_name);
-    }
-  }
-
   /* get existing modifier */
-  import = _get_import(_import_section.section_name);
+  import = _get_import(section_name);
   if (!import) {
     /* out of memory */
     return;
   }
 
-  if (_import_section.post == NULL) {
+  if (section->post == NULL) {
     /* section was removed */
-    _destroy_import(import);
+    _remove_import(import);
     return;
   }
 
-  if (cfg_schema_tobin(import, _import_section.post, _import_entries, ARRAYSIZE(_import_entries))) {
-    OONF_WARN(LOG_LAN_IMPORT, "Could not convert configuration data of section '%s'", _import_section.section_name);
+  /* remove old interface listener */
+  os_interface_remove(&import->fixed_if_listener);
 
-    if (_import_section.pre == NULL) {
-      _destroy_import(import);
+  if (cfg_schema_tobin(import, section->post, section->entries, section->entry_count)) {
+    OONF_WARN(LOG_L2_IMPORT, "Could not convert configuration data of section '%s'", section->section_name);
+
+    if (section->pre == NULL) {
+      _remove_import(import);
     }
     return;
   }
 
   cfg_get_phy_if(import->ifname, import->ifname);
+  cfg_get_phy_if(import->fixed_mac_if, import->fixed_mac_if);
 
-  /* trigger wildcard query */
-  if (!os_routing_is_in_progress(&_unicast_query)) {
-    os_routing_query(&_unicast_query);
+  if (!import->fixed_mac_if[0]) {
+    strscpy(import->fixed_mac_if, import->ifname, IF_NAMESIZE);
+  }
+  if (import->fixed_mac_if[0]) {
+    os_interface_add(&import->fixed_if_listener);
+  }
+
+  if (!oonf_timer_is_active(&_route_reload_instance)) {
+    oonf_timer_set(&_route_reload_instance, 1000);
   }
 }
  * @file
  */
 
-#ifndef LAN_IMPORT_H_
-#define LAN_IMPORT_H_
+#ifndef LAYER2_IMPORT_H_
+#define LAYER2_IMPORT_H_
 
 /*! subsystem identifier */
-#define OONF_LAN_IMPORT_SUBSYSTEM "lan_import"
+#define OONF_LAYER2_IMPORT_SUBSYSTEM "layer2_import"
 
-#endif /* LAN_IMPORT_H_ */
+#define OONF_LAN_IMPORT_SECTION "lan_import"
+
+/*! prefix for the names of the layer2 origins */
+#define LAN_ORIGIN_PREFIX "lan-"
+#define L2IMPORT_ORIGIN_PREFIX "l2i-"
+
+#endif /* LAYER2_IMPORT_H_ */
index 0651a1c..c4e6635 100644 (file)
@@ -133,12 +133,21 @@ static int _cb_create_text_dst(struct oonf_viewer_template *);
 /*! template key for neighbor link-id length */
 #define KEY_NEIGH_LID_LEN "neigh_lid_length"
 
+/*! template key for neighbor IPv4 next hop */
+#define KEY_NEIGH_NEXTHOP_V4 "neigh_nexthop_v4"
+
+/*! template key for neighbor IPv4 next hop */
+#define KEY_NEIGH_NEXTHOP_V6 "neigh_nexthop_v6"
+
 /*! template key for last time neighbor was active */
 #define KEY_NEIGH_LASTSEEN "neigh_lastseen"
 
 /*! template key for IP/prefixes of the neighbors remote router */
 #define KEY_NEIGH_REMOTE_IP "neigh_remote_ip"
 
+/*! template key for neighbors IP next hop */
+#define KEY_NEIGH_REMOTE_NEXTHOP "neigh_remote_ip_nexthop"
+
 /*! template key for IP/prefixes origin of the neighbors remote router */
 #define KEY_NEIGH_REMOTE_IP_ORIGIN "neigh_remote_ip_origin"
 
@@ -175,9 +184,12 @@ static char _value_if_data[OONF_LAYER2_NET_COUNT][64];
 static char _value_if_origin[OONF_LAYER2_NET_COUNT][IF_NAMESIZE];
 static struct netaddr_str _value_neigh_addr;
 static union oonf_layer2_neigh_key_str _value_neigh_key;
+static struct netaddr_str _value_neigh_nexthop_v4;
+static struct netaddr_str _value_neigh_nexthop_v6;
 static char _value_neigh_key_length[6];
 static struct isonumber_str _value_neigh_lastseen;
 static struct netaddr_str _value_neigh_remote_ip;
+static struct netaddr_str _value_neigh_remote_ip_nexthop;
 static char _value_neigh_remote_ip_origin[IF_NAMESIZE];
 static char _value_neigh_data[OONF_LAYER2_NEIGH_COUNT][64];
 static char _value_neigh_origin[OONF_LAYER2_NEIGH_COUNT][IF_NAMESIZE];
@@ -215,11 +227,14 @@ static struct abuf_template_data_entry _tde_neigh_key[] = {
 };
 
 static struct abuf_template_data_entry _tde_neigh[] = {
+  { KEY_NEIGH_NEXTHOP_V4, _value_neigh_nexthop_v4.buf, true },
+  { KEY_NEIGH_NEXTHOP_V6, _value_neigh_nexthop_v6.buf, true },
   { KEY_NEIGH_LASTSEEN, _value_neigh_lastseen.buf, false },
 };
 
 static struct abuf_template_data_entry _tde_neigh_remote_ip[] = {
   { KEY_NEIGH_REMOTE_IP, _value_neigh_remote_ip.buf, true },
+  { KEY_NEIGH_REMOTE_NEXTHOP, _value_neigh_remote_ip_nexthop.buf, true },
   { KEY_NEIGH_REMOTE_IP_ORIGIN, _value_neigh_remote_ip_origin, true },
 };
 
@@ -497,8 +512,11 @@ _initialize_neigh_values(struct oonf_layer2_neigh *neigh) {
   oonf_layer2_neigh_key_to_string(&_value_neigh_key, &neigh->key, false);
   snprintf(_value_neigh_key_length, sizeof(_value_neigh_key_length), "%u", neigh->key.link_id_length);
 
-  if (neigh->last_seen) {
-    oonf_clock_toIntervalString(&_value_neigh_lastseen, -oonf_clock_get_relative(neigh->last_seen));
+  netaddr_to_string(&_value_neigh_nexthop_v4, oonf_layer2_neigh_get_nexthop(neigh, AF_INET));
+  netaddr_to_string(&_value_neigh_nexthop_v6, oonf_layer2_neigh_get_nexthop(neigh, AF_INET6));
+
+  if (oonf_layer2_neigh_get_lastseen(neigh)) {
+    oonf_clock_toIntervalString(&_value_neigh_lastseen, -oonf_clock_get_relative(oonf_layer2_neigh_get_lastseen(neigh)));
   }
   else {
     _value_neigh_lastseen.buf[0] = 0;
@@ -512,6 +530,8 @@ _initialize_neigh_values(struct oonf_layer2_neigh *neigh) {
 static void
 _initialize_neigh_ip_values(struct oonf_layer2_neighbor_address *neigh_addr) {
   netaddr_to_string(&_value_neigh_remote_ip, &neigh_addr->ip);
+  netaddr_to_string(&_value_neigh_remote_ip_nexthop,
+      oonf_layer2_neigh_get_nexthop(neigh_addr->l2neigh, netaddr_get_address_family(&neigh_addr->ip)));
   strscpy(_value_neigh_remote_ip_origin, neigh_addr->origin->name, sizeof(_value_neigh_remote_ip_origin));
 }
 
index 8dda903..d3866e7 100644 (file)
@@ -168,7 +168,8 @@ nl80211_process_get_station_dump_result(struct nl80211_if *interf, struct nlmsgh
   }
 
   if (sinfo[NL80211_STA_INFO_INACTIVE_TIME]) {
-    l2neigh->last_seen = oonf_clock_get_absolute(-((int64_t)(nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME]))));
+    oonf_layer2_neigh_set_lastseen(l2neigh,
+        oonf_clock_get_absolute(-((int64_t)(nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME])))));
   }
 
   /* byte data is 64 bit */
index 0840cc6..a712de9 100644 (file)
@@ -919,6 +919,23 @@ nhdp_domain_set_incoming_metric(struct nhdp_domain_metric *metric, struct nhdp_l
 }
 
 /**
+ * Calculate the metric cost of a link defined by a layer2 neighbor.
+ * The function will not change or initialize the target buffer if the result
+ * is a NHDP_METRIC_NOT_AVAILABLE.
+ * @param domain nhdp domain the metric calculation should be based upon
+ * @param metric pointer to target buffer for metric result
+ * @param neigh layer2 neighbor
+ * @return status of metric calculation
+ */
+enum nhdp_metric_result
+nhdp_domain_get_metric(struct nhdp_domain *domain, uint32_t *metric, struct oonf_layer2_neigh *neigh) {
+  if (!domain->metric->cb_get_metric) {
+    return NHDP_METRIC_NOT_AVAILABLE;
+  }
+  return domain->metric->cb_get_metric(domain, metric, neigh);
+}
+
+/**
  * @return list of domains
  */
 struct list_entity *
index 689ced4..676d839 100644 (file)
@@ -57,6 +57,8 @@
 /*! memory class for nhdp domain */
 #define NHDP_CLASS_DOMAIN "nhdp_domain"
 
+struct nhdp_domain;
+
 /**
  * NHDP domain constants
  */
@@ -70,6 +72,20 @@ enum
 };
 
 /**
+ * Result of a metric calculation based on a layer2 neighbor
+ */
+enum nhdp_metric_result {
+  /*! metric has been calculated normally */
+  NHDP_METRIC_OKAY,
+
+  /*! metric has been calculated, but some data has been missing */
+  NHDP_METRIC_PARTIAL_DATA,
+
+  /*! metric could not be calculated */
+  NHDP_METRIC_NOT_AVAILABLE,
+};
+
+/**
  * Buffer for string representation of a linkmetric value
  */
 struct nhdp_metric_str {
@@ -153,6 +169,15 @@ struct nhdp_domain_metric {
    */
   void (*disable)(void);
 
+  /**
+   * Calculate the metric cost of a link defined by a layer2 neighbor
+   * @param domain nhdp domain the metric calculation should be based upon
+   * @param metric pointer to target buffer for metric result
+   * @param neigh layer2 neighbor
+   * @return status of metric calculation
+   */
+  enum nhdp_metric_result (*cb_get_metric)(struct nhdp_domain *domain, uint32_t *metric, struct oonf_layer2_neigh *neigh);
+
   /*! reference count */
   int _refcount;
 
@@ -160,8 +185,6 @@ struct nhdp_domain_metric {
   struct avl_node _node;
 };
 
-struct nhdp_domain;
-
 /**
  * MPR handler for a NHDP domain
  */
@@ -319,6 +342,7 @@ EXPORT size_t nhdp_domain_encode_willingness_tlvvalue(uint8_t *tlvvalue, size_t
 EXPORT bool nhdp_domain_set_incoming_metric(
   struct nhdp_domain_metric *metric, struct nhdp_link *lnk, uint32_t metric_in);
 EXPORT bool nhdp_domain_recalculate_metrics(struct nhdp_domain *domain, struct nhdp_neighbor *neigh);
+EXPORT enum nhdp_metric_result nhdp_domain_get_metric(struct nhdp_domain *domain, uint32_t *metric, struct oonf_layer2_neigh *neigh);
 
 EXPORT bool nhdp_domain_node_is_mpr(void);
 EXPORT void nhdp_domain_delayed_mpr_recalculation(struct nhdp_domain *domain, struct nhdp_neighbor *neigh);
index a85cf81..2a67695 100644 (file)
@@ -1,9 +1,9 @@
 # add subdirectories
 add_subdirectory(netjsoninfo)
-add_subdirectory(lan_import)
 add_subdirectory(olsrv2)
 add_subdirectory(olsrv2info)
 add_subdirectory(olsrv2_old_lan)
+add_subdirectory(olsrv2_l2import)
 add_subdirectory(olsrv2_lan)
 add_subdirectory(route_modifier)
 
diff --git a/src-plugins/olsrv2/olsrv2_l2import/CMakeLists.txt b/src-plugins/olsrv2/olsrv2_l2import/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c4113ff
--- /dev/null
@@ -0,0 +1,5 @@
+# set library parameters
+SET (name olsrv2_l2import)
+
+# use generic plugin maker
+oonf_create_plugin("${name}" "${name}.c" "${name}.h" "")
diff --git a/src-plugins/olsrv2/olsrv2_l2import/olsrv2_l2import.c b/src-plugins/olsrv2/olsrv2_l2import/olsrv2_l2import.c
new file mode 100644 (file)
index 0000000..ae87019
--- /dev/null
@@ -0,0 +1,353 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
+ * Copyright (c) 2004-2015, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <errno.h>
+
+#include "common/avl.h"
+#include "common/avl_comp.h"
+#include "common/common_types.h"
+#include "common/netaddr.h"
+#include "config/cfg_schema.h"
+#include "core/oonf_logging.h"
+#include "core/oonf_subsystem.h"
+#include "subsystems/oonf_class.h"
+#include "layer2_import/layer2_import.h"
+#include "olsrv2/olsrv2_lan.h"
+
+#include "olsrv2_l2import/olsrv2_l2import.h"
+
+/*! logging for plugin */
+#define LOG_L2IMPORT _l2import_subsystem.logging
+
+/*! locally attached network option for source-specific prefix */
+#define LAN_DEFAULT_DOMAIN -1
+
+/**
+ * Additional parameters of an imported layer2 network
+ */
+struct _l2export_data {
+  /*! originator to import, defined as the section name */
+  char originator[24];
+
+  /*! domain for import, -1 for all domains */
+  int32_t domain;
+
+  /*! routing metric for import, -1 to attempt calculating from layer2 database */
+  int32_t routing_metric;
+
+  /*! fib distance entry for import */
+  int32_t fib_distance;
+
+  /*! node to hold all l2imports together */
+  struct avl_node _node;
+};
+
+/* prototypes */
+static int _init(void);
+static void _cleanup(void);
+
+static struct _l2export_data *_get_l2export(const char *name);
+static void _destroy_l2export(struct _l2export_data *);
+static bool _is_matching_origin(struct oonf_layer2_neighbor_address *, const char *pattern);
+
+static void _remove_l2neighip_lans(struct oonf_layer2_neighbor_address *nip);
+
+static void _cb_l2neigh_ip_added(void *);
+static void _cb_l2neigh_ip_removed(void *);
+
+static void _cb_cfg_changed(void);
+
+static struct cfg_schema_entry _l2import_entries[] = {
+  CFG_MAP_INT32_MINMAX(_l2export_data, domain, "domain", "-1",
+      "domain for the imported LAN entries, -1 for all domains", 0, -1, 255),
+  CFG_MAP_INT32_MINMAX(_l2export_data, routing_metric, "metric", "-1",
+      "routing metric for the imported LAN entries, -1 to calculate from layer2 data", 0, -1, RFC7181_METRIC_MAX),
+  CFG_MAP_INT32_MINMAX(_l2export_data, fib_distance, "fib_distance", "2",
+      "fib distance for imported LAN entries, -1 for all domains", 0, 1, 255),
+};
+
+static struct cfg_schema_section _l2import_section = {
+  .type = OONF_OLSRV2_L2IMPORT_SUBSYSTEM,
+  .mode = CFG_SSMODE_NAMED_WITH_DEFAULT,
+  .def_name = LAN_ORIGIN_PREFIX "*",
+
+  .cb_delta_handler = _cb_cfg_changed,
+  .entries = _l2import_entries,
+  .entry_count = ARRAYSIZE(_l2import_entries),
+};
+
+static const char *_dependencies[] = {
+  OONF_OLSRV2_SUBSYSTEM,
+};
+static struct oonf_subsystem _l2import_subsystem = {
+  .name = OONF_OLSRV2_L2IMPORT_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
+  .init = _init,
+  .cleanup = _cleanup,
+  .cfg_section = &_l2import_section,
+};
+DECLARE_OONF_PLUGIN(_l2import_subsystem);
+
+/*! tree to remember all imported layer2 originators */
+static struct avl_tree _l2export_tree;
+
+/* class definition for filters */
+static struct oonf_class _l2export_class = {
+  .name = "olsrv2 l2import",
+  .size = sizeof(struct _l2export_data),
+};
+
+static struct oonf_class_extension _l2neighip_ext = {
+  .ext_name = "l2import listener",
+  .class_name = LAYER2_CLASS_NEIGHBOR_ADDRESS,
+
+  .cb_add = _cb_l2neigh_ip_added,
+  .cb_remove = _cb_l2neigh_ip_removed,
+};
+
+/* tree of routing filters */
+static struct avl_tree _l2export_tree;
+
+/**
+ * Initialize plugin
+ * @return always returns 0 (cannot fail)
+ */
+static int
+_init(void) {
+  if (oonf_class_extension_add(&_l2neighip_ext)) {
+    return -1;
+  }
+  avl_init(&_l2export_tree, avl_comp_strcasecmp, false);
+  oonf_class_add(&_l2export_class);
+  return 0;
+}
+
+/**
+ * Cleanup plugin
+ */
+static void
+_cleanup(void) {
+  struct _l2export_data *mod, *mod_it;
+
+  avl_for_each_element_safe(&_l2export_tree, mod, _node, mod_it) {
+        _destroy_l2export(mod);
+  }
+
+  oonf_class_remove(&_l2export_class);
+  oonf_class_extension_remove(&_l2neighip_ext);
+}
+
+/**
+ * Lookups a layer2 import or create a new one
+ * @param name name of layer2 import
+ * @return pointer to import data or NULL if out of memory
+ */
+static struct _l2export_data *
+_get_l2export(const char *name) {
+  struct _l2export_data *mod;
+
+  mod = avl_find_element(&_l2export_tree, name, mod, _node);
+  if (mod) {
+    return mod;
+  }
+
+  mod = oonf_class_malloc(&_l2export_class);
+  if (mod == NULL) {
+    return NULL;
+  }
+
+  /* copy key and add to tree */
+  strscpy(mod->originator, name, sizeof(mod->originator));
+  mod->_node.key = mod->originator;
+  avl_insert(&_l2export_tree, &mod->_node);
+
+  return mod;
+}
+
+/**
+ * Free all resources associated with a layer2 import
+ * @param l2import layer2 import
+ */
+static void
+_destroy_l2export(struct _l2export_data *l2import) {
+  struct oonf_layer2_neighbor_address *l2nip;
+  struct oonf_layer2_neigh *l2neigh;
+  struct oonf_layer2_net *l2net;
+
+  /* first remove the import settings from the tree */
+  avl_remove(&_l2export_tree, &l2import->_node);
+
+  avl_for_each_element(oonf_layer2_get_net_tree(), l2net, _node) {
+    avl_for_each_element(&l2net->neighbors, l2neigh, _node) {
+      avl_for_each_element(&l2neigh->remote_neighbor_ips, l2nip, _neigh_node) {
+        if (strcmp(l2nip->origin->name, l2import->originator) == 0) {
+          _remove_l2neighip_lans(l2nip);
+        }
+      }
+    }
+  }
+
+  // TODO: iterate over the l2 database if we need to remove something from the olsrv2 LAN database
+  oonf_class_free(&_l2export_class, l2import);
+}
+
+static bool
+_is_matching_origin(struct oonf_layer2_neighbor_address *addr, const char *pattern) {
+  int len;
+
+  if (strcmp(addr->origin->name, pattern) == 0) {
+    return true;
+  }
+
+  len = strlen(pattern);
+  if (len == 0 || pattern[len-1] != '*') {
+    return false;
+  }
+
+  return strncmp(addr->origin->name, pattern, len-1) == 0;
+}
+
+static void
+_remove_l2neighip_lans(struct oonf_layer2_neighbor_address *nip) {
+  struct _l2export_data *l2import;
+  struct os_route_key rt_key;
+  struct nhdp_domain *domain;
+
+  os_routing_init_sourcespec_prefix(&rt_key, &nip->ip);
+
+  avl_for_each_element(&_l2export_tree, l2import, _node) {
+    if (_is_matching_origin(nip, l2import->originator)) {
+      if (l2import->domain >= 0) {
+        domain = nhdp_domain_get_by_ext(l2import->domain);
+        olsrv2_lan_remove(domain, &rt_key);
+      }
+      else {
+        list_for_each_element(nhdp_domain_get_list(), domain, _node) {
+          olsrv2_lan_remove(domain, &rt_key);
+        }
+      }
+    }
+  }
+}
+
+static void
+_cb_l2neigh_ip_added(void *ptr) {
+  struct oonf_layer2_neighbor_address *nip = ptr;
+  struct _l2export_data *l2import;
+  struct os_route_key rt_key;
+  struct nhdp_domain *domain;
+  uint32_t metric;
+  int32_t distance;
+  os_routing_init_sourcespec_prefix(&rt_key, &nip->ip);
+
+  avl_for_each_element(&_l2export_tree, l2import, _node) {
+    if (_is_matching_origin(nip, l2import->originator)) {
+      distance = l2import->fib_distance;
+
+      if (l2import->domain >= 0) {
+        domain = nhdp_domain_get_by_ext(l2import->domain);
+        metric = 1;
+        if (l2import->routing_metric < RFC7181_METRIC_MIN) {
+          nhdp_domain_get_metric(domain, &metric, nip->l2neigh);
+        }
+        else {
+          metric = l2import->routing_metric;
+        }
+
+        olsrv2_lan_add(domain, &rt_key, metric , distance);
+      }
+      else {
+        list_for_each_element(nhdp_domain_get_list(), domain, _node) {
+          metric = 1;
+          if (l2import->routing_metric < RFC7181_METRIC_MIN) {
+            nhdp_domain_get_metric(domain, &metric, nip->l2neigh);
+          }
+          else {
+            metric = l2import->routing_metric;
+          }
+
+          olsrv2_lan_add(domain, &rt_key, metric , distance);
+        }
+      }
+    }
+  }
+}
+
+static void
+_cb_l2neigh_ip_removed(void *ptr) {
+  _remove_l2neighip_lans(ptr);
+}
+
+/**
+ * Configuration changed
+ */
+static void
+_cb_cfg_changed(void) {
+  struct _l2export_data *l2import;
+
+  /* get existing import */
+  l2import = _get_l2export(_l2import_section.section_name);
+  if (!l2import) {
+    /* out of memory */
+    return;
+  }
+
+  if (!_l2import_section.post) {
+    /* section was removed */
+        _destroy_l2export(l2import);
+    return;
+  }
+
+  if (cfg_schema_tobin(l2import, _l2import_section.post, _l2import_entries, ARRAYSIZE(_l2import_entries))) {
+    OONF_WARN(LOG_L2IMPORT,
+        "Could not convert configuration data of section '%s'", _l2import_section.section_name);
+
+    if (!_l2import_section.pre) {
+            _destroy_l2export(l2import);
+    }
+    return;
+  }
+
+  if (!_l2import_section.pre) {
+    // TODO: iterate over the l2 database if we need to remove something from the olsrv2 LAN database
+  }
+}
diff --git a/src-plugins/olsrv2/olsrv2_l2import/olsrv2_l2import.h b/src-plugins/olsrv2/olsrv2_l2import/olsrv2_l2import.h
new file mode 100644 (file)
index 0000000..4a89550
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * olsrv2_l2import.h
+ *
+ *  Created on: 18.10.2017
+ *      Author: rogge
+ */
+
+#ifndef _OLSRV2_L2IMPORT_H_
+#define _OLSRV2_L2IMPORT_H_
+
+#define OONF_OLSRV2_L2IMPORT_SUBSYSTEM "olsrv2_l2import"
+
+#endif /* _OLSRV2_L2IMPORT_H_ */
index 6bd4291..28c1cd9 100644 (file)
@@ -878,12 +878,14 @@ oonf_layer2_neigh_commit(struct oonf_layer2_neigh *l2neigh) {
 
   if (l2neigh->destinations.count > 0 || l2neigh->remote_neighbor_ips.count > 0) {
     oonf_class_event(&_l2neighbor_class, l2neigh, OONF_OBJECT_CHANGED);
+    l2neigh->modified = OONF_LAYER2_NEIGH_MODIFY_NONE;
     return false;
   }
 
   for (i = 0; i < OONF_LAYER2_NEIGH_COUNT; i++) {
     if (oonf_layer2_data_has_value(&l2neigh->data[i])) {
       oonf_class_event(&_l2neighbor_class, l2neigh, OONF_OBJECT_CHANGED);
+      l2neigh->modified = OONF_LAYER2_NEIGH_MODIFY_NONE;
       return false;
     }
   }
@@ -925,6 +927,41 @@ oonf_layer2_neigh_relabel(struct oonf_layer2_neigh *l2neigh, const struct oonf_l
 }
 
 /**
+* Sets the (ip) next hop of a neighbor, you should call oonf_layer2_neigh_commit after a
+* successful change.
+* @param neigh layer2 neighbor
+* @param nexthop next hop, should be IPv4 or IPv6
+* @return -1 if nothing was changed, 0 if the next hop was updated.
+*/
+int
+oonf_layer2_neigh_set_nexthop(struct oonf_layer2_neigh *neigh, const struct netaddr *nexthop) {
+  enum oonf_layer2_neigh_mods mod;
+  struct netaddr *nh;
+
+  switch (netaddr_get_address_family(nexthop)) {
+    case AF_INET:
+      nh = &neigh->_next_hop_v4;
+      mod = OONF_LAYER2_NEIGH_MODIFY_NEXTHOP_V4;
+      break;
+    case AF_INET6:
+      nh = &neigh->_next_hop_v6;
+      mod = OONF_LAYER2_NEIGH_MODIFY_NEXTHOP_V6;
+      break;
+    default:
+      return -1;
+  }
+
+  if (memcmp(nh, nexthop, sizeof(*nexthop)) == 0) {
+    return -1;
+  }
+
+  memcpy(nh, nexthop, sizeof(*nexthop));
+  neigh->modified |= mod;
+  return 0;
+}
+
+
+/**
  * Add an IP address or prefix to a layer-2 interface. This represents
  * an address of the local radio or modem.
  * @param l2neigh layer-2 neighbor object
index 88d9d9a..8d19992 100644 (file)
@@ -487,6 +487,13 @@ union oonf_layer2_neigh_key_str {
   char buf[sizeof(struct netaddr_str) + 5 + 16*2];
 };
 
+enum oonf_layer2_neigh_mods {
+  OONF_LAYER2_NEIGH_MODIFY_NONE       = 0,
+  OONF_LAYER2_NEIGH_MODIFY_NEXTHOP_V4 = 1<<0,
+  OONF_LAYER2_NEIGH_MODIFY_NEXTHOP_V6 = 1<<1,
+  OONF_LAYER2_NEIGH_MODIFY_LASTSEEN   = 1<<2,
+};
+
 /**
  * representation of a remote layer2 neighbor
  */
@@ -497,6 +504,15 @@ struct oonf_layer2_neigh {
   /*! back pointer to layer2 network */
   struct oonf_layer2_net *network;
 
+  /*! fields modified since last commit */
+  enum oonf_layer2_neigh_mods modified;
+
+  /* (linklocal) ip address to read neighbor with IPv4 */
+  struct netaddr _next_hop_v4;
+
+  /* (linklocal) ip address to read neighbor with IPv6 */
+  struct netaddr _next_hop_v6;
+
   /*! tree of proxied destinations */
   struct avl_tree destinations;
 
@@ -504,7 +520,7 @@ struct oonf_layer2_neigh {
   struct avl_tree remote_neighbor_ips;
 
   /*! absolute timestamp when neighbor has been active last */
-  uint64_t last_seen;
+  uint64_t _last_seen;
 
   /*! neigbor layer 2 data */
   struct oonf_layer2_data data[OONF_LAYER2_NEIGH_COUNT];
@@ -593,6 +609,7 @@ EXPORT bool oonf_layer2_neigh_remove(struct oonf_layer2_neigh *l2neigh, const st
 EXPORT bool oonf_layer2_neigh_commit(struct oonf_layer2_neigh *l2neigh);
 EXPORT void oonf_layer2_neigh_relabel(struct oonf_layer2_neigh *l2neigh, const struct oonf_layer2_origin *new_origin,
   const struct oonf_layer2_origin *old_origin);
+EXPORT int oonf_layer2_neigh_set_nexthop(struct oonf_layer2_neigh *neigh, const struct netaddr *nexthop);
 EXPORT struct oonf_layer2_neighbor_address *oonf_layer2_neigh_add_ip(
   struct oonf_layer2_neigh *l2neigh, const struct oonf_layer2_origin *origin, const struct netaddr *ip);
 EXPORT int oonf_layer2_neigh_remove_ip(
@@ -705,6 +722,44 @@ oonf_layer2_neigh_get_lid(const struct oonf_layer2_net *l2net, const struct oonf
   return avl_find_element(&l2net->neighbors, key, l2neigh, _node);
 }
 
+static INLINE bool
+oonf_layer2_neigh_is_modified(const struct oonf_layer2_neigh *neigh, enum oonf_layer2_neigh_mods mod_mask) {
+  return (neigh->modified & mod_mask) != 0;
+}
+
+static INLINE const struct netaddr *
+oonf_layer2_neigh_get_nexthop(const struct oonf_layer2_neigh *neigh, int af_type) {
+  switch (af_type) {
+    case AF_INET:
+      return &neigh->_next_hop_v4;
+    case AF_INET6:
+      return &neigh->_next_hop_v6;
+    default:
+      return NULL;
+  }
+}
+
+static INLINE bool
+oonf_layer2_neigh_has_nexthop(const struct oonf_layer2_neigh *neigh, int af_type) {
+  const struct netaddr *next_hop;
+
+  next_hop = oonf_layer2_neigh_get_nexthop(neigh, af_type);
+  return next_hop != NULL && netaddr_get_address_family(next_hop) == af_type;
+}
+
+static INLINE uint64_t
+oonf_layer2_neigh_get_lastseen(const struct oonf_layer2_neigh *neigh) {
+  return neigh->_last_seen;
+}
+
+static INLINE void
+oonf_layer2_neigh_set_lastseen(struct oonf_layer2_neigh *neigh, uint64_t lastseen) {
+  if (neigh->_last_seen != lastseen) {
+    neigh->_last_seen = lastseen;
+    neigh->modified |= OONF_LAYER2_NEIGH_MODIFY_LASTSEEN;
+  }
+}
+
 /**
  * Get a layer-2 ip address object from the database
  * @param l2neigh layer-2 neighbor object
index c555126..529fa63 100644 (file)
@@ -40,10 +40,12 @@ IF (NOT OONF_STATIC_PLUGINS)
                              os_fd
                              os_interface
                              os_system
+                             os_routing
                              cfg_compact
                              layer2info
                              systeminfo
                              layer2_config
+                             layer2_import
                              dlep_radio
                              )
 ENDIF (NOT OONF_STATIC_PLUGINS)
index 4e12394..c182fc7 100644 (file)
@@ -40,10 +40,12 @@ IF (NOT OONF_STATIC_PLUGINS)
                              os_fd
                              os_interface
                              os_system
+                             os_routing
                              cfg_compact
                              layer2info
                              systeminfo
                              dlep_router
+                             layer2_export
                              )
 ENDIF (NOT OONF_STATIC_PLUGINS)
 
index d41e9ee..16156f1 100644 (file)
@@ -55,7 +55,7 @@ IF (NOT OONF_STATIC_PLUGINS)
                              olsrv2info
                              olsrv2_lan
                              netjsoninfo
-                             lan_import
+                             layer2_import
                              auto_ll4
                              http
                              dlep_router
index 631bb74..483a1d0 100644 (file)
@@ -55,8 +55,9 @@ IF (NOT OONF_STATIC_PLUGINS)
                              olsrv2info
                              olsrv2_lan
                              olsrv2_old_lan
+                             olsrv2_l2import
                              netjsoninfo
-                             lan_import
+                             layer2_import
                              auto_ll4
                              http
                              mpr