]>
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> | |
16 | #include <syslog.h> | |
17 | #include <fcntl.h> | |
18 | #include <sys/socket.h> | |
19 | #include <netinet/in.h> | |
20 | #include <string.h> | |
5f218239 | 21 | #include <net/if.h> |
aba5acdf SH |
22 | |
23 | #include "libnetlink.h" | |
24 | #include "ll_map.h" | |
4952b459 | 25 | #include "list.h" |
aba5acdf | 26 | |
0025e5d6 SH |
27 | struct ll_cache { |
28 | struct hlist_node idx_hash; | |
29 | struct hlist_node name_hash; | |
aba5acdf | 30 | unsigned flags; |
656111b2 | 31 | unsigned index; |
4b3385f6 | 32 | unsigned short type; |
4b3385f6 | 33 | char name[IFNAMSIZ]; |
aba5acdf SH |
34 | }; |
35 | ||
1e21ea71 | 36 | #define IDXMAP_SIZE 1024 |
0025e5d6 SH |
37 | static struct hlist_head idx_head[IDXMAP_SIZE]; |
38 | static struct hlist_head name_head[IDXMAP_SIZE]; | |
4b3385f6 | 39 | |
0025e5d6 | 40 | static struct ll_cache *ll_get_by_index(unsigned index) |
4b3385f6 | 41 | { |
0025e5d6 SH |
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 | ||
d652ccbf | 55 | unsigned namehash(const char *str) |
0025e5d6 SH |
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; | |
4b3385f6 | 79 | } |
aba5acdf | 80 | |
ae665a52 | 81 | int ll_remember_index(const struct sockaddr_nl *who, |
50772dc5 | 82 | struct nlmsghdr *n, void *arg) |
aba5acdf | 83 | { |
0025e5d6 SH |
84 | unsigned int h; |
85 | const char *ifname; | |
aba5acdf | 86 | struct ifinfomsg *ifi = NLMSG_DATA(n); |
0025e5d6 | 87 | struct ll_cache *im; |
aba5acdf SH |
88 | struct rtattr *tb[IFLA_MAX+1]; |
89 | ||
0025e5d6 | 90 | if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK) |
aba5acdf SH |
91 | return 0; |
92 | ||
93 | if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi))) | |
94 | return -1; | |
95 | ||
0025e5d6 SH |
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 | ||
aba5acdf SH |
106 | memset(tb, 0, sizeof(tb)); |
107 | parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); | |
0025e5d6 SH |
108 | ifname = rta_getattr_str(tb[IFLA_IFNAME]); |
109 | if (ifname == NULL) | |
aba5acdf SH |
110 | return 0; |
111 | ||
0025e5d6 SH |
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; | |
aba5acdf SH |
122 | } |
123 | ||
0025e5d6 SH |
124 | im = malloc(sizeof(*im)); |
125 | if (im == NULL) | |
126 | return 0; | |
127 | im->index = ifi->ifi_index; | |
128 | strcpy(im->name, ifname); | |
aba5acdf SH |
129 | im->type = ifi->ifi_type; |
130 | im->flags = ifi->ifi_flags; | |
0025e5d6 SH |
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 | ||
aba5acdf SH |
138 | return 0; |
139 | } | |
140 | ||
99f830de | 141 | const char *ll_idx_n2a(unsigned idx, char *buf) |
aba5acdf | 142 | { |
4b3385f6 | 143 | const struct ll_cache *im; |
aba5acdf SH |
144 | |
145 | if (idx == 0) | |
146 | return "*"; | |
1e21ea71 | 147 | |
0025e5d6 SH |
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); | |
4b3385f6 | 154 | |
aba5acdf SH |
155 | return buf; |
156 | } | |
157 | ||
99f830de | 158 | const char *ll_index_to_name(unsigned idx) |
aba5acdf | 159 | { |
4b3385f6 | 160 | static char nbuf[IFNAMSIZ]; |
aba5acdf SH |
161 | |
162 | return ll_idx_n2a(idx, nbuf); | |
163 | } | |
164 | ||
99f830de | 165 | int ll_index_to_type(unsigned idx) |
aba5acdf | 166 | { |
4b3385f6 | 167 | const struct ll_cache *im; |
aba5acdf SH |
168 | |
169 | if (idx == 0) | |
170 | return -1; | |
0025e5d6 SH |
171 | |
172 | im = ll_get_by_index(idx); | |
173 | return im ? im->type : -1; | |
aba5acdf SH |
174 | } |
175 | ||
656111b2 | 176 | int ll_index_to_flags(unsigned idx) |
aba5acdf | 177 | { |
4b3385f6 | 178 | const struct ll_cache *im; |
aba5acdf SH |
179 | |
180 | if (idx == 0) | |
181 | return 0; | |
182 | ||
0025e5d6 SH |
183 | im = ll_get_by_index(idx); |
184 | return im ? im->flags : -1; | |
aba5acdf SH |
185 | } |
186 | ||
99f830de | 187 | unsigned ll_name_to_index(const char *name) |
aba5acdf | 188 | { |
0025e5d6 | 189 | const struct ll_cache *im; |
24abb62e | 190 | unsigned idx; |
aba5acdf SH |
191 | |
192 | if (name == NULL) | |
193 | return 0; | |
4b3385f6 | 194 | |
0025e5d6 SH |
195 | im = ll_get_by_name(name); |
196 | if (im) | |
197 | return im->index; | |
99f830de | 198 | |
24abb62e FW |
199 | idx = if_nametoindex(name); |
200 | if (idx == 0) | |
201 | sscanf(name, "if%u", &idx); | |
202 | return idx; | |
aba5acdf SH |
203 | } |
204 | ||
0025e5d6 | 205 | void ll_init_map(struct rtnl_handle *rth) |
aba5acdf | 206 | { |
30564237 OP |
207 | static int initialized; |
208 | ||
209 | if (initialized) | |
0025e5d6 | 210 | return; |
30564237 | 211 | |
aba5acdf SH |
212 | if (rtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK) < 0) { |
213 | perror("Cannot send dump request"); | |
214 | exit(1); | |
215 | } | |
216 | ||
cd70f3f5 | 217 | if (rtnl_dump_filter(rth, ll_remember_index, NULL) < 0) { |
aba5acdf SH |
218 | fprintf(stderr, "Dump terminated\n"); |
219 | exit(1); | |
220 | } | |
30564237 OP |
221 | |
222 | initialized = 1; | |
aba5acdf | 223 | } |