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

sfc: Add support for retrieving and removing filters by ID

These new functions will support an implementation of the ethtool
RX NFC rules API.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Ben Hutchings and committed by
David S. Miller
1a6281ac 3532650f

+266
+12
drivers/net/ethernet/sfc/efx.h
··· 66 66 bool replace); 67 67 extern int efx_filter_remove_filter(struct efx_nic *efx, 68 68 struct efx_filter_spec *spec); 69 + extern int efx_filter_remove_id_safe(struct efx_nic *efx, 70 + enum efx_filter_priority priority, 71 + u32 filter_id); 72 + extern int efx_filter_get_filter_safe(struct efx_nic *efx, 73 + enum efx_filter_priority priority, 74 + u32 filter_id, struct efx_filter_spec *); 69 75 extern void efx_filter_clear_rx(struct efx_nic *efx, 70 76 enum efx_filter_priority priority); 77 + extern u32 efx_filter_count_rx_used(struct efx_nic *efx, 78 + enum efx_filter_priority priority); 79 + extern u32 efx_filter_get_rx_id_limit(struct efx_nic *efx); 80 + extern s32 efx_filter_get_rx_ids(struct efx_nic *efx, 81 + enum efx_filter_priority priority, 82 + u32 *buf, u32 size); 71 83 #ifdef CONFIG_RFS_ACCEL 72 84 extern int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, 73 85 u16 rxq_index, u32 flow_id);
+247
drivers/net/ethernet/sfc/filter.c
··· 155 155 spec->data[2] = ntohl(host2); 156 156 } 157 157 158 + static inline void __efx_filter_get_ipv4(const struct efx_filter_spec *spec, 159 + __be32 *host1, __be16 *port1, 160 + __be32 *host2, __be16 *port2) 161 + { 162 + *host1 = htonl(spec->data[0] >> 16 | spec->data[1] << 16); 163 + *port1 = htons(spec->data[0]); 164 + *host2 = htonl(spec->data[2]); 165 + *port2 = htons(spec->data[1] >> 16); 166 + } 167 + 158 168 /** 159 169 * efx_filter_set_ipv4_local - specify IPv4 host, transport protocol and port 160 170 * @spec: Specification to initialise ··· 215 205 return 0; 216 206 } 217 207 208 + int efx_filter_get_ipv4_local(const struct efx_filter_spec *spec, 209 + u8 *proto, __be32 *host, __be16 *port) 210 + { 211 + __be32 host1; 212 + __be16 port1; 213 + 214 + switch (spec->type) { 215 + case EFX_FILTER_TCP_WILD: 216 + *proto = IPPROTO_TCP; 217 + __efx_filter_get_ipv4(spec, &host1, &port1, host, port); 218 + return 0; 219 + case EFX_FILTER_UDP_WILD: 220 + *proto = IPPROTO_UDP; 221 + __efx_filter_get_ipv4(spec, &host1, port, host, &port1); 222 + return 0; 223 + default: 224 + return -EINVAL; 225 + } 226 + } 227 + 218 228 /** 219 229 * efx_filter_set_ipv4_full - specify IPv4 hosts, transport protocol and ports 220 230 * @spec: Specification to initialise ··· 272 242 return 0; 273 243 } 274 244 245 + int efx_filter_get_ipv4_full(const struct efx_filter_spec *spec, 246 + u8 *proto, __be32 *host, __be16 *port, 247 + __be32 *rhost, __be16 *rport) 248 + { 249 + switch (spec->type) { 250 + case EFX_FILTER_TCP_FULL: 251 + *proto = IPPROTO_TCP; 252 + break; 253 + case EFX_FILTER_UDP_FULL: 254 + *proto = IPPROTO_UDP; 255 + break; 256 + default: 257 + return -EINVAL; 258 + } 259 + 260 + __efx_filter_get_ipv4(spec, rhost, rport, host, port); 261 + return 0; 262 + } 263 + 275 264 /** 276 265 * efx_filter_set_eth_local - specify local Ethernet address and optional VID 277 266 * @spec: Specification to initialise ··· 316 267 317 268 spec->data[1] = addr[2] << 24 | addr[3] << 16 | addr[4] << 8 | addr[5]; 318 269 spec->data[2] = addr[0] << 8 | addr[1]; 270 + return 0; 271 + } 272 + 273 + int efx_filter_get_eth_local(const struct efx_filter_spec *spec, 274 + u16 *vid, u8 *addr) 275 + { 276 + switch (spec->type) { 277 + case EFX_FILTER_MAC_WILD: 278 + *vid = EFX_FILTER_VID_UNSPEC; 279 + break; 280 + case EFX_FILTER_MAC_FULL: 281 + *vid = spec->data[0]; 282 + break; 283 + default: 284 + return -EINVAL; 285 + } 286 + 287 + addr[0] = spec->data[2] >> 8; 288 + addr[1] = spec->data[2]; 289 + addr[2] = spec->data[1] >> 24; 290 + addr[3] = spec->data[1] >> 16; 291 + addr[4] = spec->data[1] >> 8; 292 + addr[5] = spec->data[1]; 319 293 return 0; 320 294 } 321 295 ··· 479 407 EFX_FILTER_FLAG_RX; 480 408 } 481 409 410 + u32 efx_filter_get_rx_id_limit(struct efx_nic *efx) 411 + { 412 + struct efx_filter_state *state = efx->filter_state; 413 + 414 + if (state->table[EFX_FILTER_TABLE_RX_MAC].size != 0) 415 + return ((EFX_FILTER_TABLE_RX_MAC + 1) << EFX_FILTER_INDEX_WIDTH) 416 + + state->table[EFX_FILTER_TABLE_RX_MAC].size; 417 + else if (state->table[EFX_FILTER_TABLE_RX_IP].size != 0) 418 + return ((EFX_FILTER_TABLE_RX_IP + 1) << EFX_FILTER_INDEX_WIDTH) 419 + + state->table[EFX_FILTER_TABLE_RX_IP].size; 420 + else 421 + return 0; 422 + } 423 + 482 424 /** 483 425 * efx_filter_insert_filter - add or replace a filter 484 426 * @efx: NIC in which to insert the filter ··· 582 496 } 583 497 584 498 /** 499 + * efx_filter_remove_id_safe - remove a filter by ID, carefully 500 + * @efx: NIC from which to remove the filter 501 + * @priority: Priority of filter, as passed to @efx_filter_insert_filter 502 + * @filter_id: ID of filter, as returned by @efx_filter_insert_filter 503 + * 504 + * This function will range-check @filter_id, so it is safe to call 505 + * with a value passed from userland. 506 + */ 507 + int efx_filter_remove_id_safe(struct efx_nic *efx, 508 + enum efx_filter_priority priority, 509 + u32 filter_id) 510 + { 511 + struct efx_filter_state *state = efx->filter_state; 512 + enum efx_filter_table_id table_id; 513 + struct efx_filter_table *table; 514 + unsigned int filter_idx; 515 + struct efx_filter_spec *spec; 516 + u8 filter_flags; 517 + int rc; 518 + 519 + table_id = efx_filter_id_table_id(filter_id); 520 + if ((unsigned int)table_id >= EFX_FILTER_TABLE_COUNT) 521 + return -ENOENT; 522 + table = &state->table[table_id]; 523 + 524 + filter_idx = efx_filter_id_index(filter_id); 525 + if (filter_idx >= table->size) 526 + return -ENOENT; 527 + spec = &table->spec[filter_idx]; 528 + 529 + filter_flags = efx_filter_id_flags(filter_id); 530 + 531 + spin_lock_bh(&state->lock); 532 + 533 + if (test_bit(filter_idx, table->used_bitmap) && 534 + spec->priority == priority && spec->flags == filter_flags) { 535 + efx_filter_table_clear_entry(efx, table, filter_idx); 536 + if (table->used == 0) 537 + efx_filter_table_reset_search_depth(table); 538 + rc = 0; 539 + } else { 540 + rc = -ENOENT; 541 + } 542 + 543 + spin_unlock_bh(&state->lock); 544 + 545 + return rc; 546 + } 547 + 548 + /** 549 + * efx_filter_get_filter_safe - retrieve a filter by ID, carefully 550 + * @efx: NIC from which to remove the filter 551 + * @priority: Priority of filter, as passed to @efx_filter_insert_filter 552 + * @filter_id: ID of filter, as returned by @efx_filter_insert_filter 553 + * @spec: Buffer in which to store filter specification 554 + * 555 + * This function will range-check @filter_id, so it is safe to call 556 + * with a value passed from userland. 557 + */ 558 + int efx_filter_get_filter_safe(struct efx_nic *efx, 559 + enum efx_filter_priority priority, 560 + u32 filter_id, struct efx_filter_spec *spec_buf) 561 + { 562 + struct efx_filter_state *state = efx->filter_state; 563 + enum efx_filter_table_id table_id; 564 + struct efx_filter_table *table; 565 + struct efx_filter_spec *spec; 566 + unsigned int filter_idx; 567 + u8 filter_flags; 568 + int rc; 569 + 570 + table_id = efx_filter_id_table_id(filter_id); 571 + if ((unsigned int)table_id >= EFX_FILTER_TABLE_COUNT) 572 + return -ENOENT; 573 + table = &state->table[table_id]; 574 + 575 + filter_idx = efx_filter_id_index(filter_id); 576 + if (filter_idx >= table->size) 577 + return -ENOENT; 578 + spec = &table->spec[filter_idx]; 579 + 580 + filter_flags = efx_filter_id_flags(filter_id); 581 + 582 + spin_lock_bh(&state->lock); 583 + 584 + if (test_bit(filter_idx, table->used_bitmap) && 585 + spec->priority == priority && spec->flags == filter_flags) { 586 + *spec_buf = *spec; 587 + rc = 0; 588 + } else { 589 + rc = -ENOENT; 590 + } 591 + 592 + spin_unlock_bh(&state->lock); 593 + 594 + return rc; 595 + } 596 + 597 + /** 585 598 * efx_filter_remove_filter - remove a filter by specification 586 599 * @efx: NIC from which to remove the filter 587 600 * @spec: Specification for the filter ··· 754 569 { 755 570 efx_filter_table_clear(efx, EFX_FILTER_TABLE_RX_IP, priority); 756 571 efx_filter_table_clear(efx, EFX_FILTER_TABLE_RX_MAC, priority); 572 + } 573 + 574 + u32 efx_filter_count_rx_used(struct efx_nic *efx, 575 + enum efx_filter_priority priority) 576 + { 577 + struct efx_filter_state *state = efx->filter_state; 578 + enum efx_filter_table_id table_id; 579 + struct efx_filter_table *table; 580 + unsigned int filter_idx; 581 + u32 count = 0; 582 + 583 + spin_lock_bh(&state->lock); 584 + 585 + for (table_id = EFX_FILTER_TABLE_RX_IP; 586 + table_id <= EFX_FILTER_TABLE_RX_MAC; 587 + table_id++) { 588 + table = &state->table[table_id]; 589 + for (filter_idx = 0; filter_idx < table->size; filter_idx++) { 590 + if (test_bit(filter_idx, table->used_bitmap) && 591 + table->spec[filter_idx].priority == priority) 592 + ++count; 593 + } 594 + } 595 + 596 + spin_unlock_bh(&state->lock); 597 + 598 + return count; 599 + } 600 + 601 + s32 efx_filter_get_rx_ids(struct efx_nic *efx, 602 + enum efx_filter_priority priority, 603 + u32 *buf, u32 size) 604 + { 605 + struct efx_filter_state *state = efx->filter_state; 606 + enum efx_filter_table_id table_id; 607 + struct efx_filter_table *table; 608 + unsigned int filter_idx; 609 + s32 count = 0; 610 + 611 + spin_lock_bh(&state->lock); 612 + 613 + for (table_id = EFX_FILTER_TABLE_RX_IP; 614 + table_id <= EFX_FILTER_TABLE_RX_MAC; 615 + table_id++) { 616 + table = &state->table[table_id]; 617 + for (filter_idx = 0; filter_idx < table->size; filter_idx++) { 618 + if (test_bit(filter_idx, table->used_bitmap) && 619 + table->spec[filter_idx].priority == priority) { 620 + if (count == size) { 621 + count = -EMSGSIZE; 622 + goto out; 623 + } 624 + buf[count++] = efx_filter_make_id( 625 + table_id, filter_idx, 626 + table->spec[filter_idx].flags); 627 + } 628 + } 629 + } 630 + out: 631 + spin_unlock_bh(&state->lock); 632 + 633 + return count; 757 634 } 758 635 759 636 /* Restore filter stater after reset */
+7
drivers/net/ethernet/sfc/filter.h
··· 105 105 106 106 extern int efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto, 107 107 __be32 host, __be16 port); 108 + extern int efx_filter_get_ipv4_local(const struct efx_filter_spec *spec, 109 + u8 *proto, __be32 *host, __be16 *port); 108 110 extern int efx_filter_set_ipv4_full(struct efx_filter_spec *spec, u8 proto, 109 111 __be32 host, __be16 port, 110 112 __be32 rhost, __be16 rport); 113 + extern int efx_filter_get_ipv4_full(const struct efx_filter_spec *spec, 114 + u8 *proto, __be32 *host, __be16 *port, 115 + __be32 *rhost, __be16 *rport); 111 116 extern int efx_filter_set_eth_local(struct efx_filter_spec *spec, 112 117 u16 vid, const u8 *addr); 118 + extern int efx_filter_get_eth_local(const struct efx_filter_spec *spec, 119 + u16 *vid, u8 *addr); 113 120 enum { 114 121 EFX_FILTER_VID_UNSPEC = 0xffff, 115 122 };