]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
Prefix pools are attached to shared network scopes
authorFrancis Dupont <fdupont@isc.org>
Mon, 17 Mar 2008 15:25:49 +0000 (15:25 +0000)
committerFrancis Dupont <fdupont@isc.org>
Mon, 17 Mar 2008 15:25:49 +0000 (15:25 +0000)
RELNOTES
includes/dhcpd.h
server/confpars.c
server/dhcpv6.c

index 15d55f612e5bba30acff7dc0005b78b883a7e235..2d08edcee25cf43996f9155050622d2b64b92aa3 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -69,6 +69,8 @@ work on other platforms. Please report any problems and suggested fixes to
 - Shared network selection should be done from the innermost relay
   valid link-address field, rather than the outermost.
 
+- Prefix pools are attached to shared network scopes.
+
                        Changes since 4.0.0 (new features)
 
 - Added DHCPv6 rapid commit support.
index 7b17709335a782a45a216cdb5ceaa638f94c0c61..eddeb08141ddcb70aee39930008968f89ca98b16 100644 (file)
@@ -813,6 +813,7 @@ struct shared_network {
        struct ipv6_pool **ipv6_pools;          /* NULL-terminated array */
        int last_ipv6_pool;                     /* offset of last IPv6 pool
                                                   used to issue a lease */
+       struct ipv6_ppool **ipv6_ppools;        /* NULL-terminated array */
        struct group *group;
 #if defined (FAILOVER_PROTOCOL)
        dhcp_failover_state_t *failover_peer;
@@ -1427,6 +1428,8 @@ struct ipv6_ppool {
        int num_inactive;                       /* count of inactive IAADDR */
        isc_heap_t *inactive_timeouts;          /* timeouts for expired or 
                                                   released leases */
+       struct shared_network *shared_network;  /* shared_network for 
+                                                  this pool */
 };
 
 extern struct ipv6_ppool **ppools;
index 1aaaaed20e340d8f3ec147146882f880d908c0e9..b01638844920404f92e449feda9078af23c4da15 100644 (file)
@@ -627,7 +627,7 @@ int parse_statement (cfile, group, type, host_decl, declaration)
 
              case PREFIX6:
                next_token(NULL, NULL, cfile);
-               if (type != ROOT_GROUP) {
+               if ((type != SUBNET_DECL) || (group->subnet == NULL)) {
                        parse_warn (cfile,
                                    "prefix6 definitions may not be scoped.");
                        skip_to_semi(cfile);
@@ -3817,11 +3817,14 @@ parse_address_range6(struct parse *cfile, struct group *group) {
 }
 
 static void
-add_ipv6_ppool_to_global(struct iaddr *start_addr,
-                        int pool_bits,
-                        int alloc_bits) {
+add_ipv6_ppool_to_shared_network(struct shared_network *share, 
+                                struct iaddr *start_addr,
+                                int pool_bits,
+                                int alloc_bits) {
        struct ipv6_ppool *ppool;
        struct in6_addr tmp_in6_addr;
+       int num_ppools;
+       struct ipv6_ppool **tmp;
 
        /*
         * Create our prefix pool.
@@ -3843,6 +3846,43 @@ add_ipv6_ppool_to_global(struct iaddr *start_addr,
        if (add_ipv6_ppool(ppool) != ISC_R_SUCCESS) {
                log_fatal ("Out of memory");
        }
+
+       /*
+        * Link our prefix pool to our shared_network.
+        */
+       ppool->shared_network = NULL;
+       shared_network_reference(&ppool->shared_network, share, MDL);
+
+       /* 
+        * Increase our array size for ipv6_ppools in the shared_network.
+        */
+       if (share->ipv6_ppools == NULL) {
+               num_ppools = 0;
+       } else {
+               num_ppools = 0;
+               while (share->ipv6_ppools[num_ppools] != NULL) {
+                       num_ppools++;
+               }
+       }
+       tmp = dmalloc(sizeof(struct ipv6_ppool *) * (num_ppools + 2), MDL);
+       if (tmp == NULL) {
+               log_fatal("Out of memory");
+       }
+       if (num_ppools > 0) {
+               memcpy(tmp, share->ipv6_ppools,
+                      sizeof(struct ipv6_ppool *) * num_ppools);
+       }
+       if (share->ipv6_ppools != NULL) {
+               dfree(share->ipv6_ppools, MDL);
+       }
+       share->ipv6_ppools = tmp;
+
+       /* 
+        * Record this prefix pool in our array of prefix pools
+        * for this shared network.
+        */
+       ipv6_ppool_reference(&share->ipv6_ppools[num_ppools], ppool, MDL);
+       share->ipv6_ppools[num_ppools+1] = NULL;
 }
 
 /* prefix6-declaration :== ip-address6 ip-address6 SLASH number SEMI */
@@ -3853,9 +3893,25 @@ parse_prefix6(struct parse *cfile, struct group *group) {
        int bits;
        enum dhcp_token token;
        const char *val;
+       struct shared_network *share;
        struct iaddrcidrnetlist *nets;
        struct iaddrcidrnetlist *p;
 
+       if (local_family != AF_INET6) {
+               parse_warn(cfile, "prefix6 statement is only supported "
+                                 "in DHCPv6 mode.");
+               skip_to_semi(cfile);
+               return;
+       }
+
+       /*
+        * We'll use the shared_network from our group.
+        */
+       share = group->shared_network;
+       if (share == NULL) {
+               share = group->subnet->shared_network;
+       }
+        
        /*
         * Read starting and ending address.
         */
@@ -3900,7 +3956,6 @@ parse_prefix6(struct parse *cfile, struct group *group) {
                return;
        }
 
-
        /*
         * Convert our range to a set of CIDR networks.
         */
@@ -3918,8 +3973,9 @@ parse_prefix6(struct parse *cfile, struct group *group) {
                        parse_warn(cfile, "impossible mask length");
                        continue;
                }
-               add_ipv6_ppool_to_global(&p->cidrnet.lo_addr,
-                                        p->cidrnet.bits, bits);
+               add_ipv6_ppool_to_shared_network(share,
+                                                &p->cidrnet.lo_addr,
+                                                p->cidrnet.bits, bits);
        }
 
        free_iaddrcidrnetlist(&nets);
index 7b20d36b5ec7ed73da9424df742b8b60eef6529a..a0ecec03b9ae7202a051e8398a5ef9f7264b49b5 100644 (file)
@@ -103,8 +103,8 @@ static int get_encapsulated_IA_state(struct option_state **enc_opt_state,
                                     struct option_cache *oc,
                                     int offset);
 static void build_dhcpv6_reply(struct data_string *, struct packet *);
-static void shared_network_from_packet6(struct shared_network **shared,
-                                       struct packet *packet);
+static isc_result_t shared_network_from_packet6(struct shared_network **shared,
+                                               struct packet *packet);
 static void seek_shared_host(struct host_decl **hp,
                             struct shared_network *shared);
 static isc_boolean_t fixed_matches_shared(struct host_decl *host,
@@ -1143,6 +1143,7 @@ try_client_v6_prefix(struct iaprefix **pref,
  */
 static isc_result_t 
 pick_v6_prefix(struct iaprefix **pref, int plen,
+              struct shared_network *shared_network,
               const struct data_string *client_id)
 {
        struct ipv6_ppool *p;
@@ -1153,19 +1154,19 @@ pick_v6_prefix(struct iaprefix **pref, int plen,
        /*
         * No prefix pools, we're done.
         */
-       if (!num_ppools) {
+       if (shared_network->ipv6_ppools == NULL) {
                log_debug("Unable to pick client prefix: "
-                         "no IPv6 prefix pools");
+                         "no IPv6 prefix pools on this shared network");
                return ISC_R_NORESOURCES;
        }
 
        /*
         * Otherwise try to get a prefix.
         */
-       for (i = 0; i < num_ppools; i++) {
-               p = ppools[i];
+       for (i = 0;; i++) {
+               p = shared_network->ipv6_ppools[i];
                if (p == NULL) {
-                       continue;
+                       break;
                }
 
                /*
@@ -1229,7 +1230,9 @@ lease_to_client(struct data_string *reply_ret,
        isc_boolean_t no_resources_avail;
 
        /* Locate the client.  */
-       shared_network_from_packet6(&reply.shared, packet);
+       if (shared_network_from_packet6(&reply.shared,
+                                       packet) != ISC_R_SUCCESS)
+               goto exit;
 
        /* 
         * Initialize the reply.
@@ -1264,17 +1267,13 @@ lease_to_client(struct data_string *reply_ret,
         * valid for the shared network the client is on.
         */
        if (find_hosts_by_option(&reply.host, packet, packet->options, MDL)) {
-               if (reply.shared != NULL) {
-                       seek_shared_host(&reply.host, reply.shared);
-               }
+               seek_shared_host(&reply.host, reply.shared);
        }
 
        if ((reply.host == NULL) &&
            find_hosts_by_uid(&reply.host, client_id->data, client_id->len,
                              MDL)) {
-               if (reply.shared != NULL) {
-                       seek_shared_host(&reply.host, reply.shared);
-               }
+               seek_shared_host(&reply.host, reply.shared);
        }
 
        /* Process the client supplied IA's onto the reply buffer. */
@@ -1284,10 +1283,6 @@ lease_to_client(struct data_string *reply_ret,
        for (; oc != NULL ; oc = oc->next) {
                isc_result_t status;
 
-               /* A shared network is required. */
-               if (reply.shared == NULL)
-                       goto exit;
-
                /* Start counting resources (addresses) offered. */
                reply.client_resources = 0;
                reply.ia_resources_included = ISC_FALSE;
@@ -1313,10 +1308,6 @@ lease_to_client(struct data_string *reply_ret,
        for (; oc != NULL ; oc = oc->next) {
                isc_result_t status;
 
-               /* A shared network is required. */
-               if (reply.shared == NULL)
-                       goto exit;
-
                /* Start counting resources (addresses) offered. */
                reply.client_resources = 0;
                reply.ia_resources_included = ISC_FALSE;
@@ -3373,7 +3364,7 @@ reply_process_prefix(struct reply_state *reply, struct option_cache *pref) {
                        log_fatal("Impossible condition at %s:%d.", MDL);
 
                scope = &reply->prefix->scope;
-               group = root_group;
+               group = reply->shared->group;
        }
 
        /*
@@ -3490,7 +3481,9 @@ reply_process_try_prefix(struct reply_state *reply,
        int i;
        struct data_string data_pref;
 
-       if ((reply == NULL) || (pref == NULL) || (reply->prefix != NULL))
+       if ((reply == NULL) || (reply->shared == NULL) ||
+           (reply->shared->ipv6_ppools == NULL) || (pref == NULL) ||
+           (reply->prefix != NULL))
                return ISC_R_INVALIDARG;
 
        memset(&data_pref, 0, sizeof(data_pref));
@@ -3503,10 +3496,10 @@ reply_process_try_prefix(struct reply_state *reply,
        data_pref.buffer->data[0] = (u_int8_t) pref->bits;
        memcpy(data_pref.buffer->data + 1, pref->lo_addr.iabuf, 16);
 
-       for (i = 0 ; i < num_ppools ; i++) {
-               ppool = ppools[i];
+       for (i = 0 ;; i++) {
+               ppool = reply->shared->ipv6_ppools[i];
                if (ppool == NULL)
-                       continue;
+                       break;
                status = try_client_v6_prefix(&reply->prefix, ppool,
                                              &data_pref);
                if (status == ISC_R_SUCCESS)
@@ -3533,10 +3526,8 @@ find_client_prefix(struct reply_state *reply) {
 
        if (reply->host != NULL)
                group = reply->host->group;
-       else if (reply->shared != NULL)
-               group = reply->shared->group;
        else
-               group = root_group;
+               group = reply->shared->group;
 
        if (reply->static_prefixes > 0) {
                struct iaddrcidrnetlist *l;
@@ -3576,7 +3567,7 @@ find_client_prefix(struct reply_state *reply) {
         */
        if ((best_prefix == NULL) || (best_prefix->state == FTS_ABANDONED)) {
                status = pick_v6_prefix(&reply->prefix, reply->preflen,
-                                       &reply->client_id);
+                                       reply->shared, &reply->client_id);
        } else if (best_prefix != NULL) {
                iaprefix_reference(&reply->prefix, best_prefix, MDL);
                status = ISC_R_SUCCESS;
@@ -3599,11 +3590,7 @@ find_client_prefix(struct reply_state *reply) {
                log_fatal("Impossible condition at %s:%d.", MDL);
 
        scope = &reply->prefix->scope;
-       if (reply->shared != NULL) {
-               group = reply->shared->group;
-       } else {
-               group = root_group;
-       }
+       group = reply->shared->group;
 
        send_pref.lo_addr.len = 16;
        memcpy(send_pref.lo_addr.iabuf, &reply->prefix->pref, 16);
@@ -3929,7 +3916,7 @@ dhcpv6_request(struct data_string *reply_ret, struct packet *packet) {
 
 /* Find a DHCPv6 packet's shared network from hints in the packet.
  */
-static void
+static isc_result_t
 shared_network_from_packet6(struct shared_network **shared,
                            struct packet *packet)
 {
@@ -3937,11 +3924,10 @@ shared_network_from_packet6(struct shared_network **shared,
        const struct in6_addr *link_addr, *first_link_addr;
        struct iaddr tmp_addr;
        struct subnet *subnet;
+       isc_result_t status;
 
-       if ((shared == NULL) || (*shared != NULL) || (packet == NULL)) {
-               log_error("shared_network_from_packet6: invalid arg.");
-               return;
-       }
+       if ((shared == NULL) || (*shared != NULL) || (packet == NULL))
+               return ISC_R_INVALIDARG;
 
        /*
         * First, find the link address where the packet from the client
@@ -3972,9 +3958,10 @@ shared_network_from_packet6(struct shared_network **shared,
                if (!find_subnet(&subnet, tmp_addr, MDL)) {
                        log_debug("No subnet found for link-address %s.",
                                  piaddr(tmp_addr));
-                       return;
+                       return ISC_R_NOTFOUND;
                }
-               shared_network_reference(shared, subnet->shared_network, MDL);
+               status = shared_network_reference(shared,
+                                                 subnet->shared_network, MDL);
                subnet_dereference(&subnet, MDL);
 
        /*
@@ -3982,10 +3969,12 @@ shared_network_from_packet6(struct shared_network **shared,
         * that this packet came in on to pick the shared_network.
         */
        } else {
-               shared_network_reference(shared,
+               status = shared_network_reference(shared,
                                         packet->interface->shared_network,
                                         MDL);
        }
+
+       return status;
 }
 
 /*
@@ -4054,8 +4043,8 @@ dhcpv6_confirm(struct data_string *reply_ret, struct packet *packet) {
         * network the client is on.
         */
        shared = NULL;
-       shared_network_from_packet6(&shared, packet);
-       if (shared == NULL)
+       if ((shared_network_from_packet6(&shared, packet) != ISC_R_SUCCESS) ||
+           (shared == NULL))
                goto exit;
 
        /* If there are no recorded subnets, then we have no
@@ -5651,8 +5640,9 @@ seek_shared_host(struct host_decl **hp, struct shared_network *shared) {
        struct host_decl *seek, *hold = NULL;
 
        /*
-        * Seek forward through fixed addresses for the right broadcast
-        * domain.
+        * Seek forward through fixed addresses for the right link.
+        *
+        * Note: how to do this for fixed prefixes???
         */
        host_reference(&hold, *hp, MDL);
        host_dereference(hp, MDL);