IPアドレス
IPネットワーク上の情報機器に割り当てられるインターネット上の住所のようなもの。
アドレスプリフィックス
IPアドレスは前から何ビット目かまでの部分と残りの部分の2つに分割されます。
- アドレスプリフィックス(ネットワークアドレス)
- ホスト識別子 (ホストアドレス)
ネットマスク
ネットマスクにより、前から何ビット目までがネットワークのアドレスを表すかを示します。
ネットマスクが255.0.0.0
(二進数で11111111 00000000 00000000 00000000
)の場合、プレフィックス長は8ビット。
ネットマスクが255.255.0.0
(二進数で11111111 11111111 00000000 00000000
)の場合、プレフィックス長は16ビット。
ネットマスクが255.255.255.0
(二進数で11111111 11111111 11111111 00000000
)の場合、プレフィックス長は24ビット。
CIDR記法
IPアドレスは、プレフィックス長と一緒に「a.b.c.d/プレフィックス長
」と表記されることがあります。(例、192.168.1.3/24
)
ですので、ネットマスクをプレフィックス長に変換したい場合もあるでしょう。
Elixirでネットマスクをプレフィックス長に変換
ElixirのIoTフレームワークであるNervesでネットマスクをプレフィックス長に変換する面白いコードがあるのでご紹介いたします。
「ネットマスクをプレフィックス長に変換する」というのは、単に前から二進数の1
の数を数えるだけです。
早速IExを開きます。
iex
以下のモジュールをiexに貼り付けます。
defmodule MyIp do
def leading_ones(ip_binary, sum \\ 0)
def leading_ones(<<0b11111111, rest::binary>>, sum), do: leading_ones(rest, sum + 8)
def leading_ones(<<0b11111110, _rest::binary>>, sum), do: sum + 7
def leading_ones(<<0b11111100, _rest::binary>>, sum), do: sum + 6
def leading_ones(<<0b11111000, _rest::binary>>, sum), do: sum + 5
def leading_ones(<<0b11110000, _rest::binary>>, sum), do: sum + 4
def leading_ones(<<0b11100000, _rest::binary>>, sum), do: sum + 3
def leading_ones(<<0b11000000, _rest::binary>>, sum), do: sum + 2
def leading_ones(<<0b10000000, _rest::binary>>, sum), do: sum + 1
def leading_ones(_, sum), do: sum
end
遊びます。
<<255, 255, 255, 255>> |> MyIp.leading_ones()
<<255, 255, 255, 254>> |> MyIp.leading_ones()
<<255, 255, 255, 252>> |> MyIp.leading_ones()
<<255, 255, 255, 248>> |> MyIp.leading_ones()
<<255, 255, 255, 240>> |> MyIp.leading_ones()
<<255, 255, 255, 224>> |> MyIp.leading_ones()
<<255, 255, 255, 192>> |> MyIp.leading_ones()
<<255, 255, 255, 128>> |> MyIp.leading_ones()
<<255, 255, 255, 0>> |> MyIp.leading_ones()
<<255, 255, 254, 0>> |> MyIp.leading_ones()
<<255, 255, 252, 0>> |> MyIp.leading_ones()
<<255, 255, 248, 0>> |> MyIp.leading_ones()
<<255, 255, 240, 0>> |> MyIp.leading_ones()
<<255, 255, 224, 0>> |> MyIp.leading_ones()
<<255, 255, 192, 0>> |> MyIp.leading_ones()
<<255, 255, 128, 0>> |> MyIp.leading_ones()
<<255, 255, 0, 0>> |> MyIp.leading_ones()
<<255, 254, 0, 0>> |> MyIp.leading_ones()
<<255, 252, 0, 0>> |> MyIp.leading_ones()
<<255, 248, 0, 0>> |> MyIp.leading_ones()
<<255, 240, 0, 0>> |> MyIp.leading_ones()
<<255, 224, 0, 0>> |> MyIp.leading_ones()
<<255, 192, 0, 0>> |> MyIp.leading_ones()
<<255, 128, 0, 0>> |> MyIp.leading_ones()
<<255, 0, 0, 0>> |> MyIp.leading_ones()
<<254, 0, 0, 0>> |> MyIp.leading_ones()
<<252, 0, 0, 0>> |> MyIp.leading_ones()
<<248, 0, 0, 0>> |> MyIp.leading_ones()
<<240, 0, 0, 0>> |> MyIp.leading_ones()
<<224, 0, 0, 0>> |> MyIp.leading_ones()
<<192, 0, 0, 0>> |> MyIp.leading_ones()
<<128, 0, 0, 0>> |> MyIp.leading_ones()
いろんなやり方があると思いますが、ここではバイナリデータパターンマッチが利用されています。
関数使用者のインプットを信用すれば単にリスト全体の1
数えるだけでも十分かもしれませんが、プレフィックス(接頭辞)という意味を明示するために律儀に前から数えた方が良いのでしょう。
for <<bit::1 <- <<255, 128, 0, 0>> >>, reduce: 0 do
count ->
case bit do
1 -> count + 1
0 -> count
end
end
Elixirのバイナリデータパターンマッチについては以下の記事の解説がおすすめです。
ご参考までに