| .. | .. |
|---|
| 130 | 130 | return 0; |
|---|
| 131 | 131 | } |
|---|
| 132 | 132 | |
|---|
| 133 | +static int mqprio_parse_nlattr(struct Qdisc *sch, struct tc_mqprio_qopt *qopt, |
|---|
| 134 | + struct nlattr *opt, |
|---|
| 135 | + struct netlink_ext_ack *extack) |
|---|
| 136 | +{ |
|---|
| 137 | + struct mqprio_sched *priv = qdisc_priv(sch); |
|---|
| 138 | + struct nlattr *tb[TCA_MQPRIO_MAX + 1]; |
|---|
| 139 | + struct nlattr *attr; |
|---|
| 140 | + int i, rem, err; |
|---|
| 141 | + |
|---|
| 142 | + err = parse_attr(tb, TCA_MQPRIO_MAX, opt, mqprio_policy, |
|---|
| 143 | + sizeof(*qopt)); |
|---|
| 144 | + if (err < 0) |
|---|
| 145 | + return err; |
|---|
| 146 | + |
|---|
| 147 | + if (!qopt->hw) { |
|---|
| 148 | + NL_SET_ERR_MSG(extack, |
|---|
| 149 | + "mqprio TCA_OPTIONS can only contain netlink attributes in hardware mode"); |
|---|
| 150 | + return -EINVAL; |
|---|
| 151 | + } |
|---|
| 152 | + |
|---|
| 153 | + if (tb[TCA_MQPRIO_MODE]) { |
|---|
| 154 | + priv->flags |= TC_MQPRIO_F_MODE; |
|---|
| 155 | + priv->mode = *(u16 *)nla_data(tb[TCA_MQPRIO_MODE]); |
|---|
| 156 | + } |
|---|
| 157 | + |
|---|
| 158 | + if (tb[TCA_MQPRIO_SHAPER]) { |
|---|
| 159 | + priv->flags |= TC_MQPRIO_F_SHAPER; |
|---|
| 160 | + priv->shaper = *(u16 *)nla_data(tb[TCA_MQPRIO_SHAPER]); |
|---|
| 161 | + } |
|---|
| 162 | + |
|---|
| 163 | + if (tb[TCA_MQPRIO_MIN_RATE64]) { |
|---|
| 164 | + if (priv->shaper != TC_MQPRIO_SHAPER_BW_RATE) { |
|---|
| 165 | + NL_SET_ERR_MSG_ATTR(extack, tb[TCA_MQPRIO_MIN_RATE64], |
|---|
| 166 | + "min_rate accepted only when shaper is in bw_rlimit mode"); |
|---|
| 167 | + return -EINVAL; |
|---|
| 168 | + } |
|---|
| 169 | + i = 0; |
|---|
| 170 | + nla_for_each_nested(attr, tb[TCA_MQPRIO_MIN_RATE64], |
|---|
| 171 | + rem) { |
|---|
| 172 | + if (nla_type(attr) != TCA_MQPRIO_MIN_RATE64) { |
|---|
| 173 | + NL_SET_ERR_MSG_ATTR(extack, attr, |
|---|
| 174 | + "Attribute type expected to be TCA_MQPRIO_MIN_RATE64"); |
|---|
| 175 | + return -EINVAL; |
|---|
| 176 | + } |
|---|
| 177 | + |
|---|
| 178 | + if (nla_len(attr) != sizeof(u64)) { |
|---|
| 179 | + NL_SET_ERR_MSG_ATTR(extack, attr, |
|---|
| 180 | + "Attribute TCA_MQPRIO_MIN_RATE64 expected to have 8 bytes length"); |
|---|
| 181 | + return -EINVAL; |
|---|
| 182 | + } |
|---|
| 183 | + |
|---|
| 184 | + if (i >= qopt->num_tc) |
|---|
| 185 | + break; |
|---|
| 186 | + priv->min_rate[i] = *(u64 *)nla_data(attr); |
|---|
| 187 | + i++; |
|---|
| 188 | + } |
|---|
| 189 | + priv->flags |= TC_MQPRIO_F_MIN_RATE; |
|---|
| 190 | + } |
|---|
| 191 | + |
|---|
| 192 | + if (tb[TCA_MQPRIO_MAX_RATE64]) { |
|---|
| 193 | + if (priv->shaper != TC_MQPRIO_SHAPER_BW_RATE) { |
|---|
| 194 | + NL_SET_ERR_MSG_ATTR(extack, tb[TCA_MQPRIO_MAX_RATE64], |
|---|
| 195 | + "max_rate accepted only when shaper is in bw_rlimit mode"); |
|---|
| 196 | + return -EINVAL; |
|---|
| 197 | + } |
|---|
| 198 | + i = 0; |
|---|
| 199 | + nla_for_each_nested(attr, tb[TCA_MQPRIO_MAX_RATE64], |
|---|
| 200 | + rem) { |
|---|
| 201 | + if (nla_type(attr) != TCA_MQPRIO_MAX_RATE64) { |
|---|
| 202 | + NL_SET_ERR_MSG_ATTR(extack, attr, |
|---|
| 203 | + "Attribute type expected to be TCA_MQPRIO_MAX_RATE64"); |
|---|
| 204 | + return -EINVAL; |
|---|
| 205 | + } |
|---|
| 206 | + |
|---|
| 207 | + if (nla_len(attr) != sizeof(u64)) { |
|---|
| 208 | + NL_SET_ERR_MSG_ATTR(extack, attr, |
|---|
| 209 | + "Attribute TCA_MQPRIO_MAX_RATE64 expected to have 8 bytes length"); |
|---|
| 210 | + return -EINVAL; |
|---|
| 211 | + } |
|---|
| 212 | + |
|---|
| 213 | + if (i >= qopt->num_tc) |
|---|
| 214 | + break; |
|---|
| 215 | + priv->max_rate[i] = *(u64 *)nla_data(attr); |
|---|
| 216 | + i++; |
|---|
| 217 | + } |
|---|
| 218 | + priv->flags |= TC_MQPRIO_F_MAX_RATE; |
|---|
| 219 | + } |
|---|
| 220 | + |
|---|
| 221 | + return 0; |
|---|
| 222 | +} |
|---|
| 223 | + |
|---|
| 133 | 224 | static int mqprio_init(struct Qdisc *sch, struct nlattr *opt, |
|---|
| 134 | 225 | struct netlink_ext_ack *extack) |
|---|
| 135 | 226 | { |
|---|
| .. | .. |
|---|
| 139 | 230 | struct Qdisc *qdisc; |
|---|
| 140 | 231 | int i, err = -EOPNOTSUPP; |
|---|
| 141 | 232 | struct tc_mqprio_qopt *qopt = NULL; |
|---|
| 142 | | - struct nlattr *tb[TCA_MQPRIO_MAX + 1]; |
|---|
| 143 | | - struct nlattr *attr; |
|---|
| 144 | | - int rem; |
|---|
| 145 | 233 | int len; |
|---|
| 146 | 234 | |
|---|
| 147 | 235 | BUILD_BUG_ON(TC_MAX_QUEUE != TC_QOPT_MAX_QUEUE); |
|---|
| .. | .. |
|---|
| 166 | 254 | |
|---|
| 167 | 255 | len = nla_len(opt) - NLA_ALIGN(sizeof(*qopt)); |
|---|
| 168 | 256 | if (len > 0) { |
|---|
| 169 | | - err = parse_attr(tb, TCA_MQPRIO_MAX, opt, mqprio_policy, |
|---|
| 170 | | - sizeof(*qopt)); |
|---|
| 171 | | - if (err < 0) |
|---|
| 257 | + err = mqprio_parse_nlattr(sch, qopt, opt, extack); |
|---|
| 258 | + if (err) |
|---|
| 172 | 259 | return err; |
|---|
| 173 | | - |
|---|
| 174 | | - if (!qopt->hw) |
|---|
| 175 | | - return -EINVAL; |
|---|
| 176 | | - |
|---|
| 177 | | - if (tb[TCA_MQPRIO_MODE]) { |
|---|
| 178 | | - priv->flags |= TC_MQPRIO_F_MODE; |
|---|
| 179 | | - priv->mode = *(u16 *)nla_data(tb[TCA_MQPRIO_MODE]); |
|---|
| 180 | | - } |
|---|
| 181 | | - |
|---|
| 182 | | - if (tb[TCA_MQPRIO_SHAPER]) { |
|---|
| 183 | | - priv->flags |= TC_MQPRIO_F_SHAPER; |
|---|
| 184 | | - priv->shaper = *(u16 *)nla_data(tb[TCA_MQPRIO_SHAPER]); |
|---|
| 185 | | - } |
|---|
| 186 | | - |
|---|
| 187 | | - if (tb[TCA_MQPRIO_MIN_RATE64]) { |
|---|
| 188 | | - if (priv->shaper != TC_MQPRIO_SHAPER_BW_RATE) |
|---|
| 189 | | - return -EINVAL; |
|---|
| 190 | | - i = 0; |
|---|
| 191 | | - nla_for_each_nested(attr, tb[TCA_MQPRIO_MIN_RATE64], |
|---|
| 192 | | - rem) { |
|---|
| 193 | | - if (nla_type(attr) != TCA_MQPRIO_MIN_RATE64) |
|---|
| 194 | | - return -EINVAL; |
|---|
| 195 | | - if (i >= qopt->num_tc) |
|---|
| 196 | | - break; |
|---|
| 197 | | - priv->min_rate[i] = *(u64 *)nla_data(attr); |
|---|
| 198 | | - i++; |
|---|
| 199 | | - } |
|---|
| 200 | | - priv->flags |= TC_MQPRIO_F_MIN_RATE; |
|---|
| 201 | | - } |
|---|
| 202 | | - |
|---|
| 203 | | - if (tb[TCA_MQPRIO_MAX_RATE64]) { |
|---|
| 204 | | - if (priv->shaper != TC_MQPRIO_SHAPER_BW_RATE) |
|---|
| 205 | | - return -EINVAL; |
|---|
| 206 | | - i = 0; |
|---|
| 207 | | - nla_for_each_nested(attr, tb[TCA_MQPRIO_MAX_RATE64], |
|---|
| 208 | | - rem) { |
|---|
| 209 | | - if (nla_type(attr) != TCA_MQPRIO_MAX_RATE64) |
|---|
| 210 | | - return -EINVAL; |
|---|
| 211 | | - if (i >= qopt->num_tc) |
|---|
| 212 | | - break; |
|---|
| 213 | | - priv->max_rate[i] = *(u64 *)nla_data(attr); |
|---|
| 214 | | - i++; |
|---|
| 215 | | - } |
|---|
| 216 | | - priv->flags |= TC_MQPRIO_F_MAX_RATE; |
|---|
| 217 | | - } |
|---|
| 218 | 260 | } |
|---|
| 219 | 261 | |
|---|
| 220 | 262 | /* pre-allocate qdisc, attachment can't fail */ |
|---|