]>
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 | |
ae665a52 | 80 | int ll_remember_index(const struct sockaddr_nl *who, |
50772dc5 | 81 | struct nlmsghdr *n, void *arg) |
aba5acdf | 82 | { |
0025e5d6 SH |
83 | unsigned int h; |
84 | const char *ifname; | |
aba5acdf | 85 | struct ifinfomsg *ifi = NLMSG_DATA(n); |
0025e5d6 | 86 | struct ll_cache *im; |
aba5acdf SH |
87 | struct rtattr *tb[IFLA_MAX+1]; |
88 | ||
0025e5d6 | 89 | if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK) |
aba5acdf SH |
90 | return 0; |
91 | ||
6cf2609d | 92 | if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*ifi))) |
aba5acdf SH |
93 | return -1; |
94 | ||
0025e5d6 SH |
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 | ||
aba5acdf | 105 | parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); |
0025e5d6 SH |
106 | ifname = rta_getattr_str(tb[IFLA_IFNAME]); |
107 | if (ifname == NULL) | |
aba5acdf SH |
108 | return 0; |
109 | ||
0025e5d6 SH |
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; | |
aba5acdf SH |
120 | } |
121 | ||
4b9e9178 | 122 | im = malloc(sizeof(*im) + strlen(ifname) + 1); |
0025e5d6 SH |
123 | if (im == NULL) |
124 | return 0; | |
125 | im->index = ifi->ifi_index; | |
126 | strcpy(im->name, ifname); | |
aba5acdf SH |
127 | im->type = ifi->ifi_type; |
128 | im->flags = ifi->ifi_flags; | |
0025e5d6 SH |
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 | ||
aba5acdf SH |
136 | return 0; |
137 | } | |
138 | ||
99f830de | 139 | const char *ll_idx_n2a(unsigned idx, char *buf) |
aba5acdf | 140 | { |
4b3385f6 | 141 | const struct ll_cache *im; |
aba5acdf SH |
142 | |
143 | if (idx == 0) | |
144 | return "*"; | |
1e21ea71 | 145 | |
0025e5d6 SH |
146 | im = ll_get_by_index(idx); |
147 | if (im) | |
148 | return im->name; | |
149 | ||
150 | if (if_indextoname(idx, buf) == NULL) | |
151 | snprintf(buf, IFNAMSIZ, "if%d", idx); | |
4b3385f6 | 152 | |
aba5acdf SH |
153 | return buf; |
154 | } | |
155 | ||
99f830de | 156 | const char *ll_index_to_name(unsigned idx) |
aba5acdf | 157 | { |
4b3385f6 | 158 | static char nbuf[IFNAMSIZ]; |
aba5acdf SH |
159 | |
160 | return ll_idx_n2a(idx, nbuf); | |
161 | } | |
162 | ||
99f830de | 163 | int ll_index_to_type(unsigned idx) |
aba5acdf | 164 | { |
4b3385f6 | 165 | const struct ll_cache *im; |
aba5acdf SH |
166 | |
167 | if (idx == 0) | |
168 | return -1; | |
0025e5d6 SH |
169 | |
170 | im = ll_get_by_index(idx); | |
171 | return im ? im->type : -1; | |
aba5acdf SH |
172 | } |
173 | ||
656111b2 | 174 | int ll_index_to_flags(unsigned idx) |
aba5acdf | 175 | { |
4b3385f6 | 176 | const struct ll_cache *im; |
aba5acdf SH |
177 | |
178 | if (idx == 0) | |
179 | return 0; | |
180 | ||
0025e5d6 SH |
181 | im = ll_get_by_index(idx); |
182 | return im ? im->flags : -1; | |
aba5acdf SH |
183 | } |
184 | ||
99f830de | 185 | unsigned ll_name_to_index(const char *name) |
aba5acdf | 186 | { |
0025e5d6 | 187 | const struct ll_cache *im; |
24abb62e | 188 | unsigned idx; |
aba5acdf SH |
189 | |
190 | if (name == NULL) | |
191 | return 0; | |
4b3385f6 | 192 | |
0025e5d6 SH |
193 | im = ll_get_by_name(name); |
194 | if (im) | |
195 | return im->index; | |
99f830de | 196 | |
24abb62e FW |
197 | idx = if_nametoindex(name); |
198 | if (idx == 0) | |
199 | sscanf(name, "if%u", &idx); | |
200 | return idx; | |
aba5acdf SH |
201 | } |
202 | ||
0025e5d6 | 203 | void ll_init_map(struct rtnl_handle *rth) |
aba5acdf | 204 | { |
30564237 OP |
205 | static int initialized; |
206 | ||
207 | if (initialized) | |
0025e5d6 | 208 | return; |
30564237 | 209 | |
aba5acdf SH |
210 | if (rtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK) < 0) { |
211 | perror("Cannot send dump request"); | |
212 | exit(1); | |
213 | } | |
214 | ||
cd70f3f5 | 215 | if (rtnl_dump_filter(rth, ll_remember_index, NULL) < 0) { |
aba5acdf SH |
216 | fprintf(stderr, "Dump terminated\n"); |
217 | exit(1); | |
218 | } | |
30564237 OP |
219 | |
220 | initialized = 1; | |
aba5acdf | 221 | } |