aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_frontend.c
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2006-08-17 21:14:52 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 17:55:04 -0400
commit4e902c57417c4c285b98ba2722468d1c3ed83d1b (patch)
tree83251829a4bc9628a3543e5f70e7b11090fe22d9 /net/ipv4/fib_frontend.c
parentab32ea5d8a760e7dd4339634e95d7be24ee5b842 (diff)
[IPv4]: FIB configuration using struct fib_config
Introduces struct fib_config replacing the ugly struct kern_rta prone to ordering issues. Avoids creating faked netlink messages for auto generated routes or requests via ioctl. A new interface net/nexthop.h is added to help navigate through nexthop configuration arrays. A new struct nl_info will be used to carry the necessary netlink information to be used for notifications later on. Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/fib_frontend.c')
-rw-r--r--net/ipv4/fib_frontend.c364
1 files changed, 294 insertions, 70 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index ad4c14f968a1..acc18bdf2dee 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -253,42 +253,190 @@ e_inval:
253 253
254#ifndef CONFIG_IP_NOSIOCRT 254#ifndef CONFIG_IP_NOSIOCRT
255 255
256static inline u32 sk_extract_addr(struct sockaddr *addr)
257{
258 return ((struct sockaddr_in *) addr)->sin_addr.s_addr;
259}
260
261static int put_rtax(struct nlattr *mx, int len, int type, u32 value)
262{
263 struct nlattr *nla;
264
265 nla = (struct nlattr *) ((char *) mx + len);
266 nla->nla_type = type;
267 nla->nla_len = nla_attr_size(4);
268 *(u32 *) nla_data(nla) = value;
269
270 return len + nla_total_size(4);
271}
272
273static int rtentry_to_fib_config(int cmd, struct rtentry *rt,
274 struct fib_config *cfg)
275{
276 u32 addr;
277 int plen;
278
279 memset(cfg, 0, sizeof(*cfg));
280
281 if (rt->rt_dst.sa_family != AF_INET)
282 return -EAFNOSUPPORT;
283
284 /*
285 * Check mask for validity:
286 * a) it must be contiguous.
287 * b) destination must have all host bits clear.
288 * c) if application forgot to set correct family (AF_INET),
289 * reject request unless it is absolutely clear i.e.
290 * both family and mask are zero.
291 */
292 plen = 32;
293 addr = sk_extract_addr(&rt->rt_dst);
294 if (!(rt->rt_flags & RTF_HOST)) {
295 u32 mask = sk_extract_addr(&rt->rt_genmask);
296
297 if (rt->rt_genmask.sa_family != AF_INET) {
298 if (mask || rt->rt_genmask.sa_family)
299 return -EAFNOSUPPORT;
300 }
301
302 if (bad_mask(mask, addr))
303 return -EINVAL;
304
305 plen = inet_mask_len(mask);
306 }
307
308 cfg->fc_dst_len = plen;
309 cfg->fc_dst = addr;
310
311 if (cmd != SIOCDELRT) {
312 cfg->fc_nlflags = NLM_F_CREATE;
313 cfg->fc_protocol = RTPROT_BOOT;
314 }
315
316 if (rt->rt_metric)
317 cfg->fc_priority = rt->rt_metric - 1;
318
319 if (rt->rt_flags & RTF_REJECT) {
320 cfg->fc_scope = RT_SCOPE_HOST;
321 cfg->fc_type = RTN_UNREACHABLE;
322 return 0;
323 }
324
325 cfg->fc_scope = RT_SCOPE_NOWHERE;
326 cfg->fc_type = RTN_UNICAST;
327
328 if (rt->rt_dev) {
329 char *colon;
330 struct net_device *dev;
331 char devname[IFNAMSIZ];
332
333 if (copy_from_user(devname, rt->rt_dev, IFNAMSIZ-1))
334 return -EFAULT;
335
336 devname[IFNAMSIZ-1] = 0;
337 colon = strchr(devname, ':');
338 if (colon)
339 *colon = 0;
340 dev = __dev_get_by_name(devname);
341 if (!dev)
342 return -ENODEV;
343 cfg->fc_oif = dev->ifindex;
344 if (colon) {
345 struct in_ifaddr *ifa;
346 struct in_device *in_dev = __in_dev_get_rtnl(dev);
347 if (!in_dev)
348 return -ENODEV;
349 *colon = ':';
350 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next)
351 if (strcmp(ifa->ifa_label, devname) == 0)
352 break;
353 if (ifa == NULL)
354 return -ENODEV;
355 cfg->fc_prefsrc = ifa->ifa_local;
356 }
357 }
358
359 addr = sk_extract_addr(&rt->rt_gateway);
360 if (rt->rt_gateway.sa_family == AF_INET && addr) {
361 cfg->fc_gw = addr;
362 if (rt->rt_flags & RTF_GATEWAY &&
363 inet_addr_type(addr) == RTN_UNICAST)
364 cfg->fc_scope = RT_SCOPE_UNIVERSE;
365 }
366
367 if (cmd == SIOCDELRT)
368 return 0;
369
370 if (rt->rt_flags & RTF_GATEWAY && !cfg->fc_gw)
371 return -EINVAL;
372
373 if (cfg->fc_scope == RT_SCOPE_NOWHERE)
374 cfg->fc_scope = RT_SCOPE_LINK;
375
376 if (rt->rt_flags & (RTF_MTU | RTF_WINDOW | RTF_IRTT)) {
377 struct nlattr *mx;
378 int len = 0;
379
380 mx = kzalloc(3 * nla_total_size(4), GFP_KERNEL);
381 if (mx == NULL)
382 return -ENOMEM;
383
384 if (rt->rt_flags & RTF_MTU)
385 len = put_rtax(mx, len, RTAX_ADVMSS, rt->rt_mtu - 40);
386
387 if (rt->rt_flags & RTF_WINDOW)
388 len = put_rtax(mx, len, RTAX_WINDOW, rt->rt_window);
389
390 if (rt->rt_flags & RTF_IRTT)
391 len = put_rtax(mx, len, RTAX_RTT, rt->rt_irtt << 3);
392
393 cfg->fc_mx = mx;
394 cfg->fc_mx_len = len;
395 }
396
397 return 0;
398}
399
256/* 400/*
257 * Handle IP routing ioctl calls. These are used to manipulate the routing tables 401 * Handle IP routing ioctl calls. These are used to manipulate the routing tables
258 */ 402 */
259 403
260int ip_rt_ioctl(unsigned int cmd, void __user *arg) 404int ip_rt_ioctl(unsigned int cmd, void __user *arg)
261{ 405{
406 struct fib_config cfg;
407 struct rtentry rt;
262 int err; 408 int err;
263 struct kern_rta rta;
264 struct rtentry r;
265 struct {
266 struct nlmsghdr nlh;
267 struct rtmsg rtm;
268 } req;
269 409
270 switch (cmd) { 410 switch (cmd) {
271 case SIOCADDRT: /* Add a route */ 411 case SIOCADDRT: /* Add a route */
272 case SIOCDELRT: /* Delete a route */ 412 case SIOCDELRT: /* Delete a route */
273 if (!capable(CAP_NET_ADMIN)) 413 if (!capable(CAP_NET_ADMIN))
274 return -EPERM; 414 return -EPERM;
275 if (copy_from_user(&r, arg, sizeof(struct rtentry))) 415
416 if (copy_from_user(&rt, arg, sizeof(rt)))
276 return -EFAULT; 417 return -EFAULT;
418
277 rtnl_lock(); 419 rtnl_lock();
278 err = fib_convert_rtentry(cmd, &req.nlh, &req.rtm, &rta, &r); 420 err = rtentry_to_fib_config(cmd, &rt, &cfg);
279 if (err == 0) { 421 if (err == 0) {
422 struct fib_table *tb;
423
280 if (cmd == SIOCDELRT) { 424 if (cmd == SIOCDELRT) {
281 struct fib_table *tb = fib_get_table(req.rtm.rtm_table); 425 tb = fib_get_table(cfg.fc_table);
282 err = -ESRCH;
283 if (tb) 426 if (tb)
284 err = tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL); 427 err = tb->tb_delete(tb, &cfg);
428 else
429 err = -ESRCH;
285 } else { 430 } else {
286 struct fib_table *tb = fib_new_table(req.rtm.rtm_table); 431 tb = fib_new_table(cfg.fc_table);
287 err = -ENOBUFS;
288 if (tb) 432 if (tb)
289 err = tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL); 433 err = tb->tb_insert(tb, &cfg);
434 else
435 err = -ENOBUFS;
290 } 436 }
291 kfree(rta.rta_mx); 437
438 /* allocated by rtentry_to_fib_config() */
439 kfree(cfg.fc_mx);
292 } 440 }
293 rtnl_unlock(); 441 rtnl_unlock();
294 return err; 442 return err;
@@ -305,51 +453,134 @@ int ip_rt_ioctl(unsigned int cmd, void *arg)
305 453
306#endif 454#endif
307 455
308static int inet_check_attr(struct rtmsg *r, struct rtattr **rta) 456static struct nla_policy rtm_ipv4_policy[RTA_MAX+1] __read_mostly = {
457 [RTA_DST] = { .type = NLA_U32 },
458 [RTA_SRC] = { .type = NLA_U32 },
459 [RTA_IIF] = { .type = NLA_U32 },
460 [RTA_OIF] = { .type = NLA_U32 },
461 [RTA_GATEWAY] = { .type = NLA_U32 },
462 [RTA_PRIORITY] = { .type = NLA_U32 },
463 [RTA_PREFSRC] = { .type = NLA_U32 },
464 [RTA_METRICS] = { .type = NLA_NESTED },
465 [RTA_MULTIPATH] = { .minlen = sizeof(struct rtnexthop) },
466 [RTA_PROTOINFO] = { .type = NLA_U32 },
467 [RTA_FLOW] = { .type = NLA_U32 },
468 [RTA_MP_ALGO] = { .type = NLA_U32 },
469};
470
471static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh,
472 struct fib_config *cfg)
309{ 473{
310 int i; 474 struct nlattr *attr;
311 475 int err, remaining;
312 for (i=1; i<=RTA_MAX; i++, rta++) { 476 struct rtmsg *rtm;
313 struct rtattr *attr = *rta; 477
314 if (attr) { 478 err = nlmsg_validate(nlh, sizeof(*rtm), RTA_MAX, rtm_ipv4_policy);
315 if (RTA_PAYLOAD(attr) < 4) 479 if (err < 0)
316 return -EINVAL; 480 goto errout;
317 if (i != RTA_MULTIPATH && i != RTA_METRICS && 481
318 i != RTA_TABLE) 482 memset(cfg, 0, sizeof(*cfg));
319 *rta = (struct rtattr*)RTA_DATA(attr); 483
484 rtm = nlmsg_data(nlh);
485 cfg->fc_family = rtm->rtm_family;
486 cfg->fc_dst_len = rtm->rtm_dst_len;
487 cfg->fc_src_len = rtm->rtm_src_len;
488 cfg->fc_tos = rtm->rtm_tos;
489 cfg->fc_table = rtm->rtm_table;
490 cfg->fc_protocol = rtm->rtm_protocol;
491 cfg->fc_scope = rtm->rtm_scope;
492 cfg->fc_type = rtm->rtm_type;
493 cfg->fc_flags = rtm->rtm_flags;
494 cfg->fc_nlflags = nlh->nlmsg_flags;
495
496 cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid;
497 cfg->fc_nlinfo.nlh = nlh;
498
499 nlmsg_for_each_attr(attr, nlh, sizeof(struct rtmsg), remaining) {
500 switch (attr->nla_type) {
501 case RTA_DST:
502 cfg->fc_dst = nla_get_u32(attr);
503 break;
504 case RTA_SRC:
505 cfg->fc_src = nla_get_u32(attr);
506 break;
507 case RTA_OIF:
508 cfg->fc_oif = nla_get_u32(attr);
509 break;
510 case RTA_GATEWAY:
511 cfg->fc_gw = nla_get_u32(attr);
512 break;
513 case RTA_PRIORITY:
514 cfg->fc_priority = nla_get_u32(attr);
515 break;
516 case RTA_PREFSRC:
517 cfg->fc_prefsrc = nla_get_u32(attr);
518 break;
519 case RTA_METRICS:
520 cfg->fc_mx = nla_data(attr);
521 cfg->fc_mx_len = nla_len(attr);
522 break;
523 case RTA_MULTIPATH:
524 cfg->fc_mp = nla_data(attr);
525 cfg->fc_mp_len = nla_len(attr);
526 break;
527 case RTA_FLOW:
528 cfg->fc_flow = nla_get_u32(attr);
529 break;
530 case RTA_MP_ALGO:
531 cfg->fc_mp_alg = nla_get_u32(attr);
532 break;
533 case RTA_TABLE:
534 cfg->fc_table = nla_get_u32(attr);
535 break;
320 } 536 }
321 } 537 }
538
322 return 0; 539 return 0;
540errout:
541 return err;
323} 542}
324 543
325int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) 544int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
326{ 545{
327 struct fib_table * tb; 546 struct fib_config cfg;
328 struct rtattr **rta = arg; 547 struct fib_table *tb;
329 struct rtmsg *r = NLMSG_DATA(nlh); 548 int err;
330 549
331 if (inet_check_attr(r, rta)) 550 err = rtm_to_fib_config(skb, nlh, &cfg);
332 return -EINVAL; 551 if (err < 0)
552 goto errout;
333 553
334 tb = fib_get_table(rtm_get_table(rta, r->rtm_table)); 554 tb = fib_get_table(cfg.fc_table);
335 if (tb) 555 if (tb == NULL) {
336 return tb->tb_delete(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb)); 556 err = -ESRCH;
337 return -ESRCH; 557 goto errout;
558 }
559
560 err = tb->tb_delete(tb, &cfg);
561errout:
562 return err;
338} 563}
339 564
340int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) 565int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
341{ 566{
342 struct fib_table * tb; 567 struct fib_config cfg;
343 struct rtattr **rta = arg; 568 struct fib_table *tb;
344 struct rtmsg *r = NLMSG_DATA(nlh); 569 int err;
345 570
346 if (inet_check_attr(r, rta)) 571 err = rtm_to_fib_config(skb, nlh, &cfg);
347 return -EINVAL; 572 if (err < 0)
573 goto errout;
348 574
349 tb = fib_new_table(rtm_get_table(rta, r->rtm_table)); 575 tb = fib_new_table(cfg.fc_table);
350 if (tb) 576 if (tb == NULL) {
351 return tb->tb_insert(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb)); 577 err = -ENOBUFS;
352 return -ENOBUFS; 578 goto errout;
579 }
580
581 err = tb->tb_insert(tb, &cfg);
582errout:
583 return err;
353} 584}
354 585
355int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) 586int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
@@ -396,17 +627,19 @@ out:
396 only when netlink is already locked. 627 only when netlink is already locked.
397 */ 628 */
398 629
399static void fib_magic(int cmd, int type, u32 dst, int dst_len, struct in_ifaddr *ifa) 630static void fib_magic(int cmd, int type, u32 dst, int dst_len,
631 struct in_ifaddr *ifa)
400{ 632{
401 struct fib_table * tb; 633 struct fib_table *tb;
402 struct { 634 struct fib_config cfg = {
403 struct nlmsghdr nlh; 635 .fc_protocol = RTPROT_KERNEL,
404 struct rtmsg rtm; 636 .fc_type = type,
405 } req; 637 .fc_dst = dst,
406 struct kern_rta rta; 638 .fc_dst_len = dst_len,
407 639 .fc_prefsrc = ifa->ifa_local,
408 memset(&req.rtm, 0, sizeof(req.rtm)); 640 .fc_oif = ifa->ifa_dev->dev->ifindex,
409 memset(&rta, 0, sizeof(rta)); 641 .fc_nlflags = NLM_F_CREATE | NLM_F_APPEND,
642 };
410 643
411 if (type == RTN_UNICAST) 644 if (type == RTN_UNICAST)
412 tb = fib_new_table(RT_TABLE_MAIN); 645 tb = fib_new_table(RT_TABLE_MAIN);
@@ -416,26 +649,17 @@ static void fib_magic(int cmd, int type, u32 dst, int dst_len, struct in_ifaddr
416 if (tb == NULL) 649 if (tb == NULL)
417 return; 650 return;
418 651
419 req.nlh.nlmsg_len = sizeof(req); 652 cfg.fc_table = tb->tb_id;
420 req.nlh.nlmsg_type = cmd;
421 req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND;
422 req.nlh.nlmsg_pid = 0;
423 req.nlh.nlmsg_seq = 0;
424 653
425 req.rtm.rtm_dst_len = dst_len; 654 if (type != RTN_LOCAL)
426 req.rtm.rtm_table = tb->tb_id; 655 cfg.fc_scope = RT_SCOPE_LINK;
427 req.rtm.rtm_protocol = RTPROT_KERNEL; 656 else
428 req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST); 657 cfg.fc_scope = RT_SCOPE_HOST;
429 req.rtm.rtm_type = type;
430
431 rta.rta_dst = &dst;
432 rta.rta_prefsrc = &ifa->ifa_local;
433 rta.rta_oif = &ifa->ifa_dev->dev->ifindex;
434 658
435 if (cmd == RTM_NEWROUTE) 659 if (cmd == RTM_NEWROUTE)
436 tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL); 660 tb->tb_insert(tb, &cfg);
437 else 661 else
438 tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL); 662 tb->tb_delete(tb, &cfg);
439} 663}
440 664
441void fib_add_ifaddr(struct in_ifaddr *ifa) 665void fib_add_ifaddr(struct in_ifaddr *ifa)