diff options
author | Thomas Graf <tgraf@suug.ch> | 2006-08-05 02:05:34 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 17:53:49 -0400 |
commit | b60c5115f4abf0b961a18682889798dcfbe6a801 (patch) | |
tree | 2612f4a912b3396b6770cb3b8a7ae0e71b0ecc13 /net | |
parent | da5e0494c542dddc56a1f1edfd30310ea30f41ff (diff) |
[NET]: Convert link dumping to new netlink api
Transforms netlink code to dump link tables to use the new
netlink api. Makes rtnl_getlink() available regardless of the
availability of the wireless extensions.
Adding copy_rtnl_link_stats() avoids the structural dependency
of struct rtnl_link_stats on struct net_device_stats and thus
avoids troubles later on.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/rtnetlink.c | 281 |
1 files changed, 137 insertions, 144 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 2adc966d981e..93ba04fb8444 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -218,41 +218,73 @@ static void set_operstate(struct net_device *dev, unsigned char transition) | |||
218 | } | 218 | } |
219 | } | 219 | } |
220 | 220 | ||
221 | static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | 221 | static void copy_rtnl_link_stats(struct rtnl_link_stats *a, |
222 | int type, u32 pid, u32 seq, u32 change, | 222 | struct net_device_stats *b) |
223 | unsigned int flags) | ||
224 | { | 223 | { |
225 | struct ifinfomsg *r; | 224 | a->rx_packets = b->rx_packets; |
226 | struct nlmsghdr *nlh; | 225 | a->tx_packets = b->tx_packets; |
227 | unsigned char *b = skb->tail; | 226 | a->rx_bytes = b->rx_bytes; |
228 | 227 | a->tx_bytes = b->tx_bytes; | |
229 | nlh = NLMSG_NEW(skb, pid, seq, type, sizeof(*r), flags); | 228 | a->rx_errors = b->rx_errors; |
230 | r = NLMSG_DATA(nlh); | 229 | a->tx_errors = b->tx_errors; |
231 | r->ifi_family = AF_UNSPEC; | 230 | a->rx_dropped = b->rx_dropped; |
232 | r->__ifi_pad = 0; | 231 | a->tx_dropped = b->tx_dropped; |
233 | r->ifi_type = dev->type; | 232 | |
234 | r->ifi_index = dev->ifindex; | 233 | a->multicast = b->multicast; |
235 | r->ifi_flags = dev_get_flags(dev); | 234 | a->collisions = b->collisions; |
236 | r->ifi_change = change; | 235 | |
236 | a->rx_length_errors = b->rx_length_errors; | ||
237 | a->rx_over_errors = b->rx_over_errors; | ||
238 | a->rx_crc_errors = b->rx_crc_errors; | ||
239 | a->rx_frame_errors = b->rx_frame_errors; | ||
240 | a->rx_fifo_errors = b->rx_fifo_errors; | ||
241 | a->rx_missed_errors = b->rx_missed_errors; | ||
242 | |||
243 | a->tx_aborted_errors = b->tx_aborted_errors; | ||
244 | a->tx_carrier_errors = b->tx_carrier_errors; | ||
245 | a->tx_fifo_errors = b->tx_fifo_errors; | ||
246 | a->tx_heartbeat_errors = b->tx_heartbeat_errors; | ||
247 | a->tx_window_errors = b->tx_window_errors; | ||
248 | |||
249 | a->rx_compressed = b->rx_compressed; | ||
250 | a->tx_compressed = b->tx_compressed; | ||
251 | }; | ||
237 | 252 | ||
238 | RTA_PUT(skb, IFLA_IFNAME, strlen(dev->name)+1, dev->name); | 253 | static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, |
254 | void *iwbuf, int iwbuflen, int type, u32 pid, | ||
255 | u32 seq, u32 change, unsigned int flags) | ||
256 | { | ||
257 | struct ifinfomsg *ifm; | ||
258 | struct nlmsghdr *nlh; | ||
239 | 259 | ||
240 | if (1) { | 260 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); |
241 | u32 txqlen = dev->tx_queue_len; | 261 | if (nlh == NULL) |
242 | RTA_PUT(skb, IFLA_TXQLEN, sizeof(txqlen), &txqlen); | 262 | return -ENOBUFS; |
243 | } | ||
244 | 263 | ||
245 | if (1) { | 264 | ifm = nlmsg_data(nlh); |
246 | u32 weight = dev->weight; | 265 | ifm->ifi_family = AF_UNSPEC; |
247 | RTA_PUT(skb, IFLA_WEIGHT, sizeof(weight), &weight); | 266 | ifm->__ifi_pad = 0; |
248 | } | 267 | ifm->ifi_type = dev->type; |
268 | ifm->ifi_index = dev->ifindex; | ||
269 | ifm->ifi_flags = dev_get_flags(dev); | ||
270 | ifm->ifi_change = change; | ||
271 | |||
272 | NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); | ||
273 | NLA_PUT_U32(skb, IFLA_TXQLEN, dev->tx_queue_len); | ||
274 | NLA_PUT_U32(skb, IFLA_WEIGHT, dev->weight); | ||
275 | NLA_PUT_U8(skb, IFLA_OPERSTATE, | ||
276 | netif_running(dev) ? dev->operstate : IF_OPER_DOWN); | ||
277 | NLA_PUT_U8(skb, IFLA_LINKMODE, dev->link_mode); | ||
278 | NLA_PUT_U32(skb, IFLA_MTU, dev->mtu); | ||
279 | |||
280 | if (dev->ifindex != dev->iflink) | ||
281 | NLA_PUT_U32(skb, IFLA_LINK, dev->iflink); | ||
282 | |||
283 | if (dev->master) | ||
284 | NLA_PUT_U32(skb, IFLA_MASTER, dev->master->ifindex); | ||
249 | 285 | ||
250 | if (1) { | 286 | if (dev->qdisc_sleeping) |
251 | u8 operstate = netif_running(dev)?dev->operstate:IF_OPER_DOWN; | 287 | NLA_PUT_STRING(skb, IFLA_QDISC, dev->qdisc_sleeping->ops->id); |
252 | u8 link_mode = dev->link_mode; | ||
253 | RTA_PUT(skb, IFLA_OPERSTATE, sizeof(operstate), &operstate); | ||
254 | RTA_PUT(skb, IFLA_LINKMODE, sizeof(link_mode), &link_mode); | ||
255 | } | ||
256 | 288 | ||
257 | if (1) { | 289 | if (1) { |
258 | struct rtnl_link_ifmap map = { | 290 | struct rtnl_link_ifmap map = { |
@@ -263,58 +295,38 @@ static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
263 | .dma = dev->dma, | 295 | .dma = dev->dma, |
264 | .port = dev->if_port, | 296 | .port = dev->if_port, |
265 | }; | 297 | }; |
266 | RTA_PUT(skb, IFLA_MAP, sizeof(map), &map); | 298 | NLA_PUT(skb, IFLA_MAP, sizeof(map), &map); |
267 | } | 299 | } |
268 | 300 | ||
269 | if (dev->addr_len) { | 301 | if (dev->addr_len) { |
270 | RTA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr); | 302 | NLA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr); |
271 | RTA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast); | 303 | NLA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast); |
272 | } | ||
273 | |||
274 | if (1) { | ||
275 | u32 mtu = dev->mtu; | ||
276 | RTA_PUT(skb, IFLA_MTU, sizeof(mtu), &mtu); | ||
277 | } | ||
278 | |||
279 | if (dev->ifindex != dev->iflink) { | ||
280 | u32 iflink = dev->iflink; | ||
281 | RTA_PUT(skb, IFLA_LINK, sizeof(iflink), &iflink); | ||
282 | } | ||
283 | |||
284 | if (dev->qdisc_sleeping) | ||
285 | RTA_PUT(skb, IFLA_QDISC, | ||
286 | strlen(dev->qdisc_sleeping->ops->id) + 1, | ||
287 | dev->qdisc_sleeping->ops->id); | ||
288 | |||
289 | if (dev->master) { | ||
290 | u32 master = dev->master->ifindex; | ||
291 | RTA_PUT(skb, IFLA_MASTER, sizeof(master), &master); | ||
292 | } | 304 | } |
293 | 305 | ||
294 | if (dev->get_stats) { | 306 | if (dev->get_stats) { |
295 | unsigned long *stats = (unsigned long*)dev->get_stats(dev); | 307 | struct net_device_stats *stats = dev->get_stats(dev); |
296 | if (stats) { | 308 | if (stats) { |
297 | struct rtattr *a; | 309 | struct nlattr *attr; |
298 | __u32 *s; | 310 | |
299 | int i; | 311 | attr = nla_reserve(skb, IFLA_STATS, |
300 | int n = sizeof(struct rtnl_link_stats)/4; | 312 | sizeof(struct rtnl_link_stats)); |
301 | 313 | if (attr == NULL) | |
302 | a = __RTA_PUT(skb, IFLA_STATS, n*4); | 314 | goto nla_put_failure; |
303 | s = RTA_DATA(a); | 315 | |
304 | for (i=0; i<n; i++) | 316 | copy_rtnl_link_stats(nla_data(attr), stats); |
305 | s[i] = stats[i]; | ||
306 | } | 317 | } |
307 | } | 318 | } |
308 | nlh->nlmsg_len = skb->tail - b; | ||
309 | return skb->len; | ||
310 | 319 | ||
311 | nlmsg_failure: | 320 | if (iwbuf) |
312 | rtattr_failure: | 321 | NLA_PUT(skb, IFLA_WIRELESS, iwbuflen, iwbuf); |
313 | skb_trim(skb, b - skb->data); | 322 | |
314 | return -1; | 323 | return nlmsg_end(skb, nlh); |
324 | |||
325 | nla_put_failure: | ||
326 | return nlmsg_cancel(skb, nlh); | ||
315 | } | 327 | } |
316 | 328 | ||
317 | static int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | 329 | static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) |
318 | { | 330 | { |
319 | int idx; | 331 | int idx; |
320 | int s_idx = cb->args[0]; | 332 | int s_idx = cb->args[0]; |
@@ -324,10 +336,9 @@ static int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *c | |||
324 | for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) { | 336 | for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) { |
325 | if (idx < s_idx) | 337 | if (idx < s_idx) |
326 | continue; | 338 | continue; |
327 | if (rtnetlink_fill_ifinfo(skb, dev, RTM_NEWLINK, | 339 | if (rtnl_fill_ifinfo(skb, dev, NULL, 0, RTM_NEWLINK, |
328 | NETLINK_CB(cb->skb).pid, | 340 | NETLINK_CB(cb->skb).pid, |
329 | cb->nlh->nlmsg_seq, 0, | 341 | cb->nlh->nlmsg_seq, 0, NLM_F_MULTI) <= 0) |
330 | NLM_F_MULTI) <= 0) | ||
331 | break; | 342 | break; |
332 | } | 343 | } |
333 | read_unlock(&dev_base_lock); | 344 | read_unlock(&dev_base_lock); |
@@ -515,84 +526,69 @@ errout: | |||
515 | return err; | 526 | return err; |
516 | } | 527 | } |
517 | 528 | ||
518 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | 529 | static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) |
519 | static int do_getlink(struct sk_buff *in_skb, struct nlmsghdr* in_nlh, void *arg) | ||
520 | { | 530 | { |
521 | struct ifinfomsg *ifm = NLMSG_DATA(in_nlh); | 531 | struct ifinfomsg *ifm; |
522 | struct rtattr **ida = arg; | 532 | struct nlattr *tb[IFLA_MAX+1]; |
523 | struct net_device *dev; | 533 | struct net_device *dev = NULL; |
524 | struct ifinfomsg *r; | 534 | struct sk_buff *nskb; |
525 | struct nlmsghdr *nlh; | 535 | char *iw_buf = NULL, *iw = NULL; |
526 | int err = -ENOBUFS; | ||
527 | struct sk_buff *skb; | ||
528 | unsigned char *b; | ||
529 | char *iw_buf = NULL; | ||
530 | int iw_buf_len = 0; | 536 | int iw_buf_len = 0; |
537 | int err, payload; | ||
531 | 538 | ||
532 | if (ifm->ifi_index >= 0) | 539 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); |
540 | if (err < 0) | ||
541 | goto errout; | ||
542 | |||
543 | ifm = nlmsg_data(nlh); | ||
544 | if (ifm->ifi_index >= 0) { | ||
533 | dev = dev_get_by_index(ifm->ifi_index); | 545 | dev = dev_get_by_index(ifm->ifi_index); |
534 | else | 546 | if (dev == NULL) |
547 | return -ENODEV; | ||
548 | } else | ||
535 | return -EINVAL; | 549 | return -EINVAL; |
536 | if (!dev) | ||
537 | return -ENODEV; | ||
538 | 550 | ||
539 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | ||
540 | if (ida[IFLA_WIRELESS - 1]) { | ||
541 | 551 | ||
552 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | ||
553 | if (tb[IFLA_WIRELESS]) { | ||
542 | /* Call Wireless Extensions. We need to know the size before | 554 | /* Call Wireless Extensions. We need to know the size before |
543 | * we can alloc. Various stuff checked in there... */ | 555 | * we can alloc. Various stuff checked in there... */ |
544 | err = wireless_rtnetlink_get(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len, &iw_buf, &iw_buf_len); | 556 | err = wireless_rtnetlink_get(dev, nla_data(tb[IFLA_WIRELESS]), |
545 | if (err) | 557 | nla_len(tb[IFLA_WIRELESS]), |
546 | goto out; | 558 | &iw_buf, &iw_buf_len); |
559 | if (err < 0) | ||
560 | goto errout; | ||
561 | |||
562 | iw += IW_EV_POINT_OFF; | ||
547 | } | 563 | } |
548 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | 564 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ |
549 | 565 | ||
550 | /* Create a skb big enough to include all the data. | 566 | payload = NLMSG_ALIGN(sizeof(struct ifinfomsg) + |
551 | * Some requests are way bigger than 4k... Jean II */ | 567 | nla_total_size(iw_buf_len)); |
552 | skb = alloc_skb((NLMSG_LENGTH(sizeof(*r))) + (RTA_SPACE(iw_buf_len)), | 568 | nskb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL); |
553 | GFP_KERNEL); | 569 | if (nskb == NULL) { |
554 | if (!skb) | 570 | err = -ENOBUFS; |
555 | goto out; | 571 | goto errout; |
556 | b = skb->tail; | 572 | } |
557 | 573 | ||
558 | /* Put in the message the usual good stuff */ | 574 | err = rtnl_fill_ifinfo(nskb, dev, iw, iw_buf_len, RTM_NEWLINK, |
559 | nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, in_nlh->nlmsg_seq, | 575 | NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, 0); |
560 | RTM_NEWLINK, sizeof(*r)); | 576 | if (err <= 0) { |
561 | r = NLMSG_DATA(nlh); | 577 | kfree_skb(skb); |
562 | r->ifi_family = AF_UNSPEC; | 578 | goto errout; |
563 | r->__ifi_pad = 0; | 579 | } |
564 | r->ifi_type = dev->type; | 580 | |
565 | r->ifi_index = dev->ifindex; | 581 | err = netlink_unicast(rtnl, skb, NETLINK_CB(skb).pid, MSG_DONTWAIT); |
566 | r->ifi_flags = dev->flags; | ||
567 | r->ifi_change = 0; | ||
568 | |||
569 | /* Put the wireless payload if it exist */ | ||
570 | if(iw_buf != NULL) | ||
571 | RTA_PUT(skb, IFLA_WIRELESS, iw_buf_len, | ||
572 | iw_buf + IW_EV_POINT_OFF); | ||
573 | |||
574 | nlh->nlmsg_len = skb->tail - b; | ||
575 | |||
576 | /* Needed ? */ | ||
577 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | ||
578 | |||
579 | err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); | ||
580 | if (err > 0) | 582 | if (err > 0) |
581 | err = 0; | 583 | err = 0; |
582 | out: | 584 | errout: |
583 | if(iw_buf != NULL) | 585 | kfree(iw_buf); |
584 | kfree(iw_buf); | ||
585 | dev_put(dev); | 586 | dev_put(dev); |
586 | return err; | ||
587 | 587 | ||
588 | rtattr_failure: | 588 | return err; |
589 | nlmsg_failure: | ||
590 | kfree_skb(skb); | ||
591 | goto out; | ||
592 | } | 589 | } |
593 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | ||
594 | 590 | ||
595 | static int rtnetlink_dump_all(struct sk_buff *skb, struct netlink_callback *cb) | 591 | static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) |
596 | { | 592 | { |
597 | int idx; | 593 | int idx; |
598 | int s_idx = cb->family; | 594 | int s_idx = cb->family; |
@@ -623,11 +619,11 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) | |||
623 | sizeof(struct rtnl_link_ifmap) + | 619 | sizeof(struct rtnl_link_ifmap) + |
624 | sizeof(struct rtnl_link_stats) + 128); | 620 | sizeof(struct rtnl_link_stats) + 128); |
625 | 621 | ||
626 | skb = alloc_skb(size, GFP_KERNEL); | 622 | skb = nlmsg_new(size, GFP_KERNEL); |
627 | if (!skb) | 623 | if (!skb) |
628 | return; | 624 | return; |
629 | 625 | ||
630 | if (rtnetlink_fill_ifinfo(skb, dev, type, 0, 0, change, 0) < 0) { | 626 | if (rtnl_fill_ifinfo(skb, dev, NULL, 0, type, 0, 0, change, 0) < 0) { |
631 | kfree_skb(skb); | 627 | kfree_skb(skb); |
632 | return; | 628 | return; |
633 | } | 629 | } |
@@ -757,14 +753,11 @@ static void rtnetlink_rcv(struct sock *sk, int len) | |||
757 | 753 | ||
758 | static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] = | 754 | static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] = |
759 | { | 755 | { |
760 | [RTM_GETLINK - RTM_BASE] = { | 756 | [RTM_GETLINK - RTM_BASE] = { .doit = rtnl_getlink, |
761 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | 757 | .dumpit = rtnl_dump_ifinfo }, |
762 | .doit = do_getlink, | ||
763 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | ||
764 | .dumpit = rtnetlink_dump_ifinfo }, | ||
765 | [RTM_SETLINK - RTM_BASE] = { .doit = rtnl_setlink }, | 758 | [RTM_SETLINK - RTM_BASE] = { .doit = rtnl_setlink }, |
766 | [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, | 759 | [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnl_dump_all }, |
767 | [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, | 760 | [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnl_dump_all }, |
768 | [RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add }, | 761 | [RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add }, |
769 | [RTM_DELNEIGH - RTM_BASE] = { .doit = neigh_delete }, | 762 | [RTM_DELNEIGH - RTM_BASE] = { .doit = neigh_delete }, |
770 | [RTM_GETNEIGH - RTM_BASE] = { .dumpit = neigh_dump_info }, | 763 | [RTM_GETNEIGH - RTM_BASE] = { .dumpit = neigh_dump_info }, |
@@ -772,7 +765,7 @@ static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] = | |||
772 | [RTM_NEWRULE - RTM_BASE] = { .doit = fib_nl_newrule }, | 765 | [RTM_NEWRULE - RTM_BASE] = { .doit = fib_nl_newrule }, |
773 | [RTM_DELRULE - RTM_BASE] = { .doit = fib_nl_delrule }, | 766 | [RTM_DELRULE - RTM_BASE] = { .doit = fib_nl_delrule }, |
774 | #endif | 767 | #endif |
775 | [RTM_GETRULE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, | 768 | [RTM_GETRULE - RTM_BASE] = { .dumpit = rtnl_dump_all }, |
776 | [RTM_GETNEIGHTBL - RTM_BASE] = { .dumpit = neightbl_dump_info }, | 769 | [RTM_GETNEIGHTBL - RTM_BASE] = { .dumpit = neightbl_dump_info }, |
777 | [RTM_SETNEIGHTBL - RTM_BASE] = { .doit = neightbl_set }, | 770 | [RTM_SETNEIGHTBL - RTM_BASE] = { .doit = neightbl_set }, |
778 | }; | 771 | }; |