]>
Commit | Line | Data |
---|---|---|
aba5acdf SH |
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> | |
aba5acdf SH |
16 | #include <fcntl.h> |
17 | #include <sys/socket.h> | |
18 | #include <netinet/in.h> | |
19 | #include <string.h> | |
5f218239 | 20 | #include <net/if.h> |
aba5acdf SH |
21 | |
22 | #include "libnetlink.h" | |
23 | #include "ll_map.h" | |
4952b459 | 24 | #include "list.h" |
aba5acdf | 25 | |
0025e5d6 SH |
26 | struct ll_cache { |
27 | struct hlist_node idx_hash; | |
28 | struct hlist_node name_hash; | |
aba5acdf | 29 | unsigned flags; |
656111b2 | 30 | unsigned index; |
4b3385f6 | 31 | unsigned short type; |
4b9e9178 | 32 | char name[]; |
aba5acdf SH |
33 | }; |
34 | ||
1e21ea71 | 35 | #define IDXMAP_SIZE 1024 |
0025e5d6 SH |
36 | static struct hlist_head idx_head[IDXMAP_SIZE]; |
37 | static struct hlist_head name_head[IDXMAP_SIZE]; | |
4b3385f6 | 38 | |
0025e5d6 | 39 | static struct ll_cache *ll_get_by_index(unsigned index) |
4b3385f6 | 40 | { |
0025e5d6 SH |
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 | ||
d652ccbf | 54 | unsigned namehash(const char *str) |
0025e5d6 SH |
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; | |
4b3385f6 | 78 | } |
aba5acdf | 79 | |
cd554f2c | 80 | int ll_remember_index(struct nlmsghdr *n, void *arg) |
aba5acdf | 81 | { |
0025e5d6 SH |
82 | unsigned int h; |
83 | const char *ifname; | |
aba5acdf | 84 | struct ifinfomsg *ifi = NLMSG_DATA(n); |
0025e5d6 | 85 | struct ll_cache *im; |
aba5acdf SH |
86 | struct rtattr *tb[IFLA_MAX+1]; |
87 | ||
0025e5d6 | 88 | if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK) |
aba5acdf SH |
89 | return 0; |
90 | ||
6cf2609d | 91 | if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*ifi))) |
aba5acdf SH |
92 | return -1; |
93 | ||
0025e5d6 SH |
94 | im = ll_get_by_index(ifi->ifi_index); |
95 | if (n->nlmsg_type == RTM_DELLINK) { | |
96 | if (im) { | |
97 | hlist_del(&im->name_hash); | |
98 | hlist_del(&im->idx_hash); | |
99 | free(im); | |
100 | } | |
101 | return 0; | |
102 | } | |
103 | ||
aba5acdf | 104 | parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); |
0025e5d6 SH |
105 | ifname = rta_getattr_str(tb[IFLA_IFNAME]); |
106 | if (ifname == NULL) | |
aba5acdf SH |
107 | return 0; |
108 | ||
0025e5d6 SH |
109 | if (im) { |
110 | /* change to existing entry */ | |
111 | if (strcmp(im->name, ifname) != 0) { | |
112 | hlist_del(&im->name_hash); | |
113 | h = namehash(ifname) & (IDXMAP_SIZE - 1); | |
114 | hlist_add_head(&im->name_hash, &name_head[h]); | |
115 | } | |
116 | ||
117 | im->flags = ifi->ifi_flags; | |
118 | return 0; | |
aba5acdf SH |
119 | } |
120 | ||
4b9e9178 | 121 | im = malloc(sizeof(*im) + strlen(ifname) + 1); |
0025e5d6 SH |
122 | if (im == NULL) |
123 | return 0; | |
124 | im->index = ifi->ifi_index; | |
125 | strcpy(im->name, ifname); | |
aba5acdf SH |
126 | im->type = ifi->ifi_type; |
127 | im->flags = ifi->ifi_flags; | |
0025e5d6 SH |
128 | |
129 | h = ifi->ifi_index & (IDXMAP_SIZE - 1); | |
130 | hlist_add_head(&im->idx_hash, &idx_head[h]); | |
131 | ||
132 | h = namehash(ifname) & (IDXMAP_SIZE - 1); | |
133 | hlist_add_head(&im->name_hash, &name_head[h]); | |
134 | ||
aba5acdf SH |
135 | return 0; |
136 | } | |
137 | ||
fe269b6e | 138 | const char *ll_idx_n2a(unsigned int idx) |
aba5acdf | 139 | { |
fe269b6e SP |
140 | static char buf[IFNAMSIZ]; |
141 | ||
142 | snprintf(buf, sizeof(buf), "if%u", idx); | |
143 | return buf; | |
144 | } | |
145 | ||
cc5b7e37 | 146 | static unsigned int ll_idx_a2n(const char *name) |
fe269b6e SP |
147 | { |
148 | unsigned int idx; | |
149 | ||
150 | if (sscanf(name, "if%u", &idx) != 1) | |
151 | return 0; | |
152 | return idx; | |
153 | } | |
154 | ||
155 | const char *ll_index_to_name(unsigned int idx) | |
156 | { | |
157 | static char buf[IFNAMSIZ]; | |
4b3385f6 | 158 | const struct ll_cache *im; |
aba5acdf SH |
159 | |
160 | if (idx == 0) | |
161 | return "*"; | |
1e21ea71 | 162 | |
0025e5d6 SH |
163 | im = ll_get_by_index(idx); |
164 | if (im) | |
165 | return im->name; | |
166 | ||
167 | if (if_indextoname(idx, buf) == NULL) | |
fe269b6e | 168 | snprintf(buf, IFNAMSIZ, "if%u", idx); |
4b3385f6 | 169 | |
aba5acdf SH |
170 | return buf; |
171 | } | |
172 | ||
99f830de | 173 | int ll_index_to_type(unsigned idx) |
aba5acdf | 174 | { |
4b3385f6 | 175 | const struct ll_cache *im; |
aba5acdf SH |
176 | |
177 | if (idx == 0) | |
178 | return -1; | |
0025e5d6 SH |
179 | |
180 | im = ll_get_by_index(idx); | |
181 | return im ? im->type : -1; | |
aba5acdf SH |
182 | } |
183 | ||
656111b2 | 184 | int ll_index_to_flags(unsigned idx) |
aba5acdf | 185 | { |
4b3385f6 | 186 | const struct ll_cache *im; |
aba5acdf SH |
187 | |
188 | if (idx == 0) | |
189 | return 0; | |
190 | ||
0025e5d6 SH |
191 | im = ll_get_by_index(idx); |
192 | return im ? im->flags : -1; | |
aba5acdf SH |
193 | } |
194 | ||
99f830de | 195 | unsigned ll_name_to_index(const char *name) |
aba5acdf | 196 | { |
0025e5d6 | 197 | const struct ll_cache *im; |
24abb62e | 198 | unsigned idx; |
aba5acdf SH |
199 | |
200 | if (name == NULL) | |
201 | return 0; | |
4b3385f6 | 202 | |
0025e5d6 SH |
203 | im = ll_get_by_name(name); |
204 | if (im) | |
205 | return im->index; | |
99f830de | 206 | |
24abb62e FW |
207 | idx = if_nametoindex(name); |
208 | if (idx == 0) | |
fe269b6e | 209 | idx = ll_idx_a2n(name); |
24abb62e | 210 | return idx; |
aba5acdf SH |
211 | } |
212 | ||
0025e5d6 | 213 | void ll_init_map(struct rtnl_handle *rth) |
aba5acdf | 214 | { |
30564237 OP |
215 | static int initialized; |
216 | ||
217 | if (initialized) | |
0025e5d6 | 218 | return; |
30564237 | 219 | |
31ae2912 | 220 | if (rtnl_linkdump_req(rth, AF_UNSPEC) < 0) { |
aba5acdf SH |
221 | perror("Cannot send dump request"); |
222 | exit(1); | |
223 | } | |
224 | ||
cd70f3f5 | 225 | if (rtnl_dump_filter(rth, ll_remember_index, NULL) < 0) { |
aba5acdf SH |
226 | fprintf(stderr, "Dump terminated\n"); |
227 | exit(1); | |
228 | } | |
30564237 OP |
229 | |
230 | initialized = 1; | |
aba5acdf | 231 | } |