1/* 2 * lib/route/pktloc.c Packet Location Aliasing 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation version 2 of the License. 7 * 8 * Copyright (c) 2008-2010 Thomas Graf <tgraf@suug.ch> 9 */ 10 11/** 12 * @ingroup tc 13 * @defgroup pktloc Packet Location Aliasing 14 * Packet Location Aliasing 15 * 16 * The packet location aliasing interface eases the use of offset definitions 17 * inside packets by allowing them to be referenced by name. Known positions 18 * of protocol fields are stored in a configuration file and associated with 19 * a name for later reference. The configuration file is distributed with the 20 * library and provides a well defined set of definitions for most common 21 * protocol fields. 22 * 23 * @subsection pktloc_examples Examples 24 * @par Example 1.1 Looking up a packet location 25 * @code 26 * struct rtnl_pktloc *loc; 27 * 28 * rtnl_pktloc_lookup("ip.src", &loc); 29 * @endcode 30 * @{ 31 */ 32 33#include <netlink-local.h> 34#include <netlink-tc.h> 35#include <netlink/netlink.h> 36#include <netlink/utils.h> 37#include <netlink/route/pktloc.h> 38 39#include "pktloc_syntax.h" 40#include "pktloc_grammar.h" 41 42/** @cond */ 43#define PKTLOC_NAME_HT_SIZ 256 44 45static struct nl_list_head pktloc_name_ht[PKTLOC_NAME_HT_SIZ]; 46 47/* djb2 */ 48unsigned int pktloc_hash(const char *str) 49{ 50 unsigned long hash = 5381; 51 int c; 52 53 while ((c = *str++)) 54 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ 55 56 return hash % PKTLOC_NAME_HT_SIZ; 57} 58 59 60void rtnl_pktloc_add(struct rtnl_pktloc *loc) 61{ 62 nl_list_add_tail(&loc->list, &pktloc_name_ht[pktloc_hash(loc->name)]); 63} 64 65extern int pktloc_parse(void *scanner); 66 67/** @endcond */ 68 69static void rtnl_pktloc_free(struct rtnl_pktloc *loc) 70{ 71 if (!loc) 72 return; 73 74 free(loc->name); 75 free(loc); 76} 77 78static int read_pktlocs(void) 79{ 80 YY_BUFFER_STATE buf; 81 yyscan_t scanner = NULL; 82 static time_t last_read; 83 struct stat st = {0}; 84 char *path; 85 int i, err; 86 FILE *fd; 87 88 asprintf(&path, "%s/pktloc", SYSCONFDIR); 89 90 /* if stat fails, just try to read the file */ 91 if (stat(path, &st) == 0) { 92 /* Don't re-read file if file is unchanged */ 93 if (last_read == st.st_mtime) 94 return 0; 95 } 96 97 if (!(fd = fopen(path, "r"))) 98 return -NLE_PKTLOC_FILE; 99 100 for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) { 101 struct rtnl_pktloc *loc, *n; 102 103 nl_list_for_each_entry_safe(loc, n, &pktloc_name_ht[i], list) 104 rtnl_pktloc_free(loc); 105 106 nl_init_list_head(&pktloc_name_ht[i]); 107 } 108 109 if ((err = pktloc_lex_init(&scanner)) < 0) 110 return -NLE_FAILURE; 111 112 buf = pktloc__create_buffer(fd, YY_BUF_SIZE, scanner); 113 pktloc__switch_to_buffer(buf, scanner); 114 115 if ((err = pktloc_parse(scanner)) < 0) 116 return -NLE_FAILURE; 117 118 if (scanner) 119 pktloc_lex_destroy(scanner); 120 121 free(path); 122 last_read = st.st_mtime; 123 124 return 0; 125} 126 127/** 128 * Lookup packet location alias 129 * @arg name Name of packet location. 130 * 131 * Tries to find a matching packet location alias for the supplied 132 * packet location name. 133 * 134 * The file containing the packet location definitions is automatically 135 * re-read if its modification time has changed since the last call. 136 * 137 * @return 0 on success or a negative error code. 138 * @retval NLE_PKTLOC_FILE Unable to open packet location file. 139 * @retval NLE_OBJ_NOTFOUND No matching packet location alias found. 140 */ 141int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result) 142{ 143 struct rtnl_pktloc *loc; 144 int hash, err; 145 146 if ((err = read_pktlocs()) < 0) 147 return err; 148 149 hash = pktloc_hash(name); 150 nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) { 151 if (!strcasecmp(loc->name, name)) { 152 *result = loc; 153 return 0; 154 } 155 } 156 157 return -NLE_OBJ_NOTFOUND; 158} 159 160static int __init pktloc_init(void) 161{ 162 int i; 163 164 for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) 165 nl_init_list_head(&pktloc_name_ht[i]); 166 167 return 0; 168} 169