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

RDMA/sa_query: Support IB service records resolution

Add an SA query API ib_sa_service_rec_get() to support building and
sending SA query MADs that ask for service records with a specific
name or ID, and receiving and parsing responses from the SM.

Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Signed-off-by: Mark Zhang <markzhang@nvidia.com>
Reviewed-by: Vlad Dumitrescu <vdumitrescu@nvidia.com>
Link: https://patch.msgid.link/9af6c82f3a3a9d975115a33235fb4ffc7c8edb21.1751279793.git.leonro@nvidia.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>

authored by

Mark Zhang and committed by
Leon Romanovsky
a892a3e7 ef5fcdb7

+276
+238
drivers/infiniband/core/sa_query.c
··· 152 152 struct ib_sa_query sa_query; 153 153 }; 154 154 155 + struct ib_sa_service_query { 156 + void (*callback)(int status, struct sa_service_rec *rec, 157 + unsigned int num_services, void *context); 158 + void *context; 159 + struct ib_sa_query sa_query; 160 + }; 161 + 155 162 static LIST_HEAD(ib_nl_request_list); 156 163 static DEFINE_SPINLOCK(ib_nl_request_lock); 157 164 static atomic_t ib_nl_sa_request_seq; ··· 691 684 .offset_words = 2, 692 685 .offset_bits = 0, 693 686 .size_bits = 512 }, 687 + }; 688 + 689 + #define SERVICE_REC_FIELD(field) \ 690 + .struct_offset_bytes = offsetof(struct sa_service_rec, field), \ 691 + .struct_size_bytes = sizeof_field(struct sa_service_rec, field), \ 692 + .field_name = "sa_service_rec:" #field 693 + 694 + static const struct ib_field service_rec_table[] = { 695 + { SERVICE_REC_FIELD(id), 696 + .offset_words = 0, 697 + .offset_bits = 0, 698 + .size_bits = 64 }, 699 + { SERVICE_REC_FIELD(gid), 700 + .offset_words = 2, 701 + .offset_bits = 0, 702 + .size_bits = 128 }, 703 + { SERVICE_REC_FIELD(pkey), 704 + .offset_words = 6, 705 + .offset_bits = 0, 706 + .size_bits = 16 }, 707 + { RESERVED, 708 + .offset_words = 6, 709 + .offset_bits = 16, 710 + .size_bits = 16 }, 711 + { SERVICE_REC_FIELD(lease), 712 + .offset_words = 7, 713 + .offset_bits = 0, 714 + .size_bits = 32 }, 715 + { SERVICE_REC_FIELD(key), 716 + .offset_words = 8, 717 + .offset_bits = 0, 718 + .size_bits = 128 }, 719 + { SERVICE_REC_FIELD(name), 720 + .offset_words = 12, 721 + .offset_bits = 0, 722 + .size_bits = 512 }, 723 + { SERVICE_REC_FIELD(data_8), 724 + .offset_words = 28, 725 + .offset_bits = 0, 726 + .size_bits = 128 }, 727 + { SERVICE_REC_FIELD(data_16), 728 + .offset_words = 32, 729 + .offset_bits = 0, 730 + .size_bits = 128 }, 731 + { SERVICE_REC_FIELD(data_32), 732 + .offset_words = 36, 733 + .offset_bits = 0, 734 + .size_bits = 128 }, 735 + { SERVICE_REC_FIELD(data_64), 736 + .offset_words = 40, 737 + .offset_bits = 0, 738 + .size_bits = 128 }, 694 739 }; 695 740 696 741 #define RDMA_PRIMARY_PATH_MAX_REC_NUM 3 ··· 1451 1392 } 1452 1393 EXPORT_SYMBOL(ib_sa_pack_path); 1453 1394 1395 + void ib_sa_pack_service(struct sa_service_rec *rec, void *attribute) 1396 + { 1397 + ib_pack(service_rec_table, ARRAY_SIZE(service_rec_table), rec, 1398 + attribute); 1399 + } 1400 + EXPORT_SYMBOL(ib_sa_pack_service); 1401 + 1402 + void ib_sa_unpack_service(void *attribute, struct sa_service_rec *rec) 1403 + { 1404 + ib_unpack(service_rec_table, ARRAY_SIZE(service_rec_table), attribute, 1405 + rec); 1406 + } 1407 + EXPORT_SYMBOL(ib_sa_unpack_service); 1408 + 1454 1409 static bool ib_sa_opa_pathrecord_support(struct ib_sa_client *client, 1455 1410 struct ib_sa_device *sa_dev, 1456 1411 u32 port_num) ··· 1554 1481 } 1555 1482 } 1556 1483 1484 + #define IB_SA_DATA_OFFS 56 1485 + #define IB_SERVICE_REC_SZ 176 1486 + 1487 + static void ib_unpack_service_rmpp(struct sa_service_rec *rec, 1488 + struct ib_mad_recv_wc *mad_wc, 1489 + int num_services) 1490 + { 1491 + unsigned int cp_sz, data_i, data_size, rec_i = 0, buf_i = 0; 1492 + struct ib_mad_recv_buf *mad_buf; 1493 + u8 buf[IB_SERVICE_REC_SZ]; 1494 + u8 *data; 1495 + 1496 + data_size = sizeof(((struct ib_sa_mad *) mad_buf->mad)->data); 1497 + 1498 + list_for_each_entry(mad_buf, &mad_wc->rmpp_list, list) { 1499 + data = ((struct ib_sa_mad *) mad_buf->mad)->data; 1500 + data_i = 0; 1501 + while (data_i < data_size && rec_i < num_services) { 1502 + cp_sz = min(IB_SERVICE_REC_SZ - buf_i, 1503 + data_size - data_i); 1504 + memcpy(buf + buf_i, data + data_i, cp_sz); 1505 + data_i += cp_sz; 1506 + buf_i += cp_sz; 1507 + if (buf_i == IB_SERVICE_REC_SZ) { 1508 + ib_sa_unpack_service(buf, rec + rec_i); 1509 + buf_i = 0; 1510 + rec_i++; 1511 + } 1512 + } 1513 + } 1514 + } 1515 + 1516 + static void ib_sa_service_rec_callback(struct ib_sa_query *sa_query, int status, 1517 + struct ib_mad_recv_wc *mad_wc) 1518 + { 1519 + struct ib_sa_service_query *query = 1520 + container_of(sa_query, struct ib_sa_service_query, sa_query); 1521 + struct sa_service_rec *rec; 1522 + int num_services; 1523 + 1524 + if (!mad_wc || !mad_wc->recv_buf.mad) { 1525 + query->callback(status, NULL, 0, query->context); 1526 + return; 1527 + } 1528 + 1529 + num_services = (mad_wc->mad_len - IB_SA_DATA_OFFS) / IB_SERVICE_REC_SZ; 1530 + if (!num_services) { 1531 + query->callback(-ENODATA, NULL, 0, query->context); 1532 + return; 1533 + } 1534 + 1535 + rec = kmalloc_array(num_services, sizeof(*rec), GFP_KERNEL); 1536 + if (!rec) { 1537 + query->callback(-ENOMEM, NULL, 0, query->context); 1538 + return; 1539 + } 1540 + 1541 + ib_unpack_service_rmpp(rec, mad_wc, num_services); 1542 + query->callback(status, rec, num_services, query->context); 1543 + kfree(rec); 1544 + } 1545 + 1557 1546 static void ib_sa_path_rec_release(struct ib_sa_query *sa_query) 1558 1547 { 1559 1548 struct ib_sa_path_query *query = 1560 1549 container_of(sa_query, struct ib_sa_path_query, sa_query); 1561 1550 1562 1551 kfree(query->conv_pr); 1552 + kfree(query); 1553 + } 1554 + 1555 + static void ib_sa_service_rec_release(struct ib_sa_query *sa_query) 1556 + { 1557 + struct ib_sa_service_query *query = 1558 + container_of(sa_query, struct ib_sa_service_query, sa_query); 1559 + 1563 1560 kfree(query); 1564 1561 } 1565 1562 ··· 1762 1619 return ret; 1763 1620 } 1764 1621 EXPORT_SYMBOL(ib_sa_path_rec_get); 1622 + 1623 + /** 1624 + * ib_sa_service_rec_get - Start a Service get query 1625 + * @client: SA client 1626 + * @device: device to send query on 1627 + * @port_num: port number to send query on 1628 + * @rec: Service Record to send in query 1629 + * @comp_mask: component mask to send in query 1630 + * @timeout_ms: time to wait for response 1631 + * @gfp_mask: GFP mask to use for internal allocations 1632 + * @callback: function called when query completes, times out or is 1633 + * canceled 1634 + * @context: opaque user context passed to callback 1635 + * @sa_query: query context, used to cancel query 1636 + * 1637 + * Send a Service Record Get query to the SA to look up a path. The 1638 + * callback function will be called when the query completes (or 1639 + * fails); status is 0 for a successful response, -EINTR if the query 1640 + * is canceled, -ETIMEDOUT is the query timed out, or -EIO if an error 1641 + * occurred sending the query. The resp parameter of the callback is 1642 + * only valid if status is 0. 1643 + * 1644 + * If the return value of ib_sa_service_rec_get() is negative, it is an 1645 + * error code. Otherwise it is a query ID that can be used to cancel 1646 + * the query. 1647 + */ 1648 + int ib_sa_service_rec_get(struct ib_sa_client *client, 1649 + struct ib_device *device, u32 port_num, 1650 + struct sa_service_rec *rec, 1651 + ib_sa_comp_mask comp_mask, 1652 + unsigned long timeout_ms, gfp_t gfp_mask, 1653 + void (*callback)(int status, 1654 + struct sa_service_rec *resp, 1655 + unsigned int num_services, 1656 + void *context), 1657 + void *context, struct ib_sa_query **sa_query) 1658 + { 1659 + struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); 1660 + struct ib_sa_service_query *query; 1661 + struct ib_mad_agent *agent; 1662 + struct ib_sa_port *port; 1663 + struct ib_sa_mad *mad; 1664 + int ret; 1665 + 1666 + if (!sa_dev) 1667 + return -ENODEV; 1668 + 1669 + port = &sa_dev->port[port_num - sa_dev->start_port]; 1670 + agent = port->agent; 1671 + 1672 + query = kzalloc(sizeof(*query), gfp_mask); 1673 + if (!query) 1674 + return -ENOMEM; 1675 + 1676 + query->sa_query.port = port; 1677 + 1678 + ret = alloc_mad(&query->sa_query, gfp_mask); 1679 + if (ret) 1680 + goto err1; 1681 + 1682 + ib_sa_client_get(client); 1683 + query->sa_query.client = client; 1684 + query->callback = callback; 1685 + query->context = context; 1686 + 1687 + mad = query->sa_query.mad_buf->mad; 1688 + init_mad(&query->sa_query, agent); 1689 + 1690 + query->sa_query.rmpp_callback = callback ? ib_sa_service_rec_callback : 1691 + NULL; 1692 + query->sa_query.release = ib_sa_service_rec_release; 1693 + mad->mad_hdr.method = IB_MGMT_METHOD_GET_TABLE; 1694 + mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_SERVICE_REC); 1695 + mad->sa_hdr.comp_mask = comp_mask; 1696 + 1697 + ib_sa_pack_service(rec, mad->data); 1698 + 1699 + *sa_query = &query->sa_query; 1700 + query->sa_query.mad_buf->context[1] = rec; 1701 + 1702 + ret = send_mad(&query->sa_query, timeout_ms, gfp_mask); 1703 + if (ret < 0) 1704 + goto err2; 1705 + 1706 + return ret; 1707 + 1708 + err2: 1709 + *sa_query = NULL; 1710 + ib_sa_client_put(query->sa_query.client); 1711 + free_mad(&query->sa_query); 1712 + err1: 1713 + kfree(query); 1714 + return ret; 1715 + } 1716 + EXPORT_SYMBOL(ib_sa_service_rec_get); 1765 1717 1766 1718 static void ib_sa_mcmember_rec_callback(struct ib_sa_query *sa_query, 1767 1719 int status, struct ib_sa_mad *mad)
+1
include/rdma/ib_mad.h
··· 48 48 #define IB_MGMT_METHOD_REPORT 0x06 49 49 #define IB_MGMT_METHOD_REPORT_RESP 0x86 50 50 #define IB_MGMT_METHOD_TRAP_REPRESS 0x07 51 + #define IB_MGMT_METHOD_GET_TABLE 0x12 51 52 52 53 #define IB_MGMT_METHOD_RESP 0x80 53 54 #define IB_BM_ATTR_MOD_RESP cpu_to_be32(1)
+37
include/rdma/ib_sa.h
··· 189 189 u32 flags; 190 190 }; 191 191 192 + struct sa_service_rec { 193 + __be64 id; 194 + __u8 gid[16]; 195 + __be16 pkey; 196 + __u8 reserved[2]; 197 + __be32 lease; 198 + __u8 key[16]; 199 + __u8 name[64]; 200 + __u8 data_8[16]; 201 + __be16 data_16[8]; 202 + __be32 data_32[4]; 203 + __be64 data_64[2]; 204 + }; 205 + 192 206 static inline enum ib_gid_type 193 207 sa_conv_pathrec_to_gid_type(struct sa_path_rec *rec) 194 208 { ··· 431 417 unsigned int num_prs, void *context), 432 418 void *context, struct ib_sa_query **query); 433 419 420 + int ib_sa_service_rec_get(struct ib_sa_client *client, 421 + struct ib_device *device, u32 port_num, 422 + struct sa_service_rec *rec, 423 + ib_sa_comp_mask comp_mask, 424 + unsigned long timeout_ms, gfp_t gfp_mask, 425 + void (*callback)(int status, 426 + struct sa_service_rec *resp, 427 + unsigned int num_services, 428 + void *context), 429 + void *context, struct ib_sa_query **sa_query); 430 + 434 431 struct ib_sa_multicast { 435 432 struct ib_sa_mcmember_rec rec; 436 433 ib_sa_comp_mask comp_mask; ··· 532 507 * to IB MAD wire format. 533 508 */ 534 509 void ib_sa_pack_path(struct sa_path_rec *rec, void *attribute); 510 + 511 + /** 512 + * ib_sa_pack_service - Convert a service record from struct ib_sa_service_rec 513 + * to IB MAD wire format. 514 + */ 515 + void ib_sa_pack_service(struct sa_service_rec *rec, void *attribute); 516 + 517 + /** 518 + * ib_sa_unpack_service - Convert a service record from MAD format to struct 519 + * ib_sa_service_rec. 520 + */ 521 + void ib_sa_unpack_service(void *attribute, struct sa_service_rec *rec); 535 522 536 523 /** 537 524 * ib_sa_unpack_path - Convert a path record from MAD format to struct