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