4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright 2022 Hewlett Packard Enterprise Development LP
26 * This file is part of Lustre, http://www.lustre.org/
29 * kfilnd peer management implementation.
31 #include "kfilnd_peer.h"
32 #include "kfilnd_dev.h"
34 static const struct rhashtable_params peer_cache_params = {
35 .head_offset = offsetof(struct kfilnd_peer, node),
36 .key_offset = offsetof(struct kfilnd_peer, nid),
37 .key_len = sizeof_field(struct kfilnd_peer, nid),
38 .automatic_shrinking = true,
42 * kfilnd_peer_free() - RCU safe way to free a peer.
43 * @ptr: Pointer to peer.
46 static void kfilnd_peer_free(void *ptr, void *arg)
48 struct kfilnd_peer *peer = ptr;
50 CDEBUG(D_NET, "%s(0x%llx) peer entry freed\n",
51 libcfs_nid2str(peer->nid), peer->addr);
53 kfi_av_remove(peer->dev->kfd_av, &peer->addr, 1, 0);
55 kfree_rcu(peer, rcu_head);
59 * kfilnd_peer_down() - Mark a peer as down.
60 * @peer: Peer to be downed.
62 void kfilnd_peer_down(struct kfilnd_peer *peer)
64 if (atomic_cmpxchg(&peer->remove_peer, 0, 1) == 0) {
65 struct lnet_nid peer_nid;
67 lnet_nid4_to_nid(peer->nid, &peer_nid);
68 CDEBUG(D_NET, "%s(0x%llx) marked for removal from peer cache\n",
69 libcfs_nidstr(&peer_nid), peer->addr);
71 lnet_notify(peer->dev->kfd_ni, &peer_nid, false, false,
77 * kfilnd_peer_put() - Return a reference for a peer.
78 * @peer: Peer where the reference should be returned.
80 void kfilnd_peer_put(struct kfilnd_peer *peer)
84 /* Return allocation reference if the peer was marked for removal. */
85 if (atomic_cmpxchg(&peer->remove_peer, 1, 2) == 1) {
86 rhashtable_remove_fast(&peer->dev->peer_cache, &peer->node,
88 refcount_dec(&peer->cnt);
90 CDEBUG(D_NET, "%s(0x%llx) removed from peer cache\n",
91 libcfs_nid2str(peer->nid), peer->addr);
94 if (refcount_dec_and_test(&peer->cnt))
95 kfilnd_peer_free(peer, NULL);
100 u16 kfilnd_peer_target_rx_base(struct kfilnd_peer *peer)
102 int cpt = lnet_cpt_of_nid(peer->nid, peer->dev->kfd_ni);
103 struct kfilnd_ep *ep = peer->dev->cpt_to_endpoint[cpt];
105 return ep->end_context_id;
109 * kfilnd_peer_get() - Get a reference for a peer.
110 * @dev: Device used to lookup peer.
111 * @nid: LNet NID of peer.
113 * Return: On success, pointer to a valid peer structed. Else, ERR_PTR.
115 struct kfilnd_peer *kfilnd_peer_get(struct kfilnd_dev *dev, lnet_nid_t nid)
120 u32 nid_addr = LNET_NIDADDR(nid);
121 u32 net_num = LNET_NETNUM(LNET_NIDNET(nid));
122 struct kfilnd_peer *peer;
123 struct kfilnd_peer *clash_peer;
126 /* Check the cache for a match. */
128 peer = rhashtable_lookup_fast(&dev->peer_cache, &nid,
130 if (peer && !refcount_inc_not_zero(&peer->cnt))
137 /* Allocate a new peer for the cache. */
138 peer = kzalloc(sizeof(*peer), GFP_KERNEL);
144 node = kasprintf(GFP_KERNEL, "%#x", nid_addr);
150 service = kasprintf(GFP_KERNEL, "%u", net_num);
153 goto err_free_node_str;
156 /* Use the KFI address vector to translate node and service string into
157 * a KFI address handle.
159 rc = kfi_av_insertsvc(dev->kfd_av, node, service, &peer->addr, 0, dev);
166 } else if (rc != 1) {
173 atomic_set(&peer->rx_base, 0);
174 atomic_set(&peer->remove_peer, 0);
175 peer->local_session_key = kfilnd_dev_get_session_key(dev);
177 /* One reference for the allocation and another for get operation
178 * performed for this peer. The allocation reference is returned when
179 * the entry is marked for removal.
181 refcount_set(&peer->cnt, 2);
183 clash_peer = rhashtable_lookup_get_insert_fast(&dev->peer_cache,
188 kfi_av_remove(dev->kfd_av, &peer->addr, 1, 0);
191 if (IS_ERR(clash_peer)) {
192 rc = PTR_ERR(clash_peer);
199 kfilnd_peer_alive(peer);
201 CDEBUG(D_NET, "%s(0x%llx) peer entry allocated\n",
202 libcfs_nid2str(peer->nid), peer->addr);
215 * kfilnd_peer_get_kfi_addr() - Return kfi_addr_t used for eager untagged send
217 * @peer: Peer struct.
219 * The returned kfi_addr_t is updated to target a specific RX context. The
220 * address return by this function should not be used if a specific RX context
221 * needs to be targeted (i/e the response RX context for a bulk transfer
224 * Return: kfi_addr_t.
226 kfi_addr_t kfilnd_peer_get_kfi_addr(struct kfilnd_peer *peer)
228 /* TODO: Support RX count by round-robining the generated kfi_addr_t's
229 * across multiple RX contexts using RX base and RX count.
231 return kfi_rx_addr(KFILND_BASE_ADDR(peer->addr),
232 atomic_read(&peer->rx_base), KFILND_FAB_RX_CTX_BITS);
236 * kfilnd_peer_update_rx_contexts() - Update the RX context for a peer.
237 * @peer: Peer to be updated.
238 * @rx_base: New RX base for peer.
239 * @rx_count: New RX count for peer.
241 void kfilnd_peer_update_rx_contexts(struct kfilnd_peer *peer,
242 unsigned int rx_base, unsigned int rx_count)
244 /* TODO: Support RX count. */
245 LASSERT(rx_count > 0);
246 atomic_set(&peer->rx_base, rx_base);
250 * kfilnd_peer_alive() - Update when the peer was last alive.
251 * @peer: Peer to be updated.
253 void kfilnd_peer_alive(struct kfilnd_peer *peer)
255 peer->last_alive = ktime_get_seconds();
257 /* Ensure timestamp is committed to memory before used. */
262 * kfilnd_peer_destroy() - Destroy peer cache.
263 * @dev: Device peer cache to be destroyed.
265 void kfilnd_peer_destroy(struct kfilnd_dev *dev)
267 rhashtable_free_and_destroy(&dev->peer_cache, kfilnd_peer_free, NULL);
271 * kfilnd_peer_init() - Initialize peer cache.
272 * @dev: Device peer cache to be initialized.
274 void kfilnd_peer_init(struct kfilnd_dev *dev)
276 rhashtable_init(&dev->peer_cache, &peer_cache_params);