aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/sch_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/sch_api.c')
-rw-r--r--net/sched/sch_api.c68
1 files changed, 66 insertions, 2 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index e7f8e4bfd4ec..929b024f41ba 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -35,6 +35,7 @@
35#include <net/sock.h> 35#include <net/sock.h>
36#include <net/netlink.h> 36#include <net/netlink.h>
37#include <net/pkt_sched.h> 37#include <net/pkt_sched.h>
38#include <net/pkt_cls.h>
38 39
39/* 40/*
40 41
@@ -1648,6 +1649,64 @@ static int tclass_del_notify(struct net *net,
1648 n->nlmsg_flags & NLM_F_ECHO); 1649 n->nlmsg_flags & NLM_F_ECHO);
1649} 1650}
1650 1651
1652#ifdef CONFIG_NET_CLS
1653
1654struct tcf_bind_args {
1655 struct tcf_walker w;
1656 u32 classid;
1657 unsigned long cl;
1658};
1659
1660static int tcf_node_bind(struct tcf_proto *tp, void *n, struct tcf_walker *arg)
1661{
1662 struct tcf_bind_args *a = (void *)arg;
1663
1664 if (tp->ops->bind_class) {
1665 tcf_tree_lock(tp);
1666 tp->ops->bind_class(n, a->classid, a->cl);
1667 tcf_tree_unlock(tp);
1668 }
1669 return 0;
1670}
1671
1672static void tc_bind_tclass(struct Qdisc *q, u32 portid, u32 clid,
1673 unsigned long new_cl)
1674{
1675 const struct Qdisc_class_ops *cops = q->ops->cl_ops;
1676 struct tcf_block *block;
1677 struct tcf_chain *chain;
1678 unsigned long cl;
1679
1680 cl = cops->find(q, portid);
1681 if (!cl)
1682 return;
1683 block = cops->tcf_block(q, cl);
1684 if (!block)
1685 return;
1686 list_for_each_entry(chain, &block->chain_list, list) {
1687 struct tcf_proto *tp;
1688
1689 for (tp = rtnl_dereference(chain->filter_chain);
1690 tp; tp = rtnl_dereference(tp->next)) {
1691 struct tcf_bind_args arg = {};
1692
1693 arg.w.fn = tcf_node_bind;
1694 arg.classid = clid;
1695 arg.cl = new_cl;
1696 tp->ops->walk(tp, &arg.w);
1697 }
1698 }
1699}
1700
1701#else
1702
1703static void tc_bind_tclass(struct Qdisc *q, u32 portid, u32 clid,
1704 unsigned long new_cl)
1705{
1706}
1707
1708#endif
1709
1651static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, 1710static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n,
1652 struct netlink_ext_ack *extack) 1711 struct netlink_ext_ack *extack)
1653{ 1712{
@@ -1753,6 +1812,8 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n,
1753 break; 1812 break;
1754 case RTM_DELTCLASS: 1813 case RTM_DELTCLASS:
1755 err = tclass_del_notify(net, cops, skb, n, q, cl); 1814 err = tclass_del_notify(net, cops, skb, n, q, cl);
1815 /* Unbind the class with flilters with 0 */
1816 tc_bind_tclass(q, portid, clid, 0);
1756 goto out; 1817 goto out;
1757 case RTM_GETTCLASS: 1818 case RTM_GETTCLASS:
1758 err = tclass_notify(net, skb, n, q, cl, RTM_NEWTCLASS); 1819 err = tclass_notify(net, skb, n, q, cl, RTM_NEWTCLASS);
@@ -1767,9 +1828,12 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n,
1767 err = -EOPNOTSUPP; 1828 err = -EOPNOTSUPP;
1768 if (cops->change) 1829 if (cops->change)
1769 err = cops->change(q, clid, portid, tca, &new_cl); 1830 err = cops->change(q, clid, portid, tca, &new_cl);
1770 if (err == 0) 1831 if (err == 0) {
1771 tclass_notify(net, skb, n, q, new_cl, RTM_NEWTCLASS); 1832 tclass_notify(net, skb, n, q, new_cl, RTM_NEWTCLASS);
1772 1833 /* We just create a new class, need to do reverse binding. */
1834 if (cl != new_cl)
1835 tc_bind_tclass(q, portid, clid, new_cl);
1836 }
1773out: 1837out:
1774 return err; 1838 return err;
1775} 1839}