diff --git a/ospp-kmesh-break/bpf/deserialization_to_bpf_map/Makefile b/ospp-kmesh-break/bpf/deserialization_to_bpf_map/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..492630ed9077e19437b19702eba91922ea51adbf --- /dev/null +++ b/ospp-kmesh-break/bpf/deserialization_to_bpf_map/Makefile @@ -0,0 +1,59 @@ +# Copyright (c) 2019 Huawei Technologies Co., Ltd. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Author: LemmyHuang +# Create: 2021-09-17 + +ROOT_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) + +include ../../mk/bpf.vars.mk +include ../../mk/bpf.print.mk + +INCLUDES = + +# compiler flags +LDFLAGS := -lbpf -lboundscheck +CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_CDEFINE) +CFLAGS += -fstack-protector -fPIC +CFLAGS += -Wall -Werror + +SOURCES = $(wildcard *.c) +OBJECTS = $(subst .c,.o,$(SOURCES)) +# target +APPS := libkmesh_deserial.so + +.PHONY: all install clean + +all: $(APPS) + +$(APPS): $(OBJECTS) + $(call printlog, BUILD, bpf/deserialization_to_bpf_map/$@) + $(QUIET) $(CLANG) $(CFLAGS) $(LDFLAGS) -shared $^ -o $@ + +%.o: %.c + $(call printlog, BUILD, bpf/deserialization_to_bpf_map/$@) + $(QUIET) $(CLANG) $(CFLAGS) $(INCLUDES) -c $^ -o $@ + +install: + $(call printlog, INSTALL, $(INSTALL_LIB)/$(APPS)) + $(QUIET) install -Dp -m 0550 $(APPS) $(INSTALL_LIB) + +uninstall: + $(call printlog, UNINSTALL, $(INSTALL_LIB)/$(APPS)) + $(QUIET) rm -rf $(INSTALL_LIB)/$(APPS) + +clean: + $(call printlog, CLEAN, $(APPS)) + $(QUIET) rm -rf $(APPS) $(APPS) $(OBJECTS) + diff --git a/ospp-kmesh-break/bpf/deserialization_to_bpf_map/deserialization_to_bpf_map.c b/ospp-kmesh-break/bpf/deserialization_to_bpf_map/deserialization_to_bpf_map.c new file mode 100644 index 0000000000000000000000000000000000000000..d071d5a49865627a3fbd75da1d92179f61de463a --- /dev/null +++ b/ospp-kmesh-break/bpf/deserialization_to_bpf_map/deserialization_to_bpf_map.c @@ -0,0 +1,1526 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "deserialization_to_bpf_map.h" + +#define LOG_ERR(fmt, args...) printf(fmt, ## args) +#define LOG_WARN(fmt, args...) printf(fmt, ## args) +#define LOG_INFO(fmt, args...) printf(fmt, ## args) + +#define FREE_MAP_SIZE (MAX_OUTTER_MAP_ENTRIES / (sizeof(uint32_t) * 8)) + +struct outter_map_alloc_control { + unsigned int used; + uint32_t free_map[FREE_MAP_SIZE]; +}; + +struct op_context { + void *key; + void *value; + int outter_fd; + int map_fd; + int curr_fd; + struct bpf_map_info *outter_info; + struct bpf_map_info *inner_info; + struct bpf_map_info *info; + struct bpf_map_info *curr_info; + char *inner_map_object; + const ProtobufCMessageDescriptor *desc; +}; + +#define init_op_context(context, key, val, desc, o_fd, fd, o_info, \ + i_info, m_info) \ +do { \ + (context).key = (key); \ + (context).value = (val); \ + (context).desc = (desc); \ + (context).outter_fd = (o_fd); \ + (context).map_fd = (fd); \ + (context).outter_info = (o_info); \ + (context).inner_info = (i_info); \ + (context).info = (m_info); \ + (context).curr_info = (m_info); \ + (context).curr_fd = (fd); \ +} while (0) + +static int update_bpf_map(struct op_context *ctx); +static void* create_struct(struct op_context *ctx, int *err); +static int del_bpf_map(struct op_context *ctx, int is_inner); +static int free_outter_map_entry(struct op_context *ctx, void *outter_key); + +static int normalize_key(struct op_context *ctx, void *key, const char *map_name) +{ + ctx->key = calloc(1, ctx->curr_info->key_size); + if (!ctx->key) + return -errno; + + if (!map_name) + return -errno; + + // TODO + if (!strncmp(map_name, "Listener", strlen(map_name))) + memcpy_s(ctx->key, ctx->curr_info->key_size, key, ctx->curr_info->key_size); + else + strncpy(ctx->key, key, ctx->curr_info->key_size); + + return 0; +} + +static inline int selected_oneof_field(void *value, + const ProtobufCFieldDescriptor *field) +{ + uint32_t n = *(uint32_t*)((char*)value + field->quantifier_offset); + + if ((field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF) && field->id != n) + return 0; + + return 1; +} + +static inline int valid_field_value(void *value, + const ProtobufCFieldDescriptor *field) +{ + uint32_t val = *(uint32_t*)((char*)value + field->offset); + + if (val == 0) { + switch (field->type) { + case PROTOBUF_C_TYPE_MESSAGE: + case PROTOBUF_C_TYPE_STRING: + return 0; + default: + break; + } + + switch (field->label) { + case PROTOBUF_C_LABEL_REPEATED: + return 0; + default: + break; + } + } + + return 1; +} + +static inline size_t sizeof_elt_in_repeated_array(ProtobufCType type) +{ + switch (type) { + case PROTOBUF_C_TYPE_SINT32: + case PROTOBUF_C_TYPE_INT32: + case PROTOBUF_C_TYPE_UINT32: + case PROTOBUF_C_TYPE_SFIXED32: + case PROTOBUF_C_TYPE_FIXED32: + case PROTOBUF_C_TYPE_FLOAT: + case PROTOBUF_C_TYPE_ENUM: + return 4; + case PROTOBUF_C_TYPE_SINT64: + case PROTOBUF_C_TYPE_INT64: + case PROTOBUF_C_TYPE_UINT64: + case PROTOBUF_C_TYPE_SFIXED64: + case PROTOBUF_C_TYPE_FIXED64: + case PROTOBUF_C_TYPE_DOUBLE: + return 8; + case PROTOBUF_C_TYPE_BOOL: + return sizeof(protobuf_c_boolean); + case PROTOBUF_C_TYPE_STRING: + case PROTOBUF_C_TYPE_MESSAGE: + return sizeof(void *); + case PROTOBUF_C_TYPE_BYTES: + return sizeof(ProtobufCBinaryData); + default: + break; + } + + return 0; +} + +static inline int valid_outter_key(struct op_context *ctx, unsigned int outter_key) +{ + if (outter_key >= ctx->outter_info->max_entries || !outter_key) + return 0; + + return 1; +} + +static void free_elem(void *ptr) +{ + if ((uintptr_t)ptr < MAX_OUTTER_MAP_ENTRIES) + return; + + free(ptr); +} + +static void free_keys(struct op_context *ctx, void *keys, int n) +{ + int i; + unsigned int key; + for (i = 0; i < n; i++) { + key = *((uintptr_t*)keys + i); + if (!key) + return; + + free_outter_map_entry(ctx, &key); + } +} + +static int get_map_ids(const char *name, unsigned int *id, unsigned int *outter_id, unsigned int *inner_id) +{ + char *ptr = NULL; + char *map_id, *map_in_map_id; + + map_id = (name == NULL) ? getenv("MAP_ID") : getenv(name); + if (!map_id) { + LOG_ERR("%s is not set\n", ((name == NULL) ? "MAP_ID" : name)); + return -EINVAL; + } + + errno = 0; + + *id = (unsigned int)strtol(map_id, &ptr, 10); + if (!ptr[0]) { + map_in_map_id = getenv("OUTTER_MAP_ID"); + if (!map_in_map_id) + return 0; + *outter_id = (unsigned int)strtol(map_in_map_id, &ptr, 10); + } + + if (!ptr[0]) { + map_in_map_id = getenv("INNER_MAP_ID"); + if (!map_in_map_id) { + LOG_ERR("INNER_MAP_ID is not set\n"); + return -EINVAL; + } + *inner_id = (unsigned int)strtol(map_in_map_id, &ptr, 10); + } + return -errno; +} + +static int get_map_fd_info(unsigned int id, int *map_fd, struct bpf_map_info *info) +{ + int ret; + __u32 map_info_len; + + *map_fd = bpf_map_get_fd_by_id(id); + if (*map_fd < 0) + return *map_fd; + + map_info_len = sizeof(*info); + ret = bpf_obj_get_info_by_fd(*map_fd, info, &map_info_len); + return ret; +} + +static int alloc_and_set_inner_map(struct op_context *ctx, int key) +{ + int fd, ret; + struct bpf_map_info *inner_info = ctx->inner_info; + LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = inner_info->map_flags); + + fd = bpf_map_create(inner_info->type, NULL, inner_info->key_size, + inner_info->value_size, inner_info->max_entries, + &opts); + if (fd < 0) + return fd; + + ret = bpf_map_update_elem(ctx->outter_fd, &key, &fd, BPF_ANY); + close(fd); + + return ret; +} + +static int find_free_outter_map_entry(struct op_context *ctx, + struct outter_map_alloc_control *a_ctl) +{ + int index; + unsigned int i; + + for (i = 0; i < FREE_MAP_SIZE; i++) { + if (a_ctl->free_map[i]) { + index = __builtin_ffs(a_ctl->free_map[i]); + a_ctl->free_map[i] &= ~(1U << (index - 1)); + return (index - 1 + (i * 32)); + } + } + + return -ENOENT; +} + +static int free_outter_map_entry(struct op_context *ctx, void *outter_key) +{ + int ret; + int key = 0; + unsigned int i = *(unsigned int*)outter_key; + int inner_map_fd; + __u32 inner_map_id; + struct outter_map_alloc_control *a_ctl; + void *inner_map_object; + + ret = bpf_map_delete_elem(ctx->outter_fd, outter_key); + if (ret) + return ret; + + ret = bpf_map_lookup_elem(ctx->outter_fd, &key, &inner_map_id); + if (ret < 0) + return 0; + + inner_map_fd = bpf_map_get_fd_by_id(inner_map_id); + if (inner_map_fd < 0) + return inner_map_fd; + + inner_map_object = malloc(ctx->inner_info->value_size); + if (!inner_map_object) { + close(inner_map_fd); + return -ENOMEM; + } + + ret = bpf_map_lookup_elem(inner_map_fd, &key, inner_map_object); + if (ret < 0) { + close(inner_map_fd); + free(inner_map_object); + return ret; + } + + a_ctl = (struct outter_map_alloc_control *)inner_map_object; + a_ctl->used--; + a_ctl->free_map[i / 32] |= (1U << (i % 32)); + bpf_map_update_elem(inner_map_fd, &key, a_ctl, BPF_ANY); + free(inner_map_object); + close(inner_map_fd); + + return 0; +} + +static int alloc_outter_map_entry(struct op_context *ctx) +{ + int ret; + unsigned int first = 0; + int key = 0, ret_key; + int inner_map_fd; + __u32 inner_map_id; + struct outter_map_alloc_control *a_ctl; + +retry: + ret = bpf_map_lookup_elem(ctx->outter_fd, &key, &inner_map_id); + if (ret < 0) { + if (-errno != -ENOENT) + return ret; + ret = alloc_and_set_inner_map(ctx, key); + if (ret) + return ret; + + first = 1; + goto retry; + } + + inner_map_fd = bpf_map_get_fd_by_id(inner_map_id); + if (inner_map_fd < 0) + return inner_map_fd; + + ret = bpf_map_lookup_elem(inner_map_fd, &key, ctx->inner_map_object); + if (ret < 0) { + close(inner_map_fd); + return ret; + } + + a_ctl = (struct outter_map_alloc_control *)ctx->inner_map_object; + if (a_ctl->used >= (int)ctx->outter_info->max_entries) { + LOG_ERR("outter map entries has consumed out\n"); + close(inner_map_fd); + return -ENOENT; + } + + if (first) { + memset_s(a_ctl->free_map, sizeof(a_ctl->free_map), 0xff, sizeof(a_ctl->free_map)); + a_ctl->free_map[0] &= ~1U; + } + + ret_key = find_free_outter_map_entry(ctx, a_ctl); + if (ret_key > 0) { + ret = alloc_and_set_inner_map(ctx, ret_key); + if (ret) { + close(inner_map_fd); + return ret; + } + + a_ctl->used += first + 1; + bpf_map_update_elem(inner_map_fd, &key, a_ctl, BPF_ANY); + } + + close(inner_map_fd); + return ret_key; +} + +static int outter_key_to_inner_fd(struct op_context *ctx, unsigned int key) +{ + int ret; + __u32 inner_map_id; + + ret = bpf_map_lookup_elem(ctx->outter_fd, &key, &inner_map_id); + if (ret < 0) + return ret; + + return bpf_map_get_fd_by_id(inner_map_id); +} + +static int copy_sfield_to_map(struct op_context *ctx, int o_index, + const ProtobufCFieldDescriptor *field) +{ + int ret; + int key = 0; + int inner_fd; + char **value = (char**)((char*)ctx->value + field->offset); + char *save_value = *value; + + *(uintptr_t *)value = (size_t)o_index; + ret = bpf_map_update_elem(ctx->curr_fd, ctx->key, ctx->value, BPF_ANY); + if (ret) { + free_outter_map_entry(ctx, &o_index); + return ret; + } + + inner_fd = outter_key_to_inner_fd(ctx, o_index); + if (inner_fd < 0) + return inner_fd; + + strcpy_s(ctx->inner_map_object, ctx->inner_info->value_size, save_value); + ret = bpf_map_update_elem(inner_fd, &key, ctx->inner_map_object, BPF_ANY); + close(inner_fd); + return ret; +} + +static int copy_msg_field_to_map(struct op_context *ctx, int o_index, + const ProtobufCFieldDescriptor *field) +{ + int ret; + int key = 0; + int inner_fd; + void **value = (void**)((char*)ctx->value + field->offset); + void *msg = *value; + struct op_context new_ctx; + const ProtobufCMessageDescriptor *desc; + + *(uintptr_t*)value = (size_t)o_index; + ret = bpf_map_update_elem(ctx->curr_fd, ctx->key, ctx->value, BPF_ANY); + if (ret) { + free_outter_map_entry(ctx, &o_index); + return ret; + } + + inner_fd = outter_key_to_inner_fd(ctx, o_index); + if (inner_fd < 0) + return inner_fd; + + memcpy_s(&new_ctx, sizeof(new_ctx), ctx, sizeof(*ctx)); + + new_ctx.curr_fd = inner_fd; + new_ctx.key = (void*)&key; + new_ctx.value = msg; + new_ctx.curr_info = ctx->inner_info; + + desc = ((ProtobufCMessage *)new_ctx.value)->descriptor; + if (!desc || desc->magic != PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) { + close(inner_fd); + return -EINVAL; + } + + new_ctx.desc = desc; + + ret = update_bpf_map(&new_ctx); + close(inner_fd); + return ret; +} + +static int field_handle(struct op_context *ctx, + const ProtobufCFieldDescriptor *field) +{ + int key = 0; + + if (field->type == PROTOBUF_C_TYPE_MESSAGE || + field->type == PROTOBUF_C_TYPE_STRING) { + key = alloc_outter_map_entry(ctx); + if (key < 0) + return key; + } + + switch (field->type) { + case PROTOBUF_C_TYPE_MESSAGE: + return copy_msg_field_to_map(ctx, key, field); + case PROTOBUF_C_TYPE_STRING: + return copy_sfield_to_map(ctx, key, field); + default: + break; + } + + return 0; +} + +static int copy_indirect_data_to_map(struct op_context *ctx, int outter_key, + void *value, ProtobufCType type) +{ + int ret = 0; + int inner_fd, key = 0; + struct op_context new_ctx; + const ProtobufCMessageDescriptor *desc; + + inner_fd = outter_key_to_inner_fd(ctx, outter_key); + if (inner_fd < 0) + return inner_fd; + + switch (type) { + case PROTOBUF_C_TYPE_MESSAGE: + memcpy_s(&new_ctx, sizeof(new_ctx), ctx, sizeof(*ctx)); + new_ctx.curr_fd = inner_fd; + new_ctx.key = (void*)&key; + new_ctx.value = value; + new_ctx.curr_info = ctx->inner_info; + + desc = ((ProtobufCMessage *)value)->descriptor; + if (!desc || desc->magic != PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) { + close(inner_fd); + return -EINVAL; + } + + new_ctx.desc = desc; + ret = update_bpf_map(&new_ctx); + break; + case PROTOBUF_C_TYPE_STRING: + strcpy_s(ctx->inner_map_object, ctx->inner_info->value_size, (char*)value); + ret = bpf_map_update_elem(inner_fd, &key, + ctx->inner_map_object, BPF_ANY); + break; + default: + break; + } + + close(inner_fd); + return ret; +} + +static bool indirect_data_type(ProtobufCType type) +{ + switch (type) { + case PROTOBUF_C_TYPE_MESSAGE: + case PROTOBUF_C_TYPE_STRING: + return true; + default: + return false; + } +} + +static int repeat_field_handle(struct op_context *ctx, + const ProtobufCFieldDescriptor *field) +{ + int ret, ret1; + unsigned int i; + int outter_key, inner_fd, key = 0; + void *n = ((char*)ctx->value) + field->quantifier_offset; + void ***value = (void***)((char*)ctx->value + field->offset); + void **origin_value = *value; + char *inner_map_object; + + outter_key = alloc_outter_map_entry(ctx); + if (outter_key < 0) + return outter_key; + + *(uintptr_t*)value = (size_t)outter_key; + ret = bpf_map_update_elem(ctx->curr_fd, ctx->key, ctx->value, BPF_ANY); + if (ret) { + free_outter_map_entry(ctx, &outter_key); + return ret; + } + + inner_fd = outter_key_to_inner_fd(ctx, outter_key); + if (inner_fd < 0) + return inner_fd; + + inner_map_object = calloc(1, ctx->inner_info->value_size); + if (!inner_map_object) { + close(inner_fd); + return -ENOMEM; + } + + switch (field->type) { + case PROTOBUF_C_TYPE_MESSAGE: + case PROTOBUF_C_TYPE_STRING: + for (i = 0; i < *(unsigned int*)n; i++) { + outter_key = alloc_outter_map_entry(ctx); + if (outter_key < 0) + goto end; + + *((uintptr_t*)inner_map_object + i) = (size_t)outter_key; + ret = copy_indirect_data_to_map(ctx, outter_key, + origin_value[i], field->type); + if (ret) + goto end; + } + break; + default: + memcpy_s(inner_map_object, ctx->inner_info->value_size, (void*)origin_value, + *(size_t*)n * sizeof_elt_in_repeated_array(field->type)); + break; + } + +end: + ret1 = bpf_map_update_elem(inner_fd, &key, inner_map_object, BPF_ANY); + if (ret1) { + ret = ret1; + if (indirect_data_type(field->type)) + free_keys(ctx, inner_map_object, *(size_t*)n); + } + + free(inner_map_object); + close(inner_fd); + + return ret; +} + +static int update_bpf_map(struct op_context *ctx) +{ + int ret; + unsigned int i; + void *temp_val; + const ProtobufCMessageDescriptor *desc = ctx->desc; + + if (desc->sizeof_message > ctx->curr_info->value_size) { + LOG_ERR("map entry size is too small\n"); + return -EINVAL; + } + + temp_val = malloc(ctx->curr_info->value_size); + if (!temp_val) + return -ENOMEM; + + memcpy_s(temp_val, ctx->curr_info->value_size, ctx->value, ctx->curr_info->value_size); + ctx->value = temp_val; + + for (i = 0; i < desc->n_fields; i++) { + const ProtobufCFieldDescriptor *field = desc->fields + i; + + if (!selected_oneof_field(ctx->value, field) || + !valid_field_value(ctx->value, field)) + continue; + + switch (field->label) { + case PROTOBUF_C_LABEL_REPEATED: + ret = repeat_field_handle(ctx, field); + break; + default: + ret = field_handle(ctx, field); + break; + } + + if (ret) { + LOG_INFO("field[%d] handle fail\n", i); + free(temp_val); + return ret; + } + } + + ret = bpf_map_update_elem(ctx->curr_fd, ctx->key, ctx->value, BPF_ANY); + free(temp_val); + return ret; +} + +static int map_info_check(struct bpf_map_info *outter_info, + struct bpf_map_info *inner_info) +{ + if (outter_info->type != BPF_MAP_TYPE_ARRAY_OF_MAPS) { + LOG_ERR("outter map type must be BPF_MAP_TYPE_ARRAY_OF_MAPS\n"); + return -EINVAL; + } + + if (outter_info->max_entries < 2 || + outter_info->max_entries > MAX_OUTTER_MAP_ENTRIES) { + LOG_ERR("outter map max_entries must be in[2,%d]\n", + MAX_OUTTER_MAP_ENTRIES); + return -EINVAL; + } + + if (inner_info->value_size < sizeof(struct outter_map_alloc_control)) { + LOG_ERR("inner map value_size must be large than %lu(bytes)\n", + sizeof(struct outter_map_alloc_control)); + return -EINVAL; + } + + return 0; +} + +int deserial_update_elem(void *key, void *value) +{ + int ret; + const char *map_name = NULL; + struct op_context context = {.inner_map_object = NULL}; + const ProtobufCMessageDescriptor *desc; + struct bpf_map_info outter_info, inner_info, info; + int map_fd, outter_fd = 0, inner_fd = 0; + unsigned int id, outter_id = 0, inner_id = 0; + + if (!key || !value) + return -EINVAL; + + desc = ((ProtobufCMessage *)value)->descriptor; + if (desc && desc->magic == PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) + map_name = desc->short_name; + + ret = get_map_ids(map_name, &id, &outter_id, &inner_id); + if (ret) + return ret; + + ret = get_map_fd_info(id, &map_fd, &info); + if (ret < 0) { + LOG_ERR("invlid MAP_ID: %d\n", id); + return ret; + } + + if (!map_name) { + ret = bpf_map_update_elem(map_fd, key, value, BPF_ANY); + goto end; + } + + ret = get_map_fd_info(inner_id, &inner_fd, &inner_info); + ret |= get_map_fd_info(outter_id, &outter_fd, &outter_info); + if (ret < 0 || map_info_check(&outter_info, &inner_info)) + goto end; + + deserial_delete_elem(key, desc); + + init_op_context(context, key, value, desc, outter_fd, map_fd, + &outter_info, &inner_info, &info); + + context.inner_map_object = calloc(1, context.inner_info->value_size); + if (context.inner_map_object == NULL) { + ret = -errno; + goto end; + } + + normalize_key(&context, key, map_name); + + ret = update_bpf_map(&context); + if (ret) + deserial_delete_elem(key, desc); + +end: + if (context.key != NULL) + free(context.key); + if (context.inner_map_object != NULL) + free(context.inner_map_object); + if (map_fd > 0) + close(map_fd); + if (outter_fd > 0) + close(outter_fd); + if (inner_fd > 0) + close(inner_fd); + return ret; +} + +static int query_string_field(struct op_context *ctx, + const ProtobufCFieldDescriptor *field) +{ + int key = 0, ret; + int inner_fd; + void *string; + void *outter_key = (void*)((char*)ctx->value + field->offset); + + inner_fd = outter_key_to_inner_fd(ctx, *(int*)outter_key); + if (inner_fd < 0) + return inner_fd; + + string = malloc(ctx->inner_info->value_size); + if (!string) { + close(inner_fd); + return -ENOMEM; + } + + (*(uintptr_t *)outter_key) = (uintptr_t)string; + + ret = bpf_map_lookup_elem(inner_fd, &key, string); + close(inner_fd); + return ret; +} + +static int query_message_field(struct op_context *ctx, + const ProtobufCFieldDescriptor *field) +{ + int ret; + int key = 0; + int inner_fd; + void *message; + struct op_context new_ctx; + const ProtobufCMessageDescriptor *desc; + uintptr_t *outter_key = (uintptr_t *)((char*)ctx->value + field->offset); + + inner_fd = outter_key_to_inner_fd(ctx, *outter_key); + if (inner_fd < 0) + return inner_fd; + + memcpy_s(&new_ctx, sizeof(new_ctx), ctx, sizeof(*ctx)); + new_ctx.curr_fd = inner_fd; + new_ctx.key = (void*)&key; + new_ctx.curr_info = ctx->inner_info; + + desc = (ProtobufCMessageDescriptor*)field->descriptor; + if (!desc || desc->magic != PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) { + close(inner_fd); + return -EINVAL; + } + + new_ctx.desc = desc; + + message = create_struct(&new_ctx, &ret); + *outter_key = (uintptr_t)message; + close(inner_fd); + return ret; +} + +static int field_query(struct op_context *ctx, + const ProtobufCFieldDescriptor *field) +{ + switch (field->type) { + case PROTOBUF_C_TYPE_MESSAGE: + return query_message_field(ctx, field); + case PROTOBUF_C_TYPE_STRING: + return query_string_field(ctx, field); + default: + break; + } + + return 0; +} + +static void* create_indirect_struct(struct op_context *ctx, unsigned long outter_key, + const ProtobufCFieldDescriptor *field, + int *err) +{ + int inner_fd, key = 0; + void *value; + struct op_context new_ctx; + const ProtobufCMessageDescriptor *desc; + + inner_fd = outter_key_to_inner_fd(ctx, outter_key); + if (inner_fd < 0) { + *err = inner_fd; + return NULL; + } + + switch (field->type) { + case PROTOBUF_C_TYPE_MESSAGE: + memcpy_s(&new_ctx, sizeof(new_ctx), ctx, sizeof(*ctx)); + new_ctx.curr_fd = inner_fd; + new_ctx.key = (void*)&key; + new_ctx.curr_info = ctx->inner_info; + + desc = (ProtobufCMessageDescriptor*)field->descriptor; + if (!desc || desc->magic != PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) { + *err = -EINVAL; + close(inner_fd); + return NULL; + } + + new_ctx.desc = desc; + value = create_struct(&new_ctx, err); + close(inner_fd); + return value; + default: + value = malloc(ctx->inner_info->value_size); + if (!value) { + *err = -ENOMEM; + close(inner_fd); + return NULL; + } + + *err = bpf_map_lookup_elem(inner_fd, &key, value); + if (*err < 0) { + close(inner_fd); + return value; + } + + break; + } + + close(inner_fd); + *err = 0; + return value; +} + +static int repeat_field_query(struct op_context *ctx, + const ProtobufCFieldDescriptor *field) +{ + int ret; + int key = 0; + int inner_fd; + void *array; + unsigned int i; + void *n = ((char*)ctx->value) + field->quantifier_offset; + uintptr_t *outter_key = (uintptr_t*)((char*)ctx->value + field->offset); + + inner_fd = outter_key_to_inner_fd(ctx, *outter_key); + if (inner_fd < 0) + return inner_fd; + + array = calloc(1, ctx->inner_info->value_size); + if (!array) { + close(inner_fd); + return -ENOMEM; + } + + *outter_key = (uintptr_t)array; + ret = bpf_map_lookup_elem(inner_fd, &key, array); + if (ret < 0) { + close(inner_fd); + return ret; + } + + switch (field->type) { + case PROTOBUF_C_TYPE_MESSAGE: + case PROTOBUF_C_TYPE_STRING: + for (i = 0; i < *(unsigned int*)n; i++) { + outter_key = (uintptr_t*)array + i; + *outter_key = (uintptr_t)create_indirect_struct(ctx, + *outter_key, field, &ret); + if (ret) + break; + } + break; + default: + break; + } + + close(inner_fd); + return ret; +} + +static void* create_struct(struct op_context *ctx, int *err) +{ + void *value; + int ret; + unsigned int i; + const ProtobufCMessageDescriptor *desc = ctx->desc; + + *err = 0; + + if (desc->sizeof_message > ctx->curr_info->value_size) { + LOG_ERR("map entry size is too small\n"); + return NULL; + } + + value = calloc(1, ctx->curr_info->value_size); + if (!value) + return value; + + ret = bpf_map_lookup_elem(ctx->curr_fd, ctx->key, value); + if (ret < 0) { + free(value); + return NULL; + } + + ctx->value = value; + for (i = 0; i < desc->n_fields; i++) { + const ProtobufCFieldDescriptor *field = desc->fields + i; + + if (!selected_oneof_field(ctx->value, field) || + !valid_field_value(ctx->value, field)) + continue; + + switch (field->label) { + case PROTOBUF_C_LABEL_REPEATED: + ret = repeat_field_query(ctx, field); + break; + default: + ret = field_query(ctx, field); + break; + } + + if (ret) { + LOG_INFO("field[%d] query fail\n", i); + *err = 1; + return value; + } + } + + return value; +} + +void* deserial_lookup_elem(void *key, const void *msg_desciptor) +{ + int ret, err; + void *value = NULL; + const char *map_name = NULL; + struct op_context context = {.inner_map_object = NULL}; + const ProtobufCMessageDescriptor *desc; + struct bpf_map_info outter_info, inner_info, info; + int map_fd, outter_fd = 0, inner_fd = 0; + unsigned int id, outter_id = 0, inner_id = 0; + + if (msg_desciptor == NULL || key == NULL) + return NULL; + + desc = (ProtobufCMessageDescriptor*)msg_desciptor; + if (desc->magic != PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) + return NULL; + + map_name = desc->short_name; + ret = get_map_ids(map_name, &id, &outter_id, &inner_id); + if (ret) + return NULL; + + ret = get_map_fd_info(id, &map_fd, &info); + if (ret < 0) { + LOG_ERR("invlid MAP_ID: %d\n", id); + return NULL; + } + + ret = get_map_fd_info(inner_id, &inner_fd, &inner_info); + ret |= get_map_fd_info(outter_id, &outter_fd, &outter_info); + if (ret < 0 || map_info_check(&outter_info, &inner_info)) + goto end; + + init_op_context(context, key, NULL, desc, outter_fd, map_fd, + &outter_info, &inner_info, &info); + + normalize_key(&context, key, map_name); + value = create_struct(&context, &err); + if (err != 0) { + deserial_free_elem(value); + value = NULL; + } + +end: + if (context.key != NULL) + free(context.key); + if (map_fd > 0) + close(map_fd); + if (outter_fd > 0) + close(outter_fd); + if (inner_fd > 0) + close(inner_fd); + return value; +} + +static int indirect_field_del(struct op_context *ctx, unsigned int outter_key, + const ProtobufCFieldDescriptor *field) +{ + char *inner_map_object = NULL; + int inner_fd, key = 0; + struct op_context new_ctx; + const ProtobufCMessageDescriptor *desc; + + if (!valid_outter_key(ctx, outter_key)) + return -EINVAL; + + inner_fd = outter_key_to_inner_fd(ctx, (unsigned long)outter_key); + if (inner_fd < 0) + return inner_fd; + + free_outter_map_entry(ctx, &outter_key); + + switch (field->type) { + case PROTOBUF_C_TYPE_MESSAGE: + desc = (ProtobufCMessageDescriptor*)field->descriptor; + if (!desc || desc->magic != PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) { + close(inner_fd); + return -EINVAL; + } + + inner_map_object = malloc(ctx->inner_info->value_size); + if (!inner_map_object) { + close(inner_fd); + return -ENOMEM; + } + + memcpy_s(&new_ctx, sizeof(new_ctx), ctx, sizeof(*ctx)); + new_ctx.curr_fd = inner_fd; + new_ctx.key = (void*)&key; + new_ctx.curr_info = ctx->inner_info; + new_ctx.value = inner_map_object; + new_ctx.desc = desc; + + (void)del_bpf_map(&new_ctx, 1); + free(inner_map_object); + break; + + default: + break; + } + + close(inner_fd); + return 0; +} + +static int repeat_field_del(struct op_context *ctx, + const ProtobufCFieldDescriptor *field) +{ + int ret; + unsigned int i; + int inner_fd, key = 0; + void *inner_map_object = NULL; + void *n; + uintptr_t *outter_key; + + ret = bpf_map_lookup_elem(ctx->curr_fd, ctx->key, ctx->value); + if (ret < 0) { + LOG_WARN("faild to find map(%d) elem: %d.", ctx->curr_fd, ret); + return ret; + } + + outter_key = (uintptr_t*)((char*)ctx->value + field->offset); + if (!valid_outter_key(ctx, *outter_key)) + return -EINVAL; + + inner_fd = outter_key_to_inner_fd(ctx, *outter_key); + if (inner_fd < 0) + return inner_fd; + + ret = free_outter_map_entry(ctx, outter_key); + if (ret) + return ret; + + n = ((char*)ctx->value) + field->quantifier_offset; + + switch (field->type) { + case PROTOBUF_C_TYPE_MESSAGE: + //lint -fallthrough + case PROTOBUF_C_TYPE_STRING: + inner_map_object = calloc(1, ctx->inner_info->value_size); + if (!inner_map_object) { + ret = -ENOMEM; + goto end; + } + + ret = bpf_map_lookup_elem(inner_fd, &key, inner_map_object); + if (ret < 0) + goto end; + + for (i = 0; i < *(size_t*)n; i++) { + outter_key = (uintptr_t*)inner_map_object + i; + indirect_field_del(ctx, *outter_key, field); + } + default: + break; + } + +end: + if (inner_map_object != NULL) + free(inner_map_object); + close(inner_fd); + return ret; +} + +static int msg_field_del(struct op_context *ctx, int inner_fd, + const ProtobufCFieldDescriptor *field) +{ + int key = 0; + int ret; + char *inner_map_object = NULL; + struct op_context new_ctx; + const ProtobufCMessageDescriptor *desc; + + desc = (ProtobufCMessageDescriptor*)field->descriptor; + if (!desc || desc->magic != PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) + return -EINVAL; + + inner_map_object = malloc(ctx->inner_info->value_size); + if (!inner_map_object) + return -ENOMEM; + + memcpy_s(&new_ctx, sizeof(new_ctx), ctx, sizeof(*ctx)); + new_ctx.curr_fd = inner_fd; + new_ctx.key = (void*)&key; + new_ctx.curr_info = ctx->inner_info; + new_ctx.value = inner_map_object; + new_ctx.desc = desc; + + ret = del_bpf_map(&new_ctx, 1); + free(inner_map_object); + return ret; +} + +static int field_del(struct op_context *ctx, + const ProtobufCFieldDescriptor *field) +{ + int ret; + int inner_fd; + uintptr_t *outter_key; + + switch (field->type) { + case PROTOBUF_C_TYPE_MESSAGE: + case PROTOBUF_C_TYPE_STRING: + ret = bpf_map_lookup_elem(ctx->curr_fd, ctx->key, ctx->value); + if (ret < 0) + return ret; + + outter_key = (uintptr_t*)((char*)ctx->value + field->offset); + if (!valid_outter_key(ctx, *outter_key)) + return -EINVAL; + + inner_fd = outter_key_to_inner_fd(ctx, *outter_key); + if (inner_fd < 0) + return inner_fd; + + free_outter_map_entry(ctx, outter_key); + + if (field->type == PROTOBUF_C_TYPE_STRING) { + close(inner_fd); + break; + } + + msg_field_del(ctx, inner_fd, field); + close(inner_fd); + break; + default: + break; + } + + return 0; +} + +static int del_bpf_map(struct op_context *ctx, int is_inner) +{ + int ret; + unsigned int i; + const ProtobufCMessageDescriptor *desc = ctx->desc; + + ret = bpf_map_lookup_elem(ctx->curr_fd, ctx->key, ctx->value); + if (ret < 0) + return ret; + + for (i = 0; i < desc->n_fields; i++) { + const ProtobufCFieldDescriptor *field = desc->fields + i; + + if (!selected_oneof_field(ctx->value, field) || + !valid_field_value(ctx->value, field)) + continue; + + switch (field->label) { + case PROTOBUF_C_LABEL_REPEATED: + ret = repeat_field_del(ctx, field); + if (ret) + goto end; + break; + default: + ret = field_del(ctx, field); + if (ret) + goto end; + break; + } + } + +end: + return (is_inner == 1) ? close(ctx->curr_fd) : + bpf_map_delete_elem(ctx->curr_fd, ctx->key); +} + +int deserial_delete_elem(void *key, const void *msg_desciptor) +{ + int ret; + const char *map_name = NULL; + struct op_context context = {.inner_map_object = NULL}; + const ProtobufCMessageDescriptor *desc; + struct bpf_map_info outter_info, inner_info, info; + int map_fd, outter_fd = 0, inner_fd = 0; + unsigned int id, outter_id = 0, inner_id = 0; + char *inner_map_object = NULL; + + if (!key || !msg_desciptor) + return -EINVAL; + + desc = (ProtobufCMessageDescriptor *)msg_desciptor; + if (desc->magic == PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) + map_name = desc->short_name; + + ret = get_map_ids(map_name, &id, &outter_id, &inner_id); + if (ret) + return ret; + + ret = get_map_fd_info(id, &map_fd, &info); + if (ret < 0) { + LOG_ERR("invlid MAP_ID: %d\n", id); + return ret; + } + + if (!map_name) { + ret = bpf_map_delete_elem(map_fd, key); + goto end; + } + + ret = get_map_fd_info(inner_id, &inner_fd, &inner_info); + ret |= get_map_fd_info(outter_id, &outter_fd, &outter_info); + if (ret < 0 || map_info_check(&outter_info, &inner_info)) + goto end; + + init_op_context(context, key, NULL, desc, outter_fd, map_fd, + &outter_info, &inner_info, &info); + + context.inner_map_object = calloc(1, context.inner_info->value_size); + context.value = calloc(1, context.curr_info->value_size); + if (!context.inner_map_object || !context.value) { + ret = -errno; + goto end; + } + + inner_map_object = context.inner_map_object; + + normalize_key(&context, key, map_name); + ret = del_bpf_map(&context, 0); + +end: + if (context.key != NULL) + free(context.key); + if (context.value != NULL) + free(context.value); + if (inner_map_object != NULL) + free(inner_map_object); + if (map_fd > 0) + close(map_fd); + if (outter_fd > 0) + close(outter_fd); + if (inner_fd > 0) + close(inner_fd); + return ret; +} + + +static void repeat_field_free(void *value, + const ProtobufCFieldDescriptor *field) +{ + unsigned int i; + void *n = ((char*)value) + field->quantifier_offset; + uintptr_t *ptr_array = *(uintptr_t**)((char*)value + field->offset); + + switch (field->type) { + case PROTOBUF_C_TYPE_MESSAGE: + case PROTOBUF_C_TYPE_STRING: + for (i = 0; i < *(unsigned int*)n; i++) { + if (field->type == PROTOBUF_C_TYPE_STRING) + free_elem((void*)ptr_array[i]); + else + deserial_free_elem((void*)ptr_array[i]); + } + break; + default: + free_elem((void*)ptr_array); + break; + } + + return; +} + +static void field_free(void *value, + const ProtobufCFieldDescriptor *field) +{ + uintptr_t *tobe_free = (uintptr_t *)((char*)value + field->offset); + + switch (field->type) { + case PROTOBUF_C_TYPE_MESSAGE: + deserial_free_elem((void*)(*tobe_free)); + break; + case PROTOBUF_C_TYPE_STRING: + free_elem((void*)*tobe_free); + break; + default: + break; + } + + return; +} + +void deserial_free_elem(void *value) +{ + unsigned int i; + const char *map_name = NULL; + const ProtobufCMessageDescriptor *desc; + + if (!value || (uintptr_t)value < MAX_OUTTER_MAP_ENTRIES) + return; + + desc = ((ProtobufCMessage *)value)->descriptor; + if (desc && desc->magic == PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) + map_name = desc->short_name; + + if (!map_name) { + LOG_ERR("map_name is NULL"); + free_elem(value); + return; + } + + for (i = 0; i < desc->n_fields; i++) { + const ProtobufCFieldDescriptor *field = desc->fields + i; + + if (!selected_oneof_field(value, field) || + !valid_field_value(value, field)) + continue; + + switch (field->label) { + case PROTOBUF_C_LABEL_REPEATED: + repeat_field_free(value, field); + break; + default: + field_free(value, field); + break; + } + } + + free_elem(value); + return; +} + +// Update function for map_of_break_count +int deserial_update_map_of_break_count_elem(void *key, void *value) { + unsigned int id; + char *map_name = "map_of_break_count"; + int ret; + struct bpf_map_info info; + int map_fd; + + ret = get_map_ids(map_name, &id, NULL, NULL); + if (ret) + return ret; + + ret = get_map_fd_info(id, &map_fd, &info); + if (ret < 0) { + LOG_ERR("invalid MAP_ID: %d\n", id); + return ret; + } + + ret = bpf_map_update_elem(map_fd, key, value, BPF_ANY); + if (ret) + LOG_ERR("update MAP: %s failed\n", map_name); + close(map_fd); + return ret; +} + +// Delete function for map_of_break_count +int deserial_delete_map_of_break_count_elem(void *key) { + unsigned int id; + char *map_name = "map_of_break_count"; + int ret; + struct bpf_map_info info; + int map_fd; + + ret = get_map_ids(map_name, &id, NULL, NULL); + if (ret) + return ret; + + ret = get_map_fd_info(id, &map_fd, &info); + if (ret < 0) { + LOG_ERR("invalid MAP_ID: %d\n", id); + return ret; + } + + ret = bpf_map_delete_elem(map_fd, key); + if (ret) + LOG_ERR("delete MAP: %s failed\n", map_name); + close(map_fd); + return ret; +} + +// Update function for map_of_is_break +int deserial_update_map_of_is_break_elem(void *key, void *value) { + unsigned int id; + char *map_name = "map_of_is_break"; + int ret; + struct bpf_map_info info; + int map_fd; + + ret = get_map_ids(map_name, &id, NULL, NULL); + if (ret) + return ret; + + ret = get_map_fd_info(id, &map_fd, &info); + if (ret < 0) { + LOG_ERR("invalid MAP_ID: %d\n", id); + return ret; + } + + ret = bpf_map_update_elem(map_fd, key, value, BPF_ANY); + if (ret) + LOG_ERR("update MAP: %s failed\n", map_name); + close(map_fd); + return ret; +} + +// Delete function for map_of_is_break +int deserial_delete_map_of_is_break_elem(void *key) { + unsigned int id; + char *map_name = "map_of_is_break"; + int ret; + struct bpf_map_info info; + int map_fd; + + ret = get_map_ids(map_name, &id, NULL, NULL); + if (ret) + return ret; + + ret = get_map_fd_info(id, &map_fd, &info); + if (ret < 0) { + LOG_ERR("invalid MAP_ID: %d\n", id); + return ret; + } + + ret = bpf_map_delete_elem(map_fd, key); + if (ret) + LOG_ERR("delete MAP: %s failed\n", map_name); + close(map_fd); + return ret; +} + +// Update function for map_of_break +int deserial_update_map_of_break_elem(void *key, void *value) { + unsigned int id; + char *map_name = "map_of_break"; + int ret; + struct bpf_map_info info; + int map_fd; + + ret = get_map_ids(map_name, &id, NULL, NULL); + if (ret) + return ret; + + ret = get_map_fd_info(id, &map_fd, &info); + if (ret < 0) { + LOG_ERR("invalid MAP_ID: %d\n", id); + return ret; + } + + ret = bpf_map_update_elem(map_fd, key, value, BPF_ANY); + if (ret) + LOG_ERR("update MAP: %s failed\n", map_name); + close(map_fd); + return ret; +} + +// Delete function for map_of_break +int deserial_delete_map_of_break_elem(void *key) { + unsigned int id; + char *map_name = "map_of_break"; + int ret; + struct bpf_map_info info; + int map_fd; + + ret = get_map_ids(map_name, &id, NULL, NULL); + if (ret) + return ret; + + ret = get_map_fd_info(id, &map_fd, &info); + if (ret < 0) { + LOG_ERR("invalid MAP_ID: %d\n", id); + return ret; + } + + ret = bpf_map_delete_elem(map_fd, key); + if (ret) + LOG_ERR("delete MAP: %s failed\n", map_name); + close(map_fd); + return ret; +} \ No newline at end of file diff --git a/ospp-kmesh-break/bpf/deserialization_to_bpf_map/deserialization_to_bpf_map.h b/ospp-kmesh-break/bpf/deserialization_to_bpf_map/deserialization_to_bpf_map.h new file mode 100644 index 0000000000000000000000000000000000000000..8d6ae39091d5444df3eb06b1b7e0c55a04a6605b --- /dev/null +++ b/ospp-kmesh-break/bpf/deserialization_to_bpf_map/deserialization_to_bpf_map.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +#ifndef __DESERIALIZATION_TO_BPF_MAP_H__ +#define __DESERIALIZATION_TO_BPF_MAP_H__ + +#define MAX_OUTTER_MAP_ENTRIES (10000) + +int deserial_update_elem(void *key, void *value); +void* deserial_lookup_elem(void *key, const void *msg_desciptor); +void deserial_free_elem(void *value); +int deserial_delete_elem(void *key, const void *msg_desciptor); + + +int deserial_update_map_of_break_count_elem(void *key, void *value); +int deserial_delete_map_of_break_count_elem(void *key); +int deserial_update_map_of_is_break_elem(void *key, void *value); +int deserial_delete_map_of_is_break_elem(void *key); +int deserial_update_map_of_break_elem(void *key, void *value); +int deserial_delete_map_of_break_elem(void *key); + +#endif /* __DESERIALIZATION_TO_BPF_MAP_H__ */ diff --git a/ospp-kmesh-break/bpf/kmesh/cgroup_sock.c b/ospp-kmesh-break/bpf/kmesh/cgroup_sock.c new file mode 100644 index 0000000000000000000000000000000000000000..a8c854fe2b24cc8937378d673072ac53dd8779a1 --- /dev/null +++ b/ospp-kmesh-break/bpf/kmesh/cgroup_sock.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + * Author: nlgwcy + * Create: 2022-02-14 + */ + +#include +#include +#include +#include "bpf_log.h" +#include "listener.h" +#include "listener/listener.pb-c.h" +#if KMESH_ENABLE_IPV4 +#if KMESH_ENABLE_HTTP + +static const char kmesh_module_name[] = "kmesh_defer"; +#ifdef DECLARE_VAR_ADDRESS +#undef DECLARE_VAR_ADDRESS +#define DECLARE_VAR_ADDRESS(ctx, name) \ + address_t name = {0}; \ + name.ipv4 = (ctx)->user_ip4; \ + name.port = (ctx)->user_port; \ + name.protocol = ((ctx)->protocol == IPPROTO_TCP) ? \ + CORE__SOCKET_ADDRESS__PROTOCOL__TCP: CORE__SOCKET_ADDRESS__PROTOCOL__UDP +#endif + +static inline int sock4_traffic_control(struct bpf_sock_addr *ctx) +{ + int ret; + __u64 *count_ptr; + __u64 new_count; + __u64 *is_limit_ptr; + + __u64 key = 'is_limit'; + + + Listener__Listener *listener = NULL; + + DECLARE_VAR_ADDRESS(ctx, address); + + listener = map_lookup_listener(&address); + if (listener == NULL) { + address.ipv4 = 0; + listener = map_lookup_listener(&address); + if (!listener) + return -ENOENT; + } + + count_ptr = map_lookup_count(&address); + if (count_ptr) { + new_count = *count_ptr + 1; + } else { + new_count = 1; + } + ret = map_update_count(&address, &new_count); + if (ret != 0) { + BPF_LOG(ERR, KMESH, "Failed to update count, ret %d\n", ret); + } + +#if KMESH_ENABLE_HTTP + // defer conn + ret = bpf_setsockopt(ctx, IPPROTO_TCP, TCP_ULP, (void *)kmesh_module_name, sizeof(kmesh_module_name)); + if (ret) + BPF_LOG(ERR, KMESH, "bpf set sockopt failed! ret:%d\n", ret); +#else // KMESH_ENABLE_HTTP + ret = l4_listener_manager(ctx, lisdemotener); + if (ret != 0) { + BPF_LOG(ERR, KMESH, "listener_manager failed, ret %d\n", ret); + return ret; + } +#endif // KMESH_ENABLE_HTTP + + return 0; +} + +SEC("cgroup/connect4") +int cgroup_connect4_prog(struct bpf_sock_addr *ctx) +{ + int ret = sock4_traffic_control(ctx); + return CGROUP_SOCK_OK; +} + +#endif // KMESH_ENABLE_TCP +#endif // KMESH_ENABLE_IPV4 + +char _license[] SEC("license") = "GPL"; +int _version SEC("version") = 1; diff --git a/ospp-kmesh-break/bpf/kmesh/include/config.h b/ospp-kmesh-break/bpf/kmesh/include/config.h new file mode 100644 index 0000000000000000000000000000000000000000..13777442c6b2e6005edfe43dac3b05873b433b59 --- /dev/null +++ b/ospp-kmesh-break/bpf/kmesh/include/config.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + * Author: nlgwcy + * Create: 2022-02-17 + */ + +#ifndef _KMESH_CONFIG_H_ +#define _KMESH_CONFIG_H_ + +// ************ +// options +#define KMESH_MODULE_ON 1 +#define KMESH_MODULE_OFF 0 + +// L3 +#define KMESH_ENABLE_IPV4 KMESH_MODULE_ON +#define KMESH_ENABLE_IPV6 KMESH_MODULE_OFF +// L4 +#define KMESH_ENABLE_TCP KMESH_MODULE_ON +#define KMESH_ENABLE_UDP KMESH_MODULE_OFF +// L7 +#define KMESH_ENABLE_HTTP KMESH_MODULE_ON +#define KMESH_ENABLE_HTTPS KMESH_MODULE_OFF + + +// ************ +// map size +#define MAP_SIZE_OF_PER_LISTENER 64 +#define MAP_SIZE_OF_PER_FILTER_CHAIN 4 +#define MAP_SIZE_OF_PER_FILTER 4 +#define MAP_SIZE_OF_PER_VIRTUAL_HOST 16 +#define MAP_SIZE_OF_PER_ROUTE 8 +#define MAP_SIZE_OF_PER_CLUSTER 32 +#define MAP_SIZE_OF_PER_ENDPOINT 64 + +#define MAP_SIZE_OF_MAX 8192 + +#define MAP_SIZE_OF_LISTENER \ + BPF_MIN(MAP_SIZE_OF_MAX, MAP_SIZE_OF_PER_LISTENER) +#define MAP_SIZE_OF_FILTER_CHAIN \ + BPF_MIN(MAP_SIZE_OF_MAX, MAP_SIZE_OF_PER_FILTER_CHAIN * MAP_SIZE_OF_LISTENER) +#define MAP_SIZE_OF_FILTER \ + BPF_MIN(MAP_SIZE_OF_MAX, MAP_SIZE_OF_PER_FILTER * MAP_SIZE_OF_FILTER_CHAIN) +#define MAP_SIZE_OF_VIRTUAL_HOST \ + BPF_MIN(MAP_SIZE_OF_MAX, MAP_SIZE_OF_PER_VIRTUAL_HOST * MAP_SIZE_OF_FILTER) +#define MAP_SIZE_OF_ROUTE \ + BPF_MIN(MAP_SIZE_OF_MAX, MAP_SIZE_OF_PER_ROUTE * MAP_SIZE_OF_VIRTUAL_HOST) +#define MAP_SIZE_OF_CLUSTER \ + BPF_MIN(MAP_SIZE_OF_MAX, MAP_SIZE_OF_PER_CLUSTER * MAP_SIZE_OF_ROUTE) +#define MAP_SIZE_OF_ENDPOINT \ + BPF_MIN(MAP_SIZE_OF_MAX, MAP_SIZE_OF_PER_ENDPOINT * MAP_SIZE_OF_CLUSTER) + +// rename map to avoid truncation when name length exceeds BPF_OBJ_NAME_LEN = 16 +#define map_of_listener kmesh_listener +#define map_of_break_count kmesh_break_count +#define map_of_break kmesh_break +#define map_of_is_break kmesh_is_break +#define map_of_filter_chain kmesh_filter_chain +#define map_of_filter kmesh_filter +#define map_of_virtual_host kmesh_virtual_host +#define map_of_route kmesh_route +#define map_of_cluster kmesh_cluster +#define map_of_loadbalance kmesh_loadbalance +#define map_of_endpoint kmesh_endpoint +#define map_of_tail_call_prog kmesh_tail_call_prog +#define map_of_tail_call_ctx kmesh_tail_call_ctx + + +// ************ +// array len +#define KMESH_NAME_LEN 64 +#define KMESH_TYPE_LEN 64 +#define KMESH_HOST_LEN 128 +#define KMESH_FILTER_CHAINS_LEN 64 +#define KMESH_HTTP_DOMAIN_NUM 32 +#define KMESH_HTTP_DOMAIN_LEN 128 +#define KMESH_PER_FILTER_CHAIN_NUM MAP_SIZE_OF_PER_FILTER_CHAIN +#define KMESH_PER_FILTER_NUM MAP_SIZE_OF_PER_FILTER +#define KMESH_PER_VIRT_HOST_NUM MAP_SIZE_OF_PER_VIRTUAL_HOST +#define KMESH_PER_ROUTE_NUM MAP_SIZE_OF_PER_ROUTE +#define KMESH_PER_ENDPOINT_NUM MAP_SIZE_OF_PER_ENDPOINT +#define KMESH_PER_HEADER_MUM 32 +#define KMESH_PER_WEIGHT_CLUSTER_NUM 32 +#endif // _CONFIG_H_ diff --git a/ospp-kmesh-break/bpf/kmesh/include/listener.h b/ospp-kmesh-break/bpf/kmesh/include/listener.h new file mode 100644 index 0000000000000000000000000000000000000000..5911dffba51eee838a2b3fbf16d73b0f97d406a0 --- /dev/null +++ b/ospp-kmesh-break/bpf/kmesh/include/listener.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + * Author: nlgwcy + * Create: 2022-02-14 + */ +#ifndef __KMESH_LISTENER_H__ +#define __KMESH_LISTENER_H__ + +#include "kmesh_common.h" +#include "tail_call.h" +#include "listener/listener.pb-c.h" + +// 将 count 作为一个 u64 值存储 key 还需要设置,限制于单条服务 +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(address_t)); + __uint(value_size, sizeof(__u64)); + __uint(max_entries, 10000); + __uint(map_flags, 0); +} map_of_break_count SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(address_t)); + __uint(value_size, sizeof(__u64)); + __uint(max_entries, 10000); + __uint(map_flags, 0); +} map_of_is_break SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, 50*sizeof(char)); + __uint(value_size, sizeof(__u64)); + __uint(max_entries, 20000); + __uint(map_flags, 0); +} map_of_break SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(address_t)); + __uint(value_size, sizeof(Listener__Listener)); + __uint(max_entries, MAP_SIZE_OF_LISTENER); + __uint(map_flags, 0); +} map_of_listener SEC(".maps"); + +static inline Listener__Listener *map_lookup_listener(const address_t *addr) +{ + return kmesh_map_lookup_elem(&map_of_listener, addr); +} + +static inline bool listener_filter_chain_match_check(const Listener__FilterChain *filter_chain, + const address_t *addr, + const ctx_buff_t *ctx) +{ + char *transport_protocol; + const char buf[] = "raw_buffer"; + + Listener__FilterChainMatch *filter_chain_match = + kmesh_get_ptr_val(filter_chain->filter_chain_match); + if (!filter_chain_match) + return false; + + if (filter_chain_match->destination_port != 0 && + filter_chain_match->destination_port != addr->port) + return false; + + transport_protocol = kmesh_get_ptr_val(filter_chain_match->transport_protocol); + if (!transport_protocol) { + BPF_LOG(WARN, LISTENER, "transport_protocol is NULL\n"); + return false; + } else if (transport_protocol[0] != '\0' && bpf_strncmp(buf, sizeof(buf), transport_protocol) != 0) { + BPF_LOG(WARN, LISTENER, "transport_protocol %s mismatch\n", transport_protocol); + return false; + } + + // TODO: application_protocols + + BPF_LOG(DEBUG, LISTENER, "match filter_chain, name=\"%s\"\n", + (char *)kmesh_get_ptr_val(filter_chain->name)); + return true; +} + +static inline int listener_filter_chain_match(const Listener__Listener *listener, + const address_t *addr, + const ctx_buff_t *ctx, + Listener__FilterChain **filter_chain_ptr, + __u64 *filter_chain_idx) +{ + int i; + void *ptrs = NULL; + Listener__FilterChain *filter_chain = NULL; + + if (listener->n_filter_chains == 0 || listener->n_filter_chains > KMESH_PER_FILTER_CHAIN_NUM) { + BPF_LOG(ERR, LISTENER, "listener has no filter chains\n"); + return -1; + } + + ptrs = kmesh_get_ptr_val(listener->filter_chains); + if (!ptrs) { + BPF_LOG(ERR, LISTENER, "failed to get filter chain ptrs\n"); + return -1; + } + + for (i = 0; i < KMESH_PER_FILTER_CHAIN_NUM; i++) { + if (i >= (int)listener->n_filter_chains) { + break; + } + + filter_chain = (Listener__FilterChain *)kmesh_get_ptr_val((void*)*((__u64*)ptrs + i)); + if (!filter_chain) { + continue; + } + + if (listener_filter_chain_match_check(filter_chain, addr, ctx)) { + *filter_chain_ptr = filter_chain; + *filter_chain_idx = (__u64)*((__u64*)ptrs + i); + return 0; + } + } + return -1; +} + +static inline int l7_listener_manager(ctx_buff_t *ctx, Listener__Listener *listener, struct bpf_mem_ptr *msg) +{ + int ret = 0; + __u64 filter_chain_idx = 0; + Listener__FilterChain *filter_chain = NULL; + ctx_key_t ctx_key = {0}; + ctx_val_t ctx_val = {0}; + + DECLARE_VAR_ADDRESS(ctx, addr); + /* filter chain match */ + ret = listener_filter_chain_match(listener, &addr, ctx, &filter_chain, &filter_chain_idx); + if (ret != 0) { + BPF_LOG(WARN, LISTENER, "filterchain mismatch, un support addr=%u:%u\n", addr.ipv4, addr.port); + return -1; + } + + /* exec filter chain */ + ctx_key.address = addr; + ctx_key.tail_call_index = KMESH_TAIL_CALL_FILTER_CHAIN + bpf_get_current_task(); + ctx_val.val = filter_chain_idx; + ctx_val.msg = msg; + ret = kmesh_tail_update_ctx(&ctx_key, &ctx_val); + if (ret != 0) { + BPF_LOG(ERR, LISTENER, "kmesh tail update failed:%d\n", ret); + return ret; + } + + kmesh_tail_call(ctx, KMESH_TAIL_CALL_FILTER_CHAIN); + (void)kmesh_tail_delete_ctx(&ctx_key); + + BPF_LOG(ERR, LISTENER, "l7_listener_manager exit\n"); + return ret; +} +#endif diff --git a/ospp-kmesh-break/bpf/kmesh/sockops.c b/ospp-kmesh-break/bpf/kmesh/sockops.c new file mode 100644 index 0000000000000000000000000000000000000000..631268e0f908c320b10597832946414dbc8dce4c --- /dev/null +++ b/ospp-kmesh-break/bpf/kmesh/sockops.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + * Author: nlgwcy + * Create: 2022-02-14 + */ +#include +#include "bpf_log.h" +#include "listener.h" +#include "listener/listener.pb-c.h" + +#if KMESH_ENABLE_IPV4 +#if KMESH_ENABLE_HTTP + +static int sockops_traffic_control(struct bpf_sock_ops *skops, struct bpf_mem_ptr *msg) +{ + int ret; + /* 1 lookup listener */ + DECLARE_VAR_ADDRESS(skops, addr); + Listener__Listener *listener = map_lookup_listener(&addr); + + if (!listener) { + addr.ipv4 = 0; + listener = map_lookup_listener(&addr); + if (!listener) { + /* no match vip/nodeport listener */ + return 0; + } + } + + BPF_LOG(DEBUG, SOCKOPS, "sockops_traffic_control listener=\"%s\", addr=[%u:%u]\n", + (char *)kmesh_get_ptr_val(listener->name), skops->remote_ip4, skops->remote_port); + + ret = bpf_parse_header_msg(msg); + if (GET_RET_PROTO_TYPE(ret) != PROTO_HTTP_1_1) { + BPF_LOG(DEBUG, SOCKOPS, "sockops_traffic_control listener=\"%s\", remote_ip:%u, ret:%d\n", + (char *)kmesh_get_ptr_val(listener->name), skops->remote_ip4, ret); + return 0; + } + return l7_listener_manager(skops, listener, msg); +} + +static int handle_tcp_timeout(struct bpf_sock_ops *skops) +{ + int error_count_key = skops->remote_ip4; // access the map of break count + int break_key = 1; + int is_break_key = skops->remote_ip4; + int *error_count, *limit, current_error_count = 1; + int break_val = 1; + + error_count = bpf_map_lookup_elem(&map_of_break_count, &error_count_key); + if (error_count) { + current_error_count += *error_count; + } + bpf_map_update_elem(&map_of_break_count, &error_count_key, ¤t_error_count, BPF_ANY); + + limit = bpf_map_lookup_elem(&map_of_break, &break_key); + if (limit && current_error_count > *limit) { + bpf_map_update_elem(&map_of_is_break, &is_break_key, &break_val, BPF_ANY); + return 0; + } + return 0; +} + +SEC("sockops") +int sockops_prog(struct bpf_sock_ops *skops) +{ +#define BPF_CONSTRUCT_PTR(low_32, high_32) \ + (unsigned long long)(((unsigned long long)(high_32) << 32) + (low_32)) + + struct bpf_mem_ptr *msg = NULL; + + if (skops->family != AF_INET) + return 0; + + switch (skops->op) { + case BPF_SOCK_OPS_TCP_DEFER_CONNECT_CB: + msg = (struct bpf_mem_ptr *)BPF_CONSTRUCT_PTR(skops->args[0], skops->args[1]); + (void)sockops_traffic_control(skops, msg); + break; + case BPF_SOCK_OPS_TIMEOUT_INIT: + if (handle_tcp_timeout(skops) == 0) { + return 0; + } + break; + } + return 0; +} + +#endif +#endif +char _license[] SEC("license") = "GPL"; +int _version SEC("version") = 1; diff --git a/ospp-kmesh-break/daemon/manager/manager.go b/ospp-kmesh-break/daemon/manager/manager.go new file mode 100644 index 0000000000000000000000000000000000000000..9174290b64b60f7f3bcf93f803226104cdfd103b --- /dev/null +++ b/ospp-kmesh-break/daemon/manager/manager.go @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2019 Huawei Technologies Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + * Author: LemmyHuang + * Create: 2021-10-09 + */ + +// Package manager: kmesh daemon manager +package manager + +import ( + "fmt" + "os" + "os/signal" + "syscall" + "time" + + "github.com/cilium/ebpf" + + "openeuler.io/mesh/cmd/command" + "openeuler.io/mesh/pkg/bpf" + "openeuler.io/mesh/pkg/controller" + "openeuler.io/mesh/pkg/logger" + "openeuler.io/mesh/pkg/options" + "openeuler.io/mesh/pkg/pid" + "openeuler.io/mesh/api/v2/core" +) + +const ( + pkgSubsys = "manager" +) + +var ( + log = logger.NewLoggerField(pkgSubsys) +) + +// 初始化 ebpf map +var ebpfMap1 *ebpf.Map +var ebpfMap2 *ebpf.Map +var ticker *time.Ticker + +func initMaps() { + var err error + options := &ebpf.LoadPinOptions{ + } + ebpfMap1, err = ebpf.LoadPinnedMap("map_of_break", options) + if err != nil { + log.Fatal("Failed to load map_of_break:", err) + } + + ebpfMap2, err = ebpf.LoadPinnedMap("map_of_break_count", options) + if err != nil { + log.Fatal("Failed to load map_of_break_count:", err) + } +} + +// 获取限额数 +func getLimit() (int, error) { + var limit int + var str string + str = "break_config" + + err := ebpfMap1.Lookup(&str, &limit) + if err != nil { + return 0, err + } + return limit, nil +} + +// 重置计数 +func resetCount() error { + var nextKey, currentKey SocketAddress + var zeroValue = 0 + + for { + err := ebpfMap2.NextKey(¤tKey, &nextKey) + if err != nil { + // No more keys to iterate + break + } + + // Set the value for this key to zero + if err := ebpfMap2.Put(&nextKey, &zeroValue); err != nil { + return fmt.Errorf("failed to reset count for key %v: %w", nextKey, err) + } + + currentKey = nextKey + } + + return nil +} + +// 检查 ebpf map 中键值对是否存在 +func exists() (bool, error) { + var someKey = SocketAddress{ + Protocol: 0, + Port: 22, + Ipv4: 127, + } + err := ebpfMap2.Lookup(&someKey, nil) + if err != nil { + return false, err + } + return true, nil +} + +func handleTicker() bool { + limit, err := getLimit() + if err != nil { + log.Error("获取限额数失败:", err) + return false + } + done := make(chan struct{}) + ticker := time.NewTicker(time.Duration(limit) * time.Second) + defer ticker.Stop() + go func() { + for { + select { + case <-ticker.C: + processTicker() + } + case <-done: + return + } + } + }() + return true +} + +func processTicker() { + if exists, err := exists(); err != nil { + log.Error("检查ebpfMap2存在性失败:", err) + } else if !exists { + createEbpfMap2Entry() + } + resetMap2Count() +} + +func createEbpfMap2Entry() { + var someKey = SocketAddress{ + Protocol: 0, + Port: 22, + Ipv4: 127, + } + initialValue := 0 + if err := ebpfMap2.Put(&someKey, &initialValue); err != nil { + log.Error("创建ebpfMap2失败:", err) + } +} + +func resetMap2Count() { + if err := resetCount(); err != nil { + log.Error("重置ebpfMap2的count变量失败:", err) + } +} + +// Execute start daemon manager process +func Execute() { + var err error + + if err = options.InitDaemonConfig(); err != nil { + log.Error(err) + return + } + log.Info("options InitDaemonConfig successful") + + if err = pid.CreatePidFile(); err != nil { + log.Errorf("failed to start, reason: %v", err) + return + } + defer pid.RemovePidFile() + + if err = bpf.Start(); err != nil { + fmt.Println(err) + return + } + log.Info("bpf Start successful") + + if err = controller.Start(); err != nil { + log.Error(err) + bpf.Stop() + return + } + log.Info("controller Start successful") + initMaps() + if !handleTicker() { + return + } + ticker = time.NewTicker(time.Duration(limit) * time.Second) + if err = command.StartServer(); err != nil { + log.Error(err) + controller.Stop() + bpf.Stop() + return + } + log.Info("command StartServer successful") + setupCloseHandler() + return +} + +func setupCloseHandler() { + ch := make(chan os.Signal, 1) + signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGHUP, syscall.SIGABRT, syscall.SIGTSTP) + + <-ch + command.StopServer() + controller.Stop() + bpf.Stop() + // 定时器清理 + ticker.Stop() + close(done) + fmt.Println("定时器已经清理") + log.Warn("signal Notify exit") +} diff --git a/ospp-kmesh-break/pkg/cache/v2/maps/break.go b/ospp-kmesh-break/pkg/cache/v2/maps/break.go new file mode 100644 index 0000000000000000000000000000000000000000..285a6efaecdbbc95f15ff27eb078de33b62c9c94 --- /dev/null +++ b/ospp-kmesh-break/pkg/cache/v2/maps/break.go @@ -0,0 +1,71 @@ +package maps + +// #cgo pkg-config: api-v2-c +// #include "deserialization_to_bpf_map.h" +// #include "listener/listener.pb-c.h" +import "C" +import ( + "fmt" + "unsafe" + +) + +const MaxKeyLength = 50 + +type BreakKeyAndValue struct { + BreakKey [MaxKeyLength]byte + BreakValue int +} + +func MapOfBreakUpdate(key string, value *int) error { + if len(key) > MaxKeyLength { + return fmt.Errorf("key length exceeds maximum allowed length") + } + + var err error + + log.Debugf("map of break update [%s], [%d]", key, *value) + + // Convert Go string to [MaxKeyLength]byte + var cKey [MaxKeyLength]byte + copy(cKey[:], key) + + cKeyPtr, err := keyToClang(&cKey) + if err != nil { + return fmt.Errorf("map of break lookup %s", err) + } + defer keyFreeClang(cKeyPtr) + + // Assuming value is directly compatible with C.int + breakValue := C.int(*value) + + ret := C.deserial_update_map_of_break_elem(unsafe.Pointer(cKeyPtr), unsafe.Pointer(&breakValue)) + if ret != 0 { + return fmt.Errorf("map of break update deserial_update_map_of_break_elem failed") + } + return nil +} + +func MapOfBreakDelete(key string) error { + if len(key) > MaxKeyLength { + return fmt.Errorf("key length exceeds maximum allowed length") + } + + log.Debugf("map of break delete [%s]", key) + + // Convert Go string to [MaxKeyLength]byte + var cKey [MaxKeyLength]byte + copy(cKey[:], key) + + cKeyPtr, err := keyToClang(&cKey) + if err != nil { + return fmt.Errorf("map of break lookup %s", err) + } + defer keyFreeClang(cKeyPtr) + + ret := C.deserial_delete_map_of_break_elem(unsafe.Pointer(cKeyPtr)) + if ret != 0 { + return fmt.Errorf("map of break update deserial_delete_map_of_break_elem failed") + } + return nil +} diff --git a/ospp-kmesh-break/pkg/cache/v2/maps/break_count.go b/ospp-kmesh-break/pkg/cache/v2/maps/break_count.go new file mode 100644 index 0000000000000000000000000000000000000000..0bd6d2c5e7dc963b5bf28ef9b756597487205e63 --- /dev/null +++ b/ospp-kmesh-break/pkg/cache/v2/maps/break_count.go @@ -0,0 +1,52 @@ +package maps + +// #cgo pkg-config: api-v2-c +// #include "deserialization_to_bpf_map.h" +// #include "listener/listener.pb-c.h" +import "C" +import ( + "fmt" + "unsafe" + + core_v2 "openeuler.io/mesh/api/v2/core" +) + +type BreakCountKeyAndValue struct { + Address core_v2.SocketAddress + BreakCount int +} + +func MapOfBreakCountUpdate(key *core_v2.SocketAddress, value *int) error { + var err error + + log.Debugf("MapOfBreakCountUpdate [%s], [%d]", key.String(), *value) + + cKey, err := socketAddressToClang(key) + if err != nil { + return fmt.Errorf("map of break count lookup %s", err) + } + defer socketAddressFreeClang(cKey) + + overCount := C.int(*value) + + ret := C.deserial_update_map_of_break_count_elem(unsafe.Pointer(cKey), unsafe.Pointer(&overCount)) + if ret != 0 { + return fmt.Errorf("map of break count update deserial_update_map_of_break_count_elem failed") + } + return nil +} + +func MapOfBreakCountDelete(key *core_v2.SocketAddress) error { + log.Debugf("MapOfBreakCountDelete [%s]", key.String()) + + cKey, err := socketAddressToClang(key) + if err != nil { + return fmt.Errorf("MapOfBreakCountLookup %s", err) + } + defer socketAddressFreeClang(cKey) + ret := C.deserial_delete_map_of_break_count_elem(unsafe.Pointer(cKey)) + if ret != 0 { + return fmt.Errorf("map of break count update deserial_delete_map_of_break_count_elem failed") + } + return nil +} diff --git a/ospp-kmesh-break/pkg/cache/v2/maps/common.go b/ospp-kmesh-break/pkg/cache/v2/maps/common.go new file mode 100644 index 0000000000000000000000000000000000000000..94870518fb8fc962297563dc54e45185392be1db --- /dev/null +++ b/ospp-kmesh-break/pkg/cache/v2/maps/common.go @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2019 Huawei Technologies Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + * Author: LemmyHuang + * Create: 2022-02-28 + */ + +package maps + +// #cgo pkg-config: api-v2-c +// #include "deserialization_to_bpf_map.h" +// #include "core/address.pb-c.h" +// #include +import "C" +import ( + "fmt" + "unsafe" + + "google.golang.org/protobuf/proto" + core_v2 "openeuler.io/mesh/api/v2/core" +) + +func convertToPack(buf []byte) *C.uint8_t { + return (*C.uint8_t)(unsafe.Pointer(&buf[0])) +} + +func socketAddressToGolang(goMsg *core_v2.SocketAddress, cMsg *C.Core__SocketAddress) error { + buf := make([]byte, C.core__socket_address__get_packed_size(cMsg)) + + C.core__socket_address__pack(cMsg, convertToPack(buf)) + if err := proto.Unmarshal(buf, goMsg); err != nil { + return err + } + return nil +} + +func socketAddressToClang(goMsg *core_v2.SocketAddress) (*C.Core__SocketAddress, error) { + buf, err := proto.Marshal(goMsg) + if err != nil { + return nil, err + } + + cMsg := C.core__socket_address__unpack(nil, C.size_t(len(buf)), convertToPack(buf)) + if cMsg == nil { + return nil, fmt.Errorf("core__socket_address__unpack failed") + } + return cMsg, nil +} + +func socketAddressFreeClang(cMsg *C.Core__SocketAddress) { + C.core__socket_address__free_unpacked(cMsg, nil) +} + +func keyToClang(goKey *[50]byte) (*C.char, error) { + cKey := C.CString(string(goKey[:])) + + if cKey == nil { + return nil, fmt.Errorf("conversion to C string failed") + } + return cKey, nil +} + + +func keyFreeClang(cKey *C.char) { + C.free(unsafe.Pointer(cKey)) +} + +func testSocketAddress(goMsg *core_v2.SocketAddress, cMsg *C.Core__SocketAddress) { + msg := &core_v2.SocketAddress{} + + if err := socketAddressToGolang(msg, cMsg); err != nil { + log.Errorf("testSocketAddress socketAddressToGolang failed") + } + if goMsg.String() != msg.String() { + log.Errorf("testSocketAddress invalid message") + log.Errorf("testSocketAddress [%s]", msg.String()) + } +} + +func stringToGolang(cMsg *C.char) string { + return C.GoString(cMsg) +} + +func stringToClang(goMsg string) *C.char { + return C.CString(goMsg) +} + +func stringFreeClang(cMsg *C.char) { + if cMsg != nil { + C.free(unsafe.Pointer(cMsg)) + } +} + +func testString(goMsg string, cMsg *C.char) { + msg := stringToGolang(cMsg) + if goMsg != msg { + log.Errorf("testString invalid message") + log.Errorf("testString [%s]", msg) + } +} diff --git a/ospp-kmesh-break/pkg/cache/v2/maps/is_break.go b/ospp-kmesh-break/pkg/cache/v2/maps/is_break.go new file mode 100644 index 0000000000000000000000000000000000000000..6d6d563b4e4a126235a22be93deb91486856b4c9 --- /dev/null +++ b/ospp-kmesh-break/pkg/cache/v2/maps/is_break.go @@ -0,0 +1,53 @@ +package maps + +// #cgo pkg-config: api-v2-c +// #include "deserialization_to_bpf_map.h" +// #include "listener/listener.pb-c.h" +import "C" +import ( + "fmt" + "unsafe" + + core_v2 "openeuler.io/mesh/api/v2/core" +) + +type IsBreakKeyAndValue struct { + BreakAddress core_v2.SocketAddress + BreakValue int +} + +func MapOfIsBreakUpdate(key *core_v2.SocketAddress, value *int) error { + var err error + + log.Debugf("MapOfIsBreakUpdate [%v], [%d]", *key, *value) + + cKeyPtr, err := socketAddressToClang(key) + if err != nil { + return fmt.Errorf("MapOfIsBreakLookup %s", err) + } + defer socketAddressFreeClang(cKeyPtr) + + breakValue := C.int(*value) + + ret := C.deserial_update_map_of_is_break_elem(unsafe.Pointer(cKeyPtr), unsafe.Pointer(&breakValue)) + if ret != 0 { + return fmt.Errorf("MapOfIsBreakUpdate deserial_update_map_of_is_break_elem failed") + } + return nil +} + +func MapOfIsBreakDelete(key *core_v2.SocketAddress) error { + log.Debugf("MapOfIsBreakDelete [%v]", *key) + + cKeyPtr, err := socketAddressToClang(key) + if err != nil { + return fmt.Errorf("MapOfIsBreakLookup %s", err) + } + defer socketAddressFreeClang(cKeyPtr) + + ret := C.deserial_delete_map_of_is_break_elem(unsafe.Pointer(cKeyPtr)) + if ret != 0 { + return fmt.Errorf("MapOfIsBreakDelete deserial_delete_map_of_is_break_elem failed") + } + return nil +}