int rl_get_counter_value(str *key) { unsigned int hash_idx; rl_pipe_t **pipe; int ret = -1; hash_idx = RL_GET_INDEX(*key); RL_GET_LOCK(hash_idx); /* try to get the value */ pipe = RL_FIND_PIPE(hash_idx, *key); if (!pipe || !*pipe) { LM_DBG("cannot find any pipe named %.*s\n", key->len, key->s); goto release; } if (RL_USE_CDB(*pipe)) { if (rl_get_counter(key, *pipe) < 0) { LM_ERR("cannot get the counter's value\n"); goto release; } } ret = rl_get_all_counters(*pipe); release: RL_RELEASE_LOCK(hash_idx); return ret; }
/* NOTE: assumes that the pipe has been locked. If fails, releases the lock */ static int rl_get_counter(str *name, rl_pipe_t * pipe) { str res; unsigned int hid = RL_GET_INDEX(*name); int new_counter; RL_SET_PENDING(pipe); RL_RELEASE_LOCK(hid); if (rl_set_name(name) < 0) return -1; if (cdbf.get(cdbc, &rl_name_buffer, &res) < 0) { LM_ERR("cannot retrieve key\n"); return -1; } if (str2sint(&res, &new_counter) < 0) { LM_ERR("invalid value %.*s - should be integer\n", res.len, res.s); return -1; } if (res.s) pkg_free(res.s); RL_GET_LOCK(hid); RL_RESET_PENDING(pipe); pipe->counter = new_counter; return 0; }
int rl_stats(struct mi_node *rpl, str * value) { rl_pipe_t **pipe; int i; if (value && value->s && value->len) { i = RL_GET_INDEX(*value); RL_GET_LOCK(i); pipe = RL_FIND_PIPE(i, *value); if (!pipe || !*pipe) { LM_DBG("pipe %.*s not found\n", value->len, value->s); goto error; } if (rl_map_print(rpl, *value, *pipe)) { LM_ERR("cannot print value for key %.*s\n", value->len, value->s); goto error; } RL_RELEASE_LOCK(i); } else { /* iterate through each map */ for (i = 0; i < rl_htable.size; i++) { RL_GET_LOCK(i); if (map_for_each(rl_htable.maps[i], rl_map_print, rpl)) { LM_ERR("cannot print values\n"); goto error; } RL_RELEASE_LOCK(i); } } return 0; error: RL_RELEASE_LOCK(i); return -1; }
int rl_stats(mi_item_t *resp_obj, str * value) { mi_item_t *pipe_item, *pipe_arr; rl_pipe_t **pipe; int i; if (value && value->s && value->len) { i = RL_GET_INDEX(*value); RL_GET_LOCK(i); pipe = RL_FIND_PIPE(i, *value); if (!pipe || !*pipe) { LM_DBG("pipe %.*s not found\n", value->len, value->s); goto error; } pipe_item = add_mi_object(resp_obj, MI_SSTR("Pipe")); if (!pipe_item) goto error; if (rl_map_print(pipe_item, *value, *pipe)) { LM_ERR("cannot print value for key %.*s\n", value->len, value->s); goto error; } RL_RELEASE_LOCK(i); } else { /* iterate through each map */ pipe_arr = add_mi_array(resp_obj, MI_SSTR("Pipes")); if (!pipe_arr) return -1; for (i = 0; i < rl_htable.size; i++) { pipe_item = add_mi_object(pipe_arr, NULL, 0); if (!pipe_item) return -1; RL_GET_LOCK(i); if (map_for_each(rl_htable.maps[i], rl_map_print, pipe_item)) { LM_ERR("cannot print values\n"); goto error; } RL_RELEASE_LOCK(i); } } return 0; error: RL_RELEASE_LOCK(i); return -1; }
/* NOTE: assumes that the pipe has been locked. If fails, releases the lock */ static int rl_change_counter(str *name, rl_pipe_t *pipe, int c) { unsigned int hid = RL_GET_INDEX(*name); int new_counter; RL_SET_PENDING(pipe); RL_RELEASE_LOCK(hid); if (rl_set_name(name) < 0) return -1; /* if the command should be reset */ /* XXX: This is not needed since add takes also negative numbers if (c > 0) { if (cdbf.add(cdbc, &rl_name_buffer, c, rl_expire_time, &new_counter)<0){ LM_ERR("cannot increase buffer for pipe %.*s\n", name->len, name->s); return -1; } } else { if (cdbf.sub(cdbc, &rl_name_buffer, c ? c : pipe->my_counter, rl_expire_time, &new_counter) < 0){ LM_ERR("cannot change counter for pipe %.*s with %d\n", name->len, name->s, c); return -1; } } */ if (cdbf.add(cdbc, &rl_name_buffer, c ? c : -(pipe->my_counter), rl_expire_time, &new_counter) < 0){ LM_ERR("cannot change counter for pipe %.*s with %d\n", name->len, name->s, c); return -1; } RL_GET_LOCK(hid); RL_RESET_PENDING(pipe); pipe->my_counter = c ? pipe->my_counter + c : 0; pipe->counter = new_counter; LM_DBG("changed with %d; my_counter: %d; counter: %d\n", c, pipe->my_counter, new_counter); return 0; }
int rl_stats(struct mi_root *rpl_tree, str * value) { rl_pipe_t **pipe; struct rl_param_t param; int i; memset(¶m, 0, sizeof(struct rl_param_t)); param.node = &rpl_tree->node; param.root = rpl_tree; if (value && value->s && value->len) { i = RL_GET_INDEX(*value); RL_GET_LOCK(i); pipe = RL_FIND_PIPE(i, *value); if (!pipe || !*pipe) { LM_DBG("pipe %.*s not found\n", value->len, value->s); goto error; } if (rl_map_print(¶m, *value, *pipe)) { LM_ERR("cannot print value for key %.*s\n", value->len, value->s); goto error; } RL_RELEASE_LOCK(i); } else { /* iterate through each map */ for (i = 0; i < rl_htable.size; i++) { RL_GET_LOCK(i); if (map_for_each(rl_htable.maps[i], rl_map_print, ¶m)) { LM_ERR("cannot print values\n"); goto error; } RL_RELEASE_LOCK(i); } } return 0; error: RL_RELEASE_LOCK(i); return -1; }
int w_rl_set_count(str key, int val) { unsigned int hash_idx; int ret = -1; rl_pipe_t **pipe; hash_idx = RL_GET_INDEX(key); RL_GET_LOCK(hash_idx); /* try to get the value */ pipe = RL_FIND_PIPE(hash_idx, key); if (!pipe || !*pipe) { LM_DBG("cannot find any pipe named %.*s\n", key.len, key.s); goto release; } if (RL_USE_CDB(*pipe)) { if (rl_change_counter(&key, *pipe, val) < 0) { LM_ERR("cannot decrease counter\n"); goto release; } } else if ((*pipe)->algo == PIPE_ALGO_HISTORY) { hist_set_count(*pipe, val); } else { if (val && (val + (*pipe)->counter >= 0)) { (*pipe)->counter += val; } else { (*pipe)->counter = 0; } } LM_DBG("new counter for key %.*s is %d\n", key.len, key.s, (*pipe)->counter); ret = 0; release: RL_RELEASE_LOCK(hash_idx); return ret; }
void rl_rcv_bin(int packet_type, struct receive_info *ri) { rl_algo_t algo; int limit; int counter; str name; int index; char *ip; unsigned short port; rl_pipe_t **pipe; unsigned int hash_idx; time_t now; if (packet_type != RL_PIPE_COUNTER) return; /* match the server */ for (index = 0; index < rl_dests_nr; index++) { if (su_cmp(&ri->src_su, &rl_dests[index].to)) break; } if (index == rl_dests_nr) { get_su_info(&ri->src_su.s, ip, port); LM_WARN("received bin packet from unknown source: %s:%hu\n", ip, port); return; } now = time(0); *rl_dests[index].last_msg = now; for (;;) { if (bin_pop_str(&name) == 1) break; /* pop'ed all pipes */ if (bin_pop_int(&algo) < 0) { LM_ERR("cannot pop pipe's algorithm\n"); return; } if (bin_pop_int(&limit) < 0) { LM_ERR("cannot pop pipe's limit\n"); return; } if (bin_pop_int(&counter) < 0) { LM_ERR("cannot pop pipe's counter\n"); return; } hash_idx = RL_GET_INDEX(name); RL_GET_LOCK(hash_idx); /* try to get the value */ pipe = RL_GET_PIPE(hash_idx, name); if (!pipe) { LM_ERR("cannot get the index\n"); goto release; } if (!*pipe) { /* if the pipe does not exist, alocate it in case we need it later */ *pipe = shm_malloc(sizeof(rl_pipe_t) + rl_dests_nr * sizeof(rl_repl_counter_t)); if (!*pipe) { LM_ERR("no more shm memory\n"); goto release; } memset(*pipe, 0, sizeof(rl_pipe_t) + rl_dests_nr * sizeof(rl_repl_counter_t)); (*pipe)->dsts = (rl_repl_counter_t *)((*pipe) + 1); LM_DBG("Pipe %.*s doesn't exist, but was created %p\n", name.len, name.s, *pipe); (*pipe)->algo = algo; (*pipe)->limit = limit; } else { LM_DBG("Pipe %.*s found: %p - last used %lu\n", name.len, name.s, *pipe, (*pipe)->last_used); if ((*pipe)->algo != algo) LM_WARN("algorithm %d different from the initial one %d for " "pipe %.*s", algo, (*pipe)->algo, name.len, name.s); if ((*pipe)->limit != limit) LM_WARN("limit %d different from the initial one %d for " "pipe %.*s", limit, (*pipe)->limit, name.len, name.s); } /* set the last used time */ (*pipe)->last_used = time(0); /* set the destination's counter */ (*pipe)->dsts[index].counter = counter; (*pipe)->dsts[index].update = now; RL_RELEASE_LOCK(hash_idx); } return; release: RL_RELEASE_LOCK(hash_idx); }
int w_rl_check_3(struct sip_msg *_m, char *_n, char *_l, char *_a) { str name; int limit = 0, ret = 1, should_update = 0; str algorithm; unsigned int hash_idx; rl_pipe_t **pipe; rl_algo_t algo = -1; /* retrieve and check parameters */ if (!_n || !_l) { LM_ERR("invalid parameters\n"); goto end; } if (fixup_get_svalue(_m, (gparam_p)_n, &name) < 0) { LM_ERR("cannot retrieve identifier\n"); goto end; } if (fixup_get_ivalue(_m, (gparam_p)_l, &limit) < 0) { LM_ERR("cannot retrieve limit\n"); goto end; } algorithm.s = 0; if (!_a || fixup_get_svalue(_m, (gparam_p)_a, &algorithm) < 0 || (algo = get_rl_algo(algorithm)) < 0) { algo = PIPE_ALGO_NOP; } /* get limit for FEEDBACK algorithm */ if (algo == PIPE_ALGO_FEEDBACK) { lock_get(rl_lock); if (*rl_feedback_limit) { if (*rl_feedback_limit != limit) { LM_WARN("FEEDBACK limit should be the same for all pipes, but" " new limit %d differs - setting to %d\n", limit, *rl_feedback_limit); limit = *rl_feedback_limit; } } else { if (limit <= 0 || limit >= 100) { LM_ERR("invalid limit for FEEDBACK algorithm " "(must be between 0 and 100)\n"); lock_release(rl_lock); goto end; } *rl_feedback_limit = limit; pid_setpoint_limit(limit); } lock_release(rl_lock); } hash_idx = RL_GET_INDEX(name); RL_GET_LOCK(hash_idx); /* try to get the value */ pipe = RL_GET_PIPE(hash_idx, name); if (!pipe) { LM_ERR("cannot get the index\n"); goto release; } if (!*pipe) { /* allocate new pipe */ *pipe = shm_malloc(sizeof(rl_pipe_t) + rl_dests_nr * sizeof(rl_repl_counter_t)); if (!*pipe) { LM_ERR("no more shm memory\n"); goto release; } memset(*pipe, 0, sizeof(rl_pipe_t) + rl_dests_nr * sizeof(rl_repl_counter_t)); (*pipe)->dsts = (rl_repl_counter_t *)((*pipe) + 1); LM_DBG("Pipe %.*s doens't exist, but was created %p\n", name.len, name.s, *pipe); if (algo == PIPE_ALGO_NETWORK) should_update = 1; (*pipe)->algo = (algo == PIPE_ALGO_NOP) ? rl_default_algo : algo; } else { LM_DBG("Pipe %.*s found: %p - last used %lu\n", name.len, name.s, *pipe, (*pipe)->last_used); if (algo != PIPE_ALGO_NOP && (*pipe)->algo != algo) { LM_WARN("algorithm %d different from the initial one %d for pipe " "%.*s", algo, (*pipe)->algo, name.len, name.s); } } /* set/update the limit */ (*pipe)->limit = limit; /* set the last used time */ (*pipe)->last_used = time(0); if (RL_USE_CDB(*pipe)) { /* release the counter for a while */ if (rl_change_counter(&name, *pipe, 1) < 0) { LM_ERR("cannot increase counter\n"); goto end; } } else { (*pipe)->counter++; } ret = rl_pipe_check(*pipe); LM_DBG("Pipe %.*s counter:%d load:%d limit:%d should %sbe blocked (%p)\n", name.len, name.s, (*pipe)->counter, (*pipe)->load, (*pipe)->limit, ret == 1? "NOT " : "", *pipe); release: RL_RELEASE_LOCK(hash_idx); if (should_update) { lock_get(rl_lock); (*rl_network_count)++; lock_release(rl_lock); } end: return ret; }
void rl_rcv_bin(bin_packet_t *packet) { rl_algo_t algo; int limit; int counter; str name; rl_pipe_t **pipe; unsigned int hash_idx; time_t now; rl_repl_counter_t *destination; if (packet->type != RL_PIPE_COUNTER) { LM_WARN("Invalid binary packet command: %d (from node: %d in cluster: %d)\n", packet->type, packet->src_id, rl_repl_cluster); return; } now = time(0); for (;;) { if (bin_pop_str(packet, &name) == 1) break; /* pop'ed all pipes */ if (bin_pop_int(packet, &algo) < 0) { LM_ERR("cannot pop pipe's algorithm\n"); return; } if (bin_pop_int(packet, &limit) < 0) { LM_ERR("cannot pop pipe's limit\n"); return; } if (bin_pop_int(packet, &counter) < 0) { LM_ERR("cannot pop pipe's counter\n"); return; } hash_idx = RL_GET_INDEX(name); RL_GET_LOCK(hash_idx); /* try to get the value */ pipe = RL_GET_PIPE(hash_idx, name); if (!pipe) { LM_ERR("cannot get the index\n"); goto release; } if (!*pipe) { /* if the pipe does not exist, allocate it in case we need it later */ if (!(*pipe = rl_create_pipe(limit, algo))) goto release; LM_DBG("Pipe %.*s doesn't exist, but was created %p\n", name.len, name.s, *pipe); } else { LM_DBG("Pipe %.*s found: %p - last used %lu\n", name.len, name.s, *pipe, (*pipe)->last_used); if ((*pipe)->algo != algo) LM_WARN("algorithm %d different from the initial one %d for " "pipe %.*s", algo, (*pipe)->algo, name.len, name.s); /* * XXX: do not output these warnings since they can be triggered * when a custom limit is used if ((*pipe)->limit != limit) LM_WARN("limit %d different from the initial one %d for " "pipe %.*s", limit, (*pipe)->limit, name.len, name.s); */ } /* set the last used time */ (*pipe)->last_used = time(0); /* set the destination's counter */ destination = find_destination(*pipe, packet->src_id); if (!destination) goto release; destination->counter = counter; destination->update = now; RL_RELEASE_LOCK(hash_idx); } return; release: RL_RELEASE_LOCK(hash_idx); }
int w_rl_check(struct sip_msg *_m, str *name, int *limit, str *algorithm) { int ret = 1, should_update = 0; unsigned int hash_idx; rl_pipe_t **pipe; rl_algo_t algo = -1; if (!algorithm || (algo = get_rl_algo(*algorithm)) == PIPE_ALGO_NOP) { algo = PIPE_ALGO_NOP; } /* get limit for FEEDBACK algorithm */ if (algo == PIPE_ALGO_FEEDBACK) { lock_get(rl_lock); if (*rl_feedback_limit) { if (*rl_feedback_limit != *limit) { LM_WARN("FEEDBACK limit should be the same for all pipes, but" " new limit %d differs - setting to %d\n", *limit, *rl_feedback_limit); *limit = *rl_feedback_limit; } } else { if (*limit <= 0 || *limit >= 100) { LM_ERR("invalid limit for FEEDBACK algorithm " "(must be between 0 and 100)\n"); lock_release(rl_lock); goto end; } *rl_feedback_limit = *limit; pid_setpoint_limit(*limit); } lock_release(rl_lock); } hash_idx = RL_GET_INDEX(*name); RL_GET_LOCK(hash_idx); /* try to get the value */ pipe = RL_GET_PIPE(hash_idx, *name); if (!pipe) { LM_ERR("cannot get the index\n"); goto release; } if (!*pipe) { /* allocate new pipe */ if (!(*pipe = rl_create_pipe(*limit, algo))) goto release; LM_DBG("Pipe %.*s doesn't exist, but was created %p\n", name->len, name->s, *pipe); if ((*pipe)->algo == PIPE_ALGO_NETWORK) should_update = 1; } else { LM_DBG("Pipe %.*s found: %p - last used %lu\n", name->len, name->s, *pipe, (*pipe)->last_used); if (algo != PIPE_ALGO_NOP && (*pipe)->algo != algo) { LM_WARN("algorithm %d different from the initial one %d for pipe " "%.*s", algo, (*pipe)->algo, name->len, name->s); } /* update the limit */ (*pipe)->limit = *limit; } /* set the last used time */ (*pipe)->last_used = time(0); if (RL_USE_CDB(*pipe)) { /* release the counter for a while */ if (rl_change_counter(name, *pipe, 1) < 0) { LM_ERR("cannot increase counter\n"); goto release; } } else { (*pipe)->counter++; } ret = rl_pipe_check(*pipe); LM_DBG("Pipe %.*s counter:%d load:%d limit:%d should %sbe blocked (%p)\n", name->len, name->s, (*pipe)->counter, (*pipe)->load, (*pipe)->limit, ret == 1 ? "NOT " : "", *pipe); release: RL_RELEASE_LOCK(hash_idx); if (should_update) { lock_get(rl_lock); (*rl_network_count)++; lock_release(rl_lock); } end: return ret; }
void rl_rcv_bin(int packet_type, struct receive_info *ri, int server_id) { rl_algo_t algo; int limit; int counter; str name; char *ip; unsigned short port; rl_pipe_t **pipe; unsigned int hash_idx; time_t now; rl_repl_counter_t *destination; if (packet_type == SERVER_TEMP_DISABLED) { get_su_info(&ri->src_su.s, ip, port); LM_WARN("server: %s:%hu temporary disabled\n", ip, port); return; } if (packet_type == SERVER_TIMEOUT) { LM_WARN("server with clustererer id %d timeout\n", server_id); return; } if(get_bin_pkg_version() != BIN_VERSION){ LM_ERR("incompatible bin protocol version\n"); return; } if (packet_type != RL_PIPE_COUNTER) return; if (packet_type != RL_PIPE_COUNTER) return; now = time(0); for (;;) { if (bin_pop_str(&name) == 1) break; /* pop'ed all pipes */ if (bin_pop_int(&algo) < 0) { LM_ERR("cannot pop pipe's algorithm\n"); return; } if (bin_pop_int(&limit) < 0) { LM_ERR("cannot pop pipe's limit\n"); return; } if (bin_pop_int(&counter) < 0) { LM_ERR("cannot pop pipe's counter\n"); return; } hash_idx = RL_GET_INDEX(name); RL_GET_LOCK(hash_idx); /* try to get the value */ pipe = RL_GET_PIPE(hash_idx, name); if (!pipe) { LM_ERR("cannot get the index\n"); goto release; } if (!*pipe) { /* if the pipe does not exist, alocate it in case we need it later */ *pipe = shm_malloc(sizeof(rl_pipe_t)); if (!*pipe) { LM_ERR("no more shm memory\n"); goto release; } memset(*pipe, 0, sizeof(rl_pipe_t)); LM_DBG("Pipe %.*s doesn't exist, but was created %p\n", name.len, name.s, *pipe); (*pipe)->algo = algo; (*pipe)->limit = limit; } else { LM_DBG("Pipe %.*s found: %p - last used %lu\n", name.len, name.s, *pipe, (*pipe)->last_used); if ((*pipe)->algo != algo) LM_WARN("algorithm %d different from the initial one %d for " "pipe %.*s", algo, (*pipe)->algo, name.len, name.s); if ((*pipe)->limit != limit) LM_WARN("limit %d different from the initial one %d for " "pipe %.*s", limit, (*pipe)->limit, name.len, name.s); } /* set the last used time */ (*pipe)->last_used = time(0); /* set the destination's counter */ destination = find_destination(*pipe, server_id); destination->counter = counter; destination->update = now; RL_RELEASE_LOCK(hash_idx); } return; release: RL_RELEASE_LOCK(hash_idx); }
void rl_rcv_bin(int packet_type, struct receive_info *ri) { rl_algo_t algo; int limit; int counter; int rc; int server_id; str name; char *ip; unsigned short port; rl_pipe_t **pipe; unsigned int hash_idx; time_t now; rl_repl_counter_t *destination; LM_DBG("received a binary packet [%d]!\n", packet_type); if (packet_type != RL_PIPE_COUNTER) return; rc = bin_pop_int(&server_id); if (rc < 0) return; if (!clusterer_api.check(accept_repl_pipes, &ri->src_su, server_id, ri->proto)){ get_su_info(&ri->src_su.s, ip, port); LM_WARN("received bin packet from unknown source: %s:%hu\n", ip, port); return; } now = time(0); for (;;) { if (bin_pop_str(&name) == 1) break; /* pop'ed all pipes */ if (bin_pop_int(&algo) < 0) { LM_ERR("cannot pop pipe's algorithm\n"); return; } if (bin_pop_int(&limit) < 0) { LM_ERR("cannot pop pipe's limit\n"); return; } if (bin_pop_int(&counter) < 0) { LM_ERR("cannot pop pipe's counter\n"); return; } hash_idx = RL_GET_INDEX(name); RL_GET_LOCK(hash_idx); /* try to get the value */ pipe = RL_GET_PIPE(hash_idx, name); if (!pipe) { LM_ERR("cannot get the index\n"); goto release; } if (!*pipe) { /* if the pipe does not exist, alocate it in case we need it later */ *pipe = shm_malloc(sizeof(rl_pipe_t)); if (!*pipe) { LM_ERR("no more shm memory\n"); goto release; } memset(*pipe, 0, sizeof(rl_pipe_t)); LM_DBG("Pipe %.*s doesn't exist, but was created %p\n", name.len, name.s, *pipe); (*pipe)->algo = algo; (*pipe)->limit = limit; } else { LM_DBG("Pipe %.*s found: %p - last used %lu\n", name.len, name.s, *pipe, (*pipe)->last_used); if ((*pipe)->algo != algo) LM_WARN("algorithm %d different from the initial one %d for " "pipe %.*s", algo, (*pipe)->algo, name.len, name.s); if ((*pipe)->limit != limit) LM_WARN("limit %d different from the initial one %d for " "pipe %.*s", limit, (*pipe)->limit, name.len, name.s); } /* set the last used time */ (*pipe)->last_used = time(0); /* set the destination's counter */ destination = find_destination(*pipe, server_id); destination->counter = counter; destination->update = now; RL_RELEASE_LOCK(hash_idx); } return; release: RL_RELEASE_LOCK(hash_idx); }