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