1 /* 2 * This file is part of the Chelsio T4 Ethernet driver for Linux. 3 * 4 * Copyright (c) 2016 Chelsio Communications, Inc. All rights reserved. 5 * 6 * This software is available to you under a choice of one of two 7 * licenses. You may choose to be licensed under the terms of the GNU 8 * General Public License (GPL) Version 2, available from the file 9 * COPYING in the main directory of this source tree, or the 10 * OpenIB.org BSD license below: 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer. 19 * 20 * - Redistributions in binary form must reproduce the above 21 * copyright notice, this list of conditions and the following 22 * disclaimer in the documentation and/or other materials 23 * provided with the distribution. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 * SOFTWARE. 33 */ 34 35 #include <net/tc_act/tc_gact.h> 36 #include <net/tc_act/tc_mirred.h> 37 38 #include "cxgb4.h" 39 #include "cxgb4_tc_u32_parse.h" 40 #include "cxgb4_tc_u32.h" 41 42 /* Fill ch_filter_specification with parsed match value/mask pair. */ 43 static int fill_match_fields(struct adapter *adap, 44 struct ch_filter_specification *fs, 45 struct tc_cls_u32_offload *cls, 46 const struct cxgb4_match_field *entry, 47 bool next_header) 48 { 49 unsigned int i, j; 50 u32 val, mask; 51 int off, err; 52 bool found; 53 54 for (i = 0; i < cls->knode.sel->nkeys; i++) { 55 off = cls->knode.sel->keys[i].off; 56 val = cls->knode.sel->keys[i].val; 57 mask = cls->knode.sel->keys[i].mask; 58 59 if (next_header) { 60 /* For next headers, parse only keys with offmask */ 61 if (!cls->knode.sel->keys[i].offmask) 62 continue; 63 } else { 64 /* For the remaining, parse only keys without offmask */ 65 if (cls->knode.sel->keys[i].offmask) 66 continue; 67 } 68 69 found = false; 70 71 for (j = 0; entry[j].val; j++) { 72 if (off == entry[j].off) { 73 found = true; 74 err = entry[j].val(fs, val, mask); 75 if (err) 76 return err; 77 break; 78 } 79 } 80 81 if (!found) 82 return -EINVAL; 83 } 84 85 return 0; 86 } 87 88 /* Fill ch_filter_specification with parsed action. */ 89 static int fill_action_fields(struct adapter *adap, 90 struct ch_filter_specification *fs, 91 struct tc_cls_u32_offload *cls) 92 { 93 unsigned int num_actions = 0; 94 const struct tc_action *a; 95 struct tcf_exts *exts; 96 LIST_HEAD(actions); 97 98 exts = cls->knode.exts; 99 if (tc_no_actions(exts)) 100 return -EINVAL; 101 102 tcf_exts_to_list(exts, &actions); 103 list_for_each_entry(a, &actions, list) { 104 /* Don't allow more than one action per rule. */ 105 if (num_actions) 106 return -EINVAL; 107 108 /* Drop in hardware. */ 109 if (is_tcf_gact_shot(a)) { 110 fs->action = FILTER_DROP; 111 num_actions++; 112 continue; 113 } 114 115 /* Re-direct to specified port in hardware. */ 116 if (is_tcf_mirred_egress_redirect(a)) { 117 struct net_device *n_dev; 118 unsigned int i, index; 119 bool found = false; 120 121 index = tcf_mirred_ifindex(a); 122 for_each_port(adap, i) { 123 n_dev = adap->port[i]; 124 if (index == n_dev->ifindex) { 125 fs->action = FILTER_SWITCH; 126 fs->eport = i; 127 found = true; 128 break; 129 } 130 } 131 132 /* Interface doesn't belong to any port of 133 * the underlying hardware. 134 */ 135 if (!found) 136 return -EINVAL; 137 138 num_actions++; 139 continue; 140 } 141 142 /* Un-supported action. */ 143 return -EINVAL; 144 } 145 146 return 0; 147 } 148 149 int cxgb4_config_knode(struct net_device *dev, __be16 protocol, 150 struct tc_cls_u32_offload *cls) 151 { 152 const struct cxgb4_match_field *start, *link_start = NULL; 153 struct adapter *adapter = netdev2adap(dev); 154 struct ch_filter_specification fs; 155 struct cxgb4_tc_u32_table *t; 156 struct cxgb4_link *link; 157 unsigned int filter_id; 158 u32 uhtid, link_uhtid; 159 bool is_ipv6 = false; 160 int ret; 161 162 if (!can_tc_u32_offload(dev)) 163 return -EOPNOTSUPP; 164 165 if (protocol != htons(ETH_P_IP) && protocol != htons(ETH_P_IPV6)) 166 return -EOPNOTSUPP; 167 168 /* Fetch the location to insert the filter. */ 169 filter_id = cls->knode.handle & 0xFFFFF; 170 171 if (filter_id > adapter->tids.nftids) { 172 dev_err(adapter->pdev_dev, 173 "Location %d out of range for insertion. Max: %d\n", 174 filter_id, adapter->tids.nftids); 175 return -ERANGE; 176 } 177 178 t = adapter->tc_u32; 179 uhtid = TC_U32_USERHTID(cls->knode.handle); 180 link_uhtid = TC_U32_USERHTID(cls->knode.link_handle); 181 182 /* Ensure that uhtid is either root u32 (i.e. 0x800) 183 * or a a valid linked bucket. 184 */ 185 if (uhtid != 0x800 && uhtid >= t->size) 186 return -EINVAL; 187 188 /* Ensure link handle uhtid is sane, if specified. */ 189 if (link_uhtid >= t->size) 190 return -EINVAL; 191 192 memset(&fs, 0, sizeof(fs)); 193 194 if (protocol == htons(ETH_P_IPV6)) { 195 start = cxgb4_ipv6_fields; 196 is_ipv6 = true; 197 } else { 198 start = cxgb4_ipv4_fields; 199 is_ipv6 = false; 200 } 201 202 if (uhtid != 0x800) { 203 /* Link must exist from root node before insertion. */ 204 if (!t->table[uhtid - 1].link_handle) 205 return -EINVAL; 206 207 /* Link must have a valid supported next header. */ 208 link_start = t->table[uhtid - 1].match_field; 209 if (!link_start) 210 return -EINVAL; 211 } 212 213 /* Parse links and record them for subsequent jumps to valid 214 * next headers. 215 */ 216 if (link_uhtid) { 217 const struct cxgb4_next_header *next; 218 bool found = false; 219 unsigned int i, j; 220 u32 val, mask; 221 int off; 222 223 if (t->table[link_uhtid - 1].link_handle) { 224 dev_err(adapter->pdev_dev, 225 "Link handle exists for: 0x%x\n", 226 link_uhtid); 227 return -EINVAL; 228 } 229 230 next = is_ipv6 ? cxgb4_ipv6_jumps : cxgb4_ipv4_jumps; 231 232 /* Try to find matches that allow jumps to next header. */ 233 for (i = 0; next[i].jump; i++) { 234 if (next[i].offoff != cls->knode.sel->offoff || 235 next[i].shift != cls->knode.sel->offshift || 236 next[i].mask != cls->knode.sel->offmask || 237 next[i].offset != cls->knode.sel->off) 238 continue; 239 240 /* Found a possible candidate. Find a key that 241 * matches the corresponding offset, value, and 242 * mask to jump to next header. 243 */ 244 for (j = 0; j < cls->knode.sel->nkeys; j++) { 245 off = cls->knode.sel->keys[j].off; 246 val = cls->knode.sel->keys[j].val; 247 mask = cls->knode.sel->keys[j].mask; 248 249 if (next[i].match_off == off && 250 next[i].match_val == val && 251 next[i].match_mask == mask) { 252 found = true; 253 break; 254 } 255 } 256 257 if (!found) 258 continue; /* Try next candidate. */ 259 260 /* Candidate to jump to next header found. 261 * Translate all keys to internal specification 262 * and store them in jump table. This spec is copied 263 * later to set the actual filters. 264 */ 265 ret = fill_match_fields(adapter, &fs, cls, 266 start, false); 267 if (ret) 268 goto out; 269 270 link = &t->table[link_uhtid - 1]; 271 link->match_field = next[i].jump; 272 link->link_handle = cls->knode.handle; 273 memcpy(&link->fs, &fs, sizeof(fs)); 274 break; 275 } 276 277 /* No candidate found to jump to next header. */ 278 if (!found) 279 return -EINVAL; 280 281 return 0; 282 } 283 284 /* Fill ch_filter_specification match fields to be shipped to hardware. 285 * Copy the linked spec (if any) first. And then update the spec as 286 * needed. 287 */ 288 if (uhtid != 0x800 && t->table[uhtid - 1].link_handle) { 289 /* Copy linked ch_filter_specification */ 290 memcpy(&fs, &t->table[uhtid - 1].fs, sizeof(fs)); 291 ret = fill_match_fields(adapter, &fs, cls, 292 link_start, true); 293 if (ret) 294 goto out; 295 } 296 297 ret = fill_match_fields(adapter, &fs, cls, start, false); 298 if (ret) 299 goto out; 300 301 /* Fill ch_filter_specification action fields to be shipped to 302 * hardware. 303 */ 304 ret = fill_action_fields(adapter, &fs, cls); 305 if (ret) 306 goto out; 307 308 /* The filter spec has been completely built from the info 309 * provided from u32. We now set some default fields in the 310 * spec for sanity. 311 */ 312 313 /* Match only packets coming from the ingress port where this 314 * filter will be created. 315 */ 316 fs.val.iport = netdev2pinfo(dev)->port_id; 317 fs.mask.iport = ~0; 318 319 /* Enable filter hit counts. */ 320 fs.hitcnts = 1; 321 322 /* Set type of filter - IPv6 or IPv4 */ 323 fs.type = is_ipv6 ? 1 : 0; 324 325 /* Set the filter */ 326 ret = cxgb4_set_filter(dev, filter_id, &fs); 327 if (ret) 328 goto out; 329 330 /* If this is a linked bucket, then set the corresponding 331 * entry in the bitmap to mark it as belonging to this linked 332 * bucket. 333 */ 334 if (uhtid != 0x800 && t->table[uhtid - 1].link_handle) 335 set_bit(filter_id, t->table[uhtid - 1].tid_map); 336 337 out: 338 return ret; 339 } 340 341 int cxgb4_delete_knode(struct net_device *dev, __be16 protocol, 342 struct tc_cls_u32_offload *cls) 343 { 344 struct adapter *adapter = netdev2adap(dev); 345 unsigned int filter_id, max_tids, i, j; 346 struct cxgb4_link *link = NULL; 347 struct cxgb4_tc_u32_table *t; 348 u32 handle, uhtid; 349 int ret; 350 351 if (!can_tc_u32_offload(dev)) 352 return -EOPNOTSUPP; 353 354 /* Fetch the location to delete the filter. */ 355 filter_id = cls->knode.handle & 0xFFFFF; 356 357 if (filter_id > adapter->tids.nftids) { 358 dev_err(adapter->pdev_dev, 359 "Location %d out of range for deletion. Max: %d\n", 360 filter_id, adapter->tids.nftids); 361 return -ERANGE; 362 } 363 364 t = adapter->tc_u32; 365 handle = cls->knode.handle; 366 uhtid = TC_U32_USERHTID(cls->knode.handle); 367 368 /* Ensure that uhtid is either root u32 (i.e. 0x800) 369 * or a a valid linked bucket. 370 */ 371 if (uhtid != 0x800 && uhtid >= t->size) 372 return -EINVAL; 373 374 /* Delete the specified filter */ 375 if (uhtid != 0x800) { 376 link = &t->table[uhtid - 1]; 377 if (!link->link_handle) 378 return -EINVAL; 379 380 if (!test_bit(filter_id, link->tid_map)) 381 return -EINVAL; 382 } 383 384 ret = cxgb4_del_filter(dev, filter_id); 385 if (ret) 386 goto out; 387 388 if (link) 389 clear_bit(filter_id, link->tid_map); 390 391 /* If a link is being deleted, then delete all filters 392 * associated with the link. 393 */ 394 max_tids = adapter->tids.nftids; 395 for (i = 0; i < t->size; i++) { 396 link = &t->table[i]; 397 398 if (link->link_handle == handle) { 399 for (j = 0; j < max_tids; j++) { 400 if (!test_bit(j, link->tid_map)) 401 continue; 402 403 ret = __cxgb4_del_filter(dev, j, NULL); 404 if (ret) 405 goto out; 406 407 clear_bit(j, link->tid_map); 408 } 409 410 /* Clear the link state */ 411 link->match_field = NULL; 412 link->link_handle = 0; 413 memset(&link->fs, 0, sizeof(link->fs)); 414 break; 415 } 416 } 417 418 out: 419 return ret; 420 } 421 422 void cxgb4_cleanup_tc_u32(struct adapter *adap) 423 { 424 struct cxgb4_tc_u32_table *t; 425 unsigned int i; 426 427 if (!adap->tc_u32) 428 return; 429 430 /* Free up all allocated memory. */ 431 t = adap->tc_u32; 432 for (i = 0; i < t->size; i++) { 433 struct cxgb4_link *link = &t->table[i]; 434 435 kvfree(link->tid_map); 436 } 437 kvfree(adap->tc_u32); 438 } 439 440 struct cxgb4_tc_u32_table *cxgb4_init_tc_u32(struct adapter *adap) 441 { 442 unsigned int max_tids = adap->tids.nftids; 443 struct cxgb4_tc_u32_table *t; 444 unsigned int i; 445 446 if (!max_tids) 447 return NULL; 448 449 t = kvzalloc(sizeof(*t) + 450 (max_tids * sizeof(struct cxgb4_link)), GFP_KERNEL); 451 if (!t) 452 return NULL; 453 454 t->size = max_tids; 455 456 for (i = 0; i < t->size; i++) { 457 struct cxgb4_link *link = &t->table[i]; 458 unsigned int bmap_size; 459 460 bmap_size = BITS_TO_LONGS(max_tids); 461 link->tid_map = kvzalloc(sizeof(unsigned long) * bmap_size, GFP_KERNEL); 462 if (!link->tid_map) 463 goto out_no_mem; 464 bitmap_zero(link->tid_map, max_tids); 465 } 466 467 return t; 468 469 out_no_mem: 470 for (i = 0; i < t->size; i++) { 471 struct cxgb4_link *link = &t->table[i]; 472 473 if (link->tid_map) 474 kvfree(link->tid_map); 475 } 476 477 if (t) 478 kvfree(t); 479 480 return NULL; 481 } 482