0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 #include <net/tc_act/tc_gact.h>
0036 #include <net/tc_act/tc_mirred.h>
0037
0038 #include "cxgb4.h"
0039 #include "cxgb4_filter.h"
0040 #include "cxgb4_tc_u32_parse.h"
0041 #include "cxgb4_tc_u32.h"
0042
0043
0044 static int fill_match_fields(struct adapter *adap,
0045 struct ch_filter_specification *fs,
0046 struct tc_cls_u32_offload *cls,
0047 const struct cxgb4_match_field *entry,
0048 bool next_header)
0049 {
0050 unsigned int i, j;
0051 __be32 val, mask;
0052 int off, err;
0053 bool found;
0054
0055 for (i = 0; i < cls->knode.sel->nkeys; i++) {
0056 off = cls->knode.sel->keys[i].off;
0057 val = cls->knode.sel->keys[i].val;
0058 mask = cls->knode.sel->keys[i].mask;
0059
0060 if (next_header) {
0061
0062 if (!cls->knode.sel->keys[i].offmask)
0063 continue;
0064 } else {
0065
0066 if (cls->knode.sel->keys[i].offmask)
0067 continue;
0068 }
0069
0070 found = false;
0071
0072 for (j = 0; entry[j].val; j++) {
0073 if (off == entry[j].off) {
0074 found = true;
0075 err = entry[j].val(fs, val, mask);
0076 if (err)
0077 return err;
0078 break;
0079 }
0080 }
0081
0082 if (!found)
0083 return -EINVAL;
0084 }
0085
0086 return 0;
0087 }
0088
0089
0090 static int fill_action_fields(struct adapter *adap,
0091 struct ch_filter_specification *fs,
0092 struct tc_cls_u32_offload *cls)
0093 {
0094 unsigned int num_actions = 0;
0095 const struct tc_action *a;
0096 struct tcf_exts *exts;
0097 int i;
0098
0099 exts = cls->knode.exts;
0100 if (!tcf_exts_has_actions(exts))
0101 return -EINVAL;
0102
0103 tcf_exts_for_each_action(i, a, exts) {
0104
0105 if (num_actions)
0106 return -EINVAL;
0107
0108
0109 if (is_tcf_gact_shot(a)) {
0110 fs->action = FILTER_DROP;
0111 num_actions++;
0112 continue;
0113 }
0114
0115
0116 if (is_tcf_mirred_egress_redirect(a)) {
0117 struct net_device *n_dev, *target_dev;
0118 bool found = false;
0119 unsigned int i;
0120
0121 target_dev = tcf_mirred_dev(a);
0122 for_each_port(adap, i) {
0123 n_dev = adap->port[i];
0124 if (target_dev == n_dev) {
0125 fs->action = FILTER_SWITCH;
0126 fs->eport = i;
0127 found = true;
0128 break;
0129 }
0130 }
0131
0132
0133
0134
0135 if (!found)
0136 return -EINVAL;
0137
0138 num_actions++;
0139 continue;
0140 }
0141
0142
0143 return -EINVAL;
0144 }
0145
0146 return 0;
0147 }
0148
0149 int cxgb4_config_knode(struct net_device *dev, struct tc_cls_u32_offload *cls)
0150 {
0151 const struct cxgb4_match_field *start, *link_start = NULL;
0152 struct netlink_ext_ack *extack = cls->common.extack;
0153 struct adapter *adapter = netdev2adap(dev);
0154 __be16 protocol = cls->common.protocol;
0155 struct ch_filter_specification fs;
0156 struct cxgb4_tc_u32_table *t;
0157 struct cxgb4_link *link;
0158 u32 uhtid, link_uhtid;
0159 bool is_ipv6 = false;
0160 u8 inet_family;
0161 int filter_id;
0162 int ret;
0163
0164 if (!can_tc_u32_offload(dev))
0165 return -EOPNOTSUPP;
0166
0167 if (protocol != htons(ETH_P_IP) && protocol != htons(ETH_P_IPV6))
0168 return -EOPNOTSUPP;
0169
0170 inet_family = (protocol == htons(ETH_P_IPV6)) ? PF_INET6 : PF_INET;
0171
0172
0173
0174
0175
0176 filter_id = cxgb4_get_free_ftid(dev, inet_family, false,
0177 TC_U32_NODE(cls->knode.handle));
0178 if (filter_id < 0) {
0179 NL_SET_ERR_MSG_MOD(extack,
0180 "No free LETCAM index available");
0181 return -ENOMEM;
0182 }
0183
0184 t = adapter->tc_u32;
0185 uhtid = TC_U32_USERHTID(cls->knode.handle);
0186 link_uhtid = TC_U32_USERHTID(cls->knode.link_handle);
0187
0188
0189
0190
0191 if (uhtid != 0x800 && uhtid >= t->size)
0192 return -EINVAL;
0193
0194
0195 if (link_uhtid >= t->size)
0196 return -EINVAL;
0197
0198 memset(&fs, 0, sizeof(fs));
0199
0200 if (filter_id < adapter->tids.nhpftids)
0201 fs.prio = 1;
0202 fs.tc_prio = cls->common.prio;
0203 fs.tc_cookie = cls->knode.handle;
0204
0205 if (protocol == htons(ETH_P_IPV6)) {
0206 start = cxgb4_ipv6_fields;
0207 is_ipv6 = true;
0208 } else {
0209 start = cxgb4_ipv4_fields;
0210 is_ipv6 = false;
0211 }
0212
0213 if (uhtid != 0x800) {
0214
0215 if (!t->table[uhtid - 1].link_handle)
0216 return -EINVAL;
0217
0218
0219 link_start = t->table[uhtid - 1].match_field;
0220 if (!link_start)
0221 return -EINVAL;
0222 }
0223
0224
0225
0226
0227 if (link_uhtid) {
0228 const struct cxgb4_next_header *next;
0229 bool found = false;
0230 unsigned int i, j;
0231 __be32 val, mask;
0232 int off;
0233
0234 if (t->table[link_uhtid - 1].link_handle) {
0235 dev_err(adapter->pdev_dev,
0236 "Link handle exists for: 0x%x\n",
0237 link_uhtid);
0238 return -EINVAL;
0239 }
0240
0241 next = is_ipv6 ? cxgb4_ipv6_jumps : cxgb4_ipv4_jumps;
0242
0243
0244 for (i = 0; next[i].jump; i++) {
0245 if (next[i].sel.offoff != cls->knode.sel->offoff ||
0246 next[i].sel.offshift != cls->knode.sel->offshift ||
0247 next[i].sel.offmask != cls->knode.sel->offmask ||
0248 next[i].sel.off != cls->knode.sel->off)
0249 continue;
0250
0251
0252
0253
0254
0255 for (j = 0; j < cls->knode.sel->nkeys; j++) {
0256 off = cls->knode.sel->keys[j].off;
0257 val = cls->knode.sel->keys[j].val;
0258 mask = cls->knode.sel->keys[j].mask;
0259
0260 if (next[i].key.off == off &&
0261 next[i].key.val == val &&
0262 next[i].key.mask == mask) {
0263 found = true;
0264 break;
0265 }
0266 }
0267
0268 if (!found)
0269 continue;
0270
0271
0272
0273
0274
0275
0276 ret = fill_match_fields(adapter, &fs, cls,
0277 start, false);
0278 if (ret)
0279 goto out;
0280
0281 link = &t->table[link_uhtid - 1];
0282 link->match_field = next[i].jump;
0283 link->link_handle = cls->knode.handle;
0284 memcpy(&link->fs, &fs, sizeof(fs));
0285 break;
0286 }
0287
0288
0289 if (!found)
0290 return -EINVAL;
0291
0292 return 0;
0293 }
0294
0295
0296
0297
0298
0299 if (uhtid != 0x800 && t->table[uhtid - 1].link_handle) {
0300
0301 memcpy(&fs, &t->table[uhtid - 1].fs, sizeof(fs));
0302 ret = fill_match_fields(adapter, &fs, cls,
0303 link_start, true);
0304 if (ret)
0305 goto out;
0306 }
0307
0308 ret = fill_match_fields(adapter, &fs, cls, start, false);
0309 if (ret)
0310 goto out;
0311
0312
0313
0314
0315 ret = fill_action_fields(adapter, &fs, cls);
0316 if (ret)
0317 goto out;
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327 fs.val.iport = netdev2pinfo(dev)->port_id;
0328 fs.mask.iport = ~0;
0329
0330
0331 fs.hitcnts = 1;
0332
0333
0334 fs.type = is_ipv6 ? 1 : 0;
0335
0336
0337 ret = cxgb4_set_filter(dev, filter_id, &fs);
0338 if (ret)
0339 goto out;
0340
0341
0342
0343
0344
0345 if (uhtid != 0x800 && t->table[uhtid - 1].link_handle)
0346 set_bit(filter_id, t->table[uhtid - 1].tid_map);
0347
0348 out:
0349 return ret;
0350 }
0351
0352 int cxgb4_delete_knode(struct net_device *dev, struct tc_cls_u32_offload *cls)
0353 {
0354 struct adapter *adapter = netdev2adap(dev);
0355 unsigned int filter_id, max_tids, i, j;
0356 struct cxgb4_link *link = NULL;
0357 struct cxgb4_tc_u32_table *t;
0358 struct filter_entry *f;
0359 bool found = false;
0360 u32 handle, uhtid;
0361 u8 nslots;
0362 int ret;
0363
0364 if (!can_tc_u32_offload(dev))
0365 return -EOPNOTSUPP;
0366
0367
0368 max_tids = adapter->tids.nhpftids + adapter->tids.nftids;
0369
0370 spin_lock_bh(&adapter->tids.ftid_lock);
0371 filter_id = 0;
0372 while (filter_id < max_tids) {
0373 if (filter_id < adapter->tids.nhpftids) {
0374 i = filter_id;
0375 f = &adapter->tids.hpftid_tab[i];
0376 if (f->valid && f->fs.tc_cookie == cls->knode.handle) {
0377 found = true;
0378 break;
0379 }
0380
0381 i = find_next_bit(adapter->tids.hpftid_bmap,
0382 adapter->tids.nhpftids, i + 1);
0383 if (i >= adapter->tids.nhpftids) {
0384 filter_id = adapter->tids.nhpftids;
0385 continue;
0386 }
0387
0388 filter_id = i;
0389 } else {
0390 i = filter_id - adapter->tids.nhpftids;
0391 f = &adapter->tids.ftid_tab[i];
0392 if (f->valid && f->fs.tc_cookie == cls->knode.handle) {
0393 found = true;
0394 break;
0395 }
0396
0397 i = find_next_bit(adapter->tids.ftid_bmap,
0398 adapter->tids.nftids, i + 1);
0399 if (i >= adapter->tids.nftids)
0400 break;
0401
0402 filter_id = i + adapter->tids.nhpftids;
0403 }
0404
0405 nslots = 0;
0406 if (f->fs.type) {
0407 nslots++;
0408 if (CHELSIO_CHIP_VERSION(adapter->params.chip) <
0409 CHELSIO_T6)
0410 nslots += 2;
0411 }
0412
0413 filter_id += nslots;
0414 }
0415 spin_unlock_bh(&adapter->tids.ftid_lock);
0416
0417 if (!found)
0418 return -ERANGE;
0419
0420 t = adapter->tc_u32;
0421 handle = cls->knode.handle;
0422 uhtid = TC_U32_USERHTID(cls->knode.handle);
0423
0424
0425
0426
0427 if (uhtid != 0x800 && uhtid >= t->size)
0428 return -EINVAL;
0429
0430
0431 if (uhtid != 0x800) {
0432 link = &t->table[uhtid - 1];
0433 if (!link->link_handle)
0434 return -EINVAL;
0435
0436 if (!test_bit(filter_id, link->tid_map))
0437 return -EINVAL;
0438 }
0439
0440 ret = cxgb4_del_filter(dev, filter_id, NULL);
0441 if (ret)
0442 goto out;
0443
0444 if (link)
0445 clear_bit(filter_id, link->tid_map);
0446
0447
0448
0449
0450 for (i = 0; i < t->size; i++) {
0451 link = &t->table[i];
0452
0453 if (link->link_handle == handle) {
0454 for (j = 0; j < max_tids; j++) {
0455 if (!test_bit(j, link->tid_map))
0456 continue;
0457
0458 ret = __cxgb4_del_filter(dev, j, NULL, NULL);
0459 if (ret)
0460 goto out;
0461
0462 clear_bit(j, link->tid_map);
0463 }
0464
0465
0466 link->match_field = NULL;
0467 link->link_handle = 0;
0468 memset(&link->fs, 0, sizeof(link->fs));
0469 break;
0470 }
0471 }
0472
0473 out:
0474 return ret;
0475 }
0476
0477 void cxgb4_cleanup_tc_u32(struct adapter *adap)
0478 {
0479 struct cxgb4_tc_u32_table *t;
0480 unsigned int i;
0481
0482 if (!adap->tc_u32)
0483 return;
0484
0485
0486 t = adap->tc_u32;
0487 for (i = 0; i < t->size; i++) {
0488 struct cxgb4_link *link = &t->table[i];
0489
0490 kvfree(link->tid_map);
0491 }
0492 kvfree(adap->tc_u32);
0493 }
0494
0495 struct cxgb4_tc_u32_table *cxgb4_init_tc_u32(struct adapter *adap)
0496 {
0497 unsigned int max_tids = adap->tids.nftids + adap->tids.nhpftids;
0498 struct cxgb4_tc_u32_table *t;
0499 unsigned int i;
0500
0501 if (!max_tids)
0502 return NULL;
0503
0504 t = kvzalloc(struct_size(t, table, max_tids), GFP_KERNEL);
0505 if (!t)
0506 return NULL;
0507
0508 t->size = max_tids;
0509
0510 for (i = 0; i < t->size; i++) {
0511 struct cxgb4_link *link = &t->table[i];
0512 unsigned int bmap_size;
0513
0514 bmap_size = BITS_TO_LONGS(max_tids);
0515 link->tid_map = kvcalloc(bmap_size, sizeof(unsigned long),
0516 GFP_KERNEL);
0517 if (!link->tid_map)
0518 goto out_no_mem;
0519 bitmap_zero(link->tid_map, max_tids);
0520 }
0521
0522 return t;
0523
0524 out_no_mem:
0525 for (i = 0; i < t->size; i++) {
0526 struct cxgb4_link *link = &t->table[i];
0527 kvfree(link->tid_map);
0528 }
0529 kvfree(t);
0530
0531 return NULL;
0532 }