1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2002 Cluster File Systems, Inc.
6 * This file is part of Portals
7 * http://sourceforge.net/projects/sandiaportals/
9 * Portals is free software; you can redistribute it and/or
10 * modify it under the terms of version 2 of the GNU General Public
11 * License as published by the Free Software Foundation.
13 * Portals is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with Portals; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 LIST_HEAD(kpr_routes);
29 unsigned long long kpr_fwd_bytes;
30 unsigned long kpr_fwd_packets;
31 unsigned long kpr_fwd_errors;
32 atomic_t kpr_queue_depth;
34 /* Mostly the tables are read-only (thread and interrupt context)
36 * Once in a blue moon we register/deregister NALs and add/remove routing
37 * entries (thread context only)... */
38 rwlock_t kpr_rwlock = RW_LOCK_UNLOCKED;
40 kpr_router_interface_t kpr_router_interface = {
41 kprri_register: kpr_register_nal,
42 kprri_lookup: kpr_lookup_target,
43 kprri_fwd_start: kpr_forward_packet,
44 kprri_fwd_done: kpr_complete_packet,
45 kprri_shutdown: kpr_shutdown_nal,
46 kprri_deregister: kpr_deregister_nal,
49 kpr_control_interface_t kpr_control_interface = {
50 kprci_add_route: kpr_add_route,
51 kprci_del_route: kpr_del_route,
52 kprci_get_route: kpr_get_route,
56 kpr_register_nal (kpr_nal_interface_t *nalif, void **argp)
62 CDEBUG (D_OTHER, "Registering NAL %d\n", nalif->kprni_nalid);
64 PORTAL_ALLOC (ne, sizeof (*ne));
68 memset (ne, 0, sizeof (*ne));
69 memcpy ((void *)&ne->kpne_interface, (void *)nalif, sizeof (*nalif));
71 LASSERT (!in_interrupt());
72 write_lock_irqsave (&kpr_rwlock, flags);
74 for (e = kpr_nals.next; e != &kpr_nals; e = e->next)
76 kpr_nal_entry_t *ne2 = list_entry (e, kpr_nal_entry_t, kpne_list);
78 if (ne2->kpne_interface.kprni_nalid == ne->kpne_interface.kprni_nalid)
80 write_unlock_irqrestore (&kpr_rwlock, flags);
82 CERROR ("Attempt to register same NAL %d twice\n", ne->kpne_interface.kprni_nalid);
84 PORTAL_FREE (ne, sizeof (*ne));
89 list_add (&ne->kpne_list, &kpr_nals);
91 write_unlock_irqrestore (&kpr_rwlock, flags);
99 kpr_shutdown_nal (void *arg)
102 kpr_nal_entry_t *ne = (kpr_nal_entry_t *)arg;
104 CDEBUG (D_OTHER, "Shutting down NAL %d\n", ne->kpne_interface.kprni_nalid);
106 LASSERT (!ne->kpne_shutdown);
107 LASSERT (!in_interrupt());
109 write_lock_irqsave (&kpr_rwlock, flags); /* locking a bit spurious... */
110 ne->kpne_shutdown = 1;
111 write_unlock_irqrestore (&kpr_rwlock, flags); /* except it's a memory barrier */
113 while (atomic_read (&ne->kpne_refcount) != 0)
115 CDEBUG (D_NET, "Waiting for refcount on NAL %d to reach zero (%d)\n",
116 ne->kpne_interface.kprni_nalid, atomic_read (&ne->kpne_refcount));
118 set_current_state (TASK_UNINTERRUPTIBLE);
119 schedule_timeout (HZ);
124 kpr_deregister_nal (void *arg)
127 kpr_nal_entry_t *ne = (kpr_nal_entry_t *)arg;
129 CDEBUG (D_OTHER, "Deregister NAL %d\n", ne->kpne_interface.kprni_nalid);
131 LASSERT (ne->kpne_shutdown); /* caller must have issued shutdown already */
132 LASSERT (atomic_read (&ne->kpne_refcount) == 0); /* can't be busy */
133 LASSERT (!in_interrupt());
135 write_lock_irqsave (&kpr_rwlock, flags);
137 list_del (&ne->kpne_list);
139 write_unlock_irqrestore (&kpr_rwlock, flags);
141 PORTAL_FREE (ne, sizeof (*ne));
147 kpr_lookup_target (void *arg, ptl_nid_t target_nid, ptl_nid_t *gateway_nidp)
149 kpr_nal_entry_t *ne = (kpr_nal_entry_t *)arg;
153 CDEBUG (D_OTHER, "lookup "LPX64" from NAL %d\n", target_nid, ne->kpne_interface.kprni_nalid);
155 if (ne->kpne_shutdown) /* caller is shutting down */
158 read_lock (&kpr_rwlock);
160 /* Search routes for one that has a gateway to target_nid on the callers network */
162 for (e = kpr_routes.next; e != &kpr_routes; e = e->next)
164 kpr_route_entry_t *re = list_entry (e, kpr_route_entry_t, kpre_list);
166 if (re->kpre_lo_nid > target_nid ||
167 re->kpre_hi_nid < target_nid)
170 /* found table entry */
172 if (re->kpre_gateway_nalid != ne->kpne_interface.kprni_nalid) /* different NAL */
177 *gateway_nidp = re->kpre_gateway_nid;
182 read_unlock (&kpr_rwlock);
184 CDEBUG (D_OTHER, "lookup "LPX64" from NAL %d: %d ("LPX64")\n",
185 target_nid, ne->kpne_interface.kprni_nalid, rc,
186 (rc == 0) ? *gateway_nidp : (ptl_nid_t)0);
191 kpr_forward_packet (void *arg, kpr_fwd_desc_t *fwd)
193 kpr_nal_entry_t *src_ne = (kpr_nal_entry_t *)arg;
194 ptl_nid_t target_nid = fwd->kprfd_target_nid;
195 int nob = fwd->kprfd_nob;
198 CDEBUG (D_OTHER, "forward [%p] "LPX64" from NAL %d\n", fwd,
199 target_nid, src_ne->kpne_interface.kprni_nalid);
201 LASSERT (nob >= sizeof (ptl_hdr_t)); /* at least got a packet header */
202 LASSERT (nob == lib_iov_nob (fwd->kprfd_niov, fwd->kprfd_iov));
204 atomic_inc (&kpr_queue_depth);
205 atomic_inc (&src_ne->kpne_refcount); /* source nal is busy until fwd completes */
207 kpr_fwd_packets++; /* (loose) stats accounting */
208 kpr_fwd_bytes += nob;
210 if (src_ne->kpne_shutdown) /* caller is shutting down */
213 fwd->kprfd_router_arg = src_ne; /* stash caller's nal entry */
215 read_lock (&kpr_rwlock);
217 /* Search routes for one that has a gateway to target_nid NOT on the caller's network */
219 for (e = kpr_routes.next; e != &kpr_routes; e = e->next)
221 kpr_route_entry_t *re = list_entry (e, kpr_route_entry_t, kpre_list);
223 if (re->kpre_lo_nid > target_nid || /* no match */
224 re->kpre_hi_nid < target_nid)
227 CDEBUG (D_OTHER, "forward [%p] "LPX64" from NAL %d: match "LPX64" on NAL %d\n", fwd,
228 target_nid, src_ne->kpne_interface.kprni_nalid,
229 re->kpre_gateway_nid, re->kpre_gateway_nalid);
231 if (re->kpre_gateway_nalid == src_ne->kpne_interface.kprni_nalid)
232 break; /* don't route to same NAL */
234 /* Search for gateway's NAL's entry */
236 for (e = kpr_nals.next; e != &kpr_nals; e = e->next)
238 kpr_nal_entry_t *dst_ne = list_entry (e, kpr_nal_entry_t, kpne_list);
240 if (re->kpre_gateway_nalid != dst_ne->kpne_interface.kprni_nalid) /* no match */
243 if (dst_ne->kpne_shutdown) /* don't route if NAL is shutting down */
246 fwd->kprfd_gateway_nid = re->kpre_gateway_nid;
247 atomic_inc (&dst_ne->kpne_refcount); /* dest nal is busy until fwd completes */
249 read_unlock (&kpr_rwlock);
251 CDEBUG (D_OTHER, "forward [%p] "LPX64" from NAL %d: "LPX64" on NAL %d\n", fwd,
252 target_nid, src_ne->kpne_interface.kprni_nalid,
253 fwd->kprfd_gateway_nid, dst_ne->kpne_interface.kprni_nalid);
255 dst_ne->kpne_interface.kprni_fwd (dst_ne->kpne_interface.kprni_arg, fwd);
261 read_unlock (&kpr_rwlock);
265 CDEBUG (D_OTHER, "Failed to forward [%p] "LPX64" from NAL %d\n", fwd,
266 target_nid, src_ne->kpne_interface.kprni_nalid);
268 /* Can't find anywhere to forward to */
269 (fwd->kprfd_callback)(fwd->kprfd_callback_arg, -EHOSTUNREACH);
271 atomic_dec (&kpr_queue_depth);
272 atomic_dec (&src_ne->kpne_refcount);
276 kpr_complete_packet (void *arg, kpr_fwd_desc_t *fwd, int error)
278 kpr_nal_entry_t *dst_ne = (kpr_nal_entry_t *)arg;
279 kpr_nal_entry_t *src_ne = (kpr_nal_entry_t *)fwd->kprfd_router_arg;
281 CDEBUG (D_OTHER, "complete(1) [%p] from NAL %d to NAL %d: %d\n", fwd,
282 src_ne->kpne_interface.kprni_nalid, dst_ne->kpne_interface.kprni_nalid, error);
284 atomic_dec (&dst_ne->kpne_refcount); /* CAVEAT EMPTOR dst_ne can disappear now!!! */
286 (fwd->kprfd_callback)(fwd->kprfd_callback_arg, error);
288 CDEBUG (D_OTHER, "complete(2) [%p] from NAL %d: %d\n", fwd,
289 src_ne->kpne_interface.kprni_nalid, error);
291 atomic_dec (&kpr_queue_depth);
292 atomic_dec (&src_ne->kpne_refcount); /* CAVEAT EMPTOR src_ne can disappear now!!! */
296 kpr_add_route (int gateway_nalid, ptl_nid_t gateway_nid, ptl_nid_t lo_nid,
301 kpr_route_entry_t *re;
303 CDEBUG(D_OTHER, "Add route: %d "LPX64" : "LPX64" - "LPX64"\n",
304 gateway_nalid, gateway_nid, lo_nid, hi_nid);
306 LASSERT(lo_nid <= hi_nid);
308 PORTAL_ALLOC (re, sizeof (*re));
312 re->kpre_gateway_nalid = gateway_nalid;
313 re->kpre_gateway_nid = gateway_nid;
314 re->kpre_lo_nid = lo_nid;
315 re->kpre_hi_nid = hi_nid;
317 LASSERT(!in_interrupt());
318 write_lock_irqsave (&kpr_rwlock, flags);
320 for (e = kpr_routes.next; e != &kpr_routes; e = e->next) {
321 kpr_route_entry_t *re2 = list_entry(e, kpr_route_entry_t,
324 if (re->kpre_lo_nid > re2->kpre_hi_nid ||
325 re->kpre_hi_nid < re2->kpre_lo_nid)
328 CERROR ("Attempt to add duplicate routes ["LPX64" - "LPX64"]"
329 "to ["LPX64" - "LPX64"]\n",
330 re->kpre_lo_nid, re->kpre_hi_nid,
331 re2->kpre_lo_nid, re2->kpre_hi_nid);
333 write_unlock_irqrestore (&kpr_rwlock, flags);
335 PORTAL_FREE (re, sizeof (*re));
339 list_add (&re->kpre_list, &kpr_routes);
341 write_unlock_irqrestore (&kpr_rwlock, flags);
346 kpr_del_route (ptl_nid_t nid)
351 CDEBUG(D_OTHER, "Del route "LPX64"\n", nid);
353 LASSERT(!in_interrupt());
354 write_lock_irqsave(&kpr_rwlock, flags);
356 for (e = kpr_routes.next; e != &kpr_routes; e = e->next) {
357 kpr_route_entry_t *re = list_entry(e, kpr_route_entry_t,
360 if (re->kpre_lo_nid > nid || re->kpre_hi_nid < nid)
363 list_del (&re->kpre_list);
364 write_unlock_irqrestore(&kpr_rwlock, flags);
366 PORTAL_FREE(re, sizeof (*re));
370 write_unlock_irqrestore(&kpr_rwlock, flags);
375 kpr_get_route(int idx, int *gateway_nalid, ptl_nid_t *gateway_nid,
376 ptl_nid_t *lo_nid, ptl_nid_t *hi_nid)
380 read_lock(&kpr_rwlock);
382 for (e = kpr_routes.next; e != &kpr_routes; e = e->next) {
383 kpr_route_entry_t *re = list_entry(e, kpr_route_entry_t,
387 *gateway_nalid = re->kpre_gateway_nalid;
388 *gateway_nid = re->kpre_gateway_nid;
389 *lo_nid = re->kpre_lo_nid;
390 *hi_nid = re->kpre_hi_nid;
392 read_unlock(&kpr_rwlock);
397 read_unlock (&kpr_rwlock);
401 static void /*__exit*/
404 LASSERT (list_empty (&kpr_nals));
406 while (!list_empty (&kpr_routes)) {
407 kpr_route_entry_t *re = list_entry(kpr_routes.next,
411 list_del(&re->kpre_list);
412 PORTAL_FREE(re, sizeof (*re));
417 PORTAL_SYMBOL_UNREGISTER(kpr_router_interface);
418 PORTAL_SYMBOL_UNREGISTER(kpr_control_interface);
420 CDEBUG(D_MALLOC, "kpr_finalise: kmem back to %d\n",
421 atomic_read(&portal_kmemory));
425 kpr_initialise (void)
427 CDEBUG(D_MALLOC, "kpr_initialise: kmem %d\n",
428 atomic_read(&portal_kmemory));
432 PORTAL_SYMBOL_REGISTER(kpr_router_interface);
433 PORTAL_SYMBOL_REGISTER(kpr_control_interface);
437 MODULE_AUTHOR("Eric Barton");
438 MODULE_DESCRIPTION("Kernel Portals Router v0.01");
439 MODULE_LICENSE("GPL");
441 module_init (kpr_initialise);
442 module_exit (kpr_finalise);
444 EXPORT_SYMBOL (kpr_control_interface);
445 EXPORT_SYMBOL (kpr_router_interface);