embox

Форк
0
/
route.c 
324 строки · 7.9 Кб
1
/**
2
 * @file
3
 * @brief implementation of the IP router.
4
 *
5
 * @date 16.11.09
6
 * @author Nikolay Korotky
7
 * @author Ilia Vaprol
8
 * @author Vladimir Sokolov
9
 */
10

11
#include <errno.h>
12
#include <assert.h>
13
#include <net/l3/route.h>
14
#include <linux/in.h>
15
#include <mem/misc/pool.h>
16
#include <net/inetdevice.h>
17
#include <lib/libds/bit.h>
18
#include <lib/libds/dlist.h>
19
#include <util/member.h>
20
#include <net/skbuff.h>
21
#include <net/sock.h>
22

23
#include <framework/mod/options.h>
24

25
/**
26
 * NOTE: Linux route uses 3 structures for routing:
27
 *    + Forwarding Information Base (FIB)
28
 *    - routing cache (256 chains)
29
 *    + neighbour table (ARP cache)
30
 */
31

32
struct rt_entry_info {
33
	struct dlist_head lnk;
34
	struct rt_entry entry;
35
};
36

37
POOL_DEF(rt_entry_info_pool, struct rt_entry_info, OPTION_GET(NUMBER,route_table_size));
38
static DLIST_DEFINE(rt_entry_info_list);
39

40
int rt_add_route(struct net_device *dev, in_addr_t dst,
41
		in_addr_t mask, in_addr_t gw, int flags) {
42
	struct rt_entry_info *rt_info;
43
	bool flag = true;
44

45
	if (dev == NULL) {
46
		return -EINVAL;
47
	}
48

49
	dlist_foreach_entry(rt_info, &rt_entry_info_list, lnk) {
50
		if ((rt_info->entry.rt_dst == dst) &&
51
                ((rt_info->entry.rt_mask == mask) || (INADDR_ANY == mask)) &&
52
    			((rt_info->entry.rt_gateway == gw) || (INADDR_ANY == gw)) &&
53
    			((rt_info->entry.dev == dev) || (NULL == dev))) {
54
			flag = false;
55
			return 0;
56
		}
57
	}
58

59
	if (flag) {
60
		rt_info = (struct rt_entry_info *)pool_alloc(&rt_entry_info_pool);
61
		if (rt_info == NULL) {
62
			return -ENOMEM;
63
		}
64
		rt_info->entry.dev = dev;
65
		rt_info->entry.rt_dst = dst; /* We assume that host bits are zeroes here */
66
		rt_info->entry.rt_mask = mask;
67
		rt_info->entry.rt_gateway = gw;
68
		rt_info->entry.rt_flags = RTF_UP | flags;
69
		dlist_add_prev_entry(rt_info, &rt_entry_info_list, lnk);
70
	}
71

72
	return 0;
73
}
74

75
int rt_del_route(struct net_device *dev, in_addr_t dst,
76
		in_addr_t mask, in_addr_t gw) {
77
	struct rt_entry_info *rt_info;
78

79
	dlist_foreach_entry(rt_info, &rt_entry_info_list, lnk) {
80
		if ((rt_info->entry.rt_dst == dst) &&
81
                ((rt_info->entry.rt_mask == mask) || (INADDR_ANY == mask)) &&
82
    			((rt_info->entry.rt_gateway == gw) || (INADDR_ANY == gw)) &&
83
    			((rt_info->entry.dev == dev) || (NULL == dev))) {
84
			dlist_del_init_entry(rt_info, lnk);
85
			pool_free(&rt_entry_info_pool, rt_info);
86
			return 0;
87
		}
88
	}
89

90
	return -ENOENT;
91
}
92

93
int rt_del_route_if(struct net_device *dev) {
94
	struct rt_entry_info *rt_info = NULL;
95
	int ret = 0;
96

97
	dlist_foreach_entry(rt_info, &rt_entry_info_list, lnk) {
98
		if (rt_info->entry.dev == dev) {
99
			dlist_del_init_entry(rt_info, lnk);
100
			pool_free(&rt_entry_info_pool, rt_info);
101
			ret ++;
102
		}
103
	}
104

105
	return ret ? 0 : -ENOENT;
106
}
107

108
/* svv: ToDo:
109
 *      1) this function returns -ENOENT/0, but arp_resolve -1/0
110
 *         style must be the same
111
 *      2) Carrier without ARP can't be supported
112
 */
113
int ip_route(struct sk_buff *skb, struct net_device *wanna_dev,
114
		struct rt_entry *suggested_route) {
115
	in_addr_t daddr;
116
	struct rt_entry *rte;
117

118
	assert(skb != NULL);
119
	assert(skb->nh.iph != NULL);
120
	daddr = skb->nh.iph->daddr;
121

122
	/* SO_BROADCAST assert. */
123
	if (daddr == INADDR_BROADCAST) {
124
		if (wanna_dev == NULL) {
125
			return -ENODEV;
126
		}
127
		skb->dev = wanna_dev;
128
		return 0;
129
	}
130

131
	/* if loopback set lo device */
132
	if (ip_is_local(daddr, 0)) {
133
		assert(inetdev_get_loopback_dev() != NULL);
134
		skb->dev = inetdev_get_loopback_dev()->dev;
135
		return 0;
136
	}
137

138
	/* route destination address */
139
	rte = ((wanna_dev == NULL)
140
		? (suggested_route == NULL) ? rt_fib_get_best(daddr, NULL) : suggested_route
141
		: rt_fib_get_best(daddr, wanna_dev));
142
	if (rte == NULL) {
143
		return -ENETUNREACH;
144
	}
145

146
	/* set the device for current destination address */
147
	assert(rte->dev != NULL);
148
	assert((wanna_dev == NULL) || (wanna_dev == rte->dev));
149
	skb->dev = rte->dev;
150

151
	/* if the packet should be sent using gateway
152
	 * nothing todo there. all will be done in arp_resolve */
153
	return 0;
154
}
155

156
int rt_fib_route_ip(in_addr_t dst_ip, in_addr_t *next_ip) {
157
	struct rt_entry *rte;
158

159
	if (dst_ip == INADDR_BROADCAST) {
160
		*next_ip = dst_ip;
161
		return 0;
162
	}
163

164
	rte = rt_fib_get_best(dst_ip, NULL);
165
	if (rte == NULL) {
166
		return -ENETUNREACH;
167
	}
168

169
	if (rte->rt_gateway == INADDR_ANY) {
170
		*next_ip = dst_ip;
171
	} else {
172
		*next_ip = rte->rt_gateway;
173
	}
174

175
	return 0;
176
}
177

178
int rt_fib_source_ip(in_addr_t dst_ip, struct net_device *dev,
179
		in_addr_t *src_ip) {
180
	struct rt_entry *rte;
181

182
	if (dst_ip != INADDR_BROADCAST) {
183
		rte = rt_fib_get_best(dst_ip, NULL);
184
		if (rte == NULL) {
185
			return -ENETUNREACH;
186
		}
187
		assert(rte->dev != NULL);
188
		dev = rte->dev;
189
	}
190
	else if (dev == NULL) {
191
		return -ENODEV;
192
	}
193

194
	assert(inetdev_get_by_dev(dev) != NULL);
195
	*src_ip = inetdev_get_by_dev(dev)->ifa_address;
196

197
	return 0;
198
}
199

200
int rt_fib_out_dev(in_addr_t dst, const struct sock *sk,
201
		struct net_device **out_dev) {
202
	struct rt_entry *rte;
203
	struct net_device *wanna_dev;
204

205
	wanna_dev = sk != NULL ? sk->opt.so_bindtodevice : NULL;
206

207
	/* SO_BROADCAST assert. */
208
	if (dst == INADDR_BROADCAST) {
209
		if (wanna_dev == NULL) {
210
			return -ENODEV;
211
		}
212
		*out_dev = wanna_dev;
213
		return 0;
214
	}
215

216
	/* if loopback set lo device */
217
	if (ip_is_local(dst, 0)) {
218
		assert(inetdev_get_loopback_dev() != NULL);
219
		*out_dev = inetdev_get_loopback_dev()->dev;
220
		return 0;
221
	}
222

223
	/* route destination address */
224
	rte = rt_fib_get_best(dst, wanna_dev);
225
	if (rte == NULL) {
226
		return -ENETUNREACH;
227
	}
228

229
	/* set the device for current destination address */
230
	assert(rte->dev != NULL);
231
	assert((wanna_dev == NULL) || (wanna_dev == rte->dev));
232
	*out_dev = rte->dev;
233

234
	/* if the packet should be sent using gateway
235
	 * nothing todo there. all will be done in arp_resolve */
236
	return 0;
237
}
238

239
struct rt_entry * rt_fib_get_first(void) {
240
	if (dlist_empty(&rt_entry_info_list)) {
241
		return NULL;
242
	}
243

244
	return &dlist_next_entry_or_null(&rt_entry_info_list,
245
			struct rt_entry_info, lnk)->entry;
246
}
247

248
struct rt_entry * rt_fib_get_next(struct rt_entry *entry) {
249
	struct rt_entry_info *rt_info;
250

251
	assert(entry != NULL);
252

253
	rt_info = member_cast_out(entry, struct rt_entry_info, entry);
254
	if (rt_info == dlist_prev_entry_or_null(&rt_entry_info_list,
255
			struct rt_entry_info, lnk)) {
256
		return NULL;
257
	}
258

259
	return &dlist_entry(rt_info->lnk.next,
260
			struct rt_entry_info, lnk)->entry;
261
}
262

263
/* ToDo: It's too ugly to perform sorting for every packet.
264
 * Routes must be added into list with mask_len decrease.
265
 * In this case we'll simply take the first match
266
 */
267
struct rt_entry * rt_fib_get_best(in_addr_t dst, struct net_device *out_dev) {
268
	struct rt_entry_info *rt_info = NULL;
269
	int mask_len, best_mask_len;
270
	struct rt_entry *best_rte;
271

272
	best_rte = NULL;
273
	best_mask_len = -1;
274
	dlist_foreach_entry(rt_info, &rt_entry_info_list, lnk) {
275
		mask_len = ~rt_info->entry.rt_mask
276
			? bit_clz(ntohl(~rt_info->entry.rt_mask)) + 1 : 32;
277
		if (((dst & rt_info->entry.rt_mask) == rt_info->entry.rt_dst)
278
				&& (out_dev == NULL || out_dev == rt_info->entry.dev)
279
				&& (mask_len > best_mask_len)) {
280
			best_rte = &rt_info->entry;
281
			best_mask_len = mask_len;
282
		}
283
	}
284

285
	return best_rte;
286
}
287

288
#if defined(NET_NAMESPACE_ENABLED) && (NET_NAMESPACE_ENABLED == 1)
289
int rt_add_route_netns(struct net_device *dev, in_addr_t dst,
290
		in_addr_t mask, in_addr_t gw, int flags,
291
		net_namespace_p net_ns) {
292
	return rt_add_route(dev, dst, mask, gw, flags);
293
}
294

295
int rt_fib_route_ip_net_ns(in_addr_t dst_ip, in_addr_t *next_ip,
296
					net_namespace_p net_ns) {
297
	return rt_fib_route_ip(dst_ip, next_ip);
298
}
299

300
int rt_fib_source_ip_net_ns(in_addr_t dst_ip, struct net_device *dev,
301
		in_addr_t *src_ip, net_namespace_p net_ns) {
302
	return rt_fib_source_ip(dst_ip, dev, src_ip);
303
}
304

305
struct rt_entry * rt_fib_get_next_net_ns(struct rt_entry *entry,
306
					 net_namespace_p netns) {
307
	return rt_fib_get_next(entry);
308
}
309

310
struct rt_entry * rt_fib_get_first_net_ns(net_namespace_p netns) {
311
	return rt_fib_get_first();
312
}
313

314
struct rt_entry * rt_fib_get_best_net_ns(in_addr_t dst,
315
					 struct net_device *out_dev,
316
					 net_namespace_p net_ns) {
317
	return rt_fib_get_best(dst, out_dev);
318
}
319

320
int rt_fib_out_dev_net_ns(in_addr_t dst, const struct sock *sk,
321
		struct net_device **out_dev, net_namespace_p net_ns) {
322
	return rt_fib_out_dev(dst, sk, out_dev);
323
}
324
#endif
325

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.