X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Futil.c;h=2402ac6e5a53de28e4702ebdaa347ea81587246c;hb=8a07709cb80462edb32fc11d056bfc08ce90f62d;hp=1aa827145323b472fd497c5a6e6c23ca17ca0cae;hpb=e868fb3d322f5c46385f1fc6db5bb1ab33f90305;p=sliver-openvswitch.git diff --git a/lib/util.c b/lib/util.c index 1aa827145..2402ac6e5 100644 --- a/lib/util.c +++ b/lib/util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010 Nicira Networks. + * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,18 @@ #include #include "util.h" +#include #include +#include #include +#include #include #include #include #include +#include "byte-order.h" #include "coverage.h" +#include "openvswitch/types.h" #include "vlog.h" VLOG_DEFINE_THIS_MODULE(util); @@ -30,11 +35,12 @@ VLOG_DEFINE_THIS_MODULE(util); COVERAGE_DEFINE(util_xalloc); const char *program_name; +static char *program_version; void out_of_memory(void) { - ovs_fatal(0, "virtual memory exhausted"); + ovs_abort(0, "virtual memory exhausted"); } void * @@ -149,32 +155,96 @@ ovs_strlcpy(char *dst, const char *src, size_t size) } } +/* Copies 'src' to 'dst'. Reads no more than 'size - 1' bytes from 'src'. + * Always null-terminates 'dst' (if 'size' is nonzero), and writes a zero byte + * to every otherwise unused byte in 'dst'. + * + * Except for performance, the following call: + * ovs_strzcpy(dst, src, size); + * is equivalent to these two calls: + * memset(dst, '\0', size); + * ovs_strlcpy(dst, src, size); + * + * (Thus, ovs_strzcpy() is similar to strncpy() without some of the pitfalls.) + */ void -ovs_fatal(int err_no, const char *format, ...) +ovs_strzcpy(char *dst, const char *src, size_t size) +{ + if (size > 0) { + size_t len = strnlen(src, size - 1); + memcpy(dst, src, len); + memset(dst + len, '\0', size - len); + } +} + +/* Prints 'format' on stderr, formatting it like printf() does. If 'err_no' is + * nonzero, then it is formatted with ovs_retval_to_string() and appended to + * the message inside parentheses. Then, terminates with abort(). + * + * This function is preferred to ovs_fatal() in a situation where it would make + * sense for a monitoring process to restart the daemon. + * + * 'format' should not end with a new-line, because this function will add one + * itself. */ +void +ovs_abort(int err_no, const char *format, ...) { va_list args; - fprintf(stderr, "%s: ", program_name); va_start(args, format); - vfprintf(stderr, format, args); + ovs_error_valist(err_no, format, args); va_end(args); - if (err_no != 0) - fprintf(stderr, " (%s)", ovs_retval_to_string(err_no)); - putc('\n', stderr); + abort(); +} + +/* Prints 'format' on stderr, formatting it like printf() does. If 'err_no' is + * nonzero, then it is formatted with ovs_retval_to_string() and appended to + * the message inside parentheses. Then, terminates with EXIT_FAILURE. + * + * 'format' should not end with a new-line, because this function will add one + * itself. */ +void +ovs_fatal(int err_no, const char *format, ...) +{ + va_list args; + + va_start(args, format); + ovs_fatal_valist(err_no, format, args); +} + +/* Same as ovs_fatal() except that the arguments are supplied as a va_list. */ +void +ovs_fatal_valist(int err_no, const char *format, va_list args) +{ + ovs_error_valist(err_no, format, args); exit(EXIT_FAILURE); } +/* Prints 'format' on stderr, formatting it like printf() does. If 'err_no' is + * nonzero, then it is formatted with ovs_retval_to_string() and appended to + * the message inside parentheses. + * + * 'format' should not end with a new-line, because this function will add one + * itself. */ void ovs_error(int err_no, const char *format, ...) { - int save_errno = errno; va_list args; - fprintf(stderr, "%s: ", program_name); va_start(args, format); - vfprintf(stderr, format, args); + ovs_error_valist(err_no, format, args); va_end(args); +} + +/* Same as ovs_error() except that the arguments are supplied as a va_list. */ +void +ovs_error_valist(int err_no, const char *format, va_list args) +{ + int save_errno = errno; + + fprintf(stderr, "%s: ", program_name); + vfprintf(stderr, format, args); if (err_no != 0) { fprintf(stderr, " (%s)", ovs_retval_to_string(err_no)); } @@ -210,21 +280,41 @@ ovs_retval_to_string(int retval) return unknown; } -/* Sets program_name based on 'argv0'. Should be called at the beginning of - * main(), as "set_program_name(argv[0]);". */ -void set_program_name(const char *argv0) +/* Sets global "program_name" and "program_version" variables. Should + * be called at the beginning of main() with "argv[0]" as the argument + * to 'argv0'. + * + * The 'date' and 'time' arguments should likely be called with + * "__DATE__" and "__TIME__" to use the time the binary was built. + * Alternatively, the "set_program_name" macro may be called to do this + * automatically. + */ +void +set_program_name__(const char *argv0, const char *date, const char *time) { const char *slash = strrchr(argv0, '/'); program_name = slash ? slash + 1 : argv0; + + free(program_version); + program_version = xasprintf("%s (Open vSwitch) "VERSION"\n" + "Compiled %s %s\n", + program_name, date, time); +} + +/* Returns a pointer to a string describing the program version. The + * caller must not modify or free the returned string. + */ +const char * +get_program_version(void) +{ + return program_version; } /* Print the version information for the program. */ void -ovs_print_version(char *date, char *time, - uint8_t min_ofp, uint8_t max_ofp) +ovs_print_version(uint8_t min_ofp, uint8_t max_ofp) { - printf("%s (Open vSwitch) "VERSION BUILDNR"\n", program_name); - printf("Compiled %s %s\n", date, time); + printf("%s", program_version); if (min_ofp || max_ofp) { printf("OpenFlow versions %#x:%#x\n", min_ofp, max_ofp); } @@ -532,3 +622,280 @@ abs_file_name(const char *dir, const char *file_name) * its return value. (Note that every scalar type can be implicitly * converted to bool.) */ void ignore(bool x OVS_UNUSED) { } + +/* Returns an appropriate delimiter for inserting just before the 0-based item + * 'index' in a list that has 'total' items in it. */ +const char * +english_list_delimiter(size_t index, size_t total) +{ + return (index == 0 ? "" + : index < total - 1 ? ", " + : total > 2 ? ", and " + : " and "); +} + +/* Given a 32 bit word 'n', calculates floor(log_2('n')). This is equivalent + * to finding the bit position of the most significant one bit in 'n'. It is + * an error to call this function with 'n' == 0. */ +int +log_2_floor(uint32_t n) +{ + assert(n); + +#if !defined(UINT_MAX) || !defined(UINT32_MAX) +#error "Someone screwed up the #includes." +#elif __GNUC__ >= 4 && UINT_MAX == UINT32_MAX + return 31 - __builtin_clz(n); +#else + { + int log = 0; + +#define BIN_SEARCH_STEP(BITS) \ + if (n >= (1 << BITS)) { \ + log += BITS; \ + n >>= BITS; \ + } + BIN_SEARCH_STEP(16); + BIN_SEARCH_STEP(8); + BIN_SEARCH_STEP(4); + BIN_SEARCH_STEP(2); + BIN_SEARCH_STEP(1); +#undef BIN_SEARCH_STEP + return log; + } +#endif +} + +/* Given a 32 bit word 'n', calculates ceil(log_2('n')). It is an error to + * call this function with 'n' == 0. */ +int +log_2_ceil(uint32_t n) +{ + return log_2_floor(n) + !IS_POW2(n); +} + +/* Returns the number of trailing 0-bits in 'n', or 32 if 'n' is 0. */ +int +ctz(uint32_t n) +{ + if (!n) { + return 32; + } else { +#if !defined(UINT_MAX) || !defined(UINT32_MAX) +#error "Someone screwed up the #includes." +#elif __GNUC__ >= 4 && UINT_MAX == UINT32_MAX + return __builtin_ctz(n); +#else + unsigned int k; + int count = 31; + +#define CTZ_STEP(X) \ + k = n << (X); \ + if (k) { \ + count -= X; \ + n = k; \ + } + CTZ_STEP(16); + CTZ_STEP(8); + CTZ_STEP(4); + CTZ_STEP(2); + CTZ_STEP(1); +#undef CTZ_STEP + + return count; +#endif + } +} + +/* Returns true if the 'n' bytes starting at 'p' are zeros. */ +bool +is_all_zeros(const uint8_t *p, size_t n) +{ + size_t i; + + for (i = 0; i < n; i++) { + if (p[i] != 0x00) { + return false; + } + } + return true; +} + +/* Returns true if the 'n' bytes starting at 'p' are 0xff. */ +bool +is_all_ones(const uint8_t *p, size_t n) +{ + size_t i; + + for (i = 0; i < n; i++) { + if (p[i] != 0xff) { + return false; + } + } + return true; +} + +/* Copies 'n_bits' bits starting from bit 'src_ofs' in 'src' to the 'n_bits' + * starting from bit 'dst_ofs' in 'dst'. 'src' is 'src_len' bytes long and + * 'dst' is 'dst_len' bytes long. + * + * If you consider all of 'src' to be a single unsigned integer in network byte + * order, then bit N is the bit with value 2**N. That is, bit 0 is the bit + * with value 1 in src[src_len - 1], bit 1 is the bit with value 2, bit 2 is + * the bit with value 4, ..., bit 8 is the bit with value 1 in src[src_len - + * 2], and so on. Similarly for 'dst'. + * + * Required invariants: + * src_ofs + n_bits <= src_len * 8 + * dst_ofs + n_bits <= dst_len * 8 + * 'src' and 'dst' must not overlap. + */ +void +bitwise_copy(const void *src_, unsigned int src_len, unsigned int src_ofs, + void *dst_, unsigned int dst_len, unsigned int dst_ofs, + unsigned int n_bits) +{ + const uint8_t *src = src_; + uint8_t *dst = dst_; + + src += src_len - (src_ofs / 8 + 1); + src_ofs %= 8; + + dst += dst_len - (dst_ofs / 8 + 1); + dst_ofs %= 8; + + if (src_ofs == 0 && dst_ofs == 0) { + unsigned int n_bytes = n_bits / 8; + if (n_bytes) { + dst -= n_bytes - 1; + src -= n_bytes - 1; + memcpy(dst, src, n_bytes); + + n_bits %= 8; + src--; + dst--; + } + if (n_bits) { + uint8_t mask = (1 << n_bits) - 1; + *dst = (*dst & ~mask) | (*src & mask); + } + } else { + while (n_bits > 0) { + unsigned int max_copy = 8 - MAX(src_ofs, dst_ofs); + unsigned int chunk = MIN(n_bits, max_copy); + uint8_t mask = ((1 << chunk) - 1) << dst_ofs; + + *dst &= ~mask; + *dst |= ((*src >> src_ofs) << dst_ofs) & mask; + + src_ofs += chunk; + if (src_ofs == 8) { + src--; + src_ofs = 0; + } + dst_ofs += chunk; + if (dst_ofs == 8) { + dst--; + dst_ofs = 0; + } + n_bits -= chunk; + } + } +} + +/* Zeros the 'n_bits' bits starting from bit 'dst_ofs' in 'dst'. 'dst' is + * 'dst_len' bytes long. + * + * If you consider all of 'dst' to be a single unsigned integer in network byte + * order, then bit N is the bit with value 2**N. That is, bit 0 is the bit + * with value 1 in dst[dst_len - 1], bit 1 is the bit with value 2, bit 2 is + * the bit with value 4, ..., bit 8 is the bit with value 1 in dst[dst_len - + * 2], and so on. + * + * Required invariant: + * dst_ofs + n_bits <= dst_len * 8 + */ +void +bitwise_zero(void *dst_, unsigned int dst_len, unsigned dst_ofs, + unsigned int n_bits) +{ + uint8_t *dst = dst_; + + if (!n_bits) { + return; + } + + dst += dst_len - (dst_ofs / 8 + 1); + dst_ofs %= 8; + + if (dst_ofs) { + unsigned int chunk = MIN(n_bits, 8 - dst_ofs); + + *dst &= ~(((1 << chunk) - 1) << dst_ofs); + + n_bits -= chunk; + if (!n_bits) { + return; + } + + dst--; + } + + while (n_bits >= 8) { + *dst-- = 0; + n_bits -= 8; + } + + if (n_bits) { + *dst &= ~((1 << n_bits) - 1); + } +} + +/* Copies the 'n_bits' low-order bits of 'value' into the 'n_bits' bits + * starting at bit 'dst_ofs' in 'dst', which is 'dst_len' bytes long. + * + * If you consider all of 'dst' to be a single unsigned integer in network byte + * order, then bit N is the bit with value 2**N. That is, bit 0 is the bit + * with value 1 in dst[dst_len - 1], bit 1 is the bit with value 2, bit 2 is + * the bit with value 4, ..., bit 8 is the bit with value 1 in dst[dst_len - + * 2], and so on. + * + * Required invariants: + * dst_ofs + n_bits <= dst_len * 8 + * n_bits <= 64 + */ +void +bitwise_put(uint64_t value, + void *dst, unsigned int dst_len, unsigned int dst_ofs, + unsigned int n_bits) +{ + ovs_be64 n_value = htonll(value); + bitwise_copy(&n_value, sizeof n_value, 0, + dst, dst_len, dst_ofs, + n_bits); +} + +/* Returns the value of the 'n_bits' bits starting at bit 'src_ofs' in 'src', + * which is 'src_len' bytes long. + * + * If you consider all of 'src' to be a single unsigned integer in network byte + * order, then bit N is the bit with value 2**N. That is, bit 0 is the bit + * with value 1 in src[src_len - 1], bit 1 is the bit with value 2, bit 2 is + * the bit with value 4, ..., bit 8 is the bit with value 1 in src[src_len - + * 2], and so on. + * + * Required invariants: + * src_ofs + n_bits <= src_len * 8 + * n_bits <= 64 + */ +uint64_t +bitwise_get(const void *src, unsigned int src_len, + unsigned int src_ofs, unsigned int n_bits) +{ + ovs_be64 value = htonll(0); + + bitwise_copy(src, src_len, src_ofs, + &value, sizeof value, 0, + n_bits); + return ntohll(value); +}