Prepare layer2 database for storage of DLEP based IP addresses and prefixes
authorHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Wed, 2 Aug 2017 09:13:46 +0000 (11:13 +0200)
committerHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Wed, 2 Aug 2017 09:13:46 +0000 (11:13 +0200)
src-plugins/subsystems/oonf_layer2.c
src-plugins/subsystems/oonf_layer2.h

index dd4cd60..d19f21c 100644 (file)
@@ -134,6 +134,14 @@ static struct oonf_class _l2dst_class = {
   .name = LAYER2_CLASS_DESTINATION,
   .size = sizeof(struct oonf_layer2_destination),
 };
+static struct oonf_class _l2net_addr_class = {
+  .name = LAYER2_CLASS_NETWORK_ADDRESS,
+  .size = sizeof(struct oonf_layer2_peer_address),
+};
+static struct oonf_class _l2neigh_addr_class = {
+  .name = LAYER2_CLASS_NEIGHBOR_ADDRESS,
+  .size = sizeof(struct oonf_layer2_neighbor_address),
+};
 
 static struct avl_tree _oonf_layer2_net_tree;
 
@@ -148,6 +156,8 @@ _init(void) {
   oonf_class_add(&_l2network_class);
   oonf_class_add(&_l2neighbor_class);
   oonf_class_add(&_l2dst_class);
+  oonf_class_add(&_l2net_addr_class);
+  oonf_class_add(&_l2neigh_addr_class);
 
   avl_init(&_oonf_layer2_net_tree, avl_comp_strcasecmp, false);
   avl_init(&_oonf_originator_tree, avl_comp_strcasecmp, false);
@@ -165,6 +175,8 @@ _cleanup(void) {
     _net_remove(l2net);
   }
 
+  oonf_class_remove(&_l2neigh_addr_class);
+  oonf_class_remove(&_l2net_addr_class);
   oonf_class_remove(&_l2dst_class);
   oonf_class_remove(&_l2neighbor_class);
   oonf_class_remove(&_l2network_class);
@@ -229,8 +241,9 @@ oonf_layer2_net_add(const char *ifname) {
   l2net->_node.key = l2net->name;
   avl_insert(&_oonf_layer2_net_tree, &l2net->_node);
 
-  /* initialize tree of neighbors and proxies */
+  /* initialize tree of neighbors, ips and proxies */
   avl_init(&l2net->neighbors, avl_comp_netaddr, false);
+  avl_init(&l2net->local_peer_ips, avl_comp_netaddr, false);
 
   /* initialize interface listener */
   l2net->if_listener.name = l2net->name;
@@ -369,6 +382,88 @@ oonf_layer2_net_relabel(struct oonf_layer2_net *l2net,
   }
 }
 
+/**
+ * Add an IP address or prefix to a layer-2 interface. This represents
+ * an address of the local radio or modem.
+ * @param l2net layer-2 network object
+ * @param ip ip address or prefix
+ * @return layer2 ip address object, NULL if out of memory
+ */
+struct oonf_layer2_peer_address *
+oonf_layer2_net_add_ip(struct oonf_layer2_net *l2net,
+    const struct oonf_layer2_origin *origin, const struct netaddr *ip) {
+  struct oonf_layer2_peer_address *l2addr;
+
+  l2addr = oonf_layer2_net_get_ip(l2net, ip);
+  if (!l2addr) {
+    l2addr = oonf_class_malloc(&_l2net_addr_class);
+    if (!l2addr) {
+      return NULL;
+    }
+
+    /* copy data */
+    memcpy(&l2addr->ip, ip, sizeof(*ip));
+
+    /* set back reference */
+    l2addr->l2net = l2net;
+
+    /* add to tree */
+    l2addr->_node.key = &l2addr->ip;
+    avl_insert(&l2net->local_peer_ips, &l2addr->_node);
+  }
+
+  l2addr->origin = origin;
+  return l2addr;
+}
+
+/**
+ * Remove a peer IP address from a layer2 network
+ * @param ip ip address or prefix
+ * @param origin origin of IP address
+ * @return 0 if IP was removed, -1 if it was registered to a different origin
+ */
+int
+oonf_layer2_net_remove_ip(
+    struct oonf_layer2_peer_address *ip, struct oonf_layer2_origin *origin) {
+  if (ip->origin != origin) {
+    return -1;
+  }
+
+  avl_remove(&ip->l2net->local_peer_ips, &ip->_node);
+  oonf_class_free(&_l2net_addr_class, ip);
+  return 0;
+}
+
+/**
+ * Look for the best matching prefix in all layer2 neighbor addresses
+ * that contains a specific address
+ * @param addr ip address to look for
+ * @return layer2 neighbor address object, NULL if no match was found
+ */
+struct oonf_layer2_neighbor_address *
+oonf_layer2_net_get_best_neighbor_match(const struct netaddr *addr) {
+  struct oonf_layer2_neighbor_address *best_match, *l2addr;
+  struct oonf_layer2_neigh *l2neigh;
+  struct oonf_layer2_net *l2net;
+  int prefix_length;
+
+  prefix_length = 256;
+  best_match = NULL;
+
+  avl_for_each_element(&_oonf_layer2_net_tree, l2net, _node) {
+    avl_for_each_element(&l2net->neighbors, l2neigh, _node) {
+      avl_for_each_element(&l2neigh->remote_neighbor_ips, l2addr, _node) {
+        if (netaddr_is_in_subnet(&l2addr->ip, addr)
+            && netaddr_get_prefix_length(&l2addr->ip) < prefix_length) {
+          best_match = l2addr;
+          prefix_length = netaddr_get_prefix_length(&l2addr->ip);
+        }
+      }
+    }
+  }
+  return best_match;
+}
+
 /**
  * Add a layer-2 neighbor to a addr.
  * @param l2net layer-2 addr object
@@ -507,6 +602,58 @@ oonf_layer2_neigh_relabel(struct oonf_layer2_neigh *l2neigh,
   }
 }
 
+/**
+ * Add an IP address or prefix to a layer-2 interface. This represents
+ * an address of the local radio or modem.
+ * @param l2net layer-2 network object
+ * @param ip ip address or prefix
+ * @return layer2 ip address object, NULL if out of memory
+ */
+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) {
+  struct oonf_layer2_neighbor_address *l2addr;
+
+  l2addr = oonf_layer2_neigh_get_ip(l2neigh, ip);
+  if (!l2addr) {
+    l2addr = oonf_class_malloc(&_l2neigh_addr_class);
+    if (!l2addr) {
+      return NULL;
+    }
+
+    /* copy data */
+    memcpy(&l2addr->ip, ip, sizeof(*ip));
+
+    /* set back reference */
+    l2addr->l2neigh = l2neigh;
+
+    /* add to tree */
+    l2addr->_node.key = &l2addr->ip;
+    avl_insert(&l2neigh->remote_neighbor_ips, &l2addr->_node);
+  }
+
+  l2addr->origin = origin;
+  return l2addr;
+}
+
+/**
+ * Remove a neighbor IP address from a layer2 neighbor
+ * @param ip ip address or prefix
+ * @param origin origin of IP address
+ * @return 0 if IP was removed, -1 if it was registered to a different origin
+ */
+int
+oonf_layer2_neigh_remove_ip(
+    struct oonf_layer2_neighbor_address *ip, struct oonf_layer2_origin *origin) {
+  if (ip->origin != origin) {
+    return -1;
+  }
+
+  avl_remove(&ip->l2neigh->remote_neighbor_ips, &ip->_node);
+  oonf_class_free(&_l2neigh_addr_class, ip);
+  return 0;
+}
+
 /**
  * add a layer2 destination (a MAC address behind a neighbor) to
  * the layer2 database
index a9cbf60..623b4de 100644 (file)
 /*! memory class for layer2 destination */
 #define LAYER2_CLASS_DESTINATION "layer2_destination"
 
+/*! memory class for layer2 network address */
+#define LAYER2_CLASS_NETWORK_ADDRESS "layer2_network_address"
+
+/*! memory class for layer2 neighbor address */
+#define LAYER2_CLASS_NEIGHBOR_ADDRESS "layer2_neighbor_address"
+
 /**
  * priorities of layer2 originators
  */
@@ -234,6 +240,9 @@ struct oonf_layer2_net {
   /*! tree of remote neighbors */
   struct avl_tree neighbors;
 
+  /*! tree of IP addresses/prefixes of local radio/modem */
+  struct avl_tree local_peer_ips;
+
   /*! absolute timestamp when network has been active last */
   uint64_t last_seen;
 
@@ -247,6 +256,23 @@ struct oonf_layer2_net {
   struct avl_node _node;
 };
 
+/**
+ * IP addresses that are attached to a local radio/modem
+ */
+struct oonf_layer2_peer_address {
+  /*! ip address attached to a local radio/modem */
+  struct netaddr ip;
+
+  /*! backlink to layer2 network */
+  struct oonf_layer2_net *l2net;
+
+  /*! origin of this address */
+  const struct oonf_layer2_origin *origin;
+
+  /*! node for tree of ip addresses */
+  struct avl_node _node;
+};
+
 /**
  * representation of a remote layer2 neighbor
  */
@@ -260,6 +286,9 @@ struct oonf_layer2_neigh {
   /*! tree of proxied destinations */
   struct avl_tree destinations;
 
+  /*! tree of IP addresses/prefixes of remote neighbor router */
+  struct avl_tree remote_neighbor_ips;
+
   /*! absolute timestamp when neighbor has been active last */
   uint64_t last_seen;
 
@@ -270,6 +299,23 @@ struct oonf_layer2_neigh {
   struct avl_node _node;
 };
 
+/**
+ * IP addresses that are attached to a remote router
+ */
+struct oonf_layer2_neighbor_address {
+  /*! ip address attached to a remote router */
+  struct netaddr ip;
+
+  /*! backlink to layer2 neighbor*/
+  struct oonf_layer2_neigh *l2neigh;
+
+  /*! origin of this address */
+  const struct oonf_layer2_origin *origin;
+
+  /*! node for tree of ip addresses */
+  struct avl_node _node;
+};
+
 /**
  * representation of a bridged MAC address behind a layer2 neighbor
  */
@@ -316,6 +362,13 @@ EXPORT bool oonf_layer2_net_commit(struct oonf_layer2_net *);
 EXPORT void oonf_layer2_net_relabel(struct oonf_layer2_net *l2net,
     const struct oonf_layer2_origin *new_origin,
     const struct oonf_layer2_origin *old_origin);
+EXPORT struct oonf_layer2_peer_address *oonf_layer2_net_add_ip(
+    struct oonf_layer2_net *l2net,
+    const struct oonf_layer2_origin *origin, const struct netaddr *ip);
+EXPORT int oonf_layer2_net_remove_ip(
+    struct oonf_layer2_peer_address *ip, struct oonf_layer2_origin *origin);
+EXPORT struct oonf_layer2_neighbor_address *oonf_layer2_net_get_best_neighbor_match(
+    const struct netaddr *addr);
 
 EXPORT struct oonf_layer2_neigh *oonf_layer2_neigh_add(
     struct oonf_layer2_net *, struct netaddr *l2neigh);
@@ -328,6 +381,11 @@ 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 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(
+    struct oonf_layer2_neighbor_address *ip, struct oonf_layer2_origin *origin);
 
 EXPORT struct oonf_layer2_destination *oonf_layer2_destination_add(
     struct oonf_layer2_neigh *l2neigh, const struct netaddr *destination,
@@ -372,9 +430,22 @@ oonf_layer2_net_get(const char *ifname) {
   return avl_find_element(oonf_layer2_get_network_tree(), ifname, l2net, _node);
 }
 
+/**
+ * Get a layer-2 ip address object from the database
+ * @param l2net layer-2 network/interface object
+ * @param ip ip address of local radio/modem
+ * @return layer-2 ip address object, NULL if not found
+ */
+static INLINE struct oonf_layer2_peer_address *
+oonf_layer2_net_get_ip(const struct oonf_layer2_net *l2net,
+    const struct netaddr *addr) {
+  struct oonf_layer2_peer_address *l2ip;
+  return avl_find_element(&l2net->local_peer_ips, addr, l2ip, _node);
+}
+
 /**
  * Get a layer-2 neighbor object from the database
- * @param l2net layer-2 addr object
+ * @param l2net layer-2 network/interface object
  * @param addr remote mac address of neighbor
  * @return layer-2 neighbor object, NULL if not found
  */
@@ -385,6 +456,12 @@ oonf_layer2_neigh_get(const struct oonf_layer2_net *l2net,
   return avl_find_element(&l2net->neighbors, addr, l2neigh, _node);
 }
 
+/**
+ * Get a layer-2 destination (secondary MAC) for a neighbor
+ * @param l2neigh layer-2 neighbor object
+ * @param destination mac address of destination
+ * @return layer-2 destination object, NULL if not found
+ */
 static INLINE struct oonf_layer2_destination *
 oonf_layer2_destination_get(const struct oonf_layer2_neigh *l2neigh,
     const struct netaddr *destination) {
@@ -392,6 +469,19 @@ oonf_layer2_destination_get(const struct oonf_layer2_neigh *l2neigh,
   return avl_find_element(&l2neigh->destinations, destination, l2dst, _node);
 }
 
+/**
+ * Get a layer-2 ip address object from the database
+ * @param l2neigh layer-2 neighbor object
+ * @param ip ip address of remote router
+ * @return layer-2 ip address object, NULL if not found
+ */
+static INLINE struct oonf_layer2_neighbor_address *
+oonf_layer2_neigh_get_ip(const struct oonf_layer2_neigh *l2neigh,
+    const struct netaddr *addr) {
+  struct oonf_layer2_neighbor_address *l2ip;
+  return avl_find_element(&l2neigh->remote_neighbor_ips, addr, l2ip, _node);
+}
+
 /**
  * @param l2data layer-2 data object
  * @return true if object contains a value, false otherwise