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

Merge tag 'mlx5-updates-2018-01-08' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux

mlx5-updates-2018-01-08

Four patches from Or that add Hairpin support to mlx5:
===========================================================
From: Or Gerlitz <ogerlitz@mellanox.com>

We refer the ability of NIC HW to fwd packet received on one port to
the other port (also from a port to itself) as hairpin. The application API
is based
on ingress tc/flower rules set on the NIC with the mirred redirect
action. Other actions can apply to packets during the redirect.

Hairpin allows to offload the data-path of various SW DDoS gateways,
load-balancers, etc to HW. Packets go through all the required
processing in HW (header re-write, encap/decap, push/pop vlan) and
then forwarded, CPU stays at practically zero usage. HW Flow counters
are used by the control plane for monitoring and accounting.

Hairpin is implemented by pairing a receive queue (RQ) to send queue (SQ).
All the flows that share <recv NIC, mirred NIC> are redirected through
the same hairpin pair. Currently, only header-rewrite is supported as a
packet modification action.

I'd like to thanks Elijah Shakkour <elijahs@mellanox.com> for implementing this
functionality
on HW simulator, before it was avail in the FW so the driver code could be
tested early.
===========================================================

From Feras three patches that provide very small changes that allow IPoIB
to support RX timestamping for child interfaces, simply by hooking the mlx5e
timestamping PTP ioctl to IPoIB child interface netdev profile.

One patch from Gal to fix a spilling mistake.

Two patches from Eugenia adds drop counters to VF statistics
to be reported as part of VF statistics in netlink (iproute2) and
implemented them in mlx5 eswitch.

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

+649 -27
+1
drivers/net/ethernet/mellanox/mlx5/core/en.h
··· 659 659 struct rhashtable ht; 660 660 661 661 DECLARE_HASHTABLE(mod_hdr_tbl, 8); 662 + DECLARE_HASHTABLE(hairpin_tbl, 8); 662 663 }; 663 664 664 665 struct mlx5e_vlan_table {
+6 -1
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
··· 1175 1175 u32 cqe_bcnt, 1176 1176 struct sk_buff *skb) 1177 1177 { 1178 + struct hwtstamp_config *tstamp; 1178 1179 struct net_device *netdev; 1180 + struct mlx5e_priv *priv; 1179 1181 char *pseudo_header; 1180 1182 u32 qpn; 1181 1183 u8 *dgid; ··· 1195 1193 pr_warn_once("Unable to map QPN %u to dev - dropping skb\n", qpn); 1196 1194 return; 1197 1195 } 1196 + 1197 + priv = mlx5i_epriv(netdev); 1198 + tstamp = &priv->tstamp; 1198 1199 1199 1200 g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3; 1200 1201 dgid = skb->data + MLX5_IB_GRH_DGID_OFFSET; ··· 1219 1214 skb->ip_summed = CHECKSUM_COMPLETE; 1220 1215 skb->csum = csum_unfold((__force __sum16)cqe->check_sum); 1221 1216 1222 - if (unlikely(mlx5e_rx_hw_stamp(rq->tstamp))) 1217 + if (unlikely(mlx5e_rx_hw_stamp(tstamp))) 1223 1218 skb_hwtstamps(skb)->hwtstamp = 1224 1219 mlx5_timecounter_cyc2time(rq->clock, get_cqe_ts(cqe)); 1225 1220
+268 -12
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
··· 56 56 u32 action; 57 57 u32 flow_tag; 58 58 u32 mod_hdr_id; 59 + u32 hairpin_tirn; 59 60 }; 60 61 61 62 enum { 62 63 MLX5E_TC_FLOW_ESWITCH = BIT(0), 63 64 MLX5E_TC_FLOW_NIC = BIT(1), 64 65 MLX5E_TC_FLOW_OFFLOADED = BIT(2), 66 + MLX5E_TC_FLOW_HAIRPIN = BIT(3), 65 67 }; 66 68 67 69 struct mlx5e_tc_flow { ··· 73 71 struct mlx5_flow_handle *rule; 74 72 struct list_head encap; /* flows sharing the same encap ID */ 75 73 struct list_head mod_hdr; /* flows sharing the same mod hdr ID */ 74 + struct list_head hairpin; /* flows sharing the same hairpin */ 76 75 union { 77 76 struct mlx5_esw_flow_attr esw_attr[0]; 78 77 struct mlx5_nic_flow_attr nic_attr[0]; ··· 95 92 96 93 #define MLX5E_TC_TABLE_NUM_GROUPS 4 97 94 #define MLX5E_TC_TABLE_MAX_GROUP_SIZE (1 << 16) 95 + 96 + struct mlx5e_hairpin { 97 + struct mlx5_hairpin *pair; 98 + 99 + struct mlx5_core_dev *func_mdev; 100 + u32 tdn; 101 + u32 tirn; 102 + }; 103 + 104 + struct mlx5e_hairpin_entry { 105 + /* a node of a hash table which keeps all the hairpin entries */ 106 + struct hlist_node hairpin_hlist; 107 + 108 + /* flows sharing the same hairpin */ 109 + struct list_head flows; 110 + 111 + int peer_ifindex; 112 + struct mlx5e_hairpin *hp; 113 + }; 98 114 99 115 struct mod_hdr_key { 100 116 int num_actions; ··· 244 222 } 245 223 } 246 224 225 + static 226 + struct mlx5_core_dev *mlx5e_hairpin_get_mdev(struct net *net, int ifindex) 227 + { 228 + struct net_device *netdev; 229 + struct mlx5e_priv *priv; 230 + 231 + netdev = __dev_get_by_index(net, ifindex); 232 + priv = netdev_priv(netdev); 233 + return priv->mdev; 234 + } 235 + 236 + static int mlx5e_hairpin_create_transport(struct mlx5e_hairpin *hp) 237 + { 238 + u32 in[MLX5_ST_SZ_DW(create_tir_in)] = {0}; 239 + void *tirc; 240 + int err; 241 + 242 + err = mlx5_core_alloc_transport_domain(hp->func_mdev, &hp->tdn); 243 + if (err) 244 + goto alloc_tdn_err; 245 + 246 + tirc = MLX5_ADDR_OF(create_tir_in, in, ctx); 247 + 248 + MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_DIRECT); 249 + MLX5_SET(tirc, tirc, inline_rqn, hp->pair->rqn); 250 + MLX5_SET(tirc, tirc, transport_domain, hp->tdn); 251 + 252 + err = mlx5_core_create_tir(hp->func_mdev, in, MLX5_ST_SZ_BYTES(create_tir_in), &hp->tirn); 253 + if (err) 254 + goto create_tir_err; 255 + 256 + return 0; 257 + 258 + create_tir_err: 259 + mlx5_core_dealloc_transport_domain(hp->func_mdev, hp->tdn); 260 + alloc_tdn_err: 261 + return err; 262 + } 263 + 264 + static void mlx5e_hairpin_destroy_transport(struct mlx5e_hairpin *hp) 265 + { 266 + mlx5_core_destroy_tir(hp->func_mdev, hp->tirn); 267 + mlx5_core_dealloc_transport_domain(hp->func_mdev, hp->tdn); 268 + } 269 + 270 + static struct mlx5e_hairpin * 271 + mlx5e_hairpin_create(struct mlx5e_priv *priv, struct mlx5_hairpin_params *params, 272 + int peer_ifindex) 273 + { 274 + struct mlx5_core_dev *func_mdev, *peer_mdev; 275 + struct mlx5e_hairpin *hp; 276 + struct mlx5_hairpin *pair; 277 + int err; 278 + 279 + hp = kzalloc(sizeof(*hp), GFP_KERNEL); 280 + if (!hp) 281 + return ERR_PTR(-ENOMEM); 282 + 283 + func_mdev = priv->mdev; 284 + peer_mdev = mlx5e_hairpin_get_mdev(dev_net(priv->netdev), peer_ifindex); 285 + 286 + pair = mlx5_core_hairpin_create(func_mdev, peer_mdev, params); 287 + if (IS_ERR(pair)) { 288 + err = PTR_ERR(pair); 289 + goto create_pair_err; 290 + } 291 + hp->pair = pair; 292 + hp->func_mdev = func_mdev; 293 + 294 + err = mlx5e_hairpin_create_transport(hp); 295 + if (err) 296 + goto create_transport_err; 297 + 298 + return hp; 299 + 300 + create_transport_err: 301 + mlx5_core_hairpin_destroy(hp->pair); 302 + create_pair_err: 303 + kfree(hp); 304 + return ERR_PTR(err); 305 + } 306 + 307 + static void mlx5e_hairpin_destroy(struct mlx5e_hairpin *hp) 308 + { 309 + mlx5e_hairpin_destroy_transport(hp); 310 + mlx5_core_hairpin_destroy(hp->pair); 311 + kvfree(hp); 312 + } 313 + 314 + static struct mlx5e_hairpin_entry *mlx5e_hairpin_get(struct mlx5e_priv *priv, 315 + int peer_ifindex) 316 + { 317 + struct mlx5e_hairpin_entry *hpe; 318 + 319 + hash_for_each_possible(priv->fs.tc.hairpin_tbl, hpe, 320 + hairpin_hlist, peer_ifindex) { 321 + if (hpe->peer_ifindex == peer_ifindex) 322 + return hpe; 323 + } 324 + 325 + return NULL; 326 + } 327 + 328 + static int mlx5e_hairpin_flow_add(struct mlx5e_priv *priv, 329 + struct mlx5e_tc_flow *flow, 330 + struct mlx5e_tc_flow_parse_attr *parse_attr) 331 + { 332 + int peer_ifindex = parse_attr->mirred_ifindex; 333 + struct mlx5_hairpin_params params; 334 + struct mlx5e_hairpin_entry *hpe; 335 + struct mlx5e_hairpin *hp; 336 + int err; 337 + 338 + if (!MLX5_CAP_GEN(priv->mdev, hairpin)) { 339 + netdev_warn(priv->netdev, "hairpin is not supported\n"); 340 + return -EOPNOTSUPP; 341 + } 342 + 343 + hpe = mlx5e_hairpin_get(priv, peer_ifindex); 344 + if (hpe) 345 + goto attach_flow; 346 + 347 + hpe = kzalloc(sizeof(*hpe), GFP_KERNEL); 348 + if (!hpe) 349 + return -ENOMEM; 350 + 351 + INIT_LIST_HEAD(&hpe->flows); 352 + hpe->peer_ifindex = peer_ifindex; 353 + 354 + params.log_data_size = 15; 355 + params.log_data_size = min_t(u8, params.log_data_size, 356 + MLX5_CAP_GEN(priv->mdev, log_max_hairpin_wq_data_sz)); 357 + params.log_data_size = max_t(u8, params.log_data_size, 358 + MLX5_CAP_GEN(priv->mdev, log_min_hairpin_wq_data_sz)); 359 + params.q_counter = priv->q_counter; 360 + 361 + hp = mlx5e_hairpin_create(priv, &params, peer_ifindex); 362 + if (IS_ERR(hp)) { 363 + err = PTR_ERR(hp); 364 + goto create_hairpin_err; 365 + } 366 + 367 + netdev_dbg(priv->netdev, "add hairpin: tirn %x rqn %x peer %s sqn %x log data size %d\n", 368 + hp->tirn, hp->pair->rqn, hp->pair->peer_mdev->priv.name, 369 + hp->pair->sqn, params.log_data_size); 370 + 371 + hpe->hp = hp; 372 + hash_add(priv->fs.tc.hairpin_tbl, &hpe->hairpin_hlist, peer_ifindex); 373 + 374 + attach_flow: 375 + flow->nic_attr->hairpin_tirn = hpe->hp->tirn; 376 + list_add(&flow->hairpin, &hpe->flows); 377 + return 0; 378 + 379 + create_hairpin_err: 380 + kfree(hpe); 381 + return err; 382 + } 383 + 384 + static void mlx5e_hairpin_flow_del(struct mlx5e_priv *priv, 385 + struct mlx5e_tc_flow *flow) 386 + { 387 + struct list_head *next = flow->hairpin.next; 388 + 389 + list_del(&flow->hairpin); 390 + 391 + /* no more hairpin flows for us, release the hairpin pair */ 392 + if (list_empty(next)) { 393 + struct mlx5e_hairpin_entry *hpe; 394 + 395 + hpe = list_entry(next, struct mlx5e_hairpin_entry, flows); 396 + 397 + netdev_dbg(priv->netdev, "del hairpin: peer %s\n", 398 + hpe->hp->pair->peer_mdev->priv.name); 399 + 400 + mlx5e_hairpin_destroy(hpe->hp); 401 + hash_del(&hpe->hairpin_hlist); 402 + kfree(hpe); 403 + } 404 + } 405 + 247 406 static struct mlx5_flow_handle * 248 407 mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, 249 408 struct mlx5e_tc_flow_parse_attr *parse_attr, ··· 432 229 { 433 230 struct mlx5_nic_flow_attr *attr = flow->nic_attr; 434 231 struct mlx5_core_dev *dev = priv->mdev; 435 - struct mlx5_flow_destination dest = {}; 232 + struct mlx5_flow_destination dest[2] = {}; 436 233 struct mlx5_flow_act flow_act = { 437 234 .action = attr->action, 438 235 .flow_tag = attr->flow_tag, ··· 441 238 struct mlx5_fc *counter = NULL; 442 239 struct mlx5_flow_handle *rule; 443 240 bool table_created = false; 444 - int err; 241 + int err, dest_ix = 0; 445 242 446 243 if (attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { 447 - dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; 448 - dest.ft = priv->fs.vlan.ft.t; 449 - } else if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { 450 - counter = mlx5_fc_create(dev, true); 451 - if (IS_ERR(counter)) 452 - return ERR_CAST(counter); 244 + if (flow->flags & MLX5E_TC_FLOW_HAIRPIN) { 245 + err = mlx5e_hairpin_flow_add(priv, flow, parse_attr); 246 + if (err) { 247 + rule = ERR_PTR(err); 248 + goto err_add_hairpin_flow; 249 + } 250 + dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_TIR; 251 + dest[dest_ix].tir_num = attr->hairpin_tirn; 252 + } else { 253 + dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; 254 + dest[dest_ix].ft = priv->fs.vlan.ft.t; 255 + } 256 + dest_ix++; 257 + } 453 258 454 - dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; 455 - dest.counter = counter; 259 + if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { 260 + counter = mlx5_fc_create(dev, true); 261 + if (IS_ERR(counter)) { 262 + rule = ERR_CAST(counter); 263 + goto err_fc_create; 264 + } 265 + dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; 266 + dest[dest_ix].counter = counter; 267 + dest_ix++; 456 268 } 457 269 458 270 if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) { ··· 510 292 511 293 parse_attr->spec.match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 512 294 rule = mlx5_add_flow_rules(priv->fs.tc.t, &parse_attr->spec, 513 - &flow_act, &dest, 1); 295 + &flow_act, dest, dest_ix); 514 296 515 297 if (IS_ERR(rule)) 516 298 goto err_add_rule; ··· 527 309 mlx5e_detach_mod_hdr(priv, flow); 528 310 err_create_mod_hdr_id: 529 311 mlx5_fc_destroy(dev, counter); 530 - 312 + err_fc_create: 313 + if (flow->flags & MLX5E_TC_FLOW_HAIRPIN) 314 + mlx5e_hairpin_flow_del(priv, flow); 315 + err_add_hairpin_flow: 531 316 return rule; 532 317 } 533 318 ··· 551 330 552 331 if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) 553 332 mlx5e_detach_mod_hdr(priv, flow); 333 + 334 + if (flow->flags & MLX5E_TC_FLOW_HAIRPIN) 335 + mlx5e_hairpin_flow_del(priv, flow); 554 336 } 555 337 556 338 static void mlx5e_detach_encap(struct mlx5e_priv *priv, ··· 1646 1422 return true; 1647 1423 } 1648 1424 1425 + static bool same_hw_devs(struct mlx5e_priv *priv, struct mlx5e_priv *peer_priv) 1426 + { 1427 + struct mlx5_core_dev *fmdev, *pmdev; 1428 + u16 func_id, peer_id; 1429 + 1430 + fmdev = priv->mdev; 1431 + pmdev = peer_priv->mdev; 1432 + 1433 + func_id = (u16)((fmdev->pdev->bus->number << 8) | PCI_SLOT(fmdev->pdev->devfn)); 1434 + peer_id = (u16)((pmdev->pdev->bus->number << 8) | PCI_SLOT(pmdev->pdev->devfn)); 1435 + 1436 + return (func_id == peer_id); 1437 + } 1438 + 1649 1439 static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, 1650 1440 struct mlx5e_tc_flow_parse_attr *parse_attr, 1651 1441 struct mlx5e_tc_flow *flow) ··· 1702 1464 continue; 1703 1465 1704 1466 return -EOPNOTSUPP; 1467 + } 1468 + 1469 + if (is_tcf_mirred_egress_redirect(a)) { 1470 + struct net_device *peer_dev = tcf_mirred_dev(a); 1471 + 1472 + if (priv->netdev->netdev_ops == peer_dev->netdev_ops && 1473 + same_hw_devs(priv, netdev_priv(peer_dev))) { 1474 + parse_attr->mirred_ifindex = peer_dev->ifindex; 1475 + flow->flags |= MLX5E_TC_FLOW_HAIRPIN; 1476 + attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | 1477 + MLX5_FLOW_CONTEXT_ACTION_COUNT; 1478 + } else { 1479 + netdev_warn(priv->netdev, "device %s not on same HW, can't offload\n", 1480 + peer_dev->name); 1481 + return -EINVAL; 1482 + } 1483 + continue; 1705 1484 } 1706 1485 1707 1486 if (is_tcf_skbedit_mark(a)) { ··· 2443 2188 struct mlx5e_tc_table *tc = &priv->fs.tc; 2444 2189 2445 2190 hash_init(tc->mod_hdr_tbl); 2191 + hash_init(tc->hairpin_tbl); 2446 2192 2447 2193 tc->ht_params = mlx5e_tc_flow_ht_params; 2448 2194 return rhashtable_init(&tc->ht, &tc->ht_params);
+97 -2
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
··· 37 37 #include <linux/mlx5/fs.h> 38 38 #include "mlx5_core.h" 39 39 #include "eswitch.h" 40 + #include "fs_core.h" 40 41 41 42 #define UPLINK_VPORT 0xFFFF 42 43 ··· 1124 1123 static int esw_vport_ingress_config(struct mlx5_eswitch *esw, 1125 1124 struct mlx5_vport *vport) 1126 1125 { 1126 + struct mlx5_fc *counter = vport->ingress.drop_counter; 1127 + struct mlx5_flow_destination drop_ctr_dst = {0}; 1128 + struct mlx5_flow_destination *dst = NULL; 1127 1129 struct mlx5_flow_act flow_act = {0}; 1128 1130 struct mlx5_flow_spec *spec; 1131 + int dest_num = 0; 1129 1132 int err = 0; 1130 1133 u8 *smac_v; 1131 1134 ··· 1193 1188 1194 1189 memset(spec, 0, sizeof(*spec)); 1195 1190 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP; 1191 + 1192 + /* Attach drop flow counter */ 1193 + if (counter) { 1194 + flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT; 1195 + drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; 1196 + drop_ctr_dst.counter = counter; 1197 + dst = &drop_ctr_dst; 1198 + dest_num++; 1199 + } 1196 1200 vport->ingress.drop_rule = 1197 1201 mlx5_add_flow_rules(vport->ingress.acl, spec, 1198 - &flow_act, NULL, 0); 1202 + &flow_act, dst, dest_num); 1199 1203 if (IS_ERR(vport->ingress.drop_rule)) { 1200 1204 err = PTR_ERR(vport->ingress.drop_rule); 1201 1205 esw_warn(esw->dev, ··· 1224 1210 static int esw_vport_egress_config(struct mlx5_eswitch *esw, 1225 1211 struct mlx5_vport *vport) 1226 1212 { 1213 + struct mlx5_fc *counter = vport->egress.drop_counter; 1214 + struct mlx5_flow_destination drop_ctr_dst = {0}; 1215 + struct mlx5_flow_destination *dst = NULL; 1227 1216 struct mlx5_flow_act flow_act = {0}; 1228 1217 struct mlx5_flow_spec *spec; 1218 + int dest_num = 0; 1229 1219 int err = 0; 1230 1220 1231 1221 esw_vport_cleanup_egress_rules(esw, vport); ··· 1280 1262 /* Drop others rule (star rule) */ 1281 1263 memset(spec, 0, sizeof(*spec)); 1282 1264 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP; 1265 + 1266 + /* Attach egress drop flow counter */ 1267 + if (counter) { 1268 + flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT; 1269 + drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; 1270 + drop_ctr_dst.counter = counter; 1271 + dst = &drop_ctr_dst; 1272 + dest_num++; 1273 + } 1283 1274 vport->egress.drop_rule = 1284 1275 mlx5_add_flow_rules(vport->egress.acl, spec, 1285 - &flow_act, NULL, 0); 1276 + &flow_act, dst, dest_num); 1286 1277 if (IS_ERR(vport->egress.drop_rule)) { 1287 1278 err = PTR_ERR(vport->egress.drop_rule); 1288 1279 esw_warn(esw->dev, ··· 1484 1457 } 1485 1458 } 1486 1459 1460 + static void esw_vport_create_drop_counters(struct mlx5_vport *vport) 1461 + { 1462 + struct mlx5_core_dev *dev = vport->dev; 1463 + 1464 + if (MLX5_CAP_ESW_INGRESS_ACL(dev, flow_counter)) { 1465 + vport->ingress.drop_counter = mlx5_fc_create(dev, false); 1466 + if (IS_ERR(vport->ingress.drop_counter)) { 1467 + esw_warn(dev, 1468 + "vport[%d] configure ingress drop rule counter failed\n", 1469 + vport->vport); 1470 + vport->ingress.drop_counter = NULL; 1471 + } 1472 + } 1473 + 1474 + if (MLX5_CAP_ESW_EGRESS_ACL(dev, flow_counter)) { 1475 + vport->egress.drop_counter = mlx5_fc_create(dev, false); 1476 + if (IS_ERR(vport->egress.drop_counter)) { 1477 + esw_warn(dev, 1478 + "vport[%d] configure egress drop rule counter failed\n", 1479 + vport->vport); 1480 + vport->egress.drop_counter = NULL; 1481 + } 1482 + } 1483 + } 1484 + 1485 + static void esw_vport_destroy_drop_counters(struct mlx5_vport *vport) 1486 + { 1487 + struct mlx5_core_dev *dev = vport->dev; 1488 + 1489 + if (vport->ingress.drop_counter) 1490 + mlx5_fc_destroy(dev, vport->ingress.drop_counter); 1491 + if (vport->egress.drop_counter) 1492 + mlx5_fc_destroy(dev, vport->egress.drop_counter); 1493 + } 1494 + 1487 1495 static void esw_enable_vport(struct mlx5_eswitch *esw, int vport_num, 1488 1496 int enable_events) 1489 1497 { ··· 1544 1482 /* only PF is trusted by default */ 1545 1483 if (!vport_num) 1546 1484 vport->info.trusted = true; 1485 + 1486 + /* create steering drop counters for ingress and egress ACLs */ 1487 + if (vport_num && esw->mode == SRIOV_LEGACY) 1488 + esw_vport_create_drop_counters(vport); 1547 1489 1548 1490 esw_vport_change_handle_locked(vport); 1549 1491 ··· 1587 1521 MLX5_ESW_VPORT_ADMIN_STATE_DOWN); 1588 1522 esw_vport_disable_egress_acl(esw, vport); 1589 1523 esw_vport_disable_ingress_acl(esw, vport); 1524 + esw_vport_destroy_drop_counters(vport); 1590 1525 } 1591 1526 esw->enabled_vports--; 1592 1527 mutex_unlock(&esw->state_lock); ··· 2083 2016 return err; 2084 2017 } 2085 2018 2019 + static void mlx5_eswitch_query_vport_drop_stats(struct mlx5_core_dev *dev, 2020 + int vport_idx, 2021 + struct mlx5_vport_drop_stats *stats) 2022 + { 2023 + struct mlx5_eswitch *esw = dev->priv.eswitch; 2024 + struct mlx5_vport *vport = &esw->vports[vport_idx]; 2025 + u64 bytes = 0; 2026 + u16 idx = 0; 2027 + 2028 + if (!vport->enabled || esw->mode != SRIOV_LEGACY) 2029 + return; 2030 + 2031 + if (vport->egress.drop_counter) { 2032 + idx = vport->egress.drop_counter->id; 2033 + mlx5_fc_query(dev, idx, &stats->rx_dropped, &bytes); 2034 + } 2035 + 2036 + if (vport->ingress.drop_counter) { 2037 + idx = vport->ingress.drop_counter->id; 2038 + mlx5_fc_query(dev, idx, &stats->tx_dropped, &bytes); 2039 + } 2040 + } 2041 + 2086 2042 int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw, 2087 2043 int vport, 2088 2044 struct ifla_vf_stats *vf_stats) 2089 2045 { 2090 2046 int outlen = MLX5_ST_SZ_BYTES(query_vport_counter_out); 2091 2047 u32 in[MLX5_ST_SZ_DW(query_vport_counter_in)] = {0}; 2048 + struct mlx5_vport_drop_stats stats = {0}; 2092 2049 int err = 0; 2093 2050 u32 *out; 2094 2051 ··· 2166 2075 2167 2076 vf_stats->broadcast = 2168 2077 MLX5_GET_CTR(out, received_eth_broadcast.packets); 2078 + 2079 + mlx5_eswitch_query_vport_drop_stats(esw->dev, vport, &stats); 2080 + vf_stats->rx_dropped = stats.rx_dropped; 2081 + vf_stats->tx_dropped = stats.tx_dropped; 2169 2082 2170 2083 free_out: 2171 2084 kvfree(out);
+7
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
··· 73 73 struct mlx5_flow_group *drop_grp; 74 74 struct mlx5_flow_handle *allow_rule; 75 75 struct mlx5_flow_handle *drop_rule; 76 + struct mlx5_fc *drop_counter; 76 77 }; 77 78 78 79 struct vport_egress { ··· 82 81 struct mlx5_flow_group *drop_grp; 83 82 struct mlx5_flow_handle *allowed_vlan; 84 83 struct mlx5_flow_handle *drop_rule; 84 + struct mlx5_fc *drop_counter; 85 + }; 86 + 87 + struct mlx5_vport_drop_stats { 88 + u64 rx_dropped; 89 + u64 tx_dropped; 85 90 }; 86 91 87 92 struct mlx5_vport_info {
+2
drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
··· 233 233 unsigned long delay); 234 234 void mlx5_fc_update_sampling_interval(struct mlx5_core_dev *dev, 235 235 unsigned long interval); 236 + int mlx5_fc_query(struct mlx5_core_dev *dev, u16 id, 237 + u64 *packets, u64 *bytes); 236 238 237 239 int mlx5_init_fs(struct mlx5_core_dev *dev); 238 240 void mlx5_cleanup_fs(struct mlx5_core_dev *dev);
+6
drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
··· 312 312 } 313 313 } 314 314 315 + int mlx5_fc_query(struct mlx5_core_dev *dev, u16 id, 316 + u64 *packets, u64 *bytes) 317 + { 318 + return mlx5_cmd_fc_query(dev, id, packets, bytes); 319 + } 320 + 315 321 void mlx5_fc_query_cached(struct mlx5_fc *counter, 316 322 u64 *bytes, u64 *packets, u64 *lastuse) 317 323 {
+1
drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
··· 254 254 const struct ethtool_ops mlx5i_pkey_ethtool_ops = { 255 255 .get_drvinfo = mlx5i_get_drvinfo, 256 256 .get_link = ethtool_op_get_link, 257 + .get_ts_info = mlx5i_get_ts_info, 257 258 };
+1 -2
drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
··· 41 41 static int mlx5i_open(struct net_device *netdev); 42 42 static int mlx5i_close(struct net_device *netdev); 43 43 static int mlx5i_change_mtu(struct net_device *netdev, int new_mtu); 44 - static int mlx5i_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); 45 44 46 45 static const struct net_device_ops mlx5i_netdev_ops = { 47 46 .ndo_open = mlx5i_open, ··· 395 396 return 0; 396 397 } 397 398 398 - static int mlx5i_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 399 + int mlx5i_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 399 400 { 400 401 struct mlx5e_priv *priv = mlx5i_epriv(dev); 401 402
+2 -1
drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
··· 76 76 /* Get the net-device corresponding to the given underlay QPN */ 77 77 struct net_device *mlx5i_pkey_get_netdev(struct net_device *netdev, u32 qpn); 78 78 79 - /* Shared ndo functionts */ 79 + /* Shared ndo functions */ 80 80 int mlx5i_dev_init(struct net_device *dev); 81 81 void mlx5i_dev_cleanup(struct net_device *dev); 82 + int mlx5i_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); 82 83 83 84 /* Parent profile functions */ 84 85 void mlx5i_init(struct mlx5_core_dev *mdev,
+7
drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
··· 140 140 static int mlx5i_pkey_dev_init(struct net_device *dev); 141 141 static void mlx5i_pkey_dev_cleanup(struct net_device *netdev); 142 142 static int mlx5i_pkey_change_mtu(struct net_device *netdev, int new_mtu); 143 + static int mlx5i_pkey_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); 143 144 144 145 static const struct net_device_ops mlx5i_pkey_netdev_ops = { 145 146 .ndo_open = mlx5i_pkey_open, ··· 148 147 .ndo_init = mlx5i_pkey_dev_init, 149 148 .ndo_uninit = mlx5i_pkey_dev_cleanup, 150 149 .ndo_change_mtu = mlx5i_pkey_change_mtu, 150 + .ndo_do_ioctl = mlx5i_pkey_ioctl, 151 151 }; 152 152 153 153 /* Child NDOs */ ··· 174 172 dev_put(parent_dev); 175 173 176 174 return mlx5i_dev_init(dev); 175 + } 176 + 177 + static int mlx5i_pkey_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 178 + { 179 + return mlx5i_ioctl(dev, ifr, cmd); 177 180 } 178 181 179 182 static void mlx5i_pkey_dev_cleanup(struct net_device *netdev)
+184
drivers/net/ethernet/mellanox/mlx5/core/transobj.c
··· 398 398 mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 399 399 } 400 400 EXPORT_SYMBOL(mlx5_core_destroy_rqt); 401 + 402 + static int mlx5_hairpin_create_rq(struct mlx5_core_dev *mdev, 403 + struct mlx5_hairpin_params *params, u32 *rqn) 404 + { 405 + u32 in[MLX5_ST_SZ_DW(create_rq_in)] = {0}; 406 + void *rqc, *wq; 407 + 408 + rqc = MLX5_ADDR_OF(create_rq_in, in, ctx); 409 + wq = MLX5_ADDR_OF(rqc, rqc, wq); 410 + 411 + MLX5_SET(rqc, rqc, hairpin, 1); 412 + MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RST); 413 + MLX5_SET(rqc, rqc, counter_set_id, params->q_counter); 414 + 415 + MLX5_SET(wq, wq, log_hairpin_data_sz, params->log_data_size); 416 + 417 + return mlx5_core_create_rq(mdev, in, MLX5_ST_SZ_BYTES(create_rq_in), rqn); 418 + } 419 + 420 + static int mlx5_hairpin_create_sq(struct mlx5_core_dev *mdev, 421 + struct mlx5_hairpin_params *params, u32 *sqn) 422 + { 423 + u32 in[MLX5_ST_SZ_DW(create_sq_in)] = {0}; 424 + void *sqc, *wq; 425 + 426 + sqc = MLX5_ADDR_OF(create_sq_in, in, ctx); 427 + wq = MLX5_ADDR_OF(sqc, sqc, wq); 428 + 429 + MLX5_SET(sqc, sqc, hairpin, 1); 430 + MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RST); 431 + 432 + MLX5_SET(wq, wq, log_hairpin_data_sz, params->log_data_size); 433 + 434 + return mlx5_core_create_sq(mdev, in, MLX5_ST_SZ_BYTES(create_sq_in), sqn); 435 + } 436 + 437 + static int mlx5_hairpin_create_queues(struct mlx5_hairpin *hp, 438 + struct mlx5_hairpin_params *params) 439 + { 440 + int err; 441 + 442 + err = mlx5_hairpin_create_rq(hp->func_mdev, params, &hp->rqn); 443 + if (err) 444 + goto out_err_rq; 445 + 446 + err = mlx5_hairpin_create_sq(hp->peer_mdev, params, &hp->sqn); 447 + if (err) 448 + goto out_err_sq; 449 + 450 + return 0; 451 + 452 + out_err_sq: 453 + mlx5_core_destroy_rq(hp->func_mdev, hp->rqn); 454 + out_err_rq: 455 + return err; 456 + } 457 + 458 + static void mlx5_hairpin_destroy_queues(struct mlx5_hairpin *hp) 459 + { 460 + mlx5_core_destroy_rq(hp->func_mdev, hp->rqn); 461 + mlx5_core_destroy_sq(hp->peer_mdev, hp->sqn); 462 + } 463 + 464 + static int mlx5_hairpin_modify_rq(struct mlx5_core_dev *func_mdev, u32 rqn, 465 + int curr_state, int next_state, 466 + u16 peer_vhca, u32 peer_sq) 467 + { 468 + u32 in[MLX5_ST_SZ_DW(modify_rq_in)] = {0}; 469 + void *rqc; 470 + 471 + rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx); 472 + 473 + if (next_state == MLX5_RQC_STATE_RDY) { 474 + MLX5_SET(rqc, rqc, hairpin_peer_sq, peer_sq); 475 + MLX5_SET(rqc, rqc, hairpin_peer_vhca, peer_vhca); 476 + } 477 + 478 + MLX5_SET(modify_rq_in, in, rq_state, curr_state); 479 + MLX5_SET(rqc, rqc, state, next_state); 480 + 481 + return mlx5_core_modify_rq(func_mdev, rqn, 482 + in, MLX5_ST_SZ_BYTES(modify_rq_in)); 483 + } 484 + 485 + static int mlx5_hairpin_modify_sq(struct mlx5_core_dev *peer_mdev, u32 sqn, 486 + int curr_state, int next_state, 487 + u16 peer_vhca, u32 peer_rq) 488 + { 489 + u32 in[MLX5_ST_SZ_DW(modify_sq_in)] = {0}; 490 + void *sqc; 491 + 492 + sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx); 493 + 494 + if (next_state == MLX5_RQC_STATE_RDY) { 495 + MLX5_SET(sqc, sqc, hairpin_peer_rq, peer_rq); 496 + MLX5_SET(sqc, sqc, hairpin_peer_vhca, peer_vhca); 497 + } 498 + 499 + MLX5_SET(modify_sq_in, in, sq_state, curr_state); 500 + MLX5_SET(sqc, sqc, state, next_state); 501 + 502 + return mlx5_core_modify_sq(peer_mdev, sqn, 503 + in, MLX5_ST_SZ_BYTES(modify_sq_in)); 504 + } 505 + 506 + static int mlx5_hairpin_pair_queues(struct mlx5_hairpin *hp) 507 + { 508 + int err; 509 + 510 + /* set peer SQ */ 511 + err = mlx5_hairpin_modify_sq(hp->peer_mdev, hp->sqn, 512 + MLX5_SQC_STATE_RST, MLX5_SQC_STATE_RDY, 513 + MLX5_CAP_GEN(hp->func_mdev, vhca_id), hp->rqn); 514 + if (err) 515 + goto err_modify_sq; 516 + 517 + /* set func RQ */ 518 + err = mlx5_hairpin_modify_rq(hp->func_mdev, hp->rqn, 519 + MLX5_RQC_STATE_RST, MLX5_RQC_STATE_RDY, 520 + MLX5_CAP_GEN(hp->peer_mdev, vhca_id), hp->sqn); 521 + 522 + if (err) 523 + goto err_modify_rq; 524 + 525 + return 0; 526 + 527 + err_modify_rq: 528 + mlx5_hairpin_modify_sq(hp->peer_mdev, hp->sqn, MLX5_SQC_STATE_RDY, 529 + MLX5_SQC_STATE_RST, 0, 0); 530 + err_modify_sq: 531 + return err; 532 + } 533 + 534 + static void mlx5_hairpin_unpair_queues(struct mlx5_hairpin *hp) 535 + { 536 + /* unset func RQ */ 537 + mlx5_hairpin_modify_rq(hp->func_mdev, hp->rqn, MLX5_RQC_STATE_RDY, 538 + MLX5_RQC_STATE_RST, 0, 0); 539 + 540 + /* unset peer SQ */ 541 + mlx5_hairpin_modify_sq(hp->peer_mdev, hp->sqn, MLX5_SQC_STATE_RDY, 542 + MLX5_SQC_STATE_RST, 0, 0); 543 + } 544 + 545 + struct mlx5_hairpin * 546 + mlx5_core_hairpin_create(struct mlx5_core_dev *func_mdev, 547 + struct mlx5_core_dev *peer_mdev, 548 + struct mlx5_hairpin_params *params) 549 + { 550 + struct mlx5_hairpin *hp; 551 + int size, err; 552 + 553 + size = sizeof(*hp); 554 + hp = kzalloc(size, GFP_KERNEL); 555 + if (!hp) 556 + return ERR_PTR(-ENOMEM); 557 + 558 + hp->func_mdev = func_mdev; 559 + hp->peer_mdev = peer_mdev; 560 + 561 + /* alloc and pair func --> peer hairpin */ 562 + err = mlx5_hairpin_create_queues(hp, params); 563 + if (err) 564 + goto err_create_queues; 565 + 566 + err = mlx5_hairpin_pair_queues(hp); 567 + if (err) 568 + goto err_pair_queues; 569 + 570 + return hp; 571 + 572 + err_pair_queues: 573 + mlx5_hairpin_destroy_queues(hp); 574 + err_create_queues: 575 + kfree(hp); 576 + return ERR_PTR(err); 577 + } 578 + 579 + void mlx5_core_hairpin_destroy(struct mlx5_hairpin *hp) 580 + { 581 + mlx5_hairpin_unpair_queues(hp); 582 + mlx5_hairpin_destroy_queues(hp); 583 + kfree(hp); 584 + }
+2
include/linux/if_link.h
··· 13 13 __u64 tx_bytes; 14 14 __u64 broadcast; 15 15 __u64 multicast; 16 + __u64 rx_dropped; 17 + __u64 tx_dropped; 16 18 }; 17 19 18 20 struct ifla_vf_info {
+35 -8
include/linux/mlx5/mlx5_ifc.h
··· 794 794 }; 795 795 796 796 struct mlx5_ifc_cmd_hca_cap_bits { 797 - u8 reserved_at_0[0x80]; 797 + u8 reserved_at_0[0x30]; 798 + u8 vhca_id[0x10]; 799 + 800 + u8 reserved_at_40[0x40]; 798 801 799 802 u8 log_max_srq_sz[0x8]; 800 803 u8 log_max_qp_sz[0x8]; ··· 1026 1023 u8 reserved_at_3b8[0x3]; 1027 1024 u8 log_min_stride_sz_sq[0x5]; 1028 1025 1029 - u8 reserved_at_3c0[0x1b]; 1026 + u8 hairpin[0x1]; 1027 + u8 reserved_at_3c1[0x2]; 1028 + u8 log_max_hairpin_queues[0x5]; 1029 + u8 reserved_at_3c8[0x3]; 1030 + u8 log_max_hairpin_wq_data_sz[0x5]; 1031 + u8 reserved_at_3d0[0xb]; 1030 1032 u8 log_max_wq_sz[0x5]; 1031 1033 1032 1034 u8 nic_vport_change_event[0x1]; 1033 1035 u8 disable_local_lb[0x1]; 1034 - u8 reserved_at_3e2[0x9]; 1036 + u8 reserved_at_3e2[0x1]; 1037 + u8 log_min_hairpin_wq_data_sz[0x5]; 1038 + u8 reserved_at_3e8[0x3]; 1035 1039 u8 log_max_vlan_list[0x5]; 1036 1040 u8 reserved_at_3f0[0x3]; 1037 1041 u8 log_max_current_mc_list[0x5]; ··· 1172 1162 u8 reserved_at_118[0x3]; 1173 1163 u8 log_wq_sz[0x5]; 1174 1164 1175 - u8 reserved_at_120[0x15]; 1165 + u8 reserved_at_120[0xb]; 1166 + u8 log_hairpin_data_sz[0x5]; 1167 + u8 reserved_at_130[0x5]; 1168 + 1176 1169 u8 log_wqe_num_of_strides[0x3]; 1177 1170 u8 two_byte_shift_en[0x1]; 1178 1171 u8 reserved_at_139[0x4]; ··· 2495 2482 u8 state[0x4]; 2496 2483 u8 reg_umr[0x1]; 2497 2484 u8 allow_swp[0x1]; 2498 - u8 reserved_at_e[0x12]; 2485 + u8 hairpin[0x1]; 2486 + u8 reserved_at_f[0x11]; 2499 2487 2500 2488 u8 reserved_at_20[0x8]; 2501 2489 u8 user_index[0x18]; ··· 2504 2490 u8 reserved_at_40[0x8]; 2505 2491 u8 cqn[0x18]; 2506 2492 2507 - u8 reserved_at_60[0x90]; 2493 + u8 reserved_at_60[0x8]; 2494 + u8 hairpin_peer_rq[0x18]; 2495 + 2496 + u8 reserved_at_80[0x10]; 2497 + u8 hairpin_peer_vhca[0x10]; 2498 + 2499 + u8 reserved_at_a0[0x50]; 2508 2500 2509 2501 u8 packet_pacing_rate_limit_index[0x10]; 2510 2502 u8 tis_lst_sz[0x10]; ··· 2582 2562 u8 state[0x4]; 2583 2563 u8 reserved_at_c[0x1]; 2584 2564 u8 flush_in_error_en[0x1]; 2585 - u8 reserved_at_e[0x12]; 2565 + u8 hairpin[0x1]; 2566 + u8 reserved_at_f[0x11]; 2586 2567 2587 2568 u8 reserved_at_20[0x8]; 2588 2569 u8 user_index[0x18]; ··· 2597 2576 u8 reserved_at_80[0x8]; 2598 2577 u8 rmpn[0x18]; 2599 2578 2600 - u8 reserved_at_a0[0xe0]; 2579 + u8 reserved_at_a0[0x8]; 2580 + u8 hairpin_peer_sq[0x18]; 2581 + 2582 + u8 reserved_at_c0[0x10]; 2583 + u8 hairpin_peer_vhca[0x10]; 2584 + 2585 + u8 reserved_at_e0[0xa0]; 2601 2586 2602 2587 struct mlx5_ifc_wq_bits wq; 2603 2588 };
+19
include/linux/mlx5/transobj.h
··· 75 75 int inlen); 76 76 void mlx5_core_destroy_rqt(struct mlx5_core_dev *dev, u32 rqtn); 77 77 78 + struct mlx5_hairpin_params { 79 + u8 log_data_size; 80 + u16 q_counter; 81 + }; 82 + 83 + struct mlx5_hairpin { 84 + struct mlx5_core_dev *func_mdev; 85 + struct mlx5_core_dev *peer_mdev; 86 + 87 + u32 rqn; 88 + u32 sqn; 89 + }; 90 + 91 + struct mlx5_hairpin * 92 + mlx5_core_hairpin_create(struct mlx5_core_dev *func_mdev, 93 + struct mlx5_core_dev *peer_mdev, 94 + struct mlx5_hairpin_params *params); 95 + 96 + void mlx5_core_hairpin_destroy(struct mlx5_hairpin *pair); 78 97 #endif /* __TRANSOBJ_H__ */
+2
include/uapi/linux/if_link.h
··· 732 732 IFLA_VF_STATS_BROADCAST, 733 733 IFLA_VF_STATS_MULTICAST, 734 734 IFLA_VF_STATS_PAD, 735 + IFLA_VF_STATS_RX_DROPPED, 736 + IFLA_VF_STATS_TX_DROPPED, 735 737 __IFLA_VF_STATS_MAX, 736 738 }; 737 739
+9 -1
net/core/rtnetlink.c
··· 904 904 nla_total_size_64bit(sizeof(__u64)) + 905 905 /* IFLA_VF_STATS_MULTICAST */ 906 906 nla_total_size_64bit(sizeof(__u64)) + 907 + /* IFLA_VF_STATS_RX_DROPPED */ 908 + nla_total_size_64bit(sizeof(__u64)) + 909 + /* IFLA_VF_STATS_TX_DROPPED */ 910 + nla_total_size_64bit(sizeof(__u64)) + 907 911 nla_total_size(sizeof(struct ifla_vf_trust))); 908 912 return size; 909 913 } else ··· 1262 1258 nla_put_u64_64bit(skb, IFLA_VF_STATS_BROADCAST, 1263 1259 vf_stats.broadcast, IFLA_VF_STATS_PAD) || 1264 1260 nla_put_u64_64bit(skb, IFLA_VF_STATS_MULTICAST, 1265 - vf_stats.multicast, IFLA_VF_STATS_PAD)) { 1261 + vf_stats.multicast, IFLA_VF_STATS_PAD) || 1262 + nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_DROPPED, 1263 + vf_stats.rx_dropped, IFLA_VF_STATS_PAD) || 1264 + nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_DROPPED, 1265 + vf_stats.tx_dropped, IFLA_VF_STATS_PAD)) { 1266 1266 nla_nest_cancel(skb, vfstats); 1267 1267 goto nla_put_vf_failure; 1268 1268 }