aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
Diffstat (limited to 'net/core')
-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)