]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/sched/cls_api.c
net/sched: cls_flower: Add offload support using egress Hardware device
[karo-tx-linux.git] / net / sched / cls_api.c
index 11da7da0b7c42520ae89d065156aeee7eed0f380..3fbba79a4ef0521604df48275fb7dae8a8b7099e 100644 (file)
@@ -101,7 +101,7 @@ EXPORT_SYMBOL(unregister_tcf_proto_ops);
 
 static int tfilter_notify(struct net *net, struct sk_buff *oskb,
                          struct nlmsghdr *n, struct tcf_proto *tp,
-                         unsigned long fh, int event);
+                         unsigned long fh, int event, bool unicast);
 
 static void tfilter_notify_chain(struct net *net, struct sk_buff *oskb,
                                 struct nlmsghdr *n,
@@ -112,7 +112,7 @@ static void tfilter_notify_chain(struct net *net, struct sk_buff *oskb,
 
        for (it_chain = chain; (tp = rtnl_dereference(*it_chain)) != NULL;
             it_chain = &tp->next)
-               tfilter_notify(net, oskb, n, tp, 0, event);
+               tfilter_notify(net, oskb, n, tp, 0, event, false);
 }
 
 /* Select new prio value from the range, managed by kernel. */
@@ -319,7 +319,8 @@ replay:
 
                        RCU_INIT_POINTER(*back, next);
 
-                       tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER);
+                       tfilter_notify(net, skb, n, tp, fh,
+                                      RTM_DELTFILTER, false);
                        tcf_destroy(tp, true);
                        err = 0;
                        goto errout;
@@ -344,15 +345,16 @@ replay:
                        if (err == 0) {
                                struct tcf_proto *next = rtnl_dereference(tp->next);
 
-                               tfilter_notify(net, skb, n, tp, fh,
-                                              RTM_DELTFILTER);
+                               tfilter_notify(net, skb, n, tp,
+                                              t->tcm_handle,
+                                              RTM_DELTFILTER, false);
                                if (tcf_destroy(tp, false))
                                        RCU_INIT_POINTER(*back, next);
                        }
                        goto errout;
                case RTM_GETTFILTER:
                        err = tfilter_notify(net, skb, n, tp, fh,
-                                            RTM_NEWTFILTER);
+                                            RTM_NEWTFILTER, true);
                        goto errout;
                default:
                        err = -EINVAL;
@@ -367,7 +369,7 @@ replay:
                        RCU_INIT_POINTER(tp->next, rtnl_dereference(*back));
                        rcu_assign_pointer(*back, tp);
                }
-               tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER);
+               tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER, false);
        } else {
                if (tp_created)
                        tcf_destroy(tp, true);
@@ -419,7 +421,7 @@ nla_put_failure:
 
 static int tfilter_notify(struct net *net, struct sk_buff *oskb,
                          struct nlmsghdr *n, struct tcf_proto *tp,
-                         unsigned long fh, int event)
+                         unsigned long fh, int event, bool unicast)
 {
        struct sk_buff *skb;
        u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
@@ -428,11 +430,15 @@ static int tfilter_notify(struct net *net, struct sk_buff *oskb,
        if (!skb)
                return -ENOBUFS;
 
-       if (tcf_fill_node(net, skb, tp, fh, portid, n->nlmsg_seq, 0, event) <= 0) {
+       if (tcf_fill_node(net, skb, tp, fh, portid, n->nlmsg_seq,
+                         n->nlmsg_flags, event) <= 0) {
                kfree_skb(skb);
                return -EINVAL;
        }
 
+       if (unicast)
+               return netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT);
+
        return rtnetlink_send(skb, net, portid, RTNLGRP_TC,
                              n->nlmsg_flags & NLM_F_ECHO);
 }
@@ -676,6 +682,30 @@ int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts)
 }
 EXPORT_SYMBOL(tcf_exts_dump_stats);
 
+int tcf_exts_get_dev(struct net_device *dev, struct tcf_exts *exts,
+                    struct net_device **hw_dev)
+{
+#ifdef CONFIG_NET_CLS_ACT
+       const struct tc_action *a;
+       LIST_HEAD(actions);
+
+       if (tc_no_actions(exts))
+               return -EINVAL;
+
+       tcf_exts_to_list(exts, &actions);
+       list_for_each_entry(a, &actions, list) {
+               if (a->ops->get_dev) {
+                       a->ops->get_dev(a, dev_net(dev), hw_dev);
+                       break;
+               }
+       }
+       if (*hw_dev)
+               return 0;
+#endif
+       return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(tcf_exts_get_dev);
+
 static int __init tc_filter_init(void)
 {
        rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_ctl_tfilter, NULL, NULL);