Skip to content

Commit

Permalink
Add mtu option for IPFrag module.
Browse files Browse the repository at this point in the history
Signed-off-by: Muhammad Asim Jamshed <muhammad.jamshed@intel.com>
  • Loading branch information
ajamshed committed Apr 18, 2020
1 parent ddf1f90 commit 09a13ed
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 66 deletions.
123 changes: 68 additions & 55 deletions conf/spgwu.bess
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,17 @@ except KeyError:
print('max_ip_defrag_flows value not set. Not installing IP4Defrag module.')

# Enable ip4 fragmentation
ip_frag_flows = None
ip_frag_with_eth_mtu = None
try:
ip_frag_flows = int(conf["ip_frag_flows"])
ip_frag_with_eth_mtu = int(conf["ip_frag_with_eth_mtu"])
except ValueError:
print('Invalid value for ip_frag_flows. Not installing IP4Frag module.')
print('Invalid value for ip_frag_with_eth_mtu. Not installing IP4Frag module.')
except KeyError:
print('ip_frag_flows value not set. Not installing IP4Frag module.')
print('ip_frag_with_eth_mtu value not set. Not installing IP4Frag module.')

# See this link for details:
## https://github.com/NetSys/bess/blob/master/bessctl/module_tests/timestamp.py
measure = bool(conf["measure"])


# ====================================================
Expand All @@ -42,10 +46,6 @@ except KeyError:

MAX_GATES = 8192
dpdk_ports = {}
# Enable MEASURE = 1 to retreive telemetry data
# See this link for details:
## https://github.com/NetSys/bess/blob/master/bessctl/module_tests/timestamp.py
MEASURE = bool(int($MEASURE!'0'))


def scan_dpdk_ports():
Expand All @@ -71,16 +71,18 @@ def scan_dpdk_ports():


class Port:
def __init__(self, name, nat, ext_addr):
def __init__(self, name, ext_addr, offset1, offset2):
self.name = name
self.wid = None
self.fpi = None
self.fpo = None
self.bpf = None
self.bpfgate = 0
self.routes_table = None
self.nat = nat
self.nat = None
self.ext_addr = ext_addr
self.msr_off1 = offset1
self.msr_off2 = offset2

def bpf_gate(self):
if self.bpfgate < MAX_GATES - 2:
Expand Down Expand Up @@ -112,8 +114,8 @@ class Port:
self.bpf.clear()

# Default drop when no matches
if MEASURE == 1:
self.fpi -> Timestamp() -> self.bpf:0 -> Sink()
if measure:
self.fpi -> Timestamp(offset=-(self.msr_off1)) -> self.bpf:0 -> Sink()
else:
self.fpi -> self.bpf:0 -> Sink()

Expand Down Expand Up @@ -188,30 +190,30 @@ class Port:

# Direct fast path traffic to Frag module
merge = __bess_module__("{}Merge".format(name), 'Merge')
if ip_frag_flows is not None:
frag = __bess_module__("{}IP4Frag".format(name), 'IPFrag')
if MEASURE == 1:
if self.nat is not None:
merge -> 0:self.nat:1 -> frag:1 -> Measure(latency_ns_resolution=1, latency_ns_max=100000) -> self.fpo
else:
merge -> frag:1 -> Measure(latency_ns_resolution=1, latency_ns_max=100000) -> self.fpo
else:
if self.nat is not None:
merge -> 0:self.nat:1 -> frag:1 -> self.fpo
else:
merge -> frag:1 -> self.fpo

out = self.fpo

# Attach frag module (if enabled)
if ip_frag_with_eth_mtu is not None:
frag = __bess_module__("{}IP4Frag".format(name), 'IPFrag', mtu=ip_frag_with_eth_mtu)
frag:1 -> out
frag:0 -> Sink()
else:
if MEASURE == 1:
if self.nat is not None:
merge -> 0:self.nat:1 -> Measure(latency_ns_resolution=1, latency_ns_max=100000) -> self.fpo
else:
merge -> Measure(latency_ns_resolution=1, latency_ns_max=100000) -> self.fpo
else:
if self.nat is not None:
merge -> 0:self.nat:1 -> self.fpo
else:
merge -> self.fpo
out = frag

# Attach telemeric module (if enabled)
if measure:
m = Measure(latency_ns_resolution=1, latency_ns_max=100000, offset=-(self.msr_off2))
m -> out
out = m

# Attach nat module (if enabled)
if self.ext_addr is not None:
self.nat = __bess_module__("{}NAT".format(conf[interface]["ifname"]), 'NAT', ext_addrs=[{'ext_addr': ext_addr}])
self.nat:1 -> out
out = self.nat

# Attach Merge module to the 'outlist' of modules
merge -> out

tc = 'slow{}'.format(wid)
try:
Expand Down Expand Up @@ -276,14 +278,21 @@ ports = {}
for idx, interface in enumerate(interfaces):
try:
ext_addr = conf[interface]["ip_masquerade"]
if ext_addr is not None:
# nat::NAT(ext_addrs=[{'ext_addr': useNAT}])
nat = __bess_module__("{}NAT".format(conf[interface]["ifname"]), 'NAT', ext_addrs=[{'ext_addr': ext_addr}])
except KeyError:
nat = None
ext_addr = None

port = Port(conf[interface]["ifname"], nat, ext_addr)
offset1 = None
offset2 = None
if measure:
if interface == "s1u":
offset1 = MEASUREHDRSZ
offset2 = MEASURE_OFFSET
if interface == 'sgi':
offset1 = MEASURE_OFFSET
offset2 = MEASUREHDRSZ

port = Port(conf[interface]["ifname"], ext_addr, offset1, offset2)
if port.name in ports:
continue
port.setup_port(idx, workers)
Expand Down Expand Up @@ -316,20 +325,24 @@ else:
"filter": "ip dst net {}".format(ue_cidr), "gate": UEGate}
sgiFastBPF.add(filters=[ue_filter])

_in = sgiFastBPF
gate = UEGate
# Append nat module (if enabled)
if ports[sgi_ifname].nat is not None:
# Append sgiIP4Defrag module (if enabled)
if max_ip_defrag_flows is not None:
sgiFastBPF:UEGate -> 1:ports[sgi_ifname].nat:0 -> sgiIP4Defrag::IPDefrag(num_flows=max_ip_defrag_flows, numa=0):1 -> EtherTrim::GenericDecap(bytes=14)
else:
sgiFastBPF:UEGate -> 1:ports[sgi_ifname].nat:0 -> EtherTrim::GenericDecap(bytes=14)
else:
# Append sgiIP4Defrag module (if enabled)
if max_ip_defrag_flows is not None:
sgiFastBPF:UEGate -> sgiIP4Defrag::IPDefrag(num_flows=max_ip_defrag_flows, numa=0):1 -> EtherTrim::GenericDecap(bytes=14)
else:
sgiFastBPF:UEGate -> EtherTrim::GenericDecap(bytes=14)
_in:gate -> 1:ports[sgi_ifname].nat
_in = ports[sgi_ifname].nat
gate = 0

# Append sgiIP4Defrag module (if enabled)
if max_ip_defrag_flows is not None:
_in:gate -> sgiIP4Defrag::IPDefrag(num_flows=max_ip_defrag_flows, numa=0)
_in = sgiIP4Defrag
gate = 1
# Drop pkts that are unable to be fragmented
sgiIP4Defrag:0 -> Sink()

EtherTrim -> GTPUEncap::GtpuEncap(s1u_sgw_ip=ip2long(ips_by_interface(s1u_ifname)[0]), num_subscribers=max_sessions):1 \
_in:gate -> EtherTrim::GenericDecap(bytes=14) \
-> GTPUEncap::GtpuEncap(s1u_sgw_ip=ip2long(ips_by_interface(s1u_ifname)[0]), num_subscribers=max_sessions):1 \
-> S1UEtherAdd::GenericEncap(fields=[
{'size': 6, 'value': {'value_int': 0x0}},
{'size': 6, 'value': {'value_int': mac2hex(mac_by_interface(s1u_ifname))}},
Expand All @@ -340,8 +353,7 @@ EtherTrim -> GTPUEncap::GtpuEncap(s1u_sgw_ip=ip2long(ips_by_interface(s1u_ifname

# Drop unknown packets
GTPUEncap:0 -> Sink()
if max_ip_defrag_flows is not None:
sgiIP4Defrag:0 -> Sink()


# ====================================================
# Uplink Pipeline
Expand Down Expand Up @@ -378,6 +390,8 @@ sgiRoutes = ports[sgi_ifname].rtr
# Append s1uIP4Defrag module (if enabled)
if max_ip_defrag_flows is not None:
s1uFastBPF:GTPUGate -> s1uIP4Defrag::IPDefrag(num_flows=max_ip_defrag_flows, numa=0):1 -> EtherDecapTrim::GenericDecap(bytes=14)
# Drop pkts that are unable to be fragmented
s1uIP4Defrag:0 -> Sink()
else:
s1uFastBPF:GTPUGate -> EtherDecapTrim::GenericDecap(bytes=14)

Expand All @@ -396,8 +410,7 @@ s1uFastBPF:GTPUEchoGate \
# Drop unknown packets
GTPUEcho:0 -> Sink()
GTPUDecap:0 -> Sink()
if max_ip_defrag_flows is not None:
s1uIP4Defrag:0 -> Sink()


# ====================================================
# SIM_TEST
Expand Down
9 changes: 6 additions & 3 deletions conf/spgwu.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@
"": "max UE sessions",
"max_sessions": 50000,

"": "max IP frag table entries (for IPv4 reassembly). Update the line below to `\"max_ip_defrag_flows\": 5000` to enable",
"": "max IP frag table entries (for IPv4 reassembly). Update the line below to `\"max_ip_defrag_flows\": 1000` to enable",
"": "max_ip_defrag_flows: 1000",

"": "Update the line below to `\"ip_frag_flows\": 1` to enable",
"": "ip_frag_flows: 1",
"": "Update the line below to `\"ip_frag_with_eth_mtu\": 1518` to enable",
"": "ip_frag_with_eth_mtu: 1518",

"": "Telemetrics-See this link for details: https://github.com/NetSys/bess/blob/master/bessctl/module_tests/timestamp.py",
"measure": false,

"": "Gateway interfaces",
"s1u": {
Expand Down
6 changes: 6 additions & 0 deletions conf/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
import psutil
from pyroute2 import IPDB

IPHDRSZ=20
UDPHDRSZ=8
GTPHDRSZ=8
MEASUREHDRSZ=12
MEASURE_OFFSET=(IPHDRSZ + UDPHDRSZ + GTPHDRSZ + MEASUREHDRSZ)


def exit(code, msg):
print(msg)
Expand Down
21 changes: 16 additions & 5 deletions core/modules/ip_frag.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
#include "ip_frag.h"
/* for rte_zmalloc() */
#include <rte_malloc.h>
/* for RTE_ETHER macros */
#include "rte_ether.h"
/* for be32_t */
#include "utils/endian.h"
/* for ToIpv4Address() */
Expand All @@ -19,6 +17,10 @@ using bess::utils::ToIpv4Address;

enum {DEFAULT_GATE = 0, FORWARD_GATE};
/*----------------------------------------------------------------------------------*/
const Commands IPFrag::cmds = {
{"get_eth_mtu", "EmptyArg", MODULE_CMD_FUNC(&IPFrag::GetEthMTU),
Command::THREAD_SAFE}};
/*----------------------------------------------------------------------------------*/
/**
* Returns NULL if packet is fragmented and needs more for reassembly.
* Returns Packet ptr if the packet is unfragmented, or is freshly reassembled.
Expand All @@ -31,7 +33,7 @@ IPFrag::FragmentPkt(Context *ctx, bess::Packet *p)
struct rte_mbuf *m = (struct rte_mbuf *)p;

if (RTE_ETH_IS_IPV4_HDR(m->packet_type) &&
unlikely((RTE_ETHER_MAX_LEN - RTE_ETHER_CRC_LEN) < p->total_len())) {
unlikely((eth_mtu - RTE_ETHER_CRC_LEN) < p->total_len())) {
volatile int32_t res;
struct rte_ether_hdr ethh_copy;
int32_t j;
Expand All @@ -54,7 +56,7 @@ IPFrag::FragmentPkt(Context *ctx, bess::Packet *p)
res = rte_ipv4_fragment_packet(m,
&frag_tbl[0],
BATCH_SIZE,
RTE_ETHER_MAX_LEN - RTE_ETHER_CRC_LEN - RTE_ETHER_HDR_LEN,
eth_mtu - RTE_ETHER_CRC_LEN - RTE_ETHER_HDR_LEN,
m->pool,
indirect_pktmbuf_pool->pool());

Expand Down Expand Up @@ -139,6 +141,11 @@ IPFrag::ProcessBatch(Context *ctx, bess::PacketBatch *batch)
}
}
/*----------------------------------------------------------------------------------*/
CommandResponse IPFrag::GetEthMTU(const bess::pb::EmptyArg &) {
std::cerr << "Ethernet MTU Size: " << eth_mtu << std::endl;
return CommandSuccess();
}
/*----------------------------------------------------------------------------------*/
void
IPFrag::DeInit()
{
Expand All @@ -150,10 +157,14 @@ IPFrag::DeInit()
}
/*----------------------------------------------------------------------------------*/
CommandResponse
IPFrag::Init(const bess::pb::EmptyArg &) {
IPFrag::Init(const bess::pb::IPFragArg &arg) {

eth_mtu = arg.mtu();
std::string pool_name = this->name() + "_indirect_mbuf_pool";

if (eth_mtu <= RTE_ETHER_MIN_LEN)
return CommandFailure(EINVAL, "Invalid MTU size!");

indirect_pktmbuf_pool = new bess::DpdkPacketPool();
if (indirect_pktmbuf_pool == NULL)
return CommandFailure(ENOMEM, "Cannot create indirect mempool!");
Expand Down
7 changes: 6 additions & 1 deletion core/modules/ip_frag.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <rte_ip_frag.h>
/* for ipv4 header */
#include <rte_ip.h>
/* for RTE_ETHER macros */
#include "rte_ether.h"
#include "../module.h"
#include "../pb/module_msg.pb.h"
/*----------------------------------------------------------------------------------*/
Expand Down Expand Up @@ -47,14 +49,17 @@ class IPFrag final : public Module {

/* Gates: (0) Default, (1) Forward */
static const gate_idx_t kNumOGates = 2;
static const Commands cmds;

CommandResponse Init(const bess::pb::EmptyArg &arg);
CommandResponse Init(const bess::pb::IPFragArg &arg);
void DeInit() override;
void ProcessBatch(Context *ctx, bess::PacketBatch *batch) override;
CommandResponse GetEthMTU(const bess::pb::EmptyArg &);

private:
bess::Packet *FragmentPkt(Context *ctx, bess::Packet *p);
bess::DpdkPacketPool *indirect_pktmbuf_pool = NULL;
int eth_mtu = RTE_ETHER_MAX_LEN;
};
/*----------------------------------------------------------------------------------*/
#endif // BESS_MODULES_IPFRAG_H_
15 changes: 13 additions & 2 deletions protobuf/module_msg.proto
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ message MACSwapArg {
*/
message MeasureArg {
// int64 warmup = 1; /// removed: instead of warmup delay, user should Clear()
uint64 offset = 2; /// Where to store the current time within the packet, offset in bytes.
int64 offset = 2; /// Where to store the current time within the packet, offset in bytes.
double jitter_sample_prob = 3; /// How often the module should sample packets for inter-packet arrival measurements (to measure jitter).
uint64 latency_ns_max = 4; /// maximum latency expected, in ns (default 0.1 s)
uint32 latency_ns_resolution = 5; /// resolution, in ns (default 100)
Expand Down Expand Up @@ -1007,6 +1007,17 @@ message IPDefragArg {
int32 numa = 2; /// numa placement for ip frags memory management
}

/**
* The IPDFrag module scans the IP datagram and checks whether
* it needs to be fragmented.
*
* __Input Gates__: 1
* __Output Gates__: 1
*/
message IPFragArg {
int32 mtu = 1; /// full Ethernet frame size (including CRC) for encapsulated ipv4 frag datagrams
}

/**
* The GtpuDecap module trims the GTPU header from the Ethernet frame
*
Expand Down Expand Up @@ -1077,7 +1088,7 @@ message SplitArg {
* __Output Gates__: 1
*/
message TimestampArg {
uint64 offset = 1;
int64 offset = 1;
}

/**
Expand Down

0 comments on commit 09a13ed

Please sign in to comment.