]>
git.proxmox.com Git - mirror_iproute2.git/blob - lib/ll_map.c
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.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
22 #include "libnetlink.h"
28 struct hlist_node idx_hash
;
29 struct hlist_node name_hash
;
33 struct list_head altnames_list
;
37 #define IDXMAP_SIZE 1024
38 static struct hlist_head idx_head
[IDXMAP_SIZE
];
39 static struct hlist_head name_head
[IDXMAP_SIZE
];
41 static struct ll_cache
*ll_get_by_index(unsigned index
)
44 unsigned h
= index
& (IDXMAP_SIZE
- 1);
46 hlist_for_each(n
, &idx_head
[h
]) {
48 = container_of(n
, struct ll_cache
, idx_hash
);
49 if (im
->index
== index
)
56 unsigned namehash(const char *str
)
61 hash
= ((hash
<< 5) + hash
) + *str
++; /* hash * 33 + c */
66 static struct ll_cache
*ll_get_by_name(const char *name
)
69 unsigned h
= namehash(name
) & (IDXMAP_SIZE
- 1);
71 hlist_for_each(n
, &name_head
[h
]) {
73 = container_of(n
, struct ll_cache
, name_hash
);
75 if (strcmp(im
->name
, name
) == 0)
82 static struct ll_cache
*ll_entry_create(struct ifinfomsg
*ifi
,
84 struct ll_cache
*parent_im
)
89 im
= malloc(sizeof(*im
) + strlen(ifname
) + 1);
92 im
->index
= ifi
->ifi_index
;
93 strcpy(im
->name
, ifname
);
94 im
->type
= ifi
->ifi_type
;
95 im
->flags
= ifi
->ifi_flags
;
98 list_add_tail(&im
->altnames_list
, &parent_im
->altnames_list
);
100 /* This is parent, insert to index hash. */
101 h
= ifi
->ifi_index
& (IDXMAP_SIZE
- 1);
102 hlist_add_head(&im
->idx_hash
, &idx_head
[h
]);
103 INIT_LIST_HEAD(&im
->altnames_list
);
106 h
= namehash(ifname
) & (IDXMAP_SIZE
- 1);
107 hlist_add_head(&im
->name_hash
, &name_head
[h
]);
111 static void ll_entry_destroy(struct ll_cache
*im
, bool im_is_parent
)
113 hlist_del(&im
->name_hash
);
115 hlist_del(&im
->idx_hash
);
117 list_del(&im
->altnames_list
);
121 static void ll_entry_update(struct ll_cache
*im
, struct ifinfomsg
*ifi
,
126 im
->flags
= ifi
->ifi_flags
;
127 if (!strcmp(im
->name
, ifname
))
129 hlist_del(&im
->name_hash
);
130 h
= namehash(ifname
) & (IDXMAP_SIZE
- 1);
131 hlist_add_head(&im
->name_hash
, &name_head
[h
]);
134 static void ll_altname_entries_create(struct ll_cache
*parent_im
,
135 struct ifinfomsg
*ifi
, struct rtattr
**tb
)
137 struct rtattr
*i
, *proplist
= tb
[IFLA_PROP_LIST
];
142 rem
= RTA_PAYLOAD(proplist
);
143 for (i
= RTA_DATA(proplist
); RTA_OK(i
, rem
);
144 i
= RTA_NEXT(i
, rem
)) {
145 if (i
->rta_type
!= IFLA_ALT_IFNAME
)
147 ll_entry_create(ifi
, rta_getattr_str(i
), parent_im
);
151 static void ll_altname_entries_destroy(struct ll_cache
*parent_im
)
153 struct ll_cache
*im
, *tmp
;
155 list_for_each_entry_safe(im
, tmp
, &parent_im
->altnames_list
,
157 ll_entry_destroy(im
, false);
160 static void ll_altname_entries_update(struct ll_cache
*parent_im
,
161 struct ifinfomsg
*ifi
, struct rtattr
**tb
)
163 struct rtattr
*i
, *proplist
= tb
[IFLA_PROP_LIST
];
168 ll_altname_entries_destroy(parent_im
);
172 /* Simply compare the altname list with the cached one
173 * and if it does not fit 1:1, recreate the cached list
176 im
= list_first_entry(&parent_im
->altnames_list
, typeof(*im
),
178 rem
= RTA_PAYLOAD(proplist
);
179 for (i
= RTA_DATA(proplist
); RTA_OK(i
, rem
);
180 i
= RTA_NEXT(i
, rem
)) {
181 if (i
->rta_type
!= IFLA_ALT_IFNAME
)
183 if (!im
|| strcmp(rta_getattr_str(i
), im
->name
))
184 goto recreate_altname_entries
;
185 im
= list_next_entry(im
, altnames_list
);
187 if (list_next_entry(im
, altnames_list
))
188 goto recreate_altname_entries
;
191 recreate_altname_entries
:
192 ll_altname_entries_destroy(parent_im
);
193 ll_altname_entries_create(parent_im
, ifi
, tb
);
196 static void ll_entries_create(struct ifinfomsg
*ifi
, struct rtattr
**tb
)
198 struct ll_cache
*parent_im
;
200 if (!tb
[IFLA_IFNAME
])
202 parent_im
= ll_entry_create(ifi
, rta_getattr_str(tb
[IFLA_IFNAME
]),
206 ll_altname_entries_create(parent_im
, ifi
, tb
);
209 static void ll_entries_destroy(struct ll_cache
*parent_im
)
211 ll_altname_entries_destroy(parent_im
);
212 ll_entry_destroy(parent_im
, true);
215 static void ll_entries_update(struct ll_cache
*parent_im
,
216 struct ifinfomsg
*ifi
, struct rtattr
**tb
)
219 ll_entry_update(parent_im
, ifi
,
220 rta_getattr_str(tb
[IFLA_IFNAME
]));
221 ll_altname_entries_update(parent_im
, ifi
, tb
);
224 int ll_remember_index(struct nlmsghdr
*n
, void *arg
)
226 struct ifinfomsg
*ifi
= NLMSG_DATA(n
);
228 struct rtattr
*tb
[IFLA_MAX
+1];
230 if (n
->nlmsg_type
!= RTM_NEWLINK
&& n
->nlmsg_type
!= RTM_DELLINK
)
233 if (n
->nlmsg_len
< NLMSG_LENGTH(sizeof(*ifi
)))
236 im
= ll_get_by_index(ifi
->ifi_index
);
237 if (n
->nlmsg_type
== RTM_DELLINK
) {
239 ll_entries_destroy(im
);
243 parse_rtattr_flags(tb
, IFLA_MAX
, IFLA_RTA(ifi
),
244 IFLA_PAYLOAD(n
), NLA_F_NESTED
);
246 ll_entries_update(im
, ifi
, tb
);
248 ll_entries_create(ifi
, tb
);
252 const char *ll_idx_n2a(unsigned int idx
)
254 static char buf
[IFNAMSIZ
];
256 snprintf(buf
, sizeof(buf
), "if%u", idx
);
260 static unsigned int ll_idx_a2n(const char *name
)
264 if (sscanf(name
, "if%u", &idx
) != 1)
269 static int ll_link_get(const char *name
, int index
)
273 struct ifinfomsg ifm
;
276 .n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
)),
277 .n
.nlmsg_flags
= NLM_F_REQUEST
,
278 .n
.nlmsg_type
= RTM_GETLINK
,
279 .ifm
.ifi_index
= index
,
281 __u32 filt_mask
= RTEXT_FILTER_VF
| RTEXT_FILTER_SKIP_STATS
;
282 struct rtnl_handle rth
= {};
283 struct nlmsghdr
*answer
;
286 if (rtnl_open(&rth
, 0) < 0)
289 addattr32(&req
.n
, sizeof(req
), IFLA_EXT_MASK
, filt_mask
);
291 addattr_l(&req
.n
, sizeof(req
),
292 !check_ifname(name
) ? IFLA_IFNAME
: IFLA_ALT_IFNAME
,
293 name
, strlen(name
) + 1);
295 if (rtnl_talk_suppress_rtnl_errmsg(&rth
, &req
.n
, &answer
) < 0)
298 /* add entry to cache */
299 rc
= ll_remember_index(answer
, NULL
);
301 struct ifinfomsg
*ifm
= NLMSG_DATA(answer
);
312 const char *ll_index_to_name(unsigned int idx
)
314 static char buf
[IFNAMSIZ
];
315 const struct ll_cache
*im
;
320 im
= ll_get_by_index(idx
);
324 if (ll_link_get(NULL
, idx
) == idx
) {
325 im
= ll_get_by_index(idx
);
330 if (if_indextoname(idx
, buf
) == NULL
)
331 snprintf(buf
, IFNAMSIZ
, "if%u", idx
);
336 int ll_index_to_type(unsigned idx
)
338 const struct ll_cache
*im
;
343 im
= ll_get_by_index(idx
);
344 return im
? im
->type
: -1;
347 int ll_index_to_flags(unsigned idx
)
349 const struct ll_cache
*im
;
354 im
= ll_get_by_index(idx
);
355 return im
? im
->flags
: -1;
358 unsigned ll_name_to_index(const char *name
)
360 const struct ll_cache
*im
;
366 im
= ll_get_by_name(name
);
370 idx
= ll_link_get(name
, 0);
372 idx
= if_nametoindex(name
);
374 idx
= ll_idx_a2n(name
);
378 void ll_drop_by_index(unsigned index
)
382 im
= ll_get_by_index(index
);
386 hlist_del(&im
->idx_hash
);
387 hlist_del(&im
->name_hash
);
392 void ll_init_map(struct rtnl_handle
*rth
)
394 static int initialized
;
399 if (rtnl_linkdump_req(rth
, AF_UNSPEC
) < 0) {
400 perror("Cannot send dump request");
404 if (rtnl_dump_filter(rth
, ll_remember_index
, NULL
) < 0) {
405 fprintf(stderr
, "Dump terminated\n");