Esempio n. 1
0
int assign_server(struct session *s)
{
	struct connection *conn;
	struct server *conn_slot;
	struct server *srv, *prev_srv;
	int err;

	DPRINTF(stderr,"assign_server : s=%p\n",s);

	err = SRV_STATUS_INTERNAL;
	if (unlikely(s->pend_pos || s->flags & SN_ASSIGNED))
		goto out_err;

	prev_srv  = objt_server(s->target);
	conn_slot = s->srv_conn;

	/* We have to release any connection slot before applying any LB algo,
	 * otherwise we may erroneously end up with no available slot.
	 */
	if (conn_slot)
		sess_change_server(s, NULL);

	/* We will now try to find the good server and store it into <objt_server(s->target)>.
	 * Note that <objt_server(s->target)> may be NULL in case of dispatch or proxy mode,
	 * as well as if no server is available (check error code).
	 */

	srv = NULL;
	s->target = NULL;
	conn = objt_conn(s->si[1].end);

	if (conn &&
	    (conn->flags & CO_FL_CONNECTED) &&
	    objt_server(conn->target) && __objt_server(conn->target)->proxy == s->be &&
	    ((s->txn.flags & TX_PREFER_LAST) ||
	     ((s->be->options & PR_O_PREF_LAST) &&
	      (!s->be->max_ka_queue ||
	       server_has_room(__objt_server(conn->target)) ||
	       (__objt_server(conn->target)->nbpend + 1) < s->be->max_ka_queue))) &&
	    srv_is_usable(__objt_server(conn->target))) {
		/* This session was relying on a server in a previous request
		 * and the proxy has "option prefer-last-server" set, so
		 * let's try to reuse the same server.
		 */
		srv = __objt_server(conn->target);
		s->target = &srv->obj_type;
	}
	else if (s->be->lbprm.algo & BE_LB_KIND) {
		/* we must check if we have at least one server available */
		if (!s->be->lbprm.tot_weight) {
			err = SRV_STATUS_NOSRV;
			goto out;
		}

		/* First check whether we need to fetch some data or simply call
		 * the LB lookup function. Only the hashing functions will need
		 * some input data in fact, and will support multiple algorithms.
		 */
		switch (s->be->lbprm.algo & BE_LB_LKUP) {
		case BE_LB_LKUP_RRTREE:
			srv = fwrr_get_next_server(s->be, prev_srv);
			break;

		case BE_LB_LKUP_FSTREE:
			srv = fas_get_next_server(s->be, prev_srv);
			break;

		case BE_LB_LKUP_LCTREE:
			srv = fwlc_get_next_server(s->be, prev_srv);
			break;

		case BE_LB_LKUP_CHTREE:
		case BE_LB_LKUP_MAP:
			if ((s->be->lbprm.algo & BE_LB_KIND) == BE_LB_KIND_RR) {
				if (s->be->lbprm.algo & BE_LB_LKUP_CHTREE)
					srv = chash_get_next_server(s->be, prev_srv);
				else
					srv = map_get_server_rr(s->be, prev_srv);
				break;
			}
			else if ((s->be->lbprm.algo & BE_LB_KIND) != BE_LB_KIND_HI) {
				/* unknown balancing algorithm */
				err = SRV_STATUS_INTERNAL;
				goto out;
			}

			switch (s->be->lbprm.algo & BE_LB_PARM) {
			case BE_LB_HASH_SRC:
				conn = objt_conn(s->si[0].end);
				if (conn && conn->addr.from.ss_family == AF_INET) {
					srv = get_server_sh(s->be,
							    (void *)&((struct sockaddr_in *)&conn->addr.from)->sin_addr,
							    4);
				}
				else if (conn && conn->addr.from.ss_family == AF_INET6) {
					srv = get_server_sh(s->be,
							    (void *)&((struct sockaddr_in6 *)&conn->addr.from)->sin6_addr,
							    16);
				}
				else {
					/* unknown IP family */
					err = SRV_STATUS_INTERNAL;
					goto out;
				}
				break;

			case BE_LB_HASH_URI:
				/* URI hashing */
				if (s->txn.req.msg_state < HTTP_MSG_BODY)
					break;
				srv = get_server_uh(s->be,
						    b_ptr(s->req.buf, -http_uri_rewind(&s->txn.req)),
						    s->txn.req.sl.rq.u_l);
				break;

			case BE_LB_HASH_PRM:
				/* URL Parameter hashing */
				if (s->txn.req.msg_state < HTTP_MSG_BODY)
					break;

				srv = get_server_ph(s->be,
						    b_ptr(s->req.buf, -http_uri_rewind(&s->txn.req)),
						    s->txn.req.sl.rq.u_l);

				if (!srv && s->txn.meth == HTTP_METH_POST)
					srv = get_server_ph_post(s);
				break;

			case BE_LB_HASH_HDR:
				/* Header Parameter hashing */
				if (s->txn.req.msg_state < HTTP_MSG_BODY)
					break;
				srv = get_server_hh(s);
				break;

			case BE_LB_HASH_RDP:
				/* RDP Cookie hashing */
				srv = get_server_rch(s);
				break;

			default:
				/* unknown balancing algorithm */
				err = SRV_STATUS_INTERNAL;
				goto out;
			}

			/* If the hashing parameter was not found, let's fall
			 * back to round robin on the map.
			 */
			if (!srv) {
				if (s->be->lbprm.algo & BE_LB_LKUP_CHTREE)
					srv = chash_get_next_server(s->be, prev_srv);
				else
					srv = map_get_server_rr(s->be, prev_srv);
			}

			/* end of map-based LB */
			break;

		default:
			/* unknown balancing algorithm */
			err = SRV_STATUS_INTERNAL;
			goto out;
		}

		if (!srv) {
			err = SRV_STATUS_FULL;
			goto out;
		}
		else if (srv != prev_srv) {
			s->be->be_counters.cum_lbconn++;
			srv->counters.cum_lbconn++;
		}
		s->target = &srv->obj_type;
	}
	else if (s->be->options & (PR_O_DISPATCH | PR_O_TRANSP)) {
		s->target = &s->be->obj_type;
	}
	else if ((s->be->options & PR_O_HTTP_PROXY) &&
		 (conn = objt_conn(s->si[1].end)) &&
		 is_addr(&conn->addr.to)) {
		/* in proxy mode, we need a valid destination address */
		s->target = &s->be->obj_type;
	}
	else {
		err = SRV_STATUS_NOSRV;
		goto out;
	}

	s->flags |= SN_ASSIGNED;
	err = SRV_STATUS_OK;
 out:

	/* Either we take back our connection slot, or we offer it to someone
	 * else if we don't need it anymore.
	 */
	if (conn_slot) {
		if (conn_slot == srv) {
			sess_change_server(s, srv);
		} else {
			if (may_dequeue_tasks(conn_slot, s->be))
				process_srv_queue(conn_slot);
		}
	}

 out_err:
	return err;
}
Esempio n. 2
0
int assign_server(struct session *s)
{

	struct server *conn_slot;
	int err;

#ifdef DEBUG_FULL
	fprintf(stderr,"assign_server : s=%p\n",s);
#endif

	err = SRV_STATUS_INTERNAL;
	if (unlikely(s->pend_pos || s->flags & SN_ASSIGNED))
		goto out_err;

	s->prev_srv = s->prev_srv;
	conn_slot = s->srv_conn;

	/* We have to release any connection slot before applying any LB algo,
	 * otherwise we may erroneously end up with no available slot.
	 */
	if (conn_slot)
		sess_change_server(s, NULL);

	/* We will now try to find the good server and store it into <s->srv>.
	 * Note that <s->srv> may be NULL in case of dispatch or proxy mode,
	 * as well as if no server is available (check error code).
	 */

	s->srv = NULL;
	if (s->be->lbprm.algo & BE_LB_KIND) {
		/* we must check if we have at least one server available */
		if (!s->be->lbprm.tot_weight) {
			err = SRV_STATUS_NOSRV;
			goto out;
		}

		/* First check whether we need to fetch some data or simply call
		 * the LB lookup function. Only the hashing functions will need
		 * some input data in fact, and will support multiple algorithms.
		 */
		switch (s->be->lbprm.algo & BE_LB_LKUP) {
		case BE_LB_LKUP_RRTREE:
			s->srv = fwrr_get_next_server(s->be, s->prev_srv);
			break;

		case BE_LB_LKUP_LCTREE:
			s->srv = fwlc_get_next_server(s->be, s->prev_srv);
			break;

		case BE_LB_LKUP_CHTREE:
		case BE_LB_LKUP_MAP:
			if ((s->be->lbprm.algo & BE_LB_KIND) == BE_LB_KIND_RR) {
				if (s->be->lbprm.algo & BE_LB_LKUP_CHTREE)
					s->srv = chash_get_next_server(s->be, s->prev_srv);
				else
					s->srv = map_get_server_rr(s->be, s->prev_srv);
				break;
			}
			else if ((s->be->lbprm.algo & BE_LB_KIND) != BE_LB_KIND_HI) {
				/* unknown balancing algorithm */
				err = SRV_STATUS_INTERNAL;
				goto out;
			}

			switch (s->be->lbprm.algo & BE_LB_PARM) {
			case BE_LB_HASH_SRC:
				if (s->cli_addr.ss_family == AF_INET)
					s->srv = get_server_sh(s->be,
					                       (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
					                       4);
				else if (s->cli_addr.ss_family == AF_INET6)
					s->srv = get_server_sh(s->be,
					                       (void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
					                       16);
				else {
					/* unknown IP family */
					err = SRV_STATUS_INTERNAL;
					goto out;
				}
				break;

			case BE_LB_HASH_URI:
				/* URI hashing */
				if (s->txn.req.msg_state < HTTP_MSG_BODY)
					break;
				s->srv = get_server_uh(s->be,
						       s->txn.req.sol + s->txn.req.sl.rq.u,
						       s->txn.req.sl.rq.u_l);
				break;

			case BE_LB_HASH_PRM:
				/* URL Parameter hashing */
				if (s->txn.req.msg_state < HTTP_MSG_BODY)
					break;

				s->srv = get_server_ph(s->be,
						       s->txn.req.sol + s->txn.req.sl.rq.u,
						       s->txn.req.sl.rq.u_l);

				if (!s->srv && s->txn.meth == HTTP_METH_POST)
					s->srv = get_server_ph_post(s);
				break;

			case BE_LB_HASH_HDR:
				/* Header Parameter hashing */
				if (s->txn.req.msg_state < HTTP_MSG_BODY)
					break;
				s->srv = get_server_hh(s);
				break;

			case BE_LB_HASH_RDP:
				/* RDP Cookie hashing */
				s->srv = get_server_rch(s);
				break;

			default:
				/* unknown balancing algorithm */
				err = SRV_STATUS_INTERNAL;
				goto out;
			}

			/* If the hashing parameter was not found, let's fall
			 * back to round robin on the map.
			 */
			if (!s->srv) {
				if (s->be->lbprm.algo & BE_LB_LKUP_CHTREE)
					s->srv = chash_get_next_server(s->be, s->prev_srv);
				else
					s->srv = map_get_server_rr(s->be, s->prev_srv);
			}

			/* end of map-based LB */
			break;

		default:
			/* unknown balancing algorithm */
			err = SRV_STATUS_INTERNAL;
			goto out;
		}

		if (!s->srv) {
			err = SRV_STATUS_FULL;
			goto out;
		}
		else if (s->srv != s->prev_srv) {
			s->be->counters.cum_lbconn++;
			s->srv->counters.cum_lbconn++;
		}
	}
	else if (s->be->options & PR_O_HTTP_PROXY) {
		if (!s->srv_addr.sin_addr.s_addr) {
			err = SRV_STATUS_NOSRV;
			goto out;
		}
	}
	else if (!*(int *)&s->be->dispatch_addr.sin_addr &&
		 !(s->be->options & PR_O_TRANSP)) {
		err = SRV_STATUS_NOSRV;
		goto out;
	}

	s->flags |= SN_ASSIGNED;
	err = SRV_STATUS_OK;
 out:

	/* Either we take back our connection slot, or we offer it to someone
	 * else if we don't need it anymore.
	 */
	if (conn_slot) {
		if (conn_slot == s->srv) {
			sess_change_server(s, s->srv);
		} else {
			if (may_dequeue_tasks(conn_slot, s->be))
				process_srv_queue(conn_slot);
		}
	}

 out_err:
	return err;
}