static clib_error_t * cj_config (vlib_main_t * vm, unformat_input_t * input) { cj_main_t * cjm = &cj_main; int matched = 0; int enable = 0; while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "records %d", &cjm->num_records)) matched = 1; else if (unformat (input, "on")) enable = 1; else return clib_error_return (0, "cj_config: unknown input '%U'", format_unformat_error, input); } if (matched == 0) return 0; cjm->num_records = max_pow2 (cjm->num_records); vec_validate (cjm->records, cjm->num_records-1); memset (cjm->records, 0xff, cjm->num_records * sizeof (cj_record_t)); cjm->tail = ~0; cjm->enable = enable; return 0; }
void * _clib_fifo_resize (void *v_old, uword n_new_elts, uword elt_bytes) { void *v_new, *end, *head; uword n_old_elts, header_bytes; uword n_copy_bytes, n_zero_bytes; clib_fifo_header_t *f_new, *f_old; n_old_elts = clib_fifo_elts (v_old); n_new_elts += n_old_elts; if (n_new_elts < 32) n_new_elts = 32; else n_new_elts = max_pow2 (n_new_elts); header_bytes = vec_header_bytes (sizeof (clib_fifo_header_t)); v_new = clib_mem_alloc_no_fail (n_new_elts * elt_bytes + header_bytes); v_new += header_bytes; f_new = clib_fifo_header (v_new); f_new->head_index = 0; f_new->tail_index = n_old_elts; _vec_len (v_new) = n_new_elts; /* Copy old -> new. */ n_copy_bytes = n_old_elts * elt_bytes; if (n_copy_bytes > 0) { f_old = clib_fifo_header (v_old); end = v_old + _vec_len (v_old) * elt_bytes; head = v_old + f_old->head_index * elt_bytes; if (head + n_copy_bytes >= end) { uword n = end - head; clib_memcpy_fast (v_new, head, n); clib_memcpy_fast (v_new + n, v_old, n_copy_bytes - n); } else clib_memcpy_fast (v_new, head, n_copy_bytes); } /* Zero empty space. */ n_zero_bytes = (n_new_elts - n_old_elts) * elt_bytes; clib_memset (v_new + n_copy_bytes, 0, n_zero_bytes); clib_fifo_free (v_old); return v_new; }
int test_mheap_main (unformat_input_t * input) { int i, j, k, n_iterations; void *h, *h_mem; uword *objects = 0; u32 objects_used, really_verbose, n_objects, max_object_size; u32 check_mask, seed, trace, use_vm; u32 print_every = 0; u32 *data; mheap_t *mh; /* Validation flags. */ check_mask = 0; #define CHECK_VALIDITY 1 #define CHECK_DATA 2 #define CHECK_ALIGN 4 #define TEST1 8 n_iterations = 10; seed = 0; max_object_size = 100; n_objects = 1000; trace = 0; really_verbose = 0; use_vm = 0; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (0 == unformat (input, "iter %d", &n_iterations) && 0 == unformat (input, "count %d", &n_objects) && 0 == unformat (input, "size %d", &max_object_size) && 0 == unformat (input, "seed %d", &seed) && 0 == unformat (input, "print %d", &print_every) && 0 == unformat (input, "validdata %|", &check_mask, CHECK_DATA | CHECK_VALIDITY) && 0 == unformat (input, "valid %|", &check_mask, CHECK_VALIDITY) && 0 == unformat (input, "verbose %=", &really_verbose, 1) && 0 == unformat (input, "trace %=", &trace, 1) && 0 == unformat (input, "vm %=", &use_vm, 1) && 0 == unformat (input, "align %|", &check_mask, CHECK_ALIGN) && 0 == unformat (input, "test1 %|", &check_mask, TEST1)) { clib_warning ("unknown input `%U'", format_unformat_error, input); return 1; } } /* Zero seed means use default. */ if (!seed) seed = random_default_seed (); if (check_mask & TEST1) { return test1 (); } if_verbose ("testing %d iterations, %d %saligned objects, max. size %d, seed %d", n_iterations, n_objects, (check_mask & CHECK_ALIGN) ? "randomly " : "un", max_object_size, seed); vec_resize (objects, n_objects); if (vec_bytes (objects) > 0) /* stupid warning be gone */ clib_memset (objects, ~0, vec_bytes (objects)); objects_used = 0; /* Allocate initial heap. */ { uword size = max_pow2 (2 * n_objects * max_object_size * sizeof (data[0])); h_mem = clib_mem_alloc (size); if (!h_mem) return 0; h = mheap_alloc (h_mem, size); } if (trace) mheap_trace (h, trace); mh = mheap_header (h); if (use_vm) mh->flags &= ~MHEAP_FLAG_DISABLE_VM; else mh->flags |= MHEAP_FLAG_DISABLE_VM; if (check_mask & CHECK_VALIDITY) mh->flags |= MHEAP_FLAG_VALIDATE; for (i = 0; i < n_iterations; i++) { while (1) { j = random_u32 (&seed) % vec_len (objects); if (objects[j] != ~0 || i + objects_used < n_iterations) break; } if (objects[j] != ~0) { mheap_put (h, objects[j]); objects_used--; objects[j] = ~0; } else { uword size, align, align_offset; size = (random_u32 (&seed) % max_object_size) * sizeof (data[0]); align = align_offset = 0; if (check_mask & CHECK_ALIGN) { align = 1 << (random_u32 (&seed) % 10); align_offset = round_pow2 (random_u32 (&seed) & (align - 1), sizeof (u32)); } h = mheap_get_aligned (h, size, align, align_offset, &objects[j]); if (align > 0) ASSERT (0 == ((objects[j] + align_offset) & (align - 1))); ASSERT (objects[j] != ~0); objects_used++; /* Set newly allocated object with test data. */ if (check_mask & CHECK_DATA) { uword len; data = (void *) h + objects[j]; len = mheap_len (h, data); ASSERT (size <= mheap_data_bytes (h, objects[j])); data[0] = len; for (k = 1; k < len; k++) data[k] = objects[j] + k; } } /* Verify that all used objects have correct test data. */ if (check_mask & 2) { for (j = 0; j < vec_len (objects); j++) if (objects[j] != ~0) { u32 *data = h + objects[j]; uword len = data[0]; for (k = 1; k < len; k++) ASSERT (data[k] == objects[j] + k); } } if (print_every != 0 && i > 0 && (i % print_every) == 0) fformat (stderr, "iteration %d: %U\n", i, format_mheap, h, really_verbose); } if (verbose) fformat (stderr, "%U\n", format_mheap, h, really_verbose); mheap_free (h); clib_mem_free (h_mem); vec_free (objects); return 0; }
/* Given next hop vector is over-written with normalized one with sorted weights and with weights corresponding to the number of adjacencies for each next hop. Returns number of adjacencies in block. */ static u32 ip_multipath_normalize_next_hops (ip_lookup_main_t * lm, ip_multipath_next_hop_t * raw_next_hops, ip_multipath_next_hop_t ** normalized_next_hops) { ip_multipath_next_hop_t * nhs; uword n_nhs, n_adj, n_adj_left, i; f64 sum_weight, norm, error; n_nhs = vec_len (raw_next_hops); ASSERT (n_nhs > 0); if (n_nhs == 0) return 0; /* Allocate enough space for 2 copies; we'll use second copy to save original weights. */ nhs = *normalized_next_hops; vec_validate (nhs, 2*n_nhs - 1); /* Fast path: 1 next hop in block. */ n_adj = n_nhs; if (n_nhs == 1) { nhs[0] = raw_next_hops[0]; nhs[0].weight = 1; _vec_len (nhs) = 1; goto done; } else if (n_nhs == 2) { int cmp = next_hop_sort_by_weight (&raw_next_hops[0], &raw_next_hops[1]) < 0; /* Fast sort. */ nhs[0] = raw_next_hops[cmp]; nhs[1] = raw_next_hops[cmp ^ 1]; /* Fast path: equal cost multipath with 2 next hops. */ if (nhs[0].weight == nhs[1].weight) { nhs[0].weight = nhs[1].weight = 1; _vec_len (nhs) = 2; goto done; } } else { memcpy (nhs, raw_next_hops, n_nhs * sizeof (raw_next_hops[0])); qsort (nhs, n_nhs, sizeof (nhs[0]), (void *) next_hop_sort_by_weight); } /* Find total weight to normalize weights. */ sum_weight = 0; for (i = 0; i < n_nhs; i++) sum_weight += nhs[i].weight; /* In the unlikely case that all weights are given as 0, set them all to 1. */ if (sum_weight == 0) { for (i = 0; i < n_nhs; i++) nhs[i].weight = 1; sum_weight = n_nhs; } /* Save copies of all next hop weights to avoid being overwritten in loop below. */ for (i = 0; i < n_nhs; i++) nhs[n_nhs + i].weight = nhs[i].weight; /* Try larger and larger power of 2 sized adjacency blocks until we find one where traffic flows to within 1% of specified weights. */ for (n_adj = max_pow2 (n_nhs); ; n_adj *= 2) { error = 0; norm = n_adj / sum_weight; n_adj_left = n_adj; for (i = 0; i < n_nhs; i++) { f64 nf = nhs[n_nhs + i].weight * norm; /* use saved weights */ word n = flt_round_nearest (nf); n = n > n_adj_left ? n_adj_left : n; n_adj_left -= n; error += fabs (nf - n); nhs[i].weight = n; } nhs[0].weight += n_adj_left; /* Less than 5% average error per adjacency with this size adjacency block? */ if (error <= lm->multipath_next_hop_error_tolerance*n_adj) { /* Truncate any next hops with zero weight. */ _vec_len (nhs) = i; break; } } done: /* Save vector for next call. */ *normalized_next_hops = nhs; return n_adj; }