From: Andrew Deason Date: Tue, 13 Nov 2012 20:54:10 +0000 (-0600) Subject: rx: Add rx_GetNetworkError X-Git-Tag: upstream/1.8.0_pre1^2~1739 X-Git-Url: https://git.michaelhowe.org/gitweb/?a=commitdiff_plain;h=399abf159b1418dea38daf166f9d55072042909c;p=packages%2Fo%2Fopenafs.git rx: Add rx_GetNetworkError 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 Tested-by: BuildBot --- diff --git a/src/libafsrpc/afsrpc.def b/src/libafsrpc/afsrpc.def index 780a9b3ce..5d5a4b356 100755 --- a/src/libafsrpc/afsrpc.def +++ b/src/libafsrpc/afsrpc.def @@ -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 diff --git a/src/libafsrpc/libafsrpc.la.sym b/src/libafsrpc/libafsrpc.la.sym index d0b4f5ef6..ea00c3e28 100644 --- a/src/libafsrpc/libafsrpc.la.sym +++ b/src/libafsrpc/libafsrpc.la.sym @@ -170,3 +170,4 @@ rx_HostOf rx_PortOf initialize_RXK_error_table rx_getAllAddrMaskMtu +rx_GetNetworkError diff --git a/src/rx/liboafs_rx.la.sym b/src/rx/liboafs_rx.la.sym index 7f3e80965..92ce66e73 100644 --- a/src/rx/liboafs_rx.la.sym +++ b/src/rx/liboafs_rx.la.sym @@ -155,3 +155,4 @@ xdr_afs_uint32 xdr_afs_uint64 xdrlen_create xdrrx_create +rx_GetNetworkError diff --git a/src/rx/rx.c b/src/rx/rx.c index a2ac7b53d..fed35c852 100644 --- a/src/rx/rx.c +++ b/src/rx/rx.c @@ -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 diff --git a/src/rx/rx.h b/src/rx/rx.h index a7cf4d2fe..da5dd9f13 100644 --- a/src/rx/rx.h +++ b/src/rx/rx.h @@ -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); diff --git a/src/rx/rx_peer.h b/src/rx/rx_peer.h index ca747f6e0..eef36776e 100644 --- a/src/rx/rx_peer.h +++ b/src/rx/rx_peer.h @@ -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 }; diff --git a/src/rx/rx_prototypes.h b/src/rx/rx_prototypes.h index 1fe2cd82c..87cffff19 100644 --- a/src/rx/rx_prototypes.h +++ b/src/rx/rx_prototypes.h @@ -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);