bitwise_copy() is generally useful so make it a general utility function. Also add a comment.
Upcoming commits will introduce users for the new functions. --- lib/nx-match.c | 54 +---------------------------- lib/util.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/util.h | 8 ++++ 3 files changed, 115 insertions(+), 53 deletions(-) diff --git a/lib/nx-match.c b/lib/nx-match.c index 63e5e5b..ef166c7 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -29,6 +29,7 @@ #include "openflow/nicira-ext.h" #include "packets.h" #include "unaligned.h" +#include "util.h" #include "vlog.h" VLOG_DEFINE_THIS_MODULE(nx_match); @@ -1044,59 +1045,6 @@ nxm_check_reg_load(const struct nx_action_reg_load *action, /* nxm_execute_reg_move(), nxm_execute_reg_load(). */ -static 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; - } - } -} - /* Returns the value of the NXM field corresponding to 'header' at 'ofs_nbits' * in 'flow'. */ uint64_t diff --git a/lib/util.c b/lib/util.c index 8379c9a..7114d9f 100644 --- a/lib/util.c +++ b/lib/util.c @@ -25,7 +25,9 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include "byte-order.h" #include "coverage.h" +#include "openvswitch/types.h" #include "vlog.h" VLOG_DEFINE_THIS_MODULE(util); @@ -733,3 +735,107 @@ is_all_ones(const uint8_t *p, size_t n) 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. Bit 0 of 'src' is the bit with value 1 in + * src[src_len - 1], bit 1 is the bit with value 2, bit 8 is the bit with value + * 1 in src[src_len - 2], and so on, and 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; + } + } +} + +/* 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. Bit 0 of + * 'dst' is the bit with value 1 in dst[dst_len - 1], bit 1 is the bit with + * value 2, 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. Bit 0 of 'src' is the bit with value 1 in + * src[src_len - 1], bit 1 is the bit with value 2, 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); +} diff --git a/lib/util.h b/lib/util.h index b2052f3..c8eb004 100644 --- a/lib/util.h +++ b/lib/util.h @@ -208,6 +208,14 @@ int ctz(uint32_t); bool is_all_zeros(const uint8_t *, size_t); bool is_all_ones(const uint8_t *, size_t); +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); +void bitwise_put(uint64_t value, + void *dst, unsigned int dst_len, unsigned int dst_ofs, + unsigned int n_bits); +uint64_t bitwise_get(const void *src, unsigned int src_len, + unsigned int src_ofs, unsigned int n_bits); #ifdef __cplusplus } -- 1.7.2.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev