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

Merge branch 'nfp-Flower-flow-merging'

Simon Horman says:

====================
nfp: Flower flow merging

John Hurley says,

These patches deal with 'implicit recirculation' on the NFP. This is a
firmware feature whereby a packet egresses to an 'internal' port meaning
that it will recirculate back to the header extract phase with the
'internal' port now marked as its ingress port. This internal port can
then be matched on by another rule. This process simulates how OvS
datapath outputs to an internal port. The FW traces the packet's
recirculation route and sends a 'merge hint' to the driver telling it
which flows it matched against. The driver can then decide if these flows
can be merged to a single rule and offloaded.

The patches deal with the following issues:

- assigning/freeing IDs to/from each of these new internal ports
- offloading rules that match on internal ports
- offloading neighbour table entries whose egress port is internal
- handling fallback traffic with an internal port as ingress
- using merge hints to create 'faster path' flows and tracking stats etc.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+1016 -53
+3 -2
drivers/net/ethernet/netronome/nfp/abm/main.c
··· 53 53 } 54 54 } 55 55 56 - static struct net_device *nfp_abm_repr_get(struct nfp_app *app, u32 port_id) 56 + static struct net_device * 57 + nfp_abm_repr_get(struct nfp_app *app, u32 port_id, bool *redir_egress) 57 58 { 58 59 enum nfp_repr_type rtype; 59 60 struct nfp_reprs *reprs; ··· 550 549 .eswitch_mode_get = nfp_abm_eswitch_mode_get, 551 550 .eswitch_mode_set = nfp_abm_eswitch_mode_set, 552 551 553 - .repr_get = nfp_abm_repr_get, 552 + .dev_get = nfp_abm_repr_get, 554 553 };
+53 -2
drivers/net/ethernet/netronome/nfp/flower/cmsg.c
··· 159 159 160 160 rtnl_lock(); 161 161 rcu_read_lock(); 162 - netdev = nfp_app_repr_get(app, be32_to_cpu(msg->portnum)); 162 + netdev = nfp_app_dev_get(app, be32_to_cpu(msg->portnum), NULL); 163 163 rcu_read_unlock(); 164 164 if (!netdev) { 165 165 nfp_flower_cmsg_warn(app, "ctrl msg for unknown port 0x%08x\n", ··· 192 192 msg = nfp_flower_cmsg_get_data(skb); 193 193 194 194 rcu_read_lock(); 195 - exists = !!nfp_app_repr_get(app, be32_to_cpu(msg->portnum)); 195 + exists = !!nfp_app_dev_get(app, be32_to_cpu(msg->portnum), NULL); 196 196 rcu_read_unlock(); 197 197 if (!exists) { 198 198 nfp_flower_cmsg_warn(app, "ctrl msg for unknown port 0x%08x\n", ··· 202 202 203 203 atomic_inc(&priv->reify_replies); 204 204 wake_up(&priv->reify_wait_queue); 205 + } 206 + 207 + static void 208 + nfp_flower_cmsg_merge_hint_rx(struct nfp_app *app, struct sk_buff *skb) 209 + { 210 + unsigned int msg_len = nfp_flower_cmsg_get_data_len(skb); 211 + struct nfp_flower_cmsg_merge_hint *msg; 212 + struct nfp_fl_payload *sub_flows[2]; 213 + int err, i, flow_cnt; 214 + 215 + msg = nfp_flower_cmsg_get_data(skb); 216 + /* msg->count starts at 0 and always assumes at least 1 entry. */ 217 + flow_cnt = msg->count + 1; 218 + 219 + if (msg_len < struct_size(msg, flow, flow_cnt)) { 220 + nfp_flower_cmsg_warn(app, "Merge hint ctrl msg too short - %d bytes but expect %ld\n", 221 + msg_len, struct_size(msg, flow, flow_cnt)); 222 + return; 223 + } 224 + 225 + if (flow_cnt != 2) { 226 + nfp_flower_cmsg_warn(app, "Merge hint contains %d flows - two are expected\n", 227 + flow_cnt); 228 + return; 229 + } 230 + 231 + rtnl_lock(); 232 + for (i = 0; i < flow_cnt; i++) { 233 + u32 ctx = be32_to_cpu(msg->flow[i].host_ctx); 234 + 235 + sub_flows[i] = nfp_flower_get_fl_payload_from_ctx(app, ctx); 236 + if (!sub_flows[i]) { 237 + nfp_flower_cmsg_warn(app, "Invalid flow in merge hint\n"); 238 + goto err_rtnl_unlock; 239 + } 240 + } 241 + 242 + err = nfp_flower_merge_offloaded_flows(app, sub_flows[0], sub_flows[1]); 243 + /* Only warn on memory fail. Hint veto will not break functionality. */ 244 + if (err == -ENOMEM) 245 + nfp_flower_cmsg_warn(app, "Flow merge memory fail.\n"); 246 + 247 + err_rtnl_unlock: 248 + rtnl_unlock(); 205 249 } 206 250 207 251 static void ··· 266 222 case NFP_FLOWER_CMSG_TYPE_PORT_MOD: 267 223 nfp_flower_cmsg_portmod_rx(app, skb); 268 224 break; 225 + case NFP_FLOWER_CMSG_TYPE_MERGE_HINT: 226 + if (app_priv->flower_ext_feats & NFP_FL_FEATS_FLOW_MERGE) { 227 + nfp_flower_cmsg_merge_hint_rx(app, skb); 228 + break; 229 + } 230 + goto err_default; 269 231 case NFP_FLOWER_CMSG_TYPE_NO_NEIGH: 270 232 nfp_tunnel_request_route(app, skb); 271 233 break; ··· 285 235 } 286 236 /* fall through */ 287 237 default: 238 + err_default: 288 239 nfp_flower_cmsg_warn(app, "Cannot handle invalid repr control type %u\n", 289 240 type); 290 241 goto out;
+19
drivers/net/ethernet/netronome/nfp/flower/cmsg.h
··· 402 402 /* Types defined for port related control messages */ 403 403 enum nfp_flower_cmsg_type_port { 404 404 NFP_FLOWER_CMSG_TYPE_FLOW_ADD = 0, 405 + NFP_FLOWER_CMSG_TYPE_FLOW_MOD = 1, 405 406 NFP_FLOWER_CMSG_TYPE_FLOW_DEL = 2, 406 407 NFP_FLOWER_CMSG_TYPE_LAG_CONFIG = 4, 407 408 NFP_FLOWER_CMSG_TYPE_PORT_REIFY = 6, 408 409 NFP_FLOWER_CMSG_TYPE_MAC_REPR = 7, 409 410 NFP_FLOWER_CMSG_TYPE_PORT_MOD = 8, 411 + NFP_FLOWER_CMSG_TYPE_MERGE_HINT = 9, 410 412 NFP_FLOWER_CMSG_TYPE_NO_NEIGH = 10, 411 413 NFP_FLOWER_CMSG_TYPE_TUN_MAC = 11, 412 414 NFP_FLOWER_CMSG_TYPE_ACTIVE_TUNS = 12, ··· 453 451 454 452 #define NFP_FLOWER_CMSG_PORTREIFY_INFO_EXIST BIT(0) 455 453 454 + /* NFP_FLOWER_CMSG_TYPE_FLOW_MERGE_HINT */ 455 + struct nfp_flower_cmsg_merge_hint { 456 + u8 reserved[3]; 457 + u8 count; 458 + struct { 459 + __be32 host_ctx; 460 + __be64 host_cookie; 461 + } __packed flow[0]; 462 + }; 463 + 456 464 enum nfp_flower_cmsg_port_type { 457 465 NFP_FLOWER_CMSG_PORT_TYPE_UNSPEC = 0x0, 458 466 NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT = 0x1, ··· 484 472 #define NFP_FLOWER_CMSG_PORT_VNIC GENMASK(11, 6) 485 473 #define NFP_FLOWER_CMSG_PORT_PCIE_Q GENMASK(5, 0) 486 474 #define NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM GENMASK(7, 0) 475 + 476 + static inline u32 nfp_flower_internal_port_get_port_id(u8 internal_port) 477 + { 478 + return FIELD_PREP(NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM, internal_port) | 479 + FIELD_PREP(NFP_FLOWER_CMSG_PORT_TYPE, 480 + NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT); 481 + } 487 482 488 483 static inline u32 nfp_flower_cmsg_phys_port(u8 phys_port) 489 484 {
+147 -2
drivers/net/ethernet/netronome/nfp/flower/main.c
··· 22 22 23 23 #define NFP_FLOWER_ALLOWED_VER 0x0001000000010000UL 24 24 25 + #define NFP_MIN_INT_PORT_ID 1 26 + #define NFP_MAX_INT_PORT_ID 256 27 + 25 28 static const char *nfp_flower_extra_cap(struct nfp_app *app, struct nfp_net *nn) 26 29 { 27 30 return "FLOWER"; ··· 33 30 static enum devlink_eswitch_mode eswitch_mode_get(struct nfp_app *app) 34 31 { 35 32 return DEVLINK_ESWITCH_MODE_SWITCHDEV; 33 + } 34 + 35 + static int 36 + nfp_flower_lookup_internal_port_id(struct nfp_flower_priv *priv, 37 + struct net_device *netdev) 38 + { 39 + struct net_device *entry; 40 + int i, id = 0; 41 + 42 + rcu_read_lock(); 43 + idr_for_each_entry(&priv->internal_ports.port_ids, entry, i) 44 + if (entry == netdev) { 45 + id = i; 46 + break; 47 + } 48 + rcu_read_unlock(); 49 + 50 + return id; 51 + } 52 + 53 + static int 54 + nfp_flower_get_internal_port_id(struct nfp_app *app, struct net_device *netdev) 55 + { 56 + struct nfp_flower_priv *priv = app->priv; 57 + int id; 58 + 59 + id = nfp_flower_lookup_internal_port_id(priv, netdev); 60 + if (id > 0) 61 + return id; 62 + 63 + idr_preload(GFP_ATOMIC); 64 + spin_lock_bh(&priv->internal_ports.lock); 65 + id = idr_alloc(&priv->internal_ports.port_ids, netdev, 66 + NFP_MIN_INT_PORT_ID, NFP_MAX_INT_PORT_ID, GFP_ATOMIC); 67 + spin_unlock_bh(&priv->internal_ports.lock); 68 + idr_preload_end(); 69 + 70 + return id; 71 + } 72 + 73 + u32 nfp_flower_get_port_id_from_netdev(struct nfp_app *app, 74 + struct net_device *netdev) 75 + { 76 + int ext_port; 77 + 78 + if (nfp_netdev_is_nfp_repr(netdev)) { 79 + return nfp_repr_get_port_id(netdev); 80 + } else if (nfp_flower_internal_port_can_offload(app, netdev)) { 81 + ext_port = nfp_flower_get_internal_port_id(app, netdev); 82 + if (ext_port < 0) 83 + return 0; 84 + 85 + return nfp_flower_internal_port_get_port_id(ext_port); 86 + } 87 + 88 + return 0; 89 + } 90 + 91 + static struct net_device * 92 + nfp_flower_get_netdev_from_internal_port_id(struct nfp_app *app, int port_id) 93 + { 94 + struct nfp_flower_priv *priv = app->priv; 95 + struct net_device *netdev; 96 + 97 + rcu_read_lock(); 98 + netdev = idr_find(&priv->internal_ports.port_ids, port_id); 99 + rcu_read_unlock(); 100 + 101 + return netdev; 102 + } 103 + 104 + static void 105 + nfp_flower_free_internal_port_id(struct nfp_app *app, struct net_device *netdev) 106 + { 107 + struct nfp_flower_priv *priv = app->priv; 108 + int id; 109 + 110 + id = nfp_flower_lookup_internal_port_id(priv, netdev); 111 + if (!id) 112 + return; 113 + 114 + spin_lock_bh(&priv->internal_ports.lock); 115 + idr_remove(&priv->internal_ports.port_ids, id); 116 + spin_unlock_bh(&priv->internal_ports.lock); 117 + } 118 + 119 + static int 120 + nfp_flower_internal_port_event_handler(struct nfp_app *app, 121 + struct net_device *netdev, 122 + unsigned long event) 123 + { 124 + if (event == NETDEV_UNREGISTER && 125 + nfp_flower_internal_port_can_offload(app, netdev)) 126 + nfp_flower_free_internal_port_id(app, netdev); 127 + 128 + return NOTIFY_OK; 129 + } 130 + 131 + static void nfp_flower_internal_port_init(struct nfp_flower_priv *priv) 132 + { 133 + spin_lock_init(&priv->internal_ports.lock); 134 + idr_init(&priv->internal_ports.port_ids); 135 + } 136 + 137 + static void nfp_flower_internal_port_cleanup(struct nfp_flower_priv *priv) 138 + { 139 + idr_destroy(&priv->internal_ports.port_ids); 36 140 } 37 141 38 142 static struct nfp_flower_non_repr_priv * ··· 229 119 } 230 120 231 121 static struct net_device * 232 - nfp_flower_repr_get(struct nfp_app *app, u32 port_id) 122 + nfp_flower_dev_get(struct nfp_app *app, u32 port_id, bool *redir_egress) 233 123 { 234 124 enum nfp_repr_type repr_type; 235 125 struct nfp_reprs *reprs; 236 126 u8 port = 0; 127 + 128 + /* Check if the port is internal. */ 129 + if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port_id) == 130 + NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT) { 131 + if (redir_egress) 132 + *redir_egress = true; 133 + port = FIELD_GET(NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM, port_id); 134 + return nfp_flower_get_netdev_from_internal_port_id(app, port); 135 + } 237 136 238 137 repr_type = nfp_flower_repr_get_type_and_port(app, port_id, &port); 239 138 if (repr_type > NFP_REPR_TYPE_MAX) ··· 760 641 goto err_cleanup_metadata; 761 642 } 762 643 644 + if (app_priv->flower_ext_feats & NFP_FL_FEATS_FLOW_MOD) { 645 + /* Tell the firmware that the driver supports flow merging. */ 646 + err = nfp_rtsym_write_le(app->pf->rtbl, 647 + "_abi_flower_merge_hint_enable", 1); 648 + if (!err) { 649 + app_priv->flower_ext_feats |= NFP_FL_FEATS_FLOW_MERGE; 650 + nfp_flower_internal_port_init(app_priv); 651 + } else if (err == -ENOENT) { 652 + nfp_warn(app->cpp, "Flow merge not supported by FW.\n"); 653 + } else { 654 + goto err_lag_clean; 655 + } 656 + } else { 657 + nfp_warn(app->cpp, "Flow mod/merge not supported by FW.\n"); 658 + } 659 + 763 660 INIT_LIST_HEAD(&app_priv->indr_block_cb_priv); 764 661 INIT_LIST_HEAD(&app_priv->non_repr_priv); 765 662 766 663 return 0; 767 664 665 + err_lag_clean: 666 + if (app_priv->flower_ext_feats & NFP_FL_FEATS_LAG) 667 + nfp_flower_lag_cleanup(&app_priv->nfp_lag); 768 668 err_cleanup_metadata: 769 669 nfp_flower_metadata_cleanup(app); 770 670 err_free_app_priv: ··· 801 663 802 664 if (app_priv->flower_ext_feats & NFP_FL_FEATS_LAG) 803 665 nfp_flower_lag_cleanup(&app_priv->nfp_lag); 666 + 667 + if (app_priv->flower_ext_feats & NFP_FL_FEATS_FLOW_MERGE) 668 + nfp_flower_internal_port_cleanup(app_priv); 804 669 805 670 nfp_flower_metadata_cleanup(app); 806 671 vfree(app->priv); ··· 903 762 if (ret & NOTIFY_STOP_MASK) 904 763 return ret; 905 764 765 + ret = nfp_flower_internal_port_event_handler(app, netdev, event); 766 + if (ret & NOTIFY_STOP_MASK) 767 + return ret; 768 + 906 769 return nfp_tunnel_mac_event_handler(app, netdev, event, ptr); 907 770 } 908 771 ··· 945 800 .sriov_disable = nfp_flower_sriov_disable, 946 801 947 802 .eswitch_mode_get = eswitch_mode_get, 948 - .repr_get = nfp_flower_repr_get, 803 + .dev_get = nfp_flower_dev_get, 949 804 950 805 .setup_tc = nfp_flower_setup_tc, 951 806 };
+69
drivers/net/ethernet/netronome/nfp/flower/main.h
··· 39 39 #define NFP_FL_NBI_MTU_SETTING BIT(1) 40 40 #define NFP_FL_FEATS_GENEVE_OPT BIT(2) 41 41 #define NFP_FL_FEATS_VLAN_PCP BIT(3) 42 + #define NFP_FL_FEATS_FLOW_MOD BIT(5) 43 + #define NFP_FL_FEATS_FLOW_MERGE BIT(30) 42 44 #define NFP_FL_FEATS_LAG BIT(31) 43 45 44 46 struct nfp_fl_mask_id { ··· 117 115 }; 118 116 119 117 /** 118 + * struct nfp_fl_internal_ports - Flower APP priv data for additional ports 119 + * @port_ids: Assignment of ids to any additional ports 120 + * @lock: Lock for extra ports list 121 + */ 122 + struct nfp_fl_internal_ports { 123 + struct idr port_ids; 124 + spinlock_t lock; 125 + }; 126 + 127 + /** 120 128 * struct nfp_flower_priv - Flower APP per-vNIC priv data 121 129 * @app: Back pointer to app 122 130 * @nn: Pointer to vNIC ··· 140 128 * @flow_table: Hash table used to store flower rules 141 129 * @stats: Stored stats updates for flower rules 142 130 * @stats_lock: Lock for flower rule stats updates 131 + * @stats_ctx_table: Hash table to map stats contexts to its flow rule 143 132 * @cmsg_work: Workqueue for control messages processing 144 133 * @cmsg_skbs_high: List of higher priority skbs for control message 145 134 * processing ··· 156 143 * @non_repr_priv: List of offloaded non-repr ports and their priv data 157 144 * @active_mem_unit: Current active memory unit for flower rules 158 145 * @total_mem_units: Total number of available memory units for flower rules 146 + * @internal_ports: Internal port ids used in offloaded rules 159 147 */ 160 148 struct nfp_flower_priv { 161 149 struct nfp_app *app; ··· 171 157 struct rhashtable flow_table; 172 158 struct nfp_fl_stats *stats; 173 159 spinlock_t stats_lock; /* lock stats */ 160 + struct rhashtable stats_ctx_table; 174 161 struct work_struct cmsg_work; 175 162 struct sk_buff_head cmsg_skbs_high; 176 163 struct sk_buff_head cmsg_skbs_low; ··· 184 169 struct list_head non_repr_priv; 185 170 unsigned int active_mem_unit; 186 171 unsigned int total_mem_units; 172 + struct nfp_fl_internal_ports internal_ports; 187 173 }; 188 174 189 175 /** ··· 252 236 char *unmasked_data; 253 237 char *mask_data; 254 238 char *action_data; 239 + struct list_head linked_flows; 240 + bool in_hw; 241 + }; 242 + 243 + struct nfp_fl_payload_link { 244 + /* A link contains a pointer to a merge flow and an associated sub_flow. 245 + * Each merge flow will feature in 2 links to its underlying sub_flows. 246 + * A sub_flow will have at least 1 link to a merge flow or more if it 247 + * has been used to create multiple merge flows. 248 + * 249 + * For a merge flow, 'linked_flows' in its nfp_fl_payload struct lists 250 + * all links to sub_flows (sub_flow.flow) via merge.list. 251 + * For a sub_flow, 'linked_flows' gives all links to merge flows it has 252 + * formed (merge_flow.flow) via sub_flow.list. 253 + */ 254 + struct { 255 + struct list_head list; 256 + struct nfp_fl_payload *flow; 257 + } merge_flow, sub_flow; 255 258 }; 256 259 257 260 extern const struct rhashtable_params nfp_flower_table_params; ··· 282 247 __be64 stats_cookie; 283 248 }; 284 249 250 + static inline bool 251 + nfp_flower_internal_port_can_offload(struct nfp_app *app, 252 + struct net_device *netdev) 253 + { 254 + struct nfp_flower_priv *app_priv = app->priv; 255 + 256 + if (!(app_priv->flower_ext_feats & NFP_FL_FEATS_FLOW_MERGE)) 257 + return false; 258 + if (!netdev->rtnl_link_ops) 259 + return false; 260 + if (!strcmp(netdev->rtnl_link_ops->kind, "openvswitch")) 261 + return true; 262 + 263 + return false; 264 + } 265 + 266 + /* The address of the merged flow acts as its cookie. 267 + * Cookies supplied to us by TC flower are also addresses to allocated 268 + * memory and thus this scheme should not generate any collisions. 269 + */ 270 + static inline bool nfp_flower_is_merge_flow(struct nfp_fl_payload *flow_pay) 271 + { 272 + return flow_pay->tc_flower_cookie == (unsigned long)flow_pay; 273 + } 274 + 285 275 int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count, 286 276 unsigned int host_ctx_split); 287 277 void nfp_flower_metadata_cleanup(struct nfp_app *app); 288 278 289 279 int nfp_flower_setup_tc(struct nfp_app *app, struct net_device *netdev, 290 280 enum tc_setup_type type, void *type_data); 281 + int nfp_flower_merge_offloaded_flows(struct nfp_app *app, 282 + struct nfp_fl_payload *sub_flow1, 283 + struct nfp_fl_payload *sub_flow2); 291 284 int nfp_flower_compile_flow_match(struct nfp_app *app, 292 285 struct tc_cls_flower_offload *flow, 293 286 struct nfp_fl_key_ls *key_ls, ··· 330 267 struct tc_cls_flower_offload *flow, 331 268 struct nfp_fl_payload *nfp_flow, 332 269 struct net_device *netdev); 270 + void __nfp_modify_flow_metadata(struct nfp_flower_priv *priv, 271 + struct nfp_fl_payload *nfp_flow); 333 272 int nfp_modify_flow_metadata(struct nfp_app *app, 334 273 struct nfp_fl_payload *nfp_flow); 335 274 336 275 struct nfp_fl_payload * 337 276 nfp_flower_search_fl_table(struct nfp_app *app, unsigned long tc_flower_cookie, 338 277 struct net_device *netdev); 278 + struct nfp_fl_payload * 279 + nfp_flower_get_fl_payload_from_ctx(struct nfp_app *app, u32 ctx_id); 339 280 struct nfp_fl_payload * 340 281 nfp_flower_remove_fl_table(struct nfp_app *app, unsigned long tc_flower_cookie); 341 282 ··· 378 311 __nfp_flower_non_repr_priv_put(struct nfp_flower_non_repr_priv *non_repr_priv); 379 312 void 380 313 nfp_flower_non_repr_priv_put(struct nfp_app *app, struct net_device *netdev); 314 + u32 nfp_flower_get_port_id_from_netdev(struct nfp_app *app, 315 + struct net_device *netdev); 381 316 #endif
+4 -5
drivers/net/ethernet/netronome/nfp/flower/match.c
··· 326 326 struct nfp_fl_payload *nfp_flow, 327 327 enum nfp_flower_tun_type tun_type) 328 328 { 329 - u32 cmsg_port = 0; 329 + u32 port_id; 330 330 int err; 331 331 u8 *ext; 332 332 u8 *msk; 333 333 334 - if (nfp_netdev_is_nfp_repr(netdev)) 335 - cmsg_port = nfp_repr_get_port_id(netdev); 334 + port_id = nfp_flower_get_port_id_from_netdev(app, netdev); 336 335 337 336 memset(nfp_flow->unmasked_data, 0, key_ls->key_size); 338 337 memset(nfp_flow->mask_data, 0, key_ls->key_size); ··· 357 358 358 359 /* Populate Exact Port data. */ 359 360 err = nfp_flower_compile_port((struct nfp_flower_in_port *)ext, 360 - cmsg_port, false, tun_type); 361 + port_id, false, tun_type); 361 362 if (err) 362 363 return err; 363 364 364 365 /* Populate Mask Port Data. */ 365 366 err = nfp_flower_compile_port((struct nfp_flower_in_port *)msk, 366 - cmsg_port, true, tun_type); 367 + port_id, true, tun_type); 367 368 if (err) 368 369 return err; 369 370
+95 -22
drivers/net/ethernet/netronome/nfp/flower/metadata.c
··· 24 24 unsigned long cookie; 25 25 }; 26 26 27 + struct nfp_fl_stats_ctx_to_flow { 28 + struct rhash_head ht_node; 29 + u32 stats_cxt; 30 + struct nfp_fl_payload *flow; 31 + }; 32 + 33 + static const struct rhashtable_params stats_ctx_table_params = { 34 + .key_offset = offsetof(struct nfp_fl_stats_ctx_to_flow, stats_cxt), 35 + .head_offset = offsetof(struct nfp_fl_stats_ctx_to_flow, ht_node), 36 + .key_len = sizeof(u32), 37 + }; 38 + 27 39 static int nfp_release_stats_entry(struct nfp_app *app, u32 stats_context_id) 28 40 { 29 41 struct nfp_flower_priv *priv = app->priv; ··· 276 264 if (!mask_entry) 277 265 return false; 278 266 279 - if (meta_flags) 280 - *meta_flags &= ~NFP_FL_META_FLAG_MANAGE_MASK; 281 - 282 267 *mask_id = mask_entry->mask_id; 283 268 mask_entry->ref_cnt--; 284 269 if (!mask_entry->ref_cnt) { ··· 294 285 struct nfp_fl_payload *nfp_flow, 295 286 struct net_device *netdev) 296 287 { 288 + struct nfp_fl_stats_ctx_to_flow *ctx_entry; 297 289 struct nfp_flower_priv *priv = app->priv; 298 290 struct nfp_fl_payload *check_entry; 299 291 u8 new_mask_id; 300 292 u32 stats_cxt; 293 + int err; 301 294 302 - if (nfp_get_stats_entry(app, &stats_cxt)) 303 - return -ENOENT; 295 + err = nfp_get_stats_entry(app, &stats_cxt); 296 + if (err) 297 + return err; 304 298 305 299 nfp_flow->meta.host_ctx_id = cpu_to_be32(stats_cxt); 306 300 nfp_flow->meta.host_cookie = cpu_to_be64(flow->cookie); 307 301 nfp_flow->ingress_dev = netdev; 308 302 303 + ctx_entry = kzalloc(sizeof(*ctx_entry), GFP_KERNEL); 304 + if (!ctx_entry) { 305 + err = -ENOMEM; 306 + goto err_release_stats; 307 + } 308 + 309 + ctx_entry->stats_cxt = stats_cxt; 310 + ctx_entry->flow = nfp_flow; 311 + 312 + if (rhashtable_insert_fast(&priv->stats_ctx_table, &ctx_entry->ht_node, 313 + stats_ctx_table_params)) { 314 + err = -ENOMEM; 315 + goto err_free_ctx_entry; 316 + } 317 + 309 318 new_mask_id = 0; 310 319 if (!nfp_check_mask_add(app, nfp_flow->mask_data, 311 320 nfp_flow->meta.mask_len, 312 321 &nfp_flow->meta.flags, &new_mask_id)) { 313 - if (nfp_release_stats_entry(app, stats_cxt)) 314 - return -EINVAL; 315 - return -ENOENT; 322 + err = -ENOENT; 323 + goto err_remove_rhash; 316 324 } 317 325 318 326 nfp_flow->meta.flow_version = cpu_to_be64(priv->flower_version); ··· 343 317 344 318 check_entry = nfp_flower_search_fl_table(app, flow->cookie, netdev); 345 319 if (check_entry) { 346 - if (nfp_release_stats_entry(app, stats_cxt)) 347 - return -EINVAL; 348 - 349 - if (!nfp_check_mask_remove(app, nfp_flow->mask_data, 350 - nfp_flow->meta.mask_len, 351 - NULL, &new_mask_id)) 352 - return -EINVAL; 353 - 354 - return -EEXIST; 320 + err = -EEXIST; 321 + goto err_remove_mask; 355 322 } 356 323 357 324 return 0; 325 + 326 + err_remove_mask: 327 + nfp_check_mask_remove(app, nfp_flow->mask_data, nfp_flow->meta.mask_len, 328 + NULL, &new_mask_id); 329 + err_remove_rhash: 330 + WARN_ON_ONCE(rhashtable_remove_fast(&priv->stats_ctx_table, 331 + &ctx_entry->ht_node, 332 + stats_ctx_table_params)); 333 + err_free_ctx_entry: 334 + kfree(ctx_entry); 335 + err_release_stats: 336 + nfp_release_stats_entry(app, stats_cxt); 337 + 338 + return err; 339 + } 340 + 341 + void __nfp_modify_flow_metadata(struct nfp_flower_priv *priv, 342 + struct nfp_fl_payload *nfp_flow) 343 + { 344 + nfp_flow->meta.flags &= ~NFP_FL_META_FLAG_MANAGE_MASK; 345 + nfp_flow->meta.flow_version = cpu_to_be64(priv->flower_version); 346 + priv->flower_version++; 358 347 } 359 348 360 349 int nfp_modify_flow_metadata(struct nfp_app *app, 361 350 struct nfp_fl_payload *nfp_flow) 362 351 { 352 + struct nfp_fl_stats_ctx_to_flow *ctx_entry; 363 353 struct nfp_flower_priv *priv = app->priv; 364 354 u8 new_mask_id = 0; 365 355 u32 temp_ctx_id; 356 + 357 + __nfp_modify_flow_metadata(priv, nfp_flow); 366 358 367 359 nfp_check_mask_remove(app, nfp_flow->mask_data, 368 360 nfp_flow->meta.mask_len, &nfp_flow->meta.flags, 369 361 &new_mask_id); 370 362 371 - nfp_flow->meta.flow_version = cpu_to_be64(priv->flower_version); 372 - priv->flower_version++; 373 - 374 363 /* Update flow payload with mask ids. */ 375 364 nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION] = new_mask_id; 376 365 377 - /* Release the stats ctx id. */ 366 + /* Release the stats ctx id and ctx to flow table entry. */ 378 367 temp_ctx_id = be32_to_cpu(nfp_flow->meta.host_ctx_id); 379 368 369 + ctx_entry = rhashtable_lookup_fast(&priv->stats_ctx_table, &temp_ctx_id, 370 + stats_ctx_table_params); 371 + if (!ctx_entry) 372 + return -ENOENT; 373 + 374 + WARN_ON_ONCE(rhashtable_remove_fast(&priv->stats_ctx_table, 375 + &ctx_entry->ht_node, 376 + stats_ctx_table_params)); 377 + kfree(ctx_entry); 378 + 380 379 return nfp_release_stats_entry(app, temp_ctx_id); 380 + } 381 + 382 + struct nfp_fl_payload * 383 + nfp_flower_get_fl_payload_from_ctx(struct nfp_app *app, u32 ctx_id) 384 + { 385 + struct nfp_fl_stats_ctx_to_flow *ctx_entry; 386 + struct nfp_flower_priv *priv = app->priv; 387 + 388 + ctx_entry = rhashtable_lookup_fast(&priv->stats_ctx_table, &ctx_id, 389 + stats_ctx_table_params); 390 + if (!ctx_entry) 391 + return NULL; 392 + 393 + return ctx_entry->flow; 381 394 } 382 395 383 396 static int nfp_fl_obj_cmpfn(struct rhashtable_compare_arg *arg, ··· 468 403 if (err) 469 404 return err; 470 405 406 + err = rhashtable_init(&priv->stats_ctx_table, &stats_ctx_table_params); 407 + if (err) 408 + goto err_free_flow_table; 409 + 471 410 get_random_bytes(&priv->mask_id_seed, sizeof(priv->mask_id_seed)); 472 411 473 412 /* Init ring buffer and unallocated mask_ids. */ ··· 479 410 kmalloc_array(NFP_FLOWER_MASK_ENTRY_RS, 480 411 NFP_FLOWER_MASK_ELEMENT_RS, GFP_KERNEL); 481 412 if (!priv->mask_ids.mask_id_free_list.buf) 482 - goto err_free_flow_table; 413 + goto err_free_stats_ctx_table; 483 414 484 415 priv->mask_ids.init_unallocated = NFP_FLOWER_MASK_ENTRY_RS - 1; 485 416 ··· 516 447 kfree(priv->mask_ids.last_used); 517 448 err_free_mask_id: 518 449 kfree(priv->mask_ids.mask_id_free_list.buf); 450 + err_free_stats_ctx_table: 451 + rhashtable_destroy(&priv->stats_ctx_table); 519 452 err_free_flow_table: 520 453 rhashtable_destroy(&priv->flow_table); 521 454 return -ENOMEM; ··· 531 460 return; 532 461 533 462 rhashtable_free_and_destroy(&priv->flow_table, 463 + nfp_check_rhashtable_empty, NULL); 464 + rhashtable_free_and_destroy(&priv->stats_ctx_table, 534 465 nfp_check_rhashtable_empty, NULL); 535 466 kvfree(priv->stats); 536 467 kfree(priv->mask_ids.mask_id_free_list.buf);
+599 -7
drivers/net/ethernet/netronome/nfp/flower/offload.c
··· 55 55 BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | \ 56 56 BIT(FLOW_DISSECTOR_KEY_ENC_PORTS)) 57 57 58 + #define NFP_FLOWER_MERGE_FIELDS \ 59 + (NFP_FLOWER_LAYER_PORT | \ 60 + NFP_FLOWER_LAYER_MAC | \ 61 + NFP_FLOWER_LAYER_TP | \ 62 + NFP_FLOWER_LAYER_IPV4 | \ 63 + NFP_FLOWER_LAYER_IPV6) 64 + 65 + struct nfp_flower_merge_check { 66 + union { 67 + struct { 68 + __be16 tci; 69 + struct nfp_flower_mac_mpls l2; 70 + struct nfp_flower_tp_ports l4; 71 + union { 72 + struct nfp_flower_ipv4 ipv4; 73 + struct nfp_flower_ipv6 ipv6; 74 + }; 75 + }; 76 + unsigned long vals[8]; 77 + }; 78 + }; 79 + 58 80 static int 59 81 nfp_flower_xmit_flow(struct nfp_app *app, struct nfp_fl_payload *nfp_flow, 60 82 u8 mtype) ··· 348 326 break; 349 327 350 328 case cpu_to_be16(ETH_P_IPV6): 351 - key_layer |= NFP_FLOWER_LAYER_IPV6; 329 + key_layer |= NFP_FLOWER_LAYER_IPV6; 352 330 key_size += sizeof(struct nfp_flower_ipv6); 353 331 break; 354 332 ··· 398 376 399 377 flow_pay->nfp_tun_ipv4_addr = 0; 400 378 flow_pay->meta.flags = 0; 379 + INIT_LIST_HEAD(&flow_pay->linked_flows); 380 + flow_pay->in_hw = false; 401 381 402 382 return flow_pay; 403 383 ··· 410 386 err_free_flow: 411 387 kfree(flow_pay); 412 388 return NULL; 389 + } 390 + 391 + static int 392 + nfp_flower_update_merge_with_actions(struct nfp_fl_payload *flow, 393 + struct nfp_flower_merge_check *merge, 394 + u8 *last_act_id, int *act_out) 395 + { 396 + struct nfp_fl_set_ipv6_tc_hl_fl *ipv6_tc_hl_fl; 397 + struct nfp_fl_set_ip4_ttl_tos *ipv4_ttl_tos; 398 + struct nfp_fl_set_ip4_addrs *ipv4_add; 399 + struct nfp_fl_set_ipv6_addr *ipv6_add; 400 + struct nfp_fl_push_vlan *push_vlan; 401 + struct nfp_fl_set_tport *tport; 402 + struct nfp_fl_set_eth *eth; 403 + struct nfp_fl_act_head *a; 404 + unsigned int act_off = 0; 405 + u8 act_id = 0; 406 + u8 *ports; 407 + int i; 408 + 409 + while (act_off < flow->meta.act_len) { 410 + a = (struct nfp_fl_act_head *)&flow->action_data[act_off]; 411 + act_id = a->jump_id; 412 + 413 + switch (act_id) { 414 + case NFP_FL_ACTION_OPCODE_OUTPUT: 415 + if (act_out) 416 + (*act_out)++; 417 + break; 418 + case NFP_FL_ACTION_OPCODE_PUSH_VLAN: 419 + push_vlan = (struct nfp_fl_push_vlan *)a; 420 + if (push_vlan->vlan_tci) 421 + merge->tci = cpu_to_be16(0xffff); 422 + break; 423 + case NFP_FL_ACTION_OPCODE_POP_VLAN: 424 + merge->tci = cpu_to_be16(0); 425 + break; 426 + case NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL: 427 + /* New tunnel header means l2 to l4 can be matched. */ 428 + eth_broadcast_addr(&merge->l2.mac_dst[0]); 429 + eth_broadcast_addr(&merge->l2.mac_src[0]); 430 + memset(&merge->l4, 0xff, 431 + sizeof(struct nfp_flower_tp_ports)); 432 + memset(&merge->ipv4, 0xff, 433 + sizeof(struct nfp_flower_ipv4)); 434 + break; 435 + case NFP_FL_ACTION_OPCODE_SET_ETHERNET: 436 + eth = (struct nfp_fl_set_eth *)a; 437 + for (i = 0; i < ETH_ALEN; i++) 438 + merge->l2.mac_dst[i] |= eth->eth_addr_mask[i]; 439 + for (i = 0; i < ETH_ALEN; i++) 440 + merge->l2.mac_src[i] |= 441 + eth->eth_addr_mask[ETH_ALEN + i]; 442 + break; 443 + case NFP_FL_ACTION_OPCODE_SET_IPV4_ADDRS: 444 + ipv4_add = (struct nfp_fl_set_ip4_addrs *)a; 445 + merge->ipv4.ipv4_src |= ipv4_add->ipv4_src_mask; 446 + merge->ipv4.ipv4_dst |= ipv4_add->ipv4_dst_mask; 447 + break; 448 + case NFP_FL_ACTION_OPCODE_SET_IPV4_TTL_TOS: 449 + ipv4_ttl_tos = (struct nfp_fl_set_ip4_ttl_tos *)a; 450 + merge->ipv4.ip_ext.ttl |= ipv4_ttl_tos->ipv4_ttl_mask; 451 + merge->ipv4.ip_ext.tos |= ipv4_ttl_tos->ipv4_tos_mask; 452 + break; 453 + case NFP_FL_ACTION_OPCODE_SET_IPV6_SRC: 454 + ipv6_add = (struct nfp_fl_set_ipv6_addr *)a; 455 + for (i = 0; i < 4; i++) 456 + merge->ipv6.ipv6_src.in6_u.u6_addr32[i] |= 457 + ipv6_add->ipv6[i].mask; 458 + break; 459 + case NFP_FL_ACTION_OPCODE_SET_IPV6_DST: 460 + ipv6_add = (struct nfp_fl_set_ipv6_addr *)a; 461 + for (i = 0; i < 4; i++) 462 + merge->ipv6.ipv6_dst.in6_u.u6_addr32[i] |= 463 + ipv6_add->ipv6[i].mask; 464 + break; 465 + case NFP_FL_ACTION_OPCODE_SET_IPV6_TC_HL_FL: 466 + ipv6_tc_hl_fl = (struct nfp_fl_set_ipv6_tc_hl_fl *)a; 467 + merge->ipv6.ip_ext.ttl |= 468 + ipv6_tc_hl_fl->ipv6_hop_limit_mask; 469 + merge->ipv6.ip_ext.tos |= ipv6_tc_hl_fl->ipv6_tc_mask; 470 + merge->ipv6.ipv6_flow_label_exthdr |= 471 + ipv6_tc_hl_fl->ipv6_label_mask; 472 + break; 473 + case NFP_FL_ACTION_OPCODE_SET_UDP: 474 + case NFP_FL_ACTION_OPCODE_SET_TCP: 475 + tport = (struct nfp_fl_set_tport *)a; 476 + ports = (u8 *)&merge->l4.port_src; 477 + for (i = 0; i < 4; i++) 478 + ports[i] |= tport->tp_port_mask[i]; 479 + break; 480 + case NFP_FL_ACTION_OPCODE_PRE_TUNNEL: 481 + case NFP_FL_ACTION_OPCODE_PRE_LAG: 482 + case NFP_FL_ACTION_OPCODE_PUSH_GENEVE: 483 + break; 484 + default: 485 + return -EOPNOTSUPP; 486 + } 487 + 488 + act_off += a->len_lw << NFP_FL_LW_SIZ; 489 + } 490 + 491 + if (last_act_id) 492 + *last_act_id = act_id; 493 + 494 + return 0; 495 + } 496 + 497 + static int 498 + nfp_flower_populate_merge_match(struct nfp_fl_payload *flow, 499 + struct nfp_flower_merge_check *merge, 500 + bool extra_fields) 501 + { 502 + struct nfp_flower_meta_tci *meta_tci; 503 + u8 *mask = flow->mask_data; 504 + u8 key_layer, match_size; 505 + 506 + memset(merge, 0, sizeof(struct nfp_flower_merge_check)); 507 + 508 + meta_tci = (struct nfp_flower_meta_tci *)mask; 509 + key_layer = meta_tci->nfp_flow_key_layer; 510 + 511 + if (key_layer & ~NFP_FLOWER_MERGE_FIELDS && !extra_fields) 512 + return -EOPNOTSUPP; 513 + 514 + merge->tci = meta_tci->tci; 515 + mask += sizeof(struct nfp_flower_meta_tci); 516 + 517 + if (key_layer & NFP_FLOWER_LAYER_EXT_META) 518 + mask += sizeof(struct nfp_flower_ext_meta); 519 + 520 + mask += sizeof(struct nfp_flower_in_port); 521 + 522 + if (key_layer & NFP_FLOWER_LAYER_MAC) { 523 + match_size = sizeof(struct nfp_flower_mac_mpls); 524 + memcpy(&merge->l2, mask, match_size); 525 + mask += match_size; 526 + } 527 + 528 + if (key_layer & NFP_FLOWER_LAYER_TP) { 529 + match_size = sizeof(struct nfp_flower_tp_ports); 530 + memcpy(&merge->l4, mask, match_size); 531 + mask += match_size; 532 + } 533 + 534 + if (key_layer & NFP_FLOWER_LAYER_IPV4) { 535 + match_size = sizeof(struct nfp_flower_ipv4); 536 + memcpy(&merge->ipv4, mask, match_size); 537 + } 538 + 539 + if (key_layer & NFP_FLOWER_LAYER_IPV6) { 540 + match_size = sizeof(struct nfp_flower_ipv6); 541 + memcpy(&merge->ipv6, mask, match_size); 542 + } 543 + 544 + return 0; 545 + } 546 + 547 + static int 548 + nfp_flower_can_merge(struct nfp_fl_payload *sub_flow1, 549 + struct nfp_fl_payload *sub_flow2) 550 + { 551 + /* Two flows can be merged if sub_flow2 only matches on bits that are 552 + * either matched by sub_flow1 or set by a sub_flow1 action. This 553 + * ensures that every packet that hits sub_flow1 and recirculates is 554 + * guaranteed to hit sub_flow2. 555 + */ 556 + struct nfp_flower_merge_check sub_flow1_merge, sub_flow2_merge; 557 + int err, act_out = 0; 558 + u8 last_act_id = 0; 559 + 560 + err = nfp_flower_populate_merge_match(sub_flow1, &sub_flow1_merge, 561 + true); 562 + if (err) 563 + return err; 564 + 565 + err = nfp_flower_populate_merge_match(sub_flow2, &sub_flow2_merge, 566 + false); 567 + if (err) 568 + return err; 569 + 570 + err = nfp_flower_update_merge_with_actions(sub_flow1, &sub_flow1_merge, 571 + &last_act_id, &act_out); 572 + if (err) 573 + return err; 574 + 575 + /* Must only be 1 output action and it must be the last in sequence. */ 576 + if (act_out != 1 || last_act_id != NFP_FL_ACTION_OPCODE_OUTPUT) 577 + return -EOPNOTSUPP; 578 + 579 + /* Reject merge if sub_flow2 matches on something that is not matched 580 + * on or set in an action by sub_flow1. 581 + */ 582 + err = bitmap_andnot(sub_flow2_merge.vals, sub_flow2_merge.vals, 583 + sub_flow1_merge.vals, 584 + sizeof(struct nfp_flower_merge_check) * 8); 585 + if (err) 586 + return -EINVAL; 587 + 588 + return 0; 589 + } 590 + 591 + static unsigned int 592 + nfp_flower_copy_pre_actions(char *act_dst, char *act_src, int len, 593 + bool *tunnel_act) 594 + { 595 + unsigned int act_off = 0, act_len; 596 + struct nfp_fl_act_head *a; 597 + u8 act_id = 0; 598 + 599 + while (act_off < len) { 600 + a = (struct nfp_fl_act_head *)&act_src[act_off]; 601 + act_len = a->len_lw << NFP_FL_LW_SIZ; 602 + act_id = a->jump_id; 603 + 604 + switch (act_id) { 605 + case NFP_FL_ACTION_OPCODE_PRE_TUNNEL: 606 + if (tunnel_act) 607 + *tunnel_act = true; 608 + case NFP_FL_ACTION_OPCODE_PRE_LAG: 609 + memcpy(act_dst + act_off, act_src + act_off, act_len); 610 + break; 611 + default: 612 + return act_off; 613 + } 614 + 615 + act_off += act_len; 616 + } 617 + 618 + return act_off; 619 + } 620 + 621 + static int nfp_fl_verify_post_tun_acts(char *acts, int len) 622 + { 623 + struct nfp_fl_act_head *a; 624 + unsigned int act_off = 0; 625 + 626 + while (act_off < len) { 627 + a = (struct nfp_fl_act_head *)&acts[act_off]; 628 + if (a->jump_id != NFP_FL_ACTION_OPCODE_OUTPUT) 629 + return -EOPNOTSUPP; 630 + 631 + act_off += a->len_lw << NFP_FL_LW_SIZ; 632 + } 633 + 634 + return 0; 635 + } 636 + 637 + static int 638 + nfp_flower_merge_action(struct nfp_fl_payload *sub_flow1, 639 + struct nfp_fl_payload *sub_flow2, 640 + struct nfp_fl_payload *merge_flow) 641 + { 642 + unsigned int sub1_act_len, sub2_act_len, pre_off1, pre_off2; 643 + bool tunnel_act = false; 644 + char *merge_act; 645 + int err; 646 + 647 + /* The last action of sub_flow1 must be output - do not merge this. */ 648 + sub1_act_len = sub_flow1->meta.act_len - sizeof(struct nfp_fl_output); 649 + sub2_act_len = sub_flow2->meta.act_len; 650 + 651 + if (!sub2_act_len) 652 + return -EINVAL; 653 + 654 + if (sub1_act_len + sub2_act_len > NFP_FL_MAX_A_SIZ) 655 + return -EINVAL; 656 + 657 + /* A shortcut can only be applied if there is a single action. */ 658 + if (sub1_act_len) 659 + merge_flow->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL); 660 + else 661 + merge_flow->meta.shortcut = sub_flow2->meta.shortcut; 662 + 663 + merge_flow->meta.act_len = sub1_act_len + sub2_act_len; 664 + merge_act = merge_flow->action_data; 665 + 666 + /* Copy any pre-actions to the start of merge flow action list. */ 667 + pre_off1 = nfp_flower_copy_pre_actions(merge_act, 668 + sub_flow1->action_data, 669 + sub1_act_len, &tunnel_act); 670 + merge_act += pre_off1; 671 + sub1_act_len -= pre_off1; 672 + pre_off2 = nfp_flower_copy_pre_actions(merge_act, 673 + sub_flow2->action_data, 674 + sub2_act_len, NULL); 675 + merge_act += pre_off2; 676 + sub2_act_len -= pre_off2; 677 + 678 + /* FW does a tunnel push when egressing, therefore, if sub_flow 1 pushes 679 + * a tunnel, sub_flow 2 can only have output actions for a valid merge. 680 + */ 681 + if (tunnel_act) { 682 + char *post_tun_acts = &sub_flow2->action_data[pre_off2]; 683 + 684 + err = nfp_fl_verify_post_tun_acts(post_tun_acts, sub2_act_len); 685 + if (err) 686 + return err; 687 + } 688 + 689 + /* Copy remaining actions from sub_flows 1 and 2. */ 690 + memcpy(merge_act, sub_flow1->action_data + pre_off1, sub1_act_len); 691 + merge_act += sub1_act_len; 692 + memcpy(merge_act, sub_flow2->action_data + pre_off2, sub2_act_len); 693 + 694 + return 0; 695 + } 696 + 697 + /* Flow link code should only be accessed under RTNL. */ 698 + static void nfp_flower_unlink_flow(struct nfp_fl_payload_link *link) 699 + { 700 + list_del(&link->merge_flow.list); 701 + list_del(&link->sub_flow.list); 702 + kfree(link); 703 + } 704 + 705 + static void nfp_flower_unlink_flows(struct nfp_fl_payload *merge_flow, 706 + struct nfp_fl_payload *sub_flow) 707 + { 708 + struct nfp_fl_payload_link *link; 709 + 710 + list_for_each_entry(link, &merge_flow->linked_flows, merge_flow.list) 711 + if (link->sub_flow.flow == sub_flow) { 712 + nfp_flower_unlink_flow(link); 713 + return; 714 + } 715 + } 716 + 717 + static int nfp_flower_link_flows(struct nfp_fl_payload *merge_flow, 718 + struct nfp_fl_payload *sub_flow) 719 + { 720 + struct nfp_fl_payload_link *link; 721 + 722 + link = kmalloc(sizeof(*link), GFP_KERNEL); 723 + if (!link) 724 + return -ENOMEM; 725 + 726 + link->merge_flow.flow = merge_flow; 727 + list_add_tail(&link->merge_flow.list, &merge_flow->linked_flows); 728 + link->sub_flow.flow = sub_flow; 729 + list_add_tail(&link->sub_flow.list, &sub_flow->linked_flows); 730 + 731 + return 0; 732 + } 733 + 734 + /** 735 + * nfp_flower_merge_offloaded_flows() - Merge 2 existing flows to single flow. 736 + * @app: Pointer to the APP handle 737 + * @sub_flow1: Initial flow matched to produce merge hint 738 + * @sub_flow2: Post recirculation flow matched in merge hint 739 + * 740 + * Combines 2 flows (if valid) to a single flow, removing the initial from hw 741 + * and offloading the new, merged flow. 742 + * 743 + * Return: negative value on error, 0 in success. 744 + */ 745 + int nfp_flower_merge_offloaded_flows(struct nfp_app *app, 746 + struct nfp_fl_payload *sub_flow1, 747 + struct nfp_fl_payload *sub_flow2) 748 + { 749 + struct tc_cls_flower_offload merge_tc_off; 750 + struct nfp_flower_priv *priv = app->priv; 751 + struct nfp_fl_payload *merge_flow; 752 + struct nfp_fl_key_ls merge_key_ls; 753 + int err; 754 + 755 + ASSERT_RTNL(); 756 + 757 + if (sub_flow1 == sub_flow2 || 758 + nfp_flower_is_merge_flow(sub_flow1) || 759 + nfp_flower_is_merge_flow(sub_flow2)) 760 + return -EINVAL; 761 + 762 + err = nfp_flower_can_merge(sub_flow1, sub_flow2); 763 + if (err) 764 + return err; 765 + 766 + merge_key_ls.key_size = sub_flow1->meta.key_len; 767 + 768 + merge_flow = nfp_flower_allocate_new(&merge_key_ls); 769 + if (!merge_flow) 770 + return -ENOMEM; 771 + 772 + merge_flow->tc_flower_cookie = (unsigned long)merge_flow; 773 + merge_flow->ingress_dev = sub_flow1->ingress_dev; 774 + 775 + memcpy(merge_flow->unmasked_data, sub_flow1->unmasked_data, 776 + sub_flow1->meta.key_len); 777 + memcpy(merge_flow->mask_data, sub_flow1->mask_data, 778 + sub_flow1->meta.mask_len); 779 + 780 + err = nfp_flower_merge_action(sub_flow1, sub_flow2, merge_flow); 781 + if (err) 782 + goto err_destroy_merge_flow; 783 + 784 + err = nfp_flower_link_flows(merge_flow, sub_flow1); 785 + if (err) 786 + goto err_destroy_merge_flow; 787 + 788 + err = nfp_flower_link_flows(merge_flow, sub_flow2); 789 + if (err) 790 + goto err_unlink_sub_flow1; 791 + 792 + merge_tc_off.cookie = merge_flow->tc_flower_cookie; 793 + err = nfp_compile_flow_metadata(app, &merge_tc_off, merge_flow, 794 + merge_flow->ingress_dev); 795 + if (err) 796 + goto err_unlink_sub_flow2; 797 + 798 + err = rhashtable_insert_fast(&priv->flow_table, &merge_flow->fl_node, 799 + nfp_flower_table_params); 800 + if (err) 801 + goto err_release_metadata; 802 + 803 + err = nfp_flower_xmit_flow(app, merge_flow, 804 + NFP_FLOWER_CMSG_TYPE_FLOW_MOD); 805 + if (err) 806 + goto err_remove_rhash; 807 + 808 + merge_flow->in_hw = true; 809 + sub_flow1->in_hw = false; 810 + 811 + return 0; 812 + 813 + err_remove_rhash: 814 + WARN_ON_ONCE(rhashtable_remove_fast(&priv->flow_table, 815 + &merge_flow->fl_node, 816 + nfp_flower_table_params)); 817 + err_release_metadata: 818 + nfp_modify_flow_metadata(app, merge_flow); 819 + err_unlink_sub_flow2: 820 + nfp_flower_unlink_flows(merge_flow, sub_flow2); 821 + err_unlink_sub_flow1: 822 + nfp_flower_unlink_flows(merge_flow, sub_flow1); 823 + err_destroy_merge_flow: 824 + kfree(merge_flow->action_data); 825 + kfree(merge_flow->mask_data); 826 + kfree(merge_flow->unmasked_data); 827 + kfree(merge_flow); 828 + return err; 413 829 } 414 830 415 831 /** ··· 918 454 if (port) 919 455 port->tc_offload_cnt++; 920 456 457 + flow_pay->in_hw = true; 458 + 921 459 /* Deallocate flow payload when flower rule has been destroyed. */ 922 460 kfree(key_layer); 923 461 ··· 941 475 return err; 942 476 } 943 477 478 + static void 479 + nfp_flower_remove_merge_flow(struct nfp_app *app, 480 + struct nfp_fl_payload *del_sub_flow, 481 + struct nfp_fl_payload *merge_flow) 482 + { 483 + struct nfp_flower_priv *priv = app->priv; 484 + struct nfp_fl_payload_link *link, *temp; 485 + struct nfp_fl_payload *origin; 486 + bool mod = false; 487 + int err; 488 + 489 + link = list_first_entry(&merge_flow->linked_flows, 490 + struct nfp_fl_payload_link, merge_flow.list); 491 + origin = link->sub_flow.flow; 492 + 493 + /* Re-add rule the merge had overwritten if it has not been deleted. */ 494 + if (origin != del_sub_flow) 495 + mod = true; 496 + 497 + err = nfp_modify_flow_metadata(app, merge_flow); 498 + if (err) { 499 + nfp_flower_cmsg_warn(app, "Metadata fail for merge flow delete.\n"); 500 + goto err_free_links; 501 + } 502 + 503 + if (!mod) { 504 + err = nfp_flower_xmit_flow(app, merge_flow, 505 + NFP_FLOWER_CMSG_TYPE_FLOW_DEL); 506 + if (err) { 507 + nfp_flower_cmsg_warn(app, "Failed to delete merged flow.\n"); 508 + goto err_free_links; 509 + } 510 + } else { 511 + __nfp_modify_flow_metadata(priv, origin); 512 + err = nfp_flower_xmit_flow(app, origin, 513 + NFP_FLOWER_CMSG_TYPE_FLOW_MOD); 514 + if (err) 515 + nfp_flower_cmsg_warn(app, "Failed to revert merge flow.\n"); 516 + origin->in_hw = true; 517 + } 518 + 519 + err_free_links: 520 + /* Clean any links connected with the merged flow. */ 521 + list_for_each_entry_safe(link, temp, &merge_flow->linked_flows, 522 + merge_flow.list) 523 + nfp_flower_unlink_flow(link); 524 + 525 + kfree(merge_flow->action_data); 526 + kfree(merge_flow->mask_data); 527 + kfree(merge_flow->unmasked_data); 528 + WARN_ON_ONCE(rhashtable_remove_fast(&priv->flow_table, 529 + &merge_flow->fl_node, 530 + nfp_flower_table_params)); 531 + kfree_rcu(merge_flow, rcu); 532 + } 533 + 534 + static void 535 + nfp_flower_del_linked_merge_flows(struct nfp_app *app, 536 + struct nfp_fl_payload *sub_flow) 537 + { 538 + struct nfp_fl_payload_link *link, *temp; 539 + 540 + /* Remove any merge flow formed from the deleted sub_flow. */ 541 + list_for_each_entry_safe(link, temp, &sub_flow->linked_flows, 542 + sub_flow.list) 543 + nfp_flower_remove_merge_flow(app, sub_flow, 544 + link->merge_flow.flow); 545 + } 546 + 944 547 /** 945 548 * nfp_flower_del_offload() - Removes a flow from hardware. 946 549 * @app: Pointer to the APP handle ··· 1017 482 * @flow: TC flower classifier offload structure 1018 483 * 1019 484 * Removes a flow from the repeated hash structure and clears the 1020 - * action payload. 485 + * action payload. Any flows merged from this are also deleted. 1021 486 * 1022 487 * Return: negative value on error, 0 if removed successfully. 1023 488 */ ··· 1039 504 1040 505 err = nfp_modify_flow_metadata(app, nfp_flow); 1041 506 if (err) 1042 - goto err_free_flow; 507 + goto err_free_merge_flow; 1043 508 1044 509 if (nfp_flow->nfp_tun_ipv4_addr) 1045 510 nfp_tunnel_del_ipv4_off(app, nfp_flow->nfp_tun_ipv4_addr); 1046 511 512 + if (!nfp_flow->in_hw) { 513 + err = 0; 514 + goto err_free_merge_flow; 515 + } 516 + 1047 517 err = nfp_flower_xmit_flow(app, nfp_flow, 1048 518 NFP_FLOWER_CMSG_TYPE_FLOW_DEL); 1049 - if (err) 1050 - goto err_free_flow; 519 + /* Fall through on error. */ 1051 520 1052 - err_free_flow: 521 + err_free_merge_flow: 522 + nfp_flower_del_linked_merge_flows(app, nfp_flow); 1053 523 if (port) 1054 524 port->tc_offload_cnt--; 1055 525 kfree(nfp_flow->action_data); ··· 1065 525 nfp_flower_table_params)); 1066 526 kfree_rcu(nfp_flow, rcu); 1067 527 return err; 528 + } 529 + 530 + static void 531 + __nfp_flower_update_merge_stats(struct nfp_app *app, 532 + struct nfp_fl_payload *merge_flow) 533 + { 534 + struct nfp_flower_priv *priv = app->priv; 535 + struct nfp_fl_payload_link *link; 536 + struct nfp_fl_payload *sub_flow; 537 + u64 pkts, bytes, used; 538 + u32 ctx_id; 539 + 540 + ctx_id = be32_to_cpu(merge_flow->meta.host_ctx_id); 541 + pkts = priv->stats[ctx_id].pkts; 542 + /* Do not cycle subflows if no stats to distribute. */ 543 + if (!pkts) 544 + return; 545 + bytes = priv->stats[ctx_id].bytes; 546 + used = priv->stats[ctx_id].used; 547 + 548 + /* Reset stats for the merge flow. */ 549 + priv->stats[ctx_id].pkts = 0; 550 + priv->stats[ctx_id].bytes = 0; 551 + 552 + /* The merge flow has received stats updates from firmware. 553 + * Distribute these stats to all subflows that form the merge. 554 + * The stats will collected from TC via the subflows. 555 + */ 556 + list_for_each_entry(link, &merge_flow->linked_flows, merge_flow.list) { 557 + sub_flow = link->sub_flow.flow; 558 + ctx_id = be32_to_cpu(sub_flow->meta.host_ctx_id); 559 + priv->stats[ctx_id].pkts += pkts; 560 + priv->stats[ctx_id].bytes += bytes; 561 + max_t(u64, priv->stats[ctx_id].used, used); 562 + } 563 + } 564 + 565 + static void 566 + nfp_flower_update_merge_stats(struct nfp_app *app, 567 + struct nfp_fl_payload *sub_flow) 568 + { 569 + struct nfp_fl_payload_link *link; 570 + 571 + /* Get merge flows that the subflow forms to distribute their stats. */ 572 + list_for_each_entry(link, &sub_flow->linked_flows, sub_flow.list) 573 + __nfp_flower_update_merge_stats(app, link->merge_flow.flow); 1068 574 } 1069 575 1070 576 /** ··· 1139 553 ctx_id = be32_to_cpu(nfp_flow->meta.host_ctx_id); 1140 554 1141 555 spin_lock_bh(&priv->stats_lock); 556 + /* If request is for a sub_flow, update stats from merged flows. */ 557 + if (!list_empty(&nfp_flow->linked_flows)) 558 + nfp_flower_update_merge_stats(app, nfp_flow); 559 + 1142 560 flow_stats_update(&flow->stats, priv->stats[ctx_id].bytes, 1143 561 priv->stats[ctx_id].pkts, priv->stats[ctx_id].used); 1144 562 ··· 1272 682 struct nfp_flower_priv *priv = app->priv; 1273 683 int err; 1274 684 1275 - if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS) 685 + if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS && 686 + !(f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS && 687 + nfp_flower_internal_port_can_offload(app, netdev))) 1276 688 return -EOPNOTSUPP; 1277 689 1278 690 switch (f->command) {
+6 -5
drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
··· 171 171 for (i = 0; i < count; i++) { 172 172 ipv4_addr = payload->tun_info[i].ipv4; 173 173 port = be32_to_cpu(payload->tun_info[i].egress_port); 174 - netdev = nfp_app_repr_get(app, port); 174 + netdev = nfp_app_dev_get(app, port, NULL); 175 175 if (!netdev) 176 176 continue; 177 177 ··· 270 270 struct flowi4 *flow, struct neighbour *neigh, gfp_t flag) 271 271 { 272 272 struct nfp_tun_neigh payload; 273 + u32 port_id; 273 274 274 - /* Only offload representor IPv4s for now. */ 275 - if (!nfp_netdev_is_nfp_repr(netdev)) 275 + port_id = nfp_flower_get_port_id_from_netdev(app, netdev); 276 + if (!port_id) 276 277 return; 277 278 278 279 memset(&payload, 0, sizeof(struct nfp_tun_neigh)); ··· 291 290 payload.src_ipv4 = flow->saddr; 292 291 ether_addr_copy(payload.src_addr, netdev->dev_addr); 293 292 neigh_ha_snapshot(payload.dst_addr, neigh, netdev); 294 - payload.port_id = cpu_to_be32(nfp_repr_get_port_id(netdev)); 293 + payload.port_id = cpu_to_be32(port_id); 295 294 /* Add destination of new route to NFP cache. */ 296 295 nfp_tun_add_route_to_cache(app, payload.dst_ipv4); 297 296 ··· 367 366 368 367 payload = nfp_flower_cmsg_get_data(skb); 369 368 370 - netdev = nfp_app_repr_get(app, be32_to_cpu(payload->ingress_port)); 369 + netdev = nfp_app_dev_get(app, be32_to_cpu(payload->ingress_port), NULL); 371 370 if (!netdev) 372 371 goto route_fail_warning; 373 372
+8 -5
drivers/net/ethernet/netronome/nfp/nfp_app.h
··· 79 79 * @eswitch_mode_set: set SR-IOV eswitch mode (under pf->lock) 80 80 * @sriov_enable: app-specific sriov initialisation 81 81 * @sriov_disable: app-specific sriov clean-up 82 - * @repr_get: get representor netdev 82 + * @dev_get: get representor or internal port representing netdev 83 83 */ 84 84 struct nfp_app_type { 85 85 enum nfp_app_id id; ··· 143 143 144 144 enum devlink_eswitch_mode (*eswitch_mode_get)(struct nfp_app *app); 145 145 int (*eswitch_mode_set)(struct nfp_app *app, u16 mode); 146 - struct net_device *(*repr_get)(struct nfp_app *app, u32 id); 146 + struct net_device *(*dev_get)(struct nfp_app *app, u32 id, 147 + bool *redir_egress); 147 148 }; 148 149 149 150 /** ··· 398 397 app->type->sriov_disable(app); 399 398 } 400 399 401 - static inline struct net_device *nfp_app_repr_get(struct nfp_app *app, u32 id) 400 + static inline 401 + struct net_device *nfp_app_dev_get(struct nfp_app *app, u32 id, 402 + bool *redir_egress) 402 403 { 403 - if (unlikely(!app || !app->type->repr_get)) 404 + if (unlikely(!app || !app->type->dev_get)) 404 405 return NULL; 405 406 406 - return app->type->repr_get(app, id); 407 + return app->type->dev_get(app, id, redir_egress); 407 408 } 408 409 409 410 struct nfp_app *nfp_app_from_netdev(struct net_device *netdev);
+13 -3
drivers/net/ethernet/netronome/nfp/nfp_net_common.c
··· 1683 1683 struct nfp_net_rx_buf *rxbuf; 1684 1684 struct nfp_net_rx_desc *rxd; 1685 1685 struct nfp_meta_parsed meta; 1686 + bool redir_egress = false; 1686 1687 struct net_device *netdev; 1687 1688 dma_addr_t new_dma_addr; 1688 1689 u32 meta_len_xdp = 0; ··· 1819 1818 struct nfp_net *nn; 1820 1819 1821 1820 nn = netdev_priv(dp->netdev); 1822 - netdev = nfp_app_repr_get(nn->app, meta.portid); 1821 + netdev = nfp_app_dev_get(nn->app, meta.portid, 1822 + &redir_egress); 1823 1823 if (unlikely(!netdev)) { 1824 1824 nfp_net_rx_drop(dp, r_vec, rx_ring, rxbuf, 1825 1825 NULL); 1826 1826 continue; 1827 1827 } 1828 - nfp_repr_inc_rx_stats(netdev, pkt_len); 1828 + 1829 + if (nfp_netdev_is_nfp_repr(netdev)) 1830 + nfp_repr_inc_rx_stats(netdev, pkt_len); 1829 1831 } 1830 1832 1831 1833 skb = build_skb(rxbuf->frag, true_bufsz); ··· 1863 1859 if (meta_len_xdp) 1864 1860 skb_metadata_set(skb, meta_len_xdp); 1865 1861 1866 - napi_gro_receive(&rx_ring->r_vec->napi, skb); 1862 + if (likely(!redir_egress)) { 1863 + napi_gro_receive(&rx_ring->r_vec->napi, skb); 1864 + } else { 1865 + skb->dev = netdev; 1866 + __skb_push(skb, ETH_HLEN); 1867 + dev_queue_xmit(skb); 1868 + } 1867 1869 } 1868 1870 1869 1871 if (xdp_prog) {