Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 
0012 
0013 typedef struct {
0014     /* the round robin data must be first */
0015     ngx_http_upstream_rr_peer_data_t   rrp;
0016 
0017     ngx_uint_t                         hash;
0018 
0019     u_char                             addrlen;
0020     u_char                            *addr;
0021 
0022     u_char                             tries;
0023 
0024     ngx_event_get_peer_pt              get_rr_peer;
0025 } ngx_http_upstream_ip_hash_peer_data_t;
0026 
0027 
0028 static ngx_int_t ngx_http_upstream_init_ip_hash_peer(ngx_http_request_t *r,
0029     ngx_http_upstream_srv_conf_t *us);
0030 static ngx_int_t ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc,
0031     void *data);
0032 static char *ngx_http_upstream_ip_hash(ngx_conf_t *cf, ngx_command_t *cmd,
0033     void *conf);
0034 
0035 
0036 static ngx_command_t  ngx_http_upstream_ip_hash_commands[] = {
0037 
0038     { ngx_string("ip_hash"),
0039       NGX_HTTP_UPS_CONF|NGX_CONF_NOARGS,
0040       ngx_http_upstream_ip_hash,
0041       0,
0042       0,
0043       NULL },
0044 
0045       ngx_null_command
0046 };
0047 
0048 
0049 static ngx_http_module_t  ngx_http_upstream_ip_hash_module_ctx = {
0050     NULL,                                  /* preconfiguration */
0051     NULL,                                  /* postconfiguration */
0052 
0053     NULL,                                  /* create main configuration */
0054     NULL,                                  /* init main configuration */
0055 
0056     NULL,                                  /* create server configuration */
0057     NULL,                                  /* merge server configuration */
0058 
0059     NULL,                                  /* create location configuration */
0060     NULL                                   /* merge location configuration */
0061 };
0062 
0063 
0064 ngx_module_t  ngx_http_upstream_ip_hash_module = {
0065     NGX_MODULE_V1,
0066     &ngx_http_upstream_ip_hash_module_ctx, /* module context */
0067     ngx_http_upstream_ip_hash_commands,    /* module directives */
0068     NGX_HTTP_MODULE,                       /* module type */
0069     NULL,                                  /* init master */
0070     NULL,                                  /* init module */
0071     NULL,                                  /* init process */
0072     NULL,                                  /* init thread */
0073     NULL,                                  /* exit thread */
0074     NULL,                                  /* exit process */
0075     NULL,                                  /* exit master */
0076     NGX_MODULE_V1_PADDING
0077 };
0078 
0079 
0080 static u_char ngx_http_upstream_ip_hash_pseudo_addr[3];
0081 
0082 
0083 static ngx_int_t
0084 ngx_http_upstream_init_ip_hash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
0085 {
0086     if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) {
0087         return NGX_ERROR;
0088     }
0089 
0090     us->peer.init = ngx_http_upstream_init_ip_hash_peer;
0091 
0092     return NGX_OK;
0093 }
0094 
0095 
0096 static ngx_int_t
0097 ngx_http_upstream_init_ip_hash_peer(ngx_http_request_t *r,
0098     ngx_http_upstream_srv_conf_t *us)
0099 {
0100     struct sockaddr_in                     *sin;
0101 #if (NGX_HAVE_INET6)
0102     struct sockaddr_in6                    *sin6;
0103 #endif
0104     ngx_http_upstream_ip_hash_peer_data_t  *iphp;
0105 
0106     iphp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_ip_hash_peer_data_t));
0107     if (iphp == NULL) {
0108         return NGX_ERROR;
0109     }
0110 
0111     r->upstream->peer.data = &iphp->rrp;
0112 
0113     if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) {
0114         return NGX_ERROR;
0115     }
0116 
0117     r->upstream->peer.get = ngx_http_upstream_get_ip_hash_peer;
0118 
0119     switch (r->connection->sockaddr->sa_family) {
0120 
0121     case AF_INET:
0122         sin = (struct sockaddr_in *) r->connection->sockaddr;
0123         iphp->addr = (u_char *) &sin->sin_addr.s_addr;
0124         iphp->addrlen = 3;
0125         break;
0126 
0127 #if (NGX_HAVE_INET6)
0128     case AF_INET6:
0129         sin6 = (struct sockaddr_in6 *) r->connection->sockaddr;
0130         iphp->addr = (u_char *) &sin6->sin6_addr.s6_addr;
0131         iphp->addrlen = 16;
0132         break;
0133 #endif
0134 
0135     default:
0136         iphp->addr = ngx_http_upstream_ip_hash_pseudo_addr;
0137         iphp->addrlen = 3;
0138     }
0139 
0140     iphp->hash = 89;
0141     iphp->tries = 0;
0142     iphp->get_rr_peer = ngx_http_upstream_get_round_robin_peer;
0143 
0144     return NGX_OK;
0145 }
0146 
0147 
0148 static ngx_int_t
0149 ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
0150 {
0151     ngx_http_upstream_ip_hash_peer_data_t  *iphp = data;
0152 
0153     time_t                        now;
0154     ngx_int_t                     w;
0155     uintptr_t                     m;
0156     ngx_uint_t                    i, n, p, hash;
0157     ngx_http_upstream_rr_peer_t  *peer;
0158 
0159     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0160                    "get ip hash peer, try: %ui", pc->tries);
0161 
0162     /* TODO: cached */
0163 
0164     ngx_http_upstream_rr_peers_wlock(iphp->rrp.peers);
0165 
0166     if (iphp->tries > 20 || iphp->rrp.peers->single) {
0167         ngx_http_upstream_rr_peers_unlock(iphp->rrp.peers);
0168         return iphp->get_rr_peer(pc, &iphp->rrp);
0169     }
0170 
0171     now = ngx_time();
0172 
0173     pc->cached = 0;
0174     pc->connection = NULL;
0175 
0176     hash = iphp->hash;
0177 
0178     for ( ;; ) {
0179 
0180         for (i = 0; i < (ngx_uint_t) iphp->addrlen; i++) {
0181             hash = (hash * 113 + iphp->addr[i]) % 6271;
0182         }
0183 
0184         w = hash % iphp->rrp.peers->total_weight;
0185         peer = iphp->rrp.peers->peer;
0186         p = 0;
0187 
0188         while (w >= peer->weight) {
0189             w -= peer->weight;
0190             peer = peer->next;
0191             p++;
0192         }
0193 
0194         n = p / (8 * sizeof(uintptr_t));
0195         m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
0196 
0197         if (iphp->rrp.tried[n] & m) {
0198             goto next;
0199         }
0200 
0201         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0202                        "get ip hash peer, hash: %ui %04XL", p, (uint64_t) m);
0203 
0204         if (peer->down) {
0205             goto next;
0206         }
0207 
0208         if (peer->max_fails
0209             && peer->fails >= peer->max_fails
0210             && now - peer->checked <= peer->fail_timeout)
0211         {
0212             goto next;
0213         }
0214 
0215         if (peer->max_conns && peer->conns >= peer->max_conns) {
0216             goto next;
0217         }
0218 
0219         break;
0220 
0221     next:
0222 
0223         if (++iphp->tries > 20) {
0224             ngx_http_upstream_rr_peers_unlock(iphp->rrp.peers);
0225             return iphp->get_rr_peer(pc, &iphp->rrp);
0226         }
0227     }
0228 
0229     iphp->rrp.current = peer;
0230 
0231     pc->sockaddr = peer->sockaddr;
0232     pc->socklen = peer->socklen;
0233     pc->name = &peer->name;
0234 
0235     peer->conns++;
0236 
0237     if (now - peer->checked > peer->fail_timeout) {
0238         peer->checked = now;
0239     }
0240 
0241     ngx_http_upstream_rr_peers_unlock(iphp->rrp.peers);
0242 
0243     iphp->rrp.tried[n] |= m;
0244     iphp->hash = hash;
0245 
0246     return NGX_OK;
0247 }
0248 
0249 
0250 static char *
0251 ngx_http_upstream_ip_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0252 {
0253     ngx_http_upstream_srv_conf_t  *uscf;
0254 
0255     uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
0256 
0257     if (uscf->peer.init_upstream) {
0258         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
0259                            "load balancing method redefined");
0260     }
0261 
0262     uscf->peer.init_upstream = ngx_http_upstream_init_ip_hash;
0263 
0264     uscf->flags = NGX_HTTP_UPSTREAM_CREATE
0265                   |NGX_HTTP_UPSTREAM_WEIGHT
0266                   |NGX_HTTP_UPSTREAM_MAX_CONNS
0267                   |NGX_HTTP_UPSTREAM_MAX_FAILS
0268                   |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
0269                   |NGX_HTTP_UPSTREAM_DOWN;
0270 
0271     return NGX_CONF_OK;
0272 }