Author: tjansen Date: Wed Sep 30 16:01:07 2009 New Revision: 1004 Log: Added caching for ARP addresses. Hopefully speeds up legacy connections. Note that this is work in progress, especially the malloc has no free counterpart yet. Modified: trunk/libpisa/arp.c Modified: trunk/libpisa/arp.c ============================================================================== --- trunk/libpisa/arp.c Wed Sep 30 15:30:10 2009 (r1003) +++ trunk/libpisa/arp.c Wed Sep 30 16:01:07 2009 (r1004) @@ -12,9 +12,20 @@ #include <arpa/inet.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include "arp.h" +#include "global.h" +#include "uthash.h" + +struct pisa_arp_cache_entry { + pisa_mac mac; + struct in_addr ip; + UT_hash_handle hh; +}; + +static struct pisa_arp_cache_entry *arp_cache = NULL; /** * Convert a string to an ARP entry. @@ -42,16 +53,63 @@ } /** - * Search the ARP table for an entry. - * @param ip IPv4 address to search for - * @param arp destination buffer for the ARP + * Find an entry in the ARP cache. + * @param ip IPv4 address we are looking for + * @return pointer to the cache entry or NULL, if none was found + */ +static inline struct pisa_arp_cache_entry *pisa_arp_cache_find(struct in_addr *ip) +{ + struct pisa_arp_cache_entry *e = NULL; + HASH_FIND(hh, arp_cache, ip, sizeof(struct in_addr), e); + return e; +} + +/** + * Set the MAC address for the IPv4 address. If a previous mapping existed, + * the old MAC is overwritten by the new MAC. If no previous mapping for that + * IPv4 existed, a new entry will be created. + * @param ip IPv4 address + * @param mac destination buffer for the MAC address + */ +static void pisa_arp_cache_set(struct in_addr *ip, pisa_mac *mac) +{ + struct pisa_arp_cache_entry *e = pisa_arp_cache_find(ip); + + if (e == NULL) { + e = malloc(sizeof(struct pisa_arp_cache_entry)); + pisa_ipv4_copy(&e->ip, ip); + HASH_ADD(hh, arp_cache, ip, sizeof(struct in_addr), e); + } + memcpy(&e->mac, mac, sizeof(pisa_mac)); +} + +/** + * Retrieve the MAC for a given IPv4 address from the ARP cache. + * @param ip IPv4 address we are looking for + * @param mac destination buffer for the MAC address + */ +static int pisa_arp_cache_lookup(struct in_addr *ip, pisa_mac *mac) +{ + struct pisa_arp_cache_entry *e = pisa_arp_cache_find(ip); + + if (e == NULL) + return -1; + + memcpy(mac, &e->mac, sizeof(pisa_mac)); + return 0; +} + +/** + * Update or create an entry in the ARP cache for a given IPv4 address. + * @param ip IPv4 address that will be updated * @return 0 on success, -1 otherwise */ -int pisa_arp_from_ipv4(struct in_addr *ip, pisa_mac *mac) +static int pisa_arp_cache_update(struct in_addr *ip) { char ip_str[INET_ADDRSTRLEN+1]; char line[1024]; int result = -1; + pisa_mac mac; FILE *f = fopen("/proc/net/arp", "r"); inet_ntop(AF_INET, ip, ip_str, sizeof(ip_str)); @@ -61,12 +119,32 @@ while (!feof(f)) { fgets(line, sizeof(line), f); if (!strncmp(ip_str, line, strlen(ip_str))) { - pisa_mac_parse_string(mac, line + 41); + pisa_mac_parse_string(&mac, line + 41); result = 0; break; } } fclose(f); + + if (result == 0) + pisa_arp_cache_set(ip, &mac); return result; } + +/** + * Search the ARP table for an entry. + * @param ip IPv4 address to search for + * @param mac destination buffer for the MAC address + * @return 0 on success, -1 otherwise + */ +int pisa_arp_from_ipv4(struct in_addr *ip, pisa_mac *mac) +{ + if (pisa_arp_cache_lookup(ip, mac) == 0) + return 0; + + if (pisa_arp_cache_update(ip) == 0) + return pisa_arp_cache_lookup(ip, mac); + + return -1; +}