3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
14 /* the round robin data must be first */
15 ngx_http_upstream_rr_peer_data_t rrp
;
24 ngx_event_get_peer_pt get_rr_peer
;
25 } ngx_http_upstream_ip_hash_peer_data_t
;
28 static ngx_int_t
ngx_http_upstream_init_ip_hash_peer(ngx_http_request_t
*r
,
29 ngx_http_upstream_srv_conf_t
*us
);
30 static ngx_int_t
ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t
*pc
,
32 static char *ngx_http_upstream_ip_hash(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
36 static ngx_command_t ngx_http_upstream_ip_hash_commands
[] = {
38 { ngx_string("ip_hash"),
39 NGX_HTTP_UPS_CONF
|NGX_CONF_NOARGS
,
40 ngx_http_upstream_ip_hash
,
49 static ngx_http_module_t ngx_http_upstream_ip_hash_module_ctx
= {
50 NULL
, /* preconfiguration */
51 NULL
, /* postconfiguration */
53 NULL
, /* create main configuration */
54 NULL
, /* init main configuration */
56 NULL
, /* create server configuration */
57 NULL
, /* merge server configuration */
59 NULL
, /* create location configuration */
60 NULL
/* merge location configuration */
64 ngx_module_t ngx_http_upstream_ip_hash_module
= {
66 &ngx_http_upstream_ip_hash_module_ctx
, /* module context */
67 ngx_http_upstream_ip_hash_commands
, /* module directives */
68 NGX_HTTP_MODULE
, /* module type */
69 NULL
, /* init master */
70 NULL
, /* init module */
71 NULL
, /* init process */
72 NULL
, /* init thread */
73 NULL
, /* exit thread */
74 NULL
, /* exit process */
75 NULL
, /* exit master */
80 static u_char ngx_http_upstream_ip_hash_pseudo_addr
[3];
84 ngx_http_upstream_init_ip_hash(ngx_conf_t
*cf
, ngx_http_upstream_srv_conf_t
*us
)
86 if (ngx_http_upstream_init_round_robin(cf
, us
) != NGX_OK
) {
90 us
->peer
.init
= ngx_http_upstream_init_ip_hash_peer
;
97 ngx_http_upstream_init_ip_hash_peer(ngx_http_request_t
*r
,
98 ngx_http_upstream_srv_conf_t
*us
)
100 struct sockaddr_in
*sin
;
102 struct sockaddr_in6
*sin6
;
104 ngx_http_upstream_ip_hash_peer_data_t
*iphp
;
106 iphp
= ngx_palloc(r
->pool
, sizeof(ngx_http_upstream_ip_hash_peer_data_t
));
111 r
->upstream
->peer
.data
= &iphp
->rrp
;
113 if (ngx_http_upstream_init_round_robin_peer(r
, us
) != NGX_OK
) {
117 r
->upstream
->peer
.get
= ngx_http_upstream_get_ip_hash_peer
;
119 switch (r
->connection
->sockaddr
->sa_family
) {
122 sin
= (struct sockaddr_in
*) r
->connection
->sockaddr
;
123 iphp
->addr
= (u_char
*) &sin
->sin_addr
.s_addr
;
129 sin6
= (struct sockaddr_in6
*) r
->connection
->sockaddr
;
130 iphp
->addr
= (u_char
*) &sin6
->sin6_addr
.s6_addr
;
136 iphp
->addr
= ngx_http_upstream_ip_hash_pseudo_addr
;
142 iphp
->get_rr_peer
= ngx_http_upstream_get_round_robin_peer
;
149 ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t
*pc
, void *data
)
151 ngx_http_upstream_ip_hash_peer_data_t
*iphp
= data
;
156 ngx_uint_t i
, n
, p
, hash
;
157 ngx_http_upstream_rr_peer_t
*peer
;
159 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, pc
->log
, 0,
160 "get ip hash peer, try: %ui", pc
->tries
);
164 if (iphp
->tries
> 20 || iphp
->rrp
.peers
->single
) {
165 return iphp
->get_rr_peer(pc
, &iphp
->rrp
);
171 pc
->connection
= NULL
;
177 for (i
= 0; i
< iphp
->addrlen
; i
++) {
178 hash
= (hash
* 113 + iphp
->addr
[i
]) % 6271;
181 if (!iphp
->rrp
.peers
->weighted
) {
182 p
= hash
% iphp
->rrp
.peers
->number
;
185 w
= hash
% iphp
->rrp
.peers
->total_weight
;
187 for (i
= 0; i
< iphp
->rrp
.peers
->number
; i
++) {
188 w
-= iphp
->rrp
.peers
->peer
[i
].weight
;
197 n
= p
/ (8 * sizeof(uintptr_t));
198 m
= (uintptr_t) 1 << p
% (8 * sizeof(uintptr_t));
200 if (!(iphp
->rrp
.tried
[n
] & m
)) {
202 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, pc
->log
, 0,
203 "get ip hash peer, hash: %ui %04XA", p
, m
);
205 peer
= &iphp
->rrp
.peers
->peer
[p
];
207 /* ngx_lock_mutex(iphp->rrp.peers->mutex); */
211 if (peer
->max_fails
== 0 || peer
->fails
< peer
->max_fails
) {
215 if (now
- peer
->checked
> peer
->fail_timeout
) {
221 iphp
->rrp
.tried
[n
] |= m
;
223 /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
228 if (++iphp
->tries
>= 20) {
229 return iphp
->get_rr_peer(pc
, &iphp
->rrp
);
233 iphp
->rrp
.current
= p
;
235 pc
->sockaddr
= peer
->sockaddr
;
236 pc
->socklen
= peer
->socklen
;
237 pc
->name
= &peer
->name
;
239 /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
241 iphp
->rrp
.tried
[n
] |= m
;
249 ngx_http_upstream_ip_hash(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
251 ngx_http_upstream_srv_conf_t
*uscf
;
253 uscf
= ngx_http_conf_get_module_srv_conf(cf
, ngx_http_upstream_module
);
255 if (uscf
->peer
.init_upstream
) {
256 ngx_conf_log_error(NGX_LOG_WARN
, cf
, 0,
257 "load balancing method redefined");
260 uscf
->peer
.init_upstream
= ngx_http_upstream_init_ip_hash
;
262 uscf
->flags
= NGX_HTTP_UPSTREAM_CREATE
263 |NGX_HTTP_UPSTREAM_WEIGHT
264 |NGX_HTTP_UPSTREAM_MAX_FAILS
265 |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
266 |NGX_HTTP_UPSTREAM_DOWN
;