0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 17:51:53 +00:00

Porting the CBOR encoder from the YANG branch

Minor cleanups by commiter.

(source commit 43ff10204b but expected
to be rebased later, don't worry if you fail to find it)
This commit is contained in:
Katerina Kubecova 2024-09-05 11:59:02 +02:00 committed by Maria Matejka
parent 253ce95bc9
commit 9f27bfc6fc
8 changed files with 658 additions and 2 deletions

View File

@ -1,4 +1,4 @@
src := bitmap.c bitops.c blake2s.c blake2b.c checksum.c defer.c event.c flowspec.c idm.c ip.c lists.c lockfree.c mac.c md5.c mempool.c net.c netindex.c patmatch.c printf.c rcu.c resource.c runtime.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
src := bitmap.c bitops.c blake2s.c blake2b.c cbor.c cbor_parse_tools.c cbor_shortcuts.c checksum.c defer.c event.c flowspec.c idm.c ip.c lists.c lockfree.c mac.c md5.c mempool.c net.c netindex.c patmatch.c printf.c rcu.c resource.c runtime.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
obj := $(src-o-files)
$(all-lib)
@ -6,6 +6,6 @@ src := a-path.c a-set.c
obj := $(src-o-files)
$(all-daemon)
tests_src := a-set_test.c a-path_test.c attribute_cleanup_test.c bitmap_test.c heap_test.c buffer_test.c event_test.c flowspec_test.c bitops_test.c patmatch_test.c fletcher16_test.c slist_test.c checksum_test.c lists_test.c locking_test.c mac_test.c ip_test.c hash_test.c printf_test.c rcu_test.c slab_test.c tlists_test.c type_test.c
tests_src := a-set_test.c a-path_test.c attribute_cleanup_test.c bitmap_test.c cbor_test.c heap_test.c buffer_test.c event_test.c flowspec_test.c bitops_test.c patmatch_test.c fletcher16_test.c slist_test.c checksum_test.c lists_test.c locking_test.c mac_test.c ip_test.c hash_test.c printf_test.c rcu_test.c slab_test.c tlists_test.c type_test.c
tests_targets := $(tests_targets) $(tests-target-files)
tests_objs := $(tests_objs) $(src-o-files)

237
lib/cbor.c Normal file
View File

@ -0,0 +1,237 @@
#include <stdint.h>
#include <string.h>
#include "lib/cbor.h"
void write_item(struct cbor_writer *writer, uint8_t major, uint64_t num);
void check_memory(struct cbor_writer *writer, int add_size);
struct cbor_writer *cbor_init(uint8_t *buff, uint32_t capacity, struct linpool *lp)
{
struct cbor_writer *writer = (struct cbor_writer*)lp_alloc(lp, sizeof(struct cbor_writer));
writer->cbor = buff;
writer->capacity = capacity;
writer->pt = 0;
writer->lp = lp;
return writer;
}
void cbor_open_block(struct cbor_writer *writer) { // We will need to close the block later manualy
check_memory(writer, 2);
writer->cbor[writer->pt] = 0xbf;
writer->pt++;
}
void cbor_open_list(struct cbor_writer *writer)
{
check_memory(writer, 2);
writer->cbor[writer->pt] = 0x9f;
writer->pt++;
}
void cbor_close_block_or_list(struct cbor_writer *writer)
{
check_memory(writer, 2);
writer->cbor[writer->pt] = 0xff;
writer->pt++;
}
void cbor_open_block_with_length(struct cbor_writer *writer, uint32_t length)
{
write_item(writer, 5, length);
}
void cbor_open_list_with_length(struct cbor_writer *writer, uint32_t length)
{
write_item(writer, 4, length);
}
void cbor_add_int(struct cbor_writer *writer, int64_t item)
{
if (item >= 0)
{
write_item(writer, 0, item); // 0 is the "major" (three bits) introducing positive int, 1 is for negative
}
else
{
write_item(writer, 1, -item - 1);
}
}
void cbor_epoch_time(struct cbor_writer *writer, int64_t time, int shift)
{
write_item(writer, 6, 1); // 6 is TAG, 1 is tag number for epoch time
cbor_relativ_time(writer, time, shift);
}
void cbor_relativ_time(struct cbor_writer *writer, int64_t time, int shift)
{
write_item(writer, 6, 4); // 6 is TAG, 4 is tag number for decimal fraction
cbor_open_list_with_length(writer, 2);
cbor_add_int(writer, shift);
cbor_add_int(writer, time);
}
void cbor_add_ipv4(struct cbor_writer *writer, ip4_addr addr)
{
write_item(writer, 6, 52); // 6 is TAG, 52 is tag number for ipv4
write_item(writer, 2, 4); // bytestring of length 4
put_ip4(&writer->cbor[writer->pt], addr);
writer->pt += 4;
}
void cbor_add_ipv6(struct cbor_writer *writer, ip6_addr addr)
{
write_item(writer, 6, 54); // 6 is TAG, 54 is tag number for ipv6
write_item(writer, 2, 16); // bytestring of length 16
put_ip6(&writer->cbor[writer->pt], addr);
writer->pt += 16;
}
void cbor_add_ipv4_prefix(struct cbor_writer *writer, net_addr_ip4 *n)
{
write_item(writer, 6, 52); // 6 is TAG, 52 is tag number for ipv4
cbor_open_block_with_length(writer, 2);
cbor_add_int(writer, n->pxlen);
write_item(writer, 2, 4); // bytestring of length 4
put_ip4(&writer->cbor[writer->pt], n->prefix);
writer->pt += 4;
}
void cbor_add_ipv6_prefix(struct cbor_writer *writer, net_addr_ip6 *n)
{
write_item(writer, 6, 54); // 6 is TAG, 54 is tag number for ipv6
cbor_open_block_with_length(writer, 2);
cbor_add_int(writer, n->pxlen);
write_item(writer, 2, 16);
put_ip6(&writer->cbor[writer->pt], n->prefix);
writer->pt += 16;
}
void cbor_add_uint(struct cbor_writer *writer, uint64_t item)
{
write_item(writer, 0, item);
}
void cbor_add_tag(struct cbor_writer *writer, int item)
{
write_item(writer, 6, item);
}
void cbor_add_string(struct cbor_writer *writer, const char *string)
{
int length = strlen(string);
write_item(writer, 3, length); // 3 is major, then goes length of string and string
check_memory(writer, length);
memcpy(writer->cbor+writer->pt, string, length);
writer->pt+=length;
}
void cbor_nonterminated_string(struct cbor_writer *writer, const char *string, uint32_t length)
{
write_item(writer, 3, length); // 3 is major, then goes length of string and string
check_memory(writer, length);
memcpy(writer->cbor+writer->pt, string, length);
writer->pt+=length;
}
void write_item(struct cbor_writer *writer, uint8_t major, uint64_t num)
{
//log("write major %i %li", major, num);
major = major<<5;
check_memory(writer, 10);
if (num > ((uint64_t)1<<(4*8))-1)
{ // We need 8 bytes to encode the num
major += 0x1b; // reserving those bytes
writer->cbor[writer->pt] = major;
writer->pt++;
for (int i = 7; i>=0; i--)
{ // write n-th byte of num
uint8_t to_write = (num>>(i*8)) & 0xff;
writer->cbor[writer->pt] = to_write;
writer->pt++;
}
return;
}
if (num > (1<<(2*8))-1)
{ // We need 4 bytes to encode the num
major += 0x1a; // reserving those bytes
writer->cbor[writer->pt] = major;
writer->pt++;
for (int i = 3; i>=0; i--)
{ // write n-th byte of num
uint8_t to_write = (num>>(i*8)) & 0xff;
writer->cbor[writer->pt] = to_write;
writer->pt++;
}
return;
}
if (num > (1<<(8))-1)
{ // We need 2 bytes to encode the num
major += 0x19; // reserving those bytes
writer->cbor[writer->pt] = major;
writer->pt++;
for (int i = 1; i>=0; i--)
{ // write n-th byte of num
uint8_t to_write = (num>>(i*8)) & 0xff;
writer->cbor[writer->pt] = to_write;
writer->pt++;
}
return;
}
if (num > 23)
{ // byte is enough, but aditional value would be too big
major += 0x18; // reserving that byte
writer->cbor[writer->pt] = major;
writer->pt++;
uint8_t to_write = num & 0xff;
writer->cbor[writer->pt] = to_write;
writer->pt++;
return;
}
//log("write item major %i num %i writer->pt %i writer->capacity %i writer %i", major, num, writer->pt, writer->capacity, writer);
major += num; // we can store the num as additional value
writer->cbor[writer->pt] = major;
writer->pt++;
}
void cbor_write_item_with_constant_val_length_4(struct cbor_writer *writer, uint8_t major, uint64_t num)
{
// this is only for headers which should be constantly long.
major = major<<5;
check_memory(writer, 10);
major += 0x1a; // reserving those bytes
writer->cbor[writer->pt] = major;
writer->pt++;
for (int i = 3; i>=0; i--)
{ // write n-th byte of num
uint8_t to_write = (num>>(i*8)) & 0xff;
writer->cbor[writer->pt] = to_write;
writer->pt++;
}
}
void rewrite_4bytes_int(struct cbor_writer *writer, int pt, int num)
{
for (int i = 3; i>=0; i--)
{
uint8_t to_write = (num>>(i*8)) & 0xff;
writer->cbor[pt] = to_write;
pt++;
}
}
void check_memory(struct cbor_writer *writer, int add_size)
{
if (writer->capacity - writer->pt-add_size < 0)
{
bug("There is not enough space for cbor response in given buffer");
}
}

58
lib/cbor.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef CBOR_H
#define CBOR_H
#include "nest/bird.h"
struct cbor_writer {
int pt; // where will next byte go
int capacity;
int8_t *cbor;
struct linpool *lp;
};
struct cbor_writer *cbor_init(uint8_t *buff, uint32_t capacity, struct linpool *lp);
void cbor_open_block(struct cbor_writer *writer);
void cbor_open_list(struct cbor_writer *writer);
void cbor_close_block_or_list(struct cbor_writer *writer);
void cbor_open_block_with_length(struct cbor_writer *writer, uint32_t length);
void cbor_open_list_with_length(struct cbor_writer *writer, uint32_t length);
void cbor_add_int(struct cbor_writer *writer, int64_t item);
void cbor_add_ipv4(struct cbor_writer *writer, ip4_addr);
void cbor_add_ipv6(struct cbor_writer *writer, ip6_addr);
void cbor_epoch_time(struct cbor_writer *writer, int64_t time, int shift);
void cbor_relativ_time(struct cbor_writer *writer, int64_t time, int shift);
void cbor_add_ipv4_prefix(struct cbor_writer *writer, net_addr_ip4 *n);
void cbor_add_ipv6_prefix(struct cbor_writer *writer, net_addr_ip6 *n);
void cbor_add_uint(struct cbor_writer *writer, uint64_t item);
void cbor_add_tag(struct cbor_writer *writer, int item);
void cbor_add_string(struct cbor_writer *writer, const char *string);
void cbor_nonterminated_string(struct cbor_writer *writer, const char *string, uint32_t length);
void write_item(struct cbor_writer *writer, uint8_t major, uint64_t num);
void cbor_write_item_with_constant_val_length_4(struct cbor_writer *writer, uint8_t major, uint64_t num);
void rewrite_4bytes_int(struct cbor_writer *writer, int pt, int num);
#endif

69
lib/cbor_parse_tools.c Normal file
View File

@ -0,0 +1,69 @@
#include <string.h>
#include "lib/cbor_parse_tools.h"
uint compare_buff_str(struct buff_reader *buf_read, uint length, char *string) {
if (length != strlen(string)) {
return 0;
}
for (size_t i = 0; i < strlen(string); i++) {
if (buf_read->buff[i+buf_read->pt]!=string[i]) {
return 0;
}
}
return 1;
};
struct value
get_value(struct buff_reader *reader)
{
struct value val;
byte *buff = reader->buff;
val.major = buff[reader->pt]>>5;
int first_byte_val = buff[reader->pt] - (val.major<<5);
if (first_byte_val <=23) {
val.val = first_byte_val;
reader->pt++;
} else if (first_byte_val == 0x18)
{
val.val = buff[reader->pt+1];
reader->pt+=2;
} else if (first_byte_val == 0x19)
{
val.val = buff[reader->pt+1];
val.val = val.val << 8;
val.val += buff[reader->pt+2];
reader->pt += 3;
} else if (first_byte_val == 0x1a)
{
val.val = 0;
for (int i = 1; i < 4; i++)
{
val.val += buff[reader->pt+i];
val.val = val.val << 8;
}
val.val += buff[reader->pt+4];
reader->pt+=5;
} else if (first_byte_val == 0x1b)
{
val.val = 0;
for (int i = 1; i < 8; i++) {
val.val += buff[reader->pt+i];
val.val = val.val << 8;
}
val.val += buff[reader->pt+8];
reader->pt += 9;
} else if (first_byte_val == 0x1f)
{
val.val = -1;
reader->pt++;
}
if (val.major == NEG_INT)
val.val = -1 - val.val;
return val;
}
int val_is_break(struct value val)
{
return val.major == FLOAT && val.val == -1; // break code is 0xff, so the major is same for float and break
}

42
lib/cbor_parse_tools.h Normal file
View File

@ -0,0 +1,42 @@
#include "sysdep/config.h"
#include "lib/birdlib.h"
enum functions {
SHOW_STATUS = 0,
SHOW_MEMORY = 1,
SHOW_SYMBOLS = 2,
SHOW_OSPF = 3,
SHOW_PROTOCOLS = 4,
};
enum cbor_majors {
UINT = 0,
NEG_INT = 1,
BYTE_STR = 2,
TEXT = 3,
ARRAY = 4,
BLOCK = 5,
TAG = 6,
FLOAT = 7,
};
struct value {
int major;
int64_t val;
};
struct buff_reader {
byte *buff;
uint pt;
uint size;
};
uint compare_buff_str(struct buff_reader *buf_read, uint length, char *string);
struct value
get_value(struct buff_reader *reader);
int val_is_break(struct value val);

87
lib/cbor_shortcuts.c Normal file
View File

@ -0,0 +1,87 @@
#include <stdio.h>
#include <stdlib.h>
#include "lib/cbor_shortcuts.h"
void cbor_string_string(struct cbor_writer *writer, char *key, const char *value) {
cbor_add_string(writer, key);
cbor_add_string(writer, value);
}
void cbor_string_int(struct cbor_writer *writer, char *key, int64_t value) {
cbor_add_string(writer, key);
cbor_add_int(writer, value);
}
void cbor_string_uint(struct cbor_writer *writer, char *key, u64 value) {
cbor_add_string(writer, key);
cbor_add_uint(writer, value);
}
void cbor_string_epoch_time(struct cbor_writer *writer, char *key, int64_t time, int shift) {
cbor_add_string(writer, key);
cbor_epoch_time(writer, time, shift);
}
void cbor_string_relativ_time(struct cbor_writer *writer, char *key, int64_t time, int shift) {
cbor_add_string(writer, key);
cbor_relativ_time(writer, time, shift);
}
void cbor_string_ip(struct cbor_writer *writer, char *key, ip_addr addr) {
cbor_add_string(writer, key);
if (ipa_is_ip4(addr))
cbor_add_ipv4(writer, ipa_to_ip4(addr));
else
cbor_add_ipv6(writer, ipa_to_ip6(addr));
}
void cbor_string_ipv4(struct cbor_writer *writer, char *key, ip4_addr addr) {
cbor_add_string(writer, key);
cbor_add_ipv4(writer, addr);
}
void cbor_string_ipv6(struct cbor_writer *writer, char *key, ip6_addr addr) {
cbor_add_string(writer, key);
cbor_add_ipv6(writer, addr);
}
void cbor_named_block_two_ints(struct cbor_writer *writer, char *key, char *name1, int val1, char *name2, int val2) {
cbor_add_string(writer, key);
cbor_open_block_with_length(writer, 2);
cbor_add_string(writer, name1);
cbor_add_int(writer, val1);
cbor_add_string(writer, name2);
cbor_add_int(writer, val2);
}
void cbor_write_to_file(struct cbor_writer *writer, char *filename) {
FILE *write_ptr;
write_ptr = fopen(filename, "wb");
fwrite(writer->cbor, writer->pt, 1, write_ptr);
fclose(write_ptr);
}
void cbor_add_net(struct cbor_writer *writer, const net_addr *N) {
// Original switch comes from lib/net.c and contains more cases.
net_addr_union *n = (void *) N;
switch (n->n.type)
{
case NET_IP4:
cbor_add_ipv4_prefix(writer, &n->ip4);
return;
case NET_IP6:
cbor_add_ipv6_prefix(writer, &n->ip6);
return;
default:
bug("net type unsupported by cbor (yet).");
}
}

26
lib/cbor_shortcuts.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef CBOR_SHORTCUTS_H
#define CBOR_SHORTCUTS_H
#include "lib/cbor.h"
#include "sysdep/config.h"
#include "lib/birdlib.h"
#include "nest/protocol.h"
#include "lib/ip.h"
void cbor_string_string(struct cbor_writer *writer, char *key, const char *value);
void cbor_string_int(struct cbor_writer *writer, char *key, int64_t value);
void cbor_string_epoch_time(struct cbor_writer *writer, char *key, int64_t time, int shift);
void cbor_string_relativ_time(struct cbor_writer *writer, char *key, int64_t time, int shift);
void cbor_string_uint(struct cbor_writer *writer, char *key, u64 value);
void cbor_string_ip(struct cbor_writer *writer, char *key, ip_addr);
void cbor_string_ipv4(struct cbor_writer *writer, char *key, ip4_addr);
void cbor_string_ipv6(struct cbor_writer *writer, char *key, ip6_addr);
void cbor_named_block_two_ints(struct cbor_writer *writer, char *key, char *name1, int val1, char *name2, int val2);
void cbor_write_to_file(struct cbor_writer *writer, char *filename);
void cbor_add_net(struct cbor_writer *writer, const net_addr *N);
#endif

137
lib/cbor_test.c Normal file
View File

@ -0,0 +1,137 @@
#include "test/birdtest.h"
#include "lib/cbor.h"
#include "lib/cbor_parse_tools.h"
#define BUFF_LEN 100
struct cbor_writer *w;
struct buff_reader reader;
void print_to_file_for_control_from_outside(void)
{
FILE *write_ptr;
write_ptr = fopen("a.cbor", "wb");
fwrite(w->cbor, w->pt, 1, write_ptr);
fclose(write_ptr);
}
static int test_int(void)
{
reader.pt = w->pt = 0;
int num_items = 13;
int64_t test_int[] = {-123456789012345678, -1234567890, -12345, -123, -25, -13, 0, 13, 25, 123, 12345, 1234567890, 123456789012345678};
byte bin_int[] = {0x8d, 0x3b, 0x1, 0xb6, 0x9b, 0x4b, 0xa6, 0x30, 0xf3, 0x4d, 0x3a, 0x49, 0x96, 0x2, 0xd1, 0x39, 0x30, 0x38, 0x38, 0x7a, 0x38, 0x18, 0x2c, 0x0, 0xd, 0x18, 0x19, 0x18, 0x7b, 0x19, 0x30, 0x39, 0x1a, 0x49, 0x96, 0x2, 0xd2, 0x1b, 0x1, 0xb6, 0x9b, 0x4b, 0xa6, 0x30, 0xf3, 0x4e};
cbor_open_list_with_length(w, num_items);
for (int i = 0; i < num_items; i++)
{
cbor_add_int(w, test_int[i]);
}
for (long unsigned int i = 0; i < sizeof(bin_int); i++)
{
bt_assert((w->cbor[i] & 0xff) == (bin_int[i] & 0xff));
}
struct value val = get_value(&reader);
bt_assert(val.major = ARRAY);
bt_assert(val.val = num_items);
for (int i = 0; i < num_items; i++)
{
val = get_value(&reader);
bt_assert(val.major == NEG_INT || val.major == UINT);
bt_assert(val.val == test_int[i]);
}
return 1;
}
static int non_aligned_int(void)
{
w->pt = reader.pt = 0;
int num_items = 4;
cbor_open_list_with_length(w, num_items);
cbor_add_int(w, 30);
w->cbor[w->pt - 1] = 1;
cbor_add_int(w, 300);
w->cbor[w->pt - 2] = 0;
w->cbor[w->pt - 1] = 1;
cbor_add_int(w, 300000000);
for (int i = 4; i > 1; i--)
{
w->cbor[w->pt - i] = 0;
}
w->cbor[w->pt - 1] = 1;
cbor_add_int(w, 30000000000000000);
for (int i = 8; i > 1; i--)
{
w->cbor[w->pt - i] = 0;
}
w->cbor[w->pt - 1] = 1;
struct value val = get_value(&reader);
bt_assert(val.major = ARRAY);
bt_assert(val.val = num_items);
for (int i = 0; i < num_items; i++)
{
val = get_value(&reader);
bt_assert(val.major == UINT);
bt_assert(val.val == 1);
}
return 1;
}
static int test_majors(void)
{
w->pt = reader.pt = 0;
cbor_open_block(w);
cbor_open_list_with_length(w, 4);
cbor_add_string(w, "b");
cbor_add_int(w, 1);
cbor_add_int(w, -1);
cbor_add_ipv4(w, ip4_build(18, 4, 0, 0));
cbor_close_block_or_list(w);
struct value val = get_value(&reader);
bt_assert(val.major == BLOCK);
val = get_value(&reader);
bt_assert(val.major == ARRAY);
val = get_value(&reader);
bt_assert(val.major == TEXT);
reader.pt += val.val;
val = get_value(&reader);
bt_assert(val.major == UINT);
val = get_value(&reader);
bt_assert(val.major == NEG_INT);
val = get_value(&reader);
bt_assert(val.major == TAG);
val = get_value(&reader);
bt_assert(val.major == BYTE_STR);
reader.pt += val.val;
val = get_value(&reader);
bt_assert(val_is_break(val));
return 1;
}
int main(int argc, char *argv[])
{
bt_init(argc, argv);
byte buff[BUFF_LEN];
w = cbor_init(buff, BUFF_LEN, tmp_linpool);
reader.buff = buff;
reader.size = BUFF_LEN;
reader.pt = 0;
bt_test_suite(test_int, "Adding and reading integer from cbor.");
bt_test_suite(non_aligned_int, "Reading non-alligned int from cbor.");
bt_test_suite(test_majors, "Test cbor datatypes.");
return bt_exit_value();
}