diff options
Diffstat (limited to 'net/core/neighbour.c')
-rw-r--r-- | net/core/neighbour.c | 333 |
1 files changed, 323 insertions, 10 deletions
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 43bdc521e20d..f6bdcad47da6 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,20 +1553,323 @@ out: | |||
1546 | return err; | 1553 | return err; |
1547 | } | 1554 | } |
1548 | 1555 | ||
1556 | static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms) | ||
1557 | { | ||
1558 | struct rtattr *nest = NULL; | ||
1559 | |||
1560 | nest = RTA_NEST(skb, NDTA_PARMS); | ||
1561 | |||
1562 | if (parms->dev) | ||
1563 | RTA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex); | ||
1564 | |||
1565 | RTA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)); | ||
1566 | RTA_PUT_U32(skb, NDTPA_QUEUE_LEN, parms->queue_len); | ||
1567 | RTA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen); | ||
1568 | RTA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes); | ||
1569 | RTA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes); | ||
1570 | RTA_PUT_U32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes); | ||
1571 | RTA_PUT_MSECS(skb, NDTPA_REACHABLE_TIME, parms->reachable_time); | ||
1572 | RTA_PUT_MSECS(skb, NDTPA_BASE_REACHABLE_TIME, | ||
1573 | parms->base_reachable_time); | ||
1574 | RTA_PUT_MSECS(skb, NDTPA_GC_STALETIME, parms->gc_staletime); | ||
1575 | RTA_PUT_MSECS(skb, NDTPA_DELAY_PROBE_TIME, parms->delay_probe_time); | ||
1576 | RTA_PUT_MSECS(skb, NDTPA_RETRANS_TIME, parms->retrans_time); | ||
1577 | RTA_PUT_MSECS(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay); | ||
1578 | RTA_PUT_MSECS(skb, NDTPA_PROXY_DELAY, parms->proxy_delay); | ||
1579 | RTA_PUT_MSECS(skb, NDTPA_LOCKTIME, parms->locktime); | ||
1580 | |||
1581 | return RTA_NEST_END(skb, nest); | ||
1582 | |||
1583 | rtattr_failure: | ||
1584 | return RTA_NEST_CANCEL(skb, nest); | ||
1585 | } | ||
1586 | |||
1587 | static int neightbl_fill_info(struct neigh_table *tbl, struct sk_buff *skb, | ||
1588 | struct netlink_callback *cb) | ||
1589 | { | ||
1590 | struct nlmsghdr *nlh; | ||
1591 | struct ndtmsg *ndtmsg; | ||
1592 | |||
1593 | nlh = NLMSG_NEW_ANSWER(skb, cb, RTM_NEWNEIGHTBL, sizeof(struct ndtmsg), | ||
1594 | NLM_F_MULTI); | ||
1595 | |||
1596 | ndtmsg = NLMSG_DATA(nlh); | ||
1597 | |||
1598 | read_lock_bh(&tbl->lock); | ||
1599 | ndtmsg->ndtm_family = tbl->family; | ||
1600 | |||
1601 | RTA_PUT_STRING(skb, NDTA_NAME, tbl->id); | ||
1602 | RTA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval); | ||
1603 | RTA_PUT_U32(skb, NDTA_THRESH1, tbl->gc_thresh1); | ||
1604 | RTA_PUT_U32(skb, NDTA_THRESH2, tbl->gc_thresh2); | ||
1605 | RTA_PUT_U32(skb, NDTA_THRESH3, tbl->gc_thresh3); | ||
1606 | |||
1607 | { | ||
1608 | unsigned long now = jiffies; | ||
1609 | unsigned int flush_delta = now - tbl->last_flush; | ||
1610 | unsigned int rand_delta = now - tbl->last_rand; | ||
1611 | |||
1612 | struct ndt_config ndc = { | ||
1613 | .ndtc_key_len = tbl->key_len, | ||
1614 | .ndtc_entry_size = tbl->entry_size, | ||
1615 | .ndtc_entries = atomic_read(&tbl->entries), | ||
1616 | .ndtc_last_flush = jiffies_to_msecs(flush_delta), | ||
1617 | .ndtc_last_rand = jiffies_to_msecs(rand_delta), | ||
1618 | .ndtc_hash_rnd = tbl->hash_rnd, | ||
1619 | .ndtc_hash_mask = tbl->hash_mask, | ||
1620 | .ndtc_hash_chain_gc = tbl->hash_chain_gc, | ||
1621 | .ndtc_proxy_qlen = tbl->proxy_queue.qlen, | ||
1622 | }; | ||
1623 | |||
1624 | RTA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc); | ||
1625 | } | ||
1626 | |||
1627 | { | ||
1628 | int cpu; | ||
1629 | struct ndt_stats ndst; | ||
1630 | |||
1631 | memset(&ndst, 0, sizeof(ndst)); | ||
1632 | |||
1633 | for (cpu = 0; cpu < NR_CPUS; cpu++) { | ||
1634 | struct neigh_statistics *st; | ||
1635 | |||
1636 | if (!cpu_possible(cpu)) | ||
1637 | continue; | ||
1638 | |||
1639 | st = per_cpu_ptr(tbl->stats, cpu); | ||
1640 | ndst.ndts_allocs += st->allocs; | ||
1641 | ndst.ndts_destroys += st->destroys; | ||
1642 | ndst.ndts_hash_grows += st->hash_grows; | ||
1643 | ndst.ndts_res_failed += st->res_failed; | ||
1644 | ndst.ndts_lookups += st->lookups; | ||
1645 | ndst.ndts_hits += st->hits; | ||
1646 | ndst.ndts_rcv_probes_mcast += st->rcv_probes_mcast; | ||
1647 | ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast; | ||
1648 | ndst.ndts_periodic_gc_runs += st->periodic_gc_runs; | ||
1649 | ndst.ndts_forced_gc_runs += st->forced_gc_runs; | ||
1650 | } | ||
1651 | |||
1652 | RTA_PUT(skb, NDTA_STATS, sizeof(ndst), &ndst); | ||
1653 | } | ||
1654 | |||
1655 | BUG_ON(tbl->parms.dev); | ||
1656 | if (neightbl_fill_parms(skb, &tbl->parms) < 0) | ||
1657 | goto rtattr_failure; | ||
1658 | |||
1659 | read_unlock_bh(&tbl->lock); | ||
1660 | return NLMSG_END(skb, nlh); | ||
1661 | |||
1662 | rtattr_failure: | ||
1663 | read_unlock_bh(&tbl->lock); | ||
1664 | return NLMSG_CANCEL(skb, nlh); | ||
1665 | |||
1666 | nlmsg_failure: | ||
1667 | return -1; | ||
1668 | } | ||
1669 | |||
1670 | static int neightbl_fill_param_info(struct neigh_table *tbl, | ||
1671 | struct neigh_parms *parms, | ||
1672 | struct sk_buff *skb, | ||
1673 | struct netlink_callback *cb) | ||
1674 | { | ||
1675 | struct ndtmsg *ndtmsg; | ||
1676 | struct nlmsghdr *nlh; | ||
1677 | |||
1678 | nlh = NLMSG_NEW_ANSWER(skb, cb, RTM_NEWNEIGHTBL, sizeof(struct ndtmsg), | ||
1679 | NLM_F_MULTI); | ||
1680 | |||
1681 | ndtmsg = NLMSG_DATA(nlh); | ||
1682 | |||
1683 | read_lock_bh(&tbl->lock); | ||
1684 | ndtmsg->ndtm_family = tbl->family; | ||
1685 | RTA_PUT_STRING(skb, NDTA_NAME, tbl->id); | ||
1686 | |||
1687 | if (neightbl_fill_parms(skb, parms) < 0) | ||
1688 | goto rtattr_failure; | ||
1689 | |||
1690 | read_unlock_bh(&tbl->lock); | ||
1691 | return NLMSG_END(skb, nlh); | ||
1692 | |||
1693 | rtattr_failure: | ||
1694 | read_unlock_bh(&tbl->lock); | ||
1695 | return NLMSG_CANCEL(skb, nlh); | ||
1696 | |||
1697 | nlmsg_failure: | ||
1698 | return -1; | ||
1699 | } | ||
1700 | |||
1701 | static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl, | ||
1702 | int ifindex) | ||
1703 | { | ||
1704 | struct neigh_parms *p; | ||
1705 | |||
1706 | for (p = &tbl->parms; p; p = p->next) | ||
1707 | if ((p->dev && p->dev->ifindex == ifindex) || | ||
1708 | (!p->dev && !ifindex)) | ||
1709 | return p; | ||
1710 | |||
1711 | return NULL; | ||
1712 | } | ||
1713 | |||
1714 | int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | ||
1715 | { | ||
1716 | struct neigh_table *tbl; | ||
1717 | struct ndtmsg *ndtmsg = NLMSG_DATA(nlh); | ||
1718 | struct rtattr **tb = arg; | ||
1719 | int err = -EINVAL; | ||
1720 | |||
1721 | if (!tb[NDTA_NAME - 1] || !RTA_PAYLOAD(tb[NDTA_NAME - 1])) | ||
1722 | return -EINVAL; | ||
1723 | |||
1724 | read_lock(&neigh_tbl_lock); | ||
1725 | for (tbl = neigh_tables; tbl; tbl = tbl->next) { | ||
1726 | if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family) | ||
1727 | continue; | ||
1728 | |||
1729 | if (!rtattr_strcmp(tb[NDTA_NAME - 1], tbl->id)) | ||
1730 | break; | ||
1731 | } | ||
1732 | |||
1733 | if (tbl == NULL) { | ||
1734 | err = -ENOENT; | ||
1735 | goto errout; | ||
1736 | } | ||
1737 | |||
1738 | /* | ||
1739 | * We acquire tbl->lock to be nice to the periodic timers and | ||
1740 | * make sure they always see a consistent set of values. | ||
1741 | */ | ||
1742 | write_lock_bh(&tbl->lock); | ||
1743 | |||
1744 | if (tb[NDTA_THRESH1 - 1]) | ||
1745 | tbl->gc_thresh1 = RTA_GET_U32(tb[NDTA_THRESH1 - 1]); | ||
1746 | |||
1747 | if (tb[NDTA_THRESH2 - 1]) | ||
1748 | tbl->gc_thresh2 = RTA_GET_U32(tb[NDTA_THRESH2 - 1]); | ||
1749 | |||
1750 | if (tb[NDTA_THRESH3 - 1]) | ||
1751 | tbl->gc_thresh3 = RTA_GET_U32(tb[NDTA_THRESH3 - 1]); | ||
1752 | |||
1753 | if (tb[NDTA_GC_INTERVAL - 1]) | ||
1754 | tbl->gc_interval = RTA_GET_MSECS(tb[NDTA_GC_INTERVAL - 1]); | ||
1755 | |||
1756 | if (tb[NDTA_PARMS - 1]) { | ||
1757 | struct rtattr *tbp[NDTPA_MAX]; | ||
1758 | struct neigh_parms *p; | ||
1759 | u32 ifindex = 0; | ||
1760 | |||
1761 | if (rtattr_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS - 1]) < 0) | ||
1762 | goto rtattr_failure; | ||
1763 | |||
1764 | if (tbp[NDTPA_IFINDEX - 1]) | ||
1765 | ifindex = RTA_GET_U32(tbp[NDTPA_IFINDEX - 1]); | ||
1766 | |||
1767 | p = lookup_neigh_params(tbl, ifindex); | ||
1768 | if (p == NULL) { | ||
1769 | err = -ENOENT; | ||
1770 | goto rtattr_failure; | ||
1771 | } | ||
1772 | |||
1773 | if (tbp[NDTPA_QUEUE_LEN - 1]) | ||
1774 | p->queue_len = RTA_GET_U32(tbp[NDTPA_QUEUE_LEN - 1]); | ||
1775 | |||
1776 | if (tbp[NDTPA_PROXY_QLEN - 1]) | ||
1777 | p->proxy_qlen = RTA_GET_U32(tbp[NDTPA_PROXY_QLEN - 1]); | ||
1778 | |||
1779 | if (tbp[NDTPA_APP_PROBES - 1]) | ||
1780 | p->app_probes = RTA_GET_U32(tbp[NDTPA_APP_PROBES - 1]); | ||
1781 | |||
1782 | if (tbp[NDTPA_UCAST_PROBES - 1]) | ||
1783 | p->ucast_probes = | ||
1784 | RTA_GET_U32(tbp[NDTPA_UCAST_PROBES - 1]); | ||
1785 | |||
1786 | if (tbp[NDTPA_MCAST_PROBES - 1]) | ||
1787 | p->mcast_probes = | ||
1788 | RTA_GET_U32(tbp[NDTPA_MCAST_PROBES - 1]); | ||
1789 | |||
1790 | if (tbp[NDTPA_BASE_REACHABLE_TIME - 1]) | ||
1791 | p->base_reachable_time = | ||
1792 | RTA_GET_MSECS(tbp[NDTPA_BASE_REACHABLE_TIME - 1]); | ||
1793 | |||
1794 | if (tbp[NDTPA_GC_STALETIME - 1]) | ||
1795 | p->gc_staletime = | ||
1796 | RTA_GET_MSECS(tbp[NDTPA_GC_STALETIME - 1]); | ||
1797 | |||
1798 | if (tbp[NDTPA_DELAY_PROBE_TIME - 1]) | ||
1799 | p->delay_probe_time = | ||
1800 | RTA_GET_MSECS(tbp[NDTPA_DELAY_PROBE_TIME - 1]); | ||
1801 | |||
1802 | if (tbp[NDTPA_RETRANS_TIME - 1]) | ||
1803 | p->retrans_time = | ||
1804 | RTA_GET_MSECS(tbp[NDTPA_RETRANS_TIME - 1]); | ||
1805 | |||
1806 | if (tbp[NDTPA_ANYCAST_DELAY - 1]) | ||
1807 | p->anycast_delay = | ||
1808 | RTA_GET_MSECS(tbp[NDTPA_ANYCAST_DELAY - 1]); | ||
1809 | |||
1810 | if (tbp[NDTPA_PROXY_DELAY - 1]) | ||
1811 | p->proxy_delay = | ||
1812 | RTA_GET_MSECS(tbp[NDTPA_PROXY_DELAY - 1]); | ||
1813 | |||
1814 | if (tbp[NDTPA_LOCKTIME - 1]) | ||
1815 | p->locktime = RTA_GET_MSECS(tbp[NDTPA_LOCKTIME - 1]); | ||
1816 | } | ||
1817 | |||
1818 | err = 0; | ||
1819 | |||
1820 | rtattr_failure: | ||
1821 | write_unlock_bh(&tbl->lock); | ||
1822 | errout: | ||
1823 | read_unlock(&neigh_tbl_lock); | ||
1824 | return err; | ||
1825 | } | ||
1826 | |||
1827 | int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) | ||
1828 | { | ||
1829 | int idx, family; | ||
1830 | int s_idx = cb->args[0]; | ||
1831 | struct neigh_table *tbl; | ||
1832 | |||
1833 | family = ((struct rtgenmsg *)NLMSG_DATA(cb->nlh))->rtgen_family; | ||
1834 | |||
1835 | read_lock(&neigh_tbl_lock); | ||
1836 | for (tbl = neigh_tables, idx = 0; tbl; tbl = tbl->next) { | ||
1837 | struct neigh_parms *p; | ||
1838 | |||
1839 | if (idx < s_idx || (family && tbl->family != family)) | ||
1840 | continue; | ||
1841 | |||
1842 | if (neightbl_fill_info(tbl, skb, cb) <= 0) | ||
1843 | break; | ||
1844 | |||
1845 | for (++idx, p = tbl->parms.next; p; p = p->next, idx++) { | ||
1846 | if (idx < s_idx) | ||
1847 | continue; | ||
1848 | |||
1849 | if (neightbl_fill_param_info(tbl, p, skb, cb) <= 0) | ||
1850 | goto out; | ||
1851 | } | ||
1852 | |||
1853 | } | ||
1854 | out: | ||
1855 | read_unlock(&neigh_tbl_lock); | ||
1856 | cb->args[0] = idx; | ||
1857 | |||
1858 | return skb->len; | ||
1859 | } | ||
1549 | 1860 | ||
1550 | static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n, | 1861 | static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n, |
1551 | u32 pid, u32 seq, int event) | 1862 | u32 pid, u32 seq, int event, unsigned int flags) |
1552 | { | 1863 | { |
1553 | unsigned long now = jiffies; | 1864 | unsigned long now = jiffies; |
1554 | unsigned char *b = skb->tail; | 1865 | unsigned char *b = skb->tail; |
1555 | struct nda_cacheinfo ci; | 1866 | struct nda_cacheinfo ci; |
1556 | int locked = 0; | 1867 | int locked = 0; |
1557 | u32 probes; | 1868 | u32 probes; |
1558 | struct nlmsghdr *nlh = NLMSG_PUT(skb, pid, seq, event, | 1869 | struct nlmsghdr *nlh = NLMSG_NEW(skb, pid, seq, event, |
1559 | sizeof(struct ndmsg)); | 1870 | sizeof(struct ndmsg), flags); |
1560 | struct ndmsg *ndm = NLMSG_DATA(nlh); | 1871 | struct ndmsg *ndm = NLMSG_DATA(nlh); |
1561 | 1872 | ||
1562 | nlh->nlmsg_flags = pid ? NLM_F_MULTI : 0; | ||
1563 | ndm->ndm_family = n->ops->family; | 1873 | ndm->ndm_family = n->ops->family; |
1564 | ndm->ndm_flags = n->flags; | 1874 | ndm->ndm_flags = n->flags; |
1565 | ndm->ndm_type = n->type; | 1875 | ndm->ndm_type = n->type; |
@@ -1609,7 +1919,8 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, | |||
1609 | continue; | 1919 | continue; |
1610 | if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid, | 1920 | if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid, |
1611 | cb->nlh->nlmsg_seq, | 1921 | cb->nlh->nlmsg_seq, |
1612 | RTM_NEWNEIGH) <= 0) { | 1922 | RTM_NEWNEIGH, |
1923 | NLM_F_MULTI) <= 0) { | ||
1613 | read_unlock_bh(&tbl->lock); | 1924 | read_unlock_bh(&tbl->lock); |
1614 | rc = -1; | 1925 | rc = -1; |
1615 | goto out; | 1926 | goto out; |
@@ -2018,7 +2329,7 @@ void neigh_app_ns(struct neighbour *n) | |||
2018 | if (!skb) | 2329 | if (!skb) |
2019 | return; | 2330 | return; |
2020 | 2331 | ||
2021 | if (neigh_fill_info(skb, n, 0, 0, RTM_GETNEIGH) < 0) { | 2332 | if (neigh_fill_info(skb, n, 0, 0, RTM_GETNEIGH, 0) < 0) { |
2022 | kfree_skb(skb); | 2333 | kfree_skb(skb); |
2023 | return; | 2334 | return; |
2024 | } | 2335 | } |
@@ -2037,7 +2348,7 @@ static void neigh_app_notify(struct neighbour *n) | |||
2037 | if (!skb) | 2348 | if (!skb) |
2038 | return; | 2349 | return; |
2039 | 2350 | ||
2040 | if (neigh_fill_info(skb, n, 0, 0, RTM_NEWNEIGH) < 0) { | 2351 | if (neigh_fill_info(skb, n, 0, 0, RTM_NEWNEIGH, 0) < 0) { |
2041 | kfree_skb(skb); | 2352 | kfree_skb(skb); |
2042 | return; | 2353 | return; |
2043 | } | 2354 | } |
@@ -2352,6 +2663,8 @@ EXPORT_SYMBOL(neigh_update); | |||
2352 | EXPORT_SYMBOL(neigh_update_hhs); | 2663 | EXPORT_SYMBOL(neigh_update_hhs); |
2353 | EXPORT_SYMBOL(pneigh_enqueue); | 2664 | EXPORT_SYMBOL(pneigh_enqueue); |
2354 | EXPORT_SYMBOL(pneigh_lookup); | 2665 | EXPORT_SYMBOL(pneigh_lookup); |
2666 | EXPORT_SYMBOL(neightbl_dump_info); | ||
2667 | EXPORT_SYMBOL(neightbl_set); | ||
2355 | 2668 | ||
2356 | #ifdef CONFIG_ARPD | 2669 | #ifdef CONFIG_ARPD |
2357 | EXPORT_SYMBOL(neigh_app_ns); | 2670 | EXPORT_SYMBOL(neigh_app_ns); |