Commit c7fb64db001f83ece669c76a02d8ec2fdb1dd307

Authored by Thomas Graf
Committed by David S. Miller
1 parent 0076824492

[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>

Showing 5 changed files with 439 additions and 11 deletions Side-by-side Diff

include/linux/rtnetlink.h
... ... @@ -89,6 +89,13 @@
89 89 RTM_GETANYCAST = 62,
90 90 #define RTM_GETANYCAST RTM_GETANYCAST
91 91  
  92 + RTM_NEWNEIGHTBL = 64,
  93 +#define RTM_NEWNEIGHTBL RTM_NEWNEIGHTBL
  94 + RTM_GETNEIGHTBL = 66,
  95 +#define RTM_GETNEIGHTBL RTM_GETNEIGHTBL
  96 + RTM_SETNEIGHTBL,
  97 +#define RTM_SETNEIGHTBL RTM_SETNEIGHTBL
  98 +
92 99 __RTM_MAX,
93 100 #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1)
94 101 };
... ... @@ -492,6 +499,106 @@
492 499 __u32 ndm_updated;
493 500 __u32 ndm_refcnt;
494 501 };
  502 +
  503 +
  504 +/*****************************************************************
  505 + * Neighbour tables specific messages.
  506 + *
  507 + * To retrieve the neighbour tables send RTM_GETNEIGHTBL with the
  508 + * NLM_F_DUMP flag set. Every neighbour table configuration is
  509 + * spread over multiple messages to avoid running into message
  510 + * size limits on systems with many interfaces. The first message
  511 + * in the sequence transports all not device specific data such as
  512 + * statistics, configuration, and the default parameter set.
  513 + * This message is followed by 0..n messages carrying device
  514 + * specific parameter sets.
  515 + * Although the ordering should be sufficient, NDTA_NAME can be
  516 + * used to identify sequences. The initial message can be identified
  517 + * by checking for NDTA_CONFIG. The device specific messages do
  518 + * not contain this TLV but have NDTPA_IFINDEX set to the
  519 + * corresponding interface index.
  520 + *
  521 + * To change neighbour table attributes, send RTM_SETNEIGHTBL
  522 + * with NDTA_NAME set. Changeable attribute include NDTA_THRESH[1-3],
  523 + * NDTA_GC_INTERVAL, and all TLVs in NDTA_PARMS unless marked
  524 + * otherwise. Device specific parameter sets can be changed by
  525 + * setting NDTPA_IFINDEX to the interface index of the corresponding
  526 + * device.
  527 + ****/
  528 +
  529 +struct ndt_stats
  530 +{
  531 + __u64 ndts_allocs;
  532 + __u64 ndts_destroys;
  533 + __u64 ndts_hash_grows;
  534 + __u64 ndts_res_failed;
  535 + __u64 ndts_lookups;
  536 + __u64 ndts_hits;
  537 + __u64 ndts_rcv_probes_mcast;
  538 + __u64 ndts_rcv_probes_ucast;
  539 + __u64 ndts_periodic_gc_runs;
  540 + __u64 ndts_forced_gc_runs;
  541 +};
  542 +
  543 +enum {
  544 + NDTPA_UNSPEC,
  545 + NDTPA_IFINDEX, /* u32, unchangeable */
  546 + NDTPA_REFCNT, /* u32, read-only */
  547 + NDTPA_REACHABLE_TIME, /* u64, read-only, msecs */
  548 + NDTPA_BASE_REACHABLE_TIME, /* u64, msecs */
  549 + NDTPA_RETRANS_TIME, /* u64, msecs */
  550 + NDTPA_GC_STALETIME, /* u64, msecs */
  551 + NDTPA_DELAY_PROBE_TIME, /* u64, msecs */
  552 + NDTPA_QUEUE_LEN, /* u32 */
  553 + NDTPA_APP_PROBES, /* u32 */
  554 + NDTPA_UCAST_PROBES, /* u32 */
  555 + NDTPA_MCAST_PROBES, /* u32 */
  556 + NDTPA_ANYCAST_DELAY, /* u64, msecs */
  557 + NDTPA_PROXY_DELAY, /* u64, msecs */
  558 + NDTPA_PROXY_QLEN, /* u32 */
  559 + NDTPA_LOCKTIME, /* u64, msecs */
  560 + __NDTPA_MAX
  561 +};
  562 +#define NDTPA_MAX (__NDTPA_MAX - 1)
  563 +
  564 +struct ndtmsg
  565 +{
  566 + __u8 ndtm_family;
  567 + __u8 ndtm_pad1;
  568 + __u16 ndtm_pad2;
  569 +};
  570 +
  571 +struct ndt_config
  572 +{
  573 + __u16 ndtc_key_len;
  574 + __u16 ndtc_entry_size;
  575 + __u32 ndtc_entries;
  576 + __u32 ndtc_last_flush; /* delta to now in msecs */
  577 + __u32 ndtc_last_rand; /* delta to now in msecs */
  578 + __u32 ndtc_hash_rnd;
  579 + __u32 ndtc_hash_mask;
  580 + __u32 ndtc_hash_chain_gc;
  581 + __u32 ndtc_proxy_qlen;
  582 +};
  583 +
  584 +enum {
  585 + NDTA_UNSPEC,
  586 + NDTA_NAME, /* char *, unchangeable */
  587 + NDTA_THRESH1, /* u32 */
  588 + NDTA_THRESH2, /* u32 */
  589 + NDTA_THRESH3, /* u32 */
  590 + NDTA_CONFIG, /* struct ndt_config, read-only */
  591 + NDTA_PARMS, /* nested TLV NDTPA_* */
  592 + NDTA_STATS, /* struct ndt_stats, read-only */
  593 + NDTA_GC_INTERVAL, /* u64, msecs */
  594 + __NDTA_MAX
  595 +};
  596 +#define NDTA_MAX (__NDTA_MAX - 1)
  597 +
  598 +#define NDTA_RTA(r) ((struct rtattr*)(((char*)(r)) + \
  599 + NLMSG_ALIGN(sizeof(struct ndtmsg))))
  600 +#define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg))
  601 +
495 602  
496 603 /****
497 604 * General form of address family dependent message.
include/net/neighbour.h
... ... @@ -65,6 +65,7 @@
65 65  
66 66 struct neigh_parms
67 67 {
  68 + struct net_device *dev;
68 69 struct neigh_parms *next;
69 70 int (*neigh_setup)(struct neighbour *);
70 71 struct neigh_table *tbl;
... ... @@ -251,6 +252,9 @@
251 252 extern int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
252 253 extern int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
253 254 extern void neigh_app_ns(struct neighbour *n);
  255 +
  256 +extern int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb);
  257 +extern int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
254 258  
255 259 extern void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie);
256 260 extern void __neigh_for_each_release(struct neigh_table *tbl, int (*cb)(struct neighbour *));
net/core/neighbour.c
... ... @@ -1276,9 +1276,14 @@
1276 1276 INIT_RCU_HEAD(&p->rcu_head);
1277 1277 p->reachable_time =
1278 1278 neigh_rand_reach_time(p->base_reachable_time);
1279   - if (dev && dev->neigh_setup && dev->neigh_setup(dev, p)) {
1280   - kfree(p);
1281   - return NULL;
  1279 + if (dev) {
  1280 + if (dev->neigh_setup && dev->neigh_setup(dev, p)) {
  1281 + kfree(p);
  1282 + return NULL;
  1283 + }
  1284 +
  1285 + dev_hold(dev);
  1286 + p->dev = dev;
1282 1287 }
1283 1288 p->sysctl_table = NULL;
1284 1289 write_lock_bh(&tbl->lock);
... ... @@ -1309,6 +1314,8 @@
1309 1314 *p = parms->next;
1310 1315 parms->dead = 1;
1311 1316 write_unlock_bh(&tbl->lock);
  1317 + if (parms->dev)
  1318 + dev_put(parms->dev);
1312 1319 call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
1313 1320 return;
1314 1321 }
1315 1322  
... ... @@ -1546,7 +1553,309 @@
1546 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 = RTA_NEST(skb, NDTA_PARMS);
1549 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 +
  1581 +rtattr_failure:
  1582 + return RTA_NEST_CANCEL(skb, nest);
  1583 +}
  1584 +
  1585 +static 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 +
  1660 +rtattr_failure:
  1661 + read_unlock_bh(&tbl->lock);
  1662 + return NLMSG_CANCEL(skb, nlh);
  1663 +
  1664 +nlmsg_failure:
  1665 + return -1;
  1666 +}
  1667 +
  1668 +static 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 +
  1691 +rtattr_failure:
  1692 + read_unlock_bh(&tbl->lock);
  1693 + return NLMSG_CANCEL(skb, nlh);
  1694 +
  1695 +nlmsg_failure:
  1696 + return -1;
  1697 +}
  1698 +
  1699 +static 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 +
  1712 +int 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 +
  1818 +rtattr_failure:
  1819 + write_unlock_bh(&tbl->lock);
  1820 +errout:
  1821 + read_unlock(&neigh_tbl_lock);
  1822 + return err;
  1823 +}
  1824 +
  1825 +int 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 + }
  1852 +out:
  1853 + read_unlock(&neigh_tbl_lock);
  1854 + cb->args[0] = idx;
  1855 +
  1856 + return skb->len;
  1857 +}
  1858 +
1550 1859 static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n,
1551 1860 u32 pid, u32 seq, int event)
1552 1861 {
... ... @@ -2352,6 +2661,8 @@
2352 2661 EXPORT_SYMBOL(neigh_update_hhs);
2353 2662 EXPORT_SYMBOL(pneigh_enqueue);
2354 2663 EXPORT_SYMBOL(pneigh_lookup);
  2664 +EXPORT_SYMBOL(neightbl_dump_info);
  2665 +EXPORT_SYMBOL(neightbl_set);
2355 2666  
2356 2667 #ifdef CONFIG_ARPD
2357 2668 EXPORT_SYMBOL(neigh_app_ns);
net/core/rtnetlink.c
... ... @@ -100,6 +100,7 @@
100 100 [RTM_FAM(RTM_NEWPREFIX)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
101 101 [RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
102 102 [RTM_FAM(RTM_GETANYCAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
  103 + [RTM_FAM(RTM_NEWNEIGHTBL)] = NLMSG_LENGTH(sizeof(struct ndtmsg)),
103 104 };
104 105  
105 106 static const int rta_max[RTM_NR_FAMILIES] =
... ... @@ -113,6 +114,7 @@
113 114 [RTM_FAM(RTM_NEWTCLASS)] = TCA_MAX,
114 115 [RTM_FAM(RTM_NEWTFILTER)] = TCA_MAX,
115 116 [RTM_FAM(RTM_NEWACTION)] = TCAA_MAX,
  117 + [RTM_FAM(RTM_NEWNEIGHTBL)] = NDTA_MAX,
116 118 };
117 119  
118 120 void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
... ... @@ -649,14 +651,16 @@
649 651  
650 652 static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] =
651 653 {
652   - [RTM_GETLINK - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo },
653   - [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink },
654   - [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
655   - [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
656   - [RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add },
657   - [RTM_DELNEIGH - RTM_BASE] = { .doit = neigh_delete },
658   - [RTM_GETNEIGH - RTM_BASE] = { .dumpit = neigh_dump_info },
659   - [RTM_GETRULE - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
  654 + [RTM_GETLINK - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo },
  655 + [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink },
  656 + [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
  657 + [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
  658 + [RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add },
  659 + [RTM_DELNEIGH - RTM_BASE] = { .doit = neigh_delete },
  660 + [RTM_GETNEIGH - RTM_BASE] = { .dumpit = neigh_dump_info },
  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  
662 666 static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr)
security/selinux/nlmsgtab.c
... ... @@ -63,6 +63,8 @@
63 63 { RTM_GETPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_READ },
64 64 { RTM_GETMULTICAST, NETLINK_ROUTE_SOCKET__NLMSG_READ },
65 65 { RTM_GETANYCAST, NETLINK_ROUTE_SOCKET__NLMSG_READ },
  66 + { RTM_GETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_READ },
  67 + { RTM_SETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
66 68 };
67 69  
68 70 static struct nlmsg_perm nlmsg_firewall_perms[] =