ib_pathrec.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  */
00018 
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020 
00021 #include <stdint.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <byteswap.h>
00025 #include <errno.h>
00026 #include <gpxe/infiniband.h>
00027 #include <gpxe/ib_mi.h>
00028 #include <gpxe/ib_pathrec.h>
00029 
00030 /** @file
00031  *
00032  * Infiniband path lookups
00033  *
00034  */
00035 
00036 /**
00037  * Handle path transaction completion
00038  *
00039  * @v ibdev             Infiniband device
00040  * @v mi                Management interface
00041  * @v madx              Management transaction
00042  * @v rc                Status code
00043  * @v mad               Received MAD (or NULL on error)
00044  * @v av                Source address vector (or NULL on error)
00045  */
00046 static void ib_path_complete ( struct ib_device *ibdev,
00047                                struct ib_mad_interface *mi,
00048                                struct ib_mad_transaction *madx,
00049                                int rc, union ib_mad *mad,
00050                                struct ib_address_vector *av __unused ) {
00051         struct ib_path *path = ib_madx_get_ownerdata ( madx );
00052         struct ib_gid *dgid = &path->av.gid;
00053         struct ib_path_record *pathrec = &mad->sa.sa_data.path_record;
00054 
00055         /* Report failures */
00056         if ( ( rc == 0 ) && ( mad->hdr.status != htons ( IB_MGMT_STATUS_OK ) ))
00057                 rc = -ENETUNREACH;
00058         if ( rc != 0 ) {
00059                 DBGC ( ibdev, "IBDEV %p path lookup for %08x:%08x:%08x:%08x "
00060                        "failed: %s\n", ibdev, htonl ( dgid->u.dwords[0] ),
00061                        htonl ( dgid->u.dwords[1] ),
00062                        htonl ( dgid->u.dwords[2] ),
00063                        htonl ( dgid->u.dwords[3] ), strerror ( rc ) );
00064                 goto out;
00065         }
00066 
00067         /* Extract values from MAD */
00068         path->av.lid = ntohs ( pathrec->dlid );
00069         path->av.sl = ( pathrec->reserved__sl & 0x0f );
00070         path->av.rate = ( pathrec->rate_selector__rate & 0x3f );
00071         DBGC ( ibdev, "IBDEV %p path to %08x:%08x:%08x:%08x is %04x sl %d "
00072                "rate %d\n", ibdev, htonl ( dgid->u.dwords[0] ),
00073                htonl ( dgid->u.dwords[1] ), htonl ( dgid->u.dwords[2] ),
00074                htonl ( dgid->u.dwords[3] ), path->av.lid, path->av.sl,
00075                path->av.rate );
00076 
00077  out:
00078         /* Destroy the completed transaction */
00079         ib_destroy_madx ( ibdev, mi, madx );
00080         path->madx = NULL;
00081 
00082         /* Hand off to upper completion handler */
00083         path->op->complete ( ibdev, path, rc, &path->av );
00084 }
00085 
00086 /** Path transaction completion operations */
00087 static struct ib_mad_transaction_operations ib_path_op = {
00088         .complete = ib_path_complete,
00089 };
00090 
00091 /**
00092  * Create path
00093  *
00094  * @v ibdev             Infiniband device
00095  * @v av                Address vector to complete
00096  * @v op                Path operations
00097  * @ret path            Path
00098  */
00099 struct ib_path *
00100 ib_create_path ( struct ib_device *ibdev, struct ib_address_vector *av,
00101                  struct ib_path_operations *op ) {
00102         struct ib_path *path;
00103         union ib_mad mad;
00104         struct ib_mad_sa *sa = &mad.sa;
00105 
00106         /* Allocate and initialise structure */
00107         path = zalloc ( sizeof ( *path ) );
00108         if ( ! path )
00109                 goto err_alloc_path;
00110         path->ibdev = ibdev;
00111         memcpy ( &path->av, av, sizeof ( path->av ) );
00112         path->op = op;
00113 
00114         /* Construct path request */
00115         memset ( sa, 0, sizeof ( *sa ) );
00116         sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
00117         sa->mad_hdr.class_version = IB_SA_CLASS_VERSION;
00118         sa->mad_hdr.method = IB_MGMT_METHOD_GET;
00119         sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_PATH_REC );
00120         sa->sa_hdr.comp_mask[1] =
00121                 htonl ( IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID );
00122         memcpy ( &sa->sa_data.path_record.dgid, &path->av.gid,
00123                  sizeof ( sa->sa_data.path_record.dgid ) );
00124         memcpy ( &sa->sa_data.path_record.sgid, &ibdev->gid,
00125                  sizeof ( sa->sa_data.path_record.sgid ) );
00126 
00127         /* Create management transaction */
00128         path->madx = ib_create_madx ( ibdev, ibdev->gsi, &mad, NULL,
00129                                       &ib_path_op );
00130         if ( ! path->madx )
00131                 goto err_create_madx;
00132         ib_madx_set_ownerdata ( path->madx, path );
00133 
00134         return path;
00135 
00136         ib_destroy_madx ( ibdev, ibdev->gsi, path->madx );
00137  err_create_madx:
00138         free ( path );
00139  err_alloc_path:
00140         return NULL;
00141 }
00142 
00143 /**
00144  * Destroy path
00145  *
00146  * @v ibdev             Infiniband device
00147  * @v path              Path
00148  */
00149 void ib_destroy_path ( struct ib_device *ibdev, struct ib_path *path ) {
00150 
00151         if ( path->madx )
00152                 ib_destroy_madx ( ibdev, ibdev->gsi, path->madx );
00153         free ( path );
00154 }
00155 
00156 /** Number of path cache entries
00157  *
00158  * Must be a power of two.
00159  */
00160 #define IB_NUM_CACHED_PATHS 4
00161 
00162 /** A cached path */
00163 struct ib_cached_path {
00164         /** Path */
00165         struct ib_path *path;
00166 };
00167 
00168 /** Path cache */
00169 static struct ib_cached_path ib_path_cache[IB_NUM_CACHED_PATHS];
00170 
00171 /** Oldest path cache entry index */
00172 static unsigned int ib_path_cache_idx;
00173 
00174 /**
00175  * Find path cache entry
00176  *
00177  * @v ibdev             Infiniband device
00178  * @v dgid              Destination GID
00179  * @ret path            Path cache entry, or NULL
00180  */
00181 static struct ib_cached_path *
00182 ib_find_path_cache_entry ( struct ib_device *ibdev, struct ib_gid *dgid ) {
00183         struct ib_cached_path *cached;
00184         unsigned int i;
00185 
00186         for ( i = 0 ; i < IB_NUM_CACHED_PATHS ; i++ ) {
00187                 cached = &ib_path_cache[i];
00188                 if ( ! cached->path )
00189                         continue;
00190                 if ( cached->path->ibdev != ibdev )
00191                         continue;
00192                 if ( memcmp ( &cached->path->av.gid, dgid,
00193                               sizeof ( cached->path->av.gid ) ) != 0 )
00194                         continue;
00195                 return cached;
00196         }
00197 
00198         return NULL;
00199 }
00200 
00201 /**
00202  * Handle cached path transaction completion
00203  *
00204  * @v ibdev             Infiniband device
00205  * @v path              Path
00206  * @v rc                Status code
00207  * @v av                Address vector, or NULL on error
00208  */
00209 static void ib_cached_path_complete ( struct ib_device *ibdev,
00210                                       struct ib_path *path, int rc,
00211                                       struct ib_address_vector *av __unused ) {
00212         struct ib_cached_path *cached = ib_path_get_ownerdata ( path );
00213 
00214         /* If the transaction failed, erase the cache entry */
00215         if ( rc != 0 ) {
00216                 /* Destroy the old cache entry */
00217                 ib_destroy_path ( ibdev, path );
00218                 memset ( cached, 0, sizeof ( *cached ) );
00219                 return;
00220         }
00221 
00222         /* Do not destroy the completed transaction; we still need to
00223          * refer to the resolved path.
00224          */
00225 }
00226 
00227 /** Cached path transaction completion operations */
00228 static struct ib_path_operations ib_cached_path_op = {
00229         .complete = ib_cached_path_complete,
00230 };
00231 
00232 /**
00233  * Resolve path
00234  *
00235  * @v ibdev             Infiniband device
00236  * @v av                Address vector to complete
00237  * @ret rc              Return status code
00238  *
00239  * This provides a non-transactional way to resolve a path, via a
00240  * cache similar to ARP.
00241  */
00242 int ib_resolve_path ( struct ib_device *ibdev, struct ib_address_vector *av ) {
00243         struct ib_gid *gid = &av->gid;
00244         struct ib_cached_path *cached;
00245         unsigned int cache_idx;
00246 
00247         /* Sanity check */
00248         if ( ! av->gid_present ) {
00249                 DBGC ( ibdev, "IBDEV %p attempt to look up path "
00250                        "without GID\n", ibdev );
00251                 return -EINVAL;
00252         }
00253 
00254         /* Look in cache for a matching entry */
00255         cached = ib_find_path_cache_entry ( ibdev, gid );
00256         if ( cached && cached->path->av.lid ) {
00257                 /* Populated entry found */
00258                 av->lid = cached->path->av.lid;
00259                 av->rate = cached->path->av.rate;
00260                 av->sl = cached->path->av.sl;
00261                 DBGC2 ( ibdev, "IBDEV %p cache hit for %08x:%08x:%08x:%08x\n",
00262                         ibdev, htonl ( gid->u.dwords[0] ),
00263                         htonl ( gid->u.dwords[1] ), htonl ( gid->u.dwords[2] ),
00264                         htonl ( gid->u.dwords[3] ) );
00265                 return 0;
00266         }
00267         DBGC ( ibdev, "IBDEV %p cache miss for %08x:%08x:%08x:%08x%s\n",
00268                ibdev, htonl ( gid->u.dwords[0] ), htonl ( gid->u.dwords[1] ),
00269                htonl ( gid->u.dwords[2] ), htonl ( gid->u.dwords[3] ),
00270                ( cached ? " (in progress)" : "" ) );
00271 
00272         /* If lookup is already in progress, do nothing */
00273         if ( cached )
00274                 return -ENOENT;
00275 
00276         /* Locate a new cache entry to use */
00277         cache_idx = ( (ib_path_cache_idx++) % IB_NUM_CACHED_PATHS );
00278         cached = &ib_path_cache[cache_idx];
00279 
00280         /* Destroy the old cache entry */
00281         if ( cached->path )
00282                 ib_destroy_path ( ibdev, cached->path );
00283         memset ( cached, 0, sizeof ( *cached ) );
00284 
00285         /* Create new path */
00286         cached->path = ib_create_path ( ibdev, av, &ib_cached_path_op );
00287         if ( ! cached->path ) {
00288                 DBGC ( ibdev, "IBDEV %p could not create path\n",
00289                        ibdev );
00290                 return -ENOMEM;
00291         }
00292         ib_path_set_ownerdata ( cached->path, cached );
00293 
00294         /* Not found yet */
00295         return -ENOENT;
00296 }

Generated on Tue Apr 6 20:01:10 2010 for gPXE by  doxygen 1.5.7.1