Commit a6ebfacf authored by Simon Kelley's avatar Simon Kelley

Massive refactor of stateful DHCPv6. Lease multiple prefixes per client.

parent c7961075
...@@ -265,8 +265,8 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct ...@@ -265,8 +265,8 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
return NULL; return NULL;
} }
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
int serial, struct dhcp_netid *netids, struct in6_addr *ans) int iaid, struct dhcp_netid *netids, struct in6_addr *ans)
{ {
/* Find a free address: exclude anything in use and anything allocated to /* Find a free address: exclude anything in use and anything allocated to
a particular hwaddr/clientid/hostname in our configuration. a particular hwaddr/clientid/hostname in our configuration.
...@@ -283,12 +283,12 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl ...@@ -283,12 +283,12 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
/* hash hwaddr: use the SDBM hashing algorithm. This works /* hash hwaddr: use the SDBM hashing algorithm. This works
for MAC addresses, let's see how it manages with client-ids! */ for MAC addresses, let's see how it manages with client-ids! */
for (j = 0, i = 0; i < clid_len; i++) for (j = iaid, i = 0; i < clid_len; i++)
j += clid[i] + (j << 6) + (j << 16) - j; j += clid[i] + (j << 6) + (j << 16) - j;
for (pass = 0; pass <= 1; pass++) for (pass = 0; pass <= 1; pass++)
for (c = context; c; c = c->current) for (c = context; c; c = c->current)
if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS)) if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS | CONTEXT_USED))
continue; continue;
else if (!match_netid(c->filter, netids, pass)) else if (!match_netid(c->filter, netids, pass))
continue; continue;
...@@ -296,9 +296,9 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl ...@@ -296,9 +296,9 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
{ {
if (option_bool(OPT_CONSEC_ADDR)) if (option_bool(OPT_CONSEC_ADDR))
/* seed is largest extant lease addr in this context */ /* seed is largest extant lease addr in this context */
start = lease_find_max_addr6(c) + serial; start = lease_find_max_addr6(c);
else else
start = addr6part(&c->start6) + ((j + c->addr_epoch + serial) % (1 + addr6part(&c->end6) - addr6part(&c->start6))); start = addr6part(&c->start6) + ((j + c->addr_epoch) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
/* iterate until we find a free address. */ /* iterate until we find a free address. */
addr = start; addr = start;
...@@ -315,7 +315,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl ...@@ -315,7 +315,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
{ {
*ans = c->start6; *ans = c->start6;
setaddr6part (ans, addr); setaddr6part (ans, addr);
return 1; return c;
} }
addr++; addr++;
...@@ -325,7 +325,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl ...@@ -325,7 +325,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
} while (addr != start); } while (addr != start);
} }
return 0; return 0;
} }
...@@ -369,34 +369,6 @@ struct dhcp_context *address6_valid(struct dhcp_context *context, ...@@ -369,34 +369,6 @@ struct dhcp_context *address6_valid(struct dhcp_context *context,
return NULL; return NULL;
} }
struct dhcp_context *narrow_context6(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids)
{
/* We start of with a set of possible contexts, all on the current physical interface.
These are chained on ->current.
Here we have an address, and return the actual context correponding to that
address. Note that none may fit, if the address came a dhcp-host and is outside
any dhcp-range. In that case we return a static range if possible, or failing that,
any context on the correct subnet. (If there's more than one, this is a dodgy
configuration: maybe there should be a warning.) */
struct dhcp_context *tmp;
if (!(tmp = address6_available(context, taddr, netids)) &&
!(tmp = address6_valid(context, taddr, netids)))
for (tmp = context; tmp; tmp = tmp->current)
if (match_netid(tmp->filter, netids, 1) &&
is_same_net6(taddr, &tmp->start6, tmp->prefix))
break;
/* Only one context allowed now */
if (tmp)
tmp->current = NULL;
return tmp;
}
static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config) static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config)
{ {
/* expand wildcard on contructed contexts */ /* expand wildcard on contructed contexts */
......
...@@ -681,6 +681,14 @@ struct cond_domain { ...@@ -681,6 +681,14 @@ struct cond_domain {
struct cond_domain *next; struct cond_domain *next;
}; };
#ifdef OPTION6_PREFIX_CLASS
struct prefix_class {
int class;
struct dhcp_netid netid;
struct prefix_class *next;
};
#endif
struct dhcp_context { struct dhcp_context {
unsigned int lease_time, addr_epoch; unsigned int lease_time, addr_epoch;
struct in_addr netmask, broadcast; struct in_addr netmask, broadcast;
...@@ -714,6 +722,7 @@ struct dhcp_context { ...@@ -714,6 +722,7 @@ struct dhcp_context {
#define CONTEXT_GC 4096 #define CONTEXT_GC 4096
#define CONTEXT_RA 8192 #define CONTEXT_RA 8192
#define CONTEXT_WILDCARD 16384 #define CONTEXT_WILDCARD 16384
#define CONTEXT_USED 32768
struct ping_result { struct ping_result {
struct in_addr addr; struct in_addr addr;
...@@ -1055,7 +1064,8 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr); ...@@ -1055,7 +1064,8 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr);
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type); struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type);
struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len, struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
int lease_type, int iaid, struct in6_addr *addr); int lease_type, int iaid, struct in6_addr *addr);
void lease6_filter(int lease_type, int iaid, struct dhcp_context *context); void lease6_reset(void);
struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid);
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr); struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr);
u64 lease_find_max_addr6(struct dhcp_context *context); u64 lease_find_max_addr6(struct dhcp_context *context);
void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface); void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface);
...@@ -1160,8 +1170,8 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr, ...@@ -1160,8 +1170,8 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
void dhcp6_init(void); void dhcp6_init(void);
void dhcp6_packet(time_t now); void dhcp6_packet(time_t now);
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
int serial, struct dhcp_netid *netids, struct in6_addr *ans); int iaid, struct dhcp_netid *netids, struct in6_addr *ans);
int is_addr_in_context6(struct dhcp_context *context, struct in6_addr *addr); int is_addr_in_context6(struct dhcp_context *context, struct in6_addr *addr);
struct dhcp_context *address6_available(struct dhcp_context *context, struct dhcp_context *address6_available(struct dhcp_context *context,
struct in6_addr *taddr, struct in6_addr *taddr,
...@@ -1169,9 +1179,6 @@ struct dhcp_context *address6_available(struct dhcp_context *context, ...@@ -1169,9 +1179,6 @@ struct dhcp_context *address6_available(struct dhcp_context *context,
struct dhcp_context *address6_valid(struct dhcp_context *context, struct dhcp_context *address6_valid(struct dhcp_context *context,
struct in6_addr *taddr, struct in6_addr *taddr,
struct dhcp_netid *netids); struct dhcp_netid *netids);
struct dhcp_context *narrow_context6(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids);
struct dhcp_config *find_config6(struct dhcp_config *configs, struct dhcp_config *find_config6(struct dhcp_config *configs,
struct dhcp_context *context, struct dhcp_context *context,
unsigned char *duid, int duid_len, unsigned char *duid, int duid_len,
......
...@@ -555,8 +555,7 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr) ...@@ -555,8 +555,7 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
} }
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
/* addr or clid may be NULL for "don't care, both NULL resets "USED" flags both /* find address for {CLID, IAID, address} */
set activates USED check */
struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len, struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
int lease_type, int iaid, struct in6_addr *addr) int lease_type, int iaid, struct in6_addr *addr)
{ {
...@@ -567,40 +566,52 @@ struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len, ...@@ -567,40 +566,52 @@ struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid) if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
continue; continue;
if (clid && addr && (lease->flags & LEASE_USED)) if (memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0)
continue; continue;
if (addr && memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0) if ((clid_len != lease->clid_len ||
continue;
if (clid &&
(clid_len != lease->clid_len ||
memcmp(clid, lease->clid, clid_len) != 0)) memcmp(clid, lease->clid, clid_len) != 0))
continue; continue;
lease->flags |= LEASE_USED;
return lease; return lease;
} }
return NULL; return NULL;
} }
void lease6_filter(int lease_type, int iaid, struct dhcp_context *context) /* reset "USED flags */
void lease6_reset(void)
{ {
struct dhcp_lease *lease; struct dhcp_lease *lease;
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
lease->flags &= ~LEASE_USED;
}
/* enumerate all leases belonging to {CLID, IAID} */
struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid)
{
struct dhcp_lease *lease;
if (!first)
first = leases;
for (lease = first; lease; lease = lease->next)
{ {
/* reset "USED flag */ if (lease->flags & LEASE_USED)
lease->flags &= ~LEASE_USED; continue;
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid) if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
continue; continue;
/* leases on the wrong interface get filtered out here */ if ((clid_len != lease->clid_len ||
if (!is_addr_in_context6(context, (struct in6_addr *)&lease->hwaddr)) memcmp(clid, lease->clid, clid_len) != 0))
lease->flags |= LEASE_USED; continue;
return lease;
} }
return NULL;
} }
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr) struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment