@@ -262,29 +262,57 @@ static void tcf_chain_hold(struct tcf_chain *chain)
262262 ++ chain -> refcnt ;
263263}
264264
265- struct tcf_chain * tcf_chain_get (struct tcf_block * block , u32 chain_index ,
266- bool create )
265+ static struct tcf_chain * tcf_chain_lookup (struct tcf_block * block ,
266+ u32 chain_index )
267267{
268268 struct tcf_chain * chain ;
269269
270270 list_for_each_entry (chain , & block -> chain_list , list ) {
271- if (chain -> index == chain_index ) {
272- tcf_chain_hold (chain );
271+ if (chain -> index == chain_index )
273272 return chain ;
274- }
273+ }
274+ return NULL ;
275+ }
276+
277+ static int tc_chain_notify (struct tcf_chain * chain , struct sk_buff * oskb ,
278+ u32 seq , u16 flags , int event , bool unicast );
279+
280+ struct tcf_chain * tcf_chain_get (struct tcf_block * block , u32 chain_index ,
281+ bool create )
282+ {
283+ struct tcf_chain * chain = tcf_chain_lookup (block , chain_index );
284+
285+ if (chain ) {
286+ tcf_chain_hold (chain );
287+ return chain ;
275288 }
276289
277- return create ? tcf_chain_create (block , chain_index ) : NULL ;
290+ if (!create )
291+ return NULL ;
292+ chain = tcf_chain_create (block , chain_index );
293+ if (!chain )
294+ return NULL ;
295+ tc_chain_notify (chain , NULL , 0 , NLM_F_CREATE | NLM_F_EXCL ,
296+ RTM_NEWCHAIN , false);
297+ return chain ;
278298}
279299EXPORT_SYMBOL (tcf_chain_get );
280300
281301void tcf_chain_put (struct tcf_chain * chain )
282302{
283- if (-- chain -> refcnt == 0 )
303+ if (-- chain -> refcnt == 0 ) {
304+ tc_chain_notify (chain , NULL , 0 , 0 , RTM_DELCHAIN , false);
284305 tcf_chain_destroy (chain );
306+ }
285307}
286308EXPORT_SYMBOL (tcf_chain_put );
287309
310+ static void tcf_chain_put_explicitly_created (struct tcf_chain * chain )
311+ {
312+ if (chain -> explicitly_created )
313+ tcf_chain_put (chain );
314+ }
315+
288316static bool tcf_block_offload_in_use (struct tcf_block * block )
289317{
290318 return block -> offloadcnt ;
@@ -694,8 +722,10 @@ void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
694722
695723 if (block -> refcnt == 1 ) {
696724 /* At this point, all the chains should have refcnt >= 1. */
697- list_for_each_entry_safe (chain , tmp , & block -> chain_list , list )
725+ list_for_each_entry_safe (chain , tmp , & block -> chain_list , list ) {
726+ tcf_chain_put_explicitly_created (chain );
698727 tcf_chain_put (chain );
728+ }
699729
700730 block -> refcnt -- ;
701731 if (list_empty (& block -> chain_list ))
@@ -1609,6 +1639,264 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
16091639 return skb -> len ;
16101640}
16111641
1642+ static int tc_chain_fill_node (struct tcf_chain * chain , struct net * net ,
1643+ struct sk_buff * skb , struct tcf_block * block ,
1644+ u32 portid , u32 seq , u16 flags , int event )
1645+ {
1646+ unsigned char * b = skb_tail_pointer (skb );
1647+ struct nlmsghdr * nlh ;
1648+ struct tcmsg * tcm ;
1649+
1650+ nlh = nlmsg_put (skb , portid , seq , event , sizeof (* tcm ), flags );
1651+ if (!nlh )
1652+ goto out_nlmsg_trim ;
1653+ tcm = nlmsg_data (nlh );
1654+ tcm -> tcm_family = AF_UNSPEC ;
1655+ tcm -> tcm__pad1 = 0 ;
1656+ tcm -> tcm__pad2 = 0 ;
1657+ tcm -> tcm_handle = 0 ;
1658+ if (block -> q ) {
1659+ tcm -> tcm_ifindex = qdisc_dev (block -> q )-> ifindex ;
1660+ tcm -> tcm_parent = block -> q -> handle ;
1661+ } else {
1662+ tcm -> tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK ;
1663+ tcm -> tcm_block_index = block -> index ;
1664+ }
1665+
1666+ if (nla_put_u32 (skb , TCA_CHAIN , chain -> index ))
1667+ goto nla_put_failure ;
1668+
1669+ nlh -> nlmsg_len = skb_tail_pointer (skb ) - b ;
1670+ return skb -> len ;
1671+
1672+ out_nlmsg_trim :
1673+ nla_put_failure :
1674+ nlmsg_trim (skb , b );
1675+ return - EMSGSIZE ;
1676+ }
1677+
1678+ static int tc_chain_notify (struct tcf_chain * chain , struct sk_buff * oskb ,
1679+ u32 seq , u16 flags , int event , bool unicast )
1680+ {
1681+ u32 portid = oskb ? NETLINK_CB (oskb ).portid : 0 ;
1682+ struct tcf_block * block = chain -> block ;
1683+ struct net * net = block -> net ;
1684+ struct sk_buff * skb ;
1685+
1686+ skb = alloc_skb (NLMSG_GOODSIZE , GFP_KERNEL );
1687+ if (!skb )
1688+ return - ENOBUFS ;
1689+
1690+ if (tc_chain_fill_node (chain , net , skb , block , portid ,
1691+ seq , flags , event ) <= 0 ) {
1692+ kfree_skb (skb );
1693+ return - EINVAL ;
1694+ }
1695+
1696+ if (unicast )
1697+ return netlink_unicast (net -> rtnl , skb , portid , MSG_DONTWAIT );
1698+
1699+ return rtnetlink_send (skb , net , portid , RTNLGRP_TC , flags & NLM_F_ECHO );
1700+ }
1701+
1702+ /* Add/delete/get a chain */
1703+
1704+ static int tc_ctl_chain (struct sk_buff * skb , struct nlmsghdr * n ,
1705+ struct netlink_ext_ack * extack )
1706+ {
1707+ struct net * net = sock_net (skb -> sk );
1708+ struct nlattr * tca [TCA_MAX + 1 ];
1709+ struct tcmsg * t ;
1710+ u32 parent ;
1711+ u32 chain_index ;
1712+ struct Qdisc * q = NULL ;
1713+ struct tcf_chain * chain = NULL ;
1714+ struct tcf_block * block ;
1715+ unsigned long cl ;
1716+ int err ;
1717+
1718+ if (n -> nlmsg_type != RTM_GETCHAIN &&
1719+ !netlink_ns_capable (skb , net -> user_ns , CAP_NET_ADMIN ))
1720+ return - EPERM ;
1721+
1722+ replay :
1723+ err = nlmsg_parse (n , sizeof (* t ), tca , TCA_MAX , NULL , extack );
1724+ if (err < 0 )
1725+ return err ;
1726+
1727+ t = nlmsg_data (n );
1728+ parent = t -> tcm_parent ;
1729+ cl = 0 ;
1730+
1731+ block = tcf_block_find (net , & q , & parent , & cl ,
1732+ t -> tcm_ifindex , t -> tcm_block_index , extack );
1733+ if (IS_ERR (block ))
1734+ return PTR_ERR (block );
1735+
1736+ chain_index = tca [TCA_CHAIN ] ? nla_get_u32 (tca [TCA_CHAIN ]) : 0 ;
1737+ if (chain_index > TC_ACT_EXT_VAL_MASK ) {
1738+ NL_SET_ERR_MSG (extack , "Specified chain index exceeds upper limit" );
1739+ return - EINVAL ;
1740+ }
1741+ chain = tcf_chain_lookup (block , chain_index );
1742+ if (n -> nlmsg_type == RTM_NEWCHAIN ) {
1743+ if (chain ) {
1744+ NL_SET_ERR_MSG (extack , "Filter chain already exists" );
1745+ return - EEXIST ;
1746+ }
1747+ if (!(n -> nlmsg_flags & NLM_F_CREATE )) {
1748+ NL_SET_ERR_MSG (extack , "Need both RTM_NEWCHAIN and NLM_F_CREATE to create a new chain" );
1749+ return - ENOENT ;
1750+ }
1751+ chain = tcf_chain_create (block , chain_index );
1752+ if (!chain ) {
1753+ NL_SET_ERR_MSG (extack , "Failed to create filter chain" );
1754+ return - ENOMEM ;
1755+ }
1756+ } else {
1757+ if (!chain ) {
1758+ NL_SET_ERR_MSG (extack , "Cannot find specified filter chain" );
1759+ return - EINVAL ;
1760+ }
1761+ tcf_chain_hold (chain );
1762+ }
1763+
1764+ switch (n -> nlmsg_type ) {
1765+ case RTM_NEWCHAIN :
1766+ /* In case the chain was successfully added, take a reference
1767+ * to the chain. This ensures that an empty chain
1768+ * does not disappear at the end of this function.
1769+ */
1770+ tcf_chain_hold (chain );
1771+ chain -> explicitly_created = true;
1772+ tc_chain_notify (chain , NULL , 0 , NLM_F_CREATE | NLM_F_EXCL ,
1773+ RTM_NEWCHAIN , false);
1774+ break ;
1775+ case RTM_DELCHAIN :
1776+ /* Flush the chain first as the user requested chain removal. */
1777+ tcf_chain_flush (chain );
1778+ /* In case the chain was successfully deleted, put a reference
1779+ * to the chain previously taken during addition.
1780+ */
1781+ tcf_chain_put_explicitly_created (chain );
1782+ break ;
1783+ case RTM_GETCHAIN :
1784+ break ;
1785+ err = tc_chain_notify (chain , skb , n -> nlmsg_seq ,
1786+ n -> nlmsg_seq , n -> nlmsg_type , true);
1787+ if (err < 0 )
1788+ NL_SET_ERR_MSG (extack , "Failed to send chain notify message" );
1789+ break ;
1790+ default :
1791+ err = - EOPNOTSUPP ;
1792+ NL_SET_ERR_MSG (extack , "Unsupported message type" );
1793+ goto errout ;
1794+ }
1795+
1796+ errout :
1797+ tcf_chain_put (chain );
1798+ if (err == - EAGAIN )
1799+ /* Replay the request. */
1800+ goto replay ;
1801+ return err ;
1802+ }
1803+
1804+ /* called with RTNL */
1805+ static int tc_dump_chain (struct sk_buff * skb , struct netlink_callback * cb )
1806+ {
1807+ struct net * net = sock_net (skb -> sk );
1808+ struct nlattr * tca [TCA_MAX + 1 ];
1809+ struct Qdisc * q = NULL ;
1810+ struct tcf_block * block ;
1811+ struct tcf_chain * chain ;
1812+ struct tcmsg * tcm = nlmsg_data (cb -> nlh );
1813+ long index_start ;
1814+ long index ;
1815+ u32 parent ;
1816+ int err ;
1817+
1818+ if (nlmsg_len (cb -> nlh ) < sizeof (* tcm ))
1819+ return skb -> len ;
1820+
1821+ err = nlmsg_parse (cb -> nlh , sizeof (* tcm ), tca , TCA_MAX , NULL , NULL );
1822+ if (err )
1823+ return err ;
1824+
1825+ if (tcm -> tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK ) {
1826+ block = tcf_block_lookup (net , tcm -> tcm_block_index );
1827+ if (!block )
1828+ goto out ;
1829+ /* If we work with block index, q is NULL and parent value
1830+ * will never be used in the following code. The check
1831+ * in tcf_fill_node prevents it. However, compiler does not
1832+ * see that far, so set parent to zero to silence the warning
1833+ * about parent being uninitialized.
1834+ */
1835+ parent = 0 ;
1836+ } else {
1837+ const struct Qdisc_class_ops * cops ;
1838+ struct net_device * dev ;
1839+ unsigned long cl = 0 ;
1840+
1841+ dev = __dev_get_by_index (net , tcm -> tcm_ifindex );
1842+ if (!dev )
1843+ return skb -> len ;
1844+
1845+ parent = tcm -> tcm_parent ;
1846+ if (!parent ) {
1847+ q = dev -> qdisc ;
1848+ parent = q -> handle ;
1849+ } else {
1850+ q = qdisc_lookup (dev , TC_H_MAJ (tcm -> tcm_parent ));
1851+ }
1852+ if (!q )
1853+ goto out ;
1854+ cops = q -> ops -> cl_ops ;
1855+ if (!cops )
1856+ goto out ;
1857+ if (!cops -> tcf_block )
1858+ goto out ;
1859+ if (TC_H_MIN (tcm -> tcm_parent )) {
1860+ cl = cops -> find (q , tcm -> tcm_parent );
1861+ if (cl == 0 )
1862+ goto out ;
1863+ }
1864+ block = cops -> tcf_block (q , cl , NULL );
1865+ if (!block )
1866+ goto out ;
1867+ if (tcf_block_shared (block ))
1868+ q = NULL ;
1869+ }
1870+
1871+ index_start = cb -> args [0 ];
1872+ index = 0 ;
1873+
1874+ list_for_each_entry (chain , & block -> chain_list , list ) {
1875+ if ((tca [TCA_CHAIN ] &&
1876+ nla_get_u32 (tca [TCA_CHAIN ]) != chain -> index ))
1877+ continue ;
1878+ if (index < index_start ) {
1879+ index ++ ;
1880+ continue ;
1881+ }
1882+ err = tc_chain_fill_node (chain , net , skb , block ,
1883+ NETLINK_CB (cb -> skb ).portid ,
1884+ cb -> nlh -> nlmsg_seq , NLM_F_MULTI ,
1885+ RTM_NEWCHAIN );
1886+ if (err <= 0 )
1887+ break ;
1888+ index ++ ;
1889+ }
1890+
1891+ cb -> args [0 ] = index ;
1892+
1893+ out :
1894+ /* If we did no progress, the error (EMSGSIZE) is real */
1895+ if (skb -> len == 0 && err )
1896+ return err ;
1897+ return skb -> len ;
1898+ }
1899+
16121900void tcf_exts_destroy (struct tcf_exts * exts )
16131901{
16141902#ifdef CONFIG_NET_CLS_ACT
@@ -1825,6 +2113,10 @@ static int __init tc_filter_init(void)
18252113 rtnl_register (PF_UNSPEC , RTM_DELTFILTER , tc_del_tfilter , NULL , 0 );
18262114 rtnl_register (PF_UNSPEC , RTM_GETTFILTER , tc_get_tfilter ,
18272115 tc_dump_tfilter , 0 );
2116+ rtnl_register (PF_UNSPEC , RTM_NEWCHAIN , tc_ctl_chain , NULL , 0 );
2117+ rtnl_register (PF_UNSPEC , RTM_DELCHAIN , tc_ctl_chain , NULL , 0 );
2118+ rtnl_register (PF_UNSPEC , RTM_GETCHAIN , tc_ctl_chain ,
2119+ tc_dump_chain , 0 );
18282120
18292121 return 0 ;
18302122
0 commit comments