12e8aad7bSRahul Lakkireddy /* 22e8aad7bSRahul Lakkireddy * This file is part of the Chelsio T4 Ethernet driver for Linux. 32e8aad7bSRahul Lakkireddy * 42e8aad7bSRahul Lakkireddy * Copyright (c) 2016 Chelsio Communications, Inc. All rights reserved. 52e8aad7bSRahul Lakkireddy * 62e8aad7bSRahul Lakkireddy * This software is available to you under a choice of one of two 72e8aad7bSRahul Lakkireddy * licenses. You may choose to be licensed under the terms of the GNU 82e8aad7bSRahul Lakkireddy * General Public License (GPL) Version 2, available from the file 92e8aad7bSRahul Lakkireddy * COPYING in the main directory of this source tree, or the 102e8aad7bSRahul Lakkireddy * OpenIB.org BSD license below: 112e8aad7bSRahul Lakkireddy * 122e8aad7bSRahul Lakkireddy * Redistribution and use in source and binary forms, with or 132e8aad7bSRahul Lakkireddy * without modification, are permitted provided that the following 142e8aad7bSRahul Lakkireddy * conditions are met: 152e8aad7bSRahul Lakkireddy * 162e8aad7bSRahul Lakkireddy * - Redistributions of source code must retain the above 172e8aad7bSRahul Lakkireddy * copyright notice, this list of conditions and the following 182e8aad7bSRahul Lakkireddy * disclaimer. 192e8aad7bSRahul Lakkireddy * 202e8aad7bSRahul Lakkireddy * - Redistributions in binary form must reproduce the above 212e8aad7bSRahul Lakkireddy * copyright notice, this list of conditions and the following 222e8aad7bSRahul Lakkireddy * disclaimer in the documentation and/or other materials 232e8aad7bSRahul Lakkireddy * provided with the distribution. 242e8aad7bSRahul Lakkireddy * 252e8aad7bSRahul Lakkireddy * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 262e8aad7bSRahul Lakkireddy * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 272e8aad7bSRahul Lakkireddy * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 282e8aad7bSRahul Lakkireddy * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 292e8aad7bSRahul Lakkireddy * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 302e8aad7bSRahul Lakkireddy * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 312e8aad7bSRahul Lakkireddy * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 322e8aad7bSRahul Lakkireddy * SOFTWARE. 332e8aad7bSRahul Lakkireddy */ 342e8aad7bSRahul Lakkireddy 352e8aad7bSRahul Lakkireddy #ifndef __CXGB4_TC_U32_PARSE_H 362e8aad7bSRahul Lakkireddy #define __CXGB4_TC_U32_PARSE_H 372e8aad7bSRahul Lakkireddy 382e8aad7bSRahul Lakkireddy struct cxgb4_match_field { 392e8aad7bSRahul Lakkireddy int off; /* Offset from the beginning of the header to match */ 402e8aad7bSRahul Lakkireddy /* Fill the value/mask pair in the spec if matched */ 412e8aad7bSRahul Lakkireddy int (*val)(struct ch_filter_specification *f, u32 val, u32 mask); 422e8aad7bSRahul Lakkireddy }; 432e8aad7bSRahul Lakkireddy 442e8aad7bSRahul Lakkireddy /* IPv4 match fields */ 452e8aad7bSRahul Lakkireddy static inline int cxgb4_fill_ipv4_tos(struct ch_filter_specification *f, 462e8aad7bSRahul Lakkireddy u32 val, u32 mask) 472e8aad7bSRahul Lakkireddy { 482e8aad7bSRahul Lakkireddy f->val.tos = (ntohl(val) >> 16) & 0x000000FF; 492e8aad7bSRahul Lakkireddy f->mask.tos = (ntohl(mask) >> 16) & 0x000000FF; 502e8aad7bSRahul Lakkireddy 512e8aad7bSRahul Lakkireddy return 0; 522e8aad7bSRahul Lakkireddy } 532e8aad7bSRahul Lakkireddy 542e8aad7bSRahul Lakkireddy static inline int cxgb4_fill_ipv4_frag(struct ch_filter_specification *f, 552e8aad7bSRahul Lakkireddy u32 val, u32 mask) 562e8aad7bSRahul Lakkireddy { 572e8aad7bSRahul Lakkireddy u32 mask_val; 582e8aad7bSRahul Lakkireddy u8 frag_val; 592e8aad7bSRahul Lakkireddy 602e8aad7bSRahul Lakkireddy frag_val = (ntohl(val) >> 13) & 0x00000007; 612e8aad7bSRahul Lakkireddy mask_val = ntohl(mask) & 0x0000FFFF; 622e8aad7bSRahul Lakkireddy 632e8aad7bSRahul Lakkireddy if (frag_val == 0x1 && mask_val != 0x3FFF) { /* MF set */ 642e8aad7bSRahul Lakkireddy f->val.frag = 1; 652e8aad7bSRahul Lakkireddy f->mask.frag = 1; 662e8aad7bSRahul Lakkireddy } else if (frag_val == 0x2 && mask_val != 0x3FFF) { /* DF set */ 672e8aad7bSRahul Lakkireddy f->val.frag = 0; 682e8aad7bSRahul Lakkireddy f->mask.frag = 1; 692e8aad7bSRahul Lakkireddy } else { 702e8aad7bSRahul Lakkireddy return -EINVAL; 712e8aad7bSRahul Lakkireddy } 722e8aad7bSRahul Lakkireddy 732e8aad7bSRahul Lakkireddy return 0; 742e8aad7bSRahul Lakkireddy } 752e8aad7bSRahul Lakkireddy 762e8aad7bSRahul Lakkireddy static inline int cxgb4_fill_ipv4_proto(struct ch_filter_specification *f, 772e8aad7bSRahul Lakkireddy u32 val, u32 mask) 782e8aad7bSRahul Lakkireddy { 792e8aad7bSRahul Lakkireddy f->val.proto = (ntohl(val) >> 16) & 0x000000FF; 802e8aad7bSRahul Lakkireddy f->mask.proto = (ntohl(mask) >> 16) & 0x000000FF; 812e8aad7bSRahul Lakkireddy 822e8aad7bSRahul Lakkireddy return 0; 832e8aad7bSRahul Lakkireddy } 842e8aad7bSRahul Lakkireddy 852e8aad7bSRahul Lakkireddy static inline int cxgb4_fill_ipv4_src_ip(struct ch_filter_specification *f, 862e8aad7bSRahul Lakkireddy u32 val, u32 mask) 872e8aad7bSRahul Lakkireddy { 882e8aad7bSRahul Lakkireddy memcpy(&f->val.fip[0], &val, sizeof(u32)); 892e8aad7bSRahul Lakkireddy memcpy(&f->mask.fip[0], &mask, sizeof(u32)); 902e8aad7bSRahul Lakkireddy 912e8aad7bSRahul Lakkireddy return 0; 922e8aad7bSRahul Lakkireddy } 932e8aad7bSRahul Lakkireddy 942e8aad7bSRahul Lakkireddy static inline int cxgb4_fill_ipv4_dst_ip(struct ch_filter_specification *f, 952e8aad7bSRahul Lakkireddy u32 val, u32 mask) 962e8aad7bSRahul Lakkireddy { 972e8aad7bSRahul Lakkireddy memcpy(&f->val.lip[0], &val, sizeof(u32)); 982e8aad7bSRahul Lakkireddy memcpy(&f->mask.lip[0], &mask, sizeof(u32)); 992e8aad7bSRahul Lakkireddy 1002e8aad7bSRahul Lakkireddy return 0; 1012e8aad7bSRahul Lakkireddy } 1022e8aad7bSRahul Lakkireddy 1032e8aad7bSRahul Lakkireddy static const struct cxgb4_match_field cxgb4_ipv4_fields[] = { 1042e8aad7bSRahul Lakkireddy { .off = 0, .val = cxgb4_fill_ipv4_tos }, 1052e8aad7bSRahul Lakkireddy { .off = 4, .val = cxgb4_fill_ipv4_frag }, 1062e8aad7bSRahul Lakkireddy { .off = 8, .val = cxgb4_fill_ipv4_proto }, 1072e8aad7bSRahul Lakkireddy { .off = 12, .val = cxgb4_fill_ipv4_src_ip }, 1082e8aad7bSRahul Lakkireddy { .off = 16, .val = cxgb4_fill_ipv4_dst_ip }, 1092e8aad7bSRahul Lakkireddy { .val = NULL } 1102e8aad7bSRahul Lakkireddy }; 1112e8aad7bSRahul Lakkireddy 1122e8aad7bSRahul Lakkireddy /* IPv6 match fields */ 1132e8aad7bSRahul Lakkireddy static inline int cxgb4_fill_ipv6_tos(struct ch_filter_specification *f, 1142e8aad7bSRahul Lakkireddy u32 val, u32 mask) 1152e8aad7bSRahul Lakkireddy { 1162e8aad7bSRahul Lakkireddy f->val.tos = (ntohl(val) >> 20) & 0x000000FF; 1172e8aad7bSRahul Lakkireddy f->mask.tos = (ntohl(mask) >> 20) & 0x000000FF; 1182e8aad7bSRahul Lakkireddy 1192e8aad7bSRahul Lakkireddy return 0; 1202e8aad7bSRahul Lakkireddy } 1212e8aad7bSRahul Lakkireddy 1222e8aad7bSRahul Lakkireddy static inline int cxgb4_fill_ipv6_proto(struct ch_filter_specification *f, 1232e8aad7bSRahul Lakkireddy u32 val, u32 mask) 1242e8aad7bSRahul Lakkireddy { 1252e8aad7bSRahul Lakkireddy f->val.proto = (ntohl(val) >> 8) & 0x000000FF; 1262e8aad7bSRahul Lakkireddy f->mask.proto = (ntohl(mask) >> 8) & 0x000000FF; 1272e8aad7bSRahul Lakkireddy 1282e8aad7bSRahul Lakkireddy return 0; 1292e8aad7bSRahul Lakkireddy } 1302e8aad7bSRahul Lakkireddy 1312e8aad7bSRahul Lakkireddy static inline int cxgb4_fill_ipv6_src_ip0(struct ch_filter_specification *f, 1322e8aad7bSRahul Lakkireddy u32 val, u32 mask) 1332e8aad7bSRahul Lakkireddy { 1342e8aad7bSRahul Lakkireddy memcpy(&f->val.fip[0], &val, sizeof(u32)); 1352e8aad7bSRahul Lakkireddy memcpy(&f->mask.fip[0], &mask, sizeof(u32)); 1362e8aad7bSRahul Lakkireddy 1372e8aad7bSRahul Lakkireddy return 0; 1382e8aad7bSRahul Lakkireddy } 1392e8aad7bSRahul Lakkireddy 1402e8aad7bSRahul Lakkireddy static inline int cxgb4_fill_ipv6_src_ip1(struct ch_filter_specification *f, 1412e8aad7bSRahul Lakkireddy u32 val, u32 mask) 1422e8aad7bSRahul Lakkireddy { 1432e8aad7bSRahul Lakkireddy memcpy(&f->val.fip[4], &val, sizeof(u32)); 1442e8aad7bSRahul Lakkireddy memcpy(&f->mask.fip[4], &mask, sizeof(u32)); 1452e8aad7bSRahul Lakkireddy 1462e8aad7bSRahul Lakkireddy return 0; 1472e8aad7bSRahul Lakkireddy } 1482e8aad7bSRahul Lakkireddy 1492e8aad7bSRahul Lakkireddy static inline int cxgb4_fill_ipv6_src_ip2(struct ch_filter_specification *f, 1502e8aad7bSRahul Lakkireddy u32 val, u32 mask) 1512e8aad7bSRahul Lakkireddy { 1522e8aad7bSRahul Lakkireddy memcpy(&f->val.fip[8], &val, sizeof(u32)); 1532e8aad7bSRahul Lakkireddy memcpy(&f->mask.fip[8], &mask, sizeof(u32)); 1542e8aad7bSRahul Lakkireddy 1552e8aad7bSRahul Lakkireddy return 0; 1562e8aad7bSRahul Lakkireddy } 1572e8aad7bSRahul Lakkireddy 1582e8aad7bSRahul Lakkireddy static inline int cxgb4_fill_ipv6_src_ip3(struct ch_filter_specification *f, 1592e8aad7bSRahul Lakkireddy u32 val, u32 mask) 1602e8aad7bSRahul Lakkireddy { 1612e8aad7bSRahul Lakkireddy memcpy(&f->val.fip[12], &val, sizeof(u32)); 1622e8aad7bSRahul Lakkireddy memcpy(&f->mask.fip[12], &mask, sizeof(u32)); 1632e8aad7bSRahul Lakkireddy 1642e8aad7bSRahul Lakkireddy return 0; 1652e8aad7bSRahul Lakkireddy } 1662e8aad7bSRahul Lakkireddy 1672e8aad7bSRahul Lakkireddy static inline int cxgb4_fill_ipv6_dst_ip0(struct ch_filter_specification *f, 1682e8aad7bSRahul Lakkireddy u32 val, u32 mask) 1692e8aad7bSRahul Lakkireddy { 1702e8aad7bSRahul Lakkireddy memcpy(&f->val.lip[0], &val, sizeof(u32)); 1712e8aad7bSRahul Lakkireddy memcpy(&f->mask.lip[0], &mask, sizeof(u32)); 1722e8aad7bSRahul Lakkireddy 1732e8aad7bSRahul Lakkireddy return 0; 1742e8aad7bSRahul Lakkireddy } 1752e8aad7bSRahul Lakkireddy 1762e8aad7bSRahul Lakkireddy static inline int cxgb4_fill_ipv6_dst_ip1(struct ch_filter_specification *f, 1772e8aad7bSRahul Lakkireddy u32 val, u32 mask) 1782e8aad7bSRahul Lakkireddy { 1792e8aad7bSRahul Lakkireddy memcpy(&f->val.lip[4], &val, sizeof(u32)); 1802e8aad7bSRahul Lakkireddy memcpy(&f->mask.lip[4], &mask, sizeof(u32)); 1812e8aad7bSRahul Lakkireddy 1822e8aad7bSRahul Lakkireddy return 0; 1832e8aad7bSRahul Lakkireddy } 1842e8aad7bSRahul Lakkireddy 1852e8aad7bSRahul Lakkireddy static inline int cxgb4_fill_ipv6_dst_ip2(struct ch_filter_specification *f, 1862e8aad7bSRahul Lakkireddy u32 val, u32 mask) 1872e8aad7bSRahul Lakkireddy { 1882e8aad7bSRahul Lakkireddy memcpy(&f->val.lip[8], &val, sizeof(u32)); 1892e8aad7bSRahul Lakkireddy memcpy(&f->mask.lip[8], &mask, sizeof(u32)); 1902e8aad7bSRahul Lakkireddy 1912e8aad7bSRahul Lakkireddy return 0; 1922e8aad7bSRahul Lakkireddy } 1932e8aad7bSRahul Lakkireddy 1942e8aad7bSRahul Lakkireddy static inline int cxgb4_fill_ipv6_dst_ip3(struct ch_filter_specification *f, 1952e8aad7bSRahul Lakkireddy u32 val, u32 mask) 1962e8aad7bSRahul Lakkireddy { 1972e8aad7bSRahul Lakkireddy memcpy(&f->val.lip[12], &val, sizeof(u32)); 1982e8aad7bSRahul Lakkireddy memcpy(&f->mask.lip[12], &mask, sizeof(u32)); 1992e8aad7bSRahul Lakkireddy 2002e8aad7bSRahul Lakkireddy return 0; 2012e8aad7bSRahul Lakkireddy } 2022e8aad7bSRahul Lakkireddy 2032e8aad7bSRahul Lakkireddy static const struct cxgb4_match_field cxgb4_ipv6_fields[] = { 2042e8aad7bSRahul Lakkireddy { .off = 0, .val = cxgb4_fill_ipv6_tos }, 2052e8aad7bSRahul Lakkireddy { .off = 4, .val = cxgb4_fill_ipv6_proto }, 2062e8aad7bSRahul Lakkireddy { .off = 8, .val = cxgb4_fill_ipv6_src_ip0 }, 2072e8aad7bSRahul Lakkireddy { .off = 12, .val = cxgb4_fill_ipv6_src_ip1 }, 2082e8aad7bSRahul Lakkireddy { .off = 16, .val = cxgb4_fill_ipv6_src_ip2 }, 2092e8aad7bSRahul Lakkireddy { .off = 20, .val = cxgb4_fill_ipv6_src_ip3 }, 2102e8aad7bSRahul Lakkireddy { .off = 24, .val = cxgb4_fill_ipv6_dst_ip0 }, 2112e8aad7bSRahul Lakkireddy { .off = 28, .val = cxgb4_fill_ipv6_dst_ip1 }, 2122e8aad7bSRahul Lakkireddy { .off = 32, .val = cxgb4_fill_ipv6_dst_ip2 }, 2132e8aad7bSRahul Lakkireddy { .off = 36, .val = cxgb4_fill_ipv6_dst_ip3 }, 2142e8aad7bSRahul Lakkireddy { .val = NULL } 2152e8aad7bSRahul Lakkireddy }; 2162e8aad7bSRahul Lakkireddy 2172e8aad7bSRahul Lakkireddy /* TCP/UDP match */ 2182e8aad7bSRahul Lakkireddy static inline int cxgb4_fill_l4_ports(struct ch_filter_specification *f, 2192e8aad7bSRahul Lakkireddy u32 val, u32 mask) 2202e8aad7bSRahul Lakkireddy { 2212e8aad7bSRahul Lakkireddy f->val.fport = ntohl(val) >> 16; 2222e8aad7bSRahul Lakkireddy f->mask.fport = ntohl(mask) >> 16; 2232e8aad7bSRahul Lakkireddy f->val.lport = ntohl(val) & 0x0000FFFF; 2242e8aad7bSRahul Lakkireddy f->mask.lport = ntohl(mask) & 0x0000FFFF; 2252e8aad7bSRahul Lakkireddy 2262e8aad7bSRahul Lakkireddy return 0; 2272e8aad7bSRahul Lakkireddy }; 2282e8aad7bSRahul Lakkireddy 2292e8aad7bSRahul Lakkireddy static const struct cxgb4_match_field cxgb4_tcp_fields[] = { 2302e8aad7bSRahul Lakkireddy { .off = 0, .val = cxgb4_fill_l4_ports }, 2312e8aad7bSRahul Lakkireddy { .val = NULL } 2322e8aad7bSRahul Lakkireddy }; 2332e8aad7bSRahul Lakkireddy 2342e8aad7bSRahul Lakkireddy static const struct cxgb4_match_field cxgb4_udp_fields[] = { 2352e8aad7bSRahul Lakkireddy { .off = 0, .val = cxgb4_fill_l4_ports }, 2362e8aad7bSRahul Lakkireddy { .val = NULL } 2372e8aad7bSRahul Lakkireddy }; 2382e8aad7bSRahul Lakkireddy 2392e8aad7bSRahul Lakkireddy struct cxgb4_next_header { 2402e8aad7bSRahul Lakkireddy unsigned int offset; /* Offset to next header */ 2412e8aad7bSRahul Lakkireddy /* offset, shift, and mask added to offset above 2422e8aad7bSRahul Lakkireddy * to get to next header. Useful when using a header 2432e8aad7bSRahul Lakkireddy * field's value to jump to next header such as IHL field 2442e8aad7bSRahul Lakkireddy * in IPv4 header. 2452e8aad7bSRahul Lakkireddy */ 2462e8aad7bSRahul Lakkireddy unsigned int offoff; 2472e8aad7bSRahul Lakkireddy u32 shift; 2482e8aad7bSRahul Lakkireddy u32 mask; 2492e8aad7bSRahul Lakkireddy /* match criteria to make this jump */ 2502e8aad7bSRahul Lakkireddy unsigned int match_off; 2512e8aad7bSRahul Lakkireddy u32 match_val; 2522e8aad7bSRahul Lakkireddy u32 match_mask; 2532e8aad7bSRahul Lakkireddy /* location of jump to make */ 2542e8aad7bSRahul Lakkireddy const struct cxgb4_match_field *jump; 2552e8aad7bSRahul Lakkireddy }; 2562e8aad7bSRahul Lakkireddy 2572e8aad7bSRahul Lakkireddy /* Accept a rule with a jump to transport layer header based on IHL field in 2582e8aad7bSRahul Lakkireddy * IPv4 header. 2592e8aad7bSRahul Lakkireddy */ 2602e8aad7bSRahul Lakkireddy static const struct cxgb4_next_header cxgb4_ipv4_jumps[] = { 2612e8aad7bSRahul Lakkireddy { .offset = 0, .offoff = 0, .shift = 6, .mask = 0xF, 2622e8aad7bSRahul Lakkireddy .match_off = 8, .match_val = 0x600, .match_mask = 0xFF00, 2632e8aad7bSRahul Lakkireddy .jump = cxgb4_tcp_fields }, 2642e8aad7bSRahul Lakkireddy { .offset = 0, .offoff = 0, .shift = 6, .mask = 0xF, 2652e8aad7bSRahul Lakkireddy .match_off = 8, .match_val = 0x1100, .match_mask = 0xFF00, 2662e8aad7bSRahul Lakkireddy .jump = cxgb4_udp_fields }, 2672e8aad7bSRahul Lakkireddy { .jump = NULL } 2682e8aad7bSRahul Lakkireddy }; 2692e8aad7bSRahul Lakkireddy 2702e8aad7bSRahul Lakkireddy /* Accept a rule with a jump directly past the 40 Bytes of IPv6 fixed header 2712e8aad7bSRahul Lakkireddy * to get to transport layer header. 2722e8aad7bSRahul Lakkireddy */ 2732e8aad7bSRahul Lakkireddy static const struct cxgb4_next_header cxgb4_ipv6_jumps[] = { 2742e8aad7bSRahul Lakkireddy { .offset = 0x28, .offoff = 0, .shift = 0, .mask = 0, 2752e8aad7bSRahul Lakkireddy .match_off = 4, .match_val = 0x60000, .match_mask = 0xFF0000, 2762e8aad7bSRahul Lakkireddy .jump = cxgb4_tcp_fields }, 2772e8aad7bSRahul Lakkireddy { .offset = 0x28, .offoff = 0, .shift = 0, .mask = 0, 2782e8aad7bSRahul Lakkireddy .match_off = 4, .match_val = 0x110000, .match_mask = 0xFF0000, 2792e8aad7bSRahul Lakkireddy .jump = cxgb4_udp_fields }, 2802e8aad7bSRahul Lakkireddy { .jump = NULL } 2812e8aad7bSRahul Lakkireddy }; 282*d8931847SRahul Lakkireddy 283*d8931847SRahul Lakkireddy struct cxgb4_link { 284*d8931847SRahul Lakkireddy const struct cxgb4_match_field *match_field; /* Next header */ 285*d8931847SRahul Lakkireddy struct ch_filter_specification fs; /* Match spec associated with link */ 286*d8931847SRahul Lakkireddy u32 link_handle; /* Knode handle associated with the link */ 287*d8931847SRahul Lakkireddy unsigned long *tid_map; /* Bitmap for filter tids */ 288*d8931847SRahul Lakkireddy }; 289*d8931847SRahul Lakkireddy 290*d8931847SRahul Lakkireddy struct cxgb4_tc_u32_table { 291*d8931847SRahul Lakkireddy unsigned int size; /* number of entries in table */ 292*d8931847SRahul Lakkireddy struct cxgb4_link table[0]; /* Jump table */ 293*d8931847SRahul Lakkireddy }; 2942e8aad7bSRahul Lakkireddy #endif /* __CXGB4_TC_U32_PARSE_H */ 295