From 1fc61896a97c1469e885bd620670137e133e2165 Mon Sep 17 00:00:00 2001 From: Deepak S Date: Fri, 5 Oct 2018 09:43:01 +0530 Subject: [PATCH 1/2] initial commit --- include/net/pkt_cls.h | 27 ++++++++++ net/sched/cls_api.c | 119 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index 753ac9361154be..358d7b106fb6e0 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h @@ -34,6 +34,33 @@ struct tcf_block_ext_info { struct tcf_block_cb; bool tcf_queue_work(struct work_struct *work); +struct tc_keys { + u16 type; + u16 len; + union { + /* match part start */ + char mac[ETH_ALEN]; + u32 flags; + u16 port; + u16 eth_type; + u32 ip; + u32 ip_mask; + u8 ip_proto; + char classifier_kind[10]; + /* match part end */ + /* actions part start */ + char act_kind[10]; + void *action; + //struct tc_gact p; + //struct tc_mirred p; + /* actions part end */ + } data; +}; + +int tc_filter_ingress_add(struct net_device *dev, + struct tcmsg *t, int keys, + struct tc_keys *tc_keys[]); + #ifdef CONFIG_NET_CLS struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, bool create); diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index b9d63d2246e667..5a25d56436b56f 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -938,6 +938,125 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, return err; } +#define MAX_MSG 1024 + +#define NLMSG_TAIL(nmsg) \ + ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) + +static int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, + int alen) +{ + int len = RTA_LENGTH(alen); + struct rtattr *rta = NULL; + + if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { + printk("addattr_l ERROR: message exceeded bound of %d", + maxlen); + return -1; + } + rta = NLMSG_TAIL(n); + rta->rta_type = type; + rta->rta_len = len; + if (alen) + memcpy(RTA_DATA(rta), data, alen); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); + + return 0; +} + +static int addattr(struct nlmsghdr *n, struct tc_keys *key, + const void *data) +{ + return addattr_l(n, MAX_MSG, key->type, &data, key->len); +} + +struct req_struct { + struct nlmsghdr n; + struct tcmsg t; + char buf[MAX_MSG]; +}; + +int tc_filter_ingress_add(struct net_device *dev, struct tcmsg *t, int keys, + struct tc_keys *tc_keys[keys]) +{ + int err = 0, i = 0; + + __be16 eth_type; + + struct sock *sk = NULL; + struct sk_buff *skb = NULL; + struct tc_keys *key = NULL; + struct rtattr *tail, *tail1, *tail2, *tail3; + + if (!t) + return -ENOENT; + + struct req_struct req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), + .n.nlmsg_flags = NLM_F_REQUEST|NLM_F_EXCL|NLM_F_CREATE, + .n.nlmsg_type = RTM_NEWTFILTER, + .n.nlmsg_pid = 0, + .n.nlmsg_seq = 0, + .t.tcm_family = AF_UNSPEC, + .t.tcm_parent = TC_H_INGRESS, + .t.tcm_ifindex = dev->ifindex, + }; + + eth_type = TC_H_MIN(req.t.tcm_info); + + for (;i < keys && tc_keys[i] != NULL; i++) + { + key = tc_keys[i]; + switch(key->type) + { + case TCA_KIND: + case TCA_ACT_KIND: + tail2 = NLMSG_TAIL(&req.n); + addattr_l(&req.n, MAX_MSG, TCA_FLOWER_ACT, NULL, 0); + tail1 = NLMSG_TAIL(&req.n); + addattr_l(&req.n, MAX_MSG, 1, NULL, 0); + addattr(&req.n, key, &key->data.act_kind); + break; + addattr(&req.n, key, &key->data.classifier_kind); + tail3 = (struct rtattr *) + (((void *) &req.n) + NLMSG_ALIGN((&req.n)->nlmsg_len)); + addattr_l(&req.n, MAX_MSG, TCA_OPTIONS, NULL, 0); + break; + case TCA_FLOWER_KEY_IP_PROTO: + addattr(&req.n, key, &key->data.ip_proto); + break; + case TCA_FLOWER_KEY_IPV4_DST: + case TCA_FLOWER_KEY_IPV4_SRC: + addattr(&req.n, key, &key->data.ip); + break; + case TCA_FLOWER_KEY_IPV4_SRC_MASK: + case TCA_FLOWER_KEY_IPV4_DST_MASK: + addattr(&req.n, key, &key->data.ip_mask); + break; + case TCA_FLOWER_KEY_TCP_SRC: + case TCA_FLOWER_KEY_TCP_DST: + case TCA_FLOWER_KEY_UDP_SRC: + case TCA_FLOWER_KEY_UDP_DST: + addattr(&req.n, key, &key->data.port); + break; + default: + return -EOPNOTSUPP; + + } + } + + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); + if (!skb) + return -ENOBUFS; + sock_net_set(sk, &init_net); + skb->sk = sk; + + err = tc_ctl_tfilter(skb, &req.n, NULL); + + return err; +} +EXPORT_SYMBOL(tc_filter_ingress_add); + struct tcf_dump_args { struct tcf_walker w; struct sk_buff *skb; From 51a8905a435519ee44d9d65564f0a2f4232c26de Mon Sep 17 00:00:00 2001 From: Deepak S Date: Fri, 5 Oct 2018 15:33:12 +0530 Subject: [PATCH 2/2] 2 --- include/net/pkt_cls.h | 1 - net/sched/cls_api.c | 124 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 102 insertions(+), 23 deletions(-) diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index 358d7b106fb6e0..4e114ed291e378 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h @@ -42,7 +42,6 @@ struct tc_keys { char mac[ETH_ALEN]; u32 flags; u16 port; - u16 eth_type; u32 ip; u32 ip_mask; u8 ip_proto; diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 5a25d56436b56f..ba891f3dfa0d7d 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -29,6 +29,7 @@ #include #include #include +#include /* The list of all installed classifier types */ static LIST_HEAD(tcf_proto_base); @@ -648,6 +649,10 @@ static int tfilter_notify(struct net *net, struct sk_buff *oskb, struct sk_buff *skb; u32 portid = oskb ? NETLINK_CB(oskb).portid : 0; + /* If the request originated from kernel */ + if (n->nlmsg_pid == 0) + return 0; + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb) return -ENOBUFS; @@ -670,10 +675,14 @@ static int tfilter_del_notify(struct net *net, struct sk_buff *oskb, struct Qdisc *q, u32 parent, void *fh, bool unicast, bool *last) { - struct sk_buff *skb; + struct sk_buff *skb = NULL; u32 portid = oskb ? NETLINK_CB(oskb).portid : 0; int err; + /* If the request originated from kernel */ + if (n->nlmsg_pid == 0) + goto skip_fill_node; + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb) return -ENOBUFS; @@ -684,11 +693,14 @@ static int tfilter_del_notify(struct net *net, struct sk_buff *oskb, return -EINVAL; } +skip_fill_node: err = tp->ops->delete(tp, fh, last); if (err) { kfree_skb(skb); return err; } + if (n->nlmsg_pid == 0) + return 0; if (unicast) return netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT); @@ -734,7 +746,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, int err; int tp_created; - if ((n->nlmsg_type != RTM_GETTFILTER) && + if ((n->nlmsg_type != RTM_GETTFILTER) && (n->nlmsg_pid !=0) && !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) return -EPERM; @@ -979,17 +991,18 @@ struct req_struct { int tc_filter_ingress_add(struct net_device *dev, struct tcmsg *t, int keys, struct tc_keys *tc_keys[keys]) { - int err = 0, i = 0; - __be16 eth_type; + char act_kind[10]; + int err = 0, i = 0; + u32 flags; struct sock *sk = NULL; struct sk_buff *skb = NULL; struct tc_keys *key = NULL; struct rtattr *tail, *tail1, *tail2, *tail3; - if (!t) - return -ENOENT; + if (!t || !keys || !tc_keys) + return -ENODATA; struct req_struct req = { .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), @@ -1002,48 +1015,115 @@ int tc_filter_ingress_add(struct net_device *dev, struct tcmsg *t, int keys, .t.tcm_ifindex = dev->ifindex, }; - eth_type = TC_H_MIN(req.t.tcm_info); - + /* pre classifier start */ for (;i < keys && tc_keys[i] != NULL; i++) { key = tc_keys[i]; switch(key->type) { case TCA_KIND: - case TCA_ACT_KIND: - tail2 = NLMSG_TAIL(&req.n); - addattr_l(&req.n, MAX_MSG, TCA_FLOWER_ACT, NULL, 0); - tail1 = NLMSG_TAIL(&req.n); - addattr_l(&req.n, MAX_MSG, 1, NULL, 0); - addattr(&req.n, key, &key->data.act_kind); - break; - addattr(&req.n, key, &key->data.classifier_kind); - tail3 = (struct rtattr *) - (((void *) &req.n) + NLMSG_ALIGN((&req.n)->nlmsg_len)); - addattr_l(&req.n, MAX_MSG, TCA_OPTIONS, NULL, 0); - break; + if (key->data.classifier_kind) { + addattr(&req.n, key, &key->data.classifier_kind); + tail3 = (struct rtattr *) + (((void *) &req.n) + NLMSG_ALIGN((&req.n)->nlmsg_len)); + addattr_l(&req.n, MAX_MSG, TCA_OPTIONS, NULL, 0); + tc_keys[i] = NULL; + goto start_filter_processing; + } + } + } + /* pre classifier end */ + +start_filter_processing: + /* classifier start */ + for (;i < keys && tc_keys[i] != NULL; i++) + { + key = tc_keys[i]; + switch(key->type) + { case TCA_FLOWER_KEY_IP_PROTO: addattr(&req.n, key, &key->data.ip_proto); + tc_keys[i] = NULL; break; case TCA_FLOWER_KEY_IPV4_DST: case TCA_FLOWER_KEY_IPV4_SRC: addattr(&req.n, key, &key->data.ip); + tc_keys[i] = NULL; break; case TCA_FLOWER_KEY_IPV4_SRC_MASK: case TCA_FLOWER_KEY_IPV4_DST_MASK: addattr(&req.n, key, &key->data.ip_mask); + tc_keys[i] = NULL; break; case TCA_FLOWER_KEY_TCP_SRC: case TCA_FLOWER_KEY_TCP_DST: case TCA_FLOWER_KEY_UDP_SRC: case TCA_FLOWER_KEY_UDP_DST: addattr(&req.n, key, &key->data.port); + tc_keys[i] = NULL; break; - default: - return -EOPNOTSUPP; + case TCA_FLOWER_KEY_ETH_TYPE: + eth_type = TC_H_MIN(req.t.tcm_info); + break; + case TCA_FLOWER_FLAGS: + flags = key->data.flags; + tc_keys[i] = NULL; + break; + } + } + /* classifier start */ + + /* pre action start */ + for (;i < keys && tc_keys[i] != NULL; i++) + { + key = tc_keys[i]; + switch(key->type) + { + case TCA_ACT_KIND: + if (key->data.act_kind) { + tail2 = NLMSG_TAIL(&req.n); + addattr_l(&req.n, MAX_MSG, TCA_FLOWER_ACT, NULL, 0); + tail1 = NLMSG_TAIL(&req.n); + addattr_l(&req.n, MAX_MSG, 1, NULL, 0); + addattr(&req.n, key, &key->data.act_kind); + strncpy(act_kind, key->data.act_kind, sizeof(act_kind)); + tc_keys[i] = NULL; + goto start_action_processing; + } + } + } + /* pre action end */ + +start_action_processing: + /* action start */ + for (;i < keys && tc_keys[i] != NULL; i++) + { + key = tc_keys[i]; + if (!strncmp(act_kind, "gact", sizeof(act_kind))) { + switch(key->type) + { + case TCA_GACT_PARMS: + tail = NLMSG_TAIL(&req.n); + addattr_l(&req.n, MAX_MSG, TCA_ACT_OPTIONS, NULL, 0); + addattr(&req.n, key, &key->data.action); + tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail; + tail1->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail1; + tail2->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail2; + tc_keys[i] = NULL; + goto end; + } } } + /* action end */ + +end: + /* post classifier start */ + addattr_l(&req.n, MAX_MSG, TCA_FLOWER_FLAGS, &flags, sizeof(u32)); + addattr_l(&req.n, MAX_MSG, TCA_FLOWER_KEY_ETH_TYPE, ð_type, sizeof(u16)); + tail3->rta_len = (((void *) + (&req.n))+(&req.n)->nlmsg_len) - (void *)tail3; + /* post classifier end */ skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb)