📄 dhcp-icmp-discovery.c
字号:
/* $Header: /cvsroot/dhcp-agent/dhcp-agent/src/dhcp-icmp-discovery.c,v 1.5 2003/06/08 22:14:16 actmodern Exp $ * * Copyright 2002 Thamer Alharbash <tmh@whitefang.com> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * ICMP discovery routines: * * subnet discovery, and rtt discovery by icmp echo requests. * */#define MODULE_NAME "dhcp-icmp-discovery"#include "dhcp-local.h"#include "dhcp-libutil.h"#include "dhcp-librawnet.h"/* Check for icmp mask response. */static int icmp_check_mask_reply(void *arg){ rawnet_t *net = arg; if((net->type = RAWNET_ICMP) && (icmp_get_type(net->icmp_p) == ICMP_MASKREPLY)) return 1; else return 0;}/* Discover subnet mask: * If discovered fill in subnet_mask and return 0. * Otherwise return 1 */int icmp_subnet_mask_discovery(rawnet_t *net, int retries, uint32_t *subnet_mask){ uint32_t reply_mask; int retval; /* Build ICMP mask request packet. We don't actually care * about sequence or IDs since we'll accept the first * response on our subnet regardless. Still let's be nice to * the mask repliers and set them up anyway. */ build_icmp_mask_request(net, 0, 0); if(retries <= 0) { /* let's not get hosed shall we? */ ERROR_MESSAGE("bad number of retries: %d", retries); return -1; } while(retries--) { retval = rawnet_packet_transact(net, net, NULL, icmp_check_mask_reply, RECOMMENDED_MAX_SECS_WAIT); switch (retval) { case RAWNET_TIMEOUT: break; case RAWNET_ERROR: ERROR_MESSAGE("received error from raw network handler."); return -1; case RAWNET_OK: /* A reply should contain the subnet mask. If we're actually * doing subnet mask discovery we assume any subnet mask * returned is valid. */ reply_mask = icmp_mask_get_mask(net->icmp_p); memcpy(subnet_mask, &reply_mask, IP_ADDR_LEN); return 0; case RAWNET_USER_INTERRUPT: FATAL_MESSAGE("user interrupt. bailing out!"); default: FATAL_MESSAGE("invalid return value from raw network handler -- this a bug report it."); } } ERROR_MESSAGE("timeout on icmp subnet discovery."); return -1;}/* Check for icmp echo reply. */static int icmp_check_echo_reply(void *arg){ rawnet_t *net = arg; if((net->type == RAWNET_ICMP) && (icmp_get_type(net->icmp_p) == ICMP_ECHOREPLY)) return 1; else return 0;}/* Send out an echo request per retries to get latency of host. */int icmp_do_echo(rawnet_t *net, ip_addr_t dest_addr, eth_addr_t dest_mac){ uint16_t id, seq; struct timeval before, after, difference; int latency; id = get_random_uint16(); seq = 1; build_icmp_echo_request(net, net->cip_addr, dest_addr, net->chw_addr, dest_mac, id, seq); gettimeofday(&before, NULL); if(rawnet_packet_transact(net, net, NULL, icmp_check_echo_reply, RECOMMENDED_MAX_SECS_WAIT)) { /* on a timeout we set the latency to -1 */ return -1; } gettimeofday(&after, NULL); difference = timeval_diff(before, after); latency = (difference.tv_sec * 1000); latency += (difference.tv_usec / 1000); return latency;}/* * ICMP Round Trip Time (RTT) Discovery: Here we're interested in * how long it takes to get a response from a list of addresses. * We return a list of unsigned integers representing the latency * of each host followed by the address of the host. * */list_t *icmp_rtt_discovery(rawnet_t *net, int sends, int timeout, int arp_retries, int arp_timeout, list_t *addresses){ list_t *rtts; int *latency, *average_latency; int send_count, unreachable_count, highest_latency; ip_addr_t *host_addr, *host_addr_copy; eth_addr_t dest_mac; rtts = list_create(); /* Our algorithm works as such: send out an ICMP echo request * and wait for a reply. We count the total number of * milliseconds we waited as the latency time. We keep doing * this per the packet_count. If we don't get a reply we keep * doing per number of retries. If we run out of retries we * return -1 as the latency signifying an unreliable * address. */ list_rewind(addresses); while((host_addr = list_next(addresses)) != NULL) { /* We need to arp for MAC address first. Call * arp_discover_hardware_address for that. */ if(route_find(net, arp_retries, arp_timeout, *host_addr, &dest_mac)) { WARN_MESSAGE("could not find route for address for %s -- skipping", rawnet_network_address_to_string_static(*host_addr)); continue; } /* allocate latency array. */ latency = xmalloc(sizeof(int) * sends); send_count = 0; /* fill up our latency array. */ for(send_count = 0; send_count < sends; send_count++) latency[send_count] = icmp_do_echo(net, *(host_addr), dest_mac); /* This part is a little tricky. We want to make sure * the host is actually up first. So if we got all -1's * we know it wasn't. Then if it is up we set the -1 * latencies (indicating we never got an answer) to the * largest latency multiplied by two. This severely hurts * a host's average, but it's the right thing to do as * long as we're doing it fairly to everyone. */ /* check our latency if it's all -1 */ unreachable_count = 0; for(send_count = 0; send_count < sends; send_count++) { if(latency[send_count] == -1) unreachable_count++; } average_latency = xmalloc(sizeof(int)); if(unreachable_count == send_count) { /* the host is * unreachable. */ /* host is unreachable give it an average of -1. */ *average_latency = -1; } else { if(unreachable_count) { /* the host didn't respond to some of our packets in time. */ /* get highest. */ highest_latency = 0; for(send_count = 0; send_count < sends; send_count++) { if(latency[send_count] > highest_latency) highest_latency = latency[send_count]; } /* replace unreachables with highest multiplied by two */ for(send_count = 0; send_count < sends; send_count++) { if(latency[send_count] == -1) latency[send_count] = highest_latency * 2; } } /* now we can get the average. */ *average_latency = 0; for(send_count = 0; send_count < sends; send_count++) { *average_latency += latency[send_count]; } *average_latency /= sends; } xfree(latency); /* free our latency array. */ list_add_to_end(rtts, average_latency); host_addr_copy = xmalloc(sizeof(IP_ADDR_LEN)); memcpy(host_addr_copy, host_addr, IP_ADDR_LEN); list_add_to_end(rtts, host_addr_copy); } return rtts;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -