4444 * @host_traddr: Host transport address (source address)
4545 * @host_iface: Host interface for connection (tcp only)
4646 * @iface_list: Interface list (tcp only)
47+ * @addreq: Address comparison function (for traddr, host-traddr)
48+ * @well_known_nqn: Set to "true" when @subsysnqn is the well-known NQN
4749 */
4850struct candidate_args {
4951 const char * transport ;
@@ -53,7 +55,10 @@ struct candidate_args {
5355 const char * host_traddr ;
5456 const char * host_iface ;
5557 struct ifaddrs * iface_list ;
58+ bool (* addreq )(const char * , const char * );
59+ bool well_known_nqn ;
5660};
61+ typedef bool (* ctrl_match_t )(struct nvme_ctrl * c , struct candidate_args * candidate );
5762
5863const char * nvme_slots_sysfs_dir = "/sys/bus/pci/slots" ;
5964
@@ -1257,7 +1262,7 @@ struct nvme_ctrl *nvme_create_ctrl(nvme_root_t r,
12571262static bool _tcp_ctrl_match_host_traddr_no_src_addr (struct nvme_ctrl * c , struct candidate_args * candidate )
12581263{
12591264 if (c -> cfg .host_traddr )
1260- return nvme_ipaddrs_eq (candidate -> host_traddr , c -> cfg .host_traddr );
1265+ return candidate -> addreq (candidate -> host_traddr , c -> cfg .host_traddr );
12611266
12621267 /* If c->cfg.host_traddr is NULL, then the controller (c)
12631268 * uses the interface's primary address as the source
@@ -1405,7 +1410,7 @@ static bool _tcp_opt_params_match(struct nvme_ctrl *c, struct candidate_args *ca
14051410
14061411 /* Check host_traddr only if candidate is interested */
14071412 if (candidate -> host_traddr &&
1408- !nvme_ipaddrs_eq (candidate -> host_traddr , src_addr ))
1413+ !candidate -> addreq (candidate -> host_traddr , src_addr ))
14091414 return false;
14101415
14111416 /* Check host_iface only if candidate is interested */
@@ -1418,19 +1423,12 @@ static bool _tcp_opt_params_match(struct nvme_ctrl *c, struct candidate_args *ca
14181423}
14191424
14201425/**
1421- * _tcp_lookup_ctrl() - Look for an existing controller that can be reused
1422- * @s: Subsystem object under which to do the search
1423- * @transport: Transport type ("tcp")
1424- * @traddr: Destination IP address
1425- * @host_iface: Interface for the connection (optional)
1426- * @host_traddr: Source IP address (optional)
1427- * @trsvcid: Destination TCP port
1428- * @p: Starting point is the linked-list (NULL to start at the beginning)
1426+ * _tcp_match_ctrl() - Check if controller matches candidate (TCP only)
1427+ * @c: An existing controller instance
1428+ * @candidate: Candidate ctrl we're trying to match with @c.
14291429 *
14301430 * We want to determine if an existing controller can be re-used
1431- * for the candidate controller we're trying to instantiate. The
1432- * candidate is identified by @transport, @traddr, @trsvcid,
1433- * @host_traddr, and @host_iface.
1431+ * for the candidate controller we're trying to instantiate.
14341432 *
14351433 * For TCP, we do not have a match if the candidate's transport, traddr,
14361434 * trsvcid are not identical to those of the the existing controller.
@@ -1440,92 +1438,204 @@ static bool _tcp_opt_params_match(struct nvme_ctrl *c, struct candidate_args *ca
14401438 * not specify them (both NULL), we can ignore them. Otherwise, we must
14411439 * employ advanced investigation techniques to determine if there's a match.
14421440 *
1443- * Return: Pointer to the matching controller or NULL .
1441+ * Return: true if a match is found, false otherwise .
14441442 */
1445- static nvme_ctrl_t _tcp_lookup_ctrl (nvme_subsystem_t s , const char * transport ,
1446- const char * traddr , const char * host_traddr ,
1447- const char * host_iface , const char * trsvcid ,
1448- nvme_ctrl_t p )
1443+ static bool _tcp_match_ctrl (struct nvme_ctrl * c , struct candidate_args * candidate )
14491444{
1450- struct candidate_args candidate = { 0 };
1451- struct nvme_ctrl * c , * matching_c = NULL ;
1445+ if (! streq0 ( c -> transport , candidate -> transport ))
1446+ return false ;
14521447
1453- candidate .traddr = traddr ;
1454- candidate .trsvcid = trsvcid ;
1455- candidate .transport = transport ;
1456- candidate .host_iface = host_iface ;
1457- candidate .host_traddr = host_traddr ;
1448+ if (!streq0 (c -> trsvcid , candidate -> trsvcid ))
1449+ return false;
14581450
1459- /* For TCP we may need to access the interface map. Let's retrieve
1460- * and cache the map and use it for the duration of the loop below.
1461- */
1462- if (getifaddrs (& candidate .iface_list ) == -1 )
1463- candidate .iface_list = NULL ;
1451+ if (!candidate -> addreq (c -> traddr , candidate -> traddr ))
1452+ return false;
14641453
1465- c = p ? nvme_subsystem_next_ctrl (s , p ) : nvme_subsystem_first_ctrl (s );
1466- for (; c != NULL ; c = nvme_subsystem_next_ctrl (s , c )) {
1467- if (!streq0 (c -> transport , candidate .transport ))
1468- continue ;
1454+ if (candidate -> well_known_nqn && !nvme_ctrl_is_discovery_ctrl (c ))
1455+ return false;
14691456
1470- if (!streq0 (c -> trsvcid , candidate . trsvcid ))
1471- continue ;
1457+ if (candidate -> subsysnqn && !streq0 (c -> subsysnqn , candidate -> subsysnqn ))
1458+ return false ;
14721459
1473- if (!nvme_ipaddrs_eq (c -> traddr , candidate .traddr ))
1474- continue ;
1460+ /* Check host_traddr / host_iface only if candidate is interested */
1461+ if ((candidate -> host_iface || candidate -> host_traddr ) &&
1462+ !_tcp_opt_params_match (c , candidate ))
1463+ return false;
14751464
1476- /* Check host_traddr / host_iface only if candidate is interested */
1477- if ((candidate .host_iface || candidate .host_traddr ) &&
1478- !_tcp_opt_params_match (c , & candidate ))
1479- continue ;
1465+ return true;
1466+ }
14801467
1481- matching_c = c ;
1482- break ;
1468+ /**
1469+ * _match_ctrl() - Check if controller matches candidate (non TCP transport)
1470+ * @c: An existing controller instance
1471+ * @candidate: Candidate ctrl we're trying to match with @c.
1472+ *
1473+ * We want to determine if an existing controller can be re-used
1474+ * for the candidate controller we're trying to instantiate. This function
1475+ * is used for all transports except TCP.
1476+ *
1477+ * Return: true if a match is found, false otherwise.
1478+ */
1479+ static bool _match_ctrl (struct nvme_ctrl * c , struct candidate_args * candidate )
1480+ {
1481+ if (!streq0 (c -> transport , candidate -> transport ))
1482+ return false;
1483+
1484+ if (candidate -> traddr && c -> traddr &&
1485+ !candidate -> addreq (c -> traddr , candidate -> traddr ))
1486+ return false;
1487+
1488+ if (candidate -> host_traddr && c -> cfg .host_traddr &&
1489+ !candidate -> addreq (c -> cfg .host_traddr , candidate -> host_traddr ))
1490+ return false;
1491+
1492+ if (candidate -> host_iface && c -> cfg .host_iface &&
1493+ !streq0 (c -> cfg .host_iface , candidate -> host_iface ))
1494+ return false;
1495+
1496+ if (candidate -> trsvcid && c -> trsvcid &&
1497+ !streq0 (c -> trsvcid , candidate -> trsvcid ))
1498+ return false;
1499+
1500+ if (candidate -> well_known_nqn && !nvme_ctrl_is_discovery_ctrl (c ))
1501+ return false;
1502+
1503+ if (candidate -> subsysnqn && !streq0 (c -> subsysnqn , candidate -> subsysnqn ))
1504+ return false;
1505+
1506+ return true;
1507+ }
1508+ /**
1509+ * _candidate_init() - Init candidate and get the matching function
1510+ *
1511+ * @candidate: Candidate struct to initialize
1512+ * @transport: Transport name
1513+ * @traddr: Transport address
1514+ * @trsvcid: Transport service identifier
1515+ * @subsysnqn: Subsystem NQN
1516+ * @host_traddr: Host transport address
1517+ * @host_iface: Host interface name
1518+ * @host_iface: Host interface name
1519+ *
1520+ * The function _candidate_free() must be called to release resources once
1521+ * the candidate object is not longer required.
1522+ *
1523+ * Return: The matching function to use when comparing an existing
1524+ * controller to the candidate controller.
1525+ */
1526+ static ctrl_match_t _candidate_init (struct candidate_args * candidate ,
1527+ const char * transport ,
1528+ const char * traddr ,
1529+ const char * trsvcid ,
1530+ const char * subsysnqn ,
1531+ const char * host_traddr ,
1532+ const char * host_iface )
1533+ {
1534+ memset (candidate , 0 , sizeof (* candidate ));
1535+
1536+ candidate -> traddr = traddr ;
1537+ candidate -> trsvcid = trsvcid ;
1538+ candidate -> transport = transport ;
1539+ candidate -> subsysnqn = subsysnqn ;
1540+ candidate -> host_iface = host_iface ;
1541+ candidate -> host_traddr = host_traddr ;
1542+
1543+ if (streq0 (subsysnqn , NVME_DISC_SUBSYS_NAME )) {
1544+ /* Since TP8013, the NQN of discovery controllers can be the
1545+ * well-known NQN (i.e. nqn.2014-08.org.nvmexpress.discovery) or
1546+ * a unique NQN. A DC created using the well-known NQN may later
1547+ * display a unique NQN when looked up in the sysfs. Therefore,
1548+ * ignore (i.e. set to NULL) the well-known NQN when looking for
1549+ * a match.
1550+ */
1551+ candidate -> subsysnqn = NULL ;
1552+ candidate -> well_known_nqn = true;
14831553 }
14841554
1485- freeifaddrs (candidate .iface_list ); /* This is NULL-safe */
1555+ if (streq0 (transport , "tcp" )) {
1556+ /* For TCP we may need to access the interface map.
1557+ * Let's retrieve and cache the map.
1558+ */
1559+ if (getifaddrs (& candidate -> iface_list ) == -1 )
1560+ candidate -> iface_list = NULL ;
14861561
1487- return matching_c ;
1562+ candidate -> addreq = nvme_ipaddrs_eq ;
1563+ return _tcp_match_ctrl ;
1564+ }
1565+
1566+ if (streq0 (transport , "rdma" )) {
1567+ candidate -> addreq = nvme_ipaddrs_eq ;
1568+ return _match_ctrl ;
1569+ }
1570+
1571+ /* All other transport types */
1572+ candidate -> addreq = streqcase0 ;
1573+ return _match_ctrl ;
1574+ }
1575+
1576+ /**
1577+ * _candidate_free() - Release resources allocated by _candidate_init()
1578+ *
1579+ * @candidate: data to free.
1580+ */
1581+ static void _candidate_free (struct candidate_args * candidate )
1582+ {
1583+ freeifaddrs (candidate -> iface_list ); /* This is NULL-safe */
14881584}
14891585
14901586nvme_ctrl_t __nvme_lookup_ctrl (nvme_subsystem_t s , const char * transport ,
14911587 const char * traddr , const char * host_traddr ,
14921588 const char * host_iface , const char * trsvcid ,
1493- nvme_ctrl_t p )
1494-
1589+ const char * subsysnqn , nvme_ctrl_t p )
14951590{
1496- struct nvme_ctrl * c ;
1497- bool (* addreq )(const char * , const char * );
1498-
1499- /* TCP requires special handling */
1500- if (streq0 (transport , "tcp" ))
1501- return _tcp_lookup_ctrl (s , transport , traddr ,
1502- host_traddr , host_iface , trsvcid , p );
1591+ struct nvme_ctrl * c , * matching_c = NULL ;
1592+ struct candidate_args candidate ;
1593+ ctrl_match_t ctrl_match ;
15031594
1504- if (streq0 (transport , "rdma" ))
1505- addreq = nvme_ipaddrs_eq ; /* IP address compare for RDMA */
1506- else
1507- addreq = streqcase0 ; /* Case-insensitive for everything else */
1595+ /* Init candidate and get the matching function to use */
1596+ ctrl_match = _candidate_init (& candidate , transport , traddr , trsvcid ,
1597+ subsysnqn , host_traddr , host_iface );
15081598
15091599 c = p ? nvme_subsystem_next_ctrl (s , p ) : nvme_subsystem_first_ctrl (s );
15101600 for (; c != NULL ; c = nvme_subsystem_next_ctrl (s , c )) {
1511- if (!streq0 (c -> transport , transport ))
1512- continue ;
1513- if (traddr && c -> traddr &&
1514- !addreq (c -> traddr , traddr ))
1515- continue ;
1516- if (host_traddr && c -> cfg .host_traddr &&
1517- !addreq (c -> cfg .host_traddr , host_traddr ))
1518- continue ;
1519- if (host_iface && c -> cfg .host_iface &&
1520- !streq0 (c -> cfg .host_iface , host_iface ))
1521- continue ;
1522- if (trsvcid && c -> trsvcid &&
1523- !streq0 (c -> trsvcid , trsvcid ))
1524- continue ;
1525- return c ;
1601+ if (ctrl_match (c , & candidate )) {
1602+ matching_c = c ;
1603+ break ;
1604+ }
15261605 }
15271606
1528- return NULL ;
1607+ _candidate_free (& candidate );
1608+
1609+ return matching_c ;
1610+ }
1611+
1612+ bool nvme_ctrl_config_match (struct nvme_ctrl * c , const char * transport ,
1613+ const char * traddr , const char * trsvcid ,
1614+ const char * subsysnqn , const char * host_traddr ,
1615+ const char * host_iface )
1616+ {
1617+ bool match ;
1618+ ctrl_match_t ctrl_match ;
1619+ struct candidate_args candidate ;
1620+
1621+ /* Init candidate and get the matching function to use */
1622+ ctrl_match = _candidate_init (& candidate , transport , traddr , trsvcid ,
1623+ subsysnqn , host_traddr , host_iface );
1624+
1625+ match = ctrl_match (c , & candidate );
1626+
1627+ _candidate_free (& candidate );
1628+
1629+ return match ;
1630+ }
1631+
1632+ nvme_ctrl_t nvme_ctrl_find (nvme_subsystem_t s , const char * transport ,
1633+ const char * traddr , const char * trsvcid ,
1634+ const char * subsysnqn , const char * host_traddr ,
1635+ const char * host_iface )
1636+ {
1637+ return __nvme_lookup_ctrl (s , transport , traddr , host_traddr , host_iface ,
1638+ trsvcid , subsysnqn , NULL /*p*/ );
15291639}
15301640
15311641nvme_ctrl_t nvme_lookup_ctrl (nvme_subsystem_t s , const char * transport ,
@@ -1540,7 +1650,7 @@ nvme_ctrl_t nvme_lookup_ctrl(nvme_subsystem_t s, const char *transport,
15401650 return NULL ;
15411651
15421652 c = __nvme_lookup_ctrl (s , transport , traddr , host_traddr ,
1543- host_iface , trsvcid , p );
1653+ host_iface , trsvcid , NULL , p );
15441654 if (c )
15451655 return c ;
15461656
0 commit comments