|
16 | 16 | #include <net/tc_act/tc_skbedit.h> |
17 | 17 | #include <net/tc_act/tc_mirred.h> |
18 | 18 | #include <net/tc_act/tc_vlan.h> |
| 19 | +#include <net/tc_act/tc_pedit.h> |
19 | 20 | #include <net/tc_act/tc_tunnel_key.h> |
20 | 21 |
|
21 | 22 | #include "bnxt_hsi.h" |
|
36 | 37 | #define is_vid_exactmatch(vlan_tci_mask) \ |
37 | 38 | ((ntohs(vlan_tci_mask) & VLAN_VID_MASK) == VLAN_VID_MASK) |
38 | 39 |
|
| 40 | +static bool is_wildcard(void *mask, int len); |
| 41 | +static bool is_exactmatch(void *mask, int len); |
39 | 42 | /* Return the dst fid of the func for flow forwarding |
40 | 43 | * For PFs: src_fid is the fid of the PF |
41 | 44 | * For VF-reps: src_fid the fid of the VF |
@@ -111,10 +114,115 @@ static int bnxt_tc_parse_tunnel_set(struct bnxt *bp, |
111 | 114 | return 0; |
112 | 115 | } |
113 | 116 |
|
| 117 | +/* Key & Mask from the stack comes unaligned in multiple iterations. |
| 118 | + * This routine consolidates such multiple unaligned values into one |
| 119 | + * field each for Key & Mask (for src and dst macs separately) |
| 120 | + * For example, |
| 121 | + * Mask/Key Offset Iteration |
| 122 | + * ========== ====== ========= |
| 123 | + * dst mac 0xffffffff 0 1 |
| 124 | + * dst mac 0x0000ffff 4 2 |
| 125 | + * |
| 126 | + * src mac 0xffff0000 4 1 |
| 127 | + * src mac 0xffffffff 8 2 |
| 128 | + * |
| 129 | + * The above combination coming from the stack will be consolidated as |
| 130 | + * Mask/Key |
| 131 | + * ============== |
| 132 | + * src mac: 0xffffffffffff |
| 133 | + * dst mac: 0xffffffffffff |
| 134 | + */ |
| 135 | +static void bnxt_set_l2_key_mask(u32 part_key, u32 part_mask, |
| 136 | + u8 *actual_key, u8 *actual_mask) |
| 137 | +{ |
| 138 | + u32 key = get_unaligned((u32 *)actual_key); |
| 139 | + u32 mask = get_unaligned((u32 *)actual_mask); |
| 140 | + |
| 141 | + part_key &= part_mask; |
| 142 | + part_key |= key & ~part_mask; |
| 143 | + |
| 144 | + put_unaligned(mask | part_mask, (u32 *)actual_mask); |
| 145 | + put_unaligned(part_key, (u32 *)actual_key); |
| 146 | +} |
| 147 | + |
| 148 | +static int |
| 149 | +bnxt_fill_l2_rewrite_fields(struct bnxt_tc_actions *actions, |
| 150 | + u16 *eth_addr, u16 *eth_addr_mask) |
| 151 | +{ |
| 152 | + u16 *p; |
| 153 | + int j; |
| 154 | + |
| 155 | + if (unlikely(bnxt_eth_addr_key_mask_invalid(eth_addr, eth_addr_mask))) |
| 156 | + return -EINVAL; |
| 157 | + |
| 158 | + if (!is_wildcard(ð_addr_mask[0], ETH_ALEN)) { |
| 159 | + if (!is_exactmatch(ð_addr_mask[0], ETH_ALEN)) |
| 160 | + return -EINVAL; |
| 161 | + /* FW expects dmac to be in u16 array format */ |
| 162 | + p = eth_addr; |
| 163 | + for (j = 0; j < 3; j++) |
| 164 | + actions->l2_rewrite_dmac[j] = cpu_to_be16(*(p + j)); |
| 165 | + } |
| 166 | + |
| 167 | + if (!is_wildcard(ð_addr_mask[ETH_ALEN], ETH_ALEN)) { |
| 168 | + if (!is_exactmatch(ð_addr_mask[ETH_ALEN], ETH_ALEN)) |
| 169 | + return -EINVAL; |
| 170 | + /* FW expects smac to be in u16 array format */ |
| 171 | + p = ð_addr[ETH_ALEN / 2]; |
| 172 | + for (j = 0; j < 3; j++) |
| 173 | + actions->l2_rewrite_smac[j] = cpu_to_be16(*(p + j)); |
| 174 | + } |
| 175 | + |
| 176 | + return 0; |
| 177 | +} |
| 178 | + |
| 179 | +static int |
| 180 | +bnxt_tc_parse_pedit(struct bnxt *bp, struct bnxt_tc_actions *actions, |
| 181 | + struct flow_action_entry *act, u8 *eth_addr, |
| 182 | + u8 *eth_addr_mask) |
| 183 | +{ |
| 184 | + u32 mask, val, offset; |
| 185 | + u8 htype; |
| 186 | + |
| 187 | + offset = act->mangle.offset; |
| 188 | + htype = act->mangle.htype; |
| 189 | + switch (htype) { |
| 190 | + case FLOW_ACT_MANGLE_HDR_TYPE_ETH: |
| 191 | + if (offset > PEDIT_OFFSET_SMAC_LAST_4_BYTES) { |
| 192 | + netdev_err(bp->dev, |
| 193 | + "%s: eth_hdr: Invalid pedit field\n", |
| 194 | + __func__); |
| 195 | + return -EINVAL; |
| 196 | + } |
| 197 | + actions->flags |= BNXT_TC_ACTION_FLAG_L2_REWRITE; |
| 198 | + mask = ~act->mangle.mask; |
| 199 | + val = act->mangle.val; |
| 200 | + |
| 201 | + bnxt_set_l2_key_mask(val, mask, ð_addr[offset], |
| 202 | + ð_addr_mask[offset]); |
| 203 | + break; |
| 204 | + default: |
| 205 | + netdev_err(bp->dev, "%s: Unsupported pedit hdr type\n", |
| 206 | + __func__); |
| 207 | + return -EINVAL; |
| 208 | + } |
| 209 | + return 0; |
| 210 | +} |
| 211 | + |
114 | 212 | static int bnxt_tc_parse_actions(struct bnxt *bp, |
115 | 213 | struct bnxt_tc_actions *actions, |
116 | 214 | struct flow_action *flow_action) |
117 | 215 | { |
| 216 | + /* Used to store the L2 rewrite mask for dmac (6 bytes) followed by |
| 217 | + * smac (6 bytes) if rewrite of both is specified, otherwise either |
| 218 | + * dmac or smac |
| 219 | + */ |
| 220 | + u16 eth_addr_mask[ETH_ALEN] = { 0 }; |
| 221 | + /* Used to store the L2 rewrite key for dmac (6 bytes) followed by |
| 222 | + * smac (6 bytes) if rewrite of both is specified, otherwise either |
| 223 | + * dmac or smac |
| 224 | + */ |
| 225 | + u16 eth_addr[ETH_ALEN] = { 0 }; |
118 | 226 | struct flow_action_entry *act; |
119 | 227 | int i, rc; |
120 | 228 |
|
@@ -148,11 +256,26 @@ static int bnxt_tc_parse_actions(struct bnxt *bp, |
148 | 256 | case FLOW_ACTION_TUNNEL_DECAP: |
149 | 257 | actions->flags |= BNXT_TC_ACTION_FLAG_TUNNEL_DECAP; |
150 | 258 | break; |
| 259 | + /* Packet edit: L2 rewrite, NAT, NAPT */ |
| 260 | + case FLOW_ACTION_MANGLE: |
| 261 | + rc = bnxt_tc_parse_pedit(bp, actions, act, |
| 262 | + (u8 *)eth_addr, |
| 263 | + (u8 *)eth_addr_mask); |
| 264 | + if (rc) |
| 265 | + return rc; |
| 266 | + break; |
151 | 267 | default: |
152 | 268 | break; |
153 | 269 | } |
154 | 270 | } |
155 | 271 |
|
| 272 | + if (actions->flags & BNXT_TC_ACTION_FLAG_L2_REWRITE) { |
| 273 | + rc = bnxt_fill_l2_rewrite_fields(actions, eth_addr, |
| 274 | + eth_addr_mask); |
| 275 | + if (rc) |
| 276 | + return rc; |
| 277 | + } |
| 278 | + |
156 | 279 | if (actions->flags & BNXT_TC_ACTION_FLAG_FWD) { |
157 | 280 | if (actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP) { |
158 | 281 | /* dst_fid is PF's fid */ |
@@ -401,6 +524,15 @@ static int bnxt_hwrm_cfa_flow_alloc(struct bnxt *bp, struct bnxt_tc_flow *flow, |
401 | 524 | req.src_fid = cpu_to_le16(flow->src_fid); |
402 | 525 | req.ref_flow_handle = ref_flow_handle; |
403 | 526 |
|
| 527 | + if (actions->flags & BNXT_TC_ACTION_FLAG_L2_REWRITE) { |
| 528 | + memcpy(req.l2_rewrite_dmac, actions->l2_rewrite_dmac, |
| 529 | + ETH_ALEN); |
| 530 | + memcpy(req.l2_rewrite_smac, actions->l2_rewrite_smac, |
| 531 | + ETH_ALEN); |
| 532 | + action_flags |= |
| 533 | + CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_L2_HEADER_REWRITE; |
| 534 | + } |
| 535 | + |
404 | 536 | if (actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_DECAP || |
405 | 537 | actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP) { |
406 | 538 | req.tunnel_handle = tunnel_handle; |
|
0 commit comments