2
\$\begingroup\$

I have the following EF Core table:

[PrimaryKey(nameof(Name))]
public class Scope
{
    public required string Name { get; set; }
    public required IPNetwork Network { get; set; }
    public required IPAddress From { get; set; }
    public required IPAddress To { get; set; }
    public required IPAddress Gateway { get; set; }
    public required IPAddress Dns1 { get; set; }
    public IPAddress? Dns2 { get; set; }
    public required uint LeaseTimeInSeconds { get; set; }

    [ConcurrencyCheck]
    public DateTimeOffset LastUpdate { get; set; }

    public ICollection<AddressReservation> Reservations { get; set; } = null!;
    public ICollection<AddressLease> Leases { get; set; } = null!;
}

And I want to find the first IP address in this scope that is free and can be assigned to a client. This is what I wrote:

let rec checkAvailability ipAddress endIp =
    match
        (
            s.Leases |> Seq.tryFind (fun l -> l.IpAddress = ipAddress),
            s.Reservations |> Seq.tryFind (fun r -> r.IpAddress = ipAddress)
        )
    with
    | (None, None) -> Some ipAddress
    | _ when ipAddress.Equals(endIp) -> None
    | _ -> checkAvailability (incrementIp ipAddress) endIp

checkAvailability s.From s.To
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

preliminaries: Let us ignore IPv6 and focus on this proposed scope, supported by a router port:

  • 192.168.0.0/24

interval endpoints

I find this ambiguous; it needs documentation in the Review Context or at least the occasional comment.

    public required IPAddress From { get; set; }
    public required IPAddress To   { get; set; }

For the given scope, should From be 192.168.0.0, the all-zeros broadcast address? Or 192.168.0.1, the first available host? I will assume the latter.

More significantly, should To be .254, an "inclusive" representation of valid hosts? Or the .255 broadcast, an "exclusive" or half-open interval? The DB query implies the former; I suggest adopting the latter, as half-open intervals compose more nicely.

CIDR prefixes

I am sad that the OP code does not establish any "within range" relationship between (From, To) and the Network prefix.

query plan

    | _ -> checkAvailability (incrementIp ipAddress) endIp

It appears to me the app-level code is doing ip++ in order to issue many such queries. For RAM-resident datastructures that might be OK. But ideally we'd like to store a great many addresses in an RDBMS, and issue a single query for max(ip) within the interval, increment the result, and verify it's still within the interval. It looks like the OP code issues orders of magnitude more queries than necessary.

\$\endgroup\$
2
  • \$\begingroup\$ Thank you for your answer. From and To examples in your mentioned network could be 50 and 150 inclusive. For validations and guards the idea was it should happen at the controller level and we can relax DB (it shouldn't be modified directly). And as for the query, everything will be fetched into memory first. \$\endgroup\$ Commented Aug 3 at 8:32
  • \$\begingroup\$ This was a side project for me to practice F# and socket programming Link \$\endgroup\$ Commented Aug 3 at 8:33

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.