diff options
Diffstat (limited to 'net/core/rtnetlink.c')
-rw-r--r-- | net/core/rtnetlink.c | 68 |
1 files changed, 38 insertions, 30 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 44dfaf8f04af..00caf4b318b2 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/types.h> | 22 | #include <linux/types.h> |
23 | #include <linux/socket.h> | 23 | #include <linux/socket.h> |
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/major.h> | ||
26 | #include <linux/sched.h> | 25 | #include <linux/sched.h> |
27 | #include <linux/timer.h> | 26 | #include <linux/timer.h> |
28 | #include <linux/string.h> | 27 | #include <linux/string.h> |
@@ -87,30 +86,33 @@ struct sock *rtnl; | |||
87 | 86 | ||
88 | struct rtnetlink_link * rtnetlink_links[NPROTO]; | 87 | struct rtnetlink_link * rtnetlink_links[NPROTO]; |
89 | 88 | ||
90 | static const int rtm_min[(RTM_MAX+1-RTM_BASE)/4] = | 89 | static const int rtm_min[RTM_NR_FAMILIES] = |
91 | { | 90 | { |
92 | NLMSG_LENGTH(sizeof(struct ifinfomsg)), | 91 | [RTM_FAM(RTM_NEWLINK)] = NLMSG_LENGTH(sizeof(struct ifinfomsg)), |
93 | NLMSG_LENGTH(sizeof(struct ifaddrmsg)), | 92 | [RTM_FAM(RTM_NEWADDR)] = NLMSG_LENGTH(sizeof(struct ifaddrmsg)), |
94 | NLMSG_LENGTH(sizeof(struct rtmsg)), | 93 | [RTM_FAM(RTM_NEWROUTE)] = NLMSG_LENGTH(sizeof(struct rtmsg)), |
95 | NLMSG_LENGTH(sizeof(struct ndmsg)), | 94 | [RTM_FAM(RTM_NEWNEIGH)] = NLMSG_LENGTH(sizeof(struct ndmsg)), |
96 | NLMSG_LENGTH(sizeof(struct rtmsg)), | 95 | [RTM_FAM(RTM_NEWRULE)] = NLMSG_LENGTH(sizeof(struct rtmsg)), |
97 | NLMSG_LENGTH(sizeof(struct tcmsg)), | 96 | [RTM_FAM(RTM_NEWQDISC)] = NLMSG_LENGTH(sizeof(struct tcmsg)), |
98 | NLMSG_LENGTH(sizeof(struct tcmsg)), | 97 | [RTM_FAM(RTM_NEWTCLASS)] = NLMSG_LENGTH(sizeof(struct tcmsg)), |
99 | NLMSG_LENGTH(sizeof(struct tcmsg)), | 98 | [RTM_FAM(RTM_NEWTFILTER)] = NLMSG_LENGTH(sizeof(struct tcmsg)), |
100 | NLMSG_LENGTH(sizeof(struct tcamsg)) | 99 | [RTM_FAM(RTM_NEWACTION)] = NLMSG_LENGTH(sizeof(struct tcamsg)), |
100 | [RTM_FAM(RTM_NEWPREFIX)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), | ||
101 | [RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), | ||
102 | [RTM_FAM(RTM_GETANYCAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), | ||
101 | }; | 103 | }; |
102 | 104 | ||
103 | static const int rta_max[(RTM_MAX+1-RTM_BASE)/4] = | 105 | static const int rta_max[RTM_NR_FAMILIES] = |
104 | { | 106 | { |
105 | IFLA_MAX, | 107 | [RTM_FAM(RTM_NEWLINK)] = IFLA_MAX, |
106 | IFA_MAX, | 108 | [RTM_FAM(RTM_NEWADDR)] = IFA_MAX, |
107 | RTA_MAX, | 109 | [RTM_FAM(RTM_NEWROUTE)] = RTA_MAX, |
108 | NDA_MAX, | 110 | [RTM_FAM(RTM_NEWNEIGH)] = NDA_MAX, |
109 | RTA_MAX, | 111 | [RTM_FAM(RTM_NEWRULE)] = RTA_MAX, |
110 | TCA_MAX, | 112 | [RTM_FAM(RTM_NEWQDISC)] = TCA_MAX, |
111 | TCA_MAX, | 113 | [RTM_FAM(RTM_NEWTCLASS)] = TCA_MAX, |
112 | TCA_MAX, | 114 | [RTM_FAM(RTM_NEWTFILTER)] = TCA_MAX, |
113 | TCAA_MAX | 115 | [RTM_FAM(RTM_NEWACTION)] = TCAA_MAX, |
114 | }; | 116 | }; |
115 | 117 | ||
116 | void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data) | 118 | void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data) |
@@ -607,27 +609,33 @@ static inline int rtnetlink_rcv_skb(struct sk_buff *skb) | |||
607 | 609 | ||
608 | /* | 610 | /* |
609 | * rtnetlink input queue processing routine: | 611 | * rtnetlink input queue processing routine: |
610 | * - try to acquire shared lock. If it is failed, defer processing. | 612 | * - process as much as there was in the queue upon entry. |
611 | * - feed skbs to rtnetlink_rcv_skb, until it refuse a message, | 613 | * - feed skbs to rtnetlink_rcv_skb, until it refuse a message, |
612 | * that will occur, when a dump started and/or acquisition of | 614 | * that will occur, when a dump started. |
613 | * exclusive lock failed. | ||
614 | */ | 615 | */ |
615 | 616 | ||
616 | static void rtnetlink_rcv(struct sock *sk, int len) | 617 | static void rtnetlink_rcv(struct sock *sk, int len) |
617 | { | 618 | { |
619 | unsigned int qlen = skb_queue_len(&sk->sk_receive_queue); | ||
620 | |||
618 | do { | 621 | do { |
619 | struct sk_buff *skb; | 622 | struct sk_buff *skb; |
620 | 623 | ||
621 | if (rtnl_shlock_nowait()) | 624 | rtnl_lock(); |
622 | return; | 625 | |
626 | if (qlen > skb_queue_len(&sk->sk_receive_queue)) | ||
627 | qlen = skb_queue_len(&sk->sk_receive_queue); | ||
623 | 628 | ||
624 | while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { | 629 | for (; qlen; qlen--) { |
630 | skb = skb_dequeue(&sk->sk_receive_queue); | ||
625 | if (rtnetlink_rcv_skb(skb)) { | 631 | if (rtnetlink_rcv_skb(skb)) { |
626 | if (skb->len) | 632 | if (skb->len) |
627 | skb_queue_head(&sk->sk_receive_queue, | 633 | skb_queue_head(&sk->sk_receive_queue, |
628 | skb); | 634 | skb); |
629 | else | 635 | else { |
630 | kfree_skb(skb); | 636 | kfree_skb(skb); |
637 | qlen--; | ||
638 | } | ||
631 | break; | 639 | break; |
632 | } | 640 | } |
633 | kfree_skb(skb); | 641 | kfree_skb(skb); |
@@ -636,10 +644,10 @@ static void rtnetlink_rcv(struct sock *sk, int len) | |||
636 | up(&rtnl_sem); | 644 | up(&rtnl_sem); |
637 | 645 | ||
638 | netdev_run_todo(); | 646 | netdev_run_todo(); |
639 | } while (rtnl && rtnl->sk_receive_queue.qlen); | 647 | } while (qlen); |
640 | } | 648 | } |
641 | 649 | ||
642 | static struct rtnetlink_link link_rtnetlink_table[RTM_MAX-RTM_BASE+1] = | 650 | static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] = |
643 | { | 651 | { |
644 | [RTM_GETLINK - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo }, | 652 | [RTM_GETLINK - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo }, |
645 | [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink }, | 653 | [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink }, |