aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/routing_table.ex (renamed from lib/tree_bitmap.ex)60
-rw-r--r--lib/routing_table/tree_bitmap.ex (renamed from lib/tree_bitmap/nif.ex)4
2 files changed, 43 insertions, 21 deletions
diff --git a/lib/tree_bitmap.ex b/lib/routing_table.ex
index 0da87fa..90b0160 100644
--- a/lib/tree_bitmap.ex
+++ b/lib/routing_table.ex
@@ -1,12 +1,25 @@
-defmodule TreeBitmap do
- alias TreeBitmap.NIF
+defmodule RoutingTable do
+ alias RoutingTable.TreeBitmap
defstruct [:i4, :i6, :ets]
@opaque t() :: %__MODULE__{}
@type masklen :: non_neg_integer()
+ @moduledoc """
+ Efficient routing table.
+
+ ```elixir
+ table = RoutingTable.new()
+ RoutingTable.add(table, {10, 69, 0, 0}, 16, :vpn)
+ RoutingTable.add(table, {10, 69, 1, 0}, 24, :lan)
+ :vpn = RoutingTable.longest_match(table, {10, 69, 2, 1})
+ :lan = RoutingTable.longest_match(table, {10, 69, 1, 1})
+ nil = RoutingTable.longest_match(table, {10, 68, 1, 1})
+ ```
+ """
+
def new(_opts \\ []) do
- %__MODULE__{i4: NIF.new(), i6: NIF.new(), ets: :ets.new(__MODULE__, [:public])}
+ %__MODULE__{i4: TreeBitmap.new(), i6: TreeBitmap.new(), ets: :ets.new(__MODULE__, [:public])}
end
@spec add(t(), :inet.ip_address(), masklen(), any()) :: nil | any()
@@ -78,40 +91,49 @@ defmodule TreeBitmap do
@type tree_memory() :: {nodes :: non_neg_integer(), results :: non_neg_integer()}
@spec memory(t()) :: %{inet4: tree_memory(), inet6: tree_memory(), ets: non_neg_integer()}
def memory(tree) do
- %{inet4: NIF.memory(tree.i4), inet6: NIF.memory(tree.i6), ets: :ets.info(tree.ets, :memory)}
+ %{inet4: TreeBitmap.memory(tree.i4), inet6: TreeBitmap.memory(tree.i6), ets: :ets.info(tree.ets, :memory)}
end
@spec length(t()) :: %{inet4: non_neg_integer(), inet6: non_neg_integer(), ets: non_neg_integer()}
def length(tree) do
- %{inet4: NIF.length(tree.i4), inet6: NIF.length(tree.i6), ets: :ets.info(tree.ets, :size)}
+ %{inet4: TreeBitmap.length(tree.i4), inet6: TreeBitmap.length(tree.i6), ets: :ets.info(tree.ets, :size)}
end
defp add(tree, tbm, ip, masklen, value) do
- id = :ets.update_counter(tree.ets, {__MODULE__, :counter}, 1, {{__MODULE__, :counter}, -1})
- :ets.insert(tree.ets, {id, value})
- {:ok, prev_id} = NIF.add(tbm, ip, masklen, id)
+ id = case :ets.match(tree.ets, {:'$1', :_, value}) do
+ [[id]] ->
+ :ets.update_counter(tree.ets, id, 1)
+ id
+ [] ->
+ id = :ets.update_counter(tree.ets, {__MODULE__, :counter}, 1, {{__MODULE__, :counter}, -1, 0})
+ :ets.insert(tree.ets, {id, 1, value})
+ id
+ end
+ {:ok, prev_id} = TreeBitmap.add(tbm, ip, masklen, id)
prev = if prev_id do
- [{^prev_id, value}] = :ets.lookup(tree.ets, prev_id)
- :ets.delete(tree.ets, prev_id)
+ [{^prev_id, _refc, value}] = :ets.lookup(tree.ets, prev_id)
+ refc = :ets.update_counter(tree.ets, id, -1)
+ if refc < 1, do: :ets.delete(tree.ets, prev_id)
value
end
prev
end
defp remove(tree, tbm, ip, masklen) do
- {:ok, id} = NIF.remove(tbm, ip, masklen)
+ {:ok, id} = TreeBitmap.remove(tbm, ip, masklen)
prev = if id do
- [{^id, value}] = :ets.lookup(tree.ets, id)
- :ets.delete(tree.ets, id)
+ [{^id, _refc, value}] = :ets.lookup(tree.ets, id)
+ refc = :ets.update_counter(tree.ets, id, -1)
+ if refc < 1, do: :ets.delete(tree.ets, id)
value
end
prev
end
defp longest_match(tree, tbm, ip) do
- case NIF.longest_match(tbm, ip) do
+ case TreeBitmap.longest_match(tbm, ip) do
{:ok, prefix, masklen, id} ->
- [{^id, value}] = :ets.lookup(tree.ets, id)
+ [{^id, _refc, value}] = :ets.lookup(tree.ets, id)
%{prefix: to_inet(prefix), len: masklen, value: value}
{:ok, nil} ->
nil
@@ -119,24 +141,24 @@ defmodule TreeBitmap do
end
defp longest_match?(_, tbm, ip) do
- case NIF.longest_match(tbm, ip) do
+ case TreeBitmap.longest_match(tbm, ip) do
{:ok, nil} -> false
{:ok, _, _, _} -> true
end
end
defp exact_match(tree, tbm, ip, masklen) do
- case NIF.exact_match(tbm, ip, masklen) do
+ case TreeBitmap.exact_match(tbm, ip, masklen) do
{:ok, nil} ->
nil
{:ok, id} ->
- [{^id, value}] = :ets.lookup(tree.ets, id)
+ [{^id, _refc, value}] = :ets.lookup(tree.ets, id)
value
end
end
defp exact_match?(_, tbm, ip, masklen) do
- case NIF.exact_match(tbm, ip, masklen) do
+ case TreeBitmap.exact_match(tbm, ip, masklen) do
{:ok, nil} -> false
{:ok, _} -> true
end
diff --git a/lib/tree_bitmap/nif.ex b/lib/routing_table/tree_bitmap.ex
index 7934f5a..1592bcb 100644
--- a/lib/tree_bitmap/nif.ex
+++ b/lib/routing_table/tree_bitmap.ex
@@ -1,5 +1,5 @@
-defmodule TreeBitmap.NIF do
- use Rustler, otp_app: :tree_bitmap, crate: "treebitmap_nif"
+defmodule RoutingTable.TreeBitmap do
+ use Rustler, otp_app: :routing_table, crate: "treebitmap_nif"
def new(), do: :erlang.nif_error(:nif_not_loaded)
def new_with_capacity(_), do: :erlang.nif_error(:nif_not_loaded)