Commit 3313d4e2 authored by Franck Messaoudi's avatar Franck Messaoudi

Update: update code to manage separately the tc bpf program

parent 694fc287
...@@ -115,9 +115,6 @@ void my_app_signal_handler(int s) { ...@@ -115,9 +115,6 @@ void my_app_signal_handler(int s) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void setup_bpf() { void setup_bpf() {
// std::shared_ptr<RulesUtilities> mpRulesFactory;
// mpRulesFactory = std::make_shared<RulesUtilitiesImpl>();
std::string sGTPInterface = N3_IF_NAME; std::string sGTPInterface = N3_IF_NAME;
std::string sUDPInterface = N6_IF_NAME; std::string sUDPInterface = N6_IF_NAME;
Logger::upf_app().info("GTP interface: %s", sGTPInterface.c_str()); Logger::upf_app().info("GTP interface: %s", sGTPInterface.c_str());
...@@ -134,6 +131,8 @@ int main(int argc, char** argv) { ...@@ -134,6 +131,8 @@ int main(int argc, char** argv) {
return 1; return 1;
} }
const bool isBpfAccelerationEnabled = upf_cfg.enable_bpf_datapath;
// Logger // Logger
// Config // Config
std::string conf_file_name = Options::getlibconfigConfig(); std::string conf_file_name = Options::getlibconfigConfig();
...@@ -208,7 +207,7 @@ int main(int argc, char** argv) { ...@@ -208,7 +207,7 @@ int main(int argc, char** argv) {
fflush(fp); fflush(fp);
fclose(fp); fclose(fp);
if (upf_cfg.enable_bpf_datapath) { if (isBpfAccelerationEnabled) {
setup_bpf(); setup_bpf();
} }
// once all udp servers initialized // once all udp servers initialized
......
...@@ -144,7 +144,8 @@ void SessionManager::processPDRs( ...@@ -144,7 +144,8 @@ void SessionManager::processPDRs(
const bool is_qos_enabled = upf_cfg.enable_bpf_datapath && upf_cfg.enable_qos; const bool is_qos_enabled = upf_cfg.enable_bpf_datapath && upf_cfg.enable_qos;
// Helper function to find QER by ID // Helper function to find QER by ID
auto find_qer_by_id = [&](uint64_t qer_id) -> std::shared_ptr<pfcp::pfcp_qer> { auto find_qer_by_id =
[&](uint64_t qer_id) -> std::shared_ptr<pfcp::pfcp_qer> {
for (auto& qer : pSession_establishment->qers) { for (auto& qer : pSession_establishment->qers) {
if (qer->qer_id.second.qer_id == qer_id) { if (qer->qer_id.second.qer_id == qer_id) {
return qer; return qer;
...@@ -235,24 +236,24 @@ void SessionManager::prepareEbpfSession( ...@@ -235,24 +236,24 @@ void SessionManager::prepareEbpfSession(
pfcp::pdi pdi; pfcp::pdi pdi;
pfcp::source_interface_t sourceInterface; pfcp::source_interface_t sourceInterface;
if (!(pdrHighPrecedence->get(pdi) && pdi.get(sourceInterface))){ if (!(pdrHighPrecedence->get(pdi) && pdi.get(sourceInterface))) {
throw std::runtime_error( throw std::runtime_error(
"Missing Mandatory IE (PDI or Source Interface) within PDR: " + "Missing Mandatory IE (PDI or Source Interface) within PDR: " +
std::to_string(pdrHighPrecedence->pdr_id.rule_id)); std::to_string(pdrHighPrecedence->pdr_id.rule_id));
} }
logger.debug( logger.debug(
"The PDR %d has the Highest Precedence", "The PDR %d has the Highest Precedence",
pdrHighPrecedence->pdr_id.rule_id); pdrHighPrecedence->pdr_id.rule_id);
processPDRDetails(pSession_establishment,pdrHighPrecedence); processPDRDetails(pSession_establishment, pdrHighPrecedence);
} }
//--------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------
void SessionManager::processPDRDetails( void SessionManager::processPDRDetails(
std::shared_ptr<pfcp::pfcp_session> pSession, std::shared_ptr<pfcp::pfcp_session> pSession,
std::shared_ptr<pfcp::pfcp_pdr> pdrHighPrecedence) { std::shared_ptr<pfcp::pfcp_pdr> pdrHighPrecedence) {
auto& logger = Logger::upf_app(); auto& logger = Logger::upf_app();
const bool is_qos_enabled = upf_cfg.enable_bpf_datapath && upf_cfg.enable_qos; const bool is_qos_enabled = upf_cfg.enable_bpf_datapath && upf_cfg.enable_qos;
pfcp::pdi pdi; pfcp::pdi pdi;
...@@ -271,38 +272,44 @@ void SessionManager::processPDRDetails( ...@@ -271,38 +272,44 @@ void SessionManager::processPDRDetails(
int interfaceValue = sourceInterface.interface_value; int interfaceValue = sourceInterface.interface_value;
switch (interfaceValue) { switch (interfaceValue) {
case INTERFACE_VALUE_CORE:{ case INTERFACE_VALUE_CORE: {
direction = Direction::Uplink; direction = Direction::Uplink;
logger.debug("Create the eBPF Uplink Datapath for Session %lu", pSession->get_up_seid()); logger.debug(
"Create the eBPF Uplink Datapath for Session %lu",
pSession->get_up_seid());
break; break;
} }
case INTERFACE_VALUE_ACCESS:{ case INTERFACE_VALUE_ACCESS: {
direction = Direction::Downlink; direction = Direction::Downlink;
logger.debug("Create the eBPF Downlink Datapath for Session %lu", pSession->get_up_seid()); logger.debug(
"Create the eBPF Downlink Datapath for Session %lu",
pSession->get_up_seid());
break; break;
} }
default:{ default: {
Logger::upf_app().warn("Unknown interface value: %d", interfaceValue); Logger::upf_app().warn("Unknown interface value: %d", interfaceValue);
break; break;
} }
} }
// Check for missing FTEID // Check for missing FTEID
if (!pdi.get(fteid)) { if (!pdi.get(fteid)) {
fteid.teid = -1; fteid.teid = -1;
logger.warn( logger.warn(
"FTEID is missing for the current PDR. " "FTEID is missing for the current PDR. "
"Note: This IE should not be present if the Traffic Endpoint ID is present. " "Note: This IE should not be present if the Traffic Endpoint ID is "
"If the CHOOSE (CH) bit is set to 1, the UP function is expected to assign " "present. "
"If the CHOOSE (CH) bit is set to 1, the UP function is expected to "
"assign "
"a local F-TEID to the PDR."); "a local F-TEID to the PDR.");
if (fteid.ch) { if (fteid.ch) {
logger.debug("CHOOSE (CH) bit is set in FTEID."); logger.debug("CHOOSE (CH) bit is set in FTEID.");
} else { } else {
logger.debug("CHOOSE (CH) bit is not set in FTEID."); logger.debug("CHOOSE (CH) bit is not set in FTEID.");
} }
} }
...@@ -312,14 +319,15 @@ void SessionManager::processPDRDetails( ...@@ -312,14 +319,15 @@ void SessionManager::processPDRDetails(
logger.warn( logger.warn(
"UE IP Address is missing for the current PDR. " "UE IP Address is missing for the current PDR. "
"Note: This IE should not be present if the Traffic Endpoint ID is present."); "Note: This IE should not be present if the Traffic Endpoint ID is "
"present.");
} }
// Log PDI extraction details // Log PDI extraction details
logger.debug("PDI successfully extracted from PDR ID: %d.", pdr_id); logger.debug("PDI successfully extracted from PDR ID: %d.", pdr_id);
logger.debug( logger.debug(
"Extracting FAR from the highest precedence PDR ID: %d.", pdr_id); "Extracting FAR from the highest precedence PDR ID: %d.", pdr_id);
std::shared_ptr<pfcp::pfcp_far> pFar; std::shared_ptr<pfcp::pfcp_far> pFar;
if (!extractFar(pdrHighPrecedence, pSession, pFar)) { if (!extractFar(pdrHighPrecedence, pSession, pFar)) {
...@@ -334,18 +342,26 @@ void SessionManager::processPDRDetails( ...@@ -334,18 +342,26 @@ void SessionManager::processPDRDetails(
std::vector<std::shared_ptr<pfcp::pfcp_qer>> pQer; std::vector<std::shared_ptr<pfcp::pfcp_qer>> pQer;
/*
* TODO: implement the QoS Enforcement on the uplink side
if (is_qos_enabled) { if (is_qos_enabled) {
pQer = (direction == Direction::Uplink) ? pSession->qers_uplink : pQer = (direction == Direction::Uplink) ? pSession->qers_uplink :
pSession->qers_downlink; std::vector<std::shared_ptr<pfcp::pfcp_qer>>{};
}
SessionProgramManager::getInstance().createPipeline( SessionProgramManager::getInstance().createPipeline(
pSession->get_up_seid(), fteid.teid, interfaceValue, pSession->get_up_seid(), fteid.teid, interfaceValue,
ueIpAddress.ipv4_address.s_addr, pFar, pQer, false, 0); ueIpAddress.ipv4_address.s_addr, pFar, pQer, false, 0);
} else{ */
SessionProgramManager::getInstance().createPipeline(
pSession->get_up_seid(), fteid.teid, interfaceValue, if (is_qos_enabled) {
ueIpAddress.ipv4_address.s_addr, pFar, false, 0); pQer = (direction == Direction::Downlink) ?
} pSession->qers_downlink :
std::vector<std::shared_ptr<pfcp::pfcp_qer>>{};
}
SessionProgramManager::getInstance().createPipeline(
pSession->get_up_seid(), fteid.teid, interfaceValue,
ueIpAddress.ipv4_address.s_addr, pFar, pQer, false, 0);
} }
//--------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------
......
...@@ -196,30 +196,30 @@ void SessionProgramManager::storeSessionMappingMap( ...@@ -196,30 +196,30 @@ void SessionProgramManager::storeSessionMappingMap(
void SessionProgramManager::updateARPTableForN6( void SessionProgramManager::updateARPTableForN6(
std::shared_ptr<PFCP_Session_LookupProgram> pPFCP_Session_LookupProgram, std::shared_ptr<PFCP_Session_LookupProgram> pPFCP_Session_LookupProgram,
uint32_t dnIP, uint32_t upfn6IP) { uint32_t dnIP, uint32_t upfn6IP) {
try { try {
std::string remoteDN = "192.168.24.160"; std::string remoteDN = "192.168.24.160";
uint32_t remoteN6IPv4 = inet_addr(remoteDN.c_str()); uint32_t remoteN6IPv4 = inet_addr(remoteDN.c_str());
// const char* remoteN6MAC = "0061BB000001"; // const char* remoteN6MAC = "0061BB000001";
uint8_t remoteN6MAC[6] = {0x00, 0x61, 0xbb, 0x00, 0x00, 0x01}; uint8_t remoteN6MAC[6] = {0x00, 0x61, 0xbb, 0x00, 0x00, 0x01};
Logger::upf_app().warn(
"updateARPTableForN6 is modified with hard values to test with "
"Trex! I dont understand why the execution goes through the "
"exception!"
"Need to check and debug");
struct s_arp_mapping map_table;
memset(&map_table, 0, sizeof(struct s_arp_mapping));
memcpy(map_table.mac_address, remoteN6MAC, 6);
map_table.ipv4_address = remoteN6IPv4;
pPFCP_Session_LookupProgram->getArpTableMap()->update( Logger::upf_app().warn(
upfn6IP, map_table, BPF_ANY); "updateARPTableForN6 is modified with hard values to test with "
} catch (const std::exception& ex) { "Trex! I dont understand why the execution goes through the "
Logger::upf_app().error( "exception!"
"Error: The ARP table was not updated for N6 Next HOP"); "Need to check and debug");
}
} struct s_arp_mapping map_table;
memset(&map_table, 0, sizeof(struct s_arp_mapping));
memcpy(map_table.mac_address, remoteN6MAC, 6);
map_table.ipv4_address = remoteN6IPv4;
pPFCP_Session_LookupProgram->getArpTableMap()->update(
upfn6IP, map_table, BPF_ANY);
} catch (const std::exception& ex) {
Logger::upf_app().error(
"Error: The ARP table was not updated for N6 Next HOP");
}
}
/* /*
void SessionProgramManager::updateARPTableForN6( void SessionProgramManager::updateARPTableForN6(
...@@ -272,8 +272,7 @@ void SessionProgramManager::updateARPTableForN3( ...@@ -272,8 +272,7 @@ void SessionProgramManager::updateARPTableForN3(
for (auto it = pfcpPrograms->begin(); it != pfcpPrograms->end(); ++it) { for (auto it = pfcpPrograms->begin(); it != pfcpPrograms->end(); ++it) {
// Access the members of the 'farprograms' struct // Access the members of the 'farprograms' struct
uint64_t savedSeid = it->seid; uint64_t savedSeid = it->seid;
std::shared_ptr<PFCP_Session_LookupProgram> pPFCP_Session_LookupProgram std::shared_ptr<PFCP_Session_LookupProgram> pPFCP_Session_LookupProgram =
=
it->pPFCP_Session_LookupProgram; it->pPFCP_Session_LookupProgram;
if (savedSeid == seid) { if (savedSeid == seid) {
...@@ -311,7 +310,8 @@ void SessionProgramManager::updateARPTableForN3( ...@@ -311,7 +310,8 @@ void SessionProgramManager::updateARPTableForN3(
// for (auto it = pfcpPrograms->begin(); it != pfcpPrograms->end(); ++it) { // for (auto it = pfcpPrograms->begin(); it != pfcpPrograms->end(); ++it) {
// // Access the members of the 'farprograms' struct // // Access the members of the 'farprograms' struct
// uint64_t savedSeid = it->seid; // uint64_t savedSeid = it->seid;
// std::shared_ptr<PFCP_Session_LookupProgram> pPFCP_Session_LookupProgram = // std::shared_ptr<PFCP_Session_LookupProgram> pPFCP_Session_LookupProgram
// =
// it->pPFCP_Session_LookupProgram; // it->pPFCP_Session_LookupProgram;
// if (savedSeid == seid) { // if (savedSeid == seid) {
...@@ -366,15 +366,27 @@ void SessionProgramManager::createPipeline( ...@@ -366,15 +366,27 @@ void SessionProgramManager::createPipeline(
uint32_t ueIpAddress, std::shared_ptr<pfcp::pfcp_far> pFar, uint32_t ueIpAddress, std::shared_ptr<pfcp::pfcp_far> pFar,
std::vector<std::shared_ptr<pfcp::pfcp_qer>> pQer, bool isModification, std::vector<std::shared_ptr<pfcp::pfcp_qer>> pQer, bool isModification,
uint32_t teid2) { uint32_t teid2) {
uint32_t dnIP = upf_cfg.remote_n6.s_addr; uint32_t dnIP = upf_cfg.remote_n6.s_addr;
uint32_t upfn3IP = upf_cfg.n3.addr4.s_addr; uint32_t upfn3IP = upf_cfg.n3.addr4.s_addr;
uint32_t upfn6IP = upf_cfg.n6.addr4.s_addr; uint32_t upfn6IP = upf_cfg.n6.addr4.s_addr;
uint32_t far_id = pFar->far_id.far_id; uint32_t far_id = pFar->far_id.far_id;
next_rule_prog_index_key key; next_rule_prog_index_key key;
initializeNextRuleProgIndexKey(key, teid1, ueIpAddress, sourceInterface); initializeNextRuleProgIndexKey(key, teid1, ueIpAddress, sourceInterface);
bool enforcing_qos = !pQer.empty();
const bool isBpfAccelerationEnabled = upf_cfg.enable_bpf_datapath;
const bool isQosEnabled = isBpfAccelerationEnabled && upf_cfg.enable_qos;
/*======================================================================================*/
if (isQosEnabled && enforcing_qos) {
Logger::upf_app().debug("Instantiate a new QERProgram ");
std::shared_ptr<QERProgram> pQERProgram = std::make_shared<QERProgram>();
pQERProgram->setup(seid, pQer);
}
/*======================================================================================*/
auto pPFCP_Session_LookupProgram = auto pPFCP_Session_LookupProgram =
UserPlaneComponent::getInstance().getPFCP_Session_LookupProgram(); UserPlaneComponent::getInstance().getPFCP_Session_LookupProgram();
...@@ -414,12 +426,9 @@ void SessionProgramManager::createPipeline( ...@@ -414,12 +426,9 @@ void SessionProgramManager::createPipeline(
void SessionProgramManager::removePipeline(uint64_t seid) { void SessionProgramManager::removePipeline(uint64_t seid) {
Logger::upf_app().debug("Remove FARProgram index from UPFProgram map"); Logger::upf_app().debug("Remove FARProgram index from UPFProgram map");
auto it = mSessionProgramsMap.find(seid); auto it = mSessionProgramsMap.find(seid);
if (it == mSessionProgramsMap.end()) { if (it == mSessionProgramsMap.end()) {
Logger::upf_app().error( Logger::upf_app().error("Session with SEID: %lu Does Not Exist", seid);
"Session %d Does Not Exist. It Cannot be Removed", seid);
// throw std::runtime_error("Session does Not Exist. It Cannot be
// Removed");
} }
Logger::upf_app().debug( Logger::upf_app().debug(
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
class BPFMap; class BPFMap;
class OnStateChangeSessionProgramObserver; class OnStateChangeSessionProgramObserver;
class PFCP_Session_LookupProgram; class PFCP_Session_LookupProgram;
// class PFCP_Session_PDR_LookupProgram;
class SessionPrograms; class SessionPrograms;
class FARProgram; class FARProgram;
...@@ -112,11 +111,6 @@ class SessionProgramManager { ...@@ -112,11 +111,6 @@ class SessionProgramManager {
bool isModification = false, uint32_t teid2 = 0); bool isModification = false, uint32_t teid2 = 0);
/*---------------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------------*/
void createPipeline(
uint64_t seid, uint32_t teid1, uint8_t sourceInterface,
uint32_t ueIpAddress, std::shared_ptr<pfcp::pfcp_far> pFar,
bool isModification = false, uint32_t teid2 = 0);
/*---------------------------------------------------------------------------------------------------------------*/
void initializeNextRuleProgIndexKey( void initializeNextRuleProgIndexKey(
next_rule_prog_index_key& key, uint32_t teid, uint32_t ueIpAddress, next_rule_prog_index_key& key, uint32_t teid, uint32_t ueIpAddress,
uint8_t sourceInterface); uint8_t sourceInterface);
......
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
#include <next_prog_rule_key.h> #include <next_prog_rule_key.h>
/** /**
* @brief This class represents the datapath path. It stores the program related * @brief This class represents the Data-Path path. It stores the program
* to a PFCP session. For each session, there might be a QERProgram. The * related to a PFCP session. For each session, there might be a QERProgram. The
* FARProgram is mandatory. * FARProgram is mandatory.
* *
*/ */
......
#include "UserPlaneComponent.h" #include "UserPlaneComponent.h"
#include <SessionManager.h> #include <SessionManager.h>
//#include <pfcp_session_pdr_lookup_xdp_user.h>
#include <SessionProgramManager.h> #include <SessionProgramManager.h>
#include <SignalHandler.h> #include <SignalHandler.h>
#include <pfcp_session_lookup_xdp_user.h> #include <pfcp_session_lookup_xdp_user.h>
#include "logger.hpp" #include "logger.hpp"
#include <helpers/GetNicInformation.hpp> #include <helpers/GetNicInformation.hpp>
#include "upf_config.hpp"
using namespace oai::config;
extern upf_config upf_cfg;
//--------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------
UserPlaneComponent::UserPlaneComponent() { UserPlaneComponent::UserPlaneComponent() {
// Set new handlers for libbpf. // Set new handlers for libbpf.
...@@ -82,9 +85,12 @@ void UserPlaneComponent::setMembers( ...@@ -82,9 +85,12 @@ void UserPlaneComponent::setMembers(
//--------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------
void UserPlaneComponent::setup( void UserPlaneComponent::setup(
const std::string& gtpInterface, const std::string& udpInterface) { const std::string& gtpInterface, const std::string& udpInterface) {
const bool isQosEnabled = upf_cfg.enable_qos;
setMembers(gtpInterface, udpInterface); setMembers(gtpInterface, udpInterface);
SignalHandler::getInstance().enable(); SignalHandler::getInstance().enable();
mpPFCP_Session_LookupProgram->setup();
mpPFCP_Session_LookupProgram->setup(isQosEnabled);
// Pass maps to sessionManager. // Pass maps to sessionManager.
mpSessionManager = std::make_shared<SessionManager>(); mpSessionManager = std::make_shared<SessionManager>();
......
...@@ -6,17 +6,18 @@ ...@@ -6,17 +6,18 @@
#include <linux/bpf.h> #include <linux/bpf.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
//#define UDP_CSUM_OFFSET (sizeof(struct ethhdr) + offsetof(struct udphdr, check)) //#define UDP_CSUM_OFFSET (sizeof(struct ethhdr) + offsetof(struct udphdr,
//check))
// static u32 udp_handle( // static u32 udp_handle(
// struct xdp_md* ctx, struct udphdr* udph, u32 src_ip, u32 dest_ip); // struct xdp_md* ctx, struct udphdr* udph, u32 src_ip, u32 dest_ip);
// static u32 udp_handle( // static u32 udp_handle(
// struct xdp_md* ctx, struct udphdr* udph, u32 dest_ip); // struct xdp_md* ctx, struct udphdr* udph, u32 dest_ip);
static u32 udp_handle( // static u32 udp_handle(
struct xdp_md* p_ctx, struct udphdr* udph, u32 src_ip, u32 dest_ip, // struct xdp_md* p_ctx, struct udphdr* udph, u32 src_ip, u32 dest_ip,
u8 dscp); // u8 dscp);
static u32 handle_uplink_traffic(struct xdp_md* p_ctx, struct udphdr* udph); // static u32 handle_uplink_traffic(struct xdp_md* p_ctx, struct udphdr* udph);
#endif // PROTOCOLS_UDP_H #endif // PROTOCOLS_UDP_H
...@@ -37,12 +37,12 @@ struct { ...@@ -37,12 +37,12 @@ struct {
} m_arp_table SEC(".maps"); } m_arp_table SEC(".maps");
/*---------------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------------*/
struct { // struct {
__uint(type, BPF_MAP_TYPE_HASH); // __uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, MAX_FAR_PROGRAMS); // __uint(max_entries, MAX_FAR_PROGRAMS);
__type(key, u32); // __type(key, u32);
__type(value, u32); // __type(value, u32);
} m_enforcing_qos SEC(".maps"); // } m_enforcing_qos SEC(".maps");
/*---------------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------------*/
......
...@@ -57,7 +57,6 @@ struct vlan_hdr { ...@@ -57,7 +57,6 @@ struct vlan_hdr {
static u32 upf_n3_ip = 0; static u32 upf_n3_ip = 0;
static u32 upf_n6_ip = 0; static u32 upf_n6_ip = 0;
static u32 ue_ip = 0;
static u8 next_hop_n3_mac_address[6] = {0}; static u8 next_hop_n3_mac_address[6] = {0};
static u8 next_hop_n6_mac_address[6] = {0}; static u8 next_hop_n6_mac_address[6] = {0};
...@@ -259,69 +258,69 @@ create_outer_header_gtpu_ipv4(struct xdp_md* ctx, pfcp_far_t_* p_far) { ...@@ -259,69 +258,69 @@ create_outer_header_gtpu_ipv4(struct xdp_md* ctx, pfcp_far_t_* p_far) {
/*---------------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------------*/
SEC("xdp") SEC("xdp")
int xdp_handle_uplink(struct xdp_md* ctx) { int xdp_handle_uplink(struct xdp_md* ctx) {
bpf_debug("================< PFCP PDR Sesction: Handle Uplink >================"); bpf_debug("================< XDP: Handle Uplink >================");
void* data = (void*) (long) ctx->data; void* data = (void*) (long) ctx->data;
void* data_end = (void*) (long) ctx->data_end; void* data_end = (void*) (long) ctx->data_end;
struct ethhdr* ethh = (void*) (long) ctx->data; struct ethhdr* ethh = (void*) (long) ctx->data;
u16 eth_type = bpf_htons(ethh->h_proto);
u64 offset = sizeof(*ethh);
if ((void*) (ethh + 1) > (void*) (long) ctx->data_end) { if ((void*) (ethh + 1) > (void*) (long) ctx->data_end) {
bpf_debug("Invalid Ethernet header"); bpf_debug("Error: Invalid Ethernet header");
return XDP_DROP; return XDP_DROP;
} }
u16 eth_type = bpf_htons(ethh->h_proto);
bpf_debug("Debug: eth_type:0x%x", eth_type); bpf_debug("Debug: eth_type:0x%x", eth_type);
switch (eth_type) { switch (eth_type) {
case ETH_P_IP: { case ETH_P_IP: {
struct iphdr* iph = (struct iphdr*) ((void*) ethh + offset); struct iphdr* iph = (struct iphdr*) ((void*) ethh + sizeof(*ethh));
if ((void*) (iph + 1) > data_end) { if ((void*) (iph + 1) > data_end) {
bpf_debug("Invalid IPv4 Packet"); bpf_debug("Error: Invalid IPv4 Packet");
return XDP_DROP; return XDP_DROP;
} }
struct udphdr* udph = (struct udphdr*) (iph + 1); struct udphdr* udph = (struct udphdr*) (iph + 1);
if ((void*) (udph + 1) > data_end) { if ((void*) (udph + 1) > data_end) {
bpf_debug("Invalid UDP packet"); bpf_debug("Error: Invalid UDP packet");
return XDP_DROP; return XDP_DROP;
} }
if (bpf_htons(udph->dest) == GTP_UDP_PORT) { if (bpf_htons(udph->dest) == GTP_UDP_PORT) {
bpf_debug("This is a GTP traffic"); bpf_debug("Identified GTP Traffic");
struct gtpuhdr* gtpuh = (struct gtpuhdr*) (udph + 1); struct gtpuhdr* gtpuh = (struct gtpuhdr*) (udph + 1);
// Check if the GTP header extends beyond the data end.
if ((void*) gtpuh + sizeof(*gtpuh) > data_end) { if ((void*) gtpuh + sizeof(*gtpuh) > data_end) {
bpf_debug("Invalid GTPU packet"); bpf_debug("Error: Invalid GTP-U packet");
return XDP_DROP; return XDP_DROP;
} }
if (gtpuh->message_type != GTPU_G_PDU) {
bpf_debug(
"Message type 0x%x is not GTPU GPDU(0x%x)\n", gtpuh->message_type,
GTPU_G_PDU);
return XDP_PASS;
}
struct ethhdr* ethh_new = data + GTP_ENCAPSULATED_SIZE; struct ethhdr* ethh_new = data + GTP_ENCAPSULATED_SIZE;
if ((void*) ethh_new + sizeof(*ethh_new) > data_end) { if ((void*) ethh_new + sizeof(*ethh_new) > data_end) {
bpf_debug("Invalid Ethernet packet"); bpf_debug("Error: Invalid encapsulated Ethernet packet");
return XDP_DROP; return XDP_DROP;
} }
struct iphdr* iph_inner = (void*) (ethh_new + 1); struct iphdr* iph_inner = (void*) (ethh_new + 1);
if ((void*) iph_inner + sizeof(*iph_inner) > data_end) { if ((void*) iph_inner + sizeof(*iph_inner) > data_end) {
bpf_debug("Invalid Inner IP packet"); bpf_debug("Error: Invalid Inner IP packet");
return XDP_DROP; return XDP_DROP;
} }
u32 src_ip_in = bpf_htonl(iph_inner->saddr); u32 src_ip_in = bpf_htonl(iph_inner->saddr);
if (gtpuh->message_type != GTPU_G_PDU) {
bpf_debug(
"Message type 0x%x is not GTPU GPDU(0x%x)\n", gtpuh->message_type,
GTPU_G_PDU);
return XDP_PASS;
}
struct next_rule_prog_index_key map_key = {0}; struct next_rule_prog_index_key map_key = {0};
map_key.teid = gtpuh->teid; map_key.teid = gtpuh->teid;
map_key.source_value = INTERFACE_VALUE_ACCESS; map_key.source_value = INTERFACE_VALUE_ACCESS;
...@@ -332,19 +331,17 @@ int xdp_handle_uplink(struct xdp_md* ctx) { ...@@ -332,19 +331,17 @@ int xdp_handle_uplink(struct xdp_md* ctx) {
if (p_far) { if (p_far) {
bpf_debug("FAR ID = %d", p_far->far_id.far_id); bpf_debug("FAR ID = %d", p_far->far_id.far_id);
u8 dest_interface = p_far->forwarding_parameters.destination_interface // u8 dest_interface = p_far->forwarding_parameters.destination_interface.interface_value;
.interface_value;
if (!p_far->apply_action.forw) { if (!p_far->apply_action.forw) {
bpf_debug("Forward Action Is NOT set"); bpf_debug("Forward Action Is NOT set");
return XDP_PASS; return XDP_PASS;
} }
bpf_debug("GTP Header Removal ..."); bpf_debug("GTP Header Removal in Progress");
__builtin_memcpy(ethh_new, ethh, sizeof(*ethh)); __builtin_memcpy(ethh_new, ethh, sizeof(*ethh));
// Retrieve the N6 Interface IP address:
e_reference_point n6_key = N6_INTERFACE; e_reference_point n6_key = N6_INTERFACE;
if (!cached_n6) { if (!cached_n6) {
...@@ -378,6 +375,7 @@ int xdp_handle_uplink(struct xdp_md* ctx) { ...@@ -378,6 +375,7 @@ int xdp_handle_uplink(struct xdp_md* ctx) {
sizeof(ethh_new->h_dest)); sizeof(ethh_new->h_dest));
// Adjust head to the right. // Adjust head to the right.
if (bpf_xdp_adjust_head(ctx, GTP_ENCAPSULATED_SIZE)) { if (bpf_xdp_adjust_head(ctx, GTP_ENCAPSULATED_SIZE)) {
bpf_debug("Error: Adjusting packet head failed");
return XDP_DROP; return XDP_DROP;
} }
...@@ -385,7 +383,7 @@ int xdp_handle_uplink(struct xdp_md* ctx) { ...@@ -385,7 +383,7 @@ int xdp_handle_uplink(struct xdp_md* ctx) {
// ethh_new->h_dest[1], ethh_new->h_dest[2]); bpf_debug(" %x:%x:%x", // ethh_new->h_dest[1], ethh_new->h_dest[2]); bpf_debug(" %x:%x:%x",
// ethh_new->h_dest[3], ethh_new->h_dest[4], ethh_new->h_dest[5]); // ethh_new->h_dest[3], ethh_new->h_dest[4], ethh_new->h_dest[5]);
bpf_debug("The Packet is redirected for transmission to DN ..."); bpf_debug("Redirecting Packet to DN");
return bpf_redirect_map(&m_redirect_interfaces, UPLINK, 0); return bpf_redirect_map(&m_redirect_interfaces, UPLINK, 0);
...@@ -396,7 +394,7 @@ int xdp_handle_uplink(struct xdp_md* ctx) { ...@@ -396,7 +394,7 @@ int xdp_handle_uplink(struct xdp_md* ctx) {
} }
} }
default: { default: {
bpf_debug("Cannot parse L2: L3off:%llu proto:0x%x", offset, eth_type); bpf_debug("Unsupported protocol: 0x%x", eth_type);
return XDP_PASS; return XDP_PASS;
} }
} }
...@@ -405,32 +403,32 @@ int xdp_handle_uplink(struct xdp_md* ctx) { ...@@ -405,32 +403,32 @@ int xdp_handle_uplink(struct xdp_md* ctx) {
/*---------------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------------*/
SEC("xdp") SEC("xdp")
int xdp_handle_downlink(struct xdp_md* ctx) { int xdp_handle_downlink(struct xdp_md* ctx) {
bpf_debug("================< PFCP PDR Sesction: Handle Downlink >================"); bpf_debug("================< XDP: Handle Downlink >================");
void* data_end = (void*) (long) ctx->data_end; void* data_end = (void*) (long) ctx->data_end;
struct ethhdr* ethh = (void*) (long) ctx->data; struct ethhdr* ethh = (void*) (long) ctx->data;
u64 offset = sizeof(*ethh);
if ((void*) (ethh + 1) > (void*) (long) ctx->data_end) { if ((void*) (ethh + 1) > (void*) (long) ctx->data_end) {
bpf_debug("Invalid Ethernet header"); bpf_debug("Error: Invalid Ethernet header");
return XDP_DROP; return XDP_DROP;
} }
struct iphdr* iph = (struct iphdr*) ((void*) ethh + offset); struct iphdr* iph = (struct iphdr*) ((void*) ethh + sizeof(*ethh));
if ((void*) (iph + 1) > data_end) { if ((void*) (iph + 1) > data_end) {
bpf_debug("Invalid IPv4 Packet"); bpf_debug("Error: Invalid IPv4 Packet");
return XDP_DROP; return XDP_DROP;
} }
u32 ip_dest = bpf_htonl(iph->daddr); u32 ip_dest = bpf_htonl(iph->daddr);
struct session_id* session = struct session_id* session =
bpf_map_lookup_elem(&m_session_mapping, &ip_dest); bpf_map_lookup_elem(&m_session_mapping, &ip_dest);
// u32* teid_dl = bpf_map_lookup_elem(&m_session_mapping, &ip_dest);
if (session) { if (session) {
u32 teid_dl = session->teid_dl; u32 teid_dl = session->teid_dl;
bpf_debug( bpf_debug(
"TEID downlink: 0x%x was found for UE IP: 0x%x", teid_dl, ip_dest); "TEID for downlink: 0x%x, UE IP: 0x%x", teid_dl, ip_dest);
struct next_rule_prog_index_key map_key = {0}; struct next_rule_prog_index_key map_key = {0};
map_key.teid = teid_dl; map_key.teid = teid_dl;
map_key.source_value = INTERFACE_VALUE_CORE; map_key.source_value = INTERFACE_VALUE_CORE;
...@@ -446,6 +444,55 @@ int xdp_handle_downlink(struct xdp_md* ctx) { ...@@ -446,6 +444,55 @@ int xdp_handle_downlink(struct xdp_md* ctx) {
} }
} }
bpf_debug("Session not found for Downlink, tail call failed");
return XDP_PASS;
}
/*---------------------------------------------------------------------------------------------------------------*/
SEC("xdp")
int xdp_handle_shaping(struct xdp_md* ctx) {
bpf_debug("================< XDP: Handle Shaping >================");
void* data_end = (void*) (long) ctx->data_end;
struct ethhdr* ethh = (void*) (long) ctx->data;
if ((void*) (ethh + 1) > (void*) (long) ctx->data_end) {
bpf_debug("Error: Invalid Ethernet header");
return XDP_DROP;
}
struct iphdr* iph = (struct iphdr*) ((void*) ethh + sizeof(*ethh));
if ((void*) (iph + 1) > data_end) {
bpf_debug("Error: Invalid IPv4 Packet");
return XDP_DROP;
}
u32 ip_dest = bpf_htonl(iph->daddr);
struct session_id* session =
bpf_map_lookup_elem(&m_session_mapping, &ip_dest);
if (session) {
u32 teid_dl = session->teid_dl;
bpf_debug(
"TEID downlink: 0x%x was found for UE IP: 0x%x", teid_dl, ip_dest);
struct next_rule_prog_index_key map_key = {0};
map_key.teid = teid_dl;
map_key.source_value = INTERFACE_VALUE_CORE;
map_key.ipv4_address = ip_dest;
pfcp_far_t_* p_far = bpf_map_lookup_elem(&m_next_rule_prog_index, &map_key);
if (p_far) {
bpf_debug("FAR ID = %d", p_far->far_id.far_id);
create_outer_header_gtpu_ipv4(ctx, p_far);
bpf_debug("The packet is passed to tc layer");
return XDP_PASS;
}
}
bpf_debug("BPF tail call was not executed!"); bpf_debug("BPF tail call was not executed!");
return XDP_PASS; return XDP_PASS;
......
...@@ -226,7 +226,7 @@ sdf_filter(struct __sk_buff* skb, struct ethhdr* ethh) { ...@@ -226,7 +226,7 @@ sdf_filter(struct __sk_buff* skb, struct ethhdr* ethh) {
SEC("tc/egress") SEC("tc/egress")
int tc_filter_traffic(struct __sk_buff* skb) { int tc_filter_traffic(struct __sk_buff* skb) {
bpf_debug("==========< QER Rules >==========\n"); bpf_debug("==========< tc/egress: Filter Traffic >==========\n");
// void *data = (void *)(long)skb->data; // void *data = (void *)(long)skb->data;
// void *data_meta = (void *)(long)skb->data_meta; // void *data_meta = (void *)(long)skb->data_meta;
...@@ -265,6 +265,7 @@ int tc_filter_traffic(struct __sk_buff* skb) { ...@@ -265,6 +265,7 @@ int tc_filter_traffic(struct __sk_buff* skb) {
SEC("tc/ingress") SEC("tc/ingress")
int tc_redirect_traffic(struct __sk_buff* skb) { int tc_redirect_traffic(struct __sk_buff* skb) {
bpf_debug("==========< tc/ingress: Redirect Traffic >==========\n");
int key = DOWNLINK, *ifindex; int key = DOWNLINK, *ifindex;
// return bpf_redirect_map(&m_redirect_interfaces, DOWNLINK, 0); // return bpf_redirect_map(&m_redirect_interfaces, DOWNLINK, 0);
......
...@@ -4,27 +4,37 @@ ...@@ -4,27 +4,37 @@
#include <types.h> #include <types.h>
/* Use uint8_t*/ // /* Use uint8_t*/
struct s_gate { // struct s_gate {
uint8_t ul_gate; // uint8_t ul_gate;
uint8_t dl_gate; // uint8_t dl_gate;
}; // };
struct s_mbr { // struct s_mbr {
uint64_t ul_mbr; // uint64_t ul_mbr;
uint64_t dl_mbr; // uint64_t dl_mbr;
}; // };
// struct s_gbr {
// uint64_t ul_gbr;
// uint64_t dl_gbr;
// };
// struct s_fiveQosFlow {
// struct s_gate gate;
// struct s_mbr mbr;
// struct s_gbr gbr;
// uint64_t qfi;
// };
struct s_gbr {
uint64_t ul_gbr;
uint64_t dl_gbr;
};
struct s_fiveQosFlow { struct s_fiveQosFlow {
struct s_gate gate; uint8_t gate;
struct s_mbr mbr; uint64_t mbr;
struct s_gbr gbr; uint64_t gbr;
uint64_t qfi; uint8_t qfi;
}; };
#endif //__QOS_FLOW_H__ #endif //__QOS_FLOW_H__
\ No newline at end of file
#ifndef CONFIG_MANAGER_HPP
#define CONFIG_MANAGER_HPP
class ConfigManager {
public:
// Returns the singleton instance
static ConfigManager& getInstance();
// Initializes the configuration
void initialize(bool enableBpfDatapath, bool enableQos);
// Checks if BPF datapath is enabled
bool isBpfDatapathEnabled() const;
// Checks if QoS is enabled
bool isQosEnabled() const;
private:
// Private constructor to prevent instantiation
ConfigManager() = default;
// Deleted copy constructor and assignment operator
ConfigManager(const ConfigManager&) = delete;
ConfigManager& operator=(const ConfigManager&) = delete;
// Configuration variables
bool enable_bpf_datapath = false;
bool enable_qos = false;
};
#endif // CONFIG_MANAGER_HPP
\ No newline at end of file
...@@ -12,6 +12,14 @@ ...@@ -12,6 +12,14 @@
using namespace oai::config; using namespace oai::config;
extern upf_config upf_cfg; extern upf_config upf_cfg;
class XDPSection {
public:
static constexpr const char* Uplink = "xdp_handle_uplink";
static constexpr const char* Downlink = "xdp_handle_downlink";
static constexpr const char* Shaping = "xdp_handle_shaping";
};
/*---------------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------------*/
int is_little_endian2() { int is_little_endian2() {
u32 value = 1; u32 value = 1;
...@@ -73,7 +81,7 @@ void PFCP_Session_LookupProgram::create_upf_interface_map_entry( ...@@ -73,7 +81,7 @@ void PFCP_Session_LookupProgram::create_upf_interface_map_entry(
PFCP_Session_LookupProgram::~PFCP_Session_LookupProgram() {} PFCP_Session_LookupProgram::~PFCP_Session_LookupProgram() {}
/*---------------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------------*/
void PFCP_Session_LookupProgram::setup() { void PFCP_Session_LookupProgram::setup(bool isQosEnabled) {
spSkeleton = mpLifeCycle->open(); spSkeleton = mpLifeCycle->open();
initializeMaps(); initializeMaps();
mpLifeCycle->load(); mpLifeCycle->load();
...@@ -91,7 +99,7 @@ void PFCP_Session_LookupProgram::setup() { ...@@ -91,7 +99,7 @@ void PFCP_Session_LookupProgram::setup() {
mpEgressInterfaceMap->update(uplinkId, udpInterfaceIndex, BPF_ANY); mpEgressInterfaceMap->update(uplinkId, udpInterfaceIndex, BPF_ANY);
mpEgressInterfaceMap->update(downlinkId, gtpInterfaceIndex, BPF_ANY); mpEgressInterfaceMap->update(downlinkId, gtpInterfaceIndex, BPF_ANY);
Logger::upf_app().debug("Adding Reference Points to m_upf_interface Map:"); Logger::upf_app().debug("Adding Reference Points to m_upf_interface Map");
create_upf_interface_map_entry(N3_INTERFACE); create_upf_interface_map_entry(N3_INTERFACE);
create_upf_interface_map_entry(N6_INTERFACE); create_upf_interface_map_entry(N6_INTERFACE);
create_upf_interface_map_entry(N4_INTERFACE); create_upf_interface_map_entry(N4_INTERFACE);
...@@ -103,12 +111,21 @@ void PFCP_Session_LookupProgram::setup() { ...@@ -103,12 +111,21 @@ void PFCP_Session_LookupProgram::setup() {
} }
Logger::upf_app().debug( Logger::upf_app().debug(
"Link Non-GTP interface to interface %s", mUDPInterface.c_str()); "Link GTP XDP Section to interface %s", mGTPInterface.c_str());
mpLifeCycle->link("xdp_handle_downlink", mUDPInterface.c_str()); mpLifeCycle->link(XDPSection::Uplink, mGTPInterface.c_str());
Logger::upf_app().debug( Logger::upf_app().debug(
"Link GTP interface to interface %s", mGTPInterface.c_str()); "Link Non-GTP XDP Section to interface %s", mUDPInterface.c_str());
mpLifeCycle->link("xdp_handle_uplink", mGTPInterface.c_str()); if (isQosEnabled) {
Logger::upf_app().debug(
"QoS enforcement is enabled in the configuration. A TC BPF section is "
"created ");
mpLifeCycle->link(XDPSection::Shaping, mUDPInterface.c_str());
} else {
Logger::upf_app().debug(
"QoS enforcement is disabled in the configuration.");
mpLifeCycle->link(XDPSection::Downlink, mUDPInterface.c_str());
}
} }
/*---------------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------------*/
......
...@@ -42,7 +42,7 @@ class PFCP_Session_LookupProgram { ...@@ -42,7 +42,7 @@ class PFCP_Session_LookupProgram {
* @brief Setup the BPF program. * @brief Setup the BPF program.
* *
*/ */
void setup(); void setup(bool isQosEnabled);
/*---------------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------------*/
/** /**
......
...@@ -54,10 +54,6 @@ ...@@ -54,10 +54,6 @@
#endif // MAX_CEIL #endif // MAX_CEIL
#endif // DEFAULT_CEIL #endif // DEFAULT_CEIL
#ifndef DEFAULT_QFI
#define DEFAULT_QFI 5
#endif // DEFAULT_QFI
#ifndef BUILD_DIRECTORY #ifndef BUILD_DIRECTORY
#define BUILD_DIRECTORY \ #define BUILD_DIRECTORY \
"build/upf/build/upf_app/bpf/CMakeFiles/qer_tc.dir/rules/qer" "build/upf/build/upf_app/bpf/CMakeFiles/qer_tc.dir/rules/qer"
...@@ -86,16 +82,10 @@ void QERProgram::storeQosFlow(std::shared_ptr<pfcp::pfcp_qer> pQer) { ...@@ -86,16 +82,10 @@ void QERProgram::storeQosFlow(std::shared_ptr<pfcp::pfcp_qer> pQer) {
struct s_fiveQosFlow fiveFlow; struct s_fiveQosFlow fiveFlow;
memset(&fiveFlow, 0, sizeof(struct s_fiveQosFlow)); memset(&fiveFlow, 0, sizeof(struct s_fiveQosFlow));
fiveFlow.gate.dl_gate = pQer->gate_status.second.dl_gate; fiveFlow.gate = pQer->gate_status.second.dl_gate;
fiveFlow.gate.ul_gate = pQer->gate_status.second.ul_gate; fiveFlow.gbr = pQer->gbr.second.dl_gbr;
fiveFlow.mbr = pQer->mbr.second.dl_mbr;
fiveFlow.gbr.dl_gbr = pQer->gbr.second.dl_gbr; fiveFlow.qfi = pQer->qfi.second.qfi;
fiveFlow.gbr.ul_gbr = pQer->gbr.second.ul_gbr;
fiveFlow.mbr.dl_mbr = pQer->mbr.second.dl_mbr;
fiveFlow.mbr.ul_mbr = pQer->mbr.second.ul_mbr;
fiveFlow.qfi = pQer->qfi.second.qfi;
qosFlowsQfis.push_back(fiveFlow); qosFlowsQfis.push_back(fiveFlow);
...@@ -117,6 +107,23 @@ bool QERProgram::no_htb_root_qdisc(std::string interface) { ...@@ -117,6 +107,23 @@ bool QERProgram::no_htb_root_qdisc(std::string interface) {
return ret ? false : true; return ret ? false : true;
} }
/*---------------------------------------------------------------------------------------------------------------*/
std::shared_ptr<pfcp::pfcp_qer>
QERProgram::retrive_default_qer_with_default_qfi(
std::vector<std::shared_ptr<pfcp::pfcp_qer>> pQer) {
for (const auto& qer : pQer) {
if (!qer->gbr.first && !qer->mbr.first) {
Logger::upf_app().debug(
"Default QoS Flow: (QER ID, QFI): (%d, %d)",
qer->qer_id.second.qer_id, qer->qfi.second.qfi);
return qer;
}
}
// Return nullptr if no such QER is found
return nullptr;
}
/*---------------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------------*/
void QERProgram::setup( void QERProgram::setup(
uint64_t seid, std::vector<std::shared_ptr<pfcp::pfcp_qer>> pQer) { uint64_t seid, std::vector<std::shared_ptr<pfcp::pfcp_qer>> pQer) {
...@@ -125,7 +132,7 @@ void QERProgram::setup( ...@@ -125,7 +132,7 @@ void QERProgram::setup(
mpLifeCycle->load(); mpLifeCycle->load();
mpLifeCycle->attach(); mpLifeCycle->attach();
struct qer_tc_kernel_c* obj = NULL; std::shared_ptr<pfcp::pfcp_qer> default_qer = nullptr;
std::string cmd = {}; std::string cmd = {};
int rc = 0; int rc = 0;
...@@ -133,97 +140,106 @@ void QERProgram::setup( ...@@ -133,97 +140,106 @@ void QERProgram::setup(
uint32_t udpInterfaceIndex = if_nametoindex(UDP_INTERFACE.c_str()); uint32_t udpInterfaceIndex = if_nametoindex(UDP_INTERFACE.c_str());
uint32_t gtpInterfaceIndex = if_nametoindex(GTP_INTERFACE.c_str()); uint32_t gtpInterfaceIndex = if_nametoindex(GTP_INTERFACE.c_str());
uint32_t uplinkId = static_cast<uint32_t>(FlowDirection::UPLINK);
uint32_t downlinkId = static_cast<uint32_t>(FlowDirection::DOWNLINK);
mpEgressIfindexMap->update(uplinkId, udpInterfaceIndex, BPF_ANY);
mpEgressIfindexMap->update(downlinkId, gtpInterfaceIndex, BPF_ANY);
if (no_htb_root_qdisc(GTP_INTERFACE)) { if (udpInterfaceIndex == 0 || gtpInterfaceIndex == 0) {
Logger::upf_app().info( Logger::upf_app().error("Failed to retrieve interface indices");
"Creating Root qdisc on interface %s", GTP_INTERFACE.c_str()); throw std::runtime_error("Invalid network interface index");
cmd = fmt::format(
"tc qdisc add dev {} root handle 1:0 htb default {}", GTP_INTERFACE,
DEFAULT_QFI);
rc = system((const char*) cmd.c_str());
} }
Logger::upf_app().info("Create PDU Session Class 1:%d", seid); uint32_t uplinkId = static_cast<uint32_t>(FlowDirection::UPLINK);
cmd = fmt::format( uint32_t downlinkId = static_cast<uint32_t>(FlowDirection::DOWNLINK);
"tc class add dev {} parent 1:0 classid 1:{} htb rate {}kbit",
GTP_INTERFACE, seid, MAX_RATE);
rc = system((const char*) cmd.c_str());
Logger::upf_app().debug("QDISC Root DL Rate (GBR) : %dkbps", MAX_RATE);
Logger::upf_app().debug("QDISC Root DL Ceil (MBR) : %dkbps", MAX_CEIL);
for (const auto& qer : pQer) { mpEgressIfindexMap->update(uplinkId, udpInterfaceIndex, BPF_ANY);
if (qer == nullptr) { mpEgressIfindexMap->update(downlinkId, gtpInterfaceIndex, BPF_ANY);
continue;
}
uint8_t qfi = qer->qfi.second.qfi;
uint32_t qer_id = qer->qer_id.second.qer_id;
Logger::upf_app().warn(
"Set dl_rate and dl_ceil to 1kbit, for QER %d, as the minimum required "
"values to \n"
"create a tc class within the Linux kernel. These values are only used "
"if \n"
" dl_rate and dl_ceil are null within the PFCP Establishment request. "
"Of course, the \n "
"class rate and ceil are updated from the PFCP Modification request",
qer_id);
uint64_t dl_rate = 1;
uint64_t dl_ceil = 1;
uint64_t ul_rate = 1;
uint64_t ul_ceil = 1;
uint8_t dl_gate = 0;
uint8_t ul_gate = 0;
if (qfi != DEFAULT_QFI) { if (!pQer.empty()) {
if (qer->gbr.second.dl_gbr != 0) dl_rate = qer->gbr.second.dl_gbr; default_qer = retrive_default_qer_with_default_qfi(pQer);
if (qer->gbr.second.ul_gbr != 0) ul_rate = qer->gbr.second.ul_gbr; if (!default_qer) {
Logger::upf_app().error(
"QER with default QFI not found! select the first element as "
"default");
default_qer = pQer.front();
}
if (qer->mbr.second.dl_mbr != 0) dl_ceil = qer->mbr.second.dl_mbr; // Configure Root Qdisc if not already present
if (no_htb_root_qdisc(GTP_INTERFACE)) {
Logger::upf_app().info(
"Create Root qdisc on interface %s", GTP_INTERFACE.c_str());
cmd = fmt::format(
"tc qdisc add dev {} root handle 1:0 htb default {}", GTP_INTERFACE,
static_cast<uint8_t>(default_qer->qfi.second.qfi));
// rc = system((const char*) cmd.c_str());
if (system(cmd.c_str()) != 0) {
Logger::upf_app().error("Failed to create root Qdisc");
}
}
if (qer->mbr.second.ul_mbr != 0) ul_ceil = qer->mbr.second.ul_mbr; // Create PDU Session Class
Logger::upf_app().info("Create PDU Session Class 1:%d", seid);
cmd = fmt::format(
"tc class add dev {} parent 1:0 classid 1:{} htb rate {}kbit",
GTP_INTERFACE, seid, MAX_RATE);
dl_gate = qer->gate_status.second.dl_gate; if (system(cmd.c_str()) != 0) {
ul_gate = qer->gate_status.second.ul_gate; Logger::upf_app().error("Failed to create PDU Session class");
} }
struct s_fiveQosFlow fiveFlow; Logger::upf_app().debug("QDISC Root DL Rate (GBR) : %dkbps", MAX_RATE);
memset(&fiveFlow, 0, sizeof(struct s_fiveQosFlow)); Logger::upf_app().debug("QDISC Root DL Ceil (MBR) : %dkbps", MAX_CEIL);
fiveFlow.gate.dl_gate = dl_gate; // Process each QER
fiveFlow.gate.ul_gate = ul_gate; for (const auto& qer : pQer) {
fiveFlow.gbr.dl_gbr = dl_rate; if (qer == default_qer) {
fiveFlow.gbr.ul_gbr = ul_rate; continue;
fiveFlow.mbr.dl_mbr = dl_ceil; }
fiveFlow.mbr.ul_mbr = ul_ceil;
if ((qer->gbr.first) && (qer->mbr.first)) {
fiveFlow.qfi = qfi; uint32_t qer_id = qer->qer_id.second.qer_id;
getQoSFlowMap()->update(qer_id, fiveFlow, BPF_ANY); uint8_t qfi = qer->qfi.second.qfi;
uint64_t dl_rate = qer->gbr.second.dl_gbr ? qer->gbr.second.dl_gbr : 1;
uint16_t minor = (ntohs(seid) * 256) + (qfi * 251 % 256); uint64_t dl_ceil = qer->mbr.second.dl_mbr ? qer->mbr.second.dl_mbr : 1;
cmd = fmt::format( uint8_t dl_gate = qer->gate_status.second.dl_gate;
"tc class add dev {} parent 1:{} classid {}:{} htb rate {}kbit ceil "
"{}kbit", Logger::upf_app().warn(
GTP_INTERFACE, seid, seid, minor, dl_rate, dl_ceil); "Setting dl_rate and dl_ceil to minimum values (1 kbit) for QER %d "
rc = system((const char*) cmd.c_str()); "if GBR/MBR are null",
qer_id);
Logger::upf_app().debug(" HTB Class ID (QER) ........... %d", qer_id);
Logger::upf_app().debug(" Class QFI: %d", qfi); // Update QoS flow map
Logger::upf_app().debug(" Class DL Rate: %dkbps", dl_rate); struct s_fiveQosFlow fiveFlow = {};
Logger::upf_app().debug(" Class DL Ceil: %dkbps", dl_ceil); fiveFlow.gate = dl_gate;
} fiveFlow.gbr = dl_rate;
fiveFlow.mbr = dl_ceil;
getQoSFlowMap()->update(qer_id, fiveFlow, BPF_ANY);
// Add tc class for QER
uint16_t minor = (ntohs(seid) * 256) + (qfi * 251 % 256);
cmd = fmt::format(
"tc class add dev {} parent 1:{} classid {}:{} htb rate {}kbit "
"ceil "
"{}kbit",
GTP_INTERFACE, seid, seid, minor, dl_rate, dl_ceil);
if (system(cmd.c_str()) != 0) {
Logger::upf_app().error("Failed to add tc class for QER {}", qer_id);
}
Logger::upf_app().debug(
" HTB Class ID (QER) ........... %d", qer_id);
Logger::upf_app().debug(" Class QFI: %d", qfi);
Logger::upf_app().debug(" Class DL Rate: %dkbps", dl_rate);
Logger::upf_app().debug(" Class DL Ceil: %dkbps", dl_ceil);
}
}
Logger::upf_app().info("Attach Section tc_filter_traffic to gtp interface"); Logger::upf_app().info("Attach Section tc_filter_traffic to gtp interface");
mpLifeCycle->tcAttachEgress("tc_filter_traffic", GTP_INTERFACE.c_str()); mpLifeCycle->tcAttachEgress("tc_filter_traffic", GTP_INTERFACE.c_str());
Logger::upf_app().info("Attach Sesction tc_redirect to udp interface"); Logger::upf_app().info("Attach Sesction tc_redirect to udp interface");
mpLifeCycle->tcAttachIngress("tc_redirect_traffic", UDP_INTERFACE.c_str()); mpLifeCycle->tcAttachIngress("tc_redirect_traffic", UDP_INTERFACE.c_str());
}
} }
// change: // change:
......
...@@ -109,6 +109,10 @@ class QERProgram : public BPFProgram { ...@@ -109,6 +109,10 @@ class QERProgram : public BPFProgram {
// int add_clsact_qdisc(int ifindex, enum bpf_tc_attach_point attach_point); // int add_clsact_qdisc(int ifindex, enum bpf_tc_attach_point attach_point);
bool no_htb_root_qdisc(std::string interface); bool no_htb_root_qdisc(std::string interface);
/*---------------------------------------------------------------------------------------------------------------*/
std::shared_ptr<pfcp::pfcp_qer> retrive_default_qer_with_default_qfi(
std::vector<std::shared_ptr<pfcp::pfcp_qer>> pQer);
/*---------------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------------*/
private: private:
/** /**
......
...@@ -419,6 +419,7 @@ pfcp_switch::pfcp_switch() ...@@ -419,6 +419,7 @@ pfcp_switch::pfcp_switch()
ul_n3_teid2pfcp_pdr(PFCP_SWITCH_MAX_PDRS), ul_n3_teid2pfcp_pdr(PFCP_SWITCH_MAX_PDRS),
up_seid2pfcp_sessions(PFCP_SWITCH_MAX_SESSIONS), up_seid2pfcp_sessions(PFCP_SWITCH_MAX_SESSIONS),
sock_w(0) { sock_w(0) {
bool isBpfAccelerationEnabled = upf_cfg.enable_bpf_datapath;
num_threads_ = upf_cfg.n6.thread_rd_sched_params.thread_pool_size; num_threads_ = upf_cfg.n6.thread_rd_sched_params.thread_pool_size;
int num_blocks = num_threads_ * 16; int num_blocks = num_threads_ * 16;
free_pool_ = new folly::MPMCQueue<iovec_q_item_t*>(num_blocks); free_pool_ = new folly::MPMCQueue<iovec_q_item_t*>(num_blocks);
...@@ -440,7 +441,7 @@ pfcp_switch::pfcp_switch() ...@@ -440,7 +441,7 @@ pfcp_switch::pfcp_switch()
v->msg.msg_controllen = 0; v->msg.msg_controllen = 0;
free_pool_->blockingWrite(v); free_pool_->blockingWrite(v);
} }
if (!upf_cfg.enable_bpf_datapath) { if (!isBpfAccelerationEnabled) {
// num_threads_ is currently fixed to 1 // num_threads_ is currently fixed to 1
for (int i = 0; i < num_threads_; i++) { for (int i = 0; i < num_threads_; i++) {
pwThread_ = std::thread( pwThread_ = std::thread(
...@@ -689,6 +690,9 @@ void pfcp_switch::call_datapath( ...@@ -689,6 +690,9 @@ void pfcp_switch::call_datapath(
void pfcp_switch::handle_pfcp_session_establishment_request( void pfcp_switch::handle_pfcp_session_establishment_request(
std::shared_ptr<itti_n4_session_establishment_request> sreq, std::shared_ptr<itti_n4_session_establishment_request> sreq,
itti_n4_session_establishment_response* resp) { itti_n4_session_establishment_response* resp) {
bool isBpfAccelerationEnabled = upf_cfg.enable_bpf_datapath;
bool isQosEnabled = isBpfAccelerationEnabled && upf_cfg.enable_qos;
itti_n4_session_establishment_request* req = sreq.get(); itti_n4_session_establishment_request* req = sreq.get();
pfcp::fseid_t fseid = {}; pfcp::fseid_t fseid = {};
pfcp::cause_t cause = {.cause_value = CAUSE_VALUE_REQUEST_ACCEPTED}; pfcp::cause_t cause = {.cause_value = CAUSE_VALUE_REQUEST_ACCEPTED};
...@@ -737,11 +741,11 @@ void pfcp_switch::handle_pfcp_session_establishment_request( ...@@ -737,11 +741,11 @@ void pfcp_switch::handle_pfcp_session_establishment_request(
break; break;
} }
/*======================================================================*/ /*======================================================================*/
/* /*
* Add create_qers * Add create_qers
*/ */
if (upf_cfg.enable_bpf_datapath && upf_cfg.enable_qos) { if (isQosEnabled) {
pfcp::qer_id_t qer_id = {}; pfcp::qer_id_t qer_id = {};
if (cr_pdr.get(qer_id)) { if (cr_pdr.get(qer_id)) {
pfcp::create_qer cr_qer = {}; pfcp::create_qer cr_qer = {};
...@@ -759,9 +763,9 @@ void pfcp_switch::handle_pfcp_session_establishment_request( ...@@ -759,9 +763,9 @@ void pfcp_switch::handle_pfcp_session_establishment_request(
session->create(cr_qer, cause, offending_ie.offending_ie); session->create(cr_qer, cause, offending_ie.offending_ie);
} }
} }
/*======================================================================*/ /*======================================================================*/
if (not session->create( if (not session->create(
cr_pdr, cause, offending_ie.offending_ie, allocated_fteid)) { cr_pdr, cause, offending_ie.offending_ie, allocated_fteid)) {
session->cleanup(); session->cleanup();
...@@ -779,7 +783,7 @@ void pfcp_switch::handle_pfcp_session_establishment_request( ...@@ -779,7 +783,7 @@ void pfcp_switch::handle_pfcp_session_establishment_request(
} }
} }
if (upf_cfg.enable_bpf_datapath) { if (isBpfAccelerationEnabled) {
Logger::pfcp_switch().info( Logger::pfcp_switch().info(
"Establishing datapath: create PDRs + create FARs + create QERs " "Establishing datapath: create PDRs + create FARs + create QERs "
"(if any)"); "(if any)");
...@@ -860,6 +864,9 @@ void pfcp_switch::handle_pfcp_session_establishment_request( ...@@ -860,6 +864,9 @@ void pfcp_switch::handle_pfcp_session_establishment_request(
void pfcp_switch::handle_pfcp_session_modification_request( void pfcp_switch::handle_pfcp_session_modification_request(
std::shared_ptr<itti_n4_session_modification_request> sreq, std::shared_ptr<itti_n4_session_modification_request> sreq,
itti_n4_session_modification_response* resp) { itti_n4_session_modification_response* resp) {
bool isBpfAccelerationEnabled = upf_cfg.enable_bpf_datapath;
bool isQosEnabled = isBpfAccelerationEnabled && upf_cfg.enable_qos;
itti_n4_session_modification_request* req = sreq.get(); itti_n4_session_modification_request* req = sreq.get();
std::shared_ptr<pfcp::pfcp_session> s = {}; std::shared_ptr<pfcp::pfcp_session> s = {};
...@@ -882,7 +889,7 @@ void pfcp_switch::handle_pfcp_session_modification_request( ...@@ -882,7 +889,7 @@ void pfcp_switch::handle_pfcp_session_modification_request(
resp->seid = session->cp_fseid.seid; resp->seid = session->cp_fseid.seid;
for (auto it : req->pfcp_ies.remove_pdrs) { for (auto it : req->pfcp_ies.remove_pdrs) {
if (upf_cfg.enable_bpf_datapath) { if (isBpfAccelerationEnabled) {
Logger::pfcp_switch().info("Modifying datapath: remove PDRs"); Logger::pfcp_switch().info("Modifying datapath: remove PDRs");
call_datapath( call_datapath(
NULL, req, NULL, session, spSessionManager, NULL, req, NULL, session, spSessionManager,
...@@ -904,7 +911,7 @@ void pfcp_switch::handle_pfcp_session_modification_request( ...@@ -904,7 +911,7 @@ void pfcp_switch::handle_pfcp_session_modification_request(
if (cause.cause_value == CAUSE_VALUE_REQUEST_ACCEPTED) { if (cause.cause_value == CAUSE_VALUE_REQUEST_ACCEPTED) {
for (auto it : req->pfcp_ies.remove_fars) { for (auto it : req->pfcp_ies.remove_fars) {
if (upf_cfg.enable_bpf_datapath) { if (isBpfAccelerationEnabled) {
Logger::pfcp_switch().info("Modifying datapath: remove FARs"); Logger::pfcp_switch().info("Modifying datapath: remove FARs");
call_datapath( call_datapath(
NULL, req, NULL, session, spSessionManager, NULL, req, NULL, session, spSessionManager,
...@@ -929,15 +936,13 @@ void pfcp_switch::handle_pfcp_session_modification_request( ...@@ -929,15 +936,13 @@ void pfcp_switch::handle_pfcp_session_modification_request(
/* /*
* Add remove_qers * Add remove_qers
*/ */
if (upf_cfg.enable_bpf_datapath && upf_cfg.enable_qos) { if (isQosEnabled) {
if (cause.cause_value == CAUSE_VALUE_REQUEST_ACCEPTED) { if (cause.cause_value == CAUSE_VALUE_REQUEST_ACCEPTED) {
for (auto it : req->pfcp_ies.remove_qers) { for (auto it : req->pfcp_ies.remove_qers) {
if (upf_cfg.enable_bpf_datapath) { Logger::pfcp_switch().info("Modifying datapath: remove QERs");
Logger::pfcp_switch().info("Modifying datapath: remove QERs"); call_datapath(
call_datapath( NULL, req, NULL, session, spSessionManager,
NULL, req, NULL, session, spSessionManager, &SessionManager::updateBPFSession);
&SessionManager::updateBPFSession);
}
remove_qer& qer = it; remove_qer& qer = it;
...@@ -957,7 +962,7 @@ void pfcp_switch::handle_pfcp_session_modification_request( ...@@ -957,7 +962,7 @@ void pfcp_switch::handle_pfcp_session_modification_request(
if (cause.cause_value == CAUSE_VALUE_REQUEST_ACCEPTED) { if (cause.cause_value == CAUSE_VALUE_REQUEST_ACCEPTED) {
for (auto it : req->pfcp_ies.create_fars) { for (auto it : req->pfcp_ies.create_fars) {
if (upf_cfg.enable_bpf_datapath) { if (isBpfAccelerationEnabled) {
Logger::pfcp_switch().info("Modifying datapath: create FARs"); Logger::pfcp_switch().info("Modifying datapath: create FARs");
call_datapath( call_datapath(
NULL, req, NULL, session, spSessionManager, NULL, req, NULL, session, spSessionManager,
...@@ -1007,7 +1012,7 @@ void pfcp_switch::handle_pfcp_session_modification_request( ...@@ -1007,7 +1012,7 @@ void pfcp_switch::handle_pfcp_session_modification_request(
resp->pfcp_ies.set(created_pdr); resp->pfcp_ies.set(created_pdr);
} }
if (upf_cfg.enable_bpf_datapath) { if (isBpfAccelerationEnabled) {
Logger::pfcp_switch().info( Logger::pfcp_switch().info(
"Modifying datapath: create PDRs + create FARs"); "Modifying datapath: create PDRs + create FARs");
call_datapath( call_datapath(
...@@ -1021,15 +1026,13 @@ void pfcp_switch::handle_pfcp_session_modification_request( ...@@ -1021,15 +1026,13 @@ void pfcp_switch::handle_pfcp_session_modification_request(
/* /*
* Add create_qers * Add create_qers
*/ */
if (upf_cfg.enable_bpf_datapath && upf_cfg.enable_qos) { if (isQosEnabled) {
if (cause.cause_value == CAUSE_VALUE_REQUEST_ACCEPTED) { if (cause.cause_value == CAUSE_VALUE_REQUEST_ACCEPTED) {
for (auto it : req->pfcp_ies.create_qers) { for (auto it : req->pfcp_ies.create_qers) {
if (upf_cfg.enable_bpf_datapath) { Logger::pfcp_switch().info("Modifying datapath: create QERs");
Logger::pfcp_switch().info("Modifying datapath: create QERs"); call_datapath(
call_datapath( NULL, req, NULL, session, spSessionManager,
NULL, req, NULL, session, spSessionManager, &SessionManager::updateBPFSession);
&SessionManager::updateBPFSession);
}
create_qer& cr_qer = it; create_qer& cr_qer = it;
if (not session->create(cr_qer, cause, offending_ie.offending_ie)) { if (not session->create(cr_qer, cause, offending_ie.offending_ie)) {
break; break;
...@@ -1041,7 +1044,7 @@ void pfcp_switch::handle_pfcp_session_modification_request( ...@@ -1041,7 +1044,7 @@ void pfcp_switch::handle_pfcp_session_modification_request(
if (cause.cause_value == CAUSE_VALUE_REQUEST_ACCEPTED) { if (cause.cause_value == CAUSE_VALUE_REQUEST_ACCEPTED) {
for (auto it : req->pfcp_ies.update_pdrs) { for (auto it : req->pfcp_ies.update_pdrs) {
if (upf_cfg.enable_bpf_datapath) { if (isBpfAccelerationEnabled) {
Logger::pfcp_switch().info("Modifying datapath: update PDRs"); Logger::pfcp_switch().info("Modifying datapath: update PDRs");
call_datapath( call_datapath(
NULL, req, NULL, session, spSessionManager, NULL, req, NULL, session, spSessionManager,
...@@ -1059,7 +1062,7 @@ void pfcp_switch::handle_pfcp_session_modification_request( ...@@ -1059,7 +1062,7 @@ void pfcp_switch::handle_pfcp_session_modification_request(
} }
for (auto it : req->pfcp_ies.update_fars) { for (auto it : req->pfcp_ies.update_fars) {
if (upf_cfg.enable_bpf_datapath) { if (isBpfAccelerationEnabled) {
Logger::pfcp_switch().info("Modifying datapath: update FARs"); Logger::pfcp_switch().info("Modifying datapath: update FARs");
call_datapath( call_datapath(
NULL, req, NULL, session, spSessionManager, NULL, req, NULL, session, spSessionManager,
...@@ -1082,14 +1085,12 @@ void pfcp_switch::handle_pfcp_session_modification_request( ...@@ -1082,14 +1085,12 @@ void pfcp_switch::handle_pfcp_session_modification_request(
/* /*
* Add update_qers * Add update_qers
*/ */
if (upf_cfg.enable_bpf_datapath && upf_cfg.enable_qos) { if (isQosEnabled) {
for (auto it : req->pfcp_ies.update_qers) { for (auto it : req->pfcp_ies.update_qers) {
if (upf_cfg.enable_bpf_datapath) { Logger::pfcp_switch().info("Modifying datapath: update QERs");
Logger::pfcp_switch().info("Modifying datapath: update QERs"); call_datapath(
call_datapath( NULL, req, NULL, session, spSessionManager,
NULL, req, NULL, session, spSessionManager, &SessionManager::updateBPFSession);
&SessionManager::updateBPFSession);
}
update_qer& qer = it; update_qer& qer = it;
uint8_t cause_value = CAUSE_VALUE_REQUEST_ACCEPTED; uint8_t cause_value = CAUSE_VALUE_REQUEST_ACCEPTED;
...@@ -1151,6 +1152,8 @@ void pfcp_switch::handle_pfcp_session_modification_request( ...@@ -1151,6 +1152,8 @@ void pfcp_switch::handle_pfcp_session_modification_request(
void pfcp_switch::handle_pfcp_session_deletion_request( void pfcp_switch::handle_pfcp_session_deletion_request(
std::shared_ptr<itti_n4_session_deletion_request> sreq, std::shared_ptr<itti_n4_session_deletion_request> sreq,
itti_n4_session_deletion_response* resp) { itti_n4_session_deletion_response* resp) {
bool isBpfAccelerationEnabled = upf_cfg.enable_bpf_datapath;
itti_n4_session_deletion_request* req = sreq.get(); itti_n4_session_deletion_request* req = sreq.get();
std::shared_ptr<pfcp::pfcp_session> s = {}; std::shared_ptr<pfcp::pfcp_session> s = {};
...@@ -1165,7 +1168,7 @@ void pfcp_switch::handle_pfcp_session_deletion_request( ...@@ -1165,7 +1168,7 @@ void pfcp_switch::handle_pfcp_session_deletion_request(
pfcp::pfcp_session* session = s.get(); pfcp::pfcp_session* session = s.get();
resp->seid = s->cp_fseid.seid; resp->seid = s->cp_fseid.seid;
if (upf_cfg.enable_bpf_datapath) { if (isBpfAccelerationEnabled) {
Logger::pfcp_switch().info( Logger::pfcp_switch().info(
"Deleting datapath: delete PDRs + delete FARs"); "Deleting datapath: delete PDRs + delete FARs");
call_datapath( call_datapath(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment