diff options
Diffstat (limited to 'net/sched')
36 files changed, 1682 insertions, 1664 deletions
diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 9c15c4888d1..87af7c913d8 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -198,6 +198,7 @@ config NET_SCH_NETEM config NET_SCH_INGRESS tristate "Ingress Qdisc" + depends on NET_CLS_ACT || NETFILTER ---help--- Say Y here if you want to use classifiers for incoming packets. If unsure, say Y. @@ -445,7 +446,6 @@ config NET_ACT_IPT config NET_ACT_NAT tristate "Stateless NAT" depends on NET_CLS_ACT - select NETFILTER ---help--- Say Y here to do stateless NAT on IPv4 packets. You should use netfilter for NAT unless you know what you are doing. @@ -476,15 +476,6 @@ config NET_ACT_SIMP To compile this code as a module, choose M here: the module will be called simple. -config NET_CLS_POLICE - bool "Traffic Policing (obsolete)" - select NET_CLS_ACT - select NET_ACT_POLICE - ---help--- - Say Y here if you want to do traffic policing, i.e. strict - bandwidth limiting. This option is obsolete and just selects - the option replacing it. It will be removed in the future. - config NET_CLS_IND bool "Incoming device classification" depends on NET_CLS_U32 || NET_CLS_FW diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 72cdb0fade2..0b8eb235bc1 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -18,6 +18,9 @@ #include <linux/skbuff.h> #include <linux/init.h> #include <linux/kmod.h> +#include <linux/err.h> +#include <net/net_namespace.h> +#include <net/sock.h> #include <net/sch_generic.h> #include <net/act_api.h> #include <net/netlink.h> @@ -66,7 +69,7 @@ static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb, { struct tcf_common *p; int err = 0, index = -1,i = 0, s_i = 0, n_i = 0; - struct rtattr *r ; + struct nlattr *nest; read_lock_bh(hinfo->lock); @@ -81,15 +84,17 @@ static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb, continue; a->priv = p; a->order = n_i; - r = (struct rtattr *)skb_tail_pointer(skb); - RTA_PUT(skb, a->order, 0, NULL); + + nest = nla_nest_start(skb, a->order); + if (nest == NULL) + goto nla_put_failure; err = tcf_action_dump_1(skb, a, 0, 0); if (err < 0) { index--; - nlmsg_trim(skb, r); + nlmsg_trim(skb, nest); goto done; } - r->rta_len = skb_tail_pointer(skb) - (u8 *)r; + nla_nest_end(skb, nest); n_i++; if (n_i >= TCA_ACT_MAX_PRIO) goto done; @@ -101,8 +106,8 @@ done: cb->args[0] += n_i; return n_i; -rtattr_failure: - nlmsg_trim(skb, r); +nla_put_failure: + nla_nest_cancel(skb, nest); goto done; } @@ -110,12 +115,13 @@ static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a, struct tcf_hashinfo *hinfo) { struct tcf_common *p, *s_p; - struct rtattr *r ; + struct nlattr *nest; int i= 0, n_i = 0; - r = (struct rtattr *)skb_tail_pointer(skb); - RTA_PUT(skb, a->order, 0, NULL); - RTA_PUT(skb, TCA_KIND, IFNAMSIZ, a->ops->kind); + nest = nla_nest_start(skb, a->order); + if (nest == NULL) + goto nla_put_failure; + NLA_PUT_STRING(skb, TCA_KIND, a->ops->kind); for (i = 0; i < (hinfo->hmask + 1); i++) { p = hinfo->htab[tcf_hash(i, hinfo->hmask)]; @@ -127,12 +133,12 @@ static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a, p = s_p; } } - RTA_PUT(skb, TCA_FCNT, 4, &n_i); - r->rta_len = skb_tail_pointer(skb) - (u8 *)r; + NLA_PUT_U32(skb, TCA_FCNT, n_i); + nla_nest_end(skb, nest); return n_i; -rtattr_failure: - nlmsg_trim(skb, r); +nla_put_failure: + nla_nest_cancel(skb, nest); return -EINVAL; } @@ -209,7 +215,7 @@ struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a, int bind, } EXPORT_SYMBOL(tcf_hash_check); -struct tcf_common *tcf_hash_create(u32 index, struct rtattr *est, struct tc_action *a, int size, int bind, u32 *idx_gen, struct tcf_hashinfo *hinfo) +struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a, int size, int bind, u32 *idx_gen, struct tcf_hashinfo *hinfo) { struct tcf_common *p = kzalloc(size, GFP_KERNEL); @@ -261,6 +267,7 @@ int tcf_register_action(struct tc_action_ops *act) write_unlock(&act_mod_lock); return 0; } +EXPORT_SYMBOL(tcf_register_action); int tcf_unregister_action(struct tc_action_ops *act) { @@ -279,6 +286,7 @@ int tcf_unregister_action(struct tc_action_ops *act) write_unlock(&act_mod_lock); return err; } +EXPORT_SYMBOL(tcf_unregister_action); /* lookup by name */ static struct tc_action_ops *tc_lookup_action_n(char *kind) @@ -301,15 +309,15 @@ static struct tc_action_ops *tc_lookup_action_n(char *kind) return a; } -/* lookup by rtattr */ -static struct tc_action_ops *tc_lookup_action(struct rtattr *kind) +/* lookup by nlattr */ +static struct tc_action_ops *tc_lookup_action(struct nlattr *kind) { struct tc_action_ops *a = NULL; if (kind) { read_lock(&act_mod_lock); for (a = act_base; a; a = a->next) { - if (rtattr_strcmp(kind, a->kind) == 0) { + if (nla_strcmp(kind, a->kind) == 0) { if (!try_module_get(a->owner)) { read_unlock(&act_mod_lock); return NULL; @@ -375,6 +383,7 @@ repeat: exec_done: return ret; } +EXPORT_SYMBOL(tcf_action_exec); void tcf_action_destroy(struct tc_action *act, int bind) { @@ -409,73 +418,77 @@ tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref) { int err = -EINVAL; unsigned char *b = skb_tail_pointer(skb); - struct rtattr *r; + struct nlattr *nest; if (a->ops == NULL || a->ops->dump == NULL) return err; - RTA_PUT(skb, TCA_KIND, IFNAMSIZ, a->ops->kind); + NLA_PUT_STRING(skb, TCA_KIND, a->ops->kind); if (tcf_action_copy_stats(skb, a, 0)) - goto rtattr_failure; - r = (struct rtattr *)skb_tail_pointer(skb); - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); + goto nla_put_failure; + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; if ((err = tcf_action_dump_old(skb, a, bind, ref)) > 0) { - r->rta_len = skb_tail_pointer(skb) - (u8 *)r; + nla_nest_end(skb, nest); return err; } -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } +EXPORT_SYMBOL(tcf_action_dump_1); int tcf_action_dump(struct sk_buff *skb, struct tc_action *act, int bind, int ref) { struct tc_action *a; int err = -EINVAL; - unsigned char *b = skb_tail_pointer(skb); - struct rtattr *r ; + struct nlattr *nest; while ((a = act) != NULL) { - r = (struct rtattr *)skb_tail_pointer(skb); act = a->next; - RTA_PUT(skb, a->order, 0, NULL); + nest = nla_nest_start(skb, a->order); + if (nest == NULL) + goto nla_put_failure; err = tcf_action_dump_1(skb, a, bind, ref); if (err < 0) goto errout; - r->rta_len = skb_tail_pointer(skb) - (u8 *)r; + nla_nest_end(skb, nest); } return 0; -rtattr_failure: +nla_put_failure: err = -EINVAL; errout: - nlmsg_trim(skb, b); + nla_nest_cancel(skb, nest); return err; } -struct tc_action *tcf_action_init_1(struct rtattr *rta, struct rtattr *est, - char *name, int ovr, int bind, int *err) +struct tc_action *tcf_action_init_1(struct nlattr *nla, struct nlattr *est, + char *name, int ovr, int bind) { struct tc_action *a; struct tc_action_ops *a_o; char act_name[IFNAMSIZ]; - struct rtattr *tb[TCA_ACT_MAX+1]; - struct rtattr *kind; - - *err = -EINVAL; + struct nlattr *tb[TCA_ACT_MAX+1]; + struct nlattr *kind; + int err; if (name == NULL) { - if (rtattr_parse_nested(tb, TCA_ACT_MAX, rta) < 0) + err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL); + if (err < 0) goto err_out; - kind = tb[TCA_ACT_KIND-1]; + err = -EINVAL; + kind = tb[TCA_ACT_KIND]; if (kind == NULL) goto err_out; - if (rtattr_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ) + if (nla_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ) goto err_out; } else { + err = -EINVAL; if (strlcpy(act_name, name, IFNAMSIZ) >= IFNAMSIZ) goto err_out; } @@ -496,36 +509,35 @@ struct tc_action *tcf_action_init_1(struct rtattr *rta, struct rtattr *est, * indicate this using -EAGAIN. */ if (a_o != NULL) { - *err = -EAGAIN; + err = -EAGAIN; goto err_mod; } #endif - *err = -ENOENT; + err = -ENOENT; goto err_out; } - *err = -ENOMEM; + err = -ENOMEM; a = kzalloc(sizeof(*a), GFP_KERNEL); if (a == NULL) goto err_mod; /* backward compatibility for policer */ if (name == NULL) - *err = a_o->init(tb[TCA_ACT_OPTIONS-1], est, a, ovr, bind); + err = a_o->init(tb[TCA_ACT_OPTIONS], est, a, ovr, bind); else - *err = a_o->init(rta, est, a, ovr, bind); - if (*err < 0) + err = a_o->init(nla, est, a, ovr, bind); + if (err < 0) goto err_free; /* module count goes up only when brand new policy is created if it exists and is only bound to in a_o->init() then ACT_P_CREATED is not returned (a zero is). */ - if (*err != ACT_P_CREATED) + if (err != ACT_P_CREATED) module_put(a_o->owner); a->ops = a_o; - *err = 0; return a; err_free: @@ -533,26 +545,26 @@ err_free: err_mod: module_put(a_o->owner); err_out: - return NULL; + return ERR_PTR(err); } -struct tc_action *tcf_action_init(struct rtattr *rta, struct rtattr *est, - char *name, int ovr, int bind, int *err) +struct tc_action *tcf_action_init(struct nlattr *nla, struct nlattr *est, + char *name, int ovr, int bind) { - struct rtattr *tb[TCA_ACT_MAX_PRIO+1]; + struct nlattr *tb[TCA_ACT_MAX_PRIO+1]; struct tc_action *head = NULL, *act, *act_prev = NULL; + int err; int i; - if (rtattr_parse_nested(tb, TCA_ACT_MAX_PRIO, rta) < 0) { - *err = -EINVAL; - return head; - } + err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL); + if (err < 0) + return ERR_PTR(err); - for (i=0; i < TCA_ACT_MAX_PRIO && tb[i]; i++) { - act = tcf_action_init_1(tb[i], est, name, ovr, bind, err); - if (act == NULL) + for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) { + act = tcf_action_init_1(tb[i], est, name, ovr, bind); + if (IS_ERR(act)) goto err; - act->order = i+1; + act->order = i; if (head == NULL) head = act; @@ -565,7 +577,7 @@ struct tc_action *tcf_action_init(struct rtattr *rta, struct rtattr *est, err: if (head != NULL) tcf_action_destroy(head, bind); - return NULL; + return act; } int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a, @@ -619,7 +631,7 @@ tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 pid, u32 seq, struct tcamsg *t; struct nlmsghdr *nlh; unsigned char *b = skb_tail_pointer(skb); - struct rtattr *x; + struct nlattr *nest; nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*t), flags); @@ -628,18 +640,19 @@ tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 pid, u32 seq, t->tca__pad1 = 0; t->tca__pad2 = 0; - x = (struct rtattr *)skb_tail_pointer(skb); - RTA_PUT(skb, TCA_ACT_TAB, 0, NULL); + nest = nla_nest_start(skb, TCA_ACT_TAB); + if (nest == NULL) + goto nla_put_failure; if (tcf_action_dump(skb, a, bind, ref) < 0) - goto rtattr_failure; + goto nla_put_failure; - x->rta_len = skb_tail_pointer(skb) - (u8 *)x; + nla_nest_end(skb, nest); nlh->nlmsg_len = skb_tail_pointer(skb) - b; return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_failure: nlmsg_trim(skb, b); return -1; @@ -658,48 +671,51 @@ act_get_notify(u32 pid, struct nlmsghdr *n, struct tc_action *a, int event) return -EINVAL; } - return rtnl_unicast(skb, pid); + return rtnl_unicast(skb, &init_net, pid); } static struct tc_action * -tcf_action_get_1(struct rtattr *rta, struct nlmsghdr *n, u32 pid, int *err) +tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 pid) { - struct rtattr *tb[TCA_ACT_MAX+1]; + struct nlattr *tb[TCA_ACT_MAX+1]; struct tc_action *a; int index; + int err; - *err = -EINVAL; - if (rtattr_parse_nested(tb, TCA_ACT_MAX, rta) < 0) - return NULL; + err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL); + if (err < 0) + goto err_out; - if (tb[TCA_ACT_INDEX - 1] == NULL || - RTA_PAYLOAD(tb[TCA_ACT_INDEX - 1]) < sizeof(index)) - return NULL; - index = *(int *)RTA_DATA(tb[TCA_ACT_INDEX - 1]); + err = -EINVAL; + if (tb[TCA_ACT_INDEX] == NULL || + nla_len(tb[TCA_ACT_INDEX]) < sizeof(index)) + goto err_out; + index = nla_get_u32(tb[TCA_ACT_INDEX]); - *err = -ENOMEM; + err = -ENOMEM; a = kzalloc(sizeof(struct tc_action), GFP_KERNEL); if (a == NULL) - return NULL; + goto err_out; - *err = -EINVAL; - a->ops = tc_lookup_action(tb[TCA_ACT_KIND - 1]); + err = -EINVAL; + a->ops = tc_lookup_action(tb[TCA_ACT_KIND]); if (a->ops == NULL) goto err_free; if (a->ops->lookup == NULL) goto err_mod; - *err = -ENOENT; + err = -ENOENT; if (a->ops->lookup(a, index) == 0) goto err_mod; module_put(a->ops->owner); - *err = 0; return a; + err_mod: module_put(a->ops->owner); err_free: kfree(a); - return NULL; +err_out: + return ERR_PTR(err); } static void cleanup_a(struct tc_action *act) @@ -725,16 +741,16 @@ static struct tc_action *create_a(int i) return act; } -static int tca_action_flush(struct rtattr *rta, struct nlmsghdr *n, u32 pid) +static int tca_action_flush(struct nlattr *nla, struct nlmsghdr *n, u32 pid) { struct sk_buff *skb; unsigned char *b; struct nlmsghdr *nlh; struct tcamsg *t; struct netlink_callback dcb; - struct rtattr *x; - struct rtattr *tb[TCA_ACT_MAX+1]; - struct rtattr *kind; + struct nlattr *nest; + struct nlattr *tb[TCA_ACT_MAX+1]; + struct nlattr *kind; struct tc_action *a = create_a(0); int err = -EINVAL; @@ -752,10 +768,12 @@ static int tca_action_flush(struct rtattr *rta, struct nlmsghdr *n, u32 pid) b = skb_tail_pointer(skb); - if (rtattr_parse_nested(tb, TCA_ACT_MAX, rta) < 0) + err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL); + if (err < 0) goto err_out; - kind = tb[TCA_ACT_KIND-1]; + err = -EINVAL; + kind = tb[TCA_ACT_KIND]; a->ops = tc_lookup_action(kind); if (a->ops == NULL) goto err_out; @@ -766,26 +784,27 @@ static int tca_action_flush(struct rtattr *rta, struct nlmsghdr *n, u32 pid) t->tca__pad1 = 0; t->tca__pad2 = 0; - x = (struct rtattr *)skb_tail_pointer(skb); - RTA_PUT(skb, TCA_ACT_TAB, 0, NULL); + nest = nla_nest_start(skb, TCA_ACT_TAB); + if (nest == NULL) + goto nla_put_failure; err = a->ops->walk(skb, &dcb, RTM_DELACTION, a); if (err < 0) - goto rtattr_failure; + goto nla_put_failure; - x->rta_len = skb_tail_pointer(skb) - (u8 *)x; + nla_nest_end(skb, nest); nlh->nlmsg_len = skb_tail_pointer(skb) - b; nlh->nlmsg_flags |= NLM_F_ROOT; module_put(a->ops->owner); kfree(a); - err = rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); + err = rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); if (err > 0) return 0; return err; -rtattr_failure: +nla_put_failure: nlmsg_failure: module_put(a->ops->owner); err_out: @@ -795,25 +814,28 @@ err_out: } static int -tca_action_gd(struct rtattr *rta, struct nlmsghdr *n, u32 pid, int event) +tca_action_gd(struct nlattr *nla, struct nlmsghdr *n, u32 pid, int event) { - int i, ret = 0; - struct rtattr *tb[TCA_ACT_MAX_PRIO+1]; + int i, ret; + struct nlattr *tb[TCA_ACT_MAX_PRIO+1]; struct tc_action *head = NULL, *act, *act_prev = NULL; - if (rtattr_parse_nested(tb, TCA_ACT_MAX_PRIO, rta) < 0) - return -EINVAL; + ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL); + if (ret < 0) + return ret; if (event == RTM_DELACTION && n->nlmsg_flags&NLM_F_ROOT) { if (tb[0] != NULL && tb[1] == NULL) return tca_action_flush(tb[0], n, pid); } - for (i=0; i < TCA_ACT_MAX_PRIO && tb[i]; i++) { - act = tcf_action_get_1(tb[i], n, pid, &ret); - if (act == NULL) + for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) { + act = tcf_action_get_1(tb[i], n, pid); + if (IS_ERR(act)) { + ret = PTR_ERR(act); goto err; - act->order = i+1; + } + act->order = i; if (head == NULL) head = act; @@ -842,7 +864,7 @@ tca_action_gd(struct rtattr *rta, struct nlmsghdr *n, u32 pid, int event) /* now do the delete */ tcf_action_destroy(head, 0); - ret = rtnetlink_send(skb, pid, RTNLGRP_TC, + ret = rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); if (ret > 0) return 0; @@ -859,7 +881,7 @@ static int tcf_add_notify(struct tc_action *a, u32 pid, u32 seq, int event, struct tcamsg *t; struct nlmsghdr *nlh; struct sk_buff *skb; - struct rtattr *x; + struct nlattr *nest; unsigned char *b; int err = 0; @@ -875,23 +897,24 @@ static int tcf_add_notify(struct tc_action *a, u32 pid, u32 seq, int event, t->tca__pad1 = 0; t->tca__pad2 = 0; - x = (struct rtattr *)skb_tail_pointer(skb); - RTA_PUT(skb, TCA_ACT_TAB, 0, NULL); + nest = nla_nest_start(skb, TCA_ACT_TAB); + if (nest == NULL) + goto nla_put_failure; if (tcf_action_dump(skb, a, 0, 0) < 0) - goto rtattr_failure; + goto nla_put_failure; - x->rta_len = skb_tail_pointer(skb) - (u8 *)x; + nla_nest_end(skb, nest); nlh->nlmsg_len = skb_tail_pointer(skb) - b; NETLINK_CB(skb).dst_group = RTNLGRP_TC; - err = rtnetlink_send(skb, pid, RTNLGRP_TC, flags&NLM_F_ECHO); + err = rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, flags&NLM_F_ECHO); if (err > 0) err = 0; return err; -rtattr_failure: +nla_put_failure: nlmsg_failure: kfree_skb(skb); return -1; @@ -899,16 +922,20 @@ nlmsg_failure: static int -tcf_action_add(struct rtattr *rta, struct nlmsghdr *n, u32 pid, int ovr) +tcf_action_add(struct nlattr *nla, struct nlmsghdr *n, u32 pid, int ovr) { int ret = 0; struct tc_action *act; struct tc_action *a; u32 seq = n->nlmsg_seq; - act = tcf_action_init(rta, NULL, NULL, ovr, 0, &ret); + act = tcf_action_init(nla, NULL, NULL, ovr, 0); if (act == NULL) goto done; + if (IS_ERR(act)) { + ret = PTR_ERR(act); + goto done; + } /* dump then free all the actions after update; inserted policy * stays intact @@ -924,11 +951,19 @@ done: static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { - struct rtattr **tca = arg; + struct net *net = skb->sk->sk_net; + struct nlattr *tca[TCA_ACT_MAX + 1]; u32 pid = skb ? NETLINK_CB(skb).pid : 0; int ret = 0, ovr = 0; - if (tca[TCA_ACT_TAB-1] == NULL) { + if (net != &init_net) + return -EINVAL; + + ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL); + if (ret < 0) + return ret; + + if (tca[TCA_ACT_TAB] == NULL) { printk("tc_ctl_action: received NO action attribs\n"); return -EINVAL; } @@ -946,15 +981,15 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg) if (n->nlmsg_flags&NLM_F_REPLACE) ovr = 1; replay: - ret = tcf_action_add(tca[TCA_ACT_TAB-1], n, pid, ovr); + ret = tcf_action_add(tca[TCA_ACT_TAB], n, pid, ovr); if (ret == -EAGAIN) goto replay; break; case RTM_DELACTION: - ret = tca_action_gd(tca[TCA_ACT_TAB-1], n, pid, RTM_DELACTION); + ret = tca_action_gd(tca[TCA_ACT_TAB], n, pid, RTM_DELACTION); break; case RTM_GETACTION: - ret = tca_action_gd(tca[TCA_ACT_TAB-1], n, pid, RTM_GETACTION); + ret = tca_action_gd(tca[TCA_ACT_TAB], n, pid, RTM_GETACTION); break; default: BUG(); @@ -963,33 +998,30 @@ replay: return ret; } -static struct rtattr * +static struct nlattr * find_dump_kind(struct nlmsghdr *n) { - struct rtattr *tb1, *tb2[TCA_ACT_MAX+1]; - struct rtattr *tb[TCA_ACT_MAX_PRIO + 1]; - struct rtattr *rta[TCAA_MAX + 1]; - struct rtattr *kind; - int min_len = NLMSG_LENGTH(sizeof(struct tcamsg)); - int attrlen = n->nlmsg_len - NLMSG_ALIGN(min_len); - struct rtattr *attr = (void *) n + NLMSG_ALIGN(min_len); - - if (rtattr_parse(rta, TCAA_MAX, attr, attrlen) < 0) + struct nlattr *tb1, *tb2[TCA_ACT_MAX+1]; + struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; + struct nlattr *nla[TCAA_MAX + 1]; + struct nlattr *kind; + + if (nlmsg_parse(n, sizeof(struct tcamsg), nla, TCAA_MAX, NULL) < 0) return NULL; - tb1 = rta[TCA_ACT_TAB - 1]; + tb1 = nla[TCA_ACT_TAB]; if (tb1 == NULL) return NULL; - if (rtattr_parse(tb, TCA_ACT_MAX_PRIO, RTA_DATA(tb1), - NLMSG_ALIGN(RTA_PAYLOAD(tb1))) < 0) - return NULL; - if (tb[0] == NULL) + if (nla_parse(tb, TCA_ACT_MAX_PRIO, nla_data(tb1), + NLMSG_ALIGN(nla_len(tb1)), NULL) < 0) return NULL; - if (rtattr_parse(tb2, TCA_ACT_MAX, RTA_DATA(tb[0]), - RTA_PAYLOAD(tb[0])) < 0) + if (tb[1] == NULL) return NULL; - kind = tb2[TCA_ACT_KIND-1]; + if (nla_parse(tb2, TCA_ACT_MAX, nla_data(tb[1]), + nla_len(tb[1]), NULL) < 0) + return NULL; + kind = tb2[TCA_ACT_KIND]; return kind; } @@ -997,14 +1029,18 @@ find_dump_kind(struct nlmsghdr *n) static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) { + struct net *net = skb->sk->sk_net; struct nlmsghdr *nlh; unsigned char *b = skb_tail_pointer(skb); - struct rtattr *x; + struct nlattr *nest; struct tc_action_ops *a_o; struct tc_action a; int ret = 0; struct tcamsg *t = (struct tcamsg *) NLMSG_DATA(cb->nlh); - struct rtattr *kind = find_dump_kind(cb->nlh); + struct nlattr *kind = find_dump_kind(cb->nlh); + + if (net != &init_net) + return 0; if (kind == NULL) { printk("tc_dump_action: action bad kind\n"); @@ -1021,7 +1057,7 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) if (a_o->walk == NULL) { printk("tc_dump_action: %s !capable of dumping table\n", a_o->kind); - goto rtattr_failure; + goto nla_put_failure; } nlh = NLMSG_PUT(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, @@ -1031,18 +1067,19 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) t->tca__pad1 = 0; t->tca__pad2 = 0; - x = (struct rtattr *)skb_tail_pointer(skb); - RTA_PUT(skb, TCA_ACT_TAB, 0, NULL); + nest = nla_nest_start(skb, TCA_ACT_TAB); + if (nest == NULL) + goto nla_put_failure; ret = a_o->walk(skb, cb, RTM_GETACTION, &a); if (ret < 0) - goto rtattr_failure; + goto nla_put_failure; if (ret > 0) { - x->rta_len = skb_tail_pointer(skb) - (u8 *)x; + nla_nest_end(skb, nest); ret = skb->len; } else - nlmsg_trim(skb, x); + nla_nest_cancel(skb, nest); nlh->nlmsg_len = skb_tail_pointer(skb) - b; if (NETLINK_CB(cb->skb).pid && ret) @@ -1050,7 +1087,7 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) module_put(a_o->owner); return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_failure: module_put(a_o->owner); nlmsg_trim(skb, b); @@ -1067,8 +1104,3 @@ static int __init tc_action_init(void) } subsys_initcall(tc_action_init); - -EXPORT_SYMBOL(tcf_register_action); -EXPORT_SYMBOL(tcf_unregister_action); -EXPORT_SYMBOL(tcf_action_exec); -EXPORT_SYMBOL(tcf_action_dump_1); diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index a9631e426d9..422872c4f14 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -53,28 +53,34 @@ typedef int (*g_rand)(struct tcf_gact *gact); static g_rand gact_rand[MAX_RAND]= { NULL, gact_net_rand, gact_determ }; #endif /* CONFIG_GACT_PROB */ -static int tcf_gact_init(struct rtattr *rta, struct rtattr *est, +static const struct nla_policy gact_policy[TCA_GACT_MAX + 1] = { + [TCA_GACT_PARMS] = { .len = sizeof(struct tc_gact) }, + [TCA_GACT_PROB] = { .len = sizeof(struct tc_gact_p) }, +}; + +static int tcf_gact_init(struct nlattr *nla, struct nlattr *est, struct tc_action *a, int ovr, int bind) { - struct rtattr *tb[TCA_GACT_MAX]; + struct nlattr *tb[TCA_GACT_MAX + 1]; struct tc_gact *parm; struct tcf_gact *gact; struct tcf_common *pc; int ret = 0; + int err; - if (rta == NULL || rtattr_parse_nested(tb, TCA_GACT_MAX, rta) < 0) + if (nla == NULL) return -EINVAL; - if (tb[TCA_GACT_PARMS - 1] == NULL || - RTA_PAYLOAD(tb[TCA_GACT_PARMS - 1]) < sizeof(*parm)) + err = nla_parse_nested(tb, TCA_GACT_MAX, nla, gact_policy); + if (err < 0) + return err; + + if (tb[TCA_GACT_PARMS] == NULL) return -EINVAL; - parm = RTA_DATA(tb[TCA_GACT_PARMS - 1]); + parm = nla_data(tb[TCA_GACT_PARMS]); - if (tb[TCA_GACT_PROB-1] != NULL) -#ifdef CONFIG_GACT_PROB - if (RTA_PAYLOAD(tb[TCA_GACT_PROB-1]) < sizeof(struct tc_gact_p)) - return -EINVAL; -#else +#ifndef CONFIG_GACT_PROB + if (tb[TCA_GACT_PROB] != NULL) return -EOPNOTSUPP; #endif @@ -97,8 +103,8 @@ static int tcf_gact_init(struct rtattr *rta, struct rtattr *est, spin_lock_bh(&gact->tcf_lock); gact->tcf_action = parm->action; #ifdef CONFIG_GACT_PROB - if (tb[TCA_GACT_PROB-1] != NULL) { - struct tc_gact_p *p_parm = RTA_DATA(tb[TCA_GACT_PROB-1]); + if (tb[TCA_GACT_PROB] != NULL) { + struct tc_gact_p *p_parm = nla_data(tb[TCA_GACT_PROB]); gact->tcfg_paction = p_parm->paction; gact->tcfg_pval = p_parm->pval; gact->tcfg_ptype = p_parm->ptype; @@ -154,23 +160,23 @@ static int tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int opt.refcnt = gact->tcf_refcnt - ref; opt.bindcnt = gact->tcf_bindcnt - bind; opt.action = gact->tcf_action; - RTA_PUT(skb, TCA_GACT_PARMS, sizeof(opt), &opt); + NLA_PUT(skb, TCA_GACT_PARMS, sizeof(opt), &opt); #ifdef CONFIG_GACT_PROB if (gact->tcfg_ptype) { struct tc_gact_p p_opt; p_opt.paction = gact->tcfg_paction; p_opt.pval = gact->tcfg_pval; p_opt.ptype = gact->tcfg_ptype; - RTA_PUT(skb, TCA_GACT_PROB, sizeof(p_opt), &p_opt); + NLA_PUT(skb, TCA_GACT_PROB, sizeof(p_opt), &p_opt); } #endif t.install = jiffies_to_clock_t(jiffies - gact->tcf_tm.install); t.lastuse = jiffies_to_clock_t(jiffies - gact->tcf_tm.lastuse); t.expires = jiffies_to_clock_t(gact->tcf_tm.expires); - RTA_PUT(skb, TCA_GACT_TM, sizeof(t), &t); + NLA_PUT(skb, TCA_GACT_TM, sizeof(t), &t); return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index fa006e06ce3..da696fd3e34 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c @@ -92,10 +92,17 @@ static int tcf_ipt_release(struct tcf_ipt *ipt, int bind) return ret; } -static int tcf_ipt_init(struct rtattr *rta, struct rtattr *est, +static const struct nla_policy ipt_policy[TCA_IPT_MAX + 1] = { + [TCA_IPT_TABLE] = { .type = NLA_STRING, .len = IFNAMSIZ }, + [TCA_IPT_HOOK] = { .type = NLA_U32 }, + [TCA_IPT_INDEX] = { .type = NLA_U32 }, + [TCA_IPT_TARG] = { .len = sizeof(struct ipt_entry_target) }, +}; + +static int tcf_ipt_init(struct nlattr *nla, struct nlattr *est, struct tc_action *a, int ovr, int bind) { - struct rtattr *tb[TCA_IPT_MAX]; + struct nlattr *tb[TCA_IPT_MAX + 1]; struct tcf_ipt *ipt; struct tcf_common *pc; struct ipt_entry_target *td, *t; @@ -104,22 +111,24 @@ static int tcf_ipt_init(struct rtattr *rta, struct rtattr *est, u32 hook = 0; u32 index = 0; - if (rta == NULL || rtattr_parse_nested(tb, TCA_IPT_MAX, rta) < 0) + if (nla == NULL) return -EINVAL; - if (tb[TCA_IPT_HOOK-1] == NULL || - RTA_PAYLOAD(tb[TCA_IPT_HOOK-1]) < sizeof(u32)) + err = nla_parse_nested(tb, TCA_IPT_MAX, nla, ipt_policy); + if (err < 0) + return err; + + if (tb[TCA_IPT_HOOK] == NULL) return -EINVAL; - if (tb[TCA_IPT_TARG-1] == NULL || - RTA_PAYLOAD(tb[TCA_IPT_TARG-1]) < sizeof(*t)) + if (tb[TCA_IPT_TARG] == NULL) return -EINVAL; - td = (struct ipt_entry_target *)RTA_DATA(tb[TCA_IPT_TARG-1]); - if (RTA_PAYLOAD(tb[TCA_IPT_TARG-1]) < td->u.target_size) + + td = (struct ipt_entry_target *)nla_data(tb[TCA_IPT_TARG]); + if (nla_len(tb[TCA_IPT_TARG]) < td->u.target_size) return -EINVAL; - if (tb[TCA_IPT_INDEX-1] != NULL && - RTA_PAYLOAD(tb[TCA_IPT_INDEX-1]) >= sizeof(u32)) - index = *(u32 *)RTA_DATA(tb[TCA_IPT_INDEX-1]); + if (tb[TCA_IPT_INDEX] != NULL) + index = nla_get_u32(tb[TCA_IPT_INDEX]); pc = tcf_hash_check(index, a, bind, &ipt_hash_info); if (!pc) { @@ -136,14 +145,14 @@ static int tcf_ipt_init(struct rtattr *rta, struct rtattr *est, } ipt = to_ipt(pc); - hook = *(u32 *)RTA_DATA(tb[TCA_IPT_HOOK-1]); + hook = nla_get_u32(tb[TCA_IPT_HOOK]); err = -ENOMEM; tname = kmalloc(IFNAMSIZ, GFP_KERNEL); if (unlikely(!tname)) goto err1; - if (tb[TCA_IPT_TABLE - 1] == NULL || - rtattr_strlcpy(tname, tb[TCA_IPT_TABLE-1], IFNAMSIZ) >= IFNAMSIZ) + if (tb[TCA_IPT_TABLE] == NULL || + nla_strlcpy(tname, tb[TCA_IPT_TABLE], IFNAMSIZ) >= IFNAMSIZ) strcpy(tname, "mangle"); t = kmemdup(td, td->u.target_size, GFP_KERNEL); @@ -243,25 +252,25 @@ static int tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int t = kmemdup(ipt->tcfi_t, ipt->tcfi_t->u.user.target_size, GFP_ATOMIC); if (unlikely(!t)) - goto rtattr_failure; + goto nla_put_failure; c.bindcnt = ipt->tcf_bindcnt - bind; c.refcnt = ipt->tcf_refcnt - ref; strcpy(t->u.user.name, ipt->tcfi_t->u.kernel.target->name); - RTA_PUT(skb, TCA_IPT_TARG, ipt->tcfi_t->u.user.target_size, t); - RTA_PUT(skb, TCA_IPT_INDEX, 4, &ipt->tcf_index); - RTA_PUT(skb, TCA_IPT_HOOK, 4, &ipt->tcfi_hook); - RTA_PUT(skb, TCA_IPT_CNT, sizeof(struct tc_cnt), &c); - RTA_PUT(skb, TCA_IPT_TABLE, IFNAMSIZ, ipt->tcfi_tname); + NLA_PUT(skb, TCA_IPT_TARG, ipt->tcfi_t->u.user.target_size, t); + NLA_PUT_U32(skb, TCA_IPT_INDEX, ipt->tcf_index); + NLA_PUT_U32(skb, TCA_IPT_HOOK, ipt->tcfi_hook); + NLA_PUT(skb, TCA_IPT_CNT, sizeof(struct tc_cnt), &c); + NLA_PUT_STRING(skb, TCA_IPT_TABLE, ipt->tcfi_tname); tm.install = jiffies_to_clock_t(jiffies - ipt->tcf_tm.install); tm.lastuse = jiffies_to_clock_t(jiffies - ipt->tcf_tm.lastuse); tm.expires = jiffies_to_clock_t(ipt->tcf_tm.expires); - RTA_PUT(skb, TCA_IPT_TM, sizeof (tm), &tm); + NLA_PUT(skb, TCA_IPT_TM, sizeof (tm), &tm); kfree(t); return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); kfree(t); return -1; diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index c3fde9180f9..1aff005d95c 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -54,24 +54,31 @@ static inline int tcf_mirred_release(struct tcf_mirred *m, int bind) return 0; } -static int tcf_mirred_init(struct rtattr *rta, struct rtattr *est, +static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = { + [TCA_MIRRED_PARMS] = { .len = sizeof(struct tc_mirred) }, +}; + +static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est, struct tc_action *a, int ovr, int bind) { - struct rtattr *tb[TCA_MIRRED_MAX]; + struct nlattr *tb[TCA_MIRRED_MAX + 1]; struct tc_mirred *parm; struct tcf_mirred *m; struct tcf_common *pc; struct net_device *dev = NULL; - int ret = 0; + int ret = 0, err; int ok_push = 0; - if (rta == NULL || rtattr_parse_nested(tb, TCA_MIRRED_MAX, rta) < 0) + if (nla == NULL) return -EINVAL; - if (tb[TCA_MIRRED_PARMS-1] == NULL || - RTA_PAYLOAD(tb[TCA_MIRRED_PARMS-1]) < sizeof(*parm)) + err = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy); + if (err < 0) + return err; + + if (tb[TCA_MIRRED_PARMS] == NULL) return -EINVAL; - parm = RTA_DATA(tb[TCA_MIRRED_PARMS-1]); + parm = nla_data(tb[TCA_MIRRED_PARMS]); if (parm->ifindex) { dev = __dev_get_by_index(&init_net, parm->ifindex); @@ -207,14 +214,14 @@ static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, i opt.bindcnt = m->tcf_bindcnt - bind; opt.eaction = m->tcfm_eaction; opt.ifindex = m->tcfm_ifindex; - RTA_PUT(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt); + NLA_PUT(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt); t.install = jiffies_to_clock_t(jiffies - m->tcf_tm.install); t.lastuse = jiffies_to_clock_t(jiffies - m->tcf_tm.lastuse); t.expires = jiffies_to_clock_t(m->tcf_tm.expires); - RTA_PUT(skb, TCA_MIRRED_TM, sizeof(t), &t); + NLA_PUT(skb, TCA_MIRRED_TM, sizeof(t), &t); return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index c96273bcaf9..0a3c8339767 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c @@ -40,22 +40,29 @@ static struct tcf_hashinfo nat_hash_info = { .lock = &nat_lock, }; -static int tcf_nat_init(struct rtattr *rta, struct rtattr *est, +static const struct nla_policy nat_policy[TCA_NAT_MAX + 1] = { + [TCA_NAT_PARMS] = { .len = sizeof(struct tc_nat) }, +}; + +static int tcf_nat_init(struct nlattr *nla, struct nlattr *est, struct tc_action *a, int ovr, int bind) { - struct rtattr *tb[TCA_NAT_MAX]; + struct nlattr *tb[TCA_NAT_MAX + 1]; struct tc_nat *parm; - int ret = 0; + int ret = 0, err; struct tcf_nat *p; struct tcf_common *pc; - if (rta == NULL || rtattr_parse_nested(tb, TCA_NAT_MAX, rta) < 0) + if (nla == NULL) return -EINVAL; - if (tb[TCA_NAT_PARMS - 1] == NULL || - RTA_PAYLOAD(tb[TCA_NAT_PARMS - 1]) < sizeof(*parm)) + err = nla_parse_nested(tb, TCA_NAT_MAX, nla, nat_policy); + if (err < 0) + return err; + + if (tb[TCA_NAT_PARMS] == NULL) return -EINVAL; - parm = RTA_DATA(tb[TCA_NAT_PARMS - 1]); + parm = nla_data(tb[TCA_NAT_PARMS]); pc = tcf_hash_check(parm->index, a, bind, &nat_hash_info); if (!pc) { @@ -151,7 +158,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, else iph->daddr = new_addr; - nf_csum_replace4(&iph->check, addr, new_addr); + csum_replace4(&iph->check, addr, new_addr); } ihl = iph->ihl * 4; @@ -169,7 +176,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, goto drop; tcph = (void *)(skb_network_header(skb) + ihl); - nf_proto_csum_replace4(&tcph->check, skb, addr, new_addr, 1); + inet_proto_csum_replace4(&tcph->check, skb, addr, new_addr, 1); break; } case IPPROTO_UDP: @@ -184,8 +191,8 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, udph = (void *)(skb_network_header(skb) + ihl); if (udph->check || skb->ip_summed == CHECKSUM_PARTIAL) { - nf_proto_csum_replace4(&udph->check, skb, addr, - new_addr, 1); + inet_proto_csum_replace4(&udph->check, skb, addr, + new_addr, 1); if (!udph->check) udph->check = CSUM_MANGLED_0; } @@ -232,8 +239,8 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, else iph->saddr = new_addr; - nf_proto_csum_replace4(&icmph->checksum, skb, addr, new_addr, - 1); + inet_proto_csum_replace4(&icmph->checksum, skb, addr, new_addr, + 1); break; } default: @@ -275,17 +282,17 @@ static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a, opt->refcnt = p->tcf_refcnt - ref; opt->bindcnt = p->tcf_bindcnt - bind; - RTA_PUT(skb, TCA_NAT_PARMS, s, opt); + NLA_PUT(skb, TCA_NAT_PARMS, s, opt); t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install); t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse); t.expires = jiffies_to_clock_t(p->tcf_tm.expires); - RTA_PUT(skb, TCA_NAT_TM, sizeof(t), &t); + NLA_PUT(skb, TCA_NAT_TM, sizeof(t), &t); kfree(opt); return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); kfree(opt); return -1; diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index b46fab5fb32..3cc4cb9e500 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -33,26 +33,33 @@ static struct tcf_hashinfo pedit_hash_info = { .lock = &pedit_lock, }; -static int tcf_pedit_init(struct rtattr *rta, struct rtattr *est, +static const struct nla_policy pedit_policy[TCA_PEDIT_MAX + 1] = { + [TCA_PEDIT_PARMS] = { .len = sizeof(struct tcf_pedit) }, +}; + +static int tcf_pedit_init(struct nlattr *nla, struct nlattr *est, struct tc_action *a, int ovr, int bind) { - struct rtattr *tb[TCA_PEDIT_MAX]; + struct nlattr *tb[TCA_PEDIT_MAX + 1]; struct tc_pedit *parm; - int ret = 0; + int ret = 0, err; struct tcf_pedit *p; struct tcf_common *pc; struct tc_pedit_key *keys = NULL; int ksize; - if (rta == NULL || rtattr_parse_nested(tb, TCA_PEDIT_MAX, rta) < 0) + if (nla == NULL) return -EINVAL; - if (tb[TCA_PEDIT_PARMS - 1] == NULL || - RTA_PAYLOAD(tb[TCA_PEDIT_PARMS-1]) < sizeof(*parm)) + err = nla_parse_nested(tb, TCA_PEDIT_MAX, nla, pedit_policy); + if (err < 0) + return err; + + if (tb[TCA_PEDIT_PARMS] == NULL) return -EINVAL; - parm = RTA_DATA(tb[TCA_PEDIT_PARMS-1]); + parm = nla_data(tb[TCA_PEDIT_PARMS]); ksize = parm->nkeys * sizeof(struct tc_pedit_key); - if (RTA_PAYLOAD(tb[TCA_PEDIT_PARMS-1]) < sizeof(*parm) + ksize) + if (nla_len(tb[TCA_PEDIT_PARMS]) < sizeof(*parm) + ksize) return -EINVAL; pc = tcf_hash_check(parm->index, a, bind, &pedit_hash_info); @@ -206,15 +213,15 @@ static int tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a, opt->refcnt = p->tcf_refcnt - ref; opt->bindcnt = p->tcf_bindcnt - bind; - RTA_PUT(skb, TCA_PEDIT_PARMS, s, opt); + NLA_PUT(skb, TCA_PEDIT_PARMS, s, opt); t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install); t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse); t.expires = jiffies_to_clock_t(p->tcf_tm.expires); - RTA_PUT(skb, TCA_PEDIT_TM, sizeof(t), &t); + NLA_PUT(skb, TCA_PEDIT_TM, sizeof(t), &t); kfree(opt); return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); kfree(opt); return -1; diff --git a/net/sched/act_police.c b/net/sched/act_police.c index a73e3e6d87e..0898120bbcc 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -54,7 +54,7 @@ static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *c { struct tcf_common *p; int err = 0, index = -1, i = 0, s_i = 0, n_i = 0; - struct rtattr *r; + struct nlattr *nest; read_lock_bh(&police_lock); @@ -69,18 +69,19 @@ static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *c continue; a->priv = p; a->order = index; - r = (struct rtattr *)skb_tail_pointer(skb); - RTA_PUT(skb, a->order, 0, NULL); + nest = nla_nest_start(skb, a->order); + if (nest == NULL) + goto nla_put_failure; if (type == RTM_DELACTION) err = tcf_action_dump_1(skb, a, 0, 1); else err = tcf_action_dump_1(skb, a, 0, 0); if (err < 0) { index--; - nlmsg_trim(skb, r); + nla_nest_cancel(skb, nest); goto done; } - r->rta_len = skb_tail_pointer(skb) - (u8 *)r; + nla_nest_end(skb, nest); n_i++; } } @@ -90,8 +91,8 @@ done: cb->args[0] += n_i; return n_i; -rtattr_failure: - nlmsg_trim(skb, r); +nla_put_failure: + nla_nest_cancel(skb, nest); goto done; } @@ -118,33 +119,37 @@ static void tcf_police_destroy(struct tcf_police *p) BUG_TRAP(0); } -static int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est, +static const struct nla_policy police_policy[TCA_POLICE_MAX + 1] = { + [TCA_POLICE_RATE] = { .len = TC_RTAB_SIZE }, + [TCA_POLICE_PEAKRATE] = { .len = TC_RTAB_SIZE }, + [TCA_POLICE_AVRATE] = { .type = NLA_U32 }, + [TCA_POLICE_RESULT] = { .type = NLA_U32 }, +}; + +static int tcf_act_police_locate(struct nlattr *nla, struct nlattr *est, struct tc_action *a, int ovr, int bind) { unsigned h; int ret = 0, err; - struct rtattr *tb[TCA_POLICE_MAX]; + struct nlattr *tb[TCA_POLICE_MAX + 1]; struct tc_police *parm; struct tcf_police *police; struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL; int size; - if (rta == NULL || rtattr_parse_nested(tb, TCA_POLICE_MAX, rta) < 0) + if (nla == NULL) return -EINVAL; - if (tb[TCA_POLICE_TBF-1] == NULL) - return -EINVAL; - size = RTA_PAYLOAD(tb[TCA_POLICE_TBF-1]); - if (size != sizeof(*parm) && size != sizeof(struct tc_police_compat)) - return -EINVAL; - parm = RTA_DATA(tb[TCA_POLICE_TBF-1]); + err = nla_parse_nested(tb, TCA_POLICE_MAX, nla, police_policy); + if (err < 0) + return err; - if (tb[TCA_POLICE_RESULT-1] != NULL && - RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32)) + if (tb[TCA_POLICE_TBF] == NULL) return -EINVAL; - if (tb[TCA_POLICE_RESULT-1] != NULL && - RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32)) + size = nla_len(tb[TCA_POLICE_TBF]); + if (size != sizeof(*parm) && size != sizeof(struct tc_police_compat)) return -EINVAL; + parm = nla_data(tb[TCA_POLICE_TBF]); if (parm->index) { struct tcf_common *pc; @@ -174,12 +179,12 @@ static int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est, override: if (parm->rate.rate) { err = -ENOMEM; - R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1]); + R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE]); if (R_tab == NULL) goto failure; if (parm->peakrate.rate) { P_tab = qdisc_get_rtab(&parm->peakrate, - tb[TCA_POLICE_PEAKRATE-1]); + tb[TCA_POLICE_PEAKRATE]); if (P_tab == NULL) { qdisc_put_rtab(R_tab); goto failure; @@ -197,8 +202,8 @@ override: police->tcfp_P_tab = P_tab; } - if (tb[TCA_POLICE_RESULT-1]) - police->tcfp_result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]); + if (tb[TCA_POLICE_RESULT]) + police->tcfp_result = nla_get_u32(tb[TCA_POLICE_RESULT]); police->tcfp_toks = police->tcfp_burst = parm->burst; police->tcfp_mtu = parm->mtu; if (police->tcfp_mtu == 0) { @@ -210,9 +215,8 @@ override: police->tcfp_ptoks = L2T_P(police, police->tcfp_mtu); police->tcf_action = parm->action; - if (tb[TCA_POLICE_AVRATE-1]) - police->tcfp_ewma_rate = - *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]); + if (tb[TCA_POLICE_AVRATE]) + police->tcfp_ewma_rate = nla_get_u32(tb[TCA_POLICE_AVRATE]); if (est) gen_replace_estimator(&police->tcf_bstats, &police->tcf_rate_est, @@ -332,15 +336,14 @@ tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) opt.peakrate = police->tcfp_P_tab->rate; else memset(&opt.peakrate, 0, sizeof(opt.peakrate)); - RTA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt); + NLA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt); if (police->tcfp_result) - RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int), - &police->tcfp_result); + NLA_PUT_U32(skb, TCA_POLICE_RESULT, police->tcfp_result); if (police->tcfp_ewma_rate) - RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &police->tcfp_ewma_rate); + NLA_PUT_U32(skb, TCA_POLICE_AVRATE, police->tcfp_ewma_rate); return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index fb84ef33d14..fbde461b716 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -84,30 +84,37 @@ static int realloc_defdata(struct tcf_defact *d, u32 datalen, void *defdata) return alloc_defdata(d, datalen, defdata); } -static int tcf_simp_init(struct rtattr *rta, struct rtattr *est, +static const struct nla_policy simple_policy[TCA_DEF_MAX + 1] = { + [TCA_DEF_PARMS] = { .len = sizeof(struct tc_defact) }, +}; + +static int tcf_simp_init(struct nlattr *nla, struct nlattr *est, struct tc_action *a, int ovr, int bind) { - struct rtattr *tb[TCA_DEF_MAX]; + struct nlattr *tb[TCA_DEF_MAX + 1]; struct tc_defact *parm; struct tcf_defact *d; struct tcf_common *pc; void *defdata; u32 datalen = 0; - int ret = 0; + int ret = 0, err; - if (rta == NULL || rtattr_parse_nested(tb, TCA_DEF_MAX, rta) < 0) + if (nla == NULL) return -EINVAL; - if (tb[TCA_DEF_PARMS - 1] == NULL || - RTA_PAYLOAD(tb[TCA_DEF_PARMS - 1]) < sizeof(*parm)) + err = nla_parse_nested(tb, TCA_DEF_MAX, nla, NULL); + if (err < 0) + return err; + + if (tb[TCA_DEF_PARMS] == NULL) return -EINVAL; - parm = RTA_DATA(tb[TCA_DEF_PARMS - 1]); - defdata = RTA_DATA(tb[TCA_DEF_DATA - 1]); + parm = nla_data(tb[TCA_DEF_PARMS]); + defdata = nla_data(tb[TCA_DEF_DATA]); if (defdata == NULL) return -EINVAL; - datalen = RTA_PAYLOAD(tb[TCA_DEF_DATA - 1]); + datalen = nla_len(tb[TCA_DEF_DATA]); if (datalen <= 0) return -EINVAL; @@ -164,15 +171,15 @@ static inline int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a, opt.refcnt = d->tcf_refcnt - ref; opt.bindcnt = d->tcf_bindcnt - bind; opt.action = d->tcf_action; - RTA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt); - RTA_PUT(skb, TCA_DEF_DATA, d->tcfd_datalen, d->tcfd_defdata); + NLA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt); + NLA_PUT(skb, TCA_DEF_DATA, d->tcfd_datalen, d->tcfd_defdata); t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install); t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse); t.expires = jiffies_to_clock_t(d->tcf_tm.expires); - RTA_PUT(skb, TCA_DEF_TM, sizeof(t), &t); + NLA_PUT(skb, TCA_DEF_TM, sizeof(t), &t); return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 03657976fd5..3377ca0d0a0 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -23,33 +23,30 @@ #include <linux/init.h> #include <linux/kmod.h> #include <linux/netlink.h> +#include <linux/err.h> +#include <net/net_namespace.h> +#include <net/sock.h> #include <net/netlink.h> #include <net/pkt_sched.h> #include <net/pkt_cls.h> -#if 0 /* control */ -#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define DPRINTK(format,args...) -#endif - /* The list of all installed classifier types */ -static struct tcf_proto_ops *tcf_proto_base; +static struct tcf_proto_ops *tcf_proto_base __read_mostly; /* Protects list of registered TC modules. It is pure SMP lock. */ static DEFINE_RWLOCK(cls_mod_lock); /* Find classifier type by string name */ -static struct tcf_proto_ops * tcf_proto_lookup_ops(struct rtattr *kind) +static struct tcf_proto_ops *tcf_proto_lookup_ops(struct nlattr *kind) { struct tcf_proto_ops *t = NULL; if (kind) { read_lock(&cls_mod_lock); for (t = tcf_proto_base; t; t = t->next) { - if (rtattr_strcmp(kind, t->kind) == 0) { + if (nla_strcmp(kind, t->kind) == 0) { if (!try_module_get(t->owner)) t = NULL; break; @@ -79,6 +76,7 @@ out: write_unlock(&cls_mod_lock); return rc; } +EXPORT_SYMBOL(register_tcf_proto_ops); int unregister_tcf_proto_ops(struct tcf_proto_ops *ops) { @@ -98,6 +96,7 @@ out: write_unlock(&cls_mod_lock); return rc; } +EXPORT_SYMBOL(unregister_tcf_proto_ops); static int tfilter_notify(struct sk_buff *oskb, struct nlmsghdr *n, struct tcf_proto *tp, unsigned long fh, int event); @@ -105,9 +104,9 @@ static int tfilter_notify(struct sk_buff *oskb, struct nlmsghdr *n, /* Select new prio value from the range, managed by kernel. */ -static __inline__ u32 tcf_auto_prio(struct tcf_proto *tp) +static inline u32 tcf_auto_prio(struct tcf_proto *tp) { - u32 first = TC_H_MAKE(0xC0000000U,0U); + u32 first = TC_H_MAKE(0xC0000000U, 0U); if (tp) first = tp->prio-1; @@ -119,7 +118,8 @@ static __inline__ u32 tcf_auto_prio(struct tcf_proto *tp) static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { - struct rtattr **tca; + struct net *net = skb->sk->sk_net; + struct nlattr *tca[TCA_MAX + 1]; struct tcmsg *t; u32 protocol; u32 prio; @@ -130,13 +130,15 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg) struct tcf_proto **back, **chain; struct tcf_proto *tp; struct tcf_proto_ops *tp_ops; - struct Qdisc_class_ops *cops; + const struct Qdisc_class_ops *cops; unsigned long cl; unsigned long fh; int err; + if (net != &init_net) + return -EINVAL; + replay: - tca = arg; t = NLMSG_DATA(n); protocol = TC_H_MIN(t->tcm_info); prio = TC_H_MAJ(t->tcm_info); @@ -148,21 +150,29 @@ replay: /* If no priority is given, user wants we allocated it. */ if (n->nlmsg_type != RTM_NEWTFILTER || !(n->nlmsg_flags&NLM_F_CREATE)) return -ENOENT; - prio = TC_H_MAKE(0x80000000U,0U); + prio = TC_H_MAKE(0x80000000U, 0U); } /* Find head of filter chain. */ /* Find link */ - if ((dev = __dev_get_by_index(&init_net, t->tcm_ifindex)) == NULL) + dev = __dev_get_by_index(&init_net, t->tcm_ifindex); + if (dev == NULL) return -ENODEV; + err = nlmsg_parse(n, sizeof(*t), tca, TCA_MAX, NULL); + if (err < 0) + return err; + /* Find qdisc */ if (!parent) { q = dev->qdisc_sleeping; parent = q->handle; - } else if ((q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent))) == NULL) - return -EINVAL; + } else { + q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent)); + if (q == NULL) + return -EINVAL; + } /* Is it classful? */ if ((cops = q->ops->cl_ops) == NULL) @@ -196,7 +206,7 @@ replay: if (tp == NULL) { /* Proto-tcf does not exist, create new one */ - if (tca[TCA_KIND-1] == NULL || !protocol) + if (tca[TCA_KIND] == NULL || !protocol) goto errout; err = -ENOENT; @@ -207,17 +217,18 @@ replay: /* Create new proto tcf */ err = -ENOBUFS; - if ((tp = kzalloc(sizeof(*tp), GFP_KERNEL)) == NULL) + tp = kzalloc(sizeof(*tp), GFP_KERNEL); + if (tp == NULL) goto errout; err = -EINVAL; - tp_ops = tcf_proto_lookup_ops(tca[TCA_KIND-1]); + tp_ops = tcf_proto_lookup_ops(tca[TCA_KIND]); if (tp_ops == NULL) { #ifdef CONFIG_KMOD - struct rtattr *kind = tca[TCA_KIND-1]; + struct nlattr *kind = tca[TCA_KIND]; char name[IFNAMSIZ]; if (kind != NULL && - rtattr_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) { + nla_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) { rtnl_unlock(); request_module("cls_%s", name); rtnl_lock(); @@ -243,7 +254,9 @@ replay: tp->q = q; tp->classify = tp_ops->classify; tp->classid = parent; - if ((err = tp_ops->init(tp)) != 0) { + + err = tp_ops->init(tp); + if (err != 0) { module_put(tp_ops->owner); kfree(tp); goto errout; @@ -254,7 +267,7 @@ replay: *back = tp; qdisc_unlock_tree(dev); - } else if (tca[TCA_KIND-1] && rtattr_strcmp(tca[TCA_KIND-1], tp->ops->kind)) + } else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) goto errout; fh = tp->ops->get(tp, t->tcm_handle); @@ -272,13 +285,14 @@ replay: } err = -ENOENT; - if (n->nlmsg_type != RTM_NEWTFILTER || !(n->nlmsg_flags&NLM_F_CREATE)) + if (n->nlmsg_type != RTM_NEWTFILTER || + !(n->nlmsg_flags & NLM_F_CREATE)) goto errout; } else { switch (n->nlmsg_type) { case RTM_NEWTFILTER: err = -EEXIST; - if (n->nlmsg_flags&NLM_F_EXCL) + if (n->nlmsg_flags & NLM_F_EXCL) goto errout; break; case RTM_DELTFILTER: @@ -308,9 +322,8 @@ errout: return err; } -static int -tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp, unsigned long fh, - u32 pid, u32 seq, u16 flags, int event) +static int tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp, + unsigned long fh, u32 pid, u32 seq, u16 flags, int event) { struct tcmsg *tcm; struct nlmsghdr *nlh; @@ -324,18 +337,18 @@ tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp, unsigned long fh, tcm->tcm_ifindex = tp->q->dev->ifindex; tcm->tcm_parent = tp->classid; tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol); - RTA_PUT(skb, TCA_KIND, IFNAMSIZ, tp->ops->kind); + NLA_PUT_STRING(skb, TCA_KIND, tp->ops->kind); tcm->tcm_handle = fh; if (RTM_DELTFILTER != event) { tcm->tcm_handle = 0; if (tp->ops->dump && tp->ops->dump(tp, fh, skb, tcm) < 0) - goto rtattr_failure; + goto nla_put_failure; } nlh->nlmsg_len = skb_tail_pointer(skb) - b; return skb->len; nlmsg_failure: -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } @@ -355,19 +368,20 @@ static int tfilter_notify(struct sk_buff *oskb, struct nlmsghdr *n, return -EINVAL; } - return rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); + return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, + n->nlmsg_flags & NLM_F_ECHO); } -struct tcf_dump_args -{ +struct tcf_dump_args { struct tcf_walker w; struct sk_buff *skb; struct netlink_callback *cb; }; -static int tcf_node_dump(struct tcf_proto *tp, unsigned long n, struct tcf_walker *arg) +static int tcf_node_dump(struct tcf_proto *tp, unsigned long n, + struct tcf_walker *arg) { - struct tcf_dump_args *a = (void*)arg; + struct tcf_dump_args *a = (void *)arg; return tcf_fill_node(a->skb, tp, n, NETLINK_CB(a->cb->skb).pid, a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTFILTER); @@ -375,16 +389,20 @@ static int tcf_node_dump(struct tcf_proto *tp, unsigned long n, struct tcf_walke static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) { + struct net *net = skb->sk->sk_net; int t; int s_t; struct net_device *dev; struct Qdisc *q; struct tcf_proto *tp, **chain; - struct tcmsg *tcm = (struct tcmsg*)NLMSG_DATA(cb->nlh); + struct tcmsg *tcm = (struct tcmsg *)NLMSG_DATA(cb->nlh); unsigned long cl = 0; - struct Qdisc_class_ops *cops; + const struct Qdisc_class_ops *cops; struct tcf_dump_args arg; + if (net != &init_net) + return 0; + if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) return skb->len; if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) @@ -421,9 +439,10 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0])); if (cb->args[1] == 0) { if (tcf_fill_node(skb, tp, 0, NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTFILTER) <= 0) { + cb->nlh->nlmsg_seq, NLM_F_MULTI, + RTM_NEWTFILTER) <= 0) break; - } + cb->args[1] = 1; } if (tp->ops->walk == NULL) @@ -450,8 +469,7 @@ out: return skb->len; } -void -tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts) +void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts) { #ifdef CONFIG_NET_CLS_ACT if (exts->action) { @@ -460,49 +478,48 @@ tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts) } #endif } +EXPORT_SYMBOL(tcf_exts_destroy); - -int -tcf_exts_validate(struct tcf_proto *tp, struct rtattr **tb, - struct rtattr *rate_tlv, struct tcf_exts *exts, +int tcf_exts_validate(struct tcf_proto *tp, struct nlattr **tb, + struct nlattr *rate_tlv, struct tcf_exts *exts, struct tcf_ext_map *map) { memset(exts, 0, sizeof(*exts)); #ifdef CONFIG_NET_CLS_ACT { - int err; struct tc_action *act; - if (map->police && tb[map->police-1]) { - act = tcf_action_init_1(tb[map->police-1], rate_tlv, "police", - TCA_ACT_NOREPLACE, TCA_ACT_BIND, &err); - if (act == NULL) - return err; + if (map->police && tb[map->police]) { + act = tcf_action_init_1(tb[map->police], rate_tlv, + "police", TCA_ACT_NOREPLACE, + TCA_ACT_BIND); + if (IS_ERR(act)) + return PTR_ERR(act); act->type = TCA_OLD_COMPAT; exts->action = act; - } else if (map->action && tb[map->action-1]) { - act = tcf_action_init(tb[map->action-1], rate_tlv, NULL, - TCA_ACT_NOREPLACE, TCA_ACT_BIND, &err); - if (act == NULL) - return err; + } else if (map->action && tb[map->action]) { + act = tcf_action_init(tb[map->action], rate_tlv, NULL, + TCA_ACT_NOREPLACE, TCA_ACT_BIND); + if (IS_ERR(act)) + return PTR_ERR(act); exts->action = act; } } #else - if ((map->action && tb[map->action-1]) || - (map->police && tb[map->police-1])) + if ((map->action && tb[map->action]) || + (map->police && tb[map->police])) return -EOPNOTSUPP; #endif return 0; } +EXPORT_SYMBOL(tcf_exts_validate); -void -tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst, - struct tcf_exts *src) +void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst, + struct tcf_exts *src) { #ifdef CONFIG_NET_CLS_ACT if (src->action) { @@ -515,9 +532,9 @@ tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst, } #endif } +EXPORT_SYMBOL(tcf_exts_change); -int -tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts, +int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts, struct tcf_ext_map *map) { #ifdef CONFIG_NET_CLS_ACT @@ -527,39 +544,45 @@ tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts, * to work with both old and new modes of entering * tc data even if iproute2 was newer - jhs */ - struct rtattr *p_rta = (struct rtattr *)skb_tail_pointer(skb); + struct nlattr *nest; if (exts->action->type != TCA_OLD_COMPAT) { - RTA_PUT(skb, map->action, 0, NULL); + nest = nla_nest_start(skb, map->action); + if (nest == NULL) + goto nla_put_failure; if (tcf_action_dump(skb, exts->action, 0, 0) < 0) - goto rtattr_failure; - p_rta->rta_len = skb_tail_pointer(skb) - (u8 *)p_rta; + goto nla_put_failure; + nla_nest_end(skb, nest); } else if (map->police) { - RTA_PUT(skb, map->police, 0, NULL); + nest = nla_nest_start(skb, map->police); + if (nest == NULL) + goto nla_put_failure; if (tcf_action_dump_old(skb, exts->action, 0, 0) < 0) - goto rtattr_failure; - p_rta->rta_len = skb_tail_pointer(skb) - (u8 *)p_rta; + goto nla_put_failure; + nla_nest_end(skb, nest); } } #endif return 0; -rtattr_failure: __attribute__ ((unused)) +nla_put_failure: __attribute__ ((unused)) return -1; } +EXPORT_SYMBOL(tcf_exts_dump); -int -tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts, - struct tcf_ext_map *map) + +int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts, + struct tcf_ext_map *map) { #ifdef CONFIG_NET_CLS_ACT if (exts->action) if (tcf_action_copy_stats(skb, exts->action, 1) < 0) - goto rtattr_failure; + goto nla_put_failure; #endif return 0; -rtattr_failure: __attribute__ ((unused)) +nla_put_failure: __attribute__ ((unused)) return -1; } +EXPORT_SYMBOL(tcf_exts_dump_stats); static int __init tc_filter_init(void) { @@ -572,11 +595,3 @@ static int __init tc_filter_init(void) } subsys_initcall(tc_filter_init); - -EXPORT_SYMBOL(register_tcf_proto_ops); -EXPORT_SYMBOL(unregister_tcf_proto_ops); -EXPORT_SYMBOL(tcf_exts_validate); -EXPORT_SYMBOL(tcf_exts_destroy); -EXPORT_SYMBOL(tcf_exts_change); -EXPORT_SYMBOL(tcf_exts_dump); -EXPORT_SYMBOL(tcf_exts_dump_stats); diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c index 8dbcf2771a4..bfb4342ea88 100644 --- a/net/sched/cls_basic.c +++ b/net/sched/cls_basic.c @@ -129,28 +129,29 @@ static int basic_delete(struct tcf_proto *tp, unsigned long arg) return -ENOENT; } +static const struct nla_policy basic_policy[TCA_BASIC_MAX + 1] = { + [TCA_BASIC_CLASSID] = { .type = NLA_U32 }, + [TCA_BASIC_EMATCHES] = { .type = NLA_NESTED }, +}; + static inline int basic_set_parms(struct tcf_proto *tp, struct basic_filter *f, - unsigned long base, struct rtattr **tb, - struct rtattr *est) + unsigned long base, struct nlattr **tb, + struct nlattr *est) { int err = -EINVAL; struct tcf_exts e; struct tcf_ematch_tree t; - if (tb[TCA_BASIC_CLASSID-1]) - if (RTA_PAYLOAD(tb[TCA_BASIC_CLASSID-1]) < sizeof(u32)) - return err; - err = tcf_exts_validate(tp, tb, est, &e, &basic_ext_map); if (err < 0) return err; - err = tcf_em_tree_validate(tp, tb[TCA_BASIC_EMATCHES-1], &t); + err = tcf_em_tree_validate(tp, tb[TCA_BASIC_EMATCHES], &t); if (err < 0) goto errout; - if (tb[TCA_BASIC_CLASSID-1]) { - f->res.classid = *(u32*)RTA_DATA(tb[TCA_BASIC_CLASSID-1]); + if (tb[TCA_BASIC_CLASSID]) { + f->res.classid = nla_get_u32(tb[TCA_BASIC_CLASSID]); tcf_bind_filter(tp, &f->res, base); } @@ -164,23 +165,25 @@ errout: } static int basic_change(struct tcf_proto *tp, unsigned long base, u32 handle, - struct rtattr **tca, unsigned long *arg) + struct nlattr **tca, unsigned long *arg) { - int err = -EINVAL; + int err; struct basic_head *head = (struct basic_head *) tp->root; - struct rtattr *tb[TCA_BASIC_MAX]; + struct nlattr *tb[TCA_BASIC_MAX + 1]; struct basic_filter *f = (struct basic_filter *) *arg; - if (tca[TCA_OPTIONS-1] == NULL) + if (tca[TCA_OPTIONS] == NULL) return -EINVAL; - if (rtattr_parse_nested(tb, TCA_BASIC_MAX, tca[TCA_OPTIONS-1]) < 0) - return -EINVAL; + err = nla_parse_nested(tb, TCA_BASIC_MAX, tca[TCA_OPTIONS], + basic_policy); + if (err < 0) + return err; if (f != NULL) { if (handle && f->handle != handle) return -EINVAL; - return basic_set_parms(tp, f, base, tb, tca[TCA_RATE-1]); + return basic_set_parms(tp, f, base, tb, tca[TCA_RATE]); } err = -ENOBUFS; @@ -206,7 +209,7 @@ static int basic_change(struct tcf_proto *tp, unsigned long base, u32 handle, f->handle = head->hgenerator; } - err = basic_set_parms(tp, f, base, tb, tca[TCA_RATE-1]); + err = basic_set_parms(tp, f, base, tb, tca[TCA_RATE]); if (err < 0) goto errout; @@ -245,33 +248,33 @@ static int basic_dump(struct tcf_proto *tp, unsigned long fh, struct sk_buff *skb, struct tcmsg *t) { struct basic_filter *f = (struct basic_filter *) fh; - unsigned char *b = skb_tail_pointer(skb); - struct rtattr *rta; + struct nlattr *nest; if (f == NULL) return skb->len; t->tcm_handle = f->handle; - rta = (struct rtattr *) b; - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; if (f->res.classid) - RTA_PUT(skb, TCA_BASIC_CLASSID, sizeof(u32), &f->res.classid); + NLA_PUT_U32(skb, TCA_BASIC_CLASSID, f->res.classid); if (tcf_exts_dump(skb, &f->exts, &basic_ext_map) < 0 || tcf_em_tree_dump(skb, &f->ematches, TCA_BASIC_EMATCHES) < 0) - goto rtattr_failure; + goto nla_put_failure; - rta->rta_len = skb_tail_pointer(skb) - b; + nla_nest_end(skb, nest); return skb->len; -rtattr_failure: - nlmsg_trim(skb, b); +nla_put_failure: + nla_nest_cancel(skb, nest); return -1; } -static struct tcf_proto_ops cls_basic_ops = { +static struct tcf_proto_ops cls_basic_ops __read_mostly = { .kind = "basic", .classify = basic_classify, .init = basic_init, diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index 8adbd6a37d1..436a6e7c438 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c @@ -186,39 +186,41 @@ out: return -EINVAL; } +static const struct nla_policy fw_policy[TCA_FW_MAX + 1] = { + [TCA_FW_CLASSID] = { .type = NLA_U32 }, + [TCA_FW_INDEV] = { .type = NLA_STRING, .len = IFNAMSIZ }, + [TCA_FW_MASK] = { .type = NLA_U32 }, +}; + static int fw_change_attrs(struct tcf_proto *tp, struct fw_filter *f, - struct rtattr **tb, struct rtattr **tca, unsigned long base) + struct nlattr **tb, struct nlattr **tca, unsigned long base) { struct fw_head *head = (struct fw_head *)tp->root; struct tcf_exts e; u32 mask; int err; - err = tcf_exts_validate(tp, tb, tca[TCA_RATE-1], &e, &fw_ext_map); + err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &fw_ext_map); if (err < 0) return err; err = -EINVAL; - if (tb[TCA_FW_CLASSID-1]) { - if (RTA_PAYLOAD(tb[TCA_FW_CLASSID-1]) != sizeof(u32)) - goto errout; - f->res.classid = *(u32*)RTA_DATA(tb[TCA_FW_CLASSID-1]); + if (tb[TCA_FW_CLASSID]) { + f->res.classid = nla_get_u32(tb[TCA_FW_CLASSID]); tcf_bind_filter(tp, &f->res, base); } #ifdef CONFIG_NET_CLS_IND - if (tb[TCA_FW_INDEV-1]) { - err = tcf_change_indev(tp, f->indev, tb[TCA_FW_INDEV-1]); + if (tb[TCA_FW_INDEV]) { + err = tcf_change_indev(tp, f->indev, tb[TCA_FW_INDEV]); if (err < 0) goto errout; } #endif /* CONFIG_NET_CLS_IND */ - if (tb[TCA_FW_MASK-1]) { - if (RTA_PAYLOAD(tb[TCA_FW_MASK-1]) != sizeof(u32)) - goto errout; - mask = *(u32*)RTA_DATA(tb[TCA_FW_MASK-1]); + if (tb[TCA_FW_MASK]) { + mask = nla_get_u32(tb[TCA_FW_MASK]); if (mask != head->mask) goto errout; } else if (head->mask != 0xFFFFFFFF) @@ -234,20 +236,21 @@ errout: static int fw_change(struct tcf_proto *tp, unsigned long base, u32 handle, - struct rtattr **tca, + struct nlattr **tca, unsigned long *arg) { struct fw_head *head = (struct fw_head*)tp->root; struct fw_filter *f = (struct fw_filter *) *arg; - struct rtattr *opt = tca[TCA_OPTIONS-1]; - struct rtattr *tb[TCA_FW_MAX]; + struct nlattr *opt = tca[TCA_OPTIONS]; + struct nlattr *tb[TCA_FW_MAX + 1]; int err; if (!opt) return handle ? -EINVAL : 0; - if (rtattr_parse_nested(tb, TCA_FW_MAX, opt) < 0) - return -EINVAL; + err = nla_parse_nested(tb, TCA_FW_MAX, opt, fw_policy); + if (err < 0) + return err; if (f != NULL) { if (f->id != handle && handle) @@ -260,11 +263,8 @@ static int fw_change(struct tcf_proto *tp, unsigned long base, if (head == NULL) { u32 mask = 0xFFFFFFFF; - if (tb[TCA_FW_MASK-1]) { - if (RTA_PAYLOAD(tb[TCA_FW_MASK-1]) != sizeof(u32)) - return -EINVAL; - mask = *(u32*)RTA_DATA(tb[TCA_FW_MASK-1]); - } + if (tb[TCA_FW_MASK]) + mask = nla_get_u32(tb[TCA_FW_MASK]); head = kzalloc(sizeof(struct fw_head), GFP_KERNEL); if (head == NULL) @@ -333,7 +333,7 @@ static int fw_dump(struct tcf_proto *tp, unsigned long fh, struct fw_head *head = (struct fw_head *)tp->root; struct fw_filter *f = (struct fw_filter*)fh; unsigned char *b = skb_tail_pointer(skb); - struct rtattr *rta; + struct nlattr *nest; if (f == NULL) return skb->len; @@ -343,35 +343,35 @@ static int fw_dump(struct tcf_proto *tp, unsigned long fh, if (!f->res.classid && !tcf_exts_is_available(&f->exts)) return skb->len; - rta = (struct rtattr*)b; - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; if (f->res.classid) - RTA_PUT(skb, TCA_FW_CLASSID, 4, &f->res.classid); + NLA_PUT_U32(skb, TCA_FW_CLASSID, f->res.classid); #ifdef CONFIG_NET_CLS_IND if (strlen(f->indev)) - RTA_PUT(skb, TCA_FW_INDEV, IFNAMSIZ, f->indev); + NLA_PUT_STRING(skb, TCA_FW_INDEV, f->indev); #endif /* CONFIG_NET_CLS_IND */ if (head->mask != 0xFFFFFFFF) - RTA_PUT(skb, TCA_FW_MASK, 4, &head->mask); + NLA_PUT_U32(skb, TCA_FW_MASK, head->mask); if (tcf_exts_dump(skb, &f->exts, &fw_ext_map) < 0) - goto rtattr_failure; + goto nla_put_failure; - rta->rta_len = skb_tail_pointer(skb) - b; + nla_nest_end(skb, nest); if (tcf_exts_dump_stats(skb, &f->exts, &fw_ext_map) < 0) - goto rtattr_failure; + goto nla_put_failure; return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } -static struct tcf_proto_ops cls_fw_ops = { - .next = NULL, +static struct tcf_proto_ops cls_fw_ops __read_mostly = { .kind = "fw", .classify = fw_classify, .init = fw_init, diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index 0a8409c1d28..f7e7d3955d2 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c @@ -323,9 +323,16 @@ static int route4_delete(struct tcf_proto *tp, unsigned long arg) return 0; } +static const struct nla_policy route4_policy[TCA_ROUTE4_MAX + 1] = { + [TCA_ROUTE4_CLASSID] = { .type = NLA_U32 }, + [TCA_ROUTE4_TO] = { .type = NLA_U32 }, + [TCA_ROUTE4_FROM] = { .type = NLA_U32 }, + [TCA_ROUTE4_IIF] = { .type = NLA_U32 }, +}; + static int route4_set_parms(struct tcf_proto *tp, unsigned long base, struct route4_filter *f, u32 handle, struct route4_head *head, - struct rtattr **tb, struct rtattr *est, int new) + struct nlattr **tb, struct nlattr *est, int new) { int err; u32 id = 0, to = 0, nhandle = 0x8000; @@ -339,34 +346,24 @@ static int route4_set_parms(struct tcf_proto *tp, unsigned long base, return err; err = -EINVAL; - if (tb[TCA_ROUTE4_CLASSID-1]) - if (RTA_PAYLOAD(tb[TCA_ROUTE4_CLASSID-1]) < sizeof(u32)) - goto errout; - - if (tb[TCA_ROUTE4_TO-1]) { + if (tb[TCA_ROUTE4_TO]) { if (new && handle & 0x8000) goto errout; - if (RTA_PAYLOAD(tb[TCA_ROUTE4_TO-1]) < sizeof(u32)) - goto errout; - to = *(u32*)RTA_DATA(tb[TCA_ROUTE4_TO-1]); + to = nla_get_u32(tb[TCA_ROUTE4_TO]); if (to > 0xFF) goto errout; nhandle = to; } - if (tb[TCA_ROUTE4_FROM-1]) { - if (tb[TCA_ROUTE4_IIF-1]) + if (tb[TCA_ROUTE4_FROM]) { + if (tb[TCA_ROUTE4_IIF]) goto errout; - if (RTA_PAYLOAD(tb[TCA_ROUTE4_FROM-1]) < sizeof(u32)) - goto errout; - id = *(u32*)RTA_DATA(tb[TCA_ROUTE4_FROM-1]); + id = nla_get_u32(tb[TCA_ROUTE4_FROM]); if (id > 0xFF) goto errout; nhandle |= id << 16; - } else if (tb[TCA_ROUTE4_IIF-1]) { - if (RTA_PAYLOAD(tb[TCA_ROUTE4_IIF-1]) < sizeof(u32)) - goto errout; - id = *(u32*)RTA_DATA(tb[TCA_ROUTE4_IIF-1]); + } else if (tb[TCA_ROUTE4_IIF]) { + id = nla_get_u32(tb[TCA_ROUTE4_IIF]); if (id > 0x7FFF) goto errout; nhandle |= (id | 0x8000) << 16; @@ -398,20 +395,20 @@ static int route4_set_parms(struct tcf_proto *tp, unsigned long base, } tcf_tree_lock(tp); - if (tb[TCA_ROUTE4_TO-1]) + if (tb[TCA_ROUTE4_TO]) f->id = to; - if (tb[TCA_ROUTE4_FROM-1]) + if (tb[TCA_ROUTE4_FROM]) f->id = to | id<<16; - else if (tb[TCA_ROUTE4_IIF-1]) + else if (tb[TCA_ROUTE4_IIF]) f->iif = id; f->handle = nhandle; f->bkt = b; tcf_tree_unlock(tp); - if (tb[TCA_ROUTE4_CLASSID-1]) { - f->res.classid = *(u32*)RTA_DATA(tb[TCA_ROUTE4_CLASSID-1]); + if (tb[TCA_ROUTE4_CLASSID]) { + f->res.classid = nla_get_u32(tb[TCA_ROUTE4_CLASSID]); tcf_bind_filter(tp, &f->res, base); } @@ -425,14 +422,14 @@ errout: static int route4_change(struct tcf_proto *tp, unsigned long base, u32 handle, - struct rtattr **tca, + struct nlattr **tca, unsigned long *arg) { struct route4_head *head = tp->root; struct route4_filter *f, *f1, **fp; struct route4_bucket *b; - struct rtattr *opt = tca[TCA_OPTIONS-1]; - struct rtattr *tb[TCA_ROUTE4_MAX]; + struct nlattr *opt = tca[TCA_OPTIONS]; + struct nlattr *tb[TCA_ROUTE4_MAX + 1]; unsigned int h, th; u32 old_handle = 0; int err; @@ -440,8 +437,9 @@ static int route4_change(struct tcf_proto *tp, unsigned long base, if (opt == NULL) return handle ? -EINVAL : 0; - if (rtattr_parse_nested(tb, TCA_ROUTE4_MAX, opt) < 0) - return -EINVAL; + err = nla_parse_nested(tb, TCA_ROUTE4_MAX, opt, route4_policy); + if (err < 0) + return err; if ((f = (struct route4_filter*)*arg) != NULL) { if (f->handle != handle && handle) @@ -451,7 +449,7 @@ static int route4_change(struct tcf_proto *tp, unsigned long base, old_handle = f->handle; err = route4_set_parms(tp, base, f, handle, head, tb, - tca[TCA_RATE-1], 0); + tca[TCA_RATE], 0); if (err < 0) return err; @@ -474,7 +472,7 @@ static int route4_change(struct tcf_proto *tp, unsigned long base, goto errout; err = route4_set_parms(tp, base, f, handle, head, tb, - tca[TCA_RATE-1], 1); + tca[TCA_RATE], 1); if (err < 0) goto errout; @@ -550,7 +548,7 @@ static int route4_dump(struct tcf_proto *tp, unsigned long fh, { struct route4_filter *f = (struct route4_filter*)fh; unsigned char *b = skb_tail_pointer(skb); - struct rtattr *rta; + struct nlattr *nest; u32 id; if (f == NULL) @@ -558,40 +556,40 @@ static int route4_dump(struct tcf_proto *tp, unsigned long fh, t->tcm_handle = f->handle; - rta = (struct rtattr*)b; - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; if (!(f->handle&0x8000)) { id = f->id&0xFF; - RTA_PUT(skb, TCA_ROUTE4_TO, sizeof(id), &id); + NLA_PUT_U32(skb, TCA_ROUTE4_TO, id); } if (f->handle&0x80000000) { if ((f->handle>>16) != 0xFFFF) - RTA_PUT(skb, TCA_ROUTE4_IIF, sizeof(f->iif), &f->iif); + NLA_PUT_U32(skb, TCA_ROUTE4_IIF, f->iif); } else { id = f->id>>16; - RTA_PUT(skb, TCA_ROUTE4_FROM, sizeof(id), &id); + NLA_PUT_U32(skb, TCA_ROUTE4_FROM, id); } if (f->res.classid) - RTA_PUT(skb, TCA_ROUTE4_CLASSID, 4, &f->res.classid); + NLA_PUT_U32(skb, TCA_ROUTE4_CLASSID, f->res.classid); if (tcf_exts_dump(skb, &f->exts, &route_ext_map) < 0) - goto rtattr_failure; + goto nla_put_failure; - rta->rta_len = skb_tail_pointer(skb) - b; + nla_nest_end(skb, nest); if (tcf_exts_dump_stats(skb, &f->exts, &route_ext_map) < 0) - goto rtattr_failure; + goto nla_put_failure; return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } -static struct tcf_proto_ops cls_route4_ops = { - .next = NULL, +static struct tcf_proto_ops cls_route4_ops __read_mostly = { .kind = "route", .classify = route4_classify, .init = route4_init, diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h index 22f9ede70e8..7034ea4530e 100644 --- a/net/sched/cls_rsvp.h +++ b/net/sched/cls_rsvp.h @@ -397,17 +397,26 @@ static u32 gen_tunnel(struct rsvp_head *data) return 0; } +static const struct nla_policy rsvp_policy[TCA_RSVP_MAX + 1] = { + [TCA_RSVP_CLASSID] = { .type = NLA_U32 }, + [TCA_RSVP_DST] = { .type = NLA_BINARY, + .len = RSVP_DST_LEN * sizeof(u32) }, + [TCA_RSVP_SRC] = { .type = NLA_BINARY, + .len = RSVP_DST_LEN * sizeof(u32) }, + [TCA_RSVP_PINFO] = { .len = sizeof(struct tc_rsvp_pinfo) }, +}; + static int rsvp_change(struct tcf_proto *tp, unsigned long base, u32 handle, - struct rtattr **tca, + struct nlattr **tca, unsigned long *arg) { struct rsvp_head *data = tp->root; struct rsvp_filter *f, **fp; struct rsvp_session *s, **sp; struct tc_rsvp_pinfo *pinfo = NULL; - struct rtattr *opt = tca[TCA_OPTIONS-1]; - struct rtattr *tb[TCA_RSVP_MAX]; + struct nlattr *opt = tca[TCA_OPTIONS-1]; + struct nlattr *tb[TCA_RSVP_MAX + 1]; struct tcf_exts e; unsigned h1, h2; __be32 *dst; @@ -416,8 +425,9 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base, if (opt == NULL) return handle ? -EINVAL : 0; - if (rtattr_parse_nested(tb, TCA_RSVP_MAX, opt) < 0) - return -EINVAL; + err = nla_parse_nested(tb, TCA_RSVP_MAX, opt, rsvp_policy); + if (err < 0) + return err; err = tcf_exts_validate(tp, tb, tca[TCA_RATE-1], &e, &rsvp_ext_map); if (err < 0) @@ -429,7 +439,7 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base, if (f->handle != handle && handle) goto errout2; if (tb[TCA_RSVP_CLASSID-1]) { - f->res.classid = *(u32*)RTA_DATA(tb[TCA_RSVP_CLASSID-1]); + f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID-1]); tcf_bind_filter(tp, &f->res, base); } @@ -451,31 +461,18 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base, h2 = 16; if (tb[TCA_RSVP_SRC-1]) { - err = -EINVAL; - if (RTA_PAYLOAD(tb[TCA_RSVP_SRC-1]) != sizeof(f->src)) - goto errout; - memcpy(f->src, RTA_DATA(tb[TCA_RSVP_SRC-1]), sizeof(f->src)); + memcpy(f->src, nla_data(tb[TCA_RSVP_SRC-1]), sizeof(f->src)); h2 = hash_src(f->src); } if (tb[TCA_RSVP_PINFO-1]) { - err = -EINVAL; - if (RTA_PAYLOAD(tb[TCA_RSVP_PINFO-1]) < sizeof(struct tc_rsvp_pinfo)) - goto errout; - pinfo = RTA_DATA(tb[TCA_RSVP_PINFO-1]); + pinfo = nla_data(tb[TCA_RSVP_PINFO-1]); f->spi = pinfo->spi; f->tunnelhdr = pinfo->tunnelhdr; } - if (tb[TCA_RSVP_CLASSID-1]) { - err = -EINVAL; - if (RTA_PAYLOAD(tb[TCA_RSVP_CLASSID-1]) != 4) - goto errout; - f->res.classid = *(u32*)RTA_DATA(tb[TCA_RSVP_CLASSID-1]); - } + if (tb[TCA_RSVP_CLASSID-1]) + f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID-1]); - err = -EINVAL; - if (RTA_PAYLOAD(tb[TCA_RSVP_DST-1]) != sizeof(f->src)) - goto errout; - dst = RTA_DATA(tb[TCA_RSVP_DST-1]); + dst = nla_data(tb[TCA_RSVP_DST-1]); h1 = hash_dst(dst, pinfo ? pinfo->protocol : 0, pinfo ? pinfo->tunnelid : 0); err = -ENOMEM; @@ -594,7 +591,7 @@ static int rsvp_dump(struct tcf_proto *tp, unsigned long fh, struct rsvp_filter *f = (struct rsvp_filter*)fh; struct rsvp_session *s; unsigned char *b = skb_tail_pointer(skb); - struct rtattr *rta; + struct nlattr *nest; struct tc_rsvp_pinfo pinfo; if (f == NULL) @@ -603,33 +600,33 @@ static int rsvp_dump(struct tcf_proto *tp, unsigned long fh, t->tcm_handle = f->handle; + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; - rta = (struct rtattr*)b; - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); - - RTA_PUT(skb, TCA_RSVP_DST, sizeof(s->dst), &s->dst); + NLA_PUT(skb, TCA_RSVP_DST, sizeof(s->dst), &s->dst); pinfo.dpi = s->dpi; pinfo.spi = f->spi; pinfo.protocol = s->protocol; pinfo.tunnelid = s->tunnelid; pinfo.tunnelhdr = f->tunnelhdr; pinfo.pad = 0; - RTA_PUT(skb, TCA_RSVP_PINFO, sizeof(pinfo), &pinfo); + NLA_PUT(skb, TCA_RSVP_PINFO, sizeof(pinfo), &pinfo); if (f->res.classid) - RTA_PUT(skb, TCA_RSVP_CLASSID, 4, &f->res.classid); + NLA_PUT_U32(skb, TCA_RSVP_CLASSID, f->res.classid); if (((f->handle>>8)&0xFF) != 16) - RTA_PUT(skb, TCA_RSVP_SRC, sizeof(f->src), f->src); + NLA_PUT(skb, TCA_RSVP_SRC, sizeof(f->src), f->src); if (tcf_exts_dump(skb, &f->exts, &rsvp_ext_map) < 0) - goto rtattr_failure; + goto nla_put_failure; - rta->rta_len = skb_tail_pointer(skb) - b; + nla_nest_end(skb, nest); if (tcf_exts_dump_stats(skb, &f->exts, &rsvp_ext_map) < 0) - goto rtattr_failure; + goto nla_put_failure; return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index 2314820a080..ee60b2d1705 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c @@ -29,19 +29,6 @@ #define DEFAULT_HASH_SIZE 64 /* optimized for diffserv */ -#if 1 /* control */ -#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define DPRINTK(format,args...) -#endif - -#if 0 /* data */ -#define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define D2PRINTK(format,args...) -#endif - - #define PRIV(tp) ((struct tcindex_data *) (tp)->root) @@ -104,7 +91,8 @@ static int tcindex_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcindex_filter_result *f; int key = (skb->tc_index & p->mask) >> p->shift; - D2PRINTK("tcindex_classify(skb %p,tp %p,res %p),p %p\n",skb,tp,res,p); + pr_debug("tcindex_classify(skb %p,tp %p,res %p),p %p\n", + skb, tp, res, p); f = tcindex_lookup(p, key); if (!f) { @@ -112,11 +100,11 @@ static int tcindex_classify(struct sk_buff *skb, struct tcf_proto *tp, return -1; res->classid = TC_H_MAKE(TC_H_MAJ(tp->q->handle), key); res->class = 0; - D2PRINTK("alg 0x%x\n",res->classid); + pr_debug("alg 0x%x\n", res->classid); return 0; } *res = f->res; - D2PRINTK("map 0x%x\n",res->classid); + pr_debug("map 0x%x\n", res->classid); return tcf_exts_exec(skb, &f->exts, res); } @@ -127,7 +115,7 @@ static unsigned long tcindex_get(struct tcf_proto *tp, u32 handle) struct tcindex_data *p = PRIV(tp); struct tcindex_filter_result *r; - DPRINTK("tcindex_get(tp %p,handle 0x%08x)\n",tp,handle); + pr_debug("tcindex_get(tp %p,handle 0x%08x)\n", tp, handle); if (p->perfect && handle >= p->alloc_hash) return 0; r = tcindex_lookup(p, handle); @@ -137,7 +125,7 @@ static unsigned long tcindex_get(struct tcf_proto *tp, u32 handle) static void tcindex_put(struct tcf_proto *tp, unsigned long f) { - DPRINTK("tcindex_put(tp %p,f 0x%lx)\n",tp,f); + pr_debug("tcindex_put(tp %p,f 0x%lx)\n", tp, f); } @@ -145,8 +133,8 @@ static int tcindex_init(struct tcf_proto *tp) { struct tcindex_data *p; - DPRINTK("tcindex_init(tp %p)\n",tp); - p = kzalloc(sizeof(struct tcindex_data),GFP_KERNEL); + pr_debug("tcindex_init(tp %p)\n", tp); + p = kzalloc(sizeof(struct tcindex_data), GFP_KERNEL); if (!p) return -ENOMEM; @@ -166,7 +154,7 @@ __tcindex_delete(struct tcf_proto *tp, unsigned long arg, int lock) struct tcindex_filter_result *r = (struct tcindex_filter_result *) arg; struct tcindex_filter *f = NULL; - DPRINTK("tcindex_delete(tp %p,arg 0x%lx),p %p,f %p\n",tp,arg,p,f); + pr_debug("tcindex_delete(tp %p,arg 0x%lx),p %p,f %p\n", tp, arg, p, f); if (p->perfect) { if (!r->res.class) return -ENOENT; @@ -205,10 +193,18 @@ valid_perfect_hash(struct tcindex_data *p) return p->hash > (p->mask >> p->shift); } +static const struct nla_policy tcindex_policy[TCA_TCINDEX_MAX + 1] = { + [TCA_TCINDEX_HASH] = { .type = NLA_U32 }, + [TCA_TCINDEX_MASK] = { .type = NLA_U16 }, + [TCA_TCINDEX_SHIFT] = { .type = NLA_U32 }, + [TCA_TCINDEX_FALL_THROUGH] = { .type = NLA_U32 }, + [TCA_TCINDEX_CLASSID] = { .type = NLA_U32 }, +}; + static int tcindex_set_parms(struct tcf_proto *tp, unsigned long base, u32 handle, struct tcindex_data *p, struct tcindex_filter_result *r, - struct rtattr **tb, struct rtattr *est) + struct nlattr **tb, struct nlattr *est) { int err, balloc = 0; struct tcindex_filter_result new_filter_result, *old_r = r; @@ -229,24 +225,14 @@ tcindex_set_parms(struct tcf_proto *tp, unsigned long base, u32 handle, else memset(&cr, 0, sizeof(cr)); - err = -EINVAL; - if (tb[TCA_TCINDEX_HASH-1]) { - if (RTA_PAYLOAD(tb[TCA_TCINDEX_HASH-1]) < sizeof(u32)) - goto errout; - cp.hash = *(u32 *) RTA_DATA(tb[TCA_TCINDEX_HASH-1]); - } + if (tb[TCA_TCINDEX_HASH]) + cp.hash = nla_get_u32(tb[TCA_TCINDEX_HASH]); - if (tb[TCA_TCINDEX_MASK-1]) { - if (RTA_PAYLOAD(tb[TCA_TCINDEX_MASK-1]) < sizeof(u16)) - goto errout; - cp.mask = *(u16 *) RTA_DATA(tb[TCA_TCINDEX_MASK-1]); - } + if (tb[TCA_TCINDEX_MASK]) + cp.mask = nla_get_u16(tb[TCA_TCINDEX_MASK]); - if (tb[TCA_TCINDEX_SHIFT-1]) { - if (RTA_PAYLOAD(tb[TCA_TCINDEX_SHIFT-1]) < sizeof(int)) - goto errout; - cp.shift = *(int *) RTA_DATA(tb[TCA_TCINDEX_SHIFT-1]); - } + if (tb[TCA_TCINDEX_SHIFT]) + cp.shift = nla_get_u32(tb[TCA_TCINDEX_SHIFT]); err = -EBUSY; /* Hash already allocated, make sure that we still meet the @@ -260,12 +246,8 @@ tcindex_set_parms(struct tcf_proto *tp, unsigned long base, u32 handle, goto errout; err = -EINVAL; - if (tb[TCA_TCINDEX_FALL_THROUGH-1]) { - if (RTA_PAYLOAD(tb[TCA_TCINDEX_FALL_THROUGH-1]) < sizeof(u32)) - goto errout; - cp.fall_through = - *(u32 *) RTA_DATA(tb[TCA_TCINDEX_FALL_THROUGH-1]); - } + if (tb[TCA_TCINDEX_FALL_THROUGH]) + cp.fall_through = nla_get_u32(tb[TCA_TCINDEX_FALL_THROUGH]); if (!cp.hash) { /* Hash not specified, use perfect hash if the upper limit @@ -316,8 +298,8 @@ tcindex_set_parms(struct tcf_proto *tp, unsigned long base, u32 handle, goto errout_alloc; } - if (tb[TCA_TCINDEX_CLASSID-1]) { - cr.res.classid = *(u32 *) RTA_DATA(tb[TCA_TCINDEX_CLASSID-1]); + if (tb[TCA_TCINDEX_CLASSID]) { + cr.res.classid = nla_get_u32(tb[TCA_TCINDEX_CLASSID]); tcf_bind_filter(tp, &cr.res, base); } @@ -356,34 +338,36 @@ errout: static int tcindex_change(struct tcf_proto *tp, unsigned long base, u32 handle, - struct rtattr **tca, unsigned long *arg) + struct nlattr **tca, unsigned long *arg) { - struct rtattr *opt = tca[TCA_OPTIONS-1]; - struct rtattr *tb[TCA_TCINDEX_MAX]; + struct nlattr *opt = tca[TCA_OPTIONS]; + struct nlattr *tb[TCA_TCINDEX_MAX + 1]; struct tcindex_data *p = PRIV(tp); struct tcindex_filter_result *r = (struct tcindex_filter_result *) *arg; + int err; - DPRINTK("tcindex_change(tp %p,handle 0x%08x,tca %p,arg %p),opt %p," + pr_debug("tcindex_change(tp %p,handle 0x%08x,tca %p,arg %p),opt %p," "p %p,r %p,*arg 0x%lx\n", tp, handle, tca, arg, opt, p, r, arg ? *arg : 0L); if (!opt) return 0; - if (rtattr_parse_nested(tb, TCA_TCINDEX_MAX, opt) < 0) - return -EINVAL; + err = nla_parse_nested(tb, TCA_TCINDEX_MAX, opt, tcindex_policy); + if (err < 0) + return err; - return tcindex_set_parms(tp, base, handle, p, r, tb, tca[TCA_RATE-1]); + return tcindex_set_parms(tp, base, handle, p, r, tb, tca[TCA_RATE]); } static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker) { struct tcindex_data *p = PRIV(tp); - struct tcindex_filter *f,*next; + struct tcindex_filter *f, *next; int i; - DPRINTK("tcindex_walk(tp %p,walker %p),p %p\n",tp,walker,p); + pr_debug("tcindex_walk(tp %p,walker %p),p %p\n", tp, walker, p); if (p->perfect) { for (i = 0; i < p->hash; i++) { if (!p->perfect[i].res.class) @@ -405,7 +389,7 @@ static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker) for (f = p->h[i]; f; f = next) { next = f->next; if (walker->count >= walker->skip) { - if (walker->fn(tp,(unsigned long) &f->result, + if (walker->fn(tp, (unsigned long) &f->result, walker) < 0) { walker->stop = 1; return; @@ -429,11 +413,11 @@ static void tcindex_destroy(struct tcf_proto *tp) struct tcindex_data *p = PRIV(tp); struct tcf_walker walker; - DPRINTK("tcindex_destroy(tp %p),p %p\n",tp,p); + pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p); walker.count = 0; walker.skip = 0; walker.fn = &tcindex_destroy_element; - tcindex_walk(tp,&walker); + tcindex_walk(tp, &walker); kfree(p->perfect); kfree(p->h); kfree(p); @@ -447,21 +431,23 @@ static int tcindex_dump(struct tcf_proto *tp, unsigned long fh, struct tcindex_data *p = PRIV(tp); struct tcindex_filter_result *r = (struct tcindex_filter_result *) fh; unsigned char *b = skb_tail_pointer(skb); - struct rtattr *rta; + struct nlattr *nest; + + pr_debug("tcindex_dump(tp %p,fh 0x%lx,skb %p,t %p),p %p,r %p,b %p\n", + tp, fh, skb, t, p, r, b); + pr_debug("p->perfect %p p->h %p\n", p->perfect, p->h); + + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; - DPRINTK("tcindex_dump(tp %p,fh 0x%lx,skb %p,t %p),p %p,r %p,b %p\n", - tp,fh,skb,t,p,r,b); - DPRINTK("p->perfect %p p->h %p\n",p->perfect,p->h); - rta = (struct rtattr *) b; - RTA_PUT(skb,TCA_OPTIONS,0,NULL); if (!fh) { t->tcm_handle = ~0; /* whatever ... */ - RTA_PUT(skb,TCA_TCINDEX_HASH,sizeof(p->hash),&p->hash); - RTA_PUT(skb,TCA_TCINDEX_MASK,sizeof(p->mask),&p->mask); - RTA_PUT(skb,TCA_TCINDEX_SHIFT,sizeof(p->shift),&p->shift); - RTA_PUT(skb,TCA_TCINDEX_FALL_THROUGH,sizeof(p->fall_through), - &p->fall_through); - rta->rta_len = skb_tail_pointer(skb) - b; + NLA_PUT_U32(skb, TCA_TCINDEX_HASH, p->hash); + NLA_PUT_U16(skb, TCA_TCINDEX_MASK, p->mask); + NLA_PUT_U32(skb, TCA_TCINDEX_SHIFT, p->shift); + NLA_PUT_U32(skb, TCA_TCINDEX_FALL_THROUGH, p->fall_through); + nla_nest_end(skb, nest); } else { if (p->perfect) { t->tcm_handle = r-p->perfect; @@ -478,27 +464,26 @@ static int tcindex_dump(struct tcf_proto *tp, unsigned long fh, } } } - DPRINTK("handle = %d\n",t->tcm_handle); + pr_debug("handle = %d\n", t->tcm_handle); if (r->res.class) - RTA_PUT(skb, TCA_TCINDEX_CLASSID, 4, &r->res.classid); + NLA_PUT_U32(skb, TCA_TCINDEX_CLASSID, r->res.classid); if (tcf_exts_dump(skb, &r->exts, &tcindex_ext_map) < 0) - goto rtattr_failure; - rta->rta_len = skb_tail_pointer(skb) - b; + goto nla_put_failure; + nla_nest_end(skb, nest); if (tcf_exts_dump_stats(skb, &r->exts, &tcindex_ext_map) < 0) - goto rtattr_failure; + goto nla_put_failure; } return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } -static struct tcf_proto_ops cls_tcindex_ops = { - .next = NULL, +static struct tcf_proto_ops cls_tcindex_ops __read_mostly = { .kind = "tcindex", .classify = tcindex_classify, .init = tcindex_init, diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index c3900820916..e8a77568912 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -460,10 +460,20 @@ static u32 gen_new_kid(struct tc_u_hnode *ht, u32 handle) return handle|(i>0xFFF ? 0xFFF : i); } +static const struct nla_policy u32_policy[TCA_U32_MAX + 1] = { + [TCA_U32_CLASSID] = { .type = NLA_U32 }, + [TCA_U32_HASH] = { .type = NLA_U32 }, + [TCA_U32_LINK] = { .type = NLA_U32 }, + [TCA_U32_DIVISOR] = { .type = NLA_U32 }, + [TCA_U32_SEL] = { .len = sizeof(struct tc_u32_sel) }, + [TCA_U32_INDEV] = { .type = NLA_STRING, .len = IFNAMSIZ }, + [TCA_U32_MARK] = { .len = sizeof(struct tc_u32_mark) }, +}; + static int u32_set_parms(struct tcf_proto *tp, unsigned long base, struct tc_u_hnode *ht, - struct tc_u_knode *n, struct rtattr **tb, - struct rtattr *est) + struct tc_u_knode *n, struct nlattr **tb, + struct nlattr *est) { int err; struct tcf_exts e; @@ -473,8 +483,8 @@ static int u32_set_parms(struct tcf_proto *tp, unsigned long base, return err; err = -EINVAL; - if (tb[TCA_U32_LINK-1]) { - u32 handle = *(u32*)RTA_DATA(tb[TCA_U32_LINK-1]); + if (tb[TCA_U32_LINK]) { + u32 handle = nla_get_u32(tb[TCA_U32_LINK]); struct tc_u_hnode *ht_down = NULL; if (TC_U32_KEY(handle)) @@ -495,14 +505,14 @@ static int u32_set_parms(struct tcf_proto *tp, unsigned long base, if (ht_down) ht_down->refcnt--; } - if (tb[TCA_U32_CLASSID-1]) { - n->res.classid = *(u32*)RTA_DATA(tb[TCA_U32_CLASSID-1]); + if (tb[TCA_U32_CLASSID]) { + n->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]); tcf_bind_filter(tp, &n->res, base); } #ifdef CONFIG_NET_CLS_IND - if (tb[TCA_U32_INDEV-1]) { - err = tcf_change_indev(tp, n->indev, tb[TCA_U32_INDEV-1]); + if (tb[TCA_U32_INDEV]) { + err = tcf_change_indev(tp, n->indev, tb[TCA_U32_INDEV]); if (err < 0) goto errout; } @@ -516,33 +526,34 @@ errout: } static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle, - struct rtattr **tca, + struct nlattr **tca, unsigned long *arg) { struct tc_u_common *tp_c = tp->data; struct tc_u_hnode *ht; struct tc_u_knode *n; struct tc_u32_sel *s; - struct rtattr *opt = tca[TCA_OPTIONS-1]; - struct rtattr *tb[TCA_U32_MAX]; + struct nlattr *opt = tca[TCA_OPTIONS]; + struct nlattr *tb[TCA_U32_MAX + 1]; u32 htid; int err; if (opt == NULL) return handle ? -EINVAL : 0; - if (rtattr_parse_nested(tb, TCA_U32_MAX, opt) < 0) - return -EINVAL; + err = nla_parse_nested(tb, TCA_U32_MAX, opt, u32_policy); + if (err < 0) + return err; if ((n = (struct tc_u_knode*)*arg) != NULL) { if (TC_U32_KEY(n->handle) == 0) return -EINVAL; - return u32_set_parms(tp, base, n->ht_up, n, tb, tca[TCA_RATE-1]); + return u32_set_parms(tp, base, n->ht_up, n, tb, tca[TCA_RATE]); } - if (tb[TCA_U32_DIVISOR-1]) { - unsigned divisor = *(unsigned*)RTA_DATA(tb[TCA_U32_DIVISOR-1]); + if (tb[TCA_U32_DIVISOR]) { + unsigned divisor = nla_get_u32(tb[TCA_U32_DIVISOR]); if (--divisor > 0x100) return -EINVAL; @@ -567,8 +578,8 @@ static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle, return 0; } - if (tb[TCA_U32_HASH-1]) { - htid = *(unsigned*)RTA_DATA(tb[TCA_U32_HASH-1]); + if (tb[TCA_U32_HASH]) { + htid = nla_get_u32(tb[TCA_U32_HASH]); if (TC_U32_HTID(htid) == TC_U32_ROOT) { ht = tp->root; htid = ht->handle; @@ -592,11 +603,10 @@ static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle, } else handle = gen_new_kid(ht, htid); - if (tb[TCA_U32_SEL-1] == NULL || - RTA_PAYLOAD(tb[TCA_U32_SEL-1]) < sizeof(struct tc_u32_sel)) + if (tb[TCA_U32_SEL] == NULL) return -EINVAL; - s = RTA_DATA(tb[TCA_U32_SEL-1]); + s = nla_data(tb[TCA_U32_SEL]); n = kzalloc(sizeof(*n) + s->nkeys*sizeof(struct tc_u32_key), GFP_KERNEL); if (n == NULL) @@ -616,23 +626,16 @@ static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle, n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0; #ifdef CONFIG_CLS_U32_MARK - if (tb[TCA_U32_MARK-1]) { + if (tb[TCA_U32_MARK]) { struct tc_u32_mark *mark; - if (RTA_PAYLOAD(tb[TCA_U32_MARK-1]) < sizeof(struct tc_u32_mark)) { -#ifdef CONFIG_CLS_U32_PERF - kfree(n->pf); -#endif - kfree(n); - return -EINVAL; - } - mark = RTA_DATA(tb[TCA_U32_MARK-1]); + mark = nla_data(tb[TCA_U32_MARK]); memcpy(&n->mark, mark, sizeof(struct tc_u32_mark)); n->mark.success = 0; } #endif - err = u32_set_parms(tp, base, ht, n, tb, tca[TCA_RATE-1]); + err = u32_set_parms(tp, base, ht, n, tb, tca[TCA_RATE]); if (err == 0) { struct tc_u_knode **ins; for (ins = &ht->ht[TC_U32_HASH(handle)]; *ins; ins = &(*ins)->next) @@ -693,66 +696,66 @@ static int u32_dump(struct tcf_proto *tp, unsigned long fh, struct sk_buff *skb, struct tcmsg *t) { struct tc_u_knode *n = (struct tc_u_knode*)fh; - unsigned char *b = skb_tail_pointer(skb); - struct rtattr *rta; + struct nlattr *nest; if (n == NULL) return skb->len; t->tcm_handle = n->handle; - rta = (struct rtattr*)b; - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; if (TC_U32_KEY(n->handle) == 0) { struct tc_u_hnode *ht = (struct tc_u_hnode*)fh; u32 divisor = ht->divisor+1; - RTA_PUT(skb, TCA_U32_DIVISOR, 4, &divisor); + NLA_PUT_U32(skb, TCA_U32_DIVISOR, divisor); } else { - RTA_PUT(skb, TCA_U32_SEL, + NLA_PUT(skb, TCA_U32_SEL, sizeof(n->sel) + n->sel.nkeys*sizeof(struct tc_u32_key), &n->sel); if (n->ht_up) { u32 htid = n->handle & 0xFFFFF000; - RTA_PUT(skb, TCA_U32_HASH, 4, &htid); + NLA_PUT_U32(skb, TCA_U32_HASH, htid); } if (n->res.classid) - RTA_PUT(skb, TCA_U32_CLASSID, 4, &n->res.classid); + NLA_PUT_U32(skb, TCA_U32_CLASSID, n->res.classid); if (n->ht_down) - RTA_PUT(skb, TCA_U32_LINK, 4, &n->ht_down->handle); + NLA_PUT_U32(skb, TCA_U32_LINK, n->ht_down->handle); #ifdef CONFIG_CLS_U32_MARK if (n->mark.val || n->mark.mask) - RTA_PUT(skb, TCA_U32_MARK, sizeof(n->mark), &n->mark); + NLA_PUT(skb, TCA_U32_MARK, sizeof(n->mark), &n->mark); #endif if (tcf_exts_dump(skb, &n->exts, &u32_ext_map) < 0) - goto rtattr_failure; + goto nla_put_failure; #ifdef CONFIG_NET_CLS_IND if(strlen(n->indev)) - RTA_PUT(skb, TCA_U32_INDEV, IFNAMSIZ, n->indev); + NLA_PUT_STRING(skb, TCA_U32_INDEV, n->indev); #endif #ifdef CONFIG_CLS_U32_PERF - RTA_PUT(skb, TCA_U32_PCNT, + NLA_PUT(skb, TCA_U32_PCNT, sizeof(struct tc_u32_pcnt) + n->sel.nkeys*sizeof(u64), n->pf); #endif } - rta->rta_len = skb_tail_pointer(skb) - b; + nla_nest_end(skb, nest); + if (TC_U32_KEY(n->handle)) if (tcf_exts_dump_stats(skb, &n->exts, &u32_ext_map) < 0) - goto rtattr_failure; + goto nla_put_failure; return skb->len; -rtattr_failure: - nlmsg_trim(skb, b); +nla_put_failure: + nla_nest_cancel(skb, nest); return -1; } -static struct tcf_proto_ops cls_u32_ops = { - .next = NULL, +static struct tcf_proto_ops cls_u32_ops __read_mostly = { .kind = "u32", .classify = u32_classify, .init = u32_init, diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index ceda8890ab0..a1e5619b187 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -542,11 +542,11 @@ static int meta_var_compare(struct meta_obj *a, struct meta_obj *b) return r; } -static int meta_var_change(struct meta_value *dst, struct rtattr *rta) +static int meta_var_change(struct meta_value *dst, struct nlattr *nla) { - int len = RTA_PAYLOAD(rta); + int len = nla_len(nla); - dst->val = (unsigned long)kmemdup(RTA_DATA(rta), len, GFP_KERNEL); + dst->val = (unsigned long)kmemdup(nla_data(nla), len, GFP_KERNEL); if (dst->val == 0UL) return -ENOMEM; dst->len = len; @@ -570,10 +570,10 @@ static void meta_var_apply_extras(struct meta_value *v, static int meta_var_dump(struct sk_buff *skb, struct meta_value *v, int tlv) { if (v->val && v->len) - RTA_PUT(skb, tlv, v->len, (void *) v->val); + NLA_PUT(skb, tlv, v->len, (void *) v->val); return 0; -rtattr_failure: +nla_put_failure: return -1; } @@ -594,13 +594,13 @@ static int meta_int_compare(struct meta_obj *a, struct meta_obj *b) return 1; } -static int meta_int_change(struct meta_value *dst, struct rtattr *rta) +static int meta_int_change(struct meta_value *dst, struct nlattr *nla) { - if (RTA_PAYLOAD(rta) >= sizeof(unsigned long)) { - dst->val = *(unsigned long *) RTA_DATA(rta); + if (nla_len(nla) >= sizeof(unsigned long)) { + dst->val = *(unsigned long *) nla_data(nla); dst->len = sizeof(unsigned long); - } else if (RTA_PAYLOAD(rta) == sizeof(u32)) { - dst->val = *(u32 *) RTA_DATA(rta); + } else if (nla_len(nla) == sizeof(u32)) { + dst->val = nla_get_u32(nla); dst->len = sizeof(u32); } else return -EINVAL; @@ -621,15 +621,14 @@ static void meta_int_apply_extras(struct meta_value *v, static int meta_int_dump(struct sk_buff *skb, struct meta_value *v, int tlv) { if (v->len == sizeof(unsigned long)) - RTA_PUT(skb, tlv, sizeof(unsigned long), &v->val); + NLA_PUT(skb, tlv, sizeof(unsigned long), &v->val); else if (v->len == sizeof(u32)) { - u32 d = v->val; - RTA_PUT(skb, tlv, sizeof(d), &d); + NLA_PUT_U32(skb, tlv, v->val); } return 0; -rtattr_failure: +nla_put_failure: return -1; } @@ -641,7 +640,7 @@ struct meta_type_ops { void (*destroy)(struct meta_value *); int (*compare)(struct meta_obj *, struct meta_obj *); - int (*change)(struct meta_value *, struct rtattr *); + int (*change)(struct meta_value *, struct nlattr *); void (*apply_extras)(struct meta_value *, struct meta_obj *); int (*dump)(struct sk_buff *, struct meta_value *, int); }; @@ -729,13 +728,13 @@ static inline void meta_delete(struct meta_match *meta) kfree(meta); } -static inline int meta_change_data(struct meta_value *dst, struct rtattr *rta) +static inline int meta_change_data(struct meta_value *dst, struct nlattr *nla) { - if (rta) { - if (RTA_PAYLOAD(rta) == 0) + if (nla) { + if (nla_len(nla) == 0) return -EINVAL; - return meta_type_ops(dst)->change(dst, rta); + return meta_type_ops(dst)->change(dst, nla); } return 0; @@ -746,21 +745,26 @@ static inline int meta_is_supported(struct meta_value *val) return (!meta_id(val) || meta_ops(val)->get); } +static const struct nla_policy meta_policy[TCA_EM_META_MAX + 1] = { + [TCA_EM_META_HDR] = { .len = sizeof(struct tcf_meta_hdr) }, +}; + static int em_meta_change(struct tcf_proto *tp, void *data, int len, struct tcf_ematch *m) { - int err = -EINVAL; - struct rtattr *tb[TCA_EM_META_MAX]; + int err; + struct nlattr *tb[TCA_EM_META_MAX + 1]; struct tcf_meta_hdr *hdr; struct meta_match *meta = NULL; - if (rtattr_parse(tb, TCA_EM_META_MAX, data, len) < 0) + err = nla_parse(tb, TCA_EM_META_MAX, data, len, meta_policy); + if (err < 0) goto errout; - if (tb[TCA_EM_META_HDR-1] == NULL || - RTA_PAYLOAD(tb[TCA_EM_META_HDR-1]) < sizeof(*hdr)) + err = -EINVAL; + if (tb[TCA_EM_META_HDR] == NULL) goto errout; - hdr = RTA_DATA(tb[TCA_EM_META_HDR-1]); + hdr = nla_data(tb[TCA_EM_META_HDR]); if (TCF_META_TYPE(hdr->left.kind) != TCF_META_TYPE(hdr->right.kind) || TCF_META_TYPE(hdr->left.kind) > TCF_META_TYPE_MAX || @@ -781,8 +785,8 @@ static int em_meta_change(struct tcf_proto *tp, void *data, int len, goto errout; } - if (meta_change_data(&meta->lvalue, tb[TCA_EM_META_LVALUE-1]) < 0 || - meta_change_data(&meta->rvalue, tb[TCA_EM_META_RVALUE-1]) < 0) + if (meta_change_data(&meta->lvalue, tb[TCA_EM_META_LVALUE]) < 0 || + meta_change_data(&meta->rvalue, tb[TCA_EM_META_RVALUE]) < 0) goto errout; m->datalen = sizeof(*meta); @@ -811,16 +815,16 @@ static int em_meta_dump(struct sk_buff *skb, struct tcf_ematch *em) memcpy(&hdr.left, &meta->lvalue.hdr, sizeof(hdr.left)); memcpy(&hdr.right, &meta->rvalue.hdr, sizeof(hdr.right)); - RTA_PUT(skb, TCA_EM_META_HDR, sizeof(hdr), &hdr); + NLA_PUT(skb, TCA_EM_META_HDR, sizeof(hdr), &hdr); ops = meta_type_ops(&meta->lvalue); if (ops->dump(skb, &meta->lvalue, TCA_EM_META_LVALUE) < 0 || ops->dump(skb, &meta->rvalue, TCA_EM_META_RVALUE) < 0) - goto rtattr_failure; + goto nla_put_failure; return 0; -rtattr_failure: +nla_put_failure: return -1; } diff --git a/net/sched/em_text.c b/net/sched/em_text.c index d5cd86efb7d..853c5ead87f 100644 --- a/net/sched/em_text.c +++ b/net/sched/em_text.c @@ -118,11 +118,14 @@ static int em_text_dump(struct sk_buff *skb, struct tcf_ematch *m) conf.pattern_len = textsearch_get_pattern_len(tm->config); conf.pad = 0; - RTA_PUT_NOHDR(skb, sizeof(conf), &conf); - RTA_APPEND(skb, conf.pattern_len, textsearch_get_pattern(tm->config)); + if (nla_put_nohdr(skb, sizeof(conf), &conf) < 0) + goto nla_put_failure; + if (nla_append(skb, conf.pattern_len, + textsearch_get_pattern(tm->config)) < 0) + goto nla_put_failure; return 0; -rtattr_failure: +nla_put_failure: return -1; } diff --git a/net/sched/ematch.c b/net/sched/ematch.c index f3a104e323b..74ff918455a 100644 --- a/net/sched/ematch.c +++ b/net/sched/ematch.c @@ -141,6 +141,7 @@ errout: write_unlock(&ematch_mod_lock); return err; } +EXPORT_SYMBOL(tcf_em_register); /** * tcf_em_unregister - unregster and extended match @@ -171,6 +172,7 @@ out: write_unlock(&ematch_mod_lock); return err; } +EXPORT_SYMBOL(tcf_em_unregister); static inline struct tcf_ematch * tcf_em_get_match(struct tcf_ematch_tree *tree, int index) @@ -181,11 +183,11 @@ static inline struct tcf_ematch * tcf_em_get_match(struct tcf_ematch_tree *tree, static int tcf_em_validate(struct tcf_proto *tp, struct tcf_ematch_tree_hdr *tree_hdr, - struct tcf_ematch *em, struct rtattr *rta, int idx) + struct tcf_ematch *em, struct nlattr *nla, int idx) { int err = -EINVAL; - struct tcf_ematch_hdr *em_hdr = RTA_DATA(rta); - int data_len = RTA_PAYLOAD(rta) - sizeof(*em_hdr); + struct tcf_ematch_hdr *em_hdr = nla_data(nla); + int data_len = nla_len(nla) - sizeof(*em_hdr); void *data = (void *) em_hdr + sizeof(*em_hdr); if (!TCF_EM_REL_VALID(em_hdr->flags)) @@ -280,15 +282,20 @@ errout: return err; } +static const struct nla_policy em_policy[TCA_EMATCH_TREE_MAX + 1] = { + [TCA_EMATCH_TREE_HDR] = { .len = sizeof(struct tcf_ematch_tree_hdr) }, + [TCA_EMATCH_TREE_LIST] = { .type = NLA_NESTED }, +}; + /** * tcf_em_tree_validate - validate ematch config TLV and build ematch tree * * @tp: classifier kind handle - * @rta: ematch tree configuration TLV + * @nla: ematch tree configuration TLV * @tree: destination ematch tree variable to store the resulting * ematch tree. * - * This function validates the given configuration TLV @rta and builds an + * This function validates the given configuration TLV @nla and builds an * ematch tree in @tree. The resulting tree must later be copied into * the private classifier data using tcf_em_tree_change(). You MUST NOT * provide the ematch tree variable of the private classifier data directly, @@ -296,45 +303,43 @@ errout: * * Returns a negative error code if the configuration TLV contains errors. */ -int tcf_em_tree_validate(struct tcf_proto *tp, struct rtattr *rta, +int tcf_em_tree_validate(struct tcf_proto *tp, struct nlattr *nla, struct tcf_ematch_tree *tree) { - int idx, list_len, matches_len, err = -EINVAL; - struct rtattr *tb[TCA_EMATCH_TREE_MAX]; - struct rtattr *rt_match, *rt_hdr, *rt_list; + int idx, list_len, matches_len, err; + struct nlattr *tb[TCA_EMATCH_TREE_MAX + 1]; + struct nlattr *rt_match, *rt_hdr, *rt_list; struct tcf_ematch_tree_hdr *tree_hdr; struct tcf_ematch *em; - if (!rta) { + if (!nla) { memset(tree, 0, sizeof(*tree)); return 0; } - if (rtattr_parse_nested(tb, TCA_EMATCH_TREE_MAX, rta) < 0) + err = nla_parse_nested(tb, TCA_EMATCH_TREE_MAX, nla, em_policy); + if (err < 0) goto errout; - rt_hdr = tb[TCA_EMATCH_TREE_HDR-1]; - rt_list = tb[TCA_EMATCH_TREE_LIST-1]; + err = -EINVAL; + rt_hdr = tb[TCA_EMATCH_TREE_HDR]; + rt_list = tb[TCA_EMATCH_TREE_LIST]; if (rt_hdr == NULL || rt_list == NULL) goto errout; - if (RTA_PAYLOAD(rt_hdr) < sizeof(*tree_hdr) || - RTA_PAYLOAD(rt_list) < sizeof(*rt_match)) - goto errout; - - tree_hdr = RTA_DATA(rt_hdr); + tree_hdr = nla_data(rt_hdr); memcpy(&tree->hdr, tree_hdr, sizeof(*tree_hdr)); - rt_match = RTA_DATA(rt_list); - list_len = RTA_PAYLOAD(rt_list); + rt_match = nla_data(rt_list); + list_len = nla_len(rt_list); matches_len = tree_hdr->nmatches * sizeof(*em); tree->matches = kzalloc(matches_len, GFP_KERNEL); if (tree->matches == NULL) goto errout; - /* We do not use rtattr_parse_nested here because the maximum + /* We do not use nla_parse_nested here because the maximum * number of attributes is unknown. This saves us the allocation * for a tb buffer which would serve no purpose at all. * @@ -342,16 +347,16 @@ int tcf_em_tree_validate(struct tcf_proto *tp, struct rtattr *rta, * provided, their type must be incremental from 1 to n. Even * if it does not serve any real purpose, a failure of sticking * to this policy will result in parsing failure. */ - for (idx = 0; RTA_OK(rt_match, list_len); idx++) { + for (idx = 0; nla_ok(rt_match, list_len); idx++) { err = -EINVAL; - if (rt_match->rta_type != (idx + 1)) + if (rt_match->nla_type != (idx + 1)) goto errout_abort; if (idx >= tree_hdr->nmatches) goto errout_abort; - if (RTA_PAYLOAD(rt_match) < sizeof(struct tcf_ematch_hdr)) + if (nla_len(rt_match) < sizeof(struct tcf_ematch_hdr)) goto errout_abort; em = tcf_em_get_match(tree, idx); @@ -360,7 +365,7 @@ int tcf_em_tree_validate(struct tcf_proto *tp, struct rtattr *rta, if (err < 0) goto errout_abort; - rt_match = RTA_NEXT(rt_match, list_len); + rt_match = nla_next(rt_match, &list_len); } /* Check if the number of matches provided by userspace actually @@ -380,6 +385,7 @@ errout_abort: tcf_em_tree_destroy(tp, tree); return err; } +EXPORT_SYMBOL(tcf_em_tree_validate); /** * tcf_em_tree_destroy - destroy an ematch tree @@ -413,6 +419,7 @@ void tcf_em_tree_destroy(struct tcf_proto *tp, struct tcf_ematch_tree *tree) tree->hdr.nmatches = 0; kfree(tree->matches); } +EXPORT_SYMBOL(tcf_em_tree_destroy); /** * tcf_em_tree_dump - dump ematch tree into a rtnl message @@ -430,18 +437,22 @@ int tcf_em_tree_dump(struct sk_buff *skb, struct tcf_ematch_tree *tree, int tlv) { int i; u8 *tail; - struct rtattr *top_start = (struct rtattr *)skb_tail_pointer(skb); - struct rtattr *list_start; + struct nlattr *top_start; + struct nlattr *list_start; + + top_start = nla_nest_start(skb, tlv); + if (top_start == NULL) + goto nla_put_failure; - RTA_PUT(skb, tlv, 0, NULL); - RTA_PUT(skb, TCA_EMATCH_TREE_HDR, sizeof(tree->hdr), &tree->hdr); + NLA_PUT(skb, TCA_EMATCH_TREE_HDR, sizeof(tree->hdr), &tree->hdr); - list_start = (struct rtattr *)skb_tail_pointer(skb); - RTA_PUT(skb, TCA_EMATCH_TREE_LIST, 0, NULL); + list_start = nla_nest_start(skb, TCA_EMATCH_TREE_LIST); + if (list_start == NULL) + goto nla_put_failure; tail = skb_tail_pointer(skb); for (i = 0; i < tree->hdr.nmatches; i++) { - struct rtattr *match_start = (struct rtattr *)tail; + struct nlattr *match_start = (struct nlattr *)tail; struct tcf_ematch *em = tcf_em_get_match(tree, i); struct tcf_ematch_hdr em_hdr = { .kind = em->ops ? em->ops->kind : TCF_EM_CONTAINER, @@ -449,29 +460,30 @@ int tcf_em_tree_dump(struct sk_buff *skb, struct tcf_ematch_tree *tree, int tlv) .flags = em->flags }; - RTA_PUT(skb, i+1, sizeof(em_hdr), &em_hdr); + NLA_PUT(skb, i+1, sizeof(em_hdr), &em_hdr); if (em->ops && em->ops->dump) { if (em->ops->dump(skb, em) < 0) - goto rtattr_failure; + goto nla_put_failure; } else if (tcf_em_is_container(em) || tcf_em_is_simple(em)) { u32 u = em->data; - RTA_PUT_NOHDR(skb, sizeof(u), &u); + nla_put_nohdr(skb, sizeof(u), &u); } else if (em->datalen > 0) - RTA_PUT_NOHDR(skb, em->datalen, (void *) em->data); + nla_put_nohdr(skb, em->datalen, (void *) em->data); tail = skb_tail_pointer(skb); - match_start->rta_len = tail - (u8 *)match_start; + match_start->nla_len = tail - (u8 *)match_start; } - list_start->rta_len = tail - (u8 *)list_start; - top_start->rta_len = tail - (u8 *)top_start; + nla_nest_end(skb, list_start); + nla_nest_end(skb, top_start); return 0; -rtattr_failure: +nla_put_failure: return -1; } +EXPORT_SYMBOL(tcf_em_tree_dump); static inline int tcf_em_match(struct sk_buff *skb, struct tcf_ematch *em, struct tcf_pkt_info *info) @@ -529,10 +541,4 @@ stack_overflow: printk("Local stack overflow, increase NET_EMATCH_STACK\n"); return -1; } - -EXPORT_SYMBOL(tcf_em_register); -EXPORT_SYMBOL(tcf_em_unregister); -EXPORT_SYMBOL(tcf_em_tree_validate); -EXPORT_SYMBOL(tcf_em_tree_destroy); -EXPORT_SYMBOL(tcf_em_tree_dump); EXPORT_SYMBOL(__tcf_em_tree_match); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 8ae137e3522..7e3c048ba9b 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -29,6 +29,7 @@ #include <linux/hrtimer.h> #include <net/net_namespace.h> +#include <net/sock.h> #include <net/netlink.h> #include <net/pkt_sched.h> @@ -157,6 +158,7 @@ out: write_unlock(&qdisc_mod_lock); return rc; } +EXPORT_SYMBOL(register_qdisc); int unregister_qdisc(struct Qdisc_ops *qops) { @@ -175,6 +177,7 @@ int unregister_qdisc(struct Qdisc_ops *qops) write_unlock(&qdisc_mod_lock); return err; } +EXPORT_SYMBOL(unregister_qdisc); /* We know handle. Find qdisc among all qdisc's attached to device (root qdisc, all its children, children of children etc.) @@ -195,7 +198,7 @@ static struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid) { unsigned long cl; struct Qdisc *leaf; - struct Qdisc_class_ops *cops = p->ops->cl_ops; + const struct Qdisc_class_ops *cops = p->ops->cl_ops; if (cops == NULL) return NULL; @@ -210,14 +213,14 @@ static struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid) /* Find queueing discipline by name */ -static struct Qdisc_ops *qdisc_lookup_ops(struct rtattr *kind) +static struct Qdisc_ops *qdisc_lookup_ops(struct nlattr *kind) { struct Qdisc_ops *q = NULL; if (kind) { read_lock(&qdisc_mod_lock); for (q = qdisc_base; q; q = q->next) { - if (rtattr_strcmp(kind, q->id) == 0) { + if (nla_strcmp(kind, q->id) == 0) { if (!try_module_get(q->owner)) q = NULL; break; @@ -230,7 +233,7 @@ static struct Qdisc_ops *qdisc_lookup_ops(struct rtattr *kind) static struct qdisc_rate_table *qdisc_rtab_list; -struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct rtattr *tab) +struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct nlattr *tab) { struct qdisc_rate_table *rtab; @@ -241,19 +244,21 @@ struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct rtattr *ta } } - if (tab == NULL || r->rate == 0 || r->cell_log == 0 || RTA_PAYLOAD(tab) != 1024) + if (tab == NULL || r->rate == 0 || r->cell_log == 0 || + nla_len(tab) != TC_RTAB_SIZE) return NULL; rtab = kmalloc(sizeof(*rtab), GFP_KERNEL); if (rtab) { rtab->rate = *r; rtab->refcnt = 1; - memcpy(rtab->data, RTA_DATA(tab), 1024); + memcpy(rtab->data, nla_data(tab), 1024); rtab->next = qdisc_rtab_list; qdisc_rtab_list = rtab; } return rtab; } +EXPORT_SYMBOL(qdisc_get_rtab); void qdisc_put_rtab(struct qdisc_rate_table *tab) { @@ -270,6 +275,7 @@ void qdisc_put_rtab(struct qdisc_rate_table *tab) } } } +EXPORT_SYMBOL(qdisc_put_rtab); static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer) { @@ -373,7 +379,7 @@ dev_graft_qdisc(struct net_device *dev, struct Qdisc *qdisc) void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n) { - struct Qdisc_class_ops *cops; + const struct Qdisc_class_ops *cops; unsigned long cl; u32 parentid; @@ -417,7 +423,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, *old = dev_graft_qdisc(dev, new); } } else { - struct Qdisc_class_ops *cops = parent->ops->cl_ops; + const struct Qdisc_class_ops *cops = parent->ops->cl_ops; err = -EINVAL; @@ -440,10 +446,10 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, static struct Qdisc * qdisc_create(struct net_device *dev, u32 parent, u32 handle, - struct rtattr **tca, int *errp) + struct nlattr **tca, int *errp) { int err; - struct rtattr *kind = tca[TCA_KIND-1]; + struct nlattr *kind = tca[TCA_KIND]; struct Qdisc *sch; struct Qdisc_ops *ops; @@ -451,7 +457,7 @@ qdisc_create(struct net_device *dev, u32 parent, u32 handle, #ifdef CONFIG_KMOD if (ops == NULL && kind != NULL) { char name[IFNAMSIZ]; - if (rtattr_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) { + if (nla_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) { /* We dropped the RTNL semaphore in order to * perform the module load. So, even if we * succeeded in loading the module we have to @@ -504,11 +510,11 @@ qdisc_create(struct net_device *dev, u32 parent, u32 handle, sch->handle = handle; - if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS-1])) == 0) { - if (tca[TCA_RATE-1]) { + if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS])) == 0) { + if (tca[TCA_RATE]) { err = gen_new_estimator(&sch->bstats, &sch->rate_est, sch->stats_lock, - tca[TCA_RATE-1]); + tca[TCA_RATE]); if (err) { /* * Any broken qdiscs that would require @@ -536,20 +542,20 @@ err_out: return NULL; } -static int qdisc_change(struct Qdisc *sch, struct rtattr **tca) +static int qdisc_change(struct Qdisc *sch, struct nlattr **tca) { - if (tca[TCA_OPTIONS-1]) { + if (tca[TCA_OPTIONS]) { int err; if (sch->ops->change == NULL) return -EINVAL; - err = sch->ops->change(sch, tca[TCA_OPTIONS-1]); + err = sch->ops->change(sch, tca[TCA_OPTIONS]); if (err) return err; } - if (tca[TCA_RATE-1]) + if (tca[TCA_RATE]) gen_replace_estimator(&sch->bstats, &sch->rate_est, - sch->stats_lock, tca[TCA_RATE-1]); + sch->stats_lock, tca[TCA_RATE]); return 0; } @@ -581,7 +587,7 @@ static int check_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w) { struct Qdisc *leaf; - struct Qdisc_class_ops *cops = q->ops->cl_ops; + const struct Qdisc_class_ops *cops = q->ops->cl_ops; struct check_loop_arg *arg = (struct check_loop_arg *)w; leaf = cops->leaf(q, cl); @@ -599,17 +605,25 @@ check_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w) static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { + struct net *net = skb->sk->sk_net; struct tcmsg *tcm = NLMSG_DATA(n); - struct rtattr **tca = arg; + struct nlattr *tca[TCA_MAX + 1]; struct net_device *dev; u32 clid = tcm->tcm_parent; struct Qdisc *q = NULL; struct Qdisc *p = NULL; int err; + if (net != &init_net) + return -EINVAL; + if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) return -ENODEV; + err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); + if (err < 0) + return err; + if (clid) { if (clid != TC_H_ROOT) { if (TC_H_MAJ(clid) != TC_H_MAJ(TC_H_INGRESS)) { @@ -632,7 +646,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) return -ENOENT; } - if (tca[TCA_KIND-1] && rtattr_strcmp(tca[TCA_KIND-1], q->ops->id)) + if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) return -EINVAL; if (n->nlmsg_type == RTM_DELQDISC) { @@ -660,23 +674,30 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { + struct net *net = skb->sk->sk_net; struct tcmsg *tcm; - struct rtattr **tca; + struct nlattr *tca[TCA_MAX + 1]; struct net_device *dev; u32 clid; struct Qdisc *q, *p; int err; + if (net != &init_net) + return -EINVAL; + replay: /* Reinit, just in case something touches this. */ tcm = NLMSG_DATA(n); - tca = arg; clid = tcm->tcm_parent; q = p = NULL; if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) return -ENODEV; + err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); + if (err < 0) + return err; + if (clid) { if (clid != TC_H_ROOT) { if (clid != TC_H_INGRESS) { @@ -704,7 +725,7 @@ replay: goto create_n_graft; if (n->nlmsg_flags&NLM_F_EXCL) return -EEXIST; - if (tca[TCA_KIND-1] && rtattr_strcmp(tca[TCA_KIND-1], q->ops->id)) + if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) return -EINVAL; if (q == p || (p && check_loop(q, p, 0))) @@ -737,8 +758,8 @@ replay: if ((n->nlmsg_flags&NLM_F_CREATE) && (n->nlmsg_flags&NLM_F_REPLACE) && ((n->nlmsg_flags&NLM_F_EXCL) || - (tca[TCA_KIND-1] && - rtattr_strcmp(tca[TCA_KIND-1], q->ops->id)))) + (tca[TCA_KIND] && + nla_strcmp(tca[TCA_KIND], q->ops->id)))) goto create_n_graft; } } @@ -753,7 +774,7 @@ replay: return -ENOENT; if (n->nlmsg_flags&NLM_F_EXCL) return -EEXIST; - if (tca[TCA_KIND-1] && rtattr_strcmp(tca[TCA_KIND-1], q->ops->id)) + if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) return -EINVAL; err = qdisc_change(q, tca); if (err == 0) @@ -814,31 +835,31 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, tcm->tcm_parent = clid; tcm->tcm_handle = q->handle; tcm->tcm_info = atomic_read(&q->refcnt); - RTA_PUT(skb, TCA_KIND, IFNAMSIZ, q->ops->id); + NLA_PUT_STRING(skb, TCA_KIND, q->ops->id); if (q->ops->dump && q->ops->dump(q, skb) < 0) - goto rtattr_failure; + goto nla_put_failure; q->qstats.qlen = q->q.qlen; if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS, q->stats_lock, &d) < 0) - goto rtattr_failure; + goto nla_put_failure; if (q->ops->dump_stats && q->ops->dump_stats(q, &d) < 0) - goto rtattr_failure; + goto nla_put_failure; if (gnet_stats_copy_basic(&d, &q->bstats) < 0 || gnet_stats_copy_rate_est(&d, &q->rate_est) < 0 || gnet_stats_copy_queue(&d, &q->qstats) < 0) - goto rtattr_failure; + goto nla_put_failure; if (gnet_stats_finish_copy(&d) < 0) - goto rtattr_failure; + goto nla_put_failure; nlh->nlmsg_len = skb_tail_pointer(skb) - b; return skb->len; nlmsg_failure: -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } @@ -863,7 +884,7 @@ static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, } if (skb->len) - return rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); + return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); err_out: kfree_skb(skb); @@ -872,11 +893,15 @@ err_out: static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) { + struct net *net = skb->sk->sk_net; int idx, q_idx; int s_idx, s_q_idx; struct net_device *dev; struct Qdisc *q; + if (net != &init_net) + return 0; + s_idx = cb->args[0]; s_q_idx = q_idx = cb->args[1]; read_lock(&dev_base_lock); @@ -920,11 +945,12 @@ done: static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { + struct net *net = skb->sk->sk_net; struct tcmsg *tcm = NLMSG_DATA(n); - struct rtattr **tca = arg; + struct nlattr *tca[TCA_MAX + 1]; struct net_device *dev; struct Qdisc *q = NULL; - struct Qdisc_class_ops *cops; + const struct Qdisc_class_ops *cops; unsigned long cl = 0; unsigned long new_cl; u32 pid = tcm->tcm_parent; @@ -932,9 +958,16 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) u32 qid = TC_H_MAJ(clid); int err; + if (net != &init_net) + return -EINVAL; + if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) return -ENODEV; + err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); + if (err < 0) + return err; + /* parent == TC_H_UNSPEC - unspecified parent. parent == TC_H_ROOT - class is root, which has no parent. @@ -1039,7 +1072,7 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q, struct nlmsghdr *nlh; unsigned char *b = skb_tail_pointer(skb); struct gnet_dump d; - struct Qdisc_class_ops *cl_ops = q->ops->cl_ops; + const struct Qdisc_class_ops *cl_ops = q->ops->cl_ops; nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags); tcm = NLMSG_DATA(nlh); @@ -1048,25 +1081,25 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q, tcm->tcm_parent = q->handle; tcm->tcm_handle = q->handle; tcm->tcm_info = 0; - RTA_PUT(skb, TCA_KIND, IFNAMSIZ, q->ops->id); + NLA_PUT_STRING(skb, TCA_KIND, q->ops->id); if (cl_ops->dump && cl_ops->dump(q, cl, skb, tcm) < 0) - goto rtattr_failure; + goto nla_put_failure; if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS, q->stats_lock, &d) < 0) - goto rtattr_failure; + goto nla_put_failure; if (cl_ops->dump_stats && cl_ops->dump_stats(q, cl, &d) < 0) - goto rtattr_failure; + goto nla_put_failure; if (gnet_stats_finish_copy(&d) < 0) - goto rtattr_failure; + goto nla_put_failure; nlh->nlmsg_len = skb_tail_pointer(skb) - b; return skb->len; nlmsg_failure: -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } @@ -1086,7 +1119,7 @@ static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n, return -EINVAL; } - return rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); + return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); } struct qdisc_dump_args @@ -1106,6 +1139,7 @@ static int qdisc_class_dump(struct Qdisc *q, unsigned long cl, struct qdisc_walk static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) { + struct net *net = skb->sk->sk_net; int t; int s_t; struct net_device *dev; @@ -1113,6 +1147,9 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) struct tcmsg *tcm = (struct tcmsg*)NLMSG_DATA(cb->nlh); struct qdisc_dump_args arg; + if (net != &init_net) + return 0; + if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) return 0; if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) @@ -1268,8 +1305,3 @@ static int __init pktsched_init(void) } subsys_initcall(pktsched_init); - -EXPORT_SYMBOL(qdisc_get_rtab); -EXPORT_SYMBOL(qdisc_put_rtab); -EXPORT_SYMBOL(register_qdisc); -EXPORT_SYMBOL(unregister_qdisc); diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index ddc4f2c5437..33527341638 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -16,18 +16,6 @@ extern struct socket *sockfd_lookup(int fd, int *err); /* @@@ fix this */ -#if 0 /* control */ -#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define DPRINTK(format,args...) -#endif - -#if 0 /* data */ -#define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define D2PRINTK(format,args...) -#endif - /* * The ATM queuing discipline provides a framework for invoking classifiers * (aka "filters"), which in turn select classes of this queuing discipline. @@ -49,7 +37,6 @@ extern struct socket *sockfd_lookup(int fd, int *err); /* @@@ fix this */ * - should lock the flow while there is data in the queue (?) */ -#define PRIV(sch) qdisc_priv(sch) #define VCC2FLOW(vcc) ((struct atm_flow_data *) ((vcc)->user_back)) struct atm_flow_data { @@ -57,7 +44,7 @@ struct atm_flow_data { struct tcf_proto *filter_list; struct atm_vcc *vcc; /* VCC; NULL if VCC is closed */ void (*old_pop)(struct atm_vcc *vcc, - struct sk_buff * skb); /* chaining */ + struct sk_buff *skb); /* chaining */ struct atm_qdisc_data *parent; /* parent qdisc */ struct socket *sock; /* for closing */ u32 classid; /* x:y type ID */ @@ -84,17 +71,17 @@ static int find_flow(struct atm_qdisc_data *qdisc, struct atm_flow_data *flow) { struct atm_flow_data *walk; - DPRINTK("find_flow(qdisc %p,flow %p)\n", qdisc, flow); + pr_debug("find_flow(qdisc %p,flow %p)\n", qdisc, flow); for (walk = qdisc->flows; walk; walk = walk->next) if (walk == flow) return 1; - DPRINTK("find_flow: not found\n"); + pr_debug("find_flow: not found\n"); return 0; } static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid) { - struct atm_qdisc_data *p = PRIV(sch); + struct atm_qdisc_data *p = qdisc_priv(sch); struct atm_flow_data *flow; for (flow = p->flows; flow; flow = flow->next) @@ -106,10 +93,10 @@ static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid) static int atm_tc_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, struct Qdisc **old) { - struct atm_qdisc_data *p = PRIV(sch); + struct atm_qdisc_data *p = qdisc_priv(sch); struct atm_flow_data *flow = (struct atm_flow_data *)arg; - DPRINTK("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n", + pr_debug("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n", sch, p, flow, new, old); if (!find_flow(p, flow)) return -EINVAL; @@ -125,20 +112,20 @@ static struct Qdisc *atm_tc_leaf(struct Qdisc *sch, unsigned long cl) { struct atm_flow_data *flow = (struct atm_flow_data *)cl; - DPRINTK("atm_tc_leaf(sch %p,flow %p)\n", sch, flow); + pr_debug("atm_tc_leaf(sch %p,flow %p)\n", sch, flow); return flow ? flow->q : NULL; } static unsigned long atm_tc_get(struct Qdisc *sch, u32 classid) { - struct atm_qdisc_data *p __maybe_unused = PRIV(sch); + struct atm_qdisc_data *p __maybe_unused = qdisc_priv(sch); struct atm_flow_data *flow; - DPRINTK("atm_tc_get(sch %p,[qdisc %p],classid %x)\n", sch, p, classid); + pr_debug("atm_tc_get(sch %p,[qdisc %p],classid %x)\n", sch, p, classid); flow = lookup_flow(sch, classid); if (flow) flow->ref++; - DPRINTK("atm_tc_get: flow %p\n", flow); + pr_debug("atm_tc_get: flow %p\n", flow); return (unsigned long)flow; } @@ -155,14 +142,14 @@ static unsigned long atm_tc_bind_filter(struct Qdisc *sch, */ static void atm_tc_put(struct Qdisc *sch, unsigned long cl) { - struct atm_qdisc_data *p = PRIV(sch); + struct atm_qdisc_data *p = qdisc_priv(sch); struct atm_flow_data *flow = (struct atm_flow_data *)cl; struct atm_flow_data **prev; - DPRINTK("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); + pr_debug("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); if (--flow->ref) return; - DPRINTK("atm_tc_put: destroying\n"); + pr_debug("atm_tc_put: destroying\n"); for (prev = &p->flows; *prev; prev = &(*prev)->next) if (*prev == flow) break; @@ -171,11 +158,11 @@ static void atm_tc_put(struct Qdisc *sch, unsigned long cl) return; } *prev = flow->next; - DPRINTK("atm_tc_put: qdisc %p\n", flow->q); + pr_debug("atm_tc_put: qdisc %p\n", flow->q); qdisc_destroy(flow->q); tcf_destroy_chain(flow->filter_list); if (flow->sock) { - DPRINTK("atm_tc_put: f_count %d\n", + pr_debug("atm_tc_put: f_count %d\n", file_count(flow->sock->file)); flow->vcc->pop = flow->old_pop; sockfd_put(flow->sock); @@ -194,7 +181,7 @@ static void sch_atm_pop(struct atm_vcc *vcc, struct sk_buff *skb) { struct atm_qdisc_data *p = VCC2FLOW(vcc)->parent; - D2PRINTK("sch_atm_pop(vcc %p,skb %p,[qdisc %p])\n", vcc, skb, p); + pr_debug("sch_atm_pop(vcc %p,skb %p,[qdisc %p])\n", vcc, skb, p); VCC2FLOW(vcc)->old_pop(vcc, skb); tasklet_schedule(&p->task); } @@ -208,19 +195,24 @@ static const u8 llc_oui_ip[] = { 0x08, 0x00 }; /* Ethertype IP (0800) */ +static const struct nla_policy atm_policy[TCA_ATM_MAX + 1] = { + [TCA_ATM_FD] = { .type = NLA_U32 }, + [TCA_ATM_EXCESS] = { .type = NLA_U32 }, +}; + static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, - struct rtattr **tca, unsigned long *arg) + struct nlattr **tca, unsigned long *arg) { - struct atm_qdisc_data *p = PRIV(sch); + struct atm_qdisc_data *p = qdisc_priv(sch); struct atm_flow_data *flow = (struct atm_flow_data *)*arg; struct atm_flow_data *excess = NULL; - struct rtattr *opt = tca[TCA_OPTIONS - 1]; - struct rtattr *tb[TCA_ATM_MAX]; + struct nlattr *opt = tca[TCA_OPTIONS]; + struct nlattr *tb[TCA_ATM_MAX + 1]; struct socket *sock; int fd, error, hdr_len; void *hdr; - DPRINTK("atm_tc_change(sch %p,[qdisc %p],classid %x,parent %x," + pr_debug("atm_tc_change(sch %p,[qdisc %p],classid %x,parent %x," "flow %p,opt %p)\n", sch, p, classid, parent, flow, opt); /* * The concept of parents doesn't apply for this qdisc. @@ -236,34 +228,38 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, */ if (flow) return -EBUSY; - if (opt == NULL || rtattr_parse_nested(tb, TCA_ATM_MAX, opt)) + if (opt == NULL) return -EINVAL; - if (!tb[TCA_ATM_FD - 1] || RTA_PAYLOAD(tb[TCA_ATM_FD - 1]) < sizeof(fd)) + + error = nla_parse_nested(tb, TCA_ATM_MAX, opt, atm_policy); + if (error < 0) + return error; + + if (!tb[TCA_ATM_FD]) return -EINVAL; - fd = *(int *)RTA_DATA(tb[TCA_ATM_FD - 1]); - DPRINTK("atm_tc_change: fd %d\n", fd); - if (tb[TCA_ATM_HDR - 1]) { - hdr_len = RTA_PAYLOAD(tb[TCA_ATM_HDR - 1]); - hdr = RTA_DATA(tb[TCA_ATM_HDR - 1]); + fd = nla_get_u32(tb[TCA_ATM_FD]); + pr_debug("atm_tc_change: fd %d\n", fd); + if (tb[TCA_ATM_HDR]) { + hdr_len = nla_len(tb[TCA_ATM_HDR]); + hdr = nla_data(tb[TCA_ATM_HDR]); } else { hdr_len = RFC1483LLC_LEN; hdr = NULL; /* default LLC/SNAP for IP */ } - if (!tb[TCA_ATM_EXCESS - 1]) + if (!tb[TCA_ATM_EXCESS]) excess = NULL; else { - if (RTA_PAYLOAD(tb[TCA_ATM_EXCESS - 1]) != sizeof(u32)) - return -EINVAL; excess = (struct atm_flow_data *) - atm_tc_get(sch, *(u32 *)RTA_DATA(tb[TCA_ATM_EXCESS - 1])); + atm_tc_get(sch, nla_get_u32(tb[TCA_ATM_EXCESS])); if (!excess) return -ENOENT; } - DPRINTK("atm_tc_change: type %d, payload %d, hdr_len %d\n", - opt->rta_type, RTA_PAYLOAD(opt), hdr_len); - if (!(sock = sockfd_lookup(fd, &error))) + pr_debug("atm_tc_change: type %d, payload %d, hdr_len %d\n", + opt->nla_type, nla_len(opt), hdr_len); + sock = sockfd_lookup(fd, &error); + if (!sock) return error; /* f_count++ */ - DPRINTK("atm_tc_change: f_count %d\n", file_count(sock->file)); + pr_debug("atm_tc_change: f_count %d\n", file_count(sock->file)); if (sock->ops->family != PF_ATMSVC && sock->ops->family != PF_ATMPVC) { error = -EPROTOTYPE; goto err_out; @@ -272,7 +268,7 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, on vcc->send */ if (classid) { if (TC_H_MAJ(classid ^ sch->handle)) { - DPRINTK("atm_tc_change: classid mismatch\n"); + pr_debug("atm_tc_change: classid mismatch\n"); error = -EINVAL; goto err_out; } @@ -286,26 +282,28 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, for (i = 1; i < 0x8000; i++) { classid = TC_H_MAKE(sch->handle, 0x8000 | i); - if (!(cl = atm_tc_get(sch, classid))) + cl = atm_tc_get(sch, classid); + if (!cl) break; atm_tc_put(sch, cl); } } - DPRINTK("atm_tc_change: new id %x\n", classid); + pr_debug("atm_tc_change: new id %x\n", classid); flow = kzalloc(sizeof(struct atm_flow_data) + hdr_len, GFP_KERNEL); - DPRINTK("atm_tc_change: flow %p\n", flow); + pr_debug("atm_tc_change: flow %p\n", flow); if (!flow) { error = -ENOBUFS; goto err_out; } flow->filter_list = NULL; - if (!(flow->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid))) + flow->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid); + if (!flow->q) flow->q = &noop_qdisc; - DPRINTK("atm_tc_change: qdisc %p\n", flow->q); + pr_debug("atm_tc_change: qdisc %p\n", flow->q); flow->sock = sock; flow->vcc = ATM_SD(sock); /* speedup */ flow->vcc->user_back = flow; - DPRINTK("atm_tc_change: vcc %p\n", flow->vcc); + pr_debug("atm_tc_change: vcc %p\n", flow->vcc); flow->old_pop = flow->vcc->pop; flow->parent = p; flow->vcc->pop = sch_atm_pop; @@ -330,11 +328,11 @@ err_out: static int atm_tc_delete(struct Qdisc *sch, unsigned long arg) { - struct atm_qdisc_data *p = PRIV(sch); + struct atm_qdisc_data *p = qdisc_priv(sch); struct atm_flow_data *flow = (struct atm_flow_data *)arg; - DPRINTK("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); - if (!find_flow(PRIV(sch), flow)) + pr_debug("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); + if (!find_flow(qdisc_priv(sch), flow)) return -EINVAL; if (flow->filter_list || flow == &p->link) return -EBUSY; @@ -354,10 +352,10 @@ static int atm_tc_delete(struct Qdisc *sch, unsigned long arg) static void atm_tc_walk(struct Qdisc *sch, struct qdisc_walker *walker) { - struct atm_qdisc_data *p = PRIV(sch); + struct atm_qdisc_data *p = qdisc_priv(sch); struct atm_flow_data *flow; - DPRINTK("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker); + pr_debug("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker); if (walker->stop) return; for (flow = p->flows; flow; flow = flow->next) { @@ -372,10 +370,10 @@ static void atm_tc_walk(struct Qdisc *sch, struct qdisc_walker *walker) static struct tcf_proto **atm_tc_find_tcf(struct Qdisc *sch, unsigned long cl) { - struct atm_qdisc_data *p = PRIV(sch); + struct atm_qdisc_data *p = qdisc_priv(sch); struct atm_flow_data *flow = (struct atm_flow_data *)cl; - DPRINTK("atm_tc_find_tcf(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); + pr_debug("atm_tc_find_tcf(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); return flow ? &flow->filter_list : &p->link.filter_list; } @@ -383,13 +381,13 @@ static struct tcf_proto **atm_tc_find_tcf(struct Qdisc *sch, unsigned long cl) static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch) { - struct atm_qdisc_data *p = PRIV(sch); + struct atm_qdisc_data *p = qdisc_priv(sch); struct atm_flow_data *flow = NULL; /* @@@ */ struct tcf_result res; int result; int ret = NET_XMIT_POLICED; - D2PRINTK("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); + pr_debug("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); result = TC_POLICE_OK; /* be nice to gcc */ if (TC_H_MAJ(skb->priority) != sch->handle || !(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority))) @@ -430,7 +428,8 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch) #endif } - if ((ret = flow->q->enqueue(skb, flow->q)) != 0) { + ret = flow->q->enqueue(skb, flow->q); + if (ret != 0) { drop: __maybe_unused sch->qstats.drops++; if (flow) @@ -468,11 +467,11 @@ drop: __maybe_unused static void sch_atm_dequeue(unsigned long data) { struct Qdisc *sch = (struct Qdisc *)data; - struct atm_qdisc_data *p = PRIV(sch); + struct atm_qdisc_data *p = qdisc_priv(sch); struct atm_flow_data *flow; struct sk_buff *skb; - D2PRINTK("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p); + pr_debug("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p); for (flow = p->link.next; flow; flow = flow->next) /* * If traffic is properly shaped, this won't generate nasty @@ -483,7 +482,7 @@ static void sch_atm_dequeue(unsigned long data) (void)flow->q->ops->requeue(skb, flow->q); break; } - D2PRINTK("atm_tc_dequeue: sending on class %p\n", flow); + pr_debug("atm_tc_dequeue: sending on class %p\n", flow); /* remove any LL header somebody else has attached */ skb_pull(skb, skb_network_offset(skb)); if (skb_headroom(skb) < flow->hdr_len) { @@ -495,7 +494,7 @@ static void sch_atm_dequeue(unsigned long data) continue; skb = new; } - D2PRINTK("sch_atm_dequeue: ip %p, data %p\n", + pr_debug("sch_atm_dequeue: ip %p, data %p\n", skb_network_header(skb), skb->data); ATM_SKB(skb)->vcc = flow->vcc; memcpy(skb_push(skb, flow->hdr_len), flow->hdr, @@ -509,10 +508,10 @@ static void sch_atm_dequeue(unsigned long data) static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch) { - struct atm_qdisc_data *p = PRIV(sch); + struct atm_qdisc_data *p = qdisc_priv(sch); struct sk_buff *skb; - D2PRINTK("atm_tc_dequeue(sch %p,[qdisc %p])\n", sch, p); + pr_debug("atm_tc_dequeue(sch %p,[qdisc %p])\n", sch, p); tasklet_schedule(&p->task); skb = p->link.q->dequeue(p->link.q); if (skb) @@ -522,10 +521,10 @@ static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch) static int atm_tc_requeue(struct sk_buff *skb, struct Qdisc *sch) { - struct atm_qdisc_data *p = PRIV(sch); + struct atm_qdisc_data *p = qdisc_priv(sch); int ret; - D2PRINTK("atm_tc_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); + pr_debug("atm_tc_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); ret = p->link.q->ops->requeue(skb, p->link.q); if (!ret) { sch->q.qlen++; @@ -539,27 +538,27 @@ static int atm_tc_requeue(struct sk_buff *skb, struct Qdisc *sch) static unsigned int atm_tc_drop(struct Qdisc *sch) { - struct atm_qdisc_data *p = PRIV(sch); + struct atm_qdisc_data *p = qdisc_priv(sch); struct atm_flow_data *flow; unsigned int len; - DPRINTK("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p); + pr_debug("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p); for (flow = p->flows; flow; flow = flow->next) if (flow->q->ops->drop && (len = flow->q->ops->drop(flow->q))) return len; return 0; } -static int atm_tc_init(struct Qdisc *sch, struct rtattr *opt) +static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt) { - struct atm_qdisc_data *p = PRIV(sch); + struct atm_qdisc_data *p = qdisc_priv(sch); - DPRINTK("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt); + pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt); p->flows = &p->link; - if (!(p->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, - sch->handle))) + p->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, sch->handle); + if (!p->link.q) p->link.q = &noop_qdisc; - DPRINTK("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q); + pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q); p->link.filter_list = NULL; p->link.vcc = NULL; p->link.sock = NULL; @@ -572,10 +571,10 @@ static int atm_tc_init(struct Qdisc *sch, struct rtattr *opt) static void atm_tc_reset(struct Qdisc *sch) { - struct atm_qdisc_data *p = PRIV(sch); + struct atm_qdisc_data *p = qdisc_priv(sch); struct atm_flow_data *flow; - DPRINTK("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p); + pr_debug("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p); for (flow = p->flows; flow; flow = flow->next) qdisc_reset(flow->q); sch->q.qlen = 0; @@ -583,10 +582,10 @@ static void atm_tc_reset(struct Qdisc *sch) static void atm_tc_destroy(struct Qdisc *sch) { - struct atm_qdisc_data *p = PRIV(sch); + struct atm_qdisc_data *p = qdisc_priv(sch); struct atm_flow_data *flow; - DPRINTK("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p); + pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p); /* races ? */ while ((flow = p->flows)) { tcf_destroy_chain(flow->filter_list); @@ -608,20 +607,22 @@ static void atm_tc_destroy(struct Qdisc *sch) static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, struct tcmsg *tcm) { - struct atm_qdisc_data *p = PRIV(sch); + struct atm_qdisc_data *p = qdisc_priv(sch); struct atm_flow_data *flow = (struct atm_flow_data *)cl; - unsigned char *b = skb_tail_pointer(skb); - struct rtattr *rta; + struct nlattr *nest; - DPRINTK("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n", + pr_debug("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n", sch, p, flow, skb, tcm); if (!find_flow(p, flow)) return -EINVAL; tcm->tcm_handle = flow->classid; tcm->tcm_info = flow->q->handle; - rta = (struct rtattr *)b; - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); - RTA_PUT(skb, TCA_ATM_HDR, flow->hdr_len, flow->hdr); + + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; + + NLA_PUT(skb, TCA_ATM_HDR, flow->hdr_len, flow->hdr); if (flow->vcc) { struct sockaddr_atmpvc pvc; int state; @@ -630,22 +631,21 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl, pvc.sap_addr.itf = flow->vcc->dev ? flow->vcc->dev->number : -1; pvc.sap_addr.vpi = flow->vcc->vpi; pvc.sap_addr.vci = flow->vcc->vci; - RTA_PUT(skb, TCA_ATM_ADDR, sizeof(pvc), &pvc); + NLA_PUT(skb, TCA_ATM_ADDR, sizeof(pvc), &pvc); state = ATM_VF2VS(flow->vcc->flags); - RTA_PUT(skb, TCA_ATM_STATE, sizeof(state), &state); + NLA_PUT_U32(skb, TCA_ATM_STATE, state); } if (flow->excess) - RTA_PUT(skb, TCA_ATM_EXCESS, sizeof(u32), &flow->classid); + NLA_PUT_U32(skb, TCA_ATM_EXCESS, flow->classid); else { - static u32 zero; - - RTA_PUT(skb, TCA_ATM_EXCESS, sizeof(zero), &zero); + NLA_PUT_U32(skb, TCA_ATM_EXCESS, 0); } - rta->rta_len = skb_tail_pointer(skb) - b; + + nla_nest_end(skb, nest); return skb->len; -rtattr_failure: - nlmsg_trim(skb, b); +nla_put_failure: + nla_nest_cancel(skb, nest); return -1; } static int @@ -668,7 +668,7 @@ static int atm_tc_dump(struct Qdisc *sch, struct sk_buff *skb) return 0; } -static struct Qdisc_class_ops atm_class_ops = { +static const struct Qdisc_class_ops atm_class_ops = { .graft = atm_tc_graft, .leaf = atm_tc_leaf, .get = atm_tc_get, @@ -683,7 +683,7 @@ static struct Qdisc_class_ops atm_class_ops = { .dump_stats = atm_tc_dump_class_stats, }; -static struct Qdisc_ops atm_qdisc_ops = { +static struct Qdisc_ops atm_qdisc_ops __read_mostly = { .cl_ops = &atm_class_ops, .id = "atm", .priv_size = sizeof(struct atm_qdisc_data), diff --git a/net/sched/sch_blackhole.c b/net/sched/sch_blackhole.c index f914fc43a12..507fb488bc9 100644 --- a/net/sched/sch_blackhole.c +++ b/net/sched/sch_blackhole.c @@ -28,7 +28,7 @@ static struct sk_buff *blackhole_dequeue(struct Qdisc *sch) return NULL; } -static struct Qdisc_ops blackhole_qdisc_ops = { +static struct Qdisc_ops blackhole_qdisc_ops __read_mostly = { .id = "blackhole", .priv_size = 0, .enqueue = blackhole_enqueue, diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 4de3744e65c..09969c1fbc0 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1377,24 +1377,33 @@ static int cbq_set_fopt(struct cbq_class *cl, struct tc_cbq_fopt *fopt) return 0; } -static int cbq_init(struct Qdisc *sch, struct rtattr *opt) +static const struct nla_policy cbq_policy[TCA_CBQ_MAX + 1] = { + [TCA_CBQ_LSSOPT] = { .len = sizeof(struct tc_cbq_lssopt) }, + [TCA_CBQ_WRROPT] = { .len = sizeof(struct tc_cbq_wrropt) }, + [TCA_CBQ_FOPT] = { .len = sizeof(struct tc_cbq_fopt) }, + [TCA_CBQ_OVL_STRATEGY] = { .len = sizeof(struct tc_cbq_ovl) }, + [TCA_CBQ_RATE] = { .len = sizeof(struct tc_ratespec) }, + [TCA_CBQ_RTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE }, + [TCA_CBQ_POLICE] = { .len = sizeof(struct tc_cbq_police) }, +}; + +static int cbq_init(struct Qdisc *sch, struct nlattr *opt) { struct cbq_sched_data *q = qdisc_priv(sch); - struct rtattr *tb[TCA_CBQ_MAX]; + struct nlattr *tb[TCA_CBQ_MAX + 1]; struct tc_ratespec *r; + int err; - if (rtattr_parse_nested(tb, TCA_CBQ_MAX, opt) < 0 || - tb[TCA_CBQ_RTAB-1] == NULL || tb[TCA_CBQ_RATE-1] == NULL || - RTA_PAYLOAD(tb[TCA_CBQ_RATE-1]) < sizeof(struct tc_ratespec)) - return -EINVAL; + err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy); + if (err < 0) + return err; - if (tb[TCA_CBQ_LSSOPT-1] && - RTA_PAYLOAD(tb[TCA_CBQ_LSSOPT-1]) < sizeof(struct tc_cbq_lssopt)) + if (tb[TCA_CBQ_RTAB] == NULL || tb[TCA_CBQ_RATE] == NULL) return -EINVAL; - r = RTA_DATA(tb[TCA_CBQ_RATE-1]); + r = nla_data(tb[TCA_CBQ_RATE]); - if ((q->link.R_tab = qdisc_get_rtab(r, tb[TCA_CBQ_RTAB-1])) == NULL) + if ((q->link.R_tab = qdisc_get_rtab(r, tb[TCA_CBQ_RTAB])) == NULL) return -EINVAL; q->link.refcnt = 1; @@ -1427,8 +1436,8 @@ static int cbq_init(struct Qdisc *sch, struct rtattr *opt) cbq_link_class(&q->link); - if (tb[TCA_CBQ_LSSOPT-1]) - cbq_set_lss(&q->link, RTA_DATA(tb[TCA_CBQ_LSSOPT-1])); + if (tb[TCA_CBQ_LSSOPT]) + cbq_set_lss(&q->link, nla_data(tb[TCA_CBQ_LSSOPT])); cbq_addprio(q, &q->link); return 0; @@ -1438,10 +1447,10 @@ static __inline__ int cbq_dump_rate(struct sk_buff *skb, struct cbq_class *cl) { unsigned char *b = skb_tail_pointer(skb); - RTA_PUT(skb, TCA_CBQ_RATE, sizeof(cl->R_tab->rate), &cl->R_tab->rate); + NLA_PUT(skb, TCA_CBQ_RATE, sizeof(cl->R_tab->rate), &cl->R_tab->rate); return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } @@ -1463,10 +1472,10 @@ static __inline__ int cbq_dump_lss(struct sk_buff *skb, struct cbq_class *cl) opt.minidle = (u32)(-cl->minidle); opt.offtime = cl->offtime; opt.change = ~0; - RTA_PUT(skb, TCA_CBQ_LSSOPT, sizeof(opt), &opt); + NLA_PUT(skb, TCA_CBQ_LSSOPT, sizeof(opt), &opt); return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } @@ -1481,10 +1490,10 @@ static __inline__ int cbq_dump_wrr(struct sk_buff *skb, struct cbq_class *cl) opt.priority = cl->priority+1; opt.cpriority = cl->cpriority+1; opt.weight = cl->weight; - RTA_PUT(skb, TCA_CBQ_WRROPT, sizeof(opt), &opt); + NLA_PUT(skb, TCA_CBQ_WRROPT, sizeof(opt), &opt); return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } @@ -1498,10 +1507,10 @@ static __inline__ int cbq_dump_ovl(struct sk_buff *skb, struct cbq_class *cl) opt.priority2 = cl->priority2+1; opt.pad = 0; opt.penalty = cl->penalty; - RTA_PUT(skb, TCA_CBQ_OVL_STRATEGY, sizeof(opt), &opt); + NLA_PUT(skb, TCA_CBQ_OVL_STRATEGY, sizeof(opt), &opt); return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } @@ -1515,11 +1524,11 @@ static __inline__ int cbq_dump_fopt(struct sk_buff *skb, struct cbq_class *cl) opt.split = cl->split ? cl->split->classid : 0; opt.defmap = cl->defmap; opt.defchange = ~0; - RTA_PUT(skb, TCA_CBQ_FOPT, sizeof(opt), &opt); + NLA_PUT(skb, TCA_CBQ_FOPT, sizeof(opt), &opt); } return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } @@ -1534,11 +1543,11 @@ static __inline__ int cbq_dump_police(struct sk_buff *skb, struct cbq_class *cl) opt.police = cl->police; opt.__res1 = 0; opt.__res2 = 0; - RTA_PUT(skb, TCA_CBQ_POLICE, sizeof(opt), &opt); + NLA_PUT(skb, TCA_CBQ_POLICE, sizeof(opt), &opt); } return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } @@ -1561,18 +1570,18 @@ static int cbq_dump_attr(struct sk_buff *skb, struct cbq_class *cl) static int cbq_dump(struct Qdisc *sch, struct sk_buff *skb) { struct cbq_sched_data *q = qdisc_priv(sch); - unsigned char *b = skb_tail_pointer(skb); - struct rtattr *rta; + struct nlattr *nest; - rta = (struct rtattr*)b; - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; if (cbq_dump_attr(skb, &q->link) < 0) - goto rtattr_failure; - rta->rta_len = skb_tail_pointer(skb) - b; + goto nla_put_failure; + nla_nest_end(skb, nest); return skb->len; -rtattr_failure: - nlmsg_trim(skb, b); +nla_put_failure: + nla_nest_cancel(skb, nest); return -1; } @@ -1590,8 +1599,7 @@ cbq_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb, struct tcmsg *tcm) { struct cbq_class *cl = (struct cbq_class*)arg; - unsigned char *b = skb_tail_pointer(skb); - struct rtattr *rta; + struct nlattr *nest; if (cl->tparent) tcm->tcm_parent = cl->tparent->classid; @@ -1600,15 +1608,16 @@ cbq_dump_class(struct Qdisc *sch, unsigned long arg, tcm->tcm_handle = cl->classid; tcm->tcm_info = cl->q->handle; - rta = (struct rtattr*)b; - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; if (cbq_dump_attr(skb, cl) < 0) - goto rtattr_failure; - rta->rta_len = skb_tail_pointer(skb) - b; + goto nla_put_failure; + nla_nest_end(skb, nest); return skb->len; -rtattr_failure: - nlmsg_trim(skb, b); +nla_put_failure: + nla_nest_cancel(skb, nest); return -1; } @@ -1753,45 +1762,23 @@ static void cbq_put(struct Qdisc *sch, unsigned long arg) } static int -cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **tca, +cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **tca, unsigned long *arg) { int err; struct cbq_sched_data *q = qdisc_priv(sch); struct cbq_class *cl = (struct cbq_class*)*arg; - struct rtattr *opt = tca[TCA_OPTIONS-1]; - struct rtattr *tb[TCA_CBQ_MAX]; + struct nlattr *opt = tca[TCA_OPTIONS]; + struct nlattr *tb[TCA_CBQ_MAX + 1]; struct cbq_class *parent; struct qdisc_rate_table *rtab = NULL; - if (opt==NULL || rtattr_parse_nested(tb, TCA_CBQ_MAX, opt)) + if (opt == NULL) return -EINVAL; - if (tb[TCA_CBQ_OVL_STRATEGY-1] && - RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY-1]) < sizeof(struct tc_cbq_ovl)) - return -EINVAL; - - if (tb[TCA_CBQ_FOPT-1] && - RTA_PAYLOAD(tb[TCA_CBQ_FOPT-1]) < sizeof(struct tc_cbq_fopt)) - return -EINVAL; - - if (tb[TCA_CBQ_RATE-1] && - RTA_PAYLOAD(tb[TCA_CBQ_RATE-1]) < sizeof(struct tc_ratespec)) - return -EINVAL; - - if (tb[TCA_CBQ_LSSOPT-1] && - RTA_PAYLOAD(tb[TCA_CBQ_LSSOPT-1]) < sizeof(struct tc_cbq_lssopt)) - return -EINVAL; - - if (tb[TCA_CBQ_WRROPT-1] && - RTA_PAYLOAD(tb[TCA_CBQ_WRROPT-1]) < sizeof(struct tc_cbq_wrropt)) - return -EINVAL; - -#ifdef CONFIG_NET_CLS_ACT - if (tb[TCA_CBQ_POLICE-1] && - RTA_PAYLOAD(tb[TCA_CBQ_POLICE-1]) < sizeof(struct tc_cbq_police)) - return -EINVAL; -#endif + err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy); + if (err < 0) + return err; if (cl) { /* Check parent */ @@ -1802,8 +1789,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t return -EINVAL; } - if (tb[TCA_CBQ_RATE-1]) { - rtab = qdisc_get_rtab(RTA_DATA(tb[TCA_CBQ_RATE-1]), tb[TCA_CBQ_RTAB-1]); + if (tb[TCA_CBQ_RATE]) { + rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), tb[TCA_CBQ_RTAB]); if (rtab == NULL) return -EINVAL; } @@ -1819,45 +1806,45 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t qdisc_put_rtab(rtab); } - if (tb[TCA_CBQ_LSSOPT-1]) - cbq_set_lss(cl, RTA_DATA(tb[TCA_CBQ_LSSOPT-1])); + if (tb[TCA_CBQ_LSSOPT]) + cbq_set_lss(cl, nla_data(tb[TCA_CBQ_LSSOPT])); - if (tb[TCA_CBQ_WRROPT-1]) { + if (tb[TCA_CBQ_WRROPT]) { cbq_rmprio(q, cl); - cbq_set_wrr(cl, RTA_DATA(tb[TCA_CBQ_WRROPT-1])); + cbq_set_wrr(cl, nla_data(tb[TCA_CBQ_WRROPT])); } - if (tb[TCA_CBQ_OVL_STRATEGY-1]) - cbq_set_overlimit(cl, RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY-1])); + if (tb[TCA_CBQ_OVL_STRATEGY]) + cbq_set_overlimit(cl, nla_data(tb[TCA_CBQ_OVL_STRATEGY])); #ifdef CONFIG_NET_CLS_ACT - if (tb[TCA_CBQ_POLICE-1]) - cbq_set_police(cl, RTA_DATA(tb[TCA_CBQ_POLICE-1])); + if (tb[TCA_CBQ_POLICE]) + cbq_set_police(cl, nla_data(tb[TCA_CBQ_POLICE])); #endif - if (tb[TCA_CBQ_FOPT-1]) - cbq_set_fopt(cl, RTA_DATA(tb[TCA_CBQ_FOPT-1])); + if (tb[TCA_CBQ_FOPT]) + cbq_set_fopt(cl, nla_data(tb[TCA_CBQ_FOPT])); if (cl->q->q.qlen) cbq_activate_class(cl); sch_tree_unlock(sch); - if (tca[TCA_RATE-1]) + if (tca[TCA_RATE]) gen_replace_estimator(&cl->bstats, &cl->rate_est, &sch->dev->queue_lock, - tca[TCA_RATE-1]); + tca[TCA_RATE]); return 0; } if (parentid == TC_H_ROOT) return -EINVAL; - if (tb[TCA_CBQ_WRROPT-1] == NULL || tb[TCA_CBQ_RATE-1] == NULL || - tb[TCA_CBQ_LSSOPT-1] == NULL) + if (tb[TCA_CBQ_WRROPT] == NULL || tb[TCA_CBQ_RATE] == NULL || + tb[TCA_CBQ_LSSOPT] == NULL) return -EINVAL; - rtab = qdisc_get_rtab(RTA_DATA(tb[TCA_CBQ_RATE-1]), tb[TCA_CBQ_RTAB-1]); + rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), tb[TCA_CBQ_RTAB]); if (rtab == NULL) return -EINVAL; @@ -1912,8 +1899,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t cl->share = cl->tparent; cbq_adjust_levels(parent); cl->minidle = -0x7FFFFFFF; - cbq_set_lss(cl, RTA_DATA(tb[TCA_CBQ_LSSOPT-1])); - cbq_set_wrr(cl, RTA_DATA(tb[TCA_CBQ_WRROPT-1])); + cbq_set_lss(cl, nla_data(tb[TCA_CBQ_LSSOPT])); + cbq_set_wrr(cl, nla_data(tb[TCA_CBQ_WRROPT])); if (cl->ewma_log==0) cl->ewma_log = q->link.ewma_log; if (cl->maxidle==0) @@ -1921,19 +1908,19 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t if (cl->avpkt==0) cl->avpkt = q->link.avpkt; cl->overlimit = cbq_ovl_classic; - if (tb[TCA_CBQ_OVL_STRATEGY-1]) - cbq_set_overlimit(cl, RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY-1])); + if (tb[TCA_CBQ_OVL_STRATEGY]) + cbq_set_overlimit(cl, nla_data(tb[TCA_CBQ_OVL_STRATEGY])); #ifdef CONFIG_NET_CLS_ACT - if (tb[TCA_CBQ_POLICE-1]) - cbq_set_police(cl, RTA_DATA(tb[TCA_CBQ_POLICE-1])); + if (tb[TCA_CBQ_POLICE]) + cbq_set_police(cl, nla_data(tb[TCA_CBQ_POLICE])); #endif - if (tb[TCA_CBQ_FOPT-1]) - cbq_set_fopt(cl, RTA_DATA(tb[TCA_CBQ_FOPT-1])); + if (tb[TCA_CBQ_FOPT]) + cbq_set_fopt(cl, nla_data(tb[TCA_CBQ_FOPT])); sch_tree_unlock(sch); - if (tca[TCA_RATE-1]) + if (tca[TCA_RATE]) gen_new_estimator(&cl->bstats, &cl->rate_est, - &sch->dev->queue_lock, tca[TCA_RATE-1]); + &sch->dev->queue_lock, tca[TCA_RATE]); *arg = (unsigned long)cl; return 0; @@ -2045,7 +2032,7 @@ static void cbq_walk(struct Qdisc *sch, struct qdisc_walker *arg) } } -static struct Qdisc_class_ops cbq_class_ops = { +static const struct Qdisc_class_ops cbq_class_ops = { .graft = cbq_graft, .leaf = cbq_leaf, .qlen_notify = cbq_qlen_notify, @@ -2061,7 +2048,7 @@ static struct Qdisc_class_ops cbq_class_ops = { .dump_stats = cbq_dump_class_stats, }; -static struct Qdisc_ops cbq_qdisc_ops = { +static struct Qdisc_ops cbq_qdisc_ops __read_mostly = { .next = NULL, .cl_ops = &cbq_class_ops, .id = "cbq", diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index 60f89199e3d..0df911fd67b 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -10,28 +10,12 @@ #include <linux/errno.h> #include <linux/skbuff.h> #include <linux/rtnetlink.h> +#include <linux/bitops.h> #include <net/pkt_sched.h> #include <net/dsfield.h> #include <net/inet_ecn.h> #include <asm/byteorder.h> - -#if 0 /* control */ -#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define DPRINTK(format,args...) -#endif - -#if 0 /* data */ -#define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define D2PRINTK(format,args...) -#endif - - -#define PRIV(sch) ((struct dsmark_qdisc_data *) qdisc_priv(sch)) - - /* * classid class marking * ------- ----- ------- @@ -60,17 +44,6 @@ struct dsmark_qdisc_data { int set_tc_index; }; -static inline int dsmark_valid_indices(u16 indices) -{ - while (indices != 1) { - if (indices & 1) - return 0; - indices >>= 1; - } - - return 1; -} - static inline int dsmark_valid_index(struct dsmark_qdisc_data *p, u16 index) { return (index <= p->indices && index > 0); @@ -81,9 +54,9 @@ static inline int dsmark_valid_index(struct dsmark_qdisc_data *p, u16 index) static int dsmark_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, struct Qdisc **old) { - struct dsmark_qdisc_data *p = PRIV(sch); + struct dsmark_qdisc_data *p = qdisc_priv(sch); - DPRINTK("dsmark_graft(sch %p,[qdisc %p],new %p,old %p)\n", + pr_debug("dsmark_graft(sch %p,[qdisc %p],new %p,old %p)\n", sch, p, new, old); if (new == NULL) { @@ -104,13 +77,14 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg, static struct Qdisc *dsmark_leaf(struct Qdisc *sch, unsigned long arg) { - return PRIV(sch)->q; + struct dsmark_qdisc_data *p = qdisc_priv(sch); + return p->q; } static unsigned long dsmark_get(struct Qdisc *sch, u32 classid) { - DPRINTK("dsmark_get(sch %p,[qdisc %p],classid %x)\n", - sch, PRIV(sch), classid); + pr_debug("dsmark_get(sch %p,[qdisc %p],classid %x)\n", + sch, qdisc_priv(sch), classid); return TC_H_MIN(classid) + 1; } @@ -125,44 +99,56 @@ static void dsmark_put(struct Qdisc *sch, unsigned long cl) { } +static const struct nla_policy dsmark_policy[TCA_DSMARK_MAX + 1] = { + [TCA_DSMARK_INDICES] = { .type = NLA_U16 }, + [TCA_DSMARK_DEFAULT_INDEX] = { .type = NLA_U16 }, + [TCA_DSMARK_SET_TC_INDEX] = { .type = NLA_FLAG }, + [TCA_DSMARK_MASK] = { .type = NLA_U8 }, + [TCA_DSMARK_VALUE] = { .type = NLA_U8 }, +}; + static int dsmark_change(struct Qdisc *sch, u32 classid, u32 parent, - struct rtattr **tca, unsigned long *arg) + struct nlattr **tca, unsigned long *arg) { - struct dsmark_qdisc_data *p = PRIV(sch); - struct rtattr *opt = tca[TCA_OPTIONS-1]; - struct rtattr *tb[TCA_DSMARK_MAX]; + struct dsmark_qdisc_data *p = qdisc_priv(sch); + struct nlattr *opt = tca[TCA_OPTIONS]; + struct nlattr *tb[TCA_DSMARK_MAX + 1]; int err = -EINVAL; u8 mask = 0; - DPRINTK("dsmark_change(sch %p,[qdisc %p],classid %x,parent %x)," + pr_debug("dsmark_change(sch %p,[qdisc %p],classid %x,parent %x)," "arg 0x%lx\n", sch, p, classid, parent, *arg); if (!dsmark_valid_index(p, *arg)) { err = -ENOENT; - goto rtattr_failure; + goto errout; } - if (!opt || rtattr_parse_nested(tb, TCA_DSMARK_MAX, opt)) - goto rtattr_failure; + if (!opt) + goto errout; - if (tb[TCA_DSMARK_MASK-1]) - mask = RTA_GET_U8(tb[TCA_DSMARK_MASK-1]); + err = nla_parse_nested(tb, TCA_DSMARK_MAX, opt, dsmark_policy); + if (err < 0) + goto errout; + + if (tb[TCA_DSMARK_MASK]) + mask = nla_get_u8(tb[TCA_DSMARK_MASK]); - if (tb[TCA_DSMARK_VALUE-1]) - p->value[*arg-1] = RTA_GET_U8(tb[TCA_DSMARK_VALUE-1]); + if (tb[TCA_DSMARK_VALUE]) + p->value[*arg-1] = nla_get_u8(tb[TCA_DSMARK_VALUE]); - if (tb[TCA_DSMARK_MASK-1]) + if (tb[TCA_DSMARK_MASK]) p->mask[*arg-1] = mask; err = 0; -rtattr_failure: +errout: return err; } static int dsmark_delete(struct Qdisc *sch, unsigned long arg) { - struct dsmark_qdisc_data *p = PRIV(sch); + struct dsmark_qdisc_data *p = qdisc_priv(sch); if (!dsmark_valid_index(p, arg)) return -EINVAL; @@ -173,12 +159,12 @@ static int dsmark_delete(struct Qdisc *sch, unsigned long arg) return 0; } -static void dsmark_walk(struct Qdisc *sch,struct qdisc_walker *walker) +static void dsmark_walk(struct Qdisc *sch, struct qdisc_walker *walker) { - struct dsmark_qdisc_data *p = PRIV(sch); + struct dsmark_qdisc_data *p = qdisc_priv(sch); int i; - DPRINTK("dsmark_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker); + pr_debug("dsmark_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker); if (walker->stop) return; @@ -197,34 +183,42 @@ ignore: } } -static struct tcf_proto **dsmark_find_tcf(struct Qdisc *sch,unsigned long cl) +static inline struct tcf_proto **dsmark_find_tcf(struct Qdisc *sch, + unsigned long cl) { - return &PRIV(sch)->filter_list; + struct dsmark_qdisc_data *p = qdisc_priv(sch); + return &p->filter_list; } /* --------------------------- Qdisc operations ---------------------------- */ -static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch) +static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch) { - struct dsmark_qdisc_data *p = PRIV(sch); + struct dsmark_qdisc_data *p = qdisc_priv(sch); int err; - D2PRINTK("dsmark_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); + pr_debug("dsmark_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); if (p->set_tc_index) { - /* FIXME: Safe with non-linear skbs? --RR */ switch (skb->protocol) { - case __constant_htons(ETH_P_IP): - skb->tc_index = ipv4_get_dsfield(ip_hdr(skb)) - & ~INET_ECN_MASK; - break; - case __constant_htons(ETH_P_IPV6): - skb->tc_index = ipv6_get_dsfield(ipv6_hdr(skb)) - & ~INET_ECN_MASK; - break; - default: - skb->tc_index = 0; - break; + case __constant_htons(ETH_P_IP): + if (skb_cow_head(skb, sizeof(struct iphdr))) + goto drop; + + skb->tc_index = ipv4_get_dsfield(ip_hdr(skb)) + & ~INET_ECN_MASK; + break; + + case __constant_htons(ETH_P_IPV6): + if (skb_cow_head(skb, sizeof(struct ipv6hdr))) + goto drop; + + skb->tc_index = ipv6_get_dsfield(ipv6_hdr(skb)) + & ~INET_ECN_MASK; + break; + default: + skb->tc_index = 0; + break; } } @@ -234,7 +228,7 @@ static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch) struct tcf_result res; int result = tc_classify(skb, p->filter_list, &res); - D2PRINTK("result %d class 0x%04x\n", result, res.classid); + pr_debug("result %d class 0x%04x\n", result, res.classid); switch (result) { #ifdef CONFIG_NET_CLS_ACT @@ -242,14 +236,14 @@ static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch) case TC_ACT_STOLEN: kfree_skb(skb); return NET_XMIT_SUCCESS; + case TC_ACT_SHOT: - kfree_skb(skb); - sch->qstats.drops++; - return NET_XMIT_BYPASS; + goto drop; #endif case TC_ACT_OK: skb->tc_index = TC_H_MIN(res.classid); break; + default: if (p->default_index != NO_DEFAULT_INDEX) skb->tc_index = p->default_index; @@ -257,7 +251,7 @@ static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch) } } - err = p->q->enqueue(skb,p->q); + err = p->q->enqueue(skb, p->q); if (err != NET_XMIT_SUCCESS) { sch->qstats.drops++; return err; @@ -268,15 +262,20 @@ static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch) sch->q.qlen++; return NET_XMIT_SUCCESS; + +drop: + kfree_skb(skb); + sch->qstats.drops++; + return NET_XMIT_BYPASS; } static struct sk_buff *dsmark_dequeue(struct Qdisc *sch) { - struct dsmark_qdisc_data *p = PRIV(sch); + struct dsmark_qdisc_data *p = qdisc_priv(sch); struct sk_buff *skb; u32 index; - D2PRINTK("dsmark_dequeue(sch %p,[qdisc %p])\n", sch, p); + pr_debug("dsmark_dequeue(sch %p,[qdisc %p])\n", sch, p); skb = p->q->ops->dequeue(p->q); if (skb == NULL) @@ -285,39 +284,39 @@ static struct sk_buff *dsmark_dequeue(struct Qdisc *sch) sch->q.qlen--; index = skb->tc_index & (p->indices - 1); - D2PRINTK("index %d->%d\n", skb->tc_index, index); + pr_debug("index %d->%d\n", skb->tc_index, index); switch (skb->protocol) { - case __constant_htons(ETH_P_IP): - ipv4_change_dsfield(ip_hdr(skb), p->mask[index], - p->value[index]); - break; - case __constant_htons(ETH_P_IPV6): - ipv6_change_dsfield(ipv6_hdr(skb), p->mask[index], - p->value[index]); + case __constant_htons(ETH_P_IP): + ipv4_change_dsfield(ip_hdr(skb), p->mask[index], + p->value[index]); break; - default: - /* - * Only complain if a change was actually attempted. - * This way, we can send non-IP traffic through dsmark - * and don't need yet another qdisc as a bypass. - */ - if (p->mask[index] != 0xff || p->value[index]) - printk(KERN_WARNING "dsmark_dequeue: " - "unsupported protocol %d\n", - ntohs(skb->protocol)); + case __constant_htons(ETH_P_IPV6): + ipv6_change_dsfield(ipv6_hdr(skb), p->mask[index], + p->value[index]); break; + default: + /* + * Only complain if a change was actually attempted. + * This way, we can send non-IP traffic through dsmark + * and don't need yet another qdisc as a bypass. + */ + if (p->mask[index] != 0xff || p->value[index]) + printk(KERN_WARNING + "dsmark_dequeue: unsupported protocol %d\n", + ntohs(skb->protocol)); + break; } return skb; } -static int dsmark_requeue(struct sk_buff *skb,struct Qdisc *sch) +static int dsmark_requeue(struct sk_buff *skb, struct Qdisc *sch) { - struct dsmark_qdisc_data *p = PRIV(sch); + struct dsmark_qdisc_data *p = qdisc_priv(sch); int err; - D2PRINTK("dsmark_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); + pr_debug("dsmark_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); err = p->q->ops->requeue(skb, p->q); if (err != NET_XMIT_SUCCESS) { @@ -333,10 +332,10 @@ static int dsmark_requeue(struct sk_buff *skb,struct Qdisc *sch) static unsigned int dsmark_drop(struct Qdisc *sch) { - struct dsmark_qdisc_data *p = PRIV(sch); + struct dsmark_qdisc_data *p = qdisc_priv(sch); unsigned int len; - DPRINTK("dsmark_reset(sch %p,[qdisc %p])\n", sch, p); + pr_debug("dsmark_reset(sch %p,[qdisc %p])\n", sch, p); if (p->q->ops->drop == NULL) return 0; @@ -348,26 +347,32 @@ static unsigned int dsmark_drop(struct Qdisc *sch) return len; } -static int dsmark_init(struct Qdisc *sch, struct rtattr *opt) +static int dsmark_init(struct Qdisc *sch, struct nlattr *opt) { - struct dsmark_qdisc_data *p = PRIV(sch); - struct rtattr *tb[TCA_DSMARK_MAX]; + struct dsmark_qdisc_data *p = qdisc_priv(sch); + struct nlattr *tb[TCA_DSMARK_MAX + 1]; int err = -EINVAL; u32 default_index = NO_DEFAULT_INDEX; u16 indices; u8 *mask; - DPRINTK("dsmark_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt); + pr_debug("dsmark_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt); - if (!opt || rtattr_parse_nested(tb, TCA_DSMARK_MAX, opt) < 0) + if (!opt) goto errout; - indices = RTA_GET_U16(tb[TCA_DSMARK_INDICES-1]); - if (!indices || !dsmark_valid_indices(indices)) + err = nla_parse_nested(tb, TCA_DSMARK_MAX, opt, dsmark_policy); + if (err < 0) + goto errout; + + err = -EINVAL; + indices = nla_get_u16(tb[TCA_DSMARK_INDICES]); + + if (hweight32(indices) != 1) goto errout; - if (tb[TCA_DSMARK_DEFAULT_INDEX-1]) - default_index = RTA_GET_U16(tb[TCA_DSMARK_DEFAULT_INDEX-1]); + if (tb[TCA_DSMARK_DEFAULT_INDEX]) + default_index = nla_get_u16(tb[TCA_DSMARK_DEFAULT_INDEX]); mask = kmalloc(indices * 2, GFP_KERNEL); if (mask == NULL) { @@ -383,34 +388,33 @@ static int dsmark_init(struct Qdisc *sch, struct rtattr *opt) p->indices = indices; p->default_index = default_index; - p->set_tc_index = RTA_GET_FLAG(tb[TCA_DSMARK_SET_TC_INDEX-1]); + p->set_tc_index = nla_get_flag(tb[TCA_DSMARK_SET_TC_INDEX]); p->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, sch->handle); if (p->q == NULL) p->q = &noop_qdisc; - DPRINTK("dsmark_init: qdisc %p\n", p->q); + pr_debug("dsmark_init: qdisc %p\n", p->q); err = 0; errout: -rtattr_failure: return err; } static void dsmark_reset(struct Qdisc *sch) { - struct dsmark_qdisc_data *p = PRIV(sch); + struct dsmark_qdisc_data *p = qdisc_priv(sch); - DPRINTK("dsmark_reset(sch %p,[qdisc %p])\n", sch, p); + pr_debug("dsmark_reset(sch %p,[qdisc %p])\n", sch, p); qdisc_reset(p->q); sch->q.qlen = 0; } static void dsmark_destroy(struct Qdisc *sch) { - struct dsmark_qdisc_data *p = PRIV(sch); + struct dsmark_qdisc_data *p = qdisc_priv(sch); - DPRINTK("dsmark_destroy(sch %p,[qdisc %p])\n", sch, p); + pr_debug("dsmark_destroy(sch %p,[qdisc %p])\n", sch, p); tcf_destroy_chain(p->filter_list); qdisc_destroy(p->q); @@ -420,10 +424,10 @@ static void dsmark_destroy(struct Qdisc *sch) static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, struct tcmsg *tcm) { - struct dsmark_qdisc_data *p = PRIV(sch); - struct rtattr *opts = NULL; + struct dsmark_qdisc_data *p = qdisc_priv(sch); + struct nlattr *opts = NULL; - DPRINTK("dsmark_dump_class(sch %p,[qdisc %p],class %ld\n", sch, p, cl); + pr_debug("dsmark_dump_class(sch %p,[qdisc %p],class %ld\n", sch, p, cl); if (!dsmark_valid_index(p, cl)) return -EINVAL; @@ -431,37 +435,41 @@ static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl, tcm->tcm_handle = TC_H_MAKE(TC_H_MAJ(sch->handle), cl-1); tcm->tcm_info = p->q->handle; - opts = RTA_NEST(skb, TCA_OPTIONS); - RTA_PUT_U8(skb,TCA_DSMARK_MASK, p->mask[cl-1]); - RTA_PUT_U8(skb,TCA_DSMARK_VALUE, p->value[cl-1]); + opts = nla_nest_start(skb, TCA_OPTIONS); + if (opts == NULL) + goto nla_put_failure; + NLA_PUT_U8(skb, TCA_DSMARK_MASK, p->mask[cl-1]); + NLA_PUT_U8(skb, TCA_DSMARK_VALUE, p->value[cl-1]); - return RTA_NEST_END(skb, opts); + return nla_nest_end(skb, opts); -rtattr_failure: - return RTA_NEST_CANCEL(skb, opts); +nla_put_failure: + return nla_nest_cancel(skb, opts); } static int dsmark_dump(struct Qdisc *sch, struct sk_buff *skb) { - struct dsmark_qdisc_data *p = PRIV(sch); - struct rtattr *opts = NULL; + struct dsmark_qdisc_data *p = qdisc_priv(sch); + struct nlattr *opts = NULL; - opts = RTA_NEST(skb, TCA_OPTIONS); - RTA_PUT_U16(skb, TCA_DSMARK_INDICES, p->indices); + opts = nla_nest_start(skb, TCA_OPTIONS); + if (opts == NULL) + goto nla_put_failure; + NLA_PUT_U16(skb, TCA_DSMARK_INDICES, p->indices); if (p->default_index != NO_DEFAULT_INDEX) - RTA_PUT_U16(skb, TCA_DSMARK_DEFAULT_INDEX, p->default_index); + NLA_PUT_U16(skb, TCA_DSMARK_DEFAULT_INDEX, p->default_index); if (p->set_tc_index) - RTA_PUT_FLAG(skb, TCA_DSMARK_SET_TC_INDEX); + NLA_PUT_FLAG(skb, TCA_DSMARK_SET_TC_INDEX); - return RTA_NEST_END(skb, opts); + return nla_nest_end(skb, opts); -rtattr_failure: - return RTA_NEST_CANCEL(skb, opts); +nla_put_failure: + return nla_nest_cancel(skb, opts); } -static struct Qdisc_class_ops dsmark_class_ops = { +static const struct Qdisc_class_ops dsmark_class_ops = { .graft = dsmark_graft, .leaf = dsmark_leaf, .get = dsmark_get, @@ -475,7 +483,7 @@ static struct Qdisc_class_ops dsmark_class_ops = { .dump = dsmark_dump_class, }; -static struct Qdisc_ops dsmark_qdisc_ops = { +static struct Qdisc_ops dsmark_qdisc_ops __read_mostly = { .next = NULL, .cl_ops = &dsmark_class_ops, .id = "dsmark", diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c index c264308f17c..95ed4822165 100644 --- a/net/sched/sch_fifo.c +++ b/net/sched/sch_fifo.c @@ -43,7 +43,7 @@ static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch) return qdisc_reshape_fail(skb, sch); } -static int fifo_init(struct Qdisc *sch, struct rtattr *opt) +static int fifo_init(struct Qdisc *sch, struct nlattr *opt) { struct fifo_sched_data *q = qdisc_priv(sch); @@ -55,9 +55,9 @@ static int fifo_init(struct Qdisc *sch, struct rtattr *opt) q->limit = limit; } else { - struct tc_fifo_qopt *ctl = RTA_DATA(opt); + struct tc_fifo_qopt *ctl = nla_data(opt); - if (RTA_PAYLOAD(opt) < sizeof(*ctl)) + if (nla_len(opt) < sizeof(*ctl)) return -EINVAL; q->limit = ctl->limit; @@ -71,14 +71,14 @@ static int fifo_dump(struct Qdisc *sch, struct sk_buff *skb) struct fifo_sched_data *q = qdisc_priv(sch); struct tc_fifo_qopt opt = { .limit = q->limit }; - RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); + NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); return skb->len; -rtattr_failure: +nla_put_failure: return -1; } -struct Qdisc_ops pfifo_qdisc_ops = { +struct Qdisc_ops pfifo_qdisc_ops __read_mostly = { .id = "pfifo", .priv_size = sizeof(struct fifo_sched_data), .enqueue = pfifo_enqueue, @@ -91,8 +91,9 @@ struct Qdisc_ops pfifo_qdisc_ops = { .dump = fifo_dump, .owner = THIS_MODULE, }; +EXPORT_SYMBOL(pfifo_qdisc_ops); -struct Qdisc_ops bfifo_qdisc_ops = { +struct Qdisc_ops bfifo_qdisc_ops __read_mostly = { .id = "bfifo", .priv_size = sizeof(struct fifo_sched_data), .enqueue = bfifo_enqueue, @@ -105,6 +106,4 @@ struct Qdisc_ops bfifo_qdisc_ops = { .dump = fifo_dump, .owner = THIS_MODULE, }; - EXPORT_SYMBOL(bfifo_qdisc_ops); -EXPORT_SYMBOL(pfifo_qdisc_ops); diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index e595e6570ce..10b5c0887ff 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -40,16 +40,22 @@ */ void qdisc_lock_tree(struct net_device *dev) + __acquires(dev->queue_lock) + __acquires(dev->ingress_lock) { spin_lock_bh(&dev->queue_lock); spin_lock(&dev->ingress_lock); } +EXPORT_SYMBOL(qdisc_lock_tree); void qdisc_unlock_tree(struct net_device *dev) + __releases(dev->ingress_lock) + __releases(dev->queue_lock) { spin_unlock(&dev->ingress_lock); spin_unlock_bh(&dev->queue_lock); } +EXPORT_SYMBOL(qdisc_unlock_tree); static inline int qdisc_qlen(struct Qdisc *q) { @@ -211,13 +217,6 @@ static void dev_watchdog(unsigned long arg) dev_put(dev); } -static void dev_watchdog_init(struct net_device *dev) -{ - init_timer(&dev->watchdog_timer); - dev->watchdog_timer.data = (unsigned long)dev; - dev->watchdog_timer.function = dev_watchdog; -} - void __netdev_watchdog_up(struct net_device *dev) { if (dev->tx_timeout) { @@ -256,6 +255,7 @@ void netif_carrier_on(struct net_device *dev) __netdev_watchdog_up(dev); } } +EXPORT_SYMBOL(netif_carrier_on); /** * netif_carrier_off - clear carrier @@ -268,6 +268,7 @@ void netif_carrier_off(struct net_device *dev) if (!test_and_set_bit(__LINK_STATE_NOCARRIER, &dev->state)) linkwatch_fire_event(dev); } +EXPORT_SYMBOL(netif_carrier_off); /* "NOOP" scheduler: the best scheduler, recommended for all interfaces under all circumstances. It is difficult to invent anything faster or @@ -294,7 +295,7 @@ static int noop_requeue(struct sk_buff *skb, struct Qdisc* qdisc) return NET_XMIT_CN; } -struct Qdisc_ops noop_qdisc_ops = { +struct Qdisc_ops noop_qdisc_ops __read_mostly = { .id = "noop", .priv_size = 0, .enqueue = noop_enqueue, @@ -310,8 +311,9 @@ struct Qdisc noop_qdisc = { .ops = &noop_qdisc_ops, .list = LIST_HEAD_INIT(noop_qdisc.list), }; +EXPORT_SYMBOL(noop_qdisc); -static struct Qdisc_ops noqueue_qdisc_ops = { +static struct Qdisc_ops noqueue_qdisc_ops __read_mostly = { .id = "noqueue", .priv_size = 0, .enqueue = noop_enqueue, @@ -395,14 +397,14 @@ static int pfifo_fast_dump(struct Qdisc *qdisc, struct sk_buff *skb) struct tc_prio_qopt opt = { .bands = PFIFO_FAST_BANDS }; memcpy(&opt.priomap, prio2band, TC_PRIO_MAX+1); - RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); + NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); return skb->len; -rtattr_failure: +nla_put_failure: return -1; } -static int pfifo_fast_init(struct Qdisc *qdisc, struct rtattr *opt) +static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt) { int prio; struct sk_buff_head *list = qdisc_priv(qdisc); @@ -413,7 +415,7 @@ static int pfifo_fast_init(struct Qdisc *qdisc, struct rtattr *opt) return 0; } -static struct Qdisc_ops pfifo_fast_ops = { +static struct Qdisc_ops pfifo_fast_ops __read_mostly = { .id = "pfifo_fast", .priv_size = PFIFO_FAST_BANDS * sizeof(struct sk_buff_head), .enqueue = pfifo_fast_enqueue, @@ -474,16 +476,18 @@ struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops, errout: return NULL; } +EXPORT_SYMBOL(qdisc_create_dflt); /* Under dev->queue_lock and BH! */ void qdisc_reset(struct Qdisc *qdisc) { - struct Qdisc_ops *ops = qdisc->ops; + const struct Qdisc_ops *ops = qdisc->ops; if (ops->reset) ops->reset(qdisc); } +EXPORT_SYMBOL(qdisc_reset); /* this is the rcu callback function to clean up a qdisc when there * are no further references to it */ @@ -498,7 +502,7 @@ static void __qdisc_destroy(struct rcu_head *head) void qdisc_destroy(struct Qdisc *qdisc) { - struct Qdisc_ops *ops = qdisc->ops; + const struct Qdisc_ops *ops = qdisc->ops; if (qdisc->flags & TCQ_F_BUILTIN || !atomic_dec_and_test(&qdisc->refcnt)) @@ -515,6 +519,7 @@ void qdisc_destroy(struct Qdisc *qdisc) dev_put(qdisc->dev); call_rcu(&qdisc->q_rcu, __qdisc_destroy); } +EXPORT_SYMBOL(qdisc_destroy); void dev_activate(struct net_device *dev) { @@ -608,7 +613,7 @@ void dev_init_scheduler(struct net_device *dev) INIT_LIST_HEAD(&dev->qdisc_list); qdisc_unlock_tree(dev); - dev_watchdog_init(dev); + setup_timer(&dev->watchdog_timer, dev_watchdog, (unsigned long)dev); } void dev_shutdown(struct net_device *dev) @@ -629,12 +634,3 @@ void dev_shutdown(struct net_device *dev) BUG_TRAP(!timer_pending(&dev->watchdog_timer)); qdisc_unlock_tree(dev); } - -EXPORT_SYMBOL(netif_carrier_on); -EXPORT_SYMBOL(netif_carrier_off); -EXPORT_SYMBOL(noop_qdisc); -EXPORT_SYMBOL(qdisc_create_dflt); -EXPORT_SYMBOL(qdisc_destroy); -EXPORT_SYMBOL(qdisc_reset); -EXPORT_SYMBOL(qdisc_lock_tree); -EXPORT_SYMBOL(qdisc_unlock_tree); diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index 3cc6dda02e2..3a9d226ff1e 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c @@ -350,16 +350,16 @@ static inline void gred_destroy_vq(struct gred_sched_data *q) kfree(q); } -static inline int gred_change_table_def(struct Qdisc *sch, struct rtattr *dps) +static inline int gred_change_table_def(struct Qdisc *sch, struct nlattr *dps) { struct gred_sched *table = qdisc_priv(sch); struct tc_gred_sopt *sopt; int i; - if (dps == NULL || RTA_PAYLOAD(dps) < sizeof(*sopt)) + if (dps == NULL) return -EINVAL; - sopt = RTA_DATA(dps); + sopt = nla_data(dps); if (sopt->DPs > MAX_DPs || sopt->DPs == 0 || sopt->def_DP >= sopt->DPs) return -EINVAL; @@ -425,28 +425,37 @@ static inline int gred_change_vq(struct Qdisc *sch, int dp, return 0; } -static int gred_change(struct Qdisc *sch, struct rtattr *opt) +static const struct nla_policy gred_policy[TCA_GRED_MAX + 1] = { + [TCA_GRED_PARMS] = { .len = sizeof(struct tc_gred_qopt) }, + [TCA_GRED_STAB] = { .len = 256 }, + [TCA_GRED_DPS] = { .len = sizeof(struct tc_gred_sopt) }, +}; + +static int gred_change(struct Qdisc *sch, struct nlattr *opt) { struct gred_sched *table = qdisc_priv(sch); struct tc_gred_qopt *ctl; - struct rtattr *tb[TCA_GRED_MAX]; - int err = -EINVAL, prio = GRED_DEF_PRIO; + struct nlattr *tb[TCA_GRED_MAX + 1]; + int err, prio = GRED_DEF_PRIO; u8 *stab; - if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_MAX, opt)) + if (opt == NULL) return -EINVAL; - if (tb[TCA_GRED_PARMS-1] == NULL && tb[TCA_GRED_STAB-1] == NULL) + err = nla_parse_nested(tb, TCA_GRED_MAX, opt, gred_policy); + if (err < 0) + return err; + + if (tb[TCA_GRED_PARMS] == NULL && tb[TCA_GRED_STAB] == NULL) return gred_change_table_def(sch, opt); - if (tb[TCA_GRED_PARMS-1] == NULL || - RTA_PAYLOAD(tb[TCA_GRED_PARMS-1]) < sizeof(*ctl) || - tb[TCA_GRED_STAB-1] == NULL || - RTA_PAYLOAD(tb[TCA_GRED_STAB-1]) < 256) + if (tb[TCA_GRED_PARMS] == NULL || + tb[TCA_GRED_STAB] == NULL) return -EINVAL; - ctl = RTA_DATA(tb[TCA_GRED_PARMS-1]); - stab = RTA_DATA(tb[TCA_GRED_STAB-1]); + err = -EINVAL; + ctl = nla_data(tb[TCA_GRED_PARMS]); + stab = nla_data(tb[TCA_GRED_STAB]); if (ctl->DP >= table->DPs) goto errout; @@ -486,23 +495,28 @@ errout: return err; } -static int gred_init(struct Qdisc *sch, struct rtattr *opt) +static int gred_init(struct Qdisc *sch, struct nlattr *opt) { - struct rtattr *tb[TCA_GRED_MAX]; + struct nlattr *tb[TCA_GRED_MAX + 1]; + int err; - if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_MAX, opt)) + if (opt == NULL) return -EINVAL; - if (tb[TCA_GRED_PARMS-1] || tb[TCA_GRED_STAB-1]) + err = nla_parse_nested(tb, TCA_GRED_MAX, opt, gred_policy); + if (err < 0) + return err; + + if (tb[TCA_GRED_PARMS] || tb[TCA_GRED_STAB]) return -EINVAL; - return gred_change_table_def(sch, tb[TCA_GRED_DPS-1]); + return gred_change_table_def(sch, tb[TCA_GRED_DPS]); } static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) { struct gred_sched *table = qdisc_priv(sch); - struct rtattr *parms, *opts = NULL; + struct nlattr *parms, *opts = NULL; int i; struct tc_gred_sopt sopt = { .DPs = table->DPs, @@ -511,9 +525,13 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) .flags = table->red_flags, }; - opts = RTA_NEST(skb, TCA_OPTIONS); - RTA_PUT(skb, TCA_GRED_DPS, sizeof(sopt), &sopt); - parms = RTA_NEST(skb, TCA_GRED_PARMS); + opts = nla_nest_start(skb, TCA_OPTIONS); + if (opts == NULL) + goto nla_put_failure; + NLA_PUT(skb, TCA_GRED_DPS, sizeof(sopt), &sopt); + parms = nla_nest_start(skb, TCA_GRED_PARMS); + if (parms == NULL) + goto nla_put_failure; for (i = 0; i < MAX_DPs; i++) { struct gred_sched_data *q = table->tab[i]; @@ -555,15 +573,16 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) opt.qave = red_calc_qavg(&q->parms, q->parms.qavg); append_opt: - RTA_APPEND(skb, sizeof(opt), &opt); + if (nla_append(skb, sizeof(opt), &opt) < 0) + goto nla_put_failure; } - RTA_NEST_END(skb, parms); + nla_nest_end(skb, parms); - return RTA_NEST_END(skb, opts); + return nla_nest_end(skb, opts); -rtattr_failure: - return RTA_NEST_CANCEL(skb, opts); +nla_put_failure: + return nla_nest_cancel(skb, opts); } static void gred_destroy(struct Qdisc *sch) @@ -577,7 +596,7 @@ static void gred_destroy(struct Qdisc *sch) } } -static struct Qdisc_ops gred_qdisc_ops = { +static struct Qdisc_ops gred_qdisc_ops __read_mostly = { .id = "gred", .priv_size = sizeof(struct gred_sched), .enqueue = gred_enqueue, diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index a6ad491e434..87293d0db1d 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -986,41 +986,46 @@ hfsc_change_usc(struct hfsc_class *cl, struct tc_service_curve *usc, cl->cl_flags |= HFSC_USC; } +static const struct nla_policy hfsc_policy[TCA_HFSC_MAX + 1] = { + [TCA_HFSC_RSC] = { .len = sizeof(struct tc_service_curve) }, + [TCA_HFSC_FSC] = { .len = sizeof(struct tc_service_curve) }, + [TCA_HFSC_USC] = { .len = sizeof(struct tc_service_curve) }, +}; + static int hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, - struct rtattr **tca, unsigned long *arg) + struct nlattr **tca, unsigned long *arg) { struct hfsc_sched *q = qdisc_priv(sch); struct hfsc_class *cl = (struct hfsc_class *)*arg; struct hfsc_class *parent = NULL; - struct rtattr *opt = tca[TCA_OPTIONS-1]; - struct rtattr *tb[TCA_HFSC_MAX]; + struct nlattr *opt = tca[TCA_OPTIONS]; + struct nlattr *tb[TCA_HFSC_MAX + 1]; struct tc_service_curve *rsc = NULL, *fsc = NULL, *usc = NULL; u64 cur_time; + int err; - if (opt == NULL || rtattr_parse_nested(tb, TCA_HFSC_MAX, opt)) + if (opt == NULL) return -EINVAL; - if (tb[TCA_HFSC_RSC-1]) { - if (RTA_PAYLOAD(tb[TCA_HFSC_RSC-1]) < sizeof(*rsc)) - return -EINVAL; - rsc = RTA_DATA(tb[TCA_HFSC_RSC-1]); + err = nla_parse_nested(tb, TCA_HFSC_MAX, opt, hfsc_policy); + if (err < 0) + return err; + + if (tb[TCA_HFSC_RSC]) { + rsc = nla_data(tb[TCA_HFSC_RSC]); if (rsc->m1 == 0 && rsc->m2 == 0) rsc = NULL; } - if (tb[TCA_HFSC_FSC-1]) { - if (RTA_PAYLOAD(tb[TCA_HFSC_FSC-1]) < sizeof(*fsc)) - return -EINVAL; - fsc = RTA_DATA(tb[TCA_HFSC_FSC-1]); + if (tb[TCA_HFSC_FSC]) { + fsc = nla_data(tb[TCA_HFSC_FSC]); if (fsc->m1 == 0 && fsc->m2 == 0) fsc = NULL; } - if (tb[TCA_HFSC_USC-1]) { - if (RTA_PAYLOAD(tb[TCA_HFSC_USC-1]) < sizeof(*usc)) - return -EINVAL; - usc = RTA_DATA(tb[TCA_HFSC_USC-1]); + if (tb[TCA_HFSC_USC]) { + usc = nla_data(tb[TCA_HFSC_USC]); if (usc->m1 == 0 && usc->m2 == 0) usc = NULL; } @@ -1050,10 +1055,10 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, } sch_tree_unlock(sch); - if (tca[TCA_RATE-1]) + if (tca[TCA_RATE]) gen_replace_estimator(&cl->bstats, &cl->rate_est, &sch->dev->queue_lock, - tca[TCA_RATE-1]); + tca[TCA_RATE]); return 0; } @@ -1106,9 +1111,9 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, cl->cl_pcvtoff = parent->cl_cvtoff; sch_tree_unlock(sch); - if (tca[TCA_RATE-1]) + if (tca[TCA_RATE]) gen_new_estimator(&cl->bstats, &cl->rate_est, - &sch->dev->queue_lock, tca[TCA_RATE-1]); + &sch->dev->queue_lock, tca[TCA_RATE]); *arg = (unsigned long)cl; return 0; } @@ -1304,11 +1309,11 @@ hfsc_dump_sc(struct sk_buff *skb, int attr, struct internal_sc *sc) tsc.m1 = sm2m(sc->sm1); tsc.d = dx2d(sc->dx); tsc.m2 = sm2m(sc->sm2); - RTA_PUT(skb, attr, sizeof(tsc), &tsc); + NLA_PUT(skb, attr, sizeof(tsc), &tsc); return skb->len; - rtattr_failure: + nla_put_failure: return -1; } @@ -1317,19 +1322,19 @@ hfsc_dump_curves(struct sk_buff *skb, struct hfsc_class *cl) { if ((cl->cl_flags & HFSC_RSC) && (hfsc_dump_sc(skb, TCA_HFSC_RSC, &cl->cl_rsc) < 0)) - goto rtattr_failure; + goto nla_put_failure; if ((cl->cl_flags & HFSC_FSC) && (hfsc_dump_sc(skb, TCA_HFSC_FSC, &cl->cl_fsc) < 0)) - goto rtattr_failure; + goto nla_put_failure; if ((cl->cl_flags & HFSC_USC) && (hfsc_dump_sc(skb, TCA_HFSC_USC, &cl->cl_usc) < 0)) - goto rtattr_failure; + goto nla_put_failure; return skb->len; - rtattr_failure: + nla_put_failure: return -1; } @@ -1338,22 +1343,23 @@ hfsc_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb, struct tcmsg *tcm) { struct hfsc_class *cl = (struct hfsc_class *)arg; - unsigned char *b = skb_tail_pointer(skb); - struct rtattr *rta = (struct rtattr *)b; + struct nlattr *nest; tcm->tcm_parent = cl->cl_parent ? cl->cl_parent->classid : TC_H_ROOT; tcm->tcm_handle = cl->classid; if (cl->level == 0) tcm->tcm_info = cl->qdisc->handle; - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; if (hfsc_dump_curves(skb, cl) < 0) - goto rtattr_failure; - rta->rta_len = skb_tail_pointer(skb) - b; + goto nla_put_failure; + nla_nest_end(skb, nest); return skb->len; - rtattr_failure: - nlmsg_trim(skb, b); + nla_put_failure: + nla_nest_cancel(skb, nest); return -1; } @@ -1423,15 +1429,15 @@ hfsc_schedule_watchdog(struct Qdisc *sch) } static int -hfsc_init_qdisc(struct Qdisc *sch, struct rtattr *opt) +hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt) { struct hfsc_sched *q = qdisc_priv(sch); struct tc_hfsc_qopt *qopt; unsigned int i; - if (opt == NULL || RTA_PAYLOAD(opt) < sizeof(*qopt)) + if (opt == NULL || nla_len(opt) < sizeof(*qopt)) return -EINVAL; - qopt = RTA_DATA(opt); + qopt = nla_data(opt); q->defcls = qopt->defcls; for (i = 0; i < HFSC_HSIZE; i++) @@ -1459,14 +1465,14 @@ hfsc_init_qdisc(struct Qdisc *sch, struct rtattr *opt) } static int -hfsc_change_qdisc(struct Qdisc *sch, struct rtattr *opt) +hfsc_change_qdisc(struct Qdisc *sch, struct nlattr *opt) { struct hfsc_sched *q = qdisc_priv(sch); struct tc_hfsc_qopt *qopt; - if (opt == NULL || RTA_PAYLOAD(opt) < sizeof(*qopt)) + if (opt == NULL || nla_len(opt) < sizeof(*qopt)) return -EINVAL; - qopt = RTA_DATA(opt); + qopt = nla_data(opt); sch_tree_lock(sch); q->defcls = qopt->defcls; @@ -1550,10 +1556,10 @@ hfsc_dump_qdisc(struct Qdisc *sch, struct sk_buff *skb) struct tc_hfsc_qopt qopt; qopt.defcls = q->defcls; - RTA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt); + NLA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt); return skb->len; - rtattr_failure: + nla_put_failure: nlmsg_trim(skb, b); return -1; } @@ -1698,7 +1704,7 @@ hfsc_drop(struct Qdisc *sch) return 0; } -static struct Qdisc_class_ops hfsc_class_ops = { +static const struct Qdisc_class_ops hfsc_class_ops = { .change = hfsc_change_class, .delete = hfsc_delete_class, .graft = hfsc_graft_class, @@ -1714,7 +1720,7 @@ static struct Qdisc_class_ops hfsc_class_ops = { .walk = hfsc_walk }; -static struct Qdisc_ops hfsc_qdisc_ops = { +static struct Qdisc_ops hfsc_qdisc_ops __read_mostly = { .id = "hfsc", .init = hfsc_init_qdisc, .change = hfsc_change_qdisc, diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 5e608a64935..e1a579efc21 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -214,10 +214,6 @@ static inline struct htb_class *htb_find(u32 handle, struct Qdisc *sch) * then finish and return direct queue. */ #define HTB_DIRECT (struct htb_class*)-1 -static inline u32 htb_classid(struct htb_class *cl) -{ - return (cl && cl != HTB_DIRECT) ? cl->classid : TC_H_UNSPEC; -} static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) @@ -996,19 +992,33 @@ static void htb_reset(struct Qdisc *sch) INIT_LIST_HEAD(q->drops + i); } -static int htb_init(struct Qdisc *sch, struct rtattr *opt) +static const struct nla_policy htb_policy[TCA_HTB_MAX + 1] = { + [TCA_HTB_PARMS] = { .len = sizeof(struct tc_htb_opt) }, + [TCA_HTB_INIT] = { .len = sizeof(struct tc_htb_glob) }, + [TCA_HTB_CTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE }, + [TCA_HTB_RTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE }, +}; + +static int htb_init(struct Qdisc *sch, struct nlattr *opt) { struct htb_sched *q = qdisc_priv(sch); - struct rtattr *tb[TCA_HTB_INIT]; + struct nlattr *tb[TCA_HTB_INIT + 1]; struct tc_htb_glob *gopt; + int err; int i; - if (!opt || rtattr_parse_nested(tb, TCA_HTB_INIT, opt) || - tb[TCA_HTB_INIT - 1] == NULL || - RTA_PAYLOAD(tb[TCA_HTB_INIT - 1]) < sizeof(*gopt)) { + + if (!opt) + return -EINVAL; + + err = nla_parse_nested(tb, TCA_HTB_INIT, opt, htb_policy); + if (err < 0) + return err; + + if (tb[TCA_HTB_INIT] == NULL) { printk(KERN_ERR "HTB: hey probably you have bad tc tool ?\n"); return -EINVAL; } - gopt = RTA_DATA(tb[TCA_HTB_INIT - 1]); + gopt = nla_data(tb[TCA_HTB_INIT]); if (gopt->version != HTB_VER >> 16) { printk(KERN_ERR "HTB: need tc/htb version %d (minor is %d), you have %d\n", @@ -1039,25 +1049,29 @@ static int htb_init(struct Qdisc *sch, struct rtattr *opt) static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) { struct htb_sched *q = qdisc_priv(sch); - unsigned char *b = skb_tail_pointer(skb); - struct rtattr *rta; + struct nlattr *nest; struct tc_htb_glob gopt; + spin_lock_bh(&sch->dev->queue_lock); - gopt.direct_pkts = q->direct_pkts; + gopt.direct_pkts = q->direct_pkts; gopt.version = HTB_VER; gopt.rate2quantum = q->rate2quantum; gopt.defcls = q->defcls; gopt.debug = 0; - rta = (struct rtattr *)b; - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); - RTA_PUT(skb, TCA_HTB_INIT, sizeof(gopt), &gopt); - rta->rta_len = skb_tail_pointer(skb) - b; + + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; + NLA_PUT(skb, TCA_HTB_INIT, sizeof(gopt), &gopt); + nla_nest_end(skb, nest); + spin_unlock_bh(&sch->dev->queue_lock); return skb->len; -rtattr_failure: + +nla_put_failure: spin_unlock_bh(&sch->dev->queue_lock); - nlmsg_trim(skb, skb_tail_pointer(skb)); + nla_nest_cancel(skb, nest); return -1; } @@ -1065,8 +1079,7 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb, struct tcmsg *tcm) { struct htb_class *cl = (struct htb_class *)arg; - unsigned char *b = skb_tail_pointer(skb); - struct rtattr *rta; + struct nlattr *nest; struct tc_htb_opt opt; spin_lock_bh(&sch->dev->queue_lock); @@ -1075,8 +1088,9 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, if (!cl->level && cl->un.leaf.q) tcm->tcm_info = cl->un.leaf.q->handle; - rta = (struct rtattr *)b; - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; memset(&opt, 0, sizeof(opt)); @@ -1087,13 +1101,15 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, opt.quantum = cl->un.leaf.quantum; opt.prio = cl->un.leaf.prio; opt.level = cl->level; - RTA_PUT(skb, TCA_HTB_PARMS, sizeof(opt), &opt); - rta->rta_len = skb_tail_pointer(skb) - b; + NLA_PUT(skb, TCA_HTB_PARMS, sizeof(opt), &opt); + + nla_nest_end(skb, nest); spin_unlock_bh(&sch->dev->queue_lock); return skb->len; -rtattr_failure: + +nla_put_failure: spin_unlock_bh(&sch->dev->queue_lock); - nlmsg_trim(skb, b); + nla_nest_cancel(skb, nest); return -1; } @@ -1294,29 +1310,35 @@ static void htb_put(struct Qdisc *sch, unsigned long arg) } static int htb_change_class(struct Qdisc *sch, u32 classid, - u32 parentid, struct rtattr **tca, + u32 parentid, struct nlattr **tca, unsigned long *arg) { int err = -EINVAL; struct htb_sched *q = qdisc_priv(sch); struct htb_class *cl = (struct htb_class *)*arg, *parent; - struct rtattr *opt = tca[TCA_OPTIONS - 1]; + struct nlattr *opt = tca[TCA_OPTIONS]; struct qdisc_rate_table *rtab = NULL, *ctab = NULL; - struct rtattr *tb[TCA_HTB_RTAB]; + struct nlattr *tb[TCA_HTB_RTAB + 1]; struct tc_htb_opt *hopt; /* extract all subattrs from opt attr */ - if (!opt || rtattr_parse_nested(tb, TCA_HTB_RTAB, opt) || - tb[TCA_HTB_PARMS - 1] == NULL || - RTA_PAYLOAD(tb[TCA_HTB_PARMS - 1]) < sizeof(*hopt)) + if (!opt) + goto failure; + + err = nla_parse_nested(tb, TCA_HTB_RTAB, opt, htb_policy); + if (err < 0) + goto failure; + + err = -EINVAL; + if (tb[TCA_HTB_PARMS] == NULL) goto failure; parent = parentid == TC_H_ROOT ? NULL : htb_find(parentid, sch); - hopt = RTA_DATA(tb[TCA_HTB_PARMS - 1]); + hopt = nla_data(tb[TCA_HTB_PARMS]); - rtab = qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB - 1]); - ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB - 1]); + rtab = qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB]); + ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB]); if (!rtab || !ctab) goto failure; @@ -1324,12 +1346,12 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, struct Qdisc *new_q; int prio; struct { - struct rtattr rta; + struct nlattr nla; struct gnet_estimator opt; } est = { - .rta = { - .rta_len = RTA_LENGTH(sizeof(est.opt)), - .rta_type = TCA_RATE, + .nla = { + .nla_len = nla_attr_size(sizeof(est.opt)), + .nla_type = TCA_RATE, }, .opt = { /* 4s interval, 16s averaging constant */ @@ -1354,7 +1376,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, gen_new_estimator(&cl->bstats, &cl->rate_est, &sch->dev->queue_lock, - tca[TCA_RATE-1] ? : &est.rta); + tca[TCA_RATE] ? : &est.nla); cl->refcnt = 1; INIT_LIST_HEAD(&cl->sibling); INIT_HLIST_NODE(&cl->hlist); @@ -1407,10 +1429,10 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, list_add_tail(&cl->sibling, parent ? &parent->children : &q->root); } else { - if (tca[TCA_RATE-1]) + if (tca[TCA_RATE]) gen_replace_estimator(&cl->bstats, &cl->rate_est, &sch->dev->queue_lock, - tca[TCA_RATE-1]); + tca[TCA_RATE]); sch_tree_lock(sch); } @@ -1529,7 +1551,7 @@ static void htb_walk(struct Qdisc *sch, struct qdisc_walker *arg) } } -static struct Qdisc_class_ops htb_class_ops = { +static const struct Qdisc_class_ops htb_class_ops = { .graft = htb_graft, .leaf = htb_leaf, .qlen_notify = htb_qlen_notify, @@ -1545,7 +1567,7 @@ static struct Qdisc_class_ops htb_class_ops = { .dump_stats = htb_dump_class_stats, }; -static struct Qdisc_ops htb_qdisc_ops = { +static struct Qdisc_ops htb_qdisc_ops __read_mostly = { .next = NULL, .cl_ops = &htb_class_ops, .id = "htb", diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c index 3f8335e6ea2..3f72d528273 100644 --- a/net/sched/sch_ingress.c +++ b/net/sched/sch_ingress.c @@ -19,127 +19,71 @@ #include <net/pkt_sched.h> -#undef DEBUG_INGRESS - -#ifdef DEBUG_INGRESS /* control */ -#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define DPRINTK(format,args...) -#endif - -#if 0 /* data */ -#define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define D2PRINTK(format,args...) -#endif - - -#define PRIV(sch) qdisc_priv(sch) - - -/* Thanks to Doron Oz for this hack -*/ -#ifndef CONFIG_NET_CLS_ACT -#ifdef CONFIG_NETFILTER +/* Thanks to Doron Oz for this hack */ +#if !defined(CONFIG_NET_CLS_ACT) && defined(CONFIG_NETFILTER) static int nf_registered; #endif -#endif struct ingress_qdisc_data { - struct Qdisc *q; struct tcf_proto *filter_list; }; - /* ------------------------- Class/flow operations ------------------------- */ - -static int ingress_graft(struct Qdisc *sch,unsigned long arg, - struct Qdisc *new,struct Qdisc **old) +static int ingress_graft(struct Qdisc *sch, unsigned long arg, + struct Qdisc *new, struct Qdisc **old) { -#ifdef DEBUG_INGRESS - struct ingress_qdisc_data *p = PRIV(sch); -#endif - - DPRINTK("ingress_graft(sch %p,[qdisc %p],new %p,old %p)\n", - sch, p, new, old); - DPRINTK("\n ingress_graft: You cannot add qdiscs to classes"); - return 1; + return -EOPNOTSUPP; } - static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg) { return NULL; } - -static unsigned long ingress_get(struct Qdisc *sch,u32 classid) +static unsigned long ingress_get(struct Qdisc *sch, u32 classid) { -#ifdef DEBUG_INGRESS - struct ingress_qdisc_data *p = PRIV(sch); -#endif - DPRINTK("ingress_get(sch %p,[qdisc %p],classid %x)\n", sch, p, classid); return TC_H_MIN(classid) + 1; } - static unsigned long ingress_bind_filter(struct Qdisc *sch, - unsigned long parent, u32 classid) + unsigned long parent, u32 classid) { return ingress_get(sch, classid); } - static void ingress_put(struct Qdisc *sch, unsigned long cl) { } - static int ingress_change(struct Qdisc *sch, u32 classid, u32 parent, - struct rtattr **tca, unsigned long *arg) + struct nlattr **tca, unsigned long *arg) { -#ifdef DEBUG_INGRESS - struct ingress_qdisc_data *p = PRIV(sch); -#endif - DPRINTK("ingress_change(sch %p,[qdisc %p],classid %x,parent %x)," - "arg 0x%lx\n", sch, p, classid, parent, *arg); - DPRINTK("No effect. sch_ingress doesn't maintain classes at the moment"); return 0; } - - -static void ingress_walk(struct Qdisc *sch,struct qdisc_walker *walker) +static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker) { -#ifdef DEBUG_INGRESS - struct ingress_qdisc_data *p = PRIV(sch); -#endif - DPRINTK("ingress_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker); - DPRINTK("No effect. sch_ingress doesn't maintain classes at the moment"); + return; } - -static struct tcf_proto **ingress_find_tcf(struct Qdisc *sch,unsigned long cl) +static struct tcf_proto **ingress_find_tcf(struct Qdisc *sch, unsigned long cl) { - struct ingress_qdisc_data *p = PRIV(sch); + struct ingress_qdisc_data *p = qdisc_priv(sch); return &p->filter_list; } - /* --------------------------- Qdisc operations ---------------------------- */ - -static int ingress_enqueue(struct sk_buff *skb,struct Qdisc *sch) +static int ingress_enqueue(struct sk_buff *skb, struct Qdisc *sch) { - struct ingress_qdisc_data *p = PRIV(sch); + struct ingress_qdisc_data *p = qdisc_priv(sch); struct tcf_result res; int result; - D2PRINTK("ingress_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); result = tc_classify(skb, p->filter_list, &res); - D2PRINTK("result %d class 0x%04x\n", result, res.classid); + /* * Unlike normal "enqueue" functions, ingress_enqueue returns a * firewall FW_* code. @@ -148,23 +92,22 @@ static int ingress_enqueue(struct sk_buff *skb,struct Qdisc *sch) sch->bstats.packets++; sch->bstats.bytes += skb->len; switch (result) { - case TC_ACT_SHOT: - result = TC_ACT_SHOT; - sch->qstats.drops++; - break; - case TC_ACT_STOLEN: - case TC_ACT_QUEUED: - result = TC_ACT_STOLEN; - break; - case TC_ACT_RECLASSIFY: - case TC_ACT_OK: - skb->tc_index = TC_H_MIN(res.classid); - default: - result = TC_ACT_OK; - break; + case TC_ACT_SHOT: + result = TC_ACT_SHOT; + sch->qstats.drops++; + break; + case TC_ACT_STOLEN: + case TC_ACT_QUEUED: + result = TC_ACT_STOLEN; + break; + case TC_ACT_RECLASSIFY: + case TC_ACT_OK: + skb->tc_index = TC_H_MIN(res.classid); + default: + result = TC_ACT_OK; + break; } #else - D2PRINTK("Overriding result to ACCEPT\n"); result = NF_ACCEPT; sch->bstats.packets++; sch->bstats.bytes += skb->len; @@ -173,39 +116,8 @@ static int ingress_enqueue(struct sk_buff *skb,struct Qdisc *sch) return result; } - -static struct sk_buff *ingress_dequeue(struct Qdisc *sch) -{ -/* - struct ingress_qdisc_data *p = PRIV(sch); - D2PRINTK("ingress_dequeue(sch %p,[qdisc %p])\n",sch,PRIV(p)); -*/ - return NULL; -} - - -static int ingress_requeue(struct sk_buff *skb,struct Qdisc *sch) -{ -/* - struct ingress_qdisc_data *p = PRIV(sch); - D2PRINTK("ingress_requeue(skb %p,sch %p,[qdisc %p])\n",skb,sch,PRIV(p)); -*/ - return 0; -} - -static unsigned int ingress_drop(struct Qdisc *sch) -{ -#ifdef DEBUG_INGRESS - struct ingress_qdisc_data *p = PRIV(sch); -#endif - DPRINTK("ingress_drop(sch %p,[qdisc %p])\n", sch, p); - return 0; -} - -#ifndef CONFIG_NET_CLS_ACT -#ifdef CONFIG_NETFILTER -static unsigned int -ing_hook(unsigned int hook, struct sk_buff *skb, +#if !defined(CONFIG_NET_CLS_ACT) && defined(CONFIG_NETFILTER) +static unsigned int ing_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *indev, const struct net_device *outdev, int (*okfn)(struct sk_buff *)) @@ -213,12 +125,7 @@ ing_hook(unsigned int hook, struct sk_buff *skb, struct Qdisc *q; struct net_device *dev = skb->dev; - int fwres=NF_ACCEPT; - - DPRINTK("ing_hook: skb %s dev=%s len=%u\n", - skb->sk ? "(owned)" : "(unowned)", - skb->dev ? skb->dev->name : "(no dev)", - skb->len); + int fwres = NF_ACCEPT; if (dev->qdisc_ingress) { spin_lock(&dev->ingress_lock); @@ -231,168 +138,101 @@ ing_hook(unsigned int hook, struct sk_buff *skb, } /* after ipt_filter */ -static struct nf_hook_ops ing_ops = { - .hook = ing_hook, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_PRE_ROUTING, - .priority = NF_IP_PRI_FILTER + 1, -}; - -static struct nf_hook_ops ing6_ops = { - .hook = ing_hook, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_PRE_ROUTING, - .priority = NF_IP6_PRI_FILTER + 1, +static struct nf_hook_ops ing_ops[] __read_mostly = { + { + .hook = ing_hook, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_INET_PRE_ROUTING, + .priority = NF_IP_PRI_FILTER + 1, + }, + { + .hook = ing_hook, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_INET_PRE_ROUTING, + .priority = NF_IP6_PRI_FILTER + 1, + }, }; - -#endif #endif -static int ingress_init(struct Qdisc *sch,struct rtattr *opt) +static int ingress_init(struct Qdisc *sch, struct nlattr *opt) { - struct ingress_qdisc_data *p = PRIV(sch); - -/* Make sure either netfilter or preferably CLS_ACT is -* compiled in */ -#ifndef CONFIG_NET_CLS_ACT -#ifndef CONFIG_NETFILTER - printk("You MUST compile classifier actions into the kernel\n"); - return -EINVAL; -#else +#if !defined(CONFIG_NET_CLS_ACT) && defined(CONFIG_NETFILTER) printk("Ingress scheduler: Classifier actions prefered over netfilter\n"); -#endif -#endif -#ifndef CONFIG_NET_CLS_ACT -#ifdef CONFIG_NETFILTER if (!nf_registered) { - if (nf_register_hook(&ing_ops) < 0) { + if (nf_register_hooks(ing_ops, ARRAY_SIZE(ing_ops)) < 0) { printk("ingress qdisc registration error \n"); return -EINVAL; } nf_registered++; - - if (nf_register_hook(&ing6_ops) < 0) { - printk("IPv6 ingress qdisc registration error, " \ - "disabling IPv6 support.\n"); - } else - nf_registered++; } #endif -#endif - - DPRINTK("ingress_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt); - p->q = &noop_qdisc; return 0; } - -static void ingress_reset(struct Qdisc *sch) -{ - struct ingress_qdisc_data *p = PRIV(sch); - - DPRINTK("ingress_reset(sch %p,[qdisc %p])\n", sch, p); - -/* -#if 0 -*/ -/* for future use */ - qdisc_reset(p->q); -/* -#endif -*/ -} - -/* ------------------------------------------------------------- */ - - /* ------------------------------------------------------------- */ static void ingress_destroy(struct Qdisc *sch) { - struct ingress_qdisc_data *p = PRIV(sch); + struct ingress_qdisc_data *p = qdisc_priv(sch); - DPRINTK("ingress_destroy(sch %p,[qdisc %p])\n", sch, p); tcf_destroy_chain(p->filter_list); -#if 0 -/* for future use */ - qdisc_destroy(p->q); -#endif } - static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb) { - unsigned char *b = skb_tail_pointer(skb); - struct rtattr *rta; + struct nlattr *nest; - rta = (struct rtattr *) b; - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); - rta->rta_len = skb_tail_pointer(skb) - b; + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; + nla_nest_end(skb, nest); return skb->len; -rtattr_failure: - nlmsg_trim(skb, b); +nla_put_failure: + nla_nest_cancel(skb, nest); return -1; } -static struct Qdisc_class_ops ingress_class_ops = { +static const struct Qdisc_class_ops ingress_class_ops = { .graft = ingress_graft, .leaf = ingress_leaf, .get = ingress_get, .put = ingress_put, .change = ingress_change, - .delete = NULL, .walk = ingress_walk, .tcf_chain = ingress_find_tcf, .bind_tcf = ingress_bind_filter, .unbind_tcf = ingress_put, - .dump = NULL, }; -static struct Qdisc_ops ingress_qdisc_ops = { - .next = NULL, +static struct Qdisc_ops ingress_qdisc_ops __read_mostly = { .cl_ops = &ingress_class_ops, .id = "ingress", .priv_size = sizeof(struct ingress_qdisc_data), .enqueue = ingress_enqueue, - .dequeue = ingress_dequeue, - .requeue = ingress_requeue, - .drop = ingress_drop, .init = ingress_init, - .reset = ingress_reset, .destroy = ingress_destroy, - .change = NULL, .dump = ingress_dump, .owner = THIS_MODULE, }; static int __init ingress_module_init(void) { - int ret = 0; - - if ((ret = register_qdisc(&ingress_qdisc_ops)) < 0) { - printk("Unable to register Ingress qdisc\n"); - return ret; - } - - return ret; + return register_qdisc(&ingress_qdisc_ops); } + static void __exit ingress_module_exit(void) { unregister_qdisc(&ingress_qdisc_ops); -#ifndef CONFIG_NET_CLS_ACT -#ifdef CONFIG_NETFILTER - if (nf_registered) { - nf_unregister_hook(&ing_ops); - if (nf_registered > 1) - nf_unregister_hook(&ing6_ops); - } -#endif +#if !defined(CONFIG_NET_CLS_ACT) && defined(CONFIG_NETFILTER) + if (nf_registered) + nf_unregister_hooks(ing_ops, ARRAY_SIZE(ing_ops)); #endif } + module_init(ingress_module_init) module_exit(ingress_module_exit) MODULE_LICENSE("GPL"); diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 9e5e87e81f0..c9c649b26ea 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -313,21 +313,21 @@ static void netem_reset(struct Qdisc *sch) /* Pass size change message down to embedded FIFO */ static int set_fifo_limit(struct Qdisc *q, int limit) { - struct rtattr *rta; + struct nlattr *nla; int ret = -ENOMEM; /* Hack to avoid sending change message to non-FIFO */ if (strncmp(q->ops->id + 1, "fifo", 4) != 0) return 0; - rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), GFP_KERNEL); - if (rta) { - rta->rta_type = RTM_NEWQDISC; - rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt)); - ((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit; + nla = kmalloc(nla_attr_size(sizeof(struct tc_fifo_qopt)), GFP_KERNEL); + if (nla) { + nla->nla_type = RTM_NEWQDISC; + nla->nla_len = nla_attr_size(sizeof(struct tc_fifo_qopt)); + ((struct tc_fifo_qopt *)nla_data(nla))->limit = limit; - ret = q->ops->change(q, rta); - kfree(rta); + ret = q->ops->change(q, nla); + kfree(nla); } return ret; } @@ -336,11 +336,11 @@ static int set_fifo_limit(struct Qdisc *q, int limit) * Distribution data is a variable size payload containing * signed 16 bit values. */ -static int get_dist_table(struct Qdisc *sch, const struct rtattr *attr) +static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) { struct netem_sched_data *q = qdisc_priv(sch); - unsigned long n = RTA_PAYLOAD(attr)/sizeof(__s16); - const __s16 *data = RTA_DATA(attr); + unsigned long n = nla_len(attr)/sizeof(__s16); + const __s16 *data = nla_data(attr); struct disttable *d; int i; @@ -363,13 +363,10 @@ static int get_dist_table(struct Qdisc *sch, const struct rtattr *attr) return 0; } -static int get_correlation(struct Qdisc *sch, const struct rtattr *attr) +static int get_correlation(struct Qdisc *sch, const struct nlattr *attr) { struct netem_sched_data *q = qdisc_priv(sch); - const struct tc_netem_corr *c = RTA_DATA(attr); - - if (RTA_PAYLOAD(attr) != sizeof(*c)) - return -EINVAL; + const struct tc_netem_corr *c = nla_data(attr); init_crandom(&q->delay_cor, c->delay_corr); init_crandom(&q->loss_cor, c->loss_corr); @@ -377,43 +374,48 @@ static int get_correlation(struct Qdisc *sch, const struct rtattr *attr) return 0; } -static int get_reorder(struct Qdisc *sch, const struct rtattr *attr) +static int get_reorder(struct Qdisc *sch, const struct nlattr *attr) { struct netem_sched_data *q = qdisc_priv(sch); - const struct tc_netem_reorder *r = RTA_DATA(attr); - - if (RTA_PAYLOAD(attr) != sizeof(*r)) - return -EINVAL; + const struct tc_netem_reorder *r = nla_data(attr); q->reorder = r->probability; init_crandom(&q->reorder_cor, r->correlation); return 0; } -static int get_corrupt(struct Qdisc *sch, const struct rtattr *attr) +static int get_corrupt(struct Qdisc *sch, const struct nlattr *attr) { struct netem_sched_data *q = qdisc_priv(sch); - const struct tc_netem_corrupt *r = RTA_DATA(attr); - - if (RTA_PAYLOAD(attr) != sizeof(*r)) - return -EINVAL; + const struct tc_netem_corrupt *r = nla_data(attr); q->corrupt = r->probability; init_crandom(&q->corrupt_cor, r->correlation); return 0; } +static const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = { + [TCA_NETEM_CORR] = { .len = sizeof(struct tc_netem_corr) }, + [TCA_NETEM_REORDER] = { .len = sizeof(struct tc_netem_reorder) }, + [TCA_NETEM_CORRUPT] = { .len = sizeof(struct tc_netem_corrupt) }, +}; + /* Parse netlink message to set options */ -static int netem_change(struct Qdisc *sch, struct rtattr *opt) +static int netem_change(struct Qdisc *sch, struct nlattr *opt) { struct netem_sched_data *q = qdisc_priv(sch); + struct nlattr *tb[TCA_NETEM_MAX + 1]; struct tc_netem_qopt *qopt; int ret; - if (opt == NULL || RTA_PAYLOAD(opt) < sizeof(*qopt)) + if (opt == NULL) return -EINVAL; - qopt = RTA_DATA(opt); + ret = nla_parse_nested_compat(tb, TCA_NETEM_MAX, opt, netem_policy, + qopt, sizeof(*qopt)); + if (ret < 0) + return ret; + ret = set_fifo_limit(q->qdisc, qopt->limit); if (ret) { pr_debug("netem: can't set fifo limit\n"); @@ -434,39 +436,28 @@ static int netem_change(struct Qdisc *sch, struct rtattr *opt) if (q->gap) q->reorder = ~0; - /* Handle nested options after initial queue options. - * Should have put all options in nested format but too late now. - */ - if (RTA_PAYLOAD(opt) > sizeof(*qopt)) { - struct rtattr *tb[TCA_NETEM_MAX]; - if (rtattr_parse(tb, TCA_NETEM_MAX, - RTA_DATA(opt) + sizeof(*qopt), - RTA_PAYLOAD(opt) - sizeof(*qopt))) - return -EINVAL; - - if (tb[TCA_NETEM_CORR-1]) { - ret = get_correlation(sch, tb[TCA_NETEM_CORR-1]); - if (ret) - return ret; - } + if (tb[TCA_NETEM_CORR]) { + ret = get_correlation(sch, tb[TCA_NETEM_CORR]); + if (ret) + return ret; + } - if (tb[TCA_NETEM_DELAY_DIST-1]) { - ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST-1]); - if (ret) - return ret; - } + if (tb[TCA_NETEM_DELAY_DIST]) { + ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST]); + if (ret) + return ret; + } - if (tb[TCA_NETEM_REORDER-1]) { - ret = get_reorder(sch, tb[TCA_NETEM_REORDER-1]); - if (ret) - return ret; - } + if (tb[TCA_NETEM_REORDER]) { + ret = get_reorder(sch, tb[TCA_NETEM_REORDER]); + if (ret) + return ret; + } - if (tb[TCA_NETEM_CORRUPT-1]) { - ret = get_corrupt(sch, tb[TCA_NETEM_CORRUPT-1]); - if (ret) - return ret; - } + if (tb[TCA_NETEM_CORRUPT]) { + ret = get_corrupt(sch, tb[TCA_NETEM_CORRUPT]); + if (ret) + return ret; } return 0; @@ -515,13 +506,13 @@ static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch) return qdisc_reshape_fail(nskb, sch); } -static int tfifo_init(struct Qdisc *sch, struct rtattr *opt) +static int tfifo_init(struct Qdisc *sch, struct nlattr *opt) { struct fifo_sched_data *q = qdisc_priv(sch); if (opt) { - struct tc_fifo_qopt *ctl = RTA_DATA(opt); - if (RTA_PAYLOAD(opt) < sizeof(*ctl)) + struct tc_fifo_qopt *ctl = nla_data(opt); + if (nla_len(opt) < sizeof(*ctl)) return -EINVAL; q->limit = ctl->limit; @@ -537,14 +528,14 @@ static int tfifo_dump(struct Qdisc *sch, struct sk_buff *skb) struct fifo_sched_data *q = qdisc_priv(sch); struct tc_fifo_qopt opt = { .limit = q->limit }; - RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); + NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); return skb->len; -rtattr_failure: +nla_put_failure: return -1; } -static struct Qdisc_ops tfifo_qdisc_ops = { +static struct Qdisc_ops tfifo_qdisc_ops __read_mostly = { .id = "tfifo", .priv_size = sizeof(struct fifo_sched_data), .enqueue = tfifo_enqueue, @@ -557,7 +548,7 @@ static struct Qdisc_ops tfifo_qdisc_ops = { .dump = tfifo_dump, }; -static int netem_init(struct Qdisc *sch, struct rtattr *opt) +static int netem_init(struct Qdisc *sch, struct nlattr *opt) { struct netem_sched_data *q = qdisc_priv(sch); int ret; @@ -595,7 +586,7 @@ static int netem_dump(struct Qdisc *sch, struct sk_buff *skb) { const struct netem_sched_data *q = qdisc_priv(sch); unsigned char *b = skb_tail_pointer(skb); - struct rtattr *rta = (struct rtattr *) b; + struct nlattr *nla = (struct nlattr *) b; struct tc_netem_qopt qopt; struct tc_netem_corr cor; struct tc_netem_reorder reorder; @@ -607,26 +598,26 @@ static int netem_dump(struct Qdisc *sch, struct sk_buff *skb) qopt.loss = q->loss; qopt.gap = q->gap; qopt.duplicate = q->duplicate; - RTA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt); + NLA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt); cor.delay_corr = q->delay_cor.rho; cor.loss_corr = q->loss_cor.rho; cor.dup_corr = q->dup_cor.rho; - RTA_PUT(skb, TCA_NETEM_CORR, sizeof(cor), &cor); + NLA_PUT(skb, TCA_NETEM_CORR, sizeof(cor), &cor); reorder.probability = q->reorder; reorder.correlation = q->reorder_cor.rho; - RTA_PUT(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder); + NLA_PUT(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder); corrupt.probability = q->corrupt; corrupt.correlation = q->corrupt_cor.rho; - RTA_PUT(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt); + NLA_PUT(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt); - rta->rta_len = skb_tail_pointer(skb) - b; + nla->nla_len = skb_tail_pointer(skb) - b; return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } @@ -678,7 +669,7 @@ static void netem_put(struct Qdisc *sch, unsigned long arg) } static int netem_change_class(struct Qdisc *sch, u32 classid, u32 parentid, - struct rtattr **tca, unsigned long *arg) + struct nlattr **tca, unsigned long *arg) { return -ENOSYS; } @@ -705,7 +696,7 @@ static struct tcf_proto **netem_find_tcf(struct Qdisc *sch, unsigned long cl) return NULL; } -static struct Qdisc_class_ops netem_class_ops = { +static const struct Qdisc_class_ops netem_class_ops = { .graft = netem_graft, .leaf = netem_leaf, .get = netem_get, @@ -717,7 +708,7 @@ static struct Qdisc_class_ops netem_class_ops = { .dump = netem_dump_class, }; -static struct Qdisc_ops netem_qdisc_ops = { +static struct Qdisc_ops netem_qdisc_ops __read_mostly = { .id = "netem", .cl_ops = &netem_class_ops, .priv_size = sizeof(struct netem_sched_data), diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index de894096e44..4aa2b45dad0 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -224,16 +224,19 @@ prio_destroy(struct Qdisc* sch) qdisc_destroy(q->queues[prio]); } -static int prio_tune(struct Qdisc *sch, struct rtattr *opt) +static int prio_tune(struct Qdisc *sch, struct nlattr *opt) { struct prio_sched_data *q = qdisc_priv(sch); struct tc_prio_qopt *qopt; - struct rtattr *tb[TCA_PRIO_MAX]; + struct nlattr *tb[TCA_PRIO_MAX + 1]; + int err; int i; - if (rtattr_parse_nested_compat(tb, TCA_PRIO_MAX, opt, qopt, - sizeof(*qopt))) - return -EINVAL; + err = nla_parse_nested_compat(tb, TCA_PRIO_MAX, opt, NULL, qopt, + sizeof(*qopt)); + if (err < 0) + return err; + q->bands = qopt->bands; /* If we're multiqueue, make sure the number of incoming bands * matches the number of queues on the device we're associating with. @@ -242,7 +245,7 @@ static int prio_tune(struct Qdisc *sch, struct rtattr *opt) * only one that is enabled for multiqueue, since it's the only one * that interacts with the underlying device. */ - q->mq = RTA_GET_FLAG(tb[TCA_PRIO_MQ - 1]); + q->mq = nla_get_flag(tb[TCA_PRIO_MQ]); if (q->mq) { if (sch->parent != TC_H_ROOT) return -EINVAL; @@ -296,7 +299,7 @@ static int prio_tune(struct Qdisc *sch, struct rtattr *opt) return 0; } -static int prio_init(struct Qdisc *sch, struct rtattr *opt) +static int prio_init(struct Qdisc *sch, struct nlattr *opt) { struct prio_sched_data *q = qdisc_priv(sch); int i; @@ -319,20 +322,24 @@ static int prio_dump(struct Qdisc *sch, struct sk_buff *skb) { struct prio_sched_data *q = qdisc_priv(sch); unsigned char *b = skb_tail_pointer(skb); - struct rtattr *nest; + struct nlattr *nest; struct tc_prio_qopt opt; opt.bands = q->bands; memcpy(&opt.priomap, q->prio2band, TC_PRIO_MAX+1); - nest = RTA_NEST_COMPAT(skb, TCA_OPTIONS, sizeof(opt), &opt); - if (q->mq) - RTA_PUT_FLAG(skb, TCA_PRIO_MQ); - RTA_NEST_COMPAT_END(skb, nest); + nest = nla_nest_compat_start(skb, TCA_OPTIONS, sizeof(opt), &opt); + if (nest == NULL) + goto nla_put_failure; + if (q->mq) { + if (nla_put_flag(skb, TCA_PRIO_MQ) < 0) + goto nla_put_failure; + } + nla_nest_compat_end(skb, nest); return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } @@ -392,7 +399,7 @@ static void prio_put(struct Qdisc *q, unsigned long cl) return; } -static int prio_change(struct Qdisc *sch, u32 handle, u32 parent, struct rtattr **tca, unsigned long *arg) +static int prio_change(struct Qdisc *sch, u32 handle, u32 parent, struct nlattr **tca, unsigned long *arg) { unsigned long cl = *arg; struct prio_sched_data *q = qdisc_priv(sch); @@ -468,7 +475,7 @@ static struct tcf_proto ** prio_find_tcf(struct Qdisc *sch, unsigned long cl) return &q->filter_list; } -static struct Qdisc_class_ops prio_class_ops = { +static const struct Qdisc_class_ops prio_class_ops = { .graft = prio_graft, .leaf = prio_leaf, .get = prio_get, @@ -483,7 +490,7 @@ static struct Qdisc_class_ops prio_class_ops = { .dump_stats = prio_dump_class_stats, }; -static struct Qdisc_ops prio_qdisc_ops = { +static struct Qdisc_ops prio_qdisc_ops __read_mostly = { .next = NULL, .cl_ops = &prio_class_ops, .id = "prio", @@ -500,7 +507,7 @@ static struct Qdisc_ops prio_qdisc_ops = { .owner = THIS_MODULE, }; -static struct Qdisc_ops rr_qdisc_ops = { +static struct Qdisc_ops rr_qdisc_ops __read_mostly = { .next = NULL, .cl_ops = &prio_class_ops, .id = "rr", diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 9b95fefb70f..3dcd493f4f4 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -177,21 +177,21 @@ static void red_destroy(struct Qdisc *sch) static struct Qdisc *red_create_dflt(struct Qdisc *sch, u32 limit) { struct Qdisc *q; - struct rtattr *rta; + struct nlattr *nla; int ret; q = qdisc_create_dflt(sch->dev, &bfifo_qdisc_ops, TC_H_MAKE(sch->handle, 1)); if (q) { - rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), + nla = kmalloc(nla_attr_size(sizeof(struct tc_fifo_qopt)), GFP_KERNEL); - if (rta) { - rta->rta_type = RTM_NEWQDISC; - rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt)); - ((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit; + if (nla) { + nla->nla_type = RTM_NEWQDISC; + nla->nla_len = nla_attr_size(sizeof(struct tc_fifo_qopt)); + ((struct tc_fifo_qopt *)nla_data(nla))->limit = limit; - ret = q->ops->change(q, rta); - kfree(rta); + ret = q->ops->change(q, nla); + kfree(nla); if (ret == 0) return q; @@ -201,23 +201,31 @@ static struct Qdisc *red_create_dflt(struct Qdisc *sch, u32 limit) return NULL; } -static int red_change(struct Qdisc *sch, struct rtattr *opt) +static const struct nla_policy red_policy[TCA_RED_MAX + 1] = { + [TCA_RED_PARMS] = { .len = sizeof(struct tc_red_qopt) }, + [TCA_RED_STAB] = { .len = RED_STAB_SIZE }, +}; + +static int red_change(struct Qdisc *sch, struct nlattr *opt) { struct red_sched_data *q = qdisc_priv(sch); - struct rtattr *tb[TCA_RED_MAX]; + struct nlattr *tb[TCA_RED_MAX + 1]; struct tc_red_qopt *ctl; struct Qdisc *child = NULL; + int err; - if (opt == NULL || rtattr_parse_nested(tb, TCA_RED_MAX, opt)) + if (opt == NULL) return -EINVAL; - if (tb[TCA_RED_PARMS-1] == NULL || - RTA_PAYLOAD(tb[TCA_RED_PARMS-1]) < sizeof(*ctl) || - tb[TCA_RED_STAB-1] == NULL || - RTA_PAYLOAD(tb[TCA_RED_STAB-1]) < RED_STAB_SIZE) + err = nla_parse_nested(tb, TCA_RED_MAX, opt, red_policy); + if (err < 0) + return err; + + if (tb[TCA_RED_PARMS] == NULL || + tb[TCA_RED_STAB] == NULL) return -EINVAL; - ctl = RTA_DATA(tb[TCA_RED_PARMS-1]); + ctl = nla_data(tb[TCA_RED_PARMS]); if (ctl->limit > 0) { child = red_create_dflt(sch, ctl->limit); @@ -235,7 +243,7 @@ static int red_change(struct Qdisc *sch, struct rtattr *opt) red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, ctl->Plog, ctl->Scell_log, - RTA_DATA(tb[TCA_RED_STAB-1])); + nla_data(tb[TCA_RED_STAB])); if (skb_queue_empty(&sch->q)) red_end_of_idle_period(&q->parms); @@ -244,7 +252,7 @@ static int red_change(struct Qdisc *sch, struct rtattr *opt) return 0; } -static int red_init(struct Qdisc* sch, struct rtattr *opt) +static int red_init(struct Qdisc* sch, struct nlattr *opt) { struct red_sched_data *q = qdisc_priv(sch); @@ -255,7 +263,7 @@ static int red_init(struct Qdisc* sch, struct rtattr *opt) static int red_dump(struct Qdisc *sch, struct sk_buff *skb) { struct red_sched_data *q = qdisc_priv(sch); - struct rtattr *opts = NULL; + struct nlattr *opts = NULL; struct tc_red_qopt opt = { .limit = q->limit, .flags = q->flags, @@ -266,12 +274,14 @@ static int red_dump(struct Qdisc *sch, struct sk_buff *skb) .Scell_log = q->parms.Scell_log, }; - opts = RTA_NEST(skb, TCA_OPTIONS); - RTA_PUT(skb, TCA_RED_PARMS, sizeof(opt), &opt); - return RTA_NEST_END(skb, opts); + opts = nla_nest_start(skb, TCA_OPTIONS); + if (opts == NULL) + goto nla_put_failure; + NLA_PUT(skb, TCA_RED_PARMS, sizeof(opt), &opt); + return nla_nest_end(skb, opts); -rtattr_failure: - return RTA_NEST_CANCEL(skb, opts); +nla_put_failure: + return nla_nest_cancel(skb, opts); } static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d) @@ -332,7 +342,7 @@ static void red_put(struct Qdisc *sch, unsigned long arg) } static int red_change_class(struct Qdisc *sch, u32 classid, u32 parentid, - struct rtattr **tca, unsigned long *arg) + struct nlattr **tca, unsigned long *arg) { return -ENOSYS; } @@ -359,7 +369,7 @@ static struct tcf_proto **red_find_tcf(struct Qdisc *sch, unsigned long cl) return NULL; } -static struct Qdisc_class_ops red_class_ops = { +static const struct Qdisc_class_ops red_class_ops = { .graft = red_graft, .leaf = red_leaf, .get = red_get, @@ -371,7 +381,7 @@ static struct Qdisc_class_ops red_class_ops = { .dump = red_dump_class, }; -static struct Qdisc_ops red_qdisc_ops = { +static struct Qdisc_ops red_qdisc_ops __read_mostly = { .id = "red", .priv_size = sizeof(struct red_sched_data), .cl_ops = &red_class_ops, diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index b542c875e15..91af539ab6e 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -122,7 +122,7 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb) { const struct iphdr *iph = ip_hdr(skb); h = iph->daddr; - h2 = iph->saddr^iph->protocol; + h2 = iph->saddr ^ iph->protocol; if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP || @@ -137,7 +137,7 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb) { struct ipv6hdr *iph = ipv6_hdr(skb); h = iph->daddr.s6_addr32[3]; - h2 = iph->saddr.s6_addr32[3]^iph->nexthdr; + h2 = iph->saddr.s6_addr32[3] ^ iph->nexthdr; if (iph->nexthdr == IPPROTO_TCP || iph->nexthdr == IPPROTO_UDP || iph->nexthdr == IPPROTO_UDPLITE || @@ -148,9 +148,10 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb) break; } default: - h = (u32)(unsigned long)skb->dst^skb->protocol; - h2 = (u32)(unsigned long)skb->sk; + h = (unsigned long)skb->dst ^ skb->protocol; + h2 = (unsigned long)skb->sk; } + return sfq_fold_hash(q, h, h2); } @@ -208,7 +209,7 @@ static unsigned int sfq_drop(struct Qdisc *sch) drop a packet from it */ if (d > 1) { - sfq_index x = q->dep[d+SFQ_DEPTH].next; + sfq_index x = q->dep[d + SFQ_DEPTH].next; skb = q->qs[x].prev; len = skb->len; __skb_unlink(skb, &q->qs[x]); @@ -241,7 +242,7 @@ static unsigned int sfq_drop(struct Qdisc *sch) } static int -sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch) +sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) { struct sfq_sched_data *q = qdisc_priv(sch); unsigned hash = sfq_hash(q, skb); @@ -252,6 +253,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch) q->ht[hash] = x = q->dep[SFQ_DEPTH].next; q->hash[x] = hash; } + /* If selected queue has length q->limit, this means that * all another queues are empty and that we do simple tail drop, * i.e. drop _this_ packet. @@ -284,7 +286,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch) } static int -sfq_requeue(struct sk_buff *skb, struct Qdisc* sch) +sfq_requeue(struct sk_buff *skb, struct Qdisc *sch) { struct sfq_sched_data *q = qdisc_priv(sch); unsigned hash = sfq_hash(q, skb); @@ -295,6 +297,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch) q->ht[hash] = x = q->dep[SFQ_DEPTH].next; q->hash[x] = hash; } + sch->qstats.backlog += skb->len; __skb_queue_head(&q->qs[x], skb); /* If selected queue has length q->limit+1, this means that @@ -310,6 +313,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch) kfree_skb(skb); return NET_XMIT_CN; } + sfq_inc(q, x); if (q->qs[x].qlen == 1) { /* The flow is new */ if (q->tail == SFQ_DEPTH) { /* It is the first flow */ @@ -322,6 +326,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch) q->tail = x; } } + if (++sch->q.qlen <= q->limit) { sch->qstats.requeues++; return 0; @@ -336,7 +341,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch) static struct sk_buff * -sfq_dequeue(struct Qdisc* sch) +sfq_dequeue(struct Qdisc *sch) { struct sfq_sched_data *q = qdisc_priv(sch); struct sk_buff *skb; @@ -373,7 +378,7 @@ sfq_dequeue(struct Qdisc* sch) } static void -sfq_reset(struct Qdisc* sch) +sfq_reset(struct Qdisc *sch) { struct sk_buff *skb; @@ -383,27 +388,27 @@ sfq_reset(struct Qdisc* sch) static void sfq_perturbation(unsigned long arg) { - struct Qdisc *sch = (struct Qdisc*)arg; + struct Qdisc *sch = (struct Qdisc *)arg; struct sfq_sched_data *q = qdisc_priv(sch); - get_random_bytes(&q->perturbation, 4); + q->perturbation = net_random(); if (q->perturb_period) mod_timer(&q->perturb_timer, jiffies + q->perturb_period); } -static int sfq_change(struct Qdisc *sch, struct rtattr *opt) +static int sfq_change(struct Qdisc *sch, struct nlattr *opt) { struct sfq_sched_data *q = qdisc_priv(sch); - struct tc_sfq_qopt *ctl = RTA_DATA(opt); + struct tc_sfq_qopt *ctl = nla_data(opt); unsigned int qlen; - if (opt->rta_len < RTA_LENGTH(sizeof(*ctl))) + if (opt->nla_len < nla_attr_size(sizeof(*ctl))) return -EINVAL; sch_tree_lock(sch); q->quantum = ctl->quantum ? : psched_mtu(sch->dev); - q->perturb_period = ctl->perturb_period*HZ; + q->perturb_period = ctl->perturb_period * HZ; if (ctl->limit) q->limit = min_t(u32, ctl->limit, SFQ_DEPTH - 1); @@ -415,41 +420,44 @@ static int sfq_change(struct Qdisc *sch, struct rtattr *opt) del_timer(&q->perturb_timer); if (q->perturb_period) { mod_timer(&q->perturb_timer, jiffies + q->perturb_period); - get_random_bytes(&q->perturbation, 4); + q->perturbation = net_random(); } sch_tree_unlock(sch); return 0; } -static int sfq_init(struct Qdisc *sch, struct rtattr *opt) +static int sfq_init(struct Qdisc *sch, struct nlattr *opt) { struct sfq_sched_data *q = qdisc_priv(sch); int i; - init_timer(&q->perturb_timer); - q->perturb_timer.data = (unsigned long)sch; q->perturb_timer.function = sfq_perturbation; + q->perturb_timer.data = (unsigned long)sch;; + init_timer_deferrable(&q->perturb_timer); - for (i=0; i<SFQ_HASH_DIVISOR; i++) + for (i = 0; i < SFQ_HASH_DIVISOR; i++) q->ht[i] = SFQ_DEPTH; - for (i=0; i<SFQ_DEPTH; i++) { + + for (i = 0; i < SFQ_DEPTH; i++) { skb_queue_head_init(&q->qs[i]); - q->dep[i+SFQ_DEPTH].next = i+SFQ_DEPTH; - q->dep[i+SFQ_DEPTH].prev = i+SFQ_DEPTH; + q->dep[i + SFQ_DEPTH].next = i + SFQ_DEPTH; + q->dep[i + SFQ_DEPTH].prev = i + SFQ_DEPTH; } + q->limit = SFQ_DEPTH - 1; q->max_depth = 0; q->tail = SFQ_DEPTH; if (opt == NULL) { q->quantum = psched_mtu(sch->dev); q->perturb_period = 0; - get_random_bytes(&q->perturbation, 4); + q->perturbation = net_random(); } else { int err = sfq_change(sch, opt); if (err) return err; } - for (i=0; i<SFQ_DEPTH; i++) + + for (i = 0; i < SFQ_DEPTH; i++) sfq_link(q, i); return 0; } @@ -467,22 +475,22 @@ static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb) struct tc_sfq_qopt opt; opt.quantum = q->quantum; - opt.perturb_period = q->perturb_period/HZ; + opt.perturb_period = q->perturb_period / HZ; opt.limit = q->limit; opt.divisor = SFQ_HASH_DIVISOR; opt.flows = q->limit; - RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); + NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); return skb->len; -rtattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } -static struct Qdisc_ops sfq_qdisc_ops = { +static struct Qdisc_ops sfq_qdisc_ops __read_mostly = { .next = NULL, .cl_ops = NULL, .id = "sfq", diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index b0d81098b0e..0b7d78f59d8 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -245,20 +245,21 @@ static void tbf_reset(struct Qdisc* sch) static struct Qdisc *tbf_create_dflt_qdisc(struct Qdisc *sch, u32 limit) { struct Qdisc *q; - struct rtattr *rta; + struct nlattr *nla; int ret; q = qdisc_create_dflt(sch->dev, &bfifo_qdisc_ops, TC_H_MAKE(sch->handle, 1)); if (q) { - rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), GFP_KERNEL); - if (rta) { - rta->rta_type = RTM_NEWQDISC; - rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt)); - ((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit; + nla = kmalloc(nla_attr_size(sizeof(struct tc_fifo_qopt)), + GFP_KERNEL); + if (nla) { + nla->nla_type = RTM_NEWQDISC; + nla->nla_len = nla_attr_size(sizeof(struct tc_fifo_qopt)); + ((struct tc_fifo_qopt *)nla_data(nla))->limit = limit; - ret = q->ops->change(q, rta); - kfree(rta); + ret = q->ops->change(q, nla); + kfree(nla); if (ret == 0) return q; @@ -269,30 +270,39 @@ static struct Qdisc *tbf_create_dflt_qdisc(struct Qdisc *sch, u32 limit) return NULL; } -static int tbf_change(struct Qdisc* sch, struct rtattr *opt) +static const struct nla_policy tbf_policy[TCA_TBF_MAX + 1] = { + [TCA_TBF_PARMS] = { .len = sizeof(struct tc_tbf_qopt) }, + [TCA_TBF_RTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE }, + [TCA_TBF_PTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE }, +}; + +static int tbf_change(struct Qdisc* sch, struct nlattr *opt) { - int err = -EINVAL; + int err; struct tbf_sched_data *q = qdisc_priv(sch); - struct rtattr *tb[TCA_TBF_PTAB]; + struct nlattr *tb[TCA_TBF_PTAB + 1]; struct tc_tbf_qopt *qopt; struct qdisc_rate_table *rtab = NULL; struct qdisc_rate_table *ptab = NULL; struct Qdisc *child = NULL; int max_size,n; - if (rtattr_parse_nested(tb, TCA_TBF_PTAB, opt) || - tb[TCA_TBF_PARMS-1] == NULL || - RTA_PAYLOAD(tb[TCA_TBF_PARMS-1]) < sizeof(*qopt)) + err = nla_parse_nested(tb, TCA_TBF_PTAB, opt, tbf_policy); + if (err < 0) + return err; + + err = -EINVAL; + if (tb[TCA_TBF_PARMS] == NULL) goto done; - qopt = RTA_DATA(tb[TCA_TBF_PARMS-1]); - rtab = qdisc_get_rtab(&qopt->rate, tb[TCA_TBF_RTAB-1]); + qopt = nla_data(tb[TCA_TBF_PARMS]); + rtab = qdisc_get_rtab(&qopt->rate, tb[TCA_TBF_RTAB]); if (rtab == NULL) goto done; if (qopt->peakrate.rate) { if (qopt->peakrate.rate > qopt->rate.rate) - ptab = qdisc_get_rtab(&qopt->peakrate, tb[TCA_TBF_PTAB-1]); + ptab = qdisc_get_rtab(&qopt->peakrate, tb[TCA_TBF_PTAB]); if (ptab == NULL) goto done; } @@ -339,7 +349,7 @@ done: return err; } -static int tbf_init(struct Qdisc* sch, struct rtattr *opt) +static int tbf_init(struct Qdisc* sch, struct nlattr *opt) { struct tbf_sched_data *q = qdisc_priv(sch); @@ -370,12 +380,12 @@ static void tbf_destroy(struct Qdisc *sch) static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb) { struct tbf_sched_data *q = qdisc_priv(sch); - unsigned char *b = skb_tail_pointer(skb); - struct rtattr *rta; + struct nlattr *nest; struct tc_tbf_qopt opt; - rta = (struct rtattr*)b; - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; opt.limit = q->limit; opt.rate = q->R_tab->rate; @@ -385,13 +395,13 @@ static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb) memset(&opt.peakrate, 0, sizeof(opt.peakrate)); opt.mtu = q->mtu; opt.buffer = q->buffer; - RTA_PUT(skb, TCA_TBF_PARMS, sizeof(opt), &opt); - rta->rta_len = skb_tail_pointer(skb) - b; + NLA_PUT(skb, TCA_TBF_PARMS, sizeof(opt), &opt); + nla_nest_end(skb, nest); return skb->len; -rtattr_failure: - nlmsg_trim(skb, b); +nla_put_failure: + nla_nest_cancel(skb, nest); return -1; } @@ -442,7 +452,7 @@ static void tbf_put(struct Qdisc *sch, unsigned long arg) } static int tbf_change_class(struct Qdisc *sch, u32 classid, u32 parentid, - struct rtattr **tca, unsigned long *arg) + struct nlattr **tca, unsigned long *arg) { return -ENOSYS; } @@ -469,7 +479,7 @@ static struct tcf_proto **tbf_find_tcf(struct Qdisc *sch, unsigned long cl) return NULL; } -static struct Qdisc_class_ops tbf_class_ops = +static const struct Qdisc_class_ops tbf_class_ops = { .graft = tbf_graft, .leaf = tbf_leaf, @@ -482,7 +492,7 @@ static struct Qdisc_class_ops tbf_class_ops = .dump = tbf_dump_class, }; -static struct Qdisc_ops tbf_qdisc_ops = { +static struct Qdisc_ops tbf_qdisc_ops __read_mostly = { .next = NULL, .cl_ops = &tbf_class_ops, .id = "tbf", diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index c0ed06d4a50..1411c7b1fbd 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -168,7 +168,7 @@ teql_destroy(struct Qdisc* sch) } } -static int teql_qdisc_init(struct Qdisc *sch, struct rtattr *opt) +static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt) { struct net_device *dev = sch->dev; struct teql_master *m = (struct teql_master*)sch->ops; |