From a42abd51f68ce52c91048c39bd1f43d8a0a83157 Mon Sep 17 00:00:00 2001 From: FedeParola Date: Tue, 28 Jan 2020 10:12:09 +0100 Subject: [PATCH 01/12] Add gtphandler service --- src/services/CMakeLists.txt | 1 + .../pcn-gtphandler/.swagger-codegen-ignore | 14 + src/services/pcn-gtphandler/CMakeLists.txt | 5 + .../pcn-gtphandler/datamodel/gtphandler.yang | 46 ++ .../pcn-gtphandler/src/CMakeLists.txt | 50 ++ .../pcn-gtphandler/src/Gtphandler-lib.cpp | 21 + .../pcn-gtphandler/src/Gtphandler.cpp | 152 ++++++ src/services/pcn-gtphandler/src/Gtphandler.h | 58 ++ .../pcn-gtphandler/src/Gtphandler_dp_egress.c | 168 ++++++ .../src/Gtphandler_dp_ingress.c | 132 +++++ .../pcn-gtphandler/src/UserEquipment.cpp | 96 ++++ .../pcn-gtphandler/src/UserEquipment.h | 64 +++ .../pcn-gtphandler/src/api/GtphandlerApi.cpp | 513 ++++++++++++++++++ .../pcn-gtphandler/src/api/GtphandlerApi.h | 62 +++ .../src/api/GtphandlerApiImpl.cpp | 421 ++++++++++++++ .../src/api/GtphandlerApiImpl.h | 66 +++ .../src/base/GtphandlerBase.cpp | 66 +++ .../pcn-gtphandler/src/base/GtphandlerBase.h | 53 ++ .../src/base/UserEquipmentBase.cpp | 44 ++ .../src/base/UserEquipmentBase.h | 61 +++ .../src/serializer/GtphandlerJsonObject.cpp | 106 ++++ .../src/serializer/GtphandlerJsonObject.h | 67 +++ .../src/serializer/JsonObjectBase.cpp | 69 +++ .../src/serializer/JsonObjectBase.h | 55 ++ .../serializer/UserEquipmentJsonObject.cpp | 116 ++++ .../src/serializer/UserEquipmentJsonObject.h | 72 +++ src/services/pcn-gtphandler/test/test.sh | 67 +++ 27 files changed, 2645 insertions(+) create mode 100644 src/services/pcn-gtphandler/.swagger-codegen-ignore create mode 100644 src/services/pcn-gtphandler/CMakeLists.txt create mode 100644 src/services/pcn-gtphandler/datamodel/gtphandler.yang create mode 100644 src/services/pcn-gtphandler/src/CMakeLists.txt create mode 100644 src/services/pcn-gtphandler/src/Gtphandler-lib.cpp create mode 100644 src/services/pcn-gtphandler/src/Gtphandler.cpp create mode 100644 src/services/pcn-gtphandler/src/Gtphandler.h create mode 100644 src/services/pcn-gtphandler/src/Gtphandler_dp_egress.c create mode 100644 src/services/pcn-gtphandler/src/Gtphandler_dp_ingress.c create mode 100644 src/services/pcn-gtphandler/src/UserEquipment.cpp create mode 100644 src/services/pcn-gtphandler/src/UserEquipment.h create mode 100644 src/services/pcn-gtphandler/src/api/GtphandlerApi.cpp create mode 100644 src/services/pcn-gtphandler/src/api/GtphandlerApi.h create mode 100644 src/services/pcn-gtphandler/src/api/GtphandlerApiImpl.cpp create mode 100644 src/services/pcn-gtphandler/src/api/GtphandlerApiImpl.h create mode 100644 src/services/pcn-gtphandler/src/base/GtphandlerBase.cpp create mode 100644 src/services/pcn-gtphandler/src/base/GtphandlerBase.h create mode 100644 src/services/pcn-gtphandler/src/base/UserEquipmentBase.cpp create mode 100644 src/services/pcn-gtphandler/src/base/UserEquipmentBase.h create mode 100644 src/services/pcn-gtphandler/src/serializer/GtphandlerJsonObject.cpp create mode 100644 src/services/pcn-gtphandler/src/serializer/GtphandlerJsonObject.h create mode 100644 src/services/pcn-gtphandler/src/serializer/JsonObjectBase.cpp create mode 100644 src/services/pcn-gtphandler/src/serializer/JsonObjectBase.h create mode 100644 src/services/pcn-gtphandler/src/serializer/UserEquipmentJsonObject.cpp create mode 100644 src/services/pcn-gtphandler/src/serializer/UserEquipmentJsonObject.h create mode 100755 src/services/pcn-gtphandler/test/test.sh diff --git a/src/services/CMakeLists.txt b/src/services/CMakeLists.txt index 55ca7e4ef..44036ae26 100644 --- a/src/services/CMakeLists.txt +++ b/src/services/CMakeLists.txt @@ -37,6 +37,7 @@ add_service(transparenthelloworld pcn-transparent-helloworld) add_service(synflood pcn-synflood) add_service(packetcapture pcn-packetcapture) add_service(dynmon pcn-dynmon) +add_service(gtphandler pcn-gtphandler) # save string to create code that load the services SET_PROPERTY(GLOBAL PROPERTY LOAD_SERVICES_ ${LOAD_SERVICES}) diff --git a/src/services/pcn-gtphandler/.swagger-codegen-ignore b/src/services/pcn-gtphandler/.swagger-codegen-ignore new file mode 100644 index 000000000..f90131c08 --- /dev/null +++ b/src/services/pcn-gtphandler/.swagger-codegen-ignore @@ -0,0 +1,14 @@ +# Swagger Codegen Ignore +# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen + +# Use this file to prevent files from being overwritten by the generator. + +.swagger-codegen-ignore + +src/*.c +src/*.cpp +src/*.h + +!src/*Interface.h +!src/*JsonObject.h +!src/*JsonObject.cpp diff --git a/src/services/pcn-gtphandler/CMakeLists.txt b/src/services/pcn-gtphandler/CMakeLists.txt new file mode 100644 index 000000000..9857094f7 --- /dev/null +++ b/src/services/pcn-gtphandler/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required (VERSION 3.2) + +set (CMAKE_CXX_STANDARD 11) + +add_subdirectory(src) diff --git a/src/services/pcn-gtphandler/datamodel/gtphandler.yang b/src/services/pcn-gtphandler/datamodel/gtphandler.yang new file mode 100644 index 000000000..cc5a04981 --- /dev/null +++ b/src/services/pcn-gtphandler/datamodel/gtphandler.yang @@ -0,0 +1,46 @@ +module gtphandler { + yang-version 1.1; + namespace "http://polycube.network/gtphandler"; + prefix "gtphandler"; + + import polycube-base { prefix "polycube-base"; } + import polycube-transparent-base { prefix "polycube-transparent-base"; } + + import ietf-inet-types { prefix "inet"; } + + organization "Polycube Open Source Project"; + description "YANG data model for the Polycube GTP Handler service"; + + polycube-base:service-description "GTP Handler Service"; + polycube-base:service-version "1.0"; + polycube-base:service-name "gtphandler"; + polycube-base:service-min-kernel-version "5.2.0"; + + uses "polycube-transparent-base:transparent-base-yang-module"; + + list user-equipment { + key "ip"; + description "User Equipment connected with GTP tunnel"; + + leaf ip { + type inet:ipv4-address; + mandatory true; + description "IP address of the User Equipment"; + polycube-base:cli-example "123.14.23.3"; + } + + leaf tunnel-endpoint { + type inet:ipv4-address; + mandatory true; + description "IP address of the Base Station that connects the User Equipment"; + polycube-base:cli-example "110.0.0.1"; + } + + leaf teid { + type uint32; + mandatory true; + description "Tunnel Endpoint ID of the GTP tunnel used by the User Equipment"; + polycube-base:cli-example "56000"; + } + } +} diff --git a/src/services/pcn-gtphandler/src/CMakeLists.txt b/src/services/pcn-gtphandler/src/CMakeLists.txt new file mode 100644 index 000000000..a769378ba --- /dev/null +++ b/src/services/pcn-gtphandler/src/CMakeLists.txt @@ -0,0 +1,50 @@ +include(${PROJECT_SOURCE_DIR}/cmake/LoadFileAsVariable.cmake) + +aux_source_directory(serializer SERIALIZER_SOURCES) +aux_source_directory(api API_SOURCES) +aux_source_directory(base BASE_SOURCES) + +include_directories(serializer) + +if (NOT DEFINED POLYCUBE_STANDALONE_SERVICE OR POLYCUBE_STANDALONE_SERVICE) + find_package(PkgConfig REQUIRED) + pkg_check_modules(POLYCUBE libpolycube) + include_directories(${POLYCUBE_INCLUDE_DIRS}) +endif(NOT DEFINED POLYCUBE_STANDALONE_SERVICE OR POLYCUBE_STANDALONE_SERVICE) + +# Needed to load files as variables +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +add_library(pcn-gtphandler SHARED + ${SERIALIZER_SOURCES} + ${API_SOURCES} + ${BASE_SOURCES} + Gtphandler.cpp + UserEquipment.cpp + Gtphandler-lib.cpp) + +# load ebpf datapath code a variable +load_file_as_variable(pcn-gtphandler + Gtphandler_dp_egress.c + gtphandler_code_egress) +load_file_as_variable(pcn-gtphandler + Gtphandler_dp_ingress.c + gtphandler_code_ingress) + +# load datamodel in a variable +load_file_as_variable(pcn-gtphandler + ../datamodel/gtphandler.yang + gtphandler_datamodel) + +target_link_libraries(pcn-gtphandler ${POLYCUBE_LIBRARIES}) + +# Specify shared library install directory + +set(CMAKE_INSTALL_LIBDIR /usr/lib) + +install( + TARGETS + pcn-gtphandler + DESTINATION + "${CMAKE_INSTALL_LIBDIR}" +) diff --git a/src/services/pcn-gtphandler/src/Gtphandler-lib.cpp b/src/services/pcn-gtphandler/src/Gtphandler-lib.cpp new file mode 100644 index 000000000..83734d72f --- /dev/null +++ b/src/services/pcn-gtphandler/src/Gtphandler-lib.cpp @@ -0,0 +1,21 @@ +/** +* gtphandler API generated from gtphandler.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +#include "api/GtphandlerApiImpl.h" +#include "../datamodel/gtphandler.h" // generated from datamodel + +#define SERVICE_PYANG_GIT "" +#define SERVICE_SWAGGER_CODEGEN_GIT "master/f3b9193" + +#include + +extern "C" const char *data_model() { + return gtphandler_datamodel.c_str(); +} diff --git a/src/services/pcn-gtphandler/src/Gtphandler.cpp b/src/services/pcn-gtphandler/src/Gtphandler.cpp new file mode 100644 index 000000000..09eb05eec --- /dev/null +++ b/src/services/pcn-gtphandler/src/Gtphandler.cpp @@ -0,0 +1,152 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#include "Gtphandler.h" +#include "Gtphandler_dp_ingress.h" +#include "Gtphandler_dp_egress.h" + + +using namespace polycube::service; + +Gtphandler::Gtphandler(const std::string name, const GtphandlerJsonObject &conf) + : TransparentCube(conf.getBase(), {}, {}), + GtphandlerBase(name) { + logger()->info("Creating Gtphandler instance"); + + add_program(getWrapperCode() + gtphandler_code_ingress, 0, ProgramType::INGRESS); + add_program(getWrapperCode() + gtphandler_code_egress, 0, ProgramType::EGRESS); + + addUserEquipmentList(conf.getUserEquipment()); + + ParameterEventCallback cb_ip = [&](const std::string ¶meter, const std::string &value) { + local_ip_ = utils::get_ip_from_string(value); + logger()->info("Local IP set to {0}", local_ip_); + + if (local_mac_ != "" && local_ip_ != "") { + reloadCode(); + } + }; + subscribe_parent_parameter("ip", cb_ip); + + ParameterEventCallback cb_mac = [&](const std::string ¶meter, const std::string &value) { + local_mac_ = value; + logger()->info("Local MAC set to {0}", local_mac_); + + if (local_mac_ != "" && local_ip_ != "") { + reloadCode(); + } + }; + subscribe_parent_parameter("mac", cb_mac); +} + + +Gtphandler::~Gtphandler() { + logger()->info("Destroying Gtphandler instance"); + unsubscribe_parent_parameter("ip"); + unsubscribe_parent_parameter("mac"); +} + +void Gtphandler::packet_in(polycube::service::Direction direction, + polycube::service::PacketInMetadata &md, + const std::vector &packet) { + logger()->debug("Packet received"); +} + +std::shared_ptr Gtphandler::getUserEquipment(const std::string &ip) { + if (user_equipments_.count(ip) == 0) { + throw std::runtime_error("No user equipment with the given ip"); + } + + return user_equipments_.at(ip); +} + +std::vector> Gtphandler::getUserEquipmentList() { + std::vector> user_equipments_v; + + user_equipments_v.reserve(user_equipments_v.size()); + + for (auto const &entry : user_equipments_) { + user_equipments_v.push_back(entry.second); + } + + return user_equipments_v; +} + +void Gtphandler::addUserEquipment(const std::string &ip, const UserEquipmentJsonObject &conf) { + if (user_equipments_.count(ip) != 0) { + throw std::runtime_error("User equipment with the given ip already registered"); + } + + if (user_equipments_.size() == MAX_USER_EQUIPMENTS) { + throw std::runtime_error("Maximum number of user equipments reached"); + } + + user_equipments_[ip] = std::make_shared(*this, conf); +} + +// Basic default implementation, place your extension here (if needed) +void Gtphandler::addUserEquipmentList(const std::vector &conf) { + // call default implementation in base class + GtphandlerBase::addUserEquipmentList(conf); +} + +// Basic default implementation, place your extension here (if needed) +void Gtphandler::replaceUserEquipment(const std::string &ip, const UserEquipmentJsonObject &conf) { + // call default implementation in base class + GtphandlerBase::replaceUserEquipment(ip, conf); +} + +void Gtphandler::delUserEquipment(const std::string &ip) { + if (user_equipments_.count(ip) == 0) { + throw std::runtime_error("No user equipment with the given ip"); + } + + user_equipments_.erase(ip); +} + +// Basic default implementation, place your extension here (if needed) +void Gtphandler::delUserEquipmentList() { + // call default implementation in base class + GtphandlerBase::delUserEquipmentList(); +} + +std::string Gtphandler::getWrapperCode() { + std::ostringstream wrapper_code; + wrapper_code << "#define MAX_USER_EQUIPMENTS " << MAX_USER_EQUIPMENTS << "\n"; + + if (local_ip_ != "") { + wrapper_code << "#define LOCAL_IP " << utils::ip_string_to_nbo_uint(local_ip_) << "\n"; + } + + if (local_mac_ != "") { + wrapper_code << "#define LOCAL_MAC " << utils::mac_string_to_nbo_uint(local_mac_) << "\n"; + } + + return wrapper_code.str(); +} + +void Gtphandler::reloadCode() { + std::string wrapper_code = getWrapperCode(); + + std::string ingress_code = wrapper_code + gtphandler_code_ingress; + std::string egress_code = wrapper_code + gtphandler_code_egress; + + reload(ingress_code, 0, ProgramType::INGRESS); + reload(egress_code, 0, ProgramType::EGRESS); + + logger()->info("Dataplane code reloaded"); +} \ No newline at end of file diff --git a/src/services/pcn-gtphandler/src/Gtphandler.h b/src/services/pcn-gtphandler/src/Gtphandler.h new file mode 100644 index 000000000..b3589934d --- /dev/null +++ b/src/services/pcn-gtphandler/src/Gtphandler.h @@ -0,0 +1,58 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#pragma once + + +#include "../base/GtphandlerBase.h" + +#include "UserEquipment.h" + + +#define MAX_USER_EQUIPMENTS 1024 + + +using namespace polycube::service::model; + +class Gtphandler : public GtphandlerBase { + public: + Gtphandler(const std::string name, const GtphandlerJsonObject &conf); + virtual ~Gtphandler(); + + void packet_in(polycube::service::Direction direction, + polycube::service::PacketInMetadata &md, + const std::vector &packet) override; + + /// + /// User Equipment connected with GTP tunnel + /// + std::shared_ptr getUserEquipment(const std::string &ip) override; + std::vector> getUserEquipmentList() override; + void addUserEquipment(const std::string &ip, const UserEquipmentJsonObject &conf) override; + void addUserEquipmentList(const std::vector &conf) override; + void replaceUserEquipment(const std::string &ip, const UserEquipmentJsonObject &conf) override; + void delUserEquipment(const std::string &ip) override; + void delUserEquipmentList() override; + + private: + std::string local_ip_; + std::string local_mac_; + std::unordered_map> user_equipments_; + + std::string getWrapperCode(); + void reloadCode(); +}; diff --git a/src/services/pcn-gtphandler/src/Gtphandler_dp_egress.c b/src/services/pcn-gtphandler/src/Gtphandler_dp_egress.c new file mode 100644 index 000000000..d0fa2d5d0 --- /dev/null +++ b/src/services/pcn-gtphandler/src/Gtphandler_dp_egress.c @@ -0,0 +1,168 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#include + +#include +#include +#include +#include + + +// #define MAX_USER_EQUIPMENTS n + +// Following constants are added to the program at user level once the cube +// is attached to an interface +// Default values are used to inject the program before attachment +#ifndef LOCAL_IP +#define LOCAL_IP 0 +#endif +#ifndef LOCAL_MAC +#define LOCAL_MAC 0 +#endif + +#define GTP_PORT 2152 +#define GTP_TYPE_GPDU 255 // User data packet (T-PDU) plus GTP-U header +#define GTP_FLAGS 0x30 // Version: GTPv1, Protocol Type: GTP, Others: 0 + + +struct eth_hdr { + __be64 dst : 48; + __be64 src : 48; + __be16 proto; +} __attribute__((packed)); + +struct gtp1_header { /* According to 3GPP TS 29.060. */ + u8 flags; + u8 type; + __be16 length; + __be32 tid; +} __attribute__((packed)); + +struct user_equipment { + __be32 tunnel_endpoint; + __be32 teid; +}; + +BPF_TABLE("extern", __be32, struct user_equipment, user_equipments, MAX_USER_EQUIPMENTS); + + +#define IP_CSUM_OFFSET (sizeof(struct eth_hdr) + offsetof(struct iphdr, check)) +#define GTP_ENCAP_SIZE (sizeof(struct iphdr) + \ + sizeof(struct udphdr) + \ + sizeof(struct gtp1_header)) + + +static __always_inline +int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) { + void *data = (void *)(long)ctx->data; + void *data_end = (void *)(long)ctx->data_end; + + struct eth_hdr *eth = data; + if (data + sizeof(*eth) > data_end) { + return RX_DROP; + } + + if (eth->proto != htons(ETH_P_IP)) { + return RX_OK; + } + + struct iphdr *ip = data + sizeof(*eth); + if ((void *)ip + sizeof(*ip) > data_end) { + return RX_DROP; + } + + // Check if packet is directed to a user equipment + struct user_equipment *ue = user_equipments.lookup(&ip->daddr); + if (!ue) { + return RX_OK; + } + + // Add space for encapsulation to packet buffer +#ifdef POLYCUBE_XDP + bpf_xdp_adjust_head(ctx, (int32_t)-GTP_ENCAP_SIZE); +#else + bpf_skb_adjust_room(ctx, GTP_ENCAP_SIZE, BPF_ADJ_ROOM_MAC, 0); +#endif + + // Packet buffer changed, all pointers need to be recomputed + data = (void *)(long)ctx->data; + data_end = (void *)(long)ctx->data_end; + + eth = data; + if (data + sizeof(*eth) > data_end) { + return RX_DROP; + } + +#ifdef POLYCUBE_XDP + // Space allocated before packet buffer, move eth header + struct eth_hdr *old_eth = data + GTP_ENCAP_SIZE; + if ((void *)old_eth + sizeof(*eth) > data_end) { + return RX_DROP; + } + memmove(eth, old_eth, sizeof(*eth)); +#endif + + ip = data + sizeof(*eth); + if ((void *)ip + sizeof(*ip) > data_end) { + return RX_DROP; + } + + struct iphdr *inner_ip = (void *)ip + GTP_ENCAP_SIZE; + if ((void *)inner_ip + sizeof(*inner_ip) > data_end) { + return RX_DROP; + } + + // Add the outer IP header + ip->version = 4; + ip->ihl = 5; // No options + ip->tos = 0; + ip->tot_len = htons(ntohs(inner_ip->tot_len) + GTP_ENCAP_SIZE); + ip->id = 0; // No fragmentation + ip->frag_off = 0x0040; // Don't fragment; Fragment offset = 0 + ip->ttl = 64; + ip->protocol = IPPROTO_UDP; + ip->check = 0; + ip->saddr = LOCAL_IP; + ip->daddr = ue->tunnel_endpoint; + + // Add the UDP header + struct udphdr *udp = (void *)ip + sizeof(*ip); + if ((void *)udp + sizeof(*udp) > data_end) { + return RX_DROP; + } + udp->source = htons(GTP_PORT); + udp->dest = htons(GTP_PORT); + udp->len = htons(ntohs(inner_ip->tot_len) + sizeof(*udp) + sizeof(struct gtp1_header)); + udp->check = 0; + + // Add the GTP header + struct gtp1_header *gtp = (void *)udp + sizeof(*udp); + if ((void *)gtp + sizeof(*gtp) > data_end) { + return RX_DROP; + } + gtp->flags = GTP_FLAGS; + gtp->type = GTP_TYPE_GPDU; + gtp->length = inner_ip->tot_len; + gtp->tid = ue->teid; + + // Compute l3 checksum + __wsum l3sum = pcn_csum_diff(0, 0, (__be32 *)ip, sizeof(*ip), 0); + pcn_l3_csum_replace(ctx, IP_CSUM_OFFSET, 0, l3sum, 0); + + return RX_OK; +} \ No newline at end of file diff --git a/src/services/pcn-gtphandler/src/Gtphandler_dp_ingress.c b/src/services/pcn-gtphandler/src/Gtphandler_dp_ingress.c new file mode 100644 index 000000000..7c0af0950 --- /dev/null +++ b/src/services/pcn-gtphandler/src/Gtphandler_dp_ingress.c @@ -0,0 +1,132 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#include + +#include +#include +#include +#include + + +// #define MAX_USER_EQUIPMENTS n + +// Following constants are added to the program at user level once the cube +// is attached to an interface +// Default values are used to inject the program before attachment +#ifndef LOCAL_IP +#define LOCAL_IP 0 +#endif +#ifndef LOCAL_MAC +#define LOCAL_MAC 0 +#endif + +#define GTP_PORT 2152 + + +struct eth_hdr { + __be64 dst : 48; + __be64 src : 48; + __be16 proto; +} __attribute__((packed)); + +struct gtp1_header { /* According to 3GPP TS 29.060. */ + u8 flags; + u8 type; + __be16 length; + __be32 tid; +} __attribute__((packed)); + +struct user_equipment { + __be32 tunnel_endpoint; + __be32 teid; +}; + +BPF_TABLE_SHARED("hash", __be32, struct user_equipment, user_equipments, MAX_USER_EQUIPMENTS); + + +#define GTP_ENCAP_SIZE (sizeof(struct iphdr) + \ + sizeof(struct udphdr) + \ + sizeof(struct gtp1_header)) + + +static __always_inline +int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) { + void *data = (void *)(long)ctx->data; + void *data_end = (void *)(long)ctx->data_end; + + // Check if packet is GTP encapsulated, if not pass it to the next cube + + struct eth_hdr *eth = data; + if (data + sizeof(*eth) > data_end) { + return RX_DROP; + } + + if (eth->dst != LOCAL_MAC) { + return RX_OK; + } + + if (eth->proto != htons(ETH_P_IP)) { + return RX_OK; + } + + struct iphdr *ip = data + sizeof(*eth); + if ((void *)ip + sizeof(*ip) > data_end) { + return RX_DROP; + } + + if (ip->daddr != LOCAL_IP) { + return RX_OK; + } + + if (ip->protocol != IPPROTO_UDP) { + return RX_OK; + } + + struct udphdr *udp = (void *)ip + 4*ip->ihl; + if ((void *)udp + sizeof(*udp) > data_end) { + return RX_DROP; + } + + if (udp->dest != htons(GTP_PORT)) { + return RX_OK; + } + + struct gtp1_header *gtp = (void *)udp + sizeof(*udp); + if ((void *)gtp + sizeof(*gtp) > data_end) { + return RX_DROP; + } + + // Save tunnel as traffic class + md->traffic_class = ntohl(gtp->tid); + + // Remove encapsulation +#ifdef POLYCUBE_XDP + // Move eth header forward + struct eth_hdr *new_eth = data + GTP_ENCAP_SIZE; + if ((void *)new_eth + sizeof(*eth) > data_end) { + return RX_DROP; + } + memmove(new_eth, eth, sizeof(*eth)); + bpf_xdp_adjust_head(ctx, GTP_ENCAP_SIZE); + +#else + bpf_skb_adjust_room(ctx, (int32_t)-GTP_ENCAP_SIZE, BPF_ADJ_ROOM_MAC, 0); +#endif + + return RX_OK; +} \ No newline at end of file diff --git a/src/services/pcn-gtphandler/src/UserEquipment.cpp b/src/services/pcn-gtphandler/src/UserEquipment.cpp new file mode 100644 index 000000000..69296ae9a --- /dev/null +++ b/src/services/pcn-gtphandler/src/UserEquipment.cpp @@ -0,0 +1,96 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#include "UserEquipment.h" +#include "Gtphandler.h" + + +using namespace polycube::service; + +UserEquipment::UserEquipment(Gtphandler &parent, const UserEquipmentJsonObject &conf) + : UserEquipmentBase(parent) { + ip_ = conf.getIp(); + tunnel_endpoint_ = conf.getTunnelEndpoint(); + teid_ = conf.getTeid(); + + updateDataplane(); + + logger()->info("User equipment created {0}", toString()); +} + +UserEquipment::~UserEquipment() { + parent_.get_hash_table("user_equipments") + .remove(utils::ip_string_to_nbo_uint(ip_)); + + logger()->info("User equipment {0} deleted", ip_); +} + +std::string UserEquipment::getIp() { + return ip_; +} + +std::string UserEquipment::getTunnelEndpoint() { + return tunnel_endpoint_; +} + +void UserEquipment::setTunnelEndpoint(const std::string &value) { + if (tunnel_endpoint_ == value) { + return; + } + + tunnel_endpoint_ = value; + + updateDataplane(); + + logger()->info("User equipment updated {0}", toString()); +} + +uint32_t UserEquipment::getTeid() { + return teid_; +} + +void UserEquipment::setTeid(const uint32_t &value) { + if (teid_ == value) { + return; + } + + teid_ = value; + + updateDataplane(); + + logger()->info("User equipment updated {0}", toString()); +} + +std::string UserEquipment::toString() { + std::ostringstream out; + + out << "[ip=" << ip_ + << "; tunel-endpoint=" << tunnel_endpoint_ + << "; teid=" << teid_ << "]"; + + return out.str(); +} + +void UserEquipment::updateDataplane() { + struct user_equipment ue = { + .tunnel_endpoint = utils::ip_string_to_nbo_uint(tunnel_endpoint_), + .teid = htonl(teid_) + }; + + parent_.get_hash_table("user_equipments") + .set(utils::ip_string_to_nbo_uint(ip_), ue); +} \ No newline at end of file diff --git a/src/services/pcn-gtphandler/src/UserEquipment.h b/src/services/pcn-gtphandler/src/UserEquipment.h new file mode 100644 index 000000000..33919cfcd --- /dev/null +++ b/src/services/pcn-gtphandler/src/UserEquipment.h @@ -0,0 +1,64 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#pragma once + + +#include "../base/UserEquipmentBase.h" + + +struct user_equipment { + uint32_t tunnel_endpoint; + uint32_t teid; +}; + +class Gtphandler; + + +using namespace polycube::service::model; + +class UserEquipment : public UserEquipmentBase { + public: + UserEquipment(Gtphandler &parent, const UserEquipmentJsonObject &conf); + virtual ~UserEquipment(); + + /// + /// IP address of the User Equipment + /// + std::string getIp() override; + + /// + /// IP address of the Base Station that connects the User Equipment + /// + std::string getTunnelEndpoint() override; + void setTunnelEndpoint(const std::string &value) override; + + /// + /// Tunnel Endpoint ID of the GTP tunnel used by the User Equipment + /// + uint32_t getTeid() override; + void setTeid(const uint32_t &value) override; + + std::string toString(); + + private: + std::string ip_; + std::string tunnel_endpoint_; + uint32_t teid_; + + void updateDataplane(); +}; \ No newline at end of file diff --git a/src/services/pcn-gtphandler/src/api/GtphandlerApi.cpp b/src/services/pcn-gtphandler/src/api/GtphandlerApi.cpp new file mode 100644 index 000000000..e4298abe0 --- /dev/null +++ b/src/services/pcn-gtphandler/src/api/GtphandlerApi.cpp @@ -0,0 +1,513 @@ +/** +* gtphandler API generated from gtphandler.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + +#include "GtphandlerApi.h" +#include "GtphandlerApiImpl.h" + +using namespace polycube::service::model; +using namespace polycube::service::api::GtphandlerApiImpl; + +#ifdef __cplusplus +extern "C" { +#endif + +Response create_gtphandler_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + GtphandlerJsonObject unique_value { request_body }; + + unique_value.setName(unique_name); + create_gtphandler_by_id(unique_name, unique_value); + return { kCreated, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response create_gtphandler_user_equipment_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + std::string unique_ip; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "ip")) { + unique_ip = std::string { keys[i].value.string }; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + UserEquipmentJsonObject unique_value { request_body }; + + unique_value.setIp(unique_ip); + create_gtphandler_user_equipment_by_id(unique_name, unique_ip, unique_value); + return { kCreated, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response create_gtphandler_user_equipment_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + // Getting the body param + std::vector unique_value; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + std::vector unique_value; + for (auto &j : request_body) { + UserEquipmentJsonObject a { j }; + unique_value.push_back(a); + } + create_gtphandler_user_equipment_list_by_id(unique_name, unique_value); + return { kCreated, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response delete_gtphandler_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + + try { + delete_gtphandler_by_id(unique_name); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response delete_gtphandler_user_equipment_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + std::string unique_ip; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "ip")) { + unique_ip = std::string { keys[i].value.string }; + break; + } + } + + + try { + delete_gtphandler_user_equipment_by_id(unique_name, unique_ip); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response delete_gtphandler_user_equipment_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + + try { + delete_gtphandler_user_equipment_list_by_id(unique_name); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_gtphandler_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + + try { + + auto x = read_gtphandler_by_id(unique_name); + nlohmann::json response_body; + response_body = x.toJson(); + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_gtphandler_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + + + try { + + auto x = read_gtphandler_list_by_id(); + nlohmann::json response_body; + for (auto &i : x) { + response_body += i.toJson(); + } + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_gtphandler_user_equipment_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + std::string unique_ip; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "ip")) { + unique_ip = std::string { keys[i].value.string }; + break; + } + } + + + try { + + auto x = read_gtphandler_user_equipment_by_id(unique_name, unique_ip); + nlohmann::json response_body; + response_body = x.toJson(); + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_gtphandler_user_equipment_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + + try { + + auto x = read_gtphandler_user_equipment_list_by_id(unique_name); + nlohmann::json response_body; + for (auto &i : x) { + response_body += i.toJson(); + } + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_gtphandler_user_equipment_teid_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + std::string unique_ip; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "ip")) { + unique_ip = std::string { keys[i].value.string }; + break; + } + } + + + try { + + auto x = read_gtphandler_user_equipment_teid_by_id(unique_name, unique_ip); + nlohmann::json response_body; + response_body = x; + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_gtphandler_user_equipment_tunnel_endpoint_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + std::string unique_ip; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "ip")) { + unique_ip = std::string { keys[i].value.string }; + break; + } + } + + + try { + + auto x = read_gtphandler_user_equipment_tunnel_endpoint_by_id(unique_name, unique_ip); + nlohmann::json response_body; + response_body = x; + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response replace_gtphandler_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + GtphandlerJsonObject unique_value { request_body }; + + unique_value.setName(unique_name); + replace_gtphandler_by_id(unique_name, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response replace_gtphandler_user_equipment_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + std::string unique_ip; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "ip")) { + unique_ip = std::string { keys[i].value.string }; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + UserEquipmentJsonObject unique_value { request_body }; + + unique_value.setIp(unique_ip); + replace_gtphandler_user_equipment_by_id(unique_name, unique_ip, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response replace_gtphandler_user_equipment_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + // Getting the body param + std::vector unique_value; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + std::vector unique_value; + for (auto &j : request_body) { + UserEquipmentJsonObject a { j }; + unique_value.push_back(a); + } + replace_gtphandler_user_equipment_list_by_id(unique_name, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_gtphandler_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + GtphandlerJsonObject unique_value { request_body }; + + unique_value.setName(unique_name); + update_gtphandler_by_id(unique_name, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_gtphandler_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + + // Getting the body param + std::vector unique_value; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + std::vector unique_value; + for (auto &j : request_body) { + GtphandlerJsonObject a { j }; + unique_value.push_back(a); + } + update_gtphandler_list_by_id(unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_gtphandler_user_equipment_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + std::string unique_ip; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "ip")) { + unique_ip = std::string { keys[i].value.string }; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + UserEquipmentJsonObject unique_value { request_body }; + + unique_value.setIp(unique_ip); + update_gtphandler_user_equipment_by_id(unique_name, unique_ip, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_gtphandler_user_equipment_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + // Getting the body param + std::vector unique_value; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + std::vector unique_value; + for (auto &j : request_body) { + UserEquipmentJsonObject a { j }; + unique_value.push_back(a); + } + update_gtphandler_user_equipment_list_by_id(unique_name, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_gtphandler_user_equipment_teid_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + std::string unique_ip; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "ip")) { + unique_ip = std::string { keys[i].value.string }; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // The conversion is done automatically by the json library + uint32_t unique_value = request_body; + update_gtphandler_user_equipment_teid_by_id(unique_name, unique_ip, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_gtphandler_user_equipment_tunnel_endpoint_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + std::string unique_ip; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "ip")) { + unique_ip = std::string { keys[i].value.string }; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // The conversion is done automatically by the json library + std::string unique_value = request_body; + update_gtphandler_user_equipment_tunnel_endpoint_by_id(unique_name, unique_ip, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + + +Response gtphandler_list_by_id_help( + const char *name, const Key *keys, size_t num_keys) { + + nlohmann::json val = read_gtphandler_list_by_id_get_list(); + + return { kOk, ::strdup(val.dump().c_str()) }; +} + +Response gtphandler_user_equipment_list_by_id_help( + const char *name, const Key *keys, size_t num_keys) { + // Getting the path params + std::string unique_name { name }; + nlohmann::json val = read_gtphandler_user_equipment_list_by_id_get_list(unique_name); + + return { kOk, ::strdup(val.dump().c_str()) }; +} + +#ifdef __cplusplus +} +#endif + diff --git a/src/services/pcn-gtphandler/src/api/GtphandlerApi.h b/src/services/pcn-gtphandler/src/api/GtphandlerApi.h new file mode 100644 index 000000000..622a1e210 --- /dev/null +++ b/src/services/pcn-gtphandler/src/api/GtphandlerApi.h @@ -0,0 +1,62 @@ +/** +* gtphandler API generated from gtphandler.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* GtphandlerApi.h +* +*/ + +#pragma once + +#define POLYCUBE_SERVICE_NAME "gtphandler" + + +#include "polycube/services/response.h" +#include "polycube/services/shared_lib_elements.h" + +#include "GtphandlerJsonObject.h" +#include "UserEquipmentJsonObject.h" +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +Response create_gtphandler_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response create_gtphandler_user_equipment_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response create_gtphandler_user_equipment_list_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response delete_gtphandler_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response delete_gtphandler_user_equipment_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response delete_gtphandler_user_equipment_list_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_gtphandler_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_gtphandler_list_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_gtphandler_user_equipment_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_gtphandler_user_equipment_list_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_gtphandler_user_equipment_teid_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_gtphandler_user_equipment_tunnel_endpoint_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response replace_gtphandler_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response replace_gtphandler_user_equipment_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response replace_gtphandler_user_equipment_list_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_gtphandler_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_gtphandler_list_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_gtphandler_user_equipment_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_gtphandler_user_equipment_list_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_gtphandler_user_equipment_teid_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_gtphandler_user_equipment_tunnel_endpoint_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); + +Response gtphandler_list_by_id_help(const char *name, const Key *keys, size_t num_keys); +Response gtphandler_user_equipment_list_by_id_help(const char *name, const Key *keys, size_t num_keys); + + +#ifdef __cplusplus +} +#endif + diff --git a/src/services/pcn-gtphandler/src/api/GtphandlerApiImpl.cpp b/src/services/pcn-gtphandler/src/api/GtphandlerApiImpl.cpp new file mode 100644 index 000000000..a8f96df15 --- /dev/null +++ b/src/services/pcn-gtphandler/src/api/GtphandlerApiImpl.cpp @@ -0,0 +1,421 @@ +/** +* gtphandler API generated from gtphandler.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + +#include "GtphandlerApiImpl.h" + +namespace polycube { +namespace service { +namespace api { + +using namespace polycube::service::model; + +namespace GtphandlerApiImpl { +namespace { +std::unordered_map> cubes; +std::mutex cubes_mutex; + +std::shared_ptr get_cube(const std::string &name) { + std::lock_guard guard(cubes_mutex); + auto iter = cubes.find(name); + if (iter == cubes.end()) { + throw std::runtime_error("Cube " + name + " does not exist"); + } + + return iter->second; +} + +} + +void create_gtphandler_by_id(const std::string &name, const GtphandlerJsonObject &jsonObject) { + { + // check if name is valid before creating it + std::lock_guard guard(cubes_mutex); + if (cubes.count(name) != 0) { + throw std::runtime_error("There is already a cube with name " + name); + } + } + auto ptr = std::make_shared(name, jsonObject); + std::unordered_map>::iterator iter; + bool inserted; + + std::lock_guard guard(cubes_mutex); + std::tie(iter, inserted) = cubes.emplace(name, std::move(ptr)); + + if (!inserted) { + throw std::runtime_error("There is already a cube with name " + name); + } +} + +void replace_gtphandler_by_id(const std::string &name, const GtphandlerJsonObject &bridge){ + throw std::runtime_error("Method not supported!"); +} + +void delete_gtphandler_by_id(const std::string &name) { + std::lock_guard guard(cubes_mutex); + if (cubes.count(name) == 0) { + throw std::runtime_error("Cube " + name + " does not exist"); + } + cubes.erase(name); +} + +std::vector read_gtphandler_list_by_id() { + std::vector jsonObject_vect; + for(auto &i : cubes) { + auto m = get_cube(i.first); + jsonObject_vect.push_back(m->toJsonObject()); + } + return jsonObject_vect; +} + +std::vector> read_gtphandler_list_by_id_get_list() { + std::vector> r; + for (auto &x : cubes) { + nlohmann::fifo_map m; + m["name"] = x.first; + r.push_back(std::move(m)); + } + return r; +} + +/** +* @brief Create user-equipment by ID +* +* Create operation of resource: user-equipment* +* +* @param[in] name ID of name +* @param[in] ip ID of ip +* @param[in] value user-equipmentbody object +* +* Responses: +* +*/ +void +create_gtphandler_user_equipment_by_id(const std::string &name, const std::string &ip, const UserEquipmentJsonObject &value) { + auto gtphandler = get_cube(name); + + return gtphandler->addUserEquipment(ip, value); +} + +/** +* @brief Create user-equipment by ID +* +* Create operation of resource: user-equipment* +* +* @param[in] name ID of name +* @param[in] value user-equipmentbody object +* +* Responses: +* +*/ +void +create_gtphandler_user_equipment_list_by_id(const std::string &name, const std::vector &value) { + auto gtphandler = get_cube(name); + gtphandler->addUserEquipmentList(value); +} + +/** +* @brief Delete user-equipment by ID +* +* Delete operation of resource: user-equipment* +* +* @param[in] name ID of name +* @param[in] ip ID of ip +* +* Responses: +* +*/ +void +delete_gtphandler_user_equipment_by_id(const std::string &name, const std::string &ip) { + auto gtphandler = get_cube(name); + + return gtphandler->delUserEquipment(ip); +} + +/** +* @brief Delete user-equipment by ID +* +* Delete operation of resource: user-equipment* +* +* @param[in] name ID of name +* +* Responses: +* +*/ +void +delete_gtphandler_user_equipment_list_by_id(const std::string &name) { + auto gtphandler = get_cube(name); + gtphandler->delUserEquipmentList(); +} + +/** +* @brief Read gtphandler by ID +* +* Read operation of resource: gtphandler* +* +* @param[in] name ID of name +* +* Responses: +* GtphandlerJsonObject +*/ +GtphandlerJsonObject +read_gtphandler_by_id(const std::string &name) { + return get_cube(name)->toJsonObject(); + +} + +/** +* @brief Read user-equipment by ID +* +* Read operation of resource: user-equipment* +* +* @param[in] name ID of name +* @param[in] ip ID of ip +* +* Responses: +* UserEquipmentJsonObject +*/ +UserEquipmentJsonObject +read_gtphandler_user_equipment_by_id(const std::string &name, const std::string &ip) { + auto gtphandler = get_cube(name); + return gtphandler->getUserEquipment(ip)->toJsonObject(); + +} + +/** +* @brief Read user-equipment by ID +* +* Read operation of resource: user-equipment* +* +* @param[in] name ID of name +* +* Responses: +* std::vector +*/ +std::vector +read_gtphandler_user_equipment_list_by_id(const std::string &name) { + auto gtphandler = get_cube(name); + auto &&userEquipment = gtphandler->getUserEquipmentList(); + std::vector m; + for(auto &i : userEquipment) + m.push_back(i->toJsonObject()); + return m; +} + +/** +* @brief Read teid by ID +* +* Read operation of resource: teid* +* +* @param[in] name ID of name +* @param[in] ip ID of ip +* +* Responses: +* uint32_t +*/ +uint32_t +read_gtphandler_user_equipment_teid_by_id(const std::string &name, const std::string &ip) { + auto gtphandler = get_cube(name); + auto userEquipment = gtphandler->getUserEquipment(ip); + return userEquipment->getTeid(); + +} + +/** +* @brief Read tunnel-endpoint by ID +* +* Read operation of resource: tunnel-endpoint* +* +* @param[in] name ID of name +* @param[in] ip ID of ip +* +* Responses: +* std::string +*/ +std::string +read_gtphandler_user_equipment_tunnel_endpoint_by_id(const std::string &name, const std::string &ip) { + auto gtphandler = get_cube(name); + auto userEquipment = gtphandler->getUserEquipment(ip); + return userEquipment->getTunnelEndpoint(); + +} + +/** +* @brief Replace user-equipment by ID +* +* Replace operation of resource: user-equipment* +* +* @param[in] name ID of name +* @param[in] ip ID of ip +* @param[in] value user-equipmentbody object +* +* Responses: +* +*/ +void +replace_gtphandler_user_equipment_by_id(const std::string &name, const std::string &ip, const UserEquipmentJsonObject &value) { + auto gtphandler = get_cube(name); + + return gtphandler->replaceUserEquipment(ip, value); +} + +/** +* @brief Replace user-equipment by ID +* +* Replace operation of resource: user-equipment* +* +* @param[in] name ID of name +* @param[in] value user-equipmentbody object +* +* Responses: +* +*/ +void +replace_gtphandler_user_equipment_list_by_id(const std::string &name, const std::vector &value) { + throw std::runtime_error("Method not supported"); +} + +/** +* @brief Update gtphandler by ID +* +* Update operation of resource: gtphandler* +* +* @param[in] name ID of name +* @param[in] value gtphandlerbody object +* +* Responses: +* +*/ +void +update_gtphandler_by_id(const std::string &name, const GtphandlerJsonObject &value) { + auto gtphandler = get_cube(name); + + return gtphandler->update(value); +} + +/** +* @brief Update gtphandler by ID +* +* Update operation of resource: gtphandler* +* +* @param[in] value gtphandlerbody object +* +* Responses: +* +*/ +void +update_gtphandler_list_by_id(const std::vector &value) { + throw std::runtime_error("Method not supported"); +} + +/** +* @brief Update user-equipment by ID +* +* Update operation of resource: user-equipment* +* +* @param[in] name ID of name +* @param[in] ip ID of ip +* @param[in] value user-equipmentbody object +* +* Responses: +* +*/ +void +update_gtphandler_user_equipment_by_id(const std::string &name, const std::string &ip, const UserEquipmentJsonObject &value) { + auto gtphandler = get_cube(name); + auto userEquipment = gtphandler->getUserEquipment(ip); + + return userEquipment->update(value); +} + +/** +* @brief Update user-equipment by ID +* +* Update operation of resource: user-equipment* +* +* @param[in] name ID of name +* @param[in] value user-equipmentbody object +* +* Responses: +* +*/ +void +update_gtphandler_user_equipment_list_by_id(const std::string &name, const std::vector &value) { + throw std::runtime_error("Method not supported"); +} + +/** +* @brief Update teid by ID +* +* Update operation of resource: teid* +* +* @param[in] name ID of name +* @param[in] ip ID of ip +* @param[in] value Tunnel Endpoint ID of the GTP tunnel used by the User Equipment +* +* Responses: +* +*/ +void +update_gtphandler_user_equipment_teid_by_id(const std::string &name, const std::string &ip, const uint32_t &value) { + auto gtphandler = get_cube(name); + auto userEquipment = gtphandler->getUserEquipment(ip); + + return userEquipment->setTeid(value); +} + +/** +* @brief Update tunnel-endpoint by ID +* +* Update operation of resource: tunnel-endpoint* +* +* @param[in] name ID of name +* @param[in] ip ID of ip +* @param[in] value IP address of the Base Station that connects the User Equipment +* +* Responses: +* +*/ +void +update_gtphandler_user_equipment_tunnel_endpoint_by_id(const std::string &name, const std::string &ip, const std::string &value) { + auto gtphandler = get_cube(name); + auto userEquipment = gtphandler->getUserEquipment(ip); + + return userEquipment->setTunnelEndpoint(value); +} + + + +/* + * help related + */ + +std::vector> read_gtphandler_user_equipment_list_by_id_get_list(const std::string &name) { + std::vector> r; + auto &>phandler = get_cube(name); + + auto &&userEquipment = gtphandler->getUserEquipmentList(); + for(auto &i : userEquipment) { + nlohmann::fifo_map keys; + + keys["ip"] = i->getIp(); + + r.push_back(keys); + } + return r; +} + + +} + +} +} +} + diff --git a/src/services/pcn-gtphandler/src/api/GtphandlerApiImpl.h b/src/services/pcn-gtphandler/src/api/GtphandlerApiImpl.h new file mode 100644 index 000000000..7323a8c16 --- /dev/null +++ b/src/services/pcn-gtphandler/src/api/GtphandlerApiImpl.h @@ -0,0 +1,66 @@ +/** +* gtphandler API generated from gtphandler.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* GtphandlerApiImpl.h +* +* +*/ + +#pragma once + + +#include +#include +#include +#include "../Gtphandler.h" + +#include "GtphandlerJsonObject.h" +#include "UserEquipmentJsonObject.h" +#include + +namespace polycube { +namespace service { +namespace api { + +using namespace polycube::service::model; + +namespace GtphandlerApiImpl { + void create_gtphandler_by_id(const std::string &name, const GtphandlerJsonObject &value); + void create_gtphandler_user_equipment_by_id(const std::string &name, const std::string &ip, const UserEquipmentJsonObject &value); + void create_gtphandler_user_equipment_list_by_id(const std::string &name, const std::vector &value); + void delete_gtphandler_by_id(const std::string &name); + void delete_gtphandler_user_equipment_by_id(const std::string &name, const std::string &ip); + void delete_gtphandler_user_equipment_list_by_id(const std::string &name); + GtphandlerJsonObject read_gtphandler_by_id(const std::string &name); + std::vector read_gtphandler_list_by_id(); + UserEquipmentJsonObject read_gtphandler_user_equipment_by_id(const std::string &name, const std::string &ip); + std::vector read_gtphandler_user_equipment_list_by_id(const std::string &name); + uint32_t read_gtphandler_user_equipment_teid_by_id(const std::string &name, const std::string &ip); + std::string read_gtphandler_user_equipment_tunnel_endpoint_by_id(const std::string &name, const std::string &ip); + void replace_gtphandler_by_id(const std::string &name, const GtphandlerJsonObject &value); + void replace_gtphandler_user_equipment_by_id(const std::string &name, const std::string &ip, const UserEquipmentJsonObject &value); + void replace_gtphandler_user_equipment_list_by_id(const std::string &name, const std::vector &value); + void update_gtphandler_by_id(const std::string &name, const GtphandlerJsonObject &value); + void update_gtphandler_list_by_id(const std::vector &value); + void update_gtphandler_user_equipment_by_id(const std::string &name, const std::string &ip, const UserEquipmentJsonObject &value); + void update_gtphandler_user_equipment_list_by_id(const std::string &name, const std::vector &value); + void update_gtphandler_user_equipment_teid_by_id(const std::string &name, const std::string &ip, const uint32_t &value); + void update_gtphandler_user_equipment_tunnel_endpoint_by_id(const std::string &name, const std::string &ip, const std::string &value); + + /* help related */ + std::vector> read_gtphandler_list_by_id_get_list(); + std::vector> read_gtphandler_user_equipment_list_by_id_get_list(const std::string &name); + +} +} +} +} + diff --git a/src/services/pcn-gtphandler/src/base/GtphandlerBase.cpp b/src/services/pcn-gtphandler/src/base/GtphandlerBase.cpp new file mode 100644 index 000000000..9ac9b0586 --- /dev/null +++ b/src/services/pcn-gtphandler/src/base/GtphandlerBase.cpp @@ -0,0 +1,66 @@ +/** +* gtphandler API generated from gtphandler.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + +#include "GtphandlerBase.h" + +GtphandlerBase::GtphandlerBase(const std::string name) { + logger()->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [Gtphandler] [%n] [%l] %v"); +} + + + +GtphandlerBase::~GtphandlerBase() {} + +void GtphandlerBase::update(const GtphandlerJsonObject &conf) { + set_conf(conf.getBase()); + + if (conf.userEquipmentIsSet()) { + for (auto &i : conf.getUserEquipment()) { + auto ip = i.getIp(); + auto m = getUserEquipment(ip); + m->update(i); + } + } +} + +GtphandlerJsonObject GtphandlerBase::toJsonObject() { + GtphandlerJsonObject conf; + conf.setBase(to_json()); + + conf.setName(getName()); + for(auto &i : getUserEquipmentList()) { + conf.addUserEquipment(i->toJsonObject()); + } + + return conf; +} +void GtphandlerBase::addUserEquipmentList(const std::vector &conf) { + for (auto &i : conf) { + std::string ip_ = i.getIp(); + addUserEquipment(ip_, i); + } +} + +void GtphandlerBase::replaceUserEquipment(const std::string &ip, const UserEquipmentJsonObject &conf) { + delUserEquipment(ip); + std::string ip_ = conf.getIp(); + addUserEquipment(ip_, conf); +} + +void GtphandlerBase::delUserEquipmentList() { + auto elements = getUserEquipmentList(); + for (auto &i : elements) { + std::string ip_ = i->getIp(); + delUserEquipment(ip_); + } +} + + diff --git a/src/services/pcn-gtphandler/src/base/GtphandlerBase.h b/src/services/pcn-gtphandler/src/base/GtphandlerBase.h new file mode 100644 index 000000000..d821227a3 --- /dev/null +++ b/src/services/pcn-gtphandler/src/base/GtphandlerBase.h @@ -0,0 +1,53 @@ +/** +* gtphandler API generated from gtphandler.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* GtphandlerBase.h +* +* +*/ + +#pragma once + +#include "../serializer/GtphandlerJsonObject.h" + +#include "../UserEquipment.h" + +#include "polycube/services/transparent_cube.h" + + + +#include "polycube/services/utils.h" +#include "polycube/services/fifo_map.hpp" + +#include + +using namespace polycube::service::model; + + +class GtphandlerBase: public virtual polycube::service::TransparentCube { + public: + GtphandlerBase(const std::string name); + + virtual ~GtphandlerBase(); + virtual void update(const GtphandlerJsonObject &conf); + virtual GtphandlerJsonObject toJsonObject(); + + /// + /// User Equipment connected with GTP tunnel + /// + virtual std::shared_ptr getUserEquipment(const std::string &ip) = 0; + virtual std::vector> getUserEquipmentList() = 0; + virtual void addUserEquipment(const std::string &ip, const UserEquipmentJsonObject &conf) = 0; + virtual void addUserEquipmentList(const std::vector &conf); + virtual void replaceUserEquipment(const std::string &ip, const UserEquipmentJsonObject &conf); + virtual void delUserEquipment(const std::string &ip) = 0; + virtual void delUserEquipmentList(); +}; diff --git a/src/services/pcn-gtphandler/src/base/UserEquipmentBase.cpp b/src/services/pcn-gtphandler/src/base/UserEquipmentBase.cpp new file mode 100644 index 000000000..ccaa27eb8 --- /dev/null +++ b/src/services/pcn-gtphandler/src/base/UserEquipmentBase.cpp @@ -0,0 +1,44 @@ +/** +* gtphandler API generated from gtphandler.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + +#include "UserEquipmentBase.h" +#include "../Gtphandler.h" + + +UserEquipmentBase::UserEquipmentBase(Gtphandler &parent) + : parent_(parent) {} + +UserEquipmentBase::~UserEquipmentBase() {} + +void UserEquipmentBase::update(const UserEquipmentJsonObject &conf) { + + if (conf.tunnelEndpointIsSet()) { + setTunnelEndpoint(conf.getTunnelEndpoint()); + } + if (conf.teidIsSet()) { + setTeid(conf.getTeid()); + } +} + +UserEquipmentJsonObject UserEquipmentBase::toJsonObject() { + UserEquipmentJsonObject conf; + + conf.setIp(getIp()); + conf.setTunnelEndpoint(getTunnelEndpoint()); + conf.setTeid(getTeid()); + + return conf; +} + +std::shared_ptr UserEquipmentBase::logger() { + return parent_.logger(); +} + diff --git a/src/services/pcn-gtphandler/src/base/UserEquipmentBase.h b/src/services/pcn-gtphandler/src/base/UserEquipmentBase.h new file mode 100644 index 000000000..b1f6ec38d --- /dev/null +++ b/src/services/pcn-gtphandler/src/base/UserEquipmentBase.h @@ -0,0 +1,61 @@ +/** +* gtphandler API generated from gtphandler.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* UserEquipmentBase.h +* +* +*/ + +#pragma once + +#include "../serializer/UserEquipmentJsonObject.h" + + + + + + +#include + +using namespace polycube::service::model; + +class Gtphandler; + +class UserEquipmentBase { + public: + + UserEquipmentBase(Gtphandler &parent); + + virtual ~UserEquipmentBase(); + virtual void update(const UserEquipmentJsonObject &conf); + virtual UserEquipmentJsonObject toJsonObject(); + + /// + /// IP address of the User Equipment + /// + virtual std::string getIp() = 0; + + /// + /// IP address of the Base Station that connects the User Equipment + /// + virtual std::string getTunnelEndpoint() = 0; + virtual void setTunnelEndpoint(const std::string &value) = 0; + + /// + /// Tunnel Endpoint ID of the GTP tunnel used by the User Equipment + /// + virtual uint32_t getTeid() = 0; + virtual void setTeid(const uint32_t &value) = 0; + + std::shared_ptr logger(); + protected: + Gtphandler &parent_; +}; diff --git a/src/services/pcn-gtphandler/src/serializer/GtphandlerJsonObject.cpp b/src/services/pcn-gtphandler/src/serializer/GtphandlerJsonObject.cpp new file mode 100644 index 000000000..ba503e4b1 --- /dev/null +++ b/src/services/pcn-gtphandler/src/serializer/GtphandlerJsonObject.cpp @@ -0,0 +1,106 @@ +/** +* gtphandler API generated from gtphandler.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + + +#include "GtphandlerJsonObject.h" +#include + +namespace polycube { +namespace service { +namespace model { + +GtphandlerJsonObject::GtphandlerJsonObject() { + m_nameIsSet = false; + m_userEquipmentIsSet = false; +} + +GtphandlerJsonObject::GtphandlerJsonObject(const nlohmann::json &val) : + JsonObjectBase(val) { + m_nameIsSet = false; + m_userEquipmentIsSet = false; + + + if (val.count("name")) { + setName(val.at("name").get()); + } + + if (val.count("user-equipment")) { + for (auto& item : val["user-equipment"]) { + UserEquipmentJsonObject newItem{ item }; + m_userEquipment.push_back(newItem); + } + + m_userEquipmentIsSet = true; + } +} + +nlohmann::json GtphandlerJsonObject::toJson() const { + nlohmann::json val = nlohmann::json::object(); + if (!getBase().is_null()) { + val.update(getBase()); + } + + if (m_nameIsSet) { + val["name"] = m_name; + } + + { + nlohmann::json jsonArray; + for (auto& item : m_userEquipment) { + jsonArray.push_back(JsonObjectBase::toJson(item)); + } + + if (jsonArray.size() > 0) { + val["user-equipment"] = jsonArray; + } + } + + return val; +} + +std::string GtphandlerJsonObject::getName() const { + return m_name; +} + +void GtphandlerJsonObject::setName(std::string value) { + m_name = value; + m_nameIsSet = true; +} + +bool GtphandlerJsonObject::nameIsSet() const { + return m_nameIsSet; +} + + + +const std::vector& GtphandlerJsonObject::getUserEquipment() const{ + return m_userEquipment; +} + +void GtphandlerJsonObject::addUserEquipment(UserEquipmentJsonObject value) { + m_userEquipment.push_back(value); + m_userEquipmentIsSet = true; +} + + +bool GtphandlerJsonObject::userEquipmentIsSet() const { + return m_userEquipmentIsSet; +} + +void GtphandlerJsonObject::unsetUserEquipment() { + m_userEquipmentIsSet = false; +} + + +} +} +} + diff --git a/src/services/pcn-gtphandler/src/serializer/GtphandlerJsonObject.h b/src/services/pcn-gtphandler/src/serializer/GtphandlerJsonObject.h new file mode 100644 index 000000000..343c53260 --- /dev/null +++ b/src/services/pcn-gtphandler/src/serializer/GtphandlerJsonObject.h @@ -0,0 +1,67 @@ +/** +* gtphandler API generated from gtphandler.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* GtphandlerJsonObject.h +* +* +*/ + +#pragma once + + +#include "JsonObjectBase.h" + +#include "UserEquipmentJsonObject.h" +#include +#include "polycube/services/cube.h" + +namespace polycube { +namespace service { +namespace model { + + +/// +/// +/// +class GtphandlerJsonObject : public JsonObjectBase { +public: + GtphandlerJsonObject(); + GtphandlerJsonObject(const nlohmann::json &json); + ~GtphandlerJsonObject() final = default; + nlohmann::json toJson() const final; + + + /// + /// Name of the gtphandler service + /// + std::string getName() const; + void setName(std::string value); + bool nameIsSet() const; + + /// + /// User Equipment connected with GTP tunnel + /// + const std::vector& getUserEquipment() const; + void addUserEquipment(UserEquipmentJsonObject value); + bool userEquipmentIsSet() const; + void unsetUserEquipment(); + +private: + std::string m_name; + bool m_nameIsSet; + std::vector m_userEquipment; + bool m_userEquipmentIsSet; +}; + +} +} +} + diff --git a/src/services/pcn-gtphandler/src/serializer/JsonObjectBase.cpp b/src/services/pcn-gtphandler/src/serializer/JsonObjectBase.cpp new file mode 100644 index 000000000..6fa5e01a4 --- /dev/null +++ b/src/services/pcn-gtphandler/src/serializer/JsonObjectBase.cpp @@ -0,0 +1,69 @@ +/** +* gtphandler API generated from gtphandler.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +#include "JsonObjectBase.h" + +namespace polycube { +namespace service { +namespace model { + +JsonObjectBase::JsonObjectBase(const nlohmann::json &base) : base_(base) {} + +bool JsonObjectBase::iequals(const std::string &a, const std::string &b) { + if(a.size() != b.size()) + return false; + for (unsigned int i = 0; i < a.size(); i++){ + if(tolower(a[i]) != tolower(b[i])) + return false; + } + return true; +} + +std::string JsonObjectBase::toJson(const std::string& value) { + return value; +} + +std::string JsonObjectBase::toJson(const std::time_t& value) { + char buf[sizeof "2011-10-08T07:07:09Z"]; + strftime(buf, sizeof buf, "%FT%TZ", gmtime(&value)); + return buf; +} + +int32_t JsonObjectBase::toJson(int32_t value) { + return value; +} + +int64_t JsonObjectBase::toJson(int64_t value) { + return value; +} + +double JsonObjectBase::toJson(double value) { + return value; +} + +bool JsonObjectBase::toJson(bool value) { + return value; +} + +nlohmann::json JsonObjectBase::toJson(const JsonObjectBase &content) { + return content.toJson(); +} + +const nlohmann::json &JsonObjectBase::getBase() const { + return base_; +} + +void JsonObjectBase::setBase(const nlohmann::json &base) { + base_ = base; +} + +} +} +} diff --git a/src/services/pcn-gtphandler/src/serializer/JsonObjectBase.h b/src/services/pcn-gtphandler/src/serializer/JsonObjectBase.h new file mode 100644 index 000000000..e5b3ab8aa --- /dev/null +++ b/src/services/pcn-gtphandler/src/serializer/JsonObjectBase.h @@ -0,0 +1,55 @@ +/** +* gtphandler API generated from gtphandler.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* JsonObjectBase.h +* +* This is the base class for all model classes +*/ + +#pragma once + + +#include "polycube/services/json.hpp" +#include "polycube/services/fifo_map.hpp" +#include +#include + +namespace polycube { +namespace service { +namespace model { + +class JsonObjectBase { + public: + JsonObjectBase() = default; + JsonObjectBase(const nlohmann::json &base); + virtual ~JsonObjectBase() = default; + + virtual nlohmann::json toJson() const = 0; + + static bool iequals(const std::string &a, const std::string &b); + static std::string toJson(const std::string& value); + static std::string toJson(const std::time_t& value); + static int32_t toJson(int32_t value); + static int64_t toJson(int64_t value); + static double toJson(double value); + static bool toJson(bool value); + static nlohmann::json toJson(const JsonObjectBase &content); + + const nlohmann::json &getBase() const; + void setBase(const nlohmann::json &base); + + private: + nlohmann::json base_; +}; + +} +} +} diff --git a/src/services/pcn-gtphandler/src/serializer/UserEquipmentJsonObject.cpp b/src/services/pcn-gtphandler/src/serializer/UserEquipmentJsonObject.cpp new file mode 100644 index 000000000..ba5d18507 --- /dev/null +++ b/src/services/pcn-gtphandler/src/serializer/UserEquipmentJsonObject.cpp @@ -0,0 +1,116 @@ +/** +* gtphandler API generated from gtphandler.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + + +#include "UserEquipmentJsonObject.h" +#include + +namespace polycube { +namespace service { +namespace model { + +UserEquipmentJsonObject::UserEquipmentJsonObject() { + m_ipIsSet = false; + m_tunnelEndpointIsSet = false; + m_teidIsSet = false; +} + +UserEquipmentJsonObject::UserEquipmentJsonObject(const nlohmann::json &val) : + JsonObjectBase(val) { + m_ipIsSet = false; + m_tunnelEndpointIsSet = false; + m_teidIsSet = false; + + + if (val.count("ip")) { + setIp(val.at("ip").get()); + } + + if (val.count("tunnel-endpoint")) { + setTunnelEndpoint(val.at("tunnel-endpoint").get()); + } + + if (val.count("teid")) { + setTeid(val.at("teid").get()); + } +} + +nlohmann::json UserEquipmentJsonObject::toJson() const { + nlohmann::json val = nlohmann::json::object(); + if (!getBase().is_null()) { + val.update(getBase()); + } + + if (m_ipIsSet) { + val["ip"] = m_ip; + } + + if (m_tunnelEndpointIsSet) { + val["tunnel-endpoint"] = m_tunnelEndpoint; + } + + if (m_teidIsSet) { + val["teid"] = m_teid; + } + + return val; +} + +std::string UserEquipmentJsonObject::getIp() const { + return m_ip; +} + +void UserEquipmentJsonObject::setIp(std::string value) { + m_ip = value; + m_ipIsSet = true; +} + +bool UserEquipmentJsonObject::ipIsSet() const { + return m_ipIsSet; +} + + + +std::string UserEquipmentJsonObject::getTunnelEndpoint() const { + return m_tunnelEndpoint; +} + +void UserEquipmentJsonObject::setTunnelEndpoint(std::string value) { + m_tunnelEndpoint = value; + m_tunnelEndpointIsSet = true; +} + +bool UserEquipmentJsonObject::tunnelEndpointIsSet() const { + return m_tunnelEndpointIsSet; +} + + + +uint32_t UserEquipmentJsonObject::getTeid() const { + return m_teid; +} + +void UserEquipmentJsonObject::setTeid(uint32_t value) { + m_teid = value; + m_teidIsSet = true; +} + +bool UserEquipmentJsonObject::teidIsSet() const { + return m_teidIsSet; +} + + + + +} +} +} + diff --git a/src/services/pcn-gtphandler/src/serializer/UserEquipmentJsonObject.h b/src/services/pcn-gtphandler/src/serializer/UserEquipmentJsonObject.h new file mode 100644 index 000000000..75a2c7091 --- /dev/null +++ b/src/services/pcn-gtphandler/src/serializer/UserEquipmentJsonObject.h @@ -0,0 +1,72 @@ +/** +* gtphandler API generated from gtphandler.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* UserEquipmentJsonObject.h +* +* +*/ + +#pragma once + + +#include "JsonObjectBase.h" + + +namespace polycube { +namespace service { +namespace model { + + +/// +/// +/// +class UserEquipmentJsonObject : public JsonObjectBase { +public: + UserEquipmentJsonObject(); + UserEquipmentJsonObject(const nlohmann::json &json); + ~UserEquipmentJsonObject() final = default; + nlohmann::json toJson() const final; + + + /// + /// IP address of the User Equipment + /// + std::string getIp() const; + void setIp(std::string value); + bool ipIsSet() const; + + /// + /// IP address of the Base Station that connects the User Equipment + /// + std::string getTunnelEndpoint() const; + void setTunnelEndpoint(std::string value); + bool tunnelEndpointIsSet() const; + + /// + /// Tunnel Endpoint ID of the GTP tunnel used by the User Equipment + /// + uint32_t getTeid() const; + void setTeid(uint32_t value); + bool teidIsSet() const; + +private: + std::string m_ip; + bool m_ipIsSet; + std::string m_tunnelEndpoint; + bool m_tunnelEndpointIsSet; + uint32_t m_teid; + bool m_teidIsSet; +}; + +} +} +} + diff --git a/src/services/pcn-gtphandler/test/test.sh b/src/services/pcn-gtphandler/test/test.sh new file mode 100755 index 000000000..1333fade5 --- /dev/null +++ b/src/services/pcn-gtphandler/test/test.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +LIBGTPNL=$HOME/libgtpnl/tools + +function cleanup { + set +e + set +x + + echo "Cleaning up..." + + polycubectl gh1 del + sudo ip netns exec ns1 $LIBGTPNL/gtp-link del gtp1 > /dev/null 2>&1 + sudo pkill gtp-link > /dev/null 2>&1 + sudo arp -d 10.0.0.2 + sudo ip route del 172.99.0.1/32 via 10.0.0.2 + sudo ip link del veth1 + sudo ip netns del ns1 +} +trap cleanup EXIT + +set -x + +# Remove ns and veth if already exist +sudo ip netns del ns1 > /dev/null 2>&1 +sudo ip link del veth1 > /dev/null 2>&1 +sudo ip addr del 172.0.0.1/24 dev lo > /dev/null 2>&1 + +sudo ip netns add ns1 + +# Configure the UE +sudo ip netns exec ns1 ip addr add 172.99.0.1/32 dev lo +sudo ip netns exec ns1 ip link set lo up + +sudo ip link add veth1_ type veth peer name veth1 + +# Configure the BS +sudo ip link set veth1_ netns ns1 +sudo ip netns exec ns1 ip link set dev veth1_ up +sudo ip netns exec ns1 ip addr add 10.0.0.2/24 dev veth1_ +BS_MAC=$(sudo ip netns exec ns1 ip addr show veth1_ | grep link/ether | awk -F ' ' '{print $2}') + +# Configure the GW +sudo ip link set dev veth1 up +sudo ip addr add 10.0.1.1/24 dev veth1 +sudo ip addr add 10.0.0.1/24 dev veth1 +sudo ip route add 172.99.0.1/32 via 10.0.0.2 +sudo arp -s 10.0.0.2 ${BS_MAC} + +# Configure the GTP tunnel +sudo ip netns exec ns1 $LIBGTPNL/gtp-link add gtp1 --sgsn & +sleep 1 +sudo ip netns exec ns1 $LIBGTPNL/gtp-tunnel add gtp1 v1 100 100 172.99.0.1 10.0.0.1 +sudo ip netns exec ns1 route add default dev gtp1 + +set -e + +# Configure the gtphandler +polycubectl gtphandler add gh1 +polycubectl attach gh1 veth1 +polycubectl gh1 user-equipment add 172.99.0.1 tunnel-endpoint=10.0.0.2 teid=100 + +ping -I 10.0.1.1 -c 1 172.99.0.1 +sudo ip netns exec ns1 ping -c 1 10.0.1.1 + +set +x + +echo "+++ ALL TESTS PASSED +++" \ No newline at end of file From 3789652dee101b605ffed024bb1a3b6e75d89bb1 Mon Sep 17 00:00:00 2001 From: FedeParola Date: Wed, 3 Jun 2020 12:13:55 +0200 Subject: [PATCH 02/12] Retrieve TEID from pkt metadata insted of config --- .../pcn-gtphandler/.swagger-codegen-ignore | 1 + .../pcn-gtphandler/datamodel/gtphandler.yang | 7 --- .../pcn-gtphandler/src/Gtphandler.cpp | 63 +++++++++++-------- src/services/pcn-gtphandler/src/Gtphandler.h | 22 +++---- .../pcn-gtphandler/src/Gtphandler_dp_egress.c | 47 +++++++------- .../src/Gtphandler_dp_ingress.c | 26 ++++---- .../pcn-gtphandler/src/UserEquipment.cpp | 42 +++---------- .../pcn-gtphandler/src/UserEquipment.h | 16 ----- .../pcn-gtphandler/src/api/GtphandlerApi.cpp | 51 --------------- .../pcn-gtphandler/src/api/GtphandlerApi.h | 2 - .../src/api/GtphandlerApiImpl.cpp | 39 ------------ .../src/api/GtphandlerApiImpl.h | 2 - .../src/base/UserEquipmentBase.cpp | 4 -- .../src/base/UserEquipmentBase.h | 6 -- .../serializer/UserEquipmentJsonObject.cpp | 25 -------- .../src/serializer/UserEquipmentJsonObject.h | 9 --- src/services/pcn-gtphandler/test/test.sh | 4 +- 17 files changed, 91 insertions(+), 275 deletions(-) diff --git a/src/services/pcn-gtphandler/.swagger-codegen-ignore b/src/services/pcn-gtphandler/.swagger-codegen-ignore index f90131c08..aa4a98a96 100644 --- a/src/services/pcn-gtphandler/.swagger-codegen-ignore +++ b/src/services/pcn-gtphandler/.swagger-codegen-ignore @@ -8,6 +8,7 @@ src/*.c src/*.cpp src/*.h +src/CMakeLists.txt !src/*Interface.h !src/*JsonObject.h diff --git a/src/services/pcn-gtphandler/datamodel/gtphandler.yang b/src/services/pcn-gtphandler/datamodel/gtphandler.yang index cc5a04981..33675afb9 100644 --- a/src/services/pcn-gtphandler/datamodel/gtphandler.yang +++ b/src/services/pcn-gtphandler/datamodel/gtphandler.yang @@ -35,12 +35,5 @@ module gtphandler { description "IP address of the Base Station that connects the User Equipment"; polycube-base:cli-example "110.0.0.1"; } - - leaf teid { - type uint32; - mandatory true; - description "Tunnel Endpoint ID of the GTP tunnel used by the User Equipment"; - polycube-base:cli-example "56000"; - } } } diff --git a/src/services/pcn-gtphandler/src/Gtphandler.cpp b/src/services/pcn-gtphandler/src/Gtphandler.cpp index 09eb05eec..22d14f5b6 100644 --- a/src/services/pcn-gtphandler/src/Gtphandler.cpp +++ b/src/services/pcn-gtphandler/src/Gtphandler.cpp @@ -14,12 +14,10 @@ * limitations under the License. */ - #include "Gtphandler.h" #include "Gtphandler_dp_ingress.h" #include "Gtphandler_dp_egress.h" - using namespace polycube::service; Gtphandler::Gtphandler(const std::string name, const GtphandlerJsonObject &conf) @@ -27,12 +25,15 @@ Gtphandler::Gtphandler(const std::string name, const GtphandlerJsonObject &conf) GtphandlerBase(name) { logger()->info("Creating Gtphandler instance"); - add_program(getWrapperCode() + gtphandler_code_ingress, 0, ProgramType::INGRESS); - add_program(getWrapperCode() + gtphandler_code_egress, 0, ProgramType::EGRESS); + add_program(getWrapperCode() + gtphandler_code_ingress, 0, + ProgramType::INGRESS); + add_program(getWrapperCode() + gtphandler_code_egress, 0, + ProgramType::EGRESS); addUserEquipmentList(conf.getUserEquipment()); - ParameterEventCallback cb_ip = [&](const std::string ¶meter, const std::string &value) { + ParameterEventCallback cb_ip = [&](const std::string ¶meter, + const std::string &value) { local_ip_ = utils::get_ip_from_string(value); logger()->info("Local IP set to {0}", local_ip_); @@ -42,7 +43,8 @@ Gtphandler::Gtphandler(const std::string name, const GtphandlerJsonObject &conf) }; subscribe_parent_parameter("ip", cb_ip); - ParameterEventCallback cb_mac = [&](const std::string ¶meter, const std::string &value) { + ParameterEventCallback cb_mac = [&](const std::string ¶meter, + const std::string &value) { local_mac_ = value; logger()->info("Local MAC set to {0}", local_mac_); @@ -66,56 +68,61 @@ void Gtphandler::packet_in(polycube::service::Direction direction, logger()->debug("Packet received"); } -std::shared_ptr Gtphandler::getUserEquipment(const std::string &ip) { - if (user_equipments_.count(ip) == 0) { +std::shared_ptr Gtphandler::getUserEquipment( + const std::string &ip) { + if (user_equipment_map_.count(ip) == 0) { throw std::runtime_error("No user equipment with the given ip"); } - return user_equipments_.at(ip); + return user_equipment_map_.at(ip); } std::vector> Gtphandler::getUserEquipmentList() { - std::vector> user_equipments_v; + std::vector> user_equipment_map_v; - user_equipments_v.reserve(user_equipments_v.size()); + user_equipment_map_v.reserve(user_equipment_map_v.size()); - for (auto const &entry : user_equipments_) { - user_equipments_v.push_back(entry.second); + for (auto const &entry : user_equipment_map_) { + user_equipment_map_v.push_back(entry.second); } - return user_equipments_v; + return user_equipment_map_v; } -void Gtphandler::addUserEquipment(const std::string &ip, const UserEquipmentJsonObject &conf) { - if (user_equipments_.count(ip) != 0) { - throw std::runtime_error("User equipment with the given ip already registered"); +void Gtphandler::addUserEquipment(const std::string &ip, + const UserEquipmentJsonObject &conf) { + if (user_equipment_map_.count(ip) != 0) { + throw std::runtime_error( + "User equipment with the given ip already registered"); } - if (user_equipments_.size() == MAX_USER_EQUIPMENTS) { + if (user_equipment_map_.size() == MAX_USER_EQUIPMENT) { throw std::runtime_error("Maximum number of user equipments reached"); } - user_equipments_[ip] = std::make_shared(*this, conf); + user_equipment_map_[ip] = std::make_shared(*this, conf); } // Basic default implementation, place your extension here (if needed) -void Gtphandler::addUserEquipmentList(const std::vector &conf) { +void Gtphandler::addUserEquipmentList( + const std::vector &conf) { // call default implementation in base class GtphandlerBase::addUserEquipmentList(conf); } // Basic default implementation, place your extension here (if needed) -void Gtphandler::replaceUserEquipment(const std::string &ip, const UserEquipmentJsonObject &conf) { +void Gtphandler::replaceUserEquipment(const std::string &ip, + const UserEquipmentJsonObject &conf) { // call default implementation in base class GtphandlerBase::replaceUserEquipment(ip, conf); } void Gtphandler::delUserEquipment(const std::string &ip) { - if (user_equipments_.count(ip) == 0) { + if (user_equipment_map_.count(ip) == 0) { throw std::runtime_error("No user equipment with the given ip"); } - user_equipments_.erase(ip); + user_equipment_map_.erase(ip); } // Basic default implementation, place your extension here (if needed) @@ -126,14 +133,18 @@ void Gtphandler::delUserEquipmentList() { std::string Gtphandler::getWrapperCode() { std::ostringstream wrapper_code; - wrapper_code << "#define MAX_USER_EQUIPMENTS " << MAX_USER_EQUIPMENTS << "\n"; + wrapper_code << "#define MAX_USER_EQUIPMENT " << MAX_USER_EQUIPMENT << "\n"; if (local_ip_ != "") { - wrapper_code << "#define LOCAL_IP " << utils::ip_string_to_nbo_uint(local_ip_) << "\n"; + wrapper_code << "#define LOCAL_IP " << + utils::ip_string_to_nbo_uint(local_ip_) << + "\n"; } if (local_mac_ != "") { - wrapper_code << "#define LOCAL_MAC " << utils::mac_string_to_nbo_uint(local_mac_) << "\n"; + wrapper_code << "#define LOCAL_MAC " << + utils::mac_string_to_nbo_uint(local_mac_) << + "\n"; } return wrapper_code.str(); diff --git a/src/services/pcn-gtphandler/src/Gtphandler.h b/src/services/pcn-gtphandler/src/Gtphandler.h index b3589934d..3286ccd87 100644 --- a/src/services/pcn-gtphandler/src/Gtphandler.h +++ b/src/services/pcn-gtphandler/src/Gtphandler.h @@ -14,17 +14,12 @@ * limitations under the License. */ - #pragma once - #include "../base/GtphandlerBase.h" - #include "UserEquipment.h" - -#define MAX_USER_EQUIPMENTS 1024 - +#define MAX_USER_EQUIPMENT 100000 using namespace polycube::service::model; @@ -40,18 +35,23 @@ class Gtphandler : public GtphandlerBase { /// /// User Equipment connected with GTP tunnel /// - std::shared_ptr getUserEquipment(const std::string &ip) override; + std::shared_ptr getUserEquipment( + const std::string &ip) override; std::vector> getUserEquipmentList() override; - void addUserEquipment(const std::string &ip, const UserEquipmentJsonObject &conf) override; - void addUserEquipmentList(const std::vector &conf) override; - void replaceUserEquipment(const std::string &ip, const UserEquipmentJsonObject &conf) override; + void addUserEquipment(const std::string &ip, + const UserEquipmentJsonObject &conf) override; + void addUserEquipmentList( + const std::vector &conf) override; + void replaceUserEquipment(const std::string &ip, + const UserEquipmentJsonObject &conf) override; void delUserEquipment(const std::string &ip) override; void delUserEquipmentList() override; private: std::string local_ip_; std::string local_mac_; - std::unordered_map> user_equipments_; + std::unordered_map> + user_equipment_map_; std::string getWrapperCode(); void reloadCode(); diff --git a/src/services/pcn-gtphandler/src/Gtphandler_dp_egress.c b/src/services/pcn-gtphandler/src/Gtphandler_dp_egress.c index d0fa2d5d0..26b9ccfc0 100644 --- a/src/services/pcn-gtphandler/src/Gtphandler_dp_egress.c +++ b/src/services/pcn-gtphandler/src/Gtphandler_dp_egress.c @@ -23,7 +23,7 @@ #include -// #define MAX_USER_EQUIPMENTS n +// #define MAX_USER_EQUIPMENT n // Following constants are added to the program at user level once the cube // is attached to an interface @@ -53,12 +53,8 @@ struct gtp1_header { /* According to 3GPP TS 29.060. */ __be32 tid; } __attribute__((packed)); -struct user_equipment { - __be32 tunnel_endpoint; - __be32 teid; -}; - -BPF_TABLE("extern", __be32, struct user_equipment, user_equipments, MAX_USER_EQUIPMENTS); +BPF_TABLE("extern", __be32, __be32, user_equipment_map, + MAX_USER_EQUIPMENT); #define IP_CSUM_OFFSET (sizeof(struct eth_hdr) + offsetof(struct iphdr, check)) @@ -73,7 +69,7 @@ int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) { void *data_end = (void *)(long)ctx->data_end; struct eth_hdr *eth = data; - if (data + sizeof(*eth) > data_end) { + if ((void *)(eth + 1) > data_end) { return RX_DROP; } @@ -81,14 +77,14 @@ int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) { return RX_OK; } - struct iphdr *ip = data + sizeof(*eth); - if ((void *)ip + sizeof(*ip) > data_end) { + struct iphdr *ip = (void *)(eth + 1); + if ((void *)(ip + 1) > data_end) { return RX_DROP; } // Check if packet is directed to a user equipment - struct user_equipment *ue = user_equipments.lookup(&ip->daddr); - if (!ue) { + __be32 *tunnel_endpoint = user_equipment_map.lookup(&ip->daddr); + if (!tunnel_endpoint) { return RX_OK; } @@ -104,26 +100,26 @@ int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) { data_end = (void *)(long)ctx->data_end; eth = data; - if (data + sizeof(*eth) > data_end) { + if ((void *)(eth + 1) > data_end) { return RX_DROP; } #ifdef POLYCUBE_XDP // Space allocated before packet buffer, move eth header struct eth_hdr *old_eth = data + GTP_ENCAP_SIZE; - if ((void *)old_eth + sizeof(*eth) > data_end) { + if ((void *)(old_eth + 1) > data_end) { return RX_DROP; } - memmove(eth, old_eth, sizeof(*eth)); + __builtin_memcpy(eth, old_eth, sizeof(*eth)); #endif - ip = data + sizeof(*eth); - if ((void *)ip + sizeof(*ip) > data_end) { + ip = (void *)(eth + 1); + if ((void *)(ip + 1) > data_end) { return RX_DROP; } struct iphdr *inner_ip = (void *)ip + GTP_ENCAP_SIZE; - if ((void *)inner_ip + sizeof(*inner_ip) > data_end) { + if ((void *)(inner_ip + 1) > data_end) { return RX_DROP; } @@ -138,27 +134,28 @@ int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) { ip->protocol = IPPROTO_UDP; ip->check = 0; ip->saddr = LOCAL_IP; - ip->daddr = ue->tunnel_endpoint; + ip->daddr = *tunnel_endpoint; // Add the UDP header - struct udphdr *udp = (void *)ip + sizeof(*ip); - if ((void *)udp + sizeof(*udp) > data_end) { + struct udphdr *udp = (void *)(ip + 1); + if ((void *)(udp + 1) > data_end) { return RX_DROP; } udp->source = htons(GTP_PORT); udp->dest = htons(GTP_PORT); - udp->len = htons(ntohs(inner_ip->tot_len) + sizeof(*udp) + sizeof(struct gtp1_header)); + udp->len = htons(ntohs(inner_ip->tot_len) + + sizeof(*udp) + sizeof(struct gtp1_header)); udp->check = 0; // Add the GTP header - struct gtp1_header *gtp = (void *)udp + sizeof(*udp); - if ((void *)gtp + sizeof(*gtp) > data_end) { + struct gtp1_header *gtp = (void *)(udp + 1); + if ((void *)(gtp + 1) > data_end) { return RX_DROP; } gtp->flags = GTP_FLAGS; gtp->type = GTP_TYPE_GPDU; gtp->length = inner_ip->tot_len; - gtp->tid = ue->teid; + gtp->tid = md->traffic_class; // Compute l3 checksum __wsum l3sum = pcn_csum_diff(0, 0, (__be32 *)ip, sizeof(*ip), 0); diff --git a/src/services/pcn-gtphandler/src/Gtphandler_dp_ingress.c b/src/services/pcn-gtphandler/src/Gtphandler_dp_ingress.c index 7c0af0950..6c6dde736 100644 --- a/src/services/pcn-gtphandler/src/Gtphandler_dp_ingress.c +++ b/src/services/pcn-gtphandler/src/Gtphandler_dp_ingress.c @@ -23,7 +23,7 @@ #include -// #define MAX_USER_EQUIPMENTS n +// #define MAX_USER_EQUIPMENT n // Following constants are added to the program at user level once the cube // is attached to an interface @@ -51,12 +51,8 @@ struct gtp1_header { /* According to 3GPP TS 29.060. */ __be32 tid; } __attribute__((packed)); -struct user_equipment { - __be32 tunnel_endpoint; - __be32 teid; -}; - -BPF_TABLE_SHARED("hash", __be32, struct user_equipment, user_equipments, MAX_USER_EQUIPMENTS); +BPF_TABLE_SHARED("hash", __be32, __be32, user_equipment_map, + MAX_USER_EQUIPMENT); #define GTP_ENCAP_SIZE (sizeof(struct iphdr) + \ @@ -72,7 +68,7 @@ int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) { // Check if packet is GTP encapsulated, if not pass it to the next cube struct eth_hdr *eth = data; - if (data + sizeof(*eth) > data_end) { + if ((void *)(eth + 1) > data_end) { return RX_DROP; } @@ -84,8 +80,8 @@ int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) { return RX_OK; } - struct iphdr *ip = data + sizeof(*eth); - if ((void *)ip + sizeof(*ip) > data_end) { + struct iphdr *ip = (void *)(eth + 1); + if ((void *)(ip + 1) > data_end) { return RX_DROP; } @@ -98,7 +94,7 @@ int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) { } struct udphdr *udp = (void *)ip + 4*ip->ihl; - if ((void *)udp + sizeof(*udp) > data_end) { + if ((void *)(udp + 1) > data_end) { return RX_DROP; } @@ -106,8 +102,8 @@ int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) { return RX_OK; } - struct gtp1_header *gtp = (void *)udp + sizeof(*udp); - if ((void *)gtp + sizeof(*gtp) > data_end) { + struct gtp1_header *gtp = (void *)(udp + 1); + if ((void *)(gtp + 1) > data_end) { return RX_DROP; } @@ -118,10 +114,10 @@ int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) { #ifdef POLYCUBE_XDP // Move eth header forward struct eth_hdr *new_eth = data + GTP_ENCAP_SIZE; - if ((void *)new_eth + sizeof(*eth) > data_end) { + if ((void *)(new_eth + 1) > data_end) { return RX_DROP; } - memmove(new_eth, eth, sizeof(*eth)); + __builtin_memcpy(new_eth, eth, sizeof(*eth)); bpf_xdp_adjust_head(ctx, GTP_ENCAP_SIZE); #else diff --git a/src/services/pcn-gtphandler/src/UserEquipment.cpp b/src/services/pcn-gtphandler/src/UserEquipment.cpp index 69296ae9a..1a4a4c5a3 100644 --- a/src/services/pcn-gtphandler/src/UserEquipment.cpp +++ b/src/services/pcn-gtphandler/src/UserEquipment.cpp @@ -14,18 +14,16 @@ * limitations under the License. */ - #include "UserEquipment.h" #include "Gtphandler.h" - using namespace polycube::service; -UserEquipment::UserEquipment(Gtphandler &parent, const UserEquipmentJsonObject &conf) +UserEquipment::UserEquipment(Gtphandler &parent, + const UserEquipmentJsonObject &conf) : UserEquipmentBase(parent) { ip_ = conf.getIp(); tunnel_endpoint_ = conf.getTunnelEndpoint(); - teid_ = conf.getTeid(); updateDataplane(); @@ -33,7 +31,7 @@ UserEquipment::UserEquipment(Gtphandler &parent, const UserEquipmentJsonObject & } UserEquipment::~UserEquipment() { - parent_.get_hash_table("user_equipments") + parent_.get_hash_table("user_equipment_map") .remove(utils::ip_string_to_nbo_uint(ip_)); logger()->info("User equipment {0} deleted", ip_); @@ -59,38 +57,12 @@ void UserEquipment::setTunnelEndpoint(const std::string &value) { logger()->info("User equipment updated {0}", toString()); } -uint32_t UserEquipment::getTeid() { - return teid_; -} - -void UserEquipment::setTeid(const uint32_t &value) { - if (teid_ == value) { - return; - } - - teid_ = value; - - updateDataplane(); - - logger()->info("User equipment updated {0}", toString()); -} - std::string UserEquipment::toString() { - std::ostringstream out; - - out << "[ip=" << ip_ - << "; tunel-endpoint=" << tunnel_endpoint_ - << "; teid=" << teid_ << "]"; - - return out.str(); + return toJsonObject().toJson().dump(); } void UserEquipment::updateDataplane() { - struct user_equipment ue = { - .tunnel_endpoint = utils::ip_string_to_nbo_uint(tunnel_endpoint_), - .teid = htonl(teid_) - }; - - parent_.get_hash_table("user_equipments") - .set(utils::ip_string_to_nbo_uint(ip_), ue); + parent_.get_hash_table("user_equipment_map") + .set(utils::ip_string_to_nbo_uint(ip_), + utils::ip_string_to_nbo_uint(tunnel_endpoint_)); } \ No newline at end of file diff --git a/src/services/pcn-gtphandler/src/UserEquipment.h b/src/services/pcn-gtphandler/src/UserEquipment.h index 33919cfcd..b9e3a5812 100644 --- a/src/services/pcn-gtphandler/src/UserEquipment.h +++ b/src/services/pcn-gtphandler/src/UserEquipment.h @@ -14,21 +14,12 @@ * limitations under the License. */ - #pragma once - #include "../base/UserEquipmentBase.h" - -struct user_equipment { - uint32_t tunnel_endpoint; - uint32_t teid; -}; - class Gtphandler; - using namespace polycube::service::model; class UserEquipment : public UserEquipmentBase { @@ -47,18 +38,11 @@ class UserEquipment : public UserEquipmentBase { std::string getTunnelEndpoint() override; void setTunnelEndpoint(const std::string &value) override; - /// - /// Tunnel Endpoint ID of the GTP tunnel used by the User Equipment - /// - uint32_t getTeid() override; - void setTeid(const uint32_t &value) override; - std::string toString(); private: std::string ip_; std::string tunnel_endpoint_; - uint32_t teid_; void updateDataplane(); }; \ No newline at end of file diff --git a/src/services/pcn-gtphandler/src/api/GtphandlerApi.cpp b/src/services/pcn-gtphandler/src/api/GtphandlerApi.cpp index e4298abe0..2151f1e93 100644 --- a/src/services/pcn-gtphandler/src/api/GtphandlerApi.cpp +++ b/src/services/pcn-gtphandler/src/api/GtphandlerApi.cpp @@ -220,31 +220,6 @@ Response read_gtphandler_user_equipment_list_by_id_handler( } } -Response read_gtphandler_user_equipment_teid_by_id_handler( - const char *name, const Key *keys, - size_t num_keys ) { - // Getting the path params - std::string unique_name { name }; - std::string unique_ip; - for (size_t i = 0; i < num_keys; ++i) { - if (!strcmp(keys[i].name, "ip")) { - unique_ip = std::string { keys[i].value.string }; - break; - } - } - - - try { - - auto x = read_gtphandler_user_equipment_teid_by_id(unique_name, unique_ip); - nlohmann::json response_body; - response_body = x; - return { kOk, ::strdup(response_body.dump().c_str()) }; - } catch(const std::exception &e) { - return { kGenericError, ::strdup(e.what()) }; - } -} - Response read_gtphandler_user_equipment_tunnel_endpoint_by_id_handler( const char *name, const Key *keys, size_t num_keys ) { @@ -437,32 +412,6 @@ Response update_gtphandler_user_equipment_list_by_id_handler( } } -Response update_gtphandler_user_equipment_teid_by_id_handler( - const char *name, const Key *keys, - size_t num_keys , - const char *value) { - // Getting the path params - std::string unique_name { name }; - std::string unique_ip; - for (size_t i = 0; i < num_keys; ++i) { - if (!strcmp(keys[i].name, "ip")) { - unique_ip = std::string { keys[i].value.string }; - break; - } - } - - - try { - auto request_body = nlohmann::json::parse(std::string { value }); - // The conversion is done automatically by the json library - uint32_t unique_value = request_body; - update_gtphandler_user_equipment_teid_by_id(unique_name, unique_ip, unique_value); - return { kOk, nullptr }; - } catch(const std::exception &e) { - return { kGenericError, ::strdup(e.what()) }; - } -} - Response update_gtphandler_user_equipment_tunnel_endpoint_by_id_handler( const char *name, const Key *keys, size_t num_keys , diff --git a/src/services/pcn-gtphandler/src/api/GtphandlerApi.h b/src/services/pcn-gtphandler/src/api/GtphandlerApi.h index 622a1e210..d8ed69455 100644 --- a/src/services/pcn-gtphandler/src/api/GtphandlerApi.h +++ b/src/services/pcn-gtphandler/src/api/GtphandlerApi.h @@ -40,7 +40,6 @@ Response read_gtphandler_by_id_handler(const char *name, const Key *keys, size_t Response read_gtphandler_list_by_id_handler(const char *name, const Key *keys, size_t num_keys); Response read_gtphandler_user_equipment_by_id_handler(const char *name, const Key *keys, size_t num_keys); Response read_gtphandler_user_equipment_list_by_id_handler(const char *name, const Key *keys, size_t num_keys); -Response read_gtphandler_user_equipment_teid_by_id_handler(const char *name, const Key *keys, size_t num_keys); Response read_gtphandler_user_equipment_tunnel_endpoint_by_id_handler(const char *name, const Key *keys, size_t num_keys); Response replace_gtphandler_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); Response replace_gtphandler_user_equipment_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); @@ -49,7 +48,6 @@ Response update_gtphandler_by_id_handler(const char *name, const Key *keys, size Response update_gtphandler_list_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); Response update_gtphandler_user_equipment_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); Response update_gtphandler_user_equipment_list_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); -Response update_gtphandler_user_equipment_teid_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); Response update_gtphandler_user_equipment_tunnel_endpoint_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); Response gtphandler_list_by_id_help(const char *name, const Key *keys, size_t num_keys); diff --git a/src/services/pcn-gtphandler/src/api/GtphandlerApiImpl.cpp b/src/services/pcn-gtphandler/src/api/GtphandlerApiImpl.cpp index a8f96df15..175d95ca6 100644 --- a/src/services/pcn-gtphandler/src/api/GtphandlerApiImpl.cpp +++ b/src/services/pcn-gtphandler/src/api/GtphandlerApiImpl.cpp @@ -209,25 +209,6 @@ read_gtphandler_user_equipment_list_by_id(const std::string &name) { return m; } -/** -* @brief Read teid by ID -* -* Read operation of resource: teid* -* -* @param[in] name ID of name -* @param[in] ip ID of ip -* -* Responses: -* uint32_t -*/ -uint32_t -read_gtphandler_user_equipment_teid_by_id(const std::string &name, const std::string &ip) { - auto gtphandler = get_cube(name); - auto userEquipment = gtphandler->getUserEquipment(ip); - return userEquipment->getTeid(); - -} - /** * @brief Read tunnel-endpoint by ID * @@ -351,26 +332,6 @@ update_gtphandler_user_equipment_list_by_id(const std::string &name, const std:: throw std::runtime_error("Method not supported"); } -/** -* @brief Update teid by ID -* -* Update operation of resource: teid* -* -* @param[in] name ID of name -* @param[in] ip ID of ip -* @param[in] value Tunnel Endpoint ID of the GTP tunnel used by the User Equipment -* -* Responses: -* -*/ -void -update_gtphandler_user_equipment_teid_by_id(const std::string &name, const std::string &ip, const uint32_t &value) { - auto gtphandler = get_cube(name); - auto userEquipment = gtphandler->getUserEquipment(ip); - - return userEquipment->setTeid(value); -} - /** * @brief Update tunnel-endpoint by ID * diff --git a/src/services/pcn-gtphandler/src/api/GtphandlerApiImpl.h b/src/services/pcn-gtphandler/src/api/GtphandlerApiImpl.h index 7323a8c16..8f4dfa4ed 100644 --- a/src/services/pcn-gtphandler/src/api/GtphandlerApiImpl.h +++ b/src/services/pcn-gtphandler/src/api/GtphandlerApiImpl.h @@ -43,7 +43,6 @@ namespace GtphandlerApiImpl { std::vector read_gtphandler_list_by_id(); UserEquipmentJsonObject read_gtphandler_user_equipment_by_id(const std::string &name, const std::string &ip); std::vector read_gtphandler_user_equipment_list_by_id(const std::string &name); - uint32_t read_gtphandler_user_equipment_teid_by_id(const std::string &name, const std::string &ip); std::string read_gtphandler_user_equipment_tunnel_endpoint_by_id(const std::string &name, const std::string &ip); void replace_gtphandler_by_id(const std::string &name, const GtphandlerJsonObject &value); void replace_gtphandler_user_equipment_by_id(const std::string &name, const std::string &ip, const UserEquipmentJsonObject &value); @@ -52,7 +51,6 @@ namespace GtphandlerApiImpl { void update_gtphandler_list_by_id(const std::vector &value); void update_gtphandler_user_equipment_by_id(const std::string &name, const std::string &ip, const UserEquipmentJsonObject &value); void update_gtphandler_user_equipment_list_by_id(const std::string &name, const std::vector &value); - void update_gtphandler_user_equipment_teid_by_id(const std::string &name, const std::string &ip, const uint32_t &value); void update_gtphandler_user_equipment_tunnel_endpoint_by_id(const std::string &name, const std::string &ip, const std::string &value); /* help related */ diff --git a/src/services/pcn-gtphandler/src/base/UserEquipmentBase.cpp b/src/services/pcn-gtphandler/src/base/UserEquipmentBase.cpp index ccaa27eb8..84d26396c 100644 --- a/src/services/pcn-gtphandler/src/base/UserEquipmentBase.cpp +++ b/src/services/pcn-gtphandler/src/base/UserEquipmentBase.cpp @@ -23,9 +23,6 @@ void UserEquipmentBase::update(const UserEquipmentJsonObject &conf) { if (conf.tunnelEndpointIsSet()) { setTunnelEndpoint(conf.getTunnelEndpoint()); } - if (conf.teidIsSet()) { - setTeid(conf.getTeid()); - } } UserEquipmentJsonObject UserEquipmentBase::toJsonObject() { @@ -33,7 +30,6 @@ UserEquipmentJsonObject UserEquipmentBase::toJsonObject() { conf.setIp(getIp()); conf.setTunnelEndpoint(getTunnelEndpoint()); - conf.setTeid(getTeid()); return conf; } diff --git a/src/services/pcn-gtphandler/src/base/UserEquipmentBase.h b/src/services/pcn-gtphandler/src/base/UserEquipmentBase.h index b1f6ec38d..0fefa46d4 100644 --- a/src/services/pcn-gtphandler/src/base/UserEquipmentBase.h +++ b/src/services/pcn-gtphandler/src/base/UserEquipmentBase.h @@ -49,12 +49,6 @@ class UserEquipmentBase { virtual std::string getTunnelEndpoint() = 0; virtual void setTunnelEndpoint(const std::string &value) = 0; - /// - /// Tunnel Endpoint ID of the GTP tunnel used by the User Equipment - /// - virtual uint32_t getTeid() = 0; - virtual void setTeid(const uint32_t &value) = 0; - std::shared_ptr logger(); protected: Gtphandler &parent_; diff --git a/src/services/pcn-gtphandler/src/serializer/UserEquipmentJsonObject.cpp b/src/services/pcn-gtphandler/src/serializer/UserEquipmentJsonObject.cpp index ba5d18507..7a6191c03 100644 --- a/src/services/pcn-gtphandler/src/serializer/UserEquipmentJsonObject.cpp +++ b/src/services/pcn-gtphandler/src/serializer/UserEquipmentJsonObject.cpp @@ -20,14 +20,12 @@ namespace model { UserEquipmentJsonObject::UserEquipmentJsonObject() { m_ipIsSet = false; m_tunnelEndpointIsSet = false; - m_teidIsSet = false; } UserEquipmentJsonObject::UserEquipmentJsonObject(const nlohmann::json &val) : JsonObjectBase(val) { m_ipIsSet = false; m_tunnelEndpointIsSet = false; - m_teidIsSet = false; if (val.count("ip")) { @@ -37,10 +35,6 @@ UserEquipmentJsonObject::UserEquipmentJsonObject(const nlohmann::json &val) : if (val.count("tunnel-endpoint")) { setTunnelEndpoint(val.at("tunnel-endpoint").get()); } - - if (val.count("teid")) { - setTeid(val.at("teid").get()); - } } nlohmann::json UserEquipmentJsonObject::toJson() const { @@ -57,10 +51,6 @@ nlohmann::json UserEquipmentJsonObject::toJson() const { val["tunnel-endpoint"] = m_tunnelEndpoint; } - if (m_teidIsSet) { - val["teid"] = m_teid; - } - return val; } @@ -94,21 +84,6 @@ bool UserEquipmentJsonObject::tunnelEndpointIsSet() const { -uint32_t UserEquipmentJsonObject::getTeid() const { - return m_teid; -} - -void UserEquipmentJsonObject::setTeid(uint32_t value) { - m_teid = value; - m_teidIsSet = true; -} - -bool UserEquipmentJsonObject::teidIsSet() const { - return m_teidIsSet; -} - - - } } diff --git a/src/services/pcn-gtphandler/src/serializer/UserEquipmentJsonObject.h b/src/services/pcn-gtphandler/src/serializer/UserEquipmentJsonObject.h index 75a2c7091..e7d09b2ad 100644 --- a/src/services/pcn-gtphandler/src/serializer/UserEquipmentJsonObject.h +++ b/src/services/pcn-gtphandler/src/serializer/UserEquipmentJsonObject.h @@ -50,20 +50,11 @@ class UserEquipmentJsonObject : public JsonObjectBase { void setTunnelEndpoint(std::string value); bool tunnelEndpointIsSet() const; - /// - /// Tunnel Endpoint ID of the GTP tunnel used by the User Equipment - /// - uint32_t getTeid() const; - void setTeid(uint32_t value); - bool teidIsSet() const; - private: std::string m_ip; bool m_ipIsSet; std::string m_tunnelEndpoint; bool m_tunnelEndpointIsSet; - uint32_t m_teid; - bool m_teidIsSet; }; } diff --git a/src/services/pcn-gtphandler/test/test.sh b/src/services/pcn-gtphandler/test/test.sh index 1333fade5..c5866727c 100755 --- a/src/services/pcn-gtphandler/test/test.sh +++ b/src/services/pcn-gtphandler/test/test.sh @@ -49,7 +49,7 @@ sudo arp -s 10.0.0.2 ${BS_MAC} # Configure the GTP tunnel sudo ip netns exec ns1 $LIBGTPNL/gtp-link add gtp1 --sgsn & sleep 1 -sudo ip netns exec ns1 $LIBGTPNL/gtp-tunnel add gtp1 v1 100 100 172.99.0.1 10.0.0.1 +sudo ip netns exec ns1 $LIBGTPNL/gtp-tunnel add gtp1 v1 0 0 172.99.0.1 10.0.0.1 sudo ip netns exec ns1 route add default dev gtp1 set -e @@ -57,7 +57,7 @@ set -e # Configure the gtphandler polycubectl gtphandler add gh1 polycubectl attach gh1 veth1 -polycubectl gh1 user-equipment add 172.99.0.1 tunnel-endpoint=10.0.0.2 teid=100 +polycubectl gh1 user-equipment add 172.99.0.1 tunnel-endpoint=10.0.0.2 ping -I 10.0.1.1 -c 1 172.99.0.1 sudo ip netns exec ns1 ping -c 1 10.0.1.1 From 71c21fe4d5d593f3fd802fb4f632759af4dfce7d Mon Sep 17 00:00:00 2001 From: FedeParola Date: Fri, 24 Jan 2020 15:06:56 +0100 Subject: [PATCH 03/12] Add policer service --- src/services/CMakeLists.txt | 1 + .../pcn-policer/.swagger-codegen-ignore | 14 + src/services/pcn-policer/CMakeLists.txt | 5 + .../pcn-policer/datamodel/policer.yang | 86 +++ src/services/pcn-policer/src/CMakeLists.txt | 48 ++ src/services/pcn-policer/src/Contract.cpp | 147 ++++ src/services/pcn-policer/src/Contract.h | 66 ++ .../pcn-policer/src/DefaultContract.cpp | 137 ++++ .../pcn-policer/src/DefaultContract.h | 60 ++ src/services/pcn-policer/src/Policer-lib.cpp | 21 + src/services/pcn-policer/src/Policer.cpp | 125 ++++ src/services/pcn-policer/src/Policer.h | 79 +++ src/services/pcn-policer/src/Policer_dp.c | 121 ++++ .../pcn-policer/src/api/PolicerApi.cpp | 671 ++++++++++++++++++ src/services/pcn-policer/src/api/PolicerApi.h | 74 ++ .../pcn-policer/src/api/PolicerApiImpl.cpp | 582 +++++++++++++++ .../pcn-policer/src/api/PolicerApiImpl.h | 78 ++ .../pcn-policer/src/base/ContractBase.cpp | 39 + .../pcn-policer/src/base/ContractBase.h | 67 ++ .../src/base/DefaultContractBase.cpp | 38 + .../src/base/DefaultContractBase.h | 62 ++ .../pcn-policer/src/base/PolicerBase.cpp | 77 ++ .../pcn-policer/src/base/PolicerBase.h | 62 ++ .../src/serializer/ContractJsonObject.cpp | 167 +++++ .../src/serializer/ContractJsonObject.h | 91 +++ .../ContractUpdateDataInputJsonObject.cpp | 144 ++++ .../ContractUpdateDataInputJsonObject.h | 83 +++ .../serializer/DefaultContractJsonObject.cpp | 145 ++++ .../serializer/DefaultContractJsonObject.h | 83 +++ ...faultContractUpdateDataInputJsonObject.cpp | 144 ++++ ...DefaultContractUpdateDataInputJsonObject.h | 83 +++ .../src/serializer/JsonObjectBase.cpp | 69 ++ .../src/serializer/JsonObjectBase.h | 55 ++ .../src/serializer/PolicerJsonObject.cpp | 136 ++++ .../src/serializer/PolicerJsonObject.h | 78 ++ 35 files changed, 3938 insertions(+) create mode 100644 src/services/pcn-policer/.swagger-codegen-ignore create mode 100644 src/services/pcn-policer/CMakeLists.txt create mode 100644 src/services/pcn-policer/datamodel/policer.yang create mode 100644 src/services/pcn-policer/src/CMakeLists.txt create mode 100644 src/services/pcn-policer/src/Contract.cpp create mode 100644 src/services/pcn-policer/src/Contract.h create mode 100644 src/services/pcn-policer/src/DefaultContract.cpp create mode 100644 src/services/pcn-policer/src/DefaultContract.h create mode 100644 src/services/pcn-policer/src/Policer-lib.cpp create mode 100644 src/services/pcn-policer/src/Policer.cpp create mode 100644 src/services/pcn-policer/src/Policer.h create mode 100644 src/services/pcn-policer/src/Policer_dp.c create mode 100644 src/services/pcn-policer/src/api/PolicerApi.cpp create mode 100644 src/services/pcn-policer/src/api/PolicerApi.h create mode 100644 src/services/pcn-policer/src/api/PolicerApiImpl.cpp create mode 100644 src/services/pcn-policer/src/api/PolicerApiImpl.h create mode 100644 src/services/pcn-policer/src/base/ContractBase.cpp create mode 100644 src/services/pcn-policer/src/base/ContractBase.h create mode 100644 src/services/pcn-policer/src/base/DefaultContractBase.cpp create mode 100644 src/services/pcn-policer/src/base/DefaultContractBase.h create mode 100644 src/services/pcn-policer/src/base/PolicerBase.cpp create mode 100644 src/services/pcn-policer/src/base/PolicerBase.h create mode 100644 src/services/pcn-policer/src/serializer/ContractJsonObject.cpp create mode 100644 src/services/pcn-policer/src/serializer/ContractJsonObject.h create mode 100644 src/services/pcn-policer/src/serializer/ContractUpdateDataInputJsonObject.cpp create mode 100644 src/services/pcn-policer/src/serializer/ContractUpdateDataInputJsonObject.h create mode 100644 src/services/pcn-policer/src/serializer/DefaultContractJsonObject.cpp create mode 100644 src/services/pcn-policer/src/serializer/DefaultContractJsonObject.h create mode 100644 src/services/pcn-policer/src/serializer/DefaultContractUpdateDataInputJsonObject.cpp create mode 100644 src/services/pcn-policer/src/serializer/DefaultContractUpdateDataInputJsonObject.h create mode 100644 src/services/pcn-policer/src/serializer/JsonObjectBase.cpp create mode 100644 src/services/pcn-policer/src/serializer/JsonObjectBase.h create mode 100644 src/services/pcn-policer/src/serializer/PolicerJsonObject.cpp create mode 100644 src/services/pcn-policer/src/serializer/PolicerJsonObject.h diff --git a/src/services/CMakeLists.txt b/src/services/CMakeLists.txt index 55ca7e4ef..56168b0d3 100644 --- a/src/services/CMakeLists.txt +++ b/src/services/CMakeLists.txt @@ -37,6 +37,7 @@ add_service(transparenthelloworld pcn-transparent-helloworld) add_service(synflood pcn-synflood) add_service(packetcapture pcn-packetcapture) add_service(dynmon pcn-dynmon) +add_service(policer pcn-policer) # save string to create code that load the services SET_PROPERTY(GLOBAL PROPERTY LOAD_SERVICES_ ${LOAD_SERVICES}) diff --git a/src/services/pcn-policer/.swagger-codegen-ignore b/src/services/pcn-policer/.swagger-codegen-ignore new file mode 100644 index 000000000..f90131c08 --- /dev/null +++ b/src/services/pcn-policer/.swagger-codegen-ignore @@ -0,0 +1,14 @@ +# Swagger Codegen Ignore +# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen + +# Use this file to prevent files from being overwritten by the generator. + +.swagger-codegen-ignore + +src/*.c +src/*.cpp +src/*.h + +!src/*Interface.h +!src/*JsonObject.h +!src/*JsonObject.cpp diff --git a/src/services/pcn-policer/CMakeLists.txt b/src/services/pcn-policer/CMakeLists.txt new file mode 100644 index 000000000..9857094f7 --- /dev/null +++ b/src/services/pcn-policer/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required (VERSION 3.2) + +set (CMAKE_CXX_STANDARD 11) + +add_subdirectory(src) diff --git a/src/services/pcn-policer/datamodel/policer.yang b/src/services/pcn-policer/datamodel/policer.yang new file mode 100644 index 000000000..7e5b573a7 --- /dev/null +++ b/src/services/pcn-policer/datamodel/policer.yang @@ -0,0 +1,86 @@ +module policer { + yang-version 1.1; + namespace "http://polycube.network/policer"; + prefix "policer"; + + import polycube-base { prefix "polycube-base"; } + import polycube-transparent-base { prefix "polycube-transparent-base"; } + + organization "Polycube Open Source Project"; + description "YANG data model for the Polycube Traffic Policer service based on token bucket algorithm"; + + polycube-base:service-description "Traffic Policer Service"; + polycube-base:service-version "1.0"; + polycube-base:service-name "policer"; + polycube-base:service-min-kernel-version "5.1.0"; + + uses "polycube-transparent-base:transparent-base-yang-module"; + + typedef action-type { + type enumeration { + enum PASS; + enum LIMIT; + enum DROP; + } + } + + grouping contract-data { + leaf action { + type action-type; + description "Action applied to traffic of the contract: PASS = Let all the traffic pass without limitations; LIMIT = Apply rate and burst limits to selected traffic; DROP = Drop all the traffic"; + polycube-base:cli-example "LIMIT"; + polycube-base:init-only-config; + } + + leaf rate-limit { + type uint64; + description "Maximum average traffic rate (in bps)"; + polycube-base:cli-example "10000"; + polycube-base:init-only-config; + } + + leaf burst-limit { + type uint64; + description "Maximum size of a burst of packets (in bits)"; + polycube-base:cli-example "50000"; + polycube-base:init-only-config; + } + } + + grouping updatable-contract-data { + uses contract-data; + + action update-data { + input { + uses contract-data; + } + } + } + + container default-contract { + description "Contract applied to traffic not matching any of the specified classes (default: PASS)"; + uses updatable-contract-data { + refine action { + default PASS; + } + } + } + + list contract { + key "traffic-class"; + description "Contract applied to a specific class of traffic"; + + leaf traffic-class { + type uint32; + mandatory true; + description "Identifier of the class of traffic, provided as packet metadata"; + polycube-base:cli-example "1000"; + } + + uses updatable-contract-data { + refine action { + mandatory true; + } + } + } +} diff --git a/src/services/pcn-policer/src/CMakeLists.txt b/src/services/pcn-policer/src/CMakeLists.txt new file mode 100644 index 000000000..d8313f4ea --- /dev/null +++ b/src/services/pcn-policer/src/CMakeLists.txt @@ -0,0 +1,48 @@ +include(${PROJECT_SOURCE_DIR}/cmake/LoadFileAsVariable.cmake) + +aux_source_directory(serializer SERIALIZER_SOURCES) +aux_source_directory(api API_SOURCES) +aux_source_directory(base BASE_SOURCES) + +include_directories(serializer) + +if (NOT DEFINED POLYCUBE_STANDALONE_SERVICE OR POLYCUBE_STANDALONE_SERVICE) + find_package(PkgConfig REQUIRED) + pkg_check_modules(POLYCUBE libpolycube) + include_directories(${POLYCUBE_INCLUDE_DIRS}) +endif(NOT DEFINED POLYCUBE_STANDALONE_SERVICE OR POLYCUBE_STANDALONE_SERVICE) + +# Needed to load files as variables +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +add_library(pcn-policer SHARED + ${SERIALIZER_SOURCES} + ${API_SOURCES} + ${BASE_SOURCES} + Contract.cpp + DefaultContract.cpp + Policer.cpp + Policer-lib.cpp) + +# load ebpf datapath code a variable +load_file_as_variable(pcn-policer + Policer_dp.c + policer_code) + +# load datamodel in a variable +load_file_as_variable(pcn-policer + ../datamodel/policer.yang + policer_datamodel) + +target_link_libraries(pcn-policer ${POLYCUBE_LIBRARIES}) + +# Specify shared library install directory + +set(CMAKE_INSTALL_LIBDIR /usr/lib) + +install( + TARGETS + pcn-policer + DESTINATION + "${CMAKE_INSTALL_LIBDIR}" +) diff --git a/src/services/pcn-policer/src/Contract.cpp b/src/services/pcn-policer/src/Contract.cpp new file mode 100644 index 000000000..dcae069e6 --- /dev/null +++ b/src/services/pcn-policer/src/Contract.cpp @@ -0,0 +1,147 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#include "Contract.h" +#include "Policer.h" + + +Contract::Contract(Policer &parent, const ContractJsonObject &conf) + : ContractBase(parent) { + traffic_class_ = conf.getTrafficClass(); + action_ = conf.getAction(); + + if (action_ == ActionTypeEnum::LIMIT) { + if (!conf.rateLimitIsSet() || ! conf.burstLimitIsSet()) { + throw std::runtime_error("Action LIMIT requires rate and burst limits"); + } + + rate_limit_ = conf.getRateLimit(); + burst_limit_ = conf.getBurstLimit(); + + } else { + if (conf.rateLimitIsSet() || conf.burstLimitIsSet()) { + throw std::runtime_error( + "Rate and burst limits can only be set with action LIMIT"); + } + + rate_limit_ = 0; + burst_limit_ = 0; + } + + updateDataplane(); + + logger()->info("Contract created {0}", toString()); +} + +Contract::~Contract() { + parent_.get_hash_table("contracts") + .remove(traffic_class_); + + logger()->info("Contract for class {0} deleted", traffic_class_); +} + +ContractJsonObject Contract::toJsonObject() { + ContractJsonObject conf; + + conf.setTrafficClass(traffic_class_); + conf.setAction(action_); + if (action_ == ActionTypeEnum::LIMIT) { + conf.setRateLimit(rate_limit_); + conf.setBurstLimit(burst_limit_); + } + + return conf; +} + +uint32_t Contract::getTrafficClass() { + return traffic_class_; +} + +ActionTypeEnum Contract::getAction() { + return action_; +} + +uint64_t Contract::getRateLimit() { + return rate_limit_; +} + +uint64_t Contract::getBurstLimit() { + return burst_limit_; +} + +void Contract::updateData(ContractUpdateDataInputJsonObject input) { + if (input.actionIsSet()) { + if (input.getAction() == ActionTypeEnum::LIMIT) { + if (!input.rateLimitIsSet() || !input.burstLimitIsSet()) { + throw std::runtime_error("Action LIMIT requires rate and burst limits"); + } + + rate_limit_ = input.getRateLimit(); + burst_limit_ = input.getBurstLimit(); + + } else { + if (input.rateLimitIsSet() || input.burstLimitIsSet()) { + throw std::runtime_error( + "Rate and burst limits can only be set with action LIMIT"); + } + + rate_limit_ = 0; + burst_limit_ = 0; + } + + action_ = input.getAction(); + + } else { + if (action_ != ActionTypeEnum::LIMIT) { + throw std::runtime_error( + "Rate and burst limits can only be set with action LIMIT"); + } + + if (input.rateLimitIsSet()) { + rate_limit_ = input.getRateLimit(); + } + + if (input.burstLimitIsSet()) { + burst_limit_ = input.getBurstLimit(); + } + } + + updateDataplane(); + + logger()->info("Contract updated {0}", toString()); +} + +void Contract::updateDataplane() { + struct bucket bucket = { + .tokens = burst_limit_, + .refill_rate = rate_limit_, + .capacity = burst_limit_, + .last_update = 0 + }; + + struct contract contract = { + .action = static_cast(action_), + .bucket = bucket + }; + + parent_.get_hash_table("contracts") + .set(traffic_class_, contract); +} + +std::string Contract::toString() { + return toJsonObject().toJson().dump(); +} \ No newline at end of file diff --git a/src/services/pcn-policer/src/Contract.h b/src/services/pcn-policer/src/Contract.h new file mode 100644 index 000000000..4cbcf91bf --- /dev/null +++ b/src/services/pcn-policer/src/Contract.h @@ -0,0 +1,66 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#pragma once + + +#include "../base/ContractBase.h" + + +class Policer; + +using namespace polycube::service::model; + + +class Contract : public ContractBase { + public: + Contract(Policer &parent, const ContractJsonObject &conf); + ~Contract(); + ContractJsonObject toJsonObject(); + + /// + /// Identifier of the class of traffic, provided as packet metadata + /// + uint32_t getTrafficClass() override; + + /// + /// Action applied to traffic of the contract: PASS = Let all the traffic pass without limitations; LIMIT = Apply rate and burst limits to selected traffic; DROP = Drop all the traffic + /// + ActionTypeEnum getAction() override; + + /// + /// Maximum average traffic rate (in bps) + /// + uint64_t getRateLimit() override; + + /// + /// Maximum size of a burst of packets (in bits) + /// + uint64_t getBurstLimit() override; + + void updateData(ContractUpdateDataInputJsonObject input) override; + + std::string toString(); + + private: + uint32_t traffic_class_; + ActionTypeEnum action_; + uint64_t rate_limit_; + uint64_t burst_limit_; + + void updateDataplane(); +}; diff --git a/src/services/pcn-policer/src/DefaultContract.cpp b/src/services/pcn-policer/src/DefaultContract.cpp new file mode 100644 index 000000000..ee7036bde --- /dev/null +++ b/src/services/pcn-policer/src/DefaultContract.cpp @@ -0,0 +1,137 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#include "DefaultContract.h" +#include "Policer.h" + + +DefaultContract::DefaultContract(Policer &parent, + const DefaultContractJsonObject &conf) + : DefaultContractBase(parent) { + action_ = conf.getAction(); + + if (action_ == ActionTypeEnum::LIMIT) { + if (!conf.rateLimitIsSet() || ! conf.burstLimitIsSet()) { + throw std::runtime_error("Action LIMIT requires rate and burst limits"); + } + + rate_limit_ = conf.getRateLimit(); + burst_limit_ = conf.getBurstLimit(); + + } else { + if (conf.rateLimitIsSet() || conf.burstLimitIsSet()) { + throw std::runtime_error( + "Rate and burst limits can only be set with action LIMIT"); + } + + rate_limit_ = 0; + burst_limit_ = 0; + } + + updateDataplane(); + + logger()->info("Default contract initialized {0}", toString()); +} + +DefaultContract::~DefaultContract() {} + +DefaultContractJsonObject DefaultContract::toJsonObject() { + DefaultContractJsonObject conf; + + conf.setAction(action_); + if (action_ == ActionTypeEnum::LIMIT) { + conf.setRateLimit(rate_limit_); + conf.setBurstLimit(burst_limit_); + } + + return conf; +} + +ActionTypeEnum DefaultContract::getAction() { + return action_; +} + +uint64_t DefaultContract::getRateLimit() { + return rate_limit_; +} + +uint64_t DefaultContract::getBurstLimit() { + return burst_limit_; +} + +void DefaultContract::updateData( + DefaultContractUpdateDataInputJsonObject input) { + if (input.actionIsSet()) { + if (input.getAction() == ActionTypeEnum::LIMIT) { + if (!input.rateLimitIsSet() || !input.burstLimitIsSet()) { + throw std::runtime_error("Action LIMIT requires rate and burst limits"); + } + + rate_limit_ = input.getRateLimit(); + burst_limit_ = input.getBurstLimit(); + + } else { + if (input.rateLimitIsSet() || input.burstLimitIsSet()) { + throw std::runtime_error( + "Rate and burst limits can only be set with action LIMIT"); + } + + rate_limit_ = 0; + burst_limit_ = 0; + } + + action_ = input.getAction(); + + } else { + if (action_ != ActionTypeEnum::LIMIT) { + throw std::runtime_error( + "Rate and burst limits can only be set with action LIMIT"); + } + + if (input.rateLimitIsSet()) { + rate_limit_ = input.getRateLimit(); + } + + if (input.burstLimitIsSet()) { + burst_limit_ = input.getBurstLimit(); + } + } + + updateDataplane(); + + logger()->info("Default contract updated {0}", toString()); +} + +void DefaultContract::updateDataplane() { + struct bucket bucket = { + .tokens = burst_limit_, + .refill_rate = rate_limit_, + .capacity = burst_limit_, + .last_update = 0 + }; + + struct contract contract = { + .action = static_cast(action_), + .bucket = bucket + }; + + parent_.get_array_table("default_contract").set(0, contract); +} + +std::string DefaultContract::toString() { + return toJsonObject().toJson().dump(); +} \ No newline at end of file diff --git a/src/services/pcn-policer/src/DefaultContract.h b/src/services/pcn-policer/src/DefaultContract.h new file mode 100644 index 000000000..8ed4d620b --- /dev/null +++ b/src/services/pcn-policer/src/DefaultContract.h @@ -0,0 +1,60 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#pragma once + + +#include "../base/DefaultContractBase.h" + + +class Policer; + +using namespace polycube::service::model; + + +class DefaultContract : public DefaultContractBase { + public: + DefaultContract(Policer &parent, const DefaultContractJsonObject &conf); + ~DefaultContract(); + DefaultContractJsonObject toJsonObject(); + + /// + /// Action applied to traffic of the contract: PASS = Let all the traffic pass without limitations; LIMIT = Apply rate and burst limits to selected traffic; DROP = Drop all the traffic + /// + ActionTypeEnum getAction() override; + + /// + /// Maximum average traffic rate (in bps) + /// + uint64_t getRateLimit() override; + + /// + /// Maximum size of a burst of packets (in bits) + /// + uint64_t getBurstLimit() override; + + void updateData(DefaultContractUpdateDataInputJsonObject input) override; + + std::string toString(); + + private: + ActionTypeEnum action_; + uint64_t rate_limit_; + uint64_t burst_limit_; + + void updateDataplane(); +}; diff --git a/src/services/pcn-policer/src/Policer-lib.cpp b/src/services/pcn-policer/src/Policer-lib.cpp new file mode 100644 index 000000000..6fbbe0c00 --- /dev/null +++ b/src/services/pcn-policer/src/Policer-lib.cpp @@ -0,0 +1,21 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +#include "api/PolicerApiImpl.h" +#include "../datamodel/policer.h" // generated from datamodel + +#define SERVICE_PYANG_GIT "" +#define SERVICE_SWAGGER_CODEGEN_GIT "bug-fixes/ba6e909" + +#include + +extern "C" const char *data_model() { + return policer_datamodel.c_str(); +} diff --git a/src/services/pcn-policer/src/Policer.cpp b/src/services/pcn-policer/src/Policer.cpp new file mode 100644 index 000000000..8658cafa1 --- /dev/null +++ b/src/services/pcn-policer/src/Policer.cpp @@ -0,0 +1,125 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#include "Policer.h" +#include "Policer_dp.h" + + +Policer::Policer(const std::string name, const PolicerJsonObject &conf) + : TransparentCube(conf.getBase(), {}, {}), PolicerBase(name) { + logger()->info("Creating Policer instance"); + + // Inject ingress program + std::string code = std::string("#define MAX_CONTRACTS ") + + std::to_string(MAX_CONTRACTS) + std::string("\n") + + policer_code; + add_program(code, 0, polycube::service::ProgramType::INGRESS); + + // Inject egress program + code = std::string("#define EGRESS_PROG\n") + code; + add_program(code, 0, polycube::service::ProgramType::EGRESS); + + default_contract_ = + std::make_shared(*this, conf.getDefaultContract()); + addContractList(conf.getContract()); +} + +Policer::~Policer() { + logger()->info("Destroying Policer instance"); +} + +void Policer::packet_in(polycube::service::Direction direction, + polycube::service::PacketInMetadata &md, + const std::vector &packet) { + logger()->debug("Packet received"); +} + +std::shared_ptr Policer::getDefaultContract() { + return default_contract_; +} + +void Policer::addDefaultContract(const DefaultContractJsonObject &value) { + throw std::runtime_error("Cannot add a default contract"); +} + +void Policer::replaceDefaultContract(const DefaultContractJsonObject &conf) { + throw std::runtime_error("Cannot replace the default contract"); +} + +void Policer::delDefaultContract() { + throw std::runtime_error("Cannot remove the default contract"); +} + +std::shared_ptr Policer::getContract(const uint32_t &trafficClass) { + if (contracts_.count(trafficClass) == 0) { + throw std::runtime_error("No contract registered for the given class"); + } + + return contracts_.at(trafficClass); +} + +std::vector> Policer::getContractList() { + std::vector> contracts_v; + + contracts_v.reserve(contracts_.size()); + + for (auto const &entry : contracts_) { + contracts_v.push_back(entry.second); + } + + return contracts_v; +} + +void Policer::addContract(const uint32_t &trafficClass, + const ContractJsonObject &conf) { + if (contracts_.count(trafficClass) != 0) { + throw std::runtime_error("Contract for the given class already registered"); + } + + if (contracts_.size() == MAX_CONTRACTS) { + throw std::runtime_error("Maximum number of contracts reached"); + } + + contracts_[trafficClass] = std::make_shared(*this, conf); +} + +// Basic default implementation, place your extension here (if needed) +void Policer::addContractList(const std::vector &conf) { + // call default implementation in base class + PolicerBase::addContractList(conf); +} + +// Basic default implementation, place your extension here (if needed) +void Policer::replaceContract(const uint32_t &trafficClass, + const ContractJsonObject &conf) { + // call default implementation in base class + PolicerBase::replaceContract(trafficClass, conf); +} + +void Policer::delContract(const uint32_t &trafficClass) { + if (contracts_.count(trafficClass) == 0) { + throw std::runtime_error("No contract registered for the given class"); + } + + contracts_.erase(trafficClass); +} + +// Basic default implementation, place your extension here (if needed) +void Policer::delContractList() { + // call default implementation in base class + PolicerBase::delContractList(); +} \ No newline at end of file diff --git a/src/services/pcn-policer/src/Policer.h b/src/services/pcn-policer/src/Policer.h new file mode 100644 index 000000000..f2b2c4eed --- /dev/null +++ b/src/services/pcn-policer/src/Policer.h @@ -0,0 +1,79 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#pragma once + + +#include "../base/PolicerBase.h" + +#include "Contract.h" +#include "DefaultContract.h" + + +#define MAX_CONTRACTS 1024 + + +struct bucket { + uint64_t tokens; + uint64_t refill_rate; // tokens/s + uint64_t capacity; + uint64_t last_update; +}; + +struct contract { + uint8_t action; + struct bucket bucket; + uint32_t reserved; // Used in kernel to store the spinlock +}; + +using namespace polycube::service::model; + + +class Policer : public PolicerBase { + public: + Policer(const std::string name, const PolicerJsonObject &conf); + ~Policer(); + + void packet_in(polycube::service::Direction direction, + polycube::service::PacketInMetadata &md, + const std::vector &packet) override; + + /// + /// Contract applied to traffic not matching any of the specified classes (default: PASS) + /// + std::shared_ptr getDefaultContract() override; + void addDefaultContract(const DefaultContractJsonObject &value) override; + void replaceDefaultContract(const DefaultContractJsonObject &conf) override; + void delDefaultContract() override; + + /// + /// Contract applied to a specific class of traffic + /// + std::shared_ptr getContract(const uint32_t &trafficClass) override; + std::vector> getContractList() override; + void addContract(const uint32_t &trafficClass, + const ContractJsonObject &conf) override; + void addContractList(const std::vector &conf) override; + void replaceContract(const uint32_t &trafficClass, + const ContractJsonObject &conf) override; + void delContract(const uint32_t &trafficClass) override; + void delContractList() override; + + private: + std::shared_ptr default_contract_; + std::unordered_map> contracts_; +}; diff --git a/src/services/pcn-policer/src/Policer_dp.c b/src/services/pcn-policer/src/Policer_dp.c new file mode 100644 index 000000000..ca8118127 --- /dev/null +++ b/src/services/pcn-policer/src/Policer_dp.c @@ -0,0 +1,121 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#include + + +enum { + ACTION_PASS, + ACTION_LIMIT, + ACTION_DROP +}; + +struct bucket { + u64 tokens; + u64 refill_rate; // tokens/s + u64 capacity; + u64 last_update; +}; + +struct contract { + u8 action; + struct bucket bucket; + struct bpf_spin_lock lock; +}; + +#ifdef EGRESS_PROG +BPF_TABLE("extern", int, struct contract, default_contract, 1); +BPF_TABLE("extern", u32, struct contract, contracts, MAX_CONTRACTS); +#else +BPF_TABLE_SHARED("array", int, struct contract, default_contract, 1); +BPF_TABLE_SHARED("hash", u32, struct contract, contracts, MAX_CONTRACTS); +#endif + + +static inline int limit_rate(struct CTXTYPE *ctx, struct contract *contract) { + struct bucket *bucket = &contract->bucket; + void *data = (void *)(long)ctx->data; + void *data_end = (void *)(long)ctx->data_end; + + u64 curtime = bpf_ktime_get_ns(); + + bpf_spin_lock(&contract->lock); + + // Refill tokens + // If last_update == 0 the bucket is new, no need to add tokens + if (bucket->last_update == 0) { + bucket->last_update = curtime; + + } else if (curtime > bucket->last_update){ + u64 new_tokens = + (curtime - bucket->last_update) * bucket->refill_rate / 1000000000; + if (new_tokens > 0) { + bucket->tokens += new_tokens; + if (bucket->tokens > bucket->capacity) { + bucket->tokens = bucket->capacity; + } + bucket->last_update = curtime; + } + } + + // Consume tokens + u32 size = (data_end - data) * 8; // In bits + u8 retval; + if (bucket->tokens >= size) { + bucket->tokens -= size; + retval = RX_OK; + } else { + retval = RX_DROP; + } + + bpf_spin_unlock(&contract->lock); + + return retval; +} + +static __always_inline +int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) { + int zero = 0; + + // Retrieve contract + struct contract *contract = contracts.lookup(&md->traffic_class); + if (!contract) { + contract = default_contract.lookup(&zero); + if (!contract) { + pcn_log(ctx, LOG_ERR, "Cannot access default contract"); + return RX_DROP; + } + } + + // Apply action + switch (contract->action) { + case ACTION_PASS: + return RX_OK; + break; + + case ACTION_LIMIT: + return limit_rate(ctx, contract); + break; + + case ACTION_DROP: + return RX_DROP; + break; + } + + pcn_log(ctx, LOG_ERR, "Unknown action"); + return RX_DROP; +} \ No newline at end of file diff --git a/src/services/pcn-policer/src/api/PolicerApi.cpp b/src/services/pcn-policer/src/api/PolicerApi.cpp new file mode 100644 index 000000000..fa5ba6a47 --- /dev/null +++ b/src/services/pcn-policer/src/api/PolicerApi.cpp @@ -0,0 +1,671 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + +#include "PolicerApi.h" +#include "PolicerApiImpl.h" + +using namespace polycube::service::model; +using namespace polycube::service::api::PolicerApiImpl; + +#ifdef __cplusplus +extern "C" { +#endif + +Response create_policer_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + PolicerJsonObject unique_value { request_body }; + + unique_value.setName(unique_name); + create_policer_by_id(unique_name, unique_value); + return { kCreated, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response create_policer_contract_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_trafficClass; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "traffic-class")) { + unique_trafficClass = keys[i].value.uint32; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + ContractJsonObject unique_value { request_body }; + + unique_value.setTrafficClass(unique_trafficClass); + create_policer_contract_by_id(unique_name, unique_trafficClass, unique_value); + return { kCreated, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response create_policer_contract_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + // Getting the body param + std::vector unique_value; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + std::vector unique_value; + for (auto &j : request_body) { + ContractJsonObject a { j }; + unique_value.push_back(a); + } + create_policer_contract_list_by_id(unique_name, unique_value); + return { kCreated, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response create_policer_contract_update_data_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_trafficClass; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "traffic-class")) { + unique_trafficClass = keys[i].value.uint32; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + ContractUpdateDataInputJsonObject unique_value { request_body }; + + create_policer_contract_update_data_by_id(unique_name, unique_trafficClass, unique_value); + return { kCreated, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response create_policer_default_contract_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + DefaultContractJsonObject unique_value { request_body }; + + create_policer_default_contract_by_id(unique_name, unique_value); + return { kCreated, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response create_policer_default_contract_update_data_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + DefaultContractUpdateDataInputJsonObject unique_value { request_body }; + + create_policer_default_contract_update_data_by_id(unique_name, unique_value); + return { kCreated, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response delete_policer_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + + try { + delete_policer_by_id(unique_name); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response delete_policer_contract_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_trafficClass; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "traffic-class")) { + unique_trafficClass = keys[i].value.uint32; + break; + } + } + + + try { + delete_policer_contract_by_id(unique_name, unique_trafficClass); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response delete_policer_contract_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + + try { + delete_policer_contract_list_by_id(unique_name); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response delete_policer_default_contract_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + + try { + delete_policer_default_contract_by_id(unique_name); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_policer_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + + try { + + auto x = read_policer_by_id(unique_name); + nlohmann::json response_body; + response_body = x.toJson(); + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_policer_contract_action_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_trafficClass; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "traffic-class")) { + unique_trafficClass = keys[i].value.uint32; + break; + } + } + + + try { + + auto x = read_policer_contract_action_by_id(unique_name, unique_trafficClass); + nlohmann::json response_body; + response_body = ContractJsonObject::ActionTypeEnum_to_string(x); + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_policer_contract_burst_limit_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_trafficClass; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "traffic-class")) { + unique_trafficClass = keys[i].value.uint32; + break; + } + } + + + try { + + auto x = read_policer_contract_burst_limit_by_id(unique_name, unique_trafficClass); + nlohmann::json response_body; + response_body = x; + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_policer_contract_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_trafficClass; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "traffic-class")) { + unique_trafficClass = keys[i].value.uint32; + break; + } + } + + + try { + + auto x = read_policer_contract_by_id(unique_name, unique_trafficClass); + nlohmann::json response_body; + response_body = x.toJson(); + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_policer_contract_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + + try { + + auto x = read_policer_contract_list_by_id(unique_name); + nlohmann::json response_body; + for (auto &i : x) { + response_body += i.toJson(); + } + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_policer_contract_rate_limit_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_trafficClass; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "traffic-class")) { + unique_trafficClass = keys[i].value.uint32; + break; + } + } + + + try { + + auto x = read_policer_contract_rate_limit_by_id(unique_name, unique_trafficClass); + nlohmann::json response_body; + response_body = x; + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_policer_default_contract_action_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + + try { + + auto x = read_policer_default_contract_action_by_id(unique_name); + nlohmann::json response_body; + response_body = DefaultContractJsonObject::ActionTypeEnum_to_string(x); + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_policer_default_contract_burst_limit_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + + try { + + auto x = read_policer_default_contract_burst_limit_by_id(unique_name); + nlohmann::json response_body; + response_body = x; + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_policer_default_contract_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + + try { + + auto x = read_policer_default_contract_by_id(unique_name); + nlohmann::json response_body; + response_body = x.toJson(); + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_policer_default_contract_rate_limit_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + + try { + + auto x = read_policer_default_contract_rate_limit_by_id(unique_name); + nlohmann::json response_body; + response_body = x; + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_policer_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + + + try { + + auto x = read_policer_list_by_id(); + nlohmann::json response_body; + for (auto &i : x) { + response_body += i.toJson(); + } + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response replace_policer_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + PolicerJsonObject unique_value { request_body }; + + unique_value.setName(unique_name); + replace_policer_by_id(unique_name, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response replace_policer_contract_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_trafficClass; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "traffic-class")) { + unique_trafficClass = keys[i].value.uint32; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + ContractJsonObject unique_value { request_body }; + + unique_value.setTrafficClass(unique_trafficClass); + replace_policer_contract_by_id(unique_name, unique_trafficClass, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response replace_policer_contract_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + // Getting the body param + std::vector unique_value; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + std::vector unique_value; + for (auto &j : request_body) { + ContractJsonObject a { j }; + unique_value.push_back(a); + } + replace_policer_contract_list_by_id(unique_name, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response replace_policer_default_contract_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + DefaultContractJsonObject unique_value { request_body }; + + replace_policer_default_contract_by_id(unique_name, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_policer_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + PolicerJsonObject unique_value { request_body }; + + unique_value.setName(unique_name); + update_policer_by_id(unique_name, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_policer_contract_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_trafficClass; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "traffic-class")) { + unique_trafficClass = keys[i].value.uint32; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + ContractJsonObject unique_value { request_body }; + + unique_value.setTrafficClass(unique_trafficClass); + update_policer_contract_by_id(unique_name, unique_trafficClass, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_policer_contract_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + // Getting the body param + std::vector unique_value; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + std::vector unique_value; + for (auto &j : request_body) { + ContractJsonObject a { j }; + unique_value.push_back(a); + } + update_policer_contract_list_by_id(unique_name, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_policer_default_contract_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + DefaultContractJsonObject unique_value { request_body }; + + update_policer_default_contract_by_id(unique_name, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_policer_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + + // Getting the body param + std::vector unique_value; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + std::vector unique_value; + for (auto &j : request_body) { + PolicerJsonObject a { j }; + unique_value.push_back(a); + } + update_policer_list_by_id(unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + + +Response policer_contract_list_by_id_help( + const char *name, const Key *keys, size_t num_keys) { + // Getting the path params + std::string unique_name { name }; + nlohmann::json val = read_policer_contract_list_by_id_get_list(unique_name); + + return { kOk, ::strdup(val.dump().c_str()) }; +} + +Response policer_list_by_id_help( + const char *name, const Key *keys, size_t num_keys) { + + nlohmann::json val = read_policer_list_by_id_get_list(); + + return { kOk, ::strdup(val.dump().c_str()) }; +} + +#ifdef __cplusplus +} +#endif + diff --git a/src/services/pcn-policer/src/api/PolicerApi.h b/src/services/pcn-policer/src/api/PolicerApi.h new file mode 100644 index 000000000..fc17537f0 --- /dev/null +++ b/src/services/pcn-policer/src/api/PolicerApi.h @@ -0,0 +1,74 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* PolicerApi.h +* +*/ + +#pragma once + +#define POLYCUBE_SERVICE_NAME "policer" + + +#include "polycube/services/response.h" +#include "polycube/services/shared_lib_elements.h" + +#include "ContractJsonObject.h" +#include "ContractUpdateDataInputJsonObject.h" +#include "DefaultContractJsonObject.h" +#include "DefaultContractUpdateDataInputJsonObject.h" +#include "PolicerJsonObject.h" +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +Response create_policer_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response create_policer_contract_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response create_policer_contract_list_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response create_policer_contract_update_data_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response create_policer_default_contract_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response create_policer_default_contract_update_data_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response delete_policer_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response delete_policer_contract_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response delete_policer_contract_list_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response delete_policer_default_contract_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_policer_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_policer_contract_action_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_policer_contract_burst_limit_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_policer_contract_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_policer_contract_list_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_policer_contract_rate_limit_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_policer_default_contract_action_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_policer_default_contract_burst_limit_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_policer_default_contract_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_policer_default_contract_rate_limit_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_policer_list_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response replace_policer_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response replace_policer_contract_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response replace_policer_contract_list_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response replace_policer_default_contract_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_policer_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_policer_contract_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_policer_contract_list_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_policer_default_contract_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_policer_list_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); + +Response policer_contract_list_by_id_help(const char *name, const Key *keys, size_t num_keys); +Response policer_list_by_id_help(const char *name, const Key *keys, size_t num_keys); + + +#ifdef __cplusplus +} +#endif + diff --git a/src/services/pcn-policer/src/api/PolicerApiImpl.cpp b/src/services/pcn-policer/src/api/PolicerApiImpl.cpp new file mode 100644 index 000000000..d0bab7c0a --- /dev/null +++ b/src/services/pcn-policer/src/api/PolicerApiImpl.cpp @@ -0,0 +1,582 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + +#include "PolicerApiImpl.h" + +namespace polycube { +namespace service { +namespace api { + +using namespace polycube::service::model; + +namespace PolicerApiImpl { +namespace { +std::unordered_map> cubes; +std::mutex cubes_mutex; + +std::shared_ptr get_cube(const std::string &name) { + std::lock_guard guard(cubes_mutex); + auto iter = cubes.find(name); + if (iter == cubes.end()) { + throw std::runtime_error("Cube " + name + " does not exist"); + } + + return iter->second; +} + +} + +void create_policer_by_id(const std::string &name, const PolicerJsonObject &jsonObject) { + { + // check if name is valid before creating it + std::lock_guard guard(cubes_mutex); + if (cubes.count(name) != 0) { + throw std::runtime_error("There is already a cube with name " + name); + } + } + auto ptr = std::make_shared(name, jsonObject); + std::unordered_map>::iterator iter; + bool inserted; + + std::lock_guard guard(cubes_mutex); + std::tie(iter, inserted) = cubes.emplace(name, std::move(ptr)); + + if (!inserted) { + throw std::runtime_error("There is already a cube with name " + name); + } +} + +void replace_policer_by_id(const std::string &name, const PolicerJsonObject &bridge){ + throw std::runtime_error("Method not supported!"); +} + +void delete_policer_by_id(const std::string &name) { + std::lock_guard guard(cubes_mutex); + if (cubes.count(name) == 0) { + throw std::runtime_error("Cube " + name + " does not exist"); + } + cubes.erase(name); +} + +std::vector read_policer_list_by_id() { + std::vector jsonObject_vect; + for(auto &i : cubes) { + auto m = get_cube(i.first); + jsonObject_vect.push_back(m->toJsonObject()); + } + return jsonObject_vect; +} + +std::vector> read_policer_list_by_id_get_list() { + std::vector> r; + for (auto &x : cubes) { + nlohmann::fifo_map m; + m["name"] = x.first; + r.push_back(std::move(m)); + } + return r; +} + +/** +* @brief Create contract by ID +* +* Create operation of resource: contract* +* +* @param[in] name ID of name +* @param[in] trafficClass ID of traffic-class +* @param[in] value contractbody object +* +* Responses: +* +*/ +void +create_policer_contract_by_id(const std::string &name, const uint32_t &trafficClass, const ContractJsonObject &value) { + auto policer = get_cube(name); + + return policer->addContract(trafficClass, value); +} + +/** +* @brief Create contract by ID +* +* Create operation of resource: contract* +* +* @param[in] name ID of name +* @param[in] value contractbody object +* +* Responses: +* +*/ +void +create_policer_contract_list_by_id(const std::string &name, const std::vector &value) { + auto policer = get_cube(name); + policer->addContractList(value); +} + +/** +* @brief Create update-data by ID +* +* Create operation of resource: update-data* +* +* @param[in] name ID of name +* @param[in] trafficClass ID of traffic-class +* @param[in] value update-databody object +* +* Responses: +* +*/ +void +create_policer_contract_update_data_by_id(const std::string &name, const uint32_t &trafficClass, const ContractUpdateDataInputJsonObject &value) { + auto policer = get_cube(name); + auto contract = policer->getContract(trafficClass); + + return contract->updateData(value); +} + +/** +* @brief Create default-contract by ID +* +* Create operation of resource: default-contract* +* +* @param[in] name ID of name +* @param[in] value default-contractbody object +* +* Responses: +* +*/ +void +create_policer_default_contract_by_id(const std::string &name, const DefaultContractJsonObject &value) { + auto policer = get_cube(name); + + return policer->addDefaultContract(value); +} + +/** +* @brief Create update-data by ID +* +* Create operation of resource: update-data* +* +* @param[in] name ID of name +* @param[in] value update-databody object +* +* Responses: +* +*/ +void +create_policer_default_contract_update_data_by_id(const std::string &name, const DefaultContractUpdateDataInputJsonObject &value) { + auto policer = get_cube(name); + auto defaultContract = policer->getDefaultContract(); + + return defaultContract->updateData(value); +} + +/** +* @brief Delete contract by ID +* +* Delete operation of resource: contract* +* +* @param[in] name ID of name +* @param[in] trafficClass ID of traffic-class +* +* Responses: +* +*/ +void +delete_policer_contract_by_id(const std::string &name, const uint32_t &trafficClass) { + auto policer = get_cube(name); + + return policer->delContract(trafficClass); +} + +/** +* @brief Delete contract by ID +* +* Delete operation of resource: contract* +* +* @param[in] name ID of name +* +* Responses: +* +*/ +void +delete_policer_contract_list_by_id(const std::string &name) { + auto policer = get_cube(name); + policer->delContractList(); +} + +/** +* @brief Delete default-contract by ID +* +* Delete operation of resource: default-contract* +* +* @param[in] name ID of name +* +* Responses: +* +*/ +void +delete_policer_default_contract_by_id(const std::string &name) { + auto policer = get_cube(name); + + return policer->delDefaultContract(); +} + +/** +* @brief Read policer by ID +* +* Read operation of resource: policer* +* +* @param[in] name ID of name +* +* Responses: +* PolicerJsonObject +*/ +PolicerJsonObject +read_policer_by_id(const std::string &name) { + return get_cube(name)->toJsonObject(); + +} + +/** +* @brief Read action by ID +* +* Read operation of resource: action* +* +* @param[in] name ID of name +* @param[in] trafficClass ID of traffic-class +* +* Responses: +* ActionTypeEnum +*/ +ActionTypeEnum +read_policer_contract_action_by_id(const std::string &name, const uint32_t &trafficClass) { + auto policer = get_cube(name); + auto contract = policer->getContract(trafficClass); + return contract->getAction(); + +} + +/** +* @brief Read burst-limit by ID +* +* Read operation of resource: burst-limit* +* +* @param[in] name ID of name +* @param[in] trafficClass ID of traffic-class +* +* Responses: +* uint64_t +*/ +uint64_t +read_policer_contract_burst_limit_by_id(const std::string &name, const uint32_t &trafficClass) { + auto policer = get_cube(name); + auto contract = policer->getContract(trafficClass); + return contract->getBurstLimit(); + +} + +/** +* @brief Read contract by ID +* +* Read operation of resource: contract* +* +* @param[in] name ID of name +* @param[in] trafficClass ID of traffic-class +* +* Responses: +* ContractJsonObject +*/ +ContractJsonObject +read_policer_contract_by_id(const std::string &name, const uint32_t &trafficClass) { + auto policer = get_cube(name); + return policer->getContract(trafficClass)->toJsonObject(); + +} + +/** +* @brief Read contract by ID +* +* Read operation of resource: contract* +* +* @param[in] name ID of name +* +* Responses: +* std::vector +*/ +std::vector +read_policer_contract_list_by_id(const std::string &name) { + auto policer = get_cube(name); + auto &&contract = policer->getContractList(); + std::vector m; + for(auto &i : contract) + m.push_back(i->toJsonObject()); + return m; +} + +/** +* @brief Read rate-limit by ID +* +* Read operation of resource: rate-limit* +* +* @param[in] name ID of name +* @param[in] trafficClass ID of traffic-class +* +* Responses: +* uint64_t +*/ +uint64_t +read_policer_contract_rate_limit_by_id(const std::string &name, const uint32_t &trafficClass) { + auto policer = get_cube(name); + auto contract = policer->getContract(trafficClass); + return contract->getRateLimit(); + +} + +/** +* @brief Read action by ID +* +* Read operation of resource: action* +* +* @param[in] name ID of name +* +* Responses: +* ActionTypeEnum +*/ +ActionTypeEnum +read_policer_default_contract_action_by_id(const std::string &name) { + auto policer = get_cube(name); + auto defaultContract = policer->getDefaultContract(); + return defaultContract->getAction(); + +} + +/** +* @brief Read burst-limit by ID +* +* Read operation of resource: burst-limit* +* +* @param[in] name ID of name +* +* Responses: +* uint64_t +*/ +uint64_t +read_policer_default_contract_burst_limit_by_id(const std::string &name) { + auto policer = get_cube(name); + auto defaultContract = policer->getDefaultContract(); + return defaultContract->getBurstLimit(); + +} + +/** +* @brief Read default-contract by ID +* +* Read operation of resource: default-contract* +* +* @param[in] name ID of name +* +* Responses: +* DefaultContractJsonObject +*/ +DefaultContractJsonObject +read_policer_default_contract_by_id(const std::string &name) { + auto policer = get_cube(name); + return policer->getDefaultContract()->toJsonObject(); + +} + +/** +* @brief Read rate-limit by ID +* +* Read operation of resource: rate-limit* +* +* @param[in] name ID of name +* +* Responses: +* uint64_t +*/ +uint64_t +read_policer_default_contract_rate_limit_by_id(const std::string &name) { + auto policer = get_cube(name); + auto defaultContract = policer->getDefaultContract(); + return defaultContract->getRateLimit(); + +} + +/** +* @brief Replace contract by ID +* +* Replace operation of resource: contract* +* +* @param[in] name ID of name +* @param[in] trafficClass ID of traffic-class +* @param[in] value contractbody object +* +* Responses: +* +*/ +void +replace_policer_contract_by_id(const std::string &name, const uint32_t &trafficClass, const ContractJsonObject &value) { + auto policer = get_cube(name); + + return policer->replaceContract(trafficClass, value); +} + +/** +* @brief Replace contract by ID +* +* Replace operation of resource: contract* +* +* @param[in] name ID of name +* @param[in] value contractbody object +* +* Responses: +* +*/ +void +replace_policer_contract_list_by_id(const std::string &name, const std::vector &value) { + throw std::runtime_error("Method not supported"); +} + +/** +* @brief Replace default-contract by ID +* +* Replace operation of resource: default-contract* +* +* @param[in] name ID of name +* @param[in] value default-contractbody object +* +* Responses: +* +*/ +void +replace_policer_default_contract_by_id(const std::string &name, const DefaultContractJsonObject &value) { + auto policer = get_cube(name); + + return policer->replaceDefaultContract(value); +} + +/** +* @brief Update policer by ID +* +* Update operation of resource: policer* +* +* @param[in] name ID of name +* @param[in] value policerbody object +* +* Responses: +* +*/ +void +update_policer_by_id(const std::string &name, const PolicerJsonObject &value) { + auto policer = get_cube(name); + + return policer->update(value); +} + +/** +* @brief Update contract by ID +* +* Update operation of resource: contract* +* +* @param[in] name ID of name +* @param[in] trafficClass ID of traffic-class +* @param[in] value contractbody object +* +* Responses: +* +*/ +void +update_policer_contract_by_id(const std::string &name, const uint32_t &trafficClass, const ContractJsonObject &value) { + auto policer = get_cube(name); + auto contract = policer->getContract(trafficClass); + + return contract->update(value); +} + +/** +* @brief Update contract by ID +* +* Update operation of resource: contract* +* +* @param[in] name ID of name +* @param[in] value contractbody object +* +* Responses: +* +*/ +void +update_policer_contract_list_by_id(const std::string &name, const std::vector &value) { + throw std::runtime_error("Method not supported"); +} + +/** +* @brief Update default-contract by ID +* +* Update operation of resource: default-contract* +* +* @param[in] name ID of name +* @param[in] value default-contractbody object +* +* Responses: +* +*/ +void +update_policer_default_contract_by_id(const std::string &name, const DefaultContractJsonObject &value) { + auto policer = get_cube(name); + auto defaultContract = policer->getDefaultContract(); + + return defaultContract->update(value); +} + +/** +* @brief Update policer by ID +* +* Update operation of resource: policer* +* +* @param[in] value policerbody object +* +* Responses: +* +*/ +void +update_policer_list_by_id(const std::vector &value) { + throw std::runtime_error("Method not supported"); +} + + + +/* + * help related + */ + +std::vector> read_policer_contract_list_by_id_get_list(const std::string &name) { + std::vector> r; + auto &&policer = get_cube(name); + + auto &&contract = policer->getContractList(); + for(auto &i : contract) { + nlohmann::fifo_map keys; + + keys["trafficClass"] = std::to_string(i->getTrafficClass()); + + r.push_back(keys); + } + return r; +} + + +} + +} +} +} + diff --git a/src/services/pcn-policer/src/api/PolicerApiImpl.h b/src/services/pcn-policer/src/api/PolicerApiImpl.h new file mode 100644 index 000000000..93aaa2f01 --- /dev/null +++ b/src/services/pcn-policer/src/api/PolicerApiImpl.h @@ -0,0 +1,78 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* PolicerApiImpl.h +* +* +*/ + +#pragma once + + +#include +#include +#include +#include "../Policer.h" + +#include "ContractJsonObject.h" +#include "ContractUpdateDataInputJsonObject.h" +#include "DefaultContractJsonObject.h" +#include "DefaultContractUpdateDataInputJsonObject.h" +#include "PolicerJsonObject.h" +#include + +namespace polycube { +namespace service { +namespace api { + +using namespace polycube::service::model; + +namespace PolicerApiImpl { + void create_policer_by_id(const std::string &name, const PolicerJsonObject &value); + void create_policer_contract_by_id(const std::string &name, const uint32_t &trafficClass, const ContractJsonObject &value); + void create_policer_contract_list_by_id(const std::string &name, const std::vector &value); + void create_policer_contract_update_data_by_id(const std::string &name, const uint32_t &trafficClass, const ContractUpdateDataInputJsonObject &value); + void create_policer_default_contract_by_id(const std::string &name, const DefaultContractJsonObject &value); + void create_policer_default_contract_update_data_by_id(const std::string &name, const DefaultContractUpdateDataInputJsonObject &value); + void delete_policer_by_id(const std::string &name); + void delete_policer_contract_by_id(const std::string &name, const uint32_t &trafficClass); + void delete_policer_contract_list_by_id(const std::string &name); + void delete_policer_default_contract_by_id(const std::string &name); + PolicerJsonObject read_policer_by_id(const std::string &name); + ActionTypeEnum read_policer_contract_action_by_id(const std::string &name, const uint32_t &trafficClass); + uint64_t read_policer_contract_burst_limit_by_id(const std::string &name, const uint32_t &trafficClass); + ContractJsonObject read_policer_contract_by_id(const std::string &name, const uint32_t &trafficClass); + std::vector read_policer_contract_list_by_id(const std::string &name); + uint64_t read_policer_contract_rate_limit_by_id(const std::string &name, const uint32_t &trafficClass); + ActionTypeEnum read_policer_default_contract_action_by_id(const std::string &name); + uint64_t read_policer_default_contract_burst_limit_by_id(const std::string &name); + DefaultContractJsonObject read_policer_default_contract_by_id(const std::string &name); + uint64_t read_policer_default_contract_rate_limit_by_id(const std::string &name); + std::vector read_policer_list_by_id(); + void replace_policer_by_id(const std::string &name, const PolicerJsonObject &value); + void replace_policer_contract_by_id(const std::string &name, const uint32_t &trafficClass, const ContractJsonObject &value); + void replace_policer_contract_list_by_id(const std::string &name, const std::vector &value); + void replace_policer_default_contract_by_id(const std::string &name, const DefaultContractJsonObject &value); + void update_policer_by_id(const std::string &name, const PolicerJsonObject &value); + void update_policer_contract_by_id(const std::string &name, const uint32_t &trafficClass, const ContractJsonObject &value); + void update_policer_contract_list_by_id(const std::string &name, const std::vector &value); + void update_policer_default_contract_by_id(const std::string &name, const DefaultContractJsonObject &value); + void update_policer_list_by_id(const std::vector &value); + + /* help related */ + std::vector> read_policer_contract_list_by_id_get_list(const std::string &name); + std::vector> read_policer_list_by_id_get_list(); + +} +} +} +} + diff --git a/src/services/pcn-policer/src/base/ContractBase.cpp b/src/services/pcn-policer/src/base/ContractBase.cpp new file mode 100644 index 000000000..9ca15b488 --- /dev/null +++ b/src/services/pcn-policer/src/base/ContractBase.cpp @@ -0,0 +1,39 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + +#include "ContractBase.h" +#include "../Policer.h" + + +ContractBase::ContractBase(Policer &parent) + : parent_(parent) {} + +ContractBase::~ContractBase() {} + +void ContractBase::update(const ContractJsonObject &conf) { + +} + +ContractJsonObject ContractBase::toJsonObject() { + ContractJsonObject conf; + + conf.setTrafficClass(getTrafficClass()); + conf.setAction(getAction()); + conf.setRateLimit(getRateLimit()); + conf.setBurstLimit(getBurstLimit()); + + return conf; +} + +std::shared_ptr ContractBase::logger() { + return parent_.logger(); +} + diff --git a/src/services/pcn-policer/src/base/ContractBase.h b/src/services/pcn-policer/src/base/ContractBase.h new file mode 100644 index 000000000..2034e7561 --- /dev/null +++ b/src/services/pcn-policer/src/base/ContractBase.h @@ -0,0 +1,67 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* ContractBase.h +* +* +*/ + +#pragma once + +#include "../serializer/ContractJsonObject.h" + +#include "../serializer/ContractUpdateDataInputJsonObject.h" + + + + + + +#include + +using namespace polycube::service::model; + +class Policer; + +class ContractBase { + public: + + ContractBase(Policer &parent); + + virtual ~ContractBase(); + virtual void update(const ContractJsonObject &conf); + virtual ContractJsonObject toJsonObject(); + + /// + /// Identifier of the class of traffic, provided as packet metadata + /// + virtual uint32_t getTrafficClass() = 0; + + /// + /// Action applied to traffic of the contract: PASS = Let all the traffic pass without limitations; LIMIT = Apply rate and burst limits to selected traffic; DROP = Drop all the traffic + /// + virtual ActionTypeEnum getAction() = 0; + + /// + /// Maximum average traffic rate (in bps) + /// + virtual uint64_t getRateLimit() = 0; + + /// + /// Maximum size of a burst of packets (in bits) + /// + virtual uint64_t getBurstLimit() = 0; + virtual void updateData(ContractUpdateDataInputJsonObject input) = 0; + + std::shared_ptr logger(); + protected: + Policer &parent_; +}; diff --git a/src/services/pcn-policer/src/base/DefaultContractBase.cpp b/src/services/pcn-policer/src/base/DefaultContractBase.cpp new file mode 100644 index 000000000..4a63dd5bd --- /dev/null +++ b/src/services/pcn-policer/src/base/DefaultContractBase.cpp @@ -0,0 +1,38 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + +#include "DefaultContractBase.h" +#include "../Policer.h" + + +DefaultContractBase::DefaultContractBase(Policer &parent) + : parent_(parent) {} + +DefaultContractBase::~DefaultContractBase() {} + +void DefaultContractBase::update(const DefaultContractJsonObject &conf) { + +} + +DefaultContractJsonObject DefaultContractBase::toJsonObject() { + DefaultContractJsonObject conf; + + conf.setAction(getAction()); + conf.setRateLimit(getRateLimit()); + conf.setBurstLimit(getBurstLimit()); + + return conf; +} + +std::shared_ptr DefaultContractBase::logger() { + return parent_.logger(); +} + diff --git a/src/services/pcn-policer/src/base/DefaultContractBase.h b/src/services/pcn-policer/src/base/DefaultContractBase.h new file mode 100644 index 000000000..85d3c6604 --- /dev/null +++ b/src/services/pcn-policer/src/base/DefaultContractBase.h @@ -0,0 +1,62 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* DefaultContractBase.h +* +* +*/ + +#pragma once + +#include "../serializer/DefaultContractJsonObject.h" + +#include "../serializer/DefaultContractUpdateDataInputJsonObject.h" + + + + + + +#include + +using namespace polycube::service::model; + +class Policer; + +class DefaultContractBase { + public: + + DefaultContractBase(Policer &parent); + + virtual ~DefaultContractBase(); + virtual void update(const DefaultContractJsonObject &conf); + virtual DefaultContractJsonObject toJsonObject(); + + /// + /// Action applied to traffic of the contract: PASS = Let all the traffic pass without limitations; LIMIT = Apply rate and burst limits to selected traffic; DROP = Drop all the traffic + /// + virtual ActionTypeEnum getAction() = 0; + + /// + /// Maximum average traffic rate (in bps) + /// + virtual uint64_t getRateLimit() = 0; + + /// + /// Maximum size of a burst of packets (in bits) + /// + virtual uint64_t getBurstLimit() = 0; + virtual void updateData(DefaultContractUpdateDataInputJsonObject input) = 0; + + std::shared_ptr logger(); + protected: + Policer &parent_; +}; diff --git a/src/services/pcn-policer/src/base/PolicerBase.cpp b/src/services/pcn-policer/src/base/PolicerBase.cpp new file mode 100644 index 000000000..29ff3d750 --- /dev/null +++ b/src/services/pcn-policer/src/base/PolicerBase.cpp @@ -0,0 +1,77 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + +#include "PolicerBase.h" + +PolicerBase::PolicerBase(const std::string name) { + logger()->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [Policer] [%n] [%l] %v"); +} + + + +PolicerBase::~PolicerBase() {} + +void PolicerBase::update(const PolicerJsonObject &conf) { + set_conf(conf.getBase()); + + if (conf.defaultContractIsSet()) { + auto m = getDefaultContract(); + m->update(conf.getDefaultContract()); + } + if (conf.contractIsSet()) { + for (auto &i : conf.getContract()) { + auto trafficClass = i.getTrafficClass(); + auto m = getContract(trafficClass); + m->update(i); + } + } +} + +PolicerJsonObject PolicerBase::toJsonObject() { + PolicerJsonObject conf; + conf.setBase(to_json()); + + conf.setName(getName()); + conf.setDefaultContract(getDefaultContract()->toJsonObject()); + for(auto &i : getContractList()) { + conf.addContract(i->toJsonObject()); + } + + return conf; +} + +void PolicerBase::replaceDefaultContract(const DefaultContractJsonObject &conf) { + // TODO: This is a basic default implementation, maybe you want to improve it + delDefaultContract(); + addDefaultContract(conf); +} +void PolicerBase::addContractList(const std::vector &conf) { + for (auto &i : conf) { + uint32_t trafficClass_ = i.getTrafficClass(); + addContract(trafficClass_, i); + } +} + +void PolicerBase::replaceContract(const uint32_t &trafficClass, const ContractJsonObject &conf) { + delContract(trafficClass); + uint32_t trafficClass_ = conf.getTrafficClass(); + addContract(trafficClass_, conf); +} + +void PolicerBase::delContractList() { + auto elements = getContractList(); + for (auto &i : elements) { + uint32_t trafficClass_ = i->getTrafficClass(); + delContract(trafficClass_); + } +} + + diff --git a/src/services/pcn-policer/src/base/PolicerBase.h b/src/services/pcn-policer/src/base/PolicerBase.h new file mode 100644 index 000000000..8b076a65d --- /dev/null +++ b/src/services/pcn-policer/src/base/PolicerBase.h @@ -0,0 +1,62 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* PolicerBase.h +* +* +*/ + +#pragma once + +#include "../serializer/PolicerJsonObject.h" + +#include "../Contract.h" +#include "../DefaultContract.h" + +#include "polycube/services/transparent_cube.h" + + + +#include "polycube/services/utils.h" +#include "polycube/services/fifo_map.hpp" + +#include + +using namespace polycube::service::model; + + +class PolicerBase: public virtual polycube::service::TransparentCube { + public: + PolicerBase(const std::string name); + + virtual ~PolicerBase(); + virtual void update(const PolicerJsonObject &conf); + virtual PolicerJsonObject toJsonObject(); + + /// + /// Contract applied to traffic not matching any of the specified classes (default: PASS) + /// + virtual std::shared_ptr getDefaultContract() = 0; + virtual void addDefaultContract(const DefaultContractJsonObject &value) = 0; + virtual void replaceDefaultContract(const DefaultContractJsonObject &conf); + virtual void delDefaultContract() = 0; + + /// + /// Contract applied to a specific class of traffic + /// + virtual std::shared_ptr getContract(const uint32_t &trafficClass) = 0; + virtual std::vector> getContractList() = 0; + virtual void addContract(const uint32_t &trafficClass, const ContractJsonObject &conf) = 0; + virtual void addContractList(const std::vector &conf); + virtual void replaceContract(const uint32_t &trafficClass, const ContractJsonObject &conf); + virtual void delContract(const uint32_t &trafficClass) = 0; + virtual void delContractList(); +}; diff --git a/src/services/pcn-policer/src/serializer/ContractJsonObject.cpp b/src/services/pcn-policer/src/serializer/ContractJsonObject.cpp new file mode 100644 index 000000000..15e63d850 --- /dev/null +++ b/src/services/pcn-policer/src/serializer/ContractJsonObject.cpp @@ -0,0 +1,167 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + + +#include "ContractJsonObject.h" +#include + +namespace polycube { +namespace service { +namespace model { + +ContractJsonObject::ContractJsonObject() { + m_trafficClassIsSet = false; + m_actionIsSet = false; + m_rateLimitIsSet = false; + m_burstLimitIsSet = false; +} + +ContractJsonObject::ContractJsonObject(const nlohmann::json &val) : + JsonObjectBase(val) { + m_trafficClassIsSet = false; + m_actionIsSet = false; + m_rateLimitIsSet = false; + m_burstLimitIsSet = false; + + + if (val.count("traffic-class")) { + setTrafficClass(val.at("traffic-class").get()); + } + + if (val.count("action")) { + setAction(string_to_ActionTypeEnum(val.at("action").get())); + } + + if (val.count("rate-limit")) { + setRateLimit(val.at("rate-limit").get()); + } + + if (val.count("burst-limit")) { + setBurstLimit(val.at("burst-limit").get()); + } +} + +nlohmann::json ContractJsonObject::toJson() const { + nlohmann::json val = nlohmann::json::object(); + if (!getBase().is_null()) { + val.update(getBase()); + } + + if (m_trafficClassIsSet) { + val["traffic-class"] = m_trafficClass; + } + + if (m_actionIsSet) { + val["action"] = ActionTypeEnum_to_string(m_action); + } + + if (m_rateLimitIsSet) { + val["rate-limit"] = m_rateLimit; + } + + if (m_burstLimitIsSet) { + val["burst-limit"] = m_burstLimit; + } + + return val; +} + +uint32_t ContractJsonObject::getTrafficClass() const { + return m_trafficClass; +} + +void ContractJsonObject::setTrafficClass(uint32_t value) { + m_trafficClass = value; + m_trafficClassIsSet = true; +} + +bool ContractJsonObject::trafficClassIsSet() const { + return m_trafficClassIsSet; +} + + + +ActionTypeEnum ContractJsonObject::getAction() const { + return m_action; +} + +void ContractJsonObject::setAction(ActionTypeEnum value) { + m_action = value; + m_actionIsSet = true; +} + +bool ContractJsonObject::actionIsSet() const { + return m_actionIsSet; +} + + + +std::string ContractJsonObject::ActionTypeEnum_to_string(const ActionTypeEnum &value){ + switch(value) { + case ActionTypeEnum::PASS: + return std::string("pass"); + case ActionTypeEnum::LIMIT: + return std::string("limit"); + case ActionTypeEnum::DROP: + return std::string("drop"); + default: + throw std::runtime_error("Bad Contract action"); + } +} + +ActionTypeEnum ContractJsonObject::string_to_ActionTypeEnum(const std::string &str){ + if (JsonObjectBase::iequals("pass", str)) + return ActionTypeEnum::PASS; + if (JsonObjectBase::iequals("limit", str)) + return ActionTypeEnum::LIMIT; + if (JsonObjectBase::iequals("drop", str)) + return ActionTypeEnum::DROP; + throw std::runtime_error("Contract action is invalid"); +} +uint64_t ContractJsonObject::getRateLimit() const { + return m_rateLimit; +} + +void ContractJsonObject::setRateLimit(uint64_t value) { + m_rateLimit = value; + m_rateLimitIsSet = true; +} + +bool ContractJsonObject::rateLimitIsSet() const { + return m_rateLimitIsSet; +} + +void ContractJsonObject::unsetRateLimit() { + m_rateLimitIsSet = false; +} + +uint64_t ContractJsonObject::getBurstLimit() const { + return m_burstLimit; +} + +void ContractJsonObject::setBurstLimit(uint64_t value) { + m_burstLimit = value; + m_burstLimitIsSet = true; +} + +bool ContractJsonObject::burstLimitIsSet() const { + return m_burstLimitIsSet; +} + +void ContractJsonObject::unsetBurstLimit() { + m_burstLimitIsSet = false; +} + + +} +} +} + diff --git a/src/services/pcn-policer/src/serializer/ContractJsonObject.h b/src/services/pcn-policer/src/serializer/ContractJsonObject.h new file mode 100644 index 000000000..af60f790c --- /dev/null +++ b/src/services/pcn-policer/src/serializer/ContractJsonObject.h @@ -0,0 +1,91 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* ContractJsonObject.h +* +* +*/ + +#pragma once + + +#include "JsonObjectBase.h" + + +namespace polycube { +namespace service { +namespace model { + +#ifndef ACTIONTYPEENUM +#define ACTIONTYPEENUM +enum class ActionTypeEnum { + PASS, LIMIT, DROP +}; +#endif + +/// +/// +/// +class ContractJsonObject : public JsonObjectBase { +public: + ContractJsonObject(); + ContractJsonObject(const nlohmann::json &json); + ~ContractJsonObject() final = default; + nlohmann::json toJson() const final; + + + /// + /// Identifier of the class of traffic, provided as packet metadata + /// + uint32_t getTrafficClass() const; + void setTrafficClass(uint32_t value); + bool trafficClassIsSet() const; + + /// + /// Action applied to traffic of the contract: PASS = Let all the traffic pass without limitations; LIMIT = Apply rate and burst limits to selected traffic; DROP = Drop all the traffic + /// + ActionTypeEnum getAction() const; + void setAction(ActionTypeEnum value); + bool actionIsSet() const; + static std::string ActionTypeEnum_to_string(const ActionTypeEnum &value); + static ActionTypeEnum string_to_ActionTypeEnum(const std::string &str); + + /// + /// Maximum average traffic rate (in bps) + /// + uint64_t getRateLimit() const; + void setRateLimit(uint64_t value); + bool rateLimitIsSet() const; + void unsetRateLimit(); + + /// + /// Maximum size of a burst of packets (in bits) + /// + uint64_t getBurstLimit() const; + void setBurstLimit(uint64_t value); + bool burstLimitIsSet() const; + void unsetBurstLimit(); + +private: + uint32_t m_trafficClass; + bool m_trafficClassIsSet; + ActionTypeEnum m_action; + bool m_actionIsSet; + uint64_t m_rateLimit; + bool m_rateLimitIsSet; + uint64_t m_burstLimit; + bool m_burstLimitIsSet; +}; + +} +} +} + diff --git a/src/services/pcn-policer/src/serializer/ContractUpdateDataInputJsonObject.cpp b/src/services/pcn-policer/src/serializer/ContractUpdateDataInputJsonObject.cpp new file mode 100644 index 000000000..c30ab416b --- /dev/null +++ b/src/services/pcn-policer/src/serializer/ContractUpdateDataInputJsonObject.cpp @@ -0,0 +1,144 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + + +#include "ContractUpdateDataInputJsonObject.h" +#include + +namespace polycube { +namespace service { +namespace model { + +ContractUpdateDataInputJsonObject::ContractUpdateDataInputJsonObject() { + m_actionIsSet = false; + m_rateLimitIsSet = false; + m_burstLimitIsSet = false; +} + +ContractUpdateDataInputJsonObject::ContractUpdateDataInputJsonObject(const nlohmann::json &val) : + JsonObjectBase(val) { + m_actionIsSet = false; + m_rateLimitIsSet = false; + m_burstLimitIsSet = false; + + + if (val.count("action")) { + setAction(string_to_ActionTypeEnum(val.at("action").get())); + } + + if (val.count("rate-limit")) { + setRateLimit(val.at("rate-limit").get()); + } + + if (val.count("burst-limit")) { + setBurstLimit(val.at("burst-limit").get()); + } +} + +nlohmann::json ContractUpdateDataInputJsonObject::toJson() const { + nlohmann::json val = nlohmann::json::object(); + if (!getBase().is_null()) { + val.update(getBase()); + } + + if (m_actionIsSet) { + val["action"] = ActionTypeEnum_to_string(m_action); + } + + if (m_rateLimitIsSet) { + val["rate-limit"] = m_rateLimit; + } + + if (m_burstLimitIsSet) { + val["burst-limit"] = m_burstLimit; + } + + return val; +} + +ActionTypeEnum ContractUpdateDataInputJsonObject::getAction() const { + return m_action; +} + +void ContractUpdateDataInputJsonObject::setAction(ActionTypeEnum value) { + m_action = value; + m_actionIsSet = true; +} + +bool ContractUpdateDataInputJsonObject::actionIsSet() const { + return m_actionIsSet; +} + +void ContractUpdateDataInputJsonObject::unsetAction() { + m_actionIsSet = false; +} + +std::string ContractUpdateDataInputJsonObject::ActionTypeEnum_to_string(const ActionTypeEnum &value){ + switch(value) { + case ActionTypeEnum::PASS: + return std::string("pass"); + case ActionTypeEnum::LIMIT: + return std::string("limit"); + case ActionTypeEnum::DROP: + return std::string("drop"); + default: + throw std::runtime_error("Bad ContractUpdateDataInput action"); + } +} + +ActionTypeEnum ContractUpdateDataInputJsonObject::string_to_ActionTypeEnum(const std::string &str){ + if (JsonObjectBase::iequals("pass", str)) + return ActionTypeEnum::PASS; + if (JsonObjectBase::iequals("limit", str)) + return ActionTypeEnum::LIMIT; + if (JsonObjectBase::iequals("drop", str)) + return ActionTypeEnum::DROP; + throw std::runtime_error("ContractUpdateDataInput action is invalid"); +} +uint64_t ContractUpdateDataInputJsonObject::getRateLimit() const { + return m_rateLimit; +} + +void ContractUpdateDataInputJsonObject::setRateLimit(uint64_t value) { + m_rateLimit = value; + m_rateLimitIsSet = true; +} + +bool ContractUpdateDataInputJsonObject::rateLimitIsSet() const { + return m_rateLimitIsSet; +} + +void ContractUpdateDataInputJsonObject::unsetRateLimit() { + m_rateLimitIsSet = false; +} + +uint64_t ContractUpdateDataInputJsonObject::getBurstLimit() const { + return m_burstLimit; +} + +void ContractUpdateDataInputJsonObject::setBurstLimit(uint64_t value) { + m_burstLimit = value; + m_burstLimitIsSet = true; +} + +bool ContractUpdateDataInputJsonObject::burstLimitIsSet() const { + return m_burstLimitIsSet; +} + +void ContractUpdateDataInputJsonObject::unsetBurstLimit() { + m_burstLimitIsSet = false; +} + + +} +} +} + diff --git a/src/services/pcn-policer/src/serializer/ContractUpdateDataInputJsonObject.h b/src/services/pcn-policer/src/serializer/ContractUpdateDataInputJsonObject.h new file mode 100644 index 000000000..3868c7f5c --- /dev/null +++ b/src/services/pcn-policer/src/serializer/ContractUpdateDataInputJsonObject.h @@ -0,0 +1,83 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* ContractUpdateDataInputJsonObject.h +* +* +*/ + +#pragma once + + +#include "JsonObjectBase.h" + + +namespace polycube { +namespace service { +namespace model { + +#ifndef ACTIONTYPEENUM +#define ACTIONTYPEENUM +enum class ActionTypeEnum { + PASS, LIMIT, DROP +}; +#endif + +/// +/// +/// +class ContractUpdateDataInputJsonObject : public JsonObjectBase { +public: + ContractUpdateDataInputJsonObject(); + ContractUpdateDataInputJsonObject(const nlohmann::json &json); + ~ContractUpdateDataInputJsonObject() final = default; + nlohmann::json toJson() const final; + + + /// + /// Action applied to traffic of the contract: PASS = Let all the traffic pass without limitations; LIMIT = Apply rate and burst limits to selected traffic; DROP = Drop all the traffic + /// + ActionTypeEnum getAction() const; + void setAction(ActionTypeEnum value); + bool actionIsSet() const; + void unsetAction(); + static std::string ActionTypeEnum_to_string(const ActionTypeEnum &value); + static ActionTypeEnum string_to_ActionTypeEnum(const std::string &str); + + /// + /// Maximum average traffic rate (in bps) + /// + uint64_t getRateLimit() const; + void setRateLimit(uint64_t value); + bool rateLimitIsSet() const; + void unsetRateLimit(); + + /// + /// Maximum size of a burst of packets (in bits) + /// + uint64_t getBurstLimit() const; + void setBurstLimit(uint64_t value); + bool burstLimitIsSet() const; + void unsetBurstLimit(); + +private: + ActionTypeEnum m_action; + bool m_actionIsSet; + uint64_t m_rateLimit; + bool m_rateLimitIsSet; + uint64_t m_burstLimit; + bool m_burstLimitIsSet; +}; + +} +} +} + diff --git a/src/services/pcn-policer/src/serializer/DefaultContractJsonObject.cpp b/src/services/pcn-policer/src/serializer/DefaultContractJsonObject.cpp new file mode 100644 index 000000000..ffa801b26 --- /dev/null +++ b/src/services/pcn-policer/src/serializer/DefaultContractJsonObject.cpp @@ -0,0 +1,145 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + + +#include "DefaultContractJsonObject.h" +#include + +namespace polycube { +namespace service { +namespace model { + +DefaultContractJsonObject::DefaultContractJsonObject() { + m_action = ActionTypeEnum::PASS; + m_actionIsSet = true; + m_rateLimitIsSet = false; + m_burstLimitIsSet = false; +} + +DefaultContractJsonObject::DefaultContractJsonObject(const nlohmann::json &val) : + JsonObjectBase(val) { + m_actionIsSet = false; + m_rateLimitIsSet = false; + m_burstLimitIsSet = false; + + + if (val.count("action")) { + setAction(string_to_ActionTypeEnum(val.at("action").get())); + } + + if (val.count("rate-limit")) { + setRateLimit(val.at("rate-limit").get()); + } + + if (val.count("burst-limit")) { + setBurstLimit(val.at("burst-limit").get()); + } +} + +nlohmann::json DefaultContractJsonObject::toJson() const { + nlohmann::json val = nlohmann::json::object(); + if (!getBase().is_null()) { + val.update(getBase()); + } + + if (m_actionIsSet) { + val["action"] = ActionTypeEnum_to_string(m_action); + } + + if (m_rateLimitIsSet) { + val["rate-limit"] = m_rateLimit; + } + + if (m_burstLimitIsSet) { + val["burst-limit"] = m_burstLimit; + } + + return val; +} + +ActionTypeEnum DefaultContractJsonObject::getAction() const { + return m_action; +} + +void DefaultContractJsonObject::setAction(ActionTypeEnum value) { + m_action = value; + m_actionIsSet = true; +} + +bool DefaultContractJsonObject::actionIsSet() const { + return m_actionIsSet; +} + +void DefaultContractJsonObject::unsetAction() { + m_actionIsSet = false; +} + +std::string DefaultContractJsonObject::ActionTypeEnum_to_string(const ActionTypeEnum &value){ + switch(value) { + case ActionTypeEnum::PASS: + return std::string("pass"); + case ActionTypeEnum::LIMIT: + return std::string("limit"); + case ActionTypeEnum::DROP: + return std::string("drop"); + default: + throw std::runtime_error("Bad DefaultContract action"); + } +} + +ActionTypeEnum DefaultContractJsonObject::string_to_ActionTypeEnum(const std::string &str){ + if (JsonObjectBase::iequals("pass", str)) + return ActionTypeEnum::PASS; + if (JsonObjectBase::iequals("limit", str)) + return ActionTypeEnum::LIMIT; + if (JsonObjectBase::iequals("drop", str)) + return ActionTypeEnum::DROP; + throw std::runtime_error("DefaultContract action is invalid"); +} +uint64_t DefaultContractJsonObject::getRateLimit() const { + return m_rateLimit; +} + +void DefaultContractJsonObject::setRateLimit(uint64_t value) { + m_rateLimit = value; + m_rateLimitIsSet = true; +} + +bool DefaultContractJsonObject::rateLimitIsSet() const { + return m_rateLimitIsSet; +} + +void DefaultContractJsonObject::unsetRateLimit() { + m_rateLimitIsSet = false; +} + +uint64_t DefaultContractJsonObject::getBurstLimit() const { + return m_burstLimit; +} + +void DefaultContractJsonObject::setBurstLimit(uint64_t value) { + m_burstLimit = value; + m_burstLimitIsSet = true; +} + +bool DefaultContractJsonObject::burstLimitIsSet() const { + return m_burstLimitIsSet; +} + +void DefaultContractJsonObject::unsetBurstLimit() { + m_burstLimitIsSet = false; +} + + +} +} +} + diff --git a/src/services/pcn-policer/src/serializer/DefaultContractJsonObject.h b/src/services/pcn-policer/src/serializer/DefaultContractJsonObject.h new file mode 100644 index 000000000..fd16c1a0e --- /dev/null +++ b/src/services/pcn-policer/src/serializer/DefaultContractJsonObject.h @@ -0,0 +1,83 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* DefaultContractJsonObject.h +* +* +*/ + +#pragma once + + +#include "JsonObjectBase.h" + + +namespace polycube { +namespace service { +namespace model { + +#ifndef ACTIONTYPEENUM +#define ACTIONTYPEENUM +enum class ActionTypeEnum { + PASS, LIMIT, DROP +}; +#endif + +/// +/// +/// +class DefaultContractJsonObject : public JsonObjectBase { +public: + DefaultContractJsonObject(); + DefaultContractJsonObject(const nlohmann::json &json); + ~DefaultContractJsonObject() final = default; + nlohmann::json toJson() const final; + + + /// + /// Action applied to traffic of the contract: PASS = Let all the traffic pass without limitations; LIMIT = Apply rate and burst limits to selected traffic; DROP = Drop all the traffic + /// + ActionTypeEnum getAction() const; + void setAction(ActionTypeEnum value); + bool actionIsSet() const; + void unsetAction(); + static std::string ActionTypeEnum_to_string(const ActionTypeEnum &value); + static ActionTypeEnum string_to_ActionTypeEnum(const std::string &str); + + /// + /// Maximum average traffic rate (in bps) + /// + uint64_t getRateLimit() const; + void setRateLimit(uint64_t value); + bool rateLimitIsSet() const; + void unsetRateLimit(); + + /// + /// Maximum size of a burst of packets (in bits) + /// + uint64_t getBurstLimit() const; + void setBurstLimit(uint64_t value); + bool burstLimitIsSet() const; + void unsetBurstLimit(); + +private: + ActionTypeEnum m_action; + bool m_actionIsSet; + uint64_t m_rateLimit; + bool m_rateLimitIsSet; + uint64_t m_burstLimit; + bool m_burstLimitIsSet; +}; + +} +} +} + diff --git a/src/services/pcn-policer/src/serializer/DefaultContractUpdateDataInputJsonObject.cpp b/src/services/pcn-policer/src/serializer/DefaultContractUpdateDataInputJsonObject.cpp new file mode 100644 index 000000000..afac07f52 --- /dev/null +++ b/src/services/pcn-policer/src/serializer/DefaultContractUpdateDataInputJsonObject.cpp @@ -0,0 +1,144 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + + +#include "DefaultContractUpdateDataInputJsonObject.h" +#include + +namespace polycube { +namespace service { +namespace model { + +DefaultContractUpdateDataInputJsonObject::DefaultContractUpdateDataInputJsonObject() { + m_actionIsSet = false; + m_rateLimitIsSet = false; + m_burstLimitIsSet = false; +} + +DefaultContractUpdateDataInputJsonObject::DefaultContractUpdateDataInputJsonObject(const nlohmann::json &val) : + JsonObjectBase(val) { + m_actionIsSet = false; + m_rateLimitIsSet = false; + m_burstLimitIsSet = false; + + + if (val.count("action")) { + setAction(string_to_ActionTypeEnum(val.at("action").get())); + } + + if (val.count("rate-limit")) { + setRateLimit(val.at("rate-limit").get()); + } + + if (val.count("burst-limit")) { + setBurstLimit(val.at("burst-limit").get()); + } +} + +nlohmann::json DefaultContractUpdateDataInputJsonObject::toJson() const { + nlohmann::json val = nlohmann::json::object(); + if (!getBase().is_null()) { + val.update(getBase()); + } + + if (m_actionIsSet) { + val["action"] = ActionTypeEnum_to_string(m_action); + } + + if (m_rateLimitIsSet) { + val["rate-limit"] = m_rateLimit; + } + + if (m_burstLimitIsSet) { + val["burst-limit"] = m_burstLimit; + } + + return val; +} + +ActionTypeEnum DefaultContractUpdateDataInputJsonObject::getAction() const { + return m_action; +} + +void DefaultContractUpdateDataInputJsonObject::setAction(ActionTypeEnum value) { + m_action = value; + m_actionIsSet = true; +} + +bool DefaultContractUpdateDataInputJsonObject::actionIsSet() const { + return m_actionIsSet; +} + +void DefaultContractUpdateDataInputJsonObject::unsetAction() { + m_actionIsSet = false; +} + +std::string DefaultContractUpdateDataInputJsonObject::ActionTypeEnum_to_string(const ActionTypeEnum &value){ + switch(value) { + case ActionTypeEnum::PASS: + return std::string("pass"); + case ActionTypeEnum::LIMIT: + return std::string("limit"); + case ActionTypeEnum::DROP: + return std::string("drop"); + default: + throw std::runtime_error("Bad DefaultContractUpdateDataInput action"); + } +} + +ActionTypeEnum DefaultContractUpdateDataInputJsonObject::string_to_ActionTypeEnum(const std::string &str){ + if (JsonObjectBase::iequals("pass", str)) + return ActionTypeEnum::PASS; + if (JsonObjectBase::iequals("limit", str)) + return ActionTypeEnum::LIMIT; + if (JsonObjectBase::iequals("drop", str)) + return ActionTypeEnum::DROP; + throw std::runtime_error("DefaultContractUpdateDataInput action is invalid"); +} +uint64_t DefaultContractUpdateDataInputJsonObject::getRateLimit() const { + return m_rateLimit; +} + +void DefaultContractUpdateDataInputJsonObject::setRateLimit(uint64_t value) { + m_rateLimit = value; + m_rateLimitIsSet = true; +} + +bool DefaultContractUpdateDataInputJsonObject::rateLimitIsSet() const { + return m_rateLimitIsSet; +} + +void DefaultContractUpdateDataInputJsonObject::unsetRateLimit() { + m_rateLimitIsSet = false; +} + +uint64_t DefaultContractUpdateDataInputJsonObject::getBurstLimit() const { + return m_burstLimit; +} + +void DefaultContractUpdateDataInputJsonObject::setBurstLimit(uint64_t value) { + m_burstLimit = value; + m_burstLimitIsSet = true; +} + +bool DefaultContractUpdateDataInputJsonObject::burstLimitIsSet() const { + return m_burstLimitIsSet; +} + +void DefaultContractUpdateDataInputJsonObject::unsetBurstLimit() { + m_burstLimitIsSet = false; +} + + +} +} +} + diff --git a/src/services/pcn-policer/src/serializer/DefaultContractUpdateDataInputJsonObject.h b/src/services/pcn-policer/src/serializer/DefaultContractUpdateDataInputJsonObject.h new file mode 100644 index 000000000..2cd3ef743 --- /dev/null +++ b/src/services/pcn-policer/src/serializer/DefaultContractUpdateDataInputJsonObject.h @@ -0,0 +1,83 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* DefaultContractUpdateDataInputJsonObject.h +* +* +*/ + +#pragma once + + +#include "JsonObjectBase.h" + + +namespace polycube { +namespace service { +namespace model { + +#ifndef ACTIONTYPEENUM +#define ACTIONTYPEENUM +enum class ActionTypeEnum { + PASS, LIMIT, DROP +}; +#endif + +/// +/// +/// +class DefaultContractUpdateDataInputJsonObject : public JsonObjectBase { +public: + DefaultContractUpdateDataInputJsonObject(); + DefaultContractUpdateDataInputJsonObject(const nlohmann::json &json); + ~DefaultContractUpdateDataInputJsonObject() final = default; + nlohmann::json toJson() const final; + + + /// + /// Action applied to traffic of the contract: PASS = Let all the traffic pass without limitations; LIMIT = Apply rate and burst limits to selected traffic; DROP = Drop all the traffic + /// + ActionTypeEnum getAction() const; + void setAction(ActionTypeEnum value); + bool actionIsSet() const; + void unsetAction(); + static std::string ActionTypeEnum_to_string(const ActionTypeEnum &value); + static ActionTypeEnum string_to_ActionTypeEnum(const std::string &str); + + /// + /// Maximum average traffic rate (in bps) + /// + uint64_t getRateLimit() const; + void setRateLimit(uint64_t value); + bool rateLimitIsSet() const; + void unsetRateLimit(); + + /// + /// Maximum size of a burst of packets (in bits) + /// + uint64_t getBurstLimit() const; + void setBurstLimit(uint64_t value); + bool burstLimitIsSet() const; + void unsetBurstLimit(); + +private: + ActionTypeEnum m_action; + bool m_actionIsSet; + uint64_t m_rateLimit; + bool m_rateLimitIsSet; + uint64_t m_burstLimit; + bool m_burstLimitIsSet; +}; + +} +} +} + diff --git a/src/services/pcn-policer/src/serializer/JsonObjectBase.cpp b/src/services/pcn-policer/src/serializer/JsonObjectBase.cpp new file mode 100644 index 000000000..f18473138 --- /dev/null +++ b/src/services/pcn-policer/src/serializer/JsonObjectBase.cpp @@ -0,0 +1,69 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +#include "JsonObjectBase.h" + +namespace polycube { +namespace service { +namespace model { + +JsonObjectBase::JsonObjectBase(const nlohmann::json &base) : base_(base) {} + +bool JsonObjectBase::iequals(const std::string &a, const std::string &b) { + if(a.size() != b.size()) + return false; + for (unsigned int i = 0; i < a.size(); i++){ + if(tolower(a[i]) != tolower(b[i])) + return false; + } + return true; +} + +std::string JsonObjectBase::toJson(const std::string& value) { + return value; +} + +std::string JsonObjectBase::toJson(const std::time_t& value) { + char buf[sizeof "2011-10-08T07:07:09Z"]; + strftime(buf, sizeof buf, "%FT%TZ", gmtime(&value)); + return buf; +} + +int32_t JsonObjectBase::toJson(int32_t value) { + return value; +} + +int64_t JsonObjectBase::toJson(int64_t value) { + return value; +} + +double JsonObjectBase::toJson(double value) { + return value; +} + +bool JsonObjectBase::toJson(bool value) { + return value; +} + +nlohmann::json JsonObjectBase::toJson(const JsonObjectBase &content) { + return content.toJson(); +} + +const nlohmann::json &JsonObjectBase::getBase() const { + return base_; +} + +void JsonObjectBase::setBase(const nlohmann::json &base) { + base_ = base; +} + +} +} +} diff --git a/src/services/pcn-policer/src/serializer/JsonObjectBase.h b/src/services/pcn-policer/src/serializer/JsonObjectBase.h new file mode 100644 index 000000000..f5ec33376 --- /dev/null +++ b/src/services/pcn-policer/src/serializer/JsonObjectBase.h @@ -0,0 +1,55 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* JsonObjectBase.h +* +* This is the base class for all model classes +*/ + +#pragma once + + +#include "polycube/services/json.hpp" +#include "polycube/services/fifo_map.hpp" +#include +#include + +namespace polycube { +namespace service { +namespace model { + +class JsonObjectBase { + public: + JsonObjectBase() = default; + JsonObjectBase(const nlohmann::json &base); + virtual ~JsonObjectBase() = default; + + virtual nlohmann::json toJson() const = 0; + + static bool iequals(const std::string &a, const std::string &b); + static std::string toJson(const std::string& value); + static std::string toJson(const std::time_t& value); + static int32_t toJson(int32_t value); + static int64_t toJson(int64_t value); + static double toJson(double value); + static bool toJson(bool value); + static nlohmann::json toJson(const JsonObjectBase &content); + + const nlohmann::json &getBase() const; + void setBase(const nlohmann::json &base); + + private: + nlohmann::json base_; +}; + +} +} +} diff --git a/src/services/pcn-policer/src/serializer/PolicerJsonObject.cpp b/src/services/pcn-policer/src/serializer/PolicerJsonObject.cpp new file mode 100644 index 000000000..739724f02 --- /dev/null +++ b/src/services/pcn-policer/src/serializer/PolicerJsonObject.cpp @@ -0,0 +1,136 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + + +#include "PolicerJsonObject.h" +#include + +namespace polycube { +namespace service { +namespace model { + +PolicerJsonObject::PolicerJsonObject() { + m_nameIsSet = false; + m_defaultContractIsSet = false; + m_contractIsSet = false; +} + +PolicerJsonObject::PolicerJsonObject(const nlohmann::json &val) : + JsonObjectBase(val) { + m_nameIsSet = false; + m_defaultContractIsSet = false; + m_contractIsSet = false; + + + if (val.count("name")) { + setName(val.at("name").get()); + } + + if (val.count("default-contract")) { + if (!val["default-contract"].is_null()) { + DefaultContractJsonObject newItem { val["default-contract"] }; + setDefaultContract(newItem); + } + } + + if (val.count("contract")) { + for (auto& item : val["contract"]) { + ContractJsonObject newItem{ item }; + m_contract.push_back(newItem); + } + + m_contractIsSet = true; + } +} + +nlohmann::json PolicerJsonObject::toJson() const { + nlohmann::json val = nlohmann::json::object(); + if (!getBase().is_null()) { + val.update(getBase()); + } + + if (m_nameIsSet) { + val["name"] = m_name; + } + + if (m_defaultContractIsSet) { + val["default-contract"] = JsonObjectBase::toJson(m_defaultContract); + } + + { + nlohmann::json jsonArray; + for (auto& item : m_contract) { + jsonArray.push_back(JsonObjectBase::toJson(item)); + } + + if (jsonArray.size() > 0) { + val["contract"] = jsonArray; + } + } + + return val; +} + +std::string PolicerJsonObject::getName() const { + return m_name; +} + +void PolicerJsonObject::setName(std::string value) { + m_name = value; + m_nameIsSet = true; +} + +bool PolicerJsonObject::nameIsSet() const { + return m_nameIsSet; +} + + + +DefaultContractJsonObject PolicerJsonObject::getDefaultContract() const { + return m_defaultContract; +} + +void PolicerJsonObject::setDefaultContract(DefaultContractJsonObject value) { + m_defaultContract = value; + m_defaultContractIsSet = true; +} + +bool PolicerJsonObject::defaultContractIsSet() const { + return m_defaultContractIsSet; +} + +void PolicerJsonObject::unsetDefaultContract() { + m_defaultContractIsSet = false; +} + +const std::vector& PolicerJsonObject::getContract() const{ + return m_contract; +} + +void PolicerJsonObject::addContract(ContractJsonObject value) { + m_contract.push_back(value); + m_contractIsSet = true; +} + + +bool PolicerJsonObject::contractIsSet() const { + return m_contractIsSet; +} + +void PolicerJsonObject::unsetContract() { + m_contractIsSet = false; +} + + +} +} +} + diff --git a/src/services/pcn-policer/src/serializer/PolicerJsonObject.h b/src/services/pcn-policer/src/serializer/PolicerJsonObject.h new file mode 100644 index 000000000..bde205b18 --- /dev/null +++ b/src/services/pcn-policer/src/serializer/PolicerJsonObject.h @@ -0,0 +1,78 @@ +/** +* policer API generated from policer.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* PolicerJsonObject.h +* +* +*/ + +#pragma once + + +#include "JsonObjectBase.h" + +#include "DefaultContractJsonObject.h" +#include "ContractJsonObject.h" +#include +#include "polycube/services/cube.h" + +namespace polycube { +namespace service { +namespace model { + + +/// +/// +/// +class PolicerJsonObject : public JsonObjectBase { +public: + PolicerJsonObject(); + PolicerJsonObject(const nlohmann::json &json); + ~PolicerJsonObject() final = default; + nlohmann::json toJson() const final; + + + /// + /// Name of the policer service + /// + std::string getName() const; + void setName(std::string value); + bool nameIsSet() const; + + /// + /// Contract applied to traffic not matching any of the specified classes (default: PASS) + /// + DefaultContractJsonObject getDefaultContract() const; + void setDefaultContract(DefaultContractJsonObject value); + bool defaultContractIsSet() const; + void unsetDefaultContract(); + + /// + /// Contract applied to a specific class of traffic + /// + const std::vector& getContract() const; + void addContract(ContractJsonObject value); + bool contractIsSet() const; + void unsetContract(); + +private: + std::string m_name; + bool m_nameIsSet; + DefaultContractJsonObject m_defaultContract; + bool m_defaultContractIsSet; + std::vector m_contract; + bool m_contractIsSet; +}; + +} +} +} + From 77c5d6272bdb52fea91560ddc10a45c6605097a5 Mon Sep 17 00:00:00 2001 From: FedeParola Date: Mon, 17 Feb 2020 17:12:09 +0100 Subject: [PATCH 04/12] Add classifier service --- src/services/CMakeLists.txt | 1 + .../pcn-classifier/.swagger-codegen-ignore | 17 + src/services/pcn-classifier/CMakeLists.txt | 5 + .../cmake/LoadFileAsVariable.cmake | 52 + .../pcn-classifier/datamodel/classifier.yang | 105 ++ .../pcn-classifier/src/CMakeLists.txt | 60 ++ .../pcn-classifier/src/Classifier-lib.cpp | 21 + .../pcn-classifier/src/Classifier.cpp | 506 ++++++++++ src/services/pcn-classifier/src/Classifier.h | 111 +++ .../pcn-classifier/src/Classifier_dp.c | 174 ++++ src/services/pcn-classifier/src/Matcher_dp.c | 71 ++ .../pcn-classifier/src/MatchingTable_dp.c | 46 + src/services/pcn-classifier/src/Selector_dp.c | 43 + .../pcn-classifier/src/TrafficClass.cpp | 458 +++++++++ .../pcn-classifier/src/TrafficClass.h | 134 +++ src/services/pcn-classifier/src/Utils.cpp | 28 + src/services/pcn-classifier/src/Utils.h | 22 + .../pcn-classifier/src/api/ClassifierApi.cpp | 918 ++++++++++++++++++ .../pcn-classifier/src/api/ClassifierApi.h | 78 ++ .../src/api/ClassifierApiImpl.cpp | 733 ++++++++++++++ .../src/api/ClassifierApiImpl.h | 82 ++ .../src/base/ClassifierBase.cpp | 66 ++ .../pcn-classifier/src/base/ClassifierBase.h | 53 + .../src/base/TrafficClassBase.cpp | 76 ++ .../src/base/TrafficClassBase.h | 109 +++ .../pcn-classifier/src/matcher/ExactMatcher.h | 107 ++ .../pcn-classifier/src/matcher/Matcher.h | 101 ++ .../src/matcher/MatcherInterface.h | 33 + .../src/matcher/PrefixMatcher.h | 122 +++ .../src/serializer/ClassifierJsonObject.cpp | 106 ++ .../src/serializer/ClassifierJsonObject.h | 67 ++ .../src/serializer/JsonObjectBase.cpp | 69 ++ .../src/serializer/JsonObjectBase.h | 55 ++ .../src/serializer/TrafficClassJsonObject.cpp | 397 ++++++++ .../src/serializer/TrafficClassJsonObject.h | 168 ++++ 35 files changed, 5194 insertions(+) create mode 100644 src/services/pcn-classifier/.swagger-codegen-ignore create mode 100644 src/services/pcn-classifier/CMakeLists.txt create mode 100644 src/services/pcn-classifier/cmake/LoadFileAsVariable.cmake create mode 100644 src/services/pcn-classifier/datamodel/classifier.yang create mode 100644 src/services/pcn-classifier/src/CMakeLists.txt create mode 100644 src/services/pcn-classifier/src/Classifier-lib.cpp create mode 100644 src/services/pcn-classifier/src/Classifier.cpp create mode 100644 src/services/pcn-classifier/src/Classifier.h create mode 100644 src/services/pcn-classifier/src/Classifier_dp.c create mode 100644 src/services/pcn-classifier/src/Matcher_dp.c create mode 100644 src/services/pcn-classifier/src/MatchingTable_dp.c create mode 100644 src/services/pcn-classifier/src/Selector_dp.c create mode 100644 src/services/pcn-classifier/src/TrafficClass.cpp create mode 100644 src/services/pcn-classifier/src/TrafficClass.h create mode 100644 src/services/pcn-classifier/src/Utils.cpp create mode 100644 src/services/pcn-classifier/src/Utils.h create mode 100644 src/services/pcn-classifier/src/api/ClassifierApi.cpp create mode 100644 src/services/pcn-classifier/src/api/ClassifierApi.h create mode 100644 src/services/pcn-classifier/src/api/ClassifierApiImpl.cpp create mode 100644 src/services/pcn-classifier/src/api/ClassifierApiImpl.h create mode 100644 src/services/pcn-classifier/src/base/ClassifierBase.cpp create mode 100644 src/services/pcn-classifier/src/base/ClassifierBase.h create mode 100644 src/services/pcn-classifier/src/base/TrafficClassBase.cpp create mode 100644 src/services/pcn-classifier/src/base/TrafficClassBase.h create mode 100644 src/services/pcn-classifier/src/matcher/ExactMatcher.h create mode 100644 src/services/pcn-classifier/src/matcher/Matcher.h create mode 100644 src/services/pcn-classifier/src/matcher/MatcherInterface.h create mode 100644 src/services/pcn-classifier/src/matcher/PrefixMatcher.h create mode 100644 src/services/pcn-classifier/src/serializer/ClassifierJsonObject.cpp create mode 100644 src/services/pcn-classifier/src/serializer/ClassifierJsonObject.h create mode 100644 src/services/pcn-classifier/src/serializer/JsonObjectBase.cpp create mode 100644 src/services/pcn-classifier/src/serializer/JsonObjectBase.h create mode 100644 src/services/pcn-classifier/src/serializer/TrafficClassJsonObject.cpp create mode 100644 src/services/pcn-classifier/src/serializer/TrafficClassJsonObject.h diff --git a/src/services/CMakeLists.txt b/src/services/CMakeLists.txt index 55ca7e4ef..9491509df 100644 --- a/src/services/CMakeLists.txt +++ b/src/services/CMakeLists.txt @@ -37,6 +37,7 @@ add_service(transparenthelloworld pcn-transparent-helloworld) add_service(synflood pcn-synflood) add_service(packetcapture pcn-packetcapture) add_service(dynmon pcn-dynmon) +add_service(classifier pcn-classifier) # save string to create code that load the services SET_PROPERTY(GLOBAL PROPERTY LOAD_SERVICES_ ${LOAD_SERVICES}) diff --git a/src/services/pcn-classifier/.swagger-codegen-ignore b/src/services/pcn-classifier/.swagger-codegen-ignore new file mode 100644 index 000000000..8c4cc4ccb --- /dev/null +++ b/src/services/pcn-classifier/.swagger-codegen-ignore @@ -0,0 +1,17 @@ +# Swagger Codegen Ignore +# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen + +# Use this file to prevent files from being overwritten by the generator. + +.swagger-codegen-ignore + +src/*.c +src/*.cpp +src/*.h +src/modules/*.cpp +src/modules/*.h +src/CMakeLists.txt + +!src/*Base.h +!src/*JsonObject.h +!src/*JsonObject.cpp diff --git a/src/services/pcn-classifier/CMakeLists.txt b/src/services/pcn-classifier/CMakeLists.txt new file mode 100644 index 000000000..9857094f7 --- /dev/null +++ b/src/services/pcn-classifier/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required (VERSION 3.2) + +set (CMAKE_CXX_STANDARD 11) + +add_subdirectory(src) diff --git a/src/services/pcn-classifier/cmake/LoadFileAsVariable.cmake b/src/services/pcn-classifier/cmake/LoadFileAsVariable.cmake new file mode 100644 index 000000000..2b58da763 --- /dev/null +++ b/src/services/pcn-classifier/cmake/LoadFileAsVariable.cmake @@ -0,0 +1,52 @@ +# Loads the contents of a file into a std::string variable +# +# It creates a header file in ${CMAKE_CURRENT_BINARY_DIR}/${file}.h +# that wrapps the contents of the file in a std::string using the raw +# string literal feature of C++11. The user needs to include that file +# into the source code in order to see the variable. +# +# parameters: +# target: target to add a dependency on file +# file: file to be loaded +# variable_name: name variable where the file is loaded +# +# example: +# load_file_as_variable(my-lib resource.c my_resource) +# Creates a resource.h in CMAKE_CURRENT_BINARY_DIR with a string variable +# my_resource with the contents of resource.c +# A dependency in resource.c is added to my-lib + +function(load_file_as_variable target file variable_name) + get_filename_component(file_name ${file} NAME_WE) + get_filename_component(file_dir ${file} DIRECTORY) + + set(new_path ${file_dir}/${file_name}.h) + + add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/${new_path} + COMMAND + mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/${file_dir} + COMMAND + echo "#pragma once" > ${CMAKE_CURRENT_BINARY_DIR}/${new_path} + COMMAND + echo "#include " >> ${CMAKE_CURRENT_BINARY_DIR}/${new_path} + COMMAND + echo "const std::string ${variable_name} = R\"POLYCUBE_DP(" >> ${CMAKE_CURRENT_BINARY_DIR}/${new_path} + COMMAND + cat ${CMAKE_CURRENT_SOURCE_DIR}/${file} >> ${CMAKE_CURRENT_BINARY_DIR}/${new_path} + COMMAND + cmake -E echo ")POLYCUBE_DP\";" >> ${CMAKE_CURRENT_BINARY_DIR}/${new_path} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file} + VERBATIM + ) + + string(REPLACE "/" "-" path_replaced ${new_path}) + + add_custom_target( + generate_${path_replaced} + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${new_path} + ) + + add_dependencies(${target} generate_${path_replaced}) +endfunction() diff --git a/src/services/pcn-classifier/datamodel/classifier.yang b/src/services/pcn-classifier/datamodel/classifier.yang new file mode 100644 index 000000000..3bbaaf20e --- /dev/null +++ b/src/services/pcn-classifier/datamodel/classifier.yang @@ -0,0 +1,105 @@ +module classifier { + yang-version 1.1; + namespace "http://polycube.network/classifier"; + prefix "classifier"; + + import polycube-base { prefix "polycube-base"; } + import polycube-transparent-base { prefix "polycube-transparent-base"; } + + import ietf-yang-types { prefix "yang"; } + import ietf-inet-types { prefix "inet"; } + + organization "Polycube Open Source Project"; + description "YANG data model for the Polycube Traffic Classifier"; + + polycube-base:service-description "Traffic Classifier Service"; + polycube-base:service-version "1.0"; + polycube-base:service-name "classifier"; + polycube-base:service-min-kernel-version "4.15.0"; + + uses "polycube-transparent-base:transparent-base-yang-module"; + + list traffic-class { + key id; + description "Traffic class identified by id"; + + leaf id { + type uint32; + mandatory true; + description "Id of the class, set in metadata of matching packets"; + polycube-base:cli-example "100"; + } + + leaf priority { + type uint32; + mandatory true; + description "Packets matching multiple classes are assigned to the one with highest priority"; + } + + leaf direction { + type enumeration { + enum INGRESS; + enum EGRESS; + enum BOTH; + } + default BOTH; + description "Direction (INGRESS, EGRESS or BOTH) of the packet (default: BOTH)"; + polycube-base:cli-example "INGRESS"; + } + + leaf smac { + type yang:mac-address; + description "Source MAC address of the packet"; + polycube-base:cli-example "AC:00:00:00:00:01"; + } + + leaf dmac { + type yang:mac-address; + description "Destination MAC address of the packet"; + polycube-base:cli-example "AC:00:00:00:00:02"; + } + + leaf ethtype { + type enumeration { + enum ARP; + enum IP; + } + description "Ethertype of the packet (ARP | IP)"; + polycube-base:cli-example "IP"; + } + + leaf srcip { + type inet:ipv4-prefix; + description "Source IP address prefix of the packet"; + polycube-base:cli-example "10.0.0.0/8"; + } + + leaf dstip { + type inet:ipv4-prefix; + description "Destination IP address prefix of the packet"; + polycube-base:cli-example "192.168.0.0/24"; + } + + leaf l4proto { + type enumeration { + enum ICMP; + enum TCP; + enum UDP; + } + description "Level 4 protocol of the packet (ICMP | TCP | UDP)"; + polycube-base:cli-example "TCP"; + } + + leaf sport { + type uint16; + description "Source port of the packet"; + polycube-base:cli-example "80"; + } + + leaf dport { + type uint16; + description "Destination port of the packet"; + polycube-base:cli-example "56000"; + } + } +} diff --git a/src/services/pcn-classifier/src/CMakeLists.txt b/src/services/pcn-classifier/src/CMakeLists.txt new file mode 100644 index 000000000..3d561a5b6 --- /dev/null +++ b/src/services/pcn-classifier/src/CMakeLists.txt @@ -0,0 +1,60 @@ +include(${PROJECT_SOURCE_DIR}/cmake/LoadFileAsVariable.cmake) + +aux_source_directory(serializer SERIALIZER_SOURCES) +aux_source_directory(api API_SOURCES) +aux_source_directory(base BASE_SOURCES) +aux_source_directory(modules MODULES) + +include_directories(serializer) +include_directories(matcher) + +if (NOT DEFINED POLYCUBE_STANDALONE_SERVICE OR POLYCUBE_STANDALONE_SERVICE) + find_package(PkgConfig REQUIRED) + pkg_check_modules(POLYCUBE libpolycube) + include_directories(${POLYCUBE_INCLUDE_DIRS}) +endif(NOT DEFINED POLYCUBE_STANDALONE_SERVICE OR POLYCUBE_STANDALONE_SERVICE) + +# Needed to load files as variables +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +add_library(pcn-classifier SHARED + ${SERIALIZER_SOURCES} + ${API_SOURCES} + ${BASE_SOURCES} + ${MODULES} + TrafficClass.cpp + Classifier.cpp + Classifier-lib.cpp + Utils.cpp) + +# load ebpf datapath code a variable +load_file_as_variable(pcn-classifier + Classifier_dp.c + classifier_code) +load_file_as_variable(pcn-classifier + Selector_dp.c + selector_code) +load_file_as_variable(pcn-classifier + MatchingTable_dp.c + matching_table_code) +load_file_as_variable(pcn-classifier + Matcher_dp.c + matcher_code) + +# load datamodel in a variable +load_file_as_variable(pcn-classifier + ../datamodel/classifier.yang + classifier_datamodel) + +target_link_libraries(pcn-classifier ${POLYCUBE_LIBRARIES}) + +# Specify shared library install directory + +set(CMAKE_INSTALL_LIBDIR /usr/lib) + +install( + TARGETS + pcn-classifier + DESTINATION + "${CMAKE_INSTALL_LIBDIR}" +) diff --git a/src/services/pcn-classifier/src/Classifier-lib.cpp b/src/services/pcn-classifier/src/Classifier-lib.cpp new file mode 100644 index 000000000..47921a7c2 --- /dev/null +++ b/src/services/pcn-classifier/src/Classifier-lib.cpp @@ -0,0 +1,21 @@ +/** +* classifier API generated from classifier.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +#include "api/ClassifierApiImpl.h" +#include "../datamodel/classifier.h" // generated from datamodel + +#define SERVICE_PYANG_GIT "" +#define SERVICE_SWAGGER_CODEGEN_GIT "master/f3b9193" + +#include + +extern "C" const char *data_model() { + return classifier_datamodel.c_str(); +} diff --git a/src/services/pcn-classifier/src/Classifier.cpp b/src/services/pcn-classifier/src/Classifier.cpp new file mode 100644 index 000000000..c4c37b92b --- /dev/null +++ b/src/services/pcn-classifier/src/Classifier.cpp @@ -0,0 +1,506 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#include "Classifier.h" +#include "../matcher/ExactMatcher.h" +#include "../matcher/PrefixMatcher.h" +#include "Classifier_dp.h" +#include "Selector_dp.h" +#include "Utils.h" + + +Classifier::Classifier(const std::string name, + const ClassifierJsonObject &conf) + : TransparentCube(conf.getBase(), {}, {}), + ClassifierBase(name) { + logger()->info("Creating Classifier instance"); + + matchers_[FIELD_INDEX(SMAC)] = std::dynamic_pointer_cast( + std::make_shared>(*this, SMAC)); + + matchers_[FIELD_INDEX(DMAC)] = std::dynamic_pointer_cast( + std::make_shared>(*this, DMAC)); + + matchers_[FIELD_INDEX(ETHTYPE)] = std::dynamic_pointer_cast( + std::make_shared>(*this, ETHTYPE)); + + matchers_[FIELD_INDEX(SRCIP)] = std::dynamic_pointer_cast( + std::make_shared>(*this, SRCIP)); + + matchers_[FIELD_INDEX(DSTIP)] = std::dynamic_pointer_cast( + std::make_shared>(*this, DSTIP)); + + matchers_[FIELD_INDEX(L4PROTO)] = std::dynamic_pointer_cast( + std::make_shared>(*this, L4PROTO)); + + matchers_[FIELD_INDEX(SPORT)] = std::dynamic_pointer_cast( + std::make_shared>(*this, SPORT)); + + matchers_[FIELD_INDEX(DPORT)] = std::dynamic_pointer_cast( + std::make_shared>(*this, DPORT)); + + // Load selector programs with classification disabled + std::string code = selector_code; + replaceAll(code, "_CLASSIFY", "0"); + std::string ingress_code = code, egress_code = code; + replaceAll(ingress_code, "_DIRECTION", "ingress"); + replaceAll(egress_code, "_DIRECTION", "egress"); + add_program(ingress_code, 0, ProgramType::INGRESS); + add_program(egress_code, 0, ProgramType::EGRESS); + + // Load Index64 table + const uint16_t index64[64] = { + 0, 47, 1, 56, 48, 27, 2, 60, 57, 49, 41, 37, 28, 16, 3, 61, + 54, 58, 35, 52, 50, 42, 21, 44, 38, 32, 29, 23, 17, 11, 4, 62, + 46, 55, 26, 59, 40, 36, 15, 53, 34, 51, 20, 43, 31, 22, 10, 45, + 25, 39, 14, 33, 19, 30, 9, 24, 13, 18, 8, 12, 7, 6, 5, 63}; + + auto table = get_array_table("index64", 0); + + for (int i = 0; i < 64; i++) { + table.set(i, index64[i]); + } + + classification_enabled_[ProgramType::INGRESS] = false; + classification_enabled_[ProgramType::EGRESS] = false; + active_program_[ProgramType::INGRESS] = 2; + active_program_[ProgramType::EGRESS] = 2; + + addTrafficClassList(conf.getTrafficClass()); +} + +Classifier::~Classifier() { + logger()->info("Destroying Classifier instance"); +} + +void Classifier::packet_in(polycube::service::Direction direction, + polycube::service::PacketInMetadata &md, + const std::vector &packet) { + logger()->debug("Packet received"); +} + +std::shared_ptr Classifier::getTrafficClass( + const uint32_t &id) { + if (traffic_classes_.count(id) == 0) { + throw std::runtime_error("No traffic class with the given id"); + } + + return traffic_classes_.at(id); +} + +std::vector> +Classifier::getTrafficClassList() { + std::vector> traffic_classes_v; + + traffic_classes_v.reserve(traffic_classes_.size()); + + for (auto const &entry : traffic_classes_) { + traffic_classes_v.push_back(entry.second); + } + + return traffic_classes_v; +} + +void Classifier::addTrafficClass(const uint32_t &id, + const TrafficClassJsonObject &conf) { + if (traffic_classes_.count(id) != 0) { + throw std::runtime_error("Traffic class with the given id already exists"); + } + + if (traffic_classes_.size() == MAX_TRAFFIC_CLASSES) { + throw std::runtime_error("Maximum number of traffic classes reached"); + } + + traffic_classes_[id] = std::make_shared(*this, conf); + + updateProgram(conf.getDirection()); + + logger()->info("Traffic class added {0}", traffic_classes_[id]->toString()); +} + +void Classifier::addTrafficClassList( + const std::vector &conf) { + if (conf.size() == 0) { + return; + } + + if (traffic_classes_.size() + conf.size() > MAX_TRAFFIC_CLASSES) { + throw std::runtime_error("Maximum number of traffic classes reached"); + } + + for (auto &it : conf) { + if (traffic_classes_.count(it.getId()) != 0) { + throw std::runtime_error(std::string("Traffic class with id ") + + std::to_string(it.getId()) + " already exists"); + } + } + + bool update_ingress = false, update_egress = false; + for (auto &it : conf) { + traffic_classes_[it.getId()] = std::make_shared(*this, it); + + switch (it.getDirection()) { + case TrafficClassDirectionEnum::INGRESS: + update_ingress = true; + break; + + case TrafficClassDirectionEnum::EGRESS: + update_egress = true; + break; + + case TrafficClassDirectionEnum::BOTH: + update_ingress = true; + update_egress = true; + break; + } + } + + if (update_ingress) { + updateProgram(ProgramType::INGRESS); + } + if (update_egress) { + updateProgram(ProgramType::EGRESS); + } + + logger()->info("Traffic class list added"); +} + +void Classifier::replaceTrafficClass( + const uint32_t &id, const TrafficClassJsonObject &conf) { + if (traffic_classes_.count(id) == 0) { + throw std::runtime_error("No traffic class with the given id"); + } + + bool update_ingress = false, update_egress = false; + switch (traffic_classes_[id]->getDirection()) { + case TrafficClassDirectionEnum::INGRESS: + update_ingress = true; + break; + + case TrafficClassDirectionEnum::EGRESS: + update_egress = true; + break; + + case TrafficClassDirectionEnum::BOTH: + update_ingress = true; + update_egress = true; + break; + } + + traffic_classes_[id] = std::make_shared(*this, conf); + + switch (conf.getDirection()) { + case TrafficClassDirectionEnum::INGRESS: + update_ingress = true; + break; + + case TrafficClassDirectionEnum::EGRESS: + update_egress = true; + break; + + case TrafficClassDirectionEnum::BOTH: + update_ingress = true; + update_egress = true; + break; + } + + if (update_ingress) { + updateProgram(ProgramType::INGRESS); + } + if (update_egress) { + updateProgram(ProgramType::EGRESS); + } + + logger()->info("Traffic class replaced {0}", + traffic_classes_[id]->toString()); +} + +void Classifier::delTrafficClass(const uint32_t &id) { + if (traffic_classes_.count(id) == 0) { + throw std::runtime_error("No traffic class with the given id"); + } + + std::shared_ptr tclass = traffic_classes_[id]; + + traffic_classes_.erase(id); + + updateProgram(tclass->getDirection()); + + logger()->info("Traffic class deleted {0}", tclass->toString()); +} + +void Classifier::delTrafficClassList() { + traffic_classes_.clear(); + + updateProgram(TrafficClassDirectionEnum::BOTH); + + logger()->info("Traffic class list deleted"); +} + +void Classifier::updateProgram(TrafficClassDirectionEnum direction) { + switch (direction) { + case TrafficClassDirectionEnum::INGRESS: + updateProgram(ProgramType::INGRESS); + break; + + case TrafficClassDirectionEnum::EGRESS: + updateProgram(ProgramType::EGRESS); + break; + + case TrafficClassDirectionEnum::BOTH: + updateProgram(ProgramType::INGRESS); + updateProgram(ProgramType::EGRESS); + break; + } +} + +void Classifier::updateProgram(ProgramType direction) { + std::string direction_str = + direction == ProgramType::INGRESS ? "ingress" : "egress"; + + // Select classes for the given direction + std::vector> classes; + for (auto const &entry : traffic_classes_) { + if (static_cast(entry.second->getDirection()) == + static_cast(direction) || + entry.second->getDirection() == TrafficClassDirectionEnum::BOTH) + classes.push_back(entry.second); + } + + if (classes.size() == 0) { + // No classes, disable classification + if (classification_enabled_[direction]) { + std::string code = selector_code; + replaceAll(code, "_CLASSIFY", "0"); + replaceAll(code, "_DIRECTION", direction_str); + reload(code, 0, direction); + + del_program(active_program_[direction], direction); + classification_enabled_[direction] = false; + logger()->debug(direction_str + " classification disabled"); + } + + return; + } + + for (auto &matcher : matchers_) { + matcher->initBitvector(traffic_classes_.size()); + } + + // Compute bitvectors + + // Sort by priority in decreasing order + std::sort(classes.begin(), classes.end(), + [](std::shared_ptr c1, + std::shared_ptr c2) { return !(*c1 <= *c2); }); + + bool parse_l3 = false, parse_l4 = false; + + for (auto c : classes) { + bool need_ip = false; + bool need_tcp_udp = false; + + // sport + { + std::shared_ptr> m = + std::dynamic_pointer_cast>( + matchers_[FIELD_INDEX(SPORT)]); + + if (c->sportIsSet()) { + m->appendValueBit(htons(c->getSport())); + parse_l4 = true; + need_tcp_udp = true; + + } else { + m->appendWildcardBit(); + } + } + + // dport + { + std::shared_ptr> m = + std::dynamic_pointer_cast>( + matchers_[FIELD_INDEX(DPORT)]); + + if (c->dportIsSet()) { + m->appendValueBit(htons(c->getDport())); + parse_l4 = true; + need_tcp_udp = true; + + } else { + m->appendWildcardBit(); + } + } + + // l4proto + { + std::shared_ptr> m = + std::dynamic_pointer_cast>( + matchers_[FIELD_INDEX(L4PROTO)]); + + if (c->l4protoIsSet()) { + m->appendValueBit(kL4protos[static_cast(c->getL4proto())]); + parse_l3 = true; + need_ip = true; + + } else if (need_tcp_udp) { + m->appendValuesBit({IPPROTO_TCP, IPPROTO_UDP}); + parse_l3 = true; + need_ip = true; + + } else { + m->appendWildcardBit(); + } + } + + // srcip + { + std::shared_ptr> m = + std::dynamic_pointer_cast>( + matchers_[FIELD_INDEX(SRCIP)]); + + if (c->srcipIsSet()) { + m->appendValueBit(ip_string_to_nbo_uint(c->getSrcip()), + std::stoi(get_netmask_from_string(c->getSrcip()))); + parse_l3 = true; + need_ip = true; + + } else { + m->appendWildcardBit(); + } + } + + // dstip + { + std::shared_ptr> m = + std::dynamic_pointer_cast>( + matchers_[FIELD_INDEX(DSTIP)]); + + if (c->dstipIsSet()) { + m->appendValueBit(ip_string_to_nbo_uint(c->getDstip()), + std::stoi(get_netmask_from_string(c->getDstip()))); + parse_l3 = true; + need_ip = true; + + } else { + m->appendWildcardBit(); + } + } + + // ethtype + { + std::shared_ptr> m = + std::dynamic_pointer_cast>( + matchers_[FIELD_INDEX(ETHTYPE)]); + + if (c->ethtypeIsSet()) { + m->appendValueBit(htons(kEthtypes[static_cast(c->getEthtype())])); + + } else if (need_ip) { + m->appendValueBit(htons(ETH_P_IP)); + + } else { + m->appendWildcardBit(); + } + } + + // smac + { + std::shared_ptr> m = + std::dynamic_pointer_cast>( + matchers_[FIELD_INDEX(SMAC)]); + + if (c->smacIsSet()) { + m->appendValueBit(mac_string_to_nbo_uint(c->getSmac())); + + } else { + m->appendWildcardBit(); + } + } + + // dmac + { + std::shared_ptr> m = + std::dynamic_pointer_cast>( + matchers_[FIELD_INDEX(DMAC)]); + + if (c->dmacIsSet()) { + m->appendValueBit(mac_string_to_nbo_uint(c->getDmac())); + + } else { + m->appendWildcardBit(); + } + } + } + + // Generate table declaration and matching code + std::string tables_code, matching_code; + for (auto &matcher : matchers_) { + if (matcher->isActive()) { + tables_code += matcher->getTableCode(); + matching_code += matcher->getMatchingCode(); + } + } + + // Generate complete code + std::string code = classifier_code; + replaceAll(code, "_MATCHING_TABLES", tables_code); + replaceAll(code, "_MATCHING_CODE", matching_code); + replaceAll(code, "_SUBVECTS_COUNT", + std::to_string((classes.size() - 1) / 64 + 1)); + replaceAll(code, "_CLASSES_COUNT", std::to_string(classes.size())); + replaceAll(code, "_PARSE_L3", std::to_string(static_cast(parse_l3))); + replaceAll(code, "_PARSE_L4", std::to_string(static_cast(parse_l4))); + replaceAll(code, "_DIRECTION", direction_str); + + // Load new program + active_program_[direction] = active_program_[direction] % 2 + 1; + add_program(code, active_program_[direction], direction); + logger()->debug(std::string("New ") + direction_str + " program loaded"); + + // Fill matching tables + for (auto &matcher : matchers_) { + if (matcher->isActive()) { + matcher->loadTable(active_program_[direction], direction); + logger()->debug("{0} matching table for {1} loaded", direction_str, + FIELD_NAME(matcher->getField())); + } + } + + // Fill classes table + auto class_ids_table = get_array_table( + std::string("class_ids"), active_program_[direction], direction); + + for (int i = 0; i < classes.size(); i++) { + class_ids_table.set(i, classes[i]->getId()); + } + logger()->debug("{0} classes table loaded", direction_str); + + // Update selector to point to the active program + code = selector_code; + replaceAll(code, "_DIRECTION", direction_str); + replaceAll(code, "_CLASSIFY", "1"); + replaceAll(code, "_NEXT", std::to_string(active_program_[direction])); + reload(code, 0, direction); + logger()->debug("{0} selector updated", direction_str); + + if (classification_enabled_[direction]) { + del_program(active_program_[direction] % 2 + 1, direction); + } + + classification_enabled_[direction] = true; +} \ No newline at end of file diff --git a/src/services/pcn-classifier/src/Classifier.h b/src/services/pcn-classifier/src/Classifier.h new file mode 100644 index 000000000..aceb370a0 --- /dev/null +++ b/src/services/pcn-classifier/src/Classifier.h @@ -0,0 +1,111 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#pragma once + + +#include "../base/ClassifierBase.h" +#include "TrafficClass.h" + +#include +#include + + +#define MAX_TRAFFIC_CLASSES 10000 +#define FIELDS_COUNT 8 + +#define FIELD_INDEX(field) (static_cast(field)) +#define FIELD_NAME(field) (kFieldData[FIELD_INDEX(field)].name) +#define FIELD_TYPE(field) (kFieldData[FIELD_INDEX(field)].type) + + +using namespace polycube::service; +using namespace polycube::service::utils; + + +enum MatchingField { + SMAC, + DMAC, + ETHTYPE, + SRCIP, + DSTIP, + L4PROTO, + SPORT, + DPORT +}; + +struct FieldData { + std::string name; + std::string type; +}; + +// Used to map MatchingField to field name and type +const struct FieldData kFieldData[] { + {"smac", "__be64"}, + {"dmac", "__be64"}, + {"ethtype", "__be16"}, + {"srcip", "__be32"}, + {"dstip", "__be32"}, + {"l4proto", "u8"}, + {"sport", "__be16"}, + {"dport", "__be16"} +}; + +// Used to map TrafficClassEthtypeEnum to ethertype code +const uint16_t kEthtypes[] = {ETH_P_ARP, ETH_P_IP}; + +// Used to map TrafficClassL4protoEnum to L4 protocol code +const uint8_t kL4protos[] = {IPPROTO_ICMP, IPPROTO_TCP, IPPROTO_UDP}; + +class MatcherInterface; + +using namespace polycube::service::model; + + +class Classifier : public ClassifierBase { + public: + Classifier(const std::string name, + const ClassifierJsonObject &conf); + virtual ~Classifier(); + + void packet_in(polycube::service::Direction direction, + polycube::service::PacketInMetadata &md, + const std::vector &packet) override; + + /// + /// Traffic class identified by id + /// + std::shared_ptr getTrafficClass(const uint32_t &id) override; + std::vector> getTrafficClassList() override; + void addTrafficClass(const uint32_t &id, + const TrafficClassJsonObject &conf) override; + void addTrafficClassList( + const std::vector &conf) override; + void replaceTrafficClass(const uint32_t &id, + const TrafficClassJsonObject &conf) override; + void delTrafficClass(const uint32_t &id) override; + void delTrafficClassList() override; + + void updateProgram(TrafficClassDirectionEnum direction); + void updateProgram(ProgramType direction); + + private: + std::unordered_map> traffic_classes_; + std::array, FIELDS_COUNT> matchers_; + std::unordered_map classification_enabled_; + std::unordered_map active_program_; +}; \ No newline at end of file diff --git a/src/services/pcn-classifier/src/Classifier_dp.c b/src/services/pcn-classifier/src/Classifier_dp.c new file mode 100644 index 000000000..1408a044a --- /dev/null +++ b/src/services/pcn-classifier/src/Classifier_dp.c @@ -0,0 +1,174 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +// Template parameters: +// DIRECTION direction (ingress/egress) of the program +// SUBVECTS_COUNT number of 64 bits elements composing the bitvector +// CLASSES_COUNT number of classes currently configured (i.e. number of bits +// in the bitvector) +// MATCHING_TABLES declarations of matching tables +// MATCHING_CODE code performing matchings on packet fields +// PARSE_L3 whether l3 header parsing is enabled +// PARSE_L4 whether l4 header parsing is enabled + + +#include + +#include +#include +#include +#include +#include + + +struct eth_hdr { + __be64 dst : 48; + __be64 src : 48; + __be16 proto; +} __attribute__((packed)); + +struct pkt_headers { + __be64 smac; + __be64 dmac; + __be16 ethtype; + __be32 srcip; + __be32 dstip; + u8 l4proto; + __be16 sport; + __be16 dport; +}; + +struct bitvector { + u64 bits[_SUBVECTS_COUNT]; +}; + +// Packet bitvector is stored into a percpu array to avoid exceeding the maximum +// stack size of 512 bytes +BPF_PERCPU_ARRAY(pkt_bitvector, struct bitvector, 1); + +BPF_ARRAY(class_ids, u32, _CLASSES_COUNT); + +BPF_TABLE("extern", int, u16, index64, 64); + +_MATCHING_TABLES + + +static int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) { + pcn_log(ctx, LOG_TRACE, "_DIRECTION parser: processing packet"); + + void *data = (void *)(long)ctx->data; + void *data_end = (void *)(long)ctx->data_end; + + struct eth_hdr *eth = data; + if ((void *)(eth + 1) > data_end) { + return RX_DROP; + } + + struct pkt_headers pkt = {0}; + + pkt.smac = eth->src; + pkt.dmac = eth->dst; + pkt.ethtype = eth->proto; + +#if _PARSE_L3 || _PARSE_L4 + if (eth->proto != htons(ETH_P_IP)) { + goto CONTINUE; + } + + struct iphdr *ip = data + sizeof(*eth); + if ((void *)(ip + 1) > data_end) { + return RX_DROP; + } + + pkt.srcip = ip->saddr; + pkt.dstip = ip->daddr; + pkt.l4proto = ip->protocol; + +#if _PARSE_L4 + if (ip->protocol == IPPROTO_TCP) { + struct tcphdr *tcp = (void *)ip + 4*ip->ihl; + if ((void *)(tcp + 1) > data_end) { + return RX_DROP; + } + + pkt.sport = tcp->source; + pkt.dport = tcp->dest; + + } else if (ip->protocol == IPPROTO_UDP) { + struct udphdr *udp = (void *)ip + 4*ip->ihl; + if ((void *)(udp + 1) > data_end) { + return RX_DROP; + } + + pkt.sport = udp->source; + pkt.dport = udp->dest; + } + +#endif // _PARSE_L4 +#endif // _PARSE_L3 || _PARSE_L4 + +CONTINUE:; + int zero = 0; + struct bitvector *pkt_bv = pkt_bitvector.lookup(&zero); + if (!pkt_bv) { + return RX_DROP; + } + + // Initialize packet bitvector + for (int i = 0; i < _SUBVECTS_COUNT; i++) { + pkt_bv->bits[i] = 0xffffffffffffffff; + } + + + _MATCHING_CODE + + + int matching_class_index = -1; + u16 *matching_res; + for (int i = 0; i < _SUBVECTS_COUNT; i++) { + u64 bits = pkt_bv->bits[i]; + if (bits != 0) { + int index = (int)(((bits ^ (bits - 1)) * 0x03f79d71b4cb0a89) >> 58); + + matching_res = index64.lookup(&index); + if (!matching_res) { + return RX_DROP; + } + + matching_class_index = *matching_res + i * 64; + + break; + } + } + + if (matching_class_index >= 0) { + u32 *id = class_ids.lookup(&matching_class_index); + if (!id) { + return RX_DROP; + } + + md->traffic_class = *id; + + pcn_log(ctx, LOG_TRACE, "_DIRECTION tagger: packet tagged with class %d", + *id); + + } else { + pcn_log(ctx, LOG_TRACE, "_DIRECTION tagger: no matching class found"); + } + + return RX_OK; +} \ No newline at end of file diff --git a/src/services/pcn-classifier/src/Matcher_dp.c b/src/services/pcn-classifier/src/Matcher_dp.c new file mode 100644 index 000000000..f976ee454 --- /dev/null +++ b/src/services/pcn-classifier/src/Matcher_dp.c @@ -0,0 +1,71 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +// Template parameters: +// DIRECTION direction (ingress/egress) of the program +// SUBVECTS_COUNT number of 64 bits elements composing the bitvector +// PREFIX_MATCHER whether matching is based on lpm trie (1) or hash map (0) +// FIELD packet field to perform the match on +// TYPE c type of the matching field +// CLASSES_COUNT number of traffic classes +// WILDCARD whether there is a wildcard to match on (1 true, 0 false) + + +{ +#if _PREFIX_MATCHER + struct _FIELD_lpm_key key = {sizeof(_TYPE) * 8, pkt._FIELD}; +#else + _TYPE key = pkt._FIELD; +#endif + + struct bitvector *rule_bv = _FIELD_rules.lookup(&key); + + if (!rule_bv) { +#if !_PREFIX_MATCHER && _WILDCARD + rule_bv = _FIELD_wildcard_bv.lookup(&zero); + if (!rule_bv) { + return RX_DROP; + } +#else + + pcn_log(ctx, LOG_TRACE, + "_DIRECTION _FIELD matcher: no match found, early stop of " + "classification"); + return RX_OK; +#endif + } + + pcn_log(ctx, LOG_TRACE, "_DIRECTION _FIELD matcher: match found"); + + bool is_all_zero = true; + + for (int i = 0; i < _SUBVECTS_COUNT; i++) { + pkt_bv->bits[i] &= rule_bv->bits[i]; + + if (pkt_bv->bits[i]) { + is_all_zero = false; + } + } + + if (is_all_zero) { + pcn_log(ctx, LOG_TRACE, + "_DIRECTION _FIELD matcher: empty bitvector, early stop of " + "classification"); + return RX_OK; + } +} + diff --git a/src/services/pcn-classifier/src/MatchingTable_dp.c b/src/services/pcn-classifier/src/MatchingTable_dp.c new file mode 100644 index 000000000..d90422f8d --- /dev/null +++ b/src/services/pcn-classifier/src/MatchingTable_dp.c @@ -0,0 +1,46 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +// Template parameters: +// PREFIX_MATCHER whether matching is based on lpm trie (1) or hash map (0) +// FIELD packet field to perform the match on +// TYPE c type of the matching field +// CLASSES_COUNT number of traffic classes +// WILDCARD whether there is a wildcard to match on (1 true, 0 false) + + +#if _PREFIX_MATCHER +struct _FIELD_lpm_key { + u32 prefix_len; + _TYPE key; +}; +BPF_LPM_TRIE(_FIELD_rules, struct _FIELD_lpm_key, struct bitvector, + _CLASSES_COUNT); + +#else + +// Size of rules table is _CLASSES_COUNT + 1 to handle cases of l4matcher where +// both tcp and udp are set by a single traffic class (e.g. a class with +// dport set but not l4proto) +// Wildcard bitvector is stored into an array map to avoid exceeding the maximum +// stack size of 512 bytes +BPF_HASH(_FIELD_rules, _TYPE, struct bitvector, _CLASSES_COUNT + 1); +#if _WILDCARD +BPF_ARRAY(_FIELD_wildcard_bv, struct bitvector, 1); +#endif + +#endif \ No newline at end of file diff --git a/src/services/pcn-classifier/src/Selector_dp.c b/src/services/pcn-classifier/src/Selector_dp.c new file mode 100644 index 000000000..8412bb860 --- /dev/null +++ b/src/services/pcn-classifier/src/Selector_dp.c @@ -0,0 +1,43 @@ + +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +// Template parameters: +// DIRECTION direction (ingress/egress) of the program +// CLASSIFY whether classification is enabled (0/1) +// NEXT index of the active classification program (1/2) + + +#define _DIRECTION_PROGRAM +#ifdef ingress_PROGRAM +BPF_TABLE_SHARED("array", int, u16, index64, 64); +#endif + + +static int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) { +#if _CLASSIFY + pcn_log(ctx, LOG_TRACE, "_DIRECTION selector: redirecting to program _NEXT"); + + call__DIRECTION_program(ctx, _NEXT); + + return RX_DROP; + +#else + pcn_log(ctx, LOG_TRACE, "_DIRECTION selector: classification disabled"); + return RX_OK; +#endif +} \ No newline at end of file diff --git a/src/services/pcn-classifier/src/TrafficClass.cpp b/src/services/pcn-classifier/src/TrafficClass.cpp new file mode 100644 index 000000000..f33467fe6 --- /dev/null +++ b/src/services/pcn-classifier/src/TrafficClass.cpp @@ -0,0 +1,458 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#include "TrafficClass.h" +#include "Classifier.h" + + +TrafficClass::TrafficClass(Classifier &parent, + const TrafficClassJsonObject &conf) + : TrafficClassBase(parent) { + id_ = conf.getId(); + priority_ = conf.getPriority(); + direction_ = conf.getDirection(); + + smac_set_ = conf.smacIsSet(); + if (smac_set_) { + smac_ = conf.getSmac(); + } + + dmac_set_ = conf.dmacIsSet(); + if (dmac_set_) { + dmac_ = conf.getDmac(); + } + + ethtype_set_ = conf.ethtypeIsSet(); + if (ethtype_set_) { + ethtype_ = conf.getEthtype(); + } + + srcip_set_ = conf.srcipIsSet(); + if (srcip_set_) { + srcip_ = conf.getSrcip(); + } + + dstip_set_ = conf.dstipIsSet(); + if (dstip_set_) { + dstip_ = conf.getDstip(); + } + + l4proto_set_ = conf.l4protoIsSet(); + if (l4proto_set_) { + l4proto_ = conf.getL4proto(); + } + + sport_set_ = conf.sportIsSet(); + if (sport_set_) { + sport_ = conf.getSport(); + } + + dport_set_ = conf.dportIsSet(); + if (dport_set_) { + dport_ = conf.getDport(); + } + + if (!isValid()) { + throw std::runtime_error(std::string("Invalid traffic class ") + + toString()); + } +} + +TrafficClass::~TrafficClass() {} + +TrafficClassJsonObject TrafficClass::toJsonObject() { + TrafficClassJsonObject conf; + + conf.setId(getId()); + conf.setPriority(getPriority()); + conf.setDirection(getDirection()); + if (smac_set_) { + conf.setSmac(smac_); + } + if (dmac_set_) { + conf.setDmac(dmac_); + } + if (ethtype_set_) { + conf.setEthtype(ethtype_); + } + if (srcip_set_) { + conf.setSrcip(srcip_); + } + if (dstip_set_) { + conf.setDstip(dstip_); + } + if (l4proto_set_) { + conf.setL4proto(l4proto_); + } + if (sport_set_) { + conf.setSport(sport_); + } + if (dport_set_) { + conf.setDport(dport_); + } + + return conf; +} + +uint32_t TrafficClass::getId() { + return id_; +} + +uint32_t TrafficClass::getPriority() { + return priority_; +} + +void TrafficClass::setPriority(const uint32_t &value) { + if (priority_ == value) { + return; + } + + priority_ = value; + + parent_.updateProgram(getDirection()); + + logger()->info("Traffic class updated {0}", toString()); +} + +TrafficClassDirectionEnum TrafficClass::getDirection() { + return direction_; +} + +void TrafficClass::setDirection(const TrafficClassDirectionEnum &value) { + if (direction_ == value) { + return; + } + + direction_ = value; + + parent_.updateProgram(TrafficClassDirectionEnum::BOTH); + + logger()->info("Traffic class updated {0}", toString()); +} + +std::string TrafficClass::getSmac() { + if (!smac_set_) { + throw std::runtime_error("Field not set"); + } + + return smac_; +} + +void TrafficClass::setSmac(const std::string &value) { + if (smac_set_ && smac_ == value) { + return; + } + + bool old_set_ = smac_set_; + auto old_val_ = smac_; + + smac_ = value; + smac_set_ = true; + + if (!isValid()) { + smac_set_ = old_set_; + smac_ = old_val_; + + throw std::runtime_error(std::string("Invalid traffic class ") + + toString()); + } + + parent_.updateProgram(getDirection()); + + logger()->info("Traffic class updated {0}", toString()); +} + +bool TrafficClass::smacIsSet() { + return smac_set_; +} + +std::string TrafficClass::getDmac() { + if (!dmac_set_) { + throw std::runtime_error("Field not set"); + } + + return dmac_; +} + +void TrafficClass::setDmac(const std::string &value) { + if (dmac_set_ && dmac_ == value) { + return; + } + + bool old_set_ = dmac_set_; + auto old_val_ = dmac_; + + dmac_ = value; + dmac_set_ = true; + + if (!isValid()) { + dmac_set_ = old_set_; + dmac_ = old_val_; + + throw std::runtime_error(std::string("Invalid traffic class ") + + toString()); + } + + parent_.updateProgram(getDirection()); + + logger()->info("Traffic class updated {0}", toString()); +} + +bool TrafficClass::dmacIsSet() { + return dmac_set_; +} + +TrafficClassEthtypeEnum TrafficClass::getEthtype() { + if (!ethtype_set_) { + throw std::runtime_error("Field not set"); + } + + return ethtype_; +} + +void TrafficClass::setEthtype(const TrafficClassEthtypeEnum &value) { + if (ethtype_set_ && ethtype_ == value) { + return; + } + + bool old_set_ = ethtype_set_; + auto old_val_ = ethtype_; + + ethtype_ = value; + ethtype_set_ = true; + + if (!isValid()) { + ethtype_set_ = old_set_; + ethtype_ = old_val_; + + throw std::runtime_error(std::string("Invalid traffic class ") + + toString()); + } + + parent_.updateProgram(getDirection()); + + logger()->info("Traffic class updated {0}", toString()); +} + +bool TrafficClass::ethtypeIsSet() { + return ethtype_set_; +} + +std::string TrafficClass::getSrcip() { + if (!srcip_set_) { + throw std::runtime_error("Field not set"); + } + + return srcip_; +} + +void TrafficClass::setSrcip(const std::string &value) { + if (srcip_set_ && srcip_ == value) { + return; + } + + bool old_set_ = srcip_set_; + auto old_val_ = srcip_; + + srcip_ = value; + srcip_set_ = true; + + if (!isValid()) { + srcip_set_ = old_set_; + srcip_ = old_val_; + + throw std::runtime_error(std::string("Invalid traffic class ") + + toString()); + } + + parent_.updateProgram(getDirection()); + + logger()->info("Traffic class updated {0}", toString()); +} + +bool TrafficClass::srcipIsSet() { + return srcip_set_; +} + +std::string TrafficClass::getDstip() { + if (!dstip_set_) { + throw std::runtime_error("Field not set"); + } + + return dstip_; +} + +void TrafficClass::setDstip(const std::string &value) { + if (dstip_set_ && dstip_ == value) { + return; + } + + bool old_set_ = dstip_set_; + auto old_val_ = dstip_; + + dstip_ = value; + dstip_set_ = true; + + if (!isValid()) { + dstip_set_ = old_set_; + dstip_ = old_val_; + + throw std::runtime_error(std::string("Invalid traffic class ") + + toString()); + } + + parent_.updateProgram(getDirection()); + + logger()->info("Traffic class updated {0}", toString()); +} + +bool TrafficClass::dstipIsSet() { + return dstip_set_; +} + +TrafficClassL4protoEnum TrafficClass::getL4proto() { + if (!l4proto_set_) { + throw std::runtime_error("Field not set"); + } + + return l4proto_; +} + +void TrafficClass::setL4proto(const TrafficClassL4protoEnum &value) { + if (l4proto_set_ && l4proto_ == value) { + return; + } + + bool old_set_ = l4proto_set_; + auto old_val_ = l4proto_; + + l4proto_ = value; + l4proto_set_ = true; + + if (!isValid()) { + l4proto_set_ = old_set_; + l4proto_ = old_val_; + + throw std::runtime_error(std::string("Invalid traffic class ") + + toString()); + } + + parent_.updateProgram(getDirection()); + + logger()->info("Traffic class updated {0}", toString()); +} + +bool TrafficClass::l4protoIsSet() { + return l4proto_set_; +} + +uint16_t TrafficClass::getSport() { + if (!sport_set_) { + throw std::runtime_error("Field not set"); + } + + return sport_; +} + +void TrafficClass::setSport(const uint16_t &value) { + if (sport_set_ && sport_ == value) { + return; + } + + bool old_set_ = sport_set_; + auto old_val_ = sport_; + + sport_ = value; + sport_set_ = true; + + if (!isValid()) { + sport_set_ = old_set_; + sport_ = old_val_; + + throw std::runtime_error(std::string("Invalid traffic class ") + + toString()); + } + + parent_.updateProgram(getDirection()); + + logger()->info("Traffic class updated {0}", toString()); +} + +bool TrafficClass::sportIsSet() { + return sport_set_; +} + +uint16_t TrafficClass::getDport() { + if (!dport_set_) { + throw std::runtime_error("Field not set"); + } + + return dport_; +} + +void TrafficClass::setDport(const uint16_t &value) { + if (dport_set_ && dport_ == value) { + return; + } + + bool old_set_ = dport_set_; + auto old_val_ = dport_; + + dport_ = value; + dport_set_ = true; + + if (!isValid()) { + dport_set_ = old_set_; + dport_ = old_val_; + + throw std::runtime_error(std::string("Invalid traffic class ") + + toString()); + } + + parent_.updateProgram(getDirection()); + + logger()->info("Traffic class updated {0}", toString()); +} + +bool TrafficClass::dportIsSet() { + return dport_set_; +} + +bool TrafficClass::operator<=(const TrafficClass &other) { + return this->priority_ <= other.priority_; +} + +std::string TrafficClass::toString() { + return toJsonObject().toJson().dump(); +} + +bool TrafficClass::isValid() { + if (ethtype_set_ && ethtype_ != TrafficClassEthtypeEnum::IP) { + if (srcip_set_ || dstip_set_ || l4proto_set_ || sport_set_ || dport_set_) { + return false; + } + } + + if (l4proto_set_ && l4proto_ != TrafficClassL4protoEnum::TCP && + l4proto_ != TrafficClassL4protoEnum::UDP) { + if (sport_set_ || dport_set_) { + return false; + } + } + + return true; +} diff --git a/src/services/pcn-classifier/src/TrafficClass.h b/src/services/pcn-classifier/src/TrafficClass.h new file mode 100644 index 000000000..7555337b1 --- /dev/null +++ b/src/services/pcn-classifier/src/TrafficClass.h @@ -0,0 +1,134 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#pragma once + + +#include "../base/TrafficClassBase.h" + + +class Classifier; + + +using namespace polycube::service::model; + +class TrafficClass : public TrafficClassBase { + public: + TrafficClass(Classifier &parent, const TrafficClassJsonObject &conf); + virtual ~TrafficClass(); + + TrafficClassJsonObject toJsonObject() override; + + /// + /// Id of the class, set in metadata of matching packets + /// + uint32_t getId() override; + + /// + /// Packets matching multiple classes are assigned to the one with highest priority + /// + uint32_t getPriority() override; + void setPriority(const uint32_t &value) override; + + /// + /// Direction (INGRESS, EGRESS or BOTH) of the packet (default: BOTH) + /// + TrafficClassDirectionEnum getDirection() override; + void setDirection(const TrafficClassDirectionEnum &value) override; + + /// + /// Source MAC address of the packet + /// + std::string getSmac() override; + void setSmac(const std::string &value) override; + bool smacIsSet(); + + /// + /// Destination MAC address of the packet + /// + std::string getDmac() override; + void setDmac(const std::string &value) override; + bool dmacIsSet(); + + /// + /// Ethertype of the packet (ARP | IP) + /// + TrafficClassEthtypeEnum getEthtype() override; + void setEthtype(const TrafficClassEthtypeEnum &value) override; + bool ethtypeIsSet(); + + /// + /// Source IP address prefix of the packet + /// + std::string getSrcip() override; + void setSrcip(const std::string &value) override; + bool srcipIsSet(); + + /// + /// Destination IP address prefix of the packet + /// + std::string getDstip() override; + void setDstip(const std::string &value) override; + bool dstipIsSet(); + + /// + /// Level 4 protocol of the packet (ICMP | TCP | UDP) + /// + TrafficClassL4protoEnum getL4proto() override; + void setL4proto(const TrafficClassL4protoEnum &value) override; + bool l4protoIsSet(); + + /// + /// Source port of the packet + /// + uint16_t getSport() override; + void setSport(const uint16_t &value) override; + bool sportIsSet(); + + /// + /// Destination port of the packet + /// + uint16_t getDport() override; + void setDport(const uint16_t &value) override; + bool dportIsSet(); + + bool operator<=(const TrafficClass& other); + std::string toString(); + + private: + uint32_t id_; + uint32_t priority_; + TrafficClassDirectionEnum direction_; + std::string smac_; + bool smac_set_; + std::string dmac_; + bool dmac_set_; + TrafficClassEthtypeEnum ethtype_; + bool ethtype_set_; + std::string srcip_; + bool srcip_set_; + std::string dstip_; + bool dstip_set_; + TrafficClassL4protoEnum l4proto_; + bool l4proto_set_; + uint16_t sport_; + bool sport_set_; + uint16_t dport_; + bool dport_set_; + + bool isValid(); +}; diff --git a/src/services/pcn-classifier/src/Utils.cpp b/src/services/pcn-classifier/src/Utils.cpp new file mode 100644 index 000000000..483169bee --- /dev/null +++ b/src/services/pcn-classifier/src/Utils.cpp @@ -0,0 +1,28 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + +#include "Utils.h" + +void replaceAll(std::string &str, const std::string &from, + const std::string &to) { + if (from.empty()) + return; + size_t start_pos = 0; + while ((start_pos = str.find(from, start_pos)) != std::string::npos) { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); + } +} \ No newline at end of file diff --git a/src/services/pcn-classifier/src/Utils.h b/src/services/pcn-classifier/src/Utils.h new file mode 100644 index 000000000..cbe257cff --- /dev/null +++ b/src/services/pcn-classifier/src/Utils.h @@ -0,0 +1,22 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + +#pragma once + +#include + +void replaceAll(std::string &str, const std::string &from, + const std::string &to); \ No newline at end of file diff --git a/src/services/pcn-classifier/src/api/ClassifierApi.cpp b/src/services/pcn-classifier/src/api/ClassifierApi.cpp new file mode 100644 index 000000000..5105a26f2 --- /dev/null +++ b/src/services/pcn-classifier/src/api/ClassifierApi.cpp @@ -0,0 +1,918 @@ +/** +* classifier API generated from classifier.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + +#include "ClassifierApi.h" +#include "ClassifierApiImpl.h" + +using namespace polycube::service::model; +using namespace polycube::service::api::ClassifierApiImpl; + +#ifdef __cplusplus +extern "C" { +#endif + +Response create_classifier_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + ClassifierJsonObject unique_value { request_body }; + + unique_value.setName(unique_name); + create_classifier_by_id(unique_name, unique_value); + return { kCreated, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response create_classifier_traffic_class_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + TrafficClassJsonObject unique_value { request_body }; + + unique_value.setId(unique_id); + create_classifier_traffic_class_by_id(unique_name, unique_id, unique_value); + return { kCreated, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response create_classifier_traffic_class_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + // Getting the body param + std::vector unique_value; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + std::vector unique_value; + for (auto &j : request_body) { + TrafficClassJsonObject a { j }; + unique_value.push_back(a); + } + create_classifier_traffic_class_list_by_id(unique_name, unique_value); + return { kCreated, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response delete_classifier_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + + try { + delete_classifier_by_id(unique_name); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response delete_classifier_traffic_class_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + delete_classifier_traffic_class_by_id(unique_name, unique_id); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response delete_classifier_traffic_class_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + + try { + delete_classifier_traffic_class_list_by_id(unique_name); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_classifier_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + + try { + + auto x = read_classifier_by_id(unique_name); + nlohmann::json response_body; + response_body = x.toJson(); + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_classifier_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + + + try { + + auto x = read_classifier_list_by_id(); + nlohmann::json response_body; + for (auto &i : x) { + response_body += i.toJson(); + } + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_classifier_traffic_class_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + + auto x = read_classifier_traffic_class_by_id(unique_name, unique_id); + nlohmann::json response_body; + response_body = x.toJson(); + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_classifier_traffic_class_direction_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + + auto x = read_classifier_traffic_class_direction_by_id(unique_name, unique_id); + nlohmann::json response_body; + response_body = TrafficClassJsonObject::TrafficClassDirectionEnum_to_string(x); + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_classifier_traffic_class_dmac_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + + auto x = read_classifier_traffic_class_dmac_by_id(unique_name, unique_id); + nlohmann::json response_body; + response_body = x; + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_classifier_traffic_class_dport_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + + auto x = read_classifier_traffic_class_dport_by_id(unique_name, unique_id); + nlohmann::json response_body; + response_body = x; + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_classifier_traffic_class_dstip_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + + auto x = read_classifier_traffic_class_dstip_by_id(unique_name, unique_id); + nlohmann::json response_body; + response_body = x; + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_classifier_traffic_class_ethtype_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + + auto x = read_classifier_traffic_class_ethtype_by_id(unique_name, unique_id); + nlohmann::json response_body; + response_body = TrafficClassJsonObject::TrafficClassEthtypeEnum_to_string(x); + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_classifier_traffic_class_l4proto_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + + auto x = read_classifier_traffic_class_l4proto_by_id(unique_name, unique_id); + nlohmann::json response_body; + response_body = TrafficClassJsonObject::TrafficClassL4protoEnum_to_string(x); + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_classifier_traffic_class_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + + try { + + auto x = read_classifier_traffic_class_list_by_id(unique_name); + nlohmann::json response_body; + for (auto &i : x) { + response_body += i.toJson(); + } + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_classifier_traffic_class_priority_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + + auto x = read_classifier_traffic_class_priority_by_id(unique_name, unique_id); + nlohmann::json response_body; + response_body = x; + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_classifier_traffic_class_smac_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + + auto x = read_classifier_traffic_class_smac_by_id(unique_name, unique_id); + nlohmann::json response_body; + response_body = x; + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_classifier_traffic_class_sport_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + + auto x = read_classifier_traffic_class_sport_by_id(unique_name, unique_id); + nlohmann::json response_body; + response_body = x; + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response read_classifier_traffic_class_srcip_by_id_handler( + const char *name, const Key *keys, + size_t num_keys ) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + + auto x = read_classifier_traffic_class_srcip_by_id(unique_name, unique_id); + nlohmann::json response_body; + response_body = x; + return { kOk, ::strdup(response_body.dump().c_str()) }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response replace_classifier_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + ClassifierJsonObject unique_value { request_body }; + + unique_value.setName(unique_name); + replace_classifier_by_id(unique_name, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response replace_classifier_traffic_class_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + TrafficClassJsonObject unique_value { request_body }; + + unique_value.setId(unique_id); + replace_classifier_traffic_class_by_id(unique_name, unique_id, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response replace_classifier_traffic_class_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + // Getting the body param + std::vector unique_value; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + std::vector unique_value; + for (auto &j : request_body) { + TrafficClassJsonObject a { j }; + unique_value.push_back(a); + } + replace_classifier_traffic_class_list_by_id(unique_name, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_classifier_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + ClassifierJsonObject unique_value { request_body }; + + unique_value.setName(unique_name); + update_classifier_by_id(unique_name, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_classifier_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + + // Getting the body param + std::vector unique_value; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + std::vector unique_value; + for (auto &j : request_body) { + ClassifierJsonObject a { j }; + unique_value.push_back(a); + } + update_classifier_list_by_id(unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_classifier_traffic_class_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + TrafficClassJsonObject unique_value { request_body }; + + unique_value.setId(unique_id); + update_classifier_traffic_class_by_id(unique_name, unique_id, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_classifier_traffic_class_direction_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + TrafficClassDirectionEnum unique_value_ = TrafficClassJsonObject::string_to_TrafficClassDirectionEnum(request_body); + update_classifier_traffic_class_direction_by_id(unique_name, unique_id, unique_value_); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_classifier_traffic_class_dmac_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // The conversion is done automatically by the json library + std::string unique_value = request_body; + update_classifier_traffic_class_dmac_by_id(unique_name, unique_id, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_classifier_traffic_class_dport_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // The conversion is done automatically by the json library + uint16_t unique_value = request_body; + update_classifier_traffic_class_dport_by_id(unique_name, unique_id, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_classifier_traffic_class_dstip_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // The conversion is done automatically by the json library + std::string unique_value = request_body; + update_classifier_traffic_class_dstip_by_id(unique_name, unique_id, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_classifier_traffic_class_ethtype_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + TrafficClassEthtypeEnum unique_value_ = TrafficClassJsonObject::string_to_TrafficClassEthtypeEnum(request_body); + update_classifier_traffic_class_ethtype_by_id(unique_name, unique_id, unique_value_); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_classifier_traffic_class_l4proto_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + TrafficClassL4protoEnum unique_value_ = TrafficClassJsonObject::string_to_TrafficClassL4protoEnum(request_body); + update_classifier_traffic_class_l4proto_by_id(unique_name, unique_id, unique_value_); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_classifier_traffic_class_list_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + // Getting the body param + std::vector unique_value; + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // Getting the body param + std::vector unique_value; + for (auto &j : request_body) { + TrafficClassJsonObject a { j }; + unique_value.push_back(a); + } + update_classifier_traffic_class_list_by_id(unique_name, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_classifier_traffic_class_priority_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // The conversion is done automatically by the json library + uint32_t unique_value = request_body; + update_classifier_traffic_class_priority_by_id(unique_name, unique_id, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_classifier_traffic_class_smac_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // The conversion is done automatically by the json library + std::string unique_value = request_body; + update_classifier_traffic_class_smac_by_id(unique_name, unique_id, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_classifier_traffic_class_sport_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // The conversion is done automatically by the json library + uint16_t unique_value = request_body; + update_classifier_traffic_class_sport_by_id(unique_name, unique_id, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + +Response update_classifier_traffic_class_srcip_by_id_handler( + const char *name, const Key *keys, + size_t num_keys , + const char *value) { + // Getting the path params + std::string unique_name { name }; + uint32_t unique_id; + for (size_t i = 0; i < num_keys; ++i) { + if (!strcmp(keys[i].name, "id")) { + unique_id = keys[i].value.uint32; + break; + } + } + + + try { + auto request_body = nlohmann::json::parse(std::string { value }); + // The conversion is done automatically by the json library + std::string unique_value = request_body; + update_classifier_traffic_class_srcip_by_id(unique_name, unique_id, unique_value); + return { kOk, nullptr }; + } catch(const std::exception &e) { + return { kGenericError, ::strdup(e.what()) }; + } +} + + +Response classifier_list_by_id_help( + const char *name, const Key *keys, size_t num_keys) { + + nlohmann::json val = read_classifier_list_by_id_get_list(); + + return { kOk, ::strdup(val.dump().c_str()) }; +} + +Response classifier_traffic_class_list_by_id_help( + const char *name, const Key *keys, size_t num_keys) { + // Getting the path params + std::string unique_name { name }; + nlohmann::json val = read_classifier_traffic_class_list_by_id_get_list(unique_name); + + return { kOk, ::strdup(val.dump().c_str()) }; +} + +#ifdef __cplusplus +} +#endif + diff --git a/src/services/pcn-classifier/src/api/ClassifierApi.h b/src/services/pcn-classifier/src/api/ClassifierApi.h new file mode 100644 index 000000000..3e4edd810 --- /dev/null +++ b/src/services/pcn-classifier/src/api/ClassifierApi.h @@ -0,0 +1,78 @@ +/** +* classifier API generated from classifier.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* ClassifierApi.h +* +*/ + +#pragma once + +#define POLYCUBE_SERVICE_NAME "classifier" + + +#include "polycube/services/response.h" +#include "polycube/services/shared_lib_elements.h" + +#include "ClassifierJsonObject.h" +#include "TrafficClassJsonObject.h" +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +Response create_classifier_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response create_classifier_traffic_class_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response create_classifier_traffic_class_list_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response delete_classifier_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response delete_classifier_traffic_class_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response delete_classifier_traffic_class_list_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_classifier_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_classifier_list_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_classifier_traffic_class_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_classifier_traffic_class_direction_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_classifier_traffic_class_dmac_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_classifier_traffic_class_dport_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_classifier_traffic_class_dstip_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_classifier_traffic_class_ethtype_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_classifier_traffic_class_l4proto_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_classifier_traffic_class_list_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_classifier_traffic_class_priority_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_classifier_traffic_class_smac_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_classifier_traffic_class_sport_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response read_classifier_traffic_class_srcip_by_id_handler(const char *name, const Key *keys, size_t num_keys); +Response replace_classifier_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response replace_classifier_traffic_class_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response replace_classifier_traffic_class_list_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_classifier_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_classifier_list_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_classifier_traffic_class_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_classifier_traffic_class_direction_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_classifier_traffic_class_dmac_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_classifier_traffic_class_dport_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_classifier_traffic_class_dstip_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_classifier_traffic_class_ethtype_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_classifier_traffic_class_l4proto_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_classifier_traffic_class_list_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_classifier_traffic_class_priority_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_classifier_traffic_class_smac_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_classifier_traffic_class_sport_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); +Response update_classifier_traffic_class_srcip_by_id_handler(const char *name, const Key *keys, size_t num_keys, const char *value); + +Response classifier_list_by_id_help(const char *name, const Key *keys, size_t num_keys); +Response classifier_traffic_class_list_by_id_help(const char *name, const Key *keys, size_t num_keys); + + +#ifdef __cplusplus +} +#endif + diff --git a/src/services/pcn-classifier/src/api/ClassifierApiImpl.cpp b/src/services/pcn-classifier/src/api/ClassifierApiImpl.cpp new file mode 100644 index 000000000..b93cc9ac8 --- /dev/null +++ b/src/services/pcn-classifier/src/api/ClassifierApiImpl.cpp @@ -0,0 +1,733 @@ +/** +* classifier API generated from classifier.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + +#include "ClassifierApiImpl.h" + +namespace polycube { +namespace service { +namespace api { + +using namespace polycube::service::model; + +namespace ClassifierApiImpl { +namespace { +std::unordered_map> cubes; +std::mutex cubes_mutex; + +std::shared_ptr get_cube(const std::string &name) { + std::lock_guard guard(cubes_mutex); + auto iter = cubes.find(name); + if (iter == cubes.end()) { + throw std::runtime_error("Cube " + name + " does not exist"); + } + + return iter->second; +} + +} + +void create_classifier_by_id(const std::string &name, const ClassifierJsonObject &jsonObject) { + { + // check if name is valid before creating it + std::lock_guard guard(cubes_mutex); + if (cubes.count(name) != 0) { + throw std::runtime_error("There is already a cube with name " + name); + } + } + auto ptr = std::make_shared(name, jsonObject); + std::unordered_map>::iterator iter; + bool inserted; + + std::lock_guard guard(cubes_mutex); + std::tie(iter, inserted) = cubes.emplace(name, std::move(ptr)); + + if (!inserted) { + throw std::runtime_error("There is already a cube with name " + name); + } +} + +void replace_classifier_by_id(const std::string &name, const ClassifierJsonObject &bridge){ + throw std::runtime_error("Method not supported!"); +} + +void delete_classifier_by_id(const std::string &name) { + std::lock_guard guard(cubes_mutex); + if (cubes.count(name) == 0) { + throw std::runtime_error("Cube " + name + " does not exist"); + } + cubes.erase(name); +} + +std::vector read_classifier_list_by_id() { + std::vector jsonObject_vect; + for(auto &i : cubes) { + auto m = get_cube(i.first); + jsonObject_vect.push_back(m->toJsonObject()); + } + return jsonObject_vect; +} + +std::vector> read_classifier_list_by_id_get_list() { + std::vector> r; + for (auto &x : cubes) { + nlohmann::fifo_map m; + m["name"] = x.first; + r.push_back(std::move(m)); + } + return r; +} + +/** +* @brief Create traffic-class by ID +* +* Create operation of resource: traffic-class* +* +* @param[in] name ID of name +* @param[in] id ID of id +* @param[in] value traffic-classbody object +* +* Responses: +* +*/ +void +create_classifier_traffic_class_by_id(const std::string &name, const uint32_t &id, const TrafficClassJsonObject &value) { + auto classifier = get_cube(name); + + return classifier->addTrafficClass(id, value); +} + +/** +* @brief Create traffic-class by ID +* +* Create operation of resource: traffic-class* +* +* @param[in] name ID of name +* @param[in] value traffic-classbody object +* +* Responses: +* +*/ +void +create_classifier_traffic_class_list_by_id(const std::string &name, const std::vector &value) { + auto classifier = get_cube(name); + classifier->addTrafficClassList(value); +} + +/** +* @brief Delete traffic-class by ID +* +* Delete operation of resource: traffic-class* +* +* @param[in] name ID of name +* @param[in] id ID of id +* +* Responses: +* +*/ +void +delete_classifier_traffic_class_by_id(const std::string &name, const uint32_t &id) { + auto classifier = get_cube(name); + + return classifier->delTrafficClass(id); +} + +/** +* @brief Delete traffic-class by ID +* +* Delete operation of resource: traffic-class* +* +* @param[in] name ID of name +* +* Responses: +* +*/ +void +delete_classifier_traffic_class_list_by_id(const std::string &name) { + auto classifier = get_cube(name); + classifier->delTrafficClassList(); +} + +/** +* @brief Read classifier by ID +* +* Read operation of resource: classifier* +* +* @param[in] name ID of name +* +* Responses: +* ClassifierJsonObject +*/ +ClassifierJsonObject +read_classifier_by_id(const std::string &name) { + return get_cube(name)->toJsonObject(); + +} + +/** +* @brief Read traffic-class by ID +* +* Read operation of resource: traffic-class* +* +* @param[in] name ID of name +* @param[in] id ID of id +* +* Responses: +* TrafficClassJsonObject +*/ +TrafficClassJsonObject +read_classifier_traffic_class_by_id(const std::string &name, const uint32_t &id) { + auto classifier = get_cube(name); + return classifier->getTrafficClass(id)->toJsonObject(); + +} + +/** +* @brief Read direction by ID +* +* Read operation of resource: direction* +* +* @param[in] name ID of name +* @param[in] id ID of id +* +* Responses: +* TrafficClassDirectionEnum +*/ +TrafficClassDirectionEnum +read_classifier_traffic_class_direction_by_id(const std::string &name, const uint32_t &id) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + return trafficClass->getDirection(); + +} + +/** +* @brief Read dmac by ID +* +* Read operation of resource: dmac* +* +* @param[in] name ID of name +* @param[in] id ID of id +* +* Responses: +* std::string +*/ +std::string +read_classifier_traffic_class_dmac_by_id(const std::string &name, const uint32_t &id) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + return trafficClass->getDmac(); + +} + +/** +* @brief Read dport by ID +* +* Read operation of resource: dport* +* +* @param[in] name ID of name +* @param[in] id ID of id +* +* Responses: +* uint16_t +*/ +uint16_t +read_classifier_traffic_class_dport_by_id(const std::string &name, const uint32_t &id) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + return trafficClass->getDport(); + +} + +/** +* @brief Read dstip by ID +* +* Read operation of resource: dstip* +* +* @param[in] name ID of name +* @param[in] id ID of id +* +* Responses: +* std::string +*/ +std::string +read_classifier_traffic_class_dstip_by_id(const std::string &name, const uint32_t &id) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + return trafficClass->getDstip(); + +} + +/** +* @brief Read ethtype by ID +* +* Read operation of resource: ethtype* +* +* @param[in] name ID of name +* @param[in] id ID of id +* +* Responses: +* TrafficClassEthtypeEnum +*/ +TrafficClassEthtypeEnum +read_classifier_traffic_class_ethtype_by_id(const std::string &name, const uint32_t &id) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + return trafficClass->getEthtype(); + +} + +/** +* @brief Read l4proto by ID +* +* Read operation of resource: l4proto* +* +* @param[in] name ID of name +* @param[in] id ID of id +* +* Responses: +* TrafficClassL4protoEnum +*/ +TrafficClassL4protoEnum +read_classifier_traffic_class_l4proto_by_id(const std::string &name, const uint32_t &id) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + return trafficClass->getL4proto(); + +} + +/** +* @brief Read traffic-class by ID +* +* Read operation of resource: traffic-class* +* +* @param[in] name ID of name +* +* Responses: +* std::vector +*/ +std::vector +read_classifier_traffic_class_list_by_id(const std::string &name) { + auto classifier = get_cube(name); + auto &&trafficClass = classifier->getTrafficClassList(); + std::vector m; + for(auto &i : trafficClass) + m.push_back(i->toJsonObject()); + return m; +} + +/** +* @brief Read priority by ID +* +* Read operation of resource: priority* +* +* @param[in] name ID of name +* @param[in] id ID of id +* +* Responses: +* uint32_t +*/ +uint32_t +read_classifier_traffic_class_priority_by_id(const std::string &name, const uint32_t &id) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + return trafficClass->getPriority(); + +} + +/** +* @brief Read smac by ID +* +* Read operation of resource: smac* +* +* @param[in] name ID of name +* @param[in] id ID of id +* +* Responses: +* std::string +*/ +std::string +read_classifier_traffic_class_smac_by_id(const std::string &name, const uint32_t &id) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + return trafficClass->getSmac(); + +} + +/** +* @brief Read sport by ID +* +* Read operation of resource: sport* +* +* @param[in] name ID of name +* @param[in] id ID of id +* +* Responses: +* uint16_t +*/ +uint16_t +read_classifier_traffic_class_sport_by_id(const std::string &name, const uint32_t &id) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + return trafficClass->getSport(); + +} + +/** +* @brief Read srcip by ID +* +* Read operation of resource: srcip* +* +* @param[in] name ID of name +* @param[in] id ID of id +* +* Responses: +* std::string +*/ +std::string +read_classifier_traffic_class_srcip_by_id(const std::string &name, const uint32_t &id) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + return trafficClass->getSrcip(); + +} + +/** +* @brief Replace traffic-class by ID +* +* Replace operation of resource: traffic-class* +* +* @param[in] name ID of name +* @param[in] id ID of id +* @param[in] value traffic-classbody object +* +* Responses: +* +*/ +void +replace_classifier_traffic_class_by_id(const std::string &name, const uint32_t &id, const TrafficClassJsonObject &value) { + auto classifier = get_cube(name); + + return classifier->replaceTrafficClass(id, value); +} + +/** +* @brief Replace traffic-class by ID +* +* Replace operation of resource: traffic-class* +* +* @param[in] name ID of name +* @param[in] value traffic-classbody object +* +* Responses: +* +*/ +void +replace_classifier_traffic_class_list_by_id(const std::string &name, const std::vector &value) { + throw std::runtime_error("Method not supported"); +} + +/** +* @brief Update classifier by ID +* +* Update operation of resource: classifier* +* +* @param[in] name ID of name +* @param[in] value classifierbody object +* +* Responses: +* +*/ +void +update_classifier_by_id(const std::string &name, const ClassifierJsonObject &value) { + auto classifier = get_cube(name); + + return classifier->update(value); +} + +/** +* @brief Update classifier by ID +* +* Update operation of resource: classifier* +* +* @param[in] value classifierbody object +* +* Responses: +* +*/ +void +update_classifier_list_by_id(const std::vector &value) { + throw std::runtime_error("Method not supported"); +} + +/** +* @brief Update traffic-class by ID +* +* Update operation of resource: traffic-class* +* +* @param[in] name ID of name +* @param[in] id ID of id +* @param[in] value traffic-classbody object +* +* Responses: +* +*/ +void +update_classifier_traffic_class_by_id(const std::string &name, const uint32_t &id, const TrafficClassJsonObject &value) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + + return trafficClass->update(value); +} + +/** +* @brief Update direction by ID +* +* Update operation of resource: direction* +* +* @param[in] name ID of name +* @param[in] id ID of id +* @param[in] value Direction (INGRESS, EGRESS or BOTH) of the packet (default: BOTH) +* +* Responses: +* +*/ +void +update_classifier_traffic_class_direction_by_id(const std::string &name, const uint32_t &id, const TrafficClassDirectionEnum &value) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + + return trafficClass->setDirection(value); +} + +/** +* @brief Update dmac by ID +* +* Update operation of resource: dmac* +* +* @param[in] name ID of name +* @param[in] id ID of id +* @param[in] value Destination MAC address of the packet +* +* Responses: +* +*/ +void +update_classifier_traffic_class_dmac_by_id(const std::string &name, const uint32_t &id, const std::string &value) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + + return trafficClass->setDmac(value); +} + +/** +* @brief Update dport by ID +* +* Update operation of resource: dport* +* +* @param[in] name ID of name +* @param[in] id ID of id +* @param[in] value Destination port of the packet +* +* Responses: +* +*/ +void +update_classifier_traffic_class_dport_by_id(const std::string &name, const uint32_t &id, const uint16_t &value) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + + return trafficClass->setDport(value); +} + +/** +* @brief Update dstip by ID +* +* Update operation of resource: dstip* +* +* @param[in] name ID of name +* @param[in] id ID of id +* @param[in] value Destination IP address prefix of the packet +* +* Responses: +* +*/ +void +update_classifier_traffic_class_dstip_by_id(const std::string &name, const uint32_t &id, const std::string &value) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + + return trafficClass->setDstip(value); +} + +/** +* @brief Update ethtype by ID +* +* Update operation of resource: ethtype* +* +* @param[in] name ID of name +* @param[in] id ID of id +* @param[in] value Ethertype of the packet (ARP | IP) +* +* Responses: +* +*/ +void +update_classifier_traffic_class_ethtype_by_id(const std::string &name, const uint32_t &id, const TrafficClassEthtypeEnum &value) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + + return trafficClass->setEthtype(value); +} + +/** +* @brief Update l4proto by ID +* +* Update operation of resource: l4proto* +* +* @param[in] name ID of name +* @param[in] id ID of id +* @param[in] value Level 4 protocol of the packet (ICMP | TCP | UDP) +* +* Responses: +* +*/ +void +update_classifier_traffic_class_l4proto_by_id(const std::string &name, const uint32_t &id, const TrafficClassL4protoEnum &value) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + + return trafficClass->setL4proto(value); +} + +/** +* @brief Update traffic-class by ID +* +* Update operation of resource: traffic-class* +* +* @param[in] name ID of name +* @param[in] value traffic-classbody object +* +* Responses: +* +*/ +void +update_classifier_traffic_class_list_by_id(const std::string &name, const std::vector &value) { + throw std::runtime_error("Method not supported"); +} + +/** +* @brief Update priority by ID +* +* Update operation of resource: priority* +* +* @param[in] name ID of name +* @param[in] id ID of id +* @param[in] value Packets matching multiple classes are assigned to the one with highest priority +* +* Responses: +* +*/ +void +update_classifier_traffic_class_priority_by_id(const std::string &name, const uint32_t &id, const uint32_t &value) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + + return trafficClass->setPriority(value); +} + +/** +* @brief Update smac by ID +* +* Update operation of resource: smac* +* +* @param[in] name ID of name +* @param[in] id ID of id +* @param[in] value Source MAC address of the packet +* +* Responses: +* +*/ +void +update_classifier_traffic_class_smac_by_id(const std::string &name, const uint32_t &id, const std::string &value) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + + return trafficClass->setSmac(value); +} + +/** +* @brief Update sport by ID +* +* Update operation of resource: sport* +* +* @param[in] name ID of name +* @param[in] id ID of id +* @param[in] value Source port of the packet +* +* Responses: +* +*/ +void +update_classifier_traffic_class_sport_by_id(const std::string &name, const uint32_t &id, const uint16_t &value) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + + return trafficClass->setSport(value); +} + +/** +* @brief Update srcip by ID +* +* Update operation of resource: srcip* +* +* @param[in] name ID of name +* @param[in] id ID of id +* @param[in] value Source IP address prefix of the packet +* +* Responses: +* +*/ +void +update_classifier_traffic_class_srcip_by_id(const std::string &name, const uint32_t &id, const std::string &value) { + auto classifier = get_cube(name); + auto trafficClass = classifier->getTrafficClass(id); + + return trafficClass->setSrcip(value); +} + + + +/* + * help related + */ + +std::vector> read_classifier_traffic_class_list_by_id_get_list(const std::string &name) { + std::vector> r; + auto &&classifier = get_cube(name); + + auto &&trafficClass = classifier->getTrafficClassList(); + for(auto &i : trafficClass) { + nlohmann::fifo_map keys; + + keys["id"] = std::to_string(i->getId()); + + r.push_back(keys); + } + return r; +} + + +} + +} +} +} + diff --git a/src/services/pcn-classifier/src/api/ClassifierApiImpl.h b/src/services/pcn-classifier/src/api/ClassifierApiImpl.h new file mode 100644 index 000000000..4ded0e639 --- /dev/null +++ b/src/services/pcn-classifier/src/api/ClassifierApiImpl.h @@ -0,0 +1,82 @@ +/** +* classifier API generated from classifier.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* ClassifierApiImpl.h +* +* +*/ + +#pragma once + + +#include +#include +#include +#include "../Classifier.h" + +#include "ClassifierJsonObject.h" +#include "TrafficClassJsonObject.h" +#include + +namespace polycube { +namespace service { +namespace api { + +using namespace polycube::service::model; + +namespace ClassifierApiImpl { + void create_classifier_by_id(const std::string &name, const ClassifierJsonObject &value); + void create_classifier_traffic_class_by_id(const std::string &name, const uint32_t &id, const TrafficClassJsonObject &value); + void create_classifier_traffic_class_list_by_id(const std::string &name, const std::vector &value); + void delete_classifier_by_id(const std::string &name); + void delete_classifier_traffic_class_by_id(const std::string &name, const uint32_t &id); + void delete_classifier_traffic_class_list_by_id(const std::string &name); + ClassifierJsonObject read_classifier_by_id(const std::string &name); + std::vector read_classifier_list_by_id(); + TrafficClassJsonObject read_classifier_traffic_class_by_id(const std::string &name, const uint32_t &id); + TrafficClassDirectionEnum read_classifier_traffic_class_direction_by_id(const std::string &name, const uint32_t &id); + std::string read_classifier_traffic_class_dmac_by_id(const std::string &name, const uint32_t &id); + uint16_t read_classifier_traffic_class_dport_by_id(const std::string &name, const uint32_t &id); + std::string read_classifier_traffic_class_dstip_by_id(const std::string &name, const uint32_t &id); + TrafficClassEthtypeEnum read_classifier_traffic_class_ethtype_by_id(const std::string &name, const uint32_t &id); + TrafficClassL4protoEnum read_classifier_traffic_class_l4proto_by_id(const std::string &name, const uint32_t &id); + std::vector read_classifier_traffic_class_list_by_id(const std::string &name); + uint32_t read_classifier_traffic_class_priority_by_id(const std::string &name, const uint32_t &id); + std::string read_classifier_traffic_class_smac_by_id(const std::string &name, const uint32_t &id); + uint16_t read_classifier_traffic_class_sport_by_id(const std::string &name, const uint32_t &id); + std::string read_classifier_traffic_class_srcip_by_id(const std::string &name, const uint32_t &id); + void replace_classifier_by_id(const std::string &name, const ClassifierJsonObject &value); + void replace_classifier_traffic_class_by_id(const std::string &name, const uint32_t &id, const TrafficClassJsonObject &value); + void replace_classifier_traffic_class_list_by_id(const std::string &name, const std::vector &value); + void update_classifier_by_id(const std::string &name, const ClassifierJsonObject &value); + void update_classifier_list_by_id(const std::vector &value); + void update_classifier_traffic_class_by_id(const std::string &name, const uint32_t &id, const TrafficClassJsonObject &value); + void update_classifier_traffic_class_direction_by_id(const std::string &name, const uint32_t &id, const TrafficClassDirectionEnum &value); + void update_classifier_traffic_class_dmac_by_id(const std::string &name, const uint32_t &id, const std::string &value); + void update_classifier_traffic_class_dport_by_id(const std::string &name, const uint32_t &id, const uint16_t &value); + void update_classifier_traffic_class_dstip_by_id(const std::string &name, const uint32_t &id, const std::string &value); + void update_classifier_traffic_class_ethtype_by_id(const std::string &name, const uint32_t &id, const TrafficClassEthtypeEnum &value); + void update_classifier_traffic_class_l4proto_by_id(const std::string &name, const uint32_t &id, const TrafficClassL4protoEnum &value); + void update_classifier_traffic_class_list_by_id(const std::string &name, const std::vector &value); + void update_classifier_traffic_class_priority_by_id(const std::string &name, const uint32_t &id, const uint32_t &value); + void update_classifier_traffic_class_smac_by_id(const std::string &name, const uint32_t &id, const std::string &value); + void update_classifier_traffic_class_sport_by_id(const std::string &name, const uint32_t &id, const uint16_t &value); + void update_classifier_traffic_class_srcip_by_id(const std::string &name, const uint32_t &id, const std::string &value); + + /* help related */ + std::vector> read_classifier_list_by_id_get_list(); + std::vector> read_classifier_traffic_class_list_by_id_get_list(const std::string &name); + +} +} +} +} + diff --git a/src/services/pcn-classifier/src/base/ClassifierBase.cpp b/src/services/pcn-classifier/src/base/ClassifierBase.cpp new file mode 100644 index 000000000..d64220a57 --- /dev/null +++ b/src/services/pcn-classifier/src/base/ClassifierBase.cpp @@ -0,0 +1,66 @@ +/** +* classifier API generated from classifier.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + +#include "ClassifierBase.h" + +ClassifierBase::ClassifierBase(const std::string name) { + logger()->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [Classifier] [%n] [%l] %v"); +} + + + +ClassifierBase::~ClassifierBase() {} + +void ClassifierBase::update(const ClassifierJsonObject &conf) { + set_conf(conf.getBase()); + + if (conf.trafficClassIsSet()) { + for (auto &i : conf.getTrafficClass()) { + auto id = i.getId(); + auto m = getTrafficClass(id); + m->update(i); + } + } +} + +ClassifierJsonObject ClassifierBase::toJsonObject() { + ClassifierJsonObject conf; + conf.setBase(to_json()); + + conf.setName(getName()); + for(auto &i : getTrafficClassList()) { + conf.addTrafficClass(i->toJsonObject()); + } + + return conf; +} +void ClassifierBase::addTrafficClassList(const std::vector &conf) { + for (auto &i : conf) { + uint32_t id_ = i.getId(); + addTrafficClass(id_, i); + } +} + +void ClassifierBase::replaceTrafficClass(const uint32_t &id, const TrafficClassJsonObject &conf) { + delTrafficClass(id); + uint32_t id_ = conf.getId(); + addTrafficClass(id_, conf); +} + +void ClassifierBase::delTrafficClassList() { + auto elements = getTrafficClassList(); + for (auto &i : elements) { + uint32_t id_ = i->getId(); + delTrafficClass(id_); + } +} + + diff --git a/src/services/pcn-classifier/src/base/ClassifierBase.h b/src/services/pcn-classifier/src/base/ClassifierBase.h new file mode 100644 index 000000000..5d4615a0f --- /dev/null +++ b/src/services/pcn-classifier/src/base/ClassifierBase.h @@ -0,0 +1,53 @@ +/** +* classifier API generated from classifier.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* ClassifierBase.h +* +* +*/ + +#pragma once + +#include "../serializer/ClassifierJsonObject.h" + +#include "../TrafficClass.h" + +#include "polycube/services/transparent_cube.h" + + + +#include "polycube/services/utils.h" +#include "polycube/services/fifo_map.hpp" + +#include + +using namespace polycube::service::model; + + +class ClassifierBase: public virtual polycube::service::TransparentCube { + public: + ClassifierBase(const std::string name); + + virtual ~ClassifierBase(); + virtual void update(const ClassifierJsonObject &conf); + virtual ClassifierJsonObject toJsonObject(); + + /// + /// Traffic class identified by id + /// + virtual std::shared_ptr getTrafficClass(const uint32_t &id) = 0; + virtual std::vector> getTrafficClassList() = 0; + virtual void addTrafficClass(const uint32_t &id, const TrafficClassJsonObject &conf) = 0; + virtual void addTrafficClassList(const std::vector &conf); + virtual void replaceTrafficClass(const uint32_t &id, const TrafficClassJsonObject &conf); + virtual void delTrafficClass(const uint32_t &id) = 0; + virtual void delTrafficClassList(); +}; diff --git a/src/services/pcn-classifier/src/base/TrafficClassBase.cpp b/src/services/pcn-classifier/src/base/TrafficClassBase.cpp new file mode 100644 index 000000000..970c72334 --- /dev/null +++ b/src/services/pcn-classifier/src/base/TrafficClassBase.cpp @@ -0,0 +1,76 @@ +/** +* classifier API generated from classifier.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + +#include "TrafficClassBase.h" +#include "../Classifier.h" + + +TrafficClassBase::TrafficClassBase(Classifier &parent) + : parent_(parent) {} + +TrafficClassBase::~TrafficClassBase() {} + +void TrafficClassBase::update(const TrafficClassJsonObject &conf) { + + if (conf.priorityIsSet()) { + setPriority(conf.getPriority()); + } + if (conf.directionIsSet()) { + setDirection(conf.getDirection()); + } + if (conf.smacIsSet()) { + setSmac(conf.getSmac()); + } + if (conf.dmacIsSet()) { + setDmac(conf.getDmac()); + } + if (conf.ethtypeIsSet()) { + setEthtype(conf.getEthtype()); + } + if (conf.srcipIsSet()) { + setSrcip(conf.getSrcip()); + } + if (conf.dstipIsSet()) { + setDstip(conf.getDstip()); + } + if (conf.l4protoIsSet()) { + setL4proto(conf.getL4proto()); + } + if (conf.sportIsSet()) { + setSport(conf.getSport()); + } + if (conf.dportIsSet()) { + setDport(conf.getDport()); + } +} + +TrafficClassJsonObject TrafficClassBase::toJsonObject() { + TrafficClassJsonObject conf; + + conf.setId(getId()); + conf.setPriority(getPriority()); + conf.setDirection(getDirection()); + conf.setSmac(getSmac()); + conf.setDmac(getDmac()); + conf.setEthtype(getEthtype()); + conf.setSrcip(getSrcip()); + conf.setDstip(getDstip()); + conf.setL4proto(getL4proto()); + conf.setSport(getSport()); + conf.setDport(getDport()); + + return conf; +} + +std::shared_ptr TrafficClassBase::logger() { + return parent_.logger(); +} + diff --git a/src/services/pcn-classifier/src/base/TrafficClassBase.h b/src/services/pcn-classifier/src/base/TrafficClassBase.h new file mode 100644 index 000000000..04333d8de --- /dev/null +++ b/src/services/pcn-classifier/src/base/TrafficClassBase.h @@ -0,0 +1,109 @@ +/** +* classifier API generated from classifier.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* TrafficClassBase.h +* +* +*/ + +#pragma once + +#include "../serializer/TrafficClassJsonObject.h" + + + + + + +#include + +using namespace polycube::service::model; + +class Classifier; + +class TrafficClassBase { + public: + + TrafficClassBase(Classifier &parent); + + virtual ~TrafficClassBase(); + virtual void update(const TrafficClassJsonObject &conf); + virtual TrafficClassJsonObject toJsonObject(); + + /// + /// Id of the class, set in metadata of matching packets + /// + virtual uint32_t getId() = 0; + + /// + /// Packets matching multiple classes are assigned to the one with highest priority + /// + virtual uint32_t getPriority() = 0; + virtual void setPriority(const uint32_t &value) = 0; + + /// + /// Direction (INGRESS, EGRESS or BOTH) of the packet (default: BOTH) + /// + virtual TrafficClassDirectionEnum getDirection() = 0; + virtual void setDirection(const TrafficClassDirectionEnum &value) = 0; + + /// + /// Source MAC address of the packet + /// + virtual std::string getSmac() = 0; + virtual void setSmac(const std::string &value) = 0; + + /// + /// Destination MAC address of the packet + /// + virtual std::string getDmac() = 0; + virtual void setDmac(const std::string &value) = 0; + + /// + /// Ethertype of the packet (ARP | IP) + /// + virtual TrafficClassEthtypeEnum getEthtype() = 0; + virtual void setEthtype(const TrafficClassEthtypeEnum &value) = 0; + + /// + /// Source IP address prefix of the packet + /// + virtual std::string getSrcip() = 0; + virtual void setSrcip(const std::string &value) = 0; + + /// + /// Destination IP address prefix of the packet + /// + virtual std::string getDstip() = 0; + virtual void setDstip(const std::string &value) = 0; + + /// + /// Level 4 protocol of the packet (ICMP | TCP | UDP) + /// + virtual TrafficClassL4protoEnum getL4proto() = 0; + virtual void setL4proto(const TrafficClassL4protoEnum &value) = 0; + + /// + /// Source port of the packet + /// + virtual uint16_t getSport() = 0; + virtual void setSport(const uint16_t &value) = 0; + + /// + /// Destination port of the packet + /// + virtual uint16_t getDport() = 0; + virtual void setDport(const uint16_t &value) = 0; + + std::shared_ptr logger(); + protected: + Classifier &parent_; +}; diff --git a/src/services/pcn-classifier/src/matcher/ExactMatcher.h b/src/services/pcn-classifier/src/matcher/ExactMatcher.h new file mode 100644 index 000000000..8d520724b --- /dev/null +++ b/src/services/pcn-classifier/src/matcher/ExactMatcher.h @@ -0,0 +1,107 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#pragma once + + +#include "Matcher.h" + + +template +class ExactMatcher : public Matcher { + using Matcher::classifier_; + using Matcher::field_; + using Matcher::bitvector_size_; + using Matcher::table_code_template_; + using Matcher::matching_code_template_; + using Matcher::current_bit_; + using Matcher::wildcard_bitvector_; + using Matcher::hasWildcard; + + public: + ExactMatcher(Classifier &classifier, MatchingField field) + : Matcher(classifier, field) { + replaceAll(table_code_template_, "_PREFIX_MATCHER", "0"); + replaceAll(matching_code_template_, "_PREFIX_MATCHER", "0"); + } + + void initBitvector(uint32_t size) override { + Matcher::initBitvector(size); + bitvectors_.clear(); + wildcard_bitvector_ = std::vector((bitvector_size_ - 1) / 64 + 1); + } + + void appendValueBit(T value) { + uint32_t subvector = current_bit_ / 64; + uint32_t subbit = current_bit_ % 64; + + if (bitvectors_.count(value) == 0) { + bitvectors_[value] = wildcard_bitvector_; + } + bitvectors_[value][subvector] |= (uint64_t)1 << subbit; + + current_bit_++; + } + + void appendValuesBit(std::vector values) { + uint32_t subvector = current_bit_ / 64; + uint32_t subbit = current_bit_ % 64; + + for (auto value : values) { + if (bitvectors_.count(value) == 0) { + bitvectors_[value] = wildcard_bitvector_; + } + bitvectors_[value][subvector] |= (uint64_t)1 << subbit; + } + + current_bit_++; + } + + void appendWildcardBit() override { + uint32_t subvector = current_bit_ / 64; + uint32_t subbit = current_bit_ % 64; + + for (auto &it : bitvectors_) { + it.second[subvector] |= (uint64_t)1 << subbit; + } + wildcard_bitvector_[subvector] |= (uint64_t)1 << subbit; + + current_bit_++; + } + + void loadTable(int prog_index, ProgramType direction) override { + std::string table_name = FIELD_NAME(field_) + "_rules"; + auto table = classifier_.get_raw_table(table_name, prog_index, direction); + for (auto &it : bitvectors_) { + table.set(&it.first, it.second.data()); + } + + if (hasWildcard()) { + table_name = FIELD_NAME(field_) + "_wildcard_bv"; + table = classifier_.get_raw_table(table_name, prog_index, direction); + int zero = 0; + table.set(&zero, wildcard_bitvector_.data()); + } + } + + bool isActive() override { + return bitvectors_.size() > 0; + } + + private: + std::unordered_map> bitvectors_; +}; \ No newline at end of file diff --git a/src/services/pcn-classifier/src/matcher/Matcher.h b/src/services/pcn-classifier/src/matcher/Matcher.h new file mode 100644 index 000000000..ec4387c00 --- /dev/null +++ b/src/services/pcn-classifier/src/matcher/Matcher.h @@ -0,0 +1,101 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#pragma once + + +#include "../Utils.h" +#include "MatcherInterface.h" +#include "Matcher_dp.h" +#include "MatchingTable_dp.h" + + +template +class Matcher : public MatcherInterface { + public: + Matcher(Classifier &classifier, MatchingField field) + : classifier_(classifier), + field_(field), + matching_code_template_(matcher_code), + table_code_template_(matching_table_code), + bitvector_size_(0) { + replaceAll(table_code_template_, "_FIELD", FIELD_NAME(field_)); + replaceAll(table_code_template_, "_TYPE", FIELD_TYPE(field_)); + replaceAll(matching_code_template_, "_FIELD", FIELD_NAME(field_)); + replaceAll(matching_code_template_, "_TYPE", FIELD_TYPE(field_)); + }; + + MatchingField getField() { + return field_; + } + + virtual void initBitvector(uint32_t size) { + bitvector_size_ = size; + current_bit_ = 0; + } + + std::string getTableCode() { + std::string table_code = table_code_template_; + replaceAll(table_code, "_CLASSES_COUNT", std::to_string(bitvector_size_)); + + if (hasWildcard()) { + replaceAll(table_code, "_WILDCARD", "1"); + + } else { + replaceAll(table_code, "_WILDCARD", "0"); + } + + return table_code; + } + + std::string getMatchingCode() { + std::string matching_code = matching_code_template_; + + replaceAll(matching_code, "_CLASSES_COUNT", + std::to_string(bitvector_size_)); + replaceAll(matching_code, "_SUBVECT_COUNT", + std::to_string((bitvector_size_ - 1) / 64 + 1)); + + if (hasWildcard()) { + replaceAll(matching_code, "_WILDCARD", "1"); + + } else { + replaceAll(matching_code, "_WILDCARD", "0"); + } + + return matching_code; + } + + protected: + Classifier &classifier_; + MatchingField field_; + uint32_t bitvector_size_; + std::string table_code_template_; + std::string matching_code_template_; + uint32_t current_bit_; + std::vector wildcard_bitvector_; + + bool hasWildcard() { + for (auto &it : wildcard_bitvector_) { + if (it != 0) { + return true; + } + } + + return false; + } +}; \ No newline at end of file diff --git a/src/services/pcn-classifier/src/matcher/MatcherInterface.h b/src/services/pcn-classifier/src/matcher/MatcherInterface.h new file mode 100644 index 000000000..60f5c49b5 --- /dev/null +++ b/src/services/pcn-classifier/src/matcher/MatcherInterface.h @@ -0,0 +1,33 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#pragma once + + +#include "../Classifier.h" + + +class MatcherInterface { + public: + virtual MatchingField getField() = 0; + virtual void initBitvector(uint32_t size) = 0; + virtual void appendWildcardBit() = 0; + virtual void loadTable(int prog_index, ProgramType direction) = 0; + virtual std::string getTableCode() = 0; + virtual std::string getMatchingCode() = 0; + virtual bool isActive() = 0; +}; \ No newline at end of file diff --git a/src/services/pcn-classifier/src/matcher/PrefixMatcher.h b/src/services/pcn-classifier/src/matcher/PrefixMatcher.h new file mode 100644 index 000000000..92ef3f4da --- /dev/null +++ b/src/services/pcn-classifier/src/matcher/PrefixMatcher.h @@ -0,0 +1,122 @@ +/* + * Copyright 2020 The Polycube Authors + * + * 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. + */ + + +#pragma once + + +#include "Matcher.h" + + +template +class PrefixMatcher : public Matcher { + using Matcher::classifier_; + using Matcher::field_; + using Matcher::bitvector_size_; + using Matcher::table_code_template_; + using Matcher::matching_code_template_; + using Matcher::current_bit_; + using Matcher::wildcard_bitvector_; + using Matcher::hasWildcard; + + public: + PrefixMatcher(Classifier &classifier, MatchingField field) + : Matcher(classifier, field) { + replaceAll(table_code_template_, "_PREFIX_MATCHER", "1"); + replaceAll(matching_code_template_, "_PREFIX_MATCHER", "1"); + } + + void initBitvector(uint32_t size) override { + Matcher::initBitvector(size); + bitvectors_.clear(); + wildcard_bitvector_ = std::vector((bitvector_size_ - 1) / 64 + 1); + } + + void appendValueBit(T value, uint32_t prefix_len) { + uint32_t subvector = current_bit_ / 64; + uint32_t subbit = current_bit_ % 64; + + T mask = 0; + mask -= 1; + mask <<= sizeof(T) * 8 - prefix_len; + mask >>= sizeof(T) * 8 - prefix_len; + + value &= mask; + struct LpmKey key = {prefix_len, value}; + + // Set the bit for all values that match the new one + bool present = false; + for (auto &it : bitvectors_) { + if (it.first == key) { + present = true; + } + + if ((it.first.key & mask) == value) { + it.second[subvector] |= (uint64_t)1 << subbit; + } + } + + if (!present) { + std::vector bv = wildcard_bitvector_; + bv[subvector] |= (uint64_t)1 << subbit; + bitvectors_.push_back( + std::pair>(key, bv)); + } + + current_bit_++; + } + + void appendWildcardBit() override { + uint32_t subvector = current_bit_ / 64; + uint32_t subbit = current_bit_ % 64; + + for (auto &it : bitvectors_) { + it.second[subvector] |= (uint64_t)1 << subbit; + } + wildcard_bitvector_[subvector] |= (uint64_t)1 << subbit; + + current_bit_++; + } + + void loadTable(int prog_index, ProgramType direction) override { + std::string table_name = FIELD_NAME(field_) + "_rules"; + auto table = classifier_.get_raw_table(table_name, prog_index, direction); + for (auto &it : bitvectors_) { + table.set(&it.first, it.second.data()); + } + + if (hasWildcard()) { + struct LpmKey key = {.prefix_len = 0, .key = 0}; + table.set(&key, wildcard_bitvector_.data()); + } + } + + bool isActive() override { + return bitvectors_.size() > 0; + } + + private: + struct LpmKey { + uint32_t prefix_len; + T key; + + bool operator==(const struct LpmKey &other) { + return key == other.key && prefix_len == other.prefix_len; + } + }; + + std::vector>> bitvectors_; +}; \ No newline at end of file diff --git a/src/services/pcn-classifier/src/serializer/ClassifierJsonObject.cpp b/src/services/pcn-classifier/src/serializer/ClassifierJsonObject.cpp new file mode 100644 index 000000000..d95c4cc54 --- /dev/null +++ b/src/services/pcn-classifier/src/serializer/ClassifierJsonObject.cpp @@ -0,0 +1,106 @@ +/** +* classifier API generated from classifier.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + + +#include "ClassifierJsonObject.h" +#include + +namespace polycube { +namespace service { +namespace model { + +ClassifierJsonObject::ClassifierJsonObject() { + m_nameIsSet = false; + m_trafficClassIsSet = false; +} + +ClassifierJsonObject::ClassifierJsonObject(const nlohmann::json &val) : + JsonObjectBase(val) { + m_nameIsSet = false; + m_trafficClassIsSet = false; + + + if (val.count("name")) { + setName(val.at("name").get()); + } + + if (val.count("traffic-class")) { + for (auto& item : val["traffic-class"]) { + TrafficClassJsonObject newItem{ item }; + m_trafficClass.push_back(newItem); + } + + m_trafficClassIsSet = true; + } +} + +nlohmann::json ClassifierJsonObject::toJson() const { + nlohmann::json val = nlohmann::json::object(); + if (!getBase().is_null()) { + val.update(getBase()); + } + + if (m_nameIsSet) { + val["name"] = m_name; + } + + { + nlohmann::json jsonArray; + for (auto& item : m_trafficClass) { + jsonArray.push_back(JsonObjectBase::toJson(item)); + } + + if (jsonArray.size() > 0) { + val["traffic-class"] = jsonArray; + } + } + + return val; +} + +std::string ClassifierJsonObject::getName() const { + return m_name; +} + +void ClassifierJsonObject::setName(std::string value) { + m_name = value; + m_nameIsSet = true; +} + +bool ClassifierJsonObject::nameIsSet() const { + return m_nameIsSet; +} + + + +const std::vector& ClassifierJsonObject::getTrafficClass() const{ + return m_trafficClass; +} + +void ClassifierJsonObject::addTrafficClass(TrafficClassJsonObject value) { + m_trafficClass.push_back(value); + m_trafficClassIsSet = true; +} + + +bool ClassifierJsonObject::trafficClassIsSet() const { + return m_trafficClassIsSet; +} + +void ClassifierJsonObject::unsetTrafficClass() { + m_trafficClassIsSet = false; +} + + +} +} +} + diff --git a/src/services/pcn-classifier/src/serializer/ClassifierJsonObject.h b/src/services/pcn-classifier/src/serializer/ClassifierJsonObject.h new file mode 100644 index 000000000..efa9a094a --- /dev/null +++ b/src/services/pcn-classifier/src/serializer/ClassifierJsonObject.h @@ -0,0 +1,67 @@ +/** +* classifier API generated from classifier.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* ClassifierJsonObject.h +* +* +*/ + +#pragma once + + +#include "JsonObjectBase.h" + +#include +#include "TrafficClassJsonObject.h" +#include "polycube/services/cube.h" + +namespace polycube { +namespace service { +namespace model { + + +/// +/// +/// +class ClassifierJsonObject : public JsonObjectBase { +public: + ClassifierJsonObject(); + ClassifierJsonObject(const nlohmann::json &json); + ~ClassifierJsonObject() final = default; + nlohmann::json toJson() const final; + + + /// + /// Name of the classifier service + /// + std::string getName() const; + void setName(std::string value); + bool nameIsSet() const; + + /// + /// Traffic class identified by id + /// + const std::vector& getTrafficClass() const; + void addTrafficClass(TrafficClassJsonObject value); + bool trafficClassIsSet() const; + void unsetTrafficClass(); + +private: + std::string m_name; + bool m_nameIsSet; + std::vector m_trafficClass; + bool m_trafficClassIsSet; +}; + +} +} +} + diff --git a/src/services/pcn-classifier/src/serializer/JsonObjectBase.cpp b/src/services/pcn-classifier/src/serializer/JsonObjectBase.cpp new file mode 100644 index 000000000..7e34bdba5 --- /dev/null +++ b/src/services/pcn-classifier/src/serializer/JsonObjectBase.cpp @@ -0,0 +1,69 @@ +/** +* classifier API generated from classifier.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +#include "JsonObjectBase.h" + +namespace polycube { +namespace service { +namespace model { + +JsonObjectBase::JsonObjectBase(const nlohmann::json &base) : base_(base) {} + +bool JsonObjectBase::iequals(const std::string &a, const std::string &b) { + if(a.size() != b.size()) + return false; + for (unsigned int i = 0; i < a.size(); i++){ + if(tolower(a[i]) != tolower(b[i])) + return false; + } + return true; +} + +std::string JsonObjectBase::toJson(const std::string& value) { + return value; +} + +std::string JsonObjectBase::toJson(const std::time_t& value) { + char buf[sizeof "2011-10-08T07:07:09Z"]; + strftime(buf, sizeof buf, "%FT%TZ", gmtime(&value)); + return buf; +} + +int32_t JsonObjectBase::toJson(int32_t value) { + return value; +} + +int64_t JsonObjectBase::toJson(int64_t value) { + return value; +} + +double JsonObjectBase::toJson(double value) { + return value; +} + +bool JsonObjectBase::toJson(bool value) { + return value; +} + +nlohmann::json JsonObjectBase::toJson(const JsonObjectBase &content) { + return content.toJson(); +} + +const nlohmann::json &JsonObjectBase::getBase() const { + return base_; +} + +void JsonObjectBase::setBase(const nlohmann::json &base) { + base_ = base; +} + +} +} +} diff --git a/src/services/pcn-classifier/src/serializer/JsonObjectBase.h b/src/services/pcn-classifier/src/serializer/JsonObjectBase.h new file mode 100644 index 000000000..645584b3f --- /dev/null +++ b/src/services/pcn-classifier/src/serializer/JsonObjectBase.h @@ -0,0 +1,55 @@ +/** +* classifier API generated from classifier.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* JsonObjectBase.h +* +* This is the base class for all model classes +*/ + +#pragma once + + +#include "polycube/services/json.hpp" +#include "polycube/services/fifo_map.hpp" +#include +#include + +namespace polycube { +namespace service { +namespace model { + +class JsonObjectBase { + public: + JsonObjectBase() = default; + JsonObjectBase(const nlohmann::json &base); + virtual ~JsonObjectBase() = default; + + virtual nlohmann::json toJson() const = 0; + + static bool iequals(const std::string &a, const std::string &b); + static std::string toJson(const std::string& value); + static std::string toJson(const std::time_t& value); + static int32_t toJson(int32_t value); + static int64_t toJson(int64_t value); + static double toJson(double value); + static bool toJson(bool value); + static nlohmann::json toJson(const JsonObjectBase &content); + + const nlohmann::json &getBase() const; + void setBase(const nlohmann::json &base); + + private: + nlohmann::json base_; +}; + +} +} +} diff --git a/src/services/pcn-classifier/src/serializer/TrafficClassJsonObject.cpp b/src/services/pcn-classifier/src/serializer/TrafficClassJsonObject.cpp new file mode 100644 index 000000000..9638a30b4 --- /dev/null +++ b/src/services/pcn-classifier/src/serializer/TrafficClassJsonObject.cpp @@ -0,0 +1,397 @@ +/** +* classifier API generated from classifier.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + + + +#include "TrafficClassJsonObject.h" +#include + +namespace polycube { +namespace service { +namespace model { + +TrafficClassJsonObject::TrafficClassJsonObject() { + m_idIsSet = false; + m_priorityIsSet = false; + m_direction = TrafficClassDirectionEnum::BOTH; + m_directionIsSet = true; + m_smacIsSet = false; + m_dmacIsSet = false; + m_ethtypeIsSet = false; + m_srcipIsSet = false; + m_dstipIsSet = false; + m_l4protoIsSet = false; + m_sportIsSet = false; + m_dportIsSet = false; +} + +TrafficClassJsonObject::TrafficClassJsonObject(const nlohmann::json &val) : + JsonObjectBase(val) { + m_idIsSet = false; + m_priorityIsSet = false; + m_directionIsSet = false; + m_smacIsSet = false; + m_dmacIsSet = false; + m_ethtypeIsSet = false; + m_srcipIsSet = false; + m_dstipIsSet = false; + m_l4protoIsSet = false; + m_sportIsSet = false; + m_dportIsSet = false; + + + if (val.count("id")) { + setId(val.at("id").get()); + } + + if (val.count("priority")) { + setPriority(val.at("priority").get()); + } + + if (val.count("direction")) { + setDirection(string_to_TrafficClassDirectionEnum(val.at("direction").get())); + } + + if (val.count("smac")) { + setSmac(val.at("smac").get()); + } + + if (val.count("dmac")) { + setDmac(val.at("dmac").get()); + } + + if (val.count("ethtype")) { + setEthtype(string_to_TrafficClassEthtypeEnum(val.at("ethtype").get())); + } + + if (val.count("srcip")) { + setSrcip(val.at("srcip").get()); + } + + if (val.count("dstip")) { + setDstip(val.at("dstip").get()); + } + + if (val.count("l4proto")) { + setL4proto(string_to_TrafficClassL4protoEnum(val.at("l4proto").get())); + } + + if (val.count("sport")) { + setSport(val.at("sport").get()); + } + + if (val.count("dport")) { + setDport(val.at("dport").get()); + } +} + +nlohmann::json TrafficClassJsonObject::toJson() const { + nlohmann::json val = nlohmann::json::object(); + if (!getBase().is_null()) { + val.update(getBase()); + } + + if (m_idIsSet) { + val["id"] = m_id; + } + + if (m_priorityIsSet) { + val["priority"] = m_priority; + } + + if (m_directionIsSet) { + val["direction"] = TrafficClassDirectionEnum_to_string(m_direction); + } + + if (m_smacIsSet) { + val["smac"] = m_smac; + } + + if (m_dmacIsSet) { + val["dmac"] = m_dmac; + } + + if (m_ethtypeIsSet) { + val["ethtype"] = TrafficClassEthtypeEnum_to_string(m_ethtype); + } + + if (m_srcipIsSet) { + val["srcip"] = m_srcip; + } + + if (m_dstipIsSet) { + val["dstip"] = m_dstip; + } + + if (m_l4protoIsSet) { + val["l4proto"] = TrafficClassL4protoEnum_to_string(m_l4proto); + } + + if (m_sportIsSet) { + val["sport"] = m_sport; + } + + if (m_dportIsSet) { + val["dport"] = m_dport; + } + + return val; +} + +uint32_t TrafficClassJsonObject::getId() const { + return m_id; +} + +void TrafficClassJsonObject::setId(uint32_t value) { + m_id = value; + m_idIsSet = true; +} + +bool TrafficClassJsonObject::idIsSet() const { + return m_idIsSet; +} + + + +uint32_t TrafficClassJsonObject::getPriority() const { + return m_priority; +} + +void TrafficClassJsonObject::setPriority(uint32_t value) { + m_priority = value; + m_priorityIsSet = true; +} + +bool TrafficClassJsonObject::priorityIsSet() const { + return m_priorityIsSet; +} + + + +TrafficClassDirectionEnum TrafficClassJsonObject::getDirection() const { + return m_direction; +} + +void TrafficClassJsonObject::setDirection(TrafficClassDirectionEnum value) { + m_direction = value; + m_directionIsSet = true; +} + +bool TrafficClassJsonObject::directionIsSet() const { + return m_directionIsSet; +} + +void TrafficClassJsonObject::unsetDirection() { + m_directionIsSet = false; +} + +std::string TrafficClassJsonObject::TrafficClassDirectionEnum_to_string(const TrafficClassDirectionEnum &value){ + switch(value) { + case TrafficClassDirectionEnum::INGRESS: + return std::string("ingress"); + case TrafficClassDirectionEnum::EGRESS: + return std::string("egress"); + case TrafficClassDirectionEnum::BOTH: + return std::string("both"); + default: + throw std::runtime_error("Bad TrafficClass direction"); + } +} + +TrafficClassDirectionEnum TrafficClassJsonObject::string_to_TrafficClassDirectionEnum(const std::string &str){ + if (JsonObjectBase::iequals("ingress", str)) + return TrafficClassDirectionEnum::INGRESS; + if (JsonObjectBase::iequals("egress", str)) + return TrafficClassDirectionEnum::EGRESS; + if (JsonObjectBase::iequals("both", str)) + return TrafficClassDirectionEnum::BOTH; + throw std::runtime_error("TrafficClass direction is invalid"); +} +std::string TrafficClassJsonObject::getSmac() const { + return m_smac; +} + +void TrafficClassJsonObject::setSmac(std::string value) { + m_smac = value; + m_smacIsSet = true; +} + +bool TrafficClassJsonObject::smacIsSet() const { + return m_smacIsSet; +} + +void TrafficClassJsonObject::unsetSmac() { + m_smacIsSet = false; +} + +std::string TrafficClassJsonObject::getDmac() const { + return m_dmac; +} + +void TrafficClassJsonObject::setDmac(std::string value) { + m_dmac = value; + m_dmacIsSet = true; +} + +bool TrafficClassJsonObject::dmacIsSet() const { + return m_dmacIsSet; +} + +void TrafficClassJsonObject::unsetDmac() { + m_dmacIsSet = false; +} + +TrafficClassEthtypeEnum TrafficClassJsonObject::getEthtype() const { + return m_ethtype; +} + +void TrafficClassJsonObject::setEthtype(TrafficClassEthtypeEnum value) { + m_ethtype = value; + m_ethtypeIsSet = true; +} + +bool TrafficClassJsonObject::ethtypeIsSet() const { + return m_ethtypeIsSet; +} + +void TrafficClassJsonObject::unsetEthtype() { + m_ethtypeIsSet = false; +} + +std::string TrafficClassJsonObject::TrafficClassEthtypeEnum_to_string(const TrafficClassEthtypeEnum &value){ + switch(value) { + case TrafficClassEthtypeEnum::ARP: + return std::string("arp"); + case TrafficClassEthtypeEnum::IP: + return std::string("ip"); + default: + throw std::runtime_error("Bad TrafficClass ethtype"); + } +} + +TrafficClassEthtypeEnum TrafficClassJsonObject::string_to_TrafficClassEthtypeEnum(const std::string &str){ + if (JsonObjectBase::iequals("arp", str)) + return TrafficClassEthtypeEnum::ARP; + if (JsonObjectBase::iequals("ip", str)) + return TrafficClassEthtypeEnum::IP; + throw std::runtime_error("TrafficClass ethtype is invalid"); +} +std::string TrafficClassJsonObject::getSrcip() const { + return m_srcip; +} + +void TrafficClassJsonObject::setSrcip(std::string value) { + m_srcip = value; + m_srcipIsSet = true; +} + +bool TrafficClassJsonObject::srcipIsSet() const { + return m_srcipIsSet; +} + +void TrafficClassJsonObject::unsetSrcip() { + m_srcipIsSet = false; +} + +std::string TrafficClassJsonObject::getDstip() const { + return m_dstip; +} + +void TrafficClassJsonObject::setDstip(std::string value) { + m_dstip = value; + m_dstipIsSet = true; +} + +bool TrafficClassJsonObject::dstipIsSet() const { + return m_dstipIsSet; +} + +void TrafficClassJsonObject::unsetDstip() { + m_dstipIsSet = false; +} + +TrafficClassL4protoEnum TrafficClassJsonObject::getL4proto() const { + return m_l4proto; +} + +void TrafficClassJsonObject::setL4proto(TrafficClassL4protoEnum value) { + m_l4proto = value; + m_l4protoIsSet = true; +} + +bool TrafficClassJsonObject::l4protoIsSet() const { + return m_l4protoIsSet; +} + +void TrafficClassJsonObject::unsetL4proto() { + m_l4protoIsSet = false; +} + +std::string TrafficClassJsonObject::TrafficClassL4protoEnum_to_string(const TrafficClassL4protoEnum &value){ + switch(value) { + case TrafficClassL4protoEnum::ICMP: + return std::string("icmp"); + case TrafficClassL4protoEnum::TCP: + return std::string("tcp"); + case TrafficClassL4protoEnum::UDP: + return std::string("udp"); + default: + throw std::runtime_error("Bad TrafficClass l4proto"); + } +} + +TrafficClassL4protoEnum TrafficClassJsonObject::string_to_TrafficClassL4protoEnum(const std::string &str){ + if (JsonObjectBase::iequals("icmp", str)) + return TrafficClassL4protoEnum::ICMP; + if (JsonObjectBase::iequals("tcp", str)) + return TrafficClassL4protoEnum::TCP; + if (JsonObjectBase::iequals("udp", str)) + return TrafficClassL4protoEnum::UDP; + throw std::runtime_error("TrafficClass l4proto is invalid"); +} +uint16_t TrafficClassJsonObject::getSport() const { + return m_sport; +} + +void TrafficClassJsonObject::setSport(uint16_t value) { + m_sport = value; + m_sportIsSet = true; +} + +bool TrafficClassJsonObject::sportIsSet() const { + return m_sportIsSet; +} + +void TrafficClassJsonObject::unsetSport() { + m_sportIsSet = false; +} + +uint16_t TrafficClassJsonObject::getDport() const { + return m_dport; +} + +void TrafficClassJsonObject::setDport(uint16_t value) { + m_dport = value; + m_dportIsSet = true; +} + +bool TrafficClassJsonObject::dportIsSet() const { + return m_dportIsSet; +} + +void TrafficClassJsonObject::unsetDport() { + m_dportIsSet = false; +} + + +} +} +} + diff --git a/src/services/pcn-classifier/src/serializer/TrafficClassJsonObject.h b/src/services/pcn-classifier/src/serializer/TrafficClassJsonObject.h new file mode 100644 index 000000000..8687acfff --- /dev/null +++ b/src/services/pcn-classifier/src/serializer/TrafficClassJsonObject.h @@ -0,0 +1,168 @@ +/** +* classifier API generated from classifier.yang +* +* NOTE: This file is auto generated by polycube-codegen +* https://github.com/polycube-network/polycube-codegen +*/ + + +/* Do not edit this file manually */ + +/* +* TrafficClassJsonObject.h +* +* +*/ + +#pragma once + + +#include "JsonObjectBase.h" + + +namespace polycube { +namespace service { +namespace model { + +enum class TrafficClassDirectionEnum { + INGRESS, EGRESS, BOTH +}; +enum class TrafficClassEthtypeEnum { + ARP, IP +}; +enum class TrafficClassL4protoEnum { + ICMP, TCP, UDP +}; + +/// +/// +/// +class TrafficClassJsonObject : public JsonObjectBase { +public: + TrafficClassJsonObject(); + TrafficClassJsonObject(const nlohmann::json &json); + ~TrafficClassJsonObject() final = default; + nlohmann::json toJson() const final; + + + /// + /// Id of the class, set in metadata of matching packets + /// + uint32_t getId() const; + void setId(uint32_t value); + bool idIsSet() const; + + /// + /// Packets matching multiple classes are assigned to the one with highest priority + /// + uint32_t getPriority() const; + void setPriority(uint32_t value); + bool priorityIsSet() const; + + /// + /// Direction (INGRESS, EGRESS or BOTH) of the packet (default: BOTH) + /// + TrafficClassDirectionEnum getDirection() const; + void setDirection(TrafficClassDirectionEnum value); + bool directionIsSet() const; + void unsetDirection(); + static std::string TrafficClassDirectionEnum_to_string(const TrafficClassDirectionEnum &value); + static TrafficClassDirectionEnum string_to_TrafficClassDirectionEnum(const std::string &str); + + /// + /// Source MAC address of the packet + /// + std::string getSmac() const; + void setSmac(std::string value); + bool smacIsSet() const; + void unsetSmac(); + + /// + /// Destination MAC address of the packet + /// + std::string getDmac() const; + void setDmac(std::string value); + bool dmacIsSet() const; + void unsetDmac(); + + /// + /// Ethertype of the packet (ARP | IP) + /// + TrafficClassEthtypeEnum getEthtype() const; + void setEthtype(TrafficClassEthtypeEnum value); + bool ethtypeIsSet() const; + void unsetEthtype(); + static std::string TrafficClassEthtypeEnum_to_string(const TrafficClassEthtypeEnum &value); + static TrafficClassEthtypeEnum string_to_TrafficClassEthtypeEnum(const std::string &str); + + /// + /// Source IP address prefix of the packet + /// + std::string getSrcip() const; + void setSrcip(std::string value); + bool srcipIsSet() const; + void unsetSrcip(); + + /// + /// Destination IP address prefix of the packet + /// + std::string getDstip() const; + void setDstip(std::string value); + bool dstipIsSet() const; + void unsetDstip(); + + /// + /// Level 4 protocol of the packet (ICMP | TCP | UDP) + /// + TrafficClassL4protoEnum getL4proto() const; + void setL4proto(TrafficClassL4protoEnum value); + bool l4protoIsSet() const; + void unsetL4proto(); + static std::string TrafficClassL4protoEnum_to_string(const TrafficClassL4protoEnum &value); + static TrafficClassL4protoEnum string_to_TrafficClassL4protoEnum(const std::string &str); + + /// + /// Source port of the packet + /// + uint16_t getSport() const; + void setSport(uint16_t value); + bool sportIsSet() const; + void unsetSport(); + + /// + /// Destination port of the packet + /// + uint16_t getDport() const; + void setDport(uint16_t value); + bool dportIsSet() const; + void unsetDport(); + +private: + uint32_t m_id; + bool m_idIsSet; + uint32_t m_priority; + bool m_priorityIsSet; + TrafficClassDirectionEnum m_direction; + bool m_directionIsSet; + std::string m_smac; + bool m_smacIsSet; + std::string m_dmac; + bool m_dmacIsSet; + TrafficClassEthtypeEnum m_ethtype; + bool m_ethtypeIsSet; + std::string m_srcip; + bool m_srcipIsSet; + std::string m_dstip; + bool m_dstipIsSet; + TrafficClassL4protoEnum m_l4proto; + bool m_l4protoIsSet; + uint16_t m_sport; + bool m_sportIsSet; + uint16_t m_dport; + bool m_dportIsSet; +}; + +} +} +} + From c78cc1e1f413ea37c2e4b65b64b60fe155fe3d9b Mon Sep 17 00:00:00 2001 From: FedeParola Date: Wed, 3 Jun 2020 18:16:56 +0200 Subject: [PATCH 05/12] Set max contracts to 100000 --- src/services/pcn-policer/src/Policer.cpp | 12 +----------- src/services/pcn-policer/src/Policer.h | 2 +- src/services/pcn-policer/src/Policer_dp.c | 6 ++++-- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/services/pcn-policer/src/Policer.cpp b/src/services/pcn-policer/src/Policer.cpp index 8658cafa1..719dfefcc 100644 --- a/src/services/pcn-policer/src/Policer.cpp +++ b/src/services/pcn-policer/src/Policer.cpp @@ -20,19 +20,9 @@ Policer::Policer(const std::string name, const PolicerJsonObject &conf) - : TransparentCube(conf.getBase(), {}, {}), PolicerBase(name) { + : TransparentCube(conf.getBase(), {policer_code}, {policer_code}), PolicerBase(name) { logger()->info("Creating Policer instance"); - // Inject ingress program - std::string code = std::string("#define MAX_CONTRACTS ") + - std::to_string(MAX_CONTRACTS) + std::string("\n") + - policer_code; - add_program(code, 0, polycube::service::ProgramType::INGRESS); - - // Inject egress program - code = std::string("#define EGRESS_PROG\n") + code; - add_program(code, 0, polycube::service::ProgramType::EGRESS); - default_contract_ = std::make_shared(*this, conf.getDefaultContract()); addContractList(conf.getContract()); diff --git a/src/services/pcn-policer/src/Policer.h b/src/services/pcn-policer/src/Policer.h index f2b2c4eed..07db10af4 100644 --- a/src/services/pcn-policer/src/Policer.h +++ b/src/services/pcn-policer/src/Policer.h @@ -24,7 +24,7 @@ #include "DefaultContract.h" -#define MAX_CONTRACTS 1024 +#define MAX_CONTRACTS 100000 struct bucket { diff --git a/src/services/pcn-policer/src/Policer_dp.c b/src/services/pcn-policer/src/Policer_dp.c index ca8118127..e383f5ef5 100644 --- a/src/services/pcn-policer/src/Policer_dp.c +++ b/src/services/pcn-policer/src/Policer_dp.c @@ -37,10 +37,12 @@ struct contract { struct bpf_spin_lock lock; }; -#ifdef EGRESS_PROG +#define MAX_CONTRACTS 100000 + +#if POLYCUBE_PROGRAM_TYPE == 1 // EGRESS BPF_TABLE("extern", int, struct contract, default_contract, 1); BPF_TABLE("extern", u32, struct contract, contracts, MAX_CONTRACTS); -#else +#else // INGRESS BPF_TABLE_SHARED("array", int, struct contract, default_contract, 1); BPF_TABLE_SHARED("hash", u32, struct contract, contracts, MAX_CONTRACTS); #endif From 04258b4af5bcaae3eea21535b91aaf91340f9b38 Mon Sep 17 00:00:00 2001 From: FedeParola Date: Sun, 7 Jun 2020 14:48:47 +0200 Subject: [PATCH 06/12] Use us granularity timestamp, minor improvements --- src/services/pcn-policer/src/Contract.cpp | 10 ++---- src/services/pcn-policer/src/Contract.h | 4 --- .../pcn-policer/src/DefaultContract.cpp | 6 ++-- .../pcn-policer/src/DefaultContract.h | 4 --- src/services/pcn-policer/src/Policer.cpp | 35 ++++++++++++++----- src/services/pcn-policer/src/Policer.h | 12 ++----- src/services/pcn-policer/src/Policer_dp.c | 16 ++++----- 7 files changed, 42 insertions(+), 45 deletions(-) diff --git a/src/services/pcn-policer/src/Contract.cpp b/src/services/pcn-policer/src/Contract.cpp index dcae069e6..27c6aef83 100644 --- a/src/services/pcn-policer/src/Contract.cpp +++ b/src/services/pcn-policer/src/Contract.cpp @@ -14,11 +14,9 @@ * limitations under the License. */ - #include "Contract.h" #include "Policer.h" - Contract::Contract(Policer &parent, const ContractJsonObject &conf) : ContractBase(parent) { traffic_class_ = conf.getTrafficClass(); @@ -43,15 +41,11 @@ Contract::Contract(Policer &parent, const ContractJsonObject &conf) } updateDataplane(); - - logger()->info("Contract created {0}", toString()); } Contract::~Contract() { parent_.get_hash_table("contracts") .remove(traffic_class_); - - logger()->info("Contract for class {0} deleted", traffic_class_); } ContractJsonObject Contract::toJsonObject() { @@ -127,9 +121,9 @@ void Contract::updateData(ContractUpdateDataInputJsonObject input) { void Contract::updateDataplane() { struct bucket bucket = { - .tokens = burst_limit_, + .tokens = burst_limit_ * 1000000, .refill_rate = rate_limit_, - .capacity = burst_limit_, + .capacity = burst_limit_ * 1000000, .last_update = 0 }; diff --git a/src/services/pcn-policer/src/Contract.h b/src/services/pcn-policer/src/Contract.h index 4cbcf91bf..19ac35419 100644 --- a/src/services/pcn-policer/src/Contract.h +++ b/src/services/pcn-policer/src/Contract.h @@ -14,18 +14,14 @@ * limitations under the License. */ - #pragma once - #include "../base/ContractBase.h" - class Policer; using namespace polycube::service::model; - class Contract : public ContractBase { public: Contract(Policer &parent, const ContractJsonObject &conf); diff --git a/src/services/pcn-policer/src/DefaultContract.cpp b/src/services/pcn-policer/src/DefaultContract.cpp index ee7036bde..ef55f7470 100644 --- a/src/services/pcn-policer/src/DefaultContract.cpp +++ b/src/services/pcn-policer/src/DefaultContract.cpp @@ -14,11 +14,9 @@ * limitations under the License. */ - #include "DefaultContract.h" #include "Policer.h" - DefaultContract::DefaultContract(Policer &parent, const DefaultContractJsonObject &conf) : DefaultContractBase(parent) { @@ -118,9 +116,9 @@ void DefaultContract::updateData( void DefaultContract::updateDataplane() { struct bucket bucket = { - .tokens = burst_limit_, + .tokens = burst_limit_ * 1000000, .refill_rate = rate_limit_, - .capacity = burst_limit_, + .capacity = burst_limit_ * 1000000, .last_update = 0 }; diff --git a/src/services/pcn-policer/src/DefaultContract.h b/src/services/pcn-policer/src/DefaultContract.h index 8ed4d620b..82f82ed2a 100644 --- a/src/services/pcn-policer/src/DefaultContract.h +++ b/src/services/pcn-policer/src/DefaultContract.h @@ -14,18 +14,14 @@ * limitations under the License. */ - #pragma once - #include "../base/DefaultContractBase.h" - class Policer; using namespace polycube::service::model; - class DefaultContract : public DefaultContractBase { public: DefaultContract(Policer &parent, const DefaultContractJsonObject &conf); diff --git a/src/services/pcn-policer/src/Policer.cpp b/src/services/pcn-policer/src/Policer.cpp index 719dfefcc..9aab2de63 100644 --- a/src/services/pcn-policer/src/Policer.cpp +++ b/src/services/pcn-policer/src/Policer.cpp @@ -14,11 +14,9 @@ * limitations under the License. */ - #include "Policer.h" #include "Policer_dp.h" - Policer::Policer(const std::string name, const PolicerJsonObject &conf) : TransparentCube(conf.getBase(), {policer_code}, {policer_code}), PolicerBase(name) { logger()->info("Creating Policer instance"); @@ -85,12 +83,31 @@ void Policer::addContract(const uint32_t &trafficClass, } contracts_[trafficClass] = std::make_shared(*this, conf); + + logger()->info("Contract added {0}", contracts_[trafficClass]->toString()); } -// Basic default implementation, place your extension here (if needed) void Policer::addContractList(const std::vector &conf) { - // call default implementation in base class - PolicerBase::addContractList(conf); + if (conf.size() == 0) { + return; + } + + if (contracts_.size() + conf.size() > MAX_CONTRACTS) { + throw std::runtime_error("Maximum number of traffic contracts reached"); + } + + for (auto &it : conf) { + if (contracts_.count(it.getTrafficClass()) != 0) { + throw std::runtime_error(std::string("Contract for traffic class ") + + std::to_string(it.getTrafficClass()) + + " already registered"); + } + } + for (auto &it : conf) { + contracts_[it.getTrafficClass()] = std::make_shared(*this, it); + } + + logger()->info("Contract list added"); } // Basic default implementation, place your extension here (if needed) @@ -106,10 +123,12 @@ void Policer::delContract(const uint32_t &trafficClass) { } contracts_.erase(trafficClass); + + logger()->info("Contract {0} deleted", trafficClass); } -// Basic default implementation, place your extension here (if needed) void Policer::delContractList() { - // call default implementation in base class - PolicerBase::delContractList(); + contracts_.clear(); + + logger()->info("Contract list deleted"); } \ No newline at end of file diff --git a/src/services/pcn-policer/src/Policer.h b/src/services/pcn-policer/src/Policer.h index 07db10af4..055dc6ef9 100644 --- a/src/services/pcn-policer/src/Policer.h +++ b/src/services/pcn-policer/src/Policer.h @@ -14,24 +14,19 @@ * limitations under the License. */ - #pragma once - #include "../base/PolicerBase.h" - #include "Contract.h" #include "DefaultContract.h" - #define MAX_CONTRACTS 100000 - struct bucket { - uint64_t tokens; - uint64_t refill_rate; // tokens/s + uint64_t tokens; // 1 bit = 1000000 tokens + uint64_t refill_rate; // tokens/us uint64_t capacity; - uint64_t last_update; + uint64_t last_update; // timestamp in us }; struct contract { @@ -42,7 +37,6 @@ struct contract { using namespace polycube::service::model; - class Policer : public PolicerBase { public: Policer(const std::string name, const PolicerJsonObject &conf); diff --git a/src/services/pcn-policer/src/Policer_dp.c b/src/services/pcn-policer/src/Policer_dp.c index e383f5ef5..5e41b92ef 100644 --- a/src/services/pcn-policer/src/Policer_dp.c +++ b/src/services/pcn-policer/src/Policer_dp.c @@ -25,10 +25,10 @@ enum { }; struct bucket { - u64 tokens; - u64 refill_rate; // tokens/s + u64 tokens; // 1 bit = 1000000 tokens + u64 refill_rate; // tokens/us u64 capacity; - u64 last_update; + u64 last_update; // timestamp in us }; struct contract { @@ -53,7 +53,7 @@ static inline int limit_rate(struct CTXTYPE *ctx, struct contract *contract) { void *data = (void *)(long)ctx->data; void *data_end = (void *)(long)ctx->data_end; - u64 curtime = bpf_ktime_get_ns(); + u64 curtime = bpf_ktime_get_ns() / 1000; // In us bpf_spin_lock(&contract->lock); @@ -64,7 +64,7 @@ static inline int limit_rate(struct CTXTYPE *ctx, struct contract *contract) { } else if (curtime > bucket->last_update){ u64 new_tokens = - (curtime - bucket->last_update) * bucket->refill_rate / 1000000000; + (curtime - bucket->last_update) * bucket->refill_rate; if (new_tokens > 0) { bucket->tokens += new_tokens; if (bucket->tokens > bucket->capacity) { @@ -75,10 +75,10 @@ static inline int limit_rate(struct CTXTYPE *ctx, struct contract *contract) { } // Consume tokens - u32 size = (data_end - data) * 8; // In bits + u32 needed_tokens = (data_end - data) * 8 * 1000000; u8 retval; - if (bucket->tokens >= size) { - bucket->tokens -= size; + if (bucket->tokens >= needed_tokens) { + bucket->tokens -= needed_tokens; retval = RX_OK; } else { retval = RX_DROP; From 8cd46339fe7c74fbd006da0ce01ed1dad4b8eca9 Mon Sep 17 00:00:00 2001 From: FedeParola Date: Tue, 9 Jun 2020 09:02:05 +0200 Subject: [PATCH 07/12] Store needed tokens in u64 --- src/services/pcn-policer/src/Policer_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/pcn-policer/src/Policer_dp.c b/src/services/pcn-policer/src/Policer_dp.c index 5e41b92ef..bb842beb1 100644 --- a/src/services/pcn-policer/src/Policer_dp.c +++ b/src/services/pcn-policer/src/Policer_dp.c @@ -75,7 +75,7 @@ static inline int limit_rate(struct CTXTYPE *ctx, struct contract *contract) { } // Consume tokens - u32 needed_tokens = (data_end - data) * 8 * 1000000; + u64 needed_tokens = (data_end - data) * 8 * 1000000; u8 retval; if (bucket->tokens >= needed_tokens) { bucket->tokens -= needed_tokens; From 8e0d5bab4848ae402ca61f4f57a049bea5d5ca29 Mon Sep 17 00:00:00 2001 From: FedeParola Date: Wed, 10 Jun 2020 10:52:09 +0200 Subject: [PATCH 08/12] Implement cp updated clock --- src/services/pcn-policer/src/Contract.cpp | 4 +-- .../pcn-policer/src/DefaultContract.cpp | 4 +-- src/services/pcn-policer/src/Policer.cpp | 19 ++++++++++++ src/services/pcn-policer/src/Policer.h | 6 ++++ src/services/pcn-policer/src/Policer_dp.c | 31 ++++++++++--------- 5 files changed, 46 insertions(+), 18 deletions(-) diff --git a/src/services/pcn-policer/src/Contract.cpp b/src/services/pcn-policer/src/Contract.cpp index 27c6aef83..e95931cf3 100644 --- a/src/services/pcn-policer/src/Contract.cpp +++ b/src/services/pcn-policer/src/Contract.cpp @@ -121,9 +121,9 @@ void Contract::updateData(ContractUpdateDataInputJsonObject input) { void Contract::updateDataplane() { struct bucket bucket = { - .tokens = burst_limit_ * 1000000, + .tokens = burst_limit_ * 1000, .refill_rate = rate_limit_, - .capacity = burst_limit_ * 1000000, + .capacity = burst_limit_ * 1000, .last_update = 0 }; diff --git a/src/services/pcn-policer/src/DefaultContract.cpp b/src/services/pcn-policer/src/DefaultContract.cpp index ef55f7470..6f423be6a 100644 --- a/src/services/pcn-policer/src/DefaultContract.cpp +++ b/src/services/pcn-policer/src/DefaultContract.cpp @@ -116,9 +116,9 @@ void DefaultContract::updateData( void DefaultContract::updateDataplane() { struct bucket bucket = { - .tokens = burst_limit_ * 1000000, + .tokens = burst_limit_ * 1000, .refill_rate = rate_limit_, - .capacity = burst_limit_ * 1000000, + .capacity = burst_limit_ * 1000, .last_update = 0 }; diff --git a/src/services/pcn-policer/src/Policer.cpp b/src/services/pcn-policer/src/Policer.cpp index 9aab2de63..3c3dc631c 100644 --- a/src/services/pcn-policer/src/Policer.cpp +++ b/src/services/pcn-policer/src/Policer.cpp @@ -21,6 +21,9 @@ Policer::Policer(const std::string name, const PolicerJsonObject &conf) : TransparentCube(conf.getBase(), {policer_code}, {policer_code}), PolicerBase(name) { logger()->info("Creating Policer instance"); + quit_thread_ = false; + clock_update_thread_ = std::thread(&Policer::updateClock, this); + default_contract_ = std::make_shared(*this, conf.getDefaultContract()); addContractList(conf.getContract()); @@ -28,6 +31,9 @@ Policer::Policer(const std::string name, const PolicerJsonObject &conf) Policer::~Policer() { logger()->info("Destroying Policer instance"); + + quit_thread_ = true; + clock_update_thread_.join(); } void Policer::packet_in(polycube::service::Direction direction, @@ -131,4 +137,17 @@ void Policer::delContractList() { contracts_.clear(); logger()->info("Contract list deleted"); +} + +void Policer::updateClock() { + while (!quit_thread_) { + std::chrono::milliseconds ms = + std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()); + uint64_t count = ms.count(); + auto clock_table = get_percpuarray_table("clock"); + clock_table.set(0, count); + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } } \ No newline at end of file diff --git a/src/services/pcn-policer/src/Policer.h b/src/services/pcn-policer/src/Policer.h index 055dc6ef9..22957e5df 100644 --- a/src/services/pcn-policer/src/Policer.h +++ b/src/services/pcn-policer/src/Policer.h @@ -70,4 +70,10 @@ class Policer : public PolicerBase { private: std::shared_ptr default_contract_; std::unordered_map> contracts_; + + // Thread to update the clock for the data plane + std::thread clock_update_thread_; + std::atomic quit_thread_; + + void updateClock(); }; diff --git a/src/services/pcn-policer/src/Policer_dp.c b/src/services/pcn-policer/src/Policer_dp.c index bb842beb1..938fbbcc2 100644 --- a/src/services/pcn-policer/src/Policer_dp.c +++ b/src/services/pcn-policer/src/Policer_dp.c @@ -42,40 +42,43 @@ struct contract { #if POLYCUBE_PROGRAM_TYPE == 1 // EGRESS BPF_TABLE("extern", int, struct contract, default_contract, 1); BPF_TABLE("extern", u32, struct contract, contracts, MAX_CONTRACTS); +BPF_TABLE("extern", int, uint64_t, clock, 1); #else // INGRESS BPF_TABLE_SHARED("array", int, struct contract, default_contract, 1); BPF_TABLE_SHARED("hash", u32, struct contract, contracts, MAX_CONTRACTS); +BPF_TABLE_SHARED("percpu_array", int, uint64_t, clock, 1); #endif static inline int limit_rate(struct CTXTYPE *ctx, struct contract *contract) { + int zero = 0; struct bucket *bucket = &contract->bucket; void *data = (void *)(long)ctx->data; void *data_end = (void *)(long)ctx->data_end; - u64 curtime = bpf_ktime_get_ns() / 1000; // In us - + u64 *clock_p = clock.lookup(&zero); + if (!clock_p) { + return RX_DROP; + } + + u64 curtime = *clock_p; // In ms + bpf_spin_lock(&contract->lock); // Refill tokens - // If last_update == 0 the bucket is new, no need to add tokens - if (bucket->last_update == 0) { - bucket->last_update = curtime; - - } else if (curtime > bucket->last_update){ + if (curtime > bucket->last_update){ u64 new_tokens = (curtime - bucket->last_update) * bucket->refill_rate; - if (new_tokens > 0) { - bucket->tokens += new_tokens; - if (bucket->tokens > bucket->capacity) { - bucket->tokens = bucket->capacity; - } - bucket->last_update = curtime; + + bucket->tokens += new_tokens; + if (bucket->tokens > bucket->capacity) { + bucket->tokens = bucket->capacity; } + bucket->last_update = curtime; } // Consume tokens - u64 needed_tokens = (data_end - data) * 8 * 1000000; + u64 needed_tokens = (data_end - data) * 8 * 1000; u8 retval; if (bucket->tokens >= needed_tokens) { bucket->tokens -= needed_tokens; From fb3798b354e249d034ce94969ad3ad3a99ec81b4 Mon Sep 17 00:00:00 2001 From: FedeParola Date: Thu, 11 Jun 2020 09:35:39 +0200 Subject: [PATCH 09/12] Set max traffic classes to 100000 --- src/services/pcn-classifier/src/Classifier.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/pcn-classifier/src/Classifier.h b/src/services/pcn-classifier/src/Classifier.h index aceb370a0..b66647d04 100644 --- a/src/services/pcn-classifier/src/Classifier.h +++ b/src/services/pcn-classifier/src/Classifier.h @@ -25,7 +25,7 @@ #include -#define MAX_TRAFFIC_CLASSES 10000 +#define MAX_TRAFFIC_CLASSES 100000 #define FIELDS_COUNT 8 #define FIELD_INDEX(field) (static_cast(field)) From 7e19bccba623dc2e9a53f6264edd592823c4aa28 Mon Sep 17 00:00:00 2001 From: FedeParola Date: Fri, 19 Jun 2020 08:45:28 +0200 Subject: [PATCH 10/12] Configure rate and burst in kbit --- src/services/pcn-policer/datamodel/policer.yang | 4 ++-- src/services/pcn-policer/src/Contract.cpp | 2 +- src/services/pcn-policer/src/Contract.h | 4 ++-- src/services/pcn-policer/src/DefaultContract.cpp | 2 +- src/services/pcn-policer/src/DefaultContract.h | 4 ++-- src/services/pcn-policer/src/Policer.h | 7 ++++--- src/services/pcn-policer/src/Policer_dp.c | 16 ++++++++-------- src/services/pcn-policer/src/base/ContractBase.h | 4 ++-- .../pcn-policer/src/base/DefaultContractBase.h | 4 ++-- .../src/serializer/ContractJsonObject.h | 4 ++-- .../ContractUpdateDataInputJsonObject.h | 4 ++-- .../src/serializer/DefaultContractJsonObject.h | 4 ++-- .../DefaultContractUpdateDataInputJsonObject.h | 4 ++-- 13 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/services/pcn-policer/datamodel/policer.yang b/src/services/pcn-policer/datamodel/policer.yang index 7e5b573a7..1d9b6bbb8 100644 --- a/src/services/pcn-policer/datamodel/policer.yang +++ b/src/services/pcn-policer/datamodel/policer.yang @@ -34,14 +34,14 @@ module policer { leaf rate-limit { type uint64; - description "Maximum average traffic rate (in bps)"; + description "Maximum average traffic rate (in kbit/s)"; polycube-base:cli-example "10000"; polycube-base:init-only-config; } leaf burst-limit { type uint64; - description "Maximum size of a burst of packets (in bits)"; + description "Maximum size of a burst of packets (in kbits)"; polycube-base:cli-example "50000"; polycube-base:init-only-config; } diff --git a/src/services/pcn-policer/src/Contract.cpp b/src/services/pcn-policer/src/Contract.cpp index e95931cf3..70e057574 100644 --- a/src/services/pcn-policer/src/Contract.cpp +++ b/src/services/pcn-policer/src/Contract.cpp @@ -124,7 +124,7 @@ void Contract::updateDataplane() { .tokens = burst_limit_ * 1000, .refill_rate = rate_limit_, .capacity = burst_limit_ * 1000, - .last_update = 0 + .last_refill = 0 }; struct contract contract = { diff --git a/src/services/pcn-policer/src/Contract.h b/src/services/pcn-policer/src/Contract.h index 19ac35419..6d19c9279 100644 --- a/src/services/pcn-policer/src/Contract.h +++ b/src/services/pcn-policer/src/Contract.h @@ -39,12 +39,12 @@ class Contract : public ContractBase { ActionTypeEnum getAction() override; /// - /// Maximum average traffic rate (in bps) + /// Maximum average traffic rate (in kbit/s) /// uint64_t getRateLimit() override; /// - /// Maximum size of a burst of packets (in bits) + /// Maximum size of a burst of packets (in kbits) /// uint64_t getBurstLimit() override; diff --git a/src/services/pcn-policer/src/DefaultContract.cpp b/src/services/pcn-policer/src/DefaultContract.cpp index 6f423be6a..5d0d70e70 100644 --- a/src/services/pcn-policer/src/DefaultContract.cpp +++ b/src/services/pcn-policer/src/DefaultContract.cpp @@ -119,7 +119,7 @@ void DefaultContract::updateDataplane() { .tokens = burst_limit_ * 1000, .refill_rate = rate_limit_, .capacity = burst_limit_ * 1000, - .last_update = 0 + .last_refill = 0 }; struct contract contract = { diff --git a/src/services/pcn-policer/src/DefaultContract.h b/src/services/pcn-policer/src/DefaultContract.h index 82f82ed2a..66c035e69 100644 --- a/src/services/pcn-policer/src/DefaultContract.h +++ b/src/services/pcn-policer/src/DefaultContract.h @@ -34,12 +34,12 @@ class DefaultContract : public DefaultContractBase { ActionTypeEnum getAction() override; /// - /// Maximum average traffic rate (in bps) + /// Maximum average traffic rate (in kbit/s) /// uint64_t getRateLimit() override; /// - /// Maximum size of a burst of packets (in bits) + /// Maximum size of a burst of packets (in kbits) /// uint64_t getBurstLimit() override; diff --git a/src/services/pcn-policer/src/Policer.h b/src/services/pcn-policer/src/Policer.h index 22957e5df..f1b40a3b6 100644 --- a/src/services/pcn-policer/src/Policer.h +++ b/src/services/pcn-policer/src/Policer.h @@ -23,10 +23,11 @@ #define MAX_CONTRACTS 100000 struct bucket { - uint64_t tokens; // 1 bit = 1000000 tokens - uint64_t refill_rate; // tokens/us + uint64_t tokens; + uint64_t refill_rate; // tokens/ms uint64_t capacity; - uint64_t last_update; // timestamp in us + uint64_t last_refill; // Timestamp of the last time the bucket was refilled + // in ms }; struct contract { diff --git a/src/services/pcn-policer/src/Policer_dp.c b/src/services/pcn-policer/src/Policer_dp.c index 938fbbcc2..69f4f6408 100644 --- a/src/services/pcn-policer/src/Policer_dp.c +++ b/src/services/pcn-policer/src/Policer_dp.c @@ -25,10 +25,10 @@ enum { }; struct bucket { - u64 tokens; // 1 bit = 1000000 tokens - u64 refill_rate; // tokens/us + u64 tokens; + u64 refill_rate; // tokens/ms u64 capacity; - u64 last_update; // timestamp in us + u64 last_refill; // Timestamp of the last time the bucket was refilled in ms }; struct contract { @@ -61,24 +61,24 @@ static inline int limit_rate(struct CTXTYPE *ctx, struct contract *contract) { return RX_DROP; } - u64 curtime = *clock_p; // In ms + u64 now = *clock_p; // In ms bpf_spin_lock(&contract->lock); // Refill tokens - if (curtime > bucket->last_update){ + if (now > bucket->last_refill){ u64 new_tokens = - (curtime - bucket->last_update) * bucket->refill_rate; + (now - bucket->last_refill) * bucket->refill_rate; bucket->tokens += new_tokens; if (bucket->tokens > bucket->capacity) { bucket->tokens = bucket->capacity; } - bucket->last_update = curtime; + bucket->last_refill = now; } // Consume tokens - u64 needed_tokens = (data_end - data) * 8 * 1000; + u64 needed_tokens = (data_end - data) * 8; u8 retval; if (bucket->tokens >= needed_tokens) { bucket->tokens -= needed_tokens; diff --git a/src/services/pcn-policer/src/base/ContractBase.h b/src/services/pcn-policer/src/base/ContractBase.h index 2034e7561..0431746cc 100644 --- a/src/services/pcn-policer/src/base/ContractBase.h +++ b/src/services/pcn-policer/src/base/ContractBase.h @@ -51,12 +51,12 @@ class ContractBase { virtual ActionTypeEnum getAction() = 0; /// - /// Maximum average traffic rate (in bps) + /// Maximum average traffic rate (in kbit/s) /// virtual uint64_t getRateLimit() = 0; /// - /// Maximum size of a burst of packets (in bits) + /// Maximum size of a burst of packets (in kbits) /// virtual uint64_t getBurstLimit() = 0; virtual void updateData(ContractUpdateDataInputJsonObject input) = 0; diff --git a/src/services/pcn-policer/src/base/DefaultContractBase.h b/src/services/pcn-policer/src/base/DefaultContractBase.h index 85d3c6604..d83b3844e 100644 --- a/src/services/pcn-policer/src/base/DefaultContractBase.h +++ b/src/services/pcn-policer/src/base/DefaultContractBase.h @@ -46,12 +46,12 @@ class DefaultContractBase { virtual ActionTypeEnum getAction() = 0; /// - /// Maximum average traffic rate (in bps) + /// Maximum average traffic rate (in kbit/s) /// virtual uint64_t getRateLimit() = 0; /// - /// Maximum size of a burst of packets (in bits) + /// Maximum size of a burst of packets (in kbits) /// virtual uint64_t getBurstLimit() = 0; virtual void updateData(DefaultContractUpdateDataInputJsonObject input) = 0; diff --git a/src/services/pcn-policer/src/serializer/ContractJsonObject.h b/src/services/pcn-policer/src/serializer/ContractJsonObject.h index af60f790c..29f8046b9 100644 --- a/src/services/pcn-policer/src/serializer/ContractJsonObject.h +++ b/src/services/pcn-policer/src/serializer/ContractJsonObject.h @@ -59,7 +59,7 @@ class ContractJsonObject : public JsonObjectBase { static ActionTypeEnum string_to_ActionTypeEnum(const std::string &str); /// - /// Maximum average traffic rate (in bps) + /// Maximum average traffic rate (in kbit/s) /// uint64_t getRateLimit() const; void setRateLimit(uint64_t value); @@ -67,7 +67,7 @@ class ContractJsonObject : public JsonObjectBase { void unsetRateLimit(); /// - /// Maximum size of a burst of packets (in bits) + /// Maximum size of a burst of packets (in kbits) /// uint64_t getBurstLimit() const; void setBurstLimit(uint64_t value); diff --git a/src/services/pcn-policer/src/serializer/ContractUpdateDataInputJsonObject.h b/src/services/pcn-policer/src/serializer/ContractUpdateDataInputJsonObject.h index 3868c7f5c..286ee35ae 100644 --- a/src/services/pcn-policer/src/serializer/ContractUpdateDataInputJsonObject.h +++ b/src/services/pcn-policer/src/serializer/ContractUpdateDataInputJsonObject.h @@ -53,7 +53,7 @@ class ContractUpdateDataInputJsonObject : public JsonObjectBase { static ActionTypeEnum string_to_ActionTypeEnum(const std::string &str); /// - /// Maximum average traffic rate (in bps) + /// Maximum average traffic rate (in kbit/s) /// uint64_t getRateLimit() const; void setRateLimit(uint64_t value); @@ -61,7 +61,7 @@ class ContractUpdateDataInputJsonObject : public JsonObjectBase { void unsetRateLimit(); /// - /// Maximum size of a burst of packets (in bits) + /// Maximum size of a burst of packets (in kbits) /// uint64_t getBurstLimit() const; void setBurstLimit(uint64_t value); diff --git a/src/services/pcn-policer/src/serializer/DefaultContractJsonObject.h b/src/services/pcn-policer/src/serializer/DefaultContractJsonObject.h index fd16c1a0e..23d9ec389 100644 --- a/src/services/pcn-policer/src/serializer/DefaultContractJsonObject.h +++ b/src/services/pcn-policer/src/serializer/DefaultContractJsonObject.h @@ -53,7 +53,7 @@ class DefaultContractJsonObject : public JsonObjectBase { static ActionTypeEnum string_to_ActionTypeEnum(const std::string &str); /// - /// Maximum average traffic rate (in bps) + /// Maximum average traffic rate (in kbit/s) /// uint64_t getRateLimit() const; void setRateLimit(uint64_t value); @@ -61,7 +61,7 @@ class DefaultContractJsonObject : public JsonObjectBase { void unsetRateLimit(); /// - /// Maximum size of a burst of packets (in bits) + /// Maximum size of a burst of packets (in kbits) /// uint64_t getBurstLimit() const; void setBurstLimit(uint64_t value); diff --git a/src/services/pcn-policer/src/serializer/DefaultContractUpdateDataInputJsonObject.h b/src/services/pcn-policer/src/serializer/DefaultContractUpdateDataInputJsonObject.h index 2cd3ef743..f388679c6 100644 --- a/src/services/pcn-policer/src/serializer/DefaultContractUpdateDataInputJsonObject.h +++ b/src/services/pcn-policer/src/serializer/DefaultContractUpdateDataInputJsonObject.h @@ -53,7 +53,7 @@ class DefaultContractUpdateDataInputJsonObject : public JsonObjectBase { static ActionTypeEnum string_to_ActionTypeEnum(const std::string &str); /// - /// Maximum average traffic rate (in bps) + /// Maximum average traffic rate (in kbit/s) /// uint64_t getRateLimit() const; void setRateLimit(uint64_t value); @@ -61,7 +61,7 @@ class DefaultContractUpdateDataInputJsonObject : public JsonObjectBase { void unsetRateLimit(); /// - /// Maximum size of a burst of packets (in bits) + /// Maximum size of a burst of packets (in kbits) /// uint64_t getBurstLimit() const; void setBurstLimit(uint64_t value); From 0dc44c4a25c9e625b42daa0fa73a87aff5e84c81 Mon Sep 17 00:00:00 2001 From: FedeParola Date: Fri, 19 Jun 2020 11:57:01 +0200 Subject: [PATCH 11/12] Use sleep_until() to update clock --- src/services/pcn-policer/src/Policer.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/services/pcn-policer/src/Policer.cpp b/src/services/pcn-policer/src/Policer.cpp index 3c3dc631c..9964f0dfc 100644 --- a/src/services/pcn-policer/src/Policer.cpp +++ b/src/services/pcn-policer/src/Policer.cpp @@ -140,14 +140,14 @@ void Policer::delContractList() { } void Policer::updateClock() { + uint64_t clock = 0; + auto begin = std::chrono::system_clock::now(); + while (!quit_thread_) { - std::chrono::milliseconds ms = - std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()); - uint64_t count = ms.count(); auto clock_table = get_percpuarray_table("clock"); - clock_table.set(0, count); + clock_table.set(0, clock); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + clock++; + std::this_thread::sleep_until(begin + std::chrono::milliseconds(clock)); } } \ No newline at end of file From 82ff0ad3c9cb4b7e5f862cf4e42d18ac41bb6755 Mon Sep 17 00:00:00 2001 From: FedeParola Date: Fri, 19 Jun 2020 15:14:33 +0200 Subject: [PATCH 12/12] Set ROUTING_TABLE_DIM to 100000 --- src/services/pcn-router/src/Router_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/pcn-router/src/Router_dp.c b/src/services/pcn-router/src/Router_dp.c index 150ce5834..0be6de5a8 100644 --- a/src/services/pcn-router/src/Router_dp.c +++ b/src/services/pcn-router/src/Router_dp.c @@ -28,7 +28,7 @@ #include #define CHECK_MAC_DST -#define ROUTING_TABLE_DIM 256 +#define ROUTING_TABLE_DIM 100000 #define ROUTER_PORT_N 32 #define ARP_TABLE_DIM 32 #define MAX_SECONDARY_ADDRESSES 5 // also defined in Ports.h