1 /* 2 * ll_map.c 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Alexey Kuznetsov, <kuznet (at) ms2.inr.ac.ru> 10 * 11 */ 12 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <unistd.h> 16 #include <syslog.h> 17 #include <fcntl.h> 18 #include <sys/socket.h> 19 #include <netinet/in.h> 20 #include <string.h> 21 #include <net/if.h> 22 23 #include "libnetlink.h" 24 #include "ll_map.h" 25 #include "hlist.h" 26 27 struct ll_cache { 28 struct hlist_node idx_hash; 29 struct hlist_node name_hash; 30 unsigned flags; 31 unsigned index; 32 unsigned short type; 33 char name[IFNAMSIZ]; 34 }; 35 36 #define IDXMAP_SIZE 1024 37 static struct hlist_head idx_head[IDXMAP_SIZE]; 38 static struct hlist_head name_head[IDXMAP_SIZE]; 39 40 static struct ll_cache *ll_get_by_index(unsigned index) 41 { 42 struct hlist_node *n; 43 unsigned h = index & (IDXMAP_SIZE - 1); 44 45 hlist_for_each(n, &idx_head[h]) { 46 struct ll_cache *im 47 = container_of(n, struct ll_cache, idx_hash); 48 if (im->index == index) 49 return im; 50 } 51 52 return NULL; 53 } 54 55 unsigned namehash(const char *str) 56 { 57 unsigned hash = 5381; 58 59 while (*str) 60 hash = ((hash << 5) + hash) + *str++; /* hash * 33 + c */ 61 62 return hash; 63 } 64 65 static struct ll_cache *ll_get_by_name(const char *name) 66 { 67 struct hlist_node *n; 68 unsigned h = namehash(name) & (IDXMAP_SIZE - 1); 69 70 hlist_for_each(n, &name_head[h]) { 71 struct ll_cache *im 72 = container_of(n, struct ll_cache, name_hash); 73 74 if (strncmp(im->name, name, IFNAMSIZ) == 0) 75 return im; 76 } 77 78 return NULL; 79 } 80 81 int ll_remember_index(const struct sockaddr_nl *who, 82 struct nlmsghdr *n, void *arg) 83 { 84 unsigned int h; 85 const char *ifname; 86 struct ifinfomsg *ifi = NLMSG_DATA(n); 87 struct ll_cache *im; 88 struct rtattr *tb[IFLA_MAX+1]; 89 90 if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK) 91 return 0; 92 93 if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi))) 94 return -1; 95 96 im = ll_get_by_index(ifi->ifi_index); 97 if (n->nlmsg_type == RTM_DELLINK) { 98 if (im) { 99 hlist_del(&im->name_hash); 100 hlist_del(&im->idx_hash); 101 free(im); 102 } 103 return 0; 104 } 105 106 memset(tb, 0, sizeof(tb)); 107 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); 108 ifname = rta_getattr_str(tb[IFLA_IFNAME]); 109 if (ifname == NULL) 110 return 0; 111 112 if (im) { 113 /* change to existing entry */ 114 if (strcmp(im->name, ifname) != 0) { 115 hlist_del(&im->name_hash); 116 h = namehash(ifname) & (IDXMAP_SIZE - 1); 117 hlist_add_head(&im->name_hash, &name_head[h]); 118 } 119 120 im->flags = ifi->ifi_flags; 121 return 0; 122 } 123 124 im = malloc(sizeof(*im)); 125 if (im == NULL) 126 return 0; 127 im->index = ifi->ifi_index; 128 strcpy(im->name, ifname); 129 im->type = ifi->ifi_type; 130 im->flags = ifi->ifi_flags; 131 132 h = ifi->ifi_index & (IDXMAP_SIZE - 1); 133 hlist_add_head(&im->idx_hash, &idx_head[h]); 134 135 h = namehash(ifname) & (IDXMAP_SIZE - 1); 136 hlist_add_head(&im->name_hash, &name_head[h]); 137 138 return 0; 139 } 140 141 const char *ll_idx_n2a(unsigned idx, char *buf) 142 { 143 const struct ll_cache *im; 144 145 if (idx == 0) 146 return "*"; 147 148 im = ll_get_by_index(idx); 149 if (im) 150 return im->name; 151 152 if (if_indextoname(idx, buf) == NULL) 153 snprintf(buf, IFNAMSIZ, "if%d", idx); 154 155 return buf; 156 } 157 158 const char *ll_index_to_name(unsigned idx) 159 { 160 static char nbuf[IFNAMSIZ]; 161 162 return ll_idx_n2a(idx, nbuf); 163 } 164 165 int ll_index_to_type(unsigned idx) 166 { 167 const struct ll_cache *im; 168 169 if (idx == 0) 170 return -1; 171 172 im = ll_get_by_index(idx); 173 return im ? im->type : -1; 174 } 175 176 int ll_index_to_flags(unsigned idx) 177 { 178 const struct ll_cache *im; 179 180 if (idx == 0) 181 return 0; 182 183 im = ll_get_by_index(idx); 184 return im ? im->flags : -1; 185 } 186 187 unsigned ll_name_to_index(const char *name) 188 { 189 const struct ll_cache *im; 190 unsigned idx; 191 192 if (name == NULL) 193 return 0; 194 195 im = ll_get_by_name(name); 196 if (im) 197 return im->index; 198 199 idx = if_nametoindex(name); 200 if (idx == 0) 201 sscanf(name, "if%u", &idx); 202 return idx; 203 } 204 205 void ll_init_map(struct rtnl_handle *rth) 206 { 207 static int initialized; 208 209 if (initialized) 210 return; 211 212 if (rtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK) < 0) { 213 perror("Cannot send dump request"); 214 exit(1); 215 } 216 217 if (rtnl_dump_filter(rth, ll_remember_index, NULL) < 0) { 218 fprintf(stderr, "Dump terminated\n"); 219 exit(1); 220 } 221 222 initialized = 1; 223 } 224