diff options
author | Thomas Graf <tgraf@suug.ch> | 2006-08-17 21:14:52 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 17:55:04 -0400 |
commit | 4e902c57417c4c285b98ba2722468d1c3ed83d1b (patch) | |
tree | 83251829a4bc9628a3543e5f70e7b11090fe22d9 /net/ipv4/fib_hash.c | |
parent | ab32ea5d8a760e7dd4339634e95d7be24ee5b842 (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_hash.c')
-rw-r--r-- | net/ipv4/fib_hash.c | 94 |
1 files changed, 44 insertions, 50 deletions
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index b5bee1a71e5c..357557549ce5 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c | |||
@@ -379,42 +379,39 @@ static struct fib_node *fib_find_node(struct fn_zone *fz, u32 key) | |||
379 | return NULL; | 379 | return NULL; |
380 | } | 380 | } |
381 | 381 | ||
382 | static int | 382 | static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg) |
383 | fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | ||
384 | struct nlmsghdr *n, struct netlink_skb_parms *req) | ||
385 | { | 383 | { |
386 | struct fn_hash *table = (struct fn_hash *) tb->tb_data; | 384 | struct fn_hash *table = (struct fn_hash *) tb->tb_data; |
387 | struct fib_node *new_f, *f; | 385 | struct fib_node *new_f, *f; |
388 | struct fib_alias *fa, *new_fa; | 386 | struct fib_alias *fa, *new_fa; |
389 | struct fn_zone *fz; | 387 | struct fn_zone *fz; |
390 | struct fib_info *fi; | 388 | struct fib_info *fi; |
391 | int z = r->rtm_dst_len; | 389 | u8 tos = cfg->fc_tos; |
392 | int type = r->rtm_type; | ||
393 | u8 tos = r->rtm_tos; | ||
394 | u32 key; | 390 | u32 key; |
395 | int err; | 391 | int err; |
396 | 392 | ||
397 | if (z > 32) | 393 | if (cfg->fc_dst_len > 32) |
398 | return -EINVAL; | 394 | return -EINVAL; |
399 | fz = table->fn_zones[z]; | 395 | |
400 | if (!fz && !(fz = fn_new_zone(table, z))) | 396 | fz = table->fn_zones[cfg->fc_dst_len]; |
397 | if (!fz && !(fz = fn_new_zone(table, cfg->fc_dst_len))) | ||
401 | return -ENOBUFS; | 398 | return -ENOBUFS; |
402 | 399 | ||
403 | key = 0; | 400 | key = 0; |
404 | if (rta->rta_dst) { | 401 | if (cfg->fc_dst) { |
405 | u32 dst; | 402 | if (cfg->fc_dst & ~FZ_MASK(fz)) |
406 | memcpy(&dst, rta->rta_dst, 4); | ||
407 | if (dst & ~FZ_MASK(fz)) | ||
408 | return -EINVAL; | 403 | return -EINVAL; |
409 | key = fz_key(dst, fz); | 404 | key = fz_key(cfg->fc_dst, fz); |
410 | } | 405 | } |
411 | 406 | ||
412 | if ((fi = fib_create_info(r, rta, n, &err)) == NULL) | 407 | fi = fib_create_info(cfg); |
413 | return err; | 408 | if (IS_ERR(fi)) |
409 | return PTR_ERR(fi); | ||
414 | 410 | ||
415 | if (fz->fz_nent > (fz->fz_divisor<<1) && | 411 | if (fz->fz_nent > (fz->fz_divisor<<1) && |
416 | fz->fz_divisor < FZ_MAX_DIVISOR && | 412 | fz->fz_divisor < FZ_MAX_DIVISOR && |
417 | (z==32 || (1<<z) > fz->fz_divisor)) | 413 | (cfg->fc_dst_len == 32 || |
414 | (1 << cfg->fc_dst_len) > fz->fz_divisor)) | ||
418 | fn_rehash_zone(fz); | 415 | fn_rehash_zone(fz); |
419 | 416 | ||
420 | f = fib_find_node(fz, key); | 417 | f = fib_find_node(fz, key); |
@@ -440,18 +437,18 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
440 | struct fib_alias *fa_orig; | 437 | struct fib_alias *fa_orig; |
441 | 438 | ||
442 | err = -EEXIST; | 439 | err = -EEXIST; |
443 | if (n->nlmsg_flags & NLM_F_EXCL) | 440 | if (cfg->fc_nlflags & NLM_F_EXCL) |
444 | goto out; | 441 | goto out; |
445 | 442 | ||
446 | if (n->nlmsg_flags & NLM_F_REPLACE) { | 443 | if (cfg->fc_nlflags & NLM_F_REPLACE) { |
447 | struct fib_info *fi_drop; | 444 | struct fib_info *fi_drop; |
448 | u8 state; | 445 | u8 state; |
449 | 446 | ||
450 | write_lock_bh(&fib_hash_lock); | 447 | write_lock_bh(&fib_hash_lock); |
451 | fi_drop = fa->fa_info; | 448 | fi_drop = fa->fa_info; |
452 | fa->fa_info = fi; | 449 | fa->fa_info = fi; |
453 | fa->fa_type = type; | 450 | fa->fa_type = cfg->fc_type; |
454 | fa->fa_scope = r->rtm_scope; | 451 | fa->fa_scope = cfg->fc_scope; |
455 | state = fa->fa_state; | 452 | state = fa->fa_state; |
456 | fa->fa_state &= ~FA_S_ACCESSED; | 453 | fa->fa_state &= ~FA_S_ACCESSED; |
457 | fib_hash_genid++; | 454 | fib_hash_genid++; |
@@ -474,17 +471,17 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
474 | break; | 471 | break; |
475 | if (fa->fa_info->fib_priority != fi->fib_priority) | 472 | if (fa->fa_info->fib_priority != fi->fib_priority) |
476 | break; | 473 | break; |
477 | if (fa->fa_type == type && | 474 | if (fa->fa_type == cfg->fc_type && |
478 | fa->fa_scope == r->rtm_scope && | 475 | fa->fa_scope == cfg->fc_scope && |
479 | fa->fa_info == fi) | 476 | fa->fa_info == fi) |
480 | goto out; | 477 | goto out; |
481 | } | 478 | } |
482 | if (!(n->nlmsg_flags & NLM_F_APPEND)) | 479 | if (!(cfg->fc_nlflags & NLM_F_APPEND)) |
483 | fa = fa_orig; | 480 | fa = fa_orig; |
484 | } | 481 | } |
485 | 482 | ||
486 | err = -ENOENT; | 483 | err = -ENOENT; |
487 | if (!(n->nlmsg_flags&NLM_F_CREATE)) | 484 | if (!(cfg->fc_nlflags & NLM_F_CREATE)) |
488 | goto out; | 485 | goto out; |
489 | 486 | ||
490 | err = -ENOBUFS; | 487 | err = -ENOBUFS; |
@@ -506,8 +503,8 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
506 | 503 | ||
507 | new_fa->fa_info = fi; | 504 | new_fa->fa_info = fi; |
508 | new_fa->fa_tos = tos; | 505 | new_fa->fa_tos = tos; |
509 | new_fa->fa_type = type; | 506 | new_fa->fa_type = cfg->fc_type; |
510 | new_fa->fa_scope = r->rtm_scope; | 507 | new_fa->fa_scope = cfg->fc_scope; |
511 | new_fa->fa_state = 0; | 508 | new_fa->fa_state = 0; |
512 | 509 | ||
513 | /* | 510 | /* |
@@ -526,7 +523,8 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
526 | fz->fz_nent++; | 523 | fz->fz_nent++; |
527 | rt_cache_flush(-1); | 524 | rt_cache_flush(-1); |
528 | 525 | ||
529 | rtmsg_fib(RTM_NEWROUTE, key, new_fa, z, tb->tb_id, n, req); | 526 | rtmsg_fib(RTM_NEWROUTE, key, new_fa, cfg->fc_dst_len, tb->tb_id, |
527 | &cfg->fc_nlinfo); | ||
530 | return 0; | 528 | return 0; |
531 | 529 | ||
532 | out_free_new_fa: | 530 | out_free_new_fa: |
@@ -537,30 +535,25 @@ out: | |||
537 | } | 535 | } |
538 | 536 | ||
539 | 537 | ||
540 | static int | 538 | static int fn_hash_delete(struct fib_table *tb, struct fib_config *cfg) |
541 | fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | ||
542 | struct nlmsghdr *n, struct netlink_skb_parms *req) | ||
543 | { | 539 | { |
544 | struct fn_hash *table = (struct fn_hash*)tb->tb_data; | 540 | struct fn_hash *table = (struct fn_hash*)tb->tb_data; |
545 | struct fib_node *f; | 541 | struct fib_node *f; |
546 | struct fib_alias *fa, *fa_to_delete; | 542 | struct fib_alias *fa, *fa_to_delete; |
547 | int z = r->rtm_dst_len; | ||
548 | struct fn_zone *fz; | 543 | struct fn_zone *fz; |
549 | u32 key; | 544 | u32 key; |
550 | u8 tos = r->rtm_tos; | ||
551 | 545 | ||
552 | if (z > 32) | 546 | if (cfg->fc_dst_len > 32) |
553 | return -EINVAL; | 547 | return -EINVAL; |
554 | if ((fz = table->fn_zones[z]) == NULL) | 548 | |
549 | if ((fz = table->fn_zones[cfg->fc_dst_len]) == NULL) | ||
555 | return -ESRCH; | 550 | return -ESRCH; |
556 | 551 | ||
557 | key = 0; | 552 | key = 0; |
558 | if (rta->rta_dst) { | 553 | if (cfg->fc_dst) { |
559 | u32 dst; | 554 | if (cfg->fc_dst & ~FZ_MASK(fz)) |
560 | memcpy(&dst, rta->rta_dst, 4); | ||
561 | if (dst & ~FZ_MASK(fz)) | ||
562 | return -EINVAL; | 555 | return -EINVAL; |
563 | key = fz_key(dst, fz); | 556 | key = fz_key(cfg->fc_dst, fz); |
564 | } | 557 | } |
565 | 558 | ||
566 | f = fib_find_node(fz, key); | 559 | f = fib_find_node(fz, key); |
@@ -568,7 +561,7 @@ fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
568 | if (!f) | 561 | if (!f) |
569 | fa = NULL; | 562 | fa = NULL; |
570 | else | 563 | else |
571 | fa = fib_find_alias(&f->fn_alias, tos, 0); | 564 | fa = fib_find_alias(&f->fn_alias, cfg->fc_tos, 0); |
572 | if (!fa) | 565 | if (!fa) |
573 | return -ESRCH; | 566 | return -ESRCH; |
574 | 567 | ||
@@ -577,16 +570,16 @@ fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
577 | list_for_each_entry_continue(fa, &f->fn_alias, fa_list) { | 570 | list_for_each_entry_continue(fa, &f->fn_alias, fa_list) { |
578 | struct fib_info *fi = fa->fa_info; | 571 | struct fib_info *fi = fa->fa_info; |
579 | 572 | ||
580 | if (fa->fa_tos != tos) | 573 | if (fa->fa_tos != cfg->fc_tos) |
581 | break; | 574 | break; |
582 | 575 | ||
583 | if ((!r->rtm_type || | 576 | if ((!cfg->fc_type || |
584 | fa->fa_type == r->rtm_type) && | 577 | fa->fa_type == cfg->fc_type) && |
585 | (r->rtm_scope == RT_SCOPE_NOWHERE || | 578 | (cfg->fc_scope == RT_SCOPE_NOWHERE || |
586 | fa->fa_scope == r->rtm_scope) && | 579 | fa->fa_scope == cfg->fc_scope) && |
587 | (!r->rtm_protocol || | 580 | (!cfg->fc_protocol || |
588 | fi->fib_protocol == r->rtm_protocol) && | 581 | fi->fib_protocol == cfg->fc_protocol) && |
589 | fib_nh_match(r, n, rta, fi) == 0) { | 582 | fib_nh_match(cfg, fi) == 0) { |
590 | fa_to_delete = fa; | 583 | fa_to_delete = fa; |
591 | break; | 584 | break; |
592 | } | 585 | } |
@@ -596,7 +589,8 @@ fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
596 | int kill_fn; | 589 | int kill_fn; |
597 | 590 | ||
598 | fa = fa_to_delete; | 591 | fa = fa_to_delete; |
599 | rtmsg_fib(RTM_DELROUTE, key, fa, z, tb->tb_id, n, req); | 592 | rtmsg_fib(RTM_DELROUTE, key, fa, cfg->fc_dst_len, |
593 | tb->tb_id, &cfg->fc_nlinfo); | ||
600 | 594 | ||
601 | kill_fn = 0; | 595 | kill_fn = 0; |
602 | write_lock_bh(&fib_hash_lock); | 596 | write_lock_bh(&fib_hash_lock); |