[NETLINK]: Synchronous message processing.
[linux-2.6.git] / net / core / rtnetlink.c
index d8c198e..6e1ab1e 100644 (file)
@@ -86,30 +86,33 @@ struct sock *rtnl;
 
 struct rtnetlink_link * rtnetlink_links[NPROTO];
 
-static const int rtm_min[(RTM_MAX+1-RTM_BASE)/4] =
+static const int rtm_min[RTM_NR_FAMILIES] =
 {
-       NLMSG_LENGTH(sizeof(struct ifinfomsg)),
-       NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
-       NLMSG_LENGTH(sizeof(struct rtmsg)),
-       NLMSG_LENGTH(sizeof(struct ndmsg)),
-       NLMSG_LENGTH(sizeof(struct rtmsg)),
-       NLMSG_LENGTH(sizeof(struct tcmsg)),
-       NLMSG_LENGTH(sizeof(struct tcmsg)),
-       NLMSG_LENGTH(sizeof(struct tcmsg)),
-       NLMSG_LENGTH(sizeof(struct tcamsg))
+       [RTM_FAM(RTM_NEWLINK)]      = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+       [RTM_FAM(RTM_NEWADDR)]      = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
+       [RTM_FAM(RTM_NEWROUTE)]     = NLMSG_LENGTH(sizeof(struct rtmsg)),
+       [RTM_FAM(RTM_NEWNEIGH)]     = NLMSG_LENGTH(sizeof(struct ndmsg)),
+       [RTM_FAM(RTM_NEWRULE)]      = NLMSG_LENGTH(sizeof(struct rtmsg)),
+       [RTM_FAM(RTM_NEWQDISC)]     = NLMSG_LENGTH(sizeof(struct tcmsg)),
+       [RTM_FAM(RTM_NEWTCLASS)]    = NLMSG_LENGTH(sizeof(struct tcmsg)),
+       [RTM_FAM(RTM_NEWTFILTER)]   = NLMSG_LENGTH(sizeof(struct tcmsg)),
+       [RTM_FAM(RTM_NEWACTION)]    = NLMSG_LENGTH(sizeof(struct tcamsg)),
+       [RTM_FAM(RTM_NEWPREFIX)]    = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
+       [RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
+       [RTM_FAM(RTM_GETANYCAST)]   = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
 };
 
-static const int rta_max[(RTM_MAX+1-RTM_BASE)/4] =
+static const int rta_max[RTM_NR_FAMILIES] =
 {
-       IFLA_MAX,
-       IFA_MAX,
-       RTA_MAX,
-       NDA_MAX,
-       RTA_MAX,
-       TCA_MAX,
-       TCA_MAX,
-       TCA_MAX,
-       TCAA_MAX
+       [RTM_FAM(RTM_NEWLINK)]      = IFLA_MAX,
+       [RTM_FAM(RTM_NEWADDR)]      = IFA_MAX,
+       [RTM_FAM(RTM_NEWROUTE)]     = RTA_MAX,
+       [RTM_FAM(RTM_NEWNEIGH)]     = NDA_MAX,
+       [RTM_FAM(RTM_NEWRULE)]      = RTA_MAX,
+       [RTM_FAM(RTM_NEWQDISC)]     = TCA_MAX,
+       [RTM_FAM(RTM_NEWTCLASS)]    = TCA_MAX,
+       [RTM_FAM(RTM_NEWTFILTER)]   = TCA_MAX,
+       [RTM_FAM(RTM_NEWACTION)]    = TCAA_MAX,
 };
 
 void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
@@ -606,26 +609,31 @@ static inline int rtnetlink_rcv_skb(struct sk_buff *skb)
 
 /*
  *  rtnetlink input queue processing routine:
- *     - try to acquire shared lock. If it is failed, defer processing.
+ *     - process as much as there was in the queue upon entry.
  *     - feed skbs to rtnetlink_rcv_skb, until it refuse a message,
- *       that will occur, when a dump started and/or acquisition of
- *       exclusive lock failed.
+ *       that will occur, when a dump started.
  */
 
 static void rtnetlink_rcv(struct sock *sk, int len)
 {
+       unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
+
        do {
                struct sk_buff *skb;
 
-               if (rtnl_shlock_nowait())
-                       return;
+               rtnl_lock();
+
+               if (qlen > skb_queue_len(&sk->sk_receive_queue))
+                       qlen = skb_queue_len(&sk->sk_receive_queue);
 
-               while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
+               while (qlen--) {
+                       skb = skb_dequeue(&sk->sk_receive_queue);
                        if (rtnetlink_rcv_skb(skb)) {
-                               if (skb->len)
+                               if (skb->len) {
                                        skb_queue_head(&sk->sk_receive_queue,
                                                       skb);
-                               else
+                                       qlen++;
+                               } else
                                        kfree_skb(skb);
                                break;
                        }
@@ -635,10 +643,10 @@ static void rtnetlink_rcv(struct sock *sk, int len)
                up(&rtnl_sem);
 
                netdev_run_todo();
-       } while (rtnl && rtnl->sk_receive_queue.qlen);
+       } while (qlen);
 }
 
-static struct rtnetlink_link link_rtnetlink_table[RTM_MAX-RTM_BASE+1] =
+static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] =
 {
        [RTM_GETLINK  - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo },
        [RTM_SETLINK  - RTM_BASE] = { .doit   = do_setlink            },