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

This commit is contained in:
Simon Kelley
2013-03-06 20:52:35 +00:00
parent c7961075c4
commit a6ebfacf7b
4 changed files with 713 additions and 638 deletions

View File

@@ -265,8 +265,8 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
return NULL;
}
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
int serial, struct dhcp_netid *netids, struct in6_addr *ans)
struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
int iaid, struct dhcp_netid *netids, struct in6_addr *ans)
{
/* Find a free address: exclude anything in use and anything allocated to
a particular hwaddr/clientid/hostname in our configuration.
@@ -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
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;
for (pass = 0; pass <= 1; pass++)
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;
else if (!match_netid(c->filter, netids, pass))
continue;
@@ -296,9 +296,9 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
{
if (option_bool(OPT_CONSEC_ADDR))
/* seed is largest extant lease addr in this context */
start = lease_find_max_addr6(c) + serial;
start = lease_find_max_addr6(c);
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. */
addr = start;
@@ -315,7 +315,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
{
*ans = c->start6;
setaddr6part (ans, addr);
return 1;
return c;
}
addr++;
@@ -325,7 +325,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
} while (addr != start);
}
return 0;
}
@@ -369,34 +369,6 @@ struct dhcp_context *address6_valid(struct dhcp_context *context,
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)
{
/* expand wildcard on contructed contexts */

View File

@@ -681,6 +681,14 @@ struct cond_domain {
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 {
unsigned int lease_time, addr_epoch;
struct in_addr netmask, broadcast;
@@ -714,6 +722,7 @@ struct dhcp_context {
#define CONTEXT_GC 4096
#define CONTEXT_RA 8192
#define CONTEXT_WILDCARD 16384
#define CONTEXT_USED 32768
struct ping_result {
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_find(unsigned char *clid, int clid_len,
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);
u64 lease_find_max_addr6(struct dhcp_context *context);
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,
#ifdef HAVE_DHCP6
void dhcp6_init(void);
void dhcp6_packet(time_t now);
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
int serial, struct dhcp_netid *netids, struct in6_addr *ans);
struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
int iaid, struct dhcp_netid *netids, struct in6_addr *ans);
int is_addr_in_context6(struct dhcp_context *context, struct in6_addr *addr);
struct dhcp_context *address6_available(struct dhcp_context *context,
struct in6_addr *taddr,
@@ -1169,9 +1179,6 @@ struct dhcp_context *address6_available(struct dhcp_context *context,
struct dhcp_context *address6_valid(struct dhcp_context *context,
struct in6_addr *taddr,
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_context *context,
unsigned char *duid, int duid_len,

View File

@@ -555,8 +555,7 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
}
#ifdef HAVE_DHCP6
/* addr or clid may be NULL for "don't care, both NULL resets "USED" flags both
set activates USED check */
/* find address for {CLID, IAID, address} */
struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
int lease_type, int iaid, struct in6_addr *addr)
{
@@ -567,40 +566,52 @@ struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
continue;
if (clid && addr && (lease->flags & LEASE_USED))
if (memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0)
continue;
if (addr && memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0)
continue;
if (clid &&
(clid_len != lease->clid_len ||
if ((clid_len != lease->clid_len ||
memcmp(clid, lease->clid, clid_len) != 0))
continue;
lease->flags |= LEASE_USED;
return lease;
}
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;
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 */
lease->flags &= ~LEASE_USED;
if (lease->flags & LEASE_USED)
continue;
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
continue;
/* leases on the wrong interface get filtered out here */
if (!is_addr_in_context6(context, (struct in6_addr *)&lease->hwaddr))
lease->flags |= LEASE_USED;
if ((clid_len != lease->clid_len ||
memcmp(clid, lease->clid, clid_len) != 0))
continue;
return lease;
}
return NULL;
}
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)

File diff suppressed because it is too large Load Diff