Index: src/cf.data.pre =================================================================== RCS file: /server/cvs-server/squid/squid/src/cf.data.pre,v retrieving revision 1.368 diff -u -r1.368 cf.data.pre --- src/cf.data.pre 18 Sep 2006 23:09:39 -0000 1.368 +++ src/cf.data.pre 20 Sep 2006 09:28:06 -0000 @@ -4291,6 +4291,26 @@ option is set to GRE. DOC_END +NAME: wccp2_assignment_method +TYPE: int +LOC: Config.Wccp2.assignment_method +DEFAULT: 1 +IFDEF: USE_WCCPv2 +DOC_START + WCCP2 allows the setting of methods to assign the WCCP hash + Valid values are as follows: + + 1 - Hash assignment + 2 - Mask assignment + + Currently (as of IOS 12.4) cisco routers only support assignment. + Cisco switches support the L2 redirect assignment method. + + On a cisco 7600, enabling the "accelerated" feature on a wccp service + forces the router to use L2 forwarding/return methods and a mask + assignment method +DOC_END + NAME: wccp2_service TYPE: wccp2_service LOC: Config.Wccp2.info Index: src/structs.h =================================================================== RCS file: /server/cvs-server/squid/squid/src/structs.h,v retrieving revision 1.501 diff -u -r1.501 structs.h --- src/structs.h 18 Sep 2006 23:09:39 -0000 1.501 +++ src/structs.h 20 Sep 2006 09:28:08 -0000 @@ -507,6 +507,7 @@ struct in_addr address; int forwarding_method; int return_method; + int assignment_method; int weight; int rebuildwait; void *info; Index: src/wccp2.c =================================================================== RCS file: /server/cvs-server/squid/squid/src/wccp2.c,v retrieving revision 1.25 diff -u -r1.25 wccp2.c --- src/wccp2.c 18 Sep 2006 23:09:39 -0000 1.25 +++ src/wccp2.c 20 Sep 2006 09:28:11 -0000 @@ -67,7 +67,7 @@ #define WCCP2_SERVICE_SRC_IP_HASH 0x1 #define WCCP2_SERVICE_DST_IP_HASH 0x2 -#define WCCP2_SERVICE_SOURCE_PORT_HASH 0x4 +#define WCCP2_SERVICE_SRC_PORT_HASH 0x4 #define WCCP2_SERVICE_DST_PORT_HASH 0x8 #define WCCP2_SERVICE_PORTS_DEFINED 0x10 #define WCCP2_SERVICE_PORTS_SOURCE 0x20 @@ -90,6 +90,12 @@ #define WCCP2_CAPABILITY_INFO 8 +#define WCCP2_ALT_ASSIGNMENT 13 + +#define WCCP2_ASSIGN_MAP 14 + +#define WCCP2_COMMAND_EXTENSION 15 + #define WCCP2_CAPABILITY_FORWARDING_METHOD 0x01 #define WCCP2_CAPABILITY_ASSIGNMENT_METHOD 0x02 #define WCCP2_CAPABILITY_RETURN_METHOD 0x03 @@ -103,6 +109,9 @@ #define WCCP2_PACKET_RETURN_METHOD_GRE 0x00000001 #define WCCP2_PACKET_RETURN_METHOD_L2 0x00000002 +#define WCCP2_HASH_ASSIGNMENT 0x00 +#define WCCP2_MASK_ASSIGNMENT 0x01 + #define WCCP2_NONE_SECURITY_LEN 0 #define WCCP2_MD5_SECURITY_LEN 16 @@ -170,6 +179,27 @@ static struct wccp2_identity_info_t wccp2_identity_info; +struct wccp2_cache_mask_identity_info_t { + struct in_addr addr; + uint32_t num1; + uint32_t num2; + uint32_t source_ip_mask; + uint32_t dest_ip_mask; + uint16_t source_port_mask; + uint16_t dest_port_mask; + uint32_t num3; + uint32_t num4; +}; + +/* Web Cache identity info */ +struct wccp2_mask_identity_info_t { + uint16_t cache_identity_type; + uint16_t cache_identity_length; + struct wccp2_cache_mask_identity_info_t cache_identity; +}; + +static struct wccp2_mask_identity_info_t wccp2_mask_identity_info; + /* View header */ struct wccp2_cache_view_header_t { uint16_t cache_view_type; @@ -218,6 +248,23 @@ static struct wccp2_capability_element_t wccp2_capability_element; +/* Mask Element */ +struct wccp2_mask_element_t { + uint32_t source_ip_mask; + uint32_t dest_ip_mask; + uint16_t source_port_mask; + uint16_t dest_port_mask; + uint32_t number_values; +}; + +/* Value Element */ +struct wccp2_value_element_t { + uint32_t source_ip_value; + uint32_t dest_ip_value; + uint16_t source_port_value; + uint16_t dest_port_value; + struct in_addr cache_ip; +}; /* RECEIVED PACKET STRUCTURE */ struct wccp2_i_see_you_t { @@ -250,6 +297,14 @@ uint32_t number_caches; }; +/* The received packet for a mask assignment is unusual */ +struct cache_mask_info_t { + struct in_addr addr; + uint32_t num1; + uint32_t num2; + uint32_t num3; +}; + /* assigment key */ struct assignment_key_t { struct in_addr master_ip; @@ -263,7 +318,6 @@ struct assignment_key_t assignment_key; }; - /* Lists used to keep track of caches, routers and services */ struct wccp2_cache_list_t { struct in_addr cache_ip; @@ -289,7 +343,7 @@ struct wccp2_router_list_t router_list_head; int lowest_ip; uint32_t change_num; - struct wccp2_identity_info_t *wccp2_identity_info_ptr; + char *wccp2_identity_info_ptr; struct wccp2_security_md5_t *security_info; struct wccp2_service_info_t *service_info; char wccp_packet[WCCP_RESPONSE_SIZE]; @@ -471,6 +525,7 @@ { sockaddr_in_list *s; char *ptr; + uint32_t service_flags; struct wccp2_service_list_t *service_list_ptr; struct wccp2_router_list_t *router_list_ptr; struct wccp2_security_md5_t wccp2_security_md5; @@ -537,19 +592,64 @@ ptr += sizeof(struct wccp2_service_info_t); /* Add the cache identity section */ - wccp2_here_i_am_header.length += sizeof(struct wccp2_identity_info_t); - assert(wccp2_here_i_am_header.length <= WCCP_RESPONSE_SIZE); - wccp2_identity_info.cache_identity_type = htons(WCCP2_WC_ID_INFO); - wccp2_identity_info.cache_identity_length = htons(sizeof(wccp2_identity_info.cache_identity)); - memset(&wccp2_identity_info.cache_identity.addr, '\0', sizeof(wccp2_identity_info.cache_identity.addr)); - memset(&wccp2_identity_info.cache_identity.hash_revision, '\0', sizeof(wccp2_identity_info.cache_identity.hash_revision)); - memset(&wccp2_identity_info.cache_identity.bits, '\0', sizeof(wccp2_identity_info.cache_identity.bits)); - memset(&wccp2_identity_info.cache_identity.buckets, '\0', sizeof(wccp2_identity_info.cache_identity.buckets)); - wccp2_identity_info.cache_identity.weight = htons(Config.Wccp2.weight); - memset(&wccp2_identity_info.cache_identity.status, '\0', sizeof(wccp2_identity_info.cache_identity.status)); - xmemcpy(ptr, &wccp2_identity_info, sizeof(struct wccp2_identity_info_t)); - service_list_ptr->wccp2_identity_info_ptr = (struct wccp2_identity_info_t *) ptr; - ptr += sizeof(struct wccp2_identity_info_t); + switch (Config.Wccp2.assignment_method) { + case WCCP2_ASSIGNMENT_METHOD_HASH: + wccp2_here_i_am_header.length += sizeof(struct wccp2_identity_info_t); + assert(wccp2_here_i_am_header.length <= WCCP_RESPONSE_SIZE); + wccp2_identity_info.cache_identity_type = htons(WCCP2_WC_ID_INFO); + wccp2_identity_info.cache_identity_length = htons(sizeof(wccp2_identity_info.cache_identity)); + memset(&wccp2_identity_info.cache_identity.addr, '\0', sizeof(wccp2_identity_info.cache_identity.addr)); + memset(&wccp2_identity_info.cache_identity.hash_revision, '\0', sizeof(wccp2_identity_info.cache_identity.hash_revision)); + memset(&wccp2_identity_info.cache_identity.bits, '\0', sizeof(wccp2_identity_info.cache_identity.bits)); + memset(&wccp2_identity_info.cache_identity.buckets, '\0', sizeof(wccp2_identity_info.cache_identity.buckets)); + wccp2_identity_info.cache_identity.weight = htons(Config.Wccp2.weight); + memset(&wccp2_identity_info.cache_identity.status, '\0', sizeof(wccp2_identity_info.cache_identity.status)); + xmemcpy(ptr, &wccp2_identity_info, sizeof(struct wccp2_identity_info_t)); + service_list_ptr->wccp2_identity_info_ptr = ptr; + ptr += sizeof(struct wccp2_identity_info_t); + break; + case WCCP2_ASSIGNMENT_METHOD_MASK: + wccp2_here_i_am_header.length += sizeof(struct wccp2_mask_identity_info_t); + assert(wccp2_here_i_am_header.length <= WCCP_RESPONSE_SIZE); + wccp2_mask_identity_info.cache_identity_type = htons(WCCP2_WC_ID_INFO); + wccp2_mask_identity_info.cache_identity_length = htons(sizeof(wccp2_mask_identity_info.cache_identity)); + memset(&wccp2_mask_identity_info.cache_identity.addr, '\0', sizeof(wccp2_mask_identity_info.cache_identity.addr)); + wccp2_mask_identity_info.cache_identity.num1 = htonl(2); + wccp2_mask_identity_info.cache_identity.num2 = htonl(1); + service_flags = ntohl(service_list_ptr->service_info->service_flags); + if ((service_flags & WCCP2_SERVICE_SRC_IP_HASH) || (service_flags & WCCP2_SERVICE_SRC_IP_ALT_HASH)) { + wccp2_mask_identity_info.cache_identity.source_ip_mask = htonl(0x00001741); + wccp2_mask_identity_info.cache_identity.dest_ip_mask = 0; + wccp2_mask_identity_info.cache_identity.source_port_mask = 0; + wccp2_mask_identity_info.cache_identity.dest_port_mask = 0; + } else if ((service_flags & WCCP2_SERVICE_DST_IP_HASH) || (service_flags & WCCP2_SERVICE_DST_IP_ALT_HASH)) { + wccp2_mask_identity_info.cache_identity.source_ip_mask = 0; + wccp2_mask_identity_info.cache_identity.dest_ip_mask = htonl(0x00001741); + wccp2_mask_identity_info.cache_identity.source_port_mask = 0; + wccp2_mask_identity_info.cache_identity.dest_port_mask = 0; + } else if ((service_flags & WCCP2_SERVICE_SRC_PORT_HASH) || (service_flags & WCCP2_SERVICE_SRC_PORT_ALT_HASH)) { + wccp2_mask_identity_info.cache_identity.source_ip_mask = 0; + wccp2_mask_identity_info.cache_identity.dest_ip_mask = 0; + wccp2_mask_identity_info.cache_identity.source_port_mask = htons(0x1741); + wccp2_mask_identity_info.cache_identity.dest_port_mask = 0; + } else if ((service_flags & WCCP2_SERVICE_DST_PORT_HASH) || (service_flags & WCCP2_SERVICE_DST_PORT_ALT_HASH)) { + wccp2_mask_identity_info.cache_identity.source_ip_mask = 0; + wccp2_mask_identity_info.cache_identity.dest_ip_mask = 0; + wccp2_mask_identity_info.cache_identity.source_port_mask = 0; + wccp2_mask_identity_info.cache_identity.dest_port_mask = htons(0x1741); + } else { + fatalf("Unknown service hash method\n"); + } + wccp2_mask_identity_info.cache_identity.num3 = 0; + wccp2_mask_identity_info.cache_identity.num4 = 0; + + xmemcpy(ptr, &wccp2_mask_identity_info, sizeof(struct wccp2_mask_identity_info_t)); + service_list_ptr->wccp2_identity_info_ptr = ptr; + ptr += sizeof(struct wccp2_mask_identity_info_t); + break; + default: + fatalf("Unknown Wccp2 assignment method\n"); + } /* Add the cache view section */ wccp2_here_i_am_header.length += sizeof(wccp2_cache_view_header); @@ -622,7 +722,7 @@ assert(wccp2_here_i_am_header.length <= WCCP_RESPONSE_SIZE); wccp2_capability_element.capability_type = htons(WCCP2_CAPABILITY_ASSIGNMENT_METHOD); wccp2_capability_element.capability_length = htons(sizeof(wccp2_capability_element.capability_value)); - wccp2_capability_element.capability_value = htonl(WCCP2_ASSIGNMENT_METHOD_HASH); + wccp2_capability_element.capability_value = htonl(Config.Wccp2.assignment_method); xmemcpy(ptr, &wccp2_capability_element, sizeof(wccp2_capability_element)); ptr += sizeof(wccp2_capability_element); @@ -784,6 +884,8 @@ struct router_identity_info_t *router_identity_info = NULL; struct router_view_t *router_view_header = NULL; struct wccp2_cache_identity_info_t *cache_identity = NULL; + struct wccp2_cache_mask_identity_info_t *cache_mask_identity = NULL; + struct cache_mask_info_t *cache_mask_info = NULL; struct wccp2_capability_info_header_t *router_capability_header = NULL; struct wccp2_capability_element_t *router_capability_element; @@ -868,6 +970,9 @@ } router_capability_header = (struct wccp2_capability_info_header_t *) &wccp2_i_see_you.data[offset]; break; + /* Nothing to do for the types below */ + case WCCP2_ASSIGN_MAP: + break; default: debug(80, 1) ("Unknown record type in WCCPv2 Packet (%d).\n", ntohs(header->type)); @@ -946,8 +1051,8 @@ } break; case WCCP2_CAPABILITY_ASSIGNMENT_METHOD: - if (!(ntohl(router_capability_element->capability_value) & WCCP2_ASSIGNMENT_METHOD_HASH)) { - debug(80, 1) ("wccp2HandleUdp: fatal error - A WCCP router has specified a different assignment method %d, expected %d\n", ntohl(router_capability_element->capability_value), WCCP2_ASSIGNMENT_METHOD_HASH); + if (!(ntohl(router_capability_element->capability_value) & Config.Wccp2.assignment_method)) { + debug(80, 1) ("wccp2HandleUdp: fatal error - A WCCP router has specified a different assignment method %d, expected %d\n", ntohl(router_capability_element->capability_value), Config.Wccp2.assignment_method); wccp2ConnectionClose(); return; } @@ -1000,9 +1105,28 @@ /* search through the list of received-from ip addresses */ for (num_caches = 0; num_caches < ntohl(tmp); num_caches++) { /* Get a copy of the ip */ - cache_identity = (struct wccp2_cache_identity_info_t *) ptr; - ptr += sizeof(struct wccp2_cache_identity_info_t); - memcpy(&cache_address, &cache_identity->addr, sizeof(struct in_addr)); + switch (Config.Wccp2.assignment_method) { + case WCCP2_ASSIGNMENT_METHOD_HASH: + cache_identity = (struct wccp2_cache_identity_info_t *) ptr; + ptr += sizeof(struct wccp2_cache_identity_info_t); + memcpy(&cache_address, &cache_identity->addr, sizeof(struct in_addr)); + break; + case WCCP2_ASSIGNMENT_METHOD_MASK: + cache_mask_info = (struct cache_mask_info_t *) ptr; + + /* The mask assignment has an undocumented variable length entry here */ + if (ntohl(cache_mask_info->num1) == 3) { + cache_mask_identity = (struct wccp2_cache_mask_identity_info_t *) ptr; + ptr += sizeof(struct wccp2_cache_mask_identity_info_t); + memcpy(&cache_address, &cache_mask_identity->addr, sizeof(struct in_addr)); + } else { + ptr += sizeof(struct cache_mask_info_t); + memcpy(&cache_address, &cache_mask_info->addr, sizeof(struct in_addr)); + } + break; + default: + fatalf("Unknown Wccp2 assignment method\n"); + } /* Update the cache list */ cache_list_ptr->cache_ip = cache_address; @@ -1021,6 +1145,7 @@ } } } else { + debug(80, 5) ("Adding ourselves as the only cache\n"); /* Update the cache list */ cache_list_ptr->cache_ip = router_list_ptr->local_ip; @@ -1028,7 +1153,7 @@ cache_list_ptr = cache_list_ptr->next; cache_list_ptr->next = NULL; - service_list_ptr->lowest_ip = 0; + service_list_ptr->lowest_ip = 1; found = 1; num_caches = 1; } @@ -1040,8 +1165,11 @@ router_list_ptr->member_change = ntohl(router_view_header->change_number); eventDelete(wccp2AssignBuckets, NULL); eventAdd("wccp2AssignBuckets", wccp2AssignBuckets, NULL, 15.0, 1); + } else { + debug(80, 5) ("Change not detected (%d = %d)\n", ntohl(router_view_header->change_number), router_list_ptr->member_change); } } else { + eventDelete(wccp2AssignBuckets, NULL); debug(80, 5) ("I am not the lowest ip cache - not assigning buckets\n"); } } @@ -1051,6 +1179,8 @@ { struct wccp2_service_list_t *service_list_ptr; struct wccp2_router_list_t *router_list_ptr; + struct wccp2_identity_info_t *wccp2_identity_info_ptr; + struct wccp2_mask_identity_info_t *wccp2_mask_identity_info_ptr; struct sockaddr_in router; int router_len; u_short port = WCCP_PORT; @@ -1078,7 +1208,19 @@ router.sin_addr = router_list_ptr->router_sendto_address; /* Set the cache id (ip) */ - service_list_ptr->wccp2_identity_info_ptr->cache_identity.addr = router_list_ptr->local_ip; + switch (Config.Wccp2.assignment_method) { + case WCCP2_ASSIGNMENT_METHOD_HASH: + wccp2_identity_info_ptr = (struct wccp2_identity_info_t *) service_list_ptr->wccp2_identity_info_ptr; + wccp2_identity_info_ptr->cache_identity.addr = router_list_ptr->local_ip; + break; + case WCCP2_ASSIGNMENT_METHOD_MASK: + wccp2_mask_identity_info_ptr = (struct wccp2_mask_identity_info_t *) service_list_ptr->wccp2_identity_info_ptr; + wccp2_mask_identity_info_ptr->cache_identity.addr = router_list_ptr->local_ip; + break; + default: + fatalf("Unknown Wccp2 assignment method\n"); + } + /* Security update, if needed */ if (service_list_ptr->wccp2_security_type == WCCP2_MD5_SECURITY) { wccp2_update_md5_security(service_list_ptr->wccp_password, (char *) service_list_ptr->security_info, service_list_ptr->wccp_packet, service_list_ptr->wccp_packet_size); @@ -1112,10 +1254,11 @@ struct wccp2_router_list_t *router_list_ptr; struct wccp2_cache_list_t *cache_list_ptr; char wccp_packet[WCCP_RESPONSE_SIZE]; - short int offset, saved_offset; + short int offset, saved_offset, assignment_offset, alt_assignment_offset; struct sockaddr_in router; int router_len; int bucket_counter; + uint32_t service_flags; u_short port = WCCP_PORT; /* Packet segments */ @@ -1123,13 +1266,21 @@ struct wccp2_security_md5_t *security = NULL; /* service from service struct */ struct wccp2_item_header_t *assignment_header; + struct wccp2_item_header_t *alt_assignment_type_header = NULL; struct assignment_key_t *assignment_key; /* number of routers */ struct wccp2_router_assign_element_t *router_assign; /* number of caches */ struct in_addr *cache_address; + /* Alternative assignement mask/values */ + int num_maskval; + struct wccp2_mask_element_t *mask_element; + struct wccp2_value_element_t *value_element; + int valuecounter, value; char *buckets; + assignment_offset = alt_assignment_offset = 0; + router_len = sizeof(router); memset(&router, '\0', router_len); router.sin_family = AF_INET; @@ -1178,8 +1329,27 @@ /* assignment header - fill in length later */ assignment_header = (struct wccp2_item_header_t *) &wccp_packet[offset]; - assignment_header->type = htons(WCCP2_REDIRECT_ASSIGNMENT); - offset += sizeof(struct wccp2_item_header_t); + switch (Config.Wccp2.assignment_method) { + case WCCP2_ASSIGNMENT_METHOD_HASH: + assignment_header->type = htons(WCCP2_REDIRECT_ASSIGNMENT); + offset += sizeof(struct wccp2_item_header_t); + assignment_offset = offset; + break; + case WCCP2_ASSIGNMENT_METHOD_MASK: + assignment_header->type = htons(WCCP2_ALT_ASSIGNMENT); + offset += sizeof(struct wccp2_item_header_t); + assignment_offset = offset; + + /* The alternative assignment has an extra header, fill in length later */ + alt_assignment_type_header = (struct wccp2_item_header_t *) &wccp_packet[offset]; + alt_assignment_type_header->type = htons(WCCP2_MASK_ASSIGNMENT); + offset += sizeof(struct wccp2_item_header_t); + alt_assignment_offset = offset; + + break; + default: + fatalf("Unknown Wccp2 assignment method\n"); + } /* Assignment key - fill in master ip later */ assignment_key = (struct assignment_key_t *) &wccp_packet[offset]; @@ -1207,64 +1377,143 @@ int num_caches = ntohl(router_list_ptr->num_caches); offset = saved_offset; - /* Number of caches */ - xmemcpy(&wccp_packet[offset], &router_list_ptr->num_caches, sizeof(router_list_ptr->num_caches)); - offset += sizeof(router_list_ptr->num_caches); - - if (num_caches) { - int cache; - for (cache = 0, cache_list_ptr = &router_list_ptr->cache_list_head; cache_list_ptr->next; cache_list_ptr = cache_list_ptr->next, cache++) { - /* add caches */ - cache_address = (struct in_addr *) &wccp_packet[offset]; - xmemcpy(cache_address, &cache_list_ptr->cache_ip, sizeof(struct in_addr)); - total_weight += cache_list_ptr->weight << 12; - weight[cache] = cache_list_ptr->weight << 12; - offset += sizeof(struct in_addr); - } - } - /* Add buckets */ - buckets = (char *) &wccp_packet[offset]; - memset(buckets, '\0', WCCP_BUCKETS); - if (num_caches != 0) { - if (total_weight == 0) { - for (bucket_counter = 0; bucket_counter < WCCP_BUCKETS; bucket_counter++) { - buckets[bucket_counter] = (char) (bucket_counter % num_caches); + switch (Config.Wccp2.assignment_method) { + case WCCP2_ASSIGNMENT_METHOD_HASH: + /* Number of caches */ + xmemcpy(&wccp_packet[offset], &router_list_ptr->num_caches, sizeof(router_list_ptr->num_caches)); + offset += sizeof(router_list_ptr->num_caches); + + if (num_caches) { + int cache; + for (cache = 0, cache_list_ptr = &router_list_ptr->cache_list_head; cache_list_ptr->next; cache_list_ptr = cache_list_ptr->next, cache++) { + /* add caches */ + cache_address = (struct in_addr *) &wccp_packet[offset]; + xmemcpy(cache_address, &cache_list_ptr->cache_ip, sizeof(struct in_addr)); + total_weight += cache_list_ptr->weight << 12; + weight[cache] = cache_list_ptr->weight << 12; + offset += sizeof(struct in_addr); } - } else { - unsigned long *assigned = xcalloc(sizeof(*assigned), num_caches); - unsigned long done = 0; - int cache = -1; - unsigned long per_bucket = total_weight / WCCP_BUCKETS; - for (bucket_counter = 0; bucket_counter < WCCP_BUCKETS; bucket_counter++) { - int n; - unsigned long step; - for (n = num_caches; n; n--) { - cache++; - if (cache >= num_caches) - cache = 0; - if (!weight[cache]) { - n++; - continue; + } + /* Add buckets */ + buckets = (char *) &wccp_packet[offset]; + memset(buckets, '\0', WCCP_BUCKETS); + if (num_caches != 0) { + if (total_weight == 0) { + for (bucket_counter = 0; bucket_counter < WCCP_BUCKETS; bucket_counter++) { + buckets[bucket_counter] = (char) (bucket_counter % num_caches); + } + } else { + unsigned long *assigned = xcalloc(sizeof(*assigned), num_caches); + unsigned long done = 0; + int cache = -1; + unsigned long per_bucket = total_weight / WCCP_BUCKETS; + for (bucket_counter = 0; bucket_counter < WCCP_BUCKETS; bucket_counter++) { + int n; + unsigned long step; + for (n = num_caches; n; n--) { + cache++; + if (cache >= num_caches) + cache = 0; + if (!weight[cache]) { + n++; + continue; + } + if (assigned[cache] <= done) + break; } - if (assigned[cache] <= done) - break; + buckets[bucket_counter] = (char) cache; + step = per_bucket * total_weight / weight[cache]; + assigned[cache] += step; + done += per_bucket; } - buckets[bucket_counter] = (char) cache; - step = per_bucket * total_weight / weight[cache]; - assigned[cache] += step; - done += per_bucket; + safe_free(assigned); } - safe_free(assigned); } - } - offset += (WCCP_BUCKETS * sizeof(char)); - safe_free(weight); + offset += (WCCP_BUCKETS * sizeof(char)); + safe_free(weight); + break; + case WCCP2_ASSIGNMENT_METHOD_MASK: + num_maskval = htonl(1); + xmemcpy(&wccp_packet[offset], &num_maskval, sizeof(int)); + offset += sizeof(int); + + mask_element = (struct wccp2_mask_element_t *) &wccp_packet[offset]; + service_flags = ntohl(service_list_ptr->service_info->service_flags); + if ((service_flags & WCCP2_SERVICE_SRC_IP_HASH) || (service_flags & WCCP2_SERVICE_SRC_IP_ALT_HASH)) { + mask_element->source_ip_mask = htonl(0x00001741); + mask_element->dest_ip_mask = 0; + mask_element->source_port_mask = 0; + mask_element->dest_port_mask = 0; + } else if ((service_flags & WCCP2_SERVICE_DST_IP_HASH) || (service_flags & WCCP2_SERVICE_DST_IP_ALT_HASH)) { + mask_element->source_ip_mask = 0; + mask_element->dest_ip_mask = htonl(0x00001741); + mask_element->source_port_mask = 0; + mask_element->dest_port_mask = 0; + } else if ((service_flags & WCCP2_SERVICE_SRC_PORT_HASH) || (service_flags & WCCP2_SERVICE_SRC_PORT_ALT_HASH)) { + mask_element->source_ip_mask = 0; + mask_element->dest_ip_mask = 0; + mask_element->source_port_mask = htons(0x1741); + mask_element->dest_port_mask = 0; + } else if ((service_flags & WCCP2_SERVICE_DST_PORT_HASH) || (service_flags & WCCP2_SERVICE_DST_PORT_ALT_HASH)) { + mask_element->source_ip_mask = 0; + mask_element->dest_ip_mask = 0; + mask_element->source_port_mask = 0; + mask_element->dest_port_mask = htons(0x1741); + } else { + fatalf("Unknown service hash method\n"); + } + mask_element->number_values = htonl(64); + offset += sizeof(struct wccp2_mask_element_t); + cache_list_ptr = &router_list_ptr->cache_list_head; + value = 0; + for (valuecounter = 0; valuecounter < 64; valuecounter++) { + value_element = (struct wccp2_value_element_t *) &wccp_packet[offset]; + + if ((service_flags & WCCP2_SERVICE_SRC_IP_HASH) || (service_flags & WCCP2_SERVICE_SRC_IP_ALT_HASH)) { + value_element->source_ip_value = htonl(value); + value_element->dest_ip_value = 0; + value_element->source_port_value = 0; + value_element->dest_port_value = 0; + } else if ((service_flags & WCCP2_SERVICE_DST_IP_HASH) || (service_flags & WCCP2_SERVICE_DST_IP_ALT_HASH)) { + value_element->source_ip_value = 0; + value_element->dest_ip_value = htonl(value); + value_element->source_port_value = 0; + value_element->dest_port_value = 0; + } else if ((service_flags & WCCP2_SERVICE_SRC_PORT_HASH) || (service_flags & WCCP2_SERVICE_SRC_PORT_ALT_HASH)) { + value_element->source_ip_value = 0; + value_element->dest_ip_value = 0; + value_element->source_port_value = htons(value); + value_element->dest_port_value = 0; + } else if ((service_flags & WCCP2_SERVICE_DST_PORT_HASH) || (service_flags & WCCP2_SERVICE_DST_PORT_ALT_HASH)) { + value_element->source_ip_value = 0; + value_element->dest_ip_value = 0; + value_element->source_port_value = 0; + value_element->dest_port_value = htons(value); + } else { + fatalf("Unknown service hash method\n"); + } + value_element->cache_ip = cache_list_ptr->cache_ip; + offset += sizeof(struct wccp2_value_element_t); + + /* Update the value according the the "correct" formula */ + for (value++; (value & 0x1741) != value; value++); + + /* Assign the next value to the next cache */ + if ((cache_list_ptr->next) && (cache_list_ptr->next->next)) + cache_list_ptr = cache_list_ptr->next; + else + cache_list_ptr = &router_list_ptr->cache_list_head; + } + /* Fill in length */ + alt_assignment_type_header->length = htons(offset - alt_assignment_offset); + + break; + default: + fatalf("Unknown Wccp2 assignment method\n"); + } /* Fill in length */ - assignment_header->length = htons(sizeof(struct assignment_key_t) + sizeof(service_list_ptr->num_routers) + - (ntohl(service_list_ptr->num_routers) * sizeof(struct wccp2_router_assign_element_t)) + - sizeof (router_list_ptr->num_caches) + (ntohl(router_list_ptr->num_caches) * sizeof(struct in_addr)) + - (WCCP_BUCKETS * sizeof(char))); + assignment_header->length = htons(offset - assignment_offset); /* Fill in assignment key */ assignment_key->master_ip = router_list_ptr->local_ip; @@ -1419,7 +1668,7 @@ } else if (strcmp(flag, "dst_ip_hash") == 0) { retflag |= WCCP2_SERVICE_DST_IP_HASH; } else if (strcmp(flag, "source_port_hash") == 0) { - retflag |= WCCP2_SERVICE_SOURCE_PORT_HASH; + retflag |= WCCP2_SERVICE_SRC_PORT_HASH; } else if (strcmp(flag, "dst_port_hash") == 0) { retflag |= WCCP2_SERVICE_DST_PORT_HASH; } else if (strcmp(flag, "ports_source") == 0) { @@ -1575,7 +1824,7 @@ storeAppendPrintf(e, "%sdst_ip_hash", comma ? "," : ""); comma = 1; } - if (flags & WCCP2_SERVICE_SOURCE_PORT_HASH) { + if (flags & WCCP2_SERVICE_SRC_PORT_HASH) { storeAppendPrintf(e, "%ssource_port_hash", comma ? "," : ""); comma = 1; }