Compare commits
2 Commits
0d49fc86d7
...
cf39b623ae
Author | SHA1 | Date | |
---|---|---|---|
cf39b623ae | |||
023b399a32 |
@ -14,14 +14,15 @@
|
|||||||
// along with netaddr. If not, see <https://www.gnu.org/licenses/>.
|
// along with netaddr. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This file contains functions for operating with big endian ordered byte arrays.
|
This file contains functions for operating with 128-bit unsigned integer
|
||||||
Using big.Integer is significantly slower than doing math strictly on 128-bit
|
numbers represented as big endian ordered byte fixed size arrays.
|
||||||
numbers. At a minimum, you have to do expensive instantiation of big.Integer.
|
Note that arrays always be 16 byte length and may contain leading zeros.
|
||||||
The functions below do not require copying arrays and allocate less memory.
|
|
||||||
|
|
||||||
Functions missing:
|
Using V math.big is significantly slower than doing math strictly on
|
||||||
fn add_128(a [16]u8, b [16]u8) [16]u8
|
128-bit numbers. At a minimum, you have to do expensive instantiation of
|
||||||
fn diff_128(a [16]u8, b [16]u8) [16]u8
|
big.Integer.
|
||||||
|
|
||||||
|
The functions below do not requires copying and allocates less memory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module netaddr
|
module netaddr
|
||||||
@ -29,6 +30,39 @@ module netaddr
|
|||||||
import math.bits
|
import math.bits
|
||||||
|
|
||||||
const max_128 = [16]u8{init: 0xff}
|
const max_128 = [16]u8{init: 0xff}
|
||||||
|
const one_128 = [u8(0), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]!
|
||||||
|
|
||||||
|
@[direct_array_access; inline]
|
||||||
|
fn add_128(a [16]u8, b [16]u8) [16]u8 {
|
||||||
|
mut res := [16]u8{}
|
||||||
|
mut num := u16(0)
|
||||||
|
for i := 15; i >= 0; i-- {
|
||||||
|
num += u16(a[i])
|
||||||
|
num += u16(b[i])
|
||||||
|
res[i] += u8(num % 256)
|
||||||
|
num /= 256
|
||||||
|
}
|
||||||
|
if num > 0 {
|
||||||
|
panic('128 bit overflow detected')
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
@[direct_array_access; inline]
|
||||||
|
fn sub_128(a [16]u8, b [16]u8) [16]u8 {
|
||||||
|
mut res := [16]u8{}
|
||||||
|
mut borrowed := u8(0)
|
||||||
|
for i := 15; i >= 0; i-- {
|
||||||
|
if a[i] < b[i] {
|
||||||
|
res[i] = (a[i] + 256) - borrowed - b[i]
|
||||||
|
borrowed = 1
|
||||||
|
} else {
|
||||||
|
res[i] = a[i] - borrowed - b[i]
|
||||||
|
borrowed = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
@[direct_array_access; inline]
|
@[direct_array_access; inline]
|
||||||
fn bit_len_128(a [16]u8) int {
|
fn bit_len_128(a [16]u8) int {
|
||||||
|
23
ip6.v
23
ip6.v
@ -514,7 +514,7 @@ pub:
|
|||||||
host_address ?Ipv6Addr
|
host_address ?Ipv6Addr
|
||||||
prefix_len int
|
prefix_len int
|
||||||
mut:
|
mut:
|
||||||
current big.Integer
|
current [16]u8
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ipv6Net.new creates new IPv6 network from given Ipv6Addr and prefix.
|
// Ipv6Net.new creates new IPv6 network from given Ipv6Addr and prefix.
|
||||||
@ -548,7 +548,7 @@ pub fn Ipv6Net.new(addr Ipv6Addr, prefix int) !Ipv6Net {
|
|||||||
broadcast_address: broadcast
|
broadcast_address: broadcast
|
||||||
host_address: host_addr
|
host_address: host_addr
|
||||||
prefix_len: prefix
|
prefix_len: prefix
|
||||||
current: net_addr.bigint()
|
current: net_addr.u8_array_fixed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -617,7 +617,7 @@ pub fn Ipv6Net.from_string(cidr string) !Ipv6Net {
|
|||||||
broadcast_address: broadcast
|
broadcast_address: broadcast
|
||||||
host_address: host_addr
|
host_address: host_addr
|
||||||
prefix_len: prefix_len
|
prefix_len: prefix_len
|
||||||
current: net_addr.bigint()
|
current: net_addr.u8_array_fixed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,14 +639,15 @@ pub fn Ipv6Net.from_bigint(addr big.Integer, prefix int) !Ipv6Net {
|
|||||||
}
|
}
|
||||||
host_mask := net_mask.bitwise_xor(max_u128)
|
host_mask := net_mask.bitwise_xor(max_u128)
|
||||||
broadcast := net_addr.bitwise_or(host_mask)
|
broadcast := net_addr.bitwise_or(host_mask)
|
||||||
|
net_addr6 := Ipv6Addr.from_bigint(net_addr)!
|
||||||
return Ipv6Net{
|
return Ipv6Net{
|
||||||
network_address: Ipv6Addr.from_bigint(net_addr)!
|
network_address: net_addr6
|
||||||
network_mask: Ipv6Addr.from_bigint(net_mask)!
|
network_mask: Ipv6Addr.from_bigint(net_mask)!
|
||||||
host_mask: Ipv6Addr.from_bigint(host_mask)!
|
host_mask: Ipv6Addr.from_bigint(host_mask)!
|
||||||
broadcast_address: Ipv6Addr.from_bigint(broadcast)!
|
broadcast_address: Ipv6Addr.from_bigint(broadcast)!
|
||||||
host_address: host_addr
|
host_address: host_addr
|
||||||
prefix_len: prefix
|
prefix_len: prefix
|
||||||
current: net_addr
|
current: net_addr6.u8_array_fixed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -689,13 +690,15 @@ pub fn (n Ipv6Net) capacity() big.Integer {
|
|||||||
// }
|
// }
|
||||||
// ```
|
// ```
|
||||||
pub fn (mut n Ipv6Net) next() ?Ipv6Addr {
|
pub fn (mut n Ipv6Net) next() ?Ipv6Addr {
|
||||||
if n.current >= n.broadcast_address.bigint() + big.one_int {
|
// Possible optimization: do not calculate `limit` on each fn call (use LRU cache?)
|
||||||
|
limit := add_128(n.broadcast_address.addr, one_128)
|
||||||
|
if compare_128(n.current, limit) in [0, 1] {
|
||||||
return none
|
return none
|
||||||
}
|
}
|
||||||
defer {
|
defer {
|
||||||
n.current = n.current + big.one_int
|
n.current = add_128(n.current, one_128)
|
||||||
}
|
}
|
||||||
return Ipv6Addr.from_bigint(n.current)!
|
return Ipv6Addr.from_octets(n.current)!
|
||||||
}
|
}
|
||||||
|
|
||||||
// first returns the first usable host address in network.
|
// first returns the first usable host address in network.
|
||||||
@ -703,7 +706,7 @@ pub fn (n Ipv6Net) first() Ipv6Addr {
|
|||||||
if n.prefix_len in [127, 128] {
|
if n.prefix_len in [127, 128] {
|
||||||
return n.network_address
|
return n.network_address
|
||||||
}
|
}
|
||||||
return Ipv6Addr.from_bigint(n.network_address.bigint() + big.one_int) or { panic(err) }
|
return Ipv6Addr.from_octets(add_128(n.network_address.addr, one_128)) or { panic(err) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// last returns the last usable host address in network.
|
// last returns the last usable host address in network.
|
||||||
@ -711,7 +714,7 @@ pub fn (n Ipv6Net) last() Ipv6Addr {
|
|||||||
if n.prefix_len in [127, 128] {
|
if n.prefix_len in [127, 128] {
|
||||||
return n.broadcast_address
|
return n.broadcast_address
|
||||||
}
|
}
|
||||||
return Ipv6Addr.from_bigint(n.broadcast_address.bigint() - big.one_int) or { panic(err) }
|
return Ipv6Addr.from_octets(sub_128(n.broadcast_address.addr, one_128)) or { panic(err) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// nth returns the Nth address in network. Supports negative indexes.
|
// nth returns the Nth address in network. Supports negative indexes.
|
||||||
|
@ -185,6 +185,12 @@ fn test_ipv6_net_format() {
|
|||||||
assert net.format(.verbose | .with_host_mask) == 'fe80:ffff:0000:0000:0000:0000:0000:0000/0000:0000:0000:0000:ffff:ffff:ffff:ffff'
|
assert net.format(.verbose | .with_host_mask) == 'fe80:ffff:0000:0000:0000:0000:0000:0000/0000:0000:0000:0000:ffff:ffff:ffff:ffff'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_ipv6_net_first_last() {
|
||||||
|
net := netaddr.Ipv6Net.from_string('fe80:ffff::/64')!
|
||||||
|
assert net.first().str() == 'fe80:ffff::1'
|
||||||
|
assert net.last().str() == 'fe80:ffff::ffff:ffff:ffff:fffe'
|
||||||
|
}
|
||||||
|
|
||||||
fn test_ipv6_net_next() {
|
fn test_ipv6_net_next() {
|
||||||
net := netaddr.Ipv6Net.from_string('fe80::/64')!
|
net := netaddr.Ipv6Net.from_string('fe80::/64')!
|
||||||
mut addrs := []netaddr.Ipv6Addr{}
|
mut addrs := []netaddr.Ipv6Addr{}
|
||||||
|
Reference in New Issue
Block a user