From ad4baf17fb00303d7b8244a101b993b8dcf12d29 Mon Sep 17 00:00:00 2001 From: Muhammad Asim Jamshed Date: Tue, 24 Mar 2020 23:00:12 -0700 Subject: [PATCH 1/5] Added telemetry-based enhancements. Signed-off-by: Muhammad Asim Jamshed --- conf/spgwu.bess | 15 ++++++++++++--- core/modules/gtpu_encap.cc | 7 +++++++ core/modules/gtpu_encap.h | 1 + 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/conf/spgwu.bess b/conf/spgwu.bess index 76e546da7..892e4cf9b 100644 --- a/conf/spgwu.bess +++ b/conf/spgwu.bess @@ -32,6 +32,10 @@ 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 = 0 def scan_dpdk_ports(): @@ -98,8 +102,10 @@ class Port: # Reassemble IP4 fragments (if needed) defrag = __bess_module__("{}IP4Defrag".format(name), 'IPDefrag', num_flows=max_ip_defrag_flows, numa=0) # Default drop when no matches - self.fpi -> defrag:1 -> self.bpf:0 -> Sink() - defrag:0 -> Sink() + if MEASURE == 1: + self.fpi -> Timestamp() -> self.bpf:0 -> Sink() + else: + self.fpi -> self.bpf:0 -> Sink() # Initialize route module self.rtr = __bess_module__("{}Routes".format(name), 'IPLookup') @@ -173,7 +179,10 @@ class Port: # Direct fast path traffic to Frag module merge = __bess_module__("{}Merge".format(name), 'Merge') frag = __bess_module__("{}IP4Frag".format(name), 'IPFrag') - merge -> frag:1 -> self.fpo + if MEASURE == 1: + merge -> frag:1 -> Measure(latency_ns_resolution=1, latency_ns_max=100000) -> self.fpo + else: + merge -> frag:1 ->self.fpo frag:0 -> Sink() tc = 'slow{}'.format(wid) diff --git a/core/modules/gtpu_encap.cc b/core/modules/gtpu_encap.cc index ea9f05359..3016ef9c0 100644 --- a/core/modules/gtpu_encap.cc +++ b/core/modules/gtpu_encap.cc @@ -33,6 +33,8 @@ const Commands GtpuEncap::cmds = { {"remove", "GtpuEncapRemoveSessionRecordArg", MODULE_CMD_FUNC(&GtpuEncap::RemoveSessionRecord), Command::THREAD_SAFE}, {"show_records", "EmptyArg", MODULE_CMD_FUNC(&GtpuEncap::ShowRecords), + Command::THREAD_SAFE}, + {"show_count", "EmptyArg", MODULE_CMD_FUNC(&GtpuEncap::ShowCount), Command::THREAD_SAFE}}; /*----------------------------------------------------------------------------------*/ // Template for generating UDP packets without data @@ -202,6 +204,11 @@ CommandResponse GtpuEncap::ShowRecords(const bess::pb::EmptyArg &) { return CommandSuccess(); } /*----------------------------------------------------------------------------------*/ +CommandResponse GtpuEncap::ShowCount(const bess::pb::EmptyArg &) { + std::cerr << "# of records: " << rte_hash_count(session_map) << std::endl; + return CommandSuccess(); +} +/*----------------------------------------------------------------------------------*/ void GtpuEncap::ProcessBatch(Context *ctx, bess::PacketBatch *batch) { int cnt = batch->cnt(); int hits = 0; diff --git a/core/modules/gtpu_encap.h b/core/modules/gtpu_encap.h index 022984ce9..275556df3 100644 --- a/core/modules/gtpu_encap.h +++ b/core/modules/gtpu_encap.h @@ -37,6 +37,7 @@ class GtpuEncap final : public Module { CommandResponse RemoveSessionRecord( const bess::pb::GtpuEncapRemoveSessionRecordArg &arg); CommandResponse ShowRecords(const bess::pb::EmptyArg &); + CommandResponse ShowCount(const bess::pb::EmptyArg &); void ProcessBatch(Context *ctx, bess::PacketBatch *batch) override; private: From a26ae9d81ca720ea9028fba079f32ad0da608745 Mon Sep 17 00:00:00 2001 From: Muhammad Asim Jamshed Date: Thu, 9 Apr 2020 18:22:16 -0700 Subject: [PATCH 2/5] Make IP4DeFrag & IP4Frag modules optional. Users should rely on MSS clamping instead. Signed-off-by: Muhammad Asim Jamshed --- conf/spgwu.bess | 57 ++++++++++++++++++++++++++++++++++++++----------- conf/spgwu.json | 9 +++++--- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/conf/spgwu.bess b/conf/spgwu.bess index 892e4cf9b..a713245c0 100644 --- a/conf/spgwu.bess +++ b/conf/spgwu.bess @@ -16,14 +16,24 @@ from conf.utils import * conf_file = get_env('CONF_FILE', 'conf/spgwu.json') conf = get_json_conf(conf_file, False) -# Maximum number of flows to manage ip frags for re-assembly +# Maximum number of flows to manage ip4 frags for re-assembly max_ip_defrag_flows = None try: max_ip_defrag_flows = int(conf["max_ip_defrag_flows"]) except ValueError: - print('Invalid value for max_ip_defrag_flows. Not installing IPDefrag module.') + print('Invalid value for max_ip_defrag_flows. Not installing IP4Defrag module.') except KeyError: - print('max_ip_defrag_flows value not set. Not installing IPDefrag module.') + print('max_ip_defrag_flows value not set. Not installing IP4Defrag module.') + +# Enable ip4 fragmentation +ip_frag_flows = None +try: + ip_frag_flows = int(conf["ip_frag_flows"]) +except ValueError: + print('Invalid value for ip_frag_flows. Not installing IP4Frag module.') +except KeyError: + print('ip_frag_flows value not set. Not installing IP4Frag module.') + # ==================================================== # Port Helpers @@ -178,12 +188,18 @@ class Port: # Direct fast path traffic to Frag module merge = __bess_module__("{}Merge".format(name), 'Merge') - frag = __bess_module__("{}IP4Frag".format(name), 'IPFrag') - if MEASURE == 1: - merge -> frag:1 -> Measure(latency_ns_resolution=1, latency_ns_max=100000) -> self.fpo + if ip_frag_flows is not None: + frag = __bess_module__("{}IP4Frag".format(name), 'IPFrag') + if MEASURE == 1: + merge -> frag:1 -> Measure(latency_ns_resolution=1, latency_ns_max=100000) -> self.fpo + else: + merge -> frag:1 -> self.fpo + frag:0 -> Sink() else: - merge -> frag:1 ->self.fpo - frag:0 -> Sink() + if MEASURE == 1: + merge -> Measure(latency_ns_resolution=1, latency_ns_max=100000) -> self.fpo + else: + merge -> self.fpo tc = 'slow{}'.format(wid) try: @@ -273,9 +289,13 @@ ue_filter = {"priority": -UEGate, "filter": "ip dst net {}".format(ue_cidr), "gate": UEGate} sgiFastBPF.add(filters=[ue_filter]) -sgiFastBPF:UEGate \ - -> EtherTrim::GenericDecap(bytes=14) \ - -> GTPUEncap::GtpuEncap(s1u_sgw_ip=ip2long(ips_by_interface(s1u_ifname)[0]), num_subscribers=max_sessions):1 \ +# 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) + +EtherTrim -> 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))}}, @@ -286,6 +306,9 @@ sgiFastBPF:UEGate \ # Drop unknown packets GTPUEncap:0 -> Sink() +if max_ip_defrag_flows is not None: + sgiIP4Defrag:0 -> Sink() + # ==================================================== # Uplink Pipeline @@ -319,8 +342,13 @@ s1uFastBPF.add(filters=[uplink_filter]) sgiRoutes = ports[sgi_ifname].rtr -s1uFastBPF:GTPUGate \ - -> EtherDecapTrim::GenericDecap(bytes=14) -> GTPUDecap::GtpuDecap(ename="GTPUEncap"):1 \ +# 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) +else: + s1uFastBPF:GTPUGate -> EtherDecapTrim::GenericDecap(bytes=14) + +EtherDecapTrim -> GTPUDecap::GtpuDecap(ename="GTPUEncap"):1 \ -> SGIEtherAdd::GenericEncap(fields=[ {'size': 6, 'value': {'value_int': 0x0}}, {'size': 6, 'value': {'value_int': mac2hex(mac_by_interface(sgi_ifname))}}, @@ -335,6 +363,9 @@ 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 63e6263fe..e912475b8 100644 --- a/conf/spgwu.json +++ b/conf/spgwu.json @@ -8,10 +8,13 @@ "": "max UE sessions", "max_sessions": 50000, - "": "max IP frag table entries (for IPv4 reassembly)", - "max_ip_defrag_flows": 1000, + "": "max IP frag table entries (for IPv4 reassembly). Update the line below to `\"max_ip_defrag_flows\": 5000` to enable", + "": "max_ip_defrag_flows: 1000", - "": "Gateway interfaces", + "": "Update the line below to `\"ip_frag_flows\": 1` to enable", + "": "ip_frag_flows: 1", + + "": "Gateway interfaces", "s1u": { "ifname": "ens803f2" }, From 8beb9be109c90194ddbc29a2b18dc06297d8ef5c Mon Sep 17 00:00:00 2001 From: Muhammad Asim Jamshed Date: Fri, 10 Apr 2020 20:09:00 -0700 Subject: [PATCH 3/5] Add logic for UE Natting (for IPv4 traffic). Signed-off-by: Muhammad Asim Jamshed --- conf/spgwu.bess | 62 ++++++++++++++++++++++++++++++++++++++----------- conf/spgwu.json | 4 +++- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/conf/spgwu.bess b/conf/spgwu.bess index a713245c0..64542dae9 100644 --- a/conf/spgwu.bess +++ b/conf/spgwu.bess @@ -45,7 +45,7 @@ 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 = 0 +MEASURE = bool(int($MEASURE!'0')) def scan_dpdk_ports(): @@ -71,7 +71,7 @@ def scan_dpdk_ports(): class Port: - def __init__(self, name): + def __init__(self, name, nat, ext_addr): self.name = name self.wid = None self.fpi = None @@ -79,6 +79,8 @@ class Port: self.bpf = None self.bpfgate = 0 self.routes_table = None + self.nat = nat + self.ext_addr = ext_addr def bpf_gate(self): if self.bpfgate < MAX_GATES - 2: @@ -191,15 +193,27 @@ class Port: if ip_frag_flows is not None: frag = __bess_module__("{}IP4Frag".format(name), 'IPFrag') if MEASURE == 1: - merge -> frag:1 -> Measure(latency_ns_resolution=1, latency_ns_max=100000) -> self.fpo + 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: - merge -> frag:1 -> self.fpo + if self.nat is not None: + merge -> 0:self.nat:1 -> frag:1 -> self.fpo + else: + merge -> frag:1 -> self.fpo frag:0 -> Sink() else: if MEASURE == 1: - merge -> Measure(latency_ns_resolution=1, latency_ns_max=100000) -> self.fpo + 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: - merge -> self.fpo + if self.nat is not None: + merge -> 0:self.nat:1 -> self.fpo + else: + merge -> self.fpo tc = 'slow{}'.format(wid) try: @@ -260,8 +274,18 @@ for wid in xrange(workers): interfaces = ["s1u", "sgi"] ports = {} + for idx, interface in enumerate(interfaces): - port = Port(conf[interface]["ifname"]) + 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) if port.name in ports: continue port.setup_port(idx, workers) @@ -270,6 +294,7 @@ for idx, interface in enumerate(interfaces): s1u_ifname = conf["s1u"]["ifname"] sgi_ifname = conf["sgi"]["ifname"] + # ==================================================== # Downlink Pipeline # ==================================================== @@ -285,15 +310,26 @@ except ValueError: # Setting filter to detect UE subnet sgiFastBPF = ports[sgi_ifname].bpf UEGate = ports[sgi_ifname].bpf_gate() -ue_filter = {"priority": -UEGate, - "filter": "ip dst net {}".format(ue_cidr), "gate": UEGate} +if ports[sgi_ifname].nat is not None: + ue_filter = {"priority": -UEGate, + "filter": "ip dst {}".format(ports[sgi_ifname].ext_addr), "gate": UEGate} +else: + ue_filter = {"priority": -UEGate, + "filter": "ip dst net {}".format(ue_cidr), "gate": UEGate} sgiFastBPF.add(filters=[ue_filter]) -# 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) +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: - sgiFastBPF:UEGate -> EtherTrim::GenericDecap(bytes=14) + # 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) EtherTrim -> GTPUEncap::GtpuEncap(s1u_sgw_ip=ip2long(ips_by_interface(s1u_ifname)[0]), num_subscribers=max_sessions):1 \ -> S1UEtherAdd::GenericEncap(fields=[ diff --git a/conf/spgwu.json b/conf/spgwu.json index e912475b8..9b0654d88 100644 --- a/conf/spgwu.json +++ b/conf/spgwu.json @@ -19,8 +19,10 @@ "ifname": "ens803f2" }, + "": "UE IP Natting. Update the line below to `\"ip_masquerade\": \"\"` to enable", "sgi": { - "ifname": "ens803f3" + "ifname": "ens803f3", + "": "ip_masquerade: 18.0.0.1" }, "": "Number of worker threads. Default: use 1 thread to run both (uplink/downlink) pipelines", From 44df8a2ee275cc3de86ddc27672716ed911f1607 Mon Sep 17 00:00:00 2001 From: Muhammad Asim Jamshed Date: Wed, 15 Apr 2020 14:14:01 -0700 Subject: [PATCH 4/5] Add mtu option for IPFrag module. Signed-off-by: Muhammad Asim Jamshed --- conf/spgwu.bess | 131 +++++++++++++++------------ conf/spgwu.json | 9 +- core/modules/ip_frag.cc | 21 +++-- core/modules/ip_frag.h | 7 +- core/modules/nat.h | 182 ++++++++++++++++++++++++++++++++++++++ protobuf/module_msg.proto | 15 +++- 6 files changed, 296 insertions(+), 69 deletions(-) create mode 100644 core/modules/nat.h diff --git a/conf/spgwu.bess b/conf/spgwu.bess index 64542dae9..7946664e4 100644 --- a/conf/spgwu.bess +++ b/conf/spgwu.bess @@ -26,13 +26,22 @@ 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"]) +IPHDRSZ=20 +UDPHDRSZ=8 +GTPHDRSZ=8 +MEASUREHDRSZ=12 +MEASURE_OFFSET=(IPHDRSZ + UDPHDRSZ + GTPHDRSZ + MEASUREHDRSZ) # ==================================================== @@ -42,10 +51,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 +76,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 +84,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: @@ -111,11 +118,9 @@ class Port: self.bpf = __bess_module__("{}FastBPF".format(name), 'BPF') self.bpf.clear() - # Reassemble IP4 fragments (if needed) - defrag = __bess_module__("{}IP4Defrag".format(name), 'IPDefrag', num_flows=max_ip_defrag_flows, numa=0) # 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() @@ -190,30 +195,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: @@ -278,14 +283,20 @@ 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) @@ -318,20 +329,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))}}, @@ -342,8 +357,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() + # ==================================================== @@ -381,6 +395,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) @@ -399,8 +415,7 @@ s1uFastBPF:GTPUEchoGate \ # Drop unknown packets GTPUEcho:0 -> Sink() GTPUDecap:0 -> Sink() -if max_ip_defrag_flows is not None: - s1uIP4Defrag:0 -> Sink() + # ==================================================== diff --git a/conf/spgwu.json b/conf/spgwu.json index 9b0654d88..ae7326802 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/core/modules/ip_frag.cc b/core/modules/ip_frag.cc index fcebd9ae2..71335e370 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 under two conditions: (1) if the packet failed to fragment due to e.g., * DF bit on and IP4 datagram size > MTU, or (2) if the packet successfully fragmented @@ -33,7 +35,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; @@ -62,7 +64,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()); @@ -150,6 +152,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() { @@ -161,10 +168,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 b4b19587c..1315594a4 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/core/modules/nat.h b/core/modules/nat.h new file mode 100644 index 000000000..a43d34a86 --- /dev/null +++ b/core/modules/nat.h @@ -0,0 +1,182 @@ +// Copyright (c) 2016-2017, Nefeli Networks, Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the names of the copyright holders nor the names of their +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#ifndef BESS_MODULES_NAT_H_ +#define BESS_MODULES_NAT_H_ + +#include "../module.h" +#include "../pb/module_msg.pb.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "../utils/cuckoo_map.h" +#include "../utils/endian.h" +#include "../utils/random.h" + +// Theory of operation: +// +// Definitions: +// Endpoint = +// Forward direction = outbound (internal -> external) +// Reverse direction = inbound (external -> internal) +// +// There is a single hash table of Endpoint -> (Endpoint, timestamp), which +// contains both forward and reverse mapping. They have the same lifespan. +// (e.g., if one entry is deleted, its peer is also deleted) +// +// Suppose the table is empty, and we see a packet A:a ===> B:b. +// Then we find a free external endpoint A':a' for the internal endpoint A:a +// from the pool and create two entries: +// - entry 1 A:a -> A':a' +// - entry 2 A':a' -> A:a +// Then the packet is updated to A':a' ===> B:b (with entry 1). +// When a return packet B:b ===> A':a' comes in, the destination (since it is +// reverse dir) endpoint is B:b ===> A:a (with entry 2). + +using bess::utils::be16_t; +using bess::utils::be32_t; + +struct alignas(8) Endpoint { + be32_t addr; + + // TCP/UDP port number or ICMP identifier + be16_t port; + + // L4 protocol (IPPROTO_*). Note that this is a 1-byte field in the IP header, + // but we store the value in a 2-byte field so that the struct be 8-byte long + // without a hole, without needing to initialize it explicitly. + uint16_t protocol; + + struct Hash { + std::size_t operator()(const Endpoint &e) const { +#if __x86_64 + return crc32c_sse42_u64( + (static_cast(e.addr.raw_value()) << 32) | + (static_cast(e.port.raw_value()) << 16) | + static_cast(e.protocol), + 0); +#else + return rte_hash_crc(&e, sizeof(uint64_t), 0); +#endif + } + }; + + struct EqualTo { + bool operator()(const Endpoint &lhs, const Endpoint &rhs) const { + const union { + Endpoint endpoint; + uint64_t u64; + } &left = {.endpoint = lhs}, &right = {.endpoint = rhs}; + + return left.u64 == right.u64; + } + }; +}; + +static_assert(sizeof(Endpoint) == sizeof(uint64_t), "Incorrect Endpoint"); + +struct NatEntry { + Endpoint endpoint; + + // last_refresh is only updated for forward-direction (outbound) packets, as + // per rfc4787 REQ-6. Reverse entries will have an garbage value. + // We do lazy reclaim of expired; NAT mapping entry will NOT expire unless it + // runs out of ports in the pool. + uint64_t last_refresh; // in nanoseconds (ctx.current_ns) +}; + +// Port ranges are used to scale out the NAT. +struct PortRange { + // Start of port range. + uint16_t begin; + // End of port range (exclusive). + uint16_t end; + // Is range usable, i.e., can we safely give out ports. + bool suspended; +}; + +// NAT module. 2 igates and 2 ogates +// igate/ogate 0: forward dir +// igate/ogate 1: reverse dir +class NAT final : public Module { + public: + NAT() { max_allowed_workers_ = Worker::kMaxWorkers; } + enum Direction { + kForward = 0, // internal -> external + kReverse = 1, // external -> internal + }; + + static const gate_idx_t kNumIGates = 2; + static const gate_idx_t kNumOGates = 2; + + static const Commands cmds; + + CommandResponse Init(const bess::pb::NATArg &arg); + CommandResponse GetInitialArg(const bess::pb::EmptyArg &arg); + CommandResponse GetRuntimeConfig(const bess::pb::EmptyArg &arg); + CommandResponse SetRuntimeConfig(const bess::pb::EmptyArg &arg); + + void ProcessBatch(Context *ctx, bess::PacketBatch *batch) override; + + // returns the number of active NAT entries (flows) + std::string GetDesc() const override; + + private: + using HashTable = bess::utils::CuckooMap; + + // 5 minutes for entry expiration (rfc4787 REQ-5-c) + static const uint64_t kTimeOutNs = 300ull * 1000 * 1000 * 1000; + + // how many times shall we try to find a free port number? + static const int kMaxTrials = 128; + + HashTable::Entry *CreateNewEntry(const Endpoint &internal, uint64_t now); + + template + void DoProcessBatch(Context *ctx, bess::PacketBatch *batch); + + std::vector ext_addrs_; + + // Port ranges available for each address. The first index is the same as the + // ext_addrs_ range. + std::vector> port_ranges_; + + HashTable map_; + Random rng_; +}; + +#endif // BESS_MODULES_NAT_H_ diff --git a/protobuf/module_msg.proto b/protobuf/module_msg.proto index 973ec5a55..a164340da 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; } /** From ab1f6929fdffb473b8735e7d3c602364b3c89db7 Mon Sep 17 00:00:00 2001 From: Muhammad Asim Jamshed Date: Sun, 19 Apr 2020 02:29:50 -0700 Subject: [PATCH 5/5] Added GetDesc() logic in GtpuEncap and GtpuDecap. Also patched up a small fix w.r.t. removing a session. Signed-off-by: Muhammad Asim Jamshed --- Dockerfile | 1 - README.md | 1 + conf/spgwu.bess | 49 +- conf/spgwu.json | 4 +- core/modules/gtpu_decap.cc | 6 + core/modules/gtpu_decap.h | 2 + core/modules/gtpu_encap.cc | 14 +- core/modules/gtpu_encap.h | 2 + core/modules/ip_frag.cc | 6 +- core/modules/ip_lookup.cc | 298 ---- core/modules/ip_lookup.h | 81 -- core/modules/l4_checksum.h | 45 - core/modules/nat.h | 182 --- cpiface/zmq-cpiface.cc | 2 +- ...-Add-2-workers-support-to-Nat-module.patch | 25 + ...B-routing-support-in-IPLookup-module.patch | 180 +++ ...-Add-more-gates-to-L4Checksum-module.patch | 25 + ...e-Packet-Metadata-for-Measure-module.patch | 79 ++ ...dded-module-messages-for-new-modules.patch | 104 ++ protobuf/module_msg.proto | 1257 ----------------- 20 files changed, 464 insertions(+), 1899 deletions(-) delete mode 100644 core/modules/ip_lookup.cc delete mode 100644 core/modules/ip_lookup.h delete mode 100644 core/modules/l4_checksum.h delete mode 100644 core/modules/nat.h create mode 100644 patches/bess/0001-Add-2-workers-support-to-Nat-module.patch create mode 100644 patches/bess/0003-Add-FIB-routing-support-in-IPLookup-module.patch create mode 100644 patches/bess/0004-Add-more-gates-to-L4Checksum-module.patch create mode 100644 patches/bess/0006-Use-Packet-Metadata-for-Measure-module.patch create mode 100644 patches/bess/0007-Added-module-messages-for-new-modules.patch delete mode 100644 protobuf/module_msg.proto diff --git a/Dockerfile b/Dockerfile index 7eaf2c908..f89504a12 100644 --- a/Dockerfile +++ b/Dockerfile @@ -57,7 +57,6 @@ RUN wget -qO bess.zip https://github.com/NetSys/bess/archive/${BESS_COMMIT}.zip WORKDIR bess-${BESS_COMMIT} COPY core/modules/ core/modules/ COPY core/utils/ core/utils/ -COPY protobuf/ protobuf/ COPY patches/bess patches RUN cp -a ${DPDK_DIR} deps/dpdk-19.11.1 && \ cat patches/* | patch -p1 diff --git a/README.md b/README.md index a836f7c8d..491401ad5 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ reading from file /tmp/tmpUBTGau, link-type EN10MB (Ethernet) * Dynamic IP routing * Support for IPv4 datagrams reassembly * Support for IP packets fragmentation +* Support for UE IP NAT ### In Progress diff --git a/conf/spgwu.bess b/conf/spgwu.bess index 7946664e4..d589699d3 100644 --- a/conf/spgwu.bess +++ b/conf/spgwu.bess @@ -37,11 +37,6 @@ except KeyError: # See this link for details: ## https://github.com/NetSys/bess/blob/master/bessctl/module_tests/timestamp.py measure = bool(conf["measure"]) -IPHDRSZ=20 -UDPHDRSZ=8 -GTPHDRSZ=8 -MEASUREHDRSZ=12 -MEASURE_OFFSET=(IPHDRSZ + UDPHDRSZ + GTPHDRSZ + MEASUREHDRSZ) # ==================================================== @@ -76,7 +71,7 @@ def scan_dpdk_ports(): class Port: - def __init__(self, name, ext_addr, offset1, offset2): + def __init__(self, name, ext_addrs): self.name = name self.wid = None self.fpi = None @@ -85,9 +80,7 @@ class Port: self.bpfgate = 0 self.routes_table = None self.nat = None - self.ext_addr = ext_addr - self.msr_off1 = offset1 - self.msr_off2 = offset2 + self.ext_addrs = ext_addrs def bpf_gate(self): if self.bpfgate < MAX_GATES - 2: @@ -120,7 +113,7 @@ class Port: # Default drop when no matches if measure: - self.fpi -> Timestamp(offset=-(self.msr_off1)) -> self.bpf:0 -> Sink() + self.fpi -> Timestamp() -> self.bpf:0 -> Sink() else: self.fpi -> self.bpf:0 -> Sink() @@ -207,13 +200,23 @@ class Port: # Attach telemeric module (if enabled) if measure: - m = Measure(latency_ns_resolution=1, latency_ns_max=100000, offset=-(self.msr_off2)) + m = Measure() 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}]) + if self.ext_addrs is not None: + # Tokenize the string + addrs = self.ext_addrs.split(' or ') + # Make a list of ext_addr + nat_list = list() + for addr in addrs: + nat_dict = dict() + nat_dict['ext_addr'] = addr + nat_list.append(nat_dict) + + # Create the NAT module + self.nat = __bess_module__("{}NAT".format(conf[interface]["ifname"]), 'NAT', ext_addrs=nat_list) self.nat:1 -> out out = self.nat @@ -282,21 +285,11 @@ ports = {} for idx, interface in enumerate(interfaces): try: - ext_addr = conf[interface]["ip_masquerade"] + ext_addrs = conf[interface]["ip_masquerade"] except KeyError: - ext_addr = None - - 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) + ext_addrs = None + + port = Port(conf[interface]["ifname"], ext_addrs) if port.name in ports: continue port.setup_port(idx, workers) @@ -323,7 +316,7 @@ sgiFastBPF = ports[sgi_ifname].bpf UEGate = ports[sgi_ifname].bpf_gate() if ports[sgi_ifname].nat is not None: ue_filter = {"priority": -UEGate, - "filter": "ip dst {}".format(ports[sgi_ifname].ext_addr), "gate": UEGate} + "filter": "ip dst {}".format(ports[sgi_ifname].ext_addrs), "gate": UEGate} else: ue_filter = {"priority": -UEGate, "filter": "ip dst net {}".format(ue_cidr), "gate": UEGate} diff --git a/conf/spgwu.json b/conf/spgwu.json index ae7326802..8063849bf 100644 --- a/conf/spgwu.json +++ b/conf/spgwu.json @@ -22,10 +22,10 @@ "ifname": "ens803f2" }, - "": "UE IP Natting. Update the line below to `\"ip_masquerade\": \"\"` to enable", + "": "UE IP Natting. Update the line below to `\"ip_masquerade\": \" [or ]\"` to enable", "sgi": { "ifname": "ens803f3", - "": "ip_masquerade: 18.0.0.1" + "": "ip_masquerade: 18.0.0.1 or 18.0.0.2 or 18.0.0.3" }, "": "Number of worker threads. Default: use 1 thread to run both (uplink/downlink) pipelines", diff --git a/core/modules/gtpu_decap.cc b/core/modules/gtpu_decap.cc index 9f8576c6f..305f3ae0c 100644 --- a/core/modules/gtpu_decap.cc +++ b/core/modules/gtpu_decap.cc @@ -16,6 +16,8 @@ #include "utils/udp.h" /* for gtp header */ #include "utils/gtp.h" +/* for GetDesc() */ +#include "utils/format.h" #include /*----------------------------------------------------------------------------------*/ using bess::utils::be32_t; @@ -96,4 +98,8 @@ CommandResponse GtpuDecap::Init(const bess::pb::GtpuDecapArg &arg) { return CommandSuccess(); } /*----------------------------------------------------------------------------------*/ +std::string GtpuDecap::GetDesc() const { + return bess::utils::Format("%zu sessions", (size_t)rte_hash_count(session_map)); +} +/*----------------------------------------------------------------------------------*/ ADD_MODULE(GtpuDecap, "gtpu_decap", "first version of gtpu decap module") diff --git a/core/modules/gtpu_decap.h b/core/modules/gtpu_decap.h index 2c86699dd..b79dd85a3 100644 --- a/core/modules/gtpu_decap.h +++ b/core/modules/gtpu_decap.h @@ -19,6 +19,8 @@ class GtpuDecap final : public Module { CommandResponse Init(const bess::pb::GtpuDecapArg &arg); void ProcessBatch(Context *ctx, bess::PacketBatch *batch) override; + // returns the number of active UE sessions + std::string GetDesc() const override; private: struct rte_hash *session_map = NULL; diff --git a/core/modules/gtpu_encap.cc b/core/modules/gtpu_encap.cc index 3016ef9c0..c15e6b7d7 100644 --- a/core/modules/gtpu_encap.cc +++ b/core/modules/gtpu_encap.cc @@ -16,6 +16,8 @@ #include "utils/udp.h" /* for gtp header */ #include "utils/gtp.h" +/* for GetDesc() */ +#include "utils/format.h" #include /*----------------------------------------------------------------------------------*/ using bess::utils::be16_t; @@ -154,6 +156,7 @@ CommandResponse GtpuEncap::AddSessionRecord( << ToIpv4Address(be32_t(ueaddr)) << std::endl; return CommandFailure(ENOMEM, "Failed to insert session record"); } + return CommandSuccess(); } /*----------------------------------------------------------------------------------*/ @@ -205,8 +208,11 @@ CommandResponse GtpuEncap::ShowRecords(const bess::pb::EmptyArg &) { } /*----------------------------------------------------------------------------------*/ CommandResponse GtpuEncap::ShowCount(const bess::pb::EmptyArg &) { - std::cerr << "# of records: " << rte_hash_count(session_map) << std::endl; - return CommandSuccess(); + bess::pb::GtpuEncapArg arg; + arg.set_s1u_sgw_ip(0); + arg.set_num_subscribers(rte_hash_count(session_map)); + DLOG(INFO) << "# of records: " << rte_hash_count(session_map) << std::endl; + return CommandSuccess(arg); } /*----------------------------------------------------------------------------------*/ void GtpuEncap::ProcessBatch(Context *ctx, bess::PacketBatch *batch) { @@ -349,4 +355,8 @@ CommandResponse GtpuEncap::Init(const bess::pb::GtpuEncapArg &arg) { return CommandSuccess(); } /*----------------------------------------------------------------------------------*/ +std::string GtpuEncap::GetDesc() const { + return bess::utils::Format("%zu sessions", (size_t)rte_hash_count(session_map)); +} +/*----------------------------------------------------------------------------------*/ ADD_MODULE(GtpuEncap, "gtpu_encap", "first version of gtpu encap module") diff --git a/core/modules/gtpu_encap.h b/core/modules/gtpu_encap.h index 275556df3..4a9733016 100644 --- a/core/modules/gtpu_encap.h +++ b/core/modules/gtpu_encap.h @@ -39,6 +39,8 @@ class GtpuEncap final : public Module { CommandResponse ShowRecords(const bess::pb::EmptyArg &); CommandResponse ShowCount(const bess::pb::EmptyArg &); void ProcessBatch(Context *ctx, bess::PacketBatch *batch) override; + // returns the number of active UE sessions + std::string GetDesc() const override; private: int dp_session_create(struct session_info *entry); diff --git a/core/modules/ip_frag.cc b/core/modules/ip_frag.cc index 71335e370..eb669e5b0 100644 --- a/core/modules/ip_frag.cc +++ b/core/modules/ip_frag.cc @@ -153,8 +153,10 @@ 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(); + bess::pb::IPFragArg arg; + arg.set_mtu(eth_mtu); + DLOG(INFO) << "Ethernet MTU Size: " << eth_mtu << std::endl; + return CommandSuccess(arg); } /*----------------------------------------------------------------------------------*/ void diff --git a/core/modules/ip_lookup.cc b/core/modules/ip_lookup.cc deleted file mode 100644 index c45edcf8f..000000000 --- a/core/modules/ip_lookup.cc +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright (c) 2014-2016, The Regents of the University of California. -// Copyright (c) 2016-2017, Nefeli Networks, Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * Neither the names of the copyright holders nor the names of their -// contributors may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. - -#include "ip_lookup.h" - -#include -#include - -#include "../utils/bits.h" -#include "../utils/ether.h" -#include "../utils/format.h" -#include "../utils/ip.h" - -#define VECTOR_OPTIMIZATION 1 - -static inline int is_valid_gate(gate_idx_t gate) { - return (gate < MAX_GATES || gate == DROP_GATE); -} - -const Commands IPLookup::cmds = { - {"add", "IPLookupCommandAddArg", MODULE_CMD_FUNC(&IPLookup::CommandAdd), - Command::THREAD_UNSAFE}, - {"delete", "IPLookupCommandDeleteArg", MODULE_CMD_FUNC(&IPLookup::CommandDelete), - Command::THREAD_UNSAFE}, - {"clear", "EmptyArg", MODULE_CMD_FUNC(&IPLookup::CommandClear), - Command::THREAD_UNSAFE}}; - -CommandResponse IPLookup::Init(const bess::pb::IPLookupArg &arg) { -#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) - struct rte_lpm_config conf = { - .max_rules = arg.max_rules() ? arg.max_rules() : 1024, - .number_tbl8s = arg.max_tbl8s() ? arg.max_tbl8s() : 128, - .flags = 0, - }; -#else - conf.type = RTE_FIB_DIR24_8; - conf.default_nh = DROP_GATE; - conf.max_routes = arg.max_rules() ? (int)arg.max_rules() : 1024; - conf.dir24_8.nh_sz = RTE_FIB_DIR24_8_4B; - conf.dir24_8.num_tbl8 = arg.max_tbl8s() ? arg.max_tbl8s() : 128; -#endif - - default_gate_ = DROP_GATE; -#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) - lpm_ = rte_lpm_create(name().c_str(), /* socket_id = */ 0, &conf); -#else - lpm_ = rte_fib_create(name().c_str(), /* socket_id = */ 0, &conf); -#endif - - if (!lpm_) { - return CommandFailure(rte_errno, "DPDK error: %s", rte_strerror(rte_errno)); - } - - return CommandSuccess(); -} - -void IPLookup::DeInit() { - if (lpm_) { -#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) - rte_lpm_free(lpm_); -#else - rte_fib_free(lpm_); -#endif - } -} - -void IPLookup::ProcessBatch(Context *ctx, bess::PacketBatch *batch) { - using bess::utils::Ethernet; - using bess::utils::Ipv4; - - gate_idx_t default_gate = default_gate_; - - int cnt = batch->cnt(); - int i; - -#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) -#if VECTOR_OPTIMIZATION - // Convert endianness for four addresses at the same time - const __m128i bswap_mask = - _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3); - - /* 4 at a time */ - for (i = 0; i + 3 < cnt; i += 4) { - Ethernet *eth; - Ipv4 *ip; - - uint32_t a0, a1, a2, a3; - uint32_t next_hops[4]; - - __m128i ip_addr; - - eth = batch->pkts()[i]->head_data(); - ip = (Ipv4 *)(eth + 1); - a0 = ip->dst.raw_value(); - - eth = batch->pkts()[i + 1]->head_data(); - ip = (Ipv4 *)(eth + 1); - a1 = ip->dst.raw_value(); - - eth = batch->pkts()[i + 2]->head_data(); - ip = (Ipv4 *)(eth + 1); - a2 = ip->dst.raw_value(); - - eth = batch->pkts()[i + 3]->head_data(); - ip = (Ipv4 *)(eth + 1); - a3 = ip->dst.raw_value(); - - ip_addr = _mm_set_epi32(a3, a2, a1, a0); - ip_addr = _mm_shuffle_epi8(ip_addr, bswap_mask); - - rte_lpm_lookupx4(lpm_, ip_addr, next_hops, default_gate); - - EmitPacket(ctx, batch->pkts()[i], next_hops[0]); - EmitPacket(ctx, batch->pkts()[i + 1], next_hops[1]); - EmitPacket(ctx, batch->pkts()[i + 2], next_hops[2]); - EmitPacket(ctx, batch->pkts()[i + 3], next_hops[3]); - } -#endif - - /* process the rest one by one */ - for (; i < cnt; i++) { - Ethernet *eth; - Ipv4 *ip; - - uint32_t next_hop; - int ret; - - eth = batch->pkts()[i]->head_data(); - ip = (Ipv4 *)(eth + 1); - - ret = rte_lpm_lookup(lpm_, ip->dst.value(), &next_hop); - - if (ret == 0) { - EmitPacket(ctx, batch->pkts()[i], next_hop); - } else { - EmitPacket(ctx, batch->pkts()[i], default_gate); - } - } -#else /* RTE_VERSION >= 19.11 */ - Ethernet *eth; - Ipv4 *ip; - int ret; - uint32_t ip_list[cnt]; - uint64_t next_hops[cnt]; - - for (i = 0; i < cnt; i++) { - eth = batch->pkts()[i]->head_data(); - ip = (Ipv4 *)(eth + 1); - ip_list[i] = ip->dst.value(); - } - - ret = rte_fib_lookup_bulk(lpm_, ip_list, next_hops, cnt); - - if (ret != 0) - RunNextModule(ctx, batch); - else - for (i = 0; i < cnt; i++) { - EmitPacket(ctx, batch->pkts()[i], (next_hops[i] == DROP_GATE) ? default_gate_ : next_hops[i]); - } - USED(default_gate); -#endif -} - -ParsedPrefix IPLookup::ParseIpv4Prefix( - const std::string &prefix, uint64_t prefix_len) { - using bess::utils::Format; - be32_t net_addr; - be32_t net_mask; - - if (!prefix.length()) { - return std::make_tuple(EINVAL, "prefix' is missing", be32_t(0)); - } - if (!bess::utils::ParseIpv4Address(prefix, &net_addr)) { - return std::make_tuple(EINVAL, - Format("Invalid IP prefix: %s", prefix.c_str()), - be32_t(0)); - } - - if (prefix_len > 32) { - return std::make_tuple(EINVAL, - Format("Invalid prefix length: %" PRIu64, - prefix_len), - be32_t(0)); - } - - net_mask = be32_t(bess::utils::SetBitsLow(prefix_len)); - if ((net_addr & ~net_mask).value()) { - return std::make_tuple(EINVAL, - Format("Invalid IP prefix %s/%" PRIu64 " %x %x", - prefix.c_str(), prefix_len, net_addr.value(), - net_mask.value()), - be32_t(0)); - } - return std::make_tuple(0, "", net_addr); -} - -CommandResponse IPLookup::CommandAdd( - const bess::pb::IPLookupCommandAddArg &arg) { - gate_idx_t gate = arg.gate(); - uint64_t prefix_len = arg.prefix_len(); - ParsedPrefix prefix = ParseIpv4Prefix(arg.prefix(), prefix_len); - if (std::get<0>(prefix)) { - return CommandFailure(std::get<0>(prefix), "%s", - std::get<1>(prefix).c_str()); - } - - if (!is_valid_gate(gate)) { - return CommandFailure(EINVAL, "Invalid gate: %hu", gate); - } - - if (prefix_len == 0) { - default_gate_ = gate; - } else { - be32_t net_addr = std::get<2>(prefix); -#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) - int ret = rte_lpm_add(lpm_, net_addr.value(), prefix_len, gate); -#else - uint64_t next_hop = (uint64_t)gate; - int ret = rte_fib_add(lpm_, net_addr.value(), prefix_len, next_hop); -#endif - if (ret) { - return CommandFailure(-ret, "rpm_lpm_add() failed"); - } - } - - return CommandSuccess(); -} - -CommandResponse IPLookup::CommandDelete( - const bess::pb::IPLookupCommandDeleteArg &arg) { - uint64_t prefix_len = arg.prefix_len(); - ParsedPrefix prefix = ParseIpv4Prefix(arg.prefix(), prefix_len); - if (std::get<0>(prefix)) { - return CommandFailure(std::get<0>(prefix), "%s", - std::get<1>(prefix).c_str()); - } - - if (prefix_len == 0) { - default_gate_ = DROP_GATE; - } else { - be32_t net_addr = std::get<2>(prefix); -#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) - int ret = rte_lpm_delete(lpm_, net_addr.value(), prefix_len); -#else - int ret = rte_fib_delete(lpm_, net_addr.value(), prefix_len); -#endif - if (ret) { - return CommandFailure(-ret, "rpm_lpm_delete() failed"); - } - } - - return CommandSuccess(); -} - -CommandResponse IPLookup::CommandClear(const bess::pb::EmptyArg &) { -#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) - rte_lpm_delete_all(lpm_); -#else - /* rte_fib_delete_all(lpm_) does not exist! */ - rte_fib_free(lpm_); - - lpm_ = rte_fib_create(name().c_str(), /* socket_id = */ 0, &conf); - if (!lpm_) { - return CommandFailure(rte_errno, "DPDK error: %s", rte_strerror(rte_errno)); - } -#endif - return CommandSuccess(); -} - -ADD_MODULE(IPLookup, "ip_lookup", - "performs Longest Prefix Match on IPv4 packets") diff --git a/core/modules/ip_lookup.h b/core/modules/ip_lookup.h deleted file mode 100644 index a866ad085..000000000 --- a/core/modules/ip_lookup.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2014-2016, The Regents of the University of California. -// Copyright (c) 2016-2017, Nefeli Networks, Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * Neither the names of the copyright holders nor the names of their -// contributors may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. - -#ifndef BESS_MODULES_IPLOOKUP_H_ -#define BESS_MODULES_IPLOOKUP_H_ - -#include "../module.h" -#include "../pb/module_msg.pb.h" -#include "../utils/endian.h" -#include -#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) -#include -#else -#define USED(x) (void)(x) -extern "C" { -#include -} -#endif - -using bess::utils::be32_t; -using ParsedPrefix = std::tuple; - -class IPLookup final : public Module { - public: - static const gate_idx_t kNumOGates = MAX_GATES; - - static const Commands cmds; - - IPLookup() : Module(), lpm_(), default_gate_() { - max_allowed_workers_ = Worker::kMaxWorkers; - } - - CommandResponse Init(const bess::pb::IPLookupArg &arg); - - void DeInit() override; - - void ProcessBatch(Context *ctx, bess::PacketBatch *batch) override; - - CommandResponse CommandAdd(const bess::pb::IPLookupCommandAddArg &arg); - CommandResponse CommandDelete(const bess::pb::IPLookupCommandDeleteArg &arg); - CommandResponse CommandClear(const bess::pb::EmptyArg &arg); - - private: -#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) - struct rte_lpm *lpm_; -#else - struct rte_fib *lpm_; - struct rte_fib_conf conf; -#endif - gate_idx_t default_gate_; - ParsedPrefix ParseIpv4Prefix(const std::string &prefix, uint64_t prefix_len); -}; - -#endif // BESS_MODULES_IPLOOKUP_H_ diff --git a/core/modules/l4_checksum.h b/core/modules/l4_checksum.h deleted file mode 100644 index 8f0f7ac56..000000000 --- a/core/modules/l4_checksum.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2017, The Regents of the University of California. -// Copyright (c) 2017, Nefeli Networks, Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * Neither the names of the copyright holders nor the names of their -// contributors may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. - -#ifndef BESS_MODULES_L4_CHECKSUM_H_ -#define BESS_MODULES_L4_CHECKSUM_H_ - -#include "../module.h" - -// Compute L4 checksum on packet - -class L4Checksum final : public Module { - public: - L4Checksum() : Module() { max_allowed_workers_ = Worker::kMaxWorkers; } - static const gate_idx_t kNumIGates = MAX_GATES; - void ProcessBatch(Context *ctx, bess::PacketBatch *batch) override; -}; - -#endif // BESS_MODULES_L4_CHECKSUM_H_ diff --git a/core/modules/nat.h b/core/modules/nat.h deleted file mode 100644 index a43d34a86..000000000 --- a/core/modules/nat.h +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) 2016-2017, Nefeli Networks, Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * Neither the names of the copyright holders nor the names of their -// contributors may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. - -#ifndef BESS_MODULES_NAT_H_ -#define BESS_MODULES_NAT_H_ - -#include "../module.h" -#include "../pb/module_msg.pb.h" - -#include -#include - -#include -#include -#include -#include -#include - -#include "../utils/cuckoo_map.h" -#include "../utils/endian.h" -#include "../utils/random.h" - -// Theory of operation: -// -// Definitions: -// Endpoint = -// Forward direction = outbound (internal -> external) -// Reverse direction = inbound (external -> internal) -// -// There is a single hash table of Endpoint -> (Endpoint, timestamp), which -// contains both forward and reverse mapping. They have the same lifespan. -// (e.g., if one entry is deleted, its peer is also deleted) -// -// Suppose the table is empty, and we see a packet A:a ===> B:b. -// Then we find a free external endpoint A':a' for the internal endpoint A:a -// from the pool and create two entries: -// - entry 1 A:a -> A':a' -// - entry 2 A':a' -> A:a -// Then the packet is updated to A':a' ===> B:b (with entry 1). -// When a return packet B:b ===> A':a' comes in, the destination (since it is -// reverse dir) endpoint is B:b ===> A:a (with entry 2). - -using bess::utils::be16_t; -using bess::utils::be32_t; - -struct alignas(8) Endpoint { - be32_t addr; - - // TCP/UDP port number or ICMP identifier - be16_t port; - - // L4 protocol (IPPROTO_*). Note that this is a 1-byte field in the IP header, - // but we store the value in a 2-byte field so that the struct be 8-byte long - // without a hole, without needing to initialize it explicitly. - uint16_t protocol; - - struct Hash { - std::size_t operator()(const Endpoint &e) const { -#if __x86_64 - return crc32c_sse42_u64( - (static_cast(e.addr.raw_value()) << 32) | - (static_cast(e.port.raw_value()) << 16) | - static_cast(e.protocol), - 0); -#else - return rte_hash_crc(&e, sizeof(uint64_t), 0); -#endif - } - }; - - struct EqualTo { - bool operator()(const Endpoint &lhs, const Endpoint &rhs) const { - const union { - Endpoint endpoint; - uint64_t u64; - } &left = {.endpoint = lhs}, &right = {.endpoint = rhs}; - - return left.u64 == right.u64; - } - }; -}; - -static_assert(sizeof(Endpoint) == sizeof(uint64_t), "Incorrect Endpoint"); - -struct NatEntry { - Endpoint endpoint; - - // last_refresh is only updated for forward-direction (outbound) packets, as - // per rfc4787 REQ-6. Reverse entries will have an garbage value. - // We do lazy reclaim of expired; NAT mapping entry will NOT expire unless it - // runs out of ports in the pool. - uint64_t last_refresh; // in nanoseconds (ctx.current_ns) -}; - -// Port ranges are used to scale out the NAT. -struct PortRange { - // Start of port range. - uint16_t begin; - // End of port range (exclusive). - uint16_t end; - // Is range usable, i.e., can we safely give out ports. - bool suspended; -}; - -// NAT module. 2 igates and 2 ogates -// igate/ogate 0: forward dir -// igate/ogate 1: reverse dir -class NAT final : public Module { - public: - NAT() { max_allowed_workers_ = Worker::kMaxWorkers; } - enum Direction { - kForward = 0, // internal -> external - kReverse = 1, // external -> internal - }; - - static const gate_idx_t kNumIGates = 2; - static const gate_idx_t kNumOGates = 2; - - static const Commands cmds; - - CommandResponse Init(const bess::pb::NATArg &arg); - CommandResponse GetInitialArg(const bess::pb::EmptyArg &arg); - CommandResponse GetRuntimeConfig(const bess::pb::EmptyArg &arg); - CommandResponse SetRuntimeConfig(const bess::pb::EmptyArg &arg); - - void ProcessBatch(Context *ctx, bess::PacketBatch *batch) override; - - // returns the number of active NAT entries (flows) - std::string GetDesc() const override; - - private: - using HashTable = bess::utils::CuckooMap; - - // 5 minutes for entry expiration (rfc4787 REQ-5-c) - static const uint64_t kTimeOutNs = 300ull * 1000 * 1000 * 1000; - - // how many times shall we try to find a free port number? - static const int kMaxTrials = 128; - - HashTable::Entry *CreateNewEntry(const Endpoint &internal, uint64_t now); - - template - void DoProcessBatch(Context *ctx, bess::PacketBatch *batch); - - std::vector ext_addrs_; - - // Port ranges available for each address. The first index is the same as the - // ext_addrs_ range. - std::vector> port_ranges_; - - HashTable map_; - Random rng_; -}; - -#endif // BESS_MODULES_NAT_H_ diff --git a/cpiface/zmq-cpiface.cc b/cpiface/zmq-cpiface.cc index 1d4b809ad..d52d4a797 100644 --- a/cpiface/zmq-cpiface.cc +++ b/cpiface/zmq-cpiface.cc @@ -242,7 +242,7 @@ int main(int argc, char **argv) { BessClient b(CreateChannel(std::string(args.bessd_ip) + ":" + std::to_string(args.bessd_port), InsecureChannelCredentials())); - b.runRemoveCommand(rbuf.sess_entry.ue_addr.u.ipv4_addr, + b.runRemoveCommand(ntohl(rbuf.sess_entry.ue_addr.u.ipv4_addr), args.encapmod); std::map::iterator it = zmq_sess_map.find( SESS_ID(ntohl(rbuf.sess_entry.ue_addr.u.ipv4_addr), diff --git a/patches/bess/0001-Add-2-workers-support-to-Nat-module.patch b/patches/bess/0001-Add-2-workers-support-to-Nat-module.patch new file mode 100644 index 000000000..453f1a87e --- /dev/null +++ b/patches/bess/0001-Add-2-workers-support-to-Nat-module.patch @@ -0,0 +1,25 @@ +From fc91a830e221c306d1bc8aa96bade4617eae1fed Mon Sep 17 00:00:00 2001 +From: Muhammad Asim Jamshed +Date: Wed, 22 Apr 2020 12:55:37 -0700 +Subject: [PATCH] Add 2 workers support to Nat module. + +Signed-off-by: Muhammad Asim Jamshed +--- + core/modules/nat.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/core/modules/nat.h b/core/modules/nat.h +index ff29dbf5..4ec594de 100644 +--- a/core/modules/nat.h ++++ b/core/modules/nat.h +@@ -133,6 +133,7 @@ struct PortRange { + // igate/ogate 1: reverse dir + class NAT final : public Module { + public: ++ NAT() { max_allowed_workers_ = 2; } + enum Direction { + kForward = 0, // internal -> external + kReverse = 1, // external -> internal +-- +2.25.1 + diff --git a/patches/bess/0003-Add-FIB-routing-support-in-IPLookup-module.patch b/patches/bess/0003-Add-FIB-routing-support-in-IPLookup-module.patch new file mode 100644 index 000000000..d98af5dc6 --- /dev/null +++ b/patches/bess/0003-Add-FIB-routing-support-in-IPLookup-module.patch @@ -0,0 +1,180 @@ +From 06c0b21b92bda80304ec3c0fc679d1fa0800f287 Mon Sep 17 00:00:00 2001 +From: Muhammad Asim Jamshed +Date: Wed, 22 Apr 2020 12:50:58 -0700 +Subject: [PATCH] Add FIB routing support in IPLookup module. + +Signed-off-by: Muhammad Asim Jamshed +--- + core/modules/ip_lookup.cc | 61 +++++++++++++++++++++++++++++++++++++-- + core/modules/ip_lookup.h | 14 +++++++++ + 2 files changed, 73 insertions(+), 2 deletions(-) + +diff --git a/core/modules/ip_lookup.cc b/core/modules/ip_lookup.cc +index 3c8b1157..c45edcf8 100644 +--- a/core/modules/ip_lookup.cc ++++ b/core/modules/ip_lookup.cc +@@ -32,7 +32,6 @@ + + #include + #include +-#include + + #include "../utils/bits.h" + #include "../utils/ether.h" +@@ -54,15 +53,26 @@ const Commands IPLookup::cmds = { + Command::THREAD_UNSAFE}}; + + CommandResponse IPLookup::Init(const bess::pb::IPLookupArg &arg) { ++#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) + struct rte_lpm_config conf = { + .max_rules = arg.max_rules() ? arg.max_rules() : 1024, + .number_tbl8s = arg.max_tbl8s() ? arg.max_tbl8s() : 128, + .flags = 0, + }; ++#else ++ conf.type = RTE_FIB_DIR24_8; ++ conf.default_nh = DROP_GATE; ++ conf.max_routes = arg.max_rules() ? (int)arg.max_rules() : 1024; ++ conf.dir24_8.nh_sz = RTE_FIB_DIR24_8_4B; ++ conf.dir24_8.num_tbl8 = arg.max_tbl8s() ? arg.max_tbl8s() : 128; ++#endif + + default_gate_ = DROP_GATE; +- ++#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) + lpm_ = rte_lpm_create(name().c_str(), /* socket_id = */ 0, &conf); ++#else ++ lpm_ = rte_fib_create(name().c_str(), /* socket_id = */ 0, &conf); ++#endif + + if (!lpm_) { + return CommandFailure(rte_errno, "DPDK error: %s", rte_strerror(rte_errno)); +@@ -73,7 +83,11 @@ CommandResponse IPLookup::Init(const bess::pb::IPLookupArg &arg) { + + void IPLookup::DeInit() { + if (lpm_) { ++#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) + rte_lpm_free(lpm_); ++#else ++ rte_fib_free(lpm_); ++#endif + } + } + +@@ -86,6 +100,7 @@ void IPLookup::ProcessBatch(Context *ctx, bess::PacketBatch *batch) { + int cnt = batch->cnt(); + int i; + ++#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) + #if VECTOR_OPTIMIZATION + // Convert endianness for four addresses at the same time + const __m128i bswap_mask = +@@ -148,6 +163,29 @@ void IPLookup::ProcessBatch(Context *ctx, bess::PacketBatch *batch) { + EmitPacket(ctx, batch->pkts()[i], default_gate); + } + } ++#else /* RTE_VERSION >= 19.11 */ ++ Ethernet *eth; ++ Ipv4 *ip; ++ int ret; ++ uint32_t ip_list[cnt]; ++ uint64_t next_hops[cnt]; ++ ++ for (i = 0; i < cnt; i++) { ++ eth = batch->pkts()[i]->head_data(); ++ ip = (Ipv4 *)(eth + 1); ++ ip_list[i] = ip->dst.value(); ++ } ++ ++ ret = rte_fib_lookup_bulk(lpm_, ip_list, next_hops, cnt); ++ ++ if (ret != 0) ++ RunNextModule(ctx, batch); ++ else ++ for (i = 0; i < cnt; i++) { ++ EmitPacket(ctx, batch->pkts()[i], (next_hops[i] == DROP_GATE) ? default_gate_ : next_hops[i]); ++ } ++ USED(default_gate); ++#endif + } + + ParsedPrefix IPLookup::ParseIpv4Prefix( +@@ -201,7 +239,12 @@ CommandResponse IPLookup::CommandAdd( + default_gate_ = gate; + } else { + be32_t net_addr = std::get<2>(prefix); ++#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) + int ret = rte_lpm_add(lpm_, net_addr.value(), prefix_len, gate); ++#else ++ uint64_t next_hop = (uint64_t)gate; ++ int ret = rte_fib_add(lpm_, net_addr.value(), prefix_len, next_hop); ++#endif + if (ret) { + return CommandFailure(-ret, "rpm_lpm_add() failed"); + } +@@ -223,7 +266,11 @@ CommandResponse IPLookup::CommandDelete( + default_gate_ = DROP_GATE; + } else { + be32_t net_addr = std::get<2>(prefix); ++#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) + int ret = rte_lpm_delete(lpm_, net_addr.value(), prefix_len); ++#else ++ int ret = rte_fib_delete(lpm_, net_addr.value(), prefix_len); ++#endif + if (ret) { + return CommandFailure(-ret, "rpm_lpm_delete() failed"); + } +@@ -233,7 +280,17 @@ CommandResponse IPLookup::CommandDelete( + } + + CommandResponse IPLookup::CommandClear(const bess::pb::EmptyArg &) { ++#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) + rte_lpm_delete_all(lpm_); ++#else ++ /* rte_fib_delete_all(lpm_) does not exist! */ ++ rte_fib_free(lpm_); ++ ++ lpm_ = rte_fib_create(name().c_str(), /* socket_id = */ 0, &conf); ++ if (!lpm_) { ++ return CommandFailure(rte_errno, "DPDK error: %s", rte_strerror(rte_errno)); ++ } ++#endif + return CommandSuccess(); + } + +diff --git a/core/modules/ip_lookup.h b/core/modules/ip_lookup.h +index de020e7f..a866ad08 100644 +--- a/core/modules/ip_lookup.h ++++ b/core/modules/ip_lookup.h +@@ -34,6 +34,15 @@ + #include "../module.h" + #include "../pb/module_msg.pb.h" + #include "../utils/endian.h" ++#include ++#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) ++#include ++#else ++#define USED(x) (void)(x) ++extern "C" { ++#include ++} ++#endif + + using bess::utils::be32_t; + using ParsedPrefix = std::tuple; +@@ -59,7 +68,12 @@ class IPLookup final : public Module { + CommandResponse CommandClear(const bess::pb::EmptyArg &arg); + + private: ++#if RTE_VERSION < RTE_VERSION_NUM(19, 11, 0, 0) + struct rte_lpm *lpm_; ++#else ++ struct rte_fib *lpm_; ++ struct rte_fib_conf conf; ++#endif + gate_idx_t default_gate_; + ParsedPrefix ParseIpv4Prefix(const std::string &prefix, uint64_t prefix_len); + }; +-- +2.25.1 + diff --git a/patches/bess/0004-Add-more-gates-to-L4Checksum-module.patch b/patches/bess/0004-Add-more-gates-to-L4Checksum-module.patch new file mode 100644 index 000000000..9db1d8300 --- /dev/null +++ b/patches/bess/0004-Add-more-gates-to-L4Checksum-module.patch @@ -0,0 +1,25 @@ +From 5ae3a4f23f4ceff1e5938a76b5be523034357c3d Mon Sep 17 00:00:00 2001 +From: Muhammad Asim Jamshed +Date: Wed, 22 Apr 2020 12:56:18 -0700 +Subject: [PATCH] Add more gates to L4Checksum module. + +Signed-off-by: Muhammad Asim Jamshed +--- + core/modules/l4_checksum.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/core/modules/l4_checksum.h b/core/modules/l4_checksum.h +index 89388bab..15acbe90 100644 +--- a/core/modules/l4_checksum.h ++++ b/core/modules/l4_checksum.h +@@ -38,6 +38,7 @@ class L4Checksum final : public Module { + public: + L4Checksum() : Module() { max_allowed_workers_ = Worker::kMaxWorkers; } + ++ static const gate_idx_t kNumIGates = MAX_GATES; + void ProcessBatch(Context *ctx, bess::PacketBatch *batch) override; + }; + +-- +2.25.1 + diff --git a/patches/bess/0006-Use-Packet-Metadata-for-Measure-module.patch b/patches/bess/0006-Use-Packet-Metadata-for-Measure-module.patch new file mode 100644 index 000000000..c09c24897 --- /dev/null +++ b/patches/bess/0006-Use-Packet-Metadata-for-Measure-module.patch @@ -0,0 +1,79 @@ +From 897c5a063be06bc092a597a6385e8eb330d6454f Mon Sep 17 00:00:00 2001 +From: Muhammad Asim Jamshed +Date: Wed, 22 Apr 2020 12:52:16 -0700 +Subject: [PATCH] Use Packet Metadata for Measure module. + +Signed-off-by: Muhammad Asim Jamshed +--- + core/modules/measure.cc | 11 ++++++++--- + core/modules/timestamp.cc | 10 ++++++++-- + 2 files changed, 16 insertions(+), 5 deletions(-) + +diff --git a/core/modules/measure.cc b/core/modules/measure.cc +index 5d71d482..cd5c7e5d 100644 +--- a/core/modules/measure.cc ++++ b/core/modules/measure.cc +@@ -63,6 +63,7 @@ const Commands Measure::cmds = { + CommandResponse Measure::Init(const bess::pb::MeasureArg &arg) { + uint64_t latency_ns_max = arg.latency_ns_max(); + uint64_t latency_ns_resolution = arg.latency_ns_resolution(); ++ + if (latency_ns_max == 0) { + latency_ns_max = kDefaultMaxNs; + } +@@ -85,7 +86,9 @@ CommandResponse Measure::Init(const bess::pb::MeasureArg &arg) { + if (arg.offset()) { + offset_ = arg.offset(); + } else { +- offset_ = sizeof(Ethernet) + sizeof(Ipv4) + sizeof(Udp); ++ offset_ = INT_MAX; ++ using AccessMode = bess::metadata::Attribute::AccessMode; ++ AddMetadataAttr("timestamp", sizeof(uint64_t), AccessMode::kRead); + } + + if (arg.jitter_sample_prob()) { +@@ -111,8 +114,10 @@ void Measure::ProcessBatch(Context *ctx, bess::PacketBatch *batch) { + + int cnt = batch->cnt(); + for (int i = 0; i < cnt; i++) { +- uint64_t pkt_time; +- if (IsTimestamped(batch->pkts()[i], offset, &pkt_time)) { ++ uint64_t pkt_time = 0; ++ if (offset == INT_MAX) ++ pkt_time = get_attr(this, 0, batch->pkts()[i]); ++ if (pkt_time || IsTimestamped(batch->pkts()[i], offset, &pkt_time)) { + uint64_t diff; + + if (now_ns >= pkt_time) { +diff --git a/core/modules/timestamp.cc b/core/modules/timestamp.cc +index b2489c76..049df739 100644 +--- a/core/modules/timestamp.cc ++++ b/core/modules/timestamp.cc +@@ -65,8 +65,11 @@ CommandResponse Timestamp::Init(const bess::pb::TimestampArg &arg) { + if (arg.offset()) { + offset_ = arg.offset(); + } else { +- offset_ = sizeof(Ethernet) + sizeof(Ipv4) + sizeof(Udp); ++ offset_ = INT_MAX; ++ using AccessMode = bess::metadata::Attribute::AccessMode; ++ AddMetadataAttr("timestamp", sizeof(uint64_t), AccessMode::kWrite); + } ++ + return CommandSuccess(); + } + +@@ -77,7 +80,10 @@ void Timestamp::ProcessBatch(Context *ctx, bess::PacketBatch *batch) { + + int cnt = batch->cnt(); + for (int i = 0; i < cnt; i++) { +- timestamp_packet(batch->pkts()[i], offset, now_ns); ++ if (offset == INT_MAX) ++ set_attr(this, 0, batch->pkts()[i], now_ns); ++ else ++ timestamp_packet(batch->pkts()[i], offset, now_ns); + } + + RunNextModule(ctx, batch); +-- +2.25.1 + diff --git a/patches/bess/0007-Added-module-messages-for-new-modules.patch b/patches/bess/0007-Added-module-messages-for-new-modules.patch new file mode 100644 index 000000000..5639d3ba8 --- /dev/null +++ b/patches/bess/0007-Added-module-messages-for-new-modules.patch @@ -0,0 +1,104 @@ +From ef51d92e3e8660869ec2a226342fc7fe1842b2dc Mon Sep 17 00:00:00 2001 +From: Muhammad Asim Jamshed +Date: Wed, 22 Apr 2020 19:00:50 -0700 +Subject: [PATCH] Added module messages for new modules. + +Signed-off-by: Muhammad Asim Jamshed +--- + protobuf/module_msg.proto | 80 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 80 insertions(+) + +diff --git a/protobuf/module_msg.proto b/protobuf/module_msg.proto +index 2aeaf47e..716b3870 100644 +--- a/protobuf/module_msg.proto ++++ b/protobuf/module_msg.proto +@@ -982,6 +982,86 @@ message SourceArg { + uint64 pkt_size = 1; /// The size (in bytes) of packet data to produce. + } + ++/** ++ * The GtpuEcho module processes the GTPv1 echo packet and prepares ++ * corresponding IP packet containing GTP echo response. It assumes ++ * Recovery IE is always zero. ++ * ++ * __Input Gates__: 1 ++ * __Output Gates__: 1 ++ */ ++message GtpuEchoArg { ++ uint32 s1u_sgw_ip = 1; /// IP address of S1U interface ++} ++ ++/** ++ * The IPDefrag module scans the IP datagram and checks whether ++ * it is fragmented. It returns a fully reassembled datagram or ++ * an unfragmented IP datagram ++ * ++ * __Input Gates__: 1 ++ * __Output Gates__: 1 ++ */ ++message IPDefragArg { ++ uint32 num_flows = 1; /// max number of flows the module can handle ++ 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 ++ * ++ * __Input Gates__: 1 ++ * __Output Gates__: 2 ++ */ ++message GtpuDecapArg { ++ string ename = 1; /// name of gtpencap module ++} ++ ++/** ++ * The GtpuEncap module encapsulates an IP packet for tunnelling purposes ++ * ++ * __Input Gates__: 1 ++ * __Output Gates__: 1 ++ */ ++message GtpuEncapArg { ++ uint32 s1u_sgw_ip = 1; /// IP address of S1U interface ++ uint32 num_subscribers = 2; /// Number of subscribers limit ++} ++ ++/** ++ * The GtpuEncap module has a command `add(...)` which takes two ++ * parameters. This function accepts the teids, and UE IP address, and creates ++ * a session record. ++ * Example use in bessctl: `gencap.add(teid=0xf0000000, eteid=..., ueaddr=0x10000001, enodeb_ip=...)` ++ */ ++message GtpuEncapAddSessionRecordArg { ++ uint32 teid = 1; /// sgw tunnel endpoint identifier ++ uint32 eteid = 2; /// enodeb tunnel endpoint identifier ++ uint32 ueaddr = 3; /// ip address of UE ++ uint32 enodeb_ip = 4; /// enodeb ip address ++} ++ ++/** ++ * The GtpuEncap module has a command `remove(...)` which takes one ++ * parameter. This function accepts the ueaddr, and removes the ++ * respective session record. ++ * Example use in bessctl: `gencap.remove(ueaddr=0x10000001)` ++ */ ++message GtpuEncapRemoveSessionRecordArg { ++ uint32 ueaddr = 1; /// ip address of UE ++} ++ + /** + * The Split module is a basic classifier which directs packets out a gate + * based on data in the packet (e.g., if the read in value is 3, the packet +-- +2.25.1 + diff --git a/protobuf/module_msg.proto b/protobuf/module_msg.proto deleted file mode 100644 index a164340da..000000000 --- a/protobuf/module_msg.proto +++ /dev/null @@ -1,1257 +0,0 @@ -// Copyright (c) 2016-2017, Nefeli Networks, Inc. -// Copyright (c) 2017, The Regents of the University of California. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * Neither the names of the copyright holders nor the names of their -// contributors may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package bess.pb; -import "util_msg.proto"; - -// Module-specific messages. -// The header generated from this file should not be included in the BESS core -// source code. - -// For your comments to come out in the auto-documentation: -// Format comments with two stars at the top, or use three slashes (///) -// Anything you write will show up as markdown, so feel free to add italics, etc. - -/// The module_msg.proto file is stored in `bess/protobuf/` and it supplies the glue between -/// bessd modules and the outside world via GRPC. -/// bessctl uses GRPC to update modules. Whenever you call a function in bessctl, a corresponding function -/// is called on modules in bessd. This file lists all modules, their initialization parameters -/// and any functions that may be called on them. - -message EmptyArg { -} - -/** - * The BPF module has a command `clear()` that takes no parameters. - * This command removes all filters from the module. - */ -message BPFCommandClearArg { -} - -/** - * The ExactMatch module has a command `add(...)` that takes two parameters. - * The ExactMatch initializer specifies what fields in a packet to inspect; add() specifies - * which values to check for over these fields. - * add() inserts a new rule into the ExactMatch module such that traffic matching - * that bytestring will be forwarded - * out a specified gate. - * Example use: `add(fields=[aton('12.3.4.5'), aton('5.4.3.2')], gate=2)` - */ -message ExactMatchCommandAddArg { - uint64 gate = 1; /// The gate to forward out packets that mach this rule. - repeated FieldData fields = 2; /// The exact match values to check for -} - -/** - * The ExactMatch module has a command `delete(...)` which deletes an existing rule. - * Example use: `delete(fields=[aton('12.3.4.5'), aton('5.4.3.2')])` - */ -message ExactMatchCommandDeleteArg { - repeated FieldData fields = 2; /// The field values for the rule to be deleted. -} - -/** - * The ExactMatch module has a command `clear()` which takes no parameters. - * This command removes all rules from the ExactMatch module. - */ -message ExactMatchCommandClearArg { -} - -/** - * The ExactMatch module has a command `set_default_gate(...)` which takes one parameter. - * This command routes all traffic which does _not_ match a rule to a specified gate. - * Example use in bessctl: `setDefaultGate(gate=2)` - */ -message ExactMatchCommandSetDefaultGateArg { - uint64 gate = 1; /// The gate number to send the default traffic out. -} - -/** - * The FlowGen module has a command `set_burst(...)` that allows you to specify - * the maximum number of packets to be stored in a single PacketBatch released - * by the module. - */ -message FlowGenCommandSetBurstArg { - uint64 burst = 1; -} - -/** - * The HashLB module has a command `set_mode(...)` which takes two parameters. - * The `mode` parameter specifies whether the load balancer will hash over the - * src/dest ethernet header (`'l2'`), over the src/dest IP addresses (`'l3'`), or over - * the flow 5-tuple (`'l4'`). Alternatively, if the `fields` parameter is set, the - * load balancer will hash over the N-tuple with the specified offsets and - * sizes. - * Example use in bessctl: `lb.set_mode('l2')` - */ -message HashLBCommandSetModeArg { - string mode = 1; /// What fields to hash over, `'l2'`, `'l3'`, and `'l4'` are only valid values. - repeated Field fields = 2; /// A list of fields that define a custom tuple. -} - -/** - * The HashLB module has a command `set_gates(...)` which takes one parameter. - * This function takes in a list of gate numbers to send hashed traffic out over. - * Example use in bessctl: `lb.setGates(gates=[0,1,2,3])` - */ -message HashLBCommandSetGatesArg { - repeated int64 gates = 1; ///A list of gate numbers to load balance traffic over -} - -/** - * The IPLookup module has a command `add(...)` which takes three paramters. - * This function accepts the routing rules -- CIDR prefix, CIDR prefix length, - * and what gate to forward matching traffic out on. - * Example use in bessctl: `table.add(prefix='10.0.0.0', prefix_len=8, gate=2)` - */ -message IPLookupCommandAddArg { - string prefix = 1; /// The CIDR IP part of the prefix to match - uint64 prefix_len = 2; /// The prefix length - uint64 gate = 3; /// The number of the gate to forward matching traffic on. -} - -/** - * The IPLookup module has a command `delete(...)` which takes two paramters. - * This function accepts the routing rules -- CIDR prefix, CIDR prefix length, - * Example use in bessctl: `table.delete(prefix='10.0.0.0', prefix_len=8)` - */ -message IPLookupCommandDeleteArg { - string prefix = 1; /// The CIDR IP part of the prefix to match - uint64 prefix_len = 2; /// The prefix length -} - -/** - * The IPLookup module has a command `clear()` which takes no parameters. - * This function removes all rules in the IPLookup table. - * Example use in bessctl: `myiplookuptable.clear()` - */ -message IPLookupCommandClearArg { -} - -/** - * The L2Forward module forwards traffic via exact match over the Ethernet - * destination address. The command `add(...)` allows you to specifiy a - * MAC address and which gate the L2Forward module should direct it out of. - */ -message L2ForwardCommandAddArg { - message Entry { - string addr = 1; /// The MAC address to match - int64 gate = 2; /// Which gate to send out traffic matching this address. - } - repeated Entry entries = 1; /// A list of L2Forward entries. -} - -/** - * The L2Forward module has a function `delete(...)` to remove a rule - * from the MAC forwarding table. - */ -message L2ForwardCommandDeleteArg { - repeated string addrs = 1; /// The address to remove from the forwarding table -} - -/** - * For traffic reaching the L2Forward module which does not match a MAC rule, - * the function `set_default_gate(...)` allows you to specify a default gate - * to direct unmatched traffic to. - */ -message L2ForwardCommandSetDefaultGateArg { - int64 gate = 1; /// The default gate to forward traffic which matches no entry to. -} - -/** - * The L2Forward module has a function `lookup(...)` to query what output gate - * a given MAC address will be forwared to; it returns the gate ID number. - */ -message L2ForwardCommandLookupArg { - repeated string addrs = 1; /// The MAC address to query for -} - -/** - * This message type provides the reponse to the L2Forward function `lookup(..)`. - * It returns the gate that a requested MAC address is currently assigned to. - */ -message L2ForwardCommandLookupResponse { - repeated uint64 gates = 1; /// The gate ID that the requested MAC address maps to -} - -/** - * The L2Forward module has a command `populate(...)` which allows for fast creation - * of the forwarding table given a range of MAC addresses. The function takes in a - * 'base' MAC address, a count (number of MAC addresses), and a gate_id. The module - * will route all MAC addresses starting from the base address, up to base+count address - * round-robin over gate_count total gates. - * For example, `populate(base='11:22:33:44:00', count = 10, gate_count = 2) would - * route addresses 11:22:33:44::(00, 02, 04, 06, 08) out a gate 0 and the odd-suffixed - * addresses out gate 1. - */ -message L2ForwardCommandPopulateArg { - string base = 1; /// The base MAC address - int64 count = 2; /// How many addresses beyond base to populate into the routing table - int64 gate_count = 3; /// How many gates to create in the L2Forward module. -} - -/** - * The Measure module measures and collects latency/jitter data for packets - * annotated by a Timestamp module. Note that Timestamp and Measure module must reside - * on the server for accurate measurement (as a result, the most typical use case is - * measuring roundtrip time). - * Optionally, you can also retrieve percentile values by specifying points in - * "percentiles". For example, "percentiles" of [50.0, 99.0] will return - * [median, 99'th %-ile tail latency] in "percentile_values_ns" in the response. - */ -message MeasureCommandGetSummaryArg { - bool clear = 1; /// if true, the data will be all cleared after read - repeated double latency_percentiles = 2; /// ascending list of real numbers in [0.0, 100.0] - repeated double jitter_percentiles = 3; /// ascending list of real numbers in [0.0, 100.0] -} - -/** - * The Measure module function `get_summary()` returns the following values. - * Note that the resolution value tells you how grainy the samples are, - * e.g., 100 means that anything from 0-99 ns counts as "0", - * anything from 100-199 counts as "100", and so on. The average - * is of samples using this graininess, but (being a result of division) - * may not be a multiple of the resolution. - */ -message MeasureCommandGetSummaryResponse { - message Histogram { - uint64 count = 1; /// Total # of measured data points, including above_range - uint64 above_range = 2; /// # of data points for the "too large value" bucket - uint64 resolution_ns = 8; /// resolution of measured data - uint64 min_ns = 3; - uint64 avg_ns = 4; - uint64 max_ns = 5; - uint64 total_ns = 6; - repeated uint64 percentile_values_ns = 7; - } - - double timestamp = 1; /// Seconds since boot. - uint64 packets = 2; /// Total # of packets seen by this module. - uint64 bits = 3; /// Total # of bits seen by this module. - Histogram latency = 4; - Histogram jitter = 5; -} - - -/** - * The Module DRR provides fair scheduling of flows based on a quantum which is - * number of bytes allocated to each flow on each round of going through all flows. - * Examples can be found [./bessctl/conf/samples/drr.bess] - * - * __Input_Gates__: 1 - * __Output_Gates__: 1 - */ -message DRRArg { - uint32 num_flows = 1; /// Number of flows to handle in module - uint64 quantum = 2; /// the number of bytes to allocate to each on every round - uint32 max_flow_queue_size = 3; /// the max size that any Flows queue can get -} - -/** - * the SetQuantumSize function sets a new quantum for DRR module to operate on. - */ -message DRRQuantumArg { - uint32 quantum = 1; /// the number of bytes to allocate to each on every round -} - -/** - * The SetMaxQueueSize function sets a new maximum flow queue size for DRR module. - * If the flow's queue gets to this size, the module starts dropping packets to - * that flow until the queue is below this size. - */ -message DRRMaxFlowQueueSizeArg { - uint32 max_queue_size = 1; /// the max size that any Flows queue can get -} - -/** - * The module PortInc has a function `set_burst(...)` that allows you to specify the - * maximum number of packets to be stored in a single PacketBatch released by - * the module. - */ -message PortIncCommandSetBurstArg { - uint64 burst = 1; /// The maximum "burst" of packets (ie, the maximum batch size) -} - -/** - * The module QueueInc has a function `set_burst(...)` that allows you to specify - * the maximum number of packets to be stored in a single PacketBatch released - * by the module. - */ -message QueueIncCommandSetBurstArg { - uint64 burst = 1; /// The maximum "burst" of packets (ie, the maximum batch size) -} - -/** - * The module Queue has a function `set_burst(...)` that allows you to specify - * the maximum number of packets to be stored in a single PacketBatch released - * by the module. - */ -message QueueCommandSetBurstArg { - uint64 burst = 1; /// The maximum "burst" of packets (ie, the maximum batch size) -} - -/** - * The module Queue has a function `set_size(...)` that allows specifying the - * size of the queue in total number of packets. - */ -message QueueCommandSetSizeArg { - uint64 size = 1; /// The maximum number of packets to store in the queue. -} - -/** - * Modules that are queues or contain queues may contain functions - * `get_status()` that return QueueCommandGetStatusResponse. - */ -message QueueCommandGetStatusArg {} - -/** - * Modules that are queues or contain queues may contain functions - * `get_status()` that take no parameters and returns the queue occupancy and - * size. - */ -message QueueCommandGetStatusResponse { - uint64 count = 1; /// The number of packets currently in the queue. - uint64 size = 2; /// The maximum number of packets the queue can contain. - uint64 enqueued = 3; /// total enqueued - uint64 dequeued = 4; /// total dequeued - uint64 dropped = 5; /// total dropped -} - -/** - * The function `clear()` for RandomUpdate takes no parameters and clears all - * state in the module. - */ -message RandomUpdateCommandClearArg { -} - -/** - * The function `clear()` for Rewrite takes no parameters and clears all state - * in the module. - */ -message RewriteCommandClearArg { -} - -/** - * The function `clear()` for Update takes no parameters and clears all state in - * the module. - */ -message UpdateCommandClearArg { -} - -/** - * The module WildcardMatch has a command `add(...)` which inserts a new rule - * into the WildcardMatch module. For an example of code using WilcardMatch see - * `bess/bessctl/conf/samples/wildcardmatch.bess`. - */ -message WildcardMatchCommandAddArg { - uint64 gate = 1; /// Traffic matching this new rule will be sent to this gate. - int64 priority = 2; ///If a packet matches multiple rules, the rule with higher priority will be applied. If priorities are equal behavior is undefined. - repeated FieldData values = 3; /// The values to check for in each field. - repeated FieldData masks = 4; /// The bitmask for each field -- set `0x0` to ignore the field altogether. -} - -/** - * The module WildcardMatch has a command `delete(...)` which removes a rule -- simply specify the values and masks from the previously inserted rule to remove them. - */ -message WildcardMatchCommandDeleteArg { - repeated FieldData values = 1; /// The values being checked for in the rule - repeated FieldData masks = 2; /// The bitmask from the rule. -} - -/** - * The function `clear()` for WildcardMatch takes no parameters, it clears - * all state in the WildcardMatch module (is equivalent to calling delete for all rules) - */ -message WildcardMatchCommandClearArg { -} - -/** - * For traffic which does not match any rule in the WildcardMatch module, - * the `set_default_gate(...)` function specifies which gate to send this extra traffic to. - */ -message WildcardMatchCommandSetDefaultGateArg { - uint64 gate = 1; -} - -/** - * The module ACL creates an access control module which by default blocks all traffic, unless it contains a rule which specifies otherwise. - * Examples of ACL can be found in [acl.bess](https://github.com/NetSys/bess/blob/master/bessctl/conf/samples/acl.bess) - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message ACLArg { - /** - * One ACL rule is represented by the following 6-tuple. - */ - message Rule { - string src_ip = 1; /// Source IP block in CIDR. Wildcard if "". - string dst_ip = 2; /// Destination IP block in CIDR. Wildcard if "". - uint32 src_port = 3; /// TCP/UDP source port. Wildcard if 0. - uint32 dst_port = 4; /// TCP/UDP Destination port. Wildcard if 0. - bool established = 5; /// Not implemented - bool drop = 6; /// Drop matched packets if true, forward if false. By default ACL drops all traffic. - } - repeated Rule rules = 1; ///A list of ACL rules. -} - -/** - * The BPF module is an access control module that sends packets out on a particular gate based on whether they match a BPF filter. - * - * __Input Gates__: 1 - * __Output Gates__: many (configurable) - */ -message BPFArg { - /** - * One BPF filter is represented by the following 3-tuple. - */ - message Filter { - int64 priority = 1; /// The priority level for this rule. If a packet matches multiple rules, it will be forwarded out the gate with the highest priority. If a packet matches multiple rules with the same priority, the behavior is undefined. - string filter = 2; /// The actual BPF string. - int64 gate = 3; ///What gate to forward packets that match this BPF to. - } - repeated Filter filters = 1; /// The BPF initialized function takes a list of BPF filters. -} - -/** - * The Buffer module takes no parameters to initialize (ie, `Buffer()` is sufficient to create one). - * Buffer accepts packets and stores them; it may forward them to the next module only after it has - * received enough packets to fill an entire PacketBatch. - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message BufferArg { -} - -/** - * The Bypass module forwards packets by emulating pre-defined packet processing overhead. - * It burns cpu cycles per_batch, per_packet, and per-bytes. - * Bypass is useful primarily for testing and performance evaluation. - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message BypassArg { - uint32 cycles_per_batch = 1; - uint32 cycles_per_packet = 2; - uint32 cycles_per_byte = 3; -} - -/** - * The Dump module blindly forwards packets without modifying them. It periodically samples a packet and prints out out to the BESS log (by default stored in `/tmp/bessd.INFO`). - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message DumpArg { - double interval = 1; ///How frequently to sample and print a packet, in seconds. -} - -/** - * The EtherEncap module wraps packets in an Ethernet header, but it takes no parameters. Instead, Ethernet source, destination, and type are pulled from a packet's metadata attributes. - * For example: `SetMetadata('dst_mac', 11:22:33:44:55) -> EtherEncap()` - * This is useful when upstream modules wish to assign a MAC address to a packet, e.g., due to an ARP request. - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message EtherEncapArg { -} - -/** - * The ExactMatch module splits packets along output gates according to exact match values in arbitrary packet fields. - * To instantiate an ExactMatch module, you must specify which fields in the packet to match over. You can add rules using the function `ExactMatch.add(...)` - * Fields may be stored either in the packet data or its metadata attributes. - * An example script using the ExactMatch code is found - * in [`bess/bessctl/conf/samples/exactmatch.bess`](https://github.com/NetSys/bess/blob/master/bessctl/conf/samples/exactmatch.bess). - * - * __Input Gates__: 1 - * __Output Gates__: many (configurable) - */ -message ExactMatchArg { - repeated Field fields = 1; ///A list of ExactMatch Fields - repeated FieldData masks = 2; /// mask(i) corresponds to the mask for field(i) -} - -/** - * ExactMatchConfig represents the current runtime configuration - * of an ExactMatch module, as returned by get_runtime_config and - * set by set_runtime_config. - */ -message ExactMatchConfig { - uint64 default_gate = 1; - repeated ExactMatchCommandAddArg rules = 2; -} - -/** - * The FlowGen module generates simulated TCP flows of packets with correct SYN/FIN flags and sequence numbers. - * This module is useful for testing, e.g., a NAT module or other flow-aware code. - * Packets are generated off a base, "template" packet by modifying the IP src/dst and TCP src/dst. By default, only the ports are changed and will be modified by incrementing the template ports by up to 20000 more than the template values. - * - * __Input Gates__: 0 - * __Output Gates__: 1 - */ -message FlowGenArg { - bytes template = 1; /// The packet "template". All data packets are derived from this template and contain the same payload. - double pps = 2; /// The total number of packets per second to generate. - double flow_rate = 3; /// The number of new flows to create every second. flow_rate must be <= pps. - double flow_duration = 4; /// The lifetime of a flow in seconds. - string arrival = 5; /// The packet arrival distribution -- must be either "uniform" or "exponential" - string duration = 6; /// The flow duration distribution -- must be either "uniform" or "pareto" - bool quick_rampup = 7; /// Whether or not to populate the flowgenerator with initial flows (start generating full pps rate immediately) or to wait for new flows to be generated naturally (all flows have a SYN packet). - uint32 ip_src_range = 8; /// When generating new flows, FlowGen modifies the template packet by changing the IP src, incrementing it by at most ip_src_range (e.g., if the base packet is 10.0.0.1 and range is 5, it will generate packets with IPs 10.0.0.1-10.0.0.6). - uint32 ip_dst_range = 9; /// When generating new flows, FlowGen modifies the template packet by changing the IP dst, incrementing it by at most ip_dst_range. - uint32 port_src_range = 10; /// When generating new flows, FlowGen modifies the template packet by changing the TCP port, incrementing it by at most port_src_range. - uint32 port_dst_range = 11; /// When generating new flows, FlowGen modifies the template packet by changing the TCP dst port, incrementing it by at most port_dst_range. -} - -/** - * The GenericDecap module strips off the first few bytes of data from a packet. - * - * __Input Gates__: 1 - * __Ouptut Gates__: 1 - */ -message GenericDecapArg { - uint64 bytes = 1; /// The number of bytes to strip off. -} - -/** - * The GenericEncap module adds a header to packets passing through it. - * Takes a list of fields. Each field is either: - * - * 1. {'size': X, 'value': Y} (for constant values) - * 2. {'size': X, 'attribute': Y} (for metadata attributes) - * - * e.g.: `GenericEncap([{'size': 4, 'value': 0xdeadbeef}, - * {'size': 2, 'attribute': 'foo'}, - * {'size': 2, 'value': 0x1234}])` - * will prepend a 8-byte header: - * `de ad be ef 12 34` - * where the 2-byte ` ` comes from the value of metadata attribute `'foo'` - * for each packet. - * An example script using GenericEncap is in [`bess/bessctl/conf/samples/generic_encap.bess`](https://github.com/NetSys/bess/blob/master/bessctl/conf/samples/generic_encap.bess). - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message GenericEncapArg { - /** - * An EncapField represents one field in the new packet header. - */ - message EncapField { - uint64 size = 1; /// The length of the field. - oneof insertion { - string attribute = 2; /// The metadata attribute name to pull the field value from - FieldData value = 3; /// Or, the fixed value to insert into the packet. - } - } - repeated EncapField fields = 1; -} - -/** - * The HashLB module partitions packets between output gates according to either - * a hash over their MAC src/dst (`mode='l2'`), their IP src/dst (`mode='l3'`), the full - * IP/TCP 5-tuple (`mode='l4'`), or the N-tuple defined by `fields`. - * - * __Input Gates__: 1 - * __Output Gates__: many (configurable) - */ -message HashLBArg { - repeated int64 gates = 1; /// A list of gate numbers over which to partition packets - string mode = 2; /// The mode (`'l2'`, `'l3'`, or `'l4'`) for the hash function. - repeated Field fields = 3; /// A list of fields that define a custom tuple. -} - -/** - * Encapsulates a packet with an IP header, where IP src, dst, and proto are filled in - * by metadata values carried with the packet. Metadata attributes must include: - * ip_src, ip_dst, ip_proto, ip_nexthop, and ether_type. - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message IPEncapArg { -} - -/** - * An IPLookup module perfroms LPM lookups over a packet destination. - * IPLookup takes no parameters to instantiate. - * To add rules to the IPLookup table, use `IPLookup.add()` - * - * __Input Gates__: 1 - * __Output Gates__: many (configurable, depending on rule values) - */ -message IPLookupArg { - uint32 max_rules = 1; /// Maximum number of rules (default: 1024) - uint32 max_tbl8s = 2; /// Maximum number of IP prefixes with smaller than /24 (default: 128) -} - -/** - * An L2Forward module forwards packets to an output gate according to exact-match rules over - * an Ethernet destination. - * Note that this is _not_ a learning switch -- forwards according to fixed - * routes specified by `add(..)`. - * - * __Input Gates__: 1 - * __Ouput Gates__: many (configurable, depending on rules) - */ -message L2ForwardArg { - int64 size = 1; /// Configures the forwarding hash table -- total number of hash table entries. - int64 bucket = 2; /// Configures the forwarding hash table -- total number of slots per hash value. -} - -/** - * The MACSwap module takes no arguments. It swaps the src/destination MAC addresses - * within a packet. - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message MACSwapArg { -} - -/** - * The measure module tracks latencies, packets per second, and other statistics. - * It should be paired with a Timestamp module, which attaches a timestamp to packets. - * The measure module will log how long (in nanoseconds) it has been for each packet it received since it was timestamped. - * This module is somewhat experimental and undergoing various changes. - * There is a test for the the Measure module in [`bessctl/module_tests/timestamp.py`](https://github.com/NetSys/bess/blob/master/bessctl/module_tests/timestamp.py). - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message MeasureArg { - // int64 warmup = 1; /// removed: instead of warmup delay, user should Clear() - 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) -} - -/** - * The merge module takes no parameters. It has multiple input gates, - * and passes out all packets from a single output gate. - * - * __Input Gates__: many (configurable) - * __Output Gates__: 1 - */ -message MergeArg { -} - -/** - * The MetadataTest module is used for internal testing purposes. - */ -message MetadataTestArg { - map read = 1; - map write = 2; - map update = 3; -} - -/** - * The NAT module implements Dynamic IPv4 address/port translation, - * rewriting packet source addresses with external addresses as specified, - * and destination addresses for packets on the reverse direction. - * L3/L4 checksums are updated correspondingly. - * To see an example of NAT in use, see: - * [`bess/bessctl/conf/samples/nat.bess`](https://github.com/NetSys/bess/blob/master/bessctl/conf/samples/nat.bess) - * - * Currently only supports TCP/UDP/ICMP. - * Note that address/port in packet payload (e.g., FTP) are NOT translated. - * - * __Input Gates__: 2 (0 for internal->external, and 1 for external->internal direction) - * __Output Gates__: 2 (same as the input gate) - */ -message NATArg { - message PortRange { - uint32 begin = 1; - uint32 end = 2; - bool suspended = 3; - } - message ExternalAddress { - string ext_addr = 1; - repeated PortRange port_ranges = 2; - } - repeated ExternalAddress ext_addrs = 1; /// list of external IP addresses -} - -/** - * Static NAT module implements one-to-one translation of source/destination - * IPv4 addresses. No port number is translated. - * L3/L4 checksums are updated correspondingly. - * To see an example of NAT in use, see: - * [`bess/bessctl/conf/samples/nat.bess`](https://github.com/NetSys/bess/blob/master/bessctl/conf/samples/nat.bess) - * - * Forward direction (from input gate 0 to output gate 0): - * - Source IP address is updated, from internal to external address. - * Reverse direction (from input gate 1 to output gate 1): - * - Destination IP address is updated, from external to internal address. - * If the original address is outside any of the ranges, packets are forwarded - * without NAT. - * - * Note that address in packet payload (e.g., FTP) are NOT translated. - * - * __Input Gates__: 2 (0 for internal->external, and 1 for external->internal direction) - * __Output Gates__: 2 (same as the input gate) - */ -message StaticNATArg { - message AddressRange { - string start = 1; /// first IP address to use - string end = 2; /// last IP address to use - } - - message AddressRangePair { - AddressRange int_range = 1; - AddressRange ext_range = 2; /// should be the same size as int_range - } - - repeated AddressRangePair pairs = 1; -} - -/** - * This module is used for testing purposes. - */ -message NoOpArg { -} - -/** - * The PortInc module connects a physical or virtual port and releases - * packets from it. PortInc does not support multiqueueing. - * For details on how to configure PortInc using DPDK, virtual ports, - * or libpcap, see the sidebar in the wiki. - * - * __Input Gates__: 0 - * __Output Gates__: 1 - */ -message PortIncArg { - string port = 1; /// The portname to connect to. - bool prefetch = 2; /// Whether or not to prefetch packets from the port. -} - -/** - * The PortOut module connects to a physical or virtual port and pushes - * packets to it. For details on how to configure PortOut with DPDK, - * virtual ports, libpcap, etc, see the sidebar in the wiki. - * - * __Input Gates__: 1 - * __Output Gates__: 0 - */ -message PortOutArg { - string port = 1; /// The portname to connect to. -} - -/** - * The module QueueInc produces input packets from a physical or virtual port. - * Unlike PortInc, it supports multiqueue ports. - * For details on how to configure QueueInc with DPDK, virtualports, - * libpcap, etc, see the sidebar in the wiki. - * - * __Input Gates__: 0 - * __Output Gates__: 1 - */ -message QueueIncArg { - string port = 1; /// The portname to connect to (read from). - uint64 qid = 2; /// The queue on that port to read from. qid starts from 0. - bool prefetch = 3; /// When prefetch is enabled, the module will perform CPU prefetch on the first 64B of each packet onto CPU L1 cache. Default value is false. -} - -/** - * The QueueOut module releases packets to a physical or virtual port. - * Unlike PortOut, it supports multiqueue ports. - * For details on how to configure QueueOut with DPDK, virtualports, - * libpcap, etc, see the sidebar in the wiki. - * - * __Input Gates__: 1 - * __Output Gates__: 0 - */ -message QueueOutArg { - string port = 1; /// The portname to connect to. - uint64 qid = 2; /// The queue on that port to write out to. -} - -/** - * The Queue module implements a simple packet queue. - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message QueueArg { - uint64 size = 1; /// The maximum number of packets to store in the queue. - bool prefetch = 2; /// When prefetch is enabled, the module will perform CPU prefetch on the first 64B of each packet onto CPU L1 cache. Default value is false. - bool backpressure = 3; // When backpressure is enabled, the module will notify upstream if it is overloaded. -} - -/** - * The RandomSplit module randomly split/drop packets - * - * __InputGates__: 1 - * __Output Gates__: many (configurable) - */ -message RandomSplitArg { - double drop_rate = 1; /// Probability of dropping packet. - repeated int64 gates = 2; /// A list of gate numbers to split the traffic. -} - -/** - * The RandomSplit module has a function `set_droprate(...)` which specifies - * the probability of dropping packets - */ -message RandomSplitCommandSetDroprateArg { - double drop_rate = 1; /// Probability of dropping packet. -} - -/** - * The RandomSplit module has a function `set_gates(...)` which changes - * the total number of output gates in the module. - */ -message RandomSplitCommandSetGatesArg { - repeated int64 gates = 1; /// A list of gate numbers to split the traffic. -} - -/** - * The RandomUpdate module rewrites a specified field (`offset` and `size`) in a packet - * with a random value between a specified min and max values. - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message RandomUpdateArg { - /** - * RandomUpdate's Field specifies where to rewrite, and what values to rewrite - * in each packet processed. - */ - message Field { - int64 offset = 1; /// Offset in bytes of where to rewrite. - uint64 size = 2; /// The number of bytes to write. - uint64 min = 3; /// The minimum value to insert into the packet. - uint64 max = 4; /// The maximum value to insert into the packet. - } - repeated Field fields = 1; /// A list of Random Update Fields. -} - -/** - * The Rewrite module replaces an entire packet body with a packet "template" - * converting all packets that pass through to copies of the of one of - * the templates. - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message RewriteArg { - repeated bytes templates = 1; /// A list of bytestrings representing packet templates. -} - -/** - * The RoundRobin module has a function `set_gates(...)` which changes - * the total number of output gates in the module. - */ -message RoundRobinCommandSetGatesArg { - repeated int64 gates = 1; /// A list of gate numbers to round-robin the traffic over. -} - -/** - * The RoundRobin module has a function `set_mode(...)` which specifies whether - * to balance traffic across gates per-packet or per-batch. - */ -message RoundRobinCommandSetModeArg { - string mode = 1; /// whether to perform `'packet'` or `'batch'` round robin partitioning. -} - -/** - * The RoundRobin module splits packets from one input gate across multiple output - * gates. - * - * __Input Gates__: 1 - * __Output Gates__: many (configurable) - */ -message RoundRobinArg { - repeated int64 gates = 1; /// A list of gate numbers to split packets across. - string mode = 2; /// Whether to split across gate with every `'packet'` or every `'batch'`. -} - -/** - * The Replicate module makes copies of a packet sending one copy out over each - * of n output gates. - * - * __Input Gates__: 1 - * __Output Gates__: many (configurable) - */ -message ReplicateArg { - repeated int64 gates = 1; /// A list of gate numbers to send packet copies to. -} - -/** - * The Replicate module has a function `set_gates(...)` which changes - * the total number of output gates in the module. - */ -message ReplicateCommandSetGatesArg { - repeated int64 gates = 1; /// A list of gate numbers to replicate the traffic over. -} - -/** - * The SetMetadata module adds metadata attributes to packets, which are not stored - * or sent out with packet data. For examples of SetMetadata use, see - * [`bess/bessctl/conf/attr_match.bess`](https://github.com/NetSys/bess/blob/master/bessctl/conf/metadata/attr_match.bess) - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message SetMetadataArg { - /** - * SetMetadata Attribute describes a metadata attribute and value to attach to every packet. - * If copying data from a packet buffer, SetMetadata can also logically shift - * then mask the value before storing it as metadata, i.e., - * metadata_value = (packet_value >> `rshift_bits`) & `mask`. - */ - message Attribute { - string name = 1; /// The metadata attribute name. - uint64 size = 2; /// The size of values stored in this attribute in bytes. - oneof value { - uint64 value_int = 3; /// An integer value to store in the packet (host-order). - bytes value_bin = 4; /// A binary value to store in the packet (host-order). - } - int32 offset = 5; /// An index in the packet data to store copy into the metadata attribute. - bytes mask = 6; /// An array of bit masks to apply to each of the bytes copied starting from `offset`. If empty, the mask `[0xFF,....,0xFF]` will be used. - int32 rshift_bits = 7; /// The number of bits to shift the value at `offset` by before masking. Must be a multiple of 8. Positive and negative values represent right and left shifts respectively. - } - repeated Attribute attrs = 1; /// A list of attributes to attach to the packet. -} - -/** - * The sink module drops all packets that are sent to it. - * - * __Input Gates__: 1 - * __Output Gates__: 0 - */ -message SinkArg { -} - -/** - * The Source module has a function `set_burst(...)` which - * specifies the maximum number of packets to release in a single packetbatch - * from the module. - */ -message SourceCommandSetBurstArg { - uint64 burst = 1; /// The maximum number of packets to release in a packetbatch from the module. -} - -/** - * The Source module has a function `set_pkt_size(...)` which specifies the size - * of packets to be produced by the Source module. - */ -message SourceCommandSetPktSizeArg { - uint64 pkt_size = 1; /// The size (in bytes) of the packets for Source to create. -} - -/** - * The Source module generates packets with no payload contents. - * - * __Input Gates__: 0 - * __Output Gates__: 1 - */ -message SourceArg { - uint64 pkt_size = 1; /// The size (in bytes) of packet data to produce. -} - -/** - * The GtpuEcho module processes the GTPv1 echo packet and prepares - * corresponding IP packet containing GTP echo response. It assumes - * Recovery IE is always zero. - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message GtpuEchoArg { - uint32 s1u_sgw_ip = 1; /// IP address of S1U interface -} - -/** - * The IPDefrag module scans the IP datagram and checks whether - * it is fragmented. It returns a fully reassembled datagram or - * an unfragmented IP datagram - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message IPDefragArg { - uint32 num_flows = 1; /// max number of flows the module can handle - 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 - * - * __Input Gates__: 1 - * __Output Gates__: 2 - */ -message GtpuDecapArg { - string ename = 1; /// name of gtpencap module -} - -/** - * The GtpuEncap module encapsulates an IP packet for tunnelling purposes - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message GtpuEncapArg { - uint32 s1u_sgw_ip = 1; /// IP address of S1U interface - uint32 num_subscribers = 2; /// Number of subscribers limit -} - -/** - * The GtpuEncap module has a command `add(...)` which takes two - * parameters. This function accepts the teids, and UE IP address, and creates - * a session record. - * Example use in bessctl: `gencap.add(teid=0xf0000000, eteid=..., ueaddr=0x10000001, enodeb_ip=...)` - */ -message GtpuEncapAddSessionRecordArg { - uint32 teid = 1; /// sgw tunnel endpoint identifier - uint32 eteid = 2; /// enodeb tunnel endpoint identifier - uint32 ueaddr = 3; /// ip address of UE - uint32 enodeb_ip = 4; /// enodeb ip address -} - -/** - * The GtpuEncap module has a command `remove(...)` which takes one - * parameter. This function accepts the ueaddr, and removes the - * respective session record. - * Example use in bessctl: `gencap.remove(ueaddr=0x10000001)` - */ -message GtpuEncapRemoveSessionRecordArg { - uint32 ueaddr = 1; /// ip address of UE -} - -/** - * The Split module is a basic classifier which directs packets out a gate - * based on data in the packet (e.g., if the read in value is 3, the packet - * is directed out output gate 3). - * - * __Input Gates__: 1 - * __Output Gates__: many (up to 2^(size * 8)) - */ -message SplitArg { - uint64 size = 1; /// The size of the value to read in bytes - oneof type { - string attribute = 2; /// The name of the metadata field to read. - int64 offset = 3; /// The offset (in bytes) of the data field to read. - } -} - -/** - * The timestamp module takes an offset parameter. It inserts the current - * time in nanoseconds into the packet, to be used for latency measurements - * alongside the Measure module. The default offset is after an IPv4 UDP - * header. - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message TimestampArg { - int64 offset = 1; -} - -/** - * The Update module rewrites a field in a packet's data with a specific value. - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message UpdateArg { - /** - * Update Field describes where in a packet's data to rewrite, and with what value. - */ - message Field { - int64 offset = 1; /// The offset in the packet in bytes to rewrite at. - uint64 size = 2; /// The number of bytes to rewrite (max 8 bytes). - uint64 value = 3; /// The value to write into the packet, max 8 bytes. - } - repeated Field fields = 1; /// A list of Update Fields. -} - -/** - * The URLFilter performs TCP reconstruction over a flow and blocks - * connections which mention a banned URL. - * - * __Input Gates__: 2 - * __Output Gates__: 2 - * - * Note that the add() command takes this same argument, and the - * clear() command takes an empty argument. - */ -message UrlFilterArg { - /** - * A URL consists of a host and a path. - */ - message Url { - string host = 1; /// Host field, e.g. "www.google.com" - string path = 2; /// Path prefix, e.g. "/" - } - repeated Url blacklist = 1; /// A list of Urls to block. -} - -/** - * The runtime configuration of a URLFilter is the current - * blacklist. This means that getting the Arg gets an *empty* - * list: we assume anyone using get_initial_arg is also using - * get_runtime_config. - */ -message UrlFilterConfig { - repeated UrlFilterArg.Url blacklist = 1; -} - -/** - * VLANPop removes the VLAN tag. - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message VLANPopArg { -} - -/** - * VLANPush appends a VLAN tag with a specified TCI value. - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message VLANPushArg { - uint64 tci = 1; /// The TCI value to insert in the VLAN tag. -} - -/** - * Splits packets across output gates according to VLAN id (e.g., id 3 goes out gate 3). - * - * __Input Gates__: 1 - * __Output Gates__: many - */ -message VLANSplitArg { -} - -/** - * VXLANDecap module decapsulates a VXLAN header on a packet. - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message VXLANDecapArg { -} - -/** - * VXLANEncap module wraps a packet in a VXLAN header with a specified destination port. - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message VXLANEncapArg { - uint64 dstport = 1; /// The destination UDP port -} - -/** - * The WildcardMatch module matches over multiple fields in a packet and - * pushes packets that do match out a specified gate, and those that don't out a default - * gate. WildcardMatch is initialized with the fields it should inspect over, - * rules are added via the `add(...)` function. - * An example of WildcardMatch is in [`bess/bessctl/conf/samples/wildcardmatch.bess`](https://github.com/NetSys/bess/blob/master/bessctl/conf/samples/wildcardmatch.bess) - * - * __Input Gates__: 1 - * __Output Gates__: many (configurable) - */ -message WildcardMatchArg { - repeated Field fields = 1; /// A list of WildcardMatch fields. -} - -/** - * WildcardMatchConfig represents the current runtime configuration - * of a WildcardMatch module, as returned by get_runtime_config and - * set by set_runtime_config. - */ -message WildcardMatchConfig { - uint64 default_gate = 1; - repeated WildcardMatchCommandAddArg rules = 2; -} - -/** - * The ARP Responder module is responding to ARP requests - * TODO: Dynamic learn new MAC's-IP's mapping - * - * __Input Gates__: 1 - * __Output Gates__: 1 - */ -message ArpResponderArg { - /** - * One ARP IP-MAC mapping - */ - string ip = 1; // The IP - string mac_addr = 2; /// The MAC address -} - -/** - * The MPLS pop module removes MPLS labels - * - * __Input Gates__: 1 - * __Output Gates__: 2 - */ -message MplsPopArg { - bool remove_eth_header = 1; // Remove ETH header with the pop - uint32 next_eth_type = 2; /// The next ETH type to set -} - -/** - * WorkerSplit splits packets based on the worker calling ProcessBatch(). It has - * two modes. - * 1) Packets from worker `x` are mapped to output gate `x`. This is the default - * mode. - * 2) When the `worker_gates` field is set, packets from a worker `x` are mapped - * to `worker_gates[x]`. In this mode, packet batches from workers not - * mapped to an output gate will be dropped. - * - * Calling the `reset` command with an empty `worker_gates` field will revert - * WorkerSplit to the default mode. - * - * __Input Gates__: 1 - * __Output Gates__: many - */ -message WorkerSplitArg { - map worker_gates = 1; // ogate -> worker mask -}