]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
rx: Add rx_GetNetworkError
authorAndrew Deason <adeason@sinenomine.net>
Tue, 13 Nov 2012 20:54:10 +0000 (14:54 -0600)
committerDerrick Brashear <shadow@your-file-system.com>
Wed, 5 Dec 2012 18:46:34 +0000 (10:46 -0800)
Add the function rx_GetNetworkError to rx, to allow callers to
retrieve some information about the last ICMP error received for a
connection's peer. This can be useful if a call on that connection was
recently ended due to ICMP errors.

Change-Id: I7c507185f6a4ab986c0119f67cdaa4e50e447175
Reviewed-on: http://gerrit.openafs.org/8451
Reviewed-by: Derrick Brashear <shadow@your-file-system.com>
Tested-by: BuildBot <buildbot@rampaginggeek.com>
src/libafsrpc/afsrpc.def
src/libafsrpc/libafsrpc.la.sym
src/rx/liboafs_rx.la.sym
src/rx/rx.c
src/rx/rx.h
src/rx/rx_peer.h
src/rx/rx_prototypes.h

index 780a9b3ce390c4a9197d63ae8e69ae6c79d07e82..5d5a4b356d89105d5d93e85c844322edab791ee3 100755 (executable)
@@ -338,6 +338,7 @@ EXPORTS
        rx_ReleaseRPCStats                      @343
         RXAFS_OpCodeIndex                       @344
        initialize_RXK_error_table              @345
+       rx_GetNetworkError                      @346
 
 ; for performance testing
         rx_TSFPQGlobSize                        @2001 DATA
index d0b4f5ef67ab7cd0b879af0650a2c93dde1606b1..ea00c3e28f3f2407f114b187ada657f8ec48f6e9 100644 (file)
@@ -170,3 +170,4 @@ rx_HostOf
 rx_PortOf
 initialize_RXK_error_table
 rx_getAllAddrMaskMtu
+rx_GetNetworkError
index 7f3e80965e9233bcab4579785666d3041de2a099..92ce66e734f0e4d176d1789d91505ac37f3ecb53 100644 (file)
@@ -155,3 +155,4 @@ xdr_afs_uint32
 xdr_afs_uint64
 xdrlen_create
 xdrrx_create
+rx_GetNetworkError
index a2ac7b53de1fb520fe903b4a54a2f9361ce810ca..fed35c8529d1c1e940dfd8075aa2481e90e91fad 100644 (file)
@@ -2943,7 +2943,7 @@ rxi_SetPeerMtu(struct rx_peer *peer, afs_uint32 host, afs_uint32 port, int mtu)
 
 #ifdef AFS_RXERRQ_ENV
 static void
-rxi_SetPeerDead(afs_uint32 host, afs_uint16 port)
+rxi_SetPeerDead(struct sock_extended_err *err, afs_uint32 host, afs_uint16 port)
 {
     int hashIndex = PEER_HASH(host, port);
     struct rx_peer *peer;
@@ -2952,15 +2952,25 @@ rxi_SetPeerDead(afs_uint32 host, afs_uint16 port)
 
     for (peer = rx_peerHashTable[hashIndex]; peer; peer = peer->next) {
        if (peer->host == host && peer->port == port) {
+           peer->refCount++;
            break;
        }
     }
 
+    MUTEX_EXIT(&rx_peerHashTable_lock);
+
     if (peer) {
        rx_atomic_inc(&peer->neterrs);
-    }
+       MUTEX_ENTER(&peer->peer_lock);
+       peer->last_err_origin = RX_NETWORK_ERROR_ORIGIN_ICMP;
+       peer->last_err_type = err->ee_type;
+       peer->last_err_code = err->ee_code;
+       MUTEX_EXIT(&peer->peer_lock);
 
-    MUTEX_EXIT(&rx_peerHashTable_lock);
+       MUTEX_ENTER(&rx_peerHashTable_lock);
+       peer->refCount--;
+       MUTEX_EXIT(&rx_peerHashTable_lock);
+    }
 }
 
 void
@@ -2979,13 +2989,87 @@ rxi_ProcessNetError(struct sock_extended_err *err, afs_uint32 addr, afs_uint16 p
        case ICMP_PORT_UNREACH:
        case ICMP_NET_ANO:
        case ICMP_HOST_ANO:
-           rxi_SetPeerDead(addr, port);
+           rxi_SetPeerDead(err, addr, port);
            break;
        }
     }
 }
+
+static const char *
+rxi_TranslateICMP(int type, int code)
+{
+    switch (type) {
+    case ICMP_DEST_UNREACH:
+       switch (code) {
+       case ICMP_NET_UNREACH:
+           return "Destination Net Unreachable";
+       case ICMP_HOST_UNREACH:
+           return "Destination Host Unreachable";
+       case ICMP_PROT_UNREACH:
+           return "Destination Protocol Unreachable";
+       case ICMP_PORT_UNREACH:
+           return "Destination Port Unreachable";
+       case ICMP_NET_ANO:
+           return "Destination Net Prohibited";
+       case ICMP_HOST_ANO:
+           return "Destination Host Prohibited";
+       }
+       break;
+    }
+    return NULL;
+}
 #endif /* AFS_RXERRQ_ENV */
 
+/**
+ * Get the last network error for a connection
+ *
+ * A "network error" here means an error retrieved from ICMP, or some other
+ * mechanism outside of Rx that informs us of errors in network reachability.
+ *
+ * If a peer associated with the given Rx connection has received a network
+ * error recently, this function allows the caller to know what error
+ * specifically occurred. This can be useful to know, since e.g. ICMP errors
+ * can cause calls to that peer to be quickly aborted. So, this function can
+ * help see why a call was aborted due to network errors.
+ *
+ * If we have received traffic from a peer since the last network error, we
+ * treat that peer as if we had not received an network error for it.
+ *
+ * @param[in] conn  The Rx connection to examine
+ * @param[out] err_origin  The origin of the last network error (e.g. ICMP);
+ *                         one of the RX_NETWORK_ERROR_ORIGIN_* constants
+ * @param[out] err_type  The type of the last error
+ * @param[out] err_code  The code of the last error
+ * @param[out] msg  Human-readable error message, if applicable; NULL otherwise
+ *
+ * @return If we have an error
+ *  @retval -1 No error to get; 'out' params are undefined
+ *  @retval 0 We have an error; 'out' params contain the last error
+ */
+int
+rx_GetNetworkError(struct rx_connection *conn, int *err_origin, int *err_type,
+                   int *err_code, const char **msg)
+{
+#ifdef AFS_RXERRQ_ENV
+    struct rx_peer *peer = conn->peer;
+    if (rx_atomic_read(&peer->neterrs)) {
+       MUTEX_ENTER(&peer->peer_lock);
+       *err_origin = peer->last_err_origin;
+       *err_type = peer->last_err_type;
+       *err_code = peer->last_err_code;
+       MUTEX_EXIT(&peer->peer_lock);
+
+       *msg = NULL;
+       if (*err_origin == RX_NETWORK_ERROR_ORIGIN_ICMP) {
+           *msg = rxi_TranslateICMP(*err_type, *err_code);
+       }
+
+       return 0;
+    }
+#endif
+    return -1;
+}
+
 /* Find the peer process represented by the supplied (host,port)
  * combination.  If there is no appropriate active peer structure, a
  * new one will be allocated and initialized
index a7cf4d2fec28a1d290bc73f5493aba80624eaa81..da5dd9f137eed93824df944dc06518755baf1147 100644 (file)
@@ -452,6 +452,15 @@ struct rx_ackPacket {
 #define        RX_CHECKREACH_TIMEOUT   2       /* Number of seconds before another ping is generated */
 #define        RX_CHECKREACH_TTL       60      /* Re-check reachability this often */
 
+/*
+ * rx_GetNetworkError 'origin' constants. These define the meaning of the
+ * 'type' and 'code' values returned by rx_GetNetworkError.
+ */
+
+/* Used for ICMP errors; the type and code are the ICMP type and code,
+ * respectively */
+#define RX_NETWORK_ERROR_ORIGIN_ICMP (0)
+
 /*
  * RX error codes.  RX uses error codes from -1 to -64 and -100.
  * Rxgen uses other error codes < -64 (see src/rxgen/rpc_errors.h);
index ca747f6e0cf2612b51ad5d7138e8496c1958c79a..eef36776ef02061effa666e09b5286f6c877f6b4 100644 (file)
@@ -65,6 +65,11 @@ struct rx_peer {
     afs_int32 maxPacketSize;    /* peer packetsize hint */
 #ifdef AFS_RXERRQ_ENV
     rx_atomic_t neterrs;
+
+    /* protected by peer_lock */
+    int last_err_origin; /* origin of the last network error received */
+    int last_err_type; /* last error 'type' received */
+    int last_err_code; /* last error 'code' received */
 #endif
 };
 
index 1fe2cd82cac3a5fb3e743d1da1ba7041342cfd14..87cffff190b069f644cd8816ac5ea1b92b48c3ff 100644 (file)
@@ -179,6 +179,9 @@ void rxi_DebugInit(void);
 void rxi_DebugPrint(char *format, ...)
     AFS_ATTRIBUTE_FORMAT(__printf__, 1, 2);
 
+extern int rx_GetNetworkError(struct rx_connection *conn, int *err_origin,
+                              int *err_type, int *err_code, const char **msg);
+
 /* rx_clock.c */
 #if !defined(clock_Init)
 extern void clock_Init(void);