aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_semantics.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/fib_semantics.c')
-rw-r--r--net/ipv4/fib_semantics.c518
1 files changed, 187 insertions, 331 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 51738000f3dc..2ead09543f68 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -33,7 +33,6 @@
33#include <linux/if_arp.h> 33#include <linux/if_arp.h>
34#include <linux/proc_fs.h> 34#include <linux/proc_fs.h>
35#include <linux/skbuff.h> 35#include <linux/skbuff.h>
36#include <linux/netlink.h>
37#include <linux/init.h> 36#include <linux/init.h>
38 37
39#include <net/arp.h> 38#include <net/arp.h>
@@ -44,12 +43,14 @@
44#include <net/sock.h> 43#include <net/sock.h>
45#include <net/ip_fib.h> 44#include <net/ip_fib.h>
46#include <net/ip_mp_alg.h> 45#include <net/ip_mp_alg.h>
46#include <net/netlink.h>
47#include <net/nexthop.h>
47 48
48#include "fib_lookup.h" 49#include "fib_lookup.h"
49 50
50#define FSprintk(a...) 51#define FSprintk(a...)
51 52
52static DEFINE_RWLOCK(fib_info_lock); 53static DEFINE_SPINLOCK(fib_info_lock);
53static struct hlist_head *fib_info_hash; 54static struct hlist_head *fib_info_hash;
54static struct hlist_head *fib_info_laddrhash; 55static struct hlist_head *fib_info_laddrhash;
55static unsigned int fib_hash_size; 56static unsigned int fib_hash_size;
@@ -159,7 +160,7 @@ void free_fib_info(struct fib_info *fi)
159 160
160void fib_release_info(struct fib_info *fi) 161void fib_release_info(struct fib_info *fi)
161{ 162{
162 write_lock_bh(&fib_info_lock); 163 spin_lock_bh(&fib_info_lock);
163 if (fi && --fi->fib_treeref == 0) { 164 if (fi && --fi->fib_treeref == 0) {
164 hlist_del(&fi->fib_hash); 165 hlist_del(&fi->fib_hash);
165 if (fi->fib_prefsrc) 166 if (fi->fib_prefsrc)
@@ -172,7 +173,7 @@ void fib_release_info(struct fib_info *fi)
172 fi->fib_dead = 1; 173 fi->fib_dead = 1;
173 fib_info_put(fi); 174 fib_info_put(fi);
174 } 175 }
175 write_unlock_bh(&fib_info_lock); 176 spin_unlock_bh(&fib_info_lock);
176} 177}
177 178
178static __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *ofi) 179static __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
@@ -254,7 +255,7 @@ int ip_fib_check_default(u32 gw, struct net_device *dev)
254 struct fib_nh *nh; 255 struct fib_nh *nh;
255 unsigned int hash; 256 unsigned int hash;
256 257
257 read_lock(&fib_info_lock); 258 spin_lock(&fib_info_lock);
258 259
259 hash = fib_devindex_hashfn(dev->ifindex); 260 hash = fib_devindex_hashfn(dev->ifindex);
260 head = &fib_info_devhash[hash]; 261 head = &fib_info_devhash[hash];
@@ -262,41 +263,41 @@ int ip_fib_check_default(u32 gw, struct net_device *dev)
262 if (nh->nh_dev == dev && 263 if (nh->nh_dev == dev &&
263 nh->nh_gw == gw && 264 nh->nh_gw == gw &&
264 !(nh->nh_flags&RTNH_F_DEAD)) { 265 !(nh->nh_flags&RTNH_F_DEAD)) {
265 read_unlock(&fib_info_lock); 266 spin_unlock(&fib_info_lock);
266 return 0; 267 return 0;
267 } 268 }
268 } 269 }
269 270
270 read_unlock(&fib_info_lock); 271 spin_unlock(&fib_info_lock);
271 272
272 return -1; 273 return -1;
273} 274}
274 275
275void rtmsg_fib(int event, u32 key, struct fib_alias *fa, 276void rtmsg_fib(int event, u32 key, struct fib_alias *fa,
276 int z, int tb_id, 277 int dst_len, u32 tb_id, struct nl_info *info)
277 struct nlmsghdr *n, struct netlink_skb_parms *req)
278{ 278{
279 struct sk_buff *skb; 279 struct sk_buff *skb;
280 u32 pid = req ? req->pid : n->nlmsg_pid; 280 int payload = sizeof(struct rtmsg) + 256;
281 int size = NLMSG_SPACE(sizeof(struct rtmsg)+256); 281 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
282 282 int err = -ENOBUFS;
283 skb = alloc_skb(size, GFP_KERNEL); 283
284 if (!skb) 284 skb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL);
285 return; 285 if (skb == NULL)
286 286 goto errout;
287 if (fib_dump_info(skb, pid, n->nlmsg_seq, event, tb_id, 287
288 fa->fa_type, fa->fa_scope, &key, z, 288 err = fib_dump_info(skb, info->pid, seq, event, tb_id,
289 fa->fa_tos, 289 fa->fa_type, fa->fa_scope, key, dst_len,
290 fa->fa_info, 0) < 0) { 290 fa->fa_tos, fa->fa_info, 0);
291 if (err < 0) {
291 kfree_skb(skb); 292 kfree_skb(skb);
292 return; 293 goto errout;
293 } 294 }
294 NETLINK_CB(skb).dst_group = RTNLGRP_IPV4_ROUTE; 295
295 if (n->nlmsg_flags&NLM_F_ECHO) 296 err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE,
296 atomic_inc(&skb->users); 297 info->nlh, GFP_KERNEL);
297 netlink_broadcast(rtnl, skb, pid, RTNLGRP_IPV4_ROUTE, GFP_KERNEL); 298errout:
298 if (n->nlmsg_flags&NLM_F_ECHO) 299 if (err < 0)
299 netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT); 300 rtnl_set_sk_err(RTNLGRP_IPV4_ROUTE, err);
300} 301}
301 302
302/* Return the first fib alias matching TOS with 303/* Return the first fib alias matching TOS with
@@ -342,102 +343,100 @@ int fib_detect_death(struct fib_info *fi, int order,
342 343
343#ifdef CONFIG_IP_ROUTE_MULTIPATH 344#ifdef CONFIG_IP_ROUTE_MULTIPATH
344 345
345static u32 fib_get_attr32(struct rtattr *attr, int attrlen, int type) 346static int fib_count_nexthops(struct rtnexthop *rtnh, int remaining)
346{
347 while (RTA_OK(attr,attrlen)) {
348 if (attr->rta_type == type)
349 return *(u32*)RTA_DATA(attr);
350 attr = RTA_NEXT(attr, attrlen);
351 }
352 return 0;
353}
354
355static int
356fib_count_nexthops(struct rtattr *rta)
357{ 347{
358 int nhs = 0; 348 int nhs = 0;
359 struct rtnexthop *nhp = RTA_DATA(rta);
360 int nhlen = RTA_PAYLOAD(rta);
361 349
362 while (nhlen >= (int)sizeof(struct rtnexthop)) { 350 while (rtnh_ok(rtnh, remaining)) {
363 if ((nhlen -= nhp->rtnh_len) < 0)
364 return 0;
365 nhs++; 351 nhs++;
366 nhp = RTNH_NEXT(nhp); 352 rtnh = rtnh_next(rtnh, &remaining);
367 }; 353 }
368 return nhs; 354
355 /* leftover implies invalid nexthop configuration, discard it */
356 return remaining > 0 ? 0 : nhs;
369} 357}
370 358
371static int 359static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
372fib_get_nhs(struct fib_info *fi, const struct rtattr *rta, const struct rtmsg *r) 360 int remaining, struct fib_config *cfg)
373{ 361{
374 struct rtnexthop *nhp = RTA_DATA(rta);
375 int nhlen = RTA_PAYLOAD(rta);
376
377 change_nexthops(fi) { 362 change_nexthops(fi) {
378 int attrlen = nhlen - sizeof(struct rtnexthop); 363 int attrlen;
379 if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0) 364
365 if (!rtnh_ok(rtnh, remaining))
380 return -EINVAL; 366 return -EINVAL;
381 nh->nh_flags = (r->rtm_flags&~0xFF) | nhp->rtnh_flags; 367
382 nh->nh_oif = nhp->rtnh_ifindex; 368 nh->nh_flags = (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags;
383 nh->nh_weight = nhp->rtnh_hops + 1; 369 nh->nh_oif = rtnh->rtnh_ifindex;
384 if (attrlen) { 370 nh->nh_weight = rtnh->rtnh_hops + 1;
385 nh->nh_gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_GATEWAY); 371
372 attrlen = rtnh_attrlen(rtnh);
373 if (attrlen > 0) {
374 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
375
376 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
377 nh->nh_gw = nla ? nla_get_u32(nla) : 0;
386#ifdef CONFIG_NET_CLS_ROUTE 378#ifdef CONFIG_NET_CLS_ROUTE
387 nh->nh_tclassid = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_FLOW); 379 nla = nla_find(attrs, attrlen, RTA_FLOW);
380 nh->nh_tclassid = nla ? nla_get_u32(nla) : 0;
388#endif 381#endif
389 } 382 }
390 nhp = RTNH_NEXT(nhp); 383
384 rtnh = rtnh_next(rtnh, &remaining);
391 } endfor_nexthops(fi); 385 } endfor_nexthops(fi);
386
392 return 0; 387 return 0;
393} 388}
394 389
395#endif 390#endif
396 391
397int fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct kern_rta *rta, 392int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)
398 struct fib_info *fi)
399{ 393{
400#ifdef CONFIG_IP_ROUTE_MULTIPATH 394#ifdef CONFIG_IP_ROUTE_MULTIPATH
401 struct rtnexthop *nhp; 395 struct rtnexthop *rtnh;
402 int nhlen; 396 int remaining;
403#endif 397#endif
404 398
405 if (rta->rta_priority && 399 if (cfg->fc_priority && cfg->fc_priority != fi->fib_priority)
406 *rta->rta_priority != fi->fib_priority)
407 return 1; 400 return 1;
408 401
409 if (rta->rta_oif || rta->rta_gw) { 402 if (cfg->fc_oif || cfg->fc_gw) {
410 if ((!rta->rta_oif || *rta->rta_oif == fi->fib_nh->nh_oif) && 403 if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) &&
411 (!rta->rta_gw || memcmp(rta->rta_gw, &fi->fib_nh->nh_gw, 4) == 0)) 404 (!cfg->fc_gw || cfg->fc_gw == fi->fib_nh->nh_gw))
412 return 0; 405 return 0;
413 return 1; 406 return 1;
414 } 407 }
415 408
416#ifdef CONFIG_IP_ROUTE_MULTIPATH 409#ifdef CONFIG_IP_ROUTE_MULTIPATH
417 if (rta->rta_mp == NULL) 410 if (cfg->fc_mp == NULL)
418 return 0; 411 return 0;
419 nhp = RTA_DATA(rta->rta_mp); 412
420 nhlen = RTA_PAYLOAD(rta->rta_mp); 413 rtnh = cfg->fc_mp;
414 remaining = cfg->fc_mp_len;
421 415
422 for_nexthops(fi) { 416 for_nexthops(fi) {
423 int attrlen = nhlen - sizeof(struct rtnexthop); 417 int attrlen;
424 u32 gw;
425 418
426 if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0) 419 if (!rtnh_ok(rtnh, remaining))
427 return -EINVAL; 420 return -EINVAL;
428 if (nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif) 421
422 if (rtnh->rtnh_ifindex && rtnh->rtnh_ifindex != nh->nh_oif)
429 return 1; 423 return 1;
430 if (attrlen) { 424
431 gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_GATEWAY); 425 attrlen = rtnh_attrlen(rtnh);
432 if (gw && gw != nh->nh_gw) 426 if (attrlen < 0) {
427 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
428
429 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
430 if (nla && nla_get_u32(nla) != nh->nh_gw)
433 return 1; 431 return 1;
434#ifdef CONFIG_NET_CLS_ROUTE 432#ifdef CONFIG_NET_CLS_ROUTE
435 gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_FLOW); 433 nla = nla_find(attrs, attrlen, RTA_FLOW);
436 if (gw && gw != nh->nh_tclassid) 434 if (nla && nla_get_u32(nla) != nh->nh_tclassid)
437 return 1; 435 return 1;
438#endif 436#endif
439 } 437 }
440 nhp = RTNH_NEXT(nhp); 438
439 rtnh = rtnh_next(rtnh, &remaining);
441 } endfor_nexthops(fi); 440 } endfor_nexthops(fi);
442#endif 441#endif
443 return 0; 442 return 0;
@@ -488,7 +487,8 @@ int fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct kern_rta *rta,
488 |-> {local prefix} (terminal node) 487 |-> {local prefix} (terminal node)
489 */ 488 */
490 489
491static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_nh *nh) 490static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
491 struct fib_nh *nh)
492{ 492{
493 int err; 493 int err;
494 494
@@ -502,7 +502,7 @@ static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_n
502 if (nh->nh_flags&RTNH_F_ONLINK) { 502 if (nh->nh_flags&RTNH_F_ONLINK) {
503 struct net_device *dev; 503 struct net_device *dev;
504 504
505 if (r->rtm_scope >= RT_SCOPE_LINK) 505 if (cfg->fc_scope >= RT_SCOPE_LINK)
506 return -EINVAL; 506 return -EINVAL;
507 if (inet_addr_type(nh->nh_gw) != RTN_UNICAST) 507 if (inet_addr_type(nh->nh_gw) != RTN_UNICAST)
508 return -EINVAL; 508 return -EINVAL;
@@ -516,10 +516,15 @@ static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_n
516 return 0; 516 return 0;
517 } 517 }
518 { 518 {
519 struct flowi fl = { .nl_u = { .ip4_u = 519 struct flowi fl = {
520 { .daddr = nh->nh_gw, 520 .nl_u = {
521 .scope = r->rtm_scope + 1 } }, 521 .ip4_u = {
522 .oif = nh->nh_oif }; 522 .daddr = nh->nh_gw,
523 .scope = cfg->fc_scope + 1,
524 },
525 },
526 .oif = nh->nh_oif,
527 };
523 528
524 /* It is not necessary, but requires a bit of thinking */ 529 /* It is not necessary, but requires a bit of thinking */
525 if (fl.fl4_scope < RT_SCOPE_LINK) 530 if (fl.fl4_scope < RT_SCOPE_LINK)
@@ -598,7 +603,7 @@ static void fib_hash_move(struct hlist_head *new_info_hash,
598 unsigned int old_size = fib_hash_size; 603 unsigned int old_size = fib_hash_size;
599 unsigned int i, bytes; 604 unsigned int i, bytes;
600 605
601 write_lock_bh(&fib_info_lock); 606 spin_lock_bh(&fib_info_lock);
602 old_info_hash = fib_info_hash; 607 old_info_hash = fib_info_hash;
603 old_laddrhash = fib_info_laddrhash; 608 old_laddrhash = fib_info_laddrhash;
604 fib_hash_size = new_size; 609 fib_hash_size = new_size;
@@ -639,46 +644,35 @@ static void fib_hash_move(struct hlist_head *new_info_hash,
639 } 644 }
640 fib_info_laddrhash = new_laddrhash; 645 fib_info_laddrhash = new_laddrhash;
641 646
642 write_unlock_bh(&fib_info_lock); 647 spin_unlock_bh(&fib_info_lock);
643 648
644 bytes = old_size * sizeof(struct hlist_head *); 649 bytes = old_size * sizeof(struct hlist_head *);
645 fib_hash_free(old_info_hash, bytes); 650 fib_hash_free(old_info_hash, bytes);
646 fib_hash_free(old_laddrhash, bytes); 651 fib_hash_free(old_laddrhash, bytes);
647} 652}
648 653
649struct fib_info * 654struct fib_info *fib_create_info(struct fib_config *cfg)
650fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
651 const struct nlmsghdr *nlh, int *errp)
652{ 655{
653 int err; 656 int err;
654 struct fib_info *fi = NULL; 657 struct fib_info *fi = NULL;
655 struct fib_info *ofi; 658 struct fib_info *ofi;
656#ifdef CONFIG_IP_ROUTE_MULTIPATH
657 int nhs = 1; 659 int nhs = 1;
658#else
659 const int nhs = 1;
660#endif
661#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
662 u32 mp_alg = IP_MP_ALG_NONE;
663#endif
664 660
665 /* Fast check to catch the most weird cases */ 661 /* Fast check to catch the most weird cases */
666 if (fib_props[r->rtm_type].scope > r->rtm_scope) 662 if (fib_props[cfg->fc_type].scope > cfg->fc_scope)
667 goto err_inval; 663 goto err_inval;
668 664
669#ifdef CONFIG_IP_ROUTE_MULTIPATH 665#ifdef CONFIG_IP_ROUTE_MULTIPATH
670 if (rta->rta_mp) { 666 if (cfg->fc_mp) {
671 nhs = fib_count_nexthops(rta->rta_mp); 667 nhs = fib_count_nexthops(cfg->fc_mp, cfg->fc_mp_len);
672 if (nhs == 0) 668 if (nhs == 0)
673 goto err_inval; 669 goto err_inval;
674 } 670 }
675#endif 671#endif
676#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED 672#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
677 if (rta->rta_mp_alg) { 673 if (cfg->fc_mp_alg) {
678 mp_alg = *rta->rta_mp_alg; 674 if (cfg->fc_mp_alg < IP_MP_ALG_NONE ||
679 675 cfg->fc_mp_alg > IP_MP_ALG_MAX)
680 if (mp_alg < IP_MP_ALG_NONE ||
681 mp_alg > IP_MP_ALG_MAX)
682 goto err_inval; 676 goto err_inval;
683 } 677 }
684#endif 678#endif
@@ -714,43 +708,42 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
714 goto failure; 708 goto failure;
715 fib_info_cnt++; 709 fib_info_cnt++;
716 710
717 fi->fib_protocol = r->rtm_protocol; 711 fi->fib_protocol = cfg->fc_protocol;
712 fi->fib_flags = cfg->fc_flags;
713 fi->fib_priority = cfg->fc_priority;
714 fi->fib_prefsrc = cfg->fc_prefsrc;
718 715
719 fi->fib_nhs = nhs; 716 fi->fib_nhs = nhs;
720 change_nexthops(fi) { 717 change_nexthops(fi) {
721 nh->nh_parent = fi; 718 nh->nh_parent = fi;
722 } endfor_nexthops(fi) 719 } endfor_nexthops(fi)
723 720
724 fi->fib_flags = r->rtm_flags; 721 if (cfg->fc_mx) {
725 if (rta->rta_priority) 722 struct nlattr *nla;
726 fi->fib_priority = *rta->rta_priority; 723 int remaining;
727 if (rta->rta_mx) { 724
728 int attrlen = RTA_PAYLOAD(rta->rta_mx); 725 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
729 struct rtattr *attr = RTA_DATA(rta->rta_mx); 726 int type = nla->nla_type;
730 727
731 while (RTA_OK(attr, attrlen)) { 728 if (type) {
732 unsigned flavor = attr->rta_type; 729 if (type > RTAX_MAX)
733 if (flavor) {
734 if (flavor > RTAX_MAX)
735 goto err_inval; 730 goto err_inval;
736 fi->fib_metrics[flavor-1] = *(unsigned*)RTA_DATA(attr); 731 fi->fib_metrics[type - 1] = nla_get_u32(nla);
737 } 732 }
738 attr = RTA_NEXT(attr, attrlen);
739 } 733 }
740 } 734 }
741 if (rta->rta_prefsrc)
742 memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 4);
743 735
744 if (rta->rta_mp) { 736 if (cfg->fc_mp) {
745#ifdef CONFIG_IP_ROUTE_MULTIPATH 737#ifdef CONFIG_IP_ROUTE_MULTIPATH
746 if ((err = fib_get_nhs(fi, rta->rta_mp, r)) != 0) 738 err = fib_get_nhs(fi, cfg->fc_mp, cfg->fc_mp_len, cfg);
739 if (err != 0)
747 goto failure; 740 goto failure;
748 if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif) 741 if (cfg->fc_oif && fi->fib_nh->nh_oif != cfg->fc_oif)
749 goto err_inval; 742 goto err_inval;
750 if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 4)) 743 if (cfg->fc_gw && fi->fib_nh->nh_gw != cfg->fc_gw)
751 goto err_inval; 744 goto err_inval;
752#ifdef CONFIG_NET_CLS_ROUTE 745#ifdef CONFIG_NET_CLS_ROUTE
753 if (rta->rta_flow && memcmp(&fi->fib_nh->nh_tclassid, rta->rta_flow, 4)) 746 if (cfg->fc_flow && fi->fib_nh->nh_tclassid != cfg->fc_flow)
754 goto err_inval; 747 goto err_inval;
755#endif 748#endif
756#else 749#else
@@ -758,34 +751,32 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
758#endif 751#endif
759 } else { 752 } else {
760 struct fib_nh *nh = fi->fib_nh; 753 struct fib_nh *nh = fi->fib_nh;
761 if (rta->rta_oif) 754
762 nh->nh_oif = *rta->rta_oif; 755 nh->nh_oif = cfg->fc_oif;
763 if (rta->rta_gw) 756 nh->nh_gw = cfg->fc_gw;
764 memcpy(&nh->nh_gw, rta->rta_gw, 4); 757 nh->nh_flags = cfg->fc_flags;
765#ifdef CONFIG_NET_CLS_ROUTE 758#ifdef CONFIG_NET_CLS_ROUTE
766 if (rta->rta_flow) 759 nh->nh_tclassid = cfg->fc_flow;
767 memcpy(&nh->nh_tclassid, rta->rta_flow, 4);
768#endif 760#endif
769 nh->nh_flags = r->rtm_flags;
770#ifdef CONFIG_IP_ROUTE_MULTIPATH 761#ifdef CONFIG_IP_ROUTE_MULTIPATH
771 nh->nh_weight = 1; 762 nh->nh_weight = 1;
772#endif 763#endif
773 } 764 }
774 765
775#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED 766#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
776 fi->fib_mp_alg = mp_alg; 767 fi->fib_mp_alg = cfg->fc_mp_alg;
777#endif 768#endif
778 769
779 if (fib_props[r->rtm_type].error) { 770 if (fib_props[cfg->fc_type].error) {
780 if (rta->rta_gw || rta->rta_oif || rta->rta_mp) 771 if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp)
781 goto err_inval; 772 goto err_inval;
782 goto link_it; 773 goto link_it;
783 } 774 }
784 775
785 if (r->rtm_scope > RT_SCOPE_HOST) 776 if (cfg->fc_scope > RT_SCOPE_HOST)
786 goto err_inval; 777 goto err_inval;
787 778
788 if (r->rtm_scope == RT_SCOPE_HOST) { 779 if (cfg->fc_scope == RT_SCOPE_HOST) {
789 struct fib_nh *nh = fi->fib_nh; 780 struct fib_nh *nh = fi->fib_nh;
790 781
791 /* Local address is added. */ 782 /* Local address is added. */
@@ -798,14 +789,14 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
798 goto failure; 789 goto failure;
799 } else { 790 } else {
800 change_nexthops(fi) { 791 change_nexthops(fi) {
801 if ((err = fib_check_nh(r, fi, nh)) != 0) 792 if ((err = fib_check_nh(cfg, fi, nh)) != 0)
802 goto failure; 793 goto failure;
803 } endfor_nexthops(fi) 794 } endfor_nexthops(fi)
804 } 795 }
805 796
806 if (fi->fib_prefsrc) { 797 if (fi->fib_prefsrc) {
807 if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL || 798 if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst ||
808 memcmp(&fi->fib_prefsrc, rta->rta_dst, 4)) 799 fi->fib_prefsrc != cfg->fc_dst)
809 if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL) 800 if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
810 goto err_inval; 801 goto err_inval;
811 } 802 }
@@ -820,7 +811,7 @@ link_it:
820 811
821 fi->fib_treeref++; 812 fi->fib_treeref++;
822 atomic_inc(&fi->fib_clntref); 813 atomic_inc(&fi->fib_clntref);
823 write_lock_bh(&fib_info_lock); 814 spin_lock_bh(&fib_info_lock);
824 hlist_add_head(&fi->fib_hash, 815 hlist_add_head(&fi->fib_hash,
825 &fib_info_hash[fib_info_hashfn(fi)]); 816 &fib_info_hash[fib_info_hashfn(fi)]);
826 if (fi->fib_prefsrc) { 817 if (fi->fib_prefsrc) {
@@ -839,19 +830,19 @@ link_it:
839 head = &fib_info_devhash[hash]; 830 head = &fib_info_devhash[hash];
840 hlist_add_head(&nh->nh_hash, head); 831 hlist_add_head(&nh->nh_hash, head);
841 } endfor_nexthops(fi) 832 } endfor_nexthops(fi)
842 write_unlock_bh(&fib_info_lock); 833 spin_unlock_bh(&fib_info_lock);
843 return fi; 834 return fi;
844 835
845err_inval: 836err_inval:
846 err = -EINVAL; 837 err = -EINVAL;
847 838
848failure: 839failure:
849 *errp = err;
850 if (fi) { 840 if (fi) {
851 fi->fib_dead = 1; 841 fi->fib_dead = 1;
852 free_fib_info(fi); 842 free_fib_info(fi);
853 } 843 }
854 return NULL; 844
845 return ERR_PTR(err);
855} 846}
856 847
857/* Note! fib_semantic_match intentionally uses RCU list functions. */ 848/* Note! fib_semantic_match intentionally uses RCU list functions. */
@@ -937,224 +928,89 @@ u32 __fib_res_prefsrc(struct fib_result *res)
937 return inet_select_addr(FIB_RES_DEV(*res), FIB_RES_GW(*res), res->scope); 928 return inet_select_addr(FIB_RES_DEV(*res), FIB_RES_GW(*res), res->scope);
938} 929}
939 930
940int 931int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
941fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, 932 u32 tb_id, u8 type, u8 scope, u32 dst, int dst_len, u8 tos,
942 u8 tb_id, u8 type, u8 scope, void *dst, int dst_len, u8 tos, 933 struct fib_info *fi, unsigned int flags)
943 struct fib_info *fi, unsigned int flags)
944{ 934{
935 struct nlmsghdr *nlh;
945 struct rtmsg *rtm; 936 struct rtmsg *rtm;
946 struct nlmsghdr *nlh;
947 unsigned char *b = skb->tail;
948 937
949 nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*rtm), flags); 938 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*rtm), flags);
950 rtm = NLMSG_DATA(nlh); 939 if (nlh == NULL)
940 return -ENOBUFS;
941
942 rtm = nlmsg_data(nlh);
951 rtm->rtm_family = AF_INET; 943 rtm->rtm_family = AF_INET;
952 rtm->rtm_dst_len = dst_len; 944 rtm->rtm_dst_len = dst_len;
953 rtm->rtm_src_len = 0; 945 rtm->rtm_src_len = 0;
954 rtm->rtm_tos = tos; 946 rtm->rtm_tos = tos;
955 rtm->rtm_table = tb_id; 947 rtm->rtm_table = tb_id;
948 NLA_PUT_U32(skb, RTA_TABLE, tb_id);
956 rtm->rtm_type = type; 949 rtm->rtm_type = type;
957 rtm->rtm_flags = fi->fib_flags; 950 rtm->rtm_flags = fi->fib_flags;
958 rtm->rtm_scope = scope; 951 rtm->rtm_scope = scope;
959 if (rtm->rtm_dst_len)
960 RTA_PUT(skb, RTA_DST, 4, dst);
961 rtm->rtm_protocol = fi->fib_protocol; 952 rtm->rtm_protocol = fi->fib_protocol;
953
954 if (rtm->rtm_dst_len)
955 NLA_PUT_U32(skb, RTA_DST, dst);
956
962 if (fi->fib_priority) 957 if (fi->fib_priority)
963 RTA_PUT(skb, RTA_PRIORITY, 4, &fi->fib_priority); 958 NLA_PUT_U32(skb, RTA_PRIORITY, fi->fib_priority);
959
964 if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0) 960 if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0)
965 goto rtattr_failure; 961 goto nla_put_failure;
962
966 if (fi->fib_prefsrc) 963 if (fi->fib_prefsrc)
967 RTA_PUT(skb, RTA_PREFSRC, 4, &fi->fib_prefsrc); 964 NLA_PUT_U32(skb, RTA_PREFSRC, fi->fib_prefsrc);
965
968 if (fi->fib_nhs == 1) { 966 if (fi->fib_nhs == 1) {
969 if (fi->fib_nh->nh_gw) 967 if (fi->fib_nh->nh_gw)
970 RTA_PUT(skb, RTA_GATEWAY, 4, &fi->fib_nh->nh_gw); 968 NLA_PUT_U32(skb, RTA_GATEWAY, fi->fib_nh->nh_gw);
969
971 if (fi->fib_nh->nh_oif) 970 if (fi->fib_nh->nh_oif)
972 RTA_PUT(skb, RTA_OIF, sizeof(int), &fi->fib_nh->nh_oif); 971 NLA_PUT_U32(skb, RTA_OIF, fi->fib_nh->nh_oif);
973#ifdef CONFIG_NET_CLS_ROUTE 972#ifdef CONFIG_NET_CLS_ROUTE
974 if (fi->fib_nh[0].nh_tclassid) 973 if (fi->fib_nh[0].nh_tclassid)
975 RTA_PUT(skb, RTA_FLOW, 4, &fi->fib_nh[0].nh_tclassid); 974 NLA_PUT_U32(skb, RTA_FLOW, fi->fib_nh[0].nh_tclassid);
976#endif 975#endif
977 } 976 }
978#ifdef CONFIG_IP_ROUTE_MULTIPATH 977#ifdef CONFIG_IP_ROUTE_MULTIPATH
979 if (fi->fib_nhs > 1) { 978 if (fi->fib_nhs > 1) {
980 struct rtnexthop *nhp; 979 struct rtnexthop *rtnh;
981 struct rtattr *mp_head; 980 struct nlattr *mp;
982 if (skb_tailroom(skb) <= RTA_SPACE(0)) 981
983 goto rtattr_failure; 982 mp = nla_nest_start(skb, RTA_MULTIPATH);
984 mp_head = (struct rtattr*)skb_put(skb, RTA_SPACE(0)); 983 if (mp == NULL)
984 goto nla_put_failure;
985 985
986 for_nexthops(fi) { 986 for_nexthops(fi) {
987 if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) 987 rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));
988 goto rtattr_failure; 988 if (rtnh == NULL)
989 nhp = (struct rtnexthop*)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); 989 goto nla_put_failure;
990 nhp->rtnh_flags = nh->nh_flags & 0xFF; 990
991 nhp->rtnh_hops = nh->nh_weight-1; 991 rtnh->rtnh_flags = nh->nh_flags & 0xFF;
992 nhp->rtnh_ifindex = nh->nh_oif; 992 rtnh->rtnh_hops = nh->nh_weight - 1;
993 rtnh->rtnh_ifindex = nh->nh_oif;
994
993 if (nh->nh_gw) 995 if (nh->nh_gw)
994 RTA_PUT(skb, RTA_GATEWAY, 4, &nh->nh_gw); 996 NLA_PUT_U32(skb, RTA_GATEWAY, nh->nh_gw);
995#ifdef CONFIG_NET_CLS_ROUTE 997#ifdef CONFIG_NET_CLS_ROUTE
996 if (nh->nh_tclassid) 998 if (nh->nh_tclassid)
997 RTA_PUT(skb, RTA_FLOW, 4, &nh->nh_tclassid); 999 NLA_PUT_U32(skb, RTA_FLOW, nh->nh_tclassid);
998#endif 1000#endif
999 nhp->rtnh_len = skb->tail - (unsigned char*)nhp; 1001 /* length of rtnetlink header + attributes */
1002 rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *) rtnh;
1000 } endfor_nexthops(fi); 1003 } endfor_nexthops(fi);
1001 mp_head->rta_type = RTA_MULTIPATH;
1002 mp_head->rta_len = skb->tail - (u8*)mp_head;
1003 }
1004#endif
1005 nlh->nlmsg_len = skb->tail - b;
1006 return skb->len;
1007
1008nlmsg_failure:
1009rtattr_failure:
1010 skb_trim(skb, b - skb->data);
1011 return -1;
1012}
1013
1014#ifndef CONFIG_IP_NOSIOCRT
1015
1016int
1017fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm,
1018 struct kern_rta *rta, struct rtentry *r)
1019{
1020 int plen;
1021 u32 *ptr;
1022
1023 memset(rtm, 0, sizeof(*rtm));
1024 memset(rta, 0, sizeof(*rta));
1025
1026 if (r->rt_dst.sa_family != AF_INET)
1027 return -EAFNOSUPPORT;
1028
1029 /* Check mask for validity:
1030 a) it must be contiguous.
1031 b) destination must have all host bits clear.
1032 c) if application forgot to set correct family (AF_INET),
1033 reject request unless it is absolutely clear i.e.
1034 both family and mask are zero.
1035 */
1036 plen = 32;
1037 ptr = &((struct sockaddr_in*)&r->rt_dst)->sin_addr.s_addr;
1038 if (!(r->rt_flags&RTF_HOST)) {
1039 u32 mask = ((struct sockaddr_in*)&r->rt_genmask)->sin_addr.s_addr;
1040 if (r->rt_genmask.sa_family != AF_INET) {
1041 if (mask || r->rt_genmask.sa_family)
1042 return -EAFNOSUPPORT;
1043 }
1044 if (bad_mask(mask, *ptr))
1045 return -EINVAL;
1046 plen = inet_mask_len(mask);
1047 }
1048
1049 nl->nlmsg_flags = NLM_F_REQUEST;
1050 nl->nlmsg_pid = 0;
1051 nl->nlmsg_seq = 0;
1052 nl->nlmsg_len = NLMSG_LENGTH(sizeof(*rtm));
1053 if (cmd == SIOCDELRT) {
1054 nl->nlmsg_type = RTM_DELROUTE;
1055 nl->nlmsg_flags = 0;
1056 } else {
1057 nl->nlmsg_type = RTM_NEWROUTE;
1058 nl->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE;
1059 rtm->rtm_protocol = RTPROT_BOOT;
1060 }
1061
1062 rtm->rtm_dst_len = plen;
1063 rta->rta_dst = ptr;
1064
1065 if (r->rt_metric) {
1066 *(u32*)&r->rt_pad3 = r->rt_metric - 1;
1067 rta->rta_priority = (u32*)&r->rt_pad3;
1068 }
1069 if (r->rt_flags&RTF_REJECT) {
1070 rtm->rtm_scope = RT_SCOPE_HOST;
1071 rtm->rtm_type = RTN_UNREACHABLE;
1072 return 0;
1073 }
1074 rtm->rtm_scope = RT_SCOPE_NOWHERE;
1075 rtm->rtm_type = RTN_UNICAST;
1076
1077 if (r->rt_dev) {
1078 char *colon;
1079 struct net_device *dev;
1080 char devname[IFNAMSIZ];
1081
1082 if (copy_from_user(devname, r->rt_dev, IFNAMSIZ-1))
1083 return -EFAULT;
1084 devname[IFNAMSIZ-1] = 0;
1085 colon = strchr(devname, ':');
1086 if (colon)
1087 *colon = 0;
1088 dev = __dev_get_by_name(devname);
1089 if (!dev)
1090 return -ENODEV;
1091 rta->rta_oif = &dev->ifindex;
1092 if (colon) {
1093 struct in_ifaddr *ifa;
1094 struct in_device *in_dev = __in_dev_get_rtnl(dev);
1095 if (!in_dev)
1096 return -ENODEV;
1097 *colon = ':';
1098 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next)
1099 if (strcmp(ifa->ifa_label, devname) == 0)
1100 break;
1101 if (ifa == NULL)
1102 return -ENODEV;
1103 rta->rta_prefsrc = &ifa->ifa_local;
1104 }
1105 }
1106 1004
1107 ptr = &((struct sockaddr_in*)&r->rt_gateway)->sin_addr.s_addr; 1005 nla_nest_end(skb, mp);
1108 if (r->rt_gateway.sa_family == AF_INET && *ptr) {
1109 rta->rta_gw = ptr;
1110 if (r->rt_flags&RTF_GATEWAY && inet_addr_type(*ptr) == RTN_UNICAST)
1111 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
1112 } 1006 }
1007#endif
1008 return nlmsg_end(skb, nlh);
1113 1009
1114 if (cmd == SIOCDELRT) 1010nla_put_failure:
1115 return 0; 1011 return nlmsg_cancel(skb, nlh);
1116
1117 if (r->rt_flags&RTF_GATEWAY && rta->rta_gw == NULL)
1118 return -EINVAL;
1119
1120 if (rtm->rtm_scope == RT_SCOPE_NOWHERE)
1121 rtm->rtm_scope = RT_SCOPE_LINK;
1122
1123 if (r->rt_flags&(RTF_MTU|RTF_WINDOW|RTF_IRTT)) {
1124 struct rtattr *rec;
1125 struct rtattr *mx = kmalloc(RTA_LENGTH(3*RTA_LENGTH(4)), GFP_KERNEL);
1126 if (mx == NULL)
1127 return -ENOMEM;
1128 rta->rta_mx = mx;
1129 mx->rta_type = RTA_METRICS;
1130 mx->rta_len = RTA_LENGTH(0);
1131 if (r->rt_flags&RTF_MTU) {
1132 rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
1133 rec->rta_type = RTAX_ADVMSS;
1134 rec->rta_len = RTA_LENGTH(4);
1135 mx->rta_len += RTA_LENGTH(4);
1136 *(u32*)RTA_DATA(rec) = r->rt_mtu - 40;
1137 }
1138 if (r->rt_flags&RTF_WINDOW) {
1139 rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
1140 rec->rta_type = RTAX_WINDOW;
1141 rec->rta_len = RTA_LENGTH(4);
1142 mx->rta_len += RTA_LENGTH(4);
1143 *(u32*)RTA_DATA(rec) = r->rt_window;
1144 }
1145 if (r->rt_flags&RTF_IRTT) {
1146 rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
1147 rec->rta_type = RTAX_RTT;
1148 rec->rta_len = RTA_LENGTH(4);
1149 mx->rta_len += RTA_LENGTH(4);
1150 *(u32*)RTA_DATA(rec) = r->rt_irtt<<3;
1151 }
1152 }
1153 return 0;
1154} 1012}
1155 1013
1156#endif
1157
1158/* 1014/*
1159 Update FIB if: 1015 Update FIB if:
1160 - local address disappeared -> we must delete all the entries 1016 - local address disappeared -> we must delete all the entries