Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: sched: cls_u32: Undo tcf_bind_filter if u32_replace_hw_knode

When u32_replace_hw_knode fails, we need to undo the tcf_bind_filter
operation done at u32_set_parms.

Fixes: d34e3e181395 ("net: cls_u32: Add support for skip-sw flag to tc u32 classifier.")
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Reviewed-by: Pedro Tammela <pctammela@mojatatu.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Victor Nogueira and committed by
David S. Miller
9cb36fae b3d0e048

+30 -11
+30 -11
net/sched/cls_u32.c
··· 712 712 [TCA_U32_FLAGS] = { .type = NLA_U32 }, 713 713 }; 714 714 715 + static void u32_unbind_filter(struct tcf_proto *tp, struct tc_u_knode *n, 716 + struct nlattr **tb) 717 + { 718 + if (tb[TCA_U32_CLASSID]) 719 + tcf_unbind_filter(tp, &n->res); 720 + } 721 + 722 + static void u32_bind_filter(struct tcf_proto *tp, struct tc_u_knode *n, 723 + unsigned long base, struct nlattr **tb) 724 + { 725 + if (tb[TCA_U32_CLASSID]) { 726 + n->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]); 727 + tcf_bind_filter(tp, &n->res, base); 728 + } 729 + } 730 + 715 731 static int u32_set_parms(struct net *net, struct tcf_proto *tp, 716 - unsigned long base, 717 732 struct tc_u_knode *n, struct nlattr **tb, 718 733 struct nlattr *est, u32 flags, u32 fl_flags, 719 734 struct netlink_ext_ack *extack) ··· 774 759 775 760 if (ht_old) 776 761 ht_old->refcnt--; 777 - } 778 - if (tb[TCA_U32_CLASSID]) { 779 - n->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]); 780 - tcf_bind_filter(tp, &n->res, base); 781 762 } 782 763 783 764 if (ifindex >= 0) ··· 914 903 if (!new) 915 904 return -ENOMEM; 916 905 917 - err = u32_set_parms(net, tp, base, new, tb, 918 - tca[TCA_RATE], flags, new->flags, 919 - extack); 906 + err = u32_set_parms(net, tp, new, tb, tca[TCA_RATE], 907 + flags, new->flags, extack); 920 908 921 909 if (err) { 922 910 __u32_destroy_key(new); 923 911 return err; 924 912 } 925 913 914 + u32_bind_filter(tp, new, base, tb); 915 + 926 916 err = u32_replace_hw_knode(tp, new, flags, extack); 927 917 if (err) { 918 + u32_unbind_filter(tp, new, tb); 919 + 928 920 __u32_destroy_key(new); 929 921 return err; 930 922 } ··· 1088 1074 } 1089 1075 #endif 1090 1076 1091 - err = u32_set_parms(net, tp, base, n, tb, tca[TCA_RATE], 1077 + err = u32_set_parms(net, tp, n, tb, tca[TCA_RATE], 1092 1078 flags, n->flags, extack); 1079 + 1080 + u32_bind_filter(tp, n, base, tb); 1081 + 1093 1082 if (err == 0) { 1094 1083 struct tc_u_knode __rcu **ins; 1095 1084 struct tc_u_knode *pins; 1096 1085 1097 1086 err = u32_replace_hw_knode(tp, n, flags, extack); 1098 1087 if (err) 1099 - goto errhw; 1088 + goto errunbind; 1100 1089 1101 1090 if (!tc_in_hw(n->flags)) 1102 1091 n->flags |= TCA_CLS_FLAGS_NOT_IN_HW; ··· 1117 1100 return 0; 1118 1101 } 1119 1102 1120 - errhw: 1103 + errunbind: 1104 + u32_unbind_filter(tp, n, tb); 1105 + 1121 1106 #ifdef CONFIG_CLS_U32_MARK 1122 1107 free_percpu(n->pcpu_success); 1123 1108 #endif