act_api.c

来自「linux 内核源代码」· C语言 代码 · 共 1,075 行 · 第 1/2 页

C
1,075
字号
struct tc_action *tcf_action_init(struct rtattr *rta, struct rtattr *est,				  char *name, int ovr, int bind, int *err){	struct rtattr *tb[TCA_ACT_MAX_PRIO+1];	struct tc_action *head = NULL, *act, *act_prev = NULL;	int i;	if (rtattr_parse_nested(tb, TCA_ACT_MAX_PRIO, rta) < 0) {		*err = -EINVAL;		return head;	}	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)			goto err;		act->order = i+1;		if (head == NULL)			head = act;		else			act_prev->next = act;		act_prev = act;	}	return head;err:	if (head != NULL)		tcf_action_destroy(head, bind);	return NULL;}int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,			  int compat_mode){	int err = 0;	struct gnet_dump d;	struct tcf_act_hdr *h = a->priv;	if (h == NULL)		goto errout;	/* compat_mode being true specifies a call that is supposed	 * to add additional backward compatiblity statistic TLVs.	 */	if (compat_mode) {		if (a->type == TCA_OLD_COMPAT)			err = gnet_stats_start_copy_compat(skb, 0,				TCA_STATS, TCA_XSTATS, &h->tcf_lock, &d);		else			return 0;	} else		err = gnet_stats_start_copy(skb, TCA_ACT_STATS,					    &h->tcf_lock, &d);	if (err < 0)		goto errout;	if (a->ops != NULL && a->ops->get_stats != NULL)		if (a->ops->get_stats(skb, a) < 0)			goto errout;	if (gnet_stats_copy_basic(&d, &h->tcf_bstats) < 0 ||	    gnet_stats_copy_rate_est(&d, &h->tcf_rate_est) < 0 ||	    gnet_stats_copy_queue(&d, &h->tcf_qstats) < 0)		goto errout;	if (gnet_stats_finish_copy(&d) < 0)		goto errout;	return 0;errout:	return -1;}static inttca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 pid, u32 seq,	     u16 flags, int event, int bind, int ref){	struct tcamsg *t;	struct nlmsghdr *nlh;	unsigned char *b = skb_tail_pointer(skb);	struct rtattr *x;	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*t), flags);	t = NLMSG_DATA(nlh);	t->tca_family = AF_UNSPEC;	t->tca__pad1 = 0;	t->tca__pad2 = 0;	x = (struct rtattr *)skb_tail_pointer(skb);	RTA_PUT(skb, TCA_ACT_TAB, 0, NULL);	if (tcf_action_dump(skb, a, bind, ref) < 0)		goto rtattr_failure;	x->rta_len = skb_tail_pointer(skb) - (u8 *)x;	nlh->nlmsg_len = skb_tail_pointer(skb) - b;	return skb->len;rtattr_failure:nlmsg_failure:	nlmsg_trim(skb, b);	return -1;}static intact_get_notify(u32 pid, struct nlmsghdr *n, struct tc_action *a, int event){	struct sk_buff *skb;	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);	if (!skb)		return -ENOBUFS;	if (tca_get_fill(skb, a, pid, n->nlmsg_seq, 0, event, 0, 0) <= 0) {		kfree_skb(skb);		return -EINVAL;	}	return rtnl_unicast(skb, pid);}static struct tc_action *tcf_action_get_1(struct rtattr *rta, struct nlmsghdr *n, u32 pid, int *err){	struct rtattr *tb[TCA_ACT_MAX+1];	struct tc_action *a;	int index;	*err = -EINVAL;	if (rtattr_parse_nested(tb, TCA_ACT_MAX, rta) < 0)		return NULL;	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 = -ENOMEM;	a = kzalloc(sizeof(struct tc_action), GFP_KERNEL);	if (a == NULL)		return NULL;	*err = -EINVAL;	a->ops = tc_lookup_action(tb[TCA_ACT_KIND - 1]);	if (a->ops == NULL)		goto err_free;	if (a->ops->lookup == NULL)		goto err_mod;	*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;}static void cleanup_a(struct tc_action *act){	struct tc_action *a;	for (a = act; a; a = act) {		act = a->next;		kfree(a);	}}static struct tc_action *create_a(int i){	struct tc_action *act;	act = kzalloc(sizeof(*act), GFP_KERNEL);	if (act == NULL) {		printk("create_a: failed to alloc!\n");		return NULL;	}	act->order = i;	return act;}static int tca_action_flush(struct rtattr *rta, 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 tc_action *a = create_a(0);	int err = -EINVAL;	if (a == NULL) {		printk("tca_action_flush: couldnt create tc_action\n");		return err;	}	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);	if (!skb) {		printk("tca_action_flush: failed skb alloc\n");		kfree(a);		return -ENOBUFS;	}	b = skb_tail_pointer(skb);	if (rtattr_parse_nested(tb, TCA_ACT_MAX, rta) < 0)		goto err_out;	kind = tb[TCA_ACT_KIND-1];	a->ops = tc_lookup_action(kind);	if (a->ops == NULL)		goto err_out;	nlh = NLMSG_PUT(skb, pid, n->nlmsg_seq, RTM_DELACTION, sizeof(*t));	t = NLMSG_DATA(nlh);	t->tca_family = AF_UNSPEC;	t->tca__pad1 = 0;	t->tca__pad2 = 0;	x = (struct rtattr *)skb_tail_pointer(skb);	RTA_PUT(skb, TCA_ACT_TAB, 0, NULL);	err = a->ops->walk(skb, &dcb, RTM_DELACTION, a);	if (err < 0)		goto rtattr_failure;	x->rta_len = skb_tail_pointer(skb) - (u8 *)x;	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);	if (err > 0)		return 0;	return err;rtattr_failure:nlmsg_failure:	module_put(a->ops->owner);err_out:	kfree_skb(skb);	kfree(a);	return err;}static inttca_action_gd(struct rtattr *rta, struct nlmsghdr *n, u32 pid, int event){	int i, ret = 0;	struct rtattr *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;	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)			goto err;		act->order = i+1;		if (head == NULL)			head = act;		else			act_prev->next = act;		act_prev = act;	}	if (event == RTM_GETACTION)		ret = act_get_notify(pid, n, head, event);	else { /* delete */		struct sk_buff *skb;		skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);		if (!skb) {			ret = -ENOBUFS;			goto err;		}		if (tca_get_fill(skb, head, pid, n->nlmsg_seq, 0, event,				 0, 1) <= 0) {			kfree_skb(skb);			ret = -EINVAL;			goto err;		}		/* now do the delete */		tcf_action_destroy(head, 0);		ret = rtnetlink_send(skb, pid, RTNLGRP_TC,				     n->nlmsg_flags&NLM_F_ECHO);		if (ret > 0)			return 0;		return ret;	}err:	cleanup_a(head);	return ret;}static int tcf_add_notify(struct tc_action *a, u32 pid, u32 seq, int event,			  u16 flags){	struct tcamsg *t;	struct nlmsghdr *nlh;	struct sk_buff *skb;	struct rtattr *x;	unsigned char *b;	int err = 0;	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);	if (!skb)		return -ENOBUFS;	b = skb_tail_pointer(skb);	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*t), flags);	t = NLMSG_DATA(nlh);	t->tca_family = AF_UNSPEC;	t->tca__pad1 = 0;	t->tca__pad2 = 0;	x = (struct rtattr *)skb_tail_pointer(skb);	RTA_PUT(skb, TCA_ACT_TAB, 0, NULL);	if (tcf_action_dump(skb, a, 0, 0) < 0)		goto rtattr_failure;	x->rta_len = skb_tail_pointer(skb) - (u8 *)x;	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);	if (err > 0)		err = 0;	return err;rtattr_failure:nlmsg_failure:	kfree_skb(skb);	return -1;}static inttcf_action_add(struct rtattr *rta, 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);	if (act == NULL)		goto done;	/* dump then free all the actions after update; inserted policy	 * stays intact	 * */	ret = tcf_add_notify(act, pid, seq, RTM_NEWACTION, n->nlmsg_flags);	for (a = act; a; a = act) {		act = a->next;		kfree(a);	}done:	return ret;}static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg){	struct rtattr **tca = arg;	u32 pid = skb ? NETLINK_CB(skb).pid : 0;	int ret = 0, ovr = 0;	if (tca[TCA_ACT_TAB-1] == NULL) {		printk("tc_ctl_action: received NO action attribs\n");		return -EINVAL;	}	/* n->nlmsg_flags&NLM_F_CREATE	 * */	switch (n->nlmsg_type) {	case RTM_NEWACTION:		/* we are going to assume all other flags		 * imply create only if it doesnt exist		 * Note that CREATE | EXCL implies that		 * but since we want avoid ambiguity (eg when flags		 * is zero) then just set this		 */		if (n->nlmsg_flags&NLM_F_REPLACE)			ovr = 1;replay:		ret = tcf_action_add(tca[TCA_ACT_TAB-1], 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);		break;	case RTM_GETACTION:		ret = tca_action_gd(tca[TCA_ACT_TAB-1], n, pid, RTM_GETACTION);		break;	default:		BUG();	}	return ret;}static struct rtattr *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)		return NULL;	tb1 = rta[TCA_ACT_TAB - 1];	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)		return NULL;	if (rtattr_parse(tb2, TCA_ACT_MAX, RTA_DATA(tb[0]),			 RTA_PAYLOAD(tb[0])) < 0)		return NULL;	kind = tb2[TCA_ACT_KIND-1];	return kind;}static inttc_dump_action(struct sk_buff *skb, struct netlink_callback *cb){	struct nlmsghdr *nlh;	unsigned char *b = skb_tail_pointer(skb);	struct rtattr *x;	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);	if (kind == NULL) {		printk("tc_dump_action: action bad kind\n");		return 0;	}	a_o = tc_lookup_action(kind);	if (a_o == NULL) {		return 0;	}	memset(&a, 0, sizeof(struct tc_action));	a.ops = a_o;	if (a_o->walk == NULL) {		printk("tc_dump_action: %s !capable of dumping table\n", a_o->kind);		goto rtattr_failure;	}	nlh = NLMSG_PUT(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,			cb->nlh->nlmsg_type, sizeof(*t));	t = NLMSG_DATA(nlh);	t->tca_family = AF_UNSPEC;	t->tca__pad1 = 0;	t->tca__pad2 = 0;	x = (struct rtattr *)skb_tail_pointer(skb);	RTA_PUT(skb, TCA_ACT_TAB, 0, NULL);	ret = a_o->walk(skb, cb, RTM_GETACTION, &a);	if (ret < 0)		goto rtattr_failure;	if (ret > 0) {		x->rta_len = skb_tail_pointer(skb) - (u8 *)x;		ret = skb->len;	} else		nlmsg_trim(skb, x);	nlh->nlmsg_len = skb_tail_pointer(skb) - b;	if (NETLINK_CB(cb->skb).pid && ret)		nlh->nlmsg_flags |= NLM_F_MULTI;	module_put(a_o->owner);	return skb->len;rtattr_failure:nlmsg_failure:	module_put(a_o->owner);	nlmsg_trim(skb, b);	return skb->len;}static int __init tc_action_init(void){	rtnl_register(PF_UNSPEC, RTM_NEWACTION, tc_ctl_action, NULL);	rtnl_register(PF_UNSPEC, RTM_DELACTION, tc_ctl_action, NULL);	rtnl_register(PF_UNSPEC, RTM_GETACTION, tc_ctl_action, tc_dump_action);	return 0;}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);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?