diff options
author | Jordan Bracco <href@random.sh> | 2021-11-12 16:12:26 +0100 |
---|---|---|
committer | Jordan Bracco <href@random.sh> | 2021-11-12 16:12:26 +0100 |
commit | df4d0399133a7ab3a40d5bde05c642875d1d4c14 (patch) | |
tree | 908c178514e08d6e8060ab69016d01d78113d01a | |
parent | improve rust.. (diff) |
Rename to RoutingTable, improvements
-rw-r--r-- | README.md | 25 | ||||
-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 | ||||
-rw-r--r-- | mix.exs | 4 | ||||
-rw-r--r-- | native/treebitmap_nif/src/lib.rs | 57 | ||||
-rw-r--r-- | test/routing_table_test.exs | 40 | ||||
-rw-r--r-- | test/tree_bitmap_test.exs | 134 |
7 files changed, 173 insertions, 151 deletions
@@ -1,21 +1,14 @@ -# TreeBitmap +# Routing Table -**TODO: Add description** +Efficient RIB for Elixir, implemented using a Rust NIF and [treebitmap](https://crates.io/crates/treebitmap). -## Installation - -If [available in Hex](https://hex.pm/docs/publish), the package can be installed -by adding `tree_bitmap` to your list of dependencies in `mix.exs`: +The tables covers both IPv4 and IPv6, and values are any erlang term, stored in ets. ```elixir -def deps do - [ - {:tree_bitmap, "~> 0.1.0"} - ] -end +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}) ``` - -Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) -and published on [HexDocs](https://hexdocs.pm). Once published, the docs can -be found at [https://hexdocs.pm/tree_bitmap](https://hexdocs.pm/tree_bitmap). - 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) @@ -1,9 +1,9 @@ -defmodule TreeBitmap.MixProject do +defmodule RoutingTable.MixProject do use Mix.Project def project do [ - app: :tree_bitmap, + app: :routing_table, version: "0.1.0", elixir: "~> 1.12-rc", start_permanent: Mix.env() == :prod, diff --git a/native/treebitmap_nif/src/lib.rs b/native/treebitmap_nif/src/lib.rs index 5d1821b..58859e7 100644 --- a/native/treebitmap_nif/src/lib.rs +++ b/native/treebitmap_nif/src/lib.rs @@ -17,34 +17,10 @@ mod atoms { } } -trait Address { +trait Maskable { fn mask(self, masklen: u32) -> Self; } -#[derive(NifUntaggedEnum, Copy, Clone)] -enum AddrTuple { - V4(TupleV4), - V6(TupleV6) -} - -impl Address for AddrTuple { - fn mask(self, masklen: u32) -> Self { - match self { - AddrTuple::V4(tuple_v4) => AddrTuple::V4(tuple_v4.mask(masklen)), - AddrTuple::V6(tuple_v6) => AddrTuple::V6(tuple_v6.mask(masklen)) - } - } -} - -#[derive(Debug, NifRecord, Copy, Clone)] -#[tag = "inet4"] -struct TupleV4 { - pub a: u8, - pub b: u8, - pub c: u8, - pub d: u8 -} - struct NibblesV4 { pub n: [u8; 8]} struct NibblesV6 { pub n: [u8; 32]} @@ -71,6 +47,31 @@ impl AsRef<[u8]> for NibblesV6 { } } + +#[derive(NifUntaggedEnum, Copy, Clone)] +enum AddrTuple { + V4(TupleV4), + V6(TupleV6) +} + +impl Maskable for AddrTuple { + fn mask(self, masklen: u32) -> Self { + match self { + AddrTuple::V4(tuple_v4) => AddrTuple::V4(tuple_v4.mask(masklen)), + AddrTuple::V6(tuple_v6) => AddrTuple::V6(tuple_v6.mask(masklen)) + } + } +} + +#[derive(Debug, NifRecord, Copy, Clone)] +#[tag = "inet4"] +struct TupleV4 { + pub a: u8, + pub b: u8, + pub c: u8, + pub d: u8 +} + impl TupleV4 { pub fn from(num: u32) -> Self { TupleV4 { @@ -86,7 +87,7 @@ impl TupleV4 { } } -impl Address for TupleV4 { +impl Maskable for TupleV4 { fn mask(self, masklen: u32) -> Self { debug_assert!(masklen <= 32); let ip = u32::from(self); @@ -186,7 +187,7 @@ impl TupleV6 { } -impl Address for TupleV6 { +impl Maskable for TupleV6 { fn mask(self, masklen: u32) -> Self { debug_assert!(masklen <= 128); @@ -312,7 +313,7 @@ fn memory<'a>( make_tuple(env, &[nodes.encode(env), results.encode(env)]) } -rustler::init!("Elixir.TreeBitmap.NIF", +rustler::init!("Elixir.RoutingTable.TreeBitmap", [new, new_with_capacity, length, diff --git a/test/routing_table_test.exs b/test/routing_table_test.exs new file mode 100644 index 0000000..730ed0d --- /dev/null +++ b/test/routing_table_test.exs @@ -0,0 +1,40 @@ +defmodule RoutingTableTest do + use ExUnit.Case + doctest RoutingTable + + test "RoutingTable" do + t = RoutingTable.new() + assert nil == RoutingTable.add(t, {192, 168, 1, 0}, 24, :lan) + assert nil == RoutingTable.add(t, {8193, 3512, 34211, 0, 0, 35374, 880, 1}, 64, :lan) + + assert %{value: :lan} = RoutingTable.longest_match(t, {192, 168, 1, 2}) + assert true = RoutingTable.longest_match?(t, {192, 168, 1, 2}) + assert %{value: :lan} = RoutingTable.longest_match(t, {8193, 3512, 34211, 0, 0, 35374, 880, 29492}) + assert true = RoutingTable.longest_match?(t, {8193, 3512, 34211, 0, 0, 35374, 880, 29492}) + + assert :lan = RoutingTable.exact_match(t, {192, 168, 1, 1}, 24) + assert true = RoutingTable.exact_match?(t, {192, 168, 1, 1}, 24) + assert :lan = RoutingTable.exact_match(t, {8193, 3512, 34211, 0, 0, 35374, 880, 29492}, 64) + assert true = RoutingTable.exact_match?(t, {8193, 3512, 34211, 0, 0, 35374, 880, 29492}, 64) + + assert nil == RoutingTable.longest_match(t, {8, 8, 8, 8}) + assert false == RoutingTable.longest_match?(t, {8, 8, 8, 8}) + assert nil == RoutingTable.exact_match(t, {8, 8, 8, 8}, 32) + assert false == RoutingTable.exact_match?(t, {8, 8, 8, 8}, 32) + + assert %{ets: 330, inet4: {1248, 1168}, inet6: {1344, 1168}} = RoutingTable.memory(t) + + assert %{ets: 2, inet4: 1, inet6: 1} = RoutingTable.length(t) + assert :lan = RoutingTable.remove(t, {8193, 3512, 34211, 0, 0, 35374, 880, 1}, 64) + assert nil == RoutingTable.longest_match(t, {8193, 3512, 34211, 0, 0, 35374, 880, 29492}) + assert %{ets: 2, inet4: 1, inet6: 0} = RoutingTable.length(t) + assert :lan == RoutingTable.remove(t, {192, 168, 1, 0}, 24) + assert %{ets: 1, inet4: 0, inet6: 0} = RoutingTable.length(t) + + assert nil == RoutingTable.add(t, {8193, 3512, 34211, 0, 0, 35374, 880, 1}, 64, :lan) + assert :lan = RoutingTable.add(t, {8193, 3512, 34211, 0, 0, 35374, 880, 1}, 64, :lan2) + assert %{ets: 2, inet4: 0, inet6: 1} = RoutingTable.length(t) + end + + +end diff --git a/test/tree_bitmap_test.exs b/test/tree_bitmap_test.exs index aedf78f..5c4f39e 100644 --- a/test/tree_bitmap_test.exs +++ b/test/tree_bitmap_test.exs @@ -1,126 +1,92 @@ defmodule TreeBitmapTest do use ExUnit.Case - doctest TreeBitmap - alias TreeBitmap.NIF - alias TreeBitmap - - test "TreeBitmap" do - t = TreeBitmap.new() - assert nil == TreeBitmap.add(t, {192, 168, 1, 0}, 24, :lan) - assert nil == TreeBitmap.add(t, {8193, 3512, 34211, 0, 0, 35374, 880, 1}, 64, :lan) - - assert %{value: :lan} = TreeBitmap.longest_match(t, {192, 168, 1, 2}) - assert true = TreeBitmap.longest_match?(t, {192, 168, 1, 2}) - assert %{value: :lan} = TreeBitmap.longest_match(t, {8193, 3512, 34211, 0, 0, 35374, 880, 29492}) - assert true = TreeBitmap.longest_match?(t, {8193, 3512, 34211, 0, 0, 35374, 880, 29492}) - - assert :lan = TreeBitmap.exact_match(t, {192, 168, 1, 1}, 24) - assert true = TreeBitmap.exact_match?(t, {192, 168, 1, 1}, 24) - assert :lan = TreeBitmap.exact_match(t, {8193, 3512, 34211, 0, 0, 35374, 880, 29492}, 64) - assert true = TreeBitmap.exact_match?(t, {8193, 3512, 34211, 0, 0, 35374, 880, 29492}, 64) - - assert nil == TreeBitmap.longest_match(t, {8, 8, 8, 8}) - assert false == TreeBitmap.longest_match?(t, {8, 8, 8, 8}) - assert nil == TreeBitmap.exact_match(t, {8, 8, 8, 8}, 32) - assert false == TreeBitmap.exact_match?(t, {8, 8, 8, 8}, 32) - - assert %{ets: 335, inet4: {1248, 1168}, inet6: {1344, 1168}} = TreeBitmap.memory(t) - - assert %{ets: 3, inet4: 1, inet6: 1} = TreeBitmap.length(t) - assert :lan = TreeBitmap.remove(t, {8193, 3512, 34211, 0, 0, 35374, 880, 1}, 64) - assert nil == TreeBitmap.longest_match(t, {8193, 3512, 34211, 0, 0, 35374, 880, 29492}) - assert %{ets: 2, inet4: 1, inet6: 0} = TreeBitmap.length(t) - - assert nil == TreeBitmap.add(t, {8193, 3512, 34211, 0, 0, 35374, 880, 1}, 64, :lan) - assert :lan = TreeBitmap.add(t, {8193, 3512, 34211, 0, 0, 35374, 880, 1}, 64, :lan2) - assert %{ets: 3, inet4: 1, inet6: 1} = TreeBitmap.length(t) - end + alias RoutingTable.TreeBitmap test "new/0" do - table = NIF.new() + table = TreeBitmap.new() assert is_reference(table) end test "memory/1" do - table = NIF.new() - assert {1200, 1152} == NIF.memory(table) - {:ok, _} = NIF.add(table, {:inet4, 192, 168, 1, 0}, 24, 0) - assert {1248, 1168} == NIF.memory(table) + table = TreeBitmap.new() + assert {1200, 1152} == TreeBitmap.memory(table) + {:ok, _} = TreeBitmap.add(table, {:inet4, 192, 168, 1, 0}, 24, 0) + assert {1248, 1168} == TreeBitmap.memory(table) end test "new_with_capacity/1" do - table = NIF.new_with_capacity(1000) + table = TreeBitmap.new_with_capacity(1000) assert is_reference(table) - assert {109152, 37152} = NIF.memory(table) + assert {109152, 37152} = TreeBitmap.memory(table) end test "length/1" do - table = NIF.new() - assert 0 == NIF.length(table) + table = TreeBitmap.new() + assert 0 == TreeBitmap.length(table) end test "add/4 and longest_match/2" do - table = NIF.new() - assert {:ok, _} = NIF.add(table, {:inet4, 192, 168, 1, 0}, 24, 0) - assert {:ok, _, 24, 0} = NIF.longest_match(table, {:inet4, 192, 168, 1, 1}) - assert {:ok, nil} = NIF.longest_match(table, {:inet4, 1, 1, 1, 1}) + table = TreeBitmap.new() + assert {:ok, _} = TreeBitmap.add(table, {:inet4, 192, 168, 1, 0}, 24, 0) + assert {:ok, _, 24, 0} = TreeBitmap.longest_match(table, {:inet4, 192, 168, 1, 1}) + assert {:ok, nil} = TreeBitmap.longest_match(table, {:inet4, 1, 1, 1, 1}) end test "add/2 existing" do - table = NIF.new() - {:ok, nil} = NIF.add(table, {:inet4, 10, 69, 0, 0}, 16, 0) - assert {:ok, 0} = NIF.add(table, {:inet4, 10, 69, 0, 0}, 16, 1) - assert {:ok, _, _, 1} = NIF.longest_match(table, {:inet4, 10, 69, 1, 1}) + table = TreeBitmap.new() + {:ok, nil} = TreeBitmap.add(table, {:inet4, 10, 69, 0, 0}, 16, 0) + assert {:ok, 0} = TreeBitmap.add(table, {:inet4, 10, 69, 0, 0}, 16, 1) + assert {:ok, _, _, 1} = TreeBitmap.longest_match(table, {:inet4, 10, 69, 1, 1}) end test "remove/3" do - table = NIF.new() - {:ok, _} = NIF.add(table, {:inet4, 192, 168, 1, 0}, 24, 0) - assert {:ok, 0} == NIF.remove(table, {:inet4, 192, 168, 1, 0}, 24) - assert {:ok, nil} = NIF.longest_match(table, {:inet4, 192, 168, 1, 1}) + table = TreeBitmap.new() + {:ok, _} = TreeBitmap.add(table, {:inet4, 192, 168, 1, 0}, 24, 0) + assert {:ok, 0} == TreeBitmap.remove(table, {:inet4, 192, 168, 1, 0}, 24) + assert {:ok, nil} = TreeBitmap.longest_match(table, {:inet4, 192, 168, 1, 1}) end test "exact_match/3" do - table = NIF.new() - {:ok, _} = NIF.add(table, {:inet4, 192, 168, 1, 0}, 24, 0) - assert {:ok, 0} = NIF.exact_match(table, {:inet4, 192, 168, 1, 0}, 24) - assert {:ok, nil} = NIF.exact_match(table, {:inet4, 192, 168, 1, 1}, 32) + table = TreeBitmap.new() + {:ok, _} = TreeBitmap.add(table, {:inet4, 192, 168, 1, 0}, 24, 0) + assert {:ok, 0} = TreeBitmap.exact_match(table, {:inet4, 192, 168, 1, 0}, 24) + assert {:ok, nil} = TreeBitmap.exact_match(table, {:inet4, 192, 168, 1, 1}, 32) end test "default route" do - table = NIF.new() - assert {:ok, nil} == NIF.add(table, {:inet4, 0, 0, 0, 0}, 0, 0) - assert {:ok, _, 0, 0} = NIF.longest_match(table, {:inet4, 192, 168, 1, 1}) + table = TreeBitmap.new() + assert {:ok, nil} == TreeBitmap.add(table, {:inet4, 0, 0, 0, 0}, 0, 0) + assert {:ok, _, 0, 0} = TreeBitmap.longest_match(table, {:inet4, 192, 168, 1, 1}) end test "more to less specific" do - table = NIF.new() - {:ok, _} = NIF.add(table, {:inet4, 10, 69, 1, 0}, 24, 2) - {:ok, _} = NIF.add(table, {:inet4, 10, 69, 0, 0}, 16, 1) - {:ok, _} = NIF.add(table, {:inet4, 0, 0, 0, 0}, 0, 0) - assert {:ok, _, _, 0} = NIF.longest_match(table, {:inet4, 8, 8, 8, 8}) - assert {:ok, _, _, 2} = NIF.longest_match(table, {:inet4, 10, 69, 1, 2}) - assert {:ok, _, _, 1} = NIF.longest_match(table, {:inet4, 10, 69, 2, 2}) + table = TreeBitmap.new() + {:ok, _} = TreeBitmap.add(table, {:inet4, 10, 69, 1, 0}, 24, 2) + {:ok, _} = TreeBitmap.add(table, {:inet4, 10, 69, 0, 0}, 16, 1) + {:ok, _} = TreeBitmap.add(table, {:inet4, 0, 0, 0, 0}, 0, 0) + assert {:ok, _, _, 0} = TreeBitmap.longest_match(table, {:inet4, 8, 8, 8, 8}) + assert {:ok, _, _, 2} = TreeBitmap.longest_match(table, {:inet4, 10, 69, 1, 2}) + assert {:ok, _, _, 1} = TreeBitmap.longest_match(table, {:inet4, 10, 69, 2, 2}) end test "less to more specific" do - table = NIF.new() - {:ok, _} = NIF.add(table, {:inet4, 0, 0, 0, 0}, 0, 0) - {:ok, _} = NIF.add(table, {:inet4, 10, 69, 0, 0}, 16, 1) - {:ok, _} = NIF.add(table, {:inet4, 10, 69, 1, 0}, 24, 2) - assert {:ok, _, _, 0} = NIF.longest_match(table, {:inet4, 8, 8, 8, 8}) - assert {:ok, _, _, 2} = NIF.longest_match(table, {:inet4, 10, 69, 1, 2}) - assert {:ok, _, _, 1} = NIF.longest_match(table, {:inet4, 10, 69, 2, 2}) + table = TreeBitmap.new() + {:ok, _} = TreeBitmap.add(table, {:inet4, 0, 0, 0, 0}, 0, 0) + {:ok, _} = TreeBitmap.add(table, {:inet4, 10, 69, 0, 0}, 16, 1) + {:ok, _} = TreeBitmap.add(table, {:inet4, 10, 69, 1, 0}, 24, 2) + assert {:ok, _, _, 0} = TreeBitmap.longest_match(table, {:inet4, 8, 8, 8, 8}) + assert {:ok, _, _, 2} = TreeBitmap.longest_match(table, {:inet4, 10, 69, 1, 2}) + assert {:ok, _, _, 1} = TreeBitmap.longest_match(table, {:inet4, 10, 69, 2, 2}) end test "multiple routes" do - table = NIF.new() - {:ok, _} = NIF.add(table, {:inet4, 8, 8, 8, 0}, 24, 8) - {:ok, _} = NIF.add(table, {:inet4, 1, 1, 0, 0}, 16, 1) - {:ok, _} = NIF.add(table, {:inet4, 192, 168, 1, 1}, 32, 200) - assert {:ok, _, _, 8} = NIF.longest_match(table, {:inet4, 8, 8, 8, 8}) - assert {:ok, _, _, 1} = NIF.longest_match(table, {:inet4, 1, 1, 0, 0}) - assert {:ok, _, _, 200} = NIF.longest_match(table, {:inet4, 192, 168, 1, 1}) + table = TreeBitmap.new() + {:ok, _} = TreeBitmap.add(table, {:inet4, 8, 8, 8, 0}, 24, 8) + {:ok, _} = TreeBitmap.add(table, {:inet4, 1, 1, 0, 0}, 16, 1) + {:ok, _} = TreeBitmap.add(table, {:inet4, 192, 168, 1, 1}, 32, 200) + assert {:ok, _, _, 8} = TreeBitmap.longest_match(table, {:inet4, 8, 8, 8, 8}) + assert {:ok, _, _, 1} = TreeBitmap.longest_match(table, {:inet4, 1, 1, 0, 0}) + assert {:ok, _, _, 200} = TreeBitmap.longest_match(table, {:inet4, 192, 168, 1, 1}) end end |