aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2005-06-19 01:50:55 -0400
committerDavid S. Miller <davem@davemloft.net>2005-06-19 01:50:55 -0400
commitc7fb64db001f83ece669c76a02d8ec2fdb1dd307 (patch)
treef8b8375b8b619c00db3399a4ef6f67e2636dfac7 /net
parent00768244923f66801958a8d2d103f7b65608c9b6 (diff)
[NETLINK]: Neighbour table configuration and statistics via rtnetlink
To retrieve the neighbour tables send RTM_GETNEIGHTBL with the NLM_F_DUMP flag set. Every neighbour table configuration is spread over multiple messages to avoid running into message size limits on systems with many interfaces. The first message in the sequence transports all not device specific data such as statistics, configuration, and the default parameter set. This message is followed by 0..n messages carrying device specific parameter sets. Although the ordering should be sufficient, NDTA_NAME can be used to identify sequences. The initial message can be identified by checking for NDTA_CONFIG. The device specific messages do not contain this TLV but have NDTPA_IFINDEX set to the corresponding interface index. To change neighbour table attributes, send RTM_SETNEIGHTBL with NDTA_NAME set. Changeable attribute include NDTA_THRESH[1-3], NDTA_GC_INTERVAL, and all TLVs in NDTA_PARMS unless marked otherwise. Device specific parameter sets can be changed by setting NDTPA_IFINDEX to the interface index of the corresponding device. 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/neighbour.c317
-rw-r--r--net/core/rtnetlink.c20
2 files changed, 326 insertions, 11 deletions
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 43bdc521e20d..0841ac78c67d 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1276,9 +1276,14 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
1276 INIT_RCU_HEAD(&p->rcu_head); 1276 INIT_RCU_HEAD(&p->rcu_head);
1277 p->reachable_time = 1277 p->reachable_time =
1278 neigh_rand_reach_time(p->base_reachable_time); 1278 neigh_rand_reach_time(p->base_reachable_time);
1279 if (dev && dev->neigh_setup && dev->neigh_setup(dev, p)) { 1279 if (dev) {
1280 kfree(p); 1280 if (dev->neigh_setup && dev->neigh_setup(dev, p)) {
1281 return NULL; 1281 kfree(p);
1282 return NULL;
1283 }
1284
1285 dev_hold(dev);
1286 p->dev = dev;
1282 } 1287 }
1283 p->sysctl_table = NULL; 1288 p->sysctl_table = NULL;
1284 write_lock_bh(&tbl->lock); 1289 write_lock_bh(&tbl->lock);
@@ -1309,6 +1314,8 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
1309 *p = parms->next; 1314 *p = parms->next;
1310 parms->dead = 1; 1315 parms->dead = 1;
1311 write_unlock_bh(&tbl->lock); 1316 write_unlock_bh(&tbl->lock);
1317 if (parms->dev)
1318 dev_put(parms->dev);
1312 call_rcu(&parms->rcu_head, neigh_rcu_free_parms); 1319 call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
1313 return; 1320 return;
1314 } 1321 }
@@ -1546,6 +1553,308 @@ out:
1546 return err; 1553 return err;
1547} 1554}
1548 1555
1556static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
1557{
1558 struct rtattr *nest = RTA_NEST(skb, NDTA_PARMS);
1559
1560 if (parms->dev)
1561 RTA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex);
1562
1563 RTA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt));
1564 RTA_PUT_U32(skb, NDTPA_QUEUE_LEN, parms->queue_len);
1565 RTA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen);
1566 RTA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes);
1567 RTA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes);
1568 RTA_PUT_U32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes);
1569 RTA_PUT_MSECS(skb, NDTPA_REACHABLE_TIME, parms->reachable_time);
1570 RTA_PUT_MSECS(skb, NDTPA_BASE_REACHABLE_TIME,
1571 parms->base_reachable_time);
1572 RTA_PUT_MSECS(skb, NDTPA_GC_STALETIME, parms->gc_staletime);
1573 RTA_PUT_MSECS(skb, NDTPA_DELAY_PROBE_TIME, parms->delay_probe_time);
1574 RTA_PUT_MSECS(skb, NDTPA_RETRANS_TIME, parms->retrans_time);
1575 RTA_PUT_MSECS(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay);
1576 RTA_PUT_MSECS(skb, NDTPA_PROXY_DELAY, parms->proxy_delay);
1577 RTA_PUT_MSECS(skb, NDTPA_LOCKTIME, parms->locktime);
1578
1579 return RTA_NEST_END(skb, nest);
1580
1581rtattr_failure:
1582 return RTA_NEST_CANCEL(skb, nest);
1583}
1584
1585static int neightbl_fill_info(struct neigh_table *tbl, struct sk_buff *skb,
1586 struct netlink_callback *cb)
1587{
1588 struct nlmsghdr *nlh;
1589 struct ndtmsg *ndtmsg;
1590
1591 nlh = NLMSG_PUT_ANSWER(skb, cb, RTM_NEWNEIGHTBL, sizeof(struct ndtmsg));
1592 ndtmsg = NLMSG_DATA(nlh);
1593
1594 NLMSG_SET_MULTIPART(nlh);
1595
1596 read_lock_bh(&tbl->lock);
1597 ndtmsg->ndtm_family = tbl->family;
1598
1599 RTA_PUT_STRING(skb, NDTA_NAME, tbl->id);
1600 RTA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval);
1601 RTA_PUT_U32(skb, NDTA_THRESH1, tbl->gc_thresh1);
1602 RTA_PUT_U32(skb, NDTA_THRESH2, tbl->gc_thresh2);
1603 RTA_PUT_U32(skb, NDTA_THRESH3, tbl->gc_thresh3);
1604
1605 {
1606 unsigned long now = jiffies;
1607 unsigned int flush_delta = now - tbl->last_flush;
1608 unsigned int rand_delta = now - tbl->last_rand;
1609
1610 struct ndt_config ndc = {
1611 .ndtc_key_len = tbl->key_len,
1612 .ndtc_entry_size = tbl->entry_size,
1613 .ndtc_entries = atomic_read(&tbl->entries),
1614 .ndtc_last_flush = jiffies_to_msecs(flush_delta),
1615 .ndtc_last_rand = jiffies_to_msecs(rand_delta),
1616 .ndtc_hash_rnd = tbl->hash_rnd,
1617 .ndtc_hash_mask = tbl->hash_mask,
1618 .ndtc_hash_chain_gc = tbl->hash_chain_gc,
1619 .ndtc_proxy_qlen = tbl->proxy_queue.qlen,
1620 };
1621
1622 RTA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc);
1623 }
1624
1625 {
1626 int cpu;
1627 struct ndt_stats ndst;
1628
1629 memset(&ndst, 0, sizeof(ndst));
1630
1631 for (cpu = 0; cpu < NR_CPUS; cpu++) {
1632 struct neigh_statistics *st;
1633
1634 if (!cpu_possible(cpu))
1635 continue;
1636
1637 st = per_cpu_ptr(tbl->stats, cpu);
1638 ndst.ndts_allocs += st->allocs;
1639 ndst.ndts_destroys += st->destroys;
1640 ndst.ndts_hash_grows += st->hash_grows;
1641 ndst.ndts_res_failed += st->res_failed;
1642 ndst.ndts_lookups += st->lookups;
1643 ndst.ndts_hits += st->hits;
1644 ndst.ndts_rcv_probes_mcast += st->rcv_probes_mcast;
1645 ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast;
1646 ndst.ndts_periodic_gc_runs += st->periodic_gc_runs;
1647 ndst.ndts_forced_gc_runs += st->forced_gc_runs;
1648 }
1649
1650 RTA_PUT(skb, NDTA_STATS, sizeof(ndst), &ndst);
1651 }
1652
1653 BUG_ON(tbl->parms.dev);
1654 if (neightbl_fill_parms(skb, &tbl->parms) < 0)
1655 goto rtattr_failure;
1656
1657 read_unlock_bh(&tbl->lock);
1658 return NLMSG_END(skb, nlh);
1659
1660rtattr_failure:
1661 read_unlock_bh(&tbl->lock);
1662 return NLMSG_CANCEL(skb, nlh);
1663
1664nlmsg_failure:
1665 return -1;
1666}
1667
1668static int neightbl_fill_param_info(struct neigh_table *tbl,
1669 struct neigh_parms *parms,
1670 struct sk_buff *skb,
1671 struct netlink_callback *cb)
1672{
1673 struct ndtmsg *ndtmsg;
1674 struct nlmsghdr *nlh;
1675
1676 nlh = NLMSG_PUT_ANSWER(skb, cb, RTM_NEWNEIGHTBL, sizeof(struct ndtmsg));
1677 ndtmsg = NLMSG_DATA(nlh);
1678
1679 NLMSG_SET_MULTIPART(nlh);
1680
1681 read_lock_bh(&tbl->lock);
1682 ndtmsg->ndtm_family = tbl->family;
1683 RTA_PUT_STRING(skb, NDTA_NAME, tbl->id);
1684
1685 if (neightbl_fill_parms(skb, parms) < 0)
1686 goto rtattr_failure;
1687
1688 read_unlock_bh(&tbl->lock);
1689 return NLMSG_END(skb, nlh);
1690
1691rtattr_failure:
1692 read_unlock_bh(&tbl->lock);
1693 return NLMSG_CANCEL(skb, nlh);
1694
1695nlmsg_failure:
1696 return -1;
1697}
1698
1699static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl,
1700 int ifindex)
1701{
1702 struct neigh_parms *p;
1703
1704 for (p = &tbl->parms; p; p = p->next)
1705 if ((p->dev && p->dev->ifindex == ifindex) ||
1706 (!p->dev && !ifindex))
1707 return p;
1708
1709 return NULL;
1710}
1711
1712int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
1713{
1714 struct neigh_table *tbl;
1715 struct ndtmsg *ndtmsg = NLMSG_DATA(nlh);
1716 struct rtattr **tb = arg;
1717 int err = -EINVAL;
1718
1719 if (!tb[NDTA_NAME - 1] || !RTA_PAYLOAD(tb[NDTA_NAME - 1]))
1720 return -EINVAL;
1721
1722 read_lock(&neigh_tbl_lock);
1723 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
1724 if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
1725 continue;
1726
1727 if (!rtattr_strcmp(tb[NDTA_NAME - 1], tbl->id))
1728 break;
1729 }
1730
1731 if (tbl == NULL) {
1732 err = -ENOENT;
1733 goto errout;
1734 }
1735
1736 /*
1737 * We acquire tbl->lock to be nice to the periodic timers and
1738 * make sure they always see a consistent set of values.
1739 */
1740 write_lock_bh(&tbl->lock);
1741
1742 if (tb[NDTA_THRESH1 - 1])
1743 tbl->gc_thresh1 = RTA_GET_U32(tb[NDTA_THRESH1 - 1]);
1744
1745 if (tb[NDTA_THRESH2 - 1])
1746 tbl->gc_thresh2 = RTA_GET_U32(tb[NDTA_THRESH2 - 1]);
1747
1748 if (tb[NDTA_THRESH3 - 1])
1749 tbl->gc_thresh3 = RTA_GET_U32(tb[NDTA_THRESH3 - 1]);
1750
1751 if (tb[NDTA_GC_INTERVAL - 1])
1752 tbl->gc_interval = RTA_GET_MSECS(tb[NDTA_GC_INTERVAL - 1]);
1753
1754 if (tb[NDTA_PARMS - 1]) {
1755 struct rtattr *tbp[NDTPA_MAX];
1756 struct neigh_parms *p;
1757 u32 ifindex = 0;
1758
1759 if (rtattr_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS - 1]) < 0)
1760 goto rtattr_failure;
1761
1762 if (tbp[NDTPA_IFINDEX - 1])
1763 ifindex = RTA_GET_U32(tbp[NDTPA_IFINDEX - 1]);
1764
1765 p = lookup_neigh_params(tbl, ifindex);
1766 if (p == NULL) {
1767 err = -ENOENT;
1768 goto rtattr_failure;
1769 }
1770
1771 if (tbp[NDTPA_QUEUE_LEN - 1])
1772 p->queue_len = RTA_GET_U32(tbp[NDTPA_QUEUE_LEN - 1]);
1773
1774 if (tbp[NDTPA_PROXY_QLEN - 1])
1775 p->proxy_qlen = RTA_GET_U32(tbp[NDTPA_PROXY_QLEN - 1]);
1776
1777 if (tbp[NDTPA_APP_PROBES - 1])
1778 p->app_probes = RTA_GET_U32(tbp[NDTPA_APP_PROBES - 1]);
1779
1780 if (tbp[NDTPA_UCAST_PROBES - 1])
1781 p->ucast_probes =
1782 RTA_GET_U32(tbp[NDTPA_UCAST_PROBES - 1]);
1783
1784 if (tbp[NDTPA_MCAST_PROBES - 1])
1785 p->mcast_probes =
1786 RTA_GET_U32(tbp[NDTPA_MCAST_PROBES - 1]);
1787
1788 if (tbp[NDTPA_BASE_REACHABLE_TIME - 1])
1789 p->base_reachable_time =
1790 RTA_GET_MSECS(tbp[NDTPA_BASE_REACHABLE_TIME - 1]);
1791
1792 if (tbp[NDTPA_GC_STALETIME - 1])
1793 p->gc_staletime =
1794 RTA_GET_MSECS(tbp[NDTPA_GC_STALETIME - 1]);
1795
1796 if (tbp[NDTPA_DELAY_PROBE_TIME - 1])
1797 p->delay_probe_time =
1798 RTA_GET_MSECS(tbp[NDTPA_DELAY_PROBE_TIME - 1]);
1799
1800 if (tbp[NDTPA_RETRANS_TIME - 1])
1801 p->retrans_time =
1802 RTA_GET_MSECS(tbp[NDTPA_RETRANS_TIME - 1]);
1803
1804 if (tbp[NDTPA_ANYCAST_DELAY - 1])
1805 p->anycast_delay =
1806 RTA_GET_MSECS(tbp[NDTPA_ANYCAST_DELAY - 1]);
1807
1808 if (tbp[NDTPA_PROXY_DELAY - 1])
1809 p->proxy_delay =
1810 RTA_GET_MSECS(tbp[NDTPA_PROXY_DELAY - 1]);
1811
1812 if (tbp[NDTPA_LOCKTIME - 1])
1813 p->locktime = RTA_GET_MSECS(tbp[NDTPA_LOCKTIME - 1]);
1814 }
1815
1816 err = 0;
1817
1818rtattr_failure:
1819 write_unlock_bh(&tbl->lock);
1820errout:
1821 read_unlock(&neigh_tbl_lock);
1822 return err;
1823}
1824
1825int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
1826{
1827 int idx, family;
1828 int s_idx = cb->args[0];
1829 struct neigh_table *tbl;
1830
1831 family = ((struct rtgenmsg *)NLMSG_DATA(cb->nlh))->rtgen_family;
1832
1833 read_lock(&neigh_tbl_lock);
1834 for (tbl = neigh_tables, idx = 0; tbl; tbl = tbl->next) {
1835 struct neigh_parms *p;
1836
1837 if (idx < s_idx || (family && tbl->family != family))
1838 continue;
1839
1840 if (neightbl_fill_info(tbl, skb, cb) <= 0)
1841 break;
1842
1843 for (++idx, p = tbl->parms.next; p; p = p->next, idx++) {
1844 if (idx < s_idx)
1845 continue;
1846
1847 if (neightbl_fill_param_info(tbl, p, skb, cb) <= 0)
1848 goto out;
1849 }
1850
1851 }
1852out:
1853 read_unlock(&neigh_tbl_lock);
1854 cb->args[0] = idx;
1855
1856 return skb->len;
1857}
1549 1858
1550static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n, 1859static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n,
1551 u32 pid, u32 seq, int event) 1860 u32 pid, u32 seq, int event)
@@ -2352,6 +2661,8 @@ EXPORT_SYMBOL(neigh_update);
2352EXPORT_SYMBOL(neigh_update_hhs); 2661EXPORT_SYMBOL(neigh_update_hhs);
2353EXPORT_SYMBOL(pneigh_enqueue); 2662EXPORT_SYMBOL(pneigh_enqueue);
2354EXPORT_SYMBOL(pneigh_lookup); 2663EXPORT_SYMBOL(pneigh_lookup);
2664EXPORT_SYMBOL(neightbl_dump_info);
2665EXPORT_SYMBOL(neightbl_set);
2355 2666
2356#ifdef CONFIG_ARPD 2667#ifdef CONFIG_ARPD
2357EXPORT_SYMBOL(neigh_app_ns); 2668EXPORT_SYMBOL(neigh_app_ns);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 00caf4b318b2..56a20f014b8a 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -100,6 +100,7 @@ static const int rtm_min[RTM_NR_FAMILIES] =
100 [RTM_FAM(RTM_NEWPREFIX)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), 100 [RTM_FAM(RTM_NEWPREFIX)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
101 [RTM_FAM(RTM_GETMULTICAST)] = 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)), 102 [RTM_FAM(RTM_GETANYCAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
103 [RTM_FAM(RTM_NEWNEIGHTBL)] = NLMSG_LENGTH(sizeof(struct ndtmsg)),
103}; 104};
104 105
105static const int rta_max[RTM_NR_FAMILIES] = 106static const int rta_max[RTM_NR_FAMILIES] =
@@ -113,6 +114,7 @@ static const int rta_max[RTM_NR_FAMILIES] =
113 [RTM_FAM(RTM_NEWTCLASS)] = TCA_MAX, 114 [RTM_FAM(RTM_NEWTCLASS)] = TCA_MAX,
114 [RTM_FAM(RTM_NEWTFILTER)] = TCA_MAX, 115 [RTM_FAM(RTM_NEWTFILTER)] = TCA_MAX,
115 [RTM_FAM(RTM_NEWACTION)] = TCAA_MAX, 116 [RTM_FAM(RTM_NEWACTION)] = TCAA_MAX,
117 [RTM_FAM(RTM_NEWNEIGHTBL)] = NDTA_MAX,
116}; 118};
117 119
118void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data) 120void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
@@ -649,14 +651,16 @@ static void rtnetlink_rcv(struct sock *sk, int len)
649 651
650static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] = 652static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] =
651{ 653{
652 [RTM_GETLINK - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo }, 654 [RTM_GETLINK - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo },
653 [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink }, 655 [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink },
654 [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, 656 [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
655 [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, 657 [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
656 [RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add }, 658 [RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add },
657 [RTM_DELNEIGH - RTM_BASE] = { .doit = neigh_delete }, 659 [RTM_DELNEIGH - RTM_BASE] = { .doit = neigh_delete },
658 [RTM_GETNEIGH - RTM_BASE] = { .dumpit = neigh_dump_info }, 660 [RTM_GETNEIGH - RTM_BASE] = { .dumpit = neigh_dump_info },
659 [RTM_GETRULE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, 661 [RTM_GETRULE - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
662 [RTM_GETNEIGHTBL - RTM_BASE] = { .dumpit = neightbl_dump_info },
663 [RTM_SETNEIGHTBL - RTM_BASE] = { .doit = neightbl_set },
660}; 664};
661 665
662static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr) 666static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr)