diff --git a/conf/spgwu.bess b/conf/spgwu.bess index d983edc147..34494159f3 100644 --- a/conf/spgwu.bess +++ b/conf/spgwu.bess @@ -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"]) # ==================================================== @@ -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(): @@ -71,7 +71,7 @@ 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 @@ -79,8 +79,10 @@ class Port: 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: @@ -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() @@ -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: @@ -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) @@ -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))}}, @@ -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 @@ -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) @@ -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 diff --git a/conf/spgwu.json b/conf/spgwu.json index 9b0654d88a..ae7326802f 100644 --- a/conf/spgwu.json +++ b/conf/spgwu.json @@ -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": { diff --git a/conf/utils.py b/conf/utils.py index 5b060b6f5f..3acd317b6f 100644 --- a/conf/utils.py +++ b/conf/utils.py @@ -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) diff --git a/core/modules/ip_frag.cc b/core/modules/ip_frag.cc index 19422a8138..319cdc2263 100644 --- a/core/modules/ip_frag.cc +++ b/core/modules/ip_frag.cc @@ -2,8 +2,6 @@ #include "ip_frag.h" /* for rte_zmalloc() */ #include -/* for RTE_ETHER macros */ -#include "rte_ether.h" /* for be32_t */ #include "utils/endian.h" /* for ToIpv4Address() */ @@ -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. @@ -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; @@ -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()); @@ -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() { @@ -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!"); diff --git a/core/modules/ip_frag.h b/core/modules/ip_frag.h index b4b19587c8..1315594a42 100644 --- a/core/modules/ip_frag.h +++ b/core/modules/ip_frag.h @@ -5,6 +5,8 @@ #include /* for ipv4 header */ #include +/* for RTE_ETHER macros */ +#include "rte_ether.h" #include "../module.h" #include "../pb/module_msg.pb.h" /*----------------------------------------------------------------------------------*/ @@ -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_ diff --git a/protobuf/module_msg.proto b/protobuf/module_msg.proto index 973ec5a55a..a164340dac 100644 --- a/protobuf/module_msg.proto +++ b/protobuf/module_msg.proto @@ -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) @@ -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 * @@ -1077,7 +1088,7 @@ message SplitArg { * __Output Gates__: 1 */ message TimestampArg { - uint64 offset = 1; + int64 offset = 1; } /**